aboutsummaryrefslogblamecommitdiff
path: root/rtl/modexpng_reductor.v
blob: 7404eba9826d16dfa0868863b8603a980ae1ec02 (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_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"


    //
    // 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_x_din_aux_pipe, rd_wide_y_din_aux_pipe} <=
        {rd_wide_x_din_aux,      rd_wide_y_din_aux     } ;



    //
    // Delay rcmb_final_* to match rd_wide_*
    //
    reg                    rcmb_xy_valid_dly1_x = 1'b0;
    reg                    rcmb_xy_valid_dly2_x = 1'b0;
    reg                    rcmb_xy_valid_dly3_x = 1'b0;
    reg                    rcmb_xy_valid_dly4_x = 1'b0;

    reg [BANK_ADDR_W -1:0] rcmb_xy_bank_dly1_x;
    reg [BANK_ADDR_W -1:0] rcmb_xy_bank_dly2_x;
    reg [BANK_ADDR_W -1:0] rcmb_xy_bank_dly3_x;
    reg [BANK_ADDR_W -1:0] rcmb_xy_bank_dly4_x;

    reg [  OP_ADDR_W -1:0] rcmb_xy_addr_dly1_x;
    reg [  OP_ADDR_W -1:0] rcmb_xy_addr_dly2_x;
    reg [  OP_ADDR_W -1:0] rcmb_xy_addr_dly3_x;
    reg [  OP_ADDR_W -1:0] rcmb_xy_addr_dly4_x;

    reg [ WORD_EXT_W -1:0] rcmb_x_dout_dly1_x;
    reg [ WORD_EXT_W -1:0] rcmb_x_dout_dly2_x;
    reg [ WORD_EXT_W -1:0] rcmb_x_dout_dly3_x;
    reg [ WORD_EXT_W -1:0] rcmb_x_dout_dly4_x;

    reg [ WORD_EXT_W -1:0] rcmb_y_dout_dly1_x;
    reg [ WORD_EXT_W -1:0] rcmb_y_dout_dly2_x;
    reg [ WORD_EXT_W -1:0] rcmb_y_dout_dly3_x;
    reg [ WORD_EXT_W -1:0] rcmb_y_dout_dly4_x;
    
    always @(posedge clk or negedge rst_n)
        //
        if (!rst_n) {rcmb_xy_valid_dly4_x, rcmb_xy_valid_dly3_x, rcmb_xy_valid_dly2_x, rcmb_xy_valid_dly1_x} <= 4'b0000;      
        else        {rcmb_xy_valid_dly4_x, rcmb_xy_valid_dly3_x, rcmb_xy_valid_dly2_x, rcmb_xy_valid_dly1_x} <= 
                    {rcmb_xy_valid_dly3_x, rcmb_xy_valid_dly2_x, rcmb_xy_valid_dly1_x, rcmb_final_xy_valid } ;
    
    always @(posedge clk) begin
        //
        if (rcmb_final_xy_valid)  {rcmb_xy_bank_dly1_x, rcmb_xy_addr_dly1_x, rcmb_x_dout_dly1_x, rcmb_y_dout_dly1_x} <=
                                  {rcmb_final_xy_bank,  rcmb_final_xy_addr,  rcmb_final_x_din,   rcmb_final_y_din  } ;   
        if (rcmb_xy_valid_dly1_x) {rcmb_xy_bank_dly2_x, rcmb_xy_addr_dly2_x, rcmb_x_dout_dly2_x, rcmb_y_dout_dly2_x} <=
                                  {rcmb_xy_bank_dly1_x, rcmb_xy_addr_dly1_x, rcmb_x_dout_dly1_x, rcmb_y_dout_dly1_x} ;
        if (rcmb_xy_valid_dly2_x) {rcmb_xy_bank_dly3_x, rcmb_xy_addr_dly3_x, rcmb_x_dout_dly3_x, rcmb_y_dout_dly3_x} <=
                                  {rcmb_xy_bank_dly2_x, rcmb_xy_addr_dly2_x, rcmb_x_dout_dly2_x, rcmb_y_dout_dly2_x} ;
        if (rcmb_xy_valid_dly3_x) {rcmb_xy_bank_dly4_x, rcmb_xy_addr_dly4_x, rcmb_x_dout_dly4_x, rcmb_y_dout_dly4_x} <=
                                  {rcmb_xy_bank_dly3_x, rcmb_xy_addr_dly3_x, rcmb_x_dout_dly3_x, rcmb_y_dout_dly3_x} ;
        //
    end
      
      
    //
    // LSB Carry Logic
    //
    reg  [   CARRY_W -1:0] rcmb_x_lsb_carry;
    reg  [   CARRY_W -1:0] rcmb_y_lsb_carry;
    reg  [    WORD_W -1:0] rcmb_x_lsb_dummy;
    reg  [    WORD_W -1:0] rcmb_y_lsb_dummy;
    wire [WORD_EXT_W -1:0] rcmb_x_lsb_carry_ext = {WORD_ZERO, rcmb_x_lsb_carry};
    wire [WORD_EXT_W -1:0] rcmb_y_lsb_carry_ext = {WORD_ZERO, rcmb_y_lsb_carry};
    
    task calc_rcmb_xy_lsb_carry;
        begin
            {rcmb_x_lsb_carry, rcmb_x_lsb_dummy} <= rcmb_x_dout_dly4_x + rd_wide_x_din_aux_pipe + rcmb_x_lsb_carry_ext;
            {rcmb_y_lsb_carry, rcmb_y_lsb_dummy} <= rcmb_y_dout_dly4_x + rd_wide_y_din_aux_pipe + rcmb_y_lsb_carry_ext;
        end
    endtask
    

    //
    // LSB Carry Computation
    //
    always @(posedge clk)
        //
        if (ena) begin
            //
            rcmb_x_lsb_carry <= CARRY_ZERO;
            rcmb_y_lsb_carry <= CARRY_ZERO;
            //
        end else if (rcmb_xy_valid_dly4_x)
            //
            case (rcmb_xy_bank_dly4_x)
                BANK_RCMB_ML:                                          calc_rcmb_xy_lsb_carry;  
                BANK_RCMB_MH: if (rcmb_xy_addr_dly4_x == OP_ADDR_ZERO) calc_rcmb_xy_lsb_carry;  
            endcase

    
    //
    // MSB Sum Logic
    //
    wire [WORD_EXT_W -1:0] sum_rdct_x = rcmb_x_dout_dly4_x + rd_wide_x_din_aux_pipe;
    wire [WORD_EXT_W -1:0] sum_rdct_y = rcmb_y_dout_dly4_x + rd_wide_y_din_aux_pipe;
    
    wire [WORD_EXT_W -1:0] sum_rdct_x_carry = sum_rdct_x + rcmb_x_lsb_carry_ext;
    wire [WORD_EXT_W -1:0] sum_rdct_y_carry = sum_rdct_y + rcmb_y_lsb_carry_ext;
    
    
    //
    // MSB Sum Computation
    //
    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 (rcmb_xy_valid_dly4_x)
                //
                case (rcmb_xy_bank_dly4_x)
                                    
                    BANK_RCMB_MH:
                        if (rcmb_xy_addr_dly4_x == OP_ADDR_ONE) begin
                            set_rdct_wide  (sel_wide_out,   OP_ADDR_ZERO, sum_rdct_x_carry, sum_rdct_y_carry);
                            set_rdct_narrow(sel_narrow_out, OP_ADDR_ZERO, sum_rdct_x_carry, sum_rdct_y_carry);
                        end else if (rcmb_xy_addr_dly4_x > OP_ADDR_ONE) begin
                            set_rdct_wide  (sel_wide_out,   rcmb_xy_addr_dly4_x - 1'b1, sum_rdct_x, sum_rdct_y);
                            set_rdct_narrow(sel_narrow_out, rcmb_xy_addr_dly4_x - 1'b1, sum_rdct_x, sum_rdct_y);
                        end
                            
                    BANK_RCMB_EXT: begin
                        set_rdct_wide  (sel_wide_out,   word_index_last, rcmb_x_dout_dly4_x, rcmb_y_dout_dly4_x);
                        set_rdct_narrow(sel_narrow_out, word_index_last, rcmb_x_dout_dly4_x, rcmb_y_dout_dly4_x);
                    end

                endcase
            //
        end


    //
    // Internal Busy Flag Logic
    //
    reg       busy_next      = 1'b0;
    reg [2:0] busy_now_shreg = 3'b000;
    wire      busy_now       = busy_now_shreg[2];
    
    always @(posedge clk or negedge rst_n)
        //
        if (!rst_n)         busy_now_shreg <= 3'b000;
        else begin
            if (rdy && ena) busy_now_shreg <= 3'b111;
            else            busy_now_shreg <= {busy_now_shreg[1: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_dly4_x && (rcmb_xy_bank_dly4_x == 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  


endmodule