`define SM3_INPT_DW_32
`define INPT_DW    32
`define INPT_DW1        (`INPT_DW - 1)
`define INPT_BYTE_DW1   (`INPT_DW/8 - 1)
`define INPT_BYTE_DW    (`INPT_BYTE_DW1 + 1)
module sm3_cmprss_core (
    input                       clk,
    input                       rst_n,

    input  [`INPT_DW1:0]        expnd_inpt_wj_i,                    
    input  [`INPT_DW1:0]        expnd_inpt_wjj_i,                    
    input                       expnd_inpt_lst_i,                  
    input                       expnd_inpt_vld_i,    

    output [255:0]              cmprss_otpt_res_o,
    output                      cmprss_otpt_vld_o
);

//每时钟输入的数据字数量 32bit位宽：1 64bit位宽：2
`ifdef SM3_INPT_DW_32
    localparam [1:0]            INPT_WORD_NUM               =   2'd1;
`elsif SM3_INPT_DW_64
    localparam [1:0]            INPT_WORD_NUM               =   2'd2;
`endif

localparam  [6:0]           CMPRSS_RND_NUM = 7'd64;

//A-H 字寄存器
reg		[31 : 0]	reg_a;
reg		[31 : 0]	reg_b;
reg		[31 : 0]	reg_c;
reg		[31 : 0]	reg_d;
reg		[31 : 0]	reg_e;
reg		[31 : 0]	reg_f;
reg		[31 : 0]	reg_g;
reg		[31 : 0]	reg_h;
reg		[31 : 0]	reg_tj;
reg		[5  : 0]	reg_cmprss_round;

reg                 cmprss_round_sm_16;

//结果寄存器
reg                 sm3_res_valid;
reg                 sm3_res_valid_r1;
reg  [255:0]        sm3_res;

reg                 cmprss_blk_res_finish;

//A-H 字运算中间值
wire	[31 : 0]	reg_a_new;
wire	[31 : 0]	reg_b_new;
wire	[31 : 0]	reg_c_new;
wire	[31 : 0]	reg_d_new;
wire	[31 : 0]	reg_e_new;
wire	[31 : 0]	reg_f_new;
wire	[31 : 0]	reg_g_new;
wire	[31 : 0]	reg_h_new;

`ifdef SM3_INPT_DW_64
    wire	[31 : 0]	reg_a_mid;
    wire	[31 : 0]	reg_b_mid;
    wire	[31 : 0]	reg_c_mid;
    wire	[31 : 0]	reg_d_mid;
    wire	[31 : 0]	reg_e_mid;
    wire	[31 : 0]	reg_f_mid;
    wire	[31 : 0]	reg_g_mid;
    wire	[31 : 0]	reg_h_mid;

    //两轮运算的 tj 值
    wire	[31 : 0]	reg_tj_rnd_odd;
    wire	[31 : 0]	reg_tj_rnd_even;
`endif

//块迭代标志
wire                cmprss_new_round_valid;
wire                cmprss_blk_start;  
wire                cmprss_blk_finish; 

//对输入的 wj 值打拍或者分离
reg                 sm3_wj_wjj_vld_r;
reg                 sm3_wj_wjj_lst_r;

`ifdef SM3_INPT_DW_32
    reg     [31:0]      wj_rnd_r;
    reg     [31:0]      wjj_rnd_r;
`elsif SM3_INPT_DW_64
    reg     [31:0]      wj_rnd_odd_r;
    reg     [31:0]      wjj_rnd_odd_r;
    reg     [31:0]      wj_rnd_even_r;
    reg     [31:0]      wjj_rnd_even_r;
`endif

//输入每数据块所属数据字计数
reg     [5:0]       inpt_wrd_of_blk_cntr;
wire                inpt_wrd_of_blk_cntr_add;
wire                inpt_wrd_of_blk_cntr_clr;

