目录
fmt_pkg
do_config():被动接受数据,do_config()从req中获取需要的配置
do_consume():do_consume()尝试拿到data后等若干周期在拿一次,$urandom_range(1, this.data_consum_peroid)周期越短尝试的越频繁。
do_receive():this.fifo_bound-this.fifo.num()) >= intf.fmt_length,最大容量减去当前已放置,余量需要大于将要放置的数据。
task do_config();
fmt_trans req, rsp;
forever begin
this.req_mb.get(req);
case(req.fifo)
SHORT_FIFO: this.fifo_bound = 64;
MED_FIFO: this.fifo_bound = 256;
LONG_FIFO: this.fifo_bound = 512;
ULTRA_FIFO: this.fifo_bound = 2048;
endcase
this.fifo = new(this.fifo_bound);
case(req.bandwidth)
LOW_WIDTH: this.data_consum_peroid = 8;
MED_WIDTH: this.data_consum_peroid = 4;
HIGH_WIDTH: this.data_consum_peroid = 2;
ULTRA_WIDTH: this.data_consum_peroid = 1;
endcase
rsp = req.clone();
rsp.rsp = 1;
this.rsp_mb.put(rsp);
end
endtask
task do_reset();
forever begin
@(negedge intf.rstn)
intf.fmt_grant <= 0;
end
endtask
task do_receive();
forever begin
@(posedge intf.fmt_req);
forever begin
@(posedge intf.clk);
if((this.fifo_bound-this.fifo.num()) >= intf.fmt_length)
break;
end
intf.drv_ck.fmt_grant <= 1;
@(posedge intf.fmt_start);
fork
begin
@(posedge intf.clk);
intf.drv_ck.fmt_grant <= 0;
end
join_none
repeat(intf.fmt_length) begin
@(negedge intf.clk);
this.fifo.put(intf.fmt_data);
end
end
endtask
task do_consume();
bit[31:0] data;
forever begin
void'(this.fifo.try_get(data));
repeat($urandom_range(1, this.data_consum_peroid)) @(posedge intf.clk);
end
endtask
endclass
mcdf_pkg
建立虚拟模型class mcdf_refmod
task do_reg_update():联系reg_pkg的reg_trans,当reg_trans变化时,mcdf_pkg中的mcdf_refmod对于实际reg变化同步改变(即及时捕捉到硬件上对reg的变化,更新mcdf_pkg。
task do_packet(int id):fmt_trans ot;ot.data为数据包形式, mon_data_t it,it.data为单一数据格式。
class mcdf_refmod;
local virtual mcdf_intf intf;
local string name;
mcdf_reg_t regs[3];
mailbox #(reg_trans) reg_mb;
mailbox #(mon_data_t) in_mbs[3];
mailbox #(fmt_trans) out_mbs[3];
function new(string name="mcdf_refmod");
this.name = name;
foreach(this.out_mbs[i]) this.out_mbs[i] = new();
endfunction
task run();
fork
do_reset();
this.do_reg_update();
do_packet(0);
do_packet(1);
do_packet(2);
join
endtask
task do_reg_update();
reg_trans t;
forever begin
this.reg_mb.get(t);
if(t.addr[7:4] == 0 && t.cmd == `WRITE) begin
this.regs[t.addr[3:2]].en = t.data[0];
this.regs[t.addr[3:2]].prio = t.data[2:1];
this.regs[t.addr[3:2]].len = t.data[5:3];
end
else if(t.addr[7:4] == 1 && t.cmd == `READ) begin
this.regs[t.addr[3:2]].avail = t.data[7:0];
end
end
endtask
task do_packet(int id);
fmt_trans ot;
mon_data_t it;
forever begin
this.in_mbs[id].peek(it);
ot = new();
ot.length = 4 << (this.get_field_value(id, RW_LEN) & 'b11);
ot.data = new[ot.length];
ot.ch_id = id;
foreach(ot.data[m]) begin
this.in_mbs[id].get(it);
ot.data[m] = it.data;
end
this.out_mbs[id].put(ot);
end
endtask
function int get_field_value(int id, mcdf_field_t f);
case(f)
RW_LEN: return regs[id].len;
RW_PRIO: return regs[id].prio;
RW_EN: return regs[id].en;
RD_AVAIL: return regs[id].avail;
endcase
endfunction
task do_reset();
forever begin
@(negedge intf.rstn);
foreach(regs[i]) begin
regs[i].len = 'h0;
regs[i].prio = 'h3;
regs[i].en = 'h1;
regs[i].avail = 'h20;
end
end
endtask
function void set_interface(virtual mcdf_intf intf);
if(intf == null)
$error("interface handle is NULL, please check if target interface has been intantiated");
else
this.intf = intf;
endfunction
endclass
数据检查mcdf_checker
this.fmt_mb.get(mont);
this.exp_mbs[mont.ch_id].get(expt);
cmp = mont.compare(expt);
上述数据之所以可以比较是因为:this.fmt_mb.get(mont)从fmt_pkg中的monitor接受dut的数据(id,data);this.exp_mbs[mont.ch_id].get(expt) exp_mbs中id为do_packet(0\1\2)模拟真实dut设定,exp_mbs获得(chnl_trans打包的数据包)以及fmt.ch_id
class mcdf_checker;
local string name;
local int err_count;
local int total_count;
local int chnl_count[3];
local virtual mcdf_intf intf;
local mcdf_refmod refmod;
mailbox #(mon_data_t) chnl_mbs[3];
mailbox #(fmt_trans) fmt_mb;
mailbox #(reg_trans) reg_mb;
mailbox #(fmt_trans) exp_mbs[3];
function new(string name="mcdf_checker");
this.name = name;
foreach(this.chnl_mbs[i]) this.chnl_mbs[i] = new();
this.fmt_mb = new();
this.reg_mb = new();
this.refmod = new();
foreach(this.refmod.in_mbs[i]) begin
this.refmod.in_mbs[i] = this.chnl_mbs[i];
this.exp_mbs[i] = this.refmod.out_mbs[i];
end
this.refmod.reg_mb = this.reg_mb;
this.err_count = 0;
this.total_count = 0;
foreach(this.chnl_count[i]) this.chnl_count[i] = 0;
endfunction
function void set_interface(virtual mcdf_intf intf);
if(intf == null)
$error("interface handle is NULL, please check if target interface has been intantiated");
else
this.intf = intf;
this.refmod.set_interface(intf);
endfunction
task run();
fork
this.do_compare();
this.refmod.run();
join
endtask
task do_compare();
fmt_trans expt, mont;
bit cmp;
forever begin
this.fmt_mb.get(mont);
this.exp_mbs[mont.ch_id].get(expt);
cmp = mont.compare(expt);
this.total_count++;
this.chnl_count[mont.ch_id]++;
if(cmp == 0) begin
this.err_count++;
rpt_pkg::rpt_msg("[CMPFAIL]",
$sformatf("%0t %0dth times comparing but failed! MCDF monitored output packet is different with reference model output", $time, this.total_count),
rpt_pkg::ERROR,
rpt_pkg::TOP,
rpt_pkg::LOG);
end
else begin
rpt_pkg::rpt_msg("[CMPSUCD]",
$sformatf("%0t %0dth times comparing and succeeded! MCDF monitored output packet is the same with reference model output", $time, this.total_count),
rpt_pkg::INFO,
rpt_pkg::HIGH);
end
end
endtask