multiplier.sv 3.87 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
// 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
//

import ariane_pkg::*;

module multiplier (
    input  logic                     clk_i,
    input  logic                     rst_ni,
    input  logic [TRANS_ID_BITS-1:0] trans_id_i,
    input  logic                     mult_valid_i,
    input  fu_op                     operator_i,
    input  logic [63:0]              operand_a_i,
    input  logic [63:0]              operand_b_i,
    output logic [63:0]              result_o,
    output logic                     mult_valid_o,
    output logic                     mult_ready_o,
    output logic [TRANS_ID_BITS-1:0] mult_trans_id_o
);
    // Pipeline register
    logic [TRANS_ID_BITS-1:0]    trans_id_q;
    logic                        mult_valid_q;
    fu_op                        operator_d, operator_q;
    logic [127: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_ready_o    = 1'b1;

    assign mult_valid      = mult_valid_i && (operator_i inside {MUL, MULH, MULHU, MULHSU, MULW});
    // datapath
    logic [127:0] mult_result;
    assign mult_result   = $signed({operand_a_i[63] & sign_a, operand_a_i}) * $signed({operand_b_i[63] & sign_b, operand_b_i});

    // Sign Select MUX
    always_comb begin
        sign_a = 1'b0;
        sign_b = 1'b0;

        // signed multiplication
        if (operator_i == MULH) begin
            sign_a   = 1'b1;
            sign_b   = 1'b1;
        // signed - unsigned multiplication
        end else if (operator_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[63] & sign_a, operand_a_i}) *
                             $signed({operand_b_i[63] & sign_b, operand_b_i});


    assign operator_d = operator_i;
    always_comb begin : p_selmux
        unique case (operator_q)
            MULH, MULHU, MULHSU: result_o = mult_result_q[127:64];
            MULW:                result_o = sext32(mult_result_q[31:0]);
            // MUL performs an XLEN-bit×XLEN-bit multiplication and places the lower XLEN bits in the destination register
            default:             result_o = mult_result_q[63:0];// including MUL
        endcase
    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