Compare commits

..

13 Commits

Author SHA1 Message Date
Mikhail Yenuchenko
b3e5f395a1 Update RUN_PAR.tcl 2026-01-21 16:42:58 +03:00
Mikhail Yenuchenko
12b848a74c Update FLOW_PAR.tcl 2026-01-21 16:42:55 +03:00
Mikhail Yenuchenko
0f3384e157 Update RUN_PAR.tcl 2026-01-21 15:25:51 +03:00
Mikhail Yenuchenko
513244f16f Update RUN_SYN.tcl 2026-01-21 15:11:43 +03:00
Mikhail Yenuchenko
9ed2c9a8f4 Update scr1_core_top.sdc 2026-01-21 15:09:42 +03:00
Mikhail Yenuchenko
da358566a4 Add comments 2026-01-21 14:59:40 +03:00
Mikhail Yenuchenko
10b5b08537 Remove set_clock_groups 2026-01-21 14:59:32 +03:00
Mikhail Yenuchenko
b76ce3629e Rename 2026-01-21 14:53:13 +03:00
Mikhail Yenuchenko
86249ca0f0 Copy files 2026-01-21 14:06:27 +03:00
Mikhail Yenuchenko
bd5792ac5d Move file 2026-01-21 14:05:56 +03:00
Mikhail Yenuchenko
13be3b023a Update RUN_SYN.tcl 2026-01-21 14:05:38 +03:00
Mikhail Yenuchenko
099605414c Move file 2026-01-21 14:05:16 +03:00
Mikhail Yenuchenko
23e0e58f8b Folder rename 2026-01-20 17:48:32 +03:00
106 changed files with 17372 additions and 168 deletions

View File

@@ -13,7 +13,7 @@ if {$PaR_INIT eq "TRUE"} {
set init_verilog ${NETLIST_PATH}/${NETLIST_TOP_NAME}; # SYN netlist file
set init_mmmc_file ${PAR_MMMC_FILE}; # Techmological file for multi-mode multi-corner PaR
set init_io_file ${PAR_NETLIST_TOP_PORT_FILE}; # File with location of the TOP level ports on the floorplan
#set init_io_file ${PAR_NETLIST_TOP_PORT_FILE}; # File with location of the TOP level ports on the floorplan
init_design
}

View File

@@ -12,10 +12,10 @@
### ================= USER SETTINGS =================
set NETLIST_TOP_NAME "scr1_top_ahb_syn_netlist.v"; # RTL top module name
set NETLIST_TOP_NAME "scr1_core_top_syn_netlist.v"; # RTL top module name
set NETLIST_PATH "../results/results_syn"; # RTL path to the source files
set PAR_SDC_TOP_NAME "scr1_top_ahb_syn.sdc"; # SDC top file name
set PAR_SDC_TOP_NAME "scr1_core_top_syn.sdc"; # SDC top file name
set PAR_SDC_PATH "../results/results_syn"; # SDC path to the sources
set PAR_MMMC_FILE "../scripts/scripts_aux/XFAB180_MMMC.tcl"; # Multi-mode multi-corner file
@@ -28,7 +28,7 @@ set PAR_INIT_LEF_FILESET "/Cadence/Libs/X_FAB/XKIT/xt018/cadence/v7_0/techLEF/v7
set PAR_REPORTS_FOLDER "../reports/reports_PaR"; # Reports folder
set PAR_RESULTS_FOLDER "../results/results_PaR"; # Results folder
set FLOORPLAN_DIMENSIONS {9000 9000}; # FP chip area
set FLOORPLAN_DIMENSIONS {500 500}; # FP chip area
set FLOORPLAN_MARGINS {50 50 50 50}; #FP chip margins
### ================= END of USER SETTINGS =============

View File

