📄 main.cc
字号:
// DEC Tulip Plus Ethernet Controller// Matt Chapman <matthewc@cse.unsw.edu.au>#include <stdio.h>#include <string.h>#include <unistd.h>#include <assert.hh>#include <checkpoint.hh>#include <device.hh>#include <inttypes.hh>#include <module.hh>#include <serial.hh>#include <simarg.hh>#include <sulima.hh>#include "tulip.hh"// Serialization information.SerialType<Tulip> Tulip::type( "Tulip", "DEC Tulip Plus Ethernet Controller");// Runtime constructor.Tulip::Tulip(const SimArgs& args) : Module(args), PCIDevice(32, PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS, PCI_CLASS_NETWORK_ETHERNET){ if (args.length() > 2) throw Error("Too many arguments to \"sim::install Tulip\".");}// Serialized constructor.Tulip::Tulip(Checkpoint& cp) : Module(cp), PCIDevice(32, PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS, PCI_CLASS_NETWORK_ETHERNET){ reset(false);}// Module interface.voidTulip::reset(bool warm){ irq_status = irq_mask = 0; setup_tap(); memset(srom, 0, sizeof(srom)); srom[9] = 1 | (1 << 8); /* SROM Format Version, Controller Count */ srom[10] = 0x10; /* MAC address 10:00:00:00:00:00 */ srom[63] = 0xffff; /* Checksum */}voidTulip::init(Bus *b, InterruptSink *intc, UInt64 base_address, UInt64 size, int base_irq){ int i; bus = b; intctrl = intc; bar[0] = base_address | 1; for (i = 1; i <= 5; i++) bar[i] = 0; irq = base_irq;}// Serialization interface.voidTulip::checkpoint(Checkpoint& cp, bool parent) const{}voidTulip::read_uint32(UInt32 address, UInt32 *value){ UInt64 buf_64; bus->read(address, &buf_64, 4); *value = buf_64; /* when to byte swap? */}voidTulip::write_uint32(UInt32 address, UInt32 value){ UInt64 buf_64 = value; /* when to byte swap? */ bus->write(address, &buf_64, 4);}voidTulip::tx_fragment(UInt32 address, UInt32 length){ UInt64 buf; if (tx_offset + length > sizeof(tx_buffer)) return; while (length > 0) { bus->read(address, &buf, 1); tx_buffer[tx_offset++] = buf; address++; length--; }}voidTulip::tx_frame(void){#if 0 UInt32 i; printf("network: send "); for (i = 0; i < tx_offset; i++) printf("%02x", tx_buffer[i]); printf("\n");#endif ::write(io_fd, tx_buffer, tx_offset); tx_offset = 0;}voidTulip::tx_poll(void){ struct tdes tdes; while (1) { /* fetch descriptor */ read_uint32(tx_next, &tdes.tdes0.raw); read_uint32(tx_next+4, &tdes.tdes1.raw); read_uint32(tx_next+8, &tdes.tdes2); read_uint32(tx_next+12, &tdes.tdes3); if (!tdes.tdes0.x.own) { irq_status |= IRQ_TU; break; } if (!tdes.tdes1.x.set) /* ignore setup packets */ { /* send data */ tx_fragment(tdes.tdes2, tdes.tdes1.x.tbs1); if (!tdes.tdes1.x.tch) tx_fragment(tdes.tdes3, tdes.tdes1.x.tbs2); if (tdes.tdes1.x.ls) tx_frame(); } /* write back status */ tdes.tdes0.raw = 0; write_uint32(tx_next, tdes.tdes0.raw); if (tdes.tdes1.x.ic) irq_status |= IRQ_TI; /* proceed to next descriptor */ if (tdes.tdes1.x.ter) tx_next = tx_base; else if (tdes.tdes1.x.tch) tx_next = tdes.tdes3; else tx_next += sizeof(tdes) + 4*bus_mode.r.dsl; } check_interrupts();}voidTulip::rx_fragment(UInt32 address, UInt32 length, UInt8 *buffer, UInt32 &offset, UInt32 &remaining){ UInt64 buf; if (length > remaining) length = remaining; remaining -= length; while (length > 0) { buf = buffer[offset++]; bus->write(address, &buf, 1); address++; length--; }}voidTulip::rx_input(UInt8 *buffer, UInt32 length){ struct rdes rdes; UInt32 remaining = length, offset = 0; bool first = true; /* append (bogus) CRC - hopefully the OS doesn't check */ buffer[length] = buffer[length+1] = buffer[length+2] = buffer[length+3] = 0xff; length += 4; while (1) { /* fetch descriptor */ read_uint32(rx_next, &rdes.rdes0.raw); read_uint32(rx_next+4, &rdes.rdes1.raw); read_uint32(rx_next+8, &rdes.rdes2); read_uint32(rx_next+12, &rdes.rdes3); if (!rdes.rdes0.x.own) { irq_status |= IRQ_RU; break; } if (remaining == 0) break; /* receive data */ rx_fragment(rdes.rdes2, rdes.rdes1.x.rbs1, buffer, offset, remaining); if (!rdes.rdes1.x.rch) rx_fragment(rdes.rdes3, rdes.rdes1.x.rbs2, buffer, offset, remaining); /* write back status */ rdes.rdes0.raw = 0; rdes.rdes0.x.fl = length; rdes.rdes0.x.fs = first; rdes.rdes0.x.ls = (remaining == 0); write_uint32(rx_next, rdes.rdes0.raw); first = false; /* proceed to next descriptor */ if (rdes.rdes1.x.rer) rx_next = rx_base; else if (rdes.rdes1.x.rch) rx_next = rdes.rdes3; else rx_next += sizeof(rdes) + 4*bus_mode.r.dsl; } irq_status |= IRQ_RI; check_interrupts();}voidTulip::check_interrupts(void){ bool intr = false; /* recalculate these bits */ irq_status &= ~(IRQ_NIS|IRQ_AIS); if ((irq_mask & irq_status) & (IRQ_TI|IRQ_TU|IRQ_RI)) { if (irq_mask & IRQ_NIS) intr = true; irq_status |= IRQ_NIS; } if ((irq_mask & irq_status) & (IRQ_RU)) { if (irq_mask & IRQ_AIS) intr = true; irq_status |= IRQ_AIS; } if (intr) intctrl->deliver_interrupt(irq); else intctrl->clear_interrupt(irq);}ClockValueTulip::read(UInt64 addr, UInt64* buf, int size){ unsigned int reg = (addr >> 3) & 0xf; UInt32 val; switch (reg) { case 0: /* Bus Mode Register */ val = bus_mode.data; break; case 1: /* Transmit Poll Demand Register */ case 2: /* Receive Poll Demand Register */ val = 0; break; case 3: /* Rx Descriptor Base */ val = rx_base; break; case 4: /* Tx Descriptor Base */ val = tx_base; break; case 5: /* Status Register */ val = irq_status; if (op_mode.r.start_rcv) val |= (3 << 17); /* Rx running */ if (op_mode.r.start_send) val |= (6 << 20); /* Tx active (but suspended) */ break; case 6: /* Operating Mode Register */ val = op_mode.data; break; case 7: /* Interrupt Mask */ val = irq_mask; break; case 9: /* Boot and Ethernet ROMs Register */ val = srom_mii.data; break; case 12: /* SIA Status Register */ val = (1 << 4) | (1 << 5); /* PLL Self Test Done | PLL Self Test Pass */ break; default: log("Read unimplemented register %d", reg); val = 0; break; } *buf = val; return 0; // ignore latency}ClockValueTulip::write(UInt64 addr, const UInt64* buf, int size){ unsigned int reg = (addr >> 3) & 0xf; UInt32 val = *buf; switch (reg) { case 0: /* Bus Mode Register */ bus_mode.data = val; /* Should handle swr */ if (bus_mode.r.swr == 1) { bus_mode.r.swr = 0; } break; case 1: /* Transmit Poll Demand Register */ tx_poll(); break; case 2: /* Receive Poll Demand Register */ break; case 3: /* Rx Descriptor Base */ rx_next = rx_base = val; break; case 4: /* Tx Descriptor Base */ tx_next = tx_base = val; break; case 5: /* Status Register */ /* writing 1 clears corresponding IRQ status bit */ irq_status &= ~val; check_interrupts(); break; case 6: /* Operating Mode Register */ op_mode.data = val; if (op_mode.r.start_send) tx_poll(); break; case 7: /* Interrupt Mask */ irq_mask = val; break; case 9: /* Boot and Ethernet ROMs Register */ srom_mii.data = val; if (srom_mii.r.sr) { if (srom_mii.r.cs && srom_mii.r.clk) { srom_out <<= 1; srom_out |= srom_mii.r.dout; srom_mii.r.din = srom_in >> 15; srom_in <<= 1; if ((srom_out >> srom_address_bits) == 6) srom_in = srom[srom_out & 63]; } else if (!srom_mii.r.cs) { srom_out = srom_in = 0; } } break; default: log("Write unimplemented register %d %x", reg, val); break; } return 0; // ignore latency}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -