📄 mac.sv
字号:
endendfunction: reset_xactor task eth_mac::main(); fork super.main(); this.tx_driver(); this.rx_monitor(); this.deference(); join_noneendtask: maintask eth_mac::tx_driver(); eth_frame fr; while (1) begin bit drop = 0; eth_frame_tx_status status = new; status.successful = 0; status.n_attempts = 0; this.transmitting = 0; this.wait_if_stopped_or_empty(this.tx_chan); this.tx_chan.activate(fr); `vmm_callback(eth_mac_callbacks, pre_frame_tx(this, fr, drop)); if (drop) begin this.tx_chan.remove(); fr.notify.indicate(vmm_data::ENDED , status); continue; end this.tx_chan.start(); while (status.n_attempts < this.cfg.attempt_limit && !status.successful) begin bit col = 0; `vmm_callback(eth_mac_callbacks, pre_frame_tx_attempt(this, fr, status.n_attempts, drop)); if (drop) break; if (log.start_msg(vmm_log::DEBUG_TYP , vmm_log::TRACE_SEV )) begin string prefix; log.text("Attempting to transmitting frame..."); $sformat(prefix, " Attempt #%0d: ", status.n_attempts); log.text(fr.psdisplay(prefix)); log.end_msg(); end if (status.n_attempts > 0) this.back_off(status.n_attempts); this.defer(); // Watch for collisions if (!this.cfg.full_duplex) begin fork begin this.indications.wait_for(eth_pls_indications::COLLISION); col = 1; `vmm_debug(this.log, "Collision!"); end join_none end // PLS Tx channel has a blocking model this.transmitting = 1; this.pls_tx_chan.put(fr); this.transmitting = 0; disable fork; status.n_attempts++; // If there were no collisions, success! if (!col) begin status.successful = 1; break; end end if (log.start_msg(vmm_log::DEBUG_TYP , vmm_log::TRACE_SEV )) begin string prefix; log.text("Done transmitting frame..."); $sformat(prefix, " %0s: ", (status.successful) ? "Success" : "Failure"); log.text(fr.psdisplay(prefix)); log.end_msg(); end this.tx_chan.complete(); `vmm_callback(eth_mac_callbacks, post_frame_tx(this, fr, status)); fr.notify.indicate(vmm_data::ENDED , status); this.tx_chan.remove(); endendtask: tx_driver task eth_mac::rx_monitor(); eth_frame fr; while (1) begin this.pls_rx_chan.get(fr); `vmm_callback(eth_mac_callbacks, post_frame_rx(this, fr)); if (log.start_msg(vmm_log::DEBUG_TYP , vmm_log::TRACE_SEV )) begin log.text("Received frame..."); log.text(fr.psdisplay(" ")); log.end_msg(); end if (this.cfg.promiscuous || this.cfg.addr === fr.dst || fr.dst[47] === 1'b1) begin this.rx_chan.sneak(fr); end else begin `vmm_debug(this.log, "Frame ignored because of wrong unicast address"); end endendtask: rx_monitor task eth_mac::back_off(int unsigned n_attempts); int unsigned n; if (n_attempts == 1) this.maxBackOff = 2; else if (n_attempts < this.cfg.backoff_limit) this.maxBackOff *= 2; n = $random() % this.maxBackOff; `vmm_debug(this.log, $psprintf("Backing off for %0d slotTimes...", n)); #(this.cfg.slot_time * n);endtask: back_offtask eth_mac::deference(); forever begin this.deferring = 0; `vmm_debug(this.log, "Deference: not active"); if (this.cfg.full_duplex) begin wait (this.transmitting === 1'b1); this.deferring = 1; wait (this.transmitting === 1'b0); #(this.cfg.ifg); end else begin bit wasTransmitting; `vmm_debug(this.log, "Deference: Waiting for CRS"); this.indications.wait_for(eth_pls_indications::CARRIER); wasTransmitting = this.transmitting; this.deferring = 1; `vmm_debug(this.log, "Deference: ACTIVE. Waiting for ~CRS"); this.indications.wait_for_off(eth_pls_indications::CARRIER); wait (this.transmitting === 1'b0); `vmm_debug(this.log, "Deference: IFG"); if (wasTransmitting) begin #(this.cfg.ifg_part1); end else begin: interFrameSpacingPart1 forever begin fork begin #(this.cfg.ifg_part1); disable interFrameSpacingPart1; end join_none this.indications.wait_for(eth_pls_indications::CARRIER); disable fork; this.indications.wait_for_off(eth_pls_indications::CARRIER); end end #(this.cfg.ifg - this.cfg.ifg_part1); end endendtask: deferencetask eth_mac::defer(); `vmm_debug(this.log, "Deferring..."); wait(this.deferring === 1'b0); `vmm_debug(this.log, "Deferred.");endtask: defer // // eth_mac_monitor // function void eth_mac_monitor::reconfigure(eth_mac_cfg cfg); this.cfg = cfg;endfunction: reconfigure function void eth_mac_monitor::reset_xactor(reset_e typ); super.reset_xactor(typ); this.to_phy_chan.flush(); this.to_mac_chan.flush(); this.pls_to_phy_chan.flush(); this.pls_to_mac_chan.flush(); this.indications.reset(); if (typ >= FIRM_RST) begin this.indications.reset(, vmm_notify::HARD ); end if (typ >= HARD_RST) begin this.cfg = this.hard_rst_cfg; endendfunction: reset_xactor task eth_mac_monitor::main(); fork super.main(); this.to_phy_monitor(); this.to_mac_monitor(); join_noneendtask: maintask eth_mac_monitor::to_phy_monitor(); eth_frame fr; while (1) begin this.pls_to_phy_chan.get(fr); `vmm_callback(eth_mac_monitor_callbacks, post_frame_rx(this, eth_mac_monitor_callbacks::TO_PHY, fr)); this.to_phy_chan.sneak(fr); endendtask: to_phy_monitor task eth_mac_monitor::to_mac_monitor(); eth_frame fr; while (1) begin this.pls_to_mac_chan.get(fr); `vmm_callback(eth_mac_monitor_callbacks, post_frame_rx(this, eth_mac_monitor_callbacks::TO_MAC, fr)); this.to_mac_chan.sneak(fr); endendtask: to_mac_monitor
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -