Commit e3c2613f918ed1e302ec6c3d3a35bb176e154aa5

Authored by bellard
1 parent 6cadb320

pcnet nic support (Antony T Curtis)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2036 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
... ... @@ -329,7 +329,7 @@ VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
329 329 VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o
330 330  
331 331 # PCI network cards
332   -VL_OBJS+= ne2000.o rtl8139.o
  332 +VL_OBJS+= ne2000.o rtl8139.o pcnet.o
333 333  
334 334 ifeq ($(TARGET_BASE_ARCH), i386)
335 335 # Hardware support
... ...
hw/pci.c
... ... @@ -493,6 +493,8 @@ void pci_nic_init(PCIBus *bus, NICInfo *nd)
493 493 pci_ne2000_init(bus, nd);
494 494 } else if (strcmp(nd->model, "rtl8139") == 0) {
495 495 pci_rtl8139_init(bus, nd);
  496 + } else if (strcmp(nd->model, "pcnet") == 0) {
  497 + pci_pcnet_init(bus, nd);
496 498 } else {
497 499 fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
498 500 exit (1);
... ...
hw/pcnet.c 0 → 100644
  1 +/*
  2 + * QEMU AMD PC-Net II (Am79C970A) emulation
  3 + *
  4 + * Copyright (c) 2004 Antony T Curtis
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +
  25 +/* This software was written to be compatible with the specification:
  26 + * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
  27 + * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000
  28 + */
  29 +
  30 +#include "vl.h"
  31 +
  32 +/* XXX: suppress those headers */
  33 +#include <sys/times.h>
  34 +#include <arpa/inet.h>
  35 +#include <net/ethernet.h>
  36 +
  37 +//#define PCNET_DEBUG
  38 +//#define PCNET_DEBUG_IO
  39 +//#define PCNET_DEBUG_BCR
  40 +//#define PCNET_DEBUG_CSR
  41 +//#define PCNET_DEBUG_RMD
  42 +//#define PCNET_DEBUG_TMD
  43 +//#define PCNET_DEBUG_MATCH
  44 +
  45 +
  46 +#define PCNET_IOPORT_SIZE 0x20
  47 +#define PCNET_PNPMMIO_SIZE 0x20
  48 +
  49 +
  50 +typedef struct PCNetState_st PCNetState;
  51 +
  52 +struct PCNetState_st {
  53 + PCIDevice dev;
  54 + VLANClientState *vc;
  55 + NICInfo *nd;
  56 + QEMUTimer *poll_timer;
  57 + int mmio_io_addr, rap, isr, lnkst;
  58 + target_phys_addr_t rdra, tdra;
  59 + uint8_t prom[16];
  60 + uint16_t csr[128];
  61 + uint16_t bcr[32];
  62 + uint64_t timer;
  63 + int xmit_pos, recv_pos;
  64 + uint8_t buffer[4096];
  65 +};
  66 +
  67 +#ifdef __GNUC__
  68 +#define PACKED(A) A __attribute__ ((packed))
  69 +#else
  70 +#error FixMe
  71 +#endif
  72 +
  73 +/* BUS CONFIGURATION REGISTERS */
  74 +#define BCR_MSRDA 0
  75 +#define BCR_MSWRA 1
  76 +#define BCR_MC 2
  77 +#define BCR_LNKST 4
  78 +#define BCR_LED1 5
  79 +#define BCR_LED2 6
  80 +#define BCR_LED3 7
  81 +#define BCR_FDC 9
  82 +#define BCR_BSBC 18
  83 +#define BCR_EECAS 19
  84 +#define BCR_SWS 20
  85 +#define BCR_PLAT 22
  86 +
  87 +#define BCR_DWIO(S) !!((S)->bcr[BCR_BSBC] & 0x0080)
  88 +#define BCR_SSIZE32(S) !!((S)->bcr[BCR_SWS ] & 0x0100)
  89 +#define BCR_SWSTYLE(S) ((S)->bcr[BCR_SWS ] & 0x00FF)
  90 +
  91 +#define CSR_INIT(S) !!(((S)->csr[0])&0x0001)
  92 +#define CSR_STRT(S) !!(((S)->csr[0])&0x0002)
  93 +#define CSR_STOP(S) !!(((S)->csr[0])&0x0004)
  94 +#define CSR_TDMD(S) !!(((S)->csr[0])&0x0008)
  95 +#define CSR_TXON(S) !!(((S)->csr[0])&0x0010)
  96 +#define CSR_RXON(S) !!(((S)->csr[0])&0x0020)
  97 +#define CSR_INEA(S) !!(((S)->csr[0])&0x0040)
  98 +#define CSR_LAPPEN(S) !!(((S)->csr[3])&0x0020)
  99 +#define CSR_DXSUFLO(S) !!(((S)->csr[3])&0x0040)
  100 +#define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800)
  101 +#define CSR_DPOLL(S) !!(((S)->csr[4])&0x1000)
  102 +#define CSR_SPND(S) !!(((S)->csr[5])&0x0001)
  103 +#define CSR_LTINTEN(S) !!(((S)->csr[5])&0x4000)
  104 +#define CSR_TOKINTD(S) !!(((S)->csr[5])&0x8000)
  105 +#define CSR_DRX(S) !!(((S)->csr[15])&0x0001)
  106 +#define CSR_DTX(S) !!(((S)->csr[15])&0x0002)
  107 +#define CSR_LOOP(S) !!(((S)->csr[15])&0x0004)
  108 +#define CSR_DRCVPA(S) !!(((S)->csr[15])&0x2000)
  109 +#define CSR_DRCVBC(S) !!(((S)->csr[15])&0x4000)
  110 +#define CSR_PROM(S) !!(((S)->csr[15])&0x8000)
  111 +
  112 +#define CSR_CRBC(S) ((S)->csr[40])
  113 +#define CSR_CRST(S) ((S)->csr[41])
  114 +#define CSR_CXBC(S) ((S)->csr[42])
  115 +#define CSR_CXST(S) ((S)->csr[43])
  116 +#define CSR_NRBC(S) ((S)->csr[44])
  117 +#define CSR_NRST(S) ((S)->csr[45])
  118 +#define CSR_POLL(S) ((S)->csr[46])
  119 +#define CSR_PINT(S) ((S)->csr[47])
  120 +#define CSR_RCVRC(S) ((S)->csr[72])
  121 +#define CSR_XMTRC(S) ((S)->csr[74])
  122 +#define CSR_RCVRL(S) ((S)->csr[76])
  123 +#define CSR_XMTRL(S) ((S)->csr[78])
  124 +#define CSR_MISSC(S) ((S)->csr[112])
  125 +
  126 +#define CSR_IADR(S) ((S)->csr[ 1] | ((S)->csr[ 2] << 16))
  127 +#define CSR_CRBA(S) ((S)->csr[18] | ((S)->csr[19] << 16))
  128 +#define CSR_CXBA(S) ((S)->csr[20] | ((S)->csr[21] << 16))
  129 +#define CSR_NRBA(S) ((S)->csr[22] | ((S)->csr[23] << 16))
  130 +#define CSR_BADR(S) ((S)->csr[24] | ((S)->csr[25] << 16))
  131 +#define CSR_NRDA(S) ((S)->csr[26] | ((S)->csr[27] << 16))
  132 +#define CSR_CRDA(S) ((S)->csr[28] | ((S)->csr[29] << 16))
  133 +#define CSR_BADX(S) ((S)->csr[30] | ((S)->csr[31] << 16))
  134 +#define CSR_NXDA(S) ((S)->csr[32] | ((S)->csr[33] << 16))
  135 +#define CSR_CXDA(S) ((S)->csr[34] | ((S)->csr[35] << 16))
  136 +#define CSR_NNRD(S) ((S)->csr[36] | ((S)->csr[37] << 16))
  137 +#define CSR_NNXD(S) ((S)->csr[38] | ((S)->csr[39] << 16))
  138 +#define CSR_PXDA(S) ((S)->csr[60] | ((S)->csr[61] << 16))
  139 +#define CSR_NXBA(S) ((S)->csr[64] | ((S)->csr[65] << 16))
  140 +
  141 +#define PHYSADDR(S,A) \
  142 + (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(s)->csr[2])<<16))
  143 +
  144 +struct pcnet_initblk16 {
  145 + uint16_t mode;
  146 + uint16_t padr1;
  147 + uint16_t padr2;
  148 + uint16_t padr3;
  149 + uint16_t ladrf1;
  150 + uint16_t ladrf2;
  151 + uint16_t ladrf3;
  152 + uint16_t ladrf4;
  153 + unsigned PACKED(rdra:24);
  154 + unsigned PACKED(res1:5);
  155 + unsigned PACKED(rlen:3);
  156 + unsigned PACKED(tdra:24);
  157 + unsigned PACKED(res2:5);
  158 + unsigned PACKED(tlen:3);
  159 +};
  160 +
  161 +struct pcnet_initblk32 {
  162 + uint16_t mode;
  163 + unsigned PACKED(res1:4);
  164 + unsigned PACKED(rlen:4);
  165 + unsigned PACKED(res2:4);
  166 + unsigned PACKED(tlen:4);
  167 + uint16_t padr1;
  168 + uint16_t padr2;
  169 + uint16_t padr3;
  170 + uint16_t _res;
  171 + uint16_t ladrf1;
  172 + uint16_t ladrf2;
  173 + uint16_t ladrf3;
  174 + uint16_t ladrf4;
  175 + uint32_t rdra;
  176 + uint32_t tdra;
  177 +};
  178 +
  179 +struct pcnet_TMD {
  180 + struct {
  181 + unsigned tbadr:32;
  182 + } tmd0;
  183 + struct {
  184 + unsigned PACKED(bcnt:12), PACKED(ones:4), PACKED(res:7), PACKED(bpe:1);
  185 + unsigned PACKED(enp:1), PACKED(stp:1), PACKED(def:1), PACKED(one:1);
  186 + unsigned PACKED(ltint:1), PACKED(nofcs:1), PACKED(err:1), PACKED(own:1);
  187 + } tmd1;
  188 + struct {
  189 + unsigned PACKED(trc:4), PACKED(res:12);
  190 + unsigned PACKED(tdr:10), PACKED(rtry:1), PACKED(lcar:1);
  191 + unsigned PACKED(lcol:1), PACKED(exdef:1), PACKED(uflo:1), PACKED(buff:1);
  192 + } tmd2;
  193 + struct {
  194 + unsigned res:32;
  195 + } tmd3;
  196 +};
  197 +
  198 +struct pcnet_RMD {
  199 + struct {
  200 + unsigned rbadr:32;
  201 + } rmd0;
  202 + struct {
  203 + unsigned PACKED(bcnt:12), PACKED(ones:4), PACKED(res:4);
  204 + unsigned PACKED(bam:1), PACKED(lafm:1), PACKED(pam:1), PACKED(bpe:1);
  205 + unsigned PACKED(enp:1), PACKED(stp:1), PACKED(buff:1), PACKED(crc:1);
  206 + unsigned PACKED(oflo:1), PACKED(fram:1), PACKED(err:1), PACKED(own:1);
  207 + } rmd1;
  208 + struct {
  209 + unsigned PACKED(mcnt:12), PACKED(zeros:4);
  210 + unsigned PACKED(rpc:8), PACKED(rcc:8);
  211 + } rmd2;
  212 + struct {
  213 + unsigned res:32;
  214 + } rmd3;
  215 +};
  216 +
  217 +
  218 +#define PRINT_TMD(T) printf( \
  219 + "TMD0 : TBADR=0x%08x\n" \
  220 + "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, " \
  221 + "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n" \
  222 + " BPE=%d, BCNT=%d\n" \
  223 + "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, " \
  224 + "LCA=%d, RTR=%d,\n" \
  225 + " TDR=%d, TRC=%d\n", \
  226 + (T)->tmd0.tbadr, \
  227 + (T)->tmd1.own, (T)->tmd1.err, (T)->tmd1.nofcs, \
  228 + (T)->tmd1.ltint, (T)->tmd1.one, (T)->tmd1.def, \
  229 + (T)->tmd1.stp, (T)->tmd1.enp, (T)->tmd1.bpe, \
  230 + 4096-(T)->tmd1.bcnt, \
  231 + (T)->tmd2.buff, (T)->tmd2.uflo, (T)->tmd2.exdef,\
  232 + (T)->tmd2.lcol, (T)->tmd2.lcar, (T)->tmd2.rtry, \
  233 + (T)->tmd2.tdr, (T)->tmd2.trc)
  234 +
  235 +#define PRINT_RMD(R) printf( \
  236 + "RMD0 : RBADR=0x%08x\n" \
  237 + "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, " \
  238 + "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n " \
  239 + "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \
  240 + "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n", \
  241 + (R)->rmd0.rbadr, \
  242 + (R)->rmd1.own, (R)->rmd1.err, (R)->rmd1.fram, \
  243 + (R)->rmd1.oflo, (R)->rmd1.crc, (R)->rmd1.buff, \
  244 + (R)->rmd1.stp, (R)->rmd1.enp, (R)->rmd1.bpe, \
  245 + (R)->rmd1.pam, (R)->rmd1.lafm, (R)->rmd1.bam, \
  246 + (R)->rmd1.ones, 4096-(R)->rmd1.bcnt, \
  247 + (R)->rmd2.rcc, (R)->rmd2.rpc, (R)->rmd2.mcnt, \
  248 + (R)->rmd2.zeros)
  249 +
  250 +static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr)
  251 +{
  252 + if (!BCR_SWSTYLE(s)) {
  253 + uint16_t xda[4];
  254 + cpu_physical_memory_read(addr,
  255 + (void *)&xda[0], sizeof(xda));
  256 + ((uint32_t *)tmd)[0] = (xda[0]&0xffff) |
  257 + ((xda[1]&0x00ff) << 16);
  258 + ((uint32_t *)tmd)[1] = (xda[2]&0xffff)|
  259 + ((xda[1] & 0xff00) << 16);
  260 + ((uint32_t *)tmd)[2] =
  261 + (xda[3] & 0xffff) << 16;
  262 + ((uint32_t *)tmd)[3] = 0;
  263 + }
  264 + else
  265 + if (BCR_SWSTYLE(s) != 3)
  266 + cpu_physical_memory_read(addr, (void *)tmd, 16);
  267 + else {
  268 + uint32_t xda[4];
  269 + cpu_physical_memory_read(addr,
  270 + (void *)&xda[0], sizeof(xda));
  271 + ((uint32_t *)tmd)[0] = xda[2];
  272 + ((uint32_t *)tmd)[1] = xda[1];
  273 + ((uint32_t *)tmd)[2] = xda[0];
  274 + ((uint32_t *)tmd)[3] = xda[3];
  275 + }
  276 +}
  277 +
  278 +static inline void pcnet_tmd_store(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr)
  279 +{
  280 + if (!BCR_SWSTYLE(s)) {
  281 + uint16_t xda[4];
  282 + xda[0] = ((uint32_t *)tmd)[0] & 0xffff;
  283 + xda[1] = ((((uint32_t *)tmd)[0]>>16)&0x00ff) |
  284 + ((((uint32_t *)tmd)[1]>>16)&0xff00);
  285 + xda[2] = ((uint32_t *)tmd)[1] & 0xffff;
  286 + xda[3] = ((uint32_t *)tmd)[2] >> 16;
  287 + cpu_physical_memory_write(addr,
  288 + (void *)&xda[0], sizeof(xda));
  289 + }
  290 + else {
  291 + if (BCR_SWSTYLE(s) != 3)
  292 + cpu_physical_memory_write(addr, (void *)tmd, 16);
  293 + else {
  294 + uint32_t xda[4];
  295 + xda[0] = ((uint32_t *)tmd)[2];
  296 + xda[1] = ((uint32_t *)tmd)[1];
  297 + xda[2] = ((uint32_t *)tmd)[0];
  298 + xda[3] = ((uint32_t *)tmd)[3];
  299 + cpu_physical_memory_write(addr,
  300 + (void *)&xda[0], sizeof(xda));
  301 + }
  302 + }
  303 +}
  304 +
  305 +static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr)
  306 +{
  307 + if (!BCR_SWSTYLE(s)) {
  308 + uint16_t rda[4];
  309 + cpu_physical_memory_read(addr,
  310 + (void *)&rda[0], sizeof(rda));
  311 + ((uint32_t *)rmd)[0] = (rda[0]&0xffff)|
  312 + ((rda[1] & 0x00ff) << 16);
  313 + ((uint32_t *)rmd)[1] = (rda[2]&0xffff)|
  314 + ((rda[1] & 0xff00) << 16);
  315 + ((uint32_t *)rmd)[2] = rda[3] & 0xffff;
  316 + ((uint32_t *)rmd)[3] = 0;
  317 + }
  318 + else
  319 + if (BCR_SWSTYLE(s) != 3)
  320 + cpu_physical_memory_read(addr, (void *)rmd, 16);
  321 + else {
  322 + uint32_t rda[4];
  323 + cpu_physical_memory_read(addr,
  324 + (void *)&rda[0], sizeof(rda));
  325 + ((uint32_t *)rmd)[0] = rda[2];
  326 + ((uint32_t *)rmd)[1] = rda[1];
  327 + ((uint32_t *)rmd)[2] = rda[0];
  328 + ((uint32_t *)rmd)[3] = rda[3];
  329 + }
  330 +}
  331 +
  332 +static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr)
  333 +{
  334 + if (!BCR_SWSTYLE(s)) {
  335 + uint16_t rda[4]; \
  336 + rda[0] = ((uint32_t *)rmd)[0] & 0xffff; \
  337 + rda[1] = ((((uint32_t *)rmd)[0]>>16)&0xff)|\
  338 + ((((uint32_t *)rmd)[1]>>16)&0xff00);\
  339 + rda[2] = ((uint32_t *)rmd)[1] & 0xffff; \
  340 + rda[3] = ((uint32_t *)rmd)[2] & 0xffff; \
  341 + cpu_physical_memory_write(addr, \
  342 + (void *)&rda[0], sizeof(rda)); \
  343 + }
  344 + else {
  345 + if (BCR_SWSTYLE(s) != 3)
  346 + cpu_physical_memory_write(addr, (void *)rmd, 16);
  347 + else {
  348 + uint32_t rda[4];
  349 + rda[0] = ((uint32_t *)rmd)[2];
  350 + rda[1] = ((uint32_t *)rmd)[1];
  351 + rda[2] = ((uint32_t *)rmd)[0];
  352 + rda[3] = ((uint32_t *)rmd)[3];
  353 + cpu_physical_memory_write(addr,
  354 + (void *)&rda[0], sizeof(rda));
  355 + }
  356 + }
  357 +}
  358 +
  359 +
  360 +#define TMDLOAD(TMD,ADDR) pcnet_tmd_load(s,TMD,ADDR)
  361 +
  362 +#define TMDSTORE(TMD,ADDR) pcnet_tmd_store(s,TMD,ADDR)
  363 +
  364 +#define RMDLOAD(RMD,ADDR) pcnet_rmd_load(s,RMD,ADDR)
  365 +
  366 +#define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR)
  367 +
  368 +#if 1
  369 +
  370 +#define CHECK_RMD(ADDR,RES) do { \
  371 + struct pcnet_RMD rmd; \
  372 + RMDLOAD(&rmd,(ADDR)); \
  373 + (RES) |= (rmd.rmd1.ones != 15) \
  374 + || (rmd.rmd2.zeros != 0); \
  375 +} while (0)
  376 +
  377 +#define CHECK_TMD(ADDR,RES) do { \
  378 + struct pcnet_TMD tmd; \
  379 + TMDLOAD(&tmd,(ADDR)); \
  380 + (RES) |= (tmd.tmd1.ones != 15); \
  381 +} while (0)
  382 +
  383 +#else
  384 +
  385 +#define CHECK_RMD(ADDR,RES) do { \
  386 + switch (BCR_SWSTYLE(s)) { \
  387 + case 0x00: \
  388 + do { \
  389 + uint16_t rda[4]; \
  390 + cpu_physical_memory_read((ADDR), \
  391 + (void *)&rda[0], sizeof(rda)); \
  392 + (RES) |= (rda[2] & 0xf000)!=0xf000; \
  393 + (RES) |= (rda[3] & 0xf000)!=0x0000; \
  394 + } while (0); \
  395 + break; \
  396 + case 0x01: \
  397 + case 0x02: \
  398 + do { \
  399 + uint32_t rda[4]; \
  400 + cpu_physical_memory_read((ADDR), \
  401 + (void *)&rda[0], sizeof(rda)); \
  402 + (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
  403 + (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \
  404 + } while (0); \
  405 + break; \
  406 + case 0x03: \
  407 + do { \
  408 + uint32_t rda[4]; \
  409 + cpu_physical_memory_read((ADDR), \
  410 + (void *)&rda[0], sizeof(rda)); \
  411 + (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \
  412 + (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
  413 + } while (0); \
  414 + break; \
  415 + } \
  416 +} while (0)
  417 +
  418 +#define CHECK_TMD(ADDR,RES) do { \
  419 + switch (BCR_SWSTYLE(s)) { \
  420 + case 0x00: \
  421 + do { \
  422 + uint16_t xda[4]; \
  423 + cpu_physical_memory_read((ADDR), \
  424 + (void *)&xda[0], sizeof(xda)); \
  425 + (RES) |= (xda[2] & 0xf000)!=0xf000;\
  426 + } while (0); \
  427 + break; \
  428 + case 0x01: \
  429 + case 0x02: \
  430 + case 0x03: \
  431 + do { \
  432 + uint32_t xda[4]; \
  433 + cpu_physical_memory_read((ADDR), \
  434 + (void *)&xda[0], sizeof(xda)); \
  435 + (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \
  436 + } while (0); \
  437 + break; \
  438 + } \
  439 +} while (0)
  440 +
  441 +#endif
  442 +
  443 +#define PRINT_PKTHDR(BUF) do { \
  444 + struct ether_header *hdr = (void *)(BUF); \
  445 + printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \
  446 + "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \
  447 + "type=0x%04x (bcast=%d)\n", \
  448 + hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \
  449 + hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \
  450 + hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \
  451 + hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \
  452 + htons(hdr->ether_type), \
  453 + !!ETHER_IS_MULTICAST(hdr->ether_dhost)); \
  454 +} while (0)
  455 +
  456 +#define MULTICAST_FILTER_LEN 8
  457 +
  458 +static inline uint32_t lnc_mchash(const uint8_t *ether_addr)
  459 +{
  460 +#define LNC_POLYNOMIAL 0xEDB88320UL
  461 + uint32_t crc = 0xFFFFFFFF;
  462 + int idx, bit;
  463 + uint8_t data;
  464 +
  465 + for (idx = 0; idx < ETHER_ADDR_LEN; idx++) {
  466 + for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) {
  467 + crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0);
  468 + data >>= 1;
  469 + }
  470 + }
  471 + return crc;
  472 +#undef LNC_POLYNOMIAL
  473 +}
  474 +
  475 +#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
  476 +
  477 +/* generated using the AUTODIN II polynomial
  478 + * x^32 + x^26 + x^23 + x^22 + x^16 +
  479 + * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
  480 + */
  481 +static const uint32_t crctab[256] = {
  482 + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
  483 + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
  484 + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
  485 + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
  486 + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
  487 + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
  488 + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
  489 + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
  490 + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
  491 + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
  492 + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
  493 + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
  494 + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
  495 + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
  496 + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
  497 + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
  498 + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
  499 + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
  500 + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
  501 + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
  502 + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
  503 + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
  504 + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
  505 + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
  506 + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
  507 + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
  508 + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
  509 + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
  510 + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
  511 + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
  512 + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
  513 + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
  514 + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
  515 + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
  516 + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
  517 + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
  518 + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
  519 + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
  520 + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
  521 + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
  522 + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
  523 + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
  524 + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
  525 + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
  526 + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
  527 + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
  528 + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
  529 + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
  530 + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
  531 + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
  532 + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
  533 + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
  534 + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
  535 + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
  536 + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
  537 + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
  538 + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
  539 + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
  540 + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
  541 + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
  542 + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
  543 + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
  544 + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
  545 + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
  546 +};
  547 +
  548 +static inline int padr_match(PCNetState *s, const uint8_t *buf, int size)
  549 +{
  550 + struct ether_header *hdr = (void *)buf;
  551 + uint8_t padr[6] = {
  552 + s->csr[12] & 0xff, s->csr[12] >> 8,
  553 + s->csr[13] & 0xff, s->csr[13] >> 8,
  554 + s->csr[14] & 0xff, s->csr[14] >> 8
  555 + };
  556 + int result = (!CSR_DRCVPA(s)) && !bcmp(hdr->ether_dhost, padr, 6);
  557 +#ifdef PCNET_DEBUG_MATCH
  558 + printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, "
  559 + "padr=%02x:%02x:%02x:%02x:%02x:%02x\n",
  560 + hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2],
  561 + hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5],
  562 + padr[0],padr[1],padr[2],padr[3],padr[4],padr[5]);
  563 + printf("padr_match result=%d\n", result);
  564 +#endif
  565 + return result;
  566 +}
  567 +
  568 +static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size)
  569 +{
  570 + static uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  571 + struct ether_header *hdr = (void *)buf;
  572 + int result = !CSR_DRCVBC(s) && !bcmp(hdr->ether_dhost, BCAST, 6);
  573 +#ifdef PCNET_DEBUG_MATCH
  574 + printf("padr_bcast result=%d\n", result);
  575 +#endif
  576 + return result;
  577 +}
  578 +
  579 +static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size)
  580 +{
  581 + struct ether_header *hdr = (void *)buf;
  582 + if ((*(hdr->ether_dhost)&0x01) &&
  583 + ((uint64_t *)&s->csr[8])[0] != 0LL) {
  584 + uint8_t ladr[8] = {
  585 + s->csr[8] & 0xff, s->csr[8] >> 8,
  586 + s->csr[9] & 0xff, s->csr[9] >> 8,
  587 + s->csr[10] & 0xff, s->csr[10] >> 8,
  588 + s->csr[11] & 0xff, s->csr[11] >> 8
  589 + };
  590 + int index = lnc_mchash(hdr->ether_dhost) >> 26;
  591 + return !!(ladr[index >> 3] & (1 << (index & 7)));
  592 + }
  593 + return 0;
  594 +}
  595 +
  596 +static inline target_phys_addr_t pcnet_rdra_addr(PCNetState *s, int idx)
  597 +{
  598 + while (idx < 1) idx += CSR_RCVRL(s);
  599 + return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8));
  600 +}
  601 +
  602 +static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time)
  603 +{
  604 + int64_t next_time = current_time +
  605 + muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)),
  606 + ticks_per_sec, 33000000L);
  607 + if (next_time <= current_time)
  608 + next_time = current_time + 1;
  609 + return next_time;
  610 +}
  611 +
  612 +static void pcnet_poll(PCNetState *s);
  613 +static void pcnet_poll_timer(void *opaque);
  614 +
  615 +static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap);
  616 +static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value);
  617 +static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val);
  618 +static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
  619 +
  620 +static void pcnet_s_reset(PCNetState *s)
  621 +{
  622 +#ifdef PCNET_DEBUG
  623 + printf("pcnet_s_reset\n");
  624 +#endif
  625 +
  626 + s->lnkst = 0x40;
  627 + s->rdra = 0;
  628 + s->tdra = 0;
  629 + s->rap = 0;
  630 +
  631 + s->bcr[BCR_BSBC] &= ~0x0080;
  632 +
  633 + s->csr[0] = 0x0004;
  634 + s->csr[3] = 0x0000;
  635 + s->csr[4] = 0x0115;
  636 + s->csr[5] = 0x0000;
  637 + s->csr[6] = 0x0000;
  638 + s->csr[8] = 0;
  639 + s->csr[9] = 0;
  640 + s->csr[10] = 0;
  641 + s->csr[11] = 0;
  642 + s->csr[12] = le16_to_cpu(((uint16_t *)&s->prom[0])[0]);
  643 + s->csr[13] = le16_to_cpu(((uint16_t *)&s->prom[0])[1]);
  644 + s->csr[14] = le16_to_cpu(((uint16_t *)&s->prom[0])[2]);
  645 + s->csr[15] &= 0x21c4;
  646 + s->csr[72] = 1;
  647 + s->csr[74] = 1;
  648 + s->csr[76] = 1;
  649 + s->csr[78] = 1;
  650 + s->csr[80] = 0x1410;
  651 + s->csr[88] = 0x1003;
  652 + s->csr[89] = 0x0262;
  653 + s->csr[94] = 0x0000;
  654 + s->csr[100] = 0x0200;
  655 + s->csr[103] = 0x0105;
  656 + s->csr[103] = 0x0105;
  657 + s->csr[112] = 0x0000;
  658 + s->csr[114] = 0x0000;
  659 + s->csr[122] = 0x0000;
  660 + s->csr[124] = 0x0000;
  661 +}
  662 +
  663 +static void pcnet_update_irq(PCNetState *s)
  664 +{
  665 + int isr = 0;
  666 + s->csr[0] &= ~0x0080;
  667 +
  668 +#if 1
  669 + if (((s->csr[0] & ~s->csr[3]) & 0x5f00) ||
  670 + (((s->csr[4]>>1) & ~s->csr[4]) & 0x0115) ||
  671 + (((s->csr[5]>>1) & s->csr[5]) & 0x0048))
  672 +#else
  673 + if ((!(s->csr[3] & 0x4000) && !!(s->csr[0] & 0x4000)) /* BABL */ ||
  674 + (!(s->csr[3] & 0x1000) && !!(s->csr[0] & 0x1000)) /* MISS */ ||
  675 + (!(s->csr[3] & 0x0100) && !!(s->csr[0] & 0x0100)) /* IDON */ ||
  676 + (!(s->csr[3] & 0x0200) && !!(s->csr[0] & 0x0200)) /* TINT */ ||
  677 + (!(s->csr[3] & 0x0400) && !!(s->csr[0] & 0x0400)) /* RINT */ ||
  678 + (!(s->csr[3] & 0x0800) && !!(s->csr[0] & 0x0800)) /* MERR */ ||
  679 + (!(s->csr[4] & 0x0001) && !!(s->csr[4] & 0x0002)) /* JAB */ ||
  680 + (!(s->csr[4] & 0x0004) && !!(s->csr[4] & 0x0008)) /* TXSTRT */ ||
  681 + (!(s->csr[4] & 0x0010) && !!(s->csr[4] & 0x0020)) /* RCVO */ ||
  682 + (!(s->csr[4] & 0x0100) && !!(s->csr[4] & 0x0200)) /* MFCO */ ||
  683 + (!!(s->csr[5] & 0x0040) && !!(s->csr[5] & 0x0080)) /* EXDINT */ ||
  684 + (!!(s->csr[5] & 0x0008) && !!(s->csr[5] & 0x0010)) /* MPINT */)
  685 +#endif
  686 + {
  687 +
  688 + isr = CSR_INEA(s);
  689 + s->csr[0] |= 0x0080;
  690 + }
  691 +
  692 + if (!!(s->csr[4] & 0x0080) && CSR_INEA(s)) { /* UINT */
  693 + s->csr[4] &= ~0x0080;
  694 + s->csr[4] |= 0x0040;
  695 + s->csr[0] |= 0x0080;
  696 + isr = 1;
  697 +#ifdef PCNET_DEBUG
  698 + printf("pcnet user int\n");
  699 +#endif
  700 + }
  701 +
  702 +#if 1
  703 + if (((s->csr[5]>>1) & s->csr[5]) & 0x0500)
  704 +#else
  705 + if ((!!(s->csr[5] & 0x0400) && !!(s->csr[5] & 0x0800)) /* SINT */ ||
  706 + (!!(s->csr[5] & 0x0100) && !!(s->csr[5] & 0x0200)) /* SLPINT */ )
  707 +#endif
  708 + {
  709 + isr = 1;
  710 + s->csr[0] |= 0x0080;
  711 + }
  712 +
  713 + if (isr != s->isr) {
  714 +#ifdef PCNET_DEBUG
  715 + printf("pcnet: INTA=%d\n", isr);
  716 +#endif
  717 + }
  718 + pci_set_irq(&s->dev, 0, isr);
  719 + s->isr = isr;
  720 +}
  721 +
  722 +static void pcnet_init(PCNetState *s)
  723 +{
  724 +#ifdef PCNET_DEBUG
  725 + printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s)));
  726 +#endif
  727 +
  728 +#define PCNET_INIT() do { \
  729 + cpu_physical_memory_read(PHYSADDR(s,CSR_IADR(s)), \
  730 + (uint8_t *)&initblk, sizeof(initblk)); \
  731 + s->csr[15] = le16_to_cpu(initblk.mode); \
  732 + CSR_RCVRL(s) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \
  733 + CSR_XMTRL(s) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \
  734 + s->csr[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8); \
  735 + s->csr[ 8] = le16_to_cpu(initblk.ladrf1); \
  736 + s->csr[ 9] = le16_to_cpu(initblk.ladrf2); \
  737 + s->csr[10] = le16_to_cpu(initblk.ladrf3); \
  738 + s->csr[11] = le16_to_cpu(initblk.ladrf4); \
  739 + s->csr[12] = le16_to_cpu(initblk.padr1); \
  740 + s->csr[13] = le16_to_cpu(initblk.padr2); \
  741 + s->csr[14] = le16_to_cpu(initblk.padr3); \
  742 + s->rdra = PHYSADDR(s,initblk.rdra); \
  743 + s->tdra = PHYSADDR(s,initblk.tdra); \
  744 +} while (0)
  745 +
  746 + if (BCR_SSIZE32(s)) {
  747 + struct pcnet_initblk32 initblk;
  748 + PCNET_INIT();
  749 +#ifdef PCNET_DEBUG
  750 + printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n",
  751 + initblk.rlen, initblk.tlen);
  752 +#endif
  753 + } else {
  754 + struct pcnet_initblk16 initblk;
  755 + PCNET_INIT();
  756 +#ifdef PCNET_DEBUG
  757 + printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n",
  758 + initblk.rlen, initblk.tlen);
  759 +#endif
  760 + }
  761 +
  762 +#undef PCNET_INIT
  763 +
  764 + CSR_RCVRC(s) = CSR_RCVRL(s);
  765 + CSR_XMTRC(s) = CSR_XMTRL(s);
  766 +
  767 +#ifdef PCNET_DEBUG
  768 + printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n",
  769 + BCR_SSIZE32(s),
  770 + s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s));
  771 +#endif
  772 +
  773 + s->csr[0] |= 0x0101;
  774 + s->csr[0] &= ~0x0004; /* clear STOP bit */
  775 +}
  776 +
  777 +static void pcnet_start(PCNetState *s)
  778 +{
  779 +#ifdef PCNET_DEBUG
  780 + printf("pcnet_start\n");
  781 +#endif
  782 +
  783 + if (!CSR_DTX(s))
  784 + s->csr[0] |= 0x0010; /* set TXON */
  785 +
  786 + if (!CSR_DRX(s))
  787 + s->csr[0] |= 0x0020; /* set RXON */
  788 +
  789 + s->csr[0] &= ~0x0004; /* clear STOP bit */
  790 + s->csr[0] |= 0x0002;
  791 +}
  792 +
  793 +static void pcnet_stop(PCNetState *s)
  794 +{
  795 +#ifdef PCNET_DEBUG
  796 + printf("pcnet_stop\n");
  797 +#endif
  798 + s->csr[0] &= ~0x7feb;
  799 + s->csr[0] |= 0x0014;
  800 + s->csr[4] &= ~0x02c2;
  801 + s->csr[5] &= ~0x0011;
  802 + pcnet_poll_timer(s);
  803 +}
  804 +
  805 +static void pcnet_rdte_poll(PCNetState *s)
  806 +{
  807 + s->csr[28] = s->csr[29] = 0;
  808 + if (s->rdra) {
  809 + int bad = 0;
  810 +#if 1
  811 + target_phys_addr_t crda = pcnet_rdra_addr(s, CSR_RCVRC(s));
  812 + target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s));
  813 + target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s));
  814 +#else
  815 + target_phys_addr_t crda = s->rdra +
  816 + (CSR_RCVRL(s) - CSR_RCVRC(s)) *
  817 + (BCR_SWSTYLE(s) ? 16 : 8 );
  818 + int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1;
  819 + target_phys_addr_t nrda = s->rdra +
  820 + (CSR_RCVRL(s) - nrdc) *
  821 + (BCR_SWSTYLE(s) ? 16 : 8 );
  822 + int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1;
  823 + target_phys_addr_t nnrd = s->rdra +
  824 + (CSR_RCVRL(s) - nnrc) *
  825 + (BCR_SWSTYLE(s) ? 16 : 8 );
  826 +#endif
  827 +
  828 + CHECK_RMD(PHYSADDR(s,crda), bad);
  829 + if (!bad) {
  830 + CHECK_RMD(PHYSADDR(s,nrda), bad);
  831 + if (bad || (nrda == crda)) nrda = 0;
  832 + CHECK_RMD(PHYSADDR(s,nnrd), bad);
  833 + if (bad || (nnrd == crda)) nnrd = 0;
  834 +
  835 + s->csr[28] = crda & 0xffff;
  836 + s->csr[29] = crda >> 16;
  837 + s->csr[26] = nrda & 0xffff;
  838 + s->csr[27] = nrda >> 16;
  839 + s->csr[36] = nnrd & 0xffff;
  840 + s->csr[37] = nnrd >> 16;
  841 +#ifdef PCNET_DEBUG
  842 + if (bad) {
  843 + printf("pcnet: BAD RMD RECORDS AFTER 0x%08x\n",
  844 + PHYSADDR(s,crda));
  845 + }
  846 + } else {
  847 + printf("pcnet: BAD RMD RDA=0x%08x\n", PHYSADDR(s,crda));
  848 +#endif
  849 + }
  850 + }
  851 +
  852 + if (CSR_CRDA(s)) {
  853 + struct pcnet_RMD rmd;
  854 + RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s)));
  855 + CSR_CRBC(s) = rmd.rmd1.bcnt;
  856 + CSR_CRST(s) = ((uint32_t *)&rmd)[1] >> 16;
  857 +#ifdef PCNET_DEBUG_RMD_X
  858 + printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMD1=0x%08x RMD2=0x%08x\n",
  859 + PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s),
  860 + ((uint32_t *)&rmd)[1], ((uint32_t *)&rmd)[2]);
  861 + PRINT_RMD(&rmd);
  862 +#endif
  863 + } else {
  864 + CSR_CRBC(s) = CSR_CRST(s) = 0;
  865 + }
  866 +
  867 + if (CSR_NRDA(s)) {
  868 + struct pcnet_RMD rmd;
  869 + RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s)));
  870 + CSR_NRBC(s) = rmd.rmd1.bcnt;
  871 + CSR_NRST(s) = ((uint32_t *)&rmd)[1] >> 16;
  872 + } else {
  873 + CSR_NRBC(s) = CSR_NRST(s) = 0;
  874 + }
  875 +
  876 +}
  877 +
  878 +static int pcnet_tdte_poll(PCNetState *s)
  879 +{
  880 + s->csr[34] = s->csr[35] = 0;
  881 + if (s->tdra) {
  882 + target_phys_addr_t cxda = s->tdra +
  883 + (CSR_XMTRL(s) - CSR_XMTRC(s)) *
  884 + (BCR_SWSTYLE(s) ? 16 : 8 );
  885 + int bad = 0;
  886 + CHECK_TMD(PHYSADDR(s, cxda),bad);
  887 + if (!bad) {
  888 + if (CSR_CXDA(s) != cxda) {
  889 + s->csr[60] = s->csr[34];
  890 + s->csr[61] = s->csr[35];
  891 + s->csr[62] = CSR_CXBC(s);
  892 + s->csr[63] = CSR_CXST(s);
  893 + }
  894 + s->csr[34] = cxda & 0xffff;
  895 + s->csr[35] = cxda >> 16;
  896 +#ifdef PCNET_DEBUG
  897 + } else {
  898 + printf("pcnet: BAD TMD XDA=0x%08x\n", PHYSADDR(s,cxda));
  899 +#endif
  900 + }
  901 + }
  902 +
  903 + if (CSR_CXDA(s)) {
  904 + struct pcnet_TMD tmd;
  905 +
  906 + TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
  907 +
  908 + CSR_CXBC(s) = tmd.tmd1.bcnt;
  909 + CSR_CXST(s) = ((uint32_t *)&tmd)[1] >> 16;
  910 + } else {
  911 + CSR_CXBC(s) = CSR_CXST(s) = 0;
  912 + }
  913 +
  914 + return !!(CSR_CXST(s) & 0x8000);
  915 +}
  916 +
  917 +static int pcnet_can_receive(void *opaque)
  918 +{
  919 + PCNetState *s = opaque;
  920 + if (CSR_STOP(s) || CSR_SPND(s))
  921 + return 0;
  922 +
  923 + if (s->recv_pos > 0)
  924 + return 0;
  925 +
  926 + return sizeof(s->buffer)-16;
  927 +}
  928 +
  929 +#define MIN_BUF_SIZE 60
  930 +
  931 +static void pcnet_receive(void *opaque, const uint8_t *buf, int size)
  932 +{
  933 + PCNetState *s = opaque;
  934 + int is_padr = 0, is_bcast = 0, is_ladr = 0;
  935 + uint8_t buf1[60];
  936 +
  937 + if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size)
  938 + return;
  939 +
  940 +#ifdef PCNET_DEBUG
  941 + printf("pcnet_receive size=%d\n", size);
  942 +#endif
  943 +
  944 + /* if too small buffer, then expand it */
  945 + if (size < MIN_BUF_SIZE) {
  946 + memcpy(buf1, buf, size);
  947 + memset(buf1 + size, 0, MIN_BUF_SIZE - size);
  948 + buf = buf1;
  949 + size = MIN_BUF_SIZE;
  950 + }
  951 +
  952 + if (CSR_PROM(s)
  953 + || (is_padr=padr_match(s, buf, size))
  954 + || (is_bcast=padr_bcast(s, buf, size))
  955 + || (is_ladr=ladr_match(s, buf, size))) {
  956 +
  957 + pcnet_rdte_poll(s);
  958 +
  959 + if (!(CSR_CRST(s) & 0x8000) && s->rdra) {
  960 + struct pcnet_RMD rmd;
  961 + int rcvrc = CSR_RCVRC(s)-1,i;
  962 + target_phys_addr_t nrda;
  963 + for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) {
  964 + if (rcvrc <= 1)
  965 + rcvrc = CSR_RCVRL(s);
  966 + nrda = s->rdra +
  967 + (CSR_RCVRL(s) - rcvrc) *
  968 + (BCR_SWSTYLE(s) ? 16 : 8 );
  969 + RMDLOAD(&rmd, PHYSADDR(s,nrda));
  970 + if (rmd.rmd1.own) {
  971 +#ifdef PCNET_DEBUG_RMD
  972 + printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n",
  973 + rcvrc, CSR_RCVRC(s));
  974 +#endif
  975 + CSR_RCVRC(s) = rcvrc;
  976 + pcnet_rdte_poll(s);
  977 + break;
  978 + }
  979 + }
  980 + }
  981 +
  982 + if (!(CSR_CRST(s) & 0x8000)) {
  983 +#ifdef PCNET_DEBUG_RMD
  984 + printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s));
  985 +#endif
  986 + s->csr[0] |= 0x1000; /* Set MISS flag */
  987 + CSR_MISSC(s)++;
  988 + } else {
  989 + uint8_t *src = &s->buffer[8];
  990 + target_phys_addr_t crda = CSR_CRDA(s);
  991 + struct pcnet_RMD rmd;
  992 + int pktcount = 0;
  993 +
  994 + memcpy(src, buf, size);
  995 +
  996 + /* XXX: avoid CRC generation */
  997 + if (!CSR_ASTRP_RCV(s)) {
  998 + uint32_t fcs = ~0;
  999 +#if 0
  1000 + uint8_t *p = s->buffer;
  1001 +
  1002 + ((uint32_t *)p)[0] = ((uint32_t *)p)[1] = 0xaaaaaaaa;
  1003 + p[7] = 0xab;
  1004 +#else
  1005 + uint8_t *p = src;
  1006 +#endif
  1007 +
  1008 + while (size < 46) {
  1009 + src[size++] = 0;
  1010 + }
  1011 +
  1012 + while (p != &src[size]) {
  1013 + CRC(fcs, *p++);
  1014 + }
  1015 + ((uint32_t *)&src[size])[0] = htonl(fcs);
  1016 + size += 4; /* FCS at end of packet */
  1017 + } else size += 4;
  1018 +
  1019 +#ifdef PCNET_DEBUG_MATCH
  1020 + PRINT_PKTHDR(buf);
  1021 +#endif
  1022 +
  1023 + RMDLOAD(&rmd, PHYSADDR(s,crda));
  1024 + /*if (!CSR_LAPPEN(s))*/
  1025 + rmd.rmd1.stp = 1;
  1026 +
  1027 +#define PCNET_RECV_STORE() do { \
  1028 + int count = MIN(4096 - rmd.rmd1.bcnt,size); \
  1029 + target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr); \
  1030 + cpu_physical_memory_write(rbadr, src, count); \
  1031 + src += count; size -= count; \
  1032 + rmd.rmd2.mcnt = count; rmd.rmd1.own = 0; \
  1033 + RMDSTORE(&rmd, PHYSADDR(s,crda)); \
  1034 + pktcount++; \
  1035 +} while (0)
  1036 +
  1037 + PCNET_RECV_STORE();
  1038 + if ((size > 0) && CSR_NRDA(s)) {
  1039 + target_phys_addr_t nrda = CSR_NRDA(s);
  1040 + RMDLOAD(&rmd, PHYSADDR(s,nrda));
  1041 + if (rmd.rmd1.own) {
  1042 + crda = nrda;
  1043 + PCNET_RECV_STORE();
  1044 + if ((size > 0) && (nrda=CSR_NNRD(s))) {
  1045 + RMDLOAD(&rmd, PHYSADDR(s,nrda));
  1046 + if (rmd.rmd1.own) {
  1047 + crda = nrda;
  1048 + PCNET_RECV_STORE();
  1049 + }
  1050 + }
  1051 + }
  1052 + }
  1053 +
  1054 +#undef PCNET_RECV_STORE
  1055 +
  1056 + RMDLOAD(&rmd, PHYSADDR(s,crda));
  1057 + if (size == 0) {
  1058 + rmd.rmd1.enp = 1;
  1059 + rmd.rmd1.pam = !CSR_PROM(s) && is_padr;
  1060 + rmd.rmd1.lafm = !CSR_PROM(s) && is_ladr;
  1061 + rmd.rmd1.bam = !CSR_PROM(s) && is_bcast;
  1062 + } else {
  1063 + rmd.rmd1.oflo = 1;
  1064 + rmd.rmd1.buff = 1;
  1065 + rmd.rmd1.err = 1;
  1066 + }
  1067 + RMDSTORE(&rmd, PHYSADDR(s,crda));
  1068 + s->csr[0] |= 0x0400;
  1069 +
  1070 +#ifdef PCNET_DEBUG
  1071 + printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n",
  1072 + CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount);
  1073 +#endif
  1074 +#ifdef PCNET_DEBUG_RMD
  1075 + PRINT_RMD(&rmd);
  1076 +#endif
  1077 +
  1078 + while (pktcount--) {
  1079 + if (CSR_RCVRC(s) <= 1)
  1080 + CSR_RCVRC(s) = CSR_RCVRL(s);
  1081 + else
  1082 + CSR_RCVRC(s)--;
  1083 + }
  1084 +
  1085 + pcnet_rdte_poll(s);
  1086 +
  1087 + }
  1088 + }
  1089 +
  1090 + pcnet_poll(s);
  1091 + pcnet_update_irq(s);
  1092 +}
  1093 +
  1094 +static void pcnet_transmit(PCNetState *s)
  1095 +{
  1096 + target_phys_addr_t xmit_cxda = 0;
  1097 + int count = CSR_XMTRL(s)-1;
  1098 + s->xmit_pos = -1;
  1099 +
  1100 + if (!CSR_TXON(s)) {
  1101 + s->csr[0] &= ~0x0008;
  1102 + return;
  1103 + }
  1104 +
  1105 + txagain:
  1106 + if (pcnet_tdte_poll(s)) {
  1107 + struct pcnet_TMD tmd;
  1108 +
  1109 + TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
  1110 +
  1111 +#ifdef PCNET_DEBUG_TMD
  1112 + printf(" TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s)));
  1113 + PRINT_TMD(&tmd);
  1114 +#endif
  1115 + if (tmd.tmd1.stp) {
  1116 + s->xmit_pos = 0;
  1117 + if (!tmd.tmd1.enp) {
  1118 + cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr),
  1119 + s->buffer, 4096 - tmd.tmd1.bcnt);
  1120 + s->xmit_pos += 4096 - tmd.tmd1.bcnt;
  1121 + }
  1122 + xmit_cxda = PHYSADDR(s,CSR_CXDA(s));
  1123 + }
  1124 + if (tmd.tmd1.enp && (s->xmit_pos >= 0)) {
  1125 + cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr),
  1126 + s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt);
  1127 + s->xmit_pos += 4096 - tmd.tmd1.bcnt;
  1128 +#ifdef PCNET_DEBUG
  1129 + printf("pcnet_transmit size=%d\n", s->xmit_pos);
  1130 +#endif
  1131 + if (CSR_LOOP(s))
  1132 + pcnet_receive(s, s->buffer, s->xmit_pos);
  1133 + else
  1134 + qemu_send_packet(s->vc, s->buffer, s->xmit_pos);
  1135 +
  1136 + s->csr[0] &= ~0x0008; /* clear TDMD */
  1137 + s->csr[4] |= 0x0004; /* set TXSTRT */
  1138 + s->xmit_pos = -1;
  1139 + }
  1140 +
  1141 + tmd.tmd1.own = 0;
  1142 + TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
  1143 + if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && tmd.tmd1.ltint))
  1144 + s->csr[0] |= 0x0200; /* set TINT */
  1145 +
  1146 + if (CSR_XMTRC(s)<=1)
  1147 + CSR_XMTRC(s) = CSR_XMTRL(s);
  1148 + else
  1149 + CSR_XMTRC(s)--;
  1150 + if (count--)
  1151 + goto txagain;
  1152 +
  1153 + } else
  1154 + if (s->xmit_pos >= 0) {
  1155 + struct pcnet_TMD tmd;
  1156 + TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda));
  1157 + tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1;
  1158 + tmd.tmd1.own = 0;
  1159 + TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda));
  1160 + s->csr[0] |= 0x0200; /* set TINT */
  1161 + if (!CSR_DXSUFLO(s)) {
  1162 + s->csr[0] &= ~0x0010;
  1163 + } else
  1164 + if (count--)
  1165 + goto txagain;
  1166 + }
  1167 +}
  1168 +
  1169 +static void pcnet_poll(PCNetState *s)
  1170 +{
  1171 + if (CSR_RXON(s)) {
  1172 + pcnet_rdte_poll(s);
  1173 + }
  1174 +
  1175 + if (CSR_TDMD(s) ||
  1176 + (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s)))
  1177 + pcnet_transmit(s);
  1178 +}
  1179 +
  1180 +static void pcnet_poll_timer(void *opaque)
  1181 +{
  1182 + PCNetState *s = opaque;
  1183 +
  1184 + qemu_del_timer(s->poll_timer);
  1185 +
  1186 + if (CSR_TDMD(s)) {
  1187 + pcnet_transmit(s);
  1188 + }
  1189 +
  1190 + pcnet_update_irq(s);
  1191 +
  1192 + if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) {
  1193 + uint64_t now = qemu_get_clock(vm_clock) * 33;
  1194 + if (!s->timer || !now)
  1195 + s->timer = now;
  1196 + else {
  1197 + uint64_t t = now - s->timer + CSR_POLL(s);
  1198 + if (t > 0xffffLL) {
  1199 + pcnet_poll(s);
  1200 + CSR_POLL(s) = CSR_PINT(s);
  1201 + } else
  1202 + CSR_POLL(s) = t;
  1203 + }
  1204 + qemu_mod_timer(s->poll_timer,
  1205 + pcnet_get_next_poll_time(s,qemu_get_clock(vm_clock)));
  1206 + }
  1207 +}
  1208 +
  1209 +
  1210 +static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value)
  1211 +{
  1212 + uint16_t val = new_value;
  1213 +#ifdef PCNET_DEBUG_CSR
  1214 + printf("pcnet_csr_writew rap=%d val=0x%04x\n", rap, val);
  1215 +#endif
  1216 + switch (rap) {
  1217 + case 0:
  1218 + s->csr[0] &= ~(val & 0x7f00); /* Clear any interrupt flags */
  1219 +
  1220 + s->csr[0] = (s->csr[0] & ~0x0040) | (val & 0x0048);
  1221 +
  1222 + val = (val & 0x007f) | (s->csr[0] & 0x7f00);
  1223 +
  1224 + /* IFF STOP, STRT and INIT are set, clear STRT and INIT */
  1225 + if ((val&7) == 7)
  1226 + val &= ~3;
  1227 +
  1228 + if (!CSR_STOP(s) && (val & 4))
  1229 + pcnet_stop(s);
  1230 +
  1231 + if (!CSR_INIT(s) && (val & 1))
  1232 + pcnet_init(s);
  1233 +
  1234 + if (!CSR_STRT(s) && (val & 2))
  1235 + pcnet_start(s);
  1236 +
  1237 + if (CSR_TDMD(s))
  1238 + pcnet_transmit(s);
  1239 +
  1240 + return;
  1241 + case 1:
  1242 + case 2:
  1243 + case 8:
  1244 + case 9:
  1245 + case 10:
  1246 + case 11:
  1247 + case 12:
  1248 + case 13:
  1249 + case 14:
  1250 + case 15:
  1251 + case 18: /* CRBAL */
  1252 + case 19: /* CRBAU */
  1253 + case 20: /* CXBAL */
  1254 + case 21: /* CXBAU */
  1255 + case 22: /* NRBAU */
  1256 + case 23: /* NRBAU */
  1257 + case 24:
  1258 + case 25:
  1259 + case 26:
  1260 + case 27:
  1261 + case 28:
  1262 + case 29:
  1263 + case 30:
  1264 + case 31:
  1265 + case 32:
  1266 + case 33:
  1267 + case 34:
  1268 + case 35:
  1269 + case 36:
  1270 + case 37:
  1271 + case 38:
  1272 + case 39:
  1273 + case 40: /* CRBC */
  1274 + case 41:
  1275 + case 42: /* CXBC */
  1276 + case 43:
  1277 + case 44:
  1278 + case 45:
  1279 + case 46: /* POLL */
  1280 + case 47: /* POLLINT */
  1281 + case 72:
  1282 + case 74:
  1283 + case 76: /* RCVRL */
  1284 + case 78: /* XMTRL */
  1285 + case 112:
  1286 + if (CSR_STOP(s) || CSR_SPND(s))
  1287 + break;
  1288 + return;
  1289 + case 3:
  1290 + break;
  1291 + case 4:
  1292 + s->csr[4] &= ~(val & 0x026a);
  1293 + val &= ~0x026a; val |= s->csr[4] & 0x026a;
  1294 + break;
  1295 + case 5:
  1296 + s->csr[5] &= ~(val & 0x0a90);
  1297 + val &= ~0x0a90; val |= s->csr[5] & 0x0a90;
  1298 + break;
  1299 + case 16:
  1300 + pcnet_csr_writew(s,1,val);
  1301 + return;
  1302 + case 17:
  1303 + pcnet_csr_writew(s,2,val);
  1304 + return;
  1305 + case 58:
  1306 + pcnet_bcr_writew(s,BCR_SWS,val);
  1307 + break;
  1308 + default:
  1309 + return;
  1310 + }
  1311 + s->csr[rap] = val;
  1312 +}
  1313 +
  1314 +static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap)
  1315 +{
  1316 + uint32_t val;
  1317 + switch (rap) {
  1318 + case 0:
  1319 + pcnet_update_irq(s);
  1320 + val = s->csr[0];
  1321 + val |= (val & 0x7800) ? 0x8000 : 0;
  1322 + break;
  1323 + case 16:
  1324 + return pcnet_csr_readw(s,1);
  1325 + case 17:
  1326 + return pcnet_csr_readw(s,2);
  1327 + case 58:
  1328 + return pcnet_bcr_readw(s,BCR_SWS);
  1329 + case 88:
  1330 + val = s->csr[89];
  1331 + val <<= 16;
  1332 + val |= s->csr[88];
  1333 + break;
  1334 + default:
  1335 + val = s->csr[rap];
  1336 + }
  1337 +#ifdef PCNET_DEBUG_CSR
  1338 + printf("pcnet_csr_readw rap=%d val=0x%04x\n", rap, val);
  1339 +#endif
  1340 + return val;
  1341 +}
  1342 +
  1343 +static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val)
  1344 +{
  1345 + rap &= 127;
  1346 +#ifdef PCNET_DEBUG_BCR
  1347 + printf("pcnet_bcr_writew rap=%d val=0x%04x\n", rap, val);
  1348 +#endif
  1349 + switch (rap) {
  1350 + case BCR_SWS:
  1351 + if (!(CSR_STOP(s) || CSR_SPND(s)))
  1352 + return;
  1353 + val &= ~0x0300;
  1354 + switch (val & 0x00ff) {
  1355 + case 0:
  1356 + val |= 0x0200;
  1357 + break;
  1358 + case 1:
  1359 + val |= 0x0100;
  1360 + break;
  1361 + case 2:
  1362 + case 3:
  1363 + val |= 0x0300;
  1364 + break;
  1365 + default:
  1366 + printf("Bad SWSTYLE=0x%02x\n", val & 0xff);
  1367 + val = 0x0200;
  1368 + break;
  1369 + }
  1370 +#ifdef PCNET_DEBUG
  1371 + printf("BCR_SWS=0x%04x\n", val);
  1372 +#endif
  1373 + case BCR_LNKST:
  1374 + case BCR_LED1:
  1375 + case BCR_LED2:
  1376 + case BCR_LED3:
  1377 + case BCR_MC:
  1378 + case BCR_FDC:
  1379 + case BCR_BSBC:
  1380 + case BCR_EECAS:
  1381 + case BCR_PLAT:
  1382 + s->bcr[rap] = val;
  1383 + break;
  1384 + default:
  1385 + break;
  1386 + }
  1387 +}
  1388 +
  1389 +static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
  1390 +{
  1391 + uint32_t val;
  1392 + rap &= 127;
  1393 + switch (rap) {
  1394 + case BCR_LNKST:
  1395 + case BCR_LED1:
  1396 + case BCR_LED2:
  1397 + case BCR_LED3:
  1398 + val = s->bcr[rap] & ~0x8000;
  1399 + val |= (val & 0x017f & s->lnkst) ? 0x8000 : 0;
  1400 + break;
  1401 + default:
  1402 + val = rap < 32 ? s->bcr[rap] : 0;
  1403 + break;
  1404 + }
  1405 +#ifdef PCNET_DEBUG_BCR
  1406 + printf("pcnet_bcr_readw rap=%d val=0x%04x\n", rap, val);
  1407 +#endif
  1408 + return val;
  1409 +}
  1410 +
  1411 +static void pcnet_h_reset(PCNetState *s)
  1412 +{
  1413 + int i;
  1414 + uint16_t checksum;
  1415 +
  1416 + /* Initialize the PROM */
  1417 +
  1418 + memcpy(s->prom, s->nd->macaddr, 6);
  1419 + s->prom[12] = s->prom[13] = 0x00;
  1420 + s->prom[14] = s->prom[15] = 0x57;
  1421 +
  1422 + for (i = 0,checksum = 0; i < 16; i++)
  1423 + checksum += s->prom[i];
  1424 + *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum);
  1425 +
  1426 +
  1427 + s->bcr[BCR_MSRDA] = 0x0005;
  1428 + s->bcr[BCR_MSWRA] = 0x0005;
  1429 + s->bcr[BCR_MC ] = 0x0002;
  1430 + s->bcr[BCR_LNKST] = 0x00c0;
  1431 + s->bcr[BCR_LED1 ] = 0x0084;
  1432 + s->bcr[BCR_LED2 ] = 0x0088;
  1433 + s->bcr[BCR_LED3 ] = 0x0090;
  1434 + s->bcr[BCR_FDC ] = 0x0000;
  1435 + s->bcr[BCR_BSBC ] = 0x9001;
  1436 + s->bcr[BCR_EECAS] = 0x0002;
  1437 + s->bcr[BCR_SWS ] = 0x0200;
  1438 + s->bcr[BCR_PLAT ] = 0xff06;
  1439 +
  1440 + pcnet_s_reset(s);
  1441 +}
  1442 +
  1443 +static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
  1444 +{
  1445 + PCNetState *s = opaque;
  1446 +#ifdef PCNET_DEBUG
  1447 + printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);
  1448 +#endif
  1449 + /* Check APROMWE bit to enable write access */
  1450 + if (pcnet_bcr_readw(s,2) & 0x80)
  1451 + s->prom[addr & 15] = val;
  1452 +}
  1453 +
  1454 +static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
  1455 +{
  1456 + PCNetState *s = opaque;
  1457 + uint32_t val = s->prom[addr &= 15];
  1458 +#ifdef PCNET_DEBUG
  1459 + printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val);
  1460 +#endif
  1461 + return val;
  1462 +}
  1463 +
  1464 +static void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
  1465 +{
  1466 + PCNetState *s = opaque;
  1467 + pcnet_poll_timer(s);
  1468 +#ifdef PCNET_DEBUG_IO
  1469 + printf("pcnet_ioport_writew addr=0x%08x val=0x%04x\n", addr, val);
  1470 +#endif
  1471 + if (!BCR_DWIO(s)) {
  1472 + switch (addr & 0x0f) {
  1473 + case 0x00: /* RDP */
  1474 + pcnet_csr_writew(s, s->rap, val);
  1475 + break;
  1476 + case 0x02:
  1477 + s->rap = val & 0x7f;
  1478 + break;
  1479 + case 0x06:
  1480 + pcnet_bcr_writew(s, s->rap, val);
  1481 + break;
  1482 + }
  1483 + }
  1484 + pcnet_update_irq(s);
  1485 +}
  1486 +
  1487 +static uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr)
  1488 +{
  1489 + PCNetState *s = opaque;
  1490 + uint32_t val = -1;
  1491 + pcnet_poll_timer(s);
  1492 + if (!BCR_DWIO(s)) {
  1493 + switch (addr & 0x0f) {
  1494 + case 0x00: /* RDP */
  1495 + val = pcnet_csr_readw(s, s->rap);
  1496 + break;
  1497 + case 0x02:
  1498 + val = s->rap;
  1499 + break;
  1500 + case 0x04:
  1501 + pcnet_s_reset(s);
  1502 + val = 0;
  1503 + break;
  1504 + case 0x06:
  1505 + val = pcnet_bcr_readw(s, s->rap);
  1506 + break;
  1507 + }
  1508 + }
  1509 + pcnet_update_irq(s);
  1510 +#ifdef PCNET_DEBUG_IO
  1511 + printf("pcnet_ioport_readw addr=0x%08x val=0x%04x\n", addr, val & 0xffff);
  1512 +#endif
  1513 + return val;
  1514 +}
  1515 +
  1516 +static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
  1517 +{
  1518 + PCNetState *s = opaque;
  1519 + pcnet_poll_timer(s);
  1520 +#ifdef PCNET_DEBUG_IO
  1521 + printf("pcnet_ioport_writel addr=0x%08x val=0x%08x\n", addr, val);
  1522 +#endif
  1523 + if (BCR_DWIO(s)) {
  1524 + switch (addr & 0x0f) {
  1525 + case 0x00: /* RDP */
  1526 + pcnet_csr_writew(s, s->rap, val & 0xffff);
  1527 + break;
  1528 + case 0x04:
  1529 + s->rap = val & 0x7f;
  1530 + break;
  1531 + case 0x0c:
  1532 + pcnet_bcr_writew(s, s->rap, val & 0xffff);
  1533 + break;
  1534 + }
  1535 + } else
  1536 + if ((addr & 0x0f) == 0) {
  1537 + /* switch device to dword i/o mode */
  1538 + pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080);
  1539 +#ifdef PCNET_DEBUG_IO
  1540 + printf("device switched into dword i/o mode\n");
  1541 +#endif
  1542 + }
  1543 + pcnet_update_irq(s);
  1544 +}
  1545 +
  1546 +static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
  1547 +{
  1548 + PCNetState *s = opaque;
  1549 + uint32_t val = -1;
  1550 + pcnet_poll_timer(s);
  1551 + if (BCR_DWIO(s)) {
  1552 + switch (addr & 0x0f) {
  1553 + case 0x00: /* RDP */
  1554 + val = pcnet_csr_readw(s, s->rap);
  1555 + break;
  1556 + case 0x04:
  1557 + val = s->rap;
  1558 + break;
  1559 + case 0x08:
  1560 + pcnet_s_reset(s);
  1561 + val = 0;
  1562 + break;
  1563 + case 0x0c:
  1564 + val = pcnet_bcr_readw(s, s->rap);
  1565 + break;
  1566 + }
  1567 + }
  1568 + pcnet_update_irq(s);
  1569 +#ifdef PCNET_DEBUG_IO
  1570 + printf("pcnet_ioport_readl addr=0x%08x val=0x%08x\n", addr, val);
  1571 +#endif
  1572 + return val;
  1573 +}
  1574 +
  1575 +static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
  1576 + uint32_t addr, uint32_t size, int type)
  1577 +{
  1578 + PCNetState *d = (PCNetState *)pci_dev;
  1579 +
  1580 +#ifdef PCNET_DEBUG_IO
  1581 + printf("pcnet_ioport_map addr=0x%04x size=0x%04x\n", addr, size);
  1582 +#endif
  1583 +
  1584 + register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
  1585 + register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
  1586 +
  1587 + register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
  1588 + register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
  1589 + register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
  1590 + register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);
  1591 +}
  1592 +
  1593 +static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
  1594 +{
  1595 + PCNetState *d = opaque;
  1596 +#ifdef PCNET_DEBUG_IO
  1597 + printf("pcnet_mmio_writeb addr=0x%08x val=0x%02x\n", addr, val);
  1598 +#endif
  1599 + if (!(addr & 0x10))
  1600 + pcnet_aprom_writeb(d, addr & 0x0f, val);
  1601 +}
  1602 +
  1603 +static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr)
  1604 +{
  1605 + PCNetState *d = opaque;
  1606 + uint32_t val = -1;
  1607 + if (!(addr & 0x10))
  1608 + val = pcnet_aprom_readb(d, addr & 0x0f);
  1609 +#ifdef PCNET_DEBUG_IO
  1610 + printf("pcnet_mmio_readb addr=0x%08x val=0x%02x\n", addr, val & 0xff);
  1611 +#endif
  1612 + return val;
  1613 +}
  1614 +
  1615 +static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
  1616 +{
  1617 + PCNetState *d = opaque;
  1618 +#ifdef PCNET_DEBUG_IO
  1619 + printf("pcnet_mmio_writew addr=0x%08x val=0x%04x\n", addr, val);
  1620 +#endif
  1621 + if (addr & 0x10)
  1622 + pcnet_ioport_writew(d, addr & 0x0f, val);
  1623 + else {
  1624 + addr &= 0x0f;
  1625 + pcnet_aprom_writeb(d, addr, val & 0xff);
  1626 + pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
  1627 + }
  1628 +}
  1629 +
  1630 +static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr)
  1631 +{
  1632 + PCNetState *d = opaque;
  1633 + uint32_t val = -1;
  1634 + if (addr & 0x10)
  1635 + val = pcnet_ioport_readw(d, addr & 0x0f);
  1636 + else {
  1637 + addr &= 0x0f;
  1638 + val = pcnet_aprom_readb(d, addr+1);
  1639 + val <<= 8;
  1640 + val |= pcnet_aprom_readb(d, addr);
  1641 + }
  1642 +#ifdef PCNET_DEBUG_IO
  1643 + printf("pcnet_mmio_readw addr=0x%08x val = 0x%04x\n", addr, val & 0xffff);
  1644 +#endif
  1645 + return val;
  1646 +}
  1647 +
  1648 +static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
  1649 +{
  1650 + PCNetState *d = opaque;
  1651 +#ifdef PCNET_DEBUG_IO
  1652 + printf("pcnet_mmio_writel addr=0x%08x val=0x%08x\n", addr, val);
  1653 +#endif
  1654 + if (addr & 0x10)
  1655 + pcnet_ioport_writel(d, addr & 0x0f, val);
  1656 + else {
  1657 + addr &= 0x0f;
  1658 + pcnet_aprom_writeb(d, addr, val & 0xff);
  1659 + pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
  1660 + pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16);
  1661 + pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24);
  1662 + }
  1663 +}
  1664 +
  1665 +static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr)
  1666 +{
  1667 + PCNetState *d = opaque;
  1668 + uint32_t val;
  1669 + if (addr & 0x10)
  1670 + val = pcnet_ioport_readl(d, addr & 0x0f);
  1671 + else {
  1672 + addr &= 0x0f;
  1673 + val = pcnet_aprom_readb(d, addr+3);
  1674 + val <<= 8;
  1675 + val |= pcnet_aprom_readb(d, addr+2);
  1676 + val <<= 8;
  1677 + val |= pcnet_aprom_readb(d, addr+1);
  1678 + val <<= 8;
  1679 + val |= pcnet_aprom_readb(d, addr);
  1680 + }
  1681 +#ifdef PCNET_DEBUG_IO
  1682 + printf("pcnet_mmio_readl addr=0x%08x val=0x%08x\n", addr, val);
  1683 +#endif
  1684 + return val;
  1685 +}
  1686 +
  1687 +
  1688 +static CPUWriteMemoryFunc *pcnet_mmio_write[] = {
  1689 + (CPUWriteMemoryFunc *)&pcnet_mmio_writeb,
  1690 + (CPUWriteMemoryFunc *)&pcnet_mmio_writew,
  1691 + (CPUWriteMemoryFunc *)&pcnet_mmio_writel
  1692 +};
  1693 +
  1694 +static CPUReadMemoryFunc *pcnet_mmio_read[] = {
  1695 + (CPUReadMemoryFunc *)&pcnet_mmio_readb,
  1696 + (CPUReadMemoryFunc *)&pcnet_mmio_readw,
  1697 + (CPUReadMemoryFunc *)&pcnet_mmio_readl
  1698 +};
  1699 +
  1700 +static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
  1701 + uint32_t addr, uint32_t size, int type)
  1702 +{
  1703 + PCNetState *d = (PCNetState *)pci_dev;
  1704 +
  1705 +#ifdef PCNET_DEBUG_IO
  1706 + printf("pcnet_ioport_map addr=0x%08x 0x%08x\n", addr, size);
  1707 +#endif
  1708 +
  1709 + cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_io_addr);
  1710 +}
  1711 +
  1712 +void pci_pcnet_init(PCIBus *bus, NICInfo *nd)
  1713 +{
  1714 + PCNetState *d;
  1715 + uint8_t *pci_conf;
  1716 +
  1717 +#if 0
  1718 + printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
  1719 + sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
  1720 +#endif
  1721 +
  1722 + d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState),
  1723 + -1, NULL, NULL);
  1724 +
  1725 + pci_conf = d->dev.config;
  1726 +
  1727 + *(uint16_t *)&pci_conf[0x00] = cpu_to_le16(0x1022);
  1728 + *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x2000);
  1729 + *(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0007);
  1730 + *(uint16_t *)&pci_conf[0x06] = cpu_to_le16(0x0280);
  1731 + pci_conf[0x08] = 0x10;
  1732 + pci_conf[0x09] = 0x00;
  1733 + pci_conf[0x0a] = 0x00; // ethernet network controller
  1734 + pci_conf[0x0b] = 0x02;
  1735 + pci_conf[0x0e] = 0x00; // header_type
  1736 +
  1737 + *(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0x00000001);
  1738 + *(uint32_t *)&pci_conf[0x14] = cpu_to_le32(0x00000000);
  1739 +
  1740 + pci_conf[0x3d] = 1; // interrupt pin 0
  1741 + pci_conf[0x3e] = 0x06;
  1742 + pci_conf[0x3f] = 0xff;
  1743 +
  1744 + /* Handler for memory-mapped I/O */
  1745 + d->mmio_io_addr =
  1746 + cpu_register_io_memory(0, pcnet_mmio_read, pcnet_mmio_write, d);
  1747 +
  1748 + pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE,
  1749 + PCI_ADDRESS_SPACE_IO, pcnet_ioport_map);
  1750 +
  1751 + pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE,
  1752 + PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map);
  1753 +
  1754 + d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d);
  1755 +
  1756 + d->nd = nd;
  1757 +
  1758 + d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive,
  1759 + pcnet_can_receive, d);
  1760 +
  1761 + snprintf(d->vc->info_str, sizeof(d->vc->info_str),
  1762 + "pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
  1763 + d->nd->macaddr[0],
  1764 + d->nd->macaddr[1],
  1765 + d->nd->macaddr[2],
  1766 + d->nd->macaddr[3],
  1767 + d->nd->macaddr[4],
  1768 + d->nd->macaddr[5]);
  1769 +
  1770 + pcnet_h_reset(d);
  1771 +}
... ...
... ... @@ -828,6 +828,10 @@ void pci_ne2000_init(PCIBus *bus, NICInfo *nd);
828 828  
829 829 void pci_rtl8139_init(PCIBus *bus, NICInfo *nd);
830 830  
  831 +/* pcnet.c */
  832 +
  833 +void pci_pcnet_init(PCIBus *bus, NICInfo *nd);
  834 +
831 835 /* pckbd.c */
832 836  
833 837 void kbd_init(void);
... ...