aboutsummaryrefslogblamecommitdiff
path: root/rtl/_modexpng_reductor.v
blob: 25cf394c972f6ce85c476009424c19eaf54e6f9e (plain) (tree)



























































































































































































































































                                                                                                                         
module modexpng_reductor
(
    clk, rst,
    ena, rdy,
    word_index_last,
    rd_wide_xy_addr_aux, rd_wide_xy_bank_aux, rd_wide_x_dout_aux, rd_wide_y_dout_aux,
    rcmb_final_xy_bank, rcmb_final_xy_addr, rcmb_final_x_dout, rcmb_final_y_dout, rcmb_final_xy_valid,
                        rdct_final_xy_addr, rdct_final_x_dout, rdct_final_y_dout, rdct_final_xy_valid
);

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


    input                     clk;
    input                     rst;
    //
    input                     ena;
    output                    rdy;
    //
    input  [  OP_ADDR_W -1:0] word_index_last;
    //
    input  [BANK_ADDR_W -1:0] rd_wide_xy_bank_aux;
    input  [  OP_ADDR_W -1:0] rd_wide_xy_addr_aux;
    input  [ WORD_EXT_W -1:0] rd_wide_x_dout_aux;
    input  [ WORD_EXT_W -1:0] rd_wide_y_dout_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_dout;
    input  [ WORD_EXT_W -1:0] rcmb_final_y_dout;
    input                     rcmb_final_xy_valid;
    //
    output [  OP_ADDR_W -1:0] rdct_final_xy_addr;
    output [ WORD_EXT_W -1:0] rdct_final_x_dout;
    output [ WORD_EXT_W -1:0] rdct_final_y_dout;
    output                    rdct_final_xy_valid;


    //
    // Ready
    //
    reg rdy_reg  = 1'b1;
    reg busy_now = 1'b0;

    assign rdy = rdy_reg;
    
    always @(posedge clk)
        //
        if (rst) rdy_reg <= 1'b1;
        else begin
            if (rdy && ena) rdy_reg <= 1'b0;
            if (!rdy && !busy_now) rdy_reg <= 1'b1;
        end
          

    //
    // Pipeline (Delay Match)
    //
    reg rcmb_xy_valid_dly1 = 1'b0;
    reg rcmb_xy_valid_dly2 = 1'b0;
    reg rcmb_xy_valid_dly3 = 1'b0;

    reg [BANK_ADDR_W -1:0] rcmb_xy_bank_dly1;
    reg [BANK_ADDR_W -1:0] rcmb_xy_bank_dly2;
    reg [BANK_ADDR_W -1:0] rcmb_xy_bank_dly3;

    reg [  OP_ADDR_W -1:0] rcmb_xy_addr_dly1;
    reg [  OP_ADDR_W -1:0] rcmb_xy_addr_dly2;
    reg [  OP_ADDR_W -1:0] rcmb_xy_addr_dly3;

    reg [ WORD_EXT_W -1:0] rcmb_x_dout_dly1;
    reg [ WORD_EXT_W -1:0] rcmb_x_dout_dly2;
    reg [ WORD_EXT_W -1:0] rcmb_x_dout_dly3;

    reg [ WORD_EXT_W -1:0] rcmb_y_dout_dly1;
    reg [ WORD_EXT_W -1:0] rcmb_y_dout_dly2;
    reg [ WORD_EXT_W -1:0] rcmb_y_dout_dly3;
    
    always @(posedge clk) 
        //
        if (rst) begin
            rcmb_xy_valid_dly1 <= 1'b0;
            rcmb_xy_valid_dly2 <= 1'b0;
            rcmb_xy_valid_dly3 <= 1'b0;
        end else begin
            rcmb_xy_valid_dly1 <= rcmb_final_xy_valid;
            rcmb_xy_valid_dly2 <= rcmb_xy_valid_dly1;
            rcmb_xy_valid_dly3 <= rcmb_xy_valid_dly2;        
        end
    
    
    always @(posedge clk) begin
        //
        if (rcmb_final_xy_valid) begin
            rcmb_xy_bank_dly1 <= rcmb_final_xy_bank;
            rcmb_xy_addr_dly1 <= rcmb_final_xy_addr;
            rcmb_x_dout_dly1  <= rcmb_final_x_dout;
            rcmb_y_dout_dly1  <= rcmb_final_y_dout;
        end
        //
        if (rcmb_xy_valid_dly1) begin
            rcmb_xy_bank_dly2 <= rcmb_xy_bank_dly1;
            rcmb_xy_addr_dly2 <= rcmb_xy_addr_dly1;
            rcmb_x_dout_dly2  <= rcmb_x_dout_dly1;
            rcmb_y_dout_dly2  <= rcmb_y_dout_dly1;
        end
        //
        if (rcmb_xy_valid_dly2) begin
            rcmb_xy_bank_dly3 <= rcmb_xy_bank_dly2;
            rcmb_xy_addr_dly3 <= rcmb_xy_addr_dly2;
            rcmb_x_dout_dly3  <= rcmb_x_dout_dly2;
            rcmb_y_dout_dly3  <= rcmb_y_dout_dly2;
        end
        //
    end


    //
    // Carry Logic
    //    
    reg [RDCT_CARRY_W -1:0] rcmb_x_lsb_carry;
    reg [WORD_W       -1:0] rcmb_x_lsb_dummy;
    reg [WORD_EXT_W   -1:0] rcmb_x_lsb_dout;

    reg [RDCT_CARRY_W -1:0] rcmb_y_lsb_carry;
    reg [WORD_W       -1:0] rcmb_y_lsb_dummy;
    reg [WORD_EXT_W   -1:0] rcmb_y_lsb_dout;


    //
    // Carry Computation
    //
    always @(posedge clk)
        //
        if (ena) begin
            rcmb_x_lsb_carry <= RDCT_CARRY_ZEROES;
            rcmb_y_lsb_carry <= RDCT_CARRY_ZEROES;
        end else if (rcmb_xy_valid_dly3)
            //
            case (rcmb_xy_bank_dly3)    
        
                BANK_RCMB_ML: begin
                    {rcmb_x_lsb_carry, rcmb_x_lsb_dummy} <= rcmb_x_dout_dly3 + rd_wide_x_dout_aux + rcmb_x_lsb_carry;
                    {rcmb_y_lsb_carry, rcmb_y_lsb_dummy} <= rcmb_y_dout_dly3 + rd_wide_y_dout_aux + rcmb_y_lsb_carry;
                end
                    
                BANK_RCMB_MH:
                    if (rcmb_xy_addr_dly3 == OP_ADDR_ZERO) begin
                        {rcmb_x_lsb_carry, rcmb_x_lsb_dummy} <= rcmb_x_dout_dly3 + rd_wide_x_dout_aux + rcmb_x_lsb_carry;
                        {rcmb_y_lsb_carry, rcmb_y_lsb_dummy} <= rcmb_y_dout_dly3 + rd_wide_y_dout_aux + rcmb_y_lsb_carry;
                    end
                    
            endcase


    //
    // Reduction
    //
    reg [ OP_ADDR_W -1:0] rdct_xy_addr;
    reg [WORD_EXT_W -1:0] rdct_x_dout;
    reg [WORD_EXT_W -1:0] rdct_y_dout;
    reg                   rdct_xy_valid = 1'b0;

    assign rdct_final_xy_addr  = rdct_xy_addr;
    assign rdct_final_x_dout   = rdct_x_dout;
    assign rdct_final_y_dout   = rdct_y_dout;
    assign rdct_final_xy_valid = rdct_xy_valid;

    task _update_rdct;
        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
            rdct_xy_addr  <= addr;
            rdct_x_dout   <= dout_x;
            rdct_y_dout   <= dout_y;
            rdct_xy_valid <= valid;
        end
    endtask
    
    task set_rdct;
        input [ OP_ADDR_W -1:0] addr;
        input [WORD_EXT_W -1:0] dout_x;
        input [WORD_EXT_W -1:0] dout_y;
        begin
            _update_rdct(addr, dout_x, dout_y, 1'b1);
        end
    endtask
    
    task clear_rdct;
        begin
            _update_rdct(OP_ADDR_DONT_CARE, WORD_EXT_DONT_CARE, WORD_EXT_DONT_CARE, 1'b0);
        end
    endtask
    
    
    //
    // Helper Wires
    //
    wire [WORD_EXT_W -1:0] sum_rdct_x = rcmb_x_dout_dly3 + rd_wide_x_dout_aux;
    wire [WORD_EXT_W -1:0] sum_rdct_y = rcmb_y_dout_dly3 + rd_wide_y_dout_aux;
    
    wire [WORD_EXT_W -1:0] sum_rdct_x_carry = sum_rdct_x + {WORD_NULL, rcmb_x_lsb_carry};
    wire [WORD_EXT_W -1:0] sum_rdct_y_carry = sum_rdct_y + {WORD_NULL, rcmb_y_lsb_carry};
    
    
    //
    //
    //
    always @(posedge clk)
        //
        if (rst) clear_rdct;
        else begin
            //
            clear_rdct;
            //
            if (busy_now && rcmb_xy_valid_dly3)
                //
                case (rcmb_xy_bank_dly3)
                                    
                    BANK_RCMB_MH:
                        if (rcmb_xy_addr_dly3 == OP_ADDR_ONE)
                            set_rdct(OP_ADDR_ZERO, sum_rdct_x_carry, sum_rdct_y_carry);
                        else if (rcmb_xy_addr_dly3 > OP_ADDR_ONE)
                            set_rdct(rcmb_xy_addr_dly3 - 1'b1, sum_rdct_x, sum_rdct_y);
                            
                    BANK_RCMB_EXT:
                        set_rdct(word_index_last, rcmb_x_dout_dly3, rcmb_y_dout_dly3);

                endcase
            //
        end



    //
    // Busy
    //
    always @(posedge clk)
        //
        if (rst) busy_now <= 1'b0;
        else begin
            if (rdy && ena) busy_now <= 1'b1;
            //if (!rdy && !busy_now) rdy <= 1'b1;
        end

    
endmodule