📄 ps2_keyboard.v
字号:
//-------------------------------------------------------------------------------------
`define TOTAL_BITS 11
`define EXTEND_CODE 16'hE0
`define RELEASE_CODE 16'hF0
`define LEFT_SHIFT 16'h12
`define RIGHT_SHIFT 16'h59
module ps2_keyboard (
clk,
reset,
ps2_clk_en_o_,
ps2_data_en_o_,
ps2_clk_i,
ps2_data_i,
rx_extended,
rx_released,
rx_shift_key_on,
rx_scan_code,
rx_ascii,
rx_data_ready, // rx_read_o
rx_read, // rx_read_ack_i
tx_data,
tx_write,
tx_write_ack_o,
tx_error_no_keyboard_ack,
translate
);
// Parameters
// The timer value can be up to (2^bits) inclusive.
parameter TIMER_60USEC_VALUE_PP = 2950; // Number of sys_clks for 60usec.
parameter TIMER_60USEC_BITS_PP = 12; // Number of bits needed for timer
parameter TIMER_5USEC_VALUE_PP = 186; // Number of sys_clks for debounce
parameter TIMER_5USEC_BITS_PP = 8; // Number of bits needed for timer
parameter TRAP_SHIFT_KEYS_PP = 0; // Default: No shift key trap.
// State encodings, provided as parameters
// for flexibility to the one instantiating the module.
// In general, the default values need not be changed.
// State "m1_rx_clk_l" has been chosen on purpose. Since the input
// synchronizing flip-flops initially contain zero, it takes one clk
// for them to update to reflect the actual (idle = high) status of
// the I/O lines from the keyboard. Therefore, choosing 0 for m1_rx_clk_l
// allows the state machine to transition to m1_rx_clk_h when the true
// values of the input signals become present at the outputs of the
// synchronizing flip-flops. This initial transition is harmless, and it
// eliminates the need for a "reset" pulse before the interface can operate.
parameter m1_rx_clk_h = 1;
parameter m1_rx_clk_l = 0;
parameter m1_rx_falling_edge_marker = 13;
parameter m1_rx_rising_edge_marker = 14;
parameter m1_tx_force_clk_l = 3;
parameter m1_tx_first_wait_clk_h = 10;
parameter m1_tx_first_wait_clk_l = 11;
parameter m1_tx_reset_timer = 12;
parameter m1_tx_wait_clk_h = 2;
parameter m1_tx_clk_h = 4;
parameter m1_tx_clk_l = 5;
parameter m1_tx_wait_keyboard_ack = 6;
parameter m1_tx_done_recovery = 7;
parameter m1_tx_error_no_keyboard_ack = 8;
parameter m1_tx_rising_edge_marker = 9;
parameter m2_rx_data_ready = 1;
parameter m2_rx_data_ready_ack = 0;
// I/O declarations
input clk;
input reset;
output ps2_clk_en_o_ ;
output ps2_data_en_o_ ;
input ps2_clk_i ;
input ps2_data_i ;
output rx_extended;
output rx_released;
output rx_shift_key_on;
output [7:0] rx_scan_code;
output [7:0] rx_ascii;
output rx_data_ready;
input rx_read;
input [7:0] tx_data;
input tx_write;
output tx_write_ack_o;
output tx_error_no_keyboard_ack;
input translate ;
reg rx_extended;
reg rx_released;
reg [7:0] rx_scan_code;
reg [7:0] rx_ascii;
reg rx_data_ready;
reg tx_error_no_keyboard_ack;
// Internal signal declarations
wire timer_60usec_done;
wire timer_5usec_done;
wire extended;
wire released;
wire shift_key_on;
// NOTE: These two signals used to be one. They
// were split into two signals because of
// shift key trapping. With shift key
// trapping, no event is generated externally,
// but the "hold" data must still be cleared
// anyway regardless, in preparation for the
// next scan codes.
wire rx_output_event; // Used only to clear: hold_released, hold_extended
wire rx_output_strobe; // Used to produce the actual output.
wire tx_parity_bit;
wire rx_shifting_done;
wire tx_shifting_done;
wire [11:0] shift_key_plus_code;
reg [`TOTAL_BITS-1:0] q;
reg [3:0] m1_state;
reg [3:0] m1_next_state;
reg m2_state;
reg m2_next_state;
reg [3:0] bit_count;
reg enable_timer_60usec;
reg enable_timer_5usec;
reg [TIMER_60USEC_BITS_PP-1:0] timer_60usec_count;
reg [TIMER_5USEC_BITS_PP-1:0] timer_5usec_count;
reg [7:0] ascii; // "REG" type only because a case statement is used.
reg left_shift_key;
reg right_shift_key;
reg hold_extended; // Holds prior value, cleared at rx_output_strobe
reg hold_released; // Holds prior value, cleared at rx_output_strobe
reg ps2_clk_s; // Synchronous version of this input
reg ps2_data_s; // Synchronous version of this input
reg ps2_clk_hi_z; // Without keyboard, high Z equals 1 due to pullups.
reg ps2_data_hi_z; // Without keyboard, high Z equals 1 due to pullups.
//--------------------------------------------------------------------------
// Module code
assign ps2_clk_en_o_ = ps2_clk_hi_z ;
assign ps2_data_en_o_ = ps2_data_hi_z ;
// Input "synchronizing" logic -- synchronizes the inputs to the state
// machine clock, thus avoiding errors related to
// spurious state machine transitions.
always @(posedge clk)
begin
ps2_clk_s <= ps2_clk_i;
ps2_data_s <= ps2_data_i;
end
// State register
always @(posedge clk)
begin : m1_state_register
if (reset) m1_state <= m1_rx_clk_h;
else m1_state <= m1_next_state;
end
// State transition logic
always @(m1_state
or q
or tx_shifting_done
or tx_write
or ps2_clk_s
or ps2_data_s
or timer_60usec_done
or timer_5usec_done
)
begin : m1_state_logic
// Output signals default to this value, unless changed in a state condition.
ps2_clk_hi_z <= 1;
ps2_data_hi_z <= 1;
tx_error_no_keyboard_ack <= 0;
enable_timer_60usec <= 0;
enable_timer_5usec <= 0;
case (m1_state)
m1_rx_clk_h :
begin
enable_timer_60usec <= 1;
if (tx_write) m1_next_state <= m1_tx_reset_timer;
else if (~ps2_clk_s) m1_next_state <= m1_rx_falling_edge_marker;
else m1_next_state <= m1_rx_clk_h;
end
m1_rx_falling_edge_marker :
begin
enable_timer_60usec <= 0;
m1_next_state <= m1_rx_clk_l;
end
m1_rx_rising_edge_marker :
begin
enable_timer_60usec <= 0;
m1_next_state <= m1_rx_clk_h;
end
m1_rx_clk_l :
begin
enable_timer_60usec <= 1;
if (tx_write) m1_next_state <= m1_tx_reset_timer;
else if (ps2_clk_s) m1_next_state <= m1_rx_rising_edge_marker;
else m1_next_state <= m1_rx_clk_l;
end
m1_tx_reset_timer:
begin
enable_timer_60usec <= 0;
m1_next_state <= m1_tx_force_clk_l;
end
m1_tx_force_clk_l :
begin
enable_timer_60usec <= 1;
ps2_clk_hi_z <= 0; // Force the ps2_clk line low.
if (timer_60usec_done) m1_next_state <= m1_tx_first_wait_clk_h;
else m1_next_state <= m1_tx_force_clk_l;
end
m1_tx_first_wait_clk_h :
begin
enable_timer_5usec <= 1;
ps2_data_hi_z <= 0; // Start bit.
if (~ps2_clk_s && timer_5usec_done)
m1_next_state <= m1_tx_clk_l;
else
m1_next_state <= m1_tx_first_wait_clk_h;
end
// This state must be included because the device might possibly
// delay for up to 10 milliseconds before beginning its clock pulses.
// During that waiting time, we cannot drive the data (q[0]) because it
// is possibly 1, which would cause the keyboard to abort its receive
// and the expected clocks would then never be generated.
m1_tx_first_wait_clk_l :
begin
ps2_data_hi_z <= 0;
if (~ps2_clk_s) m1_next_state <= m1_tx_clk_l;
else m1_next_state <= m1_tx_first_wait_clk_l;
end
m1_tx_wait_clk_h :
begin
enable_timer_5usec <= 1;
ps2_data_hi_z <= q[0];
if (ps2_clk_s && timer_5usec_done)
m1_next_state <= m1_tx_rising_edge_marker;
else
m1_next_state <= m1_tx_wait_clk_h;
end
m1_tx_rising_edge_marker :
begin
ps2_data_hi_z <= q[0];
m1_next_state <= m1_tx_clk_h;
end
m1_tx_clk_h :
begin
ps2_data_hi_z <= q[0];
if (tx_shifting_done) m1_next_state <= m1_tx_wait_keyboard_ack;
else if (~ps2_clk_s) m1_next_state <= m1_tx_clk_l;
else m1_next_state <= m1_tx_clk_h;
end
m1_tx_clk_l :
begin
ps2_data_hi_z <= q[0];
if (ps2_clk_s) m1_next_state <= m1_tx_wait_clk_h;
else m1_next_state <= m1_tx_clk_l;
end
m1_tx_wait_keyboard_ack :
begin
if (~ps2_clk_s && ps2_data_s)
m1_next_state <= m1_tx_error_no_keyboard_ack;
else if (~ps2_clk_s && ~ps2_data_s)
m1_next_state <= m1_tx_done_recovery;
else m1_next_state <= m1_tx_wait_keyboard_ack;
end
m1_tx_done_recovery :
begin
if (ps2_clk_s && ps2_data_s) m1_next_state <= m1_rx_clk_h;
else m1_next_state <= m1_tx_done_recovery;
end
m1_tx_error_no_keyboard_ack :
begin
tx_error_no_keyboard_ack <= 1;
if (ps2_clk_s && ps2_data_s) m1_next_state <= m1_rx_clk_h;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -