├── tb ├── uart_tb_diagram.png ├── cpu_intr_interface.sv ├── tb.sv ├── dut_wrapper.sv ├── uart_ip_tb.sv └── uart_fw_seq_lib.sv ├── test ├── uart_ip_test_lib.sv ├── uart_base_test.sv └── uart_rdwr_test.sv ├── src ├── uart_host_pkg.sv ├── uart_interface.sv ├── uart_host_sequencer.sv ├── uart_host_agent.sv ├── uart_host_config.sv ├── uart_host_sequence.sv ├── uart_host_monitor.sv ├── uart_host_driver.sv └── uart_host_scoreboard.sv └── README.md /tb/uart_tb_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiChungWu/UVM_UART_Example/HEAD/tb/uart_tb_diagram.png -------------------------------------------------------------------------------- /test/uart_ip_test_lib.sv: -------------------------------------------------------------------------------- 1 | `include "uart_ip_tb.sv" 2 | `include "uart_base_test.sv" 3 | `include "uart_rdwr_test.sv" 4 | -------------------------------------------------------------------------------- /src/uart_host_pkg.sv: -------------------------------------------------------------------------------- 1 | `ifndef UART_HOST_PKG_SV 2 | `define UART_HOST_PKG_SV 3 | 4 | package uart_host_pkg; 5 | import uvm_pkg::*; 6 | 7 | `include "uart_host_config.sv" 8 | `include "uart_host_sequencer.sv" 9 | `include "uart_host_driver.sv" 10 | `include "uart_host_monitor.sv" 11 | `include "uart_host_agent.sv" 12 | `include "uart_host_sequence.sv" 13 | `include "uart_host_scoreboard.sv" 14 | endpackage 15 | `endif 16 | -------------------------------------------------------------------------------- /tb/cpu_intr_interface.sv: -------------------------------------------------------------------------------- 1 | `ifndef CPU_INTR_INTERFACE_SV 2 | `define CPU_INTR_INTERFACE_SV 3 | 4 | interface cpu_intr_interface(input clk, input sclk); 5 | logic interrupt; 6 | 7 | clocking mon_cb @(posedge clk); 8 | default input #1step output #0; 9 | input interrupt; 10 | endclocking 11 | 12 | task idle_sclk(int count); 13 | repeat(count) @(posedge sclk); 14 | endtask 15 | 16 | task idle_ahb(int count); 17 | repeat(count) @mon_cb; 18 | endtask 19 | endinterface 20 | 21 | `endif 22 | -------------------------------------------------------------------------------- /tb/tb.sv: -------------------------------------------------------------------------------- 1 | `ifndef TP__SV 2 | `define TP__SV 3 | 4 | `timescale 1ns/10ps 5 | 6 | module tb; 7 | import uvm_pkg::*; 8 | import uart_host_pkg::*; 9 | 10 | dut_wrapper top(); 11 | 12 | `include "uart_ip_test_lib.sv" 13 | 14 | initial begin 15 | uvm_config_db#(virtual uart_interface)::set(null, "*", "uart_interface", top.uart_if); 16 | uvm_config_db#(virtual cpu_intr_interface)::set(null, "*", "cpu_intr_interface", top.cpu_intr_if); 17 | run_test(); 18 | end 19 | endmodule : tb 20 | 21 | `endif 22 | -------------------------------------------------------------------------------- /src/uart_interface.sv: -------------------------------------------------------------------------------- 1 | `ifndef UART_INTERFACE_SV 2 | `define UART_INTERFACE_SV 3 | 4 | interface uart_interface(input clk, input rst_); 5 | logic sin_data; 6 | logic sout_data; 7 | logic rts_n; 8 | logic cts_n; 9 | logic dtr_n; 10 | logic dsr_n; 11 | 12 | clocking mst_cb @(posedge clk); 13 | default input #1step output #1; 14 | input sin_data, cts_n, dsr_n; 15 | output sout_data, rts_n, dtr_n; 16 | endclocking 17 | 18 | clocking mon_cb @(posedge clk); 19 | default input #1step output #0; 20 | input sin_data, cts_n, dsr_n; 21 | input sout_data, rts_n, dtr_n; 22 | endclocking 23 | endinterface 24 | 25 | `endif 26 | -------------------------------------------------------------------------------- /src/uart_host_sequencer.sv: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // File Name : uart_host_sequencer.sv 3 | // Date : 8/14/2020 4 | // Author(s) : WeiChung Wu (exelion04 at gmail.com) 5 | // Description : 6 | //---------------------------------------------------------------------------- 7 | 8 | `ifndef UART_HOST_SEQUENCER_SV 9 | `define UART_HOST_SEQUENCER_SV 10 | 11 | class uart_host_sequencer extends uvm_sequencer; 12 | `uvm_component_utils(uart_host_sequencer) 13 | function new(string name = "uart_host_sequencer", uvm_component parent = null); 14 | super.new(name, parent); 15 | endfunction : new 16 | endclass : uart_host_sequencer 17 | 18 | `endif 19 | -------------------------------------------------------------------------------- /test/uart_base_test.sv: -------------------------------------------------------------------------------- 1 | `ifndef UART_BASE_TEST__SV 2 | `define UART_BASE_TEST__SV 3 | 4 | class uart_base_test extends uvm_test; 5 | 6 | `uvm_component_utils(uart_base_test) 7 | 8 | uart_ip_tb uarttb; 9 | 10 | function new (string name = "uart_base_test", uvm_component parent = null); 11 | super.new(name, parent); 12 | endfunction 13 | 14 | virtual function void build_phase(uvm_phase phase); 15 | super.build_phase(phase); 16 | uarttb = uart_ip_tb::type_id::create("uart_tb", this); 17 | endfunction : build_phase 18 | 19 | virtual task main_phase(uvm_phase phase); 20 | phase.raise_objection(this); 21 | `uvm_info(get_type_name(),"[UART Test] Main Phase", UVM_LOW) 22 | phase.drop_objection(this); 23 | endtask : main_phase 24 | 25 | endclass : uart_base_test 26 | `endif 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | UVM UART Host Agent Bench Example 2 | ============ 3 | Author: WeiChung Wu 4 | 5 | This is an UVM test bench example to demonstrate that an UART host agent performs TX/RX data transfer between UART device design. 6 | It is an example of how to build a basic UVM environment bench. So if you are a beginner in the field of constraint random verification, it might help you well to go through the UVM methodology. 7 | 8 | ## Features in this example 9 | 1. It demonstrates how to implement pipeline mechanism in the uvm_driver and also perform UART TX/RX transfer simultaneously. 10 | 2. It demonstrates a use case of uvm_event_callback exmaple that providing a loose coupling mechanism to interact between uvm_sequence and uvm_component. 11 | 3. It demonstrates how to perform better practice of read()/write() tasks in uvm_sequence. 12 | 13 | ## Note 14 | This is an example for UVM learning only. 15 | If you are trying to run this example, there will be some missing files and runtime errors which are left intentionally. 16 | Users should be able to implement the rest of part by themselves. 17 | 18 | ## Test Bench Diagram 19 | ![uart_tb_diagram](https://github.com/WeiChungWu/UVM_UART_Example/raw/master/tb/uart_tb_diagram.png) 20 | -------------------------------------------------------------------------------- /src/uart_host_agent.sv: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // File Name : uart_host_agent.sv 3 | // Date : 8/14/2020 4 | // Author(s) : WeiChung Wu (exelion04 at gmail.com) 5 | // Description : 6 | //---------------------------------------------------------------------------- 7 | 8 | `ifndef UART_HOST_AGENT_SV 9 | `define UART_HOST_AGENT_SV 10 | 11 | class uart_host_agent extends uvm_agent; 12 | uart_host_sequencer sequencer; 13 | uart_host_driver driver; 14 | uart_host_monitor monitor; 15 | uart_host_config cfg; 16 | 17 | `uvm_component_utils_begin(uart_host_agent) 18 | `uvm_field_object(cfg, UVM_DEFAULT|UVM_REFERENCE) 19 | `uvm_component_utils_end 20 | 21 | function new(string name = "uart_host_agent", uvm_component parent = null); 22 | super.new(name, parent); 23 | endfunction : new 24 | 25 | virtual function void build_phase(uvm_phase phase); 26 | super.build_phase(phase); 27 | if(is_active == UVM_ACTIVE) begin 28 | sequencer = uart_host_sequencer::type_id::create("sequencer", this); 29 | driver = uart_host_driver::type_id::create("driver", this); 30 | cfg.set_sequencer(sequencer); 31 | end 32 | monitor = uart_host_monitor::type_id::create("monitor", this); 33 | endfunction : build_phase 34 | 35 | virtual function void connect_phase(uvm_phase phase); 36 | super.connect_phase(phase); 37 | if(is_active == UVM_ACTIVE) begin 38 | driver.seq_item_port.connect(sequencer.seq_item_export); 39 | driver.rsp_port.connect(sequencer.rsp_export); 40 | end 41 | endfunction : connect_phase 42 | endclass : uart_host_agent 43 | `endif 44 | -------------------------------------------------------------------------------- /tb/dut_wrapper.sv: -------------------------------------------------------------------------------- 1 | module dut_wrapper(); 2 | 3 | reg clk; 4 | reg rstn; 5 | 6 | reg siu_clkg; 7 | 8 | wire uart_intr; 9 | wire [13:0] uart_debug_mon; 10 | 11 | // ------------------------------- 12 | // Clocks and Resets 13 | // ------------------------------- 14 | initial begin 15 | // init 16 | clk = 0; 17 | rstn = 0; 18 | siu_clkg = 0; 19 | #100ns; 20 | rstn = 1; 21 | end 22 | 23 | always #(clk_period/2) clk <= ~clk; 24 | always #(sclk_period/2) siu_clkg <= ~siu_clkg; 25 | 26 | uart_interface uart_if(.clk(siu_clkg), .rst_(rstn)); 27 | cpu_intr_interface cpu_intr_if(.clk(clk), .sclk(siu_clkg)); 28 | 29 | assign cpu_intr_if.interrupt = uart_intr; 30 | 31 | // ---------------------------------------------------------------- 32 | // UART DUT 33 | // ---------------------------------------------------------------- 34 | 35 | uart_top uart_top ( 36 | .HCLK (), 37 | .HRESETn (), 38 | .HTRANS (), 39 | .HADDR (), 40 | .HWRITE (), 41 | .HSIZE (), 42 | .HBURST (), 43 | .HWDATA (), 44 | .HSEL (), 45 | .AHB_HREADY (), 46 | .HREADY (), 47 | .HRESP (), 48 | .HRDATA (), 49 | .apbclk (), 50 | .clk (), 51 | .rst_ (), 52 | .sclk (siu_clkg), 53 | .siu_rst_ (rstn), 54 | .siu_cfg_rst_ (rstn), 55 | .inst_sin (uart_if.sout_data), 56 | .inst_cts_n (uart_if.rts_n), 57 | .inst_dsr_n (uart_if.dtr_n), 58 | .inst_dcd_n (1'b1), 59 | .inst_ri_n (1'b1), 60 | .intr_inst (uart_intr), 61 | .sout_inst (uart_if.sin_data), 62 | .dtr_n_inst (uart_if.dsr_n), 63 | .rts_n_inst (uart_if.cts_n) 64 | ); 65 | 66 | endmodule 67 | -------------------------------------------------------------------------------- /tb/uart_ip_tb.sv: -------------------------------------------------------------------------------- 1 | `ifndef UART_IP_TB_SV 2 | `define UART_IP_TB_SV 3 | 4 | `include "uart_fw_seq_lib.sv" 5 | 6 | class uart_ip_tb extends uvm_env; 7 | 8 | `uvm_component_utils(uart_ip_tb) 9 | 10 | uart_host_config uart_host_cfg; 11 | uart_host_agent uart_host; 12 | uart_host_scoreboard uart_sb; 13 | 14 | uvm_table_printer printer; 15 | 16 | function new (string name = "uart_ip_tb", uvm_component parent = null); 17 | super.new(name, parent); 18 | endfunction 19 | 20 | virtual function void build_phase(uvm_phase phase); 21 | super.build_phase(phase); 22 | //UART Host 23 | uart_host_cfg = uart_host_config::type_id::create("uart_host_cfg"); 24 | if(!uart_host_cfg.randomize()) 25 | `uvm_fatal(get_name(), "uart_host_cfg randomize failed!") 26 | if (!uvm_config_db#(virtual uart_interface)::get(this, "", "uart_interface", uart_host_cfg.uart_vif)) begin 27 | `uvm_fatal(get_name(), $sformatf("No virtual uart_interface specified")) 28 | end 29 | uvm_config_object::set(this, "uart_host*", "cfg", uart_host_cfg); 30 | uart_host = uart_host_agent::type_id::create("uart_host", this); 31 | uart_sb = uart_host_scoreboard::type_id::create("uart_sb", this); 32 | endfunction : build_phase 33 | 34 | virtual function void connect_phase(uvm_phase phase); 35 | super.connect_phase(phase); 36 | uart_host.monitor.tx_trans_ap.connect(uart_sb.exp_tx_in); 37 | uart_host.monitor.rx_trans_ap.connect(uart_sb.act_rx_in); 38 | endfunction 39 | 40 | virtual function void end_of_elaboration_phase(uvm_phase phase); 41 | super.end_of_elaboration_phase(phase); 42 | printer = new(); 43 | printer.knobs.depth = 3; 44 | 45 | begin 46 | uvm_report_server rs =uvm_report_server::get_server(); 47 | rs.set_max_quit_count(1); 48 | end 49 | 50 | uvm_report_info(get_type_name(), $psprintf("Printing the test topology :\n%s", this.sprint(printer)), UVM_LOW); 51 | 52 | `uvm_info(get_name(), "Print timescale:", UVM_MEDIUM) 53 | $printtimescale(tb.top); 54 | endfunction : end_of_elaboration_phase 55 | 56 | virtual function void start_of_simulation_phase(uvm_phase phase); 57 | super.start_of_simulation_phase(phase); 58 | endfunction : start_of_simulation_phase 59 | 60 | virtual task run_phase(uvm_phase phase); 61 | endtask : run_phase 62 | 63 | virtual task reset_phase(uvm_phase phase); 64 | phase.raise_objection(this); 65 | @(posedge tb.top.rstn); 66 | `uvm_info(get_type_name(), "Reset is done", UVM_MEDIUM) 67 | phase.drop_objection(this); 68 | endtask : reset_phase 69 | 70 | endclass : uart_ip_tb 71 | `endif 72 | -------------------------------------------------------------------------------- /src/uart_host_config.sv: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // File Name : uart_host_config.sv 3 | // Date : 8/14/2020 4 | // Author(s) : WeiChung Wu (exelion04 at gmail.com) 5 | // Description : 6 | //---------------------------------------------------------------------------- 7 | 8 | `ifndef UART_HOST_CONFIG_SV 9 | `define UART_HOST_CONFIG_SV 10 | 11 | class uart_host_config extends uvm_object; 12 | int id; 13 | uvm_sequencer_base m_sequencer; //sequencer in current agent 14 | virtual uart_interface uart_vif; 15 | int baud_cnt = 16; 16 | int half_cnt = 8; 17 | rand int data_len; //refer LCR[1:0] 18 | rand int stop_len; //refer LCR[2] 19 | rand bit parity_en; //refer LCR[3] 20 | rand bit even_parity; //refer LCR[4] 21 | rand bit auto_flow_ctrl; //refer MCR[5] 22 | rand int rcv_threshold; //refer FCR[7:6] 23 | 24 | `uvm_object_utils_begin(uart_host_config) 25 | `uvm_field_int(id, UVM_ALL_ON|UVM_NOPACK) 26 | `uvm_field_int(baud_cnt, UVM_ALL_ON|UVM_NOPACK) 27 | `uvm_field_int(data_len, UVM_ALL_ON|UVM_NOPACK) 28 | `uvm_field_int(stop_len, UVM_ALL_ON|UVM_NOPACK) 29 | `uvm_field_int(parity_en, UVM_ALL_ON|UVM_NOPACK) 30 | `uvm_field_int(even_parity, UVM_ALL_ON|UVM_NOPACK) 31 | `uvm_field_int(auto_flow_ctrl, UVM_ALL_ON|UVM_NOPACK) 32 | `uvm_object_utils_end 33 | 34 | function new(string name = "uart_host_config"); 35 | super.new(name); 36 | half_cnt = baud_cnt/2; 37 | endfunction : new 38 | 39 | constraint con_data_len { 40 | data_len inside {[5:8]}; 41 | soft data_len == 8; 42 | } 43 | constraint con_stop_len { 44 | stop_len inside {1,2}; 45 | soft stop_len == 1; 46 | } 47 | constraint con_parity_en { 48 | soft parity_en == 1; 49 | } 50 | constraint con_even_parity { 51 | soft even_parity == 0; 52 | } 53 | constraint con_auto_flow_ctrl { 54 | soft auto_flow_ctrl == 0; 55 | } 56 | constraint con_rcv_threshold { 57 | soft rcv_threshold == 256; 58 | } 59 | 60 | virtual function void set_sequencer(uvm_sequencer_base seqr); 61 | m_sequencer = seqr; 62 | endfunction : set_sequencer 63 | 64 | virtual function uvm_sequencer_base get_sequencer(); 65 | return m_sequencer; 66 | endfunction : get_sequencer 67 | 68 | virtual function string convert2string(); 69 | string qs[$]; 70 | qs.push_back($sformatf("UART_HOST_CONFIG (type: %0s)\n", get_type_name())); 71 | qs.push_back($sformatf(" data_len = %0d\n", data_len)); 72 | qs.push_back($sformatf(" stop_len = %0d\n", stop_len)); 73 | qs.push_back($sformatf(" parity_en = %0d\n", parity_en)); 74 | qs.push_back($sformatf(" even_parity = %0d\n", even_parity)); 75 | qs.push_back($sformatf(" auto_flow_ctrl = %0d\n", auto_flow_ctrl)); 76 | qs.push_back($sformatf(" rcv_threshold = %0d\n", rcv_threshold)); 77 | return `UVM_STRING_QUEUE_STREAMING_PACK(qs); 78 | endfunction 79 | endclass : uart_host_config 80 | `endif 81 | -------------------------------------------------------------------------------- /test/uart_rdwr_test.sv: -------------------------------------------------------------------------------- 1 | `ifndef UART_RDWR_TEST_SV 2 | `define UART_RDWR_TEST_SV 3 | 4 | class uart_rdwr_sequence extends uart_host_base_sequence; 5 | bit [7:0] tx_data[]; 6 | bit [7:0] rx_data[]; 7 | `uvm_object_utils(uart_rdwr_sequence) 8 | function new(string name = "uart_rdwr_sequence"); 9 | super.new(name); 10 | endfunction : new 11 | 12 | virtual task body(); 13 | bit [7:0] rdata; 14 | for(int i=0; i D] SOUT_DATA = %2h", rdata), UVM_MEDIUM) 120 | if(dir) rx_trans_ap.write(transform(rdata, dir)); 121 | else tx_trans_ap.write(transform(rdata, dir)); 122 | trans_ap.write(transform(rdata, dir)); 123 | end 124 | end 125 | endtask 126 | 127 | function uart_trans uart_host_monitor::transform(bit [7:0] data, uart_dir_e dir=RX); 128 | uart_trans pkt = uart_trans::type_id::create("uart_mon"); 129 | pkt.addr = 64'h0; 130 | pkt.data_width = DATA_WIDTH_8BIT; 131 | pkt.burst_length = 1; 132 | pkt.direction = dir ? UART_READ : UART_WRITE; 133 | pkt.byte_array = new[1]; 134 | pkt.byte_array[0] = data; 135 | pkt.data = pkt.unpack_bytestream(); 136 | return pkt; 137 | endfunction 138 | `endif 139 | -------------------------------------------------------------------------------- /src/uart_host_driver.sv: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // File Name : uart_host_driver.sv 3 | // Date : 8/14/2020 4 | // Author(s) : WeiChung Wu (exelion04 at gmail.com) 5 | // Description : 6 | //---------------------------------------------------------------------------- 7 | 8 | `ifndef UART_HOST_DRIVER_SV 9 | `define UART_HOST_DRIVER_SV 10 | 11 | class uart_host_driver extends uvm_driver; 12 | uart_host_config cfg; 13 | virtual uart_interface uart_vif; 14 | 15 | protected bit [7:0] received_data_fifo[$]; 16 | 17 | // TX, RX operation can be performed simultaneously 18 | // In TX or RX operation, one transfer is following previous transfer ended 19 | protected semaphore tx_lock, rx_lock; 20 | 21 | `uvm_component_utils_begin(uart_host_driver) 22 | `uvm_field_object(cfg, UVM_DEFAULT|UVM_REFERENCE) 23 | `uvm_component_utils_end 24 | 25 | function new(string name = "uart_host_driver", uvm_component parent = null); 26 | super.new(name, parent); 27 | endfunction : new 28 | 29 | virtual function void build_phase(uvm_phase phase); 30 | string val; 31 | uvm_cmdline_processor clp = uvm_cmdline_processor::get_inst(); 32 | 33 | super.build_phase(phase); 34 | uart_vif = cfg.uart_vif; 35 | tx_lock = new(1); 36 | rx_lock = new(1); 37 | 38 | if(!clp.get_arg_value("+UART_DEBUG", val)) begin 39 | set_report_severity_id_action_hier(UVM_INFO, get_type_name(), UVM_NO_ACTION); 40 | end 41 | endfunction : build_phase 42 | 43 | virtual task run_phase(uvm_phase phase); 44 | uart_vif.sout_data <= 1'b1; 45 | uart_vif.rts_n <= 1'b1; 46 | uart_vif.dtr_n <= 1'b1; 47 | fork 48 | main_loop(); 49 | receive(); 50 | auto_flow_ctrl(); 51 | join 52 | endtask : run_phase 53 | 54 | extern virtual task main_loop(); 55 | extern virtual task reset(); 56 | extern virtual task send(ref uart_trans tr); 57 | extern virtual function bit get_parity(int n, ref uart_trans tr); 58 | extern virtual task auto_flow_ctrl(); 59 | extern virtual task receive(); 60 | extern virtual task read(ref uart_trans tr); 61 | endclass 62 | 63 | task uart_host_driver::main_loop(); 64 | uvm_sequence_item item; 65 | uart_trans tr; 66 | 67 | forever begin 68 | seq_item_port.get(item); 69 | void'($cast(tr, item)); 70 | if(tr==null) `uvm_fatal(get_name(), "casting failed or item returned null") 71 | if(tr.direction==UART_WRITE) tx_lock.get(); 72 | else rx_lock.get(); 73 | 74 | fork 75 | begin 76 | automatic uart_trans req, rsp; 77 | req = tr; 78 | if(req.direction==UART_WRITE) send(req); 79 | else read(req); 80 | $cast(rsp, req.clone()); 81 | rsp.set_id_info(req); 82 | seq_item_port.put(rsp); 83 | if(req.direction==UART_WRITE) tx_lock.put(); 84 | else rx_lock.put(); 85 | end 86 | join_none 87 | end 88 | endtask 89 | 90 | task uart_host_driver::reset(); 91 | forever begin 92 | @(posedge uart_vif.rst_); 93 | received_data_fifo.delete(); 94 | uart_vif.sout_data <= 1'b1; 95 | uart_vif.rts_n <= 1'b1; 96 | uart_vif.dtr_n <= 1'b1; 97 | end 98 | endtask 99 | 100 | task uart_host_driver::send(ref uart_trans tr); 101 | `uvm_info(get_type_name(), $sformatf("In send() :\n%s", tr.convert2string()), UVM_MEDIUM) 102 | 103 | repeat (cfg.half_cnt) @(uart_vif.mst_cb); 104 | for(int n=0; n D] SOUT_DATA = %2h", tr.byte_array[n]), UVM_MEDIUM) 128 | end 129 | 130 | `uvm_info(get_type_name(), $sformatf("In send() : end"), UVM_MEDIUM) 131 | endtask 132 | 133 | function bit uart_host_driver::get_parity(int n, ref uart_trans tr); 134 | bit [7:0] data = tr.byte_array[n]; 135 | get_parity = ^{data, ~cfg.even_parity}; 136 | if(tr.strb_array[n]==0) begin //insert parity error, using strb_array to indicate it 137 | get_parity = ~get_parity; 138 | end 139 | endfunction 140 | 141 | task uart_host_driver::read(ref uart_trans tr); 142 | `uvm_info(get_type_name(), $sformatf("In read() :\n%s", tr.convert2string()), UVM_MEDIUM) 143 | for(int n=0; n=(cfg.rcv_threshold-1)) begin 158 | uart_vif.mst_cb.rts_n <= 1'b1; 159 | end 160 | end 161 | @(uart_vif.mst_cb); 162 | end 163 | endtask 164 | 165 | task uart_host_driver::receive(); 166 | uart_trans tr; 167 | bit start_bit_found; 168 | bit stop_bit_found; 169 | bit [7:0] rdata; 170 | 171 | forever begin 172 | //wait start bit 173 | do begin 174 | start_bit_found = 1; 175 | wait(uart_vif.sin_data==0); 176 | `uvm_info(get_type_name(), $sformatf("Start Bit begins..."), UVM_MEDIUM) 177 | repeat (cfg.baud_cnt) begin 178 | @(uart_vif.mst_cb); 179 | if(uart_vif.mst_cb.sin_data==1) begin 180 | start_bit_found = 0; 181 | `uvm_info(get_type_name(), $sformatf("Start Bit is aborted, mst_cb.sin_data=%1b", uart_vif.mst_cb.sin_data), UVM_MEDIUM) 182 | break; 183 | end 184 | end 185 | end while(!start_bit_found); 186 | `uvm_info(get_type_name(), $sformatf("Start Bit is detected"), UVM_MEDIUM) 187 | 188 | //receive data bit 189 | repeat (cfg.half_cnt) @(uart_vif.mst_cb); 190 | for (int i=0; i Expected : [%0s], Actual : [%0s]", msg, exp_pkt.convert2string(), act_pkt.convert2string())) 173 | end 174 | end 175 | else begin 176 | `uvm_error(get_type_name(), $sformatf("FAIL: UART Scoreboard %s is Empty => Actual : [%0s]", msg, act_pkt.convert2string())) 177 | end 178 | end 179 | endfunction : process_act_in 180 | 181 | virtual function void check_orphan(); 182 | if (m_tx_queue.size()) begin 183 | `uvm_error(get_type_name(), $sformatf("%0s HAS ORPHAN, number = %0d", get_name(), m_tx_queue.size())) 184 | end 185 | if (m_rx_queue.size()) begin 186 | `uvm_error(get_type_name(), $sformatf("%0s HAS ORPHAN, number = %0d", get_name(), m_rx_queue.size())) 187 | end 188 | endfunction 189 | 190 | virtual function uart_serial_data transform(uart_trans tr); 191 | uart_serial_data pkt = uart_serial_data::type_id::create("uart_sb"); 192 | pkt.data = tr.byte_array[0]; 193 | pkt.parity_err = 0; 194 | pkt.frame_err = 0; 195 | return pkt; 196 | endfunction 197 | 198 | virtual function void observe(uvm_event e, uvm_object data=null); 199 | uart_sb_cmd sb_cmd; 200 | void'($cast(sb_cmd, data)); 201 | if(sb_cmd.tx_data.size()>0) begin 202 | foreach(sb_cmd.tx_data[i]) write_act_tx_in(sb_cmd.tx_data[i]); 203 | end 204 | if(sb_cmd.rx_data.size()>0) begin 205 | foreach(sb_cmd.rx_data[i]) write_exp_rx_in(sb_cmd.rx_data[i]); 206 | end 207 | sb_cmd.tx_data.delete(); 208 | sb_cmd.rx_data.delete(); 209 | endfunction: observe 210 | 211 | virtual function void event_cb_configure(string ev_name); 212 | uart_sb_subscriber#(uart_host_scoreboard) cb; 213 | uvm_event e = uvm_event_pool::get_global(ev_name); 214 | cb=new(ev_name); 215 | cb.append_cb(this, e); 216 | endfunction: event_cb_configure 217 | endclass 218 | `endif 219 | --------------------------------------------------------------------------------