Ah right. Well, as you said, the timing is quite tight at 1-3MHz. My BBC Micro code suffers problems with a 2MHz CPU.
I fleshed out my PB6-interrupt-based keyboard code a bit more though, and it's very reliable now - you can see it here and even run it but of course the emulator doesn't have a PS/2 keyboard attached:
https://bbcmic.ro/#%7B%22v%22%3A1%2C%22 ... %5Cn%22%7DThis implementation is specifically for the BBC Micro, especially dealing with late interrupts due to the OS being part-way through handling an interrupt when the keyboard interrupt occurs. I'm not sure how important that would be for other systems, especially if you have the option of running the CPU at a faster clock speed to reduce the impact of handling other interrupts like this.
The program installs an interrupt handler that manages the keyboard and stores incoming bytes in a circular buffer; it then runs some BASIC code to monitor that buffer and print the byte values to the screen, along with an animation to help ensure that it's not permanently blocked in the interrupt handler. I didn't implement anything like keycode translation or inserting characters into OS buffers, because I was only really interested in the usage of the 6522 VIA. Comparing the code to the Sprow disassembly, there's some similarity in the way the read interrupt handler works - I am surprised though that the Sprow code doesn't suffer from the same problems that I did with other OS interrupts delaying the processing of the keyboard interrupts.
Hardware-wise, the PS/2 clock is connected to PB6, and PS/2 data to PB7. I didn't add pull-up resistors - the NMOS 6522 pulls up fairly well anyway - but it's probably better to use them. Timer 2 is used to create the PB6 interrupt, and Timer 1 is used to apply timeouts to each byte operation, so that if there's a problem with the signal from the keyboard we don't end up stuck waiting for a clock pulse that will never come. CB1, CB2, PB0-PB5 are all free for use by a mouse or other devices.
The data signal could be moved from PB7, though the code takes some advantage of it being on PB7 - it'd require a few extra instructions to use a different pin.
Parity and stop bits are checked, and if these checks fail we send a break signal to the keyboard, which may result in retransmission. It would probably be better to explicitly send the $FE command for those cases.
The start bit is not checked because I found that I couldn't reliably sample it. Instead I used the pulse counting on PB6 to wait specifically for the first data bit, by which point Timer 2 is set to -2, and then the rest of the read operation proceeds from there. Being able to use Timer 2 to reliably tell how far we are through the byte, regardless of interrupt response time, was very useful here. If Timer 2 is less than -2 already then we have missed the first data bit, and we abandon the read and again send a break signal to the keyboard, which this time will cause retransmission of the byte. I tested this and it seemed very reliable - mashing keys on the BBC's keyboard is enough to cause a lot of latency in the OS IRQ handler, and cause missed bytes from the PS/2 keyboard, but with this behaviour of interrupting the PS/2 keyboard mid-byte, the eventual byte stream from the keyboard looks perfect to me, with no missed bytes.
The interrupt handler blocks until the byte is fully received, which usually takes about a millisecond. The timeout for receiving the byte is set to 2ms because that's what I saw specified in a document somewhere; there's also a write timeout set to 17ms, also based on some numbers I saw documented somewhere, so if the keyboard doesn't send the right clock pulses during a write operation, we don't block forever waiting for them. I also tested to make sure that TIME was incrementing at the right rate, and it seems unaffected, so we are not blocking for too long in the interrupt handler.