func: static void pcnet_receive(void *opaque, const uint8_t *buf, size_t size)
  
  {
  
      PCNetState *s = opaque;
  
      int is_padr = 0, is_bcast = 0, is_ladr = 0;
  
      uint8_t buf1[60];
  
      int remaining;
  
      int crc_err = 0;
  
  
  
      if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size)
  
          return;
  
  
  
  #ifdef PCNET_DEBUG
  
      printf("pcnet_receive size=%d\n", size);
  
  #endif
  
  
  
      /* if too small buffer, then expand it */
  
      if (size < MIN_BUF_SIZE) {
  
          memcpy(buf1, buf, size);
  
          memset(buf1 + size, 0, MIN_BUF_SIZE - size);
  
          buf = buf1;
  
          size = MIN_BUF_SIZE;
  
      }
  
  
  
      if (CSR_PROM(s)
  
          || (is_padr=padr_match(s, buf, size))
  
          || (is_bcast=padr_bcast(s, buf, size))
  
          || (is_ladr=ladr_match(s, buf, size))) {
  
  
  
          pcnet_rdte_poll(s);
  
  
  
          if (!(CSR_CRST(s) & 0x8000) && s->rdra) {
  
              struct pcnet_RMD rmd;
  
              int rcvrc = CSR_RCVRC(s)-1,i;
  
              target_phys_addr_t nrda;
  
              for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) {
  
                  if (rcvrc <= 1)
  
                      rcvrc = CSR_RCVRL(s);
  
                  nrda = s->rdra +
  
                      (CSR_RCVRL(s) - rcvrc) *
  
                      (BCR_SWSTYLE(s) ? 16 : 8 );
  
                  RMDLOAD(&rmd, nrda);
  
                  if (GET_FIELD(rmd.status, RMDS, OWN)) {
  
  #ifdef PCNET_DEBUG_RMD
  
                      printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n",
  
                                  rcvrc, CSR_RCVRC(s));
  
  #endif
  
                      CSR_RCVRC(s) = rcvrc;
  
                      pcnet_rdte_poll(s);
  
                      break;
  
                  }
  
              }
  
          }
  
  
  
          if (!(CSR_CRST(s) & 0x8000)) {
  
  #ifdef PCNET_DEBUG_RMD
  
              printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s));
  
  #endif
  
              s->csr[0] |= 0x1000; /* Set MISS flag */
  
              CSR_MISSC(s)++;
  
          } else {
  
              uint8_t *src = s->buffer;
  
              target_phys_addr_t crda = CSR_CRDA(s);
  
              struct pcnet_RMD rmd;
  
              int pktcount = 0;
  
  
  
              if (!s->looptest) {
  
                  memcpy(src, buf, size);
  
                  /* no need to compute the CRC */
  
                  src[size] = 0;
  
                  src[size + 1] = 0;
  
                  src[size + 2] = 0;
  
                  src[size + 3] = 0;
  
                  size += 4;
  
              } else if (s->looptest == PCNET_LOOPTEST_CRC ||
  
                         !CSR_DXMTFCS(s) || size < MIN_BUF_SIZE+4) {
  
                  uint32_t fcs = ~0;
  
                  uint8_t *p = src;
  
  
  
                  while (p != &src[size])
  
                      CRC(fcs, *p++);
  
                  *(uint32_t *)p = htonl(fcs);
  
                  size += 4;
  
              } else {
  
                  uint32_t fcs = ~0;
  
                  uint8_t *p = src;
  
  
  
                  while (p != &src[size-4])
  
                      CRC(fcs, *p++);
  
                  crc_err = (*(uint32_t *)p != htonl(fcs));
  
              }
  
  
  
  #ifdef PCNET_DEBUG_MATCH
  
              PRINT_PKTHDR(buf);
  
  #endif
  
  
  
              RMDLOAD(&rmd, PHYSADDR(s,crda));
  
              /*if (!CSR_LAPPEN(s))*/
  
                  SET_FIELD(&rmd.status, RMDS, STP, 1);
  
  
  
  #define PCNET_RECV_STORE() do {                                 \
  
      int count = MIN(4096 - GET_FIELD(rmd.buf_length, RMDL, BCNT),remaining); \
  
      target_phys_addr_t rbadr = PHYSADDR(s, rmd.rbadr);          \
  
      s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \
  
      src += count; remaining -= count;                           \
  
      SET_FIELD(&rmd.status, RMDS, OWN, 0);                       \
  
      RMDSTORE(&rmd, PHYSADDR(s,crda));                           \
  
      pktcount++;                                                 \
  
  } while (0)
  
  
  
              remaining = size;
  
              PCNET_RECV_STORE();
  
              if ((remaining > 0) && CSR_NRDA(s)) {
  
                  target_phys_addr_t nrda = CSR_NRDA(s);
  
  #ifdef PCNET_DEBUG_RMD
  
                  PRINT_RMD(&rmd);
  
  #endif
  
                  RMDLOAD(&rmd, PHYSADDR(s,nrda));
  
                  if (GET_FIELD(rmd.status, RMDS, OWN)) {
  
                      crda = nrda;
  
                      PCNET_RECV_STORE();
  
  #ifdef PCNET_DEBUG_RMD
  
                      PRINT_RMD(&rmd);
  
  #endif
  
                      if ((remaining > 0) && (nrda=CSR_NNRD(s))) {
  
                          RMDLOAD(&rmd, PHYSADDR(s,nrda));
  
                          if (GET_FIELD(rmd.status, RMDS, OWN)) {
  
                              crda = nrda;
  
                              PCNET_RECV_STORE();
  
                          }
  
                      }
  
                  }
  
              }
  
  
  
  #undef PCNET_RECV_STORE
  
  
  
              RMDLOAD(&rmd, PHYSADDR(s,crda));
  
              if (remaining == 0) {
  
                  SET_FIELD(&rmd.msg_length, RMDM, MCNT, size);
  
                  SET_FIELD(&rmd.status, RMDS, ENP, 1);
  
                  SET_FIELD(&rmd.status, RMDS, PAM, !CSR_PROM(s) && is_padr);
  
                  SET_FIELD(&rmd.status, RMDS, LFAM, !CSR_PROM(s) && is_ladr);
  
                  SET_FIELD(&rmd.status, RMDS, BAM, !CSR_PROM(s) && is_bcast);
  
                  if (crc_err) {
  
                      SET_FIELD(&rmd.status, RMDS, CRC, 1);
  
                      SET_FIELD(&rmd.status, RMDS, ERR, 1);
  
                  }
  
              } else {
  
                  SET_FIELD(&rmd.status, RMDS, OFLO, 1);
  
                  SET_FIELD(&rmd.status, RMDS, BUFF, 1);
  
                  SET_FIELD(&rmd.status, RMDS, ERR, 1);
  
              }
  
              RMDSTORE(&rmd, PHYSADDR(s,crda));
  
              s->csr[0] |= 0x0400;
  
  
  
  #ifdef PCNET_DEBUG
  
              printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n",
  
                  CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount);
  
  #endif
  
  #ifdef PCNET_DEBUG_RMD
  
              PRINT_RMD(&rmd);
  
  #endif
  
  
  
              while (pktcount--) {
  
                  if (CSR_RCVRC(s) <= 1)
  
                      CSR_RCVRC(s) = CSR_RCVRL(s);
  
                  else
  
                      CSR_RCVRC(s)--;
  
              }
  
  
  
              pcnet_rdte_poll(s);
  
  
  
          }
  
      }
  
  
  
      pcnet_poll(s);
  
      pcnet_update_irq(s);
  
  }
  