📄 slave.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.// -------------------------------------------------------------// typedef class wb_slave;virtual class wb_slave_callbacks extends vmm_xactor_callbacks; virtual task pre_cycle(wb_slave xactor, wb_cycle req, ref wb_cycle_resp resp); endtask virtual task pre_response(wb_slave xactor, wb_cycle_resp resp); endtask virtual task post_cycle(wb_slave xactor, /*const*/ wb_cycle_resp resp); endtaskendclass: wb_slave_callbacksclass wb_slave extends vmm_xactor; virtual wb_if.slave sigs; wb_cycle req_factory; wb_cycle_resp randomized_resp; // NULL if req/resp channels are used wb_cycle_channel req_chan; wb_cycle_resp_channel resp_chan; protected wb_slave_cfg cfg; local wb_slave_cfg hard_rst_cfg; local integer data_id; extern function new(string instance, int unsigned stream_id = -1, wb_slave_cfg cfg, virtual wb_if.slave sigs, wb_cycle_channel req_chan = null, wb_cycle_resp_channel resp_chan = null, wb_cycle req_factory = null); extern virtual function void reconfigure(wb_slave_cfg cfg = null); extern virtual function void reset_xactor(reset_e typ = SOFT_RST); extern protected virtual task main(); endclass: wb_slavetypedef class wb_ram;virtual class wb_ram_callbacks extends vmm_xactor_callbacks; virtual task pre_response(wb_ram xactor, wb_cycle req, ref wb_cycle_resp resp); endtaskendclass: wb_ram_callbackstypedef bit unsigned [63:0] wb_ram_addr_typ;class wb_ram extends vmm_xactor; wb_cycle_resp resp_factory; wb_cycle_channel req_chan; wb_cycle_resp_channel resp_chan; local bit [63:0] ram[* /*wb_ram_addr_typ*/]; extern function new(string instance, int unsigned stream_id = -1, wb_cycle_channel req_chan = null, wb_cycle_resp_channel resp_chan = null, wb_cycle_resp resp_factory = null); extern virtual function void reset_xactor(reset_e typ = SOFT_RST); extern protected virtual task main(); extern virtual function bit [63:0] read(bit [63:0] addr); extern virtual function void write(bit [63:0] addr, bit [63:0] data);endclass: wb_ram//// wb_slave//function wb_slave::new(string instance, int unsigned stream_id, wb_slave_cfg cfg, virtual wb_if.slave sigs, wb_cycle_channel req_chan, wb_cycle_resp_channel resp_chan, wb_cycle req_factory); super.new("Wishbone Slave", instance, stream_id); this.cfg = cfg; this.hard_rst_cfg = cfg; this.sigs = sigs; this.req_chan = req_chan; this.resp_chan = resp_chan; this.log.is_above(this.req_chan.log); this.log.is_above(this.resp_chan.log); if (req_factory == null) req_factory = new; this.req_factory = req_factory; this.randomized_resp = new(null, null); this.data_id = 0;endfunction: new function void wb_slave::reconfigure(wb_slave_cfg cfg); this.cfg = cfg;endfunction: reconfigure function void wb_slave::reset_xactor(reset_e typ); super.reset_xactor(typ); this.sigs.rdat <= 64'bz; this.sigs.rtgd <= 16'bz; this.sigs.ack <= 1'bz; this.sigs.rty <= 1'bz; this.sigs.err <= 1'bz; this.req_chan.flush(); this.resp_chan.flush(); if (typ >= HARD_RST) begin this.cfg = this.hard_rst_cfg; end this.data_id = 0;endfunction: reset_xactor task wb_slave::main(); fork super.main(); join_none forever begin wb_cycle req; // // From 3.2.1 & 3.2.2 from Wishbone Spec. // // Watch for the begining of a cycle // handling back-to-back cycles... do begin if (this.sigs.cyc !== 1'b1 || this.sigs.stb !== 1'b1) begin this.sigs.rdat <= 64'bz; this.sigs.rtgd <= 16'bz; this.sigs.ack <= 1'bz; this.sigs.rty <= 1'bz; this.sigs.err <= 1'bz; end @(this.sigs.cyc or this.sigs.stb or this.sigs.adr or this.sigs.sel or this.sigs.we or this.sigs.tga or this.sigs.tgc); end while (this.sigs.cyc !== 1'b1 || this.sigs.stb !== 1'b1); $cast(req, this.req_factory.allocate()); req.stream_id = this.stream_id; req.data_id = this.data_id++; // Decode qualified input from the master req.addr = this.sigs.adr; // Are we the target of the cycle? if (!(this.cfg.min_addr <= req.addr && req.addr <= this.cfg.max_addr)) continue; // Complete the cycle req.tga = this.sigs.tga; if (this.sigs.we) begin req.kind = wb_cycle::WRITE ; req.data = this.sigs.wdat; req.tgd = this.sigs.wtgd; end else begin req.kind = wb_cycle::READ ; end req.sel = this.sigs.sel; req.tgc = this.sigs.tgc; // Wait states may be introduced by // delays in the response this.sigs.ack <= 1'b0; this.sigs.rty <= 1'b0; this.sigs.err <= 1'b0; `vmm_trace(this.log, req.psdisplay("Request: ")); begin integer n_wss = 0; wb_cycle_resp resp; fork forever begin @ (this.sigs.sck); n_wss++; end join_none resp = null; `vmm_callback(wb_slave_callbacks, pre_cycle(this, req, resp)); if (resp == null && this.req_chan != null && this.resp_chan != null) begin this.req_chan.put(req); this.resp_chan.get(resp); end if (resp != null) begin if (resp.req == null) resp.req = req; if (resp.cfg == null) resp.cfg = cfg; if (!resp.randomize()) begin `vmm_fatal(this.log, "Unable to randomize user-defined cycle response"); disable fork; break; end end else begin this.randomized_resp.req = req; this.randomized_resp.cfg = cfg; if (!this.randomized_resp.randomize()) begin `vmm_fatal(this.log, "Unable to randomize factory cycle response"); disable fork; break; end $cast(resp, this.randomized_resp.copy()); end // Does this response correspond to our request? if (resp.req != req) begin if (resp.req.kind != req.kind || resp.req.addr != req.addr) begin `vmm_error(this.log, "Response descriptor does not match request"); break; end end `vmm_callback(wb_slave_callbacks, pre_response(this, resp)); disable fork; `vmm_trace(this.log, resp.psdisplay("Responding: ")); // Maybe we do not respond? if (resp.status == wb_cycle_resp::NO_RESP ) break; // Insert the required number of wait states // less what has already been inserted because // of the response delay if (n_wss > resp.n_wss) begin `vmm_warning(this.log, $psprintf("Number of requested wait state in response (%0d) already exhausted due to delay in responding (%0d)", resp.n_wss, n_wss)); end else begin repeat (resp.n_wss - n_wss) begin @ (this.sigs.sck); end end // Complete the cycle if (req.kind == wb_cycle::READ ) begin this.sigs.rdat <= resp.data; this.sigs.rtgd <= resp.tag; end case (resp.status) wb_cycle_resp::ACK : this.sigs.ack <= 1'b1; wb_cycle_resp::RTY : this.sigs.rty <= 1'b1; wb_cycle_resp::ERR : this.sigs.err <= 1'b1; endcase // Wait for the end of the cycle or back-to-back cycles // Make sure the write data that was latched is the one we sampled if (req.kind == wb_cycle::WRITE ) begin bit [63:0] dat; bit [15:0] tag; @ (this.sigs.sck); dat = this.sigs.sck.wdat; if (dat !== req.data) `vmm_error(this.log, $psprintf("DAT_I not stable during write cycle: %h vs %h", this.sigs.sck.wdat, req.data)); tag = this.sigs.sck.wtgd; if (tag !== req.tgd) `vmm_error(this.log, $psprintf("TGD_I not stable during write cycle: %h vs %h", this.sigs.sck.wtgd, req.tgd)); end `vmm_callback(wb_slave_callbacks, post_cycle(this, resp)); end endendtask: main //// wb_ram//function wb_ram::new(string instance, int unsigned stream_id, wb_cycle_channel req_chan, wb_cycle_resp_channel resp_chan, wb_cycle_resp resp_factory); super.new("Wishbone RAM", instance, stream_id); if (req_chan == null) req_chan = new("Wishbone RAM Request Channel", instance); this.req_chan = req_chan; if (resp_chan == null) resp_chan = new("Wishbone RAM Response Channel", instance); this.resp_chan = resp_chan; if (resp_factory == null) resp_factory = new(null, null); this.resp_factory = resp_factory;endfunction: new function void wb_ram::reset_xactor(reset_e typ); super.reset_xactor(typ);endfunction: reset_xactor task wb_ram::main(); fork super.main(); join forever begin wb_cycle req; wb_cycle_resp resp; this.wait_if_stopped_or_empty(this.req_chan); this.req_chan.get(req); `vmm_trace(this.log, req.psdisplay("Request: ")); $cast(resp, this.resp_factory.copy()); resp.req = req; resp.data.rand_mode(0); resp.status = wb_cycle_resp::ACK ; resp.status.rand_mode(0); // Implement a RAM behavior if (req.kind == wb_cycle::READ ) resp.data = this.read(req.addr); `vmm_callback(wb_ram_callbacks, pre_response(this, req, resp)); if (req.kind == wb_cycle::WRITE ) this.write(req.addr, req.data); `vmm_trace(this.log, resp.psdisplay("Responding: ")); this.resp_chan.put(resp); endendtask: main function bit [63:0] wb_ram::read(bit [63:0] addr); read = (this.ram.exists(addr)) ? this.ram[addr] : 64'bx;endfunction: read function void wb_ram::write(bit [63:0] addr, bit [63:0] data); this.ram[addr] = data;endfunction: write
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -