RC 2022/10 Day 3: Debugging the PS/2 state machine

A project log for Flounder Z180 Computer

Standalone single-board computer based on the Zilog Z180 CPU

Colin MaykishColin Maykish 10/04/2022 at 01:380 Comments

The PS/2 keyboard interface is one step closer to being useful. I added some code to the monitor program to translate scan codes from the CPLD into ASCII characters for the CPU.  This was working for about 20 or 30 characters before the Z180 started reading garbage data from the CPLD.

The Verilog code that handles the PS/2 data in is a state machine that reads once bit at a time and shifts it into a register. Each time the PS/2 clock line goes low, one of these shifts takes place. Each scan code is an 11-bit frame: 1 start bit, 8 data bits, one parity bit, and one stop bit. My suspicion was that the state machine (i.e. the index of the next incoming bit) was being corrupted or otherwise losing sync with the keyboard. The CPLD has no way to know if something like this happens. It will happily keep shifting in bits from the tail end of one scan code and the first half of another. That would certainly cause trouble.

To test this, I added an LED output to the CPLD and set it to turn on at the start of a scan code, i.e. bit 1, and turn off at bit 10 when the scan code read is complete. The PS/2 clock rate is supplied by the keyboard, not the host, but it's generall around 12 kHz. This is definitely slow enough for the LED to act as a nice visual activity indicator for the keyboard.

I was expecting to see the LED flicker when keys were pressed and then turn off. That's what it did for the most part, but when the CPU started reading garbage data, the LED would occasionally stay on, meaning it received a start bit, but no stop bit.

To combat this, I tried to reset the state machine was a bad start or stop bit was detected (start bit is always 0 and stop bit is always 1), but that caused more problems.

After remembering that some of the documentation on the PS/2 mentioned timing and sampling rate being fairly important, I thought maybe the way I was reading in bits was an issue. Long story short: it was. The PS/2 state machine operates in the CPU clock domain. It does not actually treat the PS/2 clock as a clock, just another input. Since the CPU clock is so much faster than the PS/2 clock, the CPLD was reading the PS/2 data line too quickly after the PS/2 clock line was negated and not getting a reliable reading of the actual data line. My solution was to add a delay of 8 CPU cycles after the PS/2 clock goes low before reading the PS/2 data line.

This improved reliability dramatically. It doesn't actually solve any potential issues with the state machine getting out of sync. That's a problem I'll have to deal with eventually, but I think it's a fairly rare occurrence in general.

So I now have crude PS/2 support in the monitor program. It's polling, not interrupt-based, and it's slow. Typing too fast can overload it and characters will be dropped. There is also no support for capital letters or handling shift/control/etc., but it's a start.

** Flounder Z180 System Monitor **
> cpld
PS/2 keyboard test
 this is flounder with a ps2 keyboard

For reference, here's the current Verilog code implementing the PS/2 state machine: