`timescale 1 ns / 1 ps
// -------------------------------------------------------------------------------
// COMPANY        : GRL - India
// ENGINEER       : Rajeshkumar Athram
// CREATE DATE    : 22.02.2021
// DESIGN NAME    : Intel S-10 SERDES reconfiguration
// MODULE NAME    : dyn_reconfig
// PROJECT NAME   : USB4 Test Solution
// TARGET DEVICES : INTEL STRATIX 10
// TOOL VERSIONS  :
// DESCRIPTION    : Logic to interface to Dynamic reconfiguration
// REMARKS        :
// DEPENDENCIES   :
// REVISION       :1.0 -
//
// -------------------------------------------------------------------------------
// CODE REVISION HISTORY :
// -------------------------------------------------------------------------------
// Ver: | Author   | Mod. Date  | Changes Made:
// V1.0a| Rajesh   | 2019-09-11 | Initial Release : Supports the followings
//      |          |            | Dynamic reconfiguration Interface for eqalization and loopback
//      |          |            |
//      |          |            |
//      |          |            |
// -------------------------------------------------------------------------------

// 0x144[1] ,0x137[7],0x132[5:4] ,0x144[1],0x142[4],0x11D[0]
//Encodings {0x11D[0], 0x132[5:4],0x137[7], 0x144[1], 0x142[4]} :
//6'b000000 - Disable reverse serial loopback
//6'b100101 - Enable pre-CDR reverse serial loopback
//6'b001010 - Enable post-CDR reverse serial loopback
module Ch1_dyn_reconfig (
    input  wire reconfig_clk,
    input  wire reconfig_reset,
    output reg  reconfig_write,
    output reg  reconfig_read,
    output reg [10:0] reconfig_address,
    output reg [31:0] reconfig_writedata,
    input  wire [31:0] reconfig_readdata,
    input  wire  reconfig_waitrequest,
    input wire  switch_eq,
    input wire  switch_lb,
    input wire en_dyn_reconfig,
    //  tx reset

    input wire tx_ready,
    input wire rx_ready,
    input wire tx_cal_busy,
    //rx reset
    input wire rx_cal_busy,
    input wire [1:0] sel_speed,     // speed selection
    output reg dyn_reconf_status,
    output reg reset_hold  // holds reset controller till dynamic reconfig done
);


reg  rx_reset_done;
wire pos_en_dyn_reconfig;
reg dly_en_dyn_reconfig;
reg dly2_en_dyn_reconfig;

// dly2 for testing
    always @ (posedge reconfig_clk or posedge reconfig_reset) begin
        if (reconfig_reset) begin
            dly_en_dyn_reconfig <= 0;
            dly2_en_dyn_reconfig <= 0;
        end else begin
            dly_en_dyn_reconfig <= en_dyn_reconfig;
            dly2_en_dyn_reconfig <= dly_en_dyn_reconfig;
        end
        end
    assign pos_en_dyn_reconfig = !dly_en_dyn_reconfig & en_dyn_reconfig;
    assign pos2_en_dyn_reconfig = !dly2_en_dyn_reconfig & dly_en_dyn_reconfig;


    reg [2:0]write_cnt;
    reg [3:0]read_cnt;
    reg [4:0] state;
    reg [1023:0] read_data;


    wire[31:0] reg_161;
    wire[31:0] reg_149;
    wire[31:0] reg_15F;
    wire[31:0] reg_15C;

    wire[31:0] reg_11D;
    wire[31:0] reg_132;
    wire[31:0] reg_137;
    wire[31:0] reg_144;
    wire[31:0] reg_142;
    wire[31:0] reg_4E2;
	 wire[31:0] reg_ch_100;
    wire[31:0] reg_ch_000;
	 

    assign reg_161 = read_data[31:0];
    assign reg_149 = read_data[63:32];
    assign reg_15F = read_data[95:64];
    assign reg_15C = read_data[127:96];
    assign reg_11D = read_data[159:128];
    assign reg_132 = read_data[191:160];
	 assign reg_137 = read_data[223:192];
    assign reg_144 = read_data[255:224];
    assign reg_142 = read_data[287:256];
    assign reg_4E2 = read_data[319:288];
    assign reg_4E2 = read_data[319:288];
    assign reg_ch_100 = read_data[351:320];
    assign reg_ch_000 = read_data[383:352];
    localparam IDLE = 0,
               DISABLE_BAGCAL  = 1,
			      READ_REGISTERS = 2,
               STORE_READ_DATA = 3,
               SWITCH_SEL_EQ =4,
					BYPASS_EQ =5,
               MAN_DFE_OFF   =6,  // DFE: 0x148[1]; CTLE:0x11A[7:4],0x11E[7],0x11C[4:0]; VGA:0x11F[0],0x11A[3:0]
               ADAP_DFE_OFF    =7,
               EQUL_DONE    =8,
               SWITCH_SEL_LB =9,
               METALLIC_MODE =10, // 0x144[1] ,0x137[7],0x132[5:4],0x142[4],0x11D[0]
               RSL_MODE    =11,
               LB_DONE    =12,
               RESET_DISABLE  =13,			      
					REQUEST_CH_PRESICE_CAL  =14,
               RECAL_REQUEST  =15,
               RECAL_DONE  =16,
               READ_REG_VER = 17,
               RESET_REQUEST = 18,
			      READ_REG_VER1 = 19,  // verifying cal
  
               DYN_RECONFIG_DONE =20;

    always @ (posedge reconfig_clk or posedge reconfig_reset) begin
        if (reconfig_reset) begin
            state    <= IDLE;
            reconfig_writedata    <= 0;
            reconfig_address <= 11'h0;
            reconfig_writedata <= 31'd1;
            dyn_reconf_status = 0;
            write_cnt    <= 0;
            read_cnt    <= 0;
            reset_hold    <= 0;
			   reconfig_read    <= 0;
				read_data       <= 0;
			   reconfig_write     <= 0;
        end else begin
            case(state)
            IDLE: begin       
                // reconfig_writedata   <= 0;
                dyn_reconf_status = 0;
                if(en_dyn_reconfig) begin  // Enable signal from issp
              //      reset_hold = 1;
						  reconfig_read <= 1'b1;
                     reconfig_address <= 11'h404;
                    state    <= DISABLE_BAGCAL;
                end else begin
                    state    <= IDLE;
                end
            end
			DISABLE_BAGCAL: begin
                 if (!reconfig_waitrequest) begin
              //  if (reconfig_readdata[0]==0) begin
                    reconfig_write <= 1'b1;
                    reconfig_address <= 11'h4E2;
                   // reconfig_writedata <=  {reg_4E2[31:5],4'b1111};
                    reconfig_writedata <=  15;
                    state    <= READ_REGISTERS;
                end else begin
                    state    <= DISABLE_BAGCAL;
                end
            end
			READ_REGISTERS:begin //registers involved for pll 100,000,540
			 reconfig_write <= 1'b0;
                    //0x144, 0x142, 0x11D, 0x132, 0x137
			    case (read_cnt)
			 /*   3'd0:begin
				    reconfig_read <= 1'b1;
					state    <= STORE_READ_DATA;
				 end  */
			    4'd0:begin
				    reconfig_read <= 1'b1;
                    reconfig_address <= 11'h4E2;
				    state    <= STORE_READ_DATA;
				end
				4'd1:begin
				    reconfig_read <= 1'b1;
                    reconfig_address <= 11'h142;
				    state    <= STORE_READ_DATA;
				end
				4'd2:begin
				    reconfig_read <= 1'b1;
                    reconfig_address <= 11'h144;
				    state    <= STORE_READ_DATA;
				end
				4'd3:begin
				    reconfig_read <= 1'b1;
                    reconfig_address <= 11'h137;
				    state    <= STORE_READ_DATA;
				end
				4'd4:begin
				    reconfig_read <= 1'b1;
                    reconfig_address <= 11'h132;
				    state    <= STORE_READ_DATA;
				end
				4'd5:begin
				    reconfig_read <= 1'b1;
                    reconfig_address <= 11'h11D;
				    state    <= STORE_READ_DATA;
				end
				4'd6:begin
				    reconfig_read <= 1'b1;
                    reconfig_address <= 11'h15C;
				    state    <= STORE_READ_DATA;
				end
				4'd7:begin
				    reconfig_read <= 1'b1;
                    reconfig_address <= 11'h15F;
				    state    <= STORE_READ_DATA;
				end
				4'd8:begin
				    reconfig_read <= 1'b1;
                    reconfig_address <= 11'h149;
				     state    <= STORE_READ_DATA;
				end
				4'd9:begin
				    reconfig_read <= 1'b1;
                    reconfig_address <= 11'h161;
					state    <= STORE_READ_DATA;
				   end
				4'd10:begin
				    reconfig_read <= 1'b1;
                    reconfig_address <= 11'h100;
					state    <= STORE_READ_DATA;
				   end
					4'd11:begin
				    reconfig_read <= 1'b1;
                    reconfig_address <= 11'h000;
					state    <= STORE_READ_DATA;
				   end
					
			    default : begin
					reconfig_read <= 1'b1;
               reconfig_address <= 11'h4E2;
					state    <= STORE_READ_DATA;	  
				end 
				endcase end
					
			STORE_READ_DATA:begin
                reconfig_read <= 1'b0;
                    if (read_cnt >= 4'd11) begin
                        state <= SWITCH_SEL_EQ;
                    end else if (!reconfig_waitrequest) begin
                        read_cnt <= read_cnt + 1'b1;
                        read_data <= {read_data[1023:0], reconfig_readdata[31:0]};//store & left shift
                        state <= READ_REGISTERS;
                    end
                end
            SWITCH_SEL_EQ: begin
                reconfig_write <= 0;
					 reconfig_read <= 0;
                case(switch_eq)
                    1'd0: begin
                    //    state    <= MAN_DFE_OFF;
                        state    <= BYPASS_EQ;
                end
                    1'd1: begin
                        state    <= ADAP_DFE_OFF;
                end
                endcase
            end
			BYPASS_EQ:begin
                if (!reconfig_waitrequest) begin
                    write_cnt <= write_cnt + 1'b1;
                    case(write_cnt)
                        3'd0:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h161;
                            reconfig_writedata <= {reg_161[31:7],1'b1,reg_161[5:0]};
                        end
                        3'd1:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h149;
                            reconfig_writedata <= {reg_149[31:8],1'b1,reg_161[6:0]};
                        end
                        3'd2:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h15F;
                            reconfig_writedata <= {reg_15F[31:4],1'b1,reg_15F[2:0]};
                        end
                        3'd3:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h15C;
                            reconfig_writedata <=  {reg_15C[31:4],1'b1,reg_15C[2:0]};
							state    <= EQUL_DONE;
                        end
                        default: begin
                            reconfig_write <= 1'b0;
                            reconfig_address <= 11'h000;
                            reconfig_writedata <= 31'h0;
                        end
                    endcase
			 end  end
            //       Enable DFE adaptation  0x148[1] read-write adp_dfe_en 1'b0: Disable  1'b1: Enable
            MAN_DFE_OFF:begin
                if (!reconfig_waitrequest) begin
                    write_cnt <= write_cnt + 1'b1;
                    case(write_cnt)
                        3'd0:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h148;
                            reconfig_writedata <= 31'd0;
                        end
                        3'd1:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h11A;
                            reconfig_writedata <= 31'd0;
                        end
                        3'd2:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h11E;
                            reconfig_writedata <= 31'd0;
                        end
                        3'd3:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h11C;
                            reconfig_writedata <= 31'd0;
                        end
                        3'd4:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h11F;
                            reconfig_writedata <= 31'd0;
                            state    <= EQUL_DONE;
                        end
                        default: begin
                            reconfig_write <= 1'b0;
                            reconfig_address <= 11'h000;
                            reconfig_writedata <= 31'h0;
                        end
                    endcase
                end else begin
                    state    <= MAN_DFE_OFF;
                end
            end
            ADAP_DFE_OFF:begin
                if (!reconfig_waitrequest) begin
                    write_cnt <= write_cnt + 1'b1;
                    case(write_cnt)
                        3'd0:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h148;
                            reconfig_writedata <= 31'd1;
                        end
                        3'd1:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h148;
                            reconfig_writedata <= 31'd50;
                        end
                        3'd2:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h161;
                            reconfig_writedata <= 31'd64;
                            state    <= EQUL_DONE;
                        end
                        default: begin
                            reconfig_write <= 1'b0;
                            reconfig_address <= 11'h000;
                            reconfig_writedata <= 31'h0;
                        end
                    endcase
                    end else begin
                        state    <= MAN_DFE_OFF;
                end
            end

            EQUL_DONE:begin
                reconfig_write <= 0;
                state    <= SWITCH_SEL_LB;
                write_cnt    <= 0;
            end

            SWITCH_SEL_LB:begin
                case(switch_lb)
                    1'd0: begin
                        state    <= METALLIC_MODE;
                    end
                        1'd1: begin
                        state    <= RSL_MODE;
                    end
                endcase
            end
            METALLIC_MODE:begin // Encodings {0x11D[0], 0x132[5:4],0x137[7], 0x144[1], 0x142[4]} ://6'b100101 - Enable pre-CDR reverse serial loopback
                if (!reconfig_waitrequest) begin
                    write_cnt <= write_cnt + 1'b1;
                    case(write_cnt)
                        3'd0:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h11D;
                            reconfig_writedata <=  {reg_11D[31:1],1'b1 };//0x11D[0]
                        end
                        3'd1:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h132;
                            reconfig_writedata <= {reg_132[31:6],2'b00,reg_132[3:0] };//reg_132[5:4]
                        end
                        3'd2:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h137;
                            reconfig_writedata <= {reg_137[31:8],1'b1,reg_137[6:0] };//0x137[7]
                        end
                        3'd3:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h144;
                            reconfig_writedata <= {reg_144[31:2],1'b0,reg_144[0] };//0x144[1]
                        end
                        3'd4:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h142;
                            reconfig_writedata <=  {reg_142[31:5],1'b1,reg_142[3:0] };//0x142[4]
                            state    <= LB_DONE;
                        end
                        default: begin
                            reconfig_write <= 1'b0;
                            reconfig_address <= 11'h000;
                            reconfig_writedata <= 31'd0;
                        end
                        endcase
                        end else begin
                        state    <= METALLIC_MODE;
                    end
            end

            RSL_MODE:begin   //6'b001010 - Enable post-CDR reverse serial loopback
                if (!reconfig_waitrequest) begin
                    write_cnt <= write_cnt + 1'b1;
                    case(write_cnt)
                        3'd0:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h11D;
                            reconfig_writedata <=  {reg_11D[31:1],1'b0 };//0x11D[0]
                        end
                        3'd1:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h132;
                            reconfig_writedata <= {reg_132[31:6],2'b01,reg_132[3:0] };//reg_132[5:4]
                        end
                        3'd2:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h137;
                            reconfig_writedata <= {reg_137[31:8],1'b0,reg_137[6:0] };//0x137[7]
                        end
                        3'd3:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h144;
                            reconfig_writedata <= {reg_144[31:2],1'b1,reg_144[0] };//0x144[1]
                        end
                        3'd4:begin
                            reconfig_write <= 1'b1;
                            reconfig_address <= 11'h142;
                            reconfig_writedata <=  {reg_142[31:5],1'b0,reg_142[3:0] };//0x142[4]
                            state    <= LB_DONE;
                        end
                        default: begin
                            reconfig_write <= 1'b0;
                            reconfig_address <= 11'h000;
                            reconfig_writedata <= 31'd0;
                        end
                    endcase
                    end else begin
                        state    <= METALLIC_MODE;
                end
            end 

            LB_DONE:begin
				reset_hold <= 0;
                reconfig_write <= 0;
                state    <= RECAL_REQUEST;
                write_cnt    <= 0;
            end


				 RECAL_REQUEST:begin       
                if (!reconfig_waitrequest) begin
                    reconfig_write <= 1'b1;
                    reconfig_address <= 11'h100;
                    reconfig_writedata <=  {reg_ch_100[31:2],2'b11};
                    state    <= REQUEST_CH_PRESICE_CAL;
                end else begin
                    state    <= RECAL_REQUEST;
                end 
            end
				REQUEST_CH_PRESICE_CAL:begin       
                if (!reconfig_waitrequest) begin
                    reconfig_write <= 1'b1;
                    reconfig_address <= 11'h000;
                    reconfig_writedata <=  {reg_ch_000[31:1],1'b1};
                    state    <= READ_REG_VER;
                end else begin
                    state    <= REQUEST_CH_PRESICE_CAL;
                end 
            end
				
            READ_REG_VER:begin  
			  reconfig_write <= 0;	
				if (!reconfig_waitrequest) begin
                    reconfig_read <= 1'b1;
                    reconfig_address <= 11'h481;				
                    state    <= READ_REG_VER1;
                end else begin 
				    state    <= READ_REG_VER;
				end 	end			
            READ_REG_VER1:begin   
				if (reconfig_readdata[1:0] == 2'b00) begin
				
                    state    <= RECAL_DONE;
                end else begin 
				    state    <= READ_REG_VER1;
				end end				
				
            RECAL_DONE:begin
                if(!tx_cal_busy && !rx_cal_busy )begin
                    state    <= RESET_DISABLE;
                end else begin
                    state    <= RECAL_DONE;
                end end
					 
			 RESET_DISABLE:begin
			       reset_hold = 0;
					 state    <= DYN_RECONFIG_DONE;
                if (!reconfig_waitrequest) begin
                    reconfig_write <= 1'b1;
                    reconfig_address <= 11'h4E2;
                    reconfig_writedata <=  {reg_4E2[31:5],4'b0000};
                    state    <= DYN_RECONFIG_DONE;
                end else begin
                    state    <= RESET_DISABLE;
                end 
            end		 
				
            RECAL_DONE:begin
                if(!tx_cal_busy && !rx_cal_busy )begin
                    state    <= READ_REG_VER;
                end else begin
                    state    <= RECAL_DONE;
                end end
            READ_REG_VER:begin
				if (!reconfig_waitrequest) begin
                    reconfig_read <= 1'b1;
                    reconfig_address <= 11'h481;
                    state    <= READ_REG_VER1;
                end else begin
				    state    <= READ_REG_VER;
				end end
		    READ_REG_VER1:begin
			    if (!reconfig_waitrequest) begin
                    reconfig_read <= 1'b1;
                    reconfig_address <= 11'h480;
                    state    <= DYN_RECONFIG_DONE;
                end else begin
				    state    <= READ_REG_VER1;
				end end   
            DYN_RECONFIG_DONE:begin
                dyn_reconf_status = 1;
					 reconfig_read <= 0;
                if(pos_en_dyn_reconfig)begin
                    reconfig_write <= 1'b0;
					     write_cnt    <= 0;
                    reconfig_address <= 11'h000;
                    reconfig_writedata <= 31'd0;
                    state    <= IDLE;
                end else begin
                    state    <= DYN_RECONFIG_DONE;
                end
                end
            endcase
            end
    end


endmodule
