`timescale 1ns / 1ps /* module tb(); reg presetn = 0; reg pclk = 0; reg psel = 0; reg penable = 0 ; reg pwrite = 0; reg [31:0] paddr = 0, pwdata = 0; wire [31:0] prdata; wire pready, pslverr; apb_ram dut (presetn, pclk, psel, penable, pwrite, paddr, pwdata, prdata, pready, pslverr); always #10 pclk = ~pclk; initial begin presetn = 0; repeat(5) @(posedge pclk); presetn = 1; psel = 1; pwrite = 1; paddr = 12; pwdata = 35; @(posedge pclk); penable = 1; @(posedge pready); psel = 0; penable = 0; @(posedge pclk); psel = 1; pwrite = 1'b0; paddr = 12; pwdata = 35; @(posedge pclk); penable = 1'b1; @(posedge pready); psel = 0; penable = 0; @(posedge pclk); psel = 1; pwrite = 1; paddr = 45; pwdata = 35; @(posedge pclk); penable = 1; @(posedge pready); psel = 0; penable = 0; @(posedge pclk); psel = 1; pwrite = 0; paddr = 45; pwdata = 35; @(posedge pclk); penable = 1; @(posedge pready); @(posedge pclk); $stop(); end endmodule */ `include "uvm_macros.svh" import uvm_pkg::*; //////////////////////////////////////////////////////////////////////////////////// class abp_config extends uvm_object; /////configuration of env `uvm_object_utils(abp_config) function new(string name = "abp_config"); super.new(name); endfunction uvm_active_passive_enum is_active = UVM_ACTIVE; endclass /////////////////////////////////////////////////////// typedef enum bit [1:0] {readd = 0, writed = 1, rst = 2} oper_mode; ////////////////////////////////////////////////////////////////////////////////// class transaction extends uvm_sequence_item; rand oper_mode op; rand logic PWRITE; rand logic [31 : 0] PWDATA; rand logic [31 : 0] PADDR; // Output Signals of DUT for APB UART's transaction logic PREADY; logic PSLVERR; logic [31: 0] PRDATA; `uvm_object_utils_begin(transaction) `uvm_field_int (PWRITE,UVM_ALL_ON) `uvm_field_int (PWDATA,UVM_ALL_ON) `uvm_field_int (PADDR,UVM_ALL_ON) `uvm_field_int (PREADY,UVM_ALL_ON) `uvm_field_int (PSLVERR,UVM_ALL_ON) `uvm_field_int (PRDATA,UVM_ALL_ON) `uvm_field_enum(oper_mode, op, UVM_DEFAULT) `uvm_object_utils_end constraint addr_c { PADDR <= 31; } constraint addr_c_err { PADDR > 31; } function new(string name = "transaction"); super.new(name); endfunction endclass : transaction /////////////////////////////////////////////////////////////// /* module tb; transaction tr; initial begin tr = transaction::type_id::create("tr"); tr.randomize(); tr.print(); end endmodule */ ////////////////////////////////////////////////////////////////// ///////////////////write seq class write_data extends uvm_sequence#(transaction); `uvm_object_utils(write_data) transaction tr; function new(string name = "write_data"); super.new(name); endfunction virtual task body(); repeat(15) begin tr = transaction::type_id::create("tr"); tr.addr_c.constraint_mode(1);//enable tr.addr_c_err.constraint_mode(0);//disable start_item(tr); assert(tr.randomize); tr.op = writed; finish_item(tr); end endtask endclass ////////////////////////////////////////////////////////// ////////////////////////read seq class read_data extends uvm_sequence#(transaction); `uvm_object_utils(read_data) transaction tr; function new(string name = "read_data"); super.new(name); endfunction virtual task body(); repeat(15) begin tr = transaction::type_id::create("tr"); tr.addr_c.constraint_mode(1); tr.addr_c_err.constraint_mode(0);//disable start_item(tr); assert(tr.randomize); tr.op = readd; finish_item(tr); end endtask endclass ///////////////////////////////////////////// class write_read extends uvm_sequence#(transaction); //////read after write `uvm_object_utils(write_read) transaction tr; function new(string name = "write_read"); super.new(name); endfunction virtual task body(); repeat(15) begin tr = transaction::type_id::create("tr"); tr.addr_c.constraint_mode(1); tr.addr_c_err.constraint_mode(0); start_item(tr); assert(tr.randomize); tr.op = writed; finish_item(tr); start_item(tr); assert(tr.randomize); tr.op = readd; finish_item(tr); end endtask endclass /////////////////////////////////////////////////////// ///////////////write bulk read bulk class writeb_readb extends uvm_sequence#(transaction); `uvm_object_utils(writeb_readb) transaction tr; function new(string name = "writeb_readb"); super.new(name); endfunction virtual task body(); repeat(15) begin tr = transaction::type_id::create("tr"); tr.addr_c.constraint_mode(1); tr.addr_c_err.constraint_mode(0); start_item(tr); assert(tr.randomize); tr.op = writed; finish_item(tr); end repeat(15) begin tr = transaction::type_id::create("tr"); tr.addr_c.constraint_mode(1); tr.addr_c_err.constraint_mode(0); start_item(tr); assert(tr.randomize); tr.op = readd; finish_item(tr); end endtask endclass ///////////////////////////////////////////////////////////////// //////////////////////slv_error_write class write_err extends uvm_sequence#(transaction); `uvm_object_utils(write_err) transaction tr; function new(string name = "write_err"); super.new(name); endfunction virtual task body(); repeat(15) begin tr = transaction::type_id::create("tr"); tr.addr_c.constraint_mode(0); tr.addr_c_err.constraint_mode(1); start_item(tr); assert(tr.randomize); tr.op = writed; finish_item(tr); end endtask endclass /////////////////////////////////////////////////////////////// /////////////////////////read err class read_err extends uvm_sequence#(transaction); `uvm_object_utils(read_err) transaction tr; function new(string name = "read_err"); super.new(name); endfunction virtual task body(); repeat(15) begin tr = transaction::type_id::create("tr"); tr.addr_c.constraint_mode(0); tr.addr_c_err.constraint_mode(1); start_item(tr); assert(tr.randomize); tr.op = readd; finish_item(tr); end endtask endclass /////////////////////////////////////////////////////////////// class reset_dut extends uvm_sequence#(transaction); `uvm_object_utils(reset_dut) transaction tr; function new(string name = "reset_dut"); super.new(name); endfunction virtual task body(); repeat(15) begin tr = transaction::type_id::create("tr"); tr.addr_c.constraint_mode(1); tr.addr_c_err.constraint_mode(0); start_item(tr); assert(tr.randomize); tr.op = rst; finish_item(tr); end endtask endclass //////////////////////////////////////////////////////////// class driver extends uvm_driver #(transaction); `uvm_component_utils(driver) virtual apb_if vif; transaction tr; function new(input string path = "drv", uvm_component parent = null); super.new(path,parent); endfunction virtual function void build_phase(uvm_phase phase); super.build_phase(phase); tr = transaction::type_id::create("tr"); if(!uvm_config_db#(virtual apb_if)::get(this,"","vif",vif))//uvm_test_top.env.agent.drv.aif `uvm_error("drv","Unable to access Interface"); endfunction task reset_dut(); repeat(5) begin vif.presetn <= 1'b0; vif.paddr <= 'h0; vif.pwdata <= 'h0; vif.pwrite <= 'b0; vif.psel <= 'b0; vif.penable <= 'b0; `uvm_info("DRV", "System Reset : Start of Simulation", UVM_MEDIUM); @(posedge vif.pclk); end endtask task drive(); reset_dut(); forever begin seq_item_port.get_next_item(tr); if(tr.op == rst) begin vif.presetn <= 1'b0; vif.paddr <= 'h0; vif.pwdata <= 'h0; vif.pwrite <= 'b0; vif.psel <= 'b0; vif.penable <= 'b0; @(posedge vif.pclk); end else if(tr.op == writed) begin vif.psel <= 1'b1; vif.paddr <= tr.PADDR; vif.pwdata <= tr.PWDATA; vif.presetn <= 1'b1; vif.pwrite <= 1'b1; @(posedge vif.pclk); vif.penable <= 1'b1; `uvm_info("DRV", $sformatf("mode:%0s, addr:%0d, wdata:%0d, rdata:%0d, slverr:%0d",tr.op.name(),tr.PADDR,tr.PWDATA,tr.PRDATA,tr.PSLVERR), UVM_NONE); @(negedge vif.pready); vif.penable <= 1'b0; tr.PSLVERR = vif.pslverr; end else if(tr.op == readd) begin vif.psel <= 1'b1; vif.paddr <= tr.PADDR; vif.presetn <= 1'b1; vif.pwrite <= 1'b0; @(posedge vif.pclk); vif.penable <= 1'b1; `uvm_info("DRV", $sformatf("mode:%0s, addr:%0d, wdata:%0d, rdata:%0d, slverr:%0d",tr.op.name(),tr.PADDR,tr.PWDATA,tr.PRDATA,tr.PSLVERR), UVM_NONE); @(negedge vif.pready); vif.penable <= 1'b0; tr.PRDATA = vif.prdata; tr.PSLVERR = vif.pslverr; end seq_item_port.item_done(); end endtask virtual task run_phase(uvm_phase phase); drive(); endtask endclass ////////////////////////////////////////////////////////////////// class mon extends uvm_monitor; `uvm_component_utils(mon) uvm_analysis_port#(transaction) send; transaction tr; virtual apb_if vif; function new(input string inst = "mon", uvm_component parent = null); super.new(inst,parent); endfunction virtual function void build_phase(uvm_phase phase); super.build_phase(phase); tr = transaction::type_id::create("tr"); send = new("send", this); if(!uvm_config_db#(virtual apb_if)::get(this,"","vif",vif))//uvm_test_top.env.agent.drv.aif `uvm_error("MON","Unable to access Interface"); endfunction virtual task run_phase(uvm_phase phase); forever begin @(posedge vif.pclk); if(!vif.presetn) begin tr.op = rst; `uvm_info("MON", "SYSTEM RESET DETECTED", UVM_NONE); send.write(tr); end else if (vif.presetn && vif.pwrite) begin @(negedge vif.pready); tr.op = writed; tr.PWDATA = vif.pwdata; tr.PADDR = vif.paddr; tr.PSLVERR = vif.pslverr; `uvm_info("MON", $sformatf("DATA WRITE addr:%0d data:%0d slverr:%0d",tr.PADDR,tr.PWDATA,tr.PSLVERR), UVM_NONE); send.write(tr); end else if (vif.presetn && !vif.pwrite) begin @(negedge vif.pready); tr.op = readd; tr.PADDR = vif.paddr; tr.PRDATA = vif.prdata; tr.PSLVERR = vif.pslverr; `uvm_info("MON", $sformatf("DATA READ addr:%0d data:%0d slverr:%0d",tr.PADDR, tr.PRDATA,tr.PSLVERR), UVM_NONE); send.write(tr); end end endtask endclass ///////////////////////////////////////////////////////////////////// class sco extends uvm_scoreboard; `uvm_component_utils(sco) uvm_analysis_imp#(transaction,sco) recv; bit [31:0] arr[32] = '{default:0}; bit [31:0] addr = 0; bit [31:0] data_rd = 0; function new(input string inst = "sco", uvm_component parent = null); super.new(inst,parent); endfunction virtual function void build_phase(uvm_phase phase); super.build_phase(phase); recv = new("recv", this); endfunction virtual function void write(transaction tr); if(tr.op == rst) begin `uvm_info("SCO", "SYSTEM RESET DETECTED", UVM_NONE); end else if (tr.op == writed) begin if(tr.PSLVERR == 1'b1) begin `uvm_info("SCO", "SLV ERROR during WRITE OP", UVM_NONE); end else begin arr[tr.PADDR] = tr.PWDATA; `uvm_info("SCO", $sformatf("DATA WRITE OP addr:%0d, wdata:%0d arr_wr:%0d",tr.PADDR,tr.PWDATA, arr[tr.PADDR]), UVM_NONE); end end else if (tr.op == readd) begin if(tr.PSLVERR == 1'b1) begin `uvm_info("SCO", "SLV ERROR during READ OP", UVM_NONE); end else begin data_rd = arr[tr.PADDR]; if (data_rd == tr.PRDATA) `uvm_info("SCO", $sformatf("DATA MATCHED : addr:%0d, rdata:%0d",tr.PADDR,tr.PRDATA), UVM_NONE) else `uvm_info("SCO",$sformatf("TEST FAILED : addr:%0d, rdata:%0d data_rd_arr:%0d",tr.PADDR,tr.PRDATA,data_rd), UVM_NONE) end end $display("----------------------------------------------------------------"); endfunction endclass ///////////////////////////////////////////////////////////////////// class agent extends uvm_agent; `uvm_component_utils(agent) abp_config cfg; function new(input string inst = "agent", uvm_component parent = null); super.new(inst,parent); endfunction driver d; uvm_sequencer#(transaction) seqr; mon m; virtual function void build_phase(uvm_phase phase); super.build_phase(phase); cfg = abp_config::type_id::create("cfg"); m = mon::type_id::create("m",this); if(cfg.is_active == UVM_ACTIVE) begin d = driver::type_id::create("d",this); seqr = uvm_sequencer#(transaction)::type_id::create("seqr", this); end endfunction virtual function void connect_phase(uvm_phase phase); super.connect_phase(phase); if(cfg.is_active == UVM_ACTIVE) begin d.seq_item_port.connect(seqr.seq_item_export); end endfunction endclass ////////////////////////////////////////////////////////////////////////////////// class env extends uvm_env; `uvm_component_utils(env) function new(input string inst = "env", uvm_component c); super.new(inst,c); endfunction agent a; sco s; virtual function void build_phase(uvm_phase phase); super.build_phase(phase); a = agent::type_id::create("a",this); s = sco::type_id::create("s", this); endfunction virtual function void connect_phase(uvm_phase phase); super.connect_phase(phase); a.m.send.connect(s.recv); endfunction endclass ////////////////////////////////////////////////////////////////////////// class test extends uvm_test; `uvm_component_utils(test) function new(input string inst = "test", uvm_component c); super.new(inst,c); endfunction env e; write_read wrrd; writeb_readb wrrdb; write_data wdata; read_data rdata; write_err werr; read_err rerr; reset_dut rstdut; virtual function void build_phase(uvm_phase phase); super.build_phase(phase); e = env::type_id::create("env",this); wrrd = write_read::type_id::create("wrrd"); wdata = write_data::type_id::create("wdata"); rdata = read_data::type_id::create("rdata"); wrrdb = writeb_readb::type_id::create("wrrdb"); werr = write_err::type_id::create("werr"); rerr = read_err::type_id::create("rerr"); rstdut = reset_dut::type_id::create("rstdut"); endfunction virtual task run_phase(uvm_phase phase); phase.raise_objection(this); wrrdb.start(e.a.seqr); #20; phase.drop_objection(this); endtask endclass ////////////////////////////////////////////////////////////////////// module tb; apb_if vif(); apb_ram dut (.presetn(vif.presetn), .pclk(vif.pclk), .psel(vif.psel), .penable(vif.penable), .pwrite(vif.pwrite), .paddr(vif.paddr), .pwdata(vif.pwdata), .prdata(vif.prdata), .pready(vif.pready), .pslverr(vif.pslverr)); initial begin vif.pclk <= 0; end always #10 vif.pclk <= ~vif.pclk; initial begin uvm_config_db#(virtual apb_if)::set(null, "*", "vif", vif); run_test("test"); end initial begin $dumpfile("dump.vcd"); $dumpvars; end endmodule