| @@ -0,0 +1,707 @@ | |||
| `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 | |||