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