[轉]SkyEye硬件模擬平臺,第三部分: 硬件仿真實現之四

SkyEye硬件模擬平臺,第三部分: 硬件仿真實現之四

網絡芯片仿真

developerWorks
文檔選項
將打印機的版面設置成橫向打印模式

打印本頁

將此頁作爲電子郵件發送

將此頁作爲電子郵件發送

未顯示需要 JavaScript 的文檔選項


級別: 初級

陳渝 ([email protected])清華大學

2004 年 11 月 01 日

本系列文章的第三部分主要介紹了SkyEye硬件模擬平臺的實現細節。主要內容包括SkyEye的總體設計、SkyEye的可擴展框架、SkyEye的關鍵數據結構、SkyEye對各種CPU的模擬實現、SkyEye對各種外設的模擬實現、如何安裝使用SkyEye以及如何擴展SkyEye的仿真模塊等。對SkyEye的深入瞭解,有助於對嵌入式硬件系統有更深入的認識,特別是對操作系統、驅動程序如何與嵌入式硬件系統進行交互有更深刻的瞭解。

1.1.6 SkyEye的網絡模擬實現

1. RTL8019AS網絡芯片模擬的構思和設計概述

目前網絡在嵌入式系統中應用越來越廣泛,通過爲SkyEye增加虛擬以太網芯片設備,使SkyEye支持ethernet網絡接口模擬。這樣在SkyEye硬件模擬平臺上運行的操作系統能夠與本地Linux主機進行網絡通信,當然通過ipchains/iptables等包轉發機制可以進一步支持直接跟Internet通信。

鑑於目前嵌入式設備中廣泛使用了NE2K 10Base-T兼容網絡芯片,其中RTL8019AS又是比較有代表性的一種,購買也比較方便,我們就決定模擬它。設計方案完全基於真實的RTL8019AS(NE2000兼容,簡稱8019AS),但做了部份簡化。簡化掉的部分主要包括:

  • 一部分狀態寄存器。主要是收發數據包的狀態信息,一般在嵌入式系統中用的比較少,因此暫時沒有加入模擬。
  • 16位模式DMA。對NE2K的芯片,8位DMA和16位DMA模式僅在收發數據效率上不同,但這對SkyEye來說效率並不是很重要,所以僅模擬了8位DMA模式。
  • CPU從網絡芯片收數據包的Remote DMA Read模式。由於8019AS提供了另一種更高效的Send Command方式來收數據包,所以爲簡化起見,沒有模擬Remote DMA Read。

目前設計虛擬以太網芯片設備對簡化的原則是:把虛擬網絡芯片的驅動放到真實8019AS網絡芯片上去,直接能用就可以了,目前還不能保證其它系統上的NE2K驅動能直接在SkyEye上用。

2. 虛擬8019AS網絡芯片原理

SkyEye本身是一個硬件開發板的模擬器。虛擬8019AS網絡芯片是虛擬開發板上一個相對獨立的外部設備,這個設備有自己的內部數據結構和操作函數,完成相應的功能。但虛擬8019AS網絡芯片對外的接口只是幾個提供給SkyEye的API函數和它所佔用的系統資源,如Memory map Io和IRQ等。網絡芯片驅動程序看到的只是8019AS的寄存器和它佔用的系統中斷號,這些寄存器地址位於SkyEye模擬的開發板中某一段IO地址空間內,而SkyEye看到的是寄存器地址和虛擬8019AS網絡芯片提供給SkyEye的API函數。如果運行在虛擬開發板上的網絡芯片驅動程序讀寫這些寄存器地址,那麼SkyEye會截獲這些讀寫操作,並把它們轉換成對虛擬8019AS網絡芯片API接口nic_read和nic_write函數的調用,從而操作虛擬8019AS網絡芯片,並收發數據。這個過程跟真實的硬件系統的邏輯操作是一致的。

那麼SkyEye跟虛擬8019AS網絡芯片交換數據包的同時,8019AS是如何跟主機進行通訊的呢?這是通過Host主機的Linux上安裝的tun/tap或vnet虛擬網絡接口來實現的。tun/tap和vnet是Linux內核中的一個內核模塊,它們模擬了一個簡單的點對點網絡環境,後文會有進一步的說明。虛擬8019AS網絡芯片的整體結構如圖 0-1所示:


圖 0-1 8019AS模擬結構圖
圖 0-1 8019AS模擬結構圖

3. 虛擬8019AS網絡芯片的內存結構

