sinic.cc
来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· CC 代码 · 共 1,617 行 · 第 1/3 页
CC
1,617 行
/* * Copyright (c) 2004, 2005 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator. * * Permission is granted to use, copy, create derivative works and * redistribute this software and such derivative works for any * purpose, so long as the copyright notice above, this grant of * permission, and the disclaimer below appear in all copies made; and * so long as the name of The University of Michigan is not used in * any advertising or publicity pertaining to the use or distribution * of this software without specific, written prior authorization. * * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH * DAMAGES. * * Authors: Nathan L. Binkert */#include <deque>#include <limits>#include <string>#include "arch/vtophys.hh"#include "base/inet.hh"#include "cpu/thread_context.hh"#include "cpu/intr_control.hh"#include "dev/etherlink.hh"#include "dev/sinic.hh"#include "mem/packet.hh"#include "mem/packet_access.hh"#include "sim/debug.hh"#include "sim/eventq.hh"#include "sim/host.hh"#include "sim/stats.hh"using namespace Net;using namespace TheISA;namespace Sinic {const char *RxStateStrings[] ={ "rxIdle", "rxFifoBlock", "rxBeginCopy", "rxCopy", "rxCopyDone"};const char *TxStateStrings[] ={ "txIdle", "txFifoBlock", "txBeginCopy", "txCopy", "txCopyDone"};/////////////////////////////////////////////////////////////////////////// Sinic PCI Device//Base::Base(const Params *p) : PciDev(p), rxEnable(false), txEnable(false), clock(p->clock), intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false), cpuPendingIntr(false), intrEvent(0), interface(NULL){}Device::Device(const Params *p) : Base(p), rxUnique(0), txUnique(0), virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count), 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){ interface = new Interface(name() + ".int0", this); reset();}Device::~Device(){}voidDevice::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) ; totBandwidth .name(name() + ".totBandwidth") .desc("Total Bandwidth (bits/s)") .precision(0) .prereq(totBytes) ; totPackets .name(name() + ".totPackets") .desc("Total Packets") .precision(0) .prereq(totBytes) ; totBytes .name(name() + ".totBytes") .desc("Total Bytes") .precision(0) .prereq(totBytes) ; totPacketRate .name(name() + ".totPPS") .desc("Total Tranmission Rate (packets/s)") .precision(0) .prereq(totBytes) ; 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; totBandwidth = txBandwidth + rxBandwidth; totBytes = txBytes + rxBytes; totPackets = txPackets + rxPackets; txPacketRate = txPackets / simSeconds; rxPacketRate = rxPackets / simSeconds;}EtherInt*Device::getEthPort(const std::string &if_name, int idx){ if (if_name == "interface") { if (interface->getPeer()) panic("interface already connected to\n"); return interface; } return NULL;}voidDevice::prepareIO(int cpu, int index){ int size = virtualRegs.size(); if (index > size) panic("Trying to access a vnic that doesn't exist %d > %d\n", index, size);}voidDevice::prepareRead(int cpu, int index){ using namespace Regs; prepareIO(cpu, index); VirtualReg &vnic = virtualRegs[index]; // update rx registers uint64_t rxdone = vnic.RxDone; rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr)); rxdone = set_RxDone_Empty(rxdone, rxFifo.empty()); rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoMark); rxdone = set_RxDone_NotHigh(rxdone, rxLow); regs.RxData = vnic.RxData; regs.RxDone = rxdone; regs.RxWait = rxdone; // update tx regsiters uint64_t txdone = vnic.TxDone; txdone = set_TxDone_Packets(txdone, txFifo.packets()); txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy); txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoMark); regs.TxData = vnic.TxData; regs.TxDone = txdone; regs.TxWait = txdone;}voidDevice::prepareWrite(int cpu, int index){ prepareIO(cpu, index);}/** * I/O read of device register */TickDevice::read(PacketPtr pkt){ assert(config.command & PCI_CMD_MSE); assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]); int cpu = pkt->req->getCpuNum(); Addr daddr = pkt->getAddr() - BARAddrs[0]; Addr index = daddr >> Regs::VirtualShift; Addr raddr = daddr & Regs::VirtualMask; pkt->allocate(); if (!regValid(raddr)) panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d", cpu, index, daddr, pkt->getAddr(), pkt->getSize()); const Regs::Info &info = regInfo(raddr); if (!info.read) panic("read %s (write only): " "cpu=%d vnic=%d da=%#x pa=%#x size=%d", info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); panic("read %s (invalid size): " "cpu=%d vnic=%d da=%#x pa=%#x size=%d", info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); prepareRead(cpu, index); uint64_t value = 0; if (pkt->getSize() == 4) { uint32_t reg = regData32(raddr); pkt->set(reg); value = reg; } if (pkt->getSize() == 8) { uint64_t reg = regData64(raddr); pkt->set(reg); value = reg; } DPRINTF(EthernetPIO, "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n", info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value); // reading the interrupt status register has the side effect of // clearing it if (raddr == Regs::IntrStatus) devIntrClear(); return pioDelay;}/** * IPR read of device register FaultDevice::iprRead(Addr daddr, int cpu, uint64_t &result){ if (!regValid(daddr)) panic("invalid address: da=%#x", daddr); const Regs::Info &info = regInfo(daddr); if (!info.read) panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr); DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n", info.name, cpu, daddr); prepareRead(cpu, 0); if (info.size == 4) result = regData32(daddr); if (info.size == 8) result = regData64(daddr); DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n", info.name, cpu, result); return NoFault;}*//** * I/O write of device register */TickDevice::write(PacketPtr pkt){ assert(config.command & PCI_CMD_MSE); assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]); int cpu = pkt->req->getCpuNum(); Addr daddr = pkt->getAddr() - BARAddrs[0]; Addr index = daddr >> Regs::VirtualShift; Addr raddr = daddr & Regs::VirtualMask; if (!regValid(raddr)) panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d", cpu, daddr, pkt->getAddr(), pkt->getSize()); const Regs::Info &info = regInfo(raddr); if (!info.write) panic("write %s (read only): " "cpu=%d vnic=%d da=%#x pa=%#x size=%d", info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); if (pkt->getSize() != info.size) panic("write %s (invalid size): " "cpu=%d vnic=%d da=%#x pa=%#x size=%d", info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); VirtualReg &vnic = virtualRegs[index]; DPRINTF(EthernetPIO, "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n", info.name, index, cpu, info.size == 4 ? pkt->get<uint32_t>() : pkt->get<uint64_t>(), daddr, pkt->getAddr(), pkt->getSize()); prepareWrite(cpu, index); switch (raddr) { case Regs::Config: changeConfig(pkt->get<uint32_t>()); break; case Regs::Command: command(pkt->get<uint32_t>()); break; case Regs::IntrStatus: devIntrClear(regs.IntrStatus & pkt->get<uint32_t>()); break; case Regs::IntrMask: devIntrChangeMask(pkt->get<uint32_t>()); break; case Regs::RxData: if (Regs::get_RxDone_Busy(vnic.RxDone)) panic("receive machine busy with another request! rxState=%s", RxStateStrings[rxState]); vnic.rxUnique = rxUnique++; vnic.RxDone = Regs::RxDone_Busy; vnic.RxData = pkt->get<uint64_t>(); if (Regs::get_RxData_Vaddr(pkt->get<uint64_t>())) { panic("vtophys not implemented in newmem");/* Addr vaddr = Regs::get_RxData_Addr(reg64); Addr paddr = vtophys(req->xc, vaddr); DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): " "vaddr=%#x, paddr=%#x\n", index, vnic.rxUnique, vaddr, paddr); vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);*/ } else { DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n", index, vnic.rxUnique); } if (vnic.rxPacket == rxFifo.end()) { DPRINTF(EthernetPIO, "request new packet...appending to rxList\n"); rxList.push_back(index); } else { DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n"); rxBusy.push_back(index); } if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) { rxState = rxFifoBlock; rxKick(); } break; case Regs::TxData: if (Regs::get_TxDone_Busy(vnic.TxDone)) panic("transmit machine busy with another request! txState=%s", TxStateStrings[txState]); vnic.txUnique = txUnique++; vnic.TxDone = Regs::TxDone_Busy; if (Regs::get_TxData_Vaddr(pkt->get<uint64_t>())) { panic("vtophys won't work here in newmem.\n"); /*Addr vaddr = Regs::get_TxData_Addr(reg64); Addr paddr = vtophys(req->xc, vaddr); DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d): " "vaddr=%#x, paddr=%#x\n", index, vnic.txUnique, vaddr, paddr); vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);*/ } else { DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d)\n", index, vnic.txUnique); } if (txList.empty() || txList.front() != index) txList.push_back(index); if (txEnable && txState == txIdle && txList.front() == index) { txState = txFifoBlock; txKick(); } break; } return pioDelay;}void
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?