ぱたへね

はてなダイアリーはrustの色分けができないのでこっちに来た

EthmacにBFMを接続する。

簡単に作るVerilogテストベンチの続きです。Opencores で公開されているEthmacに、WishboneのBFMを接続してみました。標準でついてくるWishboneのBFMがVHDLだったので、必要な機能だけVerilogで書き直しました。

Verilogport

Wishbone付属のBFMをVerilogに移植した物をgithubにあげてあります。
https://github.com/natsutan/wishbone_BFM_verilog_port

サポートしているAPIは、以下の6つです。

  • clock_wait 指定したクロック分だけwaitする。
  • wb_init wishboneバスの初期化を行う。
  • wb_rst 指定したクロック分、wishbone busをリセット状態にする。
  • rd_32 32bitシングルリード
  • wr_32 32bitシングルライト
  • rmw_32 32bitリードモディファイライト

レジスタR/W

簡単に作るVerilogテストベンチの同じレジスタをR/Wしました。
wishboneのアドレス線をずらしてつなぐことで、tb_eth_defines.v で定義されているレジスタ名を、BFMのAPIにそのまま使用しています。これで、対象のレジスタに対して、リードライトできました。

  initial begin
    #1 CLK_stop = 0;
    reset_int = 0;
    wb_init();    
    wb_rst(2);    
    clock_wait(2); //  Wait 20 ns for global reset to finish

    wr_32(`ETH_MAC_ADDR0,32'h12345678);
    clock_wait(1);
    rd_32(`ETH_MAC_ADDR0, read_data);
    $display("RD 0 %08X", read_data);
    clock_wait(10);
    
    # 100 CLK_stop = 1;
    # 100 $finish();
  end

topレベル

// OpenCoresで公開されているEthermac用のテストベンチ
// 
// Eathermacプロジェクト  
// http://opencores.org/project,ethmac


// timescaleの設定
//`timescale 1ns/1ps

//`include "wb_model_defines.v"
`include "ethmac_defines.v"
`include "timescale.v"

