Close
0%
0%

6809/6309 Eurocard CPU System

A retrosystem based on the elegant 8/16 bit 6809 processor capable of running UniFLEX and OS9 level II multiuser/multitasking OS

Similar projects worth following
For those that would like to play with an nice 8-bit CPU from the late 1970's featuring a rich environment with memory management unit, DMA (memory-IO and memory-memory), Realtime Clock, IDE interface, CompactFlash and SD card interface. RAM disk, 4-port serial, video, ethernet.

Although some of the components used are no longer manufactured there seems to be plenty of 'old new stock' available through the various marketplaces online.

The system design philosophy was to create an eurocard based system with DIN41612 connectors which was very popular in the 1980s in Europe to create systems. Commercial systems at the time where Gespac, PEP Modular Computers, EuroCUBE Celeste and Eltec. The Elektor magazine also published an Eurocard system running FLEX (EC68). There were also many systems developed by hobbyists and I got inspired by the nice UniFLEX system developed by Kees Schoenmakers (https://github.com/kees1948/UniFLEX).

I focused on using only 5V logic but avoided the usual forest of TTL chips and a PAL/GAL solution for the glue logic. Instead I used two 5V CPLD devices which are fast, cheap and can hold a lot of logic allowing one to add some nice features to the system such as fast memory to memory DMA but also esoteric ones like a hardware CRC calculation of OS9 modules. In the File Section I have placed Python code that highlights how to create the CRC calculation in hardware.  I used it during testing of the Verilog code. With in-circuit (re)programming system development & testing is quick without having to remove devices from the PCB.

Source code for both UniFLEX and OS9 level II is available, something we could only dream about having in the 1980s since both hardware and software were rather expensive. Full details will be made available through my Codeberg GIT.

The system closely matches the CMS9639 from the 1980s which was similar to the GIMIX III board. Thanks to the SARDIS technology website (https://sardis-technologies.com/oth6809/cms.htm) there is a lot of information on these nice systems.

The addition of a dedicated ethernet interface offers opportunities not available in the 1980s.

The CPU board is the heart of the system and combines CPU with 1Mbyte memory, (EP)(EE)ROM, console port, ethernet, MMU. Thanks to a EPF10k20 CPLD which is positioned between the CPU and the rest of the system many functions can be integrated. For example, the MMU can hold 128 tasks simultaneous and each task will have the full 64k address space. Tasks are autoswitching and the dual channel DMA controller addresses memory through dedicated tasks. The detailed MMU maps are kept in a 2kbyte dual-port RAM memory which is also on the CPU board. Block (page) size chosen is 4kbyte. To have the full 64kbyte for each task requires automatic switching of tasks on interrupts and returning from interrupts. The dedicated Motorola MMU (MC6829) uses a fuse register to switch tasks. Using the 6809E we can easily work out when the first byte of an opcode is present on the database using the LIC pin and by looking for the opcode for RTI, we know when to switch when returning to a user task. Switching to a system task is easier since one can detect the occurrence of an interrupt by encoding the CPU BA & BS signals.

For a working system, however, the addition of the IDE board is advised as it allows connecting 2 SD cards, CF cards and upto 4 hard disks. All transactions can be done through either software IO or DMA. Since the 6809 is HALTed during the DMA operation (burst DMA) we can conduct transfers much faster than the 1 or 2MHz of the 6809 clocks (during DMA the E and Q clock continue as normal). The DMA controller uses a 16MHz clock (8Mbytes/s) such as to not exceed the speed of the CF cards that I have.  The above shown logic analyser traces show the onset of a DMA read of a IDE device. 

Extra serial ports are added through inclusion of a 4-port 6850 board that provides integrated serial to USB C converters with an option for mini USB.

No retro system is complete without a RAM disk and this system has one that is upto 4Mbytes large using a very small 4-byte memory interface  using high-speed DMA transfers or programmed IO.

A video board with VGA output and USB keyboard & mouse is...

Read more »

myIDEdrv_IRQ_suspend.asm

RBF IDE disk driver that uses the Suspend state whilst waiting for data to become available from disk. Once available burst DMA is used to transfer data to memory. This is the one that should be used. The other two are provided for info only.

plain - 7.97 kB - 04/09/2026 at 12:42

Download

myIDEdrv_IRQ.asm

RBF IDE disk driver sleeping while waiting for data ready from IDE releasing CPU

plain - 7.44 kB - 04/08/2026 at 09:39

Download

myIDEdrv.asm

RBF IDE disk driver w/o sleep hogging CPU during data ready waiting

plain - 6.08 kB - 04/08/2026 at 09:37

Download

myClock.asm

OS9 Clock module source code

plain - 4.47 kB - 04/02/2026 at 12:20

Download

myBoot_PIO.asm

Source code for Boot module, which resides together with OS9p1, in EPROM. This module loads the OS9boot file from disk. Note that I have assumed the use of a 6309 CPU which has the TFM instruction for moving data fast. I should really change this to have optional compilation with a 6809/6309 flag ...

plain - 5.29 kB - 03/26/2026 at 11:15

Download

View all 11 files

  • OS-9 DMA disk driver details 2

    roelof46 days ago 0 comments

    As mentioned in the earlier log on the DMA disk driver, I have now written a RBF driver that sleeps during the phase after issuing a read/write command to the IDE disk controller and uses interrupts to wake up for the DMA transfer phase releasing the intervening time for other processes. There is no clash with other processes that want to use the DMA controller because it is only setup for data transfer during the actual data transfer phase, not when the IDE command is issued.

    During the debugging I noticed an error stemming from the original driver (which is also updated) in that I tried to check the type of disk before it was defined... The verilog code for the IDE interface board was updated to provide the required interrupt signal and its associated status bit.

    Both versions of this RBF driver are uploaded in source form.

    Whilst going through the motions of updating the driver I noticed that the Programmer's Manual hints that since OS-9 level 2 version 1.2 (which is covered by the rev. H of the manual) a new SUSPEND state would improve the RBF even further since it does away with the wake up signalling ( section 5.3.2 page 5-11). For an electronic copy of the manual look at my CodeBerg repository under OS-9 documents.

    So I have revised my IDE RBF driver using this new feature. So now there are three versions of the IDE RBF driver available. Obviously the latest: myIDEdrv_IRQ_Suspend.asm is the one to go for since it has all the features available that were discussed. The other two work and have been provided for those that would like to see the changes between them.

  • OS9 Clock Module

    roelof404/02/2026 at 12:00 0 comments

    The OS9 Clock module is an interesting one. In the OS9 hierachy diagram it sits together with Init at the same level as the OS9 kernel (OS9p1 & OS9p2).

    The Clock module takes care of initialising the clock which is a 100Hz oscillator driven signal which, in our case, is connected to the onboard MC6821 (PIA). The PIA also provides a TimerEnable signal which is used to stop the 100Hz clock if it is logical '1'.

    Also the Clock module provides seconds,minutes, hours, etc. registration based on the 'ticks' coming in from the 100Hz clock. This is done through generating interrupts by the PIA.

    There is no direct start of the clock by the operating system. In fact the F$Time system call is only available when the Clock module is called using the Setime command which also starts the Clock.

    Below a snippet showing how the PIA is setup and the clock is started by setting the TimerEnable signal low '0'. By default the TimerEnable is '1' due to a pullup resistor.

    *****
    *
    *  CLOCK INITIALIZATION ENTRY
    *
    ClkEnt pshs cc
     lda #TickSec get ticks per second
     sta D.Tick
     lda #TickSec/10 set ticks/time slice
     sta D.TSlice
     sta D.Slice
     leax CLKSRV,pcr GET SERVICE ROUTINE
     stx D.IRQ SET INTERRUPT VECTOR
     
    * PIA initialisation goes here
     ldx CLKPRT,pcr get PIA address
     orcc #IntMasks set interrupt masks
     clra
     sta 1,x clr control register
     lda #%00000001 PIA port A bit0 output, rest input
     sta ,x set data direction register
     lda #5 select pheripheral register & CRA1 interrupt enable, high to low
     sta 1,x set control register
     clra
     sta ,x clear bit 0 which enables 100Hz clock
     lda ,x clear any current interrupts
     
     puls cc restore interrupt masks
     leay TIMSVC,PCR
     OS9 F$SSvc SET TIME SERVICE ROUTINE
     
    ClkEnt3 rts

    Full Clock source code is attached.

    Note: it is assumed that PIA A-side pins other than 'pin 0' are inputs. That is true (see schematic) for 'pin 4' or PA4 which is connected to the clock but not necessarily for the other pins. Currently these pins have no meaningfull purpose but one could consider using these and then the above PIA A-side initialisation needs to change.

  • CMS9639 specific changes OS9p1

    roelof404/02/2026 at 11:29 0 comments

    This first part of the OS-9 level 2 kernel (OS9p1) provides essential system calls that make up the operating system allowing proper task administration, memory management, etc.

    Comparing the OS9p1 used for the CMS9639 with standard OS9p1 code it is clear that there are three low-level functions that have changed. All three are involved with moving data between tasks and in the case of the CMS9639 the memory-to-memory DMA facility is used even if there is only one byte to be moved.

    Here, we don't consider changes in setting up/checking memory and the Data Address Translator (DAT, key part of the MMU) initialisation since these would be different for any system.

    The changes are found in the code for Mover(00)/MoveRegs, PutRegs and STABX/LDABX (using source code labels). Below the difference between standard and CMS9639 is shown for PutRegs, which copies registers between tasks.

    Below we compare PutRegs:

    CMS9639:

    ************************************************************
    *
    * Subroutine PutRegs
    *
    * Copy User interrupt register stack
    *
    * Input: X = Process Descriptor ptr
    * U = local stack ptr
    *
    * Output: none
    *
    * Data: none
    *
    * Calls: uses DMA to copy register stack
    *
    PutRegs ldb P$Task,X get process task
     andb #^SysTask
     clra
     pshs u,x,cc
     ldx P$SP,X get process stack ptr
     exg x,u switch source & destination
    PutReg.A equ *
     orcc #IntMasks
     sta >Tsk.Src Task to copy from
     stx >$FFC0 DMAC source address register
     stu >$FFC4 DMAC destination address register
     ldx #R$Size
     stx >$FFC2 DMAC Source byte count register
     stx >$FFC6 DMAC Destination byte count register
     stb >Tsk.Dst Task to copy to
     ldb #$03
     stb >ContrlSW send command
     nop
     puls pc,u,x,cc

    Standard: 

    ************************************************************
    *
    *     Subroutine PutRegs
    *
    *   Copy User interrupt register stack
    *
    * Input: X = Process Descriptor ptr
    *        U = local stack ptr
    *
    * Output: none
    *
    * Data: none
    *
    * Calls: MoveRegs
    *
    PutRegs ldb P$Task,x get process task
     lda D.SysTsk get system stack
     pshs u,y,x,DP,D,CC save registers
     ldx P$SP,x get process stack ptr
     exg x,u switch source & destination
    PutReg.A equ *
     ldy #R$Size/2 get double byte count
     tfr B,DP copy process task
     orcc #IntMasks set interrupt masks
     lbra MoveRegs 
    Mover10 lda 1,s get source task number
     orcc #IntMasks set interrupt masks
    MoveRegs sta DAT.Task set source task
     ldd ,x++ get data double byte
     exg b,dp switch data & task
     stb DAT.Task
     exg b,dp switch back
     std ,u++
    Mover30 lda #SysTask get system task
     sta DAT.Task set system task
     lda 0,s get previous masks
     tfr a,cc reset interrupt masks
     leay -1,y count double byte
     bne Mover10 branch if more
     puls pc,u,y,x,dp,d,cc

    The DMA version essentially uploads source and destination information and moves bytes during DMA just after 3 is written to the ControlSwitch (ARM DMA). Task switching is automatic between source and destination.

    For the standard case there is changing of task needed for every (double)byte. R$Size is the number of bytes to move.

    Apart from the data moving routines there is one further CMS9639 specific change that is at the heart of system calls. System calls use a SWI2 software interrupt followed by a PostByte which indicates what system call is to be performed. Normally software collects the PostByte from user space and increments the program counter to skip the PostByte upon return. The CMS9639 has a dedicated circuit that captures the PostByte and places it in memory location $FFFA0. It also increments the program counter before placing it on the stack.

    In the snippet from OS9p1 this process can be found in detail for both cases using conditional assembly:

    ************************************************************
    *
    * System Service Request Routine
    *
    * Process system service requests
    *
    * Input: S = value of stack after interrupt
    *
    * Output: none
    *
    * Data: D.SysDis, D.SysPrc
    *
    * Calls: Dispatch, SysRet
    *
    SysSvc leau 0,s get registers ptr
     ifeq CPUType-CMS9639
     ldb Postbyte...
    Read more »

  • RAM disk

    roelof403/29/2026 at 15:37 0 comments

    With available (and affordable) memory quickly passing the 64kbyte mark many people employed extra RAM in their system during the 1980s in order to create quick access disk storage. Within OS-9 it is very simple to define extra drives with bespoke drivers to integrate these into the operating system.

    Often the access would be memory mapped access through a window of varying size with 1-4kbytes as a common option. Using bank switching this window would cover the full extent of the available RAM disk size.

    I have designed the RAM disk for the CS09 system in a different way because I would like to keep the number of memory locations for I/O to a minimum. This method is much like normal disk access via a dedicated controller. There are only four bytes mapped into the CPU's address space through which all data transfer happens. Besides a data register there are 2 registers (16-bits) that set the Logical Sector Number of the sector to be accessed and a further command/status register. That's it.

    Internally, the RAM disk logic has an 8-bit counter which auto increments whenever a read or write to the data register is performed. Together with the 16-bit LSN there is room for 2^24 bytes (16Mbyte) on the RAM disk. There is an option for using a 9-bit internal counter for use with UniFLEX which uses sectors of 512-bytes.

    Access to the disk would require uploading of the LSN number of the sector followed by 256 reads/writes from/to the data register. The internal 8-bit counter get cleared automatically after any change of the LSN registers. Through the command register the disk can be write-protected.

    Using one of the two DMA engines on the CPU board all data transfers are really fast.

    RAM disk memory is low-power CMOS and the memory chips have backup batteries so that the RAM disk contents is non-volatile.

  • Floppy disk controllers

    roelof403/27/2026 at 12:35 0 comments

    During the 1980's the Western Digital floppy controllers were abundant. Starting with the 179x series and 279x ones after that. There were also more compact solutions like the 177x series which were popular due to the low supporting chip count. Like many I used all of these and learned to live with them. Especially the requirement to not poll their status too quickly was a nuisance. 

    With that in mind I made two different designs of the IDE interface. One with a WD2793 and one with a newer WD37C65 device. The latter one is a NEC uP765 like interface plus some extra support so that it is a one chip solution. Both should allow reading of both 8" and 5.25" disks but the WD37C65 goes further (3" extra density) so an interesting option to explore. A 3D KiCAD representation of the WD37C65 version is uploaded to the picture gallery.

    I have an old Siemens 8" drive which is well preserved and some original TSC FLEX OS 8" floppies (!) and it will be fun to see if I can read these eventually.

    OS-9 drivers for the WD279x are around and should be easy to adapt. However, for a multi-tasking system these can be a drag since byte don't come out as a stream of bytes that can be transferred as a burst DMA. Instead people have used 'cycle stealing' DMA something which requires some overhead in managing.

    So during design time I thought of a way to buffer the bytes from/to floppy drives sector by sector. Hence by keeping a 256-byte buffer between the CPU and the floppy drive, the sequence of writing/reading to/from floppy drives becomes much like interfacing to IDE disks and we can employ burst DMA transfer of data.

    There is still the issue of how to deal with disk formatting which requires more than 256-bytes but it should be simple to create a bypass to the sector buffer and handle these the 'old way'.

  • OS-9 DMA disk driver details

    roelof403/26/2026 at 10:37 0 comments

    As mentioned I use an IDE (PATA) type interface to connect to storage devices like hard disks or Compact Flash cards. There are several adapters for CompactFlash cards that plug into IDE connectors to make that easy.

    Currently the Boot loader module that resides in EPROM reads the disk using Programmed Input/Ouput or in other words data is transferred not using DMA but simply by programmatically reading byte for byte. This allows the code to be very compact and since that is the only task running has little downside.

    The IDEdrv RBF driver is using DMA to quickly load sectors of data to memory. Since we are using burst DMA (during which the processor is HALTed) no other task is running. However, there is a significant delay between issuing a read sector by DMA command and the onset of the DMA transfer. The delay depends on the drive used. For the CompactFlash card that I use (Scandisk Ultra II) this delay is 0.28ms much longer than the actual DMA transfer of 256bytes (which is several tens of microseconds). Currently the driver simply polls the DataReady bit during these 0.28ms then the CPU is HALTed once data is ready. So no interrupts are involved at this stage.

    It would be better to issue the read sector command go to sleep so other tasks can run and use an interrupt when done. But it is a bit more complicated than that. Because the DMA controller needs to be setup before the transfer we can't do this at the time of issuing the read sector command. That is because the same DMA controller is used for other tasks (such as moving data between tasks by OS-9 system calls). So one would have to issue the sector read command without setting up the DMA registers, go to sleep and wake up when data is ready as signalled by the IDE disk. Then load the DMA registers and acknowledge the DMA transfer. That way there is no clash between DMA users and other tasks can use the 0.28ms of waiting for data from the disk for useful operations.

    Although IDE devices have a dedicated Interrupt request line, this line is toggled only at the end of the DMA transfer which is not what we want because the driver will release the CPU directly after the DMA transfer. In our case we would like an interrupt signal directly before the IDE disk is ready to do the DMA transfer so we can quickly upload the DMA registers and allow the transfer to happen. Plan is to use the DMA request signal to trigger the interrupt request and toggle the DMA acknowledge line to the IDE disk once the DMA registers are loaded and the DMA is armed. Just like the CPU board, the IDE interface is built around a complex logic circuit and details of signalling can be adjusted easily through changes in the verilog code.

    Details of putting read/write disk to sleep and how to wake them up are described in the OS-9 programmers manual (pages 6-15 and 6-16) and the interrupt service routine on page 6-19. I have revision H (January 1984) of the manual.

    I had a look around to see how legacy drivers handle this and unfortuately I haven't found many such disk drivers around. There is the GIMIX G68 driver but that is centred on doing 'cycle stealing' DMA as far as I can see. It does show how the Sleep and Busy and Wakeup signalling is done. It also introduces a system variable that indicates if the DMA device is 'in use' or 'free'.

    For those interested in the code I have attached the source code for the Boot module and the current IDEdrv RBF device driver (still working out how to setup the CodeBerg repository ...).

  • Development System

    roelof403/15/2026 at 19:19 0 comments

    During the development stage there is a requirement to convert 6809/6309 assembly into binary OS9 modules. Thankfully OS9 is well structured and the number of modules needing changes is relatively small. Apart from the bootloader and kernel modules there are also driver modules for serial ports and disks that need changing or writing from scratch. To do so I use the Virtual Color Computer (VCC) emulator on a Windows system (https://github.com/VCCE/VCC).  It is provided in both source form and binaries. It can also be run on Linux platforms.

    The emulator allows you to hook up 4 virtual floppy disks and 2 virtual hard disks. I've installed the NitrOS9 operating system which has lots of nice code with it including a modified assembler that will generate 6309 code. Just what I needed to create a set of adapted OS9 modules from existing source code.

    VCC works with disk files (.dsk) for floppy or (.vhd) for hard disks. Files can be extracted or inserted into these virtual disks by using Toolshed (https://github.com/nitros9project/toolshed). You can also create blank virtual disk files using this tool. Alternatively there is a  Windows tool called Floppymaintenance (http://flexusergroup.com/swtpc/Downloads.htm). The latter option uses a nice looking GUI but I have had issues using it.

    If you are looking for a crosscompiler that can create OS9 modules from source then LWTOOLS is recommended (https://www.lwtools.ca/).

    Details of setting up  NitrOS9 can be found online (https://lcurtisboyle.com/nitros9/nitros9_docs.html). A quick online search will feature some guided youTube videos as well.

    In fact NitrOS9 is a further development of OS9 developed and maintained by the Color Computer community and has many upgrades. It would be a logical next step to adapt it.

  • Booting OS9 level 2

    roelof403/15/2026 at 18:53 0 comments

    Source code for the first part of the OS9 kernel (OS9p1) adapted for the CMS9639 is published on GitHUB (https://github.com/sorenroug/osnine-java/tree/master/os9software/cms9639). The binary file is available at https://www.sardis-technologies.com/oth6809/cms9639.htm.

    I took the binary file as is and removed the Boot loader part at the beginning of this file and added my own Boot module. (The CMS9639 Boot module is not well documented but seems to use a SCSI controller as a disk interface to a Winchester hard disk which I don't have). In order to manipulate binary files I use ImHex (https://imhex.werwolv.net/) which includes a 6809/6309 disassembler (amongst many).

    The CMS9639 part 1 code is different than the 'stock' OS9p1 code. This not only has to do with the details of the MMU but also because the CMS9639 has a nice way of capturing the postbyte which follows the SWI2 system calls. The postbyte indicates which system call is requested. Other systems have to capture this byte from user space and adjust the program counter so that upon return the location with the postbyte is skipped. The CMS9639 does this in hardware and makes the postbyte available in a dedicated memory location accessible only in the system state (see memory map on page 1 of the schematics).

    Secondly there are a few memory copy routines between tasks and since this has to work between tasks there is a significant overhead of switching. The CMS9639 removes the instructions for copying and uses the memory-to-memory functionality of the DMA controller with different tasks for source and destination.

    It seems I have implemented these hardware ideas correctly because I can see (with the use of a Agilent 16802A logic analyser) the system calling the Boot module which loads the so-called OS9boot file from disk (well CompactFlash in my case). Afterwards I can see the processor starts to execute the OS9p2 code which is the second part of the OS9 kernel. There is no dedicated CMS9639 version of OS9p2 so I have used a standard one at this stage (https://github.com/sorenroug/osnine-java/tree/master/os9software/dragon128).

    I do get an error upon changing directories to the default /H0 disk as indicated on the Init module which is loaded during Boot time. I suspect there is an issue with my bespoke disk driver module which has not been tested too well.

    OS9 is hard coded to use 256 byte sectors which is half of what IDE/PATA/CompactFlash filesystems have. I tried to be clever to put two 256-byte sectors into one 512 byte sector using a cache. For now I will just use one half of a 512 byte sector which makes things fast and simple.

    After updating the disk drive to use every other byte of a 512-byte sector and ironing out several bugs OS-9 booted on the system console as shown below. The hardest error to find was an indexed store of the B register which turned out to be unindexed (I forgot the 0,U) which corrupted the least significant byte of the D.POLL variable. As a consequence the system would go haywire after receiving interrupts ...

    Great to see this!

    In he Init file I have set 0x0FBFFF as the Top of RAM.

    There are no floppy disks specified yet, I still have to write the driver.

    The modules needed for booting are listed above and have standard names. Exception is IDEdrv which is the RBF type driver for the IDE board that was hooked up to a 512Mbyte ComplactFlash card.

    All these modules (minus the MDir one) are part of the OS9boot file that is loaded by the low level boot loader that together with OS9p1 resides in EPROM.

    For creating the boot disk I made a full system disk using VCC and used a small python programme to bulk up the 256byte OS9 sectors that make up the virtual hard disk file (.vhd) to 512-bytes simply by inserting a 00 byte every other byte in the disk effectively doubling the disk size. This programme code is attached for info.

    Virtual hard disk files are just binary files that contain sector data starting with Logical...

    Read more »

View all 8 project logs

  • 1
    PCB

    The provided zipped PCB file contains all Gerber files for production of the 4-layer PCB by JLCPCB. It was created within KiCAD with the JLCPCB toolkit extension.

    To get an idea of the costs you simply upload this zip file to the JLCPCB web site and it works out all the details needed from it. JLCPBC make it simple to order a solderpaste stencil from the same files, so all in one stop shopping.

    The uploaded version 2 has small changes from version 1 which I am using for testing. So I should add a note of caution:  I haven't tested PCB version 2 yet. Although the changes are small the probability of errors is not zero.

View all instructions

Enjoy this project?

Share

Discussions

Does this project spark your interest?

Become a member to follow this project and never miss any updates