kernelcrash / dragon-rom-and-floppy-emulator

Emulate ROM and floppy images on the Dragon 32 and Color Computer 2
MIT License
4 stars 2 forks source link

dragon-rom-and-floppy-emulator

Also now works on the Tandy Color Computer (tested on a Coco 2, but probably works on Coco 1 as well).

More info at https://www.kernelcrash.com/blog/emulating-roms-and-floppy-disks-on-the-dragon-32/

Heavily based on msx-rom-and-floppy-emulator (https://www.kernelcrash.com/blog/emulating-roms-and-floppy-drives-in-msx/)

Note the 'Wiring it' section below if you've built the earlier version. There are some changes.

Overview

Wiring it

Using a STM32F407VET6 or STM32F407VGT6 board

   PA2         - wire a button between it and GND. No need for a pullup. This is 'NEXT'
   PA3         - wire a button between it and GND. No need for a pullup. This is 'PREV'
   PA4         - wire to a two pin jumper. Wire the other pin to GND. No need for a pullup. When you 
                 set the jumper to tie PA4 to GND it means the board is in Tandy Coco mode. When 
                 you don't have a jumper in place to GND it means the board is in Dragon 32 mode.

   PE0 to PE15 - A0 to A15
   PD8 to PD15 - D0 to D7

   PB6         - connects to PC4
   PB7         - E (p6) (see further down. _E connects to both PC0 and PB7)

   PC0         - E (p6)
   PC1         - _CTS (p32) (the cartridge chip select)
   PC2         - _P2 (p36)  (the $FF40-$FF5F chip select)

   PC3         - R/_W (p18)
   PC4         - PB6

   PC5         - _RESET

   PC6         - CART (PIA1 CB1) (note: CART is connected to Q for a real cartridge)
   PC7         - _NMI

   PC13        - _HALT (only required for Tandy mode)

   GND         - GND

Looking at the cartridge socket (pin 1 and 2 are towards the rear of the computer)

       1  +12V           2  +12V
       3  !HALT - PC13   4  !NMI - PC7
       5  !RESET - PC5   6  E (main clock) - PC0 & PB7
       7  Q (leads E)    8  CART (PIA1 CB1) - PC6
       9  +5V           10  D0 - PD8
      11  D1  - PD9     12  D2 - PD10
      13  D3  - PD11    14  D4 - PD12
      15  D5  - PD13    16  D6 - PD14
      17  D7  - PD15    18  R/!W - PC3
      19  A0  - PE0     20  A1 - PE1
      21  A2  - PE2     22  A3 - PE3
      23  A4  - PE4     24  A5 - PE5
      25  A6  - PE6     26  A7 - PE7
      27  A8  - PE8     28  A9 - PE9
      29  A10 - PE10    30  A11 - PE11
      31  A12 - PE12    32  !CTS ($C000-$FFEF) - PC1
      33  Ground        34  Ground
      35  Ext sound src 36  !P2 (PIA2 $FF40-$FF5F) - PC2
      37  A13 - PE13    38  A14 - PE14
      39  A15 - PE15    40  !DSD (Device Select Disable)

If you get a board with a microSD card slot, then the 'standard' wiring of the SD adapter is fine.

The DEVEBOX stm32f407 board I used during development has an LED attached to PA1, so various errors will result in PA1 flashing.

Setting up the micro SD card and using it

I tend to format a micro SD card with a smallish partition (less than 1GB) with FAT32. If the board is in Dragon mode then you need:

If the board is in Tandy mode:

The order in which you copy files into the dragon or tandy directories is the order they will appear when you are cycling through disks or roms (ie. its not alphabetical).

If you then plugged the stm32f4 board in as described, then the Dragon or Coco will look at the first file in the dragon or tandy directory and 'present' it. If that file is a .rom file then the computer will see that as a cartridge at 0xC000. If its a .vdk or .dsk file then the appropriate DOS rom is loaded as a cartridge at 0xC000 and you boot into BASIC. If you type DIR then you should see a directory listing of that first .vdk or .dsk file.

Assuming you have presented a disk, if you press NEXT, then do a DIR again (or power off/on the Dragon) then you should get a directory listing of the 2nd disk you copied to the dragon directory and so on. PREV can be used to go to the previous disk image.

It's not a bad idea to power the stm32f4 board separately so you can power off/on the dragon when necessary without resetting the stm32f4 board to its first disk image (ie. make sure GND is connected from the Dragon to the stm32f4 board, but leave +5V disconnected). Given that you can intermix .rom and disk image files in the dragon or tandy directory you can end up swapping out the DOS rom to replace with a different ROM. Chances are you would crash the computer at that point. ie. it's best to power off/on the Dragon/Coco.

There is also a special ROM called menu.rom. If you have built it using lwtools (see the build.sh script), you can copy menu.rom to the root of the SD card as well. If you power off your Dragon or Coco, and reset the stm32f4 board, the Dragon or Coco should now load the menu.rom at 0xC000 and show a disk/rom menuing system called KCDFS (or renamed to KCCFS if you set the jumper for Tandy mode). From the menu you can select a disk image or ROM and the Dragon or Coco will then boot into what you selected (ie. if you chose a rom it will boot that ROM. If you chose a disk, it will boot into BASIC with a DOS loaded and the disk image in the first drive)

With the KCDFS/KCCFS menu.rom, the NEXT and PREV keys still operate as they should. So if say you had a disk image for a game. And the next disk was a blank disk you used for game saves, then you just press NEXT when the game asks to save, and press PREV to get back to the game disk. It only emulates one disk drive.

Normally to get back to the menu.rom you need to power down the Dragon or Coco and also make sure the stm32f4 board is reset. However, there is a magic restart mode whereby if you hold in the reset button of the Dragon or Tandy and then press the NEXT button, wait a second, then press the PREV button, then let go of the reset button it will hopefully go back to the menu.rom. This won't work 100% of the time due to the way some games or software have been written. In that case you'll need to power down the Dragon or Coco.

Copying the firmware to the stm32f407 board

There are lots of options for writing firmware with the stm32 chips. There is an example of using dfu-util in the transfer.sh script. In order for this to work you would need to set the BOOT0 and or BOOT1 settings such that plugging the board in via usb will show a DFU device. Then you can run transfer.sh. Remove the BOOT0 or BOOT1 jumpers after you do this.

KCDFS/KCCFS

In the kcdfs directory is menu.s. It's a 6809 assembly program for the Dragon or Coco that can communicate to the stm32f4 board in order to show a list of all the files in the dragon directory of the SD card. You need lwtools to assemble it into menu.rom that you need to put in the root of the SD card.

After reset of the stm32f4 board it should load menu.rom and present it. So if you want to 'get back to the kcdfs menu', you can power down the Dragon or Coco and hit reset on the stm32f4 board, then power on the Dragon. Sometimes you can get away with just holding in the reset button of the Dragon, then tap reset on the stm32f4 board, then let go of the Dragon reset button.

kcdfs is about as simple as I could go. No fancy graphics. On boot it shows the first 12 or so files in the dragon directory of the SD card. They are listed with 'A' to 'L' down the left hand side. You press a letter and your Dragon should reboot and start up what you selected. Assuming there are more than 12 files in the dragon directory, you just press '2' for the 2nd page of 12 files, '3' for the 3rd and so on. You can also press '?' to get some help.

There is an ultra simple protocol used;

Summary

0xff50        - command register
0xff51        - spare
0xff52/0xff53 - number of files returned in a directory listing. In little endian (so 0xff52 is the low byte)
0xff54/0xff55 - address register into a directory buffer
0xff56        - byte to read from the directory buffer OR byte to write to the directory buffer

Technical

When E goes low (-ve edge) it triggers TIM4 (PB7) to generate a one-pulse in 190 or so nanoseconds. The one-pulse comes out of PB6. PB6 is connected to PC4 to generate an EXTI4 interrupt. What this all means is that the first line of the EXTI4 interrupt handler is often executed 290ns or so from the fall of E. That may seem silly as generally E is low for about 550ns when the 6809E is clocked at 0.9MHz. But if a program uses 'the speed poke', then E is potentially low for half the time (ie. 280-ish ns). Either way, at the start of the EXTI4 interrupt handler, we wait for E to be high.

So now E has gone high, we can read the address bus to see

ROMs are accessed at 0xc000 to 0xffef with some holes along the way. The !CTS pin goes low , so its easy to tell its a ROM access. As soon as this is detected it's a mad dash to look at the address bus of the 6809, then grab the appropriate byte from a ROM that was already preloaded into the stm32f4's RAM earlier, then change the databus such that the stm32f4 can output the byte, then wait for E to go low. And as soon as it goes low tri-state the databus bins and exit the interrupt routine.

The P2 peripheral access is different depending if we are in Dragon or Tandy mode

Regardless of the mapping, the FDC and latch are emulated.

A key difference between this and the previous floppy emulation stuff I've done is that the Dragon and Tandy use interrupts. It varies a bit between the Dragon and Tandy though

This interrupt stuff ended up quite interesting as you need to delay it a bit. Initially this caused the branch that worked on the Dragon to be quite different to the one that worked with the Tandy ... and this paragraph does not do justice to how long it took to try to combine the two branches so the code base worked OK on both computers ;-)

