📄 tb_env.sv
字号:
this.wait_if_stopped_or_empty(this.tx_chan); this.tx_chan.activate(fr); `vmm_callback(sw_emulator_callbacks, pre_frame_tx(this, fr, drop)); if (!drop) begin bit [31:0] bd_addr = this.avail_txbd.pop_front(); bit [31:0] tx_pnt = this.cfg.txrx_pnt[bd_addr]; wb_cycle cyc = new(this.cfg.wb); bit wrap = 0; this.tx_chan.start(); // Write the frame in the RAM // Example 4-27 `vmm_trace(this.log, $psprintf("Buffering TX Frame at 'h%h:\n%s", tx_pnt, fr.psdisplay(" "))); // We need full DWORDs begin int len = fr.byte_size(); bytes = new [len + (4 - len % 4)]; fr.byte_pack(bytes); for (int i = 0; i < len; i += 4) begin this.ram.write(tx_pnt + i, {bytes[i], bytes[i+1], bytes[i+2], bytes[i+3]}); end end // Set the TxBD accordingly if (this.avail_txbd.size() > 0) begin if (this.avail_txbd[0] == 32'hFFFF_FFFF) begin wrap = 1; this.avail_txbd.pop_front(); end end `vmm_debug(this.log, $psprintf("Updating TxBD at 'h%h", bd_addr)); tx_pnt[31:16] = fr.byte_size(); tx_pnt[15: 0] = 16'hD400; tx_pnt[13] = wrap; ok = cyc.randomize() with {kind == wb_cycle::WRITE; addr == bd_addr; data == tx_pnt; sel == 4'hF;}; if (!ok) begin `vmm_fatal(this.log, "Unable to create WRITE cycle to TxBD"); end this.host.exec_chan.put(cyc); if (cyc.status !== wb_cycle::ACK) begin `vmm_error(this.log, "Unable to write to TxBD"); end this.busy_txbd.push_back(bd_addr); if (wrap) this.busy_txbd.push_back(32'hFFFF_FFFF); this.tx_chan.complete(); this.sb.sent_from_mac_side(fr); end this.tx_chan.remove(); end endtask: tx_driver local task int_serv(); wb_cycle cyc = new(this.cfg.wb); bit [31:0] isr; bit [31:0] val; bit ok; bit ignore_fr; // Interrupt service routine while (1) begin wait(tb_top.wb_int === 1'b1); ignore_fr = 0; ok = cyc.randomize() with {kind == wb_cycle::READ; addr == 32'h0000_0004; // INT_SOURCE sel == 4'hF;}; if (!ok) begin `vmm_fatal(this.log, "Unable to create READ cycle to INT_SOURCE"); end this.host.exec_chan.put(cyc); if (cyc.status !== wb_cycle::ACK) begin `vmm_error(this.log, "Unable to read INT_SOURCE"); end // Do an immediate write-back to clear the interrupts // so we won't miss one cyc.kind = wb_cycle::WRITE; this.host.exec_chan.put(cyc); if (cyc.status !== wb_cycle::ACK) begin `vmm_error(this.log, "Unable to write to INT_SOURCE"); end // Analyze the cause(s) for the interrupt isr = cyc.data; if (isr[1]) begin // TXE `vmm_error(this.log, "An error occured during the transmission of a frame"); end if (isr[1] || isr[0]) begin // TXB integer n = 0; `vmm_trace(this.log, "A frame has been transmitted..."); isr[1:0] = 2'b00; if (this.busy_txbd.size() == 0) begin `vmm_error(this.log, "Internal error: No busy TXBD"); end // A frame has been transmitted, check the transmit buffers... while (this.busy_txbd.size() > 0) begin bit [31:0] bd_addr = this.busy_txbd[0]; // Check if that TxBD has been transmitted ok = cyc.randomize() with {kind == wb_cycle::READ; addr == bd_addr; sel == 4'hF;}; if (!ok) begin `vmm_fatal(this.log, "Unable to create READ cycle to TxBD"); end this.host.exec_chan.put(cyc); if (cyc.status !== wb_cycle::ACK) begin `vmm_error(this.log, "Unable to read TxBD"); end // Has this frame been transmitted? if (cyc.data[15]) begin // No. This implies the subsequent frames have not // been transmitted either if (n == 0) `vmm_error(this.log, "No transmitted TxBD were found"); break; end `vmm_trace(this.log, $psprintf("Frame from TxBD @ 'h%h was transmitted", bd_addr)); // What errors happened when the frame was transmitted? if (cyc.data[8] || cyc.data[3] || cyc.data[2]) begin string descr = ""; string separator = " "; if (cyc.data[8]) begin descr = " Under-run"; separator = "/"; end if (cyc.data[3]) begin descr = {descr, separator, "Retry Limit"}; separator = "/"; end if (cyc.data[2]) descr = {descr, separator, "Late Coll"}; `vmm_warning(this.log, {"Frame was transmitted with following errors:", descr}); end // What non-errors happened? `vmm_trace(this.log, $psprintf("Frame was transmitted with %0d attempts%s%s", cyc.data[7:4], (cyc.data[1]) ? ", deferred" : "", (cyc.data[0]) ? ", carrier lost" : "")); // Indicate this TxBD is now available n++; this.avail_txbd.push_back(bd_addr); this.busy_txbd.pop_front(); // Check if the wrap indicator comes next if (this.busy_txbd.size() > 0 && this.busy_txbd[0] == 32'hFFFF_FFFF) begin this.avail_txbd.push_back(32'hFFFF_FFFF); this.busy_txbd.pop_front(); end -> this.avail_txbd_e; end end // TXB if (isr[3]) begin // RXE`ifndef OC_ETHERNET_BUG `vmm_error(this.log, "An error occured during the reception of a frame");`endif end if (isr[3] || isr[2]) begin // RXB integer n = 0; `vmm_trace(this.log, "A frame has been received..."); isr[3:2] = 2'b00; // A frame has been received, check the receive buffers... forever begin bit [31:0] bd_addr = this.next_rxbd; bit [31:0] rx_pnt; bit [15:0] len; logic [7:0] bytes[]; // Check if that RxBD contains a received frame ok = cyc.randomize() with {kind == wb_cycle::READ; addr == bd_addr; sel == 4'hF;}; if (!ok) begin `vmm_fatal(this.log, "Unable to create READ cycle to RxBD"); end this.host.exec_chan.put(cyc); if (cyc.status !== wb_cycle::ACK) begin `vmm_error(this.log, "Unable to read RxBD"); end // Is there a frame in there? if (cyc.data[15]) begin // No. This implies the subsequent buffers are empty as well if (n == 0) `vmm_error(this.log, "No received RxBD were found"); break; end n++; len = cyc.data[31:16]; `vmm_trace(this.log, $psprintf("Frame from RxBD @ 'h%h was received", bd_addr)); // What errors happened when the frame was transmitted? if (cyc.data[6:0]) begin string descr = ""; string separator = " "; if (cyc.data[0]) begin descr = " Late Collision"; separator = "/"; end if (cyc.data[1]) begin descr = {descr, separator, "Bad CRC"}; separator = "/"; end if (cyc.data[2]) begin descr = {descr, separator, "Too Short"}; separator = "/"; end if (cyc.data[3]) begin descr = {descr, separator, "Too Long"}; separator = "/"; end if (cyc.data[4]) begin descr = {descr, separator, "Dribble"}; separator = "/"; end if (cyc.data[5]) begin descr = {descr, separator, "Bad Symbol"};`ifdef OC_ETHERNET_BUG ignore_fr = 1;`endif separator = "/"; end if (cyc.data[6]) begin descr = {descr, separator, "OverRun"}; separator = "/"; end `vmm_warning(this.log, {"Frame was received with following errors:", descr}); end // Indicate this RxBD is now free val = cyc.data; val[15] = 1; ok = cyc.randomize() with {kind == wb_cycle::WRITE; addr == bd_addr; data == val; sel == 4'hF;}; if (!ok) begin `vmm_fatal(this.log, "Unable to create WRITE cycle to RxBD"); end this.host.exec_chan.put(cyc); if (cyc.status !== wb_cycle::ACK) begin `vmm_error(this.log, "Unable to write RxBD"); end // Get the frame from the buffer rx_pnt = this.cfg.txrx_pnt[bd_addr]; // We'll be recovering full DWORDs bytes = new [len + (4 - len % 4)]; for (int i = 0; i < len; i += 4) begin {bytes[i], bytes[i+1], bytes[i+2], bytes[i+3]} = this.ram.read(rx_pnt + i); end begin eth_frame fr = new; fr.byte_unpack(bytes, 0, len-4); // Do not unpack FCS if (val[1]) fr.fcs = 32'hFFFF_FFFF; `vmm_trace(this.log, $psprintf("Retreived RX Frame from 'h%h:\n%s", rx_pnt, fr.psdisplay(" "))); if (!ignore_fr) begin this.sb.received_by_mac_side(fr); end end // Move on to the next RxBD next_rxbd += 8; if (val[13]) next_rxbd = 32'h0000_0400 + this.cfg.rx_bd_offset * 8; end end // RXB if (isr[4]) begin // BUSY`ifndef OC_ETHERNET_BUG `vmm_error(this.log, "Out of Rx buffers!");`endif isr[4] = 0; end if (isr) begin `vmm_error(this.log, $psprintf("Unserviced interrupts: %h", isr)); end end endtask: int_servendclassclass wb_cycle_resp_no_wss extends wb_cycle_resp; function new(wb_cycle req, wb_slave_cfg cfg); super.new(req, cfg); endfunction constraint no_wss { n_wss == 0; } function vmm_data copy(vmm_data to); wb_cycle_resp_no_wss tr; if (to == null) tr = new(null, null); else if (!$cast(tr, to)) begin `vmm_fatal(this.log, "Unable to copy to non-wb_cycle_resp_no_wss instance"); return null; end copy = super.copy(tr); endfunction: copyendclass// Example 5-37class dut_eth_frame extends eth_frame; test_cfg cfg; constraint match_dut_address { if (!cfg.mac.promiscuous) dst == cfg.dut_addr; } constraint valid_src_address { src == cfg.mac.addr; } function new(test_cfg cfg); this.cfg = cfg; endfunction: newendclass: dut_eth_frame// Example 4-13// Example 4-18class tb_env extends vmm_env; test_cfg cfg; // Example 4-20 eth_frame_atomic_gen host_src; eth_frame_atomic_gen phy_src; eth_mac mac; mii_phy_layer phy; mii_monitor mon; wb_master host; wb_slave slv; wb_ram ram; sw_emulator swem; // Example 5-47 scoreboard sb; // Example 4-18 // Example 4-19 function new(); super.new(); this.cfg = new; $timeformat(-9, 0, "ns", 1); endfunction: new virtual function void gen_cfg(); super.gen_cfg();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -