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