Simplest possible I/O for Homebrew 8-bit CPU

I am working on designing an 8 bit cpu as a personal project for no real reason. I am using mostly 74HC series chips and am generally focusing on ease of programming over performance.

I am using various projects on the internet as inspiration, and I feel I have a pretty good grasp on how the basics will work, including the alu, registers, and the basic memory path.

The one thing I don't have a clue about is Input and output. I am not really interested in anything super fancy, like tcp/ip or uarts, but I would like to have a keyboard and a basic text output to a monitor of some kind. I really have no idea what hardware to use, or what instructions to make to use it.

I could squeeze a few more specialized instructions out of my ISA to access specialized hardware, but if I could do it all with some kind of memory mapping scheme that could be even better. I am planning on using a 64K ram chip, but maybe certain addresses could get diverted to other hardware or something.

I don't really want to implement interrupts, but I don't want to lose keyboard data either. Does that means I need some kind of queuing buffer chip for my keyboard? I don't even know where to start looking for a video chip, or how I would interface with it.

Any tips would be greatly appreciated. Again, I don't need anything fancy, a simple getChar and putChar would suffice. Pixel level control of graphics could be cool, but not absolutely required. I think I just need to be pointed in the right direction.

• how about RS232 and a terminal window to your PC? – kenny Jul 23 '11 at 11:59
• to expand what i think maybe @kenny might have been driving at - it would be much easier to use a UART instead of trying for keyboard and video. You'll need something like 16 bits of parallel I/O to deal with a keyboard, and video will require lots of finicky timing as well as at least 1K or 2K of video buffer, as compared to maybe 2 registers to map something like a 6851/6551 UART (if you can scrounge one up) – JustJeff Jul 23 '11 at 14:49

The "simplest possible I/O" depends on what your I/O requirements are. It would be very simple, if you're in control of the CPU design, to implement a couple of special instructions to input and output a few bits of parallel I/O.

But since you mention keyboard and video, it seems that your requirement is to be able to interact with your system that way - and the dead simplest way to do that is to incorporate a fixed baud-rate serial port, and use a PC & terminal program to supply the keyboard and video. Using 9600 bps is fine for human console purposes, or if you expect to transfer binary, 115200 could handle 64K bytes in around 6 seconds.

An off-the-shelf UART chip like the 6850 or 8250 (well, out of the junk-box anyway) will need only 2 to 8 registers for a complete stdin/stdout solution. This is a tiny footprint compared to trying to implement a keyboard and video interface directly. You can probably drive a keyboard matrix with just a single 8-bit output port and a single 8-bit input port, but video will need 2K addresses just to supply the frame buffer for an 80x25 character display. If you consider so-called LSI solutions like the 8250 to be cheating, I would counter that constructing a UART from 74xx would probably be easier than constructing a video generator from the same technology.

That said, the down-side of the UART is that you are likely to lose input unless you either (a) poll it frequently enough, or (b) implement interrupts. For a simple proof-of-concept for your CPU, just polling should suffice - unless you're also trying to prove out interrupt capabilities of your CPU (if/when it has them), in which case, keeping up with serial input by using UART interrupts would be a fine test case.

• I'm not really worried about cheating on the I/O side of this. I mostly want to focus on the cpu design, not on input/ output. Maybe I will cheat and put an arduino in there and make opcodes to input and output one byte at a time. Kinda defeats the purpose of building a cpu when I use a superior one for IO, but thats not really the point either. – captncraig Jul 24 '11 at 14:00
• @CMP - you mean, use the arduino to go from 8 parallel I/O bits to serial (rs232) to the PC/terminal combo? That could work - though you'd need a couple of extra bits to handshake to the arduino, unless you want it to continuously transmit whatever byte you present to it - and receiving would definitely need handshake bits. Cool idea though, as those old UART/comm adapter chips can be hard to come by. – JustJeff Jul 24 '11 at 16:13
• Pretty much set a pin high on arduino to tell it to process input, or cycle the output. If I put it high for one of my cycles, the arduino should be enough faster that it can take care of the byte within that cycle. – captncraig Jul 25 '11 at 3:28
• @CMP - thing is, if the arduino is enough faster than your CPU, and comes back and checks that pin again before your CPU can clear it, you could end up sending duplicate characters. But if you make the arduino watch for low-to-high transitions (or the other way, your choice) rather than just a level, that should sort that problem. – JustJeff Jul 25 '11 at 23:30
• Good point. Luckily there's a good debouncer library that can detect changes fairly accurately. – captncraig Jul 26 '11 at 17:04

Apart from standard parallel I/O ports you'll definitely want serial I/O, like U(S)ART, as well. We'll need it in a minute.

