MC68000 PS/2 keyboard & mouse interface

A project log for Motorola 68000 computer

A mc68k-based computer motherboard, some expansion cards, and a very basic multitasking OS, all built from scratch.

StuartStuart 01/05/2016 at 23:0318 Comments

As usual, it has been a while since my last update. I've been busy working on some new expansion cards for the MC68000 motherboard. It's a bit boring interacting with the system via an RS232 serial port, so I thought I'd build an expansion card enabling me to connect the motherboard to a keyboard and mouse.

The first step in the design was to pick a communications protocol. I wanted to implement a standardised protocol so that I could use an ordinary keyboard and mouse without modification. Having ruled out ancient XT keyboards, I was left with USB and PS/2. USB felt too modern for this project - after all, the idea is to build a system which has a level of technology roughly in line with the sort of stuff that was available in the 80s and early 90s. PS/2 it is, then! To the breadboards!

Here's the prototype dual-channel PS/2 controller plugged into the MC68000 motherboard.

The PS/2 protocol is pretty straightforward. It's an 8-bit synchronous bidirectional serial interface in which the "device" (the keyboard or mouse) generates a clock signal at around 10kHz and exchanges data with the host in a format quite similar to RS232. In PCs, the interface was implemented using an Intel 8042 microcontroller. When a key is pressed on the keyboard, a scan code is sent by the keyboard to the host. This code uniquely identifies the key, but is not related to e.g. the ASCII code representing the symbol on the key-cap. When the key is released, the keyboard sends a "key released" code (0xF0), followed by the scan code of the key. The PS/2 mouse protocol works a bit differently: whenever the mouse is moved, or a button is pressed or released, the mouse sends a small packet of data (three or four bytes, depending on the type of mouse) containing information about the mouse's relative motion and the state of the buttons.

I considered building the controller around an Intel 8042, but eventually decided against it. It's a decent enough chip, but I felt that I wouldn't learn the protocol in sufficient depth by using somebody else's implementation. Instead, I decided to build an interface around a microcontroller: the (admittedly fairly modern) Atmel ATmega8. This is what I came up with.

Dual-channel PS/2 controller schematic

The ATmega8 has 28 pins, which is just about enough to implement two separate PS/2 ports and an 8-bit interface to the host system. The firmware is quite simple: it's mainly an interrupt-driven state machine which manages communication between the microcontroller and the PS/2 devices. The non-interrupt-driven part of the code is pretty much just a loop which deals with the interface between the controller and the MC68000.

The controller exposes a bunch of registers to the host processor; these include a configuration register which can be programmed to enable interrupts to be raised when various different conditions are encountered on each port: byte received, transmission completed, timeout, parity error, etc. The controller also contains a 256-byte FIFO for each PS/2 channel (unlike the Intel 8042!); this means that the host doesn't need to respond immediately whenever data is received from the peripherals.

There are horror stories about the damage caused by unplugging PS/2 peripherals from early PCs. Apparently the electrical interface wasn't very well-protected, or whatever; if the rumours are to be believed, a motherboard could be destroyed by connecting or disconnecting a PS/2 keyboard at the wrong moment. It's difficult to know how much of this is true, but given that my controller connects to the outside world, it needs to be reasonably tolerant of abuse. With this in mind I have added short-circuit protection, protection against shorts to out-of-range voltages (within reason), and some transient/noise suppression. In order to make the interface somewhat hot-pluggable, I've wired things up so that the ATmega8 can switch each PS/2 port's power on and off independently.

Another slightly annoying thing about early PCs was the need to connect the keyboard and mouse to particular sockets. There's no electrical reason why the ports shouldn't be interchangeable, so - on my controller - they are. The driver software can easily work out whether it's talking to a keyboard or a mouse, and behave appropriately.

As you can see from the schematic, the controller is an extremely simple circuit; it only took an hour or two to lay out the PCB. The board is 95mm x 45mm, double-sided. I've sent it off for manufacture; the first boards should arrive next week.

Dual-channel PS/2 controller PCB

If anybody is interested, I might write a little more about the controller firmware and the MC68000 interface. I'm prepared for a wall of silence from you all, though :)


Jason Westervelt wrote 01/10/2016 at 19:57 point

awesome, thanks!   I'll be throwing together details of my keyboard controller setup once i get things finalized.  My job has kept me busy the past few weeks and I haven't had time to play catch-up.

  Are you sure? yes | no

Yann Guidon / YGDES wrote 01/09/2016 at 12:34 point

Nice design :-)

  Are you sure? yes | no

Stuart wrote 01/09/2016 at 13:09 point

Thank you Yann!

  Are you sure? yes | no

K.C. Lee wrote 01/09/2016 at 12:22 point

BTW I have implemented hotswap and device recognition on my FPGA board using ARM chip.  I got by without fancy power on/off control.  The logic is pretty ugly as it has to recognize unplugging in the middle of receiving a packet and being able to resynchronize/reinitialize hot plugging.

Let me know if you want the source code - it is running on ChibiOS (RTOS) and use 1 thread per PS/2 device.  Haven't got around to much beyond that unfortunately.

  Are you sure? yes | no

Stuart wrote 01/09/2016 at 13:09 point

Thanks K.C. - I like what you've done there.  I decided to avoid FPGAs for this project.  My reason was that if I use an FPGA, I may as well implement the whole hardware design in one chip - at that point, the whole project is effectively an exercise in "software" (HDL) instead of a full hardware design.  In future I'll certainly be publishing some FPGA projects, but in this case I'm sticking with the low-tech stuff :)

  Are you sure? yes | no

K.C. Lee wrote 01/09/2016 at 14:05 point

I understand the love for vintage parts etc as I hog old Zilog and Motorola parts. Different approaches as my goals and constrains are different.  

For me, the hardware design is easy and fun, but I want to improve my skills for large HDL or software projects.  I get side tracked easily or given up and procrastinate because of the complexity. :(

  Are you sure? yes | no

Yann Guidon / YGDES wrote 01/09/2016 at 21:30 point

Don't worry K.C., we're all experiencing these ups and downs :-)

  Are you sure? yes | no

oni305 wrote 01/09/2016 at 11:36 point

may i suggest to use a prallax propeller to create an interface for 2x PS/2  & 1x VGA

  Are you sure? yes | no

Jason Westervelt wrote 01/07/2016 at 18:59 point

PSH... wall of silence.

I am currently working on my PS2 keyboard interface as well.  Instead of using a modern Atmel part, I am kinda doing this in an oldschool way..ish.

Older intel based systems utilized the intel N8042 microcontroller for controlling the PS/2 keyboard and mouse, along with many other functions such as system reset and gating the A20 line.  I thought to myself, why not try making it work with a 68k machine.  I've got it mostly working, just trying to re-purpose some of its functions... the idea is that I can use the A20 gating as a RE-ROM signal to disconnect the ROM after it is shadowed to RAM.  

Using a modern micro is nice though, you can reprogram it at least.  In fact, you could probably implement a key-combo that toggles a pin to trigger a non-maskable interrupt for trace purposes.

  Are you sure? yes | no

Stuart wrote 01/08/2016 at 19:47 point

Hey Jason!  I hadn't thought of using key combinations to signal an NMI - that's an interesting notion.  Your comment led me to check out your 68020 project - it looks really interesting!  I'm starting a design based on a 68030/68882 combination at the moment; currently I'm looking at implementing a DRAM controller in a CPLD so that I can use old-school 72-pin SIMMs.

It would be good to share some ideas :)

  Are you sure? yes | no

Jason Westervelt wrote 01/09/2016 at 04:50 point

I eventually want to implement a DRAM controller as well.  Booting linux or even uclinux is pretty high up on my priority list at the moment.  

