[uart/dv] Update uart baud rate and add coverage Address #3599 Signed-off-by: Weicai Yang <weicai@google.com>
diff --git a/hw/dv/sv/uart_agent/uart_agent_cfg.sv b/hw/dv/sv/uart_agent/uart_agent_cfg.sv index c19703a..7335207 100644 --- a/hw/dv/sv/uart_agent/uart_agent_cfg.sv +++ b/hw/dv/sv/uart_agent/uart_agent_cfg.sv
@@ -14,6 +14,12 @@ bit en_parity; bit odd_parity; + // Controls upto what percentage of the clock period the RX is randomly glitched every 1ns. + // RX is glitched at the start of the clock to ensure that the design is robust enough to sample + // the correct value (typically at the center of the clock). The recommended range for this value + // is 0-10%. + local uint uart_period_glitch_pct = 10; + // Logger settings. bit en_logger = 1'b0; // enable logger on tx bit use_rx_for_logger = 1'b0; // use rx instead of tx @@ -41,10 +47,20 @@ `uvm_field_int(en_parity, UVM_DEFAULT) `uvm_field_int(odd_parity, UVM_DEFAULT) `uvm_field_enum(baud_rate_e, baud_rate, UVM_DEFAULT) + `uvm_field_int(uart_period_glitch_pct, UVM_DEFAULT) `uvm_object_utils_end `uvm_object_new + function void set_uart_period_glitch_pct(uint pct); + `DV_CHECK_LT_FATAL(pct, 20) + uart_period_glitch_pct = pct; + endfunction + + function uint get_uart_period_glitch_pct(); + return uart_period_glitch_pct; + endfunction + function void set_baud_rate(baud_rate_e b); baud_rate = b; vif.uart_clk_period_ns = (get_baud_rate_period_ns(b) * 1ns);
diff --git a/hw/dv/sv/uart_agent/uart_agent_pkg.sv b/hw/dv/sv/uart_agent/uart_agent_pkg.sv index 31a9743..216b09f 100644 --- a/hw/dv/sv/uart_agent/uart_agent_pkg.sv +++ b/hw/dv/sv/uart_agent/uart_agent_pkg.sv
@@ -21,23 +21,29 @@ UartRx } uart_dir_e; + // Max standard baudrate is 256000 bps in the link below, so 1M should be 1024000 + // Refer to www.ece.northwestern.edu/local-apps/matlabhelp/techdoc/matlab_external/baudrate.html typedef enum int { BaudRate9600 = 9600, BaudRate115200 = 115200, BaudRate230400 = 230400, - BaudRate1Mbps = 1048576, - BaudRate2Mbps = 2097152 + BaudRate128Kbps = 128000, + BaudRate256Kbps = 256000, + BaudRate1Mbps = 1000000, + BaudRate1p5Mbps = 1500000 } baud_rate_e; // functions function automatic real get_baud_rate_period_ns(baud_rate_e baud_rate); // return 10^9 / baud_rate ns upto 3 decimal places case(baud_rate) - BaudRate9600 : return 104166.667; - BaudRate115200: return 8680.556; - BaudRate230400: return 4340.278; - BaudRate1Mbps : return 953.674; - BaudRate2Mbps : return 476.837; + BaudRate9600 : return 104166.667; + BaudRate115200: return 8680.556; + BaudRate230400: return 4340.278; + BaudRate128Kbps: return 7812.5; + BaudRate256Kbps: return 3906.25; + BaudRate1Mbps : return 1000; + BaudRate1p5Mbps: return 666.667; default: `uvm_fatal("uart_agent_pkg", {"Unsupported baud_rate: ", baud_rate.name}) endcase endfunction
diff --git a/hw/dv/sv/uart_agent/uart_driver.sv b/hw/dv/sv/uart_agent/uart_driver.sv index f17174c..f1f0397 100644 --- a/hw/dv/sv/uart_agent/uart_driver.sv +++ b/hw/dv/sv/uart_agent/uart_driver.sv
@@ -19,7 +19,7 @@ // Sets the value of rx after randomly glitching for 10% of uart clk task set_rx(input bit val); - uint glitch_ns = uint'(cfg.vif.uart_clk_period_ns * 0.1); + uint glitch_ns = uint'(cfg.vif.uart_clk_period_ns * cfg.get_uart_period_glitch_pct() / 100); repeat (glitch_ns) begin if (!cfg.under_reset) begin cfg.vif.uart_rx <= $urandom_range(0, 1);
diff --git a/hw/ip/uart/dv/env/seq_lib/uart_base_vseq.sv b/hw/ip/uart/dv/env/seq_lib/uart_base_vseq.sv index 6ad678f..a8555a4 100644 --- a/hw/ip/uart/dv/env/seq_lib/uart_base_vseq.sv +++ b/hw/ip/uart/dv/env/seq_lib/uart_base_vseq.sv
@@ -16,6 +16,9 @@ rand bit odd_parity; // enable odd parity rand bit en_noise_filter; // enable noise filter + // glitch control + rand uint uart_period_glitch_pct; + // enable interrupts rand bit [NumUartIntr-1:0] en_intr; @@ -25,7 +28,17 @@ // various knobs to enable certain routines bit do_interrupt = 1'b1; + constraint uart_period_glitch_pct_c { + uart_period_glitch_pct inside {[0:10]}; + } + constraint baud_rate_c { + // when the uart frequency is very close to core freq, disable noise filter and glitch, + // otherwise, not enough timing margin to predict status correctly in scb + if (baud_rate == BaudRate1p5Mbps && p_sequencer.cfg.clk_freq_mhz == ClkFreq24Mhz) { + en_noise_filter == 0; + uart_period_glitch_pct == 0; + } // constrain nco not over nco.get_n_bits `CALC_NCO(baud_rate, p_sequencer.cfg.ral.ctrl.nco.get_n_bits(), p_sequencer.cfg.clk_freq_mhz) < 2 ** p_sequencer.cfg.ral.ctrl.nco.get_n_bits(); @@ -55,6 +68,9 @@ // setup basic uart features virtual task uart_init(); int nco = get_nco(baud_rate, cfg.clk_freq_mhz, ral.ctrl.nco.get_n_bits()); + + cfg.m_uart_agent_cfg.set_uart_period_glitch_pct(uart_period_glitch_pct); + // cfg uart agent to set the baud rate & parity cfg.m_uart_agent_cfg.set_baud_rate(baud_rate); cfg.m_uart_agent_cfg.set_parity(en_parity, odd_parity);
diff --git a/hw/ip/uart/dv/env/uart_env_cov.sv b/hw/ip/uart/dv/env/uart_env_cov.sv index 442b79a..f5aad4a 100644 --- a/hw/ip/uart/dv/env/uart_env_cov.sv +++ b/hw/ip/uart/dv/env/uart_env_cov.sv
@@ -14,9 +14,21 @@ cross cp_dir, cp_lvl, cp_rst; endgroup + // Cover all combinations of 2 different clocks + covergroup baud_rate_w_core_clk_cg with function sample(baud_rate_e baud_rate, + clk_freq_mhz_e clk_freq); + cp_baud_rate: coverpoint baud_rate; + cp_clk_freq: coverpoint clk_freq; + cross cp_baud_rate, cp_clk_freq { + ignore_bins unsupported = binsof(cp_baud_rate) intersect {BaudRate1p5Mbps} && + binsof(cp_clk_freq) intersect {ClkFreq24Mhz}; + } + endgroup + function new(string name, uvm_component parent); super.new(name, parent); fifo_level_cg = new(); + baud_rate_w_core_clk_cg = new(); endfunction : new endclass
diff --git a/hw/ip/uart/dv/env/uart_env_pkg.sv b/hw/ip/uart/dv/env/uart_env_pkg.sv index d99dbad..895d1a3 100644 --- a/hw/ip/uart/dv/env/uart_env_pkg.sv +++ b/hw/ip/uart/dv/env/uart_env_pkg.sv
@@ -63,8 +63,11 @@ endfunction // nco = 16*(2 ** nco_width) * freq_baud / freq_core, and truncate the factional number + // if uart baud rate is 1500_000 and IO is 24Mhz, NCO is 'h1_0000, which is over the NCO width + // use NCO = 'hffff for this case since the error is tolerable. Refer to #4263 `define CALC_NCO(baud_rate, nco_width, clk_freq_mhz) \ - (longint'(baud_rate) * (2**(nco_width+4))) / (clk_freq_mhz * 1000_000) + (baud_rate == BaudRate1p5Mbps && clk_freq_mhz == ClkFreq24Mhz) ? 16'hffff : \ + (longint'(baud_rate) * (2**(nco_width+4))) / (clk_freq_mhz * 1000_000) // calculate the nco function automatic int get_nco(baud_rate_e baud_rate, int clk_freq_mhz, int nco_width);
diff --git a/hw/ip/uart/dv/env/uart_scoreboard.sv b/hw/ip/uart/dv/env/uart_scoreboard.sv index 5cf8eed..b6c2302 100644 --- a/hw/ip/uart/dv/env/uart_scoreboard.sv +++ b/hw/ip/uart/dv/env/uart_scoreboard.sv
@@ -43,8 +43,6 @@ // and it also takes 3 cycles to trigger tx matermark interrupt parameter uint NUM_CLK_DLY_TO_UPDATE_TX_WATERMARK = 3; - bit obj_raised = 1'b0; - `uvm_component_new function void build_phase(uvm_phase phase); @@ -193,6 +191,10 @@ case (csr.get_name()) "ctrl": begin if (write && channel == AddrChannel) begin + if (cfg.en_cov) begin + cov.baud_rate_w_core_clk_cg.sample(cfg.m_uart_agent_cfg.baud_rate, cfg.clk_freq_mhz); + end + tx_enabled = ral.ctrl.tx.get_mirrored_value(); rx_enabled = ral.ctrl.rx.get_mirrored_value();
diff --git a/sw/device/lib/arch/device_sim_dv.c b/sw/device/lib/arch/device_sim_dv.c index b68485f..0c51286 100644 --- a/sw/device/lib/arch/device_sim_dv.c +++ b/sw/device/lib/arch/device_sim_dv.c
@@ -19,7 +19,7 @@ const uint64_t kClockFreqUsbHz = 48 * 1000 * 1000; // 48MHz -const uint64_t kUartBaudrate = 1 * (1 << 20); // 1Mbps +const uint64_t kUartBaudrate = 1 * 1000 * 1000; // 1Mbps // Defined in `hw/top_earlgrey/dv/env/chip_env_pkg.sv` const uintptr_t kDeviceTestStatusAddress = 0x30000000;