0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

以太網(wǎng)控制器程序的仿真與測(cè)試

我快閉嘴 ? 來(lái)源:FPGA技術(shù)江湖 ? 作者:FPGA技術(shù)江湖 ? 2022-07-18 11:35 ? 次閱讀

今天給大俠帶來(lái)基于FPGA以太網(wǎng)控制器(MAC)設(shè)計(jì),由于篇幅較長(zhǎng),分三篇。今天帶來(lái)第三篇,下篇,程序的仿真與測(cè)試和總結(jié)。話不多說(shuō),上貨。

導(dǎo)讀

當(dāng)前,互聯(lián)網(wǎng)已經(jīng)極大地改變了我們的生產(chǎn)和生活。與之相適應(yīng)的,在嵌入式系統(tǒng)的研究開(kāi)發(fā)方面,也越來(lái)越重視網(wǎng)絡(luò)功能。嵌入式系統(tǒng)已經(jīng)不再局限于一個(gè)個(gè)孤立的控制、處理單元,而是走向網(wǎng)絡(luò)集成化,從而實(shí)現(xiàn)了多個(gè)系統(tǒng)的集中控制、信息共享。

以太網(wǎng)(Ethernet)技術(shù)在嵌入式系統(tǒng)上的開(kāi)發(fā)應(yīng)用,已經(jīng)成為當(dāng)前嵌入式研究領(lǐng)域的技術(shù)熱點(diǎn)之一。一方面,與傳統(tǒng)的 RS-485CAN 等相比較,以太網(wǎng)更加高速、通用,而且還可以直接與 Internet 相連接,提供更大范圍的遠(yuǎn)程訪問(wèn);此外,經(jīng)過(guò)適當(dāng)剪裁和優(yōu)化的 TCP/IP協(xié)議棧,也完全可以適應(yīng)工業(yè)用途的需求。另一方面,相對(duì)于新興的 USB 2.0、IEEE 1394 等總線,以太網(wǎng)技術(shù)在傳輸距離、布線成本以及控制軟件的通用性上都有明顯的優(yōu)勢(shì)。

基于以太網(wǎng)的嵌入式系統(tǒng),在以下方面都有良好的應(yīng)用前景:

? 工業(yè):工業(yè)控制、網(wǎng)絡(luò)儀表、遠(yuǎn)程的分布式數(shù)據(jù)采集……

? 家庭自動(dòng)化:智能家庭、信息家電、家庭網(wǎng)關(guān)……

? 商業(yè):遠(yuǎn)程銷(xiāo)售平臺(tái)、智能自動(dòng)售貨機(jī)、公共電話卡發(fā)行系統(tǒng)……

? 環(huán)保:水源和空氣污染監(jiān)測(cè),防洪體系及水土質(zhì)量監(jiān)測(cè)、堤壩安全……

? 其他:交通管理、車(chē)輛導(dǎo)航、自動(dòng)抄表……

因此在使用 FPGA 設(shè)計(jì)各種嵌入式應(yīng)用系統(tǒng)時(shí),需要考慮為系統(tǒng)提供以太網(wǎng)接口。本章將通過(guò) FPGA 實(shí)現(xiàn)一個(gè)以太網(wǎng)控制器(MAC)的實(shí)例,詳細(xì)介紹實(shí)現(xiàn)過(guò)程。

第三篇內(nèi)容摘要:本篇會(huì)介紹程序的仿真與測(cè)試和總結(jié),包括頂層程序、外部 PHY 芯片模擬程序、仿真結(jié)果等相關(guān)內(nèi)容。

四、程序的仿真與測(cè)試

上面已經(jīng)介紹了程序的主要部分。為了檢驗(yàn)程序是否實(shí)現(xiàn)預(yù)先設(shè)定的功能,需要編寫(xiě)仿真程序。

以太網(wǎng)控制器的仿真程序(Testbench)需要同時(shí)模擬數(shù)據(jù)通信的兩端:主機(jī)(上層協(xié)議)和外部 PHY 芯片。因此,設(shè)計(jì)仿真程序的結(jié)構(gòu)如圖 12 所示。

cd3db208-04a1-11ed-ba43-dac502259ad0.png

圖 12 以太網(wǎng)控制器程序Testbench 的結(jié)構(gòu)

從圖 12 上可以看到仿真程序應(yīng)該包括:頂層程序、模擬 PHY 程序、模擬主機(jī)程序和以太網(wǎng)控制程序。

4.1 頂層程序

頂層程序負(fù)責(zé)連接仿真程序的各個(gè)部分:模擬 PHY 程序、模擬主機(jī)程序和以太網(wǎng)控制程序。同時(shí)頂層程序需要控制仿真的進(jìn)行,主要代碼如下:

`include "eth_phy_defines.v"`include "wb_model_defines.v"`include "tb_eth_defines.v"`include "eth_defines.v"`include "timescale.v"module tb_ethernet();
//寄存器與連線  reg wb_clk;  ……
//連接以太網(wǎng)控制器eth_top eth_top(                .wb_clk_i(wb_clk), .wb_rst_i(wb_rst),                .wb_adr_i(eth_sl_wb_adr_i[11:2]), .wb_sel_i(eth_sl_wb_sel_i), .wb_we_i(eth_sl_wb_we_i),                .wb_cyc_i(eth_sl_wb_cyc_i), .wb_stb_i(eth_sl_wb_stb_i), .wb_ack_o(eth_sl_wb_ack_o),                .wb_err_o(eth_sl_wb_err_o), .wb_dat_i(eth_sl_wb_dat_i), .wb_dat_o(eth_sl_wb_dat_o),                .m_wb_adr_o(eth_ma_wb_adr_o), .m_wb_sel_o(eth_ma_wb_sel_o), .m_wb_we_o(eth_ma_wb_we_o), .m_wb_dat_i(eth_ma_wb_dat_i), .m_wb_dat_o(eth_ma_wb_dat_o), .m_wb_cyc_o(eth_ma_wb_cyc_o),                .m_wb_stb_o(eth_ma_wb_stb_o), .m_wb_ack_i(eth_ma_wb_ack_i), .m_wb_err_i(eth_ma_wb_err_i),                //發(fā)送數(shù)據(jù)                .mtx_clk_pad_i(mtx_clk), .mtxd_pad_o(MTxD), .mtxen_pad_o(MTxEn), .mtxerr_pad_o(MTxErr),                //接收數(shù)據(jù)部分                .mrx_clk_pad_i(mrx_clk), .mrxd_pad_i(MRxD), .mrxdv_pad_i(MRxDV), .mrxerr_pad_i(MRxErr),                .mcoll_pad_i(MColl), .mcrs_pad_i(MCrs),                //媒體無(wú)關(guān)接口模塊                .mdc_pad_o(Mdc_O), .md_pad_i(Mdi_I), .md_pad_o(Mdo_O), .md_padoe_o(Mdo_OE),                .int_o(wb_int)                )
//連接模擬 PHY 部分  assign Mdio_IO = Mdo_OE ? Mdo_O : 1'bz ;  assign Mdi_I = Mdio_IO;
  integerphy_log_file_desc;
  eth_phyeth_phy(                  .m_rst_n_i(!wb_rst),                  // MAC 發(fā)送數(shù)據(jù)                  .mtx_clk_o(mtx_clk), .mtxd_i(MTxD), .mtxen_i(MTxEn), .mtxerr_i(MTxErr),                  // MAC 接收數(shù)據(jù)                  .mrx_clk_o(mrx_clk), .mrxd_o(MRxD), .mrxdv_o(MRxDV), .mrxerr_o(MRxErr),                  .mcoll_o(MColl), .mcrs_o(MCrs),                  //媒體無(wú)關(guān)接口模塊                  .mdc_i(Mdc_O), .md_io(Mdio_IO),                  .phy_log(phy_log_file_desc));// 連接主機(jī)模塊  integer host_log_file_desc;  WB_MASTER_BEHAVIORALwb_master(                                  .CLK_I(wb_clk),                                  .RST_I(wb_rst),                                  .TAG_I({`WB_TAG_WIDTH{1'b0}}),                                  .TAG_O(),                                  .ACK_I(eth_sl_wb_ack_o),                                  .ADR_O(eth_sl_wb_adr), // only eth_sl_wb_adr_i[11:2] used                                  .CYC_O(eth_sl_wb_cyc_i),                                  .DAT_I(eth_sl_wb_dat_o),                                  .DAT_O(eth_sl_wb_dat_i),                                  .ERR_I(eth_sl_wb_err_o),                                  .RTY_I(1'b0), // inactive (1'b0)                                  .SEL_O(eth_sl_wb_sel_i),                                  .STB_O(eth_sl_wb_stb_i),                                  .WE_O (eth_sl_wb_we_i),                                  .CAB_O() // NOT USED for now!                                  )
  assign eth_sl_wb_adr_i = {20'h0, eth_sl_wb_adr[11:2], 2'h0};  ……
//初始化  initial  begin  //復(fù)位信號(hào)  wb_rst = 1'b1;  #423 wb_rst = 1'b0;//清除存儲(chǔ)器內(nèi)容  clear_memories;  clear_buffer_descriptors;  #423 StartTB = 1'b1;  end
//產(chǎn)生時(shí)鐘信號(hào)  initial  begin  wb_clk=0;  forever #15 wb_clk = ~wb_clk; // 2*10 ns -> 33.3 MHz  end
  integer tests_successfull;  integer tests_failed;  reg [799:0] test_name; // used for tb_log_file  reg [3:0] wbm_init_waits; // initial wait cycles between CYC_O and STB_O of WB Master  reg [3:0] wbm_subseq_waits; // subsequent wait cycles between STB_Os of WB Master  reg [2:0] wbs_waits; // wait cycles befor WB Slave responds  reg [7:0] wbs_retries; // if RTY response, then this is the number of retries before ACKregwbm_working;//taskswbm_writeandwbm_readsetsignalwhenworkingandresetitwhenstopworking
