So one last problem I had with adapting the Dragon ROM and Floppy Emulator to work on my Coco 2 was to solve why OS-9 would not load. So most Coco disk images are not for OS-9, but there are quite a few in the colorcomputerarchive that do use OS-9, so I was curious. There were some Sierra games that required it too … and I wanted to try them out.
When I first attempted to boot OS-9 (you insert a disk and type DOS) I would see the ‘OS9 BOOT’ message and after some moments you would see the main ‘front page’ of OS-9, but instead of the prompt appearing, it would just hang and there would be one or more @ characters in the top left corner. I had a fair guess that this was to do with timing in relation to the DRQ and INTRQ signals from the floppy disk controller.
So if you think of a real floppy disk, the disk is spinning and the head is over a track, and if say you have asked the FDC (Floppy Disk Controller) to read a sector, the bits of magnetic flux are read off the disk and assembled and when the next one byte of data is read off the disk surface it goes into the FDC data register and DRQ goes high. This read timing diagram is in the back of the FC179X-02 datasheet
So the Coco and Dragon FDC interfaces treat DRQ differently. If you knew nothing about the Coco or Dragon you might think that when DRQ goes high an interrupt is generated or some DMA occurs . DMA was but a dream for home computers of this era, so what about an interrupt? In the Dragon DRQ goes through some gates to end up at one of the PIA chips and in theory fires an interrupt but its never used that way. The Coco is the more interesting one in that DRQ goes through some gates and ends up connecting to the _HALT pin of the 6809E. When _HALT goes low, the 6809E will finish its current instruction then stop .. until _HALT goes high (NOTE: those ‘gates’ involved allow you to enable or disable this behaviour of _HALT)
So DRQ has gone high. Because it’s high the 6809E can start running some instructions. Given that the 6809E has just sent a ‘read sector’ command to the FDC it’s been waiting for this DRQ to go high. So once it’s unhalted the 6809E goes and reads the FDC data register. The FDC will send DRQ low just after the 6809E reads the data register … which in this case will halt the 6809E as soon as its executing instruction finishes. Moments later the FDC will assemble the next byte off the spinning floppy disk in the FDC data register and send DRQ high again. The 6809E unhalts and given it just got some data from the FDC before it halted last time it will save that to memory somewhere then read the FDC data register which will trigger it to halt again. This whole process repeats again and again until a whole 256 byte sector is retrieved, then the FDC will send INTRQ high which does end up triggering a real _NMI interrupt (assuming the gates to enable it are set).
One key bit in that diagram is the ’16 or 32 us’ bit. Floppy disks of this era are either FM or MFM encoded generally … but most likely MFM. MFM is the ‘faster one’ so in theory we are getting a DRQ every 16 microseconds. For a CPU running at 0.895MHz that is not a lot of time. Certainly not long enough to service an interrupt by stacking the CPU state and calling an interrupt routine. There is a note down the bottom of that timing diagram to say you need to be able to service the DRQ in less than 13.5us which sounds about right.
Anyway, the DRQ going to _HALT model allows the CPU to read a sector of data in a tight loop without having to poll to see if there is any new data available. It also highlights to me , the author of a floppy disk controller emulator that I need to replicate that behaviour. So for the stm32f407 board, it’s actually reading a disk image from the micro SD card one track at a time. The track is loaded into the stm32f407’s RAM, and every time the 6809E is reading from the FDC data register it is just pulling from that RAM. Obviously this would allow me to feed data to the 6809E faster than once every 16us, but ultimately the tight timing loop that relies on _HALT at the right time has to be ‘pretty close to spot on’ for the whole thing to work. So I had made this work for the read sector routine in RS-DOS, but chances are that OS-9 used a different tight loop and somehow my logic and/or timing was wrong.
The way I did this originally was to make it such that whenever the emulated FDC wanted to send DRQ or INTRQ high, it put the signals into a delay queue where they would be delayed by maybe 12 or 24 E cycles. It was all a bit rough and I decided to simply rewrite this logic to make it more flexible.
- When the FDC emulation wanted to send DRQ high or low it would write an intent saying the desired state and how many E cycles to wait before applying that state. The same logic applied for INTRQ (in that it could have a different number of E cycles to wait until some state change)
I had to change this a little specifically for reads or writes to the FDC data register in that I need to queue up an almost immediate ‘DRQ goes low’ followed by a “DRQ going high in about 16 cycles. In theory it should work with ‘less than 16 cycles to account for the length of the service routine’, but I am happy it works for now.
Because this board works now with the Coco and the Dragon, for any changes I have to go back and re-test on both … and now that OS-9 worked on the Coco, that meant testing OS-9 on the Dragon. Getting OS-9 to work on the Dragon was another interesting ordeal.
As mentioned DRQ does not connect to _HALT in the Dragon. Instead it goes to a PIA pin which can be used to generate an interrupt, but Dragon DOS just uses a tight loop with the SYNC instruction to read or write sectors. SYNC will halt the 6809E until the interrupt occurs (there is a great disassembly of Dragon DOS here) . It’s worth reading up about SYNC as it’s not always used how the Dragon uses it.
Anyway, on my Dragon 32 I would type BOOT. I would see the ‘OS9 BOOT’ message but then it would hang. I eventually worked out that OS9 for Dragon was designed for the Dragon 64, and I had a Dragon 32 with a homebrew 64K upgrade. That gave me 64K of RAM, but its not exactly the same as a Dragon 64. A real Dragon 64 has a 6551 ACIA serial chip, and OS-9 attempts to talk to it during boot. This is what was causing my ‘hang’. Fortunately the World of Dragon page about the 32K to 64K upgrade has a specific note about OS-9 and the missing ACIA. All I had to do was
- wait a bit
- press RESET
- Enter POKE &HFF03,&H34: EXEC9736
And then you see the ‘OS9 BOOT’ screen again for a few seconds and then finally the OS9 main screen and the prompt!
So what can you do with OS-9? There’s some really nice notes about OS-9 at Sub-Etha Software . You can do a search of the colorcomputerarchive for OS-9 software. A lot of stuff is for the Coco 3 only … which I assume will never work on a 64K Coco 2. And also ignore the stuff for Coco SDC, DrivePak or Drivewire images. Effectively those are for different sized disk images.
You would think I could rest now, but the other OS-9 is NitrOS-9 . I thought this would be easy now that I had OS-9 working .. but no. Any attempt to boot a NitrOS-9 disk image on the Coco2 failed. One important change with NitrOS-9 is that I could only find double sided disk images. OS-9 just had single sided 40 track images (161,280 bytes). But NitrOS-9 comes in several different disk image types. The main ones I thought would be easy would be 40 track double sided and 80 track double sided, so I added code to support those.
I also got a bit confused how the side was actually selected. The original Coco FDC expansion schematic I was looking at had no ability to do double sided as far as I could tell … That meant looking at the source code of xroar and VCC to give me some hints. Of course they support a few different floppy expansions … and perhaps a combination of too many late nights trying to boot NitrOS-9 … but it took a long time to realise it really is just bit 6 of the 0xff40 latch ( which is also the 4th drive select bit)
Even with that realisation it still would not boot. So I had delays for both DRQ and INTRQ (as per the earlier discussion). Strangely, NitrOS-9 didn’t like having a long delay for INTRQ driving NMI, so I had to reduce that significantly (and later on had to adjust it so that it is different for a read sector compared to a write sector).
It still would not boot though. After several late nights of failure, I found this old comment in VCC’s FDC emulation that made me laugh
* Last change date 07/26/2005 Complete rewrite to get F**king nitros09 to boot *
But finally I noticed that NitrOS-9 sends a read sector command to the FDC … then straight after updates the latch to set the ‘side’. And that all happens ‘before’ the first DRQ comes in with the first byte of data off the disk. Obviously, real floppy disks are not the fastest thing in the world and there is ‘plenty of time’ between the ‘read sector command’ and that ‘first byte of data coming in’, but it struck me as unusual to ‘flip the side’ after you’ve asked to read a sector. Usually you would set the track and sector and side before you issued a read sector command. Of course I had made this assumption in my FDC emulation. Given the actual sector data was in RAM somewhere, I was calculating the offset to that data from the track and sector data provided … but also using the selected side in the calculation at the time the ‘read sector’ command comes in. So i was always setting the offset to side 0, since the latch had not been written to yet.
So it’s this part of NitrOS-9 in ./level1/modules/boot_1773.asm that I assumed was torturing me
ReadSect bsr Seek2Sect seek to the sector stored in X
bcs HWRRts if error, return to caller
ldx blockloc,u get address of buffer to fill
orcc #IntMasks mask interrupts
pshs x save X
ldb #%10000000 ($80) READ SECTOR command
stb CMDREG,y write to command register
ldb drvsel,u (DDEN+MOTORON+BootDr)
* NOTE: The 1773 FDC multiplexes the write precomp enable and ready
* signals on the ENP/RDY pin, so the READY bit must always be ON for
* read and seek commands. (from the FD502 FDC Service Manual)
orb #DDEN+READY set DDEN+READY bits ($30)
tst side,u are we on side 2?
orb #SIDESEL set side 2 bit
L0107 stb CONTROL,y
lbsr Delay2 delay 54~
orb #HALTENA HALT enable ($80)
Anyway, I adjusted my code to delay the calculation related to the side and it finally boots! (and yes it’s meant to look like this)
Well it booted on the Coco. Of course I had to try NitrOS-9 on my Dragon 32. And of course it didn’t work, but again NitrOS-9 targets a few different machines, none of which are a ‘Dragon 32 upgraded to 64K’. But deep in the comments is a flag that allows you make a build specifically for my type of Dragon. I just updated level1/d64/makefile to say UPGRADED32 = 1
#Is this machine a real 64, or a 32, upgraded to 64K.
#Set to 1 for upgraded machine.
UPGRADED32 = 1
So then I just needed to recompile. On Fedora I had to install the lwtools (which I already had) and toolshed packages, then it’s just
And after having a coffee, you should have some disk images in level1/d64 . I just used the 80 track one (so the Dragon can read these .dsk images as well), and it works!
You would think after all this pain I would have a very low opinion of OS-9 and NitrOS-9, but I must admit I am really quite impressed by them. Check them out in an emulator first if you are curious.
I’ve updated the TIM-dragon-coco-mode-version branch of the code. I’ll eventually merge this to master.