📄 eth_subenv.sv
字号:
endtask: tx_driver task service_irq(); vmm_rw::status_e status; bit [31:0] val; bit ignore_fr; bit TXE, TXB; ignore_fr = 0; this.ral.INT_SOURCE.mirror(status); if (status != vmm_rw::IS_OK) begin `vmm_fatal(this.log, "Unable to read INT_SOURCE"); end // Save the interesting flags because the mirror // will be cleared on write-back TXE = this.ral.TXE.get(); TXB = this.ral.TXB.get(); // Do an immediate write-back to clear the interrupts // so we won't miss one this.ral.INT_SOURCE.write(status, this.ral.INT_SOURCE.get()); if (status != vmm_rw::IS_OK) begin `vmm_fatal(this.log, "Unable to write-back INT_SOURCE"); end // Analyze the cause(s) for the interrupt if (TXE) begin `vmm_error(this.log, "An error occured during the transmission of a frame"); end if (TXE || TXB) begin integer n = 0; if (this.busy_txbd.size() == 0) begin `vmm_fatal(this.log, "Internal error: TXE/TXB indicated but no TxBD are busy"); end // A frame has been transmitted, check the transmit buffers... while (this.busy_txbd.size() > 0) begin int bd_addr = this.busy_txbd[0]; bit RD; // Check if that TxBD has been transmitted ral.TxBD[bd_addr].RD.read(status, RD); if (status != vmm_rw::IS_OK) begin `vmm_fatal(this.log,$psprintf("Unable to READ TxBD[%0d]", bd_addr)); end // Has this frame been transmitted? if (RD) 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[%0d] was transmitted", bd_addr)); // What errors happened when the frame was transmitted? if (ral.TxBD[bd_addr].UR.get() || ral.TxBD[bd_addr].RL.get() || ral.TxBD[bd_addr].LC.get()) begin string descr = ""; string separator = " "; if (ral.TxBD[bd_addr].UR.get()) begin descr = " Under-run"; separator = "/"; end if (ral.TxBD[bd_addr].RL.get()) begin descr = {descr, separator, "Retry Limit"}; separator = "/"; end if (ral.TxBD[bd_addr].LC.get()) begin descr = {descr, separator, "Late Coll"}; end `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", ral.TxBD[bd_addr].RTRY.get(), (ral.TxBD[bd_addr].DF.get()) ? ",ferred" : "", (ral.TxBD[bd_addr].CS.get()) ? ", carrier lost" : "")); // Indicate this TxBD is now available // and free the DMA memory n++; this.cfg.avail_txbd.push_back(bd_addr); this.busy_txbd.pop_front(); this.dma_mam.release_region(this.cfg.dma_bfrs[bd_addr]); end end // TXB endtask: service_irqendclassclass oc_eth_subenv extends vmm_subenv; oc_eth_subenv_cfg cfg; virtual mii_if.passive mii_sigs; eth_frame_channel tx_chan; ral_block_oc_ethernet ral; wb_ram dma_ram; vmm_mam dma_mam; scoreboard sb; eth_frame_atomic_gen src; mii_monitor mon; frmwr_emulator frmwr; function new(string inst, oc_eth_subenv_cfg cfg, vmm_consensus end_test, virtual mii_if.passive mii_sigs, eth_frame_channel tx_chan, ral_block_oc_ethernet ral, wb_ram dma_ram, vmm_mam dma_mam); super.new("OcEth SubEnv", inst, end_test); this.cfg = cfg; this.mii_sigs = mii_sigs; if (tx_chan == null) begin this.src = new("OcEth SubEnv Src", inst); tx_chan = this.src.out_chan; this.src.stop_after_n_insts = this.cfg.run_for_n_frames; // Make sure the frame generators generate frames with the // correct SA this.src.randomized_obj.src = this.cfg.dut_addr; this.src.randomized_obj.src.rand_mode(0); end this.tx_chan = tx_chan; this.ral = ral; this.dma_ram = dma_ram; this.dma_mam = dma_mam; this.sb = new(inst, this.cfg); this.mon = new(inst, 0, this.cfg.mii, this.mii_sigs); this.frmwr = new(inst, 0, this.cfg, tx_chan, this.sb, this.ral, this.dma_ram, this.dma_mam); endfunction: new task configure(); vmm_rw::status_e status; ral.HUGEN.set(0); ral.CRCEN.set(0); ral.FULLD.set(1); ral.PRO.set(1); ral.TXE_M.set(1); ral.TXB_M.set(1); ral.IPGT.set(16'h15); ral.MINFL.set(16'h000F); ral.MAXFL.set(cfg.max_frame_len); ral.TXFLOW.set(1); ral.RXFLOW.set(1); ral.PASSALL.set(1); ral.MAC_ADDR.set(cfg.dut_addr); ral.TX_BD_NUM.set(cfg.n_tx_bd); ral.update(status); if (status !== vmm_rw::IS_OK) begin `vmm_error(this.log, $psprintf("Unable to configure \"%s\".", ral.get_name())); end // Initialize the required number of buffer descriptors begin int bd_addr = 0; `vmm_trace(this.log, $psprintf("Configuring %0d TxBD starting at BD[%0d]", cfg.n_tx_bd, bd_addr)); repeat (cfg.n_tx_bd) begin ral.TxBD[bd_addr].TxBD_CTRL.set(32'h0000_0000); ral.TxBD[bd_addr].IRQ.set(1); if (bd_addr == cfg.n_tx_bd-1) ral.TxBD[bd_addr].WR.set(1'b1); ral.TxBD[bd_addr].RD.write(status, 0); if (status !== vmm_rw::IS_OK) begin `vmm_error(this.log, $psprintf("Unable to initialize (Tx)BD[%0d] in \"%s\".", bd_addr, ral.get_name())); end cfg.avail_txbd.push_back(bd_addr); bd_addr++; end end `vmm_trace(this.log, "Enabling Tx paths..."); ral.TXEN.write(status, 1); if (status !== vmm_rw::IS_OK) begin `vmm_error(this.log, $psprintf("Unable to configure \"%s\".", ral.get_name())); end super.configured(); endtask: configure virtual task start(); super.start(); if (this.cfg.run_for_n_frames > 0 && this.src != null) begin this.src.start_xactor(); end this.frmwr.start_xactor(); this.mon.start_xactor(); fork forever begin eth_frame fr; this.mon.to_phy_chan.get(fr); this.sb.received_by_phy_side(fr); end join_none if (this.src != null) begin this.end_test.register_notification(this.src.notify, eth_frame_atomic_gen::DONE); end this.end_test.register_channel(this.tx_chan); this.end_test.register_channel(this.mon.to_phy_chan); this.end_test.register_xactor(this.frmwr); this.end_test.register_xactor(this.mon); endtask: start virtual task stop(); super.stop(); if (this.src != null) this.src.stop_xactor(); endtask: stop virtual task cleanup(); super.cleanup(); if (this.cfg.run_for_n_frames > 0) begin `vmm_error(this.log, $psprintf("%0d frames were not seen by the scoreboard", this.cfg.run_for_n_frames)); end endtask: cleanupendclass: oc_eth_subenv`endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -