Skip to end of metadata
Go to start of metadata

Code Downloads

PS/2 Keyboard to ASCII Converter Logic (top level VHDL for the design):  ps2_keyboard_to_ascii.vhd

PS/2 Keyboard Interface Logic (must be included in the project):  ps2_keyboard.vhd

Debounce Logic (must be included in the project):  debounce.vhd


  • VHDL source code of a PS/2 keyboard to ASCII converter
  • Outputs the ASCII codes that correspond to key presses on a PS/2 keyboard
  • Ignores keys that have no ASCII equivalent
  • Sets a flag output when a new ASCII code is available
  • Validates parity, start, and stop bits of PS/2 transactions
  • Configurable system clock frequency
  • Synchronizes between PS/2 and system clock domains
  • Debounces incoming PS/2 signals


This details a PS/2 keyboard to ASCII converter component for use in CPLDs and FPGAs, written in VHDL.  The component receives data transactions from a PS/2 keyboard and provides the corresponding ASCII codes to user logic over a parallel interface.  It provides codes only for key presses (not releases) and ignores keys that do not have ASCII equivalents.  It was designed using Quartus II, version 12.1.  Figure 1 illustrates a typical example of the PS/2 keyboard to ASCII converter integrated into a system.

Figure 1.  Example Implementation


PS/2 Keyboards

PS/2 (IBM Personal System/2) is an interface for keyboards and mice to PC compatible computer systems via a 6-pin Mini-DIN connector.  The computing system must provide the keyboard or mouse with 5V source and ground connections.  Communication occurs over a 2-wire serial interface, consisting of a clock line and a data line.  Both lines require pull-up resistors (2kΩ shown in Figure 1).  The 120Ω series resistors in Figure 1 are required to interface the 3.3V FPGA I/O to the 5V signals.

Once powered, the keyboard goes through a self- initialization sequence.  Upon completion, it is ready to communicate keyboard events over the PS/2 interface. 

Figure 2 illustrates the transaction format.  Both clock and data signals are logic level high when inactive (note pull-up resistors).  The keyboard provides both the clock and data.  The clock has a frequency between 10 kHz and 16.7 kHz (i.e. a 60-100us period).  The data begins with a start bit (logic low), followed by one byte of data, a parity bit, and finally a stop bit (logic high).  The data is sent LSB first.  Each bit should be read on the falling edge of the clock signal.  Once complete, both the clock and data signals return to logic level high.

Figure 2.  PS/2 Keyboard Transmission Timing Diagram

The data byte represents part of a keyboard scan code:  either a make code (key press) or a break code (key release).  Three different sets of scan codes exist, however the vast majority of keyboards use Scan Code Set 2, which is provided here.  A make code usually consists of either one or two bytes.  If a make code uses two bytes, the first byte is x“E0”.  A given key’s break code is typically the same as its make code, except that break codes include an additional x“F0” byte as the 2nd to last byte.  (The PAUSE and PRNT SCRN keys are exceptions to the above.)

While it is possible to send data to a keyboard (to change its settings, etc.), this is generally unnecessary and is not included in this VHDL component.


ASCII (American Standard Code for Information Interchange) is a prominent standard for encoding characters and control codes into 7-bit binary integers.  ASCII defines 128 individual codes (95 characters and 33 control codes).  These codes can all be translated from a keyboard, either as direct key presses or as combinations of key presses.

PS/2 to ASCII Conversion

This PS/2 keyboard to ASCII converter handles incoming transactions from the PS/2 keyboard and determines which keys are being pressed at a given time.  It then outputs the ASCII encoding that corresponds to these key presses.  The appendix lists the ASCII Character Set.  All character keys have their respective ASCII codes outputted by the PS/2 to ASCII converter as listed, when those keys are pressed in a standard fashion (with respect to shift, caps lock, etc.).  If a control key is held down, the converter outputs the corresponding control code for each key instead (irrespective of shift or caps lock).  The converter also outputs control codes for the additional following keys:  backspace (BS), tab (HT), enter (CR), escape (ESC), and delete (DEL).

Theory of Operation

The source code for the PS/2 keyboard to ASCII converter consists of the following three files:

  • ps2_keyboard_to_ascii.vhd
  • ps2_keyboard.vhd
  • debounce.vhd

The ps2_keyboard_to_ascii.vhd file is the top level VDHL.  It instantiates the PS/2 keyboard interface component (ps2_keyboard.vhd).  This internal component handles the transactions with the keyboard.  It synchronizes the interface and system clocks domains, debounces the input signals, performs error checking, and provides the codes received from the keyboard.  Detailed documentation for the PS/2 keyboard interface is available here.  (The PS/2 keyboard interface component in turn instantiates the debounce component, debounce.vhd.  Documentation for the debounce component is available here.) 

The PS/2 codes provided by the PS/2 keyboard interface component control the converter’s state machine.  Figure 3 depicts the operation of the state machine.  Upon start-up, the component immediately enters the ready state.  It waits in this state until it receives a new PS/2 code.  The new_code state builds the PS/2 make or break codes.  If the new code received is the last byte in the make/break code, the state machine proceeds to the translate state, otherwise it returns to the ready state to await the next byte.  Once in the translate state, the converter determines which key was pressed and translates it into ASCII.  If the code is a break code, then no action is needed, so the converter ignores the code and returns to the ready state.  However, if a make code was received, the converter proceeds to the output state, where it outputs the resultant ASCII code on the ascii_code bus and sets the ascii_new output flag to indicate that the new code is available.  The converter then returns to the ready state to await the next communication from the PS/2 keyboard interface component.


Figure 3.  State Diagram

Port Descriptions

Table 1 describes the PS/2 keyboard to ASCII converter’s ports.

Table 1.  Port Descriptions

PortWidthModeData TypeInterfaceDescription
clk1instandard logic

user logic

System clock.
ps2_clk1instandard logicPS/2 keyboardClock signal from PS/2 keyboard.
ps2_data1instandard logicPS/2 keyboardData signal from PS/2 keyboard.
ascii_new1outstandard logicuser logicNew code available flag.  The flag is low during PS/2 to ASCII conversions, and a low-to-high transition indicates that a new ASCII code is available on the ascii_code bus.
ascii_code7outstandard logic vectoruser logic7-bit ASCII code translated from the PS/2 keyboard.

Setting the Timing Parameters

The system clock speed affects the debounce time and the idle counter timing of the PS/2 keyboard interface component within the converter.  The two GENERIC parameters declared in the ENTITY, clk_freq and ps2_debounce_counter_size must be set appropriately for the component to operate correctly.  The clk_freq parameter must be set to the system clock clk frequency in Hz.  The default setting in the provided code is 50 MHz (the frequency at which the component was simulated and tested).   The ps2_debounce_counter_size parameter must be set such that 2 ps2_debounce_counter_size / clk_freq = 5us, as described in the documentation for the debounce component here.  For a 50 MHz system clock, ps2_debounce_counter_size = 8.

Example Transaction

Figure 4 shows the timing diagram of an example transaction.  Once the internal PS/2 keyboard interface finishes receiving the PS/2 transaction, the ascii_new flag deasserts to indicate that a new PS/2 to ASCII conversion is in progress.  When the transaction completes, the ascii_new flag asserts to indicate that a new ASCII code has been received and is available on the ascii_code bus.  In this case, the PS/2 code received is x“1C” (the make code for the “A” key), and the resulting ASCII code is x“61” (the ASCII code for the “a” character).

Figure 4.  Example Transaction


This PS/2 keyboard to ASCII converter is a programmable logic component that receives transactions from PS/2 keyboards and outputs their ASCII equivalents.  It synchronizes the PS/2 and system clock domains, debounces the input signals, performs error checking, translates the PS/2 codes into ASCII codes, and notifies the user logic when new ASCII codes are available on its parallel output bus.

Appendix:  ASCII Character Set

Table A1.  ASCII Character Set

Control Codes

BinaryDecHexControl CodeKeyControl Code Name
000 0000000NUL^@Null Character
000 0001101SOH^AStart of Header
000 0010202STX^BStart of Text
000 0011303ETX^CEnd of Text
000 0100404EOT^DEnd of Transmission
000 0101505ENQ^EEnquiry
000 0110606ACK^FAcknowledgment
000 0111707BEL^GBell
000 1000808BS^HBackspace
000 1001909HT^IHorizontal Tab
000 1010100ALF^JLine feed
000 1011110BVT^KVertical Tab
000 1100120CFF^LForm Feed
000 1101130DCR^MCarriage Return
000 1110140ESO^NShift Out
000 1111150FSI^OShift In
001 00001610DLE^PData Link Escape
001 00011711DC1^QDevice Control 1 (oft. XON)
001 00101812DC2^RDevice Control 2
001 00111913DC3^SDevice Control 3 (oft. XOFF)
001 01002014DC4^TDevice Control 4
001 01012115NAK^UNegative Acknowledgement
001 01102216SYN^VSynchronous Idle
001 01112317ETB^WEnd of Transmission Block
001 10002418CAN^XCancel
001 10012519EM^YEnd of Medium
001 1010261ASUB^ZSubstitute
001 1011271BESC^[Escape
001 1100281CFS^\File Separator
001 1101291DGS^]Group Separator
001 1110301ERS^^Record Separator
001 1111311FUS^_Unit Separator
111 11111277FDEL^?Delete

Character Codes

010 00003220 
010 00013321!
010 00103422"
010 00113523#
010 01003624$
010 01013725%
010 01103826&
010 01113927'
010 10004028(
010 10014129)
010 1010422A*
010 1011432B+
010 1100442C,
010 1101452D-
010 1110462E.
010 1111472F/
011 000048300
011 000149311
011 001050322
011 001151333
011 010052344
011 010153355
011 011054366
011 011155377
011 100056388
011 100157399
011 1010583A:
011 1011593B;
011 1100603C<
011 1101613D=
011 1110623E>
011 1111633F?
100 00006440@
100 00016541A
100 00106642B
100 00116743C
100 01006844D
100 01016945E
100 01107046F
100 01117147G
100 10007248H
100 10017349I
100 1010744AJ
100 1011754BK
100 1100764CL
100 1101774DM
100 1110784EN
100 1111794FO
101 00008050P
101 00018151Q
101 00108252R
101 00118353S
101 01008454T
101 01018555U
101 01108656V
101 01118757W
101 10008858X
101 10018959Y
101 1010905AZ
101 1011915B[
101 1100925C\
101 1101935D]
101 1110945E^
101 1111955F_
110 00009660`
110 00019761a
110 00109862b
110 00119963c
110 010010064d
110 010110165e
110 011010266f
110 011110367g
110 100010468h
110 100110569i
110 10101066Aj
110 10111076Bk
110 11001086Cl
110 11011096Dm
110 11101106En
110 11111116Fo
111 000011270p
111 000111371q
111 001011472r
111 001111573s
111 010011674t
111 010111775u
111 011011876v
111 011111977w
111 100012078x
111 100112179y
111 10101227Az
111 10111237B{
111 11001247C|
111 11011257D}
111 11101267E~


Comments, feedback, and questions can be sent to eewiki@digikey.com.

  • No labels