blob: b63972e9b89aea8c3430a7ef783d64e2f7909016 [file] [log] [blame]
//////////////////////////////////////////////////////////////////////////////
// SPDX-FileCopyrightText: Syntacore LLC © 2016-2021
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileContributor: Syntacore LLC
// //////////////////////////////////////////////////////////////////////////
/// @file <scr1_scu.sv>
/// @brief System Control Unit (SCU)
///
//------------------------------------------------------------------------------
//
// Functionality:
// - Generates System, Core, HDU and DM resets and their qualifier signals
// - Provides debugger with software System and Core resets generation functionality
// - Allows to set the behavior of DM and HDU resets
// - Shows resets Statuses and Sticky Statuses
// Structure:
// - TAPC scan-chain interface
// - SCU CSRs write/read interface
// - SCU CSRS:
// - CONTROL register
// - MODE register
// - STATUS register
// - STICKY_STATUS register
// - Reset logic
// - System Reset
// - Core Reset
// - DM Reset
// - HDU Reset
//------------------------------------------------------------------------------
`include "scr1_arch_description.svh"
`include "scr1_scu.svh"
`ifdef SCR1_DBG_EN
module scr1_scu (
// Global signals
input logic pwrup_rst_n, // Power-Up Reset
input logic rst_n, // Regular Reset
input logic cpu_rst_n, // CPU Reset
input logic test_mode, // DFT Test Mode
input logic test_rst_n, // DFT Test Reset
input logic clk, // SCU clock
// TAPC scan-chains
input logic tapcsync2scu_ch_sel_i, // TAPC Chain Select
input logic tapcsync2scu_ch_id_i, // TAPC Chain ID
input logic tapcsync2scu_ch_capture_i, // TAPC Chain Capture
input logic tapcsync2scu_ch_shift_i, // TAPC Chain Shift
input logic tapcsync2scu_ch_update_i, // TAPC Chain Update
input logic tapcsync2scu_ch_tdi_i, // TAPC Chain TDI
output logic scu2tapcsync_ch_tdo_o, // TAPC Chain TDO
// Input sync resets:
input logic ndm_rst_n_i, // Non-DM Reset input from DM
input logic hart_rst_n_i, // HART Reset from DM
// Generated resets
output logic sys_rst_n_o, // System/Cluster Reset
output logic core_rst_n_o, // Core Reset
output logic dm_rst_n_o, // Debug Module Reset
output logic hdu_rst_n_o, // HART Debug Unit Reset
// Resets statuses
output logic sys_rst_status_o, // System Reset Status (sync'ed to POR reset domain)
output logic core_rst_status_o, // Core Reset Status (sync'ed to POR reset domain)
// Reset Domain Crossing (RDC) qualifiers
output logic sys_rdc_qlfy_o, // System/Cluster-to-ExternalSOC Reset Domain Crossing Qualifier
output logic core_rdc_qlfy_o, // Core-to-ExternalSOC Reset Domain Crossing Qualifier
output logic core2hdu_rdc_qlfy_o, // Core-to-HDU Reset Domain Crossing Qualifier
output logic core2dm_rdc_qlfy_o, // Core-to-DM Reset Domain Crossing Qualifier
output logic hdu2dm_rdc_qlfy_o // HDU-to-DM Reset Domain Crossing Qualifier
);
//------------------------------------------------------------------------------
// Local Parameters
//======================================================================================================================
localparam int unsigned SCR1_SCU_RST_SYNC_STAGES_NUM = 2;
//------------------------------------------------------------------------------
// Local Signals
//------------------------------------------------------------------------------
// SCU CSR write/read i/f
//------------------------------------------------------------------------------
// TAPC scan-chain control logic
logic scu_csr_req;
logic tapc_dr_cap_req;
logic tapc_dr_shft_req;
logic tapc_dr_upd_req;
// TAPC shift register signals
logic tapc_shift_upd;
type_scr1_scu_sysctrl_dr_s tapc_shift_ff;
type_scr1_scu_sysctrl_dr_s tapc_shift_next;
// TAPC shadow register signals
type_scr1_scu_sysctrl_dr_s tapc_shadow_ff;
// SCU CSR write/read i/f
//------------------------------------------------------------------------------
logic [SCR1_SCU_DR_SYSCTRL_DATA_WIDTH-1:0] scu_csr_wdata;
logic [SCR1_SCU_DR_SYSCTRL_DATA_WIDTH-1:0] scu_csr_rdata;
// SCU CSRs signals
//------------------------------------------------------------------------------
// Control register
type_scr1_scu_sysctrl_control_reg_s scu_control_ff;
logic scu_control_wr_req;
// Mode register
type_scr1_scu_sysctrl_mode_reg_s scu_mode_ff;
logic scu_mode_wr_req;
// Status register
type_scr1_scu_sysctrl_status_reg_s scu_status_ff;
type_scr1_scu_sysctrl_status_reg_s scu_status_ff_dly;
type_scr1_scu_sysctrl_status_reg_s scu_status_ff_posedge;
// Sticky Status register
type_scr1_scu_sysctrl_status_reg_s scu_sticky_sts_ff;
logic scu_sticky_sts_wr_req;
// Reset logic signals
//------------------------------------------------------------------------------
// Input resets synchronization signals
logic pwrup_rst_n_sync;
logic rst_n_sync;
logic cpu_rst_n_sync;
// System Reset signals
logic sys_rst_n_in;
logic sys_rst_n_status;
logic sys_rst_n_status_sync;
logic sys_rst_n_qlfy;
logic sys_reset_n;
// Core Reset signals
logic core_rst_n_in_sync;
logic core_rst_n_status;
logic core_rst_n_status_sync;
logic core_rst_n_qlfy;
logic core_reset_n;
// HDU Reset signals
logic hdu_rst_n_in_sync;
logic hdu_rst_n_status;
logic hdu_rst_n_status_sync;
logic hdu_rst_n_qlfy;
// DM Reset signals
logic dm_rst_n_in;
logic dm_rst_n_status;
//------------------------------------------------------------------------------
// TAPC scan-chain i/f
//------------------------------------------------------------------------------
//
// Consists of the following functional units:
// - TAPC scan-chain control logic
// - TAPC shift register
// - TAPC shadow register
//
// TAPC scan-chain control logic
//------------------------------------------------------------------------------
assign scu_csr_req = tapcsync2scu_ch_sel_i & (tapcsync2scu_ch_id_i == '0);
assign tapc_dr_cap_req = scu_csr_req & tapcsync2scu_ch_capture_i;
assign tapc_dr_shft_req = scu_csr_req & tapcsync2scu_ch_shift_i;
assign tapc_dr_upd_req = scu_csr_req & tapcsync2scu_ch_update_i;
// TAPC shift register
//------------------------------------------------------------------------------
assign tapc_shift_upd = tapc_dr_cap_req | tapc_dr_shft_req;
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
if (~pwrup_rst_n_sync) begin
tapc_shift_ff <= '0;
end else if (tapc_shift_upd) begin
tapc_shift_ff <= tapc_shift_next;
end
end
assign tapc_shift_next = tapc_dr_cap_req ? tapc_shadow_ff
: tapc_dr_shft_req ? {tapcsync2scu_ch_tdi_i, tapc_shift_ff[SCR1_SCU_DR_SYSCTRL_WIDTH-1:1]}// cp.5
: tapc_shift_ff;
// TAPC shadow register
//------------------------------------------------------------------------------
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
if (~pwrup_rst_n_sync) begin
tapc_shadow_ff <= '0;
end else if (tapc_dr_upd_req) begin
tapc_shadow_ff.op <= tapc_shift_ff.op;
tapc_shadow_ff.addr <= tapc_shift_ff.addr;
tapc_shadow_ff.data <= scu_csr_wdata;
end
end
assign scu2tapcsync_ch_tdo_o = tapc_shift_ff[0];
//------------------------------------------------------------------------------
// SCU CSRs write/read interface
//------------------------------------------------------------------------------
// Write interface
//------------------------------------------------------------------------------
// Register selection logic
always_comb begin
scu_control_wr_req = 1'b0;
scu_mode_wr_req = 1'b0;
scu_sticky_sts_wr_req = 1'b0;
if (tapc_dr_upd_req && (tapc_shift_ff.op != SCR1_SCU_SYSCTRL_OP_READ)) begin
case (tapc_shift_ff.addr)
SCR1_SCU_SYSCTRL_ADDR_CONTROL: scu_control_wr_req = 1'b1;
SCR1_SCU_SYSCTRL_ADDR_MODE : scu_mode_wr_req = 1'b1;
SCR1_SCU_SYSCTRL_ADDR_STICKY : scu_sticky_sts_wr_req = (tapc_shift_ff.op == SCR1_SCU_SYSCTRL_OP_CLRBITS);
default : begin end
endcase
end
end
// Write data construction
always_comb begin
scu_csr_wdata = '0;
if (tapc_dr_upd_req) begin
case (tapc_shift_ff.op)
SCR1_SCU_SYSCTRL_OP_WRITE : scu_csr_wdata = tapc_shift_ff.data;
SCR1_SCU_SYSCTRL_OP_READ : scu_csr_wdata = scu_csr_rdata;
SCR1_SCU_SYSCTRL_OP_SETBITS: scu_csr_wdata = scu_csr_rdata | tapc_shift_ff.data;
SCR1_SCU_SYSCTRL_OP_CLRBITS: scu_csr_wdata = scu_csr_rdata & (~tapc_shift_ff.data);
default : begin end
endcase
end
end
// Read interface
//------------------------------------------------------------------------------
// Read data multiplexer
always_comb begin
scu_csr_rdata = '0;
if (tapc_dr_upd_req) begin
case (tapc_shift_ff.addr)
SCR1_SCU_SYSCTRL_ADDR_CONTROL: scu_csr_rdata = scu_control_ff;
SCR1_SCU_SYSCTRL_ADDR_MODE : scu_csr_rdata = scu_mode_ff;
SCR1_SCU_SYSCTRL_ADDR_STATUS : scu_csr_rdata = scu_status_ff;
SCR1_SCU_SYSCTRL_ADDR_STICKY : scu_csr_rdata = scu_sticky_sts_ff;
default : scu_csr_rdata = 'x;
endcase
end
end
//------------------------------------------------------------------------------
// SCU CSRs
//------------------------------------------------------------------------------
//
// Registers:
// - CONTROL register
// - MODE register
// - STATUS register
// - STICKY_STATUS register
//
// CONTROL register
//------------------------------------------------------------------------------
// Allows debugger to generate System and Core resets
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
if (~pwrup_rst_n_sync) begin
scu_control_ff <= '0;
end else if (scu_control_wr_req) begin
scu_control_ff <= scu_csr_wdata;
end
end
// MODE register
//------------------------------------------------------------------------------
// Sets reset behavior for DM Reset and HDU Reset signals
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
if (~pwrup_rst_n_sync) begin
scu_mode_ff <= '0;
end else if (scu_mode_wr_req) begin
scu_mode_ff <= scu_csr_wdata;
end
end
// STATUS register
//------------------------------------------------------------------------------
// Holds the status of every output reset signal (System, Core, DM and HDU)
assign scu_status_ff.sys_reset = sys_rst_status_o ;
assign scu_status_ff.core_reset = core_rst_status_o;
assign scu_status_ff.dm_reset = ~dm_rst_n_status;
assign scu_status_ff.hdu_reset = ~hdu_rst_n_status_sync;
// Status Register positive edge detection logic
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
if (~pwrup_rst_n_sync) begin
scu_status_ff_dly <= '0;
end else begin
scu_status_ff_dly <= scu_status_ff;
end
end
assign scu_status_ff_posedge = scu_status_ff & ~scu_status_ff_dly;
// STICKY_STATUS register
//------------------------------------------------------------------------------
// For every output reset signal shows if it was asserted since the last bit clearing
integer i;
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
if (~pwrup_rst_n_sync) begin
scu_sticky_sts_ff <= '0;
end else begin
for (i = 0; i < SCR1_SCU_SYSCTRL_STATUS_REG_WIDTH ; i=i+1) begin // cp.4
if (scu_status_ff_posedge[i]) begin
scu_sticky_sts_ff[i] <= 1'b1;
end else if (scu_sticky_sts_wr_req) begin
scu_sticky_sts_ff[i] <= scu_csr_wdata[i];
end
end
end
end
//------------------------------------------------------------------------------
// Reset logic
//------------------------------------------------------------------------------
//
// Consists of the following functional units:
// - System Reset logic
// - Core Reset logic
// - Hart Debug Unit Reset logic
// - Debug Module Reset logic
//
// Reset inputs are assumed synchronous
assign pwrup_rst_n_sync = pwrup_rst_n;
assign rst_n_sync = rst_n;
assign cpu_rst_n_sync = cpu_rst_n;
// Intermediate resets:
assign sys_reset_n = ~scu_control_ff.sys_reset;
assign core_reset_n = ~scu_control_ff.core_reset;
// System/Cluster Reset: sys_rst_n_o
//------------------------------------------------------------------------------
scr1_reset_qlfy_adapter_cell_sync i_sys_rstn_qlfy_adapter_cell_sync (
.rst_n (pwrup_rst_n_sync),
.clk (clk ),
.test_rst_n (test_rst_n ),
.test_mode (test_mode ),
.reset_n_in_sync (sys_rst_n_in ),
.reset_n_out_qlfy (sys_rst_n_qlfy ),
.reset_n_out (sys_rst_n_o ),
.reset_n_status (sys_rst_n_status)
);
assign sys_rst_n_in = sys_reset_n & ndm_rst_n_i & rst_n_sync;
scr1_data_sync_cell #(
.STAGES_AMOUNT (SCR1_SCU_RST_SYNC_STAGES_NUM)
) i_sys_rstn_status_sync (
.rst_n (pwrup_rst_n_sync ),
.clk (clk ),
.data_in (sys_rst_n_status ),
.data_out (sys_rst_n_status_sync)
);
assign sys_rst_status_o = ~sys_rst_n_status_sync;
// System/Cluster-to-ExternalSOC RDC qualifier
assign sys_rdc_qlfy_o = sys_rst_n_qlfy;
// Core Reset: core_rst_n_o
//------------------------------------------------------------------------------
scr1_reset_qlfy_adapter_cell_sync i_core_rstn_qlfy_adapter_cell_sync (
.rst_n (pwrup_rst_n_sync ),
.clk (clk ),
.test_rst_n (test_rst_n ),
.test_mode (test_mode ),
.reset_n_in_sync (core_rst_n_in_sync),
.reset_n_out_qlfy (core_rst_n_qlfy ),
.reset_n_out (core_rst_n_o ),
.reset_n_status (core_rst_n_status )
);
assign core_rst_n_in_sync = sys_rst_n_in & hart_rst_n_i & core_reset_n & cpu_rst_n_sync;
scr1_data_sync_cell #(
.STAGES_AMOUNT (SCR1_SCU_RST_SYNC_STAGES_NUM)
) i_core_rstn_status_sync (
.rst_n (pwrup_rst_n_sync ),
.clk (clk ),
.data_in (core_rst_n_status ),
.data_out (core_rst_n_status_sync)
);
assign core_rst_status_o = ~core_rst_n_status_sync;
// Core Reset RDC Qualifiers:
// - Core-to-ExternalSOC RDC Qlfy
assign core_rdc_qlfy_o = core_rst_n_qlfy;
// - Core-to-HDU RDC Qlfy
assign core2hdu_rdc_qlfy_o = core_rst_n_qlfy;
// - Core-to-DebugModule RDC Qlfy
assign core2dm_rdc_qlfy_o = core_rst_n_qlfy;
// Hart Debug Unit Reset: hdu_rst_n_o
//------------------------------------------------------------------------------
scr1_reset_qlfy_adapter_cell_sync i_hdu_rstn_qlfy_adapter_cell_sync (
.rst_n (pwrup_rst_n_sync ),
.clk (clk ),
.test_rst_n (test_rst_n ),
.test_mode (test_mode ),
.reset_n_in_sync (hdu_rst_n_in_sync),
.reset_n_out_qlfy (hdu_rst_n_qlfy ),
.reset_n_out (hdu_rst_n_o ),
.reset_n_status (hdu_rst_n_status )
);
assign hdu_rst_n_in_sync = scu_mode_ff.hdu_rst_bhv | core_rst_n_in_sync;
scr1_data_sync_cell #(
.STAGES_AMOUNT (SCR1_SCU_RST_SYNC_STAGES_NUM)
) i_hdu_rstn_status_sync (
.rst_n (pwrup_rst_n_sync ),
.clk (clk ),
.data_in (hdu_rst_n_status ),
.data_out (hdu_rst_n_status_sync)
);
// Hart Debug Unit Reset RDC Qualifiers:
// - HDU-to-DebugModule RDC Qlfy
assign hdu2dm_rdc_qlfy_o = hdu_rst_n_qlfy;
// Debug Module Reset: dm_rst_n_o
//------------------------------------------------------------------------------
scr1_reset_buf_cell i_dm_rstn_buf_cell (
.rst_n (pwrup_rst_n_sync),
.clk (clk ),
.test_mode (test_mode ),
.test_rst_n (test_rst_n ),
.reset_n_in (dm_rst_n_in ),
.reset_n_out (dm_rst_n_o ),
.reset_n_status (dm_rst_n_status )
);
assign dm_rst_n_in = ~scu_mode_ff.dm_rst_bhv | sys_reset_n;
`ifdef SCR1_TRGT_SIMULATION
//--------------------------------------------------------------------
// Assertions
//--------------------------------------------------------------------
`ifndef VERILATOR
// Preventing some assertions to be raised at 0 sim time or in the first cycle
initial begin
$assertoff(0, scr1_scu);
repeat (2) @(posedge clk);
$asserton(0, scr1_scu);
end
`endif // VERILATOR
// X checks
SCR1_SVA_SCU_RESETS_XCHECK : assert property (
@(negedge clk)
!$isunknown({pwrup_rst_n, rst_n, cpu_rst_n, ndm_rst_n_i, hart_rst_n_i})
) else $error("SCU resets error: unknown values of input resets");
`ifndef VERILATOR
// Qualifiers checks
SCR1_SVA_SCU_SYS2SOC_QLFY_CHECK : assert property (
@(negedge clk) disable iff (~pwrup_rst_n)
$fell(sys_rst_n_o) |-> $fell($past(sys_rdc_qlfy_o))
) else $error("SCU sys2soc qlfy error: qlfy wasn't raised prior to reset");
SCR1_SVA_SCU_CORE2SOC_QLFY_CHECK : assert property (
@(negedge clk) disable iff (~pwrup_rst_n)
$fell(core_rst_n_o) |-> $fell($past(core_rdc_qlfy_o))
) else $error("SCU core2soc qlfy error: qlfy wasn't raised prior to reset");
SCR1_SVA_SCU_CORE2HDU_QLFY_CHECK : assert property (
@(negedge clk) disable iff (~pwrup_rst_n)
$fell(core_rst_n_o) |-> $fell($past(core2hdu_rdc_qlfy_o))
) else $error("SCU core2hdu qlfy error: qlfy wasn't raised prior to reset");
SCR1_SVA_SCU_CORE2DM_QLFY_CHECK : assert property (
@(negedge clk) disable iff (~pwrup_rst_n)
$fell(core_rst_n_o) |-> $fell($past(core2dm_rdc_qlfy_o))
) else $error("SCU core2dm qlfy error: qlfy wasn't raised prior to reset");
SCR1_SVA_SCU_HDU2DM_QLFY_CHECK : assert property (
@(negedge clk) disable iff (~pwrup_rst_n)
$fell(hdu_rst_n_o) |-> $fell($past(hdu2dm_rdc_qlfy_o))
) else $error("SCU hdu2dm qlfy error: qlfy wasn't raised prior to reset");
`endif // VERILATOR
`endif // SCR1_TRGT_SIMULATION
endmodule : scr1_scu
`endif // SCR1_DBG_EN