//開(kāi)始測(cè)試內(nèi)容  initial  begin  wait(StartTB); // 開(kāi)始測(cè)試  //初始化全局變量  tests_successfull = 0;  tests_failed = 0;  wbm_working = 0;  wbm_init_waits = 4'h1;  wbm_subseq_waits = 4'h3;  wbs_waits = 4'h1;  wbs_retries = 8'h2;  wb_slave.cycle_response(`ACK_RESPONSE, wbs_waits, wbs_retries);
//測(cè)試的各個(gè)任務(wù)  test_note("PHY generates ideal Carrier sense and Collision signals for following tests");  eth_phy.carrier_sense_real_delay(0);  test_mac_full_duplex_transmit(0, 21); //測(cè)試全雙工方式下傳輸數(shù)據(jù)  test_mac_full_duplex_receive(0, 13); //測(cè)試全雙工方式下接收數(shù)據(jù)  test_mac_full_duplex_flow_control(0, 4); // 測(cè)試整個(gè)數(shù)據(jù)流程  test_note("PHY generates 'real delayed' Carrier sense and Collision signals for following  tests");eth_phy.carrier_sense_real_delay(1);// 結(jié)束測(cè)試  test_summary;  $stop;  end

測(cè)試內(nèi)容通過(guò)多個(gè)測(cè)試任務(wù)來(lái)執(zhí)行。限于篇幅,測(cè)試任務(wù)的內(nèi)容不一一列出。

4.2 外部 PHY 芯片模擬程序

模擬程序模擬了簡(jiǎn)化的 LXT971A 芯片(Inter 公司的外部 PHY 芯片)。PHY 芯片通過(guò) MIIM(媒體無(wú)關(guān)接口管理模塊)來(lái)連接以太網(wǎng)控制器,因此:

? 當(dāng)以太網(wǎng)控制器向 PHY 芯片模擬程序發(fā)送數(shù)據(jù)時(shí),PHY 芯片模擬程序控制數(shù)據(jù)按照協(xié)議的進(jìn)行傳輸;

? 當(dāng) PHY 芯片向以太網(wǎng)控制器發(fā)送數(shù)據(jù)時(shí),外部 PHY 芯片模擬程序首先按照協(xié)議要求產(chǎn)生需要傳輸?shù)臄?shù)據(jù),然后發(fā)送到以太網(wǎng)控制器。

外部 PHY 芯片模擬程序的主要代碼如下:

`include "timescale.v"`include "eth_phy_defines.v"`include "tb_eth_defines.v"module eth_phy (m_rst_n_i, mtx_clk_o, mtxd_i, mtxen_i, mtxerr_i, mrx_clk_o, mrxd_o, mrxdv_o,mrxerr_o,mcoll_o,mcrs_o,mdc_i,md_io,phy_log);
//輸入輸出信號(hào)  input m_rst_n_i;  ……
//寄存器和連線  reg control_bit15; // self clearing bit  ……
// PHY 芯片模擬程序的 MIIM 部分  ……
//初始化  initial  begin    md_io_enable = 1'b0;    respond_to_all_phy_addr = 1'b0;    no_preamble = 1'b0;  end
// 使輸出處于三態(tài)  assign #1 md_io = (m_rst_n_i && md_io_enable) ? md_io_output : 1'  bz ;
//寄存器輸入  always@(posedge mdc_i or negedge m_rst_n_i)  begin    if (!m_rst_n_i)      md_io_reg <= #1 0;    else      md_io_reg <= #1 md_io;  end
// 獲得 PHY 地址、寄存器地址和數(shù)據(jù)輸入,把需要輸出的數(shù)據(jù)移位輸出// putting Data out and shifting  always@(posedge mdc_i or negedge m_rst_n_i)  begin    if (!m_rst_n_i)      begin        phy_address <= 0;        reg_address <= 0;        reg_data_in <= 0;        reg_data_out <= 0;        md_io_output <= 0;      end    else      begin        if (md_get_phy_address)          begin            phy_address[4:1] <= phy_address[3:0]; // correct address is `ETH_PHY_ADDR            phy_address[0] <= md_io;          end        if (md_get_reg_address)          begin            reg_address[4:1] <= reg_address[3:0];            reg_address[0] <= md_io;          end        if (md_get_reg_data_in)          begin            reg_data_in[15:1] <= reg_data_in[14:0];            reg_data_in[0] <= md_io;          end        if (md_put_reg_data_out)          begin  reg_data_out<=?register_bus_out;          end        if (md_io_enable)          begin            md_io_output <= reg_data_out[15];            reg_data_out[15:1] <= reg_data_out[14:0];            reg_data_out[0] <= 1'b0;          end      end  end
  assign #1 register_bus_in = reg_data_in; // md_put_reg_data_in - allows writing to a selected
  register// 統(tǒng)計(jì)通過(guò) MIIM(媒體無(wú)關(guān)接口管理模塊)傳輸?shù)臄?shù)據(jù)  always@(posedge mdc_i or negedge m_rst_n_i)  begin    if (!m_rst_n_i)      begin        if (no_preamble)          md_transfer_cnt <= 33;        else          md_transfer_cnt <= 1;          end        else          begin            if (md_transfer_cnt_reset)              begin                if (no_preamble)                  md_transfer_cnt <= 33;                else                  md_transfer_cnt <= 1;                  end                else if (md_transfer_cnt < 64)                  begin                    md_transfer_cnt <= md_transfer_cnt + 1'b1;                  end                else                  begin                    if (no_preamble)                      md_transfer_cnt <= 33;                    else                      md_transfer_cnt <= 1;                  end            end  end
// MIIM 的傳輸控制always@(m_rst_n_iormd_transfer_cntormd_io_regormd_io_rd_wrorphy_addressorrespond_to_all_phy_addrorno_preamble)  begin  #1;  while ((m_rst_n_i) && (md_transfer_cnt <= 64))  begin// 復(fù)位信號(hào)// 檢查報(bào)頭    if (md_transfer_cnt < 33)      begin        #4 md_put_reg_data_in = 1'b0;        if (md_io_reg !== 1'b1)          begin          #1 md_transfer_cnt_reset = 1'b1;          end        else          begin          #1 md_transfer_cnt_reset = 1'b0;          endend//檢查開(kāi)始位    else if (md_transfer_cnt == 33)      begin        if (no_preamble)          begin          #4 md_put_reg_data_in = 1'b0;        if (md_io_reg === 1'b0)          begin          #1 md_transfer_cnt_reset = 1'b0;          end        else          begin            #1 md_transfer_cnt_reset = 1'b1;            //if ((md_io_reg !== 1'bz) && (md_io_reg !== 1'b1))            if (md_io_reg !== 1'bz)          begin//錯(cuò)誤            `ifdef VERBOSE            $fdisplay(phy_log, "*E (%0t)(%m)MIIM - wrong first start bit (without preamble)",            $time);            `endif            #10 $stop;          end    end  end
  else // with preamble          begin            #4 ;            `ifdef VERBOSE            $fdisplay(phy_log, " (%0t)(%m)MIIM - 32-bit preamble received", $time);            `endif            // check start bit only if md_transfer_cnt_reset is inactive, because if            // preamble suppression was changed start bit should not be checked            if ((md_io_reg !== 1'b0) && (md_transfer_cnt_reset == 1'b0))            begin// 錯(cuò)誤              `ifdef VERBOSE              $fdisplay(phy_log, "*E (%0t)(%m)MIIM - wrong first start bit", $time);              `endif              #10 $stop;            end          end        end      else if (md_transfer_cnt == 34)        begin        #4;        if (md_io_reg !== 1'b1)          begin // 錯(cuò)誤            #1;            `ifdef VERBOSE            if (no_preamble)            $fdisplay(phy_log, "*E (%0t)(%m)MIIM - wrong second start bit (without preamble)",            $time);          else              $fdisplay(phy_log, "*E (%0t)(%m)MIIM - wrong second start bit", $time);              `endif              #10 $stop;            end            else            begin              `ifdef VERBOSE              if (no_preamble)  #1$fdisplay(phy_log,"(%0t)(%m)MIIM-2startbitsreceived(withoutpreamble)",$time);              else                #1 $fdisplay(phy_log, " (%0t)(%m)MIIM - 2 start bits received", $time);              `endif            endend            // 寄存器 op-code            else if (md_transfer_cnt == 35)            begin              #4;                if (md_io_reg === 1'b1)                  begin                  #1 md_io_rd_wr = 1'b1;            end                else                  begin                    #1 md_io_rd_wr = 1'b0;                  end            end            else if (md_transfer_cnt == 36)            begin            #4;            if ((md_io_reg === 1'b0) && (md_io_rd_wr == 1'b1))            begin            #1 md_io_rd_wr = 1'b1; // reading from PHY registers            `ifdef VERBOSE            $fdisplay(phy_log, " (%0t)(%m)MIIM - op-code for READING from registers", $time);            `endif            end            else if ((md_io_reg === 1'b1) && (md_io_rd_wr == 1'b0))            begin            #1 md_io_rd_wr = 1'b0; // writing to PHY registers            `ifdef VERBOSE            $fdisplay(phy_log, " (%0t)(%m)MIIM - op-code for WRITING to registers", $time);            `endif            end            else            begin            // 操作碼錯(cuò)誤            `ifdef VERBOSE            #1 $fdisplay(phy_log, "*E (%0t)(%m)MIIM - wrong OP-CODE", $time);            `endif            #10 $stop;  end
