aboutsummaryrefslogblamecommitdiff
path: root/rtl/modexpng_recombinator_cell.v
blob: 28d17f2ee5658880803872c9d840105caa506c7f (plain) (tree)































                                                                           


                                 
            
                    

  
 


              



                                               








                              
                               


      
                                                 
      





                                                        
 

      
                                               
      


                                                                                               
 
    


                      

                        
                         
                                               
 












                                              
    




                                                                             
      
                      
      



                                
 

                               

                                                                                                     
          

                                                        

          
    


                          
      








                                                




                                              
    


                       
      
                                                
                                       
                                               


      
                           
      

                         

                                                        

      
                        
      





                                                                                                          

      
                
      







                                                          

                               

                                                                                                     
       
 






                                              


                                      

                                        
                           

                                                                 
                                            
                           

                                              


                                             
     
                              


                                     



                                       
                                                                 

                                             
                           
                                             



      
                      










                                                                                                            

         
//======================================================================
//
// 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_recombinator_cell
(
    clk,
    ce, clr,
    din, dout, doutw
);


    //
    // Headers
    //
    `include "modexpng_parameters.vh"
    `include "modexpng_dsp48e1.vh"
    `include "modexpng_dsp_slice_primitives.vh"

    
    //
    // Ports
    //
    input                clk;
    input                ce;
    input                clr;
    input  [ MAC_W -1:0] din;
    output [WORD_W -1:0] dout;
    output [WORD_W   :0] doutw;
    
    
    //
    // Pipelined Clock Enable, Clear, Data Input 
    //
    reg             ce_pipe = 1'b0;
    reg             clr_pipe;
    reg [MAC_W-1:0] din_pipe;
    
    always @(posedge clk)
        {ce_pipe, clr_pipe, din_pipe} <= {ce, clr, din};

    
    //
    // din_pipe <=> {z[13:0], y[15:0], x[15:0]}
    //
    wire [WORD_W -1:0] din_z = {2'b00, din_pipe[3 * WORD_W -3 : 2 * WORD_W]}; // (47:46)[45:32]
    wire [WORD_W -1:0] din_y = {       din_pipe[2 * WORD_W -1 :     WORD_W]}; //        [31:16]
    wire [WORD_W -1:0] din_x = {       din_pipe[    WORD_W -1 :          0]}; //        [15: 0]

    
    //
    // Phase Flip-Flop
    //
    reg phase_ff = 1'b0;
    
    always @(posedge clk)
        phase_ff <= ce_pipe ? ~phase_ff : 1'b0;


    //
    // Delayed Clock Enable, Clear, Data Input
    //
    wire master_ce_0;
    reg  master_ce_1 = 1'b0;
    wire slave_ce_1;
    reg  slave_ce_2 = 1'b0;
    reg  dout_ce_3 = 1'b0;
    reg  dout_ce_4 = 1'b0;
    
    assign master_ce_0 = ce_pipe;
    assign slave_ce_1  = master_ce_1; 
    
    always @(posedge clk) master_ce_1 <= ce_pipe & ~phase_ff;
    always @(posedge clk) slave_ce_2  <= slave_ce_1;
    always @(posedge clk) {dout_ce_3, dout_ce_4} <= {slave_ce_2, dout_ce_3}; 


    //
    // Shift Registers
    //
    reg [WORD_W-1:0] din_x_dly1;
    reg [WORD_W-1:0] din_y_dly1;
    reg [WORD_W-1:0] din_z_dly1;
    reg [WORD_W-1:0] din_z_dly2;

    always @(posedge clk) begin
        //
        if (ce_pipe)       {din_x_dly1, din_y_dly1, din_z_dly1} <= {din_x,     din_y,     din_z};
        else if (clr_pipe) {din_x_dly1, din_y_dly1, din_z_dly1} <= {WORD_ZERO, WORD_ZERO, WORD_ZERO};
        //
        if (ce_pipe)       {din_z_dly2} <= {din_z_dly1};
        else if (clr_pipe) {din_z_dly2} <= {WORD_ZERO};
        //
    end
    

    //
    // DSP Input Registers
    //
    wire [2 * WORD_W-1:0] master_ab;
    wire [2 * WORD_W-1:0] master_c;
    wire [2 * WORD_W-1:0] slave_ab;
    reg                   slave_c;
    
    assign master_ab = {din_y,      din_y_dly1};
    assign master_c  = {din_z_dly1, din_z_dly2};
    assign slave_ab  = {din_x,      din_x_dly1};
        

    //
    // DSP Cascade Bus
    //
    wire [DSP48E1_P_W-1:0] master_slave_p_int;
    

    //
    // DSP Output Buses
    //
    wire                   master_carry_out_int;
    wire [DSP48E1_P_W-1:0] slave_p_int;
    wire                   slave_carry_out_int;


    //
    // Custom Carry Cascade
    //
    always @(posedge clk)
        //
        if (slave_ce_2) slave_c <= master_carry_out_int;

    
    //
    // DSP Input Mapping
    //
    wire [DSP48E1_C_W-1:0] master_ab_int = {master_ab, {(DSP48E1_C_W - 2*WORD_W){1'b0}}};
    wire [DSP48E1_C_W-1:0] master_c_int  = {master_c,  {(DSP48E1_C_W - 2*WORD_W){1'b0}}};

    wire [DSP48E1_C_W-1:0] slave_ab_int = {slave_ab, {(DSP48E1_C_W - 2*WORD_W){1'b0}}};
    wire [DSP48E1_C_W-1:0] slave_c_int  = {{(2*WORD_W-1){1'b0}}, slave_c, {(DSP48E1_C_W-2*WORD_W){1'b1}}};

    
    //
    // DPS Modes
    //
    wire [DSP48E1_OPMODE_W    -1:0] master_opmode;
    wire [DSP48E1_CARRYINSEL_W-1:0] master_carryinsel;
    
    reg  [DSP48E1_OPMODE_W    -1:0] slave_opmode;
    reg  [DSP48E1_CARRYINSEL_W-1:0] slave_carryinsel;
    
    assign master_opmode     = DSP48E1_OPMODE_Z0_YC_XAB;
    assign master_carryinsel = DSP48E1_CARRYINSEL_CARRYIN;
    
    always @(posedge clk) begin
        slave_opmode     <= clr_pipe ? DSP48E1_OPMODE_ZPCIN_Y0_XAB : DSP48E1_OPMODE_ZPCIN_YC_XAB;
        slave_carryinsel <= clr_pipe ? DSP48E1_CARRYINSEL_CARRYIN  : DSP48E1_CARRYINSEL_CARRYCASCOUT;
    end

    
    //
    // DSP Slice Instances
    //
    `MODEXPNG_DSP_SLICE_ADDSUB dsp_master_inst
    (
        .clk            (clk),
        .ce_abc         (master_ce_0),
        .ce_p           (master_ce_1),
        .ce_ctrl        (master_ce_0),
        .ab             (master_ab_int),
        .c              (master_c_int),
        .p              (),
        .op_mode        (master_opmode),
        .alu_mode       (DSP48E1_ALUMODE_Z_PLUS_X_AND_Y_AND_CIN),
        .carry_in_sel   (master_carryinsel),
        .casc_p_in      (),
        .casc_p_out     (master_slave_p_int),
        .carry_out      (master_carry_out_int)
    );
    
    `MODEXPNG_DSP_SLICE_ADDSUB dsp_slave_inst
    (
        .clk            (clk),
        .ce_abc         (slave_ce_1),
        .ce_p           (slave_ce_2),
        .ce_ctrl        (slave_ce_1),
        .ab             (slave_ab_int),
        .c              (slave_c_int),
        .p              (slave_p_int),
        .op_mode        (slave_opmode),
        .alu_mode       (DSP48E1_ALUMODE_Z_PLUS_X_AND_Y_AND_CIN),
        .carry_in_sel   (slave_carryinsel),
        .casc_p_in      (master_slave_p_int),
        .casc_p_out     (),
        .carry_out      (slave_carry_out_int)
    );


    //
    // Output Register
    //
    reg [WORD_W:0] doutx_reg;
    
    assign dout  = doutx_reg[WORD_W-1:0];
    assign doutw = doutx_reg;

    always @(posedge clk) begin
        doutx_reg <= {1'bX, WORD_DNC};
        if (dout_ce_4) doutx_reg <= {slave_carry_out_int, slave_p_int[DSP48E1_P_W - 0*WORD_W -1 -: WORD_W]};
        if (dout_ce_3) doutx_reg <= {1'b0,                slave_p_int[DSP48E1_P_W - 1*WORD_W -1 -: WORD_W]};
    end
    
endmodule