Home    --    Hierarchy    --    Packages    --    Entities    --    Instantiations    --    Sources

Architecture rtl of work.ps2_keyboard

Implements a PS/2 Keyboard Interface

Defined in VHDL/ps2_keyboard.vhd


Detailed description

This is a state-machine driven serial-to-parallel and parallel-to-serial interface to the ps2 style keyboard interface. The details of the operation of the keyboard interface were obtained from the following website:

http://www.beyondlogic.org/keyboard/keybrd.htm

Some aspects of the keyboard interface are not implemented (e.g, parity checking for the receive side, and recognition of the various commands which the keyboard sends out, such as "power on selt test passed," "Error" and "Resend.") However, if the user wishes to recognize these reply messages, the scan code output can always be used to extend functionality as desired.

Note that the "Extended" (0xE0) and "Released" (0xF0) codes are recognized. The rx interface provides separate indicator flags for these two conditions with every valid character scan code which it provides. The shift keys are also trapped by the interface, in order to provide correct uppercase ASCII characters at the ascii output, although the scan codes for the shift keys are still provided at the scan code output. So, the left/right ALT keys can be differentiated by the presence of the rx_entended signal, while the left/right shift keys are differentiable by the different scan codes received.

The interface to the ps2 keyboard uses ps2_clk clock rates of 30-40 kHz, dependent upon the keyboard itself. The rate at which the state machine runs should be at least twice the rate of the ps2_clk, so that the states can accurately follow the clock signal itself. Four times oversampling is better. Say 200kHz at least. The upper limit for clocking the state machine will undoubtedly be determined by delays in the logic which decodes the scan codes into ASCII equivalents. The maximum speed will be most likely many megahertz, depending upon target technology. In order to run the state machine extremely fast, synchronizing flip-flops have been added to the ps2_clk and ps2_data inputs of the state machine. This avoids poor performance related to slow transitions of the inputs.

Because this is a bi-directional interface, while reading from the keyboard the ps2_clk and ps2_data lines are used as inputs. While writing to the keyboard, however (which may be done at any time. If writing interrupts a read from the keyboard, the keyboard will buffer up its data, and send it later) both the ps2_clk and ps2_data lines are occasionally pulled low, and pullup resistors are used to bring the lines high again, by setting the drivers to high impedance state.

The tx interface, for writing to the keyboard, does not provide any special pre-processing. It simply transmits the 8-bit command value to the keyboard.

Pullups MUST BE USED on the ps2_clk and ps2_data lines for this design, whether they be internal to an FPGA I/O pad, or externally placed. If internal pullups are used, they may be fairly weak, causing bounces due to crosstalk, etc. There is a "debounce timer" implemented in order to eliminate erroneous state transitions which would occur based on bounce.

Parameters are provided in order to configure and appropriately size the counter of a 60 microsecond timer used in the transmitter, depending on the clock frequency used. The 60 microsecond period is guaranteed to be more than one period of the ps2_clk_s signal.

Also, a smaller 5 microsecond timer has been included for "debounce". This is used because, with internal pullups on the ps2_clk and ps2_data lines, there is some bouncing around which occurs

A parameter TRAP_SHIFT_KEYS allows the user to eliminate shift keypresses from producing scan codes (along with their "undefined" ASCII equivalents) at the output of the interface. If TRAP_SHIFT_KEYS is non-zero, the shift key status will only be reported by rx_shift_on. No ascii or scan codes will be reported for the shift keys. This is useful for those who wish to use the ASCII data stream, and who don't want to have to "filter out" the shift key codes.

Instantiated in...

work.keyboard (rtl)

Libraries and global use clauses

library ieee
use ieee.numeric_std.all
use ieee.std_logic_1164.all
use ieee.std_logic_arith.all
use ieee.std_logic_unsigned.all

Type declarations

typem1_typeis ( m1_rx_clk_h, m1_rx_clk_l, m1_tx_wait_clk_h, m1_tx_force_clk_l, m1_tx_clk_h, m1_tx_clk_l, m1_tx_wait_keyboard_ack, m1_tx_done_recovery, m1_tx_error, m1_tx_rising_edge_marker, m1_tx_first_wait_clk_h, m1_tx_first_wait_clk_l, m1_tx_reset_timer, m1_rx_falling_edge_marker, m1_rx_rising_edge_marker )
State encodings, provided as constants 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.

Constants

TOTAL_BITS integer := 11
EXTEND_CODE integer := 16#E0#
RELEASE_CODE integer := 16#F0#
LEFT_SHIFT integer := 16#12#
RIGHT_SHIFT integer := 16#59#
CTRL_CODE integer := 16#14#
LEFT_ALT integer := 16#11#
CAPS_CODE integer := 16#58#
SCROLL_LOCK integer := 16#7E#
NUM_LOCK integer := 16#77#
TIMER_60USEC_VALUE_PP integer := CLK_FREQ_MHZ * 60
TIMER_60USEC_BITS_PP integer := 12
TIMER_5USEC_VALUE_PP integer := CLK_FREQ_MHZ * 5
TIMER_5USEC_BITS_PP integer := 8
TRAP_SHIFT_KEYS_PP integer := 1

Component declarations

keymap_rom
key lookup table
Default binding: work.keymap_rom

Processes

ps2_direction ( ps2_clk_hi_z, ps2_data_hi_z )
Module code assign ps2_clk = ps2_clk_hi_z?1'bZ:1'b0; assign ps2_data = ps2_data_hi_z?1'bZ:1'b0;
ps2_synch (clk, ps2_clk, ps2_data)
Input "synchronizing" logic -- synchronizes the inputs to the state machine clock, thus avoiding errors related to spurious state machine transitions.
m1_state_register ( clk, reset, m1_state )
State register
m1_state_logic ( m1_state, q, tx_shifting_done, tx_write, ps2_clk_s, ps2_data_s, timer_60usec_done, timer_5usec_done )
bit_counter (clk, reset, m1_state, bit_count )
This is the bit counter
assign ( bit_count, tx_write, m1_state, tx_data_empty_o, m1_state )
q_shift (clk, tx_data_empty_o, tx_parity_bit, tx_data, m1_state, q, ps2_data_s, rx_shifting_done )
This is the shift register
timer60usec (clk, enable_timer_60usec, timer_60usec_count)
This is the 60usec timer counter
timer5usec (clk, enable_timer_5usec, timer_5usec_count )
This is the 5usec timer counter
extend_release_decode ( q, rx_shifting_done, extended, released )
Create the signals which indicate special scan codes received. These are the "unlatched versions."
special_scan (clk, reset, rx_output_event, rx_shifting_done, extended, released )
Store the special scan code status bits.
Not the final output, but an intermediate storage place, until the entire set of output data can be assembled.
scan_to_ascii ( shift_key_on, caps_key_on, q )
convert scan code to ascii code
left_shift_proc (clk, reset, q, rx_shifting_done, hold_released )
These bits contain the status of the two shift keys
right_shift_proc (clk, reset, q, rx_shifting_done, hold_released )
shift_proc ( left_shift_key, right_shift_key, shift_key_on, caps_key_on, q )
ctrl_proc (clk, reset, q, rx_shifting_done, hold_released )
Control keys
caps_proc (clk, reset, q, rx_shifting_done, hold_released, caps_key_on )
Caps lock
special_scan_proc (clk, reset, rx_output_strobe, hold_extended, hold_released, ascii, ctrl_key_on )
Output the special scan code flags, the scan code and the ascii
rx_output_proc ( clk, reset, rx_shifting_done, rx_output_strobe, extended, released, hold_extended, hold_released, q, ascii, rx_read )
Store the final rx output data only when all extend and release codes are received and the next (actual key) scan code is also ready. (the presence of rx_extended or rx_released refers to the the current latest scan code received, not the previously latched flags.)

Instantiations

my_key_map : keymap_rom
Binding: work.keymap_rom (rtl)

Generated on 1 Jan 2018 19:48:42 with VHDocL V0.2.6