mirror of
https://github.com/lowRISC/ibex.git
synced 2025-06-28 17:24:11 -04:00
With the writeback stage enabled we execute the PAC/AUT instruction before the required data is written to the register file. For example, when the load instruction precedes AUT instruction, AUT instruction is started before the loaded data is written to the register file. It is a problem that the hazard detection (stall_ld_hz) using rf_ren_a/b_o was not active for PAC/AUT instruction. Also, I change codes not to activate pa_pac_en or pa_aut_en when load hazard occurs.
1201 lines
44 KiB
Systemverilog
1201 lines
44 KiB
Systemverilog
// Copyright lowRISC contributors.
|
|
// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
|
|
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
|
/**
|
|
* Instruction decoder
|
|
*
|
|
* This module is fully combinatorial, clock and reset are used for
|
|
* assertions only.
|
|
*/
|
|
|
|
`include "prim_assert.sv"
|
|
|
|
module ibex_decoder #(
|
|
parameter bit RV32E = 0,
|
|
parameter bit RV32M = 1,
|
|
parameter bit BranchTargetALU = 0,
|
|
parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone,
|
|
parameter bit PointerAuthentication = 0
|
|
) (
|
|
input logic clk_i,
|
|
input logic rst_ni,
|
|
|
|
// to/from controller
|
|
output logic illegal_insn_o, // illegal instr encountered
|
|
output logic ebrk_insn_o, // trap instr encountered
|
|
output logic mret_insn_o, // return from exception instr
|
|
// encountered
|
|
output logic dret_insn_o, // return from debug instr encountered
|
|
output logic ecall_insn_o, // syscall instr encountered
|
|
output logic wfi_insn_o, // wait for interrupt instr encountered
|
|
output logic jump_set_o, // jump taken set signal
|
|
input logic branch_taken_i, // registered branch decision
|
|
output logic icache_inval_o,
|
|
|
|
// from IF-ID pipeline register
|
|
input logic instr_first_cycle_i, // instruction read is in its first cycle
|
|
input logic [31:0] instr_rdata_i, // instruction read from memory/cache
|
|
input logic [31:0] instr_rdata_alu_i, // instruction read from memory/cache
|
|
// replicated to ease fan-out)
|
|
|
|
input logic illegal_c_insn_i, // compressed instruction decode failed
|
|
|
|
// immediates
|
|
output ibex_pkg::imm_a_sel_e imm_a_mux_sel_o, // immediate selection for operand a
|
|
output ibex_pkg::imm_b_sel_e imm_b_mux_sel_o, // immediate selection for operand b
|
|
output ibex_pkg::op_a_sel_e bt_a_mux_sel_o, // branch target selection operand a
|
|
output ibex_pkg::imm_b_sel_e bt_b_mux_sel_o, // branch target selection operand b
|
|
output logic [31:0] imm_i_type_o,
|
|
output logic [31:0] imm_s_type_o,
|
|
output logic [31:0] imm_b_type_o,
|
|
output logic [31:0] imm_u_type_o,
|
|
output logic [31:0] imm_j_type_o,
|
|
output logic [31:0] zimm_rs1_type_o,
|
|
|
|
// register file
|
|
output ibex_pkg::rf_wd_sel_e rf_wdata_sel_o, // RF write data selection
|
|
output logic rf_we_o, // write enable for regfile
|
|
output logic [4:0] rf_raddr_a_o,
|
|
output logic [4:0] rf_raddr_b_o,
|
|
output logic [4:0] rf_waddr_o,
|
|
output logic rf_ren_a_o, // Instruction reads from RF addr A
|
|
output logic rf_ren_b_o, // Instruction reads from RF addr B
|
|
|
|
// ALU
|
|
output ibex_pkg::alu_op_e alu_operator_o, // ALU operation selection
|
|
output ibex_pkg::op_a_sel_e alu_op_a_mux_sel_o, // operand a selection: reg value, PC,
|
|
// immediate or zero
|
|
output ibex_pkg::op_b_sel_e alu_op_b_mux_sel_o, // operand b selection: reg value or
|
|
// immediate
|
|
output logic alu_multicycle_o, // ternary bitmanip instruction
|
|
|
|
// MULT & DIV
|
|
output logic mult_en_o, // perform integer multiplication
|
|
output logic div_en_o, // perform integer division or remainder
|
|
output logic mult_sel_o, // as above but static, for data muxes
|
|
output logic div_sel_o, // as above but static, for data muxes
|
|
|
|
output ibex_pkg::md_op_e multdiv_operator_o,
|
|
output logic [1:0] multdiv_signed_mode_o,
|
|
|
|
// CSRs
|
|
output logic csr_access_o, // access to CSR
|
|
output ibex_pkg::csr_op_e csr_op_o, // operation to perform on CSR
|
|
|
|
// LSU
|
|
output logic data_req_o, // start transaction to data memory
|
|
output logic data_we_o, // write enable
|
|
output logic [1:0] data_type_o, // size of transaction: byte, half
|
|
// word or word
|
|
output logic data_sign_extension_o, // sign extension for data read from
|
|
// memory
|
|
|
|
// jump/branches
|
|
output logic jump_in_dec_o, // jump is being calculated in ALU
|
|
output logic branch_in_dec_o,
|
|
|
|
// Pointer Authentication
|
|
output logic pac_en_dec_o,
|
|
output logic aut_en_dec_o
|
|
);
|
|
|
|
import ibex_pkg::*;
|
|
|
|
logic illegal_insn;
|
|
logic illegal_reg_rv32e;
|
|
logic csr_illegal;
|
|
logic rf_we;
|
|
|
|
logic [31:0] instr;
|
|
logic [31:0] instr_alu;
|
|
// Source/Destination register instruction index
|
|
logic [4:0] instr_rs1;
|
|
logic [4:0] instr_rs2;
|
|
logic [4:0] instr_rs3;
|
|
logic [4:0] instr_rd;
|
|
|
|
logic use_rs3_d;
|
|
logic use_rs3_q;
|
|
|
|
logic pa_use_rs3;
|
|
logic pa_write_to_rs1;
|
|
|
|
csr_op_e csr_op;
|
|
|
|
opcode_e opcode;
|
|
opcode_e opcode_alu;
|
|
|
|
// To help timing the flops containing the current instruction are replicated to reduce fan-out.
|
|
// instr_alu is used to determine the ALU control logic and associated operand/imm select signals
|
|
// as the ALU is often on the more critical timing paths. instr is used for everything else.
|
|
assign instr = instr_rdata_i;
|
|
assign instr_alu = instr_rdata_alu_i;
|
|
|
|
//////////////////////////////////////
|
|
// Register and immediate selection //
|
|
//////////////////////////////////////
|
|
|
|
// immediate extraction and sign extension
|
|
assign imm_i_type_o = { {20{instr[31]}}, instr[31:20] };
|
|
assign imm_s_type_o = { {20{instr[31]}}, instr[31:25], instr[11:7] };
|
|
assign imm_b_type_o = { {19{instr[31]}}, instr[31], instr[7], instr[30:25], instr[11:8], 1'b0 };
|
|
assign imm_u_type_o = { instr[31:12], 12'b0 };
|
|
assign imm_j_type_o = { {12{instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0 };
|
|
|
|
// immediate for CSR manipulation (zero extended)
|
|
assign zimm_rs1_type_o = { 27'b0, instr_rs1 }; // rs1
|
|
|
|
// the use of rs3 is known one cycle ahead.
|
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
|
if (!rst_ni) begin
|
|
use_rs3_q <= 1'b0;
|
|
end else begin
|
|
use_rs3_q <= use_rs3_d;
|
|
end
|
|
end
|
|
|
|
// source registers
|
|
assign instr_rs1 = instr[19:15];
|
|
assign instr_rs2 = instr[24:20];
|
|
assign instr_rs3 = instr[31:27];
|
|
assign rf_raddr_a_o = (use_rs3_q & ~instr_first_cycle_i) ? instr_rs3 : instr_rs1; // rs3 / rs1
|
|
assign rf_raddr_b_o = pa_use_rs3 ? instr_rs3 : instr_rs2; // rs3 / rs2
|
|
|
|
// destination register
|
|
assign instr_rd = instr[11:7];
|
|
assign rf_waddr_o = pa_write_to_rs1 ? instr_rs1 : instr_rd; // rs1 / rd
|
|
|
|
////////////////////
|
|
// Register check //
|
|
////////////////////
|
|
if (RV32E) begin : gen_rv32e_reg_check_active
|
|
assign illegal_reg_rv32e = ((rf_raddr_a_o[4] & (alu_op_a_mux_sel_o == OP_A_REG_A)) |
|
|
(rf_raddr_b_o[4] & (alu_op_b_mux_sel_o == OP_B_REG_B)) |
|
|
(rf_waddr_o[4] & rf_we));
|
|
end else begin : gen_rv32e_reg_check_inactive
|
|
assign illegal_reg_rv32e = 1'b0;
|
|
end
|
|
|
|
///////////////////////
|
|
// CSR operand check //
|
|
///////////////////////
|
|
always_comb begin : csr_operand_check
|
|
csr_op_o = csr_op;
|
|
|
|
// CSRRSI/CSRRCI must not write 0 to CSRs (uimm[4:0]=='0)
|
|
// CSRRS/CSRRC must not write from x0 to CSRs (rs1=='0)
|
|
if ((csr_op == CSR_OP_SET || csr_op == CSR_OP_CLEAR) &&
|
|
instr_rs1 == '0) begin
|
|
csr_op_o = CSR_OP_READ;
|
|
end
|
|
end
|
|
|
|
/////////////
|
|
// Decoder //
|
|
/////////////
|
|
|
|
always_comb begin
|
|
jump_in_dec_o = 1'b0;
|
|
jump_set_o = 1'b0;
|
|
branch_in_dec_o = 1'b0;
|
|
icache_inval_o = 1'b0;
|
|
|
|
multdiv_operator_o = MD_OP_MULL;
|
|
multdiv_signed_mode_o = 2'b00;
|
|
|
|
rf_wdata_sel_o = RF_WD_EX;
|
|
rf_we = 1'b0;
|
|
rf_ren_a_o = 1'b0;
|
|
rf_ren_b_o = 1'b0;
|
|
|
|
csr_access_o = 1'b0;
|
|
csr_illegal = 1'b0;
|
|
csr_op = CSR_OP_READ;
|
|
|
|
data_we_o = 1'b0;
|
|
data_type_o = 2'b00;
|
|
data_sign_extension_o = 1'b0;
|
|
data_req_o = 1'b0;
|
|
|
|
illegal_insn = 1'b0;
|
|
ebrk_insn_o = 1'b0;
|
|
mret_insn_o = 1'b0;
|
|
dret_insn_o = 1'b0;
|
|
ecall_insn_o = 1'b0;
|
|
wfi_insn_o = 1'b0;
|
|
|
|
pac_en_dec_o = 1'b0;
|
|
aut_en_dec_o = 1'b0;
|
|
pa_use_rs3 = 1'b0;
|
|
pa_write_to_rs1 = 1'b0;
|
|
|
|
opcode = opcode_e'(instr[6:0]);
|
|
|
|
unique case (opcode)
|
|
|
|
///////////
|
|
// Jumps //
|
|
///////////
|
|
|
|
OPCODE_JAL: begin // Jump and Link
|
|
jump_in_dec_o = 1'b1;
|
|
|
|
if (instr_first_cycle_i) begin
|
|
// Calculate jump target (and store PC + 4 if BranchTargetALU is configured)
|
|
rf_we = BranchTargetALU;
|
|
jump_set_o = 1'b1;
|
|
end else begin
|
|
// Calculate and store PC+4
|
|
rf_we = 1'b1;
|
|
end
|
|
end
|
|
|
|
OPCODE_JALR: begin // Jump and Link Register
|
|
jump_in_dec_o = 1'b1;
|
|
|
|
if (instr_first_cycle_i) begin
|
|
// Calculate jump target (and store PC + 4 if BranchTargetALU is configured)
|
|
rf_we = BranchTargetALU;
|
|
jump_set_o = 1'b1;
|
|
end else begin
|
|
// Calculate and store PC+4
|
|
rf_we = 1'b1;
|
|
end
|
|
if (instr[14:12] != 3'b0) begin
|
|
illegal_insn = 1'b1;
|
|
end
|
|
|
|
rf_ren_a_o = 1'b1;
|
|
end
|
|
|
|
OPCODE_BRANCH: begin // Branch
|
|
branch_in_dec_o = 1'b1;
|
|
// Check branch condition selection
|
|
unique case (instr[14:12])
|
|
3'b000,
|
|
3'b001,
|
|
3'b100,
|
|
3'b101,
|
|
3'b110,
|
|
3'b111: illegal_insn = 1'b0;
|
|
default: illegal_insn = 1'b1;
|
|
endcase
|
|
|
|
rf_ren_a_o = 1'b1;
|
|
rf_ren_b_o = 1'b1;
|
|
end
|
|
|
|
////////////////
|
|
// Load/store //
|
|
////////////////
|
|
|
|
OPCODE_STORE: begin
|
|
rf_ren_a_o = 1'b1;
|
|
rf_ren_b_o = 1'b1;
|
|
data_req_o = 1'b1;
|
|
data_we_o = 1'b1;
|
|
|
|
if (instr[14]) begin
|
|
illegal_insn = 1'b1;
|
|
end
|
|
|
|
// store size
|
|
unique case (instr[13:12])
|
|
2'b00: data_type_o = 2'b10; // sb
|
|
2'b01: data_type_o = 2'b01; // sh
|
|
2'b10: data_type_o = 2'b00; // sw
|
|
default: illegal_insn = 1'b1;
|
|
endcase
|
|
end
|
|
|
|
OPCODE_LOAD: begin
|
|
rf_ren_a_o = 1'b1;
|
|
data_req_o = 1'b1;
|
|
data_type_o = 2'b00;
|
|
|
|
// sign/zero extension
|
|
data_sign_extension_o = ~instr[14];
|
|
|
|
// load size
|
|
unique case (instr[13:12])
|
|
2'b00: data_type_o = 2'b10; // lb(u)
|
|
2'b01: data_type_o = 2'b01; // lh(u)
|
|
2'b10: begin
|
|
data_type_o = 2'b00; // lw
|
|
if (instr[14]) begin
|
|
illegal_insn = 1'b1; // lwu does not exist
|
|
end
|
|
end
|
|
default: begin
|
|
illegal_insn = 1'b1;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
/////////
|
|
// ALU //
|
|
/////////
|
|
|
|
OPCODE_LUI: begin // Load Upper Immediate
|
|
rf_we = 1'b1;
|
|
end
|
|
|
|
OPCODE_AUIPC: begin // Add Upper Immediate to PC
|
|
rf_we = 1'b1;
|
|
end
|
|
|
|
OPCODE_OP_IMM: begin // Register-Immediate ALU Operations
|
|
rf_ren_a_o = 1'b1;
|
|
rf_we = 1'b1;
|
|
|
|
unique case (instr[14:12])
|
|
3'b000,
|
|
3'b010,
|
|
3'b011,
|
|
3'b100,
|
|
3'b110,
|
|
3'b111: illegal_insn = 1'b0;
|
|
|
|
3'b001: begin
|
|
unique case (instr[31:27])
|
|
5'b0_0000: illegal_insn = 1'b0; // slli
|
|
5'b0_0100, // sloi
|
|
5'b0_1001, // sbclri
|
|
5'b0_0101, // sbseti
|
|
5'b0_1101: illegal_insn = (RV32B != RV32BNone) ? 1'b0 : 1'b1; // sbinvi
|
|
5'b0_0001: if (instr[26] == 1'b0) begin
|
|
illegal_insn = (RV32B == RV32BFull) ? 1'b0 : 1'b1; // shfl
|
|
end else begin
|
|
illegal_insn = 1'b1;
|
|
end
|
|
5'b0_1100: begin
|
|
unique case(instr[26:20])
|
|
7'b000_0000, // clz
|
|
7'b000_0001, // ctz
|
|
7'b000_0010, // pcnt
|
|
7'b000_0100, // sext.b
|
|
7'b000_0101: illegal_insn = (RV32B != RV32BNone) ? 1'b0 : 1'b1; // sext.h
|
|
7'b001_0000, // crc32.b
|
|
7'b001_0001, // crc32.h
|
|
7'b001_0010, // crc32.w
|
|
7'b001_1000, // crc32c.b
|
|
7'b001_1001, // crc32c.h
|
|
7'b001_1010: illegal_insn = (RV32B == RV32BFull) ? 1'b0 : 1'b1; // crc32c.w
|
|
|
|
default: illegal_insn = 1'b1;
|
|
endcase
|
|
end
|
|
default : illegal_insn = 1'b1;
|
|
endcase
|
|
end
|
|
|
|
3'b101: begin
|
|
if (instr[26]) begin
|
|
illegal_insn = (RV32B != RV32BNone) ? 1'b0 : 1'b1; // fsri
|
|
end else begin
|
|
unique case (instr[31:27])
|
|
5'b0_0000, // srli
|
|
5'b0_1000: illegal_insn = 1'b0; // srai
|
|
|
|
5'b0_0100, // sroi
|
|
5'b0_1100, // rori
|
|
5'b0_1001: illegal_insn = (RV32B != RV32BNone) ? 1'b0 : 1'b1; // sbexti
|
|
|
|
5'b0_1101: begin
|
|
if ((RV32B == RV32BFull)) begin
|
|
illegal_insn = 1'b0; // grevi
|
|
end else begin
|
|
unique case (instr[24:20])
|
|
5'b11111, // rev
|
|
5'b11000: illegal_insn = (RV32B == RV32BBalanced) ? 1'b0 : 1'b1; // rev8
|
|
|
|
default: illegal_insn = 1'b1;
|
|
endcase
|
|
end
|
|
end
|
|
5'b0_0101: begin
|
|
if ((RV32B == RV32BFull)) begin
|
|
illegal_insn = 1'b0; // gorci
|
|
end else if (instr[24:20] == 5'b00111) begin
|
|
illegal_insn = (RV32B == RV32BBalanced) ? 1'b0 : 1'b1; // orc.b
|
|
end
|
|
end
|
|
5'b0_0001: begin
|
|
if (instr[26] == 1'b0) begin
|
|
illegal_insn = (RV32B == RV32BFull) ? 1'b0 : 1'b1; // unshfl
|
|
end else begin
|
|
illegal_insn = 1'b1;
|
|
end
|
|
end
|
|
|
|
default: illegal_insn = 1'b1;
|
|
endcase
|
|
end
|
|
end
|
|
|
|
default: illegal_insn = 1'b1;
|
|
endcase
|
|
end
|
|
|
|
OPCODE_OP: begin // Register-Register ALU operation
|
|
rf_ren_a_o = 1'b1;
|
|
rf_ren_b_o = 1'b1;
|
|
rf_we = 1'b1;
|
|
if ({instr[26], instr[13:12]} == {1'b1, 2'b01}) begin
|
|
illegal_insn = (RV32B != RV32BNone) ? 1'b0 : 1'b1; // cmix / cmov / fsl / fsr
|
|
end else begin
|
|
unique case ({instr[31:25], instr[14:12]})
|
|
// RV32I ALU operations
|
|
{7'b000_0000, 3'b000},
|
|
{7'b010_0000, 3'b000},
|
|
{7'b000_0000, 3'b010},
|
|
{7'b000_0000, 3'b011},
|
|
{7'b000_0000, 3'b100},
|
|
{7'b000_0000, 3'b110},
|
|
{7'b000_0000, 3'b111},
|
|
{7'b000_0000, 3'b001},
|
|
{7'b000_0000, 3'b101},
|
|
{7'b010_0000, 3'b101}: illegal_insn = 1'b0;
|
|
|
|
// RV32B zbb
|
|
{7'b010_0000, 3'b111}, // andn
|
|
{7'b010_0000, 3'b110}, // orn
|
|
{7'b010_0000, 3'b100}, // xnor
|
|
{7'b001_0000, 3'b001}, // slo
|
|
{7'b001_0000, 3'b101}, // sro
|
|
{7'b011_0000, 3'b001}, // rol
|
|
{7'b011_0000, 3'b101}, // ror
|
|
{7'b000_0101, 3'b100}, // min
|
|
{7'b000_0101, 3'b101}, // max
|
|
{7'b000_0101, 3'b110}, // minu
|
|
{7'b000_0101, 3'b111}, // maxu
|
|
{7'b000_0100, 3'b100}, // pack
|
|
{7'b010_0100, 3'b100}, // packu
|
|
{7'b000_0100, 3'b111}, // packh
|
|
// RV32B zbs
|
|
{7'b010_0100, 3'b001}, // sbclr
|
|
{7'b001_0100, 3'b001}, // sbset
|
|
{7'b011_0100, 3'b001}, // sbinv
|
|
{7'b010_0100, 3'b101}, // sbext
|
|
// RV32B zbf
|
|
{7'b010_0100, 3'b111}: illegal_insn = (RV32B != RV32BNone) ? 1'b0 : 1'b1; // bfp
|
|
// RV32B zbe
|
|
{7'b010_0100, 3'b110}, // bdep
|
|
{7'b000_0100, 3'b110}, // bext
|
|
// RV32B zbp
|
|
{7'b011_0100, 3'b101}, // grev
|
|
{7'b001_0100, 3'b101}, // gorc
|
|
{7'b000_0100, 3'b001}, // shfl
|
|
{7'b000_0100, 3'b101}, // unshfl
|
|
// RV32B zbc
|
|
{7'b000_0101, 3'b001}, // clmul
|
|
{7'b000_0101, 3'b010}, // clmulr
|
|
{7'b000_0101, 3'b011}: illegal_insn = (RV32B == RV32BFull) ? 1'b0 : 1'b1; // clmulh
|
|
|
|
// RV32M instructions
|
|
{7'b000_0001, 3'b000}: begin // mul
|
|
multdiv_operator_o = MD_OP_MULL;
|
|
multdiv_signed_mode_o = 2'b00;
|
|
illegal_insn = RV32M ? 1'b0 : 1'b1;
|
|
end
|
|
{7'b000_0001, 3'b001}: begin // mulh
|
|
multdiv_operator_o = MD_OP_MULH;
|
|
multdiv_signed_mode_o = 2'b11;
|
|
illegal_insn = RV32M ? 1'b0 : 1'b1;
|
|
end
|
|
{7'b000_0001, 3'b010}: begin // mulhsu
|
|
multdiv_operator_o = MD_OP_MULH;
|
|
multdiv_signed_mode_o = 2'b01;
|
|
illegal_insn = RV32M ? 1'b0 : 1'b1;
|
|
end
|
|
{7'b000_0001, 3'b011}: begin // mulhu
|
|
multdiv_operator_o = MD_OP_MULH;
|
|
multdiv_signed_mode_o = 2'b00;
|
|
illegal_insn = RV32M ? 1'b0 : 1'b1;
|
|
end
|
|
{7'b000_0001, 3'b100}: begin // div
|
|
multdiv_operator_o = MD_OP_DIV;
|
|
multdiv_signed_mode_o = 2'b11;
|
|
illegal_insn = RV32M ? 1'b0 : 1'b1;
|
|
end
|
|
{7'b000_0001, 3'b101}: begin // divu
|
|
multdiv_operator_o = MD_OP_DIV;
|
|
multdiv_signed_mode_o = 2'b00;
|
|
illegal_insn = RV32M ? 1'b0 : 1'b1;
|
|
end
|
|
{7'b000_0001, 3'b110}: begin // rem
|
|
multdiv_operator_o = MD_OP_REM;
|
|
multdiv_signed_mode_o = 2'b11;
|
|
illegal_insn = RV32M ? 1'b0 : 1'b1;
|
|
end
|
|
{7'b000_0001, 3'b111}: begin // remu
|
|
multdiv_operator_o = MD_OP_REM;
|
|
multdiv_signed_mode_o = 2'b00;
|
|
illegal_insn = RV32M ? 1'b0 : 1'b1;
|
|
end
|
|
default: begin
|
|
illegal_insn = 1'b1;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
/////////////
|
|
// Special //
|
|
/////////////
|
|
|
|
OPCODE_MISC_MEM: begin
|
|
// For now, treat the FENCE (funct3 == 000) instruction as a NOP. This may not be correct
|
|
// in a system with caches and should be revisited.
|
|
// FENCE.I will flush the IF stage and prefetch buffer (or ICache) but nothing else.
|
|
unique case (instr[14:12])
|
|
3'b000: begin
|
|
rf_we = 1'b0;
|
|
end
|
|
3'b001: begin
|
|
// FENCE.I is implemented as a jump to the next PC, this gives the required flushing
|
|
// behaviour (iside prefetch buffer flushed and response to any outstanding iside
|
|
// requests will be ignored).
|
|
// If present, the ICache will also be flushed.
|
|
jump_in_dec_o = 1'b1;
|
|
|
|
rf_we = 1'b0;
|
|
|
|
if (instr_first_cycle_i) begin
|
|
jump_set_o = 1'b1;
|
|
icache_inval_o = 1'b1;
|
|
end
|
|
end
|
|
default: begin
|
|
illegal_insn = 1'b1;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
OPCODE_SYSTEM: begin
|
|
if (instr[14:12] == 3'b000) begin
|
|
// non CSR related SYSTEM instructions
|
|
unique case (instr[31:20])
|
|
12'h000: // ECALL
|
|
// environment (system) call
|
|
ecall_insn_o = 1'b1;
|
|
|
|
12'h001: // ebreak
|
|
// debugger trap
|
|
ebrk_insn_o = 1'b1;
|
|
|
|
12'h302: // mret
|
|
mret_insn_o = 1'b1;
|
|
|
|
12'h7b2: // dret
|
|
dret_insn_o = 1'b1;
|
|
|
|
12'h105: // wfi
|
|
wfi_insn_o = 1'b1;
|
|
|
|
default:
|
|
illegal_insn = 1'b1;
|
|
endcase
|
|
|
|
// rs1 and rd must be 0
|
|
if (instr_rs1 != 5'b0 || instr_rd != 5'b0) begin
|
|
illegal_insn = 1'b1;
|
|
end
|
|
end else begin
|
|
// instruction to read/modify CSR
|
|
csr_access_o = 1'b1;
|
|
rf_wdata_sel_o = RF_WD_CSR;
|
|
rf_we = 1'b1;
|
|
|
|
if (~instr[14]) begin
|
|
rf_ren_a_o = 1'b1;
|
|
end
|
|
|
|
unique case (instr[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
|
|
|
|
illegal_insn = csr_illegal;
|
|
end
|
|
|
|
end
|
|
|
|
////////////////////////////
|
|
// Pointer Authentication //
|
|
////////////////////////////
|
|
|
|
OPCODE_PA: begin // Custom Operations for Pointer Authentication
|
|
rf_ren_a_o = 1'b1;
|
|
rf_ren_b_o = 1'b1;
|
|
unique case (instr[14:12])
|
|
3'b000: begin // PAC
|
|
pac_en_dec_o = (PointerAuthentication) ? 1'b1 : 1'b0;
|
|
rf_wdata_sel_o = RF_WD_PA;
|
|
rf_we = 1'b1;
|
|
if (instr_first_cycle_i) begin
|
|
// First write magic number and LSBs of pointer to rs1
|
|
pa_write_to_rs1 = 1'b1;
|
|
end else begin
|
|
// Then write MSBs of pointer and pac to rd
|
|
pa_write_to_rs1 = 1'b0;
|
|
end
|
|
illegal_insn = (PointerAuthentication) ? 1'b0 : 1'b1;
|
|
end
|
|
|
|
3'b001: begin // AUT
|
|
aut_en_dec_o = (PointerAuthentication) ? 1'b1 : 1'b0;
|
|
rf_wdata_sel_o = RF_WD_PA;
|
|
rf_we = 1'b1;
|
|
if (instr_first_cycle_i) begin
|
|
// First read MSBs of pointer and pac from rs2
|
|
pa_use_rs3 = 1'b0;
|
|
end else begin
|
|
// Then read LSBs of pointer from rs1 and read context from rs3
|
|
pa_use_rs3 = 1'b1;
|
|
end
|
|
illegal_insn = (PointerAuthentication) ? 1'b0 : 1'b1;
|
|
end
|
|
|
|
default:
|
|
illegal_insn = 1'b1;
|
|
endcase
|
|
end
|
|
default: begin
|
|
illegal_insn = 1'b1;
|
|
end
|
|
endcase
|
|
|
|
// make sure illegal compressed instructions cause illegal instruction exceptions
|
|
if (illegal_c_insn_i) begin
|
|
illegal_insn = 1'b1;
|
|
end
|
|
|
|
// make sure illegal instructions detected in the decoder do not propagate from decoder
|
|
// into register file, LSU, EX, WB, CSRs, PC
|
|
// NOTE: instructions can also be detected to be illegal inside the CSRs (upon accesses with
|
|
// insufficient privileges), or when accessing non-available registers in RV32E,
|
|
// these cases are not handled here
|
|
if (illegal_insn) begin
|
|
rf_we = 1'b0;
|
|
data_req_o = 1'b0;
|
|
data_we_o = 1'b0;
|
|
jump_in_dec_o = 1'b0;
|
|
jump_set_o = 1'b0;
|
|
branch_in_dec_o = 1'b0;
|
|
csr_access_o = 1'b0;
|
|
end
|
|
end
|
|
|
|
/////////////////////////////
|
|
// Decoder for ALU control //
|
|
/////////////////////////////
|
|
|
|
always_comb begin
|
|
alu_operator_o = ALU_SLTU;
|
|
alu_op_a_mux_sel_o = OP_A_IMM;
|
|
alu_op_b_mux_sel_o = OP_B_IMM;
|
|
|
|
imm_a_mux_sel_o = IMM_A_ZERO;
|
|
imm_b_mux_sel_o = IMM_B_I;
|
|
|
|
bt_a_mux_sel_o = OP_A_CURRPC;
|
|
bt_b_mux_sel_o = IMM_B_I;
|
|
|
|
|
|
opcode_alu = opcode_e'(instr_alu[6:0]);
|
|
|
|
use_rs3_d = 1'b0;
|
|
alu_multicycle_o = 1'b0;
|
|
mult_sel_o = 1'b0;
|
|
div_sel_o = 1'b0;
|
|
|
|
unique case (opcode_alu)
|
|
|
|
///////////
|
|
// Jumps //
|
|
///////////
|
|
|
|
OPCODE_JAL: begin // Jump and Link
|
|
if (BranchTargetALU) begin
|
|
bt_a_mux_sel_o = OP_A_CURRPC;
|
|
bt_b_mux_sel_o = IMM_B_J;
|
|
end
|
|
|
|
// Jumps take two cycles without the BTALU
|
|
if (instr_first_cycle_i && !BranchTargetALU) begin
|
|
// Calculate jump target
|
|
alu_op_a_mux_sel_o = OP_A_CURRPC;
|
|
alu_op_b_mux_sel_o = OP_B_IMM;
|
|
imm_b_mux_sel_o = IMM_B_J;
|
|
alu_operator_o = ALU_ADD;
|
|
end else begin
|
|
// Calculate and store PC+4
|
|
alu_op_a_mux_sel_o = OP_A_CURRPC;
|
|
alu_op_b_mux_sel_o = OP_B_IMM;
|
|
imm_b_mux_sel_o = IMM_B_INCR_PC;
|
|
alu_operator_o = ALU_ADD;
|
|
end
|
|
end
|
|
|
|
OPCODE_JALR: begin // Jump and Link Register
|
|
if (BranchTargetALU) begin
|
|
bt_a_mux_sel_o = OP_A_REG_A;
|
|
bt_b_mux_sel_o = IMM_B_I;
|
|
end
|
|
|
|
// Jumps take two cycles without the BTALU
|
|
if (instr_first_cycle_i && !BranchTargetALU) begin
|
|
// Calculate jump target
|
|
alu_op_a_mux_sel_o = OP_A_REG_A;
|
|
alu_op_b_mux_sel_o = OP_B_IMM;
|
|
imm_b_mux_sel_o = IMM_B_I;
|
|
alu_operator_o = ALU_ADD;
|
|
end else begin
|
|
// Calculate and store PC+4
|
|
alu_op_a_mux_sel_o = OP_A_CURRPC;
|
|
alu_op_b_mux_sel_o = OP_B_IMM;
|
|
imm_b_mux_sel_o = IMM_B_INCR_PC;
|
|
alu_operator_o = ALU_ADD;
|
|
end
|
|
end
|
|
|
|
OPCODE_BRANCH: begin // Branch
|
|
// Check branch condition selection
|
|
unique case (instr_alu[14:12])
|
|
3'b000: alu_operator_o = ALU_EQ;
|
|
3'b001: alu_operator_o = ALU_NE;
|
|
3'b100: alu_operator_o = ALU_LT;
|
|
3'b101: alu_operator_o = ALU_GE;
|
|
3'b110: alu_operator_o = ALU_LTU;
|
|
3'b111: alu_operator_o = ALU_GEU;
|
|
default: ;
|
|
endcase
|
|
|
|
if (BranchTargetALU) begin
|
|
bt_a_mux_sel_o = OP_A_CURRPC;
|
|
// Not-taken branch will jump to next instruction (used in secure mode)
|
|
bt_b_mux_sel_o = branch_taken_i ? IMM_B_B : IMM_B_INCR_PC;
|
|
end
|
|
|
|
// Without branch target ALU, a branch is a two-stage operation using the Main ALU in both
|
|
// stages
|
|
if (instr_first_cycle_i) begin
|
|
// First evaluate the branch condition
|
|
alu_op_a_mux_sel_o = OP_A_REG_A;
|
|
alu_op_b_mux_sel_o = OP_B_REG_B;
|
|
end else begin
|
|
// Then calculate jump target
|
|
alu_op_a_mux_sel_o = OP_A_CURRPC;
|
|
alu_op_b_mux_sel_o = OP_B_IMM;
|
|
// Not-taken branch will jump to next instruction (used in secure mode)
|
|
imm_b_mux_sel_o = branch_taken_i ? IMM_B_B : IMM_B_INCR_PC;
|
|
alu_operator_o = ALU_ADD;
|
|
end
|
|
end
|
|
|
|
////////////////
|
|
// Load/store //
|
|
////////////////
|
|
|
|
OPCODE_STORE: begin
|
|
alu_op_a_mux_sel_o = OP_A_REG_A;
|
|
alu_op_b_mux_sel_o = OP_B_REG_B;
|
|
alu_operator_o = ALU_ADD;
|
|
|
|
if (!instr_alu[14]) begin
|
|
// offset from immediate
|
|
imm_b_mux_sel_o = IMM_B_S;
|
|
alu_op_b_mux_sel_o = OP_B_IMM;
|
|
end
|
|
end
|
|
|
|
OPCODE_LOAD: begin
|
|
alu_op_a_mux_sel_o = OP_A_REG_A;
|
|
|
|
// offset from immediate
|
|
alu_operator_o = ALU_ADD;
|
|
alu_op_b_mux_sel_o = OP_B_IMM;
|
|
imm_b_mux_sel_o = IMM_B_I;
|
|
end
|
|
|
|
/////////
|
|
// ALU //
|
|
/////////
|
|
|
|
OPCODE_LUI: begin // Load Upper Immediate
|
|
alu_op_a_mux_sel_o = OP_A_IMM;
|
|
alu_op_b_mux_sel_o = OP_B_IMM;
|
|
imm_a_mux_sel_o = IMM_A_ZERO;
|
|
imm_b_mux_sel_o = IMM_B_U;
|
|
alu_operator_o = ALU_ADD;
|
|
end
|
|
|
|
OPCODE_AUIPC: begin // Add Upper Immediate to PC
|
|
alu_op_a_mux_sel_o = OP_A_CURRPC;
|
|
alu_op_b_mux_sel_o = OP_B_IMM;
|
|
imm_b_mux_sel_o = IMM_B_U;
|
|
alu_operator_o = ALU_ADD;
|
|
end
|
|
|
|
OPCODE_OP_IMM: begin // Register-Immediate ALU Operations
|
|
alu_op_a_mux_sel_o = OP_A_REG_A;
|
|
alu_op_b_mux_sel_o = OP_B_IMM;
|
|
imm_b_mux_sel_o = IMM_B_I;
|
|
|
|
unique case (instr_alu[14:12])
|
|
3'b000: alu_operator_o = ALU_ADD; // Add Immediate
|
|
3'b010: alu_operator_o = ALU_SLT; // Set to one if Lower Than Immediate
|
|
3'b011: alu_operator_o = ALU_SLTU; // Set to one if Lower Than Immediate Unsigned
|
|
3'b100: alu_operator_o = ALU_XOR; // Exclusive Or with Immediate
|
|
3'b110: alu_operator_o = ALU_OR; // Or with Immediate
|
|
3'b111: alu_operator_o = ALU_AND; // And with Immediate
|
|
|
|
3'b001: begin
|
|
if (RV32B != RV32BNone) begin
|
|
unique case (instr_alu[31:27])
|
|
5'b0_0000: alu_operator_o = ALU_SLL; // Shift Left Logical by Immediate
|
|
5'b0_0100: alu_operator_o = ALU_SLO; // Shift Left Ones by Immediate
|
|
5'b0_1001: alu_operator_o = ALU_SBCLR; // Clear bit specified by immediate
|
|
5'b0_0101: alu_operator_o = ALU_SBSET; // Set bit specified by immediate
|
|
5'b0_1101: alu_operator_o = ALU_SBINV; // Invert bit specified by immediate.
|
|
// Shuffle with Immediate Control Value
|
|
5'b0_0001: if (instr_alu[26] == 0) alu_operator_o = ALU_SHFL;
|
|
5'b0_1100: begin
|
|
unique case (instr_alu[26:20])
|
|
7'b000_0000: alu_operator_o = ALU_CLZ; // clz
|
|
7'b000_0001: alu_operator_o = ALU_CTZ; // ctz
|
|
7'b000_0010: alu_operator_o = ALU_PCNT; // pcnt
|
|
7'b000_0100: alu_operator_o = ALU_SEXTB; // sext.b
|
|
7'b000_0101: alu_operator_o = ALU_SEXTH; // sext.h
|
|
7'b001_0000: begin
|
|
if (RV32B == RV32BFull) begin
|
|
alu_operator_o = ALU_CRC32_B; // crc32.b
|
|
alu_multicycle_o = 1'b1;
|
|
end
|
|
end
|
|
7'b001_0001: begin
|
|
if (RV32B == RV32BFull) begin
|
|
alu_operator_o = ALU_CRC32_H; // crc32.h
|
|
alu_multicycle_o = 1'b1;
|
|
end
|
|
end
|
|
7'b001_0010: begin
|
|
if (RV32B == RV32BFull) begin
|
|
alu_operator_o = ALU_CRC32_W; // crc32.w
|
|
alu_multicycle_o = 1'b1;
|
|
end
|
|
end
|
|
7'b001_1000: begin
|
|
if (RV32B == RV32BFull) begin
|
|
alu_operator_o = ALU_CRC32C_B; // crc32c.b
|
|
alu_multicycle_o = 1'b1;
|
|
end
|
|
end
|
|
7'b001_1001: begin
|
|
if (RV32B == RV32BFull) begin
|
|
alu_operator_o = ALU_CRC32C_H; // crc32c.h
|
|
alu_multicycle_o = 1'b1;
|
|
end
|
|
end
|
|
7'b001_1010: begin
|
|
if (RV32B == RV32BFull) begin
|
|
alu_operator_o = ALU_CRC32C_W; // crc32c.w
|
|
alu_multicycle_o = 1'b1;
|
|
end
|
|
end
|
|
default: ;
|
|
endcase
|
|
end
|
|
|
|
default: ;
|
|
endcase
|
|
end else begin
|
|
alu_operator_o = ALU_SLL; // Shift Left Logical by Immediate
|
|
end
|
|
end
|
|
|
|
3'b101: begin
|
|
if (RV32B != RV32BNone) begin
|
|
if (instr_alu[26] == 1'b1) begin
|
|
alu_operator_o = ALU_FSR;
|
|
alu_multicycle_o = 1'b1;
|
|
if (instr_first_cycle_i) begin
|
|
use_rs3_d = 1'b1;
|
|
end else begin
|
|
use_rs3_d = 1'b0;
|
|
end
|
|
end else begin
|
|
unique case (instr_alu[31:27])
|
|
5'b0_0000: alu_operator_o = ALU_SRL; // Shift Right Logical by Immediate
|
|
5'b0_1000: alu_operator_o = ALU_SRA; // Shift Right Arithmetically by Immediate
|
|
5'b0_0100: alu_operator_o = ALU_SRO; // Shift Right Ones by Immediate
|
|
5'b0_1001: alu_operator_o = ALU_SBEXT; // Extract bit specified by immediate.
|
|
5'b0_1100: begin
|
|
alu_operator_o = ALU_ROR; // Rotate Right by Immediate
|
|
alu_multicycle_o = 1'b1;
|
|
end
|
|
5'b0_1101: alu_operator_o = ALU_GREV; // General Reverse with Imm Control Val
|
|
5'b0_0101: alu_operator_o = ALU_GORC; // General Or-combine with Imm Control Val
|
|
// Unshuffle with Immediate Control Value
|
|
5'b0_0001: begin
|
|
if (RV32B == RV32BFull) begin
|
|
if (instr_alu[26] == 1'b0) alu_operator_o = ALU_UNSHFL;
|
|
end
|
|
end
|
|
default: ;
|
|
endcase
|
|
end
|
|
|
|
end else begin
|
|
if (instr_alu[31:27] == 5'b0_0000) begin
|
|
alu_operator_o = ALU_SRL; // Shift Right Logical by Immediate
|
|
end else if (instr_alu[31:27] == 5'b0_1000) begin
|
|
alu_operator_o = ALU_SRA; // Shift Right Arithmetically by Immediate
|
|
end
|
|
end
|
|
end
|
|
|
|
default: ;
|
|
endcase
|
|
end
|
|
|
|
OPCODE_OP: begin // Register-Register ALU operation
|
|
alu_op_a_mux_sel_o = OP_A_REG_A;
|
|
alu_op_b_mux_sel_o = OP_B_REG_B;
|
|
|
|
if (instr_alu[26]) begin
|
|
if (RV32B != RV32BNone) begin
|
|
unique case ({instr_alu[26:25], instr_alu[14:12]})
|
|
{2'b11, 3'b001}: begin
|
|
alu_operator_o = ALU_CMIX; // cmix
|
|
alu_multicycle_o = 1'b1;
|
|
if (instr_first_cycle_i) begin
|
|
use_rs3_d = 1'b1;
|
|
end else begin
|
|
use_rs3_d = 1'b0;
|
|
end
|
|
end
|
|
{2'b11, 3'b101}: begin
|
|
alu_operator_o = ALU_CMOV; // cmov
|
|
alu_multicycle_o = 1'b1;
|
|
if (instr_first_cycle_i) begin
|
|
use_rs3_d = 1'b1;
|
|
end else begin
|
|
use_rs3_d = 1'b0;
|
|
end
|
|
end
|
|
{2'b10, 3'b001}: begin
|
|
alu_operator_o = ALU_FSL; // fsl
|
|
alu_multicycle_o = 1'b1;
|
|
if (instr_first_cycle_i) begin
|
|
use_rs3_d = 1'b1;
|
|
end else begin
|
|
use_rs3_d = 1'b0;
|
|
end
|
|
end
|
|
{2'b10, 3'b101}: begin
|
|
alu_operator_o = ALU_FSR; // fsr
|
|
alu_multicycle_o = 1'b1;
|
|
if (instr_first_cycle_i) begin
|
|
use_rs3_d = 1'b1;
|
|
end else begin
|
|
use_rs3_d = 1'b0;
|
|
end
|
|
end
|
|
default: ;
|
|
endcase
|
|
end
|
|
end else begin
|
|
unique case ({instr_alu[31:25], instr_alu[14:12]})
|
|
// RV32I ALU operations
|
|
{7'b000_0000, 3'b000}: alu_operator_o = ALU_ADD; // Add
|
|
{7'b010_0000, 3'b000}: alu_operator_o = ALU_SUB; // Sub
|
|
{7'b000_0000, 3'b010}: alu_operator_o = ALU_SLT; // Set Lower Than
|
|
{7'b000_0000, 3'b011}: alu_operator_o = ALU_SLTU; // Set Lower Than Unsigned
|
|
{7'b000_0000, 3'b100}: alu_operator_o = ALU_XOR; // Xor
|
|
{7'b000_0000, 3'b110}: alu_operator_o = ALU_OR; // Or
|
|
{7'b000_0000, 3'b111}: alu_operator_o = ALU_AND; // And
|
|
{7'b000_0000, 3'b001}: alu_operator_o = ALU_SLL; // Shift Left Logical
|
|
{7'b000_0000, 3'b101}: alu_operator_o = ALU_SRL; // Shift Right Logical
|
|
{7'b010_0000, 3'b101}: alu_operator_o = ALU_SRA; // Shift Right Arithmetic
|
|
|
|
// RV32B ALU Operations
|
|
{7'b001_0000, 3'b001}: if (RV32B != RV32BNone) alu_operator_o = ALU_SLO; // slo
|
|
{7'b001_0000, 3'b101}: if (RV32B != RV32BNone) alu_operator_o = ALU_SRO; // sro
|
|
{7'b011_0000, 3'b001}: begin
|
|
if (RV32B != RV32BNone) begin
|
|
alu_operator_o = ALU_ROL; // rol
|
|
alu_multicycle_o = 1'b1;
|
|
end
|
|
end
|
|
{7'b011_0000, 3'b101}: begin
|
|
if (RV32B != RV32BNone) begin
|
|
alu_operator_o = ALU_ROR; // ror
|
|
alu_multicycle_o = 1'b1;
|
|
end
|
|
end
|
|
|
|
{7'b000_0101, 3'b100}: if (RV32B != RV32BNone) alu_operator_o = ALU_MIN; // min
|
|
{7'b000_0101, 3'b101}: if (RV32B != RV32BNone) alu_operator_o = ALU_MAX; // max
|
|
{7'b000_0101, 3'b110}: if (RV32B != RV32BNone) alu_operator_o = ALU_MINU; // minu
|
|
{7'b000_0101, 3'b111}: if (RV32B != RV32BNone) alu_operator_o = ALU_MAXU; // maxu
|
|
|
|
{7'b000_0100, 3'b100}: if (RV32B != RV32BNone) alu_operator_o = ALU_PACK; // pack
|
|
{7'b010_0100, 3'b100}: if (RV32B != RV32BNone) alu_operator_o = ALU_PACKU; // packu
|
|
{7'b000_0100, 3'b111}: if (RV32B != RV32BNone) alu_operator_o = ALU_PACKH; // packh
|
|
|
|
{7'b010_0000, 3'b100}: if (RV32B != RV32BNone) alu_operator_o = ALU_XNOR; // xnor
|
|
{7'b010_0000, 3'b110}: if (RV32B != RV32BNone) alu_operator_o = ALU_ORN; // orn
|
|
{7'b010_0000, 3'b111}: if (RV32B != RV32BNone) alu_operator_o = ALU_ANDN; // andn
|
|
|
|
// RV32B zbs
|
|
{7'b010_0100, 3'b001}: if (RV32B != RV32BNone) alu_operator_o = ALU_SBCLR; // sbclr
|
|
{7'b001_0100, 3'b001}: if (RV32B != RV32BNone) alu_operator_o = ALU_SBSET; // sbset
|
|
{7'b011_0100, 3'b001}: if (RV32B != RV32BNone) alu_operator_o = ALU_SBINV; // sbinv
|
|
{7'b010_0100, 3'b101}: if (RV32B != RV32BNone) alu_operator_o = ALU_SBEXT; // sbext
|
|
|
|
// RV32B zbf
|
|
{7'b010_0100, 3'b111}: if (RV32B != RV32BNone) alu_operator_o = ALU_BFP; // bfp
|
|
|
|
// RV32B zbp
|
|
{7'b011_0100, 3'b101}: if (RV32B != RV32BNone) alu_operator_o = ALU_GREV; // grev
|
|
{7'b001_0100, 3'b101}: if (RV32B != RV32BNone) alu_operator_o = ALU_GORC; // grev
|
|
{7'b000_0100, 3'b001}: if (RV32B == RV32BFull) alu_operator_o = ALU_SHFL; // shfl
|
|
{7'b000_0100, 3'b101}: if (RV32B == RV32BFull) alu_operator_o = ALU_UNSHFL; // unshfl
|
|
|
|
// RV32B zbc
|
|
{7'b000_0101, 3'b001}: if (RV32B == RV32BFull) alu_operator_o = ALU_CLMUL; // clmul
|
|
{7'b000_0101, 3'b010}: if (RV32B == RV32BFull) alu_operator_o = ALU_CLMULR; // clmulr
|
|
{7'b000_0101, 3'b011}: if (RV32B == RV32BFull) alu_operator_o = ALU_CLMULH; // clmulh
|
|
|
|
// RV32B zbe
|
|
{7'b010_0100, 3'b110}: begin
|
|
if (RV32B == RV32BFull) begin
|
|
alu_operator_o = ALU_BDEP; // bdep
|
|
alu_multicycle_o = 1'b1;
|
|
end
|
|
end
|
|
{7'b000_0100, 3'b110}: begin
|
|
if (RV32B == RV32BFull) begin
|
|
alu_operator_o = ALU_BEXT; // bext
|
|
alu_multicycle_o = 1'b1;
|
|
end
|
|
end
|
|
|
|
// RV32M instructions, all use the same ALU operation
|
|
{7'b000_0001, 3'b000}: begin // mul
|
|
alu_operator_o = ALU_ADD;
|
|
mult_sel_o = RV32M ? 1'b1 : 1'b0;
|
|
end
|
|
{7'b000_0001, 3'b001}: begin // mulh
|
|
alu_operator_o = ALU_ADD;
|
|
mult_sel_o = RV32M ? 1'b1 : 1'b0;
|
|
end
|
|
{7'b000_0001, 3'b010}: begin // mulhsu
|
|
alu_operator_o = ALU_ADD;
|
|
mult_sel_o = RV32M ? 1'b1 : 1'b0;
|
|
end
|
|
{7'b000_0001, 3'b011}: begin // mulhu
|
|
alu_operator_o = ALU_ADD;
|
|
mult_sel_o = RV32M ? 1'b1 : 1'b0;
|
|
end
|
|
{7'b000_0001, 3'b100}: begin // div
|
|
alu_operator_o = ALU_ADD;
|
|
div_sel_o = RV32M ? 1'b1 : 1'b0;
|
|
end
|
|
{7'b000_0001, 3'b101}: begin // divu
|
|
alu_operator_o = ALU_ADD;
|
|
div_sel_o = RV32M ? 1'b1 : 1'b0;
|
|
end
|
|
{7'b000_0001, 3'b110}: begin // rem
|
|
alu_operator_o = ALU_ADD;
|
|
div_sel_o = RV32M ? 1'b1 : 1'b0;
|
|
end
|
|
{7'b000_0001, 3'b111}: begin // remu
|
|
alu_operator_o = ALU_ADD;
|
|
div_sel_o = RV32M ? 1'b1 : 1'b0;
|
|
end
|
|
|
|
default: ;
|
|
endcase
|
|
end
|
|
end
|
|
|
|
/////////////
|
|
// Special //
|
|
/////////////
|
|
|
|
OPCODE_MISC_MEM: begin
|
|
// For now, treat the FENCE (funct3 == 000) instruction as a NOP. This may not be correct
|
|
// in a system with caches and should be revisited.
|
|
// FENCE.I will flush the IF stage and prefetch buffer but nothing else.
|
|
unique case (instr_alu[14:12])
|
|
3'b000: begin
|
|
alu_operator_o = ALU_ADD; // nop
|
|
alu_op_a_mux_sel_o = OP_A_REG_A;
|
|
alu_op_b_mux_sel_o = OP_B_IMM;
|
|
end
|
|
3'b001: begin
|
|
if (BranchTargetALU) begin
|
|
bt_a_mux_sel_o = OP_A_CURRPC;
|
|
bt_b_mux_sel_o = IMM_B_INCR_PC;
|
|
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 = IMM_B_INCR_PC;
|
|
alu_operator_o = ALU_ADD;
|
|
end
|
|
end
|
|
default: ;
|
|
endcase
|
|
end
|
|
|
|
OPCODE_SYSTEM: begin
|
|
if (instr_alu[14:12] == 3'b000) begin
|
|
// non CSR related SYSTEM instructions
|
|
alu_op_a_mux_sel_o = OP_A_REG_A;
|
|
alu_op_b_mux_sel_o = OP_B_IMM;
|
|
end else begin
|
|
// instruction to read/modify CSR
|
|
alu_op_b_mux_sel_o = OP_B_IMM;
|
|
imm_a_mux_sel_o = IMM_A_Z;
|
|
imm_b_mux_sel_o = IMM_B_I; // CSR address is encoded in I imm
|
|
|
|
if (instr_alu[14]) begin
|
|
// rs1 field is used as immediate
|
|
alu_op_a_mux_sel_o = OP_A_IMM;
|
|
end else begin
|
|
alu_op_a_mux_sel_o = OP_A_REG_A;
|
|
end
|
|
end
|
|
|
|
end
|
|
default: ;
|
|
endcase
|
|
end
|
|
|
|
// do not enable multdiv in case of illegal instruction exceptions
|
|
assign mult_en_o = illegal_insn ? 1'b0 : mult_sel_o;
|
|
assign div_en_o = illegal_insn ? 1'b0 : div_sel_o;
|
|
|
|
// make sure instructions accessing non-available registers in RV32E cause illegal
|
|
// instruction exceptions
|
|
assign illegal_insn_o = illegal_insn | illegal_reg_rv32e;
|
|
|
|
// do not propgate regfile write enable if non-available registers are accessed in RV32E
|
|
assign rf_we_o = rf_we & ~illegal_reg_rv32e;
|
|
|
|
////////////////
|
|
// Assertions //
|
|
////////////////
|
|
|
|
// Selectors must be known/valid.
|
|
`ASSERT(IbexRegImmAluOpKnown, (opcode == OPCODE_OP_IMM) |->
|
|
!$isunknown(instr[14:12]))
|
|
endmodule // controller
|