SkyEye模擬的虛擬8019AS網絡芯片工作在8位模式下,網絡芯片含有8K字節的RAM,地址爲0x4000-0x5fff(指的是網絡芯片上的存儲地址,而不是ISA總線的地址,是網絡芯片工作用的存儲器),每256個字節稱爲一頁,共有64頁。頁的地址就是地址的高8位,頁地址爲0x00--0xff 。

首先看一下0x40-0x5f頁,這8k的ram的一部分用來存放接收的數據包,一部分用來存儲待發送的數據包,具體由驅動編寫者自己決定。(一般發包只要能容納一個最大的以太網包就可以了,所以定義爲0x40-0x45頁,即0x4000-0x45ff,約1.5k。剩下的都用來收包)。按照8019AS硬件規範手冊上的規定,8位工作模式下只能使用4000-5fff,16位模式才能用到6000-7fff的RAM,所以我們還是以手冊爲準。


圖 0-2 NE2K兼容網絡芯片的RAM空間結構
圖 0-2 NE2K兼容網絡芯片的RAM空間結構

再看一下第0頁,也就是圖 0 6中的PROM,PROM的內容是網絡芯片在上電覆位的時候從93C46裏讀出來的,其中0x00-0x0B(工作於8位DMA模式)用於存放本節點MAC地址,奇偶地址內容是重複放置的。如:MAC地址00 00 12 34 56 78存放在0x00-0x0B中爲00 00 00 00 12 12 34 34 56 56 78 78,單地址和雙地址的內容是重複的,一般使用偶數地址的內容,這主要是爲了同時適應8位和16位的DMA。8019芯片外接一塊93c46 eeprom,上電時自動從93c46裏把MAC地址讀入到PROM中,所以爲虛擬網絡芯片寫驅動,只要在init函數中讀PROM中的MAC地址,並寫入工作寄存器PAR0-PAR5就可以了。網絡芯片工作時的地址判斷依據就是這幾個寄存器,與PROM及93c46無關。PROM的其它地址不能使用。值得一提的是,雖然一般來說mac地址隨便取一個就可以了,但要注意其最高字節不能是奇數,否則就是一個multicast mac地址,以後的應用中會有問題。

根據以上的分析,虛擬8019AS網絡芯片要模擬的網絡芯片內部RAM共兩塊:

0x0000-0x000B,12字節,頁號爲0x00。存放MAC地址

0x4000-0x5FFF,8192字節,頁號爲0x40-0x60(只用到0x5f,0x60爲結束邊界),用於存放收發的數據包緩衝,具體收發多少由驅動程序初始化決定。

以上兩塊內存都是網絡芯片的內部數據,不在系統的地址空間內,實際上SkyEye模擬的CPU是看不到這兩塊內存的,只能通過讀寫寄存器間接訪問。

4. 虛擬8019AS網絡芯片的寄存器結構

在RTL8019AS或其它NE2k兼容的網絡芯片中,軟件對網絡芯片內存的讀寫是通過一個數據寄存器(地址偏移0x10)進行的,方式是DMA,DMA的長度、起始地址等由控制寄存器決定。而DMA又分爲Remote DMA和Local DMA,首先解釋一下這兩種DMA:

Local DMA
以太網 網絡芯片 RAM
Remote DMA
網絡芯片 RAM host主機

Local DMA是網絡芯片自動收發數據到/從網絡芯片的RAM,而Remote DMA是CPU主動從網絡芯片的RAM讀寫數據到/從CPU的RAM。具體的讀寫其實可以分爲三種:

  • CPU讀/寫數據到網絡芯片
    控制方式是設置如下控制寄存器,它們分別爲:
    • RBCR0,RBCR1:存放要讀寫數據的長度
    • RSAR0,RSAR1:存放數據在網絡芯片RAM中存放的起始地址(而不是頁號,但通常還是以某頁的00爲起始,如0x4000)
    • CR:向命令寄存器發出Remote DMA開始指令

    然後就可以通過數據寄存器去讀寫數據了,寬度爲8位。
  • 網絡芯片發數據到以太網
    CPU把數據用Remote DMA 發到網絡芯片後,就可以讓網絡芯片用Local DMA向外發數據了。
    需要設置如下的控制寄存器,它們分別爲:
    • TPSR :網絡芯片要發送的數據在網絡芯片RAM中的起始頁號。所以發送的數據只能從某頁的開頭存放。
    • TBCR0,TBCR1:要發送的數據總長度
    • CR:向命令寄存器發出發送數據包的指令CMD_XMIT。

    然後程序就可以返回了,網絡芯片會自動用Local DMA發送數據包。
  • 網絡芯片從以太網讀數據
    網絡芯片在從以太網讀取數據過程中,會用到的寄存器如下:
    • PSTART,PSTOP:網絡芯片接收數據緩衝區的起始和終止頁號。形成一個接收緩衝環。每頁256字節
    • CURR:接收緩衝環寫頁指針,初始化=PSTART
    • BNRY:接收緩衝環讀頁指針,初始化=PSTART

