📄 ne2000.c
字号:
case EN1_MULT ... EN1_MULT + 7: s->mult[offset - EN1_MULT] = val; break; } }}static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr){ NE2000State *s = opaque; int offset, page, ret; addr &= 0xf; if (addr == E8390_CMD) { ret = s->cmd; } else { page = s->cmd >> 6; offset = addr | (page << 4); switch(offset) { case EN0_TSR: ret = s->tsr; break; case EN0_BOUNDARY: ret = s->boundary; break; case EN0_ISR: ret = s->isr; break; case EN0_RSARLO: ret = s->rsar & 0x00ff; break; case EN0_RSARHI: ret = s->rsar >> 8; break; case EN1_PHYS ... EN1_PHYS + 5: ret = s->phys[offset - EN1_PHYS]; break; case EN1_CURPAG: ret = s->curpag; break; case EN1_MULT ... EN1_MULT + 7: ret = s->mult[offset - EN1_MULT]; break; case EN0_RSR: ret = s->rsr; break; case EN2_STARTPG: ret = s->start >> 8; break; case EN2_STOPPG: ret = s->stop >> 8; break; case EN0_RTL8029ID0: ret = 0x50; break; case EN0_RTL8029ID1: ret = 0x43; break; case EN3_CONFIG0: ret = 0; /* 10baseT media */ break; case EN3_CONFIG2: ret = 0x40; /* 10baseT active */ break; case EN3_CONFIG3: ret = 0x40; /* Full duplex */ break; default: ret = 0x00; break; } }#ifdef DEBUG_NE2000 printf("NE2000: read addr=0x%x val=%02x\n", addr, ret);#endif return ret;}static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr, uint32_t val){ if (addr < 32 || (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { s->mem[addr] = val; }}static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr, uint32_t val){ addr &= ~1; /* XXX: check exact behaviour if not even */ if (addr < 32 || (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { *(uint16_t *)(s->mem + addr) = cpu_to_le16(val); }}static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr, uint32_t val){ addr &= ~1; /* XXX: check exact behaviour if not even */ if (addr < 32 || (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { cpu_to_le32wu((uint32_t *)(s->mem + addr), val); }}static inline uint32_t ne2000_mem_readb(NE2000State *s, uint32_t addr){ if (addr < 32 || (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { return s->mem[addr]; } else { return 0xff; }}static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr){ addr &= ~1; /* XXX: check exact behaviour if not even */ if (addr < 32 || (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { return le16_to_cpu(*(uint16_t *)(s->mem + addr)); } else { return 0xffff; }}static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr){ addr &= ~1; /* XXX: check exact behaviour if not even */ if (addr < 32 || (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { return le32_to_cpupu((uint32_t *)(s->mem + addr)); } else { return 0xffffffff; }}static inline void ne2000_dma_update(NE2000State *s, int len){ s->rsar += len; /* wrap */ /* XXX: check what to do if rsar > stop */ if (s->rsar == s->stop) s->rsar = s->start; if (s->rcnt <= len) { s->rcnt = 0; /* signal end of transfert */ s->isr |= ENISR_RDC; ne2000_update_irq(s); } else { s->rcnt -= len; }}static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val){ NE2000State *s = opaque;#ifdef DEBUG_NE2000 printf("NE2000: asic write val=0x%04x\n", val);#endif if (s->rcnt == 0) return; if (s->dcfg & 0x01) { /* 16 bit access */ ne2000_mem_writew(s, s->rsar, val); ne2000_dma_update(s, 2); } else { /* 8 bit access */ ne2000_mem_writeb(s, s->rsar, val); ne2000_dma_update(s, 1); }}static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr){ NE2000State *s = opaque; int ret; if (s->dcfg & 0x01) { /* 16 bit access */ ret = ne2000_mem_readw(s, s->rsar); ne2000_dma_update(s, 2); } else { /* 8 bit access */ ret = ne2000_mem_readb(s, s->rsar); ne2000_dma_update(s, 1); }#ifdef DEBUG_NE2000 printf("NE2000: asic read val=0x%04x\n", ret);#endif return ret;}static void ne2000_asic_ioport_writel(void *opaque, uint32_t addr, uint32_t val){ NE2000State *s = opaque;#ifdef DEBUG_NE2000 printf("NE2000: asic writel val=0x%04x\n", val);#endif if (s->rcnt == 0) return; /* 32 bit access */ ne2000_mem_writel(s, s->rsar, val); ne2000_dma_update(s, 4);}static uint32_t ne2000_asic_ioport_readl(void *opaque, uint32_t addr){ NE2000State *s = opaque; int ret; /* 32 bit access */ ret = ne2000_mem_readl(s, s->rsar); ne2000_dma_update(s, 4);#ifdef DEBUG_NE2000 printf("NE2000: asic readl val=0x%04x\n", ret);#endif return ret;}static void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val){ /* nothing to do (end of reset pulse) */}static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr){ NE2000State *s = opaque; ne2000_reset(s); return 0;}static void ne2000_save(QEMUFile* f,void* opaque){ NE2000State* s=(NE2000State*)opaque; qemu_put_8s(f, &s->rxcr); qemu_put_8s(f, &s->cmd); qemu_put_be32s(f, &s->start); qemu_put_be32s(f, &s->stop); qemu_put_8s(f, &s->boundary); qemu_put_8s(f, &s->tsr); qemu_put_8s(f, &s->tpsr); qemu_put_be16s(f, &s->tcnt); qemu_put_be16s(f, &s->rcnt); qemu_put_be32s(f, &s->rsar); qemu_put_8s(f, &s->rsr); qemu_put_8s(f, &s->isr); qemu_put_8s(f, &s->dcfg); qemu_put_8s(f, &s->imr); qemu_put_buffer(f, s->phys, 6); qemu_put_8s(f, &s->curpag); qemu_put_buffer(f, s->mult, 8); qemu_put_be32s(f, &s->irq); qemu_put_buffer(f, s->mem, NE2000_MEM_SIZE);}static int ne2000_load(QEMUFile* f,void* opaque,int version_id){ NE2000State* s=(NE2000State*)opaque; if (version_id == 2) { qemu_get_8s(f, &s->rxcr); } else if (version_id == 1) { s->rxcr = 0x0c; } else { return -EINVAL; } qemu_get_8s(f, &s->cmd); qemu_get_be32s(f, &s->start); qemu_get_be32s(f, &s->stop); qemu_get_8s(f, &s->boundary); qemu_get_8s(f, &s->tsr); qemu_get_8s(f, &s->tpsr); qemu_get_be16s(f, &s->tcnt); qemu_get_be16s(f, &s->rcnt); qemu_get_be32s(f, &s->rsar); qemu_get_8s(f, &s->rsr); qemu_get_8s(f, &s->isr); qemu_get_8s(f, &s->dcfg); qemu_get_8s(f, &s->imr); qemu_get_buffer(f, s->phys, 6); qemu_get_8s(f, &s->curpag); qemu_get_buffer(f, s->mult, 8); qemu_get_be32s(f, &s->irq); qemu_get_buffer(f, s->mem, NE2000_MEM_SIZE); return 0;}void isa_ne2000_init(int base, int irq, NICInfo *nd){ NE2000State *s; s = qemu_mallocz(sizeof(NE2000State)); if (!s) return; register_ioport_write(base, 16, 1, ne2000_ioport_write, s); register_ioport_read(base, 16, 1, ne2000_ioport_read, s); register_ioport_write(base + 0x10, 1, 1, ne2000_asic_ioport_write, s); register_ioport_read(base + 0x10, 1, 1, ne2000_asic_ioport_read, s); register_ioport_write(base + 0x10, 2, 2, ne2000_asic_ioport_write, s); register_ioport_read(base + 0x10, 2, 2, ne2000_asic_ioport_read, s); register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s); register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s); s->irq = irq; memcpy(s->macaddr, nd->macaddr, 6); ne2000_reset(s); s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, ne2000_can_receive, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "ne2000 macaddr=%02x:%02x:%02x:%02x:%02x:%02x", s->macaddr[0], s->macaddr[1], s->macaddr[2], s->macaddr[3], s->macaddr[4], s->macaddr[5]); register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s);}/***********************************************************//* PCI NE2000 definitions */typedef struct PCINE2000State { PCIDevice dev; NE2000State ne2000;} PCINE2000State;static void ne2000_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type){ PCINE2000State *d = (PCINE2000State *)pci_dev; NE2000State *s = &d->ne2000; register_ioport_write(addr, 16, 1, ne2000_ioport_write, s); register_ioport_read(addr, 16, 1, ne2000_ioport_read, s); register_ioport_write(addr + 0x10, 1, 1, ne2000_asic_ioport_write, s); register_ioport_read(addr + 0x10, 1, 1, ne2000_asic_ioport_read, s); register_ioport_write(addr + 0x10, 2, 2, ne2000_asic_ioport_write, s); register_ioport_read(addr + 0x10, 2, 2, ne2000_asic_ioport_read, s); register_ioport_write(addr + 0x10, 4, 4, ne2000_asic_ioport_writel, s); register_ioport_read(addr + 0x10, 4, 4, ne2000_asic_ioport_readl, s); register_ioport_write(addr + 0x1f, 1, 1, ne2000_reset_ioport_write, s); register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s);}void pci_ne2000_init(PCIBus *bus, NICInfo *nd){ PCINE2000State *d; NE2000State *s; uint8_t *pci_conf; d = (PCINE2000State *)pci_register_device(bus, "NE2000", sizeof(PCINE2000State), -1, NULL, NULL); pci_conf = d->dev.config; pci_conf[0x00] = 0xec; // Realtek 8029 pci_conf[0x01] = 0x10; pci_conf[0x02] = 0x29; pci_conf[0x03] = 0x80; pci_conf[0x0a] = 0x00; // ethernet network controller pci_conf[0x0b] = 0x02; pci_conf[0x0e] = 0x00; // header_type pci_conf[0x3d] = 1; // interrupt pin 0 pci_register_io_region(&d->dev, 0, 0x100, PCI_ADDRESS_SPACE_IO, ne2000_map); s = &d->ne2000; s->irq = 16; // PCI interrupt s->pci_dev = (PCIDevice *)d; memcpy(s->macaddr, nd->macaddr, 6); ne2000_reset(s); s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, ne2000_can_receive, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "ne2000 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x", s->macaddr[0], s->macaddr[1], s->macaddr[2], s->macaddr[3], s->macaddr[4], s->macaddr[5]); /* XXX: instance number ? */ register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s); register_savevm("ne2000_pci", 0, 1, generic_pci_save, generic_pci_load, &d->dev);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -