cva6/core/multiplier.sv
Guillaume Chauvon 3ce44b1b4e
Some checks are pending
bender-up-to-date / bender-up-to-date (push) Waiting to run
ci / build-riscv-tests (push) Waiting to run
ci / execute-riscv64-tests (push) Blocked by required conditions
ci / execute-riscv32-tests (push) Blocked by required conditions
Spyglass clean up: multiple change to remove Spyglass warnings (#2727)
Multiple changes to clean up code and remove Spyglass warnings.

Co-authored-by: JeanRochCoulon <jean-roch.coulon@thalesgroup.com>
2025-01-23 08:32:31 +01:00

166 lines
5.6 KiB
Systemverilog
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2018 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.
//
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
//
// Description: Multiplication Unit with one pipeline register
// This unit relies on retiming features of the synthesizer
//
module multiplier
import ariane_pkg::*;
#(
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty
) (
// Subsystem Clock - SUBSYSTEM
input logic clk_i,
// Asynchronous reset active low - SUBSYSTEM
input logic rst_ni,
// Multiplier transaction ID - Mult
input logic [CVA6Cfg.TRANS_ID_BITS-1:0] trans_id_i,
// Multiplier instruction is valid - Mult
input logic mult_valid_i,
// Multiplier operation - Mult
input fu_op operation_i,
// A operand - Mult
input logic [ CVA6Cfg.XLEN-1:0] operand_a_i,
// B operand - Mult
input logic [ CVA6Cfg.XLEN-1:0] operand_b_i,
// Multiplier result - Mult
output logic [ CVA6Cfg.XLEN-1:0] result_o,
// Mutliplier result is valid - Mult
output logic mult_valid_o,
// Multiplier transaction ID - Mult
output logic [CVA6Cfg.TRANS_ID_BITS-1:0] mult_trans_id_o
);
// Carry-less multiplication
logic [CVA6Cfg.XLEN-1:0]
clmul_q, clmul_d, clmulr_q, clmulr_d, operand_a, operand_b, operand_a_rev, operand_b_rev;
logic clmul_rmode, clmul_hmode;
if (CVA6Cfg.RVB) begin : gen_bitmanip
// checking for clmul_rmode and clmul_hmode
assign clmul_rmode = (operation_i == CLMULR);
assign clmul_hmode = (operation_i == CLMULH);
// operand_a and b reverse generator
for (genvar i = 0; i < CVA6Cfg.XLEN; i++) begin
assign operand_a_rev[i] = operand_a_i[(CVA6Cfg.XLEN-1)-i];
assign operand_b_rev[i] = operand_b_i[(CVA6Cfg.XLEN-1)-i];
end
// operand_a and operand_b selection
assign operand_a = (clmul_rmode | clmul_hmode) ? operand_a_rev : operand_a_i;
assign operand_b = (clmul_rmode | clmul_hmode) ? operand_b_rev : operand_b_i;
// implementation
always_comb begin
clmul_d = '0;
for (int i = 0; i <= CVA6Cfg.XLEN; i++) begin
clmul_d = (|((operand_b >> i) & 1)) ? clmul_d ^ (operand_a << i) : clmul_d;
end
end
// clmulr + clmulh result generator
for (genvar i = 0; i < CVA6Cfg.XLEN; i++) begin
assign clmulr_d[i] = clmul_d[(CVA6Cfg.XLEN-1)-i];
end
end
// Pipeline register
logic [CVA6Cfg.TRANS_ID_BITS-1:0] trans_id_q;
logic mult_valid_q;
fu_op operator_d, operator_q;
logic [CVA6Cfg.XLEN*2-1:0] mult_result_d, mult_result_q;
// control registers
logic sign_a, sign_b;
logic mult_valid;
// control signals
assign mult_valid_o = mult_valid_q;
assign mult_trans_id_o = trans_id_q;
assign mult_valid = mult_valid_i && (operation_i inside {MUL, MULH, MULHU, MULHSU, MULW, CLMUL, CLMULH, CLMULR});
// Sign Select MUX
always_comb begin
sign_a = 1'b0;
sign_b = 1'b0;
// signed multiplication
if (operation_i == MULH) begin
sign_a = 1'b1;
sign_b = 1'b1;
// signed - unsigned multiplication
end else if (operation_i == MULHSU) begin
sign_a = 1'b1;
// unsigned multiplication
end else begin
sign_a = 1'b0;
sign_b = 1'b0;
end
end
// single stage version
assign mult_result_d = $signed(
{operand_a_i[CVA6Cfg.XLEN-1] & sign_a, operand_a_i}
) * $signed(
{operand_b_i[CVA6Cfg.XLEN-1] & sign_b, operand_b_i}
);
assign operator_d = operation_i;
always_comb begin : p_selmux
unique case (operator_q)
MULH, MULHU, MULHSU: result_o = mult_result_q[CVA6Cfg.XLEN*2-1:CVA6Cfg.XLEN];
CLMUL: result_o = clmul_q;
CLMULH: result_o = clmulr_q >> 1;
CLMULR: result_o = clmulr_q;
// MUL performs an CVA6Cfg.XLEN-bit×CVA6Cfg.XLEN-bit multiplication and places the lower CVA6Cfg.XLEN bits in the destination register
default: begin
if (operator_q == MULW && CVA6Cfg.IS_XLEN64) result_o = sext32to64(mult_result_q[31:0]);
else result_o = mult_result_q[CVA6Cfg.XLEN-1:0]; // including MUL
end
endcase
end
if (CVA6Cfg.RVB) begin
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
clmul_q <= '0;
clmulr_q <= '0;
end else begin
clmul_q <= clmul_d;
clmulr_q <= clmulr_d;
end
end
end
// -----------------------
// Output pipeline register
// -----------------------
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
mult_valid_q <= '0;
trans_id_q <= '0;
operator_q <= MUL;
mult_result_q <= '0;
end else begin
// Input silencing
trans_id_q <= trans_id_i;
// Output Register
mult_valid_q <= mult_valid;
operator_q <= operator_d;
mult_result_q <= mult_result_d;
end
end
endmodule