Add zero-riscy files
diff --git a/verilog/rtl/ips/zero-riscy b/verilog/rtl/ips/zero-riscy
deleted file mode 160000
index ab3ec36..0000000
--- a/verilog/rtl/ips/zero-riscy
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit ab3ec361be6f8bd7abad1accb3700659890f7ad3
diff --git a/verilog/rtl/ips/zero-riscy/include/zeroriscy_config.sv b/verilog/rtl/ips/zero-riscy/include/zeroriscy_config.sv
new file mode 100644
index 0000000..6442a76
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/include/zeroriscy_config.sv
@@ -0,0 +1,34 @@
+// Copyright 2017 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the “License”); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// Engineer: Michael Gautschi - gautschi@iis.ee.ethz.ch //
+// //
+// Additional contributions by: //
+// Markus Wegmann - markus.wegmann@technokrat.ch //
+// Davide Schiavone - pschiavo@iis.ee.ethz.ch //
+// //
+// Design Name: RISC-V config file //
+// Project Name: zero-riscy //
+// Language: SystemVerilog //
+// //
+// Description: Configure optional simulation modules //
+// //
+////////////////////////////////////////////////////////////////////////////////
+
+// no traces for synthesis, they are not synthesizable
+`ifndef SYNTHESIS
+`ifndef PULP_FPGA_EMUL
+`define TRACE_EXECUTION
+`endif
+//`define SIMCHECKER
+`endif
+
+//`define CHECK_MISALIGNED
\ No newline at end of file
diff --git a/verilog/rtl/ips/zero-riscy/include/zeroriscy_defines.sv b/verilog/rtl/ips/zero-riscy/include/zeroriscy_defines.sv
new file mode 100644
index 0000000..4fdc806
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/include/zeroriscy_defines.sv
@@ -0,0 +1,316 @@
+// Copyright 2017 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the “License”); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// Engineer: Matthias Baer - baermatt@student.ethz.ch //
+// //
+// Additional contributions by: //
+// Sven Stucki - svstucki@student.ethz.ch //
+// //
+// //
+// Design Name: RISC-V processor core //
+// Project Name: zero-riscy //
+// Language: SystemVerilog //
+// //
+// Description: Defines for various constants used by the processor core. //
+// //
+////////////////////////////////////////////////////////////////////////////////
+
+package zeroriscy_defines;
+
+////////////////////////////////////////////////
+// ___ ____ _ //
+// / _ \ _ __ / ___|___ __| | ___ ___ //
+// | | | | '_ \| | / _ \ / _` |/ _ \/ __| //
+// | |_| | |_) | |__| (_) | (_| | __/\__ \ //
+// \___/| .__/ \____\___/ \__,_|\___||___/ //
+// |_| //
+////////////////////////////////////////////////
+
+parameter OPCODE_SYSTEM = 7'h73;
+parameter OPCODE_FENCE = 7'h0f;
+parameter OPCODE_OP = 7'h33;
+parameter OPCODE_OPIMM = 7'h13;
+parameter OPCODE_STORE = 7'h23;
+parameter OPCODE_LOAD = 7'h03;
+parameter OPCODE_BRANCH = 7'h63;
+parameter OPCODE_JALR = 7'h67;
+parameter OPCODE_JAL = 7'h6f;
+parameter OPCODE_AUIPC = 7'h17;
+parameter OPCODE_LUI = 7'h37;
+
+// those opcodes are now used for PULP custom instructions
+// parameter OPCODE_CUST0 = 7'h0b
+// parameter OPCODE_CUST1 = 7'h2b
+
+// PULP custom
+parameter OPCODE_LOAD_POST = 7'h0b;
+parameter OPCODE_STORE_POST = 7'h2b;
+parameter OPCODE_PULP_OP = 7'h5b;
+parameter OPCODE_VECOP = 7'h57;
+parameter OPCODE_HWLOOP = 7'h7b;
+
+parameter REGC_S1 = 2'b10;
+parameter REGC_RD = 2'b01;
+parameter REGC_ZERO = 2'b11;
+
+
+//////////////////////////////////////////////////////////////////////////////
+// _ _ _ _ ___ _ _ //
+// / \ | | | | | | / _ \ _ __ ___ _ __ __ _| |_(_) ___ _ __ ___ //
+// / _ \ | | | | | | | | | | '_ \ / _ \ '__/ _` | __| |/ _ \| '_ \/ __| //
+// / ___ \| |__| |_| | | |_| | |_) | __/ | | (_| | |_| | (_) | | | \__ \ //
+// /_/ \_\_____\___/ \___/| .__/ \___|_| \__,_|\__|_|\___/|_| |_|___/ //
+// |_| //
+//////////////////////////////////////////////////////////////////////////////
+
+parameter ALU_OP_WIDTH = 6;
+
+parameter ALU_ADD = 6'b011000;
+parameter ALU_SUB = 6'b011001;
+parameter ALU_ADDU = 6'b011010;
+parameter ALU_SUBU = 6'b011011;
+parameter ALU_ADDR = 6'b011100;
+parameter ALU_SUBR = 6'b011101;
+parameter ALU_ADDUR = 6'b011110;
+parameter ALU_SUBUR = 6'b011111;
+
+parameter ALU_XOR = 6'b101111;
+parameter ALU_OR = 6'b101110;
+parameter ALU_AND = 6'b010101;
+
+// Shifts
+parameter ALU_SRA = 6'b100100;
+parameter ALU_SRL = 6'b100101;
+parameter ALU_ROR = 6'b100110;
+parameter ALU_SLL = 6'b100111;
+
+// bit manipulation
+parameter ALU_BEXT = 6'b101000;
+parameter ALU_BEXTU = 6'b101001;
+parameter ALU_BINS = 6'b101010;
+parameter ALU_BCLR = 6'b101011;
+parameter ALU_BSET = 6'b101100;
+
+// Bit counting
+parameter ALU_FF1 = 6'b110110;
+parameter ALU_FL1 = 6'b110111;
+parameter ALU_CNT = 6'b110100;
+parameter ALU_CLB = 6'b110101;
+
+// Sign-/zero-extensions
+parameter ALU_EXTS = 6'b111110;
+parameter ALU_EXT = 6'b111111;
+
+// Comparisons
+parameter ALU_LTS = 6'b000000;
+parameter ALU_LTU = 6'b000001;
+parameter ALU_LES = 6'b000100;
+parameter ALU_LEU = 6'b000101;
+parameter ALU_GTS = 6'b001000;
+parameter ALU_GTU = 6'b001001;
+parameter ALU_GES = 6'b001010;
+parameter ALU_GEU = 6'b001011;
+parameter ALU_EQ = 6'b001100;
+parameter ALU_NE = 6'b001101;
+
+// Set Lower Than operations
+parameter ALU_SLTS = 6'b000010;
+parameter ALU_SLTU = 6'b000011;
+parameter ALU_SLETS = 6'b000110;
+parameter ALU_SLETU = 6'b000111;
+
+// Absolute value
+parameter ALU_ABS = 6'b010100;
+parameter ALU_CLIP = 6'b010110;
+parameter ALU_CLIPU = 6'b010111;
+
+// Insert/extract
+parameter ALU_INS = 6'b101101;
+
+// min/max
+parameter ALU_MIN = 6'b010000;
+parameter ALU_MINU = 6'b010001;
+parameter ALU_MAX = 6'b010010;
+parameter ALU_MAXU = 6'b010011;
+
+// div/rem
+parameter ALU_DIVU = 6'b110000; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_DIV = 6'b110001; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REMU = 6'b110010; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REM = 6'b110011; // bit 0 is used for signed mode, bit 1 is used for remdiv
+
+parameter ALU_SHUF = 6'b111010;
+parameter ALU_SHUF2 = 6'b111011;
+parameter ALU_PCKLO = 6'b111000;
+parameter ALU_PCKHI = 6'b111001;
+
+
+parameter MD_OP_MULL = 2'b00;
+parameter MD_OP_MULH = 2'b01;
+parameter MD_OP_DIV = 2'b10;
+parameter MD_OP_REM = 2'b11;
+
+// vector modes
+parameter VEC_MODE32 = 2'b00;
+parameter VEC_MODE16 = 2'b10;
+parameter VEC_MODE8 = 2'b11;
+
+
+/////////////////////////////////////////////////////////
+// ____ ____ ____ _ _ //
+// / ___/ ___| | _ \ ___ __ _(_)___| |_ ___ _ __ //
+// | | \___ \ | |_) / _ \/ _` | / __| __/ _ \ '__| //
+// | |___ ___) | | _ < __/ (_| | \__ \ || __/ | //
+// \____|____/ |_| \_\___|\__, |_|___/\__\___|_| //
+// |___/ //
+/////////////////////////////////////////////////////////
+
+// CSR operations
+parameter CSR_OP_NONE = 2'b00;
+parameter CSR_OP_WRITE = 2'b01;
+parameter CSR_OP_SET = 2'b10;
+parameter CSR_OP_CLEAR = 2'b11;
+
+
+// SPR for debugger, not accessible by CPU
+parameter SP_DVR0 = 16'h3000;
+parameter SP_DCR0 = 16'h3008;
+parameter SP_DMR1 = 16'h3010;
+parameter SP_DMR2 = 16'h3011;
+
+parameter SP_DVR_MSB = 8'h00;
+parameter SP_DCR_MSB = 8'h01;
+parameter SP_DMR_MSB = 8'h02;
+parameter SP_DSR_MSB = 8'h04;
+
+// Privileged mode
+typedef enum logic[1:0] {
+ PRIV_LVL_M = 2'b11,
+ PRIV_LVL_H = 2'b10,
+ PRIV_LVL_S = 2'b01,
+ PRIV_LVL_U = 2'b00
+} PrivLvl_t;
+
+///////////////////////////////////////////////
+// ___ ____ ____ _ //
+// |_ _| _ \ / ___|| |_ __ _ __ _ ___ //
+// | || | | | \___ \| __/ _` |/ _` |/ _ \ //
+// | || |_| | ___) | || (_| | (_| | __/ //
+// |___|____/ |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// forwarding operand mux
+parameter SEL_REGFILE = 2'b00;
+parameter SEL_FW_EX = 2'b01;
+parameter SEL_FW_WB = 2'b10;
+parameter SEL_MISALIGNED = 2'b11;
+
+// operand a selection
+parameter OP_A_REGA_OR_FWD = 3'b000;
+parameter OP_A_CURRPC = 3'b001;
+parameter OP_A_IMM = 3'b010;
+parameter OP_A_REGB_OR_FWD = 3'b011;
+parameter OP_A_REGC_OR_FWD = 3'b100;
+
+// immediate a selection
+parameter IMMA_Z = 1'b0;
+parameter IMMA_ZERO = 1'b1;
+
+// operand b selection
+parameter OP_B_REGB_OR_FWD = 3'b000;
+parameter OP_B_REGC_OR_FWD = 3'b001;
+parameter OP_B_IMM = 3'b010;
+parameter OP_B_REGA_OR_FWD = 3'b011;
+parameter OP_B_BMASK = 3'b100;
+parameter OP_B_ZERO = 3'b101;
+
+// immediate b selection
+parameter IMMB_I = 4'b0000;
+parameter IMMB_S = 4'b0001;
+parameter IMMB_U = 4'b0010;
+parameter IMMB_PCINCR = 4'b0011;
+parameter IMMB_S2 = 4'b0100;
+parameter IMMB_S3 = 4'b0101;
+parameter IMMB_VS = 4'b0110;
+parameter IMMB_VU = 4'b0111;
+parameter IMMB_SHUF = 4'b1000;
+parameter IMMB_CLIP = 4'b1001;
+parameter IMMB_BI = 4'b1011;
+parameter IMMB_UJ = 4'b1100;
+parameter IMMB_SB = 4'b1101;
+
+// bit mask selection
+parameter BMASK_A_ZERO = 1'b0;
+parameter BMASK_A_S3 = 1'b1;
+
+parameter BMASK_B_S2 = 2'b00;
+parameter BMASK_B_S3 = 2'b01;
+parameter BMASK_B_ZERO = 2'b10;
+parameter BMASK_B_ONE = 2'b11;
+
+parameter BMASK_A_REG = 1'b0;
+parameter BMASK_A_IMM = 1'b1;
+parameter BMASK_B_REG = 1'b0;
+parameter BMASK_B_IMM = 1'b1;
+
+
+
+///////////////////////////////////////////////
+// ___ _____ ____ _ //
+// |_ _| ___| / ___|| |_ __ _ __ _ ___ //
+// | || |_ \___ \| __/ _` |/ _` |/ _ \ //
+// | || _| ___) | || (_| | (_| | __/ //
+// |___|_| |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// PC mux selector defines
+parameter PC_BOOT = 3'b000;
+parameter PC_JUMP = 3'b010;
+parameter PC_EXCEPTION = 3'b100;
+parameter PC_ERET = 3'b101;
+parameter PC_DBG_NPC = 3'b111;
+
+// Exception PC mux selector defines
+parameter EXC_PC_ILLINSN = 2'b00;
+parameter EXC_PC_ECALL = 2'b01;
+parameter EXC_PC_LOAD = 2'b10;
+parameter EXC_PC_STORE = 2'b10;
+parameter EXC_PC_IRQ = 2'b11;
+
+// Exception Cause
+parameter EXC_CAUSE_ILLEGAL_INSN = 6'h02;
+parameter EXC_CAUSE_BREAKPOINT = 6'h03;
+parameter EXC_CAUSE_ECALL_MMODE = 6'h0B;
+
+// Exceptions offsets
+// target address = {boot_addr[31:8], EXC_OFF} (boot_addr must be 32 BYTE aligned!)
+// offset 00 to 7e is used for external interrupts
+parameter EXC_OFF_RST = 8'h80;
+parameter EXC_OFF_ILLINSN = 8'h84;
+parameter EXC_OFF_ECALL = 8'h88;
+parameter EXC_OFF_LSUERR = 8'h8c;
+
+
+// Debug module
+parameter DBG_SETS_W = 6;
+
+parameter DBG_SETS_IRQ = 5;
+parameter DBG_SETS_ECALL = 4;
+parameter DBG_SETS_EILL = 3;
+parameter DBG_SETS_ELSU = 2;
+parameter DBG_SETS_EBRK = 1;
+parameter DBG_SETS_SSTE = 0;
+
+parameter DBG_CAUSE_HALT = 6'h1F;
+
+endpackage
diff --git a/verilog/rtl/ips/zero-riscy/include/zeroriscy_tracer_defines.sv b/verilog/rtl/ips/zero-riscy/include/zeroriscy_tracer_defines.sv
new file mode 100644
index 0000000..478f6ab
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/include/zeroriscy_tracer_defines.sv
@@ -0,0 +1,74 @@
+// Copyright 2017 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the “License”); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+package zeroriscy_tracer_defines;
+import zeroriscy_defines::*;
+
+// instruction masks (for tracer)
+// parameter INSTR_CUSTOM0 = { 25'b?, OPCODE_CUST0 };
+// parameter INSTR_CUSTOM1 = { 25'b?, OPCODE_CUST1 };
+parameter INSTR_LUI = { 25'b?, OPCODE_LUI };
+parameter INSTR_AUIPC = { 25'b?, OPCODE_AUIPC };
+parameter INSTR_JAL = { 25'b?, OPCODE_JAL };
+parameter INSTR_JALR = { 17'b?, 3'b000, 5'b?, OPCODE_JALR };
+// BRANCH
+parameter INSTR_BEQ = { 17'b?, 3'b000, 5'b?, OPCODE_BRANCH };
+parameter INSTR_BNE = { 17'b?, 3'b001, 5'b?, OPCODE_BRANCH };
+parameter INSTR_BLT = { 17'b?, 3'b100, 5'b?, OPCODE_BRANCH };
+parameter INSTR_BGE = { 17'b?, 3'b101, 5'b?, OPCODE_BRANCH };
+parameter INSTR_BLTU = { 17'b?, 3'b110, 5'b?, OPCODE_BRANCH };
+parameter INSTR_BGEU = { 17'b?, 3'b111, 5'b?, OPCODE_BRANCH };
+parameter INSTR_BALL = { 17'b?, 3'b010, 5'b?, OPCODE_BRANCH };
+// OPIMM
+parameter INSTR_ADDI = { 17'b?, 3'b000, 5'b?, OPCODE_OPIMM };
+parameter INSTR_SLTI = { 17'b?, 3'b010, 5'b?, OPCODE_OPIMM };
+parameter INSTR_SLTIU = { 17'b?, 3'b011, 5'b?, OPCODE_OPIMM };
+parameter INSTR_XORI = { 17'b?, 3'b100, 5'b?, OPCODE_OPIMM };
+parameter INSTR_ORI = { 17'b?, 3'b110, 5'b?, OPCODE_OPIMM };
+parameter INSTR_ANDI = { 17'b?, 3'b111, 5'b?, OPCODE_OPIMM };
+parameter INSTR_SLLI = { 7'b0000000, 10'b?, 3'b001, 5'b?, OPCODE_OPIMM };
+parameter INSTR_SRLI = { 7'b0000000, 10'b?, 3'b101, 5'b?, OPCODE_OPIMM };
+parameter INSTR_SRAI = { 7'b0100000, 10'b?, 3'b101, 5'b?, OPCODE_OPIMM };
+// OP
+parameter INSTR_ADD = { 7'b0000000, 10'b?, 3'b000, 5'b?, OPCODE_OP };
+parameter INSTR_SUB = { 7'b0100000, 10'b?, 3'b000, 5'b?, OPCODE_OP };
+parameter INSTR_SLL = { 7'b0000000, 10'b?, 3'b001, 5'b?, OPCODE_OP };
+parameter INSTR_SLT = { 7'b0000000, 10'b?, 3'b010, 5'b?, OPCODE_OP };
+parameter INSTR_SLTU = { 7'b0000000, 10'b?, 3'b011, 5'b?, OPCODE_OP };
+parameter INSTR_XOR = { 7'b0000000, 10'b?, 3'b100, 5'b?, OPCODE_OP };
+parameter INSTR_SRL = { 7'b0000000, 10'b?, 3'b101, 5'b?, OPCODE_OP };
+parameter INSTR_SRA = { 7'b0100000, 10'b?, 3'b101, 5'b?, OPCODE_OP };
+parameter INSTR_OR = { 7'b0000000, 10'b?, 3'b110, 5'b?, OPCODE_OP };
+parameter INSTR_AND = { 7'b0000000, 10'b?, 3'b111, 5'b?, OPCODE_OP };
+
+// SYSTEM
+parameter INSTR_CSRRW = { 17'b?, 3'b001, 5'b?, OPCODE_SYSTEM };
+parameter INSTR_CSRRS = { 17'b?, 3'b010, 5'b?, OPCODE_SYSTEM };
+parameter INSTR_CSRRC = { 17'b?, 3'b011, 5'b?, OPCODE_SYSTEM };
+parameter INSTR_CSRRWI = { 17'b?, 3'b101, 5'b?, OPCODE_SYSTEM };
+parameter INSTR_CSRRSI = { 17'b?, 3'b110, 5'b?, OPCODE_SYSTEM };
+parameter INSTR_CSRRCI = { 17'b?, 3'b111, 5'b?, OPCODE_SYSTEM };
+parameter INSTR_ECALL = { 12'b000000000000, 13'b0, OPCODE_SYSTEM };
+parameter INSTR_EBREAK = { 12'b000000000001, 13'b0, OPCODE_SYSTEM };
+parameter INSTR_MRET = { 12'b001100000010, 13'b0, OPCODE_SYSTEM };
+parameter INSTR_WFI = { 12'b000100000101, 13'b0, OPCODE_SYSTEM };
+
+// RV32M
+parameter INSTR_DIV = { 7'b0000001, 10'b?, 3'b100, 5'b?, OPCODE_OP };
+parameter INSTR_DIVU = { 7'b0000001, 10'b?, 3'b101, 5'b?, OPCODE_OP };
+parameter INSTR_REM = { 7'b0000001, 10'b?, 3'b110, 5'b?, OPCODE_OP };
+parameter INSTR_REMU = { 7'b0000001, 10'b?, 3'b111, 5'b?, OPCODE_OP };
+parameter INSTR_PMUL = { 7'b0000001, 10'b?, 3'b000, 5'b?, OPCODE_OP };
+parameter INSTR_PMUH = { 7'b0000001, 10'b?, 3'b001, 5'b?, OPCODE_OP };
+parameter INSTR_PMULHSU = { 7'b0000001, 10'b?, 3'b010, 5'b?, OPCODE_OP };
+parameter INSTR_PMULHU = { 7'b0000001, 10'b?, 3'b011, 5'b?, OPCODE_OP };
+
+
+endpackage
\ No newline at end of file
diff --git a/verilog/rtl/ips/zero-riscy/zeroriscy_alu.v b/verilog/rtl/ips/zero-riscy/zeroriscy_alu.v
new file mode 100644
index 0000000..5c94c24
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/zeroriscy_alu.v
@@ -0,0 +1,398 @@
+//`include "zeroriscy_defines.sv"
+
+module zeroriscy_alu (
+ operator_i,
+ operand_a_i,
+ operand_b_i,
+ multdiv_operand_a_i,
+ multdiv_operand_b_i,
+ multdiv_en_i,
+ adder_result_o,
+ adder_result_ext_o,
+ result_o,
+ comparison_result_o,
+ is_equal_result_o
+);
+parameter OPCODE_SYSTEM = 7'h73;
+parameter OPCODE_FENCE = 7'h0f;
+parameter OPCODE_OP = 7'h33;
+parameter OPCODE_OPIMM = 7'h13;
+parameter OPCODE_STORE = 7'h23;
+parameter OPCODE_LOAD = 7'h03;
+parameter OPCODE_BRANCH = 7'h63;
+parameter OPCODE_JALR = 7'h67;
+parameter OPCODE_JAL = 7'h6f;
+parameter OPCODE_AUIPC = 7'h17;
+parameter OPCODE_LUI = 7'h37;
+
+// those opcodes are now used for PULP custom instructions
+// parameter OPCODE_CUST0 = 7'h0b
+// parameter OPCODE_CUST1 = 7'h2b
+
+// PULP custom
+parameter OPCODE_LOAD_POST = 7'h0b;
+parameter OPCODE_STORE_POST = 7'h2b;
+parameter OPCODE_PULP_OP = 7'h5b;
+parameter OPCODE_VECOP = 7'h57;
+parameter OPCODE_HWLOOP = 7'h7b;
+
+parameter REGC_S1 = 2'b10;
+parameter REGC_RD = 2'b01;
+parameter REGC_ZERO = 2'b11;
+
+
+//////////////////////////////////////////////////////////////////////////////
+// _ _ _ _ ___ _ _ //
+// / \ | | | | | | / _ \ _ __ ___ _ __ __ _| |_(_) ___ _ __ ___ //
+// / _ \ | | | | | | | | | | '_ \ / _ \ '__/ _` | __| |/ _ \| '_ \/ __| //
+// / ___ \| |__| |_| | | |_| | |_) | __/ | | (_| | |_| | (_) | | | \__ \ //
+// /_/ \_\_____\___/ \___/| .__/ \___|_| \__,_|\__|_|\___/|_| |_|___/ //
+// |_| //
+//////////////////////////////////////////////////////////////////////////////
+
+parameter ALU_OP_WIDTH = 6;
+
+parameter ALU_ADD = 6'b011000;
+parameter ALU_SUB = 6'b011001;
+parameter ALU_ADDU = 6'b011010;
+parameter ALU_SUBU = 6'b011011;
+parameter ALU_ADDR = 6'b011100;
+parameter ALU_SUBR = 6'b011101;
+parameter ALU_ADDUR = 6'b011110;
+parameter ALU_SUBUR = 6'b011111;
+
+parameter ALU_XOR = 6'b101111;
+parameter ALU_OR = 6'b101110;
+parameter ALU_AND = 6'b010101;
+
+// Shifts
+parameter ALU_SRA = 6'b100100;
+parameter ALU_SRL = 6'b100101;
+parameter ALU_ROR = 6'b100110;
+parameter ALU_SLL = 6'b100111;
+
+// bit manipulation
+parameter ALU_BEXT = 6'b101000;
+parameter ALU_BEXTU = 6'b101001;
+parameter ALU_BINS = 6'b101010;
+parameter ALU_BCLR = 6'b101011;
+parameter ALU_BSET = 6'b101100;
+
+// Bit counting
+parameter ALU_FF1 = 6'b110110;
+parameter ALU_FL1 = 6'b110111;
+parameter ALU_CNT = 6'b110100;
+parameter ALU_CLB = 6'b110101;
+
+// Sign-/zero-extensions
+parameter ALU_EXTS = 6'b111110;
+parameter ALU_EXT = 6'b111111;
+
+// Comparisons
+parameter ALU_LTS = 6'b000000;
+parameter ALU_LTU = 6'b000001;
+parameter ALU_LES = 6'b000100;
+parameter ALU_LEU = 6'b000101;
+parameter ALU_GTS = 6'b001000;
+parameter ALU_GTU = 6'b001001;
+parameter ALU_GES = 6'b001010;
+parameter ALU_GEU = 6'b001011;
+parameter ALU_EQ = 6'b001100;
+parameter ALU_NE = 6'b001101;
+
+// Set Lower Than operations
+parameter ALU_SLTS = 6'b000010;
+parameter ALU_SLTU = 6'b000011;
+parameter ALU_SLETS = 6'b000110;
+parameter ALU_SLETU = 6'b000111;
+
+// Absolute value
+parameter ALU_ABS = 6'b010100;
+parameter ALU_CLIP = 6'b010110;
+parameter ALU_CLIPU = 6'b010111;
+
+// Insert/extract
+parameter ALU_INS = 6'b101101;
+
+// min/max
+parameter ALU_MIN = 6'b010000;
+parameter ALU_MINU = 6'b010001;
+parameter ALU_MAX = 6'b010010;
+parameter ALU_MAXU = 6'b010011;
+
+// div/rem
+parameter ALU_DIVU = 6'b110000; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_DIV = 6'b110001; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REMU = 6'b110010; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REM = 6'b110011; // bit 0 is used for signed mode, bit 1 is used for remdiv
+
+parameter ALU_SHUF = 6'b111010;
+parameter ALU_SHUF2 = 6'b111011;
+parameter ALU_PCKLO = 6'b111000;
+parameter ALU_PCKHI = 6'b111001;
+
+
+parameter MD_OP_MULL = 2'b00;
+parameter MD_OP_MULH = 2'b01;
+parameter MD_OP_DIV = 2'b10;
+parameter MD_OP_REM = 2'b11;
+
+// vector modes
+parameter VEC_MODE32 = 2'b00;
+parameter VEC_MODE16 = 2'b10;
+parameter VEC_MODE8 = 2'b11;
+
+
+/////////////////////////////////////////////////////////
+// ____ ____ ____ _ _ //
+// / ___/ ___| | _ \ ___ __ _(_)___| |_ ___ _ __ //
+// | | \___ \ | |_) / _ \/ _` | / __| __/ _ \ '__| //
+// | |___ ___) | | _ < __/ (_| | \__ \ || __/ | //
+// \____|____/ |_| \_\___|\__, |_|___/\__\___|_| //
+// |___/ //
+/////////////////////////////////////////////////////////
+
+// CSR operations
+parameter CSR_OP_NONE = 2'b00;
+parameter CSR_OP_WRITE = 2'b01;
+parameter CSR_OP_SET = 2'b10;
+parameter CSR_OP_CLEAR = 2'b11;
+
+
+// SPR for debugger, not accessible by CPU
+parameter SP_DVR0 = 16'h3000;
+parameter SP_DCR0 = 16'h3008;
+parameter SP_DMR1 = 16'h3010;
+parameter SP_DMR2 = 16'h3011;
+
+parameter SP_DVR_MSB = 8'h00;
+parameter SP_DCR_MSB = 8'h01;
+parameter SP_DMR_MSB = 8'h02;
+parameter SP_DSR_MSB = 8'h04;
+
+// Privileged mode
+typedef enum logic[1:0] {
+ PRIV_LVL_M = 2'b11,
+ PRIV_LVL_H = 2'b10,
+ PRIV_LVL_S = 2'b01,
+ PRIV_LVL_U = 2'b00
+} PrivLvl_t;
+
+///////////////////////////////////////////////
+// ___ ____ ____ _ //
+// |_ _| _ \ / ___|| |_ __ _ __ _ ___ //
+// | || | | | \___ \| __/ _` |/ _` |/ _ \ //
+// | || |_| | ___) | || (_| | (_| | __/ //
+// |___|____/ |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// forwarding operand mux
+parameter SEL_REGFILE = 2'b00;
+parameter SEL_FW_EX = 2'b01;
+parameter SEL_FW_WB = 2'b10;
+parameter SEL_MISALIGNED = 2'b11;
+
+// operand a selection
+parameter OP_A_REGA_OR_FWD = 3'b000;
+parameter OP_A_CURRPC = 3'b001;
+parameter OP_A_IMM = 3'b010;
+parameter OP_A_REGB_OR_FWD = 3'b011;
+parameter OP_A_REGC_OR_FWD = 3'b100;
+
+// immediate a selection
+parameter IMMA_Z = 1'b0;
+parameter IMMA_ZERO = 1'b1;
+
+// operand b selection
+parameter OP_B_REGB_OR_FWD = 3'b000;
+parameter OP_B_REGC_OR_FWD = 3'b001;
+parameter OP_B_IMM = 3'b010;
+parameter OP_B_REGA_OR_FWD = 3'b011;
+parameter OP_B_BMASK = 3'b100;
+parameter OP_B_ZERO = 3'b101;
+
+// immediate b selection
+parameter IMMB_I = 4'b0000;
+parameter IMMB_S = 4'b0001;
+parameter IMMB_U = 4'b0010;
+parameter IMMB_PCINCR = 4'b0011;
+parameter IMMB_S2 = 4'b0100;
+parameter IMMB_S3 = 4'b0101;
+parameter IMMB_VS = 4'b0110;
+parameter IMMB_VU = 4'b0111;
+parameter IMMB_SHUF = 4'b1000;
+parameter IMMB_CLIP = 4'b1001;
+parameter IMMB_BI = 4'b1011;
+parameter IMMB_UJ = 4'b1100;
+parameter IMMB_SB = 4'b1101;
+
+// bit mask selection
+parameter BMASK_A_ZERO = 1'b0;
+parameter BMASK_A_S3 = 1'b1;
+
+parameter BMASK_B_S2 = 2'b00;
+parameter BMASK_B_S3 = 2'b01;
+parameter BMASK_B_ZERO = 2'b10;
+parameter BMASK_B_ONE = 2'b11;
+
+parameter BMASK_A_REG = 1'b0;
+parameter BMASK_A_IMM = 1'b1;
+parameter BMASK_B_REG = 1'b0;
+parameter BMASK_B_IMM = 1'b1;
+
+
+
+///////////////////////////////////////////////
+// ___ _____ ____ _ //
+// |_ _| ___| / ___|| |_ __ _ __ _ ___ //
+// | || |_ \___ \| __/ _` |/ _` |/ _ \ //
+// | || _| ___) | || (_| | (_| | __/ //
+// |___|_| |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// PC mux selector defines
+parameter PC_BOOT = 3'b000;
+parameter PC_JUMP = 3'b010;
+parameter PC_EXCEPTION = 3'b100;
+parameter PC_ERET = 3'b101;
+parameter PC_DBG_NPC = 3'b111;
+
+// Exception PC mux selector defines
+parameter EXC_PC_ILLINSN = 2'b00;
+parameter EXC_PC_ECALL = 2'b01;
+parameter EXC_PC_LOAD = 2'b10;
+parameter EXC_PC_STORE = 2'b10;
+parameter EXC_PC_IRQ = 2'b11;
+
+// Exception Cause
+parameter EXC_CAUSE_ILLEGAL_INSN = 6'h02;
+parameter EXC_CAUSE_BREAKPOINT = 6'h03;
+parameter EXC_CAUSE_ECALL_MMODE = 6'h0B;
+
+// Exceptions offsets
+// target address = {boot_addr[31:8], EXC_OFF} (boot_addr must be 32 BYTE aligned!)
+// offset 00 to 7e is used for external interrupts
+parameter EXC_OFF_RST = 8'h80;
+parameter EXC_OFF_ILLINSN = 8'h84;
+parameter EXC_OFF_ECALL = 8'h88;
+parameter EXC_OFF_LSUERR = 8'h8c;
+
+
+// Debug module
+parameter DBG_SETS_W = 6;
+
+parameter DBG_SETS_IRQ = 5;
+parameter DBG_SETS_ECALL = 4;
+parameter DBG_SETS_EILL = 3;
+parameter DBG_SETS_ELSU = 2;
+parameter DBG_SETS_EBRK = 1;
+parameter DBG_SETS_SSTE = 0;
+
+parameter DBG_CAUSE_HALT = 6'h1F;
+ input wire [ALU_OP_WIDTH - 1:0] operator_i;
+ input wire [31:0] operand_a_i;
+ input wire [31:0] operand_b_i;
+ input wire [32:0] multdiv_operand_a_i;
+ input wire [32:0] multdiv_operand_b_i;
+ input wire multdiv_en_i;
+ output wire [31:0] adder_result_o;
+ output wire [33:0] adder_result_ext_o;
+ output reg [31:0] result_o;
+ output wire comparison_result_o;
+ output wire is_equal_result_o;
+ wire [31:0] operand_a_rev;
+ wire [32:0] operand_b_neg;
+ genvar k;
+ generate
+ for (k = 0; k < 32; k = k + 1) begin : g_revloop
+ assign operand_a_rev[k] = operand_a_i[31 - k];
+ end
+ endgenerate
+ reg adder_op_b_negate;
+ wire [32:0] adder_in_a;
+ wire [32:0] adder_in_b;
+ wire [31:0] adder_result;
+ always @(*) begin
+ adder_op_b_negate = 1'b0;
+ case (operator_i)
+ ALU_SUB, ALU_EQ, ALU_NE, ALU_GTU, ALU_GEU, ALU_LTU, ALU_LEU, ALU_GTS, ALU_GES, ALU_LTS, ALU_LES, ALU_SLTS, ALU_SLTU, ALU_SLETS, ALU_SLETU: adder_op_b_negate = 1'b1;
+ default:
+ ;
+ endcase
+ end
+ assign adder_in_a = (multdiv_en_i ? multdiv_operand_a_i : {operand_a_i, 1'b1});
+ assign operand_b_neg = {operand_b_i, 1'b0} ^ {33 {adder_op_b_negate}};
+ assign adder_in_b = (multdiv_en_i ? multdiv_operand_b_i : operand_b_neg);
+ assign adder_result_ext_o = $unsigned(adder_in_a) + $unsigned(adder_in_b);
+ assign adder_result = adder_result_ext_o[32:1];
+ assign adder_result_o = adder_result;
+ wire shift_left;
+ wire shift_arithmetic;
+ wire [31:0] shift_amt;
+ wire [31:0] shift_op_a;
+ wire [31:0] shift_result;
+ wire [31:0] shift_right_result;
+ wire [31:0] shift_left_result;
+ assign shift_amt = operand_b_i;
+ assign shift_left = operator_i == ALU_SLL;
+ assign shift_arithmetic = operator_i == ALU_SRA;
+ assign shift_op_a = (shift_left ? operand_a_rev : operand_a_i);
+ wire [32:0] shift_op_a_32;
+ assign shift_op_a_32 = {shift_arithmetic & shift_op_a[31], shift_op_a};
+ assign shift_right_result = $signed(shift_op_a_32) >>> shift_amt[4:0];
+ genvar j;
+ generate
+ for (j = 0; j < 32; j = j + 1) begin : g_resrevloop
+ assign shift_left_result[j] = shift_right_result[31 - j];
+ end
+ endgenerate
+ assign shift_result = (shift_left ? shift_left_result : shift_right_result);
+ wire is_equal;
+ reg is_greater_equal;
+ reg cmp_signed;
+ always @(*) begin
+ cmp_signed = 1'b0;
+ case (operator_i)
+ ALU_GTS, ALU_GES, ALU_LTS, ALU_LES, ALU_SLTS, ALU_SLETS: cmp_signed = 1'b1;
+ default:
+ ;
+ endcase
+ end
+ assign is_equal = adder_result == 32'b00000000000000000000000000000000;
+ assign is_equal_result_o = is_equal;
+ always @(*)
+ if ((operand_a_i[31] ^ operand_b_i[31]) == 0)
+ is_greater_equal = adder_result[31] == 0;
+ else
+ is_greater_equal = operand_a_i[31] ^ cmp_signed;
+ reg cmp_result;
+ always @(*) begin
+ cmp_result = is_equal;
+ case (operator_i)
+ ALU_EQ: cmp_result = is_equal;
+ ALU_NE: cmp_result = ~is_equal;
+ ALU_GTS, ALU_GTU: cmp_result = is_greater_equal && ~is_equal;
+ ALU_GES, ALU_GEU: cmp_result = is_greater_equal;
+ ALU_LTS, ALU_SLTS, ALU_LTU, ALU_SLTU: cmp_result = ~is_greater_equal;
+ ALU_SLETS, ALU_SLETU, ALU_LES, ALU_LEU: cmp_result = ~is_greater_equal || is_equal;
+ default:
+ ;
+ endcase
+ end
+ assign comparison_result_o = cmp_result;
+ always @(*) begin
+ result_o = 1'sb0;
+ case (operator_i)
+ ALU_AND: result_o = operand_a_i & operand_b_i;
+ ALU_OR: result_o = operand_a_i | operand_b_i;
+ ALU_XOR: result_o = operand_a_i ^ operand_b_i;
+ ALU_ADD, ALU_SUB: result_o = adder_result;
+ ALU_SLL, ALU_SRL, ALU_SRA: result_o = shift_result;
+ ALU_EQ, ALU_NE, ALU_GTU, ALU_GEU, ALU_LTU, ALU_LEU, ALU_GTS, ALU_GES, ALU_LTS, ALU_LES, ALU_SLTS, ALU_SLTU, ALU_SLETS, ALU_SLETU: result_o = cmp_result;
+ default:
+ ;
+ endcase
+ end
+endmodule
diff --git a/verilog/rtl/ips/zero-riscy/zeroriscy_compressed_decoder.v b/verilog/rtl/ips/zero-riscy/zeroriscy_compressed_decoder.v
new file mode 100644
index 0000000..e41c611
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/zeroriscy_compressed_decoder.v
@@ -0,0 +1,381 @@
+module zeroriscy_compressed_decoder (
+ instr_i,
+ instr_o,
+ is_compressed_o,
+ illegal_instr_o
+);
+parameter OPCODE_SYSTEM = 7'h73;
+parameter OPCODE_FENCE = 7'h0f;
+parameter OPCODE_OP = 7'h33;
+parameter OPCODE_OPIMM = 7'h13;
+parameter OPCODE_STORE = 7'h23;
+parameter OPCODE_LOAD = 7'h03;
+parameter OPCODE_BRANCH = 7'h63;
+parameter OPCODE_JALR = 7'h67;
+parameter OPCODE_JAL = 7'h6f;
+parameter OPCODE_AUIPC = 7'h17;
+parameter OPCODE_LUI = 7'h37;
+
+// those opcodes are now used for PULP custom instructions
+// parameter OPCODE_CUST0 = 7'h0b
+// parameter OPCODE_CUST1 = 7'h2b
+
+// PULP custom
+parameter OPCODE_LOAD_POST = 7'h0b;
+parameter OPCODE_STORE_POST = 7'h2b;
+parameter OPCODE_PULP_OP = 7'h5b;
+parameter OPCODE_VECOP = 7'h57;
+parameter OPCODE_HWLOOP = 7'h7b;
+
+parameter REGC_S1 = 2'b10;
+parameter REGC_RD = 2'b01;
+parameter REGC_ZERO = 2'b11;
+
+
+//////////////////////////////////////////////////////////////////////////////
+// _ _ _ _ ___ _ _ //
+// / \ | | | | | | / _ \ _ __ ___ _ __ __ _| |_(_) ___ _ __ ___ //
+// / _ \ | | | | | | | | | | '_ \ / _ \ '__/ _` | __| |/ _ \| '_ \/ __| //
+// / ___ \| |__| |_| | | |_| | |_) | __/ | | (_| | |_| | (_) | | | \__ \ //
+// /_/ \_\_____\___/ \___/| .__/ \___|_| \__,_|\__|_|\___/|_| |_|___/ //
+// |_| //
+//////////////////////////////////////////////////////////////////////////////
+
+parameter ALU_OP_WIDTH = 6;
+
+parameter ALU_ADD = 6'b011000;
+parameter ALU_SUB = 6'b011001;
+parameter ALU_ADDU = 6'b011010;
+parameter ALU_SUBU = 6'b011011;
+parameter ALU_ADDR = 6'b011100;
+parameter ALU_SUBR = 6'b011101;
+parameter ALU_ADDUR = 6'b011110;
+parameter ALU_SUBUR = 6'b011111;
+
+parameter ALU_XOR = 6'b101111;
+parameter ALU_OR = 6'b101110;
+parameter ALU_AND = 6'b010101;
+
+// Shifts
+parameter ALU_SRA = 6'b100100;
+parameter ALU_SRL = 6'b100101;
+parameter ALU_ROR = 6'b100110;
+parameter ALU_SLL = 6'b100111;
+
+// bit manipulation
+parameter ALU_BEXT = 6'b101000;
+parameter ALU_BEXTU = 6'b101001;
+parameter ALU_BINS = 6'b101010;
+parameter ALU_BCLR = 6'b101011;
+parameter ALU_BSET = 6'b101100;
+
+// Bit counting
+parameter ALU_FF1 = 6'b110110;
+parameter ALU_FL1 = 6'b110111;
+parameter ALU_CNT = 6'b110100;
+parameter ALU_CLB = 6'b110101;
+
+// Sign-/zero-extensions
+parameter ALU_EXTS = 6'b111110;
+parameter ALU_EXT = 6'b111111;
+
+// Comparisons
+parameter ALU_LTS = 6'b000000;
+parameter ALU_LTU = 6'b000001;
+parameter ALU_LES = 6'b000100;
+parameter ALU_LEU = 6'b000101;
+parameter ALU_GTS = 6'b001000;
+parameter ALU_GTU = 6'b001001;
+parameter ALU_GES = 6'b001010;
+parameter ALU_GEU = 6'b001011;
+parameter ALU_EQ = 6'b001100;
+parameter ALU_NE = 6'b001101;
+
+// Set Lower Than operations
+parameter ALU_SLTS = 6'b000010;
+parameter ALU_SLTU = 6'b000011;
+parameter ALU_SLETS = 6'b000110;
+parameter ALU_SLETU = 6'b000111;
+
+// Absolute value
+parameter ALU_ABS = 6'b010100;
+parameter ALU_CLIP = 6'b010110;
+parameter ALU_CLIPU = 6'b010111;
+
+// Insert/extract
+parameter ALU_INS = 6'b101101;
+
+// min/max
+parameter ALU_MIN = 6'b010000;
+parameter ALU_MINU = 6'b010001;
+parameter ALU_MAX = 6'b010010;
+parameter ALU_MAXU = 6'b010011;
+
+// div/rem
+parameter ALU_DIVU = 6'b110000; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_DIV = 6'b110001; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REMU = 6'b110010; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REM = 6'b110011; // bit 0 is used for signed mode, bit 1 is used for remdiv
+
+parameter ALU_SHUF = 6'b111010;
+parameter ALU_SHUF2 = 6'b111011;
+parameter ALU_PCKLO = 6'b111000;
+parameter ALU_PCKHI = 6'b111001;
+
+
+parameter MD_OP_MULL = 2'b00;
+parameter MD_OP_MULH = 2'b01;
+parameter MD_OP_DIV = 2'b10;
+parameter MD_OP_REM = 2'b11;
+
+// vector modes
+parameter VEC_MODE32 = 2'b00;
+parameter VEC_MODE16 = 2'b10;
+parameter VEC_MODE8 = 2'b11;
+
+
+/////////////////////////////////////////////////////////
+// ____ ____ ____ _ _ //
+// / ___/ ___| | _ \ ___ __ _(_)___| |_ ___ _ __ //
+// | | \___ \ | |_) / _ \/ _` | / __| __/ _ \ '__| //
+// | |___ ___) | | _ < __/ (_| | \__ \ || __/ | //
+// \____|____/ |_| \_\___|\__, |_|___/\__\___|_| //
+// |___/ //
+/////////////////////////////////////////////////////////
+
+// CSR operations
+parameter CSR_OP_NONE = 2'b00;
+parameter CSR_OP_WRITE = 2'b01;
+parameter CSR_OP_SET = 2'b10;
+parameter CSR_OP_CLEAR = 2'b11;
+
+
+// SPR for debugger, not accessible by CPU
+parameter SP_DVR0 = 16'h3000;
+parameter SP_DCR0 = 16'h3008;
+parameter SP_DMR1 = 16'h3010;
+parameter SP_DMR2 = 16'h3011;
+
+parameter SP_DVR_MSB = 8'h00;
+parameter SP_DCR_MSB = 8'h01;
+parameter SP_DMR_MSB = 8'h02;
+parameter SP_DSR_MSB = 8'h04;
+
+// Privileged mode
+typedef enum logic[1:0] {
+ PRIV_LVL_M = 2'b11,
+ PRIV_LVL_H = 2'b10,
+ PRIV_LVL_S = 2'b01,
+ PRIV_LVL_U = 2'b00
+} PrivLvl_t;
+
+///////////////////////////////////////////////
+// ___ ____ ____ _ //
+// |_ _| _ \ / ___|| |_ __ _ __ _ ___ //
+// | || | | | \___ \| __/ _` |/ _` |/ _ \ //
+// | || |_| | ___) | || (_| | (_| | __/ //
+// |___|____/ |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// forwarding operand mux
+parameter SEL_REGFILE = 2'b00;
+parameter SEL_FW_EX = 2'b01;
+parameter SEL_FW_WB = 2'b10;
+parameter SEL_MISALIGNED = 2'b11;
+
+// operand a selection
+parameter OP_A_REGA_OR_FWD = 3'b000;
+parameter OP_A_CURRPC = 3'b001;
+parameter OP_A_IMM = 3'b010;
+parameter OP_A_REGB_OR_FWD = 3'b011;
+parameter OP_A_REGC_OR_FWD = 3'b100;
+
+// immediate a selection
+parameter IMMA_Z = 1'b0;
+parameter IMMA_ZERO = 1'b1;
+
+// operand b selection
+parameter OP_B_REGB_OR_FWD = 3'b000;
+parameter OP_B_REGC_OR_FWD = 3'b001;
+parameter OP_B_IMM = 3'b010;
+parameter OP_B_REGA_OR_FWD = 3'b011;
+parameter OP_B_BMASK = 3'b100;
+parameter OP_B_ZERO = 3'b101;
+
+// immediate b selection
+parameter IMMB_I = 4'b0000;
+parameter IMMB_S = 4'b0001;
+parameter IMMB_U = 4'b0010;
+parameter IMMB_PCINCR = 4'b0011;
+parameter IMMB_S2 = 4'b0100;
+parameter IMMB_S3 = 4'b0101;
+parameter IMMB_VS = 4'b0110;
+parameter IMMB_VU = 4'b0111;
+parameter IMMB_SHUF = 4'b1000;
+parameter IMMB_CLIP = 4'b1001;
+parameter IMMB_BI = 4'b1011;
+parameter IMMB_UJ = 4'b1100;
+parameter IMMB_SB = 4'b1101;
+
+// bit mask selection
+parameter BMASK_A_ZERO = 1'b0;
+parameter BMASK_A_S3 = 1'b1;
+
+parameter BMASK_B_S2 = 2'b00;
+parameter BMASK_B_S3 = 2'b01;
+parameter BMASK_B_ZERO = 2'b10;
+parameter BMASK_B_ONE = 2'b11;
+
+parameter BMASK_A_REG = 1'b0;
+parameter BMASK_A_IMM = 1'b1;
+parameter BMASK_B_REG = 1'b0;
+parameter BMASK_B_IMM = 1'b1;
+
+
+
+///////////////////////////////////////////////
+// ___ _____ ____ _ //
+// |_ _| ___| / ___|| |_ __ _ __ _ ___ //
+// | || |_ \___ \| __/ _` |/ _` |/ _ \ //
+// | || _| ___) | || (_| | (_| | __/ //
+// |___|_| |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// PC mux selector defines
+parameter PC_BOOT = 3'b000;
+parameter PC_JUMP = 3'b010;
+parameter PC_EXCEPTION = 3'b100;
+parameter PC_ERET = 3'b101;
+parameter PC_DBG_NPC = 3'b111;
+
+// Exception PC mux selector defines
+parameter EXC_PC_ILLINSN = 2'b00;
+parameter EXC_PC_ECALL = 2'b01;
+parameter EXC_PC_LOAD = 2'b10;
+parameter EXC_PC_STORE = 2'b10;
+parameter EXC_PC_IRQ = 2'b11;
+
+// Exception Cause
+parameter EXC_CAUSE_ILLEGAL_INSN = 6'h02;
+parameter EXC_CAUSE_BREAKPOINT = 6'h03;
+parameter EXC_CAUSE_ECALL_MMODE = 6'h0B;
+
+// Exceptions offsets
+// target address = {boot_addr[31:8], EXC_OFF} (boot_addr must be 32 BYTE aligned!)
+// offset 00 to 7e is used for external interrupts
+parameter EXC_OFF_RST = 8'h80;
+parameter EXC_OFF_ILLINSN = 8'h84;
+parameter EXC_OFF_ECALL = 8'h88;
+parameter EXC_OFF_LSUERR = 8'h8c;
+
+
+// Debug module
+parameter DBG_SETS_W = 6;
+
+parameter DBG_SETS_IRQ = 5;
+parameter DBG_SETS_ECALL = 4;
+parameter DBG_SETS_EILL = 3;
+parameter DBG_SETS_ELSU = 2;
+parameter DBG_SETS_EBRK = 1;
+parameter DBG_SETS_SSTE = 0;
+
+parameter DBG_CAUSE_HALT = 6'h1F;
+ input wire [31:0] instr_i;
+ output reg [31:0] instr_o;
+ output wire is_compressed_o;
+ output reg illegal_instr_o;
+ always @(*) begin
+ illegal_instr_o = 1'b0;
+ instr_o = 1'sb0;
+ case (instr_i[1:0])
+ 2'b00:
+ case (instr_i[15:13])
+ 3'b000: begin
+ instr_o = {2'b00, instr_i[10:7], instr_i[12:11], instr_i[5], instr_i[6], 2'b00, 5'h02, 3'b000, 2'b01, instr_i[4:2], OPCODE_OPIMM};
+ if (instr_i[12:5] == 8'b00000000)
+ illegal_instr_o = 1'b1;
+ end
+ 3'b010: instr_o = {5'b00000, instr_i[5], instr_i[12:10], instr_i[6], 2'b00, 2'b01, instr_i[9:7], 3'b010, 2'b01, instr_i[4:2], OPCODE_LOAD};
+ 3'b110: instr_o = {5'b00000, instr_i[5], instr_i[12], 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b010, instr_i[11:10], instr_i[6], 2'b00, OPCODE_STORE};
+ default: illegal_instr_o = 1'b1;
+ endcase
+ 2'b01:
+ case (instr_i[15:13])
+ 3'b000: instr_o = {{6 {instr_i[12]}}, instr_i[12], instr_i[6:2], instr_i[11:7], 3'b000, instr_i[11:7], OPCODE_OPIMM};
+ 3'b001, 3'b101: instr_o = {instr_i[12], instr_i[8], instr_i[10:9], instr_i[6], instr_i[7], instr_i[2], instr_i[11], instr_i[5:3], {9 {instr_i[12]}}, 4'b0000, ~instr_i[15], OPCODE_JAL};
+ 3'b010: begin
+ instr_o = {{6 {instr_i[12]}}, instr_i[12], instr_i[6:2], 5'b00000, 3'b000, instr_i[11:7], OPCODE_OPIMM};
+ if (instr_i[11:7] == 5'b00000)
+ illegal_instr_o = 1'b1;
+ end
+ 3'b011: begin
+ instr_o = {{15 {instr_i[12]}}, instr_i[6:2], instr_i[11:7], OPCODE_LUI};
+ if (instr_i[11:7] == 5'h02)
+ instr_o = {{3 {instr_i[12]}}, instr_i[4:3], instr_i[5], instr_i[2], instr_i[6], 4'b0000, 5'h02, 3'b000, 5'h02, OPCODE_OPIMM};
+ else if (instr_i[11:7] == 5'b00000)
+ illegal_instr_o = 1'b1;
+ if ({instr_i[12], instr_i[6:2]} == 6'b000000)
+ illegal_instr_o = 1'b1;
+ end
+ 3'b100:
+ case (instr_i[11:10])
+ 2'b00, 2'b01: begin
+ instr_o = {1'b0, instr_i[10], 5'b00000, instr_i[6:2], 2'b01, instr_i[9:7], 3'b101, 2'b01, instr_i[9:7], OPCODE_OPIMM};
+ if (instr_i[12] == 1'b1)
+ illegal_instr_o = 1'b1;
+ if (instr_i[6:2] == 5'b00000)
+ illegal_instr_o = 1'b1;
+ end
+ 2'b10: instr_o = {{6 {instr_i[12]}}, instr_i[12], instr_i[6:2], 2'b01, instr_i[9:7], 3'b111, 2'b01, instr_i[9:7], OPCODE_OPIMM};
+ 2'b11:
+ case ({instr_i[12], instr_i[6:5]})
+ 3'b000: instr_o = {9'b010000001, instr_i[4:2], 2'b01, instr_i[9:7], 3'b000, 2'b01, instr_i[9:7], OPCODE_OP};
+ 3'b001: instr_o = {9'b000000001, instr_i[4:2], 2'b01, instr_i[9:7], 3'b100, 2'b01, instr_i[9:7], OPCODE_OP};
+ 3'b010: instr_o = {9'b000000001, instr_i[4:2], 2'b01, instr_i[9:7], 3'b110, 2'b01, instr_i[9:7], OPCODE_OP};
+ 3'b011: instr_o = {9'b000000001, instr_i[4:2], 2'b01, instr_i[9:7], 3'b111, 2'b01, instr_i[9:7], OPCODE_OP};
+ 3'b100, 3'b101, 3'b110, 3'b111: illegal_instr_o = 1'b1;
+ endcase
+ endcase
+ 3'b110, 3'b111: instr_o = {{4 {instr_i[12]}}, instr_i[6:5], instr_i[2], 5'b00000, 2'b01, instr_i[9:7], 2'b00, instr_i[13], instr_i[11:10], instr_i[4:3], instr_i[12], OPCODE_BRANCH};
+ default: illegal_instr_o = 1'b1;
+ endcase
+ 2'b10:
+ case (instr_i[15:13])
+ 3'b000: begin
+ instr_o = {7'b0000000, instr_i[6:2], instr_i[11:7], 3'b001, instr_i[11:7], OPCODE_OPIMM};
+ if (instr_i[11:7] == 5'b00000)
+ illegal_instr_o = 1'b1;
+ if ((instr_i[12] == 1'b1) || (instr_i[6:2] == 5'b00000))
+ illegal_instr_o = 1'b1;
+ end
+ 3'b010: begin
+ instr_o = {4'b0000, instr_i[3:2], instr_i[12], instr_i[6:4], 2'b00, 5'h02, 3'b010, instr_i[11:7], OPCODE_LOAD};
+ if (instr_i[11:7] == 5'b00000)
+ illegal_instr_o = 1'b1;
+ end
+ 3'b100:
+ if (instr_i[12] == 1'b0) begin
+ instr_o = {7'b0000000, instr_i[6:2], 5'b00000, 3'b000, instr_i[11:7], OPCODE_OP};
+ if (instr_i[6:2] == 5'b00000)
+ instr_o = {12'b000000000000, instr_i[11:7], 3'b000, 5'b00000, OPCODE_JALR};
+ end
+ else begin
+ instr_o = {7'b0000000, instr_i[6:2], instr_i[11:7], 3'b000, instr_i[11:7], OPCODE_OP};
+ if (instr_i[11:7] == 5'b00000) begin
+ instr_o = 32'h00100073;
+ if (instr_i[6:2] != 5'b00000)
+ illegal_instr_o = 1'b1;
+ end
+ else if (instr_i[6:2] == 5'b00000)
+ instr_o = {12'b000000000000, instr_i[11:7], 3'b000, 5'b00001, OPCODE_JALR};
+ end
+ 3'b110: instr_o = {4'b0000, instr_i[8:7], instr_i[12], instr_i[6:2], 5'h02, 3'b010, instr_i[11:9], 2'b00, OPCODE_STORE};
+ default: illegal_instr_o = 1'b1;
+ endcase
+ default: instr_o = instr_i;
+ endcase
+ end
+ assign is_compressed_o = instr_i[1:0] != 2'b11;
+endmodule
diff --git a/verilog/rtl/ips/zero-riscy/zeroriscy_controller.v b/verilog/rtl/ips/zero-riscy/zeroriscy_controller.v
new file mode 100644
index 0000000..2e8ef88
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/zeroriscy_controller.v
@@ -0,0 +1,621 @@
+module zeroriscy_controller
+#(
+ parameter REG_ADDR_WIDTH = 5
+)
+(
+ clk,
+ rst_n,
+ fetch_enable_i,
+ ctrl_busy_o,
+ first_fetch_o,
+ is_decoding_o,
+ deassert_we_o,
+ illegal_insn_i,
+ ecall_insn_i,
+ mret_insn_i,
+ pipe_flush_i,
+ ebrk_insn_i,
+ csr_status_i,
+ instr_valid_i,
+ instr_req_o,
+ pc_set_o,
+ pc_mux_o,
+ exc_pc_mux_o,
+ data_misaligned_i,
+ branch_in_id_i,
+ branch_taken_ex_i,
+ branch_set_i,
+ jump_set_i,
+ instr_multicyle_i,
+ irq_req_ctrl_i,
+ irq_id_ctrl_i,
+ m_IE_i,
+ irq_ack_o,
+ irq_id_o,
+ exc_cause_o,
+ exc_ack_o,
+ exc_kill_o,
+ csr_save_if_o,
+ csr_save_id_o,
+ csr_cause_o,
+ csr_restore_mret_id_o,
+ csr_save_cause_o,
+ dbg_req_i,
+ dbg_ack_o,
+ dbg_stall_i,
+ dbg_jump_req_i,
+ dbg_settings_i,
+ dbg_trap_o,
+ operand_a_fw_mux_sel_o,
+ halt_if_o,
+ halt_id_o,
+ id_ready_i,
+ perf_jump_o,
+ perf_tbranch_o
+);
+parameter OPCODE_SYSTEM = 7'h73;
+parameter OPCODE_FENCE = 7'h0f;
+parameter OPCODE_OP = 7'h33;
+parameter OPCODE_OPIMM = 7'h13;
+parameter OPCODE_STORE = 7'h23;
+parameter OPCODE_LOAD = 7'h03;
+parameter OPCODE_BRANCH = 7'h63;
+parameter OPCODE_JALR = 7'h67;
+parameter OPCODE_JAL = 7'h6f;
+parameter OPCODE_AUIPC = 7'h17;
+parameter OPCODE_LUI = 7'h37;
+
+// those opcodes are now used for PULP custom instructions
+// parameter OPCODE_CUST0 = 7'h0b
+// parameter OPCODE_CUST1 = 7'h2b
+
+// PULP custom
+parameter OPCODE_LOAD_POST = 7'h0b;
+parameter OPCODE_STORE_POST = 7'h2b;
+parameter OPCODE_PULP_OP = 7'h5b;
+parameter OPCODE_VECOP = 7'h57;
+parameter OPCODE_HWLOOP = 7'h7b;
+
+parameter REGC_S1 = 2'b10;
+parameter REGC_RD = 2'b01;
+parameter REGC_ZERO = 2'b11;
+
+
+//////////////////////////////////////////////////////////////////////////////
+// _ _ _ _ ___ _ _ //
+// / \ | | | | | | / _ \ _ __ ___ _ __ __ _| |_(_) ___ _ __ ___ //
+// / _ \ | | | | | | | | | | '_ \ / _ \ '__/ _` | __| |/ _ \| '_ \/ __| //
+// / ___ \| |__| |_| | | |_| | |_) | __/ | | (_| | |_| | (_) | | | \__ \ //
+// /_/ \_\_____\___/ \___/| .__/ \___|_| \__,_|\__|_|\___/|_| |_|___/ //
+// |_| //
+//////////////////////////////////////////////////////////////////////////////
+
+parameter ALU_OP_WIDTH = 6;
+
+parameter ALU_ADD = 6'b011000;
+parameter ALU_SUB = 6'b011001;
+parameter ALU_ADDU = 6'b011010;
+parameter ALU_SUBU = 6'b011011;
+parameter ALU_ADDR = 6'b011100;
+parameter ALU_SUBR = 6'b011101;
+parameter ALU_ADDUR = 6'b011110;
+parameter ALU_SUBUR = 6'b011111;
+
+parameter ALU_XOR = 6'b101111;
+parameter ALU_OR = 6'b101110;
+parameter ALU_AND = 6'b010101;
+
+// Shifts
+parameter ALU_SRA = 6'b100100;
+parameter ALU_SRL = 6'b100101;
+parameter ALU_ROR = 6'b100110;
+parameter ALU_SLL = 6'b100111;
+
+// bit manipulation
+parameter ALU_BEXT = 6'b101000;
+parameter ALU_BEXTU = 6'b101001;
+parameter ALU_BINS = 6'b101010;
+parameter ALU_BCLR = 6'b101011;
+parameter ALU_BSET = 6'b101100;
+
+// Bit counting
+parameter ALU_FF1 = 6'b110110;
+parameter ALU_FL1 = 6'b110111;
+parameter ALU_CNT = 6'b110100;
+parameter ALU_CLB = 6'b110101;
+
+// Sign-/zero-extensions
+parameter ALU_EXTS = 6'b111110;
+parameter ALU_EXT = 6'b111111;
+
+// Comparisons
+parameter ALU_LTS = 6'b000000;
+parameter ALU_LTU = 6'b000001;
+parameter ALU_LES = 6'b000100;
+parameter ALU_LEU = 6'b000101;
+parameter ALU_GTS = 6'b001000;
+parameter ALU_GTU = 6'b001001;
+parameter ALU_GES = 6'b001010;
+parameter ALU_GEU = 6'b001011;
+parameter ALU_EQ = 6'b001100;
+parameter ALU_NE = 6'b001101;
+
+// Set Lower Than operations
+parameter ALU_SLTS = 6'b000010;
+parameter ALU_SLTU = 6'b000011;
+parameter ALU_SLETS = 6'b000110;
+parameter ALU_SLETU = 6'b000111;
+
+// Absolute value
+parameter ALU_ABS = 6'b010100;
+parameter ALU_CLIP = 6'b010110;
+parameter ALU_CLIPU = 6'b010111;
+
+// Insert/extract
+parameter ALU_INS = 6'b101101;
+
+// min/max
+parameter ALU_MIN = 6'b010000;
+parameter ALU_MINU = 6'b010001;
+parameter ALU_MAX = 6'b010010;
+parameter ALU_MAXU = 6'b010011;
+
+// div/rem
+parameter ALU_DIVU = 6'b110000; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_DIV = 6'b110001; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REMU = 6'b110010; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REM = 6'b110011; // bit 0 is used for signed mode, bit 1 is used for remdiv
+
+parameter ALU_SHUF = 6'b111010;
+parameter ALU_SHUF2 = 6'b111011;
+parameter ALU_PCKLO = 6'b111000;
+parameter ALU_PCKHI = 6'b111001;
+
+
+parameter MD_OP_MULL = 2'b00;
+parameter MD_OP_MULH = 2'b01;
+parameter MD_OP_DIV = 2'b10;
+parameter MD_OP_REM = 2'b11;
+
+// vector modes
+parameter VEC_MODE32 = 2'b00;
+parameter VEC_MODE16 = 2'b10;
+parameter VEC_MODE8 = 2'b11;
+
+
+/////////////////////////////////////////////////////////
+// ____ ____ ____ _ _ //
+// / ___/ ___| | _ \ ___ __ _(_)___| |_ ___ _ __ //
+// | | \___ \ | |_) / _ \/ _` | / __| __/ _ \ '__| //
+// | |___ ___) | | _ < __/ (_| | \__ \ || __/ | //
+// \____|____/ |_| \_\___|\__, |_|___/\__\___|_| //
+// |___/ //
+/////////////////////////////////////////////////////////
+
+// CSR operations
+parameter CSR_OP_NONE = 2'b00;
+parameter CSR_OP_WRITE = 2'b01;
+parameter CSR_OP_SET = 2'b10;
+parameter CSR_OP_CLEAR = 2'b11;
+
+
+// SPR for debugger, not accessible by CPU
+parameter SP_DVR0 = 16'h3000;
+parameter SP_DCR0 = 16'h3008;
+parameter SP_DMR1 = 16'h3010;
+parameter SP_DMR2 = 16'h3011;
+
+parameter SP_DVR_MSB = 8'h00;
+parameter SP_DCR_MSB = 8'h01;
+parameter SP_DMR_MSB = 8'h02;
+parameter SP_DSR_MSB = 8'h04;
+
+// Privileged mode
+typedef enum logic[1:0] {
+ PRIV_LVL_M = 2'b11,
+ PRIV_LVL_H = 2'b10,
+ PRIV_LVL_S = 2'b01,
+ PRIV_LVL_U = 2'b00
+} PrivLvl_t;
+
+///////////////////////////////////////////////
+// ___ ____ ____ _ //
+// |_ _| _ \ / ___|| |_ __ _ __ _ ___ //
+// | || | | | \___ \| __/ _` |/ _` |/ _ \ //
+// | || |_| | ___) | || (_| | (_| | __/ //
+// |___|____/ |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// forwarding operand mux
+parameter SEL_REGFILE = 2'b00;
+parameter SEL_FW_EX = 2'b01;
+parameter SEL_FW_WB = 2'b10;
+parameter SEL_MISALIGNED = 2'b11;
+
+// operand a selection
+parameter OP_A_REGA_OR_FWD = 3'b000;
+parameter OP_A_CURRPC = 3'b001;
+parameter OP_A_IMM = 3'b010;
+parameter OP_A_REGB_OR_FWD = 3'b011;
+parameter OP_A_REGC_OR_FWD = 3'b100;
+
+// immediate a selection
+parameter IMMA_Z = 1'b0;
+parameter IMMA_ZERO = 1'b1;
+
+// operand b selection
+parameter OP_B_REGB_OR_FWD = 3'b000;
+parameter OP_B_REGC_OR_FWD = 3'b001;
+parameter OP_B_IMM = 3'b010;
+parameter OP_B_REGA_OR_FWD = 3'b011;
+parameter OP_B_BMASK = 3'b100;
+parameter OP_B_ZERO = 3'b101;
+
+// immediate b selection
+parameter IMMB_I = 4'b0000;
+parameter IMMB_S = 4'b0001;
+parameter IMMB_U = 4'b0010;
+parameter IMMB_PCINCR = 4'b0011;
+parameter IMMB_S2 = 4'b0100;
+parameter IMMB_S3 = 4'b0101;
+parameter IMMB_VS = 4'b0110;
+parameter IMMB_VU = 4'b0111;
+parameter IMMB_SHUF = 4'b1000;
+parameter IMMB_CLIP = 4'b1001;
+parameter IMMB_BI = 4'b1011;
+parameter IMMB_UJ = 4'b1100;
+parameter IMMB_SB = 4'b1101;
+
+// bit mask selection
+parameter BMASK_A_ZERO = 1'b0;
+parameter BMASK_A_S3 = 1'b1;
+
+parameter BMASK_B_S2 = 2'b00;
+parameter BMASK_B_S3 = 2'b01;
+parameter BMASK_B_ZERO = 2'b10;
+parameter BMASK_B_ONE = 2'b11;
+
+parameter BMASK_A_REG = 1'b0;
+parameter BMASK_A_IMM = 1'b1;
+parameter BMASK_B_REG = 1'b0;
+parameter BMASK_B_IMM = 1'b1;
+
+
+
+///////////////////////////////////////////////
+// ___ _____ ____ _ //
+// |_ _| ___| / ___|| |_ __ _ __ _ ___ //
+// | || |_ \___ \| __/ _` |/ _` |/ _ \ //
+// | || _| ___) | || (_| | (_| | __/ //
+// |___|_| |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// PC mux selector defines
+parameter PC_BOOT = 3'b000;
+parameter PC_JUMP = 3'b010;
+parameter PC_EXCEPTION = 3'b100;
+parameter PC_ERET = 3'b101;
+parameter PC_DBG_NPC = 3'b111;
+
+// Exception PC mux selector defines
+parameter EXC_PC_ILLINSN = 2'b00;
+parameter EXC_PC_ECALL = 2'b01;
+parameter EXC_PC_LOAD = 2'b10;
+parameter EXC_PC_STORE = 2'b10;
+parameter EXC_PC_IRQ = 2'b11;
+
+// Exception Cause
+parameter EXC_CAUSE_ILLEGAL_INSN = 6'h02;
+parameter EXC_CAUSE_BREAKPOINT = 6'h03;
+parameter EXC_CAUSE_ECALL_MMODE = 6'h0B;
+
+// Exceptions offsets
+// target address = {boot_addr[31:8], EXC_OFF} (boot_addr must be 32 BYTE aligned!)
+// offset 00 to 7e is used for external interrupts
+parameter EXC_OFF_RST = 8'h80;
+parameter EXC_OFF_ILLINSN = 8'h84;
+parameter EXC_OFF_ECALL = 8'h88;
+parameter EXC_OFF_LSUERR = 8'h8c;
+
+
+// Debug module
+parameter DBG_SETS_W = 6;
+
+parameter DBG_SETS_IRQ = 5;
+parameter DBG_SETS_ECALL = 4;
+parameter DBG_SETS_EILL = 3;
+parameter DBG_SETS_ELSU = 2;
+parameter DBG_SETS_EBRK = 1;
+parameter DBG_SETS_SSTE = 0;
+
+parameter DBG_CAUSE_HALT = 6'h1F;
+ //parameter REG_ADDR_WIDTH = 5;
+ input wire clk;
+ input wire rst_n;
+ input wire fetch_enable_i;
+ output reg ctrl_busy_o;
+ output reg first_fetch_o;
+ output reg is_decoding_o;
+ output reg deassert_we_o;
+ input wire illegal_insn_i;
+ input wire ecall_insn_i;
+ input wire mret_insn_i;
+ input wire pipe_flush_i;
+ input wire ebrk_insn_i;
+ input wire csr_status_i;
+ input wire instr_valid_i;
+ output reg instr_req_o;
+ output reg pc_set_o;
+ output reg [2:0] pc_mux_o;
+ output reg [1:0] exc_pc_mux_o;
+ input wire data_misaligned_i;
+ input wire branch_in_id_i;
+ input wire branch_taken_ex_i;
+ input wire branch_set_i;
+ input wire jump_set_i;
+ input wire instr_multicyle_i;
+ input wire irq_req_ctrl_i;
+ input wire [4:0] irq_id_ctrl_i;
+ input wire m_IE_i;
+ output reg irq_ack_o;
+ output reg [4:0] irq_id_o;
+ output reg [5:0] exc_cause_o;
+ output reg exc_ack_o;
+ output reg exc_kill_o;
+ output reg csr_save_if_o;
+ output reg csr_save_id_o;
+ output reg [5:0] csr_cause_o;
+ output reg csr_restore_mret_id_o;
+ output reg csr_save_cause_o;
+ input wire dbg_req_i;
+ output reg dbg_ack_o;
+ input wire dbg_stall_i;
+ input wire dbg_jump_req_i;
+ input wire [DBG_SETS_W - 1:0] dbg_settings_i;
+ output reg dbg_trap_o;
+ output wire [1:0] operand_a_fw_mux_sel_o;
+ output reg halt_if_o;
+ output reg halt_id_o;
+ input wire id_ready_i;
+ output reg perf_jump_o;
+ output reg perf_tbranch_o;
+ reg [3:0] ctrl_fsm_cs;
+ reg [3:0] ctrl_fsm_ns;
+ reg irq_enable_int;
+ always @(*) begin
+ instr_req_o = 1'b1;
+ exc_ack_o = 1'b0;
+ exc_kill_o = 1'b0;
+ csr_save_if_o = 1'b0;
+ csr_save_id_o = 1'b0;
+ csr_restore_mret_id_o = 1'b0;
+ csr_save_cause_o = 1'b0;
+ exc_cause_o = 1'sb0;
+ exc_pc_mux_o = EXC_PC_IRQ;
+ csr_cause_o = 1'sb0;
+ pc_mux_o = PC_BOOT;
+ pc_set_o = 1'b0;
+ ctrl_fsm_ns = ctrl_fsm_cs;
+ ctrl_busy_o = 1'b1;
+ is_decoding_o = 1'b0;
+ first_fetch_o = 1'b0;
+ halt_if_o = 1'b0;
+ halt_id_o = 1'b0;
+ dbg_ack_o = 1'b0;
+ irq_ack_o = 1'b0;
+ irq_id_o = irq_id_ctrl_i;
+ irq_enable_int = m_IE_i;
+ dbg_trap_o = 1'b0;
+ perf_tbranch_o = 1'b0;
+ perf_jump_o = 1'b0;
+ case (ctrl_fsm_cs)
+ 4'd0: begin
+ ctrl_busy_o = 1'b0;
+ instr_req_o = 1'b0;
+ if (fetch_enable_i == 1'b1)
+ ctrl_fsm_ns = 4'd1;
+ else if (dbg_req_i)
+ ctrl_fsm_ns = 4'd8;
+ end
+ 4'd1: begin
+ instr_req_o = 1'b1;
+ pc_mux_o = PC_BOOT;
+ pc_set_o = 1'b1;
+ ctrl_fsm_ns = 4'd4;
+ end
+ 4'd2: begin
+ ctrl_busy_o = 1'b0;
+ instr_req_o = 1'b0;
+ halt_if_o = 1'b1;
+ halt_id_o = 1'b1;
+ ctrl_fsm_ns = 4'd3;
+ end
+ 4'd3: begin
+ ctrl_busy_o = 1'b0;
+ instr_req_o = 1'b0;
+ halt_if_o = 1'b1;
+ halt_id_o = 1'b1;
+ dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
+ if (dbg_req_i) begin
+ if (fetch_enable_i || irq_req_ctrl_i)
+ ctrl_fsm_ns = 4'd8;
+ else
+ ctrl_fsm_ns = 4'd9;
+ end
+ else if (fetch_enable_i || irq_req_ctrl_i)
+ ctrl_fsm_ns = 4'd4;
+ end
+ 4'd4: begin
+ first_fetch_o = 1'b1;
+ if ((id_ready_i == 1'b1) && (dbg_stall_i == 1'b0))
+ ctrl_fsm_ns = 4'd5;
+ if (irq_req_ctrl_i & irq_enable_int) begin
+ ctrl_fsm_ns = 4'd7;
+ halt_if_o = 1'b1;
+ halt_id_o = 1'b1;
+ end
+ end
+ 4'd5: begin
+ is_decoding_o = 1'b0;
+ if (instr_valid_i) begin
+ is_decoding_o = 1'b1;
+ case (1'b1)
+ branch_set_i: begin
+ pc_mux_o = PC_JUMP;
+ pc_set_o = 1'b1;
+ perf_tbranch_o = 1'b1;
+ dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
+ if (dbg_req_i)
+ ctrl_fsm_ns = 4'd8;
+ end
+ jump_set_i: begin
+ pc_mux_o = PC_JUMP;
+ pc_set_o = 1'b1;
+ perf_jump_o = 1'b1;
+ dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
+ end
+ ((((mret_insn_i | ecall_insn_i) | pipe_flush_i) | ebrk_insn_i) | illegal_insn_i) | csr_status_i: begin
+ ctrl_fsm_ns = 4'd6;
+ halt_if_o = 1'b1;
+ halt_id_o = 1'b1;
+ end
+ default: begin
+ dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
+ case (1'b1)
+ ((irq_req_ctrl_i & irq_enable_int) & ~instr_multicyle_i) & ~branch_in_id_i: begin
+ ctrl_fsm_ns = 4'd7;
+ halt_if_o = 1'b1;
+ halt_id_o = 1'b1;
+ end
+ dbg_req_i & ~branch_taken_ex_i: begin
+ halt_if_o = 1'b1;
+ if (id_ready_i)
+ ctrl_fsm_ns = 4'd8;
+ end
+ default: exc_kill_o = ((irq_req_ctrl_i & ~instr_multicyle_i) & ~branch_in_id_i ? 1'b1 : 1'b0);
+ endcase
+ end
+ endcase
+ end
+ else if (irq_req_ctrl_i & irq_enable_int) begin
+ ctrl_fsm_ns = 4'd7;
+ halt_if_o = 1'b1;
+ halt_id_o = 1'b1;
+ end
+ end
+ 4'd8: begin
+ dbg_ack_o = 1'b1;
+ halt_if_o = 1'b1;
+ ctrl_fsm_ns = 4'd10;
+ end
+ 4'd9: begin
+ dbg_ack_o = 1'b1;
+ halt_if_o = 1'b1;
+ ctrl_fsm_ns = 4'd12;
+ end
+ 4'd12: begin
+ halt_if_o = 1'b1;
+ if (dbg_jump_req_i) begin
+ pc_mux_o = PC_DBG_NPC;
+ pc_set_o = 1'b1;
+ ctrl_fsm_ns = 4'd10;
+ end
+ if (dbg_stall_i == 1'b0)
+ ctrl_fsm_ns = 4'd3;
+ end
+ 4'd10: begin
+ halt_if_o = 1'b1;
+ if (dbg_jump_req_i) begin
+ pc_mux_o = PC_DBG_NPC;
+ pc_set_o = 1'b1;
+ ctrl_fsm_ns = 4'd10;
+ end
+ if (dbg_stall_i == 1'b0)
+ ctrl_fsm_ns = 4'd5;
+ end
+ 4'd7: begin
+ pc_mux_o = PC_EXCEPTION;
+ pc_set_o = 1'b1;
+ exc_pc_mux_o = EXC_PC_IRQ;
+ exc_cause_o = {1'b0, irq_id_ctrl_i};
+ csr_save_cause_o = 1'b1;
+ csr_cause_o = {1'b1, irq_id_ctrl_i};
+ csr_save_if_o = 1'b1;
+ irq_ack_o = 1'b1;
+ exc_ack_o = 1'b1;
+ ctrl_fsm_ns = 4'd5;
+ end
+ 4'd6: begin
+ halt_if_o = (fetch_enable_i ? dbg_req_i : 1'b1);
+ halt_id_o = 1'b1;
+ ctrl_fsm_ns = (dbg_req_i ? 4'd8 : 4'd5);
+ case (1'b1)
+ ecall_insn_i: begin
+ pc_mux_o = PC_EXCEPTION;
+ pc_set_o = 1'b1;
+ csr_save_id_o = 1'b1;
+ csr_save_cause_o = 1'b1;
+ exc_pc_mux_o = EXC_PC_ECALL;
+ exc_cause_o = EXC_CAUSE_ECALL_MMODE;
+ csr_cause_o = EXC_CAUSE_ECALL_MMODE;
+ dbg_trap_o = dbg_settings_i[DBG_SETS_ECALL] | dbg_settings_i[DBG_SETS_SSTE];
+ end
+ illegal_insn_i: begin
+ pc_mux_o = PC_EXCEPTION;
+ pc_set_o = 1'b1;
+ csr_save_id_o = 1'b1;
+ csr_save_cause_o = 1'b1;
+ exc_pc_mux_o = EXC_PC_ILLINSN;
+ exc_cause_o = EXC_CAUSE_ILLEGAL_INSN;
+ csr_cause_o = EXC_CAUSE_ILLEGAL_INSN;
+ dbg_trap_o = dbg_settings_i[DBG_SETS_EILL] | dbg_settings_i[DBG_SETS_SSTE];
+ end
+ mret_insn_i: begin
+ pc_mux_o = PC_ERET;
+ pc_set_o = 1'b1;
+ csr_restore_mret_id_o = 1'b1;
+ dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
+ end
+ ebrk_insn_i: begin
+ dbg_trap_o = dbg_settings_i[DBG_SETS_EBRK] | dbg_settings_i[DBG_SETS_SSTE];
+ exc_cause_o = EXC_CAUSE_BREAKPOINT;
+ end
+ csr_status_i: dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
+ pipe_flush_i: dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
+ default:
+ ;
+ endcase
+ if (fetch_enable_i) begin
+ if (dbg_req_i)
+ ctrl_fsm_ns = 4'd8;
+ else
+ ctrl_fsm_ns = 4'd5;
+ end
+ else if (dbg_req_i)
+ ctrl_fsm_ns = 4'd9;
+ else
+ ctrl_fsm_ns = (mret_insn_i | pipe_flush_i ? 4'd2 : 4'd5);
+ end
+ default: begin
+ instr_req_o = 1'b0;
+ ctrl_fsm_ns = 4'd0;
+ end
+ endcase
+ end
+ always @(*) begin
+ deassert_we_o = 1'b0;
+ if (~is_decoding_o)
+ deassert_we_o = 1'b1;
+ if (illegal_insn_i)
+ deassert_we_o = 1'b1;
+ end
+ assign operand_a_fw_mux_sel_o = (data_misaligned_i ? SEL_MISALIGNED : SEL_REGFILE);
+ always @(posedge clk or negedge rst_n) begin : UPDATE_REGS
+ if (rst_n == 1'b0)
+ ctrl_fsm_cs <= 4'd0;
+ else
+ ctrl_fsm_cs <= ctrl_fsm_ns;
+ end
+endmodule
diff --git a/verilog/rtl/ips/zero-riscy/zeroriscy_core.v b/verilog/rtl/ips/zero-riscy/zeroriscy_core.v
new file mode 100644
index 0000000..371e9c5
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/zeroriscy_core.v
@@ -0,0 +1,711 @@
+module zeroriscy_core
+#(
+ parameter N_EXT_PERF_COUNTERS = 0,
+ parameter RV32E = 0,
+ parameter RV32M = 1
+)
+(
+ clk_i,
+ rst_ni,
+ clock_en_i,
+ test_en_i,
+ core_id_i,
+ cluster_id_i,
+ boot_addr_i,
+ instr_req_o,
+ instr_gnt_i,
+ instr_rvalid_i,
+ instr_addr_o,
+ instr_rdata_i,
+ data_req_o,
+ data_gnt_i,
+ data_rvalid_i,
+ data_we_o,
+ data_be_o,
+ data_addr_o,
+ data_wdata_o,
+ data_rdata_i,
+ data_err_i,
+ irq_i,
+ irq_id_i,
+ irq_ack_o,
+ irq_id_o,
+ debug_req_i,
+ debug_gnt_o,
+ debug_rvalid_o,
+ debug_addr_i,
+ debug_we_i,
+ debug_wdata_i,
+ debug_rdata_o,
+ debug_halted_o,
+ debug_halt_i,
+ debug_resume_i,
+ fetch_enable_i,
+ core_busy_o,
+ ext_perf_counters_i
+);
+parameter OPCODE_SYSTEM = 7'h73;
+parameter OPCODE_FENCE = 7'h0f;
+parameter OPCODE_OP = 7'h33;
+parameter OPCODE_OPIMM = 7'h13;
+parameter OPCODE_STORE = 7'h23;
+parameter OPCODE_LOAD = 7'h03;
+parameter OPCODE_BRANCH = 7'h63;
+parameter OPCODE_JALR = 7'h67;
+parameter OPCODE_JAL = 7'h6f;
+parameter OPCODE_AUIPC = 7'h17;
+parameter OPCODE_LUI = 7'h37;
+
+// those opcodes are now used for PULP custom instructions
+// parameter OPCODE_CUST0 = 7'h0b
+// parameter OPCODE_CUST1 = 7'h2b
+
+// PULP custom
+parameter OPCODE_LOAD_POST = 7'h0b;
+parameter OPCODE_STORE_POST = 7'h2b;
+parameter OPCODE_PULP_OP = 7'h5b;
+parameter OPCODE_VECOP = 7'h57;
+parameter OPCODE_HWLOOP = 7'h7b;
+
+parameter REGC_S1 = 2'b10;
+parameter REGC_RD = 2'b01;
+parameter REGC_ZERO = 2'b11;
+
+
+//////////////////////////////////////////////////////////////////////////////
+// _ _ _ _ ___ _ _ //
+// / \ | | | | | | / _ \ _ __ ___ _ __ __ _| |_(_) ___ _ __ ___ //
+// / _ \ | | | | | | | | | | '_ \ / _ \ '__/ _` | __| |/ _ \| '_ \/ __| //
+// / ___ \| |__| |_| | | |_| | |_) | __/ | | (_| | |_| | (_) | | | \__ \ //
+// /_/ \_\_____\___/ \___/| .__/ \___|_| \__,_|\__|_|\___/|_| |_|___/ //
+// |_| //
+//////////////////////////////////////////////////////////////////////////////
+
+parameter ALU_OP_WIDTH = 6;
+
+parameter ALU_ADD = 6'b011000;
+parameter ALU_SUB = 6'b011001;
+parameter ALU_ADDU = 6'b011010;
+parameter ALU_SUBU = 6'b011011;
+parameter ALU_ADDR = 6'b011100;
+parameter ALU_SUBR = 6'b011101;
+parameter ALU_ADDUR = 6'b011110;
+parameter ALU_SUBUR = 6'b011111;
+
+parameter ALU_XOR = 6'b101111;
+parameter ALU_OR = 6'b101110;
+parameter ALU_AND = 6'b010101;
+
+// Shifts
+parameter ALU_SRA = 6'b100100;
+parameter ALU_SRL = 6'b100101;
+parameter ALU_ROR = 6'b100110;
+parameter ALU_SLL = 6'b100111;
+
+// bit manipulation
+parameter ALU_BEXT = 6'b101000;
+parameter ALU_BEXTU = 6'b101001;
+parameter ALU_BINS = 6'b101010;
+parameter ALU_BCLR = 6'b101011;
+parameter ALU_BSET = 6'b101100;
+
+// Bit counting
+parameter ALU_FF1 = 6'b110110;
+parameter ALU_FL1 = 6'b110111;
+parameter ALU_CNT = 6'b110100;
+parameter ALU_CLB = 6'b110101;
+
+// Sign-/zero-extensions
+parameter ALU_EXTS = 6'b111110;
+parameter ALU_EXT = 6'b111111;
+
+// Comparisons
+parameter ALU_LTS = 6'b000000;
+parameter ALU_LTU = 6'b000001;
+parameter ALU_LES = 6'b000100;
+parameter ALU_LEU = 6'b000101;
+parameter ALU_GTS = 6'b001000;
+parameter ALU_GTU = 6'b001001;
+parameter ALU_GES = 6'b001010;
+parameter ALU_GEU = 6'b001011;
+parameter ALU_EQ = 6'b001100;
+parameter ALU_NE = 6'b001101;
+
+// Set Lower Than operations
+parameter ALU_SLTS = 6'b000010;
+parameter ALU_SLTU = 6'b000011;
+parameter ALU_SLETS = 6'b000110;
+parameter ALU_SLETU = 6'b000111;
+
+// Absolute value
+parameter ALU_ABS = 6'b010100;
+parameter ALU_CLIP = 6'b010110;
+parameter ALU_CLIPU = 6'b010111;
+
+// Insert/extract
+parameter ALU_INS = 6'b101101;
+
+// min/max
+parameter ALU_MIN = 6'b010000;
+parameter ALU_MINU = 6'b010001;
+parameter ALU_MAX = 6'b010010;
+parameter ALU_MAXU = 6'b010011;
+
+// div/rem
+parameter ALU_DIVU = 6'b110000; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_DIV = 6'b110001; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REMU = 6'b110010; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REM = 6'b110011; // bit 0 is used for signed mode, bit 1 is used for remdiv
+
+parameter ALU_SHUF = 6'b111010;
+parameter ALU_SHUF2 = 6'b111011;
+parameter ALU_PCKLO = 6'b111000;
+parameter ALU_PCKHI = 6'b111001;
+
+
+parameter MD_OP_MULL = 2'b00;
+parameter MD_OP_MULH = 2'b01;
+parameter MD_OP_DIV = 2'b10;
+parameter MD_OP_REM = 2'b11;
+
+// vector modes
+parameter VEC_MODE32 = 2'b00;
+parameter VEC_MODE16 = 2'b10;
+parameter VEC_MODE8 = 2'b11;
+
+
+/////////////////////////////////////////////////////////
+// ____ ____ ____ _ _ //
+// / ___/ ___| | _ \ ___ __ _(_)___| |_ ___ _ __ //
+// | | \___ \ | |_) / _ \/ _` | / __| __/ _ \ '__| //
+// | |___ ___) | | _ < __/ (_| | \__ \ || __/ | //
+// \____|____/ |_| \_\___|\__, |_|___/\__\___|_| //
+// |___/ //
+/////////////////////////////////////////////////////////
+
+// CSR operations
+parameter CSR_OP_NONE = 2'b00;
+parameter CSR_OP_WRITE = 2'b01;
+parameter CSR_OP_SET = 2'b10;
+parameter CSR_OP_CLEAR = 2'b11;
+
+
+// SPR for debugger, not accessible by CPU
+parameter SP_DVR0 = 16'h3000;
+parameter SP_DCR0 = 16'h3008;
+parameter SP_DMR1 = 16'h3010;
+parameter SP_DMR2 = 16'h3011;
+
+parameter SP_DVR_MSB = 8'h00;
+parameter SP_DCR_MSB = 8'h01;
+parameter SP_DMR_MSB = 8'h02;
+parameter SP_DSR_MSB = 8'h04;
+
+// Privileged mode
+typedef enum logic[1:0] {
+ PRIV_LVL_M = 2'b11,
+ PRIV_LVL_H = 2'b10,
+ PRIV_LVL_S = 2'b01,
+ PRIV_LVL_U = 2'b00
+} PrivLvl_t;
+
+///////////////////////////////////////////////
+// ___ ____ ____ _ //
+// |_ _| _ \ / ___|| |_ __ _ __ _ ___ //
+// | || | | | \___ \| __/ _` |/ _` |/ _ \ //
+// | || |_| | ___) | || (_| | (_| | __/ //
+// |___|____/ |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// forwarding operand mux
+parameter SEL_REGFILE = 2'b00;
+parameter SEL_FW_EX = 2'b01;
+parameter SEL_FW_WB = 2'b10;
+parameter SEL_MISALIGNED = 2'b11;
+
+// operand a selection
+parameter OP_A_REGA_OR_FWD = 3'b000;
+parameter OP_A_CURRPC = 3'b001;
+parameter OP_A_IMM = 3'b010;
+parameter OP_A_REGB_OR_FWD = 3'b011;
+parameter OP_A_REGC_OR_FWD = 3'b100;
+
+// immediate a selection
+parameter IMMA_Z = 1'b0;
+parameter IMMA_ZERO = 1'b1;
+
+// operand b selection
+parameter OP_B_REGB_OR_FWD = 3'b000;
+parameter OP_B_REGC_OR_FWD = 3'b001;
+parameter OP_B_IMM = 3'b010;
+parameter OP_B_REGA_OR_FWD = 3'b011;
+parameter OP_B_BMASK = 3'b100;
+parameter OP_B_ZERO = 3'b101;
+
+// immediate b selection
+parameter IMMB_I = 4'b0000;
+parameter IMMB_S = 4'b0001;
+parameter IMMB_U = 4'b0010;
+parameter IMMB_PCINCR = 4'b0011;
+parameter IMMB_S2 = 4'b0100;
+parameter IMMB_S3 = 4'b0101;
+parameter IMMB_VS = 4'b0110;
+parameter IMMB_VU = 4'b0111;
+parameter IMMB_SHUF = 4'b1000;
+parameter IMMB_CLIP = 4'b1001;
+parameter IMMB_BI = 4'b1011;
+parameter IMMB_UJ = 4'b1100;
+parameter IMMB_SB = 4'b1101;
+
+// bit mask selection
+parameter BMASK_A_ZERO = 1'b0;
+parameter BMASK_A_S3 = 1'b1;
+
+parameter BMASK_B_S2 = 2'b00;
+parameter BMASK_B_S3 = 2'b01;
+parameter BMASK_B_ZERO = 2'b10;
+parameter BMASK_B_ONE = 2'b11;
+
+parameter BMASK_A_REG = 1'b0;
+parameter BMASK_A_IMM = 1'b1;
+parameter BMASK_B_REG = 1'b0;
+parameter BMASK_B_IMM = 1'b1;
+
+
+
+///////////////////////////////////////////////
+// ___ _____ ____ _ //
+// |_ _| ___| / ___|| |_ __ _ __ _ ___ //
+// | || |_ \___ \| __/ _` |/ _` |/ _ \ //
+// | || _| ___) | || (_| | (_| | __/ //
+// |___|_| |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// PC mux selector defines
+parameter PC_BOOT = 3'b000;
+parameter PC_JUMP = 3'b010;
+parameter PC_EXCEPTION = 3'b100;
+parameter PC_ERET = 3'b101;
+parameter PC_DBG_NPC = 3'b111;
+
+// Exception PC mux selector defines
+parameter EXC_PC_ILLINSN = 2'b00;
+parameter EXC_PC_ECALL = 2'b01;
+parameter EXC_PC_LOAD = 2'b10;
+parameter EXC_PC_STORE = 2'b10;
+parameter EXC_PC_IRQ = 2'b11;
+
+// Exception Cause
+parameter EXC_CAUSE_ILLEGAL_INSN = 6'h02;
+parameter EXC_CAUSE_BREAKPOINT = 6'h03;
+parameter EXC_CAUSE_ECALL_MMODE = 6'h0B;
+
+// Exceptions offsets
+// target address = {boot_addr[31:8], EXC_OFF} (boot_addr must be 32 BYTE aligned!)
+// offset 00 to 7e is used for external interrupts
+parameter EXC_OFF_RST = 8'h80;
+parameter EXC_OFF_ILLINSN = 8'h84;
+parameter EXC_OFF_ECALL = 8'h88;
+parameter EXC_OFF_LSUERR = 8'h8c;
+
+
+// Debug module
+parameter DBG_SETS_W = 6;
+
+parameter DBG_SETS_IRQ = 5;
+parameter DBG_SETS_ECALL = 4;
+parameter DBG_SETS_EILL = 3;
+parameter DBG_SETS_ELSU = 2;
+parameter DBG_SETS_EBRK = 1;
+parameter DBG_SETS_SSTE = 0;
+
+parameter DBG_CAUSE_HALT = 6'h1F;
+ //parameter N_EXT_PERF_COUNTERS = 0;
+ //parameter RV32E = 0;
+ //parameter RV32M = 1;
+ input wire clk_i;
+ input wire rst_ni;
+ input wire clock_en_i;
+ input wire test_en_i;
+ input wire [3:0] core_id_i;
+ input wire [5:0] cluster_id_i;
+ input wire [31:0] boot_addr_i;
+ output wire instr_req_o;
+ input wire instr_gnt_i;
+ input wire instr_rvalid_i;
+ output wire [31:0] instr_addr_o;
+ input wire [31:0] instr_rdata_i;
+ output wire data_req_o;
+ input wire data_gnt_i;
+ input wire data_rvalid_i;
+ output wire data_we_o;
+ output wire [3:0] data_be_o;
+ output wire [31:0] data_addr_o;
+ output wire [31:0] data_wdata_o;
+ input wire [31:0] data_rdata_i;
+ input wire data_err_i;
+ input wire irq_i;
+ input wire [4:0] irq_id_i;
+ output wire irq_ack_o;
+ output wire [4:0] irq_id_o;
+ input wire debug_req_i;
+ output wire debug_gnt_o;
+ output wire debug_rvalid_o;
+ input wire [14:0] debug_addr_i;
+ input wire debug_we_i;
+ input wire [31:0] debug_wdata_i;
+ output wire [31:0] debug_rdata_o;
+ output wire debug_halted_o;
+ input wire debug_halt_i;
+ input wire debug_resume_i;
+ input wire fetch_enable_i;
+ output wire core_busy_o;
+ input wire [N_EXT_PERF_COUNTERS - 1:0] ext_perf_counters_i;
+ localparam N_HWLP = 2;
+ localparam N_HWLP_BITS = 1;
+ wire instr_valid_id;
+ wire [31:0] instr_rdata_id;
+ wire is_compressed_id;
+ wire illegal_c_insn_id;
+ wire [31:0] pc_if;
+ wire [31:0] pc_id;
+ wire clear_instr_valid;
+ wire pc_set;
+ wire [2:0] pc_mux_id;
+ wire [1:0] exc_pc_mux_id;
+ wire [5:0] exc_cause;
+ wire lsu_load_err;
+ wire lsu_store_err;
+ wire is_decoding;
+ wire data_misaligned;
+ wire [31:0] misaligned_addr;
+ wire [31:0] jump_target_ex;
+ wire branch_in_ex;
+ wire branch_decision;
+ wire ctrl_busy;
+ wire if_busy;
+ wire lsu_busy;
+ wire [ALU_OP_WIDTH - 1:0] alu_operator_ex;
+ wire [31:0] alu_operand_a_ex;
+ wire [31:0] alu_operand_b_ex;
+ wire [31:0] alu_adder_result_ex;
+ wire [31:0] regfile_wdata_ex;
+ wire mult_en_ex;
+ wire div_en_ex;
+ wire [1:0] multdiv_operator_ex;
+ wire [1:0] multdiv_signed_mode_ex;
+ wire [31:0] multdiv_operand_a_ex;
+ wire [31:0] multdiv_operand_b_ex;
+ wire csr_access_ex;
+ wire [1:0] csr_op_ex;
+ wire csr_access;
+ wire [1:0] csr_op;
+ wire [11:0] csr_addr;
+ wire [11:0] csr_addr_int;
+ wire [31:0] csr_rdata;
+ wire [31:0] csr_wdata;
+ wire data_we_ex;
+ wire [1:0] data_type_ex;
+ wire data_sign_ext_ex;
+ wire [1:0] data_reg_offset_ex;
+ wire data_req_ex;
+ wire [31:0] data_wdata_ex;
+ wire data_load_event_ex;
+ wire data_misaligned_ex;
+ wire [31:0] regfile_wdata_lsu;
+ wire halt_if;
+ wire id_ready;
+ wire ex_ready;
+ wire if_valid;
+ wire id_valid;
+ wire wb_valid;
+ wire lsu_ready_ex;
+ wire data_valid_lsu;
+ wire instr_req_int;
+ wire m_irq_enable;
+ wire [31:0] mepc;
+ wire csr_save_cause;
+ wire csr_save_if;
+ wire csr_save_id;
+ wire [5:0] csr_cause;
+ wire csr_restore_mret_id;
+ wire csr_restore_uret_id;
+ wire [DBG_SETS_W - 1:0] dbg_settings;
+ wire dbg_req;
+ wire dbg_ack;
+ wire dbg_stall;
+ wire dbg_trap;
+ wire dbg_reg_rreq;
+ wire [4:0] dbg_reg_raddr;
+ wire [31:0] dbg_reg_rdata;
+ wire dbg_reg_wreq;
+ wire [4:0] dbg_reg_waddr;
+ wire [31:0] dbg_reg_wdata;
+ wire dbg_csr_req;
+ wire [11:0] dbg_csr_addr;
+ wire dbg_csr_we;
+ wire [31:0] dbg_csr_wdata;
+ wire [31:0] dbg_jump_addr;
+ wire dbg_jump_req;
+ wire perf_imiss;
+ wire perf_jump;
+ wire perf_branch;
+ wire perf_tbranch;
+ wire core_ctrl_firstfetch;
+ wire core_busy_int;
+ reg core_busy_q;
+ wire clk;
+ wire clock_en;
+ wire dbg_busy;
+ wire sleeping;
+ assign core_busy_int = (data_load_event_ex & data_req_o ? if_busy : (if_busy | ctrl_busy) | lsu_busy);
+ always @(posedge clk or negedge rst_ni)
+ if (rst_ni == 1'b0)
+ core_busy_q <= 1'b0;
+ else
+ core_busy_q <= core_busy_int;
+ assign core_busy_o = (core_ctrl_firstfetch ? 1'b1 : core_busy_q);
+ assign dbg_busy = (((dbg_req | dbg_csr_req) | dbg_jump_req) | dbg_reg_wreq) | debug_req_i;
+ assign clock_en = (clock_en_i | core_busy_o) | dbg_busy;
+ assign sleeping = ~fetch_enable_i & ~core_busy_o;
+ cluster_clock_gating core_clock_gate_i(
+ .clk_i(clk_i),
+ .en_i(clock_en),
+ .test_en_i(test_en_i),
+ .clk_o(clk)
+ );
+ zeroriscy_if_stage if_stage_i(
+ .clk(clk),
+ .rst_n(rst_ni),
+ .boot_addr_i(boot_addr_i),
+ .req_i(instr_req_int),
+ .instr_req_o(instr_req_o),
+ .instr_addr_o(instr_addr_o),
+ .instr_gnt_i(instr_gnt_i),
+ .instr_rvalid_i(instr_rvalid_i),
+ .instr_rdata_i(instr_rdata_i),
+ .instr_valid_id_o(instr_valid_id),
+ .instr_rdata_id_o(instr_rdata_id),
+ .is_compressed_id_o(is_compressed_id),
+ .illegal_c_insn_id_o(illegal_c_insn_id),
+ .pc_if_o(pc_if),
+ .pc_id_o(pc_id),
+ .clear_instr_valid_i(clear_instr_valid),
+ .pc_set_i(pc_set),
+ .exception_pc_reg_i(mepc),
+ .pc_mux_i(pc_mux_id),
+ .exc_pc_mux_i(exc_pc_mux_id),
+ .exc_vec_pc_mux_i(exc_cause[4:0]),
+ .dbg_jump_addr_i(dbg_jump_addr),
+ .jump_target_ex_i(jump_target_ex),
+ .halt_if_i(halt_if),
+ .id_ready_i(id_ready),
+ .if_valid_o(if_valid),
+ .if_busy_o(if_busy),
+ .perf_imiss_o(perf_imiss)
+ );
+ zeroriscy_id_stage #(
+ .RV32E(RV32E),
+ .RV32M(RV32M)
+ ) id_stage_i(
+ .clk(clk),
+ .rst_n(rst_ni),
+ .test_en_i(test_en_i),
+ .fetch_enable_i(fetch_enable_i),
+ .ctrl_busy_o(ctrl_busy),
+ .core_ctrl_firstfetch_o(core_ctrl_firstfetch),
+ .is_decoding_o(is_decoding),
+ .instr_valid_i(instr_valid_id),
+ .instr_rdata_i(instr_rdata_id),
+ .instr_req_o(instr_req_int),
+ .branch_in_ex_o(branch_in_ex),
+ .branch_decision_i(branch_decision),
+ .clear_instr_valid_o(clear_instr_valid),
+ .pc_set_o(pc_set),
+ .pc_mux_o(pc_mux_id),
+ .exc_pc_mux_o(exc_pc_mux_id),
+ .exc_cause_o(exc_cause),
+ .illegal_c_insn_i(illegal_c_insn_id),
+ .is_compressed_i(is_compressed_id),
+ .pc_id_i(pc_id),
+ .halt_if_o(halt_if),
+ .id_ready_o(id_ready),
+ .ex_ready_i(ex_ready),
+ .id_valid_o(id_valid),
+ .alu_operator_ex_o(alu_operator_ex),
+ .alu_operand_a_ex_o(alu_operand_a_ex),
+ .alu_operand_b_ex_o(alu_operand_b_ex),
+ .mult_en_ex_o(mult_en_ex),
+ .div_en_ex_o(div_en_ex),
+ .multdiv_operator_ex_o(multdiv_operator_ex),
+ .multdiv_signed_mode_ex_o(multdiv_signed_mode_ex),
+ .multdiv_operand_a_ex_o(multdiv_operand_a_ex),
+ .multdiv_operand_b_ex_o(multdiv_operand_b_ex),
+ .csr_access_ex_o(csr_access_ex),
+ .csr_op_ex_o(csr_op_ex),
+ .csr_cause_o(csr_cause),
+ .csr_save_if_o(csr_save_if),
+ .csr_save_id_o(csr_save_id),
+ .csr_restore_mret_id_o(csr_restore_mret_id),
+ .csr_save_cause_o(csr_save_cause),
+ .data_req_ex_o(data_req_ex),
+ .data_we_ex_o(data_we_ex),
+ .data_type_ex_o(data_type_ex),
+ .data_sign_ext_ex_o(data_sign_ext_ex),
+ .data_reg_offset_ex_o(data_reg_offset_ex),
+ .data_load_event_ex_o(data_load_event_ex),
+ .data_wdata_ex_o(data_wdata_ex),
+ .data_misaligned_i(data_misaligned),
+ .misaligned_addr_i(misaligned_addr),
+ .irq_i(irq_i),
+ .irq_id_i(irq_id_i),
+ .m_irq_enable_i(m_irq_enable),
+ .irq_ack_o(irq_ack_o),
+ .irq_id_o(irq_id_o),
+ .lsu_load_err_i(lsu_load_err),
+ .lsu_store_err_i(lsu_store_err),
+ .dbg_settings_i(dbg_settings),
+ .dbg_req_i(dbg_req),
+ .dbg_ack_o(dbg_ack),
+ .dbg_stall_i(dbg_stall),
+ .dbg_trap_o(dbg_trap),
+ .dbg_reg_rreq_i(dbg_reg_rreq),
+ .dbg_reg_raddr_i(dbg_reg_raddr),
+ .dbg_reg_rdata_o(dbg_reg_rdata),
+ .dbg_reg_wreq_i(dbg_reg_wreq),
+ .dbg_reg_waddr_i(dbg_reg_waddr),
+ .dbg_reg_wdata_i(dbg_reg_wdata),
+ .dbg_jump_req_i(dbg_jump_req),
+ .regfile_wdata_lsu_i(regfile_wdata_lsu),
+ .regfile_wdata_ex_i(regfile_wdata_ex),
+ .csr_rdata_i(csr_rdata),
+ .perf_jump_o(perf_jump),
+ .perf_branch_o(perf_branch),
+ .perf_tbranch_o(perf_tbranch)
+ );
+ zeroriscy_ex_block #(.RV32M(RV32M)) ex_block_i(
+ .clk(clk),
+ .rst_n(rst_ni),
+ .alu_operator_i(alu_operator_ex),
+ .multdiv_operator_i(multdiv_operator_ex),
+ .alu_operand_a_i(alu_operand_a_ex),
+ .alu_operand_b_i(alu_operand_b_ex),
+ .mult_en_i(mult_en_ex),
+ .div_en_i(div_en_ex),
+ .multdiv_signed_mode_i(multdiv_signed_mode_ex),
+ .multdiv_operand_a_i(multdiv_operand_a_ex),
+ .multdiv_operand_b_i(multdiv_operand_b_ex),
+ .alu_adder_result_ex_o(alu_adder_result_ex),
+ .regfile_wdata_ex_o(regfile_wdata_ex),
+ .jump_target_o(jump_target_ex),
+ .branch_decision_o(branch_decision),
+ .lsu_en_i(data_req_ex),
+ .lsu_ready_ex_i(data_valid_lsu),
+ .ex_ready_o(ex_ready)
+ );
+ zeroriscy_load_store_unit load_store_unit_i(
+ .clk(clk),
+ .rst_n(rst_ni),
+ .data_req_o(data_req_o),
+ .data_gnt_i(data_gnt_i),
+ .data_rvalid_i(data_rvalid_i),
+ .data_err_i(data_err_i),
+ .data_addr_o(data_addr_o),
+ .data_we_o(data_we_o),
+ .data_be_o(data_be_o),
+ .data_wdata_o(data_wdata_o),
+ .data_rdata_i(data_rdata_i),
+ .data_we_ex_i(data_we_ex),
+ .data_type_ex_i(data_type_ex),
+ .data_wdata_ex_i(data_wdata_ex),
+ .data_reg_offset_ex_i(data_reg_offset_ex),
+ .data_sign_ext_ex_i(data_sign_ext_ex),
+ .data_rdata_ex_o(regfile_wdata_lsu),
+ .data_req_ex_i(data_req_ex),
+ .adder_result_ex_i(alu_adder_result_ex),
+ .data_misaligned_o(data_misaligned),
+ .misaligned_addr_o(misaligned_addr),
+ .load_err_o(lsu_load_err),
+ .store_err_o(lsu_store_err),
+ .data_valid_o(data_valid_lsu),
+ .lsu_update_addr_o(),
+ .busy_o(lsu_busy)
+ );
+ zeroriscy_cs_registers #(.N_EXT_CNT(N_EXT_PERF_COUNTERS)) cs_registers_i(
+ .clk(clk),
+ .rst_n(rst_ni),
+ .core_id_i(core_id_i),
+ .cluster_id_i(cluster_id_i),
+ .boot_addr_i(boot_addr_i[31:8]),
+ .csr_access_i(csr_access),
+ .csr_addr_i(csr_addr),
+ .csr_wdata_i(csr_wdata),
+ .csr_op_i(csr_op),
+ .csr_rdata_o(csr_rdata),
+ .m_irq_enable_o(m_irq_enable),
+ .mepc_o(mepc),
+ .pc_if_i(pc_if),
+ .pc_id_i(pc_id),
+ .csr_save_if_i(csr_save_if),
+ .csr_save_id_i(csr_save_id),
+ .csr_restore_mret_i(csr_restore_mret_id),
+ .csr_cause_i(csr_cause),
+ .csr_save_cause_i(csr_save_cause),
+ .if_valid_i(if_valid),
+ .id_valid_i(id_valid),
+ .is_compressed_i(is_compressed_id),
+ .is_decoding_i(is_decoding),
+ .imiss_i(perf_imiss),
+ .pc_set_i(pc_set),
+ .jump_i(perf_jump),
+ .branch_i(perf_branch),
+ .branch_taken_i(perf_tbranch),
+ .mem_load_i((data_req_o & data_gnt_i) & ~data_we_o),
+ .mem_store_i((data_req_o & data_gnt_i) & data_we_o),
+ .ext_counters_i(ext_perf_counters_i)
+ );
+ assign csr_access = (dbg_csr_req == 1'b0 ? csr_access_ex : 1'b1);
+ assign csr_addr = (dbg_csr_req == 1'b0 ? csr_addr_int : dbg_csr_addr);
+ assign csr_wdata = (dbg_csr_req == 1'b0 ? alu_operand_a_ex : dbg_csr_wdata);
+ assign csr_op = (dbg_csr_req == 1'b0 ? csr_op_ex : (dbg_csr_we == 1'b1 ? CSR_OP_WRITE : CSR_OP_NONE));
+ assign csr_addr_int = (csr_access_ex ? alu_operand_b_ex[11:0] : {12 {1'sb0}});
+ zeroriscy_debug_unit debug_unit_i(
+ .clk(clk_i),
+ .rst_n(rst_ni),
+ .debug_req_i(debug_req_i),
+ .debug_gnt_o(debug_gnt_o),
+ .debug_rvalid_o(debug_rvalid_o),
+ .debug_addr_i(debug_addr_i),
+ .debug_we_i(debug_we_i),
+ .debug_wdata_i(debug_wdata_i),
+ .debug_rdata_o(debug_rdata_o),
+ .debug_halt_i(debug_halt_i),
+ .debug_resume_i(debug_resume_i),
+ .debug_halted_o(debug_halted_o),
+ .settings_o(dbg_settings),
+ .trap_i(dbg_trap),
+ .exc_cause_i(exc_cause),
+ .stall_o(dbg_stall),
+ .dbg_req_o(dbg_req),
+ .dbg_ack_i(dbg_ack),
+ .regfile_rreq_o(dbg_reg_rreq),
+ .regfile_raddr_o(dbg_reg_raddr),
+ .regfile_rdata_i(dbg_reg_rdata),
+ .regfile_wreq_o(dbg_reg_wreq),
+ .regfile_waddr_o(dbg_reg_waddr),
+ .regfile_wdata_o(dbg_reg_wdata),
+ .csr_req_o(dbg_csr_req),
+ .csr_addr_o(dbg_csr_addr),
+ .csr_we_o(dbg_csr_we),
+ .csr_wdata_o(dbg_csr_wdata),
+ .csr_rdata_i(csr_rdata),
+ .pc_if_i(pc_if),
+ .pc_id_i(pc_id),
+ .instr_valid_id_i(instr_valid_id),
+ .sleeping_i(sleeping),
+ .jump_addr_o(dbg_jump_addr),
+ .jump_req_o(dbg_jump_req)
+ );
+endmodule
diff --git a/verilog/rtl/ips/zero-riscy/zeroriscy_cs_registers.v b/verilog/rtl/ips/zero-riscy/zeroriscy_cs_registers.v
new file mode 100644
index 0000000..74c5b8a
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/zeroriscy_cs_registers.v
@@ -0,0 +1,584 @@
+`define ASIC_SYNTHESIS
+
+module zeroriscy_cs_registers (
+ clk,
+ rst_n,
+ core_id_i,
+ cluster_id_i,
+ boot_addr_i,
+ csr_access_i,
+ csr_addr_i,
+ csr_wdata_i,
+ csr_op_i,
+ csr_rdata_o,
+ m_irq_enable_o,
+ mepc_o,
+ pc_if_i,
+ pc_id_i,
+ csr_save_if_i,
+ csr_save_id_i,
+ csr_restore_mret_i,
+ csr_cause_i,
+ csr_save_cause_i,
+ if_valid_i,
+ id_valid_i,
+ is_compressed_i,
+ is_decoding_i,
+ imiss_i,
+ pc_set_i,
+ jump_i,
+ branch_i,
+ branch_taken_i,
+ mem_load_i,
+ mem_store_i,
+ ext_counters_i
+);
+parameter OPCODE_SYSTEM = 7'h73;
+parameter OPCODE_FENCE = 7'h0f;
+parameter OPCODE_OP = 7'h33;
+parameter OPCODE_OPIMM = 7'h13;
+parameter OPCODE_STORE = 7'h23;
+parameter OPCODE_LOAD = 7'h03;
+parameter OPCODE_BRANCH = 7'h63;
+parameter OPCODE_JALR = 7'h67;
+parameter OPCODE_JAL = 7'h6f;
+parameter OPCODE_AUIPC = 7'h17;
+parameter OPCODE_LUI = 7'h37;
+
+// those opcodes are now used for PULP custom instructions
+// parameter OPCODE_CUST0 = 7'h0b
+// parameter OPCODE_CUST1 = 7'h2b
+
+// PULP custom
+parameter OPCODE_LOAD_POST = 7'h0b;
+parameter OPCODE_STORE_POST = 7'h2b;
+parameter OPCODE_PULP_OP = 7'h5b;
+parameter OPCODE_VECOP = 7'h57;
+parameter OPCODE_HWLOOP = 7'h7b;
+
+parameter REGC_S1 = 2'b10;
+parameter REGC_RD = 2'b01;
+parameter REGC_ZERO = 2'b11;
+
+
+//////////////////////////////////////////////////////////////////////////////
+// _ _ _ _ ___ _ _ //
+// / \ | | | | | | / _ \ _ __ ___ _ __ __ _| |_(_) ___ _ __ ___ //
+// / _ \ | | | | | | | | | | '_ \ / _ \ '__/ _` | __| |/ _ \| '_ \/ __| //
+// / ___ \| |__| |_| | | |_| | |_) | __/ | | (_| | |_| | (_) | | | \__ \ //
+// /_/ \_\_____\___/ \___/| .__/ \___|_| \__,_|\__|_|\___/|_| |_|___/ //
+// |_| //
+//////////////////////////////////////////////////////////////////////////////
+
+parameter ALU_OP_WIDTH = 6;
+
+parameter ALU_ADD = 6'b011000;
+parameter ALU_SUB = 6'b011001;
+parameter ALU_ADDU = 6'b011010;
+parameter ALU_SUBU = 6'b011011;
+parameter ALU_ADDR = 6'b011100;
+parameter ALU_SUBR = 6'b011101;
+parameter ALU_ADDUR = 6'b011110;
+parameter ALU_SUBUR = 6'b011111;
+
+parameter ALU_XOR = 6'b101111;
+parameter ALU_OR = 6'b101110;
+parameter ALU_AND = 6'b010101;
+
+// Shifts
+parameter ALU_SRA = 6'b100100;
+parameter ALU_SRL = 6'b100101;
+parameter ALU_ROR = 6'b100110;
+parameter ALU_SLL = 6'b100111;
+
+// bit manipulation
+parameter ALU_BEXT = 6'b101000;
+parameter ALU_BEXTU = 6'b101001;
+parameter ALU_BINS = 6'b101010;
+parameter ALU_BCLR = 6'b101011;
+parameter ALU_BSET = 6'b101100;
+
+// Bit counting
+parameter ALU_FF1 = 6'b110110;
+parameter ALU_FL1 = 6'b110111;
+parameter ALU_CNT = 6'b110100;
+parameter ALU_CLB = 6'b110101;
+
+// Sign-/zero-extensions
+parameter ALU_EXTS = 6'b111110;
+parameter ALU_EXT = 6'b111111;
+
+// Comparisons
+parameter ALU_LTS = 6'b000000;
+parameter ALU_LTU = 6'b000001;
+parameter ALU_LES = 6'b000100;
+parameter ALU_LEU = 6'b000101;
+parameter ALU_GTS = 6'b001000;
+parameter ALU_GTU = 6'b001001;
+parameter ALU_GES = 6'b001010;
+parameter ALU_GEU = 6'b001011;
+parameter ALU_EQ = 6'b001100;
+parameter ALU_NE = 6'b001101;
+
+// Set Lower Than operations
+parameter ALU_SLTS = 6'b000010;
+parameter ALU_SLTU = 6'b000011;
+parameter ALU_SLETS = 6'b000110;
+parameter ALU_SLETU = 6'b000111;
+
+// Absolute value
+parameter ALU_ABS = 6'b010100;
+parameter ALU_CLIP = 6'b010110;
+parameter ALU_CLIPU = 6'b010111;
+
+// Insert/extract
+parameter ALU_INS = 6'b101101;
+
+// min/max
+parameter ALU_MIN = 6'b010000;
+parameter ALU_MINU = 6'b010001;
+parameter ALU_MAX = 6'b010010;
+parameter ALU_MAXU = 6'b010011;
+
+// div/rem
+parameter ALU_DIVU = 6'b110000; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_DIV = 6'b110001; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REMU = 6'b110010; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REM = 6'b110011; // bit 0 is used for signed mode, bit 1 is used for remdiv
+
+parameter ALU_SHUF = 6'b111010;
+parameter ALU_SHUF2 = 6'b111011;
+parameter ALU_PCKLO = 6'b111000;
+parameter ALU_PCKHI = 6'b111001;
+
+
+parameter MD_OP_MULL = 2'b00;
+parameter MD_OP_MULH = 2'b01;
+parameter MD_OP_DIV = 2'b10;
+parameter MD_OP_REM = 2'b11;
+
+// vector modes
+parameter VEC_MODE32 = 2'b00;
+parameter VEC_MODE16 = 2'b10;
+parameter VEC_MODE8 = 2'b11;
+
+
+/////////////////////////////////////////////////////////
+// ____ ____ ____ _ _ //
+// / ___/ ___| | _ \ ___ __ _(_)___| |_ ___ _ __ //
+// | | \___ \ | |_) / _ \/ _` | / __| __/ _ \ '__| //
+// | |___ ___) | | _ < __/ (_| | \__ \ || __/ | //
+// \____|____/ |_| \_\___|\__, |_|___/\__\___|_| //
+// |___/ //
+/////////////////////////////////////////////////////////
+
+// CSR operations
+parameter CSR_OP_NONE = 2'b00;
+parameter CSR_OP_WRITE = 2'b01;
+parameter CSR_OP_SET = 2'b10;
+parameter CSR_OP_CLEAR = 2'b11;
+
+
+// SPR for debugger, not accessible by CPU
+parameter SP_DVR0 = 16'h3000;
+parameter SP_DCR0 = 16'h3008;
+parameter SP_DMR1 = 16'h3010;
+parameter SP_DMR2 = 16'h3011;
+
+parameter SP_DVR_MSB = 8'h00;
+parameter SP_DCR_MSB = 8'h01;
+parameter SP_DMR_MSB = 8'h02;
+parameter SP_DSR_MSB = 8'h04;
+
+// Privileged mode
+typedef enum logic[1:0] {
+ PRIV_LVL_M = 2'b11,
+ PRIV_LVL_H = 2'b10,
+ PRIV_LVL_S = 2'b01,
+ PRIV_LVL_U = 2'b00
+} PrivLvl_t;
+
+///////////////////////////////////////////////
+// ___ ____ ____ _ //
+// |_ _| _ \ / ___|| |_ __ _ __ _ ___ //
+// | || | | | \___ \| __/ _` |/ _` |/ _ \ //
+// | || |_| | ___) | || (_| | (_| | __/ //
+// |___|____/ |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// forwarding operand mux
+parameter SEL_REGFILE = 2'b00;
+parameter SEL_FW_EX = 2'b01;
+parameter SEL_FW_WB = 2'b10;
+parameter SEL_MISALIGNED = 2'b11;
+
+// operand a selection
+parameter OP_A_REGA_OR_FWD = 3'b000;
+parameter OP_A_CURRPC = 3'b001;
+parameter OP_A_IMM = 3'b010;
+parameter OP_A_REGB_OR_FWD = 3'b011;
+parameter OP_A_REGC_OR_FWD = 3'b100;
+
+// immediate a selection
+parameter IMMA_Z = 1'b0;
+parameter IMMA_ZERO = 1'b1;
+
+// operand b selection
+parameter OP_B_REGB_OR_FWD = 3'b000;
+parameter OP_B_REGC_OR_FWD = 3'b001;
+parameter OP_B_IMM = 3'b010;
+parameter OP_B_REGA_OR_FWD = 3'b011;
+parameter OP_B_BMASK = 3'b100;
+parameter OP_B_ZERO = 3'b101;
+
+// immediate b selection
+parameter IMMB_I = 4'b0000;
+parameter IMMB_S = 4'b0001;
+parameter IMMB_U = 4'b0010;
+parameter IMMB_PCINCR = 4'b0011;
+parameter IMMB_S2 = 4'b0100;
+parameter IMMB_S3 = 4'b0101;
+parameter IMMB_VS = 4'b0110;
+parameter IMMB_VU = 4'b0111;
+parameter IMMB_SHUF = 4'b1000;
+parameter IMMB_CLIP = 4'b1001;
+parameter IMMB_BI = 4'b1011;
+parameter IMMB_UJ = 4'b1100;
+parameter IMMB_SB = 4'b1101;
+
+// bit mask selection
+parameter BMASK_A_ZERO = 1'b0;
+parameter BMASK_A_S3 = 1'b1;
+
+parameter BMASK_B_S2 = 2'b00;
+parameter BMASK_B_S3 = 2'b01;
+parameter BMASK_B_ZERO = 2'b10;
+parameter BMASK_B_ONE = 2'b11;
+
+parameter BMASK_A_REG = 1'b0;
+parameter BMASK_A_IMM = 1'b1;
+parameter BMASK_B_REG = 1'b0;
+parameter BMASK_B_IMM = 1'b1;
+
+
+
+///////////////////////////////////////////////
+// ___ _____ ____ _ //
+// |_ _| ___| / ___|| |_ __ _ __ _ ___ //
+// | || |_ \___ \| __/ _` |/ _` |/ _ \ //
+// | || _| ___) | || (_| | (_| | __/ //
+// |___|_| |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// PC mux selector defines
+parameter PC_BOOT = 3'b000;
+parameter PC_JUMP = 3'b010;
+parameter PC_EXCEPTION = 3'b100;
+parameter PC_ERET = 3'b101;
+parameter PC_DBG_NPC = 3'b111;
+
+// Exception PC mux selector defines
+parameter EXC_PC_ILLINSN = 2'b00;
+parameter EXC_PC_ECALL = 2'b01;
+parameter EXC_PC_LOAD = 2'b10;
+parameter EXC_PC_STORE = 2'b10;
+parameter EXC_PC_IRQ = 2'b11;
+
+// Exception Cause
+parameter EXC_CAUSE_ILLEGAL_INSN = 6'h02;
+parameter EXC_CAUSE_BREAKPOINT = 6'h03;
+parameter EXC_CAUSE_ECALL_MMODE = 6'h0B;
+
+// Exceptions offsets
+// target address = {boot_addr[31:8], EXC_OFF} (boot_addr must be 32 BYTE aligned!)
+// offset 00 to 7e is used for external interrupts
+parameter EXC_OFF_RST = 8'h80;
+parameter EXC_OFF_ILLINSN = 8'h84;
+parameter EXC_OFF_ECALL = 8'h88;
+parameter EXC_OFF_LSUERR = 8'h8c;
+
+
+// Debug module
+parameter DBG_SETS_W = 6;
+
+parameter DBG_SETS_IRQ = 5;
+parameter DBG_SETS_ECALL = 4;
+parameter DBG_SETS_EILL = 3;
+parameter DBG_SETS_ELSU = 2;
+parameter DBG_SETS_EBRK = 1;
+parameter DBG_SETS_SSTE = 0;
+
+parameter DBG_CAUSE_HALT = 6'h1F;
+ parameter N_EXT_CNT = 0;
+ input wire clk;
+ input wire rst_n;
+ input wire [3:0] core_id_i;
+ input wire [5:0] cluster_id_i;
+ input wire [23:0] boot_addr_i;
+ input wire csr_access_i;
+ input wire [11:0] csr_addr_i;
+ input wire [31:0] csr_wdata_i;
+ input wire [1:0] csr_op_i;
+ output reg [31:0] csr_rdata_o;
+ output wire m_irq_enable_o;
+ output wire [31:0] mepc_o;
+ input wire [31:0] pc_if_i;
+ input wire [31:0] pc_id_i;
+ input wire csr_save_if_i;
+ input wire csr_save_id_i;
+ input wire csr_restore_mret_i;
+ input wire [5:0] csr_cause_i;
+ input wire csr_save_cause_i;
+ input wire if_valid_i;
+ input wire id_valid_i;
+ input wire is_compressed_i;
+ input wire is_decoding_i;
+ input wire imiss_i;
+ input wire pc_set_i;
+ input wire jump_i;
+ input wire branch_i;
+ input wire branch_taken_i;
+ input wire mem_load_i;
+ input wire mem_store_i;
+ input wire [N_EXT_CNT - 1:0] ext_counters_i;
+ localparam N_PERF_COUNTERS = 11 + N_EXT_CNT;
+ localparam N_PERF_REGS = 1;
+ reg id_valid_q;
+ wire [N_PERF_COUNTERS - 1:0] PCCR_in;
+ wire [N_PERF_COUNTERS - 1:0] PCCR_inc;
+ reg [N_PERF_COUNTERS - 1:0] PCCR_inc_q;
+ reg [31:0] PCCR_q;
+ reg [31:0] PCCR_n;
+ reg [1:0] PCMR_n;
+ reg [1:0] PCMR_q;
+ reg [N_PERF_COUNTERS - 1:0] PCER_n;
+ reg [N_PERF_COUNTERS - 1:0] PCER_q;
+ reg [31:0] perf_rdata;
+ reg [4:0] pccr_index;
+ reg pccr_all_sel;
+ reg is_pccr;
+ reg is_pcer;
+ reg is_pcmr;
+ reg [31:0] csr_wdata_int;
+ reg [31:0] csr_rdata_int;
+ reg csr_we_int;
+ reg [31:0] mepc_q;
+ reg [31:0] mepc_n;
+ reg [5:0] mcause_q;
+ reg [5:0] mcause_n;
+ struct packed {
+ logic mie;
+ logic mpie;
+ PrivLvl_t mpp;
+ } mstatus_q;
+ struct packed {
+ logic mie;
+ logic mpie;
+ PrivLvl_t mpp;
+ } mstatus_n;
+ always @(*) begin
+ csr_rdata_int = 1'sb0;
+ case (csr_addr_i)
+ 12'h300: csr_rdata_int = {19'b0000000000000000000, mstatus_q.mpp, 3'b000, mstatus_q.mpie, 3'h0, mstatus_q.mie, 3'h0};
+ 12'h305: csr_rdata_int = {boot_addr_i, 8'h00};
+ 12'h341: csr_rdata_int = mepc_q;
+ 12'h342: csr_rdata_int = {mcause_q[5], 26'b00000000000000000000000000, mcause_q[4:0]};
+ 12'hf14: csr_rdata_int = {21'b000000000000000000000, cluster_id_i[5:0], 1'b0, core_id_i[3:0]};
+ default:
+ ;
+ endcase
+ end
+ always @(*) begin
+ mepc_n = mepc_q;
+ mstatus_n = mstatus_q;
+ mcause_n = mcause_q;
+ case (csr_addr_i)
+ 12'h300:
+ if (csr_we_int)
+ mstatus_n = {
+ csr_wdata_int[3],
+ csr_wdata_int[7],
+ 1'b0
+ };
+ 12'h341:
+ if (csr_we_int)
+ mepc_n = csr_wdata_int;
+ 12'h342:
+ if (csr_we_int)
+ mcause_n = {csr_wdata_int[31], csr_wdata_int[4:0]};
+ default:
+ ;
+ endcase
+ case (1'b1)
+ csr_save_cause_i: begin
+ case (1'b1)
+ csr_save_if_i: mepc_n = pc_if_i;
+ csr_save_id_i: mepc_n = pc_id_i;
+ default:
+ ;
+ endcase
+ mstatus_n.mpie = mstatus_q.mie;
+ mstatus_n.mie = 1'b0;
+ mcause_n = csr_cause_i;
+ end
+ csr_restore_mret_i: begin
+ mstatus_n.mie = mstatus_q.mpie;
+ mstatus_n.mpie = 1'b1;
+ end
+ default:
+ ;
+ endcase
+ end
+ always @(*) begin
+ csr_wdata_int = csr_wdata_i;
+ csr_we_int = 1'b1;
+ case (csr_op_i)
+ CSR_OP_WRITE: csr_wdata_int = csr_wdata_i;
+ CSR_OP_SET: csr_wdata_int = csr_wdata_i | csr_rdata_o;
+ CSR_OP_CLEAR: csr_wdata_int = ~csr_wdata_i & csr_rdata_o;
+ CSR_OP_NONE: begin
+ csr_wdata_int = csr_wdata_i;
+ csr_we_int = 1'b0;
+ end
+ default:
+ ;
+ endcase
+ end
+ always @(*) begin
+ csr_rdata_o = csr_rdata_int;
+ if ((is_pccr || is_pcer) || is_pcmr)
+ csr_rdata_o = perf_rdata;
+ end
+ assign m_irq_enable_o = mstatus_q.mie;
+ assign mepc_o = mepc_q;
+ always @(posedge clk or negedge rst_n)
+ if (rst_n == 1'b0) begin
+ mstatus_q <= {
+ 1'b0,
+ 1'b0,
+ PRIV_LVL_M
+ };
+ mepc_q <= 1'sb0;
+ mcause_q <= 1'sb0;
+ end
+ else begin
+ mstatus_q <= {
+ mstatus_n.mie,
+ mstatus_n.mpie,
+ PRIV_LVL_M
+ };
+ mepc_q <= mepc_n;
+ mcause_q <= mcause_n;
+ end
+ assign PCCR_in[0] = 1'b1;
+ assign PCCR_in[1] = if_valid_i;
+ assign PCCR_in[2] = 1'b0;
+ assign PCCR_in[3] = 1'b0;
+ assign PCCR_in[4] = imiss_i & ~pc_set_i;
+ assign PCCR_in[5] = mem_load_i;
+ assign PCCR_in[6] = mem_store_i;
+ assign PCCR_in[7] = jump_i;
+ assign PCCR_in[8] = branch_i;
+ assign PCCR_in[9] = branch_taken_i;
+ assign PCCR_in[10] = (id_valid_i & is_decoding_i) & is_compressed_i;
+ genvar i;
+ generate
+ for (i = 0; i < N_EXT_CNT; i = i + 1) begin : g_extcounters
+ assign PCCR_in[(N_PERF_COUNTERS - N_EXT_CNT) + i] = ext_counters_i[i];
+ end
+ endgenerate
+ always @(*) begin
+ is_pccr = 1'b0;
+ is_pcmr = 1'b0;
+ is_pcer = 1'b0;
+ pccr_all_sel = 1'b0;
+ pccr_index = 1'sb0;
+ perf_rdata = 1'sb0;
+ if (csr_access_i) begin
+ case (csr_addr_i)
+ 12'h7a0: begin
+ is_pcer = 1'b1;
+ perf_rdata[15:0] = PCER_q;
+ end
+ 12'h7a1: begin
+ is_pcmr = 1'b1;
+ perf_rdata[1:0] = PCMR_q;
+ end
+ 12'h79f: begin
+ is_pccr = 1'b1;
+ pccr_all_sel = 1'b1;
+ end
+ default:
+ ;
+ endcase
+ if (csr_addr_i[11:5] == 7'b0111100) begin
+ is_pccr = 1'b1;
+ pccr_index = csr_addr_i[4:0];
+ perf_rdata = PCCR_q[0+:32];
+ end
+ end
+ end
+ assign PCCR_inc[0] = |(PCCR_in & PCER_q) & PCMR_q[0];
+ always @(*) begin
+ PCCR_n[0+:32] = PCCR_q[0+:32];
+ if ((PCCR_inc_q[0] == 1'b1) && ((PCCR_q[0+:32] != 32'hffffffff) || (PCMR_q[1] == 1'b0)))
+ PCCR_n[0+:32] = PCCR_q[0+:32] + 1;
+ if (is_pccr == 1'b1)
+ case (csr_op_i)
+ CSR_OP_NONE:
+ ;
+ CSR_OP_WRITE: PCCR_n[0+:32] = csr_wdata_i;
+ CSR_OP_SET: PCCR_n[0+:32] = csr_wdata_i | PCCR_q[0+:32];
+ CSR_OP_CLEAR: PCCR_n[0+:32] = csr_wdata_i & ~PCCR_q[0+:32];
+ endcase
+ end
+ always @(*) begin
+ PCMR_n = PCMR_q;
+ PCER_n = PCER_q;
+ if (is_pcmr)
+ case (csr_op_i)
+ CSR_OP_NONE:
+ ;
+ CSR_OP_WRITE: PCMR_n = csr_wdata_i[1:0];
+ CSR_OP_SET: PCMR_n = csr_wdata_i[1:0] | PCMR_q;
+ CSR_OP_CLEAR: PCMR_n = csr_wdata_i[1:0] & ~PCMR_q;
+ endcase
+ if (is_pcer)
+ case (csr_op_i)
+ CSR_OP_NONE:
+ ;
+ CSR_OP_WRITE: PCER_n = csr_wdata_i[N_PERF_COUNTERS - 1:0];
+ CSR_OP_SET: PCER_n = csr_wdata_i[N_PERF_COUNTERS - 1:0] | PCER_q;
+ CSR_OP_CLEAR: PCER_n = csr_wdata_i[N_PERF_COUNTERS - 1:0] & ~PCER_q;
+ endcase
+ end
+ always @(posedge clk or negedge rst_n)
+ if (rst_n == 1'b0) begin
+ id_valid_q <= 1'b0;
+ PCER_q <= 1'sb0;
+ PCMR_q <= 2'h3;
+ begin : sv2v_autoblock_1
+ reg signed [31:0] i;
+ for (i = 0; i < N_PERF_REGS; i = i + 1)
+ begin
+ PCCR_q[i * 32+:32] <= 1'sb0;
+ PCCR_inc_q[i] <= 1'sb0;
+ end
+ end
+ end
+ else begin
+ id_valid_q <= id_valid_i;
+ PCER_q <= PCER_n;
+ PCMR_q <= PCMR_n;
+ begin : sv2v_autoblock_2
+ reg signed [31:0] i;
+ for (i = 0; i < N_PERF_REGS; i = i + 1)
+ begin
+ PCCR_q[i * 32+:32] <= PCCR_n[i * 32+:32];
+ PCCR_inc_q[i] <= PCCR_inc[i];
+ end
+ end
+ end
+endmodule
diff --git a/verilog/rtl/ips/zero-riscy/zeroriscy_debug_unit.v b/verilog/rtl/ips/zero-riscy/zeroriscy_debug_unit.v
new file mode 100644
index 0000000..8afbeb4
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/zeroriscy_debug_unit.v
@@ -0,0 +1,629 @@
+module zeroriscy_debug_unit
+#(
+ parameter REG_ADDR_WIDTH = 5
+)
+(
+ clk,
+ rst_n,
+ debug_req_i,
+ debug_gnt_o,
+ debug_rvalid_o,
+ debug_addr_i,
+ debug_we_i,
+ debug_wdata_i,
+ debug_rdata_o,
+ debug_halted_o,
+ debug_halt_i,
+ debug_resume_i,
+ settings_o,
+ trap_i,
+ exc_cause_i,
+ stall_o,
+ dbg_req_o,
+ dbg_ack_i,
+ regfile_rreq_o,
+ regfile_raddr_o,
+ regfile_rdata_i,
+ regfile_wreq_o,
+ regfile_waddr_o,
+ regfile_wdata_o,
+ csr_req_o,
+ csr_addr_o,
+ csr_we_o,
+ csr_wdata_o,
+ csr_rdata_i,
+ pc_if_i,
+ pc_id_i,
+ instr_valid_id_i,
+ sleeping_i,
+ jump_req_o,
+ jump_addr_o
+);
+parameter OPCODE_SYSTEM = 7'h73;
+parameter OPCODE_FENCE = 7'h0f;
+parameter OPCODE_OP = 7'h33;
+parameter OPCODE_OPIMM = 7'h13;
+parameter OPCODE_STORE = 7'h23;
+parameter OPCODE_LOAD = 7'h03;
+parameter OPCODE_BRANCH = 7'h63;
+parameter OPCODE_JALR = 7'h67;
+parameter OPCODE_JAL = 7'h6f;
+parameter OPCODE_AUIPC = 7'h17;
+parameter OPCODE_LUI = 7'h37;
+
+// those opcodes are now used for PULP custom instructions
+// parameter OPCODE_CUST0 = 7'h0b
+// parameter OPCODE_CUST1 = 7'h2b
+
+// PULP custom
+parameter OPCODE_LOAD_POST = 7'h0b;
+parameter OPCODE_STORE_POST = 7'h2b;
+parameter OPCODE_PULP_OP = 7'h5b;
+parameter OPCODE_VECOP = 7'h57;
+parameter OPCODE_HWLOOP = 7'h7b;
+
+parameter REGC_S1 = 2'b10;
+parameter REGC_RD = 2'b01;
+parameter REGC_ZERO = 2'b11;
+
+
+//////////////////////////////////////////////////////////////////////////////
+// _ _ _ _ ___ _ _ //
+// / \ | | | | | | / _ \ _ __ ___ _ __ __ _| |_(_) ___ _ __ ___ //
+// / _ \ | | | | | | | | | | '_ \ / _ \ '__/ _` | __| |/ _ \| '_ \/ __| //
+// / ___ \| |__| |_| | | |_| | |_) | __/ | | (_| | |_| | (_) | | | \__ \ //
+// /_/ \_\_____\___/ \___/| .__/ \___|_| \__,_|\__|_|\___/|_| |_|___/ //
+// |_| //
+//////////////////////////////////////////////////////////////////////////////
+
+parameter ALU_OP_WIDTH = 6;
+
+parameter ALU_ADD = 6'b011000;
+parameter ALU_SUB = 6'b011001;
+parameter ALU_ADDU = 6'b011010;
+parameter ALU_SUBU = 6'b011011;
+parameter ALU_ADDR = 6'b011100;
+parameter ALU_SUBR = 6'b011101;
+parameter ALU_ADDUR = 6'b011110;
+parameter ALU_SUBUR = 6'b011111;
+
+parameter ALU_XOR = 6'b101111;
+parameter ALU_OR = 6'b101110;
+parameter ALU_AND = 6'b010101;
+
+// Shifts
+parameter ALU_SRA = 6'b100100;
+parameter ALU_SRL = 6'b100101;
+parameter ALU_ROR = 6'b100110;
+parameter ALU_SLL = 6'b100111;
+
+// bit manipulation
+parameter ALU_BEXT = 6'b101000;
+parameter ALU_BEXTU = 6'b101001;
+parameter ALU_BINS = 6'b101010;
+parameter ALU_BCLR = 6'b101011;
+parameter ALU_BSET = 6'b101100;
+
+// Bit counting
+parameter ALU_FF1 = 6'b110110;
+parameter ALU_FL1 = 6'b110111;
+parameter ALU_CNT = 6'b110100;
+parameter ALU_CLB = 6'b110101;
+
+// Sign-/zero-extensions
+parameter ALU_EXTS = 6'b111110;
+parameter ALU_EXT = 6'b111111;
+
+// Comparisons
+parameter ALU_LTS = 6'b000000;
+parameter ALU_LTU = 6'b000001;
+parameter ALU_LES = 6'b000100;
+parameter ALU_LEU = 6'b000101;
+parameter ALU_GTS = 6'b001000;
+parameter ALU_GTU = 6'b001001;
+parameter ALU_GES = 6'b001010;
+parameter ALU_GEU = 6'b001011;
+parameter ALU_EQ = 6'b001100;
+parameter ALU_NE = 6'b001101;
+
+// Set Lower Than operations
+parameter ALU_SLTS = 6'b000010;
+parameter ALU_SLTU = 6'b000011;
+parameter ALU_SLETS = 6'b000110;
+parameter ALU_SLETU = 6'b000111;
+
+// Absolute value
+parameter ALU_ABS = 6'b010100;
+parameter ALU_CLIP = 6'b010110;
+parameter ALU_CLIPU = 6'b010111;
+
+// Insert/extract
+parameter ALU_INS = 6'b101101;
+
+// min/max
+parameter ALU_MIN = 6'b010000;
+parameter ALU_MINU = 6'b010001;
+parameter ALU_MAX = 6'b010010;
+parameter ALU_MAXU = 6'b010011;
+
+// div/rem
+parameter ALU_DIVU = 6'b110000; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_DIV = 6'b110001; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REMU = 6'b110010; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REM = 6'b110011; // bit 0 is used for signed mode, bit 1 is used for remdiv
+
+parameter ALU_SHUF = 6'b111010;
+parameter ALU_SHUF2 = 6'b111011;
+parameter ALU_PCKLO = 6'b111000;
+parameter ALU_PCKHI = 6'b111001;
+
+
+parameter MD_OP_MULL = 2'b00;
+parameter MD_OP_MULH = 2'b01;
+parameter MD_OP_DIV = 2'b10;
+parameter MD_OP_REM = 2'b11;
+
+// vector modes
+parameter VEC_MODE32 = 2'b00;
+parameter VEC_MODE16 = 2'b10;
+parameter VEC_MODE8 = 2'b11;
+
+
+/////////////////////////////////////////////////////////
+// ____ ____ ____ _ _ //
+// / ___/ ___| | _ \ ___ __ _(_)___| |_ ___ _ __ //
+// | | \___ \ | |_) / _ \/ _` | / __| __/ _ \ '__| //
+// | |___ ___) | | _ < __/ (_| | \__ \ || __/ | //
+// \____|____/ |_| \_\___|\__, |_|___/\__\___|_| //
+// |___/ //
+/////////////////////////////////////////////////////////
+
+// CSR operations
+parameter CSR_OP_NONE = 2'b00;
+parameter CSR_OP_WRITE = 2'b01;
+parameter CSR_OP_SET = 2'b10;
+parameter CSR_OP_CLEAR = 2'b11;
+
+
+// SPR for debugger, not accessible by CPU
+parameter SP_DVR0 = 16'h3000;
+parameter SP_DCR0 = 16'h3008;
+parameter SP_DMR1 = 16'h3010;
+parameter SP_DMR2 = 16'h3011;
+
+parameter SP_DVR_MSB = 8'h00;
+parameter SP_DCR_MSB = 8'h01;
+parameter SP_DMR_MSB = 8'h02;
+parameter SP_DSR_MSB = 8'h04;
+
+// Privileged mode
+typedef enum logic[1:0] {
+ PRIV_LVL_M = 2'b11,
+ PRIV_LVL_H = 2'b10,
+ PRIV_LVL_S = 2'b01,
+ PRIV_LVL_U = 2'b00
+} PrivLvl_t;
+
+///////////////////////////////////////////////
+// ___ ____ ____ _ //
+// |_ _| _ \ / ___|| |_ __ _ __ _ ___ //
+// | || | | | \___ \| __/ _` |/ _` |/ _ \ //
+// | || |_| | ___) | || (_| | (_| | __/ //
+// |___|____/ |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// forwarding operand mux
+parameter SEL_REGFILE = 2'b00;
+parameter SEL_FW_EX = 2'b01;
+parameter SEL_FW_WB = 2'b10;
+parameter SEL_MISALIGNED = 2'b11;
+
+// operand a selection
+parameter OP_A_REGA_OR_FWD = 3'b000;
+parameter OP_A_CURRPC = 3'b001;
+parameter OP_A_IMM = 3'b010;
+parameter OP_A_REGB_OR_FWD = 3'b011;
+parameter OP_A_REGC_OR_FWD = 3'b100;
+
+// immediate a selection
+parameter IMMA_Z = 1'b0;
+parameter IMMA_ZERO = 1'b1;
+
+// operand b selection
+parameter OP_B_REGB_OR_FWD = 3'b000;
+parameter OP_B_REGC_OR_FWD = 3'b001;
+parameter OP_B_IMM = 3'b010;
+parameter OP_B_REGA_OR_FWD = 3'b011;
+parameter OP_B_BMASK = 3'b100;
+parameter OP_B_ZERO = 3'b101;
+
+// immediate b selection
+parameter IMMB_I = 4'b0000;
+parameter IMMB_S = 4'b0001;
+parameter IMMB_U = 4'b0010;
+parameter IMMB_PCINCR = 4'b0011;
+parameter IMMB_S2 = 4'b0100;
+parameter IMMB_S3 = 4'b0101;
+parameter IMMB_VS = 4'b0110;
+parameter IMMB_VU = 4'b0111;
+parameter IMMB_SHUF = 4'b1000;
+parameter IMMB_CLIP = 4'b1001;
+parameter IMMB_BI = 4'b1011;
+parameter IMMB_UJ = 4'b1100;
+parameter IMMB_SB = 4'b1101;
+
+// bit mask selection
+parameter BMASK_A_ZERO = 1'b0;
+parameter BMASK_A_S3 = 1'b1;
+
+parameter BMASK_B_S2 = 2'b00;
+parameter BMASK_B_S3 = 2'b01;
+parameter BMASK_B_ZERO = 2'b10;
+parameter BMASK_B_ONE = 2'b11;
+
+parameter BMASK_A_REG = 1'b0;
+parameter BMASK_A_IMM = 1'b1;
+parameter BMASK_B_REG = 1'b0;
+parameter BMASK_B_IMM = 1'b1;
+
+
+
+///////////////////////////////////////////////
+// ___ _____ ____ _ //
+// |_ _| ___| / ___|| |_ __ _ __ _ ___ //
+// | || |_ \___ \| __/ _` |/ _` |/ _ \ //
+// | || _| ___) | || (_| | (_| | __/ //
+// |___|_| |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// PC mux selector defines
+parameter PC_BOOT = 3'b000;
+parameter PC_JUMP = 3'b010;
+parameter PC_EXCEPTION = 3'b100;
+parameter PC_ERET = 3'b101;
+parameter PC_DBG_NPC = 3'b111;
+
+// Exception PC mux selector defines
+parameter EXC_PC_ILLINSN = 2'b00;
+parameter EXC_PC_ECALL = 2'b01;
+parameter EXC_PC_LOAD = 2'b10;
+parameter EXC_PC_STORE = 2'b10;
+parameter EXC_PC_IRQ = 2'b11;
+
+// Exception Cause
+parameter EXC_CAUSE_ILLEGAL_INSN = 6'h02;
+parameter EXC_CAUSE_BREAKPOINT = 6'h03;
+parameter EXC_CAUSE_ECALL_MMODE = 6'h0B;
+
+// Exceptions offsets
+// target address = {boot_addr[31:8], EXC_OFF} (boot_addr must be 32 BYTE aligned!)
+// offset 00 to 7e is used for external interrupts
+parameter EXC_OFF_RST = 8'h80;
+parameter EXC_OFF_ILLINSN = 8'h84;
+parameter EXC_OFF_ECALL = 8'h88;
+parameter EXC_OFF_LSUERR = 8'h8c;
+
+
+// Debug module
+parameter DBG_SETS_W = 6;
+
+parameter DBG_SETS_IRQ = 5;
+parameter DBG_SETS_ECALL = 4;
+parameter DBG_SETS_EILL = 3;
+parameter DBG_SETS_ELSU = 2;
+parameter DBG_SETS_EBRK = 1;
+parameter DBG_SETS_SSTE = 0;
+
+parameter DBG_CAUSE_HALT = 6'h1F;
+ //parameter REG_ADDR_WIDTH = 5;
+ input wire clk;
+ input wire rst_n;
+ input wire debug_req_i;
+ output reg debug_gnt_o;
+ output reg debug_rvalid_o;
+ input wire [14:0] debug_addr_i;
+ input wire debug_we_i;
+ input wire [31:0] debug_wdata_i;
+ output reg [31:0] debug_rdata_o;
+ output reg debug_halted_o;
+ input wire debug_halt_i;
+ input wire debug_resume_i;
+ output wire [DBG_SETS_W - 1:0] settings_o;
+ input wire trap_i;
+ input wire [5:0] exc_cause_i;
+ output reg stall_o;
+ output reg dbg_req_o;
+ input wire dbg_ack_i;
+ output wire regfile_rreq_o;
+ output wire [REG_ADDR_WIDTH - 1:0] regfile_raddr_o;
+ input wire [31:0] regfile_rdata_i;
+ output wire regfile_wreq_o;
+ output wire [REG_ADDR_WIDTH - 1:0] regfile_waddr_o;
+ output wire [31:0] regfile_wdata_o;
+ output wire csr_req_o;
+ output wire [11:0] csr_addr_o;
+ output reg csr_we_o;
+ output wire [31:0] csr_wdata_o;
+ input wire [31:0] csr_rdata_i;
+ input wire [31:0] pc_if_i;
+ input wire [31:0] pc_id_i;
+ input wire instr_valid_id_i;
+ input wire sleeping_i;
+ output wire jump_req_o;
+ output wire [31:0] jump_addr_o;
+ reg [2:0] rdata_sel_q;
+ reg [2:0] rdata_sel_n;
+ reg [0:0] state_q;
+ reg [0:0] state_n;
+ reg [DBG_SETS_W - 1:0] settings_q;
+ reg [DBG_SETS_W - 1:0] settings_n;
+ reg [14:0] addr_q;
+ reg [31:0] wdata_q;
+ reg regfile_rreq_q;
+ reg regfile_rreq_n;
+ reg jump_req_q;
+ reg jump_req_n;
+ reg csr_req_q;
+ reg csr_req_n;
+ reg regfile_wreq;
+ reg [1:0] stall_cs;
+ reg [1:0] stall_ns;
+ reg [31:0] dbg_rdata;
+ reg dbg_resume;
+ reg dbg_halt;
+ reg [5:0] dbg_cause_q;
+ reg [5:0] dbg_cause_n;
+ reg dbg_ssth_q;
+ reg dbg_ssth_n;
+ reg ssth_clear;
+ wire [31:0] ppc_int;
+ wire [31:0] npc_int;
+ always @(*) begin
+ rdata_sel_n = 3'd0;
+ state_n = 1'd0;
+ debug_gnt_o = 1'b0;
+ regfile_rreq_n = 1'b0;
+ regfile_wreq = 1'b0;
+ csr_req_n = 1'b0;
+ csr_we_o = 1'b0;
+ jump_req_n = 1'b0;
+ dbg_resume = 1'b0;
+ dbg_halt = 1'b0;
+ settings_n = settings_q;
+ ssth_clear = 1'b0;
+ if (debug_req_i)
+ if (debug_we_i) begin
+ if (debug_addr_i[14]) begin
+ if (state_q == 1'd0) begin
+ debug_gnt_o = 1'b0;
+ state_n = 1'd1;
+ if (debug_halted_o)
+ csr_req_n = 1'b1;
+ end
+ else begin
+ debug_gnt_o = 1'b1;
+ state_n = 1'd0;
+ csr_we_o = 1'b1;
+ end
+ end
+ else
+ case (debug_addr_i[13:8])
+ 6'b000000: begin
+ debug_gnt_o = 1'b1;
+ case (debug_addr_i[6:2])
+ 5'b00000: begin
+ if (debug_wdata_i[16]) begin
+ if (~debug_halted_o)
+ dbg_halt = 1'b1;
+ end
+ else if (debug_halted_o)
+ dbg_resume = 1'b1;
+ settings_n[DBG_SETS_SSTE] = debug_wdata_i[0];
+ end
+ 5'b00001: ssth_clear = debug_wdata_i[0];
+ 5'b00010: begin
+ settings_n[DBG_SETS_ECALL] = debug_wdata_i[11];
+ settings_n[DBG_SETS_ELSU] = debug_wdata_i[7] | debug_wdata_i[5];
+ settings_n[DBG_SETS_EBRK] = debug_wdata_i[3];
+ settings_n[DBG_SETS_EILL] = debug_wdata_i[2];
+ end
+ default:
+ ;
+ endcase
+ end
+ 6'b100000: begin
+ debug_gnt_o = 1'b1;
+ if (debug_halted_o)
+ case (debug_addr_i[6:2])
+ 5'b00000: jump_req_n = 1'b1;
+ default:
+ ;
+ endcase
+ end
+ 6'b000100: begin
+ debug_gnt_o = 1'b1;
+ if (debug_halted_o)
+ regfile_wreq = 1'b1;
+ end
+ default: debug_gnt_o = 1'b1;
+ endcase
+ end
+ else if (debug_addr_i[14]) begin
+ debug_gnt_o = 1'b1;
+ if (debug_halted_o) begin
+ csr_req_n = 1'b1;
+ rdata_sel_n = 3'd1;
+ end
+ end
+ else
+ case (debug_addr_i[13:8])
+ 6'b000000: begin
+ debug_gnt_o = 1'b1;
+ rdata_sel_n = 3'd3;
+ end
+ 6'b100000: begin
+ debug_gnt_o = 1'b1;
+ rdata_sel_n = 3'd4;
+ end
+ 6'b000100: begin
+ debug_gnt_o = 1'b1;
+ if (debug_halted_o) begin
+ regfile_rreq_n = 1'b1;
+ rdata_sel_n = 3'd2;
+ end
+ end
+ default: debug_gnt_o = 1'b1;
+ endcase
+ end
+ always @(*) begin
+ dbg_rdata = 1'sb0;
+ case (rdata_sel_q)
+ 3'd3:
+ case (addr_q[6:2])
+ 5'h00: dbg_rdata[31:0] = {15'b000000000000000, debug_halted_o, 15'b000000000000000, settings_q[DBG_SETS_SSTE]};
+ 5'h01: dbg_rdata[31:0] = {15'b000000000000000, sleeping_i, 15'b000000000000000, dbg_ssth_q};
+ 5'h02: begin
+ dbg_rdata[31:16] = 1'sb0;
+ dbg_rdata[15:12] = 1'sb0;
+ dbg_rdata[11] = settings_q[DBG_SETS_ECALL];
+ dbg_rdata[10:8] = 1'sb0;
+ dbg_rdata[7] = settings_q[DBG_SETS_ELSU];
+ dbg_rdata[6] = 1'b0;
+ dbg_rdata[5] = settings_q[DBG_SETS_ELSU];
+ dbg_rdata[4] = 1'b0;
+ dbg_rdata[3] = settings_q[DBG_SETS_EBRK];
+ dbg_rdata[2] = settings_q[DBG_SETS_EILL];
+ dbg_rdata[1:0] = 1'sb0;
+ end
+ 5'h03: dbg_rdata = {dbg_cause_q[5], 26'b00000000000000000000000000, dbg_cause_q[4:0]};
+ 5'h10: dbg_rdata = 1'sb0;
+ 5'h12: dbg_rdata = 1'sb0;
+ 5'h14: dbg_rdata = 1'sb0;
+ 5'h16: dbg_rdata = 1'sb0;
+ 5'h18: dbg_rdata = 1'sb0;
+ 5'h1a: dbg_rdata = 1'sb0;
+ 5'h1c: dbg_rdata = 1'sb0;
+ 5'h1e: dbg_rdata = 1'sb0;
+ default:
+ ;
+ endcase
+ 3'd4:
+ case (addr_q[2:2])
+ 1'b0: dbg_rdata = npc_int;
+ 1'b1: dbg_rdata = ppc_int;
+ default:
+ ;
+ endcase
+ default:
+ ;
+ endcase
+ end
+ always @(*) begin
+ debug_rdata_o = 1'sb0;
+ case (rdata_sel_q)
+ 3'd1: debug_rdata_o = csr_rdata_i;
+ 3'd2: debug_rdata_o = regfile_rdata_i;
+ 3'd3: debug_rdata_o = dbg_rdata;
+ 3'd4: debug_rdata_o = dbg_rdata;
+ default:
+ ;
+ endcase
+ end
+ always @(posedge clk or negedge rst_n)
+ if (~rst_n)
+ debug_rvalid_o <= 1'b0;
+ else
+ debug_rvalid_o <= debug_gnt_o;
+ always @(*) begin
+ stall_ns = stall_cs;
+ dbg_req_o = 1'b0;
+ stall_o = 1'b0;
+ debug_halted_o = 1'b0;
+ dbg_cause_n = dbg_cause_q;
+ dbg_ssth_n = dbg_ssth_q;
+ case (stall_cs)
+ 2'd0: begin
+ dbg_ssth_n = 1'b0;
+ if ((dbg_halt | debug_halt_i) | trap_i) begin
+ dbg_req_o = 1'b1;
+ stall_ns = 2'd1;
+ if (trap_i) begin
+ if (settings_q[DBG_SETS_SSTE])
+ dbg_ssth_n = 1'b1;
+ dbg_cause_n = exc_cause_i;
+ end
+ else
+ dbg_cause_n = DBG_CAUSE_HALT;
+ end
+ end
+ 2'd1: begin
+ dbg_req_o = 1'b1;
+ if (dbg_ack_i)
+ stall_ns = 2'd2;
+ if (dbg_resume | debug_resume_i)
+ stall_ns = 2'd0;
+ end
+ 2'd2: begin
+ stall_o = 1'b1;
+ debug_halted_o = 1'b1;
+ if (dbg_resume | debug_resume_i) begin
+ stall_ns = 2'd0;
+ stall_o = 1'b0;
+ end
+ end
+ endcase
+ if (ssth_clear)
+ dbg_ssth_n = 1'b0;
+ end
+ always @(posedge clk or negedge rst_n)
+ if (~rst_n) begin
+ stall_cs <= 2'd0;
+ dbg_cause_q <= DBG_CAUSE_HALT;
+ dbg_ssth_q <= 1'b0;
+ end
+ else begin
+ stall_cs <= stall_ns;
+ dbg_cause_q <= dbg_cause_n;
+ dbg_ssth_q <= dbg_ssth_n;
+ end
+ assign ppc_int = pc_id_i;
+ assign npc_int = pc_if_i;
+ always @(posedge clk or negedge rst_n)
+ if (~rst_n) begin
+ addr_q <= 1'sb0;
+ wdata_q <= 1'sb0;
+ state_q <= 1'd0;
+ rdata_sel_q <= 3'd0;
+ regfile_rreq_q <= 1'b0;
+ csr_req_q <= 1'b0;
+ jump_req_q <= 1'b0;
+ settings_q <= 1'b0;
+ end
+ else begin
+ settings_q <= settings_n;
+ if (debug_req_i) begin
+ addr_q <= debug_addr_i;
+ wdata_q <= debug_wdata_i;
+ state_q <= state_n;
+ end
+ if (debug_req_i | debug_rvalid_o) begin
+ regfile_rreq_q <= regfile_rreq_n;
+ csr_req_q <= csr_req_n;
+ jump_req_q <= jump_req_n;
+ rdata_sel_q <= rdata_sel_n;
+ end
+ end
+ assign regfile_rreq_o = regfile_rreq_q;
+ assign regfile_raddr_o = addr_q[6:2];
+ assign regfile_wreq_o = regfile_wreq;
+ assign regfile_waddr_o = debug_addr_i[6:2];
+ assign regfile_wdata_o = debug_wdata_i;
+ assign csr_req_o = csr_req_q;
+ assign csr_addr_o = addr_q[13:2];
+ assign csr_wdata_o = wdata_q;
+ assign jump_req_o = jump_req_q;
+ assign jump_addr_o = wdata_q;
+ assign settings_o = settings_q;
+endmodule
diff --git a/verilog/rtl/ips/zero-riscy/zeroriscy_decoder.v b/verilog/rtl/ips/zero-riscy/zeroriscy_decoder.v
new file mode 100644
index 0000000..38b064a
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/zeroriscy_decoder.v
@@ -0,0 +1,663 @@
+module zeroriscy_decoder
+#(
+ parameter RV32M = 1
+)
+(
+ deassert_we_i,
+ data_misaligned_i,
+ branch_mux_i,
+ jump_mux_i,
+ illegal_insn_o,
+ ebrk_insn_o,
+ mret_insn_o,
+ ecall_insn_o,
+ pipe_flush_o,
+ instr_rdata_i,
+ illegal_c_insn_i,
+ alu_operator_o,
+ alu_op_a_mux_sel_o,
+ alu_op_b_mux_sel_o,
+ imm_a_mux_sel_o,
+ imm_b_mux_sel_o,
+ mult_int_en_o,
+ div_int_en_o,
+ multdiv_operator_o,
+ multdiv_signed_mode_o,
+ regfile_we_o,
+ csr_access_o,
+ csr_op_o,
+ csr_status_o,
+ data_req_o,
+ data_we_o,
+ data_type_o,
+ data_sign_extension_o,
+ data_reg_offset_o,
+ data_load_event_o,
+ jump_in_id_o,
+ branch_in_id_o
+);
+parameter OPCODE_SYSTEM = 7'h73;
+parameter OPCODE_FENCE = 7'h0f;
+parameter OPCODE_OP = 7'h33;
+parameter OPCODE_OPIMM = 7'h13;
+parameter OPCODE_STORE = 7'h23;
+parameter OPCODE_LOAD = 7'h03;
+parameter OPCODE_BRANCH = 7'h63;
+parameter OPCODE_JALR = 7'h67;
+parameter OPCODE_JAL = 7'h6f;
+parameter OPCODE_AUIPC = 7'h17;
+parameter OPCODE_LUI = 7'h37;
+
+// those opcodes are now used for PULP custom instructions
+// parameter OPCODE_CUST0 = 7'h0b
+// parameter OPCODE_CUST1 = 7'h2b
+
+// PULP custom
+parameter OPCODE_LOAD_POST = 7'h0b;
+parameter OPCODE_STORE_POST = 7'h2b;
+parameter OPCODE_PULP_OP = 7'h5b;
+parameter OPCODE_VECOP = 7'h57;
+parameter OPCODE_HWLOOP = 7'h7b;
+
+parameter REGC_S1 = 2'b10;
+parameter REGC_RD = 2'b01;
+parameter REGC_ZERO = 2'b11;
+
+
+//////////////////////////////////////////////////////////////////////////////
+// _ _ _ _ ___ _ _ //
+// / \ | | | | | | / _ \ _ __ ___ _ __ __ _| |_(_) ___ _ __ ___ //
+// / _ \ | | | | | | | | | | '_ \ / _ \ '__/ _` | __| |/ _ \| '_ \/ __| //
+// / ___ \| |__| |_| | | |_| | |_) | __/ | | (_| | |_| | (_) | | | \__ \ //
+// /_/ \_\_____\___/ \___/| .__/ \___|_| \__,_|\__|_|\___/|_| |_|___/ //
+// |_| //
+//////////////////////////////////////////////////////////////////////////////
+
+parameter ALU_OP_WIDTH = 6;
+
+parameter ALU_ADD = 6'b011000;
+parameter ALU_SUB = 6'b011001;
+parameter ALU_ADDU = 6'b011010;
+parameter ALU_SUBU = 6'b011011;
+parameter ALU_ADDR = 6'b011100;
+parameter ALU_SUBR = 6'b011101;
+parameter ALU_ADDUR = 6'b011110;
+parameter ALU_SUBUR = 6'b011111;
+
+parameter ALU_XOR = 6'b101111;
+parameter ALU_OR = 6'b101110;
+parameter ALU_AND = 6'b010101;
+
+// Shifts
+parameter ALU_SRA = 6'b100100;
+parameter ALU_SRL = 6'b100101;
+parameter ALU_ROR = 6'b100110;
+parameter ALU_SLL = 6'b100111;
+
+// bit manipulation
+parameter ALU_BEXT = 6'b101000;
+parameter ALU_BEXTU = 6'b101001;
+parameter ALU_BINS = 6'b101010;
+parameter ALU_BCLR = 6'b101011;
+parameter ALU_BSET = 6'b101100;
+
+// Bit counting
+parameter ALU_FF1 = 6'b110110;
+parameter ALU_FL1 = 6'b110111;
+parameter ALU_CNT = 6'b110100;
+parameter ALU_CLB = 6'b110101;
+
+// Sign-/zero-extensions
+parameter ALU_EXTS = 6'b111110;
+parameter ALU_EXT = 6'b111111;
+
+// Comparisons
+parameter ALU_LTS = 6'b000000;
+parameter ALU_LTU = 6'b000001;
+parameter ALU_LES = 6'b000100;
+parameter ALU_LEU = 6'b000101;
+parameter ALU_GTS = 6'b001000;
+parameter ALU_GTU = 6'b001001;
+parameter ALU_GES = 6'b001010;
+parameter ALU_GEU = 6'b001011;
+parameter ALU_EQ = 6'b001100;
+parameter ALU_NE = 6'b001101;
+
+// Set Lower Than operations
+parameter ALU_SLTS = 6'b000010;
+parameter ALU_SLTU = 6'b000011;
+parameter ALU_SLETS = 6'b000110;
+parameter ALU_SLETU = 6'b000111;
+
+// Absolute value
+parameter ALU_ABS = 6'b010100;
+parameter ALU_CLIP = 6'b010110;
+parameter ALU_CLIPU = 6'b010111;
+
+// Insert/extract
+parameter ALU_INS = 6'b101101;
+
+// min/max
+parameter ALU_MIN = 6'b010000;
+parameter ALU_MINU = 6'b010001;
+parameter ALU_MAX = 6'b010010;
+parameter ALU_MAXU = 6'b010011;
+
+// div/rem
+parameter ALU_DIVU = 6'b110000; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_DIV = 6'b110001; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REMU = 6'b110010; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REM = 6'b110011; // bit 0 is used for signed mode, bit 1 is used for remdiv
+
+parameter ALU_SHUF = 6'b111010;
+parameter ALU_SHUF2 = 6'b111011;
+parameter ALU_PCKLO = 6'b111000;
+parameter ALU_PCKHI = 6'b111001;
+
+
+parameter MD_OP_MULL = 2'b00;
+parameter MD_OP_MULH = 2'b01;
+parameter MD_OP_DIV = 2'b10;
+parameter MD_OP_REM = 2'b11;
+
+// vector modes
+parameter VEC_MODE32 = 2'b00;
+parameter VEC_MODE16 = 2'b10;
+parameter VEC_MODE8 = 2'b11;
+
+
+/////////////////////////////////////////////////////////
+// ____ ____ ____ _ _ //
+// / ___/ ___| | _ \ ___ __ _(_)___| |_ ___ _ __ //
+// | | \___ \ | |_) / _ \/ _` | / __| __/ _ \ '__| //
+// | |___ ___) | | _ < __/ (_| | \__ \ || __/ | //
+// \____|____/ |_| \_\___|\__, |_|___/\__\___|_| //
+// |___/ //
+/////////////////////////////////////////////////////////
+
+// CSR operations
+parameter CSR_OP_NONE = 2'b00;
+parameter CSR_OP_WRITE = 2'b01;
+parameter CSR_OP_SET = 2'b10;
+parameter CSR_OP_CLEAR = 2'b11;
+
+
+// SPR for debugger, not accessible by CPU
+parameter SP_DVR0 = 16'h3000;
+parameter SP_DCR0 = 16'h3008;
+parameter SP_DMR1 = 16'h3010;
+parameter SP_DMR2 = 16'h3011;
+
+parameter SP_DVR_MSB = 8'h00;
+parameter SP_DCR_MSB = 8'h01;
+parameter SP_DMR_MSB = 8'h02;
+parameter SP_DSR_MSB = 8'h04;
+
+// Privileged mode
+typedef enum logic[1:0] {
+ PRIV_LVL_M = 2'b11,
+ PRIV_LVL_H = 2'b10,
+ PRIV_LVL_S = 2'b01,
+ PRIV_LVL_U = 2'b00
+} PrivLvl_t;
+
+///////////////////////////////////////////////
+// ___ ____ ____ _ //
+// |_ _| _ \ / ___|| |_ __ _ __ _ ___ //
+// | || | | | \___ \| __/ _` |/ _` |/ _ \ //
+// | || |_| | ___) | || (_| | (_| | __/ //
+// |___|____/ |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// forwarding operand mux
+parameter SEL_REGFILE = 2'b00;
+parameter SEL_FW_EX = 2'b01;
+parameter SEL_FW_WB = 2'b10;
+parameter SEL_MISALIGNED = 2'b11;
+
+// operand a selection
+parameter OP_A_REGA_OR_FWD = 3'b000;
+parameter OP_A_CURRPC = 3'b001;
+parameter OP_A_IMM = 3'b010;
+parameter OP_A_REGB_OR_FWD = 3'b011;
+parameter OP_A_REGC_OR_FWD = 3'b100;
+
+// immediate a selection
+parameter IMMA_Z = 1'b0;
+parameter IMMA_ZERO = 1'b1;
+
+// operand b selection
+parameter OP_B_REGB_OR_FWD = 3'b000;
+parameter OP_B_REGC_OR_FWD = 3'b001;
+parameter OP_B_IMM = 3'b010;
+parameter OP_B_REGA_OR_FWD = 3'b011;
+parameter OP_B_BMASK = 3'b100;
+parameter OP_B_ZERO = 3'b101;
+
+// immediate b selection
+parameter IMMB_I = 4'b0000;
+parameter IMMB_S = 4'b0001;
+parameter IMMB_U = 4'b0010;
+parameter IMMB_PCINCR = 4'b0011;
+parameter IMMB_S2 = 4'b0100;
+parameter IMMB_S3 = 4'b0101;
+parameter IMMB_VS = 4'b0110;
+parameter IMMB_VU = 4'b0111;
+parameter IMMB_SHUF = 4'b1000;
+parameter IMMB_CLIP = 4'b1001;
+parameter IMMB_BI = 4'b1011;
+parameter IMMB_UJ = 4'b1100;
+parameter IMMB_SB = 4'b1101;
+
+// bit mask selection
+parameter BMASK_A_ZERO = 1'b0;
+parameter BMASK_A_S3 = 1'b1;
+
+parameter BMASK_B_S2 = 2'b00;
+parameter BMASK_B_S3 = 2'b01;
+parameter BMASK_B_ZERO = 2'b10;
+parameter BMASK_B_ONE = 2'b11;
+
+parameter BMASK_A_REG = 1'b0;
+parameter BMASK_A_IMM = 1'b1;
+parameter BMASK_B_REG = 1'b0;
+parameter BMASK_B_IMM = 1'b1;
+
+
+
+///////////////////////////////////////////////
+// ___ _____ ____ _ //
+// |_ _| ___| / ___|| |_ __ _ __ _ ___ //
+// | || |_ \___ \| __/ _` |/ _` |/ _ \ //
+// | || _| ___) | || (_| | (_| | __/ //
+// |___|_| |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// PC mux selector defines
+parameter PC_BOOT = 3'b000;
+parameter PC_JUMP = 3'b010;
+parameter PC_EXCEPTION = 3'b100;
+parameter PC_ERET = 3'b101;
+parameter PC_DBG_NPC = 3'b111;
+
+// Exception PC mux selector defines
+parameter EXC_PC_ILLINSN = 2'b00;
+parameter EXC_PC_ECALL = 2'b01;
+parameter EXC_PC_LOAD = 2'b10;
+parameter EXC_PC_STORE = 2'b10;
+parameter EXC_PC_IRQ = 2'b11;
+
+// Exception Cause
+parameter EXC_CAUSE_ILLEGAL_INSN = 6'h02;
+parameter EXC_CAUSE_BREAKPOINT = 6'h03;
+parameter EXC_CAUSE_ECALL_MMODE = 6'h0B;
+
+// Exceptions offsets
+// target address = {boot_addr[31:8], EXC_OFF} (boot_addr must be 32 BYTE aligned!)
+// offset 00 to 7e is used for external interrupts
+parameter EXC_OFF_RST = 8'h80;
+parameter EXC_OFF_ILLINSN = 8'h84;
+parameter EXC_OFF_ECALL = 8'h88;
+parameter EXC_OFF_LSUERR = 8'h8c;
+
+
+// Debug module
+parameter DBG_SETS_W = 6;
+
+parameter DBG_SETS_IRQ = 5;
+parameter DBG_SETS_ECALL = 4;
+parameter DBG_SETS_EILL = 3;
+parameter DBG_SETS_ELSU = 2;
+parameter DBG_SETS_EBRK = 1;
+parameter DBG_SETS_SSTE = 0;
+
+parameter DBG_CAUSE_HALT = 6'h1F;
+ //parameter RV32M = 1;
+ input wire deassert_we_i;
+ input wire data_misaligned_i;
+ input wire branch_mux_i;
+ input wire jump_mux_i;
+ output reg illegal_insn_o;
+ output reg ebrk_insn_o;
+ output reg mret_insn_o;
+ output reg ecall_insn_o;
+ output reg pipe_flush_o;
+ input wire [31:0] instr_rdata_i;
+ input wire illegal_c_insn_i;
+ output reg [ALU_OP_WIDTH - 1:0] alu_operator_o;
+ output reg [2:0] alu_op_a_mux_sel_o;
+ output reg [2:0] alu_op_b_mux_sel_o;
+ output reg [0:0] imm_a_mux_sel_o;
+ output reg [3:0] imm_b_mux_sel_o;
+ output wire mult_int_en_o;
+ output wire div_int_en_o;
+ output reg [1:0] multdiv_operator_o;
+ output reg [1:0] multdiv_signed_mode_o;
+ output wire regfile_we_o;
+ output reg csr_access_o;
+ output wire [1:0] csr_op_o;
+ output reg csr_status_o;
+ output wire data_req_o;
+ output reg data_we_o;
+ output reg [1:0] data_type_o;
+ output reg data_sign_extension_o;
+ output reg [1:0] data_reg_offset_o;
+ output reg data_load_event_o;
+ output wire jump_in_id_o;
+ output wire branch_in_id_o;
+ reg regfile_we;
+ reg data_req;
+ reg mult_int_en;
+ reg div_int_en;
+ reg branch_in_id;
+ reg jump_in_id;
+ reg [1:0] csr_op;
+ reg csr_illegal;
+ always @(*) begin
+ jump_in_id = 1'b0;
+ branch_in_id = 1'b0;
+ alu_operator_o = ALU_SLTU;
+ alu_op_a_mux_sel_o = OP_A_REGA_OR_FWD;
+ alu_op_b_mux_sel_o = OP_B_REGB_OR_FWD;
+ imm_a_mux_sel_o = IMMA_ZERO;
+ imm_b_mux_sel_o = IMMB_I;
+ mult_int_en = 1'b0;
+ div_int_en = 1'b0;
+ multdiv_operator_o = MD_OP_MULL;
+ multdiv_signed_mode_o = 2'b00;
+ regfile_we = 1'b0;
+ csr_access_o = 1'b0;
+ csr_status_o = 1'b0;
+ csr_illegal = 1'b0;
+ csr_op = CSR_OP_NONE;
+ data_we_o = 1'b0;
+ data_type_o = 2'b00;
+ data_sign_extension_o = 1'b0;
+ data_reg_offset_o = 2'b00;
+ data_req = 1'b0;
+ data_load_event_o = 1'b0;
+ illegal_insn_o = 1'b0;
+ ebrk_insn_o = 1'b0;
+ mret_insn_o = 1'b0;
+ ecall_insn_o = 1'b0;
+ pipe_flush_o = 1'b0;
+ case (instr_rdata_i[6:0])
+ OPCODE_JAL: begin
+ jump_in_id = 1'b1;
+ if (jump_mux_i) begin
+ alu_op_a_mux_sel_o = OP_A_CURRPC;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_b_mux_sel_o = IMMB_UJ;
+ alu_operator_o = ALU_ADD;
+ regfile_we = 1'b0;
+ end
+ else begin
+ alu_op_a_mux_sel_o = OP_A_CURRPC;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_b_mux_sel_o = IMMB_PCINCR;
+ alu_operator_o = ALU_ADD;
+ regfile_we = 1'b1;
+ end
+ end
+ OPCODE_JALR: begin
+ jump_in_id = 1'b1;
+ if (jump_mux_i) begin
+ alu_op_a_mux_sel_o = OP_A_REGA_OR_FWD;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_b_mux_sel_o = IMMB_I;
+ alu_operator_o = ALU_ADD;
+ regfile_we = 1'b0;
+ end
+ else begin
+ alu_op_a_mux_sel_o = OP_A_CURRPC;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_b_mux_sel_o = IMMB_PCINCR;
+ alu_operator_o = ALU_ADD;
+ regfile_we = 1'b1;
+ end
+ if (instr_rdata_i[14:12] != 3'b000) begin
+ jump_in_id = 1'b0;
+ regfile_we = 1'b0;
+ illegal_insn_o = 1'b1;
+ end
+ end
+ OPCODE_BRANCH: begin
+ branch_in_id = 1'b1;
+ if (branch_mux_i)
+ case (instr_rdata_i[14:12])
+ 3'b000: alu_operator_o = ALU_EQ;
+ 3'b001: alu_operator_o = ALU_NE;
+ 3'b100: alu_operator_o = ALU_LTS;
+ 3'b101: alu_operator_o = ALU_GES;
+ 3'b110: alu_operator_o = ALU_LTU;
+ 3'b111: alu_operator_o = ALU_GEU;
+ default: illegal_insn_o = 1'b1;
+ endcase
+ else begin
+ alu_op_a_mux_sel_o = OP_A_CURRPC;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_b_mux_sel_o = IMMB_SB;
+ alu_operator_o = ALU_ADD;
+ regfile_we = 1'b0;
+ end
+ end
+ OPCODE_STORE: begin
+ data_req = 1'b1;
+ data_we_o = 1'b1;
+ alu_operator_o = ALU_ADD;
+ if (instr_rdata_i[14] == 1'b0) begin
+ imm_b_mux_sel_o = IMMB_S;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ end
+ else begin
+ data_req = 1'b0;
+ data_we_o = 1'b0;
+ illegal_insn_o = 1'b1;
+ end
+ case (instr_rdata_i[13:12])
+ 2'b00: data_type_o = 2'b10;
+ 2'b01: data_type_o = 2'b01;
+ 2'b10: data_type_o = 2'b00;
+ default: begin
+ data_req = 1'b0;
+ data_we_o = 1'b0;
+ illegal_insn_o = 1'b1;
+ end
+ endcase
+ end
+ OPCODE_LOAD: begin
+ data_req = 1'b1;
+ regfile_we = 1'b1;
+ data_type_o = 2'b00;
+ alu_operator_o = ALU_ADD;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_b_mux_sel_o = IMMB_I;
+ data_sign_extension_o = ~instr_rdata_i[14];
+ case (instr_rdata_i[13:12])
+ 2'b00: data_type_o = 2'b10;
+ 2'b01: data_type_o = 2'b01;
+ 2'b10: data_type_o = 2'b00;
+ default: data_type_o = 2'b00;
+ endcase
+ if (instr_rdata_i[14:12] == 3'b111) begin
+ alu_op_b_mux_sel_o = OP_B_REGB_OR_FWD;
+ data_sign_extension_o = ~instr_rdata_i[30];
+ case (instr_rdata_i[31:25])
+ 7'b0000000, 7'b0100000: data_type_o = 2'b10;
+ 7'b0001000, 7'b0101000: data_type_o = 2'b01;
+ 7'b0010000: data_type_o = 2'b00;
+ default: illegal_insn_o = 1'b1;
+ endcase
+ end
+ if (instr_rdata_i[14:12] == 3'b110)
+ data_load_event_o = 1'b1;
+ if (instr_rdata_i[14:12] == 3'b011)
+ illegal_insn_o = 1'b1;
+ end
+ OPCODE_LUI: begin
+ alu_op_a_mux_sel_o = OP_A_IMM;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_a_mux_sel_o = IMMA_ZERO;
+ imm_b_mux_sel_o = IMMB_U;
+ alu_operator_o = ALU_ADD;
+ regfile_we = 1'b1;
+ end
+ OPCODE_AUIPC: begin
+ alu_op_a_mux_sel_o = OP_A_CURRPC;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_b_mux_sel_o = IMMB_U;
+ alu_operator_o = ALU_ADD;
+ regfile_we = 1'b1;
+ end
+ OPCODE_OPIMM: begin
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_b_mux_sel_o = IMMB_I;
+ regfile_we = 1'b1;
+ case (instr_rdata_i[14:12])
+ 3'b000: alu_operator_o = ALU_ADD;
+ 3'b010: alu_operator_o = ALU_SLTS;
+ 3'b011: alu_operator_o = ALU_SLTU;
+ 3'b100: alu_operator_o = ALU_XOR;
+ 3'b110: alu_operator_o = ALU_OR;
+ 3'b111: alu_operator_o = ALU_AND;
+ 3'b001: begin
+ alu_operator_o = ALU_SLL;
+ if (instr_rdata_i[31:25] != 7'b0000000)
+ illegal_insn_o = 1'b1;
+ end
+ 3'b101:
+ if (instr_rdata_i[31:25] == 7'b0000000)
+ alu_operator_o = ALU_SRL;
+ else if (instr_rdata_i[31:25] == 7'b0100000)
+ alu_operator_o = ALU_SRA;
+ else
+ illegal_insn_o = 1'b1;
+ default: illegal_insn_o = 1'b1;
+ endcase
+ end
+ OPCODE_OP: begin
+ regfile_we = 1'b1;
+ if (instr_rdata_i[31])
+ illegal_insn_o = 1'b1;
+ else if (~instr_rdata_i[28])
+ case ({instr_rdata_i[30:25], instr_rdata_i[14:12]})
+ 9'b000000000: alu_operator_o = ALU_ADD;
+ 9'b100000000: alu_operator_o = ALU_SUB;
+ 9'b000000010: alu_operator_o = ALU_SLTS;
+ 9'b000000011: alu_operator_o = ALU_SLTU;
+ 9'b000000100: alu_operator_o = ALU_XOR;
+ 9'b000000110: alu_operator_o = ALU_OR;
+ 9'b000000111: alu_operator_o = ALU_AND;
+ 9'b000000001: alu_operator_o = ALU_SLL;
+ 9'b000000101: alu_operator_o = ALU_SRL;
+ 9'b100000101: alu_operator_o = ALU_SRA;
+ 9'b000001000: begin
+ alu_operator_o = ALU_ADD;
+ multdiv_operator_o = MD_OP_MULL;
+ mult_int_en = 1'b1;
+ multdiv_signed_mode_o = 2'b00;
+ illegal_insn_o = (RV32M ? 1'b0 : 1'b1);
+ end
+ 9'b000001001: begin
+ alu_operator_o = ALU_ADD;
+ multdiv_operator_o = MD_OP_MULH;
+ mult_int_en = 1'b1;
+ multdiv_signed_mode_o = 2'b11;
+ illegal_insn_o = (RV32M ? 1'b0 : 1'b1);
+ end
+ 9'b000001010: begin
+ alu_operator_o = ALU_ADD;
+ multdiv_operator_o = MD_OP_MULH;
+ mult_int_en = 1'b1;
+ multdiv_signed_mode_o = 2'b01;
+ illegal_insn_o = (RV32M ? 1'b0 : 1'b1);
+ end
+ 9'b000001011: begin
+ alu_operator_o = ALU_ADD;
+ multdiv_operator_o = MD_OP_MULH;
+ mult_int_en = 1'b1;
+ multdiv_signed_mode_o = 2'b00;
+ illegal_insn_o = (RV32M ? 1'b0 : 1'b1);
+ end
+ 9'b000001100: begin
+ alu_operator_o = ALU_ADD;
+ multdiv_operator_o = MD_OP_DIV;
+ div_int_en = 1'b1;
+ multdiv_signed_mode_o = 2'b11;
+ illegal_insn_o = (RV32M ? 1'b0 : 1'b1);
+ end
+ 9'b000001101: begin
+ alu_operator_o = ALU_ADD;
+ multdiv_operator_o = MD_OP_DIV;
+ div_int_en = 1'b1;
+ multdiv_signed_mode_o = 2'b00;
+ illegal_insn_o = (RV32M ? 1'b0 : 1'b1);
+ end
+ 9'b000001110: begin
+ alu_operator_o = ALU_ADD;
+ multdiv_operator_o = MD_OP_REM;
+ div_int_en = 1'b1;
+ multdiv_signed_mode_o = 2'b11;
+ illegal_insn_o = (RV32M ? 1'b0 : 1'b1);
+ end
+ 9'b000001111: begin
+ alu_operator_o = ALU_ADD;
+ multdiv_operator_o = MD_OP_REM;
+ div_int_en = 1'b1;
+ multdiv_signed_mode_o = 2'b00;
+ illegal_insn_o = (RV32M ? 1'b0 : 1'b1);
+ end
+ default: illegal_insn_o = 1'b1;
+ endcase
+ end
+ OPCODE_SYSTEM:
+ if (instr_rdata_i[14:12] == 3'b000)
+ case (instr_rdata_i[31:20])
+ 12'h000: ecall_insn_o = 1'b1;
+ 12'h001: ebrk_insn_o = 1'b1;
+ 12'h302: mret_insn_o = 1'b1;
+ 12'h105: pipe_flush_o = 1'b1;
+ default: illegal_insn_o = 1'b1;
+ endcase
+ else begin
+ csr_access_o = 1'b1;
+ regfile_we = 1'b1;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_a_mux_sel_o = IMMA_Z;
+ imm_b_mux_sel_o = IMMB_I;
+ if (instr_rdata_i[14] == 1'b1)
+ alu_op_a_mux_sel_o = OP_A_IMM;
+ else
+ alu_op_a_mux_sel_o = OP_A_REGA_OR_FWD;
+ case (instr_rdata_i[13:12])
+ 2'b01: csr_op = CSR_OP_WRITE;
+ 2'b10: csr_op = CSR_OP_SET;
+ 2'b11: csr_op = CSR_OP_CLEAR;
+ default: csr_illegal = 1'b1;
+ endcase
+ if (~csr_illegal)
+ if (instr_rdata_i[31:20] == 12'h300)
+ csr_status_o = 1'b1;
+ illegal_insn_o = csr_illegal;
+ end
+ default: illegal_insn_o = 1'b1;
+ endcase
+ if (illegal_c_insn_i)
+ illegal_insn_o = 1'b1;
+ if (data_misaligned_i == 1'b1) begin
+ alu_op_a_mux_sel_o = OP_A_REGA_OR_FWD;
+ alu_op_b_mux_sel_o = OP_B_IMM;
+ imm_b_mux_sel_o = IMMB_PCINCR;
+ regfile_we = 1'b0;
+ end
+ end
+ assign regfile_we_o = (deassert_we_i ? 1'b0 : regfile_we);
+ assign mult_int_en_o = (RV32M ? (deassert_we_i ? 1'b0 : mult_int_en) : 1'b0);
+ assign div_int_en_o = (RV32M ? (deassert_we_i ? 1'b0 : div_int_en) : 1'b0);
+ assign data_req_o = (deassert_we_i ? 1'b0 : data_req);
+ assign csr_op_o = (deassert_we_i ? CSR_OP_NONE : csr_op);
+ assign jump_in_id_o = (deassert_we_i ? 1'b0 : jump_in_id);
+ assign branch_in_id_o = (deassert_we_i ? 1'b0 : branch_in_id);
+endmodule
diff --git a/verilog/rtl/ips/zero-riscy/zeroriscy_ex_block.v b/verilog/rtl/ips/zero-riscy/zeroriscy_ex_block.v
new file mode 100644
index 0000000..a1066a0
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/zeroriscy_ex_block.v
@@ -0,0 +1,386 @@
+module zeroriscy_ex_block
+#(
+ parameter RV32M = 1
+)
+(
+ clk,
+ rst_n,
+ alu_operator_i,
+ multdiv_operator_i,
+ mult_en_i,
+ div_en_i,
+ alu_operand_a_i,
+ alu_operand_b_i,
+ multdiv_signed_mode_i,
+ multdiv_operand_a_i,
+ multdiv_operand_b_i,
+ alu_adder_result_ex_o,
+ regfile_wdata_ex_o,
+ jump_target_o,
+ branch_decision_o,
+ lsu_en_i,
+ lsu_ready_ex_i,
+ ex_ready_o
+);
+parameter OPCODE_SYSTEM = 7'h73;
+parameter OPCODE_FENCE = 7'h0f;
+parameter OPCODE_OP = 7'h33;
+parameter OPCODE_OPIMM = 7'h13;
+parameter OPCODE_STORE = 7'h23;
+parameter OPCODE_LOAD = 7'h03;
+parameter OPCODE_BRANCH = 7'h63;
+parameter OPCODE_JALR = 7'h67;
+parameter OPCODE_JAL = 7'h6f;
+parameter OPCODE_AUIPC = 7'h17;
+parameter OPCODE_LUI = 7'h37;
+
+// those opcodes are now used for PULP custom instructions
+// parameter OPCODE_CUST0 = 7'h0b
+// parameter OPCODE_CUST1 = 7'h2b
+
+// PULP custom
+parameter OPCODE_LOAD_POST = 7'h0b;
+parameter OPCODE_STORE_POST = 7'h2b;
+parameter OPCODE_PULP_OP = 7'h5b;
+parameter OPCODE_VECOP = 7'h57;
+parameter OPCODE_HWLOOP = 7'h7b;
+
+parameter REGC_S1 = 2'b10;
+parameter REGC_RD = 2'b01;
+parameter REGC_ZERO = 2'b11;
+
+
+//////////////////////////////////////////////////////////////////////////////
+// _ _ _ _ ___ _ _ //
+// / \ | | | | | | / _ \ _ __ ___ _ __ __ _| |_(_) ___ _ __ ___ //
+// / _ \ | | | | | | | | | | '_ \ / _ \ '__/ _` | __| |/ _ \| '_ \/ __| //
+// / ___ \| |__| |_| | | |_| | |_) | __/ | | (_| | |_| | (_) | | | \__ \ //
+// /_/ \_\_____\___/ \___/| .__/ \___|_| \__,_|\__|_|\___/|_| |_|___/ //
+// |_| //
+//////////////////////////////////////////////////////////////////////////////
+
+parameter ALU_OP_WIDTH = 6;
+
+parameter ALU_ADD = 6'b011000;
+parameter ALU_SUB = 6'b011001;
+parameter ALU_ADDU = 6'b011010;
+parameter ALU_SUBU = 6'b011011;
+parameter ALU_ADDR = 6'b011100;
+parameter ALU_SUBR = 6'b011101;
+parameter ALU_ADDUR = 6'b011110;
+parameter ALU_SUBUR = 6'b011111;
+
+parameter ALU_XOR = 6'b101111;
+parameter ALU_OR = 6'b101110;
+parameter ALU_AND = 6'b010101;
+
+// Shifts
+parameter ALU_SRA = 6'b100100;
+parameter ALU_SRL = 6'b100101;
+parameter ALU_ROR = 6'b100110;
+parameter ALU_SLL = 6'b100111;
+
+// bit manipulation
+parameter ALU_BEXT = 6'b101000;
+parameter ALU_BEXTU = 6'b101001;
+parameter ALU_BINS = 6'b101010;
+parameter ALU_BCLR = 6'b101011;
+parameter ALU_BSET = 6'b101100;
+
+// Bit counting
+parameter ALU_FF1 = 6'b110110;
+parameter ALU_FL1 = 6'b110111;
+parameter ALU_CNT = 6'b110100;
+parameter ALU_CLB = 6'b110101;
+
+// Sign-/zero-extensions
+parameter ALU_EXTS = 6'b111110;
+parameter ALU_EXT = 6'b111111;
+
+// Comparisons
+parameter ALU_LTS = 6'b000000;
+parameter ALU_LTU = 6'b000001;
+parameter ALU_LES = 6'b000100;
+parameter ALU_LEU = 6'b000101;
+parameter ALU_GTS = 6'b001000;
+parameter ALU_GTU = 6'b001001;
+parameter ALU_GES = 6'b001010;
+parameter ALU_GEU = 6'b001011;
+parameter ALU_EQ = 6'b001100;
+parameter ALU_NE = 6'b001101;
+
+// Set Lower Than operations
+parameter ALU_SLTS = 6'b000010;
+parameter ALU_SLTU = 6'b000011;
+parameter ALU_SLETS = 6'b000110;
+parameter ALU_SLETU = 6'b000111;
+
+// Absolute value
+parameter ALU_ABS = 6'b010100;
+parameter ALU_CLIP = 6'b010110;
+parameter ALU_CLIPU = 6'b010111;
+
+// Insert/extract
+parameter ALU_INS = 6'b101101;
+
+// min/max
+parameter ALU_MIN = 6'b010000;
+parameter ALU_MINU = 6'b010001;
+parameter ALU_MAX = 6'b010010;
+parameter ALU_MAXU = 6'b010011;
+
+// div/rem
+parameter ALU_DIVU = 6'b110000; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_DIV = 6'b110001; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REMU = 6'b110010; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REM = 6'b110011; // bit 0 is used for signed mode, bit 1 is used for remdiv
+
+parameter ALU_SHUF = 6'b111010;
+parameter ALU_SHUF2 = 6'b111011;
+parameter ALU_PCKLO = 6'b111000;
+parameter ALU_PCKHI = 6'b111001;
+
+
+parameter MD_OP_MULL = 2'b00;
+parameter MD_OP_MULH = 2'b01;
+parameter MD_OP_DIV = 2'b10;
+parameter MD_OP_REM = 2'b11;
+
+// vector modes
+parameter VEC_MODE32 = 2'b00;
+parameter VEC_MODE16 = 2'b10;
+parameter VEC_MODE8 = 2'b11;
+
+
+/////////////////////////////////////////////////////////
+// ____ ____ ____ _ _ //
+// / ___/ ___| | _ \ ___ __ _(_)___| |_ ___ _ __ //
+// | | \___ \ | |_) / _ \/ _` | / __| __/ _ \ '__| //
+// | |___ ___) | | _ < __/ (_| | \__ \ || __/ | //
+// \____|____/ |_| \_\___|\__, |_|___/\__\___|_| //
+// |___/ //
+/////////////////////////////////////////////////////////
+
+// CSR operations
+parameter CSR_OP_NONE = 2'b00;
+parameter CSR_OP_WRITE = 2'b01;
+parameter CSR_OP_SET = 2'b10;
+parameter CSR_OP_CLEAR = 2'b11;
+
+
+// SPR for debugger, not accessible by CPU
+parameter SP_DVR0 = 16'h3000;
+parameter SP_DCR0 = 16'h3008;
+parameter SP_DMR1 = 16'h3010;
+parameter SP_DMR2 = 16'h3011;
+
+parameter SP_DVR_MSB = 8'h00;
+parameter SP_DCR_MSB = 8'h01;
+parameter SP_DMR_MSB = 8'h02;
+parameter SP_DSR_MSB = 8'h04;
+
+// Privileged mode
+typedef enum logic[1:0] {
+ PRIV_LVL_M = 2'b11,
+ PRIV_LVL_H = 2'b10,
+ PRIV_LVL_S = 2'b01,
+ PRIV_LVL_U = 2'b00
+} PrivLvl_t;
+
+///////////////////////////////////////////////
+// ___ ____ ____ _ //
+// |_ _| _ \ / ___|| |_ __ _ __ _ ___ //
+// | || | | | \___ \| __/ _` |/ _` |/ _ \ //
+// | || |_| | ___) | || (_| | (_| | __/ //
+// |___|____/ |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// forwarding operand mux
+parameter SEL_REGFILE = 2'b00;
+parameter SEL_FW_EX = 2'b01;
+parameter SEL_FW_WB = 2'b10;
+parameter SEL_MISALIGNED = 2'b11;
+
+// operand a selection
+parameter OP_A_REGA_OR_FWD = 3'b000;
+parameter OP_A_CURRPC = 3'b001;
+parameter OP_A_IMM = 3'b010;
+parameter OP_A_REGB_OR_FWD = 3'b011;
+parameter OP_A_REGC_OR_FWD = 3'b100;
+
+// immediate a selection
+parameter IMMA_Z = 1'b0;
+parameter IMMA_ZERO = 1'b1;
+
+// operand b selection
+parameter OP_B_REGB_OR_FWD = 3'b000;
+parameter OP_B_REGC_OR_FWD = 3'b001;
+parameter OP_B_IMM = 3'b010;
+parameter OP_B_REGA_OR_FWD = 3'b011;
+parameter OP_B_BMASK = 3'b100;
+parameter OP_B_ZERO = 3'b101;
+
+// immediate b selection
+parameter IMMB_I = 4'b0000;
+parameter IMMB_S = 4'b0001;
+parameter IMMB_U = 4'b0010;
+parameter IMMB_PCINCR = 4'b0011;
+parameter IMMB_S2 = 4'b0100;
+parameter IMMB_S3 = 4'b0101;
+parameter IMMB_VS = 4'b0110;
+parameter IMMB_VU = 4'b0111;
+parameter IMMB_SHUF = 4'b1000;
+parameter IMMB_CLIP = 4'b1001;
+parameter IMMB_BI = 4'b1011;
+parameter IMMB_UJ = 4'b1100;
+parameter IMMB_SB = 4'b1101;
+
+// bit mask selection
+parameter BMASK_A_ZERO = 1'b0;
+parameter BMASK_A_S3 = 1'b1;
+
+parameter BMASK_B_S2 = 2'b00;
+parameter BMASK_B_S3 = 2'b01;
+parameter BMASK_B_ZERO = 2'b10;
+parameter BMASK_B_ONE = 2'b11;
+
+parameter BMASK_A_REG = 1'b0;
+parameter BMASK_A_IMM = 1'b1;
+parameter BMASK_B_REG = 1'b0;
+parameter BMASK_B_IMM = 1'b1;
+
+
+
+///////////////////////////////////////////////
+// ___ _____ ____ _ //
+// |_ _| ___| / ___|| |_ __ _ __ _ ___ //
+// | || |_ \___ \| __/ _` |/ _` |/ _ \ //
+// | || _| ___) | || (_| | (_| | __/ //
+// |___|_| |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// PC mux selector defines
+parameter PC_BOOT = 3'b000;
+parameter PC_JUMP = 3'b010;
+parameter PC_EXCEPTION = 3'b100;
+parameter PC_ERET = 3'b101;
+parameter PC_DBG_NPC = 3'b111;
+
+// Exception PC mux selector defines
+parameter EXC_PC_ILLINSN = 2'b00;
+parameter EXC_PC_ECALL = 2'b01;
+parameter EXC_PC_LOAD = 2'b10;
+parameter EXC_PC_STORE = 2'b10;
+parameter EXC_PC_IRQ = 2'b11;
+
+// Exception Cause
+parameter EXC_CAUSE_ILLEGAL_INSN = 6'h02;
+parameter EXC_CAUSE_BREAKPOINT = 6'h03;
+parameter EXC_CAUSE_ECALL_MMODE = 6'h0B;
+
+// Exceptions offsets
+// target address = {boot_addr[31:8], EXC_OFF} (boot_addr must be 32 BYTE aligned!)
+// offset 00 to 7e is used for external interrupts
+parameter EXC_OFF_RST = 8'h80;
+parameter EXC_OFF_ILLINSN = 8'h84;
+parameter EXC_OFF_ECALL = 8'h88;
+parameter EXC_OFF_LSUERR = 8'h8c;
+
+
+// Debug module
+parameter DBG_SETS_W = 6;
+
+parameter DBG_SETS_IRQ = 5;
+parameter DBG_SETS_ECALL = 4;
+parameter DBG_SETS_EILL = 3;
+parameter DBG_SETS_ELSU = 2;
+parameter DBG_SETS_EBRK = 1;
+parameter DBG_SETS_SSTE = 0;
+
+parameter DBG_CAUSE_HALT = 6'h1F;
+ //parameter RV32M = 1;
+ input wire clk;
+ input wire rst_n;
+ input wire [ALU_OP_WIDTH - 1:0] alu_operator_i;
+ input wire [1:0] multdiv_operator_i;
+ input wire mult_en_i;
+ input wire div_en_i;
+ input wire [31:0] alu_operand_a_i;
+ input wire [31:0] alu_operand_b_i;
+ input wire [1:0] multdiv_signed_mode_i;
+ input wire [31:0] multdiv_operand_a_i;
+ input wire [31:0] multdiv_operand_b_i;
+ output wire [31:0] alu_adder_result_ex_o;
+ output wire [31:0] regfile_wdata_ex_o;
+ output wire [31:0] jump_target_o;
+ output wire branch_decision_o;
+ input wire lsu_en_i;
+ input wire lsu_ready_ex_i;
+ output reg ex_ready_o;
+ localparam MULT_TYPE = 1;
+ wire [31:0] alu_result;
+ wire [31:0] multdiv_result;
+ wire [32:0] multdiv_alu_operand_b;
+ wire [32:0] multdiv_alu_operand_a;
+ wire [33:0] alu_adder_result_ext;
+ wire alu_cmp_result;
+ wire alu_is_equal_result;
+ wire multdiv_ready;
+ wire multdiv_en_sel;
+ wire multdiv_en;
+ generate
+ if (RV32M) begin : genblk1
+ assign multdiv_en_sel = div_en_i;
+ assign multdiv_en = mult_en_i | div_en_i;
+ end
+ else begin : genblk1
+ assign multdiv_en_sel = 1'b0;
+ assign multdiv_en = 1'b0;
+ end
+ endgenerate
+ assign regfile_wdata_ex_o = (multdiv_en ? multdiv_result : alu_result);
+ assign branch_decision_o = alu_cmp_result;
+ assign jump_target_o = alu_adder_result_ex_o;
+ zeroriscy_alu alu_i(
+ .operator_i(alu_operator_i),
+ .operand_a_i(alu_operand_a_i),
+ .operand_b_i(alu_operand_b_i),
+ .multdiv_operand_a_i(multdiv_alu_operand_a),
+ .multdiv_operand_b_i(multdiv_alu_operand_b),
+ .multdiv_en_i(multdiv_en_sel),
+ .adder_result_o(alu_adder_result_ex_o),
+ .adder_result_ext_o(alu_adder_result_ext),
+ .result_o(alu_result),
+ .comparison_result_o(alu_cmp_result),
+ .is_equal_result_o(alu_is_equal_result)
+ );
+ generate
+ if (1) begin : multdiv_fast
+ zeroriscy_multdiv_fast multdiv_i(
+ .clk(clk),
+ .rst_n(rst_n),
+ .mult_en_i(mult_en_i),
+ .div_en_i(div_en_i),
+ .operator_i(multdiv_operator_i),
+ .signed_mode_i(multdiv_signed_mode_i),
+ .op_a_i(multdiv_operand_a_i),
+ .op_b_i(multdiv_operand_b_i),
+ .alu_operand_a_o(multdiv_alu_operand_a),
+ .alu_operand_b_o(multdiv_alu_operand_b),
+ .alu_adder_ext_i(alu_adder_result_ext),
+ .alu_adder_i(alu_adder_result_ex_o),
+ .equal_to_zero(alu_is_equal_result),
+ .ready_o(multdiv_ready),
+ .multdiv_result_o(multdiv_result)
+ );
+ end
+ endgenerate
+ always @(*)
+ case (1'b1)
+ multdiv_en: ex_ready_o = multdiv_ready;
+ lsu_en_i: ex_ready_o = lsu_ready_ex_i;
+ default: ex_ready_o = 1'b1;
+ endcase
+endmodule
diff --git a/verilog/rtl/ips/zero-riscy/zeroriscy_fetch_fifo.v b/verilog/rtl/ips/zero-riscy/zeroriscy_fetch_fifo.v
new file mode 100644
index 0000000..3b736e3
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/zeroriscy_fetch_fifo.v
@@ -0,0 +1,142 @@
+module zeroriscy_fetch_fifo (
+ clk,
+ rst_n,
+ clear_i,
+ in_addr_i,
+ in_rdata_i,
+ in_valid_i,
+ in_ready_o,
+ out_valid_o,
+ out_ready_i,
+ out_rdata_o,
+ out_addr_o,
+ out_valid_stored_o
+);
+ input wire clk;
+ input wire rst_n;
+ input wire clear_i;
+ input wire [31:0] in_addr_i;
+ input wire [31:0] in_rdata_i;
+ input wire in_valid_i;
+ output wire in_ready_o;
+ output reg out_valid_o;
+ input wire out_ready_i;
+ output reg [31:0] out_rdata_o;
+ output wire [31:0] out_addr_o;
+ output reg out_valid_stored_o;
+ localparam DEPTH = 3;
+ reg [95:0] addr_n;
+ reg [95:0] addr_int;
+ reg [95:0] addr_Q;
+ reg [95:0] rdata_n;
+ reg [95:0] rdata_int;
+ reg [95:0] rdata_Q;
+ reg [2:0] valid_n;
+ reg [2:0] valid_int;
+ reg [2:0] valid_Q;
+ wire [31:0] addr_next;
+ wire [31:0] rdata;
+ wire [31:0] rdata_unaligned;
+ wire valid;
+ wire valid_unaligned;
+ wire aligned_is_compressed;
+ wire unaligned_is_compressed;
+ wire aligned_is_compressed_st;
+ wire unaligned_is_compressed_st;
+ assign rdata = (valid_Q[0] ? rdata_Q[0+:32] : in_rdata_i);
+ assign valid = valid_Q[0] || in_valid_i;
+ assign rdata_unaligned = (valid_Q[1] ? {rdata_Q[47-:16], rdata[31:16]} : {in_rdata_i[15:0], rdata[31:16]});
+ assign valid_unaligned = valid_Q[1] || (valid_Q[0] && in_valid_i);
+ assign unaligned_is_compressed = rdata[17:16] != 2'b11;
+ assign aligned_is_compressed = rdata[1:0] != 2'b11;
+ assign unaligned_is_compressed_st = rdata_Q[17-:2] != 2'b11;
+ assign aligned_is_compressed_st = rdata_Q[1-:2] != 2'b11;
+ always @(*)
+ if (out_addr_o[1]) begin
+ out_rdata_o = rdata_unaligned;
+ if (unaligned_is_compressed)
+ out_valid_o = valid;
+ else
+ out_valid_o = valid_unaligned;
+ end
+ else begin
+ out_rdata_o = rdata;
+ out_valid_o = valid;
+ end
+ assign out_addr_o = (valid_Q[0] ? addr_Q[0+:32] : in_addr_i);
+ always @(*) begin
+ out_valid_stored_o = 1'b1;
+ if (out_addr_o[1]) begin
+ if (unaligned_is_compressed_st)
+ out_valid_stored_o = 1'b1;
+ else
+ out_valid_stored_o = valid_Q[1];
+ end
+ else
+ out_valid_stored_o = valid_Q[0];
+ end
+ assign in_ready_o = ~valid_Q[1];
+ always @(*) begin : sv2v_autoblock_1
+ reg [0:1] _sv2v_jump;
+ _sv2v_jump = 2'b00;
+ begin : sv2v_autoblock_2
+ reg signed [31:0] j;
+ addr_int = addr_Q;
+ rdata_int = rdata_Q;
+ valid_int = valid_Q;
+ if (in_valid_i) begin : sv2v_autoblock_3
+ reg signed [31:0] _sv2v_value_on_break;
+ for (j = 0; j < DEPTH; j = j + 1)
+ if (_sv2v_jump < 2'b10) begin
+ _sv2v_jump = 2'b00;
+ if (~valid_Q[j]) begin
+ addr_int[j * 32+:32] = in_addr_i;
+ rdata_int[j * 32+:32] = in_rdata_i;
+ valid_int[j] = 1'b1;
+ _sv2v_jump = 2'b10;
+ end
+ _sv2v_value_on_break = j;
+ end
+ if (!(_sv2v_jump < 2'b10))
+ j = _sv2v_value_on_break;
+ if (_sv2v_jump != 2'b11)
+ _sv2v_jump = 2'b00;
+ end
+ end
+ end
+ assign addr_next = {addr_int[31-:30], 2'b00} + 32'h00000004;
+ always @(*) begin
+ addr_n = addr_int;
+ rdata_n = rdata_int;
+ valid_n = valid_int;
+ if (out_ready_i && out_valid_o)
+ if (addr_int[1]) begin
+ if (unaligned_is_compressed)
+ addr_n[0+:32] = {addr_next[31:2], 2'b00};
+ else
+ addr_n[0+:32] = {addr_next[31:2], 2'b10};
+ rdata_n = {32'b00000000000000000000000000000000, rdata_int[32+:64]};
+ valid_n = {1'b0, valid_int[2:1]};
+ end
+ else if (aligned_is_compressed)
+ addr_n[0+:32] = {addr_int[31-:30], 2'b10};
+ else begin
+ addr_n[0+:32] = {addr_next[31:2], 2'b00};
+ rdata_n = {32'b00000000000000000000000000000000, rdata_int[32+:64]};
+ valid_n = {1'b0, valid_int[2:1]};
+ end
+ end
+ always @(posedge clk or negedge rst_n)
+ if (rst_n == 1'b0) begin
+ addr_Q <= {DEPTH {32'b00000000000000000000000000000000}};
+ rdata_Q <= {DEPTH {32'b00000000000000000000000000000000}};
+ valid_Q <= 1'sb0;
+ end
+ else if (clear_i)
+ valid_Q <= 1'sb0;
+ else begin
+ addr_Q <= addr_n;
+ rdata_Q <= rdata_n;
+ valid_Q <= valid_n;
+ end
+endmodule
diff --git a/verilog/rtl/ips/zero-riscy/zeroriscy_id_stage.v b/verilog/rtl/ips/zero-riscy/zeroriscy_id_stage.v
new file mode 100644
index 0000000..dcc270f
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/zeroriscy_id_stage.v
@@ -0,0 +1,803 @@
+module zeroriscy_id_stage (
+ clk,
+ rst_n,
+ test_en_i,
+ fetch_enable_i,
+ ctrl_busy_o,
+ core_ctrl_firstfetch_o,
+ is_decoding_o,
+ instr_valid_i,
+ instr_rdata_i,
+ instr_req_o,
+ branch_in_ex_o,
+ branch_decision_i,
+ clear_instr_valid_o,
+ pc_set_o,
+ pc_mux_o,
+ exc_pc_mux_o,
+ illegal_c_insn_i,
+ is_compressed_i,
+ pc_id_i,
+ halt_if_o,
+ id_ready_o,
+ ex_ready_i,
+ id_valid_o,
+ alu_operator_ex_o,
+ alu_operand_a_ex_o,
+ alu_operand_b_ex_o,
+ mult_en_ex_o,
+ div_en_ex_o,
+ multdiv_operator_ex_o,
+ multdiv_signed_mode_ex_o,
+ multdiv_operand_a_ex_o,
+ multdiv_operand_b_ex_o,
+ csr_access_ex_o,
+ csr_op_ex_o,
+ csr_cause_o,
+ csr_save_if_o,
+ csr_save_id_o,
+ csr_restore_mret_id_o,
+ csr_save_cause_o,
+ data_req_ex_o,
+ data_we_ex_o,
+ data_type_ex_o,
+ data_sign_ext_ex_o,
+ data_reg_offset_ex_o,
+ data_load_event_ex_o,
+ data_wdata_ex_o,
+ data_misaligned_i,
+ misaligned_addr_i,
+ irq_i,
+ irq_id_i,
+ m_irq_enable_i,
+ irq_ack_o,
+ irq_id_o,
+ exc_cause_o,
+ lsu_load_err_i,
+ lsu_store_err_i,
+ dbg_settings_i,
+ dbg_req_i,
+ dbg_ack_o,
+ dbg_stall_i,
+ dbg_trap_o,
+ dbg_reg_rreq_i,
+ dbg_reg_raddr_i,
+ dbg_reg_rdata_o,
+ dbg_reg_wreq_i,
+ dbg_reg_waddr_i,
+ dbg_reg_wdata_i,
+ dbg_jump_req_i,
+ regfile_wdata_lsu_i,
+ regfile_wdata_ex_i,
+ csr_rdata_i,
+ perf_jump_o,
+ perf_branch_o,
+ perf_tbranch_o
+);
+parameter OPCODE_SYSTEM = 7'h73;
+parameter OPCODE_FENCE = 7'h0f;
+parameter OPCODE_OP = 7'h33;
+parameter OPCODE_OPIMM = 7'h13;
+parameter OPCODE_STORE = 7'h23;
+parameter OPCODE_LOAD = 7'h03;
+parameter OPCODE_BRANCH = 7'h63;
+parameter OPCODE_JALR = 7'h67;
+parameter OPCODE_JAL = 7'h6f;
+parameter OPCODE_AUIPC = 7'h17;
+parameter OPCODE_LUI = 7'h37;
+
+// those opcodes are now used for PULP custom instructions
+// parameter OPCODE_CUST0 = 7'h0b
+// parameter OPCODE_CUST1 = 7'h2b
+
+// PULP custom
+parameter OPCODE_LOAD_POST = 7'h0b;
+parameter OPCODE_STORE_POST = 7'h2b;
+parameter OPCODE_PULP_OP = 7'h5b;
+parameter OPCODE_VECOP = 7'h57;
+parameter OPCODE_HWLOOP = 7'h7b;
+
+parameter REGC_S1 = 2'b10;
+parameter REGC_RD = 2'b01;
+parameter REGC_ZERO = 2'b11;
+
+
+//////////////////////////////////////////////////////////////////////////////
+// _ _ _ _ ___ _ _ //
+// / \ | | | | | | / _ \ _ __ ___ _ __ __ _| |_(_) ___ _ __ ___ //
+// / _ \ | | | | | | | | | | '_ \ / _ \ '__/ _` | __| |/ _ \| '_ \/ __| //
+// / ___ \| |__| |_| | | |_| | |_) | __/ | | (_| | |_| | (_) | | | \__ \ //
+// /_/ \_\_____\___/ \___/| .__/ \___|_| \__,_|\__|_|\___/|_| |_|___/ //
+// |_| //
+//////////////////////////////////////////////////////////////////////////////
+
+parameter ALU_OP_WIDTH = 6;
+
+parameter ALU_ADD = 6'b011000;
+parameter ALU_SUB = 6'b011001;
+parameter ALU_ADDU = 6'b011010;
+parameter ALU_SUBU = 6'b011011;
+parameter ALU_ADDR = 6'b011100;
+parameter ALU_SUBR = 6'b011101;
+parameter ALU_ADDUR = 6'b011110;
+parameter ALU_SUBUR = 6'b011111;
+
+parameter ALU_XOR = 6'b101111;
+parameter ALU_OR = 6'b101110;
+parameter ALU_AND = 6'b010101;
+
+// Shifts
+parameter ALU_SRA = 6'b100100;
+parameter ALU_SRL = 6'b100101;
+parameter ALU_ROR = 6'b100110;
+parameter ALU_SLL = 6'b100111;
+
+// bit manipulation
+parameter ALU_BEXT = 6'b101000;
+parameter ALU_BEXTU = 6'b101001;
+parameter ALU_BINS = 6'b101010;
+parameter ALU_BCLR = 6'b101011;
+parameter ALU_BSET = 6'b101100;
+
+// Bit counting
+parameter ALU_FF1 = 6'b110110;
+parameter ALU_FL1 = 6'b110111;
+parameter ALU_CNT = 6'b110100;
+parameter ALU_CLB = 6'b110101;
+
+// Sign-/zero-extensions
+parameter ALU_EXTS = 6'b111110;
+parameter ALU_EXT = 6'b111111;
+
+// Comparisons
+parameter ALU_LTS = 6'b000000;
+parameter ALU_LTU = 6'b000001;
+parameter ALU_LES = 6'b000100;
+parameter ALU_LEU = 6'b000101;
+parameter ALU_GTS = 6'b001000;
+parameter ALU_GTU = 6'b001001;
+parameter ALU_GES = 6'b001010;
+parameter ALU_GEU = 6'b001011;
+parameter ALU_EQ = 6'b001100;
+parameter ALU_NE = 6'b001101;
+
+// Set Lower Than operations
+parameter ALU_SLTS = 6'b000010;
+parameter ALU_SLTU = 6'b000011;
+parameter ALU_SLETS = 6'b000110;
+parameter ALU_SLETU = 6'b000111;
+
+// Absolute value
+parameter ALU_ABS = 6'b010100;
+parameter ALU_CLIP = 6'b010110;
+parameter ALU_CLIPU = 6'b010111;
+
+// Insert/extract
+parameter ALU_INS = 6'b101101;
+
+// min/max
+parameter ALU_MIN = 6'b010000;
+parameter ALU_MINU = 6'b010001;
+parameter ALU_MAX = 6'b010010;
+parameter ALU_MAXU = 6'b010011;
+
+// div/rem
+parameter ALU_DIVU = 6'b110000; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_DIV = 6'b110001; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REMU = 6'b110010; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REM = 6'b110011; // bit 0 is used for signed mode, bit 1 is used for remdiv
+
+parameter ALU_SHUF = 6'b111010;
+parameter ALU_SHUF2 = 6'b111011;
+parameter ALU_PCKLO = 6'b111000;
+parameter ALU_PCKHI = 6'b111001;
+
+
+parameter MD_OP_MULL = 2'b00;
+parameter MD_OP_MULH = 2'b01;
+parameter MD_OP_DIV = 2'b10;
+parameter MD_OP_REM = 2'b11;
+
+// vector modes
+parameter VEC_MODE32 = 2'b00;
+parameter VEC_MODE16 = 2'b10;
+parameter VEC_MODE8 = 2'b11;
+
+
+/////////////////////////////////////////////////////////
+// ____ ____ ____ _ _ //
+// / ___/ ___| | _ \ ___ __ _(_)___| |_ ___ _ __ //
+// | | \___ \ | |_) / _ \/ _` | / __| __/ _ \ '__| //
+// | |___ ___) | | _ < __/ (_| | \__ \ || __/ | //
+// \____|____/ |_| \_\___|\__, |_|___/\__\___|_| //
+// |___/ //
+/////////////////////////////////////////////////////////
+
+// CSR operations
+parameter CSR_OP_NONE = 2'b00;
+parameter CSR_OP_WRITE = 2'b01;
+parameter CSR_OP_SET = 2'b10;
+parameter CSR_OP_CLEAR = 2'b11;
+
+
+// SPR for debugger, not accessible by CPU
+parameter SP_DVR0 = 16'h3000;
+parameter SP_DCR0 = 16'h3008;
+parameter SP_DMR1 = 16'h3010;
+parameter SP_DMR2 = 16'h3011;
+
+parameter SP_DVR_MSB = 8'h00;
+parameter SP_DCR_MSB = 8'h01;
+parameter SP_DMR_MSB = 8'h02;
+parameter SP_DSR_MSB = 8'h04;
+
+// Privileged mode
+typedef enum logic[1:0] {
+ PRIV_LVL_M = 2'b11,
+ PRIV_LVL_H = 2'b10,
+ PRIV_LVL_S = 2'b01,
+ PRIV_LVL_U = 2'b00
+} PrivLvl_t;
+
+///////////////////////////////////////////////
+// ___ ____ ____ _ //
+// |_ _| _ \ / ___|| |_ __ _ __ _ ___ //
+// | || | | | \___ \| __/ _` |/ _` |/ _ \ //
+// | || |_| | ___) | || (_| | (_| | __/ //
+// |___|____/ |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// forwarding operand mux
+parameter SEL_REGFILE = 2'b00;
+parameter SEL_FW_EX = 2'b01;
+parameter SEL_FW_WB = 2'b10;
+parameter SEL_MISALIGNED = 2'b11;
+
+// operand a selection
+parameter OP_A_REGA_OR_FWD = 3'b000;
+parameter OP_A_CURRPC = 3'b001;
+parameter OP_A_IMM = 3'b010;
+parameter OP_A_REGB_OR_FWD = 3'b011;
+parameter OP_A_REGC_OR_FWD = 3'b100;
+
+// immediate a selection
+parameter IMMA_Z = 1'b0;
+parameter IMMA_ZERO = 1'b1;
+
+// operand b selection
+parameter OP_B_REGB_OR_FWD = 3'b000;
+parameter OP_B_REGC_OR_FWD = 3'b001;
+parameter OP_B_IMM = 3'b010;
+parameter OP_B_REGA_OR_FWD = 3'b011;
+parameter OP_B_BMASK = 3'b100;
+parameter OP_B_ZERO = 3'b101;
+
+// immediate b selection
+parameter IMMB_I = 4'b0000;
+parameter IMMB_S = 4'b0001;
+parameter IMMB_U = 4'b0010;
+parameter IMMB_PCINCR = 4'b0011;
+parameter IMMB_S2 = 4'b0100;
+parameter IMMB_S3 = 4'b0101;
+parameter IMMB_VS = 4'b0110;
+parameter IMMB_VU = 4'b0111;
+parameter IMMB_SHUF = 4'b1000;
+parameter IMMB_CLIP = 4'b1001;
+parameter IMMB_BI = 4'b1011;
+parameter IMMB_UJ = 4'b1100;
+parameter IMMB_SB = 4'b1101;
+
+// bit mask selection
+parameter BMASK_A_ZERO = 1'b0;
+parameter BMASK_A_S3 = 1'b1;
+
+parameter BMASK_B_S2 = 2'b00;
+parameter BMASK_B_S3 = 2'b01;
+parameter BMASK_B_ZERO = 2'b10;
+parameter BMASK_B_ONE = 2'b11;
+
+parameter BMASK_A_REG = 1'b0;
+parameter BMASK_A_IMM = 1'b1;
+parameter BMASK_B_REG = 1'b0;
+parameter BMASK_B_IMM = 1'b1;
+
+
+
+///////////////////////////////////////////////
+// ___ _____ ____ _ //
+// |_ _| ___| / ___|| |_ __ _ __ _ ___ //
+// | || |_ \___ \| __/ _` |/ _` |/ _ \ //
+// | || _| ___) | || (_| | (_| | __/ //
+// |___|_| |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// PC mux selector defines
+parameter PC_BOOT = 3'b000;
+parameter PC_JUMP = 3'b010;
+parameter PC_EXCEPTION = 3'b100;
+parameter PC_ERET = 3'b101;
+parameter PC_DBG_NPC = 3'b111;
+
+// Exception PC mux selector defines
+parameter EXC_PC_ILLINSN = 2'b00;
+parameter EXC_PC_ECALL = 2'b01;
+parameter EXC_PC_LOAD = 2'b10;
+parameter EXC_PC_STORE = 2'b10;
+parameter EXC_PC_IRQ = 2'b11;
+
+// Exception Cause
+parameter EXC_CAUSE_ILLEGAL_INSN = 6'h02;
+parameter EXC_CAUSE_BREAKPOINT = 6'h03;
+parameter EXC_CAUSE_ECALL_MMODE = 6'h0B;
+
+// Exceptions offsets
+// target address = {boot_addr[31:8], EXC_OFF} (boot_addr must be 32 BYTE aligned!)
+// offset 00 to 7e is used for external interrupts
+parameter EXC_OFF_RST = 8'h80;
+parameter EXC_OFF_ILLINSN = 8'h84;
+parameter EXC_OFF_ECALL = 8'h88;
+parameter EXC_OFF_LSUERR = 8'h8c;
+
+
+// Debug module
+parameter DBG_SETS_W = 6;
+
+parameter DBG_SETS_IRQ = 5;
+parameter DBG_SETS_ECALL = 4;
+parameter DBG_SETS_EILL = 3;
+parameter DBG_SETS_ELSU = 2;
+parameter DBG_SETS_EBRK = 1;
+parameter DBG_SETS_SSTE = 0;
+
+parameter DBG_CAUSE_HALT = 6'h1F;
+ parameter RV32M = 1;
+ parameter RV32E = 0;
+ input wire clk;
+ input wire rst_n;
+ input wire test_en_i;
+ input wire fetch_enable_i;
+ output wire ctrl_busy_o;
+ output wire core_ctrl_firstfetch_o;
+ output wire is_decoding_o;
+ input wire instr_valid_i;
+ input wire [31:0] instr_rdata_i;
+ output wire instr_req_o;
+ output wire branch_in_ex_o;
+ input wire branch_decision_i;
+ output wire clear_instr_valid_o;
+ output wire pc_set_o;
+ output wire [2:0] pc_mux_o;
+ output wire [1:0] exc_pc_mux_o;
+ input wire illegal_c_insn_i;
+ input wire is_compressed_i;
+ input wire [31:0] pc_id_i;
+ output wire halt_if_o;
+ output wire id_ready_o;
+ input wire ex_ready_i;
+ output wire id_valid_o;
+ output wire [ALU_OP_WIDTH - 1:0] alu_operator_ex_o;
+ output wire [31:0] alu_operand_a_ex_o;
+ output wire [31:0] alu_operand_b_ex_o;
+ output wire mult_en_ex_o;
+ output wire div_en_ex_o;
+ output wire [1:0] multdiv_operator_ex_o;
+ output wire [1:0] multdiv_signed_mode_ex_o;
+ output wire [31:0] multdiv_operand_a_ex_o;
+ output wire [31:0] multdiv_operand_b_ex_o;
+ output wire csr_access_ex_o;
+ output wire [1:0] csr_op_ex_o;
+ output wire [5:0] csr_cause_o;
+ output wire csr_save_if_o;
+ output wire csr_save_id_o;
+ output wire csr_restore_mret_id_o;
+ output wire csr_save_cause_o;
+ output wire data_req_ex_o;
+ output wire data_we_ex_o;
+ output wire [1:0] data_type_ex_o;
+ output wire data_sign_ext_ex_o;
+ output wire [1:0] data_reg_offset_ex_o;
+ output wire data_load_event_ex_o;
+ output wire [31:0] data_wdata_ex_o;
+ input wire data_misaligned_i;
+ input wire [31:0] misaligned_addr_i;
+ input wire irq_i;
+ input wire [4:0] irq_id_i;
+ input wire m_irq_enable_i;
+ output wire irq_ack_o;
+ output wire [4:0] irq_id_o;
+ output wire [5:0] exc_cause_o;
+ input wire lsu_load_err_i;
+ input wire lsu_store_err_i;
+ input wire [DBG_SETS_W - 1:0] dbg_settings_i;
+ input wire dbg_req_i;
+ output wire dbg_ack_o;
+ input wire dbg_stall_i;
+ output wire dbg_trap_o;
+ input wire dbg_reg_rreq_i;
+ input wire [4:0] dbg_reg_raddr_i;
+ output wire [31:0] dbg_reg_rdata_o;
+ input wire dbg_reg_wreq_i;
+ input wire [4:0] dbg_reg_waddr_i;
+ input wire [31:0] dbg_reg_wdata_i;
+ input wire dbg_jump_req_i;
+ input wire [31:0] regfile_wdata_lsu_i;
+ input wire [31:0] regfile_wdata_ex_i;
+ input wire [31:0] csr_rdata_i;
+ output wire perf_jump_o;
+ output reg perf_branch_o;
+ output wire perf_tbranch_o;
+ wire [31:0] instr;
+ wire deassert_we;
+ wire illegal_insn_dec;
+ wire illegal_reg_rv32e;
+ wire ebrk_insn;
+ wire mret_insn_dec;
+ wire ecall_insn_dec;
+ wire pipe_flush_dec;
+ wire branch_taken_ex;
+ wire branch_in_id;
+ reg branch_set_n;
+ reg branch_set_q;
+ reg branch_mux_dec;
+ reg jump_set;
+ reg jump_mux_dec;
+ wire jump_in_id;
+ reg instr_multicyle;
+ reg load_stall;
+ reg multdiv_stall;
+ reg branch_stall;
+ reg jump_stall;
+ wire halt_id;
+ reg regfile_we;
+ reg select_data_rf;
+ wire [31:0] imm_i_type;
+ wire [31:0] imm_iz_type;
+ wire [31:0] imm_s_type;
+ wire [31:0] imm_sb_type;
+ wire [31:0] imm_u_type;
+ wire [31:0] imm_uj_type;
+ wire [31:0] imm_z_type;
+ wire [31:0] imm_s2_type;
+ wire [31:0] imm_bi_type;
+ wire [31:0] imm_s3_type;
+ wire [31:0] imm_vs_type;
+ wire [31:0] imm_vu_type;
+ reg [31:0] imm_a;
+ reg [31:0] imm_b;
+ wire irq_req_ctrl;
+ wire [4:0] irq_id_ctrl;
+ wire exc_ack;
+ wire exc_kill;
+ wire [4:0] regfile_addr_ra_id;
+ wire [4:0] regfile_addr_rb_id;
+ wire [4:0] regfile_alu_waddr_id;
+ wire regfile_we_id;
+ wire [31:0] regfile_data_ra_id;
+ wire [31:0] regfile_data_rb_id;
+ wire [ALU_OP_WIDTH - 1:0] alu_operator;
+ wire [2:0] alu_op_a_mux_sel;
+ wire [2:0] alu_op_b_mux_sel;
+ wire [0:0] imm_a_mux_sel;
+ wire [3:0] imm_b_mux_sel;
+ wire mult_int_en;
+ wire div_int_en;
+ wire multdiv_int_en;
+ wire [1:0] multdiv_operator;
+ wire [1:0] multdiv_signed_mode;
+ wire data_we_id;
+ wire [1:0] data_type_id;
+ wire data_sign_ext_id;
+ wire [1:0] data_reg_offset_id;
+ wire data_req_id;
+ wire data_load_event_id;
+ wire csr_access;
+ wire [1:0] csr_op;
+ wire csr_status;
+ wire [1:0] operand_a_fw_mux_sel;
+ reg [31:0] operand_a_fw_id;
+ wire [31:0] operand_b_fw_id;
+ reg [31:0] operand_b;
+ reg [31:0] alu_operand_a;
+ wire [31:0] alu_operand_b;
+ assign instr = instr_rdata_i;
+ assign imm_i_type = {{20 {instr[31]}}, instr[31:20]};
+ assign imm_iz_type = {20'b00000000000000000000, instr[31:20]};
+ assign imm_s_type = {{20 {instr[31]}}, instr[31:25], instr[11:7]};
+ assign imm_sb_type = {{19 {instr[31]}}, instr[31], instr[7], instr[30:25], instr[11:8], 1'b0};
+ assign imm_u_type = {instr[31:12], 12'b000000000000};
+ assign imm_uj_type = {{12 {instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0};
+ assign imm_z_type = {27'b000000000000000000000000000, instr[19:15]};
+ assign imm_s2_type = {27'b000000000000000000000000000, instr[24:20]};
+ assign imm_bi_type = {{27 {instr[24]}}, instr[24:20]};
+ assign imm_s3_type = {27'b000000000000000000000000000, instr[29:25]};
+ assign imm_vs_type = {{26 {instr[24]}}, instr[24:20], instr[25]};
+ assign imm_vu_type = {26'b00000000000000000000000000, instr[24:20], instr[25]};
+ assign regfile_addr_ra_id = instr[19:15];
+ assign regfile_addr_rb_id = instr[24:20];
+ assign regfile_alu_waddr_id = instr[11:7];
+ assign illegal_reg_rv32e = 1'b0;
+ assign clear_instr_valid_o = id_ready_o | halt_id;
+ assign branch_taken_ex = branch_in_id & branch_decision_i;
+ always @(*) begin : alu_operand_a_mux
+ case (alu_op_a_mux_sel)
+ OP_A_REGA_OR_FWD: alu_operand_a = operand_a_fw_id;
+ OP_A_CURRPC: alu_operand_a = pc_id_i;
+ OP_A_IMM: alu_operand_a = imm_a;
+ default: alu_operand_a = operand_a_fw_id;
+ endcase
+ end
+ always @(*) begin : immediate_a_mux
+ case (imm_a_mux_sel)
+ IMMA_Z: imm_a = imm_z_type;
+ IMMA_ZERO: imm_a = 1'sb0;
+ default: imm_a = 1'sb0;
+ endcase
+ end
+ always @(*) begin : operand_a_fw_mux
+ case (operand_a_fw_mux_sel)
+ SEL_MISALIGNED: operand_a_fw_id = misaligned_addr_i;
+ SEL_REGFILE: operand_a_fw_id = regfile_data_ra_id;
+ default: operand_a_fw_id = regfile_data_ra_id;
+ endcase
+ end
+ always @(*) begin : immediate_b_mux
+ case (imm_b_mux_sel)
+ IMMB_I: imm_b = imm_i_type;
+ IMMB_S: imm_b = imm_s_type;
+ IMMB_U: imm_b = imm_u_type;
+ IMMB_PCINCR: imm_b = (is_compressed_i && ~data_misaligned_i ? 32'h00000002 : 32'h00000004);
+ IMMB_S2: imm_b = imm_s2_type;
+ IMMB_BI: imm_b = imm_bi_type;
+ IMMB_S3: imm_b = imm_s3_type;
+ IMMB_VS: imm_b = imm_vs_type;
+ IMMB_VU: imm_b = imm_vu_type;
+ IMMB_UJ: imm_b = imm_uj_type;
+ IMMB_SB: imm_b = imm_sb_type;
+ default: imm_b = imm_i_type;
+ endcase
+ end
+ always @(*) begin : alu_operand_b_mux
+ case (alu_op_b_mux_sel)
+ OP_B_REGB_OR_FWD: operand_b = regfile_data_rb_id;
+ OP_B_IMM: operand_b = imm_b;
+ default: operand_b = regfile_data_rb_id;
+ endcase
+ end
+ assign alu_operand_b = operand_b;
+ assign operand_b_fw_id = regfile_data_rb_id;
+ reg [31:0] regfile_wdata_mux;
+ reg regfile_we_mux;
+ reg [4:0] regfile_waddr_mux;
+ always @(*)
+ if (dbg_reg_wreq_i) begin
+ regfile_wdata_mux = dbg_reg_wdata_i;
+ regfile_waddr_mux = dbg_reg_waddr_i;
+ regfile_we_mux = 1'b1;
+ end
+ else begin
+ regfile_we_mux = regfile_we;
+ regfile_waddr_mux = regfile_alu_waddr_id;
+ if (select_data_rf == 1'd0)
+ regfile_wdata_mux = regfile_wdata_lsu_i;
+ else if (csr_access)
+ regfile_wdata_mux = csr_rdata_i;
+ else
+ regfile_wdata_mux = regfile_wdata_ex_i;
+ end
+ zeroriscy_register_file #(.RV32E(RV32E)) registers_i(
+ .clk(clk),
+ .rst_n(rst_n),
+ .test_en_i(test_en_i),
+ .raddr_a_i(regfile_addr_ra_id),
+ .rdata_a_o(regfile_data_ra_id),
+ .raddr_b_i((dbg_reg_rreq_i == 1'b0 ? regfile_addr_rb_id : dbg_reg_raddr_i)),
+ .rdata_b_o(regfile_data_rb_id),
+ .waddr_a_i(regfile_waddr_mux),
+ .wdata_a_i(regfile_wdata_mux),
+ .we_a_i(regfile_we_mux)
+ );
+ assign dbg_reg_rdata_o = regfile_data_rb_id;
+ assign multdiv_int_en = mult_int_en | div_int_en;
+ zeroriscy_decoder #(.RV32M(RV32M)) decoder_i(
+ .deassert_we_i(deassert_we),
+ .data_misaligned_i(data_misaligned_i),
+ .branch_mux_i(branch_mux_dec),
+ .jump_mux_i(jump_mux_dec),
+ .illegal_insn_o(illegal_insn_dec),
+ .ebrk_insn_o(ebrk_insn),
+ .mret_insn_o(mret_insn_dec),
+ .ecall_insn_o(ecall_insn_dec),
+ .pipe_flush_o(pipe_flush_dec),
+ .instr_rdata_i(instr),
+ .illegal_c_insn_i(illegal_c_insn_i),
+ .alu_operator_o(alu_operator),
+ .alu_op_a_mux_sel_o(alu_op_a_mux_sel),
+ .alu_op_b_mux_sel_o(alu_op_b_mux_sel),
+ .imm_a_mux_sel_o(imm_a_mux_sel),
+ .imm_b_mux_sel_o(imm_b_mux_sel),
+ .mult_int_en_o(mult_int_en),
+ .div_int_en_o(div_int_en),
+ .multdiv_operator_o(multdiv_operator),
+ .multdiv_signed_mode_o(multdiv_signed_mode),
+ .regfile_we_o(regfile_we_id),
+ .csr_access_o(csr_access),
+ .csr_op_o(csr_op),
+ .csr_status_o(csr_status),
+ .data_req_o(data_req_id),
+ .data_we_o(data_we_id),
+ .data_type_o(data_type_id),
+ .data_sign_extension_o(data_sign_ext_id),
+ .data_reg_offset_o(data_reg_offset_id),
+ .data_load_event_o(data_load_event_id),
+ .jump_in_id_o(jump_in_id),
+ .branch_in_id_o(branch_in_id)
+ );
+ zeroriscy_controller controller_i(
+ .clk(clk),
+ .rst_n(rst_n),
+ .fetch_enable_i(fetch_enable_i),
+ .ctrl_busy_o(ctrl_busy_o),
+ .first_fetch_o(core_ctrl_firstfetch_o),
+ .is_decoding_o(is_decoding_o),
+ .deassert_we_o(deassert_we),
+ .illegal_insn_i(illegal_insn_dec | illegal_reg_rv32e),
+ .ecall_insn_i(ecall_insn_dec),
+ .mret_insn_i(mret_insn_dec),
+ .pipe_flush_i(pipe_flush_dec),
+ .ebrk_insn_i(ebrk_insn),
+ .csr_status_i(csr_status),
+ .instr_valid_i(instr_valid_i),
+ .instr_req_o(instr_req_o),
+ .pc_set_o(pc_set_o),
+ .pc_mux_o(pc_mux_o),
+ .exc_pc_mux_o(exc_pc_mux_o),
+ .exc_cause_o(exc_cause_o),
+ .data_misaligned_i(data_misaligned_i),
+ .branch_in_id_i(branch_in_id),
+ .branch_taken_ex_i(branch_taken_ex),
+ .branch_set_i(branch_set_q),
+ .jump_set_i(jump_set),
+ .instr_multicyle_i(instr_multicyle),
+ .irq_req_ctrl_i(irq_req_ctrl),
+ .irq_id_ctrl_i(irq_id_ctrl),
+ .m_IE_i(m_irq_enable_i),
+ .irq_ack_o(irq_ack_o),
+ .irq_id_o(irq_id_o),
+ .exc_ack_o(exc_ack),
+ .exc_kill_o(exc_kill),
+ .csr_save_cause_o(csr_save_cause_o),
+ .csr_cause_o(csr_cause_o),
+ .csr_save_if_o(csr_save_if_o),
+ .csr_save_id_o(csr_save_id_o),
+ .csr_restore_mret_id_o(csr_restore_mret_id_o),
+ .dbg_req_i(dbg_req_i),
+ .dbg_ack_o(dbg_ack_o),
+ .dbg_stall_i(dbg_stall_i),
+ .dbg_jump_req_i(dbg_jump_req_i),
+ .dbg_settings_i(dbg_settings_i),
+ .dbg_trap_o(dbg_trap_o),
+ .operand_a_fw_mux_sel_o(operand_a_fw_mux_sel),
+ .halt_if_o(halt_if_o),
+ .halt_id_o(halt_id),
+ .id_ready_i(id_ready_o),
+ .perf_jump_o(perf_jump_o),
+ .perf_tbranch_o(perf_tbranch_o)
+ );
+ zeroriscy_int_controller int_controller_i(
+ .clk(clk),
+ .rst_n(rst_n),
+ .irq_req_ctrl_o(irq_req_ctrl),
+ .irq_id_ctrl_o(irq_id_ctrl),
+ .ctrl_ack_i(exc_ack),
+ .ctrl_kill_i(exc_kill),
+ .irq_i(irq_i),
+ .irq_id_i(irq_id_i),
+ .m_IE_i(m_irq_enable_i)
+ );
+ assign data_we_ex_o = data_we_id;
+ assign data_type_ex_o = data_type_id;
+ assign data_sign_ext_ex_o = data_sign_ext_id;
+ assign data_wdata_ex_o = regfile_data_rb_id;
+ assign data_req_ex_o = data_req_id;
+ assign data_reg_offset_ex_o = data_reg_offset_id;
+ assign data_load_event_ex_o = data_load_event_id;
+ assign alu_operator_ex_o = alu_operator;
+ assign alu_operand_a_ex_o = alu_operand_a;
+ assign alu_operand_b_ex_o = alu_operand_b;
+ assign csr_access_ex_o = csr_access;
+ assign csr_op_ex_o = csr_op;
+ assign branch_in_ex_o = branch_in_id;
+ assign mult_en_ex_o = mult_int_en;
+ assign div_en_ex_o = div_int_en;
+ assign multdiv_operator_ex_o = multdiv_operator;
+ assign multdiv_signed_mode_ex_o = multdiv_signed_mode;
+ assign multdiv_operand_a_ex_o = regfile_data_ra_id;
+ assign multdiv_operand_b_ex_o = regfile_data_rb_id;
+ reg id_wb_fsm_cs;
+ reg id_wb_fsm_ns;
+ always @(posedge clk or negedge rst_n) begin : EX_WB_Pipeline_Register
+ if (~rst_n) begin
+ id_wb_fsm_cs <= 1'd0;
+ branch_set_q <= 1'b0;
+ end
+ else begin
+ id_wb_fsm_cs <= id_wb_fsm_ns;
+ branch_set_q <= branch_set_n;
+ end
+ end
+ always @(*) begin
+ id_wb_fsm_ns = id_wb_fsm_cs;
+ regfile_we = regfile_we_id;
+ load_stall = 1'b0;
+ multdiv_stall = 1'b0;
+ jump_stall = 1'b0;
+ branch_stall = 1'b0;
+ select_data_rf = 1'd1;
+ instr_multicyle = 1'b0;
+ branch_set_n = 1'b0;
+ branch_mux_dec = 1'b0;
+ jump_set = 1'b0;
+ jump_mux_dec = 1'b0;
+ perf_branch_o = 1'b0;
+ case (id_wb_fsm_cs)
+ 1'd0: begin
+ jump_mux_dec = 1'b1;
+ branch_mux_dec = 1'b1;
+ case (1'b1)
+ data_req_id: begin
+ regfile_we = 1'b0;
+ id_wb_fsm_ns = 1'd1;
+ load_stall = 1'b1;
+ instr_multicyle = 1'b1;
+ end
+ branch_in_id: begin
+ id_wb_fsm_ns = (branch_decision_i ? 1'd1 : 1'd0);
+ branch_stall = branch_decision_i;
+ instr_multicyle = branch_decision_i;
+ branch_set_n = branch_decision_i;
+ perf_branch_o = 1'b1;
+ end
+ multdiv_int_en: begin
+ regfile_we = 1'b0;
+ id_wb_fsm_ns = 1'd1;
+ multdiv_stall = 1'b1;
+ instr_multicyle = 1'b1;
+ end
+ jump_in_id: begin
+ regfile_we = 1'b0;
+ id_wb_fsm_ns = 1'd1;
+ jump_stall = 1'b1;
+ instr_multicyle = 1'b1;
+ jump_set = 1'b1;
+ end
+ default:
+ ;
+ endcase
+ end
+ 1'd1:
+ if (ex_ready_i) begin
+ regfile_we = regfile_we_id;
+ id_wb_fsm_ns = 1'd0;
+ load_stall = 1'b0;
+ multdiv_stall = 1'b0;
+ select_data_rf = (data_req_id ? 1'd0 : 1'd1);
+ end
+ else begin
+ regfile_we = 1'b0;
+ instr_multicyle = 1'b1;
+ case (1'b1)
+ data_req_id: load_stall = 1'b1;
+ multdiv_int_en: multdiv_stall = 1'b1;
+ default:
+ ;
+ endcase
+ end
+ default:
+ ;
+ endcase
+ end
+ assign id_ready_o = ((~load_stall & ~branch_stall) & ~jump_stall) & ~multdiv_stall;
+ assign id_valid_o = ~halt_id & id_ready_o;
+endmodule
diff --git a/verilog/rtl/ips/zero-riscy/zeroriscy_if_stage.v b/verilog/rtl/ips/zero-riscy/zeroriscy_if_stage.v
new file mode 100644
index 0000000..f80080c
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/zeroriscy_if_stage.v
@@ -0,0 +1,452 @@
+module zeroriscy_if_stage (
+ clk,
+ rst_n,
+ boot_addr_i,
+ req_i,
+ instr_req_o,
+ instr_addr_o,
+ instr_gnt_i,
+ instr_rvalid_i,
+ instr_rdata_i,
+ instr_valid_id_o,
+ instr_rdata_id_o,
+ is_compressed_id_o,
+ illegal_c_insn_id_o,
+ pc_if_o,
+ pc_id_o,
+ clear_instr_valid_i,
+ pc_set_i,
+ exception_pc_reg_i,
+ pc_mux_i,
+ exc_pc_mux_i,
+ exc_vec_pc_mux_i,
+ jump_target_ex_i,
+ dbg_jump_addr_i,
+ halt_if_i,
+ id_ready_i,
+ if_valid_o,
+ if_busy_o,
+ perf_imiss_o
+);
+parameter OPCODE_SYSTEM = 7'h73;
+parameter OPCODE_FENCE = 7'h0f;
+parameter OPCODE_OP = 7'h33;
+parameter OPCODE_OPIMM = 7'h13;
+parameter OPCODE_STORE = 7'h23;
+parameter OPCODE_LOAD = 7'h03;
+parameter OPCODE_BRANCH = 7'h63;
+parameter OPCODE_JALR = 7'h67;
+parameter OPCODE_JAL = 7'h6f;
+parameter OPCODE_AUIPC = 7'h17;
+parameter OPCODE_LUI = 7'h37;
+
+// those opcodes are now used for PULP custom instructions
+// parameter OPCODE_CUST0 = 7'h0b
+// parameter OPCODE_CUST1 = 7'h2b
+
+// PULP custom
+parameter OPCODE_LOAD_POST = 7'h0b;
+parameter OPCODE_STORE_POST = 7'h2b;
+parameter OPCODE_PULP_OP = 7'h5b;
+parameter OPCODE_VECOP = 7'h57;
+parameter OPCODE_HWLOOP = 7'h7b;
+
+parameter REGC_S1 = 2'b10;
+parameter REGC_RD = 2'b01;
+parameter REGC_ZERO = 2'b11;
+
+
+//////////////////////////////////////////////////////////////////////////////
+// _ _ _ _ ___ _ _ //
+// / \ | | | | | | / _ \ _ __ ___ _ __ __ _| |_(_) ___ _ __ ___ //
+// / _ \ | | | | | | | | | | '_ \ / _ \ '__/ _` | __| |/ _ \| '_ \/ __| //
+// / ___ \| |__| |_| | | |_| | |_) | __/ | | (_| | |_| | (_) | | | \__ \ //
+// /_/ \_\_____\___/ \___/| .__/ \___|_| \__,_|\__|_|\___/|_| |_|___/ //
+// |_| //
+//////////////////////////////////////////////////////////////////////////////
+
+parameter ALU_OP_WIDTH = 6;
+
+parameter ALU_ADD = 6'b011000;
+parameter ALU_SUB = 6'b011001;
+parameter ALU_ADDU = 6'b011010;
+parameter ALU_SUBU = 6'b011011;
+parameter ALU_ADDR = 6'b011100;
+parameter ALU_SUBR = 6'b011101;
+parameter ALU_ADDUR = 6'b011110;
+parameter ALU_SUBUR = 6'b011111;
+
+parameter ALU_XOR = 6'b101111;
+parameter ALU_OR = 6'b101110;
+parameter ALU_AND = 6'b010101;
+
+// Shifts
+parameter ALU_SRA = 6'b100100;
+parameter ALU_SRL = 6'b100101;
+parameter ALU_ROR = 6'b100110;
+parameter ALU_SLL = 6'b100111;
+
+// bit manipulation
+parameter ALU_BEXT = 6'b101000;
+parameter ALU_BEXTU = 6'b101001;
+parameter ALU_BINS = 6'b101010;
+parameter ALU_BCLR = 6'b101011;
+parameter ALU_BSET = 6'b101100;
+
+// Bit counting
+parameter ALU_FF1 = 6'b110110;
+parameter ALU_FL1 = 6'b110111;
+parameter ALU_CNT = 6'b110100;
+parameter ALU_CLB = 6'b110101;
+
+// Sign-/zero-extensions
+parameter ALU_EXTS = 6'b111110;
+parameter ALU_EXT = 6'b111111;
+
+// Comparisons
+parameter ALU_LTS = 6'b000000;
+parameter ALU_LTU = 6'b000001;
+parameter ALU_LES = 6'b000100;
+parameter ALU_LEU = 6'b000101;
+parameter ALU_GTS = 6'b001000;
+parameter ALU_GTU = 6'b001001;
+parameter ALU_GES = 6'b001010;
+parameter ALU_GEU = 6'b001011;
+parameter ALU_EQ = 6'b001100;
+parameter ALU_NE = 6'b001101;
+
+// Set Lower Than operations
+parameter ALU_SLTS = 6'b000010;
+parameter ALU_SLTU = 6'b000011;
+parameter ALU_SLETS = 6'b000110;
+parameter ALU_SLETU = 6'b000111;
+
+// Absolute value
+parameter ALU_ABS = 6'b010100;
+parameter ALU_CLIP = 6'b010110;
+parameter ALU_CLIPU = 6'b010111;
+
+// Insert/extract
+parameter ALU_INS = 6'b101101;
+
+// min/max
+parameter ALU_MIN = 6'b010000;
+parameter ALU_MINU = 6'b010001;
+parameter ALU_MAX = 6'b010010;
+parameter ALU_MAXU = 6'b010011;
+
+// div/rem
+parameter ALU_DIVU = 6'b110000; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_DIV = 6'b110001; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REMU = 6'b110010; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REM = 6'b110011; // bit 0 is used for signed mode, bit 1 is used for remdiv
+
+parameter ALU_SHUF = 6'b111010;
+parameter ALU_SHUF2 = 6'b111011;
+parameter ALU_PCKLO = 6'b111000;
+parameter ALU_PCKHI = 6'b111001;
+
+
+parameter MD_OP_MULL = 2'b00;
+parameter MD_OP_MULH = 2'b01;
+parameter MD_OP_DIV = 2'b10;
+parameter MD_OP_REM = 2'b11;
+
+// vector modes
+parameter VEC_MODE32 = 2'b00;
+parameter VEC_MODE16 = 2'b10;
+parameter VEC_MODE8 = 2'b11;
+
+
+/////////////////////////////////////////////////////////
+// ____ ____ ____ _ _ //
+// / ___/ ___| | _ \ ___ __ _(_)___| |_ ___ _ __ //
+// | | \___ \ | |_) / _ \/ _` | / __| __/ _ \ '__| //
+// | |___ ___) | | _ < __/ (_| | \__ \ || __/ | //
+// \____|____/ |_| \_\___|\__, |_|___/\__\___|_| //
+// |___/ //
+/////////////////////////////////////////////////////////
+
+// CSR operations
+parameter CSR_OP_NONE = 2'b00;
+parameter CSR_OP_WRITE = 2'b01;
+parameter CSR_OP_SET = 2'b10;
+parameter CSR_OP_CLEAR = 2'b11;
+
+
+// SPR for debugger, not accessible by CPU
+parameter SP_DVR0 = 16'h3000;
+parameter SP_DCR0 = 16'h3008;
+parameter SP_DMR1 = 16'h3010;
+parameter SP_DMR2 = 16'h3011;
+
+parameter SP_DVR_MSB = 8'h00;
+parameter SP_DCR_MSB = 8'h01;
+parameter SP_DMR_MSB = 8'h02;
+parameter SP_DSR_MSB = 8'h04;
+
+// Privileged mode
+typedef enum logic[1:0] {
+ PRIV_LVL_M = 2'b11,
+ PRIV_LVL_H = 2'b10,
+ PRIV_LVL_S = 2'b01,
+ PRIV_LVL_U = 2'b00
+} PrivLvl_t;
+
+///////////////////////////////////////////////
+// ___ ____ ____ _ //
+// |_ _| _ \ / ___|| |_ __ _ __ _ ___ //
+// | || | | | \___ \| __/ _` |/ _` |/ _ \ //
+// | || |_| | ___) | || (_| | (_| | __/ //
+// |___|____/ |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// forwarding operand mux
+parameter SEL_REGFILE = 2'b00;
+parameter SEL_FW_EX = 2'b01;
+parameter SEL_FW_WB = 2'b10;
+parameter SEL_MISALIGNED = 2'b11;
+
+// operand a selection
+parameter OP_A_REGA_OR_FWD = 3'b000;
+parameter OP_A_CURRPC = 3'b001;
+parameter OP_A_IMM = 3'b010;
+parameter OP_A_REGB_OR_FWD = 3'b011;
+parameter OP_A_REGC_OR_FWD = 3'b100;
+
+// immediate a selection
+parameter IMMA_Z = 1'b0;
+parameter IMMA_ZERO = 1'b1;
+
+// operand b selection
+parameter OP_B_REGB_OR_FWD = 3'b000;
+parameter OP_B_REGC_OR_FWD = 3'b001;
+parameter OP_B_IMM = 3'b010;
+parameter OP_B_REGA_OR_FWD = 3'b011;
+parameter OP_B_BMASK = 3'b100;
+parameter OP_B_ZERO = 3'b101;
+
+// immediate b selection
+parameter IMMB_I = 4'b0000;
+parameter IMMB_S = 4'b0001;
+parameter IMMB_U = 4'b0010;
+parameter IMMB_PCINCR = 4'b0011;
+parameter IMMB_S2 = 4'b0100;
+parameter IMMB_S3 = 4'b0101;
+parameter IMMB_VS = 4'b0110;
+parameter IMMB_VU = 4'b0111;
+parameter IMMB_SHUF = 4'b1000;
+parameter IMMB_CLIP = 4'b1001;
+parameter IMMB_BI = 4'b1011;
+parameter IMMB_UJ = 4'b1100;
+parameter IMMB_SB = 4'b1101;
+
+// bit mask selection
+parameter BMASK_A_ZERO = 1'b0;
+parameter BMASK_A_S3 = 1'b1;
+
+parameter BMASK_B_S2 = 2'b00;
+parameter BMASK_B_S3 = 2'b01;
+parameter BMASK_B_ZERO = 2'b10;
+parameter BMASK_B_ONE = 2'b11;
+
+parameter BMASK_A_REG = 1'b0;
+parameter BMASK_A_IMM = 1'b1;
+parameter BMASK_B_REG = 1'b0;
+parameter BMASK_B_IMM = 1'b1;
+
+
+
+///////////////////////////////////////////////
+// ___ _____ ____ _ //
+// |_ _| ___| / ___|| |_ __ _ __ _ ___ //
+// | || |_ \___ \| __/ _` |/ _` |/ _ \ //
+// | || _| ___) | || (_| | (_| | __/ //
+// |___|_| |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// PC mux selector defines
+parameter PC_BOOT = 3'b000;
+parameter PC_JUMP = 3'b010;
+parameter PC_EXCEPTION = 3'b100;
+parameter PC_ERET = 3'b101;
+parameter PC_DBG_NPC = 3'b111;
+
+// Exception PC mux selector defines
+parameter EXC_PC_ILLINSN = 2'b00;
+parameter EXC_PC_ECALL = 2'b01;
+parameter EXC_PC_LOAD = 2'b10;
+parameter EXC_PC_STORE = 2'b10;
+parameter EXC_PC_IRQ = 2'b11;
+
+// Exception Cause
+parameter EXC_CAUSE_ILLEGAL_INSN = 6'h02;
+parameter EXC_CAUSE_BREAKPOINT = 6'h03;
+parameter EXC_CAUSE_ECALL_MMODE = 6'h0B;
+
+// Exceptions offsets
+// target address = {boot_addr[31:8], EXC_OFF} (boot_addr must be 32 BYTE aligned!)
+// offset 00 to 7e is used for external interrupts
+parameter EXC_OFF_RST = 8'h80;
+parameter EXC_OFF_ILLINSN = 8'h84;
+parameter EXC_OFF_ECALL = 8'h88;
+parameter EXC_OFF_LSUERR = 8'h8c;
+
+
+// Debug module
+parameter DBG_SETS_W = 6;
+
+parameter DBG_SETS_IRQ = 5;
+parameter DBG_SETS_ECALL = 4;
+parameter DBG_SETS_EILL = 3;
+parameter DBG_SETS_ELSU = 2;
+parameter DBG_SETS_EBRK = 1;
+parameter DBG_SETS_SSTE = 0;
+
+parameter DBG_CAUSE_HALT = 6'h1F;
+ input wire clk;
+ input wire rst_n;
+ input wire [31:0] boot_addr_i;
+ input wire req_i;
+ output wire instr_req_o;
+ output wire [31:0] instr_addr_o;
+ input wire instr_gnt_i;
+ input wire instr_rvalid_i;
+ input wire [31:0] instr_rdata_i;
+ output reg instr_valid_id_o;
+ output reg [31:0] instr_rdata_id_o;
+ output reg is_compressed_id_o;
+ output reg illegal_c_insn_id_o;
+ output wire [31:0] pc_if_o;
+ output reg [31:0] pc_id_o;
+ input wire clear_instr_valid_i;
+ input wire pc_set_i;
+ input wire [31:0] exception_pc_reg_i;
+ input wire [2:0] pc_mux_i;
+ input wire [1:0] exc_pc_mux_i;
+ input wire [4:0] exc_vec_pc_mux_i;
+ input wire [31:0] jump_target_ex_i;
+ input wire [31:0] dbg_jump_addr_i;
+ input wire halt_if_i;
+ input wire id_ready_i;
+ output wire if_valid_o;
+ output wire if_busy_o;
+ output wire perf_imiss_o;
+ reg [0:0] offset_fsm_cs;
+ reg [0:0] offset_fsm_ns;
+ reg valid;
+ wire if_ready;
+ wire prefetch_busy;
+ reg branch_req;
+ reg [31:0] fetch_addr_n;
+ wire fetch_valid;
+ reg fetch_ready;
+ wire [31:0] fetch_rdata;
+ wire [31:0] fetch_addr;
+ reg [31:0] exc_pc;
+ always @(*) begin : EXC_PC_MUX
+ exc_pc = 1'sb0;
+ case (exc_pc_mux_i)
+ EXC_PC_ILLINSN: exc_pc = {boot_addr_i[31:8], EXC_OFF_ILLINSN};
+ EXC_PC_ECALL: exc_pc = {boot_addr_i[31:8], EXC_OFF_ECALL};
+ EXC_PC_IRQ: exc_pc = {boot_addr_i[31:8], 1'b0, exc_vec_pc_mux_i[4:0], 2'b00};
+ default:
+ ;
+ endcase
+ end
+ always @(*) begin
+ fetch_addr_n = 1'sb0;
+ case (pc_mux_i)
+ PC_BOOT: fetch_addr_n = {boot_addr_i[31:8], EXC_OFF_RST};
+ PC_JUMP: fetch_addr_n = jump_target_ex_i;
+ PC_EXCEPTION: fetch_addr_n = exc_pc;
+ PC_ERET: fetch_addr_n = exception_pc_reg_i;
+ PC_DBG_NPC: fetch_addr_n = dbg_jump_addr_i;
+ default:
+ ;
+ endcase
+ end
+ zeroriscy_prefetch_buffer prefetch_buffer_i(
+ .clk(clk),
+ .rst_n(rst_n),
+ .req_i(req_i),
+ .branch_i(branch_req),
+ .addr_i({fetch_addr_n[31:1], 1'b0}),
+ .ready_i(fetch_ready),
+ .valid_o(fetch_valid),
+ .rdata_o(fetch_rdata),
+ .addr_o(fetch_addr),
+ .instr_req_o(instr_req_o),
+ .instr_addr_o(instr_addr_o),
+ .instr_gnt_i(instr_gnt_i),
+ .instr_rvalid_i(instr_rvalid_i),
+ .instr_rdata_i(instr_rdata_i),
+ .busy_o(prefetch_busy)
+ );
+ always @(posedge clk or negedge rst_n)
+ if (rst_n == 1'b0)
+ offset_fsm_cs <= 1'd1;
+ else
+ offset_fsm_cs <= offset_fsm_ns;
+ always @(*) begin
+ offset_fsm_ns = offset_fsm_cs;
+ fetch_ready = 1'b0;
+ branch_req = 1'b0;
+ valid = 1'b0;
+ case (offset_fsm_cs)
+ 1'd1:
+ if (req_i) begin
+ branch_req = 1'b1;
+ offset_fsm_ns = 1'd0;
+ end
+ 1'd0:
+ if (fetch_valid) begin
+ valid = 1'b1;
+ if (req_i && if_valid_o) begin
+ fetch_ready = 1'b1;
+ offset_fsm_ns = 1'd0;
+ end
+ end
+ default: offset_fsm_ns = 1'd1;
+ endcase
+ if (pc_set_i) begin
+ valid = 1'b0;
+ branch_req = 1'b1;
+ offset_fsm_ns = 1'd0;
+ end
+ end
+ assign pc_if_o = fetch_addr;
+ assign if_busy_o = prefetch_busy;
+ assign perf_imiss_o = ~fetch_valid | branch_req;
+ wire [31:0] instr_decompressed;
+ wire illegal_c_insn;
+ wire instr_compressed_int;
+ zeroriscy_compressed_decoder compressed_decoder_i(
+ .instr_i(fetch_rdata),
+ .instr_o(instr_decompressed),
+ .is_compressed_o(instr_compressed_int),
+ .illegal_instr_o(illegal_c_insn)
+ );
+ always @(posedge clk or negedge rst_n) begin : IF_ID_PIPE_REGISTERS
+ if (rst_n == 1'b0) begin
+ instr_valid_id_o <= 1'b0;
+ instr_rdata_id_o <= 1'sb0;
+ illegal_c_insn_id_o <= 1'b0;
+ is_compressed_id_o <= 1'b0;
+ pc_id_o <= 1'sb0;
+ end
+ else if (if_valid_o) begin
+ instr_valid_id_o <= 1'b1;
+ instr_rdata_id_o <= instr_decompressed;
+ illegal_c_insn_id_o <= illegal_c_insn;
+ is_compressed_id_o <= instr_compressed_int;
+ pc_id_o <= pc_if_o;
+ end
+ else if (clear_instr_valid_i)
+ instr_valid_id_o <= 1'b0;
+ end
+ assign if_ready = valid & id_ready_i;
+ assign if_valid_o = ~halt_if_i & if_ready;
+endmodule
diff --git a/verilog/rtl/ips/zero-riscy/zeroriscy_int_controller.v b/verilog/rtl/ips/zero-riscy/zeroriscy_int_controller.v
new file mode 100644
index 0000000..72b8738
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/zeroriscy_int_controller.v
@@ -0,0 +1,48 @@
+module zeroriscy_int_controller (
+ clk,
+ rst_n,
+ irq_req_ctrl_o,
+ irq_id_ctrl_o,
+ ctrl_ack_i,
+ ctrl_kill_i,
+ irq_i,
+ irq_id_i,
+ m_IE_i
+);
+ input wire clk;
+ input wire rst_n;
+ output wire irq_req_ctrl_o;
+ output wire [4:0] irq_id_ctrl_o;
+ input wire ctrl_ack_i;
+ input wire ctrl_kill_i;
+ input wire irq_i;
+ input wire [4:0] irq_id_i;
+ input wire m_IE_i;
+ reg [1:0] exc_ctrl_cs;
+ wire [1:0] exc_ctrl_ns;
+ wire irq_enable_ext;
+ reg [4:0] irq_id_q;
+ assign irq_enable_ext = m_IE_i;
+ assign irq_req_ctrl_o = exc_ctrl_cs == 2'd1;
+ assign irq_id_ctrl_o = irq_id_q;
+ always @(posedge clk or negedge rst_n)
+ if (rst_n == 1'b0) begin
+ irq_id_q <= 1'sb0;
+ exc_ctrl_cs <= 2'd0;
+ end
+ else
+ case (exc_ctrl_cs)
+ 2'd0:
+ if (irq_enable_ext & irq_i) begin
+ exc_ctrl_cs <= 2'd1;
+ irq_id_q <= irq_id_i;
+ end
+ 2'd1:
+ case (1'b1)
+ ctrl_ack_i: exc_ctrl_cs <= 2'd2;
+ ctrl_kill_i: exc_ctrl_cs <= 2'd0;
+ default: exc_ctrl_cs <= 2'd1;
+ endcase
+ 2'd2: exc_ctrl_cs <= 2'd0;
+ endcase
+endmodule
diff --git a/verilog/rtl/ips/zero-riscy/zeroriscy_load_store_unit.v b/verilog/rtl/ips/zero-riscy/zeroriscy_load_store_unit.v
new file mode 100644
index 0000000..e8daa39
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/zeroriscy_load_store_unit.v
@@ -0,0 +1,295 @@
+module zeroriscy_load_store_unit (
+ clk,
+ rst_n,
+ data_req_o,
+ data_gnt_i,
+ data_rvalid_i,
+ data_err_i,
+ data_addr_o,
+ data_we_o,
+ data_be_o,
+ data_wdata_o,
+ data_rdata_i,
+ data_we_ex_i,
+ data_type_ex_i,
+ data_wdata_ex_i,
+ data_reg_offset_ex_i,
+ data_sign_ext_ex_i,
+ data_rdata_ex_o,
+ data_req_ex_i,
+ adder_result_ex_i,
+ data_misaligned_o,
+ misaligned_addr_o,
+ load_err_o,
+ store_err_o,
+ lsu_update_addr_o,
+ data_valid_o,
+ busy_o
+);
+ input wire clk;
+ input wire rst_n;
+ output reg data_req_o;
+ input wire data_gnt_i;
+ input wire data_rvalid_i;
+ input wire data_err_i;
+ output wire [31:0] data_addr_o;
+ output wire data_we_o;
+ output wire [3:0] data_be_o;
+ output wire [31:0] data_wdata_o;
+ input wire [31:0] data_rdata_i;
+ input wire data_we_ex_i;
+ input wire [1:0] data_type_ex_i;
+ input wire [31:0] data_wdata_ex_i;
+ input wire [1:0] data_reg_offset_ex_i;
+ input wire data_sign_ext_ex_i;
+ output wire [31:0] data_rdata_ex_o;
+ input wire data_req_ex_i;
+ input wire [31:0] adder_result_ex_i;
+ output reg data_misaligned_o;
+ output reg [31:0] misaligned_addr_o;
+ output wire load_err_o;
+ output wire store_err_o;
+ output reg lsu_update_addr_o;
+ output reg data_valid_o;
+ output wire busy_o;
+ wire [31:0] data_addr_int;
+ reg [1:0] data_type_q;
+ reg [1:0] rdata_offset_q;
+ reg data_sign_ext_q;
+ reg data_we_q;
+ wire [1:0] wdata_offset;
+ reg [3:0] data_be;
+ reg [31:0] data_wdata;
+ wire misaligned_st;
+ reg data_misaligned;
+ reg data_misaligned_q;
+ reg increase_address;
+ reg [2:0] CS;
+ reg [2:0] NS;
+ reg [31:0] rdata_q;
+ always @(*)
+ case (data_type_ex_i)
+ 2'b00:
+ if (misaligned_st == 1'b0)
+ case (data_addr_int[1:0])
+ 2'b00: data_be = 4'b1111;
+ 2'b01: data_be = 4'b1110;
+ 2'b10: data_be = 4'b1100;
+ 2'b11: data_be = 4'b1000;
+ endcase
+ else
+ case (data_addr_int[1:0])
+ 2'b00: data_be = 4'b0000;
+ 2'b01: data_be = 4'b0001;
+ 2'b10: data_be = 4'b0011;
+ 2'b11: data_be = 4'b0111;
+ endcase
+ 2'b01:
+ if (misaligned_st == 1'b0)
+ case (data_addr_int[1:0])
+ 2'b00: data_be = 4'b0011;
+ 2'b01: data_be = 4'b0110;
+ 2'b10: data_be = 4'b1100;
+ 2'b11: data_be = 4'b1000;
+ endcase
+ else
+ data_be = 4'b0001;
+ 2'b10, 2'b11:
+ case (data_addr_int[1:0])
+ 2'b00: data_be = 4'b0001;
+ 2'b01: data_be = 4'b0010;
+ 2'b10: data_be = 4'b0100;
+ 2'b11: data_be = 4'b1000;
+ endcase
+ endcase
+ assign wdata_offset = data_addr_int[1:0] - data_reg_offset_ex_i[1:0];
+ always @(*)
+ case (wdata_offset)
+ 2'b00: data_wdata = data_wdata_ex_i[31:0];
+ 2'b01: data_wdata = {data_wdata_ex_i[23:0], data_wdata_ex_i[31:24]};
+ 2'b10: data_wdata = {data_wdata_ex_i[15:0], data_wdata_ex_i[31:16]};
+ 2'b11: data_wdata = {data_wdata_ex_i[7:0], data_wdata_ex_i[31:8]};
+ endcase
+ always @(posedge clk or negedge rst_n)
+ if (rst_n == 1'b0) begin
+ data_type_q <= 1'sb0;
+ rdata_offset_q <= 1'sb0;
+ data_sign_ext_q <= 1'sb0;
+ data_we_q <= 1'b0;
+ end
+ else if (data_gnt_i == 1'b1) begin
+ data_type_q <= data_type_ex_i;
+ rdata_offset_q <= data_addr_int[1:0];
+ data_sign_ext_q <= data_sign_ext_ex_i;
+ data_we_q <= data_we_ex_i;
+ end
+ reg [31:0] data_rdata_ext;
+ reg [31:0] rdata_w_ext;
+ reg [31:0] rdata_h_ext;
+ reg [31:0] rdata_b_ext;
+ always @(*)
+ case (rdata_offset_q)
+ 2'b00: rdata_w_ext = data_rdata_i[31:0];
+ 2'b01: rdata_w_ext = {data_rdata_i[7:0], rdata_q[31:8]};
+ 2'b10: rdata_w_ext = {data_rdata_i[15:0], rdata_q[31:16]};
+ 2'b11: rdata_w_ext = {data_rdata_i[23:0], rdata_q[31:24]};
+ endcase
+ always @(*)
+ case (rdata_offset_q)
+ 2'b00:
+ if (data_sign_ext_q == 1'b0)
+ rdata_h_ext = {16'h0000, data_rdata_i[15:0]};
+ else
+ rdata_h_ext = {{16 {data_rdata_i[15]}}, data_rdata_i[15:0]};
+ 2'b01:
+ if (data_sign_ext_q == 1'b0)
+ rdata_h_ext = {16'h0000, data_rdata_i[23:8]};
+ else
+ rdata_h_ext = {{16 {data_rdata_i[23]}}, data_rdata_i[23:8]};
+ 2'b10:
+ if (data_sign_ext_q == 1'b0)
+ rdata_h_ext = {16'h0000, data_rdata_i[31:16]};
+ else
+ rdata_h_ext = {{16 {data_rdata_i[31]}}, data_rdata_i[31:16]};
+ 2'b11:
+ if (data_sign_ext_q == 1'b0)
+ rdata_h_ext = {16'h0000, data_rdata_i[7:0], rdata_q[31:24]};
+ else
+ rdata_h_ext = {{16 {data_rdata_i[7]}}, data_rdata_i[7:0], rdata_q[31:24]};
+ endcase
+ always @(*)
+ case (rdata_offset_q)
+ 2'b00:
+ if (data_sign_ext_q == 1'b0)
+ rdata_b_ext = {24'h000000, data_rdata_i[7:0]};
+ else
+ rdata_b_ext = {{24 {data_rdata_i[7]}}, data_rdata_i[7:0]};
+ 2'b01:
+ if (data_sign_ext_q == 1'b0)
+ rdata_b_ext = {24'h000000, data_rdata_i[15:8]};
+ else
+ rdata_b_ext = {{24 {data_rdata_i[15]}}, data_rdata_i[15:8]};
+ 2'b10:
+ if (data_sign_ext_q == 1'b0)
+ rdata_b_ext = {24'h000000, data_rdata_i[23:16]};
+ else
+ rdata_b_ext = {{24 {data_rdata_i[23]}}, data_rdata_i[23:16]};
+ 2'b11:
+ if (data_sign_ext_q == 1'b0)
+ rdata_b_ext = {24'h000000, data_rdata_i[31:24]};
+ else
+ rdata_b_ext = {{24 {data_rdata_i[31]}}, data_rdata_i[31:24]};
+ endcase
+ always @(*)
+ case (data_type_q)
+ 2'b00: data_rdata_ext = rdata_w_ext;
+ 2'b01: data_rdata_ext = rdata_h_ext;
+ 2'b10, 2'b11: data_rdata_ext = rdata_b_ext;
+ endcase
+ always @(posedge clk or negedge rst_n)
+ if (rst_n == 1'b0) begin
+ CS <= 3'd0;
+ rdata_q <= 1'sb0;
+ data_misaligned_q <= 1'sb0;
+ misaligned_addr_o <= 32'b00000000000000000000000000000000;
+ end
+ else begin
+ CS <= NS;
+ if (lsu_update_addr_o) begin
+ data_misaligned_q <= data_misaligned;
+ if (increase_address)
+ misaligned_addr_o <= data_addr_int;
+ end
+ if (data_rvalid_i && ~data_we_q)
+ if ((data_misaligned_q == 1'b1) || (data_misaligned == 1'b1))
+ rdata_q <= data_rdata_i;
+ else
+ rdata_q <= data_rdata_ext;
+ end
+ assign data_rdata_ex_o = (data_rvalid_i == 1'b1 ? data_rdata_ext : rdata_q);
+ assign data_addr_o = data_addr_int;
+ assign data_wdata_o = data_wdata;
+ assign data_we_o = data_we_ex_i;
+ assign data_be_o = data_be;
+ assign misaligned_st = data_misaligned_q;
+ assign load_err_o = 1'b0;
+ assign store_err_o = 1'b0;
+ always @(*) begin
+ NS = CS;
+ data_req_o = 1'b0;
+ lsu_update_addr_o = 1'b0;
+ data_valid_o = 1'b0;
+ increase_address = 1'b0;
+ data_misaligned_o = 1'b0;
+ case (CS)
+ 3'd0:
+ if (data_req_ex_i) begin
+ data_req_o = data_req_ex_i;
+ if (data_gnt_i) begin
+ lsu_update_addr_o = 1'b1;
+ increase_address = data_misaligned;
+ NS = (data_misaligned ? 3'd2 : 3'd4);
+ end
+ else
+ NS = (data_misaligned ? 3'd1 : 3'd3);
+ end
+ 3'd1: begin
+ data_req_o = 1'b1;
+ if (data_gnt_i) begin
+ lsu_update_addr_o = 1'b1;
+ increase_address = data_misaligned;
+ NS = 3'd2;
+ end
+ end
+ 3'd2: begin
+ increase_address = 1'b0;
+ data_misaligned_o = 1'b1;
+ data_req_o = 1'b0;
+ lsu_update_addr_o = data_gnt_i;
+ if (data_rvalid_i) begin
+ data_req_o = 1'b1;
+ if (data_gnt_i)
+ NS = 3'd4;
+ else
+ NS = 3'd3;
+ end
+ else
+ NS = 3'd2;
+ end
+ 3'd3: begin
+ data_misaligned_o = data_misaligned_q;
+ data_req_o = 1'b1;
+ if (data_gnt_i) begin
+ lsu_update_addr_o = 1'b1;
+ NS = 3'd4;
+ end
+ end
+ 3'd4: begin
+ data_req_o = 1'b0;
+ if (data_rvalid_i) begin
+ data_valid_o = 1'b1;
+ NS = 3'd0;
+ end
+ else
+ NS = 3'd4;
+ end
+ default: NS = 3'd0;
+ endcase
+ end
+ always @(*) begin
+ data_misaligned = 1'b0;
+ if ((data_req_ex_i == 1'b1) && (data_misaligned_q == 1'b0))
+ case (data_type_ex_i)
+ 2'b00:
+ if (data_addr_int[1:0] != 2'b00)
+ data_misaligned = 1'b1;
+ 2'b01:
+ if (data_addr_int[1:0] == 2'b11)
+ data_misaligned = 1'b1;
+ default:
+ ;
+ endcase
+ end
+ assign data_addr_int = adder_result_ex_i;
+ assign busy_o = (CS == 3'd4) || (data_req_o == 1'b1);
+endmodule
diff --git a/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_fast.v b/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_fast.v
new file mode 100644
index 0000000..dedff19
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_fast.v
@@ -0,0 +1,528 @@
+module zeroriscy_multdiv_fast (
+ clk,
+ rst_n,
+ mult_en_i,
+ div_en_i,
+ operator_i,
+ signed_mode_i,
+ op_a_i,
+ op_b_i,
+ alu_adder_ext_i,
+ alu_adder_i,
+ equal_to_zero,
+ alu_operand_a_o,
+ alu_operand_b_o,
+ multdiv_result_o,
+ ready_o
+);
+parameter OPCODE_SYSTEM = 7'h73;
+parameter OPCODE_FENCE = 7'h0f;
+parameter OPCODE_OP = 7'h33;
+parameter OPCODE_OPIMM = 7'h13;
+parameter OPCODE_STORE = 7'h23;
+parameter OPCODE_LOAD = 7'h03;
+parameter OPCODE_BRANCH = 7'h63;
+parameter OPCODE_JALR = 7'h67;
+parameter OPCODE_JAL = 7'h6f;
+parameter OPCODE_AUIPC = 7'h17;
+parameter OPCODE_LUI = 7'h37;
+
+// those opcodes are now used for PULP custom instructions
+// parameter OPCODE_CUST0 = 7'h0b
+// parameter OPCODE_CUST1 = 7'h2b
+
+// PULP custom
+parameter OPCODE_LOAD_POST = 7'h0b;
+parameter OPCODE_STORE_POST = 7'h2b;
+parameter OPCODE_PULP_OP = 7'h5b;
+parameter OPCODE_VECOP = 7'h57;
+parameter OPCODE_HWLOOP = 7'h7b;
+
+parameter REGC_S1 = 2'b10;
+parameter REGC_RD = 2'b01;
+parameter REGC_ZERO = 2'b11;
+
+
+//////////////////////////////////////////////////////////////////////////////
+// _ _ _ _ ___ _ _ //
+// / \ | | | | | | / _ \ _ __ ___ _ __ __ _| |_(_) ___ _ __ ___ //
+// / _ \ | | | | | | | | | | '_ \ / _ \ '__/ _` | __| |/ _ \| '_ \/ __| //
+// / ___ \| |__| |_| | | |_| | |_) | __/ | | (_| | |_| | (_) | | | \__ \ //
+// /_/ \_\_____\___/ \___/| .__/ \___|_| \__,_|\__|_|\___/|_| |_|___/ //
+// |_| //
+//////////////////////////////////////////////////////////////////////////////
+
+parameter ALU_OP_WIDTH = 6;
+
+parameter ALU_ADD = 6'b011000;
+parameter ALU_SUB = 6'b011001;
+parameter ALU_ADDU = 6'b011010;
+parameter ALU_SUBU = 6'b011011;
+parameter ALU_ADDR = 6'b011100;
+parameter ALU_SUBR = 6'b011101;
+parameter ALU_ADDUR = 6'b011110;
+parameter ALU_SUBUR = 6'b011111;
+
+parameter ALU_XOR = 6'b101111;
+parameter ALU_OR = 6'b101110;
+parameter ALU_AND = 6'b010101;
+
+// Shifts
+parameter ALU_SRA = 6'b100100;
+parameter ALU_SRL = 6'b100101;
+parameter ALU_ROR = 6'b100110;
+parameter ALU_SLL = 6'b100111;
+
+// bit manipulation
+parameter ALU_BEXT = 6'b101000;
+parameter ALU_BEXTU = 6'b101001;
+parameter ALU_BINS = 6'b101010;
+parameter ALU_BCLR = 6'b101011;
+parameter ALU_BSET = 6'b101100;
+
+// Bit counting
+parameter ALU_FF1 = 6'b110110;
+parameter ALU_FL1 = 6'b110111;
+parameter ALU_CNT = 6'b110100;
+parameter ALU_CLB = 6'b110101;
+
+// Sign-/zero-extensions
+parameter ALU_EXTS = 6'b111110;
+parameter ALU_EXT = 6'b111111;
+
+// Comparisons
+parameter ALU_LTS = 6'b000000;
+parameter ALU_LTU = 6'b000001;
+parameter ALU_LES = 6'b000100;
+parameter ALU_LEU = 6'b000101;
+parameter ALU_GTS = 6'b001000;
+parameter ALU_GTU = 6'b001001;
+parameter ALU_GES = 6'b001010;
+parameter ALU_GEU = 6'b001011;
+parameter ALU_EQ = 6'b001100;
+parameter ALU_NE = 6'b001101;
+
+// Set Lower Than operations
+parameter ALU_SLTS = 6'b000010;
+parameter ALU_SLTU = 6'b000011;
+parameter ALU_SLETS = 6'b000110;
+parameter ALU_SLETU = 6'b000111;
+
+// Absolute value
+parameter ALU_ABS = 6'b010100;
+parameter ALU_CLIP = 6'b010110;
+parameter ALU_CLIPU = 6'b010111;
+
+// Insert/extract
+parameter ALU_INS = 6'b101101;
+
+// min/max
+parameter ALU_MIN = 6'b010000;
+parameter ALU_MINU = 6'b010001;
+parameter ALU_MAX = 6'b010010;
+parameter ALU_MAXU = 6'b010011;
+
+// div/rem
+parameter ALU_DIVU = 6'b110000; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_DIV = 6'b110001; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REMU = 6'b110010; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REM = 6'b110011; // bit 0 is used for signed mode, bit 1 is used for remdiv
+
+parameter ALU_SHUF = 6'b111010;
+parameter ALU_SHUF2 = 6'b111011;
+parameter ALU_PCKLO = 6'b111000;
+parameter ALU_PCKHI = 6'b111001;
+
+
+parameter MD_OP_MULL = 2'b00;
+parameter MD_OP_MULH = 2'b01;
+parameter MD_OP_DIV = 2'b10;
+parameter MD_OP_REM = 2'b11;
+
+// vector modes
+parameter VEC_MODE32 = 2'b00;
+parameter VEC_MODE16 = 2'b10;
+parameter VEC_MODE8 = 2'b11;
+
+
+/////////////////////////////////////////////////////////
+// ____ ____ ____ _ _ //
+// / ___/ ___| | _ \ ___ __ _(_)___| |_ ___ _ __ //
+// | | \___ \ | |_) / _ \/ _` | / __| __/ _ \ '__| //
+// | |___ ___) | | _ < __/ (_| | \__ \ || __/ | //
+// \____|____/ |_| \_\___|\__, |_|___/\__\___|_| //
+// |___/ //
+/////////////////////////////////////////////////////////
+
+// CSR operations
+parameter CSR_OP_NONE = 2'b00;
+parameter CSR_OP_WRITE = 2'b01;
+parameter CSR_OP_SET = 2'b10;
+parameter CSR_OP_CLEAR = 2'b11;
+
+
+// SPR for debugger, not accessible by CPU
+parameter SP_DVR0 = 16'h3000;
+parameter SP_DCR0 = 16'h3008;
+parameter SP_DMR1 = 16'h3010;
+parameter SP_DMR2 = 16'h3011;
+
+parameter SP_DVR_MSB = 8'h00;
+parameter SP_DCR_MSB = 8'h01;
+parameter SP_DMR_MSB = 8'h02;
+parameter SP_DSR_MSB = 8'h04;
+
+// Privileged mode
+typedef enum logic[1:0] {
+ PRIV_LVL_M = 2'b11,
+ PRIV_LVL_H = 2'b10,
+ PRIV_LVL_S = 2'b01,
+ PRIV_LVL_U = 2'b00
+} PrivLvl_t;
+
+///////////////////////////////////////////////
+// ___ ____ ____ _ //
+// |_ _| _ \ / ___|| |_ __ _ __ _ ___ //
+// | || | | | \___ \| __/ _` |/ _` |/ _ \ //
+// | || |_| | ___) | || (_| | (_| | __/ //
+// |___|____/ |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// forwarding operand mux
+parameter SEL_REGFILE = 2'b00;
+parameter SEL_FW_EX = 2'b01;
+parameter SEL_FW_WB = 2'b10;
+parameter SEL_MISALIGNED = 2'b11;
+
+// operand a selection
+parameter OP_A_REGA_OR_FWD = 3'b000;
+parameter OP_A_CURRPC = 3'b001;
+parameter OP_A_IMM = 3'b010;
+parameter OP_A_REGB_OR_FWD = 3'b011;
+parameter OP_A_REGC_OR_FWD = 3'b100;
+
+// immediate a selection
+parameter IMMA_Z = 1'b0;
+parameter IMMA_ZERO = 1'b1;
+
+// operand b selection
+parameter OP_B_REGB_OR_FWD = 3'b000;
+parameter OP_B_REGC_OR_FWD = 3'b001;
+parameter OP_B_IMM = 3'b010;
+parameter OP_B_REGA_OR_FWD = 3'b011;
+parameter OP_B_BMASK = 3'b100;
+parameter OP_B_ZERO = 3'b101;
+
+// immediate b selection
+parameter IMMB_I = 4'b0000;
+parameter IMMB_S = 4'b0001;
+parameter IMMB_U = 4'b0010;
+parameter IMMB_PCINCR = 4'b0011;
+parameter IMMB_S2 = 4'b0100;
+parameter IMMB_S3 = 4'b0101;
+parameter IMMB_VS = 4'b0110;
+parameter IMMB_VU = 4'b0111;
+parameter IMMB_SHUF = 4'b1000;
+parameter IMMB_CLIP = 4'b1001;
+parameter IMMB_BI = 4'b1011;
+parameter IMMB_UJ = 4'b1100;
+parameter IMMB_SB = 4'b1101;
+
+// bit mask selection
+parameter BMASK_A_ZERO = 1'b0;
+parameter BMASK_A_S3 = 1'b1;
+
+parameter BMASK_B_S2 = 2'b00;
+parameter BMASK_B_S3 = 2'b01;
+parameter BMASK_B_ZERO = 2'b10;
+parameter BMASK_B_ONE = 2'b11;
+
+parameter BMASK_A_REG = 1'b0;
+parameter BMASK_A_IMM = 1'b1;
+parameter BMASK_B_REG = 1'b0;
+parameter BMASK_B_IMM = 1'b1;
+
+
+
+///////////////////////////////////////////////
+// ___ _____ ____ _ //
+// |_ _| ___| / ___|| |_ __ _ __ _ ___ //
+// | || |_ \___ \| __/ _` |/ _` |/ _ \ //
+// | || _| ___) | || (_| | (_| | __/ //
+// |___|_| |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// PC mux selector defines
+parameter PC_BOOT = 3'b000;
+parameter PC_JUMP = 3'b010;
+parameter PC_EXCEPTION = 3'b100;
+parameter PC_ERET = 3'b101;
+parameter PC_DBG_NPC = 3'b111;
+
+// Exception PC mux selector defines
+parameter EXC_PC_ILLINSN = 2'b00;
+parameter EXC_PC_ECALL = 2'b01;
+parameter EXC_PC_LOAD = 2'b10;
+parameter EXC_PC_STORE = 2'b10;
+parameter EXC_PC_IRQ = 2'b11;
+
+// Exception Cause
+parameter EXC_CAUSE_ILLEGAL_INSN = 6'h02;
+parameter EXC_CAUSE_BREAKPOINT = 6'h03;
+parameter EXC_CAUSE_ECALL_MMODE = 6'h0B;
+
+// Exceptions offsets
+// target address = {boot_addr[31:8], EXC_OFF} (boot_addr must be 32 BYTE aligned!)
+// offset 00 to 7e is used for external interrupts
+parameter EXC_OFF_RST = 8'h80;
+parameter EXC_OFF_ILLINSN = 8'h84;
+parameter EXC_OFF_ECALL = 8'h88;
+parameter EXC_OFF_LSUERR = 8'h8c;
+
+
+// Debug module
+parameter DBG_SETS_W = 6;
+
+parameter DBG_SETS_IRQ = 5;
+parameter DBG_SETS_ECALL = 4;
+parameter DBG_SETS_EILL = 3;
+parameter DBG_SETS_ELSU = 2;
+parameter DBG_SETS_EBRK = 1;
+parameter DBG_SETS_SSTE = 0;
+
+parameter DBG_CAUSE_HALT = 6'h1F;
+ input wire clk;
+ input wire rst_n;
+ input wire mult_en_i;
+ input wire div_en_i;
+ input wire [1:0] operator_i;
+ input wire [1:0] signed_mode_i;
+ input wire [31:0] op_a_i;
+ input wire [31:0] op_b_i;
+ input wire [33:0] alu_adder_ext_i;
+ input wire [31:0] alu_adder_i;
+ input wire equal_to_zero;
+ output reg [32:0] alu_operand_a_o;
+ output reg [32:0] alu_operand_b_o;
+ output wire [31:0] multdiv_result_o;
+ output wire ready_o;
+ reg [4:0] div_counter_q;
+ reg [4:0] div_counter_n;
+ reg [1:0] mult_state_q;
+ reg [1:0] mult_state_n;
+ reg [2:0] divcurr_state_q;
+ reg [2:0] divcurr_state_n;
+ wire [34:0] mac_res_ext;
+ reg [33:0] mac_res_q;
+ reg [33:0] mac_res_n;
+ wire [33:0] mac_res;
+ reg [33:0] op_reminder_n;
+ reg [15:0] mult_op_a;
+ reg [15:0] mult_op_b;
+ reg [33:0] accum;
+ reg sign_a;
+ reg sign_b;
+ wire div_sign_a;
+ wire div_sign_b;
+ wire signed_mult;
+ reg is_greater_equal;
+ wire div_change_sign;
+ wire rem_change_sign;
+ wire [31:0] one_shift;
+ reg [31:0] op_denominator_q;
+ reg [31:0] op_numerator_q;
+ reg [31:0] op_quotient_q;
+ reg [31:0] op_denominator_n;
+ reg [31:0] op_numerator_n;
+ reg [31:0] op_quotient_n;
+ wire [32:0] next_reminder;
+ wire [32:0] next_quotient;
+ wire [32:0] res_adder_h;
+ reg mult_is_ready;
+ always @(posedge clk or negedge rst_n) begin : proc_mult_state_q
+ if (~rst_n) begin
+ mult_state_q <= 2'd0;
+ mac_res_q <= 1'sb0;
+ div_counter_q <= 1'sb0;
+ divcurr_state_q <= 3'd0;
+ op_denominator_q <= 1'sb0;
+ op_numerator_q <= 1'sb0;
+ op_quotient_q <= 1'sb0;
+ end
+ else begin
+ if (mult_en_i)
+ mult_state_q <= mult_state_n;
+ if (div_en_i) begin
+ div_counter_q <= div_counter_n;
+ op_denominator_q <= op_denominator_n;
+ op_numerator_q <= op_numerator_n;
+ op_quotient_q <= op_quotient_n;
+ divcurr_state_q <= divcurr_state_n;
+ end
+ case (1'b1)
+ mult_en_i: mac_res_q <= mac_res_n;
+ div_en_i: mac_res_q <= op_reminder_n;
+ default: mac_res_q <= mac_res_q;
+ endcase
+ end
+ end
+ assign signed_mult = signed_mode_i != 2'b00;
+ assign multdiv_result_o = (div_en_i ? mac_res_q[31:0] : mac_res_n[31:0]);
+ assign mac_res_ext = ($signed({sign_a, mult_op_a}) * $signed({sign_b, mult_op_b})) + $signed(accum);
+ assign mac_res = mac_res_ext[33:0];
+ assign res_adder_h = alu_adder_ext_i[33:1];
+ assign next_reminder = (is_greater_equal ? res_adder_h : mac_res_q[32:0]);
+ assign next_quotient = (is_greater_equal ? op_quotient_q | one_shift : op_quotient_q);
+ assign one_shift = 32'b00000000000000000000000000000001 << div_counter_q;
+ always @(*)
+ if ((mac_res_q[31] ^ op_denominator_q[31]) == 0)
+ is_greater_equal = res_adder_h[31] == 0;
+ else
+ is_greater_equal = mac_res_q[31];
+ assign div_sign_a = op_a_i[31] & signed_mode_i[0];
+ assign div_sign_b = op_b_i[31] & signed_mode_i[1];
+ assign div_change_sign = div_sign_a ^ div_sign_b;
+ assign rem_change_sign = div_sign_a;
+ always @(*) begin : div_fsm
+ div_counter_n = div_counter_q - 1;
+ op_reminder_n = mac_res_q;
+ op_quotient_n = op_quotient_q;
+ divcurr_state_n = divcurr_state_q;
+ op_numerator_n = op_numerator_q;
+ op_denominator_n = op_denominator_q;
+ alu_operand_a_o = 33'b000000000000000000000000000000001;
+ alu_operand_b_o = {~op_b_i, 1'b1};
+ case (divcurr_state_q)
+ 3'd0: begin
+ case (operator_i)
+ MD_OP_DIV: begin
+ op_reminder_n = 1'sb1;
+ divcurr_state_n = (equal_to_zero ? 3'd6 : 3'd1);
+ end
+ default: begin
+ op_reminder_n = {2'b00, op_a_i};
+ divcurr_state_n = (equal_to_zero ? 3'd6 : 3'd1);
+ end
+ endcase
+ alu_operand_a_o = 33'b000000000000000000000000000000001;
+ alu_operand_b_o = {~op_b_i, 1'b1};
+ div_counter_n = 5'd31;
+ end
+ 3'd1: begin
+ op_quotient_n = 1'sb0;
+ op_numerator_n = (div_sign_a ? alu_adder_i : op_a_i);
+ divcurr_state_n = 3'd2;
+ div_counter_n = 5'd31;
+ alu_operand_a_o = 33'b000000000000000000000000000000001;
+ alu_operand_b_o = {~op_a_i, 1'b1};
+ end
+ 3'd2: begin
+ op_reminder_n = {33'h000000000, op_numerator_q[31]};
+ op_denominator_n = (div_sign_b ? alu_adder_i : op_b_i);
+ divcurr_state_n = 3'd3;
+ div_counter_n = 5'd31;
+ alu_operand_a_o = 33'b000000000000000000000000000000001;
+ alu_operand_b_o = {~op_b_i, 1'b1};
+ end
+ 3'd3: begin
+ op_reminder_n = {1'b0, next_reminder[31:0], op_numerator_q[div_counter_n]};
+ op_quotient_n = next_quotient;
+ if (div_counter_q == 5'd1)
+ divcurr_state_n = 3'd4;
+ else
+ divcurr_state_n = 3'd3;
+ alu_operand_a_o = {mac_res_q[31:0], 1'b1};
+ alu_operand_b_o = {~op_denominator_q[31:0], 1'b1};
+ end
+ 3'd4: begin
+ case (operator_i)
+ MD_OP_DIV: op_reminder_n = {1'b0, next_quotient};
+ default: op_reminder_n = {2'b00, next_reminder[31:0]};
+ endcase
+ alu_operand_a_o = {mac_res_q[31:0], 1'b1};
+ alu_operand_b_o = {~op_denominator_q[31:0], 1'b1};
+ divcurr_state_n = 3'd5;
+ end
+ 3'd5: begin
+ divcurr_state_n = 3'd6;
+ case (operator_i)
+ MD_OP_DIV: op_reminder_n = (div_change_sign ? alu_adder_i : mac_res_q);
+ default: op_reminder_n = (rem_change_sign ? alu_adder_i : mac_res_q);
+ endcase
+ alu_operand_a_o = 33'b000000000000000000000000000000001;
+ alu_operand_b_o = {~mac_res_q[31:0], 1'b1};
+ end
+ 3'd6: divcurr_state_n = 3'd0;
+ default:
+ ;
+ endcase
+ end
+ assign ready_o = mult_is_ready | (divcurr_state_q == 3'd6);
+ always @(*) begin : mult_fsm
+ mult_op_a = op_a_i[15:0];
+ mult_op_b = op_b_i[15:0];
+ sign_a = 1'b0;
+ sign_b = 1'b0;
+ accum = mac_res_q;
+ mac_res_n = mac_res;
+ mult_state_n = mult_state_q;
+ mult_is_ready = 1'b0;
+ case (mult_state_q)
+ 2'd0: begin
+ mult_op_a = op_a_i[15:0];
+ mult_op_b = op_b_i[15:0];
+ sign_a = 1'b0;
+ sign_b = 1'b0;
+ accum = 1'sb0;
+ mac_res_n = mac_res;
+ mult_state_n = 2'd1;
+ end
+ 2'd1: begin
+ mult_op_a = op_a_i[15:0];
+ mult_op_b = op_b_i[31:16];
+ sign_a = 1'b0;
+ sign_b = signed_mode_i[1] & op_b_i[31];
+ accum = {18'b000000000000000000, mac_res_q[31:16]};
+ case (operator_i)
+ MD_OP_MULL: mac_res_n = {2'b00, mac_res[15:0], mac_res_q[15:0]};
+ default: mac_res_n = mac_res;
+ endcase
+ mult_state_n = 2'd2;
+ end
+ 2'd2: begin
+ mult_op_a = op_a_i[31:16];
+ mult_op_b = op_b_i[15:0];
+ sign_a = signed_mode_i[0] & op_a_i[31];
+ sign_b = 1'b0;
+ case (operator_i)
+ MD_OP_MULL: begin
+ accum = {18'b000000000000000000, mac_res_q[31:16]};
+ mac_res_n = {2'b00, mac_res[15:0], mac_res_q[15:0]};
+ mult_is_ready = 1'b1;
+ mult_state_n = 2'd0;
+ end
+ default: begin
+ accum = mac_res_q;
+ mac_res_n = mac_res;
+ mult_state_n = 2'd3;
+ end
+ endcase
+ end
+ 2'd3: begin
+ mult_op_a = op_a_i[31:16];
+ mult_op_b = op_b_i[31:16];
+ sign_a = signed_mode_i[0] & op_a_i[31];
+ sign_b = signed_mode_i[1] & op_b_i[31];
+ accum[17:0] = mac_res_q[33:16];
+ accum[33:18] = {18 {signed_mult & mac_res_q[33]}};
+ mac_res_n = mac_res;
+ mult_state_n = 2'd0;
+ mult_is_ready = 1'b1;
+ end
+ default:
+ ;
+ endcase
+ end
+endmodule
diff --git a/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_slow.v b/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_slow.v
new file mode 100644
index 0000000..03e6501
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_slow.v
@@ -0,0 +1,491 @@
+module zeroriscy_multdiv_slow (
+ clk,
+ rst_n,
+ mult_en_i,
+ div_en_i,
+ operator_i,
+ signed_mode_i,
+ op_a_i,
+ op_b_i,
+ alu_adder_ext_i,
+ alu_adder_i,
+ equal_to_zero,
+ alu_operand_a_o,
+ alu_operand_b_o,
+ multdiv_result_o,
+ ready_o
+);
+parameter OPCODE_SYSTEM = 7'h73;
+parameter OPCODE_FENCE = 7'h0f;
+parameter OPCODE_OP = 7'h33;
+parameter OPCODE_OPIMM = 7'h13;
+parameter OPCODE_STORE = 7'h23;
+parameter OPCODE_LOAD = 7'h03;
+parameter OPCODE_BRANCH = 7'h63;
+parameter OPCODE_JALR = 7'h67;
+parameter OPCODE_JAL = 7'h6f;
+parameter OPCODE_AUIPC = 7'h17;
+parameter OPCODE_LUI = 7'h37;
+
+// those opcodes are now used for PULP custom instructions
+// parameter OPCODE_CUST0 = 7'h0b
+// parameter OPCODE_CUST1 = 7'h2b
+
+// PULP custom
+parameter OPCODE_LOAD_POST = 7'h0b;
+parameter OPCODE_STORE_POST = 7'h2b;
+parameter OPCODE_PULP_OP = 7'h5b;
+parameter OPCODE_VECOP = 7'h57;
+parameter OPCODE_HWLOOP = 7'h7b;
+
+parameter REGC_S1 = 2'b10;
+parameter REGC_RD = 2'b01;
+parameter REGC_ZERO = 2'b11;
+
+
+//////////////////////////////////////////////////////////////////////////////
+// _ _ _ _ ___ _ _ //
+// / \ | | | | | | / _ \ _ __ ___ _ __ __ _| |_(_) ___ _ __ ___ //
+// / _ \ | | | | | | | | | | '_ \ / _ \ '__/ _` | __| |/ _ \| '_ \/ __| //
+// / ___ \| |__| |_| | | |_| | |_) | __/ | | (_| | |_| | (_) | | | \__ \ //
+// /_/ \_\_____\___/ \___/| .__/ \___|_| \__,_|\__|_|\___/|_| |_|___/ //
+// |_| //
+//////////////////////////////////////////////////////////////////////////////
+
+parameter ALU_OP_WIDTH = 6;
+
+parameter ALU_ADD = 6'b011000;
+parameter ALU_SUB = 6'b011001;
+parameter ALU_ADDU = 6'b011010;
+parameter ALU_SUBU = 6'b011011;
+parameter ALU_ADDR = 6'b011100;
+parameter ALU_SUBR = 6'b011101;
+parameter ALU_ADDUR = 6'b011110;
+parameter ALU_SUBUR = 6'b011111;
+
+parameter ALU_XOR = 6'b101111;
+parameter ALU_OR = 6'b101110;
+parameter ALU_AND = 6'b010101;
+
+// Shifts
+parameter ALU_SRA = 6'b100100;
+parameter ALU_SRL = 6'b100101;
+parameter ALU_ROR = 6'b100110;
+parameter ALU_SLL = 6'b100111;
+
+// bit manipulation
+parameter ALU_BEXT = 6'b101000;
+parameter ALU_BEXTU = 6'b101001;
+parameter ALU_BINS = 6'b101010;
+parameter ALU_BCLR = 6'b101011;
+parameter ALU_BSET = 6'b101100;
+
+// Bit counting
+parameter ALU_FF1 = 6'b110110;
+parameter ALU_FL1 = 6'b110111;
+parameter ALU_CNT = 6'b110100;
+parameter ALU_CLB = 6'b110101;
+
+// Sign-/zero-extensions
+parameter ALU_EXTS = 6'b111110;
+parameter ALU_EXT = 6'b111111;
+
+// Comparisons
+parameter ALU_LTS = 6'b000000;
+parameter ALU_LTU = 6'b000001;
+parameter ALU_LES = 6'b000100;
+parameter ALU_LEU = 6'b000101;
+parameter ALU_GTS = 6'b001000;
+parameter ALU_GTU = 6'b001001;
+parameter ALU_GES = 6'b001010;
+parameter ALU_GEU = 6'b001011;
+parameter ALU_EQ = 6'b001100;
+parameter ALU_NE = 6'b001101;
+
+// Set Lower Than operations
+parameter ALU_SLTS = 6'b000010;
+parameter ALU_SLTU = 6'b000011;
+parameter ALU_SLETS = 6'b000110;
+parameter ALU_SLETU = 6'b000111;
+
+// Absolute value
+parameter ALU_ABS = 6'b010100;
+parameter ALU_CLIP = 6'b010110;
+parameter ALU_CLIPU = 6'b010111;
+
+// Insert/extract
+parameter ALU_INS = 6'b101101;
+
+// min/max
+parameter ALU_MIN = 6'b010000;
+parameter ALU_MINU = 6'b010001;
+parameter ALU_MAX = 6'b010010;
+parameter ALU_MAXU = 6'b010011;
+
+// div/rem
+parameter ALU_DIVU = 6'b110000; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_DIV = 6'b110001; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REMU = 6'b110010; // bit 0 is used for signed mode, bit 1 is used for remdiv
+parameter ALU_REM = 6'b110011; // bit 0 is used for signed mode, bit 1 is used for remdiv
+
+parameter ALU_SHUF = 6'b111010;
+parameter ALU_SHUF2 = 6'b111011;
+parameter ALU_PCKLO = 6'b111000;
+parameter ALU_PCKHI = 6'b111001;
+
+
+parameter MD_OP_MULL = 2'b00;
+parameter MD_OP_MULH = 2'b01;
+parameter MD_OP_DIV = 2'b10;
+parameter MD_OP_REM = 2'b11;
+
+// vector modes
+parameter VEC_MODE32 = 2'b00;
+parameter VEC_MODE16 = 2'b10;
+parameter VEC_MODE8 = 2'b11;
+
+
+/////////////////////////////////////////////////////////
+// ____ ____ ____ _ _ //
+// / ___/ ___| | _ \ ___ __ _(_)___| |_ ___ _ __ //
+// | | \___ \ | |_) / _ \/ _` | / __| __/ _ \ '__| //
+// | |___ ___) | | _ < __/ (_| | \__ \ || __/ | //
+// \____|____/ |_| \_\___|\__, |_|___/\__\___|_| //
+// |___/ //
+/////////////////////////////////////////////////////////
+
+// CSR operations
+parameter CSR_OP_NONE = 2'b00;
+parameter CSR_OP_WRITE = 2'b01;
+parameter CSR_OP_SET = 2'b10;
+parameter CSR_OP_CLEAR = 2'b11;
+
+
+// SPR for debugger, not accessible by CPU
+parameter SP_DVR0 = 16'h3000;
+parameter SP_DCR0 = 16'h3008;
+parameter SP_DMR1 = 16'h3010;
+parameter SP_DMR2 = 16'h3011;
+
+parameter SP_DVR_MSB = 8'h00;
+parameter SP_DCR_MSB = 8'h01;
+parameter SP_DMR_MSB = 8'h02;
+parameter SP_DSR_MSB = 8'h04;
+
+// Privileged mode
+typedef enum logic[1:0] {
+ PRIV_LVL_M = 2'b11,
+ PRIV_LVL_H = 2'b10,
+ PRIV_LVL_S = 2'b01,
+ PRIV_LVL_U = 2'b00
+} PrivLvl_t;
+
+///////////////////////////////////////////////
+// ___ ____ ____ _ //
+// |_ _| _ \ / ___|| |_ __ _ __ _ ___ //
+// | || | | | \___ \| __/ _` |/ _` |/ _ \ //
+// | || |_| | ___) | || (_| | (_| | __/ //
+// |___|____/ |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// forwarding operand mux
+parameter SEL_REGFILE = 2'b00;
+parameter SEL_FW_EX = 2'b01;
+parameter SEL_FW_WB = 2'b10;
+parameter SEL_MISALIGNED = 2'b11;
+
+// operand a selection
+parameter OP_A_REGA_OR_FWD = 3'b000;
+parameter OP_A_CURRPC = 3'b001;
+parameter OP_A_IMM = 3'b010;
+parameter OP_A_REGB_OR_FWD = 3'b011;
+parameter OP_A_REGC_OR_FWD = 3'b100;
+
+// immediate a selection
+parameter IMMA_Z = 1'b0;
+parameter IMMA_ZERO = 1'b1;
+
+// operand b selection
+parameter OP_B_REGB_OR_FWD = 3'b000;
+parameter OP_B_REGC_OR_FWD = 3'b001;
+parameter OP_B_IMM = 3'b010;
+parameter OP_B_REGA_OR_FWD = 3'b011;
+parameter OP_B_BMASK = 3'b100;
+parameter OP_B_ZERO = 3'b101;
+
+// immediate b selection
+parameter IMMB_I = 4'b0000;
+parameter IMMB_S = 4'b0001;
+parameter IMMB_U = 4'b0010;
+parameter IMMB_PCINCR = 4'b0011;
+parameter IMMB_S2 = 4'b0100;
+parameter IMMB_S3 = 4'b0101;
+parameter IMMB_VS = 4'b0110;
+parameter IMMB_VU = 4'b0111;
+parameter IMMB_SHUF = 4'b1000;
+parameter IMMB_CLIP = 4'b1001;
+parameter IMMB_BI = 4'b1011;
+parameter IMMB_UJ = 4'b1100;
+parameter IMMB_SB = 4'b1101;
+
+// bit mask selection
+parameter BMASK_A_ZERO = 1'b0;
+parameter BMASK_A_S3 = 1'b1;
+
+parameter BMASK_B_S2 = 2'b00;
+parameter BMASK_B_S3 = 2'b01;
+parameter BMASK_B_ZERO = 2'b10;
+parameter BMASK_B_ONE = 2'b11;
+
+parameter BMASK_A_REG = 1'b0;
+parameter BMASK_A_IMM = 1'b1;
+parameter BMASK_B_REG = 1'b0;
+parameter BMASK_B_IMM = 1'b1;
+
+
+
+///////////////////////////////////////////////
+// ___ _____ ____ _ //
+// |_ _| ___| / ___|| |_ __ _ __ _ ___ //
+// | || |_ \___ \| __/ _` |/ _` |/ _ \ //
+// | || _| ___) | || (_| | (_| | __/ //
+// |___|_| |____/ \__\__,_|\__, |\___| //
+// |___/ //
+///////////////////////////////////////////////
+
+// PC mux selector defines
+parameter PC_BOOT = 3'b000;
+parameter PC_JUMP = 3'b010;
+parameter PC_EXCEPTION = 3'b100;
+parameter PC_ERET = 3'b101;
+parameter PC_DBG_NPC = 3'b111;
+
+// Exception PC mux selector defines
+parameter EXC_PC_ILLINSN = 2'b00;
+parameter EXC_PC_ECALL = 2'b01;
+parameter EXC_PC_LOAD = 2'b10;
+parameter EXC_PC_STORE = 2'b10;
+parameter EXC_PC_IRQ = 2'b11;
+
+// Exception Cause
+parameter EXC_CAUSE_ILLEGAL_INSN = 6'h02;
+parameter EXC_CAUSE_BREAKPOINT = 6'h03;
+parameter EXC_CAUSE_ECALL_MMODE = 6'h0B;
+
+// Exceptions offsets
+// target address = {boot_addr[31:8], EXC_OFF} (boot_addr must be 32 BYTE aligned!)
+// offset 00 to 7e is used for external interrupts
+parameter EXC_OFF_RST = 8'h80;
+parameter EXC_OFF_ILLINSN = 8'h84;
+parameter EXC_OFF_ECALL = 8'h88;
+parameter EXC_OFF_LSUERR = 8'h8c;
+
+
+// Debug module
+parameter DBG_SETS_W = 6;
+
+parameter DBG_SETS_IRQ = 5;
+parameter DBG_SETS_ECALL = 4;
+parameter DBG_SETS_EILL = 3;
+parameter DBG_SETS_ELSU = 2;
+parameter DBG_SETS_EBRK = 1;
+parameter DBG_SETS_SSTE = 0;
+
+parameter DBG_CAUSE_HALT = 6'h1F;
+ input wire clk;
+ input wire rst_n;
+ input wire mult_en_i;
+ input wire div_en_i;
+ input wire [1:0] operator_i;
+ input wire [1:0] signed_mode_i;
+ input wire [31:0] op_a_i;
+ input wire [31:0] op_b_i;
+ input wire [33:0] alu_adder_ext_i;
+ input wire [31:0] alu_adder_i;
+ input wire equal_to_zero;
+ output reg [32:0] alu_operand_a_o;
+ output reg [32:0] alu_operand_b_o;
+ output reg [31:0] multdiv_result_o;
+ output wire ready_o;
+ reg [4:0] multdiv_state_q;
+ wire [4:0] multdiv_state_n;
+ reg [2:0] curr_state_q;
+ reg [32:0] accum_window_q;
+ wire [32:0] res_adder_l;
+ wire [32:0] res_adder_h;
+ reg [32:0] op_b_shift_q;
+ reg [32:0] op_a_shift_q;
+ wire [32:0] op_a_ext;
+ wire [32:0] op_b_ext;
+ wire [32:0] one_shift;
+ wire [32:0] op_a_bw_pp;
+ wire [32:0] op_a_bw_last_pp;
+ wire [31:0] b_0;
+ wire sign_a;
+ wire sign_b;
+ wire [32:0] next_reminder;
+ wire [32:0] next_quotient;
+ wire [32:0] op_remainder;
+ reg [31:0] op_numerator_q;
+ reg is_greater_equal;
+ wire div_change_sign;
+ wire rem_change_sign;
+ assign res_adder_l = alu_adder_ext_i[32:0];
+ assign res_adder_h = alu_adder_ext_i[33:1];
+ always @(*) begin
+ alu_operand_a_o = accum_window_q;
+ multdiv_result_o = (div_en_i ? accum_window_q[31:0] : res_adder_l);
+ case (operator_i)
+ MD_OP_MULL: alu_operand_b_o = op_a_bw_pp;
+ MD_OP_MULH:
+ if (curr_state_q == 3'd4)
+ alu_operand_b_o = op_a_bw_last_pp;
+ else
+ alu_operand_b_o = op_a_bw_pp;
+ default:
+ case (curr_state_q)
+ 3'd0: begin
+ alu_operand_a_o = 33'b000000000000000000000000000000001;
+ alu_operand_b_o = {~op_b_i, 1'b1};
+ end
+ 3'd1: begin
+ alu_operand_a_o = 33'b000000000000000000000000000000001;
+ alu_operand_b_o = {~op_a_i, 1'b1};
+ end
+ 3'd2: begin
+ alu_operand_a_o = 33'b000000000000000000000000000000001;
+ alu_operand_b_o = {~op_b_i, 1'b1};
+ end
+ 3'd5: begin
+ alu_operand_a_o = 33'b000000000000000000000000000000001;
+ alu_operand_b_o = {~accum_window_q[31:0], 1'b1};
+ end
+ default: begin
+ alu_operand_a_o = {accum_window_q[31:0], 1'b1};
+ alu_operand_b_o = {~op_b_shift_q[31:0], 1'b1};
+ end
+ endcase
+ endcase
+ end
+ always @(*)
+ if ((accum_window_q[31] ^ op_b_shift_q[31]) == 0)
+ is_greater_equal = res_adder_h[31] == 0;
+ else
+ is_greater_equal = accum_window_q[31];
+ assign one_shift = 33'b000000000000000000000000000000001 << multdiv_state_q;
+ assign next_reminder = (is_greater_equal ? res_adder_h : op_remainder);
+ assign next_quotient = (is_greater_equal ? op_a_shift_q | one_shift : op_a_shift_q);
+ assign b_0 = {32 {op_b_shift_q[0]}};
+ assign op_a_bw_pp = {~(op_a_shift_q[32] & op_b_shift_q[0]), op_a_shift_q[31:0] & b_0};
+ assign op_a_bw_last_pp = {op_a_shift_q[32] & op_b_shift_q[0], ~(op_a_shift_q[31:0] & b_0)};
+ assign sign_a = op_a_i[31] & signed_mode_i[0];
+ assign sign_b = op_b_i[31] & signed_mode_i[1];
+ assign op_a_ext = {sign_a, op_a_i};
+ assign op_b_ext = {sign_b, op_b_i};
+ assign op_remainder = accum_window_q[32:0];
+ assign multdiv_state_n = multdiv_state_q - 1;
+ assign div_change_sign = sign_a ^ sign_b;
+ assign rem_change_sign = sign_a;
+ always @(posedge clk or negedge rst_n) begin : proc_multdiv_state_q
+ if (~rst_n) begin
+ multdiv_state_q <= 1'sb0;
+ accum_window_q <= 1'sb0;
+ op_b_shift_q <= 1'sb0;
+ op_a_shift_q <= 1'sb0;
+ curr_state_q <= 3'd0;
+ op_numerator_q <= 1'sb0;
+ end
+ else if (mult_en_i | div_en_i)
+ case (curr_state_q)
+ 3'd0: begin
+ case (operator_i)
+ MD_OP_MULL: begin
+ op_a_shift_q <= op_a_ext << 1;
+ accum_window_q <= {~(op_a_ext[32] & op_b_i[0]), op_a_ext[31:0] & {32 {op_b_i[0]}}};
+ op_b_shift_q <= op_b_ext >> 1;
+ curr_state_q <= 3'd3;
+ end
+ MD_OP_MULH: begin
+ op_a_shift_q <= op_a_ext;
+ accum_window_q <= {1'b1, ~(op_a_ext[32] & op_b_i[0]), op_a_ext[31:1] & {31 {op_b_i[0]}}};
+ op_b_shift_q <= op_b_ext >> 1;
+ curr_state_q <= 3'd3;
+ end
+ MD_OP_DIV: begin
+ accum_window_q <= 1'sb1;
+ curr_state_q <= (equal_to_zero ? 3'd6 : 3'd1);
+ end
+ default: begin
+ accum_window_q <= op_a_ext;
+ curr_state_q <= (equal_to_zero ? 3'd6 : 3'd1);
+ end
+ endcase
+ multdiv_state_q <= 5'd31;
+ end
+ 3'd1: begin
+ op_a_shift_q <= 1'sb0;
+ op_numerator_q <= (sign_a ? alu_adder_i : op_a_i);
+ curr_state_q <= 3'd2;
+ end
+ 3'd2: begin
+ accum_window_q <= {32'h00000000, op_numerator_q[31]};
+ op_b_shift_q <= (sign_b ? alu_adder_i : op_b_i);
+ curr_state_q <= 3'd3;
+ end
+ 3'd3: begin
+ multdiv_state_q <= multdiv_state_n;
+ case (operator_i)
+ MD_OP_MULL: begin
+ accum_window_q <= res_adder_l;
+ op_a_shift_q <= op_a_shift_q << 1;
+ op_b_shift_q <= op_b_shift_q >> 1;
+ end
+ MD_OP_MULH: begin
+ accum_window_q <= res_adder_h;
+ op_a_shift_q <= op_a_shift_q;
+ op_b_shift_q <= op_b_shift_q >> 1;
+ end
+ default: begin
+ accum_window_q <= {next_reminder[31:0], op_numerator_q[multdiv_state_n]};
+ op_a_shift_q <= next_quotient;
+ end
+ endcase
+ if (multdiv_state_q == 5'd1)
+ curr_state_q <= 3'd4;
+ else
+ curr_state_q <= 3'd3;
+ end
+ 3'd4:
+ case (operator_i)
+ MD_OP_MULL: begin
+ accum_window_q <= res_adder_l;
+ curr_state_q <= 3'd0;
+ end
+ MD_OP_MULH: begin
+ accum_window_q <= res_adder_l;
+ curr_state_q <= 3'd0;
+ end
+ MD_OP_DIV: begin
+ accum_window_q <= next_quotient;
+ curr_state_q <= 3'd5;
+ end
+ default: begin
+ accum_window_q <= {1'b0, next_reminder[31:0]};
+ curr_state_q <= 3'd5;
+ end
+ endcase
+ 3'd5: begin
+ curr_state_q <= 3'd6;
+ case (operator_i)
+ MD_OP_DIV: accum_window_q <= (div_change_sign ? alu_adder_i : accum_window_q);
+ default: accum_window_q <= (rem_change_sign ? alu_adder_i : accum_window_q);
+ endcase
+ end
+ 3'd6: curr_state_q <= 3'd0;
+ default:
+ ;
+ endcase
+ end
+ assign ready_o = (curr_state_q == 3'd6) | ((curr_state_q == 3'd4) & ((operator_i == MD_OP_MULL) | (operator_i == MD_OP_MULH)));
+endmodule
diff --git a/verilog/rtl/ips/zero-riscy/zeroriscy_prefetch_buffer.v b/verilog/rtl/ips/zero-riscy/zeroriscy_prefetch_buffer.v
new file mode 100644
index 0000000..a10d2d5
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/zeroriscy_prefetch_buffer.v
@@ -0,0 +1,146 @@
+module zeroriscy_prefetch_buffer (
+ clk,
+ rst_n,
+ req_i,
+ branch_i,
+ addr_i,
+ ready_i,
+ valid_o,
+ rdata_o,
+ addr_o,
+ instr_req_o,
+ instr_gnt_i,
+ instr_addr_o,
+ instr_rdata_i,
+ instr_rvalid_i,
+ busy_o
+);
+ input wire clk;
+ input wire rst_n;
+ input wire req_i;
+ input wire branch_i;
+ input wire [31:0] addr_i;
+ input wire ready_i;
+ output wire valid_o;
+ output wire [31:0] rdata_o;
+ output wire [31:0] addr_o;
+ output reg instr_req_o;
+ input wire instr_gnt_i;
+ output reg [31:0] instr_addr_o;
+ input wire [31:0] instr_rdata_i;
+ input wire instr_rvalid_i;
+ output wire busy_o;
+ reg [1:0] CS;
+ reg [1:0] NS;
+ reg [31:0] instr_addr_q;
+ wire [31:0] fetch_addr;
+ reg addr_valid;
+ reg fifo_valid;
+ wire fifo_ready;
+ reg fifo_clear;
+ wire valid_stored;
+ assign busy_o = (CS != 2'd0) || instr_req_o;
+ zeroriscy_fetch_fifo fifo_i(
+ .clk(clk),
+ .rst_n(rst_n),
+ .clear_i(fifo_clear),
+ .in_addr_i(instr_addr_q),
+ .in_rdata_i(instr_rdata_i),
+ .in_valid_i(fifo_valid),
+ .in_ready_o(fifo_ready),
+ .out_valid_o(valid_o),
+ .out_ready_i(ready_i),
+ .out_rdata_o(rdata_o),
+ .out_addr_o(addr_o),
+ .out_valid_stored_o(valid_stored)
+ );
+ assign fetch_addr = {instr_addr_q[31:2], 2'b00} + 32'd4;
+ always @(*) fifo_clear = branch_i;
+ always @(*) begin
+ instr_req_o = 1'b0;
+ instr_addr_o = fetch_addr;
+ fifo_valid = 1'b0;
+ addr_valid = 1'b0;
+ NS = CS;
+ case (CS)
+ 2'd0: begin
+ instr_addr_o = fetch_addr;
+ instr_req_o = 1'b0;
+ if (branch_i)
+ instr_addr_o = addr_i;
+ if (req_i & (fifo_ready | branch_i)) begin
+ instr_req_o = 1'b1;
+ addr_valid = 1'b1;
+ if (instr_gnt_i)
+ NS = 2'd2;
+ else
+ NS = 2'd1;
+ end
+ end
+ 2'd1: begin
+ instr_addr_o = instr_addr_q;
+ instr_req_o = 1'b1;
+ if (branch_i) begin
+ instr_addr_o = addr_i;
+ addr_valid = 1'b1;
+ end
+ if (instr_gnt_i)
+ NS = 2'd2;
+ else
+ NS = 2'd1;
+ end
+ 2'd2: begin
+ instr_addr_o = fetch_addr;
+ if (branch_i)
+ instr_addr_o = addr_i;
+ if (req_i & (fifo_ready | branch_i)) begin
+ if (instr_rvalid_i) begin
+ instr_req_o = 1'b1;
+ fifo_valid = 1'b1;
+ addr_valid = 1'b1;
+ if (instr_gnt_i)
+ NS = 2'd2;
+ else
+ NS = 2'd1;
+ end
+ else if (branch_i) begin
+ addr_valid = 1'b1;
+ NS = 2'd3;
+ end
+ end
+ else if (instr_rvalid_i) begin
+ fifo_valid = 1'b1;
+ NS = 2'd0;
+ end
+ end
+ 2'd3: begin
+ instr_addr_o = instr_addr_q;
+ if (branch_i) begin
+ instr_addr_o = addr_i;
+ addr_valid = 1'b1;
+ end
+ if (instr_rvalid_i) begin
+ instr_req_o = 1'b1;
+ if (instr_gnt_i)
+ NS = 2'd2;
+ else
+ NS = 2'd1;
+ end
+ end
+ default: begin
+ NS = 2'd0;
+ instr_req_o = 1'b0;
+ end
+ endcase
+ end
+ always @(posedge clk or negedge rst_n)
+ if (rst_n == 1'b0) begin
+ CS <= 2'd0;
+ instr_addr_q <= 1'sb0;
+ end
+ else begin
+ CS <= NS;
+ if (addr_valid)
+ instr_addr_q <= instr_addr_o;
+ end
+endmodule
diff --git a/verilog/rtl/ips/zero-riscy/zeroriscy_register_file.v b/verilog/rtl/ips/zero-riscy/zeroriscy_register_file.v
new file mode 100644
index 0000000..b0498d0
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/zeroriscy_register_file.v
@@ -0,0 +1,88 @@
+module zeroriscy_register_file
+#(
+ parameter RV32E = 0,
+ parameter DATA_WIDTH = 32
+)
+(
+ clk,
+ rst_n,
+ test_en_i,
+ raddr_a_i,
+ rdata_a_o,
+ raddr_b_i,
+ rdata_b_o,
+ waddr_a_i,
+ wdata_a_i,
+ we_a_i
+);
+ //parameter RV32E = 0;
+ //parameter DATA_WIDTH = 32;
+ input wire clk;
+ input wire rst_n;
+ input wire test_en_i;
+ input wire [4:0] raddr_a_i;
+ output wire [DATA_WIDTH - 1:0] rdata_a_o;
+ input wire [4:0] raddr_b_i;
+ output wire [DATA_WIDTH - 1:0] rdata_b_o;
+ input wire [4:0] waddr_a_i;
+ input wire [DATA_WIDTH - 1:0] wdata_a_i;
+ input wire we_a_i;
+ localparam ADDR_WIDTH = (RV32E ? 4 : 5);
+ localparam NUM_WORDS = 2 ** ADDR_WIDTH;
+ reg [DATA_WIDTH - 1:0] mem [0:NUM_WORDS - 1];
+ reg [NUM_WORDS - 1:1] waddr_onehot_a;
+ wire [NUM_WORDS - 1:1] mem_clocks;
+ reg [DATA_WIDTH - 1:0] wdata_a_q;
+ wire [ADDR_WIDTH - 1:0] raddr_a_int;
+ wire [ADDR_WIDTH - 1:0] raddr_b_int;
+ wire [ADDR_WIDTH - 1:0] waddr_a_int;
+ assign raddr_a_int = raddr_a_i[ADDR_WIDTH - 1:0];
+ assign raddr_b_int = raddr_b_i[ADDR_WIDTH - 1:0];
+ assign waddr_a_int = waddr_a_i[ADDR_WIDTH - 1:0];
+ wire clk_int;
+ reg [31:0] i;
+ wire [31:0] j;
+ reg [31:0] k;
+ genvar x;
+ assign rdata_a_o = mem[raddr_a_int];
+ assign rdata_b_o = mem[raddr_b_int];
+ cluster_clock_gating CG_WE_GLOBAL(
+ .clk_i(clk),
+ .en_i(we_a_i),
+ .test_en_i(test_en_i),
+ .clk_o(clk_int)
+ );
+ always @(posedge clk_int or negedge rst_n) begin : sample_waddr
+ if (~rst_n)
+ wdata_a_q <= 1'sb0;
+ else if (we_a_i)
+ wdata_a_q <= wdata_a_i;
+ end
+ always @(*) begin : p_WADa
+ for (i = 1; i < NUM_WORDS; i = i + 1)
+ begin : p_WordItera
+ if ((we_a_i == 1'b1) && (waddr_a_int == i))
+ waddr_onehot_a[i] = 1'b1;
+ else
+ waddr_onehot_a[i] = 1'b0;
+ end
+ end
+ generate
+ for (x = 1; x < NUM_WORDS; x = x + 1) begin : CG_CELL_WORD_ITER
+ cluster_clock_gating CG_Inst(
+ .clk_i(clk_int),
+ .en_i(waddr_onehot_a[x]),
+ .test_en_i(test_en_i),
+ .clk_o(mem_clocks[x])
+ );
+ end
+ endgenerate
+ always @(*) begin : latch_wdata
+ mem[0] = 1'sb0;
+ for (k = 1; k < NUM_WORDS; k = k + 1)
+ begin : w_WordIter
+ if (mem_clocks[k] == 1'b1)
+ mem[k] = wdata_a_q;
+ end
+ end
+endmodule
diff --git a/verilog/rtl/ips/zero-riscy/zeroriscy_register_file_ff.v b/verilog/rtl/ips/zero-riscy/zeroriscy_register_file_ff.v
new file mode 100644
index 0000000..418a6db
--- /dev/null
+++ b/verilog/rtl/ips/zero-riscy/zeroriscy_register_file_ff.v
@@ -0,0 +1,60 @@
+module zeroriscy_register_file
+#(
+ parameter RV32E = 0,
+ parameter DATA_WIDTH = 32
+)
+(
+ clk,
+ rst_n,
+ test_en_i,
+ raddr_a_i,
+ rdata_a_o,
+ raddr_b_i,
+ rdata_b_o,
+ waddr_a_i,
+ wdata_a_i,
+ we_a_i
+);
+ //parameter RV32E = 0;
+ //parameter DATA_WIDTH = 32;
+ input wire clk;
+ input wire rst_n;
+ input wire test_en_i;
+ input wire [4:0] raddr_a_i;
+ output wire [DATA_WIDTH - 1:0] rdata_a_o;
+ input wire [4:0] raddr_b_i;
+ output wire [DATA_WIDTH - 1:0] rdata_b_o;
+ input wire [4:0] waddr_a_i;
+ input wire [DATA_WIDTH - 1:0] wdata_a_i;
+ input wire we_a_i;
+ localparam ADDR_WIDTH = (RV32E ? 4 : 5);
+ localparam NUM_WORDS = 2 ** ADDR_WIDTH;
+ wire [(NUM_WORDS * DATA_WIDTH) - 1:0] rf_reg;
+ reg [(NUM_WORDS * DATA_WIDTH) - 1:0] rf_reg_tmp;
+ reg [NUM_WORDS - 1:0] we_a_dec;
+ always @(*) begin : we_a_decoder
+ begin : sv2v_autoblock_1
+ reg signed [31:0] i;
+ for (i = 0; i < NUM_WORDS; i = i + 1)
+ if (waddr_a_i == i)
+ we_a_dec[i] = we_a_i;
+ else
+ we_a_dec[i] = 1'b0;
+ end
+ end
+ genvar i;
+ generate
+ for (i = 1; i < NUM_WORDS; i = i + 1) begin : rf_gen
+ always @(posedge clk or negedge rst_n) begin : register_write_behavioral
+ if (rst_n == 1'b0)
+ rf_reg_tmp[i * DATA_WIDTH+:DATA_WIDTH] <= 'b0;
+ else if (we_a_dec[i])
+ rf_reg_tmp[i * DATA_WIDTH+:DATA_WIDTH] <= wdata_a_i;
+ end
+ end
+ endgenerate
+ assign rf_reg[0+:DATA_WIDTH] = 1'sb0;
+ assign rf_reg[DATA_WIDTH * (((NUM_WORDS - 1) >= 1 ? NUM_WORDS - 1 : ((NUM_WORDS - 1) + ((NUM_WORDS - 1) >= 1 ? NUM_WORDS - 1 : 3 - NUM_WORDS)) - 1) - (((NUM_WORDS - 1) >= 1 ? NUM_WORDS - 1 : 3 - NUM_WORDS) - 1))+:DATA_WIDTH * ((NUM_WORDS - 1) >= 1 ? NUM_WORDS - 1 : 3 - NUM_WORDS)] = rf_reg_tmp[DATA_WIDTH * (((NUM_WORDS - 1) >= 1 ? NUM_WORDS - 1 : ((NUM_WORDS - 1) + ((NUM_WORDS - 1) >= 1 ? NUM_WORDS - 1 : 3 - NUM_WORDS)) - 1) - (((NUM_WORDS - 1) >= 1 ? NUM_WORDS - 1 : 3 - NUM_WORDS) - 1))+:DATA_WIDTH * ((NUM_WORDS - 1) >= 1 ? NUM_WORDS - 1 : 3 - NUM_WORDS)];
+ assign rdata_a_o = rf_reg[raddr_a_i * DATA_WIDTH+:DATA_WIDTH];
+ assign rdata_b_o = rf_reg[raddr_b_i * DATA_WIDTH+:DATA_WIDTH];
+endmodule