From: Miguel Serrano Date: Mon, 15 Aug 2005 20:59:58 +0000 (-0400) Subject: Changes for getting FreeBSD to run. X-Git-Tag: m5_1.1~48^2~1 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b64eae5e52d9eb60ad498464d076b48cd5ceafe3;p=gem5.git Changes for getting FreeBSD to run. SConscript: Added more files to compile: dev/pcifake.cc, dev/isa_fake.cc, kern/freebsd/freebsd_system.cc, kern/freebsd/freebsd_events.cc. arch/alpha/isa_traits.hh: Added constant for argument register 2 as it is needed by FreebsdSystem::doCalibrateClocks(). cpu/exec_context.hh: cpu/o3/alpha_cpu.hh: Replaced htoa()s with gtoh() and htog(). cpu/o3/fetch_impl.hh: cpu/simple/cpu.cc: Replaced htoa() with gtoh(). dev/disk_image.cc: Replaced htoa()s with letoh()s. dev/ide_ctrl.cc: Got rid of magic numbers. Added IdeChannel and IdeRegType type names where necessary. dev/ide_ctrl.hh: Got rid of unnecessary macros. Changed RegType_t to IdeRegType. Changed bmi_regs to allow accessing registers by name instead of just by array index. Added IdeChannel enum type to use in place of bool variables which were used to specify IDE channel. dev/ide_disk.cc: Rewrote IdeDisk::read and IdeDisk::write functions to specify registers by name instead of indexing through an array. dev/ide_disk.hh: Updated command register struct. dev/ns_gige.cc: dev/ns_gige.hh: Made ReadConfig and WriteConfig begin with a lower-case letter. writeConfig() now takes a pointer to data as a parameter instead of a copy of data. dev/pciconfigall.cc: writeConfig() now takes a pointer to data as a parameter instead of a copy of data. dev/pcidev.cc: Cleaned up readConfig() and writeConfig() functions. dev/pcidev.hh: Added macros to make code that works with the BARs (base adress registers) more readable. writeConfig() now takes a pointer to data. dev/pcireg.h: Changed PCIConfig struct to make accessing elements more straight forward. Removed type 1 (for PCI-to-PCI bridges) PCI configuration space struct since it is not used. dev/rtcreg.h: Added macros for bit fields in RTC status registers A & B. dev/sinic.cc: Function name change: WriteConfig --> writeConfig. writeConfig() now takes a pointer to data instead of a copy of data. The accessing of elements of PCIConfig structure is updated. dev/sinic.hh: Function name change: WriteConfig --> writeConfig. writeConfig() now takes a pointer to data instead of a copy of data. dev/tsunami_io.cc: Added implementation of new RTC and PIT classes. dev/tsunami_io.hh: Added classes for RTC and PIT modules. dev/tsunamireg.h: Added macros for DMA ports used by Tsunami-Tru64. dev/uart8250.cc: Got rid of a magic number. Transmit (Tx) interrupts should clear upon a read of the Interrupt ID register. dev/uart8250.hh: Added comments and macros dealing with the UART Interrupt ID register. kern/linux/linux_system.cc: Replaced htoa() with htog(). python/m5/objects/Pci.py: PciFake is a python class for Pci Devices that do nothing. python/m5/objects/Tsunami.py: TsunamiFake was renamed as IsaFake. sim/system.cc: Replaced htoa()s with htog()s. dev/isa_fake.cc: New BitKeeper file ``dev/isa_fake.cc'' TsunamiFake was renamed as IsaFake. dev/isa_fake.hh: New BitKeeper file ``dev/isa_fake.hh'' TsunmaiFake was renamed as IsaFake. dev/pitreg.h: New BitKeeper file ``dev/pitreg.h'' Useful macros for working with PIT (Periodic Interval Timer) registers. --HG-- extra : convert_revision : 33f3a8a1034af4f6c71b32dd743e371c8613e780 --- diff --git a/SConscript b/SConscript index ddca8b057..8a983840d 100644 --- a/SConscript +++ b/SConscript @@ -265,13 +265,14 @@ full_system_sources = Split(''' dev/ns_gige.cc dev/pciconfigall.cc dev/pcidev.cc + dev/pcifake.cc dev/pktfifo.cc dev/platform.cc dev/sinic.cc dev/simple_disk.cc dev/tsunami.cc dev/tsunami_cchip.cc - dev/tsunami_fake.cc + dev/isa_fake.cc dev/tsunami_io.cc dev/tsunami_pchip.cc dev/uart.cc @@ -280,6 +281,8 @@ full_system_sources = Split(''' kern/kernel_binning.cc kern/kernel_stats.cc kern/system_events.cc + kern/freebsd/freebsd_system.cc + kern/freebsd/freebsd_events.cc kern/linux/linux_events.cc kern/linux/linux_syscalls.cc kern/linux/linux_system.cc diff --git a/arch/alpha/isa_traits.hh b/arch/alpha/isa_traits.hh index 9c7709a60..6c0c09b7a 100644 --- a/arch/alpha/isa_traits.hh +++ b/arch/alpha/isa_traits.hh @@ -287,6 +287,7 @@ const int ReturnAddressReg = TheISA::ReturnAddressReg; const int ReturnValueReg = TheISA::ReturnValueReg; const int ArgumentReg0 = TheISA::ArgumentReg0; const int ArgumentReg1 = TheISA::ArgumentReg1; +const int ArgumentReg2 = TheISA::ArgumentReg2; const int BranchPredAddrShiftAmt = TheISA::BranchPredAddrShiftAmt; const int MaxAddr = (Addr)-1; diff --git a/cpu/exec_context.hh b/cpu/exec_context.hh index e9ff3e181..5e105c44d 100644 --- a/cpu/exec_context.hh +++ b/cpu/exec_context.hh @@ -263,7 +263,7 @@ class ExecContext Fault error; error = mem->read(req, data); - data = htoa(data); + data = gtoh(data); return error; } @@ -313,7 +313,7 @@ class ExecContext } #endif - return mem->write(req, (T)htoa(data)); + return mem->write(req, (T)htog(data)); } virtual bool misspeculating(); diff --git a/cpu/o3/alpha_cpu.hh b/cpu/o3/alpha_cpu.hh index 3c679c3b2..545165b2b 100644 --- a/cpu/o3/alpha_cpu.hh +++ b/cpu/o3/alpha_cpu.hh @@ -220,7 +220,7 @@ class AlphaFullCPU : public FullO3CPU Fault error; error = this->mem->read(req, data); - data = htoa(data); + data = gtoh(data); return error; } @@ -277,7 +277,7 @@ class AlphaFullCPU : public FullO3CPU #endif - return this->mem->write(req, (T)htoa(data)); + return this->mem->write(req, (T)htog(data)); } template diff --git a/cpu/o3/fetch_impl.hh b/cpu/o3/fetch_impl.hh index 83d7a02e5..75b6abb3d 100644 --- a/cpu/o3/fetch_impl.hh +++ b/cpu/o3/fetch_impl.hh @@ -535,7 +535,7 @@ SimpleFetch::fetch() assert(offset <= cacheBlkSize - instSize); // Get the instruction from the array of the cache line. - inst = htoa(*reinterpret_cast + inst = gtoh(*reinterpret_cast (&cacheData[offset])); // Create a new DynInst from the instruction fetched. diff --git a/cpu/simple/cpu.cc b/cpu/simple/cpu.cc index 1164e35a4..c5e12990b 100644 --- a/cpu/simple/cpu.cc +++ b/cpu/simple/cpu.cc @@ -738,7 +738,7 @@ SimpleCPU::tick() comInstEventQueue[0]->serviceEvents(numInst); // decode the instruction - inst = htoa(inst); + inst = gtoh(inst); curStaticInst = StaticInst::decode(inst); traceData = Trace::getInstRecord(curTick, xc, this, curStaticInst, 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 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 +#include +#include + +#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 mmu; + Param addr; + SimObjectParam io_bus; + Param pio_latency; + SimObjectParam hier; + Param 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 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 + +// 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: /** @@ -242,11 +338,6 @@ class TsunamiIO : public PioDevice Addr a, MemoryController *mmu, HierParams *hier, Bus *bus, 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. 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; diff --git a/kern/linux/linux_system.cc b/kern/linux/linux_system.cc index 21450e400..fd444341a 100644 --- a/kern/linux/linux_system.cc +++ b/kern/linux/linux_system.cc @@ -96,7 +96,7 @@ LinuxSystem::LinuxSystem(Params *p) char *dp264_mv = (char *)physmem->dma_addr(paddr, sizeof(uint64_t)); if (dp264_mv) { - *(uint32_t*)(dp264_mv+0x18) = htoa((uint32_t)127); + *(uint32_t*)(dp264_mv+0x18) = htog((uint32_t)127); } else panic("could not translate dp264_mv addr\n"); diff --git a/python/m5/objects/Pci.py b/python/m5/objects/Pci.py index 0957e2883..defdd10a3 100644 --- a/python/m5/objects/Pci.py +++ b/python/m5/objects/Pci.py @@ -50,3 +50,6 @@ class PciDevice(DmaDevice): pci_func = Param.Int("PCI function code") configdata = Param.PciConfigData(Parent.any, "PCI Config data") configspace = Param.PciConfigAll(Parent.any, "PCI Configspace") + +class PciFake(PciDevice): + type = 'PciFake' diff --git a/python/m5/objects/Tsunami.py b/python/m5/objects/Tsunami.py index c8fd94e2c..5425f421f 100644 --- a/python/m5/objects/Tsunami.py +++ b/python/m5/objects/Tsunami.py @@ -11,8 +11,9 @@ class TsunamiCChip(FooPioDevice): type = 'TsunamiCChip' tsunami = Param.Tsunami(Parent.any, "Tsunami") -class TsunamiFake(FooPioDevice): - type = 'TsunamiFake' +class IsaFake(FooPioDevice): + type = 'IsaFake' + size = Param.Addr("Size of address range") class TsunamiIO(FooPioDevice): type = 'TsunamiIO' diff --git a/sim/system.cc b/sim/system.cc index 47ffc4b01..3da92c447 100644 --- a/sim/system.cc +++ b/sim/system.cc @@ -154,8 +154,8 @@ System::System(Params *p) if (!hwrpb) panic("could not translate hwrpb addr\n"); - *(uint64_t*)(hwrpb+0x50) = htoa(params->system_type); - *(uint64_t*)(hwrpb+0x58) = htoa(params->system_rev); + *(uint64_t*)(hwrpb+0x50) = htog(params->system_type); + *(uint64_t*)(hwrpb+0x58) = htog(params->system_rev); } else panic("could not find hwrpb\n"); @@ -192,7 +192,7 @@ System::setAlphaAccess(Addr access) if (!m5AlphaAccess) panic("could not translate m5AlphaAccess addr\n"); - *m5AlphaAccess = htoa(EV5::Phys2K0Seg(access)); + *m5AlphaAccess = htog(EV5::Phys2K0Seg(access)); } else panic("could not find m5AlphaAccess\n"); }