|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  | // | 
|  | // Pinmux toplevel. | 
|  | // | 
|  |  | 
|  | `include "prim_assert.sv" | 
|  |  | 
|  | module pinmux | 
|  | import pinmux_pkg::*; | 
|  | import pinmux_reg_pkg::*; | 
|  | import prim_pad_wrapper_pkg::*; | 
|  | #( | 
|  | // Taget-specific pinmux configuration passed down from the | 
|  | // target-specific top-level. | 
|  | parameter target_cfg_t TargetCfg = DefaultTargetCfg, | 
|  | parameter logic [NumAlerts-1:0] AlertAsyncOn = {NumAlerts{1'b1}} | 
|  | ) ( | 
|  | input                            clk_i, | 
|  | input                            rst_ni, | 
|  | input                            rst_sys_ni, | 
|  | // Scan enable | 
|  | input  prim_mubi_pkg::mubi4_t    scanmode_i, | 
|  | // Slow always-on clock | 
|  | input                            clk_aon_i, | 
|  | input                            rst_aon_ni, | 
|  | // Wakeup request, running on clk_aon_i | 
|  | output logic                     pin_wkup_req_o, | 
|  | output logic                     usb_wkup_req_o, | 
|  | // Sleep enable and strap sample enable | 
|  | // from pwrmgr, running on clk_i | 
|  | input                            sleep_en_i, | 
|  | input                            strap_en_i, | 
|  | // LC signals for TAP qualification | 
|  | input  lc_ctrl_pkg::lc_tx_t      lc_dft_en_i, | 
|  | input  lc_ctrl_pkg::lc_tx_t      lc_hw_debug_en_i, | 
|  | input  lc_ctrl_pkg::lc_tx_t      lc_check_byp_en_i, | 
|  | input  lc_ctrl_pkg::lc_tx_t      lc_escalate_en_i, | 
|  | output lc_ctrl_pkg::lc_tx_t      pinmux_hw_debug_en_o, | 
|  | // Sampled values for DFT straps | 
|  | output dft_strap_test_req_t      dft_strap_test_o, | 
|  | // DFT indication to stop tap strap sampling | 
|  | input                            dft_hold_tap_sel_i, | 
|  | // Qualified JTAG signals for TAPs | 
|  | output jtag_pkg::jtag_req_t      lc_jtag_o, | 
|  | input  jtag_pkg::jtag_rsp_t      lc_jtag_i, | 
|  | output jtag_pkg::jtag_req_t      rv_jtag_o, | 
|  | input  jtag_pkg::jtag_rsp_t      rv_jtag_i, | 
|  | output jtag_pkg::jtag_req_t      dft_jtag_o, | 
|  | input  jtag_pkg::jtag_rsp_t      dft_jtag_i, | 
|  | // Direct USB connection | 
|  | input                            usbdev_dppullup_en_i, | 
|  | input                            usbdev_dnpullup_en_i, | 
|  | output                           usb_dppullup_en_o, | 
|  | output                           usb_dnpullup_en_o, | 
|  | input                            usbdev_suspend_req_i, | 
|  | input                            usbdev_wake_ack_i, | 
|  | output                           usbdev_bus_reset_o, | 
|  | output                           usbdev_sense_lost_o, | 
|  | output                           usbdev_wake_detect_active_o, | 
|  | // Bus Interface (device) | 
|  | input  tlul_pkg::tl_h2d_t        tl_i, | 
|  | output tlul_pkg::tl_d2h_t        tl_o, | 
|  | // Alerts | 
|  | input  prim_alert_pkg::alert_rx_t [NumAlerts-1:0] alert_rx_i, | 
|  | output prim_alert_pkg::alert_tx_t [NumAlerts-1:0] alert_tx_o, | 
|  | // Muxed Peripheral side | 
|  | input        [NMioPeriphOut-1:0] periph_to_mio_i, | 
|  | input        [NMioPeriphOut-1:0] periph_to_mio_oe_i, | 
|  | output logic [NMioPeriphIn-1:0]  mio_to_periph_o, | 
|  | // Dedicated Peripheral side | 
|  | input        [NDioPads-1:0]      periph_to_dio_i, | 
|  | input        [NDioPads-1:0]      periph_to_dio_oe_i, | 
|  | output logic [NDioPads-1:0]      dio_to_periph_o, | 
|  | // Pad side | 
|  | // MIOs | 
|  | output prim_pad_wrapper_pkg::pad_attr_t [NMioPads-1:0] mio_attr_o, | 
|  | output logic                            [NMioPads-1:0] mio_out_o, | 
|  | output logic                            [NMioPads-1:0] mio_oe_o, | 
|  | input                                   [NMioPads-1:0] mio_in_i, | 
|  | // DIOs | 
|  | output prim_pad_wrapper_pkg::pad_attr_t [NDioPads-1:0] dio_attr_o, | 
|  | output logic                            [NDioPads-1:0] dio_out_o, | 
|  | output logic                            [NDioPads-1:0] dio_oe_o, | 
|  | input                                   [NDioPads-1:0] dio_in_i | 
|  | ); | 
|  |  | 
|  | ////////////////////////////////// | 
|  | // Regfile Breakout and Mapping // | 
|  | ////////////////////////////////// | 
|  |  | 
|  | logic [NumAlerts-1:0] alert_test, alerts; | 
|  | pinmux_reg2hw_t reg2hw; | 
|  | pinmux_hw2reg_t hw2reg; | 
|  |  | 
|  | pinmux_reg_top u_reg ( | 
|  | .clk_i, | 
|  | .rst_ni, | 
|  | .clk_aon_i, | 
|  | .rst_aon_ni, | 
|  | .tl_i, | 
|  | .tl_o, | 
|  | .reg2hw, | 
|  | .hw2reg, | 
|  | // SEC_CM: BUS.INTEGRITY | 
|  | .intg_err_o(alerts[0]), | 
|  | .devmode_i(1'b1) | 
|  | ); | 
|  |  | 
|  | //////////// | 
|  | // Alerts // | 
|  | //////////// | 
|  |  | 
|  | assign alert_test = { | 
|  | reg2hw.alert_test.q & | 
|  | reg2hw.alert_test.qe | 
|  | }; | 
|  |  | 
|  | for (genvar i = 0; i < NumAlerts; i++) begin : gen_alert_tx | 
|  | prim_alert_sender #( | 
|  | .AsyncOn(AlertAsyncOn[i]), | 
|  | .IsFatal(1'b1) | 
|  | ) u_prim_alert_sender ( | 
|  | .clk_i, | 
|  | .rst_ni, | 
|  | .alert_test_i  ( alert_test[i] ), | 
|  | .alert_req_i   ( alerts[0]     ), | 
|  | .alert_ack_o   (               ), | 
|  | .alert_state_o (               ), | 
|  | .alert_rx_i    ( alert_rx_i[i] ), | 
|  | .alert_tx_o    ( alert_tx_o[i] ) | 
|  | ); | 
|  | end | 
|  |  | 
|  | ///////////////////////////// | 
|  | // Pad attribute registers // | 
|  | ///////////////////////////// | 
|  |  | 
|  | prim_pad_wrapper_pkg::pad_attr_t [NDioPads-1:0] dio_pad_attr_q; | 
|  | prim_pad_wrapper_pkg::pad_attr_t [NMioPads-1:0] mio_pad_attr_q; | 
|  |  | 
|  | always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs | 
|  | if (!rst_ni) begin | 
|  | dio_pad_attr_q <= '0; | 
|  | mio_pad_attr_q <= '0; | 
|  | end else begin | 
|  | // dedicated pads | 
|  | for (int kk = 0; kk < NDioPads; kk++) begin | 
|  | if (reg2hw.dio_pad_attr[kk].drive_strength.qe) begin | 
|  | dio_pad_attr_q[kk].drive_strength <= reg2hw.dio_pad_attr[kk].drive_strength.q; | 
|  | end | 
|  | if (reg2hw.dio_pad_attr[kk].slew_rate.qe) begin | 
|  | dio_pad_attr_q[kk].slew_rate      <= reg2hw.dio_pad_attr[kk].slew_rate.q; | 
|  | end | 
|  | if (reg2hw.dio_pad_attr[kk].od_en.qe) begin | 
|  | dio_pad_attr_q[kk].od_en          <= reg2hw.dio_pad_attr[kk].od_en.q; | 
|  | end | 
|  | if (reg2hw.dio_pad_attr[kk].schmitt_en.qe) begin | 
|  | dio_pad_attr_q[kk].schmitt_en     <= reg2hw.dio_pad_attr[kk].schmitt_en.q; | 
|  | end | 
|  | if (reg2hw.dio_pad_attr[kk].keeper_en.qe) begin | 
|  | dio_pad_attr_q[kk].keep_en        <= reg2hw.dio_pad_attr[kk].keeper_en.q; | 
|  | end | 
|  | if (reg2hw.dio_pad_attr[kk].pull_select.qe) begin | 
|  | dio_pad_attr_q[kk].pull_select    <= reg2hw.dio_pad_attr[kk].pull_select.q; | 
|  | end | 
|  | if (reg2hw.dio_pad_attr[kk].pull_en.qe) begin | 
|  | dio_pad_attr_q[kk].pull_en        <= reg2hw.dio_pad_attr[kk].pull_en.q; | 
|  | end | 
|  | if (reg2hw.dio_pad_attr[kk].virtual_od_en.qe) begin | 
|  | dio_pad_attr_q[kk].virt_od_en     <= reg2hw.dio_pad_attr[kk].virtual_od_en.q; | 
|  | end | 
|  | if (reg2hw.dio_pad_attr[kk].invert.qe) begin | 
|  | dio_pad_attr_q[kk].invert         <= reg2hw.dio_pad_attr[kk].invert.q; | 
|  | end | 
|  | end | 
|  | // muxed pads | 
|  | for (int kk = 0; kk < NMioPads; kk++) begin | 
|  | if (reg2hw.mio_pad_attr[kk].drive_strength.qe) begin | 
|  | mio_pad_attr_q[kk].drive_strength <= reg2hw.mio_pad_attr[kk].drive_strength.q; | 
|  | end | 
|  | if (reg2hw.mio_pad_attr[kk].slew_rate.qe) begin | 
|  | mio_pad_attr_q[kk].slew_rate      <= reg2hw.mio_pad_attr[kk].slew_rate.q; | 
|  | end | 
|  | if (reg2hw.mio_pad_attr[kk].od_en.qe) begin | 
|  | mio_pad_attr_q[kk].od_en          <= reg2hw.mio_pad_attr[kk].od_en.q; | 
|  | end | 
|  | if (reg2hw.mio_pad_attr[kk].schmitt_en.qe) begin | 
|  | mio_pad_attr_q[kk].schmitt_en     <= reg2hw.mio_pad_attr[kk].schmitt_en.q; | 
|  | end | 
|  | if (reg2hw.mio_pad_attr[kk].keeper_en.qe) begin | 
|  | mio_pad_attr_q[kk].keep_en        <= reg2hw.mio_pad_attr[kk].keeper_en.q; | 
|  | end | 
|  | if (reg2hw.mio_pad_attr[kk].pull_select.qe) begin | 
|  | mio_pad_attr_q[kk].pull_select    <= reg2hw.mio_pad_attr[kk].pull_select.q; | 
|  | end | 
|  | if (reg2hw.mio_pad_attr[kk].pull_en.qe) begin | 
|  | mio_pad_attr_q[kk].pull_en        <= reg2hw.mio_pad_attr[kk].pull_en.q; | 
|  | end | 
|  | if (reg2hw.mio_pad_attr[kk].virtual_od_en.qe) begin | 
|  | mio_pad_attr_q[kk].virt_od_en     <= reg2hw.mio_pad_attr[kk].virtual_od_en.q; | 
|  | end | 
|  | if (reg2hw.mio_pad_attr[kk].invert.qe) begin | 
|  | mio_pad_attr_q[kk].invert         <= reg2hw.mio_pad_attr[kk].invert.q; | 
|  | end | 
|  | end | 
|  | end | 
|  | end | 
|  |  | 
|  | //////////////////////// | 
|  | // Connect attributes // | 
|  | //////////////////////// | 
|  |  | 
|  | pad_attr_t [NDioPads-1:0] dio_attr; | 
|  | for (genvar k = 0; k < NDioPads; k++) begin : gen_dio_attr | 
|  | pad_attr_t warl_mask; | 
|  |  | 
|  | prim_pad_attr #( | 
|  | .PadType(TargetCfg.dio_pad_type[k]) | 
|  | ) u_prim_pad_attr ( | 
|  | .attr_warl_o(warl_mask) | 
|  | ); | 
|  |  | 
|  | assign dio_attr[k]                             = dio_pad_attr_q[k] & warl_mask; | 
|  | assign hw2reg.dio_pad_attr[k].drive_strength.d = dio_attr[k].drive_strength; | 
|  | assign hw2reg.dio_pad_attr[k].slew_rate.d      = dio_attr[k].slew_rate; | 
|  | assign hw2reg.dio_pad_attr[k].od_en.d          = dio_attr[k].od_en; | 
|  | assign hw2reg.dio_pad_attr[k].schmitt_en.d     = dio_attr[k].schmitt_en; | 
|  | assign hw2reg.dio_pad_attr[k].keeper_en.d      = dio_attr[k].keep_en; | 
|  | assign hw2reg.dio_pad_attr[k].pull_select.d    = dio_attr[k].pull_select; | 
|  | assign hw2reg.dio_pad_attr[k].pull_en.d        = dio_attr[k].pull_en; | 
|  | assign hw2reg.dio_pad_attr[k].virtual_od_en.d  = dio_attr[k].virt_od_en; | 
|  | assign hw2reg.dio_pad_attr[k].invert.d         = dio_attr[k].invert; | 
|  | end | 
|  |  | 
|  | pad_attr_t [NMioPads-1:0] mio_attr; | 
|  | for (genvar k = 0; k < NMioPads; k++) begin : gen_mio_attr | 
|  | pad_attr_t warl_mask; | 
|  |  | 
|  | prim_pad_attr #( | 
|  | .PadType(TargetCfg.mio_pad_type[k]) | 
|  | ) u_prim_pad_attr ( | 
|  | .attr_warl_o(warl_mask) | 
|  | ); | 
|  |  | 
|  | assign mio_attr[k]                             = mio_pad_attr_q[k] & warl_mask; | 
|  | assign hw2reg.mio_pad_attr[k].drive_strength.d = mio_attr[k].drive_strength; | 
|  | assign hw2reg.mio_pad_attr[k].slew_rate.d      = mio_attr[k].slew_rate; | 
|  | assign hw2reg.mio_pad_attr[k].od_en.d          = mio_attr[k].od_en; | 
|  | assign hw2reg.mio_pad_attr[k].schmitt_en.d     = mio_attr[k].schmitt_en; | 
|  | assign hw2reg.mio_pad_attr[k].keeper_en.d      = mio_attr[k].keep_en; | 
|  | assign hw2reg.mio_pad_attr[k].pull_select.d    = mio_attr[k].pull_select; | 
|  | assign hw2reg.mio_pad_attr[k].pull_en.d        = mio_attr[k].pull_en; | 
|  | assign hw2reg.mio_pad_attr[k].virtual_od_en.d  = mio_attr[k].virt_od_en; | 
|  | assign hw2reg.mio_pad_attr[k].invert.d         = mio_attr[k].invert; | 
|  | end | 
|  |  | 
|  |  | 
|  | ////////////////////////// | 
|  | // Strap Sampling Logic // | 
|  | ////////////////////////// | 
|  |  | 
|  | // Local versions of the input signals | 
|  | logic [NMioPads-1:0] mio_out, mio_oe, mio_in; | 
|  | logic [NDioPads-1:0] dio_out, dio_oe, dio_in; | 
|  |  | 
|  | // This module contains the strap sampling and JTAG mux. | 
|  | // Affected inputs are intercepted/tapped before they go to the pinmux | 
|  | // matrix. Likewise, affected outputs are intercepted/tapped after the | 
|  | // retention registers. | 
|  | pinmux_strap_sampling #( | 
|  | .TargetCfg (TargetCfg) | 
|  | ) u_pinmux_strap_sampling ( | 
|  | .clk_i, | 
|  | // Inside the pinmux, the strap sampling module is the only module using SYS_RST. The reason for | 
|  | // that is that SYS_RST reset will not be asserted during a NDM reset from the RV_DM and hence | 
|  | // it retains some of the TAP selection state during an active debug session where NDM reset | 
|  | // is triggered. To that end, the strap sampling module latches the lc_hw_debug_en_i signal | 
|  | // whenever strap_en_i is asserted. Note that this does not affect the DFT TAP selection, since | 
|  | // we always consume the live lc_dft_en_i signal. | 
|  | .rst_ni (rst_sys_ni), | 
|  | .scanmode_i, | 
|  | // To padring side | 
|  | .out_padring_o  ( {dio_out_o,  mio_out_o}  ), | 
|  | .oe_padring_o   ( {dio_oe_o ,  mio_oe_o }  ), | 
|  | .in_padring_i   ( {dio_in_i ,  mio_in_i }  ), | 
|  | .attr_padring_o ( {dio_attr_o, mio_attr_o} ), | 
|  | // To core side | 
|  | .out_core_i     ( {dio_out,  mio_out}  ), | 
|  | .oe_core_i      ( {dio_oe,   mio_oe}   ), | 
|  | .in_core_o      ( {dio_in,   mio_in}   ), | 
|  | .attr_core_i    ( {dio_attr, mio_attr} ), | 
|  | // Strap and JTAG signals | 
|  | .strap_en_i, | 
|  | .lc_dft_en_i, | 
|  | .lc_hw_debug_en_i, | 
|  | .lc_escalate_en_i, | 
|  | .lc_check_byp_en_i, | 
|  | // This is the latched version of lc_hw_debug_en_i. We use it exclusively to gate the JTAG | 
|  | // signals and TAP side of the RV_DM so that RV_DM can remain live during an NDM reset cycle. | 
|  | .pinmux_hw_debug_en_o, | 
|  | .dft_strap_test_o, | 
|  | .dft_hold_tap_sel_i, | 
|  | .lc_jtag_o, | 
|  | .lc_jtag_i, | 
|  | .rv_jtag_o, | 
|  | .rv_jtag_i, | 
|  | .dft_jtag_o, | 
|  | .dft_jtag_i | 
|  | ); | 
|  |  | 
|  | /////////////////////////////////////// | 
|  | // USB wake detect module connection // | 
|  | /////////////////////////////////////// | 
|  |  | 
|  | // Dedicated Peripheral side | 
|  | usbdev_aon_wake u_usbdev_aon_wake ( | 
|  | .clk_aon_i, | 
|  | .rst_aon_ni, | 
|  |  | 
|  | // input signals for resume detection | 
|  | .usb_dp_i(dio_to_periph_o[TargetCfg.usb_dp_idx]), | 
|  | .usb_dn_i(dio_to_periph_o[TargetCfg.usb_dn_idx]), | 
|  | .usb_sense_i(mio_to_periph_o[TargetCfg.usb_sense_idx]), | 
|  | .usbdev_dppullup_en_i(usbdev_dppullup_en_i), | 
|  | .usbdev_dnpullup_en_i(usbdev_dnpullup_en_i), | 
|  |  | 
|  | // output signals for pullup connectivity | 
|  | .usb_dppullup_en_o(usb_dppullup_en_o), | 
|  | .usb_dnpullup_en_o(usb_dnpullup_en_o), | 
|  |  | 
|  | // tie this to something from usbdev to indicate its out of reset | 
|  | .suspend_req_aon_i(usbdev_suspend_req_i), | 
|  | .wake_ack_aon_i(usbdev_wake_ack_i), | 
|  |  | 
|  | // wake/powerup request | 
|  | .wake_req_aon_o(usb_wkup_req_o), | 
|  | .bus_reset_aon_o(usbdev_bus_reset_o), | 
|  | .sense_lost_aon_o(usbdev_sense_lost_o), | 
|  | .wake_detect_active_aon_o(usbdev_wake_detect_active_o) | 
|  | ); | 
|  |  | 
|  | ///////////////////////// | 
|  | // Retention Registers // | 
|  | ///////////////////////// | 
|  |  | 
|  | logic sleep_en_q, sleep_trig; | 
|  |  | 
|  | logic [NMioPads-1:0] mio_sleep_trig; | 
|  | logic [NMioPads-1:0] mio_out_retreg_d, mio_oe_retreg_d; | 
|  | logic [NMioPads-1:0] mio_out_retreg_q, mio_oe_retreg_q; | 
|  |  | 
|  | logic [NDioPads-1:0] dio_sleep_trig; | 
|  | logic [NDioPads-1:0] dio_out_retreg_d, dio_oe_retreg_d; | 
|  | logic [NDioPads-1:0] dio_out_retreg_q, dio_oe_retreg_q; | 
|  |  | 
|  | // Sleep entry trigger | 
|  | assign sleep_trig = sleep_en_i & ~sleep_en_q; | 
|  |  | 
|  | always_ff @(posedge clk_i or negedge rst_ni) begin : p_sleep | 
|  | if (!rst_ni) begin | 
|  | sleep_en_q       <= 1'b0; | 
|  | mio_out_retreg_q <= '0; | 
|  | mio_oe_retreg_q  <= '0; | 
|  | dio_out_retreg_q <= '0; | 
|  | dio_oe_retreg_q  <= '0; | 
|  | end else begin | 
|  | sleep_en_q <= sleep_en_i; | 
|  |  | 
|  | // MIOs | 
|  | for (int k = 0; k < NMioPads; k++) begin | 
|  | if (mio_sleep_trig[k]) begin | 
|  | mio_out_retreg_q[k] <= mio_out_retreg_d[k]; | 
|  | mio_oe_retreg_q[k]  <= mio_oe_retreg_d[k]; | 
|  | end | 
|  | end | 
|  |  | 
|  | // DIOs | 
|  | for (int k = 0; k < NDioPads; k++) begin | 
|  | if (dio_sleep_trig[k]) begin | 
|  | dio_out_retreg_q[k] <= dio_out_retreg_d[k]; | 
|  | dio_oe_retreg_q[k]  <= dio_oe_retreg_d[k]; | 
|  | end | 
|  | end | 
|  | end | 
|  | end | 
|  |  | 
|  | ///////////////////// | 
|  | // MIO Input Muxes // | 
|  | ///////////////////// | 
|  |  | 
|  | localparam int AlignedMuxSize = (NMioPads + 2 > NDioPads) ? 2**$clog2(NMioPads + 2) : | 
|  | 2**$clog2(NDioPads); | 
|  |  | 
|  | // stack input and default signals for convenient indexing below possible defaults: | 
|  | // constant 0 or 1. make sure mux is aligned to a power of 2 to avoid Xes. | 
|  | logic [AlignedMuxSize-1:0] mio_mux; | 
|  | assign mio_mux = AlignedMuxSize'({mio_in, 1'b1, 1'b0}); | 
|  |  | 
|  | for (genvar k = 0; k < NMioPeriphIn; k++) begin : gen_mio_periph_in | 
|  | // index using configured insel | 
|  | assign mio_to_periph_o[k] = mio_mux[reg2hw.mio_periph_insel[k].q]; | 
|  | end | 
|  |  | 
|  | ////////////////////// | 
|  | // MIO Output Muxes // | 
|  | ////////////////////// | 
|  |  | 
|  | // stack output data/enable and default signals for convenient indexing below | 
|  | // possible defaults: 0, 1 or 2 (high-Z). make sure mux is aligned to a power of 2 to avoid Xes. | 
|  | logic [2**$clog2(NMioPeriphOut+3)-1:0] periph_data_mux, periph_oe_mux; | 
|  | assign periph_data_mux  = $bits(periph_data_mux)'({periph_to_mio_i, 1'b0, 1'b1, 1'b0}); | 
|  | assign periph_oe_mux    = $bits(periph_oe_mux)'({periph_to_mio_oe_i,  1'b0, 1'b1, 1'b1}); | 
|  |  | 
|  | for (genvar k = 0; k < NMioPads; k++) begin : gen_mio_out | 
|  | // Check individual sleep enable status bits | 
|  | assign mio_out[k] = reg2hw.mio_pad_sleep_status[k].q ? | 
|  | mio_out_retreg_q[k]              : | 
|  | periph_data_mux[reg2hw.mio_outsel[k].q]; | 
|  |  | 
|  | assign mio_oe[k]  = reg2hw.mio_pad_sleep_status[k].q ? | 
|  | mio_oe_retreg_q[k]               : | 
|  | periph_oe_mux[reg2hw.mio_outsel[k].q]; | 
|  |  | 
|  | // latch state when going to sleep | 
|  | // 0: drive low | 
|  | // 1: drive high | 
|  | // 2: high-z | 
|  | // 3: previous value | 
|  | assign mio_out_retreg_d[k] = (reg2hw.mio_pad_sleep_mode[k].q == 0) ? 1'b0 : | 
|  | (reg2hw.mio_pad_sleep_mode[k].q == 1) ? 1'b1 : | 
|  | (reg2hw.mio_pad_sleep_mode[k].q == 2) ? 1'b0 : mio_out[k]; | 
|  |  | 
|  | assign mio_oe_retreg_d[k] = (reg2hw.mio_pad_sleep_mode[k].q == 0) ? 1'b1 : | 
|  | (reg2hw.mio_pad_sleep_mode[k].q == 1) ? 1'b1 : | 
|  | (reg2hw.mio_pad_sleep_mode[k].q == 2) ? 1'b0 : mio_oe[k]; | 
|  |  | 
|  | // Activate sleep behavior only if it has been enabled | 
|  | assign mio_sleep_trig[k] = reg2hw.mio_pad_sleep_en[k].q & sleep_trig; | 
|  | assign hw2reg.mio_pad_sleep_status[k].d = 1'b1; | 
|  | assign hw2reg.mio_pad_sleep_status[k].de = mio_sleep_trig[k]; | 
|  | end | 
|  |  | 
|  | ///////////////////// | 
|  | // DIO connections // | 
|  | ///////////////////// | 
|  |  | 
|  | // Inputs are just fed through | 
|  | assign dio_to_periph_o = dio_in; | 
|  |  | 
|  | for (genvar k = 0; k < NDioPads; k++) begin : gen_dio_out | 
|  | // Check individual sleep enable status bits | 
|  | assign dio_out[k] = reg2hw.dio_pad_sleep_status[k].q ? | 
|  | dio_out_retreg_q[k]              : | 
|  | periph_to_dio_i[k]; | 
|  |  | 
|  | assign dio_oe[k]  = reg2hw.dio_pad_sleep_status[k].q ? | 
|  | dio_oe_retreg_q[k]               : | 
|  | periph_to_dio_oe_i[k]; | 
|  |  | 
|  | // latch state when going to sleep | 
|  | // 0: drive low | 
|  | // 1: drive high | 
|  | // 2: high-z | 
|  | // 3: previous value | 
|  | assign dio_out_retreg_d[k] = (reg2hw.dio_pad_sleep_mode[k].q == 0) ? 1'b0 : | 
|  | (reg2hw.dio_pad_sleep_mode[k].q == 1) ? 1'b1 : | 
|  | (reg2hw.dio_pad_sleep_mode[k].q == 2) ? 1'b0 : dio_out[k]; | 
|  |  | 
|  | assign dio_oe_retreg_d[k] = (reg2hw.dio_pad_sleep_mode[k].q == 0) ? 1'b1 : | 
|  | (reg2hw.dio_pad_sleep_mode[k].q == 1) ? 1'b1 : | 
|  | (reg2hw.dio_pad_sleep_mode[k].q == 2) ? 1'b0 : dio_oe[k]; | 
|  |  | 
|  | // Activate sleep behavior only if it has been enabled | 
|  | assign dio_sleep_trig[k] = reg2hw.dio_pad_sleep_en[k].q & sleep_trig; | 
|  | assign hw2reg.dio_pad_sleep_status[k].d = 1'b1; | 
|  | assign hw2reg.dio_pad_sleep_status[k].de = dio_sleep_trig[k]; | 
|  | end | 
|  |  | 
|  | ////////////////////// | 
|  | // Wakeup detectors // | 
|  | ////////////////////// | 
|  |  | 
|  | // Wakeup detector taps are not affected by JTAG/strap | 
|  | // selection mux. I.e., we always sample the unmuxed inputs | 
|  | // that come directly from the pads. | 
|  | logic [AlignedMuxSize-1:0] dio_wkup_mux; | 
|  | logic [AlignedMuxSize-1:0] mio_wkup_mux; | 
|  | assign dio_wkup_mux = AlignedMuxSize'(dio_in_i); | 
|  | // The two constants that are concatenated here make sure tha the selection | 
|  | // indices used to index this array are the same as the ones used to index | 
|  | // the mio_mux array above, where positions 0 and 1 select constant 0 and | 
|  | // 1, respectively. | 
|  | assign mio_wkup_mux = AlignedMuxSize'({mio_in_i, 1'b1, 1'b0}); | 
|  |  | 
|  | logic [NWkupDetect-1:0] aon_wkup_req; | 
|  | for (genvar k = 0; k < NWkupDetect; k++) begin : gen_wkup_detect | 
|  | logic pin_value; | 
|  | assign pin_value = (reg2hw.wkup_detector[k].miodio.q)           ? | 
|  | dio_wkup_mux[reg2hw.wkup_detector_padsel[k]] : | 
|  | mio_wkup_mux[reg2hw.wkup_detector_padsel[k]]; | 
|  |  | 
|  | // This module runs on the AON clock entirely | 
|  | pinmux_wkup u_pinmux_wkup ( | 
|  | .clk_i              (clk_aon_i                                     ), | 
|  | .rst_ni             (rst_aon_ni                                    ), | 
|  | // config signals have already been synced to the AON domain inside the CSR node. | 
|  | .wkup_en_i          ( reg2hw.wkup_detector_en[k].q                 ), | 
|  | .filter_en_i        ( reg2hw.wkup_detector[k].filter.q             ), | 
|  | .wkup_mode_i        ( wkup_mode_e'(reg2hw.wkup_detector[k].mode.q) ), | 
|  | .wkup_cnt_th_i      ( reg2hw.wkup_detector_cnt_th[k].q             ), | 
|  | .pin_value_i        ( pin_value                                    ), | 
|  | // wakeup request pulse on clk_aon, will be synced back to the bus domain insie the CSR node. | 
|  | .aon_wkup_pulse_o   ( hw2reg.wkup_cause[k].de                      ) | 
|  | ); | 
|  |  | 
|  | assign hw2reg.wkup_cause[k].d = 1'b1; | 
|  |  | 
|  | // This is the latched wakeup request, hence this request signal is level encoded. | 
|  | assign aon_wkup_req[k] = reg2hw.wkup_cause[k].q; | 
|  | end | 
|  |  | 
|  | // OR' together all wakeup requests | 
|  | assign pin_wkup_req_o = |aon_wkup_req; | 
|  |  | 
|  | //////////////// | 
|  | // Assertions // | 
|  | //////////////// | 
|  |  | 
|  | `ASSERT_KNOWN(TlDValidKnownO_A, tl_o.d_valid) | 
|  | `ASSERT_KNOWN(TlAReadyKnownO_A, tl_o.a_ready) | 
|  | `ASSERT_KNOWN(AlertsKnown_A, alert_tx_o) | 
|  | `ASSERT_KNOWN(MioOeKnownO_A, mio_oe_o) | 
|  | `ASSERT_KNOWN(DioOeKnownO_A, dio_oe_o) | 
|  |  | 
|  | `ASSERT_KNOWN(MioKnownO_A, mio_attr_o) | 
|  | `ASSERT_KNOWN(DioKnownO_A, dio_attr_o) | 
|  |  | 
|  | `ASSERT_KNOWN(LcJtagTckKnown_A, lc_jtag_o.tck) | 
|  | `ASSERT_KNOWN(LcJtagTrstKnown_A, lc_jtag_o.trst_n) | 
|  | `ASSERT_KNOWN(LcJtagTmsKnown_A, lc_jtag_o.tms) | 
|  |  | 
|  | `ASSERT_KNOWN(RvJtagTckKnown_A, rv_jtag_o.tck) | 
|  | `ASSERT_KNOWN(RvJtagTrstKnown_A, rv_jtag_o.trst_n) | 
|  | `ASSERT_KNOWN(RvJtagTmsKnown_A, rv_jtag_o.tms) | 
|  |  | 
|  | `ASSERT_KNOWN(DftJtagTckKnown_A, dft_jtag_o.tck) | 
|  | `ASSERT_KNOWN(DftJtagTrstKnown_A, dft_jtag_o.trst_n) | 
|  | `ASSERT_KNOWN(DftJtagTmsKnown_A, dft_jtag_o.tms) | 
|  |  | 
|  | `ASSERT_KNOWN(DftStrapsKnown_A, dft_strap_test_o) | 
|  |  | 
|  | // running on slow AON clock | 
|  | `ASSERT_KNOWN(AonWkupReqKnownO_A, pin_wkup_req_o, clk_aon_i, !rst_aon_ni) | 
|  | `ASSERT_KNOWN(UsbWkupReqKnownO_A, usb_wkup_req_o, clk_aon_i, !rst_aon_ni) | 
|  | `ASSERT_KNOWN(UsbWakeDetectActiveKnownO_A, usbdev_wake_detect_active_o, clk_aon_i, !rst_aon_ni) | 
|  |  | 
|  | // The wakeup signal is not latched in the pwrmgr so must be held until acked by software | 
|  | `ASSERT(PinmuxWkupStable_A, pin_wkup_req_o |=> pin_wkup_req_o || | 
|  | $fell(|reg2hw.wkup_cause) && !sleep_en_i, clk_aon_i, !rst_aon_ni) | 
|  |  | 
|  | // Some inputs at the chip-level may be forced to X in chip-level simulations. | 
|  | // Therefore, we do not instantiate these assertions. | 
|  | // `ASSERT_KNOWN(MioToPeriphKnownO_A, mio_to_periph_o) | 
|  | // `ASSERT_KNOWN(DioToPeriphKnownO_A, dio_to_periph_o) | 
|  |  | 
|  | // The assertions below are not instantiated for a similar reason as the assertions above. | 
|  | // I.e., some IPs have pass-through paths, which may lead to X'es propagating | 
|  | // from input to output. | 
|  | // for (genvar k = 0; k < NMioPads; k++) begin : gen_mio_known_if | 
|  | //   `ASSERT_KNOWN_IF(MioOutKnownO_A, mio_out_o[k], mio_oe_o[k]) | 
|  | // end | 
|  | // for (genvar k = 0; k < NDioPads; k++) begin : gen_dio_known_if | 
|  | //   `ASSERT_KNOWN_IF(DioOutKnownO_A, dio_out_o[k], dio_oe_o[k]) | 
|  | // end | 
|  |  | 
|  | // Alert assertions for reg_we onehot check | 
|  | `ASSERT_PRIM_REG_WE_ONEHOT_ERROR_TRIGGER_ALERT(RegWeOnehotCheck_A, u_reg, alert_tx_o[0]) | 
|  | endmodule : pinmux |