[chip, dv] Add chip_tap_straps
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 2e9c17b..84e6638 100644
--- a/hw/top_earlgrey/dv/chip_sim_cfg.hjson
+++ b/hw/top_earlgrey/dv/chip_sim_cfg.hjson
@@ -751,6 +751,25 @@
en_run_modes: ["sw_test_mode_test_rom"]
run_opts: ["+sw_test_timeout_ns=18000000"]
}
+ {
+ name: chip_tap_straps_dev
+ uvm_test_seq: chip_tap_straps_vseq
+ en_run_modes: ["stub_cpu_mode"]
+ en_run_modes: ["sw_test_mode_test_rom"]
+ run_opts: ["+use_otp_image=LcStDev",
+ "+create_jtag_riscv_map=1",
+ // select DFT tap
+ "+uart0_sel=0"]
+ }
+ {
+ name: chip_tap_straps_rma
+ uvm_test_seq: chip_tap_straps_vseq
+ en_run_modes: ["stub_cpu_mode"]
+ run_opts: ["+use_otp_image=LcStRma",
+ "+create_jtag_riscv_map=1",
+ // select DFT tap
+ "+uart0_sel=0"]
+ }
]
// List of regressions.
diff --git a/hw/top_earlgrey/dv/env/chip_env.core b/hw/top_earlgrey/dv/env/chip_env.core
index 8b5d5f3..00d06b1 100644
--- a/hw/top_earlgrey/dv/env/chip_env.core
+++ b/hw/top_earlgrey/dv/env/chip_env.core
@@ -40,6 +40,7 @@
- seq_lib/chip_common_vseq.sv: {is_include_file: true}
- seq_lib/chip_jtag_csr_rw_vseq.sv: {is_include_file: true}
- seq_lib/chip_jtag_mem_vseq.sv: {is_include_file: true}
+ - seq_lib/chip_tap_straps_vseq.sv: {is_include_file: true}
- seq_lib/chip_sw_base_vseq.sv: {is_include_file: true}
- seq_lib/chip_sw_full_aon_reset_vseq.sv: {is_include_file: true}
- seq_lib/chip_sw_main_power_glitch_vseq.sv: {is_include_file: true}
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 53d2cb2..6b85749 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
@@ -140,4 +140,48 @@
end
endfunction
+ task test_mem_rw(uvm_mem mem, int max_access = 2048);
+ uvm_reg_data_t rdata;
+ int wdata, exp_data[$]; // cause all data is 32bit wide in this test
+ int offmax = mem.get_size() - 1;
+ int sizemax = offmax / 4;
+ int st, sz;
+ int byte_addr;
+ st = $urandom_range(0, offmax);
+ // set the maximum transaction
+ if (sizemax > max_access) sizemax = max_access;
+
+ sz = $urandom_range(1, sizemax);
+ `uvm_info(`gfn, $sformatf("Mem write to %s offset:%0d size: %0d",
+ mem.get_full_name(), st, sz), UVM_MEDIUM)
+
+ for (int i = 0; i < sz; ++i) begin
+ wdata = $urandom();
+ exp_data.push_back(wdata);
+
+ if (mem.get_access() == "RW") begin
+ mem_wr(.ptr(mem), .offset((st + i) % (offmax + 1)), .data(wdata));
+ end else begin // if (mem.get_access() == "RW")
+ // deposit random data to rom
+ byte_addr = ((st + i) % (offmax + 1)) * 4;
+ cfg.mem_bkdr_util_h[Rom].rom_encrypt_write32_integ(.addr(byte_addr), .data(wdata),
+ .key(RndCnstRomCtrlScrKey),
+ .nonce(RndCnstRomCtrlScrNonce),
+ .scramble_data(1));
+ end
+ end
+
+ `uvm_info(`gfn, $sformatf("write to %s is complete, read back start...",
+ mem.get_full_name()), UVM_MEDIUM)
+ for (int i = 0; i < sz; ++i) begin
+ mem_rd(.ptr(mem), .offset((st + i) % (offmax + 1)), .data(rdata));
+ `DV_CHECK_EQ((int'(rdata)), exp_data[i],
+ $sformatf("read back check for offset:%0d failed",
+ ((st + i) % (offmax + 1))))
+ end
+ `uvm_info(`gfn, $sformatf("read check from %s is complete",
+ mem.get_full_name()), UVM_MEDIUM)
+
+ endtask : test_mem_rw
+
endclass : chip_base_vseq
diff --git a/hw/top_earlgrey/dv/env/seq_lib/chip_jtag_mem_vseq.sv b/hw/top_earlgrey/dv/env/seq_lib/chip_jtag_mem_vseq.sv
index c0aae8d..d823bcb 100644
--- a/hw/top_earlgrey/dv/env/seq_lib/chip_jtag_mem_vseq.sv
+++ b/hw/top_earlgrey/dv/env/seq_lib/chip_jtag_mem_vseq.sv
@@ -42,52 +42,8 @@
test_mems.shuffle();
for (int i = 0;i < test_mems.size(); ++i) begin
- access_mem(test_mems[i]);
+ test_mem_rw(test_mems[i]);
end
endtask : body
- task access_mem(uvm_mem mem);
- uvm_reg_data_t rdata;
- int wdata, exp_data[$]; // cause all data is 32bit wide in this test
- int offmax = mem.get_size() - 1;
- int sizemax = offmax / 4;
- int st, sz;
- int byte_addr;
- st = $urandom_range(0, offmax);
- // set the maximum transaction per memory to 2K * 4Byte
- if (sizemax > 2048) sizemax = 2048;
-
- sz = $urandom_range(1, sizemax);
- `uvm_info(`gfn, $sformatf("Mem write to %s offset:%0d size: %0d",
- mem.get_full_name(), st, sz), UVM_MEDIUM)
-
- for (int i = 0; i < sz; ++i) begin
- wdata = $urandom();
- exp_data.push_back(wdata);
-
- if (mem.get_access() == "RW") begin
- mem_wr(.ptr(mem), .offset((st + i) % (offmax + 1)), .data(wdata));
- end else begin // if (mem.get_access() == "RW")
- // deposit random data to rom
- byte_addr = ((st + i) % (offmax + 1)) * 4;
- cfg.mem_bkdr_util_h[Rom].rom_encrypt_write32_integ(.addr(byte_addr), .data(wdata),
- .key(RndCnstRomCtrlScrKey),
- .nonce(RndCnstRomCtrlScrNonce),
- .scramble_data(1));
- end
- end
-
- `uvm_info(`gfn, $sformatf("write to %s is complete, read back start...",
- mem.get_full_name()), UVM_MEDIUM)
- for (int i = 0; i < sz; ++i) begin
- mem_rd(.ptr(mem), .offset((st + i) % (offmax + 1)), .data(rdata));
- `DV_CHECK_EQ((int'(rdata)), exp_data[i],
- $sformatf("read back check for offset:%0d failed",
- ((st + i) % (offmax + 1))))
- end
- `uvm_info(`gfn, $sformatf("read check from %s is complete",
- mem.get_full_name()), UVM_MEDIUM)
-
- endtask // run_mem_rw
-
endclass
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 974f699..b682e92 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
@@ -11,12 +11,6 @@
`uvm_object_new
virtual task pre_start();
- super.pre_start();
- // Deselect JTAG interface.
- if (cfg.jtag_riscv_map != null) cfg.tap_straps_vif.drive(SelectRVJtagTap);
- else cfg.tap_straps_vif.drive(DeselectJtagTap);
- enable_asserts_in_hw_reset_rand_wr = 0;
-
// 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
@@ -24,6 +18,12 @@
// 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;
+
+ super.pre_start();
+ // Deselect JTAG interface.
+ if (cfg.jtag_riscv_map != null) cfg.tap_straps_vif.drive(SelectRVJtagTap);
+ else cfg.tap_straps_vif.drive(DeselectJtagTap);
+ enable_asserts_in_hw_reset_rand_wr = 0;
endtask
task post_start();
diff --git a/hw/top_earlgrey/dv/env/seq_lib/chip_tap_straps_vseq.sv b/hw/top_earlgrey/dv/env/seq_lib/chip_tap_straps_vseq.sv
new file mode 100644
index 0000000..1364a29
--- /dev/null
+++ b/hw/top_earlgrey/dv/env/seq_lib/chip_tap_straps_vseq.sv
@@ -0,0 +1,191 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// Verify pinmux can select the life_cycle, RISC-V, and DFT taps after reset.
+// Verify that in TEST_UNLOCKED* and RMA states, pinmux can switch between the three TAPs
+// without issuing reset.
+// Verify in PROD state, only the LC tap can be selected.
+// Verify in DEV state, only the LC tap and RISC-V taps can be selected.
+// Verify DFT test mode straps are sampled and output to AST via
+// top_earlgrey.dft_strap_test_o in TEST_UNLOCKED* and RMA states.
+// Verify pimux.dft_strap_test_o is always 0 in the states other than TEST_UNLOCKED* and
+// RMA, regardless of the value on DFT SW straps.
+class chip_tap_straps_vseq extends chip_common_vseq;
+ string path_dft_strap_test_o = {`DUT_HIER_STR, ".top_earlgrey.dft_strap_test_o"};
+ bit init_rv_dm_done;
+ lc_ctrl_state_pkg::lc_state_e cur_lc_state;
+
+ local uvm_reg lc_csrs[$];
+
+ `uvm_object_utils(chip_tap_straps_vseq)
+
+ `uvm_object_new
+
+ virtual task dut_init(string reset_kind = "HARD");
+ init_rv_dm_done = 0;
+ randomize_dft_straps();
+ `DV_CHECK_STD_RANDOMIZE_FATAL(select_jtag)
+ cfg.tap_straps_vif.drive(select_jtag);
+
+ super.dut_init(reset_kind);
+ endtask
+
+ virtual task body();
+ bit dft_straps_en = 1;
+ chip_tap_type_e allowed_taps_q[$];
+
+ `DV_CHECK_FATAL(uvm_hdl_check_path(path_dft_strap_test_o))
+
+ ral.lc_ctrl.get_registers(lc_csrs);
+
+ cur_lc_state = cfg.use_otp_image;
+ check_dft_straps();
+
+ // TODO, #12500 don't switch back to rv_dm again, limit to 2
+ // repeat (2) begin
+ // random_enable_jtag_tap();
+ // test_jtag_tap();
+ // end
+
+ // reproduce #12500
+ enable_jtag_tap(SelectRVJtagTap);
+ test_jtag_tap();
+ enable_jtag_tap(SelectLCJtagTap);
+ test_jtag_tap();
+ enable_jtag_tap(SelectRVJtagTap);
+ test_jtag_tap();
+
+ // check again, it shouldn't be changed
+ check_dft_straps();
+ endtask : body
+
+ virtual task random_enable_jtag_tap();
+ if (is_lc_in_unlocked_or_rma()) begin
+ `DV_CHECK_STD_RANDOMIZE_FATAL(select_jtag)
+ end else begin // switch won't take effect. tap_straps won't be sampled again
+ cfg.tap_straps_vif.drive($urandom());
+ end
+ enable_jtag_tap(select_jtag);
+ endtask
+
+ // TODO, add DFT tap
+ virtual task enable_jtag_tap(chip_tap_type_e tap);
+ select_jtag = tap;
+ cfg.tap_straps_vif.drive(select_jtag);
+ case (select_jtag)
+ SelectRVJtagTap: begin
+ if (!init_rv_dm_done) begin
+ init_rv_dm();
+ end
+ cfg.m_jtag_riscv_agent_cfg.is_rv_dm = 1;
+ end
+ SelectLCJtagTap:begin
+ cfg.m_jtag_riscv_agent_cfg.is_rv_dm = 0;
+ end
+ DeselectJtagTap: begin
+ end
+ default: begin
+ `uvm_fatal(`gfn, "Unexpected tap")
+ end
+ endcase
+ endtask
+
+ virtual task init_rv_dm();
+ jtag_riscv_dm_activation_seq jtag_dm_activation_seq =
+ jtag_riscv_dm_activation_seq::type_id::create("jtag_dm_activation_seq");
+
+ cfg.m_jtag_riscv_agent_cfg.allow_errors = 1;
+ jtag_dm_activation_seq.start(p_sequencer.jtag_sequencer_h);
+ cfg.m_jtag_riscv_agent_cfg.allow_errors = 0;
+ endtask
+
+ virtual task test_jtag_tap();
+ cfg.clk_rst_vif.wait_clks(100);
+ `uvm_info(`gfn, $sformatf("Testing jtag tab %s", select_jtag), UVM_LOW)
+ case (select_jtag)
+ SelectRVJtagTap: begin
+ test_rv_dm_access_via_jtag();
+ end
+ SelectLCJtagTap:begin
+ test_lc_access_via_jtag();
+ end
+ DeselectJtagTap: begin
+ test_no_tap_selected();
+ end
+ default: begin
+ `uvm_fatal(`gfn, "Unexpected tap")
+ end
+ endcase
+
+ cfg.clk_rst_vif.wait_clks(100);
+ endtask
+
+ virtual task test_rv_dm_access_via_jtag();
+ test_mem_rw(.mem(ral.sram_ctrl_main_ram.ram), .max_access(10));
+ endtask
+
+ virtual task test_lc_access_via_jtag();
+ foreach (ral.lc_ctrl.device_id[i]) begin
+ bit [31:0] act_device_id, exp_device_id;
+ ral.lc_ctrl.device_id[i].print(); // TODO, remove
+ csr_peek(ral.lc_ctrl.device_id[i], exp_device_id);
+ jtag_riscv_agent_pkg::jtag_read_csr(ral.lc_ctrl.device_id[i].get_offset(),
+ p_sequencer.jtag_sequencer_h,
+ act_device_id);
+ `DV_CHECK_EQ(act_device_id, exp_device_id, $sformatf("device_id index: %0d", i))
+ end
+ endtask
+
+ // if no tap is selected, expect to read all 0s
+ virtual task test_no_tap_selected();
+ bit [TL_DW-1:0] rdata;
+ repeat (10) begin
+ cfg.m_jtag_riscv_agent_cfg.is_rv_dm = $urandom_range(0, 1);
+ randcase
+ // enable rv_dm
+ 1: begin
+ cfg.m_jtag_riscv_agent_cfg.is_rv_dm = 1;
+ all_csrs.shuffle();
+ csr_rd(all_csrs[0], rdata);
+ end
+ // enable LC
+ 1: begin
+ cfg.m_jtag_riscv_agent_cfg.is_rv_dm = 0;
+ lc_csrs.shuffle();
+ jtag_riscv_agent_pkg::jtag_read_csr(lc_csrs[0].get_offset(),
+ p_sequencer.jtag_sequencer_h,
+ rdata);
+ end
+ endcase
+ $display("wcy is_rv_dm %0d", cfg.m_jtag_riscv_agent_cfg.is_rv_dm);
+ `DV_CHECK_EQ(rdata, 0)
+ end
+ endtask
+
+ virtual function void randomize_dft_straps();
+ bit [1:0] val = $urandom;
+
+ `uvm_info(`gfn, $sformatf("Drive dft straps to %0d", val), UVM_LOW)
+ cfg.dft_straps_vif.drive(val);
+ endfunction
+
+ virtual function void check_dft_straps();
+ bit [1:0] exp_val, act_val;
+
+ if (is_lc_in_unlocked_or_rma()) begin
+ exp_val = cfg.dft_straps_vif.sample();
+ end else begin
+ exp_val = 0;
+ end
+ `DV_CHECK_FATAL(uvm_hdl_read(path_dft_strap_test_o, act_val))
+
+ `DV_CHECK_EQ(act_val, exp_val)
+ endfunction
+
+ virtual function bit is_lc_in_unlocked_or_rma();
+ return cur_lc_state inside {lc_ctrl_state_pkg::LcStRma,
+ LcStTestUnlocked0, LcStTestUnlocked1, LcStTestUnlocked2, LcStTestUnlocked3,
+ LcStTestUnlocked4, LcStTestUnlocked5, LcStTestUnlocked6, LcStTestUnlocked7};
+ endfunction
+endclass
diff --git a/hw/top_earlgrey/dv/env/seq_lib/chip_vseq_list.sv b/hw/top_earlgrey/dv/env/seq_lib/chip_vseq_list.sv
index 2597f49..9299b58 100644
--- a/hw/top_earlgrey/dv/env/seq_lib/chip_vseq_list.sv
+++ b/hw/top_earlgrey/dv/env/seq_lib/chip_vseq_list.sv
@@ -8,6 +8,7 @@
`include "chip_common_vseq.sv"
`include "chip_jtag_csr_rw_vseq.sv"
`include "chip_jtag_mem_vseq.sv"
+`include "chip_tap_straps_vseq.sv"
// This needs to be listed prior to all sequences that derive from it.
`include "chip_sw_base_vseq.sv"
`include "chip_sw_full_aon_reset_vseq.sv"
diff --git a/hw/top_earlgrey/dv/tb/tb.sv b/hw/top_earlgrey/dv/tb/tb.sv
index 226c30a..d5451f9 100644
--- a/hw/top_earlgrey/dv/tb/tb.sv
+++ b/hw/top_earlgrey/dv/tb/tb.sv
@@ -94,8 +94,11 @@
// in the agent/interface.
wire ioc3;
wire ioc4;
- wire uart0_sel;
- assign uart0_sel = 1'b1;
+ bit uart0_sel = 1;
+ initial begin
+ void'($value$plusargs("uart0_sel=%0b", uart0_sel));
+ $display("wcy uart0_sel %0d",uart0_sel );
+ end
assign ioc3 = (uart0_sel) ? uart_if[0].uart_rx : dft_straps[0];
assign ioc4 = (uart0_sel) ? 1'bz : dft_straps[1];
assign uart_if[0].uart_tx = ioc4;