框架:
testbench:
HCLK_PCLK_RATIO:随机定义hclk pclk比率;各个接口clk、rst连接;生成满足相应比率的pclk;与DUT的连接;将vif set到agt中去;agt在set到底层
关于rest_if:直接在tb中写rest task,uvm侧是识别不到的,因为uvm用pkg包裹了起来。所以定义了rest_if在其中设置task,再通过config_db到uvm环境中;
`include "uvm_macros.svh"
//import uvm_pkg::*;
import ahbl_mst_pkg::*;
import apb_slv_pkg::*;
module ahb2apb_tb();
parameter HCLK_PERIOD = 100ns;//10MHz 定义周期
bit[1:0] tmp_var;
int HCLK_PCLK_RATIO;//随机定义hclk pclk比值
initial begin
tmp_var = $urandom_range(0,3);
case(tmp_var)
0:HCLK_PCLK_RATIO = 1;
1:HCLK_PCLK_RATIO = 2;
2:HCLK_PCLK_RATIO = 4;
3:HCLK_PCLK_RATIO = 8;
endcase
end
reg hclk;
wire hresetn;
wire pclk;
wire presetn;
reg [3:0] hclk_cnt;
reg pclken;
wire apbactive;
ahbl_if ahbl_if_i(hclk,hresetn);//接口的clk、rst连接
apb_if apb_if_i(pclk,presetn);
reset_if reset_if_i(hclk);
initial begin
hclk = 1'b0;
forever begin
#(HCLK_PERIOD/2);//每过1/2周期翻转一次
hclk = !hclk;
end
end
assign hresetn = !reset_if_i.reset;
always @(posedge hclk or negedge hresetn)//实现满足相应比率的pclk
if(!hresetn)
hclk_cnt <= 4'd0;
else if(hclk_cnt == (HCLK_PCLK_RATIO - 1'b1))
hclk_cnt <= 4'd0;
else
hclk_cnt <= hclk_cnt + 1'd1;
always @(negedge hclk or negedge hresetn)
if(!hresetn)
pclken <= 1'b0;
else if(hclk_cnt == (HCLK_PCLK_RATIO - 1'b1))
pclken <= 1'b1;
else
pclken <= 1'b0;
reg pclken_r;
always @(*)begin
#1ns;
pclken_r = pclken;
end
assign pclk = pclken_r & hclk;//&操作 满足比率下只在hclk为高pclk才高
assign presetn = hresetn;
cmsdk_ahb_to_apb #(
.ADDRWIDTH (16),
.REGISTER_RDATA (1),
.REGISTER_WDATA (0)) dut(
.HCLK (hclk),
.HRESETn (hresetn),
.PCLKEN (pclken),
.HSEL (ahbl_if_i.hsel),
.HADDR (ahbl_if_i.haddr[15:0]),
.HTRANS (ahbl_if_i.htrans),
.HSIZE (ahbl_if_i.hsize),
.HPROT (ahbl_if_i.hprot),
.HWRITE (ahbl_if_i.hwrite),
.HREADY (ahbl_if_i.hready),
.HWDATA (ahbl_if_i.hwdata),
.HREADYOUT (ahbl_if_i.hready),
.HRDATA (ahbl_if_i.hrdata),
.HRESP (ahbl_if_i.hresp),
.PADDR (apb_if_i.paddr[15:0]),
.PENABLE (apb_if_i.penable),
.PWRITE (apb_if_i.pwrite),
.PSTRB (apb_if_i.pstrb),
.PPROT (apb_if_i.pprot),
.PWDATA (apb_if_i.pwdata),
.PSEL (apb_if_i.psel),
.PRDATA (apb_if_i.prdata),
.PREADY (apb_if_i.pready),
.PSLVERR (apb_if_i.pslverr),
.APBACTIVE (apbactive)
);
assign apb_if_i.paddr[31:16] = 16'd0;
initial begin//vif set到agt中去
uvm_config_db#(virtual apb_if)::set(null,"uvm_test_top.env_i.apb_slv_agt_i","vif",apb_if_i);
uvm_config_db#(virtual ahbl_if)::set(null,"uvm_test_top.env_i.ahbl_mst_agt_i","vif",ahbl_if_i);
uvm_config_db#(virtual reset_if)::set(null,"uvm_test_top","vif",reset_if_i);
run_test();
end
env:
例化各个agt、scb并build;连接mon与scb中ahbFIFO和apbFIFO的TLM;drv和sqrTLM在agt连接
class ahb2apb_env extends uvm_env;
`uvm_component_utils(ahb2apb_env)
apb_slv_agt apb_slv_agt_i;
ahbl_mst_agt ahbl_mst_agt_i;
ahb2apb_scb ahb2apb_scb_i;
function new(string name,uvm_component parent);
super.new(name,parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
apb_slv_agt_i = apb_slv_agt::type_id::create("apb_slv_agt_i",this);
ahbl_mst_agt_i = ahbl_mst_agt::type_id::create("ahbl_mst_agt_i",this);
ahb2apb_scb_i = ahb2apb_scb::type_id::create("ahb2apb_scb_i",this);
endfunction
virtual function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
apb_slv_agt_i.mon_i.ap.connect(ahb2apb_scb_i.apb_fifo.analysis_export);
ahbl_mst_agt_i.mon_i.ap.connect(ahb2apb_scb_i.ahb_fifo.analysis_export);
endfunction
endclass
base_test:
virtual reset接口、例化env;set is_active到agt,get reset_if;
uvm_top.print_topology() 仿真一启动打印出uvm的hierarchy(层次结构)
report_phase中收集整个仿真过程中uvm_error,为0成功 有error失败;
import ahb2apb_pkg::*;
class ahb2apb_base_test extends uvm_test;
`uvm_component_utils(ahb2apb_base_test)
virtual reset_if reset_if_i;//例化reset接口和env
ahb2apb_env env_i;
function new(string name,uvm_component parent=null);
super.new(name,parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
env_i=ahb2apb_env::type_id::create("env_i",this);
uvm_config_db#(uvm_active_passive_enum)::set(this,"env_i.ahbl_mst_agt_i","is_active",UVM_ACTIVE);
if(!uvm_config_db#(virtual reset_if)::get(this,"","vif",reset_if_i))
`uvm_fatal("No reset_if","reset_if_i is not set!")
endfunction
virtual function void start_of_simulation_phase(uvm_phase phase);
super.start_of_simulation_phase(phase);
uvm_top.print_topology();//仿真一启动打印出uvm的hierarchy(层次结构)
endfunction
virtual task run_phase(uvm_phase phase);
super.run_phase(phase);
reset_if_i.reset_dut;//reset信号 0 1 0
phase.phase_done.set_drain_time(this,5us);//仿真延迟时间
endtask
function void report_phase(uvm_phase phase);//收集整个仿真过程中uvm_error,为0成功 有error失败
super.report_phase(phase);
if(num_uvm_errors==0)begin
`uvm_info(get_type_name(),"Simulation PASSED!",UVM_NONE)
end
else begin
`uvm_info(get_type_name(),"SImulation FAILED!",UVM_NONE)
end
endfunction
function int num_uvm_errors();
uvm_report_server server;
if(server==null) server = get_report_server();
return server.get_severity_count(UVM_ERROR);
endfunction
endclass
scb:
两个fifo两个port,使用FIFO缓存数据,可以选择ahb、apb端都单个比较,或者ahb端打包发一整个pkt,apbfifo端获得同等数量后同时发出比较;
在env中mon连接到了fifo的export;需要在scb中把fifo的export连到scb的port中;
run_phase中check_pkt中用port.get到apb、ahbl的tran后,将其中信号进行对比,有误报错并err_flag+1;
在进行prot对比时需要注意:apb_pkt.prot[0]对应于ahb_pkt.hprot[1];Privileged access访问权限
apb_pkt.prot[2]为1对应于ahb_pkt.hprot[0]为0,所以在相等的时候有错误;Bufferable
class ahb2apb_scb extends uvm_scoreboard;
//两个fifo两个port,使用FIFO缓存数据,可以选择ahb、apb端都单个比较,或者ahb端打包发一整个pkt,apbfifo端获得同等数量后同时发出比较;
uvm_tlm_analysis_fifo #(apb_tran) apb_fifo;
uvm_blocking_get_port #(apb_tran) apb_port;
uvm_tlm_analysis_fifo #(ahbl_tran) ahb_fifo;
uvm_blocking_get_port #(ahbl_tran) ahb_port;
func_cov fcov;
`uvm_component_utils(ahb2apb_scb)
function new(string name,uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
apb_fifo = new("apb_fifo",this);
apb_port = new("apb_port",this);
ahb_fifo = new("ahb_fifo",this);
ahb_port = new("ahb_port",this);
fcov = new("fcov");
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
//在env中mon连接到了fifo的export;需要在scb中把fifo的export连到scb的port中;
apb_port.connect(apb_fifo.blocking_get_export);
ahb_port.connect(ahb_fifo.blocking_get_export);
endfunction
virtual task run_phase(uvm_phase phase);
check_pkt();
endtask
virtual task check_pkt();
apb_tran apb_pkt;
ahbl_tran ahb_pkt;
bit err_flag;
while(1)begin
err_flag = 0;
ahb_port.get(ahb_pkt);
apb_port.get(apb_pkt);
fcov.cg.sample(ahb_pkt,apb_pkt);
//run_phase中check_pkt中用port.get到apb、ahbl的tran后,将其中信号进行对比,有误报错并err_flag+1;
if(ahb_pkt.haddr[15:2] != apb_pkt.addr[15:2])begin
`uvm_error(get_type_name(),$sformatf("AHB-packet and APB-packet address mismatch! ahb-addr[15:2][%0h],apb-addr[15:2][0%h]",ahb_pkt.haddr[15:2],apb_pkt.addr[15:2]))
err_flag = 1;
end
if(ahb_pkt.hrwdata != apb_pkt.data)begin
`uvm_error(get_type_name(),$sformatf("AHB-packet and APB-packet rw-data mismatch! ahb-data[%0h],apb-data[0%h]",ahb_pkt.hrwdata,apb_pkt.data))
err_flag = 1;
end
if(ahb_pkt.hwrite & (apb_pkt.kind == apb_slv_pkg::READ ))begin
`uvm_error(get_type_name(),"AHB-packet and APB-packet read/write mismatch! ahb-'write',apb-'read'")
err_flag = 1;
end
if(!ahb_pkt.hwrite & (apb_pkt.kind == apb_slv_pkg::WRITE ))begin
`uvm_error(get_type_name(),"AHB-packet and APB-packet read/write mismatch! ahb-'read',apb-'write'")
err_flag = 1;
end
if(apb_pkt.prot[0] != ahb_pkt.hprot[1])begin
`uvm_error(get_type_name(),$sformatf("AHB-packet and APB-packet 'hprot[1]/prot[0]' mismatch! ahb:[%0d],apb:[%0d]",ahb_pkt.hprot[1],apb_pkt.prot[0]))
err_flag = 1;
end
if(apb_pkt.prot[2] == ahb_pkt.hprot[0])begin
`uvm_error(get_type_name(),$sformatf("AHB-packet and APB-packet 'hport[0]/prot[2]' mismatch! ahb:[%0d],apb:[%0d]",ahb_pkt.hprot[0],apb_pkt.prot[2]))
err_flag = 1;
end
if(ahb_pkt.hwrite)begin
if((ahb_pkt.hsize==WORD) & (apb_pkt.strb != 4'b1111))begin
`uvm_error(get_type_name(),$sformatf("AHB-packet and APB-packet hsize/haddr/pstrb mismatch! ahb-hsize:WORD,apb-pstrb:%4b.",apb_pkt.strb))
err_flag = 1;
end
if(((ahb_pkt.hsize==HWORD) & !ahb_pkt.haddr[1] & (apb_pkt.strb!=4'b0011)) | ((ahb_pkt.hsize==HWORD) & ahb_pkt.haddr[1] &(apb_pkt.strb != 4'b1100)))begin
`uvm_error(get_type_name(),$sformatf("AHB-packet and APB-packet hsize/haddr/pstrb mismatch! ahb-hsize:HWORD,ahb-haddr[1]:%d,apb-pstrb:%4b.",ahb_pkt.haddr[1],apb_pkt.strb))
err_flag = 1;
end
if(((ahb_pkt.hsize==BYTE) & (ahb_pkt.haddr[1:0]==2'b00) &(apb_pkt.strb != 4'b0001)) | ((ahb_pkt.hsize==BYTE) & (ahb_pkt.haddr[1:0]==2'b01) &(apb_pkt.strb != 4'b0010)) | ((ahb_pkt.hsize==BYTE) & (ahb_pkt.haddr[1:0]==2'b10) &(apb_pkt.strb != 4'b0100)) | ((ahb_pkt.hsize==BYTE) & (ahb_pkt.haddr[1:0]==2'b11) &(apb_pkt.strb != 4'b1000)))begin
`uvm_error(get_type_name(),$sformatf("AHB-packet and APB-packet hsize/haddr/pstrb mismatch! ahb-hsize:BYTE,ahb-haddr[1:0]:%2b,apb-pstrb:%4b.",ahb_pkt.haddr[1:0],apb_pkt.strb))
err_flag = 1;
end
end
if(ahb_pkt.hresp != apb_pkt.slverr)begin
`uvm_error(get_type_name(),$sformatf("AHB-packet and APB-packet hresp/pslverr mismatch! ahb:[%0d],apb:[%0d].",ahb_pkt.hresp,apb_pkt.slverr))
err_flag = 1;
end
if(err_flag)begin
`uvm_error(get_type_name(),"Pkt comparing FAILED!")
end
else begin
`uvm_info(get_type_name(),"Pkt comparing correct!",UVM_LOW)
end
# 20ns;
end
endtask
endclass