リンク層とインターネット層を接続するLow-level APIを実装します。Low-level APIは、FPGAに実装されたEthernet MAC CoreとLocal Memoryをアクセスし、Ethernet Frameの送受信を行います。
APIの仕様
Ethernet Frameの送信
void ether_write_frame(int flen,unsigned char *fbuf);
- 説明
- fbufに格納された、長さflenのByteデータをEthernet Frameとして送信します。
- 戻り値
- なし
Ethernet Frameの受信
int ether_read_frame(unsigned char *fbuf);
- 説明
- 受信したEthernet Frameを、fbufにByteデータとして格納します。
- 戻り値
- fbufに格納したByteデータの長さ。
Ethernet Frameの送信フロー
Ethernet Frameの送信は、以下の手順で行います。
- FrameデータをCPUからFPGA内Local Memoryに転送
- Ethernet MAC CoreのMode RegisterのTXEN bitを1に設定
- Ethernet MAC CoreのTx Buffer DescriptorのTXPNTに、Frameデータを格納したLocal Memoryのアドレスを設定
- Tx Buffer DescriptorのRD bitを1に設定
- 送信完了のインタラプトを待つ
- インタラプトを解除
FrameのCRCは、Ethernet MAC CoreからPHYへの転送時に計算されて付加されます。Tx Buffer Descriptorが有効化されると、Ethernet MAC CoreはTx Buffer Descriptorレジスタの設定に従って、送信データをLocal Memoryから読み出し、Ethernet FrameとしてPHYに出力します。
送信用API ether_write_frameの実装
コード実装は以下の通りです。
void ether_write_frame(int flen,unsigned char *fbuf) { int i, flush; struct st_txdesc_l txl; unsigned int a; // Tx Buffer Descriptorの設定 txl.LONG = 0; txl.IRQ = 1; // Interrupt Request Enable txl.PAD = 1; // PAD Enable txl.CRC = 1; // CRC Enable txl.WR = 1; // Wrap // 送信データの設定 a = ETHER_BUF_TX_BASE; // Local Memoryの先頭アドレス for (i=0; i< flen;i++) { if (((a+i) % 4) == 3) flush = 1; else flush = 0; if (i == (flen -1)) flush = 1; // final data ether_write_byte(a+i, fbuf[i], flush); // Byte単位でFrameデータをLocal Memoryにセット } // set TxBD ready for descriptor 0 txl.RD = 1; // Tx Buffer Descriptorを有効化 (*(volatile unsigned int *)(ETHER_BD_BASE)) = txl.LONG; }
Ethernet Frameの受信フロー
Ethernet Frameの受信は、以下の手順で行います。
- Ethernet MAC CoreのMode RegisterのRXEN bitを1に設定
- Ethernet MAC CoreのRx Buffer DescriptorのRXPNTに、Frameデータを格納するLocal Memoryのアドレスを設定
- Ethernet MAC CoreのRx Buffer DescriptorのE(Empty)bitを1に設定
- 受信完了インタラプトを待つ
- インタラプトを解除
- FrameデータをLocal MemoryからCPUに転送
PHYからEthernet Frameを受信すると、Ethernet MAC CoreはRx Buffer Descriptorレジスタの設定に従って、Ethernet FrameをLocal Memoryに格納します。受信Frameは、Rx Buffer DescriptorのRXPNTが示すLocal Memoryのアドレスに格納されます。FrameのCRCは、Local Memoryへの格納時に削除されます。
受信用API ether_read_frameの実装
コード実装は以下の通りです。
int ether_read_frame(unsigned char *fbuf) { int i,j,p, size,s; unsigned int x; struct st_rxdesc_l rxl; rxl.LONG = (*(volatile unsigned int *)(ETHER_BD_RX_BASE+ether_cur_rx_bd*8)); size = rxl.LEN; // 受信FrameのByte長を獲得 p =0; s = size /4; if ((size %4 ) != 0) s++; for (i = 0; i< s; i++) { // 32bit単位でLocal Memoryからデータをリード x =(*(volatile unsigned int *)(ETHER_BUF_RX_BASE+ether_cur_rx_bd*ETHER_BUFFER_SIZE+i*4)); for (j=0;j <4; j++) { fbuf[p] = (x > (3-j)*8)&0xff; // fbufにByte単位で格納 p++; } } rxl.LEN = 0; rxl.E = 1; // Rx Buffer DescriptorのEmpty bitをセット (*(volatile unsigned int *)(ETHER_BD_RX_BASE+ether_cur_rx_bd*8)) = rxl.LONG; if (ether_cur_rx_bd == (ETHER_MAX_RX_BD-1)) ether_cur_rx_bd = 0; else ether_cur_rx_bd++; return size; // Frameのデータサイズを返す }