//============================================================================
// PS/2 keyboard scan-code reader
//
//  Copyright (C) 2014-2016  Goran Devic
//
//  This program is free software; you can redistribute it and/or modify it
//  under the terms of the GNU General Public License as published by the Free
//  Software Foundation; either version 2 of the License, or (at your option)
//  any later version.
//
//  This program is distributed in the hope that it will be useful, but WITHOUT
//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
//  more details.
//
//  You should have received a copy of the GNU General Public License along
//  with this program; if not, write to the Free Software Foundation, Inc.,
//  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//============================================================================
module ps2_keyboard
(
    input wire clk,
    input wire nreset,          // Active low reset
    input wire PS2_CLK,         // PS/2 keyboard clock line
    input wire PS2_DAT,         // PS/2 keyboard data line

    output wire [7:0] scan_code,// Completed keyboard scan code
    output reg scan_code_ready, // Active for 1 clock: scan code is ready
    output reg scan_code_error  // Error receiving keyboard data
);

reg [7:0] clk_filter;
reg ps2_clk_in;

reg clk_edge;
reg [3:0] bit_count;

// Shift register contains all the bits that are read so far; scan_code simply
// mirrors it and becomes valid only when "scan_code_ready" is set
reg [8:0] shiftreg;
assign scan_code = shiftreg[7:0];

// Compute parity on the fly; we only need it after the last bit is stored
wire parity;
assign parity = ^shiftreg[8:0];

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Filter the PS/2 clock signal since it might have a noise (false '1')
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
always @(posedge clk or negedge nreset)
begin
    if (!nreset) begin
        ps2_clk_in <= 1;
        clk_filter <= 8'b1;
        clk_edge <= 0;
        end
    else begin
        // Filter in a new keyboard clock sample
        clk_filter <= { PS2_CLK, clk_filter[7:1] };
        clk_edge <= 0;

        if (clk_filter==8'b1)
            ps2_clk_in <= 1;
        else if (clk_filter==8'b0) begin
            // Filter clock is low, check for edge
            if (ps2_clk_in==1)
                clk_edge <= 1;
            ps2_clk_in <= 0;
        end
    end
end

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// State machine to process bits of PS/2 data
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
always @(posedge clk or negedge nreset)
begin
    if (!nreset) begin
        bit_count <= '0;
        shiftreg <= '0;
        scan_code_ready <= 0;
        scan_code_error <= 0;
        end
    else begin
        scan_code_ready <= 0;
        scan_code_error <= 0;
        // We have a new valid clocked bit from the keyboard
        if (clk_edge==1) begin
            // Start condition, the bit count is 0
            if (bit_count==0 && PS2_DAT==0)
                    bit_count <= bit_count + 4'h1;
            else begin
                // Collecting up to 8 data bits and a parity bit
                if (bit_count < 10) begin
                    bit_count <= bit_count + 4'h1;
                    shiftreg <= { PS2_DAT, shiftreg[8:1] };
                    end
                else
                // Finalize: both the calculated parity and the stop bits should be '1'
                begin
                    bit_count <= '0;
                    scan_code_ready <= { PS2_DAT, parity} == 2'b11;
                    scan_code_error <= { PS2_DAT, parity} != 2'b11;
                end
            end
        end
    end
end

endmodule
