//====================================================================== // // 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_reductor ( clk, rst_n, ena, rdy, word_index_last, sel_wide_out, sel_narrow_out, rd_wide_x_din_aux, rd_wide_y_din_aux, rcmb_final_xy_bank, rcmb_final_xy_addr, rcmb_final_x_din, rcmb_final_y_din, rcmb_final_xy_valid, rdct_wide_xy_bank, rdct_wide_xy_addr, rdct_wide_x_dout, rdct_wide_y_dout, rdct_wide_xy_valid, rdct_narrow_xy_bank, rdct_narrow_xy_addr, rdct_narrow_x_dout, rdct_narrow_y_dout, rdct_narrow_xy_valid ); // // Headers // `include "modexpng_parameters.vh" `include "modexpng_dsp48e1.vh" `include "modexpng_dsp_slice_primitives.vh" // // Ports // input clk; input rst_n; input ena; output rdy; input [ OP_ADDR_W -1:0] word_index_last; input [BANK_ADDR_W -1:0] sel_wide_out; input [BANK_ADDR_W -1:0] sel_narrow_out; input [ WORD_EXT_W -1:0] rd_wide_x_din_aux; input [ WORD_EXT_W -1:0] rd_wide_y_din_aux; // input [BANK_ADDR_W -1:0] rcmb_final_xy_bank; input [ OP_ADDR_W -1:0] rcmb_final_xy_addr; input [ WORD_EXT_W -1:0] rcmb_final_x_din; input [ WORD_EXT_W -1:0] rcmb_final_y_din; input rcmb_final_xy_valid; output [BANK_ADDR_W -1:0] rdct_wide_xy_bank; output [ OP_ADDR_W -1:0] rdct_wide_xy_addr; output [ WORD_EXT_W -1:0] rdct_wide_x_dout; output [ WORD_EXT_W -1:0] rdct_wide_y_dout; output rdct_wide_xy_valid; output [BANK_ADDR_W -1:0] rdct_narrow_xy_bank; output [ OP_ADDR_W -1:0] rdct_narrow_xy_addr; output [ WORD_EXT_W -1:0] rdct_narrow_x_dout; output [ WORD_EXT_W -1:0] rdct_narrow_y_dout; output rdct_narrow_xy_valid; // // Output Registers // reg [BANK_ADDR_W -1:0] wide_xy_bank; reg [ OP_ADDR_W -1:0] wide_xy_addr; reg [ WORD_EXT_W -1:0] wide_x_dout; reg [ WORD_EXT_W -1:0] wide_y_dout; reg wide_xy_valid = 1'b0; reg [BANK_ADDR_W -1:0] narrow_xy_bank; reg [ OP_ADDR_W -1:0] narrow_xy_addr; reg [ WORD_EXT_W -1:0] narrow_x_dout; reg [ WORD_EXT_W -1:0] narrow_y_dout; reg narrow_xy_valid = 1'b0; // // Mapping // assign rdct_wide_xy_bank = wide_xy_bank; assign rdct_wide_xy_addr = wide_xy_addr; assign rdct_wide_x_dout = wide_x_dout; assign rdct_wide_y_dout = wide_y_dout; assign rdct_wide_xy_valid = wide_xy_valid; assign rdct_narrow_xy_bank = narrow_xy_bank; assign rdct_narrow_xy_addr = narrow_xy_addr; assign rdct_narrow_x_dout = narrow_x_dout; assign rdct_narrow_y_dout = narrow_y_dout; assign rdct_narrow_xy_valid = narrow_xy_valid; // // Helper Tasks // task _update_rdct_wide; input [BANK_ADDR_W -1:0] bank; input [ OP_ADDR_W -1:0] addr; input [ WORD_EXT_W -1:0] dout_x; input [ WORD_EXT_W -1:0] dout_y; input valid; begin wide_xy_bank <= bank; wide_xy_addr <= addr; wide_x_dout <= dout_x; wide_y_dout <= dout_y; wide_xy_valid <= valid; end endtask task _update_rdct_narrow; input [BANK_ADDR_W -1:0] bank; input [ OP_ADDR_W -1:0] addr; input [ WORD_EXT_W -1:0] dout_x; input [ WORD_EXT_W -1:0] dout_y; input valid; begin narrow_xy_bank <= bank; narrow_xy_addr <= addr; narrow_x_dout <= dout_x; narrow_y_dout <= dout_y; narrow_xy_valid <= valid; end endtask task set_rdct_wide; input [BANK_ADDR_W -1:0] bank; input [ OP_ADDR_W -1:0] addr; input [ WORD_EXT_W -1:0] dout_x; input [ WORD_EXT_W -1:0] dout_y; _update_rdct_wide(bank, addr, dout_x, dout_y, 1'b1); endtask task set_rdct_narrow; input [BANK_ADDR_W -1:0] bank; input [ OP_ADDR_W -1:0] addr; input [ WORD_EXT_W -1:0] dout_x; input [ WORD_EXT_W -1:0] dout_y; _update_rdct_narrow(bank, addr, dout_x, dout_y, 1'b1); endtask task clear_rdct_wide; _update_rdct_wide(BANK_DNC, OP_ADDR_DNC, WORD_EXT_DNC, WORD_EXT_DNC, 1'b0); endtask task clear_rdct_narrow; _update_rdct_narrow(BANK_DNC, OP_ADDR_DNC, WORD_EXT_DNC, WORD_EXT_DNC, 1'b0); endtask // // Pipeline rd_wide_* // reg [WORD_EXT_W -1:0] rd_wide_x_din_aux_pipe; reg [WORD_EXT_W -1:0] rd_wide_y_din_aux_pipe; always @(posedge clk) // {rd_wide_y_din_aux_pipe, rd_wide_x_din_aux_pipe} <= {rd_wide_y_din_aux, rd_wide_x_din_aux}; // // Counter // integer i; // // Delay rcmb_final_* to match rd_wide_* // reg rcmb_xy_valid_dly[1:6]; reg [BANK_ADDR_W -1:0] rcmb_xy_bank_dly [1:6]; reg [ OP_ADDR_W -1:0] rcmb_xy_addr_dly [1:6]; reg [ WORD_EXT_W -1:0] rcmb_x_dout_dly [1:4]; reg [ WORD_EXT_W -1:0] rcmb_y_dout_dly [1:4]; initial for (i=1; i<=6; i=i+1) rcmb_xy_valid_dly[i] = 1'b0; always @(posedge clk or negedge rst_n) // if (!rst_n) for (i=1; i<=6; i=i+1) rcmb_xy_valid_dly[i] <= 1'b0; else begin rcmb_xy_valid_dly[1] <= rcmb_final_xy_valid; for (i=2; i<=6; i=i+1) rcmb_xy_valid_dly[i] <= rcmb_xy_valid_dly[i-1]; end always @(posedge clk) begin // {rcmb_xy_bank_dly[1], rcmb_xy_addr_dly[1], rcmb_x_dout_dly[1], rcmb_y_dout_dly[1]} <= {rcmb_final_xy_bank, rcmb_final_xy_addr, rcmb_final_x_din, rcmb_final_y_din }; for (i=2; i<=6; i=i+1) {rcmb_xy_bank_dly[i], rcmb_xy_addr_dly[i] } <= {rcmb_xy_bank_dly[i-1], rcmb_xy_addr_dly[i-1] }; for (i=2; i<=4; i=i+1) { rcmb_x_dout_dly[i], rcmb_y_dout_dly[i]} <= { rcmb_x_dout_dly[i-1], rcmb_y_dout_dly[i-1]}; // end // // Internal Busy Flag Logic // reg busy_next = 1'b0; reg [4:0] busy_now_shreg = 5'b00000; wire busy_now = busy_now_shreg[4]; always @(posedge clk or negedge rst_n) // if (!rst_n) busy_now_shreg <= 5'b00000; else begin if (rdy && ena) busy_now_shreg <= 5'b11111; else busy_now_shreg <= {busy_now_shreg[3:0], busy_next}; end always @(posedge clk or negedge rst_n) // if (!rst_n) busy_next <= 1'b0; else begin if (rdy && ena) busy_next <= 1'b1; if (!rdy && rcmb_xy_valid_dly[4] && (rcmb_xy_bank_dly[4] == BANK_RCMB_EXT)) busy_next <= 1'b0; end // // Ready Flag Logic // reg rdy_reg = 1'b1; assign rdy = rdy_reg; always @(posedge clk or negedge rst_n) // if (!rst_n) rdy_reg <= 1'b1; else begin if (rdy && ena) rdy_reg <= 1'b0; if (!rdy && !busy_now) rdy_reg <= 1'b1; end // // Pipelined Flags // reg rcmb_xy_addr_dly3_is_zero; reg rcmb_xy_addr_dly3_is_one; reg rcmb_xy_addr_dly3_gt_one; reg rcmb_xy_addr_dly5_is_one; reg rcmb_xy_addr_dly5_gt_one; reg rcmb_xy_addr_dly6_is_zero; always @(posedge clk) begin rcmb_xy_addr_dly3_is_zero <= rcmb_xy_addr_dly[2] == OP_ADDR_ZERO; rcmb_xy_addr_dly3_is_one <= rcmb_xy_addr_dly[2] == OP_ADDR_ONE; rcmb_xy_addr_dly3_gt_one <= rcmb_xy_addr_dly[2] > OP_ADDR_ONE; rcmb_xy_addr_dly5_is_one <= rcmb_xy_addr_dly[4] == OP_ADDR_ONE; rcmb_xy_addr_dly5_gt_one <= rcmb_xy_addr_dly[4] > OP_ADDR_ONE; rcmb_xy_addr_dly6_is_zero <= rcmb_xy_addr_dly[5] == OP_ADDR_ZERO; end // // LSB Math // reg lsb_ce = 1'b0; reg lsb_ce_dly = 1'b0; reg [DSP48E1_OPMODE_W -1:0] lsb_opmode; wire [DSP48E1_P_W -1:0] lsb_px; wire [DSP48E1_P_W -1:0] lsb_py; wire [DSP48E1_C_W -1:0] lsb_ax = {{(DSP48E1_C_W-(WORD_EXT_W+1)){1'b0}}, rcmb_x_dout_dly[4][WORD_EXT_W-1:WORD_W], 1'b1, rcmb_x_dout_dly[4][WORD_W-1:0]}; wire [DSP48E1_C_W -1:0] lsb_ay = {{(DSP48E1_C_W-(WORD_EXT_W+1)){1'b0}}, rcmb_y_dout_dly[4][WORD_EXT_W-1:WORD_W], 1'b1, rcmb_y_dout_dly[4][WORD_W-1:0]}; wire [DSP48E1_C_W -1:0] lsb_bx = {{(DSP48E1_C_W-(WORD_EXT_W+1)){1'b0}}, rd_wide_x_din_aux_pipe[WORD_EXT_W-1:WORD_W], 1'b0, rd_wide_x_din_aux_pipe[WORD_W-1:0]}; wire [DSP48E1_C_W -1:0] lsb_by = {{(DSP48E1_C_W-(WORD_EXT_W+1)){1'b0}}, rd_wide_y_din_aux_pipe[WORD_EXT_W-1:WORD_W], 1'b0, rd_wide_y_din_aux_pipe[WORD_W-1:0]}; wire [DSP48E1_P_W -1:0] lsb2msb_px_casc; wire [DSP48E1_P_W -1:0] lsb2msb_py_casc; `MODEXPNG_DSP_SLICE_ADDSUB dsp_lsb_x ( .clk (clk), .ce_ab1 (1'b0), .ce_ab2 (lsb_ce), .ce_c (lsb_ce), .ce_p (lsb_ce_dly), .ce_ctrl (lsb_ce), .ab (lsb_ax), .c (lsb_bx), .p (lsb_px), .op_mode (lsb_opmode), .alu_mode (DSP48E1_ALUMODE_Z_PLUS_X_AND_Y_AND_CIN), .carry_in_sel (DSP48E1_CARRYINSEL_CARRYIN), .casc_p_in (), .casc_p_out (lsb2msb_px_casc), .carry_out () ); `MODEXPNG_DSP_SLICE_ADDSUB dsp_lsb_y ( .clk (clk), .ce_ab1 (1'b0), .ce_ab2 (lsb_ce), .ce_c (lsb_ce), .ce_p (lsb_ce_dly), .ce_ctrl (lsb_ce), .ab (lsb_ay), .c (lsb_by), .p (lsb_py), .op_mode (lsb_opmode), .alu_mode (DSP48E1_ALUMODE_Z_PLUS_X_AND_Y_AND_CIN), .carry_in_sel (DSP48E1_CARRYINSEL_CARRYIN), .casc_p_in (), .casc_p_out (lsb2msb_py_casc), .carry_out () ); always @(posedge clk or negedge rst_n) // if (!rst_n) lsb_ce <= 1'b0; else begin lsb_ce <= 1'b0; if (rcmb_xy_valid_dly[3]) // case (rcmb_xy_bank_dly[3]) BANK_RCMB_ML: lsb_ce <= 1'b1; BANK_RCMB_MH: if (rcmb_xy_addr_dly3_is_zero) lsb_ce <= 1'b1; endcase // end always @(posedge clk) begin // //lsb_opmode <= DSP48E1_OPMODE_DNC; // if (rcmb_xy_valid_dly[3]) // case (rcmb_xy_bank_dly[3]) BANK_RCMB_ML: if (rcmb_xy_addr_dly3_is_zero) lsb_opmode <= DSP48E1_OPMODE_Z0_YC_XAB; else lsb_opmode <= DSP48E1_OPMODE_ZP17_YC_XAB; BANK_RCMB_MH: if (rcmb_xy_addr_dly3_is_zero) lsb_opmode <= DSP48E1_OPMODE_ZP17_YC_XAB; endcase // end always @(posedge clk or negedge rst_n) // if (!rst_n) lsb_ce_dly <= 1'b0; else lsb_ce_dly <= lsb_ce; // // MSB Math // reg msb_ce = 1'b0; reg msb_ce_dly1 = 1'b0; reg msb_ce_dly2 = 1'b0; reg [DSP48E1_OPMODE_W -1:0] msb_opmode; wire [DSP48E1_P_W -1:0] msb_px; wire [DSP48E1_P_W -1:0] msb_py; wire [DSP48E1_C_W -1:0] msb_ax = {{(DSP48E1_C_W-WORD_EXT_W){1'b0}}, rcmb_x_dout_dly[4][WORD_EXT_W-1:WORD_W], rcmb_x_dout_dly[4][WORD_W-1:0]}; wire [DSP48E1_C_W -1:0] msb_ay = {{(DSP48E1_C_W-WORD_EXT_W){1'b0}}, rcmb_y_dout_dly[4][WORD_EXT_W-1:WORD_W], rcmb_y_dout_dly[4][WORD_W-1:0]}; wire [DSP48E1_C_W -1:0] msb_bx = {{(DSP48E1_C_W-WORD_EXT_W){1'b0}}, rd_wide_x_din_aux_pipe[WORD_EXT_W-1:WORD_W], rd_wide_x_din_aux_pipe[WORD_W-1:0]}; wire [DSP48E1_C_W -1:0] msb_by = {{(DSP48E1_C_W-WORD_EXT_W){1'b0}}, rd_wide_y_din_aux_pipe[WORD_EXT_W-1:WORD_W], rd_wide_y_din_aux_pipe[WORD_W-1:0]}; `MODEXPNG_DSP_SLICE_ADDSUB dsp_msb_x ( .clk (clk), .ce_ab1 (1'b0), .ce_ab2 (msb_ce), .ce_c (msb_ce), .ce_p (msb_ce_dly1), .ce_ctrl (msb_ce), .ab (msb_ax), .c (msb_bx), .p (msb_px), .op_mode (msb_opmode), .alu_mode (DSP48E1_ALUMODE_Z_PLUS_X_AND_Y_AND_CIN), .carry_in_sel (DSP48E1_CARRYINSEL_CARRYIN), .casc_p_in (lsb2msb_px_casc), .casc_p_out (), .carry_out () ); `MODEXPNG_DSP_SLICE_ADDSUB dsp_msb_y ( .clk (clk), .ce_ab1 (1'b0), .ce_ab2 (msb_ce), .ce_c (msb_ce), .ce_p (msb_ce_dly1), .ce_ctrl (msb_ce), .ab (msb_ay), .c (msb_by), .p (msb_py), .op_mode (msb_opmode), .alu_mode (DSP48E1_ALUMODE_Z_PLUS_X_AND_Y_AND_CIN), .carry_in_sel (DSP48E1_CARRYINSEL_CARRYIN), .casc_p_in (lsb2msb_py_casc), .casc_p_out (), .carry_out () ); always @(posedge clk or negedge rst_n) // if (!rst_n) msb_ce <= 1'b0; else begin msb_ce <= 1'b0; if (rcmb_xy_valid_dly[3]) // case (rcmb_xy_bank_dly[3]) BANK_RCMB_MH: if (!rcmb_xy_addr_dly3_is_zero) msb_ce <= 1'b1; BANK_RCMB_EXT: msb_ce <= 1'b1; endcase // end always @(posedge clk) begin // msb_opmode <= DSP48E1_OPMODE_DNC; // if (rcmb_xy_valid_dly[3]) // case (rcmb_xy_bank_dly[3]) BANK_RCMB_MH: if (rcmb_xy_addr_dly3_is_one) msb_opmode <= DSP48E1_OPMODE_ZPCIN17_YC_XAB; else if (rcmb_xy_addr_dly3_gt_one) msb_opmode <= DSP48E1_OPMODE_Z0_YC_XAB; BANK_RCMB_EXT: msb_opmode <= DSP48E1_OPMODE_Z0_Y0_XAB; endcase // end always @(posedge clk or negedge rst_n) // if (!rst_n) {msb_ce_dly2, msb_ce_dly1} <= {2'b00}; else {msb_ce_dly2, msb_ce_dly1} <= {msb_ce_dly1, msb_ce}; // // Output Logic // reg [OP_ADDR_W -1:0] wide_xy_addr_next; reg [OP_ADDR_W -1:0] narrow_xy_addr_next; always @(posedge clk) // if (msb_ce_dly1) // case (rcmb_xy_bank_dly[5]) BANK_RCMB_MH: if (rcmb_xy_addr_dly5_is_one) {wide_xy_addr_next, narrow_xy_addr_next} <= {OP_ADDR_ZERO, OP_ADDR_ZERO}; else if (rcmb_xy_addr_dly5_gt_one) {wide_xy_addr_next, narrow_xy_addr_next} <= {rcmb_xy_addr_dly[5] - 1'b1, rcmb_xy_addr_dly[5] - 1'b1}; BANK_RCMB_EXT: {wide_xy_addr_next, narrow_xy_addr_next} <= {word_index_last, word_index_last}; endcase always @(posedge clk or negedge rst_n) // if (!rst_n) begin clear_rdct_wide; clear_rdct_narrow; end else begin // clear_rdct_wide; clear_rdct_narrow; // if (msb_ce_dly2) // case (rcmb_xy_bank_dly[6]) // BANK_RCMB_MH: if (!rcmb_xy_addr_dly6_is_zero) begin set_rdct_wide (sel_wide_out, wide_xy_addr_next, msb_px[WORD_EXT_W-1:0], msb_py[WORD_EXT_W-1:0]); set_rdct_narrow(sel_narrow_out, narrow_xy_addr_next, msb_px[WORD_EXT_W-1:0], msb_py[WORD_EXT_W-1:0]); end // BANK_RCMB_EXT: begin set_rdct_wide (sel_wide_out, wide_xy_addr_next, msb_px[WORD_EXT_W-1:0], msb_py[WORD_EXT_W-1:0]); set_rdct_narrow(sel_narrow_out, narrow_xy_addr_next, msb_px[WORD_EXT_W-1:0], msb_py[WORD_EXT_W-1:0]); end // endcase // end endmodule