//============================================================================
|
//============================================================================
|
// Implementation of the PS/2 keyboard scan-code reader
|
// PS/2 keyboard scan-code reader
|
//
|
//
|
// Copyright (C) 2014-2016 Goran Devic
|
// Copyright (C) 2014-2016 Goran Devic
|
//
|
//
|
// This program is free software; you can redistribute it and/or modify it
|
// 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
|
// 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)
|
// Software Foundation; either version 2 of the License, or (at your option)
|
// any later version.
|
// any later version.
|
//
|
//
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
// more details.
|
// more details.
|
//
|
//
|
// You should have received a copy of the GNU General Public License along
|
// 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.,
|
// with this program; if not, write to the Free Software Foundation, Inc.,
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
//============================================================================
|
//============================================================================
|
module ps2_keyboard
|
module ps2_keyboard
|
(
|
(
|
input wire clk,
|
input wire clk,
|
input wire reset, // Reset (negative logic)
|
input wire nreset, // Active low reset
|
input wire PS2_CLK, // PS/2 keyboard clock line
|
input wire PS2_CLK, // PS/2 keyboard clock line
|
input wire PS2_DAT, // PS/2 keyboard data line
|
input wire PS2_DAT, // PS/2 keyboard data line
|
|
|
output wire [7:0] scan_code,// Completed keyboard scan code
|
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_ready, // Active for 1 clock: scan code is ready
|
output reg scan_code_error // Error receiving keyboard data
|
output reg scan_code_error // Error receiving keyboard data
|
);
|
);
|
|
|
reg [7:0] clk_filter;
|
reg [7:0] clk_filter;
|
reg ps2_clk_in;
|
reg ps2_clk_in;
|
|
|
reg clk_edge;
|
reg clk_edge;
|
reg [3:0] bit_count;
|
reg [3:0] bit_count;
|
|
|
// Shift register contains all the bits that are read so far; scan_code simply
|
// 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
|
// mirrors it and becomes valid only when "scan_code_ready" is set
|
reg [8:0] shiftreg;
|
reg [8:0] shiftreg;
|
assign scan_code = shiftreg[7:0];
|
assign scan_code = shiftreg[7:0];
|
|
|
// Compute parity on the fly; we only need it after the last bit is stored
|
// Compute parity on the fly; we only need it after the last bit is stored
|
wire parity;
|
wire parity;
|
assign parity = ^shiftreg[8:0];
|
assign parity = ^shiftreg[8:0];
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// Filter the PS/2 clock signal since it might have a noise (false '1')
|
// Filter the PS/2 clock signal since it might have a noise (false '1')
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
always @(posedge clk or negedge reset)
|
always @(posedge clk or negedge nreset)
|
begin
|
begin
|
if (!reset) begin
|
if (!nreset) begin
|
ps2_clk_in <= 1;
|
ps2_clk_in <= 1;
|
clk_filter <= 8'b1;
|
clk_filter <= 8'b1;
|
clk_edge <= 0;
|
clk_edge <= 0;
|
end
|
end
|
else begin
|
else begin
|
// Filter in a new keyboard clock sample
|
// Filter in a new keyboard clock sample
|
clk_filter <= { PS2_CLK, clk_filter[7:1] };
|
clk_filter <= { PS2_CLK, clk_filter[7:1] };
|
clk_edge <= 0;
|
clk_edge <= 0;
|
|
|
if (clk_filter==8'b1)
|
if (clk_filter==8'b1)
|
ps2_clk_in <= 1;
|
ps2_clk_in <= 1;
|
else if (clk_filter==8'b0) begin
|
else if (clk_filter==8'b0) begin
|
// Filter clock is low, check for edge
|
// Filter clock is low, check for edge
|
if (ps2_clk_in==1)
|
if (ps2_clk_in==1)
|
clk_edge <= 1;
|
clk_edge <= 1;
|
ps2_clk_in <= 0;
|
ps2_clk_in <= 0;
|
end
|
end
|
end
|
end
|
end
|
end
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// State machine to process bits of PS/2 data
|
// State machine to process bits of PS/2 data
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
always @(posedge clk or negedge reset)
|
always @(posedge clk or negedge nreset)
|
begin
|
begin
|
if (!reset) begin
|
if (!nreset) begin
|
bit_count <= '0;
|
bit_count <= '0;
|
shiftreg <= '0;
|
shiftreg <= '0;
|
scan_code_ready <= 0;
|
scan_code_ready <= 0;
|
scan_code_error <= 0;
|
scan_code_error <= 0;
|
end
|
end
|
else begin
|
else begin
|
scan_code_ready <= 0;
|
scan_code_ready <= 0;
|
scan_code_error <= 0;
|
scan_code_error <= 0;
|
// We have a new valid clocked bit from the keyboard
|
// We have a new valid clocked bit from the keyboard
|
if (clk_edge==1) begin
|
if (clk_edge==1) begin
|
// Start condition, the bit count is 0
|
// Start condition, the bit count is 0
|
if (bit_count==0 && PS2_DAT==0)
|
if (bit_count==0 && PS2_DAT==0)
|
bit_count <= bit_count + 4'h1;
|
bit_count <= bit_count + 4'h1;
|
else begin
|
else begin
|
// Collecting up to 8 data bits and a parity bit
|
// Collecting up to 8 data bits and a parity bit
|
if (bit_count < 10) begin
|
if (bit_count < 10) begin
|
bit_count <= bit_count + 4'h1;
|
bit_count <= bit_count + 4'h1;
|
shiftreg <= { PS2_DAT, shiftreg[8:1] };
|
shiftreg <= { PS2_DAT, shiftreg[8:1] };
|
end
|
end
|
else
|
else
|
// Finalize: both the calculated parity and the stop bits should be '1'
|
// Finalize: both the calculated parity and the stop bits should be '1'
|
begin
|
begin
|
bit_count <= '0;
|
bit_count <= '0;
|
scan_code_ready <= { PS2_DAT, parity} == 2'b11;
|
scan_code_ready <= { PS2_DAT, parity} == 2'b11;
|
scan_code_error <= { PS2_DAT, parity} != 2'b11;
|
scan_code_error <= { PS2_DAT, parity} != 2'b11;
|
end
|
end
|
end
|
end
|
end
|
end
|
end
|
end
|
end
|
end
|
|
|
endmodule
|
endmodule
|
|
|