diff options
Diffstat (limited to 'dev')
38 files changed, 3272 insertions, 889 deletions
diff --git a/dev/alpha_console.cc b/dev/alpha_console.cc index 680704b30..7deabe2fc 100644 --- a/dev/alpha_console.cc +++ b/dev/alpha_console.cc @@ -61,12 +61,12 @@ AlphaConsole::AlphaConsole(const string &name, SimConsole *cons, SimpleDisk *d, HierParams *hier, Bus *bus) : PioDevice(name), disk(d), console(cons), addr(a) { - mmu->add_child(this, Range<Addr>(addr, addr + size)); + mmu->add_child(this, RangeSize(addr, size)); if (bus) { pioInterface = newPioInterface(name, hier, bus, this, &AlphaConsole::cacheAccess); - pioInterface->addAddrRange(addr, addr + size); + pioInterface->addAddrRange(RangeSize(addr, size)); } alphaAccess = new AlphaAccess; @@ -98,7 +98,7 @@ AlphaConsole::read(MemReqPtr &req, uint8_t *data) { memset(data, 0, req->size); - Addr daddr = req->paddr - (addr & PA_IMPL_MASK); + Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); switch (req->size) { @@ -198,7 +198,7 @@ AlphaConsole::write(MemReqPtr &req, const uint8_t *data) return Machine_Check_Fault; } - Addr daddr = req->paddr - (addr & PA_IMPL_MASK); + Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); ExecContext *other_xc; switch (daddr) { diff --git a/dev/baddev.cc b/dev/baddev.cc index 7c563e80a..73b082d47 100644 --- a/dev/baddev.cc +++ b/dev/baddev.cc @@ -50,12 +50,12 @@ BadDevice::BadDevice(const string &name, Addr a, MemoryController *mmu, HierParams *hier, Bus *bus, const string &devicename) : PioDevice(name), addr(a), devname(devicename) { - mmu->add_child(this, Range<Addr>(addr, addr + size)); + mmu->add_child(this, RangeSize(addr, size)); if (bus) { pioInterface = newPioInterface(name, hier, bus, this, &BadDevice::cacheAccess); - pioInterface->addAddrRange(addr, addr + size - 1); + pioInterface->addAddrRange(RangeSize(addr, size)); } } diff --git a/dev/etherdump.cc b/dev/etherdump.cc index 27817d456..485d5599c 100644 --- a/dev/etherdump.cc +++ b/dev/etherdump.cc @@ -42,11 +42,9 @@ using std::string; -EtherDump::EtherDump(const string &name, const string &file, int max) - : SimObject(name), maxlen(max) +EtherDump::EtherDump(const string &name, std::ostream *_stream, int max) + : SimObject(name), stream(_stream), maxlen(max) { - if (!file.empty()) - stream.open(file.c_str()); } #define DLT_EN10MB 1 // Ethernet (10Mb) @@ -74,9 +72,6 @@ struct pcap_pkthdr { void EtherDump::init() { - if (!stream.is_open()) - return; - curtime = time(NULL); s_freq = ticksPerSecond; us_freq = ticksPerSecond / ULL(1000000); @@ -91,7 +86,7 @@ EtherDump::init() hdr.sigfigs = 0; hdr.linktype = DLT_EN10MB; - stream.write(reinterpret_cast<char *>(&hdr), sizeof(hdr)); + stream->write(reinterpret_cast<char *>(&hdr), sizeof(hdr)); /* * output an empty packet with the current time so that we know @@ -103,9 +98,9 @@ EtherDump::init() pkthdr.microseconds = 0; pkthdr.caplen = 0; pkthdr.len = 0; - stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); + stream->write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); - stream.flush(); + stream->flush(); } void @@ -116,9 +111,9 @@ EtherDump::dumpPacket(PacketPtr &packet) pkthdr.microseconds = (curTick / us_freq) % ULL(1000000); pkthdr.caplen = std::min(packet->length, maxlen); pkthdr.len = packet->length; - stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); - stream.write(reinterpret_cast<char *>(packet->data), pkthdr.caplen); - stream.flush(); + stream->write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); + stream->write(reinterpret_cast<char *>(packet->data), pkthdr.caplen); + stream->flush(); } BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDump) @@ -130,28 +125,14 @@ END_DECLARE_SIM_OBJECT_PARAMS(EtherDump) BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDump) - INIT_PARAM(file, "file to dump packets to"), + INIT_PARAM_DFLT(file, "file to dump packets to", "etherdump"), INIT_PARAM_DFLT(maxlen, "max portion of packet data to dump", 96) END_INIT_SIM_OBJECT_PARAMS(EtherDump) CREATE_SIM_OBJECT(EtherDump) { - string filename; - if (file.isValid()) { - filename = file; - - if (filename[0] != '/' && !outputDirectory.empty()) - filename = outputDirectory + filename; - } else { - if (outputDirectory.empty()) { - filename = "etherdump"; - } else { - filename = outputDirectory + "etherdump"; - } - } - - return new EtherDump(getInstanceName(), filename, maxlen); + return new EtherDump(getInstanceName(), makeOutputStream(file), maxlen); } REGISTER_SIM_OBJECT("EtherDump", EtherDump) diff --git a/dev/etherdump.hh b/dev/etherdump.hh index 62364359e..b127d05e2 100644 --- a/dev/etherdump.hh +++ b/dev/etherdump.hh @@ -43,7 +43,7 @@ class EtherDump : public SimObject { private: - std::ofstream stream; + std::ostream *stream; const int maxlen; void dumpPacket(PacketPtr &packet); void init(); @@ -53,9 +53,9 @@ class EtherDump : public SimObject Tick us_freq; public: - EtherDump(const std::string &name, const std::string &file, int max); + EtherDump(const std::string &name, std::ostream *_stream, int max); - inline void dump(PacketPtr &pkt) { if (stream.is_open()) dumpPacket(pkt); } + inline void dump(PacketPtr &pkt) { dumpPacket(pkt); } }; #endif // __ETHERDUMP_H__ diff --git a/dev/etherint.hh b/dev/etherint.hh index ddfe16d88..bcdf0ae06 100644 --- a/dev/etherint.hh +++ b/dev/etherint.hh @@ -31,8 +31,8 @@ * components. */ -#ifndef __ETHERINT_HH__ -#define __ETHERINT_HH__ +#ifndef __DEV_ETHERINT_HH__ +#define __DEV_ETHERINT_HH__ #include <string> @@ -54,13 +54,13 @@ class EtherInt : public SimObject virtual ~EtherInt() {} void setPeer(EtherInt *p); - virtual bool recvPacket(PacketPtr &packet) = 0; + void recvDone() { peer->sendDone(); } - bool sendPacket(PacketPtr &packet) - { - return peer ? peer->recvPacket(packet) : true; - } virtual void sendDone() = 0; + + bool sendPacket(PacketPtr packet) + { return peer ? peer->recvPacket(packet) : true; } + virtual bool recvPacket(PacketPtr packet) = 0; }; -#endif // __ETHERINT_HH__ +#endif // __DEV_ETHERINT_HH__ diff --git a/dev/etherlink.cc b/dev/etherlink.cc index 3cc4f75ea..d637e152a 100644 --- a/dev/etherlink.cc +++ b/dev/etherlink.cc @@ -41,8 +41,9 @@ #include "dev/etherlink.hh" #include "dev/etherpkt.hh" #include "sim/builder.hh" -#include "sim/universe.hh" +#include "sim/serialize.hh" #include "sim/system.hh" +#include "sim/universe.hh" using namespace std; @@ -104,7 +105,7 @@ EtherLink::unserialize(Checkpoint *cp, const string §ion) } void -EtherLink::Link::txComplete(PacketPtr &packet) +EtherLink::Link::txComplete(PacketPtr packet) { DPRINTF(Ethernet, "packet received: len=%d\n", packet->length); DDUMP(EthernetData, packet->data, packet->length); @@ -121,7 +122,7 @@ class LinkDelayEvent : public Event LinkDelayEvent(EtherLink::Link *link); public: - LinkDelayEvent(EtherLink::Link *link, PacketPtr &pkt, Tick when); + LinkDelayEvent(EtherLink::Link *link, PacketPtr pkt, Tick when); void process(); @@ -152,7 +153,7 @@ EtherLink::Link::txDone() } bool -EtherLink::Link::transmit(PacketPtr &pkt) +EtherLink::Link::transmit(PacketPtr pkt) { if (busy()) { DPRINTF(Ethernet, "packet not sent, link busy\n"); @@ -184,10 +185,8 @@ EtherLink::Link::serialize(ostream &os) SERIALIZE_SCALAR(event_time); } - if (packet_exists) { - nameOut(os, csprintf("%s.packet", name())); - packet->serialize(os); - } + if (packet_exists) + packet->serialize("packet", os); } void @@ -196,8 +195,8 @@ EtherLink::Link::unserialize(Checkpoint *cp, const string §ion) bool packet_exists; UNSERIALIZE_SCALAR(packet_exists); if (packet_exists) { - packet = new EtherPacket; - packet->unserialize(cp, csprintf("%s.packet", section)); + packet = new PacketData(16384); + packet->unserialize("packet", cp, section); } bool event_scheduled; @@ -216,7 +215,7 @@ LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l) setFlags(AutoDelete); } -LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, PacketPtr &p, Tick when) +LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, PacketPtr p, Tick when) : Event(&mainEventQueue), link(l), packet(p) { setFlags(AutoSerialize); @@ -237,8 +236,7 @@ LinkDelayEvent::serialize(ostream &os) Event::serialize(os); SERIALIZE_OBJPTR(link); - nameOut(os, csprintf("%s.packet", name())); - packet->serialize(os); + packet->serialize("packet", os); } @@ -246,8 +244,8 @@ void LinkDelayEvent::unserialize(Checkpoint *cp, const string §ion) { Event::unserialize(cp, section); - packet = new EtherPacket; - packet->unserialize(cp, csprintf("%s.packet", section)); + packet = new PacketData(16384); + packet->unserialize("packet", cp, section); } diff --git a/dev/etherlink.hh b/dev/etherlink.hh index 204348c6d..e998a006f 100644 --- a/dev/etherlink.hh +++ b/dev/etherlink.hh @@ -75,7 +75,7 @@ class EtherLink : public SimObject DoneEvent doneEvent; friend class LinkDelayEvent; - void txComplete(PacketPtr &packet); + void txComplete(PacketPtr packet); public: Link(const std::string &name, double rate, Tick delay, @@ -85,7 +85,7 @@ class EtherLink : public SimObject virtual const std::string name() const { return objName; } bool busy() const { return (bool)packet; } - bool transmit(PacketPtr &packet); + bool transmit(PacketPtr packet); void setTxInt(Interface *i) { assert(!txint); txint = i; } void setRxInt(Interface *i) { assert(!rxint); rxint = i; } @@ -104,7 +104,7 @@ class EtherLink : public SimObject public: Interface(const std::string &name, Link *txlink, Link *rxlink); - bool recvPacket(PacketPtr &packet) { return txlink->transmit(packet); } + bool recvPacket(PacketPtr packet) { return txlink->transmit(packet); } void sendDone() { peer->sendDone(); } }; diff --git a/dev/etherpkt.cc b/dev/etherpkt.cc index 9eda89e9d..bf60bc150 100644 --- a/dev/etherpkt.cc +++ b/dev/etherpkt.cc @@ -28,23 +28,23 @@ #include <iostream> +#include "base/misc.hh" #include "dev/etherpkt.hh" #include "sim/serialize.hh" using namespace std; void -EtherPacket::serialize(ostream &os) +PacketData::serialize(const string &base, ostream &os) { - SERIALIZE_SCALAR(length); - SERIALIZE_ARRAY(data, length); + paramOut(os, base + ".length", length); + arrayParamOut(os, base + ".data", data, length); } void -EtherPacket::unserialize(Checkpoint *cp, const string §ion) +PacketData::unserialize(const string &base, Checkpoint *cp, + const string §ion) { - UNSERIALIZE_SCALAR(length); - data = new uint8_t[length]; - UNSERIALIZE_ARRAY(data, length); + paramIn(cp, section, base + ".length", length); + arrayParamIn(cp, section, base + ".data", data, length); } - diff --git a/dev/etherpkt.hh b/dev/etherpkt.hh index abdf30166..7a7809f0a 100644 --- a/dev/etherpkt.hh +++ b/dev/etherpkt.hh @@ -37,70 +37,32 @@ #include <memory> #include <assert.h> -#include "sim/host.hh" #include "base/refcnt.hh" -#include "base/inet_hdrs.hh" +#include "sim/host.hh" -class Checkpoint; /* * Reference counted class containing ethernet packet data */ -class EtherPacket : public RefCounted +class Checkpoint; +class PacketData : public RefCounted { public: uint8_t *data; int length; public: - EtherPacket() : data(NULL), length(0) {} - EtherPacket(std::auto_ptr<uint8_t> d, int l) - : data(d.release()), length(l) {} - ~EtherPacket() { if (data) delete [] data; } + PacketData() : data(NULL), length(0) { } + explicit PacketData(size_t size) : data(new uint8_t[size]), length(0) { } + PacketData(std::auto_ptr<uint8_t> d, int l) + : data(d.release()), length(l) { } + ~PacketData() { if (data) delete [] data; } public: - bool IsUnicast() { return data[0] == 0x00; } - bool IsMulticast() { return data[0] == 0x01; } - bool IsBroadcast() { return data[0] == 0xff; } - - bool isIpPkt() { - eth_header *eth = (eth_header *) data; - return (eth->type == 0x8); - } - bool isTcpPkt(ip_header *ip) { - return (ip->protocol == 0x6); - } - bool isTcpPkt() { - ip_header *ip = getIpHdr(); - return (ip->protocol == 0x6); - } - bool isUdpPkt(ip_header *ip) { - return (ip->protocol == 17); - } - bool isUdpPkt() { - ip_header *ip = getIpHdr(); - return (ip->protocol == 17); - } - - ip_header *getIpHdr() { - assert(isIpPkt()); - return (ip_header *) (data + sizeof(eth_header)); - } - - tcp_header *getTcpHdr(ip_header *ip) { - assert(isTcpPkt(ip)); - return (tcp_header *) ((uint8_t *) ip + (ip->vers_len & 0xf)*4); - } - - udp_header *getUdpHdr(ip_header *ip) { - assert(isUdpPkt(ip)); - return (udp_header *) ((uint8_t *) ip + (ip->vers_len & 0xf)*4); - } - typedef RefCountingPtr<EtherPacket> PacketPtr; - - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); + void serialize(const std::string &base, std::ostream &os); + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); }; -typedef RefCountingPtr<EtherPacket> PacketPtr; +typedef RefCountingPtr<PacketData> PacketPtr; #endif // __ETHERPKT_HH__ diff --git a/dev/ethertap.cc b/dev/ethertap.cc index edc400760..1603a9bd3 100644 --- a/dev/ethertap.cc +++ b/dev/ethertap.cc @@ -169,7 +169,7 @@ EtherTap::detach() } bool -EtherTap::recvPacket(PacketPtr &packet) +EtherTap::recvPacket(PacketPtr packet) { if (dump) dump->dump(packet); @@ -219,8 +219,7 @@ EtherTap::process(int revent) while (data_len != 0 && buffer_offset >= data_len + sizeof(u_int32_t)) { PacketPtr packet; - packet = new EtherPacket; - packet->data = new uint8_t[data_len]; + packet = new PacketData(data_len); packet->length = data_len; memcpy(packet->data, data, data_len); diff --git a/dev/ethertap.hh b/dev/ethertap.hh index 1fe368085..5f760ed34 100644 --- a/dev/ethertap.hh +++ b/dev/ethertap.hh @@ -70,7 +70,7 @@ class EtherTap : public EtherInt std::queue<PacketPtr> packetBuffer; void process(int revent); - void enqueue(EtherPacket *packet); + void enqueue(PacketData *packet); void retransmit(); /* @@ -94,7 +94,7 @@ class EtherTap : public EtherInt EtherTap(const std::string &name, EtherDump *dump, int port, int bufsz); virtual ~EtherTap(); - virtual bool recvPacket(PacketPtr &packet); + virtual bool recvPacket(PacketPtr packet); virtual void sendDone(); virtual void serialize(std::ostream &os); diff --git a/dev/ide_ctrl.cc b/dev/ide_ctrl.cc index e40248461..109908ead 100644 --- a/dev/ide_ctrl.cc +++ b/dev/ide_ctrl.cc @@ -34,16 +34,15 @@ #include "base/trace.hh" #include "cpu/intr_control.hh" #include "dev/dma.hh" -#include "dev/pcireg.h" -#include "dev/pciconfigall.hh" -#include "dev/ide_disk.hh" #include "dev/ide_ctrl.hh" -#include "dev/tsunami_cchip.hh" +#include "dev/ide_disk.hh" +#include "dev/pciconfigall.hh" +#include "dev/pcireg.h" +#include "dev/platform.hh" #include "mem/bus/bus.hh" +#include "mem/bus/dma_interface.hh" #include "mem/bus/pio_interface.hh" #include "mem/bus/pio_interface_impl.hh" -#include "mem/bus/dma_interface.hh" -#include "dev/tsunami.hh" #include "mem/functional_mem/memory_control.hh" #include "mem/functional_mem/physical_memory.hh" #include "sim/builder.hh" @@ -55,17 +54,9 @@ using namespace std; // Initialization and destruction //// -IdeController::IdeController(const string &name, IntrControl *ic, - const vector<IdeDisk *> &new_disks, - MemoryController *mmu, PciConfigAll *cf, - PciConfigData *cd, Tsunami *t, uint32_t bus_num, - uint32_t dev_num, uint32_t func_num, - Bus *host_bus, Tick pio_latency, HierParams *hier) - : PciDev(name, mmu, cf, cd, bus_num, dev_num, func_num), tsunami(t) +IdeController::IdeController(Params *p) + : PciDev(p) { - // put back pointer into Tsunami - tsunami->disk_controller = this; - // initialize the PIO interface addresses pri_cmd_addr = 0; pri_cmd_size = BARSize[0]; @@ -99,23 +90,25 @@ IdeController::IdeController(const string &name, IntrControl *ic, memset(cmd_in_progress, 0, sizeof(cmd_in_progress)); // create the PIO and DMA interfaces - if (host_bus) { - pioInterface = newPioInterface(name, hier, host_bus, this, + if (params()->host_bus) { + pioInterface = newPioInterface(name(), params()->hier, + params()->host_bus, this, &IdeController::cacheAccess); - dmaInterface = new DMAInterface<Bus>(name + ".dma", host_bus, - host_bus, 1); - pioLatency = pio_latency * host_bus->clockRatio; + dmaInterface = new DMAInterface<Bus>(name() + ".dma", + params()->host_bus, + params()->host_bus, 1); + pioLatency = params()->pio_latency * params()->host_bus->clockRatio; } // setup the disks attached to controller memset(disks, 0, sizeof(IdeDisk *) * 4); - if (new_disks.size() > 3) + if (params()->disks.size() > 3) panic("IDE controllers support a maximum of 4 devices attached!\n"); - for (int i = 0; i < new_disks.size(); i++) { - disks[i] = new_disks[i]; + for (int i = 0; i < params()->disks.size(); i++) { + disks[i] = params()->disks[i]; disks[i]->setController(this, dmaInterface); } } @@ -239,22 +232,6 @@ IdeController::setDmaComplete(IdeDisk *disk) } //// -// Interrupt handling -//// - -void -IdeController::intrPost() -{ - tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine); -} - -void -IdeController::intrClear() -{ - tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine); -} - -//// // Bus timing and bus access functions //// @@ -377,10 +354,10 @@ IdeController::WriteConfig(int offset, int size, uint32_t data) if (BARAddrs[0] != 0) { pri_cmd_addr = BARAddrs[0]; if (pioInterface) - pioInterface->addAddrRange(pri_cmd_addr, - pri_cmd_addr + pri_cmd_size - 1); + pioInterface->addAddrRange(RangeSize(pri_cmd_addr, + pri_cmd_size)); - pri_cmd_addr &= PA_UNCACHED_MASK; + pri_cmd_addr &= EV5::PAddrUncachedMask; } break; @@ -388,10 +365,10 @@ IdeController::WriteConfig(int offset, int size, uint32_t data) if (BARAddrs[1] != 0) { pri_ctrl_addr = BARAddrs[1]; if (pioInterface) - pioInterface->addAddrRange(pri_ctrl_addr, - pri_ctrl_addr + pri_ctrl_size - 1); + pioInterface->addAddrRange(RangeSize(pri_ctrl_addr, + pri_ctrl_size)); - pri_ctrl_addr &= PA_UNCACHED_MASK; + pri_ctrl_addr &= EV5::PAddrUncachedMask; } break; @@ -399,10 +376,10 @@ IdeController::WriteConfig(int offset, int size, uint32_t data) if (BARAddrs[2] != 0) { sec_cmd_addr = BARAddrs[2]; if (pioInterface) - pioInterface->addAddrRange(sec_cmd_addr, - sec_cmd_addr + sec_cmd_size - 1); + pioInterface->addAddrRange(RangeSize(sec_cmd_addr, + sec_cmd_size)); - sec_cmd_addr &= PA_UNCACHED_MASK; + sec_cmd_addr &= EV5::PAddrUncachedMask; } break; @@ -410,10 +387,10 @@ IdeController::WriteConfig(int offset, int size, uint32_t data) if (BARAddrs[3] != 0) { sec_ctrl_addr = BARAddrs[3]; if (pioInterface) - pioInterface->addAddrRange(sec_ctrl_addr, - sec_ctrl_addr + sec_ctrl_size - 1); + pioInterface->addAddrRange(RangeSize(sec_ctrl_addr, + sec_ctrl_size)); - sec_ctrl_addr &= PA_UNCACHED_MASK; + sec_ctrl_addr &= EV5::PAddrUncachedMask; } break; @@ -421,9 +398,9 @@ IdeController::WriteConfig(int offset, int size, uint32_t data) if (BARAddrs[4] != 0) { bmi_addr = BARAddrs[4]; if (pioInterface) - pioInterface->addAddrRange(bmi_addr, bmi_addr + bmi_size - 1); + pioInterface->addAddrRange(RangeSize(bmi_addr, bmi_size)); - bmi_addr &= PA_UNCACHED_MASK; + bmi_addr &= EV5::PAddrUncachedMask; } break; } @@ -675,15 +652,11 @@ IdeController::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_ARRAY(cmd_in_progress, 4); if (pioInterface) { - pioInterface->addAddrRange(pri_cmd_addr, pri_cmd_addr + - pri_cmd_size - 1); - pioInterface->addAddrRange(pri_ctrl_addr, pri_ctrl_addr + - pri_ctrl_size - 1); - pioInterface->addAddrRange(sec_cmd_addr, sec_cmd_addr + - sec_cmd_size - 1); - pioInterface->addAddrRange(sec_ctrl_addr, sec_ctrl_addr + - sec_ctrl_size - 1); - pioInterface->addAddrRange(bmi_addr, bmi_addr + bmi_size - 1); + pioInterface->addAddrRange(RangeSize(pri_cmd_addr, pri_cmd_size)); + pioInterface->addAddrRange(RangeSize(pri_ctrl_addr, pri_ctrl_size)); + pioInterface->addAddrRange(RangeSize(sec_cmd_addr, sec_cmd_size)); + pioInterface->addAddrRange(RangeSize(sec_ctrl_addr, sec_ctrl_size)); + pioInterface->addAddrRange(RangeSize(bmi_addr, bmi_size)); } } @@ -691,12 +664,11 @@ IdeController::unserialize(Checkpoint *cp, const std::string §ion) BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController) - SimObjectParam<IntrControl *> intr_ctrl; SimObjectVectorParam<IdeDisk *> disks; SimObjectParam<MemoryController *> mmu; SimObjectParam<PciConfigAll *> configspace; SimObjectParam<PciConfigData *> configdata; - SimObjectParam<Tsunami *> tsunami; + SimObjectParam<Platform *> platform; Param<uint32_t> pci_bus; Param<uint32_t> pci_dev; Param<uint32_t> pci_func; @@ -708,12 +680,11 @@ END_DECLARE_SIM_OBJECT_PARAMS(IdeController) BEGIN_INIT_SIM_OBJECT_PARAMS(IdeController) - INIT_PARAM(intr_ctrl, "Interrupt Controller"), INIT_PARAM(disks, "IDE disks attached to this controller"), INIT_PARAM(mmu, "Memory controller"), INIT_PARAM(configspace, "PCI Configspace"), INIT_PARAM(configdata, "PCI Config data"), - INIT_PARAM(tsunami, "Tsunami chipset pointer"), + INIT_PARAM(platform, "Platform pointer"), INIT_PARAM(pci_bus, "PCI bus ID"), INIT_PARAM(pci_dev, "PCI device number"), INIT_PARAM(pci_func, "PCI function code"), @@ -725,9 +696,21 @@ END_INIT_SIM_OBJECT_PARAMS(IdeController) CREATE_SIM_OBJECT(IdeController) { - return new IdeController(getInstanceName(), intr_ctrl, disks, mmu, - configspace, configdata, tsunami, pci_bus, - pci_dev, pci_func, io_bus, pio_latency, hier); + IdeController::Params *params = new IdeController::Params; + params->name = getInstanceName(); + params->mmu = mmu; + params->configSpace = configspace; + params->configData = configdata; + params->plat = platform; + params->busNum = pci_bus; + params->deviceNum = pci_dev; + params->functionNum = pci_func; + + params->disks = disks; + params->host_bus = io_bus; + params->pio_latency = pio_latency; + params->hier = hier; + return new IdeController(params); } REGISTER_SIM_OBJECT("IdeController", IdeController) diff --git a/dev/ide_ctrl.hh b/dev/ide_ctrl.hh index b29e5ae9a..f1082d094 100644 --- a/dev/ide_ctrl.hh +++ b/dev/ide_ctrl.hh @@ -80,14 +80,14 @@ typedef enum RegType { BMI_BLOCK } RegType_t; +class BaseInterface; +class Bus; +class HierParams; class IdeDisk; class IntrControl; class PciConfigAll; -class Tsunami; class PhysicalMemory; -class BaseInterface; -class HierParams; -class Bus; +class Platform; /** * Device model for an Intel PIIX4 IDE controller @@ -95,6 +95,8 @@ class Bus; class IdeController : public PciDev { + friend class IdeDisk; + private: /** Primary command block registers */ Addr pri_cmd_addr; @@ -125,10 +127,6 @@ class IdeController : public PciDev bool bm_enabled; bool cmd_in_progress[4]; - public: - /** Pointer to the chipset */ - Tsunami *tsunami; - private: /** IDE disks connected to controller */ IdeDisk *disks[4]; @@ -149,37 +147,23 @@ class IdeController : public PciDev bool isDiskSelected(IdeDisk *diskPtr); public: - /** - * Constructs and initializes this controller. - * @param name The name of this controller. - * @param ic The interrupt controller. - * @param mmu The memory controller - * @param cf PCI config space - * @param cd PCI config data - * @param bus_num The PCI bus number - * @param dev_num The PCI device number - * @param func_num The PCI function number - * @param host_bus The host bus to connect to - * @param hier The hierarchy parameters - */ - IdeController(const std::string &name, IntrControl *ic, - const std::vector<IdeDisk *> &new_disks, - MemoryController *mmu, PciConfigAll *cf, - PciConfigData *cd, Tsunami *t, - uint32_t bus_num, uint32_t dev_num, uint32_t func_num, - Bus *host_bus, Tick pio_latency, HierParams *hier); + struct Params : public PciDev::Params + { + /** Array of disk objects */ + std::vector<IdeDisk *> disks; + Bus *host_bus; + Tick pio_latency; + HierParams *hier; + }; + const Params *params() const { return (const Params *)_params; } - /** - * Deletes the connected devices. - */ + public: + IdeController(Params *p); ~IdeController(); virtual void WriteConfig(int offset, int size, uint32_t data); virtual void ReadConfig(int offset, int size, uint8_t *data); - void intrPost(); - void intrClear(); - void setDmaComplete(IdeDisk *disk); /** diff --git a/dev/ide_disk.cc b/dev/ide_disk.cc index 99724f077..073c10436 100644 --- a/dev/ide_disk.cc +++ b/dev/ide_disk.cc @@ -35,7 +35,6 @@ #include <deque> #include <string> -#include "arch/alpha/pmap.h" #include "base/cprintf.hh" // csprintf #include "base/trace.hh" #include "dev/disk_image.hh" @@ -51,6 +50,7 @@ #include "sim/builder.hh" #include "sim/sim_object.hh" #include "sim/universe.hh" +#include "targetarch/isa_traits.hh" using namespace std; @@ -177,7 +177,7 @@ Addr IdeDisk::pciToDma(Addr pciAddr) { if (ctrl) - return ctrl->tsunami->pchip->translatePciToDma(pciAddr); + return ctrl->plat->pciToDma(pciAddr); else panic("Access to unset controller!\n"); } @@ -188,14 +188,14 @@ IdeDisk::bytesInDmaPage(Addr curAddr, uint32_t bytesLeft) uint32_t bytesInPage = 0; // First calculate how many bytes could be in the page - if (bytesLeft > ALPHA_PGBYTES) - bytesInPage = ALPHA_PGBYTES; + if (bytesLeft > TheISA::PageBytes) + bytesInPage = TheISA::PageBytes; else bytesInPage = bytesLeft; // Next, see if we have crossed a page boundary, and adjust Addr upperBound = curAddr + bytesInPage; - Addr pageBound = alpha_trunc_page(curAddr) + ALPHA_PGBYTES; + Addr pageBound = TheISA::TruncPage(curAddr) + TheISA::PageBytes; assert(upperBound >= curAddr && "DMA read wraps around address space!\n"); @@ -510,7 +510,7 @@ IdeDisk::dmaWriteDone() // setup the initial page and DMA address curAddr = curPrd.getBaseAddr(); - pageAddr = alpha_trunc_page(curAddr); + pageAddr = TheISA::TruncPage(curAddr); dmaAddr = pciToDma(curAddr); // clear out the data buffer @@ -518,14 +518,14 @@ IdeDisk::dmaWriteDone() while (bytesRead < curPrd.getByteCount()) { // see if we have crossed into a new page - if (pageAddr != alpha_trunc_page(curAddr)) { + if (pageAddr != TheISA::TruncPage(curAddr)) { // write the data to memory memcpy(physmem->dma_addr(dmaAddr, bytesInPage), (void *)(dataBuffer + (bytesRead - bytesInPage)), bytesInPage); // update the DMA address and page address - pageAddr = alpha_trunc_page(curAddr); + pageAddr = TheISA::TruncPage(curAddr); dmaAddr = pciToDma(curAddr); bytesInPage = 0; @@ -732,6 +732,7 @@ IdeDisk::startCommand() void IdeDisk::intrPost() { + DPRINTF(IdeDisk, "IDE Disk Posting Interrupt\n"); if (intrPending) panic("Attempt to post an interrupt with one pending\n"); @@ -745,6 +746,7 @@ IdeDisk::intrPost() void IdeDisk::intrClear() { + DPRINTF(IdeDisk, "IDE Disk Clearing Interrupt\n"); if (!intrPending) panic("Attempt to clear a non-pending interrupt\n"); diff --git a/dev/io_device.hh b/dev/io_device.hh index f49afc0a6..8c9dc4a35 100644 --- a/dev/io_device.hh +++ b/dev/io_device.hh @@ -34,7 +34,7 @@ class BaseInterface; class Bus; class HierParams; -template <class Bus> class DMAInterface; +template <class BusType> class DMAInterface; class PioDevice : public FunctionalMemory { diff --git a/dev/ns_gige.cc b/dev/ns_gige.cc index f7f56d39b..eee8fbbce 100644 --- a/dev/ns_gige.cc +++ b/dev/ns_gige.cc @@ -41,7 +41,6 @@ #include "dev/etherlink.hh" #include "dev/ns_gige.hh" #include "dev/pciconfigall.hh" -#include "dev/tsunami_cchip.hh" #include "mem/bus/bus.hh" #include "mem/bus/dma_interface.hh" #include "mem/bus/pio_interface.hh" @@ -51,7 +50,7 @@ #include "sim/builder.hh" #include "sim/debug.hh" #include "sim/host.hh" -#include "sim/sim_stats.hh" +#include "sim/stats.hh" #include "targetarch/vtophys.hh" const char *NsRxStateStrings[] = @@ -86,82 +85,68 @@ const char *NsDmaState[] = }; using namespace std; - -// helper function declarations -// These functions reverse Endianness so we can evaluate network data -// correctly -uint16_t reverseEnd16(uint16_t); -uint32_t reverseEnd32(uint32_t); +using namespace Net; /////////////////////////////////////////////////////////////////////// // // NSGigE PCI Device // -NSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay, - PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay, - MemoryController *mmu, HierParams *hier, Bus *header_bus, - Bus *payload_bus, Tick pio_latency, bool dma_desc_free, - bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay, - Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf, - PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev, - uint32_t func, bool rx_filter, const int eaddr[6], - uint32_t tx_fifo_size, uint32_t rx_fifo_size) - : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false), - maxTxFifoSize(tx_fifo_size), maxRxFifoSize(rx_fifo_size), +NSGigE::NSGigE(Params *p) + : PciDev(p), ioEnable(false), + txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), txXferLen(0), rxXferLen(0), txState(txIdle), txEnable(false), - CTDD(false), txFifoAvail(tx_fifo_size), + CTDD(false), txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), - rxEnable(false), CRDD(false), rxPktBytes(0), rxFifoCnt(0), + rxEnable(false), CRDD(false), rxPktBytes(0), rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), rxDmaReadEvent(this), rxDmaWriteEvent(this), txDmaReadEvent(this), txDmaWriteEvent(this), - dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free), - txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0), - txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false), + dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), + txDelay(p->tx_delay), rxDelay(p->rx_delay), + rxKickTick(0), txKickTick(0), + txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false), acceptPerfect(false), acceptArp(false), - physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false), + physmem(p->pmem), intrTick(0), cpuPendingIntr(false), intrEvent(0), interface(0) { - tsunami->ethernet = this; - - if (header_bus) { - pioInterface = newPioInterface(name, hier, header_bus, this, + if (p->header_bus) { + pioInterface = newPioInterface(name(), p->hier, + p->header_bus, this, &NSGigE::cacheAccess); - pioLatency = pio_latency * header_bus->clockRatio; + pioLatency = p->pio_latency * p->header_bus->clockRatio; - if (payload_bus) - dmaInterface = new DMAInterface<Bus>(name + ".dma", - header_bus, payload_bus, 1); + if (p->payload_bus) + dmaInterface = new DMAInterface<Bus>(name() + ".dma", + p->header_bus, + p->payload_bus, 1); else - dmaInterface = new DMAInterface<Bus>(name + ".dma", - header_bus, header_bus, 1); - } else if (payload_bus) { - pioInterface = newPioInterface(name, hier, payload_bus, this, + dmaInterface = new DMAInterface<Bus>(name() + ".dma", + p->header_bus, + p->header_bus, 1); + } else if (p->payload_bus) { + pioInterface = newPioInterface(name(), p->hier, + p->payload_bus, this, &NSGigE::cacheAccess); - pioLatency = pio_latency * payload_bus->clockRatio; + pioLatency = p->pio_latency * p->payload_bus->clockRatio; - dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus, - payload_bus, 1); + dmaInterface = new DMAInterface<Bus>(name() + ".dma", + p->payload_bus, + p->payload_bus, 1); } - intrDelay = US2Ticks(intr_delay); - dmaReadDelay = dma_read_delay; - dmaWriteDelay = dma_write_delay; - dmaReadFactor = dma_read_factor; - dmaWriteFactor = dma_write_factor; + intrDelay = US2Ticks(p->intr_delay); + dmaReadDelay = p->dma_read_delay; + dmaWriteDelay = p->dma_write_delay; + dmaReadFactor = p->dma_read_factor; + dmaWriteFactor = p->dma_write_factor; regsReset(); - rom.perfectMatch[0] = eaddr[0]; - rom.perfectMatch[1] = eaddr[1]; - rom.perfectMatch[2] = eaddr[2]; - rom.perfectMatch[3] = eaddr[3]; - rom.perfectMatch[4] = eaddr[4]; - rom.perfectMatch[5] = eaddr[5]; + memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN); } NSGigE::~NSGigE() @@ -194,34 +179,48 @@ NSGigE::regStats() .prereq(rxBytes) ; - txIPChecksums - .name(name() + ".txIPChecksums") + txIpChecksums + .name(name() + ".txIpChecksums") .desc("Number of tx IP Checksums done by device") .precision(0) .prereq(txBytes) ; - rxIPChecksums - .name(name() + ".rxIPChecksums") + rxIpChecksums + .name(name() + ".rxIpChecksums") .desc("Number of rx IP Checksums done by device") .precision(0) .prereq(rxBytes) ; - txTCPChecksums - .name(name() + ".txTCPChecksums") + txTcpChecksums + .name(name() + ".txTcpChecksums") .desc("Number of tx TCP Checksums done by device") .precision(0) .prereq(txBytes) ; - rxTCPChecksums - .name(name() + ".rxTCPChecksums") + rxTcpChecksums + .name(name() + ".rxTcpChecksums") .desc("Number of rx TCP Checksums done by device") .precision(0) .prereq(rxBytes) ; + txUdpChecksums + .name(name() + ".txUdpChecksums") + .desc("Number of tx UDP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + rxUdpChecksums + .name(name() + ".rxUdpChecksums") + .desc("Number of rx UDP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + descDmaReads .name(name() + ".descDMAReads") .desc("Number of descriptors the device read w/ DMA") @@ -275,6 +274,180 @@ NSGigE::regStats() .prereq(rxBytes) ; + postedSwi + .name(name() + ".postedSwi") + .desc("number of software interrupts posted to CPU") + .precision(0) + ; + + totalSwi + .name(name() + ".totalSwi") + .desc("number of total Swi written to ISR") + .precision(0) + ; + + coalescedSwi + .name(name() + ".coalescedSwi") + .desc("average number of Swi's coalesced into each post") + .precision(0) + ; + + postedRxIdle + .name(name() + ".postedRxIdle") + .desc("number of rxIdle interrupts posted to CPU") + .precision(0) + ; + + totalRxIdle + .name(name() + ".totalRxIdle") + .desc("number of total RxIdle written to ISR") + .precision(0) + ; + + coalescedRxIdle + .name(name() + ".coalescedRxIdle") + .desc("average number of RxIdle's coalesced into each post") + .precision(0) + ; + + postedRxOk + .name(name() + ".postedRxOk") + .desc("number of RxOk interrupts posted to CPU") + .precision(0) + ; + + totalRxOk + .name(name() + ".totalRxOk") + .desc("number of total RxOk written to ISR") + .precision(0) + ; + + coalescedRxOk + .name(name() + ".coalescedRxOk") + .desc("average number of RxOk's coalesced into each post") + .precision(0) + ; + + postedRxDesc + .name(name() + ".postedRxDesc") + .desc("number of RxDesc interrupts posted to CPU") + .precision(0) + ; + + totalRxDesc + .name(name() + ".totalRxDesc") + .desc("number of total RxDesc written to ISR") + .precision(0) + ; + + coalescedRxDesc + .name(name() + ".coalescedRxDesc") + .desc("average number of RxDesc's coalesced into each post") + .precision(0) + ; + + postedTxOk + .name(name() + ".postedTxOk") + .desc("number of TxOk interrupts posted to CPU") + .precision(0) + ; + + totalTxOk + .name(name() + ".totalTxOk") + .desc("number of total TxOk written to ISR") + .precision(0) + ; + + coalescedTxOk + .name(name() + ".coalescedTxOk") + .desc("average number of TxOk's coalesced into each post") + .precision(0) + ; + + postedTxIdle + .name(name() + ".postedTxIdle") + .desc("number of TxIdle interrupts posted to CPU") + .precision(0) + ; + + totalTxIdle + .name(name() + ".totalTxIdle") + .desc("number of total TxIdle written to ISR") + .precision(0) + ; + + coalescedTxIdle + .name(name() + ".coalescedTxIdle") + .desc("average number of TxIdle's coalesced into each post") + .precision(0) + ; + + postedTxDesc + .name(name() + ".postedTxDesc") + .desc("number of TxDesc interrupts posted to CPU") + .precision(0) + ; + + totalTxDesc + .name(name() + ".totalTxDesc") + .desc("number of total TxDesc written to ISR") + .precision(0) + ; + + coalescedTxDesc + .name(name() + ".coalescedTxDesc") + .desc("average number of TxDesc's coalesced into each post") + .precision(0) + ; + + postedRxOrn + .name(name() + ".postedRxOrn") + .desc("number of RxOrn posted to CPU") + .precision(0) + ; + + totalRxOrn + .name(name() + ".totalRxOrn") + .desc("number of total RxOrn written to ISR") + .precision(0) + ; + + coalescedRxOrn + .name(name() + ".coalescedRxOrn") + .desc("average number of RxOrn's coalesced into each post") + .precision(0) + ; + + coalescedTotal + .name(name() + ".coalescedTotal") + .desc("average number of interrupts coalesced into each post") + .precision(0) + ; + + postedInterrupts + .name(name() + ".postedInterrupts") + .desc("number of posts to CPU") + .precision(0) + ; + + droppedPackets + .name(name() + ".droppedPackets") + .desc("number of packets dropped") + .precision(0) + ; + + coalescedSwi = totalSwi / postedInterrupts; + coalescedRxIdle = totalRxIdle / postedInterrupts; + coalescedRxOk = totalRxOk / postedInterrupts; + coalescedRxDesc = totalRxDesc / postedInterrupts; + coalescedTxOk = totalTxOk / postedInterrupts; + coalescedTxIdle = totalTxIdle / postedInterrupts; + coalescedTxDesc = totalTxDesc / postedInterrupts; + coalescedRxOrn = totalRxOrn / postedInterrupts; + + coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc + totalTxOk + + totalTxIdle + totalTxDesc + totalRxOrn) / postedInterrupts; + txBandwidth = txBytes * Stats::constant(8) / simSeconds; rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; txPacketRate = txPackets / simSeconds; @@ -335,19 +508,17 @@ NSGigE::WriteConfig(int offset, int size, uint32_t data) case PCI0_BASE_ADDR0: if (BARAddrs[0] != 0) { if (pioInterface) - pioInterface->addAddrRange(BARAddrs[0], - BARAddrs[0] + BARSize[0] - 1); + pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); - BARAddrs[0] &= PA_UNCACHED_MASK; + BARAddrs[0] &= EV5::PAddrUncachedMask; } break; case PCI0_BASE_ADDR1: if (BARAddrs[1] != 0) { if (pioInterface) - pioInterface->addAddrRange(BARAddrs[1], - BARAddrs[1] + BARSize[1] - 1); + pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1])); - BARAddrs[1] &= PA_UNCACHED_MASK; + BARAddrs[1] &= EV5::PAddrUncachedMask; } break; } @@ -934,6 +1105,33 @@ NSGigE::devIntrPost(uint32_t interrupts) interrupts &= ~ISR_NOIMPL; regs.isr |= interrupts; + if (interrupts & regs.imr) { + if (interrupts & ISR_SWI) { + totalSwi++; + } + if (interrupts & ISR_RXIDLE) { + totalRxIdle++; + } + if (interrupts & ISR_RXOK) { + totalRxOk++; + } + if (interrupts & ISR_RXDESC) { + totalRxDesc++; + } + if (interrupts & ISR_TXOK) { + totalTxOk++; + } + if (interrupts & ISR_TXIDLE) { + totalTxIdle++; + } + if (interrupts & ISR_TXDESC) { + totalTxDesc++; + } + if (interrupts & ISR_RXORN) { + totalRxOrn++; + } + } + DPRINTF(EthernetIntr, "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", interrupts, regs.isr, regs.imr); @@ -946,12 +1144,46 @@ NSGigE::devIntrPost(uint32_t interrupts) } } +/* writing this interrupt counting stats inside this means that this function + is now limited to being used to clear all interrupts upon the kernel + reading isr and servicing. just telling you in case you were thinking + of expanding use. +*/ void NSGigE::devIntrClear(uint32_t interrupts) { if (interrupts & ISR_RESERVE) panic("Cannot clear a reserved interrupt"); + if (regs.isr & regs.imr & ISR_SWI) { + postedSwi++; + } + if (regs.isr & regs.imr & ISR_RXIDLE) { + postedRxIdle++; + } + if (regs.isr & regs.imr & ISR_RXOK) { + postedRxOk++; + } + if (regs.isr & regs.imr & ISR_RXDESC) { + postedRxDesc++; + } + if (regs.isr & regs.imr & ISR_TXOK) { + postedTxOk++; + } + if (regs.isr & regs.imr & ISR_TXIDLE) { + postedTxIdle++; + } + if (regs.isr & regs.imr & ISR_TXDESC) { + postedTxDesc++; + } + if (regs.isr & regs.imr & ISR_RXORN) { + postedRxOrn++; + } + + if (regs.isr & regs.imr & (ISR_SWI | ISR_RXIDLE | ISR_RXOK | ISR_RXDESC | + ISR_TXOK | ISR_TXIDLE | ISR_TXDESC | ISR_RXORN) ) + postedInterrupts++; + interrupts &= ~ISR_NOIMPL; regs.isr &= ~interrupts; @@ -987,61 +1219,50 @@ NSGigE::cpuIntrPost(Tick when) * @todo this warning should be removed and the intrTick code should * be fixed. */ - if (intrTick < curTick && intrTick != 0) { - warn("intrTick < curTick !!! intrTick=%d curTick=%d\n", - intrTick, curTick); - intrTick = 0; - } - assert((intrTick >= curTick) || (intrTick == 0)); - if (when > intrTick && intrTick != 0) + assert(when >= curTick); + assert(intrTick >= curTick || intrTick == 0); + if (when > intrTick && intrTick != 0) { + DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", + intrTick); return; + } intrTick = when; - - if (intrEvent) { - intrEvent->squash(); - intrEvent = 0; + if (intrTick < curTick) { + debug_break(); + intrTick = curTick; } - if (when < curTick) { - cpuInterrupt(); - } else { - DPRINTF(EthernetIntr, - "going to schedule an interrupt for intrTick=%d\n", - intrTick); - intrEvent = new IntrEvent(this, true); - intrEvent->schedule(intrTick); - } + DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", + intrTick); + + if (intrEvent) + intrEvent->squash(); + intrEvent = new IntrEvent(this, true); + intrEvent->schedule(intrTick); } void NSGigE::cpuInterrupt() { - // Don't send an interrupt if there's already one - if (cpuPendingIntr) { - DPRINTF(EthernetIntr, - "would send an interrupt now, but there's already pending\n"); - intrTick = 0; - return; - } - // Don't send an interrupt if it's supposed to be delayed - if (intrTick > curTick) { - DPRINTF(EthernetIntr, - "an interrupt is scheduled for %d, wait til then\n", - intrTick); - return; - } + assert(intrTick == curTick); // Whether or not there's a pending interrupt, we don't care about // it anymore intrEvent = 0; intrTick = 0; - // Send interrupt - cpuPendingIntr = true; + // Don't send an interrupt if there's already one + if (cpuPendingIntr) { + DPRINTF(EthernetIntr, + "would send an interrupt now, but there's already pending\n"); + } else { + // Send interrupt + cpuPendingIntr = true; - DPRINTF(EthernetIntr, "posting cchip interrupt\n"); - tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine); + DPRINTF(EthernetIntr, "posting interrupt\n"); + intrPost(); + } } void @@ -1050,10 +1271,17 @@ NSGigE::cpuIntrClear() if (!cpuPendingIntr) return; + if (intrEvent) { + intrEvent->squash(); + intrEvent = 0; + } + + intrTick = 0; + cpuPendingIntr = false; - DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); - tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine); + DPRINTF(EthernetIntr, "clearing interrupt\n"); + intrClear(); } bool @@ -1067,7 +1295,6 @@ NSGigE::txReset() DPRINTF(Ethernet, "transmit reset\n"); CTDD = false; - txFifoAvail = maxTxFifoSize; txEnable = false;; txFragPtr = 0; assert(txDescCnt == 0); @@ -1083,7 +1310,6 @@ NSGigE::rxReset() CRDD = false; assert(rxPktBytes == 0); - rxFifoCnt = 0; rxEnable = false; rxFragPtr = 0; assert(rxDescCnt == 0); @@ -1336,14 +1562,13 @@ NSGigE::rxKick() #if TRACING_ON if (DTRACE(Ethernet)) { - if (rxPacket->isIpPkt()) { - ip_header *ip = rxPacket->getIpHdr(); - DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID)); - if (rxPacket->isTcpPkt()) { - tcp_header *tcp = rxPacket->getTcpHdr(ip); + IpPtr ip(rxPacket); + if (ip) { + DPRINTF(Ethernet, "ID is %d\n", ip->id()); + TcpPtr tcp(ip); + if (tcp) { DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n", - reverseEnd16(tcp->src_port_num), - reverseEnd16(tcp->dest_port_num)); + tcp->sport(), tcp->dport()); } } } @@ -1351,12 +1576,7 @@ NSGigE::rxKick() // sanity check - i think the driver behaves like this assert(rxDescCnt >= rxPktBytes); - - // Must clear the value before popping to decrement the - // reference count - rxFifo.front() = NULL; - rxFifo.pop_front(); - rxFifoCnt -= rxPacket->length; + rxFifo.pop(); } @@ -1399,33 +1619,38 @@ NSGigE::rxKick() */ if (rxFilterEnable) { rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK; - if (rxFifo.front()->IsUnicast()) + const EthAddr &dst = rxFifoFront()->dst(); + if (dst->unicast()) rxDescCache.cmdsts |= CMDSTS_DEST_SELF; - if (rxFifo.front()->IsMulticast()) + if (dst->multicast()) rxDescCache.cmdsts |= CMDSTS_DEST_MULTI; - if (rxFifo.front()->IsBroadcast()) + if (dst->broadcast()) rxDescCache.cmdsts |= CMDSTS_DEST_MASK; } #endif - if (rxPacket->isIpPkt() && extstsEnable) { + IpPtr ip(rxPacket); + if (extstsEnable && ip) { rxDescCache.extsts |= EXTSTS_IPPKT; - rxIPChecksums++; - if (!ipChecksum(rxPacket, false)) { + rxIpChecksums++; + if (cksum(ip) != 0) { DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); rxDescCache.extsts |= EXTSTS_IPERR; } - if (rxPacket->isTcpPkt()) { + TcpPtr tcp(ip); + UdpPtr udp(ip); + if (tcp) { rxDescCache.extsts |= EXTSTS_TCPPKT; - rxTCPChecksums++; - if (!tcpChecksum(rxPacket, false)) { + rxTcpChecksums++; + if (cksum(tcp) != 0) { DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); rxDescCache.extsts |= EXTSTS_TCPERR; } - } else if (rxPacket->isUdpPkt()) { + } else if (udp) { rxDescCache.extsts |= EXTSTS_UDPPKT; - if (!udpChecksum(rxPacket, false)) { + rxUdpChecksums++; + if (cksum(udp) != 0) { DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); rxDescCache.extsts |= EXTSTS_UDPERR; } @@ -1539,18 +1764,17 @@ NSGigE::transmit() } DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", - maxTxFifoSize - txFifoAvail); + txFifo.size()); if (interface->sendPacket(txFifo.front())) { #if TRACING_ON if (DTRACE(Ethernet)) { - if (txFifo.front()->isIpPkt()) { - ip_header *ip = txFifo.front()->getIpHdr(); - DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID)); - if (txFifo.front()->isTcpPkt()) { - tcp_header *tcp = txFifo.front()->getTcpHdr(ip); + IpPtr ip(txFifo.front()); + if (ip) { + DPRINTF(Ethernet, "ID is %d\n", ip->id()); + TcpPtr tcp(ip); + if (tcp) { DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n", - reverseEnd16(tcp->src_port_num), - reverseEnd16(tcp->dest_port_num)); + tcp->sport(), tcp->dport()); } } } @@ -1560,12 +1784,9 @@ NSGigE::transmit() txBytes += txFifo.front()->length; txPackets++; - txFifoAvail += txFifo.front()->length; - DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", - txFifoAvail); - txFifo.front() = NULL; - txFifo.pop_front(); + txFifo.avail()); + txFifo.pop(); /* * normally do a writeback of the descriptor here, and ONLY @@ -1575,9 +1796,6 @@ NSGigE::transmit() * besides, it's functionally the same. */ devIntrPost(ISR_TXOK); - } else { - DPRINTF(Ethernet, - "May need to rethink always sending the descriptors back?\n"); } if (!txFifo.empty() && !txEvent.scheduled()) { @@ -1784,8 +2002,7 @@ NSGigE::txKick() case txFifoBlock: if (!txPacket) { DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); - txPacket = new EtherPacket; - txPacket->data = new uint8_t[16384]; + txPacket = new PacketData(16384); txPacketBufPtr = txPacket->data; } @@ -1810,15 +2027,22 @@ NSGigE::txKick() DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); /* deal with the the packet that just finished */ if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { + IpPtr ip(txPacket); if (txDescCache.extsts & EXTSTS_UDPPKT) { - udpChecksum(txPacket, true); + UdpPtr udp(ip); + udp->sum(0); + udp->sum(cksum(udp)); + txUdpChecksums++; } else if (txDescCache.extsts & EXTSTS_TCPPKT) { - tcpChecksum(txPacket, true); - txTCPChecksums++; + TcpPtr tcp(ip); + tcp->sum(0); + tcp->sum(cksum(tcp)); + txTcpChecksums++; } if (txDescCache.extsts & EXTSTS_IPPKT) { - ipChecksum(txPacket, true); - txIPChecksums++; + ip->sum(0); + ip->sum(cksum(ip)); + txIpChecksums++; } } @@ -1826,7 +2050,11 @@ NSGigE::txKick() // this is just because the receive can't handle a // packet bigger want to make sure assert(txPacket->length <= 1514); - txFifo.push_back(txPacket); +#ifndef NDEBUG + bool success = +#endif + txFifo.push(txPacket); + assert(success); /* * this following section is not tqo spec, but @@ -1872,7 +2100,7 @@ NSGigE::txKick() } } else { DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); - if (txFifoAvail) { + if (!txFifo.full()) { txState = txFragRead; /* @@ -1881,7 +2109,7 @@ NSGigE::txKick() * is not enough room in the fifo, just whatever room * is left in the fifo */ - txXferLen = min<uint32_t>(txDescCnt, txFifoAvail); + txXferLen = min<uint32_t>(txDescCnt, txFifo.avail()); txDmaAddr = txFragPtr & 0x3fffffff; txDmaData = txPacketBufPtr; @@ -1907,7 +2135,7 @@ NSGigE::txKick() txPacketBufPtr += txXferLen; txFragPtr += txXferLen; txDescCnt -= txXferLen; - txFifoAvail -= txXferLen; + txFifo.reserve(txXferLen); txState = txFifoBlock; break; @@ -1976,45 +2204,35 @@ NSGigE::transferDone() } bool -NSGigE::rxFilter(PacketPtr packet) +NSGigE::rxFilter(const PacketPtr &packet) { + EthPtr eth = packet; bool drop = true; string type; - if (packet->IsUnicast()) { - type = "unicast"; - + const EthAddr &dst = eth->dst(); + if (dst.unicast()) { // If we're accepting all unicast addresses if (acceptUnicast) drop = false; // If we make a perfect match - if (acceptPerfect && - memcmp(rom.perfectMatch, packet->data, EADDR_LEN) == 0) + if (acceptPerfect && dst == rom.perfectMatch) drop = false; - eth_header *eth = (eth_header *) packet->data; - if ((acceptArp) && (eth->type == 0x608)) + if (acceptArp && eth->type() == ETH_TYPE_ARP) drop = false; - } else if (packet->IsBroadcast()) { - type = "broadcast"; - + } else if (dst.broadcast()) { // if we're accepting broadcasts if (acceptBroadcast) drop = false; - } else if (packet->IsMulticast()) { - type = "multicast"; - + } else if (dst.multicast()) { // if we're accepting all multicasts if (acceptMulticast) drop = false; - } else { - type = "unknown"; - - // oh well, punt on this one } if (drop) { @@ -2032,7 +2250,7 @@ NSGigE::recvPacket(PacketPtr packet) rxPackets++; DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", - maxRxFifoSize - rxFifoCnt); + rxFifo.avail()); if (!rxEnable) { DPRINTF(Ethernet, "receive disabled...packet dropped\n"); @@ -2047,136 +2265,21 @@ NSGigE::recvPacket(PacketPtr packet) return true; } - if ((rxFifoCnt + packet->length) >= maxRxFifoSize) { + if (rxFifo.avail() < packet->length) { DPRINTF(Ethernet, "packet will not fit in receive buffer...packet dropped\n"); + droppedPackets++; devIntrPost(ISR_RXORN); return false; } - rxFifo.push_back(packet); - rxFifoCnt += packet->length; + rxFifo.push(packet); interface->recvDone(); rxKick(); return true; } -/** - * does a udp checksum. if gen is true, then it generates it and puts - * it in the right place else, it just checks what it calculates - * against the value in the header in packet - */ -bool -NSGigE::udpChecksum(PacketPtr packet, bool gen) -{ - ip_header *ip = packet->getIpHdr(); - udp_header *hdr = packet->getUdpHdr(ip); - - pseudo_header *pseudo = new pseudo_header; - - pseudo->src_ip_addr = ip->src_ip_addr; - pseudo->dest_ip_addr = ip->dest_ip_addr; - pseudo->protocol = ip->protocol; - pseudo->len = hdr->len; - - uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, - (uint32_t) hdr->len); - - delete pseudo; - if (gen) - hdr->chksum = cksum; - else - if (cksum != 0) - return false; - - return true; -} - -bool -NSGigE::tcpChecksum(PacketPtr packet, bool gen) -{ - ip_header *ip = packet->getIpHdr(); - tcp_header *hdr = packet->getTcpHdr(ip); - - uint16_t cksum; - pseudo_header *pseudo = new pseudo_header; - if (!gen) { - pseudo->src_ip_addr = ip->src_ip_addr; - pseudo->dest_ip_addr = ip->dest_ip_addr; - pseudo->protocol = reverseEnd16(ip->protocol); - pseudo->len = reverseEnd16(reverseEnd16(ip->dgram_len) - - (ip->vers_len & 0xf)*4); - - cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, - (uint32_t) reverseEnd16(pseudo->len)); - } else { - pseudo->src_ip_addr = 0; - pseudo->dest_ip_addr = 0; - pseudo->protocol = hdr->chksum; - pseudo->len = 0; - hdr->chksum = 0; - cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, - (uint32_t) (reverseEnd16(ip->dgram_len) - - (ip->vers_len & 0xf)*4)); - } - - delete pseudo; - if (gen) - hdr->chksum = cksum; - else - if (cksum != 0) - return false; - - return true; -} - -bool -NSGigE::ipChecksum(PacketPtr packet, bool gen) -{ - ip_header *hdr = packet->getIpHdr(); - - uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, - (hdr->vers_len & 0xf)*4); - - if (gen) { - DPRINTF(EthernetCksum, "generated checksum: %#x\n", cksum); - hdr->hdr_chksum = cksum; - } - else - if (cksum != 0) - return false; - - return true; -} - -uint16_t -NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len) -{ - uint32_t sum = 0; - - uint16_t last_pad = 0; - if (len & 1) { - last_pad = buf[len/2] & 0xff; - len--; - sum += last_pad; - } - - if (pseudo) { - sum = pseudo[0] + pseudo[1] + pseudo[2] + - pseudo[3] + pseudo[4] + pseudo[5]; - } - - for (int i=0; i < (len/2); ++i) { - sum += buf[i]; - } - - while (sum >> 16) - sum = (sum >> 16) + (sum & 0xffff); - - return ~sum; -} - //===================================================================== // // @@ -2234,30 +2337,15 @@ NSGigE::serialize(ostream &os) SERIALIZE_SCALAR(regs.taner); SERIALIZE_SCALAR(regs.tesr); - SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); + SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); SERIALIZE_SCALAR(ioEnable); /* * Serialize the data Fifos */ - int txNumPkts = txFifo.size(); - SERIALIZE_SCALAR(txNumPkts); - int i = 0; - pktiter_t end = txFifo.end(); - for (pktiter_t p = txFifo.begin(); p != end; ++p) { - nameOut(os, csprintf("%s.txFifo%d", name(), i++)); - (*p)->serialize(os); - } - - int rxNumPkts = rxFifo.size(); - SERIALIZE_SCALAR(rxNumPkts); - i = 0; - end = rxFifo.end(); - for (pktiter_t p = rxFifo.begin(); p != end; ++p) { - nameOut(os, csprintf("%s.rxFifo%d", name(), i++)); - (*p)->serialize(os); - } + rxFifo.serialize("rxFifo", os); + txFifo.serialize("txFifo", os); /* * Serialize the various helper variables @@ -2265,8 +2353,7 @@ NSGigE::serialize(ostream &os) bool txPacketExists = txPacket; SERIALIZE_SCALAR(txPacketExists); if (txPacketExists) { - nameOut(os, csprintf("%s.txPacket", name())); - txPacket->serialize(os); + txPacket->serialize("txPacket", os); uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); SERIALIZE_SCALAR(txPktBufPtr); } @@ -2274,8 +2361,7 @@ NSGigE::serialize(ostream &os) bool rxPacketExists = rxPacket; SERIALIZE_SCALAR(rxPacketExists); if (rxPacketExists) { - nameOut(os, csprintf("%s.rxPacket", name())); - rxPacket->serialize(os); + rxPacket->serialize("rxPacket", os); uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); SERIALIZE_SCALAR(rxPktBufPtr); } @@ -2302,7 +2388,6 @@ NSGigE::serialize(ostream &os) SERIALIZE_SCALAR(txState); SERIALIZE_SCALAR(txEnable); SERIALIZE_SCALAR(CTDD); - SERIALIZE_SCALAR(txFifoAvail); SERIALIZE_SCALAR(txFragPtr); SERIALIZE_SCALAR(txDescCnt); int txDmaState = this->txDmaState; @@ -2316,7 +2401,7 @@ NSGigE::serialize(ostream &os) SERIALIZE_SCALAR(rxEnable); SERIALIZE_SCALAR(CRDD); SERIALIZE_SCALAR(rxPktBytes); - SERIALIZE_SCALAR(rxFifoCnt); + SERIALIZE_SCALAR(rxFragPtr); SERIALIZE_SCALAR(rxDescCnt); int rxDmaState = this->rxDmaState; SERIALIZE_SCALAR(rxDmaState); @@ -2391,29 +2476,15 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(regs.taner); UNSERIALIZE_SCALAR(regs.tesr); - UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); + UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); UNSERIALIZE_SCALAR(ioEnable); /* * unserialize the data fifos */ - int txNumPkts; - UNSERIALIZE_SCALAR(txNumPkts); - int i; - for (i = 0; i < txNumPkts; ++i) { - PacketPtr p = new EtherPacket; - p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); - txFifo.push_back(p); - } - - int rxNumPkts; - UNSERIALIZE_SCALAR(rxNumPkts); - for (i = 0; i < rxNumPkts; ++i) { - PacketPtr p = new EtherPacket; - p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); - rxFifo.push_back(p); - } + rxFifo.unserialize("rxFifo", cp, section); + txFifo.unserialize("txFifo", cp, section); /* * unserialize the various helper variables @@ -2421,8 +2492,8 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) bool txPacketExists; UNSERIALIZE_SCALAR(txPacketExists); if (txPacketExists) { - txPacket = new EtherPacket; - txPacket->unserialize(cp, csprintf("%s.txPacket", section)); + txPacket = new PacketData(16384); + txPacket->unserialize("txPacket", cp, section); uint32_t txPktBufPtr; UNSERIALIZE_SCALAR(txPktBufPtr); txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; @@ -2433,8 +2504,8 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(rxPacketExists); rxPacket = 0; if (rxPacketExists) { - rxPacket = new EtherPacket; - rxPacket->unserialize(cp, csprintf("%s.rxPacket", section)); + rxPacket = new PacketData(16384); + rxPacket->unserialize("rxPacket", cp, section); uint32_t rxPktBufPtr; UNSERIALIZE_SCALAR(rxPktBufPtr); rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; @@ -2464,7 +2535,6 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) this->txState = (TxState) txState; UNSERIALIZE_SCALAR(txEnable); UNSERIALIZE_SCALAR(CTDD); - UNSERIALIZE_SCALAR(txFifoAvail); UNSERIALIZE_SCALAR(txFragPtr); UNSERIALIZE_SCALAR(txDescCnt); int txDmaState; @@ -2480,7 +2550,7 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(rxEnable); UNSERIALIZE_SCALAR(CRDD); UNSERIALIZE_SCALAR(rxPktBytes); - UNSERIALIZE_SCALAR(rxFifoCnt); + UNSERIALIZE_SCALAR(rxFragPtr); UNSERIALIZE_SCALAR(rxDescCnt); int rxDmaState; UNSERIALIZE_SCALAR(rxDmaState); @@ -2522,8 +2592,8 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) * re-add addrRanges to bus bridges */ if (pioInterface) { - pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1); - pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1); + pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); + pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1])); } } @@ -2534,28 +2604,6 @@ NSGigE::cacheAccess(MemReqPtr &req) req->paddr, req->paddr - addr); return curTick + pioLatency; } -//===================================================================== - - -//********** helper functions****************************************** - -uint16_t reverseEnd16(uint16_t num) -{ - uint16_t reverse = (num & 0xff)<<8; - reverse += ((num & 0xff00) >> 8); - return reverse; -} - -uint32_t reverseEnd32(uint32_t num) -{ - uint32_t reverse = (reverseEnd16(num & 0xffff)) << 16; - reverse += reverseEnd16((uint16_t) ((num & 0xffff0000) >> 8)); - return reverse; -} - - - -//===================================================================== BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) @@ -2591,7 +2639,6 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) Param<Tick> tx_delay; Param<Tick> rx_delay; - SimObjectParam<IntrControl *> intr_ctrl; Param<Tick> intr_delay; SimObjectParam<MemoryController *> mmu; SimObjectParam<PhysicalMemory *> physmem; @@ -2609,7 +2656,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) Param<Tick> dma_write_factor; SimObjectParam<PciConfigAll *> configspace; SimObjectParam<PciConfigData *> configdata; - SimObjectParam<Tsunami *> tsunami; + SimObjectParam<Platform *> platform; Param<uint32_t> pci_bus; Param<uint32_t> pci_dev; Param<uint32_t> pci_func; @@ -2622,7 +2669,6 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000), INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000), - INIT_PARAM(intr_ctrl, "Interrupt Controller"), INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0), INIT_PARAM(mmu, "Memory Controller"), INIT_PARAM(physmem, "Physical Memory"), @@ -2641,7 +2687,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0), INIT_PARAM(configspace, "PCI Configspace"), INIT_PARAM(configdata, "PCI Config data"), - INIT_PARAM(tsunami, "Tsunami"), + INIT_PARAM(platform, "Platform"), INIT_PARAM(pci_bus, "PCI bus"), INIT_PARAM(pci_dev, "PCI device number"), INIT_PARAM(pci_func, "PCI function code"), @@ -2653,17 +2699,36 @@ END_INIT_SIM_OBJECT_PARAMS(NSGigE) CREATE_SIM_OBJECT(NSGigE) { - int eaddr[6]; - sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x", - &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]); - - return new NSGigE(getInstanceName(), intr_ctrl, intr_delay, - physmem, tx_delay, rx_delay, mmu, hier, header_bus, - payload_bus, pio_latency, dma_desc_free, dma_data_free, - dma_read_delay, dma_write_delay, dma_read_factor, - dma_write_factor, configspace, configdata, - tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr, - tx_fifo_size, rx_fifo_size); + NSGigE::Params *params = new NSGigE::Params; + + params->name = getInstanceName(); + params->mmu = mmu; + params->configSpace = configspace; + params->configData = configdata; + params->plat = platform; + params->busNum = pci_bus; + params->deviceNum = pci_dev; + params->functionNum = pci_func; + + params->intr_delay = intr_delay; + params->pmem = physmem; + params->tx_delay = tx_delay; + params->rx_delay = rx_delay; + params->hier = hier; + params->header_bus = header_bus; + params->payload_bus = payload_bus; + params->pio_latency = pio_latency; + params->dma_desc_free = dma_desc_free; + params->dma_data_free = dma_data_free; + params->dma_read_delay = dma_read_delay; + params->dma_write_delay = dma_write_delay; + params->dma_read_factor = dma_read_factor; + params->dma_write_factor = dma_write_factor; + params->rx_filter = rx_filter; + params->eaddr = hardware_address; + params->tx_fifo_size = tx_fifo_size; + params->rx_fifo_size = rx_fifo_size; + return new NSGigE(params); } REGISTER_SIM_OBJECT("NSGigE", NSGigE) diff --git a/dev/ns_gige.hh b/dev/ns_gige.hh index 82f640db1..8d6016126 100644 --- a/dev/ns_gige.hh +++ b/dev/ns_gige.hh @@ -31,22 +31,20 @@ * DP83820 ethernet controller */ -#ifndef __NS_GIGE_HH__ -#define __NS_GIGE_HH__ +#ifndef __DEV_NS_GIGE_HH__ +#define __DEV_NS_GIGE_HH__ +#include "base/inet.hh" #include "base/statistics.hh" #include "dev/etherint.hh" #include "dev/etherpkt.hh" #include "dev/io_device.hh" #include "dev/ns_gige_reg.h" #include "dev/pcidev.hh" -#include "dev/tsunami.hh" +#include "dev/pktfifo.hh" #include "mem/bus/bus.hh" #include "sim/eventq.hh" -/** length of ethernet address in bytes */ -#define EADDR_LEN 6 - /** * Ethernet device registers */ @@ -90,7 +88,7 @@ struct dp_rom { * for perfect match memory. * the linux driver doesn't use any other ROM */ - uint8_t perfectMatch[EADDR_LEN]; + uint8_t perfectMatch[ETH_ADDR_LEN]; }; class IntrControl; @@ -141,10 +139,6 @@ class NSGigE : public PciDev }; private: - /** pointer to the chipset */ - Tsunami *tsunami; - - private: Addr addr; static const Addr size = sizeof(dp_regs); @@ -165,10 +159,8 @@ class NSGigE : public PciDev /*** BASIC STRUCTURES FOR TX/RX ***/ /* Data FIFOs */ - pktbuf_t txFifo; - uint32_t maxTxFifoSize; - pktbuf_t rxFifo; - uint32_t maxRxFifoSize; + PacketFifo txFifo; + PacketFifo rxFifo; /** various helper vars */ PacketPtr txPacket; @@ -190,8 +182,6 @@ class NSGigE : public PciDev /** Current Transmit Descriptor Done */ bool CTDD; - /** current amt of free space in txDataFifo in bytes */ - uint32_t txFifoAvail; /** halt the tx state machine after next packet */ bool txHalt; /** ptr to the next byte in the current fragment */ @@ -208,8 +198,6 @@ class NSGigE : public PciDev bool CRDD; /** num of bytes in the current packet being drained from rxDataFifo */ uint32_t rxPktBytes; - /** number of bytes in the rxFifo */ - uint32_t rxFifoCnt; /** halt the rx state machine after current packet */ bool rxHalt; /** ptr to the next byte in current fragment */ @@ -302,7 +290,7 @@ class NSGigE : public PciDev * receive address filter */ bool rxFilterEnable; - bool rxFilter(PacketPtr packet); + bool rxFilter(const PacketPtr &packet); bool acceptBroadcast; bool acceptMulticast; bool acceptUnicast; @@ -329,28 +317,34 @@ class NSGigE : public PciDev typedef EventWrapper<NSGigE, &NSGigE::cpuInterrupt> IntrEvent; friend class IntrEvent; IntrEvent *intrEvent; - - /** - * Hardware checksum support - */ - bool udpChecksum(PacketPtr packet, bool gen); - bool tcpChecksum(PacketPtr packet, bool gen); - bool ipChecksum(PacketPtr packet, bool gen); - uint16_t checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len); - NSGigEInt *interface; public: - NSGigE(const std::string &name, IntrControl *i, Tick intr_delay, - PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay, - MemoryController *mmu, HierParams *hier, Bus *header_bus, - Bus *payload_bus, Tick pio_latency, bool dma_desc_free, - bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay, - Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf, - PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev, - uint32_t func, bool rx_filter, const int eaddr[6], - uint32_t tx_fifo_size, uint32_t rx_fifo_size); + struct Params : public PciDev::Params + { + PhysicalMemory *pmem; + HierParams *hier; + Bus *header_bus; + Bus *payload_bus; + Tick intr_delay; + Tick tx_delay; + Tick rx_delay; + Tick pio_latency; + bool dma_desc_free; + bool dma_data_free; + Tick dma_read_delay; + Tick dma_write_delay; + Tick dma_read_factor; + Tick dma_write_factor; + bool rx_filter; + Net::EthAddr eaddr; + uint32_t tx_fifo_size; + uint32_t rx_fifo_size; + }; + + NSGigE(Params *params); ~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); @@ -377,10 +371,12 @@ class NSGigE : public PciDev Stats::Scalar<> rxBytes; Stats::Scalar<> txPackets; Stats::Scalar<> rxPackets; - Stats::Scalar<> txIPChecksums; - Stats::Scalar<> rxIPChecksums; - Stats::Scalar<> txTCPChecksums; - Stats::Scalar<> rxTCPChecksums; + Stats::Scalar<> txIpChecksums; + Stats::Scalar<> rxIpChecksums; + Stats::Scalar<> txTcpChecksums; + Stats::Scalar<> rxTcpChecksums; + Stats::Scalar<> txUdpChecksums; + Stats::Scalar<> rxUdpChecksums; Stats::Scalar<> descDmaReads; Stats::Scalar<> descDmaWrites; Stats::Scalar<> descDmaRdBytes; @@ -389,6 +385,33 @@ class NSGigE : public PciDev Stats::Formula rxBandwidth; Stats::Formula txPacketRate; Stats::Formula rxPacketRate; + Stats::Scalar<> postedSwi; + Stats::Formula coalescedSwi; + Stats::Scalar<> totalSwi; + Stats::Scalar<> postedRxIdle; + Stats::Formula coalescedRxIdle; + Stats::Scalar<> totalRxIdle; + Stats::Scalar<> postedRxOk; + Stats::Formula coalescedRxOk; + Stats::Scalar<> totalRxOk; + Stats::Scalar<> postedRxDesc; + Stats::Formula coalescedRxDesc; + Stats::Scalar<> totalRxDesc; + Stats::Scalar<> postedTxOk; + Stats::Formula coalescedTxOk; + Stats::Scalar<> totalTxOk; + Stats::Scalar<> postedTxIdle; + Stats::Formula coalescedTxIdle; + Stats::Scalar<> totalTxIdle; + Stats::Scalar<> postedTxDesc; + Stats::Formula coalescedTxDesc; + Stats::Scalar<> totalTxDesc; + Stats::Scalar<> postedRxOrn; + Stats::Formula coalescedRxOrn; + Stats::Scalar<> totalRxOrn; + Stats::Formula coalescedTotal; + Stats::Scalar<> postedInterrupts; + Stats::Scalar<> droppedPackets; public: Tick cacheAccess(MemReqPtr &req); @@ -406,8 +429,8 @@ class NSGigEInt : public EtherInt NSGigEInt(const std::string &name, NSGigE *d) : EtherInt(name), dev(d) { dev->setInterface(this); } - virtual bool recvPacket(PacketPtr &pkt) { return dev->recvPacket(pkt); } + virtual bool recvPacket(PacketPtr pkt) { return dev->recvPacket(pkt); } virtual void sendDone() { dev->transferDone(); } }; -#endif // __NS_GIGE_HH__ +#endif // __DEV_NS_GIGE_HH__ diff --git a/dev/pciconfigall.cc b/dev/pciconfigall.cc index 740a9b4ac..609763e92 100644 --- a/dev/pciconfigall.cc +++ b/dev/pciconfigall.cc @@ -33,10 +33,12 @@ #include <deque> #include <string> #include <vector> +#include <bitset> #include "base/trace.hh" #include "dev/pciconfigall.hh" #include "dev/pcidev.hh" +#include "dev/pcireg.h" #include "mem/bus/bus.hh" #include "mem/bus/pio_interface.hh" #include "mem/bus/pio_interface_impl.hh" @@ -50,12 +52,12 @@ PciConfigAll::PciConfigAll(const string &name, Addr a, MemoryController *mmu, HierParams *hier, Bus *bus, Tick pio_latency) : PioDevice(name), addr(a) { - mmu->add_child(this, Range<Addr>(addr, addr + size)); + mmu->add_child(this, RangeSize(addr, size)); if (bus) { pioInterface = newPioInterface(name, hier, bus, this, &PciConfigAll::cacheAccess); - pioInterface->addAddrRange(addr, addr + size - 1); + pioInterface->addAddrRange(RangeSize(addr, size)); pioLatency = pio_latency * bus->clockRatio; } @@ -65,13 +67,40 @@ PciConfigAll::PciConfigAll(const string &name, Addr a, MemoryController *mmu, devices[x][y] = NULL; } +// If two interrupts share the same line largely bad things will happen. +// Since we don't track how many times an interrupt was set and correspondingly +// cleared two devices on the same interrupt line and assert and deassert each +// others interrupt "line". Interrupts will not work correctly. +void +PciConfigAll::startup() +{ + bitset<256> intLines; + PciDev *tempDev; + uint8_t intline; + + for (int x = 0; x < MAX_PCI_DEV; x++) { + for (int y = 0; y < MAX_PCI_FUNC; y++) { + if (devices[x][y] != NULL) { + tempDev = devices[x][y]; + intline = tempDev->interruptLine(); + if (intLines.test(intline)) + warn("Interrupt line %#X is used multiple times" + "(You probably want to fix this).\n", (uint32_t)intline); + else + intLines.set(intline); + } // devices != NULL + } // PCI_FUNC + } // PCI_DEV + +} + Fault PciConfigAll::read(MemReqPtr &req, uint8_t *data) { DPRINTF(PciConfigAll, "read va=%#x size=%d\n", req->vaddr, req->size); - Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)); + Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); int device = (daddr >> 11) & 0x1F; int func = (daddr >> 8) & 0x7; @@ -115,7 +144,7 @@ PciConfigAll::read(MemReqPtr &req, uint8_t *data) Fault PciConfigAll::write(MemReqPtr &req, const uint8_t *data) { - Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)); + Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); int device = (daddr >> 11) & 0x1F; int func = (daddr >> 8) & 0x7; diff --git a/dev/pciconfigall.hh b/dev/pciconfigall.hh index d6b37b9b1..9cf2cf972 100644 --- a/dev/pciconfigall.hh +++ b/dev/pciconfigall.hh @@ -116,6 +116,12 @@ class PciConfigAll : public PioDevice virtual Fault write(MemReqPtr &req, const uint8_t *data); /** + * Start up function to check if more than one person is using an interrupt line + * and print a warning if such a case exists + */ + virtual void startup(); + + /** * Serialize this object to the given output stream. * @param os The stream to serialize to. */ @@ -134,6 +140,7 @@ class PciConfigAll : public PioDevice * @return Tick when the request is done */ Tick cacheAccess(MemReqPtr &req); + }; #endif // __PCICONFIGALL_HH__ diff --git a/dev/pcidev.cc b/dev/pcidev.cc index 7b13aac80..d156b6a02 100644 --- a/dev/pcidev.cc +++ b/dev/pcidev.cc @@ -50,36 +50,38 @@ using namespace std; -PciDev::PciDev(const string &name, MemoryController *mmu, PciConfigAll *cf, - PciConfigData *cd, uint32_t bus, uint32_t dev, uint32_t func) - : DmaDevice(name), mmu(mmu), configSpace(cf), configData(cd), busNum(bus), - deviceNum(dev), functionNum(func) +PciDev::PciDev(Params *p) + : DmaDevice(p->name), _params(p), plat(p->plat), configData(p->configData) { // copy the config data from the PciConfigData object - if (cd) { - memcpy(config.data, cd->config.data, sizeof(config.data)); - memcpy(BARSize, cd->BARSize, sizeof(BARSize)); - memcpy(BARAddrs, cd->BARAddrs, sizeof(BARAddrs)); + if (configData) { + memcpy(config.data, configData->config.data, sizeof(config.data)); + memcpy(BARSize, configData->BARSize, sizeof(BARSize)); + memcpy(BARAddrs, configData->BARAddrs, sizeof(BARAddrs)); } else panic("NULL pointer to configuration data"); // Setup pointer in config space to point to this entry - if (cf->deviceExists(dev,func)) - panic("Two PCI devices occuping same dev: %#x func: %#x", dev, func); + if (p->configSpace->deviceExists(p->deviceNum, p->functionNum)) + panic("Two PCI devices occuping same dev: %#x func: %#x", + p->deviceNum, p->functionNum); else - cf->registerDevice(dev, func, this); + p->configSpace->registerDevice(p->deviceNum, p->functionNum, this); } void 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", - deviceNum, functionNum, offset, size, + params()->deviceNum, params()->functionNum, offset, size, *(uint32_t*)(config.data + offset)); break; @@ -88,7 +90,7 @@ PciDev::ReadConfig(int offset, int size, uint8_t *data) *(uint16_t*)data = htoa(*(uint16_t*)data); DPRINTF(PCIDEV, "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n", - deviceNum, functionNum, offset, size, + params()->deviceNum, params()->functionNum, offset, size, *(uint16_t*)(config.data + offset)); break; @@ -96,7 +98,7 @@ PciDev::ReadConfig(int offset, int size, uint8_t *data) memcpy((uint8_t*)data, config.data + offset, sizeof(uint8_t)); DPRINTF(PCIDEV, "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n", - deviceNum, functionNum, offset, size, + params()->deviceNum, params()->functionNum, offset, size, (uint16_t)(*(uint8_t*)(config.data + offset))); break; @@ -108,6 +110,9 @@ PciDev::ReadConfig(int offset, int size, uint8_t *data) void PciDev::WriteConfig(int offset, int size, uint32_t data) { + if (offset >= PCI_DEVICE_SPECIFIC) + panic("Device specific PCI config space not implemented!\n"); + uint32_t barnum; union { @@ -119,7 +124,8 @@ PciDev::WriteConfig(int offset, int size, uint32_t data) DPRINTF(PCIDEV, "write device: %#x function: %#x reg: %#x size: %d data: %#x\n", - deviceNum, functionNum, offset, size, word_value); + params()->deviceNum, params()->functionNum, offset, size, + word_value); barnum = (offset - PCI0_BASE_ADDR0) >> 2; @@ -129,7 +135,7 @@ PciDev::WriteConfig(int offset, int size, uint32_t data) case PCI0_INTERRUPT_LINE: case PCI_CACHE_LINE_SIZE: case PCI_LATENCY_TIMER: - *(uint8_t *)&config.data[offset] = byte_value; + *(uint8_t *)&config.data[offset] = htoa(byte_value); break; default: @@ -142,7 +148,7 @@ PciDev::WriteConfig(int offset, int size, uint32_t data) case PCI_COMMAND: case PCI_STATUS: case PCI_CACHE_LINE_SIZE: - *(uint16_t *)&config.data[offset] = half_value; + *(uint16_t *)&config.data[offset] = htoa(half_value); break; default: @@ -166,67 +172,63 @@ PciDev::WriteConfig(int offset, int size, uint32_t data) // to size of memory it needs if (word_value == 0xffffffff) { // This is I/O Space, bottom two bits are read only - if (config.data[offset] & 0x1) { - *(uint32_t *)&config.data[offset] = + if (htoa(config.data[offset]) & 0x1) { + *(uint32_t *)&config.data[offset] = htoa( ~(BARSize[barnum] - 1) | - (config.data[offset] & 0x3); + (htoa(config.data[offset]) & 0x3)); } else { // This is memory space, bottom four bits are read only - *(uint32_t *)&config.data[offset] = + *(uint32_t *)&config.data[offset] = htoa( ~(BARSize[barnum] - 1) | - (config.data[offset] & 0xF); + (htoa(config.data[offset]) & 0xF)); } } else { + MemoryController *mmu = params()->mmu; + // This is I/O Space, bottom two bits are read only - if(config.data[offset] & 0x1) { - *(uint32_t *)&config.data[offset] = (word_value & ~0x3) | - (config.data[offset] & 0x3); + 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]-1; + Addr base_size = BARSize[barnum]; // It's never been set if (BARAddrs[barnum] == 0) mmu->add_child((FunctionalMemory *)this, - Range<Addr>(base_addr, - base_addr + base_size)); + RangeSize(base_addr, base_size)); else mmu->update_child((FunctionalMemory *)this, - Range<Addr>(BARAddrs[barnum], - BARAddrs[barnum] + - base_size), - Range<Addr>(base_addr, - base_addr + - base_size)); + 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] = (word_value & ~0xF) | - (config.data[offset] & 0xF); + *(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]-1; + Addr base_size = BARSize[barnum]; // It's never been set if (BARAddrs[barnum] == 0) mmu->add_child((FunctionalMemory *)this, - Range<Addr>(base_addr, - base_addr + base_size)); + RangeSize(base_addr, base_size)); else mmu->update_child((FunctionalMemory *)this, - Range<Addr>(BARAddrs[barnum], - BARAddrs[barnum] + - base_size), - Range<Addr>(base_addr, - base_addr + - base_size)); + RangeSize(BARAddrs[barnum], + base_size), + RangeSize(base_addr, base_size)); BARAddrs[barnum] = base_addr; } @@ -238,14 +240,14 @@ PciDev::WriteConfig(int offset, int size, uint32_t data) if (word_value == 0xfffffffe) *(uint32_t *)&config.data[offset] = 0xffffffff; else - *(uint32_t *)&config.data[offset] = word_value; + *(uint32_t *)&config.data[offset] = htoa(word_value); 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] = half_value; + *(uint16_t *)&config.data[offset] = htoa(half_value); break; default: @@ -273,10 +275,7 @@ PciDev::unserialize(Checkpoint *cp, const std::string §ion) // Add the MMU mappings for the BARs for (int i=0; i < 6; i++) { if (BARAddrs[i] != 0) - mmu->add_child((FunctionalMemory *)this, - Range<Addr>(BARAddrs[i], - BARAddrs[i] + - BARSize[i] - 1)); + params()->mmu->add_child(this, RangeSize(BARAddrs[i], BARSize[i])); } } diff --git a/dev/pcidev.hh b/dev/pcidev.hh index c0fe47ac4..4b947b560 100644 --- a/dev/pcidev.hh +++ b/dev/pcidev.hh @@ -30,11 +30,12 @@ * Interface for devices using PCI configuration */ -#ifndef __PCI_DEV_HH__ -#define __PCI_DEV_HH__ +#ifndef __DEV_PCIDEV_HH__ +#define __DEV_PCIDEV_HH__ -#include "dev/pcireg.h" #include "dev/io_device.hh" +#include "dev/pcireg.h" +#include "dev/platform.hh" class PciConfigAll; class MemoryController; @@ -78,29 +79,43 @@ class PciConfigData : public SimObject class PciDev : public DmaDevice { protected: - MemoryController *mmu; - /** A pointer to the configspace all object that calls - * us when a read comes to this particular device/function. - */ - PciConfigAll *configSpace; + struct Params; + Params *_params; - /** - * A pointer to the object that contains the first 64 bytes of - * config space - */ - PciConfigData *configData; + public: + struct Params + { + std::string name; + Platform *plat; + MemoryController *mmu; + + /** + * A pointer to the configspace all object that calls us when + * a read comes to this particular device/function. + */ + PciConfigAll *configSpace; + + /** + * A pointer to the object that contains the first 64 bytes of + * config space + */ + PciConfigData *configData; - /** The bus number we are on */ - uint32_t busNum; + /** The bus number we are on */ + uint32_t busNum; - /** The device number we have */ - uint32_t deviceNum; + /** The device number we have */ + uint32_t deviceNum; - /** The function number */ - uint32_t functionNum; + /** The function number */ + uint32_t functionNum; + }; + const Params *params() const { return _params; } - /** The current config space. Unlike the PciConfigData this is updated - * during simulation while continues to refelect what was in the config file. + protected: + /** The current config space. Unlike the PciConfigData this is + * updated during simulation while continues to refelect what was + * in the config file. */ PCIConfig config; @@ -110,21 +125,33 @@ class PciDev : public DmaDevice /** The current address mapping of the BARs */ Addr BARAddrs[6]; + protected: + Platform *plat; + PciConfigData *configData; + + public: + Addr pciToDma(Addr pciAddr) const + { return plat->pciToDma(pciAddr); } + + void + intrPost() + { plat->postPciInt(configData->config.hdr.pci0.interruptLine); } + + void + intrClear() + { plat->clearPciInt(configData->config.hdr.pci0.interruptLine); } + + uint8_t + interruptLine() + { return configData->config.hdr.pci0.interruptLine; } + public: /** - * Constructor for PCI Dev. This function copies data from the config file - * object PCIConfigData and registers the device with a PciConfigAll object. - * @param name name of the object - * @param mmu a pointer to the memory controller - * @param cf a pointer to the config space object that this device need to - * register with - * @param cd A pointer to the config space values specified in the conig file - * @param bus the bus this device is on - * @param dev the device id of this device - * @param func the function number of this device + * Constructor for PCI Dev. This function copies data from the + * config file object PCIConfigData and registers the device with + * a PciConfigAll object. */ - PciDev(const std::string &name, MemoryController *mmu, PciConfigAll *cf, - PciConfigData *cd, uint32_t bus, uint32_t dev, uint32_t func); + PciDev(Params *params); virtual Fault read(MemReqPtr &req, uint8_t *data) { return No_Fault; @@ -168,4 +195,4 @@ class PciDev : public DmaDevice virtual void unserialize(Checkpoint *cp, const std::string §ion); }; -#endif // __PCI_DEV_HH__ +#endif // __DEV_PCIDEV_HH__ diff --git a/dev/pktfifo.cc b/dev/pktfifo.cc new file mode 100644 index 000000000..ae82123cf --- /dev/null +++ b/dev/pktfifo.cc @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2002-2004 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. + */ + +#include "base/misc.hh" +#include "dev/pktfifo.hh" + +using namespace std; + +void +PacketFifo::serialize(const string &base, ostream &os) +{ + paramOut(os, base + ".size", _size); + paramOut(os, base + ".maxsize", _maxsize); + paramOut(os, base + ".reserved", _reserved); + paramOut(os, base + ".packets", fifo.size()); + + int i = 0; + std::list<PacketPtr>::iterator p = fifo.begin(); + std::list<PacketPtr>::iterator end = fifo.end(); + while (p != end) { + (*p)->serialize(csprintf("%s.packet%d", base, i), os); + ++p; + ++i; + } +} + +void +PacketFifo::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + paramIn(cp, section, base + ".size", _size); + paramIn(cp, section, base + ".maxsize", _maxsize); + paramIn(cp, section, base + ".reserved", _reserved); + int fifosize; + paramIn(cp, section, base + ".packets", fifosize); + + fifo.clear(); + fifo.resize(fifosize); + + for (int i = 0; i < fifosize; ++i) { + PacketPtr p = new PacketData(16384); + p->unserialize(csprintf("%s.packet%d", base, i), cp, section); + fifo.push_back(p); + } +} diff --git a/dev/pktfifo.hh b/dev/pktfifo.hh new file mode 100644 index 000000000..0c237949c --- /dev/null +++ b/dev/pktfifo.hh @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2002-2004 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. + */ + +#ifndef __DEV_PKTFIFO_HH__ +#define __DEV_PKTFIFO_HH__ + +#include <iosfwd> +#include <list> +#include <string> + +#include "dev/etherpkt.hh" +#include "sim/serialize.hh" + +class Checkpoint; +class PacketFifo +{ + protected: + std::list<PacketPtr> fifo; + int _maxsize; + int _size; + int _reserved; + + public: + explicit PacketFifo(int max) : _maxsize(max), _size(0), _reserved(0) {} + virtual ~PacketFifo() {} + + int packets() const { return fifo.size(); } + int maxsize() const { return _maxsize; } + int size() const { return _size; } + int reserved() const { return _reserved; } + int avail() const { return _maxsize - _size - _reserved; } + bool empty() const { return size() <= 0; } + bool full() const { return avail() <= 0; } + + int reserve(int len = 0) + { + _reserved += len; + assert(avail() >= 0); + return _reserved; + } + + bool push(PacketPtr ptr) + { + assert(_reserved <= ptr->length); + if (avail() < ptr->length - _reserved) + return false; + + _size += ptr->length; + fifo.push_back(ptr); + _reserved = 0; + return true; + } + + PacketPtr front() { return fifo.front(); } + + void pop() + { + if (empty()) + return; + + _size -= fifo.front()->length; + fifo.front() = NULL; + fifo.pop_front(); + } + + void clear() + { + fifo.clear(); + _size = 0; + _reserved = 0; + } + +/** + * Serialization stuff + */ + public: + void serialize(const std::string &base, std::ostream &os); + void unserialize(const std::string &base, + Checkpoint *cp, const std::string §ion); +}; + +#endif // __DEV_PKTFIFO_HH__ diff --git a/dev/platform.cc b/dev/platform.cc index 8515d543a..cf012352b 100644 --- a/dev/platform.cc +++ b/dev/platform.cc @@ -32,5 +32,23 @@ using namespace std; +void +Platform::postPciInt(int line) +{ + panic("No PCI interrupt support in platform."); +} + +void +Platform::clearPciInt(int line) +{ + panic("No PCI interrupt support in platform."); +} + +Addr +Platform::pciToDma(Addr pciAddr) const +{ + panic("No PCI dma support in platform."); +} + DEFINE_SIM_OBJECT_CLASS_NAME("Platform", Platform) diff --git a/dev/platform.hh b/dev/platform.hh index 7920480bc..717e49411 100644 --- a/dev/platform.hh +++ b/dev/platform.hh @@ -35,6 +35,7 @@ #define __PLATFORM_HH_ #include "sim/sim_object.hh" +#include "targetarch/isa_traits.hh" class PciConfigAll; class IntrControl; @@ -65,6 +66,9 @@ class Platform : public SimObject virtual void postConsoleInt() = 0; virtual void clearConsoleInt() = 0; virtual Tick intrFrequency() = 0; + virtual void postPciInt(int line); + virtual void clearPciInt(int line); + virtual Addr pciToDma(Addr pciAddr) const; }; #endif // __PLATFORM_HH_ diff --git a/dev/simconsole.cc b/dev/simconsole.cc index a15057402..d8d890e15 100644 --- a/dev/simconsole.cc +++ b/dev/simconsole.cc @@ -45,12 +45,11 @@ #include "base/misc.hh" #include "base/socket.hh" #include "base/trace.hh" +#include "dev/platform.hh" #include "dev/simconsole.hh" +#include "dev/uart.hh" #include "mem/functional_mem/memory_control.hh" #include "sim/builder.hh" -#include "targetarch/ev5.hh" -#include "dev/uart.hh" -#include "dev/platform.hh" using namespace std; @@ -72,27 +71,22 @@ SimConsole::Event::process(int revent) cons->detach(); } -SimConsole::SimConsole(const string &name, const string &file, int num) +SimConsole::SimConsole(const string &name, std::ostream *os, int num) : SimObject(name), event(NULL), number(num), in_fd(-1), out_fd(-1), - listener(NULL), txbuf(16384), rxbuf(16384), outfile(NULL) + listener(NULL), txbuf(16384), rxbuf(16384), outfile(os) #if TRACING_ON == 1 , linebuf(16384) #endif { - if (!file.empty()) - outfile = new ofstream(file.c_str()); - if (outfile) outfile->setf(ios::unitbuf); - } SimConsole::~SimConsole() { close(); - if (outfile) - delete outfile; + closeOutputStream(outfile); } void @@ -311,7 +305,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(SimConsole) INIT_PARAM(listener, "console listener"), INIT_PARAM(intr_control, "interrupt controller"), - INIT_PARAM_DFLT(output, "file to dump output to", ""), + INIT_PARAM(output, "file to dump output to"), INIT_PARAM_DFLT(append_name, "append name() to filename", true), INIT_PARAM_DFLT(number, "console number", 0) @@ -319,18 +313,18 @@ END_INIT_SIM_OBJECT_PARAMS(SimConsole) CREATE_SIM_OBJECT(SimConsole) { - string filename = output; - if (filename.empty()) { - if (!outputDirectory.empty()) - filename = outputDirectory + getInstanceName(); + string filename; + + if (!output.isValid()) { + filename = getInstanceName(); + } else if (append_name) { + filename = (string)output + "." + getInstanceName(); } else { - if (append_name) - filename += "." + getInstanceName(); - if (!outputDirectory.empty()) - filename = outputDirectory + filename; + filename = output; } - SimConsole *console = new SimConsole(getInstanceName(), filename, number); + SimConsole *console = new SimConsole(getInstanceName(), + makeOutputStream(filename), number); ((ConsoleListener *)listener)->add(console); return console; diff --git a/dev/simconsole.hh b/dev/simconsole.hh index 138e2e36a..c5a281834 100644 --- a/dev/simconsole.hh +++ b/dev/simconsole.hh @@ -70,7 +70,7 @@ class SimConsole : public SimObject ConsoleListener *listener; public: - SimConsole(const std::string &name, const std::string &file, int num); + SimConsole(const std::string &name, std::ostream *os, int num); ~SimConsole(); protected: diff --git a/dev/sinic.cc b/dev/sinic.cc new file mode 100644 index 000000000..56782b589 --- /dev/null +++ b/dev/sinic.cc @@ -0,0 +1,1433 @@ +/* + * Copyright (c) 2004 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. + */ + +#include <cstdio> +#include <deque> +#include <string> + +#include "base/inet.hh" +#include "cpu/exec_context.hh" +#include "cpu/intr_control.hh" +#include "dev/dma.hh" +#include "dev/etherlink.hh" +#include "dev/sinic.hh" +#include "dev/pciconfigall.hh" +#include "mem/bus/bus.hh" +#include "mem/bus/dma_interface.hh" +#include "mem/bus/pio_interface.hh" +#include "mem/bus/pio_interface_impl.hh" +#include "mem/functional_mem/memory_control.hh" +#include "mem/functional_mem/physical_memory.hh" +#include "sim/builder.hh" +#include "sim/debug.hh" +#include "sim/eventq.hh" +#include "sim/host.hh" +#include "sim/stats.hh" +#include "targetarch/vtophys.hh" + +using namespace Net; + +namespace Sinic { + +const char *RxStateStrings[] = +{ + "rxIdle", + "rxFifoBlock", + "rxBeginCopy", + "rxCopy", + "rxCopyDone" +}; + +const char *TxStateStrings[] = +{ + "txIdle", + "txFifoBlock", + "txBeginCopy", + "txCopy", + "txCopyDone" +}; + + +/////////////////////////////////////////////////////////////////////// +// +// Sinic PCI Device +// +Base::Base(Params *p) + : PciDev(p), rxEnable(false), txEnable(false), + intrDelay(US2Ticks(p->intr_delay)), + intrTick(0), cpuIntrEnable(false), cpuPendingIntr(false), intrEvent(0), + interface(NULL) +{ +} + +Device::Device(Params *p) + : Base(p), plat(p->plat), physmem(p->physmem), + rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), + rxKickTick(0), txKickTick(0), + txEvent(this), rxDmaEvent(this), txDmaEvent(this), + dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor), + dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor) +{ + reset(); + + if (p->header_bus) { + pioInterface = newPioInterface(p->name, p->hier, p->header_bus, this, + &Device::cacheAccess); + + pioLatency = p->pio_latency * p->header_bus->clockRatio; + + if (p->payload_bus) + dmaInterface = new DMAInterface<Bus>(p->name + ".dma", + p->header_bus, p->payload_bus, + 1); + else + dmaInterface = new DMAInterface<Bus>(p->name + ".dma", + p->header_bus, p->header_bus, + 1); + } else if (p->payload_bus) { + pioInterface = newPioInterface(p->name, p->hier, p->payload_bus, this, + &Device::cacheAccess); + + pioLatency = p->pio_latency * p->payload_bus->clockRatio; + + dmaInterface = new DMAInterface<Bus>(p->name + ".dma", p->payload_bus, + p->payload_bus, 1); + } +} + +Device::~Device() +{} + +void +Device::regStats() +{ + rxBytes + .name(name() + ".rxBytes") + .desc("Bytes Received") + .prereq(rxBytes) + ; + + rxBandwidth + .name(name() + ".rxBandwidth") + .desc("Receive Bandwidth (bits/s)") + .precision(0) + .prereq(rxBytes) + ; + + rxPackets + .name(name() + ".rxPackets") + .desc("Number of Packets Received") + .prereq(rxBytes) + ; + + rxPacketRate + .name(name() + ".rxPPS") + .desc("Packet Reception Rate (packets/s)") + .precision(0) + .prereq(rxBytes) + ; + + rxIpPackets + .name(name() + ".rxIpPackets") + .desc("Number of IP Packets Received") + .prereq(rxBytes) + ; + + rxTcpPackets + .name(name() + ".rxTcpPackets") + .desc("Number of Packets Received") + .prereq(rxBytes) + ; + + rxUdpPackets + .name(name() + ".rxUdpPackets") + .desc("Number of UDP Packets Received") + .prereq(rxBytes) + ; + + rxIpChecksums + .name(name() + ".rxIpChecksums") + .desc("Number of rx IP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + rxTcpChecksums + .name(name() + ".rxTcpChecksums") + .desc("Number of rx TCP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + rxUdpChecksums + .name(name() + ".rxUdpChecksums") + .desc("Number of rx UDP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + txBytes + .name(name() + ".txBytes") + .desc("Bytes Transmitted") + .prereq(txBytes) + ; + + txBandwidth + .name(name() + ".txBandwidth") + .desc("Transmit Bandwidth (bits/s)") + .precision(0) + .prereq(txBytes) + ; + + txPackets + .name(name() + ".txPackets") + .desc("Number of Packets Transmitted") + .prereq(txBytes) + ; + + txPacketRate + .name(name() + ".txPPS") + .desc("Packet Tranmission Rate (packets/s)") + .precision(0) + .prereq(txBytes) + ; + + txIpPackets + .name(name() + ".txIpPackets") + .desc("Number of IP Packets Transmitted") + .prereq(txBytes) + ; + + txTcpPackets + .name(name() + ".txTcpPackets") + .desc("Number of TCP Packets Transmitted") + .prereq(txBytes) + ; + + txUdpPackets + .name(name() + ".txUdpPackets") + .desc("Number of Packets Transmitted") + .prereq(txBytes) + ; + + txIpChecksums + .name(name() + ".txIpChecksums") + .desc("Number of tx IP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + txTcpChecksums + .name(name() + ".txTcpChecksums") + .desc("Number of tx TCP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + txUdpChecksums + .name(name() + ".txUdpChecksums") + .desc("Number of tx UDP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + txBandwidth = txBytes * Stats::constant(8) / simSeconds; + rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; + txPacketRate = txPackets / simSeconds; + rxPacketRate = rxPackets / simSeconds; +} + +/** + * This is to write to the PCI general configuration registers + */ +void +Device::WriteConfig(int offset, int size, uint32_t data) +{ + switch (offset) { + case PCI0_BASE_ADDR0: + // Need to catch writes to BARs to update the PIO interface + PciDev::WriteConfig(offset, size, data); + if (BARAddrs[0] != 0) { + if (pioInterface) + pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); + + BARAddrs[0] &= EV5::PAddrUncachedMask; + } + break; + + default: + PciDev::WriteConfig(offset, size, data); + } +} + +/** + * This reads the device registers, which are detailed in the NS83820 + * spec sheet + */ +Fault +Device::read(MemReqPtr &req, uint8_t *data) +{ + assert(config.hdr.command & PCI_CMD_MSE); + + //The mask is to give you only the offset into the device register file + Addr daddr = req->paddr & 0xfff; + + if (Regs::regSize(daddr) == 0) + panic("invalid address: da=%#x pa=%#x va=%#x size=%d", + daddr, req->paddr, req->vaddr, req->size); + + if (req->size != Regs::regSize(daddr)) + panic("invalid size for reg %s: da=%#x pa=%#x va=%#x size=%d", + Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size); + + DPRINTF(EthernetPIO, "read reg=%s da=%#x pa=%#x va=%#x size=%d\n", + Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size); + + uint32_t ®32 = *(uint32_t *)data; + uint64_t ®64 = *(uint64_t *)data; + + switch (daddr) { + case Regs::Config: + reg32 = regs.Config; + break; + + case Regs::RxMaxCopy: + reg32 = regs.RxMaxCopy; + break; + + case Regs::TxMaxCopy: + reg32 = regs.TxMaxCopy; + break; + + case Regs::RxThreshold: + reg32 = regs.RxThreshold; + break; + + case Regs::TxThreshold: + reg32 = regs.TxThreshold; + break; + + case Regs::IntrStatus: + reg32 = regs.IntrStatus; + devIntrClear(); + break; + + case Regs::IntrMask: + reg32 = regs.IntrMask; + break; + + case Regs::RxData: + reg64 = regs.RxData; + break; + + case Regs::RxDone: + case Regs::RxWait: + reg64 = Regs::set_RxDone_FifoLen(regs.RxDone, + min(rxFifo.packets(), 255)); + break; + + case Regs::TxData: + reg64 = regs.TxData; + break; + + case Regs::TxDone: + case Regs::TxWait: + reg64 = Regs::set_TxDone_FifoLen(regs.TxDone, + min(txFifo.packets(), 255)); + break; + + case Regs::HwAddr: + reg64 = params()->eaddr; + break; + + default: + panic("reading write only register %s: da=%#x pa=%#x va=%#x size=%d", + Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size); + } + + DPRINTF(EthernetPIO, "read reg=%s done val=%#x\n", Regs::regName(daddr), + Regs::regSize(daddr) == 4 ? reg32 : reg64); + + return No_Fault; +} + +Fault +Device::write(MemReqPtr &req, const uint8_t *data) +{ + assert(config.hdr.command & PCI_CMD_MSE); + Addr daddr = req->paddr & 0xfff; + + if (Regs::regSize(daddr) == 0) + panic("invalid address: da=%#x pa=%#x va=%#x size=%d", + daddr, req->paddr, req->vaddr, req->size); + + if (req->size != Regs::regSize(daddr)) + panic("invalid size: reg=%s da=%#x pa=%#x va=%#x size=%d", + Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size); + + uint32_t reg32 = *(uint32_t *)data; + uint64_t reg64 = *(uint64_t *)data; + + DPRINTF(EthernetPIO, "write reg=%s val=%#x da=%#x pa=%#x va=%#x size=%d\n", + Regs::regName(daddr), Regs::regSize(daddr) == 4 ? reg32 : reg64, + daddr, req->paddr, req->vaddr, req->size); + + + switch (daddr) { + case Regs::Config: + changeConfig(reg32); + break; + + case Regs::RxThreshold: + regs.RxThreshold = reg32; + break; + + case Regs::TxThreshold: + regs.TxThreshold = reg32; + break; + + case Regs::IntrMask: + devIntrChangeMask(reg32); + break; + + case Regs::RxData: + if (rxState != rxIdle) + panic("receive machine busy with another request!"); + + regs.RxDone = 0; + regs.RxData = reg64; + if (rxEnable) { + rxState = rxFifoBlock; + rxKick(); + } + break; + + case Regs::TxData: + if (txState != txIdle) + panic("transmit machine busy with another request!"); + + regs.TxDone = 0; + regs.TxData = reg64; + if (txEnable) { + txState = txFifoBlock; + txKick(); + } + break; + + default: + panic("writing read only register %s: da=%#x pa=%#x va=%#x size=%d", + Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size); + } + + return No_Fault; +} + +void +Device::devIntrPost(uint32_t interrupts) +{ + if ((interrupts & Regs::Intr_Res)) + panic("Cannot set a reserved interrupt"); + + regs.IntrStatus |= interrupts; + + DPRINTF(EthernetIntr, + "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n", + interrupts, regs.IntrStatus, regs.IntrMask); + + if ((regs.IntrStatus & regs.IntrMask)) { + Tick when = curTick; + if ((regs.IntrStatus & regs.IntrMask & Regs::Intr_NoDelay) == 0) + when += intrDelay; + cpuIntrPost(when); + } +} + +void +Device::devIntrClear(uint32_t interrupts) +{ + if ((interrupts & Regs::Intr_Res)) + panic("Cannot clear a reserved interrupt"); + + regs.IntrStatus &= ~interrupts; + + DPRINTF(EthernetIntr, + "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n", + interrupts, regs.IntrStatus, regs.IntrMask); + + if (!(regs.IntrStatus & regs.IntrMask)) + cpuIntrClear(); +} + +void +Device::devIntrChangeMask(uint32_t newmask) +{ + if (regs.IntrMask == newmask) + return; + + regs.IntrMask = newmask; + + DPRINTF(EthernetIntr, + "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n", + regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask); + + if (regs.IntrStatus & regs.IntrMask) + cpuIntrPost(curTick); + else + cpuIntrClear(); +} + +void +Base::cpuIntrPost(Tick when) +{ + // If the interrupt you want to post is later than an interrupt + // already scheduled, just let it post in the coming one and don't + // schedule another. + // HOWEVER, must be sure that the scheduled intrTick is in the + // future (this was formerly the source of a bug) + /** + * @todo this warning should be removed and the intrTick code should + * be fixed. + */ + assert(when >= curTick); + assert(intrTick >= curTick || intrTick == 0); + if (!cpuIntrEnable) { + DPRINTF(EthernetIntr, "interrupts not enabled.\n", + intrTick); + return; + } + + if (when > intrTick && intrTick != 0) { + DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", + intrTick); + return; + } + + intrTick = when; + if (intrTick < curTick) { + debug_break(); + intrTick = curTick; + } + + DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", + intrTick); + + if (intrEvent) + intrEvent->squash(); + intrEvent = new IntrEvent(this, true); + intrEvent->schedule(intrTick); +} + +void +Base::cpuInterrupt() +{ + assert(intrTick == curTick); + + // Whether or not there's a pending interrupt, we don't care about + // it anymore + intrEvent = 0; + intrTick = 0; + + // Don't send an interrupt if there's already one + if (cpuPendingIntr) { + DPRINTF(EthernetIntr, + "would send an interrupt now, but there's already pending\n"); + } else { + // Send interrupt + cpuPendingIntr = true; + + DPRINTF(EthernetIntr, "posting interrupt\n"); + intrPost(); + } +} + +void +Base::cpuIntrClear() +{ + if (!cpuPendingIntr) + return; + + if (intrEvent) { + intrEvent->squash(); + intrEvent = 0; + } + + intrTick = 0; + + cpuPendingIntr = false; + + DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); + intrClear(); +} + +bool +Base::cpuIntrPending() const +{ return cpuPendingIntr; } + +void +Device::changeConfig(uint32_t newconf) +{ + uint32_t changed = regs.Config ^ newconf; + if (!changed) + return; + + regs.Config = newconf; + + if ((changed & Regs::Config_Reset)) { + assert(regs.Config & Regs::Config_Reset); + reset(); + regs.Config &= ~Regs::Config_Reset; + } + + if ((changed & Regs::Config_IntEn)) { + cpuIntrEnable = regs.Config & Regs::Config_IntEn; + if (cpuIntrEnable) { + if (regs.IntrStatus & regs.IntrMask) + cpuIntrPost(curTick); + } else { + cpuIntrClear(); + } + } + + if ((changed & Regs::Config_TxEn)) { + txEnable = regs.Config & Regs::Config_TxEn; + if (txEnable) + txKick(); + } + + if ((changed & Regs::Config_RxEn)) { + rxEnable = regs.Config & Regs::Config_RxEn; + if (rxEnable) + rxKick(); + } +} + +void +Device::reset() +{ + using namespace Regs; + memset(®s, 0, sizeof(regs)); + regs.RxMaxCopy = params()->rx_max_copy; + regs.TxMaxCopy = params()->tx_max_copy; + regs.IntrMask = Intr_TxFifo | Intr_RxFifo | Intr_RxData; + + rxState = rxIdle; + txState = txIdle; + + rxFifo.clear(); + txFifo.clear(); +} + +void +Device::rxDmaCopy() +{ + assert(rxState == rxCopy); + rxState = rxCopyDone; + physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen); + DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", + rxDmaAddr, rxDmaLen); + DDUMP(EthernetDMA, rxDmaData, rxDmaLen); +} + +void +Device::rxDmaDone() +{ + rxDmaCopy(); + rxKick(); +} + +void +Device::rxKick() +{ + DPRINTF(EthernetSM, "receive kick rxState=%s (rxFifo.size=%d)\n", + RxStateStrings[rxState], rxFifo.size()); + + if (rxKickTick > curTick) { + DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", + rxKickTick); + return; + } + + next: + switch (rxState) { + case rxIdle: + if (rxPioRequest) { + pioInterface->respond(rxPioRequest, curTick); + rxPioRequest = 0; + } + goto exit; + + case rxFifoBlock: + if (rxPacket) { + rxState = rxBeginCopy; + break; + } + + if (rxFifo.empty()) { + DPRINTF(EthernetSM, "receive waiting for data. Nothing to do.\n"); + goto exit; + } + + // Grab a new packet from the fifo. + rxPacket = rxFifo.front(); + rxPacketBufPtr = rxPacket->data; + rxPktBytes = rxPacket->length; + assert(rxPktBytes); + + rxDoneData = 0; + /* scope for variables */ { + IpPtr ip(rxPacket); + if (ip) { + rxDoneData |= Regs::RxDone_IpPacket; + rxIpChecksums++; + if (cksum(ip) != 0) { + DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); + rxDoneData |= Regs::RxDone_IpError; + } + TcpPtr tcp(ip); + UdpPtr udp(ip); + if (tcp) { + rxDoneData |= Regs::RxDone_TcpPacket; + rxTcpChecksums++; + if (cksum(tcp) != 0) { + DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); + rxDoneData |= Regs::RxDone_TcpError; + } + } else if (udp) { + rxDoneData |= Regs::RxDone_UdpPacket; + rxUdpChecksums++; + if (cksum(udp) != 0) { + DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); + rxDoneData |= Regs::RxDone_UdpError; + } + } + } + } + rxState = rxBeginCopy; + break; + + case rxBeginCopy: + rxDmaAddr = plat->pciToDma(Regs::get_RxData_Addr(regs.RxData)); + rxDmaLen = min<int>(Regs::get_RxData_Len(regs.RxData), rxPktBytes); + rxDmaData = rxPacketBufPtr; + + if (dmaInterface) { + if (!dmaInterface->busy()) { + dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, + curTick, &rxDmaEvent, true); + rxState = rxCopy; + } + goto exit; + } + + rxState = rxCopy; + if (dmaWriteDelay != 0 || dmaWriteFactor != 0) { + Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; + Tick start = curTick + dmaWriteDelay + factor; + rxDmaEvent.schedule(start); + goto exit; + } + + rxDmaCopy(); + break; + + case rxCopy: + DPRINTF(EthernetSM, "receive machine still copying\n"); + goto exit; + + case rxCopyDone: + regs.RxDone = rxDoneData | rxDmaLen; + + if (rxPktBytes == rxDmaLen) { + rxPacket = NULL; + rxFifo.pop(); + } else { + regs.RxDone |= Regs::RxDone_More; + rxPktBytes -= rxDmaLen; + rxPacketBufPtr += rxDmaLen; + } + + regs.RxDone |= Regs::RxDone_Complete; + devIntrPost(Regs::Intr_RxData); + rxState = rxIdle; + break; + + default: + panic("Invalid rxState!"); + } + + DPRINTF(EthernetSM, "entering next rxState=%s\n", + RxStateStrings[rxState]); + + goto next; + + exit: + /** + * @todo do we want to schedule a future kick? + */ + DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", + RxStateStrings[rxState]); +} + +void +Device::txDmaCopy() +{ + assert(txState == txCopy); + txState = txCopyDone; + physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen); + DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", + txDmaAddr, txDmaLen); + DDUMP(EthernetDMA, txDmaData, txDmaLen); +} + +void +Device::txDmaDone() +{ + txDmaCopy(); + txKick(); +} + +void +Device::transmit() +{ + if (txFifo.empty()) { + DPRINTF(Ethernet, "nothing to transmit\n"); + return; + } + + PacketPtr packet = txFifo.front(); + if (!interface->sendPacket(packet)) { + DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n", + txFifo.avail()); + goto reschedule; + } + + txFifo.pop(); + +#if TRACING_ON + if (DTRACE(Ethernet)) { + IpPtr ip(packet); + if (ip) { + DPRINTF(Ethernet, "ID is %d\n", ip->id()); + TcpPtr tcp(ip); + if (tcp) { + DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n", + tcp->sport(), tcp->dport()); + } + } + } +#endif + + DDUMP(Ethernet, packet->data, packet->length); + txBytes += packet->length; + txPackets++; + + DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n", + txFifo.avail()); + + if (txFifo.size() <= params()->tx_fifo_threshold) + devIntrPost(Regs::Intr_TxFifo); + + devIntrPost(Regs::Intr_TxDone); + + reschedule: + if (!txFifo.empty() && !txEvent.scheduled()) { + DPRINTF(Ethernet, "reschedule transmit\n"); + txEvent.schedule(curTick + 1000); + } +} + +void +Device::txKick() +{ + DPRINTF(EthernetSM, "transmit kick txState=%s (txFifo.size=%d)\n", + TxStateStrings[txState], txFifo.size()); + + if (txKickTick > curTick) { + DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", + txKickTick); + return; + } + + next: + switch (txState) { + case txIdle: + if (txPioRequest) { + pioInterface->respond(txPioRequest, curTick + pioLatency); + txPioRequest = 0; + } + goto exit; + + case txFifoBlock: + if (!txPacket) { + // Grab a new packet from the fifo. + txPacket = new PacketData(16384); + txPacketBufPtr = txPacket->data; + } + + if (txFifo.avail() - txPacket->length < + Regs::get_TxData_Len(regs.TxData)) { + DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n"); + goto exit; + } + + txState = txBeginCopy; + break; + + case txBeginCopy: + txDmaAddr = plat->pciToDma(Regs::get_TxData_Addr(regs.TxData)); + txDmaLen = Regs::get_TxData_Len(regs.TxData); + txDmaData = txPacketBufPtr; + + if (dmaInterface) { + if (!dmaInterface->busy()) { + dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, + curTick, &txDmaEvent, true); + txState = txCopy; + } + + goto exit; + } + + txState = txCopy; + if (dmaReadDelay != 0 || dmaReadFactor != 0) { + Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; + Tick start = curTick + dmaReadDelay + factor; + txDmaEvent.schedule(start); + goto exit; + } + + txDmaCopy(); + break; + + case txCopy: + DPRINTF(EthernetSM, "transmit machine still copying\n"); + goto exit; + + case txCopyDone: + txPacket->length += txDmaLen; + if ((regs.TxData & Regs::TxData_More)) { + txPacketBufPtr += txDmaLen; + } else { + assert(txPacket->length <= txFifo.avail()); + if ((regs.TxData & Regs::TxData_Checksum)) { + IpPtr ip(txPacket); + if (ip) { + TcpPtr tcp(ip); + if (tcp) { + tcp->sum(0); + tcp->sum(cksum(tcp)); + txTcpChecksums++; + } + + UdpPtr udp(ip); + if (udp) { + udp->sum(0); + udp->sum(cksum(udp)); + txUdpChecksums++; + } + + ip->sum(0); + ip->sum(cksum(ip)); + txIpChecksums++; + } + } + txFifo.push(txPacket); + txPacket = 0; + transmit(); + } + + regs.TxDone = txDmaLen | Regs::TxDone_Complete; + devIntrPost(Regs::Intr_TxData); + txState = txIdle; + break; + + default: + panic("Invalid txState!"); + } + + DPRINTF(EthernetSM, "entering next txState=%s\n", + TxStateStrings[txState]); + + goto next; + + exit: + /** + * @todo do we want to schedule a future kick? + */ + DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", + TxStateStrings[txState]); +} + +void +Device::transferDone() +{ + if (txFifo.empty()) { + DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); + return; + } + + DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); + + if (txEvent.scheduled()) + txEvent.reschedule(curTick + 1); + else + txEvent.schedule(curTick + 1); +} + +bool +Device::rxFilter(const PacketPtr &packet) +{ + if (!Regs::get_Config_Filter(regs.Config)) + return false; + + panic("receive filter not implemented\n"); + bool drop = true; + +#if 0 + string type; + + EthHdr *eth = packet->eth(); + if (eth->unicast()) { + // If we're accepting all unicast addresses + if (acceptUnicast) + drop = false; + + // If we make a perfect match + if (acceptPerfect && params->eaddr == eth.dst()) + drop = false; + + if (acceptArp && eth->type() == ETH_TYPE_ARP) + drop = false; + + } else if (eth->broadcast()) { + // if we're accepting broadcasts + if (acceptBroadcast) + drop = false; + + } else if (eth->multicast()) { + // if we're accepting all multicasts + if (acceptMulticast) + drop = false; + + } + + if (drop) { + DPRINTF(Ethernet, "rxFilter drop\n"); + DDUMP(EthernetData, packet->data, packet->length); + } +#endif + return drop; +} + +bool +Device::recvPacket(PacketPtr packet) +{ + rxBytes += packet->length; + rxPackets++; + + DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n", + rxFifo.avail()); + + if (!rxEnable) { + DPRINTF(Ethernet, "receive disabled...packet dropped\n"); + interface->recvDone(); + return true; + } + + if (rxFilter(packet)) { + DPRINTF(Ethernet, "packet filtered...dropped\n"); + interface->recvDone(); + return true; + } + + if (rxFifo.size() >= params()->rx_fifo_threshold) + devIntrPost(Regs::Intr_RxFifo); + + if (!rxFifo.push(packet)) { + DPRINTF(Ethernet, + "packet will not fit in receive buffer...packet dropped\n"); + return false; + } + + interface->recvDone(); + devIntrPost(Regs::Intr_RxDone); + rxKick(); + return true; +} + +//===================================================================== +// +// +void +Base::serialize(ostream &os) +{ + // Serialize the PciDev base class + PciDev::serialize(os); + + SERIALIZE_SCALAR(rxEnable); + SERIALIZE_SCALAR(txEnable); + SERIALIZE_SCALAR(cpuIntrEnable); + + /* + * Keep track of pending interrupt status. + */ + SERIALIZE_SCALAR(intrTick); + SERIALIZE_SCALAR(cpuPendingIntr); + Tick intrEventTick = 0; + if (intrEvent) + intrEventTick = intrEvent->when(); + SERIALIZE_SCALAR(intrEventTick); +} + +void +Base::unserialize(Checkpoint *cp, const std::string §ion) +{ + // Unserialize the PciDev base class + PciDev::unserialize(cp, section); + + UNSERIALIZE_SCALAR(rxEnable); + UNSERIALIZE_SCALAR(txEnable); + UNSERIALIZE_SCALAR(cpuIntrEnable); + + /* + * Keep track of pending interrupt status. + */ + UNSERIALIZE_SCALAR(intrTick); + UNSERIALIZE_SCALAR(cpuPendingIntr); + Tick intrEventTick; + UNSERIALIZE_SCALAR(intrEventTick); + if (intrEventTick) { + intrEvent = new IntrEvent(this, true); + intrEvent->schedule(intrEventTick); + } +} + +void +Device::serialize(ostream &os) +{ + // Serialize the PciDev base class + Base::serialize(os); + + if (rxDmaEvent.scheduled()) + rxDmaCopy(); + + if (txDmaEvent.scheduled()) + txDmaCopy(); + + /* + * Serialize the device registers + */ + SERIALIZE_SCALAR(regs.Config); + SERIALIZE_SCALAR(regs.RxMaxCopy); + SERIALIZE_SCALAR(regs.TxMaxCopy); + SERIALIZE_SCALAR(regs.RxThreshold); + SERIALIZE_SCALAR(regs.TxThreshold); + SERIALIZE_SCALAR(regs.IntrStatus); + SERIALIZE_SCALAR(regs.IntrMask); + SERIALIZE_SCALAR(regs.RxData); + SERIALIZE_SCALAR(regs.RxDone); + SERIALIZE_SCALAR(regs.TxData); + SERIALIZE_SCALAR(regs.TxDone); + + /* + * Serialize rx state machine + */ + int rxState = this->rxState; + SERIALIZE_SCALAR(rxState); + rxFifo.serialize("rxFifo", os); + bool rxPacketExists = rxPacket; + SERIALIZE_SCALAR(rxPacketExists); + if (rxPacketExists) { + rxPacket->serialize("rxPacket", os); + uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); + SERIALIZE_SCALAR(rxPktBufPtr); + SERIALIZE_SCALAR(rxPktBytes); + } + SERIALIZE_SCALAR(rxDoneData); + + /* + * Serialize tx state machine + */ + int txState = this->txState; + SERIALIZE_SCALAR(txState); + txFifo.serialize("txFifo", os); + bool txPacketExists = txPacket; + SERIALIZE_SCALAR(txPacketExists); + if (txPacketExists) { + txPacket->serialize("txPacket", os); + uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); + SERIALIZE_SCALAR(txPktBufPtr); + SERIALIZE_SCALAR(txPktBytes); + } + + /* + * If there's a pending transmit, store the time so we can + * reschedule it later + */ + Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; + SERIALIZE_SCALAR(transmitTick); +} + +void +Device::unserialize(Checkpoint *cp, const std::string §ion) +{ + // Unserialize the PciDev base class + Base::unserialize(cp, section); + + /* + * Unserialize the device registers + */ + UNSERIALIZE_SCALAR(regs.Config); + UNSERIALIZE_SCALAR(regs.RxMaxCopy); + UNSERIALIZE_SCALAR(regs.TxMaxCopy); + UNSERIALIZE_SCALAR(regs.RxThreshold); + UNSERIALIZE_SCALAR(regs.TxThreshold); + UNSERIALIZE_SCALAR(regs.IntrStatus); + UNSERIALIZE_SCALAR(regs.IntrMask); + UNSERIALIZE_SCALAR(regs.RxData); + UNSERIALIZE_SCALAR(regs.RxDone); + UNSERIALIZE_SCALAR(regs.TxData); + UNSERIALIZE_SCALAR(regs.TxDone); + + /* + * Unserialize rx state machine + */ + int rxState; + UNSERIALIZE_SCALAR(rxState); + this->rxState = (RxState) rxState; + rxFifo.unserialize("rxFifo", cp, section); + bool rxPacketExists; + UNSERIALIZE_SCALAR(rxPacketExists); + rxPacket = 0; + if (rxPacketExists) { + rxPacket = new PacketData(16384); + rxPacket->unserialize("rxPacket", cp, section); + uint32_t rxPktBufPtr; + UNSERIALIZE_SCALAR(rxPktBufPtr); + this->rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; + UNSERIALIZE_SCALAR(rxPktBytes); + } + UNSERIALIZE_SCALAR(rxDoneData); + + /* + * Unserialize tx state machine + */ + int txState; + UNSERIALIZE_SCALAR(txState); + this->txState = (TxState) txState; + txFifo.unserialize("txFifo", cp, section); + bool txPacketExists; + UNSERIALIZE_SCALAR(txPacketExists); + txPacket = 0; + if (txPacketExists) { + txPacket = new PacketData(16384); + txPacket->unserialize("txPacket", cp, section); + uint32_t txPktBufPtr; + UNSERIALIZE_SCALAR(txPktBufPtr); + this->txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; + UNSERIALIZE_SCALAR(txPktBytes); + } + + /* + * If there's a pending transmit, reschedule it now + */ + Tick transmitTick; + UNSERIALIZE_SCALAR(transmitTick); + if (transmitTick) + txEvent.schedule(curTick + transmitTick); + + /* + * re-add addrRanges to bus bridges + */ + if (pioInterface) + pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); +} + +Tick +Device::cacheAccess(MemReqPtr &req) +{ + //The mask is to give you only the offset into the device register file + Addr daddr = req->paddr - addr; + + DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n", + req->paddr, daddr); + + Tick when = curTick + pioLatency; + + switch (daddr) { + case Regs::RxDone: + if (rxState != rxIdle) { + rxPioRequest = req; + when = 0; + } + break; + + case Regs::TxDone: + if (txState != txIdle) { + txPioRequest = req; + when = 0; + } + break; + } + + return when; +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Interface) + + SimObjectParam<EtherInt *> peer; + SimObjectParam<Device *> device; + +END_DECLARE_SIM_OBJECT_PARAMS(Interface) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Interface) + + INIT_PARAM_DFLT(peer, "peer interface", NULL), + INIT_PARAM(device, "Ethernet device of this interface") + +END_INIT_SIM_OBJECT_PARAMS(Interface) + +CREATE_SIM_OBJECT(Interface) +{ + Interface *dev_int = new Interface(getInstanceName(), device); + + EtherInt *p = (EtherInt *)peer; + if (p) { + dev_int->setPeer(p); + p->setPeer(dev_int); + } + + return dev_int; +} + +REGISTER_SIM_OBJECT("SinicInt", Interface) + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device) + + Param<Tick> tx_delay; + Param<Tick> rx_delay; + Param<Tick> intr_delay; + SimObjectParam<MemoryController *> mmu; + SimObjectParam<PhysicalMemory *> physmem; + Param<bool> rx_filter; + Param<string> hardware_address; + SimObjectParam<Bus*> header_bus; + SimObjectParam<Bus*> payload_bus; + SimObjectParam<HierParams *> hier; + Param<Tick> pio_latency; + SimObjectParam<PciConfigAll *> configspace; + SimObjectParam<PciConfigData *> configdata; + SimObjectParam<Platform *> platform; + Param<uint32_t> pci_bus; + Param<uint32_t> pci_dev; + Param<uint32_t> pci_func; + Param<uint32_t> rx_max_copy; + Param<uint32_t> tx_max_copy; + Param<uint32_t> rx_fifo_size; + Param<uint32_t> tx_fifo_size; + Param<uint32_t> rx_fifo_threshold; + Param<uint32_t> tx_fifo_threshold; + Param<Tick> dma_read_delay; + Param<Tick> dma_read_factor; + Param<Tick> dma_write_delay; + Param<Tick> dma_write_factor; + +END_DECLARE_SIM_OBJECT_PARAMS(Device) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Device) + + INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000), + INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000), + INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0), + INIT_PARAM(mmu, "Memory Controller"), + INIT_PARAM(physmem, "Physical Memory"), + INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true), + INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address", + "00:99:00:00:00:01"), + INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL), + INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL), + INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), + INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), + INIT_PARAM(configspace, "PCI Configspace"), + INIT_PARAM(configdata, "PCI Config data"), + INIT_PARAM(platform, "Platform"), + INIT_PARAM(pci_bus, "PCI bus"), + INIT_PARAM(pci_dev, "PCI device number"), + INIT_PARAM(pci_func, "PCI function code"), + INIT_PARAM_DFLT(rx_max_copy, "rx max copy", 16*1024), + INIT_PARAM_DFLT(tx_max_copy, "rx max copy", 16*1024), + INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 64*1024), + INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 64*1024), + INIT_PARAM_DFLT(rx_fifo_threshold, "max size in bytes of rxFifo", 48*1024), + INIT_PARAM_DFLT(tx_fifo_threshold, "max size in bytes of txFifo", 16*1024), + INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0), + INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0), + INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0), + INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0) + +END_INIT_SIM_OBJECT_PARAMS(Device) + + +CREATE_SIM_OBJECT(Device) +{ + Device::Params *params = new Device::Params; + params->name = getInstanceName(); + params->intr_delay = intr_delay; + params->physmem = physmem; + params->tx_delay = tx_delay; + params->rx_delay = rx_delay; + params->mmu = mmu; + params->hier = hier; + params->header_bus = header_bus; + params->payload_bus = payload_bus; + params->pio_latency = pio_latency; + params->configSpace = configspace; + params->configData = configdata; + params->plat = platform; + params->busNum = pci_bus; + params->deviceNum = pci_dev; + params->functionNum = pci_func; + params->rx_filter = rx_filter; + params->eaddr = hardware_address; + params->rx_max_copy = rx_max_copy; + params->tx_max_copy = tx_max_copy; + params->rx_fifo_size = rx_fifo_size; + params->tx_fifo_size = tx_fifo_size; + params->rx_fifo_threshold = rx_fifo_threshold; + params->tx_fifo_threshold = tx_fifo_threshold; + params->dma_read_delay = dma_read_delay; + params->dma_read_factor = dma_read_factor; + params->dma_write_delay = dma_write_delay; + params->dma_write_factor = dma_write_factor; + return new Device(params); +} + +REGISTER_SIM_OBJECT("Sinic", Device) + +/* namespace Sinic */ } diff --git a/dev/sinic.hh b/dev/sinic.hh new file mode 100644 index 000000000..ef515ffad --- /dev/null +++ b/dev/sinic.hh @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2004 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. + */ + +#ifndef __DEV_SINIC_HH__ +#define __DEV_SINIC_HH__ + +#include "base/inet.hh" +#include "base/statistics.hh" +#include "dev/etherint.hh" +#include "dev/etherpkt.hh" +#include "dev/io_device.hh" +#include "dev/pcidev.hh" +#include "dev/pktfifo.hh" +#include "dev/sinicreg.hh" +#include "mem/bus/bus.hh" +#include "sim/eventq.hh" + +namespace Sinic { + +class Interface; +class Base : public PciDev +{ + protected: + bool rxEnable; + bool txEnable; + + protected: + Tick intrDelay; + Tick intrTick; + bool cpuIntrEnable; + bool cpuPendingIntr; + void cpuIntrPost(Tick when); + void cpuInterrupt(); + void cpuIntrClear(); + + typedef EventWrapper<Base, &Base::cpuInterrupt> IntrEvent; + friend class IntrEvent; + IntrEvent *intrEvent; + Interface *interface; + + bool cpuIntrPending() const; + void cpuIntrAck() { cpuIntrClear(); } + +/** + * Serialization stuff + */ + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +/** + * Construction/Destruction/Parameters + */ + public: + struct Params : public PciDev::Params + { + Tick intr_delay; + }; + + Base(Params *p); +}; + +class Device : public Base +{ + protected: + Platform *plat; + PhysicalMemory *physmem; + + protected: + /** Receive State Machine States */ + enum RxState { + rxIdle, + rxFifoBlock, + rxBeginCopy, + rxCopy, + rxCopyDone + }; + + /** Transmit State Machine states */ + enum TxState { + txIdle, + txFifoBlock, + txBeginCopy, + txCopy, + txCopyDone + }; + + /** device register file */ + struct { + uint32_t Config; + uint32_t RxMaxCopy; + uint32_t TxMaxCopy; + uint32_t RxThreshold; + uint32_t TxThreshold; + uint32_t IntrStatus; + uint32_t IntrMask; + uint64_t RxData; + uint64_t RxDone; + uint64_t TxData; + uint64_t TxDone; + } regs; + + private: + Addr addr; + static const Addr size = Regs::Size; + + protected: + RxState rxState; + PacketFifo rxFifo; + PacketPtr rxPacket; + uint8_t *rxPacketBufPtr; + int rxPktBytes; + uint64_t rxDoneData; + Addr rxDmaAddr; + uint8_t *rxDmaData; + int rxDmaLen; + + TxState txState; + PacketFifo txFifo; + PacketPtr txPacket; + uint8_t *txPacketBufPtr; + int txPktBytes; + Addr txDmaAddr; + uint8_t *txDmaData; + int txDmaLen; + + protected: + void reset(); + + void rxKick(); + Tick rxKickTick; + typedef EventWrapper<Device, &Device::rxKick> RxKickEvent; + friend class RxKickEvent; + + void txKick(); + Tick txKickTick; + typedef EventWrapper<Device, &Device::txKick> TxKickEvent; + friend class TxKickEvent; + + /** + * Retransmit event + */ + void transmit(); + void txEventTransmit() + { + transmit(); + if (txState == txFifoBlock) + txKick(); + } + typedef EventWrapper<Device, &Device::txEventTransmit> TxEvent; + friend class TxEvent; + TxEvent txEvent; + + void txDump() const; + void rxDump() const; + + /** + * receive address filter + */ + bool rxFilter(const PacketPtr &packet); + +/** + * device configuration + */ + void changeConfig(uint32_t newconfig); + +/** + * device ethernet interface + */ + public: + bool recvPacket(PacketPtr packet); + void transferDone(); + void setInterface(Interface *i) { assert(!interface); interface = i; } + +/** + * DMA parameters + */ + protected: + void rxDmaCopy(); + void rxDmaDone(); + friend class EventWrapper<Device, &Device::rxDmaDone>; + EventWrapper<Device, &Device::rxDmaDone> rxDmaEvent; + + void txDmaCopy(); + void txDmaDone(); + friend class EventWrapper<Device, &Device::txDmaDone>; + EventWrapper<Device, &Device::rxDmaDone> txDmaEvent; + + Tick dmaReadDelay; + Tick dmaReadFactor; + Tick dmaWriteDelay; + Tick dmaWriteFactor; + +/** + * PIO parameters + */ + protected: + MemReqPtr rxPioRequest; + MemReqPtr txPioRequest; + +/** + * Interrupt management + */ + protected: + void devIntrPost(uint32_t interrupts); + void devIntrClear(uint32_t interrupts = Regs::Intr_All); + void devIntrChangeMask(uint32_t newmask); + +/** + * PCI Configuration interface + */ + public: + virtual void WriteConfig(int offset, int size, uint32_t data); + +/** + * Memory Interface + */ + public: + virtual Fault read(MemReqPtr &req, uint8_t *data); + virtual Fault write(MemReqPtr &req, const uint8_t *data); + Tick cacheAccess(MemReqPtr &req); + +/** + * Statistics + */ + private: + Stats::Scalar<> rxBytes; + Stats::Formula rxBandwidth; + Stats::Scalar<> rxPackets; + Stats::Formula rxPacketRate; + Stats::Scalar<> rxIpPackets; + Stats::Scalar<> rxTcpPackets; + Stats::Scalar<> rxUdpPackets; + Stats::Scalar<> rxIpChecksums; + Stats::Scalar<> rxTcpChecksums; + Stats::Scalar<> rxUdpChecksums; + + Stats::Scalar<> txBytes; + Stats::Formula txBandwidth; + Stats::Scalar<> txPackets; + Stats::Formula txPacketRate; + Stats::Scalar<> txIpPackets; + Stats::Scalar<> txTcpPackets; + Stats::Scalar<> txUdpPackets; + Stats::Scalar<> txIpChecksums; + Stats::Scalar<> txTcpChecksums; + Stats::Scalar<> txUdpChecksums; + + public: + virtual void regStats(); + +/** + * Serialization stuff + */ + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +/** + * Construction/Destruction/Parameters + */ + public: + struct Params : public Base::Params + { + IntrControl *i; + PhysicalMemory *pmem; + Tick tx_delay; + Tick rx_delay; + HierParams *hier; + Bus *header_bus; + Bus *payload_bus; + Tick pio_latency; + PhysicalMemory *physmem; + IntrControl *intctrl; + bool rx_filter; + Net::EthAddr eaddr; + uint32_t rx_max_copy; + uint32_t tx_max_copy; + uint32_t rx_fifo_size; + uint32_t tx_fifo_size; + uint32_t rx_fifo_threshold; + uint32_t tx_fifo_threshold; + Tick dma_read_delay; + Tick dma_read_factor; + Tick dma_write_delay; + Tick dma_write_factor; + }; + + protected: + const Params *params() const { return (const Params *)_params; } + + public: + Device(Params *params); + ~Device(); +}; + +/* + * Ethernet Interface for an Ethernet Device + */ +class Interface : public EtherInt +{ + private: + Device *dev; + + public: + Interface(const std::string &name, Device *d) + : EtherInt(name), dev(d) { dev->setInterface(this); } + + virtual bool recvPacket(PacketPtr pkt) { return dev->recvPacket(pkt); } + virtual void sendDone() { dev->transferDone(); } +}; + +/* namespace Sinic */ } + +#endif // __DEV_SINIC_HH__ diff --git a/dev/sinicreg.hh b/dev/sinicreg.hh new file mode 100644 index 000000000..9f3412a31 --- /dev/null +++ b/dev/sinicreg.hh @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2004 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. + */ + +#ifndef __DEV_SINICREG_HH__ +#define __DEV_SINICREG_HH__ + +#define __SINIC_REG32(NAME, VAL) static const uint32_t NAME = (VAL) +#define __SINIC_REG64(NAME, VAL) static const uint64_t NAME = (VAL) + +#define __SINIC_VAL32(NAME, OFFSET, WIDTH) \ + static const uint32_t NAME##_width = WIDTH; \ + static const uint32_t NAME##_offset = OFFSET; \ + static const uint32_t NAME##_mask = (1 << WIDTH) - 1; \ + static const uint32_t NAME = ((1 << WIDTH) - 1) << OFFSET; \ + static inline uint32_t get_##NAME(uint32_t reg) \ + { return (reg & NAME) >> OFFSET; } \ + static inline uint32_t set_##NAME(uint32_t reg, uint32_t val) \ + { return (reg & ~NAME) | ((val << OFFSET) & NAME); } + +#define __SINIC_VAL64(NAME, OFFSET, WIDTH) \ + static const uint64_t NAME##_width = WIDTH; \ + static const uint64_t NAME##_offset = OFFSET; \ + static const uint64_t NAME##_mask = (ULL(1) << WIDTH) - 1; \ + static const uint64_t NAME = ((ULL(1) << WIDTH) - 1) << OFFSET; \ + static inline uint64_t get_##NAME(uint64_t reg) \ + { return (reg & NAME) >> OFFSET; } \ + static inline uint64_t set_##NAME(uint64_t reg, uint64_t val) \ + { return (reg & ~NAME) | ((val << OFFSET) & NAME); } + +namespace Sinic { +namespace Regs { + +// Registers +__SINIC_REG32(Config, 0x00); // 32: configuration register +__SINIC_REG32(RxMaxCopy, 0x04); // 32: max rx copy +__SINIC_REG32(TxMaxCopy, 0x08); // 32: max tx copy +__SINIC_REG32(RxThreshold, 0x0c); // 32: receive fifo threshold +__SINIC_REG32(TxThreshold, 0x10); // 32: transmit fifo threshold +__SINIC_REG32(IntrStatus, 0x14); // 32: interrupt status +__SINIC_REG32(IntrMask, 0x18); // 32: interrupt mask +__SINIC_REG32(RxData, 0x20); // 64: receive data +__SINIC_REG32(RxDone, 0x28); // 64: receive done +__SINIC_REG32(RxWait, 0x30); // 64: receive done (busy wait) +__SINIC_REG32(TxData, 0x38); // 64: transmit data +__SINIC_REG32(TxDone, 0x40); // 64: transmit done +__SINIC_REG32(TxWait, 0x48); // 64: transmit done (busy wait) +__SINIC_REG32(HwAddr, 0x50); // 64: mac address +__SINIC_REG32(Size, 0x58); + +// Config register bits +__SINIC_VAL32(Config_Reset, 31, 1); // reset chip +__SINIC_VAL32(Config_Filter, 7, 1); // enable receive filter +__SINIC_VAL32(Config_Vlan, 6, 1); // enable vlan tagging +__SINIC_VAL32(Config_Virtual, 5, 1); // enable virtual addressing +__SINIC_VAL32(Config_Desc, 4, 1); // enable tx/rx descriptors +__SINIC_VAL32(Config_Poll, 3, 1); // enable polling +__SINIC_VAL32(Config_IntEn, 2, 1); // enable interrupts +__SINIC_VAL32(Config_TxEn, 1, 1); // enable transmit +__SINIC_VAL32(Config_RxEn, 0, 1); // enable receive + +// Interrupt register bits +__SINIC_VAL32(Intr_TxFifo, 5, 1); // Fifo oflow/uflow/threshold +__SINIC_VAL32(Intr_TxData, 4, 1); // DMA Completed w/ interrupt +__SINIC_VAL32(Intr_TxDone, 3, 1); // Packet transmitted +__SINIC_VAL32(Intr_RxFifo, 2, 1); // Fifo oflow/uflow/threshold +__SINIC_VAL32(Intr_RxData, 1, 1); // DMA Completed w/ interrupt +__SINIC_VAL32(Intr_RxDone, 0, 1); // Packet received +__SINIC_REG32(Intr_All, 0x3f); +__SINIC_REG32(Intr_NoDelay, 0x24); +__SINIC_REG32(Intr_Res, ~0x3f); + +// RX Data Description +__SINIC_VAL64(RxData_Len, 40, 20); // 0 - 1M +__SINIC_VAL64(RxData_Addr, 0, 40); // Address 1TB + +// TX Data Description +__SINIC_VAL64(TxData_More, 63, 1); +__SINIC_VAL64(TxData_Checksum, 62, 1); +__SINIC_VAL64(TxData_Len, 40, 20); // 0 - 1M +__SINIC_VAL64(TxData_Addr, 0, 40); // Address 1TB + +// RX Done/Busy Information +__SINIC_VAL64(RxDone_Complete, 63, 1); +__SINIC_VAL64(RxDone_IpPacket, 45, 1); +__SINIC_VAL64(RxDone_TcpPacket, 44, 1); +__SINIC_VAL64(RxDone_UdpPacket, 43, 1); +__SINIC_VAL64(RxDone_IpError, 42, 1); +__SINIC_VAL64(RxDone_TcpError, 41, 1); +__SINIC_VAL64(RxDone_UdpError, 40, 1); +__SINIC_VAL64(RxDone_More, 32, 1); +__SINIC_VAL64(RxDone_FifoLen, 20, 8); // up to 255 packets +__SINIC_VAL64(RxDone_CopyLen, 0, 20); // up to 256k + +// TX Done/Busy Information +__SINIC_VAL64(TxDone_Complete, 63, 1); +__SINIC_VAL64(TxDone_FifoLen, 20, 8); // up to 255 packets +__SINIC_VAL64(TxDone_CopyLen, 0, 20); // up to 256k + +inline int +regSize(int offset) +{ + static const char sizes[] = { + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 0, + 8, 0, + 8, 0, + 8, 0, + 8, 0, + 8, 0, + 8, 0, + 8, 0 + }; + + if (offset & 0x3) + return 0; + + if (offset >= Size) + return 0; + + return sizes[offset / 4]; +} + +inline const char * +regName(int offset) +{ + static const char *names[] = { + "Config", + "RxMaxCopy", + "TxMaxCopy", + "RxThreshold", + "TxThreshold", + "IntrStatus", + "IntrMask", + "invalid", + "RxData", "invalid", + "RxDone", "invalid", + "RxWait", "invalid", + "TxData", "invalid", + "TxDone", "invalid", + "TxWait", "invalid", + "HwAddr", "invalid" + }; + + if (offset & 0x3) + return "invalid"; + + if (offset >= Size) + return "invalid"; + + return names[offset / 4]; +} + +/* namespace Regs */ } +/* namespace Sinic */ } + +#endif // __DEV_SINICREG_HH__ diff --git a/dev/tsunami.cc b/dev/tsunami.cc index c44da69b7..f98254354 100644 --- a/dev/tsunami.cc +++ b/dev/tsunami.cc @@ -75,6 +75,24 @@ Tsunami::clearConsoleInt() } void +Tsunami::postPciInt(int line) +{ + cchip->postDRIR(line); +} + +void +Tsunami::clearPciInt(int line) +{ + cchip->clearDRIR(line); +} + +Addr +Tsunami::pciToDma(Addr pciAddr) const +{ + return pchip->translatePciToDma(pciAddr); +} + +void Tsunami::serialize(std::ostream &os) { SERIALIZE_ARRAY(intr_sum_type, Tsunami::Max_CPUs); diff --git a/dev/tsunami.hh b/dev/tsunami.hh index db266d62d..d7c549e90 100644 --- a/dev/tsunami.hh +++ b/dev/tsunami.hh @@ -58,16 +58,13 @@ class Tsunami : public Platform public: /** Max number of CPUs in a Tsunami */ - static const int Max_CPUs = 4; + static const int Max_CPUs = 64; /** Pointer to the system */ System *system; + /** Pointer to the TsunamiIO device which has the RTC */ TsunamiIO *io; - /** Pointer to the disk controller device */ - IdeController *disk_controller; - /** Pointer to the ethernet controller device */ - NSGigE *ethernet; /** Pointer to the Tsunami CChip. * The chip contains some configuration information and @@ -112,6 +109,18 @@ class Tsunami : public Platform virtual void clearConsoleInt(); /** + * Cause the chipset to post a cpi interrupt to the CPU. + */ + virtual void postPciInt(int line); + + /** + * Clear a posted PCI->CPU interrupt + */ + virtual void clearPciInt(int line); + + virtual Addr pciToDma(Addr pciAddr) const; + + /** * Serialize this object to the given output stream. * @param os The stream to serialize to. */ diff --git a/dev/tsunami_cchip.cc b/dev/tsunami_cchip.cc index 870924a2f..a1f900153 100644 --- a/dev/tsunami_cchip.cc +++ b/dev/tsunami_cchip.cc @@ -53,25 +53,24 @@ TsunamiCChip::TsunamiCChip(const string &name, Tsunami *t, Addr a, Tick pio_latency) : PioDevice(name), addr(a), tsunami(t) { - mmu->add_child(this, Range<Addr>(addr, addr + size)); - - for(int i=0; i < Tsunami::Max_CPUs; i++) { - dim[i] = 0; - dir[i] = 0; - dirInterrupting[i] = false; - ipiInterrupting[i] = false; - RTCInterrupting[i] = false; - } + mmu->add_child(this, RangeSize(addr, size)); if (bus) { pioInterface = newPioInterface(name, hier, bus, this, &TsunamiCChip::cacheAccess); - pioInterface->addAddrRange(addr, addr + size - 1); + pioInterface->addAddrRange(RangeSize(addr, size)); pioLatency = pio_latency * bus->clockRatio; } drir = 0; - misc = 0; + ipint = 0; + itint = 0; + + for (int x = 0; x < Tsunami::Max_CPUs; x++) + { + dim[x] = 0; + dir[x] = 0; + } //Put back pointer in tsunami tsunami->cchip = this; @@ -80,16 +79,29 @@ TsunamiCChip::TsunamiCChip(const string &name, Tsunami *t, Addr a, Fault TsunamiCChip::read(MemReqPtr &req, uint8_t *data) { - DPRINTF(Tsunami, "read va=%#x size=%d\n", - req->vaddr, req->size); + DPRINTF(Tsunami, "read va=%#x size=%d\n", req->vaddr, req->size); + + Addr regnum = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; + Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); - Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6; ExecContext *xc = req->xc; switch (req->size) { case sizeof(uint64_t): - switch(daddr) { + if (daddr & TSDEV_CC_BDIMS) + { + *(uint64_t*)data = dim[(daddr >> 4) & 0x3F]; + return No_Fault; + } + + if (daddr & TSDEV_CC_BDIRS) + { + *(uint64_t*)data = dir[(daddr >> 4) & 0x3F]; + return No_Fault; + } + + switch(regnum) { case TSDEV_CC_CSR: *(uint64_t*)data = 0x0; return No_Fault; @@ -97,7 +109,9 @@ TsunamiCChip::read(MemReqPtr &req, uint8_t *data) panic("TSDEV_CC_MTR not implemeted\n"); return No_Fault; case TSDEV_CC_MISC: - *(uint64_t*)data = misc | (xc->cpu_id & 0x3); + *(uint64_t*)data = (ipint << 8) & 0xF | + (itint << 4) & 0xF | + (xc->cpu_id & 0x3); return No_Fault; case TSDEV_CC_AAR0: case TSDEV_CC_AAR1: @@ -147,6 +161,12 @@ TsunamiCChip::read(MemReqPtr &req, uint8_t *data) case TSDEV_CC_MPR3: panic("TSDEV_CC_MPRx not implemented\n"); return No_Fault; + case TSDEV_CC_IPIR: + *(uint64_t*)data = ipint; + return No_Fault; + case TSDEV_CC_ITIR: + *(uint64_t*)data = itint; + return No_Fault; default: panic("default in cchip read reached, accessing 0x%x\n"); } // uint64_t @@ -158,7 +178,7 @@ TsunamiCChip::read(MemReqPtr &req, uint8_t *data) default: panic("invalid access size(?) for tsunami register!\n"); } - DPRINTFN("Tsunami CChip ERROR: read daddr=%#x size=%d\n", daddr, req->size); + DPRINTFN("Tsunami CChip ERROR: read regnum=%#x size=%d\n", regnum, req->size); return No_Fault; } @@ -169,73 +189,95 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) DPRINTF(Tsunami, "write - va=%#x value=%#x size=%d \n", req->vaddr, *(uint64_t*)data, req->size); - Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6; + Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); + Addr regnum = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; bool supportedWrite = false; - uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size(); switch (req->size) { case sizeof(uint64_t): - switch(daddr) { - case TSDEV_CC_CSR: + if (daddr & TSDEV_CC_BDIMS) + { + int number = (daddr >> 4) & 0x3F; + + uint64_t bitvector; + uint64_t olddim; + uint64_t olddir; + + olddim = dim[number]; + olddir = dir[number]; + dim[number] = *(uint64_t*)data; + dir[number] = dim[number] & drir; + for(int x = 0; x < Tsunami::Max_CPUs; x++) + { + bitvector = ULL(1) << x; + // Figure out which bits have changed + if ((dim[number] & bitvector) != (olddim & bitvector)) + { + // The bit is now set and it wasn't before (set) + if((dim[number] & bitvector) && (dir[number] & bitvector)) + { + tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x); + DPRINTF(Tsunami, "dim write resulting in posting dir" + " interrupt to cpu %d\n", number); + } + else if ((olddir & bitvector) && + !(dir[number] & bitvector)) + { + // The bit was set and now its now clear and + // we were interrupting on that bit before + tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x); + DPRINTF(Tsunami, "dim write resulting in clear" + " dir interrupt to cpu %d\n", number); + + } + + + } + } + return No_Fault; + } + + switch(regnum) { + case TSDEV_CC_CSR: panic("TSDEV_CC_CSR write\n"); return No_Fault; case TSDEV_CC_MTR: panic("TSDEV_CC_MTR write not implemented\n"); return No_Fault; case TSDEV_CC_MISC: - //If it is the 4-7th bit, clear the RTC interrupt - uint64_t itintr; - if ((itintr = (*(uint64_t*) data) & (0xf<<4))) { - //Clear the bits in ITINTR - misc &= ~(itintr); - for (int i=0; i < size; i++) { - if ((itintr & (1 << (i+4))) && RTCInterrupting[i]) { - tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0); - RTCInterrupting[i] = false; - DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i); - } - } - supportedWrite = true; - } - //If it is 12th-15th bit, IPI sent to Processor 1 uint64_t ipreq; - if ((ipreq = (*(uint64_t*) data) & (0xf << 12))) { - //Set the bits in IPINTR - misc |= (ipreq >> 4); - for (int i=0; i < size; i++) { - if ((ipreq & (1 << (i + 12)))) { - if (!ipiInterrupting[i]) - tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ3, 0); - ipiInterrupting[i]++; - DPRINTF(IPI, "send cpu=%d pending=%d from=%d\n", i, - ipiInterrupting[i], req->cpu_num); - } - } + ipreq = (*(uint64_t*)data >> 12) & 0xF; + //If it is bit 12-15, this is an IPI post + if (ipreq) { + reqIPI(ipreq); supportedWrite = true; } - //If it is bits 8-11, then clearing IPI's + + //If it is bit 8-11, this is an IPI clear uint64_t ipintr; - if ((ipintr = (*(uint64_t*) data) & (0xf << 8))) { - //Clear the bits in IPINTR - misc &= ~(ipintr); - for (int i=0; i < size; i++) { - if ((ipintr & (1 << (i + 8))) && ipiInterrupting[i]) { - if (!(--ipiInterrupting[i])) - tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ3, 0); - DPRINTF(IPI, "clearing cpu=%d pending=%d from=%d\n", i, - ipiInterrupting[i] + 1, req->cpu_num); - } - } + ipintr = (*(uint64_t*)data >> 8) & 0xF; + if (ipintr) { + clearIPI(ipintr); + supportedWrite = true; + } + + //If it is the 4-7th bit, clear the RTC interrupt + uint64_t itintr; + itintr = (*(uint64_t*)data >> 4) & 0xF; + if (itintr) { + clearITI(itintr); supportedWrite = true; } - // ignore NXMs - if (*(uint64_t*)data & 0x10000000) - supportedWrite = true; + // ignore NXMs + if (*(uint64_t*)data & 0x10000000) + supportedWrite = true; + + if(!supportedWrite) + panic("TSDEV_CC_MISC write not implemented\n"); - if(!supportedWrite) panic("TSDEV_CC_MISC write not implemented\n"); return No_Fault; case TSDEV_CC_AAR0: case TSDEV_CC_AAR1: @@ -248,11 +290,11 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) case TSDEV_CC_DIM2: case TSDEV_CC_DIM3: int number; - if(daddr == TSDEV_CC_DIM0) + if(regnum == TSDEV_CC_DIM0) number = 0; - else if(daddr == TSDEV_CC_DIM1) + else if(regnum == TSDEV_CC_DIM1) number = 1; - else if(daddr == TSDEV_CC_DIM2) + else if(regnum == TSDEV_CC_DIM2) number = 2; else number = 3; @@ -267,7 +309,7 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) dir[number] = dim[number] & drir; for(int x = 0; x < 64; x++) { - bitvector = (uint64_t)1 << x; + bitvector = ULL(1) << x; // Figure out which bits have changed if ((dim[number] & bitvector) != (olddim & bitvector)) { @@ -284,7 +326,8 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) // we were interrupting on that bit before tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x); DPRINTF(Tsunami, "dim write resulting in clear" - "dir interrupt to cpu 0\n"); + " dir interrupt to cpu %d\n", + x); } @@ -311,6 +354,15 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) case TSDEV_CC_MPR2: case TSDEV_CC_MPR3: panic("TSDEV_CC_MPRx write not implemented\n"); + case TSDEV_CC_IPIR: + clearIPI(*(uint64_t*)data); + return No_Fault; + case TSDEV_CC_ITIR: + clearITI(*(uint64_t*)data); + return No_Fault; + case TSDEV_CC_IPIQ: + reqIPI(*(uint64_t*)data); + return No_Fault; default: panic("default in cchip read reached, accessing 0x%x\n"); } @@ -329,14 +381,88 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) } void +TsunamiCChip::clearIPI(uint64_t ipintr) +{ + int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(numcpus <= Tsunami::Max_CPUs); + + if (ipintr) { + for (int cpunum=0; cpunum < numcpus; cpunum++) { + // Check each cpu bit + uint64_t cpumask = ULL(1) << cpunum; + if (ipintr & cpumask) { + // Check if there is a pending ipi + if (ipint & cpumask) { + ipint &= ~cpumask; + tsunami->intrctrl->clear(cpunum, TheISA::INTLEVEL_IRQ3, 0); + DPRINTF(IPI, "clear IPI IPI cpu=%d\n", cpunum); + } + else + warn("clear IPI for CPU=%d, but NO IPI\n", cpunum); + } + } + } + else + panic("Big IPI Clear, but not processors indicated\n"); +} + +void +TsunamiCChip::clearITI(uint64_t itintr) +{ + int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(numcpus <= Tsunami::Max_CPUs); + + if (itintr) { + for (int i=0; i < numcpus; i++) { + uint64_t cpumask = ULL(1) << i; + if (itintr & cpumask & itint) { + tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0); + itint &= ~cpumask; + DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i); + } + } + } + else + panic("Big ITI Clear, but not processors indicated\n"); +} + +void +TsunamiCChip::reqIPI(uint64_t ipreq) +{ + int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(numcpus <= Tsunami::Max_CPUs); + + if (ipreq) { + for (int cpunum=0; cpunum < numcpus; cpunum++) { + // Check each cpu bit + uint64_t cpumask = ULL(1) << cpunum; + if (ipreq & cpumask) { + // Check if there is already an ipi (bits 8:11) + if (!(ipint & cpumask)) { + ipint |= cpumask; + tsunami->intrctrl->post(cpunum, TheISA::INTLEVEL_IRQ3, 0); + DPRINTF(IPI, "send IPI cpu=%d\n", cpunum); + } + else + warn("post IPI for CPU=%d, but IPI already\n", cpunum); + } + } + } + else + panic("Big IPI Request, but not processors indicated\n"); +} + + +void TsunamiCChip::postRTC() { int size = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(size <= Tsunami::Max_CPUs); for (int i = 0; i < size; i++) { - if (!RTCInterrupting[i]) { - misc |= 16 << i; - RTCInterrupting[i] = true; + uint64_t cpumask = ULL(1) << i; + if (!(cpumask & itint)) { + itint |= cpumask; tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ2, 0); DPRINTF(Tsunami, "Posting RTC interrupt to cpu=%d", i); } @@ -347,9 +473,11 @@ TsunamiCChip::postRTC() void TsunamiCChip::postDRIR(uint32_t interrupt) { - uint64_t bitvector = (uint64_t)0x1 << interrupt; - drir |= bitvector; + uint64_t bitvector = ULL(1) << interrupt; uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(size <= Tsunami::Max_CPUs); + drir |= bitvector; + for(int i=0; i < size; i++) { dir[i] = dim[i] & drir; if (dim[i] & bitvector) { @@ -363,8 +491,10 @@ TsunamiCChip::postDRIR(uint32_t interrupt) void TsunamiCChip::clearDRIR(uint32_t interrupt) { - uint64_t bitvector = (uint64_t)0x1 << interrupt; + uint64_t bitvector = ULL(1) << interrupt; uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(size <= Tsunami::Max_CPUs); + if (drir & bitvector) { drir &= ~bitvector; @@ -394,11 +524,9 @@ TsunamiCChip::serialize(std::ostream &os) { SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs); SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs); - SERIALIZE_ARRAY(dirInterrupting, Tsunami::Max_CPUs); - SERIALIZE_ARRAY(ipiInterrupting, Tsunami::Max_CPUs); + SERIALIZE_SCALAR(ipint); + SERIALIZE_SCALAR(itint); SERIALIZE_SCALAR(drir); - SERIALIZE_SCALAR(misc); - SERIALIZE_ARRAY(RTCInterrupting, Tsunami::Max_CPUs); } void @@ -406,11 +534,9 @@ TsunamiCChip::unserialize(Checkpoint *cp, const std::string §ion) { UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs); UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs); - UNSERIALIZE_ARRAY(dirInterrupting, Tsunami::Max_CPUs); - UNSERIALIZE_ARRAY(ipiInterrupting, Tsunami::Max_CPUs); + UNSERIALIZE_SCALAR(ipint); + UNSERIALIZE_SCALAR(itint); UNSERIALIZE_SCALAR(drir); - UNSERIALIZE_SCALAR(misc); - UNSERIALIZE_ARRAY(RTCInterrupting, Tsunami::Max_CPUs); } BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip) diff --git a/dev/tsunami_cchip.hh b/dev/tsunami_cchip.hh index 3269cf53a..05fafa782 100644 --- a/dev/tsunami_cchip.hh +++ b/dev/tsunami_cchip.hh @@ -47,7 +47,7 @@ class TsunamiCChip : public PioDevice Addr addr; /** The size of mappad from the above address */ - static const Addr size = 0xfff; + static const Addr size = 0xfffffff; protected: /** @@ -68,7 +68,6 @@ class TsunamiCChip : public PioDevice * One exists for each CPU, the DRIR X DIM = DIR */ uint64_t dir[Tsunami::Max_CPUs]; - bool dirInterrupting[Tsunami::Max_CPUs]; /** * This register contains bits for each PCI interrupt @@ -76,17 +75,11 @@ class TsunamiCChip : public PioDevice */ uint64_t drir; - /** - * The MISC register contains the CPU we are currently on - * as well as bits to ack RTC and IPI interrupts. - */ - uint64_t misc; + /** Indicator of which CPUs have an IPI interrupt */ + uint64_t ipint; - /** Count of the number of pending IPIs on a CPU */ - uint64_t ipiInterrupting[Tsunami::Max_CPUs]; - - /** Indicator of which CPUs have had an RTC interrupt */ - bool RTCInterrupting[Tsunami::Max_CPUs]; + /** Indicator of which CPUs have an RTC interrupt */ + uint64_t itint; public: /** @@ -138,6 +131,25 @@ class TsunamiCChip : public PioDevice void clearDRIR(uint32_t interrupt); /** + * post an ipi interrupt to the CPU. + * @param ipintr the cpu number to clear(bitvector) + */ + void clearIPI(uint64_t ipintr); + + /** + * clear a timer interrupt previously posted to the CPU. + * @param interrupt the cpu number to clear(bitvector) + */ + void clearITI(uint64_t itintr); + + /** + * request an interrupt be posted to the CPU. + * @param ipreq the cpu number to interrupt(bitvector) + */ + void reqIPI(uint64_t ipreq); + + + /** * Serialize this object to the given output stream. * @param os The stream to serialize to. */ diff --git a/dev/tsunami_io.cc b/dev/tsunami_io.cc index 105e3b5b7..51ff8b81c 100644 --- a/dev/tsunami_io.cc +++ b/dev/tsunami_io.cc @@ -164,12 +164,12 @@ TsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time, Tick pio_latency) : PioDevice(name), addr(a), tsunami(t), rtc(t) { - mmu->add_child(this, Range<Addr>(addr, addr + size)); + mmu->add_child(this, RangeSize(addr, size)); if (bus) { pioInterface = newPioInterface(name, hier, bus, this, &TsunamiIO::cacheAccess); - pioInterface->addAddrRange(addr, addr + size - 1); + pioInterface->addAddrRange(RangeSize(addr, size)); pioLatency = pio_latency * bus->clockRatio; } @@ -196,7 +196,7 @@ TsunamiIO::read(MemReqPtr &req, uint8_t *data) DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", req->vaddr, req->size, req->vaddr & 0xfff); - Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)); + Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); switch(req->size) { @@ -298,7 +298,7 @@ TsunamiIO::write(MemReqPtr &req, const uint8_t *data) DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n", req->vaddr, req->size, req->vaddr & 0xfff, dt64); - Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)); + Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); switch(req->size) { case sizeof(uint8_t): diff --git a/dev/tsunami_pchip.cc b/dev/tsunami_pchip.cc index 89940fb5a..9af19d930 100644 --- a/dev/tsunami_pchip.cc +++ b/dev/tsunami_pchip.cc @@ -53,7 +53,7 @@ TsunamiPChip::TsunamiPChip(const string &name, Tsunami *t, Addr a, Bus *bus, Tick pio_latency) : PioDevice(name), addr(a), tsunami(t) { - mmu->add_child(this, Range<Addr>(addr, addr + size)); + mmu->add_child(this, RangeSize(addr, size)); for (int i = 0; i < 4; i++) { wsba[i] = 0; @@ -64,7 +64,7 @@ TsunamiPChip::TsunamiPChip(const string &name, Tsunami *t, Addr a, if (bus) { pioInterface = newPioInterface(name, hier, bus, this, &TsunamiPChip::cacheAccess); - pioInterface->addAddrRange(addr, addr + size - 1); + pioInterface->addAddrRange(RangeSize(addr, size)); pioLatency = pio_latency * bus->clockRatio; } @@ -82,7 +82,7 @@ TsunamiPChip::read(MemReqPtr &req, uint8_t *data) DPRINTF(Tsunami, "read va=%#x size=%d\n", req->vaddr, req->size); - Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6; + Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; switch (req->size) { @@ -171,7 +171,7 @@ TsunamiPChip::write(MemReqPtr &req, const uint8_t *data) DPRINTF(Tsunami, "write - va=%#x size=%d \n", req->vaddr, req->size); - Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6; + Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; switch (req->size) { diff --git a/dev/tsunamireg.h b/dev/tsunamireg.h index 876c6bf18..3304082a5 100644 --- a/dev/tsunamireg.h +++ b/dev/tsunamireg.h @@ -60,6 +60,13 @@ #define TSDEV_CC_IIC2 0x1C #define TSDEV_CC_IIC3 0x1D +// BigTsunami Registers +#define TSDEV_CC_BDIMS 0x1000000 +#define TSDEV_CC_BDIRS 0x2000000 +#define TSDEV_CC_IPIQ 0x20 //0xf01a000800 +#define TSDEV_CC_IPIR 0x21 //0xf01a000840 +#define TSDEV_CC_ITIR 0x22 //0xf01a000880 + // PChip Registers #define TSDEV_PC_WSBA0 0x00 diff --git a/dev/uart.cc b/dev/uart.cc index fca856d5d..2ff94dda5 100644 --- a/dev/uart.cc +++ b/dev/uart.cc @@ -44,7 +44,6 @@ #include "mem/bus/pio_interface_impl.hh" #include "mem/functional_mem/memory_control.hh" #include "sim/builder.hh" -#include "targetarch/ev5.hh" using namespace std; @@ -92,13 +91,13 @@ Uart::Uart(const string &name, SimConsole *c, MemoryController *mmu, Addr a, : PioDevice(name), addr(a), size(s), cons(c), txIntrEvent(this, TX_INT), rxIntrEvent(this, RX_INT), platform(p) { - mmu->add_child(this, Range<Addr>(addr, addr + size)); + mmu->add_child(this, RangeSize(addr, size)); if (bus) { pioInterface = newPioInterface(name, hier, bus, this, &Uart::cacheAccess); - pioInterface->addAddrRange(addr, addr + size - 1); + pioInterface->addAddrRange(RangeSize(addr, size)); pioLatency = pio_latency * bus->clockRatio; } @@ -118,7 +117,7 @@ Uart::Uart(const string &name, SimConsole *c, MemoryController *mmu, Addr a, Fault Uart::read(MemReqPtr &req, uint8_t *data) { - Addr daddr = req->paddr - (addr & PA_IMPL_MASK); + Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); DPRINTF(Uart, " read register %#x\n", daddr); @@ -246,7 +245,7 @@ Uart::read(MemReqPtr &req, uint8_t *data) Fault Uart::write(MemReqPtr &req, const uint8_t *data) { - Addr daddr = req->paddr - (addr & PA_IMPL_MASK); + Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); DPRINTF(Uart, " write register %#x value %#x\n", daddr, *(uint8_t*)data); @@ -287,7 +286,7 @@ Uart::write(MemReqPtr &req, const uint8_t *data) switch (daddr) { case 0x0: if (!(LCR & 0x80)) { // write byte - cons->out(*(uint64_t *)data); + cons->out(*(uint8_t *)data); platform->clearConsoleInt(); status &= ~TX_INT; if (UART_IER_THRI & IER) |