AHB-to-APB Bridge–06testbench, env, base_test, scb

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