I started my learning of computers by building an 8bit CPU from scratch, learned how the opcodes work internally and all that fun stuff, and then moved up to building a computer around a prefabricated CPU... that being the 68020.  I'm still in the dark about a few things though, specifically, how the memory details (sizing and mapping) is passed to linux kernel at boot time.  Hell, I don't even know how to configure the PMMU to address the RAM either.  I haven't found a good tutorial on those subjects yet.

Oh, before I forget, I am interested in your bus design.  I'm thinking about implementing something like VME, but I don't like the huge VME connectors... especially when the second connector only uses the middle row of pins, leaving 64 pins with no function.  I thought that it would be better to make something pin-compatible to VME, but in a different form factor, and use a 4x32 pin header with 0.1" spacing.  The problem with that idea is that I don't know if I could route 3 traces between two pads spaced at 0.1"... i've never tried that before.  such a design may very well require 4-layer boards.  :/

  Are you sure? yes | no

K.C. Lee wrote 01/09/2016 at 12:06 point

@Jason Westervelt

Those unused pins on the 2nd VME connector are for user I/O.  The connector is optional for 24-bit addressing and 16-bit data bus. i.e. 68000  If you don't need high bandwidth memory on expansion cards and you can get by with 16M address space, then you can leave it out.  For a 32-bit CPU, you can use a sub address space (with some decoding) for I/O expansion cards.

To route the 4th ROW, you'll only need to squeeze a 2nd trace between pins on a double sided PCB. You need to escape 3 rows (2nd-4th) in 2 layers.  That is quite feasible with 6/6 design rules.

The hardware info is passed using FDT.

You can try to port uboot which is usually used as a bios/bootloader on embedded systems and it can handle all that and a lot more.

FYI: lots of the low level stuff here.

  Are you sure? yes | no

Stuart wrote 01/09/2016 at 14:18 point

Hey @Jason Westervelt - I threw together a description of the expansion bus in a separate log.  It's probably not very relevant to your '020 system, but maybe it will give you some food for thought at least :)

  Are you sure? yes | no

Jason Westervelt wrote 01/10/2016 at 20:23 point

thanks @K.C. Lee, you gave me a bit of direction here.  I didn't originally see mention of the unused P2 pins, but I decided to just suck it up and use the standard VME form factor.  I have a 10 position backplane and a few other goodies on the way.  I figure, I might as well use existing expansion cards until I can redesign my own.  :)

  Are you sure? yes | no

K.C. Lee wrote 01/06/2016 at 14:48 point

Might want to add series resistors on base of Q3 and Q4 to limit their base current (initially) during a fault.

BTW a PIC might have a slight advantage for the host interface as some of them (mid range PIC16F and PIC18F) have parallel slave port (PSP) as part of the peripherals.

  Are you sure? yes | no

Stuart wrote 01/06/2016 at 17:32 point

Interesting - maybe this is the excuse I need to look more closely at PICs.  The only reason I went with Atmel was familiarity with their chips - it would be good to have an excuse to dig into PICs a bit.

Regarding the fault current (into the bases of the PNP transistors): were you referring to the current that charges the gate capacitance of the MOSFETs during a fault?  My thinking was that this current would be limited - indirectly - by the inductors.  I.e. if a fault occurs, the inductors will prevent the drain current (and therefore the voltage across the current-sensing resistor) rising rapidly, giving a smoother transition from "on" to "off".  I admit that I didn't actually check this with a 'scope, though...

Thanks for your comment - it's really great to get feedback on this stuff :)

  Are you sure? yes | no

Matt Bettcher wrote 01/06/2016 at 11:53 point

I'd be very interested in learning about the firmware! I'm working on a small 68020 based computer (admittedly still in the design phase, schematic is only half finished) and am trying to learn everything I can about every interface I will need to implement.

  Are you sure? yes | no

Stuart wrote 01/06/2016 at 17:33 point

In which case I will write down some ramblings about the firmware :)  In the meantime, the source code is all here if you want to take a look -

  Are you sure? yes | no