data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v
None: at end of input
1: b'%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:22: Cannot find include file: common.h\n`include "common.h" \n         ^~~~~~~~~~\n        ... Looked in:\n             data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new,data/full_repos/permissive/191476706/common.h\n             data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new,data/full_repos/permissive/191476706/common.h.v\n             data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new,data/full_repos/permissive/191476706/common.h.sv\n             common.h\n             common.h.v\n             common.h.sv\n             obj_dir/common.h\n             obj_dir/common.h.v\n             obj_dir/common.h.sv\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:59: Define or directive not defined: \'`BW_DIM_IN\'\nparameter BW_DIM_IN = `BW_DIM_IN;\n                      ^~~~~~~~~~\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:59: syntax error, unexpected \';\', expecting TYPE-IDENTIFIER\nparameter BW_DIM_IN = `BW_DIM_IN;\n                                ^\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:60: Define or directive not defined: \'`BW_DIM_EMB\'\nparameter BW_DIM_EMB = `BW_DIM_EMB;\n                       ^~~~~~~~~~~\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:60: syntax error, unexpected \';\', expecting TYPE-IDENTIFIER\nparameter BW_DIM_EMB = `BW_DIM_EMB;\n                                  ^\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:65: Define or directive not defined: \'`BW_DATA_EMB_W\'\nparameter BW_DATA = `BW_DATA_EMB_W;\n                    ^~~~~~~~~~~~~~\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:65: syntax error, unexpected \';\', expecting TYPE-IDENTIFIER\nparameter BW_DATA = `BW_DATA_EMB_W;\n                                  ^\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:72: Define or directive not defined: \'`CLOG2\'\nparameter BW_COUNTER_IN = `CLOG2(BW_DIM_IN);\n                          ^~~~~~\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:75: Define or directive not defined: \'`BW_MEM_ADDR\'\nparameter BW_MEM_ADDR = `BW_MEM_ADDR;\n                        ^~~~~~~~~~~~\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:75: syntax error, unexpected \';\', expecting TYPE-IDENTIFIER\nparameter BW_MEM_ADDR = `BW_MEM_ADDR;\n                                    ^\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:77: Define or directive not defined: \'`BW_WORD_VEC\'\nparameter BW_WORD_VEC = `BW_WORD_VEC;\n                        ^~~~~~~~~~~~\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:77: syntax error, unexpected \';\', expecting TYPE-IDENTIFIER\nparameter BW_WORD_VEC = `BW_WORD_VEC;\n                                    ^\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:79: Define or directive not defined: \'`LEARNING_RATE_SHIFT_BITS\'\nparameter LEARNING_RATE_SHIFT_BITS = `LEARNING_RATE_SHIFT_BITS;\n                                     ^~~~~~~~~~~~~~~~~~~~~~~~~\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:79: syntax error, unexpected \';\', expecting TYPE-IDENTIFIER\nparameter LEARNING_RATE_SHIFT_BITS = `LEARNING_RATE_SHIFT_BITS;\n                                                              ^\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:80: Define or directive not defined: \'`REG_L2_NORM_SHIFT_BITS\'\nparameter REG_L2_NORM_SHIFT_BITS = `REG_L2_NORM_SHIFT_BITS;\n                                   ^~~~~~~~~~~~~~~~~~~~~~~\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:80: syntax error, unexpected \';\', expecting TYPE-IDENTIFIER\nparameter REG_L2_NORM_SHIFT_BITS = `REG_L2_NORM_SHIFT_BITS;\n                                                          ^\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:81: Define or directive not defined: \'`BW_BATCH_SIZE\'\nparameter BW_BATCH_SIZE = `BW_BATCH_SIZE;\n                          ^~~~~~~~~~~~~~\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:81: syntax error, unexpected \';\', expecting TYPE-IDENTIFIER\nparameter BW_BATCH_SIZE = `BW_BATCH_SIZE;\n                                        ^\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:87: Define or directive not defined: \'`BW_ADDR_W_INIT\'\nparameter BW_ADDR_W_INIT = `BW_ADDR_W_INIT;\n                           ^~~~~~~~~~~~~~~\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:87: syntax error, unexpected \';\', expecting TYPE-IDENTIFIER\nparameter BW_ADDR_W_INIT = `BW_ADDR_W_INIT;\n                                          ^\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:123: Define or directive not defined: \'`BW_DEBUG_EMB\'\noutput reg [`BW_DEBUG_EMB-1:0] debug_out;\n            ^~~~~~~~~~~~~\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:804: Define or directive not defined: \'`BW_WL\'\n            .WL(`BW_WL),\n                ^~~~~~\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:805: Define or directive not defined: \'`BW_IWL\'\n            .IWL(`BW_IWL)\n                 ^~~~~~~\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:1023: Define or directive not defined: \'`BW_WL\'\n            .WL(`BW_WL),\n                ^~~~~~\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:1024: Define or directive not defined: \'`BW_IWL\'\n            .IWL(`BW_IWL)\n                 ^~~~~~~\n%Error: data/full_repos/permissive/191476706/MemN2N.srcs/sources_1/new/memory_network_emb.v:1321: Define or directive not defined: \'`BW_DEBUG_EMB\'\n        debug_out <= {`BW_DEBUG_EMB{1\'b0}};\n                      ^~~~~~~~~~~~~\n%Error: Exiting due to 26 error(s)\n'
module memory_network_emb
(

    clk,

    rst_n,
    rst_n_soft,
    rst_n_batch,
    rst_n_hop,

    en_init_w,
    data_in_init_w,
    addr_in_init_w,
    en_fwd_path,
    en_bwd_path,
    en_bwd_path_w_up,
    data_in,
    grad_in,
    data_word_in,
    we_data_word_in,
    done_data_word_in,
    lr_l2,

    data_out,
    done_init_w,
    done_fwd_path,
    done_bwd_path,
    done_bwd_path_w_up,
    re_data_word_in,

    debug_out
);



parameter BW_DIM_IN = `BW_DIM_IN;
parameter BW_DIM_EMB = `BW_DIM_EMB;

parameter DIM_IN = BW_DIM_IN;
parameter DIM_EMB = 1<<BW_DIM_EMB;

parameter BW_DATA = `BW_DATA_EMB_W;

parameter BW_ADDR = 8;




parameter BW_COUNTER_IN = `CLOG2(BW_DIM_IN);
parameter COUNT_VALUE_IN = DIM_IN-1;

parameter BW_MEM_ADDR = `BW_MEM_ADDR;

parameter BW_WORD_VEC = `BW_WORD_VEC;