// 獲得 PHY 地址  begin  #1 md_get_phy_address = 1'b1;  end  end  else if (md_transfer_cnt == 41)  begin  #4 md_get_phy_address = 1'b0;  // set the signal - get register address  #1 md_get_reg_address = 1'b1;  end  // 獲得寄存器地址  else if (md_transfer_cnt == 46)  begin  #4 md_get_reg_address = 1'b0;  #1 md_put_reg_data_out = 1'b1;  end  ……
// PHY 芯片與以太網(wǎng)控制器之間數(shù)據(jù)傳輸?shù)目刂?/span>// 寄存器  reg mcoll_o;  ……//初始化所有寄存器  initial  begin    mcrs_rx = 0;    mcrs_tx = 0;    task_mcoll = 0;    task_mcrs = 0;    task_mcrs_lost = 0;    no_collision_in_half_duplex = 0;    collision_in_full_duplex = 0;    no_carrier_sense_in_tx_half_duplex = 0;    no_carrier_sense_in_rx_half_duplex = 0;    carrier_sense_in_tx_full_duplex = 0;    no_carrier_sense_in_rx_full_duplex = 0;    real_carrier_sense = 0;  end
// 數(shù)據(jù)沖突  always@(m_rst_n_i or control_bit8_0 or collision_in_full_duplex ormcrs_rxormcrs_txortask_mcollorno_collision_in_half_duplex)  begin    if (!m_rst_n_i)      mcoll_o = 0;    else      begin    if (control_bit8_0[8]) // full duplex      begin    if (collision_in_full_duplex) // collision is usually not asserted in full duplex      begin      mcoll_o = ((mcrs_rx && mcrs_tx) || task_mcoll);      `ifdef VERBOSE      if (mcrs_rx && mcrs_tx)            $fdisplay(phy_log, " (%0t)(%m) Collision set in FullDuplex!", $time);        if (task_mcoll)          $fdisplay(phy_log, " (%0t)(%m) Collision set in FullDuplex from TASK!", $time);      `endif        end      else          begin            mcoll_o = task_mcoll;            `ifdef VERBOSE            if (task_mcoll)            $fdisplay(phy_log, " (%0t)(%m) Collision set in FullDuplex from TASK!", $time);            `endif          end      end          else // half duplex          beginmcoll_o=((mcrs_rx&&mcrs_tx&&!no_collision_in_half_duplex)||task_mcoll);            `ifdef VERBOSE            if (mcrs_rx && mcrs_tx)            $fdisplay(phy_log, " (%0t)(%m) Collision set in HalfDuplex!", $time);            if (task_mcoll)            $fdisplay(phy_log, " (%0t)(%m) Collision set in HalfDuplex from TASK!", $time);            `endif          end     end  end
//載波監(jiān)聽(tīng)多路訪問(wèn)  always@(m_rst_n_i or control_bit8_0 or carrier_sense_in_tx_full_duplex or  no_carrier_sense_in_rx_full_duplex or  no_carrier_sense_in_tx_half_duplex or  no_carrier_sense_in_rx_half_duplex ormcrs_rxormcrs_txortask_mcrsortask_mcrs_lost)  begin    if (!m_rst_n_i)      mcrs_o = 0;  else    begin      if (control_bit8_0[8]) // full duplex        begin    if(carrier_sense_in_tx_full_duplex)//carriersenseisusuallynotassertedduringTXinfullduplex            mcrs_o = ((mcrs_rx && !no_carrier_sense_in_rx_full_duplex) ||            mcrs_tx || task_mcrs) && !task_mcrs_lost;          else            mcrs_o = ((mcrs_rx && !no_carrier_sense_in_rx_full_duplex) ||            task_mcrs) && !task_mcrs_lost;         end      else // half duplex        begin          mcrs_o = ((mcrs_rx && !no_carrier_sense_in_rx_half_duplex) ||          (mcrs_tx && !no_carrier_sense_in_tx_half_duplex) ||          task_mcrs) && !task_mcrs_lost;        end    end  end
// 以太網(wǎng)控制器發(fā)送數(shù)據(jù)控制,PHY 芯片接收數(shù)據(jù)//寄存器reg[7:0]tx_mem[0:4194303];//4194304是22位地址線所能提供的所有地址,每個(gè)地址是8位  ……
//發(fā)送數(shù)據(jù)控制  always@(posedge mtx_clk_o)  begin//保存數(shù)據(jù)并進(jìn)行基本的幀數(shù)據(jù)檢查    if (!m_rst_n_i)      begin        tx_cnt <= 0;        tx_preamble_ok <= 0;        tx_sfd_ok <= 0;        tx_len <= 0;        tx_len_err <= 0;      end    else      begin        if (!mtxen_i)          begin            tx_cnt <= 0;          end        else          begin//發(fā)送四位字節(jié)數(shù)據(jù)的計(jì)數(shù)器            tx_cnt <= tx_cnt + 1;//設(shè)置初始化值,檢查第一個(gè)四位字節(jié)數(shù)據(jù)的報(bào)頭        if (tx_cnt == 0)            begin              `ifdef VERBOSE              $fdisplay(phy_log, " (%0t)(%m) TX frame started with tx_en set!", $time);              `endif                if (mtxd_i == 4'h5)                    tx_preamble_ok <= 1;                else                    tx_preamble_ok <= 0;                    tx_sfd_ok <= 0;                    tx_byte_aligned_ok <= 0;                    tx_len <= 0;                    tx_len_err <= 0;end// 檢查報(bào)頭                  if ((tx_cnt > 0) && (tx_cnt <= 13))                    begin                      if ((tx_preamble_ok != 1) || (mtxd_i != 4'h5))                      tx_preamble_ok <= 0;                    end  // 檢查 SFD                if (tx_cnt == 14)                    begin                      `ifdef VERBOSE                 if (tx_preamble_ok == 1)                    $fdisplay(phy_log, " (%0t)(%m) TX frame preamble OK!", $time);                  else                    $fdisplay(phy_log, "*E (%0t)(%m) TX frame preamble NOT OK!", $time);                    `endif                  if (mtxd_i == 4'h5)                      tx_sfd_ok <= 1;                  else                      tx_sfd_ok <= 0;                      end                  if (tx_cnt == 15)                    begin                      if ((tx_sfd_ok != 1) || (mtxd_i != 4'hD))                        tx_sfd_ok <= 0;                    end  // 控制存儲(chǔ)地址數(shù)據(jù)、類型/長(zhǎng)度、數(shù)據(jù)內(nèi)容和 FCS 到發(fā)送數(shù)據(jù)緩沖區(qū)                  if (tx_cnt > 15)                    begin                    if (tx_cnt == 16)                      begin                        `ifdef VERBOSE                    if (tx_sfd_ok == 1)                        $fdisplay(phy_log, " (%0t)(%m) TX frame SFD OK!", $time);                      else                          $fdisplay(phy_log, "*E (%0t)(%m) TX frame SFD NOT OK!", $time);                        `endif                          end                    if (tx_cnt[0] == 0)                          begin                            tx_mem_data_in[3:0] <= mtxd_i; // storing LSB nibbletx_byte_aligned_ok<=?0;?//?if?transfer?will?stop?after?this,?then?there?was?driblenibble                          end                      else                  begin                    tx_mem[tx_mem_addr_in[21:0]] <= {mtxd_i, tx_mem_data_in[3:0]}; // storing data into                    tx memory                    tx_len <= tx_len + 1; // enlarge byte length counter                    tx_byte_aligned_ok <= 1; // if transfer will stop after this, then transfer is byte                    alligned                    tx_mem_addr_in <= tx_mem_addr_in + 1'b1;                  end                    if (mtxerr_i)                      tx_len_err <= tx_len;          end      end  end
//為發(fā)送數(shù)據(jù)產(chǎn)生載波信號(hào)                if (!m_rst_n_i)                      begin                          mcrs_tx <= 0;                          mtxen_d1 <= 0;                          mtxen_d2 <= 0;                          mtxen_d3 <= 0;                          mtxen_d4 <= 0;                          mtxen_d5 <= 0;                          mtxen_d6 <= 0;                      end                else                      begin                          mtxen_d1 <= mtxen_i;                          mtxen_d2 <= mtxen_d1;                          mtxen_d3 <= mtxen_d2;                          mtxen_d4 <= mtxen_d3;                          mtxen_d5 <= mtxen_d4;                          mtxen_d6 <= mtxen_d5;                          if (real_carrier_sense)                          mcrs_tx <= mtxen_d6;                else                   mcrs_tx <= mtxen_i;                        end            end
  `ifdef VERBOSE  reg frame_started;
  initial  begin    frame_started = 0;  end
  always@(posedge mtxen_i)  begin    frame_started <= 1;  end
  always@(negedge mtxen_i)  begin    if (frame_started)      begin        $fdisplay(phy_log, " (%0t)(%m) TX frame ended with tx_en reset!", $time);        frame_started <= 0;      end  end
  always@(posedge mrxerr_o)  begin    $fdisplay(phy_log, " (%0t)(%m) RX frame ERROR signal was set!", $time);  end  `endif  ……endmodule