這四個寄存器在init函數裏初始化,以後有數據包到來時,網絡芯片自動判斷是否發給本機,是則用Local DMA存入數據,並自動修改讀寫指針。


圖 0-3 與DMA有關的寄存器
圖 0-3 與DMA有關的寄存器

8019AS的寄存器地址爲0x00-0x1f,有page 0-3共4頁,每頁都以0x00-0x0f訪問,但實際訪問的是不同的寄存器。page 3裏的寄存器屬於8019專用,不是NE2K標準,並且不常用,所以不模擬了。我們的寄存器共3頁,頁號爲0-2。此外還有兩個寄存器,不屬於任何頁:

  • 0x10爲DMA讀寫地址,CPU和網絡芯片交換數據通過此地址
  • 0x1F爲Reset地址,向該地址寫或讀任何數都引起網絡芯片復位,一般在初始化時將網絡芯片復位一次,注意復位後要等待幾十ms再進行下一步操作。

表 0 1 8019AS寄存器
表 0 1 8019AS寄存器

下面分別敘述虛擬8019AS網絡芯片所模擬的各頁中寄存器,如表 0 1所示。每個寄存器的各個bit位的具體含義可參考8019AS硬件規範手冊,下面寫出各寄存器的頁內偏移地址,以及編寫驅動時讀寫的常用值表示什麼意思,有助於理解。每個寄存器的各種寫入值可以以"或"的關係運算後寫入,R表示只讀,W表示只寫,R/W表示可以讀也可以寫:

PAGE 0

  • CR控制命令寄存器:0x00,R/W。CR中各個bit位的含意如下:
    CMD_STOP 0x01 網絡芯片停止收發數據
    CMD_RUN 0x02 網絡芯片執行命令並開始收發數據包(命令爲下面四種)
    CMD_XMIT 0x04 Local DMA SEND(網絡芯片――>以太網 )
    CMD_READ 0x08 Remote DMA READ,用於手動接收數據(網絡芯片―>CPU)
    CMD_WRITE 0x10 Remote DMA WRITE (網絡芯片<――CPU)
    CMD_SEND 0x18 Send命令, 用於自動接收數據包(網絡芯片――>CPU)
    CMD_NODMA 0x20 停止DMA操作
    CMD_PAGE0 0x00 選擇第0頁(要先選頁,再讀寫該頁寄存器)
    CMD_PAGE1 0x40 選擇第1頁
    CMD_PAGE2 0x80 選擇第2頁
  • PSTART:0x01,W,接收緩衝環起始頁
    RECV_START 0x4600 接收緩衝起始地址(寫入時要右移8位得到頁號)
  • PSTOP:0x02,W,接收緩衝環終止頁(不包括此頁)
    RECV_STOP 0x6000 接收緩衝結束地址(寫入時要右移8位得到頁號)
  • BNRY,0x03,R/W,接收緩衝環讀指針
    硬件初始化時,PSTART =CURR,以後用CMD_SEND 命令自動收數據包,網絡芯片會自動調整這個寄存器的值。若接收出錯,會重新調整成CURR的值。
  • TPSR,0x04,W,Local DMA發送緩衝起始頁寄存器。
    XMIT_START 0x4000 發送緩衝起始地址(寫入時要右移8位得到頁號)
  • TBCR0,0x05,W,Local DMA發送長度低位。
  • TBCR1,0x06,W,Local DMA發送長度高位。
    上述兩個寄存器是網絡芯片外發數據包的長度,執行發送命令前根據實際長度設置。
  • ISR,0x07,R/W,中斷狀態寄存器,各個bit位的含意如下:
    ISR_PRX 0x01 正確接收數據包中斷。做接收處理
    ISR_PTX 0x02 正確發送數據包中斷。做不做處理要看上層軟件了。
    ISR_RXE 0x04 接收數據包出錯。做重新設置BNRY=CURR處理。
    ISR_TXE 0x08 由於衝突次數過多,發送出錯。做重發處理
    ISR_OVW 0x10 網絡芯片內存溢出。做軟件重啓網絡芯片處理。見手冊。
    ISR_CNT 0x20 出錯計數器中斷,屏蔽掉(屏蔽用IMR寄存器)。
    ISR_RDC 0x40 Remote DMA結束 。屏蔽掉。輪詢等待DMA結束。
    ISR_RST 0x80 網絡芯片Reset,屏蔽掉。

    在中斷處理程序中讀出ISR寄存器的值,分別與以上各值"與",若結果爲1則表示發生了該種中斷,需要處理,處理完畢向ISR寄存器寫入該值(即將該中斷位置1)即可清除該中斷。
    比如:if (isr & ISR_PRX) {
        處理收到的數據包;
         IOWRITE(R_ISR,ISR_PRX); 清除正確接收數據包中斷
       };
  • RSAR0,0x08,W,Remote DMA目的起始地址低位
    XMIT_START 0x4000 取其低位
  • RSAR1,0x09,W,Remote DMA目的起始地址高位
    XMIT_START 0x4000 取其高位
  • RBCR0,0x0A,W,Remote DMA數據長度低位
  • RBCR1,0x0B,W,Remote DMA數據長度高位
    上述兩個寄存器是CPU向網絡芯片寫入或讀出數據包的實際長度,執行Remote DMA命令前需要設置這兩個寄存器。
  • RCR,0x0C,W,接收配置寄存器,
    初始化時寫入0x04,表示只接收發給本網絡芯片MAC地址的、大於64字節的以太網包或廣播包。
  • TCR,0x0D,W,發送配置寄存器
    初始化開始時寫入0x02,表示置網絡芯片爲Loop Back模式,停止發送數據包,初始化結束寫入0x00。正常發送數據包並加上CRC。
  • DCR,0x0E,W,數據配置寄存器
    初始化時寫入0x48,表示8位模式,FIFO深度8字節,DMA方式。
  • IMR,0x0F,W,中斷屏蔽寄存器
    它的各位和ISR中的各位相對應,向IMR寫入以下各值即爲打開相應中斷,
    ISR_PRX 0x01
    ISR_PTX 0x02
    ISR_RXE 0x04
    ISR_TXE 0x08
    ISR_OVW 0x10
    ISR_CNT 0x20
    ISR_RDC 0x40
    ISR_RST 0x80
    如IOWRITE(R_IMR, ISR_OVW | ISR_PRX )表示打開溢出和接收中斷,其它中斷都屏蔽。

