`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 Ch2_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,
    input wire pll_reconfig_waitrequest,
    //  tx reset
    input wire pll_cal_busy,
    input wire tx_ready,
    input wire rx_ready,
    input wire tx_cal_busy,
    input wire pll_locked,
    //rx reset
    input wire rx_cal_busy,
    input wire [1:0] sel_speed,     // speed selection
    output reg        pll_reconfig_write,
    output reg [10:0]  pll_reconfig_address,
    output reg [31:0]  pll_reconfig_writedata, 
    input wire [31:0]  pll_reconfig_readdata,
    output reg dyn_reconf_status,
    output reg pll_reconfig_read,
    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 dly_pll_reconfig_waitrequest;
    reg dly_reconfig_waitrequest;
	 
    always @ (posedge reconfig_clk or posedge reconfig_reset) begin
        if (reconfig_reset) begin
            dly_pll_reconfig_waitrequest <= 0;
            dly_reconfig_waitrequest <= 0;
        end else begin
            dly_pll_reconfig_waitrequest <= pll_reconfig_waitrequest;
            dly_reconfig_waitrequest <= reconfig_waitrequest;
        end
        end
		  
		  
	wire neg_pll_reconfig_waitrequest;
	wire neg_reconfig_waitrequest;
	
    assign neg_pll_reconfig_waitrequest = !pll_reconfig_waitrequest & dly_pll_reconfig_waitrequest;
    assign neg_reconfig_waitrequest = !dly_reconfig_waitrequest & reconfig_waitrequest;



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


   // PLL 
    wire[31:0] reg_100;
    wire[31:0] reg_000;
    wire[31:0] reg_540;
	
	
    assign reg_100 = pll_read_data[63:32];
    assign reg_000 = pll_read_data[95:64];
    assign reg_540 = pll_read_data[127:96];
	
    localparam IDLE = 0,
               DISABLE_BAGCAL  = 1,
               PLL_READ_REGISTERS =2,
               STORE_PLL_READ_DATA =3,
			    PLL_READY_RECONFIG = 4,
				 
               PRESICE_ACC_RETURN = 5, 
               PRESICE_OP_COMPL = 6, 
               SPEED_SELECT    =7,
               PRESICE_RETURN = 8,
               PLL_RECAL = 9,   
               READ_STATUS_PLL = 10,   
              CHECK_STATUS_PLL = 11,
               DYN_RECONFIG_DONE =12;

    always @ (posedge reconfig_clk or posedge reconfig_reset) begin
        if (reconfig_reset) begin
            state        <= IDLE;
            pll_reconfig_write <= 0;
            reconfig_writedata    <= 0;
            pll_reconfig_write    <= 0;
            pll_reconfig_address <= 11'h0;
            pll_reconfig_writedata <= 31'd0;
            dyn_reconf_status = 0;
            write_cnt    <= 0;
            read_cnt    <= 0;
            pll_read_cnt    <= 0;
            reset_hold    <= 0;
			   reconfig_read    <= 0;
				read_data       <= 0;
				pll_read_data       <= 0;
            reconfig_write     <= 0;
            pll_reconfig_read    <= 0;
        end else begin
            case(state)
            IDLE: begin                                                  
                dyn_reconf_status = 0;
                if(en_dyn_reconfig) begin  // Enable signal from issp 
                 //   reset_hold = 1;
					  //   reconfig_read <= 1'b1;
                 //   reconfig_address <= 11'h4E2;
                    state    <= PLL_READ_REGISTERS;
                end else begin 
                    state    <= IDLE;
                end
            end				

					
			PLL_READ_REGISTERS:begin //registers involved for pll 100,000,540            
                    //0x144, 0x142, 0x11D, 0x132, 0x137
			 case (pll_read_cnt)
			    3'd0:begin
				   pll_reconfig_read <= 1'b1;
					pll_reconfig_address <= 11'h540;  
                   state    <= STORE_PLL_READ_DATA;					 
				end
				3'd1:begin
				   pll_reconfig_read <= 1'b1;
                   pll_reconfig_address <= 11'h000;
					state    <= STORE_PLL_READ_DATA;
				end
				3'd2:begin
				   pll_reconfig_read <= 1'b1;
                   pll_reconfig_address <= 11'h100;
				   state    <= STORE_PLL_READ_DATA;
				end

            3'd3:begin 
				   pll_reconfig_read <= 1'b1;
               pll_reconfig_address <= 11'h540;
					state    <= STORE_PLL_READ_DATA;
				end
				3'd4:begin
					state    <= STORE_PLL_READ_DATA;
				end
				
				default: begin
                   pll_reconfig_read <= 1'b0;
                   pll_reconfig_address <= 11'h0; 
                   state    <= STORE_PLL_READ_DATA;
                   end
                endcase
            end
			STORE_PLL_READ_DATA:begin      
                if (pll_read_cnt >= 3'd5) begin
                    state <= PLL_READY_RECONFIG;
                  end else if (!pll_reconfig_waitrequest) begin
                    pll_read_cnt <= pll_read_cnt + 1'b1;
                    pll_read_data <= {pll_read_data[127:0], pll_reconfig_readdata[31:0]};//store & left shift
                    state <= PLL_READ_REGISTERS;
                    end else begin
						  	state    <= STORE_PLL_READ_DATA;
						  end	end
            PLL_READY_RECONFIG: begin  // Request PreSICE to configure the fPLL/ATX PLL/CDR/CMU PLL in preparation for reconfiguration       

				  if (!pll_reconfig_waitrequest) begin
                    pll_reconfig_write <= 1'b1;
                    pll_reconfig_read <= 1'b0;
                    pll_reconfig_address <=   11'h100;
                    pll_reconfig_writedata <= {reg_100[31:2],1'b1,reg_100[0]};
                    state    <= PRESICE_ACC_RETURN;
                end else begin
                    state    <= PLL_READY_RECONFIG;
                end
            end
            PRESICE_ACC_RETURN: begin  //Return the internal configuration bus access to PreSICE by writing a 0x01 to address 0x000 of the fPLL/ATX PLL/CDR/CMU    PLL,for reconfiguration
                if (!pll_reconfig_waitrequest) begin
                    pll_reconfig_write <= 1'b1;
                    pll_reconfig_address <= 11'h000;
                    pll_reconfig_writedata <= {reg_000[31:1],1'b1};
                    state    <= PRESICE_OP_COMPL;
                end else begin
                    state    <= PRESICE_ACC_RETURN;
                end
            end
            PRESICE_OP_COMPL: begin  //PreSICE to complete the operation by monitoring the pll_cal_busy or rx_cal_busy signal  
				       
                if (!pll_cal_busy && !pll_reconfig_waitrequest) begin
				//	  pll_reconfig_write <= 1'b1;
                    state    <= SPEED_SELECT;
                end else begin
                    state    <= PRESICE_OP_COMPL;
                end
            end
            SPEED_SELECT:begin 
		              		
					if (!pll_reconfig_waitrequest) begin
					      pll_reconfig_write <= 1'b1;
							pll_reconfig_address <= 11'h540;
                    case(sel_speed)
                        2'd1:begin  //5g
                       //     pll_reconfig_write <= 1'b1;
                        //    pll_reconfig_address <= 11'h540;
                            pll_reconfig_writedata <= {reg_540[31:4],3'b000};
                            state    <= PLL_RECAL;
                        end
                        2'd2:begin  //10g
                      //      pll_reconfig_write <= 1'b1;
                        //    pll_reconfig_address <= 11'h540;
                            pll_reconfig_writedata <= {reg_540[31:4],3'b001};
                            state    <= PLL_RECAL;
                        end
                        2'd3:begin  //10.3125g
                        //    pll_reconfig_write <= 1'b1;
                       //     pll_reconfig_address <= 11'h540;
                            pll_reconfig_writedata <= {reg_540[31:4],3'b010};
                            state    <= PLL_RECAL;
                        end
								
                        2'd0:begin  //10.3125g
                        //    pll_reconfig_write <= 1'b1;
                      //      pll_reconfig_address <= 11'h540;
                            pll_reconfig_writedata <= {reg_540[31:4],3'b001};
                            state    <= PLL_RECAL;
                        end
								endcase
						  end else begin
				         	state    <= SPEED_SELECT;
                end  end 
			 
          PLL_RECAL: begin    
                if (!pll_reconfig_waitrequest) begin
                    pll_reconfig_write <= 1'b1;
                    pll_reconfig_address <= 11'h100;
                    pll_reconfig_writedata <= {reg_100[31:1],1'b1};
                    state    <= PRESICE_RETURN;
                end else begin
                    state    <= PLL_RECAL;
                end
            end
								
            PRESICE_RETURN: begin  
                if (!pll_reconfig_waitrequest) begin
                    pll_reconfig_write <= 1'b1;
                    pll_reconfig_address <= 11'h000;
                    pll_reconfig_writedata <= {reg_000[31:1],1'b1};
                    state    <= READ_STATUS_PLL;
                end else begin
                    state    <= PRESICE_RETURN;
                end
            end
				
            READ_STATUS_PLL: begin 
				       pll_reconfig_write <= 1'b0;
                if (!pll_reconfig_waitrequest) begin
				       pll_reconfig_read <= 1'b1;
                   pll_reconfig_address <= 11'h480;
                    state    <= CHECK_STATUS_PLL;
                end else begin
                    state    <= READ_STATUS_PLL;
                end
            end
					 
            CHECK_STATUS_PLL: begin   
				   pll_reconfig_read <= 1'b0;
                if (pll_reconfig_readdata[1]==0) begin
				   
                    state    <= DYN_RECONFIG_DONE;
                end else begin
                    state    <= CHECK_STATUS_PLL;
                end
            end
								
         
            DYN_RECONFIG_DONE:begin   
                dyn_reconf_status = 1;
                if(pos_en_dyn_reconfig)begin
					   reconfig_read <= 1'b0;
                     reconfig_write <= 1'b0;
							write_cnt    <= 0;
                     pll_reconfig_write <= 0;
                     reconfig_address <= 11'h000;
                     reconfig_writedata <= 31'd0;
                     pll_reconfig_write <= 1'b0;
                     pll_reconfig_address <= 11'h0;
                     pll_reconfig_writedata <= 31'd0;
                     state    <= IDLE;
                end else begin
                    state    <= DYN_RECONFIG_DONE;
                end
                end
            endcase
            end
    end


endmodule