Much of the code is a lift/shift of the msx-rom-and-floppy-emulator, so have a read of that if you are interested in the use of FPU registers and WFE stuff.

VDK disk files are effectively loading a track at a time into the STM32F4's RAM during a WD2793 SEEK command. Requests to read or write sectors are effectively just reading or writing into this track buffer. That should be fast, but as mentioned it has to be slowed down a fair bit to keep the 6809E happy.

VDK files that I've used seem to mostly be single sided, 40 track, with 18 sectors of 256 bytes per track. The emulation assumes this sort of structure.

The read and write sector WD2793 commands are implemented, but the read/write track stuff is not. So that means it should work with most stuff, but don't try formatting anything.

I've tested it with Dragon Dos 1.0 and 1.2 as well as SuperDOS E6. They seem to work.

I have tested the Tandy side with RS-DOS 1.1 (disk11.rom).

Note also that the _RESET signal of the Dragon is monitored. After the stm32f4 board resets it makes sure the _RESET on the Dragon is high for a while to indicate that it should be out of reset. The rationale is that before _RESET is stable at a high level there is potentially a lot of erratic activity that could stuff up the EXTI interrupt processing.

I found most Coco software is in DSK format which is just a raw dump of the 35 tracks of 18x256 sectors. ie. filesize of 161280 bytes. For me this just means there is no header anymore (which VDK files have).

