[dv/prim_esc] Direct test for prim_rx/tx
This PR writes a direct test for prim_rx/tx pairs to cover the following
checkpoints:
1). Escalation request hanshake.
2). Escalation esc_tx integrity error.
3). Escalation reverse ping timeout.
4). Escalation counter fail.
Signed-off-by: Cindy Chen <chencindy@opentitan.org>
diff --git a/hw/ip/prim/dv/prim_esc/prim_esc_sim.core b/hw/ip/prim/dv/prim_esc/prim_esc_sim.core
new file mode 100644
index 0000000..ef00ab6
--- /dev/null
+++ b/hw/ip/prim/dv/prim_esc/prim_esc_sim.core
@@ -0,0 +1,31 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:dv:prim_esc_sim:0.1"
+description: "ESCALATOR DV sim target"
+filesets:
+ files_rtl:
+ depend:
+ - lowrisc:prim:esc
+ file_type: systemVerilogSource
+
+ files_dv:
+ depend:
+ - lowrisc:dv:dv_utils
+ - lowrisc:dv:dv_test_status
+ - lowrisc:dv:common_ifs
+ files:
+ - tb/prim_esc_tb.sv
+ file_type: systemVerilogSource
+
+targets:
+ sim: &sim_target
+ toplevel: prim_esc_tb
+ filesets:
+ - files_rtl
+ - files_dv
+ default_tool: vcs
+
+ lint:
+ <<: *sim_target
diff --git a/hw/ip/prim/dv/prim_esc/prim_esc_sim_cfg.hjson b/hw/ip/prim/dv/prim_esc/prim_esc_sim_cfg.hjson
new file mode 100644
index 0000000..ba53aac
--- /dev/null
+++ b/hw/ip/prim/dv/prim_esc/prim_esc_sim_cfg.hjson
@@ -0,0 +1,41 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+{
+ // Name of the sim cfg - typically same as the name of the DUT.
+ name: prim_esc
+
+ // Top level dut name (sv module).
+ dut: prim_esc
+
+ // Top level testbench name (sv module).
+ tb: prim_esc_tb
+
+ // Simulator used to sign off this block
+ tool: vcs
+
+ // Fusesoc core file used for building the file list.
+ fusesoc_core: lowrisc:dv:prim_esc_sim:0.1
+
+ // Import additional common sim cfg files.
+ import_cfgs: ["{proj_root}/hw/dv/tools/dvsim/common_sim_cfg.hjson"]
+
+ // Default iterations for all tests - each test entry can override this.
+ reseed: 1
+
+ // List of test specifications.
+ tests: [
+ {
+ name: prim_esc_test
+ run_opts: ["+test_timeout_ns=1_000"]
+ }
+ ]
+
+ // List of regressions.
+ regressions: [
+ {
+ name: smoke
+ tests: ["prim_esc_test"]
+ }
+ ]
+}
diff --git a/hw/ip/prim/dv/prim_esc/tb/prim_esc_tb.sv b/hw/ip/prim/dv/prim_esc/tb/prim_esc_tb.sv
new file mode 100644
index 0000000..5264b8d
--- /dev/null
+++ b/hw/ip/prim/dv/prim_esc/tb/prim_esc_tb.sv
@@ -0,0 +1,166 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Testbench module for prim_esc_sender and prim_esc_receiver_pair.
+//
+// This test has four sequnces:
+// 1). Escalation request sequence:
+// Drive `esc_req` signal to send an escalation request.
+// Wait random length of cycles and check `esc_en` and `integ_fail` signals.
+// Drive `esc_req` back to zero.
+// 2). Esc_tx integrity error sequence:
+// Drive `esc_req` signal to send an escalation request.
+// Force `esc_tx.esc_n` to stay high to create signal integrity errors.
+// Wait for `integ_fail` to fire then release the forced signal.
+// Drive `esc_req` back to zero.
+// 3). Escalation reverse ping request timeout sequence:
+// Drive `ping_req` signal to send an escalation ping request.
+// Wait for ping handshake to finish by waiting for `ping_ok` signal to set.
+// Drive `ping_req` signal back to 0 and check `esc_en` and `integ_fail` signals.
+// In the meantime, wait until ping counter timeout for next ping request, and check if
+// `esc_en` is set.
+// Reset DUT to clear `esc_en`.
+// 4). Escalation receiver counter fail sequence:
+// Drive `ping_req` signal to send an escalation ping request.
+// Wait until `ping_ok` to ensure the ping counter starts to increment.
+// Force one of the two identical counters to 0 and wait for `esc_en` to set.
+
+module prim_esc_tb;
+
+ //////////////////////////////////////////////////////
+ // config
+ //////////////////////////////////////////////////////
+
+ localparam time ClkPeriod = 10000;
+ localparam int PING_CNT_DW = 0;
+ localparam int TIMEOUT_CYCLES = 1 << (PING_CNT_DW + 6);
+
+ //////////////////////////////////////////////////////
+ // Clock and Reset
+ //////////////////////////////////////////////////////
+
+ wire clk, rst_n;
+
+ clk_rst_if main_clk (
+ .clk,
+ .rst_n
+ );
+
+ //////////////////////////////////////////////////////
+ // DUTs
+ //////////////////////////////////////////////////////
+
+ logic ping_req, ping_ok, integ_fail, esc_req, esc_en;
+ prim_esc_pkg::esc_tx_t esc_tx;
+ prim_esc_pkg::esc_rx_t esc_rx;
+
+ prim_esc_sender i_esc_sender (
+ .clk_i(clk),
+ .rst_ni(rst_n),
+ .ping_req_i(ping_req),
+ .ping_ok_o(ping_ok),
+ .integ_fail_o(integ_fail),
+ .esc_req_i(esc_req),
+ .esc_rx_i(esc_rx),
+ .esc_tx_o(esc_tx)
+ );
+
+ prim_esc_receiver #(
+ .N_ESC_SEV(4),
+ // Set to 0 to avoid long wait period to check ping request reverse timeout.
+ .PING_CNT_DW(PING_CNT_DW)
+ ) i_esc_receiver (
+ .clk_i(clk),
+ .rst_ni(rst_n),
+ .esc_en_o(esc_en),
+ .esc_rx_o(esc_rx),
+ .esc_tx_i(esc_tx)
+ );
+
+ //////////////////////////////////////////////////////
+ // Helper Functions/Tasks and Variables
+ //////////////////////////////////////////////////////
+
+ logic error = 0;
+
+ function automatic void test_error(string msg);
+ $error(msg);
+ error = 1;
+ endfunction
+
+ //////////////////////////////////////////////////////
+ // Stimuli Application / Response Checking
+ //////////////////////////////////////////////////////
+
+ initial begin: p_stimuli
+ ping_req = 0;
+ esc_req = 0;
+ main_clk.set_period_ps(ClkPeriod);
+ main_clk.set_active();
+ main_clk.apply_reset();
+
+ // 1). Escalation request sequence.
+ esc_req = 1;
+ // Drive random length of esc_req and check `esc_en` and `integ_fail` outputs.
+ main_clk.wait_clks($urandom_range(1, 20));
+ if (integ_fail == 1) test_error("Esc_req unexpected signal integrity error!");
+ if (esc_en == 0) test_error("Esc_req did not set esc_en!");
+ esc_req = 0;
+
+ $display("Escalation request sequence passed!");
+
+ // 2). Esc_tx integrity error sequence.
+ main_clk.wait_clks($urandom_range(1, 20));
+ esc_req = 1;
+ // Force esc_tx signal to create a integrity fail error case.
+ force esc_tx.esc_n = 1;
+ wait (integ_fail == 1);
+ release esc_tx.esc_n;
+ if (esc_en == 1) test_error("Signal integrity error should not set esc_en!");
+ esc_req = 0;
+
+ $display("Escalation esc_p/n integrity sequence passed!");
+
+ // 3). Escalation reverse ping request timeout sequence.
+ main_clk.wait_clks($urandom_range(0, 20));
+ ping_req = 1;
+ fork
+ begin
+ // After one ping_req, esc_receiver will start a counter to expect next ping_req. If the
+ // counter reaches its max value but no ping_req has been received, design will set
+ // `esc_en_o` signal.
+ main_clk.wait_clks(TIMEOUT_CYCLES + 1);
+ if (esc_en != 1) test_error("Design failed to detect ping request timeout!");
+ end
+ begin
+ // Wait for a ping handshake to complete.
+ wait (ping_ok == 1);
+ ping_req = 0;
+ if (integ_fail == 1) test_error("Ping_req unexpected signal integrity error!");
+ if (esc_en == 1) test_error("Ping request should not set esc_en!");
+ end
+ join
+ main_clk.apply_reset();
+
+ $display("Escalation ping request timeout sequence passed!");
+
+ // 4). Escalation receiver counter fail sequence.
+ ping_req = 1;
+ // Wait until ping request is acknowledged and counter starts to increment.
+ wait (ping_ok == 1);
+ ping_req = 0;
+ // If cnt_q[0] and cnt_q[1]'s value do not match, deisgn will set `esc_en_o` signal.
+ force prim_esc_tb.i_esc_receiver.cnt_q[1] = 0;
+ wait (esc_en == 1);
+ if (integ_fail == 1) begin
+ test_error("Escalation receiver counter unexpected signal integrity error!");
+ end
+
+ $display("Escalation couter error sequence passed!");
+
+ dv_test_status_pkg::dv_test_status(.passed(!error));
+ $finish();
+ end
+
+endmodule