Tek V2

Version 2 of PS/2 keyboard adapter for Zeddies

Similar projects worth following
This project simplified version of a previous design [1] and provides quick and dirty matrix keyboard emulator to complement ZX-80/81 and ZX Spectrum boardsThe whole project is built around an Arduino Nano board and one (optional) diode. [1]

The ZX machines read the matrix keyboard by lowering 1 out of 8 upper address lines (A8..A15) and then read 5 bits of data in lines D0..D4 (as D5..D7 serve for other purposes).

According to the Z80 manual during an I/O read cycle the time spent from the fall of /IORQ to the middle of T3 state (when the CPU effectively samples the signal) is a bit less than 2.5 CPU cycles or something close to 680ns (for 3.579MHz clock) which is a challenge for the AVR to respond.

At the time the Z80 was created the designers knew that peripherals might take too much time to respond and provided a signal to pause the CPU while waiting for the external peripheral to respond. Such signal, named WAIT (really?!) is sampled between an internal WAIT state generated by the CPU between cycles T2 and T3, which occurs at around 500ns after the /IORQ signal go down.

Well, 680ns might not be enough for an AVR to enter and IRQ, sample the Z80 and respond with data, but 500ns is more than adequate to activate the WAIT line and then do wherever necessary and then release the Z80 from its idleness.

  • 1 × Arduino nano V3.0 ATMega328p prototyping board, 16MHz
  • 1 × 1N4148 Discrete Semiconductors / Diodes and Rectifiers

  • /KBD and /WAIT generator

    danjovic4 days ago 0 comments

    That's a possibility for a /KBD and /WAIT signal generator.

    Everytime  the Z80 perform a READ at IO address xxxxxxx0 and the pin /RELEASE coming from AVR is at HIGH state, the output Y6 Will go LOW and will generate the /KBD signal to interrupt the AVR and also will signal Z80 to WAIT and the AVR will have more time to attend the external interrupt.

    Afther the correct data have been put on KB0-KB4 lines the AVR can drop the /RELEASE line for a period of time equivalent to the end of "IN (C),A" iinstruction (1us will do the job) and then return the /RELEASE line back to high level.

    I hope this mechanism can work without a companion flip flop, like in the external version.

  • Oooops!

    danjovic08/11/2019 at 04:00 0 comments

    I have completely missed that the ZX81 ULA does not provide an external signal for reading the keyboard. Same for TS1500.

    It is a pity but a a decoder required for these micros... a simple 74HC32 should do the job.

  • Issues with WAIT line on clones

    danjovic08/09/2019 at 23:12 0 comments

    On the ZX80/81 the /WAIT line is used to synchronize the Z80 with NMI timing twice during each video frame. The inverted /HALT line is ORed with /NMI using a transistor and some resistors.

    Some clone machines (even modern clones) have been designed using logic gates instead of a transistor.

    The problem with the latter designs is that a peripheral device (like my keyboard adapter) would fail to bring down the /WAIT line to hold the Z80, as the signal is generated by an ordinary TTL gate (instead of an Open Collector).

    It can be fixed though with one diode and one resistor.

  • Wish list...

    danjovic08/07/2019 at 23:37 0 comments

    Wish list

    • Selectable Keyboard Layout (US, ABNT, etc) 
    • Selectable target machine (ZX80/81, Speccy)
    • Get keystrokes from serial port  

  • Encoding examples

    danjovic08/05/2019 at 02:59 0 comments

    SPACE key on PS/2 keyboard return scancode of 0x29  (41 in decimal). In Zeddies the SPACE is at line 0 (KB0) of  row 7 (A15)

    Then the 41th positon in vector   PS2Keymap[ ] contains the value 0x07

    Backspace has a PS/2 scancode of 0x66 (102) and is a good example of the use of the modifier. On the Zeddies the corresponding key is SHIFT + '0' (ROBOUT). Key 0 itself is at line 0 of row 4. Then the 102th entry in vector  PS2Keymap[ ]  has the value of 04 for the '0' key plus  128 that is the 7th bit for the encoded value.

    Arrow keys are extended  PS/2 codes but are also mapped as SHIFT plus the values for keys 5 to 8.

    if (EXT==true) { // extended set
        switch (code) {
            case _PS2_UP:   	m=0x80 | _7; break; // Caps Shift bit + map code for ZX key 7
            case _PS2_DOWN: 	m=0x80 | _6; break;
            case _PS2_LEFT: 	m=0x80 | _5; break;
            case _PS2_RIGHT:	m=0x80 | _8; break;
            case _PS2_KPENT:	m=_ENT     ; break; // Enter key
            case _PS2_LCONTROL:	m=_SYMB    ; break; // Enter key

    The function Update_matrix( ) uses this value  to SET or RESET a bit on the keyboard matrix depending upon the reception of a 'break' code previously.

    void Update_matrix( char m){
    uint8_t line= m & 0x07;
    uint8_t row=  (m>>3) & 0x07;
    if (BRK==true) { 
        Keymap[line]|=(1<<row);          //  set bits to break
        if (m & 0x80) Keymap[0]|=(1<<0); // if bit 7 is set then set Caps Shift bit at row=0, line=0
        if (m & 0x40) Keymap[7]|=(1<<1); // if bit 6 is set then set Symbol Shift bit at row=1, line=7			
    } else {                              
        Keymap[line]&=~(1<<row);          // reset bits to make
        if (m & 0x80) Keymap[0]&=~(1<<0); // if bit 7 is set then reset Caps Shift bit at row=0, line=0
        if (m & 0x40) Keymap[7]&=~(1<<1); // if bit 6 is set then reset Symbol Shift bit at row=1, line=7	

  • Key mapping

    danjovic08/04/2019 at 01:25 0 comments

    Zeddies use a matrix keyboard of 8 rows by 5 columns. Rows are tied to address lines A8 to A15 while rows are read in data lines D0 to D4.

    Firmware uses a vector with 8 entries. Each entry corresponds to one address line A8..A15 set down.
    char Keymap[Keymap_Size] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};

    Keys are encoded using 3 bits for lines and 3 bits for row. Two remaining bits can be used as modifiers (Shift on ZX80/81 and  Caps Shift/Symbol Shift on Speccy).

       ZX spectrum keyboard matrix map codes
       bit  7   6   5   4   3   2   1   0
            CS  SS  r2  r1  r0  l2  l1  l0  
       r0..r2 is row [0..4]   mapping bits D0 to D4
       l0..l2 is line [0..7]  mapping address lines A8 to A15
       CS Caps Shift for composed keys (like directional keys)
       SS Symbol Shift for composed keys  

    PS/2 keyboard send a scancode (0x??) for each key pressed. When that key is released the scancode is preceeded by a 'break' code (0xE0 0x?? ). Some keys are preceeded by an 'extend' code (0xF0 0x??) and when released the 'break' code is sent, then the 'extend' code also sent and finally the scancode (0xE0 0xF0 ox??)

    The scancode is used as an entry to a table which returns the modifier/row/line code an used to RESET a bit in the Keymap[] vector. If a 'break' code have been previously received the bit is SET in the vector.

View all 6 project logs

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates