aboutsummaryrefslogtreecommitdiff
path: root/rtl/modexpng_dsp_slice_addsub_wrapper_generic.v
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/modexpng_dsp_slice_addsub_wrapper_generic.v')
-rw-r--r--rtl/modexpng_dsp_slice_addsub_wrapper_generic.v224
1 files changed, 224 insertions, 0 deletions
diff --git a/rtl/modexpng_dsp_slice_addsub_wrapper_generic.v b/rtl/modexpng_dsp_slice_addsub_wrapper_generic.v
new file mode 100644
index 0000000..0ef45fe
--- /dev/null
+++ b/rtl/modexpng_dsp_slice_addsub_wrapper_generic.v
@@ -0,0 +1,224 @@
+//======================================================================
+//
+// Copyright (c) 2019, NORDUnet A/S All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// - Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may
+// be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module modexpng_dsp_slice_addsub_wrapper_generic
+(
+ clk,
+ ce_abc,
+ ce_p,
+ ce_ctrl,
+ x, y, p,
+ op_mode,
+ alu_mode,
+ carry_in_sel,
+ casc_p_in,
+ casc_p_out,
+ carry_out
+);
+
+ `include "modexpng_dsp48e1.vh"
+
+ input clk;
+ input ce_abc;
+ input ce_p;
+ input ce_ctrl;
+ input [ DSP48E1_C_W -1:0] x;
+ input [ DSP48E1_C_W -1:0] y;
+ output [ DSP48E1_P_W -1:0] p;
+ input [ DSP48E1_OPMODE_W -1:0] op_mode;
+ input [ DSP48E1_ALUMODE_W -1:0] alu_mode;
+ input [DSP48E1_CARRYINSEL_W -1:0] carry_in_sel;
+ input [ DSP48E1_P_W -1:0] casc_p_in;
+ output [ DSP48E1_P_W -1:0] casc_p_out;
+ output carry_out;
+
+
+ //
+ // Internal Registers
+ //
+ reg [ DSP48E1_C_W -1:0] reg_x;
+ reg [ DSP48E1_C_W -1:0] reg_y;
+
+ reg [ DSP48E1_OPMODE_W -1:0] reg_op_mode;
+ reg [ DSP48E1_ALUMODE_W -1:0] reg_alu_mode;
+ reg [DSP48E1_CARRYINSEL_W -1:0] reg_carry_in_sel;
+
+ always @(posedge clk)
+ //
+ if (ce_abc) begin
+ reg_x <= x;
+ reg_y <= y;
+ end
+
+ always @(posedge clk)
+ //
+ if (ce_ctrl) begin
+ reg_op_mode <= op_mode;
+ reg_alu_mode <= alu_mode;
+ reg_carry_in_sel <= carry_in_sel;
+ end
+
+
+ //
+ // Generic Math Slice Model
+ //
+ function [DSP48E1_C_W-1:0] calc_mux_x;
+ input [ 1:0] opmode_x;
+ input [DSP48E1_C_W-1:0] ab_value;
+ case (opmode_x)
+ DSP48E1_OPMODE_X_0: calc_mux_x = {DSP48E1_C_W{1'b0}};
+ DSP48E1_OPMODE_X_AB: calc_mux_x = ab_value;
+ default: begin
+ $display("ERROR: Bad X opmode (%b)!", opmode_x);
+ $finish;
+ end
+ endcase
+ endfunction
+
+ function [DSP48E1_C_W-1:0] calc_mux_y;
+ input [ 1:0] opmode_y;
+ input [DSP48E1_C_W-1:0] c_value;
+ case (opmode_y)
+ DSP48E1_OPMODE_Y_0: calc_mux_y = {DSP48E1_C_W{1'b0}};
+ DSP48E1_OPMODE_Y_C: calc_mux_y = c_value;
+ default: begin
+ $display("ERROR: Bad Y opmode (%b)!", opmode_y);
+ $finish;
+ end
+ endcase
+ endfunction
+
+ function [DSP48E1_C_W-1:0] calc_mux_z;
+ input [ 2:0] opmode_z;
+ input [DSP48E1_P_W-1:0] p_value;
+ input [DSP48E1_C_W-1:0] c_value;
+ input [DSP48E1_P_W-1:0] pcin_value;
+ case (opmode_z)
+ DSP48E1_OPMODE_Z_0: calc_mux_z = {DSP48E1_C_W{1'b0}}; // 000
+ DSP48E1_OPMODE_Z_C: calc_mux_z = c_value; // 011
+ DSP48E1_OPMODE_Z_PCIN17: calc_mux_z = {{17{1'b0}}, pcin_value[DSP48E1_C_W-1:17]}; // 101
+ DSP48E1_OPMODE_Z_P17: calc_mux_z = {{17{1'b0}}, p_value[DSP48E1_C_W-1:17]}; // 110
+ default: begin
+ $display("ERROR: Bad Z opmode (%b)!", opmode_z);
+ $finish;
+ end
+ endcase
+ endfunction
+
+ function [ DSP48E1_C_W -1:0] calc_mux_cin;
+ input [DSP48E1_CARRYINSEL_W -1:0] carryinsel_value;
+ input [ DSP48E1_ALUMODE_W -1:0] alumode_value;
+ input carry_value;
+ case (carryinsel_value)
+ DSP48E1_CARRYINSEL_CARRYIN: calc_mux_cin = 1'b0; // 000
+ DSP48E1_CARRYINSEL_CARRYCASCOUT: // 100
+ case (alumode_value)
+ DSP48E1_ALUMODE_Z_PLUS_X_AND_Y_AND_CIN: calc_mux_cin = carry_value;
+ DSP48E1_ALUMODE_Z_MINUS_X_AND_Y_AND_CIN: calc_mux_cin = ~carry_value;
+ default: begin
+ $display("ERROR: Invalid ALUMODE (%b)!", alumode_value);
+ $finish;
+ end
+ endcase
+ default: begin
+ $display("ERROR: Bad CARRYINSEL (%b)!", carryinsel_value);
+ $finish;
+ end
+ endcase
+ endfunction
+
+ function [ DSP48E1_P_W :0] calc_p;
+ input [ DSP48E1_ALUMODE_W -1:0] alumode_value;
+ input [ DSP48E1_OPMODE_W -1:0] opmode_value;
+ input [DSP48E1_CARRYINSEL_W -1:0] carryinsel_value;
+ input [ DSP48E1_P_W -1:0] p_value;
+ input [ DSP48E1_C_W -1:0] ab_value;
+ input [ DSP48E1_C_W -1:0] c_value;
+ input carry_value;
+ input [ DSP48E1_P_W -1:0] pcin_value;
+ reg [ DSP48E1_C_W -1:0] mux_x;
+ reg [ DSP48E1_C_W -1:0] mux_y;
+ reg [ DSP48E1_C_W -1:0] mux_z;
+ reg mux_cin;
+ reg [ DSP48E1_P_W :0] int_p;
+ begin
+ mux_x = calc_mux_x(opmode_value[1:0], ab_value);
+ mux_y = calc_mux_y(opmode_value[3:2], c_value);
+ mux_z = calc_mux_z(opmode_value[6:4], p_value, c_value, pcin_value);
+ mux_cin = calc_mux_cin(carryinsel_value, alumode_value, carry_value);
+ case (alumode_value)
+ //
+ DSP48E1_ALUMODE_Z_PLUS_X_AND_Y_AND_CIN: begin
+ int_p = {1'b0, mux_z} + {1'b0, mux_x} + {1'b0, mux_y} + {{DSP48E1_P_W{1'b0}}, mux_cin};
+ calc_p = {int_p[DSP48E1_P_W], int_p[DSP48E1_P_W-1:0]};
+ end
+ //
+ DSP48E1_ALUMODE_Z_MINUS_X_AND_Y_AND_CIN: begin
+ int_p = {1'b0, mux_z} - {1'b0, mux_x} - {1'b0, mux_y} - {{DSP48E1_P_W{1'b0}}, mux_cin};
+ calc_p = {~int_p[DSP48E1_P_W], int_p[DSP48E1_P_W-1:0]};
+ end
+ //
+ default: begin
+ $display("ERROR: Invalid ALUMODE (%b)!", alumode_value);
+ $finish;
+ end
+ endcase
+ end
+ endfunction
+
+
+ //
+ // Output Registers
+ //
+ reg [DSP48E1_P_W -1:0] reg_p;
+ reg reg_carry_out;
+
+ always @(posedge clk)
+ //
+ if (ce_p) {reg_carry_out, reg_p} <=
+ calc_p(reg_alu_mode, reg_op_mode, reg_carry_in_sel, reg_p, reg_x, reg_y, reg_carry_out, casc_p_in);
+
+
+ //
+ // Output Buses
+ //
+ assign p = reg_p;
+ assign carry_out = reg_carry_out;
+
+
+ //
+ // Cascade Bus
+ //
+ assign casc_p_out = reg_p;
+
+
+endmodule