diff options
Diffstat (limited to 'dev')
-rw-r--r-- | dev/disk_image.cc | 4 | ||||
-rw-r--r-- | dev/ide_ctrl.cc | 210 | ||||
-rw-r--r-- | dev/ide_ctrl.hh | 65 | ||||
-rw-r--r-- | dev/ide_disk.cc | 14 | ||||
-rw-r--r-- | dev/ide_disk.hh | 4 | ||||
-rwxr-xr-x | dev/isa_fake.cc | 139 | ||||
-rwxr-xr-x | dev/isa_fake.hh | 85 | ||||
-rw-r--r-- | dev/ns_gige.cc | 12 | ||||
-rw-r--r-- | dev/ns_gige.hh | 4 | ||||
-rw-r--r-- | dev/pciconfigall.cc | 29 | ||||
-rw-r--r-- | dev/pcidev.cc | 218 | ||||
-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 | 8 | ||||
-rw-r--r-- | dev/sinic.cc | 10 | ||||
-rw-r--r-- | dev/sinic.hh | 2 | ||||
-rw-r--r-- | dev/tsunami_io.cc | 587 | ||||
-rw-r--r-- | dev/tsunami_io.hh | 320 | ||||
-rw-r--r-- | dev/tsunamireg.h | 17 | ||||
-rw-r--r-- | dev/uart8250.cc | 3 | ||||
-rw-r--r-- | dev/uart8250.hh | 13 |
22 files changed, 1153 insertions, 770 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 2c86d27c7..6ad80e69d 100644 --- a/dev/ide_ctrl.cc +++ b/dev/ide_ctrl.cc @@ -76,10 +76,12 @@ IdeController::IdeController(Params *p) // zero out all of the registers memset(bmi_regs.data, 0, sizeof(bmi_regs)); - memset(pci_config_regs.data, 0, sizeof(pci_config_regs.data)); + memset(config_regs.data, 0, sizeof(config_regs.data)); // setup initial values - pci_config_regs.idetim = htoa((uint32_t)0x80008000); // enable both channels + // enable both channels + config_regs.idetim0 = htole((uint16_t)IDETIM_DECODE_EN); + config_regs.idetim1 = htole((uint16_t)IDETIM_DECODE_EN); bmi_regs.bmis0 = DMA1CAP | DMA0CAP; bmi_regs.bmis1 = DMA1CAP | DMA0CAP; @@ -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]; } @@ -249,43 +251,33 @@ IdeController::cacheAccess(MemReqPtr &req) //// void -IdeController::ReadConfig(int offset, int size, uint8_t *data) +IdeController::readConfig(int offset, int size, uint8_t *data) { - union { - uint8_t byte; - uint16_t word; - uint32_t dword; - }; - int config_offset; if (offset < PCI_DEVICE_SPECIFIC) { - PciDev::ReadConfig(offset, size, data); - } else if (offset >= IDE_CTRL_CONFIG_START && - (offset + size) <= IDE_CTRL_CONFIG_END) { + PciDev::readConfig(offset, size, data); + } else if (offset >= IDE_CTRL_CONF_START && + (offset + size) <= IDE_CTRL_CONF_END) { - config_offset = offset - IDE_CTRL_CONFIG_START; - dword = 0; + config_offset = offset - IDE_CTRL_CONF_START; switch (size) { case sizeof(uint8_t): - memcpy(&byte, &pci_config_regs.data[config_offset], size); - *data = byte; + *data = config_regs.data[config_offset]; break; case sizeof(uint16_t): - memcpy(&byte, &pci_config_regs.data[config_offset], size); - *(uint16_t*)data = htoa(word); + *(uint16_t*)data = *(uint16_t*)&config_regs.data[config_offset]; break; case sizeof(uint32_t): - memcpy(&byte, &pci_config_regs.data[config_offset], size); - *(uint32_t*)data = htoa(dword); + *(uint32_t*)data = *(uint32_t*)&config_regs.data[config_offset]; break; default: panic("Invalid PCI configuration read size!\n"); } DPRINTF(IdeCtrl, "PCI read offset: %#x size: %#x data: %#x\n", - offset, size, htoa(dword)); + offset, size, *(uint32_t*)data); } else { panic("Read of unimplemented PCI config. register: %x\n", offset); @@ -293,27 +285,25 @@ IdeController::ReadConfig(int offset, int size, uint8_t *data) } void -IdeController::WriteConfig(int offset, int size, uint32_t data) +IdeController::writeConfig(int offset, int size, const uint8_t *data) { int config_offset; - uint32_t write_data; if (offset < PCI_DEVICE_SPECIFIC) { - PciDev::WriteConfig(offset, size, data); - } else if (offset >= IDE_CTRL_CONFIG_START && - (offset + size) <= IDE_CTRL_CONFIG_END) { - - config_offset = offset - IDE_CTRL_CONFIG_START; + PciDev::writeConfig(offset, size, data); + } else if (offset >= IDE_CTRL_CONF_START && + (offset + size) <= IDE_CTRL_CONF_END) { - write_data = htoa(data); + 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): - memcpy(&pci_config_regs.data[config_offset], &write_data, size); + *(uint32_t*)&config_regs.data[config_offset] = *(uint32_t*)data; break; - default: panic("Invalid PCI configuration write size!\n"); } @@ -328,12 +318,12 @@ IdeController::WriteConfig(int offset, int size, uint32_t data) // (like updating the PIO ranges) 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; @@ -399,48 +389,26 @@ Fault IdeController::read(MemReqPtr &req, uint8_t *data) { Addr offset; - bool primary; - RegType_t type; + IdeChannel channel; + IdeRegType reg_type; int disk; - /* union - * +-- --+-- --+-- --+-- --+ - * | 0 | 1 | 2 | 3 | - * +-- --+-- --+-- --+-- --+ - * | byte | .. | .. | .. | - * +-- --+-- --+-- --+-- --+ - * | word0 | word1 | - * +-- --+-- --+ - * | dword | - * +-- --+ - */ - union { - uint8_t byte; - uint16_t word[2]; - uint32_t dword; - }; - - dword = 0; - - parseAddr(req->paddr, offset, primary, type); + parseAddr(req->paddr, offset, channel, reg_type); if (!io_enabled) return No_Fault; - switch (type) { + switch (reg_type) { case BMI_BLOCK: switch (req->size) { case sizeof(uint8_t): - memcpy(&byte, &bmi_regs.data[offset], sizeof(uint8_t)); - *data = byte; + *data = bmi_regs.data[offset]; break; case sizeof(uint16_t): - memcpy(&byte, &bmi_regs.data[offset], sizeof(uint16_t)); - *(uint16_t*)data = htoa(word[0]); + *(uint16_t*)data = *(uint16_t*)&bmi_regs.data[offset]; break; case sizeof(uint32_t): - memcpy(&byte, &bmi_regs.data[offset], sizeof(uint32_t)); - *(uint32_t*)data = htoa(dword); + *(uint32_t*)data = *(uint32_t*)&bmi_regs.data[offset]; break; default: panic("IDE read of BMI reg invalid size: %#x\n", req->size); @@ -449,7 +417,7 @@ IdeController::read(MemReqPtr &req, uint8_t *data) case COMMAND_BLOCK: case CONTROL_BLOCK: - disk = getDisk(primary); + disk = getDisk(channel); if (disks[disk] == NULL) break; @@ -458,14 +426,12 @@ IdeController::read(MemReqPtr &req, uint8_t *data) case DATA_OFFSET: switch (req->size) { case sizeof(uint16_t): - disks[disk]->read(offset, type, (uint8_t*)&word[0]); - *(uint16_t*)data = htoa(word[0]); + disks[disk]->read(offset, reg_type, data); break; case sizeof(uint32_t): - disks[disk]->read(offset, type, (uint8_t*)&word[0]); - disks[disk]->read(offset, type, (uint8_t*)&word[1]); - *(uint32_t*)data = htoa(dword); + disks[disk]->read(offset, reg_type, data); + disks[disk]->read(offset, reg_type, &data[2]); break; default: @@ -474,8 +440,7 @@ IdeController::read(MemReqPtr &req, uint8_t *data) break; default: if (req->size == sizeof(uint8_t)) { - disks[disk]->read(offset, type, &byte); - *data = byte; + disks[disk]->read(offset, reg_type, data); } else panic("IDE read of command reg of invalid size: %#x\n", req->size); } @@ -485,7 +450,7 @@ IdeController::read(MemReqPtr &req, uint8_t *data) } DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", - offset, req->size, htoa(dword)); + offset, req->size, *(uint32_t*)data); return No_Fault; } @@ -494,26 +459,17 @@ Fault IdeController::write(MemReqPtr &req, const uint8_t *data) { Addr offset; - bool primary; - RegType_t type; + IdeChannel channel; + IdeRegType reg_type; int disk; - - union { - uint8_t byte; - uint16_t word[2]; - uint32_t dword; - }; - - dword = 0; - - parseAddr(req->paddr, offset, primary, type); - uint8_t oldVal, newVal; + parseAddr(req->paddr, offset, channel, reg_type); + if (!io_enabled) return No_Fault; - switch (type) { + switch (reg_type) { case BMI_BLOCK: if (!bm_enabled) return No_Fault; @@ -526,11 +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.data[offset]; - byte = *data; - newVal = byte; + 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) { @@ -546,7 +501,8 @@ IdeController::write(MemReqPtr &req, const uint8_t *data) DPRINTF(IdeCtrl, "Stopping DMA transfer\n"); // clear the BMIDEA bit - bmi_regs.data[offset + 0x2] &= ~BMIDEA; + bmi_regs.chan[channel].bmis = letoh( + letoh(bmi_regs.chan[channel].bmis) & ~BMIDEA); if (disks[disk] == NULL) panic("DMA stop for disk %d which does not exist\n", @@ -559,22 +515,20 @@ IdeController::write(MemReqPtr &req, const uint8_t *data) DPRINTF(IdeCtrl, "Starting DMA transfer\n"); // set the BMIDEA bit - bmi_regs.data[offset + 0x2] |= BMIDEA; + bmi_regs.chan[channel].bmis = letoh( + letoh(bmi_regs.chan[channel].bmis) | BMIDEA); if (disks[disk] == NULL) 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(bmi_regs.bmidtp0); - else - disks[disk]->startDma(bmi_regs.bmidtp1); + disks[disk]->startDma(letoh(bmi_regs.chan[channel].bmidtp)); } } // update the register value - bmi_regs.data[offset] = newVal; + bmi_regs.chan[channel].bmic = letoh(newVal); break; // Bus master IDE status register @@ -583,9 +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.data[offset]; - byte = *data; - newVal = byte; + oldVal = letoh(bmi_regs.chan[channel].bmis); + newVal = letoh(*data); // the BMIDEA bit is RO newVal |= (oldVal & BMIDEA); @@ -601,7 +554,7 @@ IdeController::write(MemReqPtr &req, const uint8_t *data) else (oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE; - bmi_regs.data[offset] = newVal; + bmi_regs.chan[channel].bmis = letoh(newVal); break; // Bus master IDE descriptor table pointer register @@ -610,8 +563,8 @@ IdeController::write(MemReqPtr &req, const uint8_t *data) if (req->size != sizeof(uint32_t)) panic("Invalid BMIDTP write size: %x\n", req->size); - dword = htoa(*(uint32_t *)data & ~0x3); - *(uint32_t *)&bmi_regs.data[offset] = dword; + bmi_regs.chan[channel].bmidtp = letoh( + letoh(*(uint32_t*)data) & ~0x3); break; default: @@ -622,17 +575,17 @@ IdeController::write(MemReqPtr &req, const uint8_t *data) req->size); // do a default copy of data into the registers - memcpy((void *)&bmi_regs.data[offset], data, req->size); + memcpy(&bmi_regs.data[offset], data, req->size); } break; case COMMAND_BLOCK: if (offset == IDE_SELECT_OFFSET) { - uint8_t *devBit = (primary ? &dev[0] : &dev[1]); - *devBit = ((*data & IDE_SELECT_DEV_BIT) ? 1 : 0); + uint8_t *devBit = &dev[channel]; + *devBit = (letoh(*data) & IDE_SELECT_DEV_BIT) ? 1 : 0; } // fall-through ok! case CONTROL_BLOCK: - disk = getDisk(primary); + disk = getDisk(channel); if (disks[disk] == NULL) break; @@ -641,14 +594,12 @@ IdeController::write(MemReqPtr &req, const uint8_t *data) case DATA_OFFSET: switch (req->size) { case sizeof(uint16_t): - word[0] = htoa(*(uint16_t*)data); - disks[disk]->write(offset, type, (uint8_t*)&word[0]); + disks[disk]->write(offset, reg_type, data); break; case sizeof(uint32_t): - dword = htoa(*(uint32_t*)data); - disks[disk]->write(offset, type, (uint8_t*)&word[0]); - disks[disk]->write(offset, type, (uint8_t*)&word[1]); + 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); @@ -656,8 +607,7 @@ IdeController::write(MemReqPtr &req, const uint8_t *data) break; default: if (req->size == sizeof(uint8_t)) { - byte = *data; - disks[disk]->write(offset, type, &byte); + disks[disk]->write(offset, reg_type, data); } else panic("IDE write of command reg of invalid size: %#x\n", req->size); } @@ -667,7 +617,7 @@ IdeController::write(MemReqPtr &req, const uint8_t *data) } DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", - offset, req->size, dword); + offset, req->size, *(uint32_t*)data); return No_Fault; } @@ -697,7 +647,7 @@ IdeController::serialize(std::ostream &os) // Serialize registers SERIALIZE_ARRAY(bmi_regs.data, sizeof(bmi_regs)); SERIALIZE_ARRAY(dev, sizeof(dev)); - SERIALIZE_ARRAY(pci_config_regs.data, sizeof(pci_config_regs)); + SERIALIZE_ARRAY(config_regs.data, sizeof(config_regs)); // Serialize internal state SERIALIZE_SCALAR(io_enabled); @@ -726,7 +676,7 @@ IdeController::unserialize(Checkpoint *cp, const std::string §ion) // Unserialize registers UNSERIALIZE_ARRAY(bmi_regs.data, sizeof(bmi_regs)); UNSERIALIZE_ARRAY(dev, sizeof(dev)); - UNSERIALIZE_ARRAY(pci_config_regs.data, sizeof(pci_config_regs)); + UNSERIALIZE_ARRAY(config_regs.data, sizeof(config_regs)); // Unserialize internal state UNSERIALIZE_SCALAR(io_enabled); diff --git a/dev/ide_ctrl.hh b/dev/ide_ctrl.hh index 51bdd93b1..d50dbbeb1 100644 --- a/dev/ide_ctrl.hh +++ b/dev/ide_ctrl.hh @@ -63,16 +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 IDE_CTRL_CONFIG_START 0x40 -#define IDE_CTRL_CONFIG_END ((IDE_CTRL_CONFIG_START) + sizeof(pci_config_regs)) +#define IDE_CTRL_CONF_START 0x40 +#define IDE_CTRL_CONF_END ((IDE_CTRL_CONF_START) + sizeof(config_regs)) -typedef enum RegType { - COMMAND_BLOCK = 0, +enum IdeRegType { + COMMAND_BLOCK, CONTROL_BLOCK, BMI_BLOCK -} RegType_t; +}; class BaseInterface; class Bus; @@ -91,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; @@ -115,16 +123,25 @@ class IdeController : public PciDev struct { uint8_t bmic0; - uint8_t padding_0; + uint8_t reserved_0; uint8_t bmis0; - uint8_t padding_1; + uint8_t reserved_1; uint32_t bmidtp0; uint8_t bmic1; - uint8_t padding_2; + uint8_t reserved_2; uint8_t bmis1; - uint8_t padding_3; + 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]; @@ -133,25 +150,17 @@ class IdeController : public PciDev uint8_t data[22]; struct { - uint32_t idetim; + uint16_t idetim0; + uint16_t idetim1; uint8_t sidetim; - uint8_t reserved_45; - uint8_t reserved_46; - uint8_t reserved_47; + uint8_t reserved_0[3]; uint8_t udmactl; - uint8_t reserved_49; + uint8_t reserved_1; uint16_t udmatim; - uint8_t reserved_4c; - uint8_t reserved_4d; - uint8_t reserved_4e; - uint8_t reserved_4f; - uint8_t reserved_50; - uint8_t reserved_51; - uint8_t reserved_52; - uint8_t reserved_53; + uint8_t reserved_2[8]; uint16_t ideconfig; }; - } pci_config_regs; + } config_regs; // Internal management variables bool io_enabled; @@ -164,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); @@ -192,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 39eb2e698..bd9aac8ea 100644 --- a/dev/ide_disk.cc +++ b/dev/ide_disk.cc @@ -162,6 +162,8 @@ 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; } @@ -212,16 +214,16 @@ IdeDisk::bytesInDmaPage(Addr curAddr, uint32_t bytesLeft) //// void -IdeDisk::read(const Addr &offset, RegType_t type, uint8_t *data) +IdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data) { DevAction_t action = ACT_NONE; - switch (type) { + switch (reg_type) { case COMMAND_BLOCK: switch (offset) { // Data transfers occur two bytes at a time case DATA_OFFSET: - memcpy(data, &cmdReg.data, sizeof(uint16_t)); + *(uint16_t*)data = cmdReg.data; action = ACT_DATA_READ_SHORT; break; case ERROR_OFFSET: @@ -265,15 +267,15 @@ IdeDisk::read(const Addr &offset, RegType_t type, uint8_t *data) } void -IdeDisk::write(const Addr &offset, RegType_t type, const uint8_t *data) +IdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data) { DevAction_t action = ACT_NONE; - switch (type) { + switch (reg_type) { case COMMAND_BLOCK: switch (offset) { case DATA_OFFSET: - memcpy(&cmdReg.data, data, sizeof(uint16_t)); + cmdReg.data = *(uint16_t*)data; action = ACT_DATA_WRITE_SHORT; break; case FEATURES_OFFSET: diff --git a/dev/ide_disk.hh b/dev/ide_disk.hh index ceec11925..a656ca464 100644 --- a/dev/ide_disk.hh +++ b/dev/ide_disk.hh @@ -270,8 +270,8 @@ class IdeDisk : public SimObject } // Device register read/write - void read(const Addr &offset, RegType_t type, uint8_t *data); - void write(const Addr &offset, RegType_t type, 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 ae129c249..304263695 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 @@ -797,7 +797,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"); diff --git a/dev/ns_gige.hh b/dev/ns_gige.hh index b6554e5d6..ac16aa266 100644 --- a/dev/ns_gige.hh +++ b/dev/ns_gige.hh @@ -392,8 +392,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 8c6657ceb..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,30 +152,17 @@ PciConfigAll::write(MemReqPtr &req, const uint8_t *data) int func = (daddr >> 8) & 0x7; int reg = daddr & 0xFF; - uint32_t word_value = 0; - 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): - word_value = *(uint8_t*)data; - break; - case sizeof(uint16_t): - word_value = *(uint16_t*)data; - break; - case sizeof(uint32_t): - word_value = *(uint32_t*)data; - break; - default: - panic("invalid access size(?) for PCI configspace!\n"); - } - } + 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 54990cef3..04a38151e 100644 --- a/dev/pcidev.cc +++ b/dev/pcidev.cc @@ -71,31 +71,20 @@ PciDev::PciDev(Params *p) } void -PciDev::ReadConfig(int offset, int size, uint8_t *data) +PciDev::readConfig(int offset, int size, uint8_t *data) { - union { - uint8_t byte; - uint16_t word; - uint32_t dword; - }; - if (offset >= PCI_DEVICE_SPECIFIC) panic("Device specific PCI config space not implemented!\n"); - dword = 0; - switch(size) { case sizeof(uint8_t): - memcpy(&byte, &config.data[offset], size); - *data = byte; + *data = config.data[offset]; break; case sizeof(uint16_t): - memcpy(&byte, &config.data[offset], size); - *(uint16_t*)data = htoa(word); + *(uint16_t*)data = *(uint16_t*)&config.data[offset]; break; case sizeof(uint32_t): - memcpy(&byte, &config.data[offset], size); - *(uint32_t*)data = htoa(dword); + *(uint32_t*)data = *(uint32_t*)&config.data[offset]; break; default: panic("Invalid PCI configuration read size!\n"); @@ -104,32 +93,32 @@ PciDev::ReadConfig(int offset, int size, uint8_t *data) DPRINTF(PCIDEV, "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n", params()->deviceNum, params()->functionNum, offset, size, - htoa(dword)); + *(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; + 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, - data); - - barnum = (offset - PCI0_BASE_ADDR0) >> 2; + params()->deviceNum, params()->functionNum, offset, size, data32); switch (size) { case sizeof(uint8_t): // 1-byte access - uint8_t byte_value = data; 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: @@ -144,21 +133,20 @@ PciDev::WriteConfig(int offset, int size, uint32_t data) break; case sizeof(uint16_t): // 2-byte access - uint16_t half_value = data; 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(uint32_t): // 4-byte access - uint32_t word_value = data; switch (offset) { case PCI0_BASE_ADDR0: case PCI0_BASE_ADDR1: @@ -166,87 +154,65 @@ 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) & ~0x3) | - (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) & ~0xF) | - (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: @@ -262,17 +228,17 @@ PciDev::WriteConfig(int offset, int size, uint32_t data) 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++) { @@ -361,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 31b0cab16..433079b61 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 032e22ab5..5025a0e95 100644 --- a/dev/rtcreg.h +++ b/dev/rtcreg.h @@ -37,12 +37,12 @@ #define RTC_MON 0x08 #define RTC_YEAR 0x09 -#define RTC_CNTRL_REGA 0x0A +#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_CNTRL_REGB 0x0B +#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 */ @@ -52,6 +52,6 @@ #define RTCB_PRDC_IE 0x40 /* 1 = enable periodic clock interrupt */ #define RTCB_NO_UPDT 0x80 /* stop clock updates */ -#define RTC_CNTRL_REGC 0x0C -#define RTC_CNTRL_REGD 0x0D +#define RTC_STAT_REGC 0x0C +#define RTC_STAT_REGD 0x0D diff --git a/dev/sinic.cc b/dev/sinic.cc index 0c55dc664..1914367bd 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 3a25712af..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,18 +51,136 @@ 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); -// Timer Event for Periodic interrupt of RTC -TsunamiIO::RTCEvent::RTCEvent(Tsunami* t, Tick i) + // unserialze the event + event.unserialize(cp, csprintf("%s.event", section)); +} + +TsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i) : Event(&mainEventQueue), tsunami(t), interval(i) { - DPRINTF(MC146818, "RTC Event Initializing\n"); + DPRINTF(MC146818, "RTC Event Initilizing\n"); schedule(curTick + interval); } 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,152 +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); } -void -TsunamiIO::RTCEvent::scheduleIntr() +TsunamiIO::PITimer::PITimer() + : SimObject("PITimer"), counter0(counter[0]), counter1(counter[1]), + counter2(counter[2]) { - schedule(curTick + interval); + } -// 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; - DPRINTF(Tsunami, "Clock Event Initilizing\n"); - mode = 0; + sel = GET_CTRL_SEL(*data); - current_count = 0; - latched_count = 0; - latch_on = false; - read_byte = READ_LSB; -} + if (sel == PIT_READ_BACK) + panic("PITimer Read-Back Command is not implemented.\n"); -void -TsunamiIO::ClockEvent::process() -{ - DPRINTF(Tsunami, "Timer Interrupt\n"); - if (mode == 0) - status = 0x20; // set bit that linux is looking for - else if (mode == 2) - schedule(curTick + current_count*interval); + 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::Program(int count) +TsunamiIO::PITimer::serialize(std::ostream &os) { - DPRINTF(Tsunami, "Timer set to curTick + %d\n", count * interval); - schedule(curTick + count * interval); - status = 0; + // serialize the counters + nameOut(os, csprintf("%s.counter0", name())); + counter0.serialize(os); - current_count = (uint16_t)count; -} + nameOut(os, csprintf("%s.counter1", name())); + counter1.serialize(os); -const char * -TsunamiIO::ClockEvent::description() -{ - return "tsunami 8254 Interval timer"; + nameOut(os, csprintf("%s.counter2", name())); + counter2.serialize(os); } void -TsunamiIO::ClockEvent::ChangeMode(uint8_t md) +TsunamiIO::PITimer::unserialize(Checkpoint *cp, const std::string §ion) { - mode = md; + // unserialze the counters + counter0.unserialize(cp, csprintf("%s.counter0", section)); + counter1.unserialize(cp, csprintf("%s.counter1", section)); + counter2.unserialize(cp, csprintf("%s.counter2", section)); } -uint8_t -TsunamiIO::ClockEvent::Status() +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 status; + } void -TsunamiIO::ClockEvent::LatchCount() +TsunamiIO::PITimer::Counter::latchCount() { // behave like a real latch if(!latch_on) { latch_on = true; - read_byte = READ_LSB; - latched_count = current_count; + read_byte = LSB; + latched_count = count; } } -uint8_t -TsunamiIO::ClockEvent::Read() +void +TsunamiIO::PITimer::Counter::read(uint8_t *data) { - uint8_t result = 0; - - if(latch_on) { + if (latch_on) { switch (read_byte) { - case READ_LSB: - read_byte = READ_MSB; - result = (uint8_t)latched_count; + case LSB: + read_byte = MSB; + *data = (uint8_t)latched_count; break; - case READ_MSB: - read_byte = READ_LSB; + case MSB: + read_byte = LSB; latch_on = false; - result = latched_count >> 8; + *data = latched_count >> 8; break; } } else { switch (read_byte) { - case READ_LSB: - read_byte = READ_MSB; - result = (uint8_t)current_count; + case LSB: + read_byte = MSB; + *data = (uint8_t)count; break; - case READ_MSB: - read_byte = READ_LSB; - result = current_count >> 8; + case MSB: + read_byte = LSB; + *data = count >> 8; break; } } +} - return result; +void +TsunamiIO::PITimer::Counter::write(const uint8_t *data) +{ + switch (write_byte) { + case LSB: + count = (count & 0xFF00) | *data; + + if (event.scheduled()) + event.deschedule(); + output_high = false; + write_byte = MSB; + break; + + case MSB: + count = (count & 0x00FF) | (*data << 8); + period = count; + + if (period > 0) { + DPRINTF(Tsunami, "Timer set to curTick + %d\n", count * event.interval); + event.schedule(curTick + count * event.interval); + } + write_byte = LSB; + break; + } } +void +TsunamiIO::PITimer::Counter::setRW(int rw_val) +{ + if (rw_val != PIT_RW_16BIT) + panic("Only LSB/MSB read/write is implemented.\n"); +} + +void +TsunamiIO::PITimer::Counter::setMode(int mode_val) +{ + if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN && + mode_val != PIT_MODE_SQWAVE) + panic("PIT mode %#x is not implemented: \n", mode_val); + + mode = mode_val; +} + +void +TsunamiIO::PITimer::Counter::setBCD(int bcd_val) +{ + if (bcd_val != PIT_BCD_FALSE) + panic("PITimer does not implement BCD counts.\n"); +} + +bool +TsunamiIO::PITimer::Counter::outputHigh() +{ + return output_high; +} + +void +TsunamiIO::PITimer::Counter::serialize(std::ostream &os) +{ + SERIALIZE_SCALAR(count); + SERIALIZE_SCALAR(latched_count); + SERIALIZE_SCALAR(period); + SERIALIZE_SCALAR(mode); + SERIALIZE_SCALAR(output_high); + SERIALIZE_SCALAR(latch_on); + SERIALIZE_SCALAR(read_byte); + SERIALIZE_SCALAR(write_byte); + + // serialize the counter event + nameOut(os, csprintf("%s.event", name())); + event.serialize(os); +} void -TsunamiIO::ClockEvent::serialize(std::ostream &os) +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"); + } +} + +const char * +TsunamiIO::PITimer::Counter::CounterEvent::description() +{ + return "tsunami 8254 Interval timer"; +} + +void +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); @@ -239,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; } @@ -251,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) { @@ -287,59 +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(); - return No_Fault; case TSDEV_TMR0_DATA: - *(uint8_t *)data = timer0.Read(); + pitimer.counter0.read(data); + return No_Fault; + case TSDEV_TMR1_DATA: + pitimer.counter1.read(data); + return No_Fault; + case TSDEV_TMR2_DATA: + pitimer.counter2.read(data); return No_Fault; case TSDEV_RTC_DATA: - switch(RTCAddress) { - case RTC_CNTRL_REGA: - *(uint8_t*)data = uip << 7 | RTCA_32768HZ | RTCA_1024HZ; - uip = !uip; - return No_Fault; - case RTC_CNTRL_REGB: - // DM and 24/12 and UIE - *(uint8_t*)data = RTCB_PRDC_IE | RTCB_BIN | RTCB_24HR; - return No_Fault; - case RTC_CNTRL_REGC: - // If we want to support RTC user access in linux - // This won't work, but for now it's fine - *(uint8_t*)data = 0x00; - return No_Fault; - case RTC_CNTRL_REGD: - panic("RTC Control Register D not implemented"); - case RTC_SEC_ALRM: - case RTC_MIN_ALRM: - case RTC_HR_ALRM: - // RTC alarm functionality is not currently implemented - *(uint8_t *)data = 0x00; - return No_Fault; - case RTC_SEC: - *(uint8_t *)data = tm.tm_sec; - return No_Fault; - case RTC_MIN: - *(uint8_t *)data = tm.tm_min; - return No_Fault; - case RTC_HR: - *(uint8_t *)data = tm.tm_hour; - return No_Fault; - case RTC_DOW: - *(uint8_t *)data = tm.tm_wday + 1; - return No_Fault; - case RTC_DOM: - *(uint8_t *)data = tm.tm_mday; - return No_Fault; - case RTC_MON: - *(uint8_t *)data = tm.tm_mon + 1; - return No_Fault; - case RTC_YEAR: - *(uint8_t *)data = tm.tm_year; - return No_Fault; - default: - panic("Unknown RTC Address\n"); - } + 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); } @@ -410,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: @@ -425,117 +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: - switch((*(uint8_t*)data >> 4) & 0x3) { - case 0x0: - switch(*(uint8_t*)data >> 6) { - case 0: - timer0.LatchCount(); - return No_Fault; - case 2: - timer2.LatchCount(); - return No_Fault; - default: - panic("Read Back Command not implemented\n"); - } - break; - case 0x3: - break; - default: - panic("Only L/M write and Counter-Latch read supported\n"); - } - - switch(*(uint8_t*)data >> 6) { - case 0: - timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1); - break; - case 2: - timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1); - break; - default: - panic("Read Back Command not implemented\n"); - } + 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); - timerData = 0; - } 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: - switch(RTCAddress) { - case RTC_CNTRL_REGA: - if (*data != (RTCA_32768HZ | RTCA_1024HZ)) - panic("Unimplemented RTC register A value write!\n"); - return No_Fault; - case RTC_CNTRL_REGB: - if ((*data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR)) - panic("Write to RTC reg B bits that are not implemented!\n"); - - if (*data & RTCB_PRDC_IE) { - if (!rtc.scheduled()) - rtc.scheduleIntr(); - } else { - if (rtc.scheduled()) - rtc.deschedule(); - } - return No_Fault; - case RTC_CNTRL_REGC: - panic("Write to RTC reg C not implemented!\n"); - return No_Fault; - case RTC_CNTRL_REGD: - panic("Write to RTC reg D not implemented!\n"); - return No_Fault; - case RTC_SEC: - tm.tm_sec = *(uint8_t *)data; - return No_Fault; - case RTC_MIN: - tm.tm_min = *(uint8_t *)data; - return No_Fault; - case RTC_HR: - tm.tm_hour = *(uint8_t *)data; - return No_Fault; - case RTC_DOW: - tm.tm_wday = *(uint8_t *)data; - return No_Fault; - case RTC_DOM: - tm.tm_mday = *(uint8_t *)data; - return No_Fault; - case RTC_MON: - tm.tm_mon = *(uint8_t *)data; - return No_Fault; - case RTC_YEAR: - tm.tm_year = *(uint8_t *)data; - return No_Fault; - } + 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): @@ -581,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); } @@ -603,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 7054b4ff4..5f20cbf4a 100644 --- a/dev/tsunami_io.hh +++ b/dev/tsunami_io.hh @@ -53,124 +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; - /** The current count of the PIT */ - uint16_t current_count; - /** The latched count of the PIT */ - uint16_t latched_count; - /** The state of the output latch of the PIT */ - bool latch_on; - /** The next count half (byte) to read */ - enum {READ_LSB, READ_MSB} read_byte; + /** 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(); + /** RTC address port: write address of RTC RAM data to access */ + void writeAddr(const uint8_t *data); - /** - * Schedule a timer interrupt to occur sometime in the future. - */ - void Program(int count); + /** RTC write data */ + void writeData(const uint8_t *data); - /** - * Write the mode bits of the PIT. - * @param mode the new mode - */ - void ChangeMode(uint8_t mode); + /** RTC read data */ + void readData(uint8_t *data); /** - * The current PIT status. - * @return the status of the PIT - */ - uint8_t Status(); - - /** - * Latch the count of the PIT. - */ - void LatchCount(); - - /** - * The current PIT count. - * @return the count of the PIT - */ - uint8_t Read(); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ + * 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; - /** - * Interrupt 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. @@ -184,17 +283,8 @@ class TsunamiIO : public PioDevice * @param section The section name of this object */ virtual void unserialize(Checkpoint *cp, const std::string §ion); - - void scheduleIntr(); }; - /** 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; @@ -218,25 +308,10 @@ 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; + /** Intel 8253 Periodic Interval Timer */ + PITimer pitimer; - /** - * This timer is used to control the speaker, which - * we normally could care less about, however it is - * also used to calculated the clockspeed and hense - * bogomips which is kinda important to the scheduler - * so we need to implemnt it although after boot I can't - * imagine we would be playing with the PC speaker much - */ - ClockEvent timer2; - - /** This is the event used to interrupt the cpu like an RTC. */ - RTCEvent rtc; + 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 @@ -264,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 8b290deb1..a10259900 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 /* Added for keyboard accesses */ #define TSDEV_KBD 0x64 @@ -157,4 +165,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 013cbfd00..bbde14769 100644 --- a/dev/uart8250.cc +++ b/dev/uart8250.cc @@ -146,7 +146,10 @@ Uart8250::read(MemReqPtr &req, uint8_t *data) break; case 0x2: // Intr Identification Register (IIR) DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status); + + //Tx interrupts are cleared on IIR reads status &= ~TX_INT; + if (status & RX_INT) *(uint8_t*)data = IIR_RXID; else diff --git a/dev/uart8250.hh b/dev/uart8250.hh index e85ad72c8..b4c660021 100644 --- a/dev/uart8250.hh +++ b/dev/uart8250.hh @@ -38,8 +38,19 @@ #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 -#define IIR_RXID 0x4 + +// Interrupt IDs +#define IIR_MODEM 0x00 /* Modem Status (lowest priority) */ +#define IIR_TXID 0x02 /* Tx Data */ +#define IIR_RXID 0x04 /* Rx Data */ +#define IIR_LINE 0x06 /* Rx Line Status (highest priority)*/ class SimConsole; class Platform; |