blob: e9e166405db1b60df0dad263d8d076eefd893f2c [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
module pinmux_strap_sampling
import pinmux_pkg::*;
import pinmux_reg_pkg::*;
(
input clk_i,
input rst_ni,
// MIO inputs.
// TODO(#5221): need tapped IOs for JTAG mux.
input logic [NMioPads-1:0] mio_in_i,
// Used for TAP qualification
input logic strap_en_i,
input lc_ctrl_pkg::lc_tx_t lc_dft_en_i,
input lc_ctrl_pkg::lc_tx_t lc_hw_debug_en_i,
// Sampled values for DFT straps
output dft_strap_test_req_t dft_strap_test_o,
// 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
);
/////////////////////////////////////
// Life cycle signal synchronizers //
/////////////////////////////////////
lc_ctrl_pkg::lc_tx_t [1:0] lc_hw_debug_en;
lc_ctrl_pkg::lc_tx_t [1:0] lc_dft_en;
prim_lc_sync #(
.NumCopies(2)
) u_prim_lc_sync_rv (
.clk_i,
.rst_ni,
.lc_en_i(lc_hw_debug_en_i),
.lc_en_o(lc_hw_debug_en)
);
prim_lc_sync #(
.NumCopies(2)
) u_prim_lc_sync_dft (
.clk_i,
.rst_ni,
.lc_en_i(lc_dft_en_i),
.lc_en_o(lc_dft_en)
);
//////////////////////////
// Strap Sampling Logic //
//////////////////////////
typedef enum logic [NTapStraps-1:0] {
FuncSel = 2'b00,
LcTapSel = 2'b01,
RvTapSel = 2'b10,
DftTapSel = 2'b11
} tap_strap_t;
logic strap_en_q;
logic dft_strap_valid_d, dft_strap_valid_q;
logic lc_strap_sample_en, rv_strap_sample_en, dft_strap_sample_en;
logic [1:0] tap_strap_sample_en;
logic [NTapStraps-1:0] tap_strap_d, tap_strap_q;
logic [NDFTStraps-1:0] dft_strap_d, dft_strap_q;
lc_ctrl_pkg::lc_tx_e continue_sampling_d, continue_sampling_q;
// Not all MIOs are used.
logic unused_mio_in;
assign unused_mio_in = ^mio_in_i;
// The LC strap at index 0 has a slightly different
// enable condition than the DFT strap at index 1.
for (genvar k = 0; k < NTapStraps; k++) begin : gen_lc_strap_taps
assign tap_strap_d[k] = (tap_strap_sample_en[k]) ? mio_in_i[TapStrapPos[k]] : tap_strap_q[k];
end
// We're always using the DFT strap sample enable for the DFT straps.
for (genvar k = 0; k < NDFTStraps; k++) begin : gen_dft_strap_taps
assign dft_strap_d[k] = (dft_strap_sample_en) ? mio_in_i[DftStrapPos[k]] : dft_strap_q[k];
end
assign dft_strap_valid_d = dft_strap_sample_en | dft_strap_valid_q;
assign dft_strap_test_o.valid = dft_strap_valid_q;
assign dft_strap_test_o.straps = dft_strap_q;
assign tap_strap_sample_en = {rv_strap_sample_en,
lc_strap_sample_en};
always_comb begin : p_strap_sampling
lc_strap_sample_en = 1'b0;
rv_strap_sample_en = 1'b0;
dft_strap_sample_en = 1'b0;
continue_sampling_d = continue_sampling_q;
// Initial strap sampling pulse from pwrmgr,
// qualified by life cycle signals.
if (strap_en_i || continue_sampling_q == lc_ctrl_pkg::On) begin
lc_strap_sample_en = 1'b1;
if (lc_hw_debug_en[0] == lc_ctrl_pkg::On) begin
rv_strap_sample_en = 1'b1;
end
if (lc_dft_en[0] == lc_ctrl_pkg::On) begin
dft_strap_sample_en = 1'b1;
end
end
// In case DFT is enabled, and in case the TAP straps
// where not set to functional mode upon the first
// sampling event, we continue sampling all straps
// until system reset. This is used during the
// DFT-enabled life cycle states only.
if (lc_dft_en[0] == lc_ctrl_pkg::On) begin
if (strap_en_q &&
tap_strap_t'(tap_strap_q) != FuncSel) begin
continue_sampling_d = lc_ctrl_pkg::On;
end
end
end
always_ff @(posedge clk_i or negedge rst_ni) begin : p_strap_sample
if (!rst_ni) begin
tap_strap_q <= '0;
dft_strap_q <= '0;
strap_en_q <= 1'b0;
dft_strap_valid_q <= 1'b0;
continue_sampling_q <= lc_ctrl_pkg::Off;
end else begin
tap_strap_q <= tap_strap_d;
dft_strap_q <= dft_strap_d;
strap_en_q <= strap_en_i;
dft_strap_valid_q <= dft_strap_valid_d;
continue_sampling_q <= continue_sampling_d;
end
end
////////////////////
// TAP Selection //
////////////////////
jtag_pkg::jtag_req_t jtag_req, lc_jtag_req, rv_jtag_req, dft_jtag_req;
jtag_pkg::jtag_rsp_t jtag_rsp, lc_jtag_rsp, rv_jtag_rsp, dft_jtag_rsp;
// TODO(#5221): need to mux this with the correct MIOs.
// But first, the jtag_mux from the chip level hierarchy needs
// to be pulled into pinmux, and the FPGA emulation and the simulation
// environments need to be adapted such that this does not break our
// regressions.
logic unused_jtag_rsp;
assign jtag_req = '0;
assign unused_jtag_rsp = ^jtag_rsp;
// This muxes the JTAG signals to the correct TAP, based on the
// sampled straps. Further, the individual JTAG signals are gated
// using the corresponding life cycle signal.
tap_strap_t tap_strap;
assign tap_strap = tap_strap_t'(tap_strap_q);
`ASSERT_KNOWN(TapStrapKnown_A, tap_strap)
always_comb begin : p_tap_mux
jtag_rsp = '0;
lc_jtag_req = '0;
rv_jtag_req = '0;
dft_jtag_req = '0;
unique case (tap_strap)
LcTapSel: begin
lc_jtag_req = jtag_req;
jtag_rsp = lc_jtag_rsp;
end
RvTapSel: begin
if (lc_hw_debug_en[1] == lc_ctrl_pkg::On) begin
rv_jtag_req = jtag_req;
jtag_rsp = rv_jtag_rsp;
end
end
DftTapSel: begin
if (lc_dft_en[1] == lc_ctrl_pkg::On) begin
dft_jtag_req = jtag_req;
jtag_rsp = dft_jtag_rsp;
end
end
default: ;
endcase // tap_strap_t'(tap_strap_q)
end
// Insert hand instantiated buffers for
// these signals to prevent further optimization.
pinmux_jtag_buf u_pinmux_jtag_buf_lc (
.req_i(lc_jtag_req),
.req_o(lc_jtag_o),
.rsp_i(lc_jtag_i),
.rsp_o(lc_jtag_rsp)
);
pinmux_jtag_buf u_pinmux_jtag_buf_rv (
.req_i(rv_jtag_req),
.req_o(rv_jtag_o),
.rsp_i(rv_jtag_i),
.rsp_o(rv_jtag_rsp)
);
pinmux_jtag_buf u_pinmux_jtag_buf_dft (
.req_i(dft_jtag_req),
.req_o(dft_jtag_o),
.rsp_i(dft_jtag_i),
.rsp_o(dft_jtag_rsp)
);
////////////////
// Assertions //
////////////////
// The strap sampling enable input shall be pulsed high exactly once after cold boot.
`ASSERT(PwrMgrStrapSampleOnce_A, strap_en_i |=> ##0 !strap_en_i [*])
`ASSERT(RvTapOff0_A, lc_hw_debug_en_i == lc_ctrl_pkg::Off |-> ##2 rv_jtag_o == '0)
`ASSERT(RvTapOff1_A, lc_hw_debug_en_i == lc_ctrl_pkg::Off |-> ##2 rv_jtag_i == '0)
`ASSERT(DftTapOff0_A, lc_dft_en_i == lc_ctrl_pkg::Off |-> ##2 dft_jtag_o == '0)
`ASSERT(DftTapOff1_A, lc_dft_en_i == lc_ctrl_pkg::Off |-> ##2 dft_jtag_i == '0)
endmodule : pinmux_strap_sampling