I'm using an
stm32f0discovery board to pretend to be a keyboard for a 128k/512k/Plus machine. I chose the board mainly because it's cheap ($8 from digikey) and comes with a perfboard, making it pretty accessible. Solder on some connectors and done (for the most part). It also comes with a builtin programmer, so nothing special needed to program it, hardware wise.
This template makes things pretty simple to compile and load onto the device from linux.
It's a 3.3V device and the Plus keyboard is 5V, so I'm using
this level converter from adafruit, also fairly cheap and easily attaches to the perfboard.
I've mainly been using
this as my reference for the protocol. Essentially the keyboard controls the clock, the data is bidirectional and orchestrated by the computer. When the computer wants to talk, it pulls the normally high data line low, the keyboard starts clocking, and the computer sends its data. The keyboard then responds, and done.
There are only a couple commands the computer sends. The two most common (and the ones I've implemented) are Model Number (0x16) and Inquiry (0x10). The computer polls the keyboard continuously with an Inquiry command, and the keyboard returns any keys that have been pressed. The keyboard must respond within 500ms or the computer resets and starts over. The keyboard will issue another Inquiry command immediately upon receiving a response, so the keyboard is responsible for rate limiting the polling. If no keys have been pressed, the keyboard should wait about 250ms before sending a null response otherwise it'll just be a tight polling loop.
Here's a screenshot from the Saleae logic analyzer:

This shows the start of the Model Number request (0x16), and my response (0x03) indicating a keyboard of model number 1 is connected with no keypad.

This shows the start of the Inquiry request (0x10) and my response (0x7B) indicating no keypress. I'm not waiting here, so the computer is immediately issuing another Inquiry command, which I'm responding immediately, etc.