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 »

CS09_CPU_ Schematic.pdf

PDF version of CS09_CPU schematics updated memory map 12/03/2026

Adobe Portable Document Format - 1.44 MB - 03/12/2026 at 11:28

Preview

CS09-CPU-III-v2.kicad_pro.zip

JLCPCB production files for CS09_CPU_III_v2

x-zip-compressed - 1.49 MB - 03/13/2026 at 15:16

Download

RTCdriver.asm

Software interface DS1302 through 3 PIA lines. The code is provided ONLY for info in case someone would like to experiment. It is not very efficient and not the way the interface was finally done! Note that the code uses a couple of UniBUG routines to deal with user interface. These routines are exposed with a couple of 'jump' words at the start of UniBUG.

plain - 6.67 kB - 04/16/2026 at 09:42

Download

my_ds1302.v

This Verilog module provides the serial interface between CPU and DS1302.

v - 7.78 kB - 04/16/2026 at 09:38

Download

ibom.zip

Interactive Bill of Materials and board population overview (zipped) html file.

x-zip-compressed - 444.42 kB - 03/08/2026 at 15:15

Download

View all 13 files

  • MMU design

    roelof4a day ago 0 comments

    The presence of a Memory Management Unit is a requirement for multi-tasking operating system such as OS-9 and UniFLEX both of which have many features from UNIX.

    Before diving into the details of the CS09 MMU I though it might be good to give an overview of the 3 main approaches to create extra address space (not necessarily MMU)

    1. Bank switching:

    2. Data Address Translation:

    3. DAT + task selector:

    The DAT + task selector gives most flexibility how to structure memory larger than 64kbyte and allows quick switching of the memory mapping of individual tasks without rewriting the DAT RAM.

    Often the task register is a physical register (latch) in real implementations which the CPU will update when there is a switching of tasks. The CMS9639 took this concept one step further and introduced a small 4x8bit memory to replace the task register. This allowed 4 sets of task registers that would form:

    - System task (task 0)

    - User task

    - DMA source task

    - DMA destination task

    Switching between these is automatic and done in the logic chip. So whenever a software or hardware interrupt occurs the System task will be selected and so on.

    Below a snippet from the CS09 CPU schematic showing the chosen implementation:

    Rather than using a standard 2kbyte RAM memory like the CMS9639, I have followed the approach by Kees Schoenmakers and used a dual-port memory chip (IDT7132). These are fast (35ns) and do away with extra tri-state buffers that are needed for normal memory when switching from MMU use to writing its contents. Here the righthand side of the dual-port memory provides access to its contents (I_D is the internal databus, C_A the CPU address bus). The left side takes CPU address lines A12..15 and the output from the small memory chips and outputs the MMU addresses MA12..MA19 which together with C_A0..11 will form the external address bus.

    A set of pullup resistors on MA12..MA19 defines the external bus address before the dual-port RAM has its contents defined and taken out of tri-state. Currently the most significant bit (DATREG7) is not used and connected to the logic chip. In future this could be used to introduce memory write protection.

    Motorola did, in fact, develop a MMU chip - the MC6829 - that provides 2kbyte pages. This chip was not long in production and not many copies are around. Unfortunately, the delay in outputting the translated address lines was significant which made operation at 2MHz next to impossible. I know only one commerical machine that used the MC6829, the Positron 9000 (https://binarydinosaurs.co.uk/Museum/Positron/).

  • Floppy Disk & Disk formatting

    roelof42 days ago 0 comments

    You will have noticed that l have avoided the topic of disk formatting.  Mainly because I did formatting of CF cards using the VCC simulator. Now that my system is about to be independent this topic needs to be tackled.

    Other than floppy disks hard disk tend to come pre-formatted and the process is mainly writing key sectors with file system data. Typically this is called Logic formatting whereas floppy disks usually require physical and logical formatting.  At the moment the driver can't do that and an upgrade is required. Here is some background info from the Microware System Programmer's Manual regarding the process of disk formatting.

    Full detail in the Manual (pages 11-58..61 & 11-68..72). Various implementations of OS-9 have added further SS. parameters to the list. Here some details of interest:

    As you may have noticed the IDEdrv (and all RBF drivers for that matter) have two useful routines accessible using the following system calls. At the moment these two routines are empty and just return to the caller. If we don't use physical formatting on the hard disk interface I don't expect we need to add anything. But for floppy disks it does require careful study. The actual number of different parameters for floppy disks is rather large with variations in track and sectors/track numbers, single/double sided, single/double density and 3 physical disk sizes.

    Anyway, I am slowly entering the stage of preparing the floppy disk interface and will have to face doing the track formatting bit. I will start with the WD2797 controller which is fairly common and should be able to read all my old 5" disks.

    The IDE interface has the same logic device as present on the CPU board and it features embedded RAM large enough to hold several sectors of data so I would like to structure the interface such that the CPU only has to give a read/write command to the WD2797 fill a buffer for writing, then go to sleep and let the logic chip collect/serve bytes from/to the on-chip RAM and generate an interrupt when the process is complete. That way the CPU is free to serve other tasks most efficiently.

    Formatting disks

    The format utility in the CMDS directory is not available in source form unfortunately. There is a commented disassembly file from the NitrOS9 community however, which is very helpful and helps with checking which SS. codes need implementation in the IDEdrv driver.

    The GetStt/SetStt routines are wildcard calls used to get or set a device's operating parameters. It may be necessary to examine or change the register stack which contains the values of MPU registers at the time of the I$GetStt or I$SetStt service request. The address of the register stack may be found in PD.RGS, located in the path descriptor.

    The calling convention is consistent across all SS. codes:

    • Register A = Path number (the open path to the disk device, e.g. /d0)
    • Register B = Function code (the SS. constant)
    • Other registers depend on the specific function code

    The SS. codes are defined in the OS9Defs equate file (part of the DEFS directory). They are passed in register B to both I$GetStt (SWI2 + $8D) and I$SetStt (SWI2 + $8E).

    The Three Codes Used by format

    Here is a detailed breakdown of each of the three status codes:

    SS.Reset — Controller Reset / Drive Restore

    • Code value: $00
    • Direction: I$SetStt (SetStt — sends a command to the driver)
    • Purpose: Issues a hardware reset/restore to the disk controller. In the context of format, this is used at the start to recalibrate the drive — stepping the head back to track 0. On floppy-based systems with the WD1793/1773 FDC chip, this causes a Restore command to be sent, which steps the head in until Track 0 is detected.
    • Registers in: A = path number, B = SS.Reset ($00)
    • Registers out: None meaningful (carry clear on success, set with error code in B on failure)

    This is typically the very first hardware-level call format makes, ensuring the drive is in a known state before writing begins. ...

    Read more »

  • Command line parameters OS-9

    roelof44 days ago 0 comments

    In OS-9 for the 6809, command line parameters are passed to a program through a specific convention using the process's data area and registers at startup.

    At Program Entry, the CPU Registers Contain:

    • X — points to the start of the parameter string in memory
    • Y — points to the top of the data area (the program's allocated memory)
    • U — points to the bottom of the data area (start of the stack/data)
    • D (A:B) — contains the size of the parameter string

    The Parameter String

    The parameter string is a raw text buffer containing everything typed after the command name on the shell line. For example, typing:

    myprogram foo bar -x
    

    ...results in X pointing to foo bar -x, with D holding its byte length.

    Key characteristics of the parameter string:

    • It is not null-terminated — you must use the length in D to know where it ends
    • It ends with a carriage return (0x0D), which counts as part of the string
    • It may be empty (D = 1, pointing to just the CR) if no arguments were given
    • The string lives in the system's I/O buffer area, not in your program's data area, so you should copy it if you need to keep it

    Memory Layout at Entry

    Low address
    ┌─────────────────────┐  ← U (data area base / stack bottom)
    │   Program Stack     │
    │         ↓           │
    │    (grows down)     │
    │                     │
    │   Static Data       │
    └─────────────────────┘  ← Y (top of data area)
    High address
    
    Separately, in system buffer:
    ┌─────────────────────┐  ← X
    │  "foo bar -x\r"     │  (D bytes long)
    └─────────────────────┘
    

    Parsing Responsibility

    OS-9 does no parsing for you. Unlike Unix which gives you argc/argv, OS-9 hands you the raw string and leaves tokenization entirely to the program (or to a library like the one in the C runtime). You walk the string byte by byte, using the length in D as your bounds, splitting on spaces or other delimiters as needed.

    Standard I/O

    At entry, the program's standard I/O paths are already open:

    • Path 0 — standard input
    • Path 1 — standard output
    • Path 2 — standard error

    These are inherited from the shell and ready to use via OS-9 I$Read / I$Write system calls.

    This convention is quite minimal and low-level compared to later systems, which is typical of OS-9's design philosophy of keeping the kernel small and fast on 8/16-bit hardware.

  • Realtime Clock

    roelof45 days ago 0 comments

    OS-9 uses a 100Hz oscillator driven signal to keep track of time. As mentioned this signal is connected through the PIA (MC68B21/HD63B21) and generates interrupts every 10ms. Upon calling the 'setime' command the PIA is initialised and valid time information becomes available to the system. Often the setime call is included in the 'startup' file which is automatically run at boot time.

    Because there is a battery backed Realtime Clock (DS1302) available there is no need to manually enter date and time information (once the Realtime Clock is setup) every time the system boots.

    In order to include the reading of the Realtime Clock at boot time changes are made to the Clock module and the setime command. Before discussing these changes it would be good to discuss the Realtime Clock itself and how it is interfaced to the CPU.

    Unfortunately the use of the same Realtime clock chip (MSM5832) as used on the CMS9639 was not an option since this obsolete chip is difficult to source. Since there was little board space available it was decided to go for a chip with a small footprint and a serial interface. The DS1302 provides date, time and a small number of non-volatile RAM locations. Its interface is bespoke and shown below.

    There are only three pins for exchanging data. A ChipEnable selects the device and data (IO) is shifted in/out using a SerialCLocK. Only the IO pin is bidirectional. 

    Originally I hooked the DS1302 to a couple of unused PIA lines and implemented a software interface to read/write date & time information. That resulted in quite a bit of code (provided) and since there was some space left over in the CPLD chip, it was decided to create a bespoke interface using a Verilog module. 

    For fun I tried to use one of the AI agents to write a module for me. This turned into a disappointing result that didn't work because the agent misinterpreted the asymmetry between reading & writing and was unable to generate the right code even when this issue was pointed out.  After testing about ten versions I gave up :(

    Thinking someone would have tackled this already I searched online and found a github repository (link in the code) that implemented burst reading/writing (many registers in one go without transmitting the address info for every register). I modified this code to include single register read/write which I needed to change the trickle charge settings. This code is provided in the file section. I will discuss the detailed instantiation of this module within the top level Verilog code in the near future. Since the actual code is rather large I will try to do this in sections.

    From a software perspective this interface takes 8 memory locations ($FFB0..$FFB7) that provide date&time and command/status register ($FFB7). In the command register the user selects the type of operation (burst read/write or single register read/write). The status register shows when the serial interface is busy/ready with any operation.

    With this interface tested it was decided to modify the 'year 2000 compliant version' (source available online: y2k upgrade) of the setime command (setime edition version 12) slightly to add an option (-s) to read the Realtime clock date & time information and copy this to the OS-9 time rather than typing it in. Setting of the Realtime Clock is done automatically if the 'setime' command is provided with user date&time information in the usual way (i.e. both OS-9 system time and Realtime Clock are set). 

    By adding 'setime -s' in the startup file the copying of the date&time info is automatic. The space between setime and -s is optional and 's' can be 'S'.

    In the modified Clock module care is taken that the Realtime Clock is present and not in a 'halted' state before initialising.

    At this point no use is made of the DS1302 RAM memory but the provided Verilog module and interface is fully prepared for it simply by reading/writing to different addresses within the DS1302 use can...

    Read more »

  • OS-9 DMA disk driver details 2

    roelof404/08/2026 at 09:52 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 ...).

View all 12 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

Similar Projects

Does this project spark your interest?

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