4.3 仿真結(jié)果

如圖 13 所示是對(duì)全雙工方式下傳輸數(shù)據(jù)的測(cè)試,圖中加亮的 MTxD 是以太網(wǎng)控制器的數(shù)據(jù)輸出。

cd69d3d8-04a1-11ed-ba43-dac502259ad0.png

圖 13 全雙工模式下發(fā)送數(shù)據(jù)的測(cè)試結(jié)果

如圖 14 所示的是全雙工模式下接收數(shù)據(jù)的測(cè)試,圖中加亮的 MRxD 是以太網(wǎng)控制器接收數(shù)據(jù)的輸入。

cd761472-04a1-11ed-ba43-dac502259ad0.png

圖 14 全雙工模式下接收數(shù)據(jù)的測(cè)試結(jié)果

如圖 15 所示的是全雙工模式下數(shù)據(jù)發(fā)送和接收整個(gè)過(guò)程的測(cè)試結(jié)果,圖中加亮的 MTxD和 MRxD 是以太網(wǎng)控制器發(fā)送數(shù)據(jù)和接收數(shù)據(jù)的輸出和輸入端口。

cd8f3182-04a1-11ed-ba43-dac502259ad0.png

圖 15 全雙模式下數(shù)據(jù)發(fā)送和接收全過(guò)程的測(cè)試結(jié)果

如圖 16 所示的是半雙工模式下發(fā)送和接收數(shù)據(jù)全過(guò)程的測(cè)試結(jié)果。

