├── README.md ├── sv_verification_case ├── arb_pkg.sv ├── rpt_pkg.sv ├── Makefile ├── tb.sv ├── tb_ref.sv ├── reg_pkg.sv ├── chnl_pkg.sv ├── fmt_pkg.sv └── mcdf_pkg_ref.sv └── uvm_verification_case ├── param_def.v ├── arb_pkg.sv ├── Makefile ├── tb.sv ├── mcdf_rgm_pkg.sv ├── mcdf_rgm_pkg_ref.sv ├── chnl_pkg.sv ├── fmt_pkg.sv ├── reg_pkg.sv ├── mcdf_pkg.sv └── mcdf_pkg_ref.sv /README.md: -------------------------------------------------------------------------------- 1 | # digital_ic_verification 2 | -------------------------------------------------------------------------------- /sv_verification_case/arb_pkg.sv: -------------------------------------------------------------------------------- 1 | 2 | package arb_pkg; 3 | 4 | class arb_trans; 5 | // ... ignored 6 | endclass 7 | 8 | class arb_driver; 9 | // ... ignored 10 | endclass 11 | 12 | class arb_generator; 13 | // ... ignored 14 | endclass 15 | 16 | class arb_monitor; 17 | // ... ignored 18 | endclass 19 | 20 | class arb_agent; 21 | // ... ignored 22 | endclass 23 | endpackage 24 | -------------------------------------------------------------------------------- /uvm_verification_case/param_def.v: -------------------------------------------------------------------------------- 1 | 2 | `define ADDR_WIDTH 8 3 | `define CMD_DATA_WIDTH 32 4 | 5 | `define WRITE 2'b10 //Register operation command 6 | `define READ 2'b01 7 | `define IDLE 2'b00 8 | 9 | `define SLV0_RW_ADDR 8'h00 //Register address 10 | `define SLV1_RW_ADDR 8'h04 11 | `define SLV2_RW_ADDR 8'h08 12 | `define SLV0_R_ADDR 8'h10 13 | `define SLV1_R_ADDR 8'h14 14 | `define SLV2_R_ADDR 8'h18 15 | 16 | 17 | `define SLV0_RW_REG 0 18 | `define SLV1_RW_REG 1 19 | `define SLV2_RW_REG 2 20 | `define SLV0_R_REG 3 21 | `define SLV1_R_REG 4 22 | `define SLV2_R_REG 5 23 | 24 | `define FIFO_MARGIN_WIDTH 8 25 | 26 | `define PRIO_WIDTH 2 27 | `define PRIO_HIGH 2 28 | `define PRIO_LOW 1 29 | 30 | `define PAC_LEN_WIDTH 3 31 | `define PAC_LEN_HIGH 5 32 | `define PAC_LEN_LOW 3 33 | -------------------------------------------------------------------------------- /uvm_verification_case/arb_pkg.sv: -------------------------------------------------------------------------------- 1 | 2 | package arb_pkg; 3 | import uvm_pkg::*; 4 | `include "uvm_macros.svh" 5 | 6 | class arb_trans extends uvm_sequence_item; 7 | `uvm_object_utils(arb_trans) 8 | // new - constructor 9 | function new (string name = "template_transfer_inst"); 10 | super.new(name); 11 | endfunction 12 | // ... ignored 13 | endclass 14 | 15 | class arb_driver extends uvm_driver #(arb_trans); 16 | `uvm_component_utils(arb_driver) 17 | function new (string name = "arb_driver", uvm_component parent); 18 | super.new(name, parent); 19 | endfunction 20 | // ... ignored 21 | endclass 22 | 23 | class arb_sequencer extends uvm_sequencer #(arb_trans); 24 | `uvm_component_utils(arb_sequencer) 25 | function new (string name = "arb_sequencer", uvm_component parent); 26 | super.new(name, parent); 27 | endfunction 28 | // ... ignored 29 | endclass 30 | 31 | class arb_monitor extends uvm_monitor; 32 | `uvm_component_utils(arb_monitor) 33 | function new (string name = "arb_monitor", uvm_component parent); 34 | super.new(name, parent); 35 | endfunction 36 | // ... ignored 37 | endclass 38 | 39 | class arb_agent extends uvm_agent; 40 | `uvm_component_utils(arb_agent) 41 | function new (string name = "arb_agent", uvm_component parent); 42 | super.new(name, parent); 43 | endfunction 44 | // ... ignored 45 | endclass 46 | endpackage 47 | -------------------------------------------------------------------------------- /uvm_verification_case/Makefile: -------------------------------------------------------------------------------- 1 | ############################# 2 | # User variables 3 | ############################# 4 | all:clean comp elab run 5 | 6 | TB = tb 7 | SEED = 1 8 | TESTNAME ?= mcdf_data_consistence_basic_test 9 | DFILES = ../mcdf/{arbiter.v,slave_fifo.v,reg.v,formater.v,mcdf.v} 10 | VFILES += arb_pkg.sv chnl_pkg.sv fmt_pkg.sv reg_pkg.sv mcdf_rgm_pkg.sv mcdf_pkg.sv $(TB).sv 11 | 12 | 13 | ############################# 14 | # Environment variables 15 | ############################# 16 | VCOMP = vlogan -full64 -ntb_opts uvm-1.1 -sverilog -timescale=1ps/1ps -nc -l comp.log +incdir+../mcdf 17 | ELAB = vcs -full64 -ntb_opts uvm-1.1 -debug_all -l elab.log -sim_res=1ps -cm line+tgl+branch -cm_hier cm.cfg\ 18 | -cpp g++-4.8 -cc gcc-4.8 -LDFLAGS -Wl,--no-as-needed 19 | RUN = ./$(TB).simv -l run.log -sml -cm line+tgl+branch -cm_name $(TB)_$(SEED) +ntb_random_seed=$(SEED) +UVM_TESTNAME=$(TESTNAME) 20 | 21 | comp: 22 | $(VCOMP) 23 | $(VCOMP) $(DFILES) $(VFILES) 24 | 25 | elab: comp 26 | $(ELAB) -top $(TB) -o $(TB).simv 27 | 28 | run: 29 | $(RUN) 30 | 31 | rung: 32 | $(RUN) -gui 33 | 34 | editcov: 35 | urg -full64 -format both -dir $(TB).simv.vdb 36 | dve -cov -dir $(TB).simv.vdb 37 | 38 | # option for exlucde file given to generate coverage report 39 | # if there is such a coverage exclusion file 40 | # urg -dir ... -elfile filename.el 41 | viewcov: 42 | urg -full64 -format both -dir $(TB).simv.vdb 43 | firefox urgReport/dashboard.html 44 | 45 | clean: 46 | rm -rf AN.DB DVEfiles csrc *.simv *.simv.daidir *.simv.vdb ucli.key 47 | rm -rf *.log* *.vpd *.h urgReport 48 | 49 | -------------------------------------------------------------------------------- /sv_verification_case/rpt_pkg.sv: -------------------------------------------------------------------------------- 1 | 2 | 3 | package rpt_pkg; 4 | typedef enum {INFO, WARNING, ERROR, FATAL} report_t; 5 | typedef enum {LOW, MEDIUM, HIGH, TOP} severity_t; 6 | typedef enum {LOG, STOP, EXIT} action_t; 7 | 8 | static severity_t svrt = LOW; 9 | static string logname = "report.log"; 10 | static int info_count = 0; 11 | static int warning_count = 0; 12 | static int error_count = 0; 13 | static int fatal_count = 0; 14 | 15 | function void rpt_msg(string src, string i, report_t r=INFO, severity_t s=LOW, action_t a=LOG); 16 | integer logf; 17 | string msg; 18 | case(r) 19 | INFO: info_count++; 20 | WARNING: warning_count++; 21 | ERROR: error_count++; 22 | FATAL: fatal_count++; 23 | endcase 24 | if(s >= svrt) begin 25 | msg = $sformatf("@%0t [%s] %s : %s", $time, r, src, i); 26 | logf = $fopen(logname, "a+"); 27 | $display(msg); 28 | $fwrite(logf, $sformatf("%s\n", msg)); 29 | $fclose(logf); 30 | if(a == STOP) begin 31 | $stop(); 32 | end 33 | else if(a == EXIT) begin 34 | $finish(); 35 | end 36 | end 37 | endfunction 38 | 39 | function void do_report(); 40 | string s; 41 | s = "\n---------------------------------------------------------------\n"; 42 | s = {s, "REPORT SUMMARY\n"}; 43 | s = {s, $sformatf("info count: %0d \n", info_count)}; 44 | s = {s, $sformatf("warning count: %0d \n", warning_count)}; 45 | s = {s, $sformatf("error count: %0d \n", error_count)}; 46 | s = {s, $sformatf("fatal count: %0d \n", fatal_count)}; 47 | s = {s, "---------------------------------------------------------------\n"}; 48 | rpt_msg("[REPORT]", s, rpt_pkg::INFO, rpt_pkg::TOP); 49 | endfunction 50 | 51 | function void clean_log(); 52 | integer logf; 53 | logf = $fopen(logname, "w"); 54 | $fclose(logf); 55 | endfunction 56 | endpackage 57 | -------------------------------------------------------------------------------- /sv_verification_case/Makefile: -------------------------------------------------------------------------------- 1 | ############################# 2 | # User variables 3 | ############################# 4 | all:comp elab run 5 | 6 | TB = tb_ref 7 | SEED = 1 8 | TESTNAME ?= mcdf_down_stream_low_bandwidth_test 9 | DFILES = ../mcdf/v0/{arbiter.v,slave_fifo.v,reg.v,formater.v,mcdf.v} 10 | VFILES += rpt_pkg.sv arb_pkg.sv chnl_pkg.sv fmt_pkg.sv reg_pkg.sv mcdf_pkg_ref.sv $(TB).sv 11 | 12 | #code coverage command 13 | CM = -cm line+cond+fsm+branch+tgl#设置覆盖率检测 14 | CM_NAME = -cm_name $(TB)_$(SEED)_$(TESTNAME)#覆盖率名字 15 | CM_DIR = -cm_dir ./$(TB).simv.vdb 16 | 17 | #generate fsdb file 18 | FSDB = -fsdb +define+FSDB 19 | 20 | #generate vdp file 21 | VDP = +vcs+vcdpluson 22 | 23 | ############################# 24 | # Environment variables 25 | ############################# 26 | VCOMP = vlogan -full64 -sverilog -timescale=1ps/1ps -nc -l comp.log +incdir+../mcdf/v0 27 | 28 | ELAB = vcs -full64 -cpp g++-4.8 -cc gcc-4.8 -LDFLAGS -Wl,--no-as-needed\ 29 | -debug_all\ 30 | -l elab.log -sim_res=1ps\ 31 | $(CM) -cm_hier cm.cfg 32 | 33 | RUN = ./$(TB).simv\ 34 | $(CM) $(CM_NAME)\ 35 | +ntb_random_seed=$(SEED)\ 36 | +TESTNAME=$(TESTNAME)\ 37 | -l run.log -sml 38 | 39 | #start compile 40 | comp: 41 | $(VCOMP) $(DFILES) $(VFILES) 42 | 43 | elab: 44 | $(ELAB) -top $(TB) -o $(TB).simv 45 | #start simulation 46 | 47 | run: 48 | $(RUN) 49 | 50 | rung: 51 | $(RUN) -gui 52 | 53 | editcov: 54 | urg -full64 -format both -dir $(TB).simv.vdb 55 | dve -full64 -cov -dir $(TB).simv.vdb 56 | 57 | # option for exlucde file given to generate coverage report 58 | # if there is such a coverage exclusion file 59 | # urg -dir ... -elfile filename.el 60 | viewcov: 61 | urg -full64 -format both -dir $(TB).simv.vdb 62 | firefox urgReport/dashboard.html 63 | 64 | mergecov: 65 | urg -full64 -dir ./$(TB).simv.vdb -dbname mergedir/merged 66 | 67 | clean: 68 | rm -rf AN.DB DVEfiles csrc *.simv *.simv.daidir *.simv.vdb ucli.key 69 | rm -rf *.log* *.vpd urgReport 70 | -------------------------------------------------------------------------------- /sv_verification_case/tb.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ps 2 | 3 | `include "param_def.v" 4 | 5 | interface chnl_intf(input clk, input rstn); 6 | logic [31:0] ch_data; 7 | logic ch_valid; 8 | logic ch_ready; 9 | clocking drv_ck @(posedge clk); 10 | default input #1ns output #1ns; 11 | output ch_data, ch_valid; 12 | input ch_ready; 13 | endclocking 14 | clocking mon_ck @(posedge clk); 15 | default input #1ns output #1ns; 16 | input ch_data, ch_valid, ch_ready; 17 | endclocking 18 | endinterface 19 | 20 | interface reg_intf(input clk, input rstn); 21 | logic [1:0] cmd; 22 | logic [`ADDR_WIDTH-1:0] cmd_addr; 23 | logic [`CMD_DATA_WIDTH-1:0] cmd_data_s2m; 24 | logic [`CMD_DATA_WIDTH-1:0] cmd_data_m2s; 25 | clocking drv_ck @(posedge clk); 26 | default input #1ns output #1ns; 27 | output cmd, cmd_addr, cmd_data_m2s; 28 | input cmd_data_s2m; 29 | endclocking 30 | clocking mon_ck @(posedge clk); 31 | default input #1ns output #1ns; 32 | input cmd, cmd_addr, cmd_data_m2s, cmd_data_s2m; 33 | endclocking 34 | endinterface 35 | 36 | interface arb_intf(input clk, input rstn); 37 | logic [1:0] slv_prios[3]; 38 | logic slv_reqs[3]; 39 | logic a2s_acks[3]; 40 | logic f2a_id_req; 41 | clocking mon_ck @(posedge clk); 42 | default input #1ns output #1ns; 43 | input slv_prios, slv_reqs, a2s_acks, f2a_id_req; 44 | endclocking 45 | endinterface 46 | 47 | interface fmt_intf(input clk, input rstn); 48 | logic fmt_grant; 49 | logic [1:0] fmt_chid; 50 | logic fmt_req; 51 | logic [5:0] fmt_length; 52 | logic [31:0] fmt_data; 53 | logic fmt_start; 54 | logic fmt_end; 55 | clocking drv_ck @(posedge clk); 56 | default input #1ns output #1ns; 57 | input fmt_chid, fmt_req, fmt_length, fmt_data, fmt_start; 58 | output fmt_grant; 59 | endclocking 60 | clocking mon_ck @(posedge clk); 61 | default input #1ns output #1ns; 62 | input fmt_grant, fmt_chid, fmt_req, fmt_length, fmt_data, fmt_start; 63 | endclocking 64 | endinterface 65 | 66 | interface mcdf_intf(input clk, input rstn); 67 | // USER TODO 68 | // To define those signals which do not exsit in 69 | // reg_if, chnl_if, arb_if or fmt_if 70 | logic chnl_en[3]; 71 | 72 | 73 | clocking mon_ck @(posedge clk); 74 | default input #1ns output #1ns; 75 | input chnl_en; 76 | endclocking 77 | endinterface 78 | 79 | module tb; 80 | logic clk; 81 | logic rstn; 82 | 83 | mcdf dut( 84 | .clk_i (clk ) 85 | ,.rstn_i (rstn ) 86 | ,.cmd_i (reg_if.cmd ) 87 | ,.cmd_addr_i (reg_if.cmd_addr ) 88 | ,.cmd_data_i (reg_if.cmd_data_m2s) 89 | ,.cmd_data_o (reg_if.cmd_data_s2m) 90 | ,.ch0_data_i (chnl0_if.ch_data ) 91 | ,.ch0_vld_i (chnl0_if.ch_valid ) 92 | ,.ch0_ready_o (chnl0_if.ch_ready ) 93 | ,.ch1_data_i (chnl1_if.ch_data ) 94 | ,.ch1_vld_i (chnl1_if.ch_valid ) 95 | ,.ch1_ready_o (chnl1_if.ch_ready ) 96 | ,.ch2_data_i (chnl2_if.ch_data ) 97 | ,.ch2_vld_i (chnl2_if.ch_valid ) 98 | ,.ch2_ready_o (chnl2_if.ch_ready ) 99 | ,.fmt_grant_i (fmt_if.fmt_grant ) 100 | ,.fmt_chid_o (fmt_if.fmt_chid ) 101 | ,.fmt_req_o (fmt_if.fmt_req ) 102 | ,.fmt_length_o(fmt_if.fmt_length ) 103 | ,.fmt_data_o (fmt_if.fmt_data ) 104 | ,.fmt_start_o (fmt_if.fmt_start ) 105 | ,.fmt_end_o (fmt_if.fmt_end ) 106 | ); 107 | 108 | // clock generation 109 | initial begin 110 | clk <= 0; 111 | forever begin 112 | #5 clk <= !clk; 113 | end 114 | end 115 | 116 | // reset trigger 117 | initial begin 118 | #10 rstn <= 0; 119 | repeat(10) @(posedge clk); 120 | rstn <= 1; 121 | end 122 | 123 | import chnl_pkg::*; 124 | import reg_pkg::*; 125 | import arb_pkg::*; 126 | import fmt_pkg::*; 127 | import mcdf_pkg::*; 128 | 129 | reg_intf reg_if(.*); 130 | chnl_intf chnl0_if(.*); 131 | chnl_intf chnl1_if(.*); 132 | chnl_intf chnl2_if(.*); 133 | arb_intf arb_if(.*); 134 | fmt_intf fmt_if(.*); 135 | mcdf_intf mcdf_if(.*); 136 | 137 | // mcdf interface monitoring MCDF ports and signals 138 | assign mcdf_if.chnl_en[0] = tb.dut.ctrl_regs_inst.slv0_en_o; 139 | assign mcdf_if.chnl_en[1] = tb.dut.ctrl_regs_inst.slv1_en_o; 140 | assign mcdf_if.chnl_en[2] = tb.dut.ctrl_regs_inst.slv2_en_o; 141 | 142 | // arbiter interface monitoring arbiter ports 143 | assign arb_if.slv_prios[0] = tb.dut.arbiter_inst.slv0_prio_i; 144 | assign arb_if.slv_prios[1] = tb.dut.arbiter_inst.slv1_prio_i; 145 | assign arb_if.slv_prios[2] = tb.dut.arbiter_inst.slv2_prio_i; 146 | assign arb_if.slv_reqs[0] = tb.dut.arbiter_inst.slv0_req_i; 147 | assign arb_if.slv_reqs[1] = tb.dut.arbiter_inst.slv1_req_i; 148 | assign arb_if.slv_reqs[2] = tb.dut.arbiter_inst.slv2_req_i; 149 | assign arb_if.a2s_acks[0] = tb.dut.arbiter_inst.a2s0_ack_o; 150 | assign arb_if.a2s_acks[1] = tb.dut.arbiter_inst.a2s1_ack_o; 151 | assign arb_if.a2s_acks[2] = tb.dut.arbiter_inst.a2s2_ack_o; 152 | assign arb_if.f2a_id_req = tb.dut.arbiter_inst.f2a_id_req_i; 153 | 154 | mcdf_data_consistence_basic_test t1; 155 | mcdf_full_random_test t2; 156 | mcdf_base_test tests[string]; 157 | string name; 158 | 159 | initial begin 160 | t1 = new(); 161 | t2 = new(); 162 | tests["mcdf_data_consistence_basic_test"] = t1; 163 | tests["mcdf_full_random_test"] = t2; 164 | if($value$plusargs("TESTNAME=%s", name)) begin 165 | if(tests.exists(name)) begin 166 | tests[name].set_interface(chnl0_if, chnl1_if, chnl2_if, reg_if, arb_if, fmt_if, mcdf_if); 167 | tests[name].run(); 168 | end 169 | else begin 170 | $fatal($sformatf("[ERRTEST], test name %s is invalid, please specify a valid name!", name)); 171 | end 172 | end 173 | else begin 174 | $display("NO runtime optiont +TESTNAME=xxx is configured, and run default test mcdf_data_consistence_basic_test"); 175 | tests["mcdf_data_consistence_basic_test"].set_interface(chnl0_if, chnl1_if, chnl2_if, reg_if, arb_if, fmt_if, mcdf_if); 176 | tests["mcdf_data_consistence_basic_test"].run(); 177 | end 178 | end 179 | endmodule 180 | 181 | -------------------------------------------------------------------------------- /uvm_verification_case/tb.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ps 2 | 3 | `include "param_def.v" 4 | 5 | interface chnl_intf(input clk, input rstn); 6 | logic [31:0] ch_data; 7 | logic ch_valid; 8 | logic ch_ready; 9 | clocking drv_ck @(posedge clk); 10 | default input #1ns output #1ns; 11 | output ch_data, ch_valid; 12 | input ch_ready; 13 | endclocking 14 | clocking mon_ck @(posedge clk); 15 | default input #1ns output #1ns; 16 | input ch_data, ch_valid, ch_ready; 17 | endclocking 18 | endinterface 19 | 20 | interface reg_intf(input clk, input rstn); 21 | logic [1:0] cmd; 22 | logic [`ADDR_WIDTH-1:0] cmd_addr; 23 | logic [`CMD_DATA_WIDTH-1:0] cmd_data_s2m; 24 | logic [`CMD_DATA_WIDTH-1:0] cmd_data_m2s; 25 | clocking drv_ck @(posedge clk); 26 | default input #1ns output #1ns; 27 | output cmd, cmd_addr, cmd_data_m2s; 28 | input cmd_data_s2m; 29 | endclocking 30 | clocking mon_ck @(posedge clk); 31 | default input #1ns output #1ns; 32 | input cmd, cmd_addr, cmd_data_m2s, cmd_data_s2m; 33 | endclocking 34 | endinterface 35 | 36 | interface arb_intf(input clk, input rstn); 37 | logic [1:0] slv_prios[3]; 38 | logic slv_reqs[3]; 39 | logic a2s_acks[3]; 40 | logic f2a_id_req; 41 | clocking mon_ck @(posedge clk); 42 | default input #1ns output #1ns; 43 | input slv_prios, slv_reqs, a2s_acks, f2a_id_req; 44 | endclocking 45 | endinterface 46 | 47 | interface fmt_intf(input clk, input rstn); 48 | logic fmt_grant; 49 | logic [1:0] fmt_chid; 50 | logic fmt_req; 51 | logic [5:0] fmt_length; 52 | logic [31:0] fmt_data; 53 | logic fmt_start; 54 | logic fmt_end; 55 | clocking drv_ck @(posedge clk); 56 | default input #1ns output #1ns; 57 | input fmt_chid, fmt_req, fmt_length, fmt_data, fmt_start; 58 | output fmt_grant; 59 | endclocking 60 | clocking mon_ck @(posedge clk); 61 | default input #1ns output #1ns; 62 | input fmt_grant, fmt_chid, fmt_req, fmt_length, fmt_data, fmt_start; 63 | endclocking 64 | endinterface 65 | 66 | interface mcdf_intf(output logic clk, output logic rstn); 67 | // USER TODO 68 | // To define those signals which do not exsit in 69 | // reg_if, chnl_if, arb_if or fmt_if 70 | logic chnl_en[3]; 71 | 72 | clocking mon_ck @(posedge clk); 73 | default input #1ns output #1ns; 74 | input chnl_en; 75 | endclocking 76 | 77 | // clock generation 78 | initial begin 79 | clk <= 0; 80 | forever begin 81 | #5 clk <= !clk; 82 | end 83 | end 84 | 85 | // reset trigger 86 | initial begin 87 | #10 rstn <= 0; 88 | repeat(10) @(posedge clk); 89 | rstn <= 1; 90 | end 91 | endinterface 92 | 93 | module tb; 94 | logic clk; 95 | logic rstn; 96 | 97 | mcdf dut( 98 | .clk_i (clk ) 99 | ,.rstn_i (rstn ) 100 | ,.cmd_i (reg_if.cmd ) 101 | ,.cmd_addr_i (reg_if.cmd_addr ) 102 | ,.cmd_data_i (reg_if.cmd_data_m2s) 103 | ,.cmd_data_o (reg_if.cmd_data_s2m) 104 | ,.ch0_data_i (chnl0_if.ch_data ) 105 | ,.ch0_vld_i (chnl0_if.ch_valid ) 106 | ,.ch0_ready_o (chnl0_if.ch_ready ) 107 | ,.ch1_data_i (chnl1_if.ch_data ) 108 | ,.ch1_vld_i (chnl1_if.ch_valid ) 109 | ,.ch1_ready_o (chnl1_if.ch_ready ) 110 | ,.ch2_data_i (chnl2_if.ch_data ) 111 | ,.ch2_vld_i (chnl2_if.ch_valid ) 112 | ,.ch2_ready_o (chnl2_if.ch_ready ) 113 | ,.fmt_grant_i (fmt_if.fmt_grant ) 114 | ,.fmt_chid_o (fmt_if.fmt_chid ) 115 | ,.fmt_req_o (fmt_if.fmt_req ) 116 | ,.fmt_length_o(fmt_if.fmt_length ) 117 | ,.fmt_data_o (fmt_if.fmt_data ) 118 | ,.fmt_start_o (fmt_if.fmt_start ) 119 | ,.fmt_end_o (fmt_if.fmt_end ) 120 | ); 121 | 122 | 123 | import uvm_pkg::*; 124 | `include "uvm_macros.svh" 125 | import chnl_pkg::*; 126 | import reg_pkg::*; 127 | import arb_pkg::*; 128 | import fmt_pkg::*; 129 | import mcdf_pkg::*; 130 | 131 | reg_intf reg_if(.*); 132 | chnl_intf chnl0_if(.*); 133 | chnl_intf chnl1_if(.*); 134 | chnl_intf chnl2_if(.*); 135 | arb_intf arb_if(.*); 136 | fmt_intf fmt_if(.*); 137 | mcdf_intf mcdf_if(.*); 138 | 139 | // mcdf interface monitoring MCDF ports and signals 140 | assign mcdf_if.chnl_en[0] = tb.dut.ctrl_regs_inst.slv0_en_o; 141 | assign mcdf_if.chnl_en[1] = tb.dut.ctrl_regs_inst.slv1_en_o; 142 | assign mcdf_if.chnl_en[2] = tb.dut.ctrl_regs_inst.slv2_en_o; 143 | 144 | // arbiter interface monitoring arbiter ports 145 | assign arb_if.slv_prios[0] = tb.dut.arbiter_inst.slv0_prio_i; 146 | assign arb_if.slv_prios[1] = tb.dut.arbiter_inst.slv1_prio_i; 147 | assign arb_if.slv_prios[2] = tb.dut.arbiter_inst.slv2_prio_i; 148 | assign arb_if.slv_reqs[0] = tb.dut.arbiter_inst.slv0_req_i; 149 | assign arb_if.slv_reqs[1] = tb.dut.arbiter_inst.slv1_req_i; 150 | assign arb_if.slv_reqs[2] = tb.dut.arbiter_inst.slv2_req_i; 151 | assign arb_if.a2s_acks[0] = tb.dut.arbiter_inst.a2s0_ack_o; 152 | assign arb_if.a2s_acks[1] = tb.dut.arbiter_inst.a2s1_ack_o; 153 | assign arb_if.a2s_acks[2] = tb.dut.arbiter_inst.a2s2_ack_o; 154 | assign arb_if.f2a_id_req = tb.dut.arbiter_inst.f2a_id_req_i; 155 | 156 | initial begin 157 | // do interface configuration from top tb (HW) to verification env (SW) 158 | // 若传送的是句柄类型,需保证set/get传递的类型严格一致:若set是子类的类型,get是父类的类型,需要通过$cast进行类型转换后再进行传递 159 | uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top", "ch0_vif", chnl0_if); 160 | uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top", "ch1_vif", chnl1_if); 161 | uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top", "ch2_vif", chnl2_if); 162 | uvm_config_db#(virtual reg_intf)::set(uvm_root::get(), "uvm_test_top", "reg_vif", reg_if); 163 | uvm_config_db#(virtual arb_intf)::set(uvm_root::get(), "uvm_test_top", "arb_vif", arb_if); 164 | uvm_config_db#(virtual fmt_intf)::set(uvm_root::get(), "uvm_test_top", "fmt_vif", fmt_if); 165 | uvm_config_db#(virtual mcdf_intf)::set(uvm_root::get(), "uvm_test_top", "mcdf_vif", mcdf_if); 166 | // If no external configured via +UVM_TESTNAME=my_test, the default test is 167 | // mcdf_data_consistence_basic_test 168 | run_test("mcdf_data_consistence_basic_test"); 169 | end 170 | endmodule 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /sv_verification_case/tb_ref.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ps 2 | 3 | `include "param_def.v" 4 | 5 | interface chnl_intf(input clk, input rstn); 6 | logic [31:0] ch_data; 7 | logic ch_valid; 8 | logic ch_ready; 9 | clocking drv_ck @(posedge clk); 10 | default input #1ns output #1ns; 11 | output ch_data, ch_valid; 12 | input ch_ready; 13 | endclocking 14 | clocking mon_ck @(posedge clk); 15 | default input #1ns output #1ns; 16 | input ch_data, ch_valid, ch_ready; 17 | endclocking 18 | endinterface 19 | 20 | interface reg_intf(input clk, input rstn); 21 | logic [1:0] cmd; 22 | logic [`ADDR_WIDTH-1:0] cmd_addr; 23 | logic [`CMD_DATA_WIDTH-1:0] cmd_data_s2m; 24 | logic [`CMD_DATA_WIDTH-1:0] cmd_data_m2s; 25 | clocking drv_ck @(posedge clk); 26 | default input #1ns output #1ns; 27 | output cmd, cmd_addr, cmd_data_m2s; 28 | input cmd_data_s2m; 29 | endclocking 30 | clocking mon_ck @(posedge clk); 31 | default input #1ns output #1ns; 32 | input cmd, cmd_addr, cmd_data_m2s, cmd_data_s2m; 33 | endclocking 34 | endinterface 35 | 36 | interface arb_intf(input clk, input rstn); 37 | logic [1:0] slv_prios[3]; 38 | logic slv_reqs[3]; 39 | logic a2s_acks[3]; 40 | logic f2a_id_req; 41 | clocking mon_ck @(posedge clk); 42 | default input #1ns output #1ns; 43 | input slv_prios, slv_reqs, a2s_acks, f2a_id_req; 44 | endclocking 45 | endinterface 46 | 47 | interface fmt_intf(input clk, input rstn); 48 | logic fmt_grant; 49 | logic [1:0] fmt_chid; 50 | logic fmt_req; 51 | logic [5:0] fmt_length; 52 | logic [31:0] fmt_data; 53 | logic fmt_start; 54 | logic fmt_end; 55 | clocking drv_ck @(posedge clk); 56 | default input #1ns output #1ns; 57 | input fmt_chid, fmt_req, fmt_length, fmt_data, fmt_start; 58 | output fmt_grant; 59 | endclocking 60 | clocking mon_ck @(posedge clk); 61 | default input #1ns output #1ns; 62 | input fmt_grant, fmt_chid, fmt_req, fmt_length, fmt_data, fmt_start; 63 | endclocking 64 | endinterface 65 | 66 | interface mcdf_intf(input clk, input rstn); 67 | // USER TODO 68 | // To define those signals which do not exsit in 69 | // reg_if, chnl_if, arb_if or fmt_if 70 | logic chnl_en[3]; 71 | 72 | 73 | clocking mon_ck @(posedge clk); 74 | default input #1ns output #1ns; 75 | input chnl_en; 76 | endclocking 77 | endinterface 78 | 79 | module tb; 80 | logic clk; 81 | logic rstn; 82 | 83 | mcdf dut( 84 | .clk_i (clk ) 85 | ,.rstn_i (rstn ) 86 | ,.cmd_i (reg_if.cmd ) 87 | ,.cmd_addr_i (reg_if.cmd_addr ) 88 | ,.cmd_data_i (reg_if.cmd_data_m2s) 89 | ,.cmd_data_o (reg_if.cmd_data_s2m) 90 | ,.ch0_data_i (chnl0_if.ch_data ) 91 | ,.ch0_vld_i (chnl0_if.ch_valid ) 92 | ,.ch0_ready_o (chnl0_if.ch_ready ) 93 | ,.ch1_data_i (chnl1_if.ch_data ) 94 | ,.ch1_vld_i (chnl1_if.ch_valid ) 95 | ,.ch1_ready_o (chnl1_if.ch_ready ) 96 | ,.ch2_data_i (chnl2_if.ch_data ) 97 | ,.ch2_vld_i (chnl2_if.ch_valid ) 98 | ,.ch2_ready_o (chnl2_if.ch_ready ) 99 | ,.fmt_grant_i (fmt_if.fmt_grant ) 100 | ,.fmt_chid_o (fmt_if.fmt_chid ) 101 | ,.fmt_req_o (fmt_if.fmt_req ) 102 | ,.fmt_length_o(fmt_if.fmt_length ) 103 | ,.fmt_data_o (fmt_if.fmt_data ) 104 | ,.fmt_start_o (fmt_if.fmt_start ) 105 | ,.fmt_end_o (fmt_if.fmt_end ) 106 | ); 107 | 108 | // clock generation 109 | initial begin 110 | clk <= 0; 111 | forever begin 112 | #5 clk <= !clk; 113 | end 114 | end 115 | 116 | // reset trigger 117 | initial begin 118 | #10 rstn <= 0; 119 | repeat(10) @(posedge clk); 120 | rstn <= 1; 121 | end 122 | 123 | import chnl_pkg::*; 124 | import reg_pkg::*; 125 | import arb_pkg::*; 126 | import fmt_pkg::*; 127 | import mcdf_pkg::*; 128 | 129 | reg_intf reg_if(.*); 130 | chnl_intf chnl0_if(.*); 131 | chnl_intf chnl1_if(.*); 132 | chnl_intf chnl2_if(.*); 133 | arb_intf arb_if(.*); 134 | fmt_intf fmt_if(.*); 135 | mcdf_intf mcdf_if(.*); 136 | 137 | // mcdf interface monitoring MCDF ports and signals 138 | assign mcdf_if.chnl_en[0] = tb.dut.ctrl_regs_inst.slv0_en_o; 139 | assign mcdf_if.chnl_en[1] = tb.dut.ctrl_regs_inst.slv1_en_o; 140 | assign mcdf_if.chnl_en[2] = tb.dut.ctrl_regs_inst.slv2_en_o; 141 | 142 | // arbiter interface monitoring arbiter ports 143 | assign arb_if.slv_prios[0] = tb.dut.arbiter_inst.slv0_prio_i; 144 | assign arb_if.slv_prios[1] = tb.dut.arbiter_inst.slv1_prio_i; 145 | assign arb_if.slv_prios[2] = tb.dut.arbiter_inst.slv2_prio_i; 146 | assign arb_if.slv_reqs[0] = tb.dut.arbiter_inst.slv0_req_i; 147 | assign arb_if.slv_reqs[1] = tb.dut.arbiter_inst.slv1_req_i; 148 | assign arb_if.slv_reqs[2] = tb.dut.arbiter_inst.slv2_req_i; 149 | assign arb_if.a2s_acks[0] = tb.dut.arbiter_inst.a2s0_ack_o; 150 | assign arb_if.a2s_acks[1] = tb.dut.arbiter_inst.a2s1_ack_o; 151 | assign arb_if.a2s_acks[2] = tb.dut.arbiter_inst.a2s2_ack_o; 152 | assign arb_if.f2a_id_req = tb.dut.arbiter_inst.f2a_id_req_i; 153 | //子类句柄 154 | mcdf_data_consistence_basic_test t1; 155 | mcdf_full_random_test t2; 156 | mcdf_reg_read_write_test t3; 157 | mcdf_reg_stability_test t4; 158 | mcdf_down_stream_low_bandwidth_test t5; 159 | //父类句柄的关联数组 160 | mcdf_base_test tests[string]; 161 | string name; 162 | 163 | initial begin 164 | t1 = new(); 165 | t2 = new(); 166 | t3 = new(); 167 | t4 = new(); 168 | t5 = new(); 169 | tests["mcdf_data_consistence_basic_test"] = t1; 170 | tests["mcdf_full_random_test"] = t2; 171 | tests["mcdf_reg_read_write_test"] = t3; 172 | tests["mcdf_reg_stability_test"] = t4; 173 | tests["mcdf_down_stream_low_bandwidth_test"] = t5; 174 | if($value$plusargs("TESTNAME=%s", name)) begin 175 | if(tests.exists(name)) begin 176 | //子类句柄赋值给父类句柄后,若要由父类句柄调用子类函数时,子类函数要声明Virtual 177 | tests[name].set_interface(chnl0_if, chnl1_if, chnl2_if, reg_if, arb_if, fmt_if, mcdf_if); 178 | tests[name].run(); 179 | end 180 | else begin 181 | // Xcelium does not support it 182 | //$fatal($sformatf("[ERRTEST], test name %s is invalid, please specify a valid name!", name)); 183 | 184 | $fatal("[ERRTEST], test name %s is invalid, please specify a valid name!", name); 185 | end 186 | end 187 | else begin 188 | $display("NO runtime optiont +TESTNAME=xxx is configured, and run default test mcdf_data_consistence_basic_test"); 189 | tests["mcdf_data_consistence_basic_test"].set_interface(chnl0_if, chnl1_if, chnl2_if, reg_if, arb_if, fmt_if, mcdf_if); 190 | tests["mcdf_data_consistence_basic_test"].run(); 191 | end 192 | end 193 | endmodule 194 | -------------------------------------------------------------------------------- /uvm_verification_case/mcdf_rgm_pkg.sv: -------------------------------------------------------------------------------- 1 | `include "param_def.v" 2 | 3 | package mcdf_rgm_pkg; 4 | import uvm_pkg::*; 5 | `include "uvm_macros.svh" 6 | import reg_pkg::*; 7 | 8 | // Dedicated register description [write-read reg] with uvm_reg type 9 | class ctrl_reg extends uvm_reg; 10 | `uvm_object_utils(ctrl_reg) 11 | uvm_reg_field reserved; 12 | rand uvm_reg_field pkt_len; 13 | rand uvm_reg_field prio_level; 14 | rand uvm_reg_field chnl_en; 15 | 16 | covergroup value_cg; 17 | option.per_instance = 1; 18 | reserved: coverpoint reserved.value[25:0]; 19 | pkt_len: coverpoint pkt_len.value[2:0]; 20 | prio_level: coverpoint prio_level.value[1:0]; 21 | chnl_en: coverpoint chnl_en.value[0:0]; 22 | endgroup 23 | 24 | function new(string name = "ctrl_reg"); 25 | super.new(name, 32, UVM_CVR_ALL); 26 | void'(set_coverage(UVM_CVR_FIELD_VALS)); 27 | if(has_coverage(UVM_CVR_FIELD_VALS)) begin 28 | value_cg = new(); 29 | end 30 | endfunction 31 | 32 | virtual function void build(); 33 | reserved = uvm_reg_field::type_id::create("reserved"); 34 | pkt_len = uvm_reg_field::type_id::create("pkt_len"); 35 | prio_level = uvm_reg_field::type_id::create("prio_level"); 36 | chnl_en = uvm_reg_field::type_id::create("chnl_en"); 37 | 38 | reserved.configure(this, 26, 6, "RO", 0, 26'h0, 1, 0, 0); 39 | pkt_len.configure(this, 3, 3, "RW", 0, 3'h0, 1, 1, 0); 40 | prio_level.configure(this, 2, 1, "RW", 0, 2'h3, 1, 1, 0); 41 | chnl_en.configure(this, 1, 0, "RW", 0, 1'h1, 1, 1, 0); 42 | endfunction 43 | 44 | function void sample( 45 | uvm_reg_data_t data, 46 | uvm_reg_data_t byte_en, 47 | bit is_read, 48 | uvm_reg_map map 49 | ); 50 | super.sample(data, byte_en, is_read, map); 51 | sample_values(); 52 | endfunction 53 | 54 | function void sample_values(); 55 | super.sample_values(); 56 | if (get_coverage(UVM_CVR_FIELD_VALS)) begin 57 | value_cg.sample(); 58 | end 59 | endfunction 60 | endclass 61 | 62 | // Dedicated register description [read-only reg] with uvm_reg type 63 | class stat_reg extends uvm_reg; 64 | `uvm_object_utils(stat_reg) 65 | uvm_reg_field reserved; 66 | rand uvm_reg_field fifo_avail; 67 | 68 | 69 | covergroup value_cg; 70 | option.per_instance = 1; 71 | reserved: coverpoint reserved.value[23:0]; 72 | fifo_avail: coverpoint fifo_avail.value[7:0]; 73 | endgroup 74 | 75 | function new(string name = "stat_reg"); 76 | super.new(name, 32, UVM_CVR_ALL); 77 | void'(set_coverage(UVM_CVR_FIELD_VALS)); 78 | if(has_coverage(UVM_CVR_FIELD_VALS)) begin 79 | value_cg = new(); 80 | end 81 | endfunction 82 | 83 | virtual function void build(); 84 | reserved = uvm_reg_field::type_id::create("reserved"); 85 | fifo_avail = uvm_reg_field::type_id::create("fifo_avail"); 86 | 87 | reserved.configure(this, 24, 8, "RO", 0, 24'h0, 1, 0, 0); 88 | fifo_avail.configure(this, 8, 0, "RO", 0, 8'h20, 1, 1, 0); 89 | endfunction 90 | 91 | function void sample( 92 | uvm_reg_data_t data, 93 | uvm_reg_data_t byte_en, 94 | bit is_read, 95 | uvm_reg_map map 96 | ); 97 | super.sample(data, byte_en, is_read, map); 98 | sample_values(); 99 | endfunction 100 | 101 | function void sample_values(); 102 | super.sample_values(); 103 | if (get_coverage(UVM_CVR_FIELD_VALS)) begin 104 | value_cg.sample(); 105 | end 106 | endfunction 107 | endclass 108 | 109 | //MCDF top register block which includes child registers and the address map 110 | class mcdf_rgm extends uvm_reg_block; 111 | `uvm_object_utils(mcdf_rgm) 112 | rand ctrl_reg chnl0_ctrl_reg; 113 | rand ctrl_reg chnl1_ctrl_reg; 114 | rand ctrl_reg chnl2_ctrl_reg; 115 | rand stat_reg chnl0_stat_reg; 116 | rand stat_reg chnl1_stat_reg; 117 | rand stat_reg chnl2_stat_reg; 118 | 119 | uvm_reg_map map; 120 | 121 | function new(string name = "mcdf_rgm"); 122 | super.new(name, UVM_NO_COVERAGE); 123 | endfunction 124 | 125 | virtual function void build(); 126 | chnl0_ctrl_reg = ctrl_reg::type_id::create("chnl0_ctrl_reg"); 127 | chnl0_ctrl_reg.configure(this); 128 | chnl0_ctrl_reg.build(); 129 | 130 | chnl1_ctrl_reg = ctrl_reg::type_id::create("chnl1_ctrl_reg"); 131 | chnl1_ctrl_reg.configure(this); 132 | chnl1_ctrl_reg.build(); 133 | 134 | chnl2_ctrl_reg = ctrl_reg::type_id::create("chnl2_ctrl_reg"); 135 | chnl2_ctrl_reg.configure(this); 136 | chnl2_ctrl_reg.build(); 137 | 138 | chnl0_stat_reg = stat_reg::type_id::create("chnl0_stat_reg"); 139 | chnl0_stat_reg.configure(this); 140 | chnl0_stat_reg.build(); 141 | 142 | chnl1_stat_reg = stat_reg::type_id::create("chnl1_stat_reg"); 143 | chnl1_stat_reg.configure(this); 144 | chnl1_stat_reg.build(); 145 | 146 | chnl2_stat_reg = stat_reg::type_id::create("chnl2_stat_reg"); 147 | chnl2_stat_reg.configure(this); 148 | chnl2_stat_reg.build(); 149 | 150 | // map name, offset, number of bytes, endianess 151 | map = create_map("map", 'h0, 4, UVM_LITTLE_ENDIAN); 152 | 153 | map.add_reg(chnl0_ctrl_reg, 32'h00000000, "RW"); 154 | map.add_reg(chnl1_ctrl_reg, 32'h00000004, "RW"); 155 | map.add_reg(chnl2_ctrl_reg, 32'h00000008, "RW"); 156 | map.add_reg(chnl0_stat_reg, 32'h00000010, "RO"); 157 | map.add_reg(chnl1_stat_reg, 32'h00000014, "RO"); 158 | map.add_reg(chnl2_stat_reg, 32'h00000018, "RO"); 159 | 160 | // specify HDL path 161 | chnl0_ctrl_reg.add_hdl_path_slice($sformatf("mem[%0d]", `SLV0_RW_REG), 0, 32); 162 | chnl1_ctrl_reg.add_hdl_path_slice($sformatf("mem[%0d]", `SLV1_RW_REG), 0, 32); 163 | chnl2_ctrl_reg.add_hdl_path_slice($sformatf("mem[%0d]", `SLV2_RW_REG), 0, 32); 164 | chnl0_stat_reg.add_hdl_path_slice($sformatf("mem[%0d]", `SLV0_R_REG ), 0, 32); 165 | chnl1_stat_reg.add_hdl_path_slice($sformatf("mem[%0d]", `SLV1_R_REG ), 0, 32); 166 | chnl2_stat_reg.add_hdl_path_slice($sformatf("mem[%0d]", `SLV2_R_REG ), 0, 32); 167 | 168 | add_hdl_path("tb.dut.ctrl_regs_inst"); 169 | 170 | lock_model(); 171 | endfunction 172 | endclass 173 | 174 | //TODO-1.1 Implement the reg2mcdf_adapter which converts the uvm_reg_bus_op 175 | //type and the reg_trans type 176 | class reg2mcdf_adapter extends uvm_reg_adapter; 177 | `uvm_object_utils(reg2mcdf_adapter) 178 | function new(string name = "reg2mcdf_adapter"); 179 | super.new(name); 180 | provides_responses = 1; 181 | endfunction 182 | function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); 183 | //USER TODO 184 | endfunction 185 | function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw); 186 | //USER TODO 187 | endfunction 188 | endclass 189 | 190 | 191 | 192 | endpackage: mcdf_rgm_pkg 193 | -------------------------------------------------------------------------------- /uvm_verification_case/mcdf_rgm_pkg_ref.sv: -------------------------------------------------------------------------------- 1 | `include "param_def.v" 2 | 3 | package mcdf_rgm_pkg; 4 | import uvm_pkg::*; 5 | `include "uvm_macros.svh" 6 | import reg_pkg::*; 7 | 8 | // Dedicated register description [write-read reg] with uvm_reg type 9 | class ctrl_reg extends uvm_reg; 10 | `uvm_object_utils(ctrl_reg) 11 | uvm_reg_field reserved; 12 | rand uvm_reg_field pkt_len; 13 | rand uvm_reg_field prio_level; 14 | rand uvm_reg_field chnl_en; 15 | 16 | covergroup value_cg; 17 | option.per_instance = 1; 18 | reserved: coverpoint reserved.value[25:0]; 19 | pkt_len: coverpoint pkt_len.value[2:0]; 20 | prio_level: coverpoint prio_level.value[1:0]; 21 | chnl_en: coverpoint chnl_en.value[0:0]; 22 | endgroup 23 | 24 | function new(string name = "ctrl_reg"); 25 | super.new(name, 32, UVM_CVR_ALL); 26 | void'(set_coverage(UVM_CVR_FIELD_VALS)); 27 | if(has_coverage(UVM_CVR_FIELD_VALS)) begin 28 | value_cg = new(); 29 | end 30 | endfunction 31 | 32 | virtual function void build(); 33 | reserved = uvm_reg_field::type_id::create("reserved"); 34 | pkt_len = uvm_reg_field::type_id::create("pkt_len"); 35 | prio_level = uvm_reg_field::type_id::create("prio_level"); 36 | chnl_en = uvm_reg_field::type_id::create("chnl_en"); 37 | 38 | reserved.configure(this, 26, 6, "RO", 0, 26'h0, 1, 0, 0); 39 | pkt_len.configure(this, 3, 3, "RW", 0, 3'h0, 1, 1, 0); 40 | prio_level.configure(this, 2, 1, "RW", 0, 2'h3, 1, 1, 0); 41 | chnl_en.configure(this, 1, 0, "RW", 0, 1'h1, 1, 1, 0); 42 | endfunction 43 | 44 | function void sample( 45 | uvm_reg_data_t data, 46 | uvm_reg_data_t byte_en, 47 | bit is_read, 48 | uvm_reg_map map 49 | ); 50 | super.sample(data, byte_en, is_read, map); 51 | sample_values(); 52 | endfunction 53 | 54 | function void sample_values(); 55 | super.sample_values(); 56 | if (get_coverage(UVM_CVR_FIELD_VALS)) begin 57 | value_cg.sample(); 58 | end 59 | endfunction 60 | endclass 61 | 62 | // Dedicated register description [read-only reg] with uvm_reg type 63 | class stat_reg extends uvm_reg; 64 | `uvm_object_utils(stat_reg) 65 | uvm_reg_field reserved; 66 | rand uvm_reg_field fifo_avail; 67 | 68 | 69 | covergroup value_cg; 70 | option.per_instance = 1; 71 | reserved: coverpoint reserved.value[23:0]; 72 | fifo_avail: coverpoint fifo_avail.value[7:0]; 73 | endgroup 74 | 75 | function new(string name = "stat_reg"); 76 | super.new(name, 32, UVM_CVR_ALL); 77 | void'(set_coverage(UVM_CVR_FIELD_VALS)); 78 | if(has_coverage(UVM_CVR_FIELD_VALS)) begin 79 | value_cg = new(); 80 | end 81 | endfunction 82 | 83 | virtual function void build(); 84 | reserved = uvm_reg_field::type_id::create("reserved"); 85 | fifo_avail = uvm_reg_field::type_id::create("fifo_avail"); 86 | 87 | reserved.configure(this, 24, 8, "RO", 0, 24'h0, 1, 0, 0); 88 | fifo_avail.configure(this, 8, 0, "RO", 0, 8'h20, 1, 1, 0); 89 | endfunction 90 | 91 | function void sample( 92 | uvm_reg_data_t data, 93 | uvm_reg_data_t byte_en, 94 | bit is_read, 95 | uvm_reg_map map 96 | ); 97 | super.sample(data, byte_en, is_read, map); 98 | sample_values(); 99 | endfunction 100 | 101 | function void sample_values(); 102 | super.sample_values(); 103 | if (get_coverage(UVM_CVR_FIELD_VALS)) begin 104 | value_cg.sample(); 105 | end 106 | endfunction 107 | endclass 108 | 109 | //MCDF top register block which includes child registers and the address map 110 | class mcdf_rgm extends uvm_reg_block; 111 | `uvm_object_utils(mcdf_rgm) 112 | rand ctrl_reg chnl0_ctrl_reg; 113 | rand ctrl_reg chnl1_ctrl_reg; 114 | rand ctrl_reg chnl2_ctrl_reg; 115 | rand stat_reg chnl0_stat_reg; 116 | rand stat_reg chnl1_stat_reg; 117 | rand stat_reg chnl2_stat_reg; 118 | 119 | uvm_reg_map map; 120 | 121 | function new(string name = "mcdf_rgm"); 122 | super.new(name, UVM_NO_COVERAGE); 123 | endfunction 124 | 125 | virtual function void build(); 126 | chnl0_ctrl_reg = ctrl_reg::type_id::create("chnl0_ctrl_reg"); 127 | chnl0_ctrl_reg.configure(this); 128 | chnl0_ctrl_reg.build(); 129 | 130 | chnl1_ctrl_reg = ctrl_reg::type_id::create("chnl1_ctrl_reg"); 131 | chnl1_ctrl_reg.configure(this); 132 | chnl1_ctrl_reg.build(); 133 | 134 | chnl2_ctrl_reg = ctrl_reg::type_id::create("chnl2_ctrl_reg"); 135 | chnl2_ctrl_reg.configure(this); 136 | chnl2_ctrl_reg.build(); 137 | 138 | chnl0_stat_reg = stat_reg::type_id::create("chnl0_stat_reg"); 139 | chnl0_stat_reg.configure(this); 140 | chnl0_stat_reg.build(); 141 | 142 | chnl1_stat_reg = stat_reg::type_id::create("chnl1_stat_reg"); 143 | chnl1_stat_reg.configure(this); 144 | chnl1_stat_reg.build(); 145 | 146 | chnl2_stat_reg = stat_reg::type_id::create("chnl2_stat_reg"); 147 | chnl2_stat_reg.configure(this); 148 | chnl2_stat_reg.build(); 149 | 150 | // map name, offset, number of bytes, endianess 151 | map = create_map("map", 'h0, 4, UVM_LITTLE_ENDIAN); 152 | 153 | map.add_reg(chnl0_ctrl_reg, 32'h00000000, "RW"); 154 | map.add_reg(chnl1_ctrl_reg, 32'h00000004, "RW"); 155 | map.add_reg(chnl2_ctrl_reg, 32'h00000008, "RW"); 156 | map.add_reg(chnl0_stat_reg, 32'h00000010, "RO"); 157 | map.add_reg(chnl1_stat_reg, 32'h00000014, "RO"); 158 | map.add_reg(chnl2_stat_reg, 32'h00000018, "RO"); 159 | 160 | // specify HDL path 161 | chnl0_ctrl_reg.add_hdl_path_slice($sformatf("mem[%0d]", `SLV0_RW_REG), 0, 32); 162 | chnl1_ctrl_reg.add_hdl_path_slice($sformatf("mem[%0d]", `SLV1_RW_REG), 0, 32); 163 | chnl2_ctrl_reg.add_hdl_path_slice($sformatf("mem[%0d]", `SLV2_RW_REG), 0, 32); 164 | chnl0_stat_reg.add_hdl_path_slice($sformatf("mem[%0d]", `SLV0_R_REG ), 0, 32); 165 | chnl1_stat_reg.add_hdl_path_slice($sformatf("mem[%0d]", `SLV1_R_REG ), 0, 32); 166 | chnl2_stat_reg.add_hdl_path_slice($sformatf("mem[%0d]", `SLV2_R_REG ), 0, 32); 167 | 168 | add_hdl_path("tb.dut.ctrl_regs_inst"); 169 | 170 | lock_model(); 171 | endfunction 172 | endclass 173 | 174 | //TODO-1.1 Implement the reg2mcdf_adapter which converts the uvm_reg_bus_op 175 | //type and the reg_trans type 176 | class reg2mcdf_adapter extends uvm_reg_adapter; 177 | `uvm_object_utils(reg2mcdf_adapter) 178 | function new(string name = "reg2mcdf_adapter"); 179 | super.new(name); 180 | provides_responses = 1; 181 | endfunction 182 | function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); 183 | reg_trans t = reg_trans::type_id::create("t"); 184 | t.cmd = (rw.kind == UVM_WRITE) ? `WRITE : `READ; 185 | t.addr = rw.addr; 186 | t.data = rw.data; 187 | return t; 188 | endfunction 189 | function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw); 190 | reg_trans t; 191 | if (!$cast(t, bus_item)) begin 192 | `uvm_fatal("CASTFAIL","Provided bus_item is not of the correct type") 193 | return; 194 | end 195 | rw.kind = (t.cmd == `WRITE) ? UVM_WRITE : UVM_READ; 196 | rw.addr = t.addr; 197 | rw.data = t.data; 198 | rw.status = UVM_IS_OK; 199 | endfunction 200 | endclass 201 | 202 | 203 | 204 | endpackage: mcdf_rgm_pkg 205 | -------------------------------------------------------------------------------- /sv_verification_case/reg_pkg.sv: -------------------------------------------------------------------------------- 1 | `include "param_def.v" 2 | 3 | package reg_pkg; 4 | //发送寄存读写的数据 5 | class reg_trans; 6 | rand bit[7:0] addr; 7 | rand bit[1:0] cmd; 8 | rand bit[31:0] data; 9 | bit rsp; 10 | 11 | constraint cstr { 12 | soft cmd inside {`WRITE, `READ, `IDLE}; 13 | soft addr inside {`SLV0_RW_ADDR, `SLV1_RW_ADDR, `SLV2_RW_ADDR, `SLV0_R_ADDR, `SLV1_R_ADDR, `SLV2_R_ADDR}; 14 | addr[7:4]==0 && cmd==`WRITE -> soft data[31:6]==0;//若对读寄存器进行写操作 15 | soft addr[7:5]==0; 16 | addr[4]==1 -> soft cmd == `READ;//表示只读寄存器 17 | }; 18 | 19 | function reg_trans clone(); 20 | reg_trans c = new(); 21 | c.addr = this.addr; 22 | c.cmd = this.cmd; 23 | c.data = this.data; 24 | c.rsp = this.rsp; 25 | return c; 26 | endfunction 27 | 28 | function string sprint(); 29 | string s; 30 | s = {s, $sformatf("=======================================\n")}; 31 | s = {s, $sformatf("reg_trans object content is as below: \n")}; 32 | s = {s, $sformatf("addr = %2x: \n", this.addr)}; 33 | s = {s, $sformatf("cmd = %2b: \n", this.cmd)}; 34 | s = {s, $sformatf("data = %8x: \n", this.data)}; 35 | s = {s, $sformatf("rsp = %0d: \n", this.rsp)}; 36 | s = {s, $sformatf("=======================================\n")}; 37 | return s; 38 | endfunction 39 | endclass 40 | //发送激励 41 | class reg_driver; 42 | local string name; 43 | local virtual reg_intf intf; 44 | mailbox #(reg_trans) req_mb; 45 | mailbox #(reg_trans) rsp_mb; 46 | 47 | function new(string name = "reg_driver"); 48 | this.name = name; 49 | endfunction 50 | 51 | function void set_interface(virtual reg_intf intf); 52 | if(intf == null) 53 | $error("interface handle is NULL, please check if target interface has been intantiated"); 54 | else 55 | this.intf = intf; 56 | endfunction 57 | 58 | task run(); 59 | fork 60 | this.do_drive(); 61 | this.do_reset(); 62 | join 63 | endtask 64 | 65 | task do_reset(); 66 | forever begin 67 | @(negedge intf.rstn); 68 | intf.cmd_addr <= 0; 69 | intf.cmd <= `IDLE; 70 | intf.cmd_data_m2s <= 0; 71 | end 72 | endtask 73 | 74 | task do_drive(); 75 | reg_trans req, rsp; 76 | @(posedge intf.rstn); 77 | forever begin 78 | this.req_mb.get(req); 79 | this.reg_write(req); 80 | rsp = req.clone(); 81 | rsp.rsp = 1; 82 | this.rsp_mb.put(rsp); 83 | end 84 | endtask 85 | //读写操作时序设计 86 | task reg_write(reg_trans t); 87 | @(posedge intf.clk iff intf.rstn); 88 | case(t.cmd) 89 | `WRITE: begin 90 | intf.drv_ck.cmd_addr <= t.addr; 91 | intf.drv_ck.cmd <= t.cmd; 92 | intf.drv_ck.cmd_data_m2s <= t.data; 93 | end 94 | `READ: begin 95 | intf.drv_ck.cmd_addr <= t.addr; 96 | intf.drv_ck.cmd <= t.cmd; 97 | //注意:这里需要等待两个下降沿,因为读数据时数据在下一个下降沿生效 98 | repeat(2) @(negedge intf.clk); 99 | t.data = intf.cmd_data_s2m; 100 | end 101 | `IDLE: begin 102 | this.reg_idle(); 103 | end 104 | default: $error("command %b is illegal", t.cmd); 105 | endcase 106 | $display("%0t reg driver [%s] sent addr %2x, cmd %2b, data %8x", $time, name, t.addr, t.cmd, t.data); 107 | endtask 108 | 109 | task reg_idle(); 110 | @(posedge intf.clk); 111 | intf.drv_ck.cmd_addr <= 0; 112 | intf.drv_ck.cmd <= `IDLE; 113 | intf.drv_ck.cmd_data_m2s <= 0; 114 | endtask 115 | endclass 116 | 117 | class reg_generator; 118 | rand bit[7:0] addr = -1; 119 | rand bit[1:0] cmd = -1; 120 | rand bit[31:0] data = -1; 121 | 122 | mailbox #(reg_trans) req_mb; 123 | mailbox #(reg_trans) rsp_mb; 124 | 125 | reg_trans reg_req[$]; 126 | 127 | constraint cstr{ 128 | soft addr == -1; 129 | soft cmd == -1; 130 | soft data == -1; 131 | } 132 | 133 | function new(); 134 | this.req_mb = new(); 135 | this.rsp_mb = new(); 136 | endfunction 137 | 138 | task start(); 139 | send_trans(); 140 | endtask 141 | 142 | // generate transaction and put into local mailbox 143 | task send_trans(); 144 | reg_trans req, rsp; 145 | req = new(); 146 | assert(req.randomize with {local::addr >= 0 -> addr == local::addr; 147 | local::cmd >= 0 -> cmd == local::cmd; 148 | local::data >= 0 -> data == local::data; 149 | }) 150 | else $fatal("[RNDFAIL] register packet randomization failure!"); 151 | $display(req.sprint()); 152 | this.req_mb.put(req); 153 | this.rsp_mb.get(rsp); 154 | $display(rsp.sprint()); 155 | if(req.cmd == `READ) 156 | this.data = rsp.data; 157 | assert(rsp.rsp) 158 | else $error("[RSPERR] %0t error response received!", $time); 159 | endtask 160 | 161 | function string sprint(); 162 | string s; 163 | s = {s, $sformatf("=======================================\n")}; 164 | s = {s, $sformatf("reg_generator object content is as below: \n")}; 165 | s = {s, $sformatf("addr = %2x: \n", this.addr)}; 166 | s = {s, $sformatf("cmd = %2b: \n", this.cmd)}; 167 | s = {s, $sformatf("data = %8x: \n", this.data)}; 168 | s = {s, $sformatf("=======================================\n")}; 169 | return s; 170 | endfunction 171 | 172 | function void post_randomize(); 173 | string s; 174 | s = {"AFTER RANDOMIZATION \n", this.sprint()}; 175 | $display(s); 176 | endfunction 177 | endclass 178 | 179 | class reg_monitor; 180 | local string name; 181 | local virtual reg_intf intf; 182 | mailbox #(reg_trans) mon_mb; 183 | function new(string name="reg_monitor"); 184 | this.name = name; 185 | endfunction 186 | function void set_interface(virtual reg_intf intf); 187 | if(intf == null) 188 | $error("interface handle is NULL, please check if target interface has been intantiated"); 189 | else 190 | this.intf = intf; 191 | endfunction 192 | task run(); 193 | this.mon_trans(); 194 | endtask 195 | 196 | task mon_trans(); 197 | reg_trans m; 198 | forever begin 199 | @(posedge intf.clk iff (intf.rstn && intf.mon_ck.cmd != `IDLE)); 200 | m = new(); 201 | m.addr = intf.mon_ck.cmd_addr; 202 | m.cmd = intf.mon_ck.cmd; 203 | if(intf.mon_ck.cmd == `WRITE) begin 204 | m.data = intf.mon_ck.cmd_data_m2s; 205 | end 206 | else if(intf.mon_ck.cmd == `READ) begin 207 | @(posedge intf.clk); 208 | m.data = intf.mon_ck.cmd_data_s2m; 209 | end 210 | mon_mb.put(m); 211 | $display("%0t %s monitored addr %2x, cmd %2b, data %8x", $time, this.name, m.addr, m.cmd, m.data); 212 | end 213 | endtask 214 | endclass 215 | 216 | class reg_agent; 217 | local string name; 218 | reg_driver driver; 219 | reg_monitor monitor; 220 | local virtual reg_intf vif; 221 | function new(string name = "reg_agent"); 222 | this.name = name; 223 | this.driver = new({name, ".driver"}); 224 | this.monitor = new({name, ".monitor"}); 225 | endfunction 226 | 227 | function void set_interface(virtual reg_intf vif); 228 | this.vif = vif; 229 | driver.set_interface(vif); 230 | monitor.set_interface(vif); 231 | endfunction 232 | task run(); 233 | fork 234 | driver.run(); 235 | monitor.run(); 236 | join 237 | endtask 238 | endclass 239 | 240 | endpackage 241 | -------------------------------------------------------------------------------- /sv_verification_case/chnl_pkg.sv: -------------------------------------------------------------------------------- 1 | package chnl_pkg; 2 | //发送Chnl的数据 3 | class chnl_trans; 4 | rand bit[31:0] data[]; 5 | rand int ch_id; 6 | rand int pkt_id; 7 | rand int data_nidles;//相邻数据的间隔 8 | rand int pkt_nidles;//相邻数据包的间隔 9 | bit rsp; 10 | constraint cstr{ 11 | soft data.size inside {[4:32]}; 12 | //动态数组的约束 13 | foreach(data[i]) data[i] == 'hC000 _0000 + (this.ch_id<<24) + (this.pkt_id<<8) + i; 14 | //soft表示软约束 15 | soft ch_id == 0; 16 | soft pkt_id == 0; 17 | soft data_nidles inside {[0:2]}; 18 | soft pkt_nidles inside {[1:10]}; 19 | }; 20 | 21 | function chnl_trans clone(); 22 | chnl_trans c = new(); 23 | c.data = this.data; 24 | c.ch_id = this.ch_id; 25 | c.pkt_id = this.pkt_id; 26 | c.data_nidles = this.data_nidles; 27 | c.pkt_nidles = this.pkt_nidles; 28 | c.rsp = this.rsp; 29 | return c; 30 | endfunction 31 | 32 | function string sprint(); 33 | string s; 34 | s = {s, $sformatf("=======================================\n")}; 35 | s = {s, $sformatf("chnl_trans object content is as below: \n")}; 36 | foreach(data[i]) s = {s, $sformatf("data[%0d] = %8x \n", i, this.data[i])}; 37 | s = {s, $sformatf("ch_id = %0d: \n", this.ch_id)}; 38 | s = {s, $sformatf("pkt_id = %0d: \n", this.pkt_id)}; 39 | s = {s, $sformatf("data_nidles = %0d: \n", this.data_nidles)}; 40 | s = {s, $sformatf("pkt_nidles = %0d: \n", this.pkt_nidles)}; 41 | s = {s, $sformatf("rsp = %0d: \n", this.rsp)}; 42 | s = {s, $sformatf("=======================================\n")}; 43 | return s; 44 | endfunction 45 | endclass: chnl_trans 46 | 47 | class chnl_driver; 48 | local string name; 49 | local virtual chnl_intf intf; 50 | mailbox #(chnl_trans) req_mb; 51 | mailbox #(chnl_trans) rsp_mb; 52 | 53 | function new(string name = "chnl_driver"); 54 | this.name = name; 55 | endfunction 56 | 57 | function void set_interface(virtual chnl_intf intf); 58 | if(intf == null) 59 | $error("interface handle is NULL, please check if target interface has been intantiated"); 60 | else 61 | this.intf = intf; 62 | endfunction 63 | 64 | task run(); 65 | fork 66 | this.do_drive(); 67 | this.do_reset(); 68 | join 69 | endtask 70 | 71 | task do_reset(); 72 | forever begin 73 | @(negedge intf.rstn); 74 | intf.ch_valid <= 0; 75 | intf.ch_data <= 0; 76 | end 77 | endtask 78 | 79 | task do_drive(); 80 | chnl_trans req, rsp;//产生两个空句柄 81 | @(posedge intf.rstn); 82 | forever begin 83 | this.req_mb.get(req); 84 | this.chnl_write(req); 85 | rsp = req.clone(); 86 | rsp.rsp = 1; 87 | this.rsp_mb.put(rsp); 88 | end 89 | endtask 90 | 91 | task chnl_write(input chnl_trans t); 92 | foreach(t.data[i]) begin 93 | @(posedge intf.clk); 94 | intf.drv_ck.ch_valid <= 1; 95 | intf.drv_ck.ch_data <= t.data[i]; 96 | @(negedge intf.clk); 97 | wait(intf.ch_ready === 'b1); 98 | $display("%0t channel driver [%s] sent data %x", $time, name, t.data[i]); 99 | repeat(t.data_nidles) chnl_idle(); 100 | end 101 | repeat(t.pkt_nidles) chnl_idle(); 102 | endtask 103 | 104 | task chnl_idle(); 105 | @(posedge intf.clk); 106 | intf.drv_ck.ch_valid <= 0; 107 | intf.drv_ck.ch_data <= 0; 108 | endtask 109 | endclass: chnl_driver 110 | 111 | class chnl_generator; 112 | rand int pkt_id = 0; 113 | rand int ch_id = -1; 114 | rand int data_nidles = -1; 115 | rand int pkt_nidles = -1; 116 | rand int data_size = -1; 117 | rand int ntrans = 10; 118 | 119 | mailbox #(chnl_trans) req_mb; 120 | mailbox #(chnl_trans) rsp_mb; 121 | 122 | constraint cstr{ 123 | soft ch_id == -1; 124 | soft pkt_id == 0; 125 | soft data_size == -1; 126 | soft data_nidles == -1; 127 | soft pkt_nidles == -1; 128 | soft ntrans == 10; 129 | } 130 | 131 | function new(); 132 | this.req_mb = new(); 133 | this.rsp_mb = new(); 134 | endfunction 135 | 136 | task start(); 137 | repeat(ntrans) send_trans(); 138 | endtask 139 | 140 | task send_trans(); 141 | chnl_trans req, rsp; 142 | req = new(); //chnl_generator.ch_id req.ch_id 143 | assert(req.randomize with {local::ch_id >= 0 -> ch_id == local::ch_id; 144 | local::pkt_id >= 0 -> pkt_id == local::pkt_id; 145 | local::data_nidles >= 0 -> data_nidles == local::data_nidles; 146 | local::pkt_nidles >= 0 -> pkt_nidles == local::pkt_nidles; 147 | local::data_size >0 -> data.size() == local::data_size; 148 | }) 149 | else $fatal("[RNDFAIL] channel packet randomization failure!"); 150 | this.pkt_id++; 151 | $display(req.sprint()); 152 | //握手操作 153 | this.req_mb.put(req); 154 | this.rsp_mb.get(rsp); 155 | $display(rsp.sprint()); 156 | assert(rsp.rsp) 157 | else $error("[RSPERR] %0t error response received!", $time); 158 | endtask 159 | 160 | function string sprint(); 161 | string s; 162 | s = {s, $sformatf("=======================================\n")}; 163 | s = {s, $sformatf("chnl_generator object content is as below: \n")}; 164 | s = {s, $sformatf("ntrans = %0d: \n", this.ntrans)}; 165 | s = {s, $sformatf("ch_id = %0d: \n", this.ch_id)}; 166 | s = {s, $sformatf("pkt_id = %0d: \n", this.pkt_id)}; 167 | s = {s, $sformatf("data_nidles = %0d: \n", this.data_nidles)}; 168 | s = {s, $sformatf("pkt_nidles = %0d: \n", this.pkt_nidles)}; 169 | s = {s, $sformatf("data_size = %0d: \n", this.data_size)}; 170 | s = {s, $sformatf("=======================================\n")}; 171 | return s; 172 | endfunction 173 | 174 | function void post_randomize(); 175 | string s; 176 | s = {"AFTER RANDOMIZATION \n", this.sprint()}; 177 | $display(s); 178 | endfunction 179 | endclass: chnl_generator 180 | 181 | typedef struct packed { 182 | bit[31:0] data; 183 | bit[1:0] id; 184 | } mon_data_t; 185 | 186 | class chnl_monitor; 187 | local string name; 188 | local virtual chnl_intf intf; 189 | mailbox #(mon_data_t) mon_mb; 190 | function new(string name="chnl_monitor"); 191 | this.name = name; 192 | endfunction 193 | function void set_interface(virtual chnl_intf intf); 194 | if(intf == null) 195 | $error("interface handle is NULL, please check if target interface has been intantiated"); 196 | else 197 | this.intf = intf; 198 | endfunction 199 | task run(); 200 | this.mon_trans(); 201 | endtask 202 | 203 | task mon_trans(); 204 | mon_data_t m; 205 | forever begin 206 | @(posedge intf.clk iff (intf.mon_ck.ch_valid==='b1 && intf.mon_ck.ch_ready==='b1)); 207 | m.data = intf.mon_ck.ch_data; 208 | mon_mb.put(m); 209 | $display("%0t %s monitored channle data %8x", $time, this.name, m.data); 210 | end 211 | endtask 212 | endclass 213 | 214 | class chnl_agent; 215 | local string name; 216 | chnl_driver driver; 217 | chnl_monitor monitor; 218 | local virtual chnl_intf vif; 219 | function new(string name = "chnl_agent"); 220 | this.name = name; 221 | this.driver = new({name, ".driver"}); 222 | this.monitor = new({name, ".monitor"}); 223 | endfunction 224 | 225 | function void set_interface(virtual chnl_intf vif); 226 | this.vif = vif; 227 | driver.set_interface(vif); 228 | monitor.set_interface(vif); 229 | endfunction 230 | task run(); 231 | fork 232 | driver.run(); 233 | monitor.run(); 234 | join 235 | endtask 236 | endclass: chnl_agent 237 | 238 | endpackage 239 | 240 | -------------------------------------------------------------------------------- /uvm_verification_case/chnl_pkg.sv: -------------------------------------------------------------------------------- 1 | package chnl_pkg; 2 | import uvm_pkg::*; 3 | `include "uvm_macros.svh" 4 | 5 | // channel sequence item 6 | class chnl_trans extends uvm_sequence_item; 7 | rand bit[31:0] data[]; 8 | rand int ch_id; 9 | rand int pkt_id; 10 | rand int data_nidles; 11 | rand int pkt_nidles; 12 | bit rsp; 13 | 14 | constraint cstr{ 15 | soft data.size inside {[4:32]}; 16 | foreach(data[i]) data[i] == 'hC000_0000 + (this.ch_id<<24) + (this.pkt_id<<8) + i; 17 | soft ch_id == 0; 18 | soft pkt_id == 0; 19 | soft data_nidles inside {[0:2]}; 20 | soft pkt_nidles inside {[1:10]}; 21 | }; 22 | 23 | `uvm_object_utils_begin(chnl_trans) 24 | //域的自动化声明 field automation 25 | `uvm_field_array_int(data, UVM_ALL_ON) 26 | `uvm_field_int(ch_id, UVM_ALL_ON) 27 | `uvm_field_int(pkt_id, UVM_ALL_ON) 28 | `uvm_field_int(data_nidles, UVM_ALL_ON) 29 | `uvm_field_int(pkt_nidles, UVM_ALL_ON) 30 | `uvm_field_int(rsp, UVM_ALL_ON) 31 | `uvm_object_utils_end 32 | 33 | function new (string name = "chnl_trans"); 34 | super.new(name); 35 | endfunction 36 | endclass: chnl_trans 37 | 38 | // channel driver 39 | class chnl_driver extends uvm_driver #(chnl_trans); 40 | local virtual chnl_intf intf; 41 | 42 | `uvm_component_utils(chnl_driver) 43 | 44 | function new (string name = "chnl_driver", uvm_component parent); 45 | super.new(name, parent); 46 | endfunction 47 | 48 | function void set_interface(virtual chnl_intf intf); 49 | if(intf == null) 50 | $error("interface handle is NULL, please check if target interface has been intantiated"); 51 | else 52 | this.intf = intf; 53 | endfunction 54 | 55 | task run_phase(uvm_phase phase); 56 | fork 57 | this.do_drive(); 58 | this.do_reset(); 59 | join 60 | endtask 61 | 62 | task do_reset(); 63 | forever begin 64 | @(negedge intf.rstn); 65 | intf.ch_valid <= 0; 66 | intf.ch_data <= 0; 67 | end 68 | endtask 69 | 70 | task do_drive(); 71 | chnl_trans req, rsp; 72 | @(posedge intf.rstn); 73 | forever begin 74 | seq_item_port.get_next_item(req); 75 | this.chnl_write(req); 76 | void'($cast(rsp, req.clone())); 77 | rsp.rsp = 1; 78 | rsp.set_sequence_id(req.get_sequence_id()); 79 | seq_item_port.item_done(rsp); 80 | end 81 | endtask 82 | 83 | task chnl_write(input chnl_trans t); 84 | foreach(t.data[i]) begin 85 | @(posedge intf.clk); 86 | intf.drv_ck.ch_valid <= 1; 87 | intf.drv_ck.ch_data <= t.data[i]; 88 | @(negedge intf.clk); 89 | wait(intf.ch_ready === 'b1); 90 | `uvm_info(get_type_name(), $sformatf("sent data 'h%8x", t.data[i]), UVM_HIGH) 91 | repeat(t.data_nidles) chnl_idle(); 92 | end 93 | repeat(t.pkt_nidles) chnl_idle(); 94 | endtask 95 | 96 | task chnl_idle(); 97 | @(posedge intf.clk); 98 | intf.drv_ck.ch_valid <= 0; 99 | intf.drv_ck.ch_data <= 0; 100 | endtask 101 | endclass: chnl_driver 102 | 103 | class chnl_sequencer extends uvm_sequencer #(chnl_trans); 104 | `uvm_component_utils(chnl_sequencer) 105 | function new (string name = "chnl_sequencer", uvm_component parent); 106 | super.new(name, parent); 107 | endfunction 108 | endclass: chnl_sequencer 109 | 110 | class chnl_data_sequence extends uvm_sequence #(chnl_trans); 111 | rand int pkt_id = 0; 112 | rand int ch_id = -1; 113 | rand int data_nidles = -1; 114 | rand int pkt_nidles = -1; 115 | rand int data_size = -1; 116 | rand int ntrans = 10; 117 | `uvm_object_utils_begin(chnl_data_sequence) 118 | `uvm_field_int(pkt_id, UVM_ALL_ON) 119 | `uvm_field_int(ch_id, UVM_ALL_ON) 120 | `uvm_field_int(data_nidles, UVM_ALL_ON) 121 | `uvm_field_int(pkt_nidles, UVM_ALL_ON) 122 | `uvm_field_int(data_size, UVM_ALL_ON) 123 | `uvm_field_int(ntrans, UVM_ALL_ON) 124 | `uvm_object_utils_end 125 | `uvm_declare_p_sequencer(chnl_sequencer) 126 | function new (string name = "chnl_data_sequence"); 127 | super.new(name); 128 | endfunction 129 | 130 | task body(); 131 | repeat(ntrans) send_trans(); 132 | endtask 133 | 134 | task send_trans(); 135 | chnl_trans req, rsp; 136 | `uvm_do_with(req, {local::ch_id >= 0 -> ch_id == local::ch_id; 137 | local::pkt_id >= 0 -> pkt_id == local::pkt_id; 138 | local::data_nidles >= 0 -> data_nidles == local::data_nidles; 139 | local::pkt_nidles >= 0 -> pkt_nidles == local::pkt_nidles; 140 | local::data_size >0 -> data.size() == local::data_size; 141 | }) 142 | this.pkt_id++; 143 | `uvm_info(get_type_name(), req.sprint(), UVM_HIGH) 144 | get_response(rsp); 145 | `uvm_info(get_type_name(), rsp.sprint(), UVM_HIGH) 146 | assert(rsp.rsp) 147 | else $error("[RSPERR] %0t error response received!", $time); 148 | endtask 149 | 150 | function void post_randomize(); 151 | string s; 152 | s = {s, "AFTER RANDOMIZATION \n"}; 153 | s = {s, "=======================================\n"}; 154 | s = {s, "chnl_data_sequence object content is as below: \n"}; 155 | s = {s, super.sprint()}; 156 | s = {s, "=======================================\n"}; 157 | `uvm_info(get_type_name(), s, UVM_HIGH) 158 | endfunction 159 | endclass: chnl_data_sequence 160 | 161 | typedef struct packed { 162 | bit[31:0] data; 163 | bit[1:0] id; 164 | } mon_data_t; 165 | 166 | // channel monitor 167 | class chnl_monitor extends uvm_monitor; 168 | local virtual chnl_intf intf; 169 | uvm_blocking_put_port #(mon_data_t) mon_bp_port; 170 | 171 | `uvm_component_utils(chnl_monitor) 172 | 173 | function new(string name="chnl_monitor", uvm_component parent); 174 | super.new(name, parent); 175 | mon_bp_port = new("mon_bp_port", this); 176 | endfunction 177 | 178 | function void set_interface(virtual chnl_intf intf); 179 | if(intf == null) 180 | $error("interface handle is NULL, please check if target interface has been intantiated"); 181 | else 182 | this.intf = intf; 183 | endfunction 184 | 185 | task run_phase(uvm_phase phase); 186 | this.mon_trans(); 187 | endtask 188 | 189 | task mon_trans(); 190 | mon_data_t m; 191 | forever begin 192 | @(posedge intf.clk iff (intf.mon_ck.ch_valid==='b1 && intf.mon_ck.ch_ready==='b1)); 193 | m.data = intf.mon_ck.ch_data; 194 | mon_bp_port.put(m); 195 | `uvm_info(get_type_name(), $sformatf("monitored channel data 'h%8x", m.data), UVM_HIGH) 196 | end 197 | endtask 198 | endclass: chnl_monitor 199 | 200 | // channel agent 201 | class chnl_agent extends uvm_agent; 202 | chnl_driver driver; 203 | chnl_monitor monitor; 204 | chnl_sequencer sequencer; 205 | local virtual chnl_intf vif; 206 | 207 | `uvm_component_utils(chnl_agent) 208 | 209 | function new(string name = "chnl_agent", uvm_component parent); 210 | super.new(name, parent); 211 | endfunction 212 | 213 | function void build_phase(uvm_phase phase); 214 | super.build_phase(phase); 215 | driver = chnl_driver::type_id::create("driver", this); 216 | monitor = chnl_monitor::type_id::create("monitor", this); 217 | sequencer = chnl_sequencer::type_id::create("sequencer", this); 218 | endfunction 219 | 220 | function void connect_phase(uvm_phase phase); 221 | super.connect_phase(phase); 222 | driver.seq_item_port.connect(sequencer.seq_item_export); 223 | endfunction 224 | 225 | function void set_interface(virtual chnl_intf vif); 226 | this.vif = vif; 227 | driver.set_interface(vif); 228 | monitor.set_interface(vif); 229 | endfunction 230 | endclass: chnl_agent 231 | 232 | endpackage 233 | 234 | -------------------------------------------------------------------------------- /uvm_verification_case/fmt_pkg.sv: -------------------------------------------------------------------------------- 1 | 2 | package fmt_pkg; 3 | import uvm_pkg::*; 4 | `include "uvm_macros.svh" 5 | 6 | typedef enum {SHORT_FIFO, MED_FIFO, LONG_FIFO, ULTRA_FIFO} fmt_fifo_t; 7 | typedef enum {LOW_WIDTH, MED_WIDTH, HIGH_WIDTH, ULTRA_WIDTH} fmt_bandwidth_t; 8 | 9 | // formatter sequence item 10 | class fmt_trans extends uvm_sequence_item; 11 | rand fmt_fifo_t fifo; 12 | rand fmt_bandwidth_t bandwidth; 13 | bit [9:0] length; 14 | bit [31:0] data[]; 15 | bit [1:0] ch_id; 16 | bit rsp; 17 | 18 | constraint cstr{ 19 | soft fifo == MED_FIFO; 20 | soft bandwidth == MED_WIDTH; 21 | }; 22 | 23 | `uvm_object_utils_begin(fmt_trans) 24 | `uvm_field_enum(fmt_fifo_t, fifo, UVM_ALL_ON) 25 | `uvm_field_enum(fmt_bandwidth_t, bandwidth, UVM_ALL_ON) 26 | `uvm_field_int(length, UVM_ALL_ON) 27 | `uvm_field_array_int(data, UVM_ALL_ON) 28 | `uvm_field_int(ch_id, UVM_ALL_ON) 29 | `uvm_field_int(rsp, UVM_ALL_ON) 30 | `uvm_object_utils_end 31 | 32 | function new (string name = "fmt_trans"); 33 | super.new(name); 34 | endfunction 35 | endclass 36 | 37 | // formatter driver 38 | class fmt_driver extends uvm_driver #(fmt_trans); 39 | local virtual fmt_intf intf; 40 | 41 | local mailbox #(bit[31:0]) fifo; 42 | local int fifo_bound; 43 | local int data_consum_peroid; 44 | 45 | `uvm_component_utils(fmt_driver) 46 | 47 | function new (string name = "fmt_driver", uvm_component parent); 48 | super.new(name, parent); 49 | this.fifo = new(); 50 | this.fifo_bound = 4096; 51 | this.data_consum_peroid = 1; 52 | endfunction 53 | 54 | function void set_interface(virtual fmt_intf intf); 55 | if(intf == null) 56 | $error("interface handle is NULL, please check if target interface has been intantiated"); 57 | else 58 | this.intf = intf; 59 | endfunction 60 | 61 | task run_phase(uvm_phase phase); 62 | fork 63 | this.do_receive(); 64 | this.do_consume(); 65 | this.do_config(); 66 | this.do_reset(); 67 | join 68 | endtask 69 | 70 | task do_config(); 71 | fmt_trans req, rsp; 72 | forever begin 73 | seq_item_port.get_next_item(req); 74 | case(req.fifo) 75 | SHORT_FIFO: this.fifo_bound = 64; 76 | MED_FIFO: this.fifo_bound = 256; 77 | LONG_FIFO: this.fifo_bound = 512; 78 | ULTRA_FIFO: this.fifo_bound = 2048; 79 | endcase 80 | this.fifo = new(this.fifo_bound); 81 | case(req.bandwidth) 82 | LOW_WIDTH: this.data_consum_peroid = 8; 83 | MED_WIDTH: this.data_consum_peroid = 4; 84 | HIGH_WIDTH: this.data_consum_peroid = 2; 85 | ULTRA_WIDTH: this.data_consum_peroid = 1; 86 | endcase 87 | //copy默认创建好了对象,只需要对数据进行拷贝; 88 | //clone自动创建对象并对source obiect进行数据拷贝,再返回target object句柄 89 | void'($cast(rsp, req.clone())); 90 | rsp.rsp = 1; 91 | rsp.set_sequence_id(req.get_sequence_id()); 92 | seq_item_port.item_done(rsp); 93 | end 94 | endtask 95 | 96 | task do_reset(); 97 | forever begin 98 | @(negedge intf.rstn) 99 | intf.fmt_grant <= 0; 100 | end 101 | endtask 102 | 103 | task do_receive(); 104 | forever begin 105 | @(posedge intf.fmt_req); 106 | forever begin 107 | @(posedge intf.clk); 108 | if((this.fifo_bound-this.fifo.num()) >= intf.fmt_length) 109 | break; 110 | end 111 | intf.drv_ck.fmt_grant <= 1; 112 | @(posedge intf.fmt_start); 113 | fork 114 | begin 115 | @(posedge intf.clk); 116 | intf.drv_ck.fmt_grant <= 0; 117 | end 118 | join_none 119 | repeat(intf.fmt_length) begin 120 | @(negedge intf.clk); 121 | this.fifo.put(intf.fmt_data); 122 | end 123 | end 124 | endtask 125 | 126 | task do_consume(); 127 | bit[31:0] data; 128 | forever begin 129 | void'(this.fifo.try_get(data)); 130 | repeat($urandom_range(1, this.data_consum_peroid)) @(posedge intf.clk); 131 | end 132 | endtask 133 | endclass: fmt_driver 134 | 135 | class fmt_sequencer extends uvm_sequencer #(fmt_trans); 136 | `uvm_component_utils(fmt_sequencer) 137 | function new (string name = "fmt_sequencer", uvm_component parent); 138 | super.new(name, parent); 139 | endfunction 140 | endclass: fmt_sequencer 141 | 142 | 143 | class fmt_config_sequence extends uvm_sequence #(fmt_trans); 144 | rand fmt_fifo_t fifo = MED_FIFO; 145 | rand fmt_bandwidth_t bandwidth = MED_WIDTH; 146 | constraint cstr{ 147 | soft fifo == MED_FIFO; 148 | soft bandwidth == MED_WIDTH; 149 | } 150 | 151 | `uvm_object_utils_begin(fmt_config_sequence) 152 | `uvm_field_enum(fmt_fifo_t, fifo, UVM_ALL_ON) 153 | `uvm_field_enum(fmt_bandwidth_t, bandwidth, UVM_ALL_ON) 154 | `uvm_object_utils_end 155 | `uvm_declare_p_sequencer(fmt_sequencer) 156 | 157 | function new (string name = "fmt_config_sequence"); 158 | super.new(name); 159 | endfunction 160 | 161 | task body(); 162 | send_trans(); 163 | endtask 164 | 165 | task send_trans(); 166 | fmt_trans req, rsp; 167 | `uvm_do_with(req, {local::fifo != MED_FIFO -> fifo == local::fifo; 168 | local::bandwidth != MED_WIDTH -> bandwidth == local::bandwidth; 169 | }) 170 | `uvm_info(get_type_name(), req.sprint(), UVM_HIGH) 171 | get_response(rsp); 172 | `uvm_info(get_type_name(), rsp.sprint(), UVM_HIGH) 173 | assert(rsp.rsp) 174 | else $error("[RSPERR] %0t error response received!", $time); 175 | endtask 176 | 177 | function void post_randomize(); 178 | string s; 179 | s = {s, "AFTER RANDOMIZATION \n"}; 180 | s = {s, "=======================================\n"}; 181 | s = {s, "fmt_config_sequence object content is as below: \n"}; 182 | s = {s, super.sprint()}; 183 | s = {s, "=======================================\n"}; 184 | `uvm_info(get_type_name(), s, UVM_HIGH) 185 | endfunction 186 | endclass: fmt_config_sequence 187 | 188 | // formatter monitor 189 | class fmt_monitor extends uvm_monitor; 190 | local string name; 191 | local virtual fmt_intf intf; 192 | uvm_blocking_put_port #(fmt_trans) mon_bp_port; 193 | 194 | `uvm_component_utils(fmt_monitor) 195 | 196 | function new(string name="fmt_monitor", uvm_component parent); 197 | super.new(name, parent); 198 | mon_bp_port = new("mon_bp_port", this); 199 | endfunction 200 | 201 | function void set_interface(virtual fmt_intf intf); 202 | if(intf == null) 203 | $error("interface handle is NULL, please check if target interface has been intantiated"); 204 | else 205 | this.intf = intf; 206 | endfunction 207 | 208 | task run_phase(uvm_phase phase); 209 | this.mon_trans(); 210 | endtask 211 | 212 | task mon_trans(); 213 | fmt_trans m; 214 | string s; 215 | forever begin 216 | @(posedge intf.mon_ck.fmt_start); 217 | m = new(); 218 | m.length = intf.mon_ck.fmt_length; 219 | m.ch_id = intf.mon_ck.fmt_chid; 220 | m.data = new[m.length]; 221 | foreach(m.data[i]) begin 222 | @(posedge intf.clk); 223 | m.data[i] = intf.mon_ck.fmt_data; 224 | end 225 | mon_bp_port.put(m); 226 | s = $sformatf("=======================================\n"); 227 | s = {s, $sformatf("%0t %s monitored a packet: \n", $time, this.m_name)}; 228 | s = {s, $sformatf("length = %0d: \n", m.length)}; 229 | s = {s, $sformatf("chid = %0d: \n", m.ch_id)}; 230 | foreach(m.data[i]) s = {s, $sformatf("data[%0d] = %8x \n", i, m.data[i])}; 231 | s = {s, $sformatf("=======================================\n")}; 232 | `uvm_info(get_type_name(), s, UVM_HIGH) 233 | end 234 | endtask 235 | endclass: fmt_monitor 236 | 237 | // formatter agent 238 | class fmt_agent extends uvm_agent; 239 | fmt_driver driver; 240 | fmt_monitor monitor; 241 | fmt_sequencer sequencer; 242 | local virtual fmt_intf vif; 243 | 244 | `uvm_component_utils(fmt_agent) 245 | 246 | function new(string name = "chnl_agent", uvm_component parent); 247 | super.new(name, parent); 248 | endfunction 249 | 250 | function void build_phase(uvm_phase phase); 251 | super.build_phase(phase); 252 | driver = fmt_driver::type_id::create("driver", this); 253 | monitor = fmt_monitor::type_id::create("monitor", this); 254 | sequencer = fmt_sequencer::type_id::create("sequencer", this); 255 | endfunction 256 | 257 | function void connect_phase(uvm_phase phase); 258 | super.connect_phase(phase); 259 | driver.seq_item_port.connect(sequencer.seq_item_export); 260 | endfunction 261 | 262 | function void set_interface(virtual fmt_intf vif); 263 | this.vif = vif; 264 | driver.set_interface(vif); 265 | monitor.set_interface(vif); 266 | endfunction 267 | endclass 268 | 269 | endpackage 270 | -------------------------------------------------------------------------------- /uvm_verification_case/reg_pkg.sv: -------------------------------------------------------------------------------- 1 | `include "param_def.v" 2 | 3 | package reg_pkg; 4 | import uvm_pkg::*; 5 | `include "uvm_macros.svh" 6 | 7 | // register sequence item 8 | class reg_trans extends uvm_sequence_item; 9 | rand bit[7:0] addr; 10 | rand bit[1:0] cmd; 11 | rand bit[31:0] data; 12 | bit rsp; 13 | 14 | constraint cstr { 15 | soft cmd inside {`WRITE, `READ, `IDLE}; 16 | soft addr inside {`SLV0_RW_ADDR, `SLV1_RW_ADDR, `SLV2_RW_ADDR, `SLV0_R_ADDR, `SLV1_R_ADDR, `SLV2_R_ADDR}; 17 | addr[7:4]==0 && cmd==`WRITE -> soft data[31:6]==0; 18 | soft addr[7:5]==0; 19 | addr[4]==1 -> soft cmd == `READ; 20 | }; 21 | 22 | `uvm_object_utils_begin(reg_trans) 23 | `uvm_field_int(addr, UVM_ALL_ON) 24 | `uvm_field_int(cmd, UVM_ALL_ON) 25 | `uvm_field_int(data, UVM_ALL_ON) 26 | `uvm_field_int(rsp, UVM_ALL_ON) 27 | `uvm_object_utils_end 28 | 29 | function new (string name = "reg_trans"); 30 | super.new(name); 31 | endfunction 32 | endclass 33 | 34 | // register driver 35 | class reg_driver extends uvm_driver #(reg_trans); 36 | local virtual reg_intf intf; 37 | 38 | `uvm_component_utils(reg_driver) 39 | 40 | function new (string name = "reg_driver", uvm_component parent); 41 | super.new(name, parent); 42 | endfunction 43 | 44 | function void set_interface(virtual reg_intf intf); 45 | if(intf == null) 46 | $error("interface handle is NULL, please check if target interface has been intantiated"); 47 | else 48 | this.intf = intf; 49 | endfunction 50 | 51 | task run_phase(uvm_phase phase); 52 | fork 53 | this.do_drive(); 54 | this.do_reset(); 55 | join 56 | endtask 57 | 58 | task do_reset(); 59 | forever begin 60 | @(negedge intf.rstn); 61 | intf.cmd_addr <= 0; 62 | intf.cmd <= `IDLE; 63 | intf.cmd_data_m2s <= 0; 64 | end 65 | endtask 66 | 67 | task do_drive(); 68 | reg_trans req, rsp; 69 | @(posedge intf.rstn); 70 | forever begin 71 | seq_item_port.get_next_item(req); 72 | this.reg_write(req); 73 | void'($cast(rsp, req.clone())); 74 | rsp.rsp = 1; 75 | rsp.set_sequence_id(req.get_sequence_id()); 76 | seq_item_port.item_done(rsp); 77 | end 78 | endtask 79 | 80 | task reg_write(reg_trans t); 81 | @(posedge intf.clk iff intf.rstn); 82 | case(t.cmd) 83 | `WRITE: begin 84 | intf.drv_ck.cmd_addr <= t.addr; 85 | intf.drv_ck.cmd <= t.cmd; 86 | intf.drv_ck.cmd_data_m2s <= t.data; 87 | end 88 | `READ: begin 89 | intf.drv_ck.cmd_addr <= t.addr; 90 | intf.drv_ck.cmd <= t.cmd; 91 | repeat(2) @(negedge intf.clk); 92 | t.data = intf.cmd_data_s2m; 93 | end 94 | `IDLE: begin 95 | this.reg_idle(); 96 | end 97 | default: $error("command %b is illegal", t.cmd); 98 | endcase 99 | `uvm_info(get_type_name(), $sformatf("sent addr %2x, cmd %2b, data %8x", t.addr, t.cmd, t.data), UVM_HIGH) 100 | endtask 101 | 102 | task reg_idle(); 103 | @(posedge intf.clk); 104 | intf.drv_ck.cmd_addr <= 0; 105 | intf.drv_ck.cmd <= `IDLE; 106 | intf.drv_ck.cmd_data_m2s <= 0; 107 | endtask 108 | endclass 109 | 110 | class reg_sequencer extends uvm_sequencer #(reg_trans); 111 | `uvm_component_utils(reg_sequencer) 112 | function new (string name = "reg_sequencer", uvm_component parent); 113 | super.new(name, parent); 114 | endfunction 115 | endclass: reg_sequencer 116 | 117 | class reg_base_sequence extends uvm_sequence #(reg_trans); 118 | rand bit[7:0] addr = -1; 119 | rand bit[1:0] cmd = -1; 120 | rand bit[31:0] data = -1; 121 | 122 | constraint cstr{ 123 | soft addr == -1; 124 | soft cmd == -1; 125 | soft data == -1; 126 | } 127 | 128 | `uvm_object_utils_begin(reg_base_sequence) 129 | `uvm_field_int(addr, UVM_ALL_ON) 130 | `uvm_field_int(cmd, UVM_ALL_ON) 131 | `uvm_field_int(data, UVM_ALL_ON) 132 | `uvm_object_utils_end 133 | `uvm_declare_p_sequencer(reg_sequencer) 134 | 135 | function new (string name = "reg_base_sequence"); 136 | super.new(name); 137 | endfunction 138 | 139 | task body(); 140 | send_trans(); 141 | endtask 142 | 143 | // generate transaction and put into local mailbox 144 | task send_trans(); 145 | reg_trans req, rsp; 146 | `uvm_do_with(req, {local::addr >= 0 -> addr == local::addr; 147 | local::cmd >= 0 -> cmd == local::cmd; 148 | local::data >= 0 -> data == local::data; 149 | }) 150 | `uvm_info(get_type_name(), req.sprint(), UVM_HIGH) 151 | get_response(rsp); 152 | `uvm_info(get_type_name(), rsp.sprint(), UVM_HIGH) 153 | if(req.cmd == `READ) 154 | this.data = rsp.data; 155 | assert(rsp.rsp) 156 | else $error("[RSPERR] %0t error response received!", $time); 157 | endtask 158 | 159 | function void post_randomize(); 160 | string s; 161 | s = {s, "AFTER RANDOMIZATION \n"}; 162 | s = {s, "=======================================\n"}; 163 | s = {s, "reg_base_sequence object content is as below: \n"}; 164 | s = {s, super.sprint()}; 165 | s = {s, "=======================================\n"}; 166 | `uvm_info(get_type_name(), s, UVM_HIGH) 167 | endfunction 168 | endclass: reg_base_sequence 169 | 170 | class idle_reg_sequence extends reg_base_sequence; 171 | constraint cstr{ 172 | addr == 0; 173 | cmd == `IDLE; 174 | data == 0; 175 | } 176 | `uvm_object_utils(idle_reg_sequence) 177 | function new (string name = "idle_reg_sequence"); 178 | super.new(name); 179 | endfunction 180 | endclass: idle_reg_sequence 181 | 182 | class write_reg_sequence extends reg_base_sequence; 183 | constraint cstr{ 184 | cmd == `WRITE; 185 | } 186 | `uvm_object_utils(write_reg_sequence) 187 | function new (string name = "write_reg_sequence"); 188 | super.new(name); 189 | endfunction 190 | endclass: write_reg_sequence 191 | 192 | class read_reg_sequence extends reg_base_sequence; 193 | constraint cstr{ 194 | cmd == `READ; 195 | } 196 | `uvm_object_utils(read_reg_sequence) 197 | function new (string name = "read_reg_sequence"); 198 | super.new(name); 199 | endfunction 200 | endclass: read_reg_sequence 201 | 202 | // register monitor 203 | class reg_monitor extends uvm_monitor; 204 | local virtual reg_intf intf; 205 | uvm_blocking_put_port #(reg_trans) mon_bp_port; 206 | uvm_analysis_port #(reg_trans) mon_ana_port; 207 | 208 | `uvm_component_utils(reg_monitor) 209 | 210 | function new(string name="reg_monitor", uvm_component parent); 211 | super.new(name, parent); 212 | mon_bp_port = new("mon_bp_port", this); 213 | mon_ana_port = new("mon_ana_port", this); 214 | endfunction 215 | 216 | function void set_interface(virtual reg_intf intf); 217 | if(intf == null) 218 | $error("interface handle is NULL, please check if target interface has been intantiated"); 219 | else 220 | this.intf = intf; 221 | endfunction 222 | 223 | task run_phase(uvm_phase phase); 224 | this.mon_trans(); 225 | endtask 226 | 227 | task mon_trans(); 228 | reg_trans m; 229 | forever begin 230 | @(posedge intf.clk iff (intf.rstn && intf.mon_ck.cmd != `IDLE)); 231 | m = new(); 232 | m.addr = intf.mon_ck.cmd_addr; 233 | m.cmd = intf.mon_ck.cmd; 234 | if(intf.mon_ck.cmd == `WRITE) begin 235 | m.data = intf.mon_ck.cmd_data_m2s; 236 | end 237 | else if(intf.mon_ck.cmd == `READ) begin 238 | @(posedge intf.clk); 239 | m.data = intf.mon_ck.cmd_data_s2m; 240 | end 241 | mon_bp_port.put(m); 242 | mon_ana_port.write(m); 243 | `uvm_info(get_type_name(), $sformatf("monitored addr %2x, cmd %2b, data %8x", m.addr, m.cmd, m.data), UVM_HIGH) 244 | end 245 | endtask 246 | endclass: reg_monitor 247 | 248 | // register agent 249 | class reg_agent extends uvm_agent; 250 | reg_driver driver; 251 | reg_monitor monitor; 252 | reg_sequencer sequencer; 253 | local virtual reg_intf vif; 254 | 255 | `uvm_component_utils(reg_agent) 256 | 257 | function new(string name = "reg_agent", uvm_component parent); 258 | super.new(name, parent); 259 | endfunction 260 | 261 | function void build_phase(uvm_phase phase); 262 | super.build_phase(phase); 263 | driver = reg_driver::type_id::create("driver", this); 264 | monitor = reg_monitor::type_id::create("monitor", this); 265 | sequencer = reg_sequencer::type_id::create("sequencer", this); 266 | endfunction 267 | 268 | function void connect_phase(uvm_phase phase); 269 | super.connect_phase(phase); 270 | driver.seq_item_port.connect(sequencer.seq_item_export); 271 | endfunction 272 | 273 | function void set_interface(virtual reg_intf vif); 274 | this.vif = vif; 275 | driver.set_interface(vif); 276 | monitor.set_interface(vif); 277 | endfunction 278 | endclass 279 | 280 | endpackage 281 | -------------------------------------------------------------------------------- /sv_verification_case/fmt_pkg.sv: -------------------------------------------------------------------------------- 1 | package fmt_pkg; 2 | //需要模拟一个与设计相符的buffer 3 | import rpt_pkg::*; 4 | 5 | typedef enum {SHORT_FIFO, MED_FIFO, LONG_FIFO, ULTRA_FIFO} fmt_fifo_t; 6 | typedef enum {LOW_WIDTH, MED_WIDTH, HIGH_WIDTH, ULTRA_WIDTH} fmt_bandwidth_t; 7 | 8 | class fmt_trans; 9 | rand fmt_fifo_t fifo; 10 | rand fmt_bandwidth_t bandwidth; 11 | bit [9:0] length; 12 | bit [31:0] data[]; 13 | bit [1:0] ch_id; 14 | bit rsp; 15 | constraint cstr{ 16 | soft fifo == MED_FIFO; 17 | soft bandwidth == MED_WIDTH; 18 | }; 19 | function fmt_trans clone(); 20 | fmt_trans c = new(); 21 | c.fifo = this.fifo; 22 | c.bandwidth = this.bandwidth; 23 | c.length = this.length; 24 | c.data = this.data; 25 | c.ch_id = this.ch_id; 26 | c.rsp = this.rsp; 27 | return c; 28 | endfunction 29 | 30 | function string sprint(); 31 | string s; 32 | s = {s, $sformatf("=======================================\n")}; 33 | s = {s, $sformatf("fmt_trans object content is as below: \n")}; 34 | s = {s, $sformatf("fifo = %s: \n", this.fifo)}; 35 | s = {s, $sformatf("bandwidth = %s: \n", this.bandwidth)}; 36 | s = {s, $sformatf("length = %s: \n", this.length)}; 37 | foreach(data[i]) s = {s, $sformatf("data[%0d] = %8x \n", i, this.data[i])}; 38 | s = {s, $sformatf("ch_id = %0d: \n", this.ch_id)}; 39 | s = {s, $sformatf("rsp = %0d: \n", this.rsp)}; 40 | s = {s, $sformatf("=======================================\n")}; 41 | return s; 42 | endfunction 43 | 44 | function bit compare(fmt_trans t); 45 | string s; 46 | compare = 1; 47 | s = "\n=======================================\n"; 48 | s = {s, $sformatf("COMPARING fmt_trans object at time %0d \n", $time)}; 49 | if(this.length != t.length) begin 50 | compare = 0; 51 | s = {s, $sformatf("sobj length %0d != tobj length %0d \n", this.length, t.length)}; 52 | end 53 | if(this.ch_id != t.ch_id) begin 54 | compare = 0; 55 | s = {s, $sformatf("sobj ch_id %0d != tobj ch_id %0d\n", this.ch_id, t.ch_id)}; 56 | end 57 | foreach(this.data[i]) begin 58 | if(this.data[i] != t.data[i]) begin 59 | compare = 0; 60 | s = {s, $sformatf("sobj data[%0d] %8x != tobj data[%0d] %8x\n", i, this.data[i], i, t.data[i])}; 61 | end 62 | end 63 | if(compare == 1) s = {s, "COMPARED SUCCESS!\n"}; 64 | else s = {s, "COMPARED FAILURE!\n"}; 65 | s = {s, "=======================================\n"}; 66 | rpt_pkg::rpt_msg("[CMPOBJ]", s, rpt_pkg::INFO, rpt_pkg::MEDIUM); 67 | endfunction 68 | endclass 69 | 70 | class fmt_driver; 71 | local string name; 72 | local virtual fmt_intf intf; 73 | mailbox #(fmt_trans) req_mb; 74 | mailbox #(fmt_trans) rsp_mb; 75 | 76 | local mailbox #(bit[31:0]) fifo; 77 | local int fifo_bound; 78 | local int data_consum_peroid; 79 | 80 | 81 | function new(string name = "fmt_driver"); 82 | this.name = name; 83 | this.fifo = new(); 84 | this.fifo_bound = 4096; 85 | this.data_consum_peroid = 1; 86 | endfunction 87 | 88 | function void set_interface(virtual fmt_intf intf); 89 | if(intf == null) 90 | $error("interface handle is NULL, please check if target interface has been intantiated"); 91 | else 92 | this.intf = intf; 93 | endfunction 94 | 95 | task run();//模拟硬件操作 96 | fork 97 | this.do_receive(); 98 | this.do_consume(); 99 | this.do_config(); 100 | this.do_reset(); 101 | join 102 | endtask 103 | 104 | task do_config(); 105 | fmt_trans req, rsp; 106 | forever begin 107 | this.req_mb.get(req); 108 | case(req.fifo) 109 | SHORT_FIFO: this.fifo_bound = 64; 110 | MED_FIFO: this.fifo_bound = 256; 111 | LONG_FIFO: this.fifo_bound = 512; 112 | ULTRA_FIFO: this.fifo_bound = 2048; 113 | endcase 114 | this.fifo = new(this.fifo_bound); 115 | case(req.bandwidth) 116 | LOW_WIDTH: this.data_consum_peroid = 8; 117 | MED_WIDTH: this.data_consum_peroid = 4; 118 | HIGH_WIDTH: this.data_consum_peroid = 2; 119 | ULTRA_WIDTH: this.data_consum_peroid = 1; 120 | endcase 121 | rsp = req.clone(); 122 | rsp.rsp = 1; 123 | this.rsp_mb.put(rsp); 124 | end 125 | endtask 126 | 127 | task do_reset(); 128 | forever begin 129 | @(negedge intf.rstn) 130 | intf.fmt_grant <= 0; 131 | end 132 | endtask 133 | 134 | task do_receive(); 135 | forever begin 136 | @(posedge intf.fmt_req); 137 | forever begin 138 | @(posedge intf.clk); 139 | if((this.fifo_bound-this.fifo.num()) >= intf.fmt_length) 140 | break; 141 | end 142 | intf.drv_ck.fmt_grant <= 1;//余量大于一次读写长度 grant拉高1个周期 143 | @(posedge intf.fmt_start); 144 | fork 145 | begin 146 | @(posedge intf.clk); 147 | intf.drv_ck.fmt_grant <= 0; 148 | end 149 | join_none 150 | repeat(intf.fmt_length) begin 151 | @(negedge intf.clk); 152 | this.fifo.put(intf.fmt_data); 153 | end 154 | end 155 | endtask 156 | 157 | task do_consume(); 158 | bit[31:0] data; 159 | forever begin 160 | void'(this.fifo.try_get(data)); 161 | repeat($urandom_range(1, this.data_consum_peroid)) @(posedge intf.clk); 162 | end 163 | endtask 164 | endclass 165 | 166 | class fmt_generator; 167 | rand fmt_fifo_t fifo = MED_FIFO; 168 | rand fmt_bandwidth_t bandwidth = MED_WIDTH; 169 | 170 | mailbox #(fmt_trans) req_mb; 171 | mailbox #(fmt_trans) rsp_mb; 172 | 173 | constraint cstr{ 174 | soft fifo == MED_FIFO; 175 | soft bandwidth == MED_WIDTH; 176 | } 177 | 178 | function new(); 179 | this.req_mb = new(); 180 | this.rsp_mb = new(); 181 | endfunction 182 | 183 | task start(); 184 | send_trans(); 185 | endtask 186 | 187 | // generate transaction and put into local mailbox 188 | task send_trans(); 189 | fmt_trans req, rsp; 190 | req = new(); 191 | assert(req.randomize with {local::fifo != MED_FIFO -> fifo == local::fifo; 192 | local::bandwidth != MED_WIDTH -> bandwidth == local::bandwidth; 193 | }) 194 | else $fatal("[RNDFAIL] formatter packet randomization failure!"); 195 | $display(req.sprint()); 196 | this.req_mb.put(req); 197 | this.rsp_mb.get(rsp); 198 | $display(rsp.sprint()); 199 | assert(rsp.rsp) 200 | else $error("[RSPERR] %0t error response received!", $time); 201 | endtask 202 | 203 | function string sprint(); 204 | string s; 205 | s = {s, $sformatf("=======================================\n")}; 206 | s = {s, $sformatf("fmt_generator object content is as below: \n")}; 207 | s = {s, $sformatf("fifo = %s: \n", this.fifo)}; 208 | s = {s, $sformatf("bandwidth = %s: \n", this.bandwidth)}; 209 | s = {s, $sformatf("=======================================\n")}; 210 | return s; 211 | endfunction 212 | 213 | function void post_randomize(); 214 | string s; 215 | s = {"AFTER RANDOMIZATION \n", this.sprint()}; 216 | $display(s); 217 | endfunction 218 | 219 | endclass 220 | 221 | class fmt_monitor; 222 | local string name; 223 | local virtual fmt_intf intf; 224 | mailbox #(fmt_trans) mon_mb; 225 | function new(string name="fmt_monitor"); 226 | this.name = name; 227 | endfunction 228 | function void set_interface(virtual fmt_intf intf); 229 | if(intf == null) 230 | $error("interface handle is NULL, please check if target interface has been intantiated"); 231 | else 232 | this.intf = intf; 233 | endfunction 234 | 235 | task run(); 236 | this.mon_trans(); 237 | endtask 238 | 239 | task mon_trans(); 240 | fmt_trans m; 241 | string s; 242 | forever begin 243 | @(posedge intf.mon_ck.fmt_start); 244 | m = new(); 245 | m.length = intf.mon_ck.fmt_length; 246 | m.ch_id = intf.mon_ck.fmt_chid; 247 | m.data = new[m.length]; 248 | foreach(m.data[i]) begin 249 | @(posedge intf.clk); 250 | m.data[i] = intf.mon_ck.fmt_data; 251 | end 252 | mon_mb.put(m); 253 | s = $sformatf("=======================================\n"); 254 | s = {s, $sformatf("%0t %s monitored a packet: \n", $time, this.name)}; 255 | s = {s, $sformatf("length = %0d: \n", m.length)}; 256 | s = {s, $sformatf("chid = %0d: \n", m.ch_id)}; 257 | foreach(m.data[i]) s = {s, $sformatf("data[%0d] = %8x \n", i, m.data[i])}; 258 | s = {s, $sformatf("=======================================\n")}; 259 | $display(s); 260 | end 261 | endtask 262 | endclass 263 | 264 | class fmt_agent; 265 | local string name; 266 | fmt_driver driver; 267 | fmt_monitor monitor; 268 | local virtual fmt_intf vif; 269 | function new(string name = "fmt_agent"); 270 | this.name = name; 271 | this.driver = new({name, ".driver"}); 272 | this.monitor = new({name, ".monitor"}); 273 | endfunction 274 | 275 | function void set_interface(virtual fmt_intf vif); 276 | this.vif = vif; 277 | driver.set_interface(vif); 278 | monitor.set_interface(vif); 279 | endfunction 280 | task run(); 281 | fork 282 | driver.run(); 283 | monitor.run(); 284 | join 285 | endtask 286 | endclass 287 | 288 | endpackage 289 | -------------------------------------------------------------------------------- /sv_verification_case/mcdf_pkg_ref.sv: -------------------------------------------------------------------------------- 1 | `include "param_def.v" 2 | 3 | package mcdf_pkg; 4 | 5 | import chnl_pkg::*; 6 | import reg_pkg::*; 7 | import arb_pkg::*; 8 | import fmt_pkg::*; 9 | import rpt_pkg::*; 10 | 11 | typedef struct packed { 12 | bit[2:0] len; 13 | bit[1:0] prio; 14 | bit en; 15 | bit[7:0] avail; 16 | } mcdf_reg_t; 17 | 18 | typedef enum {RW_LEN, RW_PRIO, RW_EN, RD_AVAIL} mcdf_field_t; 19 | 20 | class mcdf_refmod; 21 | local virtual mcdf_intf intf; 22 | local string name; 23 | mcdf_reg_t regs[3]; 24 | mailbox #(reg_trans) reg_mb; 25 | mailbox #(mon_data_t) in_mbs[3]; 26 | mailbox #(fmt_trans) out_mbs[3]; 27 | 28 | function new(string name="mcdf_refmod"); 29 | this.name = name; 30 | foreach(this.out_mbs[i]) this.out_mbs[i] = new(); 31 | endfunction 32 | 33 | task run(); 34 | fork 35 | do_reset(); 36 | this.do_reg_update(); 37 | do_packet(0); 38 | do_packet(1); 39 | do_packet(2); 40 | join 41 | endtask 42 | 43 | task do_reg_update(); 44 | reg_trans t; 45 | forever begin 46 | this.reg_mb.get(t); 47 | if(t.addr[7:4] == 0 && t.cmd == `WRITE) begin 48 | this.regs[t.addr[3:2]].en = t.data[0]; 49 | this.regs[t.addr[3:2]].prio = t.data[2:1]; 50 | this.regs[t.addr[3:2]].len = t.data[5:3]; 51 | end 52 | else if(t.addr[7:4] == 1 && t.cmd == `READ) begin 53 | this.regs[t.addr[3:2]].avail = t.data[7:0]; 54 | end 55 | end 56 | endtask 57 | 58 | task do_packet(int id); 59 | fmt_trans ot; 60 | mon_data_t it; 61 | bit[2:0] len; 62 | forever begin 63 | this.in_mbs[id].peek(it); 64 | ot = new(); 65 | len = this.get_field_value(id, RW_LEN); 66 | ot.length = len > 3 ? 32 : 4 << len; 67 | ot.data = new[ot.length]; 68 | ot.ch_id = id; 69 | foreach(ot.data[m]) begin 70 | this.in_mbs[id].get(it); 71 | ot.data[m] = it.data; 72 | end 73 | this.out_mbs[id].put(ot); 74 | end 75 | endtask 76 | 77 | function int get_field_value(int id, mcdf_field_t f); 78 | case(f) 79 | RW_LEN: return regs[id].len; 80 | RW_PRIO: return regs[id].prio; 81 | RW_EN: return regs[id].en; 82 | RD_AVAIL: return regs[id].avail; 83 | endcase 84 | endfunction 85 | 86 | task do_reset(); 87 | forever begin 88 | @(negedge intf.rstn); 89 | foreach(regs[i]) begin 90 | regs[i].len = 'h0; 91 | regs[i].prio = 'h3; 92 | regs[i].en = 'h1; 93 | regs[i].avail = 'h20; 94 | end 95 | end 96 | endtask 97 | 98 | function void set_interface(virtual mcdf_intf intf); 99 | if(intf == null) 100 | $error("interface handle is NULL, please check if target interface has been intantiated"); 101 | else 102 | this.intf = intf; 103 | endfunction 104 | 105 | endclass 106 | 107 | class mcdf_checker; 108 | local string name; 109 | local int err_count; 110 | local int total_count; 111 | local int chnl_count[3]; 112 | local virtual chnl_intf chnl_vifs[3]; 113 | local virtual arb_intf arb_vif; 114 | local virtual mcdf_intf mcdf_vif; 115 | local mcdf_refmod refmod; 116 | mailbox #(mon_data_t) chnl_mbs[3]; 117 | mailbox #(fmt_trans) fmt_mb; 118 | mailbox #(reg_trans) reg_mb; 119 | mailbox #(fmt_trans) exp_mbs[3]; 120 | 121 | function new(string name="mcdf_checker"); 122 | this.name = name; 123 | foreach(this.chnl_mbs[i]) this.chnl_mbs[i] = new();//先例化实例 124 | this.fmt_mb = new(); 125 | this.reg_mb = new(); 126 | this.refmod = new(); 127 | foreach(this.refmod.in_mbs[i]) begin 128 | this.refmod.in_mbs[i] = this.chnl_mbs[i];//再做连接 129 | this.exp_mbs[i] = this.refmod.out_mbs[i]; 130 | end 131 | this.refmod.reg_mb = this.reg_mb; 132 | this.err_count = 0; 133 | this.total_count = 0; 134 | foreach(this.chnl_count[i]) this.chnl_count[i] = 0; 135 | endfunction 136 | 137 | function void set_interface(virtual mcdf_intf mcdf_vif, virtual chnl_intf chnl_vifs[3], virtual arb_intf arb_vif); 138 | if(mcdf_vif == null) 139 | $error("mcdf interface handle is NULL, please check if target interface has been intantiated"); 140 | else begin 141 | this.mcdf_vif = mcdf_vif; 142 | this.refmod.set_interface(mcdf_vif); 143 | end 144 | if(chnl_vifs[0] == null || chnl_vifs[1] == null || chnl_vifs[2] == null) 145 | $error("chnl interface handle is NULL, please check if target interface has been intantiated"); 146 | else begin 147 | this.chnl_vifs = chnl_vifs; 148 | end 149 | if(arb_vif == null) 150 | $error("arb interface handle is NULL, please check if target interface has been intantiated"); 151 | else begin 152 | this.arb_vif = arb_vif; 153 | end 154 | endfunction 155 | 156 | task run(); 157 | fork 158 | this.do_channel_disable_check(0); 159 | this.do_channel_disable_check(1); 160 | this.do_channel_disable_check(2); 161 | this.do_arbiter_priority_check(); 162 | this.do_compare(); 163 | this.refmod.run(); 164 | join 165 | endtask 166 | 167 | task do_compare(); 168 | fmt_trans expt, mont; 169 | bit cmp; 170 | forever begin 171 | this.fmt_mb.get(mont); 172 | this.exp_mbs[mont.ch_id].get(expt); 173 | cmp = mont.compare(expt); 174 | this.total_count++; 175 | this.chnl_count[mont.ch_id]++; 176 | if(cmp == 0) begin 177 | this.err_count++; 178 | rpt_pkg::rpt_msg("[CMPFAIL]", 179 | $sformatf("%0t %0dth times comparing but failed! MCDF monitored output packet is different with reference model output", $time, this.total_count), 180 | rpt_pkg::ERROR, 181 | rpt_pkg::TOP, 182 | rpt_pkg::LOG); 183 | end 184 | else begin 185 | rpt_pkg::rpt_msg("[CMPSUCD]", 186 | $sformatf("%0t %0dth times comparing and succeeded! MCDF monitored output packet is the same with reference model output", $time, this.total_count), 187 | rpt_pkg::INFO, 188 | rpt_pkg::HIGH); 189 | end 190 | end 191 | endtask 192 | 193 | task do_channel_disable_check(int id); 194 | forever begin 195 | @(posedge this.mcdf_vif.clk iff (this.mcdf_vif.rstn && this.mcdf_vif.mon_ck.chnl_en[id]===0)); 196 | if(this.chnl_vifs[id].mon_ck.ch_valid===1 && this.chnl_vifs[id].mon_ck.ch_ready===1) 197 | rpt_pkg::rpt_msg("[CHKERR]", 198 | $sformatf("ERROR! %0t when channel disabled, ready signal raised when valid high",$time), 199 | rpt_pkg::ERROR, 200 | rpt_pkg::TOP); 201 | end 202 | endtask 203 | 204 | task do_arbiter_priority_check(); 205 | int id; 206 | forever begin 207 | @(posedge this.arb_vif.clk iff (this.arb_vif.rstn && this.arb_vif.mon_ck.f2a_id_req===1)); 208 | id = this.get_slave_id_with_prio(); 209 | if(id >= 0) begin 210 | @(posedge this.arb_vif.clk); 211 | if(this.arb_vif.mon_ck.a2s_acks[id] !== 1) 212 | rpt_pkg::rpt_msg("[CHKERR]", 213 | $sformatf("ERROR! %0t arbiter received f2a_id_req===1 and channel[%0d] raising request with high priority, but is not granted by arbiter", $time, id), 214 | rpt_pkg::ERROR, 215 | rpt_pkg::TOP); 216 | end 217 | end 218 | endtask 219 | 220 | function int get_slave_id_with_prio(); 221 | int id=-1; 222 | int prio=999; 223 | foreach(this.arb_vif.mon_ck.slv_prios[i]) begin 224 | if(this.arb_vif.mon_ck.slv_prios[i] < prio && this.arb_vif.mon_ck.slv_reqs[i]===1) begin 225 | id = i; 226 | prio = this.arb_vif.mon_ck.slv_prios[i]; 227 | end 228 | end 229 | return id; 230 | endfunction 231 | 232 | function void do_report(); 233 | string s; 234 | s = "\n---------------------------------------------------------------\n"; 235 | s = {s, "CHECKER SUMMARY \n"}; 236 | s = {s, $sformatf("total comparison count: %0d \n", this.total_count)}; 237 | foreach(this.chnl_count[i]) s = {s, $sformatf(" channel[%0d] comparison count: %0d \n", i, this.chnl_count[i])}; 238 | s = {s, $sformatf("total error count: %0d \n", this.err_count)}; 239 | foreach(this.chnl_mbs[i]) begin 240 | if(this.chnl_mbs[i].num() != 0) 241 | s = {s, $sformatf("WARNING:: chnl_mbs[%0d] is not empty! size = %0d \n", i, this.chnl_mbs[i].num())}; 242 | end 243 | if(this.fmt_mb.num() != 0) 244 | s = {s, $sformatf("WARNING:: fmt_mb is not empty! size = %0d \n", this.fmt_mb.num())}; 245 | s = {s, "---------------------------------------------------------------\n"}; 246 | rpt_pkg::rpt_msg($sformatf("[%s]",this.name), s, rpt_pkg::INFO, rpt_pkg::TOP); 247 | endfunction 248 | endclass 249 | 250 | class mcdf_coverage; 251 | local virtual chnl_intf chnl_vifs[3]; 252 | local virtual arb_intf arb_vif; 253 | local virtual mcdf_intf mcdf_vif; 254 | local virtual reg_intf reg_vif; 255 | local virtual fmt_intf fmt_vif; 256 | local string name; 257 | local int delay_req_to_grant; 258 | 259 | covergroup cg_mcdf_reg_write_read; 260 | addr: coverpoint reg_vif.mon_ck.cmd_addr { 261 | //weight=0 说明 当前coverpoint会被收集,但是不会占任何权重 262 | type_option.weight = 0; 263 | bins slv0_rw_addr = {`SLV0_RW_ADDR}; 264 | bins slv1_rw_addr = {`SLV1_RW_ADDR}; 265 | bins slv2_rw_addr = {`SLV2_RW_ADDR}; 266 | bins slv0_r_addr = {`SLV0_R_ADDR }; 267 | bins slv1_r_addr = {`SLV1_R_ADDR }; 268 | bins slv2_r_addr = {`SLV2_R_ADDR }; 269 | } 270 | cmd: coverpoint reg_vif.mon_ck.cmd { 271 | type_option.weight = 0; 272 | bins write = {`WRITE}; 273 | bins read = {`READ}; 274 | bins idle = {`IDLE}; 275 | } 276 | cmdXaddr: cross cmd, addr { 277 | //由于上诉权重=0 所以需要二次声明 278 | bins slv0_rw_addr = binsof(addr.slv0_rw_addr); 279 | bins slv1_rw_addr = binsof(addr.slv1_rw_addr); 280 | bins slv2_rw_addr = binsof(addr.slv2_rw_addr); 281 | bins slv0_r_addr = binsof(addr.slv0_r_addr ); 282 | bins slv1_r_addr = binsof(addr.slv1_r_addr ); 283 | bins slv2_r_addr = binsof(addr.slv2_r_addr ); 284 | bins write = binsof(cmd.write); 285 | bins read = binsof(cmd.read ); 286 | bins idle = binsof(cmd.idle ); 287 | 288 | bins write_slv0_rw_addr = binsof(cmd.write) && binsof(addr.slv0_rw_addr); 289 | bins write_slv1_rw_addr = binsof(cmd.write) && binsof(addr.slv1_rw_addr); 290 | bins write_slv2_rw_addr = binsof(cmd.write) && binsof(addr.slv2_rw_addr); 291 | bins read_slv0_rw_addr = binsof(cmd.read) && binsof(addr.slv0_rw_addr); 292 | bins read_slv1_rw_addr = binsof(cmd.read) && binsof(addr.slv1_rw_addr); 293 | bins read_slv2_rw_addr = binsof(cmd.read) && binsof(addr.slv2_rw_addr); 294 | bins read_slv0_r_addr = binsof(cmd.read) && binsof(addr.slv0_r_addr); 295 | bins read_slv1_r_addr = binsof(cmd.read) && binsof(addr.slv1_r_addr); 296 | bins read_slv2_r_addr = binsof(cmd.read) && binsof(addr.slv2_r_addr); 297 | } 298 | endgroup 299 | 300 | covergroup cg_mcdf_reg_illegal_access; 301 | addr: coverpoint reg_vif.mon_ck.cmd_addr { 302 | type_option.weight = 0; 303 | //bins legal_rw []={};要求括号内所以元素都覆盖到 304 | bins legal_rw = {`SLV0_RW_ADDR, `SLV1_RW_ADDR, `SLV2_RW_ADDR}; 305 | bins legal_r = {`SLV0_R_ADDR, `SLV1_R_ADDR, `SLV2_R_ADDR}; 306 | bins illegal = {[8'h20:$], 8'hC, 8'h1C};//覆盖到一个元素即可 307 | } 308 | cmd: coverpoint reg_vif.mon_ck.cmd { 309 | type_option.weight = 0; 310 | bins write = {`WRITE}; 311 | bins read = {`READ}; 312 | } 313 | wdata: coverpoint reg_vif.mon_ck.cmd_data_m2s { 314 | type_option.weight = 0; 315 | bins legal = {[0:'h3F]}; 316 | bins illegal = {['h40:$]}; 317 | } 318 | rdata: coverpoint reg_vif.mon_ck.cmd_data_s2m { 319 | type_option.weight = 0; 320 | bins legal = {[0:'hFF]}; 321 | illegal_bins illegal = default; 322 | } 323 | cmdXaddrXdata: cross cmd, addr, wdata, rdata { 324 | bins addr_legal_rw = binsof(addr.legal_rw); 325 | bins addr_legal_r = binsof(addr.legal_r); 326 | bins addr_illegal = binsof(addr.illegal); 327 | bins cmd_write = binsof(cmd.write); 328 | bins cmd_read = binsof(cmd.read); 329 | bins wdata_legal = binsof(wdata.legal); 330 | bins wdata_illegal = binsof(wdata.illegal); 331 | bins rdata_legal = binsof(rdata.legal); 332 | bins write_illegal_addr = binsof(cmd.write) && binsof(addr.illegal); 333 | bins read_illegal_addr = binsof(cmd.read) && binsof(addr.illegal); 334 | bins write_illegal_rw_data = binsof(cmd.write) && binsof(addr.legal_rw) && binsof(wdata.illegal); 335 | bins write_illegal_r_data = binsof(cmd.write) && binsof(addr.legal_r) && binsof(wdata.illegal); 336 | } 337 | endgroup 338 | 339 | covergroup cg_channel_disable; 340 | ch0_en: coverpoint mcdf_vif.mon_ck.chnl_en[0] { 341 | type_option.weight = 0; 342 | wildcard bins en = {1'b1}; 343 | wildcard bins dis = {1'b0}; 344 | } 345 | ch1_en: coverpoint mcdf_vif.mon_ck.chnl_en[1] { 346 | type_option.weight = 0; 347 | wildcard bins en = {1'b1}; 348 | wildcard bins dis = {1'b0}; 349 | } 350 | ch2_en: coverpoint mcdf_vif.mon_ck.chnl_en[2] { 351 | type_option.weight = 0; 352 | wildcard bins en = {1'b1}; 353 | wildcard bins dis = {1'b0}; 354 | } 355 | ch0_vld: coverpoint chnl_vifs[0].mon_ck.ch_valid { 356 | type_option.weight = 0; 357 | bins hi = {1'b1}; 358 | bins lo = {1'b0}; 359 | } 360 | ch1_vld: coverpoint chnl_vifs[1].mon_ck.ch_valid { 361 | type_option.weight = 0; 362 | bins hi = {1'b1}; 363 | bins lo = {1'b0}; 364 | } 365 | ch2_vld: coverpoint chnl_vifs[2].mon_ck.ch_valid { 366 | type_option.weight = 0; 367 | bins hi = {1'b1}; 368 | bins lo = {1'b0}; 369 | } 370 | chenXchvld: cross ch0_en, ch1_en, ch2_en, ch0_vld, ch1_vld, ch2_vld { 371 | bins ch0_en = binsof(ch0_en.en); 372 | bins ch0_dis = binsof(ch0_en.dis); 373 | bins ch1_en = binsof(ch1_en.en); 374 | bins ch1_dis = binsof(ch1_en.dis); 375 | bins ch2_en = binsof(ch2_en.en); 376 | bins ch2_dis = binsof(ch2_en.dis); 377 | bins ch0_hi = binsof(ch0_vld.hi); 378 | bins ch0_lo = binsof(ch0_vld.lo); 379 | bins ch1_hi = binsof(ch1_vld.hi); 380 | bins ch1_lo = binsof(ch1_vld.lo); 381 | bins ch2_hi = binsof(ch2_vld.hi); 382 | bins ch2_lo = binsof(ch2_vld.lo); 383 | bins ch0_en_vld = binsof(ch0_en.en) && binsof(ch0_vld.hi); 384 | bins ch0_dis_vld = binsof(ch0_en.dis) && binsof(ch0_vld.hi); 385 | bins ch1_en_vld = binsof(ch1_en.en) && binsof(ch1_vld.hi); 386 | bins ch1_dis_vld = binsof(ch1_en.dis) && binsof(ch1_vld.hi); 387 | bins ch2_en_vld = binsof(ch2_en.en) && binsof(ch2_vld.hi); 388 | bins ch2_dis_vld = binsof(ch2_en.dis) && binsof(ch2_vld.hi); 389 | } 390 | endgroup 391 | 392 | covergroup cg_arbiter_priority; 393 | ch0_prio: coverpoint arb_vif.mon_ck.slv_prios[0] { 394 | bins ch_prio0 = {0}; 395 | bins ch_prio1 = {1}; 396 | bins ch_prio2 = {2}; 397 | bins ch_prio3 = {3}; 398 | } 399 | ch1_prio: coverpoint arb_vif.mon_ck.slv_prios[1] { 400 | bins ch_prio0 = {0}; 401 | bins ch_prio1 = {1}; 402 | bins ch_prio2 = {2}; 403 | bins ch_prio3 = {3}; 404 | } 405 | ch2_prio: coverpoint arb_vif.mon_ck.slv_prios[2] { 406 | bins ch_prio0 = {0}; 407 | bins ch_prio1 = {1}; 408 | bins ch_prio2 = {2}; 409 | bins ch_prio3 = {3}; 410 | } 411 | endgroup 412 | 413 | covergroup cg_formatter_length; 414 | id: coverpoint fmt_vif.mon_ck.fmt_chid { 415 | bins ch0 = {0}; 416 | bins ch1 = {1}; 417 | bins ch2 = {2}; 418 | illegal_bins illegal = default; 419 | } 420 | length: coverpoint fmt_vif.mon_ck.fmt_length { 421 | bins len4 = {4}; 422 | bins len8 = {8}; 423 | bins len16 = {16}; 424 | bins len32 = {32}; 425 | illegal_bins illegal = default; 426 | } 427 | endgroup 428 | 429 | covergroup cg_formatter_grant(); 430 | delay_req_to_grant: coverpoint this.delay_req_to_grant { 431 | bins delay1 = {1}; 432 | bins delay2 = {2}; 433 | bins delay3_or_more = {[3:10]}; 434 | illegal_bins illegal = {0}; 435 | } 436 | endgroup 437 | 438 | function new(string name="mcdf_coverage"); 439 | this.name = name; 440 | this.cg_mcdf_reg_write_read = new(); 441 | this.cg_mcdf_reg_illegal_access = new(); 442 | this.cg_channel_disable = new(); 443 | this.cg_arbiter_priority = new(); 444 | this.cg_formatter_length = new(); 445 | this.cg_formatter_grant = new(); 446 | endfunction 447 | 448 | task run(); 449 | fork 450 | this.do_reg_sample(); 451 | this.do_channel_sample(); 452 | this.do_arbiter_sample(); 453 | this.do_formater_sample(); 454 | join 455 | endtask 456 | 457 | task do_reg_sample(); 458 | forever begin 459 | @(posedge reg_vif.clk iff reg_vif.rstn); 460 | this.cg_mcdf_reg_write_read.sample(); 461 | this.cg_mcdf_reg_illegal_access.sample(); 462 | end 463 | endtask 464 | 465 | task do_channel_sample(); 466 | forever begin 467 | @(posedge mcdf_vif.clk iff mcdf_vif.rstn); 468 | if(chnl_vifs[0].mon_ck.ch_valid===1 469 | || chnl_vifs[1].mon_ck.ch_valid===1 470 | || chnl_vifs[2].mon_ck.ch_valid===1) 471 | this.cg_channel_disable.sample(); 472 | end 473 | endtask 474 | 475 | task do_arbiter_sample(); 476 | forever begin 477 | @(posedge arb_vif.clk iff arb_vif.rstn); 478 | if(arb_vif.slv_reqs[0]!==0 || arb_vif.slv_reqs[1]!==0 || arb_vif.slv_reqs[2]!==0) 479 | this.cg_arbiter_priority.sample(); 480 | end 481 | endtask 482 | 483 | task do_formater_sample(); 484 | fork 485 | forever begin 486 | @(posedge fmt_vif.clk iff fmt_vif.rstn); 487 | if(fmt_vif.mon_ck.fmt_req === 1) 488 | this.cg_formatter_length.sample(); 489 | end 490 | forever begin 491 | @(posedge fmt_vif.mon_ck.fmt_req); 492 | this.delay_req_to_grant = 0; 493 | forever begin 494 | if(fmt_vif.fmt_grant === 1) begin 495 | this.cg_formatter_grant.sample(); 496 | break; 497 | end 498 | else begin 499 | @(posedge fmt_vif.clk); 500 | this.delay_req_to_grant++; 501 | end 502 | end 503 | end 504 | join 505 | endtask 506 | 507 | function void do_report(); 508 | string s; 509 | s = "\n---------------------------------------------------------------\n"; 510 | s = {s, "COVERAGE SUMMARY \n"}; 511 | s = {s, $sformatf("total coverage: %.1f \n", $get_coverage())}; 512 | s = {s, $sformatf(" cg_mcdf_reg_write_read coverage: %.1f \n", this.cg_mcdf_reg_write_read.get_coverage())}; 513 | s = {s, $sformatf(" cg_mcdf_reg_illegal_access coverage: %.1f \n", this.cg_mcdf_reg_illegal_access.get_coverage())}; 514 | s = {s, $sformatf(" cg_channel_disable_test coverage: %.1f \n", this.cg_channel_disable.get_coverage())}; 515 | s = {s, $sformatf(" cg_arbiter_priority_test coverage: %.1f \n", this.cg_arbiter_priority.get_coverage())}; 516 | s = {s, $sformatf(" cg_formatter_length_test coverage: %.1f \n", this.cg_formatter_length.get_coverage())}; 517 | s = {s, $sformatf(" cg_formatter_grant_test coverage: %.1f \n", this.cg_formatter_grant.get_coverage())}; 518 | s = {s, "---------------------------------------------------------------\n"}; 519 | rpt_pkg::rpt_msg($sformatf("[%s]",this.name), s, rpt_pkg::INFO, rpt_pkg::TOP); 520 | endfunction 521 | 522 | virtual function void set_interface(virtual chnl_intf ch_vifs[3] 523 | ,virtual reg_intf reg_vif 524 | ,virtual arb_intf arb_vif 525 | ,virtual fmt_intf fmt_vif 526 | ,virtual mcdf_intf mcdf_vif 527 | ); 528 | this.chnl_vifs = ch_vifs; 529 | this.arb_vif = arb_vif; 530 | this.reg_vif = reg_vif; 531 | this.fmt_vif = fmt_vif; 532 | this.mcdf_vif = mcdf_vif; 533 | if(chnl_vifs[0] == null || chnl_vifs[1] == null || chnl_vifs[2] == null) 534 | $error("chnl interface handle is NULL, please check if target interface has been intantiated"); 535 | if(arb_vif == null) 536 | $error("arb interface handle is NULL, please check if target interface has been intantiated"); 537 | if(reg_vif == null) 538 | $error("reg interface handle is NULL, please check if target interface has been intantiated"); 539 | if(fmt_vif == null) 540 | $error("fmt interface handle is NULL, please check if target interface has been intantiated"); 541 | if(mcdf_vif == null) 542 | $error("mcdf interface handle is NULL, please check if target interface has been intantiated"); 543 | endfunction 544 | endclass 545 | 546 | // mcdf_env connect chnl/reg/fmt.monitor and chker 547 | class mcdf_env; 548 | chnl_agent chnl_agts[3]; 549 | reg_agent reg_agt; 550 | fmt_agent fmt_agt; 551 | mcdf_checker chker; 552 | mcdf_coverage cvrg; 553 | protected string name; 554 | 555 | function new(string name = "mcdf_env"); 556 | this.name = name; 557 | this.chker = new(); 558 | foreach(chnl_agts[i]) begin 559 | this.chnl_agts[i] = new($sformatf("chnl_agts[%0d]",i)); 560 | this.chnl_agts[i].monitor.mon_mb = this.chker.chnl_mbs[i]; 561 | end 562 | this.reg_agt = new("reg_agt"); 563 | this.reg_agt.monitor.mon_mb = this.chker.reg_mb; 564 | this.fmt_agt = new("fmt_agt"); 565 | this.fmt_agt.monitor.mon_mb = this.chker.fmt_mb; 566 | this.cvrg = new(); 567 | $display("%s instantiated and connected objects", this.name); 568 | endfunction 569 | 570 | virtual task run(); 571 | $display($sformatf("*****************%s started********************", this.name)); 572 | this.do_config(); 573 | fork 574 | this.chnl_agts[0].run(); 575 | this.chnl_agts[1].run(); 576 | this.chnl_agts[2].run(); 577 | this.reg_agt.run(); 578 | this.fmt_agt.run(); 579 | this.chker.run(); 580 | this.cvrg.run(); 581 | join 582 | endtask 583 | 584 | virtual function void do_config(); 585 | endfunction 586 | 587 | virtual function void do_report(); 588 | this.chker.do_report(); 589 | this.cvrg.do_report(); 590 | endfunction 591 | 592 | endclass 593 | // mcdf_base_test connect chnl/reg/fmt.generator mailbox 594 | class mcdf_base_test; 595 | chnl_generator chnl_gens[3]; 596 | reg_generator reg_gen; 597 | fmt_generator fmt_gen; 598 | mcdf_env env; 599 | protected string name; 600 | local int timeout = 10; // 10 * ms 601 | 602 | function new(string name = "mcdf_base_test"); 603 | this.name = name; 604 | this.env = new("env"); 605 | 606 | foreach(this.chnl_gens[i]) begin 607 | this.chnl_gens[i] = new(); 608 | this.env.chnl_agts[i].driver.req_mb = this.chnl_gens[i].req_mb; 609 | this.env.chnl_agts[i].driver.rsp_mb = this.chnl_gens[i].rsp_mb; 610 | end 611 | 612 | this.reg_gen = new(); 613 | this.env.reg_agt.driver.req_mb = this.reg_gen.req_mb; 614 | this.env.reg_agt.driver.rsp_mb = this.reg_gen.rsp_mb; 615 | 616 | this.fmt_gen = new(); 617 | this.env.fmt_agt.driver.req_mb = this.fmt_gen.req_mb; 618 | this.env.fmt_agt.driver.rsp_mb = this.fmt_gen.rsp_mb; 619 | 620 | rpt_pkg::logname = {this.name, "_check.log"}; 621 | rpt_pkg::clean_log(); 622 | $display("%s instantiated and connected objects", this.name); 623 | endfunction 624 | 625 | virtual task run(); 626 | fork 627 | env.run(); 628 | join_none 629 | rpt_pkg::rpt_msg("[TEST]", 630 | $sformatf("=====================%s AT TIME %0t STARTED=====================", this.name, $time), 631 | rpt_pkg::INFO, 632 | rpt_pkg::HIGH); 633 | this.do_reg(); 634 | this.do_formatter(); 635 | fork 636 | this.do_data(); 637 | this.do_watchdog(); 638 | join_any 639 | rpt_pkg::rpt_msg("[TEST]", 640 | $sformatf("=====================%s AT TIME %0t FINISHED=====================", this.name, $time), 641 | rpt_pkg::INFO, 642 | rpt_pkg::HIGH); 643 | this.do_report(); 644 | $finish(); 645 | endtask 646 | 647 | // do register configuration 648 | virtual task do_reg(); 649 | endtask 650 | 651 | // do external formatter down stream slave configuration 652 | virtual task do_formatter(); 653 | endtask 654 | 655 | // do data transition from 3 channel slaves 656 | virtual task do_data(); 657 | endtask 658 | 659 | // timeout watchdog to avoid simulation pending 660 | virtual task do_watchdog(); 661 | rpt_pkg::rpt_msg("[TEST]", 662 | $sformatf("=====================%s AT TIME %0t WATCHDOG GUARDING=====================", this.name, $time), 663 | rpt_pkg::INFO, 664 | rpt_pkg::HIGH); 665 | #(this.timeout * 1ms); 666 | rpt_pkg::rpt_msg("[TEST]", 667 | $sformatf("=====================%s AT TIME %0t WATCHDOG BARKING=====================", this.name, $time), 668 | rpt_pkg::INFO, 669 | rpt_pkg::HIGH); 670 | endtask 671 | 672 | // do simulation summary 673 | virtual function void do_report(); 674 | this.env.do_report(); 675 | rpt_pkg::do_report(); 676 | endfunction 677 | 678 | virtual function void set_interface(virtual chnl_intf ch0_vif 679 | ,virtual chnl_intf ch1_vif 680 | ,virtual chnl_intf ch2_vif 681 | ,virtual reg_intf reg_vif 682 | ,virtual arb_intf arb_vif 683 | ,virtual fmt_intf fmt_vif 684 | ,virtual mcdf_intf mcdf_vif 685 | ); 686 | this.env.chnl_agts[0].set_interface(ch0_vif); 687 | this.env.chnl_agts[1].set_interface(ch1_vif); 688 | this.env.chnl_agts[2].set_interface(ch2_vif); 689 | this.env.reg_agt.set_interface(reg_vif); 690 | this.env.fmt_agt.set_interface(fmt_vif); 691 | this.env.chker.set_interface(mcdf_vif, '{ch0_vif, ch1_vif, ch2_vif}, arb_vif); 692 | this.env.cvrg.set_interface('{ch0_vif, ch1_vif, ch2_vif}, reg_vif, arb_vif, fmt_vif, mcdf_vif); 693 | endfunction 694 | 695 | virtual function bit diff_value(int val1, int val2, string id = "value_compare"); 696 | if(val1 != val2) begin 697 | rpt_pkg::rpt_msg("[CMPERR]", 698 | $sformatf("ERROR! %s val1 %8x != val2 %8x", id, val1, val2), 699 | rpt_pkg::ERROR, 700 | rpt_pkg::TOP); 701 | return 0; 702 | end 703 | else begin 704 | rpt_pkg::rpt_msg("[CMPSUC]", 705 | $sformatf("SUCCESS! %s val1 %8x == val2 %8x", id, val1, val2), 706 | rpt_pkg::INFO, 707 | rpt_pkg::HIGH); 708 | return 1; 709 | end 710 | endfunction 711 | 712 | virtual task idle_reg(); 713 | void'(reg_gen.randomize() with {cmd == `IDLE; addr == 0; data == 0;}); 714 | reg_gen.start(); 715 | endtask 716 | 717 | virtual task write_reg(bit[7:0] addr, bit[31:0] data); 718 | void'(reg_gen.randomize() with {cmd == `WRITE; addr == local::addr; data == local::data;}); 719 | reg_gen.start(); 720 | endtask 721 | 722 | virtual task read_reg(bit[7:0] addr, output bit[31:0] data); 723 | void'(reg_gen.randomize() with {cmd == `READ; addr == local::addr;}); 724 | reg_gen.start(); 725 | data = reg_gen.data; 726 | endtask 727 | endclass 728 | 729 | class mcdf_data_consistence_basic_test extends mcdf_base_test; 730 | function new(string name = "mcdf_data_consistence_basic_test"); 731 | super.new(name); 732 | endfunction 733 | 734 | task do_reg(); 735 | bit[31:0] wr_val, rd_val; 736 | // slv0 with len=8, prio=0, en=1 737 | wr_val = (1<<3)+(0<<1)+1; 738 | this.write_reg(`SLV0_RW_ADDR, wr_val); 739 | this.read_reg(`SLV0_RW_ADDR, rd_val); 740 | void'(this.diff_value(wr_val, rd_val, "SLV0_WR_REG")); 741 | 742 | // slv1 with len=16, prio=1, en=1 743 | wr_val = (2<<3)+(1<<1)+1; 744 | this.write_reg(`SLV1_RW_ADDR, wr_val); 745 | this.read_reg(`SLV1_RW_ADDR, rd_val); 746 | void'(this.diff_value(wr_val, rd_val, "SLV1_WR_REG")); 747 | 748 | // slv2 with len=32, prio=2, en=1 749 | wr_val = (3<<3)+(2<<1)+1; 750 | this.write_reg(`SLV2_RW_ADDR, wr_val); 751 | this.read_reg(`SLV2_RW_ADDR, rd_val); 752 | void'(this.diff_value(wr_val, rd_val, "SLV2_WR_REG")); 753 | 754 | // send IDLE command 755 | this.idle_reg(); 756 | endtask 757 | 758 | task do_formatter(); 759 | void'(fmt_gen.randomize() with {fifo == LONG_FIFO; bandwidth == HIGH_WIDTH;}); 760 | fmt_gen.start(); 761 | endtask 762 | 763 | task do_data(); 764 | void'(chnl_gens[0].randomize() with {ntrans==100; ch_id==0; data_nidles==0; pkt_nidles==1; data_size==8; }); 765 | void'(chnl_gens[1].randomize() with {ntrans==100; ch_id==1; data_nidles==1; pkt_nidles==4; data_size==16;}); 766 | void'(chnl_gens[2].randomize() with {ntrans==100; ch_id==2; data_nidles==2; pkt_nidles==8; data_size==32;}); 767 | fork 768 | chnl_gens[0].start(); 769 | chnl_gens[1].start(); 770 | chnl_gens[2].start(); 771 | join 772 | #10us; // wait until all data haven been transfered through MCDF 773 | endtask 774 | endclass 775 | 776 | // Vplan 1.1 registers.read_write_test 777 | class mcdf_reg_read_write_test extends mcdf_base_test; 778 | function new(string name = "mcdf_data_consistence_basic_test"); 779 | super.new(name); 780 | endfunction 781 | 782 | task do_reg(); 783 | bit[7:0] chnl_rw_addrs[] = '{`SLV0_RW_ADDR, `SLV1_RW_ADDR, `SLV2_RW_ADDR}; 784 | bit[7:0] chnl_ro_addrs[] = '{`SLV0_R_ADDR, `SLV1_R_ADDR, `SLV2_R_ADDR}; 785 | int pwidth = `PAC_LEN_WIDTH + `PRIO_WIDTH + 1; 786 | bit[31:0] check_pattern[] = '{32'h0000_C000, 32'hFFFF_0000}; 787 | bit[31:0] wr_val, rd_val; 788 | 789 | // RW register write reserved field and check 790 | foreach(chnl_rw_addrs[i]) begin 791 | foreach(check_pattern[i]) begin 792 | wr_val = check_pattern[i]; 793 | this.write_reg(chnl_rw_addrs[i], wr_val); 794 | this.read_reg(chnl_rw_addrs[i], rd_val); 795 | void'(this.diff_value(wr_val & ((1<= 0) begin 260 | @(posedge this.arb_vif.clk); 261 | if(this.arb_vif.mon_ck.a2s_acks[id] !== 1) 262 | `uvm_error("[CHKERR]", $sformatf("ERROR! arbiter received f2a_id_req===1 and channel[%0d] raising request with high priority, but is not granted by arbiter", id)) 263 | end 264 | end 265 | endtask 266 | 267 | function int get_slave_id_with_prio(); 268 | int id=-1; 269 | int prio=999; 270 | foreach(this.arb_vif.mon_ck.slv_prios[i]) begin 271 | if(this.arb_vif.mon_ck.slv_prios[i] < prio && this.arb_vif.mon_ck.slv_reqs[i]===1) begin 272 | id = i; 273 | prio = this.arb_vif.mon_ck.slv_prios[i]; 274 | end 275 | end 276 | return id; 277 | endfunction 278 | 279 | function void report_phase(uvm_phase phase); 280 | string s; 281 | super.report_phase(phase); 282 | s = "\n---------------------------------------------------------------\n"; 283 | s = {s, "CHECKER SUMMARY \n"}; 284 | s = {s, $sformatf("total comparison count: %0d \n", this.total_count)}; 285 | foreach(this.chnl_count[i]) s = {s, $sformatf(" channel[%0d] comparison count: %0d \n", i, this.chnl_count[i])}; 286 | s = {s, $sformatf("total error count: %0d \n", this.err_count)}; 287 | foreach(this.chnl_mbs[i]) begin 288 | if(this.chnl_mbs[i].num() != 0) 289 | s = {s, $sformatf("WARNING:: chnl_mbs[%0d] is not empty! size = %0d \n", i, this.chnl_mbs[i].num())}; 290 | end 291 | if(this.fmt_mb.num() != 0) 292 | s = {s, $sformatf("WARNING:: fmt_mb is not empty! size = %0d \n", this.fmt_mb.num())}; 293 | s = {s, "---------------------------------------------------------------\n"}; 294 | `uvm_info(get_type_name(), s, UVM_LOW) 295 | endfunction 296 | 297 | task put_chnl0(mon_data_t t); 298 | chnl_mbs[0].put(t); 299 | endtask 300 | task put_chnl1(mon_data_t t); 301 | chnl_mbs[1].put(t); 302 | endtask 303 | task put_chnl2(mon_data_t t); 304 | chnl_mbs[2].put(t); 305 | endtask 306 | task put_fmt(fmt_trans t); 307 | fmt_mb.put(t); 308 | endtask 309 | task put_reg(reg_trans t); 310 | reg_mb.put(t); 311 | endtask 312 | task peek_chnl0(output mon_data_t t); 313 | chnl_mbs[0].peek(t); 314 | endtask 315 | task peek_chnl1(output mon_data_t t); 316 | chnl_mbs[1].peek(t); 317 | endtask 318 | task peek_chnl2(output mon_data_t t); 319 | chnl_mbs[2].peek(t); 320 | endtask 321 | task get_chnl0(output mon_data_t t); 322 | chnl_mbs[0].get(t); 323 | endtask 324 | task get_chnl1(output mon_data_t t); 325 | chnl_mbs[1].get(t); 326 | endtask 327 | task get_chnl2(output mon_data_t t); 328 | chnl_mbs[2].get(t); 329 | endtask 330 | task get_reg(output reg_trans t); 331 | reg_mb.get(t); 332 | endtask 333 | endclass: mcdf_checker 334 | 335 | // MCDF coverage model 336 | class mcdf_coverage extends uvm_component; 337 | local virtual chnl_intf chnl_vifs[3]; 338 | local virtual arb_intf arb_vif; 339 | local virtual mcdf_intf mcdf_vif; 340 | local virtual reg_intf reg_vif; 341 | local virtual fmt_intf fmt_vif; 342 | local int delay_req_to_grant; 343 | 344 | `uvm_component_utils(mcdf_coverage) 345 | 346 | covergroup cg_mcdf_reg_write_read; 347 | addr: coverpoint reg_vif.mon_ck.cmd_addr { 348 | type_option.weight = 0; 349 | bins slv0_rw_addr = {`SLV0_RW_ADDR}; 350 | bins slv1_rw_addr = {`SLV1_RW_ADDR}; 351 | bins slv2_rw_addr = {`SLV2_RW_ADDR}; 352 | bins slv0_r_addr = {`SLV0_R_ADDR }; 353 | bins slv1_r_addr = {`SLV1_R_ADDR }; 354 | bins slv2_r_addr = {`SLV2_R_ADDR }; 355 | } 356 | cmd: coverpoint reg_vif.mon_ck.cmd { 357 | type_option.weight = 0; 358 | bins write = {`WRITE}; 359 | bins read = {`READ}; 360 | bins idle = {`IDLE}; 361 | } 362 | cmdXaddr: cross cmd, addr { 363 | bins slv0_rw_addr = binsof(addr.slv0_rw_addr); 364 | bins slv1_rw_addr = binsof(addr.slv1_rw_addr); 365 | bins slv2_rw_addr = binsof(addr.slv2_rw_addr); 366 | bins slv0_r_addr = binsof(addr.slv0_r_addr ); 367 | bins slv1_r_addr = binsof(addr.slv1_r_addr ); 368 | bins slv2_r_addr = binsof(addr.slv2_r_addr ); 369 | bins write = binsof(cmd.write); 370 | bins read = binsof(cmd.read ); 371 | bins idle = binsof(cmd.idle ); 372 | bins write_slv0_rw_addr = binsof(cmd.write) && binsof(addr.slv0_rw_addr); 373 | bins write_slv1_rw_addr = binsof(cmd.write) && binsof(addr.slv1_rw_addr); 374 | bins write_slv2_rw_addr = binsof(cmd.write) && binsof(addr.slv2_rw_addr); 375 | bins read_slv0_rw_addr = binsof(cmd.read) && binsof(addr.slv0_rw_addr); 376 | bins read_slv1_rw_addr = binsof(cmd.read) && binsof(addr.slv1_rw_addr); 377 | bins read_slv2_rw_addr = binsof(cmd.read) && binsof(addr.slv2_rw_addr); 378 | bins read_slv0_r_addr = binsof(cmd.read) && binsof(addr.slv0_r_addr); 379 | bins read_slv1_r_addr = binsof(cmd.read) && binsof(addr.slv1_r_addr); 380 | bins read_slv2_r_addr = binsof(cmd.read) && binsof(addr.slv2_r_addr); 381 | } 382 | endgroup 383 | 384 | covergroup cg_mcdf_reg_illegal_access; 385 | addr: coverpoint reg_vif.mon_ck.cmd_addr { 386 | type_option.weight = 0; 387 | bins legal_rw = {`SLV0_RW_ADDR, `SLV1_RW_ADDR, `SLV2_RW_ADDR}; 388 | bins legal_r = {`SLV0_R_ADDR, `SLV1_R_ADDR, `SLV2_R_ADDR}; 389 | bins illegal = {[8'h20:$], 8'hC, 8'h1C}; 390 | } 391 | cmd: coverpoint reg_vif.mon_ck.cmd { 392 | type_option.weight = 0; 393 | bins write = {`WRITE}; 394 | bins read = {`READ}; 395 | } 396 | wdata: coverpoint reg_vif.mon_ck.cmd_data_m2s { 397 | type_option.weight = 0; 398 | bins legal = {[0:'h3F]}; 399 | bins illegal = {['h40:$]}; 400 | } 401 | rdata: coverpoint reg_vif.mon_ck.cmd_data_s2m { 402 | type_option.weight = 0; 403 | bins legal = {[0:'hFF]}; 404 | illegal_bins illegal = default; 405 | } 406 | cmdXaddrXdata: cross cmd, addr, wdata, rdata { 407 | bins addr_legal_rw = binsof(addr.legal_rw); 408 | bins addr_legal_r = binsof(addr.legal_r); 409 | bins addr_illegal = binsof(addr.illegal); 410 | bins cmd_write = binsof(cmd.write); 411 | bins cmd_read = binsof(cmd.read); 412 | bins wdata_legal = binsof(wdata.legal); 413 | bins wdata_illegal = binsof(wdata.illegal); 414 | bins rdata_legal = binsof(rdata.legal); 415 | bins write_illegal_addr = binsof(cmd.write) && binsof(addr.illegal); 416 | bins read_illegal_addr = binsof(cmd.read) && binsof(addr.illegal); 417 | bins write_illegal_rw_data = binsof(cmd.write) && binsof(addr.legal_rw) && binsof(wdata.illegal); 418 | bins write_illegal_r_data = binsof(cmd.write) && binsof(addr.legal_r) && binsof(wdata.illegal); 419 | } 420 | endgroup 421 | 422 | covergroup cg_channel_disable; 423 | ch0_en: coverpoint mcdf_vif.mon_ck.chnl_en[0] { 424 | type_option.weight = 0; 425 | wildcard bins en = {1'b1}; 426 | wildcard bins dis = {1'b0}; 427 | } 428 | ch1_en: coverpoint mcdf_vif.mon_ck.chnl_en[1] { 429 | type_option.weight = 0; 430 | wildcard bins en = {1'b1}; 431 | wildcard bins dis = {1'b0}; 432 | } 433 | ch2_en: coverpoint mcdf_vif.mon_ck.chnl_en[2] { 434 | type_option.weight = 0; 435 | wildcard bins en = {1'b1}; 436 | wildcard bins dis = {1'b0}; 437 | } 438 | ch0_vld: coverpoint chnl_vifs[0].mon_ck.ch_valid { 439 | type_option.weight = 0; 440 | bins hi = {1'b1}; 441 | bins lo = {1'b0}; 442 | } 443 | ch1_vld: coverpoint chnl_vifs[1].mon_ck.ch_valid { 444 | type_option.weight = 0; 445 | bins hi = {1'b1}; 446 | bins lo = {1'b0}; 447 | } 448 | ch2_vld: coverpoint chnl_vifs[2].mon_ck.ch_valid { 449 | type_option.weight = 0; 450 | bins hi = {1'b1}; 451 | bins lo = {1'b0}; 452 | } 453 | chenXchvld: cross ch0_en, ch1_en, ch2_en, ch0_vld, ch1_vld, ch2_vld { 454 | bins ch0_en = binsof(ch0_en.en); 455 | bins ch0_dis = binsof(ch0_en.dis); 456 | bins ch1_en = binsof(ch1_en.en); 457 | bins ch1_dis = binsof(ch1_en.dis); 458 | bins ch2_en = binsof(ch2_en.en); 459 | bins ch2_dis = binsof(ch2_en.dis); 460 | bins ch0_hi = binsof(ch0_vld.hi); 461 | bins ch0_lo = binsof(ch0_vld.lo); 462 | bins ch1_hi = binsof(ch1_vld.hi); 463 | bins ch1_lo = binsof(ch1_vld.lo); 464 | bins ch2_hi = binsof(ch2_vld.hi); 465 | bins ch2_lo = binsof(ch2_vld.lo); 466 | bins ch0_en_vld = binsof(ch0_en.en) && binsof(ch0_vld.hi); 467 | bins ch0_dis_vld = binsof(ch0_en.dis) && binsof(ch0_vld.hi); 468 | bins ch1_en_vld = binsof(ch1_en.en) && binsof(ch1_vld.hi); 469 | bins ch1_dis_vld = binsof(ch1_en.dis) && binsof(ch1_vld.hi); 470 | bins ch2_en_vld = binsof(ch2_en.en) && binsof(ch2_vld.hi); 471 | bins ch2_dis_vld = binsof(ch2_en.dis) && binsof(ch2_vld.hi); 472 | } 473 | endgroup 474 | 475 | covergroup cg_arbiter_priority; 476 | ch0_prio: coverpoint arb_vif.mon_ck.slv_prios[0] { 477 | bins ch_prio0 = {0}; 478 | bins ch_prio1 = {1}; 479 | bins ch_prio2 = {2}; 480 | bins ch_prio3 = {3}; 481 | } 482 | ch1_prio: coverpoint arb_vif.mon_ck.slv_prios[1] { 483 | bins ch_prio0 = {0}; 484 | bins ch_prio1 = {1}; 485 | bins ch_prio2 = {2}; 486 | bins ch_prio3 = {3}; 487 | } 488 | ch2_prio: coverpoint arb_vif.mon_ck.slv_prios[2] { 489 | bins ch_prio0 = {0}; 490 | bins ch_prio1 = {1}; 491 | bins ch_prio2 = {2}; 492 | bins ch_prio3 = {3}; 493 | } 494 | endgroup 495 | 496 | covergroup cg_formatter_length; 497 | id: coverpoint fmt_vif.mon_ck.fmt_chid { 498 | bins ch0 = {0}; 499 | bins ch1 = {1}; 500 | bins ch2 = {2}; 501 | illegal_bins illegal = default; 502 | } 503 | length: coverpoint fmt_vif.mon_ck.fmt_length { 504 | bins len4 = {4}; 505 | bins len8 = {8}; 506 | bins len16 = {16}; 507 | bins len32 = {32}; 508 | illegal_bins illegal = default; 509 | } 510 | endgroup 511 | 512 | covergroup cg_formatter_grant(); 513 | delay_req_to_grant: coverpoint this.delay_req_to_grant { 514 | bins delay1 = {1}; 515 | bins delay2 = {2}; 516 | bins delay3_or_more = {[3:10]}; 517 | illegal_bins illegal = {0}; 518 | } 519 | endgroup 520 | 521 | function new (string name = "mcdf_coverage", uvm_component parent); 522 | super.new(name, parent); 523 | this.cg_mcdf_reg_write_read = new(); 524 | this.cg_mcdf_reg_illegal_access = new(); 525 | this.cg_channel_disable = new(); 526 | this.cg_arbiter_priority = new(); 527 | this.cg_formatter_length = new(); 528 | this.cg_formatter_grant = new(); 529 | endfunction 530 | 531 | task run_phase(uvm_phase phase); 532 | fork 533 | this.do_reg_sample(); 534 | this.do_channel_sample(); 535 | this.do_arbiter_sample(); 536 | this.do_formater_sample(); 537 | join 538 | endtask 539 | 540 | task do_reg_sample(); 541 | forever begin 542 | @(posedge reg_vif.clk iff reg_vif.rstn); 543 | this.cg_mcdf_reg_write_read.sample(); 544 | this.cg_mcdf_reg_illegal_access.sample(); 545 | end 546 | endtask 547 | 548 | task do_channel_sample(); 549 | forever begin 550 | @(posedge mcdf_vif.clk iff mcdf_vif.rstn); 551 | if(chnl_vifs[0].mon_ck.ch_valid===1 552 | || chnl_vifs[1].mon_ck.ch_valid===1 553 | || chnl_vifs[2].mon_ck.ch_valid===1) 554 | this.cg_channel_disable.sample(); 555 | end 556 | endtask 557 | 558 | task do_arbiter_sample(); 559 | forever begin 560 | @(posedge arb_vif.clk iff arb_vif.rstn); 561 | if(arb_vif.slv_reqs[0]!==0 || arb_vif.slv_reqs[1]!==0 || arb_vif.slv_reqs[2]!==0) 562 | this.cg_arbiter_priority.sample(); 563 | end 564 | endtask 565 | 566 | task do_formater_sample(); 567 | fork 568 | forever begin 569 | @(posedge fmt_vif.clk iff fmt_vif.rstn); 570 | if(fmt_vif.mon_ck.fmt_req === 1) 571 | this.cg_formatter_length.sample(); 572 | end 573 | forever begin 574 | @(posedge fmt_vif.mon_ck.fmt_req); 575 | this.delay_req_to_grant = 0; 576 | forever begin 577 | if(fmt_vif.fmt_grant === 1) begin 578 | this.cg_formatter_grant.sample(); 579 | break; 580 | end 581 | else begin 582 | @(posedge fmt_vif.clk); 583 | this.delay_req_to_grant++; 584 | end 585 | end 586 | end 587 | join 588 | endtask 589 | 590 | function void report_phase(uvm_phase phase); 591 | string s; 592 | super.report_phase(phase); 593 | s = "\n---------------------------------------------------------------\n"; 594 | s = {s, "COVERAGE SUMMARY \n"}; 595 | s = {s, $sformatf("total coverage: %.1f \n", $get_coverage())}; 596 | s = {s, $sformatf(" cg_mcdf_reg_write_read coverage: %.1f \n", this.cg_mcdf_reg_write_read.get_coverage())}; 597 | s = {s, $sformatf(" cg_mcdf_reg_illegal_access coverage: %.1f \n", this.cg_mcdf_reg_illegal_access.get_coverage())}; 598 | s = {s, $sformatf(" cg_channel_disable_test coverage: %.1f \n", this.cg_channel_disable.get_coverage())}; 599 | s = {s, $sformatf(" cg_arbiter_priority_test coverage: %.1f \n", this.cg_arbiter_priority.get_coverage())}; 600 | s = {s, $sformatf(" cg_formatter_length_test coverage: %.1f \n", this.cg_formatter_length.get_coverage())}; 601 | s = {s, $sformatf(" cg_formatter_grant_test coverage: %.1f \n", this.cg_formatter_grant.get_coverage())}; 602 | s = {s, "---------------------------------------------------------------\n"}; 603 | `uvm_info(get_type_name(), s, UVM_LOW) 604 | endfunction 605 | 606 | virtual function void set_interface(virtual chnl_intf ch_vifs[3] 607 | ,virtual reg_intf reg_vif 608 | ,virtual arb_intf arb_vif 609 | ,virtual fmt_intf fmt_vif 610 | ,virtual mcdf_intf mcdf_vif 611 | ); 612 | this.chnl_vifs = ch_vifs; 613 | this.arb_vif = arb_vif; 614 | this.reg_vif = reg_vif; 615 | this.fmt_vif = fmt_vif; 616 | this.mcdf_vif = mcdf_vif; 617 | if(chnl_vifs[0] == null || chnl_vifs[1] == null || chnl_vifs[2] == null) 618 | $error("chnl interface handle is NULL, please check if target interface has been intantiated"); 619 | if(arb_vif == null) 620 | $error("arb interface handle is NULL, please check if target interface has been intantiated"); 621 | if(reg_vif == null) 622 | $error("reg interface handle is NULL, please check if target interface has been intantiated"); 623 | if(fmt_vif == null) 624 | $error("fmt interface handle is NULL, please check if target interface has been intantiated"); 625 | if(mcdf_vif == null) 626 | $error("mcdf interface handle is NULL, please check if target interface has been intantiated"); 627 | endfunction 628 | endclass: mcdf_coverage 629 | 630 | class mcdf_virtual_sequencer extends uvm_sequencer; 631 | reg_sequencer reg_sqr; 632 | fmt_sequencer fmt_sqr; 633 | chnl_sequencer chnl_sqrs[3]; 634 | mcdf_rgm rgm; 635 | virtual mcdf_intf intf; 636 | `uvm_component_utils(mcdf_virtual_sequencer) 637 | function new (string name = "mcdf_virtual_sequencer", uvm_component parent); 638 | super.new(name, parent); 639 | endfunction 640 | function void set_interface(virtual mcdf_intf intf); 641 | if(intf == null) 642 | $error("interface handle is NULL, please check if target interface has been intantiated"); 643 | else 644 | this.intf = intf; 645 | endfunction 646 | endclass 647 | 648 | // MCDF top environment 649 | class mcdf_env extends uvm_env; 650 | chnl_agent chnl_agts[3]; 651 | reg_agent reg_agt; 652 | fmt_agent fmt_agt; 653 | mcdf_checker chker; 654 | mcdf_coverage cvrg; 655 | mcdf_virtual_sequencer virt_sqr; 656 | //TODO-1.2 declare the mcdf_rgm handle, reg2mcdf_adapter handle and the 657 | //predictory handle 658 | uvm_reg_predictor #(reg_trans) predictor; 659 | 660 | `uvm_component_utils(mcdf_env) 661 | 662 | function new (string name = "mcdf_env", uvm_component parent); 663 | super.new(name, parent); 664 | endfunction 665 | 666 | function void build_phase(uvm_phase phase); 667 | super.build_phase(phase); 668 | this.chker = mcdf_checker::type_id::create("chker", this); 669 | foreach(chnl_agts[i]) begin 670 | this.chnl_agts[i] = chnl_agent::type_id::create($sformatf("chnl_agts[%0d]",i), this); 671 | end 672 | this.reg_agt = reg_agent::type_id::create("reg_agt", this); 673 | this.fmt_agt = fmt_agent::type_id::create("fmt_agt", this); 674 | this.cvrg = mcdf_coverage::type_id::create("cvrg", this); 675 | virt_sqr = mcdf_virtual_sequencer::type_id::create("virt_sqr", this); 676 | //TODO-1.2 instantiate those objects 677 | // -mcdf_rgm object 678 | // -reg2mcdf_adapter object 679 | // -predictory object 680 | //and finish necessary configuration 681 | endfunction 682 | 683 | function void connect_phase(uvm_phase phase); 684 | super.connect_phase(phase); 685 | chnl_agts[0].monitor.mon_bp_port.connect(chker.chnl0_bp_imp); 686 | chnl_agts[1].monitor.mon_bp_port.connect(chker.chnl1_bp_imp); 687 | chnl_agts[2].monitor.mon_bp_port.connect(chker.chnl2_bp_imp); 688 | reg_agt.monitor.mon_bp_port.connect(chker.reg_bp_imp); 689 | fmt_agt.monitor.mon_bp_port.connect(chker.fmt_bp_imp); 690 | virt_sqr.reg_sqr = reg_agt.sequencer; 691 | virt_sqr.fmt_sqr = fmt_agt.sequencer; 692 | foreach(virt_sqr.chnl_sqrs[i]) virt_sqr.chnl_sqrs[i] = chnl_agts[i].sequencer; 693 | //TODO-1.2 Link the register model with the adapter and the predictor 694 | 695 | //TODO-2.1 connect the virtual sequencer's rgm handle with rgm object 696 | //build已使用了自顶而下的方式, 创建了环境的所有子组件,所以在调用connect()时,用户可创建测试/环境/组件之间的层次化拓扑结构 697 | uvm_top.print_topology(); 698 | endfunction 699 | endclass: mcdf_env 700 | 701 | class mcdf_base_virtual_sequence extends uvm_sequence; 702 | idle_reg_sequence idle_reg_seq; 703 | write_reg_sequence write_reg_seq; 704 | read_reg_sequence read_reg_seq; 705 | chnl_data_sequence chnl_data_seq; 706 | fmt_config_sequence fmt_config_seq; 707 | mcdf_rgm rgm; 708 | 709 | `uvm_object_utils(mcdf_base_virtual_sequence) 710 | `uvm_declare_p_sequencer(mcdf_virtual_sequencer) 711 | 712 | function new (string name = "mcdf_base_virtual_sequence"); 713 | super.new(name); 714 | endfunction 715 | 716 | virtual task body(); 717 | `uvm_info(get_type_name(), "=====================STARTED=====================", UVM_LOW) 718 | //TODO-2.1 connect rgm handle 719 | 720 | this.do_reg(); 721 | this.do_formatter(); 722 | this.do_data(); 723 | 724 | `uvm_info(get_type_name(), "=====================FINISHED=====================", UVM_LOW) 725 | endtask 726 | 727 | // do register configuration 728 | virtual task do_reg(); 729 | //User to implment the task in the child virtual sequence 730 | endtask 731 | 732 | // do external formatter down stream slave configuration 733 | virtual task do_formatter(); 734 | //User to implment the task in the child virtual sequence 735 | endtask 736 | 737 | // do data transition from 3 channel slaves 738 | virtual task do_data(); 739 | //User to implment the task in the child virtual sequence 740 | endtask 741 | 742 | virtual function bit diff_value(int val1, int val2, string id = "value_compare"); 743 | if(val1 != val2) begin 744 | `uvm_error("[CMPERR]", $sformatf("ERROR! %s val1 %8x != val2 %8x", id, val1, val2)) 745 | return 0; 746 | end 747 | else begin 748 | `uvm_info("[CMPSUC]", $sformatf("SUCCESS! %s val1 %8x == val2 %8x", id, val1, val2), UVM_LOW) 749 | return 1; 750 | end 751 | endfunction 752 | endclass 753 | 754 | // MCDF base test 755 | class mcdf_base_test extends uvm_test; 756 | mcdf_env env; 757 | virtual chnl_intf ch0_vif ; 758 | virtual chnl_intf ch1_vif ; 759 | virtual chnl_intf ch2_vif ; 760 | virtual reg_intf reg_vif ; 761 | virtual arb_intf arb_vif ; 762 | virtual fmt_intf fmt_vif ; 763 | virtual mcdf_intf mcdf_vif; 764 | 765 | `uvm_component_utils(mcdf_base_test) 766 | 767 | function new(string name = "mcdf_base_test", uvm_component parent); 768 | super.new(name, parent); 769 | endfunction 770 | 771 | function void build_phase(uvm_phase phase); 772 | super.build_phase(phase); 773 | // get virtual interface from top TB 774 | if(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch0_vif", ch0_vif)) begin 775 | `uvm_fatal("GETVIF","cannot get vif handle from config DB") 776 | end 777 | if(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch1_vif", ch1_vif)) begin 778 | `uvm_fatal("GETVIF","cannot get vif handle from config DB") 779 | end 780 | if(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch2_vif", ch2_vif)) begin 781 | `uvm_fatal("GETVIF","cannot get vif handle from config DB") 782 | end 783 | if(!uvm_config_db#(virtual reg_intf)::get(this,"","reg_vif", reg_vif)) begin 784 | `uvm_fatal("GETVIF","cannot get vif handle from config DB") 785 | end 786 | if(!uvm_config_db#(virtual arb_intf)::get(this,"","arb_vif", arb_vif)) begin 787 | `uvm_fatal("GETVIF","cannot get vif handle from config DB") 788 | end 789 | if(!uvm_config_db#(virtual fmt_intf)::get(this,"","fmt_vif", fmt_vif)) begin 790 | `uvm_fatal("GETVIF","cannot get vif handle from config DB") 791 | end 792 | if(!uvm_config_db#(virtual mcdf_intf)::get(this,"","mcdf_vif", mcdf_vif)) begin 793 | `uvm_fatal("GETVIF","cannot get vif handle from config DB") 794 | end 795 | 796 | this.env = mcdf_env::type_id::create("env", this); 797 | endfunction 798 | 799 | function void connect_phase(uvm_phase phase); 800 | super.connect_phase(phase); 801 | // After get virtual interface from config_db, and then set them to 802 | // child components 803 | this.set_interface(ch0_vif, ch1_vif, ch2_vif, reg_vif, arb_vif, fmt_vif, mcdf_vif); 804 | endfunction 805 | 806 | function void end_of_elaboration_phase(uvm_phase phase); 807 | super.end_of_elaboration_phase(phase); 808 | uvm_root::get().set_report_verbosity_level_hier(UVM_HIGH); 809 | uvm_root::get().set_report_max_quit_count(1); 810 | uvm_root::get().set_timeout(10ms); 811 | endfunction 812 | 813 | task run_phase(uvm_phase phase); 814 | // NOTE:: raise objection to prevent simulation stopping 815 | phase.raise_objection(this); 816 | 817 | this.run_top_virtual_sequence(); 818 | 819 | // NOTE:: drop objection to request simulation stopping 820 | phase.drop_objection(this); 821 | endtask 822 | 823 | virtual task run_top_virtual_sequence(); 824 | // User to implement this task in the child tests 825 | endtask 826 | 827 | virtual function void set_interface(virtual chnl_intf ch0_vif 828 | ,virtual chnl_intf ch1_vif 829 | ,virtual chnl_intf ch2_vif 830 | ,virtual reg_intf reg_vif 831 | ,virtual arb_intf arb_vif 832 | ,virtual fmt_intf fmt_vif 833 | ,virtual mcdf_intf mcdf_vif 834 | ); 835 | this.env.chnl_agts[0].set_interface(ch0_vif); 836 | this.env.chnl_agts[1].set_interface(ch1_vif); 837 | this.env.chnl_agts[2].set_interface(ch2_vif); 838 | this.env.reg_agt.set_interface(reg_vif); 839 | this.env.fmt_agt.set_interface(fmt_vif); 840 | this.env.chker.set_interface(mcdf_vif, '{ch0_vif, ch1_vif, ch2_vif}, arb_vif); 841 | this.env.cvrg.set_interface('{ch0_vif, ch1_vif, ch2_vif}, reg_vif, arb_vif, fmt_vif, mcdf_vif); 842 | this.env.virt_sqr.set_interface(mcdf_vif); 843 | endfunction 844 | endclass: mcdf_base_test 845 | 846 | //TODO-2.2 replace the register bus sequence with uvm_reg::write()/read() 847 | class mcdf_data_consistence_basic_virtual_sequence extends mcdf_base_virtual_sequence; 848 | `uvm_object_utils(mcdf_data_consistence_basic_virtual_sequence) 849 | function new (string name = "mcdf_data_consistence_basic_virtual_sequence"); 850 | super.new(name); 851 | endfunction 852 | task do_reg(); 853 | bit[31:0] wr_val, rd_val; 854 | // slv0 with len=8, prio=0, en=1 855 | wr_val = (1<<3)+(0<<1)+1; 856 | `uvm_do_on_with(write_reg_seq, p_sequencer.reg_sqr, {addr == `SLV0_RW_ADDR; data == wr_val;}) 857 | `uvm_do_on_with(read_reg_seq, p_sequencer.reg_sqr, {addr == `SLV0_RW_ADDR;}) 858 | rd_val = read_reg_seq.data; 859 | void'(this.diff_value(wr_val, rd_val, "SLV0_WR_REG")); 860 | 861 | // slv1 with len=16, prio=1, en=1 862 | wr_val = (2<<3)+(1<<1)+1; 863 | `uvm_do_on_with(write_reg_seq, p_sequencer.reg_sqr, {addr == `SLV1_RW_ADDR; data == wr_val;}) 864 | `uvm_do_on_with(read_reg_seq, p_sequencer.reg_sqr, {addr == `SLV1_RW_ADDR;}) 865 | rd_val = read_reg_seq.data; 866 | void'(this.diff_value(wr_val, rd_val, "SLV1_WR_REG")); 867 | 868 | // slv2 with len=32, prio=2, en=1 869 | wr_val = (3<<3)+(2<<1)+1; 870 | `uvm_do_on_with(write_reg_seq, p_sequencer.reg_sqr, {addr == `SLV2_RW_ADDR; data == wr_val;}) 871 | `uvm_do_on_with(read_reg_seq, p_sequencer.reg_sqr, {addr == `SLV2_RW_ADDR;}) 872 | rd_val = read_reg_seq.data; 873 | void'(this.diff_value(wr_val, rd_val, "SLV2_WR_REG")); 874 | 875 | // send IDLE command 876 | `uvm_do_on(idle_reg_seq, p_sequencer.reg_sqr) 877 | endtask 878 | task do_formatter(); 879 | `uvm_do_on_with(fmt_config_seq, p_sequencer.fmt_sqr, {fifo == LONG_FIFO; bandwidth == HIGH_WIDTH;}) 880 | endtask 881 | task do_data(); 882 | fork 883 | `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[0], {ntrans==100; ch_id==0; data_nidles==0; pkt_nidles==1; data_size==8; }) 884 | `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[1], {ntrans==100; ch_id==1; data_nidles==1; pkt_nidles==4; data_size==16;}) 885 | `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[2], {ntrans==100; ch_id==2; data_nidles==2; pkt_nidles==8; data_size==32;}) 886 | join 887 | #10us; // wait until all data haven been transfered through MCDF 888 | endtask 889 | endclass: mcdf_data_consistence_basic_virtual_sequence 890 | 891 | class mcdf_data_consistence_basic_test extends mcdf_base_test; 892 | 893 | `uvm_component_utils(mcdf_data_consistence_basic_test) 894 | 895 | function new(string name = "mcdf_data_consistence_basic_test", uvm_component parent); 896 | super.new(name, parent); 897 | endfunction 898 | 899 | task run_top_virtual_sequence(); 900 | mcdf_data_consistence_basic_virtual_sequence top_seq = new(); 901 | top_seq.start(env.virt_sqr); 902 | endtask 903 | endclass: mcdf_data_consistence_basic_test 904 | 905 | //TODO-2.3 Follow the instructions below 906 | // -reset the register block 907 | // -set all value of WR registers via uvm_reg::set() 908 | // -update them via uvm_reg_block::update() 909 | // -compare the register value via uvm_reg::mirror() 910 | class mcdf_full_random_virtual_sequence extends mcdf_base_virtual_sequence; 911 | `uvm_object_utils(mcdf_base_virtual_sequence) 912 | function new (string name = "mcdf_base_virtual_sequence"); 913 | super.new(name); 914 | endfunction 915 | 916 | task do_reg(); 917 | bit[31:0] wr_val, rd_val; 918 | // slv0 with len={4,8,16,32}, prio={[0:3]}, en={[0:1]} 919 | wr_val = ($urandom_range(0,3)<<3)+($urandom_range(0,3)<<1)+$urandom_range(0,1); 920 | `uvm_do_on_with(write_reg_seq, p_sequencer.reg_sqr, {addr == `SLV0_RW_ADDR; data == wr_val;}) 921 | `uvm_do_on_with(read_reg_seq, p_sequencer.reg_sqr, {addr == `SLV0_RW_ADDR;}) 922 | rd_val = read_reg_seq.data; 923 | void'(this.diff_value(wr_val, rd_val, "SLV0_WR_REG")); 924 | 925 | // slv0 with len={4,8,16,32}, prio={[0:3]}, en={[0:1]} 926 | wr_val = ($urandom_range(0,3)<<3)+($urandom_range(0,3)<<1)+$urandom_range(0,1); 927 | `uvm_do_on_with(write_reg_seq, p_sequencer.reg_sqr, {addr == `SLV1_RW_ADDR; data == wr_val;}) 928 | `uvm_do_on_with(read_reg_seq, p_sequencer.reg_sqr, {addr == `SLV1_RW_ADDR;}) 929 | rd_val = read_reg_seq.data; 930 | void'(this.diff_value(wr_val, rd_val, "SLV1_WR_REG")); 931 | 932 | // slv0 with len={4,8,16,32}, prio={[0:3]}, en={[0:1]} 933 | wr_val = ($urandom_range(0,3)<<3)+($urandom_range(0,3)<<1)+$urandom_range(0,1); 934 | `uvm_do_on_with(write_reg_seq, p_sequencer.reg_sqr, {addr == `SLV2_RW_ADDR; data == wr_val;}) 935 | `uvm_do_on_with(read_reg_seq, p_sequencer.reg_sqr, {addr == `SLV2_RW_ADDR;}) 936 | rd_val = read_reg_seq.data; 937 | void'(this.diff_value(wr_val, rd_val, "SLV2_WR_REG")); 938 | 939 | // send IDLE command 940 | `uvm_do_on(idle_reg_seq, p_sequencer.reg_sqr) 941 | endtask 942 | task do_formatter(); 943 | `uvm_do_on_with(fmt_config_seq, p_sequencer.fmt_sqr, {fifo inside {SHORT_FIFO, ULTRA_FIFO}; bandwidth inside {LOW_WIDTH, ULTRA_WIDTH};}) 944 | endtask 945 | task do_data(); 946 | fork 947 | `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[0], 948 | {ntrans inside {[400:600]}; ch_id==0; data_nidles inside {[0:3]}; pkt_nidles inside {1,2,4,8}; data_size inside {8,16,32};}) 949 | `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[1], 950 | {ntrans inside {[400:600]}; ch_id==0; data_nidles inside {[0:3]}; pkt_nidles inside {1,2,4,8}; data_size inside {8,16,32};}) 951 | `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[2], 952 | {ntrans inside {[400:600]}; ch_id==0; data_nidles inside {[0:3]}; pkt_nidles inside {1,2,4,8}; data_size inside {8,16,32};}) 953 | join 954 | #10us; // wait until all data haven been transfered through MCDF 955 | endtask 956 | endclass: mcdf_full_random_virtual_sequence 957 | 958 | class mcdf_full_random_test extends mcdf_base_test; 959 | 960 | `uvm_component_utils(mcdf_full_random_test) 961 | 962 | function new(string name = "mcdf_full_random_test", uvm_component parent); 963 | super.new(name, parent); 964 | endfunction 965 | 966 | task run_top_virtual_sequence(); 967 | mcdf_full_random_virtual_sequence top_seq = new(); 968 | top_seq.start(env.virt_sqr); 969 | endtask 970 | endclass: mcdf_full_random_test 971 | 972 | 973 | //TODO-3.1 Use build-in uvm register sequence 974 | // -uvm_reg_hw_reset_seq 975 | // -uvm_reg_bit_bash_seq 976 | // -uvm_reg_access_seq 977 | class mcdf_reg_builtin_virtual_sequence extends mcdf_base_virtual_sequence; 978 | `uvm_object_utils(mcdf_reg_builtin_virtual_sequence) 979 | function new (string name = "mcdf_reg_builtin_virtual_sequence"); 980 | super.new(name); 981 | endfunction 982 | 983 | task do_reg(); 984 | //USER TODO 985 | endtask 986 | endclass: mcdf_reg_builtin_virtual_sequence 987 | 988 | class mcdf_reg_builtin_test extends mcdf_base_test; 989 | 990 | `uvm_component_utils(mcdf_reg_builtin_test) 991 | 992 | function new(string name = "mcdf_reg_builtin_test", uvm_component parent); 993 | super.new(name, parent); 994 | endfunction 995 | 996 | task run_top_virtual_sequence(); 997 | mcdf_reg_builtin_virtual_sequence top_seq = new(); 998 | top_seq.start(env.virt_sqr); 999 | endtask 1000 | endclass: mcdf_reg_builtin_test 1001 | 1002 | endpackage 1003 | -------------------------------------------------------------------------------- /uvm_verification_case/mcdf_pkg_ref.sv: -------------------------------------------------------------------------------- 1 | `include "param_def.v" 2 | 3 | package mcdf_pkg; 4 | 5 | import uvm_pkg::*; 6 | `include "uvm_macros.svh" 7 | import chnl_pkg::*; 8 | import reg_pkg::*; 9 | import arb_pkg::*; 10 | import fmt_pkg::*; 11 | import mcdf_rgm_pkg::*; 12 | 13 | typedef struct packed { 14 | bit[2:0] len; 15 | bit[1:0] prio; 16 | bit en; 17 | bit[7:0] avail; 18 | } mcdf_reg_t; 19 | 20 | typedef enum {RW_LEN, RW_PRIO, RW_EN, RD_AVAIL} mcdf_field_t; 21 | 22 | // MCDF reference model 23 | class mcdf_refmod extends uvm_component; 24 | local virtual mcdf_intf intf; 25 | mcdf_reg_t regs[3]; 26 | 27 | uvm_blocking_get_port #(reg_trans) reg_bg_port; 28 | uvm_blocking_get_peek_port #(mon_data_t) in_bgpk_ports[3]; 29 | 30 | uvm_tlm_fifo #(fmt_trans) out_tlm_fifos[3]; 31 | 32 | `uvm_component_utils(mcdf_refmod) 33 | 34 | function new (string name = "mcdf_refmod", uvm_component parent); 35 | super.new(name, parent); 36 | reg_bg_port = new("reg_bg_port", this); 37 | foreach(in_bgpk_ports[i]) in_bgpk_ports[i] = new($sformatf("in_bgpk_ports[%0d]", i), this); 38 | foreach(out_tlm_fifos[i]) out_tlm_fifos[i] = new($sformatf("out_tlm_fifos[%0d]", i), this); 39 | endfunction 40 | 41 | task run_phase(uvm_phase phase); 42 | fork 43 | do_reset(); 44 | this.do_reg_update(); 45 | do_packet(0); 46 | do_packet(1); 47 | do_packet(2); 48 | join 49 | endtask 50 | 51 | task do_reg_update(); 52 | reg_trans t; 53 | forever begin 54 | this.reg_bg_port.get(t); 55 | if(t.addr[7:4] == 0 && t.cmd == `WRITE) begin 56 | this.regs[t.addr[3:2]].en = t.data[0]; 57 | this.regs[t.addr[3:2]].prio = t.data[2:1]; 58 | this.regs[t.addr[3:2]].len = t.data[5:3]; 59 | end 60 | else if(t.addr[7:4] == 1 && t.cmd == `READ) begin 61 | this.regs[t.addr[3:2]].avail = t.data[7:0]; 62 | end 63 | end 64 | endtask 65 | 66 | task do_packet(int id); 67 | fmt_trans ot; 68 | mon_data_t it; 69 | forever begin 70 | this.in_bgpk_ports[id].peek(it); 71 | ot = new(); 72 | ot.length = 4 << (this.get_field_value(id, RW_LEN) & 'b11); 73 | ot.data = new[ot.length]; 74 | ot.ch_id = id; 75 | foreach(ot.data[m]) begin 76 | this.in_bgpk_ports[id].get(it); 77 | ot.data[m] = it.data; 78 | end 79 | this.out_tlm_fifos[id].put(ot); 80 | end 81 | endtask 82 | 83 | function int get_field_value(int id, mcdf_field_t f); 84 | case(f) 85 | RW_LEN: return regs[id].len; 86 | RW_PRIO: return regs[id].prio; 87 | RW_EN: return regs[id].en; 88 | RD_AVAIL: return regs[id].avail; 89 | endcase 90 | endfunction 91 | 92 | task do_reset(); 93 | forever begin 94 | @(negedge intf.rstn); 95 | foreach(regs[i]) begin 96 | regs[i].len = 'h0; 97 | regs[i].prio = 'h3; 98 | regs[i].en = 'h1; 99 | regs[i].avail = 'h20; 100 | end 101 | end 102 | endtask 103 | 104 | function void set_interface(virtual mcdf_intf intf); 105 | if(intf == null) 106 | $error("interface handle is NULL, please check if target interface has been intantiated"); 107 | else 108 | this.intf = intf; 109 | endfunction 110 | endclass: mcdf_refmod 111 | 112 | // MCDF checker (scoreboard) 113 | 114 | `uvm_blocking_put_imp_decl(_chnl0) 115 | `uvm_blocking_put_imp_decl(_chnl1) 116 | `uvm_blocking_put_imp_decl(_chnl2) 117 | `uvm_blocking_put_imp_decl(_fmt) 118 | `uvm_blocking_put_imp_decl(_reg) 119 | 120 | `uvm_blocking_get_peek_imp_decl(_chnl0) 121 | `uvm_blocking_get_peek_imp_decl(_chnl1) 122 | `uvm_blocking_get_peek_imp_decl(_chnl2) 123 | 124 | `uvm_blocking_get_imp_decl(_reg) 125 | 126 | class mcdf_checker extends uvm_scoreboard; 127 | local int err_count; 128 | local int total_count; 129 | local int chnl_count[3]; 130 | local virtual chnl_intf chnl_vifs[3]; 131 | local virtual arb_intf arb_vif; 132 | local virtual mcdf_intf mcdf_vif; 133 | local mcdf_refmod refmod; 134 | 135 | uvm_blocking_put_imp_chnl0 #(mon_data_t, mcdf_checker) chnl0_bp_imp; 136 | uvm_blocking_put_imp_chnl1 #(mon_data_t, mcdf_checker) chnl1_bp_imp; 137 | uvm_blocking_put_imp_chnl2 #(mon_data_t, mcdf_checker) chnl2_bp_imp; 138 | uvm_blocking_put_imp_fmt #(fmt_trans , mcdf_checker) fmt_bp_imp ; 139 | uvm_blocking_put_imp_reg #(reg_trans , mcdf_checker) reg_bp_imp ; 140 | 141 | uvm_blocking_get_peek_imp_chnl0 #(mon_data_t, mcdf_checker) chnl0_bgpk_imp; 142 | uvm_blocking_get_peek_imp_chnl1 #(mon_data_t, mcdf_checker) chnl1_bgpk_imp; 143 | uvm_blocking_get_peek_imp_chnl2 #(mon_data_t, mcdf_checker) chnl2_bgpk_imp; 144 | 145 | uvm_blocking_get_imp_reg #(reg_trans , mcdf_checker) reg_bg_imp ; 146 | 147 | mailbox #(mon_data_t) chnl_mbs[3]; 148 | mailbox #(fmt_trans) fmt_mb; 149 | mailbox #(reg_trans) reg_mb; 150 | 151 | uvm_blocking_get_port #(fmt_trans) exp_bg_ports[3]; 152 | 153 | `uvm_component_utils(mcdf_checker) 154 | 155 | function new (string name = "mcdf_checker", uvm_component parent); 156 | super.new(name, parent); 157 | this.err_count = 0; 158 | this.total_count = 0; 159 | foreach(this.chnl_count[i]) this.chnl_count[i] = 0; 160 | 161 | chnl0_bp_imp = new("chnl0_bp_imp", this); 162 | chnl1_bp_imp = new("chnl1_bp_imp", this); 163 | chnl2_bp_imp = new("chnl2_bp_imp", this); 164 | fmt_bp_imp = new("fmt_bp_imp", this); 165 | reg_bp_imp = new("reg_bp_imp", this); 166 | 167 | chnl0_bgpk_imp = new("chnl0_bgpk_imp", this); 168 | chnl1_bgpk_imp = new("chnl1_bgpk_imp", this); 169 | chnl2_bgpk_imp = new("chnl2_bgpk_imp", this); 170 | 171 | reg_bg_imp = new("reg_bg_imp", this); 172 | 173 | foreach(exp_bg_ports[i]) exp_bg_ports[i] = new($sformatf("exp_bg_ports[%0d]", i), this); 174 | endfunction 175 | 176 | function void build_phase(uvm_phase phase); 177 | super.build_phase(phase); 178 | foreach(this.chnl_mbs[i]) this.chnl_mbs[i] = new(); 179 | this.fmt_mb = new(); 180 | this.reg_mb = new(); 181 | this.refmod = mcdf_refmod::type_id::create("refmod", this); 182 | endfunction 183 | 184 | function void connect_phase(uvm_phase phase); 185 | super.connect_phase(phase); 186 | refmod.in_bgpk_ports[0].connect(chnl0_bgpk_imp); 187 | refmod.in_bgpk_ports[1].connect(chnl1_bgpk_imp); 188 | refmod.in_bgpk_ports[2].connect(chnl2_bgpk_imp); 189 | 190 | refmod.reg_bg_port.connect(reg_bg_imp); 191 | 192 | foreach(exp_bg_ports[i]) begin 193 | exp_bg_ports[i].connect(refmod.out_tlm_fifos[i].blocking_get_export); 194 | end 195 | endfunction 196 | 197 | function void set_interface(virtual mcdf_intf mcdf_vif, virtual chnl_intf chnl_vifs[3], virtual arb_intf arb_vif); 198 | if(mcdf_vif == null) 199 | $error("mcdf interface handle is NULL, please check if target interface has been intantiated"); 200 | else begin 201 | this.mcdf_vif = mcdf_vif; 202 | this.refmod.set_interface(mcdf_vif); 203 | end 204 | if(chnl_vifs[0] == null || chnl_vifs[1] == null || chnl_vifs[2] == null) 205 | $error("chnl interface handle is NULL, please check if target interface has been intantiated"); 206 | else begin 207 | this.chnl_vifs = chnl_vifs; 208 | end 209 | if(arb_vif == null) 210 | $error("arb interface handle is NULL, please check if target interface has been intantiated"); 211 | else begin 212 | this.arb_vif = arb_vif; 213 | end 214 | endfunction 215 | 216 | task run_phase(uvm_phase phase); 217 | fork 218 | this.do_channel_disable_check(0); 219 | this.do_channel_disable_check(1); 220 | this.do_channel_disable_check(2); 221 | this.do_arbiter_priority_check(); 222 | // 223 | this.do_data_compare(); 224 | this.refmod.run(); 225 | join 226 | endtask 227 | 228 | task do_data_compare(); 229 | fmt_trans expt, mont; 230 | bit cmp; 231 | forever begin 232 | this.fmt_mb.get(mont); 233 | this.exp_bg_ports[mont.ch_id].get(expt); 234 | cmp = mont.compare(expt); 235 | //compare默认比较器会对其参数依次比较,发现错误则返回,后续参数不继续比较 236 | this.total_count++; 237 | this.chnl_count[mont.ch_id]++; 238 | if(cmp == 0) begin 239 | this.err_count++; 240 | `uvm_error("[CMPERR]", $sformatf("%0dth times comparing but failed! MCDF monitored output packet is different with reference model output", this.total_count)) 241 | end 242 | else begin 243 | `uvm_info("[CMPSUC]",$sformatf("%0dth times comparing and succeeded! MCDF monitored output packet is the same with reference model output", this.total_count), UVM_LOW) 244 | end 245 | end 246 | endtask 247 | 248 | task do_channel_disable_check(int id); 249 | forever begin 250 | @(posedge this.mcdf_vif.clk iff (this.mcdf_vif.rstn && this.mcdf_vif.mon_ck.chnl_en[id]===0)); 251 | if(this.chnl_vifs[id].mon_ck.ch_valid===1 && this.chnl_vifs[id].mon_ck.ch_ready===1) 252 | `uvm_error("[CHKERR]", "ERROR! when channel disabled, ready signal raised when valid high") 253 | end 254 | endtask 255 | 256 | task do_arbiter_priority_check(); 257 | int id; 258 | forever begin 259 | @(posedge this.arb_vif.clk iff (this.arb_vif.rstn && this.arb_vif.mon_ck.f2a_id_req===1)); 260 | id = this.get_slave_id_with_prio(); 261 | if(id >= 0) begin 262 | @(posedge this.arb_vif.clk); 263 | if(this.arb_vif.mon_ck.a2s_acks[id] !== 1) 264 | `uvm_error("[CHKERR]", $sformatf("ERROR! arbiter received f2a_id_req===1 and channel[%0d] raising request with high priority, but is not granted by arbiter", id)) 265 | end 266 | end 267 | endtask 268 | 269 | function int get_slave_id_with_prio(); 270 | int id=-1; 271 | int prio=999; 272 | foreach(this.arb_vif.mon_ck.slv_prios[i]) begin 273 | if(this.arb_vif.mon_ck.slv_prios[i] < prio && this.arb_vif.mon_ck.slv_reqs[i]===1) begin 274 | id = i; 275 | prio = this.arb_vif.mon_ck.slv_prios[i]; 276 | end 277 | end 278 | return id; 279 | endfunction 280 | 281 | function void report_phase(uvm_phase phase); 282 | string s; 283 | super.report_phase(phase); 284 | s = "\n---------------------------------------------------------------\n"; 285 | s = {s, "CHECKER SUMMARY \n"}; 286 | s = {s, $sformatf("total comparison count: %0d \n", this.total_count)}; 287 | foreach(this.chnl_count[i]) s = {s, $sformatf(" channel[%0d] comparison count: %0d \n", i, this.chnl_count[i])}; 288 | s = {s, $sformatf("total error count: %0d \n", this.err_count)}; 289 | foreach(this.chnl_mbs[i]) begin 290 | if(this.chnl_mbs[i].num() != 0) 291 | s = {s, $sformatf("WARNING:: chnl_mbs[%0d] is not empty! size = %0d \n", i, this.chnl_mbs[i].num())}; 292 | end 293 | if(this.fmt_mb.num() != 0) 294 | s = {s, $sformatf("WARNING:: fmt_mb is not empty! size = %0d \n", this.fmt_mb.num())}; 295 | s = {s, "---------------------------------------------------------------\n"}; 296 | `uvm_info(get_type_name(), s, UVM_LOW) 297 | endfunction 298 | 299 | task put_chnl0(mon_data_t t); 300 | chnl_mbs[0].put(t); 301 | endtask 302 | task put_chnl1(mon_data_t t); 303 | chnl_mbs[1].put(t); 304 | endtask 305 | task put_chnl2(mon_data_t t); 306 | chnl_mbs[2].put(t); 307 | endtask 308 | task put_fmt(fmt_trans t); 309 | fmt_mb.put(t); 310 | endtask 311 | task put_reg(reg_trans t); 312 | reg_mb.put(t); 313 | endtask 314 | task peek_chnl0(output mon_data_t t); 315 | chnl_mbs[0].peek(t); 316 | endtask 317 | task peek_chnl1(output mon_data_t t); 318 | chnl_mbs[1].peek(t); 319 | endtask 320 | task peek_chnl2(output mon_data_t t); 321 | chnl_mbs[2].peek(t); 322 | endtask 323 | task get_chnl0(output mon_data_t t); 324 | chnl_mbs[0].get(t); 325 | endtask 326 | task get_chnl1(output mon_data_t t); 327 | chnl_mbs[1].get(t); 328 | endtask 329 | task get_chnl2(output mon_data_t t); 330 | chnl_mbs[2].get(t); 331 | endtask 332 | task get_reg(output reg_trans t); 333 | reg_mb.get(t); 334 | endtask 335 | endclass: mcdf_checker 336 | 337 | // MCDF coverage model 338 | class mcdf_coverage extends uvm_component; 339 | local virtual chnl_intf chnl_vifs[3]; 340 | local virtual arb_intf arb_vif; 341 | local virtual mcdf_intf mcdf_vif; 342 | local virtual reg_intf reg_vif; 343 | local virtual fmt_intf fmt_vif; 344 | local int delay_req_to_grant; 345 | 346 | `uvm_component_utils(mcdf_coverage) 347 | 348 | covergroup cg_mcdf_reg_write_read; 349 | addr: coverpoint reg_vif.mon_ck.cmd_addr { 350 | type_option.weight = 0; 351 | bins slv0_rw_addr = {`SLV0_RW_ADDR}; 352 | bins slv1_rw_addr = {`SLV1_RW_ADDR}; 353 | bins slv2_rw_addr = {`SLV2_RW_ADDR}; 354 | bins slv0_r_addr = {`SLV0_R_ADDR }; 355 | bins slv1_r_addr = {`SLV1_R_ADDR }; 356 | bins slv2_r_addr = {`SLV2_R_ADDR }; 357 | } 358 | cmd: coverpoint reg_vif.mon_ck.cmd { 359 | type_option.weight = 0; 360 | bins write = {`WRITE}; 361 | bins read = {`READ}; 362 | bins idle = {`IDLE}; 363 | } 364 | cmdXaddr: cross cmd, addr { 365 | bins slv0_rw_addr = binsof(addr.slv0_rw_addr); 366 | bins slv1_rw_addr = binsof(addr.slv1_rw_addr); 367 | bins slv2_rw_addr = binsof(addr.slv2_rw_addr); 368 | bins slv0_r_addr = binsof(addr.slv0_r_addr ); 369 | bins slv1_r_addr = binsof(addr.slv1_r_addr ); 370 | bins slv2_r_addr = binsof(addr.slv2_r_addr ); 371 | bins write = binsof(cmd.write); 372 | bins read = binsof(cmd.read ); 373 | bins idle = binsof(cmd.idle ); 374 | bins write_slv0_rw_addr = binsof(cmd.write) && binsof(addr.slv0_rw_addr); 375 | bins write_slv1_rw_addr = binsof(cmd.write) && binsof(addr.slv1_rw_addr); 376 | bins write_slv2_rw_addr = binsof(cmd.write) && binsof(addr.slv2_rw_addr); 377 | bins read_slv0_rw_addr = binsof(cmd.read) && binsof(addr.slv0_rw_addr); 378 | bins read_slv1_rw_addr = binsof(cmd.read) && binsof(addr.slv1_rw_addr); 379 | bins read_slv2_rw_addr = binsof(cmd.read) && binsof(addr.slv2_rw_addr); 380 | bins read_slv0_r_addr = binsof(cmd.read) && binsof(addr.slv0_r_addr); 381 | bins read_slv1_r_addr = binsof(cmd.read) && binsof(addr.slv1_r_addr); 382 | bins read_slv2_r_addr = binsof(cmd.read) && binsof(addr.slv2_r_addr); 383 | } 384 | endgroup 385 | 386 | covergroup cg_mcdf_reg_illegal_access; 387 | addr: coverpoint reg_vif.mon_ck.cmd_addr { 388 | type_option.weight = 0; 389 | bins legal_rw = {`SLV0_RW_ADDR, `SLV1_RW_ADDR, `SLV2_RW_ADDR}; 390 | bins legal_r = {`SLV0_R_ADDR, `SLV1_R_ADDR, `SLV2_R_ADDR}; 391 | bins illegal = {[8'h20:$], 8'hC, 8'h1C}; 392 | } 393 | cmd: coverpoint reg_vif.mon_ck.cmd { 394 | type_option.weight = 0; 395 | bins write = {`WRITE}; 396 | bins read = {`READ}; 397 | } 398 | wdata: coverpoint reg_vif.mon_ck.cmd_data_m2s { 399 | type_option.weight = 0; 400 | bins legal = {[0:'h3F]}; 401 | bins illegal = {['h40:$]}; 402 | } 403 | rdata: coverpoint reg_vif.mon_ck.cmd_data_s2m { 404 | type_option.weight = 0; 405 | bins legal = {[0:'hFF]}; 406 | illegal_bins illegal = default; 407 | } 408 | cmdXaddrXdata: cross cmd, addr, wdata, rdata { 409 | bins addr_legal_rw = binsof(addr.legal_rw); 410 | bins addr_legal_r = binsof(addr.legal_r); 411 | bins addr_illegal = binsof(addr.illegal); 412 | bins cmd_write = binsof(cmd.write); 413 | bins cmd_read = binsof(cmd.read); 414 | bins wdata_legal = binsof(wdata.legal); 415 | bins wdata_illegal = binsof(wdata.illegal); 416 | bins rdata_legal = binsof(rdata.legal); 417 | bins write_illegal_addr = binsof(cmd.write) && binsof(addr.illegal); 418 | bins read_illegal_addr = binsof(cmd.read) && binsof(addr.illegal); 419 | bins write_illegal_rw_data = binsof(cmd.write) && binsof(addr.legal_rw) && binsof(wdata.illegal); 420 | bins write_illegal_r_data = binsof(cmd.write) && binsof(addr.legal_r) && binsof(wdata.illegal); 421 | } 422 | endgroup 423 | 424 | covergroup cg_channel_disable; 425 | ch0_en: coverpoint mcdf_vif.mon_ck.chnl_en[0] { 426 | type_option.weight = 0; 427 | wildcard bins en = {1'b1}; 428 | wildcard bins dis = {1'b0}; 429 | } 430 | ch1_en: coverpoint mcdf_vif.mon_ck.chnl_en[1] { 431 | type_option.weight = 0; 432 | wildcard bins en = {1'b1}; 433 | wildcard bins dis = {1'b0}; 434 | } 435 | ch2_en: coverpoint mcdf_vif.mon_ck.chnl_en[2] { 436 | type_option.weight = 0; 437 | wildcard bins en = {1'b1}; 438 | wildcard bins dis = {1'b0}; 439 | } 440 | ch0_vld: coverpoint chnl_vifs[0].mon_ck.ch_valid { 441 | type_option.weight = 0; 442 | bins hi = {1'b1}; 443 | bins lo = {1'b0}; 444 | } 445 | ch1_vld: coverpoint chnl_vifs[1].mon_ck.ch_valid { 446 | type_option.weight = 0; 447 | bins hi = {1'b1}; 448 | bins lo = {1'b0}; 449 | } 450 | ch2_vld: coverpoint chnl_vifs[2].mon_ck.ch_valid { 451 | type_option.weight = 0; 452 | bins hi = {1'b1}; 453 | bins lo = {1'b0}; 454 | } 455 | chenXchvld: cross ch0_en, ch1_en, ch2_en, ch0_vld, ch1_vld, ch2_vld { 456 | bins ch0_en = binsof(ch0_en.en); 457 | bins ch0_dis = binsof(ch0_en.dis); 458 | bins ch1_en = binsof(ch1_en.en); 459 | bins ch1_dis = binsof(ch1_en.dis); 460 | bins ch2_en = binsof(ch2_en.en); 461 | bins ch2_dis = binsof(ch2_en.dis); 462 | bins ch0_hi = binsof(ch0_vld.hi); 463 | bins ch0_lo = binsof(ch0_vld.lo); 464 | bins ch1_hi = binsof(ch1_vld.hi); 465 | bins ch1_lo = binsof(ch1_vld.lo); 466 | bins ch2_hi = binsof(ch2_vld.hi); 467 | bins ch2_lo = binsof(ch2_vld.lo); 468 | bins ch0_en_vld = binsof(ch0_en.en) && binsof(ch0_vld.hi); 469 | bins ch0_dis_vld = binsof(ch0_en.dis) && binsof(ch0_vld.hi); 470 | bins ch1_en_vld = binsof(ch1_en.en) && binsof(ch1_vld.hi); 471 | bins ch1_dis_vld = binsof(ch1_en.dis) && binsof(ch1_vld.hi); 472 | bins ch2_en_vld = binsof(ch2_en.en) && binsof(ch2_vld.hi); 473 | bins ch2_dis_vld = binsof(ch2_en.dis) && binsof(ch2_vld.hi); 474 | } 475 | endgroup 476 | 477 | covergroup cg_arbiter_priority; 478 | ch0_prio: coverpoint arb_vif.mon_ck.slv_prios[0] { 479 | bins ch_prio0 = {0}; 480 | bins ch_prio1 = {1}; 481 | bins ch_prio2 = {2}; 482 | bins ch_prio3 = {3}; 483 | } 484 | ch1_prio: coverpoint arb_vif.mon_ck.slv_prios[1] { 485 | bins ch_prio0 = {0}; 486 | bins ch_prio1 = {1}; 487 | bins ch_prio2 = {2}; 488 | bins ch_prio3 = {3}; 489 | } 490 | ch2_prio: coverpoint arb_vif.mon_ck.slv_prios[2] { 491 | bins ch_prio0 = {0}; 492 | bins ch_prio1 = {1}; 493 | bins ch_prio2 = {2}; 494 | bins ch_prio3 = {3}; 495 | } 496 | endgroup 497 | 498 | covergroup cg_formatter_length; 499 | id: coverpoint fmt_vif.mon_ck.fmt_chid { 500 | bins ch0 = {0}; 501 | bins ch1 = {1}; 502 | bins ch2 = {2}; 503 | illegal_bins illegal = default; 504 | } 505 | length: coverpoint fmt_vif.mon_ck.fmt_length { 506 | bins len4 = {4}; 507 | bins len8 = {8}; 508 | bins len16 = {16}; 509 | bins len32 = {32}; 510 | illegal_bins illegal = default; 511 | } 512 | endgroup 513 | 514 | covergroup cg_formatter_grant(); 515 | delay_req_to_grant: coverpoint this.delay_req_to_grant { 516 | bins delay1 = {1}; 517 | bins delay2 = {2}; 518 | bins delay3_or_more = {[3:10]}; 519 | illegal_bins illegal = {0}; 520 | } 521 | endgroup 522 | 523 | function new (string name = "mcdf_coverage", uvm_component parent); 524 | super.new(name, parent); 525 | this.cg_mcdf_reg_write_read = new(); 526 | this.cg_mcdf_reg_illegal_access = new(); 527 | this.cg_channel_disable = new(); 528 | this.cg_arbiter_priority = new(); 529 | this.cg_formatter_length = new(); 530 | this.cg_formatter_grant = new(); 531 | endfunction 532 | 533 | task run_phase(uvm_phase phase); 534 | fork 535 | this.do_reg_sample(); 536 | this.do_channel_sample(); 537 | this.do_arbiter_sample(); 538 | this.do_formater_sample(); 539 | join 540 | endtask 541 | 542 | task do_reg_sample(); 543 | forever begin 544 | @(posedge reg_vif.clk iff reg_vif.rstn); 545 | this.cg_mcdf_reg_write_read.sample(); 546 | this.cg_mcdf_reg_illegal_access.sample(); 547 | end 548 | endtask 549 | 550 | task do_channel_sample(); 551 | forever begin 552 | @(posedge mcdf_vif.clk iff mcdf_vif.rstn); 553 | if(chnl_vifs[0].mon_ck.ch_valid===1 554 | || chnl_vifs[1].mon_ck.ch_valid===1 555 | || chnl_vifs[2].mon_ck.ch_valid===1) 556 | this.cg_channel_disable.sample(); 557 | end 558 | endtask 559 | 560 | task do_arbiter_sample(); 561 | forever begin 562 | @(posedge arb_vif.clk iff arb_vif.rstn); 563 | if(arb_vif.slv_reqs[0]!==0 || arb_vif.slv_reqs[1]!==0 || arb_vif.slv_reqs[2]!==0) 564 | this.cg_arbiter_priority.sample(); 565 | end 566 | endtask 567 | 568 | task do_formater_sample(); 569 | fork 570 | forever begin 571 | @(posedge fmt_vif.clk iff fmt_vif.rstn); 572 | if(fmt_vif.mon_ck.fmt_req === 1) 573 | this.cg_formatter_length.sample(); 574 | end 575 | forever begin 576 | @(posedge fmt_vif.mon_ck.fmt_req); 577 | this.delay_req_to_grant = 0; 578 | forever begin 579 | if(fmt_vif.fmt_grant === 1) begin 580 | this.cg_formatter_grant.sample(); 581 | break; 582 | end 583 | else begin 584 | @(posedge fmt_vif.clk); 585 | this.delay_req_to_grant++; 586 | end 587 | end 588 | end 589 | join 590 | endtask 591 | 592 | function void report_phase(uvm_phase phase); 593 | string s; 594 | super.report_phase(phase); 595 | s = "\n---------------------------------------------------------------\n"; 596 | s = {s, "COVERAGE SUMMARY \n"}; 597 | s = {s, $sformatf("total coverage: %.1f \n", $get_coverage())}; 598 | s = {s, $sformatf(" cg_mcdf_reg_write_read coverage: %.1f \n", this.cg_mcdf_reg_write_read.get_coverage())}; 599 | s = {s, $sformatf(" cg_mcdf_reg_illegal_access coverage: %.1f \n", this.cg_mcdf_reg_illegal_access.get_coverage())}; 600 | s = {s, $sformatf(" cg_channel_disable_test coverage: %.1f \n", this.cg_channel_disable.get_coverage())}; 601 | s = {s, $sformatf(" cg_arbiter_priority_test coverage: %.1f \n", this.cg_arbiter_priority.get_coverage())}; 602 | s = {s, $sformatf(" cg_formatter_length_test coverage: %.1f \n", this.cg_formatter_length.get_coverage())}; 603 | s = {s, $sformatf(" cg_formatter_grant_test coverage: %.1f \n", this.cg_formatter_grant.get_coverage())}; 604 | s = {s, "---------------------------------------------------------------\n"}; 605 | `uvm_info(get_type_name(), s, UVM_LOW) 606 | endfunction 607 | 608 | virtual function void set_interface(virtual chnl_intf ch_vifs[3] 609 | ,virtual reg_intf reg_vif 610 | ,virtual arb_intf arb_vif 611 | ,virtual fmt_intf fmt_vif 612 | ,virtual mcdf_intf mcdf_vif 613 | ); 614 | this.chnl_vifs = ch_vifs; 615 | this.arb_vif = arb_vif; 616 | this.reg_vif = reg_vif; 617 | this.fmt_vif = fmt_vif; 618 | this.mcdf_vif = mcdf_vif; 619 | if(chnl_vifs[0] == null || chnl_vifs[1] == null || chnl_vifs[2] == null) 620 | $error("chnl interface handle is NULL, please check if target interface has been intantiated"); 621 | if(arb_vif == null) 622 | $error("arb interface handle is NULL, please check if target interface has been intantiated"); 623 | if(reg_vif == null) 624 | $error("reg interface handle is NULL, please check if target interface has been intantiated"); 625 | if(fmt_vif == null) 626 | $error("fmt interface handle is NULL, please check if target interface has been intantiated"); 627 | if(mcdf_vif == null) 628 | $error("mcdf interface handle is NULL, please check if target interface has been intantiated"); 629 | endfunction 630 | endclass: mcdf_coverage 631 | 632 | class mcdf_virtual_sequencer extends uvm_sequencer; 633 | reg_sequencer reg_sqr; 634 | fmt_sequencer fmt_sqr; 635 | chnl_sequencer chnl_sqrs[3]; 636 | mcdf_rgm rgm; 637 | virtual mcdf_intf intf; 638 | `uvm_component_utils(mcdf_virtual_sequencer) 639 | function new (string name = "mcdf_virtual_sequencer", uvm_component parent); 640 | super.new(name, parent); 641 | endfunction 642 | function void set_interface(virtual mcdf_intf intf); 643 | if(intf == null) 644 | $error("interface handle is NULL, please check if target interface has been intantiated"); 645 | else 646 | this.intf = intf; 647 | endfunction 648 | endclass 649 | 650 | // MCDF top environment 651 | class mcdf_env extends uvm_env; 652 | chnl_agent chnl_agts[3]; 653 | reg_agent reg_agt; 654 | fmt_agent fmt_agt; 655 | mcdf_checker chker; 656 | mcdf_coverage cvrg; 657 | mcdf_virtual_sequencer virt_sqr; 658 | //TODO-1.2 declare the mcdf_rgm handle, reg2mcdf_adapter handle and the 659 | //predictory handle 660 | mcdf_rgm rgm; 661 | reg2mcdf_adapter adapter; 662 | uvm_reg_predictor #(reg_trans) predictor; 663 | 664 | `uvm_component_utils(mcdf_env) 665 | 666 | function new (string name = "mcdf_env", uvm_component parent); 667 | super.new(name, parent); 668 | endfunction 669 | 670 | function void build_phase(uvm_phase phase); 671 | super.build_phase(phase); 672 | this.chker = mcdf_checker::type_id::create("chker", this); 673 | foreach(chnl_agts[i]) begin 674 | this.chnl_agts[i] = chnl_agent::type_id::create($sformatf("chnl_agts[%0d]",i), this); 675 | end 676 | this.reg_agt = reg_agent::type_id::create("reg_agt", this); 677 | this.fmt_agt = fmt_agent::type_id::create("fmt_agt", this); 678 | this.cvrg = mcdf_coverage::type_id::create("cvrg", this); 679 | virt_sqr = mcdf_virtual_sequencer::type_id::create("virt_sqr", this); 680 | //TODO-1.2 instantiate those objects 681 | // -mcdf_rgm object 682 | // -reg2mcdf_adapter object 683 | // -predictory object 684 | //and finish necessary configuration 685 | rgm = mcdf_rgm::type_id::create("rgm", this); 686 | rgm.build(); 687 | adapter = reg2mcdf_adapter::type_id::create("adapter", this); 688 | predictor = uvm_reg_predictor#(reg_trans)::type_id::create("predictor", this); 689 | endfunction 690 | 691 | function void connect_phase(uvm_phase phase); 692 | super.connect_phase(phase); 693 | chnl_agts[0].monitor.mon_bp_port.connect(chker.chnl0_bp_imp); 694 | chnl_agts[1].monitor.mon_bp_port.connect(chker.chnl1_bp_imp); 695 | chnl_agts[2].monitor.mon_bp_port.connect(chker.chnl2_bp_imp); 696 | reg_agt.monitor.mon_bp_port.connect(chker.reg_bp_imp); 697 | fmt_agt.monitor.mon_bp_port.connect(chker.fmt_bp_imp); 698 | virt_sqr.reg_sqr = reg_agt.sequencer; 699 | virt_sqr.fmt_sqr = fmt_agt.sequencer; 700 | foreach(virt_sqr.chnl_sqrs[i]) virt_sqr.chnl_sqrs[i] = chnl_agts[i].sequencer; 701 | //TODO-1.2 Link the register model with the adapter and the predictor 702 | rgm.map.set_sequencer(reg_agt.sequencer, adapter); 703 | reg_agt.monitor.mon_ana_port.connect(predictor.bus_in); 704 | predictor.map = rgm.map; 705 | predictor.adapter = adapter; 706 | //TODO-2.1 connect the virtual sequencer's rgm handle with rgm object 707 | virt_sqr.rgm = rgm; 708 | endfunction 709 | endclass: mcdf_env 710 | 711 | class mcdf_base_virtual_sequence extends uvm_sequence; 712 | idle_reg_sequence idle_reg_seq; 713 | write_reg_sequence write_reg_seq; 714 | read_reg_sequence read_reg_seq; 715 | chnl_data_sequence chnl_data_seq; 716 | fmt_config_sequence fmt_config_seq; 717 | mcdf_rgm rgm; 718 | 719 | `uvm_object_utils(mcdf_base_virtual_sequence) 720 | `uvm_declare_p_sequencer(mcdf_virtual_sequencer) 721 | 722 | function new (string name = "mcdf_base_virtual_sequence"); 723 | super.new(name); 724 | endfunction 725 | 726 | virtual task body(); 727 | `uvm_info(get_type_name(), "=====================STARTED=====================", UVM_LOW) 728 | //TODO-2.1 connect rgm handle 729 | rgm = p_sequencer.rgm; 730 | 731 | this.do_reg(); 732 | this.do_formatter(); 733 | this.do_data(); 734 | 735 | `uvm_info(get_type_name(), "=====================FINISHED=====================", UVM_LOW) 736 | endtask 737 | 738 | // do register configuration 739 | virtual task do_reg(); 740 | //User to implment the task in the child virtual sequence 741 | endtask 742 | 743 | // do external formatter down stream slave configuration 744 | virtual task do_formatter(); 745 | //User to implment the task in the child virtual sequence 746 | endtask 747 | 748 | // do data transition from 3 channel slaves 749 | virtual task do_data(); 750 | //User to implment the task in the child virtual sequence 751 | endtask 752 | 753 | virtual function bit diff_value(int val1, int val2, string id = "value_compare"); 754 | if(val1 != val2) begin 755 | `uvm_error("[CMPERR]", $sformatf("ERROR! %s val1 %8x != val2 %8x", id, val1, val2)) 756 | return 0; 757 | end 758 | else begin 759 | `uvm_info("[CMPSUC]", $sformatf("SUCCESS! %s val1 %8x == val2 %8x", id, val1, val2), UVM_LOW) 760 | return 1; 761 | end 762 | endfunction 763 | endclass 764 | 765 | // MCDF base test 766 | class mcdf_base_test extends uvm_test; 767 | mcdf_env env; 768 | virtual chnl_intf ch0_vif ; 769 | virtual chnl_intf ch1_vif ; 770 | virtual chnl_intf ch2_vif ; 771 | virtual reg_intf reg_vif ; 772 | virtual arb_intf arb_vif ; 773 | virtual fmt_intf fmt_vif ; 774 | virtual mcdf_intf mcdf_vif; 775 | 776 | `uvm_component_utils(mcdf_base_test) 777 | 778 | function new(string name = "mcdf_base_test", uvm_component parent); 779 | super.new(name, parent); 780 | endfunction 781 | 782 | function void build_phase(uvm_phase phase); 783 | super.build_phase(phase); 784 | // get virtual interface from top TB 785 | // 接口传递应该发生在run_test()之前,保证在进入build_phase之前,virtual interface已经被传递至uvm_config_db之中 786 | if(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch0_vif", ch0_vif)) begin 787 | `uvm_fatal("GETVIF","cannot get vif handle from config DB") 788 | end 789 | // SV传递接口使用自定义函数set_interface 790 | if(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch1_vif", ch1_vif)) begin 791 | `uvm_fatal("GETVIF","cannot get vif handle from config DB") 792 | end 793 | if(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch2_vif", ch2_vif)) begin 794 | `uvm_fatal("GETVIF","cannot get vif handle from config DB") 795 | end 796 | if(!uvm_config_db#(virtual reg_intf)::get(this,"","reg_vif", reg_vif)) begin 797 | `uvm_fatal("GETVIF","cannot get vif handle from config DB") 798 | end 799 | if(!uvm_config_db#(virtual arb_intf)::get(this,"","arb_vif", arb_vif)) begin 800 | `uvm_fatal("GETVIF","cannot get vif handle from config DB") 801 | end 802 | if(!uvm_config_db#(virtual fmt_intf)::get(this,"","fmt_vif", fmt_vif)) begin 803 | `uvm_fatal("GETVIF","cannot get vif handle from config DB") 804 | end 805 | if(!uvm_config_db#(virtual mcdf_intf)::get(this,"","mcdf_vif", mcdf_vif)) begin 806 | `uvm_fatal("GETVIF","cannot get vif handle from config DB") 807 | end 808 | 809 | this.env = mcdf_env::type_id::create("env", this); 810 | endfunction 811 | 812 | function void connect_phase(uvm_phase phase); 813 | super.connect_phase(phase); 814 | // After get virtual interface from config_db, and then set them to 815 | // child components 816 | this.set_interface(ch0_vif, ch1_vif, ch2_vif, reg_vif, arb_vif, fmt_vif, mcdf_vif); 817 | endfunction 818 | 819 | function void end_of_elaboration_phase(uvm_phase phase); 820 | super.end_of_elaboration_phase(phase); 821 | uvm_root::get().set_report_verbosity_level_hier(UVM_HIGH); 822 | uvm_root::get().set_report_max_quit_count(1); 823 | uvm_root::get().set_timeout(10ms); 824 | endfunction 825 | 826 | task run_phase(uvm_phase phase); 827 | // NOTE:: raise objection to prevent simulation stopping 828 | phase.raise_objection(this); 829 | 830 | this.run_top_virtual_sequence(); 831 | 832 | // NOTE:: drop objection to request simulation stopping 833 | phase.drop_objection(this); 834 | endtask 835 | 836 | virtual task run_top_virtual_sequence(); 837 | // User to implement this task in the child tests 838 | endtask 839 | 840 | virtual function void set_interface(virtual chnl_intf ch0_vif 841 | ,virtual chnl_intf ch1_vif 842 | ,virtual chnl_intf ch2_vif 843 | ,virtual reg_intf reg_vif 844 | ,virtual arb_intf arb_vif 845 | ,virtual fmt_intf fmt_vif 846 | ,virtual mcdf_intf mcdf_vif 847 | ); 848 | this.env.chnl_agts[0].set_interface(ch0_vif); 849 | this.env.chnl_agts[1].set_interface(ch1_vif); 850 | this.env.chnl_agts[2].set_interface(ch2_vif); 851 | this.env.reg_agt.set_interface(reg_vif); 852 | this.env.fmt_agt.set_interface(fmt_vif); 853 | this.env.chker.set_interface(mcdf_vif, '{ch0_vif, ch1_vif, ch2_vif}, arb_vif); 854 | this.env.cvrg.set_interface('{ch0_vif, ch1_vif, ch2_vif}, reg_vif, arb_vif, fmt_vif, mcdf_vif); 855 | this.env.virt_sqr.set_interface(mcdf_vif); 856 | endfunction 857 | endclass: mcdf_base_test 858 | 859 | //TODO-2.2 replace the register bus sequence with uvm_reg::write()/read() 860 | class mcdf_data_consistence_basic_virtual_sequence extends mcdf_base_virtual_sequence; 861 | `uvm_object_utils(mcdf_data_consistence_basic_virtual_sequence) 862 | function new (string name = "mcdf_data_consistence_basic_virtual_sequence"); 863 | super.new(name); 864 | endfunction 865 | task do_reg(); 866 | bit[31:0] wr_val, rd_val; 867 | uvm_status_e status; 868 | // slv0 with len=8, prio=0, en=1 869 | wr_val = (1<<3)+(0<<1)+1; 870 | rgm.chnl0_ctrl_reg.write(status, wr_val); 871 | rgm.chnl0_ctrl_reg.read(status, rd_val); 872 | void'(this.diff_value(wr_val, rd_val, "SLV0_WR_REG")); 873 | 874 | // slv1 with len=16, prio=1, en=1 875 | wr_val = (2<<3)+(1<<1)+1; 876 | rgm.chnl1_ctrl_reg.write(status, wr_val); 877 | rgm.chnl1_ctrl_reg.read(status, rd_val); 878 | void'(this.diff_value(wr_val, rd_val, "SLV1_WR_REG")); 879 | 880 | // slv2 with len=32, prio=2, en=1 881 | wr_val = (3<<3)+(2<<1)+1; 882 | rgm.chnl2_ctrl_reg.write(status, wr_val); 883 | rgm.chnl2_ctrl_reg.read(status, rd_val); 884 | void'(this.diff_value(wr_val, rd_val, "SLV2_WR_REG")); 885 | 886 | // send IDLE command 887 | `uvm_do_on(idle_reg_seq, p_sequencer.reg_sqr) 888 | endtask 889 | task do_formatter(); 890 | `uvm_do_on_with(fmt_config_seq, p_sequencer.fmt_sqr, {fifo == LONG_FIFO; bandwidth == HIGH_WIDTH;}) 891 | endtask 892 | task do_data(); 893 | fork 894 | `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[0], {ntrans==100; ch_id==0; data_nidles==0; pkt_nidles==1; data_size==8; }) 895 | `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[1], {ntrans==100; ch_id==1; data_nidles==1; pkt_nidles==4; data_size==16;}) 896 | `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[2], {ntrans==100; ch_id==2; data_nidles==2; pkt_nidles==8; data_size==32;}) 897 | join 898 | #10us; // wait until all data haven been transfered through MCDF 899 | endtask 900 | endclass: mcdf_data_consistence_basic_virtual_sequence 901 | 902 | class mcdf_data_consistence_basic_test extends mcdf_base_test; 903 | 904 | `uvm_component_utils(mcdf_data_consistence_basic_test) 905 | 906 | function new(string name = "mcdf_data_consistence_basic_test", uvm_component parent); 907 | super.new(name, parent); 908 | endfunction 909 | 910 | task run_top_virtual_sequence(); 911 | mcdf_data_consistence_basic_virtual_sequence top_seq = new(); 912 | top_seq.start(env.virt_sqr); 913 | endtask 914 | endclass: mcdf_data_consistence_basic_test 915 | 916 | //TODO-2.3 Follow the instructions below 917 | // -reset the register block 918 | // -set all value of WR registers via uvm_reg::set() 919 | // -update them via uvm_reg_block::update() 920 | // -compare the register value via uvm_reg::mirror() with backdoor access 921 | class mcdf_full_random_virtual_sequence extends mcdf_base_virtual_sequence; 922 | `uvm_object_utils(mcdf_base_virtual_sequence) 923 | function new (string name = "mcdf_base_virtual_sequence"); 924 | super.new(name); 925 | endfunction 926 | 927 | task do_reg(); 928 | bit[31:0] ch0_wr_val; 929 | bit[31:0] ch1_wr_val; 930 | bit[31:0] ch2_wr_val; 931 | uvm_status_e status; 932 | 933 | //reset the register block 934 | rgm.reset(); 935 | 936 | //slv0 with len={4,8,16,32}, prio={[0:3]}, en={[0:1]} 937 | ch0_wr_val = ($urandom_range(0,3)<<3)+($urandom_range(0,3)<<1)+$urandom_range(0,1); 938 | ch1_wr_val = ($urandom_range(0,3)<<3)+($urandom_range(0,3)<<1)+$urandom_range(0,1); 939 | ch2_wr_val = ($urandom_range(0,3)<<3)+($urandom_range(0,3)<<1)+$urandom_range(0,1); 940 | 941 | //set all value of WR registers via uvm_reg::set() 942 | rgm.chnl0_ctrl_reg.set(ch0_wr_val); 943 | rgm.chnl1_ctrl_reg.set(ch1_wr_val); 944 | rgm.chnl2_ctrl_reg.set(ch2_wr_val); 945 | 946 | //update them via uvm_reg_block::update() 947 | rgm.update(status); 948 | 949 | //wait until the registers in DUT have been updated 950 | #100ns; 951 | 952 | //compare all of write value and read value 953 | rgm.chnl0_ctrl_reg.mirror(status, UVM_CHECK, UVM_BACKDOOR); 954 | rgm.chnl1_ctrl_reg.mirror(status, UVM_CHECK, UVM_BACKDOOR); 955 | rgm.chnl2_ctrl_reg.mirror(status, UVM_CHECK, UVM_BACKDOOR); 956 | 957 | // send IDLE command 958 | `uvm_do_on(idle_reg_seq, p_sequencer.reg_sqr) 959 | endtask 960 | task do_formatter(); 961 | `uvm_do_on_with(fmt_config_seq, p_sequencer.fmt_sqr, {fifo inside {SHORT_FIFO, ULTRA_FIFO}; bandwidth inside {LOW_WIDTH, ULTRA_WIDTH};}) 962 | endtask 963 | task do_data(); 964 | fork 965 | `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[0], 966 | {ntrans inside {[400:600]}; ch_id==0; data_nidles inside {[0:3]}; pkt_nidles inside {1,2,4,8}; data_size inside {8,16,32};}) 967 | `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[1], 968 | {ntrans inside {[400:600]}; ch_id==0; data_nidles inside {[0:3]}; pkt_nidles inside {1,2,4,8}; data_size inside {8,16,32};}) 969 | `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[2], 970 | {ntrans inside {[400:600]}; ch_id==0; data_nidles inside {[0:3]}; pkt_nidles inside {1,2,4,8}; data_size inside {8,16,32};}) 971 | join 972 | #10us; // wait until all data haven been transfered through MCDF 973 | endtask 974 | endclass: mcdf_full_random_virtual_sequence 975 | 976 | class mcdf_full_random_test extends mcdf_base_test; 977 | 978 | `uvm_component_utils(mcdf_full_random_test) 979 | 980 | function new(string name = "mcdf_full_random_test", uvm_component parent); 981 | super.new(name, parent); 982 | endfunction 983 | 984 | task run_top_virtual_sequence(); 985 | mcdf_full_random_virtual_sequence top_seq = new(); 986 | top_seq.start(env.virt_sqr); 987 | endtask 988 | endclass: mcdf_full_random_test 989 | 990 | 991 | //TODO-3.1 Use build-in uvm register sequence 992 | // -uvm_reg_hw_reset_seq 993 | // -uvm_reg_bit_bash_seq 994 | // -uvm_reg_access_seq 995 | class mcdf_reg_builtin_virtual_sequence extends mcdf_base_virtual_sequence; 996 | `uvm_object_utils(mcdf_reg_builtin_virtual_sequence) 997 | function new (string name = "mcdf_reg_builtin_virtual_sequence"); 998 | super.new(name); 999 | endfunction 1000 | 1001 | task do_reg(); 1002 | uvm_reg_hw_reset_seq reg_rst_seq = new(); 1003 | uvm_reg_bit_bash_seq reg_bit_bash_seq = new(); 1004 | uvm_reg_access_seq reg_acc_seq = new(); 1005 | 1006 | // wait reset asserted and release 1007 | @(negedge p_sequencer.intf.rstn); 1008 | @(posedge p_sequencer.intf.rstn); 1009 | 1010 | `uvm_info("BLTINSEQ", "register reset sequence started", UVM_LOW) 1011 | rgm.reset(); 1012 | reg_rst_seq.model = rgm; 1013 | reg_rst_seq.start(p_sequencer.reg_sqr); 1014 | `uvm_info("BLTINSEQ", "register reset sequence finished", UVM_LOW) 1015 | 1016 | `uvm_info("BLTINSEQ", "register bit bash sequence started", UVM_LOW) 1017 | // reset hardware register and register model 1018 | p_sequencer.intf.rstn <= 'b0; 1019 | repeat(5) @(posedge p_sequencer.intf.clk); 1020 | p_sequencer.intf.rstn <= 'b1; 1021 | rgm.reset(); 1022 | reg_bit_bash_seq.model = rgm; 1023 | reg_bit_bash_seq.start(p_sequencer.reg_sqr); 1024 | `uvm_info("BLTINSEQ", "register bit bash sequence finished", UVM_LOW) 1025 | 1026 | `uvm_info("BLTINSEQ", "register access sequence started", UVM_LOW) 1027 | // reset hardware register and register model 1028 | p_sequencer.intf.rstn <= 'b0; 1029 | repeat(5) @(posedge p_sequencer.intf.clk); 1030 | p_sequencer.intf.rstn <= 'b1; 1031 | rgm.reset(); 1032 | reg_acc_seq.model = rgm; 1033 | reg_acc_seq.start(p_sequencer.reg_sqr); 1034 | `uvm_info("BLTINSEQ", "register access sequence finished", UVM_LOW) 1035 | endtask 1036 | endclass: mcdf_reg_builtin_virtual_sequence 1037 | 1038 | class mcdf_reg_builtin_test extends mcdf_base_test; 1039 | 1040 | `uvm_component_utils(mcdf_reg_builtin_test) 1041 | 1042 | function new(string name = "mcdf_reg_builtin_test", uvm_component parent); 1043 | super.new(name, parent); 1044 | endfunction 1045 | 1046 | task run_top_virtual_sequence(); 1047 | mcdf_reg_builtin_virtual_sequence top_seq = new(); 1048 | top_seq.start(env.virt_sqr); 1049 | endtask 1050 | endclass: mcdf_reg_builtin_test 1051 | 1052 | endpackage 1053 | --------------------------------------------------------------------------------