///////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------
//
//  © 2022 Microchip Technology Inc. and its subsidiaries
//  All rights reserved.
//                                                                 
//  ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
//  ACCORDANCE WITH THE MICROCHIP LICENSE AGREEMENT AND MUST BE APPROVED
//  IN ADVANCE IN WRITING.
//
//-------------------------------------------------------------------------
// Title        : uart_if.v
// Author       : <Application Team>
// Description  : Interface for UART communication. 
// Hierarchy    :
//               hdl           
//					led_block.v   
//					prbs_checker.v    
//					prbs_generator.v     
//					prbs_wav_sel.v
//					reset_synchronizer.v
//					uart_if.v         <-- This module
//					wav_gen_16bit.v
//					err_gen.v      
//  Target device: <Family:PolarFire> <Die:MPF300T> <Pkg:FCG484>  
//
//-------------------------------------------------------------------------

//-----------------------------------------------------------------------
module UART_IF(CLK,
               DATA_IN,
               DATA_OUT,
               RESET_N,
               WEN,
               OEN,
               TX_RDY,
               RX_RDY,
               DATA_WADDR,
               JESD_RDATA,
               DOUT_RDATA,
               R_ADDR,
               DATA_WEN,
               STATUS_OUT,
               SYNC_N,
               ALIGNED,
               CGS_ERR,
               NIT_ERR,
               DISP_ERR,
               LINK_CD_ERR,
               UCC_ERR,
               DATA_ERR,
               ERR_NO,
               EPCS_0_RX_VAL,
               P_W_SEL,
               PRBS_SEL,
               ERR_EN,
               LINK_ERR_EN);
  //----------------------------------------------------------------------
  // Inputs
  //-----------------------------------------------------------------------
  input[7 : 0] DATA_IN; // UART data input
  output[7 : 0] DATA_OUT; // UART data output
  input CLK; // Clock input, 156.25 MHz
  input RESET_N; // Sync reset, active low
  input TX_RDY; // UART status bit
  input RX_RDY; // UART status bit
  input[31 : 0] JESD_RDATA; // JESD status form URAM
  input[31 : 0] DOUT_RDATA; // JESD data form URAM
  input SYNC_N; // Status of  JESD204BRX :SYNC_N  signal
  input ALIGNED; // Status of  JESD204BRX :ALIGNED signal
  input CGS_ERR; // Status of  JESD204BRX :CGS Error signal
  input LINK_CD_ERR; // Status of  JESD204BRX :LINK_CD Error signal
  input UCC_ERR; // Status of  JESD204BRX :UCC Error signal
  input[3 : 0] NIT_ERR; // Status of  XCVR : LANE0_RX_CODE_VIOLATION  signal
  input[3 : 0] DISP_ERR; // Status of  XCVR : LANE0_RX_DISPARITY_ERROR signal          
  input EPCS_0_RX_VAL; // Status of  XCVR : LANE0_RX_VAL signal         
  input DATA_ERR; // Status of prbs_checker : o_bad signal
  input[4 : 0] ERR_NO; // Status of prbs_checker : o_error signal
  //-----------------------------------------------------------------------
  // Outputs
  //-----------------------------------------------------------------------
  output[9 : 0] R_ADDR; // URAM Read address
  output[9 : 0] DATA_WADDR; // URAM write address
  output[31 : 0] STATUS_OUT; // Status of JESD204B
  output DATA_WEN;
  output P_W_SEL; // prbs or wave selction
  output[1 : 0] PRBS_SEL; // PRBS/wave pattern selection
  output ERR_EN; // prbs error enable
  output LINK_ERR_EN; // link error enable
  output WEN; // UART Active low write enable.
  output OEN; // UART Active low read enable.
  //-----------------------------------------------------------------------
  // Internal signals
  //-----------------------------------------------------------------------
  wire[7 : 0] DATA_IN;
  reg[7 : 0] DATA_OUT;
  wire CLK;
  wire RESET_N;
  wire TX_RDY;
  wire RX_RDY;
  reg WEN;
  reg OEN;
  wire[31 : 0] JESD_RDATA;
  wire[31 : 0] DOUT_RDATA;
  wire[31 : 0] STATUS_OUT;
  wire[63 : 0] RDATA;
  reg RAM_REN;
  reg[9 : 0] R_ADDR;
  reg WR_COMPLETE;
  reg[4 : 0] rfsm;
  reg DATA_WEN;
  reg[9 : 0] DATA_WADDR;
  reg P_W_SEL;
  reg[1 : 0] PRBS_SEL;
  reg ERR_EN;
  reg LINK_ERR_EN;
  reg[7 : 0] UDATA[0 : 255];
  reg[7 : 0] UADDR;
  reg rx_en;
  reg[7 : 0] UDATA1;
  assign STATUS_OUT = { 1'b0, SYNC_N //30   Status of  JESD204BRX :SYNC_N  signal
                        , ALIGNED //29   Status of  JESD204BRX :ALIGNED signal
                        , 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0,1'b0,CGS_ERR //20 Status of  JESD204BRX :CGS Error signal
                        , LINK_CD_ERR //19    Status of  JESD204BRX :LINK_CD Error signal
                        , UCC_ERR //18    Status of  JESD204BRX :UCC Error signal
                        , 1'b0, EPCS_0_RX_VAL //16    Status of  XCVR : LANE0_RX_VAL signal 
                        , 1'b0, 1'b0, DATA_ERR //13    Status of prbs_checker : o_bad signal
                        , DISP_ERR //12-9  Status of  XCVR : LANE0_RX_DISPARITY_ERROR signal
                        , NIT_ERR //8-5   Status of  XCVR : LANE0_RX_CODE_VIOLATION  signal
                        , ERR_NO //4-0   Status of prbs_checker : o_error signal
                      };
  parameter s0 = 5'b00000,
            s1 = 5'b00001,
            s2 = 5'b00011,
            s3 = 5'b00100,
            s4 = 5'b00101,
            s5 = 5'b00110,
            s6 = 5'b00111,
            s7 = 5'b01000,
            s8 = 5'b01001;
  parameter s9 = 5'b01010,
            s10 = 5'b01011,
            s11 = 5'b01100,
            s12 = 5'b01101,
            s13 = 5'b01110,
            s14 = 5'b01111,
            s15 = 5'b10000,
            s16 = 5'b10001,
            s17 = 5'b10010;
  parameter s18 = 5'b10011,
            s19 = 5'b10100,
            s20 = 5'b10101,
            s21 = 5'b10110,
            s22 = 5'b10111,
            s23 = 5'b11000,
            s24 = 5'b11001;
  assign RDATA = { JESD_RDATA, DOUT_RDATA };
  //This block is used communicate with UART
  //
  always
    @(posedge CLK or
      negedge RESET_N)
    if (~RESET_N)
      begin
        RAM_REN <= 1'b1;
        R_ADDR <= 10'b0;
        DATA_OUT <= 8'b0;
        WR_COMPLETE <= 1'b0;
        rfsm <= s0;
        WEN <= 1'b1;
        OEN <= 1'b1;
        P_W_SEL <= 1'b0;
        PRBS_SEL <= 2'b00;
        ERR_EN <= 1'b0;
        LINK_ERR_EN <= 1'b0;
        DATA_WEN <= 1'b0;
        UADDR <= 8'h0;
        rx_en <= 1'b0;
      end
    else
      begin
        case (rfsm)
          s0:
            begin
              if (RX_RDY == 1'b1)
                begin
                  UDATA[UADDR] <= DATA_IN;
                  OEN <= 1'b0;
                  if (rx_en)
                    begin
                      UADDR <= UADDR + 1'b1;
                      rx_en <= 1'b0;
                      if (UADDR == 8'h2)
                        begin
                          UADDR <= 8'h0;
                          rfsm <= s1;
                        end
                    end
                end
              else
                begin
                  OEN <= 1'b1;
                  rx_en <= 1'b1;
                end
            end
          s1:
            begin
              if (UDATA[0] == 8'b00001001)
                rfsm <= s2;
              else
                if (UDATA[0] == 8'b00000001)
                  rfsm <= s4;
                else
                  if (UDATA[0] == 8'b00000010)
                    rfsm <= s6;
                  else
                    if (UDATA[0] == 8'b00000011)
                      rfsm <= s22;
                    else
                      if (UDATA[0] == 8'b00000100)
                        rfsm <= s23;
                      else
                        if (UDATA[0] == 8'b00000101)
                          rfsm <= s24;
            end
          //UART connection establishing
          s2:
            begin
              if (TX_RDY == 1'b1)
                begin
                  DATA_OUT <= 8'b01100001; //a
                  WEN <= 1'b0;
                end
              else
                begin
                  WEN <= 1'b1;
                  OEN <= 1'b1;
                  rfsm <= s3;
                end
            end
          s3:
            begin
              if (TX_RDY == 1'b0)
                begin
                  rfsm <= s0;
                  WEN <= 1'b1;
                end
            end
          // PRBS/waveform selction and PRBS type/waveform type selction                                 
          s4:
            begin
              UDATA1 <= UDATA[1];
              P_W_SEL <= UDATA1[2];
              PRBS_SEL <= UDATA1[1 : 0];
              rfsm <= s5;
            end
          //Assigning signals for URAM for storing JESD204BRX status
          //and JESD204BRX recieved data                   
          s5:
            begin
              DATA_WADDR <= DATA_WADDR + 1'b1;
              DATA_WEN <= 1'b1;
              if (DATA_WADDR == 10'b1111111111)
                begin
                  rfsm <= s0;
                  DATA_WEN <= 1'b0;
                  DATA_WADDR <= 10'h0;
                end
            end
          //writing to UART (JESD204BRX status and JESD204BRX recieved data)      
          s6:
            begin
              if (TX_RDY == 1'b1)
                begin
                  OEN <= 1'b1;
                  RAM_REN <= 1'b1;
                  R_ADDR <= R_ADDR + 1'b1;
                  if (R_ADDR == 10'b1111111111)
                    rfsm <= s0;
                  else
                    rfsm <= s7;
                end
            end
          s7:
            begin
              if (TX_RDY == 1'b1)
                begin
                  DATA_OUT <= RDATA[63 : 56];
                  WEN <= 1'b0;
                end
              else
                begin
                  WEN <= 1'b1;
                  rfsm <= s8;
                end
            end
          s8:
            begin
              if (TX_RDY == 1'b1)
                begin
                  DATA_OUT <= RDATA[55 : 48];
                  rfsm <= s9;
                  WEN <= 1'b0;
                end
              else
                WEN <= 1'b1;
            end
          s9:
            begin
              if (TX_RDY == 1'b0)
                begin
                  rfsm <= s10;
                  WEN <= 1'b1;
                end
            end
          s10:
            begin
              if (TX_RDY == 1'b1)
                begin
                  DATA_OUT <= RDATA[47 : 40];
                  rfsm <= s11;
                  WEN <= 1'b0;
                end
              else
                WEN <= 1'b1;
            end
          s11:
            begin
              if (TX_RDY == 1'b0)
                begin
                  rfsm <= s12;
                  WEN <= 1'b1;
                end
            end
          s12:
            begin
              if (TX_RDY == 1'b1)
                begin
                  DATA_OUT <= RDATA[39 : 32];
                  rfsm <= s13;
                  WEN <= 1'b0;
                end
              else
                WEN <= 1'b1;
            end
          s13:
            begin
              if (TX_RDY == 1'b0)
                begin
                  rfsm <= s14;
                  WEN <= 1'b1;
                end
            end
          s14:
            begin
              if (TX_RDY == 1'b1)
                begin
                  DATA_OUT <= RDATA[31 : 24];
                  rfsm <= s15;
                  WEN <= 1'b0;
                end
              else
                WEN <= 1'b1;
            end
          s15:
            begin
              if (TX_RDY == 1'b0)
                begin
                  rfsm <= s16;
                  WEN <= 1'b1;
                end
            end
          s16:
            begin
              if (TX_RDY == 1'b1)
                begin
                  DATA_OUT <= RDATA[23 : 16];
                  rfsm <= s17;
                  WEN <= 1'b0;
                end
              else
                WEN <= 1'b1;
            end
          s17:
            begin
              if (TX_RDY == 1'b0)
                begin
                  rfsm <= s18;
                  WEN <= 1'b1;
                end
            end
          s18:
            begin
              if (TX_RDY == 1'b1)
                begin
                  DATA_OUT <= RDATA[15 : 8];
                  rfsm <= s19;
                  WEN <= 1'b0;
                end
              else
                WEN <= 1'b1;
            end
          s19:
            begin
              if (TX_RDY == 1'b0)
                begin
                  rfsm <= s20;
                  WEN <= 1'b1;
                end
            end
          s20:
            begin
              if (TX_RDY == 1'b1)
                begin
                  DATA_OUT <= RDATA[7 : 0];
                  WEN <= 1'b0;
                  rfsm <= s21;
                end
              else
                WEN <= 1'b1;
            end
          s21:
            begin
              if (TX_RDY == 1'b0)
                begin
                  rfsm <= s6;
                  WEN <= 1'b1;
                end
            end
          //Enabling error in PRBS data                           
          s22:
            begin
              ERR_EN <= 1'b1;
              LINK_ERR_EN <= 1'b0;
              rfsm <= s0;
            end
          //Enabling error in JESD link              
          s23:
            begin
              ERR_EN <= 1'b0;
              LINK_ERR_EN <= 1'b1;
              rfsm <= s0;
            end
          //Clearing the Errors both JESD link and PRBS data                 
          s24:
            begin
              ERR_EN <= 1'b0;
              LINK_ERR_EN <= 1'b0;
              rfsm <= s0;
            end
          default:
            rfsm <= s0;
        endcase
      end
endmodule
