From 86249ca0f0145e4d9e82be2563e820f0ebf655f6 Mon Sep 17 00:00:00 2001 From: Mikhail Yenuchenko <76039929+mixeme@users.noreply.github.com> Date: Wed, 21 Jan 2026 14:06:27 +0300 Subject: [PATCH] Copy files --- src/rtl/scr1/scr1_ahb.svh | 59 + src/rtl/scr1/scr1_arch_description.svh | 215 ++++ src/rtl/scr1/scr1_arch_types.svh | 72 ++ src/rtl/scr1/scr1_cg.sv | 32 + src/rtl/scr1/scr1_clk_ctrl.sv | 55 + src/rtl/scr1/scr1_core_top.sv | 521 ++++++++ src/rtl/scr1/scr1_csr.svh | 196 +++ src/rtl/scr1/scr1_dm.sv | 1427 ++++++++++++++++++++++ src/rtl/scr1/scr1_dm.svh | 141 +++ src/rtl/scr1/scr1_dmem_ahb.sv | 480 ++++++++ src/rtl/scr1/scr1_dmem_router.sv | 278 +++++ src/rtl/scr1/scr1_dmi.sv | 182 +++ src/rtl/scr1/scr1_dp_memory.sv | 111 ++ src/rtl/scr1/scr1_hdu.svh | 165 +++ src/rtl/scr1/scr1_imem_ahb.sv | 319 +++++ src/rtl/scr1/scr1_imem_router.sv | 185 +++ src/rtl/scr1/scr1_ipic.sv | 605 +++++++++ src/rtl/scr1/scr1_ipic.svh | 58 + src/rtl/scr1/scr1_mem_axi.sv | 363 ++++++ src/rtl/scr1/scr1_memif.svh | 49 + src/rtl/scr1/scr1_pipe_csr.sv | 1169 ++++++++++++++++++ src/rtl/scr1/scr1_pipe_exu.sv | 1086 ++++++++++++++++ src/rtl/scr1/scr1_pipe_hdu.sv | 904 ++++++++++++++ src/rtl/scr1/scr1_pipe_ialu.sv | 720 +++++++++++ src/rtl/scr1/scr1_pipe_idu.sv | 940 ++++++++++++++ src/rtl/scr1/scr1_pipe_ifu.sv | 826 +++++++++++++ src/rtl/scr1/scr1_pipe_lsu.sv | 351 ++++++ src/rtl/scr1/scr1_pipe_mprf.sv | 167 +++ src/rtl/scr1/scr1_pipe_tdu.sv | 610 +++++++++ src/rtl/scr1/scr1_pipe_top.sv | 825 +++++++++++++ src/rtl/scr1/scr1_reset_cells.sv | 231 ++++ src/rtl/scr1/scr1_riscv_isa_decoding.svh | 185 +++ src/rtl/scr1/scr1_scu.sv | 516 ++++++++ src/rtl/scr1/scr1_scu.svh | 84 ++ src/rtl/scr1/scr1_search_ms1.svh | 94 ++ src/rtl/scr1/scr1_tapc.sv | 457 +++++++ src/rtl/scr1/scr1_tapc.svh | 66 + src/rtl/scr1/scr1_tapc_shift_reg.sv | 112 ++ src/rtl/scr1/scr1_tapc_synchronizer.sv | 183 +++ src/rtl/scr1/scr1_tcm.sv | 131 ++ src/rtl/scr1/scr1_tdu.svh | 121 ++ src/rtl/scr1/scr1_timer.sv | 271 ++++ src/rtl/scr1/scr1_top_ahb.sv | 513 ++++++++ src/rtl/scr1/scr1_top_axi.sv | 701 +++++++++++ src/rtl/scr1/scr1_tracelog.sv | 453 +++++++ 45 files changed, 17229 insertions(+) create mode 100644 src/rtl/scr1/scr1_ahb.svh create mode 100644 src/rtl/scr1/scr1_arch_description.svh create mode 100644 src/rtl/scr1/scr1_arch_types.svh create mode 100644 src/rtl/scr1/scr1_cg.sv create mode 100644 src/rtl/scr1/scr1_clk_ctrl.sv create mode 100644 src/rtl/scr1/scr1_core_top.sv create mode 100644 src/rtl/scr1/scr1_csr.svh create mode 100644 src/rtl/scr1/scr1_dm.sv create mode 100644 src/rtl/scr1/scr1_dm.svh create mode 100644 src/rtl/scr1/scr1_dmem_ahb.sv create mode 100644 src/rtl/scr1/scr1_dmem_router.sv create mode 100644 src/rtl/scr1/scr1_dmi.sv create mode 100644 src/rtl/scr1/scr1_dp_memory.sv create mode 100644 src/rtl/scr1/scr1_hdu.svh create mode 100644 src/rtl/scr1/scr1_imem_ahb.sv create mode 100644 src/rtl/scr1/scr1_imem_router.sv create mode 100644 src/rtl/scr1/scr1_ipic.sv create mode 100644 src/rtl/scr1/scr1_ipic.svh create mode 100644 src/rtl/scr1/scr1_mem_axi.sv create mode 100644 src/rtl/scr1/scr1_memif.svh create mode 100644 src/rtl/scr1/scr1_pipe_csr.sv create mode 100644 src/rtl/scr1/scr1_pipe_exu.sv create mode 100644 src/rtl/scr1/scr1_pipe_hdu.sv create mode 100644 src/rtl/scr1/scr1_pipe_ialu.sv create mode 100644 src/rtl/scr1/scr1_pipe_idu.sv create mode 100644 src/rtl/scr1/scr1_pipe_ifu.sv create mode 100644 src/rtl/scr1/scr1_pipe_lsu.sv create mode 100644 src/rtl/scr1/scr1_pipe_mprf.sv create mode 100644 src/rtl/scr1/scr1_pipe_tdu.sv create mode 100644 src/rtl/scr1/scr1_pipe_top.sv create mode 100644 src/rtl/scr1/scr1_reset_cells.sv create mode 100644 src/rtl/scr1/scr1_riscv_isa_decoding.svh create mode 100644 src/rtl/scr1/scr1_scu.sv create mode 100644 src/rtl/scr1/scr1_scu.svh create mode 100644 src/rtl/scr1/scr1_search_ms1.svh create mode 100644 src/rtl/scr1/scr1_tapc.sv create mode 100644 src/rtl/scr1/scr1_tapc.svh create mode 100644 src/rtl/scr1/scr1_tapc_shift_reg.sv create mode 100644 src/rtl/scr1/scr1_tapc_synchronizer.sv create mode 100644 src/rtl/scr1/scr1_tcm.sv create mode 100644 src/rtl/scr1/scr1_tdu.svh create mode 100644 src/rtl/scr1/scr1_timer.sv create mode 100644 src/rtl/scr1/scr1_top_ahb.sv create mode 100644 src/rtl/scr1/scr1_top_axi.sv create mode 100644 src/rtl/scr1/scr1_tracelog.sv diff --git a/src/rtl/scr1/scr1_ahb.svh b/src/rtl/scr1/scr1_ahb.svh new file mode 100644 index 0000000..2cfb207 --- /dev/null +++ b/src/rtl/scr1/scr1_ahb.svh @@ -0,0 +1,59 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief AHB header file +/// + +`ifndef SCR1_AHB_SVH +`define SCR1_AHB_SVH + +`include "scr1_arch_description.svh" + +parameter SCR1_AHB_WIDTH = 32; + +// Encoding for HTRANS signal +parameter logic [1:0] SCR1_HTRANS_IDLE = 2'b00; +parameter logic [1:0] SCR1_HTRANS_NONSEQ = 2'b10; +`ifdef SCR1_XPROP_EN +parameter logic [1:0] SCR1_HTRANS_ERR = 'x; +`else // SCR1_XPROP_EN +parameter logic [1:0] SCR1_HTRANS_ERR = '0; +`endif // SCR1_XPROP_EN + +// Encoding for HBURST signal +parameter logic [2:0] SCR1_HBURST_SINGLE = 3'b000; +`ifdef SCR1_XPROP_EN +parameter logic [2:0] SCR1_HBURST_ERR = 'x; +`else // SCR1_XPROP_EN +parameter logic [1:0] SCR1_HBURST_ERR = '0; +`endif // SCR1_XPROP_EN + +// Encoding for HSIZE signal +parameter logic [2:0] SCR1_HSIZE_8B = 3'b000; +parameter logic [2:0] SCR1_HSIZE_16B = 3'b001; +parameter logic [2:0] SCR1_HSIZE_32B = 3'b010; +`ifdef SCR1_XPROP_EN +parameter logic [2:0] SCR1_HSIZE_ERR = 'x; +`else // SCR1_XPROP_EN +parameter logic [2:0] SCR1_HSIZE_ERR = '0; +`endif // SCR1_XPROP_EN + +// Encoding HPROT signal +// HPROT[0] : 0 - instr; 1 - data +// HPROT[1] : 0 - user; 1 - privilege +// HPROT[2] : 0 - not buffer; 1 - buffer +// HPROT[3] : 0 - cacheable; 1 - cacheable +parameter SCR1_HPROT_DATA = 0; +parameter SCR1_HPROT_PRV = 1; +parameter SCR1_HPROT_BUF = 2; +parameter SCR1_HPROT_CACHE = 3; + +// Encoding HRESP signal +parameter logic SCR1_HRESP_OKAY = 1'b0; +parameter logic SCR1_HRESP_ERROR = 1'b1; +`ifdef SCR1_XPROP_EN +parameter logic SCR1_HRESP_ERR = 1'bx; +`else // SCR1_XPROP_EN +parameter logic SCR1_HRESP_ERR = 1'b0; +`endif // SCR1_XPROP_EN + +`endif // SCR1_AHB_SVH diff --git a/src/rtl/scr1/scr1_arch_description.svh b/src/rtl/scr1/scr1_arch_description.svh new file mode 100644 index 0000000..c60412e --- /dev/null +++ b/src/rtl/scr1/scr1_arch_description.svh @@ -0,0 +1,215 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Architecture description file +/// + +`ifndef SCR1_ARCH_DESCRIPTION_SVH +`define SCR1_ARCH_DESCRIPTION_SVH + + +//------------------------------------------------------------------------------ +// CORE FUNDAMENTAL PARAMETERS +//------------------------------------------------------------------------------ + +// SCR1 core identifiers +`define SCR1_MIMPID 32'h22011200 +`define SCR1_MVENDORID 32'h00000000 + +// Width of main registers and buses +`define SCR1_XLEN 32 +`define SCR1_IMEM_AWIDTH `SCR1_XLEN +`define SCR1_IMEM_DWIDTH `SCR1_XLEN +`define SCR1_DMEM_AWIDTH `SCR1_XLEN +`define SCR1_DMEM_DWIDTH `SCR1_XLEN + +// TAP IDCODE +`define SCR1_TAP_IDCODE 'hDEB11001 + + +`ifdef SCR1_ARCH_CUSTOM +//------------------------------------------------------------------------------ +// INCLUDE SCR1_ARCH_CUSTOM.SVH +//------------------------------------------------------------------------------ + +// The external file scr1_arch_custom.svh is used for the open SCR1-SDK project, +// and can also be used for any custom projects. + +// The file sets: +// - target platform (FPGA/ASIC), which affects the choice of logical constructs; +// - device build ID; +// - address constants; +// - could enables configuration parameters. + +// Possible targets: +// `define SCR1_TRGT_FPGA_INTEL // target platform is Intel FPGAs +// `define SCR1_TRGT_FPGA_INTEL_MAX10 // target platform is Intel MAX 10 FPGAs (used in the SCR1-SDK project) +// `define SCR1_TRGT_FPGA_INTEL_ARRIAV // target platform is Intel Arria V FPGAs (used in the SCR1-SDK project) +// `define SCR1_TRGT_FPGA_XILINX // target platform is Xilinx FPGAs (used in the SCR1-SDK project) +// `define SCR1_TRGT_ASIC // target platform is ASIC +// `define SCR1_TRGT_SIMULATION // target is simulation (enable simulation code) + + `include "scr1_arch_custom.svh" + +`endif // SCR1_ARCH_CUSTOM + + +//------------------------------------------------------------------------------ +// RECOMMENDED CORE ARCHITECTURE CONFIGURATIONS +//------------------------------------------------------------------------------ + +// Uncomment one of these defines to set the recommended configuration: + +//`define SCR1_CFG_RV32IMC_MAX +//`define SCR1_CFG_RV32IC_BASE +`define SCR1_CFG_RV32EC_MIN + +// If all defines are commented, custom configuration will be used (see below) + +//------------------------------------------------------------------------------ +// READ-ONLY: settings for recommended configurations +`ifdef SCR1_CFG_RV32IMC_MAX + `define SCR1_RVI_EXT + `define SCR1_RVM_EXT + `define SCR1_RVC_EXT + parameter int unsigned SCR1_MTVEC_BASE_WR_BITS = 26; + `define SCR1_MTVEC_MODE_EN + `define SCR1_FAST_MUL + `define SCR1_MPRF_RST_EN + `define SCR1_MCOUNTEN_EN + `define SCR1_DBG_EN + `define SCR1_TDU_EN + parameter int unsigned SCR1_TDU_TRIG_NUM = 4; + `define SCR1_TDU_ICOUNT_EN + `define SCR1_IPIC_EN + `define SCR1_IPIC_SYNC_EN + `define SCR1_TCM_EN +`elsif SCR1_CFG_RV32IC_BASE + `define SCR1_RVI_EXT + `define SCR1_RVC_EXT + parameter int unsigned SCR1_MTVEC_BASE_WR_BITS = 16; + `define SCR1_MTVEC_MODE_EN + `define SCR1_NO_DEC_STAGE + `define SCR1_MPRF_RST_EN + `define SCR1_MCOUNTEN_EN + `define SCR1_DBG_EN + `define SCR1_TDU_EN + parameter int unsigned SCR1_TDU_TRIG_NUM = 2; + `define SCR1_TDU_ICOUNT_EN + `define SCR1_IPIC_EN + `define SCR1_IPIC_SYNC_EN + `define SCR1_TCM_EN +`elsif SCR1_CFG_RV32EC_MIN + `define SCR1_RVE_EXT + `define SCR1_RVC_EXT + parameter int unsigned SCR1_MTVEC_BASE_WR_BITS = 0; + `define SCR1_NO_DEC_STAGE + `define SCR1_NO_EXE_STAGE + `define SCR1_TCM_EN + +`else // begin custom configuration section + + +//------------------------------------------------------------------------------ +// CUSTOM CORE ARCHITECTURE CONFIGURATION +//------------------------------------------------------------------------------ + +// To fine-tune custom configuration, you can change the values in this section. +// Make sure that the defines of the recommended configurations are commented, +// otherwise this section will be inactive. + +// RISC-V ISA options +//`define SCR1_RVE_EXT // enable RV32E base integer instruction set, otherwise RV32I will be used +`define SCR1_RVM_EXT // enable standard extension "M" for integer hardware multiplier and divider +`define SCR1_RVC_EXT // enable standard extension "C" for compressed instructions +parameter int unsigned SCR1_MTVEC_BASE_WR_BITS = 26; // number of writable high-order bits in MTVEC.base field + // legal values are 0 to 26 + // read-only bits are hardwired to reset value +`define SCR1_MTVEC_MODE_EN // enable writable MTVEC.mode field to allow vectored irq mode, otherwise only direct mode is possible + +`ifndef SCR1_RVE_EXT + `define SCR1_RVI_EXT // RV32E base integer instruction set if SCR1_RVE_EXT is not enabled +`endif // ~SCR1_RVE_EXT + +// Core pipeline options (power-performance-area optimization) +`define SCR1_NO_DEC_STAGE // disable register between IFU and IDU +`define SCR1_NO_EXE_STAGE // disable register between IDU and EXU +`define SCR1_NEW_PC_REG // enable register in IFU for New_PC value +`define SCR1_FAST_MUL // enable fast one-cycle multiplication, otherwise multiplication takes 32 cycles +`define SCR1_CLKCTRL_EN // enable global clock gating +`define SCR1_MPRF_RST_EN // enable reset for MPRF +`define SCR1_MCOUNTEN_EN // enable custom MCOUNTEN CSR for counter control + +// Uncore options +`define SCR1_DBG_EN // enable Debug Subsystem (TAPC, DM, SCU, HDU) +`define SCR1_TDU_EN // enable Trigger Debug Unit (hardware breakpoints) +parameter int unsigned SCR1_TDU_TRIG_NUM = 2; // number of hardware triggers +`define SCR1_TDU_ICOUNT_EN // enable hardware triggers on instruction counter +`define SCR1_IPIC_EN // enable Integrated Programmable Interrupt Controller +`define SCR1_IPIC_SYNC_EN // enable IPIC synchronizer +`define SCR1_TCM_EN // enable Tightly-Coupled Memory + +`endif // end custom configuration section + + +//------------------------------------------------------------------------------ +// CORE INTEGRATION OPTIONS +//------------------------------------------------------------------------------ + +// Bypasses on AXI/AHB bridge I/O +`define SCR1_IMEM_AHB_IN_BP // bypass instruction memory AHB bridge input register +`define SCR1_IMEM_AHB_OUT_BP // bypass instruction memory AHB bridge output register +`define SCR1_DMEM_AHB_IN_BP // bypass data memory AHB bridge input register +`define SCR1_DMEM_AHB_OUT_BP // bypass data memory AHB bridge output register +`define SCR1_IMEM_AXI_REQ_BP // bypass instruction memory AXI bridge request register +`define SCR1_IMEM_AXI_RESP_BP // bypass instruction memory AXI bridge response register +`define SCR1_DMEM_AXI_REQ_BP // bypass data memory AXI bridge request register +`define SCR1_DMEM_AXI_RESP_BP // bypass data memory AXI bridge response register + +`ifndef SCR1_ARCH_CUSTOM +// Default address constants (if scr1_arch_custom.svh is not used) +parameter bit [`SCR1_XLEN-1:0] SCR1_ARCH_RST_VECTOR = 'h200; // Reset vector value (start address after reset) +parameter bit [`SCR1_XLEN-1:0] SCR1_ARCH_MTVEC_BASE = 'h1C0; // MTVEC.base field reset value, or constant value for MTVEC.base bits that are hardwired + +parameter bit [`SCR1_DMEM_AWIDTH-1:0] SCR1_TCM_ADDR_MASK = 'hFFFF0000; // TCM mask and size; size in bytes is two's complement of the mask value +parameter bit [`SCR1_DMEM_AWIDTH-1:0] SCR1_TCM_ADDR_PATTERN = 'h00480000; // TCM address match pattern + +parameter bit [`SCR1_DMEM_AWIDTH-1:0] SCR1_TIMER_ADDR_MASK = 'hFFFFFFE0; // Timer mask +parameter bit [`SCR1_DMEM_AWIDTH-1:0] SCR1_TIMER_ADDR_PATTERN = 'h00490000; // Timer address match pattern + +// Device build ID + `define SCR1_ARCH_BUILD_ID `SCR1_MIMPID + +`endif // SCR1_ARCH_CUSTOM + + +//------------------------------------------------------------------------------ +// TARGET-SPECIFIC OPTIONS +//------------------------------------------------------------------------------ + +// RAM-based MPRF can be used for Intel FPGAs only +`ifdef SCR1_TRGT_FPGA_INTEL + `define SCR1_MPRF_RAM // implements MPRF with dedicated RAM blocks +`endif + +// EXU_STAGE_BYPASS and MPRF_RST_EN must be disabled for RAM-based MPRF +`ifdef SCR1_MPRF_RAM + `undef SCR1_NO_EXE_STAGE + `undef SCR1_MPRF_RST_EN +`endif + + +//------------------------------------------------------------------------------ +// SIMULATION OPTIONS +//------------------------------------------------------------------------------ + +//`define SCR1_TRGT_SIMULATION // enable simulation code (automatically defined by root makefile) +//`define SCR1_TRACE_LOG_EN // enable tracelog +//`define SCR1_XPROP_EN // enable X-propagation + +// Addresses used in testbench +localparam [`SCR1_XLEN-1:0] SCR1_SIM_EXIT_ADDR = 32'h0000_00F8; +localparam [`SCR1_XLEN-1:0] SCR1_SIM_PRINT_ADDR = 32'hF000_0000; +localparam [`SCR1_XLEN-1:0] SCR1_SIM_EXT_IRQ_ADDR = 32'hF000_0100; +localparam [`SCR1_XLEN-1:0] SCR1_SIM_SOFT_IRQ_ADDR = 32'hF000_0200; + +`endif // SCR1_ARCH_DESCRIPTION_SVH diff --git a/src/rtl/scr1/scr1_arch_types.svh b/src/rtl/scr1/scr1_arch_types.svh new file mode 100644 index 0000000..62f1037 --- /dev/null +++ b/src/rtl/scr1/scr1_arch_types.svh @@ -0,0 +1,72 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Pipeline types description file +/// + +`ifndef SCR1_ARCH_TYPES_SVH +`define SCR1_ARCH_TYPES_SVH + +`include "scr1_arch_description.svh" + +//------------------------------------------------------------------------------- +// MPRF and CSR parameters +//------------------------------------------------------------------------------- + +`ifdef SCR1_RVE_EXT + `define SCR1_MPRF_AWIDTH 4 + `define SCR1_MPRF_SIZE 16 +`else // SCR1_RVE_EXT + `define SCR1_MPRF_AWIDTH 5 + `define SCR1_MPRF_SIZE 32 +`endif // SCR1_RVE_EXT + +typedef logic [`SCR1_XLEN-1:0] type_scr1_mprf_v; +typedef logic [`SCR1_XLEN-1:0] type_scr1_pc_v; + +parameter int unsigned SCR1_CSR_ADDR_WIDTH = 12; +parameter int unsigned SCR1_CSR_MTVEC_BASE_ZERO_BITS = 6; +parameter int unsigned SCR1_CSR_MTVEC_BASE_VAL_BITS = `SCR1_XLEN-SCR1_CSR_MTVEC_BASE_ZERO_BITS; +parameter bit [`SCR1_XLEN-1:SCR1_CSR_MTVEC_BASE_ZERO_BITS] SCR1_CSR_MTVEC_BASE_WR_RST_VAL = + SCR1_CSR_MTVEC_BASE_VAL_BITS'(SCR1_ARCH_MTVEC_BASE >> SCR1_CSR_MTVEC_BASE_ZERO_BITS); +parameter int unsigned SCR1_CSR_MTVEC_BASE_RO_BITS = (`SCR1_XLEN-(SCR1_CSR_MTVEC_BASE_ZERO_BITS+SCR1_MTVEC_BASE_WR_BITS)); + +`define SCR1_MTVAL_ILLEGAL_INSTR_EN + +//------------------------------------------------------------------------------- +// Exception and IRQ codes +//------------------------------------------------------------------------------- +parameter int unsigned SCR1_EXC_CODE_WIDTH_E = 4; + +// Exceptions +typedef enum logic [SCR1_EXC_CODE_WIDTH_E-1:0] { + SCR1_EXC_CODE_INSTR_MISALIGN = 4'd0, // from EXU + SCR1_EXC_CODE_INSTR_ACCESS_FAULT = 4'd1, // from IFU + SCR1_EXC_CODE_ILLEGAL_INSTR = 4'd2, // from IDU or CSR + SCR1_EXC_CODE_BREAKPOINT = 4'd3, // from IDU or BRKM + SCR1_EXC_CODE_LD_ADDR_MISALIGN = 4'd4, // from LSU + SCR1_EXC_CODE_LD_ACCESS_FAULT = 4'd5, // from LSU + SCR1_EXC_CODE_ST_ADDR_MISALIGN = 4'd6, // from LSU + SCR1_EXC_CODE_ST_ACCESS_FAULT = 4'd7, // from LSU + SCR1_EXC_CODE_ECALL_M = 4'd11 // from IDU +} type_scr1_exc_code_e; + +// IRQs, reset +parameter bit [SCR1_EXC_CODE_WIDTH_E-1:0] SCR1_EXC_CODE_IRQ_M_SOFTWARE = 4'd3; +parameter bit [SCR1_EXC_CODE_WIDTH_E-1:0] SCR1_EXC_CODE_IRQ_M_TIMER = 4'd7; +parameter bit [SCR1_EXC_CODE_WIDTH_E-1:0] SCR1_EXC_CODE_IRQ_M_EXTERNAL = 4'd11; +parameter bit [SCR1_EXC_CODE_WIDTH_E-1:0] SCR1_EXC_CODE_RESET = 4'd0; + +//------------------------------------------------------------------------------- +// Operand width for BRKM +//------------------------------------------------------------------------------- +typedef enum logic [1:0] { + SCR1_OP_WIDTH_BYTE = 2'b00, + SCR1_OP_WIDTH_HALF = 2'b01, + SCR1_OP_WIDTH_WORD = 2'b10 +`ifdef SCR1_XPROP_EN + , + SCR1_OP_WIDTH_ERROR = 'x +`endif // SCR1_XPROP_EN +} type_scr1_op_width_e; + +`endif //SCR1_ARCH_TYPES_SVH diff --git a/src/rtl/scr1/scr1_cg.sv b/src/rtl/scr1/scr1_cg.sv new file mode 100644 index 0000000..0d9ddee --- /dev/null +++ b/src/rtl/scr1/scr1_cg.sv @@ -0,0 +1,32 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief SCR1 clock gate primitive +/// + +`include "scr1_arch_description.svh" + +`ifdef SCR1_CLKCTRL_EN +module scr1_cg ( + input logic clk, + input logic clk_en, + input logic test_mode, + output logic clk_out +); + +// The code below is a clock gate model for simulation. +// For synthesis, it should be replaced by implementation-specific +// clock gate code. + +logic latch_en; + +always_latch begin + if (~clk) begin + latch_en <= test_mode | clk_en; + end +end + +assign clk_out = latch_en & clk; + +endmodule : scr1_cg + +`endif // SCR1_CLKCTRL_EN diff --git a/src/rtl/scr1/scr1_clk_ctrl.sv b/src/rtl/scr1/scr1_clk_ctrl.sv new file mode 100644 index 0000000..914a684 --- /dev/null +++ b/src/rtl/scr1/scr1_clk_ctrl.sv @@ -0,0 +1,55 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief SCR1 clock control +/// + +`include "scr1_arch_description.svh" + +`ifdef SCR1_CLKCTRL_EN +module scr1_clk_ctrl ( + input logic clk, // Clock control module clock + input logic rst_n, // Clock control module reset + input logic test_mode, // DFT Test Mode + input logic test_rst_n, // DFT Test reset + + input logic pipe2clkctl_sleep_req_i, // CLK disable request from pipe + input logic pipe2clkctl_wake_req_i, // CLK enable request from pipe + + output logic clkctl2pipe_clk_alw_on_o, // Not gated pipe CLK + output logic clkctl2pipe_clk_o, // Gated pipe + output logic clkctl2pipe_clk_en_o, // CLK enabled flag + output logic clkctl2pipe_clk_dbgc_o // CLK for pipe debug subsystem +); + +logic ctrl_rst_n; + +assign clkctl2pipe_clk_alw_on_o = clk; +assign clkctl2pipe_clk_dbgc_o = clk; +assign ctrl_rst_n = (test_mode) ? test_rst_n : rst_n; + +always_ff @(posedge clk, negedge ctrl_rst_n) begin + if (~ctrl_rst_n) begin + clkctl2pipe_clk_en_o <= 1'b1; + end else begin + if (clkctl2pipe_clk_en_o) begin + if (pipe2clkctl_sleep_req_i & ~pipe2clkctl_wake_req_i) begin + clkctl2pipe_clk_en_o <= 1'b0; + end + end else begin // ~clkctl2pipe_clk_en_o + if (pipe2clkctl_wake_req_i) begin + clkctl2pipe_clk_en_o <= 1'b1; + end + end // pipeline + end +end + +scr1_cg i_scr1_cg_pipe ( + .clk (clk ), + .clk_en (clkctl2pipe_clk_en_o), + .test_mode (test_mode ), + .clk_out (clkctl2pipe_clk_o ) +); + +endmodule : scr1_clk_ctrl + +`endif // SCR1_CLKCTRL_EN diff --git a/src/rtl/scr1/scr1_core_top.sv b/src/rtl/scr1/scr1_core_top.sv new file mode 100644 index 0000000..518c1b8 --- /dev/null +++ b/src/rtl/scr1/scr1_core_top.sv @@ -0,0 +1,521 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief SCR1 core top +/// + +`include "scr1_arch_description.svh" +`include "scr1_arch_types.svh" +`include "scr1_memif.svh" + +`ifdef SCR1_DBG_EN +`include "scr1_tapc.svh" +`include "scr1_dm.svh" +`include "scr1_hdu.svh" +`endif // SCR1_DBG_EN + +`ifdef SCR1_IPIC_EN +`include "scr1_ipic.svh" +`endif // SCR1_IPIC_EN + +module scr1_core_top ( + // Common + 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, // Core clock + output logic core_rst_n_o, // Core reset + output logic core_rdc_qlfy_o, // Core RDC qualifier +`ifdef SCR1_DBG_EN + output logic sys_rst_n_o, // System reset + output logic sys_rdc_qlfy_o, // System RDC qualifier +`endif // SCR1_DBG_EN + + // Fuses + input logic [`SCR1_XLEN-1:0] core_fuse_mhartid_i, // Fuse MHARTID value +`ifdef SCR1_DBG_EN + input logic [31:0] tapc_fuse_idcode_i, // Fuse IDCODE value +`endif // SCR1_DBG_EN + + // IRQ +`ifdef SCR1_IPIC_EN + input logic [SCR1_IRQ_LINES_NUM-1:0] core_irq_lines_i, // External interrupt request lines +`else + input logic core_irq_ext_i, // External interrupt request +`endif // SCR1_IPIC_EN + input logic core_irq_soft_i, // Software generated interrupt request + input logic core_irq_mtimer_i, // Machine timer interrupt request + + // Memory-mapped external timer + input logic [63:0] core_mtimer_val_i, // Machine timer value + +`ifdef SCR1_DBG_EN + // Debug Interface + input logic tapc_trst_n, // Test Reset (TRSTn) + input logic tapc_tck, // Test Clock (TCK) + input logic tapc_tms, // Test Mode Select (TMS) + input logic tapc_tdi, // Test Data Input (TDI) + output logic tapc_tdo, // Test Data Output (TDO) + output logic tapc_tdo_en, // TDO Enable, signal for TDO buffer control +`endif // SCR1_DBG_EN + + // Instruction Memory Interface + input logic imem2core_req_ack_i, // IMEM request acknowledge + output logic core2imem_req_o, // IMEM request + output type_scr1_mem_cmd_e core2imem_cmd_o, // IMEM command + output logic [`SCR1_IMEM_AWIDTH-1:0] core2imem_addr_o, // IMEM address + input logic [`SCR1_IMEM_DWIDTH-1:0] imem2core_rdata_i, // IMEM read data + input type_scr1_mem_resp_e imem2core_resp_i, // IMEM response + + // Data Memory Interface + input logic dmem2core_req_ack_i, // DMEM request acknowledge + output logic core2dmem_req_o, // DMEM request + output type_scr1_mem_cmd_e core2dmem_cmd_o, // DMEM command + output type_scr1_mem_width_e core2dmem_width_o, // DMEM data width + output logic [`SCR1_DMEM_AWIDTH-1:0] core2dmem_addr_o, // DMEM address + output logic [`SCR1_DMEM_DWIDTH-1:0] core2dmem_wdata_o, // DMEM write data + input logic [`SCR1_DMEM_DWIDTH-1:0] dmem2core_rdata_i, // DMEM read data + input type_scr1_mem_resp_e dmem2core_resp_i // DMEM response +); + +//------------------------------------------------------------------------------- +// Local parameters +//------------------------------------------------------------------------------- +localparam int unsigned SCR1_CORE_TOP_RST_SYNC_STAGES_NUM = 2; + +//------------------------------------------------------------------------------- +// Local signals declaration +//------------------------------------------------------------------------------- + +// Reset Logic +`ifdef SCR1_DBG_EN +`else // SCR1_DBG_EN +logic core_rst_n_in_sync; +logic core_rst_n_qlfy; +logic core_rst_n_status; +`endif // SCR1_DBG_EN +logic core_rst_n; +logic core_rst_n_status_sync; +logic core_rst_status; +logic core2hdu_rdc_qlfy; +logic core2dm_rdc_qlfy; +logic pwrup_rst_n_sync; +logic rst_n_sync; +logic cpu_rst_n_sync; + +`ifdef SCR1_DBG_EN +// TAPC-DM Interface +logic tapc_dmi_ch_sel; +logic [SCR1_DBG_DMI_CH_ID_WIDTH-1:0] tapc_dmi_ch_id; +logic tapc_dmi_ch_capture; +logic tapc_dmi_ch_shift; +logic tapc_dmi_ch_update; +logic tapc_dmi_ch_tdi; +logic tapc_dmi_ch_tdo; +// +logic tapc_dmi_ch_sel_tapout; +logic [SCR1_DBG_DMI_CH_ID_WIDTH-1:0] tapc_dmi_ch_id_tapout; +logic tapc_dmi_ch_capture_tapout; +logic tapc_dmi_ch_shift_tapout; +logic tapc_dmi_ch_update_tapout; +logic tapc_dmi_ch_tdi_tapout; +logic tapc_dmi_ch_tdo_tapin; +// +logic dmi_req; +logic dmi_wr; +logic [SCR1_DBG_DMI_ADDR_WIDTH-1:0] dmi_addr; +logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dmi_wdata; +logic dmi_resp; +logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dmi_rdata; +// TAPC-SCU Interface +logic tapc_scu_ch_sel; +logic tapc_scu_ch_sel_tapout; +logic tapc_scu_ch_tdo; +logic tapc_ch_tdo; +// SCU nets +logic sys_rst_n; +logic sys_rst_status; +logic hdu_rst_n; +logic hdu2dm_rdc_qlfy; +logic ndm_rst_n; +logic dm_rst_n; +logic hart_rst_n; +`endif // SCR1_DBG_EN + +`ifdef SCR1_DBG_EN +// DM-Pipeline Interface +// HART Run Control i/f +logic dm_active; +logic dm_cmd_req; +type_scr1_hdu_dbgstates_e dm_cmd; +logic dm_cmd_resp; +logic dm_cmd_resp_qlfy; +logic dm_cmd_rcode; +logic dm_hart_event; +logic dm_hart_event_qlfy; +type_scr1_hdu_hartstatus_s dm_hart_status; +type_scr1_hdu_hartstatus_s dm_hart_status_qlfy; + +// Program Buffer - HART instruction execution i/f +logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] dm_pbuf_addr; +logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] dm_pbuf_addr_qlfy; +logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] dm_pbuf_instr; + +// HART Abstract Data regs i/f +logic dm_dreg_req; +logic dm_dreg_req_qlfy; +logic dm_dreg_wr; +logic [SCR1_HDU_DATA_REG_WIDTH-1:0] dm_dreg_wdata; +logic dm_dreg_resp; +logic dm_dreg_fail; +logic [SCR1_HDU_DATA_REG_WIDTH-1:0] dm_dreg_rdata; + +logic [`SCR1_XLEN-1 : 0] dm_pc_sample; +logic [`SCR1_XLEN-1 : 0] dm_pc_sample_qlfy; +`endif // SCR1_DBG_EN + +`ifdef SCR1_CLKCTRL_EN +// Global clock gating logic +logic sleep_pipe; +logic wake_pipe; +logic clk_pipe; +logic clk_pipe_en; +logic clk_dbgc; +logic clk_alw_on; +`endif // SCR1_CLKCTRL_EN + + +//------------------------------------------------------------------------------- +// Reset Logic +//------------------------------------------------------------------------------- +`ifdef SCR1_DBG_EN +scr1_scu i_scu ( + // Global signals + .pwrup_rst_n (pwrup_rst_n ), + .rst_n (rst_n ), + .cpu_rst_n (cpu_rst_n ), + .test_mode (test_mode ), + .test_rst_n (test_rst_n ), + .clk (clk ), + + // TAPC scan-chains + .tapcsync2scu_ch_sel_i (tapc_scu_ch_sel ), + .tapcsync2scu_ch_id_i ('0 ), + .tapcsync2scu_ch_capture_i (tapc_dmi_ch_capture), + .tapcsync2scu_ch_shift_i (tapc_dmi_ch_shift ), + .tapcsync2scu_ch_update_i (tapc_dmi_ch_update ), + .tapcsync2scu_ch_tdi_i (tapc_dmi_ch_tdi ), + .scu2tapcsync_ch_tdo_o (tapc_scu_ch_tdo ), + + // Input sync resets: + .ndm_rst_n_i (ndm_rst_n ), + .hart_rst_n_i (hart_rst_n ), + + // Generated resets + .sys_rst_n_o (sys_rst_n ), + .core_rst_n_o (core_rst_n ), + .dm_rst_n_o (dm_rst_n ), + .hdu_rst_n_o (hdu_rst_n ), + + // Resets statuses + .sys_rst_status_o (sys_rst_status ), + .core_rst_status_o (core_rst_status ), + + // Reset Domain Crossing (RDC) qualifiers + .sys_rdc_qlfy_o (sys_rdc_qlfy_o ), + .core_rdc_qlfy_o (core_rdc_qlfy_o ), + .core2hdu_rdc_qlfy_o (core2hdu_rdc_qlfy ), + .core2dm_rdc_qlfy_o (core2dm_rdc_qlfy ), + .hdu2dm_rdc_qlfy_o (hdu2dm_rdc_qlfy ) +); + +assign sys_rst_n_o = sys_rst_n; + +// Reset inputs are assumed synchronous +assign pwrup_rst_n_sync = pwrup_rst_n; + +`else // SCR1_DBG_EN + +// 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; +assign core_rst_n_in_sync = rst_n_sync & cpu_rst_n_sync; + +// Core Reset: core_rst_n +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 ), + .reset_n_status (core_rst_n_status ) +); + +scr1_data_sync_cell #( + .STAGES_AMOUNT (SCR1_CORE_TOP_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 = ~core_rst_n_status_sync; +assign core_rdc_qlfy_o = core_rst_n_qlfy; + +`endif // SCR1_DBG_EN +assign core_rst_n_o = core_rst_n; + +//------------------------------------------------------------------------------- +// SCR1 pipeline +//------------------------------------------------------------------------------- +scr1_pipe_top i_pipe_top ( + // Control + .pipe_rst_n (core_rst_n ), +`ifdef SCR1_DBG_EN + .pipe2hdu_rdc_qlfy_i (core2hdu_rdc_qlfy ), + .dbg_rst_n (hdu_rst_n ), +`endif // SCR1_DBG_EN +`ifndef SCR1_CLKCTRL_EN + .clk (clk ), +`else // SCR1_CLKCTRL_EN + .clk (clk_pipe ), + .pipe2clkctl_sleep_req_o (sleep_pipe ), + .pipe2clkctl_wake_req_o (wake_pipe ), + .clkctl2pipe_clk_alw_on_i (clk_alw_on ), + .clkctl2pipe_clk_dbgc_i (clk_dbgc ), + .clkctl2pipe_clk_en_i (clk_pipe_en ), +`endif // SCR1_CLKCTRL_EN + + // Instruction memory interface + .pipe2imem_req_o (core2imem_req_o ), + .pipe2imem_cmd_o (core2imem_cmd_o ), + .pipe2imem_addr_o (core2imem_addr_o ), + .imem2pipe_req_ack_i (imem2core_req_ack_i ), + .imem2pipe_rdata_i (imem2core_rdata_i ), + .imem2pipe_resp_i (imem2core_resp_i ), + + // Data memory interface + .pipe2dmem_req_o (core2dmem_req_o ), + .pipe2dmem_cmd_o (core2dmem_cmd_o ), + .pipe2dmem_width_o (core2dmem_width_o ), + .pipe2dmem_addr_o (core2dmem_addr_o ), + .pipe2dmem_wdata_o (core2dmem_wdata_o ), + .dmem2pipe_req_ack_i (dmem2core_req_ack_i ), + .dmem2pipe_rdata_i (dmem2core_rdata_i ), + .dmem2pipe_resp_i (dmem2core_resp_i ), + +`ifdef SCR1_DBG_EN + // Debug interface: + .dbg_en (1'b1 ), + // Debug interface: + // DM <-> Pipeline: HART Run Control i/f + .dm2pipe_active_i (dm_active ), + .dm2pipe_cmd_req_i (dm_cmd_req ), + .dm2pipe_cmd_i (dm_cmd ), + .pipe2dm_cmd_resp_o (dm_cmd_resp ), + .pipe2dm_cmd_rcode_o (dm_cmd_rcode ), + .pipe2dm_hart_event_o (dm_hart_event ), + .pipe2dm_hart_status_o (dm_hart_status ), + + // DM <-> Pipeline: Program Buffer - HART instruction execution i/f + .pipe2dm_pbuf_addr_o (dm_pbuf_addr ), + .dm2pipe_pbuf_instr_i (dm_pbuf_instr ), + + // DM <-> Pipeline: HART Abstract Data regs i/f + .pipe2dm_dreg_req_o (dm_dreg_req ), + .pipe2dm_dreg_wr_o (dm_dreg_wr ), + .pipe2dm_dreg_wdata_o (dm_dreg_wdata ), + .dm2pipe_dreg_resp_i (dm_dreg_resp ), + .dm2pipe_dreg_fail_i (dm_dreg_fail ), + .dm2pipe_dreg_rdata_i (dm_dreg_rdata ), + + // DM <-> Pipeline: PC i/f + .pipe2dm_pc_sample_o (dm_pc_sample ), +`endif // SCR1_DBG_EN + + // IRQ +`ifdef SCR1_IPIC_EN + .soc2pipe_irq_lines_i (core_irq_lines_i ), +`else // SCR1_IPIC_EN + .soc2pipe_irq_ext_i (core_irq_ext_i ), +`endif // SCR1_IPIC_EN + .soc2pipe_irq_soft_i (core_irq_soft_i ), + .soc2pipe_irq_mtimer_i (core_irq_mtimer_i ), + + // Memory-mapped external timer + .soc2pipe_mtimer_val_i (core_mtimer_val_i ), + + // Fuse + .soc2pipe_fuse_mhartid_i (core_fuse_mhartid_i ) +); + + +`ifdef SCR1_DBG_EN +//------------------------------------------------------------------------------- +// TAP Controller (TAPC) +//------------------------------------------------------------------------------- +scr1_tapc i_tapc ( + // JTAG signals + .tapc_trst_n (tapc_trst_n ), + .tapc_tck (tapc_tck ), + .tapc_tms (tapc_tms ), + .tapc_tdi (tapc_tdi ), + .tapc_tdo (tapc_tdo ), + .tapc_tdo_en (tapc_tdo_en ), + + // Fuses + .soc2tapc_fuse_idcode_i (tapc_fuse_idcode_i ), + + // DMI/SCU scan-chains + .tapc2tapcsync_scu_ch_sel_o (tapc_scu_ch_sel_tapout ), + .tapc2tapcsync_dmi_ch_sel_o (tapc_dmi_ch_sel_tapout ), + .tapc2tapcsync_ch_id_o (tapc_dmi_ch_id_tapout ), + .tapc2tapcsync_ch_capture_o (tapc_dmi_ch_capture_tapout), + .tapc2tapcsync_ch_shift_o (tapc_dmi_ch_shift_tapout ), + .tapc2tapcsync_ch_update_o (tapc_dmi_ch_update_tapout ), + .tapc2tapcsync_ch_tdi_o (tapc_dmi_ch_tdi_tapout ), + .tapcsync2tapc_ch_tdo_i (tapc_dmi_ch_tdo_tapin ) +); + +scr1_tapc_synchronizer i_tapc_synchronizer ( + // System common signals + .pwrup_rst_n (pwrup_rst_n_sync ), + .dm_rst_n (dm_rst_n ), + .clk (clk ), + + // JTAG common signals + .tapc_trst_n (tapc_trst_n ), + .tapc_tck (tapc_tck ), + + // DMI/SCU scan-chains + .tapc2tapcsync_scu_ch_sel_i (tapc_scu_ch_sel_tapout ), + .tapcsync2scu_ch_sel_o (tapc_scu_ch_sel ), + .tapc2tapcsync_dmi_ch_sel_i (tapc_dmi_ch_sel_tapout ), + .tapcsync2dmi_ch_sel_o (tapc_dmi_ch_sel ), + + .tapc2tapcsync_ch_id_i (tapc_dmi_ch_id_tapout ), + .tapcsync2core_ch_id_o (tapc_dmi_ch_id ), + .tapc2tapcsync_ch_capture_i (tapc_dmi_ch_capture_tapout), + .tapcsync2core_ch_capture_o (tapc_dmi_ch_capture ), + .tapc2tapcsync_ch_shift_i (tapc_dmi_ch_shift_tapout ), + .tapcsync2core_ch_shift_o (tapc_dmi_ch_shift ), + .tapc2tapcsync_ch_update_i (tapc_dmi_ch_update_tapout ), + .tapcsync2core_ch_update_o (tapc_dmi_ch_update ), + .tapc2tapcsync_ch_tdi_i (tapc_dmi_ch_tdi_tapout ), + .tapcsync2core_ch_tdi_o (tapc_dmi_ch_tdi ), + .tapc2tapcsync_ch_tdo_i (tapc_dmi_ch_tdo_tapin ), + .tapcsync2core_ch_tdo_o (tapc_ch_tdo ) +); +assign tapc_ch_tdo = (tapc_scu_ch_tdo & tapc_scu_ch_sel) + | (tapc_dmi_ch_tdo & tapc_dmi_ch_sel); + +scr1_dmi i_dmi ( + .rst_n (dm_rst_n ), + .clk (clk ), + + // TAP scan-chains + .tapcsync2dmi_ch_sel_i (tapc_dmi_ch_sel ), + .tapcsync2dmi_ch_id_i (tapc_dmi_ch_id ), + .tapcsync2dmi_ch_capture_i (tapc_dmi_ch_capture), + .tapcsync2dmi_ch_shift_i (tapc_dmi_ch_shift ), + .tapcsync2dmi_ch_update_i (tapc_dmi_ch_update ), + .tapcsync2dmi_ch_tdi_i (tapc_dmi_ch_tdi ), + .dmi2tapcsync_ch_tdo_o (tapc_dmi_ch_tdo ), + + // DMI + .dm2dmi_resp_i (dmi_resp ), + .dm2dmi_rdata_i (dmi_rdata ), + .dmi2dm_req_o (dmi_req ), + .dmi2dm_wr_o (dmi_wr ), + .dmi2dm_addr_o (dmi_addr ), + .dmi2dm_wdata_o (dmi_wdata ) +); + +`endif // SCR1_DBG_EN + + +`ifdef SCR1_DBG_EN + +//------------------------------------------------------------------------------- +// Debug Module (DM) +//------------------------------------------------------------------------------- +assign dm_cmd_resp_qlfy = dm_cmd_resp & {$bits(dm_cmd_resp){hdu2dm_rdc_qlfy}}; +assign dm_hart_event_qlfy = dm_hart_event & {$bits(dm_hart_event){hdu2dm_rdc_qlfy}}; +assign dm_hart_status_qlfy.dbg_state = hdu2dm_rdc_qlfy ? dm_hart_status.dbg_state + : SCR1_HDU_DBGSTATE_RESET; +assign dm_hart_status_qlfy.except = dm_hart_status.except; +assign dm_hart_status_qlfy.ebreak = dm_hart_status.ebreak; +assign dm_pbuf_addr_qlfy = dm_pbuf_addr & {$bits(dm_pbuf_addr){hdu2dm_rdc_qlfy}}; +assign dm_dreg_req_qlfy = dm_dreg_req & {$bits(dm_dreg_req){hdu2dm_rdc_qlfy}}; +assign dm_pc_sample_qlfy = dm_pc_sample & {$bits(dm_pc_sample){core2dm_rdc_qlfy}}; + +scr1_dm i_dm ( + // Common signals + .rst_n (dm_rst_n ), + .clk (clk ), + + // DM internal interface + .dmi2dm_req_i (dmi_req ), + .dmi2dm_wr_i (dmi_wr ), + .dmi2dm_addr_i (dmi_addr ), + .dmi2dm_wdata_i (dmi_wdata ), + .dm2dmi_resp_o (dmi_resp ), + .dm2dmi_rdata_o (dmi_rdata ), + + // DM <-> Pipeline: HART Run Control i/f + .ndm_rst_n_o (ndm_rst_n ), + .hart_rst_n_o (hart_rst_n ), + .dm2pipe_active_o (dm_active ), + .dm2pipe_cmd_req_o (dm_cmd_req ), + .dm2pipe_cmd_o (dm_cmd ), + .pipe2dm_cmd_resp_i (dm_cmd_resp_qlfy ), + .pipe2dm_cmd_rcode_i (dm_cmd_rcode ), + .pipe2dm_hart_event_i (dm_hart_event_qlfy ), + .pipe2dm_hart_status_i (dm_hart_status_qlfy ), + + .soc2dm_fuse_mhartid_i (core_fuse_mhartid_i ), + .pipe2dm_pc_sample_i (dm_pc_sample_qlfy ), + + // DM <-> Pipeline: HART Abstract Command / Program Buffer i/f + .pipe2dm_pbuf_addr_i (dm_pbuf_addr_qlfy ), + .dm2pipe_pbuf_instr_o (dm_pbuf_instr ), + + // DM <-> Pipeline: HART Abstract Data regs i/f + .pipe2dm_dreg_req_i (dm_dreg_req_qlfy ), + .pipe2dm_dreg_wr_i (dm_dreg_wr ), + .pipe2dm_dreg_wdata_i (dm_dreg_wdata ), + .dm2pipe_dreg_resp_o (dm_dreg_resp ), + .dm2pipe_dreg_fail_o (dm_dreg_fail ), + .dm2pipe_dreg_rdata_o (dm_dreg_rdata ) +); +`endif // SCR1_DBG_EN + + +`ifdef SCR1_CLKCTRL_EN +//------------------------------------------------------------------------------- +// Global clock gating logic +//------------------------------------------------------------------------------- +scr1_clk_ctrl i_clk_ctrl ( + .clk (clk ), + .rst_n (core_rst_n ), + .test_mode (test_mode ), + .test_rst_n (test_rst_n ), + + // Sleep/wake interface + .pipe2clkctl_sleep_req_i (sleep_pipe ), + .pipe2clkctl_wake_req_i (wake_pipe ), + + // Clocks + .clkctl2pipe_clk_alw_on_o (clk_alw_on ), + .clkctl2pipe_clk_o (clk_pipe ), + .clkctl2pipe_clk_en_o (clk_pipe_en), + .clkctl2pipe_clk_dbgc_o (clk_dbgc ) +); +`endif // SCR1_CLKCTRL_EN + +endmodule : scr1_core_top diff --git a/src/rtl/scr1/scr1_csr.svh b/src/rtl/scr1/scr1_csr.svh new file mode 100644 index 0000000..cbdfe43 --- /dev/null +++ b/src/rtl/scr1/scr1_csr.svh @@ -0,0 +1,196 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief CSR mapping/description file +/// + +`ifndef SCR1_CSR_SVH +`define SCR1_CSR_SVH + +`include "scr1_arch_description.svh" +`include "scr1_arch_types.svh" +`include "scr1_ipic.svh" + +`ifdef SCR1_RVE_EXT +`define SCR1_CSR_REDUCED_CNT +`endif // SCR1_RVE_EXT + +`ifdef SCR1_CSR_REDUCED_CNT +`undef SCR1_MCOUNTEN_EN +`endif // SCR1_CSR_REDUCED_CNT + +//------------------------------------------------------------------------------- +// CSR addresses (standard) +//------------------------------------------------------------------------------- + +// Machine Information Registers (read-only) +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MVENDORID = SCR1_CSR_ADDR_WIDTH'('hF11); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MARCHID = SCR1_CSR_ADDR_WIDTH'('hF12); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MIMPID = SCR1_CSR_ADDR_WIDTH'('hF13); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MHARTID = SCR1_CSR_ADDR_WIDTH'('hF14); + +// Machine Trap Setup (read-write) +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MSTATUS = SCR1_CSR_ADDR_WIDTH'('h300); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MISA = SCR1_CSR_ADDR_WIDTH'('h301); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MIE = SCR1_CSR_ADDR_WIDTH'('h304); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MTVEC = SCR1_CSR_ADDR_WIDTH'('h305); + +// Machine Trap Handling (read-write) +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MSCRATCH = SCR1_CSR_ADDR_WIDTH'('h340); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MEPC = SCR1_CSR_ADDR_WIDTH'('h341); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MCAUSE = SCR1_CSR_ADDR_WIDTH'('h342); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MTVAL = SCR1_CSR_ADDR_WIDTH'('h343); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MIP = SCR1_CSR_ADDR_WIDTH'('h344); + +// Machine Counters/Timers (read-write) +`ifndef SCR1_CSR_REDUCED_CNT +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MCYCLE = SCR1_CSR_ADDR_WIDTH'('hB00); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MINSTRET = SCR1_CSR_ADDR_WIDTH'('hB02); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MCYCLEH = SCR1_CSR_ADDR_WIDTH'('hB80); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MINSTRETH = SCR1_CSR_ADDR_WIDTH'('hB82); +`endif // SCR1_CSR_REDUCED_CNT + +// Shadow Counters/Timers (read-only) +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_TIME = SCR1_CSR_ADDR_WIDTH'('hC01); +`ifndef SCR1_CSR_REDUCED_CNT +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_CYCLE = SCR1_CSR_ADDR_WIDTH'('hC00); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_INSTRET = SCR1_CSR_ADDR_WIDTH'('hC02); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_TIMEH = SCR1_CSR_ADDR_WIDTH'('hC81); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_CYCLEH = SCR1_CSR_ADDR_WIDTH'('hC80); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_INSTRETH = SCR1_CSR_ADDR_WIDTH'('hC82); +`endif // SCR1_CSR_REDUCED_CNT + +`ifdef SCR1_DBG_EN +//parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_DBGC_SCRATCH = 'h7C8; +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_HDU_MBASE = SCR1_CSR_ADDR_WIDTH'('h7B0); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_HDU_MSPAN = SCR1_CSR_ADDR_WIDTH'('h004); // must be power of 2 +`endif // SCR1_DBG_EN + +//------------------------------------------------------------------------------- +// CSR addresses (non-standard) +//------------------------------------------------------------------------------- +`ifdef SCR1_MCOUNTEN_EN +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MCOUNTEN = SCR1_CSR_ADDR_WIDTH'('h7E0); +`endif // SCR1_MCOUNTEN_EN + +`ifdef SCR1_TDU_EN +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_TDU_MBASE = SCR1_CSR_ADDR_WIDTH'('h7A0); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_TDU_MSPAN = SCR1_CSR_ADDR_WIDTH'('h008); // must be power of 2 +`endif // SCR1_TDU_EN + +`ifdef SCR1_IPIC_EN +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_IPIC_BASE = SCR1_CSR_ADDR_WIDTH'('hBF0); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_IPIC_CISV = (SCR1_CSR_ADDR_IPIC_BASE + SCR1_IPIC_CISV ); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_IPIC_CICSR = (SCR1_CSR_ADDR_IPIC_BASE + SCR1_IPIC_CICSR); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_IPIC_IPR = (SCR1_CSR_ADDR_IPIC_BASE + SCR1_IPIC_IPR ); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_IPIC_ISVR = (SCR1_CSR_ADDR_IPIC_BASE + SCR1_IPIC_ISVR ); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_IPIC_EOI = (SCR1_CSR_ADDR_IPIC_BASE + SCR1_IPIC_EOI ); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_IPIC_SOI = (SCR1_CSR_ADDR_IPIC_BASE + SCR1_IPIC_SOI ); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_IPIC_IDX = (SCR1_CSR_ADDR_IPIC_BASE + SCR1_IPIC_IDX ); +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_IPIC_ICSR = (SCR1_CSR_ADDR_IPIC_BASE + SCR1_IPIC_ICSR ); +`endif // SCR1_IPIC_EN + + +//------------------------------------------------------------------------------- +// CSR definitions +//------------------------------------------------------------------------------- + +// General +parameter bit [`SCR1_XLEN-1:0] SCR1_RST_VECTOR = SCR1_ARCH_RST_VECTOR; + +// Reset values +parameter bit SCR1_CSR_MIE_MSIE_RST_VAL = 1'b0; +parameter bit SCR1_CSR_MIE_MTIE_RST_VAL = 1'b0; +parameter bit SCR1_CSR_MIE_MEIE_RST_VAL = 1'b0; + +parameter bit SCR1_CSR_MIP_MSIP_RST_VAL = 1'b0; +parameter bit SCR1_CSR_MIP_MTIP_RST_VAL = 1'b0; +parameter bit SCR1_CSR_MIP_MEIP_RST_VAL = 1'b0; + +parameter bit SCR1_CSR_MSTATUS_MIE_RST_VAL = 1'b0; +parameter bit SCR1_CSR_MSTATUS_MPIE_RST_VAL = 1'b1; + +// MISA +`define SCR1_RVC_ENC `SCR1_XLEN'h0004 +`define SCR1_RVE_ENC `SCR1_XLEN'h0010 +`define SCR1_RVI_ENC `SCR1_XLEN'h0100 +`define SCR1_RVM_ENC `SCR1_XLEN'h1000 +parameter bit [1:0] SCR1_MISA_MXL_32 = 2'd1; +parameter bit [`SCR1_XLEN-1:0] SCR1_CSR_MISA = (SCR1_MISA_MXL_32 << (`SCR1_XLEN-2)) +`ifndef SCR1_RVE_EXT + | `SCR1_RVI_ENC +`else // SCR1_RVE_EXT + | `SCR1_RVE_ENC +`endif // SCR1_RVE_EXT +`ifdef SCR1_RVC_EXT + | `SCR1_RVC_ENC +`endif // SCR1_RVC_EXT +`ifdef SCR1_RVM_EXT + | `SCR1_RVM_ENC +`endif // SCR1_RVM_EXT + ; + +// MVENDORID +parameter bit [`SCR1_XLEN-1:0] SCR1_CSR_MVENDORID = `SCR1_MVENDORID; + +// MARCHID +parameter bit [`SCR1_XLEN-1:0] SCR1_CSR_MARCHID = `SCR1_XLEN'd8; + +// MIMPID +parameter bit [`SCR1_XLEN-1:0] SCR1_CSR_MIMPID = `SCR1_MIMPID; + +// MSTATUS +parameter bit [1:0] SCR1_CSR_MSTATUS_MPP = 2'b11; +parameter int unsigned SCR1_CSR_MSTATUS_MIE_OFFSET = 3; +parameter int unsigned SCR1_CSR_MSTATUS_MPIE_OFFSET = 7; +parameter int unsigned SCR1_CSR_MSTATUS_MPP_OFFSET = 11; + +// MTVEC +// bits [5:0] are always zero +parameter bit [`SCR1_XLEN-1:SCR1_CSR_MTVEC_BASE_ZERO_BITS] SCR1_CSR_MTVEC_BASE_RST_VAL = SCR1_CSR_MTVEC_BASE_WR_RST_VAL; + +parameter bit SCR1_CSR_MTVEC_MODE_DIRECT = 1'b0; +`ifdef SCR1_MTVEC_MODE_EN +parameter bit SCR1_CSR_MTVEC_MODE_VECTORED = 1'b1; +`endif // SCR1_MTVEC_MODE_EN + +// MIE, MIP +parameter int unsigned SCR1_CSR_MIE_MSIE_OFFSET = 3; +parameter int unsigned SCR1_CSR_MIE_MTIE_OFFSET = 7; +parameter int unsigned SCR1_CSR_MIE_MEIE_OFFSET = 11; + +`ifdef SCR1_MCOUNTEN_EN +// MCOUNTEN +parameter int unsigned SCR1_CSR_MCOUNTEN_CY_OFFSET = 0; +parameter int unsigned SCR1_CSR_MCOUNTEN_IR_OFFSET = 2; +`endif // SCR1_MCOUNTEN_EN + +// MCAUSE +typedef logic [`SCR1_XLEN-2:0] type_scr1_csr_mcause_ec_v; + +// MCYCLE, MINSTRET +`ifdef SCR1_CSR_REDUCED_CNT +parameter int unsigned SCR1_CSR_COUNTERS_WIDTH = 32; +`else // ~SCR1_CSR_REDUCED_CNT +parameter int unsigned SCR1_CSR_COUNTERS_WIDTH = 64; +`endif // ~SCR1_CSR_REDUCED_CNT + +// HPM +parameter bit [6:0] SCR1_CSR_ADDR_HPMCOUNTER_MASK = 7'b1100000; +parameter bit [6:0] SCR1_CSR_ADDR_HPMCOUNTERH_MASK = 7'b1100100; +parameter bit [6:0] SCR1_CSR_ADDR_MHPMCOUNTER_MASK = 7'b1011000; +parameter bit [6:0] SCR1_CSR_ADDR_MHPMCOUNTERH_MASK = 7'b1011100; +parameter bit [6:0] SCR1_CSR_ADDR_MHPMEVENT_MASK = 7'b0011001; + +//------------------------------------------------------------------------------- +// Types declaration +//------------------------------------------------------------------------------- +typedef enum logic { + SCR1_CSR_RESP_OK, + SCR1_CSR_RESP_ER +`ifdef SCR1_XPROP_EN + , + SCR1_CSR_RESP_ERROR = 'x +`endif // SCR1_XPROP_EN +} type_scr1_csr_resp_e; + +`endif // SCR1_CSR_SVH diff --git a/src/rtl/scr1/scr1_dm.sv b/src/rtl/scr1/scr1_dm.sv new file mode 100644 index 0000000..cc42a94 --- /dev/null +++ b/src/rtl/scr1/scr1_dm.sv @@ -0,0 +1,1427 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Debug Module (DM) +/// + +//------------------------------------------------------------------------------ + // + // Functionality: + // - Allows debugger to perform a system reset (ndm_rst) + // - Allows debugger to control the HART's state + // - Provides debugger with information about the current HART's state + // - Provides debugger with Abstract Command interface that allows to: + // - Access MPRF registers + // - Access CSR registers + // - Access memory with the same view and permission as the hart has + // - Provides debugger with Abstract Command status information (busy flag and error code) + // - Provides debugger with Program Buffer functionality that allows to execute + // small programs on a halted HART + // + // Structure: + // - DM <-> DMI interface + // - DM registers: + // - DMCONTROL + // - DMSTATUS + // - Abstract Command Control logic + // - Abstract Command FSM + // - Abstract Command Status logic + // - Abstract Instruction logic + // - Abstract registers: + // - COMMAND + // - ABSTRACTAUTO + // - PROGBUF0..5 + // - DATA0..1 + // - DHI FSM + // - HART command registers + // - DHI interface + // +// + +`include "scr1_arch_description.svh" + +`ifdef SCR1_DBG_EN +`include "scr1_csr.svh" +`include "scr1_dm.svh" + +module scr1_dm ( + // System + input logic rst_n, // DM reset + input logic clk, // DM clock + + // DM internal interface + input logic dmi2dm_req_i, // DMI request + input logic dmi2dm_wr_i, // DMI write + input logic [SCR1_DBG_DMI_ADDR_WIDTH-1:0] dmi2dm_addr_i, // DMI address + input logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dmi2dm_wdata_i, // DMI write data + output logic dm2dmi_resp_o, // DMI response + output logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dm2dmi_rdata_o, // DMI read data + + // DM <-> Pipeline: HART Run Control i/f + output logic ndm_rst_n_o, // Non-DM Reset output + output logic hart_rst_n_o, // HART reset output + output logic dm2pipe_active_o, // Debug Module active flag + output logic dm2pipe_cmd_req_o, // Request to pipe + output type_scr1_hdu_dbgstates_e dm2pipe_cmd_o, // Command to pipe + input logic pipe2dm_cmd_resp_i, // Response to Debug Module + input logic pipe2dm_cmd_rcode_i, // HART Command return code: 0 - Ok; 1 - Error + input logic pipe2dm_hart_event_i, // HART event flag + input type_scr1_hdu_hartstatus_s pipe2dm_hart_status_i, // HART Status + + input logic [`SCR1_XLEN-1:0] soc2dm_fuse_mhartid_i, // RO MHARTID value + input logic [`SCR1_XLEN-1:0] pipe2dm_pc_sample_i, // RO PC value for sampling + + // HART Abstract Command / Program Buffer i/f + input logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] pipe2dm_pbuf_addr_i, // Program Buffer address + output logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] dm2pipe_pbuf_instr_o, // Program Buffer instruction + + // HART Abstract Data regs i/f + input logic pipe2dm_dreg_req_i, // Abstract Data Register request + input logic pipe2dm_dreg_wr_i, // Abstract Data Register write + input logic [`SCR1_XLEN-1:0] pipe2dm_dreg_wdata_i, // Abstract Data Register write data + output logic dm2pipe_dreg_resp_o, // Abstract Data Register response + output logic dm2pipe_dreg_fail_o, // Abstract Data Register fail - possibly not needed ? + output logic [`SCR1_XLEN-1:0] dm2pipe_dreg_rdata_o // Abstract Data Register read data +); + +//------------------------------------------------------------------------------ +// Local types declaration +//------------------------------------------------------------------------------ + +typedef enum logic [3:0] { + ABS_STATE_IDLE, + ABS_STATE_ERR, + ABS_STATE_EXEC, + ABS_STATE_XREG_RW, + ABS_STATE_MEM_SAVE_XREG, + ABS_STATE_MEM_SAVE_XREG_FORADDR, + ABS_STATE_MEM_RW, + ABS_STATE_MEM_RETURN_XREG, + ABS_STATE_MEM_RETURN_XREG_FORADDR, + ABS_STATE_CSR_RO, + ABS_STATE_CSR_SAVE_XREG, + ABS_STATE_CSR_RW, + ABS_STATE_CSR_RETURN_XREG +} type_scr1_abs_fsm_e; + +typedef enum logic [2:0] { + DHI_STATE_IDLE, + DHI_STATE_EXEC, + DHI_STATE_EXEC_RUN, + DHI_STATE_EXEC_HALT, + DHI_STATE_HALT_REQ, + DHI_STATE_RESUME_REQ, + DHI_STATE_RESUME_RUN +} type_scr1_dhi_fsm_e; + +typedef enum logic [SCR1_DBG_ABSTRACTCS_CMDERR_WDTH:0] { + ABS_ERR_NONE = (SCR1_DBG_ABSTRACTCS_CMDERR_WDTH+1)'('d0), + ABS_ERR_BUSY = (SCR1_DBG_ABSTRACTCS_CMDERR_WDTH+1)'('d1), + ABS_ERR_CMD = (SCR1_DBG_ABSTRACTCS_CMDERR_WDTH+1)'('d2), + ABS_ERR_EXCEPTION = (SCR1_DBG_ABSTRACTCS_CMDERR_WDTH+1)'('d3), + ABS_ERR_NOHALT = (SCR1_DBG_ABSTRACTCS_CMDERR_WDTH+1)'('d4) +} type_scr1_abs_err_e; + + +//------------------------------------------------------------------------------ +// Local parameters declaration +//------------------------------------------------------------------------------ + +// Abstract instruction opcode parameters +localparam SCR1_OP_SYSTEM = 7'b111_0011; +localparam SCR1_OP_LOAD = 7'b000_0011; +localparam SCR1_OP_STORE = 7'b010_0011; + +// Abstract instruction funct3 parameters +localparam SCR1_FUNCT3_CSRRW = 3'b001; +localparam SCR1_FUNCT3_CSRRS = 3'b010; +localparam SCR1_FUNCT3_SB = 3'b000; +localparam SCR1_FUNCT3_SH = 3'b001; +localparam SCR1_FUNCT3_SW = 3'b010; +localparam SCR1_FUNCT3_LW = 3'b010; +localparam SCR1_FUNCT3_LBU = 3'b100; +localparam SCR1_FUNCT3_LHU = 3'b101; + +// DMCONTROL parameters +//------------------------------------------------------------------------------ +localparam DMCONTROL_HARTRESET = 1'd0; +localparam DMCONTROL_RESERVEDB = 1'd0; +localparam DMCONTROL_HASEL = 1'd0; +localparam DMCONTROL_HARTSELLO = 1'd0; +localparam DMCONTROL_HARTSELHI = 1'd0; +localparam DMCONTROL_RESERVEDA = 1'd0; + +// DMSTATUS parameters +//------------------------------------------------------------------------------ +localparam DMSTATUS_RESERVEDC = 1'd0; +localparam DMSTATUS_IMPEBREAK = 1'd1; +localparam DMSTATUS_RESERVEDB = 1'd0; +localparam DMSTATUS_ALLUNAVAIL = 1'd0; +localparam DMSTATUS_ANYUNAVAIL = 1'd0; +localparam DMSTATUS_ALLANYUNAVAIL = 1'd0; +localparam DMSTATUS_ALLANYNONEXIST = 1'b0; +localparam DMSTATUS_AUTHENTICATED = 1'd1; +localparam DMSTATUS_AUTHBUSY = 1'd0; +localparam DMSTATUS_RESERVEDA = 1'd0; +localparam DMSTATUS_DEVTREEVALID = 1'd0; +localparam DMSTATUS_VERSION = 2'd2; + +// HARTINFO parameters +//------------------------------------------------------------------------------ +localparam HARTINFO_RESERVEDB = 1'd0; +localparam HARTINFO_NSCRATCH = 4'd1; +localparam HARTINFO_RESERVEDA = 1'd0; +localparam HARTINFO_DATAACCESS = 1'd0; +localparam HARTINFO_DATASIZE = 4'd1; +localparam HARTINFO_DATAADDR = 12'h7b2; + +// ABSTRACTCS parameters +//------------------------------------------------------------------------------ +localparam ABSTRACTCS_RESERVEDD = 1'd0; +localparam ABSTRACTCS_PROGBUFSIZE = 5'd6; +localparam ABSTRACTCS_RESERVEDC = 1'd0; +localparam ABSTRACTCS_RESERVEDB = 1'd0; +localparam ABSTRACTCS_RESERVEDA = 1'd0; +localparam ABSTRACTCS_DATACOUNT = 4'd2; + +localparam ABS_CMD_HARTREG = 1'd0; +localparam ABS_CMD_HARTMEM = 2'd2; +localparam ABS_CMD_HARTREG_CSR = 4'b0000; +localparam ABS_CMD_HARTREG_INTFPU = 4'b0001; +localparam ABS_CMD_HARTREG_INT = 7'b000_0000; +localparam ABS_CMD_HARTREG_FPU = 7'b000_0001; +localparam ABS_EXEC_EBREAK = 32'b000000000001_00000_000_00000_1110011; + +//------------------------------------------------------------------------------ +// Local signals declaration +//------------------------------------------------------------------------------ + +// DM <-> DMI interface internal signals +//------------------------------------------------------------------------------ + +// Register selection signals +logic dmi_req_dmcontrol; +logic dmi_req_abstractcs; +logic dmi_req_abstractauto; +logic dmi_req_command; +logic dmi_rpt_command; +logic dmi_req_data0; +logic dmi_req_data1; +logic dmi_req_progbuf0; +logic dmi_req_progbuf1; +logic dmi_req_progbuf2; +logic dmi_req_progbuf3; +logic dmi_req_progbuf4; +logic dmi_req_progbuf5; + +logic dmi_req_any; + +// Registers write request signals +logic dmcontrol_wr_req; +logic abstractcs_wr_req; +logic data0_wr_req; +logic data1_wr_req; +logic dreg_wr_req; +logic command_wr_req; +logic autoexec_wr_req; +logic progbuf0_wr_req; +logic progbuf1_wr_req; +logic progbuf2_wr_req; +logic progbuf3_wr_req; +logic progbuf4_wr_req; +logic progbuf5_wr_req; + +// DM registers +//------------------------------------------------------------------------------ + +// DM clock enable signals +logic clk_en_dm; +logic clk_en_dm_ff; + +// DMCONTROL register signals +logic dmcontrol_haltreq_ff; +logic dmcontrol_haltreq_next; +logic dmcontrol_resumereq_ff; +logic dmcontrol_resumereq_next; +logic dmcontrol_ackhavereset_ff; +logic dmcontrol_ackhavereset_next; +logic dmcontrol_ndmreset_ff; +logic dmcontrol_ndmreset_next; +logic dmcontrol_dmactive_ff; +logic dmcontrol_dmactive_next; + +// Auxilary Skip Reset On Powerup register +logic havereset_skip_pwrup_ff; +logic havereset_skip_pwrup_next; + +// DMSTATUS register signals +logic dmstatus_allany_havereset_ff; +logic dmstatus_allany_havereset_next; +logic dmstatus_allany_resumeack_ff; +logic dmstatus_allany_resumeack_next; +logic dmstatus_allany_halted_ff; +logic dmstatus_allany_halted_next; + +// Abstract command control logic signals +//------------------------------------------------------------------------------ + +logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] abs_cmd; + +logic abs_cmd_csr_ro; +logic [SCR1_DBG_COMMAND_TYPE_WDTH:0] abs_cmd_type; +logic abs_cmd_regacs; +logic [SCR1_DBG_COMMAND_ACCESSREG_REGNO_HI-12:0] abs_cmd_regtype; +logic [6:0] abs_cmd_regfile; +logic abs_cmd_regwr; +logic [SCR1_DBG_COMMAND_ACCESSREG_SIZE_WDTH:0] abs_cmd_regsize; +logic abs_cmd_execprogbuf; +logic abs_cmd_regvalid; +logic [2:0] abs_cmd_memsize; +logic abs_cmd_memwr; +logic abs_cmd_memvalid; + +logic abs_cmd_regsize_vd; +logic abs_cmd_memsize_vd; + +logic abs_cmd_wr_ff; +logic abs_cmd_wr_next; +logic abs_cmd_postexec_ff; +logic abs_cmd_postexec_next; +logic [11:0] abs_cmd_regno; +logic [11:0] abs_cmd_regno_ff; +logic [1:0] abs_cmd_size_ff; +logic [1:0] abs_cmd_size_next; + +logic abs_reg_access_csr; +logic abs_reg_access_mprf; + +logic abs_cmd_hartreg_vd; +logic abs_cmd_hartmem_vd; + +logic abs_cmd_reg_access_req; +logic abs_cmd_csr_access_req; +logic abs_cmd_mprf_access_req; +logic abs_cmd_execprogbuf_req; + +logic abs_cmd_csr_ro_access_vd; +logic abs_cmd_csr_rw_access_vd; +logic abs_cmd_mprf_access_vd; +logic abs_cmd_mem_access_vd; + +// Abstract FSM signals +//------------------------------------------------------------------------------ + +type_scr1_abs_fsm_e abs_fsm_ff; +type_scr1_abs_fsm_e abs_fsm_next; +logic abs_fsm_idle; +logic abs_fsm_exec; +logic abs_fsm_csr_ro; +logic abs_fsm_err; +logic abs_fsm_use_addr; + +// Abstract registers +//------------------------------------------------------------------------------ + +logic clk_en_abs; + +// ABSTRACTCS register signals +logic abstractcs_busy; +logic abstractcs_ro_en; + +// COMMAND register signals +logic [`SCR1_XLEN-1:0] abs_command_ff; +logic [`SCR1_XLEN-1:0] abs_command_next; + +// ABSTRACTAUTO register signals +logic abs_autoexec_ff; +logic abs_autoexec_next; + +// Program buffer registers +logic [`SCR1_XLEN-1:0] abs_progbuf0_ff; +logic [`SCR1_XLEN-1:0] abs_progbuf1_ff; +logic [`SCR1_XLEN-1:0] abs_progbuf2_ff; +logic [`SCR1_XLEN-1:0] abs_progbuf3_ff; +logic [`SCR1_XLEN-1:0] abs_progbuf4_ff; +logic [`SCR1_XLEN-1:0] abs_progbuf5_ff; + +// Data 0/1 registers +logic data0_xreg_save; +logic [`SCR1_XLEN-1:0] abs_data0_ff; +logic [`SCR1_XLEN-1:0] abs_data0_next; +logic [`SCR1_XLEN-1:0] abs_data1_ff; +logic [`SCR1_XLEN-1:0] abs_data1_next; + +// Abstract command status logic signals +//------------------------------------------------------------------------------ + +// Abstract error exception flag register +logic abs_err_exc_upd; +logic abs_err_exc_ff; +logic abs_err_exc_next; + +logic abs_err_acc_busy_upd; +logic abs_err_acc_busy_ff; +logic abs_err_acc_busy_next; + +type_scr1_abs_err_e abstractcs_cmderr_ff; +type_scr1_abs_err_e abstractcs_cmderr_next; + +// Abstract instruction signals +//------------------------------------------------------------------------------ + +// Abstract instruction execution request register +logic abs_exec_req_next; +logic abs_exec_req_ff; + +// Abstract instruction register +logic [4:0] abs_instr_rd; +logic [4:0] abs_instr_rs1; +logic [4:0] abs_instr_rs2; +logic [2:0] abs_instr_mem_funct3; +logic [`SCR1_XLEN-1:0] abs_exec_instr_next; +logic [`SCR1_XLEN-1:0] abs_exec_instr_ff; + +// DHI FSM signals +//------------------------------------------------------------------------------ + +type_scr1_dhi_fsm_e dhi_fsm_next; +type_scr1_dhi_fsm_e dhi_fsm_ff; +type_scr1_dhi_fsm_e dhi_req; + +logic dhi_fsm_idle; +logic dhi_fsm_exec; +logic dhi_fsm_exec_halt; +logic dhi_fsm_halt_req; +logic dhi_fsm_resume_req; + +// DHI interface signals +//------------------------------------------------------------------------------ + +logic cmd_resp_ok; +logic hart_rst_unexp; +logic halt_req_vd; +logic resume_req_vd; + +logic dhi_resp; +logic dhi_resp_exc; + +logic hart_pbuf_ebreak_ff; +logic hart_pbuf_ebreak_next; + +// HART command registers +//------------------------------------------------------------------------------ + +logic hart_cmd_req_ff; +logic hart_cmd_req_next; + +type_scr1_hdu_dbgstates_e hart_cmd_ff; +type_scr1_hdu_dbgstates_e hart_cmd_next; + +// HART state signals +//------------------------------------------------------------------------------ + +logic hart_state_reset; +logic hart_state_run; +logic hart_state_drun; +logic hart_state_dhalt; + +//------------------------------------------------------------------------------ +// DM <-> DMI interface +//------------------------------------------------------------------------------ + +// Register selection logic +//------------------------------------------------------------------------------ + +always_comb begin + dmi_req_dmcontrol = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_DMCONTROL); + dmi_req_abstractcs = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_ABSTRACTCS); + dmi_req_abstractauto = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_ABSTRACTAUTO); + dmi_req_data0 = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_DATA0); + dmi_req_data1 = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_DATA1); + dmi_req_command = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_COMMAND); + dmi_rpt_command = (abs_autoexec_ff & dmi_req_data0); + dmi_req_progbuf0 = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_PROGBUF0); + dmi_req_progbuf1 = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_PROGBUF1); + dmi_req_progbuf2 = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_PROGBUF2); + dmi_req_progbuf3 = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_PROGBUF3); + dmi_req_progbuf4 = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_PROGBUF4); + dmi_req_progbuf5 = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_PROGBUF5); +end + +assign dmi_req_any = dmi_req_command | dmi_rpt_command | dmi_req_abstractauto + | dmi_req_data0 | dmi_req_data1 | dmi_req_progbuf0 + | dmi_req_progbuf1 | dmi_req_progbuf2 | dmi_req_progbuf3 + | dmi_req_progbuf4 | dmi_req_progbuf5; + + +// Read data multiplexer +//------------------------------------------------------------------------------ + +always_comb begin + dm2dmi_rdata_o = '0; + + case (dmi2dm_addr_i) + SCR1_DBG_DMSTATUS: begin + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_RESERVEDC_HI: + SCR1_DBG_DMSTATUS_RESERVEDC_LO] = DMSTATUS_RESERVEDC; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_IMPEBREAK] = DMSTATUS_IMPEBREAK; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_RESERVEDB_HI: + SCR1_DBG_DMSTATUS_RESERVEDB_LO] = DMSTATUS_RESERVEDB; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ALLHAVERESET] = dmstatus_allany_havereset_ff; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ANYHAVERESET] = dmstatus_allany_havereset_ff; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ALLRESUMEACK] = dmstatus_allany_resumeack_ff; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ANYRESUMEACK] = dmstatus_allany_resumeack_ff; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ALLNONEXISTENT] = DMSTATUS_ALLANYNONEXIST; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ANYNONEXISTENT] = DMSTATUS_ALLANYNONEXIST; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ALLUNAVAIL] = DMSTATUS_ALLANYUNAVAIL; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ANYUNAVAIL] = DMSTATUS_ALLANYUNAVAIL; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ALLRUNNING] = ~dmstatus_allany_halted_ff; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ANYRUNNING] = ~dmstatus_allany_halted_ff; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ALLHALTED] = dmstatus_allany_halted_ff; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ANYHALTED] = dmstatus_allany_halted_ff; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_AUTHENTICATED] = DMSTATUS_AUTHENTICATED; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_AUTHBUSY] = DMSTATUS_AUTHBUSY; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_RESERVEDA] = DMSTATUS_RESERVEDA; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_DEVTREEVALID] = DMSTATUS_DEVTREEVALID; + dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_VERSION_HI: + SCR1_DBG_DMSTATUS_VERSION_LO] = DMSTATUS_VERSION; + end + + SCR1_DBG_DMCONTROL: begin + dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_HALTREQ] = dmcontrol_haltreq_ff; + dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_RESUMEREQ] = dmcontrol_resumereq_ff; + dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_HARTRESET] = DMCONTROL_HARTRESET; + dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_ACKHAVERESET] = dmcontrol_ackhavereset_ff; + dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_RESERVEDB] = DMCONTROL_RESERVEDB; + dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_HASEL] = DMCONTROL_HASEL; + dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_HARTSELLO_HI: + SCR1_DBG_DMCONTROL_HARTSELLO_LO] = DMCONTROL_HARTSELLO; + dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_HARTSELHI_HI: + SCR1_DBG_DMCONTROL_HARTSELHI_LO] = DMCONTROL_HARTSELHI; + dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_RESERVEDA_HI: + SCR1_DBG_DMCONTROL_RESERVEDA_LO] = DMCONTROL_RESERVEDA; + dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_NDMRESET] = dmcontrol_ndmreset_ff; + dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_DMACTIVE] = dmcontrol_dmactive_ff; + end + + SCR1_DBG_ABSTRACTCS: begin + dm2dmi_rdata_o[SCR1_DBG_ABSTRACTCS_RESERVEDD_HI: + SCR1_DBG_ABSTRACTCS_RESERVEDD_LO] = ABSTRACTCS_RESERVEDD; + dm2dmi_rdata_o[SCR1_DBG_ABSTRACTCS_PROGBUFSIZE_HI: + SCR1_DBG_ABSTRACTCS_PROGBUFSIZE_LO] = ABSTRACTCS_PROGBUFSIZE; + dm2dmi_rdata_o[SCR1_DBG_ABSTRACTCS_RESERVEDC_HI: + SCR1_DBG_ABSTRACTCS_RESERVEDC_LO] = ABSTRACTCS_RESERVEDC; + dm2dmi_rdata_o[SCR1_DBG_ABSTRACTCS_BUSY] = abstractcs_busy; + dm2dmi_rdata_o[SCR1_DBG_ABSTRACTCS_RESERVEDB] = ABSTRACTCS_RESERVEDB; + dm2dmi_rdata_o[SCR1_DBG_ABSTRACTCS_CMDERR_HI: + SCR1_DBG_ABSTRACTCS_CMDERR_LO] = abstractcs_cmderr_ff; + dm2dmi_rdata_o[SCR1_DBG_ABSTRACTCS_RESERVEDA_HI: + SCR1_DBG_ABSTRACTCS_RESERVEDA_LO] = ABSTRACTCS_RESERVEDA; + dm2dmi_rdata_o[SCR1_DBG_ABSTRACTCS_DATACOUNT_HI: + SCR1_DBG_ABSTRACTCS_DATACOUNT_LO] = ABSTRACTCS_DATACOUNT; + end + + SCR1_DBG_HARTINFO: begin + dm2dmi_rdata_o[SCR1_DBG_HARTINFO_RESERVEDB_HI: + SCR1_DBG_HARTINFO_RESERVEDB_LO] = HARTINFO_RESERVEDB; + dm2dmi_rdata_o[SCR1_DBG_HARTINFO_NSCRATCH_HI: + SCR1_DBG_HARTINFO_NSCRATCH_LO] = HARTINFO_NSCRATCH; + dm2dmi_rdata_o[SCR1_DBG_HARTINFO_RESERVEDA_HI: + SCR1_DBG_HARTINFO_RESERVEDA_LO] = HARTINFO_RESERVEDA; + dm2dmi_rdata_o[SCR1_DBG_HARTINFO_DATAACCESS] = HARTINFO_DATAACCESS; + dm2dmi_rdata_o[SCR1_DBG_HARTINFO_DATASIZE_HI: + SCR1_DBG_HARTINFO_DATASIZE_LO] = HARTINFO_DATASIZE; + dm2dmi_rdata_o[SCR1_DBG_HARTINFO_DATAADDR_HI: + SCR1_DBG_HARTINFO_DATAADDR_LO] = HARTINFO_DATAADDR; + end + + SCR1_DBG_ABSTRACTAUTO: dm2dmi_rdata_o[0] = abs_autoexec_ff; + SCR1_DBG_DATA0 : dm2dmi_rdata_o = abs_data0_ff; + SCR1_DBG_DATA1 : dm2dmi_rdata_o = abs_data1_ff; + SCR1_DBG_PROGBUF0 : dm2dmi_rdata_o = abs_progbuf0_ff; + SCR1_DBG_PROGBUF1 : dm2dmi_rdata_o = abs_progbuf1_ff; + SCR1_DBG_PROGBUF2 : dm2dmi_rdata_o = abs_progbuf2_ff; + SCR1_DBG_PROGBUF3 : dm2dmi_rdata_o = abs_progbuf3_ff; + SCR1_DBG_PROGBUF4 : dm2dmi_rdata_o = abs_progbuf4_ff; + SCR1_DBG_PROGBUF5 : dm2dmi_rdata_o = abs_progbuf5_ff; + SCR1_DBG_HALTSUM0 : dm2dmi_rdata_o[0] = dmstatus_allany_halted_ff; + + default: begin + dm2dmi_rdata_o = '0; + end + endcase +end + +// Response +assign dm2dmi_resp_o = 1'b1; + +// Write requests signals +//------------------------------------------------------------------------------ + +assign dmcontrol_wr_req = dmi_req_dmcontrol & dmi2dm_wr_i; +assign data0_wr_req = dmi_req_data0 & dmi2dm_wr_i; +assign data1_wr_req = dmi_req_data1 & dmi2dm_wr_i; +assign dreg_wr_req = pipe2dm_dreg_req_i & pipe2dm_dreg_wr_i; +assign command_wr_req = dmi_req_command & dmi2dm_wr_i; +assign autoexec_wr_req = dmi_req_abstractauto & dmi2dm_wr_i; +assign progbuf0_wr_req = dmi_req_progbuf0 & dmi2dm_wr_i; +assign progbuf1_wr_req = dmi_req_progbuf1 & dmi2dm_wr_i; +assign progbuf2_wr_req = dmi_req_progbuf2 & dmi2dm_wr_i; +assign progbuf3_wr_req = dmi_req_progbuf3 & dmi2dm_wr_i; +assign progbuf4_wr_req = dmi_req_progbuf4 & dmi2dm_wr_i; +assign progbuf5_wr_req = dmi_req_progbuf5 & dmi2dm_wr_i; +assign abstractcs_wr_req = dmi_req_abstractcs & dmi2dm_wr_i; + +// HART state signals +//------------------------------------------------------------------------------ + +assign hart_state_reset = (pipe2dm_hart_status_i.dbg_state == SCR1_HDU_DBGSTATE_RESET); +assign hart_state_run = (pipe2dm_hart_status_i.dbg_state == SCR1_HDU_DBGSTATE_RUN); +assign hart_state_dhalt = (pipe2dm_hart_status_i.dbg_state == SCR1_HDU_DBGSTATE_DHALTED); +assign hart_state_drun = (pipe2dm_hart_status_i.dbg_state == SCR1_HDU_DBGSTATE_DRUN); + +//------------------------------------------------------------------------------ +// DM registers +//------------------------------------------------------------------------------ +// + // Registers: + // - DM clock enable register + // - Auxilary Skip Reset On Powerup register + // - DMCONTROL register + // - DMSTATUS register + +// DM clock enable logic +//------------------------------------------------------------------------------ + +assign clk_en_dm = dmcontrol_wr_req | dmcontrol_dmactive_ff | clk_en_dm_ff; + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + clk_en_dm_ff <= 1'b0; + end else if (clk_en_dm) begin + clk_en_dm_ff <= dmcontrol_dmactive_ff; + end +end + +assign dm2pipe_active_o = clk_en_dm_ff; + +// DMCONTROL register +//------------------------------------------------------------------------------ + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + dmcontrol_dmactive_ff <= 1'b0; + dmcontrol_ndmreset_ff <= 1'b0; + dmcontrol_ackhavereset_ff <= 1'b0; + dmcontrol_haltreq_ff <= 1'b0; + dmcontrol_resumereq_ff <= 1'b0; + end else if (clk_en_dm) begin + dmcontrol_dmactive_ff <= dmcontrol_dmactive_next; + dmcontrol_ndmreset_ff <= dmcontrol_ndmreset_next; + dmcontrol_ackhavereset_ff <= dmcontrol_ackhavereset_next; + dmcontrol_haltreq_ff <= dmcontrol_haltreq_next; + dmcontrol_resumereq_ff <= dmcontrol_resumereq_next; + end +end + +assign dmcontrol_dmactive_next = dmcontrol_wr_req + ? dmi2dm_wdata_i[SCR1_DBG_DMCONTROL_DMACTIVE] + : dmcontrol_dmactive_ff; + +always_comb begin + dmcontrol_ndmreset_next = dmcontrol_ndmreset_ff; + dmcontrol_ackhavereset_next = dmcontrol_ackhavereset_ff; + dmcontrol_haltreq_next = dmcontrol_haltreq_ff; + dmcontrol_resumereq_next = dmcontrol_resumereq_ff; + if (~dmcontrol_dmactive_ff) begin + dmcontrol_ndmreset_next = 1'b0; + dmcontrol_ackhavereset_next = 1'b0; + dmcontrol_haltreq_next = 1'b0; + dmcontrol_resumereq_next = 1'b0; + end else if (dmcontrol_wr_req) begin + dmcontrol_ndmreset_next = dmi2dm_wdata_i[SCR1_DBG_DMCONTROL_NDMRESET]; + dmcontrol_ackhavereset_next = dmi2dm_wdata_i[SCR1_DBG_DMCONTROL_ACKHAVERESET]; + dmcontrol_haltreq_next = dmi2dm_wdata_i[SCR1_DBG_DMCONTROL_HALTREQ]; + dmcontrol_resumereq_next = dmi2dm_wdata_i[SCR1_DBG_DMCONTROL_RESUMEREQ]; + end +end + +// Reset signal for system controlled by Debug Module +assign hart_rst_n_o = ~dmcontrol_ndmreset_ff; +assign ndm_rst_n_o = ~dmcontrol_ndmreset_ff; + +// Skip reset on powerup register +//------------------------------------------------------------------------------ + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + havereset_skip_pwrup_ff <= 1'b1; + end else if (clk_en_dm) begin + havereset_skip_pwrup_ff <= havereset_skip_pwrup_next; + end +end + +assign havereset_skip_pwrup_next = ~dmcontrol_dmactive_ff ? 1'b1 + : havereset_skip_pwrup_ff ? hart_state_reset & ndm_rst_n_o & hart_rst_n_o + : havereset_skip_pwrup_ff; + +// DMSTATUS register +//------------------------------------------------------------------------------ + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + dmstatus_allany_havereset_ff <= 1'b0; + dmstatus_allany_resumeack_ff <= 1'b0; + dmstatus_allany_halted_ff <= 1'b0; + end else if (clk_en_dm) begin + dmstatus_allany_havereset_ff <= dmstatus_allany_havereset_next; + dmstatus_allany_resumeack_ff <= dmstatus_allany_resumeack_next; + dmstatus_allany_halted_ff <= dmstatus_allany_halted_next; + end +end + +assign dmstatus_allany_havereset_next = ~dmcontrol_dmactive_ff ? 1'b0 + : ~havereset_skip_pwrup_ff & hart_state_reset ? 1'b1 + : dmcontrol_ackhavereset_ff ? 1'b0 + : dmstatus_allany_havereset_ff; +assign dmstatus_allany_resumeack_next = ~dmcontrol_dmactive_ff ? 1'b0 + : ~dmcontrol_resumereq_ff ? 1'b0 + : hart_state_run ? 1'b1 + : dmstatus_allany_resumeack_ff; + +assign dmstatus_allany_halted_next = ~dmcontrol_dmactive_ff ? 1'b0 + : hart_state_dhalt ? 1'b1 + : hart_state_run ? 1'b0 + : dmstatus_allany_halted_ff; + +//------------------------------------------------------------------------------ +// Abstract Command control logic +//------------------------------------------------------------------------------ +// + // Consists of the following functional units: + // - Abstract command decoder + // - Abstract command access valid flags + // - Abstract command control registers + +assign clk_en_abs = clk_en_dm & dmcontrol_dmactive_ff; + +// Abstract command decoder +//------------------------------------------------------------------------------ + +assign abs_cmd = dmi_req_command ? dmi2dm_wdata_i : abs_command_ff; + +always_comb begin + abs_cmd_regno = abs_cmd[SCR1_DBG_COMMAND_ACCESSREG_REGNO_LO +: 12]; + + abs_cmd_csr_ro = (abs_cmd_regno == SCR1_CSR_ADDR_MISA) + | (abs_cmd_regno == SCR1_CSR_ADDR_MVENDORID) + | (abs_cmd_regno == SCR1_CSR_ADDR_MARCHID) + | (abs_cmd_regno == SCR1_CSR_ADDR_MIMPID) + | (abs_cmd_regno == SCR1_CSR_ADDR_MHARTID) + | (abs_cmd_regno == SCR1_HDU_DBGCSR_ADDR_DPC); + + abs_cmd_type = abs_cmd[SCR1_DBG_COMMAND_TYPE_HI:SCR1_DBG_COMMAND_TYPE_LO]; + abs_cmd_regacs = abs_cmd[SCR1_DBG_COMMAND_ACCESSREG_TRANSFER]; + abs_cmd_regtype = abs_cmd[SCR1_DBG_COMMAND_ACCESSREG_REGNO_HI:12]; + abs_cmd_regfile = abs_cmd[11:5]; + abs_cmd_regsize = abs_cmd[SCR1_DBG_COMMAND_ACCESSREG_SIZE_HI: + SCR1_DBG_COMMAND_ACCESSREG_SIZE_LO]; + abs_cmd_regwr = abs_cmd[SCR1_DBG_COMMAND_ACCESSREG_WRITE]; + abs_cmd_execprogbuf = abs_cmd[SCR1_DBG_COMMAND_ACCESSREG_POSTEXEC]; + + abs_cmd_regvalid = ~(|{abs_cmd[SCR1_DBG_COMMAND_ACCESSREG_RESERVEDB], + abs_cmd[SCR1_DBG_COMMAND_ACCESSREG_RESERVEDA]}); + + abs_cmd_memsize = abs_cmd[SCR1_DBG_COMMAND_ACCESSMEM_AAMSIZE_HI: + SCR1_DBG_COMMAND_ACCESSMEM_AAMSIZE_LO]; + abs_cmd_memwr = abs_cmd[SCR1_DBG_COMMAND_ACCESSMEM_WRITE]; + + abs_cmd_memvalid = ~(|{abs_cmd[SCR1_DBG_COMMAND_ACCESSMEM_AAMVIRTUAL], + abs_cmd[SCR1_DBG_COMMAND_ACCESSMEM_AAMPOSTINC], + abs_cmd[SCR1_DBG_COMMAND_ACCESSMEM_RESERVEDB_HI: + SCR1_DBG_COMMAND_ACCESSMEM_RESERVEDB_HI], + abs_cmd[SCR1_DBG_COMMAND_ACCESSMEM_RESERVEDA_HI: + SCR1_DBG_COMMAND_ACCESSMEM_RESERVEDA_HI]}); +end + +assign abs_reg_access_csr = (abs_cmd_regtype == ABS_CMD_HARTREG_CSR); +assign abs_reg_access_mprf = (abs_cmd_regtype == ABS_CMD_HARTREG_INTFPU) + & (abs_cmd_regfile == ABS_CMD_HARTREG_INT); + +// Abstract command access request and valid flags +//------------------------------------------------------------------------------ + +assign abs_cmd_regsize_vd = (abs_cmd_regsize == 3'h2); +assign abs_cmd_memsize_vd = (abs_cmd_memsize < 3'h3); + +assign abs_cmd_hartreg_vd = (abs_cmd_type == ABS_CMD_HARTREG) & abs_cmd_regvalid; +assign abs_cmd_hartmem_vd = (abs_cmd_type == ABS_CMD_HARTMEM) & abs_cmd_memvalid; + +// Abstract command requests +assign abs_cmd_reg_access_req = abs_cmd_hartreg_vd & abs_cmd_regacs; +assign abs_cmd_csr_access_req = abs_cmd_reg_access_req & abs_reg_access_csr; +assign abs_cmd_mprf_access_req = abs_cmd_reg_access_req & abs_reg_access_mprf; +assign abs_cmd_execprogbuf_req = abs_cmd_hartreg_vd & abs_cmd_execprogbuf; + +// Abstract command access valid flags +assign abs_cmd_csr_ro_access_vd = abs_cmd_csr_access_req & abs_cmd_regsize_vd & ~abs_cmd_regwr + & ~abs_cmd_execprogbuf & abs_cmd_csr_ro & hart_state_run; +assign abs_cmd_csr_rw_access_vd = abs_cmd_csr_access_req & abs_cmd_regsize_vd + & (abs_cmd_regwr | ~abs_cmd_csr_ro_access_vd); +assign abs_cmd_mprf_access_vd = abs_cmd_mprf_access_req & abs_cmd_regsize_vd; +assign abs_cmd_mem_access_vd = abs_cmd_hartmem_vd & abs_cmd_memsize_vd; + +// Abstract command control registers +//------------------------------------------------------------------------------ + +always_ff @(posedge clk) begin + if (clk_en_abs & abs_fsm_idle) begin + abs_cmd_postexec_ff <= abs_cmd_postexec_next; + abs_cmd_wr_ff <= abs_cmd_wr_next; + abs_cmd_regno_ff <= abs_cmd_regno; + abs_cmd_size_ff <= abs_cmd_size_next; + end +end + +always_comb begin + abs_cmd_wr_next = 1'b0; + abs_cmd_postexec_next = 1'b0; + abs_cmd_size_next = abs_cmd_size_ff; + if ((command_wr_req | dmi_rpt_command) & hart_state_dhalt & abs_fsm_idle) begin + if (abs_cmd_csr_rw_access_vd) begin + abs_cmd_wr_next = abs_cmd_regwr; + abs_cmd_postexec_next = abs_cmd_execprogbuf; + end else if (abs_cmd_mprf_access_vd) begin + abs_cmd_wr_next = abs_cmd_regwr; + abs_cmd_size_next = abs_cmd_regsize[1:0]; + abs_cmd_postexec_next = abs_cmd_execprogbuf; + end else if (abs_cmd_mem_access_vd) begin + abs_cmd_wr_next = abs_cmd_memwr; + abs_cmd_size_next = abs_cmd_memsize[1:0]; + end + end +end + +//------------------------------------------------------------------------------ +// Abstract command FSM +//------------------------------------------------------------------------------ + +always_ff @(posedge clk) begin + if (clk_en_dm) begin + if (~dmcontrol_dmactive_ff) begin + abs_fsm_ff <= ABS_STATE_IDLE; + end else begin + abs_fsm_ff <= abs_fsm_next; + end + end +end + +always_comb begin + abs_fsm_next = abs_fsm_ff; + + case (abs_fsm_ff) + ABS_STATE_IDLE: begin + if (command_wr_req | dmi_rpt_command) begin + case (1'b1) + abs_cmd_csr_ro_access_vd: abs_fsm_next = ABS_STATE_CSR_RO; + abs_cmd_csr_rw_access_vd: abs_fsm_next = hart_state_dhalt ? ABS_STATE_CSR_SAVE_XREG : ABS_STATE_ERR; + abs_cmd_mprf_access_vd : abs_fsm_next = hart_state_dhalt ? ABS_STATE_XREG_RW : ABS_STATE_ERR; + abs_cmd_execprogbuf_req : abs_fsm_next = ABS_STATE_EXEC; + abs_cmd_mem_access_vd : abs_fsm_next = hart_state_dhalt ? ABS_STATE_MEM_SAVE_XREG : ABS_STATE_ERR; + default : abs_fsm_next = ABS_STATE_ERR; + endcase + end + end + + ABS_STATE_EXEC: begin + if (dhi_resp) begin + if (dhi_resp_exc | abs_err_acc_busy_ff) begin + abs_fsm_next = ABS_STATE_ERR; + end else begin + abs_fsm_next = ABS_STATE_IDLE; + end + end + end + + ABS_STATE_XREG_RW: begin + if (dhi_resp) begin + case (1'b1) + abs_err_acc_busy_ff: abs_fsm_next = ABS_STATE_ERR; + abs_cmd_postexec_ff: abs_fsm_next = ABS_STATE_EXEC; + default : abs_fsm_next = ABS_STATE_IDLE; + endcase + end + end + + ABS_STATE_CSR_RO : abs_fsm_next = abs_err_acc_busy_ff ? ABS_STATE_ERR : ABS_STATE_IDLE; + ABS_STATE_CSR_SAVE_XREG: abs_fsm_next = dhi_resp ? ABS_STATE_CSR_RW : ABS_STATE_CSR_SAVE_XREG; + ABS_STATE_CSR_RW : abs_fsm_next = dhi_resp ? ABS_STATE_CSR_RETURN_XREG : ABS_STATE_CSR_RW; + + ABS_STATE_CSR_RETURN_XREG: begin + if (dhi_resp) begin + case (1'b1) + abs_err_exc_ff : abs_fsm_next = ABS_STATE_ERR; + abs_err_acc_busy_ff : abs_fsm_next = ABS_STATE_ERR; + abs_cmd_postexec_ff : abs_fsm_next = ABS_STATE_EXEC; + default : abs_fsm_next = ABS_STATE_IDLE; + endcase + end + end + + ABS_STATE_MEM_SAVE_XREG : abs_fsm_next = dhi_resp ? ABS_STATE_MEM_SAVE_XREG_FORADDR : ABS_STATE_MEM_SAVE_XREG; + ABS_STATE_MEM_SAVE_XREG_FORADDR : abs_fsm_next = dhi_resp ? ABS_STATE_MEM_RW : ABS_STATE_MEM_SAVE_XREG_FORADDR; + ABS_STATE_MEM_RW : abs_fsm_next = dhi_resp ? ABS_STATE_MEM_RETURN_XREG : ABS_STATE_MEM_RW; + ABS_STATE_MEM_RETURN_XREG : abs_fsm_next = dhi_resp ? ABS_STATE_MEM_RETURN_XREG_FORADDR : ABS_STATE_MEM_RETURN_XREG; + + ABS_STATE_MEM_RETURN_XREG_FORADDR: begin + if (dhi_resp) begin + case (1'b1) + abs_err_exc_ff: abs_fsm_next = ABS_STATE_ERR; + abs_err_acc_busy_ff : abs_fsm_next = ABS_STATE_ERR; + abs_cmd_postexec_ff : abs_fsm_next = ABS_STATE_EXEC; + default : abs_fsm_next = ABS_STATE_IDLE; + endcase + end + end + + ABS_STATE_ERR: begin + if (abstractcs_wr_req & (abstractcs_cmderr_next == 3'b0)) begin + abs_fsm_next = ABS_STATE_IDLE; + end + end + endcase + + if (~abs_fsm_idle & hart_state_reset) begin + abs_fsm_next = ABS_STATE_ERR; + end +end + +assign abs_fsm_idle = (abs_fsm_ff == ABS_STATE_IDLE); +assign abs_fsm_exec = (abs_fsm_ff == ABS_STATE_EXEC); +assign abs_fsm_csr_ro = (abs_fsm_ff == ABS_STATE_CSR_RO); +assign abs_fsm_err = (abs_fsm_ff == ABS_STATE_ERR); +assign abs_fsm_use_addr = (abs_fsm_ff == ABS_STATE_MEM_SAVE_XREG_FORADDR) + | (abs_fsm_ff == ABS_STATE_MEM_RETURN_XREG_FORADDR); + +//------------------------------------------------------------------------------ +// Abstract command status logic +//------------------------------------------------------------------------------ + +// Abstract command access busy error register +//------------------------------------------------------------------------------ + +assign abs_err_acc_busy_upd = clk_en_abs & (abs_fsm_idle | dmi_req_any); + +always_ff @(posedge clk) begin + if (abs_err_acc_busy_upd) abs_err_acc_busy_ff <= abs_err_acc_busy_next; +end + +assign abs_err_acc_busy_next = ~abs_fsm_idle & dmi_req_any; + +// Abstract command access exception error register +//------------------------------------------------------------------------------ + +assign abs_err_exc_upd = clk_en_abs & (abs_fsm_idle | (dhi_resp & dhi_resp_exc)); + +always_ff @(posedge clk) begin + if (abs_err_exc_upd) abs_err_exc_ff <= abs_err_exc_next; +end + +assign abs_err_exc_next = ~abs_fsm_idle & dhi_resp & dhi_resp_exc; + +//------------------------------------------------------------------------------ +// Abstract Instruction logic +//------------------------------------------------------------------------------ +// + // Cosists of the following functional units: + // - Instruction execution request register + // - Instruction memory FUNCT3 field multiplexer + // - Instruction RS1 multiplexer + // - Instruction RD multiplexer + // - Abstract Instruction register + +// Abstract instruction execution request register +//------------------------------------------------------------------------------ + +assign abs_exec_req_next = ~(abs_fsm_idle | abs_fsm_csr_ro | abs_fsm_err) & ~dhi_resp; + +always_ff @(posedge clk) begin + if (clk_en_dm) begin + if (~dmcontrol_dmactive_ff) begin + abs_exec_req_ff <= 1'b0; + end else begin + abs_exec_req_ff <= abs_exec_req_next; + end + end +end + +// Abstract instruction memory FUNCT3 field multiplexer +//------------------------------------------------------------------------------ + +always_comb begin + case (abs_cmd_size_ff) + 2'b00 : abs_instr_mem_funct3 = abs_cmd_wr_ff ? SCR1_FUNCT3_SB : SCR1_FUNCT3_LBU; + 2'b01 : abs_instr_mem_funct3 = abs_cmd_wr_ff ? SCR1_FUNCT3_SH : SCR1_FUNCT3_LHU; + 2'b10 : abs_instr_mem_funct3 = abs_cmd_wr_ff ? SCR1_FUNCT3_SW : SCR1_FUNCT3_LW; + default: abs_instr_mem_funct3 = SCR1_FUNCT3_SB; + endcase +end + +// Abstract instruction RS1 multiplexer +//------------------------------------------------------------------------------ + +always_comb begin + abs_instr_rs1 = 5'h0; + case (abs_fsm_ff) + ABS_STATE_XREG_RW : abs_instr_rs1 = abs_cmd_wr_ff ? 5'h0 : abs_cmd_regno_ff[4:0]; + ABS_STATE_CSR_SAVE_XREG : abs_instr_rs1 = 5'h5; + ABS_STATE_MEM_SAVE_XREG : abs_instr_rs1 = 5'h5; + ABS_STATE_CSR_RETURN_XREG : abs_instr_rs1 = 5'h5; + ABS_STATE_MEM_RETURN_XREG : abs_instr_rs1 = 5'h5; + ABS_STATE_CSR_RW : abs_instr_rs1 = abs_cmd_wr_ff ? 5'h5 : 5'h0; + ABS_STATE_MEM_SAVE_XREG_FORADDR : abs_instr_rs1 = 5'h6; + ABS_STATE_MEM_RETURN_XREG_FORADDR: abs_instr_rs1 = 5'h6; + ABS_STATE_MEM_RW : abs_instr_rs1 = 5'h6; + default : begin end + endcase +end + +assign abs_instr_rs2 = 5'h5; + +// Abstract instruction RD multiplexer +//------------------------------------------------------------------------------ + +always_comb begin + abs_instr_rd = 5'h0; + case (abs_fsm_ff) + ABS_STATE_XREG_RW : abs_instr_rd = abs_cmd_wr_ff ? abs_cmd_regno_ff[4:0] : 5'h0; + ABS_STATE_CSR_SAVE_XREG : abs_instr_rd = abs_cmd_wr_ff ? 5'h5 : 5'h0; + ABS_STATE_MEM_SAVE_XREG : abs_instr_rd = abs_cmd_wr_ff ? 5'h5 : 5'h0; + ABS_STATE_CSR_RW : abs_instr_rd = abs_cmd_wr_ff ? 5'h0 : 5'h5; + ABS_STATE_MEM_RW : abs_instr_rd = abs_cmd_wr_ff ? 5'h0 : 5'h5; + ABS_STATE_CSR_RETURN_XREG : abs_instr_rd = 5'h5; + ABS_STATE_MEM_RETURN_XREG : abs_instr_rd = 5'h5; + ABS_STATE_MEM_SAVE_XREG_FORADDR : abs_instr_rd = 5'h6; + ABS_STATE_MEM_RETURN_XREG_FORADDR: abs_instr_rd = 5'h6; + default : begin end + endcase +end + +// Abstract instruction register +//------------------------------------------------------------------------------ + +always_ff @(posedge clk) begin + if (clk_en_abs) begin + abs_exec_instr_ff <= abs_exec_instr_next; + end +end + +always_comb begin + abs_exec_instr_next = abs_exec_instr_ff; + case (abs_fsm_ff) + ABS_STATE_XREG_RW, + ABS_STATE_CSR_SAVE_XREG, + ABS_STATE_CSR_RETURN_XREG, + ABS_STATE_MEM_SAVE_XREG, + ABS_STATE_MEM_SAVE_XREG_FORADDR, + ABS_STATE_MEM_RETURN_XREG, + ABS_STATE_MEM_RETURN_XREG_FORADDR: begin + abs_exec_instr_next = {SCR1_HDU_DBGCSR_ADDR_DSCRATCH0, abs_instr_rs1, SCR1_FUNCT3_CSRRW, abs_instr_rd, SCR1_OP_SYSTEM}; + end + + ABS_STATE_CSR_RW: begin + abs_exec_instr_next = abs_cmd_wr_ff + ? {abs_cmd_regno_ff[11:0], abs_instr_rs1, SCR1_FUNCT3_CSRRW, abs_instr_rd, SCR1_OP_SYSTEM} + : {abs_cmd_regno_ff[11:0], abs_instr_rs1, SCR1_FUNCT3_CSRRS, abs_instr_rd, SCR1_OP_SYSTEM}; + end + + ABS_STATE_MEM_RW: begin + abs_exec_instr_next = abs_cmd_wr_ff + ? {7'h0, abs_instr_rs2, abs_instr_rs1, abs_instr_mem_funct3, 5'h0, SCR1_OP_STORE} + : {12'h0, abs_instr_rs1, abs_instr_mem_funct3, abs_instr_rd, SCR1_OP_LOAD}; + end + + default: begin end + endcase +end + +//------------------------------------------------------------------------------ +// Abstract registers +//------------------------------------------------------------------------------ +// + // Registers: + // - ABSTRACTCS register + // - COMMAND register + // - ABSTRACTAUTO register + // - PROGBUF0..5 registers + // - DATA0..1 registers + +// ABSTRACTCS register +//------------------------------------------------------------------------------ + +always_ff @(posedge clk) begin + if (clk_en_dm) begin + if (~dmcontrol_dmactive_ff) begin + abstractcs_cmderr_ff <= ABS_ERR_NONE; + end else begin + abstractcs_cmderr_ff <= abstractcs_cmderr_next; + end + end +end + +always_comb begin + abstractcs_cmderr_next = abstractcs_cmderr_ff; + + case (abs_fsm_ff) + ABS_STATE_IDLE: begin + if (command_wr_req | dmi_rpt_command) begin + if (abs_cmd_hartreg_vd) begin + case (1'b1) + abs_cmd_reg_access_req : begin + case (1'b1) + abs_cmd_csr_rw_access_vd: abstractcs_cmderr_next = hart_state_dhalt + ? abstractcs_cmderr_ff + : ABS_ERR_NOHALT; + abs_cmd_mprf_access_vd : abstractcs_cmderr_next = hart_state_dhalt + ? abstractcs_cmderr_ff + : ABS_ERR_NOHALT; + abs_cmd_csr_ro_access_vd: abstractcs_cmderr_next = abstractcs_cmderr_ff; + default : abstractcs_cmderr_next = ABS_ERR_CMD; + endcase + end + abs_cmd_execprogbuf_req : abstractcs_cmderr_next = abstractcs_cmderr_ff; + default : abstractcs_cmderr_next = ABS_ERR_CMD; + endcase + end else if (abs_cmd_hartmem_vd) begin + abstractcs_cmderr_next = ~abs_cmd_memsize_vd ? ABS_ERR_CMD + : ~hart_state_dhalt ? ABS_ERR_NOHALT + : abstractcs_cmderr_ff; + end else begin + abstractcs_cmderr_next = ABS_ERR_CMD; + end + end + end + + ABS_STATE_EXEC: begin + if (dhi_resp) begin + if (dhi_resp_exc) begin + abstractcs_cmderr_next = ABS_ERR_EXCEPTION; + end else if (abs_err_acc_busy_ff) begin + abstractcs_cmderr_next = ABS_ERR_BUSY; + end + end + end + + ABS_STATE_XREG_RW, + ABS_STATE_CSR_RO: begin + if (abs_err_acc_busy_ff) begin + abstractcs_cmderr_next = ABS_ERR_BUSY; + end + end + + ABS_STATE_CSR_RETURN_XREG, + ABS_STATE_MEM_RETURN_XREG_FORADDR: begin + if (dhi_resp) begin + case (1'b1) + abs_err_exc_ff : abstractcs_cmderr_next = ABS_ERR_EXCEPTION; + abs_err_acc_busy_ff: abstractcs_cmderr_next = ABS_ERR_BUSY; + default: abstractcs_cmderr_next = abstractcs_cmderr_ff; + endcase + end + end + + ABS_STATE_ERR: begin + if (dmi_req_abstractcs & dmi2dm_wr_i) begin + abstractcs_cmderr_next = type_scr1_abs_err_e'(logic'(abstractcs_cmderr_ff) + & (~dmi2dm_wdata_i[SCR1_DBG_ABSTRACTCS_CMDERR_HI: + SCR1_DBG_ABSTRACTCS_CMDERR_LO])); + end + end + + default: begin + end + endcase + + if (~abs_fsm_idle & hart_state_reset) begin + abstractcs_cmderr_next = ABS_ERR_EXCEPTION; + end +end + +assign abstractcs_busy = ~abs_fsm_idle & ~abs_fsm_err; + +// Abstract COMMAND register +//------------------------------------------------------------------------------ + +always_ff @(posedge clk) begin + if (clk_en_dm) abs_command_ff <= abs_command_next; +end + +assign abs_command_next = ~dmcontrol_dmactive_ff ? '0 + : (command_wr_req & abs_fsm_idle) ? dmi2dm_wdata_i + : abs_command_ff; + +// Abstract ABSTRACTAUTO register +//------------------------------------------------------------------------------ + +always_ff @(posedge clk) begin + if (clk_en_dm) abs_autoexec_ff <= abs_autoexec_next; +end + +assign abs_autoexec_next = ~dmcontrol_dmactive_ff ? 1'b0 + : (autoexec_wr_req & abs_fsm_idle) ? dmi2dm_wdata_i[0] + : abs_autoexec_ff; + +// Program Buffer registers +//------------------------------------------------------------------------------ + +always_ff @(posedge clk) begin + if (clk_en_abs & abs_fsm_idle) begin + if (progbuf0_wr_req) abs_progbuf0_ff <= dmi2dm_wdata_i; + if (progbuf1_wr_req) abs_progbuf1_ff <= dmi2dm_wdata_i; + if (progbuf2_wr_req) abs_progbuf2_ff <= dmi2dm_wdata_i; + if (progbuf3_wr_req) abs_progbuf3_ff <= dmi2dm_wdata_i; + if (progbuf4_wr_req) abs_progbuf4_ff <= dmi2dm_wdata_i; + if (progbuf5_wr_req) abs_progbuf5_ff <= dmi2dm_wdata_i; + end +end + +// Data 0 register +//------------------------------------------------------------------------------ + +always_ff @(posedge clk) begin + if (clk_en_abs) begin + abs_data0_ff <= abs_data0_next; + end +end + +assign data0_xreg_save = dreg_wr_req & ~abs_cmd_wr_ff; + +always_comb begin + abs_data0_next = abs_data0_ff; + + case (abs_fsm_ff) + ABS_STATE_IDLE : abs_data0_next = data0_wr_req ? dmi2dm_wdata_i : abs_data0_ff; + ABS_STATE_EXEC : abs_data0_next = dreg_wr_req ? pipe2dm_dreg_wdata_i : abs_data0_ff; + ABS_STATE_CSR_SAVE_XREG : abs_data0_next = dreg_wr_req ? pipe2dm_dreg_wdata_i : abs_data0_ff; + ABS_STATE_CSR_RETURN_XREG: abs_data0_next = dreg_wr_req ? pipe2dm_dreg_wdata_i : abs_data0_ff; + ABS_STATE_MEM_SAVE_XREG : abs_data0_next = dreg_wr_req ? pipe2dm_dreg_wdata_i : abs_data0_ff; + ABS_STATE_MEM_RETURN_XREG: abs_data0_next = dreg_wr_req ? pipe2dm_dreg_wdata_i : abs_data0_ff; + ABS_STATE_XREG_RW : abs_data0_next = data0_xreg_save ? pipe2dm_dreg_wdata_i : abs_data0_ff; + + ABS_STATE_CSR_RO: begin + case (abs_cmd_regno_ff[11:0]) + SCR1_CSR_ADDR_MISA : abs_data0_next = SCR1_CSR_MISA; + SCR1_CSR_ADDR_MVENDORID: abs_data0_next = SCR1_CSR_MVENDORID; + SCR1_CSR_ADDR_MARCHID : abs_data0_next = SCR1_CSR_MARCHID; + SCR1_CSR_ADDR_MIMPID : abs_data0_next = SCR1_CSR_MIMPID; + SCR1_CSR_ADDR_MHARTID : abs_data0_next = soc2dm_fuse_mhartid_i; + default : abs_data0_next = pipe2dm_pc_sample_i; + endcase + end + + default : begin end + endcase +end + +// Data 1 register +//------------------------------------------------------------------------------ + +always_ff @(posedge clk) begin + if (clk_en_abs) begin + abs_data1_ff <= abs_data1_next; + end +end + +always_comb begin + abs_data1_next = abs_data1_ff; + case (abs_fsm_ff) + ABS_STATE_IDLE : abs_data1_next = data1_wr_req ? dmi2dm_wdata_i : abs_data1_ff; + ABS_STATE_MEM_SAVE_XREG_FORADDR : abs_data1_next = dreg_wr_req ? pipe2dm_dreg_wdata_i : abs_data1_ff; + ABS_STATE_MEM_RETURN_XREG_FORADDR: abs_data1_next = dreg_wr_req ? pipe2dm_dreg_wdata_i : abs_data1_ff; + default : begin end + endcase +end + +//------------------------------------------------------------------------------ +// Debug Hart Interface : control +//------------------------------------------------------------------------------ + +assign cmd_resp_ok = pipe2dm_cmd_resp_i & ~pipe2dm_cmd_rcode_i; +assign hart_rst_unexp = ~dhi_fsm_idle & ~dhi_fsm_halt_req & hart_state_reset; + +assign halt_req_vd = dmcontrol_haltreq_ff & ~hart_state_dhalt; +assign resume_req_vd = dmcontrol_resumereq_ff & ~dmstatus_allany_resumeack_ff + & hart_state_dhalt; + +// DHI fsm +//------------------------------------------------------------------------------ + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + dhi_fsm_ff <= DHI_STATE_IDLE; + end else if (clk_en_dm) begin + dhi_fsm_ff <= dhi_fsm_next; + end +end + +always_comb begin + dhi_fsm_next = dhi_fsm_ff; + if (~hart_rst_unexp & dmcontrol_dmactive_ff) begin + // Normal work + case (dhi_fsm_ff) + DHI_STATE_IDLE : dhi_fsm_next = dhi_req; + DHI_STATE_EXEC : dhi_fsm_next = cmd_resp_ok ? DHI_STATE_EXEC_RUN : DHI_STATE_EXEC; + DHI_STATE_EXEC_RUN : dhi_fsm_next = hart_state_drun ? DHI_STATE_EXEC_HALT : DHI_STATE_EXEC_RUN; + DHI_STATE_HALT_REQ : dhi_fsm_next = cmd_resp_ok ? DHI_STATE_EXEC_HALT : DHI_STATE_HALT_REQ; + DHI_STATE_EXEC_HALT : dhi_fsm_next = hart_state_dhalt ? DHI_STATE_IDLE : DHI_STATE_EXEC_HALT; + DHI_STATE_RESUME_REQ: dhi_fsm_next = cmd_resp_ok ? DHI_STATE_RESUME_RUN : DHI_STATE_RESUME_REQ; + DHI_STATE_RESUME_RUN: dhi_fsm_next = hart_state_run ? DHI_STATE_IDLE : DHI_STATE_RESUME_RUN; + default : dhi_fsm_next = dhi_fsm_ff; + endcase + end else begin + // In case of DM reset or core unexpected reset + dhi_fsm_next = DHI_STATE_IDLE; + end +end + +assign dhi_fsm_idle = (dhi_fsm_ff == DHI_STATE_IDLE); +assign dhi_fsm_halt_req = (dhi_fsm_ff == DHI_STATE_HALT_REQ); +assign dhi_fsm_exec = (dhi_fsm_ff == DHI_STATE_EXEC); +assign dhi_fsm_exec_halt = (dhi_fsm_ff == DHI_STATE_EXEC_HALT); +assign dhi_fsm_resume_req = (dhi_fsm_ff == DHI_STATE_RESUME_REQ); + +always_comb begin + case (1'b1) + abs_exec_req_ff: dhi_req = DHI_STATE_EXEC; + halt_req_vd : dhi_req = DHI_STATE_HALT_REQ; + resume_req_vd : dhi_req = DHI_STATE_RESUME_REQ; + default : dhi_req = DHI_STATE_IDLE; + endcase +end + +assign dhi_resp = dhi_fsm_exec_halt & hart_state_dhalt; +assign dhi_resp_exc = pipe2dm_hart_event_i & pipe2dm_hart_status_i.except + & ~pipe2dm_hart_status_i.ebreak; + +// HART command registers +//------------------------------------------------------------------------------ + +// HART command request register +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + hart_cmd_req_ff <= 1'b0; + end else if (clk_en_dm) begin + hart_cmd_req_ff <= hart_cmd_req_next; + end +end + +assign hart_cmd_req_next = (dhi_fsm_exec | dhi_fsm_halt_req | dhi_fsm_resume_req) + & ~cmd_resp_ok & dmcontrol_dmactive_ff; + +// HART command register +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + hart_cmd_ff <= SCR1_HDU_DBGSTATE_RUN; + end else if (clk_en_dm) begin + hart_cmd_ff <= hart_cmd_next; + end +end + +always_comb begin + hart_cmd_next = SCR1_HDU_DBGSTATE_RUN; + if (dmcontrol_dmactive_ff) begin + case (dhi_fsm_ff) + DHI_STATE_EXEC : hart_cmd_next = SCR1_HDU_DBGSTATE_DRUN; + DHI_STATE_HALT_REQ : hart_cmd_next = SCR1_HDU_DBGSTATE_DHALTED; + DHI_STATE_RESUME_REQ: hart_cmd_next = SCR1_HDU_DBGSTATE_RUN; + default : hart_cmd_next = dm2pipe_cmd_o; + endcase + end +end + +assign dm2pipe_cmd_req_o = hart_cmd_req_ff; +assign dm2pipe_cmd_o = hart_cmd_ff; + +//------------------------------------------------------------------------------ +// Debug Hart Interface : program buffer +//------------------------------------------------------------------------------ + +// Program Buffer execution EBREAK flag +//------------------------------------------------------------------------------ + +always_ff @(posedge clk) begin + if (clk_en_dm) hart_pbuf_ebreak_ff <= hart_pbuf_ebreak_next; +end + +assign hart_pbuf_ebreak_next = abs_fsm_exec & (dm2pipe_pbuf_instr_o == ABS_EXEC_EBREAK); + +// Program Buffer instruction multiplexer +//------------------------------------------------------------------------------ + +always_comb begin + dm2pipe_pbuf_instr_o = ABS_EXEC_EBREAK; + + if (abs_fsm_exec & ~hart_pbuf_ebreak_ff) begin + case (pipe2dm_pbuf_addr_i) + 3'h0: dm2pipe_pbuf_instr_o = abs_progbuf0_ff; + 3'h1: dm2pipe_pbuf_instr_o = abs_progbuf1_ff; + 3'h2: dm2pipe_pbuf_instr_o = abs_progbuf2_ff; + 3'h3: dm2pipe_pbuf_instr_o = abs_progbuf3_ff; + 3'h4: dm2pipe_pbuf_instr_o = abs_progbuf4_ff; + 3'h5: dm2pipe_pbuf_instr_o = abs_progbuf5_ff; + default: begin end + endcase + end else if (pipe2dm_pbuf_addr_i == 3'b0) begin + dm2pipe_pbuf_instr_o = abs_exec_instr_ff; + end +end + +//------------------------------------------------------------------------------ +// Debug Hart Interface : abstract command data +//------------------------------------------------------------------------------ + +assign dm2pipe_dreg_resp_o = 1'b1; +assign dm2pipe_dreg_fail_o = 1'b0; +assign dm2pipe_dreg_rdata_o = abs_fsm_use_addr ? abs_data1_ff : abs_data0_ff; + +`ifdef SCR1_TRGT_SIMULATION +//------------------------------------------------------------------------------ +// Assertions +//------------------------------------------------------------------------------ + +SVA_DM_X_CONTROL : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown({dmi2dm_req_i, pipe2dm_dreg_req_i, pipe2dm_cmd_resp_i, + pipe2dm_hart_event_i}) +) else $error("DM error: control signals is X - %0b", {dmi2dm_req_i, + pipe2dm_dreg_req_i, pipe2dm_cmd_resp_i, pipe2dm_hart_event_i}); + +SVA_DM_X_DMI : assert property ( + @(negedge clk) disable iff (~rst_n) + dmi2dm_req_i |-> !$isunknown({dmi2dm_wr_i, dmi2dm_addr_i, dmi2dm_wdata_i}) +) else $error("DM error: data signals is X on dmi"); + +SVA_DM_X_HART_PBUF : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown (pipe2dm_pbuf_addr_i) +) else $error("DM error: data signals is X on hart_pbuf"); + +SVA_DM_X_HART_DREG : assert property ( + @(negedge clk) disable iff (~rst_n) + pipe2dm_dreg_req_i |-> !$isunknown({pipe2dm_dreg_wr_i, pipe2dm_dreg_wdata_i}) +) else $error("DM error: data signals is X on hart_dreg"); + +SVA_DM_X_HART_CMD : assert property ( + @(negedge clk) disable iff (~rst_n) + pipe2dm_cmd_resp_i |-> !$isunknown({pipe2dm_cmd_rcode_i}) +) else $error("DM error: data signals is X on dm2pipe_cmd_o"); + +SVA_DM_X_HART_EVENT : assert property ( + @(negedge clk) disable iff (~rst_n) + pipe2dm_hart_event_i |-> !$isunknown(pipe2dm_hart_status_i) +) else $error("DM error: data signals is X on pipe2dm_hart_event_i"); + +`endif // SCR1_TRGT_SIMULATION + +endmodule : scr1_dm + +`endif // SCR1_DBG_EN diff --git a/src/rtl/scr1/scr1_dm.svh b/src/rtl/scr1/scr1_dm.svh new file mode 100644 index 0000000..fea3921 --- /dev/null +++ b/src/rtl/scr1/scr1_dm.svh @@ -0,0 +1,141 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Debug Module header file +/// + +`ifndef SCR1_INCLUDE_DM_DEFS +`define SCR1_INCLUDE_DM_DEFS + +`include "scr1_arch_description.svh" +`include "scr1_hdu.svh" +`include "scr1_csr.svh" + +parameter SCR1_DBG_DMI_ADDR_WIDTH = 6'd7; +parameter SCR1_DBG_DMI_DATA_WIDTH = 6'd32; +parameter SCR1_DBG_DMI_OP_WIDTH = 2'd2; + +parameter SCR1_DBG_DMI_CH_ID_WIDTH = 2'd2; +parameter SCR1_DBG_DMI_DR_DTMCS_WIDTH = 6'd32; +parameter SCR1_DBG_DMI_DR_DMI_ACCESS_WIDTH = SCR1_DBG_DMI_OP_WIDTH + + SCR1_DBG_DMI_DATA_WIDTH + + SCR1_DBG_DMI_ADDR_WIDTH; + +// Debug Module addresses +parameter SCR1_DBG_DATA0 = 7'h4; +parameter SCR1_DBG_DATA1 = 7'h5; +parameter SCR1_DBG_DMCONTROL = 7'h10; +parameter SCR1_DBG_DMSTATUS = 7'h11; +parameter SCR1_DBG_HARTINFO = 7'h12; +parameter SCR1_DBG_ABSTRACTCS = 7'h16; +parameter SCR1_DBG_COMMAND = 7'h17; +parameter SCR1_DBG_ABSTRACTAUTO = 7'h18; +parameter SCR1_DBG_PROGBUF0 = 7'h20; +parameter SCR1_DBG_PROGBUF1 = 7'h21; +parameter SCR1_DBG_PROGBUF2 = 7'h22; +parameter SCR1_DBG_PROGBUF3 = 7'h23; +parameter SCR1_DBG_PROGBUF4 = 7'h24; +parameter SCR1_DBG_PROGBUF5 = 7'h25; +parameter SCR1_DBG_HALTSUM0 = 7'h40; + +// DMCONTROL +parameter SCR1_DBG_DMCONTROL_HALTREQ = 5'd31; +parameter SCR1_DBG_DMCONTROL_RESUMEREQ = 5'd30; +parameter SCR1_DBG_DMCONTROL_HARTRESET = 5'd29; +parameter SCR1_DBG_DMCONTROL_ACKHAVERESET = 5'd28; +parameter SCR1_DBG_DMCONTROL_RESERVEDB = 5'd27; +parameter SCR1_DBG_DMCONTROL_HASEL = 5'd26; +parameter SCR1_DBG_DMCONTROL_HARTSELLO_HI = 5'd25; +parameter SCR1_DBG_DMCONTROL_HARTSELLO_LO = 5'd16; +parameter SCR1_DBG_DMCONTROL_HARTSELHI_HI = 5'd15; +parameter SCR1_DBG_DMCONTROL_HARTSELHI_LO = 5'd6; +parameter SCR1_DBG_DMCONTROL_RESERVEDA_HI = 5'd5; +parameter SCR1_DBG_DMCONTROL_RESERVEDA_LO = 5'd2; +parameter SCR1_DBG_DMCONTROL_NDMRESET = 5'd1; +parameter SCR1_DBG_DMCONTROL_DMACTIVE = 5'd0; + +// DMSTATUS +parameter SCR1_DBG_DMSTATUS_RESERVEDC_HI = 5'd31; +parameter SCR1_DBG_DMSTATUS_RESERVEDC_LO = 5'd23; +parameter SCR1_DBG_DMSTATUS_IMPEBREAK = 5'd22; +parameter SCR1_DBG_DMSTATUS_RESERVEDB_HI = 5'd21; +parameter SCR1_DBG_DMSTATUS_RESERVEDB_LO = 5'd20; +parameter SCR1_DBG_DMSTATUS_ALLHAVERESET = 5'd19; +parameter SCR1_DBG_DMSTATUS_ANYHAVERESET = 5'd18; +parameter SCR1_DBG_DMSTATUS_ALLRESUMEACK = 5'd17; +parameter SCR1_DBG_DMSTATUS_ANYRESUMEACK = 5'd16; +parameter SCR1_DBG_DMSTATUS_ALLNONEXISTENT = 5'd15; +parameter SCR1_DBG_DMSTATUS_ANYNONEXISTENT = 5'd14; +parameter SCR1_DBG_DMSTATUS_ALLUNAVAIL = 5'd13; +parameter SCR1_DBG_DMSTATUS_ANYUNAVAIL = 5'd12; +parameter SCR1_DBG_DMSTATUS_ALLRUNNING = 5'd11; +parameter SCR1_DBG_DMSTATUS_ANYRUNNING = 5'd10; +parameter SCR1_DBG_DMSTATUS_ALLHALTED = 5'd9; +parameter SCR1_DBG_DMSTATUS_ANYHALTED = 5'd8; +parameter SCR1_DBG_DMSTATUS_AUTHENTICATED = 5'd7; +parameter SCR1_DBG_DMSTATUS_AUTHBUSY = 5'd6; +parameter SCR1_DBG_DMSTATUS_RESERVEDA = 5'd5; +parameter SCR1_DBG_DMSTATUS_DEVTREEVALID = 5'd4; +parameter SCR1_DBG_DMSTATUS_VERSION_HI = 5'd3; +parameter SCR1_DBG_DMSTATUS_VERSION_LO = 5'd0; + +// COMMANDS +parameter SCR1_DBG_COMMAND_TYPE_HI = 5'd31; +parameter SCR1_DBG_COMMAND_TYPE_LO = 5'd24; +parameter SCR1_DBG_COMMAND_TYPE_WDTH = SCR1_DBG_COMMAND_TYPE_HI + - SCR1_DBG_COMMAND_TYPE_LO; + +parameter SCR1_DBG_COMMAND_ACCESSREG_RESERVEDB = 5'd23; +parameter SCR1_DBG_COMMAND_ACCESSREG_SIZE_HI = 5'd22; +parameter SCR1_DBG_COMMAND_ACCESSREG_SIZE_LO = 5'd20; +parameter SCR1_DBG_COMMAND_ACCESSREG_SIZE_WDTH = SCR1_DBG_COMMAND_ACCESSREG_SIZE_HI + - SCR1_DBG_COMMAND_ACCESSREG_SIZE_LO; +parameter SCR1_DBG_COMMAND_ACCESSREG_RESERVEDA = 5'd19; +parameter SCR1_DBG_COMMAND_ACCESSREG_POSTEXEC = 5'd18; +parameter SCR1_DBG_COMMAND_ACCESSREG_TRANSFER = 5'd17; +parameter SCR1_DBG_COMMAND_ACCESSREG_WRITE = 5'd16; +parameter SCR1_DBG_COMMAND_ACCESSREG_REGNO_HI = 5'd15; +parameter SCR1_DBG_COMMAND_ACCESSREG_REGNO_LO = 5'd0; + +parameter SCR1_DBG_COMMAND_ACCESSMEM_AAMVIRTUAL = 5'd23; +parameter SCR1_DBG_COMMAND_ACCESSMEM_AAMSIZE_HI = 5'd22; +parameter SCR1_DBG_COMMAND_ACCESSMEM_AAMSIZE_LO = 5'd20; +parameter SCR1_DBG_COMMAND_ACCESSMEM_AAMPOSTINC = 5'd19; +parameter SCR1_DBG_COMMAND_ACCESSMEM_RESERVEDB_HI = 5'd18; +parameter SCR1_DBG_COMMAND_ACCESSMEM_RESERVEDB_LO = 5'd17; +parameter SCR1_DBG_COMMAND_ACCESSMEM_WRITE = 5'd16; +parameter SCR1_DBG_COMMAND_ACCESSMEM_RESERVEDA_HI = 5'd13; +parameter SCR1_DBG_COMMAND_ACCESSMEM_RESERVEDA_LO = 5'd0; + +// ABSTRACTCS +parameter SCR1_DBG_ABSTRACTCS_RESERVEDD_HI = 5'd31; +parameter SCR1_DBG_ABSTRACTCS_RESERVEDD_LO = 5'd29; +parameter SCR1_DBG_ABSTRACTCS_PROGBUFSIZE_HI = 5'd28; +parameter SCR1_DBG_ABSTRACTCS_PROGBUFSIZE_LO = 5'd24; +parameter SCR1_DBG_ABSTRACTCS_RESERVEDC_HI = 5'd23; +parameter SCR1_DBG_ABSTRACTCS_RESERVEDC_LO = 5'd13; +parameter SCR1_DBG_ABSTRACTCS_BUSY = 5'd12; +parameter SCR1_DBG_ABSTRACTCS_RESERVEDB = 5'd11; +parameter SCR1_DBG_ABSTRACTCS_CMDERR_HI = 5'd10; +parameter SCR1_DBG_ABSTRACTCS_CMDERR_LO = 5'd8; +parameter SCR1_DBG_ABSTRACTCS_CMDERR_WDTH = SCR1_DBG_ABSTRACTCS_CMDERR_HI + - SCR1_DBG_ABSTRACTCS_CMDERR_LO; +parameter SCR1_DBG_ABSTRACTCS_RESERVEDA_HI = 5'd7; +parameter SCR1_DBG_ABSTRACTCS_RESERVEDA_LO = 5'd4; +parameter SCR1_DBG_ABSTRACTCS_DATACOUNT_HI = 5'd3; +parameter SCR1_DBG_ABSTRACTCS_DATACOUNT_LO = 5'd0; + +// HARTINFO +parameter SCR1_DBG_HARTINFO_RESERVEDB_HI = 5'd31; +parameter SCR1_DBG_HARTINFO_RESERVEDB_LO = 5'd24; +parameter SCR1_DBG_HARTINFO_NSCRATCH_HI = 5'd23; +parameter SCR1_DBG_HARTINFO_NSCRATCH_LO = 5'd20; +parameter SCR1_DBG_HARTINFO_RESERVEDA_HI = 5'd19; +parameter SCR1_DBG_HARTINFO_RESERVEDA_LO = 5'd17; +parameter SCR1_DBG_HARTINFO_DATAACCESS = 5'd16; +parameter SCR1_DBG_HARTINFO_DATASIZE_HI = 5'd15; +parameter SCR1_DBG_HARTINFO_DATASIZE_LO = 5'd12; +parameter SCR1_DBG_HARTINFO_DATAADDR_HI = 5'd11; +parameter SCR1_DBG_HARTINFO_DATAADDR_LO = 5'd0; + + +`endif // SCR1_INCLUDE_DM_DEFS diff --git a/src/rtl/scr1/scr1_dmem_ahb.sv b/src/rtl/scr1/scr1_dmem_ahb.sv new file mode 100644 index 0000000..d6fbb85 --- /dev/null +++ b/src/rtl/scr1/scr1_dmem_ahb.sv @@ -0,0 +1,480 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Data memory AHB bridge +/// + +`include "scr1_ahb.svh" +`include "scr1_memif.svh" + +module scr1_dmem_ahb ( + // Control Signals + input logic rst_n, + input logic clk, + + // Core Interface + output logic dmem_req_ack, + input logic dmem_req, + input type_scr1_mem_cmd_e dmem_cmd, + input type_scr1_mem_width_e dmem_width, + input logic [SCR1_AHB_WIDTH-1:0] dmem_addr, + input logic [SCR1_AHB_WIDTH-1:0] dmem_wdata, + output logic [SCR1_AHB_WIDTH-1:0] dmem_rdata, + output type_scr1_mem_resp_e dmem_resp, + + // AHB Interface + output logic [3:0] hprot, + output logic [2:0] hburst, + output logic [2:0] hsize, + output logic [1:0] htrans, + output logic hmastlock, + output logic [SCR1_AHB_WIDTH-1:0] haddr, + output logic hwrite, + output logic [SCR1_AHB_WIDTH-1:0] hwdata, + input logic hready, + input logic [SCR1_AHB_WIDTH-1:0] hrdata, + input logic hresp + +); + +//------------------------------------------------------------------------------- +// Local Parameters +//------------------------------------------------------------------------------- +`ifndef SCR1_DMEM_AHB_OUT_BP +localparam SCR1_FIFO_WIDTH = 2; +localparam SCR1_FIFO_CNT_WIDTH = $clog2(SCR1_FIFO_WIDTH+1); +`endif // SCR1_DMEM_AHB_OUT_BP + +//------------------------------------------------------------------------------- +// Local type declaration +//------------------------------------------------------------------------------- +typedef enum logic { + SCR1_FSM_ADDR = 1'b0, + SCR1_FSM_DATA = 1'b1 +`ifdef SCR1_XPROP_EN + , + SCR1_FSM_ERR = 1'bx +`endif // SCR1_XPROP_EN +} type_scr1_fsm_e; + +typedef struct packed { + logic hwrite; + logic [2:0] hwidth; + logic [SCR1_AHB_WIDTH-1:0] haddr; + logic [SCR1_AHB_WIDTH-1:0] hwdata; +} type_scr1_req_fifo_s; + +typedef struct packed { + logic [2:0] hwidth; + logic [1:0] haddr; + logic [SCR1_AHB_WIDTH-1:0] hwdata; +} type_scr1_data_fifo_s; + +typedef struct packed { + logic hresp; + logic [2:0] hwidth; + logic [1:0] haddr; + logic [SCR1_AHB_WIDTH-1:0] hrdata; +} type_scr1_resp_fifo_s; + +//------------------------------------------------------------------------------- +// Local functions +//------------------------------------------------------------------------------- +function automatic logic [2:0] scr1_conv_mem2ahb_width ( + input type_scr1_mem_width_e dmem_width +); + logic [2:0] tmp; +begin + case (dmem_width) + SCR1_MEM_WIDTH_BYTE : begin + tmp = SCR1_HSIZE_8B; + end + SCR1_MEM_WIDTH_HWORD : begin + tmp = SCR1_HSIZE_16B; + end + SCR1_MEM_WIDTH_WORD : begin + tmp = SCR1_HSIZE_32B; + end + default : begin + tmp = SCR1_HSIZE_ERR; + end + endcase + return tmp; +end +endfunction : scr1_conv_mem2ahb_width + +function automatic logic[SCR1_AHB_WIDTH-1:0] scr1_conv_mem2ahb_wdata ( + input logic [1:0] dmem_addr, + input type_scr1_mem_width_e dmem_width, + input logic [SCR1_AHB_WIDTH-1:0] dmem_wdata +); + logic [SCR1_AHB_WIDTH-1:0] tmp; +begin +`ifdef SCR1_XPROP_EN + tmp = 'x; +`else // SCR1_XPROP_EN + tmp = '0; +`endif // SCR1_XPROP_EN + case (dmem_width) + SCR1_MEM_WIDTH_BYTE : begin + case (dmem_addr) + 2'b00 : begin + tmp[7:0] = dmem_wdata[7:0]; + end + 2'b01 : begin + tmp[15:8] = dmem_wdata[7:0]; + end + 2'b10 : begin + tmp[23:16] = dmem_wdata[7:0]; + end + 2'b11 : begin + tmp[31:24] = dmem_wdata[7:0]; + end + default : begin + end + endcase + end + SCR1_MEM_WIDTH_HWORD : begin + case (dmem_addr[1]) + 1'b0 : begin + tmp[15:0] = dmem_wdata[15:0]; + end + 1'b1 : begin + tmp[31:16] = dmem_wdata[15:0]; + end + default : begin + end + endcase + end + SCR1_MEM_WIDTH_WORD : begin + tmp = dmem_wdata; + end + default : begin + end + endcase + return tmp; +end +endfunction : scr1_conv_mem2ahb_wdata + +function automatic logic[SCR1_AHB_WIDTH-1:0] scr1_conv_ahb2mem_rdata ( + input logic [2:0] hwidth, + input logic [1:0] haddr, + input logic [SCR1_AHB_WIDTH-1:0] hrdata +); + logic [SCR1_AHB_WIDTH-1:0] tmp; +begin +`ifdef SCR1_XPROP_EN + tmp = 'x; +`else // SCR1_XPROP_EN + tmp = '0; +`endif // SCR1_XPROP_EN + case (hwidth) + SCR1_HSIZE_8B : begin + case (haddr) + 2'b00 : tmp[7:0] = hrdata[7:0]; + 2'b01 : tmp[7:0] = hrdata[15:8]; + 2'b10 : tmp[7:0] = hrdata[23:16]; + 2'b11 : tmp[7:0] = hrdata[31:24]; + default : begin + end + endcase + end + SCR1_HSIZE_16B : begin + case (haddr[1]) + 1'b0 : tmp[15:0] = hrdata[15:0]; + 1'b1 : tmp[15:0] = hrdata[31:16]; + default : begin + end + endcase + end + SCR1_HSIZE_32B : begin + tmp = hrdata; + end + default : begin + end + endcase + return tmp; +end +endfunction : scr1_conv_ahb2mem_rdata + +//------------------------------------------------------------------------------- +// Local signal declaration +//------------------------------------------------------------------------------- +type_scr1_fsm_e fsm; +logic req_fifo_rd; +logic req_fifo_wr; +logic req_fifo_up; +`ifdef SCR1_DMEM_AHB_OUT_BP +type_scr1_req_fifo_s req_fifo_new; +type_scr1_req_fifo_s req_fifo_r; +type_scr1_req_fifo_s [0:0] req_fifo; +`else // SCR1_DMEM_AHB_OUT_BP +type_scr1_req_fifo_s [0:SCR1_FIFO_WIDTH-1] req_fifo; +type_scr1_req_fifo_s [0:SCR1_FIFO_WIDTH-1] req_fifo_new; +logic [SCR1_FIFO_CNT_WIDTH-1:0] req_fifo_cnt; +logic [SCR1_FIFO_CNT_WIDTH-1:0] req_fifo_cnt_new; +`endif // SCR1_DMEM_AHB_OUT_BP +logic req_fifo_empty; +logic req_fifo_full; + +type_scr1_data_fifo_s data_fifo; +type_scr1_resp_fifo_s resp_fifo; +logic resp_fifo_hready; + +//------------------------------------------------------------------------------- +// Interface to Core +//------------------------------------------------------------------------------- +assign dmem_req_ack = ~req_fifo_full; +assign req_fifo_wr = ~req_fifo_full & dmem_req; + +assign dmem_rdata = scr1_conv_ahb2mem_rdata(resp_fifo.hwidth, resp_fifo.haddr, resp_fifo.hrdata); + +assign dmem_resp = (resp_fifo_hready) + ? (resp_fifo.hresp == SCR1_HRESP_OKAY) + ? SCR1_MEM_RESP_RDY_OK + : SCR1_MEM_RESP_RDY_ER + : SCR1_MEM_RESP_NOTRDY ; + +//------------------------------------------------------------------------------- +// REQ_FIFO +//------------------------------------------------------------------------------- +`ifdef SCR1_DMEM_AHB_OUT_BP +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + req_fifo_full <= 1'b0; + end else begin + if (~req_fifo_full) begin + req_fifo_full <= dmem_req & ~req_fifo_rd; + end else begin + req_fifo_full <= ~req_fifo_rd; + end + end +end +assign req_fifo_empty = ~(req_fifo_full | dmem_req); + +assign req_fifo_up = ~req_fifo_rd & req_fifo_wr; +always_ff @(posedge clk) begin + if (req_fifo_up) begin + req_fifo_r <= req_fifo_new; + end +end + +assign req_fifo_new.hwrite = dmem_req ? (dmem_cmd == SCR1_MEM_CMD_WR) : 1'b0; +assign req_fifo_new.hwidth = dmem_req ? scr1_conv_mem2ahb_width(dmem_width) : '0; +assign req_fifo_new.haddr = dmem_req ? dmem_addr : '0; +assign req_fifo_new.hwdata = (dmem_req & (dmem_cmd == SCR1_MEM_CMD_WR)) + ? scr1_conv_mem2ahb_wdata(dmem_addr[1:0], dmem_width, dmem_wdata) + : '0; +assign req_fifo[0] = (req_fifo_full) ? req_fifo_r: req_fifo_new; + +`else // SCR1_DMEM_AHB_OUT_BP +always_comb begin + req_fifo_up = 1'b0; + req_fifo_cnt_new = req_fifo_cnt; + req_fifo_new = req_fifo; + case ({req_fifo_rd, req_fifo_wr}) + 2'b00 : begin + // nothing todo + end + 2'b01: begin + // FIFO write + req_fifo_up = 1'b1; + req_fifo_new[req_fifo_cnt].hwrite = (dmem_cmd == SCR1_MEM_CMD_WR); + req_fifo_new[req_fifo_cnt].hwidth = scr1_conv_mem2ahb_width(dmem_width); + req_fifo_new[req_fifo_cnt].haddr = dmem_addr; + req_fifo_new[req_fifo_cnt].hwdata = scr1_conv_mem2ahb_wdata(dmem_addr[1:0], dmem_width, dmem_wdata); + req_fifo_cnt_new = req_fifo_cnt + 1'b1; + end + 2'b10 : begin + // FIFO read + req_fifo_up = 1'b1; + req_fifo_new[0] = req_fifo_new[1]; + req_fifo_new[1].hwrite = 1'b0; + req_fifo_new[1].hwidth = SCR1_HSIZE_32B; +`ifdef SCR1_XPROP_EN + req_fifo_new[1].haddr = 'x; + req_fifo_new[1].hwdata = 'x; +`endif // SCR1_XPROP_EN + req_fifo_cnt_new = req_fifo_cnt - 1'b1; + end + 2'b11 : begin + // Read and Write FIFO. It is possible only when fifo_cnt = 1 + req_fifo_up = 1'b1; + req_fifo_new[0].hwrite = (dmem_cmd == SCR1_MEM_CMD_WR); + req_fifo_new[0].hwidth = scr1_conv_mem2ahb_width(dmem_width); + req_fifo_new[0].haddr = dmem_addr; + req_fifo_new[0].hwdata = scr1_conv_mem2ahb_wdata(dmem_addr[1:0], dmem_width, dmem_wdata); + end + default : begin +`ifdef SCR1_XPROP_EN + req_fifo_up = 'x; + req_fifo_cnt_new = 'x; + req_fifo_new = 'x; +`endif // SCR1_XPROP_EN + end + endcase +end + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + req_fifo_cnt <= '0; + end else begin + if (req_fifo_up) begin + req_fifo_cnt <= req_fifo_cnt_new; + end + end +end +assign req_fifo_full = (req_fifo_cnt == SCR1_FIFO_WIDTH); +assign req_fifo_empty = ~(|req_fifo_cnt); + +always_ff @(posedge clk) begin + if (req_fifo_up) begin + req_fifo <= req_fifo_new; + end +end +`endif // SCR1_DMEM_AHB_OUT_BP +//------------------------------------------------------------------------------- +// FSM +//------------------------------------------------------------------------------- +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + fsm <= SCR1_FSM_ADDR; + end else begin + case (fsm) + SCR1_FSM_ADDR : begin + if (hready) begin + fsm <= (req_fifo_empty) ? SCR1_FSM_ADDR : SCR1_FSM_DATA; + end + end + SCR1_FSM_DATA : begin + if (hready) begin + if (hresp == SCR1_HRESP_OKAY) begin + fsm <= (req_fifo_empty) ? SCR1_FSM_ADDR : SCR1_FSM_DATA; + end else begin + fsm <= SCR1_FSM_ADDR; + end + end + end + default : begin +`ifdef SCR1_XPROP_EN + fsm <= SCR1_FSM_ERR; +`endif // SCR1_XPROP_EN + end + endcase + end +end + +always_comb begin + req_fifo_rd = 1'b0; + case (fsm) + SCR1_FSM_ADDR : begin + if (hready) begin + req_fifo_rd = ~req_fifo_empty; + end + end + SCR1_FSM_DATA : begin + if (hready) begin + req_fifo_rd = ~req_fifo_empty & (hresp == SCR1_HRESP_OKAY); + end + end + default : begin + req_fifo_rd = 1'bx; + end + endcase +end + +//------------------------------------------------------------------------------- +// FIFO data +//------------------------------------------------------------------------------- +always_ff @(posedge clk) begin + case (fsm) + SCR1_FSM_ADDR : begin + if (~req_fifo_empty) begin + data_fifo.hwidth <= req_fifo[0].hwidth; + data_fifo.haddr <= req_fifo[0].haddr[1:0]; + data_fifo.hwdata <= req_fifo[0].hwdata; + end + end + SCR1_FSM_DATA : begin + if (hready) begin + if (hresp == SCR1_HRESP_OKAY) begin + if (~req_fifo_empty) begin + data_fifo.hwidth <= req_fifo[0].hwidth; + data_fifo.haddr <= req_fifo[0].haddr[1:0]; + data_fifo.hwdata <= req_fifo[0].hwdata; + end + end + end + end + default : begin + end + endcase +end + +//------------------------------------------------------------------------------- +// FIFO response +//------------------------------------------------------------------------------- +`ifdef SCR1_DMEM_AHB_IN_BP +assign resp_fifo_hready = (fsm == SCR1_FSM_DATA) ? hready : 1'b0; +assign resp_fifo.hresp = hresp; +assign resp_fifo.hwidth = data_fifo.hwidth; +assign resp_fifo.haddr = data_fifo.haddr; +assign resp_fifo.hrdata = hrdata; +`else // SCR1_DMEM_AHB_IN_BP +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + resp_fifo_hready <= 1'b0; + end else begin + resp_fifo_hready <= (fsm == SCR1_FSM_DATA) ? hready : 1'b0; + end +end + +always_ff @(posedge clk) begin + if (hready & (fsm == SCR1_FSM_DATA)) begin + resp_fifo.hresp <= hresp; + resp_fifo.hwidth <= data_fifo.hwidth; + resp_fifo.haddr <= data_fifo.haddr; + resp_fifo.hrdata <= hrdata; + end +end +`endif // SCR1_DMEM_AHB_IN_BP + +//------------------------------------------------------------------------------- +// Interface to AHB +//------------------------------------------------------------------------------- +assign hprot[SCR1_HPROT_DATA] = 1'b1; +assign hprot[SCR1_HPROT_PRV] = 1'b0; +assign hprot[SCR1_HPROT_BUF] = 1'b0; +assign hprot[SCR1_HPROT_CACHE] = 1'b0; + +assign hburst = SCR1_HBURST_SINGLE; +assign hsize = req_fifo[0].hwidth; +assign hmastlock = 1'b0; + +always_comb begin + htrans = SCR1_HTRANS_IDLE; + case (fsm) + SCR1_FSM_ADDR : begin + if (~req_fifo_empty) begin + htrans = SCR1_HTRANS_NONSEQ; + end + end + SCR1_FSM_DATA : begin + if (hready) begin + if (hresp == SCR1_HRESP_OKAY) begin + if (~req_fifo_empty) begin + htrans = SCR1_HTRANS_NONSEQ; + end + end + end + end + default : begin + htrans = SCR1_HTRANS_ERR; + end + endcase +end + +assign haddr = req_fifo[0].haddr; +assign hwrite = req_fifo[0].hwrite; +assign hwdata = data_fifo.hwdata; + +endmodule : scr1_dmem_ahb diff --git a/src/rtl/scr1/scr1_dmem_router.sv b/src/rtl/scr1/scr1_dmem_router.sv new file mode 100644 index 0000000..afef729 --- /dev/null +++ b/src/rtl/scr1/scr1_dmem_router.sv @@ -0,0 +1,278 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Data memory router +/// +`include "scr1_memif.svh" +`include "scr1_arch_description.svh" + +module scr1_dmem_router +#( + parameter SCR1_PORT1_ADDR_MASK = `SCR1_DMEM_AWIDTH'hFFFF0000, + parameter SCR1_PORT1_ADDR_PATTERN = `SCR1_DMEM_AWIDTH'h00010000, + parameter SCR1_PORT2_ADDR_MASK = `SCR1_DMEM_AWIDTH'hFFFF0000, + parameter SCR1_PORT2_ADDR_PATTERN = `SCR1_DMEM_AWIDTH'h00020000 +) +( + // Control signals + input logic rst_n, + input logic clk, + + // Core interface + output logic dmem_req_ack, + input logic dmem_req, + input type_scr1_mem_cmd_e dmem_cmd, + input type_scr1_mem_width_e dmem_width, + input logic [`SCR1_DMEM_AWIDTH-1:0] dmem_addr, + input logic [`SCR1_DMEM_DWIDTH-1:0] dmem_wdata, + output logic [`SCR1_DMEM_DWIDTH-1:0] dmem_rdata, + output type_scr1_mem_resp_e dmem_resp, + + // PORT0 interface + input logic port0_req_ack, + output logic port0_req, + output type_scr1_mem_cmd_e port0_cmd, + output type_scr1_mem_width_e port0_width, + output logic [`SCR1_DMEM_AWIDTH-1:0] port0_addr, + output logic [`SCR1_DMEM_DWIDTH-1:0] port0_wdata, + input logic [`SCR1_DMEM_DWIDTH-1:0] port0_rdata, + input type_scr1_mem_resp_e port0_resp, + + // PORT1 interface + input logic port1_req_ack, + output logic port1_req, + output type_scr1_mem_cmd_e port1_cmd, + output type_scr1_mem_width_e port1_width, + output logic [`SCR1_DMEM_AWIDTH-1:0] port1_addr, + output logic [`SCR1_DMEM_DWIDTH-1:0] port1_wdata, + input logic [`SCR1_DMEM_DWIDTH-1:0] port1_rdata, + input type_scr1_mem_resp_e port1_resp, + + // PORT2 interface + input logic port2_req_ack, + output logic port2_req, + output type_scr1_mem_cmd_e port2_cmd, + output type_scr1_mem_width_e port2_width, + output logic [`SCR1_DMEM_AWIDTH-1:0] port2_addr, + output logic [`SCR1_DMEM_DWIDTH-1:0] port2_wdata, + input logic [`SCR1_DMEM_DWIDTH-1:0] port2_rdata, + input type_scr1_mem_resp_e port2_resp +); + +//------------------------------------------------------------------------------- +// Local types declaration +//------------------------------------------------------------------------------- +typedef enum logic { + SCR1_FSM_ADDR, + SCR1_FSM_DATA +} type_scr1_fsm_e; + +typedef enum logic [1:0] { + SCR1_SEL_PORT0, + SCR1_SEL_PORT1, + SCR1_SEL_PORT2 +} type_scr1_sel_e; + +//------------------------------------------------------------------------------- +// Local signal declaration +//------------------------------------------------------------------------------- +type_scr1_fsm_e fsm; +type_scr1_sel_e port_sel; +type_scr1_sel_e port_sel_r; +logic [`SCR1_DMEM_DWIDTH-1:0] sel_rdata; +type_scr1_mem_resp_e sel_resp; +logic sel_req_ack; + +//------------------------------------------------------------------------------- +// FSM +//------------------------------------------------------------------------------- +always_comb begin + port_sel = SCR1_SEL_PORT0; + if ((dmem_addr & SCR1_PORT1_ADDR_MASK) == SCR1_PORT1_ADDR_PATTERN) begin + port_sel = SCR1_SEL_PORT1; + end else if ((dmem_addr & SCR1_PORT2_ADDR_MASK) == SCR1_PORT2_ADDR_PATTERN) begin + port_sel = SCR1_SEL_PORT2; + end +end + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + fsm <= SCR1_FSM_ADDR; + port_sel_r <= SCR1_SEL_PORT0; + end else begin + case (fsm) + SCR1_FSM_ADDR : begin + if (dmem_req & sel_req_ack) begin + fsm <= SCR1_FSM_DATA; + port_sel_r <= port_sel; + end + end + SCR1_FSM_DATA : begin + case (sel_resp) + SCR1_MEM_RESP_RDY_OK : begin + if (dmem_req & sel_req_ack) begin + fsm <= SCR1_FSM_DATA; + port_sel_r <= port_sel; + end else begin + fsm <= SCR1_FSM_ADDR; + end + end + SCR1_MEM_RESP_RDY_ER : begin + fsm <= SCR1_FSM_ADDR; + end + default : begin + end + endcase + end + default : begin + end + endcase + end +end + +always_comb begin + if ((fsm == SCR1_FSM_ADDR) | ((fsm == SCR1_FSM_DATA) & (sel_resp == SCR1_MEM_RESP_RDY_OK))) begin + case (port_sel) + SCR1_SEL_PORT0 : sel_req_ack = port0_req_ack; + SCR1_SEL_PORT1 : sel_req_ack = port1_req_ack; + SCR1_SEL_PORT2 : sel_req_ack = port2_req_ack; + default : sel_req_ack = 1'b0; + endcase + end else begin + sel_req_ack = 1'b0; + end +end + +always_comb begin + case (port_sel_r) + SCR1_SEL_PORT0 : begin + sel_rdata = port0_rdata; + sel_resp = port0_resp; + end + SCR1_SEL_PORT1 : begin + sel_rdata = port1_rdata; + sel_resp = port1_resp; + end + SCR1_SEL_PORT2 : begin + sel_rdata = port2_rdata; + sel_resp = port2_resp; + end + default : begin + sel_rdata = '0; + sel_resp = SCR1_MEM_RESP_RDY_ER; + end + endcase +end + +//------------------------------------------------------------------------------- +// Interface to core +//------------------------------------------------------------------------------- +assign dmem_req_ack = sel_req_ack; +assign dmem_rdata = sel_rdata; +assign dmem_resp = sel_resp; + +//------------------------------------------------------------------------------- +// Interface to PORT0 +//------------------------------------------------------------------------------- +always_comb begin + port0_req = 1'b0; + case (fsm) + SCR1_FSM_ADDR : begin + port0_req = dmem_req & (port_sel == SCR1_SEL_PORT0); + end + SCR1_FSM_DATA : begin + if (sel_resp == SCR1_MEM_RESP_RDY_OK) begin + port0_req = dmem_req & (port_sel == SCR1_SEL_PORT0); + end + end + default : begin + end + endcase +end + +`ifdef SCR1_XPROP_EN +assign port0_cmd = (port_sel == SCR1_SEL_PORT0) ? dmem_cmd : SCR1_MEM_CMD_ERROR; +assign port0_width = (port_sel == SCR1_SEL_PORT0) ? dmem_width : SCR1_MEM_WIDTH_ERROR; +assign port0_addr = (port_sel == SCR1_SEL_PORT0) ? dmem_addr : 'x; +assign port0_wdata = (port_sel == SCR1_SEL_PORT0) ? dmem_wdata : 'x; +`else // SCR1_XPROP_EN +assign port0_cmd = dmem_cmd ; +assign port0_width = dmem_width; +assign port0_addr = dmem_addr ; +assign port0_wdata = dmem_wdata; +`endif // SCR1_XPROP_EN + +//------------------------------------------------------------------------------- +// Interface to PORT1 +//------------------------------------------------------------------------------- +always_comb begin + port1_req = 1'b0; + case (fsm) + SCR1_FSM_ADDR : begin + port1_req = dmem_req & (port_sel == SCR1_SEL_PORT1); + end + SCR1_FSM_DATA : begin + if (sel_resp == SCR1_MEM_RESP_RDY_OK) begin + port1_req = dmem_req & (port_sel == SCR1_SEL_PORT1); + end + end + default : begin + end + endcase +end + +`ifdef SCR1_XPROP_EN +assign port1_cmd = (port_sel == SCR1_SEL_PORT1) ? dmem_cmd : SCR1_MEM_CMD_ERROR; +assign port1_width = (port_sel == SCR1_SEL_PORT1) ? dmem_width : SCR1_MEM_WIDTH_ERROR; +assign port1_addr = (port_sel == SCR1_SEL_PORT1) ? dmem_addr : 'x; +assign port1_wdata = (port_sel == SCR1_SEL_PORT1) ? dmem_wdata : 'x; +`else // SCR1_XPROP_EN +assign port1_cmd = dmem_cmd ; +assign port1_width = dmem_width; +assign port1_addr = dmem_addr ; +assign port1_wdata = dmem_wdata; +`endif // SCR1_XPROP_EN + +//------------------------------------------------------------------------------- +// Interface to PORT2 +//------------------------------------------------------------------------------- +always_comb begin + port2_req = 1'b0; + case (fsm) + SCR1_FSM_ADDR : begin + port2_req = dmem_req & (port_sel == SCR1_SEL_PORT2); + end + SCR1_FSM_DATA : begin + if (sel_resp == SCR1_MEM_RESP_RDY_OK) begin + port2_req = dmem_req & (port_sel == SCR1_SEL_PORT2); + end + end + default : begin + end + endcase +end + +`ifdef SCR1_XPROP_EN +assign port2_cmd = (port_sel == SCR1_SEL_PORT2) ? dmem_cmd : SCR1_MEM_CMD_ERROR; +assign port2_width = (port_sel == SCR1_SEL_PORT2) ? dmem_width : SCR1_MEM_WIDTH_ERROR; +assign port2_addr = (port_sel == SCR1_SEL_PORT2) ? dmem_addr : 'x; +assign port2_wdata = (port_sel == SCR1_SEL_PORT2) ? dmem_wdata : 'x; +`else // SCR1_XPROP_EN +assign port2_cmd = dmem_cmd ; +assign port2_width = dmem_width; +assign port2_addr = dmem_addr ; +assign port2_wdata = dmem_wdata; +`endif // SCR1_XPROP_EN + +`ifdef SCR1_TRGT_SIMULATION +//------------------------------------------------------------------------------- +// Assertion +//------------------------------------------------------------------------------- + +SCR1_SVA_DMEM_RT_XCHECK : assert property ( + @(negedge clk) disable iff (~rst_n) + dmem_req |-> !$isunknown({port_sel, dmem_cmd, dmem_width}) + ) else $error("DMEM router Error: unknown values"); + +`endif // SCR1_TRGT_SIMULATION + +endmodule : scr1_dmem_router diff --git a/src/rtl/scr1/scr1_dmi.sv b/src/rtl/scr1/scr1_dmi.sv new file mode 100644 index 0000000..5b61001 --- /dev/null +++ b/src/rtl/scr1/scr1_dmi.sv @@ -0,0 +1,182 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Debug Module Interface (DMI) +/// + +//------------------------------------------------------------------------------ + // + // Functionality: + // - Provides TAPC with access to Debug Module (DM) and DTMCS + // + // Structure: + // - DMI <-> TAP interface + // - DMI <-> DM interface + // +//------------------------------------------------------------------------------ + +`include "scr1_arch_description.svh" + +`ifdef SCR1_DBG_EN +`include "scr1_dm.svh" + +module scr1_dmi ( + // System + input logic rst_n, // DMI unit reset + input logic clk, // DMI unit clock + + // TAP interface + input logic tapcsync2dmi_ch_sel_i, // Debug Transport Module Chain Select + input logic [SCR1_DBG_DMI_CH_ID_WIDTH-1:0] tapcsync2dmi_ch_id_i, // Debug Transport Module Chain ID + input logic tapcsync2dmi_ch_capture_i, // Debug Transport Module Chain Capture + input logic tapcsync2dmi_ch_shift_i, // Debug Transport Module Chain Shift + input logic tapcsync2dmi_ch_update_i, // Debug Transport Module Chain Update + input logic tapcsync2dmi_ch_tdi_i, // Debug Transport Module Chain TDI + output logic dmi2tapcsync_ch_tdo_o, // Debug Transport Module Chain TDO + + // DM interface + input logic dm2dmi_resp_i, // DMI response + input logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dm2dmi_rdata_i, // DMI read data + output logic dmi2dm_req_o, // DMI request + output logic dmi2dm_wr_o, // DMI write + output logic [SCR1_DBG_DMI_ADDR_WIDTH-1:0] dmi2dm_addr_o, // DMI address + output logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dmi2dm_wdata_o // DMI write data +); + +//------------------------------------------------------------------------------ +// Local parameters declaration +//------------------------------------------------------------------------------ + +// Debug Transport Module Status parameters +//------------------------------------------------------------------------------ + +localparam DTMCS_RESERVEDB_HI = 5'd31; +localparam DTMCS_RESERVEDB_LO = 5'd18; +localparam DTMCS_DMIHARDRESET = 5'd17; +localparam DTMCS_DMIRESET = 5'd16; +localparam DTMCS_RESERVEDA = 5'd15; +localparam DTMCS_IDLE_HI = 5'd14; +localparam DTMCS_IDLE_LO = 5'd12; +localparam DTMCS_DMISTAT_HI = 5'd11; +localparam DTMCS_DMISTAT_LO = 5'd10; +localparam DTMCS_ABITS_HI = 5'd9; +localparam DTMCS_ABITS_LO = 5'd4; +localparam DTMCS_VERSION_HI = 5'd3; +localparam DTMCS_VERSION_LO = 5'd0; + +// Debug Module Interface parameters +//------------------------------------------------------------------------------ + +localparam DMI_OP_LO = 5'd0; +localparam DMI_OP_HI = DMI_OP_LO + SCR1_DBG_DMI_OP_WIDTH - 1; +localparam DMI_DATA_LO = DMI_OP_HI + 1; +localparam DMI_DATA_HI = DMI_DATA_LO + SCR1_DBG_DMI_DATA_WIDTH - 1; +localparam DMI_ADDR_LO = DMI_DATA_HI + 1; +localparam DMI_ADDR_HI = DMI_ADDR_LO + SCR1_DBG_DMI_ADDR_WIDTH - 1; + +//------------------------------------------------------------------------------ +// Local signals declaration +//------------------------------------------------------------------------------ + +// TAP data register +logic tap_dr_upd; +logic [SCR1_DBG_DMI_DR_DMI_ACCESS_WIDTH-1:0] tap_dr_ff; +logic [SCR1_DBG_DMI_DR_DMI_ACCESS_WIDTH-1:0] tap_dr_shift; +logic [SCR1_DBG_DMI_DR_DMI_ACCESS_WIDTH-1:0] tap_dr_rdata; +logic [SCR1_DBG_DMI_DR_DMI_ACCESS_WIDTH-1:0] tap_dr_next; + +// DM read data register +logic dm_rdata_upd; +logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dm_rdata_ff; + +logic tapc_dmi_access_req; +logic tapc_dtmcs_sel; + +//------------------------------------------------------------------------------ +// DMI <-> TAP interface +//------------------------------------------------------------------------------ + +// TAPC read data multiplexer +//------------------------------------------------------------------------------ + +assign tapc_dtmcs_sel = (tapcsync2dmi_ch_id_i == 1'd1); + +// DMI operation is always successful in the current implementation +always_comb begin + tap_dr_rdata = '0; + + if(tapc_dtmcs_sel) begin + tap_dr_rdata[DTMCS_RESERVEDB_HI:DTMCS_RESERVEDB_LO] = 'b0; + tap_dr_rdata[DTMCS_DMIHARDRESET] = 'b0; + tap_dr_rdata[DTMCS_DMIRESET] = 'b0; + tap_dr_rdata[DTMCS_RESERVEDA] = 'b0; + tap_dr_rdata[DTMCS_IDLE_HI:DTMCS_IDLE_LO] = 'b0; + tap_dr_rdata[DTMCS_DMISTAT_HI:DTMCS_DMISTAT_LO] = 'b0; + tap_dr_rdata[DTMCS_ABITS_HI :DTMCS_ABITS_LO] = SCR1_DBG_DMI_ADDR_WIDTH; + tap_dr_rdata[DTMCS_VERSION_LO] = 1'b1; + end else begin + tap_dr_rdata[DMI_ADDR_HI:DMI_ADDR_LO] = 'b0; + tap_dr_rdata[DMI_DATA_HI:DMI_DATA_LO] = dm_rdata_ff; + tap_dr_rdata[DMI_OP_HI :DMI_OP_LO] = 'b0; + end +end + +assign tap_dr_shift = tapc_dtmcs_sel + ? {9'b0, tapcsync2dmi_ch_tdi_i, tap_dr_ff[SCR1_DBG_DMI_DR_DTMCS_WIDTH-1:1]} + : {tapcsync2dmi_ch_tdi_i, tap_dr_ff[SCR1_DBG_DMI_DR_DMI_ACCESS_WIDTH-1:1]}; + +// TAP data register +//------------------------------------------------------------------------------ + +assign tap_dr_upd = tapcsync2dmi_ch_capture_i | tapcsync2dmi_ch_shift_i; + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + tap_dr_ff <= '0; + end else if(tap_dr_upd) begin + tap_dr_ff <= tap_dr_next; + end +end + +assign tap_dr_next = tapcsync2dmi_ch_capture_i ? tap_dr_rdata + : tapcsync2dmi_ch_shift_i ? tap_dr_shift + : tap_dr_ff; + +assign dmi2tapcsync_ch_tdo_o = tap_dr_ff[0]; + +//------------------------------------------------------------------------------ +// DMI <-> DM interface +//------------------------------------------------------------------------------ + +assign tapc_dmi_access_req = tapcsync2dmi_ch_update_i & tapcsync2dmi_ch_sel_i + & (tapcsync2dmi_ch_id_i == 2'd2); + +always_comb begin + dmi2dm_req_o = 1'b0; + dmi2dm_wr_o = 1'b0; + dmi2dm_addr_o = 1'b0; + dmi2dm_wdata_o = 1'b0; + + if(tapc_dmi_access_req) begin + dmi2dm_req_o = tap_dr_ff[DMI_OP_HI :DMI_OP_LO] != 2'b00; + dmi2dm_wr_o = tap_dr_ff[DMI_OP_HI :DMI_OP_LO] == 2'b10; + dmi2dm_addr_o = tap_dr_ff[DMI_ADDR_HI:DMI_ADDR_LO]; + dmi2dm_wdata_o = tap_dr_ff[DMI_DATA_HI:DMI_DATA_LO]; + end +end + +// DM read data register +//------------------------------------------------------------------------------ + +assign dm_rdata_upd = dmi2dm_req_o & dm2dmi_resp_i & ~dmi2dm_wr_o; + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + dm_rdata_ff <= '0; + end else if (dm_rdata_upd) begin + dm_rdata_ff <= dm2dmi_rdata_i; + end +end + +endmodule : scr1_dmi + +`endif // SCR1_DBG_EN diff --git a/src/rtl/scr1/scr1_dp_memory.sv b/src/rtl/scr1/scr1_dp_memory.sv new file mode 100644 index 0000000..971591d --- /dev/null +++ b/src/rtl/scr1/scr1_dp_memory.sv @@ -0,0 +1,111 @@ +/// Copyright by Syntacore LLC © 2016-2020. See LICENSE for details +/// @file +/// @brief Dual-port synchronous memory with byte enable inputs +/// + +`include "scr1_arch_description.svh" + +`ifdef SCR1_TCM_EN +module scr1_dp_memory +#( + parameter SCR1_WIDTH = 32, + parameter SCR1_SIZE = `SCR1_IMEM_AWIDTH'h00010000, + parameter SCR1_NBYTES = SCR1_WIDTH / 8 +) +( + input logic clk, + // Port A + input logic rena, + input logic [$clog2(SCR1_SIZE)-1:2] addra, + output logic [SCR1_WIDTH-1:0] qa, + // Port B + input logic renb, + input logic wenb, + input logic [SCR1_NBYTES-1:0] webb, + input logic [$clog2(SCR1_SIZE)-1:2] addrb, + input logic [SCR1_WIDTH-1:0] datab, + output logic [SCR1_WIDTH-1:0] qb +); + +`ifdef SCR1_TRGT_FPGA_INTEL +//------------------------------------------------------------------------------- +// Local signal declaration +//------------------------------------------------------------------------------- + `ifdef SCR1_TRGT_FPGA_INTEL_MAX10 +(* ramstyle = "M9K" *) logic [SCR1_NBYTES-1:0][7:0] memory_array [0:(SCR1_SIZE/SCR1_NBYTES)-1]; + `elsif SCR1_TRGT_FPGA_INTEL_ARRIAV +(* ramstyle = "M10K" *) logic [SCR1_NBYTES-1:0][7:0] memory_array [0:(SCR1_SIZE/SCR1_NBYTES)-1]; + `endif +logic [3:0] wenbb; +//------------------------------------------------------------------------------- +// Port B memory behavioral description +//------------------------------------------------------------------------------- +assign wenbb = {4{wenb}} & webb; +always_ff @(posedge clk) begin + if (wenb) begin + if (wenbb[0]) begin + memory_array[addrb][0] <= datab[0+:8]; + end + if (wenbb[1]) begin + memory_array[addrb][1] <= datab[8+:8]; + end + if (wenbb[2]) begin + memory_array[addrb][2] <= datab[16+:8]; + end + if (wenbb[3]) begin + memory_array[addrb][3] <= datab[24+:8]; + end + end + qb <= memory_array[addrb]; +end +//------------------------------------------------------------------------------- +// Port A memory behavioral description +//------------------------------------------------------------------------------- +always_ff @(posedge clk) begin + qa <= memory_array[addra]; +end + +`else // SCR1_TRGT_FPGA_INTEL + +// CASE: OTHERS - SCR1_TRGT_FPGA_XILINX, SIMULATION, ASIC etc + +localparam int unsigned RAM_SIZE_WORDS = SCR1_SIZE/SCR1_NBYTES; + +//------------------------------------------------------------------------------- +// Local signal declaration +//------------------------------------------------------------------------------- + `ifdef SCR1_TRGT_FPGA_XILINX +(* ram_style = "block" *) logic [SCR1_WIDTH-1:0] ram_block [RAM_SIZE_WORDS-1:0]; + `else // ASIC or SIMULATION +logic [SCR1_WIDTH-1:0] ram_block [RAM_SIZE_WORDS-1:0]; + `endif +//------------------------------------------------------------------------------- +// Port A memory behavioral description +//------------------------------------------------------------------------------- +always_ff @(posedge clk) begin + if (rena) begin + qa <= ram_block[addra]; + end +end + +//------------------------------------------------------------------------------- +// Port B memory behavioral description +//------------------------------------------------------------------------------- +always_ff @(posedge clk) begin + if (wenb) begin + for (int i=0; i +/// @brief HART Debug Unit definitions file +/// + +`ifdef SCR1_DBG_EN +`ifndef SCR1_INCLUDE_HDU_DEFS +`define SCR1_INCLUDE_HDU_DEFS + +`include "scr1_arch_description.svh" +`include "scr1_csr.svh" + +`ifdef SCR1_MMU_EN + `define SCR1_HDU_FEATURE_MPRVEN +`endif // SCR1_MMU_EN + +//============================================================================== +// Parameters +//============================================================================== +//localparam int unsigned SCR1_HDU_DEBUGCSR_BASE_ADDR = 12'h7B0; +localparam int unsigned SCR1_HDU_DEBUGCSR_ADDR_SPAN = SCR1_CSR_ADDR_HDU_MSPAN; +localparam int unsigned SCR1_HDU_DEBUGCSR_ADDR_WIDTH = $clog2(SCR1_HDU_DEBUGCSR_ADDR_SPAN); +localparam bit [3:0] SCR1_HDU_DEBUGCSR_DCSR_XDEBUGVER = 4'h4; +localparam int unsigned SCR1_HDU_PBUF_ADDR_SPAN = 8; +localparam int unsigned SCR1_HDU_PBUF_ADDR_WIDTH = $clog2(SCR1_HDU_PBUF_ADDR_SPAN); +localparam int unsigned SCR1_HDU_DATA_REG_WIDTH = 32; +localparam int unsigned SCR1_HDU_CORE_INSTR_WIDTH = 32; + + +//============================================================================== +// Types +//============================================================================== + +// HART Debug States: +typedef enum logic [1:0] { + SCR1_HDU_DBGSTATE_RESET = 2'b00, + SCR1_HDU_DBGSTATE_RUN = 2'b01, + SCR1_HDU_DBGSTATE_DHALTED = 2'b10, + SCR1_HDU_DBGSTATE_DRUN = 2'b11 +`ifdef SCR1_XPROP_EN + , + SCR1_HDU_DBGSTATE_XXX = 'X +`endif // SCR1_XPROP_EN +} type_scr1_hdu_dbgstates_e; + +typedef enum logic [1:0] { + SCR1_HDU_PBUFSTATE_IDLE = 2'b00, + SCR1_HDU_PBUFSTATE_FETCH = 2'b01, + SCR1_HDU_PBUFSTATE_EXCINJECT = 2'b10, + SCR1_HDU_PBUFSTATE_WAIT4END = 2'b11 +`ifdef SCR1_XPROP_EN + , + SCR1_HDU_PBUFSTATE_XXX = 'X +`endif // SCR1_XPROP_EN +} type_scr1_hdu_pbufstates_e; + +typedef enum logic { + SCR1_HDU_HARTCMD_RESUME = 1'b0, + SCR1_HDU_HARTCMD_HALT = 1'b1 +`ifdef SCR1_XPROP_EN + , + SCR1_HDU_HARTCMD_XXX = 1'bX +`endif // SCR1_XPROP_EN +} type_scr1_hdu_hart_command_e; + +typedef enum logic { + SCR1_HDU_FETCH_SRC_NORMAL = 1'b0, + SCR1_HDU_FETCH_SRC_PBUF = 1'b1 +`ifdef SCR1_XPROP_EN + , + SCR1_HDU_FETCH_SRC_XXX = 1'bX +`endif // SCR1_XPROP_EN +} type_scr1_hdu_fetch_src_e; + +typedef struct packed { + //logic reset_n; + logic except; + logic ebreak; + type_scr1_hdu_dbgstates_e dbg_state; +} type_scr1_hdu_hartstatus_s; + +// Debug Mode Redirection control: +typedef struct packed { + logic sstep; // Single Step + logic ebreak; // Redirection after EBREAK execution +} type_scr1_hdu_redirect_s; + +typedef struct packed { + logic irq_dsbl; + type_scr1_hdu_fetch_src_e fetch_src; + logic pc_advmt_dsbl; + logic hwbrkpt_dsbl; + type_scr1_hdu_redirect_s redirect; +} type_scr1_hdu_runctrl_s; + +// HART Halt Status: +typedef enum logic [2:0] { + SCR1_HDU_HALTCAUSE_NONE = 3'b000, + SCR1_HDU_HALTCAUSE_EBREAK = 3'b001, + SCR1_HDU_HALTCAUSE_TMREQ = 3'b010, + SCR1_HDU_HALTCAUSE_DMREQ = 3'b011, + SCR1_HDU_HALTCAUSE_SSTEP = 3'b100, + SCR1_HDU_HALTCAUSE_RSTEXIT = 3'b101 +`ifdef SCR1_XPROP_EN + , + SCR1_HDU_HALTCAUSE_XXX = 'X +`endif // SCR1_XPROP_EN +} type_scr1_hdu_haltcause_e; + +typedef struct packed { + logic except; + type_scr1_hdu_haltcause_e cause; +} type_scr1_hdu_haltstatus_s; + + +// Debug CSR map +localparam SCR1_HDU_DBGCSR_OFFS_DCSR = SCR1_HDU_DEBUGCSR_ADDR_WIDTH'( 'd0 ); +localparam SCR1_HDU_DBGCSR_OFFS_DPC = SCR1_HDU_DEBUGCSR_ADDR_WIDTH'( 'd1 ); +localparam SCR1_HDU_DBGCSR_OFFS_DSCRATCH0 = SCR1_HDU_DEBUGCSR_ADDR_WIDTH'( 'd2 ); +localparam SCR1_HDU_DBGCSR_OFFS_DSCRATCH1 = SCR1_HDU_DEBUGCSR_ADDR_WIDTH'( 'd3 ); + +localparam bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_HDU_DBGCSR_ADDR_DCSR = SCR1_CSR_ADDR_HDU_MBASE + SCR1_HDU_DBGCSR_OFFS_DCSR; +localparam bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_HDU_DBGCSR_ADDR_DPC = SCR1_CSR_ADDR_HDU_MBASE + SCR1_HDU_DBGCSR_OFFS_DPC; +localparam bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_HDU_DBGCSR_ADDR_DSCRATCH0 = SCR1_CSR_ADDR_HDU_MBASE + SCR1_HDU_DBGCSR_OFFS_DSCRATCH0; +localparam bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_HDU_DBGCSR_ADDR_DSCRATCH1 = SCR1_CSR_ADDR_HDU_MBASE + SCR1_HDU_DBGCSR_OFFS_DSCRATCH1; + +// Debug CSRs :: DCSR +typedef enum int { + SCR1_HDU_DCSR_PRV_BIT_R = 0, + SCR1_HDU_DCSR_PRV_BIT_L = 1, + SCR1_HDU_DCSR_STEP_BIT = 2, + SCR1_HDU_DCSR_RSRV0_BIT_R = 3, + SCR1_HDU_DCSR_RSRV0_BIT_L = 5, + SCR1_HDU_DCSR_CAUSE_BIT_R = 6, + SCR1_HDU_DCSR_CAUSE_BIT_L = 8, + SCR1_HDU_DCSR_RSRV1_BIT_R = 9, + SCR1_HDU_DCSR_RSRV1_BIT_L = 10, + SCR1_HDU_DCSR_STEPIE_BIT = 11, + SCR1_HDU_DCSR_RSRV2_BIT_R = 12, + SCR1_HDU_DCSR_RSRV2_BIT_L = 14, + SCR1_HDU_DCSR_EBREAKM_BIT = 15, + SCR1_HDU_DCSR_RSRV3_BIT_R = 16, + SCR1_HDU_DCSR_RSRV3_BIT_L = 27, + SCR1_HDU_DCSR_XDEBUGVER_BIT_R = 28, + SCR1_HDU_DCSR_XDEBUGVER_BIT_L = 31 +} type_scr1_hdu_dcsr_bits_e; + +//localparam int unsigned SCR1_HDU_DEBUGCSR_DCSR_PRV_WIDTH = SCR1_HDU_DCSR_PRV_BIT_L-SCR1_HDU_DCSR_PRV_BIT_R+1; + +typedef struct packed { + logic [SCR1_HDU_DCSR_XDEBUGVER_BIT_L-SCR1_HDU_DCSR_XDEBUGVER_BIT_R:0] xdebugver; + logic [SCR1_HDU_DCSR_RSRV3_BIT_L-SCR1_HDU_DCSR_RSRV3_BIT_R:0] rsrv3; + logic ebreakm; + logic [SCR1_HDU_DCSR_RSRV2_BIT_L-SCR1_HDU_DCSR_RSRV2_BIT_R:0] rsrv2; + logic stepie; + logic [SCR1_HDU_DCSR_RSRV1_BIT_L-SCR1_HDU_DCSR_RSRV1_BIT_R:0] rsrv1; + logic [SCR1_HDU_DCSR_CAUSE_BIT_L-SCR1_HDU_DCSR_CAUSE_BIT_R:0] cause; + logic [SCR1_HDU_DCSR_RSRV0_BIT_L-SCR1_HDU_DCSR_RSRV0_BIT_R:0] rsrv0; + logic step; + logic [SCR1_HDU_DCSR_PRV_BIT_L-SCR1_HDU_DCSR_PRV_BIT_R:0] prv; +} type_scr1_hdu_dcsr_s; + + +`endif // SCR1_INCLUDE_HDU_DEFS +`endif // SCR1_DBG_EN diff --git a/src/rtl/scr1/scr1_imem_ahb.sv b/src/rtl/scr1/scr1_imem_ahb.sv new file mode 100644 index 0000000..e749f9d --- /dev/null +++ b/src/rtl/scr1/scr1_imem_ahb.sv @@ -0,0 +1,319 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Instruction memory AHB bridge +/// + +`include "scr1_ahb.svh" +`include "scr1_memif.svh" + +module scr1_imem_ahb ( + // Control Signals + input logic rst_n, + input logic clk, + + // Core Interface + output logic imem_req_ack, + input logic imem_req, + input logic [SCR1_AHB_WIDTH-1:0] imem_addr, + output logic [SCR1_AHB_WIDTH-1:0] imem_rdata, + output type_scr1_mem_resp_e imem_resp, + + // AHB Interface + output logic [3:0] hprot, + output logic [2:0] hburst, + output logic [2:0] hsize, + output logic [1:0] htrans, + output logic hmastlock, + output logic [SCR1_AHB_WIDTH-1:0] haddr, + input logic hready, + input logic [SCR1_AHB_WIDTH-1:0] hrdata, + input logic hresp + +); + +//------------------------------------------------------------------------------- +// Local parameters declaration +//------------------------------------------------------------------------------- +`ifndef SCR1_IMEM_AHB_OUT_BP +localparam SCR1_FIFO_WIDTH = 2; +localparam SCR1_FIFO_CNT_WIDTH = $clog2(SCR1_FIFO_WIDTH+1); +`endif // SCR1_IMEM_AHB_OUT_BP + +//------------------------------------------------------------------------------- +// Local types declaration +//------------------------------------------------------------------------------- +typedef enum logic { + SCR1_FSM_ADDR = 1'b0, + SCR1_FSM_DATA = 1'b1, + SCR1_FSM_ERR = 1'bx +} type_scr1_fsm_e; + +typedef struct packed { + logic [SCR1_AHB_WIDTH-1:0] haddr; +} type_scr1_req_fifo_s; + +typedef struct packed { + logic hresp; + logic [SCR1_AHB_WIDTH-1:0] hrdata; +} type_scr1_resp_fifo_s; + +//------------------------------------------------------------------------------- +// Local signal declaration +//------------------------------------------------------------------------------- +type_scr1_fsm_e fsm; +logic req_fifo_rd; +logic req_fifo_wr; +logic req_fifo_up; +`ifdef SCR1_IMEM_AHB_OUT_BP +type_scr1_req_fifo_s req_fifo_r; +type_scr1_req_fifo_s [0:0] req_fifo; +`else // SCR1_IMEM_AHB_OUT_BP +type_scr1_req_fifo_s [0:SCR1_FIFO_WIDTH-1] req_fifo; +type_scr1_req_fifo_s [0:SCR1_FIFO_WIDTH-1] req_fifo_new; +logic [SCR1_FIFO_CNT_WIDTH-1:0] req_fifo_cnt; +logic [SCR1_FIFO_CNT_WIDTH-1:0] req_fifo_cnt_new; +`endif // SCR1_IMEM_AHB_OUT_BP +logic req_fifo_empty; +logic req_fifo_full; + +type_scr1_resp_fifo_s resp_fifo; +logic resp_fifo_hready; + +//------------------------------------------------------------------------------- +// Interface to Core +//------------------------------------------------------------------------------- +assign imem_req_ack = ~req_fifo_full; +assign req_fifo_wr = ~req_fifo_full & imem_req; + +assign imem_rdata = resp_fifo.hrdata; + +assign imem_resp = (resp_fifo_hready) + ? (resp_fifo.hresp == SCR1_HRESP_OKAY) + ? SCR1_MEM_RESP_RDY_OK + : SCR1_MEM_RESP_RDY_ER + : SCR1_MEM_RESP_NOTRDY; + +//------------------------------------------------------------------------------- +// REQ_FIFO +//------------------------------------------------------------------------------- +`ifdef SCR1_IMEM_AHB_OUT_BP +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + req_fifo_full <= 1'b0; + end else begin + if (~req_fifo_full) begin + req_fifo_full <= imem_req & ~req_fifo_rd; + end else begin + req_fifo_full <= ~req_fifo_rd; + end + end +end +assign req_fifo_empty = ~(req_fifo_full | imem_req); + +assign req_fifo_up = ~req_fifo_rd & req_fifo_wr; +always_ff @(posedge clk) begin + if (req_fifo_up) begin + req_fifo_r.haddr <= imem_addr; + end +end + +assign req_fifo[0] = (req_fifo_full) ? req_fifo_r : imem_addr; + +`else // SCR1_IMEM_AHB_OUT_BP +always_comb begin + req_fifo_up = 1'b0; + req_fifo_cnt_new = req_fifo_cnt; + req_fifo_new = req_fifo; + case ({req_fifo_rd, req_fifo_wr}) + 2'b00 : begin + // nothing todo + end + 2'b01: begin + // FIFO write + req_fifo_up = 1'b1; + req_fifo_new[req_fifo_cnt].haddr = imem_addr; + req_fifo_cnt_new = req_fifo_cnt + 1'b1; + end + 2'b10 : begin + // FIFO read + req_fifo_up = 1'b1; + req_fifo_new[0] = req_fifo_new[1]; + req_fifo_new[1].haddr = 'x; + req_fifo_cnt_new = req_fifo_cnt - 1'b1; + end + 2'b11 : begin + // Read and Write FIFO. It is possible only when fifo_cnt = 1 + req_fifo_up = 1'b1; + req_fifo_new[0].haddr = imem_addr; + end + default : begin + req_fifo_up = 'x; + req_fifo_cnt_new = 'x; + req_fifo_new = 'x; + end + endcase +end + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + req_fifo_cnt <= '0; + end else begin + if (req_fifo_up) begin + req_fifo_cnt <= req_fifo_cnt_new; + end + end +end +assign req_fifo_full = (req_fifo_cnt == SCR1_FIFO_WIDTH); +assign req_fifo_empty = ~(|req_fifo_cnt); + +always_ff @(posedge clk) begin + if (req_fifo_up) begin + req_fifo <= req_fifo_new; + end +end +`endif // SCR1_IMEM_AHB_OUT_BP + +//------------------------------------------------------------------------------- +// FSM +//------------------------------------------------------------------------------- +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + fsm <= SCR1_FSM_ADDR; + end else begin + case (fsm) + SCR1_FSM_ADDR : begin + if (hready) begin + fsm <= (req_fifo_empty) ? SCR1_FSM_ADDR : SCR1_FSM_DATA; + end + end + SCR1_FSM_DATA : begin + if (hready) begin + if (hresp == SCR1_HRESP_OKAY) begin + fsm <= (req_fifo_empty) ? SCR1_FSM_ADDR : SCR1_FSM_DATA; + end else begin + fsm <= SCR1_FSM_ADDR; + end + end + end + default : begin + fsm <= SCR1_FSM_ERR; + end + endcase + end +end + +always_comb begin + req_fifo_rd = 1'b0; + case (fsm) + SCR1_FSM_ADDR : begin + if (hready) begin + req_fifo_rd = ~req_fifo_empty; + end + end + SCR1_FSM_DATA : begin + if (hready) begin + req_fifo_rd = ~req_fifo_empty & (hresp == SCR1_HRESP_OKAY); + end + end + default : begin + req_fifo_rd = 1'bx; + end + endcase +end + +//------------------------------------------------------------------------------- +// FIFO response +//------------------------------------------------------------------------------- +`ifdef SCR1_IMEM_AHB_IN_BP +assign resp_fifo_hready = (fsm == SCR1_FSM_DATA) ? hready : 1'b0; +assign resp_fifo.hresp = hresp; +assign resp_fifo.hrdata = hrdata; +`else // SCR1_IMEM_AHB_IN_BP +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + resp_fifo_hready <= 1'b0; + end else begin + resp_fifo_hready <= (fsm == SCR1_FSM_DATA) ? hready : 1'b0; + end +end + +always_ff @(posedge clk) begin + if (hready & (fsm == SCR1_FSM_DATA)) begin + resp_fifo.hresp <= hresp; + resp_fifo.hrdata <= hrdata; + end +end +`endif // SCR1_IMEM_AHB_IN_BP + +//------------------------------------------------------------------------------- +// Interface to AHB +//------------------------------------------------------------------------------- +assign hprot[SCR1_HPROT_DATA] = 1'b0; +assign hprot[SCR1_HPROT_PRV] = 1'b0; +assign hprot[SCR1_HPROT_BUF] = 1'b0; +assign hprot[SCR1_HPROT_CACHE] = 1'b0; + +assign hburst = SCR1_HBURST_SINGLE; +assign hsize = SCR1_HSIZE_32B; +assign hmastlock = 1'b0; + +always_comb begin + htrans = SCR1_HTRANS_IDLE; + case (fsm) + SCR1_FSM_ADDR : begin + if (~req_fifo_empty) begin + htrans = SCR1_HTRANS_NONSEQ; + end + end + SCR1_FSM_DATA : begin + if (hready) begin + if (hresp == SCR1_HRESP_OKAY) begin + if (~req_fifo_empty) begin + htrans = SCR1_HTRANS_NONSEQ; + end + end + end + end + default : begin + htrans = SCR1_HTRANS_ERR; + end + endcase +end + +assign haddr = req_fifo[0].haddr; + +`ifdef SCR1_TRGT_SIMULATION +//------------------------------------------------------------------------------- +// Assertion +//------------------------------------------------------------------------------- + +// Check Core interface +SCR1_SVA_IMEM_AHB_BRIDGE_REQ_XCHECK : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown(imem_req) + ) else $error("IMEM AHB bridge Error: imem_req has unknown values"); + +SCR1_IMEM_AHB_BRIDGE_ADDR_XCHECK : assert property ( + @(negedge clk) disable iff (~rst_n) + imem_req |-> !$isunknown(imem_addr) + ) else $error("IMEM AHB bridge Error: imem_addr has unknown values"); + +SCR1_IMEM_AHB_BRIDGE_ADDR_ALLIGN : assert property ( + @(negedge clk) disable iff (~rst_n) + imem_req |-> (imem_addr[1:0] == '0) + ) else $error("IMEM AHB bridge Error: imem_addr has unalign values"); + +// Check AHB interface +SCR1_IMEM_AHB_BRIDGE_HREADY_XCHECK : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown(hready) + ) else $error("IMEM AHB bridge Error: hready has unknown values"); + +SCR1_IMEM_AHB_BRIDGE_HRESP_XCHECK : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown(hresp) + ) else $error("IMEM AHB bridge Error: hresp has unknown values"); + +`endif // SCR1_TRGT_SIMULATION + +endmodule : scr1_imem_ahb diff --git a/src/rtl/scr1/scr1_imem_router.sv b/src/rtl/scr1/scr1_imem_router.sv new file mode 100644 index 0000000..dd76f25 --- /dev/null +++ b/src/rtl/scr1/scr1_imem_router.sv @@ -0,0 +1,185 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Instruction memory router +/// +`include "scr1_memif.svh" +`include "scr1_arch_description.svh" + +module scr1_imem_router +#( + parameter SCR1_ADDR_MASK = `SCR1_IMEM_AWIDTH'hFFFF0000, + parameter SCR1_ADDR_PATTERN = `SCR1_IMEM_AWIDTH'h00010000 +) +( + // Control signals + input logic rst_n, + input logic clk, + + // Core interface + output logic imem_req_ack, + input logic imem_req, + input type_scr1_mem_cmd_e imem_cmd, + input logic [`SCR1_IMEM_AWIDTH-1:0] imem_addr, + output logic [`SCR1_IMEM_DWIDTH-1:0] imem_rdata, + output type_scr1_mem_resp_e imem_resp, + + // PORT0 interface + input logic port0_req_ack, + output logic port0_req, + output type_scr1_mem_cmd_e port0_cmd, + output logic [`SCR1_IMEM_AWIDTH-1:0] port0_addr, + input logic [`SCR1_IMEM_DWIDTH-1:0] port0_rdata, + input type_scr1_mem_resp_e port0_resp, + + // PORT1 interface + input logic port1_req_ack, + output logic port1_req, + output type_scr1_mem_cmd_e port1_cmd, + output logic [`SCR1_IMEM_AWIDTH-1:0] port1_addr, + input logic [`SCR1_IMEM_DWIDTH-1:0] port1_rdata, + input type_scr1_mem_resp_e port1_resp +); + +//------------------------------------------------------------------------------- +// Local types declaration +//------------------------------------------------------------------------------- +typedef enum logic { + SCR1_FSM_ADDR, + SCR1_FSM_DATA +} type_scr1_fsm_e; + +//------------------------------------------------------------------------------- +// Local signal declaration +//------------------------------------------------------------------------------- +type_scr1_fsm_e fsm; +logic port_sel; +logic port_sel_r; +logic [`SCR1_IMEM_DWIDTH-1:0] sel_rdata; +type_scr1_mem_resp_e sel_resp; +logic sel_req_ack; + +//------------------------------------------------------------------------------- +// FSM +//------------------------------------------------------------------------------- +assign port_sel = ((imem_addr & SCR1_ADDR_MASK) == SCR1_ADDR_PATTERN); + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + fsm <= SCR1_FSM_ADDR; + port_sel_r <= 1'b0; + end else begin + case (fsm) + SCR1_FSM_ADDR : begin + if (imem_req & sel_req_ack) begin + fsm <= SCR1_FSM_DATA; + port_sel_r <= port_sel; + end + end + SCR1_FSM_DATA : begin + case (sel_resp) + SCR1_MEM_RESP_RDY_OK : begin + if (imem_req & sel_req_ack) begin + fsm <= SCR1_FSM_DATA; + port_sel_r <= port_sel; + end else begin + fsm <= SCR1_FSM_ADDR; + end + end + SCR1_MEM_RESP_RDY_ER : begin + fsm <= SCR1_FSM_ADDR; + end + default : begin + end + endcase + end + default : begin + end + endcase + end +end + +always_comb begin + if ((fsm == SCR1_FSM_ADDR) | ((fsm == SCR1_FSM_DATA) & (sel_resp == SCR1_MEM_RESP_RDY_OK))) begin + sel_req_ack = (port_sel) ? port1_req_ack : port0_req_ack; + end else begin + sel_req_ack = 1'b0; + end +end + +assign sel_rdata = (port_sel_r) ? port1_rdata : port0_rdata; +assign sel_resp = (port_sel_r) ? port1_resp : port0_resp; + +//------------------------------------------------------------------------------- +// Interface to core +//------------------------------------------------------------------------------- +assign imem_req_ack = sel_req_ack; +assign imem_rdata = sel_rdata; +assign imem_resp = sel_resp; + +//------------------------------------------------------------------------------- +// Interface to PORT0 +//------------------------------------------------------------------------------- +always_comb begin + port0_req = 1'b0; + case (fsm) + SCR1_FSM_ADDR : begin + port0_req = imem_req & ~port_sel; + end + SCR1_FSM_DATA : begin + if (sel_resp == SCR1_MEM_RESP_RDY_OK) begin + port0_req = imem_req & ~port_sel; + end + end + default : begin + end + endcase +end + +`ifdef SCR1_XPROP_EN +assign port0_cmd = (~port_sel) ? imem_cmd : SCR1_MEM_CMD_ERROR; +assign port0_addr = (~port_sel) ? imem_addr : 'x; +`else // SCR1_XPROP_EN +assign port0_cmd = imem_cmd ; +assign port0_addr = imem_addr; +`endif // SCR1_XPROP_EN + +//------------------------------------------------------------------------------- +// Interface to PORT1 +//------------------------------------------------------------------------------- +always_comb begin + port1_req = 1'b0; + case (fsm) + SCR1_FSM_ADDR : begin + port1_req = imem_req & port_sel; + end + SCR1_FSM_DATA : begin + if (sel_resp == SCR1_MEM_RESP_RDY_OK) begin + port1_req = imem_req & port_sel; + end + end + default : begin + end + endcase +end + +`ifdef SCR1_XPROP_EN +assign port1_cmd = (port_sel) ? imem_cmd : SCR1_MEM_CMD_ERROR; +assign port1_addr = (port_sel) ? imem_addr : 'x; +`else // SCR1_XPROP_EN +assign port1_cmd = imem_cmd ; +assign port1_addr = imem_addr; +`endif // SCR1_XPROP_EN + +`ifdef SCR1_TRGT_SIMULATION +//------------------------------------------------------------------------------- +// Assertion +//------------------------------------------------------------------------------- + +SCR1_SVA_IMEM_RT_XCHECK : assert property ( + @(negedge clk) disable iff (~rst_n) + imem_req |-> !$isunknown({port_sel, imem_cmd}) + ) else $error("IMEM router Error: unknown values"); + +`endif // SCR1_TRGT_SIMULATION + +endmodule : scr1_imem_router diff --git a/src/rtl/scr1/scr1_ipic.sv b/src/rtl/scr1/scr1_ipic.sv new file mode 100644 index 0000000..76d6c4b --- /dev/null +++ b/src/rtl/scr1/scr1_ipic.sv @@ -0,0 +1,605 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Integrated Programmable Interrupt Controller (IPIC) +/// + +//------------------------------------------------------------------------------ + // + // Functionality: + // - Synchronizes IRQ lines (optional) + // - Detects level and edge (with optional lines inversion) of IRQ lines + // - Setups interrupts handling (mode, inversion, enable) + // - Provides information about pending interrupts and interrupts currently in + // service + // - Generates interrupt request to CSR + // + // Structure: + // - IRQ lines handling (synchronization, level and edge detection) logic + // - IPIC registers: + // - CISV + // - CICSR + // - EOI + // - SOI + // - IDX + // - IPR + // - ISVR + // - IER + // - IMR + // - IINVR + // - ICSR + // - Priority interrupt generation logic + // +//------------------------------------------------------------------------------ + +`include "scr1_arch_description.svh" + +`ifdef SCR1_IPIC_EN + +`include "scr1_ipic.svh" + +module scr1_ipic +( + // Common + input logic rst_n, // IPIC reset + input logic clk, // IPIC clock + + // External Interrupt lines + input logic [SCR1_IRQ_LINES_NUM-1:0] soc2ipic_irq_lines_i, // External IRQ lines + + // CSR <-> IPIC interface + input logic csr2ipic_r_req_i, // IPIC read request + input logic csr2ipic_w_req_i, // IPIC write request + input logic [2:0] csr2ipic_addr_i, // IPIC address + input logic [`SCR1_XLEN-1:0] csr2ipic_wdata_i, // IPIC write data + output logic [`SCR1_XLEN-1:0] ipic2csr_rdata_o, // IPIC read data + output logic ipic2csr_irq_m_req_o // IRQ request from IPIC +); + +//------------------------------------------------------------------------------- +// Local types declaration +//------------------------------------------------------------------------------- +typedef struct { + logic vd; + logic idx; +} type_scr1_search_one_2_s; + +typedef struct { + logic vd; + logic [SCR1_IRQ_IDX_WIDTH-1:0] idx; +} type_scr1_search_one_16_s; + +typedef struct packed { + logic ip; + logic ie; + logic im; + logic inv; + logic isv; + logic [SCR1_IRQ_LINES_WIDTH-1:0] line; +} type_scr1_icsr_m_s; + +typedef struct packed { + logic ip; + logic ie; +} type_scr1_cicsr_s; + +//------------------------------------------------------------------------------- +// Local functions declaration +//------------------------------------------------------------------------------- + +function automatic type_scr1_search_one_2_s scr1_search_one_2( + input logic [1:0] din +); + type_scr1_search_one_2_s tmp; +begin + tmp.vd = |din; + tmp.idx = ~din[0]; + return tmp; +end +endfunction : scr1_search_one_2 + +function automatic type_scr1_search_one_16_s scr1_search_one_16( + input logic [15:0] din +); +begin + logic [7:0] stage1_vd; + logic [3:0] stage2_vd; + logic [1:0] stage3_vd; + + logic stage1_idx [7:0]; + logic [1:0] stage2_idx [3:0]; + logic [2:0] stage3_idx [1:0]; + type_scr1_search_one_16_s result; + + // Stage 1 + for (int unsigned i=0; i<8; ++i) begin + type_scr1_search_one_2_s tmp; + tmp = scr1_search_one_2(din[(i+1)*2-1-:2]); + stage1_vd[i] = tmp.vd; + stage1_idx[i] = tmp.idx; + end + + // Stage 2 + for (int unsigned i=0; i<4; ++i) begin + type_scr1_search_one_2_s tmp; + tmp = scr1_search_one_2(stage1_vd[(i+1)*2-1-:2]); + stage2_vd[i] = tmp.vd; + stage2_idx[i] = (~tmp.idx) ? {tmp.idx, stage1_idx[2*i]} : {tmp.idx, stage1_idx[2*i+1]}; + end + + // Stage 3 + for (int unsigned i=0; i<2; ++i) begin + type_scr1_search_one_2_s tmp; + tmp = scr1_search_one_2(stage2_vd[(i+1)*2-1-:2]); + stage3_vd[i] = tmp.vd; + stage3_idx[i] = (~tmp.idx) ? {tmp.idx, stage2_idx[2*i]} : {tmp.idx, stage2_idx[2*i+1]}; + end + + // Stage 4 + result.vd = |stage3_vd; + result.idx = (stage3_vd[0]) ? {1'b0, stage3_idx[0]} : {1'b1, stage3_idx[1]}; + + return result; +end +endfunction : scr1_search_one_16 + +//------------------------------------------------------------------------------ +// Local signals declaration +//------------------------------------------------------------------------------ + +// IRQ lines handling signals +//------------------------------------------------------------------------------ + +logic [SCR1_IRQ_VECT_NUM-1:0] irq_lines; // Internal IRQ lines +`ifdef SCR1_IPIC_SYNC_EN +logic [SCR1_IRQ_VECT_NUM-1:0] irq_lines_sync; +`endif // SCR1_IPIC_SYNC_EN +logic [SCR1_IRQ_VECT_NUM-1:0] irq_lines_dly; // Internal IRQ lines delayed for 1 cycle +logic [SCR1_IRQ_VECT_NUM-1:0] irq_edge_detected; // IRQ lines edge detected flags +logic [SCR1_IRQ_VECT_NUM-1:0] irq_lvl; // IRQ lines level + +// IPIC registers +//------------------------------------------------------------------------------ + +// CISV register +logic ipic_cisv_upd; // Current Interrupt Vecotr in Service register update +logic [SCR1_IRQ_VECT_WIDTH-1:0] ipic_cisv_ff; // Current Interrupt Vector in Service register +logic [SCR1_IRQ_VECT_WIDTH-1:0] ipic_cisv_next; // Current Interrupt Vector in Service register next value + +// CICS register (CICSR) +logic cicsr_wr_req; // Write request to Current Interrupt Control Status register +type_scr1_cicsr_s ipic_cicsr; // Current Interrupt Control Status register + +// EOI register +logic eoi_wr_req; // Write request to End of Interrupt register +logic ipic_eoi_req; // Request to end the interrupt that is currently in service + +// SOI register +logic soi_wr_req; // Write request to Start of Interrupt register +logic ipic_soi_req; // Request to start the interrupt + +// IDX register (IDXR) +logic idxr_wr_req; // Write request to Index register +logic [SCR1_IRQ_IDX_WIDTH-1:0] ipic_idxr_ff; // Index register + +// IP register (IPR) +logic ipic_ipr_upd; // Interrupt pending register update +logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_ff; // Interrupt pending register +logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_next; // Interrupt pending register next value +logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_clr_cond; // Interrupt pending clear condition +logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_clr_req; // Interrupt pending clear request +logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_clr; // Interrupt pending clear operation + +// ISV register (ISVR) +logic ipic_isvr_upd; // Interrupt Serviced register update +logic [SCR1_IRQ_VECT_NUM-1:0] ipic_isvr_ff; // Interrupt Serviced register +logic [SCR1_IRQ_VECT_NUM-1:0] ipic_isvr_next; // Interrupt Serviced register next value + +// IE register (IER) +logic ipic_ier_upd; // Interrupt enable register update +logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ier_ff; // Interrupt enable register +logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ier_next; // Interrupt enable register next value + +// IM register (IMR) +logic [SCR1_IRQ_VECT_NUM-1:0] ipic_imr_ff; // Interrupt mode register +logic [SCR1_IRQ_VECT_NUM-1:0] ipic_imr_next; // Interrupt mode register next value + +// IINV register (IINVR) +logic [SCR1_IRQ_VECT_NUM-1:0] ipic_iinvr_ff; // Interrupt Inversion register +logic [SCR1_IRQ_VECT_NUM-1:0] ipic_iinvr_next; // Interrupt Inversion register next value + +// ICS register (ICSR) +logic icsr_wr_req; // Write request to Interrupt Control Status register +type_scr1_icsr_m_s ipic_icsr; // Interrupt Control Status register + +// Priority interrupt generation signals +//------------------------------------------------------------------------------ + +// Serviced interrupt signals +logic irq_serv_vd; // There is an interrupt in service +logic [SCR1_IRQ_IDX_WIDTH-1:0] irq_serv_idx; // Index of an interrupt that is currently in service + +// Requested interrupt signals +logic irq_req_vd; // There is a requested interrupt +logic [SCR1_IRQ_IDX_WIDTH-1:0] irq_req_idx; // Index of a requested interrupt + +// Interrupt requested on "end of the previous interrupt" signals +logic irq_eoi_req_vd; // There is a requested interrupt when the previous one has ended +logic [SCR1_IRQ_IDX_WIDTH-1:0] irq_eoi_req_idx; // Index of an interrupt requested when the previous one has ended + +logic [SCR1_IRQ_VECT_NUM-1:0] irq_req_v; // Vector of interrupts that are pending and enabled + +logic irq_start_vd; // Request to start an interrupt is valid +logic irq_hi_prior_pnd; // There is a pending IRQ with a priority higher than of the interrupt that is currently in service + +type_scr1_search_one_16_s irr_priority; // Structure for vd and idx of the requested interrupt +type_scr1_search_one_16_s isvr_priority_eoi; // Structure for vd and idx of the interrupt requested when the previous interrupt has ended +logic [SCR1_IRQ_VECT_NUM-1:0] ipic_isvr_eoi; // Interrupt Serviced register when the previous interrupt has ended + +//------------------------------------------------------------------------------ +// IRQ lines handling +//------------------------------------------------------------------------------ + +`ifdef SCR1_IPIC_SYNC_EN +// IRQ lines synchronization +//------------------------------------------------------------------------------ + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + irq_lines_sync <= '0; + irq_lines <= '0; + end else begin + irq_lines_sync <= soc2ipic_irq_lines_i; + irq_lines <= irq_lines_sync; + end +end +`else // SCR1_IPIC_SYNC_EN +assign irq_lines = soc2ipic_irq_lines_i; +`endif // SCR1_IPIC_SYNC_EN + +// IRQ lines level detection +//------------------------------------------------------------------------------ + +assign irq_lvl = irq_lines ^ ipic_iinvr_next; + +// IRQ lines edge detection +//------------------------------------------------------------------------------ + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + irq_lines_dly <= '0; + end else begin + irq_lines_dly <= irq_lines; + end +end + +assign irq_edge_detected = (irq_lines_dly ^ irq_lines) & irq_lvl; + +//------------------------------------------------------------------------------ +// IPIC registers read/write interface +//------------------------------------------------------------------------------ + +// Read Logic +//------------------------------------------------------------------------------ + +// Read data multiplexer +always_comb begin + ipic2csr_rdata_o = '0; + + if (csr2ipic_r_req_i) begin + case (csr2ipic_addr_i) + SCR1_IPIC_CISV : begin + ipic2csr_rdata_o[SCR1_IRQ_VECT_WIDTH-1:0] = irq_serv_vd + ? ipic_cisv_ff + : SCR1_IRQ_VOID_VECT_NUM; + end + SCR1_IPIC_CICSR : begin + ipic2csr_rdata_o[SCR1_IPIC_ICSR_IP] = ipic_cicsr.ip; + ipic2csr_rdata_o[SCR1_IPIC_ICSR_IE] = ipic_cicsr.ie; + end + SCR1_IPIC_IPR : begin + ipic2csr_rdata_o = `SCR1_XLEN'(ipic_ipr_ff); + end + SCR1_IPIC_ISVR : begin + ipic2csr_rdata_o = `SCR1_XLEN'(ipic_isvr_ff); + end + SCR1_IPIC_EOI, + SCR1_IPIC_SOI : begin + ipic2csr_rdata_o = '0; + end + SCR1_IPIC_IDX : begin + ipic2csr_rdata_o = `SCR1_XLEN'(ipic_idxr_ff); + end + SCR1_IPIC_ICSR : begin + ipic2csr_rdata_o[SCR1_IPIC_ICSR_IP] = ipic_icsr.ip; + ipic2csr_rdata_o[SCR1_IPIC_ICSR_IE] = ipic_icsr.ie; + ipic2csr_rdata_o[SCR1_IPIC_ICSR_IM] = ipic_icsr.im; + ipic2csr_rdata_o[SCR1_IPIC_ICSR_INV] = ipic_icsr.inv; + ipic2csr_rdata_o[SCR1_IPIC_ICSR_PRV_MSB: + SCR1_IPIC_ICSR_PRV_LSB] = SCR1_IPIC_PRV_M; + ipic2csr_rdata_o[SCR1_IPIC_ICSR_IS] = ipic_icsr.isv; + ipic2csr_rdata_o[SCR1_IPIC_ICSR_LN_MSB-1: + SCR1_IPIC_ICSR_LN_LSB] = ipic_icsr.line; + end + default : begin + ipic2csr_rdata_o = 'x; + end + endcase + end +end + +// Write logic +//------------------------------------------------------------------------------ + +// Register selection +always_comb begin + cicsr_wr_req = 1'b0; + eoi_wr_req = 1'b0; + soi_wr_req = 1'b0; + idxr_wr_req = 1'b0; + icsr_wr_req = 1'b0; + if (csr2ipic_w_req_i) begin + case (csr2ipic_addr_i) + SCR1_IPIC_CISV : begin end // Quiet Read-Only + SCR1_IPIC_CICSR: cicsr_wr_req = 1'b1; + SCR1_IPIC_IPR : begin end + SCR1_IPIC_ISVR : begin end // Quiet Read-Only + SCR1_IPIC_EOI : eoi_wr_req = 1'b1; + SCR1_IPIC_SOI : soi_wr_req = 1'b1; + SCR1_IPIC_IDX : idxr_wr_req = 1'b1; + SCR1_IPIC_ICSR : icsr_wr_req = 1'b1; + default : begin // Illegal IPIC register address + cicsr_wr_req = 'x; + eoi_wr_req = 'x; + soi_wr_req = 'x; + idxr_wr_req = 'x; + icsr_wr_req = 'x; + end + endcase + end +end + +//------------------------------------------------------------------------------ +// IPIC registers +//------------------------------------------------------------------------------ +// + // Registers: + // - Current Interrupt Vector in Service (CISV) register + // - Current Interrupt Control Status (CICSR) register + // - End of Interrupt (EOI) register + // - Start of Interrupt (SOI) register + // - Index (IDX) register + // - Interrupt Pending Register (IPR) + // - Interrupt Serviced Register (ISVR) + // - Interrupt Enable Register (IER) + // - Interrupt Mode Register (IMR) + // - Interrupt Inversion Register (IINVR) + // - Interrupt Control Status Register (ICSR) +// + +// CISV register +//------------------------------------------------------------------------------ +// Contains number of the interrupt vector currently in service. When no +// interrupts are in service, contains number of the void interrupt vector (0x10). +// The register cannot contain all 0's + +assign ipic_cisv_upd = irq_start_vd | ipic_eoi_req; + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + ipic_cisv_ff <= SCR1_IRQ_VOID_VECT_NUM; + end else if (ipic_cisv_upd) begin + ipic_cisv_ff <= ipic_cisv_next; + end +end + +assign ipic_cisv_next = irq_start_vd ? {1'b0, irq_req_idx} + : ipic_eoi_req ? irq_eoi_req_vd ? {1'b0, irq_eoi_req_idx} + : SCR1_IRQ_VOID_VECT_NUM + : 1'b0; + +assign irq_serv_idx = ipic_cisv_ff[SCR1_IRQ_VECT_WIDTH-2:0]; +assign irq_serv_vd = ~ipic_cisv_ff[SCR1_IRQ_VECT_WIDTH-1]; + +// CICSR register +//------------------------------------------------------------------------------ +// Shows whether the interrupt currently in service is pending and enabled + +assign ipic_cicsr.ip = ipic_ipr_ff[irq_serv_idx] & irq_serv_vd; +assign ipic_cicsr.ie = ipic_ier_ff[irq_serv_idx] & irq_serv_vd; + +// EOI register +//------------------------------------------------------------------------------ +// Writing any value to EOI register ends the interrupt which is currently in service + +assign ipic_eoi_req = eoi_wr_req & irq_serv_vd; + +// SOI register +//------------------------------------------------------------------------------ +// Writing any value to SOI activates start of interrupt if one of the following +// conditions is true: +// - There is at least one pending interrupt with IE and ISR is zero +// - There is at least one pending interrupt with IE and higher priority than the +// interrupts currently in service + +assign ipic_soi_req = soi_wr_req & irq_req_vd; + +// IDX register +//------------------------------------------------------------------------------ +// Defines the number of interrupt vector which is accessed through the IPIC_ICSR +// register + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + ipic_idxr_ff <= '0; + end else if (idxr_wr_req) begin + ipic_idxr_ff <= csr2ipic_wdata_i[SCR1_IRQ_IDX_WIDTH-1:0]; + end +end + +// IPR +//------------------------------------------------------------------------------ +// For every IRQ line shows whether there is a pending interrupt + +assign ipic_ipr_upd = (ipic_ipr_next != ipic_ipr_ff); + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + ipic_ipr_ff <= '0; + end else if (ipic_ipr_upd) begin + ipic_ipr_ff <= ipic_ipr_next; + end +end + +always_comb begin + ipic_ipr_clr_req = '0; + if (csr2ipic_w_req_i) begin + case (csr2ipic_addr_i) + SCR1_IPIC_CICSR: ipic_ipr_clr_req[irq_serv_idx] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_IP] + & irq_serv_vd; + SCR1_IPIC_IPR : ipic_ipr_clr_req = csr2ipic_wdata_i[SCR1_IRQ_VECT_NUM-1:0]; + SCR1_IPIC_SOI : ipic_ipr_clr_req[irq_req_idx] = irq_req_vd; + SCR1_IPIC_ICSR : ipic_ipr_clr_req[ipic_idxr_ff] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_IP]; + default : begin end + endcase + end +end + +assign ipic_ipr_clr_cond = ~irq_lvl | ipic_imr_next; +assign ipic_ipr_clr = ipic_ipr_clr_req & ipic_ipr_clr_cond; + +always_comb begin + ipic_ipr_next = '0; + for (int unsigned i=0; i +/// @brief IPIC header file +/// + +`ifndef SCR1_IPIC_SVH +`define SCR1_IPIC_SVH + +`include "scr1_arch_description.svh" + +`ifdef SCR1_IPIC_EN +//------------------------------------------------------------------------------- +// Parameters declaration +//------------------------------------------------------------------------------- +parameter SCR1_IRQ_VECT_NUM = 16; // must be power of 2 in the current implementation +parameter SCR1_IRQ_VECT_WIDTH = $clog2(SCR1_IRQ_VECT_NUM+1); +parameter SCR1_IRQ_LINES_NUM = SCR1_IRQ_VECT_NUM; +parameter SCR1_IRQ_LINES_WIDTH = $clog2(SCR1_IRQ_LINES_NUM); +parameter logic [SCR1_IRQ_VECT_WIDTH-1:0] SCR1_IRQ_VOID_VECT_NUM = SCR1_IRQ_VECT_WIDTH'(SCR1_IRQ_VECT_NUM); +parameter SCR1_IRQ_IDX_WIDTH = $clog2(SCR1_IRQ_VECT_NUM); + +// Address decoding parameters +parameter logic [2:0] SCR1_IPIC_CISV = 3'h0; // RO +parameter logic [2:0] SCR1_IPIC_CICSR = 3'h1; // {IP, IE} +parameter logic [2:0] SCR1_IPIC_IPR = 3'h2; // RW1C +parameter logic [2:0] SCR1_IPIC_ISVR = 3'h3; // RO +parameter logic [2:0] SCR1_IPIC_EOI = 3'h4; // RZW +parameter logic [2:0] SCR1_IPIC_SOI = 3'h5; // RZW +parameter logic [2:0] SCR1_IPIC_IDX = 3'h6; // RW +parameter logic [2:0] SCR1_IPIC_ICSR = 3'h7; // RW + +parameter SCR1_IPIC_ICSR_IP = 0; +parameter SCR1_IPIC_ICSR_IE = 1; +parameter SCR1_IPIC_ICSR_IM = 2; +parameter SCR1_IPIC_ICSR_INV = 3; +parameter SCR1_IPIC_ICSR_IS = 4; +parameter SCR1_IPIC_ICSR_PRV_LSB = 8; +parameter SCR1_IPIC_ICSR_PRV_MSB = 9; +parameter SCR1_IPIC_ICSR_LN_LSB = 12; +parameter SCR1_IPIC_ICSR_LN_MSB = SCR1_IPIC_ICSR_LN_LSB + + SCR1_IRQ_LINES_WIDTH; + +parameter logic [1:0] SCR1_IPIC_PRV_M = 2'b11; + +//------------------------------------------------------------------------------- +// Types declaration +//------------------------------------------------------------------------------- +typedef enum logic { + SCR1_CSR2IPIC_RD, + SCR1_CSR2IPIC_WR +`ifdef SCR1_XPROP_EN + , + SCR1_CSR2IPIC_ERROR = 'x +`endif // SCR1_XPROP_EN +} type_scr1_csr2ipic_wr_e; + +`endif // SCR1_IPIC_EN +`endif // SCR1_IPIC_SVH diff --git a/src/rtl/scr1/scr1_mem_axi.sv b/src/rtl/scr1/scr1_mem_axi.sv new file mode 100644 index 0000000..406494d --- /dev/null +++ b/src/rtl/scr1/scr1_mem_axi.sv @@ -0,0 +1,363 @@ +/// Copyright by Syntacore LLC © 2016-2020. See LICENSE for details +/// @file +/// @brief Memory AXI bridge +/// + +`include "scr1_memif.svh" +`include "scr1_arch_description.svh" + +module scr1_mem_axi +#( + parameter SCR1_REQ_BUF_SIZE = 2, // Power of 2 value + parameter SCR1_AXI_IDWIDTH = 4, + parameter SCR1_ADDR_WIDTH = 32, + parameter SCR1_AXI_REQ_BP = 1, + parameter SCR1_AXI_RESP_BP = 1 +) +( + // Clock and Reset + input logic clk, + input logic rst_n, + input logic axi_reinit, + // Core Interface + output logic core_idle, + output logic core_req_ack, + input logic core_req, + input type_scr1_mem_cmd_e core_cmd, + input type_scr1_mem_width_e core_width, + input logic [SCR1_ADDR_WIDTH-1:0] core_addr, + input logic [31:0] core_wdata, + output logic [31:0] core_rdata, + output type_scr1_mem_resp_e core_resp, + + // AXI + output logic [SCR1_AXI_IDWIDTH-1:0] awid, + output logic [SCR1_ADDR_WIDTH-1:0] awaddr, + output logic [ 7:0] awlen, + output logic [ 2:0] awsize, + output logic [ 1:0] awburst, + output logic awlock, + output logic [ 3:0] awcache, + output logic [ 2:0] awprot, + output logic [ 3:0] awregion, + output logic [ 3:0] awuser, + output logic [ 3:0] awqos, + output logic awvalid, + input logic awready, + output logic [31:0] wdata, + output logic [3:0] wstrb, + output logic wlast, + output logic [3:0] wuser, + output logic wvalid, + input logic wready, + input logic [SCR1_AXI_IDWIDTH-1:0] bid, + input logic [ 1:0] bresp, + input logic bvalid, + input logic [ 3:0] buser, + output logic bready, + output logic [SCR1_AXI_IDWIDTH-1:0] arid, + output logic [SCR1_ADDR_WIDTH-1:0] araddr, + output logic [ 7:0] arlen, + output logic [ 2:0] arsize, + output logic [ 1:0] arburst, + output logic arlock, + output logic [ 3:0] arcache, + output logic [ 2:0] arprot, + output logic [ 3:0] arregion, + output logic [ 3:0] aruser, + output logic [ 3:0] arqos, + output logic arvalid, + input logic arready, + input logic [SCR1_AXI_IDWIDTH-1:0] rid, + input logic [31:0] rdata, + input logic [ 1:0] rresp, + input logic rlast, + input logic [ 3:0] ruser, + input logic rvalid, + output logic rready +); + + +// Local functions +function automatic logic [2:0] width2axsize ( + input type_scr1_mem_width_e width ); + logic [2:0] axsize; +begin + case (width) + SCR1_MEM_WIDTH_BYTE : axsize = 3'b000; + SCR1_MEM_WIDTH_HWORD: axsize = 3'b001; + SCR1_MEM_WIDTH_WORD : axsize = 3'b010; + default: axsize = 'x; + endcase + + return axsize; +end +endfunction: width2axsize + +typedef struct packed { + type_scr1_mem_width_e axi_width; + logic [SCR1_ADDR_WIDTH-1:0] axi_addr; + logic [31:0] axi_wdata; +} type_scr1_request_s; + +typedef struct packed { + logic req_write; + logic req_addr; + logic req_data; + logic req_resp; +} type_scr1_req_status_s; + + +type_scr1_request_s [SCR1_REQ_BUF_SIZE-1:0] req_fifo; +type_scr1_req_status_s [SCR1_REQ_BUF_SIZE-1:0] req_status; +type_scr1_req_status_s [SCR1_REQ_BUF_SIZE-1:0] req_status_new; +logic [SCR1_REQ_BUF_SIZE-1:0] req_status_en; +logic [$clog2(SCR1_REQ_BUF_SIZE)-1:0] req_aval_ptr; +logic [$clog2(SCR1_REQ_BUF_SIZE)-1:0] req_proc_ptr; +logic [$clog2(SCR1_REQ_BUF_SIZE)-1:0] req_done_ptr; +logic rresp_err; +logic [31:0] rcvd_rdata; +type_scr1_mem_resp_e rcvd_resp; +logic force_read; +logic force_write; + + + +assign core_req_ack = ~axi_reinit & + ~req_status[req_aval_ptr].req_resp & + core_resp!=SCR1_MEM_RESP_RDY_ER; + + +assign rready = ~req_status[req_done_ptr].req_write; +assign bready = req_status[req_done_ptr].req_write; + + +assign force_read = bit'(SCR1_AXI_REQ_BP) & core_req & core_req_ack & req_aval_ptr==req_proc_ptr & core_cmd==SCR1_MEM_CMD_RD; +assign force_write = bit'(SCR1_AXI_REQ_BP) & core_req & core_req_ack & req_aval_ptr==req_proc_ptr & core_cmd==SCR1_MEM_CMD_WR; + + +always_comb begin: idle_status + core_idle = 1'b1; + for (int unsigned i=0; i IPIC interface +//------------------------------------------------------------------------------ + +assign csr_ipic_req = csr2ipic_r_req_o | csr2ipic_w_req_o; +assign csr2ipic_addr_o = csr_ipic_req ? exu2csr_rw_addr_i[2:0] : '0; +assign csr2ipic_wdata_o = csr2ipic_w_req_o ? exu2csr_w_data_i : '0; +`endif // SCR1_IPIC_EN + +`ifdef SCR1_DBG_EN +//------------------------------------------------------------------------------ +// CSR <-> HDU interface +//------------------------------------------------------------------------------ + +assign csr2hdu_req_o = csr_hdu_req & exu_req_no_exc; +assign csr2hdu_cmd_o = exu2csr_w_cmd_i; +assign csr2hdu_addr_o = exu2csr_rw_addr_i[SCR1_HDU_DEBUGCSR_ADDR_WIDTH-1:0]; +assign csr2hdu_wdata_o = exu2csr_w_data_i; +`endif // SCR1_DBG_EN + +`ifdef SCR1_TDU_EN +//------------------------------------------------------------------------------ +// CSR <-> TDU interface +//------------------------------------------------------------------------------ + +assign csr2tdu_req_o = csr_brkm_req & exu_req_no_exc; +assign csr2tdu_cmd_o = exu2csr_w_cmd_i; +assign csr2tdu_addr_o = exu2csr_rw_addr_i[SCR1_CSR_ADDR_TDU_OFFS_W-1:0]; +assign csr2tdu_wdata_o = exu2csr_w_data_i; +`endif // SCR1_TDU_EN + +`ifdef SCR1_TRGT_SIMULATION +//------------------------------------------------------------------------------ +// Assertions +//------------------------------------------------------------------------------ + +// X checks + +SCR1_SVA_CSR_XCHECK_CTRL : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown({exu2csr_r_req_i, exu2csr_w_req_i, exu2csr_take_irq_i, exu2csr_take_exc_i, exu2csr_mret_update_i +`ifndef SCR1_CSR_REDUCED_CNT + , exu2csr_instret_no_exc_i +`endif // SCR1_CSR_REDUCED_CNT + }) + ) else $error("CSR Error: unknown control values"); + +SCR1_SVA_CSR_XCHECK_READ : assert property ( + @(negedge clk) disable iff (~rst_n) + exu2csr_r_req_i |-> !$isunknown({exu2csr_rw_addr_i, csr2exu_r_data_o, csr2exu_rw_exc_o}) + ) else $error("CSR Error: unknown control values"); + +SCR1_SVA_CSR_XCHECK_WRITE : assert property ( + @(negedge clk) disable iff (~rst_n) + exu2csr_w_req_i |-> !$isunknown({exu2csr_rw_addr_i, exu2csr_w_cmd_i, exu2csr_w_data_i, csr2exu_rw_exc_o}) + ) else $error("CSR Error: unknown control values"); + +`ifdef SCR1_IPIC_EN +SCR1_SVA_CSR_XCHECK_READ_IPIC : assert property ( + @(negedge clk) disable iff (~rst_n) + csr2ipic_r_req_o |-> !$isunknown({csr2ipic_addr_o, ipic2csr_rdata_i}) + ) else $error("CSR Error: unknown control values"); + +SCR1_SVA_CSR_XCHECK_WRITE_IPIC : assert property ( + @(negedge clk) disable iff (~rst_n) + csr2ipic_w_req_o |-> !$isunknown({csr2ipic_addr_o, csr2ipic_wdata_o}) + ) else $error("CSR Error: unknown control values"); +`endif // SCR1_IPIC_EN + +// Behavior checks + +SCR1_SVA_CSR_MRET : assert property ( + @(negedge clk) disable iff (~rst_n) + e_mret |=> ($stable(csr_mepc_ff) & $stable(csr_mtval_ff)) + ) else $error("CSR Error: MRET wrong behavior"); + +SCR1_SVA_CSR_MRET_IRQ : assert property ( + @(negedge clk) disable iff (~rst_n) + (exu2csr_mret_instr_i & e_irq) + |=> ($stable(csr_mepc_ff) & (exu2csr_pc_curr_i != csr_mepc)) + ) else $error("CSR Error: MRET+IRQ wrong behavior"); + +SCR1_SVA_CSR_EXC_IRQ : assert property ( + @(negedge clk) disable iff (~rst_n) + (exu2csr_take_exc_i & exu2csr_take_irq_i +`ifdef SCR1_DBG_EN + & ~hdu2csr_no_commit_i +`endif + ) |=> + (~csr_mstatus_mie_ff & (~csr_mcause_i_ff) + & (exu2csr_pc_curr_i=={csr_mtvec_base, SCR1_CSR_MTVEC_BASE_ZERO_BITS'(0)})) + ) else $error("CSR Error: wrong EXC+IRQ"); + +SCR1_SVA_CSR_EVENTS : assert property ( + @(negedge clk) disable iff (~rst_n) + $onehot0({e_irq, e_exc, e_mret}) + ) else $error("CSR Error: more than one event at a time"); + +SCR1_SVA_CSR_RW_EXC : assert property ( + @(negedge clk) disable iff (~rst_n) + csr2exu_rw_exc_o |-> (exu2csr_w_req_i | exu2csr_r_req_i) + ) else $error("CSR Error: impossible exception"); + +SCR1_SVA_CSR_MSTATUS_MIE_UP : assert property ( + @(negedge clk) disable iff (~rst_n) + csr2exu_mstatus_mie_up_o |=> ~csr2exu_mstatus_mie_up_o + ) else $error("CSR Error: csr2exu_mstatus_mie_up_o can only be high for one mcycle"); + + +`ifndef SCR1_CSR_REDUCED_CNT + +SCR1_SVA_CSR_CYCLE_INC : assert property ( + @( +`ifndef SCR1_CLKCTRL_EN +negedge clk +`else // SCR1_CLKCTRL_EN +negedge clk_alw_on +`endif // SCR1_CLKCTRL_EN + ) disable iff (~rst_n) + (~|csr_mcycle_upd) |=> +`ifdef SCR1_MCOUNTEN_EN + ($past(csr_mcounten_cy_ff) ? (csr_mcycle == $past(csr_mcycle + 1'b1)) : $stable(csr_mcycle)) +`else //SCR1_MCOUNTEN_EN + (csr_mcycle == $past(csr_mcycle + 1'b1)) +`endif // SCR1_MCOUNTEN_EN + ) else $error("CSR Error: CYCLE increment wrong behavior"); + +SCR1_SVA_CSR_INSTRET_INC : assert property ( + @(negedge clk) disable iff (~rst_n) + (exu2csr_instret_no_exc_i & ~|csr_minstret_upd) |=> +`ifdef SCR1_MCOUNTEN_EN + ($past(csr_mcounten_ir_ff) ? (csr_minstret == $past(csr_minstret + 1'b1)) : $stable(csr_minstret)) +`else //SCR1_MCOUNTEN_EN + (csr_minstret == $past(csr_minstret + 1'b1)) +`endif // SCR1_MCOUNTEN_EN + ) else $error("CSR Error: INSTRET increment wrong behavior"); + +SCR1_SVA_CSR_CYCLE_INSTRET_UP : assert property ( + @(negedge clk) disable iff (~rst_n) + ~(&csr_minstret_upd | &csr_mcycle_upd) + ) else $error("CSR Error: INSTRET/CYCLE up illegal value"); + +`endif // SCR1_CSR_REDUCED_CNT + +`endif // SCR1_TRGT_SIMULATION + +endmodule : scr1_pipe_csr diff --git a/src/rtl/scr1/scr1_pipe_exu.sv b/src/rtl/scr1/scr1_pipe_exu.sv new file mode 100644 index 0000000..f496979 --- /dev/null +++ b/src/rtl/scr1/scr1_pipe_exu.sv @@ -0,0 +1,1086 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Execution Unit (EXU) +/// + +//------------------------------------------------------------------------------ + // + // Functionality: + // - Performs instructions execution: + // - Prevents instructions from execution if the HART is in WFI or Debug Halted + // state + // - Fetches operands for IALU + // - Calculates operation results via IALU + // - Stores IALU results in MPRF + // - Performs LOAD/STORE operations via LSU + // - Handles exceptions: + // - Generates exception request + // - Encodes exception code + // - Calculates exception trap value + // - Controls WFI instruction execution + // - Calculates PC value: + // - Initializes PC on reset + // - Stores the current PC value + // - Calculates a New PC value and generates a New PC request to IFU + // + // Structure: + // - Instruction queue + // - Integer Arithmetic Logic Unit (IALU) + // - Exceptions logic + // - WFI logic + // - Program Counter logic + // - Load-Store Unit (LSU) + // - EXU status logic + // - EXU <-> MPRF i/f + // - EXU <-> CSR i/f + // - EXU <-> TDU i/f + // +//------------------------------------------------------------------------------ + +`include "scr1_arch_description.svh" +`include "scr1_arch_types.svh" +`include "scr1_memif.svh" +`include "scr1_riscv_isa_decoding.svh" +`include "scr1_csr.svh" + +`ifdef SCR1_DBG_EN + `include "scr1_hdu.svh" +`endif // SCR1_DBG_EN + +`ifdef SCR1_TDU_EN + `include "scr1_tdu.svh" +`endif // SCR1_TDU_EN + +module scr1_pipe_exu ( + // Common + input logic rst_n, // EXU reset + input logic clk, // Gated EXU clock +`ifdef SCR1_CLKCTRL_EN + input logic clk_alw_on, // Not-gated EXU clock + input logic clk_pipe_en, // EXU clock enabled flag +`endif // SCR1_CLKCTRL_EN + + // EXU <-> IDU interface + input logic idu2exu_req_i, // Request form IDU to EXU + output logic exu2idu_rdy_o, // EXU ready for new data from IDU + input type_scr1_exu_cmd_s idu2exu_cmd_i, // EXU command + input logic idu2exu_use_rs1_i, // Clock gating on rs1_addr field + input logic idu2exu_use_rs2_i, // Clock gating on rs2_addr field +`ifndef SCR1_NO_EXE_STAGE + input logic idu2exu_use_rd_i, // Clock gating on rd_addr field + input logic idu2exu_use_imm_i, // Clock gating on imm field +`endif // SCR1_NO_EXE_STAGE + + // EXU <-> MPRF interface + output logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rs1_addr_o, // MPRF rs1 read address + input logic [`SCR1_XLEN-1:0] mprf2exu_rs1_data_i, // MPRF rs1 read data + output logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rs2_addr_o, // MPRF rs2 read address + input logic [`SCR1_XLEN-1:0] mprf2exu_rs2_data_i, // MPRF rs2 read data + output logic exu2mprf_w_req_o, // MPRF write request + output logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rd_addr_o, // MPRF rd write address + output logic [`SCR1_XLEN-1:0] exu2mprf_rd_data_o, // MPRF rd write data + + // EXU <-> CSR read/write interface + output logic [SCR1_CSR_ADDR_WIDTH-1:0] exu2csr_rw_addr_o, // CSR read/write address + output logic exu2csr_r_req_o, // CSR read request + input logic [`SCR1_XLEN-1:0] csr2exu_r_data_i, // CSR read data + output logic exu2csr_w_req_o, // CSR write request + output type_scr1_csr_cmd_sel_e exu2csr_w_cmd_o, // CSR write command + output logic [`SCR1_XLEN-1:0] exu2csr_w_data_o, // CSR write data + input logic csr2exu_rw_exc_i, // CSR read/write access exception + + // EXU <-> CSR events interface + output logic exu2csr_take_irq_o, // Take IRQ trap + output logic exu2csr_take_exc_o, // Take exception trap + output logic exu2csr_mret_update_o, // MRET update CSR + output logic exu2csr_mret_instr_o, // MRET instruction + output type_scr1_exc_code_e exu2csr_exc_code_o, // Exception code (see scr1_arch_types.svh) + output logic [`SCR1_XLEN-1:0] exu2csr_trap_val_o, // Trap value + input logic [`SCR1_XLEN-1:0] csr2exu_new_pc_i, // Exception/IRQ/MRET new PC + input logic csr2exu_irq_i, // IRQ request + input logic csr2exu_ip_ie_i, // Some IRQ pending and locally enabled + input logic csr2exu_mstatus_mie_up_i, // MSTATUS or MIE update in the current cycle + + // EXU <-> DMEM interface + output logic exu2dmem_req_o, // Data memory request + output type_scr1_mem_cmd_e exu2dmem_cmd_o, // Data memory command + output type_scr1_mem_width_e exu2dmem_width_o, // Data memory width + output logic [`SCR1_DMEM_AWIDTH-1:0] exu2dmem_addr_o, // Data memory address + output logic [`SCR1_DMEM_DWIDTH-1:0] exu2dmem_wdata_o, // Data memory write data + input logic dmem2exu_req_ack_i, // Data memory request acknowledge + input logic [`SCR1_DMEM_DWIDTH-1:0] dmem2exu_rdata_i, // Data memory read data + input type_scr1_mem_resp_e dmem2exu_resp_i, // Data memory response + + // EXU control + output logic exu2pipe_exc_req_o, // Exception on last instruction + output logic exu2pipe_brkpt_o, // Software Breakpoint (EBREAK) + output logic exu2pipe_init_pc_o, // Reset exit + output logic exu2pipe_wfi_run2halt_o, // Transition to WFI halted state + output logic exu2pipe_instret_o, // Instruction retired (with or without exception) +`ifndef SCR1_CSR_REDUCED_CNT + output logic exu2csr_instret_no_exc_o, // Instruction retired (without exception) +`endif // SCR1_CSR_REDUCED_CNT + output logic exu2pipe_exu_busy_o, // EXU busy + +`ifdef SCR1_DBG_EN + // EXU <-> HDU interface + input logic hdu2exu_no_commit_i, // Forbid instruction commitment + input logic hdu2exu_irq_dsbl_i, // Disable IRQ + input logic hdu2exu_pc_advmt_dsbl_i, // Forbid PC advancement + input logic hdu2exu_dmode_sstep_en_i, // Enable single-step + input logic hdu2exu_pbuf_fetch_i, // Take instructions from Program Buffer + input logic hdu2exu_dbg_halted_i, // Debug halted state + input logic hdu2exu_dbg_run2halt_i, // Transition to debug halted state + input logic hdu2exu_dbg_halt2run_i, // Transition to run state + input logic hdu2exu_dbg_run_start_i, // First cycle of run state + input logic [`SCR1_XLEN-1:0] hdu2exu_dbg_new_pc_i, // New PC as starting point for HART Resume +`endif // SCR1_DBG_EN + +`ifdef SCR1_TDU_EN + // EXU <-> TDU interface + output type_scr1_brkm_instr_mon_s exu2tdu_imon_o, // Instruction monitor + input logic [SCR1_TDU_ALLTRIG_NUM-1:0] tdu2exu_ibrkpt_match_i, // Instruction breakpoint(s) match + input logic tdu2exu_ibrkpt_exc_req_i, // Instruction breakpoint exception + output type_scr1_brkm_lsu_mon_s lsu2tdu_dmon_o, // Data monitor + input logic tdu2lsu_ibrkpt_exc_req_i, // Instruction breakpoint exception + input logic [SCR1_TDU_MTRIG_NUM-1:0] tdu2lsu_dbrkpt_match_i, // Data breakpoint(s) match + input logic tdu2lsu_dbrkpt_exc_req_i, // Data breakpoint exception + output logic [SCR1_TDU_ALLTRIG_NUM-1:0] exu2tdu_ibrkpt_ret_o, // Instruction with breakpoint flag retire + `ifdef SCR1_DBG_EN + output logic exu2hdu_ibrkpt_hw_o, // Hardware breakpoint on current instruction + `endif // SCR1_DBG_EN +`endif // SCR1_TDU_EN + + // PC interface +`ifdef SCR1_CLKCTRL_EN + output logic exu2pipe_wfi_halted_o, // WFI halted state +`endif // SCR1_CLKCTRL_EN + output logic [`SCR1_XLEN-1:0] exu2pipe_pc_curr_o, // Current PC + output logic [`SCR1_XLEN-1:0] exu2csr_pc_next_o, // Next PC + output logic exu2ifu_pc_new_req_o, // New PC request + output logic [`SCR1_XLEN-1:0] exu2ifu_pc_new_o // New PC data +); + +//------------------------------------------------------------------------------ +// Local parameters declaration +//------------------------------------------------------------------------------ + +localparam SCR1_JUMP_MASK = `SCR1_XLEN'hFFFF_FFFE; + +//------------------------------------------------------------------------------ +// Local types declaration +//------------------------------------------------------------------------------ + +typedef enum logic { + SCR1_CSR_INIT, + SCR1_CSR_RDY +} scr1_csr_access_e; + +//------------------------------------------------------------------------------ +// Local signals declaration +//------------------------------------------------------------------------------ + +// Instruction queue signals +//------------------------------------------------------------------------------ +logic exu_queue_vd; +type_scr1_exu_cmd_s exu_queue; +logic exu_queue_barrier; + +`ifdef SCR1_DBG_EN +logic dbg_run_start_npbuf; +`endif // SCR1_DBG_EN +logic exu_queue_en; +logic [`SCR1_XLEN-1:0] exu_illegal_instr; + +`ifndef SCR1_NO_EXE_STAGE +logic idu2exu_use_rs1_ff; +logic idu2exu_use_rs2_ff; + +// EXU queue valid flag register signals +logic exu_queue_vd_upd; +logic exu_queue_vd_ff; +logic exu_queue_vd_next; +`endif // SCR1_NO_EXE_STAGE + +// IALU signals +//------------------------------------------------------------------------------ +`ifdef SCR1_RVM_EXT +logic ialu_rdy; +logic ialu_vd; +`endif // SCR1_RVM_EXT +logic [`SCR1_XLEN-1:0] ialu_main_op1; +logic [`SCR1_XLEN-1:0] ialu_main_op2; +logic [`SCR1_XLEN-1:0] ialu_main_res; +logic [`SCR1_XLEN-1:0] ialu_addr_op1; +logic [`SCR1_XLEN-1:0] ialu_addr_op2; +logic [`SCR1_XLEN-1:0] ialu_addr_res; +logic ialu_cmp; + +// Exceptions signals +//------------------------------------------------------------------------------ +logic exu_exc_req; +`ifdef SCR1_DBG_EN +logic exu_exc_req_ff; +logic exu_exc_req_next; +`endif // SCR1_DBG_EN +type_scr1_exc_code_e exc_code; +logic [`SCR1_XLEN-1:0] exc_trap_val; +logic instr_fault_rvi_hi; + +// WFI signals +//------------------------------------------------------------------------------ +// WFI control signals +logic wfi_halt_cond; +logic wfi_run_req; +logic wfi_halt_req; + +// WFI Run Start register +logic wfi_run_start_ff; +logic wfi_run_start_next; + +// WFI halted register +logic wfi_halted_upd; +logic wfi_halted_ff; +logic wfi_halted_next; + +// PC signals +//------------------------------------------------------------------------------ +logic [3:0] init_pc_v; +logic init_pc; +logic [`SCR1_XLEN-1:0] inc_pc; + +logic branch_taken; +logic jb_taken; +logic [`SCR1_XLEN-1:0] jb_new_pc; +`ifndef SCR1_RVC_EXT +logic jb_misalign; +`endif + +// Current PC register +logic pc_curr_upd; +logic [`SCR1_XLEN-1:0] pc_curr_ff; +logic [`SCR1_XLEN-1:0] pc_curr_next; + +// LSU signals +//------------------------------------------------------------------------------ +logic lsu_req; +logic lsu_rdy; +logic [`SCR1_XLEN-1:0] lsu_l_data; +logic lsu_exc_req; +type_scr1_exc_code_e lsu_exc_code; + +// EXU status signals +//------------------------------------------------------------------------------ +logic exu_rdy; + +// MPRF signals +//------------------------------------------------------------------------------ +logic mprf_rs1_req; +logic mprf_rs2_req; + +logic [`SCR1_MPRF_AWIDTH-1:0] mprf_rs1_addr; +logic [`SCR1_MPRF_AWIDTH-1:0] mprf_rs2_addr; + +// CSR signals +//------------------------------------------------------------------------------ +// CSR access register +scr1_csr_access_e csr_access_ff; +scr1_csr_access_e csr_access_next; +logic csr_access_init; + +//------------------------------------------------------------------------------ +// Instruction execution queue +//------------------------------------------------------------------------------ +// + // Instruction execution queue consists of the following functional units: + // - EXU queue control logic + // - EXU queue valid flag register + // - EXU queue register + // - EXU queue status logic +// + +`ifdef SCR1_DBG_EN +assign dbg_run_start_npbuf = hdu2exu_dbg_run_start_i & ~hdu2exu_pbuf_fetch_i; +`endif // SCR1_DBG_EN + +`ifndef SCR1_NO_EXE_STAGE + +// EXU queue control logic +//------------------------------------------------------------------------------ + +assign exu_queue_barrier = wfi_halted_ff | wfi_halt_req | wfi_run_start_ff +`ifdef SCR1_DBG_EN + | hdu2exu_dbg_halted_i | hdu2exu_dbg_run2halt_i + | dbg_run_start_npbuf +`endif // SCR1_DBG_EN +; + +assign exu_queue_en = exu2idu_rdy_o & idu2exu_req_i; + +// EXU queue valid flag register +//------------------------------------------------------------------------------ + +assign exu_queue_vd_upd = exu_queue_barrier | exu_rdy; + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + exu_queue_vd_ff <= 1'b0; + end else if (exu_queue_vd_upd) begin + exu_queue_vd_ff <= exu_queue_vd_next; + end +end + +assign exu_queue_vd_next = ~exu_queue_barrier & idu2exu_req_i & ~exu2ifu_pc_new_req_o; +assign exu_queue_vd = exu_queue_vd_ff; + +// EXU queue register +//------------------------------------------------------------------------------ + +always_ff @(posedge clk) begin + if (exu_queue_en) begin + exu_queue.instr_rvc <= idu2exu_cmd_i.instr_rvc; + exu_queue.ialu_op <= idu2exu_cmd_i.ialu_op; + exu_queue.ialu_cmd <= idu2exu_cmd_i.ialu_cmd; + exu_queue.sum2_op <= idu2exu_cmd_i.sum2_op; + exu_queue.lsu_cmd <= idu2exu_cmd_i.lsu_cmd; + exu_queue.csr_op <= idu2exu_cmd_i.csr_op; + exu_queue.csr_cmd <= idu2exu_cmd_i.csr_cmd; + exu_queue.rd_wb_sel <= idu2exu_cmd_i.rd_wb_sel; + exu_queue.jump_req <= idu2exu_cmd_i.jump_req; + exu_queue.branch_req <= idu2exu_cmd_i.branch_req; + exu_queue.mret_req <= idu2exu_cmd_i.mret_req; + exu_queue.fencei_req <= idu2exu_cmd_i.fencei_req; + exu_queue.wfi_req <= idu2exu_cmd_i.wfi_req; + exu_queue.exc_req <= idu2exu_cmd_i.exc_req; + exu_queue.exc_code <= idu2exu_cmd_i.exc_code; + idu2exu_use_rs1_ff <= idu2exu_use_rs1_i; + idu2exu_use_rs2_ff <= idu2exu_use_rs2_i; + if (idu2exu_use_rs1_i) begin + exu_queue.rs1_addr <= idu2exu_cmd_i.rs1_addr; + end + if (idu2exu_use_rs2_i) begin + exu_queue.rs2_addr <= idu2exu_cmd_i.rs2_addr; + end + if (idu2exu_use_rd_i) begin + exu_queue.rd_addr <= idu2exu_cmd_i.rd_addr; + end + if (idu2exu_use_imm_i) begin + exu_queue.imm <= idu2exu_cmd_i.imm; + end + end +end + +`else // ~SCR1_NO_EXE_STAGE + +assign exu_queue_barrier = wfi_halted_ff | wfi_run_start_ff +`ifdef SCR1_DBG_EN + | hdu2exu_dbg_halted_i | dbg_run_start_npbuf +`endif // SCR1_DBG_EN +; +assign exu_queue_vd = idu2exu_req_i & ~exu_queue_barrier; +assign exu_queue = idu2exu_cmd_i; + +`endif // ~SCR1_NO_EXE_STAGE + +//------------------------------------------------------------------------------ +// Integer Arithmetic Logic Unit (IALU) +//------------------------------------------------------------------------------ + // + // Functionality: + // - Performs addition/subtraction and arithmetic and branch comparisons + // - Performs logical operations (AND(I), OR(I), XOR(I)) + // - Performs address calculation for branch, jump, DMEM load and store and AUIPC + // instructions + // - Performs shift operations + // - Performs MUL/DIV operations + // +//------------------------------------------------------------------------------ + +// IALU main operands fetch +//------------------------------------------------------------------------------ + +`ifdef SCR1_RVM_EXT +assign ialu_vd = exu_queue_vd & (exu_queue.ialu_cmd != SCR1_IALU_CMD_NONE) +`ifdef SCR1_TDU_EN + & ~tdu2exu_ibrkpt_exc_req_i +`endif // SCR1_TDU_EN + ; +`endif // SCR1_RVM_EXT + +always_comb begin +`ifdef SCR1_RVM_EXT + if (~ialu_vd) begin + ialu_main_op1 = '0; + ialu_main_op2 = '0; + end else begin +`endif // SCR1_RVM_EXT + if (exu_queue.ialu_op == SCR1_IALU_OP_REG_REG) begin + ialu_main_op1 = mprf2exu_rs1_data_i; + ialu_main_op2 = mprf2exu_rs2_data_i; + end else begin + ialu_main_op1 = mprf2exu_rs1_data_i; + ialu_main_op2 = exu_queue.imm; + end +`ifdef SCR1_RVM_EXT + end +`endif // SCR1_RVM_EXT +end + +// IALU address operands fetch +//------------------------------------------------------------------------------ + +always_comb begin + if (exu_queue.sum2_op == SCR1_SUM2_OP_REG_IMM) begin + ialu_addr_op1 = mprf2exu_rs1_data_i; + ialu_addr_op2 = exu_queue.imm; + end else begin + ialu_addr_op1 = pc_curr_ff; + ialu_addr_op2 = exu_queue.imm; + end +end + +// IALU module instantiation +//------------------------------------------------------------------------------ + +scr1_pipe_ialu i_ialu( +`ifdef SCR1_RVM_EXT + // Common + .clk (clk ), + .rst_n (rst_n ), + .exu2ialu_rvm_cmd_vd_i (ialu_vd ), + .ialu2exu_rvm_res_rdy_o (ialu_rdy ), +`endif // SCR1_RVM_EXT + + // IALU + .exu2ialu_main_op1_i (ialu_main_op1 ), + .exu2ialu_main_op2_i (ialu_main_op2 ), + .exu2ialu_cmd_i (exu_queue.ialu_cmd), + .ialu2exu_main_res_o (ialu_main_res ), + .ialu2exu_cmp_res_o (ialu_cmp ), + + // Address adder signals + .exu2ialu_addr_op1_i (ialu_addr_op1 ), + .exu2ialu_addr_op2_i (ialu_addr_op2 ), + .ialu2exu_addr_res_o (ialu_addr_res ) +); + +//------------------------------------------------------------------------------ +// Exceptions logic +//------------------------------------------------------------------------------ +// + // Exceptions logic consists of the following functional units: + // - Exception request logic + // - Exception code encoder + // - Exception trap value multiplexer + // +// + +`ifndef SCR1_RVC_EXT +assign jb_misalign = exu_queue_vd & jb_taken & |jb_new_pc[1:0]; +`endif // ~SCR1_RVC_EXT + +// Exception request +assign exu_exc_req = exu_queue_vd & (exu_queue.exc_req | lsu_exc_req + | csr2exu_rw_exc_i +`ifndef SCR1_RVC_EXT + | jb_misalign +`endif // ~SCR1_RVC_EXT +`ifdef SCR1_TDU_EN + `ifdef SCR1_DBG_EN + | exu2hdu_ibrkpt_hw_o + `endif // SCR1_DBG_EN +`endif // SCR1_TDU_EN + ); + +// EXU exception request register +//------------------------------------------------------------------------------ + +`ifdef SCR1_DBG_EN + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + exu_exc_req_ff <= 1'b0; + end else begin + exu_exc_req_ff <= exu_exc_req_next; + end +end + +assign exu_exc_req_next = hdu2exu_dbg_halt2run_i ? 1'b0 : exu_exc_req; +`endif // SCR1_DBG_EN + +// Exception code encoder +//------------------------------------------------------------------------------ + +always_comb begin + case (1'b1) +`ifdef SCR1_TDU_EN + `ifdef SCR1_DBG_EN + exu2hdu_ibrkpt_hw_o: exc_code = SCR1_EXC_CODE_BREAKPOINT; + `endif // SCR1_DBG_EN +`endif // SCR1_TDU_EN + exu_queue.exc_req : exc_code = exu_queue.exc_code; + lsu_exc_req : exc_code = lsu_exc_code; + csr2exu_rw_exc_i : exc_code = SCR1_EXC_CODE_ILLEGAL_INSTR; +`ifndef SCR1_RVC_EXT + jb_misalign : exc_code = SCR1_EXC_CODE_INSTR_MISALIGN; +`endif // ~SCR1_RVC_EXT + default : exc_code = SCR1_EXC_CODE_ECALL_M; + endcase // 1'b1 +end + +// Exception trap value multiplexer +//------------------------------------------------------------------------------ + +assign instr_fault_rvi_hi = exu_queue.instr_rvc; +assign exu_illegal_instr = {exu2csr_rw_addr_o, // CSR address + 5'(exu_queue.rs1_addr), // rs1 / zimm + exu_queue.imm[14:12], // funct3 + 5'(exu_queue.rd_addr), // rd + SCR1_OPCODE_SYSTEM, + SCR1_INSTR_RVI + }; + +// If Instruction Access Fault occurred on high part of RVI instruction trap +// value is set to point on the high part of the instruction (inc_pc=pc+2) +always_comb begin + case (exc_code) +`ifndef SCR1_RVC_EXT + SCR1_EXC_CODE_INSTR_MISALIGN : exc_trap_val = jb_new_pc; +`endif // SCR1_RVC_EXT + SCR1_EXC_CODE_INSTR_ACCESS_FAULT: exc_trap_val = instr_fault_rvi_hi + ? inc_pc + : pc_curr_ff; +`ifdef SCR1_MTVAL_ILLEGAL_INSTR_EN + SCR1_EXC_CODE_ILLEGAL_INSTR : exc_trap_val = exu_queue.exc_req + ? exu_queue.imm + : exu_illegal_instr; +`else // SCR1_MTVAL_ILLEGAL_INSTR_EN + SCR1_EXC_CODE_ILLEGAL_INSTR : exc_trap_val = '0; +`endif // SCR1_MTVAL_ILLEGAL_INSTR_EN +`ifdef SCR1_TDU_EN + SCR1_EXC_CODE_BREAKPOINT: begin + case (1'b1) + tdu2exu_ibrkpt_exc_req_i: exc_trap_val = pc_curr_ff; + tdu2lsu_dbrkpt_exc_req_i: exc_trap_val = ialu_addr_res; + default : exc_trap_val = '0; + endcase + end +`endif // SCR1_TDU_EN + SCR1_EXC_CODE_LD_ADDR_MISALIGN, + SCR1_EXC_CODE_LD_ACCESS_FAULT, + SCR1_EXC_CODE_ST_ADDR_MISALIGN, + SCR1_EXC_CODE_ST_ACCESS_FAULT : exc_trap_val = ialu_addr_res; + default : exc_trap_val = '0; + endcase // exc_code +end + +//------------------------------------------------------------------------------ +// WFI logic +//------------------------------------------------------------------------------ +// + // Wait for interrupt (WFI) logic consists of the following functional units: + // - WFI control logic + // - WFI Run Start register + // - WFI Halted flag register + // - WFI status signals +// + +// WFI control logic +//------------------------------------------------------------------------------ + +assign wfi_halt_cond = ~csr2exu_ip_ie_i + & ((exu_queue_vd & exu_queue.wfi_req) | wfi_run_start_ff) +`ifdef SCR1_DBG_EN + & ~hdu2exu_no_commit_i & ~hdu2exu_dmode_sstep_en_i & ~hdu2exu_dbg_run2halt_i +`endif // SCR1_DBG_EN + ; +assign wfi_halt_req = ~wfi_halted_ff & wfi_halt_cond; + +// HART will exit WFI halted state if the event that causes the HART to resume +// execution occurs even if it doesn't cause an interrupt to be taken +assign wfi_run_req = wfi_halted_ff & (csr2exu_ip_ie_i +`ifdef SCR1_DBG_EN + | hdu2exu_dbg_halt2run_i +`endif // SCR1_DBG_EN + ); + +// WFI Run Start register +//------------------------------------------------------------------------------ + +`ifndef SCR1_CLKCTRL_EN +always_ff @(negedge rst_n, posedge clk) begin +`else // SCR1_CLKCTRL_EN +always_ff @(negedge rst_n, posedge clk_alw_on) begin +`endif // SCR1_CLKCTRL_EN + if (~rst_n) begin + wfi_run_start_ff <= 1'b0; + end else begin + wfi_run_start_ff <= wfi_run_start_next; + end +end + +assign wfi_run_start_next = wfi_halted_ff & csr2exu_ip_ie_i & ~exu2csr_take_irq_o; + +// WFI halted flag register +//------------------------------------------------------------------------------ + +assign wfi_halted_upd = wfi_halt_req | wfi_run_req; + +`ifndef SCR1_CLKCTRL_EN +always_ff @(negedge rst_n, posedge clk) begin +`else // SCR1_CLKCTRL_EN +always_ff @(negedge rst_n, posedge clk_alw_on) begin +`endif // SCR1_CLKCTRL_EN + if (~rst_n) begin + wfi_halted_ff <= 1'b0; + end else if (wfi_halted_upd) begin + wfi_halted_ff <= wfi_halted_next; + end +end + +assign wfi_halted_next = wfi_halt_req | ~wfi_run_req; + +// WFI status signals +//------------------------------------------------------------------------------ + +assign exu2pipe_wfi_run2halt_o = wfi_halt_req; +`ifdef SCR1_CLKCTRL_EN +assign exu2pipe_wfi_halted_o = wfi_halted_ff; +`endif // SCR1_CLKCTRL_EN + +//------------------------------------------------------------------------------ +// Program Counter logic +//------------------------------------------------------------------------------ +// + // PC logic consists of the following functional units: + // - PC initialization logic + // - Current PC register + // - New PC multiplexer + +// PC initialization logic +//------------------------------------------------------------------------------ +// Generates a New PC request to set PC to reset value + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + init_pc_v <= '0; + end else begin + if (~&init_pc_v) begin + init_pc_v <= {init_pc_v[2:0], 1'b1}; + end + end +end + +assign init_pc = ~init_pc_v[3] & init_pc_v[2]; + +// Current PC register +//------------------------------------------------------------------------------ + +assign pc_curr_upd = ((exu2pipe_instret_o | exu2csr_take_irq_o +`ifdef SCR1_DBG_EN + | dbg_run_start_npbuf) & ( ~hdu2exu_pc_advmt_dsbl_i + & ~hdu2exu_no_commit_i +`endif // SCR1_DBG_EN + )); + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + pc_curr_ff <= SCR1_RST_VECTOR; + end else if (pc_curr_upd) begin + pc_curr_ff <= pc_curr_next; + end +end + +`ifdef SCR1_RVC_EXT +assign inc_pc = pc_curr_ff + (exu_queue.instr_rvc ? `SCR1_XLEN'd2 : `SCR1_XLEN'd4); +`else // ~SCR1_RVC_EXT +assign inc_pc = pc_curr_ff + `SCR1_XLEN'd4; +`endif // ~SCR1_RVC_EXT + +assign pc_curr_next = exu2ifu_pc_new_req_o ? exu2ifu_pc_new_o + : (inc_pc[6] ^ pc_curr_ff[6]) ? inc_pc + : {pc_curr_ff[`SCR1_XLEN-1:6], inc_pc[5:0]}; + +// New PC multiplexer +//------------------------------------------------------------------------------ + +always_comb begin + case (1'b1) + init_pc : exu2ifu_pc_new_o = SCR1_RST_VECTOR; + exu2csr_take_exc_o, + exu2csr_take_irq_o, + exu2csr_mret_instr_o: exu2ifu_pc_new_o = csr2exu_new_pc_i; +`ifdef SCR1_DBG_EN + dbg_run_start_npbuf : exu2ifu_pc_new_o = hdu2exu_dbg_new_pc_i; +`endif // SCR1_DBG_EN + wfi_run_start_ff : exu2ifu_pc_new_o = pc_curr_ff; + exu_queue.fencei_req: exu2ifu_pc_new_o = inc_pc; + default : exu2ifu_pc_new_o = ialu_addr_res & SCR1_JUMP_MASK; + endcase +end + +assign exu2ifu_pc_new_req_o = init_pc // reset + | exu2csr_take_irq_o + | exu2csr_take_exc_o + | (exu2csr_mret_instr_o & ~csr2exu_mstatus_mie_up_i) + | (exu_queue_vd & exu_queue.fencei_req) + | (wfi_run_start_ff +`ifdef SCR1_CLKCTRL_EN + & clk_pipe_en +`endif // SCR1_CLKCTRL_EN + ) +`ifdef SCR1_DBG_EN + | dbg_run_start_npbuf +`endif // SCR1_DBG_EN + | (exu_queue_vd & jb_taken); + +// Jump/branch signals +assign branch_taken = exu_queue.branch_req & ialu_cmp; +assign jb_taken = exu_queue.jump_req | branch_taken; +assign jb_new_pc = ialu_addr_res & SCR1_JUMP_MASK; + +// PC to be loaded on MRET from interrupt trap +assign exu2csr_pc_next_o = ~exu_queue_vd ? pc_curr_ff + : jb_taken ? jb_new_pc + : inc_pc; +assign exu2pipe_pc_curr_o = pc_curr_ff; + +//------------------------------------------------------------------------------ +// Load/Store Unit (LSU) +//------------------------------------------------------------------------------ + // + // Functionality: + // - Performs load and store operations in Data Memory + // - Generates DMEM address misalign and access fault exceptions + // - Passes DMEM operations information to TDU and generates LSU breakpoint exception + // +//------------------------------------------------------------------------------ + +assign lsu_req = ((exu_queue.lsu_cmd != SCR1_LSU_CMD_NONE) & exu_queue_vd); + +scr1_pipe_lsu i_lsu( + .rst_n (rst_n ), + .clk (clk ), + + // EXU <-> LSU interface + .exu2lsu_req_i (lsu_req ), // Request to LSU + .exu2lsu_cmd_i (exu_queue.lsu_cmd ), // LSU command + .exu2lsu_addr_i (ialu_addr_res ), // DMEM address + .exu2lsu_sdata_i (mprf2exu_rs2_data_i ), // Data for store to DMEM + .lsu2exu_rdy_o (lsu_rdy ), // LSU ready + .lsu2exu_ldata_o (lsu_l_data ), // Loaded data form DMEM + .lsu2exu_exc_o (lsu_exc_req ), // LSU exception + .lsu2exu_exc_code_o (lsu_exc_code ), // LSU exception code + +`ifdef SCR1_TDU_EN + // TDU <-> LSU interface + .lsu2tdu_dmon_o (lsu2tdu_dmon_o ), + .tdu2lsu_ibrkpt_exc_req_i (tdu2lsu_ibrkpt_exc_req_i), + .tdu2lsu_dbrkpt_exc_req_i (tdu2lsu_dbrkpt_exc_req_i), +`endif // SCR1_TDU_EN + + // Data memory interface + .lsu2dmem_req_o (exu2dmem_req_o ), // DMEM request + .lsu2dmem_cmd_o (exu2dmem_cmd_o ), // DMEM command + .lsu2dmem_width_o (exu2dmem_width_o ), // DMEM width + .lsu2dmem_addr_o (exu2dmem_addr_o ), // DMEM address + .lsu2dmem_wdata_o (exu2dmem_wdata_o ), // DMEM write data + .dmem2lsu_req_ack_i (dmem2exu_req_ack_i ), // DMEM request acknowledge + .dmem2lsu_rdata_i (dmem2exu_rdata_i ), // DMEM read data + .dmem2lsu_resp_i (dmem2exu_resp_i ) // DMEM response +); + +//------------------------------------------------------------------------------ +// EXU status logic +//------------------------------------------------------------------------------ + +// EXU ready flag +always_comb begin + case (1'b1) + lsu_req : exu_rdy = lsu_rdy | lsu_exc_req; +`ifdef SCR1_RVM_EXT + ialu_vd : exu_rdy = ialu_rdy; +`endif // SCR1_RVM_EXT + csr2exu_mstatus_mie_up_i: exu_rdy = 1'b0; + default : exu_rdy = 1'b1; + endcase +end + +assign exu2pipe_init_pc_o = init_pc; +assign exu2idu_rdy_o = exu_rdy & ~exu_queue_barrier; +assign exu2pipe_exu_busy_o = exu_queue_vd & ~exu_rdy; +assign exu2pipe_instret_o = exu_queue_vd & exu_rdy; +`ifndef SCR1_CSR_REDUCED_CNT +assign exu2csr_instret_no_exc_o = exu2pipe_instret_o & ~exu_exc_req; +`endif // SCR1_CSR_REDUCED_CNT + +// Exceptions +`ifdef SCR1_DBG_EN +assign exu2pipe_exc_req_o = exu_queue_vd ? exu_exc_req : exu_exc_req_ff; +`else // SCR1_DBG_EN +assign exu2pipe_exc_req_o = exu_exc_req; +`endif // SCR1_DBG_EN + +// Breakpoints +assign exu2pipe_brkpt_o = exu_queue_vd & (exu_queue.exc_code == SCR1_EXC_CODE_BREAKPOINT); +`ifdef SCR1_TDU_EN + `ifdef SCR1_DBG_EN +assign exu2hdu_ibrkpt_hw_o = tdu2exu_ibrkpt_exc_req_i | tdu2lsu_dbrkpt_exc_req_i; + `endif // SCR1_DBG_EN +`endif // SCR1_TDU_EN + +//------------------------------------------------------------------------------ +// EXU <-> MPRF interface +//------------------------------------------------------------------------------ + +// Operands fetching stage +//------------------------------------------------------------------------------ + +`ifdef SCR1_NO_EXE_STAGE +assign mprf_rs1_req = exu_queue_vd & idu2exu_use_rs1_i; +assign mprf_rs2_req = exu_queue_vd & idu2exu_use_rs2_i; +`else // SCR1_NO_EXE_STAGE + `ifdef SCR1_MPRF_RAM +assign mprf_rs1_req = exu_queue_en + ? (exu_queue_vd_next & idu2exu_use_rs1_i) + : (exu_queue_vd & idu2exu_use_rs1_ff); +assign mprf_rs2_req = exu_queue_en + ? (exu_queue_vd_next & idu2exu_use_rs2_i) + : (exu_queue_vd & idu2exu_use_rs2_ff); + `else // SCR1_MPRF_RAM +assign mprf_rs1_req = exu_queue_vd & idu2exu_use_rs1_ff; +assign mprf_rs2_req = exu_queue_vd & idu2exu_use_rs2_ff; + `endif // SCR1_MPRF_RAM +`endif // SCR1_NO_EXE_STAGE + +// If exu_queue isn't enabled we need previous addresses and usage flags because +// RAM blocks read operation is SYNCHRONOUS +`ifdef SCR1_MPRF_RAM +assign mprf_rs1_addr = exu_queue_en ? idu2exu_cmd_i.rs1_addr[`SCR1_MPRF_AWIDTH-1:0] : exu_queue.rs1_addr[`SCR1_MPRF_AWIDTH-1:0]; +assign mprf_rs2_addr = exu_queue_en ? idu2exu_cmd_i.rs2_addr[`SCR1_MPRF_AWIDTH-1:0] : exu_queue.rs2_addr[`SCR1_MPRF_AWIDTH-1:0]; +`else // SCR1_MPRF_RAM +assign mprf_rs1_addr = exu_queue.rs1_addr[`SCR1_MPRF_AWIDTH-1:0]; +assign mprf_rs2_addr = exu_queue.rs2_addr[`SCR1_MPRF_AWIDTH-1:0]; +`endif // SCR1_MPRF_RAM + +assign exu2mprf_rs1_addr_o = mprf_rs1_req ? mprf_rs1_addr[`SCR1_MPRF_AWIDTH-1:0] : '0; +assign exu2mprf_rs2_addr_o = mprf_rs2_req ? mprf_rs2_addr[`SCR1_MPRF_AWIDTH-1:0] : '0; + +// Write back stage +//------------------------------------------------------------------------------ + +assign exu2mprf_w_req_o = (exu_queue.rd_wb_sel != SCR1_RD_WB_NONE) & exu_queue_vd & ~exu_exc_req +`ifdef SCR1_DBG_EN + & ~hdu2exu_no_commit_i +`endif // SCR1_DBG_EN + & ((exu_queue.rd_wb_sel == SCR1_RD_WB_CSR) ? csr_access_init : exu_rdy); + +assign exu2mprf_rd_addr_o = `SCR1_MPRF_AWIDTH'(exu_queue.rd_addr); + +// MRPF RD data multiplexer +always_comb begin + case (exu_queue.rd_wb_sel) + SCR1_RD_WB_SUM2 : exu2mprf_rd_data_o = ialu_addr_res; + SCR1_RD_WB_IMM : exu2mprf_rd_data_o = exu_queue.imm; + SCR1_RD_WB_INC_PC: exu2mprf_rd_data_o = inc_pc; + SCR1_RD_WB_LSU : exu2mprf_rd_data_o = lsu_l_data; + SCR1_RD_WB_CSR : exu2mprf_rd_data_o = csr2exu_r_data_i; + default : exu2mprf_rd_data_o = ialu_main_res; + endcase +end + +//------------------------------------------------------------------------------ +// EXU <-> CSR interface +//------------------------------------------------------------------------------ +// + // EXU <-> CSR interface consists of the following functional units: + // - CSR write/read interface + // - CSR access FSM + // - CSR events interface: + // - Exceptions signals + // - Interrupts signals + // - MRET signals +// + +// CSRs write/read interface +//------------------------------------------------------------------------------ + +// CSR write/read request signals calculation +always_comb begin + if (~exu_queue_vd +`ifdef SCR1_TDU_EN + | tdu2exu_ibrkpt_exc_req_i +`endif // SCR1_TDU_EN + ) begin + exu2csr_r_req_o = 1'b0; + exu2csr_w_req_o = 1'b0; + end else begin + case (exu_queue.csr_cmd) + SCR1_CSR_CMD_WRITE : begin + exu2csr_r_req_o = |exu_queue.rd_addr; + exu2csr_w_req_o = csr_access_init; + end + SCR1_CSR_CMD_SET, + SCR1_CSR_CMD_CLEAR : begin + exu2csr_r_req_o = 1'b1; + exu2csr_w_req_o = |exu_queue.rs1_addr & csr_access_init; + end + default : begin + exu2csr_r_req_o = 1'b0; + exu2csr_w_req_o = 1'b0; + end + endcase + end +end + +assign exu2csr_w_cmd_o = exu_queue.csr_cmd; +assign exu2csr_rw_addr_o = exu_queue.imm[SCR1_CSR_ADDR_WIDTH-1:0]; +assign exu2csr_w_data_o = (exu_queue.csr_op == SCR1_CSR_OP_REG) + ? mprf2exu_rs1_data_i + : {'0, exu_queue.rs1_addr}; // zimm + + +// CSR access FSM +//------------------------------------------------------------------------------ + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + csr_access_ff <= SCR1_CSR_INIT; + end else begin + csr_access_ff <= csr_access_next; + end +end + +assign csr_access_next = (csr_access_init & csr2exu_mstatus_mie_up_i) + ? SCR1_CSR_RDY + : SCR1_CSR_INIT; + +assign csr_access_init = (csr_access_ff == SCR1_CSR_INIT); + +// CSR events interface +//------------------------------------------------------------------------------ + +// Exceptions signals +assign exu2csr_take_exc_o = exu_exc_req +`ifdef SCR1_DBG_EN + & ~hdu2exu_dbg_halted_i +`endif // SCR1_DBG_EN + ; +assign exu2csr_exc_code_o = exc_code; +assign exu2csr_trap_val_o = exc_trap_val; + +// Interrupts signals +assign exu2csr_take_irq_o = csr2exu_irq_i & ~exu2pipe_exu_busy_o +`ifdef SCR1_DBG_EN + & ~hdu2exu_irq_dsbl_i + & ~hdu2exu_dbg_halted_i +`endif // SCR1_DBG_EN +`ifdef SCR1_CLKCTRL_EN + & clk_pipe_en +`endif // SCR1_CLKCTRL_EN + ; + +// MRET signals +// MRET instruction flag +assign exu2csr_mret_instr_o = exu_queue_vd & exu_queue.mret_req +`ifdef SCR1_TDU_EN + & ~tdu2exu_ibrkpt_exc_req_i +`endif // SCR1_TDU_EN +`ifdef SCR1_DBG_EN + & ~hdu2exu_dbg_halted_i +`endif // SCR1_DBG_EN + ; +assign exu2csr_mret_update_o = exu2csr_mret_instr_o & csr_access_init; + +`ifdef SCR1_TDU_EN +//------------------------------------------------------------------------------ +// EXU <-> TDU interface +//------------------------------------------------------------------------------ + +// Instruction monitor +assign exu2tdu_imon_o.vd = exu_queue_vd; +assign exu2tdu_imon_o.req = exu2pipe_instret_o; +assign exu2tdu_imon_o.addr = pc_curr_ff; + +always_comb begin + exu2tdu_ibrkpt_ret_o = '0; + if (exu_queue_vd) begin + exu2tdu_ibrkpt_ret_o = tdu2exu_ibrkpt_match_i; + if (lsu_req) begin + exu2tdu_ibrkpt_ret_o[SCR1_TDU_MTRIG_NUM-1:0] |= tdu2lsu_dbrkpt_match_i; + end + end +end +`endif // SCR1_TDU_EN + + +`ifdef SCR1_TRGT_SIMULATION +//------------------------------------------------------------------------------ +// Tracelog signals +//------------------------------------------------------------------------------ + +logic [`SCR1_XLEN-1:0] update_pc; +logic update_pc_en; + +assign update_pc_en = (init_pc | exu2pipe_instret_o | exu2csr_take_irq_o) +`ifdef SCR1_DBG_EN + & ~hdu2exu_pc_advmt_dsbl_i & ~hdu2exu_no_commit_i +`endif // SCR1_DBG_EN + ; +assign update_pc = exu2ifu_pc_new_req_o ? exu2ifu_pc_new_o : inc_pc; + + +//------------------------------------------------------------------------------ +// Assertion +//------------------------------------------------------------------------------ + +// X checks + +SCR1_SVA_EXU_XCHECK_CTRL : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown({idu2exu_req_i, csr2exu_irq_i, csr2exu_ip_ie_i, lsu_req, lsu_rdy, exu_exc_req}) + ) else $error("EXU Error: unknown control values"); + +SCR1_SVA_EXU_XCHECK_QUEUE : assert property ( + @(negedge clk) disable iff (~rst_n) + (idu2exu_req_i & exu_queue_vd) |-> !$isunknown(idu2exu_cmd_i) + ) else $error("EXU Error: unknown values in queue"); + +SCR1_SVA_EXU_XCHECK_CSR_RDATA : assert property ( + @(negedge clk) disable iff (~rst_n) + exu2csr_r_req_o |-> !$isunknown({csr2exu_r_data_i, csr2exu_rw_exc_i}) + ) else $error("EXU Error: unknown values from CSR"); + +// Behavior checks + +SCR1_SVA_EXU_ONEHOT : assert property ( + @(negedge clk) disable iff (~rst_n) + $onehot0({exu_queue.jump_req, exu_queue.branch_req, lsu_req}) + ) else $error("EXU Error: illegal combination of control signals"); + +SCR1_SVA_EXU_ONEHOT_EXC : assert property ( + @(negedge clk) disable iff (~rst_n) + exu_queue_vd |-> + $onehot0({exu_queue.exc_req, lsu_exc_req, csr2exu_rw_exc_i +`ifndef SCR1_RVC_EXT + , jb_misalign +`endif + }) + ) else $error("EXU Error: exceptions $onehot0 failed"); + +// No event can request current PC update before initial reset sequence is done +SCR1_SVA_EXU_CURR_PC_UPD_BEFORE_INIT : assert property ( + @(negedge clk) disable iff (~rst_n) + ~&init_pc_v |-> ~( pc_curr_upd & ~init_pc ) + ) else $error("EXU Error: current PC updated before been initialized"); + +// No event can generate a new PC request to IFU before initial reset sequence +// is done +SCR1_SVA_EXU_NEW_PC_REQ_BEFORE_INIT : assert property ( + @(negedge clk) disable iff (~rst_n) + ~&init_pc_v |-> ~( exu2ifu_pc_new_req_o & ~init_pc ) + ) else $error("EXU Error: new PC req generated before reset sequence is done"); + +`endif // SCR1_TRGT_SIMULATION + +endmodule : scr1_pipe_exu diff --git a/src/rtl/scr1/scr1_pipe_hdu.sv b/src/rtl/scr1/scr1_pipe_hdu.sv new file mode 100644 index 0000000..14f421b --- /dev/null +++ b/src/rtl/scr1/scr1_pipe_hdu.sv @@ -0,0 +1,904 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief HART Debug Unit (HDU) +/// + +//------------------------------------------------------------------------------ + // + // + // Functionality: + // - Controls HART state (RUN, Debug RUN, Debug HALTED) + // - Setups Debug Mode execution + // - Provides status information about Debug Mode execution + // - Provides Program Buffer functionality (a few instructions execution while + // in Debug Mode) + // - Provides access to Debug CSRs + // + // Structure: + // - Debug state FSM + // - HART Control logic + // - HART Status logic + // - Program Buffer + // - Debug CSRs + // - HDU <-> DM interface + // - HDU <-> EXU interface + // - HDU <-> IFU interface + // - HDU <-> CSR interface + // - HDU <-> TDU interface + // +//------------------------------------------------------------------------------ + +`include "scr1_arch_description.svh" + +`ifdef SCR1_DBG_EN +`include "scr1_arch_types.svh" +`include "scr1_riscv_isa_decoding.svh" +`include "scr1_hdu.svh" + +module scr1_pipe_hdu #(parameter HART_PBUF_INSTR_REGOUT_EN = 1'b1) ( + // Common signals + input logic rst_n, // HDU reset + input logic clk, // HDU clock + input logic clk_en, // HDU clock enable +`ifdef SCR1_CLKCTRL_EN + input logic clk_pipe_en, // Pipeline clock enable +`endif // SCR1_CLKCTRL_EN + input logic pipe2hdu_rdc_qlfy_i, // Pipeline RDC qualifier + + // HDU <-> CSR i/f + input logic csr2hdu_req_i, // CSR i/f request + input type_scr1_csr_cmd_sel_e csr2hdu_cmd_i, // CSR i/f command + input logic [SCR1_HDU_DEBUGCSR_ADDR_WIDTH-1:0] csr2hdu_addr_i, // CSR i/f address + input logic [`SCR1_XLEN-1:0] csr2hdu_wdata_i, // CSR i/f write data + output type_scr1_csr_resp_e hdu2csr_resp_o, // CSR i/f response + output logic [`SCR1_XLEN-1:0] hdu2csr_rdata_o, // CSR i/f read data + + // HDU <-> DM i/f + // HART Run Control i/f + input logic dm2hdu_cmd_req_i, // DM-HART Command request + input type_scr1_hdu_dbgstates_e dm2hdu_cmd_i, // DM-HART Command + output logic hdu2dm_cmd_resp_o, // DM-HART Command response + output logic hdu2dm_cmd_rcode_o, // DM-HART Command return code: 0 - Ok; 1 - Error + output logic hdu2dm_hart_event_o, // DM-HART Event: 1 if HART debug state changed + output type_scr1_hdu_hartstatus_s hdu2dm_hart_status_o, // DM-HART Status + + // Program Buffer i/f + output logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] hdu2dm_pbuf_addr_o, // Program Buffer address - so far request only for 1 instruction + input logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] dm2hdu_pbuf_instr_i, // Program Buffer instruction + + // HART Abstract Data regs i/f + output logic hdu2dm_dreg_req_o, // Abstract Data Register request + output logic hdu2dm_dreg_wr_o, // Abstract Data Register write + output logic [`SCR1_XLEN-1:0] hdu2dm_dreg_wdata_o, // Abstract Data Register write data + input logic dm2hdu_dreg_resp_i, // Abstract Data Register response + input logic dm2hdu_dreg_fail_i, // Abstract Data Register fail + input logic [`SCR1_XLEN-1:0] dm2hdu_dreg_rdata_i, // Abstract Data Register read data + +`ifdef SCR1_TDU_EN + // HDU <-> TDU interface + output logic hdu2tdu_hwbrk_dsbl_o, // Disables BRKM + input logic tdu2hdu_dmode_req_i, // Trigger Module requests transition to debug mode + input logic exu2hdu_ibrkpt_hw_i, // Hardware breakpoint on current instruction +`endif // SCR1_TDU_EN + + // HART Run Status + input logic pipe2hdu_exu_busy_i, // EXU busy + input logic pipe2hdu_instret_i, // Instruction retired (with or without exception) + input logic pipe2hdu_init_pc_i, // Reset exit + + // HART Halt Status + input logic pipe2hdu_exu_exc_req_i, // Exception request + input logic pipe2hdu_brkpt_i, // Software Breakpoint (EBREAK) + + // HDU <-> EXU i/f + // HART Run Control + output logic hdu2exu_pbuf_fetch_o, // Fetch instruction from Program Buffer + output logic hdu2exu_no_commit_o, // Forbid instruction commitment + output logic hdu2exu_irq_dsbl_o, // Disable IRQ + output logic hdu2exu_pc_advmt_dsbl_o, // Forbid PC advancement + output logic hdu2exu_dmode_sstep_en_o, // Enable single-step + + // HART state + output logic hdu2exu_dbg_halted_o, // Debug halted state + output logic hdu2exu_dbg_run2halt_o, // Transition to debug halted state + output logic hdu2exu_dbg_halt2run_o, // Transition to run state + output logic hdu2exu_dbg_run_start_o, // First cycle of run state + + // PC interface + input logic [`SCR1_XLEN-1:0] pipe2hdu_pc_curr_i, // Current PC + output logic [`SCR1_XLEN-1:0] hdu2exu_dbg_new_pc_o, // New PC for resume + + // HDU <-> IFU i/f + // Program Buffer Instruction interface + input logic ifu2hdu_pbuf_instr_rdy_i, // Program Buffer Instruction i/f ready + output logic hdu2ifu_pbuf_instr_vd_o, // Program Buffer Instruction valid + output logic hdu2ifu_pbuf_instr_err_o, // Program Buffer Instruction i/f error + output logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] hdu2ifu_pbuf_instr_o // Program Buffer Instruction itself +); + +//------------------------------------------------------------------------------ +// Local Parameters +//------------------------------------------------------------------------------ + +localparam int unsigned SCR1_HDU_TIMEOUT = 64; // must be power of 2 +localparam int unsigned SCR1_HDU_TIMEOUT_WIDTH = $clog2(SCR1_HDU_TIMEOUT); + +//------------------------------------------------------------------------------ +// Local Signals +//------------------------------------------------------------------------------ + +// Debug FSM +//------------------------------------------------------------------------------ + +// FSM control signals +logic dm_dhalt_req; +logic dm_run_req; + +logic dm_cmd_run; +logic dm_cmd_dhalted; +logic dm_cmd_drun; + +// Debug state FSM signals +type_scr1_hdu_dbgstates_e dbg_state; +type_scr1_hdu_dbgstates_e dbg_state_next; +logic dbg_state_dhalted; +logic dbg_state_drun; +logic dbg_state_run; +logic dbg_state_reset; + +// FSM transition, update and event registers +logic dfsm_trans; +logic dfsm_trans_next; +logic dfsm_update; +logic dfsm_update_next; +logic dfsm_event; +logic dfsm_event_next; + +// HART Control signals +//------------------------------------------------------------------------------ + +logic hart_resume_req; +logic hart_halt_req; +logic hart_cmd_req; + +// HART Run Control register +logic hart_runctrl_upd; +logic hart_runctrl_clr; +type_scr1_hdu_runctrl_s hart_runctrl; + +// HART halt request timeout counter signals +logic [SCR1_HDU_TIMEOUT_WIDTH-1:0] halt_req_timeout_cnt; +logic [SCR1_HDU_TIMEOUT_WIDTH-1:0] halt_req_timeout_cnt_next; +logic halt_req_timeout_cnt_en; +logic halt_req_timeout_flag; + +// HART Status signals +//------------------------------------------------------------------------------ + +type_scr1_hdu_haltstatus_s hart_haltstatus; +type_scr1_hdu_haltcause_e hart_haltcause; + +logic hart_halt_pnd; +logic hart_halt_ack; + +// Debug mode cause decoder signals +logic dmode_cause_sstep; +logic dmode_cause_except; +logic dmode_cause_ebreak; +logic dmode_cause_any; +`ifdef SCR1_TDU_EN +logic dmode_cause_tmreq; +`endif // SCR1_TDU_EN + +// Program Buffer FSM +//------------------------------------------------------------------------------ + +// PBUF FSM control signals +logic ifu_handshake_done; +logic pbuf_exc_inj_req; +logic pbuf_exc_inj_end; +logic pbuf_start_fetch; + +// PBUF FSM signals +type_scr1_hdu_pbufstates_e pbuf_fsm_curr; +type_scr1_hdu_pbufstates_e pbuf_fsm_next; +logic pbuf_fsm_idle; +logic pbuf_fsm_fetch; +logic pbuf_fsm_excinj; + +// PBUF address signals +logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] pbuf_addr_ff; +logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] pbuf_addr_next; +logic pbuf_addr_end; +logic pbuf_addr_next_vd; + +logic pbuf_instr_wait_latching; + +// Debugs CSRs +//------------------------------------------------------------------------------ + +// CSRs write/read interface signals +logic csr_upd_on_halt; +logic csr_wr; +logic [`SCR1_XLEN-1:0] csr_wr_data; +logic [`SCR1_XLEN-1:0] csr_rd_data; + +// Debug Control and Status register (DCSR) +logic csr_dcsr_sel; +logic csr_dcsr_wr; +type_scr1_hdu_dcsr_s csr_dcsr_in; +type_scr1_hdu_dcsr_s csr_dcsr_out; +logic csr_dcsr_ebreakm; +logic csr_dcsr_stepie; +logic csr_dcsr_step; +logic [SCR1_HDU_DCSR_CAUSE_BIT_L- + SCR1_HDU_DCSR_CAUSE_BIT_R:0] csr_dcsr_cause; + +// Debug Program Counter register (DPC) +logic csr_dpc_sel; +logic csr_dpc_wr; +logic [`SCR1_XLEN-1:0] csr_dpc_ff; +logic [`SCR1_XLEN-1:0] csr_dpc_next; +logic [`SCR1_XLEN-1:0] csr_dpc_out; + +// Debug Scratch register 0 (DSCRATCH0) +logic csr_addr_dscratch0; +logic csr_dscratch0_sel; +logic csr_dscratch0_wr; +logic [`SCR1_XLEN-1:0] csr_dscratch0_out; +type_scr1_csr_resp_e csr_dscratch0_resp; + +//------------------------------------------------------------------------------ +// Debug state FSM logic +//------------------------------------------------------------------------------ +// + // Debug state FSM logic consists of the following functional units: + // - FSM control logic + // - Debug state FSM + // - FSM transition, update and event registers +// + +// FSM control logic +//------------------------------------------------------------------------------ + +assign dm_cmd_dhalted = (dm2hdu_cmd_i == SCR1_HDU_DBGSTATE_DHALTED); +assign dm_cmd_run = (dm2hdu_cmd_i == SCR1_HDU_DBGSTATE_RUN); +assign dm_cmd_drun = (dm2hdu_cmd_i == SCR1_HDU_DBGSTATE_DRUN); + +assign dm_dhalt_req = dm2hdu_cmd_req_i & dm_cmd_dhalted; +assign dm_run_req = dm2hdu_cmd_req_i & (dm_cmd_run | dm_cmd_drun); + +// Debug state FSM +//------------------------------------------------------------------------------ + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + dbg_state <= SCR1_HDU_DBGSTATE_RESET; + end else begin + dbg_state <= dbg_state_next; + end +end + +always_comb begin + if (~pipe2hdu_rdc_qlfy_i) begin + dbg_state_next = SCR1_HDU_DBGSTATE_RESET; + end else begin + case (dbg_state) + SCR1_HDU_DBGSTATE_RESET: begin + dbg_state_next = ~pipe2hdu_init_pc_i ? SCR1_HDU_DBGSTATE_RESET + : dm_dhalt_req ? SCR1_HDU_DBGSTATE_DHALTED + : SCR1_HDU_DBGSTATE_RUN; + end + SCR1_HDU_DBGSTATE_RUN: begin + dbg_state_next = dfsm_update ? SCR1_HDU_DBGSTATE_DHALTED + : SCR1_HDU_DBGSTATE_RUN; + end + SCR1_HDU_DBGSTATE_DHALTED: begin + dbg_state_next = ~dfsm_update ? SCR1_HDU_DBGSTATE_DHALTED + : dm_cmd_drun ? SCR1_HDU_DBGSTATE_DRUN + : SCR1_HDU_DBGSTATE_RUN; + end + SCR1_HDU_DBGSTATE_DRUN: begin + dbg_state_next = dfsm_update ? SCR1_HDU_DBGSTATE_DHALTED + : SCR1_HDU_DBGSTATE_DRUN; + end + default: begin +`ifdef SCR1_XPROP_EN + dbg_state_next = SCR1_HDU_DBGSTATE_XXX; +`else // SCR1_XPROP_EN + dbg_state_next = dbg_state; +`endif // SCR1_XPROP_EN + end + endcase + end +end + +assign dbg_state_dhalted = (dbg_state == SCR1_HDU_DBGSTATE_DHALTED); +assign dbg_state_drun = (dbg_state == SCR1_HDU_DBGSTATE_DRUN); +assign dbg_state_run = (dbg_state == SCR1_HDU_DBGSTATE_RUN); +assign dbg_state_reset = (dbg_state == SCR1_HDU_DBGSTATE_RESET); + +// FSM transition, update and event registers +//------------------------------------------------------------------------------ + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + dfsm_trans <= 1'b0; + dfsm_update <= 1'b0; + dfsm_event <= 1'b0; + end else begin + dfsm_trans <= dfsm_trans_next; + dfsm_update <= dfsm_update_next; + dfsm_event <= dfsm_event_next; + end +end + +always_comb begin + dfsm_trans_next = 1'b0; + dfsm_update_next = 1'b0; + dfsm_event_next = 1'b0; + + if (~pipe2hdu_rdc_qlfy_i) begin + dfsm_trans_next = 1'b0; + dfsm_update_next = 1'b0; + dfsm_event_next = 1'b1; + end else begin + case (dbg_state) + SCR1_HDU_DBGSTATE_RESET: begin + dfsm_trans_next = 1'b0; + dfsm_update_next = 1'b0; + dfsm_event_next = pipe2hdu_init_pc_i & ~dm2hdu_cmd_req_i; + end + + SCR1_HDU_DBGSTATE_RUN, + SCR1_HDU_DBGSTATE_DRUN: begin + dfsm_trans_next = ~dfsm_update ? hart_halt_pnd : dfsm_trans; + dfsm_update_next = ~dfsm_update & hart_halt_ack; + dfsm_event_next = dfsm_update; + end + + SCR1_HDU_DBGSTATE_DHALTED: begin + dfsm_trans_next = ~dfsm_update ? ~dfsm_trans & dm_run_req + : dfsm_trans; + dfsm_update_next = ~dfsm_update & dfsm_trans; + dfsm_event_next = dfsm_update; + end + + default : begin + dfsm_trans_next = 'X; + dfsm_update_next = 'X; + dfsm_event_next = 'X; + end + endcase + end +end + +//------------------------------------------------------------------------------ +// HART Control logic +//------------------------------------------------------------------------------ +// + // HART Control logic consists of the following functional units: + // - Control signals + // - HART Run Control register + // - HART Halt Request Time-Out counter +// + +// Control logic +always_comb begin + hart_cmd_req = 1'b0; + + if (~pipe2hdu_rdc_qlfy_i) begin + hart_cmd_req = 1'b0; + end else begin + case (dbg_state) + SCR1_HDU_DBGSTATE_RESET : hart_cmd_req = dm2hdu_cmd_req_i; + SCR1_HDU_DBGSTATE_DHALTED: hart_cmd_req = (dfsm_update | dfsm_trans); + SCR1_HDU_DBGSTATE_RUN, + SCR1_HDU_DBGSTATE_DRUN : hart_cmd_req = ~dfsm_update & dfsm_trans; + default : hart_cmd_req = 'X; + endcase + end +end + +assign hart_halt_req = dm_cmd_dhalted & hart_cmd_req; +assign hart_resume_req = (dm_cmd_run | dm_cmd_drun) & hart_cmd_req; + +// HART Run Control register +//------------------------------------------------------------------------------ + +assign hart_runctrl_clr = (dbg_state_run | dbg_state_drun) + & (dbg_state_next == SCR1_HDU_DBGSTATE_DHALTED); +assign hart_runctrl_upd = dbg_state_dhalted & dfsm_trans_next; + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + hart_runctrl.irq_dsbl <= 1'b0; + hart_runctrl.fetch_src <= SCR1_HDU_FETCH_SRC_NORMAL; + hart_runctrl.pc_advmt_dsbl <= 1'b0; + hart_runctrl.hwbrkpt_dsbl <= 1'b0; + hart_runctrl.redirect <= '0; + end else if(clk_en) begin + if (hart_runctrl_clr) begin + hart_runctrl <= '0; + end else begin + if (hart_runctrl_upd) begin + if (~dm_cmd_drun) begin + // Case : resume to RUN state + hart_runctrl.irq_dsbl <= csr_dcsr_step ? ~csr_dcsr_stepie : 1'b0; + hart_runctrl.fetch_src <= SCR1_HDU_FETCH_SRC_NORMAL; + hart_runctrl.pc_advmt_dsbl <= 1'b0; + hart_runctrl.hwbrkpt_dsbl <= 1'b0; + hart_runctrl.redirect.sstep <= csr_dcsr_step; + hart_runctrl.redirect.ebreak <= csr_dcsr_ebreakm; + end else begin + // Case : resume to DRUN state + hart_runctrl.irq_dsbl <= 1'b1; + hart_runctrl.fetch_src <= SCR1_HDU_FETCH_SRC_PBUF; + hart_runctrl.pc_advmt_dsbl <= 1'b1; + hart_runctrl.hwbrkpt_dsbl <= 1'b1; + hart_runctrl.redirect.sstep <= 1'b0; + hart_runctrl.redirect.ebreak <= 1'b1; + end + end + end + end +end + +// HART Halt Request Time-Out counter +//------------------------------------------------------------------------------ +// HART goes into halt state only if the halt request is present for timeout period +// of time + +assign halt_req_timeout_cnt_en = hdu2exu_dbg_halt2run_o + | (hart_halt_req & ~hdu2exu_dbg_run2halt_o); + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + halt_req_timeout_cnt <= '1; + end else if (halt_req_timeout_cnt_en) begin + halt_req_timeout_cnt <= halt_req_timeout_cnt_next; + end +end + +assign halt_req_timeout_cnt_next = hdu2exu_dbg_halt2run_o ? '1 + : (hart_halt_req & ~hdu2exu_dbg_run2halt_o) ? halt_req_timeout_cnt - 1'b1 + : halt_req_timeout_cnt; + +assign halt_req_timeout_flag = ~|halt_req_timeout_cnt; + +//------------------------------------------------------------------------------ +// HART Status logic +//------------------------------------------------------------------------------ +// + // HART Status logic consists of the following functional units: + // - Debug mode cause decoder + // - Hart halt status cause encoder + // - Hart halt status register +// + +// Debug mode cause decoder +//------------------------------------------------------------------------------ + +assign dmode_cause_sstep = hart_runctrl.redirect.sstep & pipe2hdu_instret_i; +assign dmode_cause_except = dbg_state_drun & pipe2hdu_exu_exc_req_i + & ~pipe2hdu_brkpt_i +`ifdef SCR1_TDU_EN + & ~exu2hdu_ibrkpt_hw_i +`endif // SCR1_TDU_EN + ; +assign dmode_cause_ebreak = hart_runctrl.redirect.ebreak & pipe2hdu_brkpt_i; +`ifdef SCR1_TDU_EN +assign dmode_cause_tmreq = tdu2hdu_dmode_req_i & exu2hdu_ibrkpt_hw_i; +`endif // SCR1_TDU_EN + +assign dmode_cause_any = dmode_cause_sstep | dmode_cause_ebreak | dmode_cause_except + | hart_halt_req +`ifdef SCR1_TDU_EN + | dmode_cause_tmreq +`endif // SCR1_TDU_EN + ; + +// HART halt cause encoder +//------------------------------------------------------------------------------ + +always_comb begin + case (1'b1) +`ifdef SCR1_TDU_EN + dmode_cause_tmreq : hart_haltcause = SCR1_HDU_HALTCAUSE_TMREQ; +`endif // SCR1_TDU_EN + dmode_cause_ebreak : hart_haltcause = SCR1_HDU_HALTCAUSE_EBREAK; + hart_halt_req : hart_haltcause = SCR1_HDU_HALTCAUSE_DMREQ; + dmode_cause_sstep : hart_haltcause = SCR1_HDU_HALTCAUSE_SSTEP; + default : hart_haltcause = SCR1_HDU_HALTCAUSE_NONE; + endcase +end + +// HART halt status register +//------------------------------------------------------------------------------ + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + hart_haltstatus <= '0; + end else if (hart_halt_ack) begin + hart_haltstatus.except <= dmode_cause_except; + hart_haltstatus.cause <= hart_haltcause; + end +end + +assign hart_halt_pnd = (dfsm_trans | dm_dhalt_req) & ~hart_halt_ack; +assign hart_halt_ack = ~hdu2exu_dbg_halted_o + & (halt_req_timeout_flag | (~pipe2hdu_exu_busy_i & dmode_cause_any)); + +//------------------------------------------------------------------------------ +// Program Buffer (PBUF) logic +//------------------------------------------------------------------------------ +// + // Program Buffer allows to execute small programs in debug mode +// + +// To terminate Program Buffer execution exception should be raised. There are 2 +// cases: +// - One of PBUF instructions raise an exception +// - No PBUF instruction raise an exception before the last PBUF instruction has +// been issued. In this case FSM goes into EXCINJECT state and an "Instruction +// fetch access fault" exception is injected + +// PBUF FSM +//------------------------------------------------------------------------------ + +assign ifu_handshake_done = hdu2ifu_pbuf_instr_vd_o & ifu2hdu_pbuf_instr_rdy_i; +assign pbuf_addr_end = (pbuf_addr_ff == (SCR1_HDU_PBUF_ADDR_SPAN-1)); + +assign pbuf_start_fetch = dbg_state_dhalted & (dbg_state_next == SCR1_HDU_DBGSTATE_DRUN); +assign pbuf_exc_inj_req = ifu_handshake_done & pbuf_addr_end; +assign pbuf_exc_inj_end = pipe2hdu_exu_exc_req_i | ifu_handshake_done; + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + pbuf_fsm_curr <= SCR1_HDU_PBUFSTATE_IDLE; + end else if(clk_en) begin + pbuf_fsm_curr <= pbuf_fsm_next; + end +end + +always_comb begin + case (pbuf_fsm_curr) + SCR1_HDU_PBUFSTATE_IDLE: begin + pbuf_fsm_next = pbuf_start_fetch ? SCR1_HDU_PBUFSTATE_FETCH + : SCR1_HDU_PBUFSTATE_IDLE; + end + SCR1_HDU_PBUFSTATE_FETCH: begin + pbuf_fsm_next = pipe2hdu_exu_exc_req_i ? SCR1_HDU_PBUFSTATE_WAIT4END + : pbuf_exc_inj_req ? SCR1_HDU_PBUFSTATE_EXCINJECT + : SCR1_HDU_PBUFSTATE_FETCH; + end + SCR1_HDU_PBUFSTATE_EXCINJECT: begin + pbuf_fsm_next = pbuf_exc_inj_end ? SCR1_HDU_PBUFSTATE_WAIT4END + : SCR1_HDU_PBUFSTATE_EXCINJECT; + end + SCR1_HDU_PBUFSTATE_WAIT4END: begin + pbuf_fsm_next = hdu2exu_dbg_halted_o ? SCR1_HDU_PBUFSTATE_IDLE + : SCR1_HDU_PBUFSTATE_WAIT4END; + end + endcase +end + +assign pbuf_fsm_idle = (pbuf_fsm_curr == SCR1_HDU_PBUFSTATE_IDLE); +assign pbuf_fsm_fetch = (pbuf_fsm_curr == SCR1_HDU_PBUFSTATE_FETCH); +assign pbuf_fsm_excinj = (pbuf_fsm_curr == SCR1_HDU_PBUFSTATE_EXCINJECT); + +// Program Buffer address register +//------------------------------------------------------------------------------ + +assign pbuf_addr_next_vd = pbuf_fsm_fetch & ifu_handshake_done + & ~pipe2hdu_exu_exc_req_i & ~pbuf_addr_end; + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + pbuf_addr_ff <= '0; + end else if(clk_en) begin + pbuf_addr_ff <= pbuf_addr_next; + end +end + +assign pbuf_addr_next = pbuf_fsm_idle ? '0 + : pbuf_addr_next_vd ? pbuf_addr_ff + 1'b1 + : pbuf_addr_ff; + +// Pass instruction from debug program buffer to cpu pipeline with two options: +// - through register, better for frequency +// - through wires, better for area +generate if (HART_PBUF_INSTR_REGOUT_EN) begin + always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + pbuf_instr_wait_latching <= 1'b0; + end else begin + pbuf_instr_wait_latching <= ifu_handshake_done; + end + end +end else begin + assign pbuf_instr_wait_latching = 1'b0; +end endgenerate + +//------------------------------------------------------------------------------ +// Debug CSRs +//------------------------------------------------------------------------------ + +assign csr_upd_on_halt = (dbg_state_reset | dbg_state_run) + & (dbg_state_next == SCR1_HDU_DBGSTATE_DHALTED); + +// CSRs select logic +//------------------------------------------------------------------------------ + +always_comb begin : csr_if_regsel + csr_dcsr_sel = 1'b0; + csr_dpc_sel = 1'b0; + csr_dscratch0_sel = 1'b0; + //csr_dscratch1_sel = 1'b0; + + if (csr2hdu_req_i) begin + case (csr2hdu_addr_i) + SCR1_HDU_DBGCSR_OFFS_DCSR : csr_dcsr_sel = 1'b1; + SCR1_HDU_DBGCSR_OFFS_DPC : csr_dpc_sel = 1'b1; + SCR1_HDU_DBGCSR_OFFS_DSCRATCH0: csr_dscratch0_sel = 1'b1; + default : begin + csr_dcsr_sel = 1'bX; + csr_dpc_sel = 1'bX; + csr_dscratch0_sel = 1'bX; + end + endcase + end +end : csr_if_regsel + +// CSRs read interface +//------------------------------------------------------------------------------ + +assign csr_rd_data = csr_dcsr_out | csr_dpc_out | csr_dscratch0_out; + +// CSRs write interface +//------------------------------------------------------------------------------ + +assign csr_wr = csr2hdu_req_i; + +always_comb begin : csr_if_write + csr_wr_data = '0; + + if (csr2hdu_req_i) begin + case (csr2hdu_cmd_i) + SCR1_CSR_CMD_WRITE : csr_wr_data = csr2hdu_wdata_i; + SCR1_CSR_CMD_SET : csr_wr_data = csr_rd_data | csr2hdu_wdata_i; + SCR1_CSR_CMD_CLEAR : csr_wr_data = csr_rd_data & (~csr2hdu_wdata_i); + default : csr_wr_data = 'X; + endcase + end +end : csr_if_write + +// Debug Control and Status register +//------------------------------------------------------------------------------ +// Setups the HART behaviour in Debug Mode and holds Debug status information + +always_comb begin + csr_dcsr_in = csr_wr_data; + csr_dcsr_wr = csr_wr & csr_dcsr_sel; + + csr_dcsr_out = '0; + if (csr_dcsr_sel) begin + csr_dcsr_out.xdebugver = SCR1_HDU_DEBUGCSR_DCSR_XDEBUGVER; + csr_dcsr_out.ebreakm = csr_dcsr_ebreakm; + csr_dcsr_out.stepie = csr_dcsr_stepie; + csr_dcsr_out.step = csr_dcsr_step; + csr_dcsr_out.prv = 2'b11; + csr_dcsr_out.cause = csr_dcsr_cause; + end +end + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + csr_dcsr_ebreakm <= 1'b0; + csr_dcsr_stepie <= 1'b0; + csr_dcsr_step <= 1'b0; + end else if(clk_en) begin + if (csr_dcsr_wr) begin + csr_dcsr_ebreakm <= csr_dcsr_in.ebreakm; + csr_dcsr_stepie <= csr_dcsr_in.stepie; + csr_dcsr_step <= csr_dcsr_in.step; + end + end +end + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + csr_dcsr_cause <= 1'b0; + end else if(clk_en) begin + if(csr_upd_on_halt) begin + csr_dcsr_cause <= hart_haltstatus.cause; + end + end +end + +// Debug PC register +//------------------------------------------------------------------------------ +// Saves the virtual address of the next instruction to be executed when Debug +// Mode is entered. Could be changed by debugger + +assign csr_dpc_wr = csr_wr & csr_dpc_sel; + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + csr_dpc_ff <= '0; + end else if(clk_en) begin + csr_dpc_ff <= csr_dpc_next; + end +end + +assign csr_dpc_next = csr_upd_on_halt ? pipe2hdu_pc_curr_i + : csr_dpc_wr ? csr_wr_data + : csr_dpc_ff; +assign csr_dpc_out = csr_dpc_sel ? csr_dpc_ff : '0; + +// Debug Scratch 0 register +//------------------------------------------------------------------------------ + +assign csr_dscratch0_resp = (~dm2hdu_dreg_resp_i | dm2hdu_dreg_fail_i) + ? SCR1_CSR_RESP_ER + : SCR1_CSR_RESP_OK; +assign csr_dscratch0_out = csr_dscratch0_sel ? dm2hdu_dreg_rdata_i : '0; + +//------------------------------------------------------------------------------ +// HDU <-> DM interface +//------------------------------------------------------------------------------ + +assign hdu2dm_hart_event_o = dfsm_event; + +// HART status +always_comb begin + hdu2dm_hart_status_o = '0; + hdu2dm_hart_status_o.dbg_state = dbg_state; + hdu2dm_hart_status_o.except = dbg_state_dhalted & hart_haltstatus.except; + hdu2dm_hart_status_o.ebreak = dbg_state_dhalted & (hart_haltstatus.cause == SCR1_HDU_HALTCAUSE_EBREAK); +end + +assign hdu2dm_cmd_rcode_o = dbg_state_reset + ? ~pipe2hdu_rdc_qlfy_i | ~pipe2hdu_init_pc_i | ~dm2hdu_cmd_req_i + : ~pipe2hdu_rdc_qlfy_i | ~dfsm_update; + +always_comb begin + hdu2dm_cmd_resp_o = 1'b0; + + case (dbg_state) + SCR1_HDU_DBGSTATE_RESET: begin + hdu2dm_cmd_resp_o = pipe2hdu_rdc_qlfy_i & pipe2hdu_init_pc_i & dm2hdu_cmd_req_i; + end + + SCR1_HDU_DBGSTATE_RUN: begin + hdu2dm_cmd_resp_o = pipe2hdu_rdc_qlfy_i & dfsm_update & dm2hdu_cmd_req_i; + end + + SCR1_HDU_DBGSTATE_DHALTED: begin + hdu2dm_cmd_resp_o = pipe2hdu_rdc_qlfy_i ? dfsm_update : dm2hdu_cmd_req_i; + end + + SCR1_HDU_DBGSTATE_DRUN: begin + hdu2dm_cmd_resp_o = (~pipe2hdu_rdc_qlfy_i | dfsm_update) & dm2hdu_cmd_req_i; + end + + default: begin + hdu2dm_cmd_resp_o = 'X; + end + endcase +end + +assign hdu2dm_pbuf_addr_o = pbuf_addr_ff; +assign hdu2dm_dreg_req_o = csr_dscratch0_sel; +assign hdu2dm_dreg_wr_o = csr_wr & csr_dscratch0_sel; +assign hdu2dm_dreg_wdata_o = csr_wr_data; + +//------------------------------------------------------------------------------ +// HDU <-> EXU interface +//------------------------------------------------------------------------------ + +assign hdu2exu_dbg_halted_o = (dbg_state_next == SCR1_HDU_DBGSTATE_DHALTED) + | (~pipe2hdu_rdc_qlfy_i & ~dbg_state_run); +assign hdu2exu_dbg_run_start_o = dbg_state_dhalted & pipe2hdu_rdc_qlfy_i & dfsm_update; +assign hdu2exu_dbg_halt2run_o = hdu2exu_dbg_halted_o & hart_resume_req +`ifdef SCR1_CLKCTRL_EN + & clk_pipe_en +`endif // SCR1_CLKCTRL_EN + ; +assign hdu2exu_dbg_run2halt_o = hart_halt_ack; + +assign hdu2exu_pbuf_fetch_o = hart_runctrl.fetch_src; +assign hdu2exu_irq_dsbl_o = hart_runctrl.irq_dsbl; +assign hdu2exu_pc_advmt_dsbl_o = hart_runctrl.pc_advmt_dsbl; +// No change in arch. state if dmode caused by breakpoint +assign hdu2exu_no_commit_o = dmode_cause_ebreak +`ifdef SCR1_TDU_EN + | dmode_cause_tmreq +`endif // SCR1_TDU_EN + ; +assign hdu2exu_dmode_sstep_en_o = hart_runctrl.redirect.sstep; +assign hdu2exu_dbg_new_pc_o = csr_dpc_ff; + +//------------------------------------------------------------------------------ +// HDU <-> IFU interface +//------------------------------------------------------------------------------ + +assign hdu2ifu_pbuf_instr_vd_o = (pbuf_fsm_fetch | pbuf_fsm_excinj) + & ~pbuf_instr_wait_latching; +assign hdu2ifu_pbuf_instr_err_o = pbuf_fsm_excinj; + +generate if (HART_PBUF_INSTR_REGOUT_EN) begin + always_ff @(posedge clk) begin + hdu2ifu_pbuf_instr_o <= dm2hdu_pbuf_instr_i; + end +end else begin + assign hdu2ifu_pbuf_instr_o = dm2hdu_pbuf_instr_i; +end endgenerate + +//------------------------------------------------------------------------------ +// HDU <-> CSR interface +//------------------------------------------------------------------------------ + +assign csr_addr_dscratch0 = (csr2hdu_addr_i == SCR1_HDU_DBGCSR_OFFS_DSCRATCH0); + +assign hdu2csr_resp_o = ~dbg_state_drun ? SCR1_CSR_RESP_ER + : csr_addr_dscratch0 ? csr_dscratch0_resp + : csr2hdu_req_i ? SCR1_CSR_RESP_OK + : SCR1_CSR_RESP_ER; +assign hdu2csr_rdata_o = csr_rd_data; + +`ifdef SCR1_TDU_EN +//------------------------------------------------------------------------------ +// HDU <-> TDU interface +//------------------------------------------------------------------------------ + +assign hdu2tdu_hwbrk_dsbl_o = hart_runctrl.hwbrkpt_dsbl; +`endif // SCR1_TDU_EN + +`ifdef SCR1_TRGT_SIMULATION +//------------------------------------------------------------------------------- +// Assertion +//------------------------------------------------------------------------------- + +SVA_HDU_XCHECK_COMMON : + assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown( {rst_n,clk,clk_en,csr2hdu_req_i,pipe2hdu_rdc_qlfy_i} ) + ) + else $error("HDU Error: common signals are in X state"); + +SVA_HDU_XCHECK_CSR_INTF : + assert property ( + @(negedge clk) disable iff (~rst_n) + csr2hdu_req_i |-> !$isunknown( {csr2hdu_cmd_i,csr2hdu_addr_i,csr2hdu_wdata_i} ) + ) + else $error("HDU Error: CSR i/f is in X state"); + +SVA_HDU_XCHECK_DM_INTF : + assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown( {dm2hdu_cmd_req_i,dm2hdu_cmd_i,dm2hdu_dreg_resp_i, + dm2hdu_dreg_fail_i} ) + ) + else $error("HDU Error: DM i/f is in X state"); + +SVA_HDU_XCHECK_TDU_INTF : + assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown( {tdu2hdu_dmode_req_i,exu2hdu_ibrkpt_hw_i} ) + ) + else $error("HDU Error: TDU i/f is in X state"); + +SVA_HDU_XCHECK_HART_INTF : + assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown( {pipe2hdu_exu_busy_i,pipe2hdu_instret_i,pipe2hdu_init_pc_i,pipe2hdu_exu_exc_req_i,pipe2hdu_brkpt_i, + pipe2hdu_pc_curr_i,ifu2hdu_pbuf_instr_rdy_i} ) + ) + else $error("HDU Error: HART i/f is in X state"); + +`endif // SCR1_TRGT_SIMULATION + +endmodule : scr1_pipe_hdu + +`endif // SCR1_DBG_EN diff --git a/src/rtl/scr1/scr1_pipe_ialu.sv b/src/rtl/scr1/scr1_pipe_ialu.sv new file mode 100644 index 0000000..484fabc --- /dev/null +++ b/src/rtl/scr1/scr1_pipe_ialu.sv @@ -0,0 +1,720 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Integer Arithmetic Logic Unit (IALU) +/// + +//------------------------------------------------------------------------------- + // + // Functionality: + // - Performs addition/subtraction and arithmetic and branch comparisons + // - Performs logical operations (AND(I), OR(I), XOR(I)) + // - Performs address calculation for branch, jump, DMEM load and store and AUIPC + // instructions + // - Performs shift operations + // - Performs MUL/DIV operations + // + // Structure: + // - Main adder + // - Address adder + // - Shift logic + // - MUL/DIV logic + // - Output result multiplexer + // +//------------------------------------------------------------------------------- + +`include "scr1_arch_description.svh" +`include "scr1_riscv_isa_decoding.svh" +`include "scr1_search_ms1.svh" + + +module scr1_pipe_ialu ( +`ifdef SCR1_RVM_EXT + // Common + input logic clk, // IALU clock + input logic rst_n, // IALU reset + input logic exu2ialu_rvm_cmd_vd_i, // MUL/DIV command valid + output logic ialu2exu_rvm_res_rdy_o, // MUL/DIV result ready +`endif // SCR1_RVM_EXT + + // Main adder + input logic [`SCR1_XLEN-1:0] exu2ialu_main_op1_i, // main ALU 1st operand + input logic [`SCR1_XLEN-1:0] exu2ialu_main_op2_i, // main ALU 2nd operand + input type_scr1_ialu_cmd_sel_e exu2ialu_cmd_i, // IALU command + output logic [`SCR1_XLEN-1:0] ialu2exu_main_res_o, // main ALU result + output logic ialu2exu_cmp_res_o, // IALU comparison result + + // Address adder + input logic [`SCR1_XLEN-1:0] exu2ialu_addr_op1_i, // Address adder 1st operand + input logic [`SCR1_XLEN-1:0] exu2ialu_addr_op2_i, // Address adder 2nd operand + output logic [`SCR1_XLEN-1:0] ialu2exu_addr_res_o // Address adder result +); + +//------------------------------------------------------------------------------- +// Local parameters declaration +//------------------------------------------------------------------------------- + +`ifdef SCR1_RVM_EXT + `ifdef SCR1_FAST_MUL +localparam SCR1_MUL_WIDTH = `SCR1_XLEN; +localparam SCR1_MUL_RES_WIDTH = 2 * `SCR1_XLEN; +localparam SCR1_MDU_SUM_WIDTH = `SCR1_XLEN + 1; + `else +localparam SCR1_MUL_STG_NUM = 32; +localparam SCR1_MUL_WIDTH = 32 / SCR1_MUL_STG_NUM; +localparam SCR1_MUL_CNT_INIT = 32'b1 << (`SCR1_XLEN/SCR1_MUL_WIDTH - 2); +localparam SCR1_MDU_SUM_WIDTH = `SCR1_XLEN + SCR1_MUL_WIDTH; + `endif // ~SCR1_FAST_MUL +localparam SCR1_DIV_WIDTH = 1; +localparam SCR1_DIV_CNT_INIT = 32'b1 << (`SCR1_XLEN/SCR1_DIV_WIDTH - 2); +`endif // SCR1_RVM_EXT + +//------------------------------------------------------------------------------- +// Local types declaration +//------------------------------------------------------------------------------- + +typedef struct packed { + logic z; // Zero + logic s; // Sign + logic o; // Overflow + logic c; // Carry +} type_scr1_ialu_flags_s; + + `ifdef SCR1_RVM_EXT +typedef enum logic [1:0] { + SCR1_IALU_MDU_FSM_IDLE, + SCR1_IALU_MDU_FSM_ITER, + SCR1_IALU_MDU_FSM_CORR +} type_scr1_ialu_fsm_state; + +typedef enum logic [1:0] { + SCR1_IALU_MDU_NONE, + SCR1_IALU_MDU_MUL, + SCR1_IALU_MDU_DIV +} type_scr1_ialu_mdu_cmd; + `endif // SCR1_RVM_EXT + +//------------------------------------------------------------------------------- +// Local signals declaration +//------------------------------------------------------------------------------- + +// Main adder signals +logic [`SCR1_XLEN:0] main_sum_res; // Main adder result +type_scr1_ialu_flags_s main_sum_flags; // Main adder flags +logic main_sum_pos_ovflw; // Main adder positive overflow +logic main_sum_neg_ovflw; // Main adder negative overflow +logic main_ops_diff_sgn; // Main adder operands have different signs +logic main_ops_non_zero; // Both main adder operands are NOT 0 + +// Shifter signals +logic ialu_cmd_shft; // IALU command is shift +logic signed [`SCR1_XLEN-1:0] shft_op1; // SHIFT operand 1 +logic [4:0] shft_op2; // SHIFT operand 2 +logic [1:0] shft_cmd; // SHIFT command: 00 - logical left, 10 - logical right, 11 - arithmetical right +logic [`SCR1_XLEN-1:0] shft_res; // SHIFT result + +// MUL/DIV signals +`ifdef SCR1_RVM_EXT +// MUL/DIV FSM control signals +logic mdu_cmd_is_iter; // MDU Command is iterative +logic mdu_iter_req; // Request iterative stage +logic mdu_iter_rdy; // Iteration is ready +logic mdu_corr_req; // DIV/REM(U) correction request +logic div_corr_req; // Correction request for DIV operation +logic rem_corr_req; // Correction request for REM(U) operations + +// MUL/DIV FSM signals +type_scr1_ialu_fsm_state mdu_fsm_ff; // Current FSM state +type_scr1_ialu_fsm_state mdu_fsm_next; // Next FSM state +logic mdu_fsm_idle; // MDU FSM is in IDLE state +`ifdef SCR1_TRGT_SIMULATION +logic mdu_fsm_iter; // MDU FSM is in ITER state +`endif // SCR1_TRGT_SIMULATION +logic mdu_fsm_corr; // MDU FSM is in CORR state + +// MDU command signals +type_scr1_ialu_mdu_cmd mdu_cmd; // MDU command: 00 - NONE, 01 - MUL, 10 - DIV +logic mdu_cmd_mul; // MDU command is MUL(HSU) +logic mdu_cmd_div; // MDU command is DIV(U)/REM(U) +logic [1:0] mul_cmd; // MUL command: 00 - MUL, 01 - MULH, 10 - MULHSU, 11 - MULHU +logic mul_cmd_hi; // High part of MUL result is requested +logic [1:0] div_cmd; // DIV command: 00 - DIV, 01 - DIVU, 10 - REM, 11 - REMU +logic div_cmd_div; // DIV command is DIV +logic div_cmd_rem; // DIV command is REM(U) + +// Multiplier signals +logic mul_op1_is_sgn; // First MUL operand is signed +logic mul_op2_is_sgn; // Second MUL operand is signed +logic mul_op1_sgn; // First MUL operand is negative +logic mul_op2_sgn; // Second MUL operand is negative +logic signed [`SCR1_XLEN:0] mul_op1; // MUL operand 1 +logic signed [SCR1_MUL_WIDTH:0] mul_op2; // MUL operand 1 + `ifdef SCR1_FAST_MUL +logic signed [SCR1_MUL_RES_WIDTH-1:0] mul_res; // MUL result + `else // ~SCR1_FAST_MUL +logic signed [SCR1_MDU_SUM_WIDTH:0] mul_part_prod; +logic [`SCR1_XLEN-1:0] mul_res_hi; +logic [`SCR1_XLEN-1:0] mul_res_lo; + `endif // ~SCR1_FAST_MUL + +// Divisor signals +logic div_ops_are_sgn; +logic div_op1_is_neg; +logic div_op2_is_neg; +logic div_res_rem_c; +logic [`SCR1_XLEN-1:0] div_res_rem; +logic [`SCR1_XLEN-1:0] div_res_quo; +logic div_quo_bit; +logic div_dvdnd_lo_upd; +logic [`SCR1_XLEN-1:0] div_dvdnd_lo_ff; +logic [`SCR1_XLEN-1:0] div_dvdnd_lo_next; + +// MDU adder signals +logic mdu_sum_sub; // MDU adder operation: 0 - add, 1 - sub +logic signed [SCR1_MDU_SUM_WIDTH-1:0] mdu_sum_op1; // MDU adder operand 1 +logic signed [SCR1_MDU_SUM_WIDTH-1:0] mdu_sum_op2; // MDU adder operand 2 +logic signed [SCR1_MDU_SUM_WIDTH-1:0] mdu_sum_res; // MDU adder result + +// MDU iteration counter signals +logic mdu_iter_cnt_en; +logic [`SCR1_XLEN-1:0] mdu_iter_cnt; +logic [`SCR1_XLEN-1:0] mdu_iter_cnt_next; + +// Intermediate results registers +logic mdu_res_upd; +logic mdu_res_c_ff; +logic mdu_res_c_next; +logic [`SCR1_XLEN-1:0] mdu_res_hi_ff; +logic [`SCR1_XLEN-1:0] mdu_res_hi_next; +logic [`SCR1_XLEN-1:0] mdu_res_lo_ff; +logic [`SCR1_XLEN-1:0] mdu_res_lo_next; +`endif // SCR1_RVM_EXT + +//------------------------------------------------------------------------------- +// Main adder +//------------------------------------------------------------------------------- +// + // Main adder is used for the following types of operations: + // - Addition/subtraction (ADD/ADDI/SUB) + // - Branch comparisons (BEQ/BNE/BLT(U)/BGE(U)) + // - Arithmetic comparisons (SLT(U)/SLTI(U)) +// + +// Carry out (MSB of main_sum_res) is evaluated correctly because the result +// width equals to the maximum width of both the right-hand and left-hand side variables +always_comb begin + main_sum_res = (exu2ialu_cmd_i != SCR1_IALU_CMD_ADD) + ? ({1'b0, exu2ialu_main_op1_i} - {1'b0, exu2ialu_main_op2_i}) // Subtraction and comparison + : ({1'b0, exu2ialu_main_op1_i} + {1'b0, exu2ialu_main_op2_i}); // Addition + + main_sum_pos_ovflw = ~exu2ialu_main_op1_i[`SCR1_XLEN-1] + & exu2ialu_main_op2_i[`SCR1_XLEN-1] + & main_sum_res[`SCR1_XLEN-1]; + main_sum_neg_ovflw = exu2ialu_main_op1_i[`SCR1_XLEN-1] + & ~exu2ialu_main_op2_i[`SCR1_XLEN-1] + & ~main_sum_res[`SCR1_XLEN-1]; + + // FLAGS1 - flags for comparison (result of subtraction) + main_sum_flags.c = main_sum_res[`SCR1_XLEN]; + main_sum_flags.z = ~|main_sum_res[`SCR1_XLEN-1:0]; + main_sum_flags.s = main_sum_res[`SCR1_XLEN-1]; + main_sum_flags.o = main_sum_pos_ovflw | main_sum_neg_ovflw; +end + +//------------------------------------------------------------------------------- +// Address adder +//------------------------------------------------------------------------------- +// + // Additional adder is used for the following types of operations: + // - PC-based address calculation (AUIPC) + // - IMEM branch address calculation (BEQ/BNE/BLT(U)/BGE(U)) + // - IMEM jump address calculation (JAL/JALR) + // - DMEM load address calculation (LB(U)/LH(U)/LW) + // - DMEM store address calculation (SB/SH/SW) +// + +assign ialu2exu_addr_res_o = exu2ialu_addr_op1_i + exu2ialu_addr_op2_i; + +//------------------------------------------------------------------------------- +// Shift logic +//------------------------------------------------------------------------------- + // + // Shift logic supports the following types of shift operations: + // - Logical left shift (SLLI/SLL) + // - Logical right shift (SRLI/SRL) + // - Arithmetic right shift (SRAI/SRA) +// + +assign ialu_cmd_shft = (exu2ialu_cmd_i == SCR1_IALU_CMD_SLL) + | (exu2ialu_cmd_i == SCR1_IALU_CMD_SRL) + | (exu2ialu_cmd_i == SCR1_IALU_CMD_SRA); +assign shft_cmd = ialu_cmd_shft + ? {(exu2ialu_cmd_i != SCR1_IALU_CMD_SLL), + (exu2ialu_cmd_i == SCR1_IALU_CMD_SRA)} + : 2'b00; + +always_comb begin + shft_op1 = exu2ialu_main_op1_i; + shft_op2 = exu2ialu_main_op2_i[4:0]; + case (shft_cmd) + 2'b10 : shft_res = shft_op1 >> shft_op2; + 2'b11 : shft_res = shft_op1 >>> shft_op2; + default : shft_res = shft_op1 << shft_op2; + endcase +end + +`ifdef SCR1_RVM_EXT +//------------------------------------------------------------------------------- +// MUL/DIV logic +//------------------------------------------------------------------------------- +// + // MUL/DIV instructions use the following functional units: + // - MUL/DIV FSM control logic, including iteration number counter + // - MUL/DIV FSM + // - MUL logic + // - DIV logic + // - MDU adder to produce an intermediate result + // - 2 registers to save the intermediate result (shared between MUL and DIV + // operations) +// + +//------------------------------------------------------------------------------- +// MUL/DIV FSM Control logic +//------------------------------------------------------------------------------- + +assign mdu_cmd_div = (exu2ialu_cmd_i == SCR1_IALU_CMD_DIV) + | (exu2ialu_cmd_i == SCR1_IALU_CMD_DIVU) + | (exu2ialu_cmd_i == SCR1_IALU_CMD_REM) + | (exu2ialu_cmd_i == SCR1_IALU_CMD_REMU); +assign mdu_cmd_mul = (exu2ialu_cmd_i == SCR1_IALU_CMD_MUL) + | (exu2ialu_cmd_i == SCR1_IALU_CMD_MULH) + | (exu2ialu_cmd_i == SCR1_IALU_CMD_MULHU) + | (exu2ialu_cmd_i == SCR1_IALU_CMD_MULHSU); + +assign mdu_cmd = mdu_cmd_div ? SCR1_IALU_MDU_DIV + : mdu_cmd_mul ? SCR1_IALU_MDU_MUL + : SCR1_IALU_MDU_NONE; + +assign main_ops_non_zero = |exu2ialu_main_op1_i & |exu2ialu_main_op2_i; +assign main_ops_diff_sgn = exu2ialu_main_op1_i[`SCR1_XLEN-1] + ^ exu2ialu_main_op2_i[`SCR1_XLEN-1]; + + `ifdef SCR1_FAST_MUL + assign mdu_cmd_is_iter = mdu_cmd_div; + `else // ~SCR1_FAST_MUL + assign mdu_cmd_is_iter = mdu_cmd_mul | mdu_cmd_div; + `endif // ~SCR1_FAST_MUL + +assign mdu_iter_req = mdu_cmd_is_iter ? (main_ops_non_zero & mdu_fsm_idle) : 1'b0; +assign mdu_iter_rdy = mdu_iter_cnt[0]; + +assign div_cmd_div = (div_cmd == 2'b00); +assign div_cmd_rem = div_cmd[1]; + +// Correction request signals +assign div_corr_req = div_cmd_div & main_ops_diff_sgn; +assign rem_corr_req = div_cmd_rem & |div_res_rem & (div_op1_is_neg ^ div_res_rem_c); +assign mdu_corr_req = mdu_cmd_div & (div_corr_req | rem_corr_req); + +// MDU iteration counter +//------------------------------------------------------------------------------ + +assign mdu_iter_cnt_en = exu2ialu_rvm_cmd_vd_i & ~ialu2exu_rvm_res_rdy_o; + +always_ff @(posedge clk) begin + if (mdu_iter_cnt_en) begin + mdu_iter_cnt <= mdu_iter_cnt_next; + end +end + +assign mdu_iter_cnt_next = ~mdu_fsm_idle ? mdu_iter_cnt >> 1 + : mdu_cmd_div ? SCR1_DIV_CNT_INIT + `ifndef SCR1_FAST_MUL + : mdu_cmd_mul ? SCR1_MUL_CNT_INIT + `endif // ~SCR1_FAST_MUL + : mdu_iter_cnt; + +//------------------------------------------------------------------------------- +// MUL/DIV FSM +//------------------------------------------------------------------------------- + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + mdu_fsm_ff <= SCR1_IALU_MDU_FSM_IDLE; + end else begin + mdu_fsm_ff <= mdu_fsm_next; + end +end + +always_comb begin + mdu_fsm_next = SCR1_IALU_MDU_FSM_IDLE; + + if (exu2ialu_rvm_cmd_vd_i) begin + case (mdu_fsm_ff) + SCR1_IALU_MDU_FSM_IDLE : begin + mdu_fsm_next = mdu_iter_req ? SCR1_IALU_MDU_FSM_ITER + : SCR1_IALU_MDU_FSM_IDLE; + end + SCR1_IALU_MDU_FSM_ITER : begin + mdu_fsm_next = ~mdu_iter_rdy ? SCR1_IALU_MDU_FSM_ITER + : mdu_corr_req ? SCR1_IALU_MDU_FSM_CORR + : SCR1_IALU_MDU_FSM_IDLE; + end + SCR1_IALU_MDU_FSM_CORR : begin + mdu_fsm_next = SCR1_IALU_MDU_FSM_IDLE; + end + endcase + end +end + +assign mdu_fsm_idle = (mdu_fsm_ff == SCR1_IALU_MDU_FSM_IDLE); +`ifdef SCR1_TRGT_SIMULATION +assign mdu_fsm_iter = (mdu_fsm_ff == SCR1_IALU_MDU_FSM_ITER); +`endif // SCR1_TRGT_SIMULATION +assign mdu_fsm_corr = (mdu_fsm_ff == SCR1_IALU_MDU_FSM_CORR); + +//------------------------------------------------------------------------------- +// Multiplier logic +//------------------------------------------------------------------------------- +// + // Multiplication has 2 options: fast (1 cycle) and Radix-2 (32 cycles) multiplication. + // + // 1. Fast multiplication uses the straightforward approach when 2 operands are + // multiplied in one cycle + // + // 2. Radix-2 multiplication uses 2 registers (high and low part of multiplication) + // + // Radix-2 algorithm: + // 1. Initialize registers + // 2. Create a partial product by multiplying multiplicand by the LSB of multiplier + // 3. Add the partial product to the previous (intermediate) value of multiplication + // result (stored into high and low parts of multiplication result register) + // 4. Shift the low part of multiplication result register right + // 4. Store the addition result into the high part of multiplication result register + // 6. If iteration is not ready, go to step 2. Otherwise multiplication is done + // +// + +assign mul_cmd = {((exu2ialu_cmd_i == SCR1_IALU_CMD_MULHU) | (exu2ialu_cmd_i == SCR1_IALU_CMD_MULHSU)), + ((exu2ialu_cmd_i == SCR1_IALU_CMD_MULHU) | (exu2ialu_cmd_i == SCR1_IALU_CMD_MULH))}; + +assign mul_cmd_hi = |mul_cmd; +assign mul_op1_is_sgn = ~&mul_cmd; +assign mul_op2_is_sgn = ~mul_cmd[1]; +assign mul_op1_sgn = mul_op1_is_sgn & exu2ialu_main_op1_i[`SCR1_XLEN-1]; +assign mul_op2_sgn = mul_op2_is_sgn & exu2ialu_main_op2_i[`SCR1_XLEN-1]; + +`ifdef SCR1_FAST_MUL +assign mul_op1 = mdu_cmd_mul ? $signed({mul_op1_sgn, exu2ialu_main_op1_i}) : '0; +assign mul_op2 = mdu_cmd_mul ? $signed({mul_op2_sgn, exu2ialu_main_op2_i}) : '0; +assign mul_res = mdu_cmd_mul ? mul_op1 * mul_op2 : $signed('0); +`else // ~SCR1_FAST_MUL +assign mul_op1 = mdu_cmd_mul ? $signed({mul_op1_sgn, exu2ialu_main_op1_i}) : '0; +assign mul_op2 = ~mdu_cmd_mul ? '0 + : mdu_fsm_idle ? $signed({1'b0, exu2ialu_main_op2_i[SCR1_MUL_WIDTH-1:0]}) + : $signed({(mdu_iter_cnt[0] & mul_op2_is_sgn & mdu_res_lo_ff[SCR1_MUL_WIDTH-1]), + mdu_res_lo_ff[SCR1_MUL_WIDTH-1:0]}); + +assign mul_part_prod = mdu_cmd_mul ? mul_op1 * mul_op2 : $signed('0); +assign {mul_res_hi, mul_res_lo} = ~mdu_cmd_mul ? '0 + : mdu_fsm_idle ? ({mdu_sum_res, exu2ialu_main_op2_i[`SCR1_XLEN-1:SCR1_MUL_WIDTH]}) + : ({mdu_sum_res, mdu_res_lo_ff[`SCR1_XLEN-1:SCR1_MUL_WIDTH]}); +`endif // ~SCR1_FAST_MUL + +//------------------------------------------------------------------------------- +// Divider logic +//------------------------------------------------------------------------------- +// + // Division uses a non-restoring algorithm. 3 registers are used: + // - Remainder register + // - Quotient register + // - Dividend low part register (for corner case quotient bit calculation) + // + // Algorithm: + // 1. Initialize registers + // 2. Shift remainder and dividend low part registers left + // 3. Compare remainder register with the divisor (taking previous quotient bit + // and operands signs into account) and calculate quotient bit based on the + // comparison results + // 4. Shift quotient register left, append quotient bit to the quotient register + // 5. If iteration is not ready, go to step 2. Otherwise go to step 6 + // 6. Do correction if necessary, otherwise division is done + // + // Quotient bit calculation has a corner case: + // When dividend is negative result carry bit check takes into account only + // the case of remainder register been greater than divisor. To handle + // equality case we should check if both the comparison result and the + // lower part of dividend are zero +// + +assign div_cmd = {((exu2ialu_cmd_i == SCR1_IALU_CMD_REM) | (exu2ialu_cmd_i == SCR1_IALU_CMD_REMU)), + ((exu2ialu_cmd_i == SCR1_IALU_CMD_REMU) | (exu2ialu_cmd_i == SCR1_IALU_CMD_DIVU))}; + +assign div_ops_are_sgn = ~div_cmd[0]; +assign div_op1_is_neg = div_ops_are_sgn & exu2ialu_main_op1_i[`SCR1_XLEN-1]; +assign div_op2_is_neg = div_ops_are_sgn & exu2ialu_main_op2_i[`SCR1_XLEN-1]; + +always_comb begin + div_res_rem_c = '0; + div_res_rem = '0; + div_res_quo = '0; + div_quo_bit = 1'b0; + if (mdu_cmd_div & ~mdu_fsm_corr) begin + div_res_rem_c = mdu_sum_res[SCR1_MDU_SUM_WIDTH-1]; + div_res_rem = mdu_sum_res[SCR1_MDU_SUM_WIDTH-2:0]; + div_quo_bit = ~(div_op1_is_neg ^ div_res_rem_c) + | (div_op1_is_neg & ({mdu_sum_res, div_dvdnd_lo_next} == '0)); + div_res_quo = mdu_fsm_idle + ? {'0, div_quo_bit} + : {mdu_res_lo_ff[`SCR1_XLEN-2:0], div_quo_bit}; + end +end + +// Dividend low part register +//------------------------------------------------------------------------------ + +assign div_dvdnd_lo_upd = exu2ialu_rvm_cmd_vd_i & ~ialu2exu_rvm_res_rdy_o; + +always_ff @(posedge clk) begin + if (div_dvdnd_lo_upd) begin + div_dvdnd_lo_ff <= div_dvdnd_lo_next; + end +end + +assign div_dvdnd_lo_next = (~mdu_cmd_div | mdu_fsm_corr) ? '0 + : mdu_fsm_idle ? exu2ialu_main_op1_i << 1 + : div_dvdnd_lo_ff << 1; + +//------------------------------------------------------------------------------- +// MDU adder +//------------------------------------------------------------------------------- + +always_comb begin + mdu_sum_sub = 1'b0; + mdu_sum_op1 = '0; + mdu_sum_op2 = '0; + case (mdu_cmd) + SCR1_IALU_MDU_DIV : begin + logic sgn; + logic inv; + + sgn = mdu_fsm_corr ? div_op1_is_neg ^ mdu_res_c_ff + : mdu_fsm_idle ? 1'b0 + : ~mdu_res_lo_ff[0]; + inv = div_ops_are_sgn & main_ops_diff_sgn; + mdu_sum_sub = ~inv ^ sgn; + mdu_sum_op1 = mdu_fsm_corr ? $signed({1'b0, mdu_res_hi_ff}) + : mdu_fsm_idle ? $signed({div_op1_is_neg, exu2ialu_main_op1_i[`SCR1_XLEN-1]}) + : $signed({mdu_res_hi_ff, div_dvdnd_lo_ff[`SCR1_XLEN-1]}); + mdu_sum_op2 = $signed({div_op2_is_neg, exu2ialu_main_op2_i}); + end +`ifndef SCR1_FAST_MUL + SCR1_IALU_MDU_MUL : begin + mdu_sum_op1 = mdu_fsm_idle + ? '0 + : $signed({(mul_op1_is_sgn & mdu_res_hi_ff[`SCR1_XLEN-1]), mdu_res_hi_ff}); + mdu_sum_op2 = mul_part_prod; + end +`endif // SCR1_FAST_MUL + default : begin end + endcase + mdu_sum_res = mdu_sum_sub + ? (mdu_sum_op1 - mdu_sum_op2) + : (mdu_sum_op1 + mdu_sum_op2); +end + +//------------------------------------------------------------------------------- +// MUL/DIV intermediate results registers +//------------------------------------------------------------------------------- + +assign mdu_res_upd = exu2ialu_rvm_cmd_vd_i & ~ialu2exu_rvm_res_rdy_o; + +always_ff @(posedge clk) begin + if (mdu_res_upd) begin + mdu_res_c_ff <= mdu_res_c_next; + mdu_res_hi_ff <= mdu_res_hi_next; + mdu_res_lo_ff <= mdu_res_lo_next; + end +end + +assign mdu_res_c_next = mdu_cmd_div ? div_res_rem_c : mdu_res_c_ff; +assign mdu_res_hi_next = mdu_cmd_div ? div_res_rem + `ifndef SCR1_FAST_MUL + : mdu_cmd_mul ? mul_res_hi + `endif // SCR1_FAST_MUL + : mdu_res_hi_ff; +assign mdu_res_lo_next = mdu_cmd_div ? div_res_quo + `ifndef SCR1_FAST_MUL + : mdu_cmd_mul ? mul_res_lo + `endif // SCR1_FAST_MUL + : mdu_res_lo_ff; +`endif // SCR1_RVM_EXT + +//------------------------------------------------------------------------------- +// Operation result forming +//------------------------------------------------------------------------------- + +always_comb begin + ialu2exu_main_res_o = '0; + ialu2exu_cmp_res_o = 1'b0; +`ifdef SCR1_RVM_EXT + ialu2exu_rvm_res_rdy_o = 1'b1; +`endif // SCR1_RVM_EXT + + case (exu2ialu_cmd_i) + SCR1_IALU_CMD_AND : begin + ialu2exu_main_res_o = exu2ialu_main_op1_i & exu2ialu_main_op2_i; + end + SCR1_IALU_CMD_OR : begin + ialu2exu_main_res_o = exu2ialu_main_op1_i | exu2ialu_main_op2_i; + end + SCR1_IALU_CMD_XOR : begin + ialu2exu_main_res_o = exu2ialu_main_op1_i ^ exu2ialu_main_op2_i; + end + SCR1_IALU_CMD_ADD : begin + ialu2exu_main_res_o = main_sum_res[`SCR1_XLEN-1:0]; + end + SCR1_IALU_CMD_SUB : begin + ialu2exu_main_res_o = main_sum_res[`SCR1_XLEN-1:0]; + end + SCR1_IALU_CMD_SUB_LT : begin + ialu2exu_main_res_o = `SCR1_XLEN'(main_sum_flags.s ^ main_sum_flags.o); + ialu2exu_cmp_res_o = main_sum_flags.s ^ main_sum_flags.o; + end + SCR1_IALU_CMD_SUB_LTU : begin + ialu2exu_main_res_o = `SCR1_XLEN'(main_sum_flags.c); + ialu2exu_cmp_res_o = main_sum_flags.c; + end + SCR1_IALU_CMD_SUB_EQ : begin + ialu2exu_main_res_o = `SCR1_XLEN'(main_sum_flags.z); + ialu2exu_cmp_res_o = main_sum_flags.z; + end + SCR1_IALU_CMD_SUB_NE : begin + ialu2exu_main_res_o = `SCR1_XLEN'(~main_sum_flags.z); + ialu2exu_cmp_res_o = ~main_sum_flags.z; + end + SCR1_IALU_CMD_SUB_GE : begin + ialu2exu_main_res_o = `SCR1_XLEN'(~(main_sum_flags.s ^ main_sum_flags.o)); + ialu2exu_cmp_res_o = ~(main_sum_flags.s ^ main_sum_flags.o); + end + SCR1_IALU_CMD_SUB_GEU : begin + ialu2exu_main_res_o = `SCR1_XLEN'(~main_sum_flags.c); + ialu2exu_cmp_res_o = ~main_sum_flags.c; + end + SCR1_IALU_CMD_SLL, + SCR1_IALU_CMD_SRL, + SCR1_IALU_CMD_SRA: begin + ialu2exu_main_res_o = shft_res; + end +`ifdef SCR1_RVM_EXT + SCR1_IALU_CMD_MUL, + SCR1_IALU_CMD_MULHU, + SCR1_IALU_CMD_MULHSU, + SCR1_IALU_CMD_MULH : begin + `ifdef SCR1_FAST_MUL + ialu2exu_main_res_o = mul_cmd_hi + ? mul_res[SCR1_MUL_RES_WIDTH-1:`SCR1_XLEN] + : mul_res[`SCR1_XLEN-1:0]; + `else // ~SCR1_FAST_MUL + case (mdu_fsm_ff) + SCR1_IALU_MDU_FSM_IDLE : begin + ialu2exu_main_res_o = '0; + ialu2exu_rvm_res_rdy_o = ~mdu_iter_req; + end + SCR1_IALU_MDU_FSM_ITER : begin + ialu2exu_main_res_o = mul_cmd_hi ? mul_res_hi : mul_res_lo; + ialu2exu_rvm_res_rdy_o = mdu_iter_rdy; + end + endcase + `endif // ~SCR1_FAST_MUL + end + SCR1_IALU_CMD_DIV, + SCR1_IALU_CMD_DIVU, + SCR1_IALU_CMD_REM, + SCR1_IALU_CMD_REMU : begin + case (mdu_fsm_ff) + SCR1_IALU_MDU_FSM_IDLE : begin + ialu2exu_main_res_o = (|exu2ialu_main_op2_i | div_cmd_rem) + ? exu2ialu_main_op1_i + : '1; + ialu2exu_rvm_res_rdy_o = ~mdu_iter_req; + end + SCR1_IALU_MDU_FSM_ITER : begin + ialu2exu_main_res_o = div_cmd_rem ? div_res_rem : div_res_quo; + ialu2exu_rvm_res_rdy_o = mdu_iter_rdy & ~mdu_corr_req; + end + SCR1_IALU_MDU_FSM_CORR : begin + ialu2exu_main_res_o = div_cmd_rem + ? mdu_sum_res[`SCR1_XLEN-1:0] + : -mdu_res_lo_ff[`SCR1_XLEN-1:0]; + ialu2exu_rvm_res_rdy_o = 1'b1; + end + endcase + end +`endif // SCR1_RVM_EXT + default : begin end + endcase +end + + +`ifdef SCR1_TRGT_SIMULATION +//------------------------------------------------------------------------------- +// Assertion +//------------------------------------------------------------------------------- + +`ifdef SCR1_RVM_EXT + +// X checks + +SCR1_SVA_IALU_XCHECK : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown({exu2ialu_rvm_cmd_vd_i, mdu_fsm_ff}) + ) else $error("IALU Error: unknown values"); + +SCR1_SVA_IALU_XCHECK_QUEUE : assert property ( + @(negedge clk) disable iff (~rst_n) + exu2ialu_rvm_cmd_vd_i |-> + !$isunknown({exu2ialu_main_op1_i, exu2ialu_main_op2_i, exu2ialu_cmd_i}) + ) else $error("IALU Error: unknown values in queue"); + +// Behavior checks + +SCR1_SVA_IALU_ILL_STATE : assert property ( + @(negedge clk) disable iff (~rst_n) + $onehot0({~exu2ialu_rvm_cmd_vd_i, mdu_fsm_iter, mdu_fsm_corr}) + ) else $error("IALU Error: illegal state"); + +SCR1_SVA_IALU_JUMP_FROM_IDLE : assert property ( + @(negedge clk) disable iff (~rst_n) + (mdu_fsm_idle & (~exu2ialu_rvm_cmd_vd_i | ~mdu_iter_req)) |=> mdu_fsm_idle + ) else $error("EXU Error: illegal jump from IDLE state"); + +SCR1_SVA_IALU_IDLE_TO_ITER : assert property ( + @(negedge clk) disable iff (~rst_n) + (mdu_fsm_idle & exu2ialu_rvm_cmd_vd_i & mdu_iter_req) |=> mdu_fsm_iter + ) else $error("EXU Error: illegal change state form IDLE to ITER"); + +SCR1_SVA_IALU_JUMP_FROM_ITER : assert property ( + @(negedge clk) disable iff (~rst_n) + (mdu_fsm_iter & ~mdu_iter_rdy) |=> mdu_fsm_iter + ) else $error("EXU Error: illegal jump from ITER state"); + +SCR1_SVA_IALU_ITER_TO_IDLE : assert property ( + @(negedge clk) disable iff (~rst_n) + (mdu_fsm_iter & mdu_iter_rdy & ~mdu_corr_req) |=> mdu_fsm_idle + ) else $error("EXU Error: illegal state change ITER to IDLE"); + +SCR1_SVA_IALU_ITER_TO_CORR : assert property ( + @(negedge clk) disable iff (~rst_n) + (mdu_fsm_iter & mdu_iter_rdy & mdu_corr_req) |=> mdu_fsm_corr + ) else $error("EXU Error: illegal state change ITER to CORR"); + +SCR1_SVA_IALU_CORR_TO_IDLE : assert property ( + @(negedge clk) disable iff (~rst_n) + mdu_fsm_corr |=> mdu_fsm_idle + ) else $error("EXU Error: illegal state stay in CORR"); + +`endif // SCR1_RVM_EXT + +`endif // SCR1_TRGT_SIMULATION + +endmodule : scr1_pipe_ialu diff --git a/src/rtl/scr1/scr1_pipe_idu.sv b/src/rtl/scr1/scr1_pipe_idu.sv new file mode 100644 index 0000000..0e8c908 --- /dev/null +++ b/src/rtl/scr1/scr1_pipe_idu.sv @@ -0,0 +1,940 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Instruction Decoder Unit (IDU) +/// + +//------------------------------------------------------------------------------ + // + // Functionality: + // - Decodes the instruction and creates the appropriate control signals for EXU + // + // Structure: + // - Instruction decoder + // - IDU <-> IFU i/f + // - IDU <-> EXU i/f + // +//------------------------------------------------------------------------------ + +`include "scr1_memif.svh" +`include "scr1_arch_types.svh" +`include "scr1_riscv_isa_decoding.svh" +`include "scr1_arch_description.svh" + +module scr1_pipe_idu +( +`ifdef SCR1_TRGT_SIMULATION + input logic rst_n, // IDU reset + input logic clk, // IDU clock +`endif // SCR1_TRGT_SIMULATION + + // IFU <-> IDU interface + output logic idu2ifu_rdy_o, // IDU ready for new data + input logic [`SCR1_IMEM_DWIDTH-1:0] ifu2idu_instr_i, // IFU instruction + input logic ifu2idu_imem_err_i, // Instruction access fault exception + input logic ifu2idu_err_rvi_hi_i, // 1 - imem fault when trying to fetch second half of an unaligned RVI instruction + input logic ifu2idu_vd_i, // IFU request + + // IDU <-> EXU interface + output logic idu2exu_req_o, // IDU request + output type_scr1_exu_cmd_s idu2exu_cmd_o, // IDU command + output logic idu2exu_use_rs1_o, // Instruction uses rs1 + output logic idu2exu_use_rs2_o, // Instruction uses rs2 +`ifndef SCR1_NO_EXE_STAGE + output logic idu2exu_use_rd_o, // Instruction uses rd + output logic idu2exu_use_imm_o, // Instruction uses immediate +`endif // SCR1_NO_EXE_STAGE + input logic exu2idu_rdy_i // EXU ready for new data +); + +//------------------------------------------------------------------------------- +// Local parameters declaration +//------------------------------------------------------------------------------- + +localparam [SCR1_GPR_FIELD_WIDTH-1:0] SCR1_MPRF_ZERO_ADDR = 5'd0; +localparam [SCR1_GPR_FIELD_WIDTH-1:0] SCR1_MPRF_RA_ADDR = 5'd1; +localparam [SCR1_GPR_FIELD_WIDTH-1:0] SCR1_MPRF_SP_ADDR = 5'd2; + +//------------------------------------------------------------------------------- +// Local signals declaration +//------------------------------------------------------------------------------- + +logic [`SCR1_IMEM_DWIDTH-1:0] instr; +type_scr1_instr_type_e instr_type; +type_scr1_rvi_opcode_e rvi_opcode; +logic rvi_illegal; +logic [2:0] funct3; +logic [6:0] funct7; +logic [11:0] funct12; +logic [4:0] shamt; +`ifdef SCR1_RVC_EXT +logic rvc_illegal; +`endif // SCR1_RVC_EXT +`ifdef SCR1_RVE_EXT +logic rve_illegal; +`endif // SCR1_RVE_EXT + +//------------------------------------------------------------------------------- +// Instruction decoding +//------------------------------------------------------------------------------- + +assign idu2ifu_rdy_o = exu2idu_rdy_i; +assign idu2exu_req_o = ifu2idu_vd_i; +assign instr = ifu2idu_instr_i; + +// RVI / RVC +assign instr_type = type_scr1_instr_type_e'(instr[1:0]); + +// RVI / RVC fields +assign rvi_opcode = type_scr1_rvi_opcode_e'(instr[6:2]); // RVI +assign funct3 = (instr_type == SCR1_INSTR_RVI) ? instr[14:12] : instr[15:13]; // RVI / RVC +assign funct7 = instr[31:25]; // RVI +assign funct12 = instr[31:20]; // RVI (SYSTEM) +assign shamt = instr[24:20]; // RVI + +// RV32I(MC) decode +always_comb begin + // Defaults + idu2exu_cmd_o.instr_rvc = 1'b0; + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG; + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_NONE; + idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM; + idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_NONE; + idu2exu_cmd_o.csr_op = SCR1_CSR_OP_REG; + idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_NONE; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_NONE; + idu2exu_cmd_o.jump_req = 1'b0; + idu2exu_cmd_o.branch_req = 1'b0; + idu2exu_cmd_o.mret_req = 1'b0; + idu2exu_cmd_o.fencei_req = 1'b0; + idu2exu_cmd_o.wfi_req = 1'b0; + idu2exu_cmd_o.rs1_addr = '0; + idu2exu_cmd_o.rs2_addr = '0; + idu2exu_cmd_o.rd_addr = '0; + idu2exu_cmd_o.imm = '0; + idu2exu_cmd_o.exc_req = 1'b0; + idu2exu_cmd_o.exc_code = SCR1_EXC_CODE_INSTR_MISALIGN; + + // Clock gating + idu2exu_use_rs1_o = 1'b0; + idu2exu_use_rs2_o = 1'b0; +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b0; + idu2exu_use_imm_o = 1'b0; +`endif // SCR1_NO_EXE_STAGE + + rvi_illegal = 1'b0; +`ifdef SCR1_RVE_EXT + rve_illegal = 1'b0; +`endif // SCR1_RVE_EXT +`ifdef SCR1_RVC_EXT + rvc_illegal = 1'b0; +`endif // SCR1_RVC_EXT + + // Check for IMEM access fault + if (ifu2idu_imem_err_i) begin + idu2exu_cmd_o.exc_req = 1'b1; + idu2exu_cmd_o.exc_code = SCR1_EXC_CODE_INSTR_ACCESS_FAULT; + idu2exu_cmd_o.instr_rvc = ifu2idu_err_rvi_hi_i; + end else begin // no imem fault + case (instr_type) + SCR1_INSTR_RVI : begin + idu2exu_cmd_o.rs1_addr = instr[19:15]; + idu2exu_cmd_o.rs2_addr = instr[24:20]; + idu2exu_cmd_o.rd_addr = instr[11:7]; + case (rvi_opcode) + SCR1_OPCODE_AUIPC : begin +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b1; + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_SUM2; + idu2exu_cmd_o.imm = {instr[31:12], 12'b0}; +`ifdef SCR1_RVE_EXT + if (instr[11]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end // SCR1_OPCODE_AUIPC + + SCR1_OPCODE_LUI : begin +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b1; + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IMM; + idu2exu_cmd_o.imm = {instr[31:12], 12'b0}; +`ifdef SCR1_RVE_EXT + if (instr[11]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end // SCR1_OPCODE_LUI + + SCR1_OPCODE_JAL : begin +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b1; + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_INC_PC; + idu2exu_cmd_o.jump_req = 1'b1; + idu2exu_cmd_o.imm = {{12{instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0}; +`ifdef SCR1_RVE_EXT + if (instr[11]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end // SCR1_OPCODE_JAL + + SCR1_OPCODE_LOAD : begin + idu2exu_use_rs1_o = 1'b1; +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b1; + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_LSU; + idu2exu_cmd_o.imm = {{21{instr[31]}}, instr[30:20]}; + case (funct3) + 3'b000 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LB; + 3'b001 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LH; + 3'b010 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LW; + 3'b100 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LBU; + 3'b101 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LHU; + default : rvi_illegal = 1'b1; + endcase // funct3 +`ifdef SCR1_RVE_EXT + if (instr[11] | instr[19]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end // SCR1_OPCODE_LOAD + + SCR1_OPCODE_STORE : begin + idu2exu_use_rs1_o = 1'b1; + idu2exu_use_rs2_o = 1'b1; +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM; + idu2exu_cmd_o.imm = {{21{instr[31]}}, instr[30:25], instr[11:7]}; + case (funct3) + 3'b000 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_SB; + 3'b001 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_SH; + 3'b010 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_SW; + default : rvi_illegal = 1'b1; + endcase // funct3 +`ifdef SCR1_RVE_EXT + if (instr[19] | instr[24]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end // SCR1_OPCODE_STORE + + SCR1_OPCODE_OP : begin + idu2exu_use_rs1_o = 1'b1; + idu2exu_use_rs2_o = 1'b1; +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU; + case (funct7) + 7'b0000000 : begin + case (funct3) + 3'b000 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD; + 3'b001 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SLL; + 3'b010 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_LT; + 3'b011 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_LTU; + 3'b100 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_XOR; + 3'b101 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SRL; + 3'b110 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_OR; + 3'b111 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_AND; + endcase // funct3 + end // 7'b0000000 + + 7'b0100000 : begin + case (funct3) + 3'b000 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB; + 3'b101 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SRA; + default : rvi_illegal = 1'b1; + endcase // funct3 + end // 7'b0100000 +`ifdef SCR1_RVM_EXT + 7'b0000001 : begin + case (funct3) + 3'b000 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_MUL; + 3'b001 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_MULH; + 3'b010 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_MULHSU; + 3'b011 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_MULHU; + 3'b100 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_DIV; + 3'b101 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_DIVU; + 3'b110 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_REM; + 3'b111 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_REMU; + endcase // funct3 + end // 7'b0000001 +`endif // SCR1_RVM_EXT + default : rvi_illegal = 1'b1; + endcase // funct7 +`ifdef SCR1_RVE_EXT + if (instr[11] | instr[19] | instr[24]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end // SCR1_OPCODE_OP + + SCR1_OPCODE_OP_IMM : begin + idu2exu_use_rs1_o = 1'b1; +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b1; + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.imm = {{21{instr[31]}}, instr[30:20]}; + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU; + case (funct3) + 3'b000 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD; // ADDI + 3'b010 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_LT; // SLTI + 3'b011 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_LTU; // SLTIU + 3'b100 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_XOR; // XORI + 3'b110 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_OR; // ORI + 3'b111 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_AND; // ANDI + 3'b001 : begin + case (funct7) + 7'b0000000 : begin + // SLLI + idu2exu_cmd_o.imm = `SCR1_XLEN'(shamt); // zero-extend + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SLL; + end + default : rvi_illegal = 1'b1; + endcase // funct7 + end + 3'b101 : begin + case (funct7) + 7'b0000000 : begin + // SRLI + idu2exu_cmd_o.imm = `SCR1_XLEN'(shamt); // zero-extend + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SRL; + end + 7'b0100000 : begin + // SRAI + idu2exu_cmd_o.imm = `SCR1_XLEN'(shamt); // zero-extend + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SRA; + end + default : rvi_illegal = 1'b1; + endcase // funct7 + end + endcase // funct3 +`ifdef SCR1_RVE_EXT + if (instr[11] | instr[19]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end // SCR1_OPCODE_OP_IMM + + SCR1_OPCODE_MISC_MEM : begin + case (funct3) + 3'b000 : begin + if (~|{instr[31:28], instr[19:15], instr[11:7]}) begin + // FENCE = NOP + end + else rvi_illegal = 1'b1; + end + 3'b001 : begin + if (~|{instr[31:15], instr[11:7]}) begin + // FENCE.I + idu2exu_cmd_o.fencei_req = 1'b1; + end + else rvi_illegal = 1'b1; + end + default : rvi_illegal = 1'b1; + endcase // funct3 + end // SCR1_OPCODE_MISC_MEM + + SCR1_OPCODE_BRANCH : begin + idu2exu_use_rs1_o = 1'b1; + idu2exu_use_rs2_o = 1'b1; +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.imm = {{20{instr[31]}}, instr[7], instr[30:25], instr[11:8], 1'b0}; + idu2exu_cmd_o.branch_req = 1'b1; + idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM; + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG; + case (funct3) + 3'b000 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_EQ; + 3'b001 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_NE; + 3'b100 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_LT; + 3'b101 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_GE; + 3'b110 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_LTU; + 3'b111 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_GEU; + default : rvi_illegal = 1'b1; + endcase // funct3 +`ifdef SCR1_RVE_EXT + if (instr[19] | instr[24]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end // SCR1_OPCODE_BRANCH + + SCR1_OPCODE_JALR : begin + idu2exu_use_rs1_o = 1'b1; +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b1; + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + case (funct3) + 3'b000 : begin + // JALR + idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_INC_PC; + idu2exu_cmd_o.jump_req = 1'b1; + idu2exu_cmd_o.imm = {{21{instr[31]}}, instr[30:20]}; + end + default : rvi_illegal = 1'b1; + endcase +`ifdef SCR1_RVE_EXT + if (instr[11] | instr[19]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end // SCR1_OPCODE_JALR + + SCR1_OPCODE_SYSTEM : begin +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b1; + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.imm = `SCR1_XLEN'({funct3, instr[31:20]}); // {funct3, CSR address} + case (funct3) + 3'b000 : begin +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b0; + idu2exu_use_imm_o = 1'b0; +`endif // SCR1_NO_EXE_STAGE + case ({instr[19:15], instr[11:7]}) + 10'd0 : begin + case (funct12) + 12'h000 : begin + // ECALL + idu2exu_cmd_o.exc_req = 1'b1; + idu2exu_cmd_o.exc_code = SCR1_EXC_CODE_ECALL_M; + end + 12'h001 : begin + // EBREAK + idu2exu_cmd_o.exc_req = 1'b1; + idu2exu_cmd_o.exc_code = SCR1_EXC_CODE_BREAKPOINT; + end + 12'h302 : begin + // MRET + idu2exu_cmd_o.mret_req = 1'b1; + end + 12'h105 : begin + // WFI + idu2exu_cmd_o.wfi_req = 1'b1; + end + default : rvi_illegal = 1'b1; + endcase // funct12 + end + default : rvi_illegal = 1'b1; + endcase // {instr[19:15], instr[11:7]} + end + 3'b001 : begin + // CSRRW + idu2exu_use_rs1_o = 1'b1; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_CSR; + idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_WRITE; + idu2exu_cmd_o.csr_op = SCR1_CSR_OP_REG; +`ifdef SCR1_RVE_EXT + if (instr[11] | instr[19]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end + 3'b010 : begin + // CSRRS + idu2exu_use_rs1_o = 1'b1; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_CSR; + idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_SET; + idu2exu_cmd_o.csr_op = SCR1_CSR_OP_REG; +`ifdef SCR1_RVE_EXT + if (instr[11] | instr[19]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end + 3'b011 : begin + // CSRRC + idu2exu_use_rs1_o = 1'b1; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_CSR; + idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_CLEAR; + idu2exu_cmd_o.csr_op = SCR1_CSR_OP_REG; +`ifdef SCR1_RVE_EXT + if (instr[11] | instr[19]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end + 3'b101 : begin + // CSRRWI + idu2exu_use_rs1_o = 1'b1; // zimm + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_CSR; + idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_WRITE; + idu2exu_cmd_o.csr_op = SCR1_CSR_OP_IMM; +`ifdef SCR1_RVE_EXT + if (instr[11]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end + 3'b110 : begin + // CSRRSI + idu2exu_use_rs1_o = 1'b1; // zimm + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_CSR; + idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_SET; + idu2exu_cmd_o.csr_op = SCR1_CSR_OP_IMM; +`ifdef SCR1_RVE_EXT + if (instr[11]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end + 3'b111 : begin + // CSRRCI + idu2exu_use_rs1_o = 1'b1; // zimm + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_CSR; + idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_CLEAR; + idu2exu_cmd_o.csr_op = SCR1_CSR_OP_IMM; +`ifdef SCR1_RVE_EXT + if (instr[11]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end + default : rvi_illegal = 1'b1; + endcase // funct3 + end // SCR1_OPCODE_SYSTEM + + default : begin + rvi_illegal = 1'b1; + end + endcase // rvi_opcode + end // SCR1_INSTR_RVI + +`ifdef SCR1_RVC_EXT + + // Quadrant 0 + SCR1_INSTR_RVC0 : begin + idu2exu_cmd_o.instr_rvc = 1'b1; + idu2exu_use_rs1_o = 1'b1; +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + case (funct3) + 3'b000 : begin + if (~|instr[12:5]) rvc_illegal = 1'b1; + // C.ADDI4SPN +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD; + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU; + idu2exu_cmd_o.rs1_addr = SCR1_MPRF_SP_ADDR; + idu2exu_cmd_o.rd_addr = {2'b01, instr[4:2]}; + idu2exu_cmd_o.imm = {22'd0, instr[10:7], instr[12:11], instr[5], instr[6], 2'b00}; + end + 3'b010 : begin + // C.LW +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM; + idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LW; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_LSU; + idu2exu_cmd_o.rs1_addr = {2'b01, instr[9:7]}; + idu2exu_cmd_o.rd_addr = {2'b01, instr[4:2]}; + idu2exu_cmd_o.imm = {25'd0, instr[5], instr[12:10], instr[6], 2'b00}; + end + 3'b110 : begin + // C.SW + idu2exu_use_rs2_o = 1'b1; + idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM; + idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_SW; + idu2exu_cmd_o.rs1_addr = {2'b01, instr[9:7]}; + idu2exu_cmd_o.rs2_addr = {2'b01, instr[4:2]}; + idu2exu_cmd_o.imm = {25'd0, instr[5], instr[12:10], instr[6], 2'b00}; + end + default : begin + rvc_illegal = 1'b1; + end + endcase // funct3 + end // Quadrant 0 + + // Quadrant 1 + SCR1_INSTR_RVC1 : begin + idu2exu_cmd_o.instr_rvc = 1'b1; +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b1; + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + case (funct3) + 3'b000 : begin + // C.ADDI / C.NOP + idu2exu_use_rs1_o = 1'b1; + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD; + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU; + idu2exu_cmd_o.rs1_addr = instr[11:7]; + idu2exu_cmd_o.rd_addr = instr[11:7]; + idu2exu_cmd_o.imm = {{27{instr[12]}}, instr[6:2]}; +`ifdef SCR1_RVE_EXT + if (instr[11]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end + 3'b001 : begin + // C.JAL + idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_INC_PC; + idu2exu_cmd_o.jump_req = 1'b1; + idu2exu_cmd_o.rd_addr = SCR1_MPRF_RA_ADDR; + idu2exu_cmd_o.imm = {{21{instr[12]}}, instr[8], instr[10:9], instr[6], instr[7], instr[2], instr[11], instr[5:3], 1'b0}; + end + 3'b010 : begin + // C.LI + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IMM; + idu2exu_cmd_o.rd_addr = instr[11:7]; + idu2exu_cmd_o.imm = {{27{instr[12]}}, instr[6:2]}; +`ifdef SCR1_RVE_EXT + if (instr[11]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end + 3'b011 : begin + if (~|{instr[12], instr[6:2]}) rvc_illegal = 1'b1; + if (instr[11:7] == SCR1_MPRF_SP_ADDR) begin + // C.ADDI16SP + idu2exu_use_rs1_o = 1'b1; + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD; + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU; + idu2exu_cmd_o.rs1_addr = SCR1_MPRF_SP_ADDR; + idu2exu_cmd_o.rd_addr = SCR1_MPRF_SP_ADDR; + idu2exu_cmd_o.imm = {{23{instr[12]}}, instr[4:3], instr[5], instr[2], instr[6], 4'd0}; + end else begin + // C.LUI + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IMM; + idu2exu_cmd_o.rd_addr = instr[11:7]; + idu2exu_cmd_o.imm = {{15{instr[12]}}, instr[6:2], 12'd0}; +`ifdef SCR1_RVE_EXT + if (instr[11]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end + end + 3'b100 : begin + idu2exu_cmd_o.rs1_addr = {2'b01, instr[9:7]}; + idu2exu_cmd_o.rd_addr = {2'b01, instr[9:7]}; + idu2exu_cmd_o.rs2_addr = {2'b01, instr[4:2]}; + idu2exu_use_rs1_o = 1'b1; +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + case (instr[11:10]) + 2'b00 : begin + if (instr[12]) rvc_illegal = 1'b1; + // C.SRLI +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.imm = {27'd0, instr[6:2]}; + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SRL; + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU; + end + 2'b01 : begin + if (instr[12]) rvc_illegal = 1'b1; + // C.SRAI +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.imm = {27'd0, instr[6:2]}; + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SRA; + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU; + end + 2'b10 : begin + // C.ANDI +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_AND; + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU; + idu2exu_cmd_o.imm = {{27{instr[12]}}, instr[6:2]}; + end + 2'b11 : begin + idu2exu_use_rs2_o = 1'b1; + case ({instr[12], instr[6:5]}) + 3'b000 : begin + // C.SUB + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB; + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU; + end + 3'b001 : begin + // C.XOR + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_XOR; + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU; + end + 3'b010 : begin + // C.OR + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_OR; + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU; + end + 3'b011 : begin + // C.AND + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_AND; + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU; + end + default : begin + rvc_illegal = 1'b1; + end + endcase // {instr[12], instr[6:5]} + end + endcase // instr[11:10] + end // funct3 == 3'b100 + 3'b101 : begin + // C.J +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM; + idu2exu_cmd_o.jump_req = 1'b1; + idu2exu_cmd_o.imm = {{21{instr[12]}}, instr[8], instr[10:9], instr[6], instr[7], instr[2], instr[11], instr[5:3], 1'b0}; + end + 3'b110 : begin + // C.BEQZ + idu2exu_use_rs1_o = 1'b1; + idu2exu_use_rs2_o = 1'b1; +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_EQ; + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG; + idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM; + idu2exu_cmd_o.branch_req = 1'b1; + idu2exu_cmd_o.rs1_addr = {2'b01, instr[9:7]}; + idu2exu_cmd_o.rs2_addr = SCR1_MPRF_ZERO_ADDR; + idu2exu_cmd_o.imm = {{24{instr[12]}}, instr[6:5], instr[2], instr[11:10], instr[4:3], 1'b0}; + end + 3'b111 : begin + // C.BNEZ + idu2exu_use_rs1_o = 1'b1; + idu2exu_use_rs2_o = 1'b1; +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_NE; + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG; + idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM; + idu2exu_cmd_o.branch_req = 1'b1; + idu2exu_cmd_o.rs1_addr = {2'b01, instr[9:7]}; + idu2exu_cmd_o.rs2_addr = SCR1_MPRF_ZERO_ADDR; + idu2exu_cmd_o.imm = {{24{instr[12]}}, instr[6:5], instr[2], instr[11:10], instr[4:3], 1'b0}; + end + endcase // funct3 + end // Quadrant 1 + + // Quadrant 2 + SCR1_INSTR_RVC2 : begin + idu2exu_cmd_o.instr_rvc = 1'b1; + idu2exu_use_rs1_o = 1'b1; + case (funct3) + 3'b000 : begin + if (instr[12]) rvc_illegal = 1'b1; + // C.SLLI +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b1; + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.rs1_addr = instr[11:7]; + idu2exu_cmd_o.rd_addr = instr[11:7]; + idu2exu_cmd_o.imm = {27'd0, instr[6:2]}; + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SLL; + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU; +`ifdef SCR1_RVE_EXT + if (instr[11]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end + 3'b010 : begin + if (~|instr[11:7]) rvc_illegal = 1'b1; + // C.LWSP +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b1; + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM; + idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LW; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_LSU; + idu2exu_cmd_o.rs1_addr = SCR1_MPRF_SP_ADDR; + idu2exu_cmd_o.rd_addr = instr[11:7]; + idu2exu_cmd_o.imm = {24'd0, instr[3:2], instr[12], instr[6:4], 2'b00}; +`ifdef SCR1_RVE_EXT + if (instr[11]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end + 3'b100 : begin + if (~instr[12]) begin + if (|instr[6:2]) begin + // C.MV + idu2exu_use_rs2_o = 1'b1; +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD; + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU; + idu2exu_cmd_o.rs1_addr = SCR1_MPRF_ZERO_ADDR; + idu2exu_cmd_o.rs2_addr = instr[6:2]; + idu2exu_cmd_o.rd_addr = instr[11:7]; +`ifdef SCR1_RVE_EXT + if (instr[11]|instr[6]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end else begin + if (~|instr[11:7]) rvc_illegal = 1'b1; + // C.JR +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM; + idu2exu_cmd_o.jump_req = 1'b1; + idu2exu_cmd_o.rs1_addr = instr[11:7]; + idu2exu_cmd_o.imm = 0; +`ifdef SCR1_RVE_EXT + if (instr[11]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end + end else begin // instr[12] == 1 + if (~|instr[11:2]) begin + // C.EBREAK + idu2exu_cmd_o.exc_req = 1'b1; + idu2exu_cmd_o.exc_code = SCR1_EXC_CODE_BREAKPOINT; + end else if (~|instr[6:2]) begin + // C.JALR + idu2exu_use_rs1_o = 1'b1; +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b1; + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_INC_PC; + idu2exu_cmd_o.jump_req = 1'b1; + idu2exu_cmd_o.rs1_addr = instr[11:7]; + idu2exu_cmd_o.rd_addr = SCR1_MPRF_RA_ADDR; + idu2exu_cmd_o.imm = 0; +`ifdef SCR1_RVE_EXT + if (instr[11]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end else begin + // C.ADD + idu2exu_use_rs1_o = 1'b1; + idu2exu_use_rs2_o = 1'b1; +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD; + idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU; + idu2exu_cmd_o.rs1_addr = instr[11:7]; + idu2exu_cmd_o.rs2_addr = instr[6:2]; + idu2exu_cmd_o.rd_addr = instr[11:7]; +`ifdef SCR1_RVE_EXT + if (instr[11]|instr[6]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end + end // instr[12] == 1 + end + 3'b110 : begin + // C.SWSP + idu2exu_use_rs1_o = 1'b1; + idu2exu_use_rs2_o = 1'b1; +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM; + idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_SW; + idu2exu_cmd_o.rs1_addr = SCR1_MPRF_SP_ADDR; + idu2exu_cmd_o.rs2_addr = instr[6:2]; + idu2exu_cmd_o.imm = {24'd0, instr[8:7], instr[12:9], 2'b00}; +`ifdef SCR1_RVE_EXT + if (instr[6]) rve_illegal = 1'b1; +`endif // SCR1_RVE_EXT + end + default : begin + rvc_illegal = 1'b1; + end + endcase // funct3 + end // Quadrant 2 + + default : begin +`ifdef SCR1_XPROP_EN + rvi_illegal = 1'b1; +`endif // SCR1_XPROP_EN + end +`else // SCR1_RVC_EXT + default : begin + idu2exu_cmd_o.instr_rvc = 1'b1; + rvi_illegal = 1'b1; + end +`endif // SCR1_RVC_EXT + endcase // instr_type + end // no imem fault + + // At this point the instruction is fully decoded + // given that no imem fault has happened + + // Check illegal instruction + if ( + rvi_illegal +`ifdef SCR1_RVC_EXT + | rvc_illegal +`endif +`ifdef SCR1_RVE_EXT + | rve_illegal +`endif + ) begin + idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_NONE; + idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_NONE; + idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_NONE; + idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_NONE; + idu2exu_cmd_o.jump_req = 1'b0; + idu2exu_cmd_o.branch_req = 1'b0; + idu2exu_cmd_o.mret_req = 1'b0; + idu2exu_cmd_o.fencei_req = 1'b0; + idu2exu_cmd_o.wfi_req = 1'b0; + + idu2exu_use_rs1_o = 1'b0; + idu2exu_use_rs2_o = 1'b0; +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_rd_o = 1'b0; +`endif // SCR1_NO_EXE_STAGE + +`ifndef SCR1_MTVAL_ILLEGAL_INSTR_EN + idu2exu_use_imm_o = 1'b0; +`else // SCR1_MTVAL_ILLEGAL_INSTR_EN +`ifndef SCR1_NO_EXE_STAGE + idu2exu_use_imm_o = 1'b1; +`endif // SCR1_NO_EXE_STAGE + idu2exu_cmd_o.imm = instr; +`endif // SCR1_MTVAL_ILLEGAL_INSTR_EN + + idu2exu_cmd_o.exc_req = 1'b1; + idu2exu_cmd_o.exc_code = SCR1_EXC_CODE_ILLEGAL_INSTR; + end + +end // RV32I(MC) decode + +`ifdef SCR1_TRGT_SIMULATION +//------------------------------------------------------------------------------- +// Assertion +//------------------------------------------------------------------------------- + +// X checks + +SCR1_SVA_IDU_XCHECK : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown({ifu2idu_vd_i, exu2idu_rdy_i}) + ) else $error("IDU Error: unknown values"); + +// Behavior checks + +SCR1_SVA_IDU_IALU_CMD_RANGE : assert property ( + @(negedge clk) disable iff (~rst_n) + (ifu2idu_vd_i & ~ifu2idu_imem_err_i) |-> + ((idu2exu_cmd_o.ialu_cmd >= SCR1_IALU_CMD_NONE) & + (idu2exu_cmd_o.ialu_cmd <= +`ifdef SCR1_RVM_EXT + SCR1_IALU_CMD_REMU +`else + SCR1_IALU_CMD_SRA +`endif // SCR1_RVM_EXT + )) + ) else $error("IDU Error: IALU_CMD out of range"); + +`endif // SCR1_TRGT_SIMULATION + +endmodule : scr1_pipe_idu diff --git a/src/rtl/scr1/scr1_pipe_ifu.sv b/src/rtl/scr1/scr1_pipe_ifu.sv new file mode 100644 index 0000000..76fec67 --- /dev/null +++ b/src/rtl/scr1/scr1_pipe_ifu.sv @@ -0,0 +1,826 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Instruction Fetch Unit (IFU) +/// + +//------------------------------------------------------------------------------ + // + // Functionality: + // - Controls instruction fetching process: + // - Fetches instructions either from IMEM or from Program Buffer, supporting + // pending IMEM instructions handling + // - Handles new PC misalignment and constructs the correct instruction (supports + // RVI and RVC instructions) + // - Either stores instructions in the instruction queue or bypasses to the + // IDU if the corresponding option is used + // - Flushes instruction queue if requested + // + // Structure: + // - Instruction queue + // - IFU FSM + // - IFU <-> IMEM i/f + // - IFU <-> IDU i/f + // - IFU <-> HDU i/f + // +//------------------------------------------------------------------------------ + +`include "scr1_memif.svh" +`include "scr1_arch_description.svh" +`ifdef SCR1_DBG_EN +`include "scr1_hdu.svh" +`endif // SCR1_DBG_EN + +module scr1_pipe_ifu +( + // Control signals + input logic rst_n, // IFU reset + input logic clk, // IFU clock + input logic pipe2ifu_stop_fetch_i, // Stop instruction fetch + + // IFU <-> IMEM interface + input logic imem2ifu_req_ack_i, // Instruction memory request acknowledgement + output logic ifu2imem_req_o, // Instruction memory request + output type_scr1_mem_cmd_e ifu2imem_cmd_o, // Instruction memory command (READ/WRITE) + output logic [`SCR1_IMEM_AWIDTH-1:0] ifu2imem_addr_o, // Instruction memory address + input logic [`SCR1_IMEM_DWIDTH-1:0] imem2ifu_rdata_i, // Instruction memory read data + input type_scr1_mem_resp_e imem2ifu_resp_i, // Instruction memory response + + // IFU <-> EXU New PC interface + input logic exu2ifu_pc_new_req_i, // New PC request (jumps, branches, traps etc) + input logic [`SCR1_XLEN-1:0] exu2ifu_pc_new_i, // New PC + +`ifdef SCR1_DBG_EN + // IFU <-> HDU Program Buffer interface + input logic hdu2ifu_pbuf_fetch_i, // Fetch instructions provided by Program Buffer + output logic ifu2hdu_pbuf_rdy_o, // Program Buffer Instruction i/f ready + input logic hdu2ifu_pbuf_vd_i, // Program Buffer Instruction valid + input logic hdu2ifu_pbuf_err_i, // Program Buffer Instruction i/f error + input logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] hdu2ifu_pbuf_instr_i, // Program Buffer Instruction itself +`endif // SCR1_DBG_EN + +`ifdef SCR1_CLKCTRL_EN + output logic ifu2pipe_imem_txns_pnd_o, // There are pending imem transactions +`endif // SCR1_CLKCTRL_EN + + // IFU <-> IDU interface + input logic idu2ifu_rdy_i, // IDU ready for new data + output logic [`SCR1_IMEM_DWIDTH-1:0] ifu2idu_instr_o, // IFU instruction + output logic ifu2idu_imem_err_o, // Instruction access fault exception + output logic ifu2idu_err_rvi_hi_o, // 1 - imem fault when trying to fetch second half of an unaligned RVI instruction + output logic ifu2idu_vd_o // IFU request +); + +//------------------------------------------------------------------------------ +// Local parameters declaration +//------------------------------------------------------------------------------ + +localparam SCR1_IFU_Q_SIZE_WORD = 2; +localparam SCR1_IFU_Q_SIZE_HALF = SCR1_IFU_Q_SIZE_WORD * 2; +localparam SCR1_TXN_CNT_W = 3; + +localparam SCR1_IFU_QUEUE_ADR_W = $clog2(SCR1_IFU_Q_SIZE_HALF); +localparam SCR1_IFU_QUEUE_PTR_W = SCR1_IFU_QUEUE_ADR_W + 1; + +localparam SCR1_IFU_Q_FREE_H_W = $clog2(SCR1_IFU_Q_SIZE_HALF + 1); +localparam SCR1_IFU_Q_FREE_W_W = $clog2(SCR1_IFU_Q_SIZE_WORD + 1); + +//------------------------------------------------------------------------------ +// Local types declaration +//------------------------------------------------------------------------------ + +typedef enum logic { + SCR1_IFU_FSM_IDLE, + SCR1_IFU_FSM_FETCH +} type_scr1_ifu_fsm_e; + +typedef enum logic[1:0] { + SCR1_IFU_QUEUE_WR_NONE, // No write to queue + SCR1_IFU_QUEUE_WR_FULL, // Write 32 rdata bits to queue + SCR1_IFU_QUEUE_WR_HI // Write 16 upper rdata bits to queue +} type_scr1_ifu_queue_wr_e; + +typedef enum logic[1:0] { + SCR1_IFU_QUEUE_RD_NONE, // No queue read + SCR1_IFU_QUEUE_RD_HWORD, // Read halfword + SCR1_IFU_QUEUE_RD_WORD // Read word +} type_scr1_ifu_queue_rd_e; + +`ifdef SCR1_NO_DEC_STAGE +typedef enum logic[1:0] { + SCR1_BYPASS_NONE, // No bypass + SCR1_BYPASS_RVC, // Bypass RVC + SCR1_BYPASS_RVI_RDATA_QUEUE, // Bypass RVI, rdata+queue + SCR1_BYPASS_RVI_RDATA // Bypass RVI, rdata only +} type_scr1_bypass_e; +`endif // SCR1_NO_DEC_STAGE + +typedef enum logic [2:0] { + // SCR1_IFU_INSTR__ + SCR1_IFU_INSTR_NONE, // No valid instruction + SCR1_IFU_INSTR_RVI_HI_RVI_LO, // Full RV32I instruction + SCR1_IFU_INSTR_RVC_RVC, + SCR1_IFU_INSTR_RVI_LO_RVC, + SCR1_IFU_INSTR_RVC_RVI_HI, + SCR1_IFU_INSTR_RVI_LO_RVI_HI, + SCR1_IFU_INSTR_RVC_NV, // Instruction after unaligned new_pc + SCR1_IFU_INSTR_RVI_LO_NV // Instruction after unaligned new_pc +} type_scr1_ifu_instr_e; + +//------------------------------------------------------------------------------ +// Local signals declaration +//------------------------------------------------------------------------------ + +// Instruction queue signals +//------------------------------------------------------------------------------ + +// New PC unaligned flag register +logic new_pc_unaligned_ff; +logic new_pc_unaligned_next; +logic new_pc_unaligned_upd; + +// IMEM instruction type decoder +logic instr_hi_is_rvi; +logic instr_lo_is_rvi; +type_scr1_ifu_instr_e instr_type; + +// Register to store if the previous IMEM instruction had low part of RVI instruction +// in its high part +logic instr_hi_rvi_lo_ff; +logic instr_hi_rvi_lo_next; + +// Queue read/write size decoders +type_scr1_ifu_queue_rd_e q_rd_size; +logic q_rd_vd; +logic q_rd_none; +logic q_rd_hword; +type_scr1_ifu_queue_wr_e q_wr_size; +logic q_wr_none; +logic q_wr_full; + +// Write/read pointer registers +logic [SCR1_IFU_QUEUE_PTR_W-1:0] q_rptr; +logic [SCR1_IFU_QUEUE_PTR_W-1:0] q_rptr_next; +logic q_rptr_upd; +logic [SCR1_IFU_QUEUE_PTR_W-1:0] q_wptr; +logic [SCR1_IFU_QUEUE_PTR_W-1:0] q_wptr_next; +logic q_wptr_upd; + +// Instruction queue control signals +logic q_wr_en; +logic q_flush_req; + +// Queue data registers +logic [`SCR1_IMEM_DWIDTH/2-1:0] q_data [SCR1_IFU_Q_SIZE_HALF]; +logic [`SCR1_IMEM_DWIDTH/2-1:0] q_data_head; +logic [`SCR1_IMEM_DWIDTH/2-1:0] q_data_next; + +// Queue error flags registers +logic q_err [SCR1_IFU_Q_SIZE_HALF]; +logic q_err_head; +logic q_err_next; + +// Instruction queue status signals +logic q_is_empty; +logic q_has_free_slots; +logic q_has_1_ocpd_hw; +logic q_head_is_rvc; +logic q_head_is_rvi; +logic [SCR1_IFU_Q_FREE_H_W-1:0] q_ocpd_h; +logic [SCR1_IFU_Q_FREE_H_W-1:0] q_free_h_next; +logic [SCR1_IFU_Q_FREE_W_W-1:0] q_free_w_next; + +// IFU FSM signals +//------------------------------------------------------------------------------ + +// IFU FSM control signals +logic ifu_fetch_req; +logic ifu_stop_req; + +type_scr1_ifu_fsm_e ifu_fsm_curr; +type_scr1_ifu_fsm_e ifu_fsm_next; +logic ifu_fsm_fetch; + +// IMEM signals +//------------------------------------------------------------------------------ + +// IMEM response signals +logic imem_resp_ok; +logic imem_resp_er; +logic imem_resp_er_discard_pnd; +logic imem_resp_discard_req; +logic imem_resp_received; +logic imem_resp_vd; +logic imem_handshake_done; + +logic [15:0] imem_rdata_lo; +logic [31:16] imem_rdata_hi; + +// IMEM address signals +logic imem_addr_upd; +logic [`SCR1_XLEN-1:2] imem_addr_ff; +logic [`SCR1_XLEN-1:2] imem_addr_next; + +// IMEM pending transactions counter +logic imem_pnd_txns_cnt_upd; +logic [SCR1_TXN_CNT_W-1:0] imem_pnd_txns_cnt; +logic [SCR1_TXN_CNT_W-1:0] imem_pnd_txns_cnt_next; +logic [SCR1_TXN_CNT_W-1:0] imem_vd_pnd_txns_cnt; +logic imem_pnd_txns_q_full; + +// IMEM responses discard counter +logic imem_resp_discard_cnt_upd; +logic [SCR1_TXN_CNT_W-1:0] imem_resp_discard_cnt; +logic [SCR1_TXN_CNT_W-1:0] imem_resp_discard_cnt_next; + +`ifdef SCR1_NEW_PC_REG +logic new_pc_req_ff; +`endif // SCR1_NEW_PC_REG + +// Instruction bypass signals +`ifdef SCR1_NO_DEC_STAGE +type_scr1_bypass_e instr_bypass_type; +logic instr_bypass_vd; +`endif // SCR1_NO_DEC_STAGE + +//------------------------------------------------------------------------------ +// Instruction queue +//------------------------------------------------------------------------------ +// + // Instruction queue consists of the following functional units: + // - New PC unaligned flag register + // - Instruction type decoder, including register to store if the previous + // IMEM instruction had low part of RVI instruction in its high part + // - Read/write size decoders + // - Read/write pointer registers + // - Data and error flag registers + // - Status logic +// + +// New PC unaligned flag register +//------------------------------------------------------------------------------ + +assign new_pc_unaligned_upd = exu2ifu_pc_new_req_i | imem_resp_vd; + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + new_pc_unaligned_ff <= 1'b0; + end else if (new_pc_unaligned_upd) begin + new_pc_unaligned_ff <= new_pc_unaligned_next; + end +end + +assign new_pc_unaligned_next = exu2ifu_pc_new_req_i ? exu2ifu_pc_new_i[1] + : ~imem_resp_vd ? new_pc_unaligned_ff + : 1'b0; + +// Instruction type decoder +//------------------------------------------------------------------------------ + +assign instr_hi_is_rvi = &imem2ifu_rdata_i[17:16]; +assign instr_lo_is_rvi = &imem2ifu_rdata_i[1:0]; + +always_comb begin + instr_type = SCR1_IFU_INSTR_NONE; + + if (imem_resp_ok & ~imem_resp_discard_req) begin + if (new_pc_unaligned_ff) begin + instr_type = instr_hi_is_rvi ? SCR1_IFU_INSTR_RVI_LO_NV + : SCR1_IFU_INSTR_RVC_NV; + end else begin // ~new_pc_unaligned_ff + if (instr_hi_rvi_lo_ff) begin + instr_type = instr_hi_is_rvi ? SCR1_IFU_INSTR_RVI_LO_RVI_HI + : SCR1_IFU_INSTR_RVC_RVI_HI; + end else begin // SCR1_OTHER + case ({instr_hi_is_rvi, instr_lo_is_rvi}) + 2'b00 : instr_type = SCR1_IFU_INSTR_RVC_RVC; + 2'b10 : instr_type = SCR1_IFU_INSTR_RVI_LO_RVC; + default : instr_type = SCR1_IFU_INSTR_RVI_HI_RVI_LO; + endcase + end + end + end +end + +// Register to store if the previous IMEM instruction had low part of RVI +// instruction in its high part +//------------------------------------------------------------------------------ + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + instr_hi_rvi_lo_ff <= 1'b0; + end else begin + if (exu2ifu_pc_new_req_i) begin + instr_hi_rvi_lo_ff <= 1'b0; + end else if (imem_resp_vd) begin + instr_hi_rvi_lo_ff <= instr_hi_rvi_lo_next; + end + end +end + +assign instr_hi_rvi_lo_next = (instr_type == SCR1_IFU_INSTR_RVI_LO_NV) + | (instr_type == SCR1_IFU_INSTR_RVI_LO_RVI_HI) + | (instr_type == SCR1_IFU_INSTR_RVI_LO_RVC); + +// Queue write/read size decoders +//------------------------------------------------------------------------------ + +// Queue read size decoder +assign q_rd_vd = ~q_is_empty & ifu2idu_vd_o & idu2ifu_rdy_i; +assign q_rd_hword = q_head_is_rvc | q_err_head +`ifdef SCR1_NO_DEC_STAGE + | (q_head_is_rvi & instr_bypass_vd) +`endif // SCR1_NO_DEC_STAGE + ; +assign q_rd_size = ~q_rd_vd ? SCR1_IFU_QUEUE_RD_NONE + : q_rd_hword ? SCR1_IFU_QUEUE_RD_HWORD + : SCR1_IFU_QUEUE_RD_WORD; +assign q_rd_none = (q_rd_size == SCR1_IFU_QUEUE_RD_NONE); + +// Queue write size decoder +always_comb begin + q_wr_size = SCR1_IFU_QUEUE_WR_NONE; + if (~imem_resp_discard_req) begin + if (imem_resp_ok) begin +`ifdef SCR1_NO_DEC_STAGE + case (instr_type) + SCR1_IFU_INSTR_NONE : q_wr_size = SCR1_IFU_QUEUE_WR_NONE; + SCR1_IFU_INSTR_RVI_LO_NV : q_wr_size = SCR1_IFU_QUEUE_WR_HI; + SCR1_IFU_INSTR_RVC_NV : q_wr_size = (instr_bypass_vd & idu2ifu_rdy_i) + ? SCR1_IFU_QUEUE_WR_NONE + : SCR1_IFU_QUEUE_WR_HI; + SCR1_IFU_INSTR_RVI_HI_RVI_LO: q_wr_size = (instr_bypass_vd & idu2ifu_rdy_i) + ? SCR1_IFU_QUEUE_WR_NONE + : SCR1_IFU_QUEUE_WR_FULL; + SCR1_IFU_INSTR_RVC_RVC, + SCR1_IFU_INSTR_RVI_LO_RVC, + SCR1_IFU_INSTR_RVC_RVI_HI, + SCR1_IFU_INSTR_RVI_LO_RVI_HI: q_wr_size = (instr_bypass_vd & idu2ifu_rdy_i) + ? SCR1_IFU_QUEUE_WR_HI + : SCR1_IFU_QUEUE_WR_FULL; + endcase // instr_type +`else // SCR1_NO_DEC_STAGE + case (instr_type) + SCR1_IFU_INSTR_NONE : q_wr_size = SCR1_IFU_QUEUE_WR_NONE; + SCR1_IFU_INSTR_RVC_NV, + SCR1_IFU_INSTR_RVI_LO_NV : q_wr_size = SCR1_IFU_QUEUE_WR_HI; + default : q_wr_size = SCR1_IFU_QUEUE_WR_FULL; + endcase // instr_type +`endif // SCR1_NO_DEC_STAGE + end else if (imem_resp_er) begin + q_wr_size = SCR1_IFU_QUEUE_WR_FULL; + end // imem_resp_er + end // ~imem_resp_discard_req +end + +assign q_wr_none = (q_wr_size == SCR1_IFU_QUEUE_WR_NONE); +assign q_wr_full = (q_wr_size == SCR1_IFU_QUEUE_WR_FULL); + +// Write/read pointer registers +//------------------------------------------------------------------------------ + +assign q_flush_req = exu2ifu_pc_new_req_i | pipe2ifu_stop_fetch_i; + +// Queue write pointer register +assign q_wptr_upd = q_flush_req | ~q_wr_none; + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + q_wptr <= '0; + end else if (q_wptr_upd) begin + q_wptr <= q_wptr_next; + end +end + +assign q_wptr_next = q_flush_req ? '0 + : ~q_wr_none ? q_wptr + (q_wr_full ? SCR1_IFU_QUEUE_PTR_W'('b010) : SCR1_IFU_QUEUE_PTR_W'('b001)) + : q_wptr; + +// Queue read pointer register +assign q_rptr_upd = q_flush_req | ~q_rd_none; + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + q_rptr <= '0; + end else if (q_rptr_upd) begin + q_rptr <= q_rptr_next; + end +end + +assign q_rptr_next = q_flush_req ? '0 + : ~q_rd_none ? q_rptr + (q_rd_hword ? SCR1_IFU_QUEUE_PTR_W'('b001) : SCR1_IFU_QUEUE_PTR_W'('b010)) + : q_rptr; + +// Queue data and error flag registers +//------------------------------------------------------------------------------ + +assign imem_rdata_hi = imem2ifu_rdata_i[31:16]; +assign imem_rdata_lo = imem2ifu_rdata_i[15:0]; + +assign q_wr_en = imem_resp_vd & ~q_flush_req; + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + q_data <= '{SCR1_IFU_Q_SIZE_HALF{'0}}; + q_err <= '{SCR1_IFU_Q_SIZE_HALF{1'b0}}; + end else if (q_wr_en) begin + case (q_wr_size) + SCR1_IFU_QUEUE_WR_HI : begin + q_data[SCR1_IFU_QUEUE_ADR_W'(q_wptr)] <= imem_rdata_hi; + q_err [SCR1_IFU_QUEUE_ADR_W'(q_wptr)] <= imem_resp_er; + end + SCR1_IFU_QUEUE_WR_FULL : begin + q_data[SCR1_IFU_QUEUE_ADR_W'(q_wptr)] <= imem_rdata_lo; + q_err [SCR1_IFU_QUEUE_ADR_W'(q_wptr)] <= imem_resp_er; + q_data[SCR1_IFU_QUEUE_ADR_W'(q_wptr + 1'b1)] <= imem_rdata_hi; + q_err [SCR1_IFU_QUEUE_ADR_W'(q_wptr + 1'b1)] <= imem_resp_er; + end + endcase + end +end + +assign q_data_head = q_data [SCR1_IFU_QUEUE_ADR_W'(q_rptr)]; +assign q_data_next = q_data [SCR1_IFU_QUEUE_ADR_W'(q_rptr + 1'b1)]; +assign q_err_head = q_err [SCR1_IFU_QUEUE_ADR_W'(q_rptr)]; +assign q_err_next = q_err [SCR1_IFU_QUEUE_ADR_W'(q_rptr + 1'b1)]; + +// Queue status logic +//------------------------------------------------------------------------------ + +assign q_ocpd_h = SCR1_IFU_Q_FREE_H_W'(q_wptr - q_rptr); +assign q_free_h_next = SCR1_IFU_Q_FREE_H_W'(SCR1_IFU_Q_SIZE_HALF - (q_wptr - q_rptr_next)); +assign q_free_w_next = SCR1_IFU_Q_FREE_W_W'(q_free_h_next >> 1'b1); + +assign q_is_empty = (q_rptr == q_wptr); +assign q_has_free_slots = (SCR1_TXN_CNT_W'(q_free_w_next) > imem_vd_pnd_txns_cnt); +assign q_has_1_ocpd_hw = (q_ocpd_h == SCR1_IFU_Q_FREE_H_W'(1)); + +assign q_head_is_rvi = &(q_data_head[1:0]); +assign q_head_is_rvc = ~q_head_is_rvi; + +//------------------------------------------------------------------------------ +// IFU FSM +//------------------------------------------------------------------------------ + +// IFU FSM control signals +assign ifu_fetch_req = exu2ifu_pc_new_req_i & ~pipe2ifu_stop_fetch_i; +assign ifu_stop_req = pipe2ifu_stop_fetch_i + | (imem_resp_er_discard_pnd & ~exu2ifu_pc_new_req_i); + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + ifu_fsm_curr <= SCR1_IFU_FSM_IDLE; + end else begin + ifu_fsm_curr <= ifu_fsm_next; + end +end + +always_comb begin + case (ifu_fsm_curr) + SCR1_IFU_FSM_IDLE : begin + ifu_fsm_next = ifu_fetch_req ? SCR1_IFU_FSM_FETCH + : SCR1_IFU_FSM_IDLE; + end + SCR1_IFU_FSM_FETCH : begin + ifu_fsm_next = ifu_stop_req ? SCR1_IFU_FSM_IDLE + : SCR1_IFU_FSM_FETCH; + end + endcase +end + +assign ifu_fsm_fetch = (ifu_fsm_curr == SCR1_IFU_FSM_FETCH); + +//------------------------------------------------------------------------------ +// IFU <-> IMEM interface +//------------------------------------------------------------------------------ +// + // IFU <-> IMEM interface consists of the following functional units: + // - IMEM response logic + // - IMEM address register + // - Pending IMEM transactions counter + // - IMEM discard responses counter + // - IFU <-> IMEM interface output signals +// + +// IMEM response logic +//------------------------------------------------------------------------------ + +assign imem_resp_er = (imem2ifu_resp_i == SCR1_MEM_RESP_RDY_ER); +assign imem_resp_ok = (imem2ifu_resp_i == SCR1_MEM_RESP_RDY_OK); +assign imem_resp_received = imem_resp_ok | imem_resp_er; +assign imem_resp_vd = imem_resp_received & ~imem_resp_discard_req; +assign imem_resp_er_discard_pnd = imem_resp_er & ~imem_resp_discard_req; + +assign imem_handshake_done = ifu2imem_req_o & imem2ifu_req_ack_i; + +// IMEM address register +//------------------------------------------------------------------------------ + +assign imem_addr_upd = imem_handshake_done | exu2ifu_pc_new_req_i; + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + imem_addr_ff <= '0; + end else if (imem_addr_upd) begin + imem_addr_ff <= imem_addr_next; + end +end + +`ifndef SCR1_NEW_PC_REG +assign imem_addr_next = exu2ifu_pc_new_req_i ? exu2ifu_pc_new_i[`SCR1_XLEN-1:2] + imem_handshake_done + : &imem_addr_ff[5:2] ? imem_addr_ff + imem_handshake_done + : {imem_addr_ff[`SCR1_XLEN-1:6], imem_addr_ff[5:2] + imem_handshake_done}; +`else // SCR1_NEW_PC_REG +assign imem_addr_next = exu2ifu_pc_new_req_i ? exu2ifu_pc_new_i[`SCR1_XLEN-1:2] + : &imem_addr_ff[5:2] ? imem_addr_ff + imem_handshake_done + : {imem_addr_ff[`SCR1_XLEN-1:6], imem_addr_ff[5:2] + imem_handshake_done}; +`endif // SCR1_NEW_PC_REG + +// Pending IMEM transactions counter +//------------------------------------------------------------------------------ +// Pending IMEM transactions occur if IFU request has been acknowledged, but +// response comes in the next cycle or later + +assign imem_pnd_txns_cnt_upd = imem_handshake_done ^ imem_resp_received; + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + imem_pnd_txns_cnt <= '0; + end else if (imem_pnd_txns_cnt_upd) begin + imem_pnd_txns_cnt <= imem_pnd_txns_cnt_next; + end +end + +assign imem_pnd_txns_cnt_next = imem_pnd_txns_cnt + (imem_handshake_done - imem_resp_received); +assign imem_pnd_txns_q_full = &imem_pnd_txns_cnt; + +// IMEM discard responses counter +//------------------------------------------------------------------------------ +// IMEM instructions should be discarded in the following 2 cases: +// 1. New PC is requested by jump, branch, mret or other instruction +// 2. IMEM response was erroneous and not discarded +// +// In both cases the number of instructions to be discarded equals to the number +// of pending instructions. +// In the 1st case we don't need all the instructions that haven't been fetched +// yet, since the PC has changed. +// In the 2nd case, since the IMEM responce was erroneous there is no guarantee +// that subsequent IMEM instructions would be valid. + +assign imem_resp_discard_cnt_upd = exu2ifu_pc_new_req_i | imem_resp_er + | (imem_resp_ok & imem_resp_discard_req); + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + imem_resp_discard_cnt <= '0; + end else if (imem_resp_discard_cnt_upd) begin + imem_resp_discard_cnt <= imem_resp_discard_cnt_next; + end +end + +`ifndef SCR1_NEW_PC_REG +assign imem_resp_discard_cnt_next = exu2ifu_pc_new_req_i ? imem_pnd_txns_cnt_next - imem_handshake_done + : imem_resp_er_discard_pnd ? imem_pnd_txns_cnt_next + : imem_resp_discard_cnt - 1'b1; +`else // SCR1_NEW_PC_REG +assign imem_resp_discard_cnt_next = exu2ifu_pc_new_req_i | imem_resp_er_discard_pnd + ? imem_pnd_txns_cnt_next + : imem_resp_discard_cnt - 1'b1; +`endif // SCR1_NEW_PC_REG + +assign imem_vd_pnd_txns_cnt = imem_pnd_txns_cnt - imem_resp_discard_cnt; +assign imem_resp_discard_req = |imem_resp_discard_cnt; + +// IFU <-> IMEM interface output signals +//------------------------------------------------------------------------------ + +`ifndef SCR1_NEW_PC_REG +assign ifu2imem_req_o = (exu2ifu_pc_new_req_i & ~imem_pnd_txns_q_full & ~pipe2ifu_stop_fetch_i) + | (ifu_fsm_fetch & ~imem_pnd_txns_q_full & q_has_free_slots); +assign ifu2imem_addr_o = exu2ifu_pc_new_req_i + ? {exu2ifu_pc_new_i[`SCR1_XLEN-1:2], 2'b00} + : {imem_addr_ff, 2'b00}; +`else // SCR1_NEW_PC_REG +assign ifu2imem_req_o = ifu_fsm_fetch & ~imem_pnd_txns_q_full & q_has_free_slots; +assign ifu2imem_addr_o = {imem_addr_ff, 2'b00}; +`endif // SCR1_NEW_PC_REG + +assign ifu2imem_cmd_o = SCR1_MEM_CMD_RD; + +`ifdef SCR1_CLKCTRL_EN +assign ifu2pipe_imem_txns_pnd_o = |imem_pnd_txns_cnt; +`endif // SCR1_CLKCTRL_EN + +//------------------------------------------------------------------------------ +// IFU <-> IDU interface +//------------------------------------------------------------------------------ +// + // IFU <-> IDU interface consists of the following functional units: + // - Instruction bypass type decoder + // - IFU <-> IDU status signals + // - Output instruction multiplexer +// + +`ifdef SCR1_NO_DEC_STAGE + +// Instruction bypass type decoder +//------------------------------------------------------------------------------ + +assign instr_bypass_vd = (instr_bypass_type != SCR1_BYPASS_NONE); + +always_comb begin + instr_bypass_type = SCR1_BYPASS_NONE; + + if (imem_resp_vd) begin + if (q_is_empty) begin + case (instr_type) + SCR1_IFU_INSTR_RVC_NV, + SCR1_IFU_INSTR_RVC_RVC, + SCR1_IFU_INSTR_RVI_LO_RVC : begin + instr_bypass_type = SCR1_BYPASS_RVC; + end + SCR1_IFU_INSTR_RVI_HI_RVI_LO : begin + instr_bypass_type = SCR1_BYPASS_RVI_RDATA; + end + default : begin end + endcase // instr_type + end else if (q_has_1_ocpd_hw & q_head_is_rvi) begin + if (instr_hi_rvi_lo_ff) begin + instr_bypass_type = SCR1_BYPASS_RVI_RDATA_QUEUE; + end + end + end // imem_resp_vd +end + +// IFU <-> IDU interface status signals +//------------------------------------------------------------------------------ + +always_comb begin + ifu2idu_vd_o = 1'b0; + ifu2idu_imem_err_o = 1'b0; + ifu2idu_err_rvi_hi_o = 1'b0; + + if (ifu_fsm_fetch | ~q_is_empty) begin + if (instr_bypass_vd) begin + ifu2idu_vd_o = 1'b1; + ifu2idu_imem_err_o = (instr_bypass_type == SCR1_BYPASS_RVI_RDATA_QUEUE) + ? (imem_resp_er | q_err_head) + : imem_resp_er; + ifu2idu_err_rvi_hi_o = (instr_bypass_type == SCR1_BYPASS_RVI_RDATA_QUEUE) & imem_resp_er; + end else if (~q_is_empty) begin + if (q_has_1_ocpd_hw) begin + ifu2idu_vd_o = q_head_is_rvc | q_err_head; + ifu2idu_imem_err_o = q_err_head; + ifu2idu_err_rvi_hi_o = ~q_err_head & q_head_is_rvi & q_err_next; + end else begin + ifu2idu_vd_o = 1'b1; + ifu2idu_imem_err_o = q_err_head ? 1'b1 : (q_head_is_rvi & q_err_next); + end + end // ~q_is_empty + end +`ifdef SCR1_DBG_EN + if (hdu2ifu_pbuf_fetch_i) begin + ifu2idu_vd_o = hdu2ifu_pbuf_vd_i; + ifu2idu_imem_err_o = hdu2ifu_pbuf_err_i; + end +`endif // SCR1_DBG_EN +end + +// Output instruction multiplexer +//------------------------------------------------------------------------------ + +always_comb begin + case (instr_bypass_type) + SCR1_BYPASS_RVC : begin + ifu2idu_instr_o = `SCR1_IMEM_DWIDTH'(new_pc_unaligned_ff ? imem_rdata_hi + : imem_rdata_lo); + end + SCR1_BYPASS_RVI_RDATA : begin + ifu2idu_instr_o = imem2ifu_rdata_i; + end + SCR1_BYPASS_RVI_RDATA_QUEUE: begin + ifu2idu_instr_o = {imem_rdata_lo, q_data_head}; + end + default : begin + ifu2idu_instr_o = `SCR1_IMEM_DWIDTH'(q_head_is_rvc ? q_data_head + : {q_data_next, q_data_head}); + end + endcase // instr_bypass_type +`ifdef SCR1_DBG_EN + if (hdu2ifu_pbuf_fetch_i) begin + ifu2idu_instr_o = `SCR1_IMEM_DWIDTH'({'0, hdu2ifu_pbuf_instr_i}); + end +`endif // SCR1_DBG_EN +end + +`else // SCR1_NO_DEC_STAGE + +// IFU <-> IDU interface status signals +//------------------------------------------------------------------------------ + +always_comb begin + ifu2idu_vd_o = 1'b0; + ifu2idu_imem_err_o = 1'b0; + ifu2idu_err_rvi_hi_o = 1'b0; + if (~q_is_empty) begin + if (q_has_1_ocpd_hw) begin + ifu2idu_vd_o = q_head_is_rvc | q_err_head; + ifu2idu_imem_err_o = q_err_head; + end else begin + ifu2idu_vd_o = 1'b1; + ifu2idu_imem_err_o = q_err_head ? 1'b1 : (q_head_is_rvi & q_err_next); + ifu2idu_err_rvi_hi_o = ~q_err_head & q_head_is_rvi & q_err_next; + end + end // ~q_is_empty +`ifdef SCR1_DBG_EN + if (hdu2ifu_pbuf_fetch_i) begin + ifu2idu_vd_o = hdu2ifu_pbuf_vd_i; + ifu2idu_imem_err_o = hdu2ifu_pbuf_err_i; + end +`endif // SCR1_DBG_EN +end + +// Output instruction multiplexer +//------------------------------------------------------------------------------ + +always_comb begin + ifu2idu_instr_o = q_head_is_rvc ? `SCR1_IMEM_DWIDTH'(q_data_head) + : {q_data_next, q_data_head}; +`ifdef SCR1_DBG_EN + if (hdu2ifu_pbuf_fetch_i) begin + ifu2idu_instr_o = `SCR1_IMEM_DWIDTH'({'0, hdu2ifu_pbuf_instr_i}); + end +`endif // SCR1_DBG_EN +end + +`endif // SCR1_NO_DEC_STAGE + +`ifdef SCR1_DBG_EN +assign ifu2hdu_pbuf_rdy_o = idu2ifu_rdy_i; +`endif // SCR1_DBG_EN + +`ifdef SCR1_TRGT_SIMULATION + +//------------------------------------------------------------------------------ +// Assertions +//------------------------------------------------------------------------------ + +// X checks + +SCR1_SVA_IFU_XCHECK : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown({imem2ifu_req_ack_i, idu2ifu_rdy_i, exu2ifu_pc_new_req_i}) + ) else $error("IFU Error: unknown values"); + +SCR1_SVA_IFU_XCHECK_REQ : assert property ( + @(negedge clk) disable iff (~rst_n) + ifu2imem_req_o |-> !$isunknown({ifu2imem_addr_o, ifu2imem_cmd_o}) + ) else $error("IFU Error: unknown {ifu2imem_addr_o, ifu2imem_cmd_o}"); + +// Behavior checks + +SCR1_SVA_IFU_DRC_UNDERFLOW : assert property ( + @(negedge clk) disable iff (~rst_n) + ~imem_resp_discard_req |=> ~(imem_resp_discard_cnt == SCR1_TXN_CNT_W'('1)) + ) else $error("IFU Error: imem_resp_discard_cnt underflow"); + +SCR1_SVA_IFU_DRC_RANGE : assert property ( + @(negedge clk) disable iff (~rst_n) + (imem_resp_discard_cnt >= 0) & (imem_resp_discard_cnt <= imem_pnd_txns_cnt) + ) else $error("IFU Error: imem_resp_discard_cnt out of range"); + +SCR1_SVA_IFU_QUEUE_OVF : assert property ( + @(negedge clk) disable iff (~rst_n) + (q_ocpd_h >= SCR1_IFU_Q_FREE_H_W'(SCR1_IFU_Q_SIZE_HALF-1)) |-> + ((q_ocpd_h == SCR1_IFU_Q_FREE_H_W'(SCR1_IFU_Q_SIZE_HALF-1)) ? (q_wr_size != SCR1_IFU_QUEUE_WR_FULL) + : (q_wr_size == SCR1_IFU_QUEUE_WR_NONE)) + ) else $error("IFU Error: queue overflow"); + +SCR1_SVA_IFU_IMEM_ERR_BEH : assert property ( + @(negedge clk) disable iff (~rst_n) + (imem_resp_er & ~imem_resp_discard_req & ~exu2ifu_pc_new_req_i) |=> + (ifu_fsm_curr == SCR1_IFU_FSM_IDLE) & (imem_resp_discard_cnt == imem_pnd_txns_cnt) + ) else $error("IFU Error: incorrect behavior after memory error"); + +SCR1_SVA_IFU_NEW_PC_REQ_BEH : assert property ( + @(negedge clk) disable iff (~rst_n) + exu2ifu_pc_new_req_i |=> q_is_empty + ) else $error("IFU Error: incorrect behavior after exu2ifu_pc_new_req_i"); + +SCR1_SVA_IFU_IMEM_ADDR_ALIGNED : assert property ( + @(negedge clk) disable iff (~rst_n) + ifu2imem_req_o |-> ~|ifu2imem_addr_o[1:0] + ) else $error("IFU Error: unaligned IMEM access"); + +SCR1_SVA_IFU_STOP_FETCH : assert property ( + @(negedge clk) disable iff (~rst_n) + pipe2ifu_stop_fetch_i |=> (ifu_fsm_curr == SCR1_IFU_FSM_IDLE) + ) else $error("IFU Error: fetch not stopped"); + +SCR1_SVA_IFU_IMEM_FAULT_RVI_HI : assert property ( + @(negedge clk) disable iff (~rst_n) + ifu2idu_err_rvi_hi_o |-> ifu2idu_imem_err_o + ) else $error("IFU Error: ifu2idu_imem_err_o == 0"); + +`endif // SCR1_TRGT_SIMULATION + +endmodule : scr1_pipe_ifu diff --git a/src/rtl/scr1/scr1_pipe_lsu.sv b/src/rtl/scr1/scr1_pipe_lsu.sv new file mode 100644 index 0000000..3c19db6 --- /dev/null +++ b/src/rtl/scr1/scr1_pipe_lsu.sv @@ -0,0 +1,351 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Load/Store Unit (LSU) +/// + +//------------------------------------------------------------------------------ + // + // Functionality: + // - Performs load and store operations in Data Memory + // - Generates DMEM address misalign and access fault exceptions + // - Passes DMEM operations information to TDU and generates LSU breakpoint exception + // + // Structure: + // - FSM + // - Exceptions logic + // - LSU <-> EXU interface + // - LSU <-> DMEM interface + // - LSU <-> TDU interface + // +//------------------------------------------------------------------------------ + +`include "scr1_arch_description.svh" +`include "scr1_arch_types.svh" +`include "scr1_memif.svh" +`include "scr1_riscv_isa_decoding.svh" +`ifdef SCR1_TDU_EN +`include "scr1_tdu.svh" +`endif // SCR1_TDU_EN + +module scr1_pipe_lsu ( + // Common + input logic rst_n, // LSU reset + input logic clk, // LSU clock + + // LSU <-> EXU interface + input logic exu2lsu_req_i, // Request to LSU + input type_scr1_lsu_cmd_sel_e exu2lsu_cmd_i, // LSU command + input logic [`SCR1_XLEN-1:0] exu2lsu_addr_i, // Address of DMEM + input logic [`SCR1_XLEN-1:0] exu2lsu_sdata_i, // Data for store + output logic lsu2exu_rdy_o, // LSU received DMEM response + output logic [`SCR1_XLEN-1:0] lsu2exu_ldata_o, // Load data + output logic lsu2exu_exc_o, // Exception from LSU + output type_scr1_exc_code_e lsu2exu_exc_code_o, // Exception code + +`ifdef SCR1_TDU_EN + // LSU <-> TDU interface + output type_scr1_brkm_lsu_mon_s lsu2tdu_dmon_o, // Data address stream monitoring + input logic tdu2lsu_ibrkpt_exc_req_i, // Instruction BP exception request + input logic tdu2lsu_dbrkpt_exc_req_i, // Data BP exception request +`endif // SCR1_TDU_EN + + // LSU <-> DMEM interface + output logic lsu2dmem_req_o, // Data memory request + output type_scr1_mem_cmd_e lsu2dmem_cmd_o, // Data memory command (READ/WRITE) + output type_scr1_mem_width_e lsu2dmem_width_o, // Data memory data width + output logic [`SCR1_DMEM_AWIDTH-1:0] lsu2dmem_addr_o, // Data memory address + output logic [`SCR1_DMEM_DWIDTH-1:0] lsu2dmem_wdata_o, // Data memory write data + input logic dmem2lsu_req_ack_i, // Data memory request acknowledge + input logic [`SCR1_DMEM_DWIDTH-1:0] dmem2lsu_rdata_i, // Data memory read data + input type_scr1_mem_resp_e dmem2lsu_resp_i // Data memory response +); + +//------------------------------------------------------------------------------ +// Local types declaration +//------------------------------------------------------------------------------ + +typedef enum logic { + SCR1_LSU_FSM_IDLE, + SCR1_LSU_FSM_BUSY +} type_scr1_lsu_fsm_e; + +//------------------------------------------------------------------------------ +// Local signals declaration +//------------------------------------------------------------------------------ + +// LSU FSM signals +type_scr1_lsu_fsm_e lsu_fsm_curr; // LSU FSM current state +type_scr1_lsu_fsm_e lsu_fsm_next; // LSU FSM next state +logic lsu_fsm_idle; // LSU FSM is in IDLE state + +// LSU Command register signals +logic lsu_cmd_upd; // LSU Command register update +type_scr1_lsu_cmd_sel_e lsu_cmd_ff; // LSU Command register value +logic lsu_cmd_ff_load; // Registered LSU Command is load +logic lsu_cmd_ff_store; // Registered LSU Command is store + +// DMEM command and width flags +logic dmem_cmd_load; // DMEM command is load +logic dmem_cmd_store; // DMEM Command is store +logic dmem_wdth_word; // DMEM data width is WORD +logic dmem_wdth_hword; // DMEM data width is HALFWORD +logic dmem_wdth_byte; // DMEM data width is BYTE + +// DMEM response and request control signals +logic dmem_resp_ok; // DMEM response is OK +logic dmem_resp_er; // DMEM response is erroneous +logic dmem_resp_received; // DMEM response is received +logic dmem_req_vd; // DMEM request is valid (req_ack received) + +// Exceptions signals +logic lsu_exc_req; // LSU exception request +logic dmem_addr_mslgn; // DMEM address is misaligned +logic dmem_addr_mslgn_l; // DMEM load address is misaligned +logic dmem_addr_mslgn_s; // DMEM store address is misaligned +`ifdef SCR1_TDU_EN +logic lsu_exc_hwbrk; // LSU hardware breakpoint exception +`endif // SCR1_TDU_EN + +//------------------------------------------------------------------------------ +// Control logic +//------------------------------------------------------------------------------ + +// DMEM response and request control signals +assign dmem_resp_ok = (dmem2lsu_resp_i == SCR1_MEM_RESP_RDY_OK); +assign dmem_resp_er = (dmem2lsu_resp_i == SCR1_MEM_RESP_RDY_ER); +assign dmem_resp_received = dmem_resp_ok | dmem_resp_er; +assign dmem_req_vd = exu2lsu_req_i & dmem2lsu_req_ack_i & ~lsu_exc_req; + +// LSU load and store command flags +assign dmem_cmd_load = (exu2lsu_cmd_i == SCR1_LSU_CMD_LB ) + | (exu2lsu_cmd_i == SCR1_LSU_CMD_LBU) + | (exu2lsu_cmd_i == SCR1_LSU_CMD_LH ) + | (exu2lsu_cmd_i == SCR1_LSU_CMD_LHU) + | (exu2lsu_cmd_i == SCR1_LSU_CMD_LW ); +assign dmem_cmd_store = (exu2lsu_cmd_i == SCR1_LSU_CMD_SB ) + | (exu2lsu_cmd_i == SCR1_LSU_CMD_SH ) + | (exu2lsu_cmd_i == SCR1_LSU_CMD_SW ); + +// LSU data width flags +assign dmem_wdth_word = (exu2lsu_cmd_i == SCR1_LSU_CMD_LW ) + | (exu2lsu_cmd_i == SCR1_LSU_CMD_SW ); +assign dmem_wdth_hword = (exu2lsu_cmd_i == SCR1_LSU_CMD_LH ) + | (exu2lsu_cmd_i == SCR1_LSU_CMD_LHU) + | (exu2lsu_cmd_i == SCR1_LSU_CMD_SH ); +assign dmem_wdth_byte = (exu2lsu_cmd_i == SCR1_LSU_CMD_LB ) + | (exu2lsu_cmd_i == SCR1_LSU_CMD_LBU) + | (exu2lsu_cmd_i == SCR1_LSU_CMD_SB ); + +// LSU command register +assign lsu_cmd_upd = lsu_fsm_idle & dmem_req_vd; + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + lsu_cmd_ff <= SCR1_LSU_CMD_NONE; + end else if (lsu_cmd_upd) begin + lsu_cmd_ff <= exu2lsu_cmd_i; + end +end + +// LSU registered load and store command flags +assign lsu_cmd_ff_load = (lsu_cmd_ff == SCR1_LSU_CMD_LB ) + | (lsu_cmd_ff == SCR1_LSU_CMD_LBU) + | (lsu_cmd_ff == SCR1_LSU_CMD_LH ) + | (lsu_cmd_ff == SCR1_LSU_CMD_LHU) + | (lsu_cmd_ff == SCR1_LSU_CMD_LW ); +assign lsu_cmd_ff_store = (lsu_cmd_ff == SCR1_LSU_CMD_SB ) + | (lsu_cmd_ff == SCR1_LSU_CMD_SH ) + | (lsu_cmd_ff == SCR1_LSU_CMD_SW ); + +//------------------------------------------------------------------------------ +// LSU FSM +//------------------------------------------------------------------------------ + // + // LSU FSM is used to control the LSU <-> DMEM interface + // +// + +// Updating LSU FSM state +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + lsu_fsm_curr <= SCR1_LSU_FSM_IDLE; + end else begin + lsu_fsm_curr <= lsu_fsm_next; + end +end + +// LSU FSM next state logic +always_comb begin + case (lsu_fsm_curr) + SCR1_LSU_FSM_IDLE: begin + lsu_fsm_next = dmem_req_vd ? SCR1_LSU_FSM_BUSY + : SCR1_LSU_FSM_IDLE; + end + SCR1_LSU_FSM_BUSY: begin + lsu_fsm_next = dmem_resp_received ? SCR1_LSU_FSM_IDLE + : SCR1_LSU_FSM_BUSY; + end + endcase +end + +assign lsu_fsm_idle = (lsu_fsm_curr == SCR1_LSU_FSM_IDLE); + +//------------------------------------------------------------------------------ +// Exceptions logic +//------------------------------------------------------------------------------ + // + // The following types of exceptions are supported: + // - Load address misalign + // - Load access fault + // - Store address misalign + // - Store access fault + // - LSU breakpoint exception +// + +// DMEM addr misalign logic +assign dmem_addr_mslgn = exu2lsu_req_i & ( (dmem_wdth_hword & exu2lsu_addr_i[0]) + | (dmem_wdth_word & |exu2lsu_addr_i[1:0])); +assign dmem_addr_mslgn_l = dmem_addr_mslgn & dmem_cmd_load; +assign dmem_addr_mslgn_s = dmem_addr_mslgn & dmem_cmd_store; + +// Exception code logic +always_comb begin + case (1'b1) + dmem_resp_er : lsu2exu_exc_code_o = lsu_cmd_ff_load ? SCR1_EXC_CODE_LD_ACCESS_FAULT + : lsu_cmd_ff_store ? SCR1_EXC_CODE_ST_ACCESS_FAULT + : SCR1_EXC_CODE_INSTR_MISALIGN; +`ifdef SCR1_TDU_EN + lsu_exc_hwbrk : lsu2exu_exc_code_o = SCR1_EXC_CODE_BREAKPOINT; +`endif // SCR1_TDU_EN + dmem_addr_mslgn_l: lsu2exu_exc_code_o = SCR1_EXC_CODE_LD_ADDR_MISALIGN; + dmem_addr_mslgn_s: lsu2exu_exc_code_o = SCR1_EXC_CODE_ST_ADDR_MISALIGN; + default : lsu2exu_exc_code_o = SCR1_EXC_CODE_INSTR_MISALIGN; + endcase // 1'b1 +end + +assign lsu_exc_req = dmem_addr_mslgn_l | dmem_addr_mslgn_s +`ifdef SCR1_TDU_EN + | lsu_exc_hwbrk +`endif // SCR1_TDU_EN +; + +//------------------------------------------------------------------------------ +// LSU <-> EXU interface +//------------------------------------------------------------------------------ + +assign lsu2exu_rdy_o = dmem_resp_received; +assign lsu2exu_exc_o = dmem_resp_er | lsu_exc_req; + +// Sign- or zero-extending data received from DMEM +always_comb begin + case (lsu_cmd_ff) + SCR1_LSU_CMD_LH : lsu2exu_ldata_o = {{16{dmem2lsu_rdata_i[15]}}, dmem2lsu_rdata_i[15:0]}; + SCR1_LSU_CMD_LHU: lsu2exu_ldata_o = { 16'b0, dmem2lsu_rdata_i[15:0]}; + SCR1_LSU_CMD_LB : lsu2exu_ldata_o = {{24{dmem2lsu_rdata_i[7]}}, dmem2lsu_rdata_i[7:0]}; + SCR1_LSU_CMD_LBU: lsu2exu_ldata_o = { 24'b0, dmem2lsu_rdata_i[7:0]}; + default : lsu2exu_ldata_o = dmem2lsu_rdata_i; + endcase // lsu_cmd_ff +end + +//------------------------------------------------------------------------------ +// LSU <-> DMEM interface +//------------------------------------------------------------------------------ + +assign lsu2dmem_req_o = exu2lsu_req_i & ~lsu_exc_req & lsu_fsm_idle; +assign lsu2dmem_addr_o = exu2lsu_addr_i; +assign lsu2dmem_wdata_o = exu2lsu_sdata_i; +assign lsu2dmem_cmd_o = dmem_cmd_store ? SCR1_MEM_CMD_WR : SCR1_MEM_CMD_RD; +assign lsu2dmem_width_o = dmem_wdth_byte ? SCR1_MEM_WIDTH_BYTE + : dmem_wdth_hword ? SCR1_MEM_WIDTH_HWORD + : SCR1_MEM_WIDTH_WORD; + +`ifdef SCR1_TDU_EN +//------------------------------------------------------------------------------ +// LSU <-> TDU interface +//------------------------------------------------------------------------------ + +assign lsu2tdu_dmon_o.vd = exu2lsu_req_i & lsu_fsm_idle & ~tdu2lsu_ibrkpt_exc_req_i; +assign lsu2tdu_dmon_o.addr = exu2lsu_addr_i; +assign lsu2tdu_dmon_o.load = dmem_cmd_load; +assign lsu2tdu_dmon_o.store = dmem_cmd_store; + +assign lsu_exc_hwbrk = (exu2lsu_req_i & tdu2lsu_ibrkpt_exc_req_i) + | tdu2lsu_dbrkpt_exc_req_i; + +`endif // SCR1_TDU_EN + +`ifdef SCR1_TRGT_SIMULATION +//------------------------------------------------------------------------------ +// Assertions +//------------------------------------------------------------------------------ + +// X checks + +SCR1_SVA_LSU_XCHECK_CTRL : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown({exu2lsu_req_i, lsu_fsm_curr +`ifdef SCR1_TDU_EN + , tdu2lsu_ibrkpt_exc_req_i, tdu2lsu_dbrkpt_exc_req_i +`endif // SCR1_TDU_EN + }) + ) else $error("LSU Error: unknown control value"); + +SCR1_SVA_LSU_XCHECK_CMD : assert property ( + @(negedge clk) disable iff (~rst_n) + exu2lsu_req_i |-> !$isunknown({exu2lsu_cmd_i, exu2lsu_addr_i}) + ) else $error("LSU Error: undefined CMD or address"); + +SCR1_SVA_LSU_XCHECK_SDATA : assert property ( + @(negedge clk) disable iff (~rst_n) + (exu2lsu_req_i & (lsu2dmem_cmd_o == SCR1_MEM_CMD_WR)) |-> !$isunknown({exu2lsu_sdata_i}) + ) else $error("LSU Error: undefined store data"); + +SCR1_SVA_LSU_XCHECK_EXC : assert property ( + @(negedge clk) disable iff (~rst_n) + lsu2exu_exc_o |-> !$isunknown(lsu2exu_exc_code_o) + ) else $error("LSU Error: exception code undefined"); + +SCR1_SVA_LSU_IMEM_CTRL : assert property ( + @(negedge clk) disable iff (~rst_n) + lsu2dmem_req_o |-> !$isunknown({lsu2dmem_cmd_o, lsu2dmem_width_o, lsu2dmem_addr_o}) + ) else $error("LSU Error: undefined dmem control"); + +SCR1_SVA_LSU_IMEM_ACK : assert property ( + @(negedge clk) disable iff (~rst_n) + lsu2dmem_req_o |-> !$isunknown(dmem2lsu_req_ack_i) + ) else $error("LSU Error: undefined dmem ack"); + +SCR1_SVA_LSU_IMEM_WDATA : assert property ( + @(negedge clk) disable iff (~rst_n) + lsu2dmem_req_o & (lsu2dmem_cmd_o == SCR1_MEM_CMD_WR) + |-> !$isunknown(lsu2dmem_wdata_o[8:0]) + ) else $error("LSU Error: undefined dmem wdata"); + +// Behavior checks + +SCR1_SVA_LSU_EXC_ONEHOT : assert property ( + @(negedge clk) disable iff (~rst_n) + $onehot0({dmem_resp_er, dmem_addr_mslgn_l, dmem_addr_mslgn_s}) + ) else $error("LSU Error: more than one exception at a time"); + +SCR1_SVA_LSU_UNEXPECTED_DMEM_RESP : assert property ( + @(negedge clk) disable iff (~rst_n) + lsu_fsm_idle |-> ~dmem_resp_received + ) else $error("LSU Error: not expecting memory response"); + +SCR1_SVA_LSU_REQ_EXC : assert property ( + @(negedge clk) disable iff (~rst_n) + lsu2exu_exc_o |-> exu2lsu_req_i + ) else $error("LSU Error: impossible exception"); + +`ifdef SCR1_TDU_EN + +SCR1_COV_LSU_MISALIGN_BRKPT : cover property ( + @(negedge clk) disable iff (~rst_n) + (dmem_addr_mslgn_l | dmem_addr_mslgn_s) & lsu_exc_hwbrk +); +`endif // SCR1_TDU_EN + +`endif // SCR1_TRGT_SIMULATION + +endmodule : scr1_pipe_lsu diff --git a/src/rtl/scr1/scr1_pipe_mprf.sv b/src/rtl/scr1/scr1_pipe_mprf.sv new file mode 100644 index 0000000..06d4057 --- /dev/null +++ b/src/rtl/scr1/scr1_pipe_mprf.sv @@ -0,0 +1,167 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Multi Port Register File (MPRF) +/// + +`include "scr1_arch_description.svh" +`include "scr1_arch_types.svh" + +module scr1_pipe_mprf ( + // Common +`ifdef SCR1_MPRF_RST_EN + input logic rst_n, // MPRF reset +`endif // SCR1_MPRF_RST_EN + input logic clk, // MPRF clock + + // EXU <-> MPRF interface + input logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rs1_addr_i, // MPRF rs1 read address + output logic [`SCR1_XLEN-1:0] mprf2exu_rs1_data_o, // MPRF rs1 read data + input logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rs2_addr_i, // MPRF rs2 read address + output logic [`SCR1_XLEN-1:0] mprf2exu_rs2_data_o, // MPRF rs2 read data + input logic exu2mprf_w_req_i, // MPRF write request + input logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rd_addr_i, // MPRF rd write address + input logic [`SCR1_XLEN-1:0] exu2mprf_rd_data_i // MPRF rd write data +); + +//------------------------------------------------------------------------------- +// Local types declaration +//------------------------------------------------------------------------------- + +logic wr_req_vd; + +logic rs1_addr_vd; +logic rs2_addr_vd; + +`ifdef SCR1_MPRF_RAM +logic rs1_addr_vd_ff; +logic rs2_addr_vd_ff; + +logic rs1_new_data_req; +logic rs2_new_data_req; +logic rs1_new_data_req_ff; +logic rs2_new_data_req_ff; +logic read_new_data_req; + +logic [`SCR1_XLEN-1:0] rd_data_ff; + +logic [`SCR1_XLEN-1:0] rs1_data_ff; +logic [`SCR1_XLEN-1:0] rs2_data_ff; + +// when using RAM, 2 memories are needed because 3 simultaneous independent +// write/read operations can occur + `ifdef SCR1_TRGT_FPGA_INTEL_MAX10 +(* ramstyle = "M9K" *) logic [`SCR1_XLEN-1:0] mprf_int [1:`SCR1_MPRF_SIZE-1]; +(* ramstyle = "M9K" *) logic [`SCR1_XLEN-1:0] mprf_int2 [1:`SCR1_MPRF_SIZE-1]; + `elsif SCR1_TRGT_FPGA_INTEL_ARRIAV +(* ramstyle = "M10K" *) logic [`SCR1_XLEN-1:0] mprf_int [1:`SCR1_MPRF_SIZE-1]; +(* ramstyle = "M10K" *) logic [`SCR1_XLEN-1:0] mprf_int2 [1:`SCR1_MPRF_SIZE-1]; + `else +logic [`SCR1_XLEN-1:0] mprf_int [1:`SCR1_MPRF_SIZE-1]; +logic [`SCR1_XLEN-1:0] mprf_int2 [1:`SCR1_MPRF_SIZE-1]; + `endif +`else // distributed logic implementation +type_scr1_mprf_v [1:`SCR1_MPRF_SIZE-1] mprf_int; +`endif + +//------------------------------------------------------------------------------ +// MPRF control logic +//------------------------------------------------------------------------------ + +// control signals common for distributed logic and RAM implementations +assign rs1_addr_vd = |exu2mprf_rs1_addr_i; +assign rs2_addr_vd = |exu2mprf_rs2_addr_i; + +assign wr_req_vd = exu2mprf_w_req_i & |exu2mprf_rd_addr_i; + +// RAM implementation specific control signals +`ifdef SCR1_MPRF_RAM +assign rs1_new_data_req = wr_req_vd & ( exu2mprf_rs1_addr_i == exu2mprf_rd_addr_i ); +assign rs2_new_data_req = wr_req_vd & ( exu2mprf_rs2_addr_i == exu2mprf_rd_addr_i ); +assign read_new_data_req = rs1_new_data_req | rs2_new_data_req; + +always_ff @( posedge clk ) begin + rs1_addr_vd_ff <= rs1_addr_vd; + rs2_addr_vd_ff <= rs2_addr_vd; + rs1_new_data_req_ff <= rs1_new_data_req; + rs2_new_data_req_ff <= rs2_new_data_req; +end +`endif // SCR1_MPRF_RAM + +`ifdef SCR1_MPRF_RAM +//------------------------------------------------------------------------------- +// RAM implementation +//------------------------------------------------------------------------------- + +// RAM is implemented with 2 simple dual-port memories with sync read operation; +// logic for "write-first" RDW behavior is implemented externally to the embedded +// memory blocks + +// bypass new wr_data to the read output if write/read collision occurs +assign mprf2exu_rs1_data_o = ( rs1_new_data_req_ff ) ? rd_data_ff + : (( rs1_addr_vd_ff ) ? rs1_data_ff + : '0 ); + +assign mprf2exu_rs2_data_o = ( rs2_new_data_req_ff ) ? rd_data_ff + : (( rs2_addr_vd_ff ) ? rs2_data_ff + : '0 ); + +always_ff @( posedge clk ) begin + if ( read_new_data_req ) begin + rd_data_ff <= exu2mprf_rd_data_i; + end +end + +// synchronous read operation +always_ff @( posedge clk ) begin + rs1_data_ff <= mprf_int[exu2mprf_rs1_addr_i]; + rs2_data_ff <= mprf_int2[exu2mprf_rs2_addr_i]; +end + +// write operation +always_ff @( posedge clk ) begin + if ( wr_req_vd ) begin + mprf_int[exu2mprf_rd_addr_i] <= exu2mprf_rd_data_i; + mprf_int2[exu2mprf_rd_addr_i] <= exu2mprf_rd_data_i; + end +end +`else // distributed logic implementation +//------------------------------------------------------------------------------ +// distributed logic implementation +//------------------------------------------------------------------------------ + +// asynchronous read operation +assign mprf2exu_rs1_data_o = ( rs1_addr_vd ) ? mprf_int[exu2mprf_rs1_addr_i] : '0; +assign mprf2exu_rs2_data_o = ( rs2_addr_vd ) ? mprf_int[exu2mprf_rs2_addr_i] : '0; + +// write operation + `ifdef SCR1_MPRF_RST_EN +always_ff @( posedge clk, negedge rst_n ) begin + if ( ~rst_n ) begin + mprf_int <= '{default: '0}; + end else if ( wr_req_vd ) begin + mprf_int[exu2mprf_rd_addr_i] <= exu2mprf_rd_data_i; + end +end + `else // ~SCR1_MPRF_RST_EN +always_ff @( posedge clk ) begin + if ( wr_req_vd ) begin + mprf_int[exu2mprf_rd_addr_i] <= exu2mprf_rd_data_i; + end +end + `endif // ~SCR1_MPRF_RST_EN +`endif + +`ifdef SCR1_TRGT_SIMULATION +//------------------------------------------------------------------------------- +// Assertion +//------------------------------------------------------------------------------- +`ifdef SCR1_MPRF_RST_EN +SCR1_SVA_MPRF_WRITEX : assert property ( + @(negedge clk) disable iff (~rst_n) + exu2mprf_w_req_i |-> !$isunknown({exu2mprf_rd_addr_i, (|exu2mprf_rd_addr_i ? exu2mprf_rd_data_i : `SCR1_XLEN'd0)}) + ) else $error("MPRF error: unknown values"); +`endif // SCR1_MPRF_RST_EN + +`endif // SCR1_TRGT_SIMULATION + +endmodule : scr1_pipe_mprf diff --git a/src/rtl/scr1/scr1_pipe_tdu.sv b/src/rtl/scr1/scr1_pipe_tdu.sv new file mode 100644 index 0000000..28edd29 --- /dev/null +++ b/src/rtl/scr1/scr1_pipe_tdu.sv @@ -0,0 +1,610 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Trigger Debug Unit (TDU) +/// + +//------------------------------------------------------------------------------ + // + // Functionality: + // - Provides read/write interface for TDU CSRs + // - Provides triggers functionality: + // - Supports triggers either in both Debug and M modes or in Debug mode only + // - Supports virtual address matching (load, store, exec) triggers + // - Supports instruction count triggers + // - Supports the following actions on trigger firing: + // - Breakpoint exception raising + // - Debug Mode entering + // - Supports triggers chaining + // + // Structure: + // - CSR read/write i/f + // - TDU CSRs: + // - TSELECT + // - TDATA1/MCONTROL/ICOUNT + // - TDATA2 + // - TINFO + // - TDU <-> EXU i/f + // - TDU <-> LSU i/f + // - TDU <-> HDU i/f +//------------------------------------------------------------------------------ + +`include "scr1_arch_description.svh" + +`ifdef SCR1_TDU_EN +`include "scr1_riscv_isa_decoding.svh" +`include "scr1_tdu.svh" + +module scr1_pipe_tdu ( + // Common signals + input logic rst_n, // TDU reset + input logic clk, // TDU clock + input logic clk_en, // TDU clock enable + input logic tdu_dsbl_i, // TDU Disable + + // TDU <-> CSR interface + input logic csr2tdu_req_i, // CSR-TDU i/f request + input type_scr1_csr_cmd_sel_e csr2tdu_cmd_i, // CSR-TDU i/f command + input logic [SCR1_CSR_ADDR_TDU_OFFS_W-1:0] csr2tdu_addr_i, // CSR-TDU i/f address + input logic [SCR1_TDU_DATA_W-1:0] csr2tdu_wdata_i, // CSR-TDU i/f write data + output logic [SCR1_TDU_DATA_W-1:0] tdu2csr_rdata_o, // CSR-TDU i/f read data + output type_scr1_csr_resp_e tdu2csr_resp_o, // CSR-TDU i/f response + + // TDU <-> EXU interface + input type_scr1_brkm_instr_mon_s exu2tdu_imon_i, // Instruction stream monitoring + output logic [SCR1_TDU_ALLTRIG_NUM-1 : 0] tdu2exu_ibrkpt_match_o, // Instruction BP match + output logic tdu2exu_ibrkpt_exc_req_o, // Instruction BP exception request + input logic [SCR1_TDU_ALLTRIG_NUM-1 : 0] exu2tdu_bp_retire_i, // Map of BPs being retired + + // TDU <-> LSU interface +`ifndef SCR1_TDU_EN + output logic tdu2lsu_brk_en_o, // TDU-LSU Breakpoint enable +`endif // SCR1_TDU_EN + output logic tdu2lsu_ibrkpt_exc_req_o, // TDU-LSU Instruction BP exception request + input type_scr1_brkm_lsu_mon_s lsu2tdu_dmon_i, // TDU-LSU Data address stream monitoring + output logic [SCR1_TDU_MTRIG_NUM-1 : 0] tdu2lsu_dbrkpt_match_o, // TDU-LSU Data BP match + output logic tdu2lsu_dbrkpt_exc_req_o, // TDU-LSU Data BP exception request + + // TDU <-> HDU interface + output logic tdu2hdu_dmode_req_o // Debug Mode redirection request +); + +//------------------------------------------------------------------------------ +// Local parameters declaration +//------------------------------------------------------------------------------ + +localparam int unsigned MTRIG_NUM = SCR1_TDU_MTRIG_NUM; +localparam int unsigned ALLTRIG_NUM = SCR1_TDU_ALLTRIG_NUM; +localparam int unsigned ALLTRIG_W = $clog2(ALLTRIG_NUM+1); + +//------------------------------------------------------------------------------ +// Local signals declaration +//------------------------------------------------------------------------------ + +// TDU CSRs read/write i/f signals +//------------------------------------------------------------------------------ + +// Write signals +logic csr_wr_req; +logic [SCR1_TDU_DATA_W-1:0] csr_wr_data; + +// Register select +logic csr_addr_tselect; +logic [MTRIG_NUM-1:0] csr_addr_mcontrol; +logic [MTRIG_NUM-1:0] csr_addr_tdata2; +`ifdef SCR1_TDU_ICOUNT_EN +logic csr_addr_icount; +`endif // SCR1_TDU_ICOUNT_EN + +// TDU CSRs +//------------------------------------------------------------------------------ + +// TSELECT register +logic csr_tselect_upd; +logic [ALLTRIG_W-1:0] csr_tselect_ff; + +// MCONTROL register +logic [MTRIG_NUM-1:0] csr_mcontrol_wr_req; +logic [MTRIG_NUM-1:0] csr_mcontrol_clk_en; +logic [MTRIG_NUM-1:0] csr_mcontrol_upd; + +logic [MTRIG_NUM-1:0] csr_mcontrol_dmode_ff; +logic [MTRIG_NUM-1:0] csr_mcontrol_dmode_next; +logic [MTRIG_NUM-1:0] csr_mcontrol_m_ff; +logic [MTRIG_NUM-1:0] csr_mcontrol_m_next; +logic [MTRIG_NUM-1:0] csr_mcontrol_exec_ff; +logic [MTRIG_NUM-1:0] csr_mcontrol_exec_next; +logic [MTRIG_NUM-1:0] csr_mcontrol_load_ff; +logic [MTRIG_NUM-1:0] csr_mcontrol_load_next; +logic [MTRIG_NUM-1:0] csr_mcontrol_store_ff; +logic [MTRIG_NUM-1:0] csr_mcontrol_store_next; +logic [MTRIG_NUM-1:0] csr_mcontrol_action_ff; +logic [MTRIG_NUM-1:0] csr_mcontrol_action_next; +logic [MTRIG_NUM-1:0] csr_mcontrol_hit_ff; +logic [MTRIG_NUM-1:0] csr_mcontrol_hit_next; + +logic [MTRIG_NUM-1:0] csr_mcontrol_exec_hit; +logic [MTRIG_NUM-1:0] csr_mcontrol_ldst_hit; + +// ICOUNT register +`ifdef SCR1_TDU_ICOUNT_EN +logic csr_icount_wr_req; +logic csr_icount_clk_en; +logic csr_icount_upd; + +logic csr_icount_dmode_ff; +logic csr_icount_dmode_next; +logic csr_icount_m_ff; +logic csr_icount_m_next; +logic csr_icount_action_ff; +logic csr_icount_action_next; +logic csr_icount_hit_ff; +logic csr_icount_hit_next; +logic [SCR1_TDU_ICOUNT_COUNT_HI-SCR1_TDU_ICOUNT_COUNT_LO:0] + csr_icount_count_ff; +logic [SCR1_TDU_ICOUNT_COUNT_HI-SCR1_TDU_ICOUNT_COUNT_LO:0] + csr_icount_count_next; +logic csr_icount_skip_ff; +logic csr_icount_skip_next; + +logic csr_icount_decr_en; +logic csr_icount_count_decr; +logic csr_icount_skip_dsbl; +logic csr_icount_hit; +`endif // SCR1_TDU_ICOUNT_EN + +// TDATA2 register +logic [MTRIG_NUM-1:0] csr_tdata2_upd; +logic [MTRIG_NUM-1:0] [SCR1_TDU_DATA_W-1:0] csr_tdata2_ff; + +//------------------------------------------------------------------------------ +// CSR read/write interface +//------------------------------------------------------------------------------ + +// Read logic +//------------------------------------------------------------------------------ + +assign tdu2csr_resp_o = csr2tdu_req_i ? SCR1_CSR_RESP_OK : SCR1_CSR_RESP_ER; + +always_comb begin + tdu2csr_rdata_o = '0; + if (csr2tdu_req_i) begin + case (csr2tdu_addr_i) + SCR1_CSR_ADDR_TDU_OFFS_TSELECT: begin + tdu2csr_rdata_o = {'0, csr_tselect_ff}; + end + SCR1_CSR_ADDR_TDU_OFFS_TDATA2 : begin + for(int unsigned i = 0; i < MTRIG_NUM; ++i) begin + if(csr_tselect_ff == ALLTRIG_W'(i)) begin + tdu2csr_rdata_o = csr_tdata2_ff[i]; + end + end + end + SCR1_CSR_ADDR_TDU_OFFS_TDATA1 : begin + for(int unsigned i = 0; i < MTRIG_NUM; ++i) begin + if(csr_tselect_ff == ALLTRIG_W'(i)) begin + tdu2csr_rdata_o[SCR1_TDU_TDATA1_TYPE_HI: + SCR1_TDU_TDATA1_TYPE_LO] = SCR1_TDU_MCONTROL_TYPE_VAL; + tdu2csr_rdata_o[SCR1_TDU_TDATA1_DMODE] = csr_mcontrol_dmode_ff[i]; + tdu2csr_rdata_o[SCR1_TDU_MCONTROL_MASKMAX_HI: + SCR1_TDU_MCONTROL_MASKMAX_LO] = SCR1_TDU_MCONTROL_MASKMAX_VAL; + tdu2csr_rdata_o[SCR1_TDU_MCONTROL_HIT] = csr_mcontrol_hit_ff[i]; + tdu2csr_rdata_o[SCR1_TDU_MCONTROL_SELECT] = SCR1_TDU_MCONTROL_SELECT_VAL; + tdu2csr_rdata_o[SCR1_TDU_MCONTROL_TIMING] = SCR1_TDU_MCONTROL_TIMING_VAL; + tdu2csr_rdata_o[SCR1_TDU_MCONTROL_ACTION_HI: + SCR1_TDU_MCONTROL_ACTION_LO] = {5'b0, csr_mcontrol_action_ff[i]}; + tdu2csr_rdata_o[SCR1_TDU_MCONTROL_CHAIN] = 1'b0; + tdu2csr_rdata_o[SCR1_TDU_MCONTROL_MATCH_HI: + SCR1_TDU_MCONTROL_MATCH_LO] = 4'b0; + tdu2csr_rdata_o[SCR1_TDU_MCONTROL_M] = csr_mcontrol_m_ff[i]; + tdu2csr_rdata_o[SCR1_TDU_MCONTROL_RESERVEDA] = SCR1_TDU_MCONTROL_RESERVEDA_VAL; + tdu2csr_rdata_o[SCR1_TDU_MCONTROL_S] = 1'b0; + tdu2csr_rdata_o[SCR1_TDU_MCONTROL_U] = 1'b0; + tdu2csr_rdata_o[SCR1_TDU_MCONTROL_EXECUTE] = csr_mcontrol_exec_ff [i]; + tdu2csr_rdata_o[SCR1_TDU_MCONTROL_STORE] = csr_mcontrol_store_ff[i]; + tdu2csr_rdata_o[SCR1_TDU_MCONTROL_LOAD] = csr_mcontrol_load_ff [i]; + end + end +`ifdef SCR1_TDU_ICOUNT_EN + if(csr_tselect_ff == ALLTRIG_W'(SCR1_TDU_ALLTRIG_NUM - 1'b1)) begin + tdu2csr_rdata_o[SCR1_TDU_TDATA1_TYPE_HI: + SCR1_TDU_TDATA1_TYPE_LO] = SCR1_TDU_ICOUNT_TYPE_VAL; + tdu2csr_rdata_o[SCR1_TDU_TDATA1_DMODE] = csr_icount_dmode_ff; + tdu2csr_rdata_o[SCR1_TDU_ICOUNT_HIT] = csr_icount_hit_ff; + tdu2csr_rdata_o[SCR1_TDU_ICOUNT_COUNT_HI: + SCR1_TDU_ICOUNT_COUNT_LO] = csr_icount_count_ff; + tdu2csr_rdata_o[SCR1_TDU_ICOUNT_U] = 1'b0; + tdu2csr_rdata_o[SCR1_TDU_ICOUNT_S] = 1'b0; + tdu2csr_rdata_o[SCR1_TDU_ICOUNT_M] = csr_icount_m_ff; + tdu2csr_rdata_o[SCR1_TDU_ICOUNT_ACTION_HI: + SCR1_TDU_ICOUNT_ACTION_LO] = {5'b0, csr_icount_action_ff}; + end +`endif // SCR1_TDU_ICOUNT_EN + end + SCR1_CSR_ADDR_TDU_OFFS_TINFO : begin + for(int unsigned i = 0; i < MTRIG_NUM; ++i) begin + if(csr_tselect_ff == ALLTRIG_W'(i)) begin + tdu2csr_rdata_o[SCR1_TDU_MCONTROL_TYPE_VAL] = 1'b1; + end + end +`ifdef SCR1_TDU_ICOUNT_EN + if(csr_tselect_ff == ALLTRIG_W'(SCR1_TDU_ALLTRIG_NUM - 1'b1)) begin + tdu2csr_rdata_o[SCR1_TDU_ICOUNT_TYPE_VAL] = 1'b1; + end +`endif // SCR1_TDU_ICOUNT_EN + end + default : begin + end + endcase + end +end + +// Write logic +//------------------------------------------------------------------------------ + +always_comb begin + csr_wr_req = 1'b0; + csr_wr_data = '0; + + case (csr2tdu_cmd_i) + SCR1_CSR_CMD_WRITE: begin + csr_wr_req = 1'b1; + csr_wr_data = csr2tdu_wdata_i; + end + SCR1_CSR_CMD_SET : begin + csr_wr_req = |csr2tdu_wdata_i; + csr_wr_data = tdu2csr_rdata_o | csr2tdu_wdata_i; + end + SCR1_CSR_CMD_CLEAR: begin + csr_wr_req = |csr2tdu_wdata_i; + csr_wr_data = tdu2csr_rdata_o & ~csr2tdu_wdata_i; + end + default : begin + end + endcase +end + +// Register selection +//------------------------------------------------------------------------------ + +always_comb begin + csr_addr_tselect = 1'b0; + csr_addr_tdata2 = '0; + csr_addr_mcontrol = '0; +`ifdef SCR1_TDU_ICOUNT_EN + csr_addr_icount = '0; +`endif // SCR1_TDU_ICOUNT_EN + + if (csr2tdu_req_i) begin + case (csr2tdu_addr_i) + SCR1_CSR_ADDR_TDU_OFFS_TSELECT: begin + csr_addr_tselect = 1'b1; + end + SCR1_CSR_ADDR_TDU_OFFS_TDATA1 : begin + for(int unsigned i = 0; i < MTRIG_NUM; ++i) begin + if(csr_tselect_ff == ALLTRIG_W'(i)) begin + csr_addr_mcontrol[i] = 1'b1; + end + end +`ifdef SCR1_TDU_ICOUNT_EN + if(csr_tselect_ff == ALLTRIG_W'(SCR1_TDU_ALLTRIG_NUM - 1'b1)) begin + csr_addr_icount = 1'b1; + end +`endif // SCR1_TDU_ICOUNT_EN + end + SCR1_CSR_ADDR_TDU_OFFS_TDATA2 : begin + for(int unsigned i = 0; i < MTRIG_NUM; ++i) begin + if(csr_tselect_ff == ALLTRIG_W'(i) ) begin + csr_addr_tdata2[i] = 1'b1; + end + end + end + default : begin + end + endcase + end +end + +//------------------------------------------------------------------------------ +// TDU CSRs +//------------------------------------------------------------------------------ +// + // TDU CSRs consist of the following registers: + // - TSELECT + // - TDATA1/MCONTROL/ICOUNT (depending on the type field value) + // - TDATA2 +// + +// TSELECT register +//------------------------------------------------------------------------------ +// Determines which trigger is accessible through the other trigger registers + +assign csr_tselect_upd = clk_en & csr_addr_tselect & csr_wr_req + & (csr_wr_data[ALLTRIG_W-1:0] < ALLTRIG_W'(ALLTRIG_NUM)); + +always_ff @(negedge rst_n, posedge clk) begin + if(~rst_n) begin + csr_tselect_ff <= '0; + end else if(csr_tselect_upd) begin + csr_tselect_ff <= csr_wr_data[ALLTRIG_W-1:0]; + end +end + +`ifdef SCR1_TDU_ICOUNT_EN +// ICOUNT register +//------------------------------------------------------------------------------ +// Provides a trigger that fires when the certain number of instructions has retired +// Is intended to be used as a single step trigger (in this case count must be 1) + +assign csr_icount_wr_req = csr_addr_icount & csr_wr_req; +assign csr_icount_clk_en = clk_en & (csr_icount_wr_req | csr_icount_m_ff); +assign csr_icount_upd = ~csr_icount_dmode_ff + ? csr_icount_wr_req + : tdu_dsbl_i & csr_icount_wr_req; + +always_ff @(negedge rst_n, posedge clk) begin + if(~rst_n) begin + csr_icount_dmode_ff <= 1'b0; + csr_icount_m_ff <= 1'b0; + csr_icount_action_ff <= 1'b0; + csr_icount_hit_ff <= 1'b0; + csr_icount_count_ff <= '0; + csr_icount_skip_ff <= 1'b0; + end else if (csr_icount_clk_en) begin + csr_icount_dmode_ff <= csr_icount_dmode_next; + csr_icount_m_ff <= csr_icount_m_next; + csr_icount_action_ff <= csr_icount_action_next; + csr_icount_hit_ff <= csr_icount_hit_next; + csr_icount_count_ff <= csr_icount_count_next; + csr_icount_skip_ff <= csr_icount_skip_next; + end +end + +assign csr_icount_decr_en = (~tdu_dsbl_i & csr_icount_m_ff) + ? exu2tdu_imon_i.vd & (csr_icount_count_ff != 14'b0) + : 1'b0; +assign csr_icount_count_decr = exu2tdu_imon_i.req & csr_icount_decr_en & ~csr_icount_skip_ff; +assign csr_icount_skip_dsbl = exu2tdu_imon_i.req & csr_icount_decr_en & csr_icount_skip_ff; + +always_comb begin + if (csr_icount_upd) begin + csr_icount_dmode_next = csr_wr_data[SCR1_TDU_TDATA1_DMODE]; + csr_icount_m_next = csr_wr_data[SCR1_TDU_ICOUNT_M]; + csr_icount_action_next = (csr_wr_data[SCR1_TDU_ICOUNT_ACTION_HI + :SCR1_TDU_ICOUNT_ACTION_LO] == 'b1); + csr_icount_hit_next = csr_wr_data[SCR1_TDU_ICOUNT_HIT]; + csr_icount_count_next = csr_wr_data[SCR1_TDU_ICOUNT_COUNT_HI:SCR1_TDU_ICOUNT_COUNT_LO]; + end else begin + csr_icount_dmode_next = csr_icount_dmode_ff; + csr_icount_m_next = csr_icount_m_ff; + csr_icount_action_next = csr_icount_action_ff; + csr_icount_hit_next = exu2tdu_bp_retire_i[ALLTRIG_NUM - 1'b1] + ? 1'b1 + : csr_icount_hit_ff; + csr_icount_count_next = csr_icount_count_decr + ? csr_icount_count_ff - 1'b1 + : csr_icount_count_ff; + end +end + +assign csr_icount_skip_next = csr_icount_wr_req ? csr_wr_data[SCR1_TDU_ICOUNT_M] + : csr_icount_skip_dsbl ? 1'b0 + : csr_icount_skip_ff; +`endif // SCR1_TDU_ICOUNT_EN + +// MCONTROL registers +//------------------------------------------------------------------------------ +// Provides a trigger that fires on the virtual address (stored in TDATA2) match +// (load, store, exec options supported). Triggers chaining supported + +genvar trig; +generate +for (trig = 0; $unsigned(trig) < MTRIG_NUM; ++trig) begin : gblock_mtrig + +assign csr_mcontrol_wr_req[trig] = csr_addr_mcontrol[trig] & csr_wr_req; +assign csr_mcontrol_clk_en[trig] = clk_en + & (csr_mcontrol_wr_req[trig] | csr_mcontrol_m_ff[trig]); +assign csr_mcontrol_upd [trig] = ~csr_mcontrol_dmode_ff[trig] + ? csr_mcontrol_wr_req[trig] + : tdu_dsbl_i & csr_mcontrol_wr_req[trig]; + +always_ff @(negedge rst_n, posedge clk) begin + if(~rst_n) begin + csr_mcontrol_dmode_ff [trig] <= 1'b0; + csr_mcontrol_m_ff [trig] <= 1'b0; + csr_mcontrol_exec_ff [trig] <= 1'b0; + csr_mcontrol_load_ff [trig] <= 1'b0; + csr_mcontrol_store_ff [trig] <= 1'b0; + csr_mcontrol_action_ff[trig] <= 1'b0; + csr_mcontrol_hit_ff [trig] <= 1'b0; + end else if(csr_mcontrol_clk_en[trig]) begin + csr_mcontrol_dmode_ff [trig] <= csr_mcontrol_dmode_next[trig]; + csr_mcontrol_m_ff [trig] <= csr_mcontrol_m_next[trig]; + csr_mcontrol_exec_ff [trig] <= csr_mcontrol_exec_next[trig]; + csr_mcontrol_load_ff [trig] <= csr_mcontrol_load_next[trig]; + csr_mcontrol_store_ff [trig] <= csr_mcontrol_store_next[trig]; + csr_mcontrol_action_ff[trig] <= csr_mcontrol_action_next[trig]; + csr_mcontrol_hit_ff [trig] <= csr_mcontrol_hit_next[trig]; + end +end + +always_comb begin + if (csr_mcontrol_upd[trig]) begin + csr_mcontrol_dmode_next [trig] = csr_wr_data[SCR1_TDU_TDATA1_DMODE]; + csr_mcontrol_m_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_M]; + csr_mcontrol_exec_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_EXECUTE]; + csr_mcontrol_load_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_LOAD]; + csr_mcontrol_store_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_STORE]; + csr_mcontrol_action_next[trig] = (csr_wr_data[SCR1_TDU_MCONTROL_ACTION_HI + :SCR1_TDU_MCONTROL_ACTION_LO] == 'b1); + csr_mcontrol_hit_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_HIT]; + end else begin + csr_mcontrol_dmode_next [trig] = csr_mcontrol_dmode_ff [trig]; + csr_mcontrol_m_next [trig] = csr_mcontrol_m_ff [trig]; + csr_mcontrol_exec_next [trig] = csr_mcontrol_exec_ff [trig]; + csr_mcontrol_load_next [trig] = csr_mcontrol_load_ff [trig]; + csr_mcontrol_store_next [trig] = csr_mcontrol_store_ff [trig]; + csr_mcontrol_action_next[trig] = csr_mcontrol_action_ff[trig]; + csr_mcontrol_hit_next [trig] = exu2tdu_bp_retire_i[trig] + ? 1'b1 + : csr_mcontrol_hit_ff[trig]; + end +end + +// TDATA2 register +//------------------------------------------------------------------------------ + +assign csr_tdata2_upd[trig] = ~csr_mcontrol_dmode_ff[trig] + ? clk_en & csr_addr_tdata2[trig] & csr_wr_req + : clk_en & csr_addr_tdata2[trig] & csr_wr_req & tdu_dsbl_i; + +always_ff @(posedge clk) begin + if (csr_tdata2_upd[trig]) begin + csr_tdata2_ff[trig] <= csr_wr_data; + end +end + +end +endgenerate // gblock_mtrig + +//------------------------------------------------------------------------------ +// TDU <-> EXU interface +//------------------------------------------------------------------------------ + +assign csr_icount_hit = ~tdu_dsbl_i & csr_icount_m_ff + ? exu2tdu_imon_i.vd & (csr_icount_count_ff == 14'b1) & ~csr_icount_skip_ff + : 1'b0; + +`ifndef SCR1_TDU_ICOUNT_EN +assign tdu2exu_ibrkpt_match_o = csr_mcontrol_exec_hit; +assign tdu2exu_ibrkpt_exc_req_o = |csr_mcontrol_exec_hit; +`else +assign tdu2exu_ibrkpt_match_o = {csr_icount_hit, csr_mcontrol_exec_hit}; +assign tdu2exu_ibrkpt_exc_req_o = |csr_mcontrol_exec_hit | csr_icount_hit; +`endif // SCR1_TDU_ICOUNT_EN + +//------------------------------------------------------------------------------ +// TDU <-> LSU interface +//------------------------------------------------------------------------------ + +// Breakpoint logic +//------------------------------------------------------------------------------ + +generate +for (trig = 0; $unsigned(trig) < MTRIG_NUM; ++trig) begin : gblock_break_trig +assign csr_mcontrol_exec_hit[trig] = ~tdu_dsbl_i + & csr_mcontrol_m_ff[trig] + & csr_mcontrol_exec_ff[trig] + & exu2tdu_imon_i.vd + & exu2tdu_imon_i.addr == csr_tdata2_ff[trig]; +end +endgenerate + +`ifndef SCR1_TDU_ICOUNT_EN +assign tdu2lsu_ibrkpt_exc_req_o = |csr_mcontrol_exec_hit; +`else +assign tdu2lsu_ibrkpt_exc_req_o = |csr_mcontrol_exec_hit | csr_icount_hit; +`endif // SCR1_TDU_ICOUNT_EN + +// Watchpoint logic +//------------------------------------------------------------------------------ + +generate +for( trig = 0; $unsigned(trig) < MTRIG_NUM; ++trig ) begin : gblock_watch_trig +assign csr_mcontrol_ldst_hit[trig] = ~tdu_dsbl_i + & csr_mcontrol_m_ff[trig] + & lsu2tdu_dmon_i.vd + & ( (csr_mcontrol_load_ff [trig] & lsu2tdu_dmon_i.load) + | (csr_mcontrol_store_ff[trig] & lsu2tdu_dmon_i.store)) + & lsu2tdu_dmon_i.addr == csr_tdata2_ff[trig]; +end +endgenerate + +assign tdu2lsu_dbrkpt_match_o = csr_mcontrol_ldst_hit; +assign tdu2lsu_dbrkpt_exc_req_o = |csr_mcontrol_ldst_hit; + +`ifndef SCR1_TDU_EN +assign tdu2lsu_brk_en_o = |csr_mcontrol_m_ff | csr_icount_m_ff; +`endif // SCR1_TDU_EN + +//------------------------------------------------------------------------------ +// TDU <-> HDU interface +//------------------------------------------------------------------------------ + +always_comb begin + tdu2hdu_dmode_req_o = 1'b0; + + for(int unsigned i = 0; i < MTRIG_NUM; ++i) begin + tdu2hdu_dmode_req_o |= (csr_mcontrol_action_ff[i] & exu2tdu_bp_retire_i[i]); + end +`ifdef SCR1_TDU_ICOUNT_EN + tdu2hdu_dmode_req_o |= (csr_icount_action_ff & exu2tdu_bp_retire_i[ALLTRIG_NUM-1]); +`endif // SCR1_TDU_ICOUNT_EN +end + +`ifdef SCR1_TRGT_SIMULATION +//------------------------------------------------------------------------------ +// Assertion +//------------------------------------------------------------------------------ + +SVA_TDU_X_CONTROL : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown({clk_en, tdu_dsbl_i, csr2tdu_req_i, + exu2tdu_imon_i.vd, lsu2tdu_dmon_i.vd, exu2tdu_bp_retire_i}) + ) else $error("TDU Error: control signals is X - %0b", {clk_en, + tdu_dsbl_i, csr2tdu_req_i, exu2tdu_imon_i.vd, lsu2tdu_dmon_i.vd, exu2tdu_bp_retire_i}); + +SVA_DM_X_CLK_EN : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown(clk_en) + ) else $error("TDU Error: clk_en control signals is X"); + +SVA_DM_X_DSBL : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown(tdu_dsbl_i) + ) else $error("TDU Error: tdu_dsbl_i control signals is X"); + +SVA_DM_X_CSR2TDU_REQ : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown(csr2tdu_req_i) + ) else $error("TDU Error: csr2tdu_req_i control signals is X"); + +SVA_DM_X_I_MON_VD : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown(exu2tdu_imon_i.vd) + ) else $error("TDU Error: exu2tdu_imon_i.vd control signals is X"); + +SVA_DM_X_D_MON_VD : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown(lsu2tdu_dmon_i.vd) + ) else $error("TDU Error: lsu2tdu_dmon_i.vd control signals is X"); + +SVA_DM_X_BP_RETIRE : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown(exu2tdu_bp_retire_i) + ) else $error("TDU Error: exu2tdu_bp_retire_i control signals is X"); + +SVA_TDU_X_CSR : assert property ( + @(negedge clk) disable iff (~rst_n) + csr2tdu_req_i |-> !$isunknown({csr2tdu_cmd_i,csr2tdu_addr_i}) + ) else $error("TDU Error: csr is X"); + +SVA_TDU_XW_CSR : assert property ( + @(negedge clk) disable iff (~rst_n) + (csr2tdu_req_i & csr_wr_req) |-> !$isunknown(csr2tdu_wdata_i) + ) else $error("TDU Error: csr wdata is X "); + +SVA_TDU_X_IMON : assert property ( + @(negedge clk) disable iff (~rst_n) + exu2tdu_imon_i.vd |-> !$isunknown({exu2tdu_imon_i.req,exu2tdu_imon_i.addr}) + ) else $error("TDU Error: imonitor is X"); + +SVA_TDU_X_DMON : assert property ( + @(negedge clk) disable iff (~rst_n) + lsu2tdu_dmon_i.vd |-> !$isunknown({lsu2tdu_dmon_i}) + ) else $error("TDU Error: dmonitor is X"); + +`endif // SCR1_TRGT_SIMULATION + +endmodule : scr1_pipe_tdu + +`endif // SCR1_TDU_EN diff --git a/src/rtl/scr1/scr1_pipe_top.sv b/src/rtl/scr1/scr1_pipe_top.sv new file mode 100644 index 0000000..cbf9a1e --- /dev/null +++ b/src/rtl/scr1/scr1_pipe_top.sv @@ -0,0 +1,825 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief SCR1 pipeline top +/// + +`include "scr1_arch_description.svh" +`include "scr1_memif.svh" +`include "scr1_riscv_isa_decoding.svh" +`include "scr1_csr.svh" + +`ifdef SCR1_IPIC_EN +`include "scr1_ipic.svh" +`endif // SCR1_IPIC_EN + +`ifdef SCR1_DBG_EN +`include "scr1_hdu.svh" +`endif // SCR1_DBG_EN + +`ifdef SCR1_TDU_EN +`include "scr1_tdu.svh" +`endif // SCR1_TDU_EN + +module scr1_pipe_top ( + // Common + input logic pipe_rst_n, // Pipe reset +`ifdef SCR1_DBG_EN + input logic pipe2hdu_rdc_qlfy_i, // Pipe RDC qualifier + input logic dbg_rst_n, // Debug reset +`endif // SCR1_DBG_EN + input logic clk, // Pipe clock + + // Instruction Memory Interface + output logic pipe2imem_req_o, // IMEM request + output type_scr1_mem_cmd_e pipe2imem_cmd_o, // IMEM command + output logic [`SCR1_IMEM_AWIDTH-1:0] pipe2imem_addr_o, // IMEM address + input logic imem2pipe_req_ack_i, // IMEM request acknowledge + input logic [`SCR1_IMEM_DWIDTH-1:0] imem2pipe_rdata_i, // IMEM read data + input type_scr1_mem_resp_e imem2pipe_resp_i, // IMEM response + + // Data Memory Interface + output logic pipe2dmem_req_o, // DMEM request + output type_scr1_mem_cmd_e pipe2dmem_cmd_o, // DMEM command + output type_scr1_mem_width_e pipe2dmem_width_o, // DMEM data width + output logic [`SCR1_DMEM_AWIDTH-1:0] pipe2dmem_addr_o, // DMEM address + output logic [`SCR1_DMEM_DWIDTH-1:0] pipe2dmem_wdata_o, // DMEM write data + input logic dmem2pipe_req_ack_i, // DMEM request acknowledge + input logic [`SCR1_DMEM_DWIDTH-1:0] dmem2pipe_rdata_i, // DMEM read data + input type_scr1_mem_resp_e dmem2pipe_resp_i, // DMEM response + +`ifdef SCR1_DBG_EN + // Debug interface: + input logic dbg_en, // 1 - debug operations enabled + // DM <-> Pipeline: HART Run Control i/f + input logic dm2pipe_active_i, // Debug Module active flag + + input logic dm2pipe_cmd_req_i, // Request from Debug Module + input type_scr1_hdu_dbgstates_e dm2pipe_cmd_i, // Command from Debug Module + output logic pipe2dm_cmd_resp_o, // Response to Debug Module + output logic pipe2dm_cmd_rcode_o, // Debug Module return code: 0 - Ok; 1 - Error + output logic pipe2dm_hart_event_o, // HART event flag + output type_scr1_hdu_hartstatus_s pipe2dm_hart_status_o, // HART status + + // DM <-> Pipeline: Program Buffer - HART instruction execution i/f + output logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] pipe2dm_pbuf_addr_o, // Program Buffer address + input logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] dm2pipe_pbuf_instr_i, // Program Buffer instruction + + // DM <-> Pipeline: HART Abstract Data regs i/f + output logic pipe2dm_dreg_req_o, // Abstract Data Register request + output logic pipe2dm_dreg_wr_o, // Abstract Data Register write + output logic [`SCR1_XLEN-1:0] pipe2dm_dreg_wdata_o, // Abstract Data Register write data + input logic dm2pipe_dreg_resp_i, // Abstract Data Register response + input logic dm2pipe_dreg_fail_i, // Abstract Data Register fail - possibly not needed? + input logic [`SCR1_XLEN-1:0] dm2pipe_dreg_rdata_i, // Abstract Data Register read data + + // DM <-> Pipeling: PC i/f + output logic [`SCR1_XLEN-1:0] pipe2dm_pc_sample_o, // Current PC for sampling +`endif // SCR1_DBG_EN + + // IRQ +`ifdef SCR1_IPIC_EN + input logic [SCR1_IRQ_LINES_NUM-1:0] soc2pipe_irq_lines_i, // External interrupt request lines +`else // SCR1_IPIC_EN + input logic soc2pipe_irq_ext_i, // External interrupt request +`endif // SCR1_IPIC_EN + input logic soc2pipe_irq_soft_i, // Software generated interrupt request + input logic soc2pipe_irq_mtimer_i, // Machine timer interrupt request + + // Memory-mapped external timer + input logic [63:0] soc2pipe_mtimer_val_i, // Machine timer value + +`ifdef SCR1_CLKCTRL_EN + // CLK_CTRL interface + output logic pipe2clkctl_sleep_req_o, // CLK disable request to CLK gating circuit + output logic pipe2clkctl_wake_req_o, // CLK enable request to CLK gating circuit + input logic clkctl2pipe_clk_alw_on_i, // Not gated CLK + input logic clkctl2pipe_clk_dbgc_i, // CLK for HDU (not gated for now) + input logic clkctl2pipe_clk_en_i, // CLK enabled flag +`endif // SCR1_CLKCTRL_EN + + // Fuse + input logic [`SCR1_XLEN-1:0] soc2pipe_fuse_mhartid_i // Fuse MHARTID value +); + +//------------------------------------------------------------------------------- +// Local signals declaration +//------------------------------------------------------------------------------- + +// Pipeline control +logic [`SCR1_XLEN-1:0] curr_pc; // Current PC +logic [`SCR1_XLEN-1:0] next_pc; // Is written to MEPC on interrupt trap +logic new_pc_req; // New PC request (jumps, branches, traps etc) +logic [`SCR1_XLEN-1:0] new_pc; // New PC + +logic stop_fetch; // Stop IFU +logic exu_exc_req; // Exception request +logic brkpt; // Breakpoint (sw) on current instruction +logic exu_init_pc; // Reset exit +logic wfi_run2halt; // Transition to WFI halted state +logic instret; // Instruction retirement (with or without exception) +`ifndef SCR1_CSR_REDUCED_CNT +logic instret_nexc; // Instruction retirement (without exception) +`endif // SCR1_CSR_REDUCED_CNT +`ifdef SCR1_IPIC_EN +logic ipic2csr_irq; // IRQ request from IPIC +`endif // SCR1_IPIC_EN +`ifdef SCR1_TDU_EN + `ifdef SCR1_DBG_EN +logic brkpt_hw; // Hardware breakpoint on current instruction + `endif // SCR1_DBG_EN +`endif // SCR1_TDU_EN +`ifdef SCR1_CLKCTRL_EN +logic imem_txns_pending; // There are pending imem transactions +logic wfi_halted; // WFI halted state +`endif // SCR1_CLKCTRL_EN + +// IFU <-> IDU +logic ifu2idu_vd; // IFU request +logic [`SCR1_IMEM_DWIDTH-1:0] ifu2idu_instr; // IFU instruction +logic ifu2idu_imem_err; // IFU instruction access fault +logic ifu2idu_err_rvi_hi; // 1 - imem fault when trying to fetch second half of an unaligned RVI instruction +logic idu2ifu_rdy; // IDU ready for new data + +// IDU <-> EXU +logic idu2exu_req; // IDU request +type_scr1_exu_cmd_s idu2exu_cmd; // IDU command (see scr1_riscv_isa_decoding.svh) +logic idu2exu_use_rs1; // Instruction uses rs1 +logic idu2exu_use_rs2; // Instruction uses rs2 +`ifndef SCR1_NO_EXE_STAGE +logic idu2exu_use_rd; // Instruction uses rd +logic idu2exu_use_imm; // Instruction uses immediate +`endif // SCR1_NO_EXE_STAGE +logic exu2idu_rdy; // EXU ready for new data + +// EXU <-> MPRF +logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rs1_addr; // MPRF rs1 read address +logic [`SCR1_XLEN-1:0] mprf2exu_rs1_data; // MPRF rs1 read data +logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rs2_addr; // MPRF rs2 read address +logic [`SCR1_XLEN-1:0] mprf2exu_rs2_data; // MPRF rs2 read data +logic exu2mprf_w_req; // MPRF write request +logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rd_addr; // MPRF rd write address +logic [`SCR1_XLEN-1:0] exu2mprf_rd_data; // MPRF rd write data + +// EXU <-> CSR +logic [SCR1_CSR_ADDR_WIDTH-1:0] exu2csr_rw_addr; // CSR read/write address +logic exu2csr_r_req; // CSR read request +logic [`SCR1_XLEN-1:0] csr2exu_r_data; // CSR read data +logic exu2csr_w_req; // CSR write request +type_scr1_csr_cmd_sel_e exu2csr_w_cmd; // CSR write command +logic [`SCR1_XLEN-1:0] exu2csr_w_data; // CSR write data +logic csr2exu_rw_exc; // CSR read/write access exception + +// EXU <-> CSR event interface +logic exu2csr_take_irq; // Take IRQ trap +logic exu2csr_take_exc; // Take exception trap +logic exu2csr_mret_update; // MRET update CSR +logic exu2csr_mret_instr; // MRET instruction +type_scr1_exc_code_e exu2csr_exc_code; // Exception code (see scr1_arch_types.svh) +logic [`SCR1_XLEN-1:0] exu2csr_trap_val; // Trap value +logic [`SCR1_XLEN-1:0] csr2exu_new_pc; // Exception/IRQ/MRET new PC +logic csr2exu_irq; // IRQ request +logic csr2exu_ip_ie; // Some IRQ pending and locally enabled +logic csr2exu_mstatus_mie_up; // MSTATUS or MIE update in the current cycle + +`ifdef SCR1_IPIC_EN +// CSR <-> IPIC +logic csr2ipic_r_req; // IPIC read request +logic csr2ipic_w_req; // IPIC write request +logic [2:0] csr2ipic_addr; // IPIC address +logic [`SCR1_XLEN-1:0] csr2ipic_wdata; // IPIC write data +logic [`SCR1_XLEN-1:0] ipic2csr_rdata; // IPIC read data +`endif // SCR1_IPIC_EN + +`ifdef SCR1_TDU_EN +// CSR <-> TDU +logic csr2tdu_req; // Request to TDU +type_scr1_csr_cmd_sel_e csr2tdu_cmd; // TDU command +logic [SCR1_CSR_ADDR_TDU_OFFS_W-1:0] csr2tdu_addr; // TDU address +logic [`SCR1_XLEN-1:0] csr2tdu_wdata; // TDU write data +logic [`SCR1_XLEN-1:0] tdu2csr_rdata; // TDU read data +type_scr1_csr_resp_e tdu2csr_resp; // TDU response + `ifdef SCR1_DBG_EN + // Qualified TDU input signals from pipe_rst_n + // reset domain: +logic csr2tdu_req_qlfy; // Request to TDU + `endif // SCR1_DBG_EN + +// EXU/LSU <-> TDU +type_scr1_brkm_instr_mon_s exu2tdu_i_mon; // Instruction monitor +type_scr1_brkm_lsu_mon_s lsu2tdu_d_mon; // Data monitor +logic [SCR1_TDU_ALLTRIG_NUM-1:0] tdu2exu_i_match; // Instruction breakpoint(s) match +logic [SCR1_TDU_MTRIG_NUM-1:0] tdu2lsu_d_match; // Data breakpoint(s) match +logic tdu2exu_i_x_req; // Instruction breakpoint exception +logic tdu2lsu_i_x_req; // Instruction breakpoint exception +logic tdu2lsu_d_x_req; // Data breakpoint exception +logic [SCR1_TDU_ALLTRIG_NUM-1:0] exu2tdu_bp_retire; // Instruction with breakpoint flag retire + `ifdef SCR1_DBG_EN + // Qualified TDU input signals from pipe_rst_n + // reset domain: +type_scr1_brkm_instr_mon_s exu2tdu_i_mon_qlfy; // Instruction monitor +type_scr1_brkm_lsu_mon_s lsu2tdu_d_mon_qlfy; // Data monitor +logic [SCR1_TDU_ALLTRIG_NUM-1:0] exu2tdu_bp_retire_qlfy; // Instruction with breakpoint flag retire + `endif // SCR1_DBG_EN +`endif // SCR1_TDU_EN + +`ifdef SCR1_DBG_EN +// Debug signals: +logic fetch_pbuf; // Fetch instructions provided by Program Buffer (via HDU) +logic csr2hdu_req; // Request to HDU +type_scr1_csr_cmd_sel_e csr2hdu_cmd; // HDU command +logic [SCR1_HDU_DEBUGCSR_ADDR_WIDTH-1:0] csr2hdu_addr; // HDU address +logic [`SCR1_XLEN-1:0] csr2hdu_wdata; // HDU write data +logic [`SCR1_XLEN-1:0] hdu2csr_rdata; // HDU read data +type_scr1_csr_resp_e hdu2csr_resp; // HDU response + // Qualified HDU input signals from pipe_rst_n + // reset domain: +logic csr2hdu_req_qlfy; // Request to HDU + +logic hwbrk_dsbl; // Disables TDU +logic hdu_hwbrk_dsbl; // Disables TDU +logic tdu2hdu_dmode_req; // TDU requests transition to debug mode + +logic exu_no_commit; // Forbid instruction commitment +logic exu_irq_dsbl; // Disable IRQ +logic exu_pc_advmt_dsbl; // Forbid PC advancement +logic exu_dmode_sstep_en; // Enable single-step + +logic dbg_halted; // Debug halted state +logic dbg_run2halt; // Transition to debug halted state +logic dbg_halt2run; // Transition to run state +logic dbg_run_start; // First cycle of run state +logic [`SCR1_XLEN-1:0] dbg_new_pc; // New PC as starting point for HART Resume + +logic ifu2hdu_pbuf_rdy; +logic hdu2ifu_pbuf_vd; +logic hdu2ifu_pbuf_err; +logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] hdu2ifu_pbuf_instr; + +// Qualified HDU input signals from pipe_rst_n reset domain: +logic ifu2hdu_pbuf_rdy_qlfy; +logic exu_busy_qlfy; +logic instret_qlfy; +logic exu_init_pc_qlfy; +logic exu_exc_req_qlfy; +logic brkpt_qlfy; + +`endif // SCR1_DBG_EN + +logic exu_busy; + + +`ifndef SCR1_CLKCTRL_EN +logic pipe2clkctl_wake_req_o; +`endif // SCR1_CLKCTRL_EN + +//------------------------------------------------------------------------------- +// Pipeline logic +//------------------------------------------------------------------------------- +assign stop_fetch = wfi_run2halt +`ifdef SCR1_DBG_EN + | fetch_pbuf +`endif // SCR1_DBG_EN + ; + +`ifdef SCR1_CLKCTRL_EN +assign pipe2clkctl_sleep_req_o = wfi_halted & ~imem_txns_pending; +assign pipe2clkctl_wake_req_o = csr2exu_ip_ie +`ifdef SCR1_DBG_EN + | dm2pipe_active_i +`endif // SCR1_DBG_EN + ; +`endif // SCR1_CLKCTRL_EN + +`ifdef SCR1_DBG_EN +assign pipe2dm_pc_sample_o = curr_pc; +`endif // SCR1_DBG_EN + +//------------------------------------------------------------------------------- +// Instruction fetch unit +//------------------------------------------------------------------------------- +scr1_pipe_ifu i_pipe_ifu ( + .rst_n (pipe_rst_n ), + .clk (clk ), + + // Instruction memory interface + .imem2ifu_req_ack_i (imem2pipe_req_ack_i), + .ifu2imem_req_o (pipe2imem_req_o ), + .ifu2imem_cmd_o (pipe2imem_cmd_o ), + .ifu2imem_addr_o (pipe2imem_addr_o ), + .imem2ifu_rdata_i (imem2pipe_rdata_i ), + .imem2ifu_resp_i (imem2pipe_resp_i ), + + // New PC interface + .exu2ifu_pc_new_req_i (new_pc_req ), + .exu2ifu_pc_new_i (new_pc ), + .pipe2ifu_stop_fetch_i (stop_fetch ), + +`ifdef SCR1_DBG_EN + // IFU <-> HDU Program Buffer interface + .hdu2ifu_pbuf_fetch_i (fetch_pbuf ), + .ifu2hdu_pbuf_rdy_o (ifu2hdu_pbuf_rdy ), + .hdu2ifu_pbuf_vd_i (hdu2ifu_pbuf_vd ), + .hdu2ifu_pbuf_err_i (hdu2ifu_pbuf_err ), + .hdu2ifu_pbuf_instr_i (hdu2ifu_pbuf_instr ), +`endif // SCR1_DBG_EN +`ifdef SCR1_CLKCTRL_EN + .ifu2pipe_imem_txns_pnd_o (imem_txns_pending ), +`endif // SCR1_CLKCTRL_EN + + // IFU <-> IDU interface + .idu2ifu_rdy_i (idu2ifu_rdy ), + .ifu2idu_instr_o (ifu2idu_instr ), + .ifu2idu_imem_err_o (ifu2idu_imem_err ), + .ifu2idu_err_rvi_hi_o (ifu2idu_err_rvi_hi ), + .ifu2idu_vd_o (ifu2idu_vd ) +); + +//------------------------------------------------------------------------------- +// Instruction decode unit +//------------------------------------------------------------------------------- +scr1_pipe_idu i_pipe_idu ( +`ifdef SCR1_TRGT_SIMULATION + .rst_n (pipe_rst_n ), + .clk (clk ), +`endif // SCR1_TRGT_SIMULATION + .idu2ifu_rdy_o (idu2ifu_rdy ), + .ifu2idu_instr_i (ifu2idu_instr ), + .ifu2idu_imem_err_i (ifu2idu_imem_err ), + .ifu2idu_err_rvi_hi_i (ifu2idu_err_rvi_hi), + .ifu2idu_vd_i (ifu2idu_vd ), + + .idu2exu_req_o (idu2exu_req ), + .idu2exu_cmd_o (idu2exu_cmd ), + .idu2exu_use_rs1_o (idu2exu_use_rs1 ), + .idu2exu_use_rs2_o (idu2exu_use_rs2 ), +`ifndef SCR1_NO_EXE_STAGE + .idu2exu_use_rd_o (idu2exu_use_rd ), + .idu2exu_use_imm_o (idu2exu_use_imm ), +`endif // SCR1_NO_EXE_STAGE + .exu2idu_rdy_i (exu2idu_rdy ) +); + +//------------------------------------------------------------------------------- +// Execution unit +//------------------------------------------------------------------------------- +scr1_pipe_exu i_pipe_exu ( + .rst_n (pipe_rst_n ), + .clk (clk ), +`ifdef SCR1_CLKCTRL_EN + .clk_alw_on (clkctl2pipe_clk_alw_on_i), + .clk_pipe_en (clkctl2pipe_clk_en_i), +`endif // SCR1_CLKCTRL_EN + + // IDU <-> EXU interface + .idu2exu_req_i (idu2exu_req ), + .exu2idu_rdy_o (exu2idu_rdy ), + .idu2exu_cmd_i (idu2exu_cmd ), + .idu2exu_use_rs1_i (idu2exu_use_rs1 ), + .idu2exu_use_rs2_i (idu2exu_use_rs2 ), +`ifndef SCR1_NO_EXE_STAGE + .idu2exu_use_rd_i (idu2exu_use_rd ), + .idu2exu_use_imm_i (idu2exu_use_imm ), +`endif // SCR1_NO_EXE_STAGE + + // EXU <-> MPRF interface + .exu2mprf_rs1_addr_o (exu2mprf_rs1_addr ), + .mprf2exu_rs1_data_i (mprf2exu_rs1_data ), + .exu2mprf_rs2_addr_o (exu2mprf_rs2_addr ), + .mprf2exu_rs2_data_i (mprf2exu_rs2_data ), + .exu2mprf_w_req_o (exu2mprf_w_req ), + .exu2mprf_rd_addr_o (exu2mprf_rd_addr ), + .exu2mprf_rd_data_o (exu2mprf_rd_data ), + + // EXU <-> CSR read/write interface + .exu2csr_rw_addr_o (exu2csr_rw_addr ), + .exu2csr_r_req_o (exu2csr_r_req ), + .csr2exu_r_data_i (csr2exu_r_data ), + .exu2csr_w_req_o (exu2csr_w_req ), + .exu2csr_w_cmd_o (exu2csr_w_cmd ), + .exu2csr_w_data_o (exu2csr_w_data ), + .csr2exu_rw_exc_i (csr2exu_rw_exc ), + + // EXU <-> CSR event interface + .exu2csr_take_irq_o (exu2csr_take_irq ), + .exu2csr_take_exc_o (exu2csr_take_exc ), + .exu2csr_mret_update_o (exu2csr_mret_update ), + .exu2csr_mret_instr_o (exu2csr_mret_instr ), + .exu2csr_exc_code_o (exu2csr_exc_code ), + .exu2csr_trap_val_o (exu2csr_trap_val ), + .csr2exu_new_pc_i (csr2exu_new_pc ), + .csr2exu_irq_i (csr2exu_irq ), + .csr2exu_ip_ie_i (csr2exu_ip_ie ), + .csr2exu_mstatus_mie_up_i (csr2exu_mstatus_mie_up ), + + // EXU <-> DMEM interface + .exu2dmem_req_o (pipe2dmem_req_o ), + .exu2dmem_cmd_o (pipe2dmem_cmd_o ), + .exu2dmem_width_o (pipe2dmem_width_o ), + .exu2dmem_addr_o (pipe2dmem_addr_o ), + .exu2dmem_wdata_o (pipe2dmem_wdata_o ), + .dmem2exu_req_ack_i (dmem2pipe_req_ack_i ), + .dmem2exu_rdata_i (dmem2pipe_rdata_i ), + .dmem2exu_resp_i (dmem2pipe_resp_i ), + +`ifdef SCR1_DBG_EN + // EXU <-> HDU interface + .hdu2exu_no_commit_i (exu_no_commit ), + .hdu2exu_irq_dsbl_i (exu_irq_dsbl ), + .hdu2exu_pc_advmt_dsbl_i (exu_pc_advmt_dsbl ), + .hdu2exu_dmode_sstep_en_i (exu_dmode_sstep_en ), + .hdu2exu_pbuf_fetch_i (fetch_pbuf ), + .hdu2exu_dbg_halted_i (dbg_halted ), + .hdu2exu_dbg_run2halt_i (dbg_run2halt ), + .hdu2exu_dbg_halt2run_i (dbg_halt2run ), + .hdu2exu_dbg_run_start_i (dbg_run_start ), + .hdu2exu_dbg_new_pc_i (dbg_new_pc ), +`endif // SCR1_DBG_EN + +`ifdef SCR1_TDU_EN + // EXU <-> TDU interface + .exu2tdu_imon_o (exu2tdu_i_mon ), + .tdu2exu_ibrkpt_match_i (tdu2exu_i_match ), + .tdu2exu_ibrkpt_exc_req_i (tdu2exu_i_x_req ), + .lsu2tdu_dmon_o (lsu2tdu_d_mon ), + .tdu2lsu_ibrkpt_exc_req_i (tdu2lsu_i_x_req ), + .tdu2lsu_dbrkpt_match_i (tdu2lsu_d_match ), + .tdu2lsu_dbrkpt_exc_req_i (tdu2lsu_d_x_req ), + .exu2tdu_ibrkpt_ret_o (exu2tdu_bp_retire ), + `ifdef SCR1_DBG_EN + .exu2hdu_ibrkpt_hw_o (brkpt_hw ), + `endif // SCR1_DBG_EN +`endif // SCR1_TDU_EN + + // EXU control + .exu2pipe_exc_req_o (exu_exc_req ), + .exu2pipe_brkpt_o (brkpt ), + .exu2pipe_init_pc_o (exu_init_pc ), + .exu2pipe_wfi_run2halt_o (wfi_run2halt ), + .exu2pipe_instret_o (instret ), +`ifndef SCR1_CSR_REDUCED_CNT + .exu2csr_instret_no_exc_o (instret_nexc ), +`endif // SCR1_CSR_REDUCED_CNT + .exu2pipe_exu_busy_o (exu_busy ), + + // PC interface +`ifdef SCR1_CLKCTRL_EN + .exu2pipe_wfi_halted_o (wfi_halted ), +`endif // SCR1_CLKCTRL_EN + .exu2pipe_pc_curr_o (curr_pc ), + .exu2csr_pc_next_o (next_pc ), + .exu2ifu_pc_new_req_o (new_pc_req ), + .exu2ifu_pc_new_o (new_pc ) +); + +//------------------------------------------------------------------------------- +// Multi-port register file +//------------------------------------------------------------------------------- +scr1_pipe_mprf i_pipe_mprf ( +`ifdef SCR1_MPRF_RST_EN + .rst_n (pipe_rst_n ), +`endif // SCR1_MPRF_RST_EN + .clk (clk ), + + // EXU <-> MPRF interface + .exu2mprf_rs1_addr_i (exu2mprf_rs1_addr), + .mprf2exu_rs1_data_o (mprf2exu_rs1_data), + .exu2mprf_rs2_addr_i (exu2mprf_rs2_addr), + .mprf2exu_rs2_data_o (mprf2exu_rs2_data), + .exu2mprf_w_req_i (exu2mprf_w_req ), + .exu2mprf_rd_addr_i (exu2mprf_rd_addr ), + .exu2mprf_rd_data_i (exu2mprf_rd_data ) +); + +//------------------------------------------------------------------------------- +// Control and status registers +//------------------------------------------------------------------------------- +scr1_pipe_csr i_pipe_csr ( + .rst_n (pipe_rst_n ), + .clk (clk ), +`ifndef SCR1_CSR_REDUCED_CNT + `ifdef SCR1_CLKCTRL_EN + .clk_alw_on (clkctl2pipe_clk_alw_on_i), + `endif // SCR1_CLKCTRL_EN +`endif // SCR1_CSR_REDUCED_CNT + + // EXU <-> CSR read/write interface + .exu2csr_r_req_i (exu2csr_r_req ), + .exu2csr_rw_addr_i (exu2csr_rw_addr ), + .csr2exu_r_data_o (csr2exu_r_data ), + .exu2csr_w_req_i (exu2csr_w_req ), + .exu2csr_w_cmd_i (exu2csr_w_cmd ), + .exu2csr_w_data_i (exu2csr_w_data ), + .csr2exu_rw_exc_o (csr2exu_rw_exc ), + + // EXU <-> CSR event interface + .exu2csr_take_irq_i (exu2csr_take_irq ), + .exu2csr_take_exc_i (exu2csr_take_exc ), + .exu2csr_mret_update_i (exu2csr_mret_update ), + .exu2csr_mret_instr_i (exu2csr_mret_instr ), + .exu2csr_exc_code_i (exu2csr_exc_code ), + .exu2csr_trap_val_i (exu2csr_trap_val ), + .csr2exu_new_pc_o (csr2exu_new_pc ), + .csr2exu_irq_o (csr2exu_irq ), + .csr2exu_ip_ie_o (csr2exu_ip_ie ), + .csr2exu_mstatus_mie_up_o (csr2exu_mstatus_mie_up ), + +`ifdef SCR1_IPIC_EN + // CSR <-> IPIC interface + .csr2ipic_r_req_o (csr2ipic_r_req ), + .csr2ipic_w_req_o (csr2ipic_w_req ), + .csr2ipic_addr_o (csr2ipic_addr ), + .csr2ipic_wdata_o (csr2ipic_wdata ), + .ipic2csr_rdata_i (ipic2csr_rdata ), +`endif // SCR1_IPIC_EN + + // CSR <-> PC interface + .exu2csr_pc_curr_i (curr_pc ), + .exu2csr_pc_next_i (next_pc ), +`ifndef SCR1_CSR_REDUCED_CNT + .exu2csr_instret_no_exc_i (instret_nexc ), +`endif // SCR1_CSR_REDUCED_CNT + + // IRQ +`ifdef SCR1_IPIC_EN + .soc2csr_irq_ext_i (ipic2csr_irq ), +`else // SCR1_IPIC_EN + .soc2csr_irq_ext_i (soc2pipe_irq_ext_i ), +`endif // SCR1_IPIC_EN + .soc2csr_irq_soft_i (soc2pipe_irq_soft_i ), + .soc2csr_irq_mtimer_i (soc2pipe_irq_mtimer_i ), + + // Memory-mapped external timer + .soc2csr_mtimer_val_i (soc2pipe_mtimer_val_i ), + +`ifdef SCR1_DBG_EN + // CSR <-> HDU interface + .csr2hdu_req_o (csr2hdu_req ), + .csr2hdu_cmd_o (csr2hdu_cmd ), + .csr2hdu_addr_o (csr2hdu_addr ), + .csr2hdu_wdata_o (csr2hdu_wdata ), + .hdu2csr_rdata_i (hdu2csr_rdata ), + .hdu2csr_resp_i (hdu2csr_resp ), + .hdu2csr_no_commit_i (exu_no_commit ), +`endif // SCR1_DBG_EN + +`ifdef SCR1_TDU_EN + // CSR <-> TDU interface + .csr2tdu_req_o (csr2tdu_req ), + .csr2tdu_cmd_o (csr2tdu_cmd ), + .csr2tdu_addr_o (csr2tdu_addr ), + .csr2tdu_wdata_o (csr2tdu_wdata ), + .tdu2csr_rdata_i (tdu2csr_rdata ), + .tdu2csr_resp_i (tdu2csr_resp ), +`endif // SCR1_TDU_EN + .soc2csr_fuse_mhartid_i (soc2pipe_fuse_mhartid_i ) +); + +//------------------------------------------------------------------------------- +// Integrated programmable interrupt controller +//------------------------------------------------------------------------------- +`ifdef SCR1_IPIC_EN +scr1_ipic i_pipe_ipic ( + .rst_n (pipe_rst_n ), +`ifdef SCR1_CLKCTRL_EN + .clk (clkctl2pipe_clk_alw_on_i), +`else // SCR1_CLKCTRL_EN + .clk (clk ), +`endif // SCR1_CLKCTRL_EN + .soc2ipic_irq_lines_i (soc2pipe_irq_lines_i ), + .csr2ipic_r_req_i (csr2ipic_r_req ), + .csr2ipic_w_req_i (csr2ipic_w_req ), + .csr2ipic_addr_i (csr2ipic_addr ), + .csr2ipic_wdata_i (csr2ipic_wdata ), + .ipic2csr_rdata_o (ipic2csr_rdata ), + .ipic2csr_irq_m_req_o (ipic2csr_irq ) +); +`endif // SCR1_IPIC_EN + +//------------------------------------------------------------------------------- +// Breakpoint module +//------------------------------------------------------------------------------- +`ifdef SCR1_TDU_EN +scr1_pipe_tdu i_pipe_tdu ( + // Common signals + `ifdef SCR1_DBG_EN + .rst_n (dbg_rst_n ), + `else + .rst_n (pipe_rst_n ), + `endif // SCR1_DBG_EN + .clk (clk ), + .clk_en (1'b1 ), + `ifdef SCR1_DBG_EN + .tdu_dsbl_i (hwbrk_dsbl ), + `else // SCR1_DBG_EN + .tdu_dsbl_i (1'b0 ), + `endif // SCR1_DBG_EN + + // TDU <-> CSR interface + `ifdef SCR1_DBG_EN + .csr2tdu_req_i (csr2tdu_req_qlfy ), + .csr2tdu_cmd_i (csr2tdu_cmd ), + .csr2tdu_addr_i (csr2tdu_addr ), + .csr2tdu_wdata_i (csr2tdu_wdata ), + `else // SCR1_DBG_EN + .csr2tdu_req_i (csr2tdu_req ), + .csr2tdu_cmd_i (csr2tdu_cmd ), + .csr2tdu_addr_i (csr2tdu_addr ), + .csr2tdu_wdata_i (csr2tdu_wdata ), + `endif // SCR1_DBG_EN + .tdu2csr_rdata_o (tdu2csr_rdata ), + .tdu2csr_resp_o (tdu2csr_resp ), + + // TDU <-> EXU interface + `ifdef SCR1_DBG_EN + .exu2tdu_imon_i (exu2tdu_i_mon_qlfy ), + `else // SCR1_DBG_EN + .exu2tdu_imon_i (exu2tdu_i_mon ), + `endif // SCR1_DBG_EN + .tdu2exu_ibrkpt_match_o (tdu2exu_i_match ), + .tdu2exu_ibrkpt_exc_req_o (tdu2exu_i_x_req ), + `ifdef SCR1_DBG_EN + .exu2tdu_bp_retire_i (exu2tdu_bp_retire_qlfy), + `else // SCR1_DBG_EN + .exu2tdu_bp_retire_i (exu2tdu_bp_retire ), + `endif // SCR1_DBG_EN + + // TDU <-> LSU interface + .tdu2lsu_ibrkpt_exc_req_o (tdu2lsu_i_x_req ), + `ifdef SCR1_DBG_EN + .lsu2tdu_dmon_i (lsu2tdu_d_mon_qlfy ), + `else // SCR1_DBG_EN + .lsu2tdu_dmon_i (lsu2tdu_d_mon ), + `endif // SCR1_DBG_EN + .tdu2lsu_dbrkpt_match_o (tdu2lsu_d_match ), + .tdu2lsu_dbrkpt_exc_req_o (tdu2lsu_d_x_req ), + // EPU I/F + `ifdef SCR1_DBG_EN + .tdu2hdu_dmode_req_o (tdu2hdu_dmode_req ) + `else // SCR1_DBG_EN + .tdu2hdu_dmode_req_o ( ) + `endif // SCR1_DBG_EN +); + + `ifdef SCR1_DBG_EN +assign hwbrk_dsbl = (~dbg_en) | hdu_hwbrk_dsbl; +// +assign csr2tdu_req_qlfy = dbg_en & csr2tdu_req & pipe2hdu_rdc_qlfy_i; +// +assign exu2tdu_i_mon_qlfy.vd = exu2tdu_i_mon.vd & pipe2hdu_rdc_qlfy_i; +assign exu2tdu_i_mon_qlfy.req = exu2tdu_i_mon.req; +assign exu2tdu_i_mon_qlfy.addr = exu2tdu_i_mon.addr; +assign lsu2tdu_d_mon_qlfy.vd = lsu2tdu_d_mon.vd & pipe2hdu_rdc_qlfy_i; +assign lsu2tdu_d_mon_qlfy.load = lsu2tdu_d_mon.load; +assign lsu2tdu_d_mon_qlfy.store = lsu2tdu_d_mon.store; +assign lsu2tdu_d_mon_qlfy.addr = lsu2tdu_d_mon.addr; +assign exu2tdu_bp_retire_qlfy = exu2tdu_bp_retire & {$bits(exu2tdu_bp_retire){pipe2hdu_rdc_qlfy_i}}; + `endif // SCR1_DBG_EN + +`endif // SCR1_TDU_EN + +//------------------------------------------------------------------------------- +// HART Debug Unit (HDU) +//------------------------------------------------------------------------------- +`ifdef SCR1_DBG_EN +scr1_pipe_hdu i_pipe_hdu ( + // Common signals + .rst_n (dbg_rst_n ), + .clk_en (dm2pipe_active_i ), +`ifdef SCR1_CLKCTRL_EN + .clk_pipe_en (clkctl2pipe_clk_en_i ), + .clk (clkctl2pipe_clk_dbgc_i), +`else + .clk (clk ), +`endif // SCR1_CLKCTRL_EN + + // Control/status registers i/f + .csr2hdu_req_i (csr2hdu_req_qlfy ), + .csr2hdu_cmd_i (csr2hdu_cmd ), + .csr2hdu_addr_i (csr2hdu_addr ), + .csr2hdu_wdata_i (csr2hdu_wdata ), + .hdu2csr_resp_o (hdu2csr_resp ), + .hdu2csr_rdata_o (hdu2csr_rdata ), + + // HART Run Control i/f + .pipe2hdu_rdc_qlfy_i (pipe2hdu_rdc_qlfy_i ), + .dm2hdu_cmd_req_i (dm2pipe_cmd_req_i ), + .dm2hdu_cmd_i (dm2pipe_cmd_i ), + .hdu2dm_cmd_resp_o (pipe2dm_cmd_resp_o ), + .hdu2dm_cmd_rcode_o (pipe2dm_cmd_rcode_o ), + .hdu2dm_hart_event_o (pipe2dm_hart_event_o ), + .hdu2dm_hart_status_o (pipe2dm_hart_status_o ), + + // Program Buffer - HART instruction execution i/f + .hdu2dm_pbuf_addr_o (pipe2dm_pbuf_addr_o ), + .dm2hdu_pbuf_instr_i (dm2pipe_pbuf_instr_i ), + + // HART Abstract Data regs i/f + .hdu2dm_dreg_req_o (pipe2dm_dreg_req_o ), + .hdu2dm_dreg_wr_o (pipe2dm_dreg_wr_o ), + .hdu2dm_dreg_wdata_o (pipe2dm_dreg_wdata_o ), + .dm2hdu_dreg_resp_i (dm2pipe_dreg_resp_i ), + .dm2hdu_dreg_fail_i (dm2pipe_dreg_fail_i ), + .dm2hdu_dreg_rdata_i (dm2pipe_dreg_rdata_i ), + // +`ifdef SCR1_TDU_EN + // HDU <-> TDU interface + .hdu2tdu_hwbrk_dsbl_o (hdu_hwbrk_dsbl ), + .tdu2hdu_dmode_req_i (tdu2hdu_dmode_req ), + .exu2hdu_ibrkpt_hw_i (brkpt_hw ), +`endif // SCR1_TDU_EN + + // HART Run Status + .pipe2hdu_exu_busy_i (exu_busy_qlfy ), + .pipe2hdu_instret_i (instret_qlfy ), + .pipe2hdu_init_pc_i (exu_init_pc_qlfy ), + + // HART Halt Status + .pipe2hdu_exu_exc_req_i (exu_exc_req_qlfy ), + .pipe2hdu_brkpt_i (brkpt_qlfy ), + + // HART Run Control + .hdu2exu_pbuf_fetch_o (fetch_pbuf ), + .hdu2exu_no_commit_o (exu_no_commit ), + .hdu2exu_irq_dsbl_o (exu_irq_dsbl ), + .hdu2exu_pc_advmt_dsbl_o (exu_pc_advmt_dsbl ), + .hdu2exu_dmode_sstep_en_o (exu_dmode_sstep_en ), + + // HART state + .hdu2exu_dbg_halted_o (dbg_halted ), + .hdu2exu_dbg_run2halt_o (dbg_run2halt ), + .hdu2exu_dbg_halt2run_o (dbg_halt2run ), + .hdu2exu_dbg_run_start_o (dbg_run_start ), + + // PC interface + .pipe2hdu_pc_curr_i (curr_pc ), + .hdu2exu_dbg_new_pc_o (dbg_new_pc ), + + // Prgram Buffer Instruction interface + .ifu2hdu_pbuf_instr_rdy_i (ifu2hdu_pbuf_rdy_qlfy ), + .hdu2ifu_pbuf_instr_vd_o (hdu2ifu_pbuf_vd ), + .hdu2ifu_pbuf_instr_err_o (hdu2ifu_pbuf_err ), + .hdu2ifu_pbuf_instr_o (hdu2ifu_pbuf_instr ) +); + +assign csr2hdu_req_qlfy = csr2hdu_req & dbg_en & pipe2hdu_rdc_qlfy_i; +// +assign exu_busy_qlfy = exu_busy & {$bits(exu_busy){pipe2hdu_rdc_qlfy_i}}; +assign instret_qlfy = instret & {$bits(instret){pipe2hdu_rdc_qlfy_i}}; +assign exu_init_pc_qlfy = exu_init_pc & {$bits(exu_init_pc){pipe2hdu_rdc_qlfy_i}}; +assign exu_exc_req_qlfy = exu_exc_req & {$bits(exu_exc_req){pipe2hdu_rdc_qlfy_i}}; +assign brkpt_qlfy = brkpt & {$bits(brkpt){pipe2hdu_rdc_qlfy_i}}; +assign ifu2hdu_pbuf_rdy_qlfy = ifu2hdu_pbuf_rdy & {$bits(ifu2hdu_pbuf_rdy){pipe2hdu_rdc_qlfy_i}}; + +`endif // SCR1_DBG_EN + +`ifdef SCR1_TRGT_SIMULATION +//------------------------------------------------------------------------------- +// Tracelog +//------------------------------------------------------------------------------- + +scr1_tracelog i_tracelog ( + .rst_n (pipe_rst_n ), + .clk (clk ) +`ifdef SCR1_TRACE_LOG_EN + , + .soc2pipe_fuse_mhartid_i (soc2pipe_fuse_mhartid_i ), + + // MPRF + .mprf2trace_int_i (i_pipe_mprf.mprf_int ), + .mprf2trace_wr_en_i (i_pipe_mprf.exu2mprf_w_req_i ), + .mprf2trace_wr_addr_i (i_pipe_mprf.exu2mprf_rd_addr_i ), + .mprf2trace_wr_data_i (i_pipe_mprf.exu2mprf_rd_data_i ), + + // EXU + .exu2trace_update_pc_en_i (i_pipe_exu.update_pc_en ), + .exu2trace_update_pc_i (i_pipe_exu.update_pc ), + + // IFU + .ifu2trace_instr_i (i_pipe_ifu.ifu2idu_instr_o ), + + // CSR + .csr2trace_mstatus_mie_i (i_pipe_csr.csr_mstatus_mie_ff ), + .csr2trace_mstatus_mpie_i (i_pipe_csr.csr_mstatus_mpie_ff ), + .csr2trace_mtvec_base_i (i_pipe_csr.csr_mtvec_base ), + .csr2trace_mtvec_mode_i (i_pipe_csr.csr_mtvec_mode ), + .csr2trace_mie_meie_i (i_pipe_csr.csr_mie_meie_ff ), + .csr2trace_mie_mtie_i (i_pipe_csr.csr_mie_mtie_ff ), + .csr2trace_mie_msie_i (i_pipe_csr.csr_mie_msie_ff ), + .csr2trace_mip_meip_i (i_pipe_csr.csr_mip_meip ), + .csr2trace_mip_mtip_i (i_pipe_csr.csr_mip_mtip ), + .csr2trace_mip_msip_i (i_pipe_csr.csr_mip_msip ), + .csr2trace_mepc_i (i_pipe_csr.csr_mepc_ff ), + .csr2trace_mcause_irq_i (i_pipe_csr.csr_mcause_i_ff ), + .csr2trace_mcause_ec_i (i_pipe_csr.csr_mcause_ec_ff ), + .csr2trace_mtval_i (i_pipe_csr.csr_mtval_ff ), + + // Events + .csr2trace_e_exc_i (i_pipe_csr.e_exc ), + .csr2trace_e_irq_i (i_pipe_csr.e_irq ), + .pipe2trace_e_wake_i (pipe2clkctl_wake_req_o ) +`endif // SCR1_TRACE_LOG_EN +); + +`endif // SCR1_TRGT_SIMULATION + +endmodule : scr1_pipe_top diff --git a/src/rtl/scr1/scr1_reset_cells.sv b/src/rtl/scr1/scr1_reset_cells.sv new file mode 100644 index 0000000..0a11cbd --- /dev/null +++ b/src/rtl/scr1/scr1_reset_cells.sv @@ -0,0 +1,231 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Cells for reset handling +/// + +//-------------------------------------------------------------------- +// Reset Buffer Cell +//-------------------------------------------------------------------- +module scr1_reset_buf_cell ( + input logic rst_n, + input logic clk, + input logic test_mode, + input logic test_rst_n, + input logic reset_n_in, + output logic reset_n_out, + output logic reset_n_status +); + +logic reset_n_ff; +logic reset_n_status_ff; +logic rst_n_mux; + +assign rst_n_mux = (test_mode == 1'b1) ? test_rst_n : rst_n; + +always_ff @(negedge rst_n_mux, posedge clk) begin + if (~rst_n_mux) begin + reset_n_ff <= 1'b0; + end else begin + reset_n_ff <= reset_n_in; + end +end + +assign reset_n_out = (test_mode == 1'b1) ? test_rst_n : reset_n_ff; + +always_ff @(negedge rst_n_mux, posedge clk) begin + if (~rst_n_mux) begin + reset_n_status_ff <= 1'b0; + end else begin + reset_n_status_ff <= reset_n_in; + end +end +assign reset_n_status = reset_n_status_ff; + +endmodule : scr1_reset_buf_cell + +//-------------------------------------------------------------------- +// Reset CDC Synchronization Cell +//-------------------------------------------------------------------- +module scr1_reset_sync_cell #( + parameter int unsigned STAGES_AMOUNT = 2 +) ( + input logic rst_n, + input logic clk, + input logic test_rst_n, + input logic test_mode, + input logic rst_n_in, + output logic rst_n_out +); + +logic [STAGES_AMOUNT-1:0] rst_n_dff; +logic local_rst_n_in; + +assign local_rst_n_in = (test_mode == 1'b1) ? test_rst_n : rst_n; + +generate + +if (STAGES_AMOUNT == 1) + +begin : gen_reset_sync_cell_single + always_ff @(negedge local_rst_n_in, posedge clk) begin + if (~local_rst_n_in) begin + rst_n_dff <= 1'b0; + end else begin + rst_n_dff <= rst_n_in; + end + end +end : gen_reset_sync_cell_single + +else // STAGES_AMOUNT > 1 + +begin : gen_reset_sync_cell_multi + always_ff @(negedge local_rst_n_in, posedge clk) + begin + if (~local_rst_n_in) begin + rst_n_dff <= '0; + end else begin + rst_n_dff <= {rst_n_dff[STAGES_AMOUNT-2:0], rst_n_in}; + end + end +end : gen_reset_sync_cell_multi + +endgenerate + +assign rst_n_out = (test_mode == 1'b1) ? test_rst_n : rst_n_dff[STAGES_AMOUNT-1]; + +endmodule : scr1_reset_sync_cell + +//-------------------------------------------------------------------- +// Data CDC/RDC Synchronization Cell +//-------------------------------------------------------------------- +module scr1_data_sync_cell #( + parameter int unsigned STAGES_AMOUNT = 1 +) ( + input logic rst_n, + input logic clk, + input logic data_in, + output logic data_out +); + +logic [STAGES_AMOUNT-1:0] data_dff; + +generate + +if (STAGES_AMOUNT == 1) + +begin : gen_data_sync_cell_single + always_ff @(negedge rst_n, posedge clk) + begin + if (~rst_n) begin + data_dff <= 1'b0; + end else begin + data_dff <= data_in; + end + end +end : gen_data_sync_cell_single + +else // STAGES_AMOUNT > 1 + +begin : gen_data_sync_cell_multi + always_ff @(negedge rst_n, posedge clk) + begin + if (~rst_n) begin + data_dff <= '0; + end else begin + data_dff <= {data_dff[STAGES_AMOUNT-2:0], data_in}; + end + end +end : gen_data_sync_cell_multi + +endgenerate + +assign data_out = data_dff[STAGES_AMOUNT-1]; + +endmodule : scr1_data_sync_cell + +//-------------------------------------------------------------------- +// Reset / RDC Qualifyer Adapter Cell +// (Reset Generation Cell w/ RDC Qualifyer Adaptation circuitry) +//-------------------------------------------------------------------- +// Total stages amount = +// 1 Front Sync stage \ +// + 1 (delay introduced by the reset output buffer register) +//-------------------------------------------------------------------- +module scr1_reset_qlfy_adapter_cell_sync ( + input logic rst_n, + input logic clk, + input logic test_rst_n, + input logic test_mode, + input logic reset_n_in_sync, + output logic reset_n_out_qlfy, + output logic reset_n_out, + output logic reset_n_status +); + +logic rst_n_mux; +logic reset_n_front_ff; + +// Front sync stage +assign rst_n_mux = (test_mode == 1'b1) ? test_rst_n : rst_n; + +always_ff @(negedge rst_n_mux, posedge clk) begin + if (~rst_n_mux) begin + reset_n_front_ff <= 1'b0; + end else begin + reset_n_front_ff <= reset_n_in_sync; + end +end + +// Sync reset output for all reset qualifier chains targeting this reset domain +// (for reset-domain-crossings with the given reset domain as a destination). +assign reset_n_out_qlfy = reset_n_front_ff; + +// Reset output buffer +scr1_reset_buf_cell +i_reset_output_buf ( + .rst_n (rst_n), + .clk (clk), + .test_mode (test_mode), + .test_rst_n (test_rst_n), + .reset_n_in (reset_n_front_ff), + .reset_n_out (reset_n_out), + .reset_n_status (reset_n_status) +); + +endmodule : scr1_reset_qlfy_adapter_cell_sync + +module scr1_reset_and2_cell ( + input logic [1:0] rst_n_in, + input logic test_rst_n, + input logic test_mode, + output logic rst_n_out +); + +assign rst_n_out = (test_mode == 1'b1) ? test_rst_n : (&rst_n_in); + +endmodule : scr1_reset_and2_cell + + +module scr1_reset_and3_cell ( + input logic [2:0] rst_n_in, + input logic test_rst_n, + input logic test_mode, + output logic rst_n_out +); + +assign rst_n_out = (test_mode == 1'b1) ? test_rst_n : (&rst_n_in); + +endmodule : scr1_reset_and3_cell + + +module scr1_reset_mux2_cell ( + input logic [1:0] rst_n_in, + input logic select, + input logic test_rst_n, + input logic test_mode, + output logic rst_n_out +); + +assign rst_n_out = (test_mode == 1'b1) ? test_rst_n : rst_n_in[select]; + +endmodule : scr1_reset_mux2_cell diff --git a/src/rtl/scr1/scr1_riscv_isa_decoding.svh b/src/rtl/scr1/scr1_riscv_isa_decoding.svh new file mode 100644 index 0000000..e143d89 --- /dev/null +++ b/src/rtl/scr1/scr1_riscv_isa_decoding.svh @@ -0,0 +1,185 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief RISC-V ISA definitions file +/// + +`ifndef SCR1_RISCV_ISA_DECODING_SVH +`define SCR1_RISCV_ISA_DECODING_SVH + +`include "scr1_arch_description.svh" +`include "scr1_arch_types.svh" + +//------------------------------------------------------------------------------- +// Instruction types +//------------------------------------------------------------------------------- +typedef enum logic [1:0] { + SCR1_INSTR_RVC0 = 2'b00, + SCR1_INSTR_RVC1 = 2'b01, + SCR1_INSTR_RVC2 = 2'b10, + SCR1_INSTR_RVI = 2'b11 +} type_scr1_instr_type_e; + +//------------------------------------------------------------------------------- +// RV32I opcodes (bits 6:2) +//------------------------------------------------------------------------------- +typedef enum logic [6:2] { + SCR1_OPCODE_LOAD = 5'b00000, + SCR1_OPCODE_MISC_MEM = 5'b00011, + SCR1_OPCODE_OP_IMM = 5'b00100, + SCR1_OPCODE_AUIPC = 5'b00101, + SCR1_OPCODE_STORE = 5'b01000, + SCR1_OPCODE_OP = 5'b01100, + SCR1_OPCODE_LUI = 5'b01101, + SCR1_OPCODE_BRANCH = 5'b11000, + SCR1_OPCODE_JALR = 5'b11001, + SCR1_OPCODE_JAL = 5'b11011, + SCR1_OPCODE_SYSTEM = 5'b11100 +} type_scr1_rvi_opcode_e; + + +//------------------------------------------------------------------------------- +// IALU main operands +//------------------------------------------------------------------------------- +localparam SCR1_IALU_OP_ALL_NUM_E = 2; +localparam SCR1_IALU_OP_WIDTH_E = $clog2(SCR1_IALU_OP_ALL_NUM_E); +typedef enum logic [SCR1_IALU_OP_WIDTH_E-1:0] { + SCR1_IALU_OP_REG_IMM, // op1 = rs1; op2 = imm + SCR1_IALU_OP_REG_REG // op1 = rs1; op2 = rs2 +} type_scr1_ialu_op_sel_e; + +//------------------------------------------------------------------------------- +// IALU main commands +//------------------------------------------------------------------------------- +`ifdef SCR1_RVM_EXT +localparam SCR1_IALU_CMD_ALL_NUM_E = 23; +`else // ~SCR1_RVM_EXT +localparam SCR1_IALU_CMD_ALL_NUM_E = 15; +`endif // ~SCR1_RVM_EXT +localparam SCR1_IALU_CMD_WIDTH_E = $clog2(SCR1_IALU_CMD_ALL_NUM_E); +typedef enum logic [SCR1_IALU_CMD_WIDTH_E-1:0] { + SCR1_IALU_CMD_NONE = '0, // IALU disable + SCR1_IALU_CMD_AND, // op1 & op2 + SCR1_IALU_CMD_OR, // op1 | op2 + SCR1_IALU_CMD_XOR, // op1 ^ op2 + SCR1_IALU_CMD_ADD, // op1 + op2 + SCR1_IALU_CMD_SUB, // op1 - op2 + SCR1_IALU_CMD_SUB_LT, // op1 < op2 + SCR1_IALU_CMD_SUB_LTU, // op1 u< op2 + SCR1_IALU_CMD_SUB_EQ, // op1 = op2 + SCR1_IALU_CMD_SUB_NE, // op1 != op2 + SCR1_IALU_CMD_SUB_GE, // op1 >= op2 + SCR1_IALU_CMD_SUB_GEU, // op1 u>= op2 + SCR1_IALU_CMD_SLL, // op1 << op2 + SCR1_IALU_CMD_SRL, // op1 >> op2 + SCR1_IALU_CMD_SRA // op1 >>> op2 +`ifdef SCR1_RVM_EXT + , + SCR1_IALU_CMD_MUL, // low(unsig(op1) * unsig(op2)) + SCR1_IALU_CMD_MULHU, // high(unsig(op1) * unsig(op2)) + SCR1_IALU_CMD_MULHSU, // high(op1 * unsig(op2)) + SCR1_IALU_CMD_MULH, // high(op1 * op2) + SCR1_IALU_CMD_DIV, // op1 / op2 + SCR1_IALU_CMD_DIVU, // op1 u/ op2 + SCR1_IALU_CMD_REM, // op1 % op2 + SCR1_IALU_CMD_REMU // op1 u% op2 +`endif // SCR1_RVM_EXT +} type_scr1_ialu_cmd_sel_e; + +//------------------------------------------------------------------------------- +// IALU SUM2 operands (result is JUMP/BRANCH target, LOAD/STORE address) +//------------------------------------------------------------------------------- +localparam SCR1_SUM2_OP_ALL_NUM_E = 2; +localparam SCR1_SUM2_OP_WIDTH_E = $clog2(SCR1_SUM2_OP_ALL_NUM_E); +typedef enum logic [SCR1_SUM2_OP_WIDTH_E-1:0] { + SCR1_SUM2_OP_PC_IMM, // op1 = curr_pc; op2 = imm (AUIPC, target new_pc for JAL and branches) + SCR1_SUM2_OP_REG_IMM // op1 = rs1; op2 = imm (target new_pc for JALR, LOAD/STORE address) +`ifdef SCR1_XPROP_EN + , + SCR1_SUM2_OP_ERROR = 'x +`endif // SCR1_XPROP_EN +} type_scr1_ialu_sum2_op_sel_e; + +//------------------------------------------------------------------------------- +// LSU commands +//------------------------------------------------------------------------------- +localparam SCR1_LSU_CMD_ALL_NUM_E = 9; +localparam SCR1_LSU_CMD_WIDTH_E = $clog2(SCR1_LSU_CMD_ALL_NUM_E); +typedef enum logic [SCR1_LSU_CMD_WIDTH_E-1:0] { + SCR1_LSU_CMD_NONE = '0, + SCR1_LSU_CMD_LB, + SCR1_LSU_CMD_LH, + SCR1_LSU_CMD_LW, + SCR1_LSU_CMD_LBU, + SCR1_LSU_CMD_LHU, + SCR1_LSU_CMD_SB, + SCR1_LSU_CMD_SH, + SCR1_LSU_CMD_SW +} type_scr1_lsu_cmd_sel_e; + +//------------------------------------------------------------------------------- +// CSR operands +//------------------------------------------------------------------------------- +localparam SCR1_CSR_OP_ALL_NUM_E = 2; +localparam SCR1_CSR_OP_WIDTH_E = $clog2(SCR1_CSR_OP_ALL_NUM_E); +typedef enum logic [SCR1_CSR_OP_WIDTH_E-1:0] { + SCR1_CSR_OP_IMM, + SCR1_CSR_OP_REG +} type_scr1_csr_op_sel_e; + +//------------------------------------------------------------------------------- +// CSR commands +//------------------------------------------------------------------------------- +localparam SCR1_CSR_CMD_ALL_NUM_E = 4; +localparam SCR1_CSR_CMD_WIDTH_E = $clog2(SCR1_CSR_CMD_ALL_NUM_E); +typedef enum logic [SCR1_CSR_CMD_WIDTH_E-1:0] { + SCR1_CSR_CMD_NONE = '0, + SCR1_CSR_CMD_WRITE, + SCR1_CSR_CMD_SET, + SCR1_CSR_CMD_CLEAR +} type_scr1_csr_cmd_sel_e; + +//------------------------------------------------------------------------------- +// MPRF rd writeback source +//------------------------------------------------------------------------------- +localparam SCR1_RD_WB_ALL_NUM_E = 7; +localparam SCR1_RD_WB_WIDTH_E = $clog2(SCR1_RD_WB_ALL_NUM_E); +typedef enum logic [SCR1_RD_WB_WIDTH_E-1:0] { + SCR1_RD_WB_NONE = '0, + SCR1_RD_WB_IALU, // IALU main result + SCR1_RD_WB_SUM2, // IALU SUM2 result (AUIPC) + SCR1_RD_WB_IMM, // LUI + SCR1_RD_WB_INC_PC, // JAL(R) + SCR1_RD_WB_LSU, // Load from DMEM + SCR1_RD_WB_CSR // Read CSR +} type_scr1_rd_wb_sel_e; + +//------------------------------------------------------------------------------- +// IDU to EXU full command structure +//------------------------------------------------------------------------------- +localparam SCR1_GPR_FIELD_WIDTH = 5; + +typedef struct packed { + logic instr_rvc; // used with a different meaning for IFU access fault exception + type_scr1_ialu_op_sel_e ialu_op; + type_scr1_ialu_cmd_sel_e ialu_cmd; + type_scr1_ialu_sum2_op_sel_e sum2_op; + type_scr1_lsu_cmd_sel_e lsu_cmd; + type_scr1_csr_op_sel_e csr_op; + type_scr1_csr_cmd_sel_e csr_cmd; + type_scr1_rd_wb_sel_e rd_wb_sel; + logic jump_req; + logic branch_req; + logic mret_req; + logic fencei_req; + logic wfi_req; + logic [SCR1_GPR_FIELD_WIDTH-1:0] rs1_addr; // also used as zimm for CSRRxI instructions + logic [SCR1_GPR_FIELD_WIDTH-1:0] rs2_addr; + logic [SCR1_GPR_FIELD_WIDTH-1:0] rd_addr; + logic [`SCR1_XLEN-1:0] imm; // used as {funct3, CSR address} for CSR instructions + // used as instruction field for illegal instruction exception + logic exc_req; + type_scr1_exc_code_e exc_code; +} type_scr1_exu_cmd_s; + +`endif // SCR1_RISCV_ISA_DECODING_SVH + diff --git a/src/rtl/scr1/scr1_scu.sv b/src/rtl/scr1/scr1_scu.sv new file mode 100644 index 0000000..9d2aee7 --- /dev/null +++ b/src/rtl/scr1/scr1_scu.sv @@ -0,0 +1,516 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @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[$bits(type_scr1_scu_sysctrl_dr_s)-1:1]} + : 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 + +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 (int unsigned i = 0; i < $bits(type_scr1_scu_sysctrl_status_reg_s); ++i) begin + 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) begin end +$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"); + +// 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 // SCR1_TRGT_SIMULATION + +endmodule : scr1_scu +`endif // SCR1_DBG_EN + diff --git a/src/rtl/scr1/scr1_scu.svh b/src/rtl/scr1/scr1_scu.svh new file mode 100644 index 0000000..ab19386 --- /dev/null +++ b/src/rtl/scr1/scr1_scu.svh @@ -0,0 +1,84 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief SCU header file +/// + +`ifndef SCR1_INCLUDE_SCU_DEFS +`define SCR1_INCLUDE_SCU_DEFS + +//`include "scr1_arch_description.svh" + +`ifdef SCR1_DBG_EN + +//============================================================================== +// Parameters +//============================================================================== +localparam int unsigned SCR1_SCU_DR_SYSCTRL_OP_WIDTH = 2; +localparam int unsigned SCR1_SCU_DR_SYSCTRL_ADDR_WIDTH = 2; +localparam int unsigned SCR1_SCU_DR_SYSCTRL_DATA_WIDTH = 4; + +//============================================================================== +// Types +//============================================================================== +typedef enum logic [SCR1_SCU_DR_SYSCTRL_OP_WIDTH-1:0] { + SCR1_SCU_SYSCTRL_OP_WRITE = 2'h0, + SCR1_SCU_SYSCTRL_OP_READ = 2'h1, + SCR1_SCU_SYSCTRL_OP_SETBITS = 2'h2, + SCR1_SCU_SYSCTRL_OP_CLRBITS = 2'h3 +`ifdef SCR1_XPROP_EN + , + SCR1_SCU_SYSCTRL_OP_XXX = 'X +`endif // SCR1_XPROP_EN +} type_scr1_scu_sysctrl_op_e; + +typedef enum logic [SCR1_SCU_DR_SYSCTRL_ADDR_WIDTH-1:0] { + SCR1_SCU_SYSCTRL_ADDR_CONTROL = 2'h0, + SCR1_SCU_SYSCTRL_ADDR_MODE = 2'h1, + SCR1_SCU_SYSCTRL_ADDR_STATUS = 2'h2, + SCR1_SCU_SYSCTRL_ADDR_STICKY = 2'h3 +`ifdef SCR1_XPROP_EN + , + SCR1_SCU_SYSCTRL_ADDR_XXX = 'X +`endif // SCR1_XPROP_EN +} type_scr1_scu_sysctrl_addr_e; + +typedef struct packed { + logic [SCR1_SCU_DR_SYSCTRL_DATA_WIDTH-1:0] data; + logic [SCR1_SCU_DR_SYSCTRL_ADDR_WIDTH-1:0] addr; + logic [SCR1_SCU_DR_SYSCTRL_OP_WIDTH-1:0] op; +} type_scr1_scu_sysctrl_dr_s; + +typedef enum int unsigned { + SCR1_SCU_DR_SYSCTRL_OP_BIT_R = 'h0, + SCR1_SCU_DR_SYSCTRL_OP_BIT_L = SCR1_SCU_DR_SYSCTRL_OP_WIDTH-1, + SCR1_SCU_DR_SYSCTRL_ADDR_BIT_R = SCR1_SCU_DR_SYSCTRL_OP_WIDTH, + SCR1_SCU_DR_SYSCTRL_ADDR_BIT_L = SCR1_SCU_DR_SYSCTRL_OP_WIDTH + + SCR1_SCU_DR_SYSCTRL_ADDR_WIDTH - 1, + SCR1_SCU_DR_SYSCTRL_DATA_BIT_R = SCR1_SCU_DR_SYSCTRL_OP_WIDTH + + SCR1_SCU_DR_SYSCTRL_ADDR_WIDTH, + SCR1_SCU_DR_SYSCTRL_DATA_BIT_L = SCR1_SCU_DR_SYSCTRL_OP_WIDTH + + SCR1_SCU_DR_SYSCTRL_ADDR_WIDTH + + SCR1_SCU_DR_SYSCTRL_DATA_WIDTH - 1 +} type_scr1_scu_sysctrl_dr_bits_e; + +typedef struct packed { + logic [1:0] rsrv; + logic core_reset; + logic sys_reset; +} type_scr1_scu_sysctrl_control_reg_s; + +typedef struct packed { + logic [1:0] rsrv; + logic hdu_rst_bhv; + logic dm_rst_bhv; +} type_scr1_scu_sysctrl_mode_reg_s; + +typedef struct packed { + logic hdu_reset; + logic dm_reset; + logic core_reset; + logic sys_reset; +} type_scr1_scu_sysctrl_status_reg_s; + +`endif // SCR1_DBG_EN +`endif // SCR1_INCLUDE_SCU_DEFS diff --git a/src/rtl/scr1/scr1_search_ms1.svh b/src/rtl/scr1/scr1_search_ms1.svh new file mode 100644 index 0000000..8ba97c2 --- /dev/null +++ b/src/rtl/scr1/scr1_search_ms1.svh @@ -0,0 +1,94 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Most significant one search function +/// + +`ifndef SCR1_SEARCH_MS1_SVH +`define SCR1_SEARCH_MS1_SVH + +//------------------------------------------------------------------------------- +// Local types declaration +//------------------------------------------------------------------------------- +typedef struct { + logic vd; + logic idx; +} type_scr1_search_one_2_s; + +typedef struct { + logic vd; + logic [4:0] idx; +} type_scr1_search_one_32_s; + +//------------------------------------------------------------------------------- +// Leading Zeros Count Function +//------------------------------------------------------------------------------- +function automatic type_scr1_search_one_2_s scr1_lead_zeros_cnt_2( + input logic [1:0] din +); + type_scr1_search_one_2_s tmp; +begin + tmp.vd = |din; + tmp.idx = ~din[1]; + return tmp; +end +endfunction : scr1_lead_zeros_cnt_2 + +function automatic logic [4:0] scr1_lead_zeros_cnt_32( + input logic [31:0] din +); +begin + logic [15:0] stage1_vd; + logic [7:0] stage2_vd; + logic [3:0] stage3_vd; + logic [1:0] stage4_vd; + + logic stage1_idx [15:0]; + logic [1:0] stage2_idx [7:0]; + logic [2:0] stage3_idx [3:0]; + logic [3:0] stage4_idx [1:0]; + type_scr1_search_one_32_s tmp; + logic [4:0] res; + + // Stage 1 + for (int unsigned i=0; i<16; ++i) begin + type_scr1_search_one_2_s tmp; + tmp = scr1_lead_zeros_cnt_2(din[(i+1)*2-1-:2]); + stage1_vd[i] = tmp.vd; + stage1_idx[i] = tmp.idx; + end + + // Stage 2 + for (int unsigned i=0; i<8; ++i) begin + type_scr1_search_one_2_s tmp; + tmp = scr1_lead_zeros_cnt_2(stage1_vd[(i+1)*2-1-:2]); + stage2_vd[i] = tmp.vd; + stage2_idx[i] = (tmp.idx) ? {tmp.idx, stage1_idx[2*i]} : {tmp.idx, stage1_idx[2*i+1]}; + end + + // Stage 3 + for (int unsigned i=0; i<4; ++i) begin + type_scr1_search_one_2_s tmp; + tmp = scr1_lead_zeros_cnt_2(stage2_vd[(i+1)*2-1-:2]); + stage3_vd[i] = tmp.vd; + stage3_idx[i] = (tmp.idx) ? {tmp.idx, stage2_idx[2*i]} : {tmp.idx, stage2_idx[2*i+1]}; + end + + // Stage 4 + for (int unsigned i=0; i<2; ++i) begin + type_scr1_search_one_2_s tmp; + tmp = scr1_lead_zeros_cnt_2(stage3_vd[(i+1)*2-1-:2]); + stage4_vd[i] = tmp.vd; + stage4_idx[i] = (tmp.idx) ? {tmp.idx, stage3_idx[2*i]} : {tmp.idx, stage3_idx[2*i+1]}; + end + + // Stage 5 + tmp.vd = |stage4_vd; + tmp.idx = (stage4_vd[1]) ? {1'b0, stage4_idx[1]} : {1'b1, stage4_idx[0]}; + + res = tmp.idx; + + return res; +end +endfunction : scr1_lead_zeros_cnt_32 + +`endif // SCR1_SEARCH_MS1_SVH diff --git a/src/rtl/scr1/scr1_tapc.sv b/src/rtl/scr1/scr1_tapc.sv new file mode 100644 index 0000000..45687f4 --- /dev/null +++ b/src/rtl/scr1/scr1_tapc.sv @@ -0,0 +1,457 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief TAP Controller (TAPC) +/// + +//------------------------------------------------------------------------------ + // + // Functionality: + // - Controls TAP operation + // - Allows debugger to access TAP Data registers and DMI/SCU scan-chains via + // command written in Instruction register + // + // Structure: + // - Synchronous reset generation + // - TAPC FSM + // - TAPC Instruction Registers + // - TAPC DRs/DMI/SCU scan-chains + // - TAPC TDO enable and output Registers + // - TAPC Data Registers + // - BYPASS + // - IDCODE + // - BUILD ID + // +//------------------------------------------------------------------------------ + +`include "scr1_arch_description.svh" + +`ifdef SCR1_DBG_EN +`include "scr1_tapc.svh" +`include "scr1_dm.svh" + +module scr1_tapc ( + // JTAG signals + input logic tapc_trst_n, // Test Reset (TRSTn) + input logic tapc_tck, // Test Clock (TCK) + input logic tapc_tms, // Test Mode Select (TMS) + input logic tapc_tdi, // Test Data Input (TDI) + output logic tapc_tdo, // Test Data Output (TDO) + output logic tapc_tdo_en, // TDO Enable, signal for TDO buffer control + + // Fuses: + input logic [31:0] soc2tapc_fuse_idcode_i, // IDCODE value from fuses + + // DMI/SCU scan-chains + output logic tapc2tapcsync_scu_ch_sel_o, // SCU Chain Select + output logic tapc2tapcsync_dmi_ch_sel_o, // DMI Chain Select + output logic [SCR1_DBG_DMI_CH_ID_WIDTH-1:0] tapc2tapcsync_ch_id_o, // DMI/SCU Chain Identifier + output logic tapc2tapcsync_ch_capture_o, // DMI/SCU Chain Capture + output logic tapc2tapcsync_ch_shift_o, // DMI/SCU Chain Shift + output logic tapc2tapcsync_ch_update_o, // DMI/SCU Chain Update + output logic tapc2tapcsync_ch_tdi_o, // DMI/SCU Chain TDI + input logic tapcsync2tapc_ch_tdo_i // DMI/SCU Chain TDO +); + +//------------------------------------------------------------------------------ +// Local Signals +//------------------------------------------------------------------------------ + +logic trst_n_int; // Sync reset signal + +// TAPC FSM signals +//------------------------------------------------------------------------------ + +type_scr1_tap_state_e tap_fsm_ff; // TAP's current state +type_scr1_tap_state_e tap_fsm_next; // TAP's next state + +// Control signals +logic tap_fsm_reset; +logic tap_fsm_ir_upd; +logic tap_fsm_ir_cap; +logic tap_fsm_ir_shft; + +// Registered control signals +logic tap_fsm_ir_shift_ff; +logic tap_fsm_ir_shift_next; +logic tap_fsm_dr_capture_ff; +logic tap_fsm_dr_capture_next; +logic tap_fsm_dr_shift_ff; +logic tap_fsm_dr_shift_next; +logic tap_fsm_dr_update_ff; +logic tap_fsm_dr_update_next; + +// TAPC Instruction Registers signals +//------------------------------------------------------------------------------ + +logic [SCR1_TAP_INSTRUCTION_WIDTH-1:0] tap_ir_shift_ff; // Instruction Shift Register +logic [SCR1_TAP_INSTRUCTION_WIDTH-1:0] tap_ir_shift_next; // Instruction Shift Register next value +logic [SCR1_TAP_INSTRUCTION_WIDTH-1:0] tap_ir_ff; // Instruction Register +logic [SCR1_TAP_INSTRUCTION_WIDTH-1:0] tap_ir_next; // Instruction Register next value + +// TAPC Data Registers signals +//------------------------------------------------------------------------------ + +// BYPASS register +logic dr_bypass_sel; +logic dr_bypass_tdo; + +// IDCODE register +logic dr_idcode_sel; +logic dr_idcode_tdo; + +// BUILD ID register +logic dr_bld_id_sel; +logic dr_bld_id_tdo; + +logic dr_out; + +// TDO registers +//------------------------------------------------------------------------------ + +// TDO enable register +logic tdo_en_ff; +logic tdo_en_next; + +// TDO output register +logic tdo_out_ff; +logic tdo_out_next; + +//------------------------------------------------------------------------------ +// TAPC Synchronous Reset logic +//------------------------------------------------------------------------------ + +always_ff @(negedge tapc_tck, negedge tapc_trst_n) begin + if (~tapc_trst_n) begin + trst_n_int <= 1'b0; + end else begin + trst_n_int <= ~tap_fsm_reset; + end +end + +//------------------------------------------------------------------------------ +// TAP's FSM +//------------------------------------------------------------------------------ + +always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin + if (~tapc_trst_n) begin + tap_fsm_ff <= SCR1_TAP_STATE_RESET; + end else begin + tap_fsm_ff <= tap_fsm_next; + end +end + +always_comb begin + case (tap_fsm_ff) + SCR1_TAP_STATE_RESET : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_RESET : SCR1_TAP_STATE_IDLE; + SCR1_TAP_STATE_IDLE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_SEL_SCAN : SCR1_TAP_STATE_IDLE; + SCR1_TAP_STATE_DR_SEL_SCAN: tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_IR_SEL_SCAN : SCR1_TAP_STATE_DR_CAPTURE; + SCR1_TAP_STATE_DR_CAPTURE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_EXIT1 : SCR1_TAP_STATE_DR_SHIFT; + SCR1_TAP_STATE_DR_SHIFT : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_EXIT1 : SCR1_TAP_STATE_DR_SHIFT; + SCR1_TAP_STATE_DR_EXIT1 : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_UPDATE : SCR1_TAP_STATE_DR_PAUSE; + SCR1_TAP_STATE_DR_PAUSE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_EXIT2 : SCR1_TAP_STATE_DR_PAUSE; + SCR1_TAP_STATE_DR_EXIT2 : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_UPDATE : SCR1_TAP_STATE_DR_SHIFT; + SCR1_TAP_STATE_DR_UPDATE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_SEL_SCAN : SCR1_TAP_STATE_IDLE; + SCR1_TAP_STATE_IR_SEL_SCAN: tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_RESET : SCR1_TAP_STATE_IR_CAPTURE; + SCR1_TAP_STATE_IR_CAPTURE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_IR_EXIT1 : SCR1_TAP_STATE_IR_SHIFT; + SCR1_TAP_STATE_IR_SHIFT : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_IR_EXIT1 : SCR1_TAP_STATE_IR_SHIFT; + SCR1_TAP_STATE_IR_EXIT1 : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_IR_UPDATE : SCR1_TAP_STATE_IR_PAUSE; + SCR1_TAP_STATE_IR_PAUSE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_IR_EXIT2 : SCR1_TAP_STATE_IR_PAUSE; + SCR1_TAP_STATE_IR_EXIT2 : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_IR_UPDATE : SCR1_TAP_STATE_IR_SHIFT; + SCR1_TAP_STATE_IR_UPDATE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_SEL_SCAN : SCR1_TAP_STATE_IDLE; +`ifdef SCR1_XPROP_EN + default : tap_fsm_next = SCR1_TAP_STATE_XXX; +`else // SCR1_XPROP_EN + default : tap_fsm_next = tap_fsm_ff; +`endif // SCR1_XPROP_EN + endcase +end + +assign tap_fsm_reset = (tap_fsm_ff == SCR1_TAP_STATE_RESET); +assign tap_fsm_ir_upd = (tap_fsm_ff == SCR1_TAP_STATE_IR_UPDATE); +assign tap_fsm_ir_cap = (tap_fsm_ff == SCR1_TAP_STATE_IR_CAPTURE); +assign tap_fsm_ir_shft = (tap_fsm_ff == SCR1_TAP_STATE_IR_SHIFT); + +//------------------------------------------------------------------------------ +// TAPC Instruction Registers +//------------------------------------------------------------------------------ + +// TAPC Instruction Shift register +//------------------------------------------------------------------------------ + +always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin + if (~tapc_trst_n) begin + tap_ir_shift_ff <= '0; + end else if (~trst_n_int) begin + tap_ir_shift_ff <= '0; + end else begin + tap_ir_shift_ff <= tap_ir_shift_next; + end +end + +assign tap_ir_shift_next = tap_fsm_ir_cap ? {{($bits(tap_ir_shift_ff)-1){1'b0}}, 1'b1} + : tap_fsm_ir_shft ? {tapc_tdi, tap_ir_shift_ff[$left(tap_ir_shift_ff):1]} + : tap_ir_shift_ff; + +// TAPC Instruction register +//------------------------------------------------------------------------------ + +always_ff @(negedge tapc_tck, negedge tapc_trst_n) begin + if (~tapc_trst_n) begin + tap_ir_ff <= SCR1_TAP_INSTR_IDCODE; + end else if (~trst_n_int) begin + tap_ir_ff <= SCR1_TAP_INSTR_IDCODE; + end else begin + tap_ir_ff <= tap_ir_next; + end +end + +assign tap_ir_next = tap_fsm_ir_upd ? tap_ir_shift_ff : tap_ir_ff; + +//------------------------------------------------------------------------------ +// Control signals +//------------------------------------------------------------------------------ + +always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin + if (~tapc_trst_n) begin + tap_fsm_ir_shift_ff <= 1'b0; + end else if (~trst_n_int) begin + tap_fsm_ir_shift_ff <= 1'b0; + end else begin + tap_fsm_ir_shift_ff <= tap_fsm_ir_shift_next; + end +end + +assign tap_fsm_ir_shift_next = (tap_fsm_next == SCR1_TAP_STATE_IR_SHIFT); + +always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin + if (~tapc_trst_n) begin + tap_fsm_dr_capture_ff <= 1'b0; + end else if (~trst_n_int) begin + tap_fsm_dr_capture_ff <= 1'b0; + end else begin + tap_fsm_dr_capture_ff <= tap_fsm_dr_capture_next; + end +end + +assign tap_fsm_dr_capture_next = (tap_fsm_next == SCR1_TAP_STATE_DR_CAPTURE); + +always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin + if (~tapc_trst_n) begin + tap_fsm_dr_shift_ff <= 1'b0; + end else if (~trst_n_int) begin + tap_fsm_dr_shift_ff <= 1'b0; + end else begin + tap_fsm_dr_shift_ff <= tap_fsm_dr_shift_next; + end +end + +assign tap_fsm_dr_shift_next = (tap_fsm_next == SCR1_TAP_STATE_DR_SHIFT); + +always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin + if (~tapc_trst_n) begin + tap_fsm_dr_update_ff <= 1'b0; + end else if (~trst_n_int) begin + tap_fsm_dr_update_ff <= 1'b0; + end else begin + tap_fsm_dr_update_ff <= tap_fsm_dr_update_next; + end +end + +assign tap_fsm_dr_update_next = (tap_fsm_next == SCR1_TAP_STATE_DR_UPDATE); + +//------------------------------------------------------------------------------ +// TAPC DRs/DMI/SCU scan-chains +//------------------------------------------------------------------------------ +// + // Consists of the following functional units: + // - Data source/destination decoder + // - DMI channel ID decoder + +// - Read data multiplexer +// Data source/destination decoder +//------------------------------------------------------------------------------ + +always_comb begin + dr_bypass_sel = 1'b0; + dr_idcode_sel = 1'b0; + dr_bld_id_sel = 1'b0; + tapc2tapcsync_scu_ch_sel_o = 1'b0; + tapc2tapcsync_dmi_ch_sel_o = 1'b0; + case (tap_ir_ff) + SCR1_TAP_INSTR_DTMCS : tapc2tapcsync_dmi_ch_sel_o = 1'b1; + SCR1_TAP_INSTR_DMI_ACCESS: tapc2tapcsync_dmi_ch_sel_o = 1'b1; + SCR1_TAP_INSTR_IDCODE : dr_idcode_sel = 1'b1; + SCR1_TAP_INSTR_BYPASS : dr_bypass_sel = 1'b1; + SCR1_TAP_INSTR_BLD_ID : dr_bld_id_sel = 1'b1; + SCR1_TAP_INSTR_SCU_ACCESS: tapc2tapcsync_scu_ch_sel_o = 1'b1; + default : dr_bypass_sel = 1'b1; + endcase +end + +// DMI channel ID decoder +//------------------------------------------------------------------------------ + +always_comb begin + tapc2tapcsync_ch_id_o = '0; + case (tap_ir_ff) + SCR1_TAP_INSTR_DTMCS : tapc2tapcsync_ch_id_o = 'd1; + SCR1_TAP_INSTR_DMI_ACCESS: tapc2tapcsync_ch_id_o = 'd2; + default : tapc2tapcsync_ch_id_o = '0; + endcase +end + +// Read data multiplexer +//------------------------------------------------------------------------------ + +always_comb begin + dr_out = 1'b0; + case (tap_ir_ff) + SCR1_TAP_INSTR_DTMCS : dr_out = tapcsync2tapc_ch_tdo_i; + SCR1_TAP_INSTR_DMI_ACCESS: dr_out = tapcsync2tapc_ch_tdo_i; + SCR1_TAP_INSTR_IDCODE : dr_out = dr_idcode_tdo; + SCR1_TAP_INSTR_BYPASS : dr_out = dr_bypass_tdo; + SCR1_TAP_INSTR_BLD_ID : dr_out = dr_bld_id_tdo; + SCR1_TAP_INSTR_SCU_ACCESS: dr_out = tapcsync2tapc_ch_tdo_i; + default : dr_out = dr_bypass_tdo; + endcase +end + +//------------------------------------------------------------------------------ +// TDO enable and output registers +//------------------------------------------------------------------------------ + +// TDO enable register +//------------------------------------------------------------------------------ + +always_ff @(negedge tapc_tck, negedge tapc_trst_n) begin + if (~tapc_trst_n) begin + tdo_en_ff <= 1'b0; + end else if (~trst_n_int) begin + tdo_en_ff <= 1'b0; + end else begin + tdo_en_ff <= tdo_en_next; + end +end + +assign tdo_en_next = tap_fsm_dr_shift_ff | tap_fsm_ir_shift_ff; + +// TDO output register +//------------------------------------------------------------------------------ + +always_ff @(negedge tapc_tck, negedge tapc_trst_n) begin + if (~tapc_trst_n) begin + tdo_out_ff <= 1'b0; + end else if (~trst_n_int) begin + tdo_out_ff <= 1'b0; + end else begin + tdo_out_ff <= tdo_out_next; + end +end + +assign tdo_out_next = tap_fsm_dr_shift_ff ? dr_out + : tap_fsm_ir_shift_ff ? tap_ir_shift_ff[0] + : 1'b0; + +// TAPC TDO signals +assign tapc_tdo_en = tdo_en_ff; +assign tapc_tdo = tdo_out_ff; + +//------------------------------------------------------------------------------ +// TAPC Data Registers +//------------------------------------------------------------------------------ +// + // Registers: + // - BYPASS register + // - IDCODE register + // - BUILD ID register + +// BYPASS register +//------------------------------------------------------------------------------ +// 1-bit mandatory IEEE 1149.1 compliant register + +scr1_tapc_shift_reg #( + .SCR1_WIDTH (SCR1_TAP_DR_BYPASS_WIDTH), + .SCR1_RESET_VALUE (SCR1_TAP_DR_BYPASS_WIDTH'(0)) +) i_bypass_reg ( + .clk (tapc_tck ), + .rst_n (tapc_trst_n ), + .rst_n_sync (trst_n_int ), + .fsm_dr_select (dr_bypass_sel ), + .fsm_dr_capture (tap_fsm_dr_capture_ff), + .fsm_dr_shift (tap_fsm_dr_shift_ff ), + .din_serial (tapc_tdi ), + .din_parallel (1'b0 ), + .dout_serial (dr_bypass_tdo ), + .dout_parallel ( ) +); + +// IDCODE register +//------------------------------------------------------------------------------ +// Holds the Device ID value (mandatory IEEE 1149.1 compliant register) + +scr1_tapc_shift_reg #( + .SCR1_WIDTH (SCR1_TAP_DR_IDCODE_WIDTH), + .SCR1_RESET_VALUE (SCR1_TAP_DR_IDCODE_WIDTH'(0)) +) i_tap_idcode_reg ( + .clk (tapc_tck ), + .rst_n (tapc_trst_n ), + .rst_n_sync (trst_n_int ), + .fsm_dr_select (dr_idcode_sel ), + .fsm_dr_capture (tap_fsm_dr_capture_ff ), + .fsm_dr_shift (tap_fsm_dr_shift_ff ), + .din_serial (tapc_tdi ), + .din_parallel (soc2tapc_fuse_idcode_i), + .dout_serial (dr_idcode_tdo ), + .dout_parallel ( ) +); + +// BUILD ID register +//------------------------------------------------------------------------------ +// Holds the BUILD ID value + +scr1_tapc_shift_reg #( + .SCR1_WIDTH (SCR1_TAP_DR_BLD_ID_WIDTH), + .SCR1_RESET_VALUE (SCR1_TAP_DR_BLD_ID_WIDTH'(0)) +) i_tap_dr_bld_id_reg ( + .clk (tapc_tck ), + .rst_n (tapc_trst_n ), + .rst_n_sync (trst_n_int ), + .fsm_dr_select (dr_bld_id_sel ), + .fsm_dr_capture (tap_fsm_dr_capture_ff), + .fsm_dr_shift (tap_fsm_dr_shift_ff ), + .din_serial (tapc_tdi ), + .din_parallel (SCR1_TAP_BLD_ID_VALUE), + .dout_serial (dr_bld_id_tdo ), + .dout_parallel ( ) +); + +//------------------------------------------------------------------------------ +// DMI/SCU scan-chains signals +//------------------------------------------------------------------------------ + +assign tapc2tapcsync_ch_tdi_o = tapc_tdi; +assign tapc2tapcsync_ch_capture_o = tap_fsm_dr_capture_ff; +assign tapc2tapcsync_ch_shift_o = tap_fsm_dr_shift_ff; +assign tapc2tapcsync_ch_update_o = tap_fsm_dr_update_ff; + +`ifdef SCR1_TRGT_SIMULATION +//------------------------------------------------------------------------------- +// Assertion +//------------------------------------------------------------------------------- + +// X checks +SCR1_SVA_TAPC_XCHECK : assert property ( + @(posedge tapc_tck) disable iff (~tapc_trst_n) + !$isunknown({tapc_tms, tapc_tdi}) +) else $error("TAPC error: unknown values"); + +SCR1_SVA_TAPC_XCHECK_NEGCLK : assert property ( + @(negedge tapc_tck) disable iff (tap_fsm_ff != SCR1_TAP_STATE_DR_SHIFT) + !$isunknown({tapcsync2tapc_ch_tdo_i}) +) else $error("TAPC @negedge error: unknown values"); + +`endif // SCR1_TRGT_SIMULATION + +endmodule : scr1_tapc + +`endif // SCR1_DBG_EN diff --git a/src/rtl/scr1/scr1_tapc.svh b/src/rtl/scr1/scr1_tapc.svh new file mode 100644 index 0000000..e96ea44 --- /dev/null +++ b/src/rtl/scr1/scr1_tapc.svh @@ -0,0 +1,66 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief TAPC header file +/// + +`ifndef SCR1_INCLUDE_TAPC_DEFS +`define SCR1_INCLUDE_TAPC_DEFS + +`include "scr1_arch_description.svh" + +`ifdef SCR1_DBG_EN + +//============================================================================== +// Parameters +//============================================================================== +localparam int unsigned SCR1_TAP_STATE_WIDTH = 4; +localparam int unsigned SCR1_TAP_INSTRUCTION_WIDTH = 5; +localparam int unsigned SCR1_TAP_DR_IDCODE_WIDTH = 32; +localparam int unsigned SCR1_TAP_DR_BLD_ID_WIDTH = 32; +localparam int unsigned SCR1_TAP_DR_BYPASS_WIDTH = 1; +//localparam bit [SCR1_TAP_DR_IDCODE_WIDTH-1:0] SCR1_TAP_IDCODE_RISCV_SC = `SCR1_TAP_IDCODE; +localparam bit [SCR1_TAP_DR_BLD_ID_WIDTH-1:0] SCR1_TAP_BLD_ID_VALUE = `SCR1_MIMPID; + +//============================================================================== +// Types +//============================================================================== +typedef enum logic [SCR1_TAP_STATE_WIDTH-1:0] { + SCR1_TAP_STATE_RESET, + SCR1_TAP_STATE_IDLE, + SCR1_TAP_STATE_DR_SEL_SCAN, + SCR1_TAP_STATE_DR_CAPTURE, + SCR1_TAP_STATE_DR_SHIFT, + SCR1_TAP_STATE_DR_EXIT1, + SCR1_TAP_STATE_DR_PAUSE, + SCR1_TAP_STATE_DR_EXIT2, + SCR1_TAP_STATE_DR_UPDATE, + SCR1_TAP_STATE_IR_SEL_SCAN, + SCR1_TAP_STATE_IR_CAPTURE, + SCR1_TAP_STATE_IR_SHIFT, + SCR1_TAP_STATE_IR_EXIT1, + SCR1_TAP_STATE_IR_PAUSE, + SCR1_TAP_STATE_IR_EXIT2, + SCR1_TAP_STATE_IR_UPDATE +`ifdef SCR1_XPROP_EN + , + SCR1_TAP_STATE_XXX = 'X +`endif // SCR1_XPROP_EN +} type_scr1_tap_state_e; + +typedef enum logic [SCR1_TAP_INSTRUCTION_WIDTH - 1:0] { + SCR1_TAP_INSTR_IDCODE = 5'h01, + SCR1_TAP_INSTR_BLD_ID = 5'h04, + SCR1_TAP_INSTR_SCU_ACCESS = 5'h09, + + SCR1_TAP_INSTR_DTMCS = 5'h10, + SCR1_TAP_INSTR_DMI_ACCESS = 5'h11, + + SCR1_TAP_INSTR_BYPASS = 5'h1F +`ifdef SCR1_XPROP_EN + , + SCR1_TAP_INSTR_XXX = 'X +`endif // SCR1_XPROP_EN +} type_scr1_tap_instr_e; + +`endif // SCR1_DBG_EN +`endif // SCR1_INCLUDE_TAPC_DEFS diff --git a/src/rtl/scr1/scr1_tapc_shift_reg.sv b/src/rtl/scr1/scr1_tapc_shift_reg.sv new file mode 100644 index 0000000..f223532 --- /dev/null +++ b/src/rtl/scr1/scr1_tapc_shift_reg.sv @@ -0,0 +1,112 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief TAPC shift register. Parameterized implementation of JTAG TAPC's Shift Register. +/// + +`include "scr1_arch_description.svh" + +`ifdef SCR1_DBG_EN +module scr1_tapc_shift_reg #( + parameter int unsigned SCR1_WIDTH = 8, // Register width, bits + parameter logic [SCR1_WIDTH-1:0] SCR1_RESET_VALUE = '0 // Register's value after reset +) ( + input logic clk, // Clock + input logic rst_n, // Async reset + input logic rst_n_sync, // Sync reset + // TAP FSM's control signals: + input logic fsm_dr_select, // - for this DR selection (operation enabling); + input logic fsm_dr_capture, // - to capture parallel input's data into shift register; + input logic fsm_dr_shift, // - to enable data shifting; + // Inputs: + input logic din_serial, // - serial (shift_reg[msb/SCR1_WIDTH]); + input logic [SCR1_WIDTH-1:0] din_parallel, // - parallel (shift register's input). + // Outputs: + output logic dout_serial, // - serial (shift_reg[0]); + output logic [SCR1_WIDTH-1:0] dout_parallel // - parallel (shift register's output). +); + +//------------------------------------------------------------------------------- +// Local signals declaration +//------------------------------------------------------------------------------- +logic [SCR1_WIDTH-1:0] shift_reg; + +//------------------------------------------------------------------------------- +// Shift register +//------------------------------------------------------------------------------- +generate + if (SCR1_WIDTH > 1) + begin : dr_shift_reg + + always_ff @(posedge clk, negedge rst_n) + begin + if (~rst_n) begin + shift_reg <= SCR1_RESET_VALUE; + end + else if (~rst_n_sync) begin + shift_reg <= SCR1_RESET_VALUE; + end + else if (fsm_dr_select & fsm_dr_capture) begin + shift_reg <= din_parallel; + end + else if (fsm_dr_select & fsm_dr_shift) begin + shift_reg <= {din_serial, shift_reg[SCR1_WIDTH-1:1]}; + end + end + + end + else begin : dr_shift_reg + + always_ff @(posedge clk, negedge rst_n) + begin + if (~rst_n) begin + shift_reg <= SCR1_RESET_VALUE; + end + else if (~rst_n_sync) begin + shift_reg <= SCR1_RESET_VALUE; + end + else if (fsm_dr_select & fsm_dr_capture) begin + shift_reg <= din_parallel; + end + else if (fsm_dr_select & fsm_dr_shift) begin + shift_reg <= din_serial; + end + end + + end +endgenerate + +//------------------------------------------------------------------------------- +// Parallel output +//------------------------------------------------------------------------------- +assign dout_parallel = shift_reg; + +//------------------------------------------------------------------------------- +// Serial output +//------------------------------------------------------------------------------- +assign dout_serial = shift_reg[0]; + +`ifdef SCR1_TRGT_SIMULATION +//------------------------------------------------------------------------------- +// Assertion +//------------------------------------------------------------------------------- + +// X checks +SCR1_SVA_TAPC_SHIFTREG_XCHECK : assert property ( + @(negedge clk) disable iff (~rst_n) + !$isunknown({ + rst_n_sync, + fsm_dr_select, + fsm_dr_capture, + fsm_dr_shift, + din_serial, + din_parallel + }) +) else begin + $error("TAPC Shift Reg error: unknown values"); +end + +`endif // SCR1_TRGT_SIMULATION + +endmodule : scr1_tapc_shift_reg + +`endif // SCR1_DBG_EN diff --git a/src/rtl/scr1/scr1_tapc_synchronizer.sv b/src/rtl/scr1/scr1_tapc_synchronizer.sv new file mode 100644 index 0000000..a8b498c --- /dev/null +++ b/src/rtl/scr1/scr1_tapc_synchronizer.sv @@ -0,0 +1,183 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief TAPC clock domain crossing synchronizer +/// + +`include "scr1_arch_description.svh" + +`ifdef SCR1_DBG_EN +`include "scr1_tapc.svh" +`include "scr1_dm.svh" + +module scr1_tapc_synchronizer ( + // System common signals + input logic pwrup_rst_n, // Power-Up Reset + input logic dm_rst_n, // Debug Module Reset + input logic clk, // System Clock (SysCLK) + + // JTAG common signals + input logic tapc_trst_n, // JTAG Test Reset (TRSTn) + input logic tapc_tck, // JTAG Test Clock (TCK) + + + // DMI/SCU scan-chains + input logic tapc2tapcsync_scu_ch_sel_i, // SCU Chain Select input (TCK domain) + output logic tapcsync2scu_ch_sel_o, // SCU Chain Select output (SysCLK domain) + input logic tapc2tapcsync_dmi_ch_sel_i, // DMI Chain Select input (TCK domain) + output logic tapcsync2dmi_ch_sel_o, // DMI Chain Select output (SysCLK domain) + + input logic [SCR1_DBG_DMI_CH_ID_WIDTH-1:0] tapc2tapcsync_ch_id_i, // DMI/SCU Chain Identifier input (TCK domain) + output logic [SCR1_DBG_DMI_CH_ID_WIDTH-1:0] tapcsync2core_ch_id_o, // DMI/SCU Chain Identifier output (SysCLK domain) + + input logic tapc2tapcsync_ch_capture_i, // DMI/SCU Chain Capture input (TCK domain) + output logic tapcsync2core_ch_capture_o, // DMI/SCU Chain Capture output (SysCLK domain) + + input logic tapc2tapcsync_ch_shift_i, // DMI/SCU Chain Shift input (TCK domain) + output logic tapcsync2core_ch_shift_o, // DMI/SCU Chain Shift output (SysCLK domain) + + input logic tapc2tapcsync_ch_update_i, // DMI/SCU Chain Update input (TCK domain) + output logic tapcsync2core_ch_update_o, // DMI/SCU Chain Update output (SysCLK domain) + + input logic tapc2tapcsync_ch_tdi_i, // DMI/SCU Chain TDI input (TCK domain) + output logic tapcsync2core_ch_tdi_o, // DMI/SCU Chain TDI output (SysCLK domain) + + output logic tapc2tapcsync_ch_tdo_i, // DMI/SCU Chain TDO output (TCK domain) + input logic tapcsync2core_ch_tdo_o // DMI/SCU Chain TDO input (SysCLK domain) +); + +//------------------------------------------------------------------------------- +// Local signals declaration +//------------------------------------------------------------------------------- + +logic tck_divpos; +logic tck_divneg; +logic tck_rise_load; +logic tck_rise_reset; +logic tck_fall_load; +logic tck_fall_reset; +logic [3:0] tck_divpos_sync; +logic [3:0] tck_divneg_sync; +logic [2:0] dmi_ch_capture_sync; +logic [2:0] dmi_ch_shift_sync; +logic [2:0] dmi_ch_tdi_sync; + +//------------------------------------------------------------------------------- +// Logic +//------------------------------------------------------------------------------- + +always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin + if (~tapc_trst_n) begin + tck_divpos <= 1'b0; + end else begin + tck_divpos <= ~tck_divpos; + end +end + +always_ff @(negedge tapc_tck, negedge tapc_trst_n) begin + if (~tapc_trst_n) begin + tck_divneg <= 1'b0; + end else begin + tck_divneg <= ~tck_divneg; + end +end + +always_ff @(posedge clk, negedge pwrup_rst_n) begin + if (~pwrup_rst_n) begin + tck_divpos_sync <= 4'd0; + tck_divneg_sync <= 4'd0; + end else begin + tck_divpos_sync <= {tck_divpos_sync[2:0], tck_divpos}; + tck_divneg_sync <= {tck_divneg_sync[2:0], tck_divneg}; + end +end + +assign tck_rise_load = tck_divpos_sync[2] ^ tck_divpos_sync[1]; +assign tck_rise_reset = tck_divpos_sync[3] ^ tck_divpos_sync[2]; +assign tck_fall_load = tck_divneg_sync[2] ^ tck_divneg_sync[1]; +assign tck_fall_reset = tck_divneg_sync[3] ^ tck_divneg_sync[2]; + +always_ff @(posedge clk, negedge pwrup_rst_n) begin + if (~pwrup_rst_n) begin + tapcsync2core_ch_update_o <= '0; + end else begin + if (tck_fall_load) begin + tapcsync2core_ch_update_o <= tapc2tapcsync_ch_update_i; + end else if (tck_fall_reset) begin + tapcsync2core_ch_update_o <= '0; + end + end +end + +always_ff @(negedge tapc_tck, negedge tapc_trst_n) begin + if (~tapc_trst_n) begin + dmi_ch_capture_sync[0] <= '0; + dmi_ch_shift_sync[0] <= '0; + end else begin + dmi_ch_capture_sync[0] <= tapc2tapcsync_ch_capture_i; + dmi_ch_shift_sync[0] <= tapc2tapcsync_ch_shift_i; + end +end + +always_ff @(posedge clk, negedge pwrup_rst_n) begin + if (~pwrup_rst_n) begin + dmi_ch_capture_sync[2:1] <= '0; + dmi_ch_shift_sync[2:1] <= '0; + end else begin + dmi_ch_capture_sync[2:1] <= {dmi_ch_capture_sync[1], dmi_ch_capture_sync[0]}; + dmi_ch_shift_sync[2:1] <= {dmi_ch_shift_sync[1], dmi_ch_shift_sync[0]}; + end +end + +always_ff @(posedge clk, negedge pwrup_rst_n) begin + if (~pwrup_rst_n) begin + dmi_ch_tdi_sync <= '0; + end else begin + dmi_ch_tdi_sync <= {dmi_ch_tdi_sync[1:0], tapc2tapcsync_ch_tdi_i}; + end +end + +always_ff @(posedge clk, negedge pwrup_rst_n) begin + if (~pwrup_rst_n) begin + tapcsync2core_ch_capture_o <= '0; + tapcsync2core_ch_shift_o <= '0; + tapcsync2core_ch_tdi_o <= '0; + end else begin + if (tck_rise_load) begin + tapcsync2core_ch_capture_o <= dmi_ch_capture_sync[2]; + tapcsync2core_ch_shift_o <= dmi_ch_shift_sync[2]; + tapcsync2core_ch_tdi_o <= dmi_ch_tdi_sync[2]; + end else if (tck_rise_reset) begin + tapcsync2core_ch_capture_o <= '0; + tapcsync2core_ch_shift_o <= '0; + tapcsync2core_ch_tdi_o <= '0; + end + end +end + +always_ff @(posedge clk, negedge dm_rst_n) begin + if (~dm_rst_n) begin + tapcsync2dmi_ch_sel_o <= '0; + tapcsync2core_ch_id_o <= '0; + end else begin + if (tck_rise_load) begin + tapcsync2dmi_ch_sel_o <= tapc2tapcsync_dmi_ch_sel_i; + tapcsync2core_ch_id_o <= tapc2tapcsync_ch_id_i; + end + end +end + +always_ff @(posedge clk, negedge pwrup_rst_n) begin + if (~pwrup_rst_n) begin + tapcsync2scu_ch_sel_o <= '0; + end else begin + if (tck_rise_load) begin + tapcsync2scu_ch_sel_o <= tapc2tapcsync_scu_ch_sel_i; + end + end +end + +assign tapc2tapcsync_ch_tdo_i = tapcsync2core_ch_tdo_o; + +endmodule : scr1_tapc_synchronizer + +`endif // SCR1_DBG_EN diff --git a/src/rtl/scr1/scr1_tcm.sv b/src/rtl/scr1/scr1_tcm.sv new file mode 100644 index 0000000..97376cf --- /dev/null +++ b/src/rtl/scr1/scr1_tcm.sv @@ -0,0 +1,131 @@ +/// Copyright by Syntacore LLC © 2016-2020. See LICENSE for details +/// @file +/// @brief Tightly-Coupled Memory (TCM) +/// + +`include "scr1_memif.svh" +`include "scr1_arch_description.svh" + +`ifdef SCR1_TCM_EN +module scr1_tcm +#( + parameter SCR1_TCM_SIZE = `SCR1_IMEM_AWIDTH'h00010000 +) +( + // Control signals + input logic clk, + input logic rst_n, + + // Core instruction interface + output logic imem_req_ack, + input logic imem_req, + input logic [`SCR1_IMEM_AWIDTH-1:0] imem_addr, + output logic [`SCR1_IMEM_DWIDTH-1:0] imem_rdata, + output type_scr1_mem_resp_e imem_resp, + + // Core data interface + output logic dmem_req_ack, + input logic dmem_req, + input type_scr1_mem_cmd_e dmem_cmd, + input type_scr1_mem_width_e dmem_width, + input logic [`SCR1_DMEM_AWIDTH-1:0] dmem_addr, + input logic [`SCR1_DMEM_DWIDTH-1:0] dmem_wdata, + output logic [`SCR1_DMEM_DWIDTH-1:0] dmem_rdata, + output type_scr1_mem_resp_e dmem_resp +); + +//------------------------------------------------------------------------------- +// Local signal declaration +//------------------------------------------------------------------------------- +logic imem_req_en; +logic dmem_req_en; +logic imem_rd; +logic dmem_rd; +logic dmem_wr; +logic [`SCR1_DMEM_DWIDTH-1:0] dmem_writedata; +logic [`SCR1_DMEM_DWIDTH-1:0] dmem_rdata_local; +logic [3:0] dmem_byteen; +logic [1:0] dmem_rdata_shift_reg; +//------------------------------------------------------------------------------- +// Core interface +//------------------------------------------------------------------------------- +assign imem_req_en = (imem_resp == SCR1_MEM_RESP_RDY_OK) ^ imem_req; +assign dmem_req_en = (dmem_resp == SCR1_MEM_RESP_RDY_OK) ^ dmem_req; + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + imem_resp <= SCR1_MEM_RESP_NOTRDY; + end else if (imem_req_en) begin + imem_resp <= imem_req ? SCR1_MEM_RESP_RDY_OK : SCR1_MEM_RESP_NOTRDY; + end +end + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + dmem_resp <= SCR1_MEM_RESP_NOTRDY; + end else if (dmem_req_en) begin + dmem_resp <= dmem_req ? SCR1_MEM_RESP_RDY_OK : SCR1_MEM_RESP_NOTRDY; + end +end + +assign imem_req_ack = 1'b1; +assign dmem_req_ack = 1'b1; +//------------------------------------------------------------------------------- +// Memory data composing +//------------------------------------------------------------------------------- +assign imem_rd = imem_req; +assign dmem_rd = dmem_req & (dmem_cmd == SCR1_MEM_CMD_RD); +assign dmem_wr = dmem_req & (dmem_cmd == SCR1_MEM_CMD_WR); + +always_comb begin + dmem_writedata = dmem_wdata; + dmem_byteen = 4'b1111; + case ( dmem_width ) + SCR1_MEM_WIDTH_BYTE : begin + dmem_writedata = {(`SCR1_DMEM_DWIDTH / 8){dmem_wdata[7:0]}}; + dmem_byteen = 4'b0001 << dmem_addr[1:0]; + end + SCR1_MEM_WIDTH_HWORD : begin + dmem_writedata = {(`SCR1_DMEM_DWIDTH / 16){dmem_wdata[15:0]}}; + dmem_byteen = 4'b0011 << {dmem_addr[1], 1'b0}; + end + default : begin + end + endcase +end +//------------------------------------------------------------------------------- +// Memory instantiation +//------------------------------------------------------------------------------- +scr1_dp_memory #( + .SCR1_WIDTH ( 32 ), + .SCR1_SIZE ( SCR1_TCM_SIZE ) +) i_dp_memory ( + .clk ( clk ), + // Instruction port + // Port A + .rena ( imem_rd ), + .addra ( imem_addr[$clog2(SCR1_TCM_SIZE)-1:2] ), + .qa ( imem_rdata ), + // Data port + // Port B + .renb ( dmem_rd ), + .wenb ( dmem_wr ), + .webb ( dmem_byteen ), + .addrb ( dmem_addr[$clog2(SCR1_TCM_SIZE)-1:2] ), + .qb ( dmem_rdata_local ), + .datab ( dmem_writedata ) +); +//------------------------------------------------------------------------------- +// Data memory output generation +//------------------------------------------------------------------------------- +always_ff @(posedge clk) begin + if (dmem_rd) begin + dmem_rdata_shift_reg <= dmem_addr[1:0]; + end +end + +assign dmem_rdata = dmem_rdata_local >> ( 8 * dmem_rdata_shift_reg ); + +endmodule : scr1_tcm + +`endif // SCR1_TCM_EN diff --git a/src/rtl/scr1/scr1_tdu.svh b/src/rtl/scr1/scr1_tdu.svh new file mode 100644 index 0000000..efaaec2 --- /dev/null +++ b/src/rtl/scr1/scr1_tdu.svh @@ -0,0 +1,121 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Trigger Debug Module header +/// + +`ifndef SCR1_INCLUDE_TDU_DEFS +`define SCR1_INCLUDE_TDU_DEFS + +//`include "scr1_arch_description.svh" + +`ifdef SCR1_TDU_EN +//`include "scr1_csr.svh" + +`include "scr1_arch_description.svh" +//`include "scr1_arch_types.svh" +`include "scr1_csr.svh" + +parameter int unsigned SCR1_TDU_MTRIG_NUM = SCR1_TDU_TRIG_NUM; +`ifdef SCR1_TDU_ICOUNT_EN +parameter int unsigned SCR1_TDU_ALLTRIG_NUM = SCR1_TDU_MTRIG_NUM + 1'b1; +`else +parameter int unsigned SCR1_TDU_ALLTRIG_NUM = SCR1_TDU_MTRIG_NUM; +`endif + +parameter int unsigned SCR1_TDU_ADDR_W = `SCR1_XLEN; +parameter int unsigned SCR1_TDU_DATA_W = `SCR1_XLEN; + +// Register map +parameter SCR1_CSR_ADDR_TDU_OFFS_W = 3; +parameter bit [SCR1_CSR_ADDR_TDU_OFFS_W-1:0] SCR1_CSR_ADDR_TDU_OFFS_TSELECT = SCR1_CSR_ADDR_TDU_OFFS_W'(0); +parameter bit [SCR1_CSR_ADDR_TDU_OFFS_W-1:0] SCR1_CSR_ADDR_TDU_OFFS_TDATA1 = SCR1_CSR_ADDR_TDU_OFFS_W'(1); +parameter bit [SCR1_CSR_ADDR_TDU_OFFS_W-1:0] SCR1_CSR_ADDR_TDU_OFFS_TDATA2 = SCR1_CSR_ADDR_TDU_OFFS_W'(2); +parameter bit [SCR1_CSR_ADDR_TDU_OFFS_W-1:0] SCR1_CSR_ADDR_TDU_OFFS_TINFO = SCR1_CSR_ADDR_TDU_OFFS_W'(4); + + +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_TDU_TSELECT = SCR1_CSR_ADDR_TDU_MBASE + SCR1_CSR_ADDR_TDU_OFFS_TSELECT; +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_TDU_TDATA1 = SCR1_CSR_ADDR_TDU_MBASE + SCR1_CSR_ADDR_TDU_OFFS_TDATA1; +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_TDU_TDATA2 = SCR1_CSR_ADDR_TDU_MBASE + SCR1_CSR_ADDR_TDU_OFFS_TDATA2; +parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_TDU_TINFO = SCR1_CSR_ADDR_TDU_MBASE + SCR1_CSR_ADDR_TDU_OFFS_TINFO; + +// TDATA1 +parameter int unsigned SCR1_TDU_TDATA1_TYPE_HI = `SCR1_XLEN-1; +parameter int unsigned SCR1_TDU_TDATA1_TYPE_LO = `SCR1_XLEN-4; +parameter int unsigned SCR1_TDU_TDATA1_DMODE = `SCR1_XLEN-5; + +// TDATA1: constant bits values +parameter bit SCR1_TDU_TDATA1_DMODE_VAL = 1'b0; + +// MCONTROL: bits number +parameter int unsigned SCR1_TDU_MCONTROL_MASKMAX_HI = `SCR1_XLEN-6; +parameter int unsigned SCR1_TDU_MCONTROL_MASKMAX_LO = `SCR1_XLEN-11; +parameter int unsigned SCR1_TDU_MCONTROL_RESERVEDB_HI = `SCR1_XLEN-12; +parameter int unsigned SCR1_TDU_MCONTROL_RESERVEDB_LO = 21; +parameter int unsigned SCR1_TDU_MCONTROL_HIT = 20; +parameter int unsigned SCR1_TDU_MCONTROL_SELECT = 19; +parameter int unsigned SCR1_TDU_MCONTROL_TIMING = 18; +parameter int unsigned SCR1_TDU_MCONTROL_ACTION_HI = 17; +parameter int unsigned SCR1_TDU_MCONTROL_ACTION_LO = 12; +parameter int unsigned SCR1_TDU_MCONTROL_CHAIN = 11; +parameter int unsigned SCR1_TDU_MCONTROL_MATCH_HI = 10; +parameter int unsigned SCR1_TDU_MCONTROL_MATCH_LO = 7; +parameter int unsigned SCR1_TDU_MCONTROL_M = 6; +parameter int unsigned SCR1_TDU_MCONTROL_RESERVEDA = 5; +parameter int unsigned SCR1_TDU_MCONTROL_S = 4; +parameter int unsigned SCR1_TDU_MCONTROL_U = 3; +parameter int unsigned SCR1_TDU_MCONTROL_EXECUTE = 2; +parameter int unsigned SCR1_TDU_MCONTROL_STORE = 1; +parameter int unsigned SCR1_TDU_MCONTROL_LOAD = 0; + +// MCONTROL: constant bits values +parameter bit [SCR1_TDU_TDATA1_TYPE_HI-SCR1_TDU_TDATA1_TYPE_LO:0] + SCR1_TDU_MCONTROL_TYPE_VAL = 2'd2; + +parameter bit SCR1_TDU_MCONTROL_SELECT_VAL = 1'b0; +parameter bit SCR1_TDU_MCONTROL_TIMING_VAL = 1'b0; + +parameter bit [SCR1_TDU_MCONTROL_MASKMAX_HI-SCR1_TDU_MCONTROL_MASKMAX_LO:0] + SCR1_TDU_MCONTROL_MASKMAX_VAL = 1'b0; + +parameter bit SCR1_TDU_MCONTROL_RESERVEDA_VAL = 1'b0; + +// ICOUNT: bits number +parameter int unsigned SCR1_TDU_ICOUNT_DMODE = `SCR1_XLEN-5; +parameter int unsigned SCR1_TDU_ICOUNT_RESERVEDB_HI = `SCR1_XLEN-6; +parameter int unsigned SCR1_TDU_ICOUNT_RESERVEDB_LO = 25; +parameter int unsigned SCR1_TDU_ICOUNT_HIT = 24; +parameter int unsigned SCR1_TDU_ICOUNT_COUNT_HI = 23; +parameter int unsigned SCR1_TDU_ICOUNT_COUNT_LO = 10; +parameter int unsigned SCR1_TDU_ICOUNT_M = 9; +parameter int unsigned SCR1_TDU_ICOUNT_RESERVEDA = 8; +parameter int unsigned SCR1_TDU_ICOUNT_S = 7; +parameter int unsigned SCR1_TDU_ICOUNT_U = 6; +parameter int unsigned SCR1_TDU_ICOUNT_ACTION_HI = 5; +parameter int unsigned SCR1_TDU_ICOUNT_ACTION_LO = 0; + +// ICOUNT: constant bits values +parameter bit [SCR1_TDU_TDATA1_TYPE_HI-SCR1_TDU_TDATA1_TYPE_LO:0] + SCR1_TDU_ICOUNT_TYPE_VAL = 2'd3; + +parameter bit [SCR1_TDU_ICOUNT_RESERVEDB_HI-SCR1_TDU_ICOUNT_RESERVEDB_LO:0] + SCR1_TDU_ICOUNT_RESERVEDB_VAL = 1'b0; + +parameter bit SCR1_TDU_ICOUNT_RESERVEDA_VAL = 1'b0; + +// CPU pipeline monitors +typedef struct packed { + logic vd; + logic req; + logic [`SCR1_XLEN-1:0] addr; +} type_scr1_brkm_instr_mon_s; + +typedef struct packed { + logic vd; + logic load; + logic store; + logic [`SCR1_XLEN-1:0] addr; +} type_scr1_brkm_lsu_mon_s; + +`endif // SCR1_TDU_EN + +`endif // SCR1_INCLUDE_TDU_DEFS diff --git a/src/rtl/scr1/scr1_timer.sv b/src/rtl/scr1/scr1_timer.sv new file mode 100644 index 0000000..1926795 --- /dev/null +++ b/src/rtl/scr1/scr1_timer.sv @@ -0,0 +1,271 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Memory-mapped Timer +/// + +`include "scr1_arch_description.svh" +`include "scr1_memif.svh" + +module scr1_timer ( + // Common + input logic rst_n, + input logic clk, + input logic rtc_clk, + + // Memory interface + input logic dmem_req, + input type_scr1_mem_cmd_e dmem_cmd, + input type_scr1_mem_width_e dmem_width, + input logic [`SCR1_DMEM_AWIDTH-1:0] dmem_addr, + input logic [`SCR1_DMEM_DWIDTH-1:0] dmem_wdata, + output logic dmem_req_ack, + output logic [`SCR1_DMEM_DWIDTH-1:0] dmem_rdata, + output type_scr1_mem_resp_e dmem_resp, + + // Timer interface + output logic [63:0] timer_val, + output logic timer_irq +); + +//------------------------------------------------------------------------------- +// Local parameters declaration +//------------------------------------------------------------------------------- +localparam int unsigned SCR1_TIMER_ADDR_WIDTH = 5; +localparam logic [SCR1_TIMER_ADDR_WIDTH-1:0] SCR1_TIMER_CONTROL = 5'h0; +localparam logic [SCR1_TIMER_ADDR_WIDTH-1:0] SCR1_TIMER_DIVIDER = 5'h4; +localparam logic [SCR1_TIMER_ADDR_WIDTH-1:0] SCR1_TIMER_MTIMELO = 5'h8; +localparam logic [SCR1_TIMER_ADDR_WIDTH-1:0] SCR1_TIMER_MTIMEHI = 5'hC; +localparam logic [SCR1_TIMER_ADDR_WIDTH-1:0] SCR1_TIMER_MTIMECMPLO = 5'h10; +localparam logic [SCR1_TIMER_ADDR_WIDTH-1:0] SCR1_TIMER_MTIMECMPHI = 5'h14; + +localparam int unsigned SCR1_TIMER_CONTROL_EN_OFFSET = 0; +localparam int unsigned SCR1_TIMER_CONTROL_CLKSRC_OFFSET = 1; +localparam int unsigned SCR1_TIMER_DIVIDER_WIDTH = 10; + +//------------------------------------------------------------------------------- +// Local signals declaration +//------------------------------------------------------------------------------- +logic [63:0] mtime_reg; +logic [63:0] mtime_new; +logic [63:0] mtimecmp_reg; +logic [63:0] mtimecmp_new; +logic timer_en; +logic timer_clksrc_rtc; +logic [SCR1_TIMER_DIVIDER_WIDTH-1:0] timer_div; + +logic control_up; +logic divider_up; +logic mtimelo_up; +logic mtimehi_up; +logic mtimecmplo_up; +logic mtimecmphi_up; + +logic dmem_req_valid; + +logic [3:0] rtc_sync; +logic rtc_ext_pulse; +logic [SCR1_TIMER_DIVIDER_WIDTH-1:0] timeclk_cnt; +logic timeclk_cnt_en; +logic time_posedge; +logic time_cmp_flag; + +//------------------------------------------------------------------------------- +// Registers +//------------------------------------------------------------------------------- + +// CONTROL +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + timer_en <= 1'b1; + timer_clksrc_rtc <= 1'b0; + end else begin + if (control_up) begin + timer_en <= dmem_wdata[SCR1_TIMER_CONTROL_EN_OFFSET]; + timer_clksrc_rtc <= dmem_wdata[SCR1_TIMER_CONTROL_CLKSRC_OFFSET]; + end + end +end + +// DIVIDER +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + timer_div <= '0; + end else begin + if (divider_up) begin + timer_div <= dmem_wdata[SCR1_TIMER_DIVIDER_WIDTH-1:0]; + end + end +end + +// MTIME +assign time_posedge = (timeclk_cnt_en & (timeclk_cnt == 0)); + +always_comb begin + mtime_new = mtime_reg; + if (time_posedge) begin + mtime_new = mtime_reg + 1'b1; + end + if (mtimelo_up) begin + mtime_new[31:0] = dmem_wdata; + end + if (mtimehi_up) begin + mtime_new[63:32] = dmem_wdata; + end +end + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + mtime_reg <= '0; + end else begin + if (time_posedge | mtimelo_up | mtimehi_up) begin + mtime_reg <= mtime_new; + end + end +end + +// MTIMECMP +always_comb begin + mtimecmp_new = mtimecmp_reg; + if (mtimecmplo_up) begin + mtimecmp_new[31:0] = dmem_wdata; + end + if (mtimecmphi_up) begin + mtimecmp_new[63:32] = dmem_wdata; + end +end + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + mtimecmp_reg <= '0; + end else begin + if (mtimecmplo_up | mtimecmphi_up) begin + mtimecmp_reg <= mtimecmp_new; + end + end +end + +//------------------------------------------------------------------------------- +// Interrupt pending +//------------------------------------------------------------------------------- +assign time_cmp_flag = (mtime_reg >= ((mtimecmplo_up | mtimecmphi_up) ? mtimecmp_new : mtimecmp_reg)); + +always_ff @(posedge clk, negedge rst_n) begin + if (~rst_n) begin + timer_irq <= 1'b0; + end else begin + if (~timer_irq) begin + timer_irq <= time_cmp_flag; + end else begin // 1'b1 + if (mtimecmplo_up | mtimecmphi_up) begin + timer_irq <= time_cmp_flag; + end + end + end +end + +//------------------------------------------------------------------------------- +// Timer divider +//------------------------------------------------------------------------------- +assign timeclk_cnt_en = (~timer_clksrc_rtc ? 1'b1 : rtc_ext_pulse) & timer_en; + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + timeclk_cnt <= '0; + end else begin + case (1'b1) + divider_up : timeclk_cnt <= dmem_wdata[SCR1_TIMER_DIVIDER_WIDTH-1:0]; + time_posedge : timeclk_cnt <= timer_div; + timeclk_cnt_en : timeclk_cnt <= timeclk_cnt - 1'b1; + default : begin end + endcase + end +end + +//------------------------------------------------------------------------------- +// RTC synchronization +//------------------------------------------------------------------------------- +assign rtc_ext_pulse = rtc_sync[3] ^ rtc_sync[2]; + +always_ff @(negedge rst_n, posedge rtc_clk) begin + if (~rst_n) begin + rtc_sync[0] <= 1'b0; + end else begin + if (timer_clksrc_rtc) begin + rtc_sync[0] <= ~rtc_sync[0]; + end + end +end + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + rtc_sync[3:1] <= '0; + end else begin + if (timer_clksrc_rtc) begin + rtc_sync[3:1] <= rtc_sync[2:0]; + end + end +end + +//------------------------------------------------------------------------------- +// Memory interface +//------------------------------------------------------------------------------- +assign dmem_req_valid = (dmem_width == SCR1_MEM_WIDTH_WORD) & (~|dmem_addr[1:0]) & + (dmem_addr[SCR1_TIMER_ADDR_WIDTH-1:2] <= SCR1_TIMER_MTIMECMPHI[SCR1_TIMER_ADDR_WIDTH-1:2]); + +assign dmem_req_ack = 1'b1; + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + dmem_resp <= SCR1_MEM_RESP_NOTRDY; + dmem_rdata <= '0; + end else begin + if (dmem_req) begin + if (dmem_req_valid) begin + dmem_resp <= SCR1_MEM_RESP_RDY_OK; + if (dmem_cmd == SCR1_MEM_CMD_RD) begin + case (dmem_addr[SCR1_TIMER_ADDR_WIDTH-1:0]) + SCR1_TIMER_CONTROL : dmem_rdata <= `SCR1_DMEM_DWIDTH'({timer_clksrc_rtc, timer_en}); + SCR1_TIMER_DIVIDER : dmem_rdata <= `SCR1_DMEM_DWIDTH'(timer_div); + SCR1_TIMER_MTIMELO : dmem_rdata <= mtime_reg[31:0]; + SCR1_TIMER_MTIMEHI : dmem_rdata <= mtime_reg[63:32]; + SCR1_TIMER_MTIMECMPLO : dmem_rdata <= mtimecmp_reg[31:0]; + SCR1_TIMER_MTIMECMPHI : dmem_rdata <= mtimecmp_reg[63:32]; + default : begin end + endcase + end + end else begin + dmem_resp <= SCR1_MEM_RESP_RDY_ER; + end + end else begin + dmem_resp <= SCR1_MEM_RESP_NOTRDY; + dmem_rdata <= '0; + end + end +end + +always_comb begin + control_up = 1'b0; + divider_up = 1'b0; + mtimelo_up = 1'b0; + mtimehi_up = 1'b0; + mtimecmplo_up = 1'b0; + mtimecmphi_up = 1'b0; + if (dmem_req & dmem_req_valid & (dmem_cmd == SCR1_MEM_CMD_WR)) begin + case (dmem_addr[SCR1_TIMER_ADDR_WIDTH-1:0]) + SCR1_TIMER_CONTROL : control_up = 1'b1; + SCR1_TIMER_DIVIDER : divider_up = 1'b1; + SCR1_TIMER_MTIMELO : mtimelo_up = 1'b1; + SCR1_TIMER_MTIMEHI : mtimehi_up = 1'b1; + SCR1_TIMER_MTIMECMPLO : mtimecmplo_up = 1'b1; + SCR1_TIMER_MTIMECMPHI : mtimecmphi_up = 1'b1; + default : begin end + endcase + end +end + +//------------------------------------------------------------------------------- +// Timer interface +//------------------------------------------------------------------------------- +assign timer_val = mtime_reg; + +endmodule : scr1_timer diff --git a/src/rtl/scr1/scr1_top_ahb.sv b/src/rtl/scr1/scr1_top_ahb.sv new file mode 100644 index 0000000..dde2273 --- /dev/null +++ b/src/rtl/scr1/scr1_top_ahb.sv @@ -0,0 +1,513 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief SCR1 AHB top +/// + +`include "scr1_arch_description.svh" +`include "scr1_memif.svh" +`include "scr1_ahb.svh" +`ifdef SCR1_IPIC_EN +`include "scr1_ipic.svh" +`endif // SCR1_IPIC_EN + +`ifdef SCR1_TCM_EN + `define SCR1_IMEM_ROUTER_EN +`endif // SCR1_TCM_EN + +module scr1_top_ahb ( + // Control + input logic pwrup_rst_n, // Power-Up Reset + input logic rst_n, // Regular Reset signal + input logic cpu_rst_n, // CPU Reset (Core Reset) + input logic test_mode, // Test mode + input logic test_rst_n, // Test mode's reset + input logic clk, // System clock + input logic rtc_clk, // Real-time clock +`ifdef SCR1_DBG_EN + output logic sys_rst_n_o, // External System Reset output + // (for the processor cluster's components or + // external SOC (could be useful in small + // SCR-core-centric SOCs)) + output logic sys_rdc_qlfy_o, // System-to-External SOC Reset Domain Crossing Qualifier +`endif // SCR1_DBG_EN + + // Fuses + input logic [`SCR1_XLEN-1:0] fuse_mhartid, // Hart ID +`ifdef SCR1_DBG_EN + input logic [31:0] fuse_idcode, // TAPC IDCODE +`endif // SCR1_DBG_EN + + // IRQ +`ifdef SCR1_IPIC_EN + input logic [SCR1_IRQ_LINES_NUM-1:0] irq_lines, // IRQ lines to IPIC +`else // SCR1_IPIC_EN + input logic ext_irq, // External IRQ input +`endif // SCR1_IPIC_EN + input logic soft_irq, // Software IRQ input + +`ifdef SCR1_DBG_EN + // -- JTAG I/F + input logic trst_n, + input logic tck, + input logic tms, + input logic tdi, + output logic tdo, + output logic tdo_en, +`endif // SCR1_DBG_EN + + // Instruction Memory Interface + output logic [3:0] imem_hprot, + output logic [2:0] imem_hburst, + output logic [2:0] imem_hsize, + output logic [1:0] imem_htrans, + output logic imem_hmastlock, + output logic [SCR1_AHB_WIDTH-1:0] imem_haddr, + input logic imem_hready, + input logic [SCR1_AHB_WIDTH-1:0] imem_hrdata, + input logic imem_hresp, + + // Data Memory Interface + output logic [3:0] dmem_hprot, + output logic [2:0] dmem_hburst, + output logic [2:0] dmem_hsize, + output logic [1:0] dmem_htrans, + output logic dmem_hmastlock, + output logic [SCR1_AHB_WIDTH-1:0] dmem_haddr, + output logic dmem_hwrite, + output logic [SCR1_AHB_WIDTH-1:0] dmem_hwdata, + input logic dmem_hready, + input logic [SCR1_AHB_WIDTH-1:0] dmem_hrdata, + input logic dmem_hresp +); + +//------------------------------------------------------------------------------- +// Local parameters +//------------------------------------------------------------------------------- +localparam int unsigned SCR1_CLUSTER_TOP_RST_SYNC_STAGES_NUM = 2; + +//------------------------------------------------------------------------------- +// Local signal declaration +//------------------------------------------------------------------------------- +// Reset logic +logic pwrup_rst_n_sync; +logic rst_n_sync; +logic cpu_rst_n_sync; +logic core_rst_n_local; +`ifdef SCR1_DBG_EN +logic tapc_trst_n; +`endif // SCR1_DBG_EN + +// Instruction memory interface from core to router +logic core_imem_req_ack; +logic core_imem_req; +type_scr1_mem_cmd_e core_imem_cmd; +logic [`SCR1_IMEM_AWIDTH-1:0] core_imem_addr; +logic [`SCR1_IMEM_DWIDTH-1:0] core_imem_rdata; +type_scr1_mem_resp_e core_imem_resp; + +// Data memory interface from core to router +logic core_dmem_req_ack; +logic core_dmem_req; +type_scr1_mem_cmd_e core_dmem_cmd; +type_scr1_mem_width_e core_dmem_width; +logic [`SCR1_DMEM_AWIDTH-1:0] core_dmem_addr; +logic [`SCR1_DMEM_DWIDTH-1:0] core_dmem_wdata; +logic [`SCR1_DMEM_DWIDTH-1:0] core_dmem_rdata; +type_scr1_mem_resp_e core_dmem_resp; + +// Instruction memory interface from router to AHB bridge +logic ahb_imem_req_ack; +logic ahb_imem_req; +type_scr1_mem_cmd_e ahb_imem_cmd; +logic [`SCR1_IMEM_AWIDTH-1:0] ahb_imem_addr; +logic [`SCR1_IMEM_DWIDTH-1:0] ahb_imem_rdata; +type_scr1_mem_resp_e ahb_imem_resp; + +// Data memory interface from router to AHB bridge +logic ahb_dmem_req_ack; +logic ahb_dmem_req; +type_scr1_mem_cmd_e ahb_dmem_cmd; +type_scr1_mem_width_e ahb_dmem_width; +logic [`SCR1_DMEM_AWIDTH-1:0] ahb_dmem_addr; +logic [`SCR1_DMEM_DWIDTH-1:0] ahb_dmem_wdata; +logic [`SCR1_DMEM_DWIDTH-1:0] ahb_dmem_rdata; +type_scr1_mem_resp_e ahb_dmem_resp; + +`ifdef SCR1_TCM_EN +// Instruction memory interface from router to TCM +logic tcm_imem_req_ack; +logic tcm_imem_req; +type_scr1_mem_cmd_e tcm_imem_cmd; +logic [`SCR1_IMEM_AWIDTH-1:0] tcm_imem_addr; +logic [`SCR1_IMEM_DWIDTH-1:0] tcm_imem_rdata; +type_scr1_mem_resp_e tcm_imem_resp; + +// Data memory interface from router to TCM +logic tcm_dmem_req_ack; +logic tcm_dmem_req; +type_scr1_mem_cmd_e tcm_dmem_cmd; +type_scr1_mem_width_e tcm_dmem_width; +logic [`SCR1_DMEM_AWIDTH-1:0] tcm_dmem_addr; +logic [`SCR1_DMEM_DWIDTH-1:0] tcm_dmem_wdata; +logic [`SCR1_DMEM_DWIDTH-1:0] tcm_dmem_rdata; +type_scr1_mem_resp_e tcm_dmem_resp; +`endif // SCR1_TCM_EN + +// Data memory interface from router to memory-mapped timer +logic timer_dmem_req_ack; +logic timer_dmem_req; +type_scr1_mem_cmd_e timer_dmem_cmd; +type_scr1_mem_width_e timer_dmem_width; +logic [`SCR1_DMEM_AWIDTH-1:0] timer_dmem_addr; +logic [`SCR1_DMEM_DWIDTH-1:0] timer_dmem_wdata; +logic [`SCR1_DMEM_DWIDTH-1:0] timer_dmem_rdata; +type_scr1_mem_resp_e timer_dmem_resp; + +logic timer_irq; +logic [63:0] timer_val; + + +//------------------------------------------------------------------------------- +// Reset logic +//------------------------------------------------------------------------------- +// Power-Up Reset synchronizer +scr1_reset_sync_cell #( + .STAGES_AMOUNT (SCR1_CLUSTER_TOP_RST_SYNC_STAGES_NUM) +) i_pwrup_rstn_reset_sync ( + .rst_n (pwrup_rst_n ), + .clk (clk ), + .test_rst_n (test_rst_n ), + .test_mode (test_mode ), + .rst_n_in (1'b1 ), + .rst_n_out (pwrup_rst_n_sync) +); + +// Regular Reset synchronizer +scr1_reset_sync_cell #( + .STAGES_AMOUNT (SCR1_CLUSTER_TOP_RST_SYNC_STAGES_NUM) +) i_rstn_reset_sync ( + .rst_n (pwrup_rst_n ), + .clk (clk ), + .test_rst_n (test_rst_n ), + .test_mode (test_mode ), + .rst_n_in (rst_n ), + .rst_n_out (rst_n_sync ) +); + +// CPU Reset synchronizer +scr1_reset_sync_cell #( + .STAGES_AMOUNT (SCR1_CLUSTER_TOP_RST_SYNC_STAGES_NUM) +) i_cpu_rstn_reset_sync ( + .rst_n (pwrup_rst_n ), + .clk (clk ), + .test_rst_n (test_rst_n ), + .test_mode (test_mode ), + .rst_n_in (cpu_rst_n ), + .rst_n_out (cpu_rst_n_sync ) +); + +`ifdef SCR1_DBG_EN +// TAPC Reset +scr1_reset_and2_cell i_tapc_rstn_and2_cell ( + .rst_n_in ({trst_n, pwrup_rst_n}), + .test_rst_n (test_rst_n ), + .test_mode (test_mode ), + .rst_n_out (tapc_trst_n ) +); +`endif // SCR1_DBG_EN + +//------------------------------------------------------------------------------- +// SCR1 core instance +//------------------------------------------------------------------------------- +scr1_core_top i_core_top ( + // Common + .pwrup_rst_n (pwrup_rst_n_sync ), + .rst_n (rst_n_sync ), + .cpu_rst_n (cpu_rst_n_sync ), + .test_mode (test_mode ), + .test_rst_n (test_rst_n ), + .clk (clk ), + .core_rst_n_o (core_rst_n_local ), + .core_rdc_qlfy_o ( ), +`ifdef SCR1_DBG_EN + .sys_rst_n_o (sys_rst_n_o ), + .sys_rdc_qlfy_o (sys_rdc_qlfy_o ), +`endif // SCR1_DBG_EN + + // Fuses + .core_fuse_mhartid_i (fuse_mhartid ), +`ifdef SCR1_DBG_EN + .tapc_fuse_idcode_i (fuse_idcode ), +`endif // SCR1_DBG_EN + + // IRQ +`ifdef SCR1_IPIC_EN + .core_irq_lines_i (irq_lines ), +`else // SCR1_IPIC_EN + .core_irq_ext_i (ext_irq ), +`endif // SCR1_IPIC_EN + .core_irq_soft_i (soft_irq ), + .core_irq_mtimer_i (timer_irq ), + + // Memory-mapped external timer + .core_mtimer_val_i (timer_val ), + +`ifdef SCR1_DBG_EN + // Debug interface + .tapc_trst_n (tapc_trst_n ), + .tapc_tck (tck ), + .tapc_tms (tms ), + .tapc_tdi (tdi ), + .tapc_tdo (tdo ), + .tapc_tdo_en (tdo_en ), +`endif // SCR1_DBG_EN + + // Instruction memory interface + .imem2core_req_ack_i (core_imem_req_ack), + .core2imem_req_o (core_imem_req ), + .core2imem_cmd_o (core_imem_cmd ), + .core2imem_addr_o (core_imem_addr ), + .imem2core_rdata_i (core_imem_rdata ), + .imem2core_resp_i (core_imem_resp ), + + // Data memory interface + .dmem2core_req_ack_i (core_dmem_req_ack), + .core2dmem_req_o (core_dmem_req ), + .core2dmem_cmd_o (core_dmem_cmd ), + .core2dmem_width_o (core_dmem_width ), + .core2dmem_addr_o (core_dmem_addr ), + .core2dmem_wdata_o (core_dmem_wdata ), + .dmem2core_rdata_i (core_dmem_rdata ), + .dmem2core_resp_i (core_dmem_resp ) +); + + +`ifdef SCR1_TCM_EN +//------------------------------------------------------------------------------- +// TCM instance +//------------------------------------------------------------------------------- +scr1_tcm #( + .SCR1_TCM_SIZE (`SCR1_DMEM_AWIDTH'(~SCR1_TCM_ADDR_MASK + 1'b1)) +) i_tcm ( + .clk (clk ), + .rst_n (core_rst_n_local), + + // Instruction interface to TCM + .imem_req_ack (tcm_imem_req_ack), + .imem_req (tcm_imem_req ), + .imem_addr (tcm_imem_addr ), + .imem_rdata (tcm_imem_rdata ), + .imem_resp (tcm_imem_resp ), + + // Data interface to TCM + .dmem_req_ack (tcm_dmem_req_ack), + .dmem_req (tcm_dmem_req ), + .dmem_cmd (tcm_dmem_cmd ), + .dmem_width (tcm_dmem_width ), + .dmem_addr (tcm_dmem_addr ), + .dmem_wdata (tcm_dmem_wdata ), + .dmem_rdata (tcm_dmem_rdata ), + .dmem_resp (tcm_dmem_resp ) +); +`endif // SCR1_TCM_EN + + +//------------------------------------------------------------------------------- +// Memory-mapped timer instance +//------------------------------------------------------------------------------- +scr1_timer i_timer ( + // Common + .rst_n (core_rst_n_local ), + .clk (clk ), + .rtc_clk (rtc_clk ), + + // Memory interface + .dmem_req (timer_dmem_req ), + .dmem_cmd (timer_dmem_cmd ), + .dmem_width (timer_dmem_width ), + .dmem_addr (timer_dmem_addr ), + .dmem_wdata (timer_dmem_wdata ), + .dmem_req_ack (timer_dmem_req_ack), + .dmem_rdata (timer_dmem_rdata ), + .dmem_resp (timer_dmem_resp ), + + // Timer interface + .timer_val (timer_val ), + .timer_irq (timer_irq ) +); + + +`ifdef SCR1_IMEM_ROUTER_EN +//------------------------------------------------------------------------------- +// Instruction memory router +//------------------------------------------------------------------------------- +scr1_imem_router #( + `ifdef SCR1_TCM_EN + .SCR1_ADDR_MASK (SCR1_TCM_ADDR_MASK), + .SCR1_ADDR_PATTERN (SCR1_TCM_ADDR_PATTERN) + `endif // SCR1_TCM_EN +) i_imem_router ( + .rst_n (core_rst_n_local ), + .clk (clk ), + // Interface to core + .imem_req_ack (core_imem_req_ack), + .imem_req (core_imem_req ), + .imem_cmd (core_imem_cmd ), + .imem_addr (core_imem_addr ), + .imem_rdata (core_imem_rdata ), + .imem_resp (core_imem_resp ), + // Interface to AHB bridge + .port0_req_ack (ahb_imem_req_ack ), + .port0_req (ahb_imem_req ), + .port0_cmd (ahb_imem_cmd ), + .port0_addr (ahb_imem_addr ), + .port0_rdata (ahb_imem_rdata ), + .port0_resp (ahb_imem_resp ), + `ifdef SCR1_TCM_EN + // Interface to TCM + .port1_req_ack (tcm_imem_req_ack ), + .port1_req (tcm_imem_req ), + .port1_cmd (tcm_imem_cmd ), + .port1_addr (tcm_imem_addr ), + .port1_rdata (tcm_imem_rdata ), + .port1_resp (tcm_imem_resp ) + `endif // SCR1_TCM_EN +); + +`else // SCR1_IMEM_ROUTER_EN + +assign ahb_imem_req = core_imem_req; +assign ahb_imem_cmd = core_imem_cmd; +assign ahb_imem_addr = core_imem_addr; +assign core_imem_req_ack = ahb_imem_req_ack; +assign core_imem_resp = ahb_imem_resp; +assign core_imem_rdata = ahb_imem_rdata; + +`endif // SCR1_IMEM_ROUTER_EN + +//------------------------------------------------------------------------------- +// Data memory router +//------------------------------------------------------------------------------- +scr1_dmem_router #( + +`ifdef SCR1_TCM_EN + .SCR1_PORT1_ADDR_MASK (SCR1_TCM_ADDR_MASK), + .SCR1_PORT1_ADDR_PATTERN (SCR1_TCM_ADDR_PATTERN), +`else // SCR1_TCM_EN + .SCR1_PORT1_ADDR_MASK (32'h00000000), + .SCR1_PORT1_ADDR_PATTERN (32'hFFFFFFFF), +`endif // SCR1_TCM_EN + + .SCR1_PORT2_ADDR_MASK (SCR1_TIMER_ADDR_MASK), + .SCR1_PORT2_ADDR_PATTERN (SCR1_TIMER_ADDR_PATTERN) + +) i_dmem_router ( + .rst_n (core_rst_n_local ), + .clk (clk ), + // Interface to core + .dmem_req_ack (core_dmem_req_ack ), + .dmem_req (core_dmem_req ), + .dmem_cmd (core_dmem_cmd ), + .dmem_width (core_dmem_width ), + .dmem_addr (core_dmem_addr ), + .dmem_wdata (core_dmem_wdata ), + .dmem_rdata (core_dmem_rdata ), + .dmem_resp (core_dmem_resp ), +`ifdef SCR1_TCM_EN + // Interface to TCM + .port1_req_ack (tcm_dmem_req_ack ), + .port1_req (tcm_dmem_req ), + .port1_cmd (tcm_dmem_cmd ), + .port1_width (tcm_dmem_width ), + .port1_addr (tcm_dmem_addr ), + .port1_wdata (tcm_dmem_wdata ), + .port1_rdata (tcm_dmem_rdata ), + .port1_resp (tcm_dmem_resp ), +`else // SCR1_TCM_EN + .port1_req_ack (1'b0), + .port1_req ( ), + .port1_cmd ( ), + .port1_width ( ), + .port1_addr ( ), + .port1_wdata ( ), + .port1_rdata ('0 ), + .port1_resp (SCR1_MEM_RESP_RDY_ER), +`endif // SCR1_TCM_EN + // Interface to memory-mapped timer + .port2_req_ack (timer_dmem_req_ack ), + .port2_req (timer_dmem_req ), + .port2_cmd (timer_dmem_cmd ), + .port2_width (timer_dmem_width ), + .port2_addr (timer_dmem_addr ), + .port2_wdata (timer_dmem_wdata ), + .port2_rdata (timer_dmem_rdata ), + .port2_resp (timer_dmem_resp ), + // Interface to AHB bridge + .port0_req_ack (ahb_dmem_req_ack ), + .port0_req (ahb_dmem_req ), + .port0_cmd (ahb_dmem_cmd ), + .port0_width (ahb_dmem_width ), + .port0_addr (ahb_dmem_addr ), + .port0_wdata (ahb_dmem_wdata ), + .port0_rdata (ahb_dmem_rdata ), + .port0_resp (ahb_dmem_resp ) +); + + +//------------------------------------------------------------------------------- +// Instruction memory AHB bridge +//------------------------------------------------------------------------------- +scr1_imem_ahb i_imem_ahb ( + .rst_n (core_rst_n_local ), + .clk (clk ), + // Interface to imem router + .imem_req_ack (ahb_imem_req_ack ), + .imem_req (ahb_imem_req ), + .imem_addr (ahb_imem_addr ), + .imem_rdata (ahb_imem_rdata ), + .imem_resp (ahb_imem_resp ), + // AHB interface + .hprot (imem_hprot ), + .hburst (imem_hburst ), + .hsize (imem_hsize ), + .htrans (imem_htrans ), + .hmastlock (imem_hmastlock ), + .haddr (imem_haddr ), + .hready (imem_hready ), + .hrdata (imem_hrdata ), + .hresp (imem_hresp ) +); + + +//------------------------------------------------------------------------------- +// Data memory AHB bridge +//------------------------------------------------------------------------------- +scr1_dmem_ahb i_dmem_ahb ( + .rst_n (core_rst_n_local ), + .clk (clk ), + // Interface to dmem router + .dmem_req_ack (ahb_dmem_req_ack ), + .dmem_req (ahb_dmem_req ), + .dmem_cmd (ahb_dmem_cmd ), + .dmem_width (ahb_dmem_width ), + .dmem_addr (ahb_dmem_addr ), + .dmem_wdata (ahb_dmem_wdata ), + .dmem_rdata (ahb_dmem_rdata ), + .dmem_resp (ahb_dmem_resp ), + // AHB interface + .hprot (dmem_hprot ), + .hburst (dmem_hburst ), + .hsize (dmem_hsize ), + .htrans (dmem_htrans ), + .hmastlock (dmem_hmastlock ), + .haddr (dmem_haddr ), + .hwrite (dmem_hwrite ), + .hwdata (dmem_hwdata ), + .hready (dmem_hready ), + .hrdata (dmem_hrdata ), + .hresp (dmem_hresp ) +); + +endmodule : scr1_top_ahb + + diff --git a/src/rtl/scr1/scr1_top_axi.sv b/src/rtl/scr1/scr1_top_axi.sv new file mode 100644 index 0000000..735b902 --- /dev/null +++ b/src/rtl/scr1/scr1_top_axi.sv @@ -0,0 +1,701 @@ +/// Copyright by Syntacore LLC © 2016-2020. See LICENSE for details +/// @file +/// @brief SCR1 AXI top +/// + +`include "scr1_arch_description.svh" +`include "scr1_memif.svh" +`ifdef SCR1_IPIC_EN +`include "scr1_ipic.svh" +`endif // SCR1_IPIC_EN + +`ifdef SCR1_TCM_EN + `define SCR1_IMEM_ROUTER_EN +`endif // SCR1_TCM_EN + +module scr1_top_axi ( + // Control + input logic pwrup_rst_n, // Power-Up Reset + input logic rst_n, // Regular Reset signal + input logic cpu_rst_n, // CPU Reset (Core Reset) + input logic test_mode, // Test mode + input logic test_rst_n, // Test mode's reset + input logic clk, // System clock + input logic rtc_clk, // Real-time clock +`ifdef SCR1_DBG_EN + output logic sys_rst_n_o, // External System Reset output + // (for the processor cluster's components or + // external SOC (could be useful in small + // SCR-core-centric SOCs)) + output logic sys_rdc_qlfy_o, // System-to-External SOC Reset Domain Crossing Qualifier +`endif // SCR1_DBG_EN + + // Fuses + input logic [`SCR1_XLEN-1:0] fuse_mhartid, // Hart ID +`ifdef SCR1_DBG_EN + input logic [31:0] fuse_idcode, // TAPC IDCODE +`endif // SCR1_DBG_EN + + // IRQ +`ifdef SCR1_IPIC_EN + input logic [SCR1_IRQ_LINES_NUM-1:0] irq_lines, // IRQ lines to IPIC +`else // SCR1_IPIC_EN + input logic ext_irq, // External IRQ input +`endif // SCR1_IPIC_EN + input logic soft_irq, // Software IRQ input + +`ifdef SCR1_DBG_EN + // -- JTAG I/F + input logic trst_n, + input logic tck, + input logic tms, + input logic tdi, + output logic tdo, + output logic tdo_en, +`endif // SCR1_DBG_EN + + // Instruction Memory Interface + output logic [3:0] io_axi_imem_awid, + output logic [31:0] io_axi_imem_awaddr, + output logic [7:0] io_axi_imem_awlen, + output logic [2:0] io_axi_imem_awsize, + output logic [1:0] io_axi_imem_awburst, + output logic io_axi_imem_awlock, + output logic [3:0] io_axi_imem_awcache, + output logic [2:0] io_axi_imem_awprot, + output logic [3:0] io_axi_imem_awregion, + output logic [3:0] io_axi_imem_awuser, + output logic [3:0] io_axi_imem_awqos, + output logic io_axi_imem_awvalid, + input logic io_axi_imem_awready, + output logic [31:0] io_axi_imem_wdata, + output logic [3:0] io_axi_imem_wstrb, + output logic io_axi_imem_wlast, + output logic [3:0] io_axi_imem_wuser, + output logic io_axi_imem_wvalid, + input logic io_axi_imem_wready, + input logic [3:0] io_axi_imem_bid, + input logic [1:0] io_axi_imem_bresp, + input logic io_axi_imem_bvalid, + input logic [3:0] io_axi_imem_buser, + output logic io_axi_imem_bready, + output logic [3:0] io_axi_imem_arid, + output logic [31:0] io_axi_imem_araddr, + output logic [7:0] io_axi_imem_arlen, + output logic [2:0] io_axi_imem_arsize, + output logic [1:0] io_axi_imem_arburst, + output logic io_axi_imem_arlock, + output logic [3:0] io_axi_imem_arcache, + output logic [2:0] io_axi_imem_arprot, + output logic [3:0] io_axi_imem_arregion, + output logic [3:0] io_axi_imem_aruser, + output logic [3:0] io_axi_imem_arqos, + output logic io_axi_imem_arvalid, + input logic io_axi_imem_arready, + input logic [3:0] io_axi_imem_rid, + input logic [31:0] io_axi_imem_rdata, + input logic [1:0] io_axi_imem_rresp, + input logic io_axi_imem_rlast, + input logic [3:0] io_axi_imem_ruser, + input logic io_axi_imem_rvalid, + output logic io_axi_imem_rready, + + // Data Memory Interface + output logic [3:0] io_axi_dmem_awid, + output logic [31:0] io_axi_dmem_awaddr, + output logic [7:0] io_axi_dmem_awlen, + output logic [2:0] io_axi_dmem_awsize, + output logic [1:0] io_axi_dmem_awburst, + output logic io_axi_dmem_awlock, + output logic [3:0] io_axi_dmem_awcache, + output logic [2:0] io_axi_dmem_awprot, + output logic [3:0] io_axi_dmem_awregion, + output logic [3:0] io_axi_dmem_awuser, + output logic [3:0] io_axi_dmem_awqos, + output logic io_axi_dmem_awvalid, + input logic io_axi_dmem_awready, + output logic [31:0] io_axi_dmem_wdata, + output logic [3:0] io_axi_dmem_wstrb, + output logic io_axi_dmem_wlast, + output logic [3:0] io_axi_dmem_wuser, + output logic io_axi_dmem_wvalid, + input logic io_axi_dmem_wready, + input logic [3:0] io_axi_dmem_bid, + input logic [1:0] io_axi_dmem_bresp, + input logic io_axi_dmem_bvalid, + input logic [3:0] io_axi_dmem_buser, + output logic io_axi_dmem_bready, + output logic [3:0] io_axi_dmem_arid, + output logic [31:0] io_axi_dmem_araddr, + output logic [7:0] io_axi_dmem_arlen, + output logic [2:0] io_axi_dmem_arsize, + output logic [1:0] io_axi_dmem_arburst, + output logic io_axi_dmem_arlock, + output logic [3:0] io_axi_dmem_arcache, + output logic [2:0] io_axi_dmem_arprot, + output logic [3:0] io_axi_dmem_arregion, + output logic [3:0] io_axi_dmem_aruser, + output logic [3:0] io_axi_dmem_arqos, + output logic io_axi_dmem_arvalid, + input logic io_axi_dmem_arready, + input logic [3:0] io_axi_dmem_rid, + input logic [31:0] io_axi_dmem_rdata, + input logic [1:0] io_axi_dmem_rresp, + input logic io_axi_dmem_rlast, + input logic [3:0] io_axi_dmem_ruser, + input logic io_axi_dmem_rvalid, + output logic io_axi_dmem_rready +); + +//------------------------------------------------------------------------------- +// Local parameters +//------------------------------------------------------------------------------- +localparam int unsigned SCR1_CLUSTER_TOP_RST_SYNC_STAGES_NUM = 2; + +//------------------------------------------------------------------------------- +// Local signal declaration +//------------------------------------------------------------------------------- +// Reset logic +logic pwrup_rst_n_sync; +logic rst_n_sync; +logic cpu_rst_n_sync; +logic core_rst_n_local; +logic axi_rst_n; +`ifdef SCR1_DBG_EN +logic tapc_trst_n; +`endif // SCR1_DBG_EN + +// Instruction memory interface from core to router +logic core_imem_req_ack; +logic core_imem_req; +type_scr1_mem_cmd_e core_imem_cmd; +logic [`SCR1_IMEM_AWIDTH-1:0] core_imem_addr; +logic [`SCR1_IMEM_DWIDTH-1:0] core_imem_rdata; +type_scr1_mem_resp_e core_imem_resp; + +// Data memory interface from core to router +logic core_dmem_req_ack; +logic core_dmem_req; +type_scr1_mem_cmd_e core_dmem_cmd; +type_scr1_mem_width_e core_dmem_width; +logic [`SCR1_DMEM_AWIDTH-1:0] core_dmem_addr; +logic [`SCR1_DMEM_DWIDTH-1:0] core_dmem_wdata; +logic [`SCR1_DMEM_DWIDTH-1:0] core_dmem_rdata; +type_scr1_mem_resp_e core_dmem_resp; + +// Instruction memory interface from router to AXI bridge +logic axi_imem_req_ack; +logic axi_imem_req; +type_scr1_mem_cmd_e axi_imem_cmd; +logic [`SCR1_IMEM_AWIDTH-1:0] axi_imem_addr; +logic [`SCR1_IMEM_DWIDTH-1:0] axi_imem_rdata; +type_scr1_mem_resp_e axi_imem_resp; + +// Data memory interface from router to AXI bridge +logic axi_dmem_req_ack; +logic axi_dmem_req; +type_scr1_mem_cmd_e axi_dmem_cmd; +type_scr1_mem_width_e axi_dmem_width; +logic [`SCR1_DMEM_AWIDTH-1:0] axi_dmem_addr; +logic [`SCR1_DMEM_DWIDTH-1:0] axi_dmem_wdata; +logic [`SCR1_DMEM_DWIDTH-1:0] axi_dmem_rdata; +type_scr1_mem_resp_e axi_dmem_resp; + +`ifdef SCR1_TCM_EN +// Instruction memory interface from router to TCM +logic tcm_imem_req_ack; +logic tcm_imem_req; +type_scr1_mem_cmd_e tcm_imem_cmd; +logic [`SCR1_IMEM_AWIDTH-1:0] tcm_imem_addr; +logic [`SCR1_IMEM_DWIDTH-1:0] tcm_imem_rdata; +type_scr1_mem_resp_e tcm_imem_resp; + +// Data memory interface from router to TCM +logic tcm_dmem_req_ack; +logic tcm_dmem_req; +type_scr1_mem_cmd_e tcm_dmem_cmd; +type_scr1_mem_width_e tcm_dmem_width; +logic [`SCR1_DMEM_AWIDTH-1:0] tcm_dmem_addr; +logic [`SCR1_DMEM_DWIDTH-1:0] tcm_dmem_wdata; +logic [`SCR1_DMEM_DWIDTH-1:0] tcm_dmem_rdata; +type_scr1_mem_resp_e tcm_dmem_resp; +`endif // SCR1_TCM_EN + +// Data memory interface from router to memory-mapped timer +logic timer_dmem_req_ack; +logic timer_dmem_req; +type_scr1_mem_cmd_e timer_dmem_cmd; +type_scr1_mem_width_e timer_dmem_width; +logic [`SCR1_DMEM_AWIDTH-1:0] timer_dmem_addr; +logic [`SCR1_DMEM_DWIDTH-1:0] timer_dmem_wdata; +logic [`SCR1_DMEM_DWIDTH-1:0] timer_dmem_rdata; +type_scr1_mem_resp_e timer_dmem_resp; + +// Misc +logic timer_irq; +logic [63:0] timer_val; +logic axi_reinit; +logic axi_imem_idle; +logic axi_dmem_idle; + +//------------------------------------------------------------------------------- +// Reset logic +//------------------------------------------------------------------------------- +// Power-Up Reset synchronizer +scr1_reset_sync_cell #( + .STAGES_AMOUNT (SCR1_CLUSTER_TOP_RST_SYNC_STAGES_NUM) +) i_pwrup_rstn_reset_sync ( + .rst_n (pwrup_rst_n ), + .clk (clk ), + .test_rst_n (test_rst_n ), + .test_mode (test_mode ), + .rst_n_in (1'b1 ), + .rst_n_out (pwrup_rst_n_sync) +); + +// Regular Reset synchronizer +scr1_reset_sync_cell #( + .STAGES_AMOUNT (SCR1_CLUSTER_TOP_RST_SYNC_STAGES_NUM) +) i_rstn_reset_sync ( + .rst_n (pwrup_rst_n ), + .clk (clk ), + .test_rst_n (test_rst_n ), + .test_mode (test_mode ), + .rst_n_in (rst_n ), + .rst_n_out (rst_n_sync ) +); + +// CPU Reset synchronizer +scr1_reset_sync_cell #( + .STAGES_AMOUNT (SCR1_CLUSTER_TOP_RST_SYNC_STAGES_NUM) +) i_cpu_rstn_reset_sync ( + .rst_n (pwrup_rst_n ), + .clk (clk ), + .test_rst_n (test_rst_n ), + .test_mode (test_mode ), + .rst_n_in (cpu_rst_n ), + .rst_n_out (cpu_rst_n_sync ) +); + +`ifdef SCR1_DBG_EN +// TAPC Reset +scr1_reset_and2_cell i_tapc_rstn_and2_cell ( + .rst_n_in ({trst_n, pwrup_rst_n}), + .test_rst_n (test_rst_n ), + .test_mode (test_mode ), + .rst_n_out (tapc_trst_n ) +); +`endif // SCR1_DBG_EN + +`ifdef SCR1_DBG_EN +assign axi_rst_n = sys_rst_n_o; +`else // SCR1_DBG_EN +assign axi_rst_n = rst_n_sync; +`endif // SCR1_DBG_EN + +//------------------------------------------------------------------------------- +// SCR1 core instance +//------------------------------------------------------------------------------- +scr1_core_top i_core_top ( + // Common + .pwrup_rst_n (pwrup_rst_n_sync ), + .rst_n (rst_n_sync ), + .cpu_rst_n (cpu_rst_n_sync ), + .test_mode (test_mode ), + .test_rst_n (test_rst_n ), + .clk (clk ), + .core_rst_n_o (core_rst_n_local ), + .core_rdc_qlfy_o ( ), +`ifdef SCR1_DBG_EN + .sys_rst_n_o (sys_rst_n_o ), + .sys_rdc_qlfy_o (sys_rdc_qlfy_o ), +`endif // SCR1_DBG_EN + + // Fuses + .core_fuse_mhartid_i (fuse_mhartid ), +`ifdef SCR1_DBG_EN + .tapc_fuse_idcode_i (fuse_idcode ), +`endif // SCR1_DBG_EN + + // IRQ +`ifdef SCR1_IPIC_EN + .core_irq_lines_i (irq_lines ), +`else // SCR1_IPIC_EN + .core_irq_ext_i (ext_irq ), +`endif // SCR1_IPIC_EN + .core_irq_soft_i (soft_irq ), + .core_irq_mtimer_i (timer_irq ), + + // Memory-mapped external timer + .core_mtimer_val_i (timer_val ), + +`ifdef SCR1_DBG_EN + // Debug interface + .tapc_trst_n (tapc_trst_n ), + .tapc_tck (tck ), + .tapc_tms (tms ), + .tapc_tdi (tdi ), + .tapc_tdo (tdo ), + .tapc_tdo_en (tdo_en ), +`endif // SCR1_DBG_EN + + // Instruction memory interface + .imem2core_req_ack_i (core_imem_req_ack), + .core2imem_req_o (core_imem_req ), + .core2imem_cmd_o (core_imem_cmd ), + .core2imem_addr_o (core_imem_addr ), + .imem2core_rdata_i (core_imem_rdata ), + .imem2core_resp_i (core_imem_resp ), + + // Data memory interface + .dmem2core_req_ack_i (core_dmem_req_ack), + .core2dmem_req_o (core_dmem_req ), + .core2dmem_cmd_o (core_dmem_cmd ), + .core2dmem_width_o (core_dmem_width ), + .core2dmem_addr_o (core_dmem_addr ), + .core2dmem_wdata_o (core_dmem_wdata ), + .dmem2core_rdata_i (core_dmem_rdata ), + .dmem2core_resp_i (core_dmem_resp ) +); + + +`ifdef SCR1_TCM_EN +//------------------------------------------------------------------------------- +// TCM instance +//------------------------------------------------------------------------------- +scr1_tcm #( + .SCR1_TCM_SIZE (`SCR1_DMEM_AWIDTH'(~SCR1_TCM_ADDR_MASK + 1'b1)) +) i_tcm ( + .clk (clk ), + .rst_n (core_rst_n_local), + + // Instruction interface to TCM + .imem_req_ack (tcm_imem_req_ack), + .imem_req (tcm_imem_req ), + .imem_addr (tcm_imem_addr ), + .imem_rdata (tcm_imem_rdata ), + .imem_resp (tcm_imem_resp ), + + // Data interface to TCM + .dmem_req_ack (tcm_dmem_req_ack), + .dmem_req (tcm_dmem_req ), + .dmem_cmd (tcm_dmem_cmd ), + .dmem_width (tcm_dmem_width ), + .dmem_addr (tcm_dmem_addr ), + .dmem_wdata (tcm_dmem_wdata ), + .dmem_rdata (tcm_dmem_rdata ), + .dmem_resp (tcm_dmem_resp ) +); +`endif // SCR1_TCM_EN + + +//------------------------------------------------------------------------------- +// Memory-mapped timer instance +//------------------------------------------------------------------------------- +scr1_timer i_timer ( + // Common + .rst_n (core_rst_n_local ), + .clk (clk ), + .rtc_clk (rtc_clk ), + + // Memory interface + .dmem_req (timer_dmem_req ), + .dmem_cmd (timer_dmem_cmd ), + .dmem_width (timer_dmem_width ), + .dmem_addr (timer_dmem_addr ), + .dmem_wdata (timer_dmem_wdata ), + .dmem_req_ack (timer_dmem_req_ack), + .dmem_rdata (timer_dmem_rdata ), + .dmem_resp (timer_dmem_resp ), + + // Timer interface + .timer_val (timer_val ), + .timer_irq (timer_irq ) +); + + +`ifdef SCR1_IMEM_ROUTER_EN +//------------------------------------------------------------------------------- +// Instruction memory router +//------------------------------------------------------------------------------- +scr1_imem_router #( + .SCR1_ADDR_MASK (SCR1_TCM_ADDR_MASK), + .SCR1_ADDR_PATTERN (SCR1_TCM_ADDR_PATTERN) +) i_imem_router ( + .rst_n (core_rst_n_local ), + .clk (clk ), + + // Interface to core + .imem_req_ack (core_imem_req_ack), + .imem_req (core_imem_req ), + .imem_cmd (core_imem_cmd ), + .imem_addr (core_imem_addr ), + .imem_rdata (core_imem_rdata ), + .imem_resp (core_imem_resp ), + + // Interface to AXI bridge + .port0_req_ack (axi_imem_req_ack ), + .port0_req (axi_imem_req ), + .port0_cmd (axi_imem_cmd ), + .port0_addr (axi_imem_addr ), + .port0_rdata (axi_imem_rdata ), + .port0_resp (axi_imem_resp ), + + // Interface to TCM + .port1_req_ack (tcm_imem_req_ack ), + .port1_req (tcm_imem_req ), + .port1_cmd (tcm_imem_cmd ), + .port1_addr (tcm_imem_addr ), + .port1_rdata (tcm_imem_rdata ), + .port1_resp (tcm_imem_resp ) +); + +`else // SCR1_IMEM_ROUTER_EN + +assign axi_imem_req = core_imem_req; +assign axi_imem_cmd = core_imem_cmd; +assign axi_imem_addr = core_imem_addr; +assign core_imem_req_ack = axi_imem_req_ack; +assign core_imem_resp = axi_imem_resp; +assign core_imem_rdata = axi_imem_rdata; + +`endif // SCR1_IMEM_ROUTER_EN + + +//------------------------------------------------------------------------------- +// Data memory router +//------------------------------------------------------------------------------- +scr1_dmem_router #( + +`ifdef SCR1_TCM_EN + .SCR1_PORT1_ADDR_MASK (SCR1_TCM_ADDR_MASK), + .SCR1_PORT1_ADDR_PATTERN (SCR1_TCM_ADDR_PATTERN), +`else // SCR1_TCM_EN + .SCR1_PORT1_ADDR_MASK (32'h00000000), + .SCR1_PORT1_ADDR_PATTERN (32'hFFFFFFFF), +`endif // SCR1_TCM_EN + + .SCR1_PORT2_ADDR_MASK (SCR1_TIMER_ADDR_MASK), + .SCR1_PORT2_ADDR_PATTERN (SCR1_TIMER_ADDR_PATTERN) + +) i_dmem_router ( + .rst_n (core_rst_n_local ), + .clk (clk ), + + // Interface to core + .dmem_req_ack (core_dmem_req_ack ), + .dmem_req (core_dmem_req ), + .dmem_cmd (core_dmem_cmd ), + .dmem_width (core_dmem_width ), + .dmem_addr (core_dmem_addr ), + .dmem_wdata (core_dmem_wdata ), + .dmem_rdata (core_dmem_rdata ), + .dmem_resp (core_dmem_resp ), + +`ifdef SCR1_TCM_EN + // Interface to TCM + .port1_req_ack (tcm_dmem_req_ack ), + .port1_req (tcm_dmem_req ), + .port1_cmd (tcm_dmem_cmd ), + .port1_width (tcm_dmem_width ), + .port1_addr (tcm_dmem_addr ), + .port1_wdata (tcm_dmem_wdata ), + .port1_rdata (tcm_dmem_rdata ), + .port1_resp (tcm_dmem_resp ), +`else // SCR1_TCM_EN + .port1_req_ack (1'b0 ), + .port1_req ( ), + .port1_cmd ( ), + .port1_width ( ), + .port1_addr ( ), + .port1_wdata ( ), + .port1_rdata ('0 ), + .port1_resp (SCR1_MEM_RESP_RDY_ER), +`endif // SCR1_TCM_EN + + // Interface to memory-mapped timer + .port2_req_ack (timer_dmem_req_ack ), + .port2_req (timer_dmem_req ), + .port2_cmd (timer_dmem_cmd ), + .port2_width (timer_dmem_width ), + .port2_addr (timer_dmem_addr ), + .port2_wdata (timer_dmem_wdata ), + .port2_rdata (timer_dmem_rdata ), + .port2_resp (timer_dmem_resp ), + + // Interface to AXI bridge + .port0_req_ack (axi_dmem_req_ack ), + .port0_req (axi_dmem_req ), + .port0_cmd (axi_dmem_cmd ), + .port0_width (axi_dmem_width ), + .port0_addr (axi_dmem_addr ), + .port0_wdata (axi_dmem_wdata ), + .port0_rdata (axi_dmem_rdata ), + .port0_resp (axi_dmem_resp ) +); + + +//------------------------------------------------------------------------------- +// Instruction memory AXI bridge +//------------------------------------------------------------------------------- +scr1_mem_axi #( +`ifdef SCR1_IMEM_AXI_REQ_BP + .SCR1_AXI_REQ_BP (1), +`else // SCR1_IMEM_AXI_REQ_BP + .SCR1_AXI_REQ_BP (0), +`endif // SCR1_IMEM_AXI_REQ_BP +`ifdef SCR1_IMEM_AXI_RESP_BP + .SCR1_AXI_RESP_BP (1) +`else // SCR1_IMEM_AXI_RESP_BP + .SCR1_AXI_RESP_BP (0) +`endif // SCR1_IMEM_AXI_RESP_BP +) i_imem_axi ( + .clk (clk ), + .rst_n (axi_rst_n ), + .axi_reinit (axi_reinit ), + + // Interface to core + .core_idle (axi_imem_idle ), + .core_req_ack (axi_imem_req_ack ), + .core_req (axi_imem_req ), + .core_cmd (axi_imem_cmd ), + .core_width (SCR1_MEM_WIDTH_WORD ), + .core_addr (axi_imem_addr ), + .core_wdata ('0 ), + .core_rdata (axi_imem_rdata ), + .core_resp (axi_imem_resp ), + + // AXI I/O + .awid (io_axi_imem_awid ), + .awaddr (io_axi_imem_awaddr ), + .awlen (io_axi_imem_awlen ), + .awsize (io_axi_imem_awsize ), + .awburst (io_axi_imem_awburst ), + .awlock (io_axi_imem_awlock ), + .awcache (io_axi_imem_awcache ), + .awprot (io_axi_imem_awprot ), + .awregion (io_axi_imem_awregion ), + .awuser (io_axi_imem_awuser ), + .awqos (io_axi_imem_awqos ), + .awvalid (io_axi_imem_awvalid ), + .awready (io_axi_imem_awready ), + .wdata (io_axi_imem_wdata ), + .wstrb (io_axi_imem_wstrb ), + .wlast (io_axi_imem_wlast ), + .wuser (io_axi_imem_wuser ), + .wvalid (io_axi_imem_wvalid ), + .wready (io_axi_imem_wready ), + .bid (io_axi_imem_bid ), + .bresp (io_axi_imem_bresp ), + .bvalid (io_axi_imem_bvalid ), + .buser (io_axi_imem_buser ), + .bready (io_axi_imem_bready ), + .arid (io_axi_imem_arid ), + .araddr (io_axi_imem_araddr ), + .arlen (io_axi_imem_arlen ), + .arsize (io_axi_imem_arsize ), + .arburst (io_axi_imem_arburst ), + .arlock (io_axi_imem_arlock ), + .arcache (io_axi_imem_arcache ), + .arprot (io_axi_imem_arprot ), + .arregion (io_axi_imem_arregion ), + .aruser (io_axi_imem_aruser ), + .arqos (io_axi_imem_arqos ), + .arvalid (io_axi_imem_arvalid ), + .arready (io_axi_imem_arready ), + .rid (io_axi_imem_rid ), + .rdata (io_axi_imem_rdata ), + .rresp (io_axi_imem_rresp ), + .rlast (io_axi_imem_rlast ), + .ruser (io_axi_imem_ruser ), + .rvalid (io_axi_imem_rvalid ), + .rready (io_axi_imem_rready ) +); + + +//------------------------------------------------------------------------------- +// Data memory AXI bridge +//------------------------------------------------------------------------------- +scr1_mem_axi #( +`ifdef SCR1_DMEM_AXI_REQ_BP + .SCR1_AXI_REQ_BP (1), +`else // SCR1_DMEM_AXI_REQ_BP + .SCR1_AXI_REQ_BP (0), +`endif // SCR1_DMEM_AXI_REQ_BP +`ifdef SCR1_DMEM_AXI_RESP_BP + .SCR1_AXI_RESP_BP (1) +`else // SCR1_DMEM_AXI_RESP_BP + .SCR1_AXI_RESP_BP (0) +`endif // SCR1_DMEM_AXI_RESP_BP +) i_dmem_axi ( + .clk (clk ), + .rst_n (axi_rst_n ), + .axi_reinit (axi_reinit ), + + // Interface to core + .core_idle (axi_dmem_idle ), + .core_req_ack (axi_dmem_req_ack ), + .core_req (axi_dmem_req ), + .core_cmd (axi_dmem_cmd ), + .core_width (axi_dmem_width ), + .core_addr (axi_dmem_addr ), + .core_wdata (axi_dmem_wdata ), + .core_rdata (axi_dmem_rdata ), + .core_resp (axi_dmem_resp ), + + // AXI I/O + .awid (io_axi_dmem_awid ), + .awaddr (io_axi_dmem_awaddr ), + .awlen (io_axi_dmem_awlen ), + .awsize (io_axi_dmem_awsize ), + .awburst (io_axi_dmem_awburst ), + .awlock (io_axi_dmem_awlock ), + .awcache (io_axi_dmem_awcache ), + .awprot (io_axi_dmem_awprot ), + .awregion (io_axi_dmem_awregion ), + .awuser (io_axi_dmem_awuser ), + .awqos (io_axi_dmem_awqos ), + .awvalid (io_axi_dmem_awvalid ), + .awready (io_axi_dmem_awready ), + .wdata (io_axi_dmem_wdata ), + .wstrb (io_axi_dmem_wstrb ), + .wlast (io_axi_dmem_wlast ), + .wuser (io_axi_dmem_wuser ), + .wvalid (io_axi_dmem_wvalid ), + .wready (io_axi_dmem_wready ), + .bid (io_axi_dmem_bid ), + .bresp (io_axi_dmem_bresp ), + .bvalid (io_axi_dmem_bvalid ), + .buser (io_axi_dmem_buser ), + .bready (io_axi_dmem_bready ), + .arid (io_axi_dmem_arid ), + .araddr (io_axi_dmem_araddr ), + .arlen (io_axi_dmem_arlen ), + .arsize (io_axi_dmem_arsize ), + .arburst (io_axi_dmem_arburst ), + .arlock (io_axi_dmem_arlock ), + .arcache (io_axi_dmem_arcache ), + .arprot (io_axi_dmem_arprot ), + .arregion (io_axi_dmem_arregion ), + .aruser (io_axi_dmem_aruser ), + .arqos (io_axi_dmem_arqos ), + .arvalid (io_axi_dmem_arvalid ), + .arready (io_axi_dmem_arready ), + .rid (io_axi_dmem_rid ), + .rdata (io_axi_dmem_rdata ), + .rresp (io_axi_dmem_rresp ), + .rlast (io_axi_dmem_rlast ), + .ruser (io_axi_dmem_ruser ), + .rvalid (io_axi_dmem_rvalid ), + .rready (io_axi_dmem_rready ) +); + +//------------------------------------------------------------------------------- +// AXI reinit logic +//------------------------------------------------------------------------------- +always_ff @(negedge core_rst_n_local, posedge clk) begin + if (~core_rst_n_local) axi_reinit <= 1'b1; + else if (axi_imem_idle & axi_dmem_idle) axi_reinit <= 1'b0; +end + +endmodule : scr1_top_axi diff --git a/src/rtl/scr1/scr1_tracelog.sv b/src/rtl/scr1/scr1_tracelog.sv new file mode 100644 index 0000000..9d542ec --- /dev/null +++ b/src/rtl/scr1/scr1_tracelog.sv @@ -0,0 +1,453 @@ +/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details +/// @file +/// @brief Core tracelog module +/// + +`include "scr1_arch_description.svh" +`include "scr1_arch_types.svh" +`include "scr1_csr.svh" + +`ifdef SCR1_TRGT_SIMULATION + +module scr1_tracelog ( + input logic rst_n, // Tracelog reset + input logic clk // Tracelog clock +`ifdef SCR1_TRACE_LOG_EN + , + input logic [`SCR1_XLEN-1:0] soc2pipe_fuse_mhartid_i, // Fuse MHARTID + + // MPRF +`ifdef SCR1_MPRF_RAM + input logic [`SCR1_XLEN-1:0] mprf2trace_int_i [1:`SCR1_MPRF_SIZE-1], // MPRF registers content +`else // SCR1_MPRF_RAM + input type_scr1_mprf_v [1:`SCR1_MPRF_SIZE-1] mprf2trace_int_i, // MPRF registers content +`endif // SCR1_MPRF_RAM + input logic mprf2trace_wr_en_i, // MPRF write enable + input logic [`SCR1_MPRF_AWIDTH-1:0] mprf2trace_wr_addr_i, // MPRF write address + input logic [`SCR1_XLEN-1:0] mprf2trace_wr_data_i, // MPRF write data + + // EXU + input logic exu2trace_update_pc_en_i, // PC updated flag + input logic [`SCR1_XLEN-1:0] exu2trace_update_pc_i, // Next PC value + + // IFU + input logic [`SCR1_IMEM_DWIDTH-1:0] ifu2trace_instr_i, // Current instruction from IFU stage + + // CSR + input logic csr2trace_mstatus_mie_i, // CSR MSTATUS.mie bit + input logic csr2trace_mstatus_mpie_i, // CSR MSTATUS.mpie bit + input logic [`SCR1_XLEN-1:6] csr2trace_mtvec_base_i, // CSR MTVEC. + input logic csr2trace_mtvec_mode_i, // CSR MTVEC. + input logic csr2trace_mie_meie_i, // CSR MIE.meie bit + input logic csr2trace_mie_mtie_i, // CSR MIE.mtie bit + input logic csr2trace_mie_msie_i, // CSR MIE.msie bit + input logic csr2trace_mip_meip_i, // CSR MIP.meip bit + input logic csr2trace_mip_mtip_i, // CSR MIP.mtip bit + input logic csr2trace_mip_msip_i, // CSR MIP.msip bit + `ifdef SCR1_RVC_EXT + input logic [`SCR1_XLEN-1:1] csr2trace_mepc_i, // CSR MEPC register + `else // SCR1_RVC_EXT + input logic [`SCR1_XLEN-1:2] csr2trace_mepc_i, // CSR MEPC register + `endif // SCR1_RVC_EXT + input logic csr2trace_mcause_irq_i, // CSR MCAUSE.interrupt bit + input type_scr1_exc_code_e csr2trace_mcause_ec_i, // CSR MCAUSE.exception_code bit + input logic [`SCR1_XLEN-1:0] csr2trace_mtval_i, // CSR MTVAL register + + // Events + input logic csr2trace_e_exc_i, // exception event + input logic csr2trace_e_irq_i, // interrupt event + input logic pipe2trace_e_wake_i // pipe wakeup event +`endif // SCR1_TRACE_LOG_EN +); + +//------------------------------------------------------------------------------- +// Local types declaration +//------------------------------------------------------------------------------- +`ifdef SCR1_TRACE_LOG_EN +typedef struct { + logic [`SCR1_XLEN-1:0] INT_00_ZERO ; + logic [`SCR1_XLEN-1:0] INT_01_RA ; + logic [`SCR1_XLEN-1:0] INT_02_SP ; + logic [`SCR1_XLEN-1:0] INT_03_GP ; + logic [`SCR1_XLEN-1:0] INT_04_TP ; + logic [`SCR1_XLEN-1:0] INT_05_T0 ; + logic [`SCR1_XLEN-1:0] INT_06_T1 ; + logic [`SCR1_XLEN-1:0] INT_07_T2 ; + logic [`SCR1_XLEN-1:0] INT_08_S0 ; + logic [`SCR1_XLEN-1:0] INT_09_S1 ; + logic [`SCR1_XLEN-1:0] INT_10_A0 ; + logic [`SCR1_XLEN-1:0] INT_11_A1 ; + logic [`SCR1_XLEN-1:0] INT_12_A2 ; + logic [`SCR1_XLEN-1:0] INT_13_A3 ; + logic [`SCR1_XLEN-1:0] INT_14_A4 ; + logic [`SCR1_XLEN-1:0] INT_15_A5 ; +`ifndef SCR1_RVE_EXT + logic [`SCR1_XLEN-1:0] INT_16_A6 ; + logic [`SCR1_XLEN-1:0] INT_17_A7 ; + logic [`SCR1_XLEN-1:0] INT_18_S2 ; + logic [`SCR1_XLEN-1:0] INT_19_S3 ; + logic [`SCR1_XLEN-1:0] INT_20_S4 ; + logic [`SCR1_XLEN-1:0] INT_21_S5 ; + logic [`SCR1_XLEN-1:0] INT_22_S6 ; + logic [`SCR1_XLEN-1:0] INT_23_S7 ; + logic [`SCR1_XLEN-1:0] INT_24_S8 ; + logic [`SCR1_XLEN-1:0] INT_25_S9 ; + logic [`SCR1_XLEN-1:0] INT_26_S10 ; + logic [`SCR1_XLEN-1:0] INT_27_S11 ; + logic [`SCR1_XLEN-1:0] INT_28_T3 ; + logic [`SCR1_XLEN-1:0] INT_29_T4 ; + logic [`SCR1_XLEN-1:0] INT_30_T5 ; + logic [`SCR1_XLEN-1:0] INT_31_T6 ; +`endif // SCR1_RVE_EXT +} type_scr1_ireg_name_s; + +typedef struct packed { + logic [`SCR1_XLEN-1:0] mstatus; + logic [`SCR1_XLEN-1:0] mtvec; + logic [`SCR1_XLEN-1:0] mie; + logic [`SCR1_XLEN-1:0] mip; + logic [`SCR1_XLEN-1:0] mepc; + logic [`SCR1_XLEN-1:0] mcause; + logic [`SCR1_XLEN-1:0] mtval; +} type_scr1_csr_trace_s; +`endif // SCR1_TRACE_LOG_EN + +//------------------------------------------------------------------------------- +// Local Signal Declaration +//------------------------------------------------------------------------------- +`ifdef SCR1_TRACE_LOG_EN + +type_scr1_ireg_name_s mprf_int_alias; + + +time current_time; + +// Tracelog control signals +logic trace_flag; +logic trace_update; +logic trace_update_r; +byte event_type; + +logic [`SCR1_XLEN-1:0] trace_pc; +logic [`SCR1_XLEN-1:0] trace_npc; +logic [`SCR1_IMEM_DWIDTH-1:0] trace_instr; + +type_scr1_csr_trace_s csr_trace1; + +// File handlers +int unsigned trace_fhandler_core; + +// MPRF signals +logic mprf_up; +logic [`SCR1_MPRF_AWIDTH-1:0] mprf_addr; +logic [`SCR1_XLEN-1:0] mprf_wdata; + +string hart; +string test_name; + +`endif // SCR1_TRACE_LOG_EN + +//------------------------------------------------------------------------------- +// Local tasks +//------------------------------------------------------------------------------- + +`ifdef SCR1_TRACE_LOG_EN + +task trace_write_common; + $fwrite(trace_fhandler_core, "%16d ", current_time); + // $fwrite(trace_fhandler_core, " 0 "); + $fwrite(trace_fhandler_core, " %s ", event_type); + $fwrite(trace_fhandler_core, " %8x ", trace_pc); + $fwrite(trace_fhandler_core, " %8x ", trace_instr); + $fwrite(trace_fhandler_core, " %8x ", trace_npc); +endtask // trace_write_common + +task trace_write_int_walias; + case (mprf_addr) + 0 : $fwrite(trace_fhandler_core, " x00_zero "); + 1 : $fwrite(trace_fhandler_core, " x01_ra "); + 2 : $fwrite(trace_fhandler_core, " x02_sp "); + 3 : $fwrite(trace_fhandler_core, " x03_gp "); + 4 : $fwrite(trace_fhandler_core, " x04_tp "); + 5 : $fwrite(trace_fhandler_core, " x05_t0 "); + 6 : $fwrite(trace_fhandler_core, " x06_t1 "); + 7 : $fwrite(trace_fhandler_core, " x07_t2 "); + 8 : $fwrite(trace_fhandler_core, " x08_s0 "); + 9 : $fwrite(trace_fhandler_core, " x09_s1 "); + 10 : $fwrite(trace_fhandler_core, " x10_a0 "); + 11 : $fwrite(trace_fhandler_core, " x11_a1 "); + 12 : $fwrite(trace_fhandler_core, " x12_a2 "); + 13 : $fwrite(trace_fhandler_core, " x13_a3 "); + 14 : $fwrite(trace_fhandler_core, " x14_a4 "); + 15 : $fwrite(trace_fhandler_core, " x15_a5 "); +`ifndef SCR1_RVE_EXT + 16 : $fwrite(trace_fhandler_core, " x16_a6 "); + 17 : $fwrite(trace_fhandler_core, " x17_a7 "); + 18 : $fwrite(trace_fhandler_core, " x18_s2 "); + 19 : $fwrite(trace_fhandler_core, " x19_s3 "); + 20 : $fwrite(trace_fhandler_core, " x20_s4 "); + 21 : $fwrite(trace_fhandler_core, " x21_s5 "); + 22 : $fwrite(trace_fhandler_core, " x22_s6 "); + 23 : $fwrite(trace_fhandler_core, " x23_s7 "); + 24 : $fwrite(trace_fhandler_core, " x24_s8 "); + 25 : $fwrite(trace_fhandler_core, " x25_s9 "); + 26 : $fwrite(trace_fhandler_core, " x26_s10 "); + 27 : $fwrite(trace_fhandler_core, " x27_s11 "); + 28 : $fwrite(trace_fhandler_core, " x28_t3 "); + 29 : $fwrite(trace_fhandler_core, " x29_t4 "); + 30 : $fwrite(trace_fhandler_core, " x30_t5 "); + 31 : $fwrite(trace_fhandler_core, " x31_t6 "); +`endif // SCR1_RVE_EXT + default: begin + $fwrite(trace_fhandler_core, " xxx "); + end + endcase +endtask + +//------------------------------------------------------------------------------- +// MPRF Registers assignment +//------------------------------------------------------------------------------- +assign mprf_int_alias.INT_00_ZERO = '0; +assign mprf_int_alias.INT_01_RA = mprf2trace_int_i[1]; +assign mprf_int_alias.INT_02_SP = mprf2trace_int_i[2]; +assign mprf_int_alias.INT_03_GP = mprf2trace_int_i[3]; +assign mprf_int_alias.INT_04_TP = mprf2trace_int_i[4]; +assign mprf_int_alias.INT_05_T0 = mprf2trace_int_i[5]; +assign mprf_int_alias.INT_06_T1 = mprf2trace_int_i[6]; +assign mprf_int_alias.INT_07_T2 = mprf2trace_int_i[7]; +assign mprf_int_alias.INT_08_S0 = mprf2trace_int_i[8]; +assign mprf_int_alias.INT_09_S1 = mprf2trace_int_i[9]; +assign mprf_int_alias.INT_10_A0 = mprf2trace_int_i[10]; +assign mprf_int_alias.INT_11_A1 = mprf2trace_int_i[11]; +assign mprf_int_alias.INT_12_A2 = mprf2trace_int_i[12]; +assign mprf_int_alias.INT_13_A3 = mprf2trace_int_i[13]; +assign mprf_int_alias.INT_14_A4 = mprf2trace_int_i[14]; +assign mprf_int_alias.INT_15_A5 = mprf2trace_int_i[15]; +`ifndef SCR1_RVE_EXT +assign mprf_int_alias.INT_16_A6 = mprf2trace_int_i[16]; +assign mprf_int_alias.INT_17_A7 = mprf2trace_int_i[17]; +assign mprf_int_alias.INT_18_S2 = mprf2trace_int_i[18]; +assign mprf_int_alias.INT_19_S3 = mprf2trace_int_i[19]; +assign mprf_int_alias.INT_20_S4 = mprf2trace_int_i[20]; +assign mprf_int_alias.INT_21_S5 = mprf2trace_int_i[21]; +assign mprf_int_alias.INT_22_S6 = mprf2trace_int_i[22]; +assign mprf_int_alias.INT_23_S7 = mprf2trace_int_i[23]; +assign mprf_int_alias.INT_24_S8 = mprf2trace_int_i[24]; +assign mprf_int_alias.INT_25_S9 = mprf2trace_int_i[25]; +assign mprf_int_alias.INT_26_S10 = mprf2trace_int_i[26]; +assign mprf_int_alias.INT_27_S11 = mprf2trace_int_i[27]; +assign mprf_int_alias.INT_28_T3 = mprf2trace_int_i[28]; +assign mprf_int_alias.INT_29_T4 = mprf2trace_int_i[29]; +assign mprf_int_alias.INT_30_T5 = mprf2trace_int_i[30]; +assign mprf_int_alias.INT_31_T6 = mprf2trace_int_i[31]; +`endif // SCR1_RVE_EXT +`endif // SCR1_TRACE_LOG_EN + +//------------------------------------------------------------------------------- +// Legacy time counter +//------------------------------------------------------------------------------- +// The counter is left for compatibility with the current UVM environment + +int time_cnt; + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + time_cnt <= 0; + end else begin + time_cnt <= time_cnt + 1; + end +end + +//------------------------------------------------------------------------------- +// Initial part pipeline tracelog +//------------------------------------------------------------------------------- + +`ifdef SCR1_TRACE_LOG_EN +// Files opening and writing initial header +initial begin + $timeformat(-9, 0, " ns", 10); + #1 hart.hextoa(soc2pipe_fuse_mhartid_i); + + trace_fhandler_core = $fopen({"tracelog_core_", hart, ".log"}, "w"); + + // Writing initial header + $fwrite(trace_fhandler_core, "# RTL_ID %h\n", SCR1_CSR_MIMPID); + $fwrite(trace_fhandler_core, "#\n"); + // $fwrite(trace_fhandler_core, "# R - return from trap:\n"); + // $fwrite(trace_fhandler_core, "# 1 - MRET\n"); + // $fwrite(trace_fhandler_core, "# 0 - no return\n"); + $fwrite(trace_fhandler_core, "# Events:\n"); + $fwrite(trace_fhandler_core, "# N - no event\n"); + $fwrite(trace_fhandler_core, "# E - exception\n"); + $fwrite(trace_fhandler_core, "# I - interrupt\n"); + $fwrite(trace_fhandler_core, "# W - wakeup\n"); +end + +// Core reset logging and header printing +always @(posedge rst_n) begin + $fwrite(trace_fhandler_core, "# =====================================================================================\n"); +`ifndef VERILATOR + $fwrite(trace_fhandler_core, "# %16d ns : Core Reset\n", $time()); +`else + $fwrite(trace_fhandler_core, "# : Core Reset\n"); +`endif + $fwrite(trace_fhandler_core, "# =====================================================================================\n"); + $fwrite(trace_fhandler_core, "# Test: %s\n", test_name); + $fwrite(trace_fhandler_core, "# Time "); + // $fwrite(trace_fhandler_core, " R "); + $fwrite(trace_fhandler_core, " Ev "); + $fwrite(trace_fhandler_core, " Curr_PC "); + $fwrite(trace_fhandler_core, " Instr "); + $fwrite(trace_fhandler_core, " Next_PC "); + $fwrite(trace_fhandler_core, " Reg "); + $fwrite(trace_fhandler_core, " Value "); + $fwrite(trace_fhandler_core, "\n"); + $fwrite(trace_fhandler_core, "# =====================================================================================\n"); +end + +//------------------------------------------------------------------------------- +// Common trace part +//------------------------------------------------------------------------------- + +assign trace_flag = 1'b1; +assign trace_update = (exu2trace_update_pc_en_i | mprf2trace_wr_en_i) & trace_flag; + +always_ff @(posedge clk) begin + if (~rst_n) begin + current_time <= 0; + event_type <= "N"; + + trace_pc <= 'x; + trace_npc <= 'x; + trace_instr <= 'x; + + trace_update_r <= 1'b0; + + mprf_up <= '0; + mprf_addr <= '0; + mprf_wdata <= '0; + end else begin + trace_update_r <= trace_update; + if (trace_update) begin +`ifdef VERILATOR + current_time <= time_cnt; +`else + current_time <= $time(); +`endif + trace_pc <= trace_npc; + trace_npc <= exu2trace_update_pc_i; + trace_instr <= ifu2trace_instr_i; + + if (csr2trace_e_exc_i) begin + // Exception + event_type <= "E"; + end + else if (csr2trace_e_irq_i) begin + // IRQ + event_type <= "I"; + end + else if (pipe2trace_e_wake_i) begin + // Wake + event_type <= "W"; + end + else begin + // No event + event_type <= "N"; + end + end + + // Write log signals + mprf_up <= mprf2trace_wr_en_i; + mprf_addr <= mprf2trace_wr_en_i ? mprf2trace_wr_addr_i : 'x; + mprf_wdata <= mprf2trace_wr_en_i ? mprf2trace_wr_data_i : 'x; + end +end + +//------------------------------------------------------------------------------- +// Core MPRF logging +//------------------------------------------------------------------------------- + +always_ff @(negedge rst_n, posedge clk) begin + if (~rst_n) begin + end else begin + if (trace_update_r) begin + + trace_write_common(); + + case (event_type) + "W" : begin + // Wakeup + if (csr_trace1.mip & csr_trace1.mie) begin + $fwrite(trace_fhandler_core, " mip %08x\n", csr_trace1.mip ); + trace_write_common(); + $fwrite(trace_fhandler_core, " mie %08x", csr_trace1.mie ); + end + end + "N" : begin + // Regular + if (mprf_up && mprf_addr != 0) begin + // $fwrite(trace_fhandler_core, " x%2d %08x", mprf_addr, mprf_wdata); + trace_write_int_walias(); + $fwrite(trace_fhandler_core, " %08x", mprf_wdata); + end else begin + $fwrite(trace_fhandler_core, " --- --------"); + end + end + "R" : begin + // MRET + $fwrite(trace_fhandler_core, " mstatus %08x", csr_trace1.mstatus); + end + "E", "I": begin + // IRQ/Exception + $fwrite(trace_fhandler_core, " mstatus %08x\n", csr_trace1.mstatus); + trace_write_common(); + $fwrite(trace_fhandler_core, " mepc %08x\n", csr_trace1.mepc); + trace_write_common(); + $fwrite(trace_fhandler_core, " mcause %08x\n", csr_trace1.mcause); + trace_write_common(); + $fwrite(trace_fhandler_core, " mtval %08x", csr_trace1.mtval); + end + default : begin + $fwrite(trace_fhandler_core, "\n"); + end + endcase + $fwrite(trace_fhandler_core, "\n"); + end + end +end + +//------------------------------------------------------------------------------- +// Core CSR logging +//------------------------------------------------------------------------------- + +always_comb begin + csr_trace1.mtvec = {csr2trace_mtvec_base_i, 4'd0, 2'(csr2trace_mtvec_mode_i)}; + csr_trace1.mepc = +`ifdef SCR1_RVC_EXT + {csr2trace_mepc_i, 1'b0}; +`else // SCR1_RVC_EXT + {csr2trace_mepc_i, 2'b00}; +`endif // SCR1_RVC_EXT + csr_trace1.mcause = {csr2trace_mcause_irq_i, type_scr1_csr_mcause_ec_v'(csr2trace_mcause_ec_i)}; + csr_trace1.mtval = csr2trace_mtval_i; + + csr_trace1.mstatus = '0; + csr_trace1.mie = '0; + csr_trace1.mip = '0; + + csr_trace1.mstatus[SCR1_CSR_MSTATUS_MIE_OFFSET] = csr2trace_mstatus_mie_i; + csr_trace1.mstatus[SCR1_CSR_MSTATUS_MPIE_OFFSET] = csr2trace_mstatus_mpie_i; + csr_trace1.mstatus[SCR1_CSR_MSTATUS_MPP_OFFSET+1:SCR1_CSR_MSTATUS_MPP_OFFSET] = SCR1_CSR_MSTATUS_MPP; + csr_trace1.mie[SCR1_CSR_MIE_MSIE_OFFSET] = csr2trace_mie_msie_i; + csr_trace1.mie[SCR1_CSR_MIE_MTIE_OFFSET] = csr2trace_mie_mtie_i; + csr_trace1.mie[SCR1_CSR_MIE_MEIE_OFFSET] = csr2trace_mie_meie_i; + csr_trace1.mip[SCR1_CSR_MIE_MSIE_OFFSET] = csr2trace_mip_msip_i; + csr_trace1.mip[SCR1_CSR_MIE_MTIE_OFFSET] = csr2trace_mip_mtip_i; + csr_trace1.mip[SCR1_CSR_MIE_MEIE_OFFSET] = csr2trace_mip_meip_i; +end + +`endif // SCR1_TRACE_LOG_EN + +endmodule : scr1_tracelog + +`endif // SCR1_TRGT_SIMULATION