This file defines the following VMM consumer components.
VMM Producers | |
This file defines the following VMM consumer components. | |
vmm_producer_1chan | A VMM producer using a single request channel to put transactions and expects responses to be annotated in the original request. |
vmm_producer_2chan | A VMM producer using request and response channels. |
vmm_notifier | VMM Producer that conveys transactions as status in a notify indication. |
A VMM producer using a single request channel to put transactions and expects responses to be annotated in the original request. It randomly chooses one of three completion models.
class vmm_producer_1chan extends `VMM_XACTOR; vmm_channel_typed #(vmm_apb_rw) out_chan; function new(string inst, int unsigned stream_id=-1, vmm_channel_typed #(vmm_apb_rw) out_chan=null `VMM_XACTOR_NEW_ARGS); super.new("vmm_producer_1ch", inst, stream_id `VMM_XACTOR_NEW_CALL); if (out_chan == null) out_chan = new("APB Channel","out_chan"); this.out_chan = out_chan; endfunction: new virtual protected task main(); vmm_apb_rw wr_req = new(); super.main(); for(int i = 0; i < 10; i++) begin vmm_apb_rw tr; // WRITE assert(wr_req.randomize() with {wr_req.kind == vmm_apb_rw::WRITE;}); // assume blocks until tr is processed by consumer (atomic mode) `vmm_note(log,{"via ATOMIC MODE - ",wr_req.psdisplay()}); this.out_chan.put(wr_req); // READ to verify tr = new; tr.addr = wr_req.addr; tr.kind = vmm_apb_rw::READ; tr.data = 'x; randcase // atomic (blocks on put) 1: begin vmm_apb_rw local_wr = new wr_req; this.out_chan.put(tr); assert(tr.data == local_wr.data); `vmm_note(log,{"via ATOMIC MODE - ",tr.psdisplay(),"\n"}); end // blocking (blocks on vmm_data::ENDED) 1: begin vmm_apb_rw local_wr = new wr_req; this.out_chan.sneak(tr); tr.notify.wait_for(vmm_data::ENDED); assert(tr.data == local_wr.data); `vmm_note(log,{"via BLOCKING MODE - ",tr.psdisplay(),"\n"}); end // nonblocking (separate process waits for vmm_data::ENDED) 1: begin vmm_apb_rw local_wr = new wr_req; this.out_chan.sneak(tr); fork begin tr.notify.wait_for(vmm_data::ENDED); assert(tr.data == local_wr.data); `vmm_note(log,{"via NON-BLOCKING MODE - ",tr.psdisplay(),"\n"}); end join_none end endcase end // for (int i = 0; i < 10; i++) wait fork; //PH> Weihua's this.notify.indicate(XACTOR_STOPPED); endtask endclass
A VMM producer using request and response channels. It randomly chooses one of two completion models.
class vmm_producer_2chan extends vmm_xactor; vmm_channel_typed #(vmm_apb_rw) out_chan, in_chan; function new(string inst, int unsigned stream_id=-1, vmm_channel_typed #(vmm_apb_rw) out_chan=null, vmm_channel_typed #(vmm_apb_rw) in_chan=null `VMM_XACTOR_NEW_ARGS); super.new("vmm__producer_2chan", inst, stream_id `VMM_XACTOR_NEW_CALL); if (out_chan == null) out_chan = new("vmm_channel #(vmm_apb_rw)","out_chan",10); this.out_chan = out_chan; if (in_chan == null) in_chan = new("vmm_channel #(vmm_apb_rw)","in_chan",10); this.in_chan = in_chan; endfunction virtual protected task main(); vmm_apb_rw wr_req = new(); vmm_apb_rw rd_req = new(); vmm_apb_rw rr = new(); int unsigned addrs[$]; integer unsigned m[int]; vmm_apb_rw reqs[$]; string s; super.main(); for(int i = 0; i < 10; i++) begin wr_req.data_id = i; wr_req.scenario_id = 1; assert(wr_req.randomize() with {wr_req.kind == vmm_apb_rw::WRITE;}); `vmm_note(log,$psprintf("VMM Producer: Addr = %h, Data = %h, Kind = %s", wr_req.addr, wr_req.data, wr_req.kind)); addrs.push_back(wr_req.addr); m[wr_req.addr] = wr_req.data; // for results checking randcase // blocking request/response 1: begin this.out_chan.put(wr_req); this.in_chan.get(rr); end // nonblocking request/response 1: begin this.out_chan.sneak(wr_req); fork this.in_chan.get(rr); join_none #10; end endcase if(rr.compare(wr_req,s)) `vmm_note(log,$psprintf("VMM Producer Got: Addr = %h, Data = %h, Kind = %s", rr.addr, rr.data, rr.kind)); else `vmm_error(log, $psprintf("VMM R/R Producer: put %s; got %s", wr_req.psdisplay(),rr.psdisplay())); end // Now do out-of-order reads to the addresses we've just written fork for(int i = 0; i<10; i++) begin rd_req = new(); rd_req.kind = vmm_apb_rw::READ; rd_req.data = 'x; rd_req.addr = addrs[i]; rd_req.data_id = i; rd_req.scenario_id = 1; //rd_reqs.push_back(rd_req); fork automatic vmm_apb_rw mytr = rd_req; int dly = {$random} % 100; #dly this.out_chan.put(mytr); `vmm_note(log,$psprintf("VMM Producer: Addr = %h, Data = %h, Kind = %s, id = %0d", rd_req.addr, rd_req.data, rd_req.kind, rd_req.data_id)); join_none // this should put 10 read transactions out in random order end for(int j = 0; j<10; j++) begin this.in_chan.get(rr); if(!rr.compare(reqs[rr.data_id],s)) `vmm_error(log, $psprintf("VMM R/R Producer: put %s; got %s", reqs[rr.data_id].psdisplay(),rr.psdisplay())); else `vmm_note(log,$psprintf("VMM Producer Got: Addr = %h, Data = %h, Kind = %s", rr.addr, rr.data, rr.kind)); end join this.notify.indicate(XACTOR_STOPPED); endtask endclass
VMM Producer that conveys transactions as status in a notify indication.
class vmm_notifier #(type T=int) extends vmm_xactor; int GENERATED=0; vmm_channel_typed #(T) out_chan; // for scoreboard function new(string inst, vmm_channel_typed #(T) out_chan=null); super.new("vmm_notifier",inst); GENERATED = notify.configure(GENERATED,vmm_notify::ONE_SHOT); if (out_chan == null) this.out_chan = new("vmm_channel #(vmm_apb_rw)","out_chan"); endfunction virtual task main(); T tr,cp; super.main(); tr = new(); repeat(10) begin assert(tr.randomize()); $cast(cp,tr.copy()); // #0; `vmm_note(log,$psprintf("Notifying with status %s", tr.psdisplay())); notify.indicate(GENERATED, tr); out_chan.sneak(cp); #1; end endtask endclass