
module top (input CLK, output LED1, LED2, LED3, LED4, LED5,
            input SCL, inout SDA, /*output ACK,*/ output INTERRUPT,
            input COM_RX, output COM_TX, COM_DCD, COM_DSR, COM_RTS,
            input [7:0] KBD_COLUMNS, inout [15:0] KBD_ROWS);


  wire RESET;
  reg [3:0] rststate = 0;
  assign RESET = &rststate;

  //reg [7:0] I2C_TX;   //  TRANSMITTED TO MASTER
  wire [7:0] I2C_TX;
  reg [7:0] I2C_TX_DESC;
  reg [7:0] I2C_TX_REPORT;
  assign I2C_TX = (I2C_TX_DESC & I2C_OUT_DESC_MASK) | (I2C_TX_REPORT & (~I2C_OUT_DESC_MASK));
  wire [7:0] I2C_RX;  //  RECEIVED FROM MASTER
  wire I2C_TRANS, I2C_READ, I2C_ACK, I2C_ACK_MSTR_CTRL, I2C_WR;
  wire [7:0] I2C_COUNTER;
  i2c_slave I2C (CLK, RESET, SCL, SDA, I2C_TRANS, I2C_READ, I2C_ACK, I2C_WR, //I2C_ACK_MSTR_CTRL,
                I2C_RX, I2C_TX, I2C_COUNTER);

  reg UART_WR, UART_DTR, UART_RTS, UART_DCD;
  reg [7:0] UART_TX_DATA;
  wire UART_ACTIVE, UART_TX_LINE;
  initial begin
    UART_WR = 0;  UART_RTS = 1; UART_DTR = 0; UART_DCD = 0;
  end
  uart UART (CLK, RESET, UART_WR, UART_TX_DATA, UART_ACTIVE, UART_TX_LINE);

  //wire [63:0] kbd_report;
  wire [7:0] kbd_report [6:0];
  wire ISR;
  reg INT = 1;              //  INTERRUPT LINE TO HOST
  reg KBD_FREEZE = 1;       //  LOGIC REG FOR BLOCK KBD ACTIVITY WHEN I2C IS WORKING
  //reg IS_EMPTY_REPORT = 0;  //  REGISTER FOR CORRECT START (HOST MUST REQUEST EMPTY REGISTER AFTER INTERRUPT. THEN INTERRRUPT SET TO 1)
  matrix_kbd KEYBOARD (CLK, RESET, 0 /*KBD_FREEZE*/, KBD_ROWS, KBD_COLUMNS, kbd_report[0], kbd_report[1], kbd_report[2], kbd_report[3], kbd_report[4], kbd_report[5], kbd_report[6], ISR);

  descriptors I2C_HID_DESC (CLK, RESET, I2C_WR, I2C_OUTPUT_TYPE[1:0], I2C_COUNTER, I2C_TX_DESC/*, kbd_report*/);

  parameter MAX_INPUT_LEN = 10;
  reg [7:0] I2C_INPUT_DATA [MAX_INPUT_LEN:0];
  reg [7:0] temp_output_report;
  reg [3:0] i2c_input_data_type;  //  0 - UNKNOWN, 1 - I2C_HID_DESC_REQUEST, 2 - HID_REPORT_DESC_REQUEST, 3 - INPUT_REPORT_REQUEST, 4 - OUTPUT_REPORT_SET
                                  //  5 - RESET, 6 - GET_INPUT_REPORT, 7 - SET_OUTPUT_REPORT
  reg [7:0] I2C_INPUT_LEN = 0;
  reg [2:0] I2C_OUTPUT_TYPE = 0;  //  0 - ALL ZERO DATA, 1 - I2C HID DESCR, 2 - OUTPUT REPORT, 3 - HID REPORT DESCR
  reg [7:0] I2C_OUT_DESC_MASK = 0;
  reg [7:0] KBD_LED_STATUS = 0;

  reg [7:0] ring_report [(8*8-1):0];
  reg [2:0] ring_wr, ring_rd;
  reg [2:0] wr_cnt;

  reg last_wr = 0, last_trans = 0, last_uart_active = 0, last_isr = 0, uart_double_ff = 0;

  always @(posedge CLK) begin

    //  RESET LOGIC
    rststate <= rststate + !RESET;
    if (RESET == 0) begin
      I2C_OUTPUT_TYPE = 0;
      I2C_OUT_DESC_MASK = 0;
      KBD_LED_STATUS = 7;     //  BIT 0 - NUM LOCK, BIT 1 - CAPS LOCK, BIT 2 - SCROOL LOCK
      I2C_INPUT_LEN = 0;
      INT = 0;
      UART_WR = 0;
      //KBD_FREEZE = 1;
      //IS_EMPTY_REPORT = 0;
      ring_wr = 0;
      ring_rd = 0;
      wr_cnt = 0;
    end

    //  NOT RESET MODE LOGIC
    else  begin
      if ((last_wr == 0) && (I2C_WR == 1))  begin //  I2C NEW BYTE TX/RX
        I2C_INPUT_LEN = I2C_COUNTER - 1;
        if (I2C_READ == 0)  begin
          /*if (I2C_COUNTER < (MAX_INPUT_LEN + 2))
            I2C_INPUT_DATA[I2C_COUNTER - 2] <= I2C_RX;*/

          if (I2C_COUNTER == 2) begin
            if ((I2C_RX > 5) || (I2C_RX < 1))
              i2c_input_data_type = 0;
            else
              i2c_input_data_type = I2C_RX;
          end
          else if (I2C_COUNTER == 3)  begin
            if (I2C_RX != 0)
              i2c_input_data_type = 0;
          end
          else if (I2C_COUNTER == 4)  begin
            if (i2c_input_data_type == 5) begin
              case (I2C_RX) 0:  i2c_input_data_type = 5;  16: i2c_input_data_type = 6;
                            32: i2c_input_data_type = 7;  default:  i2c_input_data_type = 0;  endcase
            end
          end
          else if (I2C_COUNTER == 5)  begin
            if (((i2c_input_data_type == 5) && (I2C_RX != 1)) || ((i2c_input_data_type == 6) && (I2C_RX != 2)) || ((i2c_input_data_type == 7) && (I2C_RX != 3)))
              i2c_input_data_type = 0;
          end
          else if (I2C_COUNTER == 6)  begin
            if (i2c_input_data_type == 4)
              temp_output_report = I2C_RX;
            else if (((i2c_input_data_type == 6) || (i2c_input_data_type == 7)) && (I2C_RX != 6))
              i2c_input_data_type = 0;
          end
          else if (I2C_COUNTER == 7)  begin
            if (((i2c_input_data_type == 6) || (i2c_input_data_type == 7)) && (I2C_RX != 0))
              i2c_input_data_type = 0;
          end
          else if (I2C_COUNTER == 10)  begin
            if (i2c_input_data_type == 7)
              temp_output_report = I2C_RX;
          end

        end
        else  begin
          if (I2C_OUTPUT_TYPE == 3) begin
            if ((I2C_COUNTER < 2) || (I2C_COUNTER > (2 + 10 - 1)))
              I2C_TX_REPORT <= 0;
            else if (I2C_COUNTER == 2)
              I2C_TX_REPORT <= 10;
            else if ((I2C_COUNTER == 3) || (I2C_COUNTER == 5))
              I2C_TX_REPORT <= 0;
            else if (I2C_COUNTER == 4)
              I2C_TX_REPORT <= kbd_report[0];
            else
              I2C_TX_REPORT <= kbd_report[I2C_COUNTER - 5];
              //I2C_TX_REPORT <= kbd_report[ (8 * (I2C_COUNTER - 4) + 7) : (8 * (I2C_COUNTER - 4) + 0) ];
          end
          else
            I2C_TX_REPORT <= 0;
        end
      end  //  I2C NEW BYTE TX/RX - END

      else if ((last_wr == 1) && (I2C_WR == 0))  begin  //  I2C_NEW_BYTE_NEGEDGE_FOR_UART
        UART_WR <= 1;
        if (I2C_READ == 0)
          UART_TX_DATA <= I2C_RX;
        else
          UART_TX_DATA <= I2C_TX;
      end  //  I2C_NEW_BYTE_NEGEDGE_FOR_UART - END

      else if ((last_trans == 0) && (I2C_TRANS == 1)) begin //  I2C_START_CONDITION OR REPEAT START (UART FF)
        i2c_input_data_type = 0;  //  UNKNOWN DATA IN
        UART_TX_DATA = 8'hFF;
        UART_WR = 1;
        uart_double_ff = 1;
        KBD_FREEZE = 0;
      end //  I2C_START_CONDITION (UART FF) - END

      else if ((last_trans == 1) && (I2C_TRANS == 0)) begin //  I2C_STOP CONDITION (OR REPEAT START DETECTED)
        KBD_FREEZE <= 0;
        if (I2C_READ == 0) begin  //  DECODING PACKET RECEIVED FROM HOST
          if (((i2c_input_data_type < 4) && (I2C_INPUT_LEN != 2)) || ((i2c_input_data_type == 4) && (I2C_INPUT_LEN != 5)) || ((i2c_input_data_type == 5) && (I2C_INPUT_LEN != 4)) || ((i2c_input_data_type == 6) && (I2C_INPUT_LEN != 6)) || ((i2c_input_data_type == 7) && (I2C_INPUT_LEN != 9)))
            i2c_input_data_type = 0;
          if ((i2c_input_data_type == 1) || (i2c_input_data_type == 2) || (i2c_input_data_type == 3))
            I2C_OUTPUT_TYPE = i2c_input_data_type;
          else if ((i2c_input_data_type == 4) || (i2c_input_data_type == 7))
            KBD_LED_STATUS = temp_output_report;
          else if (i2c_input_data_type == 6)
            I2C_OUTPUT_TYPE = 3;
          else if (i2c_input_data_type == 5)
            rststate <= 4'h0;   //  RESET COMMAND
          /*if (I2C_INPUT_LEN == 0)
            KBD_FREEZE <= 0;
          else if (I2C_INPUT_LEN == 2) begin
            if ((I2C_INPUT_DATA[0] == 1) && (I2C_INPUT_DATA[1] == 0))       //  I2C_HID_DESC_REQUEST
              I2C_OUTPUT_TYPE = 1;
            else if ((I2C_INPUT_DATA[0] == 2) && (I2C_INPUT_DATA[1] == 0))  //  HID REPORT DESC REQUEST
              I2C_OUTPUT_TYPE = 2;
            else if ((I2C_INPUT_DATA[0] == 3) && (I2C_INPUT_DATA[1] == 0))  //  INPUT REPORT REQUEST (ADR)
              I2C_OUTPUT_TYPE = 3;
            //else
            //  I2C_OUTPUT_TYPE = 0;  //
          end
          else if (I2C_INPUT_LEN == 5)  begin //  OUTPUT REPORT SET (LEDS) - WRITE TO OUT ADR
            if ((I2C_INPUT_DATA[0] == 4) && (I2C_INPUT_DATA[1] == 0) && (I2C_INPUT_DATA[2] == 1) && (I2C_INPUT_DATA[3] == 0))  begin
              KBD_LED_STATUS <= I2C_INPUT_DATA[4];
              KBD_FREEZE <= 0;
            end
            //else
            //  I2C_OUTPUT_TYPE = 0;  //
          end
          else if (I2C_INPUT_LEN == 6)  begin   //  INPUT REPORT REQUEST (KBD PRESS INFO)
            if ((I2C_INPUT_DATA[0] == 5) && (I2C_INPUT_DATA[1] == 0) && (I2C_INPUT_DATA[2] == 16) && (I2C_INPUT_DATA[3] == 2) && (I2C_INPUT_DATA[4] == 6) && (I2C_INPUT_DATA[5] == 0))
              I2C_OUTPUT_TYPE = 3;
            //else
            //  I2C_OUTPUT_TYPE = 0;  //
          end
          else if (I2C_INPUT_LEN == 9)  begin //  OUTPUT REPORT SET (LEDS) - WRITE BY CMD
            if ((I2C_INPUT_DATA[0] == 5) && (I2C_INPUT_DATA[1] == 0) && (I2C_INPUT_DATA[2] == 32) && (I2C_INPUT_DATA[3] == 3)  && (I2C_INPUT_DATA[4] == 6) && (I2C_INPUT_DATA[5] == 0) /*&& (I2C_INPUT_DATA[6] == 1) && (I2C_INPUT_DATA[7] == 0)*//*)  begin
              KBD_LED_STATUS <= I2C_INPUT_DATA[8];
              KBD_FREEZE <= 0;
            end
            //else
            //  I2C_OUTPUT_TYPE = 0;  //
          end
          else if (I2C_INPUT_LEN == 4)  begin
            if ((I2C_INPUT_DATA[0] == 5) && (I2C_INPUT_DATA[1] == 0) && (I2C_INPUT_DATA[2] == 0) && (I2C_INPUT_DATA[3] == 1))
              rststate <= 4'h0;   //  RESET COMMAND
          end */
          //else
          //  I2C_OUTPUT_TYPE = 0;  //
          if ((I2C_OUTPUT_TYPE == 1) || (I2C_OUTPUT_TYPE == 2))
            I2C_OUT_DESC_MASK = 8'hFF;
          else
            I2C_OUT_DESC_MASK = 8'h00;
        end //  END OF I2C_READ == 0
        else begin
          //KBD_FREEZE <= 0;  //  UNFREEZING KBD AFTER ANYONE I2C RECEIVING
          //if (((I2C_OUTPUT_TYPE == 3) && (I2C_INPUT_LEN == 10)) || ((I2C_OUTPUT_TYPE == 0) && (I2C_INPUT_LEN > 1)))  begin  //  HARD
          if (((I2C_OUTPUT_TYPE == 3) || (I2C_OUTPUT_TYPE == 0)) && (I2C_INPUT_LEN > 1))  begin  //  SOFT
          //  DEACTIVATING INTERRRUPT IF HOST READ INPUT REPORT (LEN 10) AFTER INTERRUPT OR EMPTY DATA (>=2 BYTES) AFTER RESET
          //  AND UNFREEZING KEYBOARD
            INT <= 1;
            //KBD_FREEZE <= 0;
            //IS_EMPTY_REPORT = 1;
          end
        end
      end    //  I2C_STOP CONDITION (OR REPEAT START DETECTED) - END

      else if ((last_uart_active == 1) && (UART_ACTIVE == 0) && (uart_double_ff == 1))  begin
        UART_WR = 1;
        UART_TX_DATA = 8'hFF;
        uart_double_ff = 0;
        I2C_INPUT_LEN = 0;
      end

      else if (UART_WR == 1)
        UART_WR <= 0;

      else if ((last_isr == 0) && (ISR == 1) && (INT == 1)) begin  //  INTERRUPT FROM KEYBOARD
        /*if ((ring_wr + 1) != ring_rd)
          ring_wr = ring_wr + 1;
        ring_report[ring_wr * 8 + 0] <=  kbd_report[ (8 * 0 + 7) : (8 * 0 + 0) ];
        wr_cnt = 1;*/
        INT = 0;
        I2C_OUTPUT_TYPE = 3;
        I2C_OUT_DESC_MASK = 8'h00;
      end
      /*else if (wr_cnt != 0) begin
        ring_report[ring_wr * 8 + wr_cnt] <=  kbd_report[ (8 * wr_cnt + 7) : (8 * wr_cnt + 0) ];
        wr_cnt = wr_cnt + 1;
        //  if (wr_cnt == 0)  //  START ISR
      end*/

      last_wr <= I2C_WR;
      last_trans <= I2C_TRANS;
      last_uart_active <= UART_ACTIVE;
      last_isr <= ISR;
    end
  end

  assign LED5 = I2C_TRANS;
  //assign LED5 = COM_RX;
  assign LED1 = INT ^ 1;//KBD_COLUMNS[0];//I2C_OUTPUT_TYPE[0];//I2C_RX[0];
  //assign LED2 = I2C_OUTPUT_TYPE[0];
  //assign LED3 = I2C_OUTPUT_TYPE[1];
  assign LED2 = KBD_LED_STATUS[0];
  assign LED3 = KBD_LED_STATUS[1];
  assign LED4 = KBD_LED_STATUS[2];//KBD_FREEZE;//UART_ACTIVE;
  //assign ACK = I2C_READ;//I2C_WR; //I2C_ACK;

  assign COM_TX = UART_TX_LINE;//COM_RX;
  assign INTERRUPT = INT;
  assign COM_RTS = I2C_READ;//UART_RTS;
  assign COM_DSR = KBD_FREEZE;//UART_DTR;
  assign COM_DCD = INT;

endmodule //top
