
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);


  parameter INTERRUPT_TMR_REFLESH = 14; //  14 - 2^14=16384 tacts or 1.37 ms, 19 - 2^19=524288 tacts or 43.7 ms, 23 - 2^23=8388608 tacts or 0.7 s
  //  23 - 1119 LCs, 14 - 1081 LCs (in commit 1b6fc60221b595c2a0f69509d29b6e5c3110feb0)

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

  wire [7:0] I2C_TX;
  wire [7:0] I2C_TX_DESC;
  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;//, UART_WR2;
  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 [7:0] kbd_report [6:0];
  wire [7:0] report_byte;
  wire ISR;
  reg INT = 1;              //  INTERRUPT LINE TO HOST
  reg [INTERRUPT_TMR_REFLESH:0] int_tmr;
  reg KBD_FREEZE = 1;       //  LOGIC REG FOR BLOCK KBD ACTIVITY WHEN I2C IS WORKING
  matrix_kbd KEYBOARD (CLK, RESET, IS_RAM_INIT /*KBD_FREEZE*/, KBD_ROWS, KBD_COLUMNS, wr_cnt, report_data_wr, ISR);//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*/);

  reg [3:0] ring_wr, ring_rd;
  reg [3:0] wr_cnt;
  reg report_wr_en;
  //reg [7:0] /*report_data_wadr,*/ /*report_data_radr,*/ //report_data_wr;
  wire [7:0] report_data_radr, report_data_wadr, report_data_wr;
  assign report_data_radr[7:4] = ring_rd;
  assign report_data_radr[3:0] = I2C_COUNTER;
  assign report_data_wadr[7:4] = ring_wr;
  assign report_data_wadr[3:0] = wr_cnt;
  wire [7:0] report_data_rd;
  ram REPORT_DATA ((1^CLK), report_wr_en, report_data_wadr, report_data_wr, report_data_radr, report_data_rd);

  assign I2C_TX = (I2C_TX_DESC & I2C_OUT_DESC_MASK) | (/*I2C_TX_REPORT*/report_data_rd & (~I2C_OUT_DESC_MASK));

  reg [2: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*/6:0] I2C_COUNTER = 0;
  reg [2:0] I2C_OUTPUT_TYPE = 0;  //  0 - I2C HID DESCR, 1 - HID REPORT DESC, 2 - INPUT REPORT
  reg [7:0] I2C_OUT_DESC_MASK = 0;
  reg [2:0] KBD_LED_STATUS = 0;

  reg last_wr = 0, last_trans = 0, last_isr = 0;
  reg IS_RAM_INIT = 0;

  always @(posedge CLK) begin

    //  RESET LOGIC
    rststate <= rststate + !RESET;
    if (RESET == 0) begin
      I2C_OUTPUT_TYPE = 2;//3;//0;
      I2C_OUT_DESC_MASK = 0;
      UART_WR = 0;
      KBD_LED_STATUS = 0;     //  BIT 0 - NUM LOCK, BIT 1 - CAPS LOCK, BIT 2 - SCROOL LOCK
      last_trans = 0; last_isr = 0; last_wr = 0;
      I2C_COUNTER = 0;
      INT = 1;  int_tmr = 0;
      ring_wr = 0;      ring_rd = 15;      wr_cnt = 0;
      IS_RAM_INIT = 1;
      //report_data_wadr = 245; //  FIRST 10 TACTS ARE EMPTY
      report_wr_en = 0;
    end

    //  NOT RESET MODE LOGIC
    else  begin

      if (IS_RAM_INIT)  begin
        //report_wr_en = 1;
        //report_data_wadr = report_data_wadr + 1;
        //report_data_wr = 0;
        wr_cnt = wr_cnt + 1;
        if ((wr_cnt == 0) && (report_wr_en == 0))
          report_wr_en = 1;
        else if ((wr_cnt == 0) && (report_wr_en == 1))  begin
          report_wr_en = 0;
          IS_RAM_INIT = 0;
        end
        /*if (report_data_wadr == 17) begin
          report_wr_en = 0;
          IS_RAM_INIT = 0;
        end*/
      end

      else  begin //  START OF NON RESET AND NON INIT LOGIC

