《The UVM Primer》11章-uvm_test示例
1.用UVM启动仿真
1.1 top.sv
注1:在run_test()语句前,先进行interface的config_db::set();
module top; import uvm_pkg::*; `include "uvm_macros.svh" import tinyalu_pkg::*; `include "tinyalu_macros.svh" tinyalu_bfm bfm(); tinyalu DUT (.A(bfm.A), .B(bfm.B), .op(bfm.op), .clk(bfm.clk), .reset_n(bfm.reset_n), .start(bfm.start), .done(bfm.done), .result(bfm.result)); initial begin uvm_config_db #(virtual tinyalu_bfm)::set(null, "*", "bfm", bfm); run_test(); end endmodule : top
1.2 tinyalu_pkg.sv
package tinyalu_pkg; import uvm_pkg::*; `include "uvm_macros.svh" typedef enum bit[2:0] {no_op = 3'b000, add_op = 3'b001, and_op = 3'b010, xor_op = 3'b011, mul_op = 3'b100, rst_op = 3'b111} operation_t; virtual tinyalu_bfm bfm_g; `include "coverage.svh" `include "random_tester.svh" `include "add_tester.svh" `include "scoreboard.svh" `include "random_test.svh" `include "add_test.svh" endpackage : tinyalu_pkg
1.3 tinyalu_bfm.sv
interface tinyalu_bfm; import tinyalu_pkg::*; byte unsigned A; byte unsigned B; bit clk; bit reset_n; wire [2:0] op; bit start; wire done; wire [15:0] result; operation_t op_set; assign op = op_set; task reset_alu(); reset_n = 1'b0; @(negedge clk); @(negedge clk); reset_n = 1'b1; start = 1'b0; endtask : reset_alu task send_op(input byte iA, input byte iB, input operation_t iop, shortint alu_result); if (iop == rst_op) begin @(negedge clk); op_set = iop; @(posedge clk); reset_n = 1'b0; start = 1'b0; @(posedge clk); #1; reset_n = 1'b1; end else begin @(negedge clk); op_set = iop; A = iA; B = iB; start = 1'b1; if (iop == no_op) begin @(posedge clk); #1; start = 1'b0; end else begin do @(negedge clk); while (done == 0); alu_result = result; start = 1'b0; end end // else: !if(iop == rst_op) endtask : send_op initial begin clk = 0; forever begin #10; clk = ~clk; end end endinterface : tinyalu_bfm
1.4 coverage.svh
class coverage; virtual tinyalu_bfm bfm; byte unsigned A; byte unsigned B; operation_t op_set; covergroup op_cov; coverpoint op_set { bins single_cycle[] = {[add_op : xor_op], rst_op,no_op}; bins multi_cycle = {mul_op}; bins opn_rst[] = ([add_op:mul_op] => rst_op); bins rst_opn[] = (rst_op => [add_op:mul_op]); bins sngl_mul[] = ([add_op:xor_op],no_op => mul_op); bins mul_sngl[] = (mul_op => [add_op:xor_op], no_op); bins twoops[] = ([add_op:mul_op] [* 2]); bins manymult = (mul_op [* 3:5]); } endgroup covergroup zeros_or_ones_on_ops; all_ops : coverpoint op_set { ignore_bins null_ops = {rst_op, no_op};} a_leg: coverpoint A { bins zeros = {'h00}; bins others= {['h01:'hFE]}; bins ones = {'hFF}; } b_leg: coverpoint B { bins zeros = {'h00}; bins others= {['h01:'hFE]}; bins ones = {'hFF}; } op_00_FF: cross a_leg, b_leg, all_ops { bins add_00 = binsof (all_ops) intersect {add_op} && (binsof (a_leg.zeros) || binsof (b_leg.zeros)); bins add_FF = binsof (all_ops) intersect {add_op} && (binsof (a_leg.ones) || binsof (b_leg.ones)); bins and_00 = binsof (all_ops) intersect {and_op} && (binsof (a_leg.zeros) || binsof (b_leg.zeros)); bins and_FF = binsof (all_ops) intersect {and_op} && (binsof (a_leg.ones) || binsof (b_leg.ones)); bins xor_00 = binsof (all_ops) intersect {xor_op} && (binsof (a_leg.zeros) || binsof (b_leg.zeros)); bins xor_FF = binsof (all_ops) intersect {xor_op} && (binsof (a_leg.ones) || binsof (b_leg.ones)); bins mul_00 = binsof (all_ops) intersect {mul_op} && (binsof (a_leg.zeros) || binsof (b_leg.zeros)); bins mul_FF = binsof (all_ops) intersect {mul_op} && (binsof (a_leg.ones) || binsof (b_leg.ones)); bins mul_max = binsof (all_ops) intersect {mul_op} && (binsof (a_leg.ones) && binsof (b_leg.ones)); ignore_bins others_only = binsof(a_leg.others) && binsof(b_leg.others); } endgroup function new (virtual tinyalu_bfm b); op_cov = new(); zeros_or_ones_on_ops = new(); bfm = b; endfunction : new task execute(); forever begin : sampling_block @(negedge bfm.clk); A = bfm.A; B = bfm.B; op_set = bfm.op_set; op_cov.sample(); zeros_or_ones_on_ops.sample(); end : sampling_block endtask : execute endclass : coverage
1.5 scoreboard.svh
class scoreboard; virtual tinyalu_bfm bfm; function new (virtual tinyalu_bfm b); bfm = b; endfunction : new task execute(); shortint predicted_result; forever begin : self_checker @(posedge bfm.done) #1; case (bfm.op_set) add_op: predicted_result = bfm.A + bfm.B; and_op: predicted_result = bfm.A & bfm.B; xor_op: predicted_result = bfm.A ^ bfm.B; mul_op: predicted_result = bfm.A * bfm.B; endcase // case (op_set) if ((bfm.op_set != no_op) && (bfm.op_set != rst_op)) if (predicted_result != bfm.result) $error ("FAILED: A: %0h B: %0h op: %s result: %0h", bfm.A, bfm.B, bfm.op_set.name(), bfm.result); end : self_checker endtask : execute endclass : scoreboard
1.6 random_tester.svh
class random_tester; virtual tinyalu_bfm bfm; function new (virtual tinyalu_bfm b); bfm = b; endfunction : new protected virtual function operation_t get_op(); bit [2:0] op_choice; op_choice = $random; case (op_choice) 3'b000 : return no_op; 3'b001 : return add_op; 3'b010 : return and_op; 3'b011 : return xor_op; 3'b100 : return mul_op; 3'b101 : return no_op; 3'b110 : return rst_op; 3'b111 : return rst_op; endcase // case (op_choice) endfunction : get_op protected virtual function byte get_data(); bit [1:0] zero_ones; zero_ones = $random; if (zero_ones == 2'b00) return 8'h00; else if (zero_ones == 2'b11) return 8'hFF; else return $random; endfunction : get_data virtual task execute(); byte unsigned iA; byte unsigned iB; operation_t op_set; shortint result; bfm.reset_alu(); repeat (1000) begin : random_loop op_set = get_op(); iA = get_data(); iB = get_data(); bfm.send_op(iA, iB, op_set, result); end : random_loop #500; endtask : execute endclass : random_tester
1.7 random_test.svh
class random_test extends uvm_test; `uvm_component_utils(random_test); virtual tinyalu_bfm bfm; function new (string name, uvm_component parent); super.new(name,parent); if(!uvm_config_db #(virtual tinyalu_bfm)::get(null, "*","bfm", bfm)) $fatal("Failed to get BFM"); endfunction : new task run_phase(uvm_phase phase); random_tester random_tester_h; coverage coverage_h; scoreboard scoreboard_h; phase.raise_objection(this); random_tester_h = new(bfm); coverage_h = new(bfm); scoreboard_h = new(bfm); fork coverage_h.execute(); scoreboard_h.execute(); join_none random_tester_h.execute(); phase.drop_objection(this); endtask : run_phase endclass