/*
* Reads PS/2 keyboard keycodes sends interrupt when one is received for one tick
* Code is practically copied from "https://embeddedthoughts.com/2016/07/05/fpga-keyboard-interface/"
*/
module Keyboard
(
    input wire clk, reset, 
    input wire ps2d, ps2c,            // ps2 data and clock inputs
    output reg rx_done_tick,         // ps2 receive done tick
    output wire [7:0] rx_data        // data received 
);

// FSMD state declaration
localparam 
    idle = 1'b0,
    rx   = 1'b1;
    
// internal signal declaration
reg state_reg, state_next;          // FSMD state register
reg [7:0] filter_reg;               // shift register filter for ps2c
wire [7:0] filter_next;             // next state value of ps2c filter register
reg f_val_reg;                      // reg for ps2c filter value, either 1 or 0
wire f_val_next;                    // next state for ps2c filter value
reg [3:0] n_reg, n_next;            // register to keep track of bit number 
reg [10:0] d_reg, d_next;           // register to shift in rx data
wire neg_edge;                      // negative edge of ps2c clock filter value

// register for ps2c filter register and filter value
always @(posedge clk)
    if (reset)
        begin
        filter_reg <= 8'd0;
        f_val_reg  <= 1'b0;
        end
    else
        begin
        filter_reg <= filter_next;
        f_val_reg  <= f_val_next;
        end

// next state value of ps2c filter: right shift in current ps2c value to register
assign filter_next = {ps2c, filter_reg[7:1]};

// filter value next state, 1 if all bits are 1, 0 if all bits are 0, else no change
assign f_val_next = (filter_reg == 8'b11111111) ? 1'b1 :
            (filter_reg == 8'b00000000) ? 1'b0 :
            f_val_reg;

// negative edge of filter value: if current value is 1, and next state value is 0
assign neg_edge = f_val_reg & ~f_val_next;

// FSMD state, bit number, and data registers
always @(posedge clk)
    if (reset)
        begin
        state_reg <= idle;
        n_reg <= 4'd0;
        d_reg <= 11'd0;
        end
    else
        begin
        state_reg <= state_next;
        n_reg <= n_next;
        d_reg <= d_next;
        end

// FSMD next state logic
always @*
    begin
    
    // defaults
    state_next = state_reg;
    rx_done_tick = 1'b0;
    n_next = n_reg;
    d_next = d_reg;
    
    case (state_reg)
        
        idle:
            if (neg_edge)                 // start bit received
                begin
                n_next = 4'b1010;             // set bit count down to 10
                state_next = rx;              // go to rx state
                end
            
        rx:                                           // shift in 8 data, 1 parity, and 1 stop bit
            begin
            if (neg_edge)                         // if ps2c negative edge...
                begin
                d_next = {ps2d, d_reg[10:1]}; // sample ps2d, right shift into data register
                n_next = n_reg - 1'b1;           // decrement bit count
                end
        
            if (n_reg == 4'd0)                         // after 10 bits shifted in, go to done state
                 begin
                 rx_done_tick = 1'b1;         // assert dat received done tick
                 state_next = idle;           // go back to idle
                 end
            end
    endcase
    end
    
assign rx_data = d_reg[8:1]; // output data bits 

endmodule