blob: 16d61fdbe08a58ecf82495d2035d42ce079bd422 [file] [log] [blame]
// SPDX-FileCopyrightText: 2020 Efabless Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the 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.
// SPDX-License-Identifier: Apache-2.0
module multiplier #(parameter exp_width = 8, parameter mant_width = 24)
(
input wire [(exp_width + mant_width-1):0] a,
input wire [(exp_width + mant_width-1):0] b,
input wire [2:0] round_mode,
output wire [4:0] exceptions,
output wire [(exp_width + mant_width)-1:0] out
);
localparam norm_dis_width = 5;
wire sign_a, sign_b, sign_res;
wire exp_a_zero, mant_a_zero, exp_b_zero, mant_b_zero;
wire is_a_zero , is_a_special,is_b_zero , is_b_special;
wire is_out_inf, is_out_zero, is_out_NaN;
wire invalid_excep, infinite_excep;
wire [9:0] check_a, check_b;
wire [exp_width:0] adj_exp_a, adj_exp_b;
wire [exp_width:0] expa, expb;
wire [(exp_width-1):0] exp_a, exp_b;
wire [(mant_width-2):0] mant_a, mant_b;
wire [(mant_width-2):0] subnorm_mant_a, subnorm_mant_b;
wire [(norm_dis_width - 1):0] norm_dist_a, norm_dist_b;
wire [(exp_width+mant_width):0] oper1, oper2;
wire sign_oper1, sign_oper2;
wire [exp_width:0] exp_oper1, exp_oper2;
wire [(mant_width-2):0] mant_oper1, mant_oper2;
wire [mant_width:0] mant_1, mant_2;
wire signed [(exp_width+1):0] sexp_1, sexp_2;
wire signed [(exp_width+1):0] exp_unbais;
wire [(mant_width*2-1):0] mant_prod;
wire [(mant_width+2):0] prod_comp;
wire is_zero_oper1, is_zero_oper2;
assign {sign_a, exp_a, mant_a} = a;
assign {sign_b, exp_b, mant_b} = b;
special_check #(exp_width, mant_width) spec_check_a (.in(a), .result(check_a));
special_check #(exp_width, mant_width) spec_check_b (.in(b), .result(check_b));
assign exp_a_zero = (exp_a == 0);
assign exp_b_zero = (exp_b == 0);
assign mant_a_zero = (mant_a == 0);
assign mant_b_zero = (mant_b == 0);
lead_zero_param #(mant_width-1, norm_dis_width) norm_a (mant_a, norm_dist_a);
lead_zero_param #(mant_width-1, norm_dis_width) norm_b (mant_b, norm_dist_b);
assign subnorm_mant_a = (mant_a<<norm_dist_a)<<1;
assign subnorm_mant_b = (mant_b<<norm_dist_b)<<1;
assign adj_exp_a = (exp_a_zero ? norm_dist_a ^ ((1<<(exp_width + 1)) - 1) : exp_a)
+ ((1<<(exp_width - 1)) | (exp_a_zero ? 2 : 1));
assign adj_exp_b = (exp_b_zero ? norm_dist_b ^ ((1<<(exp_width + 1)) - 1) : exp_b)
+ ((1<<(exp_width - 1)) | (exp_b_zero ? 2 : 1));
assign is_a_zero = exp_a_zero && mant_a_zero;
assign is_b_zero = exp_b_zero && mant_b_zero;
assign is_a_special = (adj_exp_a[exp_width:(exp_width - 1)] == 'b11);
assign is_b_special = (adj_exp_b[exp_width:(exp_width - 1)] == 'b11);
assign expa[exp_width:(exp_width-2)] = is_a_special ? {2'b11, !mant_a_zero} : is_a_zero ? 3'b000
: adj_exp_a[exp_width:(exp_width - 2)];
assign expa[(exp_width - 3):0] = adj_exp_a;
assign expb[exp_width:(exp_width-2)] = is_b_special ? {2'b11, !mant_b_zero} : is_b_zero ? 3'b000
: adj_exp_b[exp_width:(exp_width - 2)];
assign expb[(exp_width - 3):0] = adj_exp_b;
assign oper1 = {sign_a, expa, exp_a_zero ? subnorm_mant_a : mant_a};
assign oper2 = {sign_b, expb, exp_b_zero ? subnorm_mant_b : mant_b};
assign {sign_oper1, exp_oper1, mant_oper1} = oper1;
assign {sign_oper2, exp_oper2, mant_oper2} = oper2;
assign is_zero_oper1 = (exp_oper1>>(exp_width - 2) == 'b000);
assign is_zero_oper2 = (exp_oper2>>(exp_width - 2) == 'b000);
assign sexp_1 = exp_oper1;
assign sexp_2 = exp_oper2;
assign mant_1 = {1'b0, !is_zero_oper1, mant_oper1};
assign mant_2 = {1'b0, !is_zero_oper2, mant_oper2};
assign infinite_excep = 1'b0;
assign invalid_excep = check_a[8] || check_b [8] || ((check_a[7] || check_a[0])
&& (check_b[4] || check_b [3])) || ((check_b[7] || check_b[0])
&& (check_a[4] || check_a[3]));
assign is_out_inf = check_a[7] || check_a[0] || check_b[7] || check_b [0];
assign is_out_zero = check_a[4] || check_a[3] || check_b[4] || check_b [3];
assign is_out_NaN = check_a[9] || check_b[9];
assign sign_res = sign_a ^ sign_b;
assign exp_unbais = sexp_1 + sexp_2 - (1<<exp_width);
assign mant_prod = mant_1 * mant_2;
assign prod_comp = {mant_prod[(mant_width*2 - 1):(mant_width - 2)], |mant_prod[(mant_width - 3):0]};
round_excep #(exp_width, mant_width+2, exp_width,mant_width,0) round_exception
( .invalid_excep(invalid_excep), .infinite_excep(infinite_excep), .in_is_NaN(is_out_NaN),
.in_is_inf(is_out_inf), .in_is_zero(is_out_zero),.in_sign(sign_res),.in_sexp(exp_unbais),
.in_mant(prod_comp),.round_mode(round_mode), .result(out), .exceptions(exceptions));
endmodule