Merge zed.eecs.umich.edu:/.automount/fox/y/mserrano/m5_dir/m5
into zed.eecs.umich.edu:/z/benash/bk/m5 dev/ide_ctrl.cc: dev/ide_ctrl.hh: dev/ide_disk.cc: dev/ide_disk.hh: dev/ns_gige.cc: dev/pciconfigall.cc: dev/pcidev.cc: dev/rtcreg.h: dev/tsunami_io.cc: dev/tsunami_io.hh: dev/uart8250.cc: dev/uart8250.hh: python/m5/objects/Tsunami.py: Merge code. --HG-- extra : convert_revision : e97d5dbcc051d2061622201265430d359f995d48
This commit is contained in:
commit
bcc333e920
30 changed files with 1213 additions and 830 deletions
|
@ -272,7 +272,7 @@ full_system_sources = Split('''
|
||||||
dev/simple_disk.cc
|
dev/simple_disk.cc
|
||||||
dev/tsunami.cc
|
dev/tsunami.cc
|
||||||
dev/tsunami_cchip.cc
|
dev/tsunami_cchip.cc
|
||||||
dev/tsunami_fake.cc
|
dev/isa_fake.cc
|
||||||
dev/tsunami_io.cc
|
dev/tsunami_io.cc
|
||||||
dev/tsunami_pchip.cc
|
dev/tsunami_pchip.cc
|
||||||
dev/uart.cc
|
dev/uart.cc
|
||||||
|
|
|
@ -263,7 +263,7 @@ class ExecContext
|
||||||
|
|
||||||
Fault error;
|
Fault error;
|
||||||
error = mem->read(req, data);
|
error = mem->read(req, data);
|
||||||
data = htoa(data);
|
data = gtoh(data);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,7 +313,7 @@ class ExecContext
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
return mem->write(req, (T)htoa(data));
|
return mem->write(req, (T)htog(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool misspeculating();
|
virtual bool misspeculating();
|
||||||
|
|
|
@ -220,7 +220,7 @@ class AlphaFullCPU : public FullO3CPU<Impl>
|
||||||
|
|
||||||
Fault error;
|
Fault error;
|
||||||
error = this->mem->read(req, data);
|
error = this->mem->read(req, data);
|
||||||
data = htoa(data);
|
data = gtoh(data);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,7 +277,7 @@ class AlphaFullCPU : public FullO3CPU<Impl>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return this->mem->write(req, (T)htoa(data));
|
return this->mem->write(req, (T)htog(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
|
|
|
@ -535,7 +535,7 @@ SimpleFetch<Impl>::fetch()
|
||||||
assert(offset <= cacheBlkSize - instSize);
|
assert(offset <= cacheBlkSize - instSize);
|
||||||
|
|
||||||
// Get the instruction from the array of the cache line.
|
// Get the instruction from the array of the cache line.
|
||||||
inst = htoa(*reinterpret_cast<MachInst *>
|
inst = gtoh(*reinterpret_cast<MachInst *>
|
||||||
(&cacheData[offset]));
|
(&cacheData[offset]));
|
||||||
|
|
||||||
// Create a new DynInst from the instruction fetched.
|
// Create a new DynInst from the instruction fetched.
|
||||||
|
|
|
@ -738,7 +738,7 @@ SimpleCPU::tick()
|
||||||
comInstEventQueue[0]->serviceEvents(numInst);
|
comInstEventQueue[0]->serviceEvents(numInst);
|
||||||
|
|
||||||
// decode the instruction
|
// decode the instruction
|
||||||
inst = htoa(inst);
|
inst = gtoh(inst);
|
||||||
curStaticInst = StaticInst<TheISA>::decode(inst);
|
curStaticInst = StaticInst<TheISA>::decode(inst);
|
||||||
|
|
||||||
traceData = Trace::getInstRecord(curTick, xc, this, curStaticInst,
|
traceData = Trace::getInstRecord(curTick, xc, this, curStaticInst,
|
||||||
|
|
|
@ -237,7 +237,7 @@ void
|
||||||
SafeReadSwap(ifstream &stream, T &data)
|
SafeReadSwap(ifstream &stream, T &data)
|
||||||
{
|
{
|
||||||
SafeRead(stream, &data, sizeof(data));
|
SafeRead(stream, &data, sizeof(data));
|
||||||
data = htoa(data);
|
data = letoh(data); //is this the proper byte order conversion?
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -319,7 +319,7 @@ template<class T>
|
||||||
void
|
void
|
||||||
SafeWriteSwap(ofstream &stream, const T &data)
|
SafeWriteSwap(ofstream &stream, const T &data)
|
||||||
{
|
{
|
||||||
T swappeddata = htoa(data);
|
T swappeddata = letoh(data); //is this the proper byte order conversion?
|
||||||
SafeWrite(stream, &swappeddata, sizeof(data));
|
SafeWrite(stream, &swappeddata, sizeof(data));
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
|
|
210
dev/ide_ctrl.cc
210
dev/ide_ctrl.cc
|
@ -76,10 +76,12 @@ IdeController::IdeController(Params *p)
|
||||||
|
|
||||||
// zero out all of the registers
|
// zero out all of the registers
|
||||||
memset(bmi_regs.data, 0, sizeof(bmi_regs));
|
memset(bmi_regs.data, 0, sizeof(bmi_regs));
|
||||||
memset(pci_config_regs.data, 0, sizeof(pci_config_regs.data));
|
memset(config_regs.data, 0, sizeof(config_regs.data));
|
||||||
|
|
||||||
// setup initial values
|
// setup initial values
|
||||||
pci_config_regs.idetim = htoa((uint32_t)0x80008000); // enable both channels
|
// enable both channels
|
||||||
|
config_regs.idetim0 = htole((uint16_t)IDETIM_DECODE_EN);
|
||||||
|
config_regs.idetim1 = htole((uint16_t)IDETIM_DECODE_EN);
|
||||||
bmi_regs.bmis0 = DMA1CAP | DMA0CAP;
|
bmi_regs.bmis0 = DMA1CAP | DMA0CAP;
|
||||||
bmi_regs.bmis1 = DMA1CAP | DMA0CAP;
|
bmi_regs.bmis1 = DMA1CAP | DMA0CAP;
|
||||||
|
|
||||||
|
@ -127,46 +129,46 @@ IdeController::~IdeController()
|
||||||
///
|
///
|
||||||
|
|
||||||
void
|
void
|
||||||
IdeController::parseAddr(const Addr &addr, Addr &offset, bool &primary,
|
IdeController::parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel,
|
||||||
RegType_t &type)
|
IdeRegType ®_type)
|
||||||
{
|
{
|
||||||
offset = addr;
|
offset = addr;
|
||||||
|
|
||||||
if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) {
|
if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) {
|
||||||
offset -= pri_cmd_addr;
|
offset -= pri_cmd_addr;
|
||||||
type = COMMAND_BLOCK;
|
reg_type = COMMAND_BLOCK;
|
||||||
primary = true;
|
channel = PRIMARY;
|
||||||
} else if (addr >= pri_ctrl_addr &&
|
} else if (addr >= pri_ctrl_addr &&
|
||||||
addr < (pri_ctrl_addr + pri_ctrl_size)) {
|
addr < (pri_ctrl_addr + pri_ctrl_size)) {
|
||||||
offset -= pri_ctrl_addr;
|
offset -= pri_ctrl_addr;
|
||||||
type = CONTROL_BLOCK;
|
reg_type = CONTROL_BLOCK;
|
||||||
primary = true;
|
channel = PRIMARY;
|
||||||
} else if (addr >= sec_cmd_addr &&
|
} else if (addr >= sec_cmd_addr &&
|
||||||
addr < (sec_cmd_addr + sec_cmd_size)) {
|
addr < (sec_cmd_addr + sec_cmd_size)) {
|
||||||
offset -= sec_cmd_addr;
|
offset -= sec_cmd_addr;
|
||||||
type = COMMAND_BLOCK;
|
reg_type = COMMAND_BLOCK;
|
||||||
primary = false;
|
channel = SECONDARY;
|
||||||
} else if (addr >= sec_ctrl_addr &&
|
} else if (addr >= sec_ctrl_addr &&
|
||||||
addr < (sec_ctrl_addr + sec_ctrl_size)) {
|
addr < (sec_ctrl_addr + sec_ctrl_size)) {
|
||||||
offset -= sec_ctrl_addr;
|
offset -= sec_ctrl_addr;
|
||||||
type = CONTROL_BLOCK;
|
reg_type = CONTROL_BLOCK;
|
||||||
primary = false;
|
channel = SECONDARY;
|
||||||
} else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) {
|
} else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) {
|
||||||
offset -= bmi_addr;
|
offset -= bmi_addr;
|
||||||
type = BMI_BLOCK;
|
reg_type = BMI_BLOCK;
|
||||||
primary = (offset < BMIC1) ? true : false;
|
channel = (offset < BMIC1) ? PRIMARY : SECONDARY;
|
||||||
} else {
|
} else {
|
||||||
panic("IDE controller access to invalid address: %#x\n", addr);
|
panic("IDE controller access to invalid address: %#x\n", addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
IdeController::getDisk(bool primary)
|
IdeController::getDisk(IdeChannel channel)
|
||||||
{
|
{
|
||||||
int disk = 0;
|
int disk = 0;
|
||||||
uint8_t *devBit = &dev[0];
|
uint8_t *devBit = &dev[0];
|
||||||
|
|
||||||
if (!primary) {
|
if (channel == SECONDARY) {
|
||||||
disk += 2;
|
disk += 2;
|
||||||
devBit = &dev[1];
|
devBit = &dev[1];
|
||||||
}
|
}
|
||||||
|
@ -249,43 +251,33 @@ IdeController::cacheAccess(MemReqPtr &req)
|
||||||
////
|
////
|
||||||
|
|
||||||
void
|
void
|
||||||
IdeController::ReadConfig(int offset, int size, uint8_t *data)
|
IdeController::readConfig(int offset, int size, uint8_t *data)
|
||||||
{
|
{
|
||||||
union {
|
|
||||||
uint8_t byte;
|
|
||||||
uint16_t word;
|
|
||||||
uint32_t dword;
|
|
||||||
};
|
|
||||||
|
|
||||||
int config_offset;
|
int config_offset;
|
||||||
|
|
||||||
if (offset < PCI_DEVICE_SPECIFIC) {
|
if (offset < PCI_DEVICE_SPECIFIC) {
|
||||||
PciDev::ReadConfig(offset, size, data);
|
PciDev::readConfig(offset, size, data);
|
||||||
} else if (offset >= IDE_CTRL_CONFIG_START &&
|
} else if (offset >= IDE_CTRL_CONF_START &&
|
||||||
(offset + size) <= IDE_CTRL_CONFIG_END) {
|
(offset + size) <= IDE_CTRL_CONF_END) {
|
||||||
|
|
||||||
config_offset = offset - IDE_CTRL_CONFIG_START;
|
config_offset = offset - IDE_CTRL_CONF_START;
|
||||||
dword = 0;
|
|
||||||
|
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case sizeof(uint8_t):
|
case sizeof(uint8_t):
|
||||||
memcpy(&byte, &pci_config_regs.data[config_offset], size);
|
*data = config_regs.data[config_offset];
|
||||||
*data = byte;
|
|
||||||
break;
|
break;
|
||||||
case sizeof(uint16_t):
|
case sizeof(uint16_t):
|
||||||
memcpy(&byte, &pci_config_regs.data[config_offset], size);
|
*(uint16_t*)data = *(uint16_t*)&config_regs.data[config_offset];
|
||||||
*(uint16_t*)data = htoa(word);
|
|
||||||
break;
|
break;
|
||||||
case sizeof(uint32_t):
|
case sizeof(uint32_t):
|
||||||
memcpy(&byte, &pci_config_regs.data[config_offset], size);
|
*(uint32_t*)data = *(uint32_t*)&config_regs.data[config_offset];
|
||||||
*(uint32_t*)data = htoa(dword);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Invalid PCI configuration read size!\n");
|
panic("Invalid PCI configuration read size!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINTF(IdeCtrl, "PCI read offset: %#x size: %#x data: %#x\n",
|
DPRINTF(IdeCtrl, "PCI read offset: %#x size: %#x data: %#x\n",
|
||||||
offset, size, htoa(dword));
|
offset, size, *(uint32_t*)data);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
panic("Read of unimplemented PCI config. register: %x\n", offset);
|
panic("Read of unimplemented PCI config. register: %x\n", offset);
|
||||||
|
@ -293,27 +285,25 @@ IdeController::ReadConfig(int offset, int size, uint8_t *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
IdeController::WriteConfig(int offset, int size, uint32_t data)
|
IdeController::writeConfig(int offset, int size, const uint8_t *data)
|
||||||
{
|
{
|
||||||
int config_offset;
|
int config_offset;
|
||||||
uint32_t write_data;
|
|
||||||
|
|
||||||
if (offset < PCI_DEVICE_SPECIFIC) {
|
if (offset < PCI_DEVICE_SPECIFIC) {
|
||||||
PciDev::WriteConfig(offset, size, data);
|
PciDev::writeConfig(offset, size, data);
|
||||||
} else if (offset >= IDE_CTRL_CONFIG_START &&
|
} else if (offset >= IDE_CTRL_CONF_START &&
|
||||||
(offset + size) <= IDE_CTRL_CONFIG_END) {
|
(offset + size) <= IDE_CTRL_CONF_END) {
|
||||||
|
|
||||||
config_offset = offset - IDE_CTRL_CONFIG_START;
|
config_offset = offset - IDE_CTRL_CONF_START;
|
||||||
|
|
||||||
write_data = htoa(data);
|
|
||||||
|
|
||||||
switch(size) {
|
switch(size) {
|
||||||
case sizeof(uint8_t):
|
case sizeof(uint8_t):
|
||||||
|
config_regs.data[config_offset] = *data;
|
||||||
case sizeof(uint16_t):
|
case sizeof(uint16_t):
|
||||||
|
*(uint16_t*)&config_regs.data[config_offset] = *(uint16_t*)data;
|
||||||
case sizeof(uint32_t):
|
case sizeof(uint32_t):
|
||||||
memcpy(&pci_config_regs.data[config_offset], &write_data, size);
|
*(uint32_t*)&config_regs.data[config_offset] = *(uint32_t*)data;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic("Invalid PCI configuration write size!\n");
|
panic("Invalid PCI configuration write size!\n");
|
||||||
}
|
}
|
||||||
|
@ -328,12 +318,12 @@ IdeController::WriteConfig(int offset, int size, uint32_t data)
|
||||||
// (like updating the PIO ranges)
|
// (like updating the PIO ranges)
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case PCI_COMMAND:
|
case PCI_COMMAND:
|
||||||
if (config.data[offset] & PCI_CMD_IOSE)
|
if (letoh(config.command) & PCI_CMD_IOSE)
|
||||||
io_enabled = true;
|
io_enabled = true;
|
||||||
else
|
else
|
||||||
io_enabled = false;
|
io_enabled = false;
|
||||||
|
|
||||||
if (config.data[offset] & PCI_CMD_BME)
|
if (letoh(config.command) & PCI_CMD_BME)
|
||||||
bm_enabled = true;
|
bm_enabled = true;
|
||||||
else
|
else
|
||||||
bm_enabled = false;
|
bm_enabled = false;
|
||||||
|
@ -399,48 +389,26 @@ Fault
|
||||||
IdeController::read(MemReqPtr &req, uint8_t *data)
|
IdeController::read(MemReqPtr &req, uint8_t *data)
|
||||||
{
|
{
|
||||||
Addr offset;
|
Addr offset;
|
||||||
bool primary;
|
IdeChannel channel;
|
||||||
RegType_t type;
|
IdeRegType reg_type;
|
||||||
int disk;
|
int disk;
|
||||||
|
|
||||||
/* union
|
parseAddr(req->paddr, offset, channel, reg_type);
|
||||||
* +-- --+-- --+-- --+-- --+
|
|
||||||
* | 0 | 1 | 2 | 3 |
|
|
||||||
* +-- --+-- --+-- --+-- --+
|
|
||||||
* | byte | .. | .. | .. |
|
|
||||||
* +-- --+-- --+-- --+-- --+
|
|
||||||
* | word0 | word1 |
|
|
||||||
* +-- --+-- --+
|
|
||||||
* | dword |
|
|
||||||
* +-- --+
|
|
||||||
*/
|
|
||||||
union {
|
|
||||||
uint8_t byte;
|
|
||||||
uint16_t word[2];
|
|
||||||
uint32_t dword;
|
|
||||||
};
|
|
||||||
|
|
||||||
dword = 0;
|
|
||||||
|
|
||||||
parseAddr(req->paddr, offset, primary, type);
|
|
||||||
|
|
||||||
if (!io_enabled)
|
if (!io_enabled)
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
|
|
||||||
switch (type) {
|
switch (reg_type) {
|
||||||
case BMI_BLOCK:
|
case BMI_BLOCK:
|
||||||
switch (req->size) {
|
switch (req->size) {
|
||||||
case sizeof(uint8_t):
|
case sizeof(uint8_t):
|
||||||
memcpy(&byte, &bmi_regs.data[offset], sizeof(uint8_t));
|
*data = bmi_regs.data[offset];
|
||||||
*data = byte;
|
|
||||||
break;
|
break;
|
||||||
case sizeof(uint16_t):
|
case sizeof(uint16_t):
|
||||||
memcpy(&byte, &bmi_regs.data[offset], sizeof(uint16_t));
|
*(uint16_t*)data = *(uint16_t*)&bmi_regs.data[offset];
|
||||||
*(uint16_t*)data = htoa(word[0]);
|
|
||||||
break;
|
break;
|
||||||
case sizeof(uint32_t):
|
case sizeof(uint32_t):
|
||||||
memcpy(&byte, &bmi_regs.data[offset], sizeof(uint32_t));
|
*(uint32_t*)data = *(uint32_t*)&bmi_regs.data[offset];
|
||||||
*(uint32_t*)data = htoa(dword);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("IDE read of BMI reg invalid size: %#x\n", req->size);
|
panic("IDE read of BMI reg invalid size: %#x\n", req->size);
|
||||||
|
@ -449,7 +417,7 @@ IdeController::read(MemReqPtr &req, uint8_t *data)
|
||||||
|
|
||||||
case COMMAND_BLOCK:
|
case COMMAND_BLOCK:
|
||||||
case CONTROL_BLOCK:
|
case CONTROL_BLOCK:
|
||||||
disk = getDisk(primary);
|
disk = getDisk(channel);
|
||||||
|
|
||||||
if (disks[disk] == NULL)
|
if (disks[disk] == NULL)
|
||||||
break;
|
break;
|
||||||
|
@ -458,14 +426,12 @@ IdeController::read(MemReqPtr &req, uint8_t *data)
|
||||||
case DATA_OFFSET:
|
case DATA_OFFSET:
|
||||||
switch (req->size) {
|
switch (req->size) {
|
||||||
case sizeof(uint16_t):
|
case sizeof(uint16_t):
|
||||||
disks[disk]->read(offset, type, (uint8_t*)&word[0]);
|
disks[disk]->read(offset, reg_type, data);
|
||||||
*(uint16_t*)data = htoa(word[0]);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case sizeof(uint32_t):
|
case sizeof(uint32_t):
|
||||||
disks[disk]->read(offset, type, (uint8_t*)&word[0]);
|
disks[disk]->read(offset, reg_type, data);
|
||||||
disks[disk]->read(offset, type, (uint8_t*)&word[1]);
|
disks[disk]->read(offset, reg_type, &data[2]);
|
||||||
*(uint32_t*)data = htoa(dword);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -474,8 +440,7 @@ IdeController::read(MemReqPtr &req, uint8_t *data)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (req->size == sizeof(uint8_t)) {
|
if (req->size == sizeof(uint8_t)) {
|
||||||
disks[disk]->read(offset, type, &byte);
|
disks[disk]->read(offset, reg_type, data);
|
||||||
*data = byte;
|
|
||||||
} else
|
} else
|
||||||
panic("IDE read of command reg of invalid size: %#x\n", req->size);
|
panic("IDE read of command reg of invalid size: %#x\n", req->size);
|
||||||
}
|
}
|
||||||
|
@ -485,7 +450,7 @@ IdeController::read(MemReqPtr &req, uint8_t *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
|
DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
|
||||||
offset, req->size, htoa(dword));
|
offset, req->size, *(uint32_t*)data);
|
||||||
|
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
}
|
}
|
||||||
|
@ -494,26 +459,17 @@ Fault
|
||||||
IdeController::write(MemReqPtr &req, const uint8_t *data)
|
IdeController::write(MemReqPtr &req, const uint8_t *data)
|
||||||
{
|
{
|
||||||
Addr offset;
|
Addr offset;
|
||||||
bool primary;
|
IdeChannel channel;
|
||||||
RegType_t type;
|
IdeRegType reg_type;
|
||||||
int disk;
|
int disk;
|
||||||
|
|
||||||
union {
|
|
||||||
uint8_t byte;
|
|
||||||
uint16_t word[2];
|
|
||||||
uint32_t dword;
|
|
||||||
};
|
|
||||||
|
|
||||||
dword = 0;
|
|
||||||
|
|
||||||
parseAddr(req->paddr, offset, primary, type);
|
|
||||||
|
|
||||||
uint8_t oldVal, newVal;
|
uint8_t oldVal, newVal;
|
||||||
|
|
||||||
|
parseAddr(req->paddr, offset, channel, reg_type);
|
||||||
|
|
||||||
if (!io_enabled)
|
if (!io_enabled)
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
|
|
||||||
switch (type) {
|
switch (reg_type) {
|
||||||
case BMI_BLOCK:
|
case BMI_BLOCK:
|
||||||
if (!bm_enabled)
|
if (!bm_enabled)
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
|
@ -526,11 +482,10 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
|
||||||
panic("Invalid BMIC write size: %x\n", req->size);
|
panic("Invalid BMIC write size: %x\n", req->size);
|
||||||
|
|
||||||
// select the current disk based on DEV bit
|
// select the current disk based on DEV bit
|
||||||
disk = getDisk(primary);
|
disk = getDisk(channel);
|
||||||
|
|
||||||
oldVal = bmi_regs.data[offset];
|
oldVal = letoh(bmi_regs.chan[channel].bmic);
|
||||||
byte = *data;
|
newVal = letoh(*data);
|
||||||
newVal = byte;
|
|
||||||
|
|
||||||
// if a DMA transfer is in progress, R/W control cannot change
|
// if a DMA transfer is in progress, R/W control cannot change
|
||||||
if (oldVal & SSBM) {
|
if (oldVal & SSBM) {
|
||||||
|
@ -546,7 +501,8 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
|
||||||
DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
|
DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
|
||||||
|
|
||||||
// clear the BMIDEA bit
|
// clear the BMIDEA bit
|
||||||
bmi_regs.data[offset + 0x2] &= ~BMIDEA;
|
bmi_regs.chan[channel].bmis = letoh(
|
||||||
|
letoh(bmi_regs.chan[channel].bmis) & ~BMIDEA);
|
||||||
|
|
||||||
if (disks[disk] == NULL)
|
if (disks[disk] == NULL)
|
||||||
panic("DMA stop for disk %d which does not exist\n",
|
panic("DMA stop for disk %d which does not exist\n",
|
||||||
|
@ -559,22 +515,20 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
|
||||||
DPRINTF(IdeCtrl, "Starting DMA transfer\n");
|
DPRINTF(IdeCtrl, "Starting DMA transfer\n");
|
||||||
|
|
||||||
// set the BMIDEA bit
|
// set the BMIDEA bit
|
||||||
bmi_regs.data[offset + 0x2] |= BMIDEA;
|
bmi_regs.chan[channel].bmis = letoh(
|
||||||
|
letoh(bmi_regs.chan[channel].bmis) | BMIDEA);
|
||||||
|
|
||||||
if (disks[disk] == NULL)
|
if (disks[disk] == NULL)
|
||||||
panic("DMA start for disk %d which does not exist\n",
|
panic("DMA start for disk %d which does not exist\n",
|
||||||
disk);
|
disk);
|
||||||
|
|
||||||
// inform the disk of the DMA transfer start
|
// inform the disk of the DMA transfer start
|
||||||
if (primary)
|
disks[disk]->startDma(letoh(bmi_regs.chan[channel].bmidtp));
|
||||||
disks[disk]->startDma(bmi_regs.bmidtp0);
|
|
||||||
else
|
|
||||||
disks[disk]->startDma(bmi_regs.bmidtp1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the register value
|
// update the register value
|
||||||
bmi_regs.data[offset] = newVal;
|
bmi_regs.chan[channel].bmic = letoh(newVal);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Bus master IDE status register
|
// Bus master IDE status register
|
||||||
|
@ -583,9 +537,8 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
|
||||||
if (req->size != sizeof(uint8_t))
|
if (req->size != sizeof(uint8_t))
|
||||||
panic("Invalid BMIS write size: %x\n", req->size);
|
panic("Invalid BMIS write size: %x\n", req->size);
|
||||||
|
|
||||||
oldVal = bmi_regs.data[offset];
|
oldVal = letoh(bmi_regs.chan[channel].bmis);
|
||||||
byte = *data;
|
newVal = letoh(*data);
|
||||||
newVal = byte;
|
|
||||||
|
|
||||||
// the BMIDEA bit is RO
|
// the BMIDEA bit is RO
|
||||||
newVal |= (oldVal & BMIDEA);
|
newVal |= (oldVal & BMIDEA);
|
||||||
|
@ -601,7 +554,7 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
|
||||||
else
|
else
|
||||||
(oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE;
|
(oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE;
|
||||||
|
|
||||||
bmi_regs.data[offset] = newVal;
|
bmi_regs.chan[channel].bmis = letoh(newVal);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Bus master IDE descriptor table pointer register
|
// Bus master IDE descriptor table pointer register
|
||||||
|
@ -610,8 +563,8 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
|
||||||
if (req->size != sizeof(uint32_t))
|
if (req->size != sizeof(uint32_t))
|
||||||
panic("Invalid BMIDTP write size: %x\n", req->size);
|
panic("Invalid BMIDTP write size: %x\n", req->size);
|
||||||
|
|
||||||
dword = htoa(*(uint32_t *)data & ~0x3);
|
bmi_regs.chan[channel].bmidtp = letoh(
|
||||||
*(uint32_t *)&bmi_regs.data[offset] = dword;
|
letoh(*(uint32_t*)data) & ~0x3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -622,17 +575,17 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
|
||||||
req->size);
|
req->size);
|
||||||
|
|
||||||
// do a default copy of data into the registers
|
// do a default copy of data into the registers
|
||||||
memcpy((void *)&bmi_regs.data[offset], data, req->size);
|
memcpy(&bmi_regs.data[offset], data, req->size);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case COMMAND_BLOCK:
|
case COMMAND_BLOCK:
|
||||||
if (offset == IDE_SELECT_OFFSET) {
|
if (offset == IDE_SELECT_OFFSET) {
|
||||||
uint8_t *devBit = (primary ? &dev[0] : &dev[1]);
|
uint8_t *devBit = &dev[channel];
|
||||||
*devBit = ((*data & IDE_SELECT_DEV_BIT) ? 1 : 0);
|
*devBit = (letoh(*data) & IDE_SELECT_DEV_BIT) ? 1 : 0;
|
||||||
}
|
}
|
||||||
// fall-through ok!
|
// fall-through ok!
|
||||||
case CONTROL_BLOCK:
|
case CONTROL_BLOCK:
|
||||||
disk = getDisk(primary);
|
disk = getDisk(channel);
|
||||||
|
|
||||||
if (disks[disk] == NULL)
|
if (disks[disk] == NULL)
|
||||||
break;
|
break;
|
||||||
|
@ -641,14 +594,12 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
|
||||||
case DATA_OFFSET:
|
case DATA_OFFSET:
|
||||||
switch (req->size) {
|
switch (req->size) {
|
||||||
case sizeof(uint16_t):
|
case sizeof(uint16_t):
|
||||||
word[0] = htoa(*(uint16_t*)data);
|
disks[disk]->write(offset, reg_type, data);
|
||||||
disks[disk]->write(offset, type, (uint8_t*)&word[0]);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case sizeof(uint32_t):
|
case sizeof(uint32_t):
|
||||||
dword = htoa(*(uint32_t*)data);
|
disks[disk]->write(offset, reg_type, data);
|
||||||
disks[disk]->write(offset, type, (uint8_t*)&word[0]);
|
disks[disk]->write(offset, reg_type, &data[2]);
|
||||||
disks[disk]->write(offset, type, (uint8_t*)&word[1]);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("IDE write of data reg invalid size: %#x\n", req->size);
|
panic("IDE write of data reg invalid size: %#x\n", req->size);
|
||||||
|
@ -656,8 +607,7 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (req->size == sizeof(uint8_t)) {
|
if (req->size == sizeof(uint8_t)) {
|
||||||
byte = *data;
|
disks[disk]->write(offset, reg_type, data);
|
||||||
disks[disk]->write(offset, type, &byte);
|
|
||||||
} else
|
} else
|
||||||
panic("IDE write of command reg of invalid size: %#x\n", req->size);
|
panic("IDE write of command reg of invalid size: %#x\n", req->size);
|
||||||
}
|
}
|
||||||
|
@ -667,7 +617,7 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
|
DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
|
||||||
offset, req->size, dword);
|
offset, req->size, *(uint32_t*)data);
|
||||||
|
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
}
|
}
|
||||||
|
@ -697,7 +647,7 @@ IdeController::serialize(std::ostream &os)
|
||||||
// Serialize registers
|
// Serialize registers
|
||||||
SERIALIZE_ARRAY(bmi_regs.data, sizeof(bmi_regs));
|
SERIALIZE_ARRAY(bmi_regs.data, sizeof(bmi_regs));
|
||||||
SERIALIZE_ARRAY(dev, sizeof(dev));
|
SERIALIZE_ARRAY(dev, sizeof(dev));
|
||||||
SERIALIZE_ARRAY(pci_config_regs.data, sizeof(pci_config_regs));
|
SERIALIZE_ARRAY(config_regs.data, sizeof(config_regs));
|
||||||
|
|
||||||
// Serialize internal state
|
// Serialize internal state
|
||||||
SERIALIZE_SCALAR(io_enabled);
|
SERIALIZE_SCALAR(io_enabled);
|
||||||
|
@ -726,7 +676,7 @@ IdeController::unserialize(Checkpoint *cp, const std::string §ion)
|
||||||
// Unserialize registers
|
// Unserialize registers
|
||||||
UNSERIALIZE_ARRAY(bmi_regs.data, sizeof(bmi_regs));
|
UNSERIALIZE_ARRAY(bmi_regs.data, sizeof(bmi_regs));
|
||||||
UNSERIALIZE_ARRAY(dev, sizeof(dev));
|
UNSERIALIZE_ARRAY(dev, sizeof(dev));
|
||||||
UNSERIALIZE_ARRAY(pci_config_regs.data, sizeof(pci_config_regs));
|
UNSERIALIZE_ARRAY(config_regs.data, sizeof(config_regs));
|
||||||
|
|
||||||
// Unserialize internal state
|
// Unserialize internal state
|
||||||
UNSERIALIZE_SCALAR(io_enabled);
|
UNSERIALIZE_SCALAR(io_enabled);
|
||||||
|
|
|
@ -63,16 +63,19 @@
|
||||||
#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET
|
#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET
|
||||||
#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET
|
#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET
|
||||||
|
|
||||||
|
// IDE Timing Register bit fields
|
||||||
|
#define IDETIM_DECODE_EN 0x8000
|
||||||
|
|
||||||
// PCI device specific register byte offsets
|
// PCI device specific register byte offsets
|
||||||
#define IDE_CTRL_CONFIG_START 0x40
|
#define IDE_CTRL_CONF_START 0x40
|
||||||
#define IDE_CTRL_CONFIG_END ((IDE_CTRL_CONFIG_START) + sizeof(pci_config_regs))
|
#define IDE_CTRL_CONF_END ((IDE_CTRL_CONF_START) + sizeof(config_regs))
|
||||||
|
|
||||||
|
|
||||||
typedef enum RegType {
|
enum IdeRegType {
|
||||||
COMMAND_BLOCK = 0,
|
COMMAND_BLOCK,
|
||||||
CONTROL_BLOCK,
|
CONTROL_BLOCK,
|
||||||
BMI_BLOCK
|
BMI_BLOCK
|
||||||
} RegType_t;
|
};
|
||||||
|
|
||||||
class BaseInterface;
|
class BaseInterface;
|
||||||
class Bus;
|
class Bus;
|
||||||
|
@ -91,6 +94,11 @@ class IdeController : public PciDev
|
||||||
{
|
{
|
||||||
friend class IdeDisk;
|
friend class IdeDisk;
|
||||||
|
|
||||||
|
enum IdeChannel {
|
||||||
|
PRIMARY = 0,
|
||||||
|
SECONDARY = 1
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** Primary command block registers */
|
/** Primary command block registers */
|
||||||
Addr pri_cmd_addr;
|
Addr pri_cmd_addr;
|
||||||
|
@ -115,16 +123,25 @@ class IdeController : public PciDev
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint8_t bmic0;
|
uint8_t bmic0;
|
||||||
uint8_t padding_0;
|
uint8_t reserved_0;
|
||||||
uint8_t bmis0;
|
uint8_t bmis0;
|
||||||
uint8_t padding_1;
|
uint8_t reserved_1;
|
||||||
uint32_t bmidtp0;
|
uint32_t bmidtp0;
|
||||||
uint8_t bmic1;
|
uint8_t bmic1;
|
||||||
uint8_t padding_2;
|
uint8_t reserved_2;
|
||||||
uint8_t bmis1;
|
uint8_t bmis1;
|
||||||
uint8_t padding_3;
|
uint8_t reserved_3;
|
||||||
uint32_t bmidtp1;
|
uint32_t bmidtp1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t bmic;
|
||||||
|
uint8_t reserved_4;
|
||||||
|
uint8_t bmis;
|
||||||
|
uint8_t reserved_5;
|
||||||
|
uint32_t bmidtp;
|
||||||
|
} chan[2];
|
||||||
|
|
||||||
} bmi_regs;
|
} bmi_regs;
|
||||||
/** Shadows of the device select bit */
|
/** Shadows of the device select bit */
|
||||||
uint8_t dev[2];
|
uint8_t dev[2];
|
||||||
|
@ -133,25 +150,17 @@ class IdeController : public PciDev
|
||||||
uint8_t data[22];
|
uint8_t data[22];
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint32_t idetim;
|
uint16_t idetim0;
|
||||||
|
uint16_t idetim1;
|
||||||
uint8_t sidetim;
|
uint8_t sidetim;
|
||||||
uint8_t reserved_45;
|
uint8_t reserved_0[3];
|
||||||
uint8_t reserved_46;
|
|
||||||
uint8_t reserved_47;
|
|
||||||
uint8_t udmactl;
|
uint8_t udmactl;
|
||||||
uint8_t reserved_49;
|
uint8_t reserved_1;
|
||||||
uint16_t udmatim;
|
uint16_t udmatim;
|
||||||
uint8_t reserved_4c;
|
uint8_t reserved_2[8];
|
||||||
uint8_t reserved_4d;
|
|
||||||
uint8_t reserved_4e;
|
|
||||||
uint8_t reserved_4f;
|
|
||||||
uint8_t reserved_50;
|
|
||||||
uint8_t reserved_51;
|
|
||||||
uint8_t reserved_52;
|
|
||||||
uint8_t reserved_53;
|
|
||||||
uint16_t ideconfig;
|
uint16_t ideconfig;
|
||||||
};
|
};
|
||||||
} pci_config_regs;
|
} config_regs;
|
||||||
|
|
||||||
// Internal management variables
|
// Internal management variables
|
||||||
bool io_enabled;
|
bool io_enabled;
|
||||||
|
@ -164,11 +173,11 @@ class IdeController : public PciDev
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** Parse the access address to pass on to device */
|
/** Parse the access address to pass on to device */
|
||||||
void parseAddr(const Addr &addr, Addr &offset, bool &primary,
|
void parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel,
|
||||||
RegType_t &type);
|
IdeRegType ®_type);
|
||||||
|
|
||||||
/** Select the disk based on the channel and device bit */
|
/** Select the disk based on the channel and device bit */
|
||||||
int getDisk(bool primary);
|
int getDisk(IdeChannel channel);
|
||||||
|
|
||||||
/** Select the disk based on a pointer */
|
/** Select the disk based on a pointer */
|
||||||
int getDisk(IdeDisk *diskPtr);
|
int getDisk(IdeDisk *diskPtr);
|
||||||
|
@ -192,8 +201,8 @@ class IdeController : public PciDev
|
||||||
IdeController(Params *p);
|
IdeController(Params *p);
|
||||||
~IdeController();
|
~IdeController();
|
||||||
|
|
||||||
virtual void WriteConfig(int offset, int size, uint32_t data);
|
virtual void writeConfig(int offset, int size, const uint8_t *data);
|
||||||
virtual void ReadConfig(int offset, int size, uint8_t *data);
|
virtual void readConfig(int offset, int size, uint8_t *data);
|
||||||
|
|
||||||
void setDmaComplete(IdeDisk *disk);
|
void setDmaComplete(IdeDisk *disk);
|
||||||
|
|
||||||
|
|
|
@ -162,6 +162,8 @@ IdeDisk::reset(int id)
|
||||||
// set the device ready bit
|
// set the device ready bit
|
||||||
status = STATUS_DRDY_BIT;
|
status = STATUS_DRDY_BIT;
|
||||||
|
|
||||||
|
/* The error register must be set to 0x1 on start-up to
|
||||||
|
indicate that no diagnostic error was detected */
|
||||||
cmdReg.error = 0x1;
|
cmdReg.error = 0x1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,16 +214,16 @@ IdeDisk::bytesInDmaPage(Addr curAddr, uint32_t bytesLeft)
|
||||||
////
|
////
|
||||||
|
|
||||||
void
|
void
|
||||||
IdeDisk::read(const Addr &offset, RegType_t type, uint8_t *data)
|
IdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data)
|
||||||
{
|
{
|
||||||
DevAction_t action = ACT_NONE;
|
DevAction_t action = ACT_NONE;
|
||||||
|
|
||||||
switch (type) {
|
switch (reg_type) {
|
||||||
case COMMAND_BLOCK:
|
case COMMAND_BLOCK:
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
// Data transfers occur two bytes at a time
|
// Data transfers occur two bytes at a time
|
||||||
case DATA_OFFSET:
|
case DATA_OFFSET:
|
||||||
memcpy(data, &cmdReg.data, sizeof(uint16_t));
|
*(uint16_t*)data = cmdReg.data;
|
||||||
action = ACT_DATA_READ_SHORT;
|
action = ACT_DATA_READ_SHORT;
|
||||||
break;
|
break;
|
||||||
case ERROR_OFFSET:
|
case ERROR_OFFSET:
|
||||||
|
@ -265,15 +267,15 @@ IdeDisk::read(const Addr &offset, RegType_t type, uint8_t *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
IdeDisk::write(const Addr &offset, RegType_t type, const uint8_t *data)
|
IdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data)
|
||||||
{
|
{
|
||||||
DevAction_t action = ACT_NONE;
|
DevAction_t action = ACT_NONE;
|
||||||
|
|
||||||
switch (type) {
|
switch (reg_type) {
|
||||||
case COMMAND_BLOCK:
|
case COMMAND_BLOCK:
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case DATA_OFFSET:
|
case DATA_OFFSET:
|
||||||
memcpy(&cmdReg.data, data, sizeof(uint16_t));
|
cmdReg.data = *(uint16_t*)data;
|
||||||
action = ACT_DATA_WRITE_SHORT;
|
action = ACT_DATA_WRITE_SHORT;
|
||||||
break;
|
break;
|
||||||
case FEATURES_OFFSET:
|
case FEATURES_OFFSET:
|
||||||
|
|
|
@ -270,8 +270,8 @@ class IdeDisk : public SimObject
|
||||||
}
|
}
|
||||||
|
|
||||||
// Device register read/write
|
// Device register read/write
|
||||||
void read(const Addr &offset, RegType_t type, uint8_t *data);
|
void read(const Addr &offset, IdeRegType regtype, uint8_t *data);
|
||||||
void write(const Addr &offset, RegType_t type, const uint8_t *data);
|
void write(const Addr &offset, IdeRegType regtype, const uint8_t *data);
|
||||||
|
|
||||||
// Start/abort functions
|
// Start/abort functions
|
||||||
void startDma(const uint32_t &prdTableBase);
|
void startDma(const uint32_t &prdTableBase);
|
||||||
|
|
139
dev/isa_fake.cc
Executable file
139
dev/isa_fake.cc
Executable file
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2004-2005 The Regents of The University of Michigan
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met: redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer;
|
||||||
|
* redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution;
|
||||||
|
* neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
* Isa Fake Device implementation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "base/trace.hh"
|
||||||
|
#include "cpu/exec_context.hh"
|
||||||
|
#include "dev/isa_fake.hh"
|
||||||
|
#include "mem/bus/bus.hh"
|
||||||
|
#include "mem/bus/pio_interface.hh"
|
||||||
|
#include "mem/bus/pio_interface_impl.hh"
|
||||||
|
#include "mem/functional/memory_control.hh"
|
||||||
|
#include "sim/builder.hh"
|
||||||
|
#include "sim/system.hh"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
IsaFake::IsaFake(const string &name, Addr a, MemoryController *mmu,
|
||||||
|
HierParams *hier, Bus *bus, Addr size)
|
||||||
|
: PioDevice(name, NULL), addr(a)
|
||||||
|
{
|
||||||
|
mmu->add_child(this, RangeSize(addr, size));
|
||||||
|
|
||||||
|
if (bus) {
|
||||||
|
pioInterface = newPioInterface(name, hier, bus, this,
|
||||||
|
&IsaFake::cacheAccess);
|
||||||
|
pioInterface->addAddrRange(RangeSize(addr, size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Fault
|
||||||
|
IsaFake::read(MemReqPtr &req, uint8_t *data)
|
||||||
|
{
|
||||||
|
DPRINTF(Tsunami, "read va=%#x size=%d\n",
|
||||||
|
req->vaddr, req->size);
|
||||||
|
|
||||||
|
#if TRACING_ON
|
||||||
|
Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (req->size) {
|
||||||
|
|
||||||
|
case sizeof(uint64_t):
|
||||||
|
*(uint64_t*)data = 0xFFFFFFFFFFFFFFFFULL;
|
||||||
|
return No_Fault;
|
||||||
|
case sizeof(uint32_t):
|
||||||
|
*(uint32_t*)data = 0xFFFFFFFF;
|
||||||
|
return No_Fault;
|
||||||
|
case sizeof(uint16_t):
|
||||||
|
*(uint16_t*)data = 0xFFFF;
|
||||||
|
return No_Fault;
|
||||||
|
case sizeof(uint8_t):
|
||||||
|
*(uint8_t*)data = 0xFF;
|
||||||
|
return No_Fault;
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic("invalid access size(?) for PCI configspace!\n");
|
||||||
|
}
|
||||||
|
DPRINTFN("Isa FakeSMC ERROR: read daddr=%#x size=%d\n", daddr, req->size);
|
||||||
|
|
||||||
|
return No_Fault;
|
||||||
|
}
|
||||||
|
|
||||||
|
Fault
|
||||||
|
IsaFake::write(MemReqPtr &req, const uint8_t *data)
|
||||||
|
{
|
||||||
|
DPRINTF(Tsunami, "write - va=%#x size=%d \n",
|
||||||
|
req->vaddr, req->size);
|
||||||
|
|
||||||
|
//:Addr daddr = (req->paddr & addr_mask) >> 6;
|
||||||
|
|
||||||
|
return No_Fault;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tick
|
||||||
|
IsaFake::cacheAccess(MemReqPtr &req)
|
||||||
|
{
|
||||||
|
return curTick;
|
||||||
|
}
|
||||||
|
|
||||||
|
BEGIN_DECLARE_SIM_OBJECT_PARAMS(IsaFake)
|
||||||
|
|
||||||
|
SimObjectParam<MemoryController *> mmu;
|
||||||
|
Param<Addr> addr;
|
||||||
|
SimObjectParam<Bus*> io_bus;
|
||||||
|
Param<Tick> pio_latency;
|
||||||
|
SimObjectParam<HierParams *> hier;
|
||||||
|
Param<Addr> size;
|
||||||
|
|
||||||
|
END_DECLARE_SIM_OBJECT_PARAMS(IsaFake)
|
||||||
|
|
||||||
|
BEGIN_INIT_SIM_OBJECT_PARAMS(IsaFake)
|
||||||
|
|
||||||
|
INIT_PARAM(mmu, "Memory Controller"),
|
||||||
|
INIT_PARAM(addr, "Device Address"),
|
||||||
|
INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL),
|
||||||
|
INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000),
|
||||||
|
INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
|
||||||
|
INIT_PARAM_DFLT(size, "Size of address range", 0x8)
|
||||||
|
|
||||||
|
END_INIT_SIM_OBJECT_PARAMS(IsaFake)
|
||||||
|
|
||||||
|
CREATE_SIM_OBJECT(IsaFake)
|
||||||
|
{
|
||||||
|
return new IsaFake(getInstanceName(), addr, mmu, hier, io_bus, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_SIM_OBJECT("IsaFake", IsaFake)
|
85
dev/isa_fake.hh
Executable file
85
dev/isa_fake.hh
Executable file
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2004-2005 The Regents of The University of Michigan
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met: redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer;
|
||||||
|
* redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution;
|
||||||
|
* neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
* Declaration of a fake device.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ISA_FAKE_HH__
|
||||||
|
#define __ISA_FAKE_HH__
|
||||||
|
|
||||||
|
#include "dev/tsunami.hh"
|
||||||
|
#include "base/range.hh"
|
||||||
|
#include "dev/io_device.hh"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IsaFake is a device that returns -1 on all reads and
|
||||||
|
* accepts all writes. It is meant to be placed at an address range
|
||||||
|
* so that an mcheck doesn't occur when an os probes a piece of hw
|
||||||
|
* that doesn't exist (e.g. UARTs1-3).
|
||||||
|
*/
|
||||||
|
class IsaFake : public PioDevice
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/** The address in memory that we respond to */
|
||||||
|
Addr addr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* The constructor for Tsunmami Fake just registers itself with the MMU.
|
||||||
|
* @param name name of this device.
|
||||||
|
* @param a address to respond to.
|
||||||
|
* @param mmu the mmu we register with.
|
||||||
|
* @param size number of addresses to respond to
|
||||||
|
*/
|
||||||
|
IsaFake(const std::string &name, Addr a, MemoryController *mmu,
|
||||||
|
HierParams *hier, Bus *bus, Addr size = 0x8);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This read always returns -1.
|
||||||
|
* @param req The memory request.
|
||||||
|
* @param data Where to put the data.
|
||||||
|
*/
|
||||||
|
virtual Fault read(MemReqPtr &req, uint8_t *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All writes are simply ignored.
|
||||||
|
* @param req The memory request.
|
||||||
|
* @param data the data to not write.
|
||||||
|
*/
|
||||||
|
virtual Fault write(MemReqPtr &req, const uint8_t *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return how long this access will take.
|
||||||
|
* @param req the memory request to calcuate
|
||||||
|
* @return Tick when the request is done
|
||||||
|
*/
|
||||||
|
Tick cacheAccess(MemReqPtr &req);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __ISA_FAKE_HH__
|
|
@ -491,10 +491,10 @@ NSGigE::regStats()
|
||||||
* This is to read the PCI general configuration registers
|
* This is to read the PCI general configuration registers
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
NSGigE::ReadConfig(int offset, int size, uint8_t *data)
|
NSGigE::readConfig(int offset, int size, uint8_t *data)
|
||||||
{
|
{
|
||||||
if (offset < PCI_DEVICE_SPECIFIC)
|
if (offset < PCI_DEVICE_SPECIFIC)
|
||||||
PciDev::ReadConfig(offset, size, data);
|
PciDev::readConfig(offset, size, data);
|
||||||
else
|
else
|
||||||
panic("Device specific PCI config space not implemented!\n");
|
panic("Device specific PCI config space not implemented!\n");
|
||||||
}
|
}
|
||||||
|
@ -503,10 +503,10 @@ NSGigE::ReadConfig(int offset, int size, uint8_t *data)
|
||||||
* This is to write to the PCI general configuration registers
|
* This is to write to the PCI general configuration registers
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
NSGigE::WriteConfig(int offset, int size, uint32_t data)
|
NSGigE::writeConfig(int offset, int size, const uint8_t* data)
|
||||||
{
|
{
|
||||||
if (offset < PCI_DEVICE_SPECIFIC)
|
if (offset < PCI_DEVICE_SPECIFIC)
|
||||||
PciDev::WriteConfig(offset, size, data);
|
PciDev::writeConfig(offset, size, data);
|
||||||
else
|
else
|
||||||
panic("Device specific PCI config space not implemented!\n");
|
panic("Device specific PCI config space not implemented!\n");
|
||||||
|
|
||||||
|
@ -577,7 +577,7 @@ NSGigE::read(MemReqPtr &req, uint8_t *data)
|
||||||
if (daddr > LAST && daddr <= RESERVED) {
|
if (daddr > LAST && daddr <= RESERVED) {
|
||||||
panic("Accessing reserved register");
|
panic("Accessing reserved register");
|
||||||
} else if (daddr > RESERVED && daddr <= 0x3FC) {
|
} else if (daddr > RESERVED && daddr <= 0x3FC) {
|
||||||
ReadConfig(daddr & 0xff, req->size, data);
|
readConfig(daddr & 0xff, req->size, data);
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
} else if (daddr >= MIB_START && daddr <= MIB_END) {
|
} else if (daddr >= MIB_START && daddr <= MIB_END) {
|
||||||
// don't implement all the MIB's. hopefully the kernel
|
// don't implement all the MIB's. hopefully the kernel
|
||||||
|
@ -797,7 +797,7 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data)
|
||||||
if (daddr > LAST && daddr <= RESERVED) {
|
if (daddr > LAST && daddr <= RESERVED) {
|
||||||
panic("Accessing reserved register");
|
panic("Accessing reserved register");
|
||||||
} else if (daddr > RESERVED && daddr <= 0x3FC) {
|
} else if (daddr > RESERVED && daddr <= 0x3FC) {
|
||||||
WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
|
writeConfig(daddr & 0xff, req->size, data);
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
} else if (daddr > 0x3FC)
|
} else if (daddr > 0x3FC)
|
||||||
panic("Something is messed up!\n");
|
panic("Something is messed up!\n");
|
||||||
|
|
|
@ -392,8 +392,8 @@ class NSGigE : public PciDev
|
||||||
~NSGigE();
|
~NSGigE();
|
||||||
const Params *params() const { return (const Params *)_params; }
|
const Params *params() const { return (const Params *)_params; }
|
||||||
|
|
||||||
virtual void WriteConfig(int offset, int size, uint32_t data);
|
virtual void writeConfig(int offset, int size, const uint8_t *data);
|
||||||
virtual void ReadConfig(int offset, int size, uint8_t *data);
|
virtual void readConfig(int offset, int size, uint8_t *data);
|
||||||
|
|
||||||
virtual Fault read(MemReqPtr &req, uint8_t *data);
|
virtual Fault read(MemReqPtr &req, uint8_t *data);
|
||||||
virtual Fault write(MemReqPtr &req, const uint8_t *data);
|
virtual Fault write(MemReqPtr &req, const uint8_t *data);
|
||||||
|
|
|
@ -65,7 +65,7 @@ PciConfigAll::PciConfigAll(const string &name,
|
||||||
// Make all the pointers to devices null
|
// Make all the pointers to devices null
|
||||||
for(int x=0; x < MAX_PCI_DEV; x++)
|
for(int x=0; x < MAX_PCI_DEV; x++)
|
||||||
for(int y=0; y < MAX_PCI_FUNC; y++)
|
for(int y=0; y < MAX_PCI_FUNC; y++)
|
||||||
devices[x][y] = NULL;
|
devices[x][y] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If two interrupts share the same line largely bad things will happen.
|
// If two interrupts share the same line largely bad things will happen.
|
||||||
|
@ -130,7 +130,7 @@ PciConfigAll::read(MemReqPtr &req, uint8_t *data)
|
||||||
case sizeof(uint32_t):
|
case sizeof(uint32_t):
|
||||||
case sizeof(uint16_t):
|
case sizeof(uint16_t):
|
||||||
case sizeof(uint8_t):
|
case sizeof(uint8_t):
|
||||||
devices[device][func]->ReadConfig(reg, req->size, data);
|
devices[device][func]->readConfig(reg, req->size, data);
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
default:
|
default:
|
||||||
panic("invalid access size(?) for PCI configspace!\n");
|
panic("invalid access size(?) for PCI configspace!\n");
|
||||||
|
@ -152,30 +152,17 @@ PciConfigAll::write(MemReqPtr &req, const uint8_t *data)
|
||||||
int func = (daddr >> 8) & 0x7;
|
int func = (daddr >> 8) & 0x7;
|
||||||
int reg = daddr & 0xFF;
|
int reg = daddr & 0xFF;
|
||||||
|
|
||||||
uint32_t word_value = 0;
|
|
||||||
|
|
||||||
if (devices[device][func] == NULL)
|
if (devices[device][func] == NULL)
|
||||||
panic("Attempting to write to config space on non-existant device\n");
|
panic("Attempting to write to config space on non-existant device\n");
|
||||||
else {
|
else if (req->size != sizeof(uint8_t) &&
|
||||||
switch (req->size) {
|
req->size != sizeof(uint16_t) &&
|
||||||
case sizeof(uint8_t):
|
req->size != sizeof(uint32_t))
|
||||||
word_value = *(uint8_t*)data;
|
panic("invalid access size(?) for PCI configspace!\n");
|
||||||
break;
|
|
||||||
case sizeof(uint16_t):
|
|
||||||
word_value = *(uint16_t*)data;
|
|
||||||
break;
|
|
||||||
case sizeof(uint32_t):
|
|
||||||
word_value = *(uint32_t*)data;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
panic("invalid access size(?) for PCI configspace!\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINTF(PciConfigAll, "write - va=%#x size=%d data=%#x\n",
|
DPRINTF(PciConfigAll, "write - va=%#x size=%d data=%#x\n",
|
||||||
req->vaddr, req->size, word_value);
|
req->vaddr, req->size, *(uint32_t*)data);
|
||||||
|
|
||||||
devices[device][func]->WriteConfig(reg, req->size, word_value);
|
devices[device][func]->writeConfig(reg, req->size, data);
|
||||||
|
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
}
|
}
|
||||||
|
|
210
dev/pcidev.cc
210
dev/pcidev.cc
|
@ -71,31 +71,20 @@ PciDev::PciDev(Params *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PciDev::ReadConfig(int offset, int size, uint8_t *data)
|
PciDev::readConfig(int offset, int size, uint8_t *data)
|
||||||
{
|
{
|
||||||
union {
|
|
||||||
uint8_t byte;
|
|
||||||
uint16_t word;
|
|
||||||
uint32_t dword;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (offset >= PCI_DEVICE_SPECIFIC)
|
if (offset >= PCI_DEVICE_SPECIFIC)
|
||||||
panic("Device specific PCI config space not implemented!\n");
|
panic("Device specific PCI config space not implemented!\n");
|
||||||
|
|
||||||
dword = 0;
|
|
||||||
|
|
||||||
switch(size) {
|
switch(size) {
|
||||||
case sizeof(uint8_t):
|
case sizeof(uint8_t):
|
||||||
memcpy(&byte, &config.data[offset], size);
|
*data = config.data[offset];
|
||||||
*data = byte;
|
|
||||||
break;
|
break;
|
||||||
case sizeof(uint16_t):
|
case sizeof(uint16_t):
|
||||||
memcpy(&byte, &config.data[offset], size);
|
*(uint16_t*)data = *(uint16_t*)&config.data[offset];
|
||||||
*(uint16_t*)data = htoa(word);
|
|
||||||
break;
|
break;
|
||||||
case sizeof(uint32_t):
|
case sizeof(uint32_t):
|
||||||
memcpy(&byte, &config.data[offset], size);
|
*(uint32_t*)data = *(uint32_t*)&config.data[offset];
|
||||||
*(uint32_t*)data = htoa(dword);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Invalid PCI configuration read size!\n");
|
panic("Invalid PCI configuration read size!\n");
|
||||||
|
@ -104,32 +93,32 @@ PciDev::ReadConfig(int offset, int size, uint8_t *data)
|
||||||
DPRINTF(PCIDEV,
|
DPRINTF(PCIDEV,
|
||||||
"read device: %#x function: %#x register: %#x %d bytes: data: %#x\n",
|
"read device: %#x function: %#x register: %#x %d bytes: data: %#x\n",
|
||||||
params()->deviceNum, params()->functionNum, offset, size,
|
params()->deviceNum, params()->functionNum, offset, size,
|
||||||
htoa(dword));
|
*(uint32_t*)data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PciDev::WriteConfig(int offset, int size, uint32_t data)
|
PciDev::writeConfig(int offset, int size, const uint8_t *data)
|
||||||
{
|
{
|
||||||
if (offset >= PCI_DEVICE_SPECIFIC)
|
if (offset >= PCI_DEVICE_SPECIFIC)
|
||||||
panic("Device specific PCI config space not implemented!\n");
|
panic("Device specific PCI config space not implemented!\n");
|
||||||
|
|
||||||
uint32_t barnum;
|
uint8_t &data8 = *(uint8_t*)data;
|
||||||
|
uint16_t &data16 = *(uint16_t*)data;
|
||||||
|
uint32_t &data32 = *(uint32_t*)data;
|
||||||
|
|
||||||
DPRINTF(PCIDEV,
|
DPRINTF(PCIDEV,
|
||||||
"write device: %#x function: %#x reg: %#x size: %d data: %#x\n",
|
"write device: %#x function: %#x reg: %#x size: %d data: %#x\n",
|
||||||
params()->deviceNum, params()->functionNum, offset, size,
|
params()->deviceNum, params()->functionNum, offset, size, data32);
|
||||||
data);
|
|
||||||
|
|
||||||
barnum = (offset - PCI0_BASE_ADDR0) >> 2;
|
|
||||||
|
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case sizeof(uint8_t): // 1-byte access
|
case sizeof(uint8_t): // 1-byte access
|
||||||
uint8_t byte_value = data;
|
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case PCI0_INTERRUPT_LINE:
|
case PCI0_INTERRUPT_LINE:
|
||||||
|
config.interruptLine = data8;
|
||||||
case PCI_CACHE_LINE_SIZE:
|
case PCI_CACHE_LINE_SIZE:
|
||||||
|
config.cacheLineSize = data8;
|
||||||
case PCI_LATENCY_TIMER:
|
case PCI_LATENCY_TIMER:
|
||||||
*(uint8_t *)&config.data[offset] = htoa(byte_value);
|
config.latencyTimer = data8;
|
||||||
break;
|
break;
|
||||||
/* Do nothing for these read-only registers */
|
/* Do nothing for these read-only registers */
|
||||||
case PCI0_INTERRUPT_PIN:
|
case PCI0_INTERRUPT_PIN:
|
||||||
|
@ -144,21 +133,20 @@ PciDev::WriteConfig(int offset, int size, uint32_t data)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case sizeof(uint16_t): // 2-byte access
|
case sizeof(uint16_t): // 2-byte access
|
||||||
uint16_t half_value = data;
|
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case PCI_COMMAND:
|
case PCI_COMMAND:
|
||||||
|
config.command = data16;
|
||||||
case PCI_STATUS:
|
case PCI_STATUS:
|
||||||
|
config.status = data16;
|
||||||
case PCI_CACHE_LINE_SIZE:
|
case PCI_CACHE_LINE_SIZE:
|
||||||
*(uint16_t *)&config.data[offset] = htoa(half_value);
|
config.cacheLineSize = data16;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic("writing to a read only register");
|
panic("writing to a read only register");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case sizeof(uint32_t): // 4-byte access
|
case sizeof(uint32_t): // 4-byte access
|
||||||
uint32_t word_value = data;
|
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case PCI0_BASE_ADDR0:
|
case PCI0_BASE_ADDR0:
|
||||||
case PCI0_BASE_ADDR1:
|
case PCI0_BASE_ADDR1:
|
||||||
|
@ -166,87 +154,65 @@ PciDev::WriteConfig(int offset, int size, uint32_t data)
|
||||||
case PCI0_BASE_ADDR3:
|
case PCI0_BASE_ADDR3:
|
||||||
case PCI0_BASE_ADDR4:
|
case PCI0_BASE_ADDR4:
|
||||||
case PCI0_BASE_ADDR5:
|
case PCI0_BASE_ADDR5:
|
||||||
|
|
||||||
|
uint32_t barnum, bar_mask;
|
||||||
|
Addr base_addr, base_size, space_base;
|
||||||
|
|
||||||
|
barnum = BAR_NUMBER(offset);
|
||||||
|
|
||||||
|
if (BAR_IO_SPACE(letoh(config.baseAddr[barnum]))) {
|
||||||
|
bar_mask = BAR_IO_MASK;
|
||||||
|
space_base = TSUNAMI_PCI0_IO;
|
||||||
|
} else {
|
||||||
|
bar_mask = BAR_MEM_MASK;
|
||||||
|
space_base = TSUNAMI_PCI0_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
// Writing 0xffffffff to a BAR tells the card to set the
|
// Writing 0xffffffff to a BAR tells the card to set the
|
||||||
// value of the bar
|
// value of the bar to size of memory it needs
|
||||||
// to size of memory it needs
|
if (letoh(data32) == 0xffffffff) {
|
||||||
if (word_value == 0xffffffff) {
|
|
||||||
// This is I/O Space, bottom two bits are read only
|
// This is I/O Space, bottom two bits are read only
|
||||||
if (htoa(config.data[offset]) & 0x1) {
|
|
||||||
*(uint32_t *)&config.data[offset] = htoa(
|
config.baseAddr[barnum] = letoh(
|
||||||
(~(BARSize[barnum] - 1) & ~0x3) |
|
(~(BARSize[barnum] - 1) & ~bar_mask) |
|
||||||
(htoa(config.data[offset]) & 0x3));
|
(letoh(config.baseAddr[barnum]) & bar_mask));
|
||||||
} else {
|
|
||||||
// This is memory space, bottom four bits are read only
|
|
||||||
*(uint32_t *)&config.data[offset] = htoa(
|
|
||||||
(~(BARSize[barnum] - 1) & ~0xF) |
|
|
||||||
(htoa(config.data[offset]) & 0xF));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
MemoryController *mmu = params()->mmu;
|
MemoryController *mmu = params()->mmu;
|
||||||
|
|
||||||
// This is I/O Space, bottom two bits are read only
|
config.baseAddr[barnum] = letoh(
|
||||||
if(htoa(config.data[offset]) & 0x1) {
|
(letoh(data32) & ~bar_mask) |
|
||||||
*(uint32_t *)&config.data[offset] =
|
(letoh(config.baseAddr[barnum]) & bar_mask));
|
||||||
htoa((word_value & ~0x3) |
|
|
||||||
(htoa(config.data[offset]) & 0x3));
|
|
||||||
|
|
||||||
if (word_value & ~0x1) {
|
if (letoh(config.baseAddr[barnum]) & ~bar_mask) {
|
||||||
Addr base_addr = (word_value & ~0x1) + TSUNAMI_PCI0_IO;
|
base_addr = (letoh(data32) & ~bar_mask) + space_base;
|
||||||
Addr base_size = BARSize[barnum];
|
base_size = BARSize[barnum];
|
||||||
|
|
||||||
// It's never been set
|
// It's never been set
|
||||||
if (BARAddrs[barnum] == 0)
|
if (BARAddrs[barnum] == 0)
|
||||||
mmu->add_child((FunctionalMemory *)this,
|
mmu->add_child((FunctionalMemory *)this,
|
||||||
RangeSize(base_addr, base_size));
|
RangeSize(base_addr, base_size));
|
||||||
else
|
else
|
||||||
mmu->update_child((FunctionalMemory *)this,
|
mmu->update_child((FunctionalMemory *)this,
|
||||||
RangeSize(BARAddrs[barnum],
|
RangeSize(BARAddrs[barnum], base_size),
|
||||||
base_size),
|
RangeSize(base_addr, base_size));
|
||||||
RangeSize(base_addr, base_size));
|
|
||||||
|
|
||||||
BARAddrs[barnum] = base_addr;
|
BARAddrs[barnum] = base_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
// This is memory space, bottom four bits are read only
|
|
||||||
*(uint32_t *)&config.data[offset] =
|
|
||||||
htoa((word_value & ~0xF) |
|
|
||||||
(htoa(config.data[offset]) & 0xF));
|
|
||||||
|
|
||||||
if (word_value & ~0x3) {
|
|
||||||
Addr base_addr = (word_value & ~0x3) +
|
|
||||||
TSUNAMI_PCI0_MEMORY;
|
|
||||||
|
|
||||||
Addr base_size = BARSize[barnum];
|
|
||||||
|
|
||||||
// It's never been set
|
|
||||||
if (BARAddrs[barnum] == 0)
|
|
||||||
mmu->add_child((FunctionalMemory *)this,
|
|
||||||
RangeSize(base_addr, base_size));
|
|
||||||
else
|
|
||||||
mmu->update_child((FunctionalMemory *)this,
|
|
||||||
RangeSize(BARAddrs[barnum],
|
|
||||||
base_size),
|
|
||||||
RangeSize(base_addr, base_size));
|
|
||||||
|
|
||||||
BARAddrs[barnum] = base_addr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PCI0_ROM_BASE_ADDR:
|
case PCI0_ROM_BASE_ADDR:
|
||||||
if (word_value == 0xfffffffe)
|
if (letoh(data32) == 0xfffffffe)
|
||||||
*(uint32_t *)&config.data[offset] = 0xffffffff;
|
config.expansionROM = letoh(0xffffffff);
|
||||||
else
|
else
|
||||||
*(uint32_t *)&config.data[offset] = htoa(word_value);
|
config.expansionROM = data32;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PCI_COMMAND:
|
case PCI_COMMAND:
|
||||||
// This could also clear some of the error bits in the Status
|
// This could also clear some of the error bits in the Status
|
||||||
// register. However they should never get set, so lets ignore
|
// register. However they should never get set, so lets ignore
|
||||||
// it for now
|
// it for now
|
||||||
*(uint16_t *)&config.data[offset] = htoa(half_value);
|
config.command = data16;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -262,17 +228,17 @@ PciDev::WriteConfig(int offset, int size, uint32_t data)
|
||||||
void
|
void
|
||||||
PciDev::serialize(ostream &os)
|
PciDev::serialize(ostream &os)
|
||||||
{
|
{
|
||||||
SERIALIZE_ARRAY(BARSize, 6);
|
SERIALIZE_ARRAY(BARSize, sizeof(BARSize));
|
||||||
SERIALIZE_ARRAY(BARAddrs, 6);
|
SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs));
|
||||||
SERIALIZE_ARRAY(config.data, 64);
|
SERIALIZE_ARRAY(config.data, sizeof(config.data));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PciDev::unserialize(Checkpoint *cp, const std::string §ion)
|
PciDev::unserialize(Checkpoint *cp, const std::string §ion)
|
||||||
{
|
{
|
||||||
UNSERIALIZE_ARRAY(BARSize, 6);
|
UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize));
|
||||||
UNSERIALIZE_ARRAY(BARAddrs, 6);
|
UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs));
|
||||||
UNSERIALIZE_ARRAY(config.data, 64);
|
UNSERIALIZE_ARRAY(config.data, sizeof(config.data));
|
||||||
|
|
||||||
// Add the MMU mappings for the BARs
|
// Add the MMU mappings for the BARs
|
||||||
for (int i=0; i < 6; i++) {
|
for (int i=0; i < 6; i++) {
|
||||||
|
@ -361,33 +327,33 @@ CREATE_SIM_OBJECT(PciConfigData)
|
||||||
{
|
{
|
||||||
PciConfigData *data = new PciConfigData(getInstanceName());
|
PciConfigData *data = new PciConfigData(getInstanceName());
|
||||||
|
|
||||||
data->config.hdr.vendor = htoa(VendorID);
|
data->config.vendor = htole(VendorID);
|
||||||
data->config.hdr.device = htoa(DeviceID);
|
data->config.device = htole(DeviceID);
|
||||||
data->config.hdr.command = htoa(Command);
|
data->config.command = htole(Command);
|
||||||
data->config.hdr.status = htoa(Status);
|
data->config.status = htole(Status);
|
||||||
data->config.hdr.revision = htoa(Revision);
|
data->config.revision = htole(Revision);
|
||||||
data->config.hdr.progIF = htoa(ProgIF);
|
data->config.progIF = htole(ProgIF);
|
||||||
data->config.hdr.subClassCode = htoa(SubClassCode);
|
data->config.subClassCode = htole(SubClassCode);
|
||||||
data->config.hdr.classCode = htoa(ClassCode);
|
data->config.classCode = htole(ClassCode);
|
||||||
data->config.hdr.cacheLineSize = htoa(CacheLineSize);
|
data->config.cacheLineSize = htole(CacheLineSize);
|
||||||
data->config.hdr.latencyTimer = htoa(LatencyTimer);
|
data->config.latencyTimer = htole(LatencyTimer);
|
||||||
data->config.hdr.headerType = htoa(HeaderType);
|
data->config.headerType = htole(HeaderType);
|
||||||
data->config.hdr.bist = htoa(BIST);
|
data->config.bist = htole(BIST);
|
||||||
|
|
||||||
data->config.hdr.pci0.baseAddr0 = htoa(BAR0);
|
data->config.baseAddr0 = htole(BAR0);
|
||||||
data->config.hdr.pci0.baseAddr1 = htoa(BAR1);
|
data->config.baseAddr1 = htole(BAR1);
|
||||||
data->config.hdr.pci0.baseAddr2 = htoa(BAR2);
|
data->config.baseAddr2 = htole(BAR2);
|
||||||
data->config.hdr.pci0.baseAddr3 = htoa(BAR3);
|
data->config.baseAddr3 = htole(BAR3);
|
||||||
data->config.hdr.pci0.baseAddr4 = htoa(BAR4);
|
data->config.baseAddr4 = htole(BAR4);
|
||||||
data->config.hdr.pci0.baseAddr5 = htoa(BAR5);
|
data->config.baseAddr5 = htole(BAR5);
|
||||||
data->config.hdr.pci0.cardbusCIS = htoa(CardbusCIS);
|
data->config.cardbusCIS = htole(CardbusCIS);
|
||||||
data->config.hdr.pci0.subsystemVendorID = htoa(SubsystemVendorID);
|
data->config.subsystemVendorID = htole(SubsystemVendorID);
|
||||||
data->config.hdr.pci0.subsystemID = htoa(SubsystemVendorID);
|
data->config.subsystemID = htole(SubsystemVendorID);
|
||||||
data->config.hdr.pci0.expansionROM = htoa(ExpansionROM);
|
data->config.expansionROM = htole(ExpansionROM);
|
||||||
data->config.hdr.pci0.interruptLine = htoa(InterruptLine);
|
data->config.interruptLine = htole(InterruptLine);
|
||||||
data->config.hdr.pci0.interruptPin = htoa(InterruptPin);
|
data->config.interruptPin = htole(InterruptPin);
|
||||||
data->config.hdr.pci0.minimumGrant = htoa(MinimumGrant);
|
data->config.minimumGrant = htole(MinimumGrant);
|
||||||
data->config.hdr.pci0.maximumLatency = htoa(MaximumLatency);
|
data->config.maximumLatency = htole(MaximumLatency);
|
||||||
|
|
||||||
data->BARSize[0] = BAR0Size;
|
data->BARSize[0] = BAR0Size;
|
||||||
data->BARSize[1] = BAR1Size;
|
data->BARSize[1] = BAR1Size;
|
||||||
|
|
|
@ -37,6 +37,12 @@
|
||||||
#include "dev/pcireg.h"
|
#include "dev/pcireg.h"
|
||||||
#include "dev/platform.hh"
|
#include "dev/platform.hh"
|
||||||
|
|
||||||
|
#define BAR_IO_MASK 0x3
|
||||||
|
#define BAR_MEM_MASK 0xF
|
||||||
|
#define BAR_IO_SPACE_BIT 0x1
|
||||||
|
#define BAR_IO_SPACE(x) ((x) & BAR_IO_SPACE_BIT)
|
||||||
|
#define BAR_NUMBER(x) (((x) - PCI0_BASE_ADDR0) >> 0x2);
|
||||||
|
|
||||||
class PciConfigAll;
|
class PciConfigAll;
|
||||||
class MemoryController;
|
class MemoryController;
|
||||||
|
|
||||||
|
@ -136,15 +142,15 @@ class PciDev : public DmaDevice
|
||||||
|
|
||||||
void
|
void
|
||||||
intrPost()
|
intrPost()
|
||||||
{ plat->postPciInt(configData->config.hdr.pci0.interruptLine); }
|
{ plat->postPciInt(configData->config.interruptLine); }
|
||||||
|
|
||||||
void
|
void
|
||||||
intrClear()
|
intrClear()
|
||||||
{ plat->clearPciInt(configData->config.hdr.pci0.interruptLine); }
|
{ plat->clearPciInt(configData->config.interruptLine); }
|
||||||
|
|
||||||
uint8_t
|
uint8_t
|
||||||
interruptLine()
|
interruptLine()
|
||||||
{ return configData->config.hdr.pci0.interruptLine; }
|
{ return configData->config.interruptLine; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
@ -169,7 +175,7 @@ class PciDev : public DmaDevice
|
||||||
* @param size the size of the write
|
* @param size the size of the write
|
||||||
* @param data the data to write
|
* @param data the data to write
|
||||||
*/
|
*/
|
||||||
virtual void WriteConfig(int offset, int size, uint32_t data);
|
virtual void writeConfig(int offset, int size, const uint8_t* data);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -180,7 +186,7 @@ class PciDev : public DmaDevice
|
||||||
* @param size the size of the read
|
* @param size the size of the read
|
||||||
* @param data pointer to the location where the read value should be stored
|
* @param data pointer to the location where the read value should be stored
|
||||||
*/
|
*/
|
||||||
virtual void ReadConfig(int offset, int size, uint8_t *data);
|
virtual void readConfig(int offset, int size, uint8_t *data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize this object to the given output stream.
|
* Serialize this object to the given output stream.
|
||||||
|
|
90
dev/pcireg.h
90
dev/pcireg.h
|
@ -36,68 +36,44 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
union PCIConfig {
|
union PCIConfig {
|
||||||
uint8_t data[64];
|
uint8_t data[64];
|
||||||
|
|
||||||
struct hdr {
|
|
||||||
uint16_t vendor;
|
|
||||||
uint16_t device;
|
|
||||||
uint16_t command;
|
|
||||||
uint16_t status;
|
|
||||||
uint8_t revision;
|
|
||||||
uint8_t progIF;
|
|
||||||
uint8_t subClassCode;
|
|
||||||
uint8_t classCode;
|
|
||||||
uint8_t cacheLineSize;
|
|
||||||
uint8_t latencyTimer;
|
|
||||||
uint8_t headerType;
|
|
||||||
uint8_t bist;
|
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint16_t vendor;
|
||||||
|
uint16_t device;
|
||||||
|
uint16_t command;
|
||||||
|
uint16_t status;
|
||||||
|
uint8_t revision;
|
||||||
|
uint8_t progIF;
|
||||||
|
uint8_t subClassCode;
|
||||||
|
uint8_t classCode;
|
||||||
|
uint8_t cacheLineSize;
|
||||||
|
uint8_t latencyTimer;
|
||||||
|
uint8_t headerType;
|
||||||
|
uint8_t bist;
|
||||||
union {
|
union {
|
||||||
struct {
|
uint32_t baseAddr[6];
|
||||||
uint32_t baseAddr0;
|
|
||||||
uint32_t baseAddr1;
|
|
||||||
uint32_t baseAddr2;
|
|
||||||
uint32_t baseAddr3;
|
|
||||||
uint32_t baseAddr4;
|
|
||||||
uint32_t baseAddr5;
|
|
||||||
uint32_t cardbusCIS;
|
|
||||||
uint16_t subsystemVendorID;
|
|
||||||
uint16_t subsystemID;
|
|
||||||
uint32_t expansionROM;
|
|
||||||
uint32_t reserved0;
|
|
||||||
uint32_t reserved1;
|
|
||||||
uint8_t interruptLine;
|
|
||||||
uint8_t interruptPin;
|
|
||||||
uint8_t minimumGrant;
|
|
||||||
uint8_t maximumLatency;
|
|
||||||
} pci0;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint32_t baseAddr0;
|
uint32_t baseAddr0;
|
||||||
uint32_t baseAddr1;
|
uint32_t baseAddr1;
|
||||||
uint8_t priBusNum;
|
uint32_t baseAddr2;
|
||||||
uint8_t secBusNum;
|
uint32_t baseAddr3;
|
||||||
uint8_t subBusNum;
|
uint32_t baseAddr4;
|
||||||
uint8_t secLatency;
|
uint32_t baseAddr5;
|
||||||
uint8_t ioBase;
|
};
|
||||||
uint8_t minimumGrantioLimit;
|
|
||||||
uint16_t secStatus;
|
|
||||||
uint16_t memBase;
|
|
||||||
uint16_t memLimit;
|
|
||||||
uint16_t prefetchMemBase;
|
|
||||||
uint16_t prefetchMemLimit;
|
|
||||||
uint32_t prfBaseUpper32;
|
|
||||||
uint32_t prfLimitUpper32;
|
|
||||||
uint16_t ioBaseUpper16;
|
|
||||||
uint16_t ioLimitUpper16;
|
|
||||||
uint32_t reserved0;
|
|
||||||
uint32_t expansionROM;
|
|
||||||
uint8_t interruptLine;
|
|
||||||
uint8_t interruptPin;
|
|
||||||
uint16_t bridgeControl;
|
|
||||||
} pci1;
|
|
||||||
};
|
};
|
||||||
} hdr;
|
uint32_t cardbusCIS;
|
||||||
|
uint16_t subsystemVendorID;
|
||||||
|
uint16_t subsystemID;
|
||||||
|
uint32_t expansionROM;
|
||||||
|
uint32_t reserved0;
|
||||||
|
uint32_t reserved1;
|
||||||
|
uint8_t interruptLine;
|
||||||
|
uint8_t interruptPin;
|
||||||
|
uint8_t minimumGrant;
|
||||||
|
uint8_t maximumLatency;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Common PCI offsets
|
// Common PCI offsets
|
||||||
|
|
73
dev/pitreg.h
Normal file
73
dev/pitreg.h
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2005 The Regents of The University of Michigan
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met: redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer;
|
||||||
|
* redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution;
|
||||||
|
* neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @file
|
||||||
|
* Device register definitions for a device's PCI config space
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PITREG_H__
|
||||||
|
#define __PITREG_H__
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
// Control Word Format
|
||||||
|
|
||||||
|
#define PIT_SEL_SHFT 0x6
|
||||||
|
#define PIT_RW_SHFT 0x4
|
||||||
|
#define PIT_MODE_SHFT 0x1
|
||||||
|
#define PIT_BCD_SHFT 0x0
|
||||||
|
|
||||||
|
#define PIT_SEL_MASK 0x3
|
||||||
|
#define PIT_RW_MASK 0x3
|
||||||
|
#define PIT_MODE_MASK 0x7
|
||||||
|
#define PIT_BCD_MASK 0x1
|
||||||
|
|
||||||
|
#define GET_CTRL_FIELD(x, s, m) (((x) >> s) & m)
|
||||||
|
#define GET_CTRL_SEL(x) GET_CTRL_FIELD(x, PIT_SEL_SHFT, PIT_SEL_MASK)
|
||||||
|
#define GET_CTRL_RW(x) GET_CTRL_FIELD(x, PIT_RW_SHFT, PIT_RW_MASK)
|
||||||
|
#define GET_CTRL_MODE(x) GET_CTRL_FIELD(x, PIT_MODE_SHFT, PIT_MODE_MASK)
|
||||||
|
#define GET_CTRL_BCD(x) GET_CTRL_FIELD(x, PIT_BCD_SHFT, PIT_BCD_MASK)
|
||||||
|
|
||||||
|
#define PIT_READ_BACK 0x3
|
||||||
|
|
||||||
|
#define PIT_RW_LATCH_COMMAND 0x0
|
||||||
|
#define PIT_RW_LSB_ONLY 0x1
|
||||||
|
#define PIT_RW_MSB_ONLY 0x2
|
||||||
|
#define PIT_RW_16BIT 0x3
|
||||||
|
|
||||||
|
#define PIT_MODE_INTTC 0x0
|
||||||
|
#define PIT_MODE_ONESHOT 0x1
|
||||||
|
#define PIT_MODE_RATEGEN 0x2
|
||||||
|
#define PIT_MODE_SQWAVE 0x3
|
||||||
|
#define PIT_MODE_SWSTROBE 0x4
|
||||||
|
#define PIT_MODE_HWSTROBE 0x5
|
||||||
|
|
||||||
|
#define PIT_BCD_FALSE 0x0
|
||||||
|
#define PIT_BCD_TRUE 0x1
|
||||||
|
|
||||||
|
#endif // __PITREG_H__
|
|
@ -37,12 +37,12 @@
|
||||||
#define RTC_MON 0x08
|
#define RTC_MON 0x08
|
||||||
#define RTC_YEAR 0x09
|
#define RTC_YEAR 0x09
|
||||||
|
|
||||||
#define RTC_CNTRL_REGA 0x0A
|
#define RTC_STAT_REGA 0x0A
|
||||||
#define RTCA_1024HZ 0x06 /* 1024Hz periodic interrupt frequency */
|
#define RTCA_1024HZ 0x06 /* 1024Hz periodic interrupt frequency */
|
||||||
#define RTCA_32768HZ 0x20 /* 22-stage divider, 32.768KHz timebase */
|
#define RTCA_32768HZ 0x20 /* 22-stage divider, 32.768KHz timebase */
|
||||||
#define RTCA_UIP 0x80 /* 1 = date and time update in progress */
|
#define RTCA_UIP 0x80 /* 1 = date and time update in progress */
|
||||||
|
|
||||||
#define RTC_CNTRL_REGB 0x0B
|
#define RTC_STAT_REGB 0x0B
|
||||||
#define RTCB_DST 0x01 /* USA Daylight Savings Time enable */
|
#define RTCB_DST 0x01 /* USA Daylight Savings Time enable */
|
||||||
#define RTCB_24HR 0x02 /* 0 = 12 hours, 1 = 24 hours */
|
#define RTCB_24HR 0x02 /* 0 = 12 hours, 1 = 24 hours */
|
||||||
#define RTCB_BIN 0x04 /* 0 = BCD, 1 = Binary coded time */
|
#define RTCB_BIN 0x04 /* 0 = BCD, 1 = Binary coded time */
|
||||||
|
@ -52,6 +52,6 @@
|
||||||
#define RTCB_PRDC_IE 0x40 /* 1 = enable periodic clock interrupt */
|
#define RTCB_PRDC_IE 0x40 /* 1 = enable periodic clock interrupt */
|
||||||
#define RTCB_NO_UPDT 0x80 /* stop clock updates */
|
#define RTCB_NO_UPDT 0x80 /* stop clock updates */
|
||||||
|
|
||||||
#define RTC_CNTRL_REGC 0x0C
|
#define RTC_STAT_REGC 0x0C
|
||||||
#define RTC_CNTRL_REGD 0x0D
|
#define RTC_STAT_REGD 0x0D
|
||||||
|
|
||||||
|
|
10
dev/sinic.cc
10
dev/sinic.cc
|
@ -296,12 +296,12 @@ Device::regStats()
|
||||||
* This is to write to the PCI general configuration registers
|
* This is to write to the PCI general configuration registers
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
Device::WriteConfig(int offset, int size, uint32_t data)
|
Device::writeConfig(int offset, int size, const uint8_t *data)
|
||||||
{
|
{
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case PCI0_BASE_ADDR0:
|
case PCI0_BASE_ADDR0:
|
||||||
// Need to catch writes to BARs to update the PIO interface
|
// Need to catch writes to BARs to update the PIO interface
|
||||||
PciDev::WriteConfig(offset, size, data);
|
PciDev::writeConfig(offset, size, data);
|
||||||
if (BARAddrs[0] != 0) {
|
if (BARAddrs[0] != 0) {
|
||||||
if (pioInterface)
|
if (pioInterface)
|
||||||
pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
|
pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
|
||||||
|
@ -311,7 +311,7 @@ Device::WriteConfig(int offset, int size, uint32_t data)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
PciDev::WriteConfig(offset, size, data);
|
PciDev::writeConfig(offset, size, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,7 +322,7 @@ Device::WriteConfig(int offset, int size, uint32_t data)
|
||||||
Fault
|
Fault
|
||||||
Device::read(MemReqPtr &req, uint8_t *data)
|
Device::read(MemReqPtr &req, uint8_t *data)
|
||||||
{
|
{
|
||||||
assert(config.hdr.command & PCI_CMD_MSE);
|
assert(config.command & PCI_CMD_MSE);
|
||||||
|
|
||||||
//The mask is to give you only the offset into the device register file
|
//The mask is to give you only the offset into the device register file
|
||||||
Addr daddr = req->paddr & 0xfff;
|
Addr daddr = req->paddr & 0xfff;
|
||||||
|
@ -409,7 +409,7 @@ Device::read(MemReqPtr &req, uint8_t *data)
|
||||||
Fault
|
Fault
|
||||||
Device::write(MemReqPtr &req, const uint8_t *data)
|
Device::write(MemReqPtr &req, const uint8_t *data)
|
||||||
{
|
{
|
||||||
assert(config.hdr.command & PCI_CMD_MSE);
|
assert(config.command & PCI_CMD_MSE);
|
||||||
Addr daddr = req->paddr & 0xfff;
|
Addr daddr = req->paddr & 0xfff;
|
||||||
|
|
||||||
if (Regs::regSize(daddr) == 0)
|
if (Regs::regSize(daddr) == 0)
|
||||||
|
|
|
@ -238,7 +238,7 @@ class Device : public Base
|
||||||
* PCI Configuration interface
|
* PCI Configuration interface
|
||||||
*/
|
*/
|
||||||
public:
|
public:
|
||||||
virtual void WriteConfig(int offset, int size, uint32_t data);
|
virtual void writeConfig(int offset, int size, const uint8_t *data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Memory Interface
|
* Memory Interface
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "base/trace.hh"
|
#include "base/trace.hh"
|
||||||
#include "dev/tsunami_io.hh"
|
#include "dev/tsunami_io.hh"
|
||||||
#include "dev/tsunami.hh"
|
#include "dev/tsunami.hh"
|
||||||
|
#include "dev/pitreg.h"
|
||||||
#include "mem/bus/bus.hh"
|
#include "mem/bus/bus.hh"
|
||||||
#include "mem/bus/pio_interface.hh"
|
#include "mem/bus/pio_interface.hh"
|
||||||
#include "mem/bus/pio_interface_impl.hh"
|
#include "mem/bus/pio_interface_impl.hh"
|
||||||
|
@ -50,18 +51,136 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#define UNIX_YEAR_OFFSET 52
|
TsunamiIO::RTC::RTC(Tsunami* t, Tick i)
|
||||||
|
: SimObject("RTC"), event(t, i), addr(0)
|
||||||
|
{
|
||||||
|
memset(clock_data, 0, sizeof(clock_data));
|
||||||
|
stat_regA = RTCA_32768HZ | RTCA_1024HZ;
|
||||||
|
stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR;
|
||||||
|
}
|
||||||
|
|
||||||
// Timer Event for Periodic interrupt of RTC
|
void
|
||||||
TsunamiIO::RTCEvent::RTCEvent(Tsunami* t, Tick i)
|
TsunamiIO::RTC::set_time(time_t t)
|
||||||
|
{
|
||||||
|
struct tm tm;
|
||||||
|
gmtime_r(&t, &tm);
|
||||||
|
|
||||||
|
sec = tm.tm_sec;
|
||||||
|
min = tm.tm_min;
|
||||||
|
hour = tm.tm_hour;
|
||||||
|
wday = tm.tm_wday + 1;
|
||||||
|
mday = tm.tm_mday;
|
||||||
|
mon = tm.tm_mon + 1;
|
||||||
|
year = tm.tm_year;
|
||||||
|
|
||||||
|
DPRINTFN("Real-time clock set to %s", asctime(&tm));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TsunamiIO::RTC::writeAddr(const uint8_t *data)
|
||||||
|
{
|
||||||
|
if (*data <= RTC_STAT_REGD)
|
||||||
|
addr = *data;
|
||||||
|
else
|
||||||
|
panic("RTC addresses over 0xD are not implemented.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TsunamiIO::RTC::writeData(const uint8_t *data)
|
||||||
|
{
|
||||||
|
if (addr < RTC_STAT_REGA)
|
||||||
|
clock_data[addr] = *data;
|
||||||
|
else {
|
||||||
|
switch (addr) {
|
||||||
|
case RTC_STAT_REGA:
|
||||||
|
if (*data != (RTCA_32768HZ | RTCA_1024HZ))
|
||||||
|
panic("Unimplemented RTC register A value write!\n");
|
||||||
|
stat_regA = *data;
|
||||||
|
break;
|
||||||
|
case RTC_STAT_REGB:
|
||||||
|
if ((*data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR))
|
||||||
|
panic("Write to RTC reg B bits that are not implemented!\n");
|
||||||
|
|
||||||
|
if (*data & RTCB_PRDC_IE) {
|
||||||
|
if (!event.scheduled())
|
||||||
|
event.scheduleIntr();
|
||||||
|
} else {
|
||||||
|
if (event.scheduled())
|
||||||
|
event.deschedule();
|
||||||
|
}
|
||||||
|
stat_regB = *data;
|
||||||
|
break;
|
||||||
|
case RTC_STAT_REGC:
|
||||||
|
case RTC_STAT_REGD:
|
||||||
|
panic("RTC status registers C and D are not implemented.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TsunamiIO::RTC::readData(uint8_t *data)
|
||||||
|
{
|
||||||
|
if (addr < RTC_STAT_REGA)
|
||||||
|
*data = clock_data[addr];
|
||||||
|
else {
|
||||||
|
switch (addr) {
|
||||||
|
case RTC_STAT_REGA:
|
||||||
|
// toggle UIP bit for linux
|
||||||
|
stat_regA ^= RTCA_UIP;
|
||||||
|
*data = stat_regA;
|
||||||
|
break;
|
||||||
|
case RTC_STAT_REGB:
|
||||||
|
*data = stat_regB;
|
||||||
|
break;
|
||||||
|
case RTC_STAT_REGC:
|
||||||
|
case RTC_STAT_REGD:
|
||||||
|
*data = 0x00;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TsunamiIO::RTC::serialize(std::ostream &os)
|
||||||
|
{
|
||||||
|
SERIALIZE_SCALAR(addr);
|
||||||
|
SERIALIZE_ARRAY(clock_data, sizeof(clock_data));
|
||||||
|
SERIALIZE_SCALAR(stat_regA);
|
||||||
|
SERIALIZE_SCALAR(stat_regB);
|
||||||
|
|
||||||
|
// serialize the RTC event
|
||||||
|
nameOut(os, csprintf("%s.event", name()));
|
||||||
|
event.serialize(os);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TsunamiIO::RTC::unserialize(Checkpoint *cp, const std::string §ion)
|
||||||
|
{
|
||||||
|
UNSERIALIZE_SCALAR(addr);
|
||||||
|
UNSERIALIZE_ARRAY(clock_data, sizeof(clock_data));
|
||||||
|
UNSERIALIZE_SCALAR(stat_regA);
|
||||||
|
UNSERIALIZE_SCALAR(stat_regB);
|
||||||
|
|
||||||
|
// unserialze the event
|
||||||
|
event.unserialize(cp, csprintf("%s.event", section));
|
||||||
|
}
|
||||||
|
|
||||||
|
TsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i)
|
||||||
: Event(&mainEventQueue), tsunami(t), interval(i)
|
: Event(&mainEventQueue), tsunami(t), interval(i)
|
||||||
{
|
{
|
||||||
DPRINTF(MC146818, "RTC Event Initializing\n");
|
DPRINTF(MC146818, "RTC Event Initilizing\n");
|
||||||
schedule(curTick + interval);
|
schedule(curTick + interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TsunamiIO::RTCEvent::process()
|
TsunamiIO::RTC::RTCEvent::scheduleIntr()
|
||||||
|
{
|
||||||
|
schedule(curTick + interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TsunamiIO::RTC::RTCEvent::process()
|
||||||
{
|
{
|
||||||
DPRINTF(MC146818, "RTC Timer Interrupt\n");
|
DPRINTF(MC146818, "RTC Timer Interrupt\n");
|
||||||
schedule(curTick + interval);
|
schedule(curTick + interval);
|
||||||
|
@ -70,152 +189,256 @@ TsunamiIO::RTCEvent::process()
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
TsunamiIO::RTCEvent::description()
|
TsunamiIO::RTC::RTCEvent::description()
|
||||||
{
|
{
|
||||||
return "tsunami RTC interrupt";
|
return "tsunami RTC interrupt";
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TsunamiIO::RTCEvent::serialize(std::ostream &os)
|
TsunamiIO::RTC::RTCEvent::serialize(std::ostream &os)
|
||||||
{
|
{
|
||||||
Tick time = when();
|
Tick time = when();
|
||||||
SERIALIZE_SCALAR(time);
|
SERIALIZE_SCALAR(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TsunamiIO::RTCEvent::unserialize(Checkpoint *cp, const std::string §ion)
|
TsunamiIO::RTC::RTCEvent::unserialize(Checkpoint *cp, const std::string §ion)
|
||||||
{
|
{
|
||||||
Tick time;
|
Tick time;
|
||||||
UNSERIALIZE_SCALAR(time);
|
UNSERIALIZE_SCALAR(time);
|
||||||
reschedule(time);
|
reschedule(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
TsunamiIO::PITimer::PITimer()
|
||||||
TsunamiIO::RTCEvent::scheduleIntr()
|
: SimObject("PITimer"), counter0(counter[0]), counter1(counter[1]),
|
||||||
|
counter2(counter[2])
|
||||||
{
|
{
|
||||||
schedule(curTick + interval);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timer Event for PIT Timers
|
void
|
||||||
TsunamiIO::ClockEvent::ClockEvent()
|
TsunamiIO::PITimer::writeControl(const uint8_t *data)
|
||||||
|
{
|
||||||
|
int rw;
|
||||||
|
int sel;
|
||||||
|
|
||||||
|
sel = GET_CTRL_SEL(*data);
|
||||||
|
|
||||||
|
if (sel == PIT_READ_BACK)
|
||||||
|
panic("PITimer Read-Back Command is not implemented.\n");
|
||||||
|
|
||||||
|
rw = GET_CTRL_RW(*data);
|
||||||
|
|
||||||
|
if (rw == PIT_RW_LATCH_COMMAND)
|
||||||
|
counter[sel].latchCount();
|
||||||
|
else {
|
||||||
|
counter[sel].setRW(rw);
|
||||||
|
counter[sel].setMode(GET_CTRL_MODE(*data));
|
||||||
|
counter[sel].setBCD(GET_CTRL_BCD(*data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TsunamiIO::PITimer::serialize(std::ostream &os)
|
||||||
|
{
|
||||||
|
// serialize the counters
|
||||||
|
nameOut(os, csprintf("%s.counter0", name()));
|
||||||
|
counter0.serialize(os);
|
||||||
|
|
||||||
|
nameOut(os, csprintf("%s.counter1", name()));
|
||||||
|
counter1.serialize(os);
|
||||||
|
|
||||||
|
nameOut(os, csprintf("%s.counter2", name()));
|
||||||
|
counter2.serialize(os);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TsunamiIO::PITimer::unserialize(Checkpoint *cp, const std::string §ion)
|
||||||
|
{
|
||||||
|
// unserialze the counters
|
||||||
|
counter0.unserialize(cp, csprintf("%s.counter0", section));
|
||||||
|
counter1.unserialize(cp, csprintf("%s.counter1", section));
|
||||||
|
counter2.unserialize(cp, csprintf("%s.counter2", section));
|
||||||
|
}
|
||||||
|
|
||||||
|
TsunamiIO::PITimer::Counter::Counter()
|
||||||
|
: SimObject("Counter"), event(this), count(0), latched_count(0), period(0),
|
||||||
|
mode(0), output_high(false), latch_on(false), read_byte(LSB),
|
||||||
|
write_byte(LSB)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TsunamiIO::PITimer::Counter::latchCount()
|
||||||
|
{
|
||||||
|
// behave like a real latch
|
||||||
|
if(!latch_on) {
|
||||||
|
latch_on = true;
|
||||||
|
read_byte = LSB;
|
||||||
|
latched_count = count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TsunamiIO::PITimer::Counter::read(uint8_t *data)
|
||||||
|
{
|
||||||
|
if (latch_on) {
|
||||||
|
switch (read_byte) {
|
||||||
|
case LSB:
|
||||||
|
read_byte = MSB;
|
||||||
|
*data = (uint8_t)latched_count;
|
||||||
|
break;
|
||||||
|
case MSB:
|
||||||
|
read_byte = LSB;
|
||||||
|
latch_on = false;
|
||||||
|
*data = latched_count >> 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (read_byte) {
|
||||||
|
case LSB:
|
||||||
|
read_byte = MSB;
|
||||||
|
*data = (uint8_t)count;
|
||||||
|
break;
|
||||||
|
case MSB:
|
||||||
|
read_byte = LSB;
|
||||||
|
*data = count >> 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TsunamiIO::PITimer::Counter::write(const uint8_t *data)
|
||||||
|
{
|
||||||
|
switch (write_byte) {
|
||||||
|
case LSB:
|
||||||
|
count = (count & 0xFF00) | *data;
|
||||||
|
|
||||||
|
if (event.scheduled())
|
||||||
|
event.deschedule();
|
||||||
|
output_high = false;
|
||||||
|
write_byte = MSB;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MSB:
|
||||||
|
count = (count & 0x00FF) | (*data << 8);
|
||||||
|
period = count;
|
||||||
|
|
||||||
|
if (period > 0) {
|
||||||
|
DPRINTF(Tsunami, "Timer set to curTick + %d\n", count * event.interval);
|
||||||
|
event.schedule(curTick + count * event.interval);
|
||||||
|
}
|
||||||
|
write_byte = LSB;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TsunamiIO::PITimer::Counter::setRW(int rw_val)
|
||||||
|
{
|
||||||
|
if (rw_val != PIT_RW_16BIT)
|
||||||
|
panic("Only LSB/MSB read/write is implemented.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TsunamiIO::PITimer::Counter::setMode(int mode_val)
|
||||||
|
{
|
||||||
|
if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN &&
|
||||||
|
mode_val != PIT_MODE_SQWAVE)
|
||||||
|
panic("PIT mode %#x is not implemented: \n", mode_val);
|
||||||
|
|
||||||
|
mode = mode_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TsunamiIO::PITimer::Counter::setBCD(int bcd_val)
|
||||||
|
{
|
||||||
|
if (bcd_val != PIT_BCD_FALSE)
|
||||||
|
panic("PITimer does not implement BCD counts.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TsunamiIO::PITimer::Counter::outputHigh()
|
||||||
|
{
|
||||||
|
return output_high;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TsunamiIO::PITimer::Counter::serialize(std::ostream &os)
|
||||||
|
{
|
||||||
|
SERIALIZE_SCALAR(count);
|
||||||
|
SERIALIZE_SCALAR(latched_count);
|
||||||
|
SERIALIZE_SCALAR(period);
|
||||||
|
SERIALIZE_SCALAR(mode);
|
||||||
|
SERIALIZE_SCALAR(output_high);
|
||||||
|
SERIALIZE_SCALAR(latch_on);
|
||||||
|
SERIALIZE_SCALAR(read_byte);
|
||||||
|
SERIALIZE_SCALAR(write_byte);
|
||||||
|
|
||||||
|
// serialize the counter event
|
||||||
|
nameOut(os, csprintf("%s.event", name()));
|
||||||
|
event.serialize(os);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TsunamiIO::PITimer::Counter::unserialize(Checkpoint *cp, const std::string §ion)
|
||||||
|
{
|
||||||
|
UNSERIALIZE_SCALAR(count);
|
||||||
|
UNSERIALIZE_SCALAR(latched_count);
|
||||||
|
UNSERIALIZE_SCALAR(period);
|
||||||
|
UNSERIALIZE_SCALAR(mode);
|
||||||
|
UNSERIALIZE_SCALAR(output_high);
|
||||||
|
UNSERIALIZE_SCALAR(latch_on);
|
||||||
|
UNSERIALIZE_SCALAR(read_byte);
|
||||||
|
UNSERIALIZE_SCALAR(write_byte);
|
||||||
|
|
||||||
|
// unserialze the counter event
|
||||||
|
event.unserialize(cp, csprintf("%s.event", section));
|
||||||
|
}
|
||||||
|
|
||||||
|
TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr)
|
||||||
: Event(&mainEventQueue)
|
: Event(&mainEventQueue)
|
||||||
{
|
{
|
||||||
/* This is the PIT Tick Rate. A constant for the 8254 timer. The
|
|
||||||
* Tsunami platform has one of these cycle counters on the Cypress
|
|
||||||
* South Bridge and it is used by linux for estimating the cycle
|
|
||||||
* frequency of the machine it is running on. --Ali
|
|
||||||
*/
|
|
||||||
interval = (Tick)(Clock::Float::s / 1193180.0);
|
interval = (Tick)(Clock::Float::s / 1193180.0);
|
||||||
|
counter = c_ptr;
|
||||||
DPRINTF(Tsunami, "Clock Event Initilizing\n");
|
|
||||||
mode = 0;
|
|
||||||
|
|
||||||
current_count = 0;
|
|
||||||
latched_count = 0;
|
|
||||||
latch_on = false;
|
|
||||||
read_byte = READ_LSB;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TsunamiIO::ClockEvent::process()
|
TsunamiIO::PITimer::Counter::CounterEvent::process()
|
||||||
{
|
{
|
||||||
DPRINTF(Tsunami, "Timer Interrupt\n");
|
DPRINTF(Tsunami, "Timer Interrupt\n");
|
||||||
if (mode == 0)
|
switch (counter->mode) {
|
||||||
status = 0x20; // set bit that linux is looking for
|
case PIT_MODE_INTTC:
|
||||||
else if (mode == 2)
|
counter->output_high = true;
|
||||||
schedule(curTick + current_count*interval);
|
case PIT_MODE_RATEGEN:
|
||||||
}
|
case PIT_MODE_SQWAVE:
|
||||||
|
break;
|
||||||
void
|
default:
|
||||||
TsunamiIO::ClockEvent::Program(int count)
|
panic("Unimplemented PITimer mode.\n");
|
||||||
{
|
}
|
||||||
DPRINTF(Tsunami, "Timer set to curTick + %d\n", count * interval);
|
|
||||||
schedule(curTick + count * interval);
|
|
||||||
status = 0;
|
|
||||||
|
|
||||||
current_count = (uint16_t)count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
TsunamiIO::ClockEvent::description()
|
TsunamiIO::PITimer::Counter::CounterEvent::description()
|
||||||
{
|
{
|
||||||
return "tsunami 8254 Interval timer";
|
return "tsunami 8254 Interval timer";
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TsunamiIO::ClockEvent::ChangeMode(uint8_t md)
|
TsunamiIO::PITimer::Counter::CounterEvent::serialize(std::ostream &os)
|
||||||
{
|
|
||||||
mode = md;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
TsunamiIO::ClockEvent::Status()
|
|
||||||
{
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TsunamiIO::ClockEvent::LatchCount()
|
|
||||||
{
|
|
||||||
// behave like a real latch
|
|
||||||
if(!latch_on) {
|
|
||||||
latch_on = true;
|
|
||||||
read_byte = READ_LSB;
|
|
||||||
latched_count = current_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
TsunamiIO::ClockEvent::Read()
|
|
||||||
{
|
|
||||||
uint8_t result = 0;
|
|
||||||
|
|
||||||
if(latch_on) {
|
|
||||||
switch (read_byte) {
|
|
||||||
case READ_LSB:
|
|
||||||
read_byte = READ_MSB;
|
|
||||||
result = (uint8_t)latched_count;
|
|
||||||
break;
|
|
||||||
case READ_MSB:
|
|
||||||
read_byte = READ_LSB;
|
|
||||||
latch_on = false;
|
|
||||||
result = latched_count >> 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (read_byte) {
|
|
||||||
case READ_LSB:
|
|
||||||
read_byte = READ_MSB;
|
|
||||||
result = (uint8_t)current_count;
|
|
||||||
break;
|
|
||||||
case READ_MSB:
|
|
||||||
read_byte = READ_LSB;
|
|
||||||
result = current_count >> 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
TsunamiIO::ClockEvent::serialize(std::ostream &os)
|
|
||||||
{
|
{
|
||||||
Tick time = scheduled() ? when() : 0;
|
Tick time = scheduled() ? when() : 0;
|
||||||
SERIALIZE_SCALAR(time);
|
SERIALIZE_SCALAR(time);
|
||||||
SERIALIZE_SCALAR(status);
|
|
||||||
SERIALIZE_SCALAR(mode);
|
|
||||||
SERIALIZE_SCALAR(interval);
|
SERIALIZE_SCALAR(interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TsunamiIO::ClockEvent::unserialize(Checkpoint *cp, const std::string §ion)
|
TsunamiIO::PITimer::Counter::CounterEvent::unserialize(Checkpoint *cp, const std::string §ion)
|
||||||
{
|
{
|
||||||
Tick time;
|
Tick time;
|
||||||
UNSERIALIZE_SCALAR(time);
|
UNSERIALIZE_SCALAR(time);
|
||||||
UNSERIALIZE_SCALAR(status);
|
|
||||||
UNSERIALIZE_SCALAR(mode);
|
|
||||||
UNSERIALIZE_SCALAR(interval);
|
UNSERIALIZE_SCALAR(interval);
|
||||||
if (time)
|
if (time)
|
||||||
schedule(time);
|
schedule(time);
|
||||||
|
@ -239,8 +462,7 @@ TsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time,
|
||||||
tsunami->io = this;
|
tsunami->io = this;
|
||||||
|
|
||||||
timerData = 0;
|
timerData = 0;
|
||||||
set_time(init_time == 0 ? time(NULL) : init_time);
|
rtc.set_time(init_time == 0 ? time(NULL) : init_time);
|
||||||
uip = 1;
|
|
||||||
picr = 0;
|
picr = 0;
|
||||||
picInterrupting = false;
|
picInterrupting = false;
|
||||||
}
|
}
|
||||||
|
@ -251,13 +473,6 @@ TsunamiIO::frequency() const
|
||||||
return Clock::Frequency / clockInterval;
|
return Clock::Frequency / clockInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
TsunamiIO::set_time(time_t t)
|
|
||||||
{
|
|
||||||
gmtime_r(&t, &tm);
|
|
||||||
DPRINTFN("Real-time clock set to %s", asctime(&tm));
|
|
||||||
}
|
|
||||||
|
|
||||||
Fault
|
Fault
|
||||||
TsunamiIO::read(MemReqPtr &req, uint8_t *data)
|
TsunamiIO::read(MemReqPtr &req, uint8_t *data)
|
||||||
{
|
{
|
||||||
|
@ -287,59 +502,24 @@ TsunamiIO::read(MemReqPtr &req, uint8_t *data)
|
||||||
// PIC2 not implemnted... just return 0
|
// PIC2 not implemnted... just return 0
|
||||||
*(uint8_t*)data = 0x00;
|
*(uint8_t*)data = 0x00;
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
case TSDEV_TMR_CTL:
|
|
||||||
*(uint8_t*)data = timer2.Status();
|
|
||||||
return No_Fault;
|
|
||||||
case TSDEV_TMR0_DATA:
|
case TSDEV_TMR0_DATA:
|
||||||
*(uint8_t *)data = timer0.Read();
|
pitimer.counter0.read(data);
|
||||||
|
return No_Fault;
|
||||||
|
case TSDEV_TMR1_DATA:
|
||||||
|
pitimer.counter1.read(data);
|
||||||
|
return No_Fault;
|
||||||
|
case TSDEV_TMR2_DATA:
|
||||||
|
pitimer.counter2.read(data);
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
case TSDEV_RTC_DATA:
|
case TSDEV_RTC_DATA:
|
||||||
switch(RTCAddress) {
|
rtc.readData(data);
|
||||||
case RTC_CNTRL_REGA:
|
return No_Fault;
|
||||||
*(uint8_t*)data = uip << 7 | RTCA_32768HZ | RTCA_1024HZ;
|
case TSDEV_CTRL_PORTB:
|
||||||
uip = !uip;
|
if (pitimer.counter2.outputHigh())
|
||||||
return No_Fault;
|
*data = PORTB_SPKR_HIGH;
|
||||||
case RTC_CNTRL_REGB:
|
else
|
||||||
// DM and 24/12 and UIE
|
*data = 0x00;
|
||||||
*(uint8_t*)data = RTCB_PRDC_IE | RTCB_BIN | RTCB_24HR;
|
return No_Fault;
|
||||||
return No_Fault;
|
|
||||||
case RTC_CNTRL_REGC:
|
|
||||||
// If we want to support RTC user access in linux
|
|
||||||
// This won't work, but for now it's fine
|
|
||||||
*(uint8_t*)data = 0x00;
|
|
||||||
return No_Fault;
|
|
||||||
case RTC_CNTRL_REGD:
|
|
||||||
panic("RTC Control Register D not implemented");
|
|
||||||
case RTC_SEC_ALRM:
|
|
||||||
case RTC_MIN_ALRM:
|
|
||||||
case RTC_HR_ALRM:
|
|
||||||
// RTC alarm functionality is not currently implemented
|
|
||||||
*(uint8_t *)data = 0x00;
|
|
||||||
return No_Fault;
|
|
||||||
case RTC_SEC:
|
|
||||||
*(uint8_t *)data = tm.tm_sec;
|
|
||||||
return No_Fault;
|
|
||||||
case RTC_MIN:
|
|
||||||
*(uint8_t *)data = tm.tm_min;
|
|
||||||
return No_Fault;
|
|
||||||
case RTC_HR:
|
|
||||||
*(uint8_t *)data = tm.tm_hour;
|
|
||||||
return No_Fault;
|
|
||||||
case RTC_DOW:
|
|
||||||
*(uint8_t *)data = tm.tm_wday + 1;
|
|
||||||
return No_Fault;
|
|
||||||
case RTC_DOM:
|
|
||||||
*(uint8_t *)data = tm.tm_mday;
|
|
||||||
return No_Fault;
|
|
||||||
case RTC_MON:
|
|
||||||
*(uint8_t *)data = tm.tm_mon + 1;
|
|
||||||
return No_Fault;
|
|
||||||
case RTC_YEAR:
|
|
||||||
*(uint8_t *)data = tm.tm_year;
|
|
||||||
return No_Fault;
|
|
||||||
default:
|
|
||||||
panic("Unknown RTC Address\n");
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
|
panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
|
||||||
}
|
}
|
||||||
|
@ -410,6 +590,14 @@ TsunamiIO::write(MemReqPtr &req, const uint8_t *data)
|
||||||
if (!(picr & mask1))
|
if (!(picr & mask1))
|
||||||
tsunami->cchip->clearDRIR(55);
|
tsunami->cchip->clearDRIR(55);
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
|
case TSDEV_DMA1_CMND:
|
||||||
|
return No_Fault;
|
||||||
|
case TSDEV_DMA2_CMND:
|
||||||
|
return No_Fault;
|
||||||
|
case TSDEV_DMA1_MMASK:
|
||||||
|
return No_Fault;
|
||||||
|
case TSDEV_DMA2_MMASK:
|
||||||
|
return No_Fault;
|
||||||
case TSDEV_PIC2_ACK:
|
case TSDEV_PIC2_ACK:
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
case TSDEV_DMA1_RESET:
|
case TSDEV_DMA1_RESET:
|
||||||
|
@ -425,117 +613,31 @@ TsunamiIO::write(MemReqPtr &req, const uint8_t *data)
|
||||||
case TSDEV_DMA1_MASK:
|
case TSDEV_DMA1_MASK:
|
||||||
case TSDEV_DMA2_MASK:
|
case TSDEV_DMA2_MASK:
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
case TSDEV_TMR_CTL:
|
case TSDEV_TMR0_DATA:
|
||||||
|
pitimer.counter0.write(data);
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
case TSDEV_TMR2_CTL:
|
case TSDEV_TMR1_DATA:
|
||||||
switch((*(uint8_t*)data >> 4) & 0x3) {
|
pitimer.counter1.write(data);
|
||||||
case 0x0:
|
|
||||||
switch(*(uint8_t*)data >> 6) {
|
|
||||||
case 0:
|
|
||||||
timer0.LatchCount();
|
|
||||||
return No_Fault;
|
|
||||||
case 2:
|
|
||||||
timer2.LatchCount();
|
|
||||||
return No_Fault;
|
|
||||||
default:
|
|
||||||
panic("Read Back Command not implemented\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x3:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
panic("Only L/M write and Counter-Latch read supported\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(*(uint8_t*)data >> 6) {
|
|
||||||
case 0:
|
|
||||||
timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
panic("Read Back Command not implemented\n");
|
|
||||||
}
|
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
case TSDEV_TMR2_DATA:
|
case TSDEV_TMR2_DATA:
|
||||||
/* two writes before we actually start the Timer
|
pitimer.counter2.write(data);
|
||||||
so I set a flag in the timerData */
|
|
||||||
if(timerData & 0x1000) {
|
|
||||||
timerData &= 0x1000;
|
|
||||||
timerData += *(uint8_t*)data << 8;
|
|
||||||
timer2.Program(timerData);
|
|
||||||
} else {
|
|
||||||
timerData = *(uint8_t*)data;
|
|
||||||
timerData |= 0x1000;
|
|
||||||
}
|
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
case TSDEV_TMR0_DATA:
|
case TSDEV_TMR_CTRL:
|
||||||
/* two writes before we actually start the Timer
|
pitimer.writeControl(data);
|
||||||
so I set a flag in the timerData */
|
|
||||||
if(timerData & 0x1000) {
|
|
||||||
timerData &= ~0x1000;
|
|
||||||
timerData += *(uint8_t*)data << 8;
|
|
||||||
timer0.Program(timerData);
|
|
||||||
timerData = 0;
|
|
||||||
} else {
|
|
||||||
timerData = *(uint8_t*)data;
|
|
||||||
timerData |= 0x1000;
|
|
||||||
}
|
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
case TSDEV_RTC_ADDR:
|
case TSDEV_RTC_ADDR:
|
||||||
RTCAddress = *(uint8_t*)data;
|
rtc.writeAddr(data);
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
case TSDEV_KBD:
|
case TSDEV_KBD:
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
case TSDEV_RTC_DATA:
|
case TSDEV_RTC_DATA:
|
||||||
switch(RTCAddress) {
|
rtc.writeData(data);
|
||||||
case RTC_CNTRL_REGA:
|
return No_Fault;
|
||||||
if (*data != (RTCA_32768HZ | RTCA_1024HZ))
|
case TSDEV_CTRL_PORTB:
|
||||||
panic("Unimplemented RTC register A value write!\n");
|
// System Control Port B not implemented
|
||||||
return No_Fault;
|
return No_Fault;
|
||||||
case RTC_CNTRL_REGB:
|
|
||||||
if ((*data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR))
|
|
||||||
panic("Write to RTC reg B bits that are not implemented!\n");
|
|
||||||
|
|
||||||
if (*data & RTCB_PRDC_IE) {
|
|
||||||
if (!rtc.scheduled())
|
|
||||||
rtc.scheduleIntr();
|
|
||||||
} else {
|
|
||||||
if (rtc.scheduled())
|
|
||||||
rtc.deschedule();
|
|
||||||
}
|
|
||||||
return No_Fault;
|
|
||||||
case RTC_CNTRL_REGC:
|
|
||||||
panic("Write to RTC reg C not implemented!\n");
|
|
||||||
return No_Fault;
|
|
||||||
case RTC_CNTRL_REGD:
|
|
||||||
panic("Write to RTC reg D not implemented!\n");
|
|
||||||
return No_Fault;
|
|
||||||
case RTC_SEC:
|
|
||||||
tm.tm_sec = *(uint8_t *)data;
|
|
||||||
return No_Fault;
|
|
||||||
case RTC_MIN:
|
|
||||||
tm.tm_min = *(uint8_t *)data;
|
|
||||||
return No_Fault;
|
|
||||||
case RTC_HR:
|
|
||||||
tm.tm_hour = *(uint8_t *)data;
|
|
||||||
return No_Fault;
|
|
||||||
case RTC_DOW:
|
|
||||||
tm.tm_wday = *(uint8_t *)data;
|
|
||||||
return No_Fault;
|
|
||||||
case RTC_DOM:
|
|
||||||
tm.tm_mday = *(uint8_t *)data;
|
|
||||||
return No_Fault;
|
|
||||||
case RTC_MON:
|
|
||||||
tm.tm_mon = *(uint8_t *)data;
|
|
||||||
return No_Fault;
|
|
||||||
case RTC_YEAR:
|
|
||||||
tm.tm_year = *(uint8_t *)data;
|
|
||||||
return No_Fault;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
panic("I/O Write - va%#x size %d\n", req->vaddr, req->size);
|
panic("I/O Write - va%#x size %d data %#x\n", req->vaddr, req->size, (int)*data);
|
||||||
}
|
}
|
||||||
case sizeof(uint16_t):
|
case sizeof(uint16_t):
|
||||||
case sizeof(uint32_t):
|
case sizeof(uint32_t):
|
||||||
|
@ -581,20 +683,16 @@ void
|
||||||
TsunamiIO::serialize(std::ostream &os)
|
TsunamiIO::serialize(std::ostream &os)
|
||||||
{
|
{
|
||||||
SERIALIZE_SCALAR(timerData);
|
SERIALIZE_SCALAR(timerData);
|
||||||
SERIALIZE_SCALAR(uip);
|
|
||||||
SERIALIZE_SCALAR(mask1);
|
SERIALIZE_SCALAR(mask1);
|
||||||
SERIALIZE_SCALAR(mask2);
|
SERIALIZE_SCALAR(mask2);
|
||||||
SERIALIZE_SCALAR(mode1);
|
SERIALIZE_SCALAR(mode1);
|
||||||
SERIALIZE_SCALAR(mode2);
|
SERIALIZE_SCALAR(mode2);
|
||||||
SERIALIZE_SCALAR(picr);
|
SERIALIZE_SCALAR(picr);
|
||||||
SERIALIZE_SCALAR(picInterrupting);
|
SERIALIZE_SCALAR(picInterrupting);
|
||||||
SERIALIZE_SCALAR(RTCAddress);
|
|
||||||
|
|
||||||
// Serialize the timers
|
// Serialize the timers
|
||||||
nameOut(os, csprintf("%s.timer0", name()));
|
nameOut(os, csprintf("%s.pitimer", name()));
|
||||||
timer0.serialize(os);
|
pitimer.serialize(os);
|
||||||
nameOut(os, csprintf("%s.timer2", name()));
|
|
||||||
timer2.serialize(os);
|
|
||||||
nameOut(os, csprintf("%s.rtc", name()));
|
nameOut(os, csprintf("%s.rtc", name()));
|
||||||
rtc.serialize(os);
|
rtc.serialize(os);
|
||||||
}
|
}
|
||||||
|
@ -603,18 +701,15 @@ void
|
||||||
TsunamiIO::unserialize(Checkpoint *cp, const std::string §ion)
|
TsunamiIO::unserialize(Checkpoint *cp, const std::string §ion)
|
||||||
{
|
{
|
||||||
UNSERIALIZE_SCALAR(timerData);
|
UNSERIALIZE_SCALAR(timerData);
|
||||||
UNSERIALIZE_SCALAR(uip);
|
|
||||||
UNSERIALIZE_SCALAR(mask1);
|
UNSERIALIZE_SCALAR(mask1);
|
||||||
UNSERIALIZE_SCALAR(mask2);
|
UNSERIALIZE_SCALAR(mask2);
|
||||||
UNSERIALIZE_SCALAR(mode1);
|
UNSERIALIZE_SCALAR(mode1);
|
||||||
UNSERIALIZE_SCALAR(mode2);
|
UNSERIALIZE_SCALAR(mode2);
|
||||||
UNSERIALIZE_SCALAR(picr);
|
UNSERIALIZE_SCALAR(picr);
|
||||||
UNSERIALIZE_SCALAR(picInterrupting);
|
UNSERIALIZE_SCALAR(picInterrupting);
|
||||||
UNSERIALIZE_SCALAR(RTCAddress);
|
|
||||||
|
|
||||||
// Unserialize the timers
|
// Unserialize the timers
|
||||||
timer0.unserialize(cp, csprintf("%s.timer0", section));
|
pitimer.unserialize(cp, csprintf("%s.pitimer", section));
|
||||||
timer2.unserialize(cp, csprintf("%s.timer2", section));
|
|
||||||
rtc.unserialize(cp, csprintf("%s.rtc", section));
|
rtc.unserialize(cp, csprintf("%s.rtc", section));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,129 +53,95 @@ class TsunamiIO : public PioDevice
|
||||||
|
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
|
|
||||||
/**
|
|
||||||
* In Tsunami RTC only has two i/o ports one for data and one for
|
|
||||||
* address, so you write the address and then read/write the
|
|
||||||
* data. This store the address you are going to be reading from
|
|
||||||
* on a read.
|
|
||||||
*/
|
|
||||||
uint8_t RTCAddress;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/**
|
/** Real-Time Clock (MC146818) */
|
||||||
* The ClockEvent is handles the PIT interrupts
|
class RTC : public SimObject
|
||||||
*/
|
|
||||||
class ClockEvent : public Event
|
|
||||||
{
|
{
|
||||||
protected:
|
/** Event for RTC periodic interrupt */
|
||||||
/** how often the PIT fires */
|
class RTCEvent : public Event
|
||||||
Tick interval;
|
{
|
||||||
/** The mode of the PIT */
|
private:
|
||||||
uint8_t mode;
|
/** A pointer back to tsunami to create interrupt the processor. */
|
||||||
/** The status of the PIT */
|
Tsunami* tsunami;
|
||||||
uint8_t status;
|
Tick interval;
|
||||||
/** The current count of the PIT */
|
|
||||||
uint16_t current_count;
|
public:
|
||||||
/** The latched count of the PIT */
|
RTCEvent(Tsunami* t, Tick i);
|
||||||
uint16_t latched_count;
|
|
||||||
/** The state of the output latch of the PIT */
|
/** Schedule the RTC periodic interrupt */
|
||||||
bool latch_on;
|
void scheduleIntr();
|
||||||
/** The next count half (byte) to read */
|
|
||||||
enum {READ_LSB, READ_MSB} read_byte;
|
/** Event process to occur at interrupt*/
|
||||||
|
virtual void process();
|
||||||
|
|
||||||
|
/** Event description */
|
||||||
|
virtual const char *description();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize this object to the given output stream.
|
||||||
|
* @param os The stream to serialize to.
|
||||||
|
*/
|
||||||
|
virtual void serialize(std::ostream &os);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reconstruct the state of this object from a checkpoint.
|
||||||
|
* @param cp The checkpoint use.
|
||||||
|
* @param section The section name of this object
|
||||||
|
*/
|
||||||
|
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** RTC periodic interrupt event */
|
||||||
|
RTCEvent event;
|
||||||
|
|
||||||
|
/** Current RTC register address/index */
|
||||||
|
int addr;
|
||||||
|
|
||||||
|
/** Data for real-time clock function */
|
||||||
|
union {
|
||||||
|
uint8_t clock_data[10];
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t sec;
|
||||||
|
uint8_t sec_alrm;
|
||||||
|
uint8_t min;
|
||||||
|
uint8_t min_alrm;
|
||||||
|
uint8_t hour;
|
||||||
|
uint8_t hour_alrm;
|
||||||
|
uint8_t wday;
|
||||||
|
uint8_t mday;
|
||||||
|
uint8_t mon;
|
||||||
|
uint8_t year;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/** RTC status register A */
|
||||||
|
uint8_t stat_regA;
|
||||||
|
|
||||||
|
/** RTC status register B */
|
||||||
|
uint8_t stat_regB;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
RTC(Tsunami* t, Tick i);
|
||||||
* Just set the mode to 0
|
|
||||||
*/
|
/** Set the initial RTC time/date */
|
||||||
ClockEvent();
|
void set_time(time_t t);
|
||||||
|
|
||||||
|
/** RTC address port: write address of RTC RAM data to access */
|
||||||
|
void writeAddr(const uint8_t *data);
|
||||||
|
|
||||||
|
/** RTC write data */
|
||||||
|
void writeData(const uint8_t *data);
|
||||||
|
|
||||||
|
/** RTC read data */
|
||||||
|
void readData(uint8_t *data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* processs the timer event
|
* Serialize this object to the given output stream.
|
||||||
*/
|
* @param os The stream to serialize to.
|
||||||
virtual void process();
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a description of this event
|
|
||||||
* @return the description
|
|
||||||
*/
|
|
||||||
virtual const char *description();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedule a timer interrupt to occur sometime in the future.
|
|
||||||
*/
|
|
||||||
void Program(int count);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write the mode bits of the PIT.
|
|
||||||
* @param mode the new mode
|
|
||||||
*/
|
|
||||||
void ChangeMode(uint8_t mode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current PIT status.
|
|
||||||
* @return the status of the PIT
|
|
||||||
*/
|
|
||||||
uint8_t Status();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Latch the count of the PIT.
|
|
||||||
*/
|
|
||||||
void LatchCount();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current PIT count.
|
|
||||||
* @return the count of the PIT
|
|
||||||
*/
|
|
||||||
uint8_t Read();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize this object to the given output stream.
|
|
||||||
* @param os The stream to serialize to.
|
|
||||||
*/
|
|
||||||
virtual void serialize(std::ostream &os);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reconstruct the state of this object from a checkpoint.
|
|
||||||
* @param cp The checkpoint use.
|
|
||||||
* @param section The section name of this object
|
|
||||||
*/
|
|
||||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process RTC timer events and generate interrupts appropriately.
|
|
||||||
*/
|
|
||||||
class RTCEvent : public Event
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
/** A pointer back to tsunami to create interrupt the processor. */
|
|
||||||
Tsunami* tsunami;
|
|
||||||
Tick interval;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* RTC Event initializes the RTC event by scheduling an event
|
|
||||||
* RTC_RATE times pre second.
|
|
||||||
*/
|
|
||||||
RTCEvent(Tsunami* t, Tick i);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interrupt the processor and reschedule the event.
|
|
||||||
*/
|
|
||||||
virtual void process();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a description of this event.
|
|
||||||
* @return a description
|
|
||||||
*/
|
|
||||||
virtual const char *description();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize this object to the given output stream.
|
|
||||||
* @param os The stream to serialize to.
|
|
||||||
*/
|
|
||||||
virtual void serialize(std::ostream &os);
|
virtual void serialize(std::ostream &os);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -184,16 +150,140 @@ class TsunamiIO : public PioDevice
|
||||||
* @param section The section name of this object
|
* @param section The section name of this object
|
||||||
*/
|
*/
|
||||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||||
|
|
||||||
void scheduleIntr();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** uip UpdateInProgess says that the rtc is updating, but we just fake it
|
/** Programmable Interval Timer (Intel 8254) */
|
||||||
* by alternating it on every read of the bit since we are going to
|
class PITimer : public SimObject
|
||||||
* override the loop_per_jiffy time that it is trying to use the UIP to
|
{
|
||||||
* calculate.
|
/** Counter element for PIT */
|
||||||
*/
|
class Counter : public SimObject
|
||||||
uint8_t uip;
|
{
|
||||||
|
/** Event for counter interrupt */
|
||||||
|
class CounterEvent : public Event
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/** Pointer back to Counter */
|
||||||
|
Counter* counter;
|
||||||
|
Tick interval;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CounterEvent(Counter*);
|
||||||
|
|
||||||
|
/** Event process */
|
||||||
|
virtual void process();
|
||||||
|
|
||||||
|
/** Event description */
|
||||||
|
virtual const char *description();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize this object to the given output stream.
|
||||||
|
* @param os The stream to serialize to.
|
||||||
|
*/
|
||||||
|
virtual void serialize(std::ostream &os);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reconstruct the state of this object from a checkpoint.
|
||||||
|
* @param cp The checkpoint use.
|
||||||
|
* @param section The section name of this object
|
||||||
|
*/
|
||||||
|
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||||
|
|
||||||
|
friend class Counter;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
CounterEvent event;
|
||||||
|
|
||||||
|
/** Current count value */
|
||||||
|
uint16_t count;
|
||||||
|
|
||||||
|
/** Latched count */
|
||||||
|
uint16_t latched_count;
|
||||||
|
|
||||||
|
/** Interrupt period */
|
||||||
|
uint16_t period;
|
||||||
|
|
||||||
|
/** Current mode of operation */
|
||||||
|
uint8_t mode;
|
||||||
|
|
||||||
|
/** Output goes high when the counter reaches zero */
|
||||||
|
bool output_high;
|
||||||
|
|
||||||
|
/** State of the count latch */
|
||||||
|
bool latch_on;
|
||||||
|
|
||||||
|
/** Set of values for read_byte and write_byte */
|
||||||
|
enum {LSB, MSB};
|
||||||
|
|
||||||
|
/** Determine which byte of a 16-bit count value to read/write */
|
||||||
|
uint8_t read_byte, write_byte;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Counter();
|
||||||
|
|
||||||
|
/** Latch the current count (if one is not already latched) */
|
||||||
|
void latchCount();
|
||||||
|
|
||||||
|
/** Set the read/write mode */
|
||||||
|
void setRW(int rw_val);
|
||||||
|
|
||||||
|
/** Set operational mode */
|
||||||
|
void setMode(int mode_val);
|
||||||
|
|
||||||
|
/** Set count encoding */
|
||||||
|
void setBCD(int bcd_val);
|
||||||
|
|
||||||
|
/** Read a count byte */
|
||||||
|
void read(uint8_t *data);
|
||||||
|
|
||||||
|
/** Write a count byte */
|
||||||
|
void write(const uint8_t *data);
|
||||||
|
|
||||||
|
/** Is the output high? */
|
||||||
|
bool outputHigh();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize this object to the given output stream.
|
||||||
|
* @param os The stream to serialize to.
|
||||||
|
*/
|
||||||
|
virtual void serialize(std::ostream &os);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reconstruct the state of this object from a checkpoint.
|
||||||
|
* @param cp The checkpoint use.
|
||||||
|
* @param section The section name of this object
|
||||||
|
*/
|
||||||
|
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** PIT has three seperate counters */
|
||||||
|
Counter counter[3];
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Public way to access individual counters (avoid array accesses) */
|
||||||
|
Counter &counter0;
|
||||||
|
Counter &counter1;
|
||||||
|
Counter &counter2;
|
||||||
|
|
||||||
|
PITimer();
|
||||||
|
|
||||||
|
/** Write control word */
|
||||||
|
void writeControl(const uint8_t* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize this object to the given output stream.
|
||||||
|
* @param os The stream to serialize to.
|
||||||
|
*/
|
||||||
|
virtual void serialize(std::ostream &os);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reconstruct the state of this object from a checkpoint.
|
||||||
|
* @param cp The checkpoint use.
|
||||||
|
* @param section The section name of this object
|
||||||
|
*/
|
||||||
|
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||||
|
};
|
||||||
|
|
||||||
/** Mask of the PIC1 */
|
/** Mask of the PIC1 */
|
||||||
uint8_t mask1;
|
uint8_t mask1;
|
||||||
|
@ -218,25 +308,10 @@ class TsunamiIO : public PioDevice
|
||||||
/** A pointer to the Tsunami device which be belong to */
|
/** A pointer to the Tsunami device which be belong to */
|
||||||
Tsunami *tsunami;
|
Tsunami *tsunami;
|
||||||
|
|
||||||
/**
|
/** Intel 8253 Periodic Interval Timer */
|
||||||
* This timer is initilized, but after I wrote the code
|
PITimer pitimer;
|
||||||
* it doesn't seem to be used again, and best I can tell
|
|
||||||
* it too is not connected to any interrupt port
|
|
||||||
*/
|
|
||||||
ClockEvent timer0;
|
|
||||||
|
|
||||||
/**
|
RTC rtc;
|
||||||
* This timer is used to control the speaker, which
|
|
||||||
* we normally could care less about, however it is
|
|
||||||
* also used to calculated the clockspeed and hense
|
|
||||||
* bogomips which is kinda important to the scheduler
|
|
||||||
* so we need to implemnt it although after boot I can't
|
|
||||||
* imagine we would be playing with the PC speaker much
|
|
||||||
*/
|
|
||||||
ClockEvent timer2;
|
|
||||||
|
|
||||||
/** This is the event used to interrupt the cpu like an RTC. */
|
|
||||||
RTCEvent rtc;
|
|
||||||
|
|
||||||
/** The interval is set via two writes to the PIT.
|
/** The interval is set via two writes to the PIT.
|
||||||
* This variable contains a flag as to how many writes have happened, and
|
* This variable contains a flag as to how many writes have happened, and
|
||||||
|
@ -263,11 +338,6 @@ class TsunamiIO : public PioDevice
|
||||||
Addr a, MemoryController *mmu, HierParams *hier, Bus *bus,
|
Addr a, MemoryController *mmu, HierParams *hier, Bus *bus,
|
||||||
Tick pio_latency, Tick ci);
|
Tick pio_latency, Tick ci);
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the tm struct from seconds since 1970
|
|
||||||
*/
|
|
||||||
void set_time(time_t t);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a read to one of the devices we are emulating.
|
* Process a read to one of the devices we are emulating.
|
||||||
* @param req Contains the address to read from.
|
* @param req Contains the address to read from.
|
||||||
|
|
|
@ -118,10 +118,18 @@
|
||||||
#define TSDEV_DMA2_MODE 0xD6
|
#define TSDEV_DMA2_MODE 0xD6
|
||||||
#define TSDEV_DMA1_MASK 0x0A
|
#define TSDEV_DMA1_MASK 0x0A
|
||||||
#define TSDEV_DMA2_MASK 0xD4
|
#define TSDEV_DMA2_MASK 0xD4
|
||||||
#define TSDEV_TMR_CTL 0x61
|
#define TSDEV_CTRL_PORTB 0x61
|
||||||
#define TSDEV_TMR2_CTL 0x43
|
|
||||||
#define TSDEV_TMR2_DATA 0x42
|
|
||||||
#define TSDEV_TMR0_DATA 0x40
|
#define TSDEV_TMR0_DATA 0x40
|
||||||
|
#define TSDEV_TMR1_DATA 0x41
|
||||||
|
#define TSDEV_TMR2_DATA 0x42
|
||||||
|
#define TSDEV_TMR_CTRL 0x43
|
||||||
|
#define TSDEV_KBD 0x64
|
||||||
|
#define TSDEV_DMA1_CMND 0x08
|
||||||
|
#define TSDEV_DMA1_STAT TSDEV_DMA1_CMND
|
||||||
|
#define TSDEV_DMA2_CMND 0xD0
|
||||||
|
#define TSDEV_DMA2_STAT TSDEV_DMA2_CMND
|
||||||
|
#define TSDEV_DMA1_MMASK 0x0F
|
||||||
|
#define TSDEV_DMA2_MMASK 0xDE
|
||||||
|
|
||||||
/* Added for keyboard accesses */
|
/* Added for keyboard accesses */
|
||||||
#define TSDEV_KBD 0x64
|
#define TSDEV_KBD 0x64
|
||||||
|
@ -157,4 +165,7 @@
|
||||||
|
|
||||||
#define UART_MCR_LOOP 0x10
|
#define UART_MCR_LOOP 0x10
|
||||||
|
|
||||||
|
// System Control PortB Status Bits
|
||||||
|
#define PORTB_SPKR_HIGH 0x20
|
||||||
|
|
||||||
#endif // __TSUNAMIREG_H__
|
#endif // __TSUNAMIREG_H__
|
||||||
|
|
|
@ -146,7 +146,10 @@ Uart8250::read(MemReqPtr &req, uint8_t *data)
|
||||||
break;
|
break;
|
||||||
case 0x2: // Intr Identification Register (IIR)
|
case 0x2: // Intr Identification Register (IIR)
|
||||||
DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status);
|
DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status);
|
||||||
|
|
||||||
|
//Tx interrupts are cleared on IIR reads
|
||||||
status &= ~TX_INT;
|
status &= ~TX_INT;
|
||||||
|
|
||||||
if (status & RX_INT)
|
if (status & RX_INT)
|
||||||
*(uint8_t*)data = IIR_RXID;
|
*(uint8_t*)data = IIR_RXID;
|
||||||
else
|
else
|
||||||
|
|
|
@ -38,8 +38,19 @@
|
||||||
#include "dev/io_device.hh"
|
#include "dev/io_device.hh"
|
||||||
#include "dev/uart.hh"
|
#include "dev/uart.hh"
|
||||||
|
|
||||||
|
|
||||||
|
/* UART8250 Interrupt ID Register
|
||||||
|
* bit 0 Interrupt Pending 0 = true, 1 = false
|
||||||
|
* bit 2:1 ID of highest priority interrupt
|
||||||
|
* bit 7:3 zeroes
|
||||||
|
*/
|
||||||
#define IIR_NOPEND 0x1
|
#define IIR_NOPEND 0x1
|
||||||
#define IIR_RXID 0x4
|
|
||||||
|
// Interrupt IDs
|
||||||
|
#define IIR_MODEM 0x00 /* Modem Status (lowest priority) */
|
||||||
|
#define IIR_TXID 0x02 /* Tx Data */
|
||||||
|
#define IIR_RXID 0x04 /* Rx Data */
|
||||||
|
#define IIR_LINE 0x06 /* Rx Line Status (highest priority)*/
|
||||||
|
|
||||||
class SimConsole;
|
class SimConsole;
|
||||||
class Platform;
|
class Platform;
|
||||||
|
|
|
@ -92,7 +92,7 @@ LinuxSystem::LinuxSystem(Params *p)
|
||||||
char *dp264_mv = (char *)physmem->dma_addr(paddr, sizeof(uint64_t));
|
char *dp264_mv = (char *)physmem->dma_addr(paddr, sizeof(uint64_t));
|
||||||
|
|
||||||
if (dp264_mv) {
|
if (dp264_mv) {
|
||||||
*(uint32_t*)(dp264_mv+0x18) = htoa((uint32_t)127);
|
*(uint32_t*)(dp264_mv+0x18) = htog((uint32_t)127);
|
||||||
} else
|
} else
|
||||||
panic("could not translate dp264_mv addr\n");
|
panic("could not translate dp264_mv addr\n");
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,9 @@ class TsunamiCChip(FooPioDevice):
|
||||||
type = 'TsunamiCChip'
|
type = 'TsunamiCChip'
|
||||||
tsunami = Param.Tsunami(Parent.any, "Tsunami")
|
tsunami = Param.Tsunami(Parent.any, "Tsunami")
|
||||||
|
|
||||||
class TsunamiFake(FooPioDevice):
|
class IsaFake(FooPioDevice):
|
||||||
type = 'TsunamiFake'
|
type = 'IsaFake'
|
||||||
size = Param.Addr(0x8, "Size of address range")
|
size = Param.Addr("Size of address range")
|
||||||
|
|
||||||
class TsunamiIO(FooPioDevice):
|
class TsunamiIO(FooPioDevice):
|
||||||
type = 'TsunamiIO'
|
type = 'TsunamiIO'
|
||||||
|
|
|
@ -154,8 +154,8 @@ System::System(Params *p)
|
||||||
if (!hwrpb)
|
if (!hwrpb)
|
||||||
panic("could not translate hwrpb addr\n");
|
panic("could not translate hwrpb addr\n");
|
||||||
|
|
||||||
*(uint64_t*)(hwrpb+0x50) = htoa(params->system_type);
|
*(uint64_t*)(hwrpb+0x50) = htog(params->system_type);
|
||||||
*(uint64_t*)(hwrpb+0x58) = htoa(params->system_rev);
|
*(uint64_t*)(hwrpb+0x58) = htog(params->system_rev);
|
||||||
} else
|
} else
|
||||||
panic("could not find hwrpb\n");
|
panic("could not find hwrpb\n");
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ System::setAlphaAccess(Addr access)
|
||||||
if (!m5AlphaAccess)
|
if (!m5AlphaAccess)
|
||||||
panic("could not translate m5AlphaAccess addr\n");
|
panic("could not translate m5AlphaAccess addr\n");
|
||||||
|
|
||||||
*m5AlphaAccess = htoa(EV5::Phys2K0Seg(access));
|
*m5AlphaAccess = htog(EV5::Phys2K0Seg(access));
|
||||||
} else
|
} else
|
||||||
panic("could not find m5AlphaAccess\n");
|
panic("could not find m5AlphaAccess\n");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue