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

📄 dev_am79c971.c

📁 思科路由器仿真器,用来仿7200系列得,可以在电脑上模拟路由器-Cisco router simulator, used to fake a 7200 series can be simulated
💻 C
📖 第 1 页 / 共 2 页
字号:
/*   * Cisco C7200 (Predator) AMD Am79c971 Module. * Copyright (C) 2006 Christophe Fillot.  All rights reserved. * * AMD Am79c971 FastEthernet chip emulation. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <unistd.h>#include <time.h>#include <errno.h>#include <assert.h>#include "utils.h"#include "mips64.h"#include "dynamips.h"#include "memory.h"#include "device.h"#include "net.h"#include "net_io.h"#include "ptask.h"#include "dev_am79c971.h"/* Debugging flags */#define DEBUG_CSR_REGS   0#define DEBUG_BCR_REGS   0#define DEBUG_PCI_REGS   0#define DEBUG_ACCESS     0#define DEBUG_TRANSMIT   0#define DEBUG_RECEIVE    0#define DEBUG_UNKNOWN    0/* AMD Am79c971 PCI vendor/product codes */#define AM79C971_PCI_VENDOR_ID    0x1022#define AM79C971_PCI_PRODUCT_ID   0x2000/* Maximum packet size */#define AM79C971_MAX_PKT_SIZE  2048/* Send up to 16 packets in a TX ring scan pass */#define AM79C971_TXRING_PASS_COUNT  16/* CSR0: Controller Status and Control Register */#define AM79C971_CSR0_ERR      0x00008000    /* Error (BABL,CERR,MISS,MERR) */#define AM79C971_CSR0_BABL     0x00004000    /* Transmitter Timeout Error */#define AM79C971_CSR0_CERR     0x00002000    /* Collision Error */#define AM79C971_CSR0_MISS     0x00001000    /* Missed Frame */#define AM79C971_CSR0_MERR     0x00000800    /* Memory Error */#define AM79C971_CSR0_RINT     0x00000400    /* Receive Interrupt */#define AM79C971_CSR0_TINT     0x00000200    /* Transmit Interrupt */#define AM79C971_CSR0_IDON     0x00000100    /* Initialization Done */#define AM79C971_CSR0_INTR     0x00000080    /* Interrupt Flag */#define AM79C971_CSR0_IENA     0x00000040    /* Interrupt Enable */#define AM79C971_CSR0_RXON     0x00000020    /* Receive On */#define AM79C971_CSR0_TXON     0x00000010    /* Transmit On */#define AM79C971_CSR0_TDMD     0x00000008    /* Transmit Demand */#define AM79C971_CSR0_STOP     0x00000004    /* Stop */#define AM79C971_CSR0_STRT     0x00000002    /* Start */#define AM79C971_CSR0_INIT     0x00000001    /* Initialization *//* CSR3: Interrupt Masks and Deferral Control */#define AM79C971_CSR3_BABLM    0x00004000    /* Transmit. Timeout Int. Mask */#define AM79C971_CSR3_CERRM    0x00002000    /* Collision Error Int. Mask*/#define AM79C971_CSR3_MISSM    0x00001000    /* Missed Frame Interrupt Mask */#define AM79C971_CSR3_MERRM    0x00000800    /* Memory Error Interrupt Mask */#define AM79C971_CSR3_RINTM    0x00000400    /* Receive Interrupt Mask */#define AM79C971_CSR3_TINTM    0x00000200    /* Transmit Interrupt Mask */#define AM79C971_CSR3_IDONM    0x00000100    /* Initialization Done Mask */#define AM79C971_CSR3_BSWP     0x00000004    /* Byte Swap */#define AM79C971_CSR3_IM_MASK  0x00007F00    /* Interrupt Masks for CSR3 *//* CSR5: Extended Control and Interrupt 1 */#define AM79C971_CSR5_TOKINTD  0x00008000    /* Receive Interrupt Mask */#define AM79C971_CSR5_SPND     0x00000001    /* Suspend *//* CSR15: Mode */#define AM79C971_CSR15_PROM    0x00008000    /* Promiscous Mode */#define AM79C971_CSR15_DRCVBC  0x00004000    /* Disable Receive Broadcast */#define AM79C971_CSR15_DRCVPA  0x00002000    /* Disable Receive PHY address */#define AM79C971_CSR15_DTX     0x00000002    /* Disable Transmit */#define AM79C971_CSR15_DRX     0x00000001    /* Disable Receive *//* AMD 79C971 Initialization block length */#define AM79C971_INIT_BLOCK_LEN  0x1c/* RX descriptors */#define AM79C971_RMD1_OWN      0x80000000    /* OWN=1: owned by Am79c971 */#define AM79C971_RMD1_ERR      0x40000000    /* Error */#define AM79C971_RMD1_FRAM     0x20000000    /* Framing Error */#define AM79C971_RMD1_OFLO     0x10000000    /* Overflow Error */#define AM79C971_RMD1_CRC      0x08000000    /* Invalid CRC */#define AM79C971_RMD1_BUFF     0x08000000    /* Buffer Error (chaining) */#define AM79C971_RMD1_STP      0x02000000    /* Start of Packet */#define AM79C971_RMD1_ENP      0x01000000    /* End of Packet */#define AM79C971_RMD1_BPE      0x00800000    /* Bus Parity Error */#define AM79C971_RMD1_PAM      0x00400000    /* Physical Address Match */#define AM79C971_RMD1_LAFM     0x00200000    /* Logical Addr. Filter Match */#define AM79C971_RMD1_BAM      0x00100000    /* Broadcast Address Match */#define AM79C971_RMD1_LEN      0x00000FFF    /* Buffer Length */#define AM79C971_RMD2_LEN      0x00000FFF    /* Received byte count *//* TX descriptors */#define AM79C971_TMD1_OWN      0x80000000    /* OWN=1: owned by Am79c971 */#define AM79C971_TMD1_ERR      0x40000000    /* Error */#define AM79C971_TMD1_ADD_FCS  0x20000000    /* FCS generation */#define AM79C971_TMD1_STP      0x02000000    /* Start of Packet */#define AM79C971_TMD1_ENP      0x01000000    /* End of Packet */#define AM79C971_TMD1_LEN      0x00000FFF    /* Buffer Length *//* RX Descriptor */struct rx_desc {   m_uint32_t rmd[4];};/* TX Descriptor */struct tx_desc {   m_uint32_t tmd[4];};/* AMD 79C971 Data */struct am79c971_data {   char *name;   /* Interface type (10baseT or 100baseTX) */   int type;   /* Current RAP (Register Address Pointer) value */   m_uint8_t rap;   /* CSR and BCR registers */   m_uint32_t csr[256],bcr[256];      /* RX/TX rings start addresses */   m_uint32_t rx_start,tx_start;   /* RX/TX number of descriptors (log2) */   m_uint32_t rx_l2len,tx_l2len;   /* RX/TX number of descriptors */   m_uint32_t rx_len,tx_len;   /* RX/TX ring positions */   m_uint32_t rx_pos,tx_pos;      /* MII registers */   m_uint16_t mii_regs[32][32];   /* Physical (MAC) address */   n_eth_addr_t mac_addr;   /* Device information */   struct vdevice *dev;   /* PCI device information */   struct pci_device *pci_dev;   /* Virtual machine */   vm_instance_t *vm;   /* NetIO descriptor */   netio_desc_t *nio;   /* TX ring scanner task id */   ptask_id_t tx_tid;};/* Log an am79c971 message */#define AM79C971_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg)static m_uint16_t mii_reg_values[32] = {   0x1000, 0x782D, 0x2000, 0x5C01, 0x01E1, 0x0000, 0x0000, 0x0000,   0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x8060,   0x8020, 0x0820, 0x0000, 0x3800, 0xA3B9, 0x0000, 0x0000, 0x0000,};/* Read a MII register */static m_uint16_t mii_reg_read(struct am79c971_data *d,u_int phy,u_int reg){   if ((phy >= 32) || (reg >= 32))      return(0);   return(d->mii_regs[phy][reg]);}/* Write a MII register */static void mii_reg_write(struct am79c971_data *d,u_int phy,u_int reg,                          m_uint16_t value){   if ((phy < 32) && (reg < 32))      d->mii_regs[phy][reg] = value;}/* Check if a packet must be delivered to the emulated chip */static inline int am79c971_handle_mac_addr(struct am79c971_data *d,                                           m_uint8_t *pkt){   n_eth_hdr_t *hdr = (n_eth_hdr_t *)pkt;   /* Accept systematically frames if we are running is promiscuous mode */   if (d->csr[15] & AM79C971_CSR15_PROM)      return(TRUE);   /* Accept systematically all multicast frames */   if (eth_addr_is_mcast(&hdr->daddr))      return(TRUE);   /* Accept frames directly for us, discard others */   if (!memcmp(&d->mac_addr,&hdr->daddr,N_ETH_ALEN))      return(TRUE);         return(FALSE);}/* Update the Interrupt Flag bit of csr0 */static void am79c971_update_intr_flag(struct am79c971_data *d){   m_uint32_t mask;   mask = d->csr[3] & AM79C971_CSR3_IM_MASK;      if (d->csr[0] & mask)      d->csr[0] |= AM79C971_CSR0_INTR;}/* Trigger an interrupt */static int am79c971_trigger_irq(struct am79c971_data *d){   if (d->csr[0] & (AM79C971_CSR0_INTR|AM79C971_CSR0_IENA)) {      pci_dev_trigger_irq(d->vm,d->pci_dev);      return(TRUE);   }   return(FALSE);}/* Update RX/TX ON bits of csr0 */static void am79c971_update_rx_tx_on_bits(struct am79c971_data *d){   /*     * Set RX ON if DRX in csr15 is cleared, and set TX on if DTX    * in csr15 is cleared. The START bit must be set.    */   d->csr[0] &= ~(AM79C971_CSR0_RXON|AM79C971_CSR0_TXON);   if (d->csr[0] & AM79C971_CSR0_STRT) {      if (!(d->csr[15] & AM79C971_CSR15_DRX))         d->csr[0] |= AM79C971_CSR0_RXON;            if (!(d->csr[15] & AM79C971_CSR15_DTX))         d->csr[0] |= AM79C971_CSR0_TXON;   }}/* Update RX/TX descriptor lengths */static void am79c971_update_rx_tx_len(struct am79c971_data *d){   d->rx_len = 1 << d->rx_l2len;   d->tx_len = 1 << d->tx_l2len;   /* Normalize ring sizes */   if (d->rx_len > 512) d->rx_len = 512;   if (d->tx_len > 512) d->tx_len = 512;}/* Fetch the initialization block from memory */static int am79c971_fetch_init_block(struct am79c971_data *d){   m_uint32_t ib[AM79C971_INIT_BLOCK_LEN];   m_uint32_t ib_addr,ib_tmp;   /* The init block address is contained in csr1 (low) and csr2 (high) */   ib_addr = (d->csr[2] << 16) | d->csr[1];   if (!ib_addr) {      AM79C971_LOG(d,"trying to fetch init block at address 0...\n");      return(-1);   }   AM79C971_LOG(d,"fetching init block at address 0x%8.8x\n",ib_addr);   physmem_copy_from_vm(d->vm,ib,ib_addr,sizeof(ib));      /* Extract RX/TX ring addresses */   d->rx_start = vmtoh32(ib[5]);   d->tx_start = vmtoh32(ib[6]);   /* Set csr15 from mode field */   ib_tmp = vmtoh32(ib[0]);   d->csr[15] = ib_tmp & 0xffff;   /* Extract RX/TX ring sizes */   d->rx_l2len = (ib_tmp >> 20) & 0x0F;   d->tx_l2len = (ib_tmp >> 28) & 0x0F;   am79c971_update_rx_tx_len(d);   AM79C971_LOG(d,"rx_ring = 0x%8.8x (%u), tx_ring = 0x%8.8x (%u)\n",                d->rx_start,d->rx_len,d->tx_start,d->tx_len);   /* Get the physical MAC address */   ib_tmp = vmtoh32(ib[1]);   d->csr[12] = ib_tmp & 0xFFFF;   d->csr[13] = ib_tmp >> 16;   d->mac_addr.eth_addr_byte[3] = (ib_tmp >> 24) & 0xFF;   d->mac_addr.eth_addr_byte[2] = (ib_tmp >> 16) & 0xFF;   d->mac_addr.eth_addr_byte[1] = (ib_tmp >>  8) & 0xFF;   d->mac_addr.eth_addr_byte[0] = ib_tmp & 0xFF;      ib_tmp = vmtoh32(ib[2]);   d->csr[14] = ib_tmp & 0xFFFF;   d->mac_addr.eth_addr_byte[5] = (ib_tmp >> 8) & 0xFF;   d->mac_addr.eth_addr_byte[4] = ib_tmp & 0xFF;   /*     * Mark the initialization as done is csr0.     */   d->csr[0] |= AM79C971_CSR0_IDON;   /* Update RX/TX ON bits of csr0 since csr15 has been modified */   am79c971_update_rx_tx_on_bits(d);   AM79C971_LOG(d,"CSR0 = 0x%4.4x\n",d->csr[0]);   am79c971_update_intr_flag(d);   if (am79c971_trigger_irq(d))      AM79C971_LOG(d,"triggering IDON interrupt\n");   return(0);}/* RDP (Register Data Port) access */static void am79c971_rdp_access(cpu_mips_t *cpu,struct am79c971_data *d,                                u_int op_type,m_uint64_t *data){   m_uint32_t mask;#if DEBUG_CSR_REGS   if (op_type == MTS_READ) {      cpu_log(cpu,d->name,"read access to CSR %d\n",d->rap);   } else {      cpu_log(cpu,d->name,"write access to CSR %d, value=0x%x\n",d->rap,*data);   }#endif   switch(d->rap) {      case 0:  /* CSR0: Controller Status and Control Register */         if (op_type == MTS_READ) {            //AM79C971_LOG(d,"reading CSR0 (val=0x%4.4x)\n",d->csr[0]);            *data = d->csr[0];         } else {            /*              * The STOP bit clears other bits.             * It has precedence over INIT and START bits.             */            if (*data & AM79C971_CSR0_STOP) {               //AM79C971_LOG(d,"stopping interface!\n");               d->csr[0] = AM79C971_CSR0_STOP;               d->tx_pos = d->rx_pos = 0;               break;            }                        /* These bits are cleared when set to 1 */            mask  = AM79C971_CSR0_BABL | AM79C971_CSR0_CERR;            mask |= AM79C971_CSR0_MISS | AM79C971_CSR0_MERR;            mask |= AM79C971_CSR0_RINT | AM79C971_CSR0_TINT;            mask |= AM79C971_CSR0_IDON;            d->csr[0] &= ~(*data & mask);            /* Save the Interrupt Enable bit */            d->csr[0] |= *data & AM79C971_CSR0_IENA;            /* If INIT bit is set, fetch the initialization block */            if (*data & AM79C971_CSR0_INIT) {               d->csr[0] |= AM79C971_CSR0_INIT;               d->csr[0] &= ~AM79C971_CSR0_STOP;               am79c971_fetch_init_block(d);            }            /* If STRT bit is set, clear the stop bit */            if (*data & AM79C971_CSR0_STRT) {               //AM79C971_LOG(d,"enabling interface!\n");               d->csr[0] |= AM79C971_CSR0_STRT;               d->csr[0] &= ~AM79C971_CSR0_STOP;               am79c971_update_rx_tx_on_bits(d);            }         }         break;      case 6:   /* CSR6: RX/TX Descriptor Table Length */         if (op_type == MTS_WRITE) {            d->rx_l2len = (*data >> 8) & 0x0F;            d->tx_l2len = (*data >> 12) & 0x0F;            am79c971_update_rx_tx_len(d);         } else {            *data = (d->tx_l2len << 12) | (d->rx_l2len << 8);         }         break;      case 15:  /* CSR15: Mode */         if (op_type == MTS_WRITE) {            d->csr[15] = *data;            am79c971_update_rx_tx_on_bits(d);         } else {            *data = d->csr[15];         }         break;      case 88:         if (op_type == MTS_READ) {            switch(d->type) {               case AM79C971_TYPE_100BASE_TX:                  *data = 0x2623003;                  break;               default:                  *data = 0;                  break;            }         }         break;      default:         if (op_type == MTS_READ) {            *data = d->csr[d->rap];         } else {            d->csr[d->rap] = *data;         }#if DEBUG_UNKNOWN         if (op_type == MTS_READ) {            cpu_log(cpu,d->name,"read access to unknown CSR %d\n",d->rap);         } else {            cpu_log(cpu,d->name,"write access to unknown CSR %d, value=0x%x\n",                    d->rap,*data);         }#endif   }}/* BDP (BCR Data Port) access */static void am79c971_bdp_access(cpu_mips_t *cpu,struct am79c971_data *d,                                u_int op_type,m_uint64_t *data){   u_int mii_phy,mii_reg;#if DEBUG_BCR_REGS   if (op_type == MTS_READ) {      cpu_log(cpu,d->name,"read access to BCR %d\n",d->rap);   } else {      cpu_log(cpu,d->name,"write access to BCR %d, value=0x%x\n",d->rap,*data);   }#endif   switch(d->rap) {      case 9:         if (op_type == MTS_READ)            *data = 1;         break;      case 34:  /* BCR34: MII Management Data Register */         mii_phy = (d->bcr[33] >> 5) & 0x1F;         mii_reg = (d->bcr[33] >> 0) & 0x1F;         if (op_type == MTS_READ)            *data = mii_reg_read(d,mii_phy,mii_reg);         //else         //mii_reg_write(d,mii_phy,mii_reg,*data);         break;      default:         if (op_type == MTS_READ) {            *data = d->bcr[d->rap];         } else {            d->bcr[d->rap] = *data;         }#if DEBUG_UNKNOWN         if (op_type == MTS_READ) {            cpu_log(cpu,d->name,"read access to unknown BCR %d\n",d->rap);         } else {            cpu_log(cpu,d->name,"write access to unknown BCR %d, value=0x%x\n",                    d->rap,*data);         }#endif   }}/* * dev_am79c971_access() */void *dev_am79c971_access(cpu_mips_t *cpu,struct vdevice *dev,                          m_uint32_t offset,u_int op_size,u_int op_type,                          m_uint64_t *data){   struct am79c971_data *d = dev->priv_data;   if (op_type == MTS_READ)      *data = 0;#if DEBUG_ACCESS   if (op_type == MTS_READ) {      cpu_log(cpu,d->name,"read  access to offset=0x%x, pc=0x%llx, size=%u\n",              offset,cpu->pc,op_size);   } else {      cpu_log(cpu,d->name,"write access to offset=0x%x, pc=0x%llx, "              "val=0x%llx, size=%u\n",offset,cpu->pc,*data,op_size);   }#endif   switch(offset) {      case 0x14:  /* RAP (Register Address Pointer) */

⌨️ 快捷键说明

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