[dv/top] Test uart multiple instances

Pick a uart to test, backdoor modify memory to let SW test the
uart we pick.
Update pinmux to enable the other 3 uarts
Remove uart mon connection with scb, which is unused

Signed-off-by: Weicai Yang <weicai@google.com>
diff --git a/hw/top_earlgrey/dv/chip_sim_cfg.hjson b/hw/top_earlgrey/dv/chip_sim_cfg.hjson
index 5ecdcc2..4b5e272 100644
--- a/hw/top_earlgrey/dv/chip_sim_cfg.hjson
+++ b/hw/top_earlgrey/dv/chip_sim_cfg.hjson
@@ -166,6 +166,31 @@
       uvm_test_seq: chip_sw_uart_tx_rx_vseq
       sw_images: ["sw/device/tests/uart_tx_rx_test:1"]
       en_run_modes: ["sw_test_mode"]
+      reseed: 10
+    }
+    {
+      name: chip_sw_uart_tx_rx_idx1
+      uvm_test_seq: chip_sw_uart_tx_rx_vseq
+      sw_images: ["sw/device/tests/uart_tx_rx_test:1"]
+      en_run_modes: ["sw_test_mode"]
+      run_opts: ["+uart_idx=1"]
+      reseed: 10
+    }
+    {
+      name: chip_sw_uart_tx_rx_idx2
+      uvm_test_seq: chip_sw_uart_tx_rx_vseq
+      sw_images: ["sw/device/tests/uart_tx_rx_test:1"]
+      en_run_modes: ["sw_test_mode"]
+      run_opts: ["+uart_idx=2"]
+      reseed: 10
+    }
+    {
+      name: chip_sw_uart_tx_rx_idx3
+      uvm_test_seq: chip_sw_uart_tx_rx_vseq
+      sw_images: ["sw/device/tests/uart_tx_rx_test:1"]
+      en_run_modes: ["sw_test_mode"]
+      run_opts: ["+uart_idx=3"]
+      reseed: 10
     }
     {
       name: chip_sw_uart_tx_rx_bootstrap
diff --git a/hw/top_earlgrey/dv/env/chip_env.sv b/hw/top_earlgrey/dv/env/chip_env.sv
index 33b01f4..d9f2043 100644
--- a/hw/top_earlgrey/dv/env/chip_env.sv
+++ b/hw/top_earlgrey/dv/env/chip_env.sv
@@ -10,7 +10,7 @@
   );
   `uvm_component_utils(chip_env)
 
-  uart_agent          m_uart_agent;
+  uart_agent          m_uart_agents[NUM_UARTS];
   jtag_riscv_agent    m_jtag_riscv_agent;
   spi_agent           m_spi_agent;
 
@@ -62,8 +62,11 @@
     end
 
     // create components
-    m_uart_agent = uart_agent::type_id::create("m_uart_agent", this);
-    uvm_config_db#(uart_agent_cfg)::set(this, "m_uart_agent*", "cfg", cfg.m_uart_agent_cfg);
+    foreach (m_uart_agents[i]) begin
+      m_uart_agents[i] = uart_agent::type_id::create($sformatf("m_uart_agent%0d", i), this);
+      uvm_config_db#(uart_agent_cfg)::set(this, $sformatf("m_uart_agent%0d*", i), "cfg",
+                                          cfg.m_uart_agent_cfgs[i]);
+    end
 
     m_jtag_riscv_agent = jtag_riscv_agent::type_id::create("m_jtag_riscv_agent", this);
     uvm_config_db#(jtag_riscv_agent_cfg)::set(this, "m_jtag_riscv_agent*", "cfg",
@@ -81,12 +84,12 @@
   function void connect_phase(uvm_phase phase);
     super.connect_phase(phase);
     if (cfg.en_scb) begin
-      m_uart_agent.monitor.tx_analysis_port.connect(scoreboard.uart_tx_fifo.analysis_export);
-      m_uart_agent.monitor.rx_analysis_port.connect(scoreboard.uart_rx_fifo.analysis_export);
       m_jtag_riscv_agent.monitor.analysis_port.connect(scoreboard.jtag_fifo.analysis_export);
     end
-    if (cfg.is_active && cfg.m_uart_agent_cfg.is_active) begin
-      virtual_sequencer.uart_sequencer_h = m_uart_agent.sequencer;
+    foreach (m_uart_agents[i]) begin
+      if (cfg.is_active && cfg.m_uart_agent_cfgs[i].is_active) begin
+        virtual_sequencer.uart_sequencer_hs[i] = m_uart_agents[i].sequencer;
+      end
     end
     if (cfg.is_active && cfg.m_jtag_riscv_agent_cfg.is_active) begin
       virtual_sequencer.jtag_sequencer_h = m_jtag_riscv_agent.sequencer;
@@ -96,7 +99,10 @@
     end
 
     // Connect the DUT's UART TX TLM port to the sequencer.
-    m_uart_agent.monitor.tx_analysis_port.connect(virtual_sequencer.uart_tx_fifo.analysis_export);
+    foreach (m_uart_agents[i]) begin
+      m_uart_agents[i].monitor.tx_analysis_port.connect(
+          virtual_sequencer.uart_tx_fifos[i].analysis_export);
+    end
   endfunction
 
   virtual function void end_of_elaboration_phase(uvm_phase phase);
diff --git a/hw/top_earlgrey/dv/env/chip_env_cfg.sv b/hw/top_earlgrey/dv/env/chip_env_cfg.sv
index 89c5e33..10ba957 100644
--- a/hw/top_earlgrey/dv/env/chip_env_cfg.sv
+++ b/hw/top_earlgrey/dv/env/chip_env_cfg.sv
@@ -58,13 +58,12 @@
   sw_test_status_vif  sw_test_status_vif;
 
   // ext component cfgs
-  rand uart_agent_cfg       m_uart_agent_cfg;
+  rand uart_agent_cfg       m_uart_agent_cfgs[NUM_UARTS];
   rand jtag_riscv_agent_cfg m_jtag_riscv_agent_cfg;
   rand spi_agent_cfg        m_spi_agent_cfg;
 
   `uvm_object_utils_begin(chip_env_cfg)
     `uvm_field_int   (stub_cpu,               UVM_DEFAULT)
-    `uvm_field_object(m_uart_agent_cfg,       UVM_DEFAULT)
     `uvm_field_object(m_jtag_riscv_agent_cfg, UVM_DEFAULT)
     `uvm_field_object(m_spi_agent_cfg,        UVM_DEFAULT)
   `uvm_object_utils_end
@@ -89,7 +88,9 @@
     m_tl_agent_cfg.valid_a_source_width = 6;
 
     // create uart agent config obj
-    m_uart_agent_cfg = uart_agent_cfg::type_id::create("m_uart_agent_cfg");
+    foreach (m_uart_agent_cfgs[i]) begin
+      m_uart_agent_cfgs[i] = uart_agent_cfg::type_id::create($sformatf("m_uart_agent_cfg%0d", i));
+    end
 
     // create jtag agent config obj
     m_jtag_riscv_agent_cfg = jtag_riscv_agent_cfg::type_id::create("m_jtag_riscv_agent_cfg");
diff --git a/hw/top_earlgrey/dv/env/chip_env_pkg.sv b/hw/top_earlgrey/dv/env/chip_env_pkg.sv
index 72b7c6b..427ed49 100644
--- a/hw/top_earlgrey/dv/env/chip_env_pkg.sv
+++ b/hw/top_earlgrey/dv/env/chip_env_pkg.sv
@@ -34,6 +34,7 @@
 
   // local parameters and types
   parameter uint NUM_GPIOS = 16;
+  parameter uint NUM_UARTS = 4;
   // Buffer is half of SPI_DEVICE Dual Port SRAM
   parameter uint SPI_FRAME_BYTE_SIZE = spi_device_reg_pkg::SPI_DEVICE_BUFFER_SIZE/2;
 
diff --git a/hw/top_earlgrey/dv/env/chip_scoreboard.sv b/hw/top_earlgrey/dv/env/chip_scoreboard.sv
index c3078ef..22a2df8 100644
--- a/hw/top_earlgrey/dv/env/chip_scoreboard.sv
+++ b/hw/top_earlgrey/dv/env/chip_scoreboard.sv
@@ -12,8 +12,6 @@
   // local variables
 
   // TLM agent fifos
-  uvm_tlm_analysis_fifo #(uart_item)       uart_tx_fifo;
-  uvm_tlm_analysis_fifo #(uart_item)       uart_rx_fifo;
   uvm_tlm_analysis_fifo #(jtag_riscv_item) jtag_fifo;
 
   // local queues to hold incoming packets pending comparison
@@ -25,8 +23,6 @@
 
   function void build_phase(uvm_phase phase);
     super.build_phase(phase);
-    uart_tx_fifo = new("uart_tx_fifo", this);
-    uart_rx_fifo = new("uart_rx_fifo", this);
     jtag_fifo = new("jtag_fifo", this);
   endfunction
 
diff --git a/hw/top_earlgrey/dv/env/chip_virtual_sequencer.sv b/hw/top_earlgrey/dv/env/chip_virtual_sequencer.sv
index cf5e17e..9c4bfad 100644
--- a/hw/top_earlgrey/dv/env/chip_virtual_sequencer.sv
+++ b/hw/top_earlgrey/dv/env/chip_virtual_sequencer.sv
@@ -8,18 +8,18 @@
   );
   `uvm_component_utils(chip_virtual_sequencer)
 
-  uart_sequencer       uart_sequencer_h;
+  uart_sequencer       uart_sequencer_hs[NUM_UARTS];
   jtag_riscv_sequencer jtag_sequencer_h;
   spi_sequencer        spi_sequencer_h;
 
   // Grab packets from UART TX port for in-sequence checking.
-  uvm_tlm_analysis_fifo #(uart_item) uart_tx_fifo;
+  uvm_tlm_analysis_fifo #(uart_item) uart_tx_fifos[NUM_UARTS];
 
   `uvm_component_new
 
   function void build_phase(uvm_phase phase);
     super.build_phase(phase);
-    uart_tx_fifo = new("uart_tx_fifo", this);
+    foreach (uart_tx_fifos[i]) uart_tx_fifos[i] = new($sformatf("uart_tx_fifo%0d", i), this);
   endfunction
 
 endclass
diff --git a/hw/top_earlgrey/dv/env/seq_lib/chip_base_vseq.sv b/hw/top_earlgrey/dv/env/seq_lib/chip_base_vseq.sv
index 782b83c..765085c 100644
--- a/hw/top_earlgrey/dv/env/seq_lib/chip_base_vseq.sv
+++ b/hw/top_earlgrey/dv/env/seq_lib/chip_base_vseq.sv
@@ -80,10 +80,10 @@
   endtask
 
   // Grab packets sent by the DUT over the UART TX port.
-  virtual task get_uart_tx_items();
+  virtual task get_uart_tx_items(int uart_idx = 0);
     uart_item item;
     forever begin
-      p_sequencer.uart_tx_fifo.get(item);
+      p_sequencer.uart_tx_fifos[uart_idx].get(item);
       `uvm_info(`gfn, $sformatf("Received UART data over TX:\n%0h", item.data), UVM_HIGH)
       uart_tx_data_q.push_back(item.data);
     end
diff --git a/hw/top_earlgrey/dv/env/seq_lib/chip_stub_cpu_base_vseq.sv b/hw/top_earlgrey/dv/env/seq_lib/chip_stub_cpu_base_vseq.sv
index 8945824..3997ced 100644
--- a/hw/top_earlgrey/dv/env/seq_lib/chip_stub_cpu_base_vseq.sv
+++ b/hw/top_earlgrey/dv/env/seq_lib/chip_stub_cpu_base_vseq.sv
@@ -19,9 +19,10 @@
     // In top-level uart RX pin may be selected in pinmux. CSR tests may randomly enable line
     // loopback, which will connect TX with RX. If RX isn't enabled in pinmux, it will be 0.
     // moniter will start to check the TX data when it changes from 1 to 0. But the length of 0 may
-    // be not right in CSR test.
-    // In block-level, we always ties RX to 1 (idle) in CSR test. No need to disable the monitor
-    cfg.m_uart_agent_cfg.en_tx_monitor = 0;
+    // be not right in CSR test, which causes a protocal error on TX
+    // In block-level, we always tie RX to 1 (idle) in CSR test so that we don't need to disable TX
+    // monitor in block-level
+    foreach (cfg.m_uart_agent_cfgs[i]) cfg.m_uart_agent_cfgs[i].en_tx_monitor = 0;
   endtask
 
   task post_start();
diff --git a/hw/top_earlgrey/dv/env/seq_lib/chip_sw_base_vseq.sv b/hw/top_earlgrey/dv/env/seq_lib/chip_sw_base_vseq.sv
index 8707f9b..4206cb9 100644
--- a/hw/top_earlgrey/dv/env/seq_lib/chip_sw_base_vseq.sv
+++ b/hw/top_earlgrey/dv/env/seq_lib/chip_sw_base_vseq.sv
@@ -17,8 +17,10 @@
   // Backdoor load the sw test image, setup UART, logger and test status interfaces.
   virtual task cpu_init();
     // TODO: Fixing this for now - need to find a way to pass this on to the SW test.
-    cfg.m_uart_agent_cfg.set_parity(1'b0, 1'b0);
-    cfg.m_uart_agent_cfg.set_baud_rate(cfg.uart_baud_rate);
+    foreach (cfg.m_uart_agent_cfgs[i]) begin
+      cfg.m_uart_agent_cfgs[i].set_parity(1'b0, 1'b0);
+      cfg.m_uart_agent_cfgs[i].set_baud_rate(cfg.uart_baud_rate);
+    end
 
     // initialize the sw logger interface
     foreach (cfg.sw_images[i]) begin
diff --git a/hw/top_earlgrey/dv/env/seq_lib/chip_sw_uart_tx_rx_vseq.sv b/hw/top_earlgrey/dv/env/seq_lib/chip_sw_uart_tx_rx_vseq.sv
index 188f826..dc4e08d 100644
--- a/hw/top_earlgrey/dv/env/seq_lib/chip_sw_uart_tx_rx_vseq.sv
+++ b/hw/top_earlgrey/dv/env/seq_lib/chip_sw_uart_tx_rx_vseq.sv
@@ -22,17 +22,29 @@
     uart_rx_data.size() == UART_DATASET_SIZE;
   }
 
+  byte uart_idx = 0;
+
+  task pre_start();
+    void'($value$plusargs("uart_idx=%0d", uart_idx));
+    `DV_CHECK_LT(uart_idx, NUM_UARTS)
+    super.pre_start();
+  endtask
+
   virtual task cpu_init();
+    // sw_symbol_backdoor_overwrite takes an array as the input
+    byte uart_idx_data[] = {uart_idx};
+
     super.cpu_init();
-    sw_symbol_backdoor_overwrite("uart_tx_data", exp_uart_tx_data);
-    sw_symbol_backdoor_overwrite("exp_uart_rx_data", uart_rx_data);
+    sw_symbol_backdoor_overwrite("kUartTxData", exp_uart_tx_data);
+    sw_symbol_backdoor_overwrite("kExpUartRxData", uart_rx_data);
+    sw_symbol_backdoor_overwrite("kUartIdx", uart_idx_data);
   endtask
 
   virtual task body();
     super.body();
 
     // Spawn off a thread to retrieve UART TX items.
-    fork get_uart_tx_items(); join_none
+    fork get_uart_tx_items(uart_idx); join_none
 
     // Wait until we receive at least 1 byte from the DUT (SW test).
     wait(uart_tx_data_q.size() > 0);
@@ -56,7 +68,7 @@
   // Send data over RX.
   virtual task send_uart_rx_data(int size = -1, bit random = 0);
     uart_default_seq send_rx_seq;
-    `uvm_create_on(send_rx_seq, p_sequencer.uart_sequencer_h);
+    `uvm_create_on(send_rx_seq, p_sequencer.uart_sequencer_hs[uart_idx]);
     if (size == -1) size = uart_rx_data.size();
     for (int i = 0; i < size; i++) begin
       byte rx_data = random ? $urandom : uart_rx_data[i];
diff --git a/hw/top_earlgrey/dv/tb/tb.sv b/hw/top_earlgrey/dv/tb/tb.sv
index ce96884..9e99edb 100644
--- a/hw/top_earlgrey/dv/tb/tb.sv
+++ b/hw/top_earlgrey/dv/tb/tb.sv
@@ -40,7 +40,7 @@
 
   wire usb_dp0, usb_dn0, usb_sense0, usb_dppullup0, usb_dnpullup0;
 
-  wire uart_rx, uart_tx;
+  wire uart_rx[NUM_UARTS], uart_tx[NUM_UARTS];
 
   bit stub_cpu;
   bit en_sim_sram = 1'b1;
@@ -62,7 +62,7 @@
   pins_if #(1) rst_n_mon_if(.pins(cpu_rst_n));
   spi_if spi_if(.rst_n);
   tl_if cpu_d_tl_if(.clk(cpu_clk), .rst_n(cpu_rst_n));
-  uart_if uart_if();
+  uart_if uart_if[NUM_UARTS-1:0]();
   jtag_if jtag_if();
 
   // TODO: Replace with correct interfaces once
@@ -129,8 +129,8 @@
     .IOC7(tie_off[7]),     // MIO 29
     .IOC8(tap_straps[0]),  // MIO 30
     .IOC9(tie_off[8]),     // MIO 31
-    .IOC10(uart_rx),       // MIO 32
-    .IOC11(uart_tx),       // MIO 33
+    .IOC10(uart_rx[0]),    // MIO 32
+    .IOC11(uart_tx[0]),    // MIO 33
     .IOC12(tie_off[9]),    // MIO 34
     // Bank R (VCC domain)
     .IOR0(jtag_tms),       // MIO 35
@@ -138,14 +138,14 @@
     .IOR2(jtag_tdi),       // MIO 37
     .IOR3(jtag_tck),       // MIO 38
     .IOR4(jtag_trst_n),    // MIO 39
-    .IOR5(tie_off[10]),    // MIO 40
-    .IOR6(tie_off[11]),    // MIO 41
-    .IOR7(tie_off[12]),    // MIO 42
-    .IOR8(tie_off[13]),    // MIO 43
-    .IOR9(tie_off[14]),    // MIO 44
-    .IOR10(tie_off[15]),   // MIO 45
-    .IOR11(tie_off[16]),   // MIO 46
-    .IOR12(tie_off[17]),   // MIO 47
+    .IOR5(uart_rx[1]),     // MIO 40
+    .IOR6(uart_tx[1]),     // MIO 41
+    .IOR7(uart_rx[2]),     // MIO 42
+    .IOR8(tie_off[13]),    // MIO 43, Dedicated sysrst_ctrl output (ec_rst_l)
+    .IOR9(tie_off[14]),    // MIO 44, Dedicated sysrst_ctrl output (pwrb_out)
+    .IOR10(uart_tx[2]),    // MIO 45
+    .IOR11(uart_rx[3]),    // MIO 46
+    .IOR12(uart_tx[3]),    // MIO 47
     .IOR13(tie_off[18]),   // MIO 48
     // DCD (VCC domain)
     .CC1(tie_off[19]),
@@ -180,13 +180,6 @@
   assign spi_device_sdi_i = spi_if.sio[0];
   assign spi_if.sio[1]    = spi_device_sdo_o;
 
-  // TODO: Replace this weak pull to a known value with initialization
-  // in the agent/interface.
-  assign (weak0, weak1) uart_rx = 1'b1;
-  assign (weak0, weak1) uart_tx = 1'b1;
-  assign uart_rx = uart_if.uart_rx;
-  assign uart_if.uart_tx = uart_tx;
-
   // TODO: USB-related signals, hookup an interface.
   assign usb_rst_n  = `USBDEV_HIER.rst_usb_48mhz_ni;
   assign usb_dp0    = 1'b1;
@@ -248,7 +241,6 @@
 
     // IO Interfaces
     uvm_config_db#(virtual pins_if #(NUM_GPIOS))::set(null, "*.env", "gpio_vif", gpio_if);
-    uvm_config_db#(virtual uart_if)::set(null, "*.env.m_uart_agent*", "vif", uart_if);
     uvm_config_db#(virtual jtag_if)::set(null, "*.env.m_jtag_riscv_agent*", "vif", jtag_if);
     uvm_config_db#(virtual spi_if)::set(null, "*.env.m_spi_agent*", "vif", spi_if);
     uvm_config_db#(virtual tl_if)::set(null, "*.env.m_tl_agent*", "vif", cpu_d_tl_if);
@@ -278,6 +270,19 @@
     run_test();
   end
 
+  for (genvar i = 0; i < NUM_UARTS; i++) begin : gen_uart_if
+    // TODO: Replace this weak pull to a known value with initialization
+    // in the agent/interface.
+    assign (weak0, weak1) uart_rx[i] = 1'b1;
+    assign (weak0, weak1) uart_tx[i] = 1'b1;
+    assign uart_rx[i] = uart_if[i].uart_rx;
+    assign uart_if[i].uart_tx = uart_tx[i];
+
+    initial begin
+      uvm_config_db#(virtual uart_if)::set(null, $sformatf("*.env.m_uart_agent%0d*", i),
+                                           "vif", uart_if[i]);
+    end
+  end
   `undef SIM_SRAM_IF
 
   // Instantitate the memory backdoor util instances.
diff --git a/hw/top_earlgrey/dv/tests/chip_base_test.sv b/hw/top_earlgrey/dv/tests/chip_base_test.sv
index 1da340b..e3aa51b 100644
--- a/hw/top_earlgrey/dv/tests/chip_base_test.sv
+++ b/hw/top_earlgrey/dv/tests/chip_base_test.sv
@@ -38,8 +38,8 @@
 
     // Knob to enable logging over UART (disabled by default).
     void'($value$plusargs("en_uart_logger=%0b", cfg.en_uart_logger));
-    cfg.m_uart_agent_cfg.en_logger = cfg.en_uart_logger;
-    cfg.m_uart_agent_cfg.write_logs_to_file = cfg.write_sw_logs_to_file;
+    cfg.m_uart_agent_cfgs[0].en_logger = cfg.en_uart_logger;
+    cfg.m_uart_agent_cfgs[0].write_logs_to_file = cfg.write_sw_logs_to_file;
 
     // Knob to set the sw_test_timeout_ns (set to 5ms by default).
     void'($value$plusargs("sw_test_timeout_ns=%0d", cfg.sw_test_timeout_ns));