New version of divider, variable latency and thus faster on average

This commit is contained in:
Andreas Traber 2016-03-15 17:42:16 +01:00
parent 4401708fdb
commit 41dc5f3aa0
5 changed files with 344 additions and 253 deletions

70
alu.sv
View file

@ -72,7 +72,13 @@ module riscv_alu
end
endgenerate
logic [31:0] operand_b_neg;
assign operand_b_neg = ~operand_b_i;
logic [5:0] div_shift;
logic div_valid;
//////////////////////////////////////////////////////////////////////////////////////////
// ____ _ _ _ _ _ _ _ _ //
@ -92,7 +98,7 @@ module riscv_alu
assign adder_op_a = (operator_i == `ALU_ABS) ? operand_a_neg : operand_a_i;
// prepare operand b
assign adder_op_b = (operator_i == `ALU_SUB) ? ~operand_b_i : operand_b_i;
assign adder_op_b = (operator_i == `ALU_SUB) ? operand_b_neg : operand_b_i;
// prepare carry
always_comb
@ -180,6 +186,8 @@ module riscv_alu
logic [31:0] shift_right_result;
logic [31:0] shift_left_result;
// shifter is also used for preparing operand for divison
assign shift_amt = div_valid ? div_shift : operand_b_i;
// by reversing the bits of the input, we also have to reverse the order of shift amounts
always_comb
@ -208,7 +216,9 @@ module riscv_alu
// `ALU_FL1 and `ALU_CBL are used for the bit counting ops later
assign shift_left = (operator_i == `ALU_SLL) || (operator_i == `ALU_BINS) ||
(operator_i == `ALU_FL1) || (operator_i == `ALU_CLB);
(operator_i == `ALU_FL1) || (operator_i == `ALU_CLB) ||
(operator_i == `ALU_DIV) || (operator_i == `ALU_DIVU) ||
(operator_i == `ALU_REM) || (operator_i == `ALU_REMU);
// choose the bit reversed or the normal input for shift operand a
assign shift_op_a = (shift_left == 1'b1) ? operand_a_rev : operand_a_i;
@ -643,7 +653,8 @@ module riscv_alu
logic [31:0] ff_input; // either op_a_i or its bit reversed version
logic [5:0] cnt_result; // population count
logic [5:0] clb_result; // count leading bits
logic [5:0] clb_result; // count leading bits
logic [5:0] clbu_result; // count leading bits
logic [5:0] ff1_result; // holds the index of the first '1'
logic ff_no_one; // if no ones are found
logic [5:0] fl1_result; // holds the index of the last '1'
@ -661,7 +672,13 @@ module riscv_alu
case (operator_i)
`ALU_FF1: ff_input = operand_a_i;
`ALU_DIVU,
`ALU_REMU,
`ALU_FL1: ff_input = operand_a_rev;
`ALU_DIV,
`ALU_REM,
`ALU_CLB: begin
if (operand_a_i[31])
ff_input = operand_a_neg_rev;
@ -680,8 +697,9 @@ module riscv_alu
// special case if ff1_res is 0 (no 1 found), then we keep the 0
// this is done in the result mux
assign fl1_result = 6'd33 - ff1_result;
assign clb_result = ff1_result - 6'd2;
assign fl1_result = 6'd33 - ff1_result;
assign clb_result = ff1_result - 6'd2;
assign clbu_result = ff1_result - 6'd1; // unsigned case, count one less
always_comb
begin
@ -742,34 +760,45 @@ module riscv_alu
logic [31:0] result_div;
logic div_valid;
logic div_ready;
logic div_signed;
logic div_rem_quot;
logic div_op_a_signed;
logic div_op_b_signed;
logic [5:0] div_shift_int;
assign div_signed = operator_i[0];
assign div_op_a_signed = operand_a_i[31] & div_signed;
assign div_op_b_signed = operand_b_i[31] & div_signed;
assign div_shift_int = (ff_no_one) ? 6'd31 : clb_result;
assign div_shift = div_shift_int + (div_op_a_signed ? 6'd0 : 6'd1);
assign div_valid = (operator_i == `ALU_DIV) || (operator_i == `ALU_DIVU) ||
(operator_i == `ALU_REM) || (operator_i == `ALU_REMU);
assign div_rem_quot = operator_i[1];
assign div_signed = operator_i[0];
// inputs A and B are swapped
riscv_alu_div div_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.Clk_CI ( clk ),
.Rst_RBI ( rst_n ),
.a_i ( operand_a_i ),
.b_i ( operand_b_i ),
.signed_i ( div_signed ),
.rem_quot_i ( div_rem_quot ),
// input IF
.OpA_DI ( operand_b_i ),
.OpB_DI ( shift_left_result ),
.OpBShift_DI ( div_shift ),
.OpBIsZero_SI ( (cnt_result == 0) ),
.result_o ( result_div ),
.OpBSign_SI ( div_op_a_signed ),
.OpCode_SI ( operator_i[1:0] ),
.div_valid_i ( div_valid ),
.div_ready_o ( div_ready ),
.ex_ready_i ( ex_ready_i )
.Res_DO ( result_div ),
// Hand-Shake
.InVld_SI ( div_valid ),
.OutRdy_SI ( ex_ready_i ),
.OutVld_SO ( div_ready )
);
////////////////////////////////////////////////////////
@ -783,7 +812,6 @@ module riscv_alu
always_comb
begin
shift_amt = operand_b_i;
result_o = 'x;
unique case (operator_i)

