uvm通信-analysis_port使用示例2(完整uvm测试平台)
资料来源
(1) 《The UVM Primer》第16章
1.top.sv
1 module top; 2 import uvm_pkg::*; 3 import tinyalu_pkg::*; 4 `include "tinyalu_macros.svh" 5 `include "uvm_macros.svh" 6 7 tinyalu_bfm bfm(); 8 tinyalu DUT (.A(bfm.A), .B(bfm.B), .op(bfm.op), 9 .clk(bfm.clk), .reset_n(bfm.reset_n), 10 .start(bfm.start), .done(bfm.done), .result(bfm.result)); 11 12 13 initial begin 14 uvm_config_db #(virtual tinyalu_bfm)::set(null, "*", "bfm", bfm); 15 run_test(); 16 end 17 18 endmodule : top
2.tinyalu_pkg.sv
1 package tinyalu_pkg; 2 import uvm_pkg::*; 3 `include "uvm_macros.svh" 4 5 typedef enum bit[2:0] {no_op = 3'b000, 6 add_op = 3'b001, 7 and_op = 3'b010, 8 xor_op = 3'b011, 9 mul_op = 3'b100, 10 rst_op = 3'b111} operation_t; 11 12 13 typedef struct { 14 byte unsigned A; 15 byte unsigned B; 16 operation_t op; 17 } command_s; 18 19 20 21 22 `include "coverage.svh" 23 `include "base_tester.svh" 24 `include "random_tester.svh" 25 `include "add_tester.svh" 26 `include "scoreboard.svh" 27 `include "command_monitor.svh" 28 `include "result_monitor.svh" 29 30 `include "env.svh" 31 32 `include "random_test.svh" 33 `include "add_test.svh" 34 35 endpackage : tinyalu_pkg
3.tinyalu_bfm.sv
1 interface tinyalu_bfm; 2 import tinyalu_pkg::*; 3 4 command_monitor command_monitor_h; 5 result_monitor result_monitor_h; 6 7 byte unsigned A; 8 byte unsigned B; 9 bit clk; 10 bit reset_n; 11 wire [2:0] op; 12 bit start; 13 wire done; 14 wire [15:0] result; 15 operation_t op_set; 16 17 18 19 20 assign op = op_set; 21 22 task reset_alu(); 23 reset_n = 1'b0; 24 @(negedge clk); 25 @(negedge clk); 26 reset_n = 1'b1; 27 start = 1'b0; 28 endtask : reset_alu 29 30 31 32 task send_op(input byte iA, input byte iB, input operation_t iop, shortint result); 33 if (iop == rst_op) begin 34 @(posedge clk); 35 reset_n = 1'b0; 36 start = 1'b0; 37 @(posedge clk); 38 #1; 39 reset_n = 1'b1; 40 end else begin 41 @(negedge clk); 42 op_set = iop; 43 A = iA; 44 B = iB; 45 start = 1'b1; 46 if (iop == no_op) begin 47 @(posedge clk); 48 #1; 49 start = 1'b0; 50 end else begin 51 do 52 @(negedge clk); 53 while (done == 0); 54 start = 1'b0; 55 end 56 end // else: !if(iop == rst_op) 57 58 endtask : send_op 59 60 61 always @(posedge clk) begin : cmd_monitor 62 bit new_command; 63 if (!start) 64 new_command = 1; 65 else 66 if (new_command) begin 67 command_monitor_h.write_to_monitor(A, B, op); 68 new_command = (op == 3'b000); // handle no_op 69 end 70 end : cmd_monitor 71 72 always @(negedge reset_n) begin : rst_monitor 73 if (command_monitor_h != null) //guard against VCS time 0 negedge 74 command_monitor_h.write_to_monitor(A, B, rst_op); 75 end : rst_monitor 76 77 78 always @(posedge clk) begin : rslt_monitor 79 if (done) 80 result_monitor_h.write_to_monitor(result); 81 end : rslt_monitor 82 83 84 initial begin 85 clk = 0; 86 forever begin 87 #10; 88 clk = ~clk; 89 end 90 end 91 92 93 endinterface : tinyalu_bfm
4.random_test.svh
1 class random_test extends uvm_test; 2 `uvm_component_utils(random_test); 3 4 env env_h; 5 6 function new (string name, uvm_component parent); 7 super.new(name,parent); 8 endfunction : new 9 10 function void build_phase(uvm_phase phase); 11 env_h = env::type_id::create("env_h",this); 12 endfunction : build_phase 13 14 endclass
5.env.svh
1 class env extends uvm_env; 2 `uvm_component_utils(env); 3 4 random_tester random_tester_h; 5 coverage coverage_h; 6 scoreboard scoreboard_h; 7 command_monitor command_monitor_h; 8 result_monitor result_monitor_h; 9 10 function new (string name, uvm_component parent); 11 super.new(name,parent); 12 endfunction : new 13 14 function void build_phase(uvm_phase phase); 15 random_tester_h = random_tester::type_id::create("random_tester_h",this); 16 coverage_h = coverage::type_id::create ("coverage_h",this); 17 scoreboard_h = scoreboard::type_id::create("scoreboard_h",this); 18 command_monitor_h = command_monitor::type_id::create("command_monitor_h",this); 19 result_monitor_h= result_monitor::type_id::create("result_monitor_h",this); 20 21 22 endfunction : build_phase 23 24 function void connect_phase(uvm_phase phase); 25 26 result_monitor_h.ap.connect(scoreboard_h.analysis_export); 27 command_monitor_h.ap.connect(scoreboard_h.cmd_f.analysis_export); 28 command_monitor_h.ap.connect(coverage_h.analysis_export); 29 30 endfunction : connect_phase 31 32 endclass
6.random_test.svh
1 `ifdef QUESTA 2 virtual class base_tester extends uvm_component; 3 `else 4 class base_tester extends uvm_component; 5 `endif 6 7 `uvm_component_utils(base_tester) 8 virtual tinyalu_bfm bfm; 9 10 function void build_phase(uvm_phase phase); 11 12 if(!uvm_config_db #(virtual tinyalu_bfm)::get(null, "*","bfm", bfm)) 13 $fatal("Failed to get BFM"); 14 endfunction : build_phase 15 16 pure virtual function operation_t get_op(); 17 18 pure virtual function byte get_data(); 19 20 task run_phase(uvm_phase phase); 21 byte unsigned iA; 22 byte unsigned iB; 23 operation_t op_set; 24 shortint result; 25 26 phase.raise_objection(this); 27 bfm.reset_alu(); 28 repeat (1000) begin : random_loop 29 op_set = get_op(); 30 iA = get_data(); 31 iB = get_data(); 32 bfm.send_op(iA, iB, op_set, result); 33 end : random_loop 34 #500; 35 phase.drop_objection(this); 36 endtask : run_phase 37 38 39 function new (string name, uvm_component parent); 40 super.new(name, parent); 41 endfunction : new 42 43 endclass : base_tester 44 45 class random_tester extends base_tester; 46 `uvm_component_utils (random_tester) 47 48 function byte get_data(); 49 bit [1:0] zero_ones; 50 zero_ones = $random; 51 if (zero_ones == 2'b00) 52 return 8'h00; 53 else if (zero_ones == 2'b11) 54 return 8'hFF; 55 else 56 return $random; 57 endfunction : get_data 58 59 function operation_t get_op(); 60 bit [2:0] op_choice; 61 op_choice = $random; 62 case (op_choice) 63 3'b000 : return no_op; 64 3'b001 : return add_op; 65 3'b010 : return and_op; 66 3'b011 : return xor_op; 67 3'b100 : return mul_op; 68 3'b101 : return no_op; 69 3'b110 : return rst_op; 70 3'b111 : return rst_op; 71 endcase // case (op_choice) 72 endfunction : get_op 73 74 function new (string name, uvm_component parent); 75 super.new(name, parent); 76 endfunction : new 77 78 endclass : random_tester
7.command_monitor.svh
1 class command_monitor extends uvm_component; 2 `uvm_component_utils(command_monitor); 3 4 uvm_analysis_port #(command_s) ap; 5 6 function void build_phase(uvm_phase phase); 7 virtual tinyalu_bfm bfm; 8 9 if(!uvm_config_db #(virtual tinyalu_bfm)::get(null, "*","bfm", bfm)) 10 $fatal("Failed to get BFM"); 11 12 bfm.command_monitor_h = this; 13 14 ap = new("ap",this); 15 16 endfunction : build_phase 17 18 function void write_to_monitor(byte A, byte B, bit[2:0] op); 19 command_s cmd; 20 cmd.A = A; 21 cmd.B = B; 22 cmd.op = op2enum(op); 23 $display("COMMAND MONITOR: A:0x%2h B:0x%2h op: %s", A, B, cmd.op.name()); 24 ap.write(cmd); 25 endfunction : write_to_monitor 26 27 28 function operation_t op2enum(bit[2:0] op); 29 case(op) 30 3'b000 : return no_op; 31 3'b001 : return add_op; 32 3'b010 : return and_op; 33 3'b011 : return xor_op; 34 3'b100 : return mul_op; 35 3'b111 : return rst_op; 36 default : $fatal($sformatf("Illegal operation on op bus: %3b",op)); 37 endcase // case (op) 38 endfunction : op2enum 39 40 function new (string name, uvm_component parent); 41 super.new(name,parent); 42 endfunction 43 44 endclass : command_monitor
8.result_monitor.svh
1 class result_monitor extends uvm_component; 2 `uvm_component_utils(result_monitor); 3 4 uvm_analysis_port #(shortint) ap; 5 6 function void write_to_monitor(shortint r); 7 $display ("RESULT MONITOR: resultA: 0x%0h",r); 8 ap.write(r); 9 endfunction : write_to_monitor 10 11 function void build_phase(uvm_phase phase); 12 virtual tinyalu_bfm bfm; 13 if(!uvm_config_db #(virtual tinyalu_bfm)::get(null, "*","bfm", bfm)) 14 $fatal("Failed to get BFM"); 15 bfm.result_monitor_h = this; 16 ap = new("ap",this); 17 endfunction : build_phase 18 19 function new (string name, uvm_component parent); 20 super.new(name, parent); 21 endfunction : new 22 23 endclass : result_monitor
9.coverage.svh
1 class coverage extends uvm_subscriber #(command_s); 2 `uvm_component_utils(coverage) 3 4 byte unsigned A; 5 byte unsigned B; 6 operation_t op_set; 7 8 covergroup op_cov; 9 10 coverpoint op_set { 11 bins single_cycle[] = {[add_op : xor_op], rst_op,no_op}; 12 bins multi_cycle = {mul_op}; 13 14 bins opn_rst[] = ([add_op:mul_op] => rst_op); 15 bins rst_opn[] = (rst_op => [add_op:mul_op]); 16 17 bins sngl_mul[] = ([add_op:xor_op],no_op => mul_op); 18 bins mul_sngl[] = (mul_op => [add_op:xor_op], no_op); 19 20 bins twoops[] = ([add_op:mul_op] [* 2]); 21 bins manymult = (mul_op [* 3:5]); 22 23 bins rstmulrst = (rst_op => mul_op [= 2] => rst_op); 24 bins rstmulrstim = (rst_op => mul_op [-> 2] => rst_op); 25 26 } 27 28 endgroup 29 30 covergroup zeros_or_ones_on_ops; 31 32 all_ops : coverpoint op_set { 33 ignore_bins null_ops = {rst_op, no_op};} 34 35 a_leg: coverpoint A { 36 bins zeros = {'h00}; 37 bins others= {['h01:'hFE]}; 38 bins ones = {'hFF}; 39 } 40 41 b_leg: coverpoint B { 42 bins zeros = {'h00}; 43 bins others= {['h01:'hFE]}; 44 bins ones = {'hFF}; 45 } 46 47 op_00_FF: cross a_leg, b_leg, all_ops { 48 bins add_00 = binsof (all_ops) intersect {add_op} && 49 (binsof (a_leg.zeros) || binsof (b_leg.zeros)); 50 51 bins add_FF = binsof (all_ops) intersect {add_op} && 52 (binsof (a_leg.ones) || binsof (b_leg.ones)); 53 54 bins and_00 = binsof (all_ops) intersect {and_op} && 55 (binsof (a_leg.zeros) || binsof (b_leg.zeros)); 56 57 bins and_FF = binsof (all_ops) intersect {and_op} && 58 (binsof (a_leg.ones) || binsof (b_leg.ones)); 59 60 bins xor_00 = binsof (all_ops) intersect {xor_op} && 61 (binsof (a_leg.zeros) || binsof (b_leg.zeros)); 62 63 bins xor_FF = binsof (all_ops) intersect {xor_op} && 64 (binsof (a_leg.ones) || binsof (b_leg.ones)); 65 66 bins mul_00 = binsof (all_ops) intersect {mul_op} && 67 (binsof (a_leg.zeros) || binsof (b_leg.zeros)); 68 69 bins mul_FF = binsof (all_ops) intersect {mul_op} && 70 (binsof (a_leg.ones) || binsof (b_leg.ones)); 71 72 bins mul_max = binsof (all_ops) intersect {mul_op} && 73 (binsof (a_leg.ones) && binsof (b_leg.ones)); 74 75 ignore_bins others_only = 76 binsof(a_leg.others) && binsof(b_leg.others); 77 78 } 79 80 endgroup 81 82 83 function new (string name, uvm_component parent); 84 super.new(name, parent); 85 op_cov = new(); 86 zeros_or_ones_on_ops = new(); 87 endfunction : new 88 89 function void write(command_s t); 90 A = t.A; 91 B = t.B; 92 op_set = t.op; 93 op_cov.sample(); 94 zeros_or_ones_on_ops.sample(); 95 endfunction : write 96 97 endclass : coverage
10.scoreboard.svh
1 class scoreboard extends uvm_subscriber #(shortint); 2 `uvm_component_utils(scoreboard); 3 4 uvm_tlm_analysis_fifo #(command_s) cmd_f; 5 6 function void build_phase(uvm_phase phase); 7 cmd_f = new ("cmd_f", this); 8 endfunction : build_phase 9 10 function void write(shortint t); 11 shortint predicted_result; 12 command_s cmd; 13 cmd.op = no_op; 14 do 15 if (!cmd_f.try_get(cmd)) $fatal(1, "No command in self checker"); 16 while ((cmd.op == no_op) || (cmd.op == rst_op)); 17 18 case (cmd.op) 19 add_op: predicted_result = cmd.A + cmd.B; 20 and_op: predicted_result = cmd.A & cmd.B; 21 xor_op: predicted_result = cmd.A ^ cmd.B; 22 mul_op: predicted_result = cmd.A * cmd.B; 23 endcase // case (op_set) 24 25 if (predicted_result != t) 26 $error ( 27 "FAILED: A: %2h B: %2h op: %s actual result: %4h expected: %4h", 28 cmd.A, cmd.B, cmd.op.name(), t, predicted_result); 29 endfunction : write 30 31 32 function new (string name, uvm_component parent); 33 super.new(name, parent); 34 endfunction : new 35 36 endclass : scoreboard