[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;