⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dev_mpc860.c

📁 思科路由器仿真器,用来仿7200系列得,可以在电脑上模拟路由器
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Update an IDMA status register */static int mpc860_idma_update_idsr(struct mpc860_data *d,u_int id){   u_int cpm_int;   switch(id) {      case 0:         cpm_int = MPC860_CIPR_IDMA1;         break;      case 1:         cpm_int = MPC860_CIPR_IDMA2;         break;      default:         return(-1);   }   if (d->idsr[id] & d->idmr[id])      d->cipr |= cpm_int;   else      d->cipr &= ~cpm_int;   mpc860_update_cpm_int_status(d);   return(0);}/* Process to an IDMA transfer for the specified buffer descriptor */static void mpc860_idma_transfer(struct mpc860_data *d,                                 struct mpc860_idma_bd *bd){   physmem_dma_transfer(d->vm,bd->src_bp,bd->dst_bp,bd->buf_len);}/* Fetch an IDMA descriptor from Dual-Port RAM */static int mpc860_idma_fetch_bd(struct mpc860_data *d,m_uint16_t bd_addr,                                struct mpc860_idma_bd *bd){   if ((bd_addr < MPC860_DPRAM_OFFSET) || (bd_addr > MPC860_DPRAM_END))      return(-1);   bd->offset = bd_addr - MPC860_DPRAM_OFFSET;   /* Fetch control word */   bd->ctrl = dpram_r16(d,bd->offset+0x00);   /* Fetch function code registers */   bd->dfcr = dpram_r8(d,bd->offset+0x02);   bd->sfcr = dpram_r8(d,bd->offset+0x03);   /* Fetch buffer length, source and destination addresses */   bd->buf_len = dpram_r32(d,bd->offset+0x04);   bd->src_bp  = dpram_r32(d,bd->offset+0x08);   bd->dst_bp  = dpram_r32(d,bd->offset+0x0c);#if DEBUG_IDMA   MPC_LOG(d,"fetched IDMA BD at 0x%4.4x, src_bp=0x%8.8x, dst_bp=0x%8.8x "           "len=%d\n",bd->offset,bd->src_bp,bd->dst_bp,bd->buf_len);#endif   return(0);}/* Start an IDMA channel */static int mpc860_idma_start_channel(struct mpc860_data *d,u_int id){   struct mpc860_idma_bd bd;   m_uint16_t dma_base,ibase,bd_offset;   switch(id) {      case 0:         dma_base = MPC860_IDMA1_BASE;         break;      case 1:         dma_base = MPC860_IDMA2_BASE;         break;      default:         return(-1);   }   /* Get the IBASE register (offset 0) */   ibase = bd_offset = dpram_r16(d,dma_base+0x00);   while(1) {      /* Fetch a descriptor */      if (mpc860_idma_fetch_bd(d,bd_offset,&bd) == -1)         return(-1);      if (!(bd.ctrl & MPC860_IDMA_CTRL_V)) {         d->idsr[id] |= MPC860_IDSR_OB;         break;      }      /* Run the DMA transfer */      mpc860_idma_transfer(d,&bd);      /* Clear the Valid bit */      bd.ctrl &= ~MPC860_IDMA_CTRL_V;      dpram_w16(d,bd_offset-MPC860_DPRAM_OFFSET+0x00,bd.ctrl);      /* Generate an interrupt for this buffer ? */      if (bd.ctrl & MPC860_IDMA_CTRL_I)         d->idsr[id] |= MPC860_IDSR_AD;      /* Stop if this is the last buffer of chain */      if (bd.ctrl & MPC860_IDMA_CTRL_L) {         d->idsr[id] |= MPC860_IDSR_DONE;         break;      }      bd_offset += sizeof(MPC860_IDMA_BD_SIZE);   }   mpc860_idma_update_idsr(d,id);   return(0);}/* ======================================================================== *//* SPI (Serial Peripheral Interface)                                        *//* ======================================================================== *//* Initialize SPI RX parameters */static void mpc860_spi_init_rx_params(struct mpc860_data *d){    m_uint16_t spi_base,rbase;   spi_base = dpram_r16(d,MPC860_SPI_BASE_ADDR);   /* Get the RBASE (offset 0) and store it in RBPTR */   rbase = dpram_r16(d,spi_base+0x00);   dpram_w16(d,spi_base+0x10,rbase);}/* Initialize SPI TX parameters */static void mpc860_spi_init_tx_params(struct mpc860_data *d){   m_uint16_t spi_base,tbase;   spi_base = dpram_r16(d,MPC860_SPI_BASE_ADDR);   /* Get the TBASE (offset 2) and store it in TBPTR */   tbase = dpram_r16(d,spi_base+0x02);   dpram_w16(d,spi_base+0x20,tbase);}/* Initialize SPI RX/TX parameters */static void mpc860_spi_init_rx_tx_params(struct mpc860_data *d){   mpc860_spi_init_rx_params(d);   mpc860_spi_init_tx_params(d);}/* Fetch a SPI buffer descriptor */static int mpc860_spi_fetch_bd(struct mpc860_data *d,m_uint16_t bd_addr,                               struct mpc860_spi_bd *bd){   void *ptr;   if ((bd_addr < MPC860_DPRAM_OFFSET) || (bd_addr > MPC860_DPRAM_END))      return(-1);   bd->offset = bd_addr - MPC860_DPRAM_OFFSET;   ptr = &d->dpram[bd->offset];   /* Fetch control word */   bd->ctrl = dpram_r16(d,bd->offset+0x00);   /* Fetch buffer length and buffer pointer */   bd->buf_len = dpram_r16(d,bd->offset+0x02);   bd->bp      = dpram_r32(d,bd->offset+0x04);#if DEBUG_SPI   MPC_LOG(d,"fetched SPI BD at 0x%4.4x, bp=0x%8.8x, len=%d\n",           bd->offset,bd->bp,bd->buf_len);#endif   return(0);}/* Start SPI transmit */static int mpc860_spi_start_tx(struct mpc860_data *d){   struct mpc860_spi_bd bd;   m_uint16_t bd_offset;   m_uint16_t spi_base;   u_char buffer[512];   u_int buf_len;   spi_base = dpram_r16(d,MPC860_SPI_BASE_ADDR);   /* Get the TBPTR (offset 0x20) register */   bd_offset = dpram_r16(d,spi_base+0x20);   while(1) {      /* Fetch a TX descriptor */      if (mpc860_spi_fetch_bd(d,bd_offset,&bd) == -1)         return(FALSE);      /* If the descriptor is not ready, stop now */      if (!(bd.ctrl & MPC860_SPI_TXBD_CTRL_R))         return(FALSE);      /* Extract the data */      buf_len = bd.buf_len;      if (bd.buf_len > sizeof(buffer)) {         MPC_LOG(d,"SPI: buffer too small for transmit.\n");         buf_len = sizeof(buffer);      }      physmem_copy_from_vm(d->vm,buffer,bd.bp,buf_len);      /* Send the data to the user callback (if specified) */      if (d->spi_tx_callback != NULL)         d->spi_tx_callback(d,buffer,buf_len,d->spi_user_arg);      /* Clear the Ready bit of the TX descriptor */      bd.ctrl &= ~MPC860_SPI_TXBD_CTRL_R;      dpram_w16(d,bd.offset+0x00,bd.ctrl);      /* Set pointer on next TX descriptor (wrap ring if necessary) */      if (bd.ctrl & MPC860_SPI_TXBD_CTRL_W) {         bd_offset = dpram_r16(d,spi_base+0x02);      } else {         bd_offset += MPC860_SPI_BD_SIZE;      }      dpram_w16(d,spi_base+0x20,bd_offset);      /* Stop if this is the last buffer in chain */      if (bd.ctrl & MPC860_SPI_TXBD_CTRL_L)         break;   }   return(TRUE);}/* Put a buffer into SPI receive buffers */int mpc860_spi_receive(struct mpc860_data *d,u_char *buffer,u_int len){   struct mpc860_spi_bd bd;   m_uint16_t bd_offset;   m_uint16_t spi_base;   u_int clen,mrblr;   spi_base = dpram_r16(d,MPC860_SPI_BASE_ADDR);   /* Get the RBPTR (offset 0x10) */   bd_offset = dpram_r16(d,spi_base+0x10);   /* Get the maximum buffer size */   mrblr = dpram_r16(d,spi_base+0x06);   while(len > 0) {      /* Fetch a RX descriptor */      if (mpc860_spi_fetch_bd(d,bd_offset,&bd) == -1)         return(FALSE);      /* If the buffer is not empty, do not use it */      if (!(bd.ctrl & MPC860_SPI_RXBD_CTRL_E))         return(FALSE);      /* Write data into the RX buffer */      clen = m_min(mrblr,len);      physmem_copy_to_vm(d->vm,buffer,bd.bp,clen);      buffer += clen;      len -= clen;      /* Update the length field */      dpram_w16(d,bd.offset+0x02,clen);      /* If no more data, set the "Last" bit */      if (!len)         bd.ctrl |= MPC860_SPI_RXBD_CTRL_L;      /* Clear the Empty bit of the RX descriptor */      bd.ctrl &= ~MPC860_SPI_RXBD_CTRL_E;      dpram_w16(d,bd.offset+0x00,bd.ctrl);      /* Set pointer on next RX descriptor */      if (bd.ctrl & MPC860_SPI_RXBD_CTRL_W) {         bd_offset = dpram_r16(d,spi_base+0x00);      } else {         bd_offset += MPC860_SPI_BD_SIZE;      }      dpram_w16(d,spi_base+0x10,bd_offset);   }   if (len > 0)      MPC_LOG(d,"SPI: no buffers available for receive.\n");   return(0);}/* Set SPI TX callback */void mpc860_spi_set_tx_callback(struct mpc860_data *d,                                mpc860_spi_tx_callback_t cbk,                                void *user_arg){   d->spi_tx_callback = cbk;   d->spi_user_arg = user_arg;}/* ======================================================================== *//* SCC (Serial Communication Controller)                                    *//* ======================================================================== */typedef struct {   u_int cipr_irq;   m_uint32_t dpram_base;}scc_chan_info_t;static scc_chan_info_t scc_chan_info[MPC860_SCC_NR_CHAN] = {   { MPC860_CIPR_SCC1, MPC860_SCC1_BASE },   { MPC860_CIPR_SCC2, MPC860_SCC2_BASE },   { MPC860_CIPR_SCC3, MPC860_SCC3_BASE },   { MPC860_CIPR_SCC4, MPC860_SCC4_BASE },};/* Initialize SCC RX parameters */static void mpc860_scc_init_rx_params(struct mpc860_data *d,u_int scc_chan){    m_uint16_t scc_base,rbase;   scc_base = scc_chan_info[scc_chan].dpram_base;      /* Get the RBASE (offset 0) and store it in RBPTR */   rbase = dpram_r16(d,scc_base+0x00);   dpram_w16(d,scc_base+0x10,rbase);}/* Initialize SCC TX parameters */static void mpc860_scc_init_tx_params(struct mpc860_data *d,u_int scc_chan){   m_uint16_t scc_base,tbase;   scc_base = scc_chan_info[scc_chan].dpram_base;   /* Get the TBASE (offset 2) and store it in TBPTR */   tbase = dpram_r16(d,scc_base+0x02);   dpram_w16(d,scc_base+0x20,tbase);}/* Initialize SCC RX/TX parameters */static void mpc860_scc_init_rx_tx_params(struct mpc860_data *d,u_int scc_chan){   mpc860_scc_init_rx_params(d,scc_chan);   mpc860_scc_init_tx_params(d,scc_chan);}/* Set an SCC interrupt */static int mpc860_scc_update_irq(struct mpc860_data *d,u_int scc_chan){   struct mpc860_scc_chan *chan = &d->scc_chan[scc_chan];   if (chan->scce & chan->sccm)      d->cipr |= scc_chan_info[scc_chan].cipr_irq;   else      d->cipr &= ~scc_chan_info[scc_chan].cipr_irq;   mpc860_update_cpm_int_status(d);   return(0);}/* Fetch a SCC buffer descriptor */static int mpc860_scc_fetch_bd(struct mpc860_data *d,m_uint16_t bd_addr,                               struct mpc860_scc_bd *bd){   void *ptr;   if ((bd_addr < MPC860_DPRAM_OFFSET) || (bd_addr > MPC860_DPRAM_END))      return(-1);   bd->offset = bd_addr - MPC860_DPRAM_OFFSET;   ptr = &d->dpram[bd->offset];   /* Fetch control word */   bd->ctrl = dpram_r16(d,bd->offset+0x00);   /* Fetch buffer length and buffer pointer */   bd->buf_len = dpram_r16(d,bd->offset+0x02);   bd->bp      = dpram_r32(d,bd->offset+0x04);#if DEBUG_SCC   MPC_LOG(d,"fetched SCC BD at 0x%4.4x, bp=0x%8.8x, len=%d\n",           bd->offset,bd->bp,bd->buf_len);#endif   return(0);}/* Handle the TX ring of an SCC channel (transmit a single packet) */static int mpc860_scc_handle_tx_ring_single(struct mpc860_data *d,                                            u_int scc_chan){      struct mpc860_scc_bd txd0,ctxd,*ptxd;   struct mpc860_scc_chan *chan;   scc_chan_info_t *scc_info;   m_uint16_t bd_offset;   m_uint32_t clen,tot_len;   u_char *pkt_ptr;   int done = FALSE;   int irq = FALSE;      scc_info = &scc_chan_info[scc_chan];   chan = &d->scc_chan[scc_chan];      /* Get the TBPTR (offset 0x20) register */   bd_offset = dpram_r16(d,scc_info->dpram_base+0x20);   /* Try to acquire the first descriptor */   ptxd = &txd0;   mpc860_scc_fetch_bd(d,bd_offset,ptxd);   /* If we don't own the first descriptor, we cannot transmit */   if (!(txd0.ctrl & MPC860_SCC_TXBD_CTRL_R))      return(FALSE);   /* Empty packet for now */   pkt_ptr = chan->tx_pkt;   tot_len = 0;   do {      /* Copy data into the buffer */      clen = ptxd->buf_len;      physmem_copy_from_vm(d->vm,pkt_ptr,ptxd->bp,clen);      pkt_ptr += clen;      tot_len += clen;      /* Signal IRQ ? */      if (ptxd->ctrl & MPC860_SCC_TXBD_CTRL_I)         irq = TRUE;      /*        * Clear the ready bit (except for the first descriptor,        * which is cleared when the full packet has been sent).       */      if (ptxd != &txd0) {         ptxd->ctrl &= ~MPC860_SCC_TXBD_CTRL_R;         dpram_w16(d,ptxd->offset+0x00,ptxd->ctrl);      }      /* Set pointer on next TX descriptor (wrap ring if necessary) */      if (ptxd->ctrl & MPC860_SCC_TXBD_CTRL_W) {         bd_offset = dpram_r16(d,scc_info->dpram_base+0x02);      } else {         bd_offset += MPC860_SCC_BD_SIZE;      }      dpram_w16(d,scc_info->dpram_base+0x20,bd_offset);      /* If this is the last descriptor, we have finished */      if (!(ptxd->ctrl & MPC860_SCC_TXBD_CTRL_L)) {         mpc860_scc_fetch_bd(d,bd_offset,&ctxd);         ptxd = &ctxd;      } else {         done = TRUE;      }   }while(!done);   if (tot_len != 0) {#if DEBUG_SCC      MPC_LOG(d,"SCC%u: sending packet of %u bytes\n",scc_chan+1,tot_len);      mem_dump(log_file,chan->tx_pkt,tot_len);#endif      /* send packet on wire */      netio_send(chan->nio,chan->tx_pkt,tot_len);   }   /* Clear the Ready bit of the first TX descriptor */   txd0.ctrl &= ~MPC860_SCC_TXBD_CTRL_R;   dpram_w16(d,txd0.offset+0x00,txd0.ctrl);   /* Trigger SCC IRQ */   if (irq) {      chan->scce |= MPC860_SCCE_TXB;      mpc860_scc_update_irq(d,scc_chan);   }      return(TRUE);}/* Handle the TX ring of the specified SCC channel (multiple pkts possible) */static int mpc860_scc_handle_tx_ring(struct mpc860_data *d,u_int scc_chan){   int i;   for(i=0;i<MPC860_TXRING_PASS_COUNT;i++)      if (!mpc860_scc_handle_tx_ring_single(d,scc_chan))         break;   return(TRUE);}/* Handle RX packet for an SCC channel */static int mpc860_scc_handle_rx_pkt(netio_desc_t *nio,                                    u_char *pkt,ssize_t pkt_len,                                    struct mpc860_data *d,void *arg){          struct mpc860_scc_bd rxd0,crxd,*prxd;   struct mpc860_scc_chan *chan;   u_int scc_chan = (int)arg;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -