Basic mulh implementation in 4 cycles

This commit is contained in:
Andreas Traber 2016-04-13 12:40:56 +02:00
parent 3a96261dac
commit 5839e120bd
3 changed files with 143 additions and 27 deletions

View file

@ -100,6 +100,7 @@ module riscv_ex_stage
logic alu_cmp_result;
logic alu_ready;
logic mult_ready;
// EX stage result mux (ALU, MAC unit, CSR)
@ -160,22 +161,29 @@ module riscv_ex_stage
riscv_mult mult_i
(
.operator_i ( mult_operator_i ),
.clk ( clk ),
.rst_n ( rst_n ),
.short_subword_i ( mult_sel_subword_i ),
.short_signed_i ( mult_signed_mode_i ),
.enable_i ( mult_en_i ),
.operator_i ( mult_operator_i ),
.op_a_i ( mult_operand_a_i ),
.op_b_i ( mult_operand_b_i ),
.op_c_i ( mult_operand_c_i ),
.imm_i ( mult_imm_i ),
.short_subword_i ( mult_sel_subword_i ),
.short_signed_i ( mult_signed_mode_i ),
.dot_op_a_i ( mult_dot_op_a_i ),
.dot_op_b_i ( mult_dot_op_b_i ),
.dot_op_c_i ( mult_dot_op_c_i ),
.dot_signed_i ( mult_dot_signed_i ),
.op_a_i ( mult_operand_a_i ),
.op_b_i ( mult_operand_b_i ),
.op_c_i ( mult_operand_c_i ),
.imm_i ( mult_imm_i ),
.result_o ( mult_result )
.dot_op_a_i ( mult_dot_op_a_i ),
.dot_op_b_i ( mult_dot_op_b_i ),
.dot_op_c_i ( mult_dot_op_c_i ),
.dot_signed_i ( mult_dot_signed_i ),
.result_o ( mult_result ),
.ready_o ( mult_ready ),
.ex_ready_i ( ex_ready_o )
);
@ -208,7 +216,7 @@ module riscv_ex_stage
// As valid always goes to the right and ready to the left, and we are able
// to finish branches without going to the WB stage, ex_valid does not
// depend on ex_ready.
assign ex_ready_o = (alu_ready & lsu_ready_ex_i & wb_ready_i) | branch_in_ex_i;
assign ex_valid_o = (alu_ready & lsu_ready_ex_i & wb_ready_i);
assign ex_ready_o = (alu_ready & mult_ready & lsu_ready_ex_i & wb_ready_i) | branch_in_ex_i;
assign ex_valid_o = (alu_ready & mult_ready & lsu_ready_ex_i & wb_ready_i);
endmodule

View file