View file

@ -1,197 +1,214 @@
// Copyright 2016 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
// 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.
// this module produces both the absolute (positive) value and the negative
// value for any input. Both signed and unsigned numbers are supported
module riscv_alu_abs_neg
(
input logic [31:0] in_i, // can be either signed or unsigned
input logic signed_i,
output logic [32:0] abs_o, // needs to be 33 bits wide to allow for -(-2**31)
output logic [32:0] neg_o // needs to be 33 bits wide to allow for -(2**32-1)
);
logic [32:0] in_neg;
assign in_neg = -{(signed_i & in_i[31]), in_i};
assign abs_o = (signed_i & in_i[31]) ? in_neg : {1'b0, in_i};
assign neg_o = (signed_i & in_i[31]) ? {1'b1, in_i} : in_neg;
endmodule
///////////////////////////////////////////////////////////////////////////////
// File : Simple Serial Divider
// Ver : 1.0
// Date : 15.03.2016
///////////////////////////////////////////////////////////////////////////////
//
// Description: this is a simple serial divider for signed integers (int32).
//
///////////////////////////////////////////////////////////////////////////////
//
// Authors : Michael Schaffner (schaffner@iis.ee.ethz.ch)
// Andreas Traber (traber@iis.ee.ethz.ch)
//
///////////////////////////////////////////////////////////////////////////////
module riscv_alu_div
#(
parameter C_WIDTH = 32,
parameter C_LOG_WIDTH = 6
)
(
input logic clk,
input logic rst_n,
input logic [31:0] a_i, // can be either signed or unsigned
input logic [31:0] b_i, // can be either signed or unsigned
input logic signed_i,
input logic rem_quot_i, // 1 for rem, 0 for div
output logic [31:0] result_o,
// handshake
input logic div_valid_i, // valid data available for division
output logic div_ready_o, // set when done or idle
input logic ex_ready_i // if we have to wait for next stage
);
enum logic [1:0] { IDLE, DIV, DIV_DONE } CS, NS;
logic [31:0] quotient_q, quotient_n;
logic [63:0] remainder_q, remainder_n, remainder_int;
logic [31:0] remainder_out;
logic [31:0] quotient_out;
logic [31:0] result_int;
logic [32:0] a_abs;
logic [32:0] a_neg;
logic [32:0] b_abs;
logic [32:0] sub_val;
logic a_is_neg;
logic b_is_neg;
logic result_negate;
logic quot_negate;
logic rem_negate;
logic geq_b;
logic load_r;
logic is_active;
logic [4:0] counter_q, counter_n;
riscv_alu_abs_neg b_abs_neg_i
(
.in_i ( b_i ),
.signed_i ( signed_i ),
.abs_o ( b_abs )
input logic Clk_CI,
input logic Rst_RBI,
// input IF
input logic [C_WIDTH-1:0] OpA_DI,
input logic [C_WIDTH-1:0] OpB_DI,
input logic [C_LOG_WIDTH-1:0] OpBShift_DI,
input logic OpBIsZero_SI,
//
input logic OpBSign_SI, // gate this to 0 in case of unsigned ops
input logic [1:0] OpCode_SI, // 0: udiv, 2: urem, 1: div, 3: rem
// handshake
input logic InVld_SI,
// output IF
input logic OutRdy_SI,
output logic OutVld_SO,
output logic [C_WIDTH-1:0] Res_DO
);
riscv_alu_abs_neg a_abs_neg_i
(
.in_i ( a_i ),
.signed_i ( signed_i ),
///////////////////////////////////////////////////////////////////////////////
// signal declarations
///////////////////////////////////////////////////////////////////////////////
.abs_o ( a_abs )
);
logic [C_WIDTH-1:0] ResReg_DP, ResReg_DN;
logic [C_WIDTH-1:0] AReg_DP, AReg_DN;
logic [C_WIDTH-1:0] BReg_DP, BReg_DN;
logic RemSel_SN, RemSel_SP;
logic CompInv_SN, CompInv_SP;
logic ResInv_SN, ResInv_SP;
logic [C_WIDTH-1:0] AddMux_D;
logic [C_WIDTH-1:0] AddOut_D;
logic [C_WIDTH-1:0] AddTmp_D;
logic [C_WIDTH-1:0] BMux_D;
logic [C_WIDTH-1:0] OutMux_D;
logic [C_LOG_WIDTH-1:0] Cnt_DP, Cnt_DN;
logic CntZero_S;
logic ARegEn_S, BRegEn_S, ResRegEn_S, ABComp_S, PmSel_S, LoadEn_S;
enum logic [1:0] {IDLE, DIVIDE, FINISH} State_SN, State_SP;
///////////////////////////////////////////////////////////////////////////////
// datapath
///////////////////////////////////////////////////////////////////////////////
assign PmSel_S = LoadEn_S & ~(OpCode_SI[0] & (OpA_DI[$high(OpA_DI)] ^ OpBSign_SI));
// muxes
assign AddMux_D = (LoadEn_S) ? OpA_DI : BReg_DP;
// attention: logical shift in case of negative operand B!
assign BMux_D = (LoadEn_S) ? OpB_DI : {CompInv_SP, (BReg_DP[$high(BReg_DP):1])};
assign OutMux_D = (RemSel_SP) ? AReg_DP : {<<{ResReg_DP}};
// invert if necessary
assign Res_DO = (ResInv_SP) ? -$signed(OutMux_D) : OutMux_D;
// main comparator
assign ABComp_S = ((AReg_DP == BReg_DP) | ((AReg_DP > BReg_DP) ^ CompInv_SP)) & ((|AReg_DP) | OpBIsZero_SI);
// main adder
assign AddTmp_D = (LoadEn_S) ? 0 : AReg_DP;
assign AddOut_D = (PmSel_S) ? AddTmp_D + AddMux_D : AddTmp_D - $signed(AddMux_D);
///////////////////////////////////////////////////////////////////////////////
// counter
///////////////////////////////////////////////////////////////////////////////
assign Cnt_DN = (LoadEn_S) ? OpBShift_DI :
(~CntZero_S) ? Cnt_DP - 1 : Cnt_DP;
assign CntZero_S = ~(|Cnt_DP);
///////////////////////////////////////////////////////////////////////////////
// FSM
///////////////////////////////////////////////////////////////////////////////
always_comb
begin
NS = CS;
div_ready_o = 1'b1;
load_r = 1'b0;
is_active = 1'b0;
counter_n = counter_q - 1;
begin : p_fsm
// default
State_SN = State_SP;
case (CS)
OutVld_SO = 1'b0;
LoadEn_S = 1'b0;
ARegEn_S = 1'b0;
BRegEn_S = 1'b0;
ResRegEn_S = 1'b0;
case (State_SP)
/////////////////////////////////
IDLE: begin
div_ready_o = 1'b1;
OutVld_SO = 1'b1;
if (div_valid_i) begin
div_ready_o = 1'b0;
NS = DIV;
load_r = 1'b1;
is_active = 1'b1;
counter_n = 31;
if(InVld_SI) begin
OutVld_SO = 1'b0;
ARegEn_S = 1'b1;
BRegEn_S = 1'b1;
LoadEn_S = 1'b1;
State_SN = DIVIDE;
end
end
/////////////////////////////////
DIVIDE: begin
DIV: begin
div_ready_o = 1'b0;
is_active = 1'b1;
ARegEn_S = ABComp_S;
BRegEn_S = 1'b1;
ResRegEn_S = 1'b1;
if (counter_q == 0) begin
NS = DIV_DONE;
// calculation finished
// one more divide cycle (32nd divide cycle)
if (CntZero_S) begin
State_SN = FINISH;
end
end
/////////////////////////////////
FINISH: begin
OutVld_SO = 1'b1;
// if the next stage was stalled when we finished
DIV_DONE: begin
div_ready_o = 1'b1;
if (ex_ready_i)
NS = IDLE;
if(OutRdy_SI) begin
State_SN = IDLE;
end
end
/////////////////////////////////
default : /* default */ ;
/////////////////////////////////
endcase
end
assign a_is_neg = a_i[31];
assign b_is_neg = b_i[31];
assign quot_negate = ((a_is_neg ^ b_is_neg) && signed_i && (b_i != 0));
assign rem_negate = a_is_neg && signed_i;
///////////////////////////////////////////////////////////////////////////////
// regs
///////////////////////////////////////////////////////////////////////////////
assign geq_b = (remainder_q[63:31] >= b_abs);
// get flags
assign RemSel_SN = (LoadEn_S) ? OpCode_SI[1] : RemSel_SP;
assign CompInv_SN = (LoadEn_S) ? OpBSign_SI : CompInv_SP;
assign ResInv_SN = (LoadEn_S) ? (~OpBIsZero_SI | OpCode_SI[1]) & OpCode_SI[0] & (OpA_DI[$high(OpA_DI)] ^ OpBSign_SI) : ResInv_SP;
always_comb
begin
quotient_n = {quotient_q[30:0], 1'b0};
sub_val = '0;
assign AReg_DN = (ARegEn_S) ? AddOut_D : AReg_DP;
assign BReg_DN = (BRegEn_S) ? BMux_D : BReg_DP;
assign ResReg_DN = (LoadEn_S) ? '0 :
(ResRegEn_S) ? {ABComp_S, ResReg_DP[$high(ResReg_DP):1]} : ResReg_DP;
if (geq_b) begin
sub_val = b_abs;
quotient_n = {quotient_q[30:0], 1'b1};
end
end
always_comb
begin
// add (or actually subtract) and shift left by one
remainder_int[63:32] = remainder_q[63:31] - sub_val;
remainder_int[31: 0] = {remainder_q[30:0], 1'b0};
end
assign remainder_n = load_r ? {31'b0, a_abs} : remainder_int;
//----------------------------------------------------------------------------
// registers
//----------------------------------------------------------------------------
always_ff @(posedge clk, negedge rst_n)
begin
if (~rst_n) begin
quotient_q <= '0;
remainder_q <= '0;
counter_q <= 0;
CS <= IDLE;
always_ff @(posedge Clk_CI or negedge Rst_RBI) begin : p_regs
if(~Rst_RBI) begin
State_SP <= IDLE;
AReg_DP <= '0;
BReg_DP <= '0;
ResReg_DP <= '0;
Cnt_DP <= '0;
RemSel_SP <= 1'b0;
CompInv_SP <= 1'b0;
ResInv_SP <= 1'b0;
end else begin
// only toggle when there is an active request
if (is_active) begin
quotient_q <= quotient_n;
remainder_q <= remainder_n;
counter_q <= counter_n;
end
CS <= NS;
State_SP <= State_SN;
AReg_DP <= AReg_DN;
BReg_DP <= BReg_DN;
ResReg_DP <= ResReg_DN;
Cnt_DP <= Cnt_DN;
RemSel_SP <= RemSel_SN;
CompInv_SP <= CompInv_SN;
ResInv_SP <= ResInv_SN;
end
end
///////////////////////////////////////////////////////////////////////////////
// assertions
///////////////////////////////////////////////////////////////////////////////
//----------------------------------------------------------------------------
// output assignments
//----------------------------------------------------------------------------
`ifndef SYNTHESIS
initial
begin : p_assertions
assert (C_LOG_WIDTH == $clog2(C_WIDTH+1)) else $error("C_LOG_WIDTH must be $clog2(C_WIDTH+1)");
end
`endif
assign quotient_out = quotient_q;
assign remainder_out = remainder_q[63:32];
assign result_int = rem_quot_i ? remainder_out : quotient_out;
assign result_negate = rem_quot_i ? rem_negate : quot_negate;
assign result_o = result_negate ? -result_int : result_int;
endmodule
endmodule // serDiv

View file

@ -55,7 +55,8 @@ module riscv_decoder
output logic [1:0] alu_op_c_mux_sel_o, // operand c selection: reg value or jump target
output logic [1:0] alu_vec_mode_o, // selects between 32 bit, 16 bit and 8 bit vectorial modes
output logic scalar_replication_o, // scalar replication enable
output logic [3:0] immediate_mux_sel_o, // immediate selection for operand b
output logic [0:0] imm_a_mux_sel_o, // immediate selection for operand a
output logic [3:0] imm_b_mux_sel_o, // immediate selection for operand b
output logic [1:0] regc_mux_o, // register c selection: S3, RD or 0
// MUL related control signals
@ -133,7 +134,8 @@ module riscv_decoder
alu_vec_mode_o = `VEC_MODE32;
scalar_replication_o = 1'b0;
regc_mux_o = `REGC_ZERO;
immediate_mux_sel_o = `IMM_I;
imm_a_mux_sel_o = `IMMA_ZERO;
imm_b_mux_sel_o = `IMMB_I;
mult_en = 1'b0;
mult_signed_mode_o = 2'b00;
@ -191,7 +193,7 @@ module riscv_decoder
// Calculate and store PC+4
alu_op_a_mux_sel_o = `OP_A_CURRPC;
alu_op_b_mux_sel_o = `OP_B_IMM;
immediate_mux_sel_o = `IMM_PCINCR;
imm_b_mux_sel_o = `IMMB_PCINCR;
alu_operator_o = `ALU_ADD;
regfile_alu_we = 1'b1;
// Calculate jump target (= PC + UJ imm)
@ -203,7 +205,7 @@ module riscv_decoder
// Calculate and store PC+4
alu_op_a_mux_sel_o = `OP_A_CURRPC;
alu_op_b_mux_sel_o = `OP_B_IMM;
immediate_mux_sel_o = `IMM_PCINCR;
imm_b_mux_sel_o = `IMMB_PCINCR;
alu_operator_o = `ALU_ADD;
regfile_alu_we = 1'b1;
// Calculate jump target (= RS1 + I imm)
@ -268,7 +270,7 @@ module riscv_decoder
if (instr_rdata_i[14] == 1'b0) begin
// offset from immediate
immediate_mux_sel_o = `IMM_S;
imm_b_mux_sel_o = `IMMB_S;
alu_op_b_mux_sel_o = `OP_B_IMM;
end else begin
// offset from register
@ -300,7 +302,7 @@ module riscv_decoder
// offset from immediate
alu_operator_o = `ALU_ADD;
alu_op_b_mux_sel_o = `OP_B_IMM;
immediate_mux_sel_o = `IMM_I;
imm_b_mux_sel_o = `IMMB_I;
// post-increment setup
if (instr_rdata_i[6:0] == `OPCODE_LOAD_POST) begin
@ -368,9 +370,10 @@ module riscv_decoder
//////////////////////////
`OPCODE_LUI: begin // Load Upper Immediate
alu_op_a_mux_sel_o = `OP_A_ZERO;
alu_op_a_mux_sel_o = `OP_A_IMM;
alu_op_b_mux_sel_o = `OP_B_IMM;
immediate_mux_sel_o = `IMM_U;
imm_a_mux_sel_o = `IMMA_ZERO;
imm_b_mux_sel_o = `IMMB_U;
alu_operator_o = `ALU_ADD;
regfile_alu_we = 1'b1;
end
@ -378,14 +381,14 @@ module riscv_decoder
`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;
immediate_mux_sel_o = `IMM_U;
imm_b_mux_sel_o = `IMMB_U;
alu_operator_o = `ALU_ADD;
regfile_alu_we = 1'b1;
end
`OPCODE_OPIMM: begin // Register-Immediate ALU Operations
alu_op_b_mux_sel_o = `OP_B_IMM;
immediate_mux_sel_o = `IMM_I;
imm_b_mux_sel_o = `IMMB_I;
regfile_alu_we = 1'b1;
rega_used_o = 1'b1;
@ -426,11 +429,11 @@ module riscv_decoder
imm_bmask_needed_o = 1'b1;
unique case (instr_rdata_i[14:12])
3'b000: begin alu_operator_o = `ALU_BEXT; immediate_mux_sel_o = `IMM_S2; end
3'b001: begin alu_operator_o = `ALU_BEXTU; immediate_mux_sel_o = `IMM_S2; end
3'b000: begin alu_operator_o = `ALU_BEXT; imm_b_mux_sel_o = `IMMB_S2; end
3'b001: begin alu_operator_o = `ALU_BEXTU; imm_b_mux_sel_o = `IMMB_S2; end
3'b010: begin
alu_operator_o = `ALU_BINS;
immediate_mux_sel_o = `IMM_S2;
imm_b_mux_sel_o = `IMMB_S2;
regc_used_o = 1'b1;
regc_mux_o = `REGC_RD;
end
@ -469,15 +472,39 @@ module riscv_decoder
mult_mac_en = 1'b1;
end
{6'b00_0001, 3'b100}: begin // div
alu_operator_o = `ALU_DIV;
alu_op_a_mux_sel_o = `OP_A_REGB_OR_FWD;
alu_op_b_mux_sel_o = `OP_B_REGC_OR_FWD;
regc_mux_o = `REGC_S1;
regc_used_o = 1'b1;
regb_used_o = 1'b1;
rega_used_o = 1'b0;
alu_operator_o = `ALU_DIV;
end
{6'b00_0001, 3'b101}: begin // divu
alu_op_a_mux_sel_o = `OP_A_REGB_OR_FWD;
alu_op_b_mux_sel_o = `OP_B_REGC_OR_FWD;
regc_mux_o = `REGC_S1;
regc_used_o = 1'b1;
regb_used_o = 1'b1;
rega_used_o = 1'b0;
alu_operator_o = `ALU_DIVU;
end
{6'b00_0001, 3'b110}: begin // rem
alu_op_a_mux_sel_o = `OP_A_REGB_OR_FWD;
alu_op_b_mux_sel_o = `OP_B_REGC_OR_FWD;
regc_mux_o = `REGC_S1;
regc_used_o = 1'b1;
regb_used_o = 1'b1;
rega_used_o = 1'b0;
alu_operator_o = `ALU_REM;
end
{6'b00_0001, 3'b111}: begin // remu
alu_op_a_mux_sel_o = `OP_A_REGB_OR_FWD;
alu_op_b_mux_sel_o = `OP_B_REGC_OR_FWD;
regc_mux_o = `REGC_S1;
regc_used_o = 1'b1;
regb_used_o = 1'b1;
rega_used_o = 1'b0;
alu_operator_o = `ALU_REMU;
end
@ -547,7 +574,7 @@ module riscv_decoder
`OPCODE_VECOP: begin
regfile_alu_we = 1'b1;
rega_used_o = 1'b1;
immediate_mux_sel_o = `IMM_VS;
imm_b_mux_sel_o = `IMMB_VS;
// vector size
if (instr_rdata_i[12])
@ -573,21 +600,21 @@ module riscv_decoder
// now decode the instruction
unique case (instr_rdata_i[31:26])
6'b00000_0: begin alu_operator_o = `ALU_ADD; immediate_mux_sel_o = `IMM_VS; end // pv.add
6'b00001_0: begin alu_operator_o = `ALU_SUB; immediate_mux_sel_o = `IMM_VS; end // pv.sub
6'b00010_0: begin alu_operator_o = `ALU_AVG; immediate_mux_sel_o = `IMM_VS; end // pv.avg
6'b00011_0: begin alu_operator_o = `ALU_AVGU; immediate_mux_sel_o = `IMM_VU; end // pv.avgu
6'b00100_0: begin alu_operator_o = `ALU_MIN; immediate_mux_sel_o = `IMM_VS; end // pv.min
6'b00101_0: begin alu_operator_o = `ALU_MINU; immediate_mux_sel_o = `IMM_VU; end // pv.minu
6'b00110_0: begin alu_operator_o = `ALU_MAX; immediate_mux_sel_o = `IMM_VS; end // pv.max
6'b00111_0: begin alu_operator_o = `ALU_MAXU; immediate_mux_sel_o = `IMM_VU; end // pv.maxu
6'b01000_0: begin alu_operator_o = `ALU_SRL; immediate_mux_sel_o = `IMM_VS; end // pv.srl
6'b01001_0: begin alu_operator_o = `ALU_SRA; immediate_mux_sel_o = `IMM_VS; end // pv.sra
6'b01010_0: begin alu_operator_o = `ALU_SLL; immediate_mux_sel_o = `IMM_VS; end // pv.sll
6'b01011_0: begin alu_operator_o = `ALU_OR; immediate_mux_sel_o = `IMM_VS; end // pv.or
6'b01100_0: begin alu_operator_o = `ALU_XOR; immediate_mux_sel_o = `IMM_VS; end // pv.xor
6'b01101_0: begin alu_operator_o = `ALU_AND; immediate_mux_sel_o = `IMM_VS; end // pv.and
6'b01110_0: begin alu_operator_o = `ALU_ABS; immediate_mux_sel_o = `IMM_VS; end // pv.abs
6'b00000_0: begin alu_operator_o = `ALU_ADD; imm_b_mux_sel_o = `IMMB_VS; end // pv.add
6'b00001_0: begin alu_operator_o = `ALU_SUB; imm_b_mux_sel_o = `IMMB_VS; end // pv.sub
6'b00010_0: begin alu_operator_o = `ALU_AVG; imm_b_mux_sel_o = `IMMB_VS; end // pv.avg
6'b00011_0: begin alu_operator_o = `ALU_AVGU; imm_b_mux_sel_o = `IMMB_VU; end // pv.avgu
6'b00100_0: begin alu_operator_o = `ALU_MIN; imm_b_mux_sel_o = `IMMB_VS; end // pv.min
6'b00101_0: begin alu_operator_o = `ALU_MINU; imm_b_mux_sel_o = `IMMB_VU; end // pv.minu
6'b00110_0: begin alu_operator_o = `ALU_MAX; imm_b_mux_sel_o = `IMMB_VS; end // pv.max
6'b00111_0: begin alu_operator_o = `ALU_MAXU; imm_b_mux_sel_o = `IMMB_VU; end // pv.maxu
6'b01000_0: begin alu_operator_o = `ALU_SRL; imm_b_mux_sel_o = `IMMB_VS; end // pv.srl
6'b01001_0: begin alu_operator_o = `ALU_SRA; imm_b_mux_sel_o = `IMMB_VS; end // pv.sra
6'b01010_0: begin alu_operator_o = `ALU_SLL; imm_b_mux_sel_o = `IMMB_VS; end // pv.sll
6'b01011_0: begin alu_operator_o = `ALU_OR; imm_b_mux_sel_o = `IMMB_VS; end // pv.or
6'b01100_0: begin alu_operator_o = `ALU_XOR; imm_b_mux_sel_o = `IMMB_VS; end // pv.xor
6'b01101_0: begin alu_operator_o = `ALU_AND; imm_b_mux_sel_o = `IMMB_VS; end // pv.and
6'b01110_0: begin alu_operator_o = `ALU_ABS; imm_b_mux_sel_o = `IMMB_VS; end // pv.abs
6'b01111_0: begin // pv.extract
if (instr_rdata_i[12])
@ -613,7 +640,7 @@ module riscv_decoder
// shuffle/pack
6'b11000_0: begin // pv.shuffle
alu_operator_o = `ALU_SHUF;
immediate_mux_sel_o = `IMM_SHUF;
imm_b_mux_sel_o = `IMMB_SHUF;
regb_used_o = 1'b1;
scalar_replication_o = 1'b0;
end
@ -637,16 +664,16 @@ module riscv_decoder
end
// comparisons, always have bit 26 set
6'b00000_1: begin alu_operator_o = `ALU_EQ; immediate_mux_sel_o = `IMM_VS; end // pv.cmpeq
6'b00001_1: begin alu_operator_o = `ALU_NE; immediate_mux_sel_o = `IMM_VS; end // pv.cmpne
6'b00010_1: begin alu_operator_o = `ALU_GTU; immediate_mux_sel_o = `IMM_VS; end // pv.cmpgt
6'b00011_1: begin alu_operator_o = `ALU_GES; immediate_mux_sel_o = `IMM_VS; end // pv.cmpge
6'b00100_1: begin alu_operator_o = `ALU_LTU; immediate_mux_sel_o = `IMM_VS; end // pv.cmplt
6'b00101_1: begin alu_operator_o = `ALU_LES; immediate_mux_sel_o = `IMM_VS; end // pv.cmple
6'b00110_1: begin alu_operator_o = `ALU_GTU; immediate_mux_sel_o = `IMM_VU; end // pv.cmpgtu
6'b00111_1: begin alu_operator_o = `ALU_GEU; immediate_mux_sel_o = `IMM_VU; end // pv.cmpgeu
6'b01000_1: begin alu_operator_o = `ALU_LTU; immediate_mux_sel_o = `IMM_VU; end // pv.cmpltu
6'b01001_1: begin alu_operator_o = `ALU_LEU; immediate_mux_sel_o = `IMM_VU; end // pv.cmpleu
6'b00000_1: begin alu_operator_o = `ALU_EQ; imm_b_mux_sel_o = `IMMB_VS; end // pv.cmpeq
6'b00001_1: begin alu_operator_o = `ALU_NE; imm_b_mux_sel_o = `IMMB_VS; end // pv.cmpne
6'b00010_1: begin alu_operator_o = `ALU_GTU; imm_b_mux_sel_o = `IMMB_VS; end // pv.cmpgt
6'b00011_1: begin alu_operator_o = `ALU_GES; imm_b_mux_sel_o = `IMMB_VS; end // pv.cmpge
6'b00100_1: begin alu_operator_o = `ALU_LTU; imm_b_mux_sel_o = `IMMB_VS; end // pv.cmplt
6'b00101_1: begin alu_operator_o = `ALU_LES; imm_b_mux_sel_o = `IMMB_VS; end // pv.cmple
6'b00110_1: begin alu_operator_o = `ALU_GTU; imm_b_mux_sel_o = `IMMB_VU; end // pv.cmpgtu
6'b00111_1: begin alu_operator_o = `ALU_GEU; imm_b_mux_sel_o = `IMMB_VU; end // pv.cmpgeu
6'b01000_1: begin alu_operator_o = `ALU_LTU; imm_b_mux_sel_o = `IMMB_VU; end // pv.cmpltu
6'b01001_1: begin alu_operator_o = `ALU_LEU; imm_b_mux_sel_o = `IMMB_VU; end // pv.cmpleu
default: illegal_insn_o = 1'b1;
endcase
@ -702,11 +729,12 @@ module riscv_decoder
csr_access_o = 1'b1;
regfile_alu_we = 1'b1;
alu_op_b_mux_sel_o = `OP_B_IMM;
immediate_mux_sel_o = `IMM_I; // CSR address is encoded in I imm
imm_a_mux_sel_o = `IMMA_Z;
imm_b_mux_sel_o = `IMMB_I; // CSR address is encoded in I imm
if (instr_rdata_i[14] == 1'b1) begin
// rs1 field is used as immediate
alu_op_a_mux_sel_o = `OP_A_ZIMM;
alu_op_a_mux_sel_o = `OP_A_IMM;
end else begin
rega_used_o = 1'b1;
alu_op_a_mux_sel_o = `OP_A_REGA_OR_FWD;
@ -802,7 +830,7 @@ module riscv_decoder
// correct operands are sent to the AGU
alu_op_a_mux_sel_o = `OP_A_REGA_OR_FWD;
alu_op_b_mux_sel_o = `OP_B_IMM;
immediate_mux_sel_o = `IMM_PCINCR;
imm_b_mux_sel_o = `IMMB_PCINCR;
// if prepost increments are used, we do not write back the
// second address since the first calculated address was

View file

@ -222,7 +222,8 @@ module riscv_id_stage
logic [31:0] imm_vu_type;
logic [31:0] imm_shuffle_type;
logic [31:0] immediate_b; // contains the immediate for operand b
logic [31:0] imm_a; // contains the immediate for operand b
logic [31:0] imm_b; // contains the immediate for operand b
logic [31:0] jump_target; // calculated jump target (-> EX -> IF)
@ -253,7 +254,8 @@ module riscv_id_stage
logic [1:0] alu_op_c_mux_sel;
logic [1:0] regc_mux;
logic [3:0] immediate_mux_sel;
logic [0:0] imm_a_mux_sel;
logic [3:0] imm_b_mux_sel;
logic [1:0] jump_target_mux_sel;
// Multiplier Control
@ -363,6 +365,7 @@ module riscv_id_stage
`REGC_ZERO: regfile_addr_rc_id = '0;
`REGC_RD: regfile_addr_rc_id = instr[`REG_D];
`REGC_S3: regfile_addr_rc_id = instr[`REG_S3];
`REGC_S1: regfile_addr_rc_id = instr[`REG_S1];
default: regfile_addr_rc_id = '0;
endcase
end
@ -483,13 +486,22 @@ module riscv_id_stage
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_REGB_OR_FWD: alu_operand_a = operand_b_fw_id;
`OP_A_CURRPC: alu_operand_a = pc_id_i;
`OP_A_ZIMM: alu_operand_a = imm_z_type;
`OP_A_ZERO: alu_operand_a = 32'b0;
`OP_A_IMM: alu_operand_a = imm_a;
default: alu_operand_a = operand_a_fw_id;
endcase; // case (alu_op_a_mux_sel)
end
always_comb
begin : immediate_a_mux
unique case (imm_a_mux_sel)
`IMMA_Z: imm_a = imm_z_type;
`IMMA_ZERO: imm_a = '0;
default: imm_a = '0;
endcase
end
// Operand a forwarding mux
always_comb
begin : operand_a_fw_mux
@ -514,19 +526,19 @@ module riscv_id_stage
// TODO: check if sign-extension stuff works well here, maybe able to save
// some area here
always_comb
begin : immediate_mux
unique case (immediate_mux_sel)
`IMM_I: immediate_b = imm_i_type;
`IMM_S: immediate_b = imm_s_type;
`IMM_U: immediate_b = imm_u_type;
`IMM_PCINCR: immediate_b = (is_compressed_i && (~data_misaligned_i)) ? 32'h2 : 32'h4;
`IMM_S2: immediate_b = imm_s2_type;
`IMM_S3: immediate_b = imm_s3_type;
`IMM_VS: immediate_b = imm_vs_type;
`IMM_VU: immediate_b = imm_vu_type;
`IMM_SHUF: immediate_b = imm_shuffle_type;
default: immediate_b = imm_i_type;
endcase; // case (immediate_mux_sel)
begin : immediate_b_mux
unique 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'h2 : 32'h4;
`IMMB_S2: imm_b = imm_s2_type;
`IMMB_S3: imm_b = imm_s3_type;
`IMMB_VS: imm_b = imm_vs_type;
`IMMB_VU: imm_b = imm_vu_type;
`IMMB_SHUF: imm_b = imm_shuffle_type;
default: imm_b = imm_i_type;
endcase
end
// ALU_Op_b Mux
@ -535,7 +547,7 @@ module riscv_id_stage
case (alu_op_b_mux_sel)
`OP_B_REGB_OR_FWD: operand_b = operand_b_fw_id;
`OP_B_REGC_OR_FWD: operand_b = operand_c_fw_id;
`OP_B_IMM: operand_b = immediate_b;
`OP_B_IMM: operand_b = imm_b;
default: operand_b = operand_b_fw_id;
endcase // case (alu_op_b_mux_sel)
end
@ -686,7 +698,8 @@ module riscv_id_stage
.alu_op_c_mux_sel_o ( alu_op_c_mux_sel ),
.alu_vec_mode_o ( alu_vec_mode ),
.scalar_replication_o ( scalar_replication ),
.immediate_mux_sel_o ( immediate_mux_sel ),
.imm_a_mux_sel_o ( imm_a_mux_sel ),
.imm_b_mux_sel_o ( imm_b_mux_sel ),
.regc_mux_o ( regc_mux ),
// MUL signals

View file

@ -29,7 +29,7 @@
// no traces for synthesis, they are not synthesizable
`ifndef SYNTHESIS
`define TRACE_EXECUTION
`define SIMCHECKER
//`define SIMCHECKER
`endif
@ -76,6 +76,7 @@
`define REGC_ZERO 2'b00
`define REGC_RD 2'b01
`define REGC_S3 2'b10
`define REGC_S1 2'b11
//////////////////////////////////////////////////////////////////////////////
@ -218,24 +219,28 @@
// operand a selection
`define OP_A_REGA_OR_FWD 2'b00
`define OP_A_CURRPC 2'b01
`define OP_A_ZIMM 2'b10
`define OP_A_ZERO 2'b11
`define OP_A_IMM 2'b10
`define OP_A_REGB_OR_FWD 2'b11
// immediate b selection
`define IMMA_Z 1'b0
`define IMMA_ZERO 1'b1
// operand b selection
`define OP_B_REGB_OR_FWD 2'b00
`define OP_B_REGC_OR_FWD 2'b01
`define OP_B_IMM 2'b10
// operand b immediate selection
`define IMM_I 4'b0000
`define IMM_S 4'b0001
`define IMM_U 4'b0010
`define IMM_PCINCR 4'b0011
`define IMM_S2 4'b0100
`define IMM_S3 4'b0101
`define IMM_VS 4'b0110
`define IMM_VU 4'b0111
`define IMM_SHUF 4'b1000
// immediate b selection
`define IMMB_I 4'b0000
`define IMMB_S 4'b0001
`define IMMB_U 4'b0010
`define IMMB_PCINCR 4'b0011
`define IMMB_S2 4'b0100
`define IMMB_S3 4'b0101
`define IMMB_VS 4'b0110
`define IMMB_VU 4'b0111
`define IMMB_SHUF 4'b1000
// operand c selection
`define OP_C_REGC_OR_FWD 2'b00