summaryrefslogtreecommitdiff
path: root/dev
diff options
context:
space:
mode:
Diffstat (limited to 'dev')
-rw-r--r--dev/disk_image.cc4
-rw-r--r--dev/ide_ctrl.cc371
-rw-r--r--dev/ide_ctrl.hh82
-rw-r--r--dev/ide_disk.cc179
-rw-r--r--dev/ide_disk.hh14
-rwxr-xr-xdev/isa_fake.cc139
-rwxr-xr-xdev/isa_fake.hh85
-rw-r--r--dev/ns_gige.cc14
-rw-r--r--dev/ns_gige.hh6
-rw-r--r--dev/pciconfigall.cc33
-rw-r--r--dev/pcidev.cc251
-rw-r--r--dev/pcidev.hh16
-rw-r--r--dev/pcireg.h90
-rw-r--r--dev/pitreg.h73
-rw-r--r--dev/rtcreg.h22
-rw-r--r--dev/sinic.cc10
-rw-r--r--dev/sinic.hh2
-rw-r--r--dev/tsunami_io.cc515
-rw-r--r--dev/tsunami_io.hh301
-rw-r--r--dev/tsunamireg.h17
-rw-r--r--dev/uart8250.cc10
-rw-r--r--dev/uart8250.hh14
22 files changed, 1467 insertions, 781 deletions
diff --git a/dev/disk_image.cc b/dev/disk_image.cc
index 4ad2e912b..106723c55 100644
--- a/dev/disk_image.cc
+++ b/dev/disk_image.cc
@@ -237,7 +237,7 @@ void
SafeReadSwap(ifstream &stream, T &data)
{
SafeRead(stream, &data, sizeof(data));
- data = htoa(data);
+ data = letoh(data); //is this the proper byte order conversion?
}
bool
@@ -319,7 +319,7 @@ template<class T>
void
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));
}
void
diff --git a/dev/ide_ctrl.cc b/dev/ide_ctrl.cc
index 785f18ae8..6ad80e69d 100644
--- a/dev/ide_ctrl.cc
+++ b/dev/ide_ctrl.cc
@@ -75,13 +75,15 @@ IdeController::IdeController(Params *p)
bmi_size = BARSize[4];
// zero out all of the registers
- memset(bmi_regs, 0, sizeof(bmi_regs));
- memset(pci_regs, 0, sizeof(pci_regs));
+ memset(bmi_regs.data, 0, sizeof(bmi_regs));
+ memset(config_regs.data, 0, sizeof(config_regs.data));
// setup initial values
- *(uint32_t *)&pci_regs[IDETIM] = 0x80008000; // enable both channels
- *(uint8_t *)&bmi_regs[BMIS0] = 0x60;
- *(uint8_t *)&bmi_regs[BMIS1] = 0x60;
+ // 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.bmis1 = DMA1CAP | DMA0CAP;
// reset all internal variables
io_enabled = false;
@@ -127,46 +129,46 @@ IdeController::~IdeController()
///
void
-IdeController::parseAddr(const Addr &addr, Addr &offset, bool &primary,
- RegType_t &type)
+IdeController::parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel,
+ IdeRegType &reg_type)
{
offset = addr;
if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) {
offset -= pri_cmd_addr;
- type = COMMAND_BLOCK;
- primary = true;
+ reg_type = COMMAND_BLOCK;
+ channel = PRIMARY;
} else if (addr >= pri_ctrl_addr &&
addr < (pri_ctrl_addr + pri_ctrl_size)) {
offset -= pri_ctrl_addr;
- type = CONTROL_BLOCK;
- primary = true;
+ reg_type = CONTROL_BLOCK;
+ channel = PRIMARY;
} else if (addr >= sec_cmd_addr &&
addr < (sec_cmd_addr + sec_cmd_size)) {
offset -= sec_cmd_addr;
- type = COMMAND_BLOCK;
- primary = false;
+ reg_type = COMMAND_BLOCK;
+ channel = SECONDARY;
} else if (addr >= sec_ctrl_addr &&
addr < (sec_ctrl_addr + sec_ctrl_size)) {
offset -= sec_ctrl_addr;
- type = CONTROL_BLOCK;
- primary = false;
+ reg_type = CONTROL_BLOCK;
+ channel = SECONDARY;
} else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) {
offset -= bmi_addr;
- type = BMI_BLOCK;
- primary = (offset < BMIC1) ? true : false;
+ reg_type = BMI_BLOCK;
+ channel = (offset < BMIC1) ? PRIMARY : SECONDARY;
} else {
panic("IDE controller access to invalid address: %#x\n", addr);
}
}
int
-IdeController::getDisk(bool primary)
+IdeController::getDisk(IdeChannel channel)
{
int disk = 0;
uint8_t *devBit = &dev[0];
- if (!primary) {
+ if (channel == SECONDARY) {
disk += 2;
devBit = &dev[1];
}
@@ -218,18 +220,18 @@ IdeController::setDmaComplete(IdeDisk *disk)
if (diskNum < 2) {
// clear the start/stop bit in the command register
- bmi_regs[BMIC0] &= ~SSBM;
+ bmi_regs.bmic0 &= ~SSBM;
// clear the bus master active bit in the status register
- bmi_regs[BMIS0] &= ~BMIDEA;
+ bmi_regs.bmis0 &= ~BMIDEA;
// set the interrupt bit
- bmi_regs[BMIS0] |= IDEINTS;
+ bmi_regs.bmis0 |= IDEINTS;
} else {
// clear the start/stop bit in the command register
- bmi_regs[BMIC1] &= ~SSBM;
+ bmi_regs.bmic1 &= ~SSBM;
// clear the bus master active bit in the status register
- bmi_regs[BMIS1] &= ~BMIDEA;
+ bmi_regs.bmis1 &= ~BMIDEA;
// set the interrupt bit
- bmi_regs[BMIS1] |= IDEINTS;
+ bmi_regs.bmis1 |= IDEINTS;
}
}
@@ -249,105 +251,79 @@ IdeController::cacheAccess(MemReqPtr &req)
////
void
-IdeController::ReadConfig(int offset, int size, uint8_t *data)
+IdeController::readConfig(int offset, int size, uint8_t *data)
{
-
-#if TRACING_ON
- Addr origOffset = offset;
-#endif
+ int config_offset;
if (offset < PCI_DEVICE_SPECIFIC) {
- PciDev::ReadConfig(offset, size, data);
- } else {
- if (offset >= PCI_IDE_TIMING && offset < (PCI_IDE_TIMING + 4)) {
- offset -= PCI_IDE_TIMING;
- offset += IDETIM;
-
- if ((offset + size) > (IDETIM + 4))
- panic("PCI read of IDETIM with invalid size\n");
- } else if (offset == PCI_SLAVE_TIMING) {
- offset -= PCI_SLAVE_TIMING;
- offset += SIDETIM;
-
- if ((offset + size) > (SIDETIM + 1))
- panic("PCI read of SIDETIM with invalid size\n");
- } else if (offset == PCI_UDMA33_CTRL) {
- offset -= PCI_UDMA33_CTRL;
- offset += UDMACTL;
-
- if ((offset + size) > (UDMACTL + 1))
- panic("PCI read of UDMACTL with invalid size\n");
- } else if (offset >= PCI_UDMA33_TIMING &&
- offset < (PCI_UDMA33_TIMING + 2)) {
- offset -= PCI_UDMA33_TIMING;
- offset += UDMATIM;
-
- if ((offset + size) > (UDMATIM + 2))
- panic("PCI read of UDMATIM with invalid size\n");
- } else {
- panic("PCI read of unimplemented register: %x\n", offset);
+ PciDev::readConfig(offset, size, data);
+ } else if (offset >= IDE_CTRL_CONF_START &&
+ (offset + size) <= IDE_CTRL_CONF_END) {
+
+ config_offset = offset - IDE_CTRL_CONF_START;
+
+ switch (size) {
+ case sizeof(uint8_t):
+ *data = config_regs.data[config_offset];
+ break;
+ case sizeof(uint16_t):
+ *(uint16_t*)data = *(uint16_t*)&config_regs.data[config_offset];
+ break;
+ case sizeof(uint32_t):
+ *(uint32_t*)data = *(uint32_t*)&config_regs.data[config_offset];
+ break;
+ default:
+ panic("Invalid PCI configuration read size!\n");
}
- memcpy((void *)data, (void *)&pci_regs[offset], size);
- }
+ DPRINTF(IdeCtrl, "PCI read offset: %#x size: %#x data: %#x\n",
+ offset, size, *(uint32_t*)data);
- DPRINTF(IdeCtrl, "PCI read offset: %#x (%#x) size: %#x data: %#x\n",
- origOffset, offset, size,
- (*(uint32_t *)data) & (0xffffffff >> 8 * (4 - size)));
+ } else {
+ panic("Read of unimplemented PCI config. register: %x\n", offset);
+ }
}
void
-IdeController::WriteConfig(int offset, int size, uint32_t data)
+IdeController::writeConfig(int offset, int size, const uint8_t *data)
{
- DPRINTF(IdeCtrl, "PCI write offset: %#x size: %#x data: %#x\n",
- offset, size, data & (0xffffffff >> 8 * (4 - size)));
+ int config_offset;
- // do standard write stuff if in standard PCI space
if (offset < PCI_DEVICE_SPECIFIC) {
- PciDev::WriteConfig(offset, size, data);
- } else {
- if (offset >= PCI_IDE_TIMING && offset < (PCI_IDE_TIMING + 4)) {
- offset -= PCI_IDE_TIMING;
- offset += IDETIM;
-
- if ((offset + size) > (IDETIM + 4))
- panic("PCI write to IDETIM with invalid size\n");
- } else if (offset == PCI_SLAVE_TIMING) {
- offset -= PCI_SLAVE_TIMING;
- offset += SIDETIM;
-
- if ((offset + size) > (SIDETIM + 1))
- panic("PCI write to SIDETIM with invalid size\n");
- } else if (offset == PCI_UDMA33_CTRL) {
- offset -= PCI_UDMA33_CTRL;
- offset += UDMACTL;
-
- if ((offset + size) > (UDMACTL + 1))
- panic("PCI write to UDMACTL with invalid size\n");
- } else if (offset >= PCI_UDMA33_TIMING &&
- offset < (PCI_UDMA33_TIMING + 2)) {
- offset -= PCI_UDMA33_TIMING;
- offset += UDMATIM;
-
- if ((offset + size) > (UDMATIM + 2))
- panic("PCI write to UDMATIM with invalid size\n");
- } else {
- panic("PCI write to unimplemented register: %x\n", offset);
+ PciDev::writeConfig(offset, size, data);
+ } else if (offset >= IDE_CTRL_CONF_START &&
+ (offset + size) <= IDE_CTRL_CONF_END) {
+
+ config_offset = offset - IDE_CTRL_CONF_START;
+
+ switch(size) {
+ case sizeof(uint8_t):
+ config_regs.data[config_offset] = *data;
+ case sizeof(uint16_t):
+ *(uint16_t*)&config_regs.data[config_offset] = *(uint16_t*)data;
+ case sizeof(uint32_t):
+ *(uint32_t*)&config_regs.data[config_offset] = *(uint32_t*)data;
+ break;
+ default:
+ panic("Invalid PCI configuration write size!\n");
}
-
- memcpy((void *)&pci_regs[offset], (void *)&data, size);
+ } else {
+ panic("Write of unimplemented PCI config. register: %x\n", offset);
}
+ DPRINTF(IdeCtrl, "PCI write offset: %#x size: %#x data: %#x\n",
+ offset, size, data);
+
// Catch the writes to specific PCI registers that have side affects
// (like updating the PIO ranges)
switch (offset) {
case PCI_COMMAND:
- if (config.data[offset] & PCI_CMD_IOSE)
+ if (letoh(config.command) & PCI_CMD_IOSE)
io_enabled = true;
else
io_enabled = false;
- if (config.data[offset] & PCI_CMD_BME)
+ if (letoh(config.command) & PCI_CMD_BME)
bm_enabled = true;
else
bm_enabled = false;
@@ -413,37 +389,68 @@ Fault
IdeController::read(MemReqPtr &req, uint8_t *data)
{
Addr offset;
- bool primary;
- bool byte;
- bool cmdBlk;
- RegType_t type;
+ IdeChannel channel;
+ IdeRegType reg_type;
int disk;
- parseAddr(req->paddr, offset, primary, type);
- byte = (req->size == sizeof(uint8_t)) ? true : false;
- cmdBlk = (type == COMMAND_BLOCK) ? true : false;
+ parseAddr(req->paddr, offset, channel, reg_type);
if (!io_enabled)
return No_Fault;
- // sanity check the size (allows byte, word, or dword access)
- if (req->size != sizeof(uint8_t) && req->size != sizeof(uint16_t) &&
- req->size != sizeof(uint32_t))
- panic("IDE controller read of invalid size: %#x\n", req->size);
+ switch (reg_type) {
+ case BMI_BLOCK:
+ switch (req->size) {
+ case sizeof(uint8_t):
+ *data = bmi_regs.data[offset];
+ break;
+ case sizeof(uint16_t):
+ *(uint16_t*)data = *(uint16_t*)&bmi_regs.data[offset];
+ break;
+ case sizeof(uint32_t):
+ *(uint32_t*)data = *(uint32_t*)&bmi_regs.data[offset];
+ break;
+ default:
+ panic("IDE read of BMI reg invalid size: %#x\n", req->size);
+ }
+ break;
+
+ case COMMAND_BLOCK:
+ case CONTROL_BLOCK:
+ disk = getDisk(channel);
- if (type != BMI_BLOCK) {
- assert(req->size != sizeof(uint32_t));
+ if (disks[disk] == NULL)
+ break;
- disk = getDisk(primary);
- if (disks[disk])
- disks[disk]->read(offset, byte, cmdBlk, data);
- } else {
- memcpy((void *)data, &bmi_regs[offset], req->size);
+ switch (offset) {
+ case DATA_OFFSET:
+ switch (req->size) {
+ case sizeof(uint16_t):
+ disks[disk]->read(offset, reg_type, data);
+ break;
+
+ case sizeof(uint32_t):
+ disks[disk]->read(offset, reg_type, data);
+ disks[disk]->read(offset, reg_type, &data[2]);
+ break;
+
+ default:
+ panic("IDE read of data reg invalid size: %#x\n", req->size);
+ }
+ break;
+ default:
+ if (req->size == sizeof(uint8_t)) {
+ disks[disk]->read(offset, reg_type, data);
+ } else
+ panic("IDE read of command reg of invalid size: %#x\n", req->size);
+ }
+ break;
+ default:
+ panic("IDE controller read of unknown register block type!\n");
}
DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
- offset, req->size,
- (*(uint32_t *)data) & (0xffffffff >> 8 * (4 - req->size)));
+ offset, req->size, *(uint32_t*)data);
return No_Fault;
}
@@ -452,41 +459,21 @@ Fault
IdeController::write(MemReqPtr &req, const uint8_t *data)
{
Addr offset;
- bool primary;
- bool byte;
- bool cmdBlk;
- RegType_t type;
+ IdeChannel channel;
+ IdeRegType reg_type;
int disk;
-
- parseAddr(req->paddr, offset, primary, type);
- byte = (req->size == sizeof(uint8_t)) ? true : false;
- cmdBlk = (type == COMMAND_BLOCK) ? true : false;
-
- DPRINTF(IdeCtrl, "write from offset: %#x size: %#x data: %#x\n",
- offset, req->size,
- (*(uint32_t *)data) & (0xffffffff >> 8 * (4 - req->size)));
-
uint8_t oldVal, newVal;
- if (!io_enabled)
- return No_Fault;
+ parseAddr(req->paddr, offset, channel, reg_type);
- if (type == BMI_BLOCK && !bm_enabled)
+ if (!io_enabled)
return No_Fault;
- if (type != BMI_BLOCK) {
- // shadow the dev bit
- if (type == COMMAND_BLOCK && offset == IDE_SELECT_OFFSET) {
- uint8_t *devBit = (primary ? &dev[0] : &dev[1]);
- *devBit = ((*data & IDE_SELECT_DEV_BIT) ? 1 : 0);
- }
-
- assert(req->size != sizeof(uint32_t));
+ switch (reg_type) {
+ case BMI_BLOCK:
+ if (!bm_enabled)
+ return No_Fault;
- disk = getDisk(primary);
- if (disks[disk])
- disks[disk]->write(offset, byte, cmdBlk, data);
- } else {
switch (offset) {
// Bus master IDE command register
case BMIC1:
@@ -495,10 +482,10 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
panic("Invalid BMIC write size: %x\n", req->size);
// select the current disk based on DEV bit
- disk = getDisk(primary);
+ disk = getDisk(channel);
- oldVal = bmi_regs[offset];
- newVal = *data;
+ oldVal = letoh(bmi_regs.chan[channel].bmic);
+ newVal = letoh(*data);
// if a DMA transfer is in progress, R/W control cannot change
if (oldVal & SSBM) {
@@ -514,7 +501,8 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
// clear the BMIDEA bit
- bmi_regs[offset + 0x2] &= ~BMIDEA;
+ bmi_regs.chan[channel].bmis = letoh(
+ letoh(bmi_regs.chan[channel].bmis) & ~BMIDEA);
if (disks[disk] == NULL)
panic("DMA stop for disk %d which does not exist\n",
@@ -527,22 +515,20 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
DPRINTF(IdeCtrl, "Starting DMA transfer\n");
// set the BMIDEA bit
- bmi_regs[offset + 0x2] |= BMIDEA;
+ bmi_regs.chan[channel].bmis = letoh(
+ letoh(bmi_regs.chan[channel].bmis) | BMIDEA);
if (disks[disk] == NULL)
panic("DMA start for disk %d which does not exist\n",
disk);
// inform the disk of the DMA transfer start
- if (primary)
- disks[disk]->startDma(*(uint32_t *)&bmi_regs[BMIDTP0]);
- else
- disks[disk]->startDma(*(uint32_t *)&bmi_regs[BMIDTP1]);
+ disks[disk]->startDma(letoh(bmi_regs.chan[channel].bmidtp));
}
}
// update the register value
- bmi_regs[offset] = newVal;
+ bmi_regs.chan[channel].bmic = letoh(newVal);
break;
// Bus master IDE status register
@@ -551,8 +537,8 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
if (req->size != sizeof(uint8_t))
panic("Invalid BMIS write size: %x\n", req->size);
- oldVal = bmi_regs[offset];
- newVal = *data;
+ oldVal = letoh(bmi_regs.chan[channel].bmis);
+ newVal = letoh(*data);
// the BMIDEA bit is RO
newVal |= (oldVal & BMIDEA);
@@ -568,7 +554,7 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
else
(oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE;
- bmi_regs[offset] = newVal;
+ bmi_regs.chan[channel].bmis = letoh(newVal);
break;
// Bus master IDE descriptor table pointer register
@@ -577,7 +563,8 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
if (req->size != sizeof(uint32_t))
panic("Invalid BMIDTP write size: %x\n", req->size);
- *(uint32_t *)&bmi_regs[offset] = *(uint32_t *)data & ~0x3;
+ bmi_regs.chan[channel].bmidtp = letoh(
+ letoh(*(uint32_t*)data) & ~0x3);
break;
default:
@@ -588,10 +575,50 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
req->size);
// do a default copy of data into the registers
- memcpy((void *)&bmi_regs[offset], data, req->size);
+ memcpy(&bmi_regs.data[offset], data, req->size);
+ }
+ break;
+ case COMMAND_BLOCK:
+ if (offset == IDE_SELECT_OFFSET) {
+ uint8_t *devBit = &dev[channel];
+ *devBit = (letoh(*data) & IDE_SELECT_DEV_BIT) ? 1 : 0;
}
+ // fall-through ok!
+ case CONTROL_BLOCK:
+ disk = getDisk(channel);
+
+ if (disks[disk] == NULL)
+ break;
+
+ switch (offset) {
+ case DATA_OFFSET:
+ switch (req->size) {
+ case sizeof(uint16_t):
+ disks[disk]->write(offset, reg_type, data);
+ break;
+
+ case sizeof(uint32_t):
+ disks[disk]->write(offset, reg_type, data);
+ disks[disk]->write(offset, reg_type, &data[2]);
+ break;
+ default:
+ panic("IDE write of data reg invalid size: %#x\n", req->size);
+ }
+ break;
+ default:
+ if (req->size == sizeof(uint8_t)) {
+ disks[disk]->write(offset, reg_type, data);
+ } else
+ panic("IDE write of command reg of invalid size: %#x\n", req->size);
+ }
+ break;
+ default:
+ panic("IDE controller write of unknown register block type!\n");
}
+ DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
+ offset, req->size, *(uint32_t*)data);
+
return No_Fault;
}
@@ -618,14 +645,14 @@ IdeController::serialize(std::ostream &os)
SERIALIZE_SCALAR(bmi_size);
// Serialize registers
- SERIALIZE_ARRAY(bmi_regs, 16);
- SERIALIZE_ARRAY(dev, 2);
- SERIALIZE_ARRAY(pci_regs, 8);
+ SERIALIZE_ARRAY(bmi_regs.data, sizeof(bmi_regs));
+ SERIALIZE_ARRAY(dev, sizeof(dev));
+ SERIALIZE_ARRAY(config_regs.data, sizeof(config_regs));
// Serialize internal state
SERIALIZE_SCALAR(io_enabled);
SERIALIZE_SCALAR(bm_enabled);
- SERIALIZE_ARRAY(cmd_in_progress, 4);
+ SERIALIZE_ARRAY(cmd_in_progress, sizeof(cmd_in_progress));
}
void
@@ -647,14 +674,14 @@ IdeController::unserialize(Checkpoint *cp, const std::string &section)
UNSERIALIZE_SCALAR(bmi_size);
// Unserialize registers
- UNSERIALIZE_ARRAY(bmi_regs, 16);
- UNSERIALIZE_ARRAY(dev, 2);
- UNSERIALIZE_ARRAY(pci_regs, 8);
+ UNSERIALIZE_ARRAY(bmi_regs.data, sizeof(bmi_regs));
+ UNSERIALIZE_ARRAY(dev, sizeof(dev));
+ UNSERIALIZE_ARRAY(config_regs.data, sizeof(config_regs));
// Unserialize internal state
UNSERIALIZE_SCALAR(io_enabled);
UNSERIALIZE_SCALAR(bm_enabled);
- UNSERIALIZE_ARRAY(cmd_in_progress, 4);
+ UNSERIALIZE_ARRAY(cmd_in_progress, sizeof(cmd_in_progress));
if (pioInterface) {
pioInterface->addAddrRange(RangeSize(pri_cmd_addr, pri_cmd_size));
diff --git a/dev/ide_ctrl.hh b/dev/ide_ctrl.hh
index 4b54c3d57..d50dbbeb1 100644
--- a/dev/ide_ctrl.hh
+++ b/dev/ide_ctrl.hh
@@ -63,22 +63,19 @@
#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET
#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET
+// IDE Timing Register bit fields
+#define IDETIM_DECODE_EN 0x8000
+
// PCI device specific register byte offsets
-#define PCI_IDE_TIMING 0x40
-#define PCI_SLAVE_TIMING 0x44
-#define PCI_UDMA33_CTRL 0x48
-#define PCI_UDMA33_TIMING 0x4a
-
-#define IDETIM (0)
-#define SIDETIM (4)
-#define UDMACTL (5)
-#define UDMATIM (6)
-
-typedef enum RegType {
- COMMAND_BLOCK = 0,
+#define IDE_CTRL_CONF_START 0x40
+#define IDE_CTRL_CONF_END ((IDE_CTRL_CONF_START) + sizeof(config_regs))
+
+
+enum IdeRegType {
+ COMMAND_BLOCK,
CONTROL_BLOCK,
BMI_BLOCK
-} RegType_t;
+};
class BaseInterface;
class Bus;
@@ -97,6 +94,11 @@ class IdeController : public PciDev
{
friend class IdeDisk;
+ enum IdeChannel {
+ PRIMARY = 0,
+ SECONDARY = 1
+ };
+
private:
/** Primary command block registers */
Addr pri_cmd_addr;
@@ -116,11 +118,49 @@ class IdeController : public PciDev
private:
/** Registers used for bus master interface */
- uint8_t bmi_regs[16];
+ union {
+ uint8_t data[16];
+
+ struct {
+ uint8_t bmic0;
+ uint8_t reserved_0;
+ uint8_t bmis0;
+ uint8_t reserved_1;
+ uint32_t bmidtp0;
+ uint8_t bmic1;
+ uint8_t reserved_2;
+ uint8_t bmis1;
+ uint8_t reserved_3;
+ 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;
/** Shadows of the device select bit */
uint8_t dev[2];
- /** Registers used in PCI configuration */
- uint8_t pci_regs[8];
+ /** Registers used in device specific PCI configuration */
+ union {
+ uint8_t data[22];
+
+ struct {
+ uint16_t idetim0;
+ uint16_t idetim1;
+ uint8_t sidetim;
+ uint8_t reserved_0[3];
+ uint8_t udmactl;
+ uint8_t reserved_1;
+ uint16_t udmatim;
+ uint8_t reserved_2[8];
+ uint16_t ideconfig;
+ };
+ } config_regs;
// Internal management variables
bool io_enabled;
@@ -133,11 +173,11 @@ class IdeController : public PciDev
private:
/** Parse the access address to pass on to device */
- void parseAddr(const Addr &addr, Addr &offset, bool &primary,
- RegType_t &type);
+ void parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel,
+ IdeRegType &reg_type);
/** 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 */
int getDisk(IdeDisk *diskPtr);
@@ -161,8 +201,8 @@ class IdeController : public PciDev
IdeController(Params *p);
~IdeController();
- virtual void WriteConfig(int offset, int size, uint32_t data);
- virtual void ReadConfig(int offset, int size, uint8_t *data);
+ virtual void writeConfig(int offset, int size, const uint8_t *data);
+ virtual void readConfig(int offset, int size, uint8_t *data);
void setDmaComplete(IdeDisk *disk);
diff --git a/dev/ide_disk.cc b/dev/ide_disk.cc
index 23d04bb5e..bd9aac8ea 100644
--- a/dev/ide_disk.cc
+++ b/dev/ide_disk.cc
@@ -116,6 +116,9 @@ IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys,
driveID.atap_udmamode_supp = 0x10;
// Statically set hardware config word
driveID.atap_hwreset_res = 0x4001;
+
+ //arbitrary for now...
+ driveID.atap_ata_major = WDC_VER_ATA7;
}
IdeDisk::~IdeDisk()
@@ -158,6 +161,10 @@ IdeDisk::reset(int id)
// set the device ready 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;
}
////
@@ -207,41 +214,52 @@ IdeDisk::bytesInDmaPage(Addr curAddr, uint32_t bytesLeft)
////
void
-IdeDisk::read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data)
+IdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data)
{
DevAction_t action = ACT_NONE;
- if (cmdBlk) {
- if (offset < 0 || offset > sizeof(CommandReg_t))
- panic("Invalid disk command register offset: %#x\n", offset);
-
- if (!byte && offset != DATA_OFFSET)
- panic("Invalid 16-bit read, only allowed on data reg\n");
-
- if (!byte)
- *(uint16_t *)data = *(uint16_t *)&cmdReg.data0;
- else
- *data = ((uint8_t *)&cmdReg)[offset];
-
- // determine if an action needs to be taken on the state machine
- if (offset == STATUS_OFFSET) {
+ switch (reg_type) {
+ case COMMAND_BLOCK:
+ switch (offset) {
+ // Data transfers occur two bytes at a time
+ case DATA_OFFSET:
+ *(uint16_t*)data = cmdReg.data;
+ action = ACT_DATA_READ_SHORT;
+ break;
+ case ERROR_OFFSET:
+ *data = cmdReg.error;
+ break;
+ case NSECTOR_OFFSET:
+ *data = cmdReg.sec_count;
+ break;
+ case SECTOR_OFFSET:
+ *data = cmdReg.sec_num;
+ break;
+ case LCYL_OFFSET:
+ *data = cmdReg.cyl_low;
+ break;
+ case HCYL_OFFSET:
+ *data = cmdReg.cyl_high;
+ break;
+ case DRIVE_OFFSET:
+ *data = cmdReg.drive;
+ break;
+ case STATUS_OFFSET:
+ *data = status;
action = ACT_STAT_READ;
- *data = status; // status is in a shadow, explicity copy
- } else if (offset == DATA_OFFSET) {
- if (byte)
- action = ACT_DATA_READ_BYTE;
- else
- action = ACT_DATA_READ_SHORT;
+ break;
+ default:
+ panic("Invalid IDE command register offset: %#x\n", offset);
}
-
- } else {
- if (offset != ALTSTAT_OFFSET)
- panic("Invalid disk control register offset: %#x\n", offset);
-
- if (!byte)
- panic("Invalid 16-bit read from control block\n");
-
- *data = status;
+ break;
+ case CONTROL_BLOCK:
+ if (offset == ALTSTAT_OFFSET)
+ *data = status;
+ else
+ panic("Invalid IDE control register offset: %#x\n", offset);
+ break;
+ default:
+ panic("Unknown register block!\n");
}
if (action != ACT_NONE)
@@ -249,50 +267,59 @@ IdeDisk::read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data)
}
void
-IdeDisk::write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data)
+IdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data)
{
DevAction_t action = ACT_NONE;
- if (cmdBlk) {
- if (offset < 0 || offset > sizeof(CommandReg_t))
- panic("Invalid disk command register offset: %#x\n", offset);
-
- if (!byte && offset != DATA_OFFSET)
- panic("Invalid 16-bit write, only allowed on data reg\n");
-
- if (!byte)
- *((uint16_t *)&cmdReg.data0) = *(uint16_t *)data;
- else
- ((uint8_t *)&cmdReg)[offset] = *data;
-
- // determine if an action needs to be taken on the state machine
- if (offset == COMMAND_OFFSET) {
- action = ACT_CMD_WRITE;
- } else if (offset == DATA_OFFSET) {
- if (byte)
- action = ACT_DATA_WRITE_BYTE;
- else
- action = ACT_DATA_WRITE_SHORT;
- } else if (offset == SELECT_OFFSET) {
+ switch (reg_type) {
+ case COMMAND_BLOCK:
+ switch (offset) {
+ case DATA_OFFSET:
+ cmdReg.data = *(uint16_t*)data;
+ action = ACT_DATA_WRITE_SHORT;
+ break;
+ case FEATURES_OFFSET:
+ break;
+ case NSECTOR_OFFSET:
+ cmdReg.sec_count = *data;
+ break;
+ case SECTOR_OFFSET:
+ cmdReg.sec_num = *data;
+ break;
+ case LCYL_OFFSET:
+ cmdReg.cyl_low = *data;
+ break;
+ case HCYL_OFFSET:
+ cmdReg.cyl_high = *data;
+ break;
+ case DRIVE_OFFSET:
+ cmdReg.drive = *data;
action = ACT_SELECT_WRITE;
+ break;
+ case COMMAND_OFFSET:
+ cmdReg.command = *data;
+ action = ACT_CMD_WRITE;
+ break;
+ default:
+ panic("Invalid IDE command register offset: %#x\n", offset);
}
-
- } else {
- if (offset != CONTROL_OFFSET)
- panic("Invalid disk control register offset: %#x\n", offset);
-
- if (!byte)
- panic("Invalid 16-bit write to control block\n");
-
- if (*data & CONTROL_RST_BIT) {
- // force the device into the reset state
- devState = Device_Srst;
- action = ACT_SRST_SET;
- } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) {
- action = ACT_SRST_CLEAR;
+ break;
+ case CONTROL_BLOCK:
+ if (offset == CONTROL_OFFSET) {
+ if (*data & CONTROL_RST_BIT) {
+ // force the device into the reset state
+ devState = Device_Srst;
+ action = ACT_SRST_SET;
+ } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT))
+ action = ACT_SRST_CLEAR;
+
+ nIENBit = (*data & CONTROL_IEN_BIT) ? true : false;
}
-
- nIENBit = (*data & CONTROL_IEN_BIT) ? true : false;
+ else
+ panic("Invalid IDE control register offset: %#x\n", offset);
+ break;
+ default:
+ panic("Unknown register block!\n");
}
if (action != ACT_NONE)
@@ -744,8 +771,10 @@ IdeDisk::intrPost()
intrPending = true;
// talk to controller to set interrupt
- if (ctrl)
+ if (ctrl) {
+ ctrl->bmi_regs.bmis0 |= IDEINTS;
ctrl->intrPost();
+ }
}
void
@@ -864,7 +893,7 @@ IdeDisk::updateState(DevAction_t action)
}
// put the first two bytes into the data register
- memcpy((void *)&cmdReg.data0, (void *)dataBuffer,
+ memcpy((void *)&cmdReg.data, (void *)dataBuffer,
sizeof(uint16_t));
if (!isIENSet()) {
@@ -893,7 +922,7 @@ IdeDisk::updateState(DevAction_t action)
// copy next short into data registers
if (drqBytesLeft)
- memcpy((void *)&cmdReg.data0,
+ memcpy((void *)&cmdReg.data,
(void *)&dataBuffer[SectorSize - drqBytesLeft],
sizeof(uint16_t));
}
@@ -966,7 +995,7 @@ IdeDisk::updateState(DevAction_t action)
} else {
// copy the latest short into the data buffer
memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
- (void *)&cmdReg.data0,
+ (void *)&cmdReg.data,
sizeof(uint16_t));
drqBytesLeft -= 2;
@@ -1090,8 +1119,7 @@ IdeDisk::serialize(ostream &os)
SERIALIZE_ENUM(event);
// Serialize device registers
- SERIALIZE_SCALAR(cmdReg.data0);
- SERIALIZE_SCALAR(cmdReg.data1);
+ SERIALIZE_SCALAR(cmdReg.data);
SERIALIZE_SCALAR(cmdReg.sec_count);
SERIALIZE_SCALAR(cmdReg.sec_num);
SERIALIZE_SCALAR(cmdReg.cyl_low);
@@ -1143,8 +1171,7 @@ IdeDisk::unserialize(Checkpoint *cp, const string &section)
}
// Unserialize device registers
- UNSERIALIZE_SCALAR(cmdReg.data0);
- UNSERIALIZE_SCALAR(cmdReg.data1);
+ UNSERIALIZE_SCALAR(cmdReg.data);
UNSERIALIZE_SCALAR(cmdReg.sec_count);
UNSERIALIZE_SCALAR(cmdReg.sec_num);
UNSERIALIZE_SCALAR(cmdReg.cyl_low);
diff --git a/dev/ide_disk.hh b/dev/ide_disk.hh
index 506f0c7cb..a656ca464 100644
--- a/dev/ide_disk.hh
+++ b/dev/ide_disk.hh
@@ -35,6 +35,7 @@
#include "dev/disk_image.hh"
#include "dev/ide_atareg.h"
+#include "dev/ide_ctrl.hh"
#include "dev/ide_wdcreg.h"
#include "dev/io_device.hh"
#include "sim/eventq.hh"
@@ -83,6 +84,7 @@ class PrdTableEntry {
#define LCYL_OFFSET (4)
#define HCYL_OFFSET (5)
#define SELECT_OFFSET (6)
+#define DRIVE_OFFSET (6)
#define STATUS_OFFSET (7)
#define COMMAND_OFFSET (7)
@@ -103,12 +105,8 @@ class PrdTableEntry {
#define DEV1 (1)
typedef struct CommandReg {
- uint8_t data0;
- union {
- uint8_t data1;
- uint8_t error;
- uint8_t features;
- };
+ uint16_t data;
+ uint8_t error;
uint8_t sec_count;
uint8_t sec_num;
uint8_t cyl_low;
@@ -272,8 +270,8 @@ class IdeDisk : public SimObject
}
// Device register read/write
- void read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data);
- void write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data);
+ void read(const Addr &offset, IdeRegType regtype, uint8_t *data);
+ void write(const Addr &offset, IdeRegType regtype, const uint8_t *data);
// Start/abort functions
void startDma(const uint32_t &prdTableBase);
diff --git a/dev/isa_fake.cc b/dev/isa_fake.cc
new file mode 100755
index 000000000..af8005f9c
--- /dev/null
+++ b/dev/isa_fake.cc
@@ -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)
diff --git a/dev/isa_fake.hh b/dev/isa_fake.hh
new file mode 100755
index 000000000..d3d37b035
--- /dev/null
+++ b/dev/isa_fake.hh
@@ -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__
diff --git a/dev/ns_gige.cc b/dev/ns_gige.cc
index 4e7deba90..03942cb62 100644
--- a/dev/ns_gige.cc
+++ b/dev/ns_gige.cc
@@ -491,10 +491,10 @@ NSGigE::regStats()
* This is to read the PCI general configuration registers
*/
void
-NSGigE::ReadConfig(int offset, int size, uint8_t *data)
+NSGigE::readConfig(int offset, int size, uint8_t *data)
{
if (offset < PCI_DEVICE_SPECIFIC)
- PciDev::ReadConfig(offset, size, data);
+ PciDev::readConfig(offset, size, data);
else
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
*/
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)
- PciDev::WriteConfig(offset, size, data);
+ PciDev::writeConfig(offset, size, data);
else
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) {
panic("Accessing reserved register");
} else if (daddr > RESERVED && daddr <= 0x3FC) {
- ReadConfig(daddr & 0xff, req->size, data);
+ readConfig(daddr & 0xff, req->size, data);
return No_Fault;
} else if (daddr >= MIB_START && daddr <= MIB_END) {
// don't implement all the MIB's. hopefully the kernel
@@ -783,7 +783,7 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data)
if (daddr > LAST && daddr <= RESERVED) {
panic("Accessing reserved register");
} else if (daddr > RESERVED && daddr <= 0x3FC) {
- WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
+ writeConfig(daddr & 0xff, req->size, data);
return No_Fault;
} else if (daddr > 0x3FC)
panic("Something is messed up!\n");
@@ -1360,7 +1360,7 @@ void
NSGigE::regsReset()
{
memset(&regs, 0, sizeof(regs));
- regs.config = CFGR_LNKSTS;
+ regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000);
regs.mear = 0x22;
regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
// fill threshold to 32 bytes
diff --git a/dev/ns_gige.hh b/dev/ns_gige.hh
index 143460b64..805d4c8cb 100644
--- a/dev/ns_gige.hh
+++ b/dev/ns_gige.hh
@@ -99,7 +99,7 @@ class Bus;
class PciConfigAll;
/**
- * NS DP82830 Ethernet device model
+ * NS DP83820 Ethernet device model
*/
class NSGigE : public PciDev
{
@@ -353,8 +353,8 @@ class NSGigE : public PciDev
~NSGigE();
const Params *params() const { return (const Params *)_params; }
- virtual void WriteConfig(int offset, int size, uint32_t data);
- virtual void ReadConfig(int offset, int size, uint8_t *data);
+ virtual void writeConfig(int offset, int size, const uint8_t *data);
+ virtual void readConfig(int offset, int size, uint8_t *data);
virtual Fault read(MemReqPtr &req, uint8_t *data);
virtual Fault write(MemReqPtr &req, const uint8_t *data);
diff --git a/dev/pciconfigall.cc b/dev/pciconfigall.cc
index 7d86c3e1b..6a5b2e56f 100644
--- a/dev/pciconfigall.cc
+++ b/dev/pciconfigall.cc
@@ -65,7 +65,7 @@ PciConfigAll::PciConfigAll(const string &name,
// Make all the pointers to devices null
for(int x=0; x < MAX_PCI_DEV; x++)
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.
@@ -130,7 +130,7 @@ PciConfigAll::read(MemReqPtr &req, uint8_t *data)
case sizeof(uint32_t):
case sizeof(uint16_t):
case sizeof(uint8_t):
- devices[device][func]->ReadConfig(reg, req->size, data);
+ devices[device][func]->readConfig(reg, req->size, data);
return No_Fault;
default:
panic("invalid access size(?) for PCI configspace!\n");
@@ -152,34 +152,17 @@ PciConfigAll::write(MemReqPtr &req, const uint8_t *data)
int func = (daddr >> 8) & 0x7;
int reg = daddr & 0xFF;
- union {
- uint8_t byte_value;
- uint16_t half_value;
- uint32_t word_value;
- };
-
if (devices[device][func] == NULL)
panic("Attempting to write to config space on non-existant device\n");
- else {
- switch (req->size) {
- case sizeof(uint8_t):
- byte_value = *(uint8_t*)data;
- break;
- case sizeof(uint16_t):
- half_value = *(uint16_t*)data;
- break;
- case sizeof(uint32_t):
- word_value = *(uint32_t*)data;
- break;
- default:
- panic("invalid access size(?) for PCI configspace!\n");
- }
- }
+ else if (req->size != sizeof(uint8_t) &&
+ req->size != sizeof(uint16_t) &&
+ req->size != sizeof(uint32_t))
+ panic("invalid access size(?) for PCI configspace!\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;
}
diff --git a/dev/pcidev.cc b/dev/pcidev.cc
index f2bce33ca..04a38151e 100644
--- a/dev/pcidev.cc
+++ b/dev/pcidev.cc
@@ -71,74 +71,62 @@ PciDev::PciDev(Params *p)
}
void
-PciDev::ReadConfig(int offset, int size, uint8_t *data)
+PciDev::readConfig(int offset, int size, uint8_t *data)
{
if (offset >= PCI_DEVICE_SPECIFIC)
panic("Device specific PCI config space not implemented!\n");
switch(size) {
- case sizeof(uint32_t):
- memcpy((uint8_t*)data, config.data + offset, sizeof(uint32_t));
- *(uint32_t*)data = htoa(*(uint32_t*)data);
- DPRINTF(PCIDEV,
- "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n",
- params()->deviceNum, params()->functionNum, offset, size,
- *(uint32_t*)(config.data + offset));
+ case sizeof(uint8_t):
+ *data = config.data[offset];
break;
-
case sizeof(uint16_t):
- memcpy((uint8_t*)data, config.data + offset, sizeof(uint16_t));
- *(uint16_t*)data = htoa(*(uint16_t*)data);
- DPRINTF(PCIDEV,
- "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n",
- params()->deviceNum, params()->functionNum, offset, size,
- *(uint16_t*)(config.data + offset));
+ *(uint16_t*)data = *(uint16_t*)&config.data[offset];
break;
-
- case sizeof(uint8_t):
- memcpy((uint8_t*)data, config.data + offset, sizeof(uint8_t));
- DPRINTF(PCIDEV,
- "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n",
- params()->deviceNum, params()->functionNum, offset, size,
- (uint16_t)(*(uint8_t*)(config.data + offset)));
+ case sizeof(uint32_t):
+ *(uint32_t*)data = *(uint32_t*)&config.data[offset];
break;
-
default:
- panic("Invalid Read Size");
+ panic("Invalid PCI configuration read size!\n");
}
+
+ DPRINTF(PCIDEV,
+ "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n",
+ params()->deviceNum, params()->functionNum, offset, size,
+ *(uint32_t*)data);
}
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)
panic("Device specific PCI config space not implemented!\n");
- uint32_t barnum;
-
- union {
- uint8_t byte_value;
- uint16_t half_value;
- uint32_t word_value;
- };
- word_value = data;
+ uint8_t &data8 = *(uint8_t*)data;
+ uint16_t &data16 = *(uint16_t*)data;
+ uint32_t &data32 = *(uint32_t*)data;
DPRINTF(PCIDEV,
"write device: %#x function: %#x reg: %#x size: %d data: %#x\n",
- params()->deviceNum, params()->functionNum, offset, size,
- word_value);
-
- barnum = (offset - PCI0_BASE_ADDR0) >> 2;
+ params()->deviceNum, params()->functionNum, offset, size, data32);
switch (size) {
case sizeof(uint8_t): // 1-byte access
switch (offset) {
case PCI0_INTERRUPT_LINE:
+ config.interruptLine = data8;
case PCI_CACHE_LINE_SIZE:
+ config.cacheLineSize = data8;
case PCI_LATENCY_TIMER:
- *(uint8_t *)&config.data[offset] = htoa(byte_value);
+ config.latencyTimer = data8;
+ break;
+ /* Do nothing for these read-only registers */
+ case PCI0_INTERRUPT_PIN:
+ case PCI0_MINIMUM_GRANT:
+ case PCI0_MAXIMUM_LATENCY:
+ case PCI_CLASS_CODE:
+ case PCI_REVISION_ID:
break;
-
default:
panic("writing to a read only register");
}
@@ -147,19 +135,17 @@ PciDev::WriteConfig(int offset, int size, uint32_t data)
case sizeof(uint16_t): // 2-byte access
switch (offset) {
case PCI_COMMAND:
+ config.command = data16;
case PCI_STATUS:
+ config.status = data16;
case PCI_CACHE_LINE_SIZE:
- *(uint16_t *)&config.data[offset] = htoa(half_value);
+ config.cacheLineSize = data16;
break;
-
default:
panic("writing to a read only register");
}
break;
- case sizeof(uint16_t)+1: // 3-byte access
- panic("invalid access size");
-
case sizeof(uint32_t): // 4-byte access
switch (offset) {
case PCI0_BASE_ADDR0:
@@ -168,110 +154,91 @@ PciDev::WriteConfig(int offset, int size, uint32_t data)
case PCI0_BASE_ADDR3:
case PCI0_BASE_ADDR4:
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
- // value of the bar
- // to size of memory it needs
- if (word_value == 0xffffffff) {
+ // value of the bar to size of memory it needs
+ if (letoh(data32) == 0xffffffff) {
// This is I/O Space, bottom two bits are read only
- if (htoa(config.data[offset]) & 0x1) {
- *(uint32_t *)&config.data[offset] = htoa(
- ~(BARSize[barnum] - 1) |
- (htoa(config.data[offset]) & 0x3));
- } else {
- // This is memory space, bottom four bits are read only
- *(uint32_t *)&config.data[offset] = htoa(
- ~(BARSize[barnum] - 1) |
- (htoa(config.data[offset]) & 0xF));
- }
+
+ config.baseAddr[barnum] = letoh(
+ (~(BARSize[barnum] - 1) & ~bar_mask) |
+ (letoh(config.baseAddr[barnum]) & bar_mask));
} else {
MemoryController *mmu = params()->mmu;
- // This is I/O Space, bottom two bits are read only
- if(htoa(config.data[offset]) & 0x1) {
- *(uint32_t *)&config.data[offset] =
- htoa((word_value & ~0x3) |
- (htoa(config.data[offset]) & 0x3));
-
- if (word_value & ~0x1) {
- Addr base_addr = (word_value & ~0x1) + TSUNAMI_PCI0_IO;
- 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;
- }
-
- } 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;
- }
- }
+ config.baseAddr[barnum] = letoh(
+ (letoh(data32) & ~bar_mask) |
+ (letoh(config.baseAddr[barnum]) & bar_mask));
+
+ if (letoh(config.baseAddr[barnum]) & ~bar_mask) {
+ base_addr = (letoh(data32) & ~bar_mask) + space_base;
+ 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;
case PCI0_ROM_BASE_ADDR:
- if (word_value == 0xfffffffe)
- *(uint32_t *)&config.data[offset] = 0xffffffff;
+ if (letoh(data32) == 0xfffffffe)
+ config.expansionROM = letoh(0xffffffff);
else
- *(uint32_t *)&config.data[offset] = htoa(word_value);
+ config.expansionROM = data32;
break;
case PCI_COMMAND:
// This could also clear some of the error bits in the Status
// register. However they should never get set, so lets ignore
// it for now
- *(uint16_t *)&config.data[offset] = htoa(half_value);
+ config.command = data16;
break;
default:
DPRINTF(PCIDEV, "Writing to a read only register");
}
break;
+
+ default:
+ panic("invalid access size");
}
}
void
PciDev::serialize(ostream &os)
{
- SERIALIZE_ARRAY(BARSize, 6);
- SERIALIZE_ARRAY(BARAddrs, 6);
- SERIALIZE_ARRAY(config.data, 64);
+ SERIALIZE_ARRAY(BARSize, sizeof(BARSize));
+ SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs));
+ SERIALIZE_ARRAY(config.data, sizeof(config.data));
}
void
PciDev::unserialize(Checkpoint *cp, const std::string &section)
{
- UNSERIALIZE_ARRAY(BARSize, 6);
- UNSERIALIZE_ARRAY(BARAddrs, 6);
- UNSERIALIZE_ARRAY(config.data, 64);
+ UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize));
+ UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs));
+ UNSERIALIZE_ARRAY(config.data, sizeof(config.data));
// Add the MMU mappings for the BARs
for (int i=0; i < 6; i++) {
@@ -360,33 +327,33 @@ CREATE_SIM_OBJECT(PciConfigData)
{
PciConfigData *data = new PciConfigData(getInstanceName());
- data->config.hdr.vendor = htoa(VendorID);
- data->config.hdr.device = htoa(DeviceID);
- data->config.hdr.command = htoa(Command);
- data->config.hdr.status = htoa(Status);
- data->config.hdr.revision = htoa(Revision);
- data->config.hdr.progIF = htoa(ProgIF);
- data->config.hdr.subClassCode = htoa(SubClassCode);
- data->config.hdr.classCode = htoa(ClassCode);
- data->config.hdr.cacheLineSize = htoa(CacheLineSize);
- data->config.hdr.latencyTimer = htoa(LatencyTimer);
- data->config.hdr.headerType = htoa(HeaderType);
- data->config.hdr.bist = htoa(BIST);
-
- data->config.hdr.pci0.baseAddr0 = htoa(BAR0);
- data->config.hdr.pci0.baseAddr1 = htoa(BAR1);
- data->config.hdr.pci0.baseAddr2 = htoa(BAR2);
- data->config.hdr.pci0.baseAddr3 = htoa(BAR3);
- data->config.hdr.pci0.baseAddr4 = htoa(BAR4);
- data->config.hdr.pci0.baseAddr5 = htoa(BAR5);
- data->config.hdr.pci0.cardbusCIS = htoa(CardbusCIS);
- data->config.hdr.pci0.subsystemVendorID = htoa(SubsystemVendorID);
- data->config.hdr.pci0.subsystemID = htoa(SubsystemVendorID);
- data->config.hdr.pci0.expansionROM = htoa(ExpansionROM);
- data->config.hdr.pci0.interruptLine = htoa(InterruptLine);
- data->config.hdr.pci0.interruptPin = htoa(InterruptPin);
- data->config.hdr.pci0.minimumGrant = htoa(MinimumGrant);
- data->config.hdr.pci0.maximumLatency = htoa(MaximumLatency);
+ data->config.vendor = htole(VendorID);
+ data->config.device = htole(DeviceID);
+ data->config.command = htole(Command);
+ data->config.status = htole(Status);
+ data->config.revision = htole(Revision);
+ data->config.progIF = htole(ProgIF);
+ data->config.subClassCode = htole(SubClassCode);
+ data->config.classCode = htole(ClassCode);
+ data->config.cacheLineSize = htole(CacheLineSize);
+ data->config.latencyTimer = htole(LatencyTimer);
+ data->config.headerType = htole(HeaderType);
+ data->config.bist = htole(BIST);
+
+ data->config.baseAddr0 = htole(BAR0);
+ data->config.baseAddr1 = htole(BAR1);
+ data->config.baseAddr2 = htole(BAR2);
+ data->config.baseAddr3 = htole(BAR3);
+ data->config.baseAddr4 = htole(BAR4);
+ data->config.baseAddr5 = htole(BAR5);
+ data->config.cardbusCIS = htole(CardbusCIS);
+ data->config.subsystemVendorID = htole(SubsystemVendorID);
+ data->config.subsystemID = htole(SubsystemVendorID);
+ data->config.expansionROM = htole(ExpansionROM);
+ data->config.interruptLine = htole(InterruptLine);
+ data->config.interruptPin = htole(InterruptPin);
+ data->config.minimumGrant = htole(MinimumGrant);
+ data->config.maximumLatency = htole(MaximumLatency);
data->BARSize[0] = BAR0Size;
data->BARSize[1] = BAR1Size;
diff --git a/dev/pcidev.hh b/dev/pcidev.hh
index 091a365e3..4293c59b9 100644
--- a/dev/pcidev.hh
+++ b/dev/pcidev.hh
@@ -37,6 +37,12 @@
#include "dev/pcireg.h"
#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 MemoryController;
@@ -136,15 +142,15 @@ class PciDev : public DmaDevice
void
intrPost()
- { plat->postPciInt(configData->config.hdr.pci0.interruptLine); }
+ { plat->postPciInt(configData->config.interruptLine); }
void
intrClear()
- { plat->clearPciInt(configData->config.hdr.pci0.interruptLine); }
+ { plat->clearPciInt(configData->config.interruptLine); }
uint8_t
interruptLine()
- { return configData->config.hdr.pci0.interruptLine; }
+ { return configData->config.interruptLine; }
public:
/**
@@ -169,7 +175,7 @@ class PciDev : public DmaDevice
* @param size the size of the 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 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.
diff --git a/dev/pcireg.h b/dev/pcireg.h
index 2f71a46ba..9d2737c20 100644
--- a/dev/pcireg.h
+++ b/dev/pcireg.h
@@ -36,68 +36,44 @@
#include <sys/types.h>
union PCIConfig {
- 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;
+ uint8_t data[64];
+ 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 {
- struct {
- 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;
+ uint32_t baseAddr[6];
struct {
- uint32_t baseAddr0;
- uint32_t baseAddr1;
- uint8_t priBusNum;
- uint8_t secBusNum;
- uint8_t subBusNum;
- uint8_t secLatency;
- 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;
+ uint32_t baseAddr0;
+ uint32_t baseAddr1;
+ uint32_t baseAddr2;
+ uint32_t baseAddr3;
+ uint32_t baseAddr4;
+ uint32_t baseAddr5;
+ };
};
- } 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
diff --git a/dev/pitreg.h b/dev/pitreg.h
new file mode 100644
index 000000000..5fe1cf03f
--- /dev/null
+++ b/dev/pitreg.h
@@ -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__
diff --git a/dev/rtcreg.h b/dev/rtcreg.h
index 0b33c25b2..5025a0e95 100644
--- a/dev/rtcreg.h
+++ b/dev/rtcreg.h
@@ -36,8 +36,22 @@
#define RTC_DOM 0x07
#define RTC_MON 0x08
#define RTC_YEAR 0x09
-#define RTC_CNTRL_REGA 0x0A
-#define RTC_CNTRL_REGB 0x0B
-#define RTC_CNTRL_REGC 0x0C
-#define RTC_CNTRL_REGD 0x0D
+
+#define RTC_STAT_REGA 0x0A
+#define RTCA_1024HZ 0x06 /* 1024Hz periodic interrupt frequency */
+#define RTCA_32768HZ 0x20 /* 22-stage divider, 32.768KHz timebase */
+#define RTCA_UIP 0x80 /* 1 = date and time update in progress */
+
+#define RTC_STAT_REGB 0x0B
+#define RTCB_DST 0x01 /* USA Daylight Savings Time enable */
+#define RTCB_24HR 0x02 /* 0 = 12 hours, 1 = 24 hours */
+#define RTCB_BIN 0x04 /* 0 = BCD, 1 = Binary coded time */
+#define RTCB_SQWE 0x08 /* 1 = output sqare wave at SQW pin */
+#define RTCB_UPDT_IE 0x10 /* 1 = enable update-ended interrupt */
+#define RTCB_ALRM_IE 0x20 /* 1 = enable alarm interrupt */
+#define RTCB_PRDC_IE 0x40 /* 1 = enable periodic clock interrupt */
+#define RTCB_NO_UPDT 0x80 /* stop clock updates */
+
+#define RTC_STAT_REGC 0x0C
+#define RTC_STAT_REGD 0x0D
diff --git a/dev/sinic.cc b/dev/sinic.cc
index f8e070e95..d30303835 100644
--- a/dev/sinic.cc
+++ b/dev/sinic.cc
@@ -296,12 +296,12 @@ Device::regStats()
* This is to write to the PCI general configuration registers
*/
void
-Device::WriteConfig(int offset, int size, uint32_t data)
+Device::writeConfig(int offset, int size, const uint8_t *data)
{
switch (offset) {
case PCI0_BASE_ADDR0:
// 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 (pioInterface)
pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
@@ -311,7 +311,7 @@ Device::WriteConfig(int offset, int size, uint32_t data)
break;
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
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
Addr daddr = req->paddr & 0xfff;
@@ -409,7 +409,7 @@ Device::read(MemReqPtr &req, uint8_t *data)
Fault
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;
if (Regs::regSize(daddr) == 0)
diff --git a/dev/sinic.hh b/dev/sinic.hh
index 4fab67b29..d190746a4 100644
--- a/dev/sinic.hh
+++ b/dev/sinic.hh
@@ -238,7 +238,7 @@ class Device : public Base
* PCI Configuration interface
*/
public:
- virtual void WriteConfig(int offset, int size, uint32_t data);
+ virtual void writeConfig(int offset, int size, const uint8_t *data);
/**
* Memory Interface
diff --git a/dev/tsunami_io.cc b/dev/tsunami_io.cc
index da1062237..569bb46cb 100644
--- a/dev/tsunami_io.cc
+++ b/dev/tsunami_io.cc
@@ -39,6 +39,7 @@
#include "base/trace.hh"
#include "dev/tsunami_io.hh"
#include "dev/tsunami.hh"
+#include "dev/pitreg.h"
#include "mem/bus/bus.hh"
#include "mem/bus/pio_interface.hh"
#include "mem/bus/pio_interface_impl.hh"
@@ -50,10 +51,122 @@
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;
+}
+
+void
+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 &section)
+{
+ 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));
+}
-// Timer Event for Periodic interrupt of RTC
-TsunamiIO::RTCEvent::RTCEvent(Tsunami* t, Tick i)
+TsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i)
: Event(&mainEventQueue), tsunami(t), interval(i)
{
DPRINTF(MC146818, "RTC Event Initilizing\n");
@@ -61,7 +174,13 @@ TsunamiIO::RTCEvent::RTCEvent(Tsunami* t, Tick i)
}
void
-TsunamiIO::RTCEvent::process()
+TsunamiIO::RTC::RTCEvent::scheduleIntr()
+{
+ schedule(curTick + interval);
+}
+
+void
+TsunamiIO::RTC::RTCEvent::process()
{
DPRINTF(MC146818, "RTC Timer Interrupt\n");
schedule(curTick + interval);
@@ -70,95 +189,256 @@ TsunamiIO::RTCEvent::process()
}
const char *
-TsunamiIO::RTCEvent::description()
+TsunamiIO::RTC::RTCEvent::description()
{
return "tsunami RTC interrupt";
}
void
-TsunamiIO::RTCEvent::serialize(std::ostream &os)
+TsunamiIO::RTC::RTCEvent::serialize(std::ostream &os)
{
Tick time = when();
SERIALIZE_SCALAR(time);
}
void
-TsunamiIO::RTCEvent::unserialize(Checkpoint *cp, const std::string &section)
+TsunamiIO::RTC::RTCEvent::unserialize(Checkpoint *cp, const std::string &section)
{
Tick time;
UNSERIALIZE_SCALAR(time);
reschedule(time);
}
+TsunamiIO::PITimer::PITimer()
+ : SimObject("PITimer"), counter0(counter[0]), counter1(counter[1]),
+ counter2(counter[2])
+{
-// Timer Event for PIT Timers
-TsunamiIO::ClockEvent::ClockEvent()
- : Event(&mainEventQueue)
+}
+
+void
+TsunamiIO::PITimer::writeControl(const uint8_t *data)
{
- /* 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);
+ int rw;
+ int sel;
+
+ sel = GET_CTRL_SEL(*data);
+
+ if (sel == PIT_READ_BACK)
+ panic("PITimer Read-Back Command is not implemented.\n");
- DPRINTF(Tsunami, "Clock Event Initilizing\n");
- mode = 0;
+ 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::ClockEvent::process()
+TsunamiIO::PITimer::serialize(std::ostream &os)
{
- DPRINTF(Tsunami, "Timer Interrupt\n");
- if (mode == 0)
- status = 0x20; // set bit that linux is looking for
- else
- schedule(curTick + interval);
+ // 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::ClockEvent::Program(int count)
+TsunamiIO::PITimer::unserialize(Checkpoint *cp, const std::string &section)
{
- DPRINTF(Tsunami, "Timer set to curTick + %d\n", count * interval);
- schedule(curTick + count * interval);
- status = 0;
+ // unserialze the counters
+ counter0.unserialize(cp, csprintf("%s.counter0", section));
+ counter1.unserialize(cp, csprintf("%s.counter1", section));
+ counter2.unserialize(cp, csprintf("%s.counter2", section));
}
-const char *
-TsunamiIO::ClockEvent::description()
+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)
{
- return "tsunami 8254 Interval timer";
+
+}
+
+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::ClockEvent::ChangeMode(uint8_t md)
+TsunamiIO::PITimer::Counter::serialize(std::ostream &os)
{
- mode = md;
+ 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 &section)
+{
+ 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)
+{
+ interval = (Tick)(Clock::Float::s / 1193180.0);
+ counter = c_ptr;
+}
+
+void
+TsunamiIO::PITimer::Counter::CounterEvent::process()
+{
+ DPRINTF(Tsunami, "Timer Interrupt\n");
+ switch (counter->mode) {
+ case PIT_MODE_INTTC:
+ counter->output_high = true;
+ case PIT_MODE_RATEGEN:
+ case PIT_MODE_SQWAVE:
+ break;
+ default:
+ panic("Unimplemented PITimer mode.\n");
+ }
}
-uint8_t
-TsunamiIO::ClockEvent::Status()
+const char *
+TsunamiIO::PITimer::Counter::CounterEvent::description()
{
- return status;
+ return "tsunami 8254 Interval timer";
}
void
-TsunamiIO::ClockEvent::serialize(std::ostream &os)
+TsunamiIO::PITimer::Counter::CounterEvent::serialize(std::ostream &os)
{
Tick time = scheduled() ? when() : 0;
SERIALIZE_SCALAR(time);
- SERIALIZE_SCALAR(status);
- SERIALIZE_SCALAR(mode);
SERIALIZE_SCALAR(interval);
}
void
-TsunamiIO::ClockEvent::unserialize(Checkpoint *cp, const std::string &section)
+TsunamiIO::PITimer::Counter::CounterEvent::unserialize(Checkpoint *cp, const std::string &section)
{
Tick time;
UNSERIALIZE_SCALAR(time);
- UNSERIALIZE_SCALAR(status);
- UNSERIALIZE_SCALAR(mode);
UNSERIALIZE_SCALAR(interval);
if (time)
schedule(time);
@@ -182,8 +462,7 @@ TsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time,
tsunami->io = this;
timerData = 0;
- set_time(init_time == 0 ? time(NULL) : init_time);
- uip = 1;
+ rtc.set_time(init_time == 0 ? time(NULL) : init_time);
picr = 0;
picInterrupting = false;
}
@@ -194,13 +473,6 @@ TsunamiIO::frequency() const
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
TsunamiIO::read(MemReqPtr &req, uint8_t *data)
{
@@ -213,6 +485,13 @@ TsunamiIO::read(MemReqPtr &req, uint8_t *data)
switch(req->size) {
case sizeof(uint8_t):
switch(daddr) {
+ // PIC1 mask read
+ case TSDEV_PIC1_MASK:
+ *(uint8_t*)data = ~mask1;
+ return No_Fault;
+ case TSDEV_PIC2_MASK:
+ *(uint8_t*)data = ~mask2;
+ return No_Fault;
case TSDEV_PIC1_ISR:
// !!! If this is modified 64bit case needs to be too
// Pal code has to do a 64 bit physical read because there is
@@ -223,50 +502,24 @@ TsunamiIO::read(MemReqPtr &req, uint8_t *data)
// PIC2 not implemnted... just return 0
*(uint8_t*)data = 0x00;
return No_Fault;
- case TSDEV_TMR_CTL:
- *(uint8_t*)data = timer2.Status();
+ case TSDEV_TMR0_DATA:
+ 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;
case TSDEV_RTC_DATA:
- switch(RTCAddress) {
- case RTC_CNTRL_REGA:
- *(uint8_t*)data = uip << 7 | 0x26;
- uip = !uip;
- return No_Fault;
- case RTC_CNTRL_REGB:
- // DM and 24/12 and UIE
- *(uint8_t*)data = 0x46;
- 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:
- *(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;
- return No_Fault;
- case RTC_DOM:
- *(uint8_t *)data = tm.tm_mday;
- case RTC_MON:
- *(uint8_t *)data = tm.tm_mon + 1;
- return No_Fault;
- case RTC_YEAR:
- *(uint8_t *)data = tm.tm_year - UNIX_YEAR_OFFSET;
- return No_Fault;
- default:
- panic("Unknown RTC Address\n");
- }
-
+ rtc.readData(data);
+ return No_Fault;
+ case TSDEV_CTRL_PORTB:
+ if (pitimer.counter2.outputHigh())
+ *data = PORTB_SPKR_HIGH;
+ else
+ *data = 0x00;
+ return No_Fault;
default:
panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
}
@@ -337,6 +590,14 @@ TsunamiIO::write(MemReqPtr &req, const uint8_t *data)
if (!(picr & mask1))
tsunami->cchip->clearDRIR(55);
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:
return No_Fault;
case TSDEV_DMA1_RESET:
@@ -352,54 +613,31 @@ TsunamiIO::write(MemReqPtr &req, const uint8_t *data)
case TSDEV_DMA1_MASK:
case TSDEV_DMA2_MASK:
return No_Fault;
- case TSDEV_TMR_CTL:
+ case TSDEV_TMR0_DATA:
+ pitimer.counter0.write(data);
return No_Fault;
- case TSDEV_TMR2_CTL:
- if ((*(uint8_t*)data & 0x30) != 0x30)
- panic("Only L/M write 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");
- }
+ case TSDEV_TMR1_DATA:
+ pitimer.counter1.write(data);
return No_Fault;
case TSDEV_TMR2_DATA:
- /* two writes before we actually start the Timer
- 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;
- }
+ pitimer.counter2.write(data);
return No_Fault;
- case TSDEV_TMR0_DATA:
- /* two writes before we actually start the Timer
- so I set a flag in the timerData */
- if(timerData & 0x1000) {
- timerData &= 0x1000;
- timerData += *(uint8_t*)data << 8;
- timer0.Program(timerData);
- } else {
- timerData = *(uint8_t*)data;
- timerData |= 0x1000;
- }
+ case TSDEV_TMR_CTRL:
+ pitimer.writeControl(data);
return No_Fault;
case TSDEV_RTC_ADDR:
- RTCAddress = *(uint8_t*)data;
+ rtc.writeAddr(data);
+ return No_Fault;
+ case TSDEV_KBD:
return No_Fault;
case TSDEV_RTC_DATA:
- panic("RTC Write not implmented (rtc.o won't work)\n");
+ rtc.writeData(data);
+ return No_Fault;
+ case TSDEV_CTRL_PORTB:
+ // System Control Port B not implemented
+ return No_Fault;
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(uint32_t):
@@ -445,20 +683,16 @@ void
TsunamiIO::serialize(std::ostream &os)
{
SERIALIZE_SCALAR(timerData);
- SERIALIZE_SCALAR(uip);
SERIALIZE_SCALAR(mask1);
SERIALIZE_SCALAR(mask2);
SERIALIZE_SCALAR(mode1);
SERIALIZE_SCALAR(mode2);
SERIALIZE_SCALAR(picr);
SERIALIZE_SCALAR(picInterrupting);
- SERIALIZE_SCALAR(RTCAddress);
// Serialize the timers
- nameOut(os, csprintf("%s.timer0", name()));
- timer0.serialize(os);
- nameOut(os, csprintf("%s.timer2", name()));
- timer2.serialize(os);
+ nameOut(os, csprintf("%s.pitimer", name()));
+ pitimer.serialize(os);
nameOut(os, csprintf("%s.rtc", name()));
rtc.serialize(os);
}
@@ -467,18 +701,15 @@ void
TsunamiIO::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_SCALAR(timerData);
- UNSERIALIZE_SCALAR(uip);
UNSERIALIZE_SCALAR(mask1);
UNSERIALIZE_SCALAR(mask2);
UNSERIALIZE_SCALAR(mode1);
UNSERIALIZE_SCALAR(mode2);
UNSERIALIZE_SCALAR(picr);
UNSERIALIZE_SCALAR(picInterrupting);
- UNSERIALIZE_SCALAR(RTCAddress);
// Unserialize the timers
- timer0.unserialize(cp, csprintf("%s.timer0", section));
- timer2.unserialize(cp, csprintf("%s.timer2", section));
+ pitimer.unserialize(cp, csprintf("%s.pitimer", section));
rtc.unserialize(cp, csprintf("%s.rtc", section));
}
diff --git a/dev/tsunami_io.hh b/dev/tsunami_io.hh
index d5d106db3..5f20cbf4a 100644
--- a/dev/tsunami_io.hh
+++ b/dev/tsunami_io.hh
@@ -53,105 +53,223 @@ class TsunamiIO : public PioDevice
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:
- /**
- * The ClockEvent is handles the PIT interrupts
- */
- class ClockEvent : public Event
+ /** Real-Time Clock (MC146818) */
+ class RTC : public SimObject
{
- protected:
- /** how often the PIT fires */
- Tick interval;
- /** The mode of the PIT */
- uint8_t mode;
- /** The status of the PIT */
- uint8_t status;
+ /** Event for RTC periodic interrupt */
+ class RTCEvent : public Event
+ {
+ private:
+ /** A pointer back to tsunami to create interrupt the processor. */
+ Tsunami* tsunami;
+ Tick interval;
+
+ public:
+ RTCEvent(Tsunami* t, Tick i);
+
+ /** Schedule the RTC periodic interrupt */
+ void scheduleIntr();
+
+ /** 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 &section);
+ };
+
+ 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:
- /**
- * Just set the mode to 0
- */
- ClockEvent();
+ RTC(Tsunami* t, Tick i);
- /**
- * processs the timer event
- */
- virtual void process();
+ /** Set the initial RTC time/date */
+ void set_time(time_t t);
- /**
- * 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);
+ /** RTC address port: write address of RTC RAM data to access */
+ void writeAddr(const uint8_t *data);
- /**
- * Write the mode bits of the PIT.
- * @param mode the new mode
- */
- void ChangeMode(uint8_t mode);
+ /** RTC write data */
+ void writeData(const uint8_t *data);
- /**
- * The current PIT status.
- * @return the status of the PIT
- */
- uint8_t Status();
+ /** RTC read data */
+ void readData(uint8_t *data);
/**
- * Serialize this object to the given output stream.
- * @param os The stream to serialize to.
- */
+ * 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 &section);
- };
+ };
- /**
- * Process RTC timer events and generate interrupts appropriately.
- */
- class RTCEvent : public Event
+ /** Programmable Interval Timer (Intel 8254) */
+ class PITimer : public SimObject
{
- protected:
- /** A pointer back to tsunami to create interrupt the processor. */
- Tsunami* tsunami;
- Tick interval;
+ /** Counter element for PIT */
+ class Counter : public SimObject
+ {
+ /** 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 &section);
+
+ 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 &section);
+ };
+
+ private:
+ /** PIT has three seperate counters */
+ Counter counter[3];
public:
- /**
- * RTC Event initializes the RTC event by scheduling an event
- * RTC_RATE times pre second.
- */
- RTCEvent(Tsunami* t, Tick i);
+ /** Public way to access individual counters (avoid array accesses) */
+ Counter &counter0;
+ Counter &counter1;
+ Counter &counter2;
- /**
- * Interrupth the processor and reschedule the event.
- */
- virtual void process();
+ PITimer();
- /**
- * Return a description of this event.
- * @return a description
- */
- virtual const char *description();
+ /** Write control word */
+ void writeControl(const uint8_t* data);
/**
* Serialize this object to the given output stream.
@@ -167,13 +285,6 @@ class TsunamiIO : public PioDevice
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
- /** uip UpdateInProgess says that the rtc is updating, but we just fake it
- * by alternating it on every read of the bit since we are going to
- * override the loop_per_jiffy time that it is trying to use the UIP to
- * calculate.
- */
- uint8_t uip;
-
/** Mask of the PIC1 */
uint8_t mask1;
@@ -197,31 +308,16 @@ class TsunamiIO : public PioDevice
/** A pointer to the Tsunami device which be belong to */
Tsunami *tsunami;
- /**
- * This timer is initilized, but after I wrote the code
- * it doesn't seem to be used again, and best I can tell
- * it too is not connected to any interrupt port
- */
- ClockEvent timer0;
-
- /**
- * 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;
+ /** Intel 8253 Periodic Interval Timer */
+ PITimer pitimer;
- /** This is the event used to interrupt the cpu like an RTC. */
- RTCEvent rtc;
+ RTC rtc;
/** The interval is set via two writes to the PIT.
* This variable contains a flag as to how many writes have happened, and
* the time so far.
*/
- uint32_t timerData;
+ uint16_t timerData;
public:
/**
@@ -243,11 +339,6 @@ class TsunamiIO : public PioDevice
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.
* @param req Contains the address to read from.
* @param data A pointer to write the read data to.
diff --git a/dev/tsunamireg.h b/dev/tsunamireg.h
index 5fbfd5c31..583ff78b4 100644
--- a/dev/tsunamireg.h
+++ b/dev/tsunamireg.h
@@ -118,10 +118,18 @@
#define TSDEV_DMA2_MODE 0xD6
#define TSDEV_DMA1_MASK 0x0A
#define TSDEV_DMA2_MASK 0xD4
-#define TSDEV_TMR_CTL 0x61
-#define TSDEV_TMR2_CTL 0x43
-#define TSDEV_TMR2_DATA 0x42
+#define TSDEV_CTRL_PORTB 0x61
#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
#define TSDEV_RTC_ADDR 0x70
#define TSDEV_RTC_DATA 0x71
@@ -145,4 +153,7 @@
#define UART_MCR_LOOP 0x10
+// System Control PortB Status Bits
+#define PORTB_SPKR_HIGH 0x20
+
#endif // __TSUNAMIREG_H__
diff --git a/dev/uart8250.cc b/dev/uart8250.cc
index 99e3bd017..bbde14769 100644
--- a/dev/uart8250.cc
+++ b/dev/uart8250.cc
@@ -146,10 +146,14 @@ Uart8250::read(MemReqPtr &req, uint8_t *data)
break;
case 0x2: // Intr Identification Register (IIR)
DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status);
- if (status)
- *(uint8_t*)data = 0;
+
+ //Tx interrupts are cleared on IIR reads
+ status &= ~TX_INT;
+
+ if (status & RX_INT)
+ *(uint8_t*)data = IIR_RXID;
else
- *(uint8_t*)data = 1;
+ *(uint8_t*)data = IIR_NOPEND;
break;
case 0x3: // Line Control Register (LCR)
*(uint8_t*)data = LCR;
diff --git a/dev/uart8250.hh b/dev/uart8250.hh
index 06a798e26..b4c660021 100644
--- a/dev/uart8250.hh
+++ b/dev/uart8250.hh
@@ -38,6 +38,20 @@
#include "dev/io_device.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
+
+// 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 Platform;