📄 tb_env.sv
字号:
// // -------------------------------------------------------------// Copyright 2004-2008 Synopsys, Inc.// All Rights Reserved Worldwide// // Licensed under the Apache License, Version 2.0 (the// "License"); you may not use this file except in// compliance with the License. You may obtain a copy of// the License at// // http://www.apache.org/licenses/LICENSE-2.0// // Unless required by applicable law or agreed to in// writing, software distributed under the License is// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR// CONDITIONS OF ANY KIND, either express or implied. See// the License for the specific language governing// permissions and limitations under the License.// -------------------------------------------------------------// `include "wishbone.sv"`include "mii.sv"class test_cfg; rand integer unsigned tx_rx_clk_offset; rand eth_mac_cfg mac; rand bit [47:0] dut_addr; rand mii_cfg mii; rand wb_slave_cfg wb; rand bit [ 7:0] rx_bd_offset; rand bit [ 7:0] n_tx_bd; rand bit [ 7:0] n_rx_bd; rand bit [31:0] txrx_bfr_base; bit [31:0] txrx_pnt[*]; rand bit [15:0] max_frame_len; rand bit huge_enable; // Stop when both limits are reached rand integer unsigned run_for_n_tx_frames; rand integer unsigned run_for_n_rx_frames; constraint test_cfg_valid { tx_rx_clk_offset < 100; mac.rate inside {10, 100}; mii.is_10Mb == (mac.rate == 10); mii.full_duplex == mac.full_duplex; dut_addr[47:46] == 2'b00; wb.port_size == wb_cfg::DWORD; wb.granularity == wb_cfg::BYTE; wb.cycles == wb_cfg::CLASSIC; rx_bd_offset inside {[8'h01:8'h7F]}; // At least one TX BD and one Rx BD n_tx_bd > 0 && n_tx_bd < rx_bd_offset+1; n_rx_bd > 0 && n_rx_bd <= 'h80 - rx_bd_offset; txrx_bfr_base < 32'hFFFF_FFFF - 256 * ((huge_enable) ? 65536 : max_frame_len); txrx_bfr_base[2:0] == 3'b000; } // Example 6-10 constraint coverage_driven { max_frame_len inside {1500, 1518, 'h0600}; } constraint reasonable { run_for_n_tx_frames < 100; run_for_n_rx_frames < 100; } function new(); this.mac = new; this.mii = new; this.wb = new; endfunction: new function string psdisplay(string prefix = ""); $sformat(psdisplay, "%sDUT MAC Addr: %h.%h.%h.%h.%h.%h", prefix, dut_addr[47:40], dut_addr[39:32], dut_addr[31:24], dut_addr[23:16], dut_addr[15:8], dut_addr[7:0]); $sformat(psdisplay, "%s\n%s", psdisplay, this.mac.psdisplay(prefix)); $sformat(psdisplay, "%s\n%sTx/Rx Clock offset: %0d", psdisplay, prefix, this.tx_rx_clk_offset); $sformat(psdisplay, "%s\n%s", psdisplay, this.wb.psdisplay(prefix)); $sformat(psdisplay, "%s\n%s%0d TxBD, #%0d RxBD based at 'h%h", psdisplay, prefix, this.n_tx_bd, this.n_rx_bd, this.txrx_bfr_base); $sformat(psdisplay, "%s\n%s%0d bytes max frame length", psdisplay, prefix, (this.huge_enable) ? 65536 : this.max_frame_len); $sformat(psdisplay, "%s\n%sfor %0d Tx + %0d Rx frames", psdisplay, prefix, this.run_for_n_tx_frames, this.run_for_n_rx_frames); endfunctionendclass: test_cfg// Example 4-63//// Example of adding supplemental information to// transaction descriptor received by a transactor//class annotated_eth_frame extends eth_frame; string direction = "Unknown"; virtual function vmm_data allocate(); annotated_eth_frame fr = new; allocate = fr; endfunction: allocate virtual function vmm_data copy(vmm_data to = null); annotated_eth_frame cpy; if (to == null) cpy = new; else if (!$cast(cpy, to)) begin //`vmm_fatal(to.log, "Unable to copy into non-annotated_eth_frame instance"); $display("Error:Unable to copy into non-annotated_eth_frame instance"); return null; end super.copy(cpy); cpy.direction = this.direction; copy = cpy; endfunction: copy virtual function string psdisplay(string prefix = ""); psdisplay = super.psdisplay({prefix, this.direction, ": "}); endfunction: psdisplayendclass: annotated_eth_frame// Example 5-45//// Self-Checking Structure//class scoreboard; test_cfg cfg; vmm_log log; eth_frame to_mac_side[$]; eth_frame to_phy_side[$]; // Example 5-56 bit rx_err; local bit is_tx; local int frame_len; // Example 6-6 covergroup frame_coverage; direction: coverpoint is_tx { bins Tx = {1}; bins Rx = {0}; // Example 6-7 option.weight = 0; } hugen : coverpoint cfg.huge_enable { option.weight = 0; } // Example 6-10 max_fl : coverpoint cfg.max_frame_len { bins fl_1500 = {1500}; bins fl_1518 = {1518}; bins fl_0600 = {'h0600}; option.weight = 0; } // Example 6-2 // Example 6-5 frame_len: coverpoint frame_len { bins max_fl_less_4 = {cfg.max_frame_len - 4}; bins max_fl_less_1 = {cfg.max_frame_len - 1}; bins max_fl = {cfg.max_frame_len}; bins max_fl_plus_1 = {cfg.max_frame_len + 1}; bins max_fl_plus_4 = {cfg.max_frame_len + 4}; bins max_size = {65535}; option.weight = 0; } // Example 6-3 cross direction, hugen, max_fl, frame_len { // Example 6-9 option.comment = "Coverage for Example 2-5"; } // Example 6-8 option.weight = 2 * 3 * 6; endgroup // Example 5-46 function new(test_cfg cfg); this.cfg = cfg; this.log = new("Scoreboard", ""); this.rx_err = 0; frame_coverage = new; endfunction: new // Example 5-48 function void sent_from_mac_side(eth_frame fr); // Example 6-4 this.is_tx = 1; this.frame_len = fr.byte_size(); this.frame_coverage.sample(); // Is it too long? if (!this.cfg.huge_enable && fr.byte_size() > this.cfg.max_frame_len) return; // Will it be accepted by the PHY-side MAC layer? if (fr.fcs) return;// Not if it has a bad FCS if (!this.cfg.mac.promiscuous && fr.dst !== this.cfg.mac.addr && !fr.dst[47]) return; // Not if wrong unicast address to_phy_side.push_back(fr); endfunction function void sent_from_phy_side(eth_frame fr); // Example 6-4 this.is_tx = 0; this.frame_len = fr.byte_size(); this.frame_coverage.sample(); // Is it too long? if (!this.cfg.huge_enable && fr.byte_size() > this.cfg.max_frame_len) return; // Will it be accepted by the MAC-side MAC layer? if (fr.fcs) return;// Not if it has a bad FCS if (!this.cfg.mac.promiscuous && fr.dst !== this.cfg.dut_addr) return; // Not if wrong unicast address to_mac_side.push_back(fr); endfunction // Example 5-48 function void received_by_mac_side(eth_frame fr); eth_frame exp; string diff; if (this.cfg.run_for_n_rx_frames > 0) begin this.cfg.run_for_n_rx_frames--; end if (this.to_mac_side.size() == 0) begin `vmm_error(this.log, $psprintf("Unexpected frame received on MAC side (none expected):\n%s", fr.psdisplay(" "))); return; end exp = this.to_mac_side.pop_front(); if (!fr.compare(exp, diff)) begin `vmm_error(this.log, $psprintf("Unexpected frame received on MAC side: %s:\n%s\n%s", diff, fr.psdisplay(" Actual: "), exp.psdisplay(" Expect: "))); return; end `vmm_note(this.log, $psprintf("Expected frame received on MAC side (%0d left):\n%s", this.cfg.run_for_n_rx_frames, fr.psdisplay(" "))); endfunction function void received_by_phy_side(eth_frame fr); eth_frame exp; string diff; if (this.cfg.run_for_n_tx_frames > 0) begin this.cfg.run_for_n_tx_frames--; end if (this.to_phy_side.size() == 0) begin `vmm_error(this.log, $psprintf("Unexpected frame received on PHY side (none expected):\n%s", fr.psdisplay(" "))); return; end exp = this.to_phy_side.pop_front(); if (!fr.compare(exp, diff)) begin `vmm_error(this.log, $psprintf("Unexpected frame received on PHY side: %s:\n%s\n%s", diff, fr.psdisplay(" Actual: "), exp.psdisplay(" Expect: "))); return; end `vmm_note(this.log, $psprintf("Expected frame received on PHY side (%0d left):\n%s", this.cfg.run_for_n_tx_frames, fr.psdisplay(" "))); endfunctionendclass: scoreboard// Example 5-53class sb_mac_cbs extends eth_mac_callbacks; scoreboard sb; function new(scoreboard sb); this.sb = sb; endfunction virtual task post_frame_tx(eth_mac xactor, eth_frame frame, eth_frame_tx_status status); if (status.successful && !this.sb.rx_err) begin this.sb.sent_from_phy_side(frame); end else begin this.sb.cfg.run_for_n_rx_frames--; end this.sb.rx_err = 0; endtaskendclasstypedef class sw_emulator;virtual class sw_emulator_callbacks extends vmm_xactor_callbacks; virtual task pre_frame_tx(sw_emulator xactor, ref eth_frame frame, ref bit drop); endtask virtual function void post_frame_rx(sw_emulator xactor, /*const*/ eth_frame frame); endfunctionendclass: sw_emulator_callbacksclass sw_emulator extends vmm_xactor; eth_frame_channel tx_chan; scoreboard sb; local test_cfg cfg; local wb_master host; local wb_ram ram; local bit [31:0] avail_txbd[$]; local bit [31:0] busy_txbd[$]; bit [31:0] next_rxbd; local event avail_txbd_e; function new(string instance, int unsigned stream_id = -1, test_cfg cfg, scoreboard sb, wb_master host, wb_ram ram); super.new("SW Emulator", instance, stream_id); tx_chan = new("SW Emulator Tx Channel", instance); this.sb = sb; this.cfg = cfg; this.host = host; this.ram = ram; this.reset_xactor(); endfunction: new function void reset_xactor(reset_e typ = SOFT_RST ); super.reset_xactor(typ); tx_chan.flush(); this.host.reset_xactor(typ); begin bit [31:0] bd_addr = 32'h0000_0400; repeat (this.cfg.n_tx_bd) begin this.avail_txbd.push_back(bd_addr); bd_addr += 8; end // Push a "wrap" flag this.avail_txbd.push_back(32'hFFFF_FFFF); -> this.avail_txbd_e; end this.busy_txbd.delete(); endfunction: reset_xactor virtual task main(); fork super.main(); this.tx_driver(); this.int_serv(); join endtask: main local task tx_driver(); logic [ 7:0] bytes[]; while (1) begin eth_frame fr; bit drop = 0; bit ok; // Wait for a free Tx buffer if none available while (this.avail_txbd.size() == 0) @(this.avail_txbd_e);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -