RetroShield 6809 Operation

2019/03/12

6809 (Sixty-Eight-Oh-Nine)

6809 has a special place in my heart because once you read the specs, you start drooling immediately. I think 6809 is a 16bit transition squeezed into 8bit bus package.

RetroShield project started because I started building myself a more powerful version of Simon6809 (Simon6809 Turbo) but then realized it would be a lot of hassle to deal with discrete logic gates and I/O to add the functionality I wanted to add (i.e. fast storage, sdio, displays, audio, etc.). So the idea of RetroShield was born for the first time for 6809. After that, I built 6502, then Z80 versions. I’m actually going to build a RetroShield for as many 8bit microprocessors as possible so people can experience them :)

Theory of Operation

Lets go over the following to understand how RetroShield works.

Note: I used 6809E (external clock) variant in RetroShield because it is usually cheaper and more available compared to the internal clock oscillator version (6809 without an E). 6809 variant basically works the same way, but it generates clocks E and Q internally using a crystal oscillator and outputs them on two pins, whereas on 6809E we need to generate E and Q ourselves for 6809E.

Arduino to 6809E connections

Arduino Mega is connected to the 6809E as follows. Arduino will drive the E, Q clock signals high <-> low, and during each cycle will look at the R/W signal and the address bus to figure out what to do, and then will either drive data bus or capture data bus to finalize the action. Arduino can also drive the IRQ, FIRQ and NMI signals to cause interrupt handling.

Arduino-to-6809E connections

Arduino ports are mapped to the 6809E signals as follows. GPIO directions must be set accordingly of course.

/* Digital Pin Assignments */
#define DATA_OUT PORTL
#define DATA_IN  PINL
#define ADDR_H   PINC
#define ADDR_L   PINA
#define ADDR     ((unsigned int) (ADDR_H << 8 | ADDR_L))

#define uP_RESET_N  38
#define uP_E        52
#define uP_Q        53
#define uP_RW_N     40
#define uP_FIRQ_N   41
#define uP_IRQ_N    50
#define uP_NMI_N    51
#define uP_GPIO     39

Cycle-by-cycle operation of 6809

6809E uses two clock inputs: E and Q.

6809E timing diagram

Remember, all interesting things happen on clock edges, specifically E clock:

  1. E goes down. Processor drives new address bus and R/W to indicate the type of bu activity (Read or Write).
  2. E goes high, getting ready for data transaction.
  3. Latching of the data by the destination device (uP or memory or IO) happens when the E goes down.
  4. if this was a READ cycle, the IO device needs to drive the data before E goes down (min delay circled 17).
  5. if this was a WRITE cycle, the IO device needs to latch the data when E goes down. Note that data will be ready circled 20 delay after rising edge of Q (a lot of time).
  6. After E goes down, the processor starts the next cycle by outputting the next adddress and R/W signals.

We didn’t talk about Q much, because if you look at the timing diagram, it doesn’t matter much, other than we have to drive it as specified. So we will toggle accordingly to make 6809E happy.

If you plan to modify the Arduino code to add your own device support, it’s good to know the following two concepts:

if these timings are not met, the data latched may be corrupted, which means you will be scratching your head why your code is acting randomly. Having said that, at ~100kHz operating clock frequency, we usually don’t have to worry about such min delaysbut good to know.

Driving clocks E & Q

to run the processor as fast as possible, the code that does low level signal handling is done thru the timer interrupt with no function calls. In summary, the timer interrupt will go thru one bus cycle, driving the clks high and low, as exactly shown in the timing diagram above, Then the interrupt handle will either input or output data bus according to the control/address signals.

Memory Map

The code currently emulates an Simon6809, which for details you should read the Simon6809 project page.

// MEMORY
#define RAM_START   0x0000
#define RAM_END     0x0FFF
#define ROM_START   0xE000
#define ROM_END     0xFFFF
byte RAM[RAM_END-RAM_START+1];


////////////////////////////////////////////////////////////////////
// Monitor Code
////////////////////////////////////////////////////////////////////
// static const unsigned char 
PROGMEM const unsigned char simon09_bin[] = {
    0x1a, 0xff, 0x4f, 0x1f, 0x8b, 0x0f, 0x36, 0x7f, 0x01, 0xa5, 0x10, 0xce, 
    ...
    0x00, 0x09, 0x00, 0x0c, 0x00, 0x0f, 0xe0, 0x00
};

RAM is created by byte RAM[RAM_END-RAM_START+1]. The PROGMEM… makes sure the ROM code is saved in the Arduino’s Flash Memory.

IO device(s)

6809 IO devices are memory mapped, meaning all io devices are mapped in memory and access thru memory read/writes.

Simon6809 used an FTDI USB-UART device to communicate. Arduino code links the emulated FTDI chip to the Arduino UART port. For details of FTDI wiring, you should read the Simon6809 project page.

To emulate any IO device, you need to read thru the datasheet and and figure out the registers and what they do/how. And then add the functionality to the interrupt code. The beauty of software is you can do anything you want :)

Last, since you can use existing arduino shields like display, sdcard, audio, etc. you can memory map them to make them available to 6809.