Or, what did I get myself into?
Recently I’ve gained interest in a lesser-known operating system called OS-9. This isn’t to be confused with System 9 or MacOS 9, but instead is an OS originally created by Microware for the 8-bit 6809 CPU.
The simplest method for running OS-9 these days is to emulate, but for me that removes some of the fun. As for real hardware a Color Computer from Tandy/Radio Shack is the easiest route, however getting my hands on such a machine was cost prohibitive when I started researching solutions. The solution I chose? Build my own. In this article I describe in short the hardware design and the decisions that led to the final design for 6809v2, an actually-6309 single board system.
But first, the result:
The story begins.
6809, the first
In order to learn about the 6809 CPU and how to build for it, I did some research online and found a minimal system designed by a fine gentleman by the name of Grant Searle. His minimal system seemed ideal as it was a tested proven model to work on, and even had a subset of Coco BASIC in its firmware. Upon selecting the design I’d like to build upon it became time to get some hardware.
To E, or not to E. That is the question
When selecting my 6809 I chose the Hitachi variant: the 63c09e. I wasn’t aware of any different requirements between the -E and the non-E versions of the processor at that moment. When initially testing the CPU, I found otherwise.
My initial sanity test was to wire the bus up for $12 (a NOP opcode in 6809-land) and lashed on a crystal oscillator to the crystal input pin on the 6309. Note that I wired it up for the non-E version of the chip. I spent a few hours trying to understand whether the CPU was bad or if I was insufficiently educated.
I do enjoy learning, so I was mightily pleased when the discovery was a lack of education on my part. As it turns out, the non-E version has an internal clock generator, and the -E version requires an external generator. Oh that’s what the E means! External!
The standard 6809 CPU internally generates what’s called a Quadrature Clock. This is two clocks running 90 degrees out of phase, named Q and E. The Q clock is used internally by the processor and the E clock is used to synchronize external devices with the system bus. Below is an illustration of what a quadrature clock looks like relative to the passage of time. I knew then what must be done.
Generating a quadrature clock
There are a handful of solutions to generating a quadrature clock. I chose the route that uses two D flipflops with reset inputs. With the correct feedback it’s simple to make an appropriate generator with the only caveat being that the source clock gets divided by four in the process of generating the Q and E signals needed by the 6809E and similar processors.
Progress, at last
Now that the clocking issue is resolved, and NOP’ing the processor on the breadboard works, it’s time to move to something a bit more advanced. I drafted the Grant’s schematic with my additional clock generator in KiCad and took a crash course in PCB layout. While the layout wasn’t the most efficient in the world it did fit within my chosen board house’s “prototype pcb” limits nicely.
The system above became the target of tinkering for quite some time and did allow some self-education on the system architecture, but it became a bit tedious as the only way to save any progress was to dump it to the tty and log the text output. Moreso was the system’s inability to tokenize BASIC programs fast enough to keep up with the console’s speed, making it impossible to simply paste data into the tty to ‘reload’ previous works. Terminal programs do have delays and limits that can be applied to outgoing text dumps, but a simple copy and paste is far easier than dealing with sending text files via that method. Grant’s notes did include a reasonable method of applying a rudimentary hardware handshake, but it was left out due to a lack of understanding the system’s speed limitations.
On to fixing a few issues: First, the system couldn’t effectively run my target OS due to a few missing capabilities. A recurring interrupt is generally required to provide a multitasking manager with its ability to reassign the processor to tasks that are to be handled. Second, there was no storage on the system to load the OS and its programs from. Less importantly was a lack of memory. While OS-9 can run with 32K of ram it’s quite sub-optimal to use a system with that little memory unless it’s running in an embedded situation to handle a single task.
6809, the second
So, now we have our requirements, and one recommendation in addition. A few other constraints as well, to fit manufacturing and cost limitation.
- 64K of RAM is required to effectively run OS-9
- Bulk non-volatile storage is needed to store the OS and its programs
- A console to communicate with the system
- The design must fit within 10x10cm to stay in the ‘inexpensive’ board category
- The design must remain minimal to ease the engineering and assembly effort
As long as I’m designing the system with some additional features in mind, I added two more requests:
- Two (or more) console ports
- Faster CPU
That considered, I moved on with research for an I/O solution.
Let’s talk IC’s
I had mentally pre-selected my console solution based on some knowledge of an IC often used with the IDE-64 interface card, called the ‘DUART’. The IC turns out to be the MC68681 DUART, which quite conveniently had two serial ports as well as some hardware-assisted handshake capability.
My next trick will be providing a GPIO chip for the system to drive a storage solution with. I did have a desire to stay within the Motorola line for the sake of it, and looked at first at the 6821. It would serve nicely, but I also need a timer interrupt of some sort and my chip list is growing as quickly as PCB space was disappearing.
For those shouting at me, wait for it. Just wait for it. 😉
At this point the design was at three DIP40’s, an unknown RAM array, a ROM, and two RS-232 transceivers. The core logic wasn’t even factored in and the system was starting to look like a dual-PCB solution. Not Good(TM).
In an attempt to avoid slapping a 6522 VIA on the board I took a break from a week’s spare-time research, and did some prototyping with the 68681 I acquired during this research.
Oh, that’s what it’s like to have an epiphany!
Knowing the Grant Searle design had a 16k area of memory that was decoded but not assigned to any IC, I decided to strap up a 68681 to the board to determine the difficulty in programming the device.
Ah, a system only an engineer could love. The ratsnest of wires soldered directly to IC’s leads to a 68681 DUART on the prototyping board, and a smaller ratsnest leads to a MAX232 RS-232 transceiver connected to port one on the DUART. I also used my oscilloscope to detect a toggle on one of the GPIO pins as a sanity test and wrote a short program in BASIC to toggle the GPIO.
Success, on the first try even! In short order I had a simple test program written in basic that would log incoming and outgoing data to the onboard console. Further testing even confirmed that the DUART is well capable of responding fast enough to not worry about the DTACK output and holding the processor long enough for a bus transaction to complete.
So, what’s this epiphany, you ask? Did you see the mention of toggling the GPIO above? Hark! The 68681 has more lines than necessary to operate a directly-connected console. Even better, they can be set and reset in software. There’s even a few -input- lines available, after configuring two console ports with RTS/CTS handshaking.
But wait! There’s more! The real epiphany came when reading the register descriptions. This handy device even has a programmable counter that can be put into free-run mode. My timer! My GPIO! They’re already there!
On with it, then!
The system’s I/O now handled, the RAM array became the next and possibly the most expedient decision in the design process. It’s non-trivial to find a 64Kx8 RAM that doesn’t require a lot of support so a 128Kx8 static RAM was chosen to resolve the 64K-RAM requirement. There was even a couple GPIO’s left, so I send them both to the RAM socket. The design would support a maximum of 256K, banking 64K at a time into view.
The firmware storage was already chosen, a 27c64 8Kx8 EPROM was chosen for that, as the device shares a pinout with the somewhat less-familiar 28c64 EEPROM. An EEPROM is more expensive in most cases, but provides a much shorter development cycle: An EPROM requires 20-30 minutes of UV exposure to erase and prepare it for another programming cycle, while the EEPROM can be erased in about two hundred milliseconds. A vast improvement!
Where do I put it all?
On the PCB, obviously. However, this is more of a discussion on where in the processor’s view things should go. The initial map was pretty straightforward, and only marginally different from the final memory map. The mapping of the GPIO pins didn’t change at all between the pre-production revisions of the design.
The initial map was as follows:
Base End Description 0000 DFFF RAM, bankswitched via GPIO E000 E0FF I/O page, 68681 present in the first $10 bytes E100 FFFF ROM or RAM, controlled via GPIO
This seemed reasonable until I considered the memory layout with the ROM disabled and RAM in its place. Having the I/O page stuck in the middle like that seemed like a poor design decision. Upon researching the Color Computer’s memory map I learned that its IO area is closer to the top. In the end $FF00-FFEF was chosen for the I/O area, with the last 16 bytes at $FFF0-FFFF accessing memory to provide the CPU with its vectors.
The design’s final map is like this:
Base End Description 0000 DFFF RAM, bankswitched via GPIO E000 FEFF ROM or RAM, controlled via GPIO FF00 FFEF I/O page, 68681 present in the first $10 bytes FFF0 FFFF ROM or RAM, controlled via GPIO
A much better layout, allowing contiguous RAM memory to be present from 0 to $FEFF and just enough room for the CPU’s hardware vectors and a bit of scratch memory to possibly handle bank-switching during hardware interrupts. The vectors would need to be copied to all banks of RAM of course, but that’s beyond the scope here.
Mapping the map-ables
The next design consideration is to consider how to control the mapping of memory. To aid in design it’s best to think in binary. Since that’s a lot of ones and zeros (16 of them per word to be exact), a good compromise is to think in a number system that’s closely related. Hexadecimal will provide an address in four digits so that or binary will be used in this section.
TOP8, the designator of Magic
First we should consider the division of memory in the system. All of the magic in the system happens in the top area of memory, from $E000 to the top at $FFFF.
As this involves a lot of one’s in the binary address for the range, an AND gate of some form is generally the best device to consider. The devices in the system generally require an inverted signal to enable them, so a NAND is best. In the 7400-series IC family one of my favorites got chosen for the job: The 74LS10, a 3-wide NAND gate. In simplest terminology, all of its inputs must be high at once for its output to drop low.
Consider the base address in binary format: $E000 becomes %1110 0000 0000 0000. As the three highest address bits are set, the ‘LS10’s triple-input becomes best to detect when the top area of memory is being accessed. The output of this gate will be referred to as ‘TOP8’, to refer to the (decimal) top 8192 bytes of system memory. Since all the magic in the system occurs here, it’ll become the most important signal in the system.
IOPAGE: When we need to access the world
The next consideration is to select memory or I/O. Let’s look at the IO page’s base address, $FF00, in binary: %1111 1111 0000 0000. That’s a lot of ones, and with the TOP8 area, a NAND is best for determining the access of this page. One of my favorites is a near-perfect fit: The 74LS133, a 13-input NAND gate. As with the ‘LS10, all inputs must be high for the output to drop low.
This comes with a caveat however. Assigning A8-15 to the ‘LS133 decodes the I/O page for the entire range of $FF00-$FFFF, denying access to ROM (or RAM) during hardware vector reads. An exception must be made, and a new signal is designed for it.
A second element in the 74LS10 is used to detect any address equal $xxEx or $xxFx by attaching A5, A6, and A7 to its inputs. This is quite a few ranges of memory, but combined with the ‘LS133 above it can be limited to disabling the IO page only for $FFE0-FFFF. A slight difference in the intended memory map, but a worthy sacrifice to minimize the logic design in the system. A bonus is the gain of 16 more bytes above the I/O space to enlarge the minuscule dispatch code area above the I/O range. The output is named ‘EF’ for the two digits it will match.
How do we connect this? It’s sent into the 74LS133 to force it to de-assert whenever any of these ranges are addressed on the bus. The final memory zone this section of the circuit will address is $FF00-FFDF, named ‘IOPAGE’.
As the only device intended for this range is the 68681 DUART, its select input is directly connected to the ‘IOPAGE’ signal.
Reading the bootstrap firmware
In order to start the system, the ROM must be readable when it comes out of reset during power-up. As the ROM occupies the memory range from $E000-FFFF, it will conflict with the IO page described above. This will be covered shortly. First, lets work out how to turn the ROM on when it’s accessed.
There are two general signals needed, one of which is newly named: ‘ROMON’. ROMON is an active-high signal that comes from the DUART’s GPIO port. It’s intended to allow software to disable the system firmware and place its own code in the RAM area it would otherwise occupy. The other signal, ‘TOP8’ described above, will be combined to provide the first of the two ROM enable inputs.
A challenge here is the optimization requirement for the system- to keep the IC count to a minimum. The TOP8 signal’s polarity isn’t suitable for the combination with ROMON, so it gets inverted by a 2-input NAND gate, a 74LS00. It’s then combined by a second 2-input NAND gate with the ROMON signal. Its output is named ‘ROMCS’. The EPROM’s CS line is chosen here to put the device in standby mode and reduce power usage while the ROM is turned off in software.
The next challenge is to ensure the ROM is disabled when the IO page is being accessed. In a method similar to the combination of ROMON and TOP8 above, the inverted TOP8 signal is used again with a third element of the 74LS00 to enable access to the ROM whenever the IO page is -not- being accessed. Its output is named ‘ROMOE’, and connected to the EPROM’s OE signal. With that, the ROM is properly decoded.
So, we’re done, right? Right??
We’re not quite done. It’s easy to say ‘and the rest is RAM,’ but that’s not all that easy, especially when we’ll be optionally overlaying an area with the EPROM’s data. The IO page’s mapping is fixed and always present so it should also be considered.
Conveniently we already have two signals to disable the RAM device: IOPAGE and ROMCS. Unfortunately the polarity of both are incorrect for our needs. They’ll both need inversion to suit the need of RAM selection. This will be handled by the two remaining NAND gates: IOPAGE is inverted by the remaining 2-input NAND gate, and ROMCS is inverted by the remaining 3-input NAND gate. These are combined by the most frustrating decision in the design: Adding a single OR gate, a 74LS32 to combine them. The resulting signal is named ‘RAMOE’, and connected to the RAM’s OE signal. With this, the RAM’s output is enabled except when ROM is enabled for $E000-FFFF, and when the IO page is accessed.
Sadly, the other three gates in the 74LS32 are unused. (Queue sad music and slow fade)
A feature designed into the system is the ability to write to the RAM, even for the memory area of $E000-FFFF while the EPROM is enabled. This permits the preloading of RAM data before the system firmware is turned off to help avoid crashes in the event of an unexpected interrupt when configuring the system to run an OS. To do this, the RAM’s WE signal is tied directly to the R/W signal from the processor. This will cause the RAM to also receive writes sent to the IO page, but as that area cannot be read by the processor, the data can be considered voided and non-impactful during normal operation. As the input is directly connected to R/W, it doesn’t have a special name.
The RAM’s requirement to be always written to makes it necessary to select it on every CPU cycle. Therefore, the CS input will always be enabled by the system clock. As the E clock’s polarity isn’t suitable for this input, the inverted signal is borrowed from the intermediate stage of the clock generator.
But what about the rest?
As for the software considerations, they’ll be covered in another article. The last few hardware details are below.
The system’s speed was ultimately set to 3.6864MHz. This was done to reduce the device count on the board, driving the system with a 14.756MHz crystal. The CPU’s clock is the same as that required by the DUART, so those familiar with RS-232 designs may recognize this frequency.
The GPIO’s are mapped to a few different devices as shown below:
Pin Connection IP0 CTS for port 1 IP1 CTS for port 2 IP2 DCD for port 1 (not routed) IP3 DCD for port 2 (not routed) IP4 Unassigned IP5 SD-Card Data Input OP0 RTS for port 1 OP1 RTS for port 2 OP2 RAM A16 OP3 RAM A17 OP4 ROMON OP5 SD-Card Clock Output OP6 SD-Card Data Output OP7 SD-Card Select Output
The outputs on the 68681 are all inverted, so when reset by the system reset line, they all are set to high output. This is a handy feature, as the ROMON signal needs to be high to enable the EPROM, and the SD-Card is de-selected upon reset.
As noted above, system software will be covered in an additional article.
Finding more information [ammendment]
On initially publishing this article, I made the ingenious decision to leave out an important link. The design files and current source code state are available on my github repository: https://github.com/jbevren/6809v2
I do invite others to use the information there, and even have their own boards made if they wish. All I want is credit for the original design.
Ascend the soap box
The design is open and free (with credit given, that is) because I feel the 8-bit community is not large enough to hold secrets and the animosity that comes from attempting to keep them so. At this stage in the community and its associated hobbies, an open and sharing attitude is best for welcoming newcomers- many of which I’ve met that barely know the names and machines we grew up and still have incredible enthusiasm in our aging technologies and the challenges and fun they offer.
If anyone- young or not- is curious about these hobbies, help them learn and encourage them to continue learning on their own. It’s a part of history that shouldn’t be lost, as automated computation and data processing is taken for granted by many people and its origin should never be forgotten.
Descend the soap box
Thanks for reading everyone! 🙂