add support for simple character input via the system console
dev/alpha_access.h: - use our standard types instead of this extra typedef - advance the ALPHA_ACCESS version since the interface has changed. *this means you need a new console binary* - shuffle a couple things around to pack the data structure a bit better - add a placeholder for character input dev/alpha_console.cc: Clean up the read code path a bit and add support for character input via the console Clean up the write path and use a switch instead of a bunch of if statements --HG-- extra : convert_revision : a1a5bc8fed9ec9c4c46548fdf79604661668b81a
This commit is contained in:
parent
c3ba166e65
commit
318e0c93ed
4 changed files with 105 additions and 76 deletions
|
@ -33,52 +33,44 @@
|
||||||
* System Console Memory Mapped Register Definition
|
* System Console Memory Mapped Register Definition
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define ALPHA_ACCESS_VERSION (1291+1) /* CH++*/
|
#define ALPHA_ACCESS_VERSION (1301) /* CH++*/
|
||||||
|
|
||||||
#ifdef CONSOLE
|
|
||||||
typedef uint32 UINT32;
|
|
||||||
typedef uint64 UINT64;
|
|
||||||
#else
|
|
||||||
typedef uint32_t UINT32;
|
|
||||||
typedef uint64_t UINT64;
|
|
||||||
|
|
||||||
|
#ifndef CONSOLE
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
class Checkpoint;
|
class Checkpoint;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This structure hacked up from simos
|
// This structure hacked up from simos
|
||||||
struct AlphaAccess
|
struct AlphaAccess
|
||||||
{
|
{
|
||||||
UINT32 last_offset; // 00: must be first field
|
uint32_t last_offset; // 00: must be first field
|
||||||
UINT32 version; // 04:
|
uint32_t version; // 04:
|
||||||
UINT32 numCPUs; // 08:
|
uint32_t numCPUs; // 08:
|
||||||
UINT32 align0; // 0C: Placeholder for alignment
|
uint32_t intrClockFrequency; // 0C: Hz
|
||||||
UINT64 mem_size; // 10:
|
uint64_t cpuClock; // 10: MHz
|
||||||
UINT64 cpuClock; // 18: MHz
|
uint64_t mem_size; // 18:
|
||||||
UINT32 intrClockFrequency; // 20: Hz
|
|
||||||
UINT32 align1; // 24: Placeholder for alignment
|
|
||||||
|
|
||||||
// Loaded kernel
|
// Loaded kernel
|
||||||
UINT64 kernStart; // 28:
|
uint64_t kernStart; // 20:
|
||||||
UINT64 kernEnd; // 30:
|
uint64_t kernEnd; // 28:
|
||||||
UINT64 entryPoint; // 38:
|
uint64_t entryPoint; // 30:
|
||||||
|
|
||||||
// console disk stuff
|
// console disk stuff
|
||||||
UINT64 diskUnit; // 40:
|
uint64_t diskUnit; // 38:
|
||||||
UINT64 diskCount; // 48:
|
uint64_t diskCount; // 40:
|
||||||
UINT64 diskPAddr; // 50:
|
uint64_t diskPAddr; // 48:
|
||||||
UINT64 diskBlock; // 58:
|
uint64_t diskBlock; // 50:
|
||||||
UINT64 diskOperation; // 60:
|
uint64_t diskOperation; // 58:
|
||||||
|
|
||||||
// console simple output stuff
|
// console simple output stuff
|
||||||
UINT64 outputChar; // 68:
|
uint64_t outputChar; // 60: Placeholder for output
|
||||||
|
uint64_t inputChar; // 68: Placeholder for input
|
||||||
|
|
||||||
// MP boot
|
// MP boot
|
||||||
UINT64 bootStrapImpure; // 70:
|
uint64_t bootStrapImpure; // 70:
|
||||||
UINT32 bootStrapCPU; // 78:
|
uint32_t bootStrapCPU; // 78:
|
||||||
UINT32 align2; // 7C: Dummy placeholder for alignment
|
uint32_t align2; // 7C: Dummy placeholder for alignment
|
||||||
|
|
||||||
#ifndef CONSOLE
|
#ifndef CONSOLE
|
||||||
void serialize(std::ostream &os);
|
void serialize(std::ostream &os);
|
||||||
|
|
|
@ -76,17 +76,35 @@ Fault
|
||||||
AlphaConsole::read(MemReqPtr req, uint8_t *data)
|
AlphaConsole::read(MemReqPtr req, uint8_t *data)
|
||||||
{
|
{
|
||||||
memset(data, 0, req->size);
|
memset(data, 0, req->size);
|
||||||
|
uint64_t val;
|
||||||
|
|
||||||
if (req->size == sizeof(uint32_t)) {
|
Addr daddr = req->paddr & addr_mask;
|
||||||
Addr daddr = req->paddr & addr_mask;
|
switch (daddr) {
|
||||||
*(uint32_t *)data = *(uint32_t *)(consoleData + daddr);
|
case offsetof(AlphaAccess, inputChar):
|
||||||
|
val = console->in();
|
||||||
|
break;
|
||||||
|
|
||||||
#if 0
|
default:
|
||||||
DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n",
|
val = *(uint64_t *)(consoleData + daddr);
|
||||||
daddr, *(uint32_t *)data);
|
break;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n", daddr, val);
|
||||||
|
|
||||||
|
switch (req->size) {
|
||||||
|
case sizeof(uint32_t):
|
||||||
|
*(uint32_t *)data = (uint32_t)val;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sizeof(uint64_t):
|
||||||
|
*(uint64_t *)data = val;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return Machine_Check_Fault;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,6 +117,7 @@ AlphaConsole::write(MemReqPtr req, const uint8_t *data)
|
||||||
case sizeof(uint32_t):
|
case sizeof(uint32_t):
|
||||||
val = *(uint32_t *)data;
|
val = *(uint32_t *)data;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case sizeof(uint64_t):
|
case sizeof(uint64_t):
|
||||||
val = *(uint64_t *)data;
|
val = *(uint64_t *)data;
|
||||||
break;
|
break;
|
||||||
|
@ -106,60 +125,57 @@ AlphaConsole::write(MemReqPtr req, const uint8_t *data)
|
||||||
return Machine_Check_Fault;
|
return Machine_Check_Fault;
|
||||||
}
|
}
|
||||||
|
|
||||||
Addr paddr = req->paddr & addr_mask;
|
Addr daddr = req->paddr & addr_mask;
|
||||||
|
ExecContext *other_xc;
|
||||||
|
|
||||||
if (paddr == offsetof(AlphaAccess, diskUnit)) {
|
switch (daddr) {
|
||||||
|
case offsetof(AlphaAccess, diskUnit):
|
||||||
alphaAccess->diskUnit = val;
|
alphaAccess->diskUnit = val;
|
||||||
return No_Fault;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if (paddr == offsetof(AlphaAccess, diskCount)) {
|
case offsetof(AlphaAccess, diskCount):
|
||||||
alphaAccess->diskCount = val;
|
alphaAccess->diskCount = val;
|
||||||
return No_Fault;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if (paddr == offsetof(AlphaAccess, diskPAddr)) {
|
case offsetof(AlphaAccess, diskPAddr):
|
||||||
alphaAccess->diskPAddr = val;
|
alphaAccess->diskPAddr = val;
|
||||||
return No_Fault;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if (paddr == offsetof(AlphaAccess, diskBlock)) {
|
case offsetof(AlphaAccess, diskBlock):
|
||||||
alphaAccess->diskBlock = val;
|
alphaAccess->diskBlock = val;
|
||||||
return No_Fault;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if (paddr == offsetof(AlphaAccess, diskOperation)) {
|
case offsetof(AlphaAccess, diskOperation):
|
||||||
if (val == 0x13)
|
if (val == 0x13)
|
||||||
disk->read(alphaAccess->diskPAddr, alphaAccess->diskBlock,
|
disk->read(alphaAccess->diskPAddr, alphaAccess->diskBlock,
|
||||||
alphaAccess->diskCount);
|
alphaAccess->diskCount);
|
||||||
else
|
else
|
||||||
panic("Invalid disk operation!");
|
panic("Invalid disk operation!");
|
||||||
|
|
||||||
return No_Fault;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if (paddr == offsetof(AlphaAccess, outputChar)) {
|
case offsetof(AlphaAccess, outputChar):
|
||||||
console->out((char)(val & 0xff), false);
|
console->out((char)(val & 0xff), false);
|
||||||
return No_Fault;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if (paddr == offsetof(AlphaAccess, bootStrapImpure)) {
|
case offsetof(AlphaAccess, bootStrapImpure):
|
||||||
alphaAccess->bootStrapImpure = val;
|
alphaAccess->bootStrapImpure = val;
|
||||||
return No_Fault;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if (paddr == offsetof(AlphaAccess, bootStrapCPU)) {
|
case offsetof(AlphaAccess, bootStrapCPU):
|
||||||
warn("%d: Trying to launch another CPU!", curTick);
|
warn("%d: Trying to launch another CPU!", curTick);
|
||||||
int cpu = val;
|
assert(val > 0 && "Must not access primary cpu");
|
||||||
assert(cpu > 0 && "Must not access primary cpu");
|
|
||||||
|
|
||||||
ExecContext *other_xc = req->xc->system->execContexts[cpu];
|
other_xc = req->xc->system->execContexts[val];
|
||||||
other_xc->regs.intRegFile[16] = cpu;
|
other_xc->regs.intRegFile[16] = val;
|
||||||
other_xc->regs.ipr[TheISA::IPR_PALtemp16] = cpu;
|
other_xc->regs.ipr[TheISA::IPR_PALtemp16] = val;
|
||||||
other_xc->regs.intRegFile[0] = cpu;
|
other_xc->regs.intRegFile[0] = val;
|
||||||
other_xc->regs.intRegFile[30] = alphaAccess->bootStrapImpure;
|
other_xc->regs.intRegFile[30] = alphaAccess->bootStrapImpure;
|
||||||
other_xc->activate(); //Start the cpu
|
other_xc->activate(); //Start the cpu
|
||||||
return No_Fault;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return Machine_Check_Fault;
|
||||||
}
|
}
|
||||||
|
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
|
@ -183,6 +199,7 @@ AlphaAccess::serialize(ostream &os)
|
||||||
SERIALIZE_SCALAR(diskBlock);
|
SERIALIZE_SCALAR(diskBlock);
|
||||||
SERIALIZE_SCALAR(diskOperation);
|
SERIALIZE_SCALAR(diskOperation);
|
||||||
SERIALIZE_SCALAR(outputChar);
|
SERIALIZE_SCALAR(outputChar);
|
||||||
|
SERIALIZE_SCALAR(inputChar);
|
||||||
SERIALIZE_SCALAR(bootStrapImpure);
|
SERIALIZE_SCALAR(bootStrapImpure);
|
||||||
SERIALIZE_SCALAR(bootStrapCPU);
|
SERIALIZE_SCALAR(bootStrapCPU);
|
||||||
}
|
}
|
||||||
|
@ -205,6 +222,7 @@ AlphaAccess::unserialize(Checkpoint *cp, const std::string §ion)
|
||||||
UNSERIALIZE_SCALAR(diskBlock);
|
UNSERIALIZE_SCALAR(diskBlock);
|
||||||
UNSERIALIZE_SCALAR(diskOperation);
|
UNSERIALIZE_SCALAR(diskOperation);
|
||||||
UNSERIALIZE_SCALAR(outputChar);
|
UNSERIALIZE_SCALAR(outputChar);
|
||||||
|
UNSERIALIZE_SCALAR(inputChar);
|
||||||
UNSERIALIZE_SCALAR(bootStrapImpure);
|
UNSERIALIZE_SCALAR(bootStrapImpure);
|
||||||
UNSERIALIZE_SCALAR(bootStrapCPU);
|
UNSERIALIZE_SCALAR(bootStrapCPU);
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,21 +223,32 @@ SimConsole::configTerm()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
#define MORE_PENDING (ULL(1) << 61)
|
||||||
|
#define RECEIVE_SUCCESS (ULL(0) << 62)
|
||||||
|
#define RECEIVE_NONE (ULL(2) << 62)
|
||||||
|
#define RECEIVE_ERROR (ULL(3) << 62)
|
||||||
|
|
||||||
|
uint64_t
|
||||||
SimConsole::in()
|
SimConsole::in()
|
||||||
{
|
{
|
||||||
|
char c = 0;
|
||||||
|
uint64_t val = 0;
|
||||||
if (rxbuf.empty()) {
|
if (rxbuf.empty()) {
|
||||||
clearInt(ReceiveInterrupt);
|
clearInt(ReceiveInterrupt);
|
||||||
return -1;
|
val |= RECEIVE_NONE;
|
||||||
|
return 0x8;
|
||||||
|
} else {
|
||||||
|
uint64_t val;
|
||||||
|
rxbuf.read(&c, 1);
|
||||||
|
val |= RECEIVE_SUCCESS | c;
|
||||||
|
if (!rxbuf.empty())
|
||||||
|
val |= MORE_PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
char c;
|
DPRINTF(ConsoleVerbose, "in: \'%c\' %#02x retval: %#x\n",
|
||||||
rxbuf.read(&c, 1);
|
isprint(c) ? c : ' ', c, val);
|
||||||
|
|
||||||
DPRINTF(ConsoleVerbose, "in: \'%c\' %#02x status: %#x\n",
|
return val;
|
||||||
isprint(c) ? c : ' ', c, _status);
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -109,9 +109,17 @@ class SimConsole : public SimObject
|
||||||
// OS interface
|
// OS interface
|
||||||
|
|
||||||
// Get a character from the console.
|
// Get a character from the console.
|
||||||
// return of -1 means there is no character pending.
|
// the return value corresponds to the console GETC return value:
|
||||||
|
// retval<63:61>
|
||||||
|
// 000: success: character received
|
||||||
|
// 001: success: character received, more pending
|
||||||
|
// 100: failure: no character ready
|
||||||
|
// 110: failure: character received with error
|
||||||
|
// 111: failure: character received with error, more pending
|
||||||
|
// retval<31:0>
|
||||||
|
// character read from console
|
||||||
// Interrupts are cleared when the buffer is empty.
|
// Interrupts are cleared when the buffer is empty.
|
||||||
int in();
|
uint64_t in();
|
||||||
|
|
||||||
// Send a character to the console
|
// Send a character to the console
|
||||||
void out(char c, bool raise_int = true);
|
void out(char c, bool raise_int = true);
|
||||||
|
|
Loading…
Reference in a new issue