PAGE 1:

  • CR:0x00,R/W,含意與PAGE0的CR含意相同
  • PAR0,0x01,R/W,網絡芯片MAC地址最高位
  • PAR1,0x02,R/W,網絡芯片MAC地址
  • PAR2,0x03,R/W,網絡芯片MAC地址
  • PAR3,0x04,R/W,網絡芯片MAC地址
  • PAR4,0x05,R/W,網絡芯片MAC地址
  • PAR5,0x06,R/W,網絡芯片MAC地址最低位
    如網絡芯片的MAC地址爲:00:01:02:03:04:05,則PARi=0x0i。初始化時網絡芯片會從PROM讀出MAC地址並寫入這六個寄存器。
  • CURR,0x07,R/W,接收緩衝環寫指針, 指向下一個包到來時的起始頁。
    硬件初始化時,CURR=BNRY=PSTART,以後由網絡芯片自動負責更新。
    PAGE1中,偏移量0x08到0x0F這8個寄存器是組播地址寄存器,它們決定了網絡芯片對組播數據包的收發,暫時不模擬這8個寄存器。

PAGE 2:

  • CR,0x00,R/W,含意與PAGE0的CR含意相同
  • PSTART,0x01,R,用來讀PSTART狀態
  • PSTOP,0x02, R,用來讀PSTOP狀態
  • TPSR,0x04, R,用來讀TPSR狀態
  • RCR,0x0C, R,用來讀接收配置寄存器RCR狀態
  • TCR,0x0D, R,用來讀發送配置寄存器TCR狀態
  • DCR,0x0E, R,用來讀數據配置寄存器DCR狀態
  • IMR,0x0F, R,用來讀中斷屏蔽寄存器IMR狀態

這頁的寄存器大部分是隻讀的,可讀出相關的配置信息等。

5. 虛擬網絡芯片接收數據包的方法

在前面CR寄存器的說明中可以看到,普通的RTL8019從網絡芯片RAM讀數據到CPU有兩種方式:

