From 3382b5ac8f331c6c2e3b722f4eeea9b9584d9649 Mon Sep 17 00:00:00 2001 From: Kolos Koblasz Date: Mon, 11 May 2026 10:34:43 +0100 Subject: [PATCH 1/7] [i2c, vendoring] Not needed .patch files removed * changes in hw/vendor/patches/lowrisc_ip/i2c/0002-Fix-Widths.patch file got implemented in upstream repo, making this patch redundant. * this commit removes the patch file Signed-off-by: Kolos Koblasz --- .../lowrisc_ip/i2c/0002-Fix-Widths.patch | 310 ------------------ 1 file changed, 310 deletions(-) delete mode 100644 hw/vendor/patches/lowrisc_ip/i2c/0002-Fix-Widths.patch diff --git a/hw/vendor/patches/lowrisc_ip/i2c/0002-Fix-Widths.patch b/hw/vendor/patches/lowrisc_ip/i2c/0002-Fix-Widths.patch deleted file mode 100644 index 5969e506d..000000000 --- a/hw/vendor/patches/lowrisc_ip/i2c/0002-Fix-Widths.patch +++ /dev/null @@ -1,310 +0,0 @@ -diff --git a/rtl/i2c_controller_fsm.sv b/rtl/i2c_controller_fsm.sv -index 2e49821..7b14ddd 100644 ---- a/rtl/i2c_controller_fsm.sv -+++ b/rtl/i2c_controller_fsm.sv -@@ -123,15 +123,15 @@ module i2c_controller_fsm import i2c_pkg::*; - tcount_d = tcount_q; - if (load_tcount) begin - unique case (tcount_sel) -- tSetupStart : tcount_d = 13'(t_r_i) + 13'(tsu_sta_i); -- tHoldStart : tcount_d = 13'(t_f_i) + 13'(thd_sta_i); -+ tSetupStart : tcount_d = 16'(t_r_i) + 16'(tsu_sta_i); -+ tHoldStart : tcount_d = 16'(t_f_i) + 16'(thd_sta_i); - tClockStart : tcount_d = 16'(thd_dat_i); -- tClockLow : tcount_d = 13'(tlow_i) - 13'(thd_dat_i); -- tClockPulse : tcount_d = 13'(t_r_i) + 13'(thigh_i); -+ tClockLow : tcount_d = 16'(tlow_i) - 16'(thd_dat_i); -+ tClockPulse : tcount_d = 16'(t_r_i) + 16'(thigh_i); - tClockHigh : tcount_d = 16'(thigh_i); -- tHoldBit : tcount_d = 13'(t_f_i) + 13'(thd_dat_i); -- tClockStop : tcount_d = 13'(t_f_i) + 13'(tlow_i) - 13'(thd_dat_i); -- tSetupStop : tcount_d = 13'(t_r_i) + 13'(tsu_sto_i); -+ tHoldBit : tcount_d = 16'(t_f_i) + 16'(thd_dat_i); -+ tClockStop : tcount_d = 16'(t_f_i) + 16'(tlow_i) - 16'(thd_dat_i); -+ tSetupStop : tcount_d = 16'(t_r_i) + 16'(tsu_sto_i); - tNoDelay : tcount_d = 16'h0001; - default : tcount_d = 16'h0001; - endcase -@@ -392,7 +392,7 @@ module i2c_controller_fsm import i2c_pkg::*; - // a repeated start, the FSM will just go back to Idle and wait for the bus to go free - // again. - ctrl_symbol_failed = 1'b1; -- end else if (tcount_q == 20'd1) begin -+ end else if (tcount_q == 16'd1) begin - log_start = 1'b1; - event_cmd_complete_o = pend_restart; - end -@@ -488,7 +488,7 @@ module i2c_controller_fsm import i2c_pkg::*; - ReadHoldBit : begin - host_idle_o = 1'b0; - scl_d = 1'b0; -- if (bit_index == '0 && tcount_q == 20'd1) begin -+ if (bit_index == '0 && tcount_q == 16'd1) begin - rx_fifo_wvalid_o = 1'b1; // assert that rx_fifo has valid data - rx_fifo_wdata_o = read_byte; // transfer read data to rx_fifo - end -@@ -670,7 +670,7 @@ module i2c_controller_fsm import i2c_pkg::*; - end else if (trans_started && !scl_i && scl_i_q) begin - // Failed to issue repeated Start. Effectively lost arbitration. - state_d = Idle; -- end else if (tcount_q == 20'd1) begin -+ end else if (tcount_q == 16'd1) begin - state_d = HoldStart; - load_tcount = 1'b1; - tcount_sel = tHoldStart; -@@ -678,7 +678,7 @@ module i2c_controller_fsm import i2c_pkg::*; - end - // HoldStart: SDA is pulled low, SCL is released - HoldStart : begin -- if (tcount_q == 20'd1 || (!scl_i && scl_i_q)) begin -+ if (tcount_q == 16'd1 || (!scl_i && scl_i_q)) begin - state_d = ClockStart; - load_tcount = 1'b1; - tcount_sel = tClockStart; -@@ -686,7 +686,7 @@ module i2c_controller_fsm import i2c_pkg::*; - end - // ClockStart: SCL is pulled low, SDA stays low - ClockStart : begin -- if (tcount_q == 20'd1) begin -+ if (tcount_q == 16'd1) begin - state_d = ClockLow; - load_tcount = 1'b1; - tcount_sel = tClockLow; -@@ -694,7 +694,7 @@ module i2c_controller_fsm import i2c_pkg::*; - end - // ClockLow: SCL stays low, shift indexed bit onto SDA - ClockLow : begin -- if (tcount_q == 20'd1) begin -+ if (tcount_q == 16'd1) begin - load_tcount = 1'b1; - if (pend_restart) begin - state_d = SetupStart; -@@ -714,7 +714,7 @@ module i2c_controller_fsm import i2c_pkg::*; - end else if (scl_i_q && scl_i && (sda_i_q != sda_i)) begin - // Unexpected Stop / Start - state_d = Idle; -- end else if (tcount_q == 20'd1 || (!scl_i && scl_i_q)) begin -+ end else if (tcount_q == 16'd1 || (!scl_i && scl_i_q)) begin - // Transition either when we finish counting our high period or - // another controller pulls clock low. - state_d = HoldBit; -@@ -724,7 +724,7 @@ module i2c_controller_fsm import i2c_pkg::*; - end - // HoldBit: SCL is pulled low - HoldBit : begin -- if (tcount_q == 20'd1) begin -+ if (tcount_q == 16'd1) begin - load_tcount = 1'b1; - tcount_sel = tClockLow; - if (bit_index == '0) begin -@@ -739,7 +739,7 @@ module i2c_controller_fsm import i2c_pkg::*; - // ClockLowAck: Target is allowed to drive ack back - // to host (dut) - ClockLowAck : begin -- if (tcount_q == 20'd1) begin -+ if (tcount_q == 16'd1) begin - state_d = ClockPulseAck; - load_tcount = 1'b1; - tcount_sel = tClockPulse; -@@ -755,7 +755,7 @@ module i2c_controller_fsm import i2c_pkg::*; - // Unexpected Stop / Start - state_d = Idle; - end else begin -- if (tcount_q == 20'd1 || (!scl_i && scl_i_q)) begin -+ if (tcount_q == 16'd1 || (!scl_i && scl_i_q)) begin - state_d = HoldDevAck; - load_tcount = 1'b1; - tcount_sel = tHoldBit; -@@ -764,7 +764,7 @@ module i2c_controller_fsm import i2c_pkg::*; - end - // HoldDevAck: SCL is pulled low - HoldDevAck : begin -- if (tcount_q == 20'd1) begin -+ if (tcount_q == 16'd1) begin - if (fmt_flag_stop_after_i) begin - state_d = ClockStop; - load_tcount = 1'b1; -@@ -778,7 +778,7 @@ module i2c_controller_fsm import i2c_pkg::*; - end - // ReadClockLow: SCL is pulled low, SDA is released - ReadClockLow : begin -- if (tcount_q == 20'd1) begin -+ if (tcount_q == 16'd1) begin - state_d = ReadClockPulse; - load_tcount = 1'b1; - tcount_sel = tClockPulse; -@@ -793,7 +793,7 @@ module i2c_controller_fsm import i2c_pkg::*; - end else if (scl_i_q && scl_i && (sda_i_q != sda_i)) begin - // Unexpected Stop / Start - state_d = Idle; -- end else if (tcount_q == 20'd1 || (!scl_i && scl_i_q)) begin -+ end else if (tcount_q == 16'd1 || (!scl_i && scl_i_q)) begin - state_d = ReadHoldBit; - load_tcount = 1'b1; - tcount_sel = tHoldBit; -@@ -802,7 +802,7 @@ module i2c_controller_fsm import i2c_pkg::*; - end - // ReadHoldBit: SCL is pulled low - ReadHoldBit : begin -- if (tcount_q == 20'd1) begin -+ if (tcount_q == 16'd1) begin - load_tcount = 1'b1; - tcount_sel = tClockLow; - if (bit_index == '0) begin -@@ -818,7 +818,7 @@ module i2c_controller_fsm import i2c_pkg::*; - // HostClockLowAck: SCL is pulled low, SDA is conditional based on - // byte position - HostClockLowAck : begin -- if (tcount_q == 20'd1) begin -+ if (tcount_q == 16'd1) begin - state_d = HostClockPulseAck; - load_tcount = 1'b1; - tcount_sel = tClockPulse; -@@ -833,7 +833,7 @@ module i2c_controller_fsm import i2c_pkg::*; - end else if (scl_i_q && scl_i && (sda_i_q != sda_i)) begin - // Unexpected Stop / Start - state_d = Idle; -- end else if (tcount_q == 20'd1 || (!scl_i && scl_i_q)) begin -+ end else if (tcount_q == 16'd1 || (!scl_i && scl_i_q)) begin - state_d = HostHoldBitAck; - load_tcount = 1'b1; - tcount_sel = tHoldBit; -@@ -841,7 +841,7 @@ module i2c_controller_fsm import i2c_pkg::*; - end - // HostHoldBitAck: SCL is pulled low - HostHoldBitAck : begin -- if (tcount_q == 20'd1) begin -+ if (tcount_q == 16'd1) begin - if (byte_index == 9'd1) begin - if (fmt_flag_stop_after_i) begin - state_d = ClockStop; -@@ -862,7 +862,7 @@ module i2c_controller_fsm import i2c_pkg::*; - end - // ClockStop: SCL is pulled low, SDA stays low - ClockStop : begin -- if (tcount_q == 20'd1) begin -+ if (tcount_q == 16'd1) begin - state_d = SetupStop; - load_tcount = 1'b1; - tcount_sel = tSetupStop; -@@ -877,7 +877,7 @@ module i2c_controller_fsm import i2c_pkg::*; - end else if (!scl_i && scl_i_q) begin - // Failed to issue Stop before some other device could pull SCL low. - state_d = Idle; -- end else if (tcount_q == 20'd1) begin -+ end else if (tcount_q == 16'd1) begin - state_d = HoldStop; - end - end -diff --git a/rtl/i2c_target_fsm.sv b/rtl/i2c_target_fsm.sv -index 8ed7608..d5108c3 100644 ---- a/rtl/i2c_target_fsm.sv -+++ b/rtl/i2c_target_fsm.sv -@@ -132,7 +132,7 @@ module i2c_target_fsm import i2c_pkg::*; - tcount_d = tcount_q; - if (load_tcount) begin - unique case (tcount_sel) -- tSetupData : tcount_d = 13'(t_r_i) + 13'(tsu_dat_i); -+ tSetupData : tcount_d = 16'(t_r_i) + 16'(tsu_dat_i); - tHoldData : tcount_d = 16'(thd_dat_i); - tNoDelay : tcount_d = 16'h0001; - default : tcount_d = 16'h0001; -@@ -266,7 +266,7 @@ module i2c_target_fsm import i2c_pkg::*; - // has happened while still keeping space for a subsequent stop or repeated - // start. - logic [AcqFifoDepthWidth-1:0] acq_fifo_remainder; -- assign acq_fifo_remainder = AcqFifoDepth - acq_fifo_depth_i; -+ assign acq_fifo_remainder = AcqFifoDepthWidth'(AcqFifoDepth) - acq_fifo_depth_i; - // This is used for acq_fifo_full_o to send the ACQ FIFO full alert to - // software. - assign acq_fifo_plenty_space = acq_fifo_remainder > AcqFifoDepthWidth'(2); -@@ -415,7 +415,7 @@ module i2c_target_fsm import i2c_pkg::*; - transmitting_o = 1'b1; - - // Upon transition to next state, populate the acquisition fifo -- if (tcount_q == 20'd1) begin -+ if (tcount_q == 16'd1) begin - if (nack_transaction_q) begin - // No need to record anything here. We already recorded the first - // NACK'd byte in a stretch state or abandoned the transaction in -@@ -507,7 +507,7 @@ module i2c_target_fsm import i2c_pkg::*; - sda_d = 1'b0; - transmitting_o = 1'b1; - -- if (tcount_q == 20'd1) begin -+ if (tcount_q == 16'd1) begin - auto_ack_cnt_d = auto_ack_cnt_q - 1'b1; - acq_fifo_wvalid_o = ~stretch_rx; // assert that acq_fifo has space - acq_fifo_wdata_o = {AcqData, input_byte}; // transfer data to acq_fifo -@@ -717,7 +717,7 @@ module i2c_target_fsm import i2c_pkg::*; - if (scl_i) begin - // The controller is going too fast. Abandon the transaction. - state_d = WaitForStop; -- end else if (tcount_q == 20'd1) begin -+ end else if (tcount_q == 16'd1) begin - if (!nack_addr_after_timeout_i) begin - // Always ACK addresses in this mode. - state_d = AddrAckSetup; -@@ -756,7 +756,7 @@ module i2c_target_fsm import i2c_pkg::*; - end - // AddrAckHold: target pulls SDA low while SCL is pulled low - AddrAckHold : begin -- if (tcount_q == 20'd1) begin -+ if (tcount_q == 16'd1) begin - // Stretch when requested by software or when there is insufficient - // space to hold the start / address format byte. - // If there is sufficient space, the format byte is written into the acquisition fifo. -@@ -807,7 +807,7 @@ module i2c_target_fsm import i2c_pkg::*; - end - // TransmitHold: target shifts indexed bit onto SDA while SCL is pulled low - TransmitHold : begin -- if (tcount_q == 20'd1) begin -+ if (tcount_q == 16'd1) begin - if (bit_ack) begin - state_d = TransmitAck; - end else begin -@@ -855,7 +855,7 @@ module i2c_target_fsm import i2c_pkg::*; - if (scl_i) begin - // The controller is going too fast. Abandon the transaction. - state_d = WaitForStop; -- end else if (tcount_q == 20'd1) begin -+ end else if (tcount_q == 16'd1) begin - if (nack_transaction_q) begin - state_d = WaitForStop; - end else if (stretch_rx) begin -@@ -882,7 +882,7 @@ module i2c_target_fsm import i2c_pkg::*; - end - // AcquireAckHold: target pulls SDA low while SCL is pulled low - AcquireAckHold : begin -- if (tcount_q == 20'd1) begin -+ if (tcount_q == 16'd1) begin - state_d = AcquireByte; - end - end -@@ -902,7 +902,7 @@ module i2c_target_fsm import i2c_pkg::*; - // StretchAddrAckSetup: target pulls SDA low while pulling SCL low for - // setup time. This is to prepare the setup time after a stretch. - StretchAddrAckSetup : begin -- if (tcount_q == 20'd1) begin -+ if (tcount_q == 16'd1) begin - state_d = AddrAckSetup; - end - end -@@ -945,7 +945,7 @@ module i2c_target_fsm import i2c_pkg::*; - end - // StretchTxSetup: Wait for tSetupData before going to transmit - StretchTxSetup : begin -- if (tcount_q == 20'd1) begin -+ if (tcount_q == 16'd1) begin - state_d = TransmitSetup; - end - end -@@ -968,7 +968,7 @@ module i2c_target_fsm import i2c_pkg::*; - // StretchAcqSetup: Drive the ACK and wait for tSetupData before - // releasing SCL - StretchAcqSetup : begin -- if (tcount_q == 20'd1) begin -+ if (tcount_q == 16'd1) begin - state_d = AcquireAckSetup; - end - end From 533dafed6de7b79c7e8f51457d41a351cb4d6ce9 Mon Sep 17 00:00:00 2001 From: Kolos Koblasz Date: Mon, 18 May 2026 15:45:15 +0100 Subject: [PATCH 2/7] [kk_rst_mgr_dv, patch] Not needed .patch removed * kmack_app_agent_rom_ctrl_dv.patch removed Signed-off-by: Kolos Koblasz --- .../0002-kmac_app_agent_rom_ctrl_dv.patch | 60 ------------------- 1 file changed, 60 deletions(-) delete mode 100644 hw/vendor/patches/lowrisc_ip/dv_sv/0002-kmac_app_agent_rom_ctrl_dv.patch diff --git a/hw/vendor/patches/lowrisc_ip/dv_sv/0002-kmac_app_agent_rom_ctrl_dv.patch b/hw/vendor/patches/lowrisc_ip/dv_sv/0002-kmac_app_agent_rom_ctrl_dv.patch deleted file mode 100644 index 3100bcd42..000000000 --- a/hw/vendor/patches/lowrisc_ip/dv_sv/0002-kmac_app_agent_rom_ctrl_dv.patch +++ /dev/null @@ -1,60 +0,0 @@ -diff --git a/kmac_app_agent/kmac_app_agent.core b/kmac_app_agent/kmac_app_agent.core -index 79527cc..acaf70c 100644 ---- a/kmac_app_agent/kmac_app_agent.core -+++ b/kmac_app_agent/kmac_app_agent.core -@@ -10,7 +10,6 @@ filesets: - - lowrisc:dv:dv_utils - - lowrisc:dv:dv_lib - - lowrisc:dv:push_pull_agent -- - lowrisc:ip:keymgr_pkg - - lowrisc:ip:kmac_pkg - files: - - kmac_app_agent_pkg.sv -diff --git a/kmac_app_agent/kmac_app_agent_pkg.sv b/kmac_app_agent/kmac_app_agent_pkg.sv -index d1b3586..572b536 100644 ---- a/kmac_app_agent/kmac_app_agent_pkg.sv -+++ b/kmac_app_agent/kmac_app_agent_pkg.sv -@@ -7,7 +7,6 @@ package kmac_app_agent_pkg; - import uvm_pkg::*; - import dv_utils_pkg::*; - import dv_lib_pkg::*; -- import keymgr_pkg::*; - import push_pull_agent_pkg::*; - - // macro includes -@@ -15,9 +14,10 @@ package kmac_app_agent_pkg; - `include "dv_macros.svh" - - // parameters -- parameter int KMAC_REQ_DATA_WIDTH = keymgr_pkg::KmacDataIfWidth // data width -- + keymgr_pkg::KmacDataIfWidth / 8 // data mask width -- + 1; // bit last -+ parameter int KmacDataIfWidth = 64; // keymgr_pkg::KmacDataIfWidth -+ parameter int KMAC_REQ_DATA_WIDTH = KmacDataIfWidth // data width -+ + KmacDataIfWidth / 8 // data mask width -+ + 1; // bit last - - `define CONNECT_DATA_WIDTH .HostDataWidth(kmac_app_agent_pkg::KMAC_REQ_DATA_WIDTH) - -diff --git a/kmac_app_agent/kmac_app_intf.sv b/kmac_app_agent/kmac_app_intf.sv -index 8fe2c41..b5c926c 100644 ---- a/kmac_app_agent/kmac_app_intf.sv -+++ b/kmac_app_agent/kmac_app_intf.sv -@@ -5,8 +5,6 @@ - // verilog_lint: waive interface-name-style - interface kmac_app_intf (input clk, input rst_n); - -- import keymgr_pkg::*; -- - dv_utils_pkg::if_mode_e if_mode; // interface mode - Host or Device - - // interface pins used to connect with DUT -@@ -60,7 +58,7 @@ interface kmac_app_intf (input clk, input rst_n); - clk, !rst_n || if_mode == dv_utils_pkg::Host) - - // Check strb is aligned to LSB, for example: if strb[1]==0, strb[$:2] should be 0 too -- for (genvar k = 1; k < KmacDataIfWidth / 8 - 1; k++) begin : gen_strb_check -+ for (genvar k = 1; k < kmac_app_agent_pkg::KmacDataIfWidth / 8 - 1; k++) begin : gen_strb_check - `ASSERT(StrbAlignLSB_A, kmac_data_req.valid && kmac_data_req.strb[k] === 0 |-> - kmac_data_req.strb[k+1] === 0, - clk, !rst_n || if_mode == dv_utils_pkg::Host) From 49bb669f61783f4d18748efa210bc76600572a0b Mon Sep 17 00:00:00 2001 From: Kolos Koblasz Date: Mon, 11 May 2026 10:58:19 +0100 Subject: [PATCH 3/7] [prim_xilinx, vendoring] Not needed .patch files removed * Upstream repo now contains the patch file, therfore hw/vendor/patches/lowrisc_ip/prim_xilinx/0001_Mem_Init_String.patch is deleted Signed-off-by: Kolos Koblasz --- hw/vendor/lowrisc_ip.vendor.hjson | 2 +- .../prim_xilinx/0001_Mem_Init_String.patch | 13 ------------- 2 files changed, 1 insertion(+), 14 deletions(-) delete mode 100644 hw/vendor/patches/lowrisc_ip/prim_xilinx/0001_Mem_Init_String.patch diff --git a/hw/vendor/lowrisc_ip.vendor.hjson b/hw/vendor/lowrisc_ip.vendor.hjson index b2cc35963..140000d75 100644 --- a/hw/vendor/lowrisc_ip.vendor.hjson +++ b/hw/vendor/lowrisc_ip.vendor.hjson @@ -51,7 +51,7 @@ // Primitives. {from: "hw/ip/prim", to: "ip/prim", patch_dir: "prim"}, {from: "hw/ip/prim_generic", to: "ip/prim_generic"}, - {from: "hw/ip/prim_xilinx", to: "ip/prim_xilinx", patch_dir: "prim_xilinx"}, + {from: "hw/ip/prim_xilinx", to: "ip/prim_xilinx"}, // Lint. {from: "hw/lint", to: "lint", patch_dir: "lint"}, diff --git a/hw/vendor/patches/lowrisc_ip/prim_xilinx/0001_Mem_Init_String.patch b/hw/vendor/patches/lowrisc_ip/prim_xilinx/0001_Mem_Init_String.patch deleted file mode 100644 index db550c901..000000000 --- a/hw/vendor/patches/lowrisc_ip/prim_xilinx/0001_Mem_Init_String.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/rtl/prim_xilinx_rom.sv b/rtl/prim_xilinx_rom.sv -index e7aa5cb..27a55c6 100644 ---- a/rtl/prim_xilinx_rom.sv -+++ b/rtl/prim_xilinx_rom.sv -@@ -7,7 +7,7 @@ - module prim_rom import prim_rom_pkg::*; #( - parameter int Width = 32, - parameter int Depth = 2048, // 8kB default -- parameter string MemInitFile = "", // VMEM file to initialize the memory with -+ parameter MemInitFile = "", // VMEM file to initialize the memory with - - localparam int Aw = $clog2(Depth) - ) ( From eba19047dfa365db5f848ff29d7fc7ad566f4975 Mon Sep 17 00:00:00 2001 From: Kolos Koblasz Date: Fri, 22 May 2026 12:19:38 +0100 Subject: [PATCH 4/7] Update lowrisc_ip to lowRISC/opentitan@bf4a2b24e4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update code from upstream repository https://github.com/lowRISC/opentitan to revision bf4a2b24e41742151cfce9c4041e959a3ba76ca3 * [I2C, DV] Refactoring the way ACKs / NACKs are driven (Kinza Qamar) * [I2C, DV] Use urandom_range() to simplify randomizing Ack / Nack (Kinza Qamar) * [dv] Correct documentation about reset tracking in csr_utils (Rupert Swarbrick) * [tl,dv] Minor timing fixes in tl_host_driver (Rupert Swarbrick) * [tl,dv] Tidy up signal names in clocking blocks (Rupert Swarbrick) * [alert,dv] Remove alert_esc_seq_item::alert_int_err_type (Rupert Swarbrick) * [dv] Define csr_excluded to balance iterations in csr_hw_reset_seq (Rupert Swarbrick) * [dv] Define a csr_excluded function in csr_base_seq (Rupert Swarbrick) * [dv] Split csr_hw_reset_seq into its own file (Rupert Swarbrick) * [dv] Split out max_num_test_csrs explicitly in csr_base_seq (Rupert Swarbrick) * [dv,doc] Add detailed documentation to csr_base_seq.sv (Rupert Swarbrick) * [dv,csr_utils] Split csr_base_seq into its own file (Rupert Swarbrick) * [dv] Fix and document timing in cip_base_vseq::wait_alert_trigger (Rupert Swarbrick) * [dv] Allow a test to configure an env_cfg before cfg.initialize() (Rupert Swarbrick) * [kmac,rtl] Add bypass to message FIFO to support 2 shares (Pascal Etterli) * [kmac,rtl] Clean up naming of strobe (Pascal Etterli) * [kmac] Increase version to 2.1.0 (Pascal Etterli) * [dv] Extend memory backdoor data width limit (Sharon Topaz) * [reggen] Avoid spamming console for some params from gen_cheader (Rupert Swarbrick) * [dv] Decouple mem_bkdr_util row width and uvm_hdl_data_t (Rupert Swarbrick) * [top,rstmgr] Rename power domain "0" to "Main" (Florian Glaser) * [top] Untangle power- and reset domains (Florian Glaser) * [doc] Update various dvsim references (Harry Callahan) * [alert,dv] Simplify how we constrain ping_delay (Rupert Swarbrick) * [alert,dv] Randomize correct object in alert_receiver_alert_rsp_seq (Rupert Swarbrick) * [jtag,dv] Make jtag_dtm_reg_adapter a bit more local (Rupert Swarbrick) * [dv] Extract the dv_base_agent files into their own core and package (Rupert Swarbrick) * [toplevels] Reorganize toplevel.sv templates (Florian Glaser) * [alert,dv] Don't return too early from a ping (Rupert Swarbrick) * [dv] Rationalise dv_base_driver reset tracking (Rupert Swarbrick) * [dv] Restructure the way jtag_dmi_reg_frontdoor is given dmi/dtmcs (Rupert Swarbrick) * [entropy_src,dv] Remove remaining tb.dut paths from entropy_src dv (Rupert Swarbrick) * [entropy_src,dv] Remove a bunch of unused path definitions (Rupert Swarbrick) * [entropy_src,dv] Use relative references in entropy_src_cov_if (Rupert Swarbrick) * [entropy_src,dv] Bind instance of entropy_src_path_if into the dut (Rupert Swarbrick) * [aes/dv] Add RAL type override to allow separating GCM and non-GCM DV (Pirmin Vogel) * [hw/otbn] Add new HPC gadgets (Hakim Filali) * [prim/rtl] Improve prim_fifo_async_simple for rv_dm and lc_ctrl (Neil Webb) * [clkmgr/cdc] Deglitch on shadow register error alerts (Neil Webb) * [prim/rtl] Explicitly assign values to FSM states in prim_sync_reqack (Neil Webb) * [rstmgr, DV] Fixed the message and ID body inside (Kinza Qamar) * [i2c,hw] Correct assign/compare widths (Elliot Baptist) * [dv] Pass is_active from cip_base_env_cfg to alert and TL agents (Rupert Swarbrick) * [prim_xilinx] Use typeless parameter for MemInitFile (Ray Lau) * [dv] Stop jtag_dmi_monitor depending on jtag_agent_cfg (Rupert Swarbrick) * [dv] Beta-reduce slightly silly templating in fpv_csr.sv.tpl (Rupert Swarbrick) * [dv] Fix REGWEN_PATH in fpv_csr.sv.tpl (Rupert Swarbrick) * [top/templates] Indentation and whitespaces fixes (Florian Glaser) * [topgen] Automatically generate port map for toplevels (Florian Glaser) * [clkmgr,dv] Fix invalid type in clkmgr_regwen_vseq (Rupert Swarbrick) * [tl,dv] Make TL assertions cause simulation failure when they fail (Rupert Swarbrick) * [topgen,sw] Fix operations between different enum types, part II (Luís Marques) * [rv_plic,rtl] Move the onehot0 checks to rv_plic_gateway (Rupert Swarbrick) * [rv_plic,doc] Add some careful documentation to rv_plic_gateway.sv (Rupert Swarbrick) * [rv_plic,rtl] Simplify code for ia update in the gateway (Rupert Swarbrick) * [rv_plic,rtl] Simplify ip_o rule in rv_plic_gateway (Rupert Swarbrick) * [rv_plic,fpv] Add an assertion about relationship between ia and ip (Rupert Swarbrick) * [I2C, dv] Removed unused argument (Kinza Qamar) * [tl,dv] Clear the stop flag at the end, not the start, of body() (Rupert Swarbrick) * [I2C, dv] Simplified i2c_device_response seq's drive_read_byte() (Kinza Qamar) * [i2c/rtl] Change VAL register input to synced SCL/SDA (Neil Webb) * [I2C, dv] Removed the unused i2c_dv_if (Kinza Qamar) * [dv] Simplify key sideload driver (Rupert Swarbrick) * [dv] Allow a cfg to be passed directly to dv_base_agent (Rupert Swarbrick) * [hw,prim] Add new prim_inv (Hakim Filali) * [prim] Add prim_flop_x module to wrap different prim_flop variants (Pirmin Vogel) * [dv] Remove csr_base_addr argument from dv_base_env_cfg::initialize (Rupert Swarbrick) * [dv] Add "Monitor" to if_mode_e (Rupert Swarbrick) * [hw] gpiodpi: fix backwards log message (Alice Ziuziakowska) * [pwrmgr,dv] Remove do-nothing $assertoff (Rupert Swarbrick) Signed-off-by: Kolos Koblasz --- hw/vendor/lowrisc_ip.lock.hjson | 2 +- hw/vendor/lowrisc_ip/dv/dpi/gpiodpi/gpiodpi.c | 8 +- .../sv/alert_esc_agent/alert_base_driver.sv | 14 +- .../sv/alert_esc_agent/alert_esc_agent_cfg.sv | 10 +- .../sv/alert_esc_agent/alert_esc_agent_pkg.sv | 8 +- .../dv/sv/alert_esc_agent/alert_esc_if.sv | 10 + .../sv/alert_esc_agent/alert_esc_seq_item.sv | 26 +- .../alert_esc_agent/alert_receiver_driver.sv | 786 ++++++++++-------- .../sv/alert_esc_agent/alert_sender_driver.sv | 148 ++-- .../sv/alert_esc_agent/esc_receiver_driver.sv | 20 +- .../sv/alert_esc_agent/esc_sender_driver.sv | 17 +- .../seq_lib/alert_receiver_alert_rsp_seq.sv | 2 +- .../seq_lib/alert_receiver_ping_seq.sv | 8 +- hw/vendor/lowrisc_ip/dv/sv/cip_lib/README.md | 22 +- .../dv/sv/cip_lib/cip_base_env_cfg.sv | 13 +- .../dv/sv/cip_lib/seq_lib/cip_base_vseq.sv | 84 +- .../lowrisc_ip/dv/sv/csr_utils/README.md | 13 +- .../dv/sv/csr_utils/csr_base_seq.sv | 306 +++++++ .../dv/sv/csr_utils/csr_hw_reset_seq.sv | 65 ++ .../lowrisc_ip/dv/sv/csr_utils/csr_seq_lib.sv | 148 ---- .../lowrisc_ip/dv/sv/csr_utils/csr_utils.core | 2 + .../dv/sv/csr_utils/csr_utils_pkg.sv | 2 + .../dv/sv/csrng_agent/csrng_agent_pkg.sv | 1 + .../dv/sv/csrng_agent/csrng_device_driver.sv | 4 +- .../dv/sv/csrng_agent/csrng_host_driver.sv | 5 - .../dv/sv/dv_base_agent/dv_base_agent.core | 27 + .../dv_base_agent.sv | 2 +- .../dv_base_agent_cfg.sv | 0 .../dv_base_agent_cov.sv | 0 .../dv/sv/dv_base_agent/dv_base_agent_pkg.sv | 28 + .../dv/sv/dv_base_agent/dv_base_driver.sv | 91 ++ .../dv_base_monitor.sv | 0 .../{dv_lib => dv_base_agent}/dv_base_seq.sv | 0 .../dv_base_sequencer.sv | 0 .../dv/sv/dv_base_reg/dv_base_reg_block.sv | 6 +- .../lowrisc_ip/dv/sv/dv_lib/dv_base_driver.sv | 53 -- .../dv/sv/dv_lib/dv_base_env_cfg.sv | 30 +- .../lowrisc_ip/dv/sv/dv_lib/dv_base_test.sv | 13 +- .../lowrisc_ip/dv/sv/dv_lib/dv_base_vseq.sv | 2 +- hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_lib.core | 9 +- .../lowrisc_ip/dv/sv/dv_lib/dv_lib_pkg.sv | 11 +- .../lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv | 9 +- .../entropy_src_xht_agent_pkg.sv | 1 + .../entropy_src_xht_device_driver.sv | 15 +- .../flash_phy_prim_agent_pkg.sv | 1 + .../flash_phy_prim_driver.sv | 4 - .../dv/sv/i2c_agent/i2c_agent_pkg.sv | 1 + .../lowrisc_ip/dv/sv/i2c_agent/i2c_driver.sv | 23 +- .../lowrisc_ip/dv/sv/i2c_agent/i2c_if.sv | 10 +- .../lowrisc_ip/dv/sv/i2c_agent/i2c_monitor.sv | 4 +- .../dv/sv/i2c_agent/seq_lib/i2c_base_seq.sv | 27 +- .../seq_lib/i2c_device_response_seq.sv | 10 +- .../seq_lib/i2c_target_may_nack_seq.sv | 38 +- .../lowrisc_ip/dv/sv/jtag_agent/jtag_agent.sv | 11 +- .../dv/sv/jtag_agent/jtag_agent_pkg.sv | 1 + .../dv/sv/jtag_agent/jtag_driver.sv | 18 +- .../dv/sv/jtag_agent/jtag_dtm_reg_adapter.sv | 95 ++- .../sv/jtag_dmi_agent/jtag_dmi_agent_pkg.sv | 7 +- .../dv/sv/jtag_dmi_agent/jtag_dmi_monitor.sv | 39 +- .../jtag_dmi_agent/jtag_dmi_reg_frontdoor.sv | 71 +- .../sv/jtag_dmi_agent/jtag_rv_debugger_pkg.sv | 1 + .../jtag_riscv_agent/jtag_riscv_agent_pkg.sv | 1 + .../sv/jtag_riscv_agent/jtag_riscv_driver.sv | 33 +- .../key_sideload_agent_pkg.sv | 1 + .../key_sideload_agent/key_sideload_driver.sv | 27 +- .../dv/sv/kmac_app_agent/kmac_app_agent.core | 1 + .../sv/kmac_app_agent/kmac_app_agent_pkg.sv | 9 +- .../kmac_app_agent/kmac_app_device_driver.sv | 4 +- .../sv/kmac_app_agent/kmac_app_host_driver.sv | 3 - .../dv/sv/kmac_app_agent/kmac_app_intf.sv | 4 +- .../dv/sv/mem_bkdr_util/mem_bkdr_util.sv | 133 ++- .../dv/sv/mem_bkdr_util/mem_bkdr_util_pkg.sv | 12 + .../mem_bkdr_util_row_adapter.sv | 16 +- .../dv/sv/pattgen_agent/pattgen_agent_pkg.sv | 1 + .../dv/sv/pattgen_agent/pattgen_driver.sv | 13 +- .../sv/push_pull_agent/push_pull_agent_pkg.sv | 1 + .../push_pull_agent/push_pull_driver_lib.sv | 9 +- .../dv/sv/pwm_monitor/pwm_monitor_pkg.sv | 1 + .../lowrisc_ip/dv/sv/rng_agent/rng_driver.sv | 4 - .../dv/sv/spi_agent/spi_agent_pkg.sv | 1 + .../dv/sv/spi_agent/spi_device_driver.sv | 14 +- .../lowrisc_ip/dv/sv/spi_agent/spi_driver.sv | 7 - .../dv/sv/spi_agent/spi_host_driver.sv | 20 +- .../dv/sv/tl_agent/dv/env/tl_agent_env_cfg.sv | 2 +- .../dv/sv/tl_agent/seq_lib/tl_device_seq.sv | 8 +- .../lowrisc_ip/dv/sv/tl_agent/tl_agent_pkg.sv | 1 + .../dv/sv/tl_agent/tl_device_driver.sv | 20 +- .../dv/sv/tl_agent/tl_host_driver.sv | 203 +++-- hw/vendor/lowrisc_ip/dv/sv/tl_agent/tl_if.sv | 4 +- .../dv/sv/uart_agent/uart_agent_pkg.sv | 1 + .../dv/sv/uart_agent/uart_driver.sv | 3 +- .../dv/sv/usb20_agent/usb20_agent_pkg.sv | 1 + .../dv/sv/usb20_agent/usb20_device_driver.sv | 4 - .../dv/sv/usb20_agent/usb20_driver.sv | 7 +- .../dv/sv/usb20_agent/usb20_host_driver.sv | 4 - hw/vendor/lowrisc_ip/dv/tools/waves.tcl | 2 +- hw/vendor/lowrisc_ip/dv/tools/z01x/README.md | 2 +- .../lowrisc_ip/ip/entropy_src/dv/README.md | 2 +- .../entropy_src/dv/cov/entropy_src_cov_if.sv | 54 +- .../ip/entropy_src/dv/env/entropy_src_env.sv | 11 + .../entropy_src/dv/env/entropy_src_env_cfg.sv | 17 +- .../entropy_src/dv/env/entropy_src_path_if.sv | 55 +- .../dv/env/entropy_src_scoreboard.sv | 10 +- .../dv/env/seq_lib/entropy_src_base_vseq.sv | 3 +- .../dv/env/seq_lib/entropy_src_err_vseq.sv | 27 - .../lowrisc_ip/ip/entropy_src/dv/tb/tb.sv | 5 +- hw/vendor/lowrisc_ip/ip/i2c/dv/README.md | 4 +- .../lowrisc_ip/ip/i2c/dv/env/i2c_dv_if.sv | 16 - .../lowrisc_ip/ip/i2c/dv/env/i2c_env.core | 1 - hw/vendor/lowrisc_ip/ip/i2c/dv/env/i2c_env.sv | 4 - .../lowrisc_ip/ip/i2c/dv/env/i2c_env_cfg.sv | 5 +- hw/vendor/lowrisc_ip/ip/i2c/dv/tb/tb.sv | 7 - hw/vendor/lowrisc_ip/ip/i2c/rtl/i2c_core.sv | 4 +- .../lowrisc_ip/ip/i2c/rtl/i2c_target_fsm.sv | 4 +- hw/vendor/lowrisc_ip/ip/kmac/README.md | 4 +- hw/vendor/lowrisc_ip/ip/kmac/data/kmac.hjson | 11 +- hw/vendor/lowrisc_ip/ip/kmac/doc/registers.md | 3 +- hw/vendor/lowrisc_ip/ip/kmac/dv/README.md | 4 +- .../lowrisc_ip/ip/kmac/dv/env/kmac_env_cfg.sv | 4 +- hw/vendor/lowrisc_ip/ip/kmac/rtl/kmac.sv | 28 +- hw/vendor/lowrisc_ip/ip/kmac/rtl/kmac_app.sv | 66 +- .../lowrisc_ip/ip/kmac/rtl/kmac_msgfifo.sv | 139 +++- hw/vendor/lowrisc_ip/ip/lc_ctrl/dv/README.md | 4 +- .../ip/lc_ctrl/dv/env/lc_ctrl_env_cfg.sv | 4 +- hw/vendor/lowrisc_ip/ip/prim/README.md | 8 +- hw/vendor/lowrisc_ip/ip/prim/prim.core | 4 + .../ip/prim/rtl/prim_fifo_async_simple.sv | 82 +- .../lowrisc_ip/ip/prim/rtl/prim_flop_x.sv | 59 ++ hw/vendor/lowrisc_ip/ip/prim/rtl/prim_hpc2.sv | 241 ++++++ hw/vendor/lowrisc_ip/ip/prim/rtl/prim_hpc3.sv | 169 ++++ .../ip/prim/rtl/prim_sdc_example.sv | 47 +- .../ip/prim/rtl/prim_sync_reqack.sv | 11 +- .../ip/prim_generic/prim_generic.core | 2 + .../ip/prim_generic/prim_generic_inv.core | 38 + .../ip/prim_generic/rtl/prim_inv.sv | 16 + .../ip/prim_xilinx/prim_xilinx.core | 2 + .../ip/prim_xilinx/prim_xilinx_inv.core | 40 + .../lowrisc_ip/ip/prim_xilinx/rtl/prim_inv.sv | 16 + hw/vendor/lowrisc_ip/ip/rom_ctrl/dv/README.md | 4 +- .../ip/rom_ctrl/dv/env/rom_ctrl_env_cfg.sv | 6 +- hw/vendor/lowrisc_ip/ip/rv_timer/dv/README.md | 4 +- .../ip/rv_timer/dv/env/rv_timer_env_cfg.sv | 4 +- .../lowrisc_ip/ip/spi_device/dv/README.md | 4 +- .../spi_device/dv/env/spi_device_env_cfg.sv | 4 +- hw/vendor/lowrisc_ip/ip/spi_host/dv/README.md | 4 +- .../ip/spi_host/dv/env/spi_host_env_cfg.sv | 4 +- hw/vendor/lowrisc_ip/ip/tlul/doc/dv/README.md | 4 +- .../ip/tlul/generic_dv/env/xbar_env_cfg.sv | 2 +- .../lowrisc_ip/ip/tlul/rtl/tlul_assert.sv | 112 ++- hw/vendor/lowrisc_ip/ip/uart/dv/README.md | 4 +- .../lowrisc_ip/ip/uart/dv/env/uart_env_cfg.sv | 4 +- .../ip_templates/alert_handler/dv/README.md | 4 +- .../dv/env/alert_handler_env_cfg.sv.tpl | 4 +- .../alert_handler_entropy_stress_vseq.sv.tpl | 1 + .../ip_templates/clkmgr/dv/README.md.tpl | 4 +- .../clkmgr/dv/env/clkmgr_env_cfg.sv.tpl | 4 +- .../dv/env/seq_lib/clkmgr_regwen_vseq.sv.tpl | 8 +- .../ip_templates/gpio/dv/README.md.tpl | 4 +- .../gpio/dv/env/gpio_env_cfg.sv.tpl | 4 +- .../ip_templates/pwrmgr/dv/README.md.tpl | 4 +- .../pwrmgr/dv/env/pwrmgr_env_cfg.sv | 4 +- .../env/seq_lib/pwrmgr_reset_invalid_vseq.sv | 1 - .../ip_templates/rstmgr/dv/README.md.tpl | 4 +- .../rstmgr/dv/env/rstmgr_env_cfg.sv.tpl | 4 +- .../rstmgr/dv/env/rstmgr_if.sv.tpl | 2 +- .../dv/sva/rstmgr_cascading_sva_if.sv.tpl | 12 +- .../dv/sva/rstmgr_rst_en_track_sva_if.sv.tpl | 2 +- .../ip_templates/rstmgr/dv/tb.sv.tpl | 6 +- .../ip_templates/rstmgr/rtl/rstmgr_ctrl.sv | 2 +- .../rv_plic/fpv/vip/rv_plic_assert_fpv.sv.tpl | 10 + .../ip_templates/rv_plic/rtl/rv_plic.sv.tpl | 4 - .../rv_plic/rtl/rv_plic_gateway.sv.tpl | 74 +- hw/vendor/lowrisc_ip/lint/README.md | 4 +- .../lowrisc_ip/util/design/check-netlist.py | 2 +- .../lowrisc_ip/util/reggen/fpv_csr.sv.tpl | 13 +- .../lowrisc_ip/util/reggen/gen_cheader.py | 108 ++- .../lowrisc_ip/util/reggen/reg_top.sv.tpl | 14 +- hw/vendor/lowrisc_ip/util/topgen/README.md | 2 +- .../lowrisc_ip/util/topgen/intermodule.py | 225 +++-- .../util/topgen/templates/alert_test.c.tpl | 2 +- .../toplevel_interrupt_assignments.tpl | 26 - .../toplevel_snippets/alert_handler_lpg.tpl | 95 +++ .../alert_handler_signals.tpl | 40 + .../toplevel_snippets/cio_assigns.tpl | 68 ++ .../toplevel_snippets/cio_signals.tpl | 31 + .../toplevel_snippets/header_parameters.tpl | 42 + .../toplevel_snippets/info_dicts.tpl | 38 + .../toplevel_snippets/intermodule_signals.tpl | 68 ++ .../toplevel_snippets/interrupt_assigns.tpl | 48 ++ .../interrupt_signals.tpl} | 3 +- .../toplevel_snippets/localparams.tpl | 32 + .../module_instantiations.tpl | 160 ++++ .../port_intermodule_signals.tpl | 17 + .../port_special_signals.tpl | 89 ++ .../racl_parameters.tpl} | 0 .../racl_signals.tpl} | 8 +- .../toplevel_snippets/xbar_instantiations.tpl | 32 + hw/vendor/lowrisc_ip/util/topgen/validate.py | 86 +- 198 files changed, 4024 insertions(+), 1741 deletions(-) create mode 100644 hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_base_seq.sv create mode 100644 hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_hw_reset_seq.sv create mode 100644 hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_agent.core rename hw/vendor/lowrisc_ip/dv/sv/{dv_lib => dv_base_agent}/dv_base_agent.sv (97%) rename hw/vendor/lowrisc_ip/dv/sv/{dv_lib => dv_base_agent}/dv_base_agent_cfg.sv (100%) rename hw/vendor/lowrisc_ip/dv/sv/{dv_lib => dv_base_agent}/dv_base_agent_cov.sv (100%) create mode 100644 hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_agent_pkg.sv create mode 100644 hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_driver.sv rename hw/vendor/lowrisc_ip/dv/sv/{dv_lib => dv_base_agent}/dv_base_monitor.sv (100%) rename hw/vendor/lowrisc_ip/dv/sv/{dv_lib => dv_base_agent}/dv_base_seq.sv (100%) rename hw/vendor/lowrisc_ip/dv/sv/{dv_lib => dv_base_agent}/dv_base_sequencer.sv (100%) delete mode 100644 hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_driver.sv delete mode 100644 hw/vendor/lowrisc_ip/ip/i2c/dv/env/i2c_dv_if.sv create mode 100644 hw/vendor/lowrisc_ip/ip/prim/rtl/prim_flop_x.sv create mode 100644 hw/vendor/lowrisc_ip/ip/prim/rtl/prim_hpc2.sv create mode 100644 hw/vendor/lowrisc_ip/ip/prim/rtl/prim_hpc3.sv create mode 100644 hw/vendor/lowrisc_ip/ip/prim_generic/prim_generic_inv.core create mode 100644 hw/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_inv.sv create mode 100644 hw/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_inv.core create mode 100644 hw/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_inv.sv delete mode 100644 hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_interrupt_assignments.tpl create mode 100644 hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/alert_handler_lpg.tpl create mode 100644 hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/alert_handler_signals.tpl create mode 100644 hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/cio_assigns.tpl create mode 100644 hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/cio_signals.tpl create mode 100644 hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/header_parameters.tpl create mode 100644 hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/info_dicts.tpl create mode 100644 hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/intermodule_signals.tpl create mode 100644 hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/interrupt_assigns.tpl rename hw/vendor/lowrisc_ip/util/topgen/templates/{toplevel_interrupts.tpl => toplevel_snippets/interrupt_signals.tpl} (94%) create mode 100644 hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/localparams.tpl create mode 100644 hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/module_instantiations.tpl create mode 100644 hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/port_intermodule_signals.tpl create mode 100644 hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/port_special_signals.tpl rename hw/vendor/lowrisc_ip/util/topgen/templates/{toplevel_racl_parameters.tpl => toplevel_snippets/racl_parameters.tpl} (100%) rename hw/vendor/lowrisc_ip/util/topgen/templates/{toplevel_racl_signals.tpl => toplevel_snippets/racl_signals.tpl} (80%) create mode 100644 hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/xbar_instantiations.tpl diff --git a/hw/vendor/lowrisc_ip.lock.hjson b/hw/vendor/lowrisc_ip.lock.hjson index 83424efa2..792b11383 100644 --- a/hw/vendor/lowrisc_ip.lock.hjson +++ b/hw/vendor/lowrisc_ip.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/lowRISC/opentitan - rev: d96fc2abd7b3c547f8a31ac4cb5a0bac645a7d1f + rev: bf4a2b24e41742151cfce9c4041e959a3ba76ca3 } } diff --git a/hw/vendor/lowrisc_ip/dv/dpi/gpiodpi/gpiodpi.c b/hw/vendor/lowrisc_ip/dv/dpi/gpiodpi/gpiodpi.c index 0da60e765..52dd297df 100644 --- a/hw/vendor/lowrisc_ip/dv/dpi/gpiodpi/gpiodpi.c +++ b/hw/vendor/lowrisc_ip/dv/dpi/gpiodpi/gpiodpi.c @@ -240,9 +240,9 @@ uint32_t gpiodpi_host_to_device_tick(void *ctx_void, svBitVecVal *gpio_oe, ++gpio_text; int idx = parse_dec(&gpio_text); if (idx < NUM_GPIO) { - if (!GET_BIT(gpio_oe[0], idx)) { + if (GET_BIT(gpio_oe[0], idx)) { fprintf(stderr, - "GPIO: Host tried to pull disabled pin low: pin %2d\n", + "GPIO: Host tried to pull output pin low: pin %2d\n", idx); } CLR_BIT(ctx->driven_pin_values, idx); @@ -260,9 +260,9 @@ uint32_t gpiodpi_host_to_device_tick(void *ctx_void, svBitVecVal *gpio_oe, ++gpio_text; int idx = parse_dec(&gpio_text); if (idx < NUM_GPIO) { - if (!GET_BIT(gpio_oe[0], idx)) { + if (GET_BIT(gpio_oe[0], idx)) { fprintf(stderr, - "GPIO: Host tried to pull disabled pin high: pin %2d\n", + "GPIO: Host tried to pull output pin high: pin %2d\n", idx); } SET_BIT(ctx->driven_pin_values, idx); diff --git a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_base_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_base_driver.sv index e47c26be5..3cb75b804 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_base_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_base_driver.sv @@ -5,10 +5,8 @@ // Virtual base class used for alert_sender_driver and alert_receiver_driver virtual class alert_base_driver extends dv_base_driver#(alert_esc_seq_item, alert_esc_agent_cfg); - alert_esc_seq_item r_alert_ping_send_q[$]; - alert_esc_seq_item r_alert_rsp_q[$]; - alert_esc_seq_item s_alert_send_q[$]; - alert_esc_seq_item s_alert_ping_rsp_q[$]; + protected uvm_tlm_analysis_fifo #(alert_esc_seq_item) m_sender_requests; + protected uvm_tlm_analysis_fifo #(alert_esc_seq_item) m_receiver_requests; extern function new (string name, uvm_component parent); @@ -28,6 +26,8 @@ endclass function alert_base_driver::new (string name, uvm_component parent); super.new(name, parent); + m_sender_requests = new("m_sender_requests", this); + m_receiver_requests = new("m_receiver_requests", this); endfunction : new task alert_base_driver::get_and_drive(); @@ -45,11 +45,9 @@ task alert_base_driver::get_req(); `downcast(req_clone, req.clone()); req_clone.set_id_info(req); // receiver mode - if (req.r_alert_ping_send) r_alert_ping_send_q.push_back(req_clone); - if (req.r_alert_rsp) r_alert_rsp_q.push_back(req_clone); + if (req.r_alert_ping_send || req.r_alert_rsp) m_receiver_requests.write(req_clone); // sender mode - if (req.s_alert_send) s_alert_send_q.push_back(req_clone); - if (req.s_alert_ping_rsp) s_alert_ping_rsp_q.push_back(req_clone); + if (req.s_alert_send || req.s_alert_ping_rsp) m_sender_requests.write(req_clone); if (req.r_esc_rsp) begin `uvm_error(get_full_name(), "Alert driver cannot drive an esc item") diff --git a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_esc_agent_cfg.sv b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_esc_agent_cfg.sv index 6fa424fba..aed7e5cb5 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_esc_agent_cfg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_esc_agent_cfg.sv @@ -53,9 +53,12 @@ class alert_esc_agent_cfg extends dv_base_agent_cfg; int unsigned ack_stable_min = 0; int unsigned ack_stable_max = 10; - bit use_seq_item_ping_delay = 1'b1; - int unsigned ping_delay_min = 0; - int unsigned ping_delay_max = 10; + // The minimum and maximum value that alert_receiver_ping_seq will use for ping_delay + // + // To enable a "stress test", which sends lots of back-to-back ping items, these can be made + // small. + int unsigned ping_delay_min = 10000; + int unsigned ping_delay_max = 20000; // When this bit is set, alert agent responds to alert without delay // This is set by plusarg "+fast_rcvr_{alert_name}" @@ -78,7 +81,6 @@ class alert_esc_agent_cfg extends dv_base_agent_cfg; `uvm_field_int(ack_delay_max, UVM_DEFAULT) `uvm_field_int(ack_stable_min, UVM_DEFAULT) `uvm_field_int(ack_stable_max, UVM_DEFAULT) - `uvm_field_int(ping_delay_min, UVM_DEFAULT) `uvm_field_int(ping_delay_max, UVM_DEFAULT) `uvm_object_utils_end diff --git a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_esc_agent_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_esc_agent_pkg.sv index 6badc8ff2..9d179b97b 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_esc_agent_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_esc_agent_pkg.sv @@ -5,6 +5,7 @@ package alert_esc_agent_pkg; // dep packages import uvm_pkg::*; + import dv_base_agent_pkg::*; import dv_lib_pkg::*; import dv_utils_pkg::*; import prim_alert_pkg::*; @@ -44,13 +45,6 @@ package alert_esc_agent_pkg; EscRespPing1 } esc_handshake_e; - typedef enum bit [1:0] { - NoAlertBeforeAfterIntFail = 'b00, - HasAlertBeforeIntFailOnly = 'b01, - HasAlertAfterIntFailOnly = 'b10, - HasAlertBeforeAfterIntFail = 'b11 - } alert_sig_int_err_e; - // macro includes `include "uvm_macros.svh" `include "dv_macros.svh" diff --git a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_esc_if.sv b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_esc_if.sv index bc809a5a5..df90e7774 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_esc_if.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_esc_if.sv @@ -183,6 +183,16 @@ interface alert_esc_if(input clk, input rst_n); end while (cycle_cnt > 1 || rst_n != 1'b1); endtask : wait_esc_ping + // Set the alert pins to the requested value (either 1;0 or 0;1) when the interface is active and + // configured to act as the alert sender. + // + // This uses a clocking drive to update the version of the signal in sender_cb (causing the update + // to have a lasting effect, and also to be synchronised with the next clock edge). + task automatic force_alert(bit alert_p, bit alert_n); + sender_cb.alert_tx_int.alert_p <= alert_p; + sender_cb.alert_tx_int.alert_n <= alert_n; + endtask + // Return true if the current state is PingSt // // This rather trivial function is needed because we want to use the interface through a virtual diff --git a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_esc_seq_item.sv b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_esc_seq_item.sv index 31c26f556..46fb92057 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_esc_seq_item.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_esc_seq_item.sv @@ -17,7 +17,6 @@ class alert_esc_seq_item extends uvm_sequence_item; rand bit int_err; rand bit standalone_int_err; rand bit ping_timeout; - rand alert_sig_int_err_e alert_int_err_type; // for monitor only rand alert_esc_trans_type_e alert_esc_type; @@ -25,19 +24,28 @@ class alert_esc_seq_item extends uvm_sequence_item; rand esc_handshake_e esc_handshake_sta; rand int sig_cycle_cnt; - // delays + // A delay injected by alert_receiver_driver before it actually sends a ping request. This allows + // the driver to be sent a stream of back-to-back items without locking up the interface. rand int unsigned ping_delay; + + // Other delays rand int unsigned ack_delay; rand int unsigned ack_stable; rand int unsigned alert_delay; rand int unsigned int_err_cyc; extern constraint delay_c; + + // An upper bound on ping_delay. This isn't really for a design reason but, instead, is to make + // sure that we do occasionally send pings. + // + // This is a soft constraint, so a sequence that uses these items can safely request an enormous + // delay. + extern constraint ping_delay_max_c; + // if agent is alert mode, cannot send any esc_rsp signal // if agent is esc mode, cannot send any alert related signals extern constraint alert_esc_mode_c; - // TODO: temp constraint, will support soon - extern constraint sig_int_err_c; `uvm_object_utils_begin(alert_esc_seq_item) `uvm_field_int (s_alert_send, UVM_DEFAULT) @@ -54,7 +62,6 @@ class alert_esc_seq_item extends uvm_sequence_item; `uvm_field_int (alert_delay, UVM_DEFAULT) `uvm_field_int (int_err_cyc, UVM_DEFAULT) `uvm_field_int (sig_cycle_cnt, UVM_DEFAULT) - `uvm_field_enum(alert_sig_int_err_e, alert_int_err_type, UVM_DEFAULT) `uvm_field_enum(alert_esc_trans_type_e, alert_esc_type, UVM_DEFAULT) `uvm_field_enum(alert_handshake_e, alert_handshake_sta, UVM_DEFAULT) `uvm_field_enum(esc_handshake_e, esc_handshake_sta, UVM_DEFAULT) @@ -65,22 +72,21 @@ class alert_esc_seq_item extends uvm_sequence_item; endclass : alert_esc_seq_item constraint alert_esc_seq_item::delay_c { - soft ping_delay dist {0 :/ 5, [1:10] :/ 5}; soft ack_delay dist {0 :/ 5, [1:10] :/ 5}; soft alert_delay dist {0 :/ 5, [1:10] :/ 5}; soft ack_stable dist {1 :/ 5, [2:10] :/ 5}; soft int_err_cyc dist {1 :/ 5, [2:10] :/ 5}; } +constraint alert_esc_seq_item::ping_delay_max_c { + soft ping_delay <= 50000; +} + constraint alert_esc_seq_item::alert_esc_mode_c { r_esc_rsp == 1 -> (!s_alert_send && !r_alert_rsp && !r_alert_ping_send && !s_alert_ping_rsp); (s_alert_send || r_alert_rsp || r_alert_ping_send || s_alert_ping_rsp) -> !r_esc_rsp; } -constraint alert_esc_seq_item::sig_int_err_c { - alert_int_err_type == NoAlertBeforeAfterIntFail; -} - function alert_esc_seq_item::new (string name = ""); super.new(name); endfunction : new diff --git a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_receiver_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_receiver_driver.sv index 420727e76..6f4351610 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_receiver_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_receiver_driver.sv @@ -2,48 +2,129 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -// A driver that receives alerts. This is used in alert_esc_agent when configured in "device mode" -// (so the dut is a device and the agent is expecting to receive alerts and send occasional pings) +// A driver that behaves as an alert_receiver. This is used in alert_esc_agent when configured in +// "device mode" + class alert_receiver_driver extends alert_base_driver; `uvm_component_utils(alert_receiver_driver) - bit working_on_alert; + // A pair of ids that can be used as a key for a sequence item. We need the sequence ID as well as + // the transaction ID so that we can distinguish items at the same position in different + // sequences. The types are chosen to match UVM's get_transaction_id and get_sequence_id. + typedef struct packed { + int sequence_id; + integer transaction_id; + } id_pair_t; + + // The drive_req_between_resets task will consume requests from m_receiver_requests and add these + // requests to this pair of FIFOs (to be consumed by the send_pings and send_alert_rsps tasks that + // it spawns). + // + // When reset is asserted, both of those tasks will exit after flushing their respective queues. + local uvm_tlm_analysis_fifo #(alert_esc_seq_item) m_pending_pings; + local uvm_tlm_analysis_fifo #(alert_esc_seq_item) m_pending_alert_rsps; + + // A map from item transaction ID to the tasks that are pending for that item. If bit 0 is set, + // the item represents an alert that must be responded to. If bit 1 is set, the item represents a + // ping request. + // + // When the send_pings or send_alert_rsps task clears the final bit for an item, it should remove + // the item from this map. Because the base driver uses get (instead of get_next_item), we don't + // also have to call seq_item_port.item_done to tell the sequencer that the item has been fully + // driven, but we *do* send a response (by sending the original item), to allow the sequence to + // see that the item is done. + // + // When reset is asserted, both of those tasks will exit, clearing this map. + local bit [1:0] m_transaction_tasks[id_pair_t]; + + // When a ping gets an alert response or a genuine alert is sent, this driver needs to acknowledge + // the alert, but the two options need to be handled serially. The ack is handled by ack_alert, + // which uses this semaphore as a mutex. + local semaphore m_ack_semaphore; extern function new(string name, uvm_component parent); + // Clear interface signals because reset has been asserted + // + // This implements a task in dv_base_driver + extern task on_enter_reset(); + + // Drive requests that have been seen by alert_base_driver::get_req. This task runs forever. + // + // This implements a task in alert_base_driver extern task drive_req(); - extern task reset_signals(); - extern task alert_init_thread(); - extern task send_ping(alert_esc_seq_item req); - // Handle a sequence item that demands an alert response (and was thus put in r_alert_rsp_q). + // Take items from m_receiver_requests and (depending on the type of the item) add them to + // m_pending_pings and m_pending_alert_rsps. + // + // Exits immediately on reset. + extern local task consume_requests_betwen_resets(); + + // Drive requests that have been seen by alert_base_driver::get_req, until the next reset. This is + // called by drive_req. + extern local task drive_req_between_resets(); + + // Clear the appropriate bit in m_transaction_tasks for the ID pair of item. If the resulting + // bitmap is zero, delete the entry from m_transaction_tasks. + extern local function void report_done(bit is_ping, alert_esc_seq_item item); + + // Drive any items that were added to m_pending_pings. + // + // Exits early on reset. + extern local task send_pings(); + + // Drive any items that were added to m_pending_alert_rsps. + // + // Exits early on reset. + extern local task send_alert_rsps(); + + // Send a ping described by item. + // + // Exits early on reset. + extern local task send_ping(alert_esc_seq_item item); + + // Handle a sequence item that demands an alert response // // An item should only be added to that queue in response to an alert being generated on the - // interface. We will wait a randomised time (in set_ack_pins) before acknowledging the alert. - extern task rsp_alert(alert_esc_seq_item req); + // interface. We will wait a randomised time (in ack_alert) before acknowledging the alert. + // + // Exits early on reset. + extern local task send_alert_rsp(alert_esc_seq_item item); - // Drive an alert ping + // Wait for a short time to allow an alert to propagate through the clocking blocks in the + // interface. The max_cycles argument is the maximum number of cycles to wait. // - // This will start by waiting between cfg.ping_delay_min and cfg.ping_delay_max cycles before - // sending the ping request. If cfg.use_seq_item_ping_delay is true then the delay is from the - // ping_delay argument. + // The task will stop as soon as any of these events happens: + // + // - The alert_p signal goes high in receiver_cb. + // - There have been max_cycles edges of both clocks. + // - A reset is asserted. + extern local task wait_for_alert_propagation(int unsigned max_cycles); + + // Drive an alert ping // - // Once the ping has gone out, we wait for an alert to arrive and then acknowledge it using - // set_ack_pins (and passing ack_delay and ack_stable). + // This will start by waiting ping_delay cycles before sending the ping request. Once the ping has + // gone out, we wait for an alert to arrive and then acknowledge it using ack_alert (and + // passing ack_delay and ack_stable). // // The task allows to retract driving the ping. If there's an alert (r_alert_rsp_q.size > 0) // before the 'ping_delay' the ping is aborted and the driver moves to tackle the alert in // 'rsp_alert' task. This is notified by setting `item_not_driven=1` // - // This task can be safely killed on a reset. - extern task drive_alert_ping(int unsigned ping_delay, - int unsigned ack_delay, - int unsigned ack_stable, - output bit item_not_driven); + // The task exits early on reset. + extern local task drive_alert_ping(int unsigned ping_delay, + int unsigned ack_delay, + int unsigned ack_stable); - // Acknowledge an alert. + // Acknowledge the next alert + // + // This task waits until an alert is signalled, then waits a short time before acknowledging the + // alert. Once the ack has been asserted, the ack stays high for a time before it, in turn, drops. + // + // This task uses m_ack_semaphore as a mutex (to serialise ping response acks and other alert + // acks). // - // The ack will come after a delay which is normally randomised in the range [cfg.ack_delay_min, + // The delay before the initial ack is normally randomised in the range [cfg.ack_delay_min, // cfg.ack_delay_max] cycles. If cfg.use_seq_item_ack_delay is true then the delay is from the // ack_delay argument. // @@ -54,279 +135,327 @@ class alert_receiver_driver extends alert_base_driver; // Both of these times will be truncated if cfg.fast_rcvr is true. In that case, they will be // cfg.ack_delay_min, cfg.ack_stable_min respectively. // - // This task can be safely killed on a reset. - extern task set_ack_pins(int unsigned ack_delay, - int unsigned ack_stable); - - extern task set_ack(); - extern task reset_ack(); - extern task set_ping(); - extern task wait_alert(); + // The task will exit quickly on reset (replacing the token on the semaphore) + extern local task ack_alert(int unsigned ack_delay, int unsigned ack_stable); + + // Set the ack signal to be the given boolean value (so either 0;1 or 1;0) + extern local task set_ack(bit asserted); + + // Toggle the ping state + extern local task set_ping(); + + // Set the ping state to 0;1 (the reset value) extern task reset_ping(); - extern task do_reset(); + + // Perform the alert init handshake, exiting early on reset extern task do_alert_rx_init(); - // Clears the items in queues `r_alert_rsp_q` and `r_alert_ping_send_q`. - // This gets used in the task `reset_signals` to clear the queues on reset - // This task prevents the scenario of accidentally driving ACK after reset - extern function void clear_item_queues(); - extern task ping_and_alert_thread(); + // Wait for num_cycles positive edges of the slower of the two clocks + // + // Return early on reset. + extern task wait_slower_clock(int unsigned num_cycles); endclass : alert_receiver_driver function alert_receiver_driver::new(string name, uvm_component parent); super.new(name, parent); + m_ack_semaphore = new(1); + m_pending_pings = new("m_pending_pings", this); + m_pending_alert_rsps = new("m_pending_alert_rsps", this); endfunction +task alert_receiver_driver::on_enter_reset(); + // Clear ping and ack signals (both the actual signals and the clocking block values) + cfg.vif.alert_rx_int.ping_p <= 1'b0; + cfg.vif.alert_rx_int.ping_n <= 1'b1; + cfg.vif.alert_rx_int.ack_p <= 1'b0; + cfg.vif.alert_rx_int.ack_n <= 1'b1; + cfg.vif.receiver_cb.alert_rx_int.ping_p <= 1'b0; + cfg.vif.receiver_cb.alert_rx_int.ping_n <= 1'b1; + cfg.vif.receiver_cb.alert_rx_int.ack_p <= 1'b0; + cfg.vif.receiver_cb.alert_rx_int.ack_n <= 1'b1; +endtask + task alert_receiver_driver::drive_req(); - fork - ping_and_alert_thread(); - alert_init_thread(); - join_none -endtask : drive_req - -// Controls whether 'send_ping' or 'rsp_alert' is called depending on the seq_items received -// If ping/alert occur close to each other, there's a chance the driver may believe a ping is -// happening whereas the alert sender is actually sending an alert. -// This situation doesn't affect behavior since the driver would just ack the ping and the -// RTL would believe the ack was for the alert, but the next alert request would be for the ping -// and the handshake would look the same either way. -task alert_receiver_driver::ping_and_alert_thread(); forever begin - wait (((r_alert_ping_send_q.size() > 0) || (r_alert_rsp_q.size() > 0)) && !cfg.in_reset); - `uvm_info(`gfn, $sformatf({"%m - Queues: r_alert_ping_send_q.size=%0d | ", - "r_alert_rsp_q.size()=%0d"}, r_alert_ping_send_q.size, - r_alert_rsp_q.size()), UVM_DEBUG) - - if (r_alert_rsp_q.size() > 0) - rsp_alert(r_alert_rsp_q.pop_front()); - else if (r_alert_ping_send_q.size() > 0) - send_ping(r_alert_ping_send_q.pop_front()); - else begin - `uvm_fatal(`gfn, $sformatf({"%m - no items in r_alert_ping_send_q.size=%0d ", - " nor r_alert_ping_send_q.size=%0d"}, r_alert_ping_send_q.size)) + // Wait until we are out of reset. Until that happens, respond instantly to any sequence items + // that come in. + while (cfg.in_reset) begin + fork : isolation_fork begin + alert_esc_seq_item item; + fork + wait (!cfg.in_reset); + m_receiver_requests.get(item); + join_any + disable fork; + // Since we are in reset, we ignore any item that we see. Because it was fetched by get() in + // alert_base_driver (instead of with get_next_item()), we do not have to declare it done. + end join end + + drive_req_between_resets(); end endtask -task alert_receiver_driver::reset_signals(); - do_reset(); - forever begin - @(negedge cfg.vif.rst_n); - clear_item_queues(); - working_on_alert = 0; - do_reset(); - @(posedge cfg.vif.rst_n); - end +task alert_receiver_driver::consume_requests_betwen_resets(); + fork : isolation_fork begin + fork + wait (cfg.in_reset); + forever begin + alert_esc_seq_item item; + id_pair_t ids; + bit [1:0] jobs; + + m_receiver_requests.get(item); + jobs[0] = item.r_alert_rsp; + jobs[1] = item.r_alert_ping_send; + + if (!jobs) begin + `uvm_fatal(get_full_name(), + $sformatf("Item sent to driver doesn't have any tasks for us: %0s", + item.sprint())) + end + + ids.transaction_id = item.get_transaction_id(); + ids.sequence_id = item.get_sequence_id(); + + if (m_transaction_tasks.exists(ids)) begin + `uvm_fatal(get_full_name(), + $sformatf("Repeated transaction ID: %0d / sequence ID 0x%0x", + ids.transaction_id, ids.sequence_id)) + end + + m_transaction_tasks[ids] = jobs; + if (jobs[1]) m_pending_pings.write(item); + if (jobs[0]) m_pending_alert_rsps.write(item); + end + join_any + disable fork; + end join endtask -task alert_receiver_driver::alert_init_thread(); +task alert_receiver_driver::drive_req_between_resets(); + // Drive the init protocol from the receiver side. do_alert_rx_init will exit early if it sees + // reset. do_alert_rx_init(); - forever @(posedge cfg.vif.rst_n) begin - do_alert_rx_init(); - end -endtask : alert_init_thread + if (cfg.in_reset) return; -task alert_receiver_driver::send_ping(alert_esc_seq_item req); - alert_esc_seq_item rsp; - bit item_not_driven; - `downcast(rsp, req.clone()); - rsp.set_id_info(req); + // Fetch items to drive and drive them. The first task takes items from the m_receiver_requests + // fifo and uses them to populate m_pending_pings and m_pending_alert_rsps. The second two tasks + // take (and drive) items from those two fifos. + // + // All three tasks exit on reset. + fork + consume_requests_betwen_resets(); + send_alert_rsps(); + send_pings(); + join - `uvm_info(`gfn, $sformatf("%m - Item received: \n%0s",req.sprint), UVM_DEBUG) + // As a consistency check, make sure that m_pending_pings, m_pending_alert_rsps and + // m_transaction_tasks were been cleared by send_alert_rsps and send_pings before they exited. + if (m_pending_pings.size()) + `uvm_error(get_full_name(), + $sformatf("m_pending_pings nonempty after reset: %0p", m_pending_pings)) + if (m_pending_alert_rsps.size()) + `uvm_error(get_full_name(), + $sformatf("m_pending_alert_rsps nonempty after reset: %0p", m_pending_alert_rsps)) + if (m_transaction_tasks.size()) + `uvm_error(get_full_name(), + $sformatf("m_transaction_tasks nonempty after reset: %0p", m_transaction_tasks)) - if (!req.int_err) begin - `uvm_info(`gfn, $sformatf({"starting to send receiver item, ping_send=%0b, alert_rsp=%0b, ", - "int_fail=%0b"}, req.r_alert_ping_send, req.r_alert_rsp, - req.int_err), UVM_HIGH) - fork - begin : isolation_fork - fork - begin - while (working_on_alert) begin - `uvm_info(`gfn, $sformatf("%m - Waiting for alert to complete"), UVM_DEBUG) - @(cfg.vif.receiver_cb); - end - drive_alert_ping(req.ping_delay, req.ack_delay, req.ack_stable, item_not_driven); - end - wait (cfg.in_reset); - join_any - disable fork; - end - join - - if (item_not_driven) begin - `uvm_info(`gfn, {"Ping sequence item not driven because there's been an alert with no", - "previous ping - pushing back to its queue"}, UVM_DEBUG) - // Note item is pushed to the front since it was the oldest in the queue - r_alert_ping_send_q.push_front(req); - // A delay is needed to avoid a potential infinite loop if the monitor doesn't have time to sample the next alert - @(cfg.vif.receiver_cb); - return; - end +endtask + +function void alert_receiver_driver::report_done(bit is_ping, alert_esc_seq_item item); + id_pair_t ids; + ids.transaction_id = item.get_transaction_id(); + ids.sequence_id = item.get_sequence_id(); + + if (!m_transaction_tasks.exists(ids)) + `uvm_fatal(get_full_name(), + $sformatf("Cannot check if item is done: %0s", item.sprint())) + + if (!m_transaction_tasks[ids][is_ping]) + `uvm_fatal(get_full_name(), + $sformatf("Cannot clear unset bit %0s for item in m_transaction_tasks: %0s", + is_ping, item.sprint())) + m_transaction_tasks[ids][is_ping] = 0; + + if (~|m_transaction_tasks[ids]) begin + // If we had originally got the item with get_next_item, this would be the right place to call + // item_done. Since we used get instead (allowing alerts and pings to be driven in parallel), we + // just send a response (the original item), which allows the sequence that sent the item to + // know driving it is completed. + m_transaction_tasks.delete(ids); + seq_item_port.put_response(item); end +endfunction - `uvm_info(`gfn, - $sformatf("finished sending receiver item, ping_send=%0b, alert_rsp=%0b, int_fail=%0b", - req.r_alert_ping_send, req.r_alert_rsp, req.int_err), UVM_HIGH) - seq_item_port.put_response(rsp); -endtask : send_ping - -task alert_receiver_driver::rsp_alert(alert_esc_seq_item req); - bit unset_working_on_alerts; - bit exit_delay_fork; - int unsigned num_iter = 7; - alert_esc_seq_item rsp; - unset_working_on_alerts = 0; - `uvm_info(`gfn, $sformatf("%m - Item received: \n%0s",req.sprint), UVM_DEBUG) - // If we get here then something should have been pushed onto the alert queue in response to - // an alert being generated. Wait a short time to allow the alert to propagate through the - // clocking blocks (which should only take a cycle, but give it a couple more to make sure). - // Stop early if we go into reset. - fork - begin : isolation_fork_1 +task alert_receiver_driver::send_pings(); + alert_esc_seq_item item; + + while(!cfg.in_reset) begin + // Clear the item variable (so that we can tell whether the fork below gets an item or sees a + // reset) + item = null; + + fork : isolation_fork begin fork wait (cfg.in_reset); - fork - // Wait for num_iter cycles on the slower of the two clocks (by - // waiting for both of them in parallel). - // 'exit_delay_fork' is used as an escape flag if an alert is detected during the wait - repeat (num_iter) begin - if (cfg.vif.receiver_cb.alert_tx.alert_p || exit_delay_fork) begin - exit_delay_fork = 1; - break; - end - @(cfg.vif.receiver_cb); - end - repeat (num_iter) begin - if (cfg.vif.monitor_cb.alert_tx_final.alert_p || exit_delay_fork) begin - exit_delay_fork = 1; - break; - end - @(cfg.vif.monitor_cb); - end - join + m_pending_pings.get(item); join_any disable fork; - end : isolation_fork_1 - join - - if (!cfg.in_reset) begin - // If we haven't gone into reset, we have an item and have waited a bit for the alert to be - // visible. Check that it really has arrived. - working_on_alert = 1; + end join - `DV_CHECK_FATAL(cfg.vif.receiver_cb.alert_tx.alert_p, - "alert_p not high, despite an item in r_alert_rsp_q") + // If there is an item, send it with send_ping. The task will exit early on reset. + if (item != null) begin + send_ping(item); - `uvm_info(`gfn, $sformatf("rsp_alert item (ping_send=%0b, alert_rsp=%0b, int_fail=%0b)", - req.r_alert_ping_send, req.r_alert_rsp, req.int_err), UVM_DEBUG) + // Now that the item has been sent, report this to the sequencer (if this was the last job to + // do for the item) + report_done(1, item); + end + end - fork - begin : isolation_fork_2 - fork - set_ack_pins(req.ack_delay, req.ack_stable); - wait (cfg.in_reset); - join_any - disable fork; - end : isolation_fork_2 - join - end // if (!cfg.in_reset) + // When we get here, we must be in reset. m_pending_pings might be nonempty (if reset was asserted + // when there were lots of pending pings). Report all the items done (in a trivial way) before + // returning. + while(m_pending_pings.try_get(item)) report_done(1, item); +endtask +task alert_receiver_driver::send_alert_rsps(); + alert_esc_seq_item item; - `uvm_info(`gfn, - $sformatf("%0s rsp_alert item (ping_send=%0b, alert_rsp=%0b, int_fail=%0b)", - cfg.in_reset ? "aborting" : "finished", - req.r_alert_ping_send, req.r_alert_rsp, req.int_err), - UVM_DEBUG) + while (!cfg.in_reset) begin + // Clear the item variable (so that we can tell whether the fork below gets an item or sees a + // reset) + item = null; - fork - begin : isolation_fork_3 + fork : isolation_fork begin fork wait (cfg.in_reset); - repeat (10) begin - if (cfg.vif.receiver_cb.alert_tx.alert_p) begin - unset_working_on_alerts = 1; - break; - end - @(cfg.vif.receiver_cb); - unset_working_on_alerts = 1; - end + m_pending_alert_rsps.get(item); join_any disable fork; - end : isolation_fork_3 - join - if (unset_working_on_alerts) - working_on_alert = 0; + end join - `downcast(rsp, req.clone()); - rsp.set_id_info(req); - seq_item_port.put_response(rsp); -endtask : rsp_alert + // If there is an item, send it with send_alert_rsp. The task will exit early on reset. + if (item != null) begin + send_alert_rsp(item); -task alert_receiver_driver::drive_alert_ping(int unsigned ping_delay, - int unsigned ack_delay, - int unsigned ack_stable, - output bit item_not_driven - ); - item_not_driven = 0; - if (!cfg.use_seq_item_ping_delay) begin - ping_delay = $urandom_range(cfg.ping_delay_max, cfg.ping_delay_min); + // Now that the item has been sent, report this to the sequencer (if this was the last job to + // do for the item) + report_done(0, item); + end end - @(cfg.vif.receiver_cb); - // Ping fail and differential signal fail scenarios are not implemented now. - // This driver is used for IP (instantiate prim_alert_sender) to finish alert handshake. - // The current use-case does not test ping fail and differential signal fail scenarios. - // These scenarios are check in prim_alert direct sequences. - `uvm_info(`gfn, $sformatf("%m - Wait for ping_delay=%0d clock cycles before driving ping", - ping_delay), UVM_DEBUG) + // When we get here, we must be in reset. m_pending_alert_rsps might be nonempty. (This probably + // shouldn't actually be possible, but let's not worry too much about it). Report all the items + // done (in a trivial way) before returning. + while(m_pending_alert_rsps.try_get(item)) report_done(0, item); +endtask - fork - begin : delay_isolation_fork - fork - repeat (ping_delay) @(cfg.vif.receiver_cb); - begin - wait (cfg.vif.receiver_cb.alert_tx.alert_p); - item_not_driven = 1; - end - join_any - disable fork; - end : delay_isolation_fork - join +task alert_receiver_driver::send_ping(alert_esc_seq_item item); + `uvm_info(get_full_name(), "Sending ping", UVM_HIGH) - if (item_not_driven) - return; // Printout added in caller task + if (item.int_err) begin + `uvm_info(get_full_name(), "Not actually sending ping (because int_err is true)", UVM_HIGH) + end else begin + drive_alert_ping(item.ping_delay, item.ack_delay, item.ack_stable); + end +endtask - `uvm_info(`gfn, "Sending ping", UVM_DEBUG) - set_ping(); +task alert_receiver_driver::send_alert_rsp(alert_esc_seq_item item); + `uvm_info(get_full_name(), "Responding to alert", UVM_HIGH) - fork - begin : isolation_fork - fork - begin : ping_timeout - // Finally, hold the driver for handshake_timeout_cycle cycles to give the alert - // sender time to respond to the ping. - repeat (cfg.handshake_timeout_cycle) @(cfg.vif.receiver_cb); - end - begin : wait_ping_handshake - wait_alert(); - `uvm_info(`gfn, "PING: alert has happened, setting ack signals", UVM_DEBUG) - // If we have sent the ping then the alert we have just seen will be a response to it. - // Call the set_ack_pins task to wait a randomised time and then ack the response. If - // we haven't sent the ping yet, immediately finish handling the sequence item - // instead. Another item will be driven through rsp_alert to respond to the alert - // properly. - set_ack_pins(ack_delay, ack_stable); - `uvm_info(`gfn, $sformatf("%m - Ack finished"), UVM_DEBUG) - end - join_any - disable fork; - end - join + // If we get here then something should have been pushed onto the alert queue in response to + // an alert being generated. Wait a short time to allow the alert to propagate through the + // clocking blocks (which should only take a cycle, but give it a couple more to make sure). + // The count of 7 cycles was chosen as an upper bound: an alert should be visible in at most that + // time. + // + // Either way, we stop as soon as the alert propagates through, or if we see a reset. + wait_for_alert_propagation(7); + if (cfg.in_reset) return; + + // Check that the alert really has arrived (which is a consistency check for the testbench, rather + // than a check about the dut). + if (cfg.vif.receiver_cb.alert_tx.alert_p !== 1'b1) begin + `uvm_fatal(get_full_name(), "alert_p not high, despite an item from the monitor") + end + + // Now send an ack with ack_alert. This then waits for the alert to drop, then clears the ack + // again. + // + // The task exits early on reset. + ack_alert(item.ack_delay, item.ack_stable); +endtask + +task alert_receiver_driver::wait_for_alert_propagation(int unsigned max_cycles); + fork : isolation_fork begin + fork + wait (cfg.in_reset); + fork : isolation_fork begin + bit seen_alert; + + fork + repeat (max_cycles) begin + if (cfg.vif.receiver_cb.alert_tx.alert_p) begin + seen_alert = 1; + end + if (seen_alert) break; + @(cfg.vif.receiver_cb); + end + repeat (max_cycles) begin + if (cfg.vif.monitor_cb.alert_tx_final.alert_p) begin + seen_alert = 1; + end + if (seen_alert) break; + @(cfg.vif.monitor_cb); + end + join + end join + join_any + disable fork; + end join +endtask + +task alert_receiver_driver::drive_alert_ping(int unsigned ping_delay, + int unsigned ack_delay, + int unsigned ack_stable); + // Wait for ping_delay cycles (which might be quite a while) before sending the ping. There may be + // other alerts happening in the meantime, but this task doesn't need to worry about them. Exit + // early on reset + fork : isolation_fork begin + fork + wait(cfg.in_reset); + begin + repeat (ping_delay) @(cfg.vif.receiver_cb); + set_ping(); + end + join_any + disable fork; + end join + if (cfg.in_reset) return; + + // After waiting (possibly for a long time), we finally sent a ping. The alert sender should + // respond with an alert, which we ack here, treating it as the ping response. + // + // If the sender decided to send an alert at the same time as we sent the ping then we'll treat + // that alert as a ping response. But the sender will then respond to the ping with an alert that + // we'll treat as a genuine alert: the end result will be that we and the sender agree on the set + // of things that happened (one ping response and one genuine alert). + ack_alert(ack_delay, ack_stable); + + // Before responding to the item, we need to wait for the sender to complete its FSM (so that we + // don't send another ping when it's still sitting in PingHsPhase2, Pause0 or Pause1). The ack + // that we just sent has to be decoded by a prim_diff_decode (u_decode_ack), which will take at + // most 3 posedges of the sender's clock, then we take two more cycles (one in each of Pause0 and + // Pause1), for a total of 5 cycles. + // + // Wait with the slower of vif.clk and vif.async_clk. + wait_slower_clock(5); endtask -task alert_receiver_driver::set_ack_pins(int unsigned ack_delay, - int unsigned ack_stable); +task alert_receiver_driver::ack_alert(int unsigned ack_delay, int unsigned ack_stable); if (!cfg.use_seq_item_ack_delay) begin ack_delay = $urandom_range(cfg.ack_delay_max, cfg.ack_delay_min); end @@ -339,34 +468,60 @@ task alert_receiver_driver::set_ack_pins(int unsigned ack_delay, ack_stable = cfg.ack_stable_min; end - @(cfg.vif.receiver_cb); - repeat (ack_delay) @(cfg.vif.receiver_cb); - set_ack(); - fork - begin : isolation_fork - fork - begin : ack_timeout - repeat (cfg.handshake_timeout_cycle) @(cfg.vif.sender_cb); - end - begin : wait_ack_handshake - while (cfg.vif.receiver_cb.alert_tx.alert_p !== 1'b0) @(cfg.vif.receiver_cb); - repeat (ack_stable) @(cfg.vif.receiver_cb); - reset_ack(); - end - join_any - disable fork; - end : isolation_fork - join -endtask : set_ack_pins + m_ack_semaphore.get(); -task alert_receiver_driver::set_ack(); - cfg.vif.receiver_cb.alert_rx_int.ack_p <= 1'b1; - cfg.vif.receiver_cb.alert_rx_int.ack_n <= 1'b0; + // Wait for the alert to appear (up to cfg.handshake_timeout_cycle cycles) + fork : isolation_fork1 begin + fork + wait(cfg.in_reset); + repeat(cfg.handshake_timeout_cycle) @(cfg.vif.receiver_cb); + wait(cfg.vif.receiver_cb.alert_tx.alert_p); + join_any + disable fork; + end join + + // If there has been a reset or no alert came out, there is nothing more to do. + if (cfg.in_reset || (cfg.vif.receiver_cb.alert_tx.alert_p !== 1'b1)) begin + m_ack_semaphore.put(); + return; + end + + // Now wait a short time and set the ack (dropping out early on reset) + fork : isolation_fork2 begin + fork + wait(cfg.in_reset); + begin + repeat (ack_delay + 1) @(cfg.vif.receiver_cb); + set_ack(1'b1); + end + join_any + disable fork; + end join + if (cfg.in_reset) begin + m_ack_semaphore.put(); + return; + end + + // Finally, wait for the alert to be cleared again (up to cfg.handshake_timeout_cycle cycles) + fork : isolation_fork3 begin + fork + wait(cfg.in_reset); + repeat(cfg.handshake_timeout_cycle) @(cfg.vif.receiver_cb); + begin + wait(!cfg.vif.receiver_cb.alert_tx.alert_p); + repeat (ack_stable) @(cfg.vif.receiver_cb); + set_ack(1'b0); + end + join_any + disable fork; + end join + + m_ack_semaphore.put(); endtask -task alert_receiver_driver::reset_ack(); - cfg.vif.receiver_cb.alert_rx_int.ack_p <= 1'b0; - cfg.vif.receiver_cb.alert_rx_int.ack_n <= 1'b1; +task alert_receiver_driver::set_ack(bit asserted); + cfg.vif.receiver_cb.alert_rx_int.ack_p <= asserted; + cfg.vif.receiver_cb.alert_rx_int.ack_n <= !asserted; endtask task alert_receiver_driver::set_ping(); @@ -374,71 +529,40 @@ task alert_receiver_driver::set_ping(); cfg.vif.receiver_cb.alert_rx_int.ping_n <= !cfg.vif.alert_rx.ping_n; endtask -task alert_receiver_driver::wait_alert(); - while (cfg.vif.receiver_cb.alert_tx.alert_p !== 1'b1) @(cfg.vif.receiver_cb); -endtask : wait_alert - task alert_receiver_driver::reset_ping(); cfg.vif.receiver_cb.alert_rx_int.ping_p <= 1'b0; cfg.vif.receiver_cb.alert_rx_int.ping_n <= 1'b1; endtask -task alert_receiver_driver::do_reset(); - cfg.vif.alert_rx_int.ping_p <= 1'b0; - cfg.vif.alert_rx_int.ping_n <= 1'b1; - cfg.vif.alert_rx_int.ack_p <= 1'b0; - cfg.vif.alert_rx_int.ack_n <= 1'b1; -endtask +task alert_receiver_driver::do_alert_rx_init(); + fork : isolation_fork begin + fork + wait(cfg.in_reset); + begin + repeat ($urandom_range(1, 10)) @(cfg.vif.receiver_cb); + cfg.vif.alert_rx_int.ack_p <= 1'b0; + cfg.vif.alert_rx_int.ack_n <= 1'b0; -function void alert_receiver_driver::clear_item_queues(); - fork - begin - alert_esc_seq_item rsp, req; - int unsigned size; - - // There may be a race condition if we call this task directly on reset - // since it can clear its queues here but then in the next delta it may - // receive a new item - // Wait 4 clock cycles here until clearing to ensure any potential item on - // the edge is still cleared - // The 4 ticks is because the signals are observed via a clocking block - // which looks at a delayed signal by 2 cycles, plus an extra cycle in the - // monitor before sending the alert_rsp item. - repeat (4) - @(cfg.vif.receiver_cb); - - - `uvm_info(`gfn, $sformatf("%m Clearing send and response queues due to reset"), UVM_DEBUG) - `uvm_info(`gfn, $sformatf({"%m - Clearing queues: r_alert_ping_send_q.size=%0d | ", - "r_alert_rsp_q.size()=%0d"}, r_alert_ping_send_q.size, - r_alert_rsp_q.size()), UVM_DEBUG) - size = r_alert_rsp_q.size(); - for(int i=0 ; i < size; i++) begin - req = r_alert_rsp_q.pop_front(); - `downcast(rsp, req.clone()); - rsp.set_id_info(req); - seq_item_port.put_response(rsp); - end + wait (cfg.vif.receiver_cb.alert_tx.alert_p == cfg.vif.receiver_cb.alert_tx.alert_n); + repeat ($urandom_range(1, 10)) @(cfg.vif.receiver_cb); + cfg.vif.alert_rx_int.ack_n <= 1'b1; - size = r_alert_ping_send_q.size(); - for(int i=0 ; i < size; i++) begin - req = r_alert_ping_send_q.pop_front(); - `downcast(rsp, req.clone()); - rsp.set_id_info(req); - seq_item_port.put_response(rsp); + wait (cfg.vif.receiver_cb.alert_tx.alert_p != cfg.vif.receiver_cb.alert_tx.alert_n); end - end // fork begin - join_none -endfunction + join_any + disable fork; + end join +endtask -task alert_receiver_driver::do_alert_rx_init(); - `DV_SPINWAIT_EXIT( - // Drive alert init signal integrity error handshake. - repeat ($urandom_range(1, 10)) @(cfg.vif.receiver_cb); - cfg.vif.alert_rx_int.ack_n <= 1'b0; - wait (cfg.vif.receiver_cb.alert_tx.alert_p == cfg.vif.receiver_cb.alert_tx.alert_n); - repeat ($urandom_range(1, 10)) @(cfg.vif.receiver_cb); - cfg.vif.alert_rx_int.ack_n <= 1'b1; - wait (cfg.vif.receiver_cb.alert_tx.alert_p != cfg.vif.receiver_cb.alert_tx.alert_n);, - wait (cfg.in_reset);) +task alert_receiver_driver::wait_slower_clock(int unsigned num_cycles); + fork : isolation_fork begin + fork + wait(cfg.in_reset); + fork + repeat (num_cycles) @(posedge cfg.vif.clk); + repeat (num_cycles) @(posedge cfg.vif.async_clk); + join + join_any + disable fork; + end join endtask diff --git a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_sender_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_sender_driver.sv index 8c01da092..664c342ca 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_sender_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/alert_sender_driver.sv @@ -10,12 +10,16 @@ class alert_sender_driver extends alert_base_driver; `uvm_component_utils(alert_sender_driver) + // An event that can be triggered (by functions as well as tasks). This is monitored by + // maintain_alert_drive, which will call cfg.vif.force_alert with m_desired_alert_val. + uvm_event m_update_alert_val; + bit [1:0] m_desired_alert_val; + extern function new (string name, uvm_component parent); - // Monitor resets and reset all driven signals when a reset occurs. - // - // An implementation of dv_base_driver::reset_signals. - extern virtual task reset_signals(); + // This function gets called by dv_base_driver::reset_signals when the interface enters reset. + // Clear any alert signal. + extern virtual task on_enter_reset(); // Drive sequence items for alerts and pings that have been retrieved by get_req (and therefore // have started) and have been pushed to the various queues. This also does the alert init @@ -62,8 +66,9 @@ class alert_sender_driver extends alert_base_driver; // Set the alert pins to be (alert_p=1; alert_n=0) if enabled=1 and (alert_p=0; alert_n=1) // otherwise. // - // This task takes zero time (but needs to be a task because it uses non-blocking assignment) - extern local task set_alert(bit enabled); + // Because the alert signals are set through a clocking block (using cfg.vif.force_alert()), this + // works by setting m_desired_alert_val and triggering the m_update_alert_val event. + extern local function void set_alert(bit enabled); // Set the alert pins to 11 or 00 (depending on the high argument). // @@ -84,62 +89,53 @@ class alert_sender_driver extends alert_base_driver; // This task exits early on reset or if cfg.en_alert_lpg is asserted (in which case, the receiver // won't reply to the init) extern local task do_alert_tx_init(); + + // This task runs forever, calling cfg.vif.set_alert() each time the m_update_alert_val event is + // triggered. + extern local task maintain_alert_drive(); endclass : alert_sender_driver function alert_sender_driver::new (string name, uvm_component parent); super.new(name, parent); + m_update_alert_val = new("m_update_alert_val"); endfunction : new -task alert_sender_driver::reset_signals(); +task alert_sender_driver::on_enter_reset(); set_alert(1'b0); - forever begin - wait(!cfg.in_reset); - wait(cfg.in_reset); - set_alert(1'b0); - end endtask task alert_sender_driver::drive_req(); - forever begin - // Wait until we are out of reset. Until that happens, respond instantly to any sequence items - // that come in. - while (cfg.in_reset) begin - fork : isolation_fork begin - alert_esc_seq_item item; - fork - wait (!cfg.in_reset); - begin - wait(s_alert_send_q.size()); - item = s_alert_send_q.pop_front(); - end - begin - wait(s_alert_ping_rsp_q.size()); - item = s_alert_ping_rsp_q.pop_front(); - end - join_any - disable fork; - if (item != null) begin - alert_esc_seq_item rsp; - `downcast(rsp, item.clone()); - rsp.set_id_info(item); - seq_item_port.put_response(rsp); - end - end join - end + fork + maintain_alert_drive(); + forever begin + // Wait until we are out of reset. Until that happens, respond instantly to any sequence items + // that come in. + while (cfg.in_reset) begin + fork : isolation_fork begin + alert_esc_seq_item item; + fork + wait(!cfg.in_reset); + m_sender_requests.get(item); + join_any + disable fork; + if (item != null) seq_item_port.put_response(item); + end join + end - while(!cfg.in_reset) begin - bit en_alert_lpg = cfg.en_alert_lpg; + while(!cfg.in_reset) begin + bit en_alert_lpg = cfg.en_alert_lpg; - // If LPG is not enabled, initialise the alert interface - if (!en_alert_lpg) begin - do_alert_tx_init(); - end + // If LPG is not enabled, initialise the alert interface + if (!en_alert_lpg) begin + do_alert_tx_init(); + end - // Drive any requests that we see. The task will exit on reset or if the LPG flag changes, - // letting us initialise the alert interface (if LPG is disabled) and continue. - drive_reqs_with_lpg_mode(en_alert_lpg); + // Drive any requests that we see. The task will exit on reset or if the LPG flag changes, + // letting us initialise the alert interface (if LPG is disabled) and continue. + drive_reqs_with_lpg_mode(en_alert_lpg); + end end - end + join endtask task alert_sender_driver::drive_reqs_with_lpg_mode(bit en_alert_lpg); @@ -150,30 +146,22 @@ task alert_sender_driver::drive_reqs_with_lpg_mode(bit en_alert_lpg); // Pick an item to drive, but keep track of resets and any change to the LPG flag. fork : isolation_fork begin fork - wait (cfg.en_alert_lpg != en_alert_lpg); - wait (cfg.in_reset); - begin - wait(s_alert_send_q.size()); - item = s_alert_send_q.pop_front(); - is_alert = 1; - end - begin - wait(s_alert_ping_rsp_q.size()); - item = s_alert_ping_rsp_q.pop_front(); - is_ping = 1; - end + wait(cfg.en_alert_lpg != en_alert_lpg); + wait(cfg.in_reset); + m_sender_requests.get(item); join_any disable fork; end join - // Handle the alert or ping response. If there is no item, there has been a reset or the LPG - // flag has changed. Return from the task. - // - // The send_alert and send_ping_rsp tasks both exit early when they see a reset, but ignore any - // further changes to en_alert_lpg. - if (is_alert) send_item(1'b0, item); - else if (is_ping) send_item(1'b1, item); - else return; + // If there is no item, there has been a reset or the LPG flag has changed. Return from the + // task. + if (item == null) return; + + // Handle the alert request or ping response. If the item requests both, send the ping response + // first and then the real alert. + if (item.s_alert_ping_rsp) send_item(1'b1, item); + if (item.s_alert_send) send_item(1'b0, item); + seq_item_port.put_response(item); end endtask @@ -196,7 +184,6 @@ task alert_sender_driver::send_item(bit is_ping_rsp, alert_esc_seq_item item); join_any disable fork; end join - `uvm_info(`gfn, $sformatf("finished sending sender item, alert_send=%0b, ping_rsp=%0b, int_err=%0b", item.s_alert_send, item.s_alert_ping_rsp, item.int_err), UVM_HIGH) @@ -216,13 +203,8 @@ task alert_sender_driver::drive_alert_pins(alert_esc_seq_item req); reset_alert_pins(ack_delay); end else begin // Because req.int_err is true, cause the alert signal integrity check to fail. - if (req.alert_int_err_type & HasAlertBeforeIntFailOnly) set_alert_pins(alert_delay); random_drive_int_fail(req.int_err_cyc); - if (req.alert_int_err_type & HasAlertAfterIntFailOnly) begin - set_alert_pins(alert_delay); - end else begin - set_alert(1'b0); - end + set_alert(1'b0); end // There must be at least two sender clock delays before next alert_handshake @@ -257,10 +239,10 @@ task alert_sender_driver::random_drive_int_fail(int int_err_cyc); end endtask -task alert_sender_driver::set_alert(bit enabled); - cfg.vif.sender_cb.alert_tx_int.alert_p <= enabled; - cfg.vif.sender_cb.alert_tx_int.alert_n <= !enabled; -endtask +function void alert_sender_driver::set_alert(bit enabled); + m_desired_alert_val = {enabled, !enabled}; + m_update_alert_val.trigger(); +endfunction task alert_sender_driver::drive_invalid_alert(bit high); cfg.vif.sender_cb.alert_tx_int.alert_p <= high; @@ -285,3 +267,11 @@ task alert_sender_driver::do_alert_tx_init(); disable fork; end join endtask + +task alert_sender_driver::maintain_alert_drive(); + forever begin + m_update_alert_val.wait_ptrigger(); + cfg.vif.force_alert(m_desired_alert_val[1], m_desired_alert_val[0]); + m_update_alert_val.reset(); + end +endtask diff --git a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/esc_receiver_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/esc_receiver_driver.sv index b0da25fc7..f2d53b974 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/esc_receiver_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/esc_receiver_driver.sv @@ -15,11 +15,6 @@ class esc_receiver_driver extends dv_base_driver#(alert_esc_seq_item, alert_esc_ extern function new (string name, uvm_component parent); - // This task runs forever calls do_reset at the start of every reset. - // - // Overridden from dv_base_driver. - extern virtual task reset_signals(); - // This task runs forever. It works by running rsp_escalator (which consumes and drives items from // seq_item_port) and esc_ping_detector (which responds to ping requests). // @@ -56,7 +51,7 @@ class esc_receiver_driver extends dv_base_driver#(alert_esc_seq_item, alert_esc_ extern virtual task wait_esc_complete(); extern virtual task wait_esc(); // Set the values driven through resp_p / resp_n to 0/1 and clear the is_ping flag - extern virtual task do_reset(); + extern task on_enter_reset(); endclass : esc_receiver_driver @@ -64,15 +59,6 @@ function esc_receiver_driver::new (string name, uvm_component parent); super.new(name, parent); endfunction : new -task esc_receiver_driver::reset_signals(); - do_reset(); - forever begin - wait (cfg.in_reset); - do_reset(); - wait (!cfg.in_reset); - end -endtask : reset_signals - task esc_receiver_driver::get_and_drive(); fork rsp_escalator(); @@ -229,8 +215,8 @@ task esc_receiver_driver::wait_esc(); while (cfg.vif.esc_tx.esc_p === 1'b0 && cfg.vif.esc_tx.esc_n === 1'b1) @(cfg.vif.receiver_cb); endtask : wait_esc -task esc_receiver_driver::do_reset(); +task esc_receiver_driver::on_enter_reset(); cfg.vif.esc_rx_int.resp_p <= 1'b0; cfg.vif.esc_rx_int.resp_n <= 1'b1; is_ping = 0; -endtask : do_reset +endtask : on_enter_reset diff --git a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/esc_sender_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/esc_sender_driver.sv index 2cc19a50d..547dc0340 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/esc_sender_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/esc_sender_driver.sv @@ -8,25 +8,14 @@ class esc_sender_driver extends dv_base_driver#(alert_esc_seq_item, alert_esc_ag `uvm_component_utils(esc_sender_driver) extern function new (string name, uvm_component parent); - extern virtual task reset_signals(); extern virtual task get_and_drive(); - - extern local task reset_esc(); + extern virtual task on_enter_reset(); endclass : esc_sender_driver function esc_sender_driver::new (string name, uvm_component parent); super.new(name, parent); endfunction : new -task esc_sender_driver::reset_signals(); - wait(cfg.vif.rst_n !== 1'b1); - forever begin - reset_esc(); - wait (!cfg.in_reset); - wait (cfg.in_reset); - end -endtask : reset_signals - task esc_sender_driver::get_and_drive(); // LC_CTRL uses virtual interface to directly drive escalation requests. // Other escalation handshakes are checked in prim_esc direct sequence. @@ -34,7 +23,7 @@ task esc_sender_driver::get_and_drive(); wait (!cfg.in_reset); endtask : get_and_drive -task esc_sender_driver::reset_esc(); +task esc_sender_driver::on_enter_reset(); cfg.vif.esc_tx_int.esc_p <= 1'b0; cfg.vif.esc_tx_int.esc_n <= 1'b1; -endtask : reset_esc +endtask diff --git a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/seq_lib/alert_receiver_alert_rsp_seq.sv b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/seq_lib/alert_receiver_alert_rsp_seq.sv index f2ac6d293..433439e2d 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/seq_lib/alert_receiver_alert_rsp_seq.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/seq_lib/alert_receiver_alert_rsp_seq.sv @@ -48,7 +48,7 @@ task alert_receiver_alert_rsp_seq::default_rsp_thread(); wait (req_q.size()); rsp = req_q.pop_front(); start_item(rsp); - `DV_CHECK_RANDOMIZE_WITH_FATAL(req, + `DV_CHECK_RANDOMIZE_WITH_FATAL(rsp, r_alert_ping_send == 0; r_alert_rsp == 1; int_err == 0; diff --git a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/seq_lib/alert_receiver_ping_seq.sv b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/seq_lib/alert_receiver_ping_seq.sv index f83c3b89d..4de48303b 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/seq_lib/alert_receiver_ping_seq.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/alert_esc_agent/seq_lib/alert_receiver_ping_seq.sv @@ -22,12 +22,14 @@ task alert_receiver_ping_seq::body(); forever begin req = alert_esc_seq_item::type_id::create("req"); start_item(req); - // Randomise the item to be a ping request, but with a large ping delay. This means that even - // enqueuing these back to back will leave in big gaps between the ping requests. + // Randomise the item to be a ping request. When driven, the item will "wait around" for + // ping_delay cycles before it actually sends the ping. Bound this to be in the interval + // cfg.ping_delay_min .. cfg.ping_delay_max. `DV_CHECK_RANDOMIZE_WITH_FATAL(req, r_alert_ping_send == 1'b1; r_alert_rsp == 1'b0; - ping_delay dist {[10000:20000] :/ 1};) + cfg.ping_delay_min <= ping_delay; + ping_delay <= cfg.ping_delay_max;) finish_item(req); get_response(req); end diff --git a/hw/vendor/lowrisc_ip/dv/sv/cip_lib/README.md b/hw/vendor/lowrisc_ip/dv/sv/cip_lib/README.md index e757506e3..d62d68335 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/cip_lib/README.md +++ b/hw/vendor/lowrisc_ip/dv/sv/cip_lib/README.md @@ -76,10 +76,10 @@ The following is a list of common features and settings: objection handle of the corresponding CSR field and valued with the expected value. This is the list of CSR fields that are modified when an alert triggers due to TL integrity violation event. The DV user is required to build this list - in the `initialize()` method after `super.initialize(csr_base_addr);` + in the `initialize()` method after `super.initialize();` ```systemverilog -virtual function void initialize(bit [31:0] csr_base_addr = '1); - super.initialize(csr_base_addr); // ral model is created in `super.initialize` +virtual function void initialize(); + super.initialize(); // ral model is created in `super.initialize` tl_intg_alert_fields[ral.a_status_reg.a_field] = value; ``` @@ -384,9 +384,9 @@ from this CIP library class, please follow the steps below: so that creating alert host agents will take the updated `list_of_alerts` variable. For example in `otp_ctrl_env_cfg.sv`: ```systemverilog - virtual function void initialize(bit [31:0] csr_base_addr = '1); + virtual function void initialize(); list_of_alerts = otp_ctrl_env_pkg::LIST_OF_ALERTS; - super.initialize(csr_base_addr); + super.initialize(); ``` * **tb.sv**: Add `DV_ALERT_IF_CONNECT` macro that declares alert interfaces, connect alert interface wirings with DUT, and set alert_if to uvm_config_db. @@ -424,8 +424,8 @@ Refer to section [cip_base_env_cfg](#cip_base_env_cfg) for more information on t The user may update these 2 variables as follows. ```systemverilog class ip_env_cfg extends cip_base_env_cfg #(.RAL_T(ip_reg_block)); - virtual function void initialize(bit [31:0] csr_base_addr = '1); - super.initialize(csr_base_addr); + virtual function void initialize(); + super.initialize(); tl_intg_alert_name = "fatal_fault_err"; // csr / field name may vary in different IPs tl_intg_alert_fields[ral.fault_status.intg_err] = 1; @@ -464,8 +464,8 @@ The countermeasure of shadow CSRs can be fully verified via importing [shadow_re The details of the test sequences are described in the testplan. Users need to assign the status CSR fields to `cfg.shadow_update_err_status_fields` and `cfg.shadow_storage_err_status_fields` for update error and storage error respectively. ```systemverilog class ip_env_cfg extends cip_base_env_cfg #(.RAL_T(ip_reg_block)); - virtual function void initialize(bit [31:0] csr_base_addr = '1); - super.initialize(csr_base_addr); + virtual function void initialize(); + super.initialize(); // csr / field name may vary in different IPs shadow_update_err_status_fields[ral.err_code.invalid_shadow_update] = 1; shadow_storage_err_status_fields[ral.fault_status.shadow] = 1; @@ -550,8 +550,8 @@ package ip_env_pkg; 4. Set alert name for countermeasure if the alert name is different from the default name - “fatal_fault”. ```systemverilog class ip_env_cfg extends cip_base_env_cfg #(.RAL_T(ip_reg_block)); - virtual function void initialize(bit [31:0] csr_base_addr = '1); - super.initialize(csr_base_addr); + virtual function void initialize(); + super.initialize(); sec_cm_alert_name = "fatal_check_error"; ``` diff --git a/hw/vendor/lowrisc_ip/dv/sv/cip_lib/cip_base_env_cfg.sv b/hw/vendor/lowrisc_ip/dv/sv/cip_lib/cip_base_env_cfg.sv index 4b9ab3b16..71b02b130 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/cip_lib/cip_base_env_cfg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/cip_lib/cip_base_env_cfg.sv @@ -130,14 +130,15 @@ class cip_base_env_cfg #(type RAL_T = dv_base_reg_block) extends dv_base_env_cfg `uvm_object_new - virtual function void initialize(bit [BUS_AW-1:0] csr_base_addr = '1); - super.initialize(csr_base_addr); + virtual function void initialize(); + super.initialize(); // Create downstream agent cfg objects. foreach (ral_model_names[i]) begin string ral_name = ral_model_names[i]; m_tl_agent_cfgs[ral_name] = tl_agent_cfg::type_id::create({"m_tl_agent_cfg_", ral_name}); - m_tl_agent_cfgs[ral_name].if_mode = dv_utils_pkg::Host; + m_tl_agent_cfgs[ral_name].is_active = is_active; + m_tl_agent_cfgs[ral_name].if_mode = (is_active ? dv_utils_pkg::Host : dv_utils_pkg::Monitor); // TL host cannot support device same cycle response. Host may drive d_ready=0 when a_valid=1. m_tl_agent_cfgs[ral_name].host_can_stall_rsp_when_a_valid_high = $urandom_range(0, 1); @@ -161,11 +162,13 @@ class cip_base_env_cfg #(type RAL_T = dv_base_reg_block) extends dv_base_env_cfg string alert_name = list_of_alerts[i]; m_alert_agent_cfgs[alert_name] = alert_esc_agent_cfg::type_id::create( $sformatf("m_alert_agent_cfgs[%s]", alert_name)); - `DV_CHECK_RANDOMIZE_FATAL(m_alert_agent_cfgs[alert_name]) - m_alert_agent_cfgs[alert_name].if_mode = dv_utils_pkg::Device; + m_alert_agent_cfgs[alert_name].is_active = is_active; + m_alert_agent_cfgs[alert_name].if_mode = (is_active ? + dv_utils_pkg::Device : dv_utils_pkg::Monitor); m_alert_agent_cfgs[alert_name].is_async = 1; // default async_on, can override this m_alert_agent_cfgs[alert_name].en_ping_cov = 0; m_alert_agent_cfgs[alert_name].en_lpg_cov = 0; + `DV_CHECK_RANDOMIZE_FATAL(m_alert_agent_cfgs[alert_name]) end end diff --git a/hw/vendor/lowrisc_ip/dv/sv/cip_lib/seq_lib/cip_base_vseq.sv b/hw/vendor/lowrisc_ip/dv/sv/cip_lib/seq_lib/cip_base_vseq.sv index 1e36cfd17..339883b31 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/cip_lib/seq_lib/cip_base_vseq.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/cip_lib/seq_lib/cip_base_vseq.sv @@ -304,10 +304,21 @@ class cip_base_vseq #( // alert_name The name of the alert to wait for. // // max_wait_cycle After any pending ping operation has completed, this gives the number of - // cycles to wait until the alert. By default it is 7, which gives one extra - // cycle longer than the gap we expect between continuously triggered alerts. - // That gap is 6 cycles: 2-3 cycles for a CDC, 2 for pauses and 1 for the idle - // state. + // cycles to wait until the alert. By default it is 7, which matches the minimum + // gap we expect between the ack signal dropping and the alert signal being + // asserted again if an alert is continuously triggered. + // + // The "ack drops" to "alert asserted" path is as follows: + // + // - ack_p in the interface drops + // + // - This is decoded in the sender (through prim_diff_decode), which takes up + // to three posedges in the sender's clock. + // + // - Four cycles in the sender: final cycle in the handshake state; two pause + // cycles; single cycle in the idle state. + // + // - The sender asserts alert_p as it moves into AlertHsPhase1. // // wait_complete If this is true, the task waits for the alert to be acked before exiting. extern protected task wait_alert_trigger(string alert_name, @@ -909,7 +920,7 @@ task cip_base_vseq::check_not_fatal_alert(string alert_name, alert_esc_agent_cfg // ignore it (but print a debug message). If ping_count is unchanged, the alert fired // when we didn't expect it to. if (alert_cfg.ping_count == ping_count) - `uvm_error("Alert %0s fired unexpectedly.", alert_name) + `uvm_error(`gfn, $sformatf("Alert %0s fired unexpectedly.", alert_name)) else `uvm_info(`gfn, $sformatf("Unexpected alert %0s, but this may have a ping response.", @@ -1016,19 +1027,58 @@ endtask task cip_base_vseq::wait_alert_trigger(string alert_name, int max_wait_cycle = 7, bit wait_complete = 0); - // wait until ping finishes before the dv_spinwait in case - // m_alert_agent_cfgs[alert_name].vif.is_alert_handshaking is true due to a ping - wait_until_ping_is_finished(cfg.m_alert_agent_cfgs[alert_name]); - `DV_SPINWAIT_EXIT(while (!cfg.m_alert_agent_cfgs[alert_name].vif.is_alert_handshaking) begin - cfg.clk_rst_vif.wait_clks(1); - wait_until_ping_is_finished(cfg.m_alert_agent_cfgs[alert_name]); - end, - // another thread to wait for given cycles. If timeout, report an error. - cfg.clk_rst_vif.wait_clks(max_wait_cycle); - `uvm_error(`gfn, $sformatf("expect alert:%0s to fire", alert_name))) + alert_esc_agent_cfg agent_cfg = cfg.m_alert_agent_cfgs[alert_name]; + virtual alert_esc_if alert_vif = agent_cfg.vif; + + // In case there is a ping in flight when we arrive, wait for the ping to clear. + wait_until_ping_is_finished(agent_cfg); + + fork : isolation_fork begin + fork + // Stop early on reset + cfg.clk_rst_vif.wait_for_reset(.wait_negedge(1), .wait_posedge(0)); + + // The timer thread (wait for max_wait_cycle cycles, then generate an error). To avoid a race + // if the alert is asserted on the positive edge of the clock after exactly that number of + // cycles, the timer waits for the following negative edge. + begin + repeat (max_wait_cycle) @(posedge alert_vif.clk); + @(negedge alert_vif.clk); + `uvm_error(get_name(), + $sformatf("Expected alert (%0s) did not fire in %0d cycles.", + alert_name, max_wait_cycle)) + end + + // Wait to see an alert come out. This happens if is_alert_handshaking becomes true + // when there is no active_ping. + forever begin + wait(alert_vif.is_alert_handshaking); + if (!alert_vif.in_ping_st()) break; + // If we get here, we were in the middle of a ping. Wait for it to complete and then wait + // for another handshake. + wait_until_ping_is_finished(agent_cfg); + end + join_any + disable fork; + end join + if (wait_complete) begin - `DV_SPINWAIT(cfg.m_alert_agent_cfgs[alert_name].vif.wait_ack_complete();, - $sformatf("timeout wait for alert handshake:%0s", alert_name)) + // Wait for the ack to be asserted and then cleared again. The wait_ack_complete task ends as + // soon as the ack signal drops. Wait until the next clock edge so that we end on the first + // clock edge where the dropped ack signal is seen. + fork : ack_isolation_fork begin + fork + begin + alert_vif.wait_ack_complete(); + @(posedge alert_vif.clk); + end + begin + #(default_spinwait_timeout_ns * 1ns); + `uvm_error(get_name(), {"Timeout waiting for end of ack for alert ", alert_name}) + end + join_any + disable fork; + end join end endtask diff --git a/hw/vendor/lowrisc_ip/dv/sv/csr_utils/README.md b/hw/vendor/lowrisc_ip/dv/sv/csr_utils/README.md index 24c937b17..959215bd4 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/csr_utils/README.md +++ b/hw/vendor/lowrisc_ip/dv/sv/csr_utils/README.md @@ -56,9 +56,9 @@ task is primarily implemented to use after reset, to make sure all the CSRs are being reset to the default value. ##### Under_reset -Due to `csr_utils_pkg` is not connected to any interface, methods inside -this package are not able to get reset information. Current the `under_reset` -bit is declared with two functions: +Because `csr_utils_pkg` is not connected to any interface, methods inside +this package are not able to get reset information. The `under_reset` +bit can be kept up to date with two functions: ```systemverilog function automatic void reset_asserted(); under_reset = 1; @@ -68,9 +68,10 @@ function automatic void reset_deasserted(); under_reset = 0; endfunction ``` -This reset information is updated in `dv_lib/dv_base_vseq.sv`. When the -`apply_reset` task is triggered, it will set and reset the `under_reset` bit -via the functions above. +This reset information is tracked by `dv_base_scoreboard` (using its +`monitor_reset` task). When that task sees a reset, it calls `reset_asserted` or +`reset_deasserted` in its environment config. That function, in turn, calls the +`csr_utils_pkg` function. #### Global CSR util methods ##### Global methods for CSR and MEM attributes diff --git a/hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_base_seq.sv b/hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_base_seq.sv new file mode 100644 index 000000000..bac7af0c8 --- /dev/null +++ b/hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_base_seq.sv @@ -0,0 +1,306 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// The base class for CSR sequences, deriving from uvm_reg_sequence +// +// To use this sequence, create the object and then populate models, external_checker, and +// num_test_csrs. Run the sequence by calling the start() task. +// +// Any subclass of this sequence performs tests across a set of registers in the design. The +// complete list of available registers is computed just before the sequence body (in the pre_start +// task), but a test may wish to check a smaller subset of these registers. +// +// To make that possible, there are two plusarg-based mechanisms: +// +// +num_test_csrs= +// +// If num_test_csrs is a positive number, the list of CSRs in all_csrs is divided into +// contiguous chunks of that length and then the sequence operates on some randomly chosen chunk +// from that list. +// +// If max_num_test_csrs has been set to a positive number after creating the sequence, it is +// used as another upper bound on the number of CSRs in a chunk for the sequence. +// +// +num_csr_chunks=, +test_csr_chunk= +// +// If num_test_csrs is not provided, the list of CSRs in all_csrs can instead be divided into a +// requested number of contiguous chunks by setting num_csr_chunks. The index of the chunk to +// test is then provided with test_csr_chunk. +// +// It is an error to use these flags if max_num_test_csrs is set to a positive number (because +// there's not a nice description of the length of chunks in that situation). + +class csr_base_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); + `uvm_object_utils(csr_base_seq) + + // A queue of register models (UVM register blocks), whose registers will be added to the lists of + // CSRs (all_csrs and test_csrs) in pre_start. + dv_base_reg_block models[$]; + + // A flag that is true if there is some external checker (scoreboard). + // + // If it is false then each register write is followed by a call to that register's predict + // function in order to update the mirrored value. Similarly, reads are checked against the + // register's mirrored value (using the by passing a true "compare" argument to the csr_rd_check + // task). + // + // If the flag is true, the sequence doesn't do predict and compare, instead leaving that to the + // scoreboard. + // + // In either case, the prediction and comparison happen as part of the register write/read, which + // means that this sequence can do completely non-blocking writes and reads. + bit external_checker; + + // An upper bound on the number of CSRs that are tested by this sequence. It can be set by the + // creator before starting the sequence. If not overridden, this will be zero (meaning there is no + // upper bound). + int unsigned max_num_test_csrs; + + // A queue holding every register across the blocks in models. + protected uvm_reg all_csrs[$]; + + // A queue of the CSR registers that have been selected for this test. These are contained in + // all_csrs, but may be a proper subset if set_csr_test_range has picked only some of them (as + // instructed by the max_num_test_csrs or the num_test_csrs or num_csr_chunks plusargs). They will + // also be shuffled into a random order. + // + // The queue gets populated by set_csr_test_range, which is called by the pre_start task. It is + // then cleared by post_start, to ensure that it will be re-populated if the sequence is run + // again. + protected uvm_reg test_csrs[$]; + + extern function new (string name=""); + + // The pre_start task overrides that of uvm_sequence_base. + // + // It is run just before the body task and is in charge of selecting a subset of all_csrs on which + // the sequence will operate. This subset is written to test_csrs. + extern task pre_start(); + + // The post_start task overrides that of uvm_sequence_base. + // + // It is run just after the body task. In the body task, the sequence will have requested a stream + // of CSR accesses, but the implementation doesn't necessarily wait for the accesses to complete. + // To make sure they have actually done so, the post_start task waits for a period with no + // outstanding CSR accesses (which would mean that each access is done). + // + // The task also clears test_csrs, which means that the same sequence can be run another time and + // the randomisation in set_csr_test_range might pick a different set of test CSRs. + extern task post_start(); + + // Pick a subset of all_csrs and write that to test_csrs. The function's behaviour is described in + // the comment about plusargs before the class. + extern local function void set_csr_test_range(); + + // Return true if this is a CSR or field that has been excluded from the test described in + // csr_test_type by some exclusion (that ultimately came from the hjson register description). + extern function bit is_excl(uvm_object obj, + csr_excl_type_e csr_excl_type, + csr_test_type_e csr_test_type); + + // Return true if this CSR should be excluded by the current sequence. The base class always + // returns false, but this allows more specialised sequences to work over more evenly sized + // chunks. + extern virtual protected function bit csr_excluded(uvm_reg csr); +endclass + +function csr_base_seq::new (string name=""); + super.new(name); +endfunction + +task csr_base_seq::pre_start(); + super.pre_start(); + + // Create test_csrs list only if it is empty. Note that this won't actually do anything if the + // entries in the models array don't have any registers. + if (test_csrs.size() == 0) begin + set_csr_test_range(); + end +endtask + +task csr_base_seq::post_start(); + super.post_start(); + wait_no_outstanding_access(); + test_csrs.delete(); +endtask + +function void csr_base_seq::set_csr_test_range(); + bit has_ntc, has_ncc, has_tcc; + + int unsigned num_csrs; + int num_test_csrs, num_csr_chunks, test_csr_chunk; + + int unsigned start_idx, end_idx; + + // Extract all csrs from the model. If this sequence has specialised the csr_excluded function, + // some CSRs might be skipped. This should help to keep chunks with similar testing times. + all_csrs.delete(); + foreach (models[i]) begin + uvm_reg model_csrs[$]; + models[i].get_registers(model_csrs); + foreach (model_csrs[j]) begin + if (!csr_excluded(model_csrs[j])) begin + all_csrs.push_back(model_csrs[j]); + end else begin + `uvm_info(`gtn, + $sformatf("Skipping register %0s due to exclusion", + model_csrs[j].get_full_name()), + UVM_MEDIUM) + end + end + end + + num_csrs = all_csrs.size(); + if (!num_csrs) return; + + // Has the num_test_csrs plusarg been supplied to give the maximum size of a chunk? + if ($value$plusargs("num_test_csrs=%0d", num_test_csrs)) begin + // Check that the user hasn't requested chunks of less than one: that wouldn't make much sense. + // Generate a UVM error and ignore the plusarg. + if (num_test_csrs < 1) begin + `uvm_error(`gtn, $sformatf("+num_test_csrs=%0d, which is not positive.", num_test_csrs)) + end else begin + has_ntc = 1; + + // If num_test_csrs is greater than the total number of CSRs, clip it to what is available. + if (num_test_csrs > num_csrs) begin + num_test_csrs = num_csrs; + end + end + end + + // Has the num_csr_chunks plusarg been supplied? + if ($value$plusargs("num_csr_chunks=%0d", num_csr_chunks)) begin + // Check that we want a positive number of CSR chunks (since "splitting the list into -3 chunks" + // wouldn't make much sense!). If not, generate a UVM error and ignore the plusarg. + if (num_csr_chunks < 1) begin + `uvm_error(`gtn, $sformatf("+num_csr_chunks=%0d, which is not positive.", num_csr_chunks)) + end else begin + has_ncc = 1; + end + end + + // Has the test_csr_chunk plusarg been supplied? + if ($value$plusargs("test_csr_chunk=%0d", test_csr_chunk)) begin + if (!has_ncc) begin + // This argument only makes sense if we *have* specified a number of CSR chunks. + `uvm_error(`gtn, "Cannot supply test_csr_chunk without num_csr_chunks") + end else if (test_csr_chunk < 0 || test_csr_chunk >= num_csr_chunks) begin + // Similarly, it only makes sense if it's a valid index into the list of chunks. + `uvm_error(`gtn, + $sformatf("+test_csr_chunk=%0d is invalid when num_csr_chunks=%0d", + test_csr_chunk, num_csr_chunks)); + end + has_tcc = 1; + end + + // Check that num_test_csrs and num_csr_chunks haven't both been supplied (because then there + // isn't any good chunk size) + if (has_ntc && has_ncc) begin + `uvm_error(`gtn, "Cannot set both +num_csr_chunks and +num_test_csrs. Using the latter.") + has_ncc = 0; + end + + // At this point, at most one of has_ntc and has_ncc is true. + if (has_ncc) begin + int unsigned chunk_idx; + + // If num_csr_chunks has been supplied we can use it to derive a chunk size in the same way as + // the has_ntc case. + int unsigned chunk_size = (num_csrs + num_csr_chunks - 1) / num_csr_chunks; + + // At this point, we might find that the requested number of chunks is incompatible with + // max_num_test_csrs. If so, generate an error and then clip chunk_size (to ensure the test + // doesn't run for a silly time) + if (max_num_test_csrs > 0 && chunk_size > max_num_test_csrs) begin + `uvm_error(`gtn, + $sformatf("chunk_size %0d is too large for max_num_test_csrs %0d", + chunk_size, max_num_test_csrs)) + chunk_size = max_num_test_csrs; + end + + // We might already have a chunk index in test_csr_chunk. If not, we pick one at random in the + // allowed range. + chunk_idx = has_tcc ? test_csr_chunk : $urandom_range(num_csr_chunks - 1); + + // Again, convert these two into a pair of CSR indices (where end_idx is strictly past the end) + start_idx = chunk_idx * chunk_size; + end_idx = start_idx + chunk_size - 1; + end else if (has_ntc || max_num_test_csrs > 0) begin + int unsigned num_chunks, chunk_size, chunk_idx; + + // Take the smaller supplied value of num_test_csrs and max_num_test_csrs to give an upper bound + // on the size of a chunk. + int unsigned max_chunk_size; + if (max_num_test_csrs > 0) begin + if (has_ntc) begin + max_chunk_size = (max_num_test_csrs < num_test_csrs) ? max_num_test_csrs : num_test_csrs; + end else begin + max_chunk_size = max_num_test_csrs; + end + end else begin + max_chunk_size = num_test_csrs; + end + + // Now divide the total number of CSRs by that bound. Rounding up gives enough chunks to be able + // to cover the whole list. + num_chunks = (num_csrs + max_chunk_size - 1) / max_chunk_size; + + // Given the number of chunks, we can now divide the number of CSRs by that to get the size of a + // chunk. Note that this will be at most max_chunk_size but may be much smaller. + // + // For example, if max_chunk_size = 50 and num_csrs = 51 then we will get 2 = ceil(51/50) chunks + // but then assign ceil(51/2) = 26 tests to each chunk, which gets "maximum parallelism" by + // avoiding dramatic differences between the size of chunks. + chunk_size = (num_csrs + num_chunks - 1) / num_chunks; + + // Pick a chunk index (less than num_chunks) at random + chunk_idx = $urandom_range(num_chunks - 1); + + // Finally, convert that into a pair of CSR indices (where end_idx is strictly past the end) + start_idx = chunk_idx * chunk_size; + end_idx = start_idx + chunk_size - 1; + end else begin + // If neither value was provided, we work on the entire list of CSRs at once. + start_idx = 0; + end_idx = num_csrs - 1; + end + + // At this point, start_idx and end_idx should have been chosen, with start_idx < end_idx. Convert + // the end index to an inclusive limit, by clipping to the number of CSRs. + end_idx = (end_idx >= num_csrs) ? num_csrs - 1 : end_idx; + + // At this point, we should have 0 <= start_idx <= end_idx < num_csrs. If that isn't true, there + // was a bug in the code above. + `DV_CHECK_FATAL(start_idx <= end_idx && end_idx < num_csrs) + + // Replace any existing list of CSRs with the chosen chunk in a random order. + test_csrs.delete(); + for (int i = start_idx; i <= end_idx; i++) begin + test_csrs.push_back(all_csrs[i]); + `uvm_info(`gtn, $sformatf("Testing CSR %0s, reset: 0x%0x.", all_csrs[i].get_full_name(), + all_csrs[i].get_mirrored_value()), UVM_HIGH) + end + `uvm_info(`gtn, + $sformatf("Testing %0d csrs [%0d - %0d] from supplied models.", + test_csrs.size(), start_idx, end_idx), + UVM_MEDIUM) + + test_csrs.shuffle(); +endfunction + +function bit csr_base_seq::is_excl(uvm_object obj, + csr_excl_type_e csr_excl_type, + csr_test_type_e csr_test_type); + csr_excl_item csr_excl = get_excl_item(obj); + if (csr_excl == null) begin + return 0; + end else begin + return csr_excl.is_excl(obj, csr_excl_type, csr_test_type); + end +endfunction + +function bit csr_base_seq::csr_excluded(uvm_reg csr); + return 1'b0; +endfunction diff --git a/hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_hw_reset_seq.sv b/hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_hw_reset_seq.sv new file mode 100644 index 000000000..f91003b55 --- /dev/null +++ b/hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_hw_reset_seq.sv @@ -0,0 +1,65 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// This sequence reads all CSRs and checks their values against the reset value provided in the RAL +// specification. Note that this does not sufficiently qualify as the CSR HW reset test. The 'full' +// CSR HW reset test is constructed externally by running csr_write_seq first, issuing reset and +// only then running this sequence. + +class csr_hw_reset_seq extends csr_base_seq; + `uvm_object_utils(csr_hw_reset_seq) + + extern function new (string name=""); + + // Read all CSRs, expecting their values to match their reset values in the register block. + extern task body(); + + // Read the given CSR if it is not excluded and check its value matches the expected reset value. + // If the register has an HDL path, use two reads, starting with a backdoor one. + extern local task test_one_csr(uvm_reg csr); + + // Return true if the CSR should be skipped by this sequence + extern protected function bit csr_excluded(uvm_reg csr); +endclass + +function csr_hw_reset_seq::new (string name=""); + super.new(name); +endfunction + +task csr_hw_reset_seq::body(); + foreach (test_csrs[i]) begin + test_one_csr(test_csrs[i]); + end +endtask + +task csr_hw_reset_seq::test_one_csr(uvm_reg csr); + uvm_reg_data_t compare_mask = get_mask_excl_fields(csr, CsrExclInitCheck, CsrHwResetTest); + + `uvm_info(`gtn, + $sformatf("Verifying reset value of register %0s", csr.get_full_name()), + UVM_MEDIUM) + + // Read CSR twice, one from backdoor (if path available), the other from frontdoor. + if (csr.has_hdl_path()) begin + // Reading from backdoor can ensure that we deposit value into the storage rather than just a + // net. If we mistakenly deposit to a net, reset can't clear it and this check will fail. + csr_rd_check(.ptr (csr), + .backdoor (1), + .compare (!external_checker), + .compare_vs_ral(1'b1), + .compare_mask (compare_mask)); + end + + // Read and check value via frontdoor. + csr_rd_check(.ptr (csr), + .backdoor (0), + .blocking (0), + .compare (!external_checker), + .compare_vs_ral(1'b1), + .compare_mask (compare_mask)); +endtask + +function bit csr_hw_reset_seq::csr_excluded(uvm_reg csr); + return is_excl(csr, CsrExclInitCheck, CsrHwResetTest); +endfunction diff --git a/hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_seq_lib.sv b/hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_seq_lib.sv index 8fab5f42e..63d10c90d 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_seq_lib.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_seq_lib.sv @@ -12,155 +12,7 @@ // register and field access policies. Also, we use csr_rd_check task instead of csr_mirror to take // field exclusions into account. // -// CSRs to be tested is accumulated and shuffled from the supplied reg models. -// What / how many CSRs to test can be further controlled in 3 ways - -// 1. Externally add specific CSRs to test_csrs queue (highest prio) -// 2. Set num_test_csrs test a randomly picked set of CSRs from the supplied models -// 3. Set / pass via plusarg, num_csr_chunks / test_csr_chunk -// // Exclusions are to be provided using the csr_excl_item item (see class for more details). -class csr_base_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); - `uvm_object_utils(csr_base_seq) - - dv_base_reg_block models[$]; - uvm_reg all_csrs[$]; - uvm_reg test_csrs[$]; - - // By default, assume external checker (example, scoreboard) is turned off. If that is the case, - // then writes are followed by call to predict function to update the mirrored value. Reads are - // then checked against the mirrored value using csr_rd_check task. If external checker is - // enabled, then we let the external checker do the predict and compare. - // In either case, we should be able to do completely non-blocking writes and reads. - bit external_checker = 1'b0; - - // either use num_test_csrs or {test_csr_chunk, num_csr_chunks} to test slice of all CSRs - int num_test_csrs = 0; - int test_csr_chunk = 1; - int num_csr_chunks = 1; - - `uvm_object_new - - // pre_start - virtual task pre_start(); - super.pre_start(); - - // create test_csrs list only if its empty - if (test_csrs.size() == 0) set_csr_test_range(); - endtask - - // post_start - virtual task post_start(); - super.post_start(); - wait_no_outstanding_access(); - test_csrs.delete(); - endtask - - // extract csrs and split and prune to a specified test_csr_chunk - virtual function void set_csr_test_range(); - int start_idx; - int end_idx; - int chunk_size; - - // extract all csrs from the model - all_csrs.delete(); - foreach (models[i]) begin - models[i].get_registers(all_csrs); - end - - void'($value$plusargs("num_test_csrs=%0d", num_test_csrs)); - if (num_test_csrs != 0) begin - num_csr_chunks = all_csrs.size / num_test_csrs + 1; - `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(test_csr_chunk, - test_csr_chunk inside {[1:num_csr_chunks]};) - end else begin - // extract test_csr_chunk, num_csr_chunks from plusargs - void'($value$plusargs("test_csr_chunk=%0d", test_csr_chunk)); - void'($value$plusargs("num_csr_chunks=%0d", num_csr_chunks)); - end - - if (!(test_csr_chunk inside {[1:num_csr_chunks]})) begin - `uvm_fatal(`gtn, $sformatf({{"Invalid opt +test_csr_chunk=%0d, +num_csr_chunks=%0d "}, - {"(1 <= test_csr_chunk <= num_csr_chunks)."}}, - test_csr_chunk, num_csr_chunks)) - end - chunk_size = (num_test_csrs != 0) ? num_test_csrs : (all_csrs.size / num_csr_chunks + 1); - start_idx = (test_csr_chunk - 1) * chunk_size; - end_idx = test_csr_chunk * chunk_size; - if (end_idx >= all_csrs.size()) end_idx = all_csrs.size() - 1; - - test_csrs.delete(); - for (int i = start_idx; i <= end_idx; i++) begin - test_csrs.push_back(all_csrs[i]); - `uvm_info(`gtn, $sformatf("Testing CSR %0s, reset: 0x%0x.", all_csrs[i].get_full_name(), - all_csrs[i].get_mirrored_value()), UVM_HIGH) - end - `uvm_info(`gtn, $sformatf("Testing %0d csrs [%0d - %0d] in all supplied models.", - test_csrs.size(), start_idx, end_idx), UVM_MEDIUM) - test_csrs.shuffle(); - endfunction - - // check if this csr/fld is excluded from test based on the excl info in blk.csr_excl - function bit is_excl(uvm_object obj, - csr_excl_type_e csr_excl_type, - csr_test_type_e csr_test_type); - csr_excl_item csr_excl = get_excl_item(obj); - if (csr_excl == null) begin - return 0; - end else begin - return csr_excl.is_excl(obj, csr_excl_type, csr_test_type); - end - endfunction -endclass - -//-------------------------------------------------------------------------------------------------- -// Class: csr_hw_reset_seq -// Brief Description: This sequence reads all CSRs and checks it against the reset value provided -// in the RAL specification. Note that this does not sufficiently qualify as the CSR HW reset test. -// The 'full' CSR HW reset test is constructed externally by running the csr_write_seq below first, -// issuing reset and only then running this sequence. -//-------------------------------------------------------------------------------------------------- -class csr_hw_reset_seq extends csr_base_seq; - `uvm_object_utils(csr_hw_reset_seq) - - `uvm_object_new - - virtual task body(); - foreach (test_csrs[i]) begin - uvm_reg_data_t compare_mask; - - // check if parent block or register is excluded from init check - if (is_excl(test_csrs[i], CsrExclInitCheck, CsrHwResetTest)) begin - `uvm_info(`gtn, $sformatf("Skipping register %0s due to CsrExclInitCheck exclusion", - test_csrs[i].get_full_name()), UVM_MEDIUM) - continue; - end - - `uvm_info(`gtn, $sformatf("Verifying reset value of register %0s", - test_csrs[i].get_full_name()), UVM_MEDIUM) - - compare_mask = get_mask_excl_fields(test_csrs[i], CsrExclInitCheck, CsrHwResetTest); - // Read CSR twice, one from backdoor (if path available), the other from frontdoor. - if (test_csrs[i].has_hdl_path()) begin - // Reading from backdoor can ensure that we deposit value into the storage rather than just - // a net. If we mistakenly deposit to a net, reset can't clear it and this check will fail. - csr_rd_check(.ptr (test_csrs[i]), - .backdoor (1), - .compare (!external_checker), - .compare_vs_ral(1'b1), - .compare_mask (compare_mask)); - end - - // Read and check value via frontdoor. - csr_rd_check(.ptr (test_csrs[i]), - .backdoor (0), - .blocking (0), - .compare (!external_checker), - .compare_vs_ral(1'b1), - .compare_mask (compare_mask)); - end - endtask - -endclass //-------------------------------------------------------------------------------------------------- // Class: csr_write_seq diff --git a/hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_utils.core b/hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_utils.core index 256e57a35..09af5315e 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_utils.core +++ b/hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_utils.core @@ -12,6 +12,8 @@ filesets: - lowrisc:dv:dv_base_reg files: - csr_utils_pkg.sv + - csr_base_seq.sv: {is_include_file: true} + - csr_hw_reset_seq.sv: {is_include_file: true} - csr_seq_lib.sv: {is_include_file: true} file_type: systemVerilogSource diff --git a/hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_utils_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_utils_pkg.sv index d4ed0800a..185093403 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_utils_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/csr_utils/csr_utils_pkg.sv @@ -855,6 +855,8 @@ package csr_utils_pkg; endfunction // sources + `include "csr_base_seq.sv" + `include "csr_hw_reset_seq.sv" `include "csr_seq_lib.sv" endpackage diff --git a/hw/vendor/lowrisc_ip/dv/sv/csrng_agent/csrng_agent_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/csrng_agent/csrng_agent_pkg.sv index 9c5e4fbf1..e11f20268 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/csrng_agent/csrng_agent_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/csrng_agent/csrng_agent_pkg.sv @@ -6,6 +6,7 @@ package csrng_agent_pkg; // dep packages import uvm_pkg::*; import dv_utils_pkg::*; + import dv_base_agent_pkg::*; import dv_lib_pkg::*; import push_pull_agent_pkg::*; import csrng_pkg::*; diff --git a/hw/vendor/lowrisc_ip/dv/sv/csrng_agent/csrng_device_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/csrng_agent/csrng_device_driver.sv index f44134e92..dc4509527 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/csrng_agent/csrng_device_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/csrng_agent/csrng_device_driver.sv @@ -9,7 +9,7 @@ class csrng_device_driver extends csrng_driver; uint cmd_ack_dly; bit rsp_sts; - virtual task reset_signals(); + task on_enter_reset(); cfg.vif.cmd_rsp_int.csrng_rsp_ack <= 1'b0; cfg.vif.cmd_rsp_int.csrng_rsp_sts <= CMD_STS_SUCCESS; endtask @@ -55,7 +55,7 @@ class csrng_device_driver extends csrng_driver; seq_item_port.item_done(rsp); end - // Write ack bit again in case the race condition with `reset_signals`. + // Write ack bit again to avoid a race with reset tracking if (cfg.in_reset) cfg.vif.device_cb.cmd_rsp_int.csrng_rsp_ack <= 1'b0; end diff --git a/hw/vendor/lowrisc_ip/dv/sv/csrng_agent/csrng_host_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/csrng_agent/csrng_host_driver.sv index 4f9519bcc..daf59c5d7 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/csrng_agent/csrng_host_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/csrng_agent/csrng_host_driver.sv @@ -9,11 +9,6 @@ class csrng_host_driver extends csrng_driver; // Break down the data and send it to push_pull_host_driver through its sequencer csrng_sequencer m_csrng_sequencer; - // reset signals - virtual task reset_signals(); -// `uvm_fatal(`gtn, "FIXME") - endtask - // drive trans received from sequencer virtual task get_and_drive(); forever begin diff --git a/hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_agent.core b/hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_agent.core new file mode 100644 index 000000000..0be0a6a07 --- /dev/null +++ b/hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_agent.core @@ -0,0 +1,27 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:dv:dv_base_agent" +description: "DV base agent" + +filesets: + files_dv: + depend: + - lowrisc:dv:dv_utils + files: + - dv_base_agent_pkg.sv + + - dv_base_agent_cfg.sv: {is_include_file: true} + - dv_base_agent_cov.sv: {is_include_file: true} + - dv_base_monitor.sv: {is_include_file: true} + - dv_base_sequencer.sv: {is_include_file: true} + - dv_base_driver.sv: {is_include_file: true} + - dv_base_agent.sv: {is_include_file: true} + - dv_base_seq.sv: {is_include_file: true} + file_type: systemVerilogSource + +targets: + default: + filesets: + - files_dv diff --git a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_agent.sv b/hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_agent.sv similarity index 97% rename from hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_agent.sv rename to hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_agent.sv index 20b8980cb..5939e64cd 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_agent.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_agent.sv @@ -52,7 +52,7 @@ endfunction function void dv_base_agent::build_phase(uvm_phase phase); super.build_phase(phase); - if (!uvm_config_db#(CFG_T)::get(this, "", "cfg", cfg)) begin + if (cfg == null && !uvm_config_db#(CFG_T)::get(this, "", "cfg", cfg)) begin `uvm_fatal(`gfn, $sformatf("failed to get %s from uvm_config_db", cfg.get_type_name())) end `uvm_info(`gfn, $sformatf("\n%0s", cfg.sprint()), UVM_HIGH) diff --git a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_agent_cfg.sv b/hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_agent_cfg.sv similarity index 100% rename from hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_agent_cfg.sv rename to hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_agent_cfg.sv diff --git a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_agent_cov.sv b/hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_agent_cov.sv similarity index 100% rename from hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_agent_cov.sv rename to hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_agent_cov.sv diff --git a/hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_agent_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_agent_pkg.sv new file mode 100644 index 000000000..d8abd0603 --- /dev/null +++ b/hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_agent_pkg.sv @@ -0,0 +1,28 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +package dv_base_agent_pkg; + // dep packages + import uvm_pkg::*; + import dv_utils_pkg::*; + + // macro includes + `include "uvm_macros.svh" + `include "dv_macros.svh" + + // package variables + string msg_id = "dv_base_agent_pkg"; + + // package sources + `include "dv_base_agent_cfg.sv" + `include "dv_base_agent_cov.sv" + `include "dv_base_monitor.sv" + `include "dv_base_sequencer.sv" + `include "dv_base_driver.sv" + `include "dv_base_agent.sv" + + // base seq + `include "dv_base_seq.sv" + +endpackage diff --git a/hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_driver.sv new file mode 100644 index 000000000..f37dec501 --- /dev/null +++ b/hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_driver.sv @@ -0,0 +1,91 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// A base class for a driver. This drives sequence items of type ITEM_T. If the subclass is designed +// to do so, it responds with items of type RSP_ITEM_T. +// +// NOTE: This class would make more sense as an abstract base class (with a pure virtual +// implementation of get_and_drive). Unfortunately, this isn't possible at the moment because +// dv_base_agent ends up needing to instantiate a uvm_driver instance unless parameters are +// overridden. This would be reasonable except that uvm_driver::create is not implemented in +// UVM 1.2 (the version that OpenTitan currently depends on). +// +// If we bump the UVM version past 1800.2-2020, we can switch this over to an abstract base +// class. + +class dv_base_driver #(type ITEM_T = uvm_sequence_item, + type CFG_T = dv_base_agent_cfg, + type RSP_ITEM_T = ITEM_T) + extends uvm_driver #(.REQ(ITEM_T), .RSP(RSP_ITEM_T)); + + `uvm_component_param_utils(dv_base_driver #(.ITEM_T (ITEM_T), + .CFG_T (CFG_T), + .RSP_ITEM_T (RSP_ITEM_T))) + + CFG_T cfg; + + extern function new (string name, uvm_component parent); + + // The run_phase task runs reset_signals() and get_and_drive() (described below) in parallel. + // Subclasses might not need to implement run_phase directly. + extern task run_phase(uvm_phase phase); + + // A task that runs forever, monitoring the cfg.in_reset flag and calling on_enter_reset when it + // becomes true. Subclasses shouldn't normally need to override this. + extern virtual task reset_signals(); + + // The get_and_drive task should be implemented in any subclass. It must repeatedly call + // get_next_item to consume items from the sequencer and, driving each. + // + // NOTE: Any implementation must implement this or fail at runtime. See note above for why this + // can't be enforced at build time. + extern virtual task get_and_drive(); + + // A task that is run at the start of any reset. It can be implemented by any subclass to clear + // any driven signals back to their "reset value". + // + // Note that this task should not consume any simulation time: it is a task to allow it to + // interact properly with clocking blocks. + extern virtual task on_enter_reset(); + + // A function that is run at the end of any reset. It may be implemented by any subclass and gives + // the class an opportunity to set up values before the start of a run, but without a race + // condition at the start of the reset. + extern virtual function void on_leave_reset(); +endclass + +function dv_base_driver::new (string name, uvm_component parent); + super.new(name, parent); +endfunction + +task dv_base_driver::run_phase(uvm_phase phase); + super.run_phase(phase); + fork + reset_signals(); + get_and_drive(); + join +endtask + +task dv_base_driver::reset_signals(); + forever begin + `uvm_info(get_full_name(), "Driver entering reset", UVM_HIGH) + on_enter_reset(); + wait(!cfg.in_reset); + `uvm_info(get_full_name(), "Driver leaving reset", UVM_HIGH) + on_leave_reset(); + wait(cfg.in_reset); + end +endtask + +task dv_base_driver::get_and_drive(); + `uvm_fatal(get_full_name(), "This task must be implemented by base classes.") +endtask + +task dv_base_driver::on_enter_reset(); + // The default behaviour of this task is to do nothing +endtask + +function void dv_base_driver::on_leave_reset(); + // The default behaviour of this function is to do nothing +endfunction diff --git a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_monitor.sv b/hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_monitor.sv similarity index 100% rename from hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_monitor.sv rename to hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_monitor.sv diff --git a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_seq.sv b/hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_seq.sv similarity index 100% rename from hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_seq.sv rename to hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_seq.sv diff --git a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_sequencer.sv b/hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_sequencer.sv similarity index 100% rename from hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_sequencer.sv rename to hw/vendor/lowrisc_ip/dv/sv/dv_base_agent/dv_base_sequencer.sv diff --git a/hw/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_block.sv b/hw/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_block.sv index b7a0487e4..df4ab3402 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_block.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/dv_base_reg/dv_base_reg_block.sv @@ -187,7 +187,7 @@ class dv_base_reg_block extends uvm_reg_block; end endfunction - function void get_shadowed_regs(ref dv_base_reg shadowed_regs[$]); + virtual function void get_shadowed_regs(ref dv_base_reg shadowed_regs[$]); dv_base_reg all_regs[$]; this.get_dv_base_regs(all_regs); foreach (all_regs[i]) begin @@ -315,8 +315,8 @@ class dv_base_reg_block extends uvm_reg_block; unmapped_addr_ranges.delete(); // unmapped address ranges consist of: - // - the address space between all mapped address ranges (if exists) - // - space between csr_base_addr and the first mapped address range (if exists) + // - any gaps in the address space between mapped address ranges + // - any space between the map base address and the first mapped address range // - space between the last mapped address and the highest address mapped by the address mask if (mapped_addr_ranges.size() == 0) begin range.start_addr = default_map.get_base_addr(); diff --git a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_driver.sv deleted file mode 100644 index fad777954..000000000 --- a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_driver.sv +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -// A base class for a driver. This drives sequence items of type ITEM_T. If the subclass is designed -// to do so, it responds with items of type RSP_ITEM_T. - -class dv_base_driver #(type ITEM_T = uvm_sequence_item, - type CFG_T = dv_base_agent_cfg, - type RSP_ITEM_T = ITEM_T) - extends uvm_driver #(.REQ(ITEM_T), .RSP(RSP_ITEM_T)); - - `uvm_component_param_utils(dv_base_driver #(.ITEM_T (ITEM_T), - .CFG_T (CFG_T), - .RSP_ITEM_T (RSP_ITEM_T))) - - bit under_reset; - CFG_T cfg; - - extern function new (string name, uvm_component parent); - - // The run_phase task runs reset_signals() and get_and_drive() (described below) in parallel. - // Subclasses might not need to implement run_phase directly. - extern task run_phase(uvm_phase phase); - - // The reset_signals task should be implemented in any subclass and is responsible for monitoring - // reset on the interface, then resetting the driven signals when a reset happens. - extern virtual task reset_signals(); - - // The get_and_drive task should be implemented in any subclass. It must repeatedly call - // get_next_item to consume items from the sequencer and, driving each. - extern virtual task get_and_drive(); -endclass - -function dv_base_driver::new (string name, uvm_component parent); - super.new(name, parent); -endfunction - -task dv_base_driver::run_phase(uvm_phase phase); - super.run_phase(phase); - fork - reset_signals(); - get_and_drive(); - join -endtask - -task dv_base_driver::reset_signals(); - // Empty - to be populated in child class -endtask - -task dv_base_driver::get_and_drive(); - // Empty - to be populated in child class -endtask diff --git a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_env_cfg.sv b/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_env_cfg.sv index 843e40f6c..8de81e672 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_env_cfg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_env_cfg.sv @@ -114,7 +114,7 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object; // Initialise the object with RAL models and set it up for randomisation // // This is virtual, allowing subclasses to set up list_of_alerts and num_interrupts. - extern virtual function void initialize(bit [BUS_AW-1:0] csr_base_addr = '1); + extern virtual function void initialize(); // Set pre-build RAL knobs. // @@ -137,15 +137,10 @@ class dv_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object; extern virtual function void reset_deasserted(); // Create missing RAL models and set their base addresses based on the supplied arg. - // - // csr_base_addr is the base address to set to the RAL models. If it is all 1s, then we treat that - // as an indication to randomize the base address internally instead. - extern local function void make_ral_models(bit [BUS_AW-1:0] csr_base_addr); + extern local function void make_ral_models(); - // Create the named RAL model and set its base address based on csr_base_addr. This randomises as - // described in make_ral_models. - extern local function void make_ral_model(string ral_model_name, - bit [BUS_AW-1:0] csr_base_addr); + // Create the named RAL model and give it a randomised base address. + extern local function void make_ral_model(string ral_model_name); // Create the named register block. This protected function is virtual to allow subclasses to // customise how the register block is created. @@ -178,7 +173,7 @@ function void dv_base_env_cfg::post_randomize(); end endfunction -function void dv_base_env_cfg::initialize(bit [BUS_AW-1:0] csr_base_addr = '1); +function void dv_base_env_cfg::initialize(); if (is_initialized) `uvm_fatal(`gfn, "Cannot call initialize when already initialized") // Prepend ral_type_name to ral_model_names (so the "default RAL" for the class gets index 0) @@ -187,7 +182,7 @@ function void dv_base_env_cfg::initialize(bit [BUS_AW-1:0] csr_base_addr = '1); is_initialized = 1'b1; // build the ral model - make_ral_models(csr_base_addr); + make_ral_models(); // add items to clk_freqs_mhz before randomizing it foreach (ral_model_names[i]) begin @@ -213,15 +208,13 @@ function void dv_base_env_cfg::reset_deasserted(); csr_utils_pkg::reset_deasserted(); endfunction -function void dv_base_env_cfg::make_ral_models(bit [BUS_AW-1:0] csr_base_addr); - foreach (ral_model_names[i]) make_ral_model(ral_model_names[i], csr_base_addr); +function void dv_base_env_cfg::make_ral_models(); + foreach (ral_model_names[i]) make_ral_model(ral_model_names[i]); `DV_CHECK_FATAL(ral_models.exists(ral_type_name)) endfunction -function void dv_base_env_cfg::make_ral_model(string ral_model_name, - bit [BUS_AW-1:0] csr_base_addr); +function void dv_base_env_cfg::make_ral_model(string ral_model_name); dv_base_reg_block reg_blk; - bit randomize_base_addr = &csr_base_addr; if (ral_models.exists(ral_model_name)) begin // If a model for this name already exists, set reg_blk to point at it. @@ -250,9 +243,8 @@ function void dv_base_env_cfg::make_ral_model(string ral_model_name, `uvm_fatal(`gfn, $sformatf("ral_models[%s] is not locked.", ral_model_name)) end - // Since the model is locked, we know its layout. Set the base address for the register block. - reg_blk.set_base_addr(.base_addr(`UVM_REG_ADDR_WIDTH'(csr_base_addr)), - .randomize_base_addr(randomize_base_addr)); + // Since the model is locked, we know its layout. Pick a base address for the register block. + reg_blk.set_base_addr(.base_addr(0), .randomize_base_addr(1)); ral_models[ral_model_name] = reg_blk; endfunction diff --git a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_test.sv b/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_test.sv index c6b7b470a..953a1ea8a 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_test.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_test.sv @@ -69,7 +69,7 @@ class dv_base_test #(type CFG_T = dv_base_env_cfg, $sformatf("Failed to cast object of type %p to expected CFG_T class.", cfg_type)) end - cfg.initialize(); + initialize_env_cfg(); end `DV_CHECK_RANDOMIZE_FATAL(cfg) @@ -99,6 +99,17 @@ class dv_base_test #(type CFG_T = dv_base_env_cfg, endfunction : build_phase + // Initialize an env_cfg that has been created in build_phase + // + // This virtual function allows classes that extend dv_base_test to configure the env_cfg before + // or after calling dv_base_test::initialize_env_cfg (which calls initialize on the cfg object). + // + // The function is not called for cfg objects that are supplied through uvm_config_db (since they + // are assumed to have been initialized in the testbench already). + virtual function void initialize_env_cfg(); + cfg.initialize(); + endfunction + virtual function void end_of_elaboration_phase(uvm_phase phase); super.end_of_elaboration_phase(phase); void'($value$plusargs("max_quit_count=%0d", max_quit_count)); diff --git a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_vseq.sv b/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_vseq.sv index 25986920f..40e34356d 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_vseq.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_base_vseq.sv @@ -270,7 +270,7 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block, m_csr_seq = csr_base_seq::type_id::create("m_csr_seq"); m_csr_seq.models = models; m_csr_seq.external_checker = cfg.en_scb; - m_csr_seq.num_test_csrs = num_test_csrs; + m_csr_seq.max_num_test_csrs = num_test_csrs; m_csr_seq.start(null); endtask diff --git a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_lib.core b/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_lib.core index a0cd70eb3..b76bcfc77 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_lib.core +++ b/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_lib.core @@ -11,19 +11,12 @@ filesets: - lowrisc:dv:dv_utils - lowrisc:dv:csr_utils - lowrisc:dv:dv_base_reg + - lowrisc:dv:dv_base_agent - lowrisc:dv:common_ifs - lowrisc:opentitan:bus_params_pkg files: - dv_lib_pkg.sv - - dv_base_agent_cfg.sv: {is_include_file: true} - - dv_base_agent_cov.sv: {is_include_file: true} - - dv_base_monitor.sv: {is_include_file: true} - - dv_base_sequencer.sv: {is_include_file: true} - - dv_base_driver.sv: {is_include_file: true} - - dv_base_agent.sv: {is_include_file: true} - - dv_base_seq.sv: {is_include_file: true} - - dv_base_env_cfg.sv: {is_include_file: true} - bit_toggle_cg_wrap.sv: {is_include_file: true} - dv_base_env_cov.sv: {is_include_file: true} diff --git a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_lib_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_lib_pkg.sv index 46bcd8893..3f4573462 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_lib_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/dv_lib/dv_lib_pkg.sv @@ -9,6 +9,7 @@ package dv_lib_pkg; import dv_utils_pkg::*; import csr_utils_pkg::*; import dv_base_reg_pkg::*; + import dv_base_agent_pkg::*; // macro includes `include "uvm_macros.svh" @@ -18,16 +19,6 @@ package dv_lib_pkg; string msg_id = "dv_lib_pkg"; // package sources - // base agent - `include "dv_base_agent_cfg.sv" - `include "dv_base_agent_cov.sv" - `include "dv_base_monitor.sv" - `include "dv_base_sequencer.sv" - `include "dv_base_driver.sv" - `include "dv_base_agent.sv" - - // base seq - `include "dv_base_seq.sv" // base env `include "dv_base_env_cfg.sv" diff --git a/hw/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv index a6fa6b8e2..47802d151 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv @@ -37,10 +37,11 @@ package dv_utils_pkg; // typedef parameterized pins_if for ease of implementation for interrupts and alerts typedef virtual pins_if #(NUM_MAX_INTERRUPTS) intr_vif; - // interface direction / mode - Host or Device - typedef enum bit { - Host, - Device + // Interface direction / mode + typedef enum bit [1:0] { + Host, // The interface is active and is driving signals as a host + Device, // The interface is active and is driving signals as a device + Monitor // The interface is passive and drives no signals } if_mode_e; // compare operator types diff --git a/hw/vendor/lowrisc_ip/dv/sv/entropy_src_xht_agent/entropy_src_xht_agent_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/entropy_src_xht_agent/entropy_src_xht_agent_pkg.sv index d353290c6..b7ff1df56 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/entropy_src_xht_agent/entropy_src_xht_agent_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/entropy_src_xht_agent/entropy_src_xht_agent_pkg.sv @@ -6,6 +6,7 @@ package entropy_src_xht_agent_pkg; // dep packages import uvm_pkg::*; import dv_utils_pkg::*; + import dv_base_agent_pkg::*; import dv_lib_pkg::*; import entropy_src_pkg::*; diff --git a/hw/vendor/lowrisc_ip/dv/sv/entropy_src_xht_agent/entropy_src_xht_device_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/entropy_src_xht_agent/entropy_src_xht_device_driver.sv index bc9bcf184..0a792734a 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/entropy_src_xht_agent/entropy_src_xht_device_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/entropy_src_xht_agent/entropy_src_xht_device_driver.sv @@ -10,16 +10,15 @@ class entropy_src_xht_device_driver extends dv_base_driver #( `uvm_component_utils(entropy_src_xht_device_driver) `uvm_component_new - virtual task reset_signals(); - forever begin - @(negedge cfg.vif.rst_n); - `uvm_info(`gfn, "Driver is under reset", UVM_DEBUG) - cfg.vif.xht_cb.rsp <= ENTROPY_SRC_XHT_META_RSP_DEFAULT; - @(posedge cfg.vif.rst_n); - `uvm_info(`gfn, "Driver is out of reset", UVM_DEBUG) - end + task on_enter_reset(); + `uvm_info(`gfn, "Driver is under reset", UVM_DEBUG) + cfg.vif.xht_cb.rsp <= ENTROPY_SRC_XHT_META_RSP_DEFAULT; endtask + function void on_leave_reset(); + `uvm_info(`gfn, "Driver is out of reset", UVM_DEBUG) + endfunction + virtual task get_and_drive(); forever begin @(cfg.vif.xht_cb); diff --git a/hw/vendor/lowrisc_ip/dv/sv/flash_phy_prim_agent/flash_phy_prim_agent_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/flash_phy_prim_agent/flash_phy_prim_agent_pkg.sv index d908190af..f2884e1f8 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/flash_phy_prim_agent/flash_phy_prim_agent_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/flash_phy_prim_agent/flash_phy_prim_agent_pkg.sv @@ -6,6 +6,7 @@ package flash_phy_prim_agent_pkg; // dep packages import uvm_pkg::*; import dv_utils_pkg::*; + import dv_base_agent_pkg::*; import dv_lib_pkg::*; import flash_ctrl_top_specific_pkg::*; diff --git a/hw/vendor/lowrisc_ip/dv/sv/flash_phy_prim_agent/flash_phy_prim_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/flash_phy_prim_agent/flash_phy_prim_driver.sv index 735be4b31..460d8d393 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/flash_phy_prim_agent/flash_phy_prim_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/flash_phy_prim_agent/flash_phy_prim_driver.sv @@ -11,10 +11,6 @@ class flash_phy_prim_driver extends dv_base_driver #(.ITEM_T(flash_phy_prim_item `uvm_component_new - // reset signals - virtual task reset_signals(); - endtask - // drive trans received from sequencer virtual task get_and_drive(); forever begin diff --git a/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/i2c_agent_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/i2c_agent_pkg.sv index fcc1c5e07..04afb93a4 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/i2c_agent_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/i2c_agent_pkg.sv @@ -9,6 +9,7 @@ package i2c_agent_pkg; // dep packages import uvm_pkg::*; import dv_utils_pkg::*; + import dv_base_agent_pkg::*; import dv_lib_pkg::*; import i2c_pkg::*; diff --git a/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/i2c_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/i2c_driver.sv index 944ac4f43..721190389 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/i2c_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/i2c_driver.sv @@ -15,15 +15,14 @@ class i2c_driver extends dv_base_driver #(i2c_item, i2c_agent_cfg); // get an array with unique read data constraint rd_data_c { unique { rd_data }; } - virtual task reset_signals(); - forever begin - @(negedge cfg.vif.rst_ni); - `uvm_info(`gfn, "\ndriver in reset progress", UVM_DEBUG) - release_bus(); - @(posedge cfg.vif.rst_ni); - `uvm_info(`gfn, "\ndriver out of reset", UVM_DEBUG) - end - endtask : reset_signals + task on_enter_reset(); + `uvm_info(`gfn, "\ndriver in reset progress", UVM_DEBUG) + release_bus(); + endtask + + function void on_leave_reset(); + `uvm_info(`gfn, "\ndriver out of reset", UVM_DEBUG) + endfunction virtual task run_phase(uvm_phase phase); fork @@ -215,15 +214,15 @@ class i2c_driver extends dv_base_driver #(i2c_item, i2c_agent_cfg); virtual task process_reset(); @(negedge cfg.vif.rst_ni); - release_bus(); + on_enter_reset(); `uvm_info(`gfn, "\n driver is reset", UVM_DEBUG) endtask : process_reset - virtual task release_bus(); + function void release_bus(); `uvm_info(`gfn, "Driver released the bus", UVM_DEBUG) cfg.vif.scl_o = 1'b1; cfg.vif.sda_o = 1'b1; - endtask : release_bus + endfunction : release_bus task drive_scl(); // This timeout is extremely long since read transactions will stretch diff --git a/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/i2c_if.sv b/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/i2c_if.sv index 3366d826d..cd0060cdc 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/i2c_if.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/i2c_if.sv @@ -68,27 +68,23 @@ interface i2c_if( // caused the tasks to cease functioning reliably, and the monitor would lose its // lock on the bus traffic. - task automatic wait_for_host_start(ref timing_cfg_t tc); + task automatic wait_for_host_start(); forever begin @(negedge sda_i); if (!scl_i) continue; @(negedge scl_i); if (!sda_i) begin - // wait_for_dly(tc.tClockStart); break; end else continue; end endtask: wait_for_host_start - task automatic wait_for_host_rstart(ref timing_cfg_t tc, - output bit rstart); + task automatic wait_for_host_rstart(output bit rstart); rstart = 1'b0; forever begin @(posedge scl_i && sda_i); - // wait_for_dly(tc.tSetupStart); @(negedge sda_i); if (scl_i) begin - // wait_for_dly(tc.tHoldStart); @(negedge scl_i) begin rstart = 1'b1; break; @@ -118,7 +114,7 @@ interface i2c_if( begin : iso_fork fork wait_for_host_stop(tc, stop); - wait_for_host_rstart(tc, rstart); + wait_for_host_rstart(rstart); join_any disable fork; end : iso_fork diff --git a/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/i2c_monitor.sv b/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/i2c_monitor.sv index 95209411d..44af21fb3 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/i2c_monitor.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/i2c_monitor.sv @@ -184,7 +184,7 @@ class i2c_monitor extends dv_base_monitor #( prev_item.stop) begin `uvm_info(`gfn, "target_collect_thread(): Waiting for START condition.", UVM_FULL) - cfg.vif.wait_for_host_start(cfg.timing_cfg); + cfg.vif.wait_for_host_start(); `uvm_info(`gfn, "target_collect_thread(): Saw START condition.", UVM_FULL) mon_dut_item.start = 1'b1; @@ -430,7 +430,7 @@ class i2c_monitor extends dv_base_monitor #( prev_item.stop) begin `uvm_info(`gfn, "controller_collect_thread(): Waiting for START condition.", UVM_FULL) - cfg.vif.wait_for_host_start(cfg.timing_cfg); + cfg.vif.wait_for_host_start(); `uvm_info(`gfn, "controller_collect_thread(): Saw START condition.", UVM_FULL) mon_dut_item.start = 1'b1; diff --git a/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/seq_lib/i2c_base_seq.sv b/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/seq_lib/i2c_base_seq.sv index b2321641d..5d98d8f56 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/seq_lib/i2c_base_seq.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/seq_lib/i2c_base_seq.sv @@ -120,7 +120,7 @@ class i2c_base_seq extends dv_base_seq #( StDataByte: begin if (inp_xfer.dir == i2c_pkg::READ) begin // The agent drives the read bytes as target-transmitter. - fork drive_read_byte(); join_none + fork drive_read_byte($urandom); join_none end end StDataByteRcvd: begin @@ -137,31 +137,36 @@ class i2c_base_seq extends dv_base_seq #( `uvm_info(`gfn, "Got to end of Agent-Target transfer. Now awaiting new transfer.", UVM_DEBUG) endtask : send_device_mode_txn + // Return DevAck by default unless an extended class overrides it. + protected virtual function drv_type_e get_ack_nack(); + return DevAck; + endfunction - virtual task drive_addr_byte_ack(); + local task drive_ack(); `uvm_create_obj(REQ, req); start_item(req); - req.drv_type = DevAck; + req.drv_type = get_ack_nack(); + if (req.drv_type == DevNack) + `uvm_info(`gfn, "Nacking the byte!", UVM_HIGH) finish_item(req); + endtask : drive_ack + + virtual task drive_addr_byte_ack(); + drive_ack(); `uvm_info(`gfn, "drive_addr_byte_ack()::finish_item()", UVM_DEBUG) endtask : drive_addr_byte_ack - - virtual task drive_read_byte(); + virtual task drive_read_byte(bit [7:0] rdata); `uvm_create_obj(REQ, req); start_item(req); req.drv_type = RdData; - req.rdata = $urandom; + req.rdata = rdata; finish_item(req); `uvm_info(`gfn, "drive_read_byte()::finish_item()", UVM_DEBUG) endtask : drive_read_byte - virtual task drive_write_byte_ack(); - `uvm_create_obj(REQ, req); - start_item(req); - req.drv_type = DevAck; - finish_item(req); + drive_ack(); `uvm_info(`gfn, "drive_write_byte_ack()::finish_item()", UVM_DEBUG) endtask : drive_write_byte_ack diff --git a/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/seq_lib/i2c_device_response_seq.sv b/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/seq_lib/i2c_device_response_seq.sv index 60e8993f3..5eb2dea72 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/seq_lib/i2c_device_response_seq.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/seq_lib/i2c_device_response_seq.sv @@ -77,9 +77,8 @@ class i2c_device_response_seq extends i2c_base_seq; // This method hooks the start of every data byte in an inprogress READ transfer. // Fetch any read data from the local memory, and drive the data byte with this value. - virtual task drive_read_byte(); + virtual task drive_read_byte(bit [7:0] rdata); bit[Addr7BitMode-1:0] xfer_addr = inp_xfer.addr[Addr7BitMode-1:0]; - bit [7:0] rdata; if (response_mem[xfer_addr].size() == 0) begin // We haven't previously seen a write transfer at this address. There is no data to return. @@ -94,12 +93,7 @@ class i2c_device_response_seq extends i2c_base_seq; xfer_addr, rdata), UVM_DEBUG) // Drive the data byte - `uvm_create_obj(REQ, req); - start_item(req); - req.drv_type = RdData; - req.rdata = rdata; - finish_item(req); + super.drive_read_byte(rdata); endtask : drive_read_byte - endclass : i2c_device_response_seq diff --git a/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/seq_lib/i2c_target_may_nack_seq.sv b/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/seq_lib/i2c_target_may_nack_seq.sv index af66de763..7abf3e113 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/seq_lib/i2c_target_may_nack_seq.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/i2c_agent/seq_lib/i2c_target_may_nack_seq.sv @@ -23,39 +23,9 @@ class i2c_target_may_nack_seq extends i2c_base_seq; // METHODS // ///////////// - - virtual function void randomize_ack(); - `DV_CHECK_STD_RANDOMIZE_FATAL(acknack); - case (acknack) - i2c_pkg::ACK: req.drv_type = DevAck; - i2c_pkg::NACK: req.drv_type = DevNack; - default: `uvm_fatal(`gfn, "Shouldn't get here!") - endcase - endfunction : randomize_ack - - - virtual task drive_addr_byte_ack(); - `uvm_create_obj(REQ, req); - start_item(req); - - // The base class / default behaviour is to ACK all address bytes. - // Here, choose randomly between ACK and NACK. - randomize_ack(); - if (req.drv_type == DevNack) `uvm_info(`gfn, "NACKing the address byte!", UVM_LOW) - - finish_item(req); - endtask : drive_addr_byte_ack - - - virtual task drive_write_byte_ack(); - `uvm_create_obj(REQ, req); - start_item(req); - - randomize_ack(); - if (req.drv_type == DevNack) `uvm_info(`gfn, "NACKing a data byte!", UVM_LOW) - - finish_item(req); - endtask : drive_write_byte_ack - + // Return DevAck or DevNack with equal probability + protected virtual function drv_type_e get_ack_nack(); + return ($urandom_range(0,1) ? DevAck : DevNack); + endfunction endclass : i2c_target_may_nack_seq diff --git a/hw/vendor/lowrisc_ip/dv/sv/jtag_agent/jtag_agent.sv b/hw/vendor/lowrisc_ip/dv/sv/jtag_agent/jtag_agent.sv index ec9cae8b3..a6624361f 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/jtag_agent/jtag_agent.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/jtag_agent/jtag_agent.sv @@ -30,8 +30,17 @@ class jtag_agent extends dv_base_agent #( end if (cfg.is_active) begin + uvm_reg_map maps[$]; + cfg.jtag_dtm_ral.get_maps(maps); + if (maps.size() != 1) begin + `uvm_fatal(get_full_name(), + $sformatf("Cannot create JTAG DTM reg adapter: there are %0d reg maps.", + maps.size())) + end + m_jtag_dtm_reg_adapter = jtag_dtm_reg_adapter::type_id::create("m_jtag_dtm_reg_adapter"); - m_jtag_dtm_reg_adapter.cfg = cfg; + m_jtag_dtm_reg_adapter.set_ir_len(cfg.ir_len); + m_jtag_dtm_reg_adapter.set_reg_map(maps[0]); end endfunction diff --git a/hw/vendor/lowrisc_ip/dv/sv/jtag_agent/jtag_agent_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/jtag_agent/jtag_agent_pkg.sv index b8e810f89..a1b67c55d 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/jtag_agent/jtag_agent_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/jtag_agent/jtag_agent_pkg.sv @@ -6,6 +6,7 @@ package jtag_agent_pkg; // dep packages import uvm_pkg::*; import dv_utils_pkg::*; + import dv_base_agent_pkg::*; import dv_lib_pkg::*; import dv_base_reg_pkg::*; import csr_utils_pkg::*; diff --git a/hw/vendor/lowrisc_ip/dv/sv/jtag_agent/jtag_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/jtag_agent/jtag_driver.sv index e2816ae86..2ce1948ed 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/jtag_agent/jtag_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/jtag_agent/jtag_driver.sv @@ -37,8 +37,7 @@ class jtag_driver extends dv_base_driver #(jtag_item, jtag_agent_cfg); selected_ir_len = 0; endfunction - // do reset signals (function) - virtual function void do_reset_signals(); + task on_enter_reset(); `DV_CHECK_FATAL(cfg.if_mode == Host, "Only Host mode is supported", "jtag_driver") reset_internal_state(); @@ -46,7 +45,7 @@ class jtag_driver extends dv_base_driver #(jtag_item, jtag_agent_cfg); cfg.vif.tck_en <= 1'b0; cfg.vif._tms_internal <= 1'b0; cfg.vif._tdi_internal <= 1'b0; - endfunction + endtask // Turn on TCK in the jtag_if // @@ -79,16 +78,11 @@ class jtag_driver extends dv_base_driver #(jtag_item, jtag_agent_cfg); end join_none endtask - virtual task reset_signals(); + // Overriding the task from dv_base_driver. That tracks cfg.in_reset (which, in turn, follows + // cfg.vif.trst_n), but we also want to trigger a reset when jtag_if_connected is triggered. + task reset_signals(); fork - begin - do_reset_signals(); - forever begin - @(negedge cfg.vif.trst_n); - do_reset_signals(); - @(posedge cfg.vif.trst_n); - end - end + super.reset_signals(); forever begin cfg.jtag_if_connected.wait_trigger(); reset_internal_state(); diff --git a/hw/vendor/lowrisc_ip/dv/sv/jtag_agent/jtag_dtm_reg_adapter.sv b/hw/vendor/lowrisc_ip/dv/sv/jtag_agent/jtag_dtm_reg_adapter.sv index 89f6c0a14..acf7ab4d5 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/jtag_agent/jtag_dtm_reg_adapter.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/jtag_agent/jtag_dtm_reg_adapter.sv @@ -6,9 +6,11 @@ class jtag_dtm_reg_adapter extends uvm_reg_adapter; `uvm_object_utils(jtag_dtm_reg_adapter) - // Ensure that when an instance of this adapter is created, the cfg handle below is initialized - // to the `jtag_agent_cfg` instance associated with this adapter instance. - jtag_agent_cfg cfg; + // Used when producing bus items for reads. See notes above set_reg_block() for details. + local uvm_reg_map m_reg_map; + + // IR length to use in transactions. Set this with set_ir_len. + local int unsigned m_ir_len; function new(string name = ""); super.new(name); @@ -19,39 +21,78 @@ class jtag_dtm_reg_adapter extends uvm_reg_adapter; `DV_CHECK_GE_FATAL(`UVM_REG_DATA_WIDTH, JTAG_DRW) endfunction + // Pass a handle to a uvm_reg_map that represents the DTM registers. This will be used by the + // register adapter to generate bus items that represent register reads (in reg2bus). The tricky + // thing is that the only way to read a register over JTAG is to write something to it and then + // see the DR that comes out. In order for the stimulus to have as little impact as possible, this + // model allows a sequence to write the value that we currently believe is in the register. + // + // If there is no such map available, reg2bus will send a DR of zero to read a register. + function void set_reg_map(uvm_reg_map reg_map); + m_reg_map = reg_map; + endfunction + + // Set the IR length to use for transactions + function void set_ir_len(int unsigned ir_len); + if (!ir_len) `uvm_fatal(get_name(), "ir_len must be greater than zero.") + m_ir_len = ir_len; + endfunction + function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); jtag_item req; logic [JTAG_DRW-1:0] data; - // Per JTAG protocol, the DR is simultaneously written and read at the same time. That means, if - // we want to read a register, we need to write its DR with the same value we wrote before, to - // read it back. Otherwise, we will end up inadvertently writing 0s to it when reading it. To do - // so, we find the mirrored value of the register and set that to DR. Unfortunately, we do not - // know which map is associated with this adapter, so this does not support a multi-map system - // at this point. - if (rw.kind == UVM_READ) begin - jtag_dtm_base_reg rg; - uvm_reg_map maps[$]; - cfg.jtag_dtm_ral.get_maps(maps); - `DV_CHECK_EQ_FATAL(maps.size(), 1, $sformatf("Multiple maps in RAL %0s is not supported", - cfg.jtag_dtm_ral.get_full_name())) - `downcast(rg, maps[0].get_reg_by_offset(rw.addr)) - data = rg.get_wdata_for_read(); - end else begin - data = rw.data[JTAG_DRW-1:0]; - end + + data = (rw.kind == UVM_READ) ? get_wdata_for_read(rw.addr) : rw.data[JTAG_DRW-1:0]; req = jtag_item::type_id::create("req"); - `DV_CHECK_RANDOMIZE_WITH_FATAL(req, - ir_len == cfg.ir_len; - ir == rw.addr[JTAG_IRW-1:0]; - dr_len == rw.n_bits; - dr == local::data; - bus_op == (rw.kind == UVM_WRITE) ? dv_utils_pkg::BusOpWrite : dv_utils_pkg::BusOpRead; - skip_reselected_ir == 1;) + if (!req.randomize() with { + ir_len == m_ir_len; + ir == rw.addr[JTAG_IRW-1:0]; + dr_len == rw.n_bits; + dr == local::data; + bus_op == (rw.kind == UVM_WRITE) ? dv_utils_pkg::BusOpWrite : dv_utils_pkg::BusOpRead; + skip_reselected_ir == 1; + }) begin + `uvm_fatal(get_name(), "Failed to randomize JTAG item.") + end `uvm_info(`gfn, $sformatf("reg2bus: %0s", req.sprint(uvm_default_line_printer)), UVM_HIGH) return req; endfunction + // Get the value to send in DR that we believe is least likely to alter the current value of a + // register at addr. See notes above set_reg_map for more information. + local function uvm_reg_data_t get_wdata_for_read(uvm_reg_addr_t addr); + uvm_reg base_reg; + jtag_dtm_base_reg dtm_reg; + + if (m_reg_map == null) begin + // We don't seem to have a register map, so have no way to know whether there is a register at + // addr. This is a user error: the adapter should have been given a reg map before being used. + `uvm_error(get_name(), "A JTAG register adapter needs a reg_map to predict wdata for reads.") + return 0; + end + + base_reg = m_reg_map.get_reg_by_offset(addr); + if (base_reg == null) begin + // If we don't believe there is a register at addr, that's fine: we don't expect the access to + // work, but it doesn't really matter what to send in DR. + `uvm_info(get_name(), "Picking wdata of zero for read with no known register.", UVM_HIGH) + return 0; + end + + if (!$cast(dtm_reg, base_reg)) begin + // jtag_agent assumes that it will only access registers that are the special class + // jtag_dtm_base_reg (and therefore have a get_wdata_for_read function). We don't support + // arbitrary uvm_reg objects. + `uvm_error(get_name(), + $sformatf("Cannot predict wdata for read of %0s: it is not a jtag_dtm_base_reg.", + base_reg.get_name())) + return 0; + end + + return dtm_reg.get_wdata_for_read(); + endfunction + function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw); jtag_item rsp; `DV_CHECK_NE_FATAL(bus_item, null) diff --git a/hw/vendor/lowrisc_ip/dv/sv/jtag_dmi_agent/jtag_dmi_agent_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/jtag_dmi_agent/jtag_dmi_agent_pkg.sv index 40b034aa1..8bad3a2f1 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/jtag_dmi_agent/jtag_dmi_agent_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/jtag_dmi_agent/jtag_dmi_agent_pkg.sv @@ -8,6 +8,7 @@ package jtag_dmi_agent_pkg; import dv_utils_pkg::*; import dv_base_reg_pkg::*; import csr_utils_pkg::*; + import dv_base_agent_pkg::*; import dv_lib_pkg::*; import jtag_agent_pkg::*; @@ -39,6 +40,10 @@ package jtag_dmi_agent_pkg; // Convenience function to create JTAG DMI RAL block. function automatic jtag_dmi_reg_block create_jtag_dmi_reg_block(jtag_agent_cfg cfg); jtag_dmi_reg_block jtag_dmi_ral = jtag_dmi_reg_block::type_id::create("jtag_dmi_ral"); + jtag_dtm_reg_block jtag_dtm_ral = cfg.jtag_dtm_ral; + jtag_dtm_reg_dmi dmi_reg = jtag_dtm_ral.dmi; + jtag_dtm_reg_dtmcs dtmcs_reg = jtag_dtm_ral.dtmcs; + jtag_dmi_ral.build(.base_addr(0), .csr_excl(null)); jtag_dmi_ral.set_supports_byte_enable(1'b0); jtag_dmi_ral.lock_model(); @@ -52,7 +57,7 @@ package jtag_dmi_agent_pkg; jtag_dmi_ral.get_registers(rg); foreach (rg[i]) begin jtag_dmi_reg_frontdoor ftdr = jtag_dmi_reg_frontdoor::type_id::create("ftdr"); - ftdr.jtag_agent_cfg_h = cfg; + ftdr.configure(cfg, dmi_reg, dtmcs_reg); ftdr.jtag_dtm_ral_sem_h = sem; rg[i].set_frontdoor(ftdr); end diff --git a/hw/vendor/lowrisc_ip/dv/sv/jtag_dmi_agent/jtag_dmi_monitor.sv b/hw/vendor/lowrisc_ip/dv/sv/jtag_dmi_agent/jtag_dmi_monitor.sv index 90ccda448..e612859c6 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/jtag_dmi_agent/jtag_dmi_monitor.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/jtag_dmi_agent/jtag_dmi_monitor.sv @@ -24,13 +24,24 @@ class jtag_dmi_monitor #(type ITEM_T = jtag_dmi_item) extends dv_base_monitor#( // Does the JTAG FSM currently have an instruction register equal to the DMI address? bit dmi_selected = 1'b0; + // A uvm_reg representing a DMI register. This isn't really being monitored in the design (so + // doesn't have to be related to any model), but makes it convenient to access register field + // values from monitored traffic. + local jtag_dtm_reg_dmi m_dmi_reg; - `uvm_component_new + // The IR of the DMI register that is being monitored. Set this with set_dmi_address(). + local uvm_reg_addr_t m_dmi_address = '1; + + function new (string name, uvm_component parent); + super.new(name, parent); + m_dmi_reg = jtag_dtm_reg_dmi::type_id::create("m_dmi_reg"); + endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); jtag_item_fifo = new("jtag_item_fifo", this); non_dmi_jtag_dtm_analysis_port = new("non_dmi_jtag_dtm_analysis_port", this); + m_dmi_reg.build(); endfunction task run_phase(uvm_phase phase); @@ -40,9 +51,19 @@ class jtag_dmi_monitor #(type ITEM_T = jtag_dmi_item) extends dv_base_monitor#( join endtask + // Set the address of the DMI register that is being monitored. + function void set_dmi_address(uvm_reg_addr_t addr); + if (&addr) `uvm_fatal(get_full_name(), "The DMI address can't possibly be '1.") + m_dmi_address = addr; + endfunction + virtual protected task collect_trans(); jtag_item jtag_item; + if (&m_dmi_address) begin + `uvm_fatal(get_full_name(), "Cannot collect transactions as we don't know the DMI address.") + end + forever begin bit is_ir_update, is_dr_update; @@ -60,7 +81,7 @@ class jtag_dmi_monitor #(type ITEM_T = jtag_dmi_item) extends dv_base_monitor#( // If this is an IR update, update our dmi_selected flag to reflect the new IR. if (is_ir_update) begin - dmi_selected = (jtag_item.ir == cfg.jtag_dtm_ral.dmi.get_address()); + dmi_selected = (jtag_item.ir == m_dmi_address); end // If we're not currently operating on the DMI register, pass the item to our non-DMI analysis @@ -89,8 +110,7 @@ class jtag_dmi_monitor #(type ITEM_T = jtag_dmi_item) extends dv_base_monitor#( // Returns true if the response was captured, or if there was no previous request, false if the // response returned was busy. virtual function bit capture_response(jtag_item jtag_item); - jtag_dmi_op_rsp_e rsp_op = jtag_dmi_op_rsp_e'( - get_field_val(cfg.jtag_dtm_ral.dmi.op, jtag_item.dout)); + jtag_dmi_op_rsp_e rsp_op = jtag_dmi_op_rsp_e'(get_field_val(m_dmi_reg.op, jtag_item.dout)); if (dmi_req_q.size() != 0) begin if (rsp_op == DmiOpInProgress) begin @@ -99,8 +119,7 @@ class jtag_dmi_monitor #(type ITEM_T = jtag_dmi_item) extends dv_base_monitor#( ITEM_T dmi_item = dmi_req_q.pop_front(); dmi_item.rsp_op = rsp_op; if (dmi_item.req_op == DmiOpRead) begin - uvm_reg_data_t data = get_field_val(cfg.jtag_dtm_ral.dmi.data, - jtag_item.dout); + uvm_reg_data_t data = get_field_val(m_dmi_reg.data, jtag_item.dout); dmi_item.rdata = data; end `uvm_info(`gfn, $sformatf("Writing DMI item to analysis_port: %0s", @@ -117,16 +136,14 @@ class jtag_dmi_monitor #(type ITEM_T = jtag_dmi_item) extends dv_base_monitor#( // Capture a new DMI request. virtual function void capture_request(jtag_item jtag_item); - jtag_dmi_op_req_e req_op = jtag_dmi_op_req_e'( - get_field_val(cfg.jtag_dtm_ral.dmi.op, jtag_item.dr)); + jtag_dmi_op_req_e req_op = jtag_dmi_op_req_e'(get_field_val(m_dmi_reg.op, jtag_item.dr)); if (req_op inside {DmiOpRead, DmiOpWrite}) begin ITEM_T dmi_item = ITEM_T::type_id::create("dmi_item"); dmi_item.req_op = req_op; - dmi_item.addr = uvm_reg_addr_t'( - get_field_val(cfg.jtag_dtm_ral.dmi.address, jtag_item.dr)); + dmi_item.addr = uvm_reg_addr_t'(get_field_val(m_dmi_reg.address, jtag_item.dr)); if (req_op == DmiOpWrite) begin - dmi_item.wdata = get_field_val(cfg.jtag_dtm_ral.dmi.data, jtag_item.dr); + dmi_item.wdata = get_field_val(m_dmi_reg.data, jtag_item.dr); end `uvm_info(`gfn, $sformatf("Writing DMI req to req_analysis_port: %0s", dmi_item.sprint(uvm_default_line_printer)), UVM_HIGH) diff --git a/hw/vendor/lowrisc_ip/dv/sv/jtag_dmi_agent/jtag_dmi_reg_frontdoor.sv b/hw/vendor/lowrisc_ip/dv/sv/jtag_dmi_agent/jtag_dmi_reg_frontdoor.sv index ce7316422..d164444b1 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/jtag_dmi_agent/jtag_dmi_reg_frontdoor.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/jtag_dmi_agent/jtag_dmi_reg_frontdoor.sv @@ -9,8 +9,15 @@ class jtag_dmi_reg_frontdoor extends uvm_reg_frontdoor; `uvm_object_utils(jtag_dmi_reg_frontdoor) - // Handle to JTAG agent cfg which has the handle to the DTM RAL model and the vif. - jtag_agent_cfg jtag_agent_cfg_h; + // Handle to JTAG agent cfg (with the virtual interface) + local jtag_agent_cfg m_agent_cfg; + + // Handle to the modelled DMI register (which allows the next layer down of front-door access) + local jtag_dtm_reg_dmi m_dmi_reg; + + // Handle to the modelled DTMCS register (used when writing dmireset to clear the sticky + // "operation in progress" flag). + local jtag_dtm_reg_dtmcs m_dtmcs_reg; // The same frontdoor instance can be attached to all DMI registers, since they all need to be // accessed via the same shared resource (the DTM DMI register). The semaphore ensures atomicity. @@ -18,19 +25,37 @@ class jtag_dmi_reg_frontdoor extends uvm_reg_frontdoor; // object. semaphore jtag_dtm_ral_sem_h; - `uvm_object_new + function new(string name=""); + super.new(name); + endfunction + + // Configure this frontdoor by passing it a JTAG agent configuration (used for interface access). + // Also, pass a uvm_reg that tracks the DMI register, through which all accesses will flow, and a + // uvm_reg that tracks the DTMCS register (needed in order to clear an operation-in-progress + // flag). + function void configure(jtag_agent_cfg agent_cfg, + jtag_dtm_reg_dmi dmi_reg, + jtag_dtm_reg_dtmcs dtmcs_reg); + m_agent_cfg = agent_cfg; + m_dmi_reg = dmi_reg; + m_dtmcs_reg = dtmcs_reg; + endfunction virtual task body(); csr_field_t csr_or_fld; uvm_reg_data_t wdata = 0; - jtag_dtm_reg_block jtag_dtm_ral = jtag_agent_cfg_h.jtag_dtm_ral; + + // Check that configure() has been called + if ((m_agent_cfg == null) || (m_dmi_reg == null) || (m_dtmcs_reg == null)) begin + `uvm_fatal(get_name(), "Frontdoor not configured: it needs JTAG agent cfg and dmi/dtmcs regs") + end // Configure the JTAG agent to have a positive run-to-clear length, ensuring that DMI operations // make it from dmi_jtag to dm_top and back again before TCK stops. - jtag_agent_cfg_h.rtc_length = 4; + m_agent_cfg.rtc_length = 4; // If the JTAG agent is sitting in reset, print a debug message and exit early - if (jtag_agent_cfg_h.in_reset) begin + if (m_agent_cfg.in_reset) begin `uvm_info(`gfn, "DMI CSR req skipped due to reset", UVM_HIGH) return; end @@ -62,19 +87,19 @@ class jtag_dmi_reg_frontdoor extends uvm_reg_frontdoor; // At this point, wdata is zero if this is a UVM_READ and is the write value for the CSR if this // is a UVM_WRITE. Shift the bits as necessary so that they are laid out in the right place for // the data field inside the DMI register. - wdata = get_csr_val_with_updated_field(jtag_dtm_ral.dmi.data, '0, wdata); + wdata = get_csr_val_with_updated_field(m_dmi_reg.data, '0, wdata); // Add in the op and address fields. When this is done, wdata is suitable for writing over JTAG // in order to perform the requested DMI operation (read or write). - wdata = get_csr_val_with_updated_field(jtag_dtm_ral.dmi.op, wdata, + wdata = get_csr_val_with_updated_field(m_dmi_reg.op, wdata, (rw_info.kind == UVM_WRITE ? DmiOpWrite : DmiOpRead)); - wdata = get_csr_val_with_updated_field(jtag_dtm_ral.dmi.address, wdata, + wdata = get_csr_val_with_updated_field(m_dmi_reg.address, wdata, csr_or_fld.csr.get_address()); // Start the DMI request. - csr_wr(.ptr(jtag_dtm_ral.dmi), .value(wdata), .blocking(1), .predict(1)); + csr_wr(.ptr(m_dmi_reg), .value(wdata), .blocking(1), .predict(1)); - if (jtag_agent_cfg_h.in_reset) begin + if (m_agent_cfg.in_reset) begin `uvm_info(`gfn, "DMI operation aborted: reset happened in middle of request", UVM_HIGH) jtag_dtm_ral_sem_h.put(); return; @@ -85,12 +110,12 @@ class jtag_dmi_reg_frontdoor extends uvm_reg_frontdoor; // a reset in the middle of the wait, stop immediately. fork begin fork - jtag_agent_cfg_h.vif.wait_tck(10); - wait(jtag_agent_cfg_h.in_reset); + m_agent_cfg.vif.wait_tck(10); + wait(m_agent_cfg.in_reset); join_any disable fork; end join - if (jtag_agent_cfg_h.in_reset) begin + if (m_agent_cfg.in_reset) begin `uvm_info(`gfn, "DMI operation aborted: reset happened in middle of request", UVM_HIGH) jtag_dtm_ral_sem_h.put(); return; @@ -104,10 +129,10 @@ class jtag_dmi_reg_frontdoor extends uvm_reg_frontdoor; fork begin - poll_for_completion(jtag_dtm_ral, csr_or_fld.field); + poll_for_completion(csr_or_fld.field); saw_completion = 1'b1; end - jtag_agent_cfg_h.vif.wait_tck(10_000); + m_agent_cfg.vif.wait_tck(10_000); join_any // The DMI operation should have completed in the time we were waiting @@ -128,21 +153,21 @@ class jtag_dmi_reg_frontdoor extends uvm_reg_frontdoor; // // If there is a reset while we are waiting for completion, stop and set rw_info.status to // UVM_NOT_OK. - task poll_for_completion(jtag_dtm_reg_block jtag_dtm_ral, uvm_reg_field field); + local task poll_for_completion(uvm_reg_field field); forever begin uvm_reg_data_t rdata; jtag_dmi_op_rsp_e op_rsp; // Try to read the DMI register over JTAG - csr_rd(.ptr(jtag_dtm_ral.dmi), .value(rdata), .blocking(1)); + csr_rd(.ptr(m_dmi_reg), .value(rdata), .blocking(1)); // If there was a JTAG reset in the meantime, set rw_info.status to UVM_NOT_OK and return. - if (jtag_agent_cfg_h.in_reset) begin + if (m_agent_cfg.in_reset) begin rw_info.status = UVM_NOT_OK; return; end - op_rsp = jtag_dmi_op_rsp_e'(get_field_val(jtag_dtm_ral.dmi.op, rdata)); + op_rsp = jtag_dmi_op_rsp_e'(get_field_val(m_dmi_reg.op, rdata)); `uvm_info(`gfn, $sformatf("DMI CSR req status: %0s", op_rsp.name()), UVM_HIGH) // If op_rsp isn't DmiOpInProgress then the DMI operation has run to completion. Write the @@ -150,7 +175,7 @@ class jtag_dmi_reg_frontdoor extends uvm_reg_frontdoor; if (op_rsp != DmiOpInProgress) begin rw_info.status = op_rsp == DmiOpOk ? UVM_IS_OK : UVM_NOT_OK; if (rw_info.kind == UVM_READ) begin - rdata = get_field_val(jtag_dtm_ral.dmi.data, rdata); + rdata = get_field_val(m_dmi_reg.data, rdata); if (field != null) begin rdata = get_field_val(field, rdata); end @@ -161,11 +186,11 @@ class jtag_dmi_reg_frontdoor extends uvm_reg_frontdoor; end // Otherwise, the operation was still in progress. Clear the (sticky) flag. - csr_wr(.ptr(jtag_dtm_ral.dtmcs.dmireset), .value(1), .blocking(1), .predict(1)); + csr_wr(.ptr(m_dtmcs_reg.dmireset), .value(1), .blocking(1), .predict(1)); // Check there hasn't been a JTAG reset while we were clearing the "op in progress" flag. If // not, we'll go around again (and read the DMI register again) - if (jtag_agent_cfg_h.in_reset) begin + if (m_agent_cfg.in_reset) begin rw_info.status = UVM_NOT_OK; return; end diff --git a/hw/vendor/lowrisc_ip/dv/sv/jtag_dmi_agent/jtag_rv_debugger_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/jtag_dmi_agent/jtag_rv_debugger_pkg.sv index 1a5b7c632..416e5799b 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/jtag_dmi_agent/jtag_rv_debugger_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/jtag_dmi_agent/jtag_rv_debugger_pkg.sv @@ -22,6 +22,7 @@ package jtag_rv_debugger_pkg; import bus_params_pkg::*; import dv_base_reg_pkg::*; import csr_utils_pkg::*; + import dv_base_agent_pkg::*; import dv_lib_pkg::*; import jtag_agent_pkg::*; import jtag_dmi_agent_pkg::*; diff --git a/hw/vendor/lowrisc_ip/dv/sv/jtag_riscv_agent/jtag_riscv_agent_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/jtag_riscv_agent/jtag_riscv_agent_pkg.sv index 7109f332a..5cc5063f8 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/jtag_riscv_agent/jtag_riscv_agent_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/jtag_riscv_agent/jtag_riscv_agent_pkg.sv @@ -6,6 +6,7 @@ package jtag_riscv_agent_pkg; // dep packages import uvm_pkg::*; import dv_utils_pkg::*; + import dv_base_agent_pkg::*; import dv_lib_pkg::*; import jtag_agent_pkg::*; diff --git a/hw/vendor/lowrisc_ip/dv/sv/jtag_riscv_agent/jtag_riscv_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/jtag_riscv_agent/jtag_riscv_driver.sv index 958a45c6c..9b359b29b 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/jtag_riscv_agent/jtag_riscv_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/jtag_riscv_agent/jtag_riscv_driver.sv @@ -12,22 +12,29 @@ class jtag_riscv_driver extends dv_base_driver #(jtag_riscv_item, jtag_riscv_age super.new(name, parent); endfunction - virtual task reset_signals(); - forever begin - wait (cfg.in_reset == 1); - `uvm_info(`gfn, "reset_signals: cfg.in_reset=1'b1", UVM_MEDIUM) - - do_hard_reset = 1; - // Assert JTAG TRST - // This clears the DMI Request and Response FIFOs. - cfg.m_jtag_agent_cfg.vif.do_trst_n(2); - cfg.rv_dm_activated = 0; + task reset_signals(); + fork + super.reset_signals(); + forever begin + wait(cfg.in_reset); + // Assert JTAG TRST + // This clears the DMI Request and Response FIFOs. + cfg.m_jtag_agent_cfg.vif.do_trst_n(2); + wait(!cfg.in_reset); + end + join + endtask - wait (cfg.in_reset == 0); - `uvm_info(`gfn, "reset_signals: cfg.in_reset=1'b0", UVM_MEDIUM) - end + task on_enter_reset(); + `uvm_info(`gfn, "on_enter_reset: cfg.in_reset=1'b1", UVM_MEDIUM) + do_hard_reset = 1; + cfg.rv_dm_activated = 0; endtask + function void on_leave_reset(); + `uvm_info(`gfn, "on_leave_reset: cfg.in_reset=1'b0", UVM_MEDIUM) + endfunction + // drive trans received from sequencer virtual task get_and_drive(); `uvm_info(`gfn, "get_and_drive: STARTED", UVM_MEDIUM) diff --git a/hw/vendor/lowrisc_ip/dv/sv/key_sideload_agent/key_sideload_agent_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/key_sideload_agent/key_sideload_agent_pkg.sv index 5d47b8995..04e4e4840 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/key_sideload_agent/key_sideload_agent_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/key_sideload_agent/key_sideload_agent_pkg.sv @@ -6,6 +6,7 @@ package key_sideload_agent_pkg; // dep packages import uvm_pkg::*; import dv_utils_pkg::*; + import dv_base_agent_pkg::*; import dv_lib_pkg::*; // macro includes diff --git a/hw/vendor/lowrisc_ip/dv/sv/key_sideload_agent/key_sideload_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/key_sideload_agent/key_sideload_driver.sv index c4d2d9c39..2ffb699a3 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/key_sideload_agent/key_sideload_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/key_sideload_agent/key_sideload_driver.sv @@ -11,10 +11,11 @@ class key_sideload_driver#( // the base class provides the following handles for use: // key_sideload_agent_cfg: cfg - `uvm_component_new + function new (string name, uvm_component parent); + super.new(name, parent); + endfunction - // reset signals - virtual task reset_signals(); + task on_enter_reset(); cfg.vif.sideload_key.valid = 0; cfg.vif.sideload_key.key[0] = 'x; cfg.vif.sideload_key.key[1] = 'x; @@ -27,22 +28,14 @@ class key_sideload_driver#( $cast(rsp, req.clone()); rsp.set_id_info(req); `uvm_info(`gfn, $sformatf("rcvd item:\n%0s", req.sprint()), UVM_HIGH) + cfg.vif.sideload_key.valid = req.valid; - if (req.valid) begin - cfg.vif.sideload_key.key[0] = req.key0; - cfg.vif.sideload_key.key[1] = req.key1; - end - else begin - cfg.vif.sideload_key.key[0] = 'x; - cfg.vif.sideload_key.key[1] = 'x; - end - // Always wait for one clock cycle. Otherwise, this task may consume zero time while the - // reset is active. This would be problematic as it would cause the key sideload interface - // to be updated endlessly and the DV environment to hang. - cfg.vif.wait_clks(1); - // send rsp back to seq + cfg.vif.sideload_key.key[0] = req.valid ? req.key0 : 'x; + cfg.vif.sideload_key.key[1] = req.valid ? req.key1 : 'x; `uvm_info(`gfn, "item sent", UVM_HIGH) - cfg.vif.wait_clks_or_rst(req.rsp_delay); + + cfg.vif.wait_clks_or_rst(1 + req.rsp_delay); + seq_item_port.item_done(req); end endtask diff --git a/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_agent.core b/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_agent.core index acaf70c5f..79527ccb5 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_agent.core +++ b/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_agent.core @@ -10,6 +10,7 @@ filesets: - lowrisc:dv:dv_utils - lowrisc:dv:dv_lib - lowrisc:dv:push_pull_agent + - lowrisc:ip:keymgr_pkg - lowrisc:ip:kmac_pkg files: - kmac_app_agent_pkg.sv diff --git a/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_agent_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_agent_pkg.sv index 572b53642..6af1f15d9 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_agent_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_agent_pkg.sv @@ -6,7 +6,9 @@ package kmac_app_agent_pkg; // dep packages import uvm_pkg::*; import dv_utils_pkg::*; + import dv_base_agent_pkg::*; import dv_lib_pkg::*; + import keymgr_pkg::*; import push_pull_agent_pkg::*; // macro includes @@ -14,10 +16,9 @@ package kmac_app_agent_pkg; `include "dv_macros.svh" // parameters - parameter int KmacDataIfWidth = 64; // keymgr_pkg::KmacDataIfWidth - parameter int KMAC_REQ_DATA_WIDTH = KmacDataIfWidth // data width - + KmacDataIfWidth / 8 // data mask width - + 1; // bit last + parameter int KMAC_REQ_DATA_WIDTH = keymgr_pkg::KmacDataIfWidth // data width + + keymgr_pkg::KmacDataIfWidth / 8 // data mask width + + 1; // bit last `define CONNECT_DATA_WIDTH .HostDataWidth(kmac_app_agent_pkg::KMAC_REQ_DATA_WIDTH) diff --git a/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_device_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_device_driver.sv index fe3ecfbb9..cac295b88 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_device_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_device_driver.sv @@ -6,9 +6,7 @@ class kmac_app_device_driver extends kmac_app_driver; `uvm_component_utils(kmac_app_device_driver) `uvm_component_new - - // reset signals - virtual task reset_signals(); + task on_enter_reset(); invalidate_signals(); endtask diff --git a/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_host_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_host_driver.sv index 39b8b47a3..36fadfbf1 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_host_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_host_driver.sv @@ -6,9 +6,6 @@ class kmac_app_host_driver extends kmac_app_driver; `uvm_component_utils(kmac_app_host_driver) `uvm_component_new - virtual task reset_signals(); - endtask - virtual task get_and_drive(); endtask diff --git a/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_intf.sv b/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_intf.sv index b5c926cb4..8fe2c4116 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_intf.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/kmac_app_agent/kmac_app_intf.sv @@ -5,6 +5,8 @@ // verilog_lint: waive interface-name-style interface kmac_app_intf (input clk, input rst_n); + import keymgr_pkg::*; + dv_utils_pkg::if_mode_e if_mode; // interface mode - Host or Device // interface pins used to connect with DUT @@ -58,7 +60,7 @@ interface kmac_app_intf (input clk, input rst_n); clk, !rst_n || if_mode == dv_utils_pkg::Host) // Check strb is aligned to LSB, for example: if strb[1]==0, strb[$:2] should be 0 too - for (genvar k = 1; k < kmac_app_agent_pkg::KmacDataIfWidth / 8 - 1; k++) begin : gen_strb_check + for (genvar k = 1; k < KmacDataIfWidth / 8 - 1; k++) begin : gen_strb_check `ASSERT(StrbAlignLSB_A, kmac_data_req.valid && kmac_data_req.strb[k] === 0 |-> kmac_data_req.strb[k+1] === 0, clk, !rst_n || if_mode == dv_utils_pkg::Host) diff --git a/hw/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util.sv b/hw/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util.sv index 0c06d7ecb..802801b95 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util.sv @@ -184,7 +184,7 @@ class mem_bkdr_util extends uvm_object; byte_width = `HAS_PARITY ? 9 : 8; bytes_per_word = data_width / byte_width; - `DV_CHECK_LE_FATAL(bytes_per_word, 32, "data width > 32 bytes is not supported") + `DV_CHECK_LE_FATAL(bytes_per_word, 64, "data width > 64 bytes is not supported") size_bytes = depth * bytes_per_word; addr_lsb = $clog2(bytes_per_word); addr_width = $clog2(depth); @@ -299,25 +299,55 @@ class mem_bkdr_util extends uvm_object; return 1'b1; endfunction - // Read the entire word at the given address. + // Read the memory row that contains the given address. // - // addr is the byte address starting at offset 0. Mask the upper address bits as needed before + // addr is the byte address, starting at offset 0. Mask the upper address bits as needed before // invocation. // // Returns the entire width of the memory at the given address, including the ECC bits. The data // returned is 'raw' i.e. it includes the parity bits. It also does not de-scramble the data if // encryption is enabled. - virtual function uvm_hdl_data_t read(bit [bus_params_pkg::BUS_AW-1:0] addr); - bit res; - uint32_t index, ram_tile; - uvm_hdl_data_t encoded_row, data; + virtual function row_data_t read(bit [bus_params_pkg::BUS_AW-1:0] addr); + int unsigned row_index, rel_row_index, row_width; + string tile_path; + row_data_t encoded_row = 0; + if (!check_addr_valid(addr)) return 'x; - index = addr >> addr_lsb; - ram_tile = index / tile_depth; - res = uvm_hdl_read($sformatf("%0s[%0d]", get_full_path(ram_tile), index), encoded_row); - `DV_CHECK_EQ(res, 1, $sformatf("uvm_hdl_read failed at index %0d", index)) - data = row_adapter.decode_row(encoded_row); - return data; + + // Convert addr to the index of the row (there are 2 ** addr_lsb items in each row) + row_index = addr >> this.addr_lsb; + + // Get an HDL path for tile that contains this row index, then reduce the row index to be + // relative to the tile. + tile_path = this.get_full_path(row_index / this.tile_depth); + rel_row_index = row_index % this.tile_depth; + + // The row itself contains this.width data bits plus (possibly) some extra bits, as defined by + // the row adapter. + row_width = this.width + this.row_adapter.get_num_extra_bits(); + + for (int unsigned lsb = 0; lsb < row_width; lsb += bits_per_backdoor_access) begin + int unsigned msb = lsb + bits_per_backdoor_access - 1; + uvm_hdl_data_t data; + string access_path; + + // If bits_per_backdoor_access doesn't divide row_width, the last access will be to a few bits + // at the top of the row. The code here trims things so that we don't fall off the end. + if (msb >= row_width) begin + msb = row_width - 1; + end + + access_path = $sformatf("%0s[%0d][%0d:%0d]", tile_path, rel_row_index, msb, lsb); + + if (!uvm_hdl_read(access_path, data)) begin + `uvm_error(get_name(), + $sformatf("Failed to access %0s with uvm_hdl_read.", access_path)) + end + + encoded_row |= row_data_t'(data) << lsb; + end + + return this.row_adapter.decode_row(encoded_row); endfunction // Convenience macro to check the addr for each flavor of read and write functions. @@ -328,7 +358,7 @@ class mem_bkdr_util extends uvm_object; // // The data returned does not include the parity bits. virtual function logic [7:0] read8(bit [bus_params_pkg::BUS_AW-1:0] addr); - uvm_hdl_data_t data = read(addr); + row_data_t data = read(addr); int byte_offset = addr % bytes_per_word; return (data >> (byte_offset * byte_width)) & 8'hff; endfunction @@ -423,17 +453,48 @@ class mem_bkdr_util extends uvm_object; // invocation. // // Updates the entire width of the memory at the given address, including the ECC bits. - virtual function void write(bit [bus_params_pkg::BUS_AW-1:0] addr, uvm_hdl_data_t data); - bit res; - uvm_hdl_data_t encoded_row; - uint32_t index, ram_tile; + virtual function void write(bit [bus_params_pkg::BUS_AW-1:0] addr, row_data_t data); + row_data_t encoded_row; + int unsigned row_index, rel_row_index, row_width; + string tile_path; + if (!check_addr_valid(addr)) return; - index = addr >> addr_lsb; - ram_tile = index / tile_depth; - encoded_row = row_adapter.encode_row(data); - res = uvm_hdl_deposit($sformatf("%0s[%0d]", get_full_path(ram_tile), index), - encoded_row); - `DV_CHECK_EQ(res, 1, $sformatf("uvm_hdl_deposit failed at index %0d", index)) + + // Convert addr to the row_index of the row (there are 2 ** addr_lsb items in each row) + row_index = addr >> this.addr_lsb; + + // Get an HDL path for tile that contains this row index, then reduce the row index to be + // relative to the tile. + tile_path = this.get_full_path(row_index / this.tile_depth); + rel_row_index = row_index % this.tile_depth; + + // The row itself contains this.width data bits plus (possibly) some extra bits, as defined by + // the row adapter. + row_width = this.width + this.row_adapter.get_num_extra_bits(); + + encoded_row = this.row_adapter.encode_row(data); + + for (int unsigned lsb = 0; lsb < row_width; lsb += bits_per_backdoor_access) begin + int unsigned msb = lsb + bits_per_backdoor_access - 1; + string access_path; + int unsigned access_width; + uvm_hdl_data_t wmask, wdata; + + if (msb >= row_width) begin + msb = row_width - 1; + end + + access_path = $sformatf("%0s[%0d][%0d:%0d]", tile_path, rel_row_index, msb, lsb); + access_width = msb - lsb + 1; + + wmask = (1 << access_width) - 1; + wdata = (encoded_row >> lsb) & wmask; + + if (!uvm_hdl_deposit(access_path, wdata)) begin + `uvm_error(get_name(), + $sformatf("Failed to access %0s with uvm_hdl_deposit.", access_path)) + end + end endfunction // Write a single byte at specified address. @@ -441,7 +502,7 @@ class mem_bkdr_util extends uvm_object; // Does a read-modify-write on the whole word. It updates the byte at the given address and // computes the parity and ECC bits as applicable. virtual function void write8(bit [bus_params_pkg::BUS_AW-1:0] addr, logic [7:0] data); - uvm_hdl_data_t rw_data; + row_data_t rw_data; uint32_t word_idx; uint32_t byte_idx; @@ -484,7 +545,7 @@ class mem_bkdr_util extends uvm_object; // this is used to write 32bit of data plus 7 raw integrity bits. virtual function void write39integ(bit [bus_params_pkg::BUS_AW-1:0] addr, logic [38:0] data); - uvm_hdl_data_t rw_data; + row_data_t rw_data; `_ACCESS_CHECKS(addr, 32) // this is essentially an aligned 32bit access. if (!check_addr_valid(addr)) return; // Perform a read-modify-write to access the underlying memory architecture @@ -526,7 +587,7 @@ class mem_bkdr_util extends uvm_object; // Intended for use with memories which have data width of 16 bits and 6 ECC bits. virtual function secded_22_16_t ecc_read16(bit [bus_params_pkg::BUS_AW-1:0] addr); - uvm_hdl_data_t data; + row_data_t data; if (!check_addr_valid(addr)) return 'x; data = read(addr); case (err_detection_scheme) @@ -548,7 +609,7 @@ class mem_bkdr_util extends uvm_object; // Intended for use with memories which have data width of 32 bits and 7 ECC bits. virtual function secded_39_32_t ecc_read32(bit [bus_params_pkg::BUS_AW-1:0] addr); - uvm_hdl_data_t data; + row_data_t data; if (!check_addr_valid(addr)) return 'x; data = read(addr); case (err_detection_scheme) @@ -570,7 +631,7 @@ class mem_bkdr_util extends uvm_object; // Intended for use with memories which have data width of 64 bits and 8 ECC bits. virtual function secded_72_64_t ecc_read64(bit [bus_params_pkg::BUS_AW-1:0] addr); - uvm_hdl_data_t data; + row_data_t data; if (!check_addr_valid(addr)) return 'x; data = read(addr); case (err_detection_scheme) @@ -643,7 +704,7 @@ class mem_bkdr_util extends uvm_object; virtual function void print_mem(); `uvm_info(`gfn, "Print memory", UVM_LOW) for (int i = 0; i < depth; i++) begin - uvm_hdl_data_t data = read(i * bytes_per_word); + row_data_t data = read(i * bytes_per_word); `uvm_info(`gfn, $sformatf("mem[%0d] = 0x%0h", i, data), UVM_LOW) end endfunction @@ -652,7 +713,7 @@ class mem_bkdr_util extends uvm_object; virtual function void clear_mem(); `uvm_info(`gfn, "Clear memory", UVM_LOW) for (int i = 0; i < depth; i++) begin - uvm_hdl_data_t data = '{default:0}; + row_data_t data = '{default:0}; write(i * bytes_per_word, data); end endfunction @@ -661,7 +722,7 @@ class mem_bkdr_util extends uvm_object; virtual function void set_mem(); `uvm_info(`gfn, "Set memory", UVM_LOW) for (int i = 0; i < depth; i++) begin - uvm_hdl_data_t data = '{default:1}; + row_data_t data = '{default:1}; write(i * bytes_per_word, data); end endfunction @@ -670,10 +731,10 @@ class mem_bkdr_util extends uvm_object; virtual function void randomize_mem(); `uvm_info(`gfn, "Randomizing mem contents", UVM_LOW) for (int i = 0; i < depth; i++) begin - uvm_hdl_data_t data; + row_data_t data; `DV_CHECK_STD_RANDOMIZE_FATAL(data, "Randomization failed!", path) if (`HAS_PARITY) begin - uvm_hdl_data_t raw_data = data; + row_data_t raw_data = data; for (int byte_idx = 0; byte_idx < bytes_per_word; byte_idx++) begin bit raw_byte = raw_data[byte_idx * 8 +: 8]; bit parity = (err_detection_scheme == ParityOdd) ? ~(^raw_byte) : (^raw_byte); @@ -690,7 +751,7 @@ class mem_bkdr_util extends uvm_object; virtual function void invalidate_mem(); `uvm_info(`gfn, "Invalidating (Xs) mem contents", UVM_LOW) for (int i = 0; i < depth; i++) begin - uvm_hdl_data_t data; + row_data_t data; write(i * bytes_per_word, data); end endfunction @@ -698,7 +759,7 @@ class mem_bkdr_util extends uvm_object; // Inject ECC or parity errors to the memory word at the given address. virtual function void inject_errors(bit [bus_params_pkg::BUS_AW-1:0] addr, uint32_t inject_num_errors); - uvm_hdl_data_t rw_data, err_mask; + row_data_t rw_data, err_mask; if (!check_addr_valid(addr)) return; `DV_CHECK_LE_FATAL(inject_num_errors, max_errors) `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(err_mask, diff --git a/hw/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util_pkg.sv index 1a7f60307..50d45123d 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util_pkg.sv @@ -10,6 +10,18 @@ package mem_bkdr_util_pkg; import prim_secded_pkg::*; import uvm_pkg::*; + // A data row in the memory. + // + // The width is arbitrary and can safely be changed in the future. The initial value of 1024 bits + // matches the standard width of uvm_hdl_data_t. + // + // Note that this uses 4-state logic, which allows the row to contain 'x values. + typedef logic [1023:0] row_data_t; + + // The number of bits used in each backdoor read from / write to memory. This must be small enough + // to fit in a uvm_hdl_data_t. + int unsigned bits_per_backdoor_access = 256; + // Represents the various forms of error detection / correction supported. typedef enum int { ErrDetectionNone = prim_secded_pkg::SecdedNone, diff --git a/hw/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util_row_adapter.sv b/hw/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util_row_adapter.sv index 4121a616f..ab4613dad 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util_row_adapter.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/mem_bkdr_util/mem_bkdr_util_row_adapter.sv @@ -20,14 +20,14 @@ class mem_bkdr_util_row_adapter; // Translates a raw encoded UVM data row from the memory in a contiguous // row of memory. // - virtual function uvm_hdl_data_t decode_row(uvm_hdl_data_t read_data); + virtual function row_data_t decode_row(row_data_t read_data); return read_data; endfunction // Translates a contiguous UVM data row to the internal organization of a row // that can be written to the memory. // - virtual function uvm_hdl_data_t encode_row(uvm_hdl_data_t write_data); + virtual function row_data_t encode_row(row_data_t write_data); return write_data; endfunction @@ -36,9 +36,9 @@ class mem_bkdr_util_row_adapter; // Given decoded `row_data`, a 39-bit `data` word to be written, and an address, return the // decoded row data with the data word at the correct position for the memory architecture and // the given address. - virtual function uvm_hdl_data_t write_row_data_39b(bit [bus_params_pkg::BUS_AW-1:0] addr, - logic [38:0] data, - uvm_hdl_data_t row_data); + virtual function row_data_t write_row_data_39b(bit [bus_params_pkg::BUS_AW-1:0] addr, + logic [38:0] data, + row_data_t row_data); row_data[38:0] = data; return row_data; endfunction @@ -48,10 +48,8 @@ class mem_bkdr_util_row_adapter; // Given decoded `row_data` and an address, return the 39-bit data from the correct position // for the memory architecture and the given address. virtual function logic [38:0] read_row_data_39b(bit [bus_params_pkg::BUS_AW-1:0] addr, - uvm_hdl_data_t row_data); - logic data; - data = row_data[38:0]; - return data; + row_data_t row_data); + return row_data[38:0]; endfunction endclass diff --git a/hw/vendor/lowrisc_ip/dv/sv/pattgen_agent/pattgen_agent_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/pattgen_agent/pattgen_agent_pkg.sv index 1ea062ac5..64b3a45a6 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/pattgen_agent/pattgen_agent_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/pattgen_agent/pattgen_agent_pkg.sv @@ -6,6 +6,7 @@ package pattgen_agent_pkg; // dep packages import uvm_pkg::*; import dv_utils_pkg::*; + import dv_base_agent_pkg::*; import dv_lib_pkg::*; // macro includes diff --git a/hw/vendor/lowrisc_ip/dv/sv/pattgen_agent/pattgen_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/pattgen_agent/pattgen_driver.sv index e676a1eae..b1ea085fc 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/pattgen_agent/pattgen_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/pattgen_agent/pattgen_driver.sv @@ -6,18 +6,13 @@ class pattgen_driver extends dv_base_driver #(pattgen_item, pattgen_agent_cfg); `uvm_component_utils(pattgen_driver) `uvm_component_new - virtual task reset_signals(); - forever begin - @(negedge cfg.vif.rst_ni); - `uvm_info(`gfn, "\ndriver in reset progress", UVM_DEBUG) - @(posedge cfg.vif.rst_ni); - `uvm_info(`gfn, "\ndriver out of reset", UVM_DEBUG) - end - endtask : reset_signals - virtual task get_and_drive(); @(posedge cfg.vif.rst_ni); // pattgen does not require responses from pattgen_agent thus this task is kept to a minimum endtask : get_and_drive + virtual task on_enter_reset(); + // pattgen does not require responses from pattgen_agent thus this task is kept to a minimum + endtask + endclass : pattgen_driver diff --git a/hw/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent_pkg.sv index 0b2e6ccca..547d09f9e 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent_pkg.sv @@ -6,6 +6,7 @@ package push_pull_agent_pkg; // dep packages import uvm_pkg::*; import dv_utils_pkg::*; + import dv_base_agent_pkg::*; import dv_lib_pkg::*; // macro includes diff --git a/hw/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_driver_lib.sv b/hw/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_driver_lib.sv index 160fc0d9a..f93a75c26 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_driver_lib.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_driver_lib.sv @@ -51,15 +51,8 @@ class push_pull_driver #( sub_driver.cfg = cfg; endfunction - virtual task reset_signals(); + virtual task on_enter_reset(); sub_driver.reset_signals(); - forever begin - @(negedge cfg.vif.rst_n); - `uvm_info(`gfn, "Driver is under reset", UVM_HIGH) - sub_driver.reset_signals(); - @(posedge cfg.vif.rst_n); - `uvm_info(`gfn, "Driver is out of reset", UVM_HIGH) - end endtask // Drive trans received from sequencer. diff --git a/hw/vendor/lowrisc_ip/dv/sv/pwm_monitor/pwm_monitor_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/pwm_monitor/pwm_monitor_pkg.sv index f553062ee..f7f448830 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/pwm_monitor/pwm_monitor_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/pwm_monitor/pwm_monitor_pkg.sv @@ -6,6 +6,7 @@ package pwm_monitor_pkg; // dep packages import uvm_pkg::*; import dv_utils_pkg::*; + import dv_base_agent_pkg::*; import dv_lib_pkg::*; // macro includes diff --git a/hw/vendor/lowrisc_ip/dv/sv/rng_agent/rng_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/rng_agent/rng_driver.sv index 9180900eb..2713b6b43 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/rng_agent/rng_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/rng_agent/rng_driver.sv @@ -13,10 +13,6 @@ class rng_driver extends dv_base_driver #(.ITEM_T(rng_item), `uvm_component_new - // reset signals - virtual task reset_signals(); - endtask - // drive outputs based on inputs virtual task get_and_drive(); forever begin diff --git a/hw/vendor/lowrisc_ip/dv/sv/spi_agent/spi_agent_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/spi_agent/spi_agent_pkg.sv index d78771c29..e62144c80 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/spi_agent/spi_agent_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/spi_agent/spi_agent_pkg.sv @@ -6,6 +6,7 @@ package spi_agent_pkg; // dep packages import uvm_pkg::*; import dv_utils_pkg::*; + import dv_base_agent_pkg::*; import dv_lib_pkg::*; // macro includes diff --git a/hw/vendor/lowrisc_ip/dv/sv/spi_agent/spi_device_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/spi_agent/spi_device_driver.sv index 6235ca18c..30c7118e1 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/spi_agent/spi_device_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/spi_agent/spi_device_driver.sv @@ -24,16 +24,8 @@ class spi_device_driver extends spi_driver; bit [CSB_WIDTH-1:0] active_csb = 0; - virtual task reset_signals(); - forever begin - @(negedge cfg.vif.rst_n); - `uvm_info(`gfn, "\n dev_drv: in reset progress", UVM_DEBUG) - under_reset = 1'b1; - cfg.vif.sio_out = 'z; - @(posedge cfg.vif.rst_n); - under_reset = 1'b0; - `uvm_info(`gfn, "\n dev_drv: out of reset", UVM_DEBUG) - end + task on_enter_reset(); + cfg.vif.sio_out = 'z; endtask virtual task get_and_drive(); @@ -52,7 +44,7 @@ class spi_device_driver extends spi_driver; // it filled out. rsp.payload_q.delete(); `uvm_info(`gfn, $sformatf("Received item - %s",req.sprint), UVM_DEBUG) - wait (!under_reset && !cfg.vif.csb[active_csb]); + wait (!cfg.in_reset && !cfg.vif.csb[active_csb]); fork begin: iso_fork fork diff --git a/hw/vendor/lowrisc_ip/dv/sv/spi_agent/spi_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/spi_agent/spi_driver.sv index 4a1ba3b68..fa8f6a530 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/spi_agent/spi_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/spi_agent/spi_driver.sv @@ -4,15 +4,8 @@ class spi_driver extends dv_base_driver #(spi_item, spi_agent_cfg); `uvm_component_utils(spi_driver) - - bit under_reset; - `uvm_component_new - virtual task reset_signals(); - `uvm_fatal(`gfn, "this is implemented as pure virtual task - please extend") - endtask - virtual task get_and_drive(); `uvm_fatal(`gfn, "this is implemented as pure virtual task - please extend") endtask diff --git a/hw/vendor/lowrisc_ip/dv/sv/spi_agent/spi_host_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/spi_agent/spi_host_driver.sv index 682eb0782..163b7e967 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/spi_agent/spi_host_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/spi_agent/spi_host_driver.sv @@ -16,20 +16,12 @@ class spi_host_driver extends spi_driver; join endtask - // Resets signals - virtual task reset_signals(); - forever begin - @(negedge cfg.vif.rst_n or negedge cfg.vif.disconnected); - if (cfg.vif.disconnected) continue; - under_reset = 1'b1; - active_csb = 1'b0; - cfg.vif.sck <= cfg.sck_polarity[0]; - cfg.vif.sio_out <= 'x; - cfg.vif.csb <= '1; - sck_pulses = 0; - @(posedge cfg.vif.rst_n); - under_reset = 1'b0; - end + task on_enter_reset(); + active_csb = 1'b0; + cfg.vif.sck <= cfg.sck_polarity[0]; + cfg.vif.sio_out <= 'x; + cfg.vif.csb <= '1; + sck_pulses = 0; endtask // generate sck diff --git a/hw/vendor/lowrisc_ip/dv/sv/tl_agent/dv/env/tl_agent_env_cfg.sv b/hw/vendor/lowrisc_ip/dv/sv/tl_agent/dv/env/tl_agent_env_cfg.sv index 1287bbcb6..ddcf906d3 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/tl_agent/dv/env/tl_agent_env_cfg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/tl_agent/dv/env/tl_agent_env_cfg.sv @@ -17,7 +17,7 @@ class tl_agent_env_cfg extends dv_base_env_cfg; `uvm_object_new - virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1); + virtual function void initialize(); // no need to call super.initialize, set is_initialized to bypass the check of calling // super.initialize is_initialized = 1'b1; diff --git a/hw/vendor/lowrisc_ip/dv/sv/tl_agent/seq_lib/tl_device_seq.sv b/hw/vendor/lowrisc_ip/dv/sv/tl_agent/seq_lib/tl_device_seq.sv index d91d11052..1c8e7e291 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/tl_agent/seq_lib/tl_device_seq.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/tl_agent/seq_lib/tl_device_seq.sv @@ -42,9 +42,6 @@ class tl_device_seq #(type REQ = tl_seq_item, int unsigned AddrWidth = 32) exten } virtual task body(); - // Clear the stop flag (which may have been set by seq_stop on the previous run of the sequence) - stop = 0; - fork begin: isolation_thread fork @@ -56,6 +53,11 @@ class tl_device_seq #(type REQ = tl_seq_item, int unsigned AddrWidth = 32) exten disable fork; end join + + // Clear the stop flag. It must be set (because collect_request_thread and send_response_thread + // don't stop otherwise). Clear it to allow a virtual sequence to start the same sequence object + // again if it wishes. + stop = 0; endtask // A blocking task that retrieves a request from the TLM fifo, unless the seq is stopped. diff --git a/hw/vendor/lowrisc_ip/dv/sv/tl_agent/tl_agent_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/tl_agent/tl_agent_pkg.sv index cf5f9cdc1..adfd0c0b8 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/tl_agent/tl_agent_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/tl_agent/tl_agent_pkg.sv @@ -9,6 +9,7 @@ package tl_agent_pkg; import bus_params_pkg::*; import tlul_pkg::*; import mem_model_pkg::*; + import dv_base_agent_pkg::*; import dv_lib_pkg::*; import dv_base_reg_pkg::*; diff --git a/hw/vendor/lowrisc_ip/dv/sv/tl_agent/tl_device_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/tl_agent/tl_device_driver.sv index 15489c83b..ca17738dd 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/tl_agent/tl_device_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/tl_agent/tl_device_driver.sv @@ -19,20 +19,14 @@ class tl_device_driver extends tl_base_driver; a_channel_thread(); d_channel_thread(); join_none - endtask + endtask - // reset signals every time reset occurs. - virtual task reset_signals(); + task on_enter_reset(); invalidate_d_channel(); cfg.vif.d2h_int.a_ready <= 1'b0; - forever begin - @(negedge cfg.vif.rst_n); - invalidate_d_channel(); - cfg.vif.d2h_int.a_ready <= 1'b0; - // Check for seq_item_port FIFO is empty when coming out of reset - `DV_CHECK_EQ(seq_item_port.has_do_available(), 0); - @(posedge cfg.vif.rst_n); - end + + // Make sure that seq_item_port FIFO will be empty when coming out of reset + `DV_CHECK_EQ(seq_item_port.has_do_available(), 0); endtask virtual task a_channel_thread(); @@ -41,9 +35,9 @@ class tl_device_driver extends tl_base_driver; forever begin ready_delay = $urandom_range(cfg.a_ready_delay_min, cfg.a_ready_delay_max); repeat(ready_delay) @(cfg.vif.device_cb); - cfg.vif.device_cb.d2h_int.a_ready <= 1'b1; + cfg.vif.device_cb.d2h.a_ready <= 1'b1; @(cfg.vif.device_cb); - cfg.vif.device_cb.d2h_int.a_ready <= 1'b0; + cfg.vif.device_cb.d2h.a_ready <= 1'b0; end endtask diff --git a/hw/vendor/lowrisc_ip/dv/sv/tl_agent/tl_host_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/tl_agent/tl_host_driver.sv index 9ea615c1c..ff9ed7d6b 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/tl_agent/tl_host_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/tl_agent/tl_host_driver.sv @@ -15,12 +15,13 @@ class tl_host_driver extends tl_base_driver; // Drive items received from the sequencer. This implements a task declared in dv_base_driver. extern task get_and_drive(); - // Clear output signals and internal state whenever a reset happens. This task runs forever, - // looping over resets. - // - // This also controls an internal reset_asserted flag, which is used by other tasks in the class - // to detect resets. This implements a task declared in dv_base_driver. - extern task reset_signals(); + // Called at the start of a reset. Clear output signals and internal state. This implements a task + // declared in dv_base_driver. + extern task on_enter_reset(); + + // Called at the end of a reset. Make sure that all sequence items have been properly flushed + // while we were in reset. + extern function void on_leave_reset(); // Wait for the next edge of host_cb. Stops early if reset is asserted. extern protected task wait_clk_or_rst(); @@ -37,8 +38,17 @@ class tl_host_driver extends tl_base_driver; // Send the body of a request on the A channel. // + // To do so, this writes a_valid and the other A signals and then waits for a clock edge where we + // see a_ready true, at which point the A channel transaction has been made. + // + // If a_ready doesn't go high, it's possible that there will be a timeout after a_valid_len + // cycles. If this is enabled and the timeout happens then remove the item from pendng_a_req, + // and invalidate the channel. + // // req: The request whose body should be sent. // + // a_valid_delay: The number of host clock cycles to wait before asserting a_valid. + // // a_valid_len: The number of host clock cycles a_valid is held high waiting for a_ready to go // high and accept the request. If req has req_abort_after_a_valid_len set, or if // the cfg has allow_a_valid_drop_wo_a_ready, then the driver will drop a_valid @@ -48,8 +58,11 @@ class tl_host_driver extends tl_base_driver; // // req_abort [out] This is set to 1'b1 if the host decides to drop a_valid because the receiver // hasn't responded with a_ready. - extern protected task send_a_request_body(tl_seq_item req, int a_valid_len, - output bit req_done, output bit req_abort); + extern local task send_a_request_body(tl_seq_item req, + int unsigned a_valid_delay, + int unsigned a_valid_len, + output bit req_done, + output bit req_abort); // Drive the d_ready pin (as the host) forever to allow a device to send responses back // @@ -76,11 +89,14 @@ class tl_host_driver extends tl_base_driver; // Return true if the given source is the a_source value of some pending request. extern protected function bit is_source_in_pending_req(bit [SourceWidth-1:0] source); - // Write rubbish to the A channel to invalidate it and set a_valid to zero + // Set a_valid to zero and write rubbish to the A channel to invalidate it. + // + // If direct is true, this directly drives the vif.h2d_int signal as well as setting signals in + // host_cb (meaning that this will have immediate effect, even if the clock is not running). // // If cfg.invalidate_a_x is true then all fields other than a_valid will be set to 'x. If it is // false then all the fields will be randomised. - extern protected function void invalidate_a_channel(); + extern local task invalidate_a_channel(bit direct); endclass : tl_host_driver function tl_host_driver::new (string name, uvm_component parent); @@ -98,35 +114,27 @@ task tl_host_driver::get_and_drive(); join_none endtask -task tl_host_driver::reset_signals(); - forever begin - // At the start of the loop body, we should either be at the start of the simulation or have - // just entered reset. Invalidate all signals and mark ourselves as not ready on the D channel. - invalidate_a_channel(); - cfg.vif.h2d_int.d_ready <= 1'b0; - - // Now wait to come out of reset. Note that if the simulation didn't start in reset then this - // first wait will take zero time. - wait(!cfg.in_reset); - - // When we were in reset, we should have flushed all sequence items immediately. To check this - // has worked correctly, the following things should be true when we leave reset: - // - // - The pending_a_req queue should be empty (d_channel_thread should have sent responses and - // flushed the requests). - // - // - The sequencer shouldn't have any items available through seq_item_port. If an item had - // been available, we should have taken it immediately in get_and_drive. - `DV_CHECK_EQ(pending_a_req.size(), 0) - `DV_CHECK_EQ(seq_item_port.has_do_available(), 0) - - // At this point, we're in the main part of the simulation and the get_and_drive task will be - // driving sequence items over the bus. Wait until reset is asserted before going back to the - // start of the loop. - wait(cfg.in_reset); - end +task tl_host_driver::on_enter_reset(); + // Since we've just started a period of reset, invalidate all signals and mark ourselves as not + // ready on the D channel (both directly and through the clocking block) + invalidate_a_channel(1'b1); + cfg.vif.h2d_int.d_ready <= 1'b0; + cfg.vif.host_cb.h2d.d_ready <= 1'b0; endtask +function void tl_host_driver::on_leave_reset(); + // We should have flushed all sequence items immediately when we were in reset. To check this has + // worked correctly, the following things should be true when we leave reset: + // + // - The pending_a_req queue should be empty (d_channel_thread should have sent responses and + // flushed the requests). + // + // - The sequencer shouldn't have any items available through seq_item_port. If an item had been + // available, we should have taken it immediately in get_and_drive. + `DV_CHECK_EQ(pending_a_req.size(), 0) + `DV_CHECK_EQ(seq_item_port.has_do_available(), 0) +endfunction + task tl_host_driver::wait_clk_or_rst(); `DV_SPINWAIT_EXIT(@(cfg.vif.host_cb);, wait(cfg.in_reset);) endtask @@ -204,32 +212,16 @@ task tl_host_driver::send_a_channel_request(tl_seq_item req); end end - // break delay loop if reset asserted to release blocking - `DV_SPINWAIT_EXIT(repeat (a_valid_delay) @(cfg.vif.host_cb);, - wait(cfg.in_reset);) - - if (!cfg.in_reset) begin - pending_a_req.push_back(req); - cfg.vif.host_cb.h2d_int.a_address <= req.a_addr; - cfg.vif.host_cb.h2d_int.a_opcode <= tl_a_op_e'(req.a_opcode); - cfg.vif.host_cb.h2d_int.a_size <= req.a_size; - cfg.vif.host_cb.h2d_int.a_param <= req.a_param; - cfg.vif.host_cb.h2d_int.a_data <= req.a_data; - cfg.vif.host_cb.h2d_int.a_mask <= req.a_mask; - cfg.vif.host_cb.h2d_int.a_user <= req.a_user; - cfg.vif.host_cb.h2d_int.a_source <= req.a_source; - cfg.vif.host_cb.h2d_int.a_valid <= 1'b1; - end else begin - req_abort = 1; - end - // drop valid if it lasts for a_valid_len, even there is no a_ready - `DV_SPINWAIT_EXIT(send_a_request_body(req, a_valid_len, req_done, req_abort);, - wait(cfg.in_reset);) - - // when reset and host_cb.h2d_int.a_valid <= 1 occur at the same time, if clock is off, - // there is a race condition and invalidate_a_channel can't clear a_valid. - if (cfg.in_reset) cfg.vif.host_cb.h2d_int.a_valid <= 1'b0; - invalidate_a_channel(); + fork : isolation_fork begin + fork + begin + wait(cfg.in_reset); + req_abort = 1; + end + send_a_request_body(req, a_valid_delay, a_valid_len, req_done, req_abort); + join_any + disable fork; + end join end seq_item_port.item_done(); if (req_abort || cfg.in_reset) begin @@ -244,13 +236,32 @@ task tl_host_driver::send_a_channel_request(tl_seq_item req); req.convert2string()), UVM_HIGH) endtask -task tl_host_driver::send_a_request_body(tl_seq_item req, int a_valid_len, - output bit req_done, output bit req_abort); +task tl_host_driver::send_a_request_body(tl_seq_item req, + int unsigned a_valid_delay, + int unsigned a_valid_len, + output bit req_done, + output bit req_abort); int unsigned a_valid_cnt = 0; req_done = 1'b0; req_abort = 1'b0; - while (1) begin + // If there is a delay before sending the item, wait that number of cycles + repeat (a_valid_delay) @(cfg.vif.host_cb); + + // Set signals on the A channel and add the request to pending_a_req, then wait for one clock + // edge, which causes the signals to actually be presented as signals on the interface. + pending_a_req.push_back(req); + cfg.vif.host_cb.h2d.a_address <= req.a_addr; + cfg.vif.host_cb.h2d.a_opcode <= tl_a_op_e'(req.a_opcode); + cfg.vif.host_cb.h2d.a_size <= req.a_size; + cfg.vif.host_cb.h2d.a_param <= req.a_param; + cfg.vif.host_cb.h2d.a_data <= req.a_data; + cfg.vif.host_cb.h2d.a_mask <= req.a_mask; + cfg.vif.host_cb.h2d.a_user <= req.a_user; + cfg.vif.host_cb.h2d.a_source <= req.a_source; + cfg.vif.host_cb.h2d.a_valid <= 1'b1; + + forever begin @(cfg.vif.host_cb); a_valid_cnt++; if (cfg.vif.host_cb.d2h.a_ready) begin @@ -259,14 +270,15 @@ task tl_host_driver::send_a_request_body(tl_seq_item req, int a_valid_len, end else if ((req.req_abort_after_a_valid_len || cfg.allow_a_valid_drop_wo_a_ready) && a_valid_cnt >= a_valid_len) begin if (req.req_abort_after_a_valid_len) req_abort = 1; - cfg.vif.host_cb.h2d_int.a_valid <= 1'b0; // remove unaccepted item void'(pending_a_req.pop_back()); - invalidate_a_channel(); - @(cfg.vif.host_cb); break; end end + + // Finally, clear up the A channel signals (because the transaction has either happened or been + // aborted). The cleared signals will be visible on the interface on the next clock edge. + invalidate_a_channel(1'b0); endtask task tl_host_driver::d_ready_rsp(); @@ -278,13 +290,13 @@ task tl_host_driver::d_ready_rsp(); d_ready_delay = $urandom_range(cfg.d_ready_delay_min, cfg.d_ready_delay_max); // if a_valid high then d_ready must be high, exit the delay when a_valid is set repeat (d_ready_delay) begin - if (!cfg.host_can_stall_rsp_when_a_valid_high && cfg.vif.h2d_int.a_valid) break; + if (!cfg.host_can_stall_rsp_when_a_valid_high && cfg.vif.h2d.a_valid) break; @(cfg.vif.host_cb); end - cfg.vif.host_cb.h2d_int.d_ready <= 1'b1; + cfg.vif.host_cb.h2d.d_ready <= 1'b1; @(cfg.vif.host_cb); - cfg.vif.host_cb.h2d_int.d_ready <= 1'b0; + cfg.vif.host_cb.h2d.d_ready <= 1'b0; end endtask @@ -293,7 +305,7 @@ task tl_host_driver::d_channel_thread(); tl_seq_item rsp; forever begin - if ((cfg.vif.host_cb.d2h.d_valid && cfg.vif.h2d_int.d_ready && !cfg.in_reset) || + if ((cfg.vif.host_cb.d2h.d_valid && cfg.vif.h2d.d_ready && !cfg.in_reset) || ((pending_a_req.size() != 0) & cfg.in_reset)) begin // Use the source ID to find the matching request foreach (pending_a_req[i]) begin @@ -344,23 +356,36 @@ function bit tl_host_driver::is_source_in_pending_req(bit [SourceWidth-1:0] sour return 0; endfunction -function void tl_host_driver::invalidate_a_channel(); +task tl_host_driver::invalidate_a_channel(bit direct); + // To invalidate the A channel, we will drive a_valid to zero and drive all the other A channel + // signals to either 'x or to a random value. Since there's just one signal on the D channel, the + // easiest way to do this is to drive all the signals, but make sure to set the d_ready signal to + // the value it had before. + // + // If either current d_ready value is not known, consider it to be 0. + bit cb_d_ready = cfg.vif.mon_cb.h2d.d_ready; + bit raw_d_ready = cfg.vif.mon_cb.h2d.d_ready; + if (cfg.invalidate_a_x) begin - cfg.vif.h2d_int.a_opcode <= tlul_pkg::tl_a_op_e'('x); - cfg.vif.h2d_int.a_param <= '{default:'x}; - cfg.vif.h2d_int.a_size <= '{default:'x}; - cfg.vif.h2d_int.a_source <= '{default:'x}; - cfg.vif.h2d_int.a_address <= '{default:'x}; - cfg.vif.h2d_int.a_mask <= '{default:'x}; - cfg.vif.h2d_int.a_data <= '{default:'x}; - // The assignment to instr_type must have a cast since the LRM doesn't allow enum assignment of - // values not belonging to the enumeration set. - cfg.vif.h2d_int.a_user <= '{instr_type:prim_mubi_pkg::mubi4_t'('x), default:'x}; - cfg.vif.h2d_int.a_valid <= 1'b0; + cfg.vif.host_cb.h2d <= tl_h2d_t'('x); + cfg.vif.host_cb.h2d.a_valid <= 1'b0; + cfg.vif.host_cb.h2d.d_ready <= cb_d_ready; + + if (direct) begin + cfg.vif.h2d_int <= tl_h2d_t'('x); + cfg.vif.h2d_int.a_valid <= 1'b0; + cfg.vif.h2d_int.d_ready <= raw_d_ready; + end end else begin tlul_pkg::tl_h2d_t h2d; - `DV_CHECK_STD_RANDOMIZE_FATAL(h2d) - h2d.a_valid = 1'b0; - cfg.vif.h2d_int <= h2d; + if (!std::randomize(h2d) with { h2d.a_valid == 1'b0; h2d.d_ready == cb_d_ready; }) begin + `uvm_fatal(get_full_name(), "Failed to randomize h2d.") + end + + cfg.vif.host_cb.h2d <= h2d; + if (direct) begin + h2d.d_ready = raw_d_ready; + cfg.vif.h2d_int <= h2d; + end end -endfunction +endtask diff --git a/hw/vendor/lowrisc_ip/dv/sv/tl_agent/tl_if.sv b/hw/vendor/lowrisc_ip/dv/sv/tl_agent/tl_if.sv index 620c580b8..c202036ec 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/tl_agent/tl_if.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/tl_agent/tl_if.sv @@ -20,7 +20,7 @@ interface tl_if(input clk, input rst_n); clocking host_cb @(posedge clk); input rst_n; - output h2d_int; + output h2d = h2d_int; input d2h; endclocking modport host_mp(clocking host_cb); @@ -28,7 +28,7 @@ interface tl_if(input clk, input rst_n); clocking device_cb @(posedge clk); input rst_n; input h2d; - output d2h_int; + output d2h = d2h_int; endclocking modport device_mp(clocking device_cb); diff --git a/hw/vendor/lowrisc_ip/dv/sv/uart_agent/uart_agent_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/uart_agent/uart_agent_pkg.sv index 17f5b72e7..b99572bc3 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/uart_agent/uart_agent_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/uart_agent/uart_agent_pkg.sv @@ -6,6 +6,7 @@ package uart_agent_pkg; // dep packages import uvm_pkg::*; import dv_utils_pkg::*; + import dv_base_agent_pkg::*; import dv_lib_pkg::*; // macro includes diff --git a/hw/vendor/lowrisc_ip/dv/sv/uart_agent/uart_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/uart_agent/uart_driver.sv index 9bb06bdd8..7cd64dae3 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/uart_agent/uart_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/uart_agent/uart_driver.sv @@ -7,8 +7,7 @@ class uart_driver extends dv_base_driver #(uart_item, uart_agent_cfg); `uvm_component_new - // Resets signals. - virtual task reset_signals(); + task on_enter_reset(); cfg.vif.reset_uart_rx(); endtask diff --git a/hw/vendor/lowrisc_ip/dv/sv/usb20_agent/usb20_agent_pkg.sv b/hw/vendor/lowrisc_ip/dv/sv/usb20_agent/usb20_agent_pkg.sv index 9c2c55b0d..543b6a047 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/usb20_agent/usb20_agent_pkg.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/usb20_agent/usb20_agent_pkg.sv @@ -5,6 +5,7 @@ package usb20_agent_pkg; // dep packages import uvm_pkg::*; + import dv_base_agent_pkg::*; import dv_utils_pkg::*; import dv_lib_pkg::*; diff --git a/hw/vendor/lowrisc_ip/dv/sv/usb20_agent/usb20_device_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/usb20_agent/usb20_device_driver.sv index 2f9bda255..4d252c70a 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/usb20_agent/usb20_device_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/usb20_agent/usb20_device_driver.sv @@ -10,10 +10,6 @@ class usb20_device_driver extends usb20_driver; `uvm_component_new - // reset signals - virtual task reset_signals(); - endtask - // drive trans received from sequencer virtual task get_and_drive(); endtask diff --git a/hw/vendor/lowrisc_ip/dv/sv/usb20_agent/usb20_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/usb20_agent/usb20_driver.sv index 4c8c82800..28d50fe35 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/usb20_agent/usb20_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/usb20_agent/usb20_driver.sv @@ -380,15 +380,14 @@ class usb20_driver extends dv_base_driver #(usb20_item, usb20_agent_cfg); end endtask - // RESET signals Task - // ------------------------------- - virtual task reset_signals(); + // Clear all bus signals, setting outputs to a high-impedance state, because this is the start of + // a reset. An implementation of dv_base_driver::on_enter_reset. + task on_enter_reset(); // Bus is unpowered and inactive. cfg.bif.drive_vbus = 1'b0; cfg.bif.usb_rx_d_i = 1'b0; cfg.bif.drive_p = 1'bZ; cfg.bif.drive_n = 1'bZ; - @(posedge cfg.bif.rst_ni); endtask // USB Bus Reset diff --git a/hw/vendor/lowrisc_ip/dv/sv/usb20_agent/usb20_host_driver.sv b/hw/vendor/lowrisc_ip/dv/sv/usb20_agent/usb20_host_driver.sv index 2612d1e47..d4c005f8e 100644 --- a/hw/vendor/lowrisc_ip/dv/sv/usb20_agent/usb20_host_driver.sv +++ b/hw/vendor/lowrisc_ip/dv/sv/usb20_agent/usb20_host_driver.sv @@ -10,10 +10,6 @@ class usb20_host_driver extends usb20_driver; `uvm_component_new - // reset signals - virtual task reset_signals(); - endtask - // drive trans received from sequencer virtual task get_and_drive(); forever begin diff --git a/hw/vendor/lowrisc_ip/dv/tools/waves.tcl b/hw/vendor/lowrisc_ip/dv/tools/waves.tcl index 3a4ac3ba4..fb92bd2df 100644 --- a/hw/vendor/lowrisc_ip/dv/tools/waves.tcl +++ b/hw/vendor/lowrisc_ip/dv/tools/waves.tcl @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 # This is sourced by all supported simulators. The driver scripts -# (dvsim.py) need to make sure that we don't ask for an unsupported +# (dvsim) need to make sure that we don't ask for an unsupported # dumping format (SHM with VCS, for example). The adjoining common.tcl # must be sourced prior to sourcing this file. diff --git a/hw/vendor/lowrisc_ip/dv/tools/z01x/README.md b/hw/vendor/lowrisc_ip/dv/tools/z01x/README.md index 63b42baba..39fec3252 100644 --- a/hw/vendor/lowrisc_ip/dv/tools/z01x/README.md +++ b/hw/vendor/lowrisc_ip/dv/tools/z01x/README.md @@ -16,6 +16,6 @@ $ export Z01X_DIR= $ export OT_DIR= $ cd opentitan/ $ ./util/prepare_dvsim_z01x.sh -$ ./util/dvsim/dvsim.py hw/top_earlgrey/ip_autogen/flash_ctrl/dv/flash_ctrl_fi_sim_cfg.hjson \ +$ dvsim hw/top_earlgrey/ip_autogen/flash_ctrl/dv/flash_ctrl_fi_sim_cfg.hjson \ -i flash_ctrl_basic_rw -t z01x --reseed-multiplier 0.0001 --fixed-seed 1 ``` diff --git a/hw/vendor/lowrisc_ip/ip/entropy_src/dv/README.md b/hw/vendor/lowrisc_ip/ip/entropy_src/dv/README.md index ea0b88f41..300af1baa 100644 --- a/hw/vendor/lowrisc_ip/ip/entropy_src/dv/README.md +++ b/hw/vendor/lowrisc_ip/ip/entropy_src/dv/README.md @@ -93,7 +93,7 @@ It creates the following analysis ports to retrieve the data monitored by corres * Unknown checks on DUT outputs: The RTL has assertions to ensure all outputs are initialized to known values after coming out of reset. ## Building and running tests -We are using our in-house developed [regression tool](../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console diff --git a/hw/vendor/lowrisc_ip/ip/entropy_src/dv/cov/entropy_src_cov_if.sv b/hw/vendor/lowrisc_ip/ip/entropy_src/dv/cov/entropy_src_cov_if.sv index 77cb2ed07..0e4e2b66e 100644 --- a/hw/vendor/lowrisc_ip/ip/entropy_src/dv/cov/entropy_src_cov_if.sv +++ b/hw/vendor/lowrisc_ip/ip/entropy_src/dv/cov/entropy_src_cov_if.sv @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // -// Implements functional coverage for entropy_src. +// Implements functional coverage for entropy_src and is bound into the dut interface entropy_src_cov_if import entropy_src_pkg::*; import prim_mubi_pkg::*; @@ -1185,8 +1185,10 @@ interface entropy_src_cov_if es_type_csr, entropy_data_reg_enable_csr, fw_ov_mode_csr, entropy_insert_csr; mubi8_t otp_en_es_fw_read_val; - assign csrng_if_req = tb.dut.entropy_src_hw_if_i.es_req; - assign csrng_if_ack = tb.dut.entropy_src_hw_if_o.es_ack; + // Assign req/ack signals to track those in the entropy_src_hw_if_i/o ports of the entropy_src + // instance into which this interface has been bound. + assign csrng_if_req = entropy_src.entropy_src_hw_if_i.es_req; + assign csrng_if_ack = entropy_src.entropy_src_hw_if_o.es_ack; logic enable_q, enable_qq; @@ -1195,37 +1197,43 @@ interface entropy_src_cov_if enable_q <= 1'b0; enable_qq <= 1'b0; end else begin + // Register the enable_i input to u_enable_delay in the entropy_src_core for the entropy_src + // instance into which this interface has been bound. + enable_q <= entropy_src.u_entropy_src_core.u_enable_delay.enable_i; enable_qq <= enable_q; - enable_q <= tb.dut.u_entropy_src_core.u_enable_delay.enable_i; if(csrng_if_req && csrng_if_ack) begin - cg_csrng_hw_sample(tb.dut.reg2hw.conf.fips_enable.q, - tb.dut.reg2hw.conf.fips_flag.q, - tb.dut.reg2hw.conf.rng_fips.q, - tb.dut.reg2hw.conf.threshold_scope.q, - tb.dut.reg2hw.conf.rng_bit_enable.q, - tb.dut.reg2hw.conf.rng_bit_sel.q, - tb.dut.reg2hw.entropy_control.es_route.q, - tb.dut.reg2hw.entropy_control.es_type.q, - tb.dut.reg2hw.conf.entropy_data_reg_enable.q, + // Sample relevant register configuration (based on a hierarchical reference to the dut + // containing this interface) + cg_csrng_hw_sample(entropy_src.reg2hw.conf.fips_enable.q, + entropy_src.reg2hw.conf.fips_flag.q, + entropy_src.reg2hw.conf.rng_fips.q, + entropy_src.reg2hw.conf.threshold_scope.q, + entropy_src.reg2hw.conf.rng_bit_enable.q, + entropy_src.reg2hw.conf.rng_bit_sel.q, + entropy_src.reg2hw.entropy_control.es_route.q, + entropy_src.reg2hw.entropy_control.es_type.q, + entropy_src.reg2hw.conf.entropy_data_reg_enable.q, otp_en_entropy_src_fw_read_i, - tb.dut.reg2hw.fw_ov_control.fw_ov_mode.q, + entropy_src.reg2hw.fw_ov_control.fw_ov_mode.q, otp_en_entropy_src_fw_over_i, - tb.dut.reg2hw.fw_ov_control.fw_ov_entropy_insert.q); + entropy_src.reg2hw.fw_ov_control.fw_ov_entropy_insert.q); end if (enable_qq != enable_q) begin // Only sample this CG when the enable signal changes. + // + // Samples are based on a hierarchical reference to the dut containing this interface. enable_delay_cg_inst.sample( enable_q, - tb.dut.u_entropy_src_core.u_enable_delay.esrng_fifo_not_empty_i, - tb.dut.u_entropy_src_core.u_enable_delay.esbit_fifo_not_empty_i, - tb.dut.u_entropy_src_core.u_enable_delay.postht_fifo_not_empty_i, - tb.dut.u_entropy_src_core.u_enable_delay.distr_fifo_not_empty_i, - tb.dut.u_entropy_src_core.u_enable_delay.sha3_block_busy_i, - tb.dut.u_entropy_src_core.u_enable_delay.sha3_block_processed_i, - tb.dut.u_entropy_src_core.u_enable_delay.bypass_mode_i, - tb.dut.u_entropy_src_core.u_enable_delay.enable_o); + entropy_src.u_entropy_src_core.u_enable_delay.esrng_fifo_not_empty_i, + entropy_src.u_entropy_src_core.u_enable_delay.esbit_fifo_not_empty_i, + entropy_src.u_entropy_src_core.u_enable_delay.postht_fifo_not_empty_i, + entropy_src.u_entropy_src_core.u_enable_delay.distr_fifo_not_empty_i, + entropy_src.u_entropy_src_core.u_enable_delay.sha3_block_busy_i, + entropy_src.u_entropy_src_core.u_enable_delay.sha3_block_processed_i, + entropy_src.u_entropy_src_core.u_enable_delay.bypass_mode_i, + entropy_src.u_entropy_src_core.u_enable_delay.enable_o); end end end diff --git a/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/entropy_src_env.sv b/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/entropy_src_env.sv index 01b937b93..06c2df6ed 100644 --- a/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/entropy_src_env.sv +++ b/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/entropy_src_env.sv @@ -118,6 +118,17 @@ class entropy_src_env extends cip_base_env #( cfg.interrupt_vif)) begin `uvm_fatal(`gfn, "failed to get entropy_src_path_vif from uvm_config_db") end + + // Disable random CDC delays in alert sender because the scoreboard otherwise could not + // accurately predict whether an alert request gets merged with an outstanding request or not + // (#18796). + cfg.disabled_prim_cdc_rand_delays = new[2]; + for (int unsigned i = 0; i < 2; i++) begin + cfg.disabled_prim_cdc_rand_delays[i] = {cfg.entropy_src_path_vif.dut_path, + ".gen_alert_tx[0].u_prim_alert_sender.u_decode_ack", + $sformatf(".gen_async.i_sync_%0s", i ? "p" : "n"), + ".u_prim_cdc_rand_delay"}; + end endfunction function void connect_phase(uvm_phase phase); diff --git a/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/entropy_src_env_cfg.sv b/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/entropy_src_env_cfg.sv index 07e521325..09afa76ab 100644 --- a/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/entropy_src_env_cfg.sv +++ b/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/entropy_src_env_cfg.sv @@ -251,10 +251,10 @@ class entropy_src_env_cfg extends cip_base_env_cfg #(.RAL_T(entropy_src_reg_bloc // Functions // /////////////// - virtual function void initialize(bit [31:0] csr_base_addr = '1); + virtual function void initialize(); list_of_alerts = entropy_src_env_pkg::LIST_OF_ALERTS; tl_intg_alert_name = "fatal_alert"; - super.initialize(csr_base_addr); + super.initialize(); dut_cfg = entropy_src_dut_cfg::type_id::create("dut_cfg"); @@ -270,19 +270,6 @@ class entropy_src_env_cfg extends cip_base_env_cfg #(.RAL_T(entropy_src_reg_bloc // only support 1 outstanding TL item m_tl_agent_cfg.max_outstanding_req = 1; - - // Disable random CDC delays in alert sender because the scoreboard otherwise could not - // accurately predict whether an alert request gets merged with an outstanding request or not - // (#18796). - disabled_prim_cdc_rand_delays = new[2]; - foreach (disabled_prim_cdc_rand_delays[i]) begin - string path = "tb.dut.gen_alert_tx[0].u_prim_alert_sender.u_decode_ack.gen_async"; - unique case (i) - 0: path = {path, ".i_sync_n"}; - 1: path = {path, ".i_sync_p"}; - endcase - disabled_prim_cdc_rand_delays[i] = {path, ".u_prim_cdc_rand_delay"}; - end endfunction virtual function string convert2string(); diff --git a/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/entropy_src_path_if.sv b/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/entropy_src_path_if.sv index 5198af2ea..89e9a4cfd 100644 --- a/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/entropy_src_path_if.sv +++ b/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/entropy_src_path_if.sv @@ -2,17 +2,20 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -// This interface deals with the force paths in ENTROPY_SRC interrupt and error tests - -`define CORE \ - tb.dut.u_entropy_src_core -`define REPCNT \ - u_entropy_src_repcnt_ht.u_prim_max_tree_rep_cntr_max +// This interface deals with the force paths in ENTROPY_SRC interrupt and error tests. +// +// It is bound into an instance of entropy_src, so can address signals inside the dut with upwards +// hierarchical references. interface entropy_src_path_if (); import uvm_pkg::*; - string core_path = "tb.dut.u_entropy_src_core"; + // The hierarchical path to the entropy_src instance into which the interface is bound. + string dut_path = dv_utils_pkg::get_parent_hier($sformatf("%m")); + + // The hierarchical path to the entropy_src_core instance in the entropy_src instance into which + // the interface is bound. + string core_path = {dut_path, ".u_entropy_src_core"}; function automatic string fifo_err_path(string fifo_name, string path_name); return {core_path, ".", fifo_name, "_", path_name}; @@ -45,20 +48,27 @@ interface entropy_src_path_if (); end endcase // case (cntr_name) endfunction // cntr_err_path - // Disable assertions that we expect to trigger when injecting errors + +// The relative hierarchical path to the entropy_src core from the entropy_src instance into which +// the interface is bound. This matches the string in the core_path variable. +`define CORE entropy_src.u_entropy_src_core + + // Disable assertions that we expect to trigger when injecting errors + // + // This uses upwards hierarchical references, pointing at the instance into which we are bound. task automatic assert_off_err(); - $assertoff(0, tb.dut.AlertTxKnownO_A); - $assertoff(0, tb.dut.IntrEsFifoErrKnownO_A); - $assertoff(0, tb.dut.EsHwIfEsAckKnownO_A); - $assertoff(0, tb.dut.EsHwIfEsBitsKnownO_A); - $assertoff(0, tb.dut.EsHwIfEsFipsKnownO_A); - $assertoff(0, tb.dut.EsXhtEntropyBitKnownO_A); - $assertoff(0, tb.dut.IntrEsEntropyValidKnownO_A); - $assertoff(0, tb.dut.IntrEsHealthTestFailedKnownO_A); - $assertoff(0, tb.dut.tlul_assert_device.dKnown_A); - $assertoff(0, tb.dut.tlul_assert_device.gen_device.gen_d2h.dDataKnown_A); - $assertoff(0, tb.dut.gen_alert_tx[0].u_prim_alert_sender.AlertPKnownO_A); - $assertoff(0, tb.dut.gen_alert_tx[0].u_prim_alert_sender.gen_async_assert.DiffEncoding_A); + $assertoff(0, entropy_src.AlertTxKnownO_A); + $assertoff(0, entropy_src.IntrEsFifoErrKnownO_A); + $assertoff(0, entropy_src.EsHwIfEsAckKnownO_A); + $assertoff(0, entropy_src.EsHwIfEsBitsKnownO_A); + $assertoff(0, entropy_src.EsHwIfEsFipsKnownO_A); + $assertoff(0, entropy_src.EsXhtEntropyBitKnownO_A); + $assertoff(0, entropy_src.IntrEsEntropyValidKnownO_A); + $assertoff(0, entropy_src.IntrEsHealthTestFailedKnownO_A); + $assertoff(0, entropy_src.tlul_assert_device.dKnown_A); + $assertoff(0, entropy_src.tlul_assert_device.gen_device.gen_d2h.dDataKnown_A); + $assertoff(0, entropy_src.gen_alert_tx[0].u_prim_alert_sender.AlertPKnownO_A); + $assertoff(0, entropy_src.gen_alert_tx[0].u_prim_alert_sender.gen_async_assert.DiffEncoding_A); $assertoff(0, `CORE.AtReset_ValidRngBitsPushedIntoEsrngFifo_A); $assertoff(0, `CORE.Final_ValidRngBitsPushedIntoEsrngFifo_A); $assertoff(0, `CORE.AtReset_EsrngFifoPushedIntoEsbitOrPosthtFifos_A); @@ -92,8 +102,10 @@ interface entropy_src_path_if (); $assertoff(0, `CORE.u_entropy_src_markov_ht.u_min.ValidInImpliesValidOut_A); $assertoff(0, `CORE.u_entropy_src_markov_ht.u_max.ValidInImpliesValidOut_A); $assertoff(0, `CORE.u_sha3.u_keccak.gen_unmask_st_chk.UnmaskValidStates_A); - $assertoff(0, `CORE.`REPCNT.ValidInImpliesValidOut_A); + $assertoff(0, + `CORE.u_entropy_src_repcnt_ht.u_prim_max_tree_rep_cntr_max.ValidInImpliesValidOut_A); endtask + function automatic void disable_entroy_drop_assertions(); // Disable assertions which expect that no entropy is dropped between the esrng, // esbit and postht FIFOs. @@ -107,4 +119,3 @@ interface entropy_src_path_if (); endinterface // entropy_src_path_if `undef CORE -`undef REPCNT diff --git a/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/entropy_src_scoreboard.sv b/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/entropy_src_scoreboard.sv index 1e49d4142..9fbff9326 100644 --- a/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/entropy_src_scoreboard.sv +++ b/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/entropy_src_scoreboard.sv @@ -32,7 +32,7 @@ class entropy_src_scoreboard extends cip_base_scoreboard#( bit observe_fifo_overflow = 0; int overflow_read_cnt = 0; - string es_delayed_enable_path = "tb.dut.u_entropy_src_core.es_delayed_enable"; + string es_delayed_enable_path; bit dut_pipeline_enabled = 0; bit regwen_pending = 0; bit ht_fips_mode = 0; @@ -161,8 +161,8 @@ class entropy_src_scoreboard extends cip_base_scoreboard#( int precon_fifo_cnt = 0; bit sha3_msg_ready = 0; bit predict_fw_ov_wr_fifo_full = 0; - string pad_st_path = "tb.dut.u_entropy_src_core.u_sha3.u_pad.st[6:0]"; - string pad_st_d_path = "tb.dut.u_entropy_src_core.u_sha3.u_pad.st_d[6:0]"; + string pad_st_path; + string pad_st_d_path; // Variables used to model entropy propagating through the pipeline. int post_ht_drops = 0; @@ -225,6 +225,10 @@ class entropy_src_scoreboard extends cip_base_scoreboard#( function void connect_phase(uvm_phase phase); super.connect_phase(phase); + + es_delayed_enable_path = {cfg.entropy_src_path_vif.core_path, ".es_delayed_enable"}; + pad_st_path = {cfg.entropy_src_path_vif.core_path, ".u_sha3.u_pad.st[6:0]"}; + pad_st_d_path = {cfg.entropy_src_path_vif.core_path, ".u_sha3.u_pad.st_d[6:0]"}; endfunction task run_phase(uvm_phase phase); diff --git a/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/seq_lib/entropy_src_base_vseq.sv b/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/seq_lib/entropy_src_base_vseq.sv index bb21e336d..8a7d5dd5c 100644 --- a/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/seq_lib/entropy_src_base_vseq.sv +++ b/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/seq_lib/entropy_src_base_vseq.sv @@ -262,7 +262,6 @@ class entropy_src_base_vseq extends cip_base_vseq #( // Otherwise, we may lock invalid configurations which would require resetting the DUT. wait_no_outstanding_access(); cfg.clk_rst_vif.wait_clks( - cfg.m_alert_agent_cfgs["recov_alert"].ping_delay_max + cfg.m_alert_agent_cfgs["recov_alert"].ack_delay_max + cfg.m_alert_agent_cfgs["recov_alert"].ack_stable_max + 2); // Pause between back-to-back handshakes at sender end. @@ -679,7 +678,7 @@ class entropy_src_base_vseq extends cip_base_vseq #( task force_fifo_err_exception(string paths [4], bit values [4], uvm_reg_field reg_field, bit exp_data); - string data_path = "tb.dut.u_entropy_src_core.sfifo_esrng_rdata"; + string data_path = {cfg.entropy_src_path_vif.core_path, ".sfifo_esrng_rdata"}; foreach (paths[i]) begin if (!uvm_hdl_check_path(paths[i])) begin `uvm_fatal(`gfn, $sformatf("\n\t ----| PATH NOT FOUND")) diff --git a/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/seq_lib/entropy_src_err_vseq.sv b/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/seq_lib/entropy_src_err_vseq.sv index aec7ec395..5ec5b3750 100644 --- a/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/seq_lib/entropy_src_err_vseq.sv +++ b/hw/vendor/lowrisc_ip/ip/entropy_src/dv/env/seq_lib/entropy_src_err_vseq.sv @@ -4,33 +4,6 @@ // Test all ERR_CODE fields are asserted as expected, as well as the ERR_CODE_TEST register -`define PATH1 \ - tb.dut.u_entropy_src_core.u_prim_mubi4_sync_entropy_fips_en -`define PATH2 \ - tb.dut.u_entropy_src_core.u_prim_mubi4_sync_entropy_data_reg_en -`define PATH3 \ - tb.dut.u_entropy_src_core.u_prim_mubi4_sync_entropy_module_en -`define PATH4 \ - tb.dut.u_entropy_src_core.u_prim_mubi4_sync_rng_bit_en -`define PATH5 \ - tb.dut.u_entropy_src_core.u_prim_mubi4_sync_fw_ov_mode -`define PATH6 \ - tb.dut.u_entropy_src_core.u_prim_mubi4_sync_fw_ov_entropy_insert -`define PATH7 \ - tb.dut.u_entropy_src_core.u_prim_mubi4_sync_es_route -`define PATH8 \ - tb.dut.u_entropy_src_core.u_prim_mubi4_sync_es_type -`define PATH9 \ - tb.dut.u_entropy_src_core.u_prim_mubi4_sync_es_enable -`define PATH10 \ - tb.dut.u_entropy_src_core.u_prim_mubi4_sync_es_enable_pulse -`define CORE \ - tb.dut.u_entropy_src_core -`define SHA3 \ - u_sha3.u_keccak.u_round_count -`define REPCNT \ - u_entropy_src_repcnt_ht.u_prim_max_tree_rep_cntr_max - class entropy_src_err_vseq extends entropy_src_base_vseq; `uvm_object_utils(entropy_src_err_vseq) diff --git a/hw/vendor/lowrisc_ip/ip/entropy_src/dv/tb/tb.sv b/hw/vendor/lowrisc_ip/ip/entropy_src/dv/tb/tb.sv index d63edf588..0e25280d4 100644 --- a/hw/vendor/lowrisc_ip/ip/entropy_src/dv/tb/tb.sv +++ b/hw/vendor/lowrisc_ip/ip/entropy_src/dv/tb/tb.sv @@ -39,7 +39,6 @@ module tb; push_pull_if#(.HostDataWidth(entropy_src_pkg::FIPS_CSRNG_BUS_WIDTH)) csrng_if(.clk(clk), .rst_n(csrng_rst_n)); entropy_src_xht_if xht_if(.clk(clk), .rst_n(rst_n)); - entropy_src_path_if entropy_src_path_if (); `DV_ALERT_IF_CONNECT() @@ -90,6 +89,8 @@ module tb; assign interrupts[ObserveFifoReady] = intr_observe_fifo_ready; assign interrupts[FatalErr] = intr_fatal_err; + bind dut entropy_src_path_if entropy_src_path_if (); + bind prim_packer_fifo : dut.u_entropy_src_core.u_prim_packer_fifo_precon entropy_subsys_fifo_exception_if #( .IsPackerFifo(1) @@ -150,7 +151,7 @@ module tb; set(null, "*.env.m_csrng_agent*", "vif", csrng_if); uvm_config_db#(virtual entropy_src_xht_if)::set(null, "*.env.m_xht_agent*", "vif", xht_if); uvm_config_db#(virtual entropy_src_path_if)::set(null, "*.env", "entropy_src_path_vif", - entropy_src_path_if); + dut.entropy_src_path_if); $timeformat(-12, 0, " ps", 12); run_test(); end diff --git a/hw/vendor/lowrisc_ip/ip/i2c/dv/README.md b/hw/vendor/lowrisc_ip/ip/i2c/dv/README.md index 44f4bb614..bd1a5a158 100644 --- a/hw/vendor/lowrisc_ip/ip/i2c/dv/README.md +++ b/hw/vendor/lowrisc_ip/ip/i2c/dv/README.md @@ -84,11 +84,11 @@ It also creates the following queues to monitor I2C packets: * Unknown checks on DUT outputs: The RTL has assertions to ensure all outputs are initialized to known values after coming out of reset. ## Building and running tests -We are using our in-house developed [regression tool](../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/ip/i2c/dv/i2c_sim_cfg.hjson -i i2c_host_smoke +$ dvsim $REPO_TOP/hw/ip/i2c/dv/i2c_sim_cfg.hjson -i i2c_host_smoke ``` ## Testplan diff --git a/hw/vendor/lowrisc_ip/ip/i2c/dv/env/i2c_dv_if.sv b/hw/vendor/lowrisc_ip/ip/i2c/dv/env/i2c_dv_if.sv deleted file mode 100644 index 9bc1d79fc..000000000 --- a/hw/vendor/lowrisc_ip/ip/i2c/dv/env/i2c_dv_if.sv +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -interface i2c_dv_if ( - input logic clk, - input logic rst_n -); - - logic [5:0] i2c_state; - bit got_state; - - clocking cb @(posedge clk); - default input #1step output #2; - endclocking -endinterface diff --git a/hw/vendor/lowrisc_ip/ip/i2c/dv/env/i2c_env.core b/hw/vendor/lowrisc_ip/ip/i2c/dv/env/i2c_env.core index 02ee982b7..27b946171 100644 --- a/hw/vendor/lowrisc_ip/ip/i2c/dv/env/i2c_env.core +++ b/hw/vendor/lowrisc_ip/ip/i2c/dv/env/i2c_env.core @@ -13,7 +13,6 @@ filesets: - lowrisc:ip:i2c files: - i2c_env_pkg.sv - - i2c_dv_if.sv - i2c_seq_cfg.sv: {is_include_file: true} - i2c_env_cfg.sv: {is_include_file: true} - i2c_env_cov.sv: {is_include_file: true} diff --git a/hw/vendor/lowrisc_ip/ip/i2c/dv/env/i2c_env.sv b/hw/vendor/lowrisc_ip/ip/i2c/dv/env/i2c_env.sv index 916b31fd4..594a95f14 100644 --- a/hw/vendor/lowrisc_ip/ip/i2c/dv/env/i2c_env.sv +++ b/hw/vendor/lowrisc_ip/ip/i2c/dv/env/i2c_env.sv @@ -16,10 +16,6 @@ class i2c_env extends cip_base_env #( function void build_phase(uvm_phase phase); super.build_phase(phase); - if (!uvm_config_db#(virtual i2c_dv_if)::get( - this, "", "i2c_dv_vif", cfg.i2c_dv_vif)) begin - `uvm_fatal(`gfn, "failed to get i2c_dv_vif from uvm_config_db") - end m_i2c_agent = i2c_agent::type_id::create("m_i2c_agent", this); uvm_config_db#(i2c_agent_cfg)::set(this, "m_i2c_agent*", "cfg", cfg.m_i2c_agent_cfg); cfg.m_i2c_agent_cfg.en_cov = cfg.en_cov; diff --git a/hw/vendor/lowrisc_ip/ip/i2c/dv/env/i2c_env_cfg.sv b/hw/vendor/lowrisc_ip/ip/i2c/dv/env/i2c_env_cfg.sv index 5bc5173d5..d30448644 100644 --- a/hw/vendor/lowrisc_ip/ip/i2c/dv/env/i2c_env_cfg.sv +++ b/hw/vendor/lowrisc_ip/ip/i2c/dv/env/i2c_env_cfg.sv @@ -6,7 +6,6 @@ typedef class i2c_scoreboard; class i2c_env_cfg extends cip_base_env_cfg #(.RAL_T(i2c_reg_block)); i2c_scoreboard scoreboard; - virtual i2c_dv_if i2c_dv_vif; //////////////////////////////// // Test Configuration Options // @@ -89,9 +88,9 @@ class i2c_env_cfg extends cip_base_env_cfg #(.RAL_T(i2c_reg_block)); `uvm_object_new - virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1); + virtual function void initialize(); list_of_alerts = i2c_env_pkg::LIST_OF_ALERTS; - super.initialize(csr_base_addr); + super.initialize(); m_i2c_agent_cfg = i2c_agent_cfg::type_id::create("m_i2c_agent_cfg"); m_i2c_agent_cfg.if_mode = Device; diff --git a/hw/vendor/lowrisc_ip/ip/i2c/dv/tb/tb.sv b/hw/vendor/lowrisc_ip/ip/i2c/dv/tb/tb.sv index 18d365886..f969eeb42 100644 --- a/hw/vendor/lowrisc_ip/ip/i2c/dv/tb/tb.sv +++ b/hw/vendor/lowrisc_ip/ip/i2c/dv/tb/tb.sv @@ -54,12 +54,6 @@ module tb; .sda_io(sda) ); - // TODO: Remove this unused interface. - i2c_dv_if i2c_dv_if( - .clk(clk), - .rst_n(rst_n) - ); - `ifndef I2C_HIER `define I2C_HIER tb.dut.i2c_core `endif @@ -146,7 +140,6 @@ module tb; uvm_config_db#(intr_vif)::set(null, "*.env", "intr_vif", intr_if); uvm_config_db#(virtual tl_if)::set(null, "*.env.m_tl_agent*", "vif", tl_if); uvm_config_db#(virtual i2c_if)::set(null, "*.env.m_i2c_agent*", "vif", i2c_if); - uvm_config_db#(virtual i2c_dv_if)::set(null, "*.env", "i2c_dv_vif", i2c_dv_if); $timeformat(-12, 0, " ps", 12); run_test(); end diff --git a/hw/vendor/lowrisc_ip/ip/i2c/rtl/i2c_core.sv b/hw/vendor/lowrisc_ip/ip/i2c/rtl/i2c_core.sv index 53e095392..3991e538b 100644 --- a/hw/vendor/lowrisc_ip/ip/i2c/rtl/i2c_core.sv +++ b/hw/vendor/lowrisc_ip/ip/i2c/rtl/i2c_core.sv @@ -280,8 +280,8 @@ module i2c_core import i2c_pkg::*; scl_rx_val <= 16'h0; sda_rx_val <= 16'h0; end else begin - scl_rx_val <= {scl_rx_val[14:0], scl_i}; - sda_rx_val <= {sda_rx_val[14:0], sda_i}; + scl_rx_val <= {scl_rx_val[14:0], scl_sync}; + sda_rx_val <= {sda_rx_val[14:0], sda_sync}; end end diff --git a/hw/vendor/lowrisc_ip/ip/i2c/rtl/i2c_target_fsm.sv b/hw/vendor/lowrisc_ip/ip/i2c/rtl/i2c_target_fsm.sv index ce1261f90..b59ec356f 100644 --- a/hw/vendor/lowrisc_ip/ip/i2c/rtl/i2c_target_fsm.sv +++ b/hw/vendor/lowrisc_ip/ip/i2c/rtl/i2c_target_fsm.sv @@ -8,8 +8,8 @@ module i2c_target_fsm import i2c_pkg::*; #( - parameter int AcqFifoDepth = 64, - localparam int AcqFifoDepthWidth = $clog2(AcqFifoDepth+1) + parameter int unsigned AcqFifoDepth = 64, + localparam int unsigned AcqFifoDepthWidth = $clog2(AcqFifoDepth+1) ) ( input clk_i, // clock input rst_ni, // active low reset diff --git a/hw/vendor/lowrisc_ip/ip/kmac/README.md b/hw/vendor/lowrisc_ip/ip/kmac/README.md index a471e46e0..e5ae0400d 100644 --- a/hw/vendor/lowrisc_ip/ip/kmac/README.md +++ b/hw/vendor/lowrisc_ip/ip/kmac/README.md @@ -2,8 +2,8 @@ | Regression | Version | [Stages](https://opentitan.org/book/doc/project_governance/development_stages.html) | Results | |-|-|-|-| - [`kmac_masked`](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/dashboard.html) | 2.0.0 | D2S, V2S | ![](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/badge/kmac_masked/test.svg) ![](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/badge/kmac_masked/passing.svg) ![](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/badge/kmac_masked/functional.svg) ![](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/badge/kmac_masked/code.svg) | - [`kmac_unmasked`](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/dashboard.html) | 2.0.0 | D2S, V2S | ![](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/badge/kmac_unmasked/test.svg) ![](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/badge/kmac_unmasked/passing.svg) ![](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/badge/kmac_unmasked/functional.svg) ![](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/badge/kmac_unmasked/code.svg) | + [`kmac_masked`](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/dashboard.html) | 2.1.0 | D1, V1 | ![](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/badge/kmac_masked/test.svg) ![](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/badge/kmac_masked/passing.svg) ![](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/badge/kmac_masked/functional.svg) ![](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/badge/kmac_masked/code.svg) | + [`kmac_unmasked`](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/dashboard.html) | 2.1.0 | D1, V1 | ![](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/badge/kmac_unmasked/test.svg) ![](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/badge/kmac_unmasked/passing.svg) ![](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/badge/kmac_unmasked/functional.svg) ![](https://dashboard.reports.lowrisc.org/opentitan/earlgrey/badge/kmac_unmasked/code.svg) | This IP has been taped out in Earl Grey 1.0.0. The corresponding documentation and regression results can be found [here](https://opentitan.org/earlgrey_1.0.0/book/hw/ip/kmac/index.html). diff --git a/hw/vendor/lowrisc_ip/ip/kmac/data/kmac.hjson b/hw/vendor/lowrisc_ip/ip/kmac/data/kmac.hjson index 33076476b..6dc620514 100644 --- a/hw/vendor/lowrisc_ip/ip/kmac/data/kmac.hjson +++ b/hw/vendor/lowrisc_ip/ip/kmac/data/kmac.hjson @@ -29,6 +29,14 @@ design_stage: "D2S", verification_stage: "V2S", dif_stage: "S2", + commit_id: "0742a8e0ad0f0c9a50720ecfea93287035d52944", + }, + { + version: "2.1.0", + life_stage: "L1", + design_stage: "D1", + verification_stage: "V1", + dif_stage: "S1", } ] clocking: [ @@ -381,8 +389,7 @@ name: "kmac_en" desc: '''KMAC datapath enable. - If this bit is 1, the incoming message is processed in KMAC - with the secret key. + If this bit is 1, the KMAC mode is active and the secret key is prepended to the incoming message. ''' tags: [// don't enable kmac and sha data paths - we will do that in functional tests "excl:CsrNonInitTests:CsrExclWrite", diff --git a/hw/vendor/lowrisc_ip/ip/kmac/doc/registers.md b/hw/vendor/lowrisc_ip/ip/kmac/doc/registers.md index 7ee109691..87f6e5f5c 100644 --- a/hw/vendor/lowrisc_ip/ip/kmac/doc/registers.md +++ b/hw/vendor/lowrisc_ip/ip/kmac/doc/registers.md @@ -327,8 +327,7 @@ Other values are reserved. ### CFG_SHADOWED . kmac_en KMAC datapath enable. -If this bit is 1, the incoming message is processed in KMAC -with the secret key. +If this bit is 1, the KMAC mode is active and the secret key is prepended to the incoming message. ## CMD KMAC/ SHA3 command register. diff --git a/hw/vendor/lowrisc_ip/ip/kmac/dv/README.md b/hw/vendor/lowrisc_ip/ip/kmac/dv/README.md index b5cf1362c..488dc0432 100644 --- a/hw/vendor/lowrisc_ip/ip/kmac/dv/README.md +++ b/hw/vendor/lowrisc_ip/ip/kmac/dv/README.md @@ -140,11 +140,11 @@ As the test sequence reads the output STATE_SHARE windows after a hash operation * Unknown checks on DUT outputs: The RTL has assertions to ensure all outputs are initialized to known values after coming out of reset. ## Building and running tests -We are using our in-house developed [regression tool](../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/ip/kmac/dv/kmac_${VARIANT}_sim_cfg.hjson -i kmac_smoke +$ dvsim $REPO_TOP/hw/ip/kmac/dv/kmac_${VARIANT}_sim_cfg.hjson -i kmac_smoke ``` In this run command, $VARIANT can be `masked` or `unmasked`. diff --git a/hw/vendor/lowrisc_ip/ip/kmac/dv/env/kmac_env_cfg.sv b/hw/vendor/lowrisc_ip/ip/kmac/dv/env/kmac_env_cfg.sv index 6033788d0..efbb3905d 100644 --- a/hw/vendor/lowrisc_ip/ip/kmac/dv/env/kmac_env_cfg.sv +++ b/hw/vendor/lowrisc_ip/ip/kmac/dv/env/kmac_env_cfg.sv @@ -41,12 +41,12 @@ class kmac_env_cfg extends cip_base_env_cfg #(.RAL_T(kmac_reg_block)); `uvm_object_new - virtual function void initialize(bit [31:0] csr_base_addr = '1); + virtual function void initialize(); num_edn = 1; list_of_alerts = kmac_env_pkg::LIST_OF_ALERTS; tl_intg_alert_name = "fatal_fault_err"; sec_cm_alert_name = "fatal_fault_err"; - super.initialize(csr_base_addr); + super.initialize(); tl_intg_alert_fields[ral.status.alert_fatal_fault] = 1; tl_intg_alert_fields[ral.cfg_regwen.en] = 0; diff --git a/hw/vendor/lowrisc_ip/ip/kmac/rtl/kmac.sv b/hw/vendor/lowrisc_ip/ip/kmac/rtl/kmac.sv index d774e0d6c..eb719248d 100644 --- a/hw/vendor/lowrisc_ip/ip/kmac/rtl/kmac.sv +++ b/hw/vendor/lowrisc_ip/ip/kmac/rtl/kmac.sv @@ -217,13 +217,6 @@ module kmac logic [kmac_pkg::MsgStrbW-1:0] msgfifo_strb ; logic msgfifo_ready ; - if (EnMasking) begin : gen_msgfifo_data_masked - // In Masked mode, the input message data is split into two shares. - // Only concern, however, here is the secret key. So message can be - // put into only one share and other is 0. - assign msgfifo_data[1] = '0; - end - // TL-UL Adapter(MSG_FIFO) signals logic tlram_req; logic tlram_gnt; @@ -238,14 +231,14 @@ module kmac logic [31:0] tlram_wmask_endian; logic sw_msg_valid; - logic [kmac_pkg::MsgWidth-1:0] sw_msg_data ; - logic [kmac_pkg::MsgWidth-1:0] sw_msg_mask ; + logic [kmac_pkg::MsgWidth-1:0] sw_msg_data; + logic [kmac_pkg::MsgWidth-1:0] sw_msg_strb; logic sw_msg_ready; // KeyMgr interface to MSG_FIFO logic mux2fifo_valid; - logic [kmac_pkg::MsgWidth-1:0] mux2fifo_data ; - logic [kmac_pkg::MsgWidth-1:0] mux2fifo_mask ; + logic [kmac_pkg::MsgWidth-1:0] mux2fifo_data[Share]; + logic [kmac_pkg::MsgWidth-1:0] mux2fifo_strb; logic mux2fifo_ready; // KMAC to SHA3 core @@ -1035,10 +1028,10 @@ module kmac assign sw_msg_valid = tlram_req & tlram_we ; if (MsgWidth == MsgWindowWidth) begin : gen_sw_msg_samewidth assign sw_msg_data = tlram_wdata_endian ; - assign sw_msg_mask = tlram_wmask_endian ; + assign sw_msg_strb = tlram_wmask_endian ; end else begin : gen_sw_msg_diff assign sw_msg_data = {{MsgWidth-MsgWindowWidth{1'b0}}, tlram_wdata_endian}; - assign sw_msg_mask = {{MsgWidth-MsgWindowWidth{1'b0}}, tlram_wmask_endian}; + assign sw_msg_strb = {{MsgWidth-MsgWindowWidth{1'b0}}, tlram_wmask_endian}; end assign tlram_gnt = sw_msg_ready ; @@ -1067,7 +1060,7 @@ module kmac // data from tl_adapter .sw_valid_i (sw_msg_valid), .sw_data_i (sw_msg_data), - .sw_mask_i (sw_msg_mask), + .sw_strb_i (sw_msg_strb), .sw_ready_o (sw_msg_ready), // KeyMgr sideloaded key interface @@ -1085,7 +1078,7 @@ module kmac // to MSG_FIFO .kmac_valid_o (mux2fifo_valid), .kmac_data_o (mux2fifo_data), - .kmac_mask_o (mux2fifo_mask), + .kmac_strb_o (mux2fifo_strb), .kmac_ready_i (mux2fifo_ready), // to KMAC Core @@ -1144,11 +1137,12 @@ module kmac .fifo_valid_i (mux2fifo_valid), .fifo_data_i (mux2fifo_data), - .fifo_mask_i (mux2fifo_mask), + .fifo_strb_i (mux2fifo_strb), .fifo_ready_o (mux2fifo_ready), + .fifo_bypass_i('0), .msg_valid_o (msgfifo_valid), - .msg_data_o (msgfifo_data[0]), + .msg_data_o (msgfifo_data), .msg_strb_o (msgfifo_strb), .msg_ready_i (msgfifo_ready), diff --git a/hw/vendor/lowrisc_ip/ip/kmac/rtl/kmac_app.sv b/hw/vendor/lowrisc_ip/ip/kmac/rtl/kmac_app.sv index 73134adae..54303868e 100644 --- a/hw/vendor/lowrisc_ip/ip/kmac/rtl/kmac_app.sv +++ b/hw/vendor/lowrisc_ip/ip/kmac/rtl/kmac_app.sv @@ -20,21 +20,21 @@ module kmac_app input rst_ni, // Secret Key from register - input [MaxKeyLen-1:0] reg_key_data_i [Share], + input [MaxKeyLen-1:0] reg_key_data_i[Share], input key_len_e reg_key_len_i, // Prefix from register input [sha3_pkg::NSRegisterSize*8-1:0] reg_prefix_i, // mode, strength, kmac_en from register - input reg_kmac_en_i, + input logic reg_kmac_en_i, input sha3_pkg::sha3_mode_e reg_sha3_mode_i, input sha3_pkg::keccak_strength_e reg_keccak_strength_i, // Data from Software input sw_valid_i, input [MsgWidth-1:0] sw_data_i, - input [MsgWidth-1:0] sw_mask_i, + input [MsgWidth-1:0] sw_strb_i, output logic sw_ready_o, // KeyMgr Sideload Key interface @@ -45,14 +45,15 @@ module kmac_app output app_rsp_t [NumAppIntf-1:0] app_o, // to KMAC Core: Secret key - output logic [MaxKeyLen-1:0] key_data_o [Share], + output logic [MaxKeyLen-1:0] key_data_o[Share], output key_len_e key_len_o, output logic key_valid_o, // to MSG_FIFO output logic kmac_valid_o, - output logic [MsgWidth-1:0] kmac_data_o, - output logic [MsgWidth-1:0] kmac_mask_o, + output logic [MsgWidth-1:0] kmac_data_o[Share], + // This strobe is on bit level for the packer. The FIFO will then convert it again to byte level. + output logic [MsgWidth-1:0] kmac_strb_o, input kmac_ready_i, // KMAC Core @@ -65,19 +66,20 @@ module kmac_app // STATE from SHA3 Core input keccak_state_valid_i, - input [sha3_pkg::StateW-1:0] keccak_state_i [Share], + input [sha3_pkg::StateW-1:0] keccak_state_i[Share], // to STATE TL-window if Application is not active, the incoming state goes to // register if kdf_en is set, the state value goes to application and the // output to the register is all zero. output logic reg_state_valid_o, - output logic [sha3_pkg::StateW-1:0] reg_state_o [Share], + output logic [sha3_pkg::StateW-1:0] reg_state_o[Share], - // Configurations If key_en is set, the logic uses KeyMgr's sideloaded key as - // a secret key rather than register values. This only affects when software - // initiates. If App initiates the hash operation and uses KMAC algorithm, it - // always uses sideloaded key. - input keymgr_key_en_i, + // Controls for SW and CmdApp operations whether to take the key from the KeyMgr sideload + // interface or registers. For KMAC operations initiated by an app interface, we always take the + // sideloaded key. + // If 1, the key for KMAC is taken from the KeyMgr sideload interface. + // If 0, the key is taken from the registers. + input logic keymgr_key_en_i, // Commands // Command from software @@ -166,7 +168,7 @@ module kmac_app 24'h 02_0002 // Key512 }; - localparam logic [OutLenW-1:0] EncodedOutLenMask [5] = '{ + localparam logic [OutLenW-1:0] EncodedOutLenStrb [5] = '{ 24'h 00FFFF, // Key128, 24'h 00FFFF, // Key192 24'h FFFFFF, // Key256 @@ -200,7 +202,7 @@ module kmac_app logic clr_appid, set_appid; // Output length - logic [OutLenW-1:0] encoded_outlen, encoded_outlen_mask; + logic [OutLenW-1:0] encoded_outlen, encoded_outlen_strb; // state output // Mux selection signal @@ -600,7 +602,7 @@ module kmac_app // Encoded output length assign encoded_outlen = EncodedOutLen[SelDigSize]; - assign encoded_outlen_mask = EncodedOutLenMask[SelKeySize]; + assign encoded_outlen_strb = EncodedOutLenStrb[SelKeySize]; // Data mux // This is the main part of the KeyMgr interface logic. @@ -614,39 +616,39 @@ module kmac_app sw_ready_o = 1'b 1; kmac_valid_o = 1'b 0; - kmac_data_o = '0; - kmac_mask_o = '0; + kmac_data_o = '{default:'0}; + kmac_strb_o = '0; unique case (mux_sel_buf_kmac) SelApp: begin // app_id is valid at this time - kmac_valid_o = app_i[app_id].valid; - kmac_data_o = app_i[app_id].data; + kmac_valid_o = app_i[app_id].valid; + kmac_data_o[0] = app_i[app_id].data; // Expand strb to bits. prim_packer inside MSG_FIFO accepts the bit masks for (int i = 0 ; i < $bits(app_i[app_id].strb) ; i++) begin - kmac_mask_o[8*i+:8] = {8{app_i[app_id].strb[i]}}; + kmac_strb_o[8*i+:8] = {8{app_i[app_id].strb[i]}}; end app_data_ready = kmac_ready_i; end SelOutLen: begin // Write encoded output length value - kmac_valid_o = 1'b 1; // always write - kmac_data_o = MsgWidth'(encoded_outlen); - kmac_mask_o = MsgWidth'(encoded_outlen_mask); + kmac_valid_o = 1'b 1; // always write + kmac_data_o[0] = MsgWidth'(encoded_outlen); + kmac_strb_o = MsgWidth'(encoded_outlen_strb); end SelSw: begin - kmac_valid_o = sw_valid_i; - kmac_data_o = sw_data_i ; - kmac_mask_o = sw_mask_i ; - sw_ready_o = kmac_ready_i ; + kmac_valid_o = sw_valid_i; + kmac_data_o[0] = sw_data_i ; + kmac_strb_o = sw_strb_i ; + sw_ready_o = kmac_ready_i ; end default: begin // Incl. SelNone kmac_valid_o = 1'b 0; - kmac_data_o = '0; - kmac_mask_o = '0; + kmac_data_o = '{default:'0}; + kmac_strb_o = '0; end endcase @@ -741,7 +743,7 @@ module kmac_app end end - // Keccak state --> KeyMgr + // Keccak state --> App interface always_comb begin app_digest_done = 1'b 0; app_digest = '{default:'0}; @@ -764,7 +766,7 @@ module kmac_app // Prepare merged key if EnMasking is not set. // Combine share keys into unpacked array for logic below to assign easily. // SEC_CM: KEY.SIDELOAD - logic [MaxKeyLen-1:0] keymgr_key [Share]; + logic [MaxKeyLen-1:0] keymgr_key[Share]; if (EnMasking == 1) begin : g_masked_key for (genvar i = 0; i < Share; i++) begin : gen_key_pad assign keymgr_key[i] = {(MaxKeyLen-KeyMgrKeyW)'(0), keymgr_key_i.key[i]}; diff --git a/hw/vendor/lowrisc_ip/ip/kmac/rtl/kmac_msgfifo.sv b/hw/vendor/lowrisc_ip/ip/kmac/rtl/kmac_msgfifo.sv index 460dd9fdb..4f32e685e 100644 --- a/hw/vendor/lowrisc_ip/ip/kmac/rtl/kmac_msgfifo.sv +++ b/hw/vendor/lowrisc_ip/ip/kmac/rtl/kmac_msgfifo.sv @@ -15,7 +15,8 @@ module kmac_msgfifo // pushing to MsgFIFO parameter int OutWidth = 64, - parameter bit EnMasking = 1'b 1, + parameter bit EnMasking = 1'b 1, + localparam int Share = (EnMasking) ? 2 : 1, // derived parameter // Internal MsgFIFO Entry count parameter int MsgDepth = 9, @@ -25,16 +26,17 @@ module kmac_msgfifo input rst_ni, // from REG or KeyMgr Intf input - input fifo_valid_i, - input [OutWidth-1:0] fifo_data_i, - input [OutWidth-1:0] fifo_mask_i, - output fifo_ready_o, + input logic fifo_valid_i, + input [OutWidth-1:0] fifo_data_i[Share], + input [OutWidth-1:0] fifo_strb_i, + output logic fifo_ready_o, + input logic fifo_bypass_i, // MSG interface output logic msg_valid_o, - output logic [OutWidth-1:0] msg_data_o, + output logic [OutWidth-1:0] msg_data_o[Share], output logic [OutWidth/8-1:0] msg_strb_o, - input msg_ready_i, + input logic msg_ready_i, output logic fifo_empty_o, output logic fifo_full_o, @@ -43,14 +45,52 @@ module kmac_msgfifo // Control input prim_mubi_pkg::mubi4_t clear_i, - // process_i --> process_o - // process_o asserted after all internal messages are flushed out to MSG interface - input process_i, + // When process_i is asserted, packer and FIFO are flushed. Once flushed, process_o is asserted. + // When bypassing, nothing must be flushed. + input logic process_i, output logic process_o, err_t err_o ); + ////////////////// + // Bypass logic // + ////////////////// + // The packing and FIFO only support one share. These can be bypassed if operating with shares. + logic fifo_valid; + logic fifo_ready; + logic [OutWidth/8-1:0] fifo_strb_byte; + logic msg_valid; + logic msg_ready; + logic [OutWidth-1:0] msg_data[Share]; + logic [OutWidth/8-1:0] msg_strb; + + // Reduce strobe from bit to byte level as KMAC core operates on byte strobes. + always_comb begin + fifo_strb_byte = '0; + for (int i = 0; i < $bits(fifo_strb_byte); i++) begin + fifo_strb_byte[i] = |fifo_strb_i[8 * i +: 8]; + end + end + + assign fifo_valid = fifo_bypass_i ? '0 : fifo_valid_i; + assign fifo_ready_o = fifo_bypass_i ? msg_ready_i : fifo_ready; + assign msg_valid_o = fifo_bypass_i ? fifo_valid_i : msg_valid; + assign msg_ready = fifo_bypass_i ? '0 : msg_ready_i; + assign msg_strb_o = fifo_bypass_i ? fifo_strb_byte : msg_strb; + + for (genvar i = 0; i < Share; i++) begin : g_msg_data_bypass_mux + assign msg_data_o[i] = fifo_bypass_i ? fifo_data_i[i] : msg_data[i]; + end + + // If bypassing, packer and FIFO must not be flushed so we can gate the flush signal and + // feed it directly to process_o. + logic process_to_fifo; + logic process_from_fifo; + + assign process_to_fifo = fifo_bypass_i ? '0 : process_i; + assign process_o = fifo_bypass_i ? process_i : process_from_fifo; + ///////////////// // Definitions // ///////////////// @@ -99,37 +139,41 @@ module kmac_msgfifo // packer flush to msg_fifo, then msg_fifo empty out the internals // then assert msgfifo_flush_done + logic packer_flush; logic packer_flush_done; logic msgfifo_flush_done; logic packer_err; + assign packer_flush = process_to_fifo; + // SEC_CM: PACKER.CTR.REDUN prim_packer #( - .InW (OutWidth), - .OutW (OutWidth), - .HintByteData (1), + .InW(OutWidth), + .OutW(OutWidth), + .HintByteData(1), // Turn on dup counter when EnMasking is set - .EnProtection (EnMasking) + .EnProtection(EnMasking) ) u_packer ( .clk_i, .rst_ni, - .valid_i (fifo_valid_i), - .data_i (fifo_data_i), - .mask_i (fifo_mask_i), - .ready_o (fifo_ready_o), + .valid_i(fifo_valid), + // FIFO operates only on one share + .data_i (fifo_data_i[0]), + .mask_i (fifo_strb_i), + .ready_o(fifo_ready), - .valid_o (packer_wvalid), - .data_o (packer_wdata), - .mask_o (packer_wmask), - .ready_i (packer_wready), + .valid_o(packer_wvalid), + .data_o (packer_wdata), + .mask_o (packer_wmask), + .ready_i(packer_wready), - .flush_i (process_i), - .flush_done_o (packer_flush_done), + .flush_i (packer_flush), + .flush_done_o(packer_flush_done), - .err_o (packer_err) + .err_o(packer_err) ); // Assign packer wdata and wmask to FIFO struct @@ -171,10 +215,13 @@ module kmac_msgfifo assign fifo_wvalid = packer_wvalid; assign packer_wready = fifo_wready; - assign msg_valid_o = fifo_rvalid; - assign fifo_rready = msg_ready_i; - assign msg_data_o = fifo_rdata.data; - assign msg_strb_o = fifo_rdata.strb; + assign msg_valid = fifo_rvalid; + assign fifo_rready = msg_ready; + assign msg_strb = fifo_rdata.strb; + assign msg_data[0] = fifo_rdata.data; + for (genvar i = 1; i < Share; i++) begin : g_msg_data_mask_assignment + assign msg_data[i] = '0; + end assign fifo_empty_o = !fifo_rvalid; @@ -196,7 +243,9 @@ module kmac_msgfifo unique case (flush_st) FlushIdle: begin - if (process_i) begin + // Only enter packer-flush sequence when not in bypass mode. + // In bypass mode, process_o is driven directly from process_i below. + if (packer_flush) begin flush_st_d = FlushPacker; end else begin flush_st_d = FlushIdle; @@ -235,7 +284,7 @@ module kmac_msgfifo endcase end - assign process_o = msgfifo_flush_done; + assign process_from_fifo = msgfifo_flush_done; err_t error; assign err_o = error; @@ -273,12 +322,36 @@ module kmac_msgfifo `ASSERT(FlushStInValid_A, flush_st inside {FlushIdle, FlushPacker, FlushFifo, FlushClear}) // Packer done signal is asserted at least one cycle later - `ASSERT(PackerDoneDelay_A, $onehot0({process_i, packer_flush_done})) + `ASSERT(PackerDoneDelay_A, $onehot0({packer_flush, packer_flush_done})) // process_i not asserted during the flush operation - `ASSUME(PackerDoneValid_a, process_i |-> flush_st == FlushIdle) + `ASSUME(PackerDoneValid_a, packer_flush |-> flush_st == FlushIdle) // No messages in between `process_i` and `clear_i` `ASSUME(MessageValid_a, fifo_valid_i |-> flush_st == FlushIdle) +`ifdef INC_ASSERT + // INC_ASSERT is used to hide signal definitions that are only used for assertions. + //VCS coverage off + // pragma coverage off + + // Assert that fifo_bypass_i remains stable once the first messages was handshaked until the FIFO + // has been flushed or the full message is sent downstream, respectively. + logic first_data_entered; + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + first_data_entered <= 1'b0; + end else if (fifo_valid_i && fifo_ready_o) begin + first_data_entered <= 1'b1; + end else if (process_o) begin + first_data_entered <= 1'b0; + end + end + + `ASSERT(BypassCtrlStable_A, + first_data_entered && !process_o + |-> fifo_bypass_i == $past(fifo_bypass_i)) + +`endif + endmodule diff --git a/hw/vendor/lowrisc_ip/ip/lc_ctrl/dv/README.md b/hw/vendor/lowrisc_ip/ip/lc_ctrl/dv/README.md index 440edadd1..b1fed3a44 100644 --- a/hw/vendor/lowrisc_ip/ip/lc_ctrl/dv/README.md +++ b/hw/vendor/lowrisc_ip/ip/lc_ctrl/dv/README.md @@ -99,11 +99,11 @@ It also updates the UVM register model. ## Building and running tests -We are using our in-house developed [regression tool](../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test for the LC_CTRL variant with volatile RAW unlock disabled: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/ip/lc_ctrl/dv/lc_ctrl_volatile_unlock_disabled_sim.hjson -i lc_ctrl_smoke +$ dvsim $REPO_TOP/hw/ip/lc_ctrl/dv/lc_ctrl_volatile_unlock_disabled_sim.hjson -i lc_ctrl_smoke ``` ## Testplan diff --git a/hw/vendor/lowrisc_ip/ip/lc_ctrl/dv/env/lc_ctrl_env_cfg.sv b/hw/vendor/lowrisc_ip/ip/lc_ctrl/dv/env/lc_ctrl_env_cfg.sv index 3fd6209ef..3bf93ea2c 100644 --- a/hw/vendor/lowrisc_ip/ip/lc_ctrl/dv/env/lc_ctrl_env_cfg.sv +++ b/hw/vendor/lowrisc_ip/ip/lc_ctrl/dv/env/lc_ctrl_env_cfg.sv @@ -61,11 +61,11 @@ class lc_ctrl_env_cfg extends cip_base_env_cfg #( `uvm_object_new - virtual function void initialize(bit [31:0] csr_base_addr = '1); + virtual function void initialize(); list_of_alerts = lc_ctrl_env_pkg::LIST_OF_ALERTS; tl_intg_alert_name = "fatal_bus_integ_error"; sec_cm_alert_name = "fatal_state_error"; - super.initialize(csr_base_addr); + super.initialize(); // Find parameters on config db if (!uvm_config_db#(lc_ctrl_parameters_cfg)::get( diff --git a/hw/vendor/lowrisc_ip/ip/prim/README.md b/hw/vendor/lowrisc_ip/ip/prim/README.md index fc654fbe6..6d7a81243 100644 --- a/hw/vendor/lowrisc_ip/ip/prim/README.md +++ b/hw/vendor/lowrisc_ip/ip/prim/README.md @@ -348,9 +348,9 @@ After synthesizing the top module `prim_sdc_example` the following checks should 1. In the synthesized netlist, the following number of size_only instances must be present: -| cell names | buf | and2 | xor | xnor | flop | tie | clock_mux2 | clock_gating | -| -----------| ---- |------|----- |------ |------|-----|------------|--------------| -| #instances | 328 | 56 | 120 | 56 | 252 | 64 | 2 | 2 | +| cell names | buf | inv | and2 | xor | xnor | flop | tie | clock_mux2 | clock_gating | +| -----------| ---- | ---- |------|----- |------ |------|-----|------------|--------------| +| #instances | 328 | 56 | 56 | 120 | 56 | 252 | 64 | 2 | 2 | 2. None of the test_*_o signals can be driven by a constant 0 or 1. The instantiated `size_only` instances must prevent logic optimizations and keep the output comparators. @@ -364,7 +364,7 @@ This can be checked by the synthesis tool, e.g. `check_design -unloaded_comb/-un 5. `lc_en_i`, `mubi_i` signals can only be connected to variables, or legal values (`MuBi4True`, `MuBi4False`, `On`, `Off`) If all checks are successful, the same constraints can be applied to the full design. -The script `utils/design/check-netlist.py` [check-netlist] can be used to report a summary of size_only cells in a netlist. +The script `util/design/check-netlist.py` [check-netlist] can be used to report a summary of size_only cells in a netlist. It can also automate an initial version of checks (4) and (5) but it does **not** replace a final manual inspection of the netlist. [check-netlist]: https://github.com/lowRISC/opentitan/tree/master/util/design#netlist-checker-script diff --git a/hw/vendor/lowrisc_ip/ip/prim/prim.core b/hw/vendor/lowrisc_ip/ip/prim/prim.core index 15a25ce47..acfd82838 100644 --- a/hw/vendor/lowrisc_ip/ip/prim/prim.core +++ b/hw/vendor/lowrisc_ip/ip/prim/prim.core @@ -32,10 +32,13 @@ filesets: - lowrisc:prim:xor2 - lowrisc:prim:xnor2 - lowrisc:prim:and2 + - lowrisc:prim:inv - lowrisc:prim:reg_we_check - lowrisc:prim:sha2 files: - rtl/prim_clock_gating_sync.sv + - rtl/prim_hpc2.sv + - rtl/prim_hpc3.sv - rtl/prim_sram_arbiter.sv - rtl/prim_slicer.sv - rtl/prim_sync_reqack.sv @@ -48,6 +51,7 @@ filesets: - rtl/prim_pulse_sync.sv - rtl/prim_filter.sv - rtl/prim_filter_ctr.sv + - rtl/prim_flop_x.sv - rtl/prim_intr_hw.sv file_type: systemVerilogSource diff --git a/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async_simple.sv b/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async_simple.sv index 76ee140d7..36886a928 100644 --- a/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async_simple.sv +++ b/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_fifo_async_simple.sv @@ -28,14 +28,27 @@ module prim_fifo_async_simple #( output logic [Width-1:0] rdata_o ); + // write side + logic wr_en; + logic src_req, src_ack; + logic pending_d, pending_q, not_in_reset_q; + logic [Width-1:0] data_wr_q; + + // read side + logic rvalid_q; + logic rvalid_d; + logic dst_req; + logic dst_ack; + logic [Width-1:0] data_rd_q; + + ////////////////// + // Write domain // + ////////////////// + //////////////// // FIFO logic // //////////////// - // Convert ready/valid to req/ack - logic wr_en; - logic src_req, src_ack; - logic pending_d, pending_q, not_in_reset_q; assign wready_o = !pending_q && not_in_reset_q; assign wr_en = wvalid_i && wready_o; assign src_req = pending_q || wvalid_i; @@ -43,10 +56,6 @@ module prim_fifo_async_simple #( assign pending_d = (src_ack) ? 1'b0 : (wr_en) ? 1'b1 : pending_q; - logic dst_req, dst_ack; - assign rvalid_o = dst_req; - assign dst_ack = dst_req && rready_i; - always_ff @(posedge clk_wr_i or negedge rst_wr_ni) begin if (!rst_wr_ni) begin pending_q <= 1'b0; @@ -57,10 +66,16 @@ module prim_fifo_async_simple #( end end + // Data holding reg + always_ff @(posedge clk_wr_i) begin + if (wr_en) begin + data_wr_q <= wdata_i; + end + end + //////////////////////////////////// // REQ/ACK synchronizer primitive // //////////////////////////////////// - prim_sync_reqack #( .EnRstChks(EnRstChks), .EnRzHs(EnRzHs) @@ -76,16 +91,49 @@ module prim_fifo_async_simple #( .dst_ack_i(dst_ack) ); - ////////////////////// - // Data holding reg // - ////////////////////// + ///////////////// + // Read domain // + ///////////////// + // This flop realigns the request signal to the data + // and manages the ready/valid to ack/req protocol + always_comb begin - logic [Width-1:0] data_q; - always_ff @(posedge clk_wr_i) begin - if (wr_en) begin - data_q <= wdata_i; + rvalid_d = rvalid_q; + + if (!rvalid_q) begin + if (dst_req) begin + rvalid_d = '1; + end + end else begin + if (rready_i) begin + rvalid_d = '0; + end end + end - assign rdata_o = data_q; + + always_ff @(posedge clk_rd_i or negedge rst_rd_ni) begin + if (!rst_rd_ni) begin + rvalid_q <= '0; + end else begin + rvalid_q <= rvalid_d; + end + end + + // Output staging registers in the read domain to ensure data is synchronous + // and enable correct back pressure in the pipe. + // NOTE: data_rd_q must be read before it can be updated, i.e. rvalid_q is low, + // otherwise data that has not yet been read would be overwritten. + always_ff @(posedge clk_rd_i) begin + if (dst_req && !rvalid_q) begin + data_rd_q <= data_wr_q; + end + end + + assign rdata_o = data_rd_q; + + // condition the dst_ack and pass the state to rvalid + assign dst_ack = !rvalid_q ? dst_req : 1'b0; + assign rvalid_o = rvalid_q; endmodule diff --git a/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_flop_x.sv b/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_flop_x.sv new file mode 100644 index 000000000..97a3ba973 --- /dev/null +++ b/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_flop_x.sv @@ -0,0 +1,59 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// This module is used to wrap different prim_flop variants to allow selecting the desired +// variant on a per-case basis using a compile-time parameter. This is particularly useful for +// building deeply pipelined masked circuits. If constructed properly, it is sufficient to only +// enable/disable the very first pipeline stage in such designs. The later pipeline stages can +// only update in subsequent clock cycles anyway, meaning they don't need an explicit enable +// signal. This allows replacing the prim_flop_en with a regular prim_flop without multiplexer cell +// on the input, which helps the reducing area for the later register stages by roughly 20%. + +`include "prim_assert.sv" + +module prim_flop_x #( + parameter int Width = 1, + parameter logic [Width-1:0] ResetValue = '0, + parameter bit PrimFlopEn = 1, + parameter bit EnSecBuf = 0 // Ignored unless PrimFlopEn == 1. +) ( + input logic clk_i, + input logic rst_ni, + input logic en_i, + input logic [Width-1:0] d_i, + output logic [Width-1:0] q_o +); + + if (PrimFlopEn) begin : gen_prim_flop_en + // Instantiate a prim_flop_en primitive. + prim_flop_en #( + .Width(Width), + .EnSecBuf(EnSecBuf), + .ResetValue(ResetValue) + ) u_prim_flop ( + .clk_i, + .rst_ni, + .en_i, + .d_i, + .q_o + ); + + end else begin : gen_prim_flop + // Instantiate a regular prim_flop primitive without enable input. + prim_flop #( + .Width(Width), + .ResetValue(ResetValue) + ) u_prim_flop ( + .clk_i, + .rst_ni, + .d_i, + .q_o + ); + + // Tie-off the unused enable signal and EnSecBuf parameter. + logic unused_en; + assign unused_en = EnSecBuf ? ~en_i : en_i; + end + +endmodule diff --git a/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_hpc2.sv b/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_hpc2.sv new file mode 100644 index 000000000..d447e24f5 --- /dev/null +++ b/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_hpc2.sv @@ -0,0 +1,241 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`include "prim_assert.sv" + +// Description: PINI-secure Hardware Private Circuit (HPC2) / Toffoli Gadget (HPC2o) +// +// This module implements a Probe-Isolating Non-Interference (PINI) secure AND gadget (HPC2) or a +// Toffoli gadget (HPC2o), configured via the compile-time parameter `EnW`. All operands (W, X, Y) +// and the result (Z) are represented as boolean-shared bits in `NumShares` shares. +// +// Compile time configurations: +// - EnW = 0 (HPC2) : Computes the masked AND operation: Z = X & Y +// - EnW = 1 (HPC2o) : Computes the masked Toffoli operation: Z = W ^ (X & Y) +// +// Pipeline & Timing Requirements: +// - Randomness: The gadget is fully pipelined and consumes 1 bit of fresh randomness (`r_i`) per +// active cycle. +// - Asymmetric Latency: Due to internal staging, `y_i` and `r_i` have a 2-cycle latency, whereas +// `x_i` and `w_i` have a 1-cycle latency. Consequently, `y_i` and `r_i` must be driven at +// least one cycle prior to their corresponding `x_i` and `w_i` inputs. +// - Stall Support: To support stallable pipelines, the `en1_i` and `en2_i` flip-flop enable +// signals can be safely deasserted to freeze the internal registers and halt data propagation. +// +// For details, see the following paper: +// Cassiers, Gaetan, et al. "Compress: Generate small and fast masked pipelined circuits." +// available at: +// https://eprint.iacr.org/2023/1600.pdf + +module prim_hpc2 #( + parameter bit EnW = 1'b0, + parameter bit PrimFlopEn = 1'b1, + localparam int unsigned NumShares = 2 +) ( + input clk_i, + input rst_ni, + + // Pipeline stage enable signals. + input logic en1_i, + input logic en2_i, + + // Masked data inputs. + input logic [NumShares-1:0] x_i, + input logic [NumShares-1:0] y_i, + input logic [NumShares-1:0] w_i, + + // Randomness input. + input logic r_i, + + // Masked data output. + output logic [NumShares-1:0] z_o +); + + // Stage 1 outputs. + logic r_q; + logic [NumShares-1:0] y_q; + logic [NumShares-1:0] y_masked_d; + logic [NumShares-1:0] y_masked_q; + + // Stage 2 combinational nodes. + logic [NumShares-1:0] x_inv; + logic [NumShares-1:0] xy; // x[Share] & y_q[Share] + logic [NumShares-1:0] x_inv_r_d; // ~x[Share] & r_q + logic [NumShares-1:0] cross_prod_d; // x[Share] & y_masked_q[OtherShare] + logic [NumShares-1:0] inner_prod_d; // xy[Share] (^ w_i[Share] if EnW) + + // Stage 2 outputs. + logic [NumShares-1:0] x_inv_r_q; + logic [NumShares-1:0] inner_prod_q; + logic [NumShares-1:0] cross_prod_q; + logic [NumShares-1:0] merge_cross; + + // Stage 1: Register y, y^r, and r. + for (genvar Share = 0; Share < NumShares; Share++) begin : gen_y_masked + prim_xor2 #( + .Width(1) + ) u_prim_xor2 ( + .in0_i(y_i[Share]), + .in1_i(r_i), + .out_o(y_masked_d[Share]) + ); + end + + prim_flop_x #( + .Width(NumShares), + .ResetValue('0), + .PrimFlopEn(PrimFlopEn) + ) u_prim_flop_x_y_masked ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .en_i (en1_i), + .d_i (y_masked_d), + .q_o (y_masked_q) + ); + + prim_flop_x #( + .Width(1), + .ResetValue('0), + .PrimFlopEn(PrimFlopEn) + ) u_prim_flop_x_r ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .en_i (en1_i), + .d_i (r_i), + .q_o (r_q) + ); + + prim_flop_x #( + .Width(NumShares), + .ResetValue('0), + .PrimFlopEn(PrimFlopEn) + ) u_prim_flop_x_y ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .en_i (en1_i), + .d_i (y_i), + .q_o (y_q) + ); + + // Stage 2: Compute xy_masked, x_inv_r, and cross products. + for (genvar Share = 0; Share < NumShares; Share++) begin : gen_xy_masked + prim_and2 u_prim_and2 ( + .in0_i(x_i[Share]), + .in1_i(y_q[Share]), + .out_o(xy[Share]) + ); + + prim_inv u_prim_inv ( + .in_i (x_i[Share]), + .out_o(x_inv[Share]) + ); + + prim_and2 u_prim_and2_x_masked ( + .in0_i(x_inv[Share]), + .in1_i(r_q), + .out_o(x_inv_r_d[Share]) + ); + end + + // Cross products use the opposite share's y_masked_q (OtherShare = ~Share). + for (genvar Share = 0; Share < NumShares; Share++) begin : gen_cross_prod + localparam int OtherShare = (Share == 0) ? 1 : 0; + + prim_and2 u_prim_and2 ( + .in0_i(x_i[Share]), + .in1_i(y_masked_q[OtherShare]), + .out_o(cross_prod_d[Share]) + ); + end + + prim_flop_x #( + .Width(NumShares), + .ResetValue('0), + .PrimFlopEn(PrimFlopEn) + ) u_prim_flop_x_x_inv_r ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .en_i (en2_i), + .d_i (x_inv_r_d), + .q_o (x_inv_r_q) + ); + + prim_flop_x #( + .Width(NumShares), + .ResetValue('0), + .PrimFlopEn(PrimFlopEn) + ) u_prim_flop_x_cross_prod ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .en_i (en2_i), + .d_i (cross_prod_d), + .q_o (cross_prod_q) + ); + + // HPC2o (EnW=1): XOR w and xy_masked into the inner term before registering. + // HPC2 (EnW=0): register the inner term and xy_masked separately, XOR after. + if (EnW) begin : gen_xor_w + for (genvar Share = 0; Share < NumShares; Share++) begin : gen_inner_prod + prim_xor2 u_prim_xor2_w ( + .in0_i(xy[Share]), + .in1_i(w_i[Share]), + .out_o(inner_prod_d[Share]) + ); + end + + end else begin : gen_no_xor_w + for (genvar Share = 0; Share < NumShares; Share++) begin : gen_inner_prod + assign inner_prod_d[Share] = xy[Share]; + end + + // Consume unused w_i to avoid lint warnings. + logic unused_w; + assign unused_w = ^w_i; + end + + prim_flop_x #( + .Width(NumShares), + .ResetValue('0), + .PrimFlopEn(PrimFlopEn) + ) u_prim_flop_x_inner_prod ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .en_i (en2_i), + .d_i (inner_prod_d), + .q_o (inner_prod_q) + ); + + // Output: z[Share] = inner_prod_q[Share] ^ cross_prod_q[Share] + for (genvar Share = 0; Share < NumShares; Share++) begin : gen_z + prim_xor2 u_prim_xor2_merge_cross ( + .in0_i(cross_prod_q[Share]), + .in1_i(x_inv_r_q[Share]), + .out_o(merge_cross[Share]) + ); + + prim_xor2 u_prim_xor2_output ( + .in0_i(merge_cross[Share]), + .in1_i(inner_prod_q[Share]), + .out_o(z_o[Share]) + ); + end + + // Asymmetric latency: en1_i (y_i/r_i path) must have fired at least once + // before en2_i (x_i/w_i path) fires. Stalls are allowed between the two. + // Stage 1 must not be overwritten while its data is still pending in Stage 2. +`ifndef SYNTHESIS + logic s_stage1_pending; + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) s_stage1_pending <= 1'b0; + else s_stage1_pending <= en1_i || (s_stage1_pending && !en2_i); + end + + // Stage 2 may only fire if Stage 1 has been triggered since the last Stage 2. + `ASSERT(AsymLatencyEn1BeforeEn2, en2_i |-> s_stage1_pending, clk_i, !rst_ni) + // Stage 1 may not overwrite pending data unless Stage 2 is completing this cycle. + `ASSERT(AsymLatencyNoStage1Overwrite, + en1_i && s_stage1_pending |-> en2_i, clk_i, !rst_ni) +`endif + +endmodule : prim_hpc2 diff --git a/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_hpc3.sv b/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_hpc3.sv new file mode 100644 index 000000000..21b247b75 --- /dev/null +++ b/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_hpc3.sv @@ -0,0 +1,169 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Description: PINI-secure Hardware Private Circuit (HPC3) / Toffoli Gadget (HPC3o) +// +// This module implements a Probe-Isolating Non-Interference (PINI) secure AND gadget (HPC3) or a +// Toffoli gadget (HPC3o), configured via the compile-time parameter `EnW`. All operands (W, X, Y) +// and the result (Z) are represented as boolean-shared bits in `NumShares` shares. +// +// Compile time configurations: +// - EnW = 0 (HPC3) : Computes the masked AND operation: Z = X & Y +// - EnW = 1 (HPC3o) : Computes the masked Toffoli operation: Z = W ^ (X & Y) +// +// Pipeline & Timing Requirements: +// - Randomness: The gadget is fully pipelined and consumes 2 bits of fresh randomness +// (`r_i` and `rp_i`) per active cycle. +// - Symmetric Latency: All inputs (x_i, y_i, w_i, r_i, rp_i) share a uniform 1-cycle latency. +// Unlike HPC2, no input needs to be presented early. +// - Stall Support: To support stallable pipelines, the `en_i` flip-flop enable signal can be +// safely deasserted to freeze the internal registers and halt data propagation. +// +// For details, see the following paper: +// Cassiers, Gaetan, et al. "Compress: Generate small and fast masked pipelined circuits." +// available at: +// https://eprint.iacr.org/2023/1600.pdf + +module prim_hpc3 #( + parameter bit EnW = 1'b0, + parameter bit PrimFlopEn = 1'b1, + localparam int unsigned NumShares = 2 +) ( + input clk_i, + input rst_ni, + + // Pipeline stage enable signal. + input logic en_i, + + // Masked data inputs. + input logic [NumShares-1:0] x_i, + input logic [NumShares-1:0] y_i, + input logic [NumShares-1:0] w_i, + + // Fresh randomness (two bits per active cycle). + input logic r_i, + input logic rp_i, + + // Masked data output. + output logic [NumShares-1:0] z_o +); + + // Stage outputs. + logic [NumShares-1:0] x_q; + logic [NumShares-1:0] y_masked_d; + logic [NumShares-1:0] y_masked_q; + logic [NumShares-1:0] inner_prod_q; + + // Output-stage combinational nodes. + logic [NumShares-1:0] xy_masked; // x[Share] & (y[Share] ^ r) + logic [NumShares-1:0] inner_prod_d; // ((x[Share] & (y[Share] ^ r)) ^ rp) (^ w_i[Share] if EnW) + logic [NumShares-1:0] cross_prod; // x[Share] & (y[OtherShare] ^ r) + + // Stage (en_i): register x, y^r, and the inner product + for (genvar Share = 0; Share < NumShares; Share++) begin : gen_y_masked + prim_xor2 u_prim_xor2 ( + .in0_i(y_i[Share]), + .in1_i(r_i), + .out_o(y_masked_d[Share]) + ); + end + + prim_flop_x #( + .Width(NumShares), + .ResetValue('0), + .PrimFlopEn(PrimFlopEn) + ) u_prim_flop_x_y_masked ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .en_i (en_i), + .d_i (y_masked_d), + .q_o (y_masked_q) + ); + + prim_flop_x #( + .Width(NumShares), + .ResetValue('0), + .PrimFlopEn(PrimFlopEn) + ) u_prim_flop_x_x ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .en_i (en_i), + .d_i (x_i), + .q_o (x_q) + ); + + for (genvar Share = 0; Share < NumShares; Share++) begin : gen_xy_masked + prim_and2 u_prim_and2 ( + .in0_i(x_i[Share]), + .in1_i(y_masked_d[Share]), + .out_o(xy_masked[Share]) + ); + end + + // HPC3o (EnW=1): XOR w into the inner term before registering. + // HPC3 (EnW=0): inner term is just (x&y_masked) ^ rp. + if (EnW) begin : gen_xor_w + logic [NumShares-1:0] xyw_masked; // (x[Share] & (y[Share] ^ r)) ^ w[Share] + + for (genvar Share = 0; Share < NumShares; Share++) begin : gen_inner_prod + prim_xor2 u_prim_xor2_w ( + .in0_i(xy_masked[Share]), + .in1_i(w_i[Share]), + .out_o(xyw_masked[Share]) + ); + + prim_xor2 u_prim_xor2_d ( + .in0_i(xyw_masked[Share]), + .in1_i(rp_i), + .out_o(inner_prod_d[Share]) + ); + end + + end else begin : gen_no_xor_w + for (genvar Share = 0; Share < NumShares; Share++) begin : gen_inner_prod + prim_xor2 u_prim_xor2_x_masked ( + .in0_i(xy_masked[Share]), + .in1_i(rp_i), + .out_o(inner_prod_d[Share]) + ); + end + + // Consume unused w_i to avoid lint warnings. + logic unused_w; + assign unused_w = ^w_i; + end + + prim_flop_x #( + .Width(NumShares), + .ResetValue('0), + .PrimFlopEn(PrimFlopEn) + ) u_prim_flop_x_p_inner ( + .clk_i (clk_i), + .rst_ni(rst_ni), + .en_i (en_i), + .d_i (inner_prod_d), + .q_o (inner_prod_q) + ); + + // Output: cross products use the opposite share's y_masked_q (OtherShare = 1-Share), + // then z[Share] = inner_prod_q[Share] ^ cross_prod[Share] + for (genvar Share = 0; Share < NumShares; Share++) begin : gen_cross_prod + localparam int OtherShare = (Share == 0) ? 1 : 0; + + prim_and2 u_prim_and2 ( + .in0_i(x_q[Share]), + .in1_i(y_masked_q[OtherShare]), + .out_o(cross_prod[Share]) + ); + end + + for (genvar Share = 0; Share < NumShares; Share++) begin : gen_z + prim_xor2 u_prim_xor2 ( + .in0_i(inner_prod_q[Share]), + .in1_i(cross_prod[Share]), + .out_o(z_o[Share]) + ); + end + +endmodule : prim_hpc3 diff --git a/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_sdc_example.sv b/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_sdc_example.sv index 924b9c07b..e6b847727 100644 --- a/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_sdc_example.sv +++ b/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_sdc_example.sv @@ -9,21 +9,21 @@ // // 1. In the synthesized netlist, the following number of size_only instances must be present: // e.g. grep -c -R u_size_only_x netlist.v (make sure the design is uniquified) -// |-------------------------------------------------------------------------| -// | Test | buf | and2 | xor | xnor | flop | tie | clock_mux2 | clock_gating | -// | -----| ----|------|-----|------|------|-----|------------|--------------| -// | 1 | 192 | - | - | - | - | 64 | - | - | -// | 2 | - | - | 64 | - | - | - | - | - | -// | 3 | 48 | 48 | 48 | 48 | 144 | - | - | - | -// | 4 | 8 | 8 | 8 | 8 | 24 | - | - | - | -// | 5 | 36 | - | - | - | 24 | - | - | - | -// | 6 | 16 | - | - | - | 8 | - | - | - | -// | 7 | - | - | - | - | 32 | - | 2 | 2 | -// | 8 | 16 | - | - | - | 8 | - | - | - | -// | 9 | 12 | - | - | - | 12 | - | - | - | -// | -----| ----|------|-----|------|------|-----|------------|--------------| -// |total | 328 | 56 | 120 | 56 | 252 | 64 | 2 | 2 | -// |-------------------------------------------------------------------------| +// |-------------------------------------------------------------------------------| +// | Test | buf | inv | and2 | xor | xnor | flop | tie | clock_mux2 | clock_gating | +// | -----|-----|-----|------|-----|------|------|-----|------------|--------------| +// | 1 | 192 | - | - | - | - | - | 64 | - | - | +// | 2 | - | - | - | 64 | - | - | - | - | - | +// | 3 | 48 | 48 | 48 | 48 | 48 | 144 | - | - | - | +// | 4 | 8 | 8 | 8 | 8 | 8 | 24 | - | - | - | +// | 5 | 36 | - | - | - | - | 24 | - | - | - | +// | 6 | 16 | - | - | - | - | 8 | - | - | - | +// | 7 | - | - | - | - | - | 32 | - | 2 | 2 | +// | 8 | 16 | - | - | - | - | 8 | - | - | - | +// | 9 | 12 | - | - | - | - | 12 | - | - | - | +// | -----|-----|-----|------|-----|------|------|-----|------------|--------------| +// |total | 328 | 56 | 56 | 120 | 56 | 252 | 64 | 2 | 2 | +// |-------------------------------------------------------------------------------| // // 2. None of the test_*_o signals can be driven by a constant 0 or 1. // The instantiated size_only instances must prevent logic optimizations and keep @@ -198,13 +198,14 @@ module prim_sdc_example #( // These gates cannot be removed // The following size_only cells are expected: // 6*8 size_only_buf + // 6*8 size_only_inv // 6*8 size_only_and2 // 6*8 size_only_xor // 6*8 size_only_xnor // 6*8*3 size_only_flop localparam int unsigned NumConst = 6; - localparam int unsigned NumGates = 7; + localparam int unsigned NumGates = 8; localparam logic [Width-1:0] ConstIn0 [NumConst] = {8'hAB, 8'hBA, @@ -280,6 +281,13 @@ module prim_sdc_example #( .d_i (ConstIn0[idx]), .q_o (const_out_not_removed[idx][6]) ); + + prim_inv #( + .Width(Width) + ) u_prim_inv ( + .in_i (ConstIn0[idx]), + .out_o(const_out_not_removed[idx][7]) + ); end assign test_const_o = ^const_out_not_removed; @@ -289,6 +297,7 @@ module prim_sdc_example #( /////////////////////////////////////////////////// // The following size_only cells are expected: // 8 size_only_buf + // 8 size_only_inv // 8 size_only_and2 // 8 size_only_xor // 8 size_only_xnor @@ -347,6 +356,12 @@ module prim_sdc_example #( .d_i (data_a[Width-1:0]), .q_o (var_out_not_removed[6]) ); + prim_inv #( + .Width(Width) + ) u_prim_inv ( + .in_i (data_a[Width-1:0]), + .out_o(var_out_not_removed[7]) + ); assign test_var_o = ^var_out_not_removed; diff --git a/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack.sv b/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack.sv index 6fafcb840..fb9246ca9 100644 --- a/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack.sv +++ b/hw/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack.sv @@ -61,7 +61,8 @@ module prim_sync_reqack #( // Types typedef enum logic { - LoSt, HiSt + LoSt = 1'b0, + HiSt = 1'b1 } rz_fsm_e; // Signals @@ -74,7 +75,6 @@ module prim_sync_reqack #( always_comb begin : src_fsm src_fsm_d = src_fsm_q; src_ack_o = 1'b0; - src_req = 1'b0; unique case (src_fsm_q) LoSt: begin @@ -85,7 +85,6 @@ module prim_sync_reqack #( end end HiSt: begin - src_req = 1'b1; // Forward the acknowledgement. src_ack_o = src_ack; // If request drops out, we go back to LoSt. @@ -121,11 +120,12 @@ module prim_sync_reqack #( end end + assign src_req = logic'(src_fsm_q); + // ACK-side FSM (DST domain) always_comb begin : dst_fsm dst_fsm_d = dst_fsm_q; dst_req_o = 1'b0; - dst_ack = 1'b0; unique case (dst_fsm_q) LoSt: begin @@ -140,7 +140,6 @@ module prim_sync_reqack #( end end HiSt: begin - dst_ack = 1'b1; // Wait for the request to drop back to zero. if (!dst_req) begin dst_fsm_d = LoSt; @@ -173,6 +172,8 @@ module prim_sync_reqack #( end end + assign dst_ack = logic'(dst_fsm_q); + end else begin : gen_nrz_hs_protocol ////////////////// // NRZ protocol // diff --git a/hw/vendor/lowrisc_ip/ip/prim_generic/prim_generic.core b/hw/vendor/lowrisc_ip/ip/prim_generic/prim_generic.core index 7bf7dc9c1..6d9314ebc 100644 --- a/hw/vendor/lowrisc_ip/ip/prim_generic/prim_generic.core +++ b/hw/vendor/lowrisc_ip/ip/prim_generic/prim_generic.core @@ -33,6 +33,7 @@ filesets: - lowrisc:prim_generic:xnor2 - lowrisc:prim_generic:xor2 - lowrisc:prim_generic:flop_no_rst + - lowrisc:prim_generic:inv # Note that flash is a macro that depends on IPs, so they are not # included here. They must be brought in explicitly. # - lowrisc:prim_generic:flash @@ -62,6 +63,7 @@ mapping: "lowrisc:prim:xnor2" : "lowrisc:prim_generic:xnor2" "lowrisc:prim:xor2" : "lowrisc:prim_generic:xor2" "lowrisc:prim:flop_no_rst" : "lowrisc:prim_generic:flop_no_rst" + "lowrisc:prim:inv" : "lowrisc:prim_generic:inv" # Flash is a good canditate to be removed from the prims and become a macro like OTP. # TODO(#27042): When this is done, it should be removed from this mapping. "lowrisc:prim:flash": "lowrisc:prim_generic:flash" diff --git a/hw/vendor/lowrisc_ip/ip/prim_generic/prim_generic_inv.core b/hw/vendor/lowrisc_ip/ip/prim_generic/prim_generic_inv.core new file mode 100644 index 000000000..84c7e71b2 --- /dev/null +++ b/hw/vendor/lowrisc_ip/ip/prim_generic/prim_generic_inv.core @@ -0,0 +1,38 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim_generic:inv" +description: "inverter" +virtual: + - lowrisc:prim:inv + +filesets: + files_rtl: + files: + - rtl/prim_inv.sv + file_type: systemVerilogSource + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + +targets: + default: + filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) + - files_rtl diff --git a/hw/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_inv.sv b/hw/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_inv.sv new file mode 100644 index 000000000..4186ffe08 --- /dev/null +++ b/hw/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_inv.sv @@ -0,0 +1,16 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`include "prim_assert.sv" + +module prim_inv #( + parameter int Width = 1 +) ( + input logic [Width-1:0] in_i, + output logic [Width-1:0] out_o +); + + assign out_o = ~in_i; + +endmodule diff --git a/hw/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx.core b/hw/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx.core index d222605da..9d59dbbea 100644 --- a/hw/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx.core +++ b/hw/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx.core @@ -32,6 +32,7 @@ filesets: - lowrisc:prim_generic:usb_diff_rx - lowrisc:prim_xilinx:xnor2 - lowrisc:prim_xilinx:xor2 + - lowrisc:prim_xilinx:inv # Note that flash is a macro that depends on IPs, so they are not # included here. They must be brought in explicitly. # - lowrisc:prim_generic:flash @@ -60,6 +61,7 @@ mapping: "lowrisc:prim:usb_diff_rx" : lowrisc:prim_generic:usb_diff_rx "lowrisc:prim:xnor2" : lowrisc:prim_xilinx:xnor2 "lowrisc:prim:xor2" : lowrisc:prim_xilinx:xor2 + "lowrisc:prim:inv" : lowrisc:prim_xilinx:inv # Flash is a good canditate to be removed from the prims and become a macro like OTP. # When this is done, it should be removed from this mapping. "lowrisc:prim:flash": "lowrisc:prim_generic:flash" diff --git a/hw/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_inv.core b/hw/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_inv.core new file mode 100644 index 000000000..1f914d88a --- /dev/null +++ b/hw/vendor/lowrisc_ip/ip/prim_xilinx/prim_xilinx_inv.core @@ -0,0 +1,40 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim_xilinx:inv" +description: "Xilinx inverter" +virtual: + - lowrisc:prim:inv + +filesets: + files_rtl: + files: + - rtl/prim_inv.sv + file_type: systemVerilogSource + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + +targets: + default: + filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) + - files_rtl diff --git a/hw/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_inv.sv b/hw/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_inv.sv new file mode 100644 index 000000000..b42fac6b7 --- /dev/null +++ b/hw/vendor/lowrisc_ip/ip/prim_xilinx/rtl/prim_inv.sv @@ -0,0 +1,16 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Prevent Vivado from performing optimizations on/across this module. +(* DONT_TOUCH = "yes" *) +module prim_inv #( + parameter int Width = 1 +) ( + input logic [Width-1:0] in_i, + output logic [Width-1:0] out_o +); + + assign out_o = ~in_i; + +endmodule diff --git a/hw/vendor/lowrisc_ip/ip/rom_ctrl/dv/README.md b/hw/vendor/lowrisc_ip/ip/rom_ctrl/dv/README.md index 2aad7a487..e29d17948 100644 --- a/hw/vendor/lowrisc_ip/ip/rom_ctrl/dv/README.md +++ b/hw/vendor/lowrisc_ip/ip/rom_ctrl/dv/README.md @@ -87,11 +87,11 @@ Traffic from the ROM TLUL interface is monitored and compared against memory mod * Unknown checks on DUT outputs: The RTL has assertions to ensure all outputs are initialized to known values after coming out of reset. ## Building and running tests -We are using our in-house developed [regression tool](../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/ip/rom_ctrl/dv/rom_ctrl_sim_cfg.hjson -i rom_ctrl_smoke +$ dvsim $REPO_TOP/hw/ip/rom_ctrl/dv/rom_ctrl_sim_cfg.hjson -i rom_ctrl_smoke ``` ## Testplan diff --git a/hw/vendor/lowrisc_ip/ip/rom_ctrl/dv/env/rom_ctrl_env_cfg.sv b/hw/vendor/lowrisc_ip/ip/rom_ctrl/dv/env/rom_ctrl_env_cfg.sv index 0f2b5bed3..d6f6776e9 100644 --- a/hw/vendor/lowrisc_ip/ip/rom_ctrl/dv/env/rom_ctrl_env_cfg.sv +++ b/hw/vendor/lowrisc_ip/ip/rom_ctrl/dv/env/rom_ctrl_env_cfg.sv @@ -26,7 +26,7 @@ class rom_ctrl_env_cfg extends cip_base_env_cfg #(.RAL_T(rom_ctrl_regs_reg_block extern constraint kmac_accept_delay_max_c; extern function new (string name=""); - extern virtual function void initialize(bit [31:0] csr_base_addr = '1); + extern virtual function void initialize(); extern virtual protected function dv_base_reg_block create_ral_by_name(string name); `uvm_object_utils_begin(rom_ctrl_env_cfg) @@ -67,8 +67,8 @@ function rom_ctrl_env_cfg::new (string name=""); sec_cm_alert_name = "fatal"; endfunction -function void rom_ctrl_env_cfg::initialize(bit [31:0] csr_base_addr = '1); - super.initialize(csr_base_addr); +function void rom_ctrl_env_cfg::initialize(); + super.initialize(); // default TLUL supports 1 outstanding item, the rom TLUL supports 2 outstanding items. m_tl_agent_cfgs[RAL_T::type_name].max_outstanding_req = 1; diff --git a/hw/vendor/lowrisc_ip/ip/rv_timer/dv/README.md b/hw/vendor/lowrisc_ip/ip/rv_timer/dv/README.md index de88f993b..d124e9d6b 100644 --- a/hw/vendor/lowrisc_ip/ip/rv_timer/dv/README.md +++ b/hw/vendor/lowrisc_ip/ip/rv_timer/dv/README.md @@ -98,11 +98,11 @@ Interrupt pins are checked against expected at every read/write data channel. * Unknown checks on DUT outputs: The RTL has assertions to ensure all outputs are initialized to known values after coming out of reset ## Building and running tests -We are using our in-house developed [regression tool](../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/ip/rv_timer/dv/rv_timer_sim_cfg.hjson -i rv_timer_smoke +$ dvsim $REPO_TOP/hw/ip/rv_timer/dv/rv_timer_sim_cfg.hjson -i rv_timer_smoke ``` ## Testplan diff --git a/hw/vendor/lowrisc_ip/ip/rv_timer/dv/env/rv_timer_env_cfg.sv b/hw/vendor/lowrisc_ip/ip/rv_timer/dv/env/rv_timer_env_cfg.sv index 835e50dbb..5de12eff5 100644 --- a/hw/vendor/lowrisc_ip/ip/rv_timer/dv/env/rv_timer_env_cfg.sv +++ b/hw/vendor/lowrisc_ip/ip/rv_timer/dv/env/rv_timer_env_cfg.sv @@ -6,9 +6,9 @@ class rv_timer_env_cfg extends cip_base_env_cfg #(.RAL_T(rv_timer_reg_block)); `uvm_object_utils(rv_timer_env_cfg) `uvm_object_new - virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1); + virtual function void initialize(); list_of_alerts = rv_timer_env_pkg::LIST_OF_ALERTS; - super.initialize(csr_base_addr); + super.initialize(); // set num_interrupts num_interrupts = NUM_HARTS * NUM_TIMERS; diff --git a/hw/vendor/lowrisc_ip/ip/spi_device/dv/README.md b/hw/vendor/lowrisc_ip/ip/spi_device/dv/README.md index 97b6fa973..c41377b6a 100644 --- a/hw/vendor/lowrisc_ip/ip/spi_device/dv/README.md +++ b/hw/vendor/lowrisc_ip/ip/spi_device/dv/README.md @@ -90,11 +90,11 @@ It creates the following analysis FIFOs to retrieve the data monitored by corres * Unknown checks on DUT outputs: The RTL has assertions to ensure all outputs are initialized to known values after coming out of reset. ## Building and running tests -We are using our in-house developed [regression tool](../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/ip/spi_device/dv/spi_device_1r1w_sim_cfg.hjson -i spi_device_smoke +$ dvsim $REPO_TOP/hw/ip/spi_device/dv/spi_device_1r1w_sim_cfg.hjson -i spi_device_smoke ``` ## Testplan diff --git a/hw/vendor/lowrisc_ip/ip/spi_device/dv/env/spi_device_env_cfg.sv b/hw/vendor/lowrisc_ip/ip/spi_device/dv/env/spi_device_env_cfg.sv index f338f218d..872660c73 100644 --- a/hw/vendor/lowrisc_ip/ip/spi_device/dv/env/spi_device_env_cfg.sv +++ b/hw/vendor/lowrisc_ip/ip/spi_device/dv/env/spi_device_env_cfg.sv @@ -56,9 +56,9 @@ class spi_device_env_cfg extends cip_base_env_cfg #(.RAL_T(spi_device_reg_block) scb_clear_mems = 1; endfunction - virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1); + virtual function void initialize(); list_of_alerts = spi_device_env_pkg::LIST_OF_ALERTS; - super.initialize(csr_base_addr); + super.initialize(); // create spi agent config obj spi_host_agent_cfg = spi_agent_cfg::type_id::create("spi_host_agent_cfg"); spi_device_agent_cfg = spi_agent_cfg::type_id::create("spi_device_agent_cfg"); diff --git a/hw/vendor/lowrisc_ip/ip/spi_host/dv/README.md b/hw/vendor/lowrisc_ip/ip/spi_host/dv/README.md index f903b58ac..f2b22f396 100644 --- a/hw/vendor/lowrisc_ip/ip/spi_host/dv/README.md +++ b/hw/vendor/lowrisc_ip/ip/spi_host/dv/README.md @@ -260,11 +260,11 @@ This way both outgoing and incoming transactions are validated independently of ## Building and running tests -We are using our in-house developed [regression tool](../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/ip/spi_host/dv/spi_host_sim_cfg.hjson -i spi_host_smoke +$ dvsim $REPO_TOP/hw/ip/spi_host/dv/spi_host_sim_cfg.hjson -i spi_host_smoke ``` ## Testplan diff --git a/hw/vendor/lowrisc_ip/ip/spi_host/dv/env/spi_host_env_cfg.sv b/hw/vendor/lowrisc_ip/ip/spi_host/dv/env/spi_host_env_cfg.sv index 5d0a30884..94ce49532 100644 --- a/hw/vendor/lowrisc_ip/ip/spi_host/dv/env/spi_host_env_cfg.sv +++ b/hw/vendor/lowrisc_ip/ip/spi_host/dv/env/spi_host_env_cfg.sv @@ -52,9 +52,9 @@ class spi_host_env_cfg extends cip_base_env_cfg #(.RAL_T(spi_host_reg_block)); `uvm_object_new - virtual function void initialize(bit [31:0] csr_base_addr = '1); + virtual function void initialize(); list_of_alerts = spi_host_env_pkg::LIST_OF_ALERTS; - super.initialize(csr_base_addr); + super.initialize(); // create spi_host agent config obj m_spi_agent_cfg = spi_agent_cfg::type_id::create("m_spi_agent_cfg"); diff --git a/hw/vendor/lowrisc_ip/ip/tlul/doc/dv/README.md b/hw/vendor/lowrisc_ip/ip/tlul/doc/dv/README.md index 610f1651e..f9767e799 100644 --- a/hw/vendor/lowrisc_ip/ip/tlul/doc/dv/README.md +++ b/hw/vendor/lowrisc_ip/ip/tlul/doc/dv/README.md @@ -112,11 +112,11 @@ We set the source of expected item to 0 before put it into scoreboard queue and * Unknown checks on DUT outputs: The RTL has assertions to ensure all outputs are initialized to known values after coming out of reset. ## Building and running tests -We are using our in-house developed [regression tool](../../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/$CHIP/ip/$XBAR_IP/dv/autogen/${XBAR_IP}_sim_cfg.hjson -i xbar_smoke +$ dvsim $REPO_TOP/hw/$CHIP/ip/$XBAR_IP/dv/autogen/${XBAR_IP}_sim_cfg.hjson -i xbar_smoke ``` In this run command, $XBAR_IP can be xbar_main, xbar_peri, etc. $CHIP can be top_earlgrey, etc. diff --git a/hw/vendor/lowrisc_ip/ip/tlul/generic_dv/env/xbar_env_cfg.sv b/hw/vendor/lowrisc_ip/ip/tlul/generic_dv/env/xbar_env_cfg.sv index e645243f4..dcc845662 100644 --- a/hw/vendor/lowrisc_ip/ip/tlul/generic_dv/env/xbar_env_cfg.sv +++ b/hw/vendor/lowrisc_ip/ip/tlul/generic_dv/env/xbar_env_cfg.sv @@ -42,7 +42,7 @@ class xbar_env_cfg extends dv_base_env_cfg; `uvm_object_new - virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1); + virtual function void initialize(); is_initialized = 1'b1; ral_model_names = {}; // no csr in xbar // Host TL agent cfg diff --git a/hw/vendor/lowrisc_ip/ip/tlul/rtl/tlul_assert.sv b/hw/vendor/lowrisc_ip/ip/tlul/rtl/tlul_assert.sv index 43a2656e8..c69e4848a 100644 --- a/hw/vendor/lowrisc_ip/ip/tlul/rtl/tlul_assert.sv +++ b/hw/vendor/lowrisc_ip/ip/tlul/rtl/tlul_assert.sv @@ -259,49 +259,101 @@ module tlul_assert #( if (EndpointType == "Host") begin : gen_host // h2d if (1) begin : gen_h2d - legalAOpcode_A: assert property (h2d_pre_S |-> legalAOpcode_S); - legalAParam_A: assert property (h2d_pre_S |-> legalAParam_S); - sizeGTEMask_A: assert property (h2d_pre_S |-> sizeGTEMask_S); - sizeMatchesMask_A: assert property (h2d_pre_S |-> sizeMatchesMask_S); - pendingReqPerSrc_A: assert property (h2d_pre_S |-> pendingReqPerSrc_S); - addrSizeAligned_A: assert property (h2d_pre_S |-> addrSizeAligned_S); - contigMask_A: assert property (h2d_pre_S and contigMask_pre_S |-> contigMask_S); - aDataKnown_A: assert property (h2d_pre_S and aDataKnown_pre_S |-> aDataKnown_S); + legalAOpcode_A: + assert property (h2d_pre_S |-> legalAOpcode_S) + else `ASSERT_ERROR(legalAOpcode_A) + legalAParam_A: + assert property (h2d_pre_S |-> legalAParam_S) + else `ASSERT_ERROR(legalAParam_A) + sizeGTEMask_A: + assert property (h2d_pre_S |-> sizeGTEMask_S) + else `ASSERT_ERROR(sizeGTEMask_A) + sizeMatchesMask_A: + assert property (h2d_pre_S |-> sizeMatchesMask_S) + else `ASSERT_ERROR(sizeMatchesMask_A) + pendingReqPerSrc_A: + assert property (h2d_pre_S |-> pendingReqPerSrc_S) + else `ASSERT_ERROR(pendingReqPerSrc_A) + addrSizeAligned_A: + assert property (h2d_pre_S |-> addrSizeAligned_S) + else `ASSERT_ERROR(addrSizeAligned_A) + contigMask_A: + assert property (h2d_pre_S and contigMask_pre_S |-> contigMask_S) + else `ASSERT_ERROR(contigMask_A) + aDataKnown_A: + assert property (h2d_pre_S and aDataKnown_pre_S |-> aDataKnown_S) + else `ASSERT_ERROR(aDataKnown_A) end // d2h if (1) begin : gen_d2h - respOpcode_M: assume property (d2h_pre_S |-> respOpcode_S); - legalDParam_M: assume property (d2h_pre_S |-> legalDParam_S); - respSzEqReqSz_M: assume property (d2h_pre_S |-> respSzEqReqSz_S); - respMustHaveReq_M: assume property (d2h_pre_S |-> respMustHaveReq_S); - dDataKnown_M: assume property (d2h_pre_S and dDataKnown_pre_S |-> dDataKnown_S); + respOpcode_M: + assume property (d2h_pre_S |-> respOpcode_S) + else `ASSERT_ERROR(respOpcode_M) + legalDParam_M: + assume property (d2h_pre_S |-> legalDParam_S) + else `ASSERT_ERROR(legalDParam_M) + respSzEqReqSz_M: + assume property (d2h_pre_S |-> respSzEqReqSz_S) + else `ASSERT_ERROR(respSzEqReqSz_M) + respMustHaveReq_M: + assume property (d2h_pre_S |-> respMustHaveReq_S) + else `ASSERT_ERROR(respMustHaveReq_M) + dDataKnown_M: + assume property (d2h_pre_S and dDataKnown_pre_S |-> dDataKnown_S) + else `ASSERT_ERROR(dDataKnown_M) end // in this case all signals coming from the host side have an assumed property end else if (EndpointType == "Device") begin : gen_device // h2d if (1) begin : gen_h2d - legalAParam_M: assume property (h2d_pre_S |-> legalAParam_S); - pendingReqPerSrc_M: assume property (h2d_pre_S |-> pendingReqPerSrc_S); - aDataKnown_M: assume property (h2d_pre_S and aDataKnown_pre_S |-> aDataKnown_S); - contigMask_M: assume property (h2d_pre_S and contigMask_pre_S |-> contigMask_S); + legalAParam_M: + assume property (h2d_pre_S |-> legalAParam_S) + else `ASSERT_ERROR(legalAParam_M) + pendingReqPerSrc_M: + assume property (h2d_pre_S |-> pendingReqPerSrc_S) + else `ASSERT_ERROR(pendingReqPerSrc_M) + aDataKnown_M: + assume property (h2d_pre_S and aDataKnown_pre_S |-> aDataKnown_S) + else `ASSERT_ERROR(aDataKnown_M) + contigMask_M: + assume property (h2d_pre_S and contigMask_pre_S |-> contigMask_S) + else `ASSERT_ERROR(contigMask_M) end // d2h if (1) begin : gen_d2h - respOpcode_A: assert property (d2h_pre_S |-> respOpcode_S); - legalDParam_A: assert property (d2h_pre_S |-> legalDParam_S); - respSzEqReqSz_A: assert property (d2h_pre_S |-> respSzEqReqSz_S); - respMustHaveReq_A: assert property (d2h_pre_S |-> respMustHaveReq_S); - dDataKnown_A: assert property (d2h_pre_S and dDataKnown_pre_S |-> dDataKnown_S); + respOpcode_A: + assert property (d2h_pre_S |-> respOpcode_S) + else `ASSERT_ERROR(respOpcode_A) + legalDParam_A: + assert property (d2h_pre_S |-> legalDParam_S) + else `ASSERT_ERROR(legalDParam_A) + respSzEqReqSz_A: + assert property (d2h_pre_S |-> respSzEqReqSz_S) + else `ASSERT_ERROR(respSzEqReqSz_A) + respMustHaveReq_A: + assert property (d2h_pre_S |-> respMustHaveReq_S) + else `ASSERT_ERROR(respMustHaveReq_A) + dDataKnown_A: + assert property (d2h_pre_S and dDataKnown_pre_S |-> dDataKnown_S) + else `ASSERT_ERROR(dDataKnown_A) // d2h error cases - legalAOpcodeErr_A: assert property (d_error_pre_S and legalAOpcodeErr_S |=> - s_eventually (d2h.d_valid && d2h.d_error)); - sizeGTEMaskErr_A: assert property (d_error_pre_S and sizeGTEMaskErr_S |=> - s_eventually (d2h.d_valid && d2h.d_error)); - sizeMatchesMaskErr_A: assert property (d_error_pre_S and sizeMatchesMaskErr_S |=> - s_eventually (d2h.d_valid && d2h.d_error)); - addrSizeAlignedErr_A: assert property (d_error_pre_S and addrSizeAlignedErr_S |=> - s_eventually (d2h.d_valid && d2h.d_error)); + legalAOpcodeErr_A: + assert property (d_error_pre_S and legalAOpcodeErr_S |=> + s_eventually (d2h.d_valid && d2h.d_error)) + else `ASSERT_ERROR(legalAOpcodeErr_A) + sizeGTEMaskErr_A: + assert property (d_error_pre_S and sizeGTEMaskErr_S |=> + s_eventually (d2h.d_valid && d2h.d_error)) + else `ASSERT_ERROR(sizeGTEMaskErr_A) + sizeMatchesMaskErr_A: + assert property (d_error_pre_S and sizeMatchesMaskErr_S |=> + s_eventually (d2h.d_valid && d2h.d_error)) + else `ASSERT_ERROR(sizeMatchesMaskErr_A) + addrSizeAlignedErr_A: + assert property (d_error_pre_S and addrSizeAlignedErr_S |=> + s_eventually (d2h.d_valid && d2h.d_error)) + else `ASSERT_ERROR(addrSizeAlignedErr_A) end end else begin : gen_unknown initial begin : p_unknown diff --git a/hw/vendor/lowrisc_ip/ip/uart/dv/README.md b/hw/vendor/lowrisc_ip/ip/uart/dv/README.md index a6de5c2eb..e3c8663b3 100644 --- a/hw/vendor/lowrisc_ip/ip/uart/dv/README.md +++ b/hw/vendor/lowrisc_ip/ip/uart/dv/README.md @@ -95,11 +95,11 @@ It creates the following analysis FIFOs to retrieve the data monitored by corres * Unknown checks on DUT outputs: The RTL has assertions to ensure all outputs are initialized to known values after coming out of reset. ## Building and running tests -We are using our in-house developed [regression tool](../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/ip/uart/dv/uart_sim_cfg.hjson -i uart_smoke +$ dvsim $REPO_TOP/hw/ip/uart/dv/uart_sim_cfg.hjson -i uart_smoke ``` ## Testplan diff --git a/hw/vendor/lowrisc_ip/ip/uart/dv/env/uart_env_cfg.sv b/hw/vendor/lowrisc_ip/ip/uart/dv/env/uart_env_cfg.sv index 406ae6a8b..9b9826c30 100644 --- a/hw/vendor/lowrisc_ip/ip/uart/dv/env/uart_env_cfg.sv +++ b/hw/vendor/lowrisc_ip/ip/uart/dv/env/uart_env_cfg.sv @@ -17,9 +17,9 @@ class uart_env_cfg extends cip_base_env_cfg #(.RAL_T(uart_reg_block)); `uvm_object_new - virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1); + virtual function void initialize(); list_of_alerts = uart_env_pkg::LIST_OF_ALERTS; - super.initialize(csr_base_addr); + super.initialize(); // create uart agent config obj m_uart_agent_cfg = uart_agent_cfg::type_id::create("m_uart_agent_cfg"); // set num_interrupts & num_alerts which will be used to create coverage and more diff --git a/hw/vendor/lowrisc_ip/ip_templates/alert_handler/dv/README.md b/hw/vendor/lowrisc_ip/ip_templates/alert_handler/dv/README.md index f747f76b5..b83d49946 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/alert_handler/dv/README.md +++ b/hw/vendor/lowrisc_ip/ip_templates/alert_handler/dv/README.md @@ -107,11 +107,11 @@ The alert_handler scoreboard is parameterized to support different number of cla * Unknown checks on DUT outputs: The RTL has assertions to ensure all outputs are initialized to known values after coming out of reset. ## Building and running tests -We are using our in-house developed [regression tool](../../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/$CHIP/ip_autogen/alert_handler/dv/alert_handler_sim_cfg.hjson -i alert_handler_smoke +$ dvsim $REPO_TOP/hw/$CHIP/ip_autogen/alert_handler/dv/alert_handler_sim_cfg.hjson -i alert_handler_smoke ``` In this run command, $CHIP can be top_earlgrey, etc. diff --git a/hw/vendor/lowrisc_ip/ip_templates/alert_handler/dv/env/alert_handler_env_cfg.sv.tpl b/hw/vendor/lowrisc_ip/ip_templates/alert_handler/dv/env/alert_handler_env_cfg.sv.tpl index 99eb95cec..23f8d383b 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/alert_handler/dv/env/alert_handler_env_cfg.sv.tpl +++ b/hw/vendor/lowrisc_ip/ip_templates/alert_handler/dv/env/alert_handler_env_cfg.sv.tpl @@ -18,9 +18,9 @@ class ${module_instance_name}_env_cfg extends cip_base_env_cfg #(.RAL_T(${module `uvm_object_new - virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1); + virtual function void initialize(); num_edn = 1; - super.initialize(csr_base_addr); + super.initialize(); shadow_update_err_status_fields[ral.loc_alert_cause[LocalShadowRegUpdateErr].la] = 1; shadow_storage_err_status_fields[ral.loc_alert_cause[LocalShadowRegStorageErr].la] = 1; diff --git a/hw/vendor/lowrisc_ip/ip_templates/alert_handler/dv/env/seq_lib/alert_handler_entropy_stress_vseq.sv.tpl b/hw/vendor/lowrisc_ip/ip_templates/alert_handler/dv/env/seq_lib/alert_handler_entropy_stress_vseq.sv.tpl index d6a741899..a3caf0c3d 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/alert_handler/dv/env/seq_lib/alert_handler_entropy_stress_vseq.sv.tpl +++ b/hw/vendor/lowrisc_ip/ip_templates/alert_handler/dv/env/seq_lib/alert_handler_entropy_stress_vseq.sv.tpl @@ -34,6 +34,7 @@ class ${module_instance_name}_entropy_stress_vseq extends ${module_instance_name foreach (cfg.alert_host_cfg[i]) begin cfg.alert_host_cfg[i].alert_delay_max = 0; + cfg.alert_host_cfg[i].ping_delay_min = 0; cfg.alert_host_cfg[i].ping_delay_max = 0; end super.pre_start(); diff --git a/hw/vendor/lowrisc_ip/ip_templates/clkmgr/dv/README.md.tpl b/hw/vendor/lowrisc_ip/ip_templates/clkmgr/dv/README.md.tpl index b98c71d79..fb2bc8219 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/clkmgr/dv/README.md.tpl +++ b/hw/vendor/lowrisc_ip/ip_templates/clkmgr/dv/README.md.tpl @@ -188,12 +188,12 @@ ${"###"} Assertions * Unknown checks on DUT outputs: The RTL has assertions to ensure all outputs are initialized to known values after coming out of reset. ${"##"} Building and running tests -We are using our in-house developed [regression tool](../../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/top_${topname}/ip_autogen/clkmgr/dv/clkmgr_sim_cfg.hjson -i clkmgr_smoke +$ dvsim $REPO_TOP/hw/top_${topname}/ip_autogen/clkmgr/dv/clkmgr_sim_cfg.hjson -i clkmgr_smoke ``` ${"##"} Testplan diff --git a/hw/vendor/lowrisc_ip/ip_templates/clkmgr/dv/env/clkmgr_env_cfg.sv.tpl b/hw/vendor/lowrisc_ip/ip_templates/clkmgr/dv/env/clkmgr_env_cfg.sv.tpl index 28bc18f73..45ad7715f 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/clkmgr/dv/env/clkmgr_env_cfg.sv.tpl +++ b/hw/vendor/lowrisc_ip/ip_templates/clkmgr/dv/env/clkmgr_env_cfg.sv.tpl @@ -36,9 +36,9 @@ class clkmgr_env_cfg extends cip_base_env_cfg #( `uvm_object_new - virtual function void initialize(bit [31:0] csr_base_addr = '1); + virtual function void initialize(); list_of_alerts = clkmgr_env_pkg::LIST_OF_ALERTS; - super.initialize(csr_base_addr); + super.initialize(); // This is for the integrity error test. tl_intg_alert_name = "fatal_fault"; diff --git a/hw/vendor/lowrisc_ip/ip_templates/clkmgr/dv/env/seq_lib/clkmgr_regwen_vseq.sv.tpl b/hw/vendor/lowrisc_ip/ip_templates/clkmgr/dv/env/seq_lib/clkmgr_regwen_vseq.sv.tpl index 1ec6cb0e9..20ae44349 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/clkmgr/dv/env/seq_lib/clkmgr_regwen_vseq.sv.tpl +++ b/hw/vendor/lowrisc_ip/ip_templates/clkmgr/dv/env/seq_lib/clkmgr_regwen_vseq.sv.tpl @@ -11,16 +11,16 @@ class clkmgr_regwen_vseq extends clkmgr_base_vseq; task check_jitter_regwen(); bit enable; - mubi4_t prev_value; - mubi4_t new_value; + logic [3:0] prev_value_bits; + mubi4_t new_value; `DV_CHECK_STD_RANDOMIZE_FATAL(enable) new_value = get_rand_mubi4_val(.t_weight(1), .f_weight(1), .other_weight(2)); `uvm_info(`gfn, $sformatf("Check jitter_regwen = %b", enable), UVM_MEDIUM) csr_wr(.ptr(ral.jitter_regwen), .value(enable)); - csr_rd(.ptr(ral.jitter_enable), .value(prev_value)); + csr_rd(.ptr(ral.jitter_enable), .value(prev_value_bits)); csr_wr(.ptr(ral.jitter_enable), .value(new_value)); - csr_rd_check(.ptr(ral. jitter_enable), .compare_value(enable ? new_value : prev_value)); + csr_rd_check(.ptr(ral.jitter_enable), .compare_value(enable ? new_value : prev_value_bits)); `uvm_info(`gfn, "Check jitter_regwen done", UVM_MEDIUM) endtask : check_jitter_regwen diff --git a/hw/vendor/lowrisc_ip/ip_templates/gpio/dv/README.md.tpl b/hw/vendor/lowrisc_ip/ip_templates/gpio/dv/README.md.tpl index ca8ac4f24..e813bf06a 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/gpio/dv/README.md.tpl +++ b/hw/vendor/lowrisc_ip/ip_templates/gpio/dv/README.md.tpl @@ -103,11 +103,11 @@ ${"####"} Assertions * `CioGpioOKnown`: Checks that GPIO output enable does not have any unknowns ${"##"} Building and running tests -We are using our in-house developed [regression tool](../../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/top_${topname}/ip_autogen/${module_instance_name}/dv/${module_instance_name}_sim_cfg.hjson -i gpio_smoke +$ dvsim $REPO_TOP/hw/top_${topname}/ip_autogen/${module_instance_name}/dv/${module_instance_name}_sim_cfg.hjson -i gpio_smoke ``` ${"##"} Testplan diff --git a/hw/vendor/lowrisc_ip/ip_templates/gpio/dv/env/gpio_env_cfg.sv.tpl b/hw/vendor/lowrisc_ip/ip_templates/gpio/dv/env/gpio_env_cfg.sv.tpl index 45b7c3f45..d52ee0e01 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/gpio/dv/env/gpio_env_cfg.sv.tpl +++ b/hw/vendor/lowrisc_ip/ip_templates/gpio/dv/env/gpio_env_cfg.sv.tpl @@ -24,9 +24,9 @@ class ${module_instance_name}_env_cfg extends cip_base_env_cfg #( super.new(name); endfunction - virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1); + virtual function void initialize(); list_of_alerts = ${module_instance_name}_env_pkg::LIST_OF_ALERTS; - super.initialize(csr_base_addr); + super.initialize(); // set num_interrupts & num_alerts which will be used to create coverage and more num_interrupts = ral.intr_state.get_n_used_bits(); diff --git a/hw/vendor/lowrisc_ip/ip_templates/pwrmgr/dv/README.md.tpl b/hw/vendor/lowrisc_ip/ip_templates/pwrmgr/dv/README.md.tpl index 807adabaa..5ef1cb670 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/pwrmgr/dv/README.md.tpl +++ b/hw/vendor/lowrisc_ip/ip_templates/pwrmgr/dv/README.md.tpl @@ -248,11 +248,11 @@ The [`hw/${top_name}/ip_autogen/pwrmgr/dv/sva/pwrmgr_bind.sv`](https://github.co In addition, the RTL has assertions to ensure all outputs are initialized to known values after coming out of reset. ${"##"} Building and running tests -We are using our in-house developed [regression tool](../../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/${top_name}/ip_autogen/pwrmgr/dv/pwrmgr_sim_cfg.hjson -i pwrmgr_smoke +$ dvsim $REPO_TOP/hw/${top_name}/ip_autogen/pwrmgr/dv/pwrmgr_sim_cfg.hjson -i pwrmgr_smoke ``` ${"##"} Testplan diff --git a/hw/vendor/lowrisc_ip/ip_templates/pwrmgr/dv/env/pwrmgr_env_cfg.sv b/hw/vendor/lowrisc_ip/ip_templates/pwrmgr/dv/env/pwrmgr_env_cfg.sv index 113b8b6ea..862a4b51b 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/pwrmgr/dv/env/pwrmgr_env_cfg.sv +++ b/hw/vendor/lowrisc_ip/ip_templates/pwrmgr/dv/env/pwrmgr_env_cfg.sv @@ -31,9 +31,9 @@ class pwrmgr_env_cfg extends cip_base_env_cfg #( // The run_phase object, to deal with objections. uvm_phase run_phase; - virtual function void initialize(bit [31:0] csr_base_addr = '1); + virtual function void initialize(); list_of_alerts = pwrmgr_env_pkg::LIST_OF_ALERTS; - super.initialize(csr_base_addr); + super.initialize(); num_interrupts = ral.intr_state.get_n_used_bits(); `ASSERT_I(NumInstrMatch_A, num_interrupts == NUM_INTERRUPTS) `uvm_info(`gfn, $sformatf("num_interrupts = %0d", num_interrupts), UVM_MEDIUM) diff --git a/hw/vendor/lowrisc_ip/ip_templates/pwrmgr/dv/env/seq_lib/pwrmgr_reset_invalid_vseq.sv b/hw/vendor/lowrisc_ip/ip_templates/pwrmgr/dv/env/seq_lib/pwrmgr_reset_invalid_vseq.sv index c5c0090f4..f3159daf8 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/pwrmgr/dv/env/seq_lib/pwrmgr_reset_invalid_vseq.sv +++ b/hw/vendor/lowrisc_ip/ip_templates/pwrmgr/dv/env/seq_lib/pwrmgr_reset_invalid_vseq.sv @@ -42,7 +42,6 @@ class pwrmgr_reset_invalid_vseq extends pwrmgr_base_vseq; wait_for_rom_and_active(); check_reset_status('0); - $assertoff(0, "tb.dut.u_cdc.u_clr_reqack.SyncReqAckHoldReq"); for (int i = 0; i < num_of_target_states; ++i) begin `uvm_info(`gfn, $sformatf("Starting new round %0d", i), UVM_MEDIUM) diff --git a/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/README.md.tpl b/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/README.md.tpl index 75afd5ddf..f1cd19933 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/README.md.tpl +++ b/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/README.md.tpl @@ -129,11 +129,11 @@ It has its own separate dv environment and tests at `hw/top_${topname}/ip_autoge It is excluded from coverage for the rstmgr dv tests. ## Building and running tests -We are using our in-house developed [regression tool](../../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/top_${topname}/ip_autogen/rstmgr/dv/rstmgr_sim_cfg.hjson -i rstmgr_smoke +$ dvsim $REPO_TOP/hw/top_${topname}/ip_autogen/rstmgr/dv/rstmgr_sim_cfg.hjson -i rstmgr_smoke ``` ## Testplan diff --git a/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/env/rstmgr_env_cfg.sv.tpl b/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/env/rstmgr_env_cfg.sv.tpl index 01d24594f..c2d78a451 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/env/rstmgr_env_cfg.sv.tpl +++ b/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/env/rstmgr_env_cfg.sv.tpl @@ -23,9 +23,9 @@ class rstmgr_env_cfg extends cip_base_env_cfg #( virtual rstmgr_cascading_sva_if rstmgr_cascading_sva_vif; virtual rstmgr_if rstmgr_vif; - virtual function void initialize(bit [31:0] csr_base_addr = '1); + virtual function void initialize(); list_of_alerts = rstmgr_env_pkg::LIST_OF_ALERTS; - super.initialize(csr_base_addr); + super.initialize(); tl_intg_alert_fields[ral.err_code.reg_intg_err] = 1; m_tl_agent_cfg.max_outstanding_req = 1; diff --git a/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/env/rstmgr_if.sv.tpl b/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/env/rstmgr_if.sv.tpl index 5763978de..cb2102d9e 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/env/rstmgr_if.sv.tpl +++ b/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/env/rstmgr_if.sv.tpl @@ -77,5 +77,5 @@ interface rstmgr_if ( always_comb cpu_info_en = `PATH_TO_DUT.reg2hw.cpu_info_ctrl.en.q; bit rst_ni_inactive; - always_comb rst_ni_inactive = resets_o.${preferred_rst_n}[rstmgr_pkg::Domain0Sel]; + always_comb rst_ni_inactive = resets_o.${preferred_rst_n}[rstmgr_pkg::DomainMainSel]; endinterface diff --git a/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/sva/rstmgr_cascading_sva_if.sv.tpl b/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/sva/rstmgr_cascading_sva_if.sv.tpl index 864247264..143d0ed5b 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/sva/rstmgr_cascading_sva_if.sv.tpl +++ b/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/sva/rstmgr_cascading_sva_if.sv.tpl @@ -186,14 +186,14 @@ interface rstmgr_cascading_sva_if ( // Controlled by rst_lc_src_n. `CASCADED_ASSERTS(CascadeLcToLcAon, rst_lc_src_n[rstmgr_pkg::DomainAonSel], resets_o.rst_lc_aon_n[rstmgr_pkg::DomainAonSel], SysCycles, clk_aon_i) - `CASCADED_ASSERTS(CascadeLcToLc, rst_lc_src_n[rstmgr_pkg::Domain0Sel], - resets_o.rst_lc_n[rstmgr_pkg::Domain0Sel], SysCycles, clk_main_i) + `CASCADED_ASSERTS(CascadeLcToLc, rst_lc_src_n[rstmgr_pkg::DomainMainSel], + resets_o.rst_lc_n[rstmgr_pkg::DomainMainSel], SysCycles, clk_main_i) // Controlled by rst_sys_src_n. - `CASCADED_ASSERTS(CascadeSysToSys, rst_sys_src_n[rstmgr_pkg::Domain0Sel], - resets_o.rst_sys_n[rstmgr_pkg::Domain0Sel], PeriCycles, clk_main_i) - `CASCADED_ASSERTS(CascadeLcToLcShadowed, rst_lc_src_n[rstmgr_pkg::Domain0Sel], - resets_o.rst_lc_shadowed_n[rstmgr_pkg::Domain0Sel], SysCycles, clk_main_i) + `CASCADED_ASSERTS(CascadeSysToSys, rst_sys_src_n[rstmgr_pkg::DomainMainSel], + resets_o.rst_sys_n[rstmgr_pkg::DomainMainSel], PeriCycles, clk_main_i) + `CASCADED_ASSERTS(CascadeLcToLcShadowed, rst_lc_src_n[rstmgr_pkg::DomainMainSel], + resets_o.rst_lc_shadowed_n[rstmgr_pkg::DomainMainSel], SysCycles, clk_main_i) `undef FALL_ASSERT `undef RISE_ASSERTS diff --git a/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/sva/rstmgr_rst_en_track_sva_if.sv.tpl b/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/sva/rstmgr_rst_en_track_sva_if.sv.tpl index 9dea2514c..6d668efc2 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/sva/rstmgr_rst_en_track_sva_if.sv.tpl +++ b/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/sva/rstmgr_rst_en_track_sva_if.sv.tpl @@ -16,7 +16,7 @@ interface rstmgr_rst_en_track_sva_if ( input logic rst_por_ni ); import rstmgr_pkg::DomainAonSel; - import rstmgr_pkg::Domain0Sel; + import rstmgr_pkg::DomainMainSel; localparam int DELAY = 1; % for rst in output_rsts: diff --git a/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/tb.sv.tpl b/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/tb.sv.tpl index d603fcd9b..c2e8ce4eb 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/tb.sv.tpl +++ b/hw/vendor/lowrisc_ip/ip_templates/rstmgr/dv/tb.sv.tpl @@ -43,7 +43,7 @@ module tb; tl_if tl_if ( .clk, - .rst_n(rstmgr_if.resets_o.${preferred_rst_n}[rstmgr_pkg::Domain0Sel]) + .rst_n(rstmgr_if.resets_o.${preferred_rst_n}[rstmgr_pkg::DomainMainSel]) ); rstmgr_if rstmgr_if ( @@ -66,7 +66,7 @@ module tb; // This is consistent with rstmgr being the only source of resets. rstmgr dut ( .clk_i (clk), - .rst_ni (rstmgr_if.resets_o.${preferred_rst_n}[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_if.resets_o.${preferred_rst_n}[rstmgr_pkg::DomainMainSel]), % for clk in sorted(list(clk_freqs.keys())): <% spaces = len("io_div2") - len(clk) %>\ .clk_${clk}_i${" " * spaces}(clk_${clk}), @@ -120,7 +120,7 @@ module tb; // This may help any code that depends on clk_rst_vif.rst_n in the infrastructure: they won't // be able to change but at least the reset value will be true to the environment. clk_rst_if.drive_rst_n = 1'b0; - force clk_rst_if.rst_n = rstmgr_if.resets_o.${preferred_rst_n}[rstmgr_pkg::Domain0Sel]; + force clk_rst_if.rst_n = rstmgr_if.resets_o.${preferred_rst_n}[rstmgr_pkg::DomainMainSel]; end endmodule diff --git a/hw/vendor/lowrisc_ip/ip_templates/rstmgr/rtl/rstmgr_ctrl.sv b/hw/vendor/lowrisc_ip/ip_templates/rstmgr/rtl/rstmgr_ctrl.sv index a762ec828..dbb26a440 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/rstmgr/rtl/rstmgr_ctrl.sv +++ b/hw/vendor/lowrisc_ip/ip_templates/rstmgr/rtl/rstmgr_ctrl.sv @@ -49,7 +49,7 @@ module rstmgr_ctrl // the non-always-on domains // These reset whenever the always on domain reset, to ensure power definition consistency. // By extension, they also reset whenever the root (rst_ni) resets - assign rst_pd_nd = ~rst_req_i[Domain0Sel +: OffDomains]; + assign rst_pd_nd = ~rst_req_i[DomainMainSel +: OffDomains]; localparam int DomainPdStartIdx = DomainAonSel + 1; for(genvar i = 0; i < OffDomains; i++) begin : gen_rst_pd_n diff --git a/hw/vendor/lowrisc_ip/ip_templates/rv_plic/fpv/vip/rv_plic_assert_fpv.sv.tpl b/hw/vendor/lowrisc_ip/ip_templates/rv_plic/fpv/vip/rv_plic_assert_fpv.sv.tpl index a7c742e74..f2cad7c0b 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/rv_plic/fpv/vip/rv_plic_assert_fpv.sv.tpl +++ b/hw/vendor/lowrisc_ip/ip_templates/rv_plic/fpv/vip/rv_plic_assert_fpv.sv.tpl @@ -119,4 +119,14 @@ module ${module_instance_name}_assert_fpv #(parameter int NumSrc = 1, // When fatal alert happens then only reset can clear it. `ASSERT(FatalAlertNeverdrops_A, ##1 !$fell(fatal_alert_i)) + + // The interrupt gateway in u_gateway is in charge of making sure that the "set; claim; complete" + // flow is followed for each interrupt line. This is done with an ia ("interrupt active") signal. + // When interrupt i is asserted, both ip[i] and ia[i] are set. When it is claimed, ip[i] gets + // cleared (but ia[i] stays high). Subsequent assertions are ignored until the processor marks the + // handling complete, which clears ia[i] again. + // + // As such, ia[i] should always be true when ip[i] is true. + `ASSERT(ActiveIfPending_A, u_gateway.ia | ~u_gateway.ip_o) + endmodule : ${module_instance_name}_assert_fpv diff --git a/hw/vendor/lowrisc_ip/ip_templates/rv_plic/rtl/rv_plic.sv.tpl b/hw/vendor/lowrisc_ip/ip_templates/rv_plic/rtl/rv_plic.sv.tpl index 0f6b48f76..9f2cc636a 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/rv_plic/rtl/rv_plic.sv.tpl +++ b/hw/vendor/lowrisc_ip/ip_templates/rv_plic/rtl/rv_plic.sv.tpl @@ -104,10 +104,6 @@ module ${module_instance_name} import ${module_instance_name}_reg_pkg::*; #( //`ASSERT_PULSE(claimPulse, claim_re[i]) //`ASSERT_PULSE(completePulse, complete_we[i]) - `ASSERT(onehot0Claim, $onehot0(claim_re)) - - `ASSERT(onehot0Complete, $onehot0(complete_we)) - ////////////// // Priority // ////////////// diff --git a/hw/vendor/lowrisc_ip/ip_templates/rv_plic/rtl/rv_plic_gateway.sv.tpl b/hw/vendor/lowrisc_ip/ip_templates/rv_plic/rtl/rv_plic_gateway.sv.tpl index 45de54870..07b5838a2 100644 --- a/hw/vendor/lowrisc_ip/ip_templates/rv_plic/rtl/rv_plic_gateway.sv.tpl +++ b/hw/vendor/lowrisc_ip/ip_templates/rv_plic/rtl/rv_plic_gateway.sv.tpl @@ -10,15 +10,59 @@ module ${module_instance_name}_gateway #( input clk_i, input rst_ni, + // Incoming interrupt requests from the interrupt sources. input [N_SOURCE-1:0] src_i, - input [N_SOURCE-1:0] le_i, // Level0 Edge1 - input [N_SOURCE-1:0] claim_i, // $onehot0(claim_i) - input [N_SOURCE-1:0] complete_i, // $onehot0(complete_i) + // Control whether each interrupt is level or edge triggered. It is considered level triggered if + // its bit of le_i is zero and edge triggered if the bit is 1. + input [N_SOURCE-1:0] le_i, + // Interrupts being claimed by a target. This should be onehot0 (so only one interrupt can be + // claimed at once). + input [N_SOURCE-1:0] claim_i, + + // Interrupts being marked complete by a target. This should be onehot0 (so only one interrupt can + // be claimed at once). It has no effect on an interrupt that has not already been claimed. + input [N_SOURCE-1:0] complete_i, + + // The "interrupt pending" flag. If a bit of ip_o is true, the target should be notified that the + // interrupt needs handling. output logic [N_SOURCE-1:0] ip_o ); + // The flow for an interrupt is described in "RISC-V Platform-Level Interrupt Controller + // Specification" (v1.0.0) in section 1.5. + // + // 1. An interrupt starts neither active nor pending (so the relevant bits of ia and ip_o are + // zero). + // + // 2. The interrupt source asserts interrupt k by setting src_i[k]. If le_i requests edge + // triggering, the gateway only recognises an interrupt with a posedge on src_i. + // + // 3. The gateway sets ip_o[k] to tell the target that interrupt k is pending. + // + // 4. The target claims the interrupt, which appears as claim_i[k] being true. + // + // 5. The gateway clears ip_o[k], but remembers that the interrupt is being handled. As such, + // further changes in src_i will not cause a new (overlapping) interrupt. + // + // 6. The target finishes handling the interrupt and sets complete_i[k]. + // + // 7. The gateway will now allow changes in src_i to cause the interrupt to become pending + // again. + // + // This is translated into hardware signals as follows: + // + // - The interrupt assertion in src_i is detected with the "set" signal. This includes posedge + // detection if le_i is true for the interrupt. + // + // - Once interrupt k is asserted, it is marked pending in ip_o[k]. It is also marked "active" + // (which implies the target hasn't yet got as far as completion) by setting ia[k]. + // + // - When the target claims the interrupt, ip_o[k] is cleared, but ia[k] stays high. + // + // - Finally, when the target completes the interrupt, ia[k] is cleared. + logic [N_SOURCE-1:0] ia; // Interrupt Active // The set[i] signal says that interrupt i is being requested. If the interrupt is level triggered @@ -35,28 +79,32 @@ module ${module_instance_name}_gateway #( assign set = src_i & ~(src_q & le_i); - // Interrupt pending is set by source (depends on le_i), cleared by claim_i. - // Until interrupt is claimed, set doesn't affect ip_o. - // RISC-V PLIC spec mentioned it can have counter for edge triggered - // But skipped the feature as counter consumes substantial logic size. + // The interrupt pending signal for interrupt k stays true until it is claimed (claim_i[k]). It is + // newly asserted if the interrupt is interrupt asserted (src_i[k]) (restricted to positive edges + // if le_i[k] is true) when the interrupt isn't already active (~ia[k]). always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin ip_o <= '0; end else begin - ip_o <= (ip_o | (set & ~ia & ~ip_o)) & (~(ip_o & claim_i)); + ip_o <= (ip_o & ~claim_i) | (set & ~ia); end end - // Interrupt active is to control ip_o. If ip_o is set then until completed - // by target, ip_o shouldn't be set by source even claim_i can clear ip_o. - // ia can be cleared only when ia was set. If `set` and `complete_i` happen - // at the same time, always `set` wins. + // The Interrupt Active signal is high for interrupts that are active. Interrupt k becomes active + // (so ia[k] is true) if the interrupt is asserted when it is not already active. An active + // interrupt is initially pending (ip_o[k] is high) and stops being pending when claimed by the + // target setting claim_i[k]. After the interrupt has been claimed, it is marked inactive when the + // target signals completion (by setting complete_i[k]). always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin ia <= '0; end else begin - ia <= (ia | (set & ~ia)) & (~(ia & complete_i & ~ip_o)); + ia <= (~ia & set) | (ia & ~(complete_i & ~ip_o)); end end + // Check the claim_i and complete_i input ports are being driven with onehot0 values. + `ASSERT(ClaimOneHot0_A, $onehot0(claim_i)) + `ASSERT(CompleteOneHot0_A, $onehot0(complete_i)) + endmodule diff --git a/hw/vendor/lowrisc_ip/lint/README.md b/hw/vendor/lowrisc_ip/lint/README.md index 9926da7fd..044ad8326 100644 --- a/hw/vendor/lowrisc_ip/lint/README.md +++ b/hw/vendor/lowrisc_ip/lint/README.md @@ -77,14 +77,14 @@ All three linting tools mentioned above have been integrated with the `dvsim` re In order to manually invoke any of the linting tools on a specific block, make sure that the corresponding linting tool is properly installed, step into the project root and call ```console $ cd $REPO_TOP -$ util/dvsim/dvsim.py hw/top_earlgrey/lint/top_earlgrey_lint_cfgs.hjson --tool (ascentlint|verilator|veriblelint) --local --purge --select-cfgs +$ dvsim hw/top_earlgrey/lint/top_earlgrey_lint_cfgs.hjson --tool (ascentlint|verilator|veriblelint) --local --purge --select-cfgs ``` where `` is the name of the linting configuration as defined in the `top_earlgrey_lint_cfgs.hjson` regression list (currently that file contains a lint configuration for all available comportable IPs and the top-level). In order to run all defined configs in `top_earlgrey_lint_cfgs.hjson` as a batch regression, just omit the `--select-cfgs` switch as follows: ```console $ cd $REPO_TOP -$ util/dvsim/dvsim.py hw/top_earlgrey/lint/top_earlgrey_lint_cfgs.hjson --tool (ascentlint|verilator|veriblelint) --local --purge +$ dvsim hw/top_earlgrey/lint/top_earlgrey_lint_cfgs.hjson --tool (ascentlint|verilator|veriblelint) --local --purge ``` The `purge` option ensures that the scratch directory is fully erased before starting the build. Depending on the number of AscentLint licenses that can be checked out at a time, you may also want to set the number of parallel workers to one using `--max-parallel `. diff --git a/hw/vendor/lowrisc_ip/util/design/check-netlist.py b/hw/vendor/lowrisc_ip/util/design/check-netlist.py index 5081843d4..f4a809be2 100755 --- a/hw/vendor/lowrisc_ip/util/design/check-netlist.py +++ b/hw/vendor/lowrisc_ip/util/design/check-netlist.py @@ -21,7 +21,7 @@ def hr(char: str) -> None: class Parser: # List of patterns we want to use for finding size_only constraints. size_only_patterns = [ - "u_size_only", + "u_size_only", "u_size_only_inv", "u_size_only_xor", "u_size_only_xnor", "u_size_only_and", "u_size_only_mux", "u_size_only_flop", "u_size_only_buf", "u_size_only_tie", "u_size_only_clock_gate" diff --git a/hw/vendor/lowrisc_ip/util/reggen/fpv_csr.sv.tpl b/hw/vendor/lowrisc_ip/util/reggen/fpv_csr.sv.tpl index 5361b5f14..a587f1a45 100644 --- a/hw/vendor/lowrisc_ip/util/reggen/fpv_csr.sv.tpl +++ b/hw/vendor/lowrisc_ip/util/reggen/fpv_csr.sv.tpl @@ -18,18 +18,15 @@ assert rb.flat_regs %>\ -<%def name="construct_classes(block)">\ - `include "prim_assert.sv" `ifdef UVM `include "uvm_macros.svh" `endif -`ifndef FPV_ON - `define REGWEN_PATH tb.dut.${reg_block_path} -`else - `define REGWEN_PATH ${lblock}.${reg_block_path} -`endif + // An upwards hierarchical reference that starts at the type of the IP block. This will correctly + // find the block, as long as the assertion module is bound into the block (rather than sitting + // outside of it) in the testbench. +`define REGWEN_PATH ${lblock}.${reg_block_path} // Block: ${lblock} module ${mod_base}_csr_assert_fpv import tlul_pkg::*; @@ -322,5 +319,3 @@ module ${mod_base}_csr_assert_fpv import tlul_pkg::*; endmodule `undef REGWEN_PATH -\ -${construct_classes(block)} diff --git a/hw/vendor/lowrisc_ip/util/reggen/gen_cheader.py b/hw/vendor/lowrisc_ip/util/reggen/gen_cheader.py index c9eee866b..5ce59c969 100644 --- a/hw/vendor/lowrisc_ip/util/reggen/gen_cheader.py +++ b/hw/vendor/lowrisc_ip/util/reggen/gen_cheader.py @@ -7,6 +7,7 @@ import io import logging as log +import re import sys import textwrap import warnings @@ -196,28 +197,107 @@ def gen_cdefine_window(outstr: TextIO, win: Window, comp: str, regwidth: int, gen_define(defname + '_MASK ', [], hex(mask), existing_defines)) +def verilog_int_literal_to_c(literal: str) -> str: + '''Convert an integer literal from Verilog syntax to C + + This is designed to cope with the form 32'h10 (giving 0x10). If the code + isn't in a known syntax, the function just passes the value straight through + (returning literal). + + If the literal looks like an integer but will not work for C code, the + function raises a ValueError with a description of the problem. This will + cause gen_cdefines_module_param to print a warning and drop the parameter. + ''' + m = re.match(r"[0-9]*'([dh])([_0-9a-f]+)\s*$", literal, re.IGNORECASE) + + # If this isn't a syntax we understand, pass the result straight through + if m is None: + return literal + + is_hex = m.group(1) == "h" + + # Interpret the integer literal. This might fail, because the regex above + # doesn't disallow e.g. 'dff. + try: + no_underscores = m.group(2).replace("_", "") + int_literal = int(no_underscores, 16 if is_hex else 10) + except ValueError as e: + raise ValueError(f"Cannot convert {literal} to a integer") from e + + # Check that the integer literal will actually fit in a C (long) integer. + bit_len = int_literal.bit_length() + if bit_len > 64: + raise ValueError(f"The literal {literal} would take {bit_len} bits") + + # Otherwise, it's looking promising. Return no_underscores, but with an 0x + # prefix if the base is 16. That way, the C literal will have the same base + # as the value we parsed (which is nice for literals like 999 or 'h100). + return f"0x{no_underscores}" if is_hex else no_underscores + + def gen_cdefines_module_param(outstr: TextIO, param: LocalParam, module_name: str, existing_defines: Set[str]) -> None: - # Presently there is only one type (int), however if the new types are - # added, they potentially need to be handled differently. - known_types = ["int", "int unsigned"] - if param.param_type not in known_types: - warnings.warn( - f"Cannot generate a module define of type {param.param_type}") - return - - if param.desc is not None: - genout(outstr, format_comment(first_line(param.desc))) # Heuristic: if the name already has underscores, it's already snake_case, # otherwise, assume StudlyCaps and covert it to snake_case. param_name = param.name if '_' in param.name else to_snake_case(param.name) define_name = as_define(module_name + '_PARAM_' + param_name) - if param.param_type == "int" or param.param_type == "int unsigned": - define = gen_define(define_name, [], param.value, existing_defines) - genout(outstr, define) - genout(outstr, '\n') + # SystemVerilog types where parameter values can be written as integer + # literals in C. (Note: we assume the author of the hjson didn't having + # written a value as something like "'h10", but that would be a silly thing + # to do! They'll just get an error further downstream) + # + # Note that the list here has the property there are no entries A before B + # where A is a prefix of B. This guarantees that the integer type + # substitution below will replace the largest possible type. + # + # Also note that the format of the entries in the list needs to be + # understood by the code that makes int_typ_regexes (because we do a simple + # substitution and then treat the result as a regex). + int_types = ["int unsigned", "int", + "logic [31:0]", "logic", "bit [31:0]", "bit"] + + # To make the matching logic below a bit easier, get rid of leading and + # trailing space and replace multiple spaces with single ones. + trimmed_type = re.sub(r"\s+", " ", param.param_type.strip()) + + # Does this param look like an array of one of the integer types? In + # SystemVerilog syntax, the type might be "int [123]" or it might be + # something like "logic [31:0][123]" or "logic [7:0][4:0]". If so, this + # isn't really something we'd want in a #define line. + # + # To spot this case, start by trying to match something from int_types at + # the start of the type. On a match (which is of maximal length because of + # the ordering in int_types), try to match "\s*[" immediately afterwards. On + # a hit, this is an array we should skip. + type_patterns = (re.escape(t).replace(r"\ ", r"\s*") for t in int_types) + int_type_regex = "|".join(f"(?:{pattern})" for pattern in type_patterns) + int_type_match = re.match(int_type_regex, trimmed_type) + if int_type_match and re.match(r"\s*\[", + param.param_type[int_type_match.end():]): + return + + if trimmed_type in int_types: + if param.desc is not None: + genout(outstr, format_comment(first_line(param.desc))) + + try: + parsed_str = verilog_int_literal_to_c(param.value) + except ValueError as e: + warnings.warn(f"Skipping parameter {param.name}: {e}") + return + + define = gen_define(define_name, [], parsed_str, existing_defines) + + genout(outstr, define) + genout(outstr, '\n') + + else: + # We don't know how to handle this parameter type. Print a warning to + # the console and ignore it. + warnings.warn(f"Skipping parameter {param.name} with " + f"unknown type {param.param_type}") def gen_cdefines_module_params(outstr: TextIO, module_data: IpBlock, diff --git a/hw/vendor/lowrisc_ip/util/reggen/reg_top.sv.tpl b/hw/vendor/lowrisc_ip/util/reggen/reg_top.sv.tpl index 5a00b3b0f..47336417e 100644 --- a/hw/vendor/lowrisc_ip/util/reggen/reg_top.sv.tpl +++ b/hw/vendor/lowrisc_ip/util/reggen/reg_top.sv.tpl @@ -1097,6 +1097,18 @@ ${bits.msb}\ % if reg.async_clk and reg.shadowed: logic async_${finst_name}_err_update; logic async_${finst_name}_err_storage; + logic deglitched_${finst_name}_err_storage; + + // flop storage error to filter combinational glitches before sending it across CDC + prim_flop #( + .Width(1), + .ResetValue('0) + ) u_${finst_name}_err_storage_deglitch ( + .clk_i (${reg.async_clk[1].clock}), + .rst_ni(${reg.async_clk[1].reset}), + .d_i (async_${finst_name}_err_storage), + .q_o (deglitched_${finst_name}_err_storage) + ); // storage error is persistent and can be sampled at any time prim_flop_2sync #( @@ -1105,7 +1117,7 @@ ${bits.msb}\ ) u_${finst_name}_err_storage_sync ( .clk_i, .rst_ni, - .d_i(async_${finst_name}_err_storage), + .d_i(deglitched_${finst_name}_err_storage), .q_o(${finst_name}_storage_err) ); diff --git a/hw/vendor/lowrisc_ip/util/topgen/README.md b/hw/vendor/lowrisc_ip/util/topgen/README.md index d3a4391db..6ba99fdba 100644 --- a/hw/vendor/lowrisc_ip/util/topgen/README.md +++ b/hw/vendor/lowrisc_ip/util/topgen/README.md @@ -231,7 +231,7 @@ To run a chip-level test using these tapeout files, the following steps are requ You can then type the usual command, e.g., ``` -./util/dvsim/dvsim.py hw/top_earlgrey/dv/chip_sim_cfg.hjson -i chip_sw_uart_tx_rx +dvsim hw/top_earlgrey/dv/chip_sim_cfg.hjson -i chip_sw_uart_tx_rx ``` to start the chip-level test. diff --git a/hw/vendor/lowrisc_ip/util/topgen/intermodule.py b/hw/vendor/lowrisc_ip/util/topgen/intermodule.py index e127b1262..342fea471 100644 --- a/hw/vendor/lowrisc_ip/util/topgen/intermodule.py +++ b/hw/vendor/lowrisc_ip/util/topgen/intermodule.py @@ -65,13 +65,17 @@ def intersignal_format(req: Dict) -> str: return result -def get_suffixes(ims: OrderedDict) -> Tuple[str, str]: +def get_suffixes(ims: OrderedDict, for_type_def: bool = True) -> Tuple[str, str]: """Get suffixes of the struct. TL-UL struct uses `h2d`, `d2h` suffixes for req, rsp pair. + Simply return empty string for non-req_rsp type """ + if ims["type"] != "req_rsp": + return ("", "") + if ims["package"] == "tlul_pkg" and ims["struct"] == "tl": - return ("_h2d", "_d2h") + return ("_h2d", "_d2h") if for_type_def else ("_req", "_rsp") return ("_req", "_rsp") @@ -247,10 +251,111 @@ def _get_default_name(sig, suffix): if sig['default']: return sig['default'] elif sig['package']: - return "{}::{}_DEFAULT".format(sig['package'], - (sig["struct"] + suffix).upper()) + scalar = "{}::{}_DEFAULT".format(sig['package'], + (sig["struct"] + suffix).upper()) + if not isinstance(sig["width"], int): + # Return array-assign style for parametrized signal widths + return "'{{{}}}".format(scalar) + return scalar if sig["width"] == 1 else "'{{{}}}".format(scalar) + else: + if sig["struct"] in ["logic", ""] and sig["width"] == 1: + return "1'b0" + else: + return "'0" + + +def get_signame_chip(topcfg: Dict, sig: OrderedDict, port: str, reqrsp: str = "req"): + # Determine all possible suffixes and stub strings + type_req_suffix, type_rsp_suffix = get_suffixes(sig, True) + sig_req_suffix, sig_rsp_suffix = get_suffixes(sig, False) + type_reqrsp_suffix = type_req_suffix if (reqrsp == "req") else type_rsp_suffix + sig_reqrsp_suffix = sig_req_suffix if (reqrsp == "req") else sig_rsp_suffix + + if sig["type"] == "req_rsp": + # Output if both are either "req" or "rsp" + if sig["act"] == reqrsp: + dir_suffix = "_o" + direction = "out" + else: + dir_suffix = "_i" + direction = "in" + elif sig["type"] == "io": + dir_suffix = "_io" + direction = "inout" + elif sig["type"] == "uni": + if sig["act"] == "req": + dir_suffix = "_o" + direction = "out" + else: + dir_suffix = "_i" + direction = "in" + else: + raise ValueError(f"Unknown signal type: {sig['type']}") + + # Stub/tieoff string. For outputs: Simply leave open + if direction == "out": + stub_str = "" else: - return "'0" + stub_str = _get_default_name(sig, type_reqrsp_suffix) + + # Check if a chip-level signal name is specified, otherwise infer it from port name + sig_name = port if port != "" else intersignal_format(sig) + sig_name_chip_stem = sig_name + + # Make sure to provide a value for the `netname` key + netname = sig.get("top_signame", sig_name) + + # Add all suffixes to the signal (port) name + sig_name_full = sig_name + sig_reqrsp_suffix + dir_suffix + + # Construct chiplevel signal name dict; overwrite sig_name_chip on stubbed signals + sig_name_chip = {} + port_name = sig["inst_name"] + '.' + sig["name"] + for tgt in topcfg["targets"]: + # Use stem + reqrsp-suffix if target does not do any chip-level modifications + sig_name_chip[tgt["name"]] = sig_name_chip_stem + sig_reqrsp_suffix + # Check if current target wants to do any modifications + if "chiplevel" in tgt and port_name in tgt["chiplevel"]["port_overrides"]: + # Tieoff, override connection name, or feedthrough + p_ovrd = tgt["chiplevel"]["port_overrides"][port_name] + # Tieoff logic: Unconnected = 'True' uses infered value for inputs + if "unused" in p_ovrd: + if p_ovrd["unused"] is True and "tie_value" in p_ovrd: + # Use manual override value, if applicable + if sig["type"] == "uni" and sig["act"] == "req": + sig_name_chip[tgt["name"]] = "" + log.warning("tie_value {} specified for output {} in target {}. " + "Override values do not apply to outputs.".format( + p_ovrd["tie_value"], port_name, tgt["name"])) + elif sig["type"] == "req_rsp" and sig["act"] == reqrsp: + # Output part of req_rsp signals, prevent using manual override + sig_name_chip[tgt["name"]] = "" + else: + # Legit use case for manual override in all remaining cases + sig_name_chip[tgt["name"]] = p_ovrd["tie_value"] + elif p_ovrd["unused"] is True: + sig_name_chip[tgt["name"]] = stub_str + else: + log.warning("unused: {} specified for {} in target {}, which has no " + "effect".format(p_ovrd["unused"], port_name, tgt["name"])) + elif "signal" in p_ovrd: + sig_name_chip[tgt["name"]] = p_ovrd["signal"] + sig_reqrsp_suffix + elif "feedthrough" in p_ovrd: + # Simply add the direction suffix for feedthrough + sig_name_chip[tgt["name"]] += dir_suffix + + # Return the ready-to-add dict and the signal (port) name + return (OrderedDict([('package', sig["package"]), + ('struct', sig["struct"] + type_reqrsp_suffix), + ('signame', sig_name_full), + ('signame_chip', sig_name_chip), + ('width', sig["width"]), ('type', sig["type"]), + ('default', sig["default"]), + ('direction', direction), + ('conn_type', sig["conn_type"]), + ('index', sig["index"]), + ('netname', netname + type_reqrsp_suffix)]), + sig_name) def elab_intermodule(topcfg: OrderedDict): @@ -470,85 +575,29 @@ def elab_intermodule(topcfg: OrderedDict): assert sig_i == -1, 'top net connection should not use bit index' sig = find_intermodule_signal(list_of_intersignals, sig_m, sig_s) - # To make netname `_o` or `_i` + # To append `_o` or `_i` suffix to netname sig['external'] = True + # Set to `True` if sig already has a top_signame + sig["conn_type"] = "top_signame" in sig - sig_name = port if port != "" else intersignal_format(sig) - - # if top signame already defined, then a previous connection category - # is already connected to external pin. Sig name is only used for - # port definition - conn_type = False - if "top_signame" not in sig: - sig["top_signame"] = sig_name - else: - conn_type = True - sig["conn_type"] = conn_type - + # Make sure there is an index key if "index" not in sig: sig["index"] = -1 # Add the port definition to top external ports - index = sig["index"] - netname = sig["top_signame"] - if sig["type"] == "req_rsp": - req_suffix, rsp_suffix = get_suffixes(sig) - if sig["act"] == "req": - req_sigsuffix, rsp_sigsuffix = ("_o", "_i") + sig_dict, sig_name = get_signame_chip(topcfg, sig, port, "req") + topcfg["inter_signal"]["external"].append(sig_dict) - else: - req_sigsuffix, rsp_sigsuffix = ("_i", "_o") + # If top signame already defined, then a previous connection category + # is already connected to external pin. Sig name is only used for + # port definition + if "top_signame" not in sig: + sig["top_signame"] = sig_name - topcfg["inter_signal"]["external"].append( - OrderedDict([('package', sig["package"]), - ('struct', sig["struct"] + req_suffix), - ('signame', sig_name + "_req" + req_sigsuffix), - ('width', sig["width"]), ('type', sig["type"]), - ('default', sig["default"]), - ('direction', - 'out' if sig['act'] == "req" else 'in'), - ('conn_type', conn_type), - ('index', index), - ('netname', netname + req_suffix)])) - topcfg["inter_signal"]["external"].append( - OrderedDict([('package', sig["package"]), - ('struct', sig["struct"] + rsp_suffix), - ('signame', sig_name + "_rsp" + rsp_sigsuffix), - ('width', sig["width"]), ('type', sig["type"]), - ('default', sig["default"]), - ('direction', - 'in' if sig['act'] == "req" else 'out'), - ('conn_type', conn_type), - ('index', index), - ('netname', netname + rsp_suffix)])) - elif sig["type"] == "io": - sigsuffix = "_io" - topcfg["inter_signal"]["external"].append( - OrderedDict([('package', sig.get("package", "")), - ('struct', sig["struct"]), - ('signame', sig_name + sigsuffix), - ('width', sig["width"]), ('type', sig["type"]), - ('default', sig["default"]), - ('direction', "inout"), - ('conn_type', conn_type), - ('index', index), - ('netname', netname)])) - else: # uni - if sig["act"] == "req": - sigsuffix = "_o" - else: - sigsuffix = "_i" - topcfg["inter_signal"]["external"].append( - OrderedDict([('package', sig.get("package", "")), - ('struct', sig["struct"]), - ('signame', sig_name + sigsuffix), - ('width', sig["width"]), ('type', sig["type"]), - ('default', sig["default"]), - ('direction', - 'out' if sig['act'] == "req" else 'in'), - ('conn_type', conn_type), - ('index', index), - ('netname', netname)])) + # One more port entry for req_rsp type signals + if sig["type"] == "req_rsp": + sig_dict, _ = get_signame_chip(topcfg, sig, port, "rsp") + topcfg["inter_signal"]["external"].append(sig_dict) for sig in topcfg["inter_signal"]["signals"]: # Check if it exist in definitions @@ -889,6 +938,30 @@ def check_intermodule(topcfg: Dict, prefix: str) -> int: err, sig_struct = check_intermodule_field(sig_struct) total_error += err + # Check if all ports requested for override exist at the toplevel. + # This inherently also makes sure that no port is requested for + # override which does not exist on a module, thanks to the check above. + for tgt in topcfg["targets"]: + if "chiplevel" not in tgt: + continue + if "port_overrides" not in tgt["chiplevel"]: + continue + + for p in tgt["chiplevel"]["port_overrides"].keys(): + assert p in topcfg["inter_module"]["external"].keys(), \ + 'Port {} was requested for override in target {} but not found ' \ + 'in topcfg["inter_module"]["external"]'.format(p, tgt["name"]) + + # Check that each entry specifies exactly one (legal) override instruction + for p in tgt["chiplevel"]["port_overrides"].values(): + if len(p.keys()) == 1: + assert (list(p.keys())[0] in ["signal", "unused", "feedthrough"]), \ + 'Allowed override instructions are "signal", "unused", "feedthrough"' + else: + assert "unused" in p and "tie_value" in p and len(p.keys()) == 2, \ + 'port_overrides only support one instruction out of "signal", ' \ + '"unused", "feedthrough", or "unused" plus an "tie_value".' + return total_error diff --git a/hw/vendor/lowrisc_ip/util/topgen/templates/alert_test.c.tpl b/hw/vendor/lowrisc_ip/util/topgen/templates/alert_test.c.tpl index 87bdab533..e9f2d7763 100644 --- a/hw/vendor/lowrisc_ip/util/topgen/templates/alert_test.c.tpl +++ b/hw/vendor/lowrisc_ip/util/topgen/templates/alert_test.c.tpl @@ -120,7 +120,7 @@ ${indent} for (dif_${p.name}_alert_t i = 0; i < ${p.num_alerts}; ++i) { ${indent} CHECK_DIF_OK(dif_${p.name}_alert_force(&${p.inst_name}, ${p.dif_alert_name} + i)); ${indent} // Verify that alert handler received it. -${indent} exp_alert = ${p.top_alert_name} + i; +${indent} exp_alert = (int)${p.top_alert_name} + i; ${indent} CHECK_DIF_OK(dif_alert_handler_alert_is_cause( ${indent} &alert_handler, exp_alert, &is_cause)); ${indent} CHECK(is_cause, "Expect alert %d!", exp_alert); diff --git a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_interrupt_assignments.tpl b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_interrupt_assignments.tpl deleted file mode 100644 index 5e29b407a..000000000 --- a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_interrupt_assignments.tpl +++ /dev/null @@ -1,26 +0,0 @@ -## Copyright lowRISC contributors (OpenTitan project). -## Licensed under the Apache License, Version 2.0, see LICENSE for details. -## SPDX-License-Identifier: Apache-2.0 -<%page args="top, plic_info"/>\ -% for plic, info in plic_info.items(): -<% - base = info["count"] - default_plic = top.get("default_plic", None) -%>\ - assign ${info["vector"]} = { - % if plic == default_plic: - % for irq_group, irqs in reversed(top['incoming_interrupt'].items()): - <% base -= len(irqs) %>\ - incoming_interrupt_${irq_group}_i, // IDs [${base} +: ${len(irqs)}] - % endfor - % endif - % for intr in top["interrupt"][::-1]: - % if intr['incoming'] or intr['plic'] != plic: -<% continue %>\ - % endif -<% base -= intr["width"] %>\ - intr_${intr["name"]}, // IDs [${base} +: ${intr['width']}] - % endfor - 1'b 0 // ID [0 +: 1] is a special case and tied to zero. - }; -% endfor diff --git a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/alert_handler_lpg.tpl b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/alert_handler_lpg.tpl new file mode 100644 index 000000000..e50b221de --- /dev/null +++ b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/alert_handler_lpg.tpl @@ -0,0 +1,95 @@ +## Copyright lowRISC contributors (OpenTitan project). +## Licensed under the Apache License, Version 2.0, see LICENSE for details. +## SPDX-License-Identifier: Apache-2.0 +<%import topgen.lib as lib%>\ +<%from topgen.clocks import Clocks%>\ +<%from topgen.resets import Resets%>\ +<%page args="top, feature_info"/>\ + // Wire up alert handler LPGs + prim_mubi_pkg::mubi4_t [alert_handler_pkg::NLpg-1:0] lpg_cg_en; + prim_mubi_pkg::mubi4_t [alert_handler_pkg::NLpg-1:0] lpg_rst_en; + +<% +# get all known typed clocks and add them to a dict +# this is used to generate the tie-off assignments further below +clocks = top['clocks'] +assert isinstance(clocks, Clocks) +typed_clocks = clocks.typed_clocks() +known_clocks = {} +for clk in typed_clocks.all_clocks(): + known_clocks.update({lib.get_clock_lpg_path(top, clk): 1}) + +# get all known resets and add them to a dict +# this is used to generate the tie-off assignments further below +resets = top['resets'] +assert isinstance(resets, Resets) +output_rsts = resets.get_top_resets() +known_resets = {} +for rst in output_rsts: + for dom in top['power']['domains']: + if rst.shadowed: + path = lib.get_reset_lpg_path(top, resets.get_reset_by_name(rst.name)._asdict(), True, dom) + known_resets.update({ + path: 1 + }) + path = lib.get_reset_lpg_path(top, resets.get_reset_by_name(rst.name)._asdict(), False, dom) + known_resets.update({ + path: 1 + }) +%>\ + +<% k = 0 %>\ +% for lpg in top['alert_lpgs']: + // ${lpg['name']} +<% + cg_en = lib.get_clock_lpg_path(top, lpg['clock_connection'], lpg['unmanaged_clock']) + rst_en = lib.get_reset_lpg_path(top, lpg['reset_connection'], False, None, lpg['unmanaged_reset']) + known_clocks[cg_en] = 0 + known_resets[rst_en] = 0 +%>\ + assign lpg_cg_en[${k}] = ${cg_en}; + assign lpg_rst_en[${k}] = ${rst_en}; +<% k += 1 %>\ +% endfor +% for alert_group, alerts in top['incoming_alert'].items(): + % for unique_alert_lpg_entry in get_alerts_with_unique_lpg_idx(alerts): + assign lpg_cg_en[${k}] = incoming_lpg_cg_en_${alert_group}_i[${unique_alert_lpg_entry["lpg_idx"]}]; + assign lpg_rst_en[${k}] = incoming_lpg_rst_en_${alert_group}_i[${unique_alert_lpg_entry["lpg_idx"]}]; +<% k += 1 %>\ + % endfor +% endfor + +% for alert_group, lpgs in top['outgoing_alert_lpgs'].items(): + // Outgoing LPGs for alert group ${alert_group} + % for k, lpg in enumerate(lpgs): + // ${lpg['name']} +<% + cg_en = lib.get_clock_lpg_path(top, lpg['clock_connection'], lpg['unmanaged_clock']) + rst_en = lib.get_reset_lpg_path(top, lpg['reset_connection'], False, None, lpg['unmanaged_reset']) + known_clocks[cg_en] = 0 + known_resets[rst_en] = 0 +%>\ + assign outgoing_lpg_cg_en_${alert_group}_o[${k}] = ${cg_en}; + assign outgoing_lpg_rst_en_${alert_group}_o[${k}] = ${rst_en}; + % endfor +% endfor + +// tie-off unused connections +//VCS coverage off +// pragma coverage off +<% k = 0 %>\ +% for clk, unused in known_clocks.items(): + % if unused: + prim_mubi_pkg::mubi4_t unused_cg_en_${k}; + assign unused_cg_en_${k} = ${clk};<% k += 1 %> + % endif +% endfor +<% k = 0 %>\ +% for rst, unused in known_resets.items(): + % if unused: + prim_mubi_pkg::mubi4_t unused_rst_en_${k}; + assign unused_rst_en_${k} = ${rst};<% k += 1 %> + % endif +% endfor +//VCS coverage on +// pragma coverage on diff --git a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/alert_handler_signals.tpl b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/alert_handler_signals.tpl new file mode 100644 index 000000000..ccb8ff388 --- /dev/null +++ b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/alert_handler_signals.tpl @@ -0,0 +1,40 @@ +## Copyright lowRISC contributors (OpenTitan project). +## Licensed under the Apache License, Version 2.0, see LICENSE for details. +## SPDX-License-Identifier: Apache-2.0 +<%import topgen.lib as lib%>\ +<%from reggen.params import Parameter%>\ +<%from topgen.merge import alert_handler_signals%>\ +<%page args="top, feature_info"/>\ +% if feature_info["has_alert_handler"]: +<% alert_handlers = [handler["type"] for handler in lib.find_modules(top["module"], "alert_handler")]%>\ + // Alert list +% for handler in alert_handlers: +<% alert_tx, alert_rx = alert_handler_signals(handler) %>\ + prim_alert_pkg::alert_tx_t [${handler}_pkg::NAlerts-1:0] ${alert_tx}; + prim_alert_pkg::alert_rx_t [${handler}_pkg::NAlerts-1:0] ${alert_rx}; +% endfor\ + +% if not top["alert"]: +% for handler in alert_handlers: +<% alert_tx, _ = alert_handler_signals(handler) %> + for (genvar k = 0; k < ${handler}_pkg::NAlerts; k++) begin : gen_alert_tie_off + // tie off if no alerts present in the system + assign ${alert_tx}[k].alert_p = 1'b0; + assign ${alert_tx}[k].alert_n = 1'b1; + end +% endfor +% endif\ + +% for alert_group, alerts in top['incoming_alert'].items(): +<% alert_info = top["alert_connections"]["incoming_" + alert_group] %>\ +% if not alert_info: +<% continue %>\ +% endif + // Alert mapping to the alert handler for alert group ${alert_group} + % for comment in alert_info["comments"]: + // ${comment} + % endfor + assign ${alert_info["tx_expr"]} = incoming_alert_${alert_group}_tx_i; + assign incoming_alert_${alert_group}_rx_o = ${alert_info["rx_expr"]}; +% endfor +% endif\ diff --git a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/cio_assigns.tpl b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/cio_assigns.tpl new file mode 100644 index 000000000..7ace0cf50 --- /dev/null +++ b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/cio_assigns.tpl @@ -0,0 +1,68 @@ +## Copyright lowRISC contributors (OpenTitan project). +## Licensed under the Apache License, Version 2.0, see LICENSE for details. +## SPDX-License-Identifier: Apache-2.0 +<%import topgen.lib as lib%>\ +<%page args="top, feature_info, cio_info"/>\ +% if feature_info["has_pinmux"]: + // Pinmux connections + // All muxed inputs + % for sig in top["pinmux"]["ios"]: + % if sig["connection"] == "muxed" and sig["type"] in ["inout", "input"]: +<% literal = lib.get_io_enum_literal(sig, 'mio_in') %>\ + assign cio_${sig["name"]}_p2d${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""} = mio_p2d[${literal}]; + % endif + % endfor + + // All muxed outputs + % for sig in top["pinmux"]["ios"]: + % if sig["connection"] == "muxed" and sig["type"] in ["inout", "output"]: +<% literal = lib.get_io_enum_literal(sig, 'mio_out') %>\ + assign mio_d2p[${literal}] = cio_${sig["name"]}_d2p${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""}; + % endif + % endfor + + // All muxed output enables + % for sig in top["pinmux"]["ios"]: + % if sig["connection"] == "muxed" and sig["type"] in ["inout", "output"]: +<% literal = lib.get_io_enum_literal(sig, 'mio_out') %>\ + assign mio_en_d2p[${literal}] = cio_${sig["name"]}_en_d2p${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""}; + % endif + % endfor + + // All dedicated inputs +<% idx = 0 %>\ + logic [${cio_info["num_dio_total"]-1}:0] unused_dio_p2d; + assign unused_dio_p2d = dio_p2d; + % for sig in top["pinmux"]["ios"]: +<% literal = lib.get_io_enum_literal(sig, 'dio') %>\ + % if sig["connection"] != "muxed" and sig["type"] in ["inout"]: + assign cio_${sig["name"]}_p2d${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""} = dio_p2d[${literal}]; + % elif sig["connection"] != "muxed" and sig["type"] in ["input"]: + assign cio_${sig["name"]}_p2d${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""} = dio_p2d[${literal}]; + % endif + % endfor + + // All dedicated outputs + % for sig in top["pinmux"]["ios"]: +<% literal = lib.get_io_enum_literal(sig, 'dio') %>\ + % if sig["connection"] != "muxed" and sig["type"] in ["inout"]: + assign dio_d2p[${literal}] = cio_${sig["name"]}_d2p${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""}; + % elif sig["connection"] != "muxed" and sig["type"] in ["input"]: + assign dio_d2p[${literal}] = 1'b0; + % elif sig["connection"] != "muxed" and sig["type"] in ["output"]: + assign dio_d2p[${literal}] = cio_${sig["name"]}_d2p${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""}; + % endif + % endfor + + // All dedicated output enables + % for sig in top["pinmux"]["ios"]: +<% literal = lib.get_io_enum_literal(sig, 'dio') %>\ + % if sig["connection"] != "muxed" and sig["type"] in ["inout"]: + assign dio_en_d2p[${literal}] = cio_${sig["name"]}_en_d2p${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""}; + % elif sig["connection"] != "muxed" and sig["type"] in ["input"]: + assign dio_en_d2p[${literal}] = 1'b0; + % elif sig["connection"] != "muxed" and sig["type"] in ["output"]: + assign dio_en_d2p[${literal}] = cio_${sig["name"]}_en_d2p${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""}; + % endif + % endfor +% endif diff --git a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/cio_signals.tpl b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/cio_signals.tpl new file mode 100644 index 000000000..83d30520b --- /dev/null +++ b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/cio_signals.tpl @@ -0,0 +1,31 @@ +## Copyright lowRISC contributors (OpenTitan project). +## Licensed under the Apache License, Version 2.0, see LICENSE for details. +## SPDX-License-Identifier: Apache-2.0 +<%import topgen.lib as lib%>\ +<%page args="top, feature_info, cio_info"/>\ + // Signals +% if feature_info["has_pinmux"]: + logic [${cio_info["num_mio_inputs"] - 1}:0] mio_p2d; + logic [${cio_info["num_mio_outputs"] - 1}:0] mio_d2p; + logic [${cio_info["num_mio_outputs"] - 1}:0] mio_en_d2p; + logic [${cio_info["num_dio_total"] - 1}:0] dio_p2d; + logic [${cio_info["num_dio_total"] - 1}:0] dio_d2p; + logic [${cio_info["num_dio_total"] - 1}:0] dio_en_d2p; +% for m in top["module"]: + % if not lib.is_inst(m): +<% continue %> + % endif +<% + block = name_to_block[m['type']] + inouts, inputs, outputs = block.xputs +%>\ + // ${m["name"]} + % for p_in in inputs + inouts: + logic ${lib.bitarray(p_in.bits.width(), cio_info["max_sigwidth"])} cio_${m["name"]}_${p_in.name}_p2d; + % endfor + % for p_out in outputs + inouts: + logic ${lib.bitarray(p_out.bits.width(), cio_info["max_sigwidth"])} cio_${m["name"]}_${p_out.name}_d2p; + logic ${lib.bitarray(p_out.bits.width(), cio_info["max_sigwidth"])} cio_${m["name"]}_${p_out.name}_en_d2p; + % endfor +% endfor +% endif\ diff --git a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/header_parameters.tpl b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/header_parameters.tpl new file mode 100644 index 000000000..0a4beb6c4 --- /dev/null +++ b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/header_parameters.tpl @@ -0,0 +1,42 @@ +## Copyright lowRISC contributors (OpenTitan project). +## Licensed under the Apache License, Version 2.0, see LICENSE for details. +## SPDX-License-Identifier: Apache-2.0 +<%import topgen.lib as lib%>\ +<%page args="top"/>\ +<% +last_modidx_with_params = lib.idx_of_last_module_with_params(top) +%>\ +% if not lib.num_rom_ctrl(top["module"]): + // Manually defined parameters + parameter BootRomInitFile = "", + +% endif + // Auto-inferred parameters +% for m in top["module"]: + % if not lib.is_inst(m): +<% continue %> + % endif + // parameters for ${m['name']} + % for p_exp in [p for p in m["param_list"] if p.get("local") == "false" and p.get("expose") == "true" ]: +<% + p_type = p_exp.get('type') + p_type_word = p_type + ' ' if p_type else '' + + p_lhs = f'{p_type_word}{p_exp["name_top"]}' + + if 'unpacked_dimensions' in p_exp: + p_lhs += p_exp['unpacked_dimensions'] + + p_rhs = p_exp['default'] + + params_follow = not loop.last or loop.parent.index < last_modidx_with_params + comma_char = ',' if params_follow else '' +%>\ + % if 12 + len(p_lhs) + 3 + len(str(p_rhs)) + 1 < 100: + parameter ${p_lhs} = ${p_rhs}${comma_char} + % else: + parameter ${p_lhs} = + ${p_rhs}${comma_char} + % endif + % endfor +% endfor diff --git a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/info_dicts.tpl b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/info_dicts.tpl new file mode 100644 index 000000000..e3aad5388 --- /dev/null +++ b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/info_dicts.tpl @@ -0,0 +1,38 @@ +## Copyright lowRISC contributors (OpenTitan project). +## Licensed under the Apache License, Version 2.0, see LICENSE for details. +## SPDX-License-Identifier: Apache-2.0 +<%import topgen.lib as lib%>\ +<%page args="top, feature_info, cio_info"/>\ +<% +## feature-gating flags +feature_info['has_pinmux'] = lib.find_module(top['module'], 'pinmux') is not None +feature_info['has_alert_handler'] = lib.find_module(top['module'], 'alert_handler') is not None +feature_info['has_ast'] = lib.find_module(top['module'], 'ast') is not None +feature_info['has_rstmgr'] = lib.find_module(top['module'], 'rstmgr') is not None +feature_info['has_gpio'] = lib.find_module(top['module'], 'gpio') is not None +feature_info['has_scan_en'] = False +for m in top['module']: + if not lib.is_inst(m): + continue + block = name_to_block[m['type']] + if block.scan_en: + feature_info['has_scan_en'] = True + +if feature_info['has_pinmux']: + cio_info['num_mio_inputs'] = top['pinmux']['io_counts']['muxed']['inouts'] + \ + top['pinmux']['io_counts']['muxed']['inputs'] + cio_info['num_mio_outputs'] = top['pinmux']['io_counts']['muxed']['inouts'] + \ + top['pinmux']['io_counts']['muxed']['outputs'] + cio_info['num_mio_pads'] = top['pinmux']['io_counts']['muxed']['pads'] + + cio_info['num_dio_inputs'] = top['pinmux']['io_counts']['dedicated']['inouts'] + \ + top['pinmux']['io_counts']['dedicated']['inputs'] + cio_info['num_dio_outputs'] = top['pinmux']['io_counts']['dedicated']['inouts'] + \ + top['pinmux']['io_counts']['dedicated']['outputs'] + cio_info['num_dio_total'] = top['pinmux']['io_counts']['dedicated']['inouts'] + \ + top['pinmux']['io_counts']['dedicated']['inputs'] + \ + top['pinmux']['io_counts']['dedicated']['outputs'] + + max_sigwidth = max([x["width"] if "width" in x else 1 for x in top["pinmux"]["ios"]]) + cio_info['max_sigwidth'] = len("{}".format(max_sigwidth)) +%>\ diff --git a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/intermodule_signals.tpl b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/intermodule_signals.tpl new file mode 100644 index 000000000..ea2457bfe --- /dev/null +++ b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/intermodule_signals.tpl @@ -0,0 +1,68 @@ +## Copyright lowRISC contributors (OpenTitan project). +## Licensed under the Apache License, Version 2.0, see LICENSE for details. +## SPDX-License-Identifier: Apache-2.0 +<%import topgen.lib as lib%>\ +<%from reggen.params import Parameter%>\ +<%page args="top"/>\ +<%unused_resets = lib.get_unused_resets(top)%>\ +<%unused_im_defs, undriven_im_defs = lib.get_dangling_im_def(top["inter_signal"]["definitions"])%>\ +## Inter-module Definitions +% if len(top["inter_signal"]["definitions"]) >= 1: + // define inter-module signals +% endif +% for sig in top["inter_signal"]["definitions"]: + % if isinstance(sig["width"], Parameter): + ${lib.im_defname(sig)} [${sig["width"].name_top}-1:0] ${sig["signame"]}; + % else: + ${lib.im_defname(sig)} ${lib.bitarray(sig["width"],1)} ${sig["signame"]}; + % endif +% endfor + +## Mixed connection to port +## Index greater than 0 means a port is assigned to an inter-module array +## whereas an index of 0 means a port is directly driven by a module + // define mixed connection to port +% for port in top['inter_signal']['external']: + % if port['conn_type'] and port['index'] > 0: + % if port['direction'] == 'in': + assign ${port['netname']}[${port['index']}] = ${port['signame']}; + % else: + assign ${port['signame']} = ${port['netname']}[${port['index']}]; + % endif + % elif port['conn_type']: + % if port['direction'] == 'in': + assign ${port['netname']} = ${port['signame']}; + % else: + assign ${port['signame']} = ${port['netname']}; + % endif + % endif +% endfor + +## Partial inter-module definition tie-off + // Define partial inter-module tie-off +% for sig in unused_im_defs: +<% + width = sig['width'].default if isinstance(sig['width'], Parameter) else sig['width'] +%>\ + % for idx in range(sig['end_idx'], width): + ${lib.im_defname(sig)} unused_${sig["signame"]}${idx}; + % endfor +% endfor + + // Assign partial inter-module tie-off +% for sig in unused_im_defs: +<% + width = sig['width'].default if isinstance(sig['width'], Parameter) else sig['width'] +%>\ + % for idx in range(sig['end_idx'], width): + assign unused_${sig["signame"]}${idx} = ${sig["signame"]}[${idx}]; + % endfor +% endfor +% for sig in undriven_im_defs: +<% + width = sig['width'].default if isinstance(sig['width'], Parameter) else sig['width'] +%>\ + % for idx in range(sig['end_idx'], width): + assign ${sig["signame"]}[${idx}] = ${sig["default"]}; + % endfor +% endfor diff --git a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/interrupt_assigns.tpl b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/interrupt_assigns.tpl new file mode 100644 index 000000000..816ac7d98 --- /dev/null +++ b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/interrupt_assigns.tpl @@ -0,0 +1,48 @@ +## Copyright lowRISC contributors (OpenTitan project). +## Licensed under the Apache License, Version 2.0, see LICENSE for details. +## SPDX-License-Identifier: Apache-2.0 +<%import topgen.lib as lib%>\ +<%page args="top, plic_info"/>\ +% for plic, info in plic_info.items(): +<% + base = info["count"] + default_plic = top.get("default_plic", None) + max_namelen = max(len(irq["name"]) for irq in top["interrupt"] + if not(irq['incoming'] or irq['plic'] != plic)) + if plic == default_plic and top['incoming_interrupt']: + max_namelen = max(max_namelen + + [len(irq["irq_group"]) for irq, _ in top["incoming_interrupt"]]) + max_namelen += 22 + else: + max_namelen += 6 +%>\ + // Interrupt assignments + assign ${info["vector"]} = { + % if plic == default_plic: + % for irq_group, irqs in reversed(top['incoming_interrupt'].items()): +<% + base -= len(irqs) + if len(irqs) > 1: + intr_comment = f"// IDs [{base} +: {intr['width']}]" + else: + intr_comment = f"// ID {base}" +%>\ + ${lib.ljust(f"incoming_interrupt_${irq_group}_i,", max_namelen)} ${intr_comment} + % endfor + % endif + % for intr in top["interrupt"][::-1]: + % if intr['incoming'] or intr['plic'] != plic: +<% continue %>\ + % endif +<% + base -= intr["width"] + if intr["width"] > 1: + intr_comment = f"// IDs [{base} +: {intr['width']}]" + else: + intr_comment = f"// ID {base}" +%>\ + ${lib.ljust(f"intr_{intr['name']},", max_namelen)} ${intr_comment} + % endfor + 1'b0 // ID 0 is a special case and tied to zero. + }; +% endfor diff --git a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_interrupts.tpl b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/interrupt_signals.tpl similarity index 94% rename from hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_interrupts.tpl rename to hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/interrupt_signals.tpl index deb191fc1..19b848f3c 100644 --- a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_interrupts.tpl +++ b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/interrupt_signals.tpl @@ -1,7 +1,8 @@ ## Copyright lowRISC contributors (OpenTitan project). ## Licensed under the Apache License, Version 2.0, see LICENSE for details. ## SPDX-License-Identifier: Apache-2.0 -<%page args="lib, top, name_to_block, plic_info"/>\ +<%import topgen.lib as lib%>\ +<%page args="top, name_to_block, plic_info"/>\ <% # Interrupt source 0 is tied to 0 to conform to the RISC-V PLIC spec. # The total number of interrupts is the sum of the widths of each entry diff --git a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/localparams.tpl b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/localparams.tpl new file mode 100644 index 000000000..85b57e2e9 --- /dev/null +++ b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/localparams.tpl @@ -0,0 +1,32 @@ +## Copyright lowRISC contributors (OpenTitan project). +## Licensed under the Apache License, Version 2.0, see LICENSE for details. +## SPDX-License-Identifier: Apache-2.0 +<%import topgen.lib as lib%>\ +<%page args="top"/>\ + // Local Parameters +% for m in top["module"]: + % if not lib.is_inst(m): +<% continue %> + % endif +<% + localparams = [p for p in m["param_list"] if p.get("local") == "true" and p.get("expose") == "true"] + if not len(localparams): + continue +%>\ + // local parameters for ${m['name']} + % for p_exp in localparams: +<% + p_type = p_exp.get('type') + p_type_word = p_type + ' ' if p_type else '' + + p_lhs = f'{p_type_word}{p_exp["name_top"]}' + p_rhs = p_exp['default'] +%>\ + % if 13 + len(p_lhs) + 3 + len(str(p_rhs)) + 1 < 100: + localparam ${p_lhs} = ${p_rhs}; + % else: + localparam ${p_lhs} = + ${p_rhs}; + % endif + % endfor +% endfor diff --git a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/module_instantiations.tpl b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/module_instantiations.tpl new file mode 100644 index 000000000..2b182067d --- /dev/null +++ b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/module_instantiations.tpl @@ -0,0 +1,160 @@ +## Copyright lowRISC contributors (OpenTitan project). +## Licensed under the Apache License, Version 2.0, see LICENSE for details. +## SPDX-License-Identifier: Apache-2.0 +<%import topgen.lib as lib%>\ +<%from collections import defaultdict%>\ +<%from topgen.merge import is_unmanaged_reset%>\ +<%from topgen.merge import alert_handler_signals%>\ +<%page args="top, plic_info"/>\ + // Peripheral Instantiation +<% outgoing_interrupt_idx = defaultdict(int) %>\ +% for m in top["module"]: +<% +if not lib.is_inst(m): + continue + +block = name_to_block[m['type']] +inouts, inputs, outputs = block.xputs + +port_list = inputs + outputs + inouts +max_sigwidth = max(len(x.name) for x in port_list) if port_list else 0 +max_intrwidth = (max(len(x.name) for x in block.interrupts) + if block.interrupts else 0) +alert_info = top["alert_connections"].get("module_" + m["name"], {}) +has_params, param_items = lib.get_params(top, m) +%>\ + % if has_params: + ${m["type"]} #( +<%include file="/toplevel_snippets/racl_parameters.tpl" args="module=m, top=top, block=block"/>\ + % for param_name, param_value in param_items: + ${param_name}(${param_value})${"," if not loop.last else ""} + % endfor + ) u_${m["name"]} ( + % else: + ${m["type"]} u_${m["name"]} ( + % endif + % for p_in in inputs + inouts: + % if loop.first: + + // Input + % endif + .${lib.ljust("cio_"+p_in.name+"_i",max_sigwidth+9)} (cio_${m["name"]}_${p_in.name}_p2d), + % endfor + % for p_out in outputs + inouts: + % if loop.first: + + // Output + % endif + .${lib.ljust("cio_"+p_out.name+"_o", max_sigwidth+9)} (cio_${m["name"]}_${p_out.name}_d2p), + .${lib.ljust("cio_"+p_out.name+"_en_o",max_sigwidth+9)} (cio_${m["name"]}_${p_out.name}_en_d2p), + % endfor + % for intr in block.interrupts: + % if loop.first: + + // Interrupt + % endif + % if "outgoing_interrupt" in m: +<% + intr_group = m["outgoing_interrupt"] + intr_idx = outgoing_interrupt_idx[intr_group] + intr_slice = str(intr_idx + intr.bits.width() - 1) + ":" + str(intr_idx) + outgoing_interrupt_idx[intr_group] += intr.bits.width() +%>\ + // External interrupt group "${intr_group}" [${intr_slice}]: ${intr.name} + .${lib.ljust("intr_"+intr.name+"_o",max_intrwidth+7)} (outgoing_interrupt_${intr_group}_o[${intr_slice}]), + % else: + .${lib.ljust("intr_"+intr.name+"_o",max_intrwidth+7)} (intr_${m["name"]}_${intr.name}), + % endif + % endfor + % if alert_info: + % for comment in alert_info["comments"]: + % if loop.first: + + % endif + // ${comment} + % endfor + .alert_tx_o ( ${alert_info["tx_expr"]} ), + .alert_rx_i ( ${alert_info["rx_expr"]} ), + % endif +<%include file="/toplevel_snippets/racl_signals.tpl" args="module=m, top=top, block=block"/>\ + ## TODO: Inter-module Connection + % if m.get('inter_signal_list'): + + // Inter-module signals + % for sig in m['inter_signal_list']: + ## TODO: handle below condition in lib.py + % if sig['type'] == "req_rsp": + .${lib.im_portname(sig,"req")}(${lib.im_netname(sig, "req")}), + .${lib.im_portname(sig,"rsp")}(${lib.im_netname(sig, "rsp")}), + % elif sig['type'] == "io": + .${lib.im_portname(sig,"io")}(${lib.im_netname(sig, "io")}), + % elif sig['type'] == "uni": + ## TODO: Broadcast type + ## TODO: default for logic type + .${lib.im_portname(sig)}(${lib.im_netname(sig)}), + % endif + % endfor + % endif + % if m.get("template_type") == "rv_plic": + .intr_src_i (${plic_info[m["name"]]["vector"]}), + % endif + % if m.get("template_type") == "pinmux": + + .periph_to_mio_i (mio_d2p ), + .periph_to_mio_oe_i (mio_en_d2p ), + .mio_to_periph_o (mio_p2d ), + + .mio_attr_o, + .mio_out_o, + .mio_oe_o, + .mio_in_i, + + .periph_to_dio_i (dio_d2p ), + .periph_to_dio_oe_i (dio_en_d2p ), + .dio_to_periph_o (dio_p2d ), + + .dio_attr_o, + .dio_out_o, + .dio_oe_o, + .dio_in_i, + + % endif + % if m.get("template_type") == "alert_handler": +<% alert_tx, alert_rx = alert_handler_signals(m["type"]) %>\ + // alert signals + .alert_rx_o ( ${alert_rx} ), + .alert_tx_i ( ${alert_tx} ), + // synchronized clock gated / reset asserted + // indications for each alert + .lpg_cg_en_i ( lpg_cg_en ), + .lpg_rst_en_i ( lpg_rst_en ), + % endif + % if block.scan: + .scanmode_i, + % endif + % if block.scan_reset: + .scan_rst_ni, + % endif + % if block.scan_en: + .scan_en_i, + % endif + + // Clock and reset connections + % for k, v in m["clock_connections"].items(): + .${k} (${v}), + % endfor + % for port, reset in m["reset_connections"].items(): +<% + is_shadowed_port = lib.is_shadowed_port(block, port) + unmanaged_reset = is_unmanaged_reset(top, reset['name']) + reset_port = lib.get_reset_path(top, reset, False, unmanaged_reset) + shadowed_port = lib.get_reset_path(top, reset, True, unmanaged_reset) +%>\ + % if is_shadowed_port: + .${lib.shadow_name(port)} (${shadowed_port}), + % endif + .${port} (${reset_port})${"," if not loop.last else ""} + % endfor + ); + +% endfor diff --git a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/port_intermodule_signals.tpl b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/port_intermodule_signals.tpl new file mode 100644 index 000000000..f0a073a78 --- /dev/null +++ b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/port_intermodule_signals.tpl @@ -0,0 +1,17 @@ +## Copyright lowRISC contributors (OpenTitan project). +## Licensed under the Apache License, Version 2.0, see LICENSE for details. +## SPDX-License-Identifier: Apache-2.0 +<%import topgen.lib as lib%>\ +<%from reggen.params import Parameter%>\ +<%page args="top"/>\ +% if top["inter_signal"]["external"]: + // Inter-module Signal External type + % for sig in top["inter_signal"]["external"]: + % if isinstance(sig["width"], Parameter): + ${lib.get_direction(sig)} ${lib.im_defname(sig)} [${sig["width"].name_top}-1:0] ${sig["signame"]}, + % else: + ${lib.get_direction(sig)} ${lib.im_defname(sig)} ${lib.bitarray(sig["width"],1)} ${sig["signame"]}, + % endif + % endfor + +% endif diff --git a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/port_special_signals.tpl b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/port_special_signals.tpl new file mode 100644 index 000000000..fd76b76db --- /dev/null +++ b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/port_special_signals.tpl @@ -0,0 +1,89 @@ +## Copyright lowRISC contributors (OpenTitan project). +## Licensed under the Apache License, Version 2.0, see LICENSE for details. +## SPDX-License-Identifier: Apache-2.0 +<%import topgen.lib as lib%>\ +<%page args="top, feature_info, cio_info"/>\ +% if feature_info["has_pinmux"]: +% if cio_info["num_mio_pads"] != 0: + // Multiplexed I/O + input logic ${lib.bitarray(cio_info["num_mio_pads"], cio_info["max_sigwidth"])} mio_in_i, + output logic ${lib.bitarray(cio_info["num_mio_pads"], cio_info["max_sigwidth"])} mio_out_o, + output logic ${lib.bitarray(cio_info["num_mio_pads"], cio_info["max_sigwidth"])} mio_oe_o, + +% endif\ + +% if cio_info["num_dio_total"] != 0: + // Dedicated I/O + input logic ${lib.bitarray(cio_info["num_dio_total"], cio_info["max_sigwidth"])} dio_in_i, + output logic ${lib.bitarray(cio_info["num_dio_total"], cio_info["max_sigwidth"])} dio_out_o, + output logic ${lib.bitarray(cio_info["num_dio_total"], cio_info["max_sigwidth"])} dio_oe_o, + +% endif\ + + // Pad attributes to padring + output prim_pad_wrapper_pkg::pad_attr_t [pinmux_reg_pkg::NMioPads-1:0] mio_attr_o, + output prim_pad_wrapper_pkg::pad_attr_t [pinmux_reg_pkg::NDioPads-1:0] dio_attr_o, + +% endif\ + +% for irq_group, irqs in top['incoming_interrupt'].items(): + // Incoming interrupt of group ${irq_group} + input logic [${len(irqs)-1}:0] incoming_interrupt_${irq_group}_i, +% endfor\ + +% for irq_group, irqs in top["outgoing_interrupt"].items(): + // Outgoing interrupt of group ${irq_group} + output logic [top_${top["name"]}_pkg::NOutgoingInterrupts${irq_group.capitalize()}-1:0] outgoing_interrupt_${irq_group}_o, +% endfor\ + + // All externally supplied clocks +% for clk in top['clocks'].typed_clocks().ast_clks: + input ${clk}, +% endfor\ + +% for alert_group in top['outgoing_alert'].keys(): + // Outgoing alerts for group ${alert_group} + output prim_alert_pkg::alert_tx_t [top_${top["name"]}_pkg::NOutgoingAlerts${alert_group.capitalize()}-1:0] outgoing_alert_${alert_group}_tx_o, + input prim_alert_pkg::alert_rx_t [top_${top["name"]}_pkg::NOutgoingAlerts${alert_group.capitalize()}-1:0] outgoing_alert_${alert_group}_rx_i, + output prim_mubi_pkg::mubi4_t [top_${top["name"]}_pkg::NOutgoingLpgs${alert_group.capitalize()}-1:0] outgoing_lpg_cg_en_${alert_group}_o, + output prim_mubi_pkg::mubi4_t [top_${top["name"]}_pkg::NOutgoingLpgs${alert_group.capitalize()}-1:0] outgoing_lpg_rst_en_${alert_group}_o, +% endfor\ + +% for alert_group in top['incoming_alert'].keys(): + // Incoming alerts for group ${alert_group} + input prim_alert_pkg::alert_tx_t [top_${top["name"]}_pkg::NIncomingAlerts${alert_group.capitalize()}-1:0] incoming_alert_${alert_group}_tx_i, + output prim_alert_pkg::alert_rx_t [top_${top["name"]}_pkg::NIncomingAlerts${alert_group.capitalize()}-1:0] incoming_alert_${alert_group}_rx_o, + input prim_mubi_pkg::mubi4_t [top_${top["name"]}_pkg::NIncomingLpgs${alert_group.capitalize()}-1:0] incoming_lpg_cg_en_${alert_group}_i, + input prim_mubi_pkg::mubi4_t [top_${top["name"]}_pkg::NIncomingLpgs${alert_group.capitalize()}-1:0] incoming_lpg_rst_en_${alert_group}_i, +% endfor + +% if feature_info["has_ast"]: + // All clocks forwarded to ast + output clkmgr_pkg::clkmgr_out_t clks_ast_o, + output rstmgr_pkg::rstmgr_out_t rsts_ast_o, + +% endif\ + +% if len(top['unmanaged_clocks']._asdict().values()) > 0: + // Unmanaged external clocks +% for clk in top['unmanaged_clocks']._asdict().values(): + input ${clk.signal_name}, + input prim_mubi_pkg::mubi4_t ${clk.cg_en_signal}, +% endfor + +% endif\ + +% if len(top['unmanaged_resets']._asdict().values()) > 0: + // Unmanaged external resets + % for rst in top['unmanaged_resets']._asdict().values(): + input ${rst.signal_name}, + input prim_mubi_pkg::mubi4_t ${rst.rst_en_signal_name}, + % endfor + +% endif\ + + input scan_rst_ni, // reset used for test mode +% if feature_info["has_scan_en"]: + input scan_en_i, +% endif + input prim_mubi_pkg::mubi4_t scanmode_i // lc_ctrl_pkg::On for Scan diff --git a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_racl_parameters.tpl b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/racl_parameters.tpl similarity index 100% rename from hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_racl_parameters.tpl rename to hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/racl_parameters.tpl diff --git a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_racl_signals.tpl b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/racl_signals.tpl similarity index 80% rename from hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_racl_signals.tpl rename to hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/racl_signals.tpl index 18037a34e..b4006f69e 100644 --- a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_racl_signals.tpl +++ b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/racl_signals.tpl @@ -13,9 +13,13 @@ policy_sel_name = f"{module['name'].upper()}{group_suffix}{if_suffix}" %>\ % if len(range_mapping) > 0: - .racl_policy_sel_ranges_${if_name}_i(RACL_POLICY_SEL_RANGES_${policy_sel_name}), + + // RACL policies + .racl_policy_sel_ranges_${if_name}_i(RACL_POLICY_SEL_RANGES_${policy_sel_name}), % else: - .racl_policy_sel_ranges_${if_name}_i('{top_racl_pkg::RACL_RANGE_T_DEFAULT}), + + // RACL policies + .racl_policy_sel_ranges_${if_name}_i('{top_racl_pkg::RACL_RANGE_T_DEFAULT}), % endif % endif % endfor diff --git a/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/xbar_instantiations.tpl b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/xbar_instantiations.tpl new file mode 100644 index 000000000..cf44f1ff3 --- /dev/null +++ b/hw/vendor/lowrisc_ip/util/topgen/templates/toplevel_snippets/xbar_instantiations.tpl @@ -0,0 +1,32 @@ +## Copyright lowRISC contributors (OpenTitan project). +## Licensed under the Apache License, Version 2.0, see LICENSE for details. +## SPDX-License-Identifier: Apache-2.0 +<%import topgen.lib as lib%>\ +<%from topgen.merge import is_unmanaged_reset%>\ +<%page args="top"/>\ + // TL-UL Crossbars +% for xbar in top["xbar"]: +<% + name_len = max([len(x["name"]) for x in xbar["nodes"]]); +%>\ + xbar_${xbar["name"]} u_xbar_${xbar["name"]} ( + % for k, v in xbar["clock_connections"].items(): + .${k} (${v}), + % endfor + % for port, reset in xbar["reset_connections"].items(): + .${port} (${lib.get_reset_path(top, reset, False, is_unmanaged_reset(top, reset['name']))}), + % endfor + + ## Inter-module signal + % for sig in xbar["inter_signal_list"]: +<% assert sig['type'] == "req_rsp" %>\ + // port: ${sig['name']} + .${lib.im_portname(sig,"req")}(${lib.im_netname(sig, "req")}), + .${lib.im_portname(sig,"rsp")}(${lib.im_netname(sig, "rsp")}), + + % endfor\ + + .scanmode_i + ); + +% endfor diff --git a/hw/vendor/lowrisc_ip/util/topgen/validate.py b/hw/vendor/lowrisc_ip/util/topgen/validate.py index 6735dc853..965f2a4da 100644 --- a/hw/vendor/lowrisc_ip/util/topgen/validate.py +++ b/hw/vendor/lowrisc_ip/util/topgen/validate.py @@ -46,6 +46,7 @@ 'clocks': ['g', 'group of clock properties'], 'resets': ['l', 'list of resets'], 'addr_spaces': ['g', 'list of address spaces'], + 'power': ['g', 'power domains supported by the design'], 'module': ['l', 'list of modules to instantiate'], 'xbar': ['l', 'List of the xbar used in the top'], 'pinout': ['g', 'Pinout configuration'], @@ -67,7 +68,6 @@ 'num_cores': ['pn', "number of computing units"], 'outgoing_alert': ['g', 'the outgoing alert groups'], 'outgoing_interrupt': ['g', 'the outgoing interrupt groups'], - 'power': ['g', 'power domains supported by the design'], 'port': ['g', 'assign special attributes to specific ports'], 'racl_config': ['s', 'Path to a RACL configuration HJSON file'], 'reset_requests': ['g', 'define reset requests grouped by type'], @@ -183,9 +183,20 @@ 'pinout': ['g', 'Target-specific pinout configuration'], 'pinmux': ['g', 'Target-specific pinmux configuration'] } -target_optional = {} +target_optional = { + 'chiplevel': ['g', 'Target-specific chiplevel configuration'] +} target_added = {} +target_chiplevel_required = { + 'port_overrides': [ + 'l', 'List of ports to manually assign a connected signal or ' + 'leave unconnected (or stub for inputs).' + ], +} +target_chiplevel_optional = {} +target_chiplevel_added = {} + target_pinmux_required = { 'special_signals': ['l', 'List of special signals and the pad they are mapped to.'], @@ -251,7 +262,10 @@ } module_optional = { - 'domain': ['l', 'optional list of power domains, defaults to Domain0'], + 'domain': [ + 's', 'power domain of the module, defaults to the domain specified ' + 'in top["power"]["default"]' + ], 'clock_reset_export': [ 'l', 'optional list with prefixes for exported ' 'clocks and resets at the chip level' @@ -829,6 +843,11 @@ def check_implementation_targets(top: ConfigT, prefix: str) -> int: error += 1 known_names[target['name']] = 1 + if 'chiplevel' in target: + error += check_keys(target['chiplevel'], target_chiplevel_required, + target_chiplevel_optional, target_chiplevel_added, + prefix + ' Target chiplevel') + error += check_keys(target['pinmux'], target_pinmux_required, target_pinmux_optional, target_pinmux_added, prefix + ' Target pinmux') @@ -910,11 +929,6 @@ def check_clocks_resets(top: ConfigT, ip_name_to_block: IpBlocksT, error = 0 - # all defined clock/reset nets - if isinstance(top['resets'], Resets): - reset_nets = [reset.name for reset in top['resets'].nodes.values()] - else: - reset_nets = [reset['name'] for reset in top['resets']['nodes']] clock_srcs = list(top['clocks'].all_srcs.keys()) unmanaged_clock_srcs = list(top['unmanaged_clocks'].clks.keys()) unmanaged_resets = top.get('unmanaged_resets') @@ -932,8 +946,8 @@ def check_clocks_resets(top: ConfigT, ip_name_to_block: IpBlocksT, for ipcfg in top['module']: ipcfg_name = ipcfg['type'] log.info("Checking clock/resets for %s" % ipcfg_name) - error += validate_reset(ipcfg, ip_name_to_block[ipcfg_name], - reset_nets, unmanaged_reset_nets) + error += validate_reset(top, ipcfg, ip_name_to_block[ipcfg_name], + unmanaged_reset_nets) error += validate_clock(ipcfg, ip_name_to_block[ipcfg_name], clock_srcs, unmanaged_clock_srcs) @@ -945,8 +959,8 @@ def check_clocks_resets(top: ConfigT, ip_name_to_block: IpBlocksT, for xbarcfg in top['xbar']: xbarcfg_name = xbarcfg['name'].lower() log.info("Checking clock/resets for xbar %s" % xbarcfg_name) - error += validate_reset(xbarcfg, xbar_name_to_block[xbarcfg_name], - reset_nets, unmanaged_reset_nets, "xbar") + error += validate_reset(top, xbarcfg, xbar_name_to_block[xbarcfg_name], + unmanaged_reset_nets, "xbar") error += validate_clock(xbarcfg, xbar_name_to_block[xbarcfg_name], clock_srcs, unmanaged_clock_srcs, "xbar") @@ -997,13 +1011,19 @@ def check_wakeups(top: ConfigT, component: str) -> int: # port at the destination and defined reset net # - There are the same number of defined connections as there are ports def validate_reset(top: ConfigT, + module: ConfigT, inst: Union[IpBlock, ConfigT], - reset_nets: List[str], unmanaged_reset_nets: List[str], prefix="") -> int: # Gather inst port list error = 0 + # all defined clock/reset nets + if isinstance(top['resets'], Resets): + reset_nets = [reset.name for reset in top['resets'].nodes.values()] + else: + reset_nets = [reset['name'] for reset in top['resets']['nodes']] + # Handle either an IpBlock (generated by reggen) or an OrderedDict # (generated by topgen for a crossbar) if isinstance(inst, IpBlock): @@ -1023,35 +1043,35 @@ def validate_reset(top: ConfigT, # If value is a string, the module can only have ONE domain # If value is a dict, it must have the keys name / domain, and the # value of domain must match that defined for the module. - for port, reset in top["reset_connections"].items(): + for port, reset in module['reset_connections'].items(): if isinstance(reset, str): - top["reset_connections"][port] = {} - top["reset_connections"][port]['name'] = reset - - if len(top["domain"]) > 1: - raise ValueError(f"{top['name']} reset connection {reset} " - "has no assigned domain") - else: - top["reset_connections"][port]['domain'] = top["domain"][0] + module['reset_connections'][port] = {} + module['reset_connections'][port]['name'] = reset + module['reset_connections'][port]['domain'] = top['power']['default'] - if isinstance(reset, dict): + elif isinstance(reset, dict): error += check_keys(reset, reset_connection_required, reset_connection_optional, reset_connection_added, 'dict structure for reset connections') - if reset['domain'] not in top["domain"]: + if reset['domain'] not in top['power']['domains']: error += 1 log.error(f"domain {reset['domain']} defined for reset " f"{reset['name']} is not a domain of {top['name']}") + else: + log.error(f"specified connection for reset port {port} of module " + f"{module['name']} is of type {type(reset)}, but must be " + f"of type string or dict") + # Check if the reset connections are fully populated - if len(top['reset_connections']) != len(reset_signals): + if len(module['reset_connections']) != len(reset_signals): error += 1 log.error(f"{prefix} {name} mismatched number of reset ports and nets") missing_port = [ - port for port in top['reset_connections'].keys() + port for port in module['reset_connections'].keys() if port not in reset_signals ] @@ -1061,7 +1081,7 @@ def validate_reset(top: ConfigT, [log.error(f"{port}") for port in missing_port] missing_net = [ - net['name'] for net in top['reset_connections'].values() + net['name'] for net in module['reset_connections'].values() if net['name'] not in reset_nets + unmanaged_reset_nets ] @@ -1158,6 +1178,9 @@ def validate_alert(top, module, block, handlers, default_handler=None): def check_power_domains(top: ConfigT): + # check that a default power domain is specified + if 'default' not in top['power']: + raise ValueError("No default power domain specified") # check that the default domain is valid if top['power']['default'] not in top['power']['domains']: @@ -1169,12 +1192,11 @@ def check_power_domains(top: ConfigT): # If there is one defined, check that it is a valid definition for end_point in top['module'] + top['xbar']: if 'domain' not in end_point: - end_point['domain'] = [top['power']['default']] + end_point['domain'] = top['power']['default'] - for d in end_point['domain']: - if d not in top['power']['domains']: - raise ValueError( - f"{end_point['name']} defined invalid domain {d}") + if end_point['domain'] not in top['power']['domains']: + raise ValueError( + f"{end_point['name']} defines invalid domain {end_point['domain']}") def check_modules(top: ConfigT, prefix: str) -> int: From 1b076f1bb525555e341398ea2a7693737c3c2e70 Mon Sep 17 00:00:00 2001 From: Kolos Koblasz Date: Wed, 20 May 2026 14:05:44 +0100 Subject: [PATCH 5/7] [rstmgr, rtl] Domain "0" changed to "Main" * To track latest Open Titan variable name changes the domain "0" had to be replaced with "Main". * This is required to be able to complie the code * Only hw/top_chip/data/rstmgr_cfg.hjson is modified in thsi commit Signed-off-by: Kolos Koblasz --- hw/top_chip/data/rstmgr_cfg.hjson | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/hw/top_chip/data/rstmgr_cfg.hjson b/hw/top_chip/data/rstmgr_cfg.hjson index dc815c303..09344b17d 100644 --- a/hw/top_chip/data/rstmgr_cfg.hjson +++ b/hw/top_chip/data/rstmgr_cfg.hjson @@ -48,7 +48,7 @@ power_domains: [ Aon - "0" + Main ] num_rstreqs: 1 sw_rsts: @@ -65,7 +65,7 @@ type: top domains: [ - "0" + Main Aon ] shadowed: false @@ -107,7 +107,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: false @@ -121,7 +121,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: false @@ -135,7 +135,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: true @@ -149,7 +149,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: true @@ -163,7 +163,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: true @@ -208,7 +208,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: false @@ -222,7 +222,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: false @@ -236,7 +236,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: true @@ -250,7 +250,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: true @@ -264,7 +264,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: true From fa474d0e9bea7b1ae9fcadddd3349ba35e394c48 Mon Sep 17 00:00:00 2001 From: Kolos Koblasz Date: Thu, 21 May 2026 09:09:38 +0100 Subject: [PATCH 6/7] [rstmgr, update] Top Level TB and RTL code updated * The latest version of OT has different rstmgr domain name ("0" -> "Main"). * This commit contains the relevant changes of the RTL and the TB Signed-off-by: Kolos Koblasz --- hw/top_chip/dv/tb/tb.sv | 6 +- .../dv/verilator/top_chip_verilator.sv | 6 +- hw/top_chip/rtl/chip_mocha_genesys2.sv | 12 ++-- hw/top_chip/rtl/top_chip_system.sv | 60 +++++++++---------- 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/hw/top_chip/dv/tb/tb.sv b/hw/top_chip/dv/tb/tb.sv index 07b2da65f..6a8967dab 100644 --- a/hw/top_chip/dv/tb/tb.sv +++ b/hw/top_chip/dv/tb/tb.sv @@ -50,7 +50,7 @@ module tb; dram_wrapper_sim u_dram_wrapper ( // Clock and reset. .clk_i (dut.clkmgr_clocks.clk_main_infra), - .rst_ni (dut.rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (dut.rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), // AXI interface. .axi_req_i (dram_req ), .axi_resp_o (dram_resp ) @@ -59,7 +59,7 @@ module tb; // ------ Noise source ------ rng u_rng( .clk_i (dut.clkmgr_clocks.clk_io_infra), - .rst_ni (dut.rstmgr_resets.rst_io_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (dut.rstmgr_resets.rst_io_n[rstmgr_pkg::DomainMainSel]), // Entropy output bus .rng_enable_i (rng_enable), @@ -138,7 +138,7 @@ module tb; // interfaced in sim_sram_axi_sink module. Thus, use the same clock and reset as them to stay in // sync. assign sim_sram_clk = dut.clkmgr_clocks.clk_main_infra; - assign sim_sram_rst = dut.rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]; + assign sim_sram_rst = dut.rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]; // Instantiate the AXI sink to intercept the AXI traffic within the simulation memory range // to provide a dedicated channel for SW-to-DV communication. diff --git a/hw/top_chip/dv/verilator/top_chip_verilator.sv b/hw/top_chip/dv/verilator/top_chip_verilator.sv index 68e852241..ae40c1fe8 100644 --- a/hw/top_chip/dv/verilator/top_chip_verilator.sv +++ b/hw/top_chip/dv/verilator/top_chip_verilator.sv @@ -181,7 +181,7 @@ module top_chip_verilator ( // Detect SW test termination. sim_sram_axi_sink u_sim_sram ( .clk_i (`DUT.clkmgr_clocks.clk_main_infra), - .rst_ni (`DUT.rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (`DUT.rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), .cpu_req_i (sim_sram_cpu_req ), .cpu_resp_o (sim_sram_cpu_resp ), .xbar_req_o (sim_sram_xbar_req ), @@ -231,7 +231,7 @@ module top_chip_verilator ( // Mock AXI external memory dram_wrapper_sim u_dram_wrapper( .clk_i (u_top_chip_system.clkmgr_clocks.clk_main_infra), - .rst_ni (u_top_chip_system.rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (u_top_chip_system.rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), // AXI interface .axi_req_i (dram_req), @@ -241,7 +241,7 @@ module top_chip_verilator ( // Noise source rng u_rng( .clk_i (u_top_chip_system.clkmgr_clocks.clk_io_infra), - .rst_ni (u_top_chip_system.rstmgr_resets.rst_io_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (u_top_chip_system.rstmgr_resets.rst_io_n[rstmgr_pkg::DomainMainSel]), // Entropy output bus .rng_enable_i (rng_enable), diff --git a/hw/top_chip/rtl/chip_mocha_genesys2.sv b/hw/top_chip/rtl/chip_mocha_genesys2.sv index 5537c0b1b..8dcb8324b 100644 --- a/hw/top_chip/rtl/chip_mocha_genesys2.sv +++ b/hw/top_chip/rtl/chip_mocha_genesys2.sv @@ -193,7 +193,7 @@ module chip_mocha_genesys2 #( .ResetValue ('0) ) u_mig_axi_rst_sync_200m ( .clk_i (clk_200m), - .rst_ni (u_top_chip_system.rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (u_top_chip_system.rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), .d_i (1'b1), .q_o (mig_axi_rst_n_sync_200m) ); @@ -203,7 +203,7 @@ module chip_mocha_genesys2 #( .ResetValue ('0) ) u_eth_rst_sync_125m ( .clk_i (clk_125m), - .rst_ni (u_top_chip_system.rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (u_top_chip_system.rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), .d_i (1'b1), .q_o (eth_rst_n_sync_125m) ); @@ -311,7 +311,7 @@ module chip_mocha_genesys2 #( // Noise source rng u_rng( .clk_i (u_top_chip_system.clkmgr_clocks.clk_io_infra), - .rst_ni (u_top_chip_system.rstmgr_resets.rst_io_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (u_top_chip_system.rstmgr_resets.rst_io_n[rstmgr_pkg::DomainMainSel]), // Entropy output bus .rng_enable_i (rng_enable), @@ -332,7 +332,7 @@ module chip_mocha_genesys2 #( .SyncStages (2) // Needs to be 2 for prim_flop_2sync ) u_mig_async_axi_fifo ( .src_clk_i (u_top_chip_system.clkmgr_clocks.clk_main_infra), - .src_rst_ni (u_top_chip_system.rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .src_rst_ni (u_top_chip_system.rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), .src_req_i (dram_req), .src_resp_o (dram_resp), .dst_clk_i (clk_200m), @@ -467,7 +467,7 @@ module chip_mocha_genesys2 #( .rule_t (axi_pkg::xbar_rule_64_t) ) u_rest_of_chip_axi_xbar ( .clk_i (u_top_chip_system.clkmgr_clocks.clk_main_infra), - .rst_ni (u_top_chip_system.rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (u_top_chip_system.rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), .test_i (1'b0), .slv_ports_req_i (xbar_host_req), .slv_ports_resp_o (xbar_host_resp), @@ -486,7 +486,7 @@ module chip_mocha_genesys2 #( ethernet_wrapper u_eth_wrapper ( // Clocking and reset .clk_axi_i (u_top_chip_system.clkmgr_clocks.clk_main_infra), - .rst_axi_ni (u_top_chip_system.rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_axi_ni (u_top_chip_system.rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), .clk_125m_i (clk_125m), .clk_125m_quad_i (clk_125m_quad), .clk_200m_i (clk_200m), diff --git a/hw/top_chip/rtl/top_chip_system.sv b/hw/top_chip/rtl/top_chip_system.sv index 1901487a5..ddad37a2a 100644 --- a/hw/top_chip/rtl/top_chip_system.sv +++ b/hw/top_chip/rtl/top_chip_system.sv @@ -335,7 +335,7 @@ module top_chip_system #( .noc_resp_t ( top_pkg::axi_resp_t ) ) i_cva6 ( .clk_i (clkmgr_clocks.clk_main_infra), - .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), .boot_addr_i (boot_cap), .hart_id_i ('0), .irq_i (intr), @@ -368,7 +368,7 @@ module top_chip_system #( .MemInitFile ( SramInitFile ) ) u_axi_sram ( .clk_i (clkmgr_clocks.clk_main_infra), - .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), // Capability AXI interface .axi_req_i (xbar_device_req[top_pkg::SRAM]), @@ -399,7 +399,7 @@ module top_chip_system #( .rule_t (axi_pkg::xbar_rule_64_t) ) u_axi_xbar ( .clk_i (clkmgr_clocks.clk_main_infra), - .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), .test_i (1'b0), .slv_ports_req_i (xbar_host_req), .slv_ports_resp_o (xbar_host_resp), @@ -426,7 +426,7 @@ module top_chip_system #( .lite_resp_t ( top_pkg::axi_lite_resp_t ) ) u_axi_to_axi_lite_mailbox_main ( .clk_i ( clkmgr_clocks.clk_main_infra ), - .rst_ni ( rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel] ), + .rst_ni ( rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel] ), .test_i ( 1'b0 ), .slv_req_i ( xbar_device_req[top_pkg::Mailbox] ), .slv_resp_o ( xbar_device_resp[top_pkg::Mailbox] ), @@ -450,7 +450,7 @@ module top_chip_system #( .lite_resp_t ( top_pkg::axi_lite_resp_t ) ) u_axi_to_axi_lite_mailbox_ext ( .clk_i ( clkmgr_clocks.clk_main_infra ), - .rst_ni ( rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel] ), + .rst_ni ( rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel] ), .test_i ( 1'b0 ), .slv_req_i ( axi_mailbox_req_i ), .slv_resp_o ( axi_mailbox_resp_o ), @@ -468,7 +468,7 @@ module top_chip_system #( .addr_t ( top_pkg::addr_t ) ) u_axi_lite_mailbox ( .clk_i ( clkmgr_clocks.clk_main_infra ), - .rst_ni ( rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel] ), + .rst_ni ( rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel] ), .test_i ( 1'b0 ), .slv_reqs_i ( { mailbox_ext_req, mailbox_main_req } ), .slv_resps_o ( { mailbox_ext_resp, mailbox_main_resp } ), @@ -486,7 +486,7 @@ module top_chip_system #( .NumBanks ( 1 ) ) u_tl_xbar_axi_to_mem ( .clk_i (clkmgr_clocks.clk_main_infra), - .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), // AXI interface. .busy_o ( ), @@ -508,7 +508,7 @@ module top_chip_system #( // 64-bit mem to 32-bit mem for TLUL crossbar mem_downsizer u_tl_xbar_mem_downsizer ( .clk_i (clkmgr_clocks.clk_main_infra), - .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), // 64-bit memory request in .mem64_req_i (mem64_tl_xbar_req), @@ -537,7 +537,7 @@ module top_chip_system #( .EnableRspDataIntgCheck ( 1 ) ) u_tl_xbar_tlul_host_adapter ( .clk_i (clkmgr_clocks.clk_main_infra), - .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), .req_i (mem32_tl_xbar_req), .gnt_o (mem32_tl_xbar_gnt), @@ -564,8 +564,8 @@ module top_chip_system #( // Clock and reset. .clk_main_i (clkmgr_clocks.clk_main_infra), .clk_io_i (clkmgr_clocks.clk_io_infra), - .rst_main_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), - .rst_io_ni (rstmgr_resets.rst_io_n[rstmgr_pkg::Domain0Sel]), + .rst_main_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), + .rst_io_ni (rstmgr_resets.rst_io_n[rstmgr_pkg::DomainMainSel]), // Host interfaces. .tl_axi_xbar_i (tl_axi_xbar_h2d), @@ -606,7 +606,7 @@ module top_chip_system #( .GpioAsHwStrapsEn(0) // straps not our problem when we are only a SoC subsystem ) u_gpio ( .clk_i (clkmgr_clocks.clk_io_infra), - .rst_ni (rstmgr_resets.rst_io_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_io_n[rstmgr_pkg::DomainMainSel]), .alert_rx_i (prim_alert_pkg::ALERT_RX_DEFAULT), .alert_tx_o ( ), @@ -634,7 +634,7 @@ module top_chip_system #( // Instantiate our UART block. uart u_uart ( .clk_i (clkmgr_clocks.clk_io_infra), - .rst_ni (rstmgr_resets.rst_io_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_io_n[rstmgr_pkg::DomainMainSel]), .alert_rx_i (prim_alert_pkg::ALERT_RX_DEFAULT), .alert_tx_o ( ), @@ -670,7 +670,7 @@ module top_chip_system #( .InputDelayCycles(0) // note: may not be true for all tops ) u_i2c ( .clk_i (clkmgr_clocks.clk_io_infra), - .rst_ni (rstmgr_resets.rst_io_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_io_n[rstmgr_pkg::DomainMainSel]), .alert_rx_i (prim_alert_pkg::ALERT_RX_DEFAULT), .alert_tx_o ( ), @@ -716,7 +716,7 @@ module top_chip_system #( // Instantiate timer rv_timer u_timer ( .clk_i (clkmgr_clocks.clk_io_infra), - .rst_ni (rstmgr_resets.rst_io_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_io_n[rstmgr_pkg::DomainMainSel]), .alert_rx_i (prim_alert_pkg::ALERT_RX_DEFAULT), .alert_tx_o ( ), @@ -735,7 +735,7 @@ module top_chip_system #( // Instantiate PLIC rv_plic u_rv_plic ( .clk_i (clkmgr_clocks.clk_io_infra), - .rst_ni (rstmgr_resets.rst_io_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_io_n[rstmgr_pkg::DomainMainSel]), // Signals to xbar .tl_i (tl_plic_h2d), @@ -757,7 +757,7 @@ module top_chip_system #( // Instantiate SPI device spi_device u_spi_device ( .clk_i (clkmgr_clocks.clk_io_infra), - .rst_ni (rstmgr_resets.rst_io_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_io_n[rstmgr_pkg::DomainMainSel]), // Signals to xbar .tl_i (tl_spi_device_h2d), @@ -809,7 +809,7 @@ module top_chip_system #( ) u_spi_host ( // Clock and reset. .clk_i (clkmgr_clocks.clk_io_infra), - .rst_ni (rstmgr_resets.rst_io_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_io_n[rstmgr_pkg::DomainMainSel]), // TileLink bus connections. .tl_i (tl_spi_host_h2d), @@ -849,7 +849,7 @@ module top_chip_system #( .DistrFifoDepth ( top_pkg::EntropySrcDistrFifoDepth ) ) u_entropy_src ( .clk_i (clkmgr_clocks.clk_io_infra), - .rst_ni (rstmgr_resets.rst_io_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_io_n[rstmgr_pkg::DomainMainSel]), // TileLink bus connections .tl_i (tl_entropy_src_h2d), @@ -970,7 +970,7 @@ module top_chip_system #( .clk_lc_i (clkmgr_clocks.clk_io_powerup), .clk_esc_i (clkmgr_clocks.clk_io_powerup), .rst_ni (rstmgr_resets.rst_por_io_n[rstmgr_pkg::DomainAonSel]), - .rst_main_ni (rstmgr_resets.rst_por_aon_n[rstmgr_pkg::Domain0Sel]), + .rst_main_ni (rstmgr_resets.rst_por_aon_n[rstmgr_pkg::DomainMainSel]), .rst_lc_ni (rstmgr_resets.rst_por_io_n[rstmgr_pkg::DomainAonSel]), .rst_esc_ni (rstmgr_resets.rst_por_io_n[rstmgr_pkg::DomainAonSel]), .rst_slow_ni (rstmgr_resets.rst_por_aon_n[rstmgr_pkg::DomainAonSel]) @@ -1042,7 +1042,7 @@ module top_chip_system #( .RISCV_WORD_WIDTH ( 64 ) ) u_axi_riscv_atomics ( .clk_i (clkmgr_clocks.clk_main_infra), - .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), .slv (xbar_device_dram), .mst (dram_post_atomics) ); @@ -1058,7 +1058,7 @@ module top_chip_system #( .axi_resp_t ( top_pkg::axi_resp_t ) ) u_axi_cut ( .clk_i (clkmgr_clocks.clk_main_infra), - .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), .slv_req_i (dram_post_atomics_req), .slv_resp_o (dram_post_atomics_resp), .mst_req_o (dram_cut_req), @@ -1077,7 +1077,7 @@ module top_chip_system #( .axi_resp_t ( top_pkg::axi_resp_t ) ) u_tag_controller_isolate ( .clk_i (clkmgr_clocks.clk_main_infra), - .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), .slv_req_i (dram_cut_req), .slv_resp_o (dram_cut_resp), .mst_req_o (tag_controller_isolated_req), @@ -1090,8 +1090,8 @@ module top_chip_system #( assign tag_controller_isolate = (dram_cut_req.ar_valid && dram_cut_resp.ar_ready) || (dram_cut_req.aw_valid && dram_cut_resp.aw_ready); - always_ff @(posedge clkmgr_clocks.clk_main_infra or negedge rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]) begin - if (!rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]) tag_controller_isolate_reg <= 1'b0; + always_ff @(posedge clkmgr_clocks.clk_main_infra or negedge rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]) begin + if (!rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]) tag_controller_isolate_reg <= 1'b0; else if (tag_controller_isolate) tag_controller_isolate_reg <= 1'b1; else if (tag_controller_isolated) tag_controller_isolate_reg <= 1'b0; end @@ -1121,7 +1121,7 @@ module top_chip_system #( .rule_full_t ( axi_pkg::xbar_rule_64_t ) ) u_tag_controller ( .clk_i (clkmgr_clocks.clk_main_infra), - .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), .test_i ('0), .slv_req_i (tag_controller_isolated_req), .slv_resp_o (tag_controller_isolated_resp), @@ -1144,7 +1144,7 @@ module top_chip_system #( .NumBanks ( 1 ) ) u_tl_rom_axi_to_mem ( .clk_i (clkmgr_clocks.clk_main_infra), - .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), // AXI interface. .busy_o ( ), @@ -1166,7 +1166,7 @@ module top_chip_system #( // 64-bit mem to 32-bit mem for TLUL ROM mem_downsizer u_tl_rom_mem_downsizer ( .clk_i (clkmgr_clocks.clk_main_infra), - .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), // 64-bit memory request in .mem64_req_i (mem64_tl_rom_mem_req), @@ -1195,7 +1195,7 @@ module top_chip_system #( .EnableRspDataIntgCheck ( 1 ) ) u_tl_rom_tlul_host_adapter ( .clk_i (clkmgr_clocks.clk_main_infra), - .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), .req_i (mem32_tl_rom_mem_req), .gnt_o (mem32_tl_rom_mem_gnt), @@ -1229,7 +1229,7 @@ module top_chip_system #( ) u_rom_ctrl ( // Clock and reset connections .clk_i (clkmgr_clocks.clk_main_infra), - .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), // Allert Signals .alert_tx_o ( ), From 0bd4b1b203a8ccccf41e0d42e620ac11c0c9489d Mon Sep 17 00:00:00 2001 From: Kolos Koblasz Date: Fri, 22 May 2026 12:24:31 +0100 Subject: [PATCH 7/7] [rstmgr_dv, autogen] Autogenerated code added * As result of previous changes autogenerated modules had to be regenerated. Signed-off-by: Kolos Koblasz --- .../ip_autogen/alert_handler/dv/README.md | 4 +- .../dv/env/alert_handler_env_cfg.sv | 4 +- .../alert_handler_entropy_stress_vseq.sv | 1 + hw/top_chip/ip_autogen/clkmgr/dv/README.md | 4 +- .../clkmgr/dv/env/clkmgr_env_cfg.sv | 4 +- .../dv/env/seq_lib/clkmgr_regwen_vseq.sv | 8 +- .../ip_autogen/clkmgr/rtl/clkmgr_reg_top.sv | 56 ++++++++- hw/top_chip/ip_autogen/gpio/dv/README.md | 4 +- .../ip_autogen/gpio/dv/env/gpio_env_cfg.sv | 4 +- hw/top_chip/ip_autogen/pwrmgr/dv/README.md | 4 +- .../pwrmgr/dv/env/pwrmgr_env_cfg.sv | 4 +- .../env/seq_lib/pwrmgr_reset_invalid_vseq.sv | 1 - .../rstmgr/data/mocha_rstmgr.ipconfig.hjson | 24 ++-- hw/top_chip/ip_autogen/rstmgr/dv/README.md | 4 +- .../rstmgr/dv/cov/rstmgr_tgl_excl.cfg | 8 +- .../rstmgr/dv/env/rstmgr_env_cfg.sv | 4 +- .../rstmgr/dv/env/rstmgr_env_pkg.sv | 12 +- .../ip_autogen/rstmgr/dv/env/rstmgr_if.sv | 2 +- .../rstmgr/dv/sva/rstmgr_cascading_sva_if.sv | 12 +- .../dv/sva/rstmgr_rst_en_track_sva_if.sv | 86 ++++++------- hw/top_chip/ip_autogen/rstmgr/dv/tb.sv | 6 +- hw/top_chip/ip_autogen/rstmgr/rtl/rstmgr.sv | 116 +++++++++--------- .../ip_autogen/rstmgr/rtl/rstmgr_ctrl.sv | 2 +- .../ip_autogen/rstmgr/rtl/rstmgr_pkg.sv | 2 +- .../rv_plic/fpv/vip/rv_plic_assert_fpv.sv | 10 ++ hw/top_chip/ip_autogen/rv_plic/rtl/rv_plic.sv | 4 - .../ip_autogen/rv_plic/rtl/rv_plic_gateway.sv | 74 +++++++++-- 27 files changed, 283 insertions(+), 181 deletions(-) diff --git a/hw/top_chip/ip_autogen/alert_handler/dv/README.md b/hw/top_chip/ip_autogen/alert_handler/dv/README.md index f747f76b5..b83d49946 100644 --- a/hw/top_chip/ip_autogen/alert_handler/dv/README.md +++ b/hw/top_chip/ip_autogen/alert_handler/dv/README.md @@ -107,11 +107,11 @@ The alert_handler scoreboard is parameterized to support different number of cla * Unknown checks on DUT outputs: The RTL has assertions to ensure all outputs are initialized to known values after coming out of reset. ## Building and running tests -We are using our in-house developed [regression tool](../../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/$CHIP/ip_autogen/alert_handler/dv/alert_handler_sim_cfg.hjson -i alert_handler_smoke +$ dvsim $REPO_TOP/hw/$CHIP/ip_autogen/alert_handler/dv/alert_handler_sim_cfg.hjson -i alert_handler_smoke ``` In this run command, $CHIP can be top_earlgrey, etc. diff --git a/hw/top_chip/ip_autogen/alert_handler/dv/env/alert_handler_env_cfg.sv b/hw/top_chip/ip_autogen/alert_handler/dv/env/alert_handler_env_cfg.sv index cb1aeb710..ad3b457f9 100644 --- a/hw/top_chip/ip_autogen/alert_handler/dv/env/alert_handler_env_cfg.sv +++ b/hw/top_chip/ip_autogen/alert_handler/dv/env/alert_handler_env_cfg.sv @@ -18,9 +18,9 @@ class alert_handler_env_cfg extends cip_base_env_cfg #(.RAL_T(alert_handler_reg_ `uvm_object_new - virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1); + virtual function void initialize(); num_edn = 1; - super.initialize(csr_base_addr); + super.initialize(); shadow_update_err_status_fields[ral.loc_alert_cause[LocalShadowRegUpdateErr].la] = 1; shadow_storage_err_status_fields[ral.loc_alert_cause[LocalShadowRegStorageErr].la] = 1; diff --git a/hw/top_chip/ip_autogen/alert_handler/dv/env/seq_lib/alert_handler_entropy_stress_vseq.sv b/hw/top_chip/ip_autogen/alert_handler/dv/env/seq_lib/alert_handler_entropy_stress_vseq.sv index b36e43178..1cd9e029a 100644 --- a/hw/top_chip/ip_autogen/alert_handler/dv/env/seq_lib/alert_handler_entropy_stress_vseq.sv +++ b/hw/top_chip/ip_autogen/alert_handler/dv/env/seq_lib/alert_handler_entropy_stress_vseq.sv @@ -34,6 +34,7 @@ class alert_handler_entropy_stress_vseq extends alert_handler_smoke_vseq; foreach (cfg.alert_host_cfg[i]) begin cfg.alert_host_cfg[i].alert_delay_max = 0; + cfg.alert_host_cfg[i].ping_delay_min = 0; cfg.alert_host_cfg[i].ping_delay_max = 0; end super.pre_start(); diff --git a/hw/top_chip/ip_autogen/clkmgr/dv/README.md b/hw/top_chip/ip_autogen/clkmgr/dv/README.md index 7546d58e2..f501a1caa 100644 --- a/hw/top_chip/ip_autogen/clkmgr/dv/README.md +++ b/hw/top_chip/ip_autogen/clkmgr/dv/README.md @@ -167,12 +167,12 @@ The `jitter_en_o` output is checked to match the `jitter_enable` CSR. * Unknown checks on DUT outputs: The RTL has assertions to ensure all outputs are initialized to known values after coming out of reset. ## Building and running tests -We are using our in-house developed [regression tool](../../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/top_mocha/ip_autogen/clkmgr/dv/clkmgr_sim_cfg.hjson -i clkmgr_smoke +$ dvsim $REPO_TOP/hw/top_mocha/ip_autogen/clkmgr/dv/clkmgr_sim_cfg.hjson -i clkmgr_smoke ``` ## Testplan diff --git a/hw/top_chip/ip_autogen/clkmgr/dv/env/clkmgr_env_cfg.sv b/hw/top_chip/ip_autogen/clkmgr/dv/env/clkmgr_env_cfg.sv index 15bd71bf4..72cfcd404 100644 --- a/hw/top_chip/ip_autogen/clkmgr/dv/env/clkmgr_env_cfg.sv +++ b/hw/top_chip/ip_autogen/clkmgr/dv/env/clkmgr_env_cfg.sv @@ -26,9 +26,9 @@ class clkmgr_env_cfg extends cip_base_env_cfg #( `uvm_object_new - virtual function void initialize(bit [31:0] csr_base_addr = '1); + virtual function void initialize(); list_of_alerts = clkmgr_env_pkg::LIST_OF_ALERTS; - super.initialize(csr_base_addr); + super.initialize(); // This is for the integrity error test. tl_intg_alert_name = "fatal_fault"; diff --git a/hw/top_chip/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_regwen_vseq.sv b/hw/top_chip/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_regwen_vseq.sv index 53ef8e01d..45e54b2ae 100644 --- a/hw/top_chip/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_regwen_vseq.sv +++ b/hw/top_chip/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_regwen_vseq.sv @@ -11,16 +11,16 @@ class clkmgr_regwen_vseq extends clkmgr_base_vseq; task check_jitter_regwen(); bit enable; - mubi4_t prev_value; - mubi4_t new_value; + logic [3:0] prev_value_bits; + mubi4_t new_value; `DV_CHECK_STD_RANDOMIZE_FATAL(enable) new_value = get_rand_mubi4_val(.t_weight(1), .f_weight(1), .other_weight(2)); `uvm_info(`gfn, $sformatf("Check jitter_regwen = %b", enable), UVM_MEDIUM) csr_wr(.ptr(ral.jitter_regwen), .value(enable)); - csr_rd(.ptr(ral.jitter_enable), .value(prev_value)); + csr_rd(.ptr(ral.jitter_enable), .value(prev_value_bits)); csr_wr(.ptr(ral.jitter_enable), .value(new_value)); - csr_rd_check(.ptr(ral. jitter_enable), .compare_value(enable ? new_value : prev_value)); + csr_rd_check(.ptr(ral.jitter_enable), .compare_value(enable ? new_value : prev_value_bits)); `uvm_info(`gfn, "Check jitter_regwen done", UVM_MEDIUM) endtask : check_jitter_regwen diff --git a/hw/top_chip/ip_autogen/clkmgr/rtl/clkmgr_reg_top.sv b/hw/top_chip/ip_autogen/clkmgr/rtl/clkmgr_reg_top.sv index 2145ba124..902057cb3 100644 --- a/hw/top_chip/ip_autogen/clkmgr/rtl/clkmgr_reg_top.sv +++ b/hw/top_chip/ip_autogen/clkmgr/rtl/clkmgr_reg_top.sv @@ -609,6 +609,18 @@ module clkmgr_reg_top ( // F[hi]: 8:0 logic async_io_meas_ctrl_shadowed_hi_err_update; logic async_io_meas_ctrl_shadowed_hi_err_storage; + logic deglitched_io_meas_ctrl_shadowed_hi_err_storage; + + // flop storage error to filter combinational glitches before sending it across CDC + prim_flop #( + .Width(1), + .ResetValue('0) + ) u_io_meas_ctrl_shadowed_hi_err_storage_deglitch ( + .clk_i (clk_io_i), + .rst_ni(rst_io_ni), + .d_i (async_io_meas_ctrl_shadowed_hi_err_storage), + .q_o (deglitched_io_meas_ctrl_shadowed_hi_err_storage) + ); // storage error is persistent and can be sampled at any time prim_flop_2sync #( @@ -617,7 +629,7 @@ module clkmgr_reg_top ( ) u_io_meas_ctrl_shadowed_hi_err_storage_sync ( .clk_i, .rst_ni, - .d_i(async_io_meas_ctrl_shadowed_hi_err_storage), + .d_i(deglitched_io_meas_ctrl_shadowed_hi_err_storage), .q_o(io_meas_ctrl_shadowed_hi_storage_err) ); @@ -668,6 +680,18 @@ module clkmgr_reg_top ( // F[lo]: 17:9 logic async_io_meas_ctrl_shadowed_lo_err_update; logic async_io_meas_ctrl_shadowed_lo_err_storage; + logic deglitched_io_meas_ctrl_shadowed_lo_err_storage; + + // flop storage error to filter combinational glitches before sending it across CDC + prim_flop #( + .Width(1), + .ResetValue('0) + ) u_io_meas_ctrl_shadowed_lo_err_storage_deglitch ( + .clk_i (clk_io_i), + .rst_ni(rst_io_ni), + .d_i (async_io_meas_ctrl_shadowed_lo_err_storage), + .q_o (deglitched_io_meas_ctrl_shadowed_lo_err_storage) + ); // storage error is persistent and can be sampled at any time prim_flop_2sync #( @@ -676,7 +700,7 @@ module clkmgr_reg_top ( ) u_io_meas_ctrl_shadowed_lo_err_storage_sync ( .clk_i, .rst_ni, - .d_i(async_io_meas_ctrl_shadowed_lo_err_storage), + .d_i(deglitched_io_meas_ctrl_shadowed_lo_err_storage), .q_o(io_meas_ctrl_shadowed_lo_storage_err) ); @@ -767,6 +791,18 @@ module clkmgr_reg_top ( // F[hi]: 8:0 logic async_main_meas_ctrl_shadowed_hi_err_update; logic async_main_meas_ctrl_shadowed_hi_err_storage; + logic deglitched_main_meas_ctrl_shadowed_hi_err_storage; + + // flop storage error to filter combinational glitches before sending it across CDC + prim_flop #( + .Width(1), + .ResetValue('0) + ) u_main_meas_ctrl_shadowed_hi_err_storage_deglitch ( + .clk_i (clk_main_i), + .rst_ni(rst_main_ni), + .d_i (async_main_meas_ctrl_shadowed_hi_err_storage), + .q_o (deglitched_main_meas_ctrl_shadowed_hi_err_storage) + ); // storage error is persistent and can be sampled at any time prim_flop_2sync #( @@ -775,7 +811,7 @@ module clkmgr_reg_top ( ) u_main_meas_ctrl_shadowed_hi_err_storage_sync ( .clk_i, .rst_ni, - .d_i(async_main_meas_ctrl_shadowed_hi_err_storage), + .d_i(deglitched_main_meas_ctrl_shadowed_hi_err_storage), .q_o(main_meas_ctrl_shadowed_hi_storage_err) ); @@ -826,6 +862,18 @@ module clkmgr_reg_top ( // F[lo]: 17:9 logic async_main_meas_ctrl_shadowed_lo_err_update; logic async_main_meas_ctrl_shadowed_lo_err_storage; + logic deglitched_main_meas_ctrl_shadowed_lo_err_storage; + + // flop storage error to filter combinational glitches before sending it across CDC + prim_flop #( + .Width(1), + .ResetValue('0) + ) u_main_meas_ctrl_shadowed_lo_err_storage_deglitch ( + .clk_i (clk_main_i), + .rst_ni(rst_main_ni), + .d_i (async_main_meas_ctrl_shadowed_lo_err_storage), + .q_o (deglitched_main_meas_ctrl_shadowed_lo_err_storage) + ); // storage error is persistent and can be sampled at any time prim_flop_2sync #( @@ -834,7 +882,7 @@ module clkmgr_reg_top ( ) u_main_meas_ctrl_shadowed_lo_err_storage_sync ( .clk_i, .rst_ni, - .d_i(async_main_meas_ctrl_shadowed_lo_err_storage), + .d_i(deglitched_main_meas_ctrl_shadowed_lo_err_storage), .q_o(main_meas_ctrl_shadowed_lo_storage_err) ); diff --git a/hw/top_chip/ip_autogen/gpio/dv/README.md b/hw/top_chip/ip_autogen/gpio/dv/README.md index 0da6c61c3..b565281e1 100644 --- a/hw/top_chip/ip_autogen/gpio/dv/README.md +++ b/hw/top_chip/ip_autogen/gpio/dv/README.md @@ -103,11 +103,11 @@ Any CSR read transaction would check actual read data against predicted value. * `CioGpioOKnown`: Checks that GPIO output enable does not have any unknowns ## Building and running tests -We are using our in-house developed [regression tool](../../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/top_mocha/ip_autogen/gpio/dv/gpio_sim_cfg.hjson -i gpio_smoke +$ dvsim $REPO_TOP/hw/top_mocha/ip_autogen/gpio/dv/gpio_sim_cfg.hjson -i gpio_smoke ``` ## Testplan diff --git a/hw/top_chip/ip_autogen/gpio/dv/env/gpio_env_cfg.sv b/hw/top_chip/ip_autogen/gpio/dv/env/gpio_env_cfg.sv index e9e269c8d..d4991a9c3 100644 --- a/hw/top_chip/ip_autogen/gpio/dv/env/gpio_env_cfg.sv +++ b/hw/top_chip/ip_autogen/gpio/dv/env/gpio_env_cfg.sv @@ -24,9 +24,9 @@ class gpio_env_cfg extends cip_base_env_cfg #( super.new(name); endfunction - virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1); + virtual function void initialize(); list_of_alerts = gpio_env_pkg::LIST_OF_ALERTS; - super.initialize(csr_base_addr); + super.initialize(); // set num_interrupts & num_alerts which will be used to create coverage and more num_interrupts = ral.intr_state.get_n_used_bits(); diff --git a/hw/top_chip/ip_autogen/pwrmgr/dv/README.md b/hw/top_chip/ip_autogen/pwrmgr/dv/README.md index 37107e16a..cf80c6701 100644 --- a/hw/top_chip/ip_autogen/pwrmgr/dv/README.md +++ b/hw/top_chip/ip_autogen/pwrmgr/dv/README.md @@ -242,11 +242,11 @@ The [`hw/top_mocha/ip_autogen/pwrmgr/dv/sva/pwrmgr_bind.sv`](https://github.com/ In addition, the RTL has assertions to ensure all outputs are initialized to known values after coming out of reset. ## Building and running tests -We are using our in-house developed [regression tool](../../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/top_mocha/ip_autogen/pwrmgr/dv/pwrmgr_sim_cfg.hjson -i pwrmgr_smoke +$ dvsim $REPO_TOP/hw/top_mocha/ip_autogen/pwrmgr/dv/pwrmgr_sim_cfg.hjson -i pwrmgr_smoke ``` ## Testplan diff --git a/hw/top_chip/ip_autogen/pwrmgr/dv/env/pwrmgr_env_cfg.sv b/hw/top_chip/ip_autogen/pwrmgr/dv/env/pwrmgr_env_cfg.sv index 113b8b6ea..862a4b51b 100644 --- a/hw/top_chip/ip_autogen/pwrmgr/dv/env/pwrmgr_env_cfg.sv +++ b/hw/top_chip/ip_autogen/pwrmgr/dv/env/pwrmgr_env_cfg.sv @@ -31,9 +31,9 @@ class pwrmgr_env_cfg extends cip_base_env_cfg #( // The run_phase object, to deal with objections. uvm_phase run_phase; - virtual function void initialize(bit [31:0] csr_base_addr = '1); + virtual function void initialize(); list_of_alerts = pwrmgr_env_pkg::LIST_OF_ALERTS; - super.initialize(csr_base_addr); + super.initialize(); num_interrupts = ral.intr_state.get_n_used_bits(); `ASSERT_I(NumInstrMatch_A, num_interrupts == NUM_INTERRUPTS) `uvm_info(`gfn, $sformatf("num_interrupts = %0d", num_interrupts), UVM_MEDIUM) diff --git a/hw/top_chip/ip_autogen/pwrmgr/dv/env/seq_lib/pwrmgr_reset_invalid_vseq.sv b/hw/top_chip/ip_autogen/pwrmgr/dv/env/seq_lib/pwrmgr_reset_invalid_vseq.sv index c5c0090f4..f3159daf8 100644 --- a/hw/top_chip/ip_autogen/pwrmgr/dv/env/seq_lib/pwrmgr_reset_invalid_vseq.sv +++ b/hw/top_chip/ip_autogen/pwrmgr/dv/env/seq_lib/pwrmgr_reset_invalid_vseq.sv @@ -42,7 +42,6 @@ class pwrmgr_reset_invalid_vseq extends pwrmgr_base_vseq; wait_for_rom_and_active(); check_reset_status('0); - $assertoff(0, "tb.dut.u_cdc.u_clr_reqack.SyncReqAckHoldReq"); for (int i = 0; i < num_of_target_states; ++i) begin `uvm_info(`gfn, $sformatf("Starting new round %0d", i), UVM_MEDIUM) diff --git a/hw/top_chip/ip_autogen/rstmgr/data/mocha_rstmgr.ipconfig.hjson b/hw/top_chip/ip_autogen/rstmgr/data/mocha_rstmgr.ipconfig.hjson index b93d2bbfe..fb5b996f8 100644 --- a/hw/top_chip/ip_autogen/rstmgr/data/mocha_rstmgr.ipconfig.hjson +++ b/hw/top_chip/ip_autogen/rstmgr/data/mocha_rstmgr.ipconfig.hjson @@ -48,7 +48,7 @@ power_domains: [ Aon - "0" + Main ] num_rstreqs: 1 sw_rsts: @@ -65,7 +65,7 @@ type: top domains: [ - "0" + Main Aon ] shadowed: false @@ -107,7 +107,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: false @@ -121,7 +121,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: false @@ -135,7 +135,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: true @@ -149,7 +149,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: true @@ -163,7 +163,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: true @@ -208,7 +208,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: false @@ -222,7 +222,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: false @@ -236,7 +236,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: true @@ -250,7 +250,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: true @@ -264,7 +264,7 @@ type: top domains: [ - "0" + Main ] shadowed: false sw: true diff --git a/hw/top_chip/ip_autogen/rstmgr/dv/README.md b/hw/top_chip/ip_autogen/rstmgr/dv/README.md index 71ecb79c4..5eb7f88b6 100644 --- a/hw/top_chip/ip_autogen/rstmgr/dv/README.md +++ b/hw/top_chip/ip_autogen/rstmgr/dv/README.md @@ -111,11 +111,11 @@ It depends on very specific timing, and requires tampering stimulus to verify it It has its own separate dv environment and tests at `hw/top_mocha/ip_autogen/rstmgr/dv/rstmgr_cnsty_chk`. It is excluded from coverage for the rstmgr dv tests. -We are using our in-house developed [regression tool](../../../../../util/dvsim/README.md) for building and running our tests and regressions. +The [dvsim](https://github.com/lowRISC/dvsim) tool is used for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here's how to run a smoke test: ```console -$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/top_mocha/ip_autogen/rstmgr/dv/rstmgr_sim_cfg.hjson -i rstmgr_smoke +$ dvsim $REPO_TOP/hw/top_mocha/ip_autogen/rstmgr/dv/rstmgr_sim_cfg.hjson -i rstmgr_smoke ``` [Testplan](../data/rstmgr_testplan.hjson) diff --git a/hw/top_chip/ip_autogen/rstmgr/dv/cov/rstmgr_tgl_excl.cfg b/hw/top_chip/ip_autogen/rstmgr/dv/cov/rstmgr_tgl_excl.cfg index 2837a8962..fd621cceb 100644 --- a/hw/top_chip/ip_autogen/rstmgr/dv/cov/rstmgr_tgl_excl.cfg +++ b/hw/top_chip/ip_autogen/rstmgr/dv/cov/rstmgr_tgl_excl.cfg @@ -6,10 +6,10 @@ // This file contains outputs of rstmgr tied to constants. //====================================================================== --module_node rstmgr resets_o.rst_por_n[Domain0Sel] --module_node rstmgr rst_en_o.por[Domain0Sel] --module_node rstmgr resets_o.rst_por_io_n[Domain0Sel] --module_node rstmgr rst_en_o.por_io[Domain0Sel] +-module_node rstmgr resets_o.rst_por_n[DomainMainSel] +-module_node rstmgr rst_en_o.por[DomainMainSel] +-module_node rstmgr resets_o.rst_por_io_n[DomainMainSel] +-module_node rstmgr rst_en_o.por_io[DomainMainSel] -module_node rstmgr resets_o.rst_main_n[DomainAonSel] -module_node rstmgr rst_en_o.main[DomainAonSel] -module_node rstmgr resets_o.rst_io_n[DomainAonSel] diff --git a/hw/top_chip/ip_autogen/rstmgr/dv/env/rstmgr_env_cfg.sv b/hw/top_chip/ip_autogen/rstmgr/dv/env/rstmgr_env_cfg.sv index 14efd1a76..55408ecd7 100644 --- a/hw/top_chip/ip_autogen/rstmgr/dv/env/rstmgr_env_cfg.sv +++ b/hw/top_chip/ip_autogen/rstmgr/dv/env/rstmgr_env_cfg.sv @@ -23,9 +23,9 @@ class rstmgr_env_cfg extends cip_base_env_cfg #( virtual rstmgr_cascading_sva_if rstmgr_cascading_sva_vif; virtual rstmgr_if rstmgr_vif; - virtual function void initialize(bit [31:0] csr_base_addr = '1); + virtual function void initialize(); list_of_alerts = rstmgr_env_pkg::LIST_OF_ALERTS; - super.initialize(csr_base_addr); + super.initialize(); tl_intg_alert_fields[ral.err_code.reg_intg_err] = 1; m_tl_agent_cfg.max_outstanding_req = 1; diff --git a/hw/top_chip/ip_autogen/rstmgr/dv/env/rstmgr_env_pkg.sv b/hw/top_chip/ip_autogen/rstmgr/dv/env/rstmgr_env_pkg.sv index ceb0f67db..f136b40c1 100644 --- a/hw/top_chip/ip_autogen/rstmgr/dv/env/rstmgr_env_pkg.sv +++ b/hw/top_chip/ip_autogen/rstmgr/dv/env/rstmgr_env_pkg.sv @@ -35,13 +35,13 @@ package rstmgr_env_pkg; // Sorted instances of rstmgr_leaf_rst instances with security checks enabled. parameter string LIST_OF_LEAFS[] = { - "u_d0_i2c", - "u_d0_io", - "u_d0_main", - "u_d0_spi_device", - "u_d0_spi_host", "u_daon_por", - "u_daon_por_io" + "u_daon_por_io", + "u_dmain_i2c", + "u_dmain_io", + "u_dmain_main", + "u_dmain_spi_device", + "u_dmain_spi_host" }; // Instances of rstmgr_leaf_rst modules which have a shadow pair. diff --git a/hw/top_chip/ip_autogen/rstmgr/dv/env/rstmgr_if.sv b/hw/top_chip/ip_autogen/rstmgr/dv/env/rstmgr_if.sv index 36d5c64af..900be51d5 100644 --- a/hw/top_chip/ip_autogen/rstmgr/dv/env/rstmgr_if.sv +++ b/hw/top_chip/ip_autogen/rstmgr/dv/env/rstmgr_if.sv @@ -65,5 +65,5 @@ interface rstmgr_if ( always_comb cpu_info_en = `PATH_TO_DUT.reg2hw.cpu_info_ctrl.en.q; bit rst_ni_inactive; - always_comb rst_ni_inactive = resets_o.rst_lc_io_n[rstmgr_pkg::Domain0Sel]; + always_comb rst_ni_inactive = resets_o.rst_lc_io_n[rstmgr_pkg::DomainMainSel]; endinterface diff --git a/hw/top_chip/ip_autogen/rstmgr/dv/sva/rstmgr_cascading_sva_if.sv b/hw/top_chip/ip_autogen/rstmgr/dv/sva/rstmgr_cascading_sva_if.sv index 1a0e26b28..a81fa6f46 100644 --- a/hw/top_chip/ip_autogen/rstmgr/dv/sva/rstmgr_cascading_sva_if.sv +++ b/hw/top_chip/ip_autogen/rstmgr/dv/sva/rstmgr_cascading_sva_if.sv @@ -161,14 +161,14 @@ interface rstmgr_cascading_sva_if ( // Controlled by rst_lc_src_n. `CASCADED_ASSERTS(CascadeLcToLcAon, rst_lc_src_n[rstmgr_pkg::DomainAonSel], resets_o.rst_lc_aon_n[rstmgr_pkg::DomainAonSel], SysCycles, clk_aon_i) - `CASCADED_ASSERTS(CascadeLcToLc, rst_lc_src_n[rstmgr_pkg::Domain0Sel], - resets_o.rst_lc_n[rstmgr_pkg::Domain0Sel], SysCycles, clk_main_i) + `CASCADED_ASSERTS(CascadeLcToLc, rst_lc_src_n[rstmgr_pkg::DomainMainSel], + resets_o.rst_lc_n[rstmgr_pkg::DomainMainSel], SysCycles, clk_main_i) // Controlled by rst_sys_src_n. - `CASCADED_ASSERTS(CascadeSysToSys, rst_sys_src_n[rstmgr_pkg::Domain0Sel], - resets_o.rst_sys_n[rstmgr_pkg::Domain0Sel], PeriCycles, clk_main_i) - `CASCADED_ASSERTS(CascadeLcToLcShadowed, rst_lc_src_n[rstmgr_pkg::Domain0Sel], - resets_o.rst_lc_shadowed_n[rstmgr_pkg::Domain0Sel], SysCycles, clk_main_i) + `CASCADED_ASSERTS(CascadeSysToSys, rst_sys_src_n[rstmgr_pkg::DomainMainSel], + resets_o.rst_sys_n[rstmgr_pkg::DomainMainSel], PeriCycles, clk_main_i) + `CASCADED_ASSERTS(CascadeLcToLcShadowed, rst_lc_src_n[rstmgr_pkg::DomainMainSel], + resets_o.rst_lc_shadowed_n[rstmgr_pkg::DomainMainSel], SysCycles, clk_main_i) `undef FALL_ASSERT `undef RISE_ASSERTS diff --git a/hw/top_chip/ip_autogen/rstmgr/dv/sva/rstmgr_rst_en_track_sva_if.sv b/hw/top_chip/ip_autogen/rstmgr/dv/sva/rstmgr_rst_en_track_sva_if.sv index 5fcd4e2be..e41eb3b67 100644 --- a/hw/top_chip/ip_autogen/rstmgr/dv/sva/rstmgr_rst_en_track_sva_if.sv +++ b/hw/top_chip/ip_autogen/rstmgr/dv/sva/rstmgr_rst_en_track_sva_if.sv @@ -13,19 +13,19 @@ interface rstmgr_rst_en_track_sva_if ( input logic rst_por_ni ); import rstmgr_pkg::DomainAonSel; - import rstmgr_pkg::Domain0Sel; + import rstmgr_pkg::DomainMainSel; localparam int DELAY = 1; - `ASSERT(D0RstPorAonEnTracksRstPorAonActive_A, - $fell(resets_i.rst_por_aon_n[Domain0Sel]) |-> ##[0:DELAY] - reset_en_i.por_aon[Domain0Sel] == prim_mubi_pkg::MuBi4True, + `ASSERT(DMainRstPorAonEnTracksRstPorAonActive_A, + $fell(resets_i.rst_por_aon_n[DomainMainSel]) |-> ##[0:DELAY] + reset_en_i.por_aon[DomainMainSel] == prim_mubi_pkg::MuBi4True, clk_aon_i, !rst_por_ni) - `ASSERT(D0RstPorAonEnTracksRstPorAonInactive_A, - $rose(resets_i.rst_por_aon_n[Domain0Sel]) |-> ##DELAY - !resets_i.rst_por_aon_n[Domain0Sel] || - reset_en_i.por_aon[Domain0Sel] == prim_mubi_pkg::MuBi4False, + `ASSERT(DMainRstPorAonEnTracksRstPorAonInactive_A, + $rose(resets_i.rst_por_aon_n[DomainMainSel]) |-> ##DELAY + !resets_i.rst_por_aon_n[DomainMainSel] || + reset_en_i.por_aon[DomainMainSel] == prim_mubi_pkg::MuBi4False, clk_aon_i, !rst_por_ni) @@ -68,68 +68,68 @@ interface rstmgr_rst_en_track_sva_if ( clk_io_i, !rst_por_ni) - `ASSERT(D0RstMainEnTracksRstMainActive_A, - $fell(resets_i.rst_main_n[Domain0Sel]) |-> ##[0:DELAY] - reset_en_i.main[Domain0Sel] == prim_mubi_pkg::MuBi4True, + `ASSERT(DMainRstMainEnTracksRstMainActive_A, + $fell(resets_i.rst_main_n[DomainMainSel]) |-> ##[0:DELAY] + reset_en_i.main[DomainMainSel] == prim_mubi_pkg::MuBi4True, clk_main_i, !rst_por_ni) - `ASSERT(D0RstMainEnTracksRstMainInactive_A, - $rose(resets_i.rst_main_n[Domain0Sel]) |-> ##DELAY - !resets_i.rst_main_n[Domain0Sel] || - reset_en_i.main[Domain0Sel] == prim_mubi_pkg::MuBi4False, + `ASSERT(DMainRstMainEnTracksRstMainInactive_A, + $rose(resets_i.rst_main_n[DomainMainSel]) |-> ##DELAY + !resets_i.rst_main_n[DomainMainSel] || + reset_en_i.main[DomainMainSel] == prim_mubi_pkg::MuBi4False, clk_main_i, !rst_por_ni) - `ASSERT(D0RstIoEnTracksRstIoActive_A, - $fell(resets_i.rst_io_n[Domain0Sel]) |-> ##[0:DELAY] - reset_en_i.io[Domain0Sel] == prim_mubi_pkg::MuBi4True, + `ASSERT(DMainRstIoEnTracksRstIoActive_A, + $fell(resets_i.rst_io_n[DomainMainSel]) |-> ##[0:DELAY] + reset_en_i.io[DomainMainSel] == prim_mubi_pkg::MuBi4True, clk_io_i, !rst_por_ni) - `ASSERT(D0RstIoEnTracksRstIoInactive_A, - $rose(resets_i.rst_io_n[Domain0Sel]) |-> ##DELAY - !resets_i.rst_io_n[Domain0Sel] || - reset_en_i.io[Domain0Sel] == prim_mubi_pkg::MuBi4False, + `ASSERT(DMainRstIoEnTracksRstIoInactive_A, + $rose(resets_i.rst_io_n[DomainMainSel]) |-> ##DELAY + !resets_i.rst_io_n[DomainMainSel] || + reset_en_i.io[DomainMainSel] == prim_mubi_pkg::MuBi4False, clk_io_i, !rst_por_ni) - `ASSERT(D0RstSpiDeviceEnTracksRstSpiDeviceActive_A, - $fell(resets_i.rst_spi_device_n[Domain0Sel]) |-> ##[0:DELAY] - reset_en_i.spi_device[Domain0Sel] == prim_mubi_pkg::MuBi4True, + `ASSERT(DMainRstSpiDeviceEnTracksRstSpiDeviceActive_A, + $fell(resets_i.rst_spi_device_n[DomainMainSel]) |-> ##[0:DELAY] + reset_en_i.spi_device[DomainMainSel] == prim_mubi_pkg::MuBi4True, clk_io_i, !rst_por_ni) - `ASSERT(D0RstSpiDeviceEnTracksRstSpiDeviceInactive_A, - $rose(resets_i.rst_spi_device_n[Domain0Sel]) |-> ##DELAY - !resets_i.rst_spi_device_n[Domain0Sel] || - reset_en_i.spi_device[Domain0Sel] == prim_mubi_pkg::MuBi4False, + `ASSERT(DMainRstSpiDeviceEnTracksRstSpiDeviceInactive_A, + $rose(resets_i.rst_spi_device_n[DomainMainSel]) |-> ##DELAY + !resets_i.rst_spi_device_n[DomainMainSel] || + reset_en_i.spi_device[DomainMainSel] == prim_mubi_pkg::MuBi4False, clk_io_i, !rst_por_ni) - `ASSERT(D0RstSpiHostEnTracksRstSpiHostActive_A, - $fell(resets_i.rst_spi_host_n[Domain0Sel]) |-> ##[0:DELAY] - reset_en_i.spi_host[Domain0Sel] == prim_mubi_pkg::MuBi4True, + `ASSERT(DMainRstSpiHostEnTracksRstSpiHostActive_A, + $fell(resets_i.rst_spi_host_n[DomainMainSel]) |-> ##[0:DELAY] + reset_en_i.spi_host[DomainMainSel] == prim_mubi_pkg::MuBi4True, clk_io_i, !rst_por_ni) - `ASSERT(D0RstSpiHostEnTracksRstSpiHostInactive_A, - $rose(resets_i.rst_spi_host_n[Domain0Sel]) |-> ##DELAY - !resets_i.rst_spi_host_n[Domain0Sel] || - reset_en_i.spi_host[Domain0Sel] == prim_mubi_pkg::MuBi4False, + `ASSERT(DMainRstSpiHostEnTracksRstSpiHostInactive_A, + $rose(resets_i.rst_spi_host_n[DomainMainSel]) |-> ##DELAY + !resets_i.rst_spi_host_n[DomainMainSel] || + reset_en_i.spi_host[DomainMainSel] == prim_mubi_pkg::MuBi4False, clk_io_i, !rst_por_ni) - `ASSERT(D0RstI2cEnTracksRstI2cActive_A, - $fell(resets_i.rst_i2c_n[Domain0Sel]) |-> ##[0:DELAY] - reset_en_i.i2c[Domain0Sel] == prim_mubi_pkg::MuBi4True, + `ASSERT(DMainRstI2cEnTracksRstI2cActive_A, + $fell(resets_i.rst_i2c_n[DomainMainSel]) |-> ##[0:DELAY] + reset_en_i.i2c[DomainMainSel] == prim_mubi_pkg::MuBi4True, clk_io_i, !rst_por_ni) - `ASSERT(D0RstI2cEnTracksRstI2cInactive_A, - $rose(resets_i.rst_i2c_n[Domain0Sel]) |-> ##DELAY - !resets_i.rst_i2c_n[Domain0Sel] || - reset_en_i.i2c[Domain0Sel] == prim_mubi_pkg::MuBi4False, + `ASSERT(DMainRstI2cEnTracksRstI2cInactive_A, + $rose(resets_i.rst_i2c_n[DomainMainSel]) |-> ##DELAY + !resets_i.rst_i2c_n[DomainMainSel] || + reset_en_i.i2c[DomainMainSel] == prim_mubi_pkg::MuBi4False, clk_io_i, !rst_por_ni) diff --git a/hw/top_chip/ip_autogen/rstmgr/dv/tb.sv b/hw/top_chip/ip_autogen/rstmgr/dv/tb.sv index 4112cc825..8ca92c45a 100644 --- a/hw/top_chip/ip_autogen/rstmgr/dv/tb.sv +++ b/hw/top_chip/ip_autogen/rstmgr/dv/tb.sv @@ -40,7 +40,7 @@ module tb; tl_if tl_if ( .clk, - .rst_n(rstmgr_if.resets_o.rst_lc_io_n[rstmgr_pkg::Domain0Sel]) + .rst_n(rstmgr_if.resets_o.rst_lc_io_n[rstmgr_pkg::DomainMainSel]) ); rstmgr_if rstmgr_if ( @@ -63,7 +63,7 @@ module tb; // This is consistent with rstmgr being the only source of resets. rstmgr dut ( .clk_i (clk), - .rst_ni (rstmgr_if.resets_o.rst_lc_io_n[rstmgr_pkg::Domain0Sel]), + .rst_ni (rstmgr_if.resets_o.rst_lc_io_n[rstmgr_pkg::DomainMainSel]), .clk_aon_i (clk_aon), .clk_io_i (clk_io), .clk_main_i (clk_main), @@ -118,7 +118,7 @@ module tb; // This may help any code that depends on clk_rst_vif.rst_n in the infrastructure: they won't // be able to change but at least the reset value will be true to the environment. clk_rst_if.drive_rst_n = 1'b0; - force clk_rst_if.rst_n = rstmgr_if.resets_o.rst_lc_io_n[rstmgr_pkg::Domain0Sel]; + force clk_rst_if.rst_n = rstmgr_if.resets_o.rst_lc_io_n[rstmgr_pkg::DomainMainSel]; end endmodule diff --git a/hw/top_chip/ip_autogen/rstmgr/rtl/rstmgr.sv b/hw/top_chip/ip_autogen/rstmgr/rtl/rstmgr.sv index f273be8b6..0dc3f6899 100644 --- a/hw/top_chip/ip_autogen/rstmgr/rtl/rstmgr.sv +++ b/hw/top_chip/ip_autogen/rstmgr/rtl/rstmgr.sv @@ -314,10 +314,10 @@ module rstmgr u_daon_por.gen_rst_chk.u_rst_chk.u_state_regs, alert_tx_o[0]) end - assign resets_o.rst_por_n[Domain0Sel] = '0; - assign cnsty_chk_errs[0][Domain0Sel] = '0; - assign fsm_errs[0][Domain0Sel] = '0; - assign rst_en_o.por[Domain0Sel] = MuBi4True; + assign resets_o.rst_por_n[DomainMainSel] = '0; + assign cnsty_chk_errs[0][DomainMainSel] = '0; + assign fsm_errs[0][DomainMainSel] = '0; + assign rst_en_o.por[DomainMainSel] = MuBi4True; assign shadow_cnsty_chk_errs[0] = '0; assign shadow_fsm_errs[0] = '0; @@ -348,15 +348,15 @@ module rstmgr u_daon_por_io.gen_rst_chk.u_rst_chk.u_state_regs, alert_tx_o[0]) end - assign resets_o.rst_por_io_n[Domain0Sel] = '0; - assign cnsty_chk_errs[1][Domain0Sel] = '0; - assign fsm_errs[1][Domain0Sel] = '0; - assign rst_en_o.por_io[Domain0Sel] = MuBi4True; + assign resets_o.rst_por_io_n[DomainMainSel] = '0; + assign cnsty_chk_errs[1][DomainMainSel] = '0; + assign fsm_errs[1][DomainMainSel] = '0; + assign rst_en_o.por_io[DomainMainSel] = MuBi4True; assign shadow_cnsty_chk_errs[1] = '0; assign shadow_fsm_errs[1] = '0; // Generating resets for main - // Power Domains: ['0'] + // Power Domains: ['Main'] // Shadowed: False assign resets_o.rst_main_n[DomainAonSel] = '0; assign cnsty_chk_errs[2][DomainAonSel] = '0; @@ -366,31 +366,31 @@ module rstmgr .SecCheck(SecCheck), .SecMaxSyncDelay(SecMaxSyncDelay), .SwRstReq(1'b0) - ) u_d0_main ( + ) u_dmain_main ( .clk_i, .rst_ni, .leaf_clk_i(clk_main_i), - .parent_rst_ni(rst_sys_src_n[Domain0Sel]), + .parent_rst_ni(rst_sys_src_n[DomainMainSel]), .sw_rst_req_ni(1'b1), .scan_rst_ni, .scanmode_i, - .rst_en_o(rst_en_o.main[Domain0Sel]), - .leaf_rst_o(resets_o.rst_main_n[Domain0Sel]), - .err_o(cnsty_chk_errs[2][Domain0Sel]), - .fsm_err_o(fsm_errs[2][Domain0Sel]) + .rst_en_o(rst_en_o.main[DomainMainSel]), + .leaf_rst_o(resets_o.rst_main_n[DomainMainSel]), + .err_o(cnsty_chk_errs[2][DomainMainSel]), + .fsm_err_o(fsm_errs[2][DomainMainSel]) ); - if (SecCheck) begin : gen_d0_main_assert + if (SecCheck) begin : gen_dmain_main_assert `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT( - D0MainFsmCheck_A, - u_d0_main.gen_rst_chk.u_rst_chk.u_state_regs, + DMainMainFsmCheck_A, + u_dmain_main.gen_rst_chk.u_rst_chk.u_state_regs, alert_tx_o[0]) end assign shadow_cnsty_chk_errs[2] = '0; assign shadow_fsm_errs[2] = '0; // Generating resets for io - // Power Domains: ['0'] + // Power Domains: ['Main'] // Shadowed: False assign resets_o.rst_io_n[DomainAonSel] = '0; assign cnsty_chk_errs[3][DomainAonSel] = '0; @@ -400,31 +400,31 @@ module rstmgr .SecCheck(SecCheck), .SecMaxSyncDelay(SecMaxSyncDelay), .SwRstReq(1'b0) - ) u_d0_io ( + ) u_dmain_io ( .clk_i, .rst_ni, .leaf_clk_i(clk_io_i), - .parent_rst_ni(rst_sys_src_n[Domain0Sel]), + .parent_rst_ni(rst_sys_src_n[DomainMainSel]), .sw_rst_req_ni(1'b1), .scan_rst_ni, .scanmode_i, - .rst_en_o(rst_en_o.io[Domain0Sel]), - .leaf_rst_o(resets_o.rst_io_n[Domain0Sel]), - .err_o(cnsty_chk_errs[3][Domain0Sel]), - .fsm_err_o(fsm_errs[3][Domain0Sel]) + .rst_en_o(rst_en_o.io[DomainMainSel]), + .leaf_rst_o(resets_o.rst_io_n[DomainMainSel]), + .err_o(cnsty_chk_errs[3][DomainMainSel]), + .fsm_err_o(fsm_errs[3][DomainMainSel]) ); - if (SecCheck) begin : gen_d0_io_assert + if (SecCheck) begin : gen_dmain_io_assert `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT( - D0IoFsmCheck_A, - u_d0_io.gen_rst_chk.u_rst_chk.u_state_regs, + DMainIoFsmCheck_A, + u_dmain_io.gen_rst_chk.u_rst_chk.u_state_regs, alert_tx_o[0]) end assign shadow_cnsty_chk_errs[3] = '0; assign shadow_fsm_errs[3] = '0; // Generating resets for spi_device - // Power Domains: ['0'] + // Power Domains: ['Main'] // Shadowed: False assign resets_o.rst_spi_device_n[DomainAonSel] = '0; assign cnsty_chk_errs[4][DomainAonSel] = '0; @@ -434,31 +434,31 @@ module rstmgr .SecCheck(SecCheck), .SecMaxSyncDelay(SecMaxSyncDelay), .SwRstReq(1'b1) - ) u_d0_spi_device ( + ) u_dmain_spi_device ( .clk_i, .rst_ni, .leaf_clk_i(clk_io_i), - .parent_rst_ni(rst_sys_src_n[Domain0Sel]), + .parent_rst_ni(rst_sys_src_n[DomainMainSel]), .sw_rst_req_ni(reg2hw.sw_rst_ctrl_n[SPI_DEVICE].q), .scan_rst_ni, .scanmode_i, - .rst_en_o(rst_en_o.spi_device[Domain0Sel]), - .leaf_rst_o(resets_o.rst_spi_device_n[Domain0Sel]), - .err_o(cnsty_chk_errs[4][Domain0Sel]), - .fsm_err_o(fsm_errs[4][Domain0Sel]) + .rst_en_o(rst_en_o.spi_device[DomainMainSel]), + .leaf_rst_o(resets_o.rst_spi_device_n[DomainMainSel]), + .err_o(cnsty_chk_errs[4][DomainMainSel]), + .fsm_err_o(fsm_errs[4][DomainMainSel]) ); - if (SecCheck) begin : gen_d0_spi_device_assert + if (SecCheck) begin : gen_dmain_spi_device_assert `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT( - D0SpiDeviceFsmCheck_A, - u_d0_spi_device.gen_rst_chk.u_rst_chk.u_state_regs, + DMainSpiDeviceFsmCheck_A, + u_dmain_spi_device.gen_rst_chk.u_rst_chk.u_state_regs, alert_tx_o[0]) end assign shadow_cnsty_chk_errs[4] = '0; assign shadow_fsm_errs[4] = '0; // Generating resets for spi_host - // Power Domains: ['0'] + // Power Domains: ['Main'] // Shadowed: False assign resets_o.rst_spi_host_n[DomainAonSel] = '0; assign cnsty_chk_errs[5][DomainAonSel] = '0; @@ -468,31 +468,31 @@ module rstmgr .SecCheck(SecCheck), .SecMaxSyncDelay(SecMaxSyncDelay), .SwRstReq(1'b1) - ) u_d0_spi_host ( + ) u_dmain_spi_host ( .clk_i, .rst_ni, .leaf_clk_i(clk_io_i), - .parent_rst_ni(rst_sys_src_n[Domain0Sel]), + .parent_rst_ni(rst_sys_src_n[DomainMainSel]), .sw_rst_req_ni(reg2hw.sw_rst_ctrl_n[SPI_HOST].q), .scan_rst_ni, .scanmode_i, - .rst_en_o(rst_en_o.spi_host[Domain0Sel]), - .leaf_rst_o(resets_o.rst_spi_host_n[Domain0Sel]), - .err_o(cnsty_chk_errs[5][Domain0Sel]), - .fsm_err_o(fsm_errs[5][Domain0Sel]) + .rst_en_o(rst_en_o.spi_host[DomainMainSel]), + .leaf_rst_o(resets_o.rst_spi_host_n[DomainMainSel]), + .err_o(cnsty_chk_errs[5][DomainMainSel]), + .fsm_err_o(fsm_errs[5][DomainMainSel]) ); - if (SecCheck) begin : gen_d0_spi_host_assert + if (SecCheck) begin : gen_dmain_spi_host_assert `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT( - D0SpiHostFsmCheck_A, - u_d0_spi_host.gen_rst_chk.u_rst_chk.u_state_regs, + DMainSpiHostFsmCheck_A, + u_dmain_spi_host.gen_rst_chk.u_rst_chk.u_state_regs, alert_tx_o[0]) end assign shadow_cnsty_chk_errs[5] = '0; assign shadow_fsm_errs[5] = '0; // Generating resets for i2c - // Power Domains: ['0'] + // Power Domains: ['Main'] // Shadowed: False assign resets_o.rst_i2c_n[DomainAonSel] = '0; assign cnsty_chk_errs[6][DomainAonSel] = '0; @@ -502,24 +502,24 @@ module rstmgr .SecCheck(SecCheck), .SecMaxSyncDelay(SecMaxSyncDelay), .SwRstReq(1'b1) - ) u_d0_i2c ( + ) u_dmain_i2c ( .clk_i, .rst_ni, .leaf_clk_i(clk_io_i), - .parent_rst_ni(rst_sys_src_n[Domain0Sel]), + .parent_rst_ni(rst_sys_src_n[DomainMainSel]), .sw_rst_req_ni(reg2hw.sw_rst_ctrl_n[I2C].q), .scan_rst_ni, .scanmode_i, - .rst_en_o(rst_en_o.i2c[Domain0Sel]), - .leaf_rst_o(resets_o.rst_i2c_n[Domain0Sel]), - .err_o(cnsty_chk_errs[6][Domain0Sel]), - .fsm_err_o(fsm_errs[6][Domain0Sel]) + .rst_en_o(rst_en_o.i2c[DomainMainSel]), + .leaf_rst_o(resets_o.rst_i2c_n[DomainMainSel]), + .err_o(cnsty_chk_errs[6][DomainMainSel]), + .fsm_err_o(fsm_errs[6][DomainMainSel]) ); - if (SecCheck) begin : gen_d0_i2c_assert + if (SecCheck) begin : gen_dmain_i2c_assert `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT( - D0I2cFsmCheck_A, - u_d0_i2c.gen_rst_chk.u_rst_chk.u_state_regs, + DMainI2cFsmCheck_A, + u_dmain_i2c.gen_rst_chk.u_rst_chk.u_state_regs, alert_tx_o[0]) end assign shadow_cnsty_chk_errs[6] = '0; diff --git a/hw/top_chip/ip_autogen/rstmgr/rtl/rstmgr_ctrl.sv b/hw/top_chip/ip_autogen/rstmgr/rtl/rstmgr_ctrl.sv index a762ec828..dbb26a440 100644 --- a/hw/top_chip/ip_autogen/rstmgr/rtl/rstmgr_ctrl.sv +++ b/hw/top_chip/ip_autogen/rstmgr/rtl/rstmgr_ctrl.sv @@ -49,7 +49,7 @@ module rstmgr_ctrl // the non-always-on domains // These reset whenever the always on domain reset, to ensure power definition consistency. // By extension, they also reset whenever the root (rst_ni) resets - assign rst_pd_nd = ~rst_req_i[Domain0Sel +: OffDomains]; + assign rst_pd_nd = ~rst_req_i[DomainMainSel +: OffDomains]; localparam int DomainPdStartIdx = DomainAonSel + 1; for(genvar i = 0; i < OffDomains; i++) begin : gen_rst_pd_n diff --git a/hw/top_chip/ip_autogen/rstmgr/rtl/rstmgr_pkg.sv b/hw/top_chip/ip_autogen/rstmgr/rtl/rstmgr_pkg.sv index 1cf8d262e..1cce9f8e5 100644 --- a/hw/top_chip/ip_autogen/rstmgr/rtl/rstmgr_pkg.sv +++ b/hw/top_chip/ip_autogen/rstmgr/rtl/rstmgr_pkg.sv @@ -8,7 +8,7 @@ package rstmgr_pkg; // Power domain parameters parameter int PowerDomains = 2; parameter int DomainAonSel = 0; - parameter int Domain0Sel = 1; + parameter int DomainMainSel = 1; // Number of non-always-on domains parameter int OffDomains = PowerDomains-1; diff --git a/hw/top_chip/ip_autogen/rv_plic/fpv/vip/rv_plic_assert_fpv.sv b/hw/top_chip/ip_autogen/rv_plic/fpv/vip/rv_plic_assert_fpv.sv index febfb4d8e..32477603a 100644 --- a/hw/top_chip/ip_autogen/rv_plic/fpv/vip/rv_plic_assert_fpv.sv +++ b/hw/top_chip/ip_autogen/rv_plic/fpv/vip/rv_plic_assert_fpv.sv @@ -119,4 +119,14 @@ module rv_plic_assert_fpv #(parameter int NumSrc = 1, // When fatal alert happens then only reset can clear it. `ASSERT(FatalAlertNeverdrops_A, ##1 !$fell(fatal_alert_i)) + + // The interrupt gateway in u_gateway is in charge of making sure that the "set; claim; complete" + // flow is followed for each interrupt line. This is done with an ia ("interrupt active") signal. + // When interrupt i is asserted, both ip[i] and ia[i] are set. When it is claimed, ip[i] gets + // cleared (but ia[i] stays high). Subsequent assertions are ignored until the processor marks the + // handling complete, which clears ia[i] again. + // + // As such, ia[i] should always be true when ip[i] is true. + `ASSERT(ActiveIfPending_A, u_gateway.ia | ~u_gateway.ip_o) + endmodule : rv_plic_assert_fpv diff --git a/hw/top_chip/ip_autogen/rv_plic/rtl/rv_plic.sv b/hw/top_chip/ip_autogen/rv_plic/rtl/rv_plic.sv index 433413be3..89a98716e 100644 --- a/hw/top_chip/ip_autogen/rv_plic/rtl/rv_plic.sv +++ b/hw/top_chip/ip_autogen/rv_plic/rtl/rv_plic.sv @@ -93,10 +93,6 @@ module rv_plic import rv_plic_reg_pkg::*; #( //`ASSERT_PULSE(claimPulse, claim_re[i]) //`ASSERT_PULSE(completePulse, complete_we[i]) - `ASSERT(onehot0Claim, $onehot0(claim_re)) - - `ASSERT(onehot0Complete, $onehot0(complete_we)) - ////////////// // Priority // ////////////// diff --git a/hw/top_chip/ip_autogen/rv_plic/rtl/rv_plic_gateway.sv b/hw/top_chip/ip_autogen/rv_plic/rtl/rv_plic_gateway.sv index b6e158004..a30293aee 100644 --- a/hw/top_chip/ip_autogen/rv_plic/rtl/rv_plic_gateway.sv +++ b/hw/top_chip/ip_autogen/rv_plic/rtl/rv_plic_gateway.sv @@ -10,15 +10,59 @@ module rv_plic_gateway #( input clk_i, input rst_ni, + // Incoming interrupt requests from the interrupt sources. input [N_SOURCE-1:0] src_i, - input [N_SOURCE-1:0] le_i, // Level0 Edge1 - input [N_SOURCE-1:0] claim_i, // $onehot0(claim_i) - input [N_SOURCE-1:0] complete_i, // $onehot0(complete_i) + // Control whether each interrupt is level or edge triggered. It is considered level triggered if + // its bit of le_i is zero and edge triggered if the bit is 1. + input [N_SOURCE-1:0] le_i, + // Interrupts being claimed by a target. This should be onehot0 (so only one interrupt can be + // claimed at once). + input [N_SOURCE-1:0] claim_i, + + // Interrupts being marked complete by a target. This should be onehot0 (so only one interrupt can + // be claimed at once). It has no effect on an interrupt that has not already been claimed. + input [N_SOURCE-1:0] complete_i, + + // The "interrupt pending" flag. If a bit of ip_o is true, the target should be notified that the + // interrupt needs handling. output logic [N_SOURCE-1:0] ip_o ); + // The flow for an interrupt is described in "RISC-V Platform-Level Interrupt Controller + // Specification" (v1.0.0) in section 1.5. + // + // 1. An interrupt starts neither active nor pending (so the relevant bits of ia and ip_o are + // zero). + // + // 2. The interrupt source asserts interrupt k by setting src_i[k]. If le_i requests edge + // triggering, the gateway only recognises an interrupt with a posedge on src_i. + // + // 3. The gateway sets ip_o[k] to tell the target that interrupt k is pending. + // + // 4. The target claims the interrupt, which appears as claim_i[k] being true. + // + // 5. The gateway clears ip_o[k], but remembers that the interrupt is being handled. As such, + // further changes in src_i will not cause a new (overlapping) interrupt. + // + // 6. The target finishes handling the interrupt and sets complete_i[k]. + // + // 7. The gateway will now allow changes in src_i to cause the interrupt to become pending + // again. + // + // This is translated into hardware signals as follows: + // + // - The interrupt assertion in src_i is detected with the "set" signal. This includes posedge + // detection if le_i is true for the interrupt. + // + // - Once interrupt k is asserted, it is marked pending in ip_o[k]. It is also marked "active" + // (which implies the target hasn't yet got as far as completion) by setting ia[k]. + // + // - When the target claims the interrupt, ip_o[k] is cleared, but ia[k] stays high. + // + // - Finally, when the target completes the interrupt, ia[k] is cleared. + logic [N_SOURCE-1:0] ia; // Interrupt Active // The set[i] signal says that interrupt i is being requested. If the interrupt is level triggered @@ -35,28 +79,32 @@ module rv_plic_gateway #( assign set = src_i & ~(src_q & le_i); - // Interrupt pending is set by source (depends on le_i), cleared by claim_i. - // Until interrupt is claimed, set doesn't affect ip_o. - // RISC-V PLIC spec mentioned it can have counter for edge triggered - // But skipped the feature as counter consumes substantial logic size. + // The interrupt pending signal for interrupt k stays true until it is claimed (claim_i[k]). It is + // newly asserted if the interrupt is interrupt asserted (src_i[k]) (restricted to positive edges + // if le_i[k] is true) when the interrupt isn't already active (~ia[k]). always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin ip_o <= '0; end else begin - ip_o <= (ip_o | (set & ~ia & ~ip_o)) & (~(ip_o & claim_i)); + ip_o <= (ip_o & ~claim_i) | (set & ~ia); end end - // Interrupt active is to control ip_o. If ip_o is set then until completed - // by target, ip_o shouldn't be set by source even claim_i can clear ip_o. - // ia can be cleared only when ia was set. If `set` and `complete_i` happen - // at the same time, always `set` wins. + // The Interrupt Active signal is high for interrupts that are active. Interrupt k becomes active + // (so ia[k] is true) if the interrupt is asserted when it is not already active. An active + // interrupt is initially pending (ip_o[k] is high) and stops being pending when claimed by the + // target setting claim_i[k]. After the interrupt has been claimed, it is marked inactive when the + // target signals completion (by setting complete_i[k]). always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin ia <= '0; end else begin - ia <= (ia | (set & ~ia)) & (~(ia & complete_i & ~ip_o)); + ia <= (~ia & set) | (ia & ~(complete_i & ~ip_o)); end end + // Check the claim_i and complete_i input ports are being driven with onehot0 values. + `ASSERT(ClaimOneHot0_A, $onehot0(claim_i)) + `ASSERT(CompleteOneHot0_A, $onehot0(complete_i)) + endmodule