module dut (clk, rst_n, addr, w_data, r_data, data_valid, w_enable); input clk, rst_n; input [31:0] addr; input [15:0] w_data; input data_valid; input w_enable; output reg [15:0] r_data; reg [15:0] mem[3]; reg [15:0] data; // mem function to control data always @(posedge clk) begin if (!rst_n) begin data <= '0; end else if (mem[0]==4'ha) begin data <= 16'haabb; end else if (mem[1]==4'hb) begin data <= 16'hbbcc; end else if (mem[2]==4'hc) begin data <= 16'hccdd; end else begin data <= '1; end end // signal to control mem write always @(posedge clk) begin if(!rst_n) begin mem[0] <= '0; mem[1] <= '1; mem[2] <= 16'b0101_0101_0101_0101; end else if (data_valid && w_enable) begin case (addr) 32'h12345678: begin mem[0] <= w_data; end 32'h12345679: begin mem[1] <= w_data; end 32'h1234567a: begin end default: begin end endcase end end // signal to control mem read always @(posedge clk) begin if (!rst_n) begin r_data <= '0; end else if (data_valid && !w_enable) begin case (addr) 32'h12345678: begin r_data <= mem[0]; end 32'h12345679: begin r_data <= '1; end 32'h1234567a: begin r_data <= mem[2]; end default: begin end endcase end end endmodule
interface bus_ctl (input bit clk); // nets logic rst_n, data_valid, w_enable; logic [31:0] addr; logic [15:0] w_data, r_data; // clocking clocking testbench_cb @(posedge clk); output rst_n, data_valid, w_enable; output addr; output w_data; input r_data; endclocking: testbench_cb // modports modport my_testbench(clocking testbench_cb, output rst_n); endinterface: bus_ctl
`include "my_interface.sv" module test_top (); bit clk; bus_ctl bus_if(clk); dut dut_inst(.clk(clk), .rst_n(bus_if.rst_n), .addr(bus_if.addr), .w_data(bus_if.w_data), .r_data(bus_if.r_data), .data_valid(bus_if.data_valid), .w_enable(bus_if.w_enable)); test test_inst(bus_if); initial begin clk = 0; forever begin #1 clk = ~clk; end end endmodule program test (bus_ctl bus_if); import uvm_pkg::*; `include "testcase.sv" initial begin run_test("my_test"); end endprogram: test
`include "my_seqr.sv" `include "my_driver.sv" `include "reg_model.sv" class my_test extends uvm_test; `uvm_component_utils(my_test) virtual bus_ctl my_if; my_seq seq; my_driver drv; my_seqr seqr; my_block rm; my_block2 rm2; my_adapter adp; function new(string name="my_test", uvm_component parent); super.new(name, parent); endfunction: new function void build_phase(uvm_phase phase); super.build_phase(phase); drv = my_driver::type_id::create("drv", this); seqr = my_seqr::type_id::create("seqr", this); uvm_config_db#(virtual bus_ctl)::set(this, "drv", "bus_if", test_top.bus_if); rm=my_block::type_id::create("name", this); rm.configure(null, ""); rm.build(); rm.lock_model(); rm.reset(); rm.set_hdl_path_root("test_top.dut_inst"); rm2 = my_block2::type_id::create("rm2", this); rm2.configure(null, ""); rm2.build(); rm2.lock_model(); rm2.reset(); rm2.set_hdl_path_root("test_top"); adp = new("apt");//type_id? endfunction: build_phase function void connect_phase(uvm_phase phase); drv.seq_item_port.connect(seqr.seq_item_export); rm.default_map.set_sequencer(seqr, adp); rm.default_map.set_auto_predict(1); rm2.default_map.set_sequencer(seqr, adp); rm2.default_map.set_auto_predict(1); check_config_usage(); endfunction: connect_phase task run_phase(uvm_phase phase); uvm_status_e status; uvm_reg_data_t value; phase.raise_objection(this); seq = new("seq"); seq.start(seqr); `uvm_info("INFO_ID", $sformatf("---------------------------------------------"), UVM_LOW) rm.reg1.read(status, value, UVM_FRONTDOOR); `uvm_info("INFO_ID", $sformatf("get data value %h", value), UVM_LOW) value = 'hbcde; rm.reg1.write(status, value, UVM_FRONTDOOR); `uvm_info("INFO_ID", $sformatf("get data value %h", value), UVM_LOW) rm.reg1.read(status, value, UVM_FRONTDOOR); `uvm_info("INFO_ID", $sformatf("get data value %h", value), UVM_LOW) `uvm_info("INFO_ID", $sformatf("---------------------------------------------"), UVM_LOW) value = 'h2345; rm.reg1.write(status, value, UVM_BACKDOOR); rm.reg1.read(status, value, UVM_BACKDOOR); `uvm_info("INFO_ID_READBACKDOOR_2345", $sformatf("get data value %h", value), UVM_LOW) `uvm_info("INFO_ID", $sformatf("---------------------------------------------"), UVM_LOW) value = 'h5678; rm.reg1.poke(status, value); rm.reg1.peek(status, value); `uvm_info("INFO_ID_PEEK_5678", $sformatf("peek get data value %h", value), UVM_LOW) `uvm_info("INFO_ID", $sformatf("---------------------------------------------"), UVM_LOW) value = 'haabb; rm2.blk2.reg1.write(status, value, UVM_FRONTDOOR); rm2.blk2.reg1.read(status, value, UVM_FRONTDOOR); `uvm_info("INFO_ID_FRONT2_aabb", $sformatf("get data value %h", value), UVM_LOW) `uvm_info("INFO_ID", $sformatf("---------------------------------------------"), UVM_LOW) value = 'hacbc; rm2.blk2.reg1.poke(status, value); rm2.blk2.reg1.peek(status, value); `uvm_info("INFO_ID_PEEK2_acbc", $sformatf("get data value %h", value), UVM_LOW) `uvm_info("INFO_ID", $sformatf("---------------------------------------------"), UVM_LOW) phase.drop_objection(this); endtask: run_phase endclass: my_test
class my_driver extends uvm_driver#(my_trans); `uvm_component_utils(my_driver) virtual bus_ctl my_if; event start_drive; function new(string name="my_driver", uvm_component parent); super.new(name, parent); endfunction: new function void build_phase(uvm_phase phase); super.build_phase(phase); uvm_config_db#(virtual bus_ctl)::get(this, "", "bus_if", my_if); endfunction: build_phase task reset_phase(uvm_phase phase); phase.raise_objection(this); my_if.my_testbench.rst_n = 0; @(my_if.my_testbench.testbench_cb); my_if.my_testbench.rst_n = 1; @(my_if.my_testbench.testbench_cb); phase.drop_objection(this); -> start_drive; endtask: reset_phase task run_phase(uvm_phase phase); @(start_drive); while (1) begin seq_item_port.get_next_item(req); `uvm_info("DRIVER_GET", $sformatf("get data: %h, %h", req.address, req.data), UVM_LOW) drive(); seq_item_port.item_done(rsp); end endtask: run_phase task drive(); if(req.w_enable == 1) begin my_if.my_testbench.testbench_cb.w_data <= req.data; my_if.my_testbench.testbench_cb.addr <= req.address; my_if.my_testbench.testbench_cb.data_valid <= 1; my_if.my_testbench.testbench_cb.w_enable <= 1; @(my_if.my_testbench.testbench_cb); `uvm_info("DRIVER_WRITE", $sformatf("write: addr: %h, data: %h", req.address, req.data), UVM_LOW) end else begin my_if.my_testbench.testbench_cb.addr <= req.address; my_if.my_testbench.testbench_cb.data_valid <= 1; my_if.my_testbench.testbench_cb.w_enable <= 0; @(my_if.my_testbench.testbench_cb); req.data = my_if.r_data; `uvm_info("DRIVER_READ", $sformatf("read : addr: %h, data: %h", req.address, req.data), UVM_LOW) end endtask: drive endclass: my_driver
-常规内容
class my_trans extends uvm_sequence_item; `uvm_object_utils(my_trans) rand int address; rand bit [15:0] data; rand bit w_enable; function new(string name="my_trans"); super.new(name); endfunction: new endclass: my_trans class my_seq extends uvm_sequence#(my_trans); `uvm_object_utils(my_seq) function new(string name="my_seq"); super.new(name); endfunction: new task body(); req = new("req"); `uvm_do_with(req, {address==32'h12345678; data==16'habcd; w_enable=='1;}) `uvm_do_with(req, {address==32'h12345678; data==16'habcd; w_enable=='0;}) endtask: body endclass: my_seq typedef uvm_sequencer#(my_trans) my_seqr;
class my_reg extends uvm_reg; `uvm_object_utils(my_reg) uvm_reg_field reg_data; function new(string name="my_reg"); // width of reg, option super.new(name, 16, UVM_NO_COVERAGE); endfunction: new function void build(); reg_data = uvm_reg_field::type_id::create("reg1"); // parent, size, lsb_pos, access, volatile, reset value, has_reset, is_rand, individually accessible reg_data.configure(this, 16, 0, "RW", 1, 0, 1, 1, 0); endfunction: build endclass: my_reg class my_block extends uvm_reg_block; `uvm_object_utils(my_block) my_reg reg1; function new(string name="my_block"); super.new(name); endfunction: new function void build(); default_map = create_map("default_map", 0, 2, UVM_LITTLE_ENDIAN, 0); reg1 = my_reg::type_id::create("reg1");//get_full_name reg1.configure(this, null, "mem[0]"); reg1.build(); default_map.add_reg(reg1, 32'h12345678, "RW"); endfunction: build endclass: my_block class reg_file extends uvm_reg_file; `uvm_object_utils(reg_file) function new(string name="reg_file"); super.new(name); endfunction: new endclass: reg_file class my_block_sub extends uvm_reg_block; `uvm_object_utils(my_block_sub) my_reg reg1; rand reg_file file1; function new(string name="my_block"); super.new(name); endfunction: new function void build(); /* file1 = reg_file::type_id::create("file1", ,get_full_name()); */ file1 = reg_file::type_id::create("file1"); file1.configure(this, null, "dut_inst"); default_map = create_map("default_map", 0, 2, UVM_LITTLE_ENDIAN, 0); reg1 = my_reg::type_id::create("reg1"); reg1.configure(this, file1, "mem[0]"); reg1.build(); default_map.add_reg(reg1, 32'h8, "RW"); endfunction: build endclass: my_block_sub class my_block2 extends uvm_reg_block; `uvm_object_utils(my_block2) my_block_sub blk2; function new(string name="my_block2"); super.new(name); endfunction: new function void build(); default_map = create_map("default_map", 0, 2, UVM_LITTLE_ENDIAN, 0); blk2 = my_block_sub::type_id::create("blk2"); blk2.configure(this, ""); blk2.build(); default_map.add_submap(blk2.default_map, 32'h12345670); blk2.lock_model(); endfunction: build endclass: my_block2 class my_adapter extends uvm_reg_adapter; `uvm_object_utils(my_adapter) function new(string name="my_adapter"); super.new(name); endfunction: new function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); my_trans tr; tr = new("tr"); tr.address = rw.addr; tr.data = rw.data; tr.w_enable = rw.kind == UVM_WRITE ? 1:0; return tr; endfunction: reg2bus function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw); my_trans tr; $cast(tr, bus_item); rw.addr = tr.address; rw.kind = tr.w_enable == 1 ? UVM_WRITE:UVM_READ; rw.data = tr.data; rw.status = UVM_IS_OK; endfunction: bus2reg endclass: my_adapter