1. 目前SkyEye虛擬網絡芯片還不支持Remote DMA READ方式:
硬件初始化時,BNRY讀指針 = CURR寫指針-1 =PSTART。
有數據包要讀時,操作步驟如下:

a.查看bnry是否=CURR-1,不等則說明有數據包要讀
b.用bnry初始化DMA起址控制器RSAR0,1
c 用18初始化DMA長度控制器RBCR0,1
d.執行Remote DMA READ命令
e.讀出以太網包頭(18字節),從包頭中讀出包長度
f.同b-e讀出所有數據
g.調整bnry指針=CURR-1
這期間如果bnry指到了緩衝環的尾部還要手工調整它回到環的開頭。

2.虛擬8019網絡芯片支持更快更簡單的SEND COMMAND方式,讀數據包的步驟如下:
硬件初始化時,BNRY = CURR = PSTART
有數據包要讀時,操作步驟如下:
a.向RBCR1寄存器寫入0FH(硬性規定)
IOWRITE(R_RBCR1, 0x0f);
b.執行SEND COMMAND命令
IOWRITE(R_CR, CMD_PAGE0 | CMD_SEND | CMD_RUN)
然後網絡芯片自動做了如下工作:
I. 用當前的BNRY讀指針指向的地址寫入DMA控制器(RSAR0,1)
II.用以太網包頭中的包長度初始化DMA控制器(RBCR0,1)
c.先讀18個字節的包頭看看是否是合法的數據包
d.從0x10端口讀數據……。(讀多少當然要你自己去看以太網包頭了)

6. skyeye_ne2k.c函數說明

  • nic_init:調用nic_reset初始化虛擬網絡芯片。
  • nic_reset:初始化虛擬8019AS的各項結構,包括寄存器,卡上PROM和RAM等。
  • nic_read:網絡芯片的讀操作函數,根據參數給出的寄存器偏移量,返回相應寄存器的當前值;如果讀的是0x10寄存器,調用DMA輸入函數remote_read;如果讀的是0x1f寄存器,調用nic_reset重新啓動網絡芯片。
  • nic_write:網絡芯片寫操作函數,根據參數給出的寄存器偏移量,修改相應寄存器的值;如果寫的是0x00 CR寄存器,調用write_cr改變網絡芯片當前狀態;如果寫的是0x10寄存器,調用DMA輸出函數remote_write;如果寫的是0x1f寄存器,調用nic_reset重新啓動網絡芯片。
  • tapif_input:從tapif網絡接口讀取網絡包,轉存入8019AS設備的內部RAM(即上圖中的8192字節的數組)。注意RTL8019AS在收到網絡包時會在最前面加上四個字節:0x10、0x50和兩字節的包長度,爲了與真實8019AS網絡芯片完全兼容,SkyEye的虛擬8019AS網絡芯片也模擬了這一特點。包轉存完畢後,tapif_input函數修改SkyEye的中斷狀態寄存器,然後返回。SkyEye會在下一次檢查中斷狀態寄存器時進入中斷狀態。
  • tapif_output:這個函數被虛擬8019AS網絡芯片的發包函數調用,負責從8019AS的內部RAM讀出要發送的網絡包,轉發到tapif網絡芯片接口。

7. tapif和vnet虛擬網絡接口說明

tun/tap設備和vnet設備爲網絡接口設備(struct net_device),被鏈接到網絡接口鏈表中。一般在函數tun_set_iff()裏創建和註冊。

8. 網絡芯片驅動程序分析

編寫驅動程序時對DMA結束的判斷的說明 cpu--->NIC's ram 的DMA結束標誌是ISR_RDC中斷: while((char) (IOREAD(R_ISR) & ISR_RDC) == 0 ); 這裏是循環等待了,如果做得更好可以先返回,等待結束中斷,一般沒必要了。

NIC'ram ---> network的DMA結束標誌是ISR_PTX中斷如果上層軟件還有包要連續發送,可以打開這個中斷,然後在ISR中繼續發下一個包。否則沒必要處理這個中斷,可以屏蔽它。(這就類似於串口UART的發送成功中斷,如果要發一個字符串,就使用這個中斷,只發送一個字符就沒必要了。)

在Linux系統的ne2k driver中也是死等一段時間,見ne2k.c中的代碼:

	while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
		if (jiffies - dma_start > 2*HZ/100) {		/* 20ms */
			printk("%s: timeout waiting for Tx RDC./n", dev->name);
			ne_reset_8390(dev);
			NS8390_init(dev,1);
			break;
		}



參考資料



關於作者

陳渝, 清華大學,通過 [email protected] 可以和他聯繫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章