// ------------------------- KBD INTERRUPT ------------------------ //

        if ((last_isr == 1/*0*/) && (ISR == 0/*1*/)) begin  //  INTERRUPT FROM KEYBOARD
          if ((ring_wr + 1) != ring_rd)
            ring_wr = ring_wr + 1;
          report_wr_en = 1;
          //report_data_wadr = ring_wr * 16 + 1;
          //report_data_wr = 10;//kbd_report [0];
          wr_cnt = 1;
          //INT = 0;
          //I2C_OUTPUT_TYPE = 2;//3;
          //I2C_OUT_DESC_MASK = 8'h00;
        end

        else if (wr_cnt != 0) begin //  WRITING TO RAM REPORT FROM KEYBOARD
          if (wr_cnt == 11)  begin
            wr_cnt = 0;
            report_wr_en = 0;
          end
          else  begin
            //report_data_wadr = ring_wr * 16 + wr_cnt + 1;
            /*if ((wr_cnt == 1) || (wr_cnt == 3))
              report_data_wr = 0;
            else if (wr_cnt == 2)
              report_data_wr = kbd_report [wr_cnt - 2];
            else
              report_data_wr = kbd_report [wr_cnt - 3];*/
            wr_cnt = wr_cnt + 1;
          end
        end

// ---------------------------- I2C NEW BYTE TX/RX RISING/FALLING EDGE, RISING - ALL LOGIC, FALLING - UART TX -------------- //

        if ((last_wr == 0) && (I2C_WR == 1))  begin //  I2C NEW BYTE TX/RX
          //I2C_COUNTER = I2C_COUNTER - 1;
          if (I2C_READ == 0)  begin //  I2C_FROM_HOST

            if (I2C_COUNTER == 0) 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 == 1)  begin
              if (I2C_RX != 0)
                i2c_input_data_type = 0;
            end
            else if (I2C_COUNTER == 2)  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 == 3)  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 == 4)  begin
              if (i2c_input_data_type == 4)
                temp_output_report = I2C_RX[2:0];
              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 == 5)  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 == 8)  begin
              if (i2c_input_data_type == 7)
                temp_output_report = I2C_RX[2:0];
            end

          end

          else  begin //  I2C_TO_HOST
            if (I2C_OUTPUT_TYPE == 2/*3*/) begin
              if (I2C_COUNTER == 0)  begin
                if (ring_rd != ring_wr)
                  ring_rd = ring_rd + 1;
                //report_data_radr = ring_rd * 10;
              end
              //else
              //  report_data_radr = report_data_radr + 1;
            end
          end
          UART_WR <= 0;
          if (I2C_COUNTER != 127)
            I2C_COUNTER = I2C_COUNTER + 1;
        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;
          //UART_TX_DATA = I2C_COUNTER;
        end  //  I2C_NEW_BYTE_NEGEDGE_FOR_UART - END

// ---------------------- I2C START/STOP CONDITIONS, START - ONLY UART FF TX, STOP - ALL LOGIC ----------------- //

        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;
          I2C_COUNTER = 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_COUNTER != 2)) || ((i2c_input_data_type == 4) && (I2C_COUNTER != 5)) || ((i2c_input_data_type == 5) && (I2C_COUNTER != 4)) || ((i2c_input_data_type == 6) && (I2C_COUNTER != 6)) || ((i2c_input_data_type == 7) && (I2C_COUNTER != 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 - 1;
            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 = 2;//3;
            else if (i2c_input_data_type == 5)
              rststate <= 4'h0;   //  RESET COMMAND

            if ((I2C_OUTPUT_TYPE == 1) || (I2C_OUTPUT_TYPE == 0))//2))
              I2C_OUT_DESC_MASK = 8'hFF;
            else
              I2C_OUT_DESC_MASK = 8'h00;
          end //  END OF I2C_READ == 0

          else begin
            if ((I2C_OUTPUT_TYPE == 2/*3*/) && (I2C_COUNTER > 1))  begin
            //  DEACTIVATING INTERRRUPT IF HOST READ INPUT REPORT (LEN 10) AFTER INTERRUPT OR EMPTY DATA (>=2 BYTES) AFTER RESET
              INT = 1;
              int_tmr = 0;
            end
            I2C_OUTPUT_TYPE = 2;//3;
            I2C_OUT_DESC_MASK = 0;
          end
          UART_WR <= 0;
          //last_trans = I2C_TRANS;
        end    //  I2C_STOP CONDITION (OR REPEAT START DETECTED) - END

// ---------------- INTERRUPT TO HOST GENERATING LOGIC: DELAY AND INTERRUPT GENERATING (IF NEED) --------------- //

        //if (int_tmr != ((1<<(INTERRUPT_TMR_REFLESH+1))-1))
        if (int_tmr[INTERRUPT_TMR_REFLESH] != 1)
          int_tmr = int_tmr + 1;

        else if ((I2C_OUTPUT_TYPE == 2/*3*/) && (I2C_TRANS == 0)) begin
          if (ring_rd != ring_wr)
            INT = 0;
        end

        last_trans <= I2C_TRANS;
        last_wr <= I2C_WR;
        last_isr <= ISR;
      end //  END OF NON RESET AND NON INIT LOGIC


    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 LED3 = UART_ACTIVE;
  //assign LED4 = uart_double_ff;
  //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
