aboutsummaryrefslogblamecommitdiff
path: root/rtl/modexpng_core_top.v
blob: c8a335fd156447ebebd29d6923498bcf4d3c7468 (plain) (tree)
1
2
3
4

                                                                        

                                                            










                                                                         


                                                                         














                                                                           


                        
          
                


                       

                      






                



                                     
                                    




            

                                                          
    
                                                        
    







                                                                     


                                                                    







                                                              
                                   
      












                                                    
 














































                                                          
                          


                                  
     
                                              
                                                





                                                           

                                           




























































                                                                       



      

                                


































































































































                                                                                                             
                                                                                                             
                                                                                                             
                                                                                                             






                                                

                                               



                                                  

                                                 



                                                   

                                                
                                                  
 

                                                

                                               



                                                  

                                                 



                                                   

                                                







                                                  

                                               



                                                  

                                                 



                                                   

                                               



                                                  

                                                 



                                                   
















                                                     




                                          
                                        



                                                    

                                                   



                                                      

                                                     






                                                        



                                                       



                                                      













                                                          




                                          
                                        



                                                    

                                                   



                                                      

                                                     






                                                        



                                                       



                                                      














                                                          








                                              
                                        



                                                    

                                                   



                                                      

                                                     
        




                                                    
    




                                                      


                                                      

                                                     



                                                        

                                                       



                                                         

                                                     



                                                        














                                                          




                                              
                                        



                                                    

                                                   



                                                      

                                                     
        




                                                    
    




                                                      


                                                      

                                                     



                                                        

                                                       



                                                         

                                                     



                                                        














                                                          



      

                




                                  
                                








                                       
                                       


                                       
                                       



                                      
                                     




                 
          

                                  
                                          
                                            
    

                                                 
    



                                                     
        
                                                    
        
                                                             
    






















                                                          
    


                                                   
    


                                                   
    




                                                  
                                                                 
                                                                 
                                                                 
                                                                 





                                                          




                         
           


                                          
                                            






                                                                   
                                                          
                                                        
                                                          









                                                            



                                                           



                                                          

                                                         


                                                          

                                                         



                                                            

                                                           



                                                             

                                                          








                                                            
                                            






                                                                   
                                                          
                                                        
                                                          









                                                            



                                                           



                                                          

                                                         


                                                          

                                                         



                                                            

                                                           



                                                             

                                                          







                                                            
              


                                      
                                        








                                                         

                                                          

                                                       


                                                       

                                                      



                                                        

                                                     



                                                        

                                                       





                                                        
                                        








                                                         

                                                          

                                                       


                                                       

                                                      



                                                        

                                                     



                                                        

                                                       




                                                        
                     
          


                                          
                                            











                                                          
                                                               



















































                                                              
                              
      



                                         

         
//======================================================================
//
// Copyright: 2019, The Commons Conservancy Cryptech Project
// SPDX-License-Identifier: BSD-3-Clause
//
// 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 copyright holder 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_core_top
(
    clk, clk_bus,
    rst_n,
    next, valid,
    crt_mode,
    word_index_last_n,
    word_index_last_pq,
    bit_index_last_n,
    bit_index_last_pq,
    bus_cs,
    bus_we,
    bus_addr,
    bus_data_wr,
    bus_data_rd
);

    //
    // Headers
    //
    `include "modexpng_parameters.vh"
    `include "modexpng_microcode.vh"

    
    //
    // Ports
    //
    input                                         clk;
    input                                         clk_bus;
    
    input                                         rst_n;
    
    input                                         next;
    output                                        valid;
    
    input                                         crt_mode;

    input  [                  OP_ADDR_W     -1:0] word_index_last_n;
    input  [                  OP_ADDR_W     -1:0] word_index_last_pq;

    input  [                  BIT_INDEX_W   -1:0] bit_index_last_n;
    input  [                  BIT_INDEX_W   -1:0] bit_index_last_pq;
    
    input                                         bus_cs;
    input                                         bus_we;
    input  [2 + BANK_ADDR_W + BUS_OP_ADDR_W -1:0] bus_addr;
    input  [                  BUS_DATA_W    -1:0] bus_data_wr;
    output [                  BUS_DATA_W    -1:0] bus_data_rd;
    
    
    //
    // uOP Control / Status Signals
    //
    wire                     io_mgr_ena;
    wire                     io_mgr_rdy;
    wire [UOP_CRT_W    -1:0] io_mgr_sel_crt;
    wire [UOP_AUX_W    -1:0] io_mgr_sel_aux;
    wire [BANK_ADDR_W  -1:0] io_mgr_sel_in;
    wire [BANK_ADDR_W  -1:0] io_mgr_sel_out;
    wire [OP_ADDR_W    -1:0] io_mgr_word_index_last;
    wire [UOP_OPCODE_W -1:0] io_mgr_opcode;
    wire [BIT_INDEX_W  -1:0] io_mgr_ladder_steps;
    wire                     io_mgr_ladder_d;
    wire                     io_mgr_ladder_p;
    wire                     io_mgr_ladder_q;
    wire                     io_mgr_ladder_done;

    wire                     mmm_ena_x;
    wire                     mmm_ena_y;  
    wire                     mmm_rdy_x;
    wire                     mmm_rdy_y; 
    wire [OP_ADDR_W    -1:0] mmm_word_index_last_x;
    wire [OP_ADDR_W    -1:0] mmm_word_index_last_y;
    wire [OP_ADDR_W    -1:0] mmm_word_index_last_minus1_x;
    wire [OP_ADDR_W    -1:0] mmm_word_index_last_minus1_y;
    wire                     mmm_ladder_mode_x;
    wire                     mmm_ladder_mode_y;
    wire [BANK_ADDR_W  -1:0] mmm_sel_wide_in_x;
    wire [BANK_ADDR_W  -1:0] mmm_sel_wide_in_y;
    wire [BANK_ADDR_W  -1:0] mmm_sel_narrow_in_x;
    wire [BANK_ADDR_W  -1:0] mmm_sel_narrow_in_y;
    wire                     mmm_force_unity_b_x;
    wire                     mmm_force_unity_b_y;
    wire                     mmm_only_reduce_x;
    wire                     mmm_only_reduce_y;
    wire                     mmm_just_multiply_x;
    wire                     mmm_just_multiply_y;
        
    wire                     rdct_ena_x;
    wire                     rdct_ena_y;
    wire                     rdct_rdy_x;
    wire                     rdct_rdy_y;
    wire [OP_ADDR_W    -1:0] rdct_word_index_last_x;
    wire [OP_ADDR_W    -1:0] rdct_word_index_last_y;
    wire [BANK_ADDR_W  -1:0] rdct_sel_wide_out_x;
    wire [BANK_ADDR_W  -1:0] rdct_sel_narrow_out_x;
    wire [BANK_ADDR_W  -1:0] rdct_sel_wide_out_y;
    wire [BANK_ADDR_W  -1:0] rdct_sel_narrow_out_y;

    wire                     wrk_ena;
    wire                     wrk_rdy;
    wire [BANK_ADDR_W  -1:0] wrk_sel_wide_in;
    wire [BANK_ADDR_W  -1:0] wrk_sel_wide_out;
    wire [BANK_ADDR_W  -1:0] wrk_sel_narrow_in;
    wire [BANK_ADDR_W  -1:0] wrk_sel_narrow_out;
    wire [OP_ADDR_W    -1:0] wrk_word_index_last;
    wire [OP_ADDR_W    -1:0] wrk_word_index_last_half;
    wire [UOP_OPCODE_W -1:0] wrk_opcode;

    
    //
    // uOP Engine
    //
    `ifdef MODEXPNG_ENABLE_DEBUG
    wire uop_decoded_stop;
    `endif
    
    modexpng_uop_engine uop_engine
    (
        .clk                            (clk),
        .rst_n                          (rst_n),
        
        .ena                            (next),
        .rdy                            (valid),

        `ifdef MODEXPNG_ENABLE_DEBUG
        .uop_decoded_stop               (uop_decoded_stop),
        `else
        .uop_decoded_stop               (),
        `endif

        .crt_mode                       (crt_mode),
        
        .word_index_last_n              (word_index_last_n),
        .word_index_last_pq             (word_index_last_pq),
        
        .bit_index_last_n               (bit_index_last_n),
        .bit_index_last_pq              (bit_index_last_pq),

        .io_mgr_ena                     (io_mgr_ena),
        .io_mgr_rdy                     (io_mgr_rdy),
        .io_mgr_sel_crt                 (io_mgr_sel_crt),
        .io_mgr_sel_aux                 (io_mgr_sel_aux),
        .io_mgr_sel_in                  (io_mgr_sel_in),
        .io_mgr_sel_out                 (io_mgr_sel_out),
        .io_mgr_word_index_last         (io_mgr_word_index_last),
        .io_mgr_opcode                  (io_mgr_opcode),
        .io_mgr_ladder_steps            (io_mgr_ladder_steps),
        .io_mgr_ladder_d                (io_mgr_ladder_d),
        .io_mgr_ladder_p                (io_mgr_ladder_p),
        .io_mgr_ladder_q                (io_mgr_ladder_q),
        .io_mgr_ladder_done             (io_mgr_ladder_done),
        
        .mmm_ena_x                      (mmm_ena_x),
        .mmm_ena_y                      (mmm_ena_y),
        .mmm_rdy_x                      (mmm_rdy_x),
        .mmm_rdy_y                      (mmm_rdy_y),
        .mmm_word_index_last_x          (mmm_word_index_last_x),
        .mmm_word_index_last_y          (mmm_word_index_last_y),
        .mmm_word_index_last_minus1_x   (mmm_word_index_last_minus1_x),
        .mmm_word_index_last_minus1_y   (mmm_word_index_last_minus1_y),
        .mmm_ladder_mode_x              (mmm_ladder_mode_x),
        .mmm_ladder_mode_y              (mmm_ladder_mode_y),
        .mmm_sel_wide_in_x              (mmm_sel_wide_in_x),
        .mmm_sel_wide_in_y              (mmm_sel_wide_in_y),
        .mmm_sel_narrow_in_x            (mmm_sel_narrow_in_x),
        .mmm_sel_narrow_in_y            (mmm_sel_narrow_in_y),
        .mmm_force_unity_b_x            (mmm_force_unity_b_x),
        .mmm_force_unity_b_y            (mmm_force_unity_b_y),
        .mmm_only_reduce_x              (mmm_only_reduce_x),
        .mmm_only_reduce_y              (mmm_only_reduce_y),
        .mmm_just_multiply_x            (mmm_just_multiply_x),
        .mmm_just_multiply_y            (mmm_just_multiply_y),
        
        .rdct_word_index_last_x         (rdct_word_index_last_x),
        .rdct_word_index_last_y         (rdct_word_index_last_y),
        .rdct_sel_wide_out_x            (rdct_sel_wide_out_x),
        .rdct_sel_wide_out_y            (rdct_sel_wide_out_y),
        .rdct_sel_narrow_out_x          (rdct_sel_narrow_out_x),
        .rdct_sel_narrow_out_y          (rdct_sel_narrow_out_y),
        
        .wrk_ena                        (wrk_ena),
        .wrk_rdy                        (wrk_rdy),
        .wrk_sel_wide_in                (wrk_sel_wide_in),
        .wrk_sel_wide_out               (wrk_sel_wide_out),
        .wrk_sel_narrow_in              (wrk_sel_narrow_in),
        .wrk_sel_narrow_out             (wrk_sel_narrow_out),
        .wrk_word_index_last            (wrk_word_index_last),
        .wrk_word_index_last_half       (wrk_word_index_last_half),
        .wrk_opcode                     (wrk_opcode)
    );


    //
    // Storage Interfaces (X, Y)
    //
    wire                                     wr_wide_xy_ena_x;        //
    wire [                 BANK_ADDR_W -1:0] wr_wide_xy_bank_x;       //
    wire [                 OP_ADDR_W   -1:0] wr_wide_xy_addr_x;       //
    wire [                 WORD_EXT_W  -1:0] wr_wide_x_data_x;        //
    wire [                 WORD_EXT_W  -1:0] wr_wide_y_data_x;        //
                                                                      //
    wire                                     wr_narrow_xy_ena_x;      //
    wire [                 BANK_ADDR_W -1:0] wr_narrow_xy_bank_x;     //
    wire [                 OP_ADDR_W   -1:0] wr_narrow_xy_addr_x;     //
    wire [                 WORD_EXT_W  -1:0] wr_narrow_x_data_x;      //
    wire [                 WORD_EXT_W  -1:0] wr_narrow_y_data_x;      //
                                                                      //
    wire                                     rd_wide_xy_ena_x;        //
    wire                                     rd_wide_xy_ena_aux_x;    //
    wire [                 BANK_ADDR_W -1:0] rd_wide_xy_bank_x;       //
    wire [                 BANK_ADDR_W -1:0] rd_wide_xy_bank_aux_x;   //
    wire [NUM_MULTS_HALF * OP_ADDR_W   -1:0] rd_wide_xy_addr_x;       //
    wire [                 OP_ADDR_W   -1:0] rd_wide_xy_addr_aux_x;   //
    wire [NUM_MULTS_HALF * WORD_EXT_W  -1:0] rd_wide_x_data_x;        //
    wire [NUM_MULTS_HALF * WORD_EXT_W  -1:0] rd_wide_y_data_x;        //
    wire [                 WORD_EXT_W  -1:0] rd_wide_x_data_aux_x;    //
    wire [                 WORD_EXT_W  -1:0] rd_wide_y_data_aux_x;    //
                                                                      //
    wire                                     rd_narrow_xy_ena_x;      //
    wire [                 BANK_ADDR_W -1:0] rd_narrow_xy_bank_x;     //
    wire [                 OP_ADDR_W   -1:0] rd_narrow_xy_addr_x;     //
    wire [                 WORD_EXT_W  -1:0] rd_narrow_x_data_x;      //
    wire [                 WORD_EXT_W  -1:0] rd_narrow_y_data_x;      //
                                                                      //
    wire                                     wrk_rd_wide_xy_ena_x;    //
    wire [                 BANK_ADDR_W -1:0] wrk_rd_wide_xy_bank_x;   //
    wire [                 OP_ADDR_W   -1:0] wrk_rd_wide_xy_addr_x;   //
    wire [                 WORD_EXT_W  -1:0] wrk_rd_wide_x_data_x;    //
    wire [                 WORD_EXT_W  -1:0] wrk_rd_wide_y_data_x;    //
                                                                      //
    wire                                     wrk_rd_narrow_xy_ena_x;  //
    wire [                 BANK_ADDR_W -1:0] wrk_rd_narrow_xy_bank_x; //
    wire [                 OP_ADDR_W   -1:0] wrk_rd_narrow_xy_addr_x; //
    wire [                 WORD_EXT_W  -1:0] wrk_rd_narrow_x_data_x;  //
    wire [                 WORD_EXT_W  -1:0] wrk_rd_narrow_y_data_x;  //
                                                                      //
    wire                                     wrk_wr_wide_xy_ena_x;    //
    wire [                 BANK_ADDR_W -1:0] wrk_wr_wide_xy_bank_x;   //
    wire [                 OP_ADDR_W   -1:0] wrk_wr_wide_xy_addr_x;   //
    wire [                 WORD_EXT_W  -1:0] wrk_wr_wide_x_data_x;    //
    wire [                 WORD_EXT_W  -1:0] wrk_wr_wide_y_data_x;    //
                                                                      //
    wire                                     wrk_wr_narrow_xy_ena_x;  //
    wire [                 BANK_ADDR_W -1:0] wrk_wr_narrow_xy_bank_x; //
    wire [                 OP_ADDR_W   -1:0] wrk_wr_narrow_xy_addr_x; //
    wire [                 WORD_EXT_W  -1:0] wrk_wr_narrow_x_data_x;  //
    wire [                 WORD_EXT_W  -1:0] wrk_wr_narrow_y_data_x;  //
                                                                      //
    wire                                     io_wide_xy_ena_x;        //
    wire [                 BANK_ADDR_W -1:0] io_wide_xy_bank_x;       //
    wire [                 OP_ADDR_W   -1:0] io_wide_xy_addr_x;       //
    wire [                 WORD_EXT_W  -1:0] io_wide_x_data_x;        //
    wire [                 WORD_EXT_W  -1:0] io_wide_y_data_x;        //
                                                                      //
    wire                                     io_narrow_xy_ena_x;      //
    wire [                 BANK_ADDR_W -1:0] io_narrow_xy_bank_x;     //
    wire [                 OP_ADDR_W   -1:0] io_narrow_xy_addr_x;     //
    wire [                 WORD_EXT_W  -1:0] io_narrow_x_data_x;      //
    wire [                 WORD_EXT_W  -1:0] io_narrow_y_data_x;      //
                                                                      //
    wire                                     wr_wide_xy_ena_y;        //
    wire [                 BANK_ADDR_W -1:0] wr_wide_xy_bank_y;       //
    wire [                 OP_ADDR_W   -1:0] wr_wide_xy_addr_y;       //
    wire [                 WORD_EXT_W  -1:0] wr_wide_x_data_y;        //
    wire [                 WORD_EXT_W  -1:0] wr_wide_y_data_y;        //
                                                                      //
    wire                                     wr_narrow_xy_ena_y;      //
    wire [                 BANK_ADDR_W -1:0] wr_narrow_xy_bank_y;     //
    wire [                 OP_ADDR_W   -1:0] wr_narrow_xy_addr_y;     //
    wire [                 WORD_EXT_W  -1:0] wr_narrow_x_data_y;      //
    wire [                 WORD_EXT_W  -1:0] wr_narrow_y_data_y;      //
                                                                      //
    wire                                     rd_wide_xy_ena_y;        //
    wire                                     rd_wide_xy_ena_aux_y;    //
    wire [                 BANK_ADDR_W -1:0] rd_wide_xy_bank_y;       //
    wire [                 BANK_ADDR_W -1:0] rd_wide_xy_bank_aux_y;   //
    wire [NUM_MULTS_HALF * OP_ADDR_W   -1:0] rd_wide_xy_addr_y;       //
    wire [                 OP_ADDR_W   -1:0] rd_wide_xy_addr_aux_y;   //
    wire [NUM_MULTS_HALF * WORD_EXT_W  -1:0] rd_wide_x_data_y;        //
    wire [NUM_MULTS_HALF * WORD_EXT_W  -1:0] rd_wide_y_data_y;        //
    wire [                 WORD_EXT_W  -1:0] rd_wide_x_data_aux_y;    //
    wire [                 WORD_EXT_W  -1:0] rd_wide_y_data_aux_y;    //
                                                                      //
    wire                                     rd_narrow_xy_ena_y;      //
    wire [                 BANK_ADDR_W -1:0] rd_narrow_xy_bank_y;     //
    wire [                 OP_ADDR_W   -1:0] rd_narrow_xy_addr_y;     //
    wire [                 WORD_EXT_W  -1:0] rd_narrow_x_data_y;      //
    wire [                 WORD_EXT_W  -1:0] rd_narrow_y_data_y;      //
                                                                      //
    wire                                     wrk_rd_wide_xy_ena_y;    //
    wire [                 BANK_ADDR_W -1:0] wrk_rd_wide_xy_bank_y;   //
    wire [                 OP_ADDR_W   -1:0] wrk_rd_wide_xy_addr_y;   //
    wire [                 WORD_EXT_W  -1:0] wrk_rd_wide_x_data_y;    //
    wire [                 WORD_EXT_W  -1:0] wrk_rd_wide_y_data_y;    //
                                                                      //
    wire                                     wrk_rd_narrow_xy_ena_y;  //
    wire [                 BANK_ADDR_W -1:0] wrk_rd_narrow_xy_bank_y; //
    wire [                 OP_ADDR_W   -1:0] wrk_rd_narrow_xy_addr_y; //
    wire [                 WORD_EXT_W  -1:0] wrk_rd_narrow_x_data_y;  //
    wire [                 WORD_EXT_W  -1:0] wrk_rd_narrow_y_data_y;  //
                                                                      //
    wire                                     wrk_wr_wide_xy_ena_y;    //
    wire [                 BANK_ADDR_W -1:0] wrk_wr_wide_xy_bank_y;   //
    wire [                 OP_ADDR_W   -1:0] wrk_wr_wide_xy_addr_y;   //
    wire [                 WORD_EXT_W  -1:0] wrk_wr_wide_x_data_y;    //
    wire [                 WORD_EXT_W  -1:0] wrk_wr_wide_y_data_y;    //
                                                                      //
    wire                                     wrk_wr_narrow_xy_ena_y;  //
    wire [                 BANK_ADDR_W -1:0] wrk_wr_narrow_xy_bank_y; //
    wire [                 OP_ADDR_W   -1:0] wrk_wr_narrow_xy_addr_y; //
    wire [                 WORD_EXT_W  -1:0] wrk_wr_narrow_x_data_y;  //
    wire [                 WORD_EXT_W  -1:0] wrk_wr_narrow_y_data_y;  //
                                                                      //
    wire                                     io_wide_xy_ena_y;        //
    wire [                 BANK_ADDR_W -1:0] io_wide_xy_bank_y;       //
    wire [                 OP_ADDR_W   -1:0] io_wide_xy_addr_y;       //
    wire [                 WORD_EXT_W  -1:0] io_wide_x_data_y;        //
    wire [                 WORD_EXT_W  -1:0] io_wide_y_data_y;        //
                                                                      //
    wire                                     io_narrow_xy_ena_y;      //
    wire [                 BANK_ADDR_W -1:0] io_narrow_xy_bank_y;     //
    wire [                 OP_ADDR_W   -1:0] io_narrow_xy_addr_y;     //
    wire [                 WORD_EXT_W  -1:0] io_narrow_x_data_y;      //
    wire [                 WORD_EXT_W  -1:0] io_narrow_y_data_y;      //

    wire [                 WORD_W      -1:0] wrk_rd_narrow_x_data_x_lsb = wrk_rd_narrow_x_data_x[WORD_W-1:0];
    wire [                 WORD_W      -1:0] wrk_rd_narrow_y_data_x_lsb = wrk_rd_narrow_y_data_x[WORD_W-1:0];
    wire [                 WORD_W      -1:0] wrk_rd_narrow_x_data_y_lsb = wrk_rd_narrow_x_data_y[WORD_W-1:0];
    wire [                 WORD_W      -1:0] wrk_rd_narrow_y_data_y_lsb = wrk_rd_narrow_y_data_y[WORD_W-1:0];


    //
    // Recombinator Interfaces (X, Y)
    //
    wire [BANK_ADDR_W -1:0] rcmb_wide_xy_bank_x;
    wire [  OP_ADDR_W -1:0] rcmb_wide_xy_addr_x;
    wire [ WORD_EXT_W -1:0] rcmb_wide_x_data_x;
    wire [ WORD_EXT_W -1:0] rcmb_wide_y_data_x;
    wire                    rcmb_wide_xy_valid_x;

    wire [BANK_ADDR_W -1:0] rcmb_narrow_xy_bank_x;
    wire [  OP_ADDR_W -1:0] rcmb_narrow_xy_addr_x;
    wire [ WORD_EXT_W -1:0] rcmb_narrow_x_data_x;
    wire [ WORD_EXT_W -1:0] rcmb_narrow_y_data_x;
    wire                    rcmb_narrow_xy_valid_x;

    wire [BANK_ADDR_W -1:0] rcmb_final_xy_bank_x;
    wire [  OP_ADDR_W -1:0] rcmb_final_xy_addr_x;
    wire [ WORD_EXT_W -1:0] rcmb_final_x_data_x;
    wire [ WORD_EXT_W -1:0] rcmb_final_y_data_x;
    wire                    rcmb_final_xy_valid_x;

    wire [BANK_ADDR_W -1:0] rcmb_wide_xy_bank_y;
    wire [  OP_ADDR_W -1:0] rcmb_wide_xy_addr_y;
    wire [ WORD_EXT_W -1:0] rcmb_wide_x_data_y;
    wire [ WORD_EXT_W -1:0] rcmb_wide_y_data_y;
    wire                    rcmb_wide_xy_valid_y;

    wire [BANK_ADDR_W -1:0] rcmb_narrow_xy_bank_y;
    wire [  OP_ADDR_W -1:0] rcmb_narrow_xy_addr_y;
    wire [ WORD_EXT_W -1:0] rcmb_narrow_x_data_y;
    wire [ WORD_EXT_W -1:0] rcmb_narrow_y_data_y;
    wire                    rcmb_narrow_xy_valid_y;

    wire [BANK_ADDR_W -1:0] rcmb_final_xy_bank_y;
    wire [  OP_ADDR_W -1:0] rcmb_final_xy_addr_y;
    wire [ WORD_EXT_W -1:0] rcmb_final_x_data_y;
    wire [ WORD_EXT_W -1:0] rcmb_final_y_data_y;
    wire                    rcmb_final_xy_valid_y;
    
    
    //
    // Reductor Interfaces (X, Y)
    //
    wire [BANK_ADDR_W -1:0] rdct_wide_xy_bank_x;
    wire [  OP_ADDR_W -1:0] rdct_wide_xy_addr_x;
    wire [ WORD_EXT_W -1:0] rdct_wide_x_data_x;
    wire [ WORD_EXT_W -1:0] rdct_wide_y_data_x;
    wire                    rdct_wide_xy_valid_x;

    wire [BANK_ADDR_W -1:0] rdct_narrow_xy_bank_x;
    wire [  OP_ADDR_W -1:0] rdct_narrow_xy_addr_x;
    wire [ WORD_EXT_W -1:0] rdct_narrow_x_data_x;
    wire [ WORD_EXT_W -1:0] rdct_narrow_y_data_x;
    wire                    rdct_narrow_xy_valid_x;

    wire [BANK_ADDR_W -1:0] rdct_wide_xy_bank_y;
    wire [  OP_ADDR_W -1:0] rdct_wide_xy_addr_y;
    wire [ WORD_EXT_W -1:0] rdct_wide_x_data_y;
    wire [ WORD_EXT_W -1:0] rdct_wide_y_data_y;
    wire                    rdct_wide_xy_valid_y;

    wire [BANK_ADDR_W -1:0] rdct_narrow_xy_bank_y;
    wire [  OP_ADDR_W -1:0] rdct_narrow_xy_addr_y;
    wire [ WORD_EXT_W -1:0] rdct_narrow_x_data_y;
    wire [ WORD_EXT_W -1:0] rdct_narrow_y_data_y;
    wire                    rdct_narrow_xy_valid_y;


    //
    // I/O Interfaces
    //
    wire                                io_in_1_en;
    wire [BANK_ADDR_W + OP_ADDR_W -1:0] io_in_1_addr;
    wire [              WORD_W    -1:0] io_in_1_data;
    
    wire                                io_in_2_en;
    wire [BANK_ADDR_W + OP_ADDR_W -1:0] io_in_2_addr;
    wire [              WORD_W    -1:0] io_in_2_data;
    
    wire                                io_out_en;
    wire                                io_out_we;
    wire [BANK_ADDR_W + OP_ADDR_W -1:0] io_out_addr;
    wire [              WORD_W    -1:0] io_out_data;


    //
    // Storage Blocks (X, Y)
    //
    modexpng_storage_block storage_block_x
    (
        .clk                    (clk),
        .rst_n                  (rst_n),

        .wr_wide_xy_ena         (wr_wide_xy_ena_x),
        .wr_wide_xy_bank        (wr_wide_xy_bank_x),
        .wr_wide_xy_addr        (wr_wide_xy_addr_x),
        .wr_wide_x_din          (wr_wide_x_data_x),
        .wr_wide_y_din          (wr_wide_y_data_x),

        .wr_narrow_xy_ena       (wr_narrow_xy_ena_x),
        .wr_narrow_xy_bank      (wr_narrow_xy_bank_x),
        .wr_narrow_xy_addr      (wr_narrow_xy_addr_x),
        .wr_narrow_x_din        (wr_narrow_x_data_x),
        .wr_narrow_y_din        (wr_narrow_y_data_x),

        .rd_wide_xy_ena         (rd_wide_xy_ena_x),
        .rd_wide_xy_ena_aux     (rd_wide_xy_ena_aux_x),
        .rd_wide_xy_bank        (rd_wide_xy_bank_x),
        .rd_wide_xy_bank_aux    (rd_wide_xy_bank_aux_x),
        .rd_wide_xy_addr        (rd_wide_xy_addr_x),
        .rd_wide_xy_addr_aux    (rd_wide_xy_addr_aux_x),
        .rd_wide_x_dout         (rd_wide_x_data_x),
        .rd_wide_y_dout         (rd_wide_y_data_x),
        .rd_wide_x_dout_aux     (rd_wide_x_data_aux_x),
        .rd_wide_y_dout_aux     (rd_wide_y_data_aux_x),

        .rd_narrow_xy_ena       (rd_narrow_xy_ena_x),
        .rd_narrow_xy_bank      (rd_narrow_xy_bank_x),
        .rd_narrow_xy_addr      (rd_narrow_xy_addr_x),
        .rd_narrow_x_dout       (rd_narrow_x_data_x),
        .rd_narrow_y_dout       (rd_narrow_y_data_x),
        
        .wrk_wide_xy_ena        (wrk_rd_wide_xy_ena_x),
        .wrk_wide_xy_bank       (wrk_rd_wide_xy_bank_x),
        .wrk_wide_xy_addr       (wrk_rd_wide_xy_addr_x),
        .wrk_wide_x_dout        (wrk_rd_wide_x_data_x),
        .wrk_wide_y_dout        (wrk_rd_wide_y_data_x),
    
        .wrk_narrow_xy_ena      (wrk_rd_narrow_xy_ena_x),
        .wrk_narrow_xy_bank     (wrk_rd_narrow_xy_bank_x),
        .wrk_narrow_xy_addr     (wrk_rd_narrow_xy_addr_x),
        .wrk_narrow_x_dout      (wrk_rd_narrow_x_data_x),
        .wrk_narrow_y_dout      (wrk_rd_narrow_y_data_x)
    );

    modexpng_storage_block storage_block_y
    (
        .clk                    (clk),
        .rst_n                  (rst_n),

        .wr_wide_xy_ena         (wr_wide_xy_ena_y),
        .wr_wide_xy_bank        (wr_wide_xy_bank_y),
        .wr_wide_xy_addr        (wr_wide_xy_addr_y),
        .wr_wide_x_din          (wr_wide_x_data_y),
        .wr_wide_y_din          (wr_wide_y_data_y),

        .wr_narrow_xy_ena       (wr_narrow_xy_ena_y),
        .wr_narrow_xy_bank      (wr_narrow_xy_bank_y),
        .wr_narrow_xy_addr      (wr_narrow_xy_addr_y),
        .wr_narrow_x_din        (wr_narrow_x_data_y),
        .wr_narrow_y_din        (wr_narrow_y_data_y),

        .rd_wide_xy_ena         (rd_wide_xy_ena_y),
        .rd_wide_xy_ena_aux     (rd_wide_xy_ena_aux_y),
        .rd_wide_xy_bank        (rd_wide_xy_bank_y),
        .rd_wide_xy_bank_aux    (rd_wide_xy_bank_aux_y),
        .rd_wide_xy_addr        (rd_wide_xy_addr_y),
        .rd_wide_xy_addr_aux    (rd_wide_xy_addr_aux_y),
        .rd_wide_x_dout         (rd_wide_x_data_y),
        .rd_wide_y_dout         (rd_wide_y_data_y),
        .rd_wide_x_dout_aux     (rd_wide_x_data_aux_y),
        .rd_wide_y_dout_aux     (rd_wide_y_data_aux_y),

        .rd_narrow_xy_ena       (rd_narrow_xy_ena_y),
        .rd_narrow_xy_bank      (rd_narrow_xy_bank_y),
        .rd_narrow_xy_addr      (rd_narrow_xy_addr_y),
        .rd_narrow_x_dout       (rd_narrow_x_data_y),
        .rd_narrow_y_dout       (rd_narrow_y_data_y),
        
        .wrk_wide_xy_ena        (wrk_rd_wide_xy_ena_y),
        .wrk_wide_xy_bank       (wrk_rd_wide_xy_bank_y),
        .wrk_wide_xy_addr       (wrk_rd_wide_xy_addr_y),
        .wrk_wide_x_dout        (wrk_rd_wide_x_data_y),
        .wrk_wide_y_dout        (wrk_rd_wide_y_data_y),
    
        .wrk_narrow_xy_ena      (wrk_rd_narrow_xy_ena_y),
        .wrk_narrow_xy_bank     (wrk_rd_narrow_xy_bank_y),
        .wrk_narrow_xy_addr     (wrk_rd_narrow_xy_addr_y),
        .wrk_narrow_x_dout      (wrk_rd_narrow_x_data_y),
        .wrk_narrow_y_dout      (wrk_rd_narrow_y_data_y)

    );

    
    //
    // Storage Managers (X, Y)
    //
    modexpng_storage_manager storage_manager_x
    (
        .clk                    (clk),
        .rst_n                  (rst_n),
        
        .wr_wide_xy_ena         (wr_wide_xy_ena_x),
        .wr_wide_xy_bank        (wr_wide_xy_bank_x),
        .wr_wide_xy_addr        (wr_wide_xy_addr_x),
        .wr_wide_x_dout         (wr_wide_x_data_x),
        .wr_wide_y_dout         (wr_wide_y_data_x),
    
        .wr_narrow_xy_ena       (wr_narrow_xy_ena_x),
        .wr_narrow_xy_bank      (wr_narrow_xy_bank_x),
        .wr_narrow_xy_addr      (wr_narrow_xy_addr_x),
        .wr_narrow_x_dout       (wr_narrow_x_data_x),
        .wr_narrow_y_dout       (wr_narrow_y_data_x),
        
        .io_wide_xy_ena         (io_wide_xy_ena_x),
        .io_wide_xy_bank        (io_wide_xy_bank_x),
        .io_wide_xy_addr        (io_wide_xy_addr_x),
        .io_wide_x_din          (io_wide_x_data_x),
        .io_wide_y_din          (io_wide_y_data_x),
    
        .io_narrow_xy_ena       (io_narrow_xy_ena_x),
        .io_narrow_xy_bank      (io_narrow_xy_bank_x),
        .io_narrow_xy_addr      (io_narrow_xy_addr_x),
        .io_narrow_x_din        (io_narrow_x_data_x),
        .io_narrow_y_din        (io_narrow_y_data_x),
        
        .rcmb_wide_xy_bank      (rcmb_wide_xy_bank_x),
        .rcmb_wide_xy_addr      (rcmb_wide_xy_addr_x),
        .rcmb_wide_x_din        (rcmb_wide_x_data_x),
        .rcmb_wide_y_din        (rcmb_wide_y_data_x),
        .rcmb_wide_xy_ena       (rcmb_wide_xy_valid_x),

        .rcmb_narrow_xy_bank    (rcmb_narrow_xy_bank_x),
        .rcmb_narrow_xy_addr    (rcmb_narrow_xy_addr_x),
        .rcmb_narrow_x_din      (rcmb_narrow_x_data_x),
        .rcmb_narrow_y_din      (rcmb_narrow_y_data_x),
        .rcmb_narrow_xy_ena     (rcmb_narrow_xy_valid_x),
        
        .rdct_wide_xy_bank      (rdct_wide_xy_bank_x),
        .rdct_wide_xy_addr      (rdct_wide_xy_addr_x),
        .rdct_wide_x_din        (rdct_wide_x_data_x),
        .rdct_wide_y_din        (rdct_wide_y_data_x),
        .rdct_wide_xy_valid     (rdct_wide_xy_valid_x),

        .rdct_narrow_xy_bank    (rdct_narrow_xy_bank_x),
        .rdct_narrow_xy_addr    (rdct_narrow_xy_addr_x),
        .rdct_narrow_x_din      (rdct_narrow_x_data_x),
        .rdct_narrow_y_din      (rdct_narrow_y_data_x),
        .rdct_narrow_xy_valid   (rdct_narrow_xy_valid_x),
        
        .wrk_wide_xy_ena        (wrk_wr_wide_xy_ena_x),
        .wrk_wide_xy_bank       (wrk_wr_wide_xy_bank_x),
        .wrk_wide_xy_addr       (wrk_wr_wide_xy_addr_x),
        .wrk_wide_x_din         (wrk_wr_wide_x_data_x),
        .wrk_wide_y_din         (wrk_wr_wide_y_data_x),

        .wrk_narrow_xy_ena      (wrk_wr_narrow_xy_ena_x),
        .wrk_narrow_xy_bank     (wrk_wr_narrow_xy_bank_x),
        .wrk_narrow_xy_addr     (wrk_wr_narrow_xy_addr_x),
        .wrk_narrow_x_din       (wrk_wr_narrow_x_data_x),
        .wrk_narrow_y_din       (wrk_wr_narrow_y_data_x)
    );

    modexpng_storage_manager storage_manager_y
    (
        .clk                    (clk),
        .rst_n                  (rst_n),
        
        .wr_wide_xy_ena         (wr_wide_xy_ena_y),
        .wr_wide_xy_bank        (wr_wide_xy_bank_y),
        .wr_wide_xy_addr        (wr_wide_xy_addr_y),
        .wr_wide_x_dout         (wr_wide_x_data_y),
        .wr_wide_y_dout         (wr_wide_y_data_y),
    
        .wr_narrow_xy_ena       (wr_narrow_xy_ena_y),
        .wr_narrow_xy_bank      (wr_narrow_xy_bank_y),
        .wr_narrow_xy_addr      (wr_narrow_xy_addr_y),
        .wr_narrow_x_dout       (wr_narrow_x_data_y),
        .wr_narrow_y_dout       (wr_narrow_y_data_y),
        
        .io_wide_xy_ena         (io_wide_xy_ena_y),
        .io_wide_xy_bank        (io_wide_xy_bank_y),
        .io_wide_xy_addr        (io_wide_xy_addr_y),
        .io_wide_x_din          (io_wide_x_data_y),
        .io_wide_y_din          (io_wide_y_data_y),
    
        .io_narrow_xy_ena       (io_narrow_xy_ena_y),
        .io_narrow_xy_bank      (io_narrow_xy_bank_y),
        .io_narrow_xy_addr      (io_narrow_xy_addr_y),
        .io_narrow_x_din        (io_narrow_x_data_y),
        .io_narrow_y_din        (io_narrow_y_data_y),
        
        .rcmb_wide_xy_bank      (rcmb_wide_xy_bank_y),
        .rcmb_wide_xy_addr      (rcmb_wide_xy_addr_y),
        .rcmb_wide_x_din        (rcmb_wide_x_data_y),
        .rcmb_wide_y_din        (rcmb_wide_y_data_y),
        .rcmb_wide_xy_ena       (rcmb_wide_xy_valid_y),

        .rcmb_narrow_xy_bank    (rcmb_narrow_xy_bank_y),
        .rcmb_narrow_xy_addr    (rcmb_narrow_xy_addr_y),
        .rcmb_narrow_x_din      (rcmb_narrow_x_data_y),
        .rcmb_narrow_y_din      (rcmb_narrow_y_data_y),
        .rcmb_narrow_xy_ena     (rcmb_narrow_xy_valid_y),
        
        .rdct_wide_xy_bank      (rdct_wide_xy_bank_y),
        .rdct_wide_xy_addr      (rdct_wide_xy_addr_y),
        .rdct_wide_x_din        (rdct_wide_x_data_y),
        .rdct_wide_y_din        (rdct_wide_y_data_y),
        .rdct_wide_xy_valid     (rdct_wide_xy_valid_y),

        .rdct_narrow_xy_bank    (rdct_narrow_xy_bank_y),
        .rdct_narrow_xy_addr    (rdct_narrow_xy_addr_y),
        .rdct_narrow_x_din      (rdct_narrow_x_data_y),
        .rdct_narrow_y_din      (rdct_narrow_y_data_y),
        .rdct_narrow_xy_valid   (rdct_narrow_xy_valid_y),
        
        .wrk_wide_xy_ena        (wrk_wr_wide_xy_ena_y),
        .wrk_wide_xy_bank       (wrk_wr_wide_xy_bank_y),
        .wrk_wide_xy_addr       (wrk_wr_wide_xy_addr_y),
        .wrk_wide_x_din         (wrk_wr_wide_x_data_y),
        .wrk_wide_y_din         (wrk_wr_wide_y_data_y),

        .wrk_narrow_xy_ena      (wrk_wr_narrow_xy_ena_y),
        .wrk_narrow_xy_bank     (wrk_wr_narrow_xy_bank_y),
        .wrk_narrow_xy_addr     (wrk_wr_narrow_xy_addr_y),
        .wrk_narrow_x_din       (wrk_wr_narrow_x_data_y),
        .wrk_narrow_y_din       (wrk_wr_narrow_y_data_y)
    );


    //
    // I/O Block
    //    
    modexpng_io_block io_block
    (
        .clk            (clk),
        .clk_bus        (clk_bus),
        
        .rst_n          (rst_n),
        
        .bus_cs         (bus_cs),
        .bus_we         (bus_we),
        .bus_addr       (bus_addr),
        .bus_data_wr    (bus_data_wr),
        .bus_data_rd    (bus_data_rd),
    
        .in_1_en        (io_in_1_en),
        .in_1_addr      (io_in_1_addr),
        .in_1_dout      (io_in_1_data),
    
        .in_2_en        (io_in_2_en),
        .in_2_addr      (io_in_2_addr),
        .in_2_dout      (io_in_2_data),
    
        .out_en         (io_out_en),
        .out_we         (io_out_we),
        .out_addr       (io_out_addr),
        .out_din        (io_out_data)
    );


    //
    // IO Manager
    //    
    modexpng_io_manager io_manager
    (
        .clk                        (clk),
        .rst_n                      (rst_n),
    
        .ena                        (io_mgr_ena),
        .rdy                        (io_mgr_rdy),
    
        .sel_crt                    (io_mgr_sel_crt),
        .sel_aux                    (io_mgr_sel_aux),
        .sel_in                     (io_mgr_sel_in),
        .sel_out                    (io_mgr_sel_out),
        
        .opcode                     (io_mgr_opcode),
        
        .word_index_last            (io_mgr_word_index_last),
    
        .io_wide_xy_ena_x           (io_wide_xy_ena_x),
        .io_wide_xy_bank_x          (io_wide_xy_bank_x),
        .io_wide_xy_addr_x          (io_wide_xy_addr_x),
        .io_wide_x_din_x            (io_wide_x_data_x),
        .io_wide_y_din_x            (io_wide_y_data_x),

        .io_narrow_xy_ena_x         (io_narrow_xy_ena_x),
        .io_narrow_xy_bank_x        (io_narrow_xy_bank_x),
        .io_narrow_xy_addr_x        (io_narrow_xy_addr_x),
        .io_narrow_x_din_x          (io_narrow_x_data_x),
        .io_narrow_y_din_x          (io_narrow_y_data_x),

        .io_wide_xy_ena_y           (io_wide_xy_ena_y),
        .io_wide_xy_bank_y          (io_wide_xy_bank_y),
        .io_wide_xy_addr_y          (io_wide_xy_addr_y),
        .io_wide_x_din_y            (io_wide_x_data_y),
        .io_wide_y_din_y            (io_wide_y_data_y),

        .io_narrow_xy_ena_y         (io_narrow_xy_ena_y),
        .io_narrow_xy_bank_y        (io_narrow_xy_bank_y),
        .io_narrow_xy_addr_y        (io_narrow_xy_addr_y),
        .io_narrow_x_din_y          (io_narrow_x_data_y),
        .io_narrow_y_din_y          (io_narrow_y_data_y),
    
        .io_in_1_en                 (io_in_1_en),
        .io_in_1_addr               (io_in_1_addr),
        .io_in_1_din                (io_in_1_data),
    
        .io_in_2_en                 (io_in_2_en),
        .io_in_2_addr               (io_in_2_addr),
        .io_in_2_din                (io_in_2_data),
    
        .io_out_en                  (io_out_en),
        .io_out_we                  (io_out_we),
        .io_out_addr                (io_out_addr),
        .io_out_dout                (io_out_data),
        
        .wrk_narrow_x_din_x_lsb     (wrk_rd_narrow_x_data_x_lsb),
        .wrk_narrow_y_din_x_lsb     (wrk_rd_narrow_y_data_x_lsb),
        .wrk_narrow_x_din_y_lsb     (wrk_rd_narrow_x_data_y_lsb),
        .wrk_narrow_y_din_y_lsb     (wrk_rd_narrow_y_data_y_lsb),
        
        .ladder_steps               (io_mgr_ladder_steps),
        .ladder_d                   (io_mgr_ladder_d),
        .ladder_p                   (io_mgr_ladder_p),
        .ladder_q                   (io_mgr_ladder_q),
        .ladder_done                (io_mgr_ladder_done)
    );


    //
    // Multipliers (X, Y)
    //     
    modexpng_mmm_dual mmm_x
    (
        .clk                        (clk),
        .rst_n                      (rst_n),
        
        .ena                        (mmm_ena_x),
        .rdy                        (mmm_rdy_x),
        
        .ladder_mode                (mmm_ladder_mode_x),
        .word_index_last            (mmm_word_index_last_x),
        .word_index_last_minus1     (mmm_word_index_last_minus1_x),
        .force_unity_b              (mmm_force_unity_b_x),
        .only_reduce                (mmm_only_reduce_x),
        .just_multiply              (mmm_just_multiply_x),
        
        .sel_wide_in                (mmm_sel_wide_in_x),
        .sel_narrow_in              (mmm_sel_narrow_in_x),
        
        .rd_wide_xy_ena             (rd_wide_xy_ena_x),
        .rd_wide_xy_ena_aux         (rd_wide_xy_ena_aux_x),
        .rd_wide_xy_bank            (rd_wide_xy_bank_x),
        .rd_wide_xy_bank_aux        (rd_wide_xy_bank_aux_x),
        .rd_wide_xy_addr            (rd_wide_xy_addr_x),
        .rd_wide_xy_addr_aux        (rd_wide_xy_addr_aux_x),
        .rd_wide_x_din              (rd_wide_x_data_x),
        .rd_wide_y_din              (rd_wide_y_data_x),
        .rd_wide_x_din_aux          (rd_wide_x_data_aux_x),
        .rd_wide_y_din_aux          (rd_wide_y_data_aux_x),

        .rd_narrow_xy_ena           (rd_narrow_xy_ena_x),
        .rd_narrow_xy_bank          (rd_narrow_xy_bank_x),
        .rd_narrow_xy_addr          (rd_narrow_xy_addr_x),
        .rd_narrow_x_din            (rd_narrow_x_data_x),
        .rd_narrow_y_din            (rd_narrow_y_data_x),
        
        .rcmb_wide_xy_bank          (rcmb_wide_xy_bank_x),
        .rcmb_wide_xy_addr          (rcmb_wide_xy_addr_x),
        .rcmb_wide_x_dout           (rcmb_wide_x_data_x),
        .rcmb_wide_y_dout           (rcmb_wide_y_data_x),
        .rcmb_wide_xy_valid         (rcmb_wide_xy_valid_x),

        .rcmb_narrow_xy_bank        (rcmb_narrow_xy_bank_x),
        .rcmb_narrow_xy_addr        (rcmb_narrow_xy_addr_x),
        .rcmb_narrow_x_dout         (rcmb_narrow_x_data_x),
        .rcmb_narrow_y_dout         (rcmb_narrow_y_data_x),
        .rcmb_narrow_xy_valid       (rcmb_narrow_xy_valid_x),
        
        .rcmb_xy_bank               (rcmb_final_xy_bank_x),
        .rcmb_xy_addr               (rcmb_final_xy_addr_x),
        .rcmb_x_dout                (rcmb_final_x_data_x),
        .rcmb_y_dout                (rcmb_final_y_data_x),
        .rcmb_xy_valid              (rcmb_final_xy_valid_x),
        
        .rdct_ena                   (rdct_ena_x),
        .rdct_rdy                   (rdct_rdy_x)
    );

    modexpng_mmm_dual mmm_y
    (
        .clk                        (clk),
        .rst_n                      (rst_n),
        
        .ena                        (mmm_ena_y),
        .rdy                        (mmm_rdy_y),
        
        .ladder_mode                (mmm_ladder_mode_y),
        .word_index_last            (mmm_word_index_last_y),
        .word_index_last_minus1     (mmm_word_index_last_minus1_y),
        .force_unity_b              (mmm_force_unity_b_y),
        .only_reduce                (mmm_only_reduce_y),
        .just_multiply              (mmm_just_multiply_y),
        
        .sel_wide_in                (mmm_sel_wide_in_y),
        .sel_narrow_in              (mmm_sel_narrow_in_y),
        
        .rd_wide_xy_ena             (rd_wide_xy_ena_y),
        .rd_wide_xy_ena_aux         (rd_wide_xy_ena_aux_y),
        .rd_wide_xy_bank            (rd_wide_xy_bank_y),
        .rd_wide_xy_bank_aux        (rd_wide_xy_bank_aux_y),
        .rd_wide_xy_addr            (rd_wide_xy_addr_y),
        .rd_wide_xy_addr_aux        (rd_wide_xy_addr_aux_y),
        .rd_wide_x_din              (rd_wide_x_data_y),
        .rd_wide_y_din              (rd_wide_y_data_y),
        .rd_wide_x_din_aux          (rd_wide_x_data_aux_y),
        .rd_wide_y_din_aux          (rd_wide_y_data_aux_y),

        .rd_narrow_xy_ena           (rd_narrow_xy_ena_y),
        .rd_narrow_xy_bank          (rd_narrow_xy_bank_y),
        .rd_narrow_xy_addr          (rd_narrow_xy_addr_y),
        .rd_narrow_x_din            (rd_narrow_x_data_y),
        .rd_narrow_y_din            (rd_narrow_y_data_y),
        
        .rcmb_wide_xy_bank          (rcmb_wide_xy_bank_y),
        .rcmb_wide_xy_addr          (rcmb_wide_xy_addr_y),
        .rcmb_wide_x_dout           (rcmb_wide_x_data_y),
        .rcmb_wide_y_dout           (rcmb_wide_y_data_y),
        .rcmb_wide_xy_valid         (rcmb_wide_xy_valid_y),

        .rcmb_narrow_xy_bank        (rcmb_narrow_xy_bank_y),
        .rcmb_narrow_xy_addr        (rcmb_narrow_xy_addr_y),
        .rcmb_narrow_x_dout         (rcmb_narrow_x_data_y),
        .rcmb_narrow_y_dout         (rcmb_narrow_y_data_y),
        .rcmb_narrow_xy_valid       (rcmb_narrow_xy_valid_y),
        
        .rcmb_xy_bank               (rcmb_final_xy_bank_y),
        .rcmb_xy_addr               (rcmb_final_xy_addr_y),
        .rcmb_x_dout                (rcmb_final_x_data_y),
        .rcmb_y_dout                (rcmb_final_y_data_y),
        .rcmb_xy_valid              (rcmb_final_xy_valid_y),
        
        .rdct_ena                   (rdct_ena_y),
        .rdct_rdy                   (rdct_rdy_y)
    );

    //
    // Reductors (X, Y)
    //        
    modexpng_reductor reductor_x
    (
        .clk                    (clk),
        .rst_n                  (rst_n),
        
        .ena                    (rdct_ena_x),
        .rdy                    (rdct_rdy_x),
        
        .word_index_last        (rdct_word_index_last_x),
        
        .sel_wide_out           (rdct_sel_wide_out_x),
        .sel_narrow_out         (rdct_sel_narrow_out_x),

        //.rd_wide_xy_addr_aux    (rd_wide_xy_addr_aux_x),
        //.rd_wide_xy_bank_aux    (rd_wide_xy_bank_aux_x),
        .rd_wide_x_din_aux      (rd_wide_x_data_aux_x),
        .rd_wide_y_din_aux      (rd_wide_y_data_aux_x),
        
        .rcmb_final_xy_bank     (rcmb_final_xy_bank_x),
        .rcmb_final_xy_addr     (rcmb_final_xy_addr_x),
        .rcmb_final_x_din       (rcmb_final_x_data_x),
        .rcmb_final_y_din       (rcmb_final_y_data_x),
        .rcmb_final_xy_valid    (rcmb_final_xy_valid_x),
        
        .rdct_wide_xy_bank      (rdct_wide_xy_bank_x),
        .rdct_wide_xy_addr      (rdct_wide_xy_addr_x),
        .rdct_wide_x_dout       (rdct_wide_x_data_x),
        .rdct_wide_y_dout       (rdct_wide_y_data_x),
        .rdct_wide_xy_valid     (rdct_wide_xy_valid_x),
        
        .rdct_narrow_xy_bank    (rdct_narrow_xy_bank_x),
        .rdct_narrow_xy_addr    (rdct_narrow_xy_addr_x),
        .rdct_narrow_x_dout     (rdct_narrow_x_data_x),
        .rdct_narrow_y_dout     (rdct_narrow_y_data_x),
        .rdct_narrow_xy_valid   (rdct_narrow_xy_valid_x)
    );

    modexpng_reductor reductor_y
    (
        .clk                    (clk),
        .rst_n                  (rst_n),
        
        .ena                    (rdct_ena_y),
        .rdy                    (rdct_rdy_y),
        
        .word_index_last        (rdct_word_index_last_y),

        .sel_wide_out           (rdct_sel_wide_out_y),
        .sel_narrow_out         (rdct_sel_narrow_out_y),
        
        //.rd_wide_xy_addr_aux    (rd_wide_xy_addr_aux_y),
        //.rd_wide_xy_bank_aux    (rd_wide_xy_bank_aux_y),
        .rd_wide_x_din_aux      (rd_wide_x_data_aux_y),
        .rd_wide_y_din_aux      (rd_wide_y_data_aux_y),
        
        .rcmb_final_xy_bank     (rcmb_final_xy_bank_y),
        .rcmb_final_xy_addr     (rcmb_final_xy_addr_y),
        .rcmb_final_x_din       (rcmb_final_x_data_y),
        .rcmb_final_y_din       (rcmb_final_y_data_y),
        .rcmb_final_xy_valid    (rcmb_final_xy_valid_y),
        
        .rdct_wide_xy_bank      (rdct_wide_xy_bank_y),
        .rdct_wide_xy_addr      (rdct_wide_xy_addr_y),
        .rdct_wide_x_dout       (rdct_wide_x_data_y),
        .rdct_wide_y_dout       (rdct_wide_y_data_y),
        .rdct_wide_xy_valid     (rdct_wide_xy_valid_y),
        
        .rdct_narrow_xy_bank    (rdct_narrow_xy_bank_y),
        .rdct_narrow_xy_addr    (rdct_narrow_xy_addr_y),
        .rdct_narrow_x_dout     (rdct_narrow_x_data_y),
        .rdct_narrow_y_dout     (rdct_narrow_y_data_y),
        .rdct_narrow_xy_valid   (rdct_narrow_xy_valid_y)
    );


    //
    // General Worker
    //    
    modexpng_general_worker general_worker
    (
        .clk                        (clk),
        .rst_n                      (rst_n),
        
        .ena                        (wrk_ena),
        .rdy                        (wrk_rdy),
        
        .sel_narrow_in              (wrk_sel_narrow_in),
        .sel_narrow_out             (wrk_sel_narrow_out),
        .sel_wide_in                (wrk_sel_wide_in),
        .sel_wide_out               (wrk_sel_wide_out),
        
        .opcode                     (wrk_opcode),
        
        .word_index_last            (wrk_word_index_last),
        .word_index_last_half       (wrk_word_index_last_half),
        
        .wrk_rd_wide_xy_ena_x       (wrk_rd_wide_xy_ena_x),
        .wrk_rd_wide_xy_bank_x      (wrk_rd_wide_xy_bank_x),
        .wrk_rd_wide_xy_addr_x      (wrk_rd_wide_xy_addr_x),
        .wrk_rd_wide_x_din_x        (wrk_rd_wide_x_data_x),
        .wrk_rd_wide_y_din_x        (wrk_rd_wide_y_data_x),
    
        .wrk_rd_narrow_xy_ena_x     (wrk_rd_narrow_xy_ena_x),
        .wrk_rd_narrow_xy_bank_x    (wrk_rd_narrow_xy_bank_x),
        .wrk_rd_narrow_xy_addr_x    (wrk_rd_narrow_xy_addr_x),
        .wrk_rd_narrow_x_din_x      (wrk_rd_narrow_x_data_x),
        .wrk_rd_narrow_y_din_x      (wrk_rd_narrow_y_data_x),
    
        .wrk_rd_wide_xy_ena_y       (wrk_rd_wide_xy_ena_y),
        .wrk_rd_wide_xy_bank_y      (wrk_rd_wide_xy_bank_y),
        .wrk_rd_wide_xy_addr_y      (wrk_rd_wide_xy_addr_y),
        .wrk_rd_wide_x_din_y        (wrk_rd_wide_x_data_y),
        .wrk_rd_wide_y_din_y        (wrk_rd_wide_y_data_y),
    
        .wrk_rd_narrow_xy_ena_y     (wrk_rd_narrow_xy_ena_y),
        .wrk_rd_narrow_xy_bank_y    (wrk_rd_narrow_xy_bank_y),
        .wrk_rd_narrow_xy_addr_y    (wrk_rd_narrow_xy_addr_y),
        .wrk_rd_narrow_x_din_y      (wrk_rd_narrow_x_data_y),
        .wrk_rd_narrow_y_din_y      (wrk_rd_narrow_y_data_y),
        
        .wrk_wr_wide_xy_ena_x       (wrk_wr_wide_xy_ena_x),
        .wrk_wr_wide_xy_bank_x      (wrk_wr_wide_xy_bank_x),
        .wrk_wr_wide_xy_addr_x      (wrk_wr_wide_xy_addr_x),
        .wrk_wr_wide_x_dout_x       (wrk_wr_wide_x_data_x),
        .wrk_wr_wide_y_dout_x       (wrk_wr_wide_y_data_x),
    
        .wrk_wr_narrow_xy_ena_x     (wrk_wr_narrow_xy_ena_x),
        .wrk_wr_narrow_xy_bank_x    (wrk_wr_narrow_xy_bank_x),
        .wrk_wr_narrow_xy_addr_x    (wrk_wr_narrow_xy_addr_x),
        .wrk_wr_narrow_x_dout_x     (wrk_wr_narrow_x_data_x),
        .wrk_wr_narrow_y_dout_x     (wrk_wr_narrow_y_data_x),
    
        .wrk_wr_wide_xy_ena_y       (wrk_wr_wide_xy_ena_y),
        .wrk_wr_wide_xy_bank_y      (wrk_wr_wide_xy_bank_y),
        .wrk_wr_wide_xy_addr_y      (wrk_wr_wide_xy_addr_y),
        .wrk_wr_wide_x_dout_y       (wrk_wr_wide_x_data_y),
        .wrk_wr_wide_y_dout_y       (wrk_wr_wide_y_data_y),
    
        .wrk_wr_narrow_xy_ena_y     (wrk_wr_narrow_xy_ena_y),
        .wrk_wr_narrow_xy_bank_y    (wrk_wr_narrow_xy_bank_y),
        .wrk_wr_narrow_xy_addr_y    (wrk_wr_narrow_xy_addr_y),
        .wrk_wr_narrow_x_dout_y     (wrk_wr_narrow_x_data_y),
        .wrk_wr_narrow_y_dout_y     (wrk_wr_narrow_y_data_y)
    );


    //
    // Optional Debug Facility
    //
    `ifdef MODEXPNG_ENABLE_DEBUG
    `include "modexpng_core_top_debug.vh"
    `endif
      

endmodule