Input
For the input I would build an interface for a common PC keyboard (the so called PS/2). This uses a synchronous serial protocol; that's what you'll need the serial interface for. That means SIPO (Serial In/Parallel Out) and PISO (Parallel In/Serial Out). A synchronous protocol like the PS/2 keyboard's has the advantage that there's also a clock signal, which makes the conversion easier than for instance a UART. (You'll soon want a UART too)

Display
Most of the TRS-80 home computer was, apart from CPU (Z80) and memory, built with TTL ICs, including the 16 lines x 64 characters video, so the schematics may help you to get started.
But this may already be a big step, and I would start with something simpler, so that you can focus on the CPU, which most likely will need some debugging before it works properly. And it would be nice to have something of a display for that. (You don't want to debug the CPU and the video logic at the same time. Take one step at a time.)
I would suggest to use a common 4x20 character LCD (bigger is OK too). This is easy to interface and can display already a lot of (debug) information.
Another option is that you create a UART interface. It's standard on most microcontrollers and you'll need it sooner or later anyway. The UART will allow you to connect to a PC, and with a simple protocol you can use the PC's display to show a virtual display of your own computer in a window.

Interrupts
Mike comments that interrupts aren't that hard to implement, but I think it's a good idea to leave them out for the moment. They do add a level of complexity, and a risk of instability (more on a software than a hardware level); safety-critical microprocessors usually don't have interrupts. I recall the old Viper, which was used in fighter planes.
To make sure you don't lose incoming data you'll have to buffer it. The usual solution is a FIFO. This one is a building block from the 74HC series, so you can simply use that, or you can roll your own. (I don't know what your make or buy criteria are.)

TRS-80 Technical Manual

• Thoughts: - Original Z8 video. - DMA – Russell McMahon Jul 23 '11 at 5:47

I/O mapping

"Some memory mapping scheme" is pretty much the definition of memory-mapped I/O.

Try the Commodore 64 trick: peripherals share memory space with RAM, and any address not taken by a peripheral goes to RAM.

Or the Intel x86 trick: I/O gets its own address space separate from RAM. This makes using pointers with peripherals much more difficult.

Peripherals in general have just enough address pins to address their registers, a chip select (CS) pin that says when it is selected, and either a Read/Write pin or a pair of Read Enable and Write Enable pins.

Framebuffer

The simplest way to generate a video signal is to make a circuit that reads consecutive addresses from RAM and converts them into a video signal. Just how you generate the signal depends on what signal you want to generate (NTSC, CGA, VGA, LVDS, etc.) If you run the CPU slow enough, you could have the CPU access RAM on one half of a clock cycle and then let the framebuffer read RAM on the other half cycle (the Commodore 64 did this). Alternatively, if your memory bus handles wait states, you could give the framebuffer priority access to RAM.

The upside of this framebuffer is that it's easy to implement and easy to write for. The downside is that it takes a lot of RAM and pushes text generation onto the CPU (but it lets you do variable width and height fonts, too).

The sad thing is that you'll be pretty much on your own here; the market for this kind of low-level video chip is pretty much nonexistent these days. Remember, though, that the Apple II did its video generation in discrete components without a dedicated chip, so you can too. ^_-

Interrupts

Interrupts shouldn't be that hard to implement: If an interrupt line is driven, and interrupts are globally enabled, and that particular interrupt is not disabled, then push the PC onto the stack (just like for a subroutine call), and finally either load a new PC value from an address depending on interrupt number (the vector table method), or just set the PC to a fixed value depending on the interrupt number, expecting a GOTO at that address to get the processor where it needs to go (the jump table method).

Keyboard Interface

Stevenvh posted his answer when I was about half done with mine, so I'll second the recommendation to use the PS/2 interface. One interesting thing to note is that the PS/2 interface can be made hot-swap, and can autodetect whether a keyboard or mouse is plugged in. These features never made it onto motherboards because nobody wanted to pay the extra \$ or rewrite their drivers to support it, but I've done it in an FPGA, so you can, too.

The trick is, though, that the PS/2 interface is two-way, so you'll probably want to use an interrupt-based serial port design to interface to it. You could use chips called FIFOs (Cypress makes a lot of them) to loosen latency requirements; you'll need one going each way.

• I think you'll find that the C64 video generator suspended the CPU and used DMA to suck in 40 bytes on every 8th scan line during the active raster, which was why if you really wanted to get cycle-accurate timing you had to (ugh) turn off the video raster, or wait and do it during vertical retrace. But your point about interleaved video/CPU access is nonetheless a feasible one. – JustJeff Jul 23 '11 at 15:19
• Da, that's right. I must have been thinking of something else, maybe the TRS-80 color computer (MC6809 CPU and MC6847 video chip with another chip to manage DRAM, whose number escapes me). – Mike DeSimone Jul 23 '11 at 23:44
• yeah, that system did interleaved video that way, using the "synchronous address multiplexer" AKA "SAM" chip, the Motorola 6883. (Man I wish I could repurpose those synapses for something else) – JustJeff Jul 24 '11 at 0:44
• That's the one! Thanks! And good luck with the neurons; I still remember SYS 64738 (reboots a C64), which is totally useless to me. And the funky C64 memory map, with its self-modifying code line editor. – Mike DeSimone Jul 24 '11 at 3:21

If you have a reasonably fast CPU, the circuitry will be simplest if you let the CPU do a significant portion of the work generating it. As a simplest case, suppose that your objective is 40-column video, your processor runs one million 16-bit instructions per second from RAM, using timings derived from an 8MHz clock, and you don't mind being unable to do anything else while generating video. In that case, you could have an I/O bit serve as a master video enable, and three more as a sub-row select, and then arrange things so that whenever an instruction is fetched from an address where bit 6 is high, the bottom 8 bits of the fetched instruction will be fed into a 2Kx8 ROM along with the three bits of sub-row select; the output of that will feed a 74HC165 to clock out pixels. To display video, arrange to fetch groups of 40 instructions where the LSB of each instruction is a byte of display data. Such an approach would totally hog the CPU, but require extremely little hardware.

A slightly nicer approach would be to add a couple counters, triggering an interrupt either once per line or frame. The CPU would be unable to do anything during the visible part of the frame, but wouldn't have to lose sync every time it decided to do something other than show video.

Incidentally, it may be easier to use LCD than video. An LCD that has a controller built in will probably be most convenient, but even one that only has drivers may be somewhat easier than video, since timings are apt to be a bit more forgiving.

I'll make this an answer rather than a comment as material presents better.

Brain fade - I meant Sinclair ZX80 ! :-(. Video in hardware using Z80 cpu DMA I think

Sinclair ZX80 circuit diagram here