cd9d05be-04a1-11ed-ba43-dac502259ad0.png

圖16 半雙工模式下發(fā)送和接收數(shù)據(jù)全過(guò)程的測(cè)試結(jié)果

五、總結(jié)

本篇介紹了一個(gè)以太網(wǎng)控制器(MAC)的實(shí)例。首先介紹了以太網(wǎng)的基本原理,然后介紹了以太網(wǎng)控制器程序的主要結(jié)構(gòu)和主要功能模塊的實(shí)現(xiàn)過(guò)程。最后用一個(gè)測(cè)試程序驗(yàn)證程序的功能是否滿足要求。本章為讀者設(shè)計(jì)自己的以太網(wǎng)控制器提供了一個(gè)有用的方案,并且有助于加深對(duì)以太網(wǎng)協(xié)議的理解。

審核編輯:湯梓紅


聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • FPGA
    +關(guān)注

    關(guān)注

    1625

    文章

    21620

    瀏覽量

    601238
  • 控制器
    +關(guān)注

    關(guān)注

    112

    文章

    16103

    瀏覽量

    177073
  • 以太網(wǎng)
    +關(guān)注

    關(guān)注

    40

    文章

    5343

    瀏覽量

    170801
  • 仿真
    +關(guān)注

    關(guān)注

    50

    文章

    4023

    瀏覽量

    133336

原文標(biāo)題:系統(tǒng)設(shè)計(jì)精選 | 基于FPGA的以太網(wǎng)控制器(MAC)設(shè)計(jì)(附代碼)