module ethermac_tb ();

   //DUTの入力に接続する信号
   wire           wb_clk_i;     // WISHBONE clock
   wire           wb_rst_i;     // WISHBONE reset
   wire [31:0]    wb_dat_i;     // WISHBONE data input
   wire [31:0]   wb_dat_o;     // WISHBONE data output
   wire          wb_err_o;     // WISHBONE error output
   
   // WISHBONE slave
   wire [31:0]    wb_adr_i;     // WISHBONE address reg
   wire [3:0] 	   wb_sel_i;     // WISHBONE byte select input
   wire           wb_we_i;      // WISHBONE write enable input
   wire           wb_cyc_i;     // WISHBONE cycle input
   wire           wb_stb_i;     // WISHBONE strobe input
   wire          wb_ack_o;     // WISHBONE acknowledge output
   
   // WISHBONE master
   wire [31:0]   m_wb_adr_o;
   wire [3:0]    m_wb_sel_o;
   wire          m_wb_we_o;
   reg [31:0]    m_wb_dat_i;
   wire [31:0]   m_wb_dat_o;
   wire          m_wb_cyc_o;
   wire          m_wb_stb_o;
   reg           m_wb_ack_i;
   reg           m_wb_err_i;

   wire [2:0]  m_wb_cti_o;   // Cycle Type Identifier
   wire [1:0]  m_wb_bte_o;   // Burst Type Extension
   
   // Tx
   reg 	 mtx_clk_pad_i; // Transmit clock (from PHY)
   wire [3:0]  mtxd_pad_o;    // Transmit nibble (to PHY)
   wire 	 mtxen_pad_o;   // Transmit enable (to PHY)
   wire 	 mtxerr_pad_o;  // Transmit error (to PHY)
   
   // Rx
   reg 	 mrx_clk_pad_i; // Receive clock (from PHY)
   reg [3:0] 	 mrxd_pad_i;    // Receive nibble (from PHY)
   reg 	 mrxdv_pad_i;   // Receive data valid (from PHY)
   reg 	 mrxerr_pad_i;  // Receive data error (from PHY)
   
   // Common Tx and Rx
   reg 	 mcoll_pad_i;   // Collision (from PHY)
   reg 	 mcrs_pad_i;    // Carrier sense (from PHY)
   
   // MII Management interface
   reg 	 md_pad_i;      // MII data input (from I/O cell)
   wire 	 mdc_pad_o;     // MII Management data clock (to PHY)
   wire 	 md_pad_o;      // MII data output (to I/O cell)
   wire 	 md_padoe_o;    // MII data output enable (to I/O cell)
  
   wire 	 int_o;         // Interrupt output


   wire  [4:0] wbm_tag;
   assign wbm_tag = 0;

  // CLKの周期
  parameter WB_PERIOD = 10.0; 
  parameter TX_PERIOD =  8.0;
  parameter RX_PERIOD =  8.0;

  
  //DUT
  ethmac u0
    (
     .wb_clk_i(wb_clk_i), .wb_rst_i(wb_rst_i), .wb_dat_i(wb_dat_i), .wb_dat_o(wb_dat_o), 
     .wb_adr_i(wb_adr_i[11:2]), .wb_sel_i(wb_sel_i), .wb_we_i(wb_we_i), .wb_cyc_i(wb_cyc_i), 
     .wb_stb_i(wb_stb_i), .wb_ack_o(wb_ack_o), .wb_err_o(wb_err_o), 
     .m_wb_adr_o(m_wb_adr_o), .m_wb_sel_o(m_wb_sel_o), .m_wb_we_o(m_wb_we_o), 
     .m_wb_dat_o(m_wb_dat_o), .m_wb_dat_i(m_wb_dat_i), .m_wb_cyc_o(m_wb_cyc_o), 
     .m_wb_stb_o(m_wb_stb_o), .m_wb_ack_i(m_wb_ack_i), .m_wb_err_i(m_wb_err_i), 
     .m_wb_cti_o(m_wb_cti_o), .m_wb_bte_o(m_wb_bte_o),

     .mtx_clk_pad_i(mtx_clk_pad_i), .mtxd_pad_o(mtxd_pad_o), .mtxen_pad_o(mtxen_pad_o), .mtxerr_pad_o(mtxerr_pad_o),
     .mrx_clk_pad_i(mrx_clk_pad_i), .mrxd_pad_i(mrxd_pad_i), .mrxdv_pad_i(mrxdv_pad_i), .mrxerr_pad_i(mrxerr_pad_i), .mcoll_pad_i(mcoll_pad_i), .mcrs_pad_i(mcrs_pad_i),      
     .mdc_pad_o(mdc_pad_o), .md_pad_i(md_pad_i), .md_pad_o(md_pad_o), .md_padoe_o(md_padoe_o),
     
     .int_o(int_o)
     );

  syscon #(.clk_period(WB_PERIOD)) sc 
    (
     .RST_sys(RST_sys),
     .CLK_stop(CLK_stop),
     .RST_o(wb_rst_i),
     .CLK_o(wb_clk_i)
     );
  
  mb_master_bfm0 #(.clk_period(WB_PERIOD)) master 
    (
     .RST_sys(RST_sys),
     .CLK_stop(CLK_stop),
     
     .RST_I(wb_rst_i),
     .CLK_I(wb_clk_i),
     
     .ADR_O(wb_adr_i),
     .DAT_I(wb_dat_o),
     .DAT_O(wb_dat_i),
     .WE_O(wb_we_i),
     
     .STB_O(wb_stb_i),
     .CYC_O(wb_cyc_i),
     .ACK_I(wb_stb_o),
     .ERR_I(wb_err_o),
     .RTY_I(),
     
     .LOCK_O(),
     .SEL_O(wb_sel_i),
     
     .CYCLE_IS()
     );

  // clkの生成   
   always # (TX_PERIOD/2) mtx_clk_pad_i = ~mtx_clk_pad_i;
   always # (RX_PERIOD/2) mrx_clk_pad_i = ~mrx_clk_pad_i;

   initial begin
      #1 	
      mtx_clk_pad_i = 1; mrx_clk_pad_i = 0;
      
   end
   
endmodule // ethermac_tb