parameter LEARNING_RATE_SHIFT_BITS = `LEARNING_RATE_SHIFT_BITS;
parameter REG_L2_NORM_SHIFT_BITS = `REG_L2_NORM_SHIFT_BITS;
parameter BW_BATCH_SIZE = `BW_BATCH_SIZE;

parameter BW_W_UP_HOP = 0;

parameter INIT_FILE = "";

parameter BW_ADDR_W_INIT = `BW_ADDR_W_INIT;






input wire clk;

input wire rst_n;
input wire rst_n_soft;
input wire rst_n_batch;
input wire rst_n_hop;

input wire en_init_w;
input wire [BW_DATA*DIM_EMB-1:0] data_in_init_w;
input wire [BW_ADDR_W_INIT-1:0] addr_in_init_w;
input wire en_fwd_path;
input wire en_bwd_path;
input wire en_bwd_path_w_up;
input wire [BW_WORD_VEC-1:0] data_in;
input wire [BW_DATA*DIM_EMB-1:0] grad_in;
input wire [BW_WORD_VEC-1:0] data_word_in;
input wire we_data_word_in;
input wire done_data_word_in;
input wire [7:0] lr_l2;

output reg [BW_DATA*DIM_EMB-1:0] data_out;

output reg done_init_w;
output reg done_fwd_path;
output reg done_bwd_path;
output reg done_bwd_path_w_up;

output reg re_data_word_in;

