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 [3:0] KBD_COLUMNS, inout [3:0] KBD_ROWS); //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 [9: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 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, KBD_FREEZE, KBD_ROWS, KBD_COLUMNS, kbd_report, 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] 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 last_wr = 0, last_trans = 0, last_uart_active = 0, last_isr = 0, uart_double_ff = 0; wire RESET; reg [3:0] rststate = 0; assign RESET = &rststate; always @(posedge CLK) begin rststate <= rststate + !RESET; if (RESET == 0) begin I2C_OUTPUT_TYPE = 0; I2C_OUT_DESC_MASK = 0; KBD_LED_STATUS = 0; // 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; end else begin if ((last_wr == 0) && (I2C_WR == 1)) begin 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; 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_TX_REPORT <= 0; else I2C_TX_REPORT <= kbd_report[ (8 * (I2C_COUNTER - 4) + 7) : (8 * (I2C_COUNTER - 4) + 0) ]; end else I2C_TX_REPORT <= 0; end end else if ((last_wr == 1) && (I2C_WR == 0)) begin UART_WR <= 1; if (I2C_READ == 0) UART_TX_DATA <= I2C_RX; else UART_TX_DATA <= I2C_TX; end else if ((last_trans == 0) && (I2C_TRANS == 1)) begin UART_TX_DATA = 8'hFF; UART_WR = 1; uart_double_ff = 1; KBD_FREEZE = 0; end else if ((last_trans == 1) && (I2C_TRANS == 0)) begin if (I2C_READ == 0) begin // DECODING PACKET RECEIVED FROM HOST 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 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 INT = 0; I2C_OUTPUT_TYPE = 3; I2C_OUT_DESC_MASK = 8'h00; 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 = KBD_LED_STATUS[0];//I2C_OUTPUT_TYPE[0]; assign LED3 = KBD_LED_STATUS[1];//I2C_OUTPUT_TYPE[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