├── README.md ├── _config.yml ├── rcc_agent.sv ├── rcc_assertions.sv ├── rcc_config.sv ├── rcc_driver.sv ├── rcc_environment.sv ├── rcc_if.sv ├── rcc_in_coverage.sv ├── rcc_monitor.sv ├── rcc_out_coverage.sv ├── rcc_pkg.sv ├── rcc_scoreboard.sv ├── rcc_sequencer.sv ├── rcc_tb_top.sv ├── rcc_test.sv ├── ref_pred.sv ├── reference_model.c ├── results_conv.v ├── results_conv_test.sv ├── results_conv_test.v ├── timescale.v └── wall_time.c /README.md: -------------------------------------------------------------------------------- 1 | ## UVM testbench with DPI integration, Assertions and Functional Coverage 2 | 3 | In this project a complete verification testbench architecture for a result character conversion chip is constructed. 4 | 5 | 6 | ![uvm_arch_v2](https://user-images.githubusercontent.com/13079690/69000332-b9e58000-089b-11ea-8f1e-323dc407b2ca.png) 7 | 8 | - The testcase used for verification are the randomly generated input transactions for the DUT. 9 | - Further the functional verification is performed by comparing the output of the DUT with that of reference model. 10 | - To implement the reference model direct programming interface (DPI) functionality of SystemVerilog is used. 11 | - The reference model is the software implementation of the DUT written using the C-programming language. 12 | 13 | # Design Under test: RCC Unit used in DTMF Receiver 14 | 15 | ![uvm_dut](https://user-images.githubusercontent.com/13079690/69000445-bd7a0680-089d-11ea-8793-ee925c54bf82.png) 16 | 17 | # 100% Coverage Achieved for the DUT Verification 18 | 19 | ![UVM_Coverage_Netlist200](https://user-images.githubusercontent.com/13079690/69000386-d8984680-089c-11ea-9df2-3c81cf5377c3.png) 20 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-architect -------------------------------------------------------------------------------- /rcc_agent.sv: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | */ 4 | 5 | class rcc_agent extends uvm_agent; 6 | `uvm_component_utils(rcc_agent) 7 | 8 | uvm_analysis_port #(rcc_transaction) mon2ref; 9 | uvm_analysis_port #(rcc_transaction) mon2scb; 10 | 11 | rcc_sequencer rcc_seqr; 12 | rcc_driver rcc_drvr; 13 | rcc_monitor rcc_mtr; 14 | 15 | function new(string name, uvm_component parent); 16 | super.new(name, parent); 17 | endfunction: new 18 | 19 | function void build_phase(uvm_phase phase); 20 | super.build_phase(phase); 21 | mon2ref = new("mon2ref", this); 22 | mon2scb = new("mon2scb", this); 23 | 24 | rcc_seqr = rcc_sequencer::type_id::create(.name("rcc_seqr"), .parent(this)); 25 | rcc_drvr = rcc_driver::type_id::create(.name("rcc_drvr"), .parent(this)); 26 | rcc_mtr = rcc_monitor::type_id::create(.name("rcc_mtr"), .parent(this)); 27 | 28 | endfunction: build_phase 29 | 30 | function void connect_phase(uvm_phase phase); 31 | super.connect_phase(phase); 32 | 33 | // connect the analysis port of monitor to analysis port of agent 34 | rcc_mtr.mon2ref.connect(mon2ref); 35 | rcc_mtr.mon2scb.connect(mon2scb); 36 | 37 | // connect driver seq_item_port to sequencer seq_item_export 38 | rcc_drvr.seq_item_port.connect(rcc_seqr.seq_item_export); 39 | 40 | endfunction: connect_phase 41 | 42 | endclass: rcc_agent 43 | -------------------------------------------------------------------------------- /rcc_assertions.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * Assertion module for the RCC block 3 | * 4 | */ 5 | 6 | 7 | module rcc_assertions(rcc_if intf); 8 | 9 | 10 | always begin 11 | //forever begin 12 | @(posedge intf.clk) 13 | if(intf.reset == 1) 14 | assert (intf.dout == 8'hff) 15 | else 16 | //$stop; 17 | $display("ERROR: dout is not correctly initialized to reset value: %h", intf.dout); 18 | 19 | assert(intf.dout_flag == 1'b1) 20 | else 21 | $display("%b ERROR: dout_flag is not correctly initialized at reset", intf.dout_flag); 22 | 23 | end 24 | 25 | 26 | // adding the concurrent assertions 27 | 28 | 29 | property din_rcc_clk; 30 | @(posedge intf.clk) 31 | disable iff (intf.reset) $rose(intf.rcc_clk) |=> !$isunknown(intf.din); 32 | endproperty 33 | 34 | din_ckeck: assert property (din_rcc_clk) else begin 35 | $error("ERROR----------- din is unknown at rcc clock"); 36 | end 37 | 38 | 39 | // need to use non-overlapped operator // 40 | /* property digclk_doutflag; 41 | @(posedge intf.clk) 42 | disable iff (intf.reset) $changed(intf.dout_flag) |=> $rose(intf.digit_clk); 43 | endproperty 44 | 45 | dout_flag_check: assert property (digclk_doutflag) else begin 46 | $error("ERROR-------------- digit clock %t", $time); 47 | end*/ 48 | 49 | endmodule //assertion 50 | -------------------------------------------------------------------------------- /rcc_config.sv: -------------------------------------------------------------------------------- 1 | class rcc_configuration extends uvm_object; 2 | `uvm_object_utils(rcc_configuration) 3 | 4 | function new(string name = ""); 5 | super.new(name); 6 | endfunction: new 7 | 8 | endclass: rcc_configuration 9 | -------------------------------------------------------------------------------- /rcc_driver.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * Driver communicates with the DUT at pin level. 3 | * It receives the stimulus from the sequencer in form of transactions 4 | * Within Driver synchroization betwen sequencer and driver takes place via handshaking 5 | */ 6 | 7 | class rcc_driver extends uvm_driver#(rcc_transaction); 8 | `uvm_component_utils(rcc_driver) 9 | 10 | // virtual interface declaration 11 | virtual rcc_if vif; 12 | 13 | uvm_analysis_port #(rcc_transaction) din_cov; 14 | uvm_analysis_port #(rcc_transaction) addrs_cov; 15 | 16 | rcc_transaction cov_din_tx; 17 | rcc_transaction cov_addr_tx; 18 | 19 | 20 | function new(string name, uvm_component parent); 21 | super.new(name, parent); 22 | 23 | endfunction 24 | 25 | function void build_phase(uvm_phase phase); 26 | super.build_phase(phase); 27 | 28 | din_cov = new("din_cov", this); 29 | addrs_cov = new("addrs_cov", this); 30 | 31 | cov_din_tx = rcc_transaction::type_id::create("cov_din_tx", this); 32 | cov_addr_tx = rcc_transaction::type_id::create("cov_addr_tx", this); 33 | 34 | // get the virtual interface handle that was stored in the uvm_config_db 35 | // and assign it to the local vif field 36 | if(!uvm_config_db#(virtual rcc_if)::get(this, "", "vif", vif)) 37 | `uvm_fatal("No Vif", {"virtual interface must be set for: ", get_full_name(), ".vif"}); 38 | 39 | endfunction: build_phase 40 | 41 | bit [3:0] g_address, digcnt, qcnt; 42 | bit [15:0] g_din; 43 | 44 | // using sequence_item_port connect with sequencer 45 | // get the transaction and then drive the DUT 46 | task run_phase(uvm_phase phase); 47 | 48 | reset(); // reset task 49 | forever 50 | begin 51 | 52 | rcc_transaction rcc_tx; 53 | seq_item_port.get_next_item(rcc_tx); // get the transaction from sequencer 54 | digcnt = rcc_tx.digcnt; 55 | seq_item_port.item_done(); 56 | 57 | repeat(digcnt) 58 | begin 59 | repeat(4) // wait for 4 clock edges // 60 | @(posedge vif.clk); 61 | 62 | g_address = 0; 63 | 64 | seq_item_port.get_next_item(rcc_tx); 65 | g_din = rcc_tx.g_din; 66 | seq_item_port.item_done(); 67 | 68 | cov_din_tx.g_din = g_din; // for din coverage 69 | din_cov.write(cov_din_tx); 70 | 71 | repeat(8) // for 8 registers write the data // 72 | begin 73 | 74 | write_it; 75 | g_address = g_address +1; 76 | //if(rcc_tx.randomize()) 77 | seq_item_port.get_next_item(rcc_tx); 78 | // g_din = rcc_tx.g_din; 79 | seq_item_port.item_done(); 80 | 81 | seq_item_port.get_next_item(rcc_tx); 82 | g_din = rcc_tx.g_din; 83 | seq_item_port.item_done(); 84 | //$display("input: %h", g_din); 85 | 86 | 87 | cov_din_tx.g_din = g_din; // for din coverage 88 | din_cov.write(cov_din_tx); 89 | 90 | 91 | end 92 | //cov_din_tx.g_din = g_din; // for din coverage 93 | //din_cov.write(cov_din_tx); 94 | write_it; 95 | g_address = 0; 96 | 97 | 98 | repeat(160) 99 | @(posedge vif.clk); 100 | end //digcnt 101 | 102 | //if(rcc_tx.randomize()) 103 | seq_item_port.get_next_item(rcc_tx); 104 | qcnt = rcc_tx.qcnt; 105 | seq_item_port.item_done(); 106 | 107 | repeat(qcnt) 108 | begin 109 | repeat(4) 110 | @(posedge vif.clk); 111 | 112 | g_address = 0; 113 | g_din = 0; 114 | 115 | //seq_item_port.get_next_item(rcc_tx); 116 | //rcc_tx.g_din = g_din; 117 | // seq_item_port.item_done(); 118 | 119 | 120 | repeat(8) 121 | begin 122 | write_it; 123 | g_address = g_address +1; 124 | end 125 | 126 | write_it; 127 | g_address = 0; 128 | 129 | repeat(160) 130 | @(posedge vif.clk); 131 | 132 | end //qcnt 133 | //seq_item_port.item_done(); // transaction complete 134 | 135 | end //forever loop 136 | 137 | endtask // run_phase 138 | 139 | task write_it(); 140 | @(posedge vif.clk); 141 | vif.address <= g_address; 142 | vif.din <= g_din; 143 | 144 | cov_addr_tx.g_address = g_address; // for addrs coverage 145 | addrs_cov.write(cov_addr_tx); 146 | 147 | @(posedge vif.clk); 148 | vif.rcc_clk <= 1; 149 | @(posedge vif.clk); 150 | vif.rcc_clk <= 0; 151 | @(posedge vif.clk); 152 | vif.din <= 'bz; 153 | endtask 154 | 155 | 156 | 157 | //bit [8:0] [15:0] temp; 158 | // reset task, Resets the interface signals to default/initial values 159 | task reset(); 160 | 161 | vif.test_mode = 0; 162 | vif.scan_in0 = 0; 163 | vif.scan_in1 = 0; 164 | vif.scan_en = 0; 165 | 166 | vif.din = 16'h0000; 167 | vif.address = 4'h0; 168 | 169 | vif.rcc_clk = 1'b0; 170 | vif.reset = 1'b0; 171 | // assertion checks 172 | //vif.dout = 8'haa; 173 | // vif.dout_flag = 1'b0; 174 | 175 | @(negedge vif.clk); 176 | @(negedge vif.clk); 177 | vif.reset = 1; 178 | 179 | $display("----------- RESET START------"); 180 | @(negedge vif.clk); 181 | @(negedge vif.clk); 182 | 183 | vif.reset = 0; 184 | $display("------------ RESET ENDS-----------"); 185 | endtask 186 | 187 | 188 | endclass: rcc_driver 189 | 190 | 191 | -------------------------------------------------------------------------------- /rcc_environment.sv: -------------------------------------------------------------------------------- 1 | class rcc_environment extends uvm_env; 2 | `uvm_component_utils(rcc_environment) 3 | 4 | rcc_agent rcc_agnt; // DUT out 5 | ref_pred rcc_ref_pred; // Ref out 6 | rcc_scoreboard rcc_scb; // compare both outputs 7 | rcc_in_coverage rcc_cov; 8 | rcc_out_coverage rcc_out_cov; 9 | 10 | 11 | function new(string name, uvm_component parent); 12 | super.new(name, parent); 13 | endfunction: new 14 | 15 | function void build_phase(uvm_phase phase); 16 | super.build_phase(phase); 17 | rcc_agnt = rcc_agent::type_id::create(.name("rcc_agnt"), .parent(this)); 18 | rcc_scb = rcc_scoreboard::type_id::create(.name("rcc_scb"), .parent(this)); 19 | rcc_ref_pred = ref_pred::type_id::create(.name("rcc_ref_pred"), .parent(this)); 20 | rcc_cov = rcc_in_coverage::type_id::create(.name("rcc_cov"), .parent(this)); 21 | rcc_out_cov = rcc_out_coverage::type_id::create(.name("rcc_out_cov"), .parent(this)); 22 | 23 | endfunction: build_phase 24 | 25 | // Connect_phase 26 | function void connect_phase(uvm_phase phase); 27 | super.connect_phase(phase); 28 | 29 | rcc_agnt.mon2scb.connect(rcc_scb.out_dut); 30 | rcc_agnt.mon2ref.connect(rcc_ref_pred.analysis_export); 31 | rcc_ref_pred.ref2scb.connect(rcc_scb.out_ref); 32 | 33 | rcc_agnt.rcc_drvr.din_cov.connect(rcc_cov.cov_din); // coverage analysis connection 34 | rcc_agnt.rcc_drvr.addrs_cov.connect(rcc_cov.cov_addr); // coverage analysis connection 35 | 36 | rcc_agnt.mon2scb.connect(rcc_out_cov.out_dut_cov); // coverage analysis connection 37 | rcc_ref_pred.ref2scb.connect(rcc_out_cov.out_ref_cov); // coverage analysis connection 38 | 39 | endfunction 40 | 41 | endclass: rcc_environment 42 | -------------------------------------------------------------------------------- /rcc_if.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * RCC interface 3 | */ 4 | interface rcc_if; 5 | 6 | bit reset, clk; 7 | 8 | bit rcc_clk; 9 | 10 | logic [3:0] address; 11 | 12 | logic [15:0] din; 13 | 14 | bit digit_clk; 15 | 16 | logic [7:0] dout; 17 | 18 | logic dout_flag; 19 | 20 | bit test_mode; 21 | 22 | bit scan_in0, scan_in1, scan_en; 23 | 24 | bit scan_out0, scan_out1; 25 | 26 | 27 | endinterface:rcc_if 28 | 29 | 30 | -------------------------------------------------------------------------------- /rcc_in_coverage.sv: -------------------------------------------------------------------------------- 1 | class rcc_in_coverage extends uvm_component; 2 | `uvm_component_utils(rcc_in_coverage) 3 | 4 | virtual rcc_if vif; 5 | 6 | uvm_analysis_export #(rcc_transaction) cov_din; 7 | uvm_analysis_export #(rcc_transaction) cov_addr; 8 | 9 | uvm_tlm_analysis_fifo #(rcc_transaction) cov_din_fifo; 10 | uvm_tlm_analysis_fifo #(rcc_transaction) cov_addr_fifo; 11 | 12 | rcc_transaction seq_din; 13 | rcc_transaction seq_addr; 14 | 15 | rcc_transaction seq_in; 16 | rcc_transaction seq_ad; 17 | 18 | covergroup din_rtl; // @(posedge vif.clk); 19 | cover_point_din_rtl: coverpoint seq_in.g_din {option.auto_bin_max = 65535;} 20 | endgroup 21 | 22 | covergroup addr_rtl; //@(posedge vif.rcc_clk); 23 | 24 | cover_point_addr_rtl: coverpoint seq_ad.g_address{ bins addrs_0 = {0}; 25 | bins addrs_1 = {1}; 26 | bins addrs_2 = {2}; 27 | bins addrs_3 = {3}; 28 | bins addrs_4 = {4}; 29 | bins addrs_5 = {5}; 30 | bins addrs_6 = {6}; 31 | bins addrs_7 = {7}; 32 | ignore_bins ig = {[8:15]}; 33 | } 34 | 35 | endgroup 36 | 37 | 38 | function new(string name = "", uvm_component parent); 39 | super.new(name, parent); 40 | din_rtl = new(); 41 | addr_rtl = new(); 42 | endfunction 43 | 44 | function void build_phase(uvm_phase phase); 45 | super.build_phase(phase); 46 | 47 | if(!uvm_config_db#(virtual rcc_if)::get(this, "", "vif", vif)) 48 | `uvm_fatal("No Vif", {"virtual interface must be set for: ", get_full_name(), ".vif"}); 49 | 50 | seq_in = rcc_transaction::type_id::create("seq_in", this); 51 | seq_ad = rcc_transaction::type_id::create("seq_ad", this); 52 | 53 | cov_din = new("cov_din", this); 54 | cov_addr = new("cov_addr", this); 55 | 56 | cov_din_fifo = new("cov_din_fifo", this); 57 | cov_addr_fifo = new("cov_addr_fifo", this); 58 | 59 | seq_din = rcc_transaction::type_id::create("seq_din", this); 60 | seq_addr = rcc_transaction::type_id::create("seq_addr", this); 61 | endfunction 62 | 63 | function void connect_phase(uvm_phase phase); 64 | cov_din.connect(cov_din_fifo.analysis_export); 65 | cov_addr.connect(cov_addr_fifo.analysis_export); 66 | endfunction 67 | 68 | task run_phase(uvm_phase phase); 69 | fork 70 | din_coverage(); 71 | addr_coverage(); 72 | join_none 73 | 74 | endtask 75 | 76 | task din_coverage; 77 | forever begin 78 | @(posedge vif.clk) 79 | cov_din_fifo.get(seq_din); 80 | seq_in.g_din = seq_din.g_din; 81 | //$display("cov input : %h\n", seq_in.g_din); 82 | din_rtl.sample(); 83 | // $display("input cov: %f\n", din_rtl.get_coverage()); 84 | end 85 | endtask 86 | 87 | task addr_coverage; 88 | forever begin 89 | @(posedge vif.rcc_clk) 90 | cov_addr_fifo.get(seq_addr); 91 | seq_ad.g_address = seq_addr.g_address; 92 | //$display("cov input : %h\n", seq_ad.g_address); 93 | addr_rtl.sample(); 94 | // $display("input address cov: %f\n", addr_rtl.get_coverage()); 95 | end 96 | 97 | endtask 98 | 99 | 100 | endclass 101 | 102 | 103 | -------------------------------------------------------------------------------- /rcc_monitor.sv: -------------------------------------------------------------------------------- 1 | // Monitor Class 2 | // It receives the response from the DUT and converts the signal level response into transactions 3 | // sends the transactions to various other testbench components 4 | 5 | class rcc_monitor extends uvm_monitor; 6 | `uvm_component_utils(rcc_monitor) 7 | 8 | // declare the interface 9 | virtual rcc_if vif; 10 | rcc_transaction rcc_tx; 11 | 12 | // Analysis Ports 13 | uvm_analysis_port#(rcc_transaction) mon2ref; 14 | uvm_analysis_port#(rcc_transaction) mon2scb; 15 | 16 | function new(string name, uvm_component parent); 17 | super.new(name, parent); 18 | endfunction: new 19 | 20 | function void build_phase(uvm_phase phase); 21 | super.build_phase(phase); 22 | 23 | mon2ref = new("mon2ref", this); 24 | mon2scb = new("mon2scb", this); 25 | 26 | // get the virtual interface handle from config database 27 | if(!uvm_config_db#(virtual rcc_if)::get(this, "", "vif", vif)) 28 | `uvm_fatal("No Vif", {"virtual interface must be set for: ", get_full_name(), ".vif"}); 29 | endfunction: build_phase 30 | 31 | bit [15:0] array_data [9]; 32 | integer i= 0; 33 | integer j; 34 | 35 | task run_phase(uvm_phase phase); 36 | fork 37 | sample_input(); 38 | sample_output(); 39 | join 40 | 41 | endtask 42 | 43 | 44 | task sample_input; 45 | forever 46 | begin 47 | rcc_transaction data_collect; 48 | data_collect = rcc_transaction::type_id::create("data_collect", this); 49 | @(posedge vif.rcc_clk) 50 | data_collect.g_din = vif.din; 51 | mon2ref.write(data_collect); 52 | 53 | 54 | end //forever loop 55 | endtask // sample_input 56 | 57 | task sample_output; 58 | forever 59 | begin 60 | 61 | rcc_transaction data_collect_out; 62 | data_collect_out = rcc_transaction::type_id::create("data_collect_out", this); 63 | 64 | @(posedge vif.digit_clk) 65 | data_collect_out.dout = vif.dout; 66 | // Send the data through analysis port 67 | mon2scb.write(data_collect_out); 68 | 69 | 70 | end //forever loop 71 | endtask // sample_output 72 | 73 | endclass 74 | 75 | -------------------------------------------------------------------------------- /rcc_out_coverage.sv: -------------------------------------------------------------------------------- 1 | // Monitor takes the input from the reference model via a mailbox and checks DUT with ref. model 2 | // 3 | 4 | class rcc_out_coverage extends uvm_component; 5 | `uvm_component_utils(rcc_out_coverage) 6 | 7 | virtual rcc_if vif; 8 | 9 | uvm_analysis_export #(rcc_transaction) out_dut_cov; 10 | uvm_analysis_export #(rcc_transaction) out_ref_cov; 11 | 12 | uvm_tlm_analysis_fifo #(rcc_transaction) dut_cov_fifo; 13 | uvm_tlm_analysis_fifo #(rcc_transaction) ref_cov_fifo; 14 | 15 | rcc_transaction dut_trans_cov; 16 | rcc_transaction ref_trans_cov; 17 | 18 | bit count_min = 0; 19 | int watermark_count = 10; 20 | 21 | bit [7:0] refmdl_dout; 22 | bit [7:0] rtl_dout; 23 | 24 | //declare coun for rtl digits 25 | int dut_1 = 0; 26 | int dut_2 = 0; 27 | int dut_3 = 0; 28 | int dut_a = 0; 29 | int dut_4 = 0; 30 | int dut_5 = 0; 31 | int dut_6 = 0; 32 | int dut_b = 0; 33 | int dut_7 = 0; 34 | int dut_8 = 0; 35 | int dut_9 = 0; 36 | int dut_c = 0; 37 | int dut_star = 0; 38 | int dut_0 = 0; 39 | int dut_pound = 0; 40 | int dut_d = 0; 41 | 42 | 43 | //declare coun for ref model digits 44 | int ref_1 = 0; 45 | int ref_2 = 0; 46 | int ref_3 = 0; 47 | int ref_a = 0; 48 | int ref_4 = 0; 49 | int ref_5 = 0; 50 | int ref_6 = 0; 51 | int ref_b = 0; 52 | int ref_7 = 0; 53 | int ref_8 = 0; 54 | int ref_9 = 0; 55 | int ref_c = 0; 56 | int ref_star = 0; 57 | int ref_0 = 0; 58 | int ref_pound = 0; 59 | int ref_d = 0; 60 | 61 | // coverage 62 | covergroup output_coverage; // @(posedge vif.digit_clk); 63 | 64 | cover_point_dout_rtl: coverpoint rtl_dout { bins dout_rtl_0 = {48}; // 48 is decimal 0 65 | bins dout_rtl_1 = {49}; 66 | bins dout_rtl_2 = {50}; 67 | bins dout_rtl_3 = {51}; 68 | bins dout_rtl_4 = {52}; 69 | bins dout_rtl_5 = {53}; 70 | bins dout_rtl_6 = {54}; 71 | bins dout_rtl_7 = {55}; 72 | bins dout_rtl_8 = {56}; 73 | bins dout_rtl_9 = {57}; 74 | bins dout_rtl_a = {97}; 75 | bins dout_rtl_b = {98}; 76 | bins dout_rtl_c = {99}; 77 | bins dout_rtl_d = {100}; 78 | bins dout_rtl_star = {42}; 79 | bins dout_rtl_pound = {35}; 80 | ignore_bins ig_rtl = {[1:34], [36:41], [43:47], [58:96],[101:255]}; 81 | } 82 | 83 | cover_point_out_ref: coverpoint refmdl_dout { bins out_ref_0 = {48}; 84 | bins out_ref_1 = {49}; 85 | bins out_ref_2 = {50}; 86 | bins out_ref_3 = {51}; 87 | bins out_ref_4 = {52}; 88 | bins out_ref_5 = {53}; 89 | bins out_ref_6 = {54}; 90 | bins out_ref_7 = {55}; 91 | bins out_ref_8 = {56}; 92 | bins out_ref_9 = {57}; 93 | bins out_ref_a = {97}; 94 | bins out_ref_b = {98}; 95 | bins out_ref_c = {99}; 96 | bins out_ref_d = {100}; 97 | bins out_ref_star = {42}; 98 | bins out_ref_pound = {35}; 99 | ignore_bins ig_ref = {[1:34], [36:41], [43:47], [58:96],[101:255]}; 100 | } 101 | 102 | // cross coverage between ASCII digit produced by RTL and ref model 103 | cross_rtl_ref_out: cross cover_point_dout_rtl, cover_point_out_ref 104 | { 105 | bins cross_out_0 = binsof (cover_point_dout_rtl) intersect {48}; 106 | bins cross_out_1 = binsof (cover_point_dout_rtl) intersect {49}; 107 | bins cross_out_2 = binsof (cover_point_dout_rtl) intersect {50}; 108 | bins cross_out_3 = binsof (cover_point_dout_rtl) intersect {51}; 109 | bins cross_out_4 = binsof (cover_point_dout_rtl) intersect {52}; 110 | bins cross_out_5 = binsof (cover_point_dout_rtl) intersect {53}; 111 | bins cross_out_6 = binsof (cover_point_dout_rtl) intersect {54}; 112 | bins cross_out_7 = binsof (cover_point_dout_rtl) intersect {55}; 113 | bins cross_out_8 = binsof (cover_point_dout_rtl) intersect {56}; 114 | bins cross_out_9 = binsof (cover_point_dout_rtl) intersect {57}; 115 | bins cross_out_a = binsof (cover_point_dout_rtl) intersect {97}; 116 | bins cross_out_b = binsof (cover_point_dout_rtl) intersect {98}; 117 | bins cross_out_c = binsof (cover_point_dout_rtl) intersect {99}; 118 | bins cross_out_d = binsof (cover_point_dout_rtl) intersect {100}; 119 | bins cross_out_star = binsof (cover_point_dout_rtl) intersect {42}; 120 | bins cross_out_pound = binsof (cover_point_dout_rtl) intersect {35}; 121 | 122 | } 123 | 124 | endgroup //output_coverage 125 | 126 | 127 | 128 | // cross coverage for digit counts 129 | covergroup cross_digit_count; // @(posedge vif.digit_clk); 130 | 131 | cross_ref_1: coverpoint ref_1{option.auto_bin_max = 1;} 132 | cross_ref_2: coverpoint ref_2{option.auto_bin_max = 1;} 133 | cross_ref_3: coverpoint ref_3{option.auto_bin_max = 1;} 134 | cross_ref_4: coverpoint ref_4{option.auto_bin_max = 1;} 135 | cross_ref_5: coverpoint ref_5{option.auto_bin_max = 1;} 136 | cross_ref_6: coverpoint ref_6{option.auto_bin_max = 1;} 137 | cross_ref_7: coverpoint ref_7{option.auto_bin_max = 1;} 138 | cross_ref_8: coverpoint ref_8{option.auto_bin_max = 1;} 139 | cross_ref_9: coverpoint ref_9{option.auto_bin_max = 1;} 140 | cross_ref_0: coverpoint ref_0{option.auto_bin_max = 1;} 141 | cross_ref_a: coverpoint ref_a{option.auto_bin_max = 1;} 142 | cross_ref_b: coverpoint ref_b{option.auto_bin_max = 1;} 143 | cross_ref_c: coverpoint ref_c{option.auto_bin_max = 1;} 144 | cross_ref_d: coverpoint ref_d{option.auto_bin_max = 1;} 145 | cross_ref_star: coverpoint ref_star{option.auto_bin_max = 1;} 146 | cross_ref_pound: coverpoint ref_pound{option.auto_bin_max = 1;} 147 | 148 | 149 | cross_rtl_1: coverpoint dut_1{option.auto_bin_max = 1;} 150 | cross_rtl_2: coverpoint dut_2{option.auto_bin_max = 1;} 151 | cross_rtl_3: coverpoint dut_3{option.auto_bin_max = 1;} 152 | cross_rtl_4: coverpoint dut_4{option.auto_bin_max = 1;} 153 | cross_rtl_5: coverpoint dut_5{option.auto_bin_max = 1;} 154 | cross_rtl_6: coverpoint dut_6{option.auto_bin_max = 1;} 155 | cross_rtl_7: coverpoint dut_7{option.auto_bin_max = 1;} 156 | cross_rtl_8: coverpoint dut_8{option.auto_bin_max = 1;} 157 | cross_rtl_9: coverpoint dut_9{option.auto_bin_max = 1;} 158 | cross_rtl_0: coverpoint dut_0{option.auto_bin_max = 1;} 159 | cross_rtl_a: coverpoint dut_a{option.auto_bin_max = 1;} 160 | cross_rtl_b: coverpoint dut_b{option.auto_bin_max = 1;} 161 | cross_rtl_c: coverpoint dut_c{option.auto_bin_max = 1;} 162 | cross_rtl_d: coverpoint dut_d{option.auto_bin_max = 1;} 163 | cross_rtl_star: coverpoint dut_star{option.auto_bin_max = 1;} 164 | cross_rtl_pound: coverpoint dut_pound{option.auto_bin_max = 1;} 165 | 166 | 167 | digit_1: cross cross_ref_1, cross_rtl_1; 168 | digit_2: cross cross_ref_2, cross_rtl_2; 169 | digit_3: cross cross_ref_3, cross_rtl_3; 170 | digit_4: cross cross_ref_4, cross_rtl_4; 171 | digit_5: cross cross_ref_5, cross_rtl_5; 172 | digit_6: cross cross_ref_6, cross_rtl_6; 173 | digit_7: cross cross_ref_7, cross_rtl_7; 174 | digit_8: cross cross_ref_8, cross_rtl_8; 175 | digit_9: cross cross_ref_9, cross_rtl_9; 176 | digit_0: cross cross_ref_0, cross_rtl_0; 177 | digit_a: cross cross_ref_a, cross_rtl_a; 178 | digit_b: cross cross_ref_b, cross_rtl_b; 179 | digit_c: cross cross_ref_c, cross_rtl_c; 180 | digit_d: cross cross_ref_d, cross_rtl_d; 181 | digit_star: cross cross_ref_star, cross_rtl_star; 182 | digit_pound: cross cross_ref_pound, cross_rtl_pound; 183 | 184 | 185 | endgroup // cross_digit_count 186 | 187 | 188 | 189 | function new(string name= "", uvm_component parent); 190 | super.new(name, parent); 191 | output_coverage = new(); 192 | cross_digit_count = new(); 193 | endfunction 194 | 195 | function void build_phase(uvm_phase phase); 196 | super.build_phase(phase); 197 | out_dut_cov = new("out_dut_cov", this); 198 | out_ref_cov = new("out_ref_cov", this); 199 | 200 | dut_cov_fifo = new("dut_cov_fifo", this); 201 | ref_cov_fifo = new("ref_cov_fifo", this); 202 | 203 | dut_trans_cov = rcc_transaction::type_id::create("dut_trans_cov", this); 204 | ref_trans_cov = rcc_transaction::type_id::create("ref_trans_cov", this); 205 | 206 | // get the virtual interface handle that was stored in the uvm_config_db 207 | // and assign it to the local vif field 208 | if(!uvm_config_db#(virtual rcc_if)::get(this, "", "vif", vif)) 209 | `uvm_fatal("No Vif", {"virtual interface must be set for: ", get_full_name(), ".vif"}); 210 | 211 | endfunction: build_phase 212 | 213 | function void connect_phase(uvm_phase phase); 214 | out_dut_cov.connect(dut_cov_fifo.analysis_export); 215 | out_ref_cov.connect(ref_cov_fifo.analysis_export); 216 | endfunction: connect_phase 217 | 218 | 219 | 220 | task run_phase(uvm_phase phase); 221 | forever begin 222 | @(posedge vif.digit_clk) 223 | dut_cov_fifo.get(dut_trans_cov); 224 | ref_cov_fifo.get(ref_trans_cov); 225 | 226 | rtl_dout = dut_trans_cov.dout; 227 | refmdl_dout = ref_trans_cov.dout; 228 | 229 | // $display("rtl_dout; %c\n", rtl_dout); 230 | // $display("refmdl_dout; %c", refmdl_dout); 231 | 232 | if(rtl_dout == "1") dut_1 += 1; 233 | else if(rtl_dout == "2") dut_2 += 1; 234 | else if(rtl_dout == "3") dut_3 += 1; 235 | else if(rtl_dout == "a") dut_a += 1; 236 | else if(rtl_dout == "4") dut_4 += 1; 237 | else if(rtl_dout == "5") dut_5 += 1; 238 | else if(rtl_dout == "6") dut_6 += 1; 239 | else if(rtl_dout == "b") dut_b += 1; 240 | else if(rtl_dout == "7") dut_7 += 1; 241 | else if(rtl_dout == "8") dut_8 += 1; 242 | else if(rtl_dout == "9") dut_9 += 1; 243 | else if(rtl_dout == "c") dut_c += 1; 244 | else if(rtl_dout == "*") dut_star += 1; 245 | else if(rtl_dout == "0") dut_0 += 1; 246 | else if(rtl_dout == "#") dut_pound += 1; 247 | else if(rtl_dout == "d") dut_d += 1; 248 | 249 | 250 | 251 | if(refmdl_dout == "1") ref_1 += 1; 252 | else if(refmdl_dout == "2") ref_2 += 1; 253 | else if(refmdl_dout == "3") ref_3 += 1; 254 | else if(refmdl_dout == "a") ref_a += 1; 255 | else if(refmdl_dout == "4") ref_4 += 1; 256 | else if(refmdl_dout == "5") ref_5 += 1; 257 | else if(refmdl_dout == "6") ref_6 += 1; 258 | else if(refmdl_dout == "b") ref_b += 1; 259 | else if(refmdl_dout == "7") ref_7 += 1; 260 | else if(refmdl_dout == "8") ref_8 += 1; 261 | else if(refmdl_dout == "9") ref_9 += 1; 262 | else if(refmdl_dout == "c") ref_c += 1; 263 | else if(refmdl_dout == "*") ref_star += 1; 264 | else if(refmdl_dout == "0") ref_0 += 1; 265 | else if(refmdl_dout == "#") ref_pound += 1; 266 | else if(refmdl_dout == "d") ref_d += 1; 267 | 268 | cross_digit_count.sample; 269 | output_coverage.sample; 270 | 271 | 272 | /*$display("--------- dut_1 count = %d", dut_1 ); 273 | $display("--------- dut_2 count = %d", dut_2 ); 274 | $display("--------- dut_3 count = %d", dut_3 ); 275 | $display("--------- dut_a count = %d", dut_a ); 276 | $display("--------- dut_4 count = %d", dut_4 ); 277 | $display("--------- dut_5 count = %d", dut_5 ); 278 | $display("--------- dut_6 count = %d", dut_6 ); 279 | $display("--------- dut_b count = %d", dut_b ); 280 | $display("--------- dut_7 count = %d", dut_7 ); 281 | $display("--------- dut_8 count = %d", dut_8 ); 282 | $display("--------- dut_9 count = %d", dut_9 ); 283 | $display("--------- dut_c count = %d", dut_c ); 284 | $display("--------- dut_d count = %d", dut_d ); 285 | $display("--------- dut_star count = %d", dut_star ); 286 | $display("--------- dut_0 count = %d", dut_0 ); 287 | $display("--------- dut_pound count = %d\n", dut_pound ); 288 | 289 | $display("--------- Count from REF Model ---------------\n"); 290 | 291 | $display("--------- ref_1 count = %d", ref_1 ); 292 | $display("--------- ref_2 count = %d", ref_2 ); 293 | $display("--------- ref_3 count = %d", ref_3 ); 294 | $display("--------- ref_a count = %d", ref_a ); 295 | $display("--------- ref_4 count = %d", ref_4 ); 296 | $display("--------- ref_5 count = %d", ref_5 ); 297 | $display("--------- ref_6 count = %d", ref_6 ); 298 | $display("--------- ref_b count = %d", ref_b ); 299 | $display("--------- ref_7 count = %d", ref_7 ); 300 | $display("--------- ref_8 count = %d", ref_8 ); 301 | $display("--------- ref_9 count = %d", ref_9 ); 302 | $display("--------- ref_c count = %d", ref_c ); 303 | $display("--------- ref_d count = %d", ref_d ); 304 | $display("--------- ref_star count = %d", ref_star ); 305 | $display("--------- ref_0 count = %d", ref_0 ); 306 | $display("--------- ref_pound count = %d", ref_pound );*/ 307 | 308 | //$display("--------- dut_9 count = %d", dut_9 ); 309 | // Watermark check 310 | 311 | 312 | if(dut_1 >= watermark_count && dut_2 >= watermark_count && dut_3 >= watermark_count && dut_4 >= watermark_count && dut_5 >= watermark_count && dut_6 >= watermark_count && dut_7 >= watermark_count &&dut_8 >= watermark_count && dut_9 >= watermark_count && dut_0 >= watermark_count && dut_a >= watermark_count && dut_b >= watermark_count && dut_c >= watermark_count && dut_d >= watermark_count && dut_star >= watermark_count && dut_pound >= watermark_count) 313 | 314 | begin 315 | 316 | count_min = 1; 317 | 318 | end 319 | 320 | if(count_min) 321 | begin 322 | 323 | $display("------Watermark of", " %d ",watermark_count, "reached for every digit----------"); 324 | $finish; 325 | 326 | end 327 | 328 | end// forever 329 | 330 | endtask 331 | 332 | 333 | 334 | endclass 335 | -------------------------------------------------------------------------------- /rcc_pkg.sv: -------------------------------------------------------------------------------- 1 | package rcc_pkg; 2 | import uvm_pkg::*; 3 | //`include "rcc_assertions.sv" 4 | `include "rcc_sequencer.sv" 5 | `include "rcc_in_coverage.sv" 6 | `include "rcc_out_coverage.sv" 7 | `include "rcc_driver.sv" 8 | `include"rcc_monitor.sv" 9 | `include "rcc_agent.sv" 10 | `include "ref_pred.sv" 11 | `include "rcc_scoreboard.sv" 12 | `include "rcc_config.sv" 13 | `include "rcc_environment.sv" 14 | `include "rcc_test.sv" 15 | 16 | endpackage: rcc_pkg 17 | -------------------------------------------------------------------------------- /rcc_scoreboard.sv: -------------------------------------------------------------------------------- 1 | // Checker receives the output from the Ref. Model and the output from DUT 2 | // It compares both the outputs 3 | // In this way it perform DUT vs Ref model verification 4 | 5 | 6 | class rcc_scoreboard extends uvm_scoreboard; 7 | `uvm_component_utils(rcc_scoreboard) 8 | 9 | 10 | uvm_analysis_export #(rcc_transaction) out_dut; 11 | uvm_analysis_export #(rcc_transaction) out_ref; 12 | 13 | uvm_tlm_analysis_fifo #(rcc_transaction) dut_fifo; 14 | uvm_tlm_analysis_fifo #(rcc_transaction) ref_fifo; 15 | 16 | //logic [7:0] dut_output, ref_output; 17 | 18 | virtual rcc_if vif; 19 | 20 | rcc_transaction dut_trans; 21 | rcc_transaction ref_trans; 22 | 23 | function new(string name= "", uvm_component parent); 24 | super.new(name, parent); 25 | endfunction 26 | 27 | function void build_phase(uvm_phase phase); 28 | super.build_phase(phase); 29 | out_dut = new("out_dut", this); 30 | out_ref = new("out_ref", this); 31 | 32 | dut_fifo = new("dut_fifo", this); 33 | ref_fifo = new("ref_fifo", this); 34 | 35 | dut_trans = rcc_transaction::type_id::create("dut_trans", this); 36 | ref_trans = rcc_transaction::type_id::create("ref_trans", this); 37 | 38 | // get the virtual interface handle that was stored in the uvm_config_db 39 | // and assign it to the local vif field 40 | if(!uvm_config_db#(virtual rcc_if)::get(this, "", "vif", vif)) 41 | `uvm_fatal("No Vif", {"virtual interface must be set for: ", get_full_name(), ".vif"}); 42 | 43 | endfunction: build_phase 44 | 45 | function void connect_phase(uvm_phase phase); 46 | out_dut.connect(dut_fifo.analysis_export); 47 | out_ref.connect(ref_fifo.analysis_export); 48 | endfunction: connect_phase 49 | 50 | 51 | task run_phase(uvm_phase phase); 52 | 53 | forever begin 54 | 55 | @(posedge vif.digit_clk) 56 | 57 | dut_fifo.get(dut_trans); 58 | ref_fifo.get(ref_trans); 59 | 60 | // using assertion to check the ref model and dut output 61 | assert(dut_trans.dout == ref_trans.dout) 62 | // $display("SUCCESS %c %c %d \n", dut_trans.dout, ref_trans.dout, $time); 63 | else 64 | $error("ERROR %c %c %d \n", dut_trans.dout, ref_trans.dout, $time); 65 | end// forever 66 | 67 | 68 | endtask 69 | 70 | endclass 71 | 72 | -------------------------------------------------------------------------------- /rcc_sequencer.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * UVM has separate class hierarchy for data (stimulus) 3 | */ 4 | 5 | /* 6 | * We use transactions to communicate between components 7 | * Its a higher abstraction layer than signal level information 8 | */ 9 | 10 | // user defined transaction extends uvm_sequence_item 11 | class rcc_transaction extends uvm_sequence_item; 12 | `uvm_object_utils(rcc_transaction) 13 | 14 | rand bit [15:0] g_din; 15 | rand bit [3:0] digcnt; 16 | rand bit [3:0] qcnt; 17 | bit [7:0] dout; // need for output checking 18 | bit [3:0] g_address; 19 | 20 | function new(string name = ""); 21 | super.new(name); 22 | endfunction: new 23 | 24 | endclass: rcc_transaction 25 | 26 | 27 | //---------------------------------------------------------------------------------------// 28 | 29 | 30 | /* 31 | * After we have created the transaction, we will create a sequence 32 | */ 33 | 34 | class rcc_sequence_child extends uvm_sequence#(rcc_transaction); 35 | `uvm_object_utils(rcc_sequence_child) 36 | 37 | rcc_transaction rcc_tx; 38 | 39 | function new(string name = ""); 40 | super.new(name); 41 | endfunction: new 42 | 43 | // body defines the behavior of the sequence 44 | task body(); 45 | 46 | rcc_tx = rcc_transaction::type_id::create("rcc_tx"); 47 | //repeat(9) 48 | //begin 49 | start_item(rcc_tx); 50 | if(rcc_tx.randomize()) 51 | //assert(rcc_tx.randomize()); 52 | finish_item(rcc_tx); 53 | 54 | //end 55 | endtask: body 56 | 57 | endclass: rcc_sequence_child 58 | 59 | 60 | class rcc_sequencer extends uvm_sequencer#(rcc_transaction); 61 | `uvm_object_utils(rcc_sequencer) 62 | 63 | function new(string name = ""); 64 | super.new(name); 65 | endfunction: new 66 | 67 | endclass: rcc_sequencer 68 | 69 | 70 | // this is top level sequenc that we start from uvm test class, which inturn creates 71 | //different sequence objects of child sequence. 72 | 73 | class rcc_sequence extends uvm_sequence#(rcc_transaction); 74 | `uvm_object_utils(rcc_sequence) 75 | 76 | //rcc_transaction rcc_tx; 77 | rcc_sequencer rcc_seqr; // handle to sequencer 78 | 79 | function new(string name = ""); 80 | super.new(name); 81 | endfunction: new 82 | 83 | // body defines the behavior of the sequence 84 | task body(); 85 | 86 | forever begin 87 | rcc_sequence_child seq; 88 | seq = rcc_sequence_child::type_id::create("seq"); // create child sequence object 89 | 90 | if(!seq.randomize()) 91 | `uvm_error(get_type_name(), "Failed to randomize sequence") 92 | //$display("First here: %d \n", $time); 93 | seq.start(rcc_seqr, this); 94 | //$display("end here: %d \n", $time); 95 | end 96 | endtask: body 97 | 98 | endclass: rcc_sequence 99 | 100 | 101 | -------------------------------------------------------------------------------- /rcc_tb_top.sv: -------------------------------------------------------------------------------- 1 | `include "uvm_macros.svh" 2 | `include "rcc_pkg.sv" 3 | `include "rcc_if.sv" 4 | 5 | module test; 6 | 7 | import uvm_pkg::*; 8 | 9 | // this package includes all our class definetion 10 | import rcc_pkg::*; 11 | 12 | 13 | import "DPI" function int sim_start_time(); 14 | import "DPI" function void start_day_date(); 15 | import "DPI" function void digit_gen_time(int dig_time); 16 | 17 | int sim_start; 18 | int sim_finish_time, execution_time; 19 | 20 | // instantiate the interface in top level module 21 | rcc_if intf(); 22 | 23 | // coverage instance for coverage result display 24 | rcc_in_coverage cov_in; 25 | rcc_out_coverage cov_out; 26 | 27 | // connect the DUT with the interface 28 | results_conv top( 29 | .clk(intf.clk), 30 | .reset(intf.reset), 31 | .test_mode(intf.test_mode), 32 | .rcc_clk(intf.rcc_clk), 33 | .address(intf.address), 34 | .din(intf.din), 35 | .digit_clk(intf.digit_clk), 36 | .dout(intf.dout), 37 | `ifdef NETLIST 38 | .dout_flag(intf.dout_flag), 39 | .scan_in0(intf.scan_in0), 40 | .scan_in1(intf.scan_in1), 41 | .scan_en(intf.scan_en) 42 | `else 43 | .dout_flag(intf.dout_flag) 44 | `endif 45 | ); 46 | 47 | 48 | rcc_assertions ass_rcc(intf); 49 | 50 | initial begin 51 | //Registers the Interface in the configuration block so that other 52 | //blocks can use it 53 | // we pass the virtual interface using config database 54 | uvm_config_db #(virtual rcc_if)::set(null, "*", "vif", intf); 55 | 56 | // execute the test 57 | run_test(); 58 | end 59 | 60 | initial begin 61 | $timeformat(-9, 2, "ns", 16); 62 | $set_coverage_db_name("results_conv"); 63 | `ifdef SDFSCAN 64 | $sdf_annotate("sdf/results_cov_tsmc18_scan.sdf", test.top); 65 | `endif 66 | end 67 | 68 | initial begin 69 | intf.clk <= 1'b0; 70 | end 71 | 72 | always begin 73 | #25 intf.clk = ~intf.clk; 74 | end 75 | 76 | // wall time 77 | initial begin 78 | sim_start = sim_start_time(); 79 | $display("-----------------------------------------------------\n"); 80 | 81 | $display("----------------SIMULATION STARTS AT: ----------------------------\n"); 82 | start_day_date(); 83 | end 84 | 85 | // final block that is executed at the end of the simulation 86 | // print other useful information like coverage results, finish wall time 87 | final begin 88 | sim_finish_time = sim_start_time(); 89 | execution_time = sim_finish_time - sim_start; 90 | 91 | $display("-----------------------------------------------------\n"); 92 | $display("Total Execution Time in days/hours/minutes/seconds is: "); 93 | digit_gen_time(execution_time); 94 | 95 | // print coverage at the end of simulation 96 | $display("din coverage for RTL = %f ", cov_in.din_rtl.get_coverage() ); 97 | $display("address coverage for RTL = %f\n ", cov_in.addr_rtl.get_coverage()); 98 | 99 | $display("RTL dout coverage for RTL = %f ", cov_out.output_coverage.cover_point_dout_rtl.get_coverage() ); 100 | $display("Ref Model dout coverage for RTL = %f\n ", cov_out.output_coverage.cover_point_out_ref.get_coverage() ); 101 | 102 | $display("dout cross coverage for RTL = %f ", cov_out.output_coverage.cross_rtl_ref_out.get_coverage() ); 103 | 104 | $display("digit count cross coverage = %f\n ", cov_out.cross_digit_count.get_coverage() ); 105 | 106 | $display("\n------------SIMULATION ENDS AT: -----------------"); 107 | start_day_date(); 108 | $display("----------------END------------------"); 109 | end 110 | 111 | 112 | endmodule 113 | -------------------------------------------------------------------------------- /rcc_test.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * test case for the RCC. It extends uvm_test base class 3 | * 1) it drives the sequence by connecting the sequence with sequencer 4 | * 2) create the env block 5 | */ 6 | 7 | class rcc_test extends uvm_test; 8 | //register the class name with uvm factory 9 | `uvm_component_utils(rcc_test) 10 | 11 | //instantiate the env 12 | rcc_environment rcc_env; 13 | 14 | function new(string name = "rcc_test", uvm_component parent = null); 15 | super.new(name, parent); 16 | endfunction: new 17 | 18 | // UVM build_phase 19 | function void build_phase (uvm_phase phase); 20 | super.build_phase(phase); 21 | rcc_env = rcc_environment::type_id::create(.name("rcc_env"), .parent(this)); 22 | endfunction: build_phase 23 | 24 | // UVM run_phase 25 | task run_phase(uvm_phase phase); 26 | // declare instance of sequence 27 | rcc_sequence rcc_seq; 28 | // create the sequence 29 | rcc_seq = rcc_sequence::type_id::create("rcc_seq"); 30 | assert(rcc_seq.randomize()); 31 | 32 | phase.raise_objection(.obj(this)); 33 | // test will call start() method of the sequence to initialte the execution of the sequence 34 | // and the argument is the sequencer on which sequence is going to start 35 | rcc_seq.start(rcc_env.rcc_agnt.rcc_seqr, null); 36 | phase.drop_objection(.obj(this)); 37 | 38 | endtask: run_phase 39 | endclass: rcc_test 40 | -------------------------------------------------------------------------------- /ref_pred.sv: -------------------------------------------------------------------------------- 1 | // class that receives the data from agent and pass it to C-reference model 2 | // and gets output returned from C-ref model 3 | 4 | // dpi imports 5 | import "DPI-C" function int input_arg( int array[8]); 6 | 7 | 8 | class ref_pred extends uvm_subscriber #(rcc_transaction); 9 | `uvm_component_utils(ref_pred) 10 | 11 | // Analysis port for sending the ref model output to scoreboard 12 | uvm_analysis_port#(rcc_transaction) ref2scb; 13 | 14 | integer i= 0; 15 | integer j = 0; 16 | integer array_data[8]; 17 | integer ref_out; 18 | 19 | 20 | rcc_transaction ref_output; 21 | //ref_output = rcc_transaction::type_id::create("ref_output", this); 22 | 23 | function new(string name = "", uvm_component parent); 24 | super.new(name, parent); 25 | endfunction 26 | 27 | function void build_phase(uvm_phase phase); 28 | super.build_phase(phase); 29 | 30 | ref2scb = new("ref2scb", this); 31 | 32 | ref_output = rcc_transaction::type_id::create("ref_output", this); 33 | 34 | endfunction 35 | 36 | 37 | function void write(rcc_transaction t); 38 | 39 | 40 | if(i <= 7) array_data[i] = t.g_din; 41 | 42 | i = i+1; 43 | 44 | if(i == 9) 45 | begin 46 | ref_out = input_arg(array_data); 47 | //$display("-------ref_out : %c\n", ref_out); 48 | ref_output.dout = ref_out; 49 | ref2scb.write(ref_output); 50 | // send the ref_out to scoreboard 51 | //ref2scb.write(ref_out); 52 | i = 0; 53 | for(j = 0; j< 8; j++) 54 | begin 55 | array_data[j] = 0; 56 | end 57 | end 58 | 59 | endfunction 60 | 61 | /*task run_phase(uvm_phase phase); 62 | 63 | // forever begin 64 | //$display("----------array_data = %h", array_data[0]); 65 | //$display("----------------HERE---------------------\n"); 66 | //$display("-----------------------ref_out: %c \n", ref_out); 67 | ref2scb.write(ref_output); 68 | // end 69 | endtask */ 70 | 71 | 72 | endclass 73 | 74 | 75 | /*------ debug -------------------------------------- 76 | $display("----------array_data = %h", array_data[0]); 77 | $display("----------array_data = %h", array_data[1]); 78 | $display("----------array_data = %h", array_data[2]); 79 | $display("----------array_data = %h", array_data[3]); 80 | $display("----------array_data = %h", array_data[4]); 81 | $display("----------array_data = %h", array_data[5]); 82 | $display("----------array_data = %h", array_data[6]); 83 | $display("----------array_data = %h", array_data[7]); 84 | //$display("----------array_data = %h", array_data[8]); 85 | --------------------------------------------------------*/ 86 | -------------------------------------------------------------------------------- /reference_model.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | 6 | struct freq_max_indx{ 7 | int max_low, max_high, low_idx, high_idx, mult_high, mult_low; 8 | }; 9 | 10 | typedef struct freq_max_indx Struct; 11 | 12 | // this function returns the index and loud frequency from low and high groups 13 | Struct frequency_group(int data_in[8]) 14 | { 15 | Struct s; 16 | 17 | s.mult_high = 0; 18 | s.mult_low = 0; 19 | s.low_idx = 0; 20 | s.high_idx = 0; 21 | s.mult_high = 0; 22 | s.mult_low = 0; 23 | 24 | int low_freq[4]; 25 | int high_freq[4]; 26 | 27 | for(int i = 0; i < 4; i++) 28 | { 29 | low_freq[i] = data_in[i]; 30 | } 31 | 32 | for(int j = 0; j < 4; j++) 33 | { 34 | high_freq[j] = data_in[j+4]; 35 | 36 | //printf("in data %04x \n", data_in[4]); 37 | //printf("in data high : %04x \n", data_in[j+4]); 38 | 39 | } 40 | 41 | //printf("\n--high---- %04x\n", high_freq[0]); 42 | 43 | // max and index 44 | s.low_idx = 0; 45 | 46 | s.max_low = low_freq[0]; 47 | for(int k = 0; k < 4; k++) 48 | { 49 | if(low_freq[k] > s.max_low) 50 | { 51 | s.max_low = low_freq[k]; 52 | s.low_idx = k; 53 | } 54 | } 55 | 56 | // max and index 57 | s.high_idx = 0; 58 | 59 | s.max_high = high_freq[0]; 60 | for(int k = 0; k < 4; k++) 61 | { 62 | if(high_freq[k] > s.max_high) 63 | { 64 | s.max_high = high_freq[k]; 65 | s.high_idx = k; 66 | } 67 | } 68 | 69 | // check for multple high frequency 70 | for(int k = 0; k <4; k++) 71 | { 72 | if(low_freq[k] == s.max_low) 73 | { 74 | s.mult_low = s.mult_low+1; 75 | } 76 | } 77 | 78 | for(int l = 0; l < 4; l++) 79 | { 80 | if(high_freq[l] == s.max_high) 81 | { 82 | s.mult_high = s.mult_high+1; 83 | } 84 | } 85 | 86 | 87 | return s; 88 | 89 | 90 | }// end frequency_group 91 | 92 | 93 | int dout = 255; 94 | int out_1 = 0; 95 | int out_2 = 255; 96 | int seen_quiet = 1; 97 | int ok = 0; 98 | int low_idx = 0; 99 | int high_idx = 0; 100 | int max_high = 0; 101 | int max_low = 0; 102 | 103 | int input_arg( int array[8]) 104 | { 105 | //int input_data[8]; 106 | Struct result; 107 | 108 | //int low_idx=0, high_idx=0; 109 | // int max_low=0, max_high=0; 110 | 111 | int mult_high=0, mult_low=0; 112 | 113 | //int dout ; 114 | //static int out_1; 115 | //static int out_2 ; 116 | 117 | //int seen_quiet=1; 118 | //int ok; 119 | 120 | //ok = 0; 121 | //printf("next out_1: %d\n", out_1); 122 | out_2 = out_1; 123 | //printf("next out_2: %d\n", out_2); 124 | low_idx = 8; 125 | high_idx= 8; 126 | mult_high = 0; 127 | mult_low = 0; 128 | 129 | 130 | 131 | result = frequency_group(array); 132 | low_idx = result.low_idx; 133 | max_low = result.max_low; 134 | high_idx = result.high_idx; 135 | max_high = result.max_high; 136 | mult_high = result.mult_high; 137 | mult_low = result.mult_low; 138 | 139 | 140 | 141 | //printf("-------------------low_idx: %d and max_low : %04x \n", low_idx, max_low); 142 | //printf("-------------------high_idx: %d and max_high : %04x \n", high_idx, max_high); 143 | //printf("##############################################################################\n"); 144 | 145 | //printf("----------------------------mult_high = %d, mult_low = %d\n", mult_high, mult_low); 146 | 147 | 148 | if(mult_high > 1 || mult_low > 1) 149 | { 150 | //printf("seen mult freq %d, %d \n",mult_high, mult_low); 151 | out_1 = 0; 152 | ok = 0; 153 | mult_low = 0; 154 | mult_high = 0; 155 | low_idx = 8; 156 | high_idx = 8; 157 | } 158 | 159 | else if(max_low == 0 && max_high == 0) 160 | { 161 | ok = 0; 162 | //out_1 = 0; 163 | low_idx = 8; 164 | high_idx = 8; 165 | mult_low = 0; 166 | mult_high = 0; 167 | } 168 | 169 | else if(low_idx != 8 && high_idx != 8) 170 | { 171 | out_1 = 0; 172 | ok = 0; 173 | 174 | if(max_low >= max_high) 175 | { 176 | if(max_high >= (max_low/4)) 177 | { 178 | ok = 1; 179 | } 180 | else 181 | { 182 | ok = 0; 183 | } 184 | } 185 | 186 | else if(max_high >= max_low) 187 | { 188 | if(max_low >= (max_high/4)) 189 | { 190 | ok = 1; 191 | } 192 | else 193 | { 194 | ok = 0; 195 | } 196 | } 197 | 198 | mult_low = 0; 199 | mult_high = 0; 200 | 201 | 202 | }// low_idx != 8 203 | 204 | 205 | if(ok ==1) 206 | { 207 | //printf("-----here------\n"); 208 | //printf("high: %d, low: %d \n", max_high, max_low); 209 | //printf("-------------------low_idx: %d and max_low : %04x \n", low_idx, max_low); 210 | //printf("-------------------high_idx: %d and max_high : %04x \n", high_idx, max_high); 211 | //printf("----------------------------ok: %d \n", ok); 212 | 213 | if(low_idx == 0) 214 | { 215 | if(high_idx == 0) 216 | out_1 = 49; 217 | else if(high_idx == 1) 218 | out_1 = 50; 219 | else if(high_idx == 2) 220 | out_1 = 51; 221 | else if(high_idx == 3) 222 | out_1 = 97; 223 | } 224 | 225 | else if(low_idx == 1) 226 | { 227 | if(high_idx == 0) 228 | out_1 = 52; 229 | else if(high_idx == 1) 230 | out_1 = 53; 231 | else if(high_idx == 2) 232 | out_1 = 54; 233 | else if(high_idx == 3) 234 | out_1 = 98; 235 | } 236 | 237 | else if(low_idx == 2) 238 | { 239 | if(high_idx== 0) 240 | out_1 = 55; 241 | else if(high_idx == 1) 242 | out_1 = 56; 243 | else if(high_idx == 2) 244 | out_1 = 57; 245 | else if(high_idx == 3) 246 | out_1 = 99; 247 | } 248 | 249 | else if(low_idx == 3) 250 | { 251 | if(high_idx == 0) 252 | out_1 = 42; 253 | else if(high_idx == 1) 254 | out_1 = 48; 255 | else if(high_idx == 2) 256 | out_1 = 35; 257 | else if(high_idx ==3) 258 | out_1 = 100; 259 | } 260 | 261 | else out_1 = 0; 262 | 263 | 264 | 265 | }// end ok = 1 266 | 267 | 268 | else 269 | { 270 | out_1 = 0; 271 | } 272 | 273 | 274 | if(out_1 == out_2) 275 | { 276 | //printf("-----------out_1 %d \n", out_1); 277 | //printf("-----------out_2 %d \n", out_2); 278 | if(out_2 == 0) 279 | { 280 | seen_quiet = 1; 281 | //out_2 = out_1; 282 | } 283 | else 284 | { 285 | if(seen_quiet) 286 | { 287 | seen_quiet = 0; 288 | dout = out_2; 289 | //printf("seen mult freq %d, %d \n",mult_high, mult_low); 290 | //printf("-----------------ref out = %c \n", dout); 291 | } 292 | else out_2 = out_1; 293 | } 294 | } 295 | 296 | else {//printf("before out_2: %d \n", out_2); 297 | out_2 = out_1; 298 | //printf("--------here ----out_2: %d out_1: %d \n", out_2, out_1); 299 | } 300 | 301 | 302 | for(int m = 0; m < 8; m++) 303 | { 304 | array[m] = 0; 305 | } 306 | 307 | return dout; 308 | 309 | }// end input_arg 310 | 311 | 312 | /* 313 | printf("---------------receive begin--------------\n"); 314 | printf("----------array_data = %04x \n", array[0]); 315 | printf("----------array_data = %04x \n", array[1]); 316 | printf("----------array_data = %04x \n", array[2]); 317 | printf("----------array_data = %04x \n", array[3]); 318 | printf("----------array_data = %04x \n", array[4]); 319 | printf("----------array_data = %04x \n", array[5]); 320 | printf("----------array_data = %04x \n", array[6]); 321 | printf("----------array_data = %04x \n", array[7]); 322 | printf("---------------receive end--------------\n"); 323 | */ 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | -------------------------------------------------------------------------------- /results_conv.v: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | * Author: Mark A. Indovina 5 | * Rochester, NY, USA 6 | * 7 | */ 8 | 9 | 10 | module results_conv ( 11 | clk, 12 | reset, 13 | rcc_clk, 14 | address, 15 | din, 16 | digit_clk, 17 | dout, 18 | dout_flag, 19 | test_mode, 20 | scan_in0, 21 | scan_in1, 22 | scan_en, 23 | scan_out0, 24 | scan_out1 25 | ) ; 26 | 27 | /* 28 | * 29 | * Results Character Conversion (RCC) 30 | * processes a computed frequency spectrum to 31 | * determine if a valid DTMF digit can be found 32 | * 33 | */ 34 | 35 | input 36 | clk, // system clock 37 | reset, // system reset 38 | rcc_clk ; // data input write strobe 39 | 40 | input [3:0] 41 | address ; // holding register address bus 42 | 43 | input [15:0] 44 | din ; // data input bus 45 | 46 | output 47 | digit_clk ; // data output write strobe 48 | 49 | output [7:0] 50 | dout ; // data output bus 51 | 52 | output 53 | dout_flag ; // data output change flag 54 | 55 | input 56 | test_mode, // test mode control 57 | scan_in0, // test scan mode data input, chain 1 58 | scan_in1, // test scan mode data input, chain 2 59 | scan_en; // test scan mode enable 60 | 61 | output 62 | scan_out0, // test scan mode data output, chain 1 63 | scan_out1; // test scan mode data output, chain 2 64 | 65 | reg 66 | digit_clk, 67 | dout_flag, 68 | go, 69 | gt, 70 | ok, 71 | clear_flag, 72 | seen_quiet, 73 | start_gt, 74 | gt_done, 75 | clear_gt, 76 | start_ct, 77 | ct_done, 78 | clear_ct; 79 | 80 | reg [2:0] 81 | low, 82 | high ; 83 | 84 | reg [4:0] 85 | state, 86 | save_state; 87 | 88 | reg [2:0] 89 | gt_state, 90 | ct_state; 91 | 92 | reg [7:0] 93 | dout, 94 | out_p1, // two stage pipeline for digit/ quiet framing; I should 95 | out_p2; // have used dout as part of the pipeline to save area... 96 | 97 | reg [15:0] 98 | r697, 99 | r770, 100 | r852, 101 | r941, 102 | r1209, 103 | r1336, 104 | r1477, 105 | r1633, 106 | low_mag, 107 | high_mag, 108 | opa, 109 | opb, 110 | opc, 111 | opd ; 112 | 113 | `include "include/results_conv.h" 114 | 115 | wire flag_reset = (reset | clear_flag) & !test_mode ; 116 | 117 | always @(negedge rcc_clk or posedge flag_reset) 118 | if (flag_reset) 119 | go <= 0 ; 120 | else 121 | go <= address[3] ; 122 | 123 | always @(negedge rcc_clk) 124 | case (address[3:0]) 125 | `R_697 : r697 <= din ; 126 | `R_770 : r770 <= din ; 127 | `R_852 : r852 <= din ; 128 | `R_941 : r941 <= din ; 129 | `R_1209 : r1209 <= din ; 130 | `R_1336 : r1336 <= din ; 131 | `R_1477 : r1477 <= din ; 132 | `R_1633 : r1633 <= din ; 133 | endcase 134 | 135 | always @(posedge reset or posedge clk) 136 | begin : rcc_machine 137 | if (reset) 138 | begin 139 | digit_clk <= 0 ; 140 | dout_flag <= 1 ; 141 | clear_flag <= 0 ; 142 | seen_quiet <= 1 ; 143 | out_p1 <= 0 ; 144 | out_p2 <= 8'hff ; 145 | low <= 0 ; 146 | high <= 0 ; 147 | low_mag <= 0 ; 148 | high_mag <= 0 ; 149 | opa <= 0 ; 150 | opb <= 0 ; 151 | opc <= 0 ; 152 | opd <= 0 ; 153 | start_gt <= 0 ; 154 | clear_gt <= 0 ; 155 | start_ct <= 0 ; 156 | clear_ct <= 0 ; 157 | dout <= 8'hff ; 158 | state <= `IDLE ; 159 | save_state <= `IDLE ; 160 | end 161 | else 162 | begin 163 | case (state) 164 | `IDLE : begin 165 | if (go) 166 | begin 167 | low <= 3'b100 ; 168 | high <= 3'b100 ; 169 | clear_flag <= 1 ; 170 | out_p2 <= out_p1 ; // digit pipeline 171 | //gt_comp( r697, r770, r852, r941 ) ; 172 | opa <= r697 ; 173 | opb <= r770 ; 174 | opc <= r852 ; 175 | opd <= r941 ; 176 | start_gt <= 1 ; 177 | save_state <= `F1 ; 178 | state <= `GT_WAIT ; 179 | end 180 | else 181 | begin 182 | state <= `IDLE ; 183 | end 184 | end 185 | `F1 : begin 186 | clear_flag <= 0 ; 187 | if (gt) 188 | begin 189 | low <= {1'b0, `V_697} ; 190 | low_mag <= r697 ; 191 | end 192 | //gt_comp( r770, r697, r852, r941 ) ; 193 | opa <= r770 ; 194 | opb <= r697 ; 195 | opc <= r852 ; 196 | opd <= r941 ; 197 | start_gt <= 1 ; 198 | save_state <= `F2 ; 199 | state <= `GT_WAIT ; 200 | end 201 | `F2 : begin 202 | if (gt) 203 | begin 204 | low <= {1'b0, `V_770} ; 205 | low_mag <= r770 ; 206 | end 207 | //gt_comp( r852, r697, r770, r941 ) ; 208 | opa <= r852 ; 209 | opb <= r697 ; 210 | opc <= r770 ; 211 | opd <= r941 ; 212 | start_gt <= 1 ; 213 | save_state <= `F3 ; 214 | state <= `GT_WAIT ; 215 | end 216 | `F3 : begin 217 | if (gt) 218 | begin 219 | low <= {1'b0, `V_852} ; 220 | low_mag <= r852 ; 221 | end 222 | //gt_comp( r941, r697, r770, r852 ) ; 223 | opa <= r941 ; 224 | opb <= r697 ; 225 | opc <= r770 ; 226 | opd <= r852 ; 227 | start_gt <= 1 ; 228 | save_state <= `F4 ; 229 | state <= `GT_WAIT ; 230 | end 231 | `F4 : begin 232 | if (gt) 233 | begin 234 | low <= {1'b0, `V_941} ; 235 | low_mag <= r941 ; 236 | end 237 | //gt_comp( r1209, r1336, r1477, r1633 ) ; 238 | opa <= r1209 ; 239 | opb <= r1336 ; 240 | opc <= r1477 ; 241 | opd <= r1633 ; 242 | start_gt <= 1 ; 243 | save_state <= `F5 ; 244 | state <= `GT_WAIT ; 245 | end 246 | `F5 : begin 247 | if (gt) 248 | begin 249 | high <= {1'b0, `V_1209} ; 250 | high_mag <= r1209 ; 251 | end 252 | //gt_comp( r1336, r1209, r1477, r1633 ) ; 253 | opa <= r1336 ; 254 | opb <= r1209 ; 255 | opc <= r1477 ; 256 | opd <= r1633 ; 257 | start_gt <= 1 ; 258 | save_state <= `F6 ; 259 | state <= `GT_WAIT ; 260 | end 261 | `F6 : begin 262 | if (gt) 263 | begin 264 | high <= {1'b0, `V_1336} ; 265 | high_mag <= r1336 ; 266 | end 267 | //gt_comp( r1477, r1209, r1336, r1633 ) ; 268 | opa <= r1477 ; 269 | opb <= r1209 ; 270 | opc <= r1336 ; 271 | opd <= r1633 ; 272 | start_gt <= 1 ; 273 | save_state <= `F7 ; 274 | state <= `GT_WAIT ; 275 | end 276 | `F7 : begin 277 | if (gt) 278 | begin 279 | high <= {1'b0, `V_1477} ; 280 | high_mag<= r1477 ; 281 | end 282 | //gt_comp( r1633, r1209, r1336, r1477 ) ; 283 | opa <= r1633 ; 284 | opb <= r1209 ; 285 | opc <= r1336 ; 286 | opd <= r1477 ; 287 | start_gt <= 1 ; 288 | save_state <= `F8 ; 289 | state <= `GT_WAIT ; 290 | end 291 | `F8 : begin 292 | if (gt) 293 | begin 294 | high <= {1'b0, `V_1633} ; 295 | high_mag <= r1633 ; 296 | end 297 | state <= `CHECK ; 298 | end 299 | // did we find both frequencies? 300 | `CHECK : begin 301 | if (!low[2] && !high[2]) 302 | begin 303 | //check_twist( low_mag, high_mag ) ; 304 | opa <= low_mag ; 305 | opb <= high_mag ; 306 | start_ct <= 1 ; 307 | save_state <= `OK ; 308 | state <= `CT_WAIT ; 309 | end 310 | else 311 | begin 312 | out_p1 <= `NO_DIGIT ; 313 | state <= `CHARACTER ; 314 | end 315 | end 316 | 317 | `OK : begin 318 | if (ok) 319 | begin 320 | case ({low[1:0], high[1:0]}) 321 | key_1[3:0] : out_p1 <= val_key_1 ; 322 | key_2[3:0] : out_p1 <= val_key_2 ; 323 | key_3[3:0] : out_p1 <= val_key_3 ; 324 | key_a[3:0] : out_p1 <= val_key_a ; 325 | key_4[3:0] : out_p1 <= val_key_4 ; 326 | key_5[3:0] : out_p1 <= val_key_5 ; 327 | key_6[3:0] : out_p1 <= val_key_6 ; 328 | key_b[3:0] : out_p1 <= val_key_b ; 329 | key_7[3:0] : out_p1 <= val_key_7 ; 330 | key_8[3:0] : out_p1 <= val_key_8 ; 331 | key_9[3:0] : out_p1 <= val_key_9 ; 332 | key_c[3:0] : out_p1 <= val_key_c ; 333 | key_star[3:0] : out_p1 <= val_key_star ; 334 | key_0[3:0] : out_p1 <= val_key_0 ; 335 | key_pound[3:0] : out_p1 <= val_key_pound ; 336 | key_d[3:0] : out_p1 <= val_key_d ; 337 | default : out_p1 <= `NO_DIGIT ; 338 | endcase 339 | state <= `CHARACTER ; 340 | end 341 | else 342 | begin 343 | out_p1 <= `NO_DIGIT ; 344 | state <= `CHARACTER ; 345 | end 346 | end 347 | // should we output a new digit? 348 | // need to see two frames worth for timing... 349 | `CHARACTER : begin 350 | if (out_p1 == out_p2) 351 | begin 352 | // quiet tone? 353 | if (out_p2 == `NO_DIGIT) 354 | begin 355 | seen_quiet <= 1 ; 356 | state <= `IDLE ; 357 | end 358 | else 359 | begin 360 | if (seen_quiet) 361 | begin 362 | seen_quiet <= 0 ; 363 | state <= `P1 ; 364 | end 365 | else 366 | state <= `IDLE ; 367 | end 368 | end 369 | else 370 | state <= `IDLE ; 371 | end 372 | // toggle msb for each new char... 373 | `P1 : begin 374 | dout <= { 1'b0, out_p2[6:0] } ; 375 | dout_flag <= ~dout_flag ; 376 | state <= `P2 ; 377 | end 378 | `P2 : begin 379 | digit_clk <= 1 ; 380 | state <= `P3 ; 381 | end 382 | `P3 : begin 383 | digit_clk <= 0 ; 384 | state <= `IDLE ; 385 | end 386 | // wait for greater_than to finish 387 | `GT_WAIT : begin 388 | if (gt_done) 389 | begin 390 | start_gt <= 0 ; 391 | clear_gt <= 1 ; 392 | state <= `GT_FINISH ; 393 | end 394 | else 395 | state <= `GT_WAIT ; 396 | end 397 | `GT_FINISH : begin 398 | clear_gt <= 0 ; 399 | state <= save_state ; 400 | end 401 | // wait for check_twist to finish 402 | `CT_WAIT : begin 403 | if (ct_done) 404 | begin 405 | start_ct <= 0 ; 406 | clear_ct <= 1 ; 407 | state <= `CT_FINISH ; 408 | end 409 | else 410 | state <= `CT_WAIT ; 411 | end 412 | `CT_FINISH : begin 413 | clear_ct <= 0 ; 414 | state <= save_state ; 415 | end 416 | default : state <= `IDLE ; 417 | endcase 418 | end 419 | end // rcc_machine 420 | 421 | // 422 | // 16 bit "greater-than" comparision 423 | // we'll build our own pipelined comparitor here 424 | // (we want to force resource sharring...) 425 | // 426 | 427 | reg [16:0] 428 | cmpb, 429 | cmpc, 430 | cmpd ; 431 | 432 | always @(posedge reset or posedge clk) 433 | begin : gt_comp 434 | if (reset) 435 | begin 436 | cmpb <= 0 ; 437 | cmpc <= 0 ; 438 | cmpd <= 0 ; 439 | gt <= 0 ; 440 | gt_done <= 0 ; 441 | gt_state <= `GT_IDLE ; 442 | end 443 | else 444 | begin 445 | case (gt_state) 446 | `GT_IDLE : begin 447 | if (start_gt) 448 | gt_state <= `GEN_B ; 449 | else 450 | gt_state <= `GT_IDLE ; 451 | end 452 | `GEN_B : begin 453 | cmpb <= opb - opa ; 454 | gt_state <= `GEN_C ; 455 | end 456 | `GEN_C : begin 457 | cmpc <= opc - opa ; 458 | gt_state <= `GEN_D ; 459 | end 460 | `GEN_D : begin 461 | cmpd <= opd - opa ; 462 | gt_state <= `GT ; 463 | end 464 | `GT : begin 465 | gt <= cmpb[16] & cmpc[16] & cmpd[16] ; 466 | gt_state <= `GT_DONE ; 467 | end 468 | `GT_DONE : begin 469 | gt_done <= 1 ; 470 | gt_state <= `GT_CLEAR ; 471 | end 472 | `GT_CLEAR : begin 473 | if (clear_gt) 474 | begin 475 | gt_done <= 0 ; 476 | gt_state <= `GT_IDLE ; 477 | end 478 | else 479 | gt_state <= `GT_CLEAR ; 480 | end 481 | default : gt_state <= `GT_IDLE ; 482 | endcase 483 | end 484 | end 485 | 486 | // 487 | // check the twist between the frequencies, 488 | // constrain to +/- 12dB for the now... 489 | // 490 | 491 | reg [16:0] 492 | cmpf, 493 | cmpr ; 494 | 495 | always @(posedge reset or posedge clk) 496 | begin : check_twist 497 | if (reset) 498 | begin 499 | cmpf <= 0 ; 500 | cmpr <= 0 ; 501 | ok <= 0 ; 502 | ct_done <= 0 ; 503 | ct_state <= `CT_IDLE ; 504 | end 505 | else 506 | begin 507 | case (ct_state) 508 | `CT_IDLE : begin 509 | if (start_ct) 510 | ct_state <= `GEN_F ; 511 | else 512 | ct_state <= `GT_IDLE ; 513 | end 514 | `GEN_F : begin 515 | cmpf <= opa - opb ; 516 | ct_state <= `GEN_R ; 517 | end 518 | `GEN_R : begin 519 | if (cmpf[16]) // high freq is larger 520 | begin 521 | cmpf <= opa - {2'b0, opb[15:2]} ; 522 | cmpr <= opb - opa ; 523 | ct_state <= `CT ; 524 | end 525 | else // low freq is larger 526 | begin 527 | cmpf <= opb - {2'b0, opa[15:2]} ; 528 | cmpr <= opa - opb ; 529 | ct_state <= `CT ; 530 | end 531 | end 532 | `CT : begin 533 | ok <= (~cmpf[16]) && (~cmpr[16]) ; 534 | ct_state <= `CT_DONE ; 535 | end 536 | `CT_DONE : begin 537 | ct_done <= 1 ; 538 | ct_state <= `CT_CLEAR ; 539 | end 540 | `CT_CLEAR : begin 541 | if (clear_ct) 542 | begin 543 | ct_done <= 0 ; 544 | ct_state <= `CT_IDLE ; 545 | end 546 | else 547 | ct_state <= `CT_CLEAR ; 548 | end 549 | default : ct_state <= `CT_IDLE ; 550 | endcase 551 | end 552 | end 553 | 554 | endmodule // results_conv 555 | -------------------------------------------------------------------------------- /results_conv_test.sv: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | * Author: Mark A. Indovina 5 | * Rochester, NY, USA 6 | * 7 | */ 8 | 9 | 10 | `timescale 1ns / 1ns 11 | 12 | module test; 13 | 14 | wire digit_clk; 15 | 16 | reg clk, rcc_clk, reset, test_mode; 17 | 18 | wire dout_flag; 19 | wire [7:0] dout; 20 | wire [7:0] dout_char = dout & 8'h7f ; 21 | 22 | reg [3:0] g_address, address, digcnt, qcnt; 23 | reg [15:0] g_din, din; 24 | reg scan_in0, scan_in1, scan_en; 25 | 26 | results_conv top ( 27 | .clk(clk), 28 | .reset(reset), 29 | .test_mode(test_mode), 30 | .rcc_clk(rcc_clk), 31 | .address(address), 32 | .din(din), 33 | .digit_clk(digit_clk), 34 | .dout(dout), 35 | `ifdef NETLIST 36 | .dout_flag(dout_flag), 37 | .scan_in0(scan_in0), 38 | .scan_in1(scan_in1), 39 | .scan_en(scan_en) 40 | `else 41 | .dout_flag(dout_flag) 42 | `endif 43 | ) ; 44 | 45 | 46 | initial 47 | begin 48 | $timeformat(-9,2,"ns", 16); 49 | `ifdef SDFSCAN 50 | $sdf_annotate("sdf/results_conv_tsmc18_scan.sdf", test.top); 51 | `endif 52 | test_mode = 0; 53 | scan_in0 = 0; 54 | scan_in1 = 0; 55 | scan_en = 0; 56 | 57 | address[3:0] = 4'b0000; 58 | g_address[3:0] = 4'b0000; 59 | 60 | clk = 1'b0; 61 | din[15:0] = 16'b0000000000000000; 62 | g_din[15:0] = 16'b0000000000000000; 63 | 64 | rcc_clk = 1'b0; 65 | test_mode = 1'b0; 66 | reset = 1'b0; 67 | @(negedge clk) ; 68 | @(negedge clk) ; 69 | reset = 1'b1; 70 | @(negedge clk) ; 71 | @(negedge clk) ; 72 | reset = 1'b0; 73 | 74 | repeat (1024) 75 | begin 76 | digcnt = $urandom ; 77 | repeat (digcnt) 78 | begin 79 | repeat (4) 80 | @(posedge clk); 81 | g_address = 0 ; 82 | g_din = $urandom ; 83 | repeat (8) 84 | begin 85 | write_it ; 86 | g_address = g_address + 1 ; 87 | g_din = $urandom ; 88 | end 89 | write_it ; 90 | g_address = 0 ; 91 | repeat (160) 92 | @(posedge clk) ; 93 | end 94 | qcnt = $urandom ; 95 | repeat (qcnt) 96 | begin 97 | repeat (4) 98 | @(posedge clk); 99 | g_address = 0 ; 100 | g_din = 0 ; 101 | repeat (8) 102 | begin 103 | write_it ; 104 | g_address = g_address + 1 ; 105 | end 106 | write_it ; 107 | g_address = 0 ; 108 | repeat (160) 109 | @(posedge clk) ; 110 | end 111 | end 112 | $stop ; 113 | end 114 | 115 | always #25 clk = ~clk ; 116 | 117 | 118 | always @(posedge digit_clk) 119 | begin 120 | #0 ; 121 | $display( "Time: %t", $time, ", Digit Clock: %b", digit_clk, ", Digit: \"%c\"", dout, ", Dout Flag: %b", dout_flag ); 122 | end 123 | 124 | task write_it ; 125 | begin 126 | @(posedge clk) ; 127 | address <= g_address ; 128 | din <= g_din ; 129 | @(posedge clk) 130 | rcc_clk <= 1 ; 131 | @(posedge clk) 132 | rcc_clk <= 0 ; 133 | @(posedge clk) ; 134 | din <= 'bz ; 135 | end 136 | endtask 137 | 138 | endmodule 139 | -------------------------------------------------------------------------------- /results_conv_test.v: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | * Author: Mark A. Indovina 5 | * Rochester, NY, USA 6 | * 7 | */ 8 | 9 | 10 | `timescale 1ns / 1ns 11 | 12 | module test; 13 | 14 | wire digit_clk; 15 | 16 | reg clk, rcc_clk, reset, test_mode; 17 | 18 | wire dout_flag; 19 | wire [7:0] dout; 20 | wire [7:0] dout_char = dout & 8'h7f ; 21 | 22 | reg [3:0] g_address, address, digcnt, qcnt; 23 | reg [15:0] g_din, din; 24 | reg scan_in0, scan_in1, scan_en; 25 | 26 | results_conv top ( 27 | .clk(clk), 28 | .reset(reset), 29 | .test_mode(test_mode), 30 | .rcc_clk(rcc_clk), 31 | .address(address), 32 | .din(din), 33 | .digit_clk(digit_clk), 34 | .dout(dout), 35 | `ifdef NETLIST 36 | .dout_flag(dout_flag), 37 | .scan_in0(scan_in0), 38 | .scan_in1(scan_in1), 39 | .scan_en(scan_en) 40 | `else 41 | .dout_flag(dout_flag) 42 | `endif 43 | ) ; 44 | 45 | 46 | initial 47 | begin 48 | $timeformat(-9,2,"ns", 16); 49 | `ifdef SDFSCAN 50 | $sdf_annotate("sdf/results_conv_tsmc18_scan.sdf", test.top); 51 | `endif 52 | test_mode = 0; 53 | scan_in0 = 0; 54 | scan_in1 = 0; 55 | scan_en = 0; 56 | 57 | address[3:0] = 4'b0000; 58 | g_address[3:0] = 4'b0000; 59 | 60 | clk = 1'b0; 61 | din[15:0] = 16'b0000000000000000; 62 | g_din[15:0] = 16'b0000000000000000; 63 | 64 | rcc_clk = 1'b0; 65 | test_mode = 1'b0; 66 | reset = 1'b0; 67 | @(negedge clk) ; 68 | @(negedge clk) ; 69 | reset = 1'b1; 70 | @(negedge clk) ; 71 | @(negedge clk) ; 72 | reset = 1'b0; 73 | 74 | repeat (1024) 75 | begin 76 | digcnt = $random ; 77 | repeat (digcnt) 78 | begin 79 | repeat (4) 80 | @(posedge clk); 81 | g_address = 0 ; 82 | g_din = $random ; 83 | repeat (8) 84 | begin 85 | write_it ; 86 | g_address = g_address + 1 ; 87 | g_din = $random ; 88 | end 89 | write_it ; 90 | g_address = 0 ; 91 | repeat (160) 92 | @(posedge clk) ; 93 | end 94 | qcnt = $random ; 95 | repeat (qcnt) 96 | begin 97 | repeat (4) 98 | @(posedge clk); 99 | g_address = 0 ; 100 | g_din = 0 ; 101 | repeat (8) 102 | begin 103 | write_it ; 104 | g_address = g_address + 1 ; 105 | end 106 | write_it ; 107 | g_address = 0 ; 108 | repeat (160) 109 | @(posedge clk) ; 110 | end 111 | end 112 | $stop ; 113 | end 114 | 115 | always #25 clk = ~clk ; 116 | 117 | 118 | always @(posedge digit_clk) 119 | begin 120 | #0 ; 121 | $display( "Time: %t", $time, ", Digit Clock: %b", digit_clk, ", Digit: \"%c\"", dout, ", Dout Flag: %b", dout_flag ); 122 | end 123 | 124 | task write_it ; 125 | begin 126 | @(posedge clk) ; 127 | address <= g_address ; 128 | din <= g_din ; 129 | @(posedge clk) 130 | rcc_clk <= 1 ; 131 | @(posedge clk) 132 | rcc_clk <= 0 ; 133 | @(posedge clk) ; 134 | din <= 'bz ; 135 | end 136 | endtask 137 | 138 | endmodule 139 | -------------------------------------------------------------------------------- /timescale.v: -------------------------------------------------------------------------------- 1 | 2 | `timescale 1ns / 1ns 3 | -------------------------------------------------------------------------------- /wall_time.c: -------------------------------------------------------------------------------- 1 | // wall time logic for testbench // 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int sim_start_time() 8 | { 9 | time_t start_time; 10 | 11 | start_time = time(NULL); 12 | 13 | return start_time; 14 | } 15 | 16 | 17 | void start_day_date() 18 | { 19 | time_t rawtime; 20 | struct tm *info; 21 | 22 | time( &rawtime); 23 | 24 | info = localtime( &rawtime); 25 | printf("Current local time and date: %s\n", asctime(info)); 26 | } 27 | 28 | 29 | void digit_gen_time(int n) 30 | { 31 | int hour, day, min, sec; 32 | 33 | day = n / (24*3600); 34 | n = n % (24*3600); 35 | hour = n / 3600; 36 | n = n % 3600; 37 | min = n / 60; 38 | n = n % 60; 39 | sec = n; 40 | 41 | printf("%0d: %0d: %0d: %0d \n", day, hour, min, sec); 42 | 43 | } 44 | --------------------------------------------------------------------------------