diff options
Diffstat (limited to 'dev')
-rw-r--r-- | dev/disk_image.cc | 4 | ||||
-rw-r--r-- | dev/ide_ctrl.cc | 371 | ||||
-rw-r--r-- | dev/ide_ctrl.hh | 82 | ||||
-rw-r--r-- | dev/ide_disk.cc | 179 | ||||
-rw-r--r-- | dev/ide_disk.hh | 14 | ||||
-rwxr-xr-x | dev/isa_fake.cc | 139 | ||||
-rwxr-xr-x | dev/isa_fake.hh | 85 | ||||
-rw-r--r-- | dev/ns_gige.cc | 14 | ||||
-rw-r--r-- | dev/ns_gige.hh | 6 | ||||
-rw-r--r-- | dev/pciconfigall.cc | 33 | ||||
-rw-r--r-- | dev/pcidev.cc | 251 | ||||
-rw-r--r-- | dev/pcidev.hh | 16 | ||||
-rw-r--r-- | dev/pcireg.h | 90 | ||||
-rw-r--r-- | dev/pitreg.h | 73 | ||||
-rw-r--r-- | dev/rtcreg.h | 22 | ||||
-rw-r--r-- | dev/sinic.cc | 10 | ||||
-rw-r--r-- | dev/sinic.hh | 2 | ||||
-rw-r--r-- | dev/tsunami_io.cc | 515 | ||||
-rw-r--r-- | dev/tsunami_io.hh | 301 | ||||
-rw-r--r-- | dev/tsunamireg.h | 17 | ||||
-rw-r--r-- | dev/uart8250.cc | 10 | ||||
-rw-r--r-- | dev/uart8250.hh | 14 |
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 ®_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 §ion) 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 ®_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 §ion) } // 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(®s, 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 §ion) { - 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 §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)); +} -// 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 §ion) +TsunamiIO::RTC::RTCEvent::unserialize(Checkpoint *cp, const std::string §ion) { 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 §ion) { - 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 §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) +{ + 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 §ion) +TsunamiIO::PITimer::Counter::CounterEvent::unserialize(Checkpoint *cp, const std::string §ion) { 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 §ion) { 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 §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: - /** - * 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 §ion); - }; + }; - /** - * 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 §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: - /** - * 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 §ion); }; - /** 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; |