@@ -12,7 +12,7 @@
### ================= USER SETTINGS =================
set RTL_TOP_NAME "scr1_top_ahb"; # RTL top module name
set RTL_TOP_NAME "scr1_core_top"; # RTL top module name
set RTL_PATH "../src/rtl"; # RTL path to the source files
set RTL_FILELIST_NAME "filelist.v"; # RTL path to the filelist for synthesis
@@ -48,6 +48,9 @@ if {$MAPPING eq "TRUE"} {
# Rear SDC constraints
read_sdc ${SYN_SDC_PATH}/${SYN_SDC_TOP_NAME}
# For testing correctness of SDC uncomment the command below
#exit
# Synthesize (technology mapped)
synthesize -to_mapped
synthesize -incremental

View File

@@ -1,63 +1,63 @@
#`include "../scr1_custom_define.svh"
#`include "../scr1_arch_custom.svh"
// `include "../scr1_custom_define.svh"
// `include "../scr1_arch_custom.svh"
# core
#/home/yenuchenko/riscv_school/scr1/scr1-master/src/core
`include "../core/scr1_clk_ctrl.sv"
`include "../core/scr1_core_top.sv"
`include "../core/scr1_dm.sv"
`include "../core/scr1_dmi.sv"
`include "../core/scr1_scu.sv"
`include "../core/scr1_tapc.sv"
`include "../core/scr1_tapc_shift_reg.sv"
`include "../core/scr1_tapc_synchronizer.sv"
// includes
// /home/yenuchenko/riscv_school/scr1/scr1-master/src/includes
`include "scr1/scr1_ahb.svh"
`include "scr1/scr1_arch_description.svh"
`include "scr1/scr1_arch_types.svh"
`include "scr1/scr1_csr.svh"
`include "scr1/scr1_dm.svh"
`include "scr1/scr1_hdu.svh"
`include "scr1/scr1_ipic.svh"
`include "scr1/scr1_memif.svh"
`include "scr1/scr1_riscv_isa_decoding.svh"
`include "scr1/scr1_scu.svh"
`include "scr1/scr1_search_ms1.svh"
`include "scr1/scr1_tapc.svh"
`include "scr1/scr1_tdu.svh"
# pipeline
#/home/yenuchenko/riscv_school/scr1/scr1-master/src/core/pipeline
`include "../core/pipeline/scr1_ipic.sv"
`include "../core/pipeline/scr1_pipe_csr.sv"
`include "../core/pipeline/scr1_pipe_exu.sv"
`include "../core/pipeline/scr1_pipe_hdu.sv"
`include "../core/pipeline/scr1_pipe_ialu.sv"
`include "../core/pipeline/scr1_pipe_idu.sv"
`include "../core/pipeline/scr1_pipe_ifu.sv"
`include "../core/pipeline/scr1_pipe_lsu.sv"
`include "../core/pipeline/scr1_pipe_mprf.sv"
`include "../core/pipeline/scr1_pipe_tdu.sv"
`include "../core/pipeline/scr1_pipe_top.sv"
`include "../core/pipeline/scr1_tracelog.sv"
// core
// /home/yenuchenko/riscv_school/scr1/scr1-master/src/core
`include "scr1/scr1_clk_ctrl.sv"
`include "scr1/scr1_core_top.sv"
`include "scr1/scr1_dm.sv"
`include "scr1/scr1_dmi.sv"
`include "scr1/scr1_scu.sv"
`include "scr1/scr1_tapc.sv"
`include "scr1/scr1_tapc_shift_reg.sv"
`include "scr1/scr1_tapc_synchronizer.sv"
# primitives
#/home/yenuchenko/riscv_school/scr1/scr1-master/src/core/primitives
`include "../core/primitives/scr1_cg.sv"
`include "../core/primitives/scr1_reset_cells.sv"
// pipeline
// /home/yenuchenko/riscv_school/scr1/scr1-master/src/core
`include "scr1/scr1_ipic.sv"
`include "scr1/scr1_pipe_csr.sv"
`include "scr1/scr1_pipe_exu.sv"
`include "scr1/scr1_pipe_hdu.sv"
`include "scr1/scr1_pipe_ialu.sv"
`include "scr1/scr1_pipe_idu.sv"
`include "scr1/scr1_pipe_ifu.sv"
`include "scr1/scr1_pipe_lsu.sv"
`include "scr1/scr1_pipe_mprf.sv"
`include "scr1/scr1_pipe_tdu.sv"
`include "scr1/scr1_pipe_top.sv"
`include "scr1/scr1_tracelog.sv"
# includes
#/home/yenuchenko/riscv_school/scr1/scr1-master/src/includes
`include "../includes/scr1_ahb.svh"
`include "../includes/scr1_arch_description.svh"
`include "../includes/scr1_arch_types.svh"
`include "../includes/scr1_csr.svh"
`include "../includes/scr1_dm.svh"
`include "../includes/scr1_hdu.svh"
`include "../includes/scr1_ipic.svh"
`include "../includes/scr1_memif.svh"
`include "../includes/scr1_riscv_isa_decoding.svh"
`include "../includes/scr1_scu.svh"
`include "../includes/scr1_search_ms1.svh"
`include "../includes/scr1_tapc.svh"
`include "../includes/scr1_tdu.svh"
// primitives
// /home/yenuchenko/riscv_school/scr1/scr1-master/src/core
`include "scr1/scr1_cg.sv"
`include "scr1/scr1_reset_cells.sv"
# top
#/home/yenuchenko/riscv_school/scr1/scr1-master/src/top
`include "../top/scr1_dmem_ahb.sv"
`include "../top/scr1_dmem_router.sv"
`include "../top/scr1_dp_memory.sv"
`include "../top/scr1_imem_ahb.sv"
`include "../top/scr1_imem_router.sv"
`include "../top/scr1_mem_axi.sv"
`include "../top/scr1_tcm.sv"
`include "../top/scr1_timer.sv"
`include "../top/scr1_top_ahb.sv"
`include "../top/scr1_top_axi.sv"
// top
// /home/yenuchenko/riscv_school/scr1/scr1-master/src/top
`include "scr1/scr1_dmem_ahb.sv"
`include "scr1/scr1_dmem_router.sv"
`include "scr1/scr1_dp_memory.sv"
`include "scr1/scr1_imem_ahb.sv"
`include "scr1/scr1_imem_router.sv"
`include "scr1/scr1_mem_axi.sv"
`include "scr1/scr1_tcm.sv"
`include "scr1/scr1_timer.sv"
`include "scr1/scr1_top_ahb.sv"
`include "scr1/scr1_top_axi.sv"

View File

@@ -0,0 +1,215 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_arch_description.svh>
/// @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

78
src/sdc/scr1_core_top.sdc Normal file
View File

@@ -0,0 +1,78 @@
### Stage: "Synthesis and PaR"
### File description: "Constraints for the design"
# SET LIB UNITS
set_units -time 1.0ns;
set_units -capacitance 1.0pF;
set_max_capacitance 0.5 [all_outputs]
### ====================== CLOCKS ===========================
# Clock period: 10 ns (100 MHz)
set CLK_PERIOD 100
# Clock uncertainty: 200 ps for all clocks
set CLK_UNCERT 0.2;
# Clock transition: 1 ns R/F
set MINRISE 0
set MAXRISE 1.0
set MINFALL 0
set MAXFALL 1.0
# Clock setup
create_clock -name "clk" -period $CLK_PERIOD -waveform "0 [expr $CLK_PERIOD/2.0]" [get_ports "clk"]
set_clock_uncertainty $CLK_UNCERT [get_clocks "clk"]
set_clock_transition -rise -min $MINRISE [get_clocks "clk"]
set_clock_transition -rise -max $MAXRISE [get_clocks "clk"]
set_clock_transition -fall -min $MINFALL [get_clocks "clk"]
set_clock_transition -fall -max $MAXFALL [get_clocks "clk"]
### ====================== DELAYS ===========================
# IO delays: 2.5 ns
set INPUT_DELAY_CLK [expr $CLK_PERIOD/4.0]
set OUTPUT_DELAY_CLK [expr $CLK_PERIOD/4.0]
# IO delays setup
set_input_delay -clock "clk" -max $INPUT_DELAY_CLK [all_inputs]
set_input_delay -clock "clk" -min $INPUT_DELAY_CLK [all_inputs]
set_output_delay -clock "clk" -max $OUTPUT_DELAY_CLK [all_outputs]
set_output_delay -clock "clk" -min $OUTPUT_DELAY_CLK [all_outputs]
# Ideal networks
set_ideal_network [get_ports "pwrup_rst_n"]
set_ideal_network [get_ports "rst_n"]
set_ideal_network [get_ports "cpu_rst_n"]
set_ideal_network [get_ports "test_rst_n"]
# False paths
set_false_path -from [get_ports "pwrup_rst_n"]
set_false_path -from [get_ports "rst_n"]
set_false_path -from [get_ports "cpu_rst_n"]
set_false_path -from [get_ports "test_rst_n"]
set_case_analysis 0 [get_ports "test_mode"]
# |--------------|
#->| |->
#->| clk |->
# | |
# ----------------
# | rtc |
# ----------------
#->| |->tdo
#->| tck |->tdo_en
# | |
# |--------------|

View File

@@ -1,106 +0,0 @@
### Stage: "Synthesis and PaR"
### File description: "Constraints for the design"
# SET LIB UNITS
set_units -time 1.0ns;
set_units -capacitance 1.0pF;
set_max_capacitance 0.5 [all_outputs]
### ====================== CLOCKS ===========================
#clock uncertainty: 200ps for all clocks
set CLK_UNCERT 0.2;
#transition: 1ns R/F
# CLOCK PERIOD
set CLK_PERIOD 11.13
set TCK_PERIOD 100
set RTC_CLK_PERIOD 10000
# IO DELAYS
set INPUT_DELAY_CLK [expr $CLK_PERIOD/4.0]
set OUTPUT_DELAY_CLK [expr $CLK_PERIOD/4.0]
set INPUT_DELAY_TCK [expr $TCK_PERIOD/4.0]
set OUTPUT_DELAY_TCK [expr $TCK_PERIOD/4.0]
#clk->100MHz
create_clock -name "clk" -period $CLK_PERIOD -waveform "0 [expr $CLK_PERIOD/2.0]" [get_ports "clk"]
#tck->10MHz
create_clock -name "tck" -period $TCK_PERIOD -waveform "0 [expr $TCK_PERIOD/2.0]" [get_ports "tck"]
#rtc_clk->100kHz
create_clock -name "rtc_clk" -period $RTC_CLK_PERIOD -waveform "0 [expr $RTC_CLK_PERIOD/2.0]" [get_ports "rtc_clk"]
set_clock_groups -asynchronous -group {"clk"} -group {"tck"} -group {"rtc_clk"}
set MINRISE 0
set MAXRISE 1.0
set MINFALL 0
set MAXFALL 1.0
set_clock_uncertainty $CLK_UNCERT [get_clocks "clk"]
set_clock_transition -rise -min $MINRISE [get_clocks "clk"]
set_clock_transition -rise -max $MAXRISE [get_clocks "clk"]
set_clock_transition -fall -min $MINFALL [get_clocks "clk"]
set_clock_transition -fall -max $MAXFALL [get_clocks "clk"]
set_clock_uncertainty $CLK_UNCERT [get_clocks "tck"]
set_clock_transition -rise -min $MINRISE [get_clocks "tck"]
set_clock_transition -rise -max $MAXRISE [get_clocks "tck"]
set_clock_transition -fall -min $MINFALL [get_clocks "tck"]
set_clock_transition -fall -max $MAXFALL [get_clocks "tck"]
set_clock_uncertainty $CLK_UNCERT [get_clocks "rtc_clk"]
set_clock_transition -rise -min $MINRISE [get_clocks "rtc_clk"]
set_clock_transition -rise -max $MAXRISE [get_clocks "rtc_clk"]
set_clock_transition -fall -min $MINFALL [get_clocks "rtc_clk"]
set_clock_transition -fall -max $MAXFALL [get_clocks "rtc_clk"]
set_ideal_network [get_ports "pwrup_rst_n"]
set_ideal_network [get_ports "rst_n"]
set_ideal_network [get_ports "cpu_rst_n"]
set_ideal_network [get_ports "test_rst_n"]
set_ideal_network [get_ports "trst_n"]
set_false_path -from [get_ports "pwrup_rst_n"]
set_false_path -from [get_ports "rst_n"]
set_false_path -from [get_ports "cpu_rst_n"]
set_false_path -from [get_ports "test_rst_n"]
set_false_path -from [get_ports "trst_n"]
#IO delays:
set_input_delay -clock "clk" -max $INPUT_DELAY_CLK [remove_from_collection [all_inputs] {trst_n tdi tms}]
set_input_delay -clock "clk" -min $INPUT_DELAY_CLK [remove_from_collection [all_inputs] {trst_n tdi tms}]
set_input_delay -clock "tck" -max $INPUT_DELAY_TCK [get_ports {trst_n tdi tms}]
set_input_delay -clock "tck" -min $INPUT_DELAY_TCK [get_ports {trst_n tdi tms}]
set_output_delay -clock "clk" -max $OUTPUT_DELAY_CLK [remove_from_collection [all_outputs] {tdo tdo_en}]
set_output_delay -clock "clk" -min $OUTPUT_DELAY_CLK [remove_from_collection [all_outputs] {tdo tdo_en}]
set_output_delay -clock "tck" -max $OUTPUT_DELAY_TCK [get_ports {tdo tdo_en}]
set_output_delay -clock "tck" -min $OUTPUT_DELAY_TCK [get_ports {tdo tdo_en}]
set_case_analysis 0 [get_ports "test_mode"]
# |--------------|
#->| |->
#->| clk |->
# | |
# ----------------
# | rtc |
# ----------------
#->| |->tdo
#->| tck |->tdo_en
# | |
# |--------------|

View File

@@ -0,0 +1,605 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_ipic.sv>
/// @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<SCR1_IRQ_VECT_NUM; ++i) begin
ipic_ipr_next[i] = ipic_ipr_clr[i] ? 1'b0
: ~ipic_imr_ff[i] ? irq_lvl[i]
: ipic_ipr_ff[i] | irq_edge_detected[i];
end
end
// ISVR
//------------------------------------------------------------------------------
// For every IRQ line shows whether the interrupt is in service or not
assign ipic_isvr_upd = irq_start_vd | ipic_eoi_req;
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
ipic_isvr_ff <= '0;
end else if (ipic_isvr_upd) begin
ipic_isvr_ff <= ipic_isvr_next;
end
end
always_comb begin
ipic_isvr_eoi = ipic_isvr_ff;
if (irq_serv_vd) begin
ipic_isvr_eoi[irq_serv_idx] = 1'b0;
end
end
always_comb begin
ipic_isvr_next = ipic_isvr_ff;
if (irq_start_vd) begin
ipic_isvr_next[irq_req_idx] = 1'b1;
end else if (ipic_eoi_req) begin
ipic_isvr_next = ipic_isvr_eoi;
end
end
// IER
//------------------------------------------------------------------------------
// Enables/disables interrupt for every IRQ line
assign ipic_ier_upd = cicsr_wr_req | icsr_wr_req;
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
ipic_ier_ff <= '0;
end else if (ipic_ier_upd) begin
ipic_ier_ff <= ipic_ier_next;
end
end
always_comb begin
ipic_ier_next = ipic_ier_ff;
if (cicsr_wr_req) begin
ipic_ier_next[irq_serv_idx] = irq_serv_vd
? csr2ipic_wdata_i[SCR1_IPIC_ICSR_IE]
: ipic_ier_ff[irq_serv_idx];
end else if (icsr_wr_req) begin
ipic_ier_next[ipic_idxr_ff] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_IE];
end
end
// IMR
//------------------------------------------------------------------------------
// For every IRQ line sets either Level (0) or Edge (1) detection
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
ipic_imr_ff <= '0;
end else if (icsr_wr_req) begin
ipic_imr_ff <= ipic_imr_next;
end
end
always_comb begin
ipic_imr_next = ipic_imr_ff;
if (icsr_wr_req) begin
ipic_imr_next[ipic_idxr_ff] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_IM];
end
end
// IINVR
//------------------------------------------------------------------------------
// For every IRQ line defines whether it should be inverted or not
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
ipic_iinvr_ff <= '0;
end else if (icsr_wr_req) begin
ipic_iinvr_ff <= ipic_iinvr_next;
end
end
always_comb begin
ipic_iinvr_next = ipic_iinvr_ff;
if (icsr_wr_req) begin
ipic_iinvr_next[ipic_idxr_ff] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_INV];
end
end
// ICSR
//------------------------------------------------------------------------------
// Holds control and status information about the interrupt defined by Index Register
assign ipic_icsr.ip = ipic_ipr_ff [ipic_idxr_ff];
assign ipic_icsr.ie = ipic_ier_ff [ipic_idxr_ff];
assign ipic_icsr.im = ipic_imr_ff [ipic_idxr_ff];
assign ipic_icsr.inv = ipic_iinvr_ff[ipic_idxr_ff];
assign ipic_icsr.isv = ipic_isvr_ff [ipic_idxr_ff];
assign ipic_icsr.line = SCR1_IRQ_LINES_WIDTH'(ipic_idxr_ff);
//------------------------------------------------------------------------------
// Priority IRQ generation logic
//------------------------------------------------------------------------------
assign irq_req_v = ipic_ipr_ff & ipic_ier_ff;
assign irr_priority = scr1_search_one_16(irq_req_v);
assign irq_req_vd = irr_priority.vd;
assign irq_req_idx = irr_priority.idx;
assign isvr_priority_eoi = scr1_search_one_16(ipic_isvr_eoi);
assign irq_eoi_req_vd = isvr_priority_eoi.vd;
assign irq_eoi_req_idx = isvr_priority_eoi.idx;
assign irq_hi_prior_pnd = irq_req_idx < irq_serv_idx;
assign ipic2csr_irq_m_req_o = irq_req_vd & (~irq_serv_vd | irq_hi_prior_pnd);
assign irq_start_vd = ipic2csr_irq_m_req_o & ipic_soi_req;
endmodule : scr1_ipic
`endif // SCR1_IPIC_EN

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,904 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_pipe_hdu.sv>
/// @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

View File

@@ -0,0 +1,720 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_pipe_ialu.sv>
/// @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

View File

@@ -0,0 +1,940 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_pipe_idu.sv>
/// @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

View File

@@ -0,0 +1,826 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_pipe_ifu.sv>
/// @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_<UPPER_16_BITS>_<LOWER_16_BITS>
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

View File

@@ -0,0 +1,351 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_pipe_lsu.sv>
/// @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

View File

@@ -0,0 +1,167 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_pipe_mprf.sv>
/// @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

View File

@@ -0,0 +1,610 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_pipe_tdu.sv>
/// @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

View File

@@ -0,0 +1,825 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_pipe_top.sv>
/// @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

View File

@@ -0,0 +1,453 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_tracelog.sv>
/// @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

View File

@@ -0,0 +1,32 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_cg.sv>
/// @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

View File

@@ -0,0 +1,231 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_sync_rstn.sv>
/// @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

View File

@@ -0,0 +1,55 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_clk_ctrl.sv>
/// @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

View File

@@ -0,0 +1,521 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_core_top.sv>
/// @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

1427
src_ref/core/scr1_dm.sv Normal file

File diff suppressed because it is too large Load Diff

182
src_ref/core/scr1_dmi.sv Normal file
View File

@@ -0,0 +1,182 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_dmi.sv>
/// @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

516
src_ref/core/scr1_scu.sv Normal file
View File

@@ -0,0 +1,516 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_scu.sv>
/// @brief System Control Unit (SCU)
///
//------------------------------------------------------------------------------
//
// Functionality:
// - Generates System, Core, HDU and DM resets and their qualifier signals
// - Provides debugger with software System and Core resets generation functionality
// - Allows to set the behavior of DM and HDU resets
// - Shows resets Statuses and Sticky Statuses
// Structure:
// - TAPC scan-chain interface
// - SCU CSRs write/read interface
// - SCU CSRS:
// - CONTROL register
// - MODE register
// - STATUS register
// - STICKY_STATUS register
// - Reset logic
// - System Reset
// - Core Reset
// - DM Reset
// - HDU Reset
//------------------------------------------------------------------------------
`include "scr1_arch_description.svh"
`include "scr1_scu.svh"
`ifdef SCR1_DBG_EN
module scr1_scu (
// Global signals
input logic pwrup_rst_n, // Power-Up Reset
input logic rst_n, // Regular Reset
input logic cpu_rst_n, // CPU Reset
input logic test_mode, // DFT Test Mode
input logic test_rst_n, // DFT Test Reset
input logic clk, // SCU clock
// TAPC scan-chains
input logic tapcsync2scu_ch_sel_i, // TAPC Chain Select
input logic tapcsync2scu_ch_id_i, // TAPC Chain ID
input logic tapcsync2scu_ch_capture_i, // TAPC Chain Capture
input logic tapcsync2scu_ch_shift_i, // TAPC Chain Shift
input logic tapcsync2scu_ch_update_i, // TAPC Chain Update
input logic tapcsync2scu_ch_tdi_i, // TAPC Chain TDI
output logic scu2tapcsync_ch_tdo_o, // TAPC Chain TDO
// Input sync resets:
input logic ndm_rst_n_i, // Non-DM Reset input from DM
input logic hart_rst_n_i, // HART Reset from DM
// Generated resets
output logic sys_rst_n_o, // System/Cluster Reset
output logic core_rst_n_o, // Core Reset
output logic dm_rst_n_o, // Debug Module Reset
output logic hdu_rst_n_o, // HART Debug Unit Reset
// Resets statuses
output logic sys_rst_status_o, // System Reset Status (sync'ed to POR reset domain)
output logic core_rst_status_o, // Core Reset Status (sync'ed to POR reset domain)
// Reset Domain Crossing (RDC) qualifiers
output logic sys_rdc_qlfy_o, // System/Cluster-to-ExternalSOC Reset Domain Crossing Qualifier
output logic core_rdc_qlfy_o, // Core-to-ExternalSOC Reset Domain Crossing Qualifier
output logic core2hdu_rdc_qlfy_o, // Core-to-HDU Reset Domain Crossing Qualifier
output logic core2dm_rdc_qlfy_o, // Core-to-DM Reset Domain Crossing Qualifier
output logic hdu2dm_rdc_qlfy_o // HDU-to-DM Reset Domain Crossing Qualifier
);
//------------------------------------------------------------------------------
// Local Parameters
//======================================================================================================================
localparam int unsigned SCR1_SCU_RST_SYNC_STAGES_NUM = 2;
//------------------------------------------------------------------------------
// Local Signals
//------------------------------------------------------------------------------
// SCU CSR write/read i/f
//------------------------------------------------------------------------------
// TAPC scan-chain control logic
logic scu_csr_req;
logic tapc_dr_cap_req;
logic tapc_dr_shft_req;
logic tapc_dr_upd_req;
// TAPC shift register signals
logic tapc_shift_upd;
type_scr1_scu_sysctrl_dr_s tapc_shift_ff;
type_scr1_scu_sysctrl_dr_s tapc_shift_next;
// TAPC shadow register signals
type_scr1_scu_sysctrl_dr_s tapc_shadow_ff;
// SCU CSR write/read i/f
//------------------------------------------------------------------------------
logic [SCR1_SCU_DR_SYSCTRL_DATA_WIDTH-1:0] scu_csr_wdata;
logic [SCR1_SCU_DR_SYSCTRL_DATA_WIDTH-1:0] scu_csr_rdata;
// SCU CSRs signals
//------------------------------------------------------------------------------
// Control register
type_scr1_scu_sysctrl_control_reg_s scu_control_ff;
logic scu_control_wr_req;
// Mode register
type_scr1_scu_sysctrl_mode_reg_s scu_mode_ff;
logic scu_mode_wr_req;
// Status register
type_scr1_scu_sysctrl_status_reg_s scu_status_ff;
type_scr1_scu_sysctrl_status_reg_s scu_status_ff_dly;
type_scr1_scu_sysctrl_status_reg_s scu_status_ff_posedge;
// Sticky Status register
type_scr1_scu_sysctrl_status_reg_s scu_sticky_sts_ff;
logic scu_sticky_sts_wr_req;
// Reset logic signals
//------------------------------------------------------------------------------
// Input resets synchronization signals
logic pwrup_rst_n_sync;
logic rst_n_sync;
logic cpu_rst_n_sync;
// System Reset signals
logic sys_rst_n_in;
logic sys_rst_n_status;
logic sys_rst_n_status_sync;
logic sys_rst_n_qlfy;
logic sys_reset_n;
// Core Reset signals
logic core_rst_n_in_sync;
logic core_rst_n_status;
logic core_rst_n_status_sync;
logic core_rst_n_qlfy;
logic core_reset_n;
// HDU Reset signals
logic hdu_rst_n_in_sync;
logic hdu_rst_n_status;
logic hdu_rst_n_status_sync;
logic hdu_rst_n_qlfy;
// DM Reset signals
logic dm_rst_n_in;
logic dm_rst_n_status;
//------------------------------------------------------------------------------
// TAPC scan-chain i/f
//------------------------------------------------------------------------------
//
// Consists of the following functional units:
// - TAPC scan-chain control logic
// - TAPC shift register
// - TAPC shadow register
//
// TAPC scan-chain control logic
//------------------------------------------------------------------------------
assign scu_csr_req = tapcsync2scu_ch_sel_i & (tapcsync2scu_ch_id_i == '0);
assign tapc_dr_cap_req = scu_csr_req & tapcsync2scu_ch_capture_i;
assign tapc_dr_shft_req = scu_csr_req & tapcsync2scu_ch_shift_i;
assign tapc_dr_upd_req = scu_csr_req & tapcsync2scu_ch_update_i;
// TAPC shift register
//------------------------------------------------------------------------------
assign tapc_shift_upd = tapc_dr_cap_req | tapc_dr_shft_req;
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
if (~pwrup_rst_n_sync) begin
tapc_shift_ff <= '0;
end else if (tapc_shift_upd) begin
tapc_shift_ff <= tapc_shift_next;
end
end
assign tapc_shift_next = tapc_dr_cap_req ? tapc_shadow_ff
: tapc_dr_shft_req ? {tapcsync2scu_ch_tdi_i, tapc_shift_ff[$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

457
src_ref/core/scr1_tapc.sv Normal file
View File

@@ -0,0 +1,457 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_tapc.sv>
/// @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

View File

@@ -0,0 +1,112 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_tapc_shift_reg.sv>
/// @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

View File

@@ -0,0 +1,183 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_tapc_synchronizer.sv>
/// @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

View File

@@ -0,0 +1,59 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_ahb.svh>
/// @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

View File

@@ -0,0 +1,72 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_arch_types.svh>
/// @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

View File

@@ -0,0 +1,196 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_csr.svh>
/// @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

View File

@@ -0,0 +1,141 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_dm.svh>
/// @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

View File

@@ -0,0 +1,165 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_pipe_hdu.svh>
/// @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

View File

@@ -0,0 +1,58 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_ipic.svh>
/// @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

View File

@@ -0,0 +1,49 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_memif.svh>
/// @brief Memory interface definitions file
///
`ifndef SCR1_MEMIF_SVH
`define SCR1_MEMIF_SVH
`include "scr1_arch_description.svh"
//-------------------------------------------------------------------------------
// Memory command enum
//-------------------------------------------------------------------------------
typedef enum logic {
SCR1_MEM_CMD_RD = 1'b0,
SCR1_MEM_CMD_WR = 1'b1
`ifdef SCR1_XPROP_EN
,
SCR1_MEM_CMD_ERROR = 'x
`endif // SCR1_XPROP_EN
} type_scr1_mem_cmd_e;
//-------------------------------------------------------------------------------
// Memory data width enum
//-------------------------------------------------------------------------------
typedef enum logic[1:0] {
SCR1_MEM_WIDTH_BYTE = 2'b00,
SCR1_MEM_WIDTH_HWORD = 2'b01,
SCR1_MEM_WIDTH_WORD = 2'b10
`ifdef SCR1_XPROP_EN
,
SCR1_MEM_WIDTH_ERROR = 'x
`endif // SCR1_XPROP_EN
} type_scr1_mem_width_e;
//-------------------------------------------------------------------------------
// Memory response enum
//-------------------------------------------------------------------------------
typedef enum logic[1:0] {
SCR1_MEM_RESP_NOTRDY = 2'b00,
SCR1_MEM_RESP_RDY_OK = 2'b01,
SCR1_MEM_RESP_RDY_ER = 2'b10
`ifdef SCR1_XPROP_EN
,
SCR1_MEM_RESP_ERROR = 'x
`endif // SCR1_XPROP_EN
} type_scr1_mem_resp_e;
`endif // SCR1_MEMIF_SVH

View File

@@ -0,0 +1,185 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_riscv_isa_decoding.svh>
/// @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

View File

@@ -0,0 +1,84 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_scu.svh>
/// @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

View File

@@ -0,0 +1,94 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_search_ms1.svh>
/// @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

View File

@@ -0,0 +1,66 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_tapc.svh>
/// @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

View File

@@ -0,0 +1,121 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_tdu.svh>
/// @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

View File

@@ -0,0 +1,480 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_dmem_ahb.sv>
/// @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

View File

@@ -0,0 +1,278 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_dmem_router.sv>
/// @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

View File

@@ -0,0 +1,111 @@
/// Copyright by Syntacore LLC © 2016-2020. See LICENSE for details
/// @file <scr1_dp_memory.sv>
/// @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<SCR1_NBYTES; i++) begin
if (webb[i]) begin
ram_block[addrb][i*8 +: 8] <= datab[i*8 +: 8];
end
end
end
if (renb) begin
qb <= ram_block[addrb];
end
end
`endif // SCR1_TRGT_FPGA_INTEL
endmodule : scr1_dp_memory
`endif // SCR1_TCM_EN

View File

@@ -0,0 +1,319 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_imem_ahb.sv>
/// @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

Some files were not shown because too many files have changed in this diff Show More