output reg [`BW_DEBUG_EMB-1:0] debug_out;





wire [BW_COUNTER_IN-1:0] count_addr_w_in;
reg [BW_COUNTER_IN-1:0] addr_w;
wire en_addr_w_in;
wire rst_n_addr_w_in;


reg [BW_DATA-1:0] buf_out [0:DIM_EMB-1];

wire [BW_DATA*DIM_EMB-1:0] data_unmasked;


wire [BW_DATA-1:0] data_w_accu [0:DIM_EMB-1];

wire [BW_DATA-1:0] data_accu [0:DIM_EMB-1];



wire we_w;












wire [BW_DATA*DIM_EMB-1:0] data_init_w;

genvar i;

reg en_init_w_sync;
reg en_fwd_path_sync;
reg en_bwd_path_sync;
reg en_bwd_path_w_up_sync;


reg re_n_data_word_in;

reg [DIM_IN-1:0] dirty_w_del;


reg f_dirty_w_del;



reg en_w_up;
wire en_w_up_latch;
reg [BW_DATA-1:0] data_w_up [0:DIM_EMB-1];

reg [BW_COUNTER_IN-1:0] addr_w_up;



reg [BW_DATA-1:0] _add_in_a [0:DIM_EMB-1];
reg [BW_DATA-1:0] _add_in_b [0:DIM_EMB-1];
wire [BW_DATA-1:0] _add_out [0:DIM_EMB-1];


reg done_w_up;

reg [BW_COUNTER_IN-1:0] _addr_w_del;
wire [BW_COUNTER_IN-1:0] addr_w_del;

wire we_w_del;
reg [BW_DATA-1:0] _data_w_del [0:DIM_EMB-1];


reg we_data_word_in_delayed;

reg we_data_word_in_delayed_2;

reg [BW_DATA-1:0] data_w_del_tmp [0:DIM_EMB-1];

wire rst_n_w_del;



wire [BW_DATA-1:0] data_in_w [0:DIM_EMB-1];
wire [BW_DATA-1:0] data_out_w [0:DIM_EMB-1];

wire [BW_DATA-1:0] data_in_w_del [0:DIM_EMB-1];
wire [BW_DATA-1:0] data_out_w_del [0:DIM_EMB-1];


wire _done_bwd_path;
wire _done_bwd_path_w_up;

wire _re_data_word_in;

reg [3:0] lr;
reg [3:0] l2;


wire [DIM_EMB-1:0] overflow_adder;
wire [DIM_EMB-1:0] overflow_adder_l2;

wire [DIM_EMB-1:0] underflow_adder;
wire [DIM_EMB-1:0] underflow_adder_l2;

wire [BW_DATA-1:0] _grad_in [0:DIM_EMB-1];





assign rst_n_addr_w_in = rst_n && (en_fwd_path_sync || en_bwd_path_w_up_sync);











assign we_w = en_init_w_sync || en_bwd_path_w_up_sync&&done_w_up;







generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : assign_data_w_accu
        assign data_w_accu[i] = data_out_w[i];
    end
endgenerate





assign data_init_w = data_in_init_w;




generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin

        assign data_in_w[i] = (en_init_w_sync== 1'b1) ? data_init_w[(i+1)*BW_DATA-1-:BW_DATA]:((en_bwd_path_w_up_sync==1'b1&&done_w_up==1'b1)? data_w_up[i]:{BW_DATA{1'b0}});
    end
endgenerate

generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin
        always@(posedge clk or negedge rst_n)
        begin
            if(rst_n==1'b0)
                data_out[(i+1)*BW_DATA-1-:BW_DATA] <= {(BW_DATA){1'b0}};
            else    
                data_out[(i+1)*BW_DATA-1-:BW_DATA] <= buf_out[i];
        end
    end
endgenerate

always@(*)
begin
    case({en_init_w_sync,en_fwd_path_sync,en_bwd_path_w_up_sync})
        3'b100 :
        begin

            addr_w = addr_in_init_w[BW_COUNTER_IN-1:0];
        end
        3'b010 :
        begin
            addr_w = data_in[BW_COUNTER_IN-1:0];
        end
        3'b001 :
        begin
            addr_w = count_addr_w_in;
        end
        default
        begin
            addr_w = 'b0;
        end
    endcase
end

assign _done_init_w = en_init_w_sync && done_addr_w_in;

assign _done_bwd_path_w_up = en_bwd_path_w_up_sync && done_addr_w_in;

always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        done_bwd_path_w_up <= 1'b0;
    else
        done_bwd_path_w_up <= _done_bwd_path_w_up;
end









always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        en_init_w_sync <= 1'b0;
    else
        en_init_w_sync <= en_init_w;
end

always@(posedge clk or negedge rst_n)
begin

    if(rst_n==1'b0)
        en_fwd_path_sync <= 1'b0;
    else
        if(done_fwd_path==1'b1)
            en_fwd_path_sync <= 1'b0;
        else if(en_fwd_path_sync==1'b0)
            en_fwd_path_sync <= en_fwd_path;
end

always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        en_bwd_path_sync <= 1'b0;
    else
        if(_done_bwd_path==1'b1)
            en_bwd_path_sync <= 1'b0;
        else if(en_bwd_path_sync==1'b0)
            en_bwd_path_sync <= en_bwd_path;
end


assign _done_bwd_path = done_data_word_in;

always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        done_bwd_path <= 1'b0;
    else
        done_bwd_path <= _done_bwd_path;
end

assign _re_data_word_in = en_bwd_path_sync && !re_n_data_word_in;

always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        re_data_word_in <= 1'b0;
    else
        re_data_word_in <= _re_data_word_in;
end

always@(posedge clk or negedge rst_n or negedge rst_n_soft or negedge rst_n_hop)
begin

    if(rst_n==1'b0 || rst_n_soft==1'b0 || rst_n_hop==1'b0) 
        re_n_data_word_in <= 1'b0;
    else
        if(we_w_del==1'b1)
            re_n_data_word_in <= 1'b0;
        else if(re_n_data_word_in==1'b0)
            re_n_data_word_in <= en_bwd_path_sync;
end



always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        en_bwd_path_w_up_sync <= 1'b0;
    else
        if(_done_bwd_path_w_up==1'b1)
            en_bwd_path_w_up_sync <= 1'b0;
        else if(en_bwd_path_w_up_sync==1'b0)
            en_bwd_path_w_up_sync <= en_bwd_path_w_up;
end


always@(posedge clk or negedge rst_n)
begin

    if(rst_n==1'b0)
        done_fwd_path <= 1'b0;
    else
        done_fwd_path <= !done_fwd_path && en_fwd_path_sync;
end






generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin
        always@(posedge clk or negedge rst_n or negedge rst_n_soft)
        begin
            if(rst_n==1'b0 || rst_n_soft == 1'b0)
                buf_out[i] <= {(BW_DATA){1'b0}};
            else

                if(done_fwd_path==1'b1)
                    buf_out[i] <= data_accu[i];
        end
    end
endgenerate







always@(posedge clk or negedge rst_n or negedge rst_n_batch)
begin
    if(rst_n==1'b0 || rst_n_batch==1'b0)
        dirty_w_del <= {DIM_IN{1'b0}};
    else
        if(en_bwd_path_sync==1'b1 && we_w_del==1'b1)
            dirty_w_del[addr_w_del] <= 1'b1;
end

always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        lr <= 4'b0;
    else
        lr <= lr_l2[7:4];
end

always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        l2 <= 4'b0;
    else
        l2 <= lr_l2[3:0];
end








generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin
        assign _grad_in[i] = grad_in[(i+1)*BW_DATA-1-:BW_DATA];
    end
endgenerate

reg [BW_DATA-1:0] shifted_lr_grad_in [0:DIM_EMB-1];

generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin
        always@(*)
        begin
            case(lr)
                4'b0000:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (0+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b0001:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (1+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b0010:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (2+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b0011:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (3+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b0100:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (4+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b0101:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (5+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b0110:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (6+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b0111:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (7+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b1000:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (8+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b1001:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (9+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b1010:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (10+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b1011:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (11+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b1100:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (12+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b1101:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (13+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b1110:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (14+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b1111:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (15+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
            endcase
        end
    end
endgenerate


generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : assign_add_in_a
        always@(*)
        begin
            case({en_fwd_path_sync,en_bwd_path_sync,en_bwd_path_w_up_sync})
                3'b100 :
                begin

                    _add_in_a[i] = buf_out[i];
                end
                3'b010 :
                begin
                    if(f_dirty_w_del==1'b1)

                        if(shifted_lr_grad_in[i][BW_DATA-1]==1'b0)
                            _add_in_a[i] = shifted_lr_grad_in[i];
                        else
                            _add_in_a[i] = shifted_lr_grad_in[i]+1'b1;
                    else
                        _add_in_a[i] = {BW_DATA{1'b0}};
                end
                3'b001 :
                begin



                        
                        _add_in_a[i] = data_out_w[i];



                end
                default
                begin
                    _add_in_a[i] = {BW_DATA{1'b0}};
                end
            endcase
        end
    end
endgenerate



generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : assign_add_in_b
        always@(*)
        begin
            case({en_fwd_path_sync,en_bwd_path_sync,en_bwd_path_w_up_sync})
                3'b100 :
                begin
                    _add_in_b[i] = data_w_accu[i];
                end
                3'b010 :
                begin
                    if(f_dirty_w_del==1'b1)
                        _add_in_b[i] = data_out_w_del[i];
                    else
                        _add_in_b[i] = {BW_DATA{1'b0}};
                end
                3'b001 :
                begin




                        

                        _add_in_b[i] = $signed(~data_out_w_del[i]+1'b1);


                end
                default
                begin
                    _add_in_b[i] = {BW_DATA{1'b0}};
                end
            endcase
        end
    end
endgenerate


generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin
        assign data_accu[i] = (en_fwd_path_sync==1'b1) ? _add_out[i]:{BW_DATA{1'b0}};
    end
endgenerate

generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : fix_adder
        fixed_adder
        #(
            .WL(`BW_WL),
            .IWL(`BW_IWL)
        )
        adder
        (

            .a(_add_in_a[i]),
            .b(_add_in_b[i]),
            .c(_add_out[i]),
            .overflow(overflow_adder[i]),
            .underflow(underflow_adder[i])
        );
    end
endgenerate


wire [BW_DATA-1:0] _add_in_reg_l2_a [0:DIM_EMB-1];
reg [BW_DATA-1:0] _add_in_reg_l2_b [0:DIM_EMB-1];
wire [BW_DATA-1:0] _add_out_reg_l2 [0:DIM_EMB-1];

reg [BW_DATA-1:0] shifted_lr_data_out_w [0:DIM_EMB-1];
reg [BW_DATA-1:0] shifted_lr_l2_data_out_w [0:DIM_EMB-1];


generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin
        assign _add_in_reg_l2_a[i] = (en_bwd_path_w_up_sync==1'b1) ? _add_out[i] : {BW_DATA{1'b0}};
    end
endgenerate

generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin
        always@(*)
        begin
            case(lr)
                4'b0000:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]);
                end
                4'b0001:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (1);
                end
                4'b0010:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (2);
                end
                4'b0011:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (3);
                end
                4'b0100:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (4);
                end
                4'b0101:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (5);
                end
                4'b0110:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (6);
                end
                4'b0111:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (7);
                end
                4'b1000:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (8);
                end
                4'b1001:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (9);
                end
                4'b1010:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (10);
                end
                4'b1011:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (11);
                end
                4'b1100:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (12);
                end
                4'b1101:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (13);
                end
                4'b1110:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (14);
                end
                4'b1111:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (15);
                end
            endcase
        end
    end
endgenerate


generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin
        always@(*)
        begin
            case(l2)
                4'b0000:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]);
                end
                4'b0001:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 1;
                end
                4'b0010:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 2;
                end
                4'b0011:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 3;
                end
                4'b0100:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 4;
                end
                4'b0101:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 5;
                end
                4'b0110:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 6;
                end
                4'b0111:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 7;
                end
                4'b1000:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 8;
                end
                4'b1001:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 9;
                end
                4'b1010:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 10;
                end
                4'b1011:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 11;
                end
                4'b1100:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 12;
                end
                4'b1101:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 13;
                end
                4'b1110:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 14;
                end
                4'b1111:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 15;
                end
            endcase
        end
    end
endgenerate



generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin


        





        always@(*)
        begin
            if(en_bwd_path_w_up_sync==1'b1)
                if(shifted_lr_l2_data_out_w[i][BW_DATA-1]==1'b0) 
                    _add_in_reg_l2_b[i] = $signed(~shifted_lr_l2_data_out_w[i]+1'b1);

                else
                    _add_in_reg_l2_b[i] = $signed(~(shifted_lr_l2_data_out_w[i]+1'b1)+1'b1);

            else
                _add_in_reg_l2_b[i] = {BW_DATA{1'b0}};
        end
    end
endgenerate

generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : fix_adder_w_up_reg_l2
        fixed_adder
        #(
            .WL(`BW_WL),
            .IWL(`BW_IWL)
        )
        adder_w_up_reg_l2
        (
            .a(_add_in_reg_l2_a[i]),
            .b(_add_in_reg_l2_b[i]),
            .c(_add_out_reg_l2[i]),
            .overflow(overflow_adder_l2[i]),
            .underflow(underflow_adder_l2[i])
        );
    end
endgenerate




assign en_addr_w_in = en_fwd_path_sync || (en_bwd_path_w_up_sync && (!dirty_w_del[addr_w]||done_w_up));




always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        addr_w_up <= {BW_COUNTER_IN{1'b0}};
    else
        if(en_w_up_latch==1'b1)
            addr_w_up <= addr_w;
end


always@(posedge clk or negedge rst_n)
begin


    if(rst_n==1'b0)
        en_w_up <= 1'b0;
    else
        if(done_w_up==1'b1)
            en_w_up <= 1'b0;
        else if(en_bwd_path_w_up_sync==1'b1)
            en_w_up <= dirty_w_del[addr_w];
end



assign en_w_up_latch = en_w_up && !done_w_up;


generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : assign_data_w_up
        always@(posedge clk or negedge rst_n)
        begin
            if(rst_n==1'b0)
                data_w_up[i] <= {BW_DATA{1'b0}};
            else
                if(en_w_up_latch==1'b1)

                    data_w_up[i] <= _add_out_reg_l2[i];
        end
    end
endgenerate


always@(posedge clk or negedge rst_n)
begin

    if(rst_n==1'b0)
        done_w_up <= 1'b0;
    else
        if(done_w_up==1'b1)
            done_w_up <= 1'b0;
        else if(en_w_up==1'b1)
            done_w_up <= 1'b1;
end


counter
#(
    .BW(BW_COUNTER_IN),
    .COUNT_VALUE(COUNT_VALUE_IN)
)
addr_w_in
(

    .clk(clk),

    .rst_n(rst_n_addr_w_in),

    .en(en_addr_w_in),
    .en_hold_max(1'b0),

    .count(count_addr_w_in),
    .done(done_addr_w_in)
);


generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : weight
        ram_sync
        #(
            .BW_DATA(BW_DATA),
            .BW_ADDR(BW_ADDR),
            .INIT_FILE({INIT_FILE,(i/10)+48,(i%10)+48,".mem"})
        )
        weight
        (

            .clk(clk),

            .rst_n(rst_n),

            .addr(addr_w),
            .oe(!we_w),
            .we(we_w),
            .data_in(data_in_w[i]),

            .data_out(data_out_w[i])

        );
    end
endgenerate



always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        _addr_w_del <= {BW_COUNTER_IN{1'b0}};
    else
        if(_done_bwd_path==1'b1)
            _addr_w_del <= {BW_COUNTER_IN{1'b0}};
        else if(_re_data_word_in==1'b1)
            _addr_w_del <= data_word_in[BW_COUNTER_IN-1:0];
end


assign addr_w_del = (en_bwd_path_sync==1'b1)? _addr_w_del : ((en_bwd_path_w_up_sync==1'b1)? addr_w : {BW_COUNTER_IN{1'b0}});




always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        f_dirty_w_del <= 1'b0;
    else
        if(_done_bwd_path==1'b1)
            f_dirty_w_del <= 1'b0;
        else if(en_bwd_path_sync==1'b1 && _re_data_word_in==1'b1)
            f_dirty_w_del <= (dirty_w_del[data_word_in[BW_COUNTER_IN-1:0]]==1'b1)? 1'b1 : 1'b0;
end




assign we_w_del =  (f_dirty_w_del==1'b0) ? we_data_word_in : we_data_word_in_delayed_2;




always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0 || en_bwd_path_sync==1'b0)
        we_data_word_in_delayed <= 1'b0;
    else
        if(f_dirty_w_del==1'b1)
            we_data_word_in_delayed <= we_data_word_in;
end



always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0 || en_bwd_path_sync==1'b0)
        we_data_word_in_delayed_2 <= 1'b0;
    else
        if(f_dirty_w_del==1'b1)
            we_data_word_in_delayed_2 <= we_data_word_in_delayed;
        else
            we_data_word_in_delayed_2 <= 1'b0;
end



generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : assign_data_w_del_tmp
        always@(posedge clk or negedge rst_n)
        begin
            if(rst_n==1'b0 || en_bwd_path_sync==1'b0)
                data_w_del_tmp[i] <= {BW_DATA{1'b0}};
            else
                if(we_data_word_in_delayed==1'b1)
                    data_w_del_tmp[i] <= _add_out[i];
        end
    end
endgenerate

generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : assign__data_w_del
        always@(*)
        begin
            if(we_w_del==1'b0)
                _data_w_del[i] = {BW_DATA{1'bz}};
            else
            begin
                if(f_dirty_w_del==1'b0)

                    _data_w_del[i] = shifted_lr_grad_in[i];
                else
                    _data_w_del[i] = data_w_del_tmp[i];
            end
        end
    end
endgenerate





assign rst_n_w_del = rst_n && rst_n_batch;



generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : assign_data_w_del
        assign data_in_w_del[i] = _data_w_del[i];
    end
endgenerate


generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : weight_del
        ram_sync
        #(
            .BW_DATA(BW_DATA),
            .BW_ADDR(BW_ADDR)
        )
        weight_del
        (

            .clk(clk),

            .rst_n(rst_n_w_del),

            .addr(addr_w_del),
            .oe(!we_w_del),
            .we(we_w_del),
            .data_in(data_in_w_del[i]),

            .data_out(data_out_w_del[i])
        );
    end
endgenerate






always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        debug_out <= {`BW_DEBUG_EMB{1'b0}};
    else
        debug_out <= {overflow_adder,overflow_adder_l2,underflow_adder,underflow_adder_l2};
end

`ifdef DEBUG
wire [BW_DATA-1:0] debug_grad_in [0:DIM_EMB-1];

generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin
        assign debug_grad_in[i] = grad_in[(i+1)*BW_DATA-1-:BW_DATA];
    end
endgenerate

`ifdef DEBUG_ILA

ila
ila_emb
(
    .clk(clk),


    .probe0(rst_n_w_del),
    .probe1(rst_n_addr_w_in),
    .probe2(re_n_data_word_in),
    .probe3(en_addr_w_in),
    .probe4(en_init_w_sync),
    .probe5(en_fwd_path_sync),
    .probe6(en_bwd_path_sync),
    .probe7(en_bwd_path_w_up_sync),


    .probe8(en_w_up),
    .probe9(en_w_up_latch),
    .probe10(done_w_up),
    .probe11(we_w_del),
    .probe12(we_data_word_in_delayed),
    .probe13(we_data_word_in_delayed_2),
    .probe14(_done_bwd_path),
    .probe15(_done_bwd_path_w_up),


    .probe16(count_addr_w_in),
    .probe17(addr_w),
    .probe18(dirty_w_del),
    .probe19(addr_w_up),
    .probe20(_addr_w_del),
    .probe21(addr_w_del),
    .probe22(),
    .probe23(),


    .probe24(overflow_adder),
    .probe25(overflow_adder_l2),
    .probe26(underflow_adder),
    .probe27(underflow_adder_l2),
    .probe28(),
    .probe29(),
    .probe30(),
    .probe31(),


    .probe32(_re_data_word_in),
    .probe33(f_dirty_w_del),
    .probe34(),
    .probe35(),
    .probe36(),
    .probe37(),
    .probe38(),
    .probe39(),


    .probe40(),
    .probe41(),
    .probe42(),
    .probe43(),
    .probe44(),
    .probe45(),
    .probe46(),
    .probe47()

);
`endif

`endif




endmodule
module memory_network_emb
(

    clk,

    rst_n,
    rst_n_soft,
    rst_n_batch,
    rst_n_hop,

    en_init_w,
    data_in_init_w,
    addr_in_init_w,
    en_fwd_path,
    en_bwd_path,
    en_bwd_path_w_up,
    data_in,
    grad_in,
    data_word_in,
    we_data_word_in,
    done_data_word_in,
    lr_l2,

    data_out,
    done_init_w,
    done_fwd_path,
    done_bwd_path,
    done_bwd_path_w_up,
    re_data_word_in,

    debug_out
);




parameter BW_DIM_IN = `BW_DIM_IN;
parameter BW_DIM_EMB = `BW_DIM_EMB;

parameter DIM_IN = BW_DIM_IN;
parameter DIM_EMB = 1<<BW_DIM_EMB;

parameter BW_DATA = `BW_DATA_EMB_W;

parameter BW_ADDR = 8;




parameter BW_COUNTER_IN = `CLOG2(BW_DIM_IN);
parameter COUNT_VALUE_IN = DIM_IN-1;

parameter BW_MEM_ADDR = `BW_MEM_ADDR;

parameter BW_WORD_VEC = `BW_WORD_VEC;

parameter LEARNING_RATE_SHIFT_BITS = `LEARNING_RATE_SHIFT_BITS;
parameter REG_L2_NORM_SHIFT_BITS = `REG_L2_NORM_SHIFT_BITS;
parameter BW_BATCH_SIZE = `BW_BATCH_SIZE;

parameter BW_W_UP_HOP = 0;

parameter INIT_FILE = "";

parameter BW_ADDR_W_INIT = `BW_ADDR_W_INIT;






input wire clk;

input wire rst_n;
input wire rst_n_soft;
input wire rst_n_batch;
input wire rst_n_hop;

input wire en_init_w;
input wire [BW_DATA*DIM_EMB-1:0] data_in_init_w;
input wire [BW_ADDR_W_INIT-1:0] addr_in_init_w;
input wire en_fwd_path;
input wire en_bwd_path;
input wire en_bwd_path_w_up;
input wire [BW_WORD_VEC-1:0] data_in;
input wire [BW_DATA*DIM_EMB-1:0] grad_in;
input wire [BW_WORD_VEC-1:0] data_word_in;
input wire we_data_word_in;
input wire done_data_word_in;
input wire [7:0] lr_l2;

output reg [BW_DATA*DIM_EMB-1:0] data_out;

output reg done_init_w;
output reg done_fwd_path;
output reg done_bwd_path;
output reg done_bwd_path_w_up;

output reg re_data_word_in;

output reg [`BW_DEBUG_EMB-1:0] debug_out;





wire [BW_COUNTER_IN-1:0] count_addr_w_in;
reg [BW_COUNTER_IN-1:0] addr_w;
wire en_addr_w_in;
wire rst_n_addr_w_in;


reg [BW_DATA-1:0] buf_out [0:DIM_EMB-1];

wire [BW_DATA*DIM_EMB-1:0] data_unmasked;


wire [BW_DATA-1:0] data_w_accu [0:DIM_EMB-1];

wire [BW_DATA-1:0] data_accu [0:DIM_EMB-1];



wire we_w;












wire [BW_DATA*DIM_EMB-1:0] data_init_w;

genvar i;

reg en_init_w_sync;
reg en_fwd_path_sync;
reg en_bwd_path_sync;
reg en_bwd_path_w_up_sync;


reg re_n_data_word_in;

reg [DIM_IN-1:0] dirty_w_del;


reg f_dirty_w_del;



reg en_w_up;
wire en_w_up_latch;
reg [BW_DATA-1:0] data_w_up [0:DIM_EMB-1];

reg [BW_COUNTER_IN-1:0] addr_w_up;



reg [BW_DATA-1:0] _add_in_a [0:DIM_EMB-1];
reg [BW_DATA-1:0] _add_in_b [0:DIM_EMB-1];
wire [BW_DATA-1:0] _add_out [0:DIM_EMB-1];


reg done_w_up;

reg [BW_COUNTER_IN-1:0] _addr_w_del;
wire [BW_COUNTER_IN-1:0] addr_w_del;

wire we_w_del;
reg [BW_DATA-1:0] _data_w_del [0:DIM_EMB-1];


reg we_data_word_in_delayed;

reg we_data_word_in_delayed_2;

reg [BW_DATA-1:0] data_w_del_tmp [0:DIM_EMB-1];

wire rst_n_w_del;



wire [BW_DATA-1:0] data_in_w [0:DIM_EMB-1];
wire [BW_DATA-1:0] data_out_w [0:DIM_EMB-1];

wire [BW_DATA-1:0] data_in_w_del [0:DIM_EMB-1];
wire [BW_DATA-1:0] data_out_w_del [0:DIM_EMB-1];


wire _done_bwd_path;
wire _done_bwd_path_w_up;

wire _re_data_word_in;

reg [3:0] lr;
reg [3:0] l2;


wire [DIM_EMB-1:0] overflow_adder;
wire [DIM_EMB-1:0] overflow_adder_l2;

wire [DIM_EMB-1:0] underflow_adder;
wire [DIM_EMB-1:0] underflow_adder_l2;

wire [BW_DATA-1:0] _grad_in [0:DIM_EMB-1];





assign rst_n_addr_w_in = rst_n && (en_fwd_path_sync || en_bwd_path_w_up_sync);











assign we_w = en_init_w_sync || en_bwd_path_w_up_sync&&done_w_up;







generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : assign_data_w_accu
        assign data_w_accu[i] = data_out_w[i];
    end
endgenerate





assign data_init_w = data_in_init_w;




generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin

        assign data_in_w[i] = (en_init_w_sync== 1'b1) ? data_init_w[(i+1)*BW_DATA-1-:BW_DATA]:((en_bwd_path_w_up_sync==1'b1&&done_w_up==1'b1)? data_w_up[i]:{BW_DATA{1'b0}});
    end
endgenerate

generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin
        always@(posedge clk or negedge rst_n)
        begin
            if(rst_n==1'b0)
                data_out[(i+1)*BW_DATA-1-:BW_DATA] <= {(BW_DATA){1'b0}};
            else    
                data_out[(i+1)*BW_DATA-1-:BW_DATA] <= buf_out[i];
        end
    end
endgenerate

always@(*)
begin
    case({en_init_w_sync,en_fwd_path_sync,en_bwd_path_w_up_sync})
        3'b100 :
        begin

            addr_w = addr_in_init_w[BW_COUNTER_IN-1:0];
        end
        3'b010 :
        begin
            addr_w = data_in[BW_COUNTER_IN-1:0];
        end
        3'b001 :
        begin
            addr_w = count_addr_w_in;
        end
        default
        begin
            addr_w = 'b0;
        end
    endcase
end

assign _done_init_w = en_init_w_sync && done_addr_w_in;

assign _done_bwd_path_w_up = en_bwd_path_w_up_sync && done_addr_w_in;

always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        done_bwd_path_w_up <= 1'b0;
    else
        done_bwd_path_w_up <= _done_bwd_path_w_up;
end









always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        en_init_w_sync <= 1'b0;
    else
        en_init_w_sync <= en_init_w;
end

always@(posedge clk or negedge rst_n)
begin

    if(rst_n==1'b0)
        en_fwd_path_sync <= 1'b0;
    else
        if(done_fwd_path==1'b1)
            en_fwd_path_sync <= 1'b0;
        else if(en_fwd_path_sync==1'b0)
            en_fwd_path_sync <= en_fwd_path;
end

always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        en_bwd_path_sync <= 1'b0;
    else
        if(_done_bwd_path==1'b1)
            en_bwd_path_sync <= 1'b0;
        else if(en_bwd_path_sync==1'b0)
            en_bwd_path_sync <= en_bwd_path;
end


assign _done_bwd_path = done_data_word_in;

always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        done_bwd_path <= 1'b0;
    else
        done_bwd_path <= _done_bwd_path;
end

assign _re_data_word_in = en_bwd_path_sync && !re_n_data_word_in;

always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        re_data_word_in <= 1'b0;
    else
        re_data_word_in <= _re_data_word_in;
end

always@(posedge clk or negedge rst_n or negedge rst_n_soft or negedge rst_n_hop)
begin

    if(rst_n==1'b0 || rst_n_soft==1'b0 || rst_n_hop==1'b0) 
        re_n_data_word_in <= 1'b0;
    else
        if(we_w_del==1'b1)
            re_n_data_word_in <= 1'b0;
        else if(re_n_data_word_in==1'b0)
            re_n_data_word_in <= en_bwd_path_sync;
end



always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        en_bwd_path_w_up_sync <= 1'b0;
    else
        if(_done_bwd_path_w_up==1'b1)
            en_bwd_path_w_up_sync <= 1'b0;
        else if(en_bwd_path_w_up_sync==1'b0)
            en_bwd_path_w_up_sync <= en_bwd_path_w_up;
end


always@(posedge clk or negedge rst_n)
begin

    if(rst_n==1'b0)
        done_fwd_path <= 1'b0;
    else
        done_fwd_path <= !done_fwd_path && en_fwd_path_sync;
end






generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin
        always@(posedge clk or negedge rst_n or negedge rst_n_soft)
        begin
            if(rst_n==1'b0 || rst_n_soft == 1'b0)
                buf_out[i] <= {(BW_DATA){1'b0}};
            else

                if(done_fwd_path==1'b1)
                    buf_out[i] <= data_accu[i];
        end
    end
endgenerate







always@(posedge clk or negedge rst_n or negedge rst_n_batch)
begin
    if(rst_n==1'b0 || rst_n_batch==1'b0)
        dirty_w_del <= {DIM_IN{1'b0}};
    else
        if(en_bwd_path_sync==1'b1 && we_w_del==1'b1)
            dirty_w_del[addr_w_del] <= 1'b1;
end

always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        lr <= 4'b0;
    else
        lr <= lr_l2[7:4];
end

always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        l2 <= 4'b0;
    else
        l2 <= lr_l2[3:0];
end








generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin
        assign _grad_in[i] = grad_in[(i+1)*BW_DATA-1-:BW_DATA];
    end
endgenerate

reg [BW_DATA-1:0] shifted_lr_grad_in [0:DIM_EMB-1];

generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin
        always@(*)
        begin
            case(lr)
                4'b0000:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (0+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b0001:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (1+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b0010:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (2+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b0011:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (3+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b0100:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (4+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b0101:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (5+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b0110:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (6+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b0111:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (7+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b1000:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (8+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b1001:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (9+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b1010:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (10+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b1011:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (11+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b1100:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (12+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b1101:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (13+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b1110:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (14+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
                4'b1111:
                begin
                    shifted_lr_grad_in[i] = $signed(_grad_in[i]) >>> (15+BW_BATCH_SIZE+BW_W_UP_HOP);
                end
            endcase
        end
    end
endgenerate


generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : assign_add_in_a
        always@(*)
        begin
            case({en_fwd_path_sync,en_bwd_path_sync,en_bwd_path_w_up_sync})
                3'b100 :
                begin

                    _add_in_a[i] = buf_out[i];
                end
                3'b010 :
                begin
                    if(f_dirty_w_del==1'b1)

                        if(shifted_lr_grad_in[i][BW_DATA-1]==1'b0)
                            _add_in_a[i] = shifted_lr_grad_in[i];
                        else
                            _add_in_a[i] = shifted_lr_grad_in[i]+1'b1;
                    else
                        _add_in_a[i] = {BW_DATA{1'b0}};
                end
                3'b001 :
                begin



                        
                        _add_in_a[i] = data_out_w[i];



                end
                default
                begin
                    _add_in_a[i] = {BW_DATA{1'b0}};
                end
            endcase
        end
    end
endgenerate



generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : assign_add_in_b
        always@(*)
        begin
            case({en_fwd_path_sync,en_bwd_path_sync,en_bwd_path_w_up_sync})
                3'b100 :
                begin
                    _add_in_b[i] = data_w_accu[i];
                end
                3'b010 :
                begin
                    if(f_dirty_w_del==1'b1)
                        _add_in_b[i] = data_out_w_del[i];
                    else
                        _add_in_b[i] = {BW_DATA{1'b0}};
                end
                3'b001 :
                begin




                        

                        _add_in_b[i] = $signed(~data_out_w_del[i]+1'b1);


                end
                default
                begin
                    _add_in_b[i] = {BW_DATA{1'b0}};
                end
            endcase
        end
    end
endgenerate


generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin
        assign data_accu[i] = (en_fwd_path_sync==1'b1) ? _add_out[i]:{BW_DATA{1'b0}};
    end
endgenerate

generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : fix_adder
        fixed_adder
        #(
            .WL(`BW_WL),
            .IWL(`BW_IWL)
        )
        adder
        (

            .a(_add_in_a[i]),
            .b(_add_in_b[i]),
            .c(_add_out[i]),
            .overflow(overflow_adder[i]),
            .underflow(underflow_adder[i])
        );
    end
endgenerate


wire [BW_DATA-1:0] _add_in_reg_l2_a [0:DIM_EMB-1];
reg [BW_DATA-1:0] _add_in_reg_l2_b [0:DIM_EMB-1];
wire [BW_DATA-1:0] _add_out_reg_l2 [0:DIM_EMB-1];

reg [BW_DATA-1:0] shifted_lr_data_out_w [0:DIM_EMB-1];
reg [BW_DATA-1:0] shifted_lr_l2_data_out_w [0:DIM_EMB-1];


generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin
        assign _add_in_reg_l2_a[i] = (en_bwd_path_w_up_sync==1'b1) ? _add_out[i] : {BW_DATA{1'b0}};
    end
endgenerate

generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin
        always@(*)
        begin
            case(lr)
                4'b0000:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]);
                end
                4'b0001:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (1);
                end
                4'b0010:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (2);
                end
                4'b0011:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (3);
                end
                4'b0100:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (4);
                end
                4'b0101:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (5);
                end
                4'b0110:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (6);
                end
                4'b0111:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (7);
                end
                4'b1000:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (8);
                end
                4'b1001:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (9);
                end
                4'b1010:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (10);
                end
                4'b1011:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (11);
                end
                4'b1100:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (12);
                end
                4'b1101:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (13);
                end
                4'b1110:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (14);
                end
                4'b1111:
                begin
                    shifted_lr_data_out_w[i] = $signed(data_out_w[i]) >>> (15);
                end
            endcase
        end
    end
endgenerate


generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin
        always@(*)
        begin
            case(l2)
                4'b0000:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]);
                end
                4'b0001:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 1;
                end
                4'b0010:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 2;
                end
                4'b0011:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 3;
                end
                4'b0100:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 4;
                end
                4'b0101:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 5;
                end
                4'b0110:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 6;
                end
                4'b0111:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 7;
                end
                4'b1000:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 8;
                end
                4'b1001:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 9;
                end
                4'b1010:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 10;
                end
                4'b1011:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 11;
                end
                4'b1100:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 12;
                end
                4'b1101:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 13;
                end
                4'b1110:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 14;
                end
                4'b1111:
                begin
                    shifted_lr_l2_data_out_w[i] = $signed(shifted_lr_data_out_w[i]) >>> 15;
                end
            endcase
        end
    end
endgenerate



generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin


        





        always@(*)
        begin
            if(en_bwd_path_w_up_sync==1'b1)
                if(shifted_lr_l2_data_out_w[i][BW_DATA-1]==1'b0) 
                    _add_in_reg_l2_b[i] = $signed(~shifted_lr_l2_data_out_w[i]+1'b1);

                else
                    _add_in_reg_l2_b[i] = $signed(~(shifted_lr_l2_data_out_w[i]+1'b1)+1'b1);

            else
                _add_in_reg_l2_b[i] = {BW_DATA{1'b0}};
        end
    end
endgenerate

generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : fix_adder_w_up_reg_l2
        fixed_adder
        #(
            .WL(`BW_WL),
            .IWL(`BW_IWL)
        )
        adder_w_up_reg_l2
        (
            .a(_add_in_reg_l2_a[i]),
            .b(_add_in_reg_l2_b[i]),
            .c(_add_out_reg_l2[i]),
            .overflow(overflow_adder_l2[i]),
            .underflow(underflow_adder_l2[i])
        );
    end
endgenerate




assign en_addr_w_in = en_fwd_path_sync || (en_bwd_path_w_up_sync && (!dirty_w_del[addr_w]||done_w_up));




always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        addr_w_up <= {BW_COUNTER_IN{1'b0}};
    else
        if(en_w_up_latch==1'b1)
            addr_w_up <= addr_w;
end


always@(posedge clk or negedge rst_n)
begin


    if(rst_n==1'b0)
        en_w_up <= 1'b0;
    else
        if(done_w_up==1'b1)
            en_w_up <= 1'b0;
        else if(en_bwd_path_w_up_sync==1'b1)
            en_w_up <= dirty_w_del[addr_w];
end



assign en_w_up_latch = en_w_up && !done_w_up;


generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : assign_data_w_up
        always@(posedge clk or negedge rst_n)
        begin
            if(rst_n==1'b0)
                data_w_up[i] <= {BW_DATA{1'b0}};
            else
                if(en_w_up_latch==1'b1)

                    data_w_up[i] <= _add_out_reg_l2[i];
        end
    end
endgenerate


always@(posedge clk or negedge rst_n)
begin

    if(rst_n==1'b0)
        done_w_up <= 1'b0;
    else
        if(done_w_up==1'b1)
            done_w_up <= 1'b0;
        else if(en_w_up==1'b1)
            done_w_up <= 1'b1;
end


counter
#(
    .BW(BW_COUNTER_IN),
    .COUNT_VALUE(COUNT_VALUE_IN)
)
addr_w_in
(

    .clk(clk),

    .rst_n(rst_n_addr_w_in),

    .en(en_addr_w_in),
    .en_hold_max(1'b0),

    .count(count_addr_w_in),
    .done(done_addr_w_in)
);


generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : weight
        ram_sync
        #(
            .BW_DATA(BW_DATA),
            .BW_ADDR(BW_ADDR),
            .INIT_FILE({INIT_FILE,(i/10)+48,(i%10)+48,".mem"})
        )
        weight
        (

            .clk(clk),

            .rst_n(rst_n),

            .addr(addr_w),
            .oe(!we_w),
            .we(we_w),
            .data_in(data_in_w[i]),

            .data_out(data_out_w[i])

        );
    end
endgenerate



always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        _addr_w_del <= {BW_COUNTER_IN{1'b0}};
    else
        if(_done_bwd_path==1'b1)
            _addr_w_del <= {BW_COUNTER_IN{1'b0}};
        else if(_re_data_word_in==1'b1)
            _addr_w_del <= data_word_in[BW_COUNTER_IN-1:0];
end


assign addr_w_del = (en_bwd_path_sync==1'b1)? _addr_w_del : ((en_bwd_path_w_up_sync==1'b1)? addr_w : {BW_COUNTER_IN{1'b0}});




always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        f_dirty_w_del <= 1'b0;
    else
        if(_done_bwd_path==1'b1)
            f_dirty_w_del <= 1'b0;
        else if(en_bwd_path_sync==1'b1 && _re_data_word_in==1'b1)
            f_dirty_w_del <= (dirty_w_del[data_word_in[BW_COUNTER_IN-1:0]]==1'b1)? 1'b1 : 1'b0;
end




assign we_w_del =  (f_dirty_w_del==1'b0) ? we_data_word_in : we_data_word_in_delayed_2;




always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0 || en_bwd_path_sync==1'b0)
        we_data_word_in_delayed <= 1'b0;
    else
        if(f_dirty_w_del==1'b1)
            we_data_word_in_delayed <= we_data_word_in;
end



always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0 || en_bwd_path_sync==1'b0)
        we_data_word_in_delayed_2 <= 1'b0;
    else
        if(f_dirty_w_del==1'b1)
            we_data_word_in_delayed_2 <= we_data_word_in_delayed;
        else
            we_data_word_in_delayed_2 <= 1'b0;
end



generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : assign_data_w_del_tmp
        always@(posedge clk or negedge rst_n)
        begin
            if(rst_n==1'b0 || en_bwd_path_sync==1'b0)
                data_w_del_tmp[i] <= {BW_DATA{1'b0}};
            else
                if(we_data_word_in_delayed==1'b1)
                    data_w_del_tmp[i] <= _add_out[i];
        end
    end
endgenerate

generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : assign__data_w_del
        always@(*)
        begin
            if(we_w_del==1'b0)
                _data_w_del[i] = {BW_DATA{1'bz}};
            else
            begin
                if(f_dirty_w_del==1'b0)

                    _data_w_del[i] = shifted_lr_grad_in[i];
                else
                    _data_w_del[i] = data_w_del_tmp[i];
            end
        end
    end
endgenerate





assign rst_n_w_del = rst_n && rst_n_batch;



generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : assign_data_w_del
        assign data_in_w_del[i] = _data_w_del[i];
    end
endgenerate


generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin : weight_del
        ram_sync
        #(
            .BW_DATA(BW_DATA),
            .BW_ADDR(BW_ADDR)
        )
        weight_del
        (

            .clk(clk),

            .rst_n(rst_n_w_del),

            .addr(addr_w_del),
            .oe(!we_w_del),
            .we(we_w_del),
            .data_in(data_in_w_del[i]),

            .data_out(data_out_w_del[i])
        );
    end
endgenerate






always@(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        debug_out <= {`BW_DEBUG_EMB{1'b0}};
    else
        debug_out <= {overflow_adder,overflow_adder_l2,underflow_adder,underflow_adder_l2};
end

`ifdef DEBUG
wire [BW_DATA-1:0] debug_grad_in [0:DIM_EMB-1];

generate
    for(i=0;i<DIM_EMB;i=i+1)
    begin
        assign debug_grad_in[i] = grad_in[(i+1)*BW_DATA-1-:BW_DATA];
    end
endgenerate

`ifdef DEBUG_ILA

ila
ila_emb
(
    .clk(clk),


    .probe0(rst_n_w_del),
    .probe1(rst_n_addr_w_in),
    .probe2(re_n_data_word_in),
    .probe3(en_addr_w_in),
    .probe4(en_init_w_sync),
    .probe5(en_fwd_path_sync),
    .probe6(en_bwd_path_sync),
    .probe7(en_bwd_path_w_up_sync),


    .probe8(en_w_up),
    .probe9(en_w_up_latch),
    .probe10(done_w_up),
    .probe11(we_w_del),
    .probe12(we_data_word_in_delayed),
    .probe13(we_data_word_in_delayed_2),
    .probe14(_done_bwd_path),
    .probe15(_done_bwd_path_w_up),


    .probe16(count_addr_w_in),
    .probe17(addr_w),
    .probe18(dirty_w_del),
    .probe19(addr_w_up),
    .probe20(_addr_w_del),
    .probe21(addr_w_del),
    .probe22(),
    .probe23(),


    .probe24(overflow_adder),
    .probe25(overflow_adder_l2),
    .probe26(underflow_adder),
    .probe27(underflow_adder_l2),
    .probe28(),
    .probe29(),
    .probe30(),
    .probe31(),


    .probe32(_re_data_word_in),
    .probe33(f_dirty_w_del),
    .probe34(),
    .probe35(),
    .probe36(),
    .probe37(),
    .probe38(),
    .probe39(),


    .probe40(),
    .probe41(),
    .probe42(),
    .probe43(),
    .probe44(),
    .probe45(),
    .probe46(),
    .probe47()

);
`endif

`endif




endmodule