blob: 5b37edd645c0d656b969ae857b8a9111692599b3 [file] [log] [blame]
// Copyright 2019 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: Stefan Mach <smach@iis.ee.ethz.ch>
module fpnew_top #(
// FPU configuration
parameter fpnew_pkg::fpu_features_t Features = fpnew_pkg::RV64D_Xsflt,
parameter fpnew_pkg::fpu_implementation_t Implementation = fpnew_pkg::DEFAULT_NOREGS,
parameter type TagType = logic,
// Do not change
localparam int unsigned WIDTH = Features.Width,
localparam int unsigned NUM_OPERANDS = 3
) (
input logic clk_i,
input logic rst_ni,
// Input signals
input logic [NUM_OPERANDS-1:0][WIDTH-1:0] operands_i,
input fpnew_pkg::roundmode_e rnd_mode_i,
input fpnew_pkg::operation_e op_i,
input logic op_mod_i,
input fpnew_pkg::fp_format_e src_fmt_i,
input fpnew_pkg::fp_format_e dst_fmt_i,
input fpnew_pkg::int_format_e int_fmt_i,
input logic vectorial_op_i,
input TagType tag_i,
// Input Handshake
input logic in_valid_i,
output logic in_ready_o,
input logic flush_i,
// Output signals
output logic [WIDTH-1:0] result_o,
output fpnew_pkg::status_t status_o,
output TagType tag_o,
// Output handshake
output logic out_valid_o,
input logic out_ready_i,
// Indication of valid data in flight
output logic busy_o
);
localparam int unsigned NUM_OPGROUPS = fpnew_pkg::NUM_OPGROUPS;
localparam int unsigned NUM_FORMATS = fpnew_pkg::NUM_FP_FORMATS;
// ----------------
// Type Definition
// ----------------
typedef struct packed {
logic [WIDTH-1:0] result;
fpnew_pkg::status_t status;
TagType tag;
} output_t;
// Handshake signals for the blocks
logic [NUM_OPGROUPS-1:0] opgrp_in_ready, opgrp_out_valid, opgrp_out_ready, opgrp_ext, opgrp_busy;
output_t [NUM_OPGROUPS-1:0] opgrp_outputs;
logic [NUM_FORMATS-1:0][NUM_OPERANDS-1:0] is_boxed;
// -----------
// Input Side
// -----------
assign in_ready_o = in_valid_i & opgrp_in_ready[fpnew_pkg::get_opgroup(op_i)];
// NaN-boxing check
for (genvar fmt = 0; fmt < int'(NUM_FORMATS); fmt++) begin : gen_nanbox_check
localparam int unsigned FP_WIDTH = fpnew_pkg::fp_width(fpnew_pkg::fp_format_e'(fmt));
// NaN boxing is only generated if it's enabled and needed
if (Features.EnableNanBox && (FP_WIDTH < WIDTH)) begin : check
for (genvar op = 0; op < int'(NUM_OPERANDS); op++) begin : operands
assign is_boxed[fmt][op] = (!vectorial_op_i)
? operands_i[op][WIDTH-1:FP_WIDTH] == '1
: 1'b1;
end
end else begin : no_check
assign is_boxed[fmt] = '1;
end
end
// -------------------------
// Generate Operation Blocks
// -------------------------
for (genvar opgrp = 0; opgrp < int'(NUM_OPGROUPS); opgrp++) begin : gen_operation_groups
localparam int unsigned NUM_OPS = fpnew_pkg::num_operands(fpnew_pkg::opgroup_e'(opgrp));
logic in_valid;
logic [NUM_FORMATS-1:0][NUM_OPS-1:0] input_boxed;
assign in_valid = in_valid_i & (fpnew_pkg::get_opgroup(op_i) == fpnew_pkg::opgroup_e'(opgrp));
// slice out input boxing
always_comb begin : slice_inputs
for (int unsigned fmt = 0; fmt < NUM_FORMATS; fmt++)
input_boxed[fmt] = is_boxed[fmt][NUM_OPS-1:0];
end
fpnew_opgroup_block #(
.OpGroup ( fpnew_pkg::opgroup_e'(opgrp) ),
.Width ( WIDTH ),
.EnableVectors ( Features.EnableVectors ),
.FpFmtMask ( Features.FpFmtMask ),
.IntFmtMask ( Features.IntFmtMask ),
.FmtPipeRegs ( Implementation.PipeRegs[opgrp] ),
.FmtUnitTypes ( Implementation.UnitTypes[opgrp] ),
.PipeConfig ( Implementation.PipeConfig ),
.TagType ( TagType )
) i_opgroup_block (
.clk_i,
.rst_ni,
.operands_i ( operands_i[NUM_OPS-1:0] ),
.is_boxed_i ( input_boxed ),
.rnd_mode_i,
.op_i,
.op_mod_i,
.src_fmt_i,
.dst_fmt_i,
.int_fmt_i,
.vectorial_op_i,
.tag_i,
.in_valid_i ( in_valid ),
.in_ready_o ( opgrp_in_ready[opgrp] ),
.flush_i,
.result_o ( opgrp_outputs[opgrp].result ),
.status_o ( opgrp_outputs[opgrp].status ),
.extension_bit_o ( opgrp_ext[opgrp] ),
.tag_o ( opgrp_outputs[opgrp].tag ),
.out_valid_o ( opgrp_out_valid[opgrp] ),
.out_ready_i ( opgrp_out_ready[opgrp] ),
.busy_o ( opgrp_busy[opgrp] )
);
end
// ------------------
// Arbitrate Outputs
// ------------------
output_t arbiter_output;
// Round-Robin arbiter to decide which result to use
rr_arb_tree #(
.NumIn ( NUM_OPGROUPS ),
.DataType ( output_t ),
.AxiVldRdy ( 1'b1 )
) i_arbiter (
.clk_i,
.rst_ni,
.flush_i,
.rr_i ( '0 ),
.req_i ( opgrp_out_valid ),
.gnt_o ( opgrp_out_ready ),
.data_i ( opgrp_outputs ),
.gnt_i ( out_ready_i ),
.req_o ( out_valid_o ),
.data_o ( arbiter_output ),
.idx_o ( /* unused */ )
);
// Unpack output
assign result_o = arbiter_output.result;
assign status_o = arbiter_output.status;
assign tag_o = arbiter_output.tag;
assign busy_o = (| opgrp_busy);
endmodule