概述
MCDF更新APB总线
原来的寄存器做总线换成了APB总线,通道数量加了1。所有的接口几乎都发生了改变。
channel更新为slave node
data和valid接口保留,新增了parity和wait和error,wait接口就是原来的ready接口,表示fifo空满、是否准备好接收新的data。数据校验位parity是data的异或!(return^data;)
时序图:
作为item的chnl_trans类不变,没有变化。传送的信号还是原来的那些。
时序图发生变化,所以驱动item的chnl_driver发生了变化:重置任务中多了ch_data_p这个信号(parity);chnl_write任务也需要多这个信号,并定义一个获取校验位的函数get_parity,就是data异或。
task chnl_write(input chnl_trans t);
foreach(t.data[i]) begin
@(posedge intf.clk);
intf.drv_ck.ch_valid <= 1;
intf.drv_ck.ch_data <= t.data[i];
intf.drv_ck.ch_data_p <= get_parity(t.data[i]);
@(negedge intf.clk);
wait(intf.ch_wait === 'b0);
`uvm_info(get_type_name(), $sformatf("sent data 'h%8x", t.data[i]), UVM_HIGH)
repeat(t.data_nidles) chnl_idle();
end
repeat(t.pkt_nidles) chnl_idle();
endtask
task chnl_idle();
@(posedge intf.clk);
intf.drv_ck.ch_valid <= 0;
intf.drv_ck.ch_data <= 0;
intf.drv_ck.ch_data_p <= 0;
endtask
function get_parity(bit[31:0] data);
return ^data;
endfunction
sequencer只有注册和new函数,无需更新。
sequence,成员变量多了动态数组data[],暂时还不知道为什么?
并对所有成员变量增加了约束。
class chnl_data_sequence extends uvm_sequence #(chnl_trans);
rand int pkt_id = 0;
rand int ch_id = -1;
rand int data_nidles = -1;
rand int pkt_nidles = -1;
rand int data_size = -1;
rand int ntrans = 10;
rand int data[];
constraint cstr{
soft pkt_id == 0;
soft ch_id == -1;
soft data_nidles == -1;
soft pkt_nidles == -1;
soft data_size == -1;
soft ntrans == 10;
soft data.size() == data_size;
foreach(data[i]) soft data[i] == -1;
};
`uvm_object_utils_begin(chnl_data_sequence)
`uvm_field_int(pkt_id, UVM_ALL_ON)
`uvm_field_int(ch_id, UVM_ALL_ON)
`uvm_field_int(data_nidles, UVM_ALL_ON)
`uvm_field_int(pkt_nidles, UVM_ALL_ON)
`uvm_field_int(data_size, UVM_ALL_ON)
`uvm_field_int(ntrans, UVM_ALL_ON)
`uvm_object_utils_end
`uvm_declare_p_sequencer(chnl_sequencer)
function new (string name = "chnl_data_sequence");
super.new(name);
endfunction
monitor的PORT从uvm_blocking_put_port变成了uvm_analysis_port,为什么?对应调用的方法也从put变成了write,ready信号更新为wait
agent的变化也稍微大了点,build_phase中调用uvm_config_db配置了接口,connect_phase调用了set_interface连接了接口。之前的接口是从顶层拿到接口指针后调用这里的set_interface
对比的文件是还没更新MCDF前的uvm入门实验5的文件。
tb中接口的更新:多了parity,ready改成wait,多了parity error,对应的时钟块信号发生变化,error作为input,parity作为output
interface chnl_intf(input clk, input rstn);
logic [31:0] ch_data;
logic ch_data_p;
logic ch_valid;
logic ch_wait;
logic ch_parity_err;
clocking drv_ck @(posedge clk);
default input #1ps output #1ps;
output ch_data, ch_valid, ch_data_p;
input ch_wait, ch_parity_err;
endclocking
clocking mon_ck @(posedge clk);
default input #1ps output #1ps;
input ch_data, ch_valid, ch_data_p, ch_wait, ch_parity_err;
endclocking
endinterface
module中的接口分别连接四个node,并且更新到dut的连接
chnl_intf chnl0_if(.*);
chnl_intf chnl1_if(.*);
chnl_intf chnl2_if(.*);
chnl_intf chnl3_if(.*);
.slv0_data_i (chnl0_if.ch_data ) , //
.slv0_data_p_i (chnl0_if.ch_data_p ) , // one bit parity of data_i
.slv0_valid_i (chnl0_if.ch_valid ) , //
.slv0_wait_o (chnl0_if.ch_wait ) , //
.slv0_parity_err_o (chnl0_if.ch_parity_err ) , //
.slv1_data_i (chnl1_if.ch_data ) , //
.slv1_data_p_i (chnl1_if.ch_data_p ) , // one bit parity of data_i
.slv1_valid_i (chnl1_if.ch_valid ) , //
.slv1_wait_o (chnl1_if.ch_wait ) , //
.slv1_parity_err_o (chnl1_if.ch_parity_err ) , //
.slv2_data_i (chnl2_if.ch_data ) , //
.slv2_data_p_i (chnl2_if.ch_data_p ) , // one bit parity of data_i
.slv2_valid_i (chnl2_if.ch_valid ) , //
.slv2_wait_o (chnl2_if.ch_wait ) , //
.slv2_parity_err_o (chnl2_if.ch_parity_err ) , //
.slv3_data_i (chnl3_if.ch_data ) , //
.slv3_data_p_i (chnl3_if.ch_data_p ) , // one bit parity of data_i
.slv3_valid_i (chnl3_if.ch_valid ) , //
.slv3_wait_o (chnl3_if.ch_wait ) , //
.slv3_parity_err_o (chnl3_if.ch_parity_err ) , //
initial块中自上而下配置接口到各个层次:top-env-agent;top-env
uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top.env.chnl_agts[0]", "vif", chnl0_if);
uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top.env.chnl_agts[1]", "vif", chnl1_if);
uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top.env.chnl_agts[2]", "vif", chnl2_if);
uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top.env.chnl_agts[3]", "vif", chnl3_if);
uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top.env.*", "chnl_vifs[0]", chnl0_if);
uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top.env.*", "chnl_vifs[1]", chnl1_if);
uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top.env.*", "chnl_vifs[2]", chnl2_if);
uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top.env.*", "chnl_vifs[3]", chnl3_if);
formatter的更新
len从0-255表示1-256个payload
时序图如下:
fmt_trans多了校验parity。
先看接口的更新,接口变为5个,ready其实就是原来的grant
interface fmt_intf(input clk, input rstn);
logic fmt_ready;
logic fmt_valid;
logic [31:0] fmt_data;
logic fmt_first;
logic fmt_last;
clocking drv_ck @(posedge clk);
default input #1ps output #1ps;
input fmt_valid, fmt_data, fmt_first, fmt_last;
output fmt_ready;
endclocking
clocking mon_ck @(posedge clk);
default input #1ps output #1ps;
input fmt_ready, fmt_valid, fmt_data, fmt_first, fmt_last;
endclocking
endinterface
连接到dut的接口对应更新
.rev_rdy_i (fmt_if.fmt_ready ) , // receiver rdy
.pkg_vld_o (fmt_if.fmt_valid ) , // data is valid
.pkg_dat_o (fmt_if.fmt_data ) , // data/payload
.pkg_fst_o (fmt_if.fmt_first ) , // header indicator
.pkg_lst_o (fmt_if.fmt_last ) // parirty data
driver更新了do_receive,一开始的思路是,看剩余的空间是否比item的长度还长,也就是余量是否充足,如果余量不足就停止了。
更新后的逻辑是,不管里面是不是装满了,放不下的时候ready拉低即可
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_receive();
forever begin
@(intf.drv_ck); #10ps;
if(intf.fmt_valid === 1'b1) begin
forever begin
if((this.fifo_bound-this.fifo.num()) >= 1)
break;
@(intf.drv_ck); #10ps;//不行就再等多一拍
end
this.fifo.put(intf.fmt_data);
#1ps; intf.fmt_ready <= 1;
end
else begin
#1ps; intf.fmt_ready <= 0;
end
end
endtask
monitor端口同样变为ap。原来的只看start是否拉高,现在是一个一个data进行记录,条件变多,信息集成度更高,将id、长度等集成在fmt_data的后16位
task mon_trans();
fmt_trans m;
string s;
forever begin
@(intf.mon_ck iff intf.mon_ck.fmt_first && intf.mon_ck.fmt_valid && intf.mon_ck.fmt_ready);
m = new();
//例化后将拿到的数据包写进这个一模一样的trans对象中
m.length = intf.mon_ck.fmt_data[23:16];//包头的len
m.ch_id = intf.mon_ck.fmt_data[31:24];//最前面的ID
m.data = new[m.length + 3];//为什么加3?这里的new是创建动态数组(trans里面已经有声明随机变量的32位动态数组data),length+3表示动态数组的长度
//len+1=(payload的数量),包头first和包尾last分别占1个payload
foreach(m.data[i]) begin
m.data[i] = intf.mon_ck.fmt_data;
if(i == m.data.size()-1) m.parity = m.data[i];
if(i < m.data.size()-1) @(intf.mon_ck iff intf.mon_ck.fmt_valid && intf.mon_ck.fmt_ready);
end
mon_ana_port.write(m);
agent也做了接口的配置和连接
顶层环境有哪些?
chnl、reg、fmt的agent,mcdf的checker、coverage、rgm,mcdf_virtual_sequencer
mcdf中rgm的更新
run_phase中无需do_reg_update(模拟硬件寄存器数组更新),现在更新后用的是rgm
由于通道数加了1,do_packet多了一个;packet的方式变化了,现在是调用rgm的函数来获得id和长度等信息
class mcdf_refmod extends uvm_component;
mcdf_rgm rgm;
uvm_blocking_get_port #(apb_transfer) reg_bg_port;
uvm_blocking_get_peek_port #(mon_data_t) in_bgpk_ports[4];
uvm_tlm_analysis_fifo #(fmt_trans) out_tlm_fifos[4];
`uvm_component_utils(mcdf_refmod)
function new (string name = "mcdf_refmod", uvm_component parent);
super.new(name, parent);
reg_bg_port = new("reg_bg_port", this);
foreach(in_bgpk_ports[i]) in_bgpk_ports[i] = new($sformatf("in_bgpk_ports[%0d]", i), this);
foreach(out_tlm_fifos[i]) out_tlm_fifos[i] = new($sformatf("out_tlm_fifos[%0d]", i), this);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(mcdf_rgm)::get(this,"","rgm", rgm)) begin
`uvm_fatal("GETRGM","cannot get RGM handle from config DB")
end
endfunction
task run_phase(uvm_phase phase);
fork
do_packet(0);
do_packet(1);
do_packet(2);
do_packet(3);
join
endtask
task do_packet(int ch);
fmt_trans ot;
mon_data_t it;
forever begin
this.in_bgpk_ports[ch].peek(it);
ot = new();
ot.length = rgm.get_reg_field_length(ch);
ot.ch_id = rgm.get_reg_field_id(ch);
ot.data = new[ot.length+3];
foreach(ot.data[m]) begin
if(m == 0) begin//包头
ot.data[m] = (ot.ch_id<<24) + (ot.length<<16);
ot.parity = ot.data[m];
end
else if(m == ot.data.size()-1) begin//包尾
ot.data[m] = ot.parity;
end
else begin //中间数据payload
this.in_bgpk_ports[ch].get(it);
ot.data[m] = it.data;
ot.parity ^= it.data;
end
end
this.out_tlm_fifos[ch].put(ot);
end
endtask
endclass: mcdf_refmod
checker的更新
大量的PORT和mailbox被TLM analysis fifo替代,
最后
以上就是害羞飞鸟为你收集整理的电力电子转战数字IC20220825day69——MCDF更新APB总线 MCDF更新APB总线 channel更新为slave nodeformatter的更新顶层环境有哪些?mcdf中rgm的更新checker的更新的全部内容,希望文章能够帮你解决电力电子转战数字IC20220825day69——MCDF更新APB总线 MCDF更新APB总线 channel更新为slave nodeformatter的更新顶层环境有哪些?mcdf中rgm的更新checker的更新所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复