文章出處:【微信號(hào):HXSLH1010101010,微信公眾號(hào):FPGA技術(shù)江湖】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    基于嵌入式系統(tǒng)的以太網(wǎng)控制器設(shè)計(jì)

    本文主要基于S3C44B0X+uClinux 系統(tǒng)平臺(tái)開(kāi)發(fā)出嵌入式以太網(wǎng)控制器,該方案和其它設(shè)計(jì)比較具有高性能、低功耗、軟硬件易擴(kuò)展特點(diǎn),是當(dāng)前及今后工業(yè)以太網(wǎng)控制器的理想選擇方案。
    發(fā)表于 10-19 15:58 ?2339次閱讀
    基于嵌入式系統(tǒng)的<b class='flag-5'>以太網(wǎng)</b><b class='flag-5'>控制器</b>設(shè)計(jì)

    基于Xilinx FPGA的千兆以太網(wǎng)控制器的開(kāi)發(fā)

    千兆以太網(wǎng)利用了原以太網(wǎng)標(biāo)準(zhǔn)所規(guī)定的全部技術(shù)規(guī)范,其中包括CSMA/CD協(xié)議、以太網(wǎng)幀、全雙工、流量控制以及IEEE 802.3標(biāo)準(zhǔn)中所定義的管理對(duì)象。##
    發(fā)表于 01-23 11:13 ?3w次閱讀
    基于Xilinx FPGA的千兆<b class='flag-5'>以太網(wǎng)</b><b class='flag-5'>控制器</b>的開(kāi)發(fā)

    以太網(wǎng)控制器(MAC)的基本框架怎么搭建

    產(chǎn)生和檢查。? 報(bào)頭的產(chǎn)生和去除。? 發(fā)送和接收數(shù)據(jù)包的完全狀態(tài)控制。? 滿足 IEEE 802.3 規(guī)定的 MII(媒體無(wú)關(guān)接口)。針對(duì)以太網(wǎng)控制器需要完成的任務(wù),本節(jié)將設(shè)計(jì)以太網(wǎng)
    發(fā)表于 12-28 17:30

    以太網(wǎng)控制器程序仿真測(cè)試頂層程序代碼示范

    頂層程序負(fù)責(zé)連接仿真程序的各個(gè)部分:模擬 PHY 程序、模擬主機(jī)程序以太網(wǎng)
    發(fā)表于 01-15 10:17

    以太網(wǎng)控制器仿真結(jié)果顯示

    如圖 10-13 所示是對(duì)全雙工方式下傳輸數(shù)據(jù)的測(cè)試,圖中加亮的 MTxD 是以太網(wǎng)控制器的數(shù)據(jù)輸出。如圖 10-14 所示的是全雙工模式下接收數(shù)據(jù)的測(cè)試,圖中加亮的 MRxD 是
    發(fā)表于 01-25 14:22

    以太網(wǎng)控制器如何工作

    我正在開(kāi)一個(gè)新帖子,因?yàn)槲艺J(rèn)為舊的已經(jīng)完成了工作,并且指出了以太網(wǎng)控制器的方向。我熟悉UART通信,并在幾個(gè)pic微控制器上實(shí)現(xiàn)它。我有幾個(gè)關(guān)于以太網(wǎng)
    發(fā)表于 04-30 10:39

    請(qǐng)問(wèn)怎樣去設(shè)計(jì)一種以太網(wǎng)控制器芯片?

    怎樣去設(shè)計(jì)一種以太網(wǎng)控制器芯片?如何對(duì)以太網(wǎng)控制器芯片進(jìn)行測(cè)試驗(yàn)證?
    發(fā)表于 05-25 06:41

    基于以太網(wǎng)的指紋門(mén)禁控制器設(shè)計(jì)與實(shí)現(xiàn)

    設(shè)計(jì)了基于以太網(wǎng)和指紋識(shí)別的智能網(wǎng)絡(luò)型門(mén)禁控制器。在ARM9 和Linux 操作系統(tǒng)(S3C2410)上采用FPS200 指紋傳感實(shí)現(xiàn)指紋圖像的采集,以及采用以太網(wǎng)
    發(fā)表于 12-19 16:35 ?41次下載

    以太網(wǎng)智能家居控制器的設(shè)計(jì)

    本文依據(jù)智能家居發(fā)展現(xiàn)狀,提出了一種基于8位單片機(jī)的以太網(wǎng)智能家居控制器的設(shè)計(jì)方案。該方案集本地紅外控制和以精簡(jiǎn)TCP/IP協(xié)議為核心的以太網(wǎng)遠(yuǎn)程
    發(fā)表于 02-24 15:10 ?18次下載

    以太網(wǎng)控制器芯片的設(shè)計(jì)及實(shí)現(xiàn)

    以太網(wǎng)控制器芯片的設(shè)計(jì)及實(shí)現(xiàn) 網(wǎng)絡(luò)控制器芯片的功能與設(shè)計(jì)實(shí)現(xiàn)IEEE 802.3協(xié)議是針對(duì)以太網(wǎng)CSMA/CD標(biāo)準(zhǔn)的傳輸介質(zhì)物理層(PHY)和介質(zhì)訪問(wèn)
    發(fā)表于 07-26 22:34 ?1488次閱讀
    <b class='flag-5'>以太網(wǎng)</b><b class='flag-5'>控制器</b>芯片的設(shè)計(jì)及實(shí)現(xiàn)

    以太網(wǎng)接口的數(shù)據(jù)采集控制器

    以太網(wǎng)接口的數(shù)據(jù)采集控制器 LabJack UE9--以太網(wǎng)接口的數(shù)據(jù)采集控制器。LabJack UE9 具有 USB ( 2.0 全速)和以太網(wǎng)
    發(fā)表于 09-09 08:24 ?892次閱讀

    萬(wàn)兆以太網(wǎng)MAC層控制器設(shè)計(jì)

    根據(jù)IEEE 802.3 和802.3 ae 協(xié)議, 設(shè)計(jì)實(shí)現(xiàn)了萬(wàn)兆以太網(wǎng)MAC 層控制器. 文中使用交叉流水CRC 和異步雙口RAM技術(shù), 解決了非固定數(shù)據(jù)寬度CRC 編碼校驗(yàn), 以及與千兆以太網(wǎng)兼容兩個(gè)關(guān)鍵問(wèn)題. 本文
    發(fā)表于 05-13 18:57 ?59次下載
    萬(wàn)兆<b class='flag-5'>以太網(wǎng)</b>MAC層<b class='flag-5'>控制器</b>設(shè)計(jì)

    以太網(wǎng)控制器_以太網(wǎng)控制器2012完整版

    網(wǎng)控制器萬(wàn)能驅(qū)動(dòng)是一款針對(duì)以太網(wǎng)控制器的驅(qū)動(dòng)大全,支持國(guó)內(nèi)主流的以太網(wǎng)設(shè)備,完全免費(fèi)哦 以太網(wǎng)
    發(fā)表于 09-21 14:39 ?0次下載
    <b class='flag-5'>以太網(wǎng)</b><b class='flag-5'>控制器</b>_<b class='flag-5'>以太網(wǎng)</b><b class='flag-5'>控制器</b>2012完整版

    Microchip以太網(wǎng)開(kāi)關(guān)和EtherCAT工業(yè)控制器及MAC PHY控制設(shè)計(jì)解決方案

    Microchip提供了旨在支持新一代以太網(wǎng)開(kāi)關(guān)、EtherCAT工業(yè)控制器和10/100工業(yè)以太網(wǎng)MAC/PHY控制器的設(shè)計(jì)解決方案。以太網(wǎng)
    發(fā)表于 06-15 17:26 ?36次下載
    Microchip<b class='flag-5'>以太網(wǎng)</b>開(kāi)關(guān)和EtherCAT工業(yè)<b class='flag-5'>控制器</b>及MAC PHY<b class='flag-5'>控制</b>設(shè)計(jì)解決方案

    利用TSN以太網(wǎng)特性改善工業(yè)以太網(wǎng)控制器的時(shí)序

    電子發(fā)燒友網(wǎng)站提供《利用TSN以太網(wǎng)特性改善工業(yè)以太網(wǎng)控制器的時(shí)序.pdf》資料免費(fèi)下載
    發(fā)表于 08-30 10:53 ?0次下載
    利用TSN<b class='flag-5'>以太網(wǎng)</b>特性改善工業(yè)<b class='flag-5'>以太網(wǎng)</b><b class='flag-5'>控制器</b>的時(shí)序