| /// Copyright by Syntacore LLC © 2016-2020. See LICENSE for details |
| /// @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 |
| |