?? smc91c111.c
字號:
case 3: case 4: case 5: /* Should be readonly, but linux writes to them anyway. Ignore. */ return; case 6: /* Pointer */ SET_LOW(ptr, value); return; case 7: SET_HIGH(ptr, value); return; case 8: case 9: case 10: case 11: /* Data */ { int p; int n; if (s->ptr & 0x8000) n = s->rx_fifo[0]; else n = s->packet_num; p = s->ptr & 0x07ff; if (s->ptr & 0x4000) { s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff); } else { p += (offset & 3); } s->data[n][p] = value; } return; case 12: /* Interrupt ACK. */ s->int_level &= ~(value & 0xd6); if (value & INT_TX) smc91c111_pop_tx_fifo_done(s); smc91c111_update(s); return; case 13: /* Interrupt mask. */ s->int_mask = value; smc91c111_update(s); return; } break;; case 3: switch (offset) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: /* Multicast table. */ /* Not implemented. */ return; case 8: case 9: /* Management Interface. */ /* Not implemented. */ return; case 12: /* Early receive. */ s->ercv = value & 0x1f; case 13: /* Ignore. */ return; } break; } cpu_abort (cpu_single_env, "smc91c111_write: Bad reg %d:%x\n", s->bank, offset);}static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset){ smc91c111_state *s = (smc91c111_state *)opaque; offset -= s->base; if (offset == 14) { return s->bank; } if (offset == 15) return 0x33; switch (s->bank) { case 0: switch (offset) { case 0: /* TCR */ return s->tcr & 0xff; case 1: return s->tcr >> 8; case 2: /* EPH Status */ return 0; case 3: return 0x40; case 4: /* RCR */ return s->rcr & 0xff; case 5: return s->rcr >> 8; case 6: /* Counter */ case 7: /* Not implemented. */ return 0; case 8: /* Free memory available. */ { int i; int n; n = 0; for (i = 0; i < NUM_PACKETS; i++) { if (s->allocated & (1 << i)) n++; } return n; } case 9: /* Memory size. */ return NUM_PACKETS; case 10: case 11: /* RPCR */ /* Not implemented. */ return 0; } break; case 1: switch (offset) { case 0: /* CONFIG */ return s->cr & 0xff; case 1: return s->cr >> 8; case 2: case 3: /* BASE */ /* Not implemented. */ return 0; case 4: case 5: case 6: case 7: case 8: case 9: /* IA */ return s->macaddr[offset - 4]; case 10: /* General Purpose */ return s->gpr & 0xff; case 11: return s->gpr >> 8; case 12: /* Control */ return s->ctr & 0xff; case 13: return s->ctr >> 8; } break; case 2: switch (offset) { case 0: case 1: /* MMUCR Busy bit. */ return 0; case 2: /* Packet Number. */ return s->packet_num; case 3: /* Allocation Result. */ return s->tx_alloc; case 4: /* TX FIFO */ if (s->tx_fifo_done_len == 0) return 0x80; else return s->tx_fifo_done[0]; case 5: /* RX FIFO */ if (s->rx_fifo_len == 0) return 0x80; else return s->rx_fifo[0]; case 6: /* Pointer */ return s->ptr & 0xff; case 7: return (s->ptr >> 8) & 0xf7; case 8: case 9: case 10: case 11: /* Data */ { int p; int n; if (s->ptr & 0x8000) n = s->rx_fifo[0]; else n = s->packet_num; p = s->ptr & 0x07ff; if (s->ptr & 0x4000) { s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff); } else { p += (offset & 3); } return s->data[n][p]; } case 12: /* Interrupt status. */ return s->int_level; case 13: /* Interrupt mask. */ return s->int_mask; } break; case 3: switch (offset) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: /* Multicast table. */ /* Not implemented. */ return 0; case 8: /* Management Interface. */ /* Not implemented. */ return 0x30; case 9: return 0x33; case 10: /* Revision. */ return 0x91; case 11: return 0x33; case 12: return s->ercv; case 13: return 0; } break; } cpu_abort (cpu_single_env, "smc91c111_read: Bad reg %d:%x\n", s->bank, offset); return 0;}static void smc91c111_writew(void *opaque, target_phys_addr_t offset, uint32_t value){ smc91c111_writeb(opaque, offset, value & 0xff); smc91c111_writeb(opaque, offset + 1, value >> 8);}static void smc91c111_writel(void *opaque, target_phys_addr_t offset, uint32_t value){ smc91c111_state *s = (smc91c111_state *)opaque; /* 32-bit writes to offset 0xc only actually write to the bank select register (offset 0xe) */ if (offset != s->base + 0xc) smc91c111_writew(opaque, offset, value & 0xffff); smc91c111_writew(opaque, offset + 2, value >> 16);}static uint32_t smc91c111_readw(void *opaque, target_phys_addr_t offset){ uint32_t val; val = smc91c111_readb(opaque, offset); val |= smc91c111_readb(opaque, offset + 1) << 8; return val;}static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset){ uint32_t val; val = smc91c111_readw(opaque, offset); val |= smc91c111_readw(opaque, offset + 2) << 16; return val;}static int smc91c111_can_receive(void *opaque){ smc91c111_state *s = (smc91c111_state *)opaque; if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) return 1; if (s->allocated == (1 << NUM_PACKETS) - 1) return 0; return 1;}static void smc91c111_receive(void *opaque, const uint8_t *buf, int size){ smc91c111_state *s = (smc91c111_state *)opaque; int status; int packetsize; uint32_t crc; int packetnum; uint8_t *p; if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) return; /* Short packets are padded with zeros. Receiving a packet < 64 bytes long is considered an error condition. */ if (size < 64) packetsize = 64; else packetsize = (size & ~1); packetsize += 6; crc = (s->rcr & RCR_STRIP_CRC) == 0; if (crc) packetsize += 4; /* TODO: Flag overrun and receive errors. */ if (packetsize > 2048) return; packetnum = smc91c111_allocate_packet(s); if (packetnum == 0x80) return; s->rx_fifo[s->rx_fifo_len++] = packetnum; p = &s->data[packetnum][0]; /* ??? Multicast packets? */ status = 0; if (size > 1518) status |= RS_TOOLONG; if (size & 1) status |= RS_ODDFRAME; *(p++) = status & 0xff; *(p++) = status >> 8; *(p++) = packetsize & 0xff; *(p++) = packetsize >> 8; memcpy(p, buf, size & ~1); p += (size & ~1); /* Pad short packets. */ if (size < 64) { int pad; if (size & 1) *(p++) = buf[size - 1]; pad = 64 - size; memset(p, 0, pad); p += pad; size = 64; } /* It's not clear if the CRC should go before or after the last byte in odd sized packets. Linux disables the CRC, so that's no help. The pictures in the documentation show the CRC aligned on a 16-bit boundary before the last odd byte, so that's what we do. */ if (crc) { crc = crc32(~0, buf, size); *(p++) = crc & 0xff; crc >>= 8; *(p++) = crc & 0xff; crc >>= 8; *(p++) = crc & 0xff; crc >>= 8; *(p++) = crc & 0xff; crc >>= 8; } if (size & 1) { *(p++) = buf[size - 1]; *(p++) = 0x60; } else { *(p++) = 0; *(p++) = 0x40; } /* TODO: Raise early RX interrupt? */ s->int_level |= INT_RCV; smc91c111_update(s);}static CPUReadMemoryFunc *smc91c111_readfn[] = { smc91c111_readb, smc91c111_readw, smc91c111_readl};static CPUWriteMemoryFunc *smc91c111_writefn[] = { smc91c111_writeb, smc91c111_writew, smc91c111_writel};void smc91c111_init(NICInfo *nd, uint32_t base, void *pic, int irq){ smc91c111_state *s; int iomemtype; s = (smc91c111_state *)qemu_mallocz(sizeof(smc91c111_state)); iomemtype = cpu_register_io_memory(0, smc91c111_readfn, smc91c111_writefn, s); cpu_register_physical_memory(base, 16, iomemtype); s->base = base; s->pic = pic; s->irq = irq; memcpy(s->macaddr, nd->macaddr, 6); smc91c111_reset(s); s->vc = qemu_new_vlan_client(nd->vlan, smc91c111_receive, smc91c111_can_receive, s); /* ??? Save/restore. */}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -