frame:
testbench:
HCLK_PCLK_RATIO: Randomly define the hclk pclk ratio; each interface clk, rst connection; generate pclk that meets the corresponding ratio; connect with DUT; set vif to agt; agt is set to the bottom layer
About rest_if: Write the rest task directly in tb, and the uvm side cannot be recognized, because uvm is wrapped with pkg. Therefore, rest_if is defined to set the task in it, and then pass config_db to the uvm environment;
`include "uvm_macros.svh" //import uvm_pkg::*; import ahbl_mst_pkg::*; import apb_slv_pkg::*; module ahb2apb_tb(); parameter HCLK_PERIOD = 100ns;//10MHz defines the period bit[1:0] tmp_var; int HCLK_PCLK_RATIO;//Random definition hclk pclk ratio 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; end case end reg hclk; wire hresetn; wire pclk; wire preset n; reg [3:0] hclk_cnt; reg pclken; wire apbactive; ahbl_if ahbl_if_i(hclk,hresetn);//connection of clk and rst of the interface apb_if apb_if_i(pclk,presetn); reset_if reset_if_i(hclk); initial begin hclk = 1'b0; forever begins #(HCLK_PERIOD/2);//Flip every 1/2 cycle hclk = !hclk; end end assign hresetn = !reset_if_i.reset; always @(posedge hclk or negedge hresetn)//realize the pclk that meets the corresponding ratio 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 & amp; hclk;// & amp; operation satisfies the ratio only when hclk is high and pclk is high 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 to 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:
Instantiate each agt, scb and build; connect mon and TLM of ahbFIFO and apbFIFO in scb; drv and sqrTLM are connected in 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); end function 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); end function 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); end function end class
base_test:
virtual reset interface, instantiate env; set is_active to agt, get reset_if;
uvm_top.print_topology() The simulation starts to print out the hierarchy of uvm (hierarchy)
uvm_error in the whole simulation process is collected in report_phase, if it is 0, it succeeds, and if there is an error, it fails;
import ahb2apb_pkg::*; class ahb2apb_base_test extends uvm_test; `uvm_component_utils(ahb2apb_base_test) virtual reset_if reset_if_i;// instantiate reset interface and env ahb2apb_env env_i; function new(string name, uvm_component parent=null); super. new(name, parent); end function 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!") end function virtual function void start_of_simulation_phase(uvm_phase phase); super.start_of_simulation_phase(phase); uvm_top.print_topology();//The simulation starts to print out the hierarchy of uvm (hierarchy) end function virtual task run_phase(uvm_phase phase); super. run_phase(phase); reset_if_i.reset_dut;//reset signal 0 1 0 phase.phase_done.set_drain_time(this,5us);//simulation delay time end task function void report_phase(uvm_phase phase);//Collect uvm_error in the whole simulation process, if it is 0, it succeeds, if there is an error, it fails 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 end function function int num_uvm_errors(); uvm_report_server server; if(server==null) server = get_report_server(); return server.get_severity_count(UVM_ERROR); end function end class
scb:
Two fifos and two ports, use FIFO to cache data, you can choose to compare ahb and apb side by side, or ahb side packs and sends a whole pkt, apbfifo side gets the same amount and sends out comparison at the same time;
In env, mon is connected to the export of fifo; it is necessary to connect the export of fifo to the port of scb in scb;
After using port.get in check_pkt in run_phase to tran of apb and ahbl, compare the signals among them, and report an error and err_flag + 1;
Note when comparing prot: apb_pkt.prot[0] corresponds to ahb_pkt.hprot[1]; Privileged access
apb_pkt.prot[2] is 1 corresponding to ahb_pkt.hprot[0] is 0, so there is an error when equal; Bufferable
class ahb2apb_scb extends uvm_scoreboard; //Two fifos and two ports, use FIFO to cache data, you can choose to compare ahb and apb ends individually, or pack and send a whole pkt at ahb end, and apbfifo end will send out comparisons at the same time after obtaining the same amount; 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); end function 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"); end function function void connect_phase(uvm_phase phase); super. connect_phase(phase); //Mon is connected to the export of fifo in env; the export of fifo needs to be connected to the port of scb in scb; apb_port.connect(apb_fifo.blocking_get_export); ahb_port.connect(ahb_fifo.blocking_get_export); end function virtual task run_phase(uvm_phase phase); check_pkt(); end task 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); //After using port.get in check_pkt in run_phase to the tran of apb and ahbl, compare the signals among them, and report an error and 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 & amp; (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 & amp; (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:[\r],apb:[\r]", 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:[\r],apb:[\r]", ahb_pkt.hprot[0], apb_pkt.prot[2])) err_flag = 1; end if(ahb_pkt.hwrite)begin if((ahb_pkt.hsize==WORD) & amp; (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:K.",apb_pkt.strb)) err_flag = 1; end if(((ahb_pkt.hsize==HWORD) & amp; !ahb_pkt.haddr[1] & amp; (apb_pkt.strb!=4'b0011)) | ((ahb_pkt.hsize==HWORD) & amp; 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:K.",ahb_pkt .haddr[1],apb_pkt.strb)) err_flag = 1; end if(((ahb_pkt.hsize==BYTE) & amp; (ahb_pkt.haddr[1:0]==2'b00) & amp;(apb_pkt.strb != 4'b0001)) | ((ahb_pkt.hsize= =BYTE) & amp; (ahb_pkt.haddr[1:0]==2'b01) & amp;(apb_pkt.strb != 4'b0010)) | ((ahb_pkt.hsize==BYTE) & amp; (ahb_pkt .haddr[1:0]==2'b10) & amp;(apb_pkt.strb != 4'b0100)) | ((ahb_pkt.hsize==BYTE) & amp; (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]:+, apb-pstrb:K.", 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:[\r],apb:[\r].",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 end task end class