//管理tj寄存器
always @(posedge clk or negedge rst_n) begin
    if(~rst_n |cmprss_blk_res_finish) begin
        reg_tj          <=  32'h79cc4519;
    end
    else if(sm3_wj_wjj_vld_r)begin
        if(reg_cmprss_round == 6'd16 - INPT_WORD_NUM)
            reg_tj          <=  32'h9d8a7a87;
        
        else begin
            `ifdef SM3_INPT_DW_32
                reg_tj          <=  {reg_tj[30:0],reg_tj[31]};
            `elsif SM3_INPT_DW_64 //每次循环左移两位
                reg_tj          <=  {reg_tj[29:0],reg_tj[31:30]};
            `endif
        end
    end
end

`ifdef SM3_INPT_DW_64
    //两轮运算的 tj 值
    assign  	reg_tj_rnd_odd      =   {reg_tj[30:0],reg_tj[31]};
    assign  	reg_tj_rnd_even     =   reg_tj;
`endif

//对输入的 wj 值打拍或者分离
always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        sm3_wj_wjj_vld_r    <=   1'b0;
        sm3_wj_wjj_lst_r    <=   1'b0;        
    end
    else begin
        sm3_wj_wjj_vld_r    <=   expnd_inpt_vld_i;
        sm3_wj_wjj_lst_r    <=   expnd_inpt_lst_i;       
    end
end

`ifdef SM3_INPT_DW_32
    always @(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            wj_rnd_r        <=   32'd0;
            wjj_rnd_r       <=   32'd0;       
        end
        else begin
            wj_rnd_r        <=   expnd_inpt_wj_i;
            wjj_rnd_r       <=   expnd_inpt_wjj_i;     
        end
    end
    
`elsif SM3_INPT_DW_64
    always @(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            wj_rnd_odd_r    <=   32'd0;
            wjj_rnd_odd_r   <=   32'd0;       
            wj_rnd_even_r   <=   32'd0;       
            wjj_rnd_even_r  <=   32'd0;       
        end
        else begin
            {wj_rnd_even_r,wj_rnd_odd_r}    <=   expnd_inpt_wj_i;
            {wjj_rnd_even_r,wjj_rnd_odd_r}  <=   expnd_inpt_wjj_i;    
        end
    end
    
`endif

//标记最后一块
assign              cmprss_new_round_valid  =   sm3_wj_wjj_vld_r;  
assign              cmprss_blk_finish       =   inpt_wrd_of_blk_cntr_clr;  

//块运算完成信号 
always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        cmprss_blk_res_finish   <=  1'b0;
    end
    else begin
        cmprss_blk_res_finish   <=  inpt_wrd_of_blk_cntr_clr;
    end
end

//输入每数据块所属数据字计数
always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        inpt_wrd_of_blk_cntr              <= 6'b0;
    end else if(inpt_wrd_of_blk_cntr_add)begin
        inpt_wrd_of_blk_cntr              <= inpt_wrd_of_blk_cntr + INPT_WORD_NUM;
    end else if(inpt_wrd_of_blk_cntr_clr)begin
        inpt_wrd_of_blk_cntr              <= 6'b0;
    end
end
assign                  inpt_wrd_of_blk_cntr_add  = sm3_wj_wjj_vld_r;
assign                  inpt_wrd_of_blk_cntr_clr  = sm3_wj_wjj_vld_r 
                                                && inpt_wrd_of_blk_cntr == (CMPRSS_RND_NUM - INPT_WORD_NUM);

//压缩迭代轮计数
always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        reg_cmprss_round        <=  6'd0;
    end
    else if(cmprss_blk_finish)begin
        reg_cmprss_round        <=  6'd0;
    end
    else if(cmprss_new_round_valid)begin
        reg_cmprss_round        <=  reg_cmprss_round + INPT_WORD_NUM;
    end
end

//产生16轮内标记
always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        cmprss_round_sm_16      <= 1'b0;
    end else begin
        cmprss_round_sm_16      <= reg_cmprss_round <  6'd16 - INPT_WORD_NUM; //标识当前小于
    end
end

//寄存器组初值装填与迭代
always @(posedge clk or negedge rst_n) begin
    if((~rst_n) || sm3_res_valid_r1) begin
        reg_a	<=	32'h7380166f;//0;
		reg_b	<=	32'h4914b2b9;//0;
		reg_c	<=	32'h172442d7;//0;
		reg_d	<=	32'hda8a0600;//0;
		reg_e	<=	32'ha96f30bc;//0;
		reg_f	<=	32'h163138aa;//0;
		reg_g	<=	32'he38dee4d;//0;
		reg_h	<=	32'hb0fb0e4e;//0;
    end
    else if(cmprss_new_round_valid)begin
        reg_a	<=	reg_a_new;
		reg_b	<=	reg_b_new;
		reg_c	<=	reg_c_new;
		reg_d	<=	reg_d_new;
		reg_e	<=	reg_e_new;
		reg_f	<=	reg_f_new;
		reg_g	<=	reg_g_new;
		reg_h	<=	reg_h_new;
    end
    else if(cmprss_blk_res_finish)begin
        reg_a	<=	reg_a ^ sm3_res[255-:32];
		reg_b	<=	reg_b ^ sm3_res[223-:32];
		reg_c	<=	reg_c ^ sm3_res[191-:32];
		reg_d	<=	reg_d ^ sm3_res[159-:32];
		reg_e	<=	reg_e ^ sm3_res[127-:32];
		reg_f	<=	reg_f ^ sm3_res[95 -:32];
		reg_g	<=	reg_g ^ sm3_res[63 -:32];
		reg_h	<=	reg_h ^ sm3_res[31 -:32];
    end
end

//消息所属块均计算完毕，输出计算结果
always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        sm3_res_valid           <=  1'b0;
        sm3_res_valid_r1        <=  1'b0;
    end
    else begin
        sm3_res_valid           <=  sm3_wj_wjj_lst_r;
        sm3_res_valid_r1        <=  sm3_res_valid;
    end
end

always @(posedge clk or negedge rst_n) begin
    if((~rst_n) || sm3_res_valid_r1) begin
        sm3_res                 <=  {32'h7380166f, 32'h4914b2b9, 32'h172442d7, 32'hda8a0600, 32'ha96f30bc, 32'h163138aa, 32'he38dee4d, 32'hb0fb0e4e};
    end
    else if(cmprss_blk_res_finish)begin
        sm3_res                 <=  {reg_a,reg_b,reg_c,reg_d,reg_e,reg_f,reg_g,reg_h} ^ sm3_res;
    end
end

`ifdef SM3_INPT_DW_32
    sm3_cmprss_ceil_comb U_sm3_cmprss_ceil_comb
    (
        .cmprss_round_sm_16_i   (cmprss_round_sm_16),
        .tj_i                   (reg_tj),
        .reg_a_i                (reg_a),
        .reg_b_i                (reg_b),
        .reg_c_i                (reg_c),
        .reg_d_i                (reg_d),
        .reg_e_i                (reg_e),
        .reg_f_i                (reg_f),
        .reg_g_i                (reg_g),
        .reg_h_i                (reg_h),
        .wj_i                   (wj_rnd_r),
        .wjj_i                  (wjj_rnd_r),
        .reg_a_o                (reg_a_new),
        .reg_b_o                (reg_b_new),
        .reg_c_o                (reg_c_new),
        .reg_d_o                (reg_d_new),
        .reg_e_o                (reg_e_new),
        .reg_f_o                (reg_f_new),
        .reg_g_o                (reg_g_new),
        .reg_h_o                (reg_h_new)
    );

`elsif SM3_INPT_DW_64
    sm3_cmprss_ceil_comb U_sm3_cmprss_ceil_comb
    (
        .cmprss_round_sm_16_i   (cmprss_round_sm_16),
        .tj_i                   (reg_tj_rnd_even),
        .reg_a_i                (reg_a),
        .reg_b_i                (reg_b),
        .reg_c_i                (reg_c),
        .reg_d_i                (reg_d),
        .reg_e_i                (reg_e),
        .reg_f_i                (reg_f),
        .reg_g_i                (reg_g),
        .reg_h_i                (reg_h),
        .wj_i                   (wj_rnd_even_r),
        .wjj_i                  (wjj_rnd_even_r),
        .reg_a_o                (reg_a_mid),
        .reg_b_o                (reg_b_mid),
        .reg_c_o                (reg_c_mid),
        .reg_d_o                (reg_d_mid),
        .reg_e_o                (reg_e_mid),
        .reg_f_o                (reg_f_mid),
        .reg_g_o                (reg_g_mid),
        .reg_h_o                (reg_h_mid)
    );

    sm3_cmprss_ceil_comb U_sm3_cmprss_ceil_comb_1
    (
        .cmprss_round_sm_16_i   (cmprss_round_sm_16),
        .tj_i                   (reg_tj_rnd_odd),
        .reg_a_i                (reg_a_mid),
        .reg_b_i                (reg_b_mid),
        .reg_c_i                (reg_c_mid),
        .reg_d_i                (reg_d_mid),
        .reg_e_i                (reg_e_mid),
        .reg_f_i                (reg_f_mid),
        .reg_g_i                (reg_g_mid),
        .reg_h_i                (reg_h_mid),
        .wj_i                   (wj_rnd_odd_r),
        .wjj_i                  (wjj_rnd_odd_r),
        .reg_a_o                (reg_a_new),
        .reg_b_o                (reg_b_new),
        .reg_c_o                (reg_c_new),
        .reg_d_o                (reg_d_new),
        .reg_e_o                (reg_e_new),
        .reg_f_o                (reg_f_new),
        .reg_g_o                (reg_g_new),
        .reg_h_o                (reg_h_new)
    );
`endif

//输出控制
assign                      cmprss_otpt_vld_o     =   sm3_res_valid_r1;
assign                      cmprss_otpt_res_o     =   sm3_res;

always@(*) begin		
    if(cmprss_otpt_vld_o)
    begin
            $display("LOG: res : %64h",cmprss_otpt_res_o);
    end
end


endmodule