@ -177,6 +177,7 @@
`define MUL_IR 3'b011
`define MUL_DOT8 3'b100
`define MUL_DOT16 3'b101
`define MUL_H 3'b110
// vector modes
`define VEC_MODE32 2'b00

133
mult.sv
View file

@ -27,6 +27,10 @@
module riscv_mult
(
input logic clk,
input logic rst_n,
input logic enable_i,
input logic [ 2:0] operator_i,
// integer and short multiplier
@ -46,10 +50,13 @@ module riscv_mult
input logic [31:0] dot_op_b_i,
input logic [31:0] dot_op_c_i,
output logic [31:0] result_o
output logic [31:0] result_o,
output logic ready_o,
input logic ex_ready_i
);
//////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
// ___ _ _ _____ ___ ___ ___ ___ __ __ _ _ _ _____ //
// |_ _| \| |_ _| __/ __| __| _ \ | \/ | | | | ||_ _| //
// | || .` | | | | _| (_ | _|| / | |\/| | |_| | |__| | //
@ -59,25 +66,113 @@ module riscv_mult
logic [16:0] short_op_a;
logic [16:0] short_op_b;
logic [32:0] short_op_c;
logic [33:0] short_mac;
logic [31:0] short_round, short_round_tmp;
logic [31:0] short_result;
logic [33:0] short_result;
logic [ 4:0] short_imm;
logic [ 1:0] short_subword;
logic [ 1:0] short_signed;
logic short_signed_shift;
logic [ 4:0] mulh_imm;
logic [ 1:0] mulh_subword;
logic [ 1:0] mulh_signed;
logic mulh_signed_shift;
logic [32:0] mulh_intermediate_q;
logic mulh_active;
logic mulh_save;
logic mulh_ready;
enum logic [1:0] {IDLE, STEP1, STEP2, FINISH} mulh_CS, mulh_NS;
// prepare the rounding value
assign short_round_tmp = (32'h00000001) << imm_i;
assign short_round = (operator_i == `MUL_IR) ? {1'b0, short_round_tmp[31:1]} : '0;
// perform subword selection and sign extensions
assign short_op_a[15:0] = short_subword_i ? op_a_i[31:16] : op_a_i[15:0];
assign short_op_b[15:0] = short_subword_i ? op_b_i[31:16] : op_b_i[15:0];
assign short_op_a[15:0] = short_subword[0] ? op_a_i[31:16] : op_a_i[15:0];
assign short_op_b[15:0] = short_subword[1] ? op_b_i[31:16] : op_b_i[15:0];
assign short_op_a[16] = short_signed_i & short_op_a[15];
assign short_op_b[16] = short_signed_i & short_op_b[15];
assign short_op_a[16] = short_signed[0] & short_op_a[15];
assign short_op_b[16] = short_signed[1] & short_op_b[15];
assign short_mac = $signed(op_c_i) + $signed(short_op_a) * $signed(short_op_b) + $signed(short_round);
assign short_op_c = mulh_active ? mulh_intermediate_q : {1'b0, op_c_i};
assign short_result = $signed({(short_signed_i & short_mac[31]), short_mac[31:0]}) >>> imm_i;
assign short_mac = $signed(short_op_c) + $signed(short_op_a) * $signed(short_op_b) + $signed(short_round);
assign short_result = $signed({(short_signed_shift & short_mac[31]), short_mac[31:0]}) >>> short_imm;
// choose between normal short multiplication operation and mulh operation
assign short_imm = mulh_active ? mulh_imm : imm_i;
assign short_subword = mulh_active ? mulh_subword : {2{short_subword_i}};
assign short_signed = mulh_active ? mulh_signed : {2{short_signed_i}};
assign short_signed_shift = mulh_active ? mulh_signed_shift : short_signed_i;
always_comb
begin
mulh_NS = mulh_CS;
mulh_imm = 5'd0;
mulh_subword = 2'b00;
mulh_signed = 2'b00;
mulh_signed_shift = 1'b1;
mulh_ready = 1'b0;
mulh_active = 1'b1;
mulh_save = 1'b0;
case (mulh_CS)
IDLE: begin
mulh_imm = 5'd16;
mulh_signed_shift = 1'b0;
mulh_ready = 1'b1;
mulh_active = 1'b0;
if ((operator_i == `MUL_H) && enable_i) begin
mulh_ready = 1'b0;
mulh_active = 1'b1;
mulh_save = 1'b1;
mulh_NS = STEP1;
end
end
STEP1: begin
mulh_subword = 2'b01;
mulh_signed = 2'b01;
mulh_save = 1'b1;
mulh_NS = STEP2;
end
STEP2: begin
mulh_subword = 2'b10;
mulh_signed = 2'b10;
mulh_imm = 5'd16;
mulh_save = 1'b1;
mulh_NS = FINISH;
end
FINISH: begin
mulh_subword = 2'b11;
mulh_signed = 2'b11;
mulh_ready = 1'b1;
if (ex_ready_i)
mulh_NS = IDLE;
end
endcase
end
always_ff @(posedge clk, negedge rst_n)
begin
if (~rst_n)
begin
mulh_CS <= IDLE;
mulh_intermediate_q <= '0;
end else begin
mulh_CS <= mulh_NS;
if (mulh_save)
mulh_intermediate_q <= short_result;
end
end
// 32x32 = 32-bit multiplier
logic [31:0] int_op_a_msu;
@ -158,14 +253,26 @@ module riscv_mult
result_o = 'x;
unique case (operator_i)
`MUL_MAC32, `MUL_MSU32: result_o = int_result;
`MUL_MAC32, `MUL_MSU32: result_o = int_result[31:0];
`MUL_I, `MUL_IR: result_o = short_result;
`MUL_I, `MUL_IR, `MUL_H: result_o = short_result[31:0];
`MUL_DOT8: result_o = dot_char_result;
`MUL_DOT16: result_o = dot_short_result;
`MUL_DOT8: result_o = dot_char_result[31:0];
`MUL_DOT16: result_o = dot_short_result[31:0];
default: ; // default case to suppress unique warning
endcase
end
assign ready_o = mulh_ready;
//----------------------------------------------------------------------------
// Assertions
//----------------------------------------------------------------------------
// check multiplication result for mulh
assert property (
@(posedge clk) (mulh_CS == FINISH)
|->
(result_o == (($signed({{32{op_a_i[31]}}, op_a_i}) * $signed({{32{op_b_i[31]}}, op_b_i})) >>> 32) ) );
endmodule