About OS-9 and Nitros-9

OS-9 and Nitros-9 for a Coco 2 with 64K should just work fine. Basically insert the disk, type DOS and you should see 'OS9 BOOT' or 'NITROS9 BOOT' and eventually the main OS-9 screen and a prompt.

So OS-9 on Dragon does work. However OS-9 was designed for the Dragon 64 in the Dragon world. My Dragon 32 has had the 64K mod done to it and OS-9 does sort of work on it. Per this page http://archive.worldofdragon.org/index.php?title=Dragon_32_-_64K_Upgrade The OS-9 boot will hang due to the 6551 ACIA missing in a Dragon 32. So the basic deal for a modded Dragon 32 is

I did look in to virtualising the ACIA, but the problem is that the primary PIA in a Dragon 32 is from FF00 to FF07, whereas in a Dragon 64 its from FF00 to FF03 with the ACIA from FF04 to FF07. You would need to at least cut the CS0/CS1 signals of the primary PIA and then have an inverter between the CPU A2 and the CS0/CS1 signals. That would just lock the primary PIA to FF00 to FF03. Then I would need to write some code to send back some appropriate dummy values when FF04 to FF07 is read.

NitrOS-9 will work on the Dragon as well. In my case, none of the publicly downloadable images work with a 'Dragon 32 upgraded to 64K'. You will need to edit level1/d64/makefile and set UPGRADED32 = 1 , then compile to generate new dsk images.

Thanks

I will note too that the xroar emulator and it's source was extremely helpful for figuring out the interactions with the FDC (http://www.6809.org.uk/xroar/), even though the floppy chip emulation code is still based mostly on fMSX.

Also the source code for Dragon DOS was enormously helpful too. https://github.com/prime6809/DragonDOS