BMOW title
Floppy Emu banner

Mac Floppy Emulator Revisited

A few weeks ago, I posted some thoughts on an SD-card based floppy emulator for classic Macintosh computers. This idea has been on my mind again recently, and I’m trying to determine whether this could be done solely with a microcontroller and a few other support chips, or whether a CPLD or FPGA is needed. I also took a look at a few related designs for inspiration. If a working emulator could be built entirely from a microcontroller and other common parts in through-hole packages, then it could be built by anyone on a piece of perfboard or even a breadboard. In contrast, a CPLD or FPGA would require a custom-made circuit board, and probably voltage level shifters as well. Unfortunately, it looks like a lone microcontroller probably wouldn’t be sufficient.

Need for Speed

The fundamental problem is access speed. The Mac reads and writes the disk drive control registers like they were an external memory: there are 4 register select lines (one doubles as the write data line), a read data line, and a write enable. Reviewing the floppy driver ROM routines, there are typically only 3-4 CPU instructions between when the last register select line is set correctly, and when the data is read or written. Call it 3 instructions to be on the safe side: that’s 12 clocks of the 68000 CPU.  If the microcontroller can’t respond that fast, it won’t work. For example, say the Mac wants to test whether the drive head is at track zero. It sets the register select lines to select the TK0 register, and 12 clock cycles later it reads the result from the drive. If the microcontroller can’t respond to the change on the register select lines fast enough to put the correct value on the read line before the Mac reads it, then an incorrect value will be read. For writes, the write enable signal LSTRB may be asserted for as little as 12 clocks. If the microcontroller doesn’t check the the signal at least that often, then a write may be missed.

I wrote some AVR code to do basic read/write management of the drive control registers, and looked at the compiled output. The read loop is 16 AVR instructions long, and something like 20 AVR clocks (I didn’t count exactly). If the AVR is clocked at the same 8 MHz speed as the Mac, then that’s not enough time. If it’s clocked at the max AVR speed of 20 MHz, then it might be fast enough. However, this assumes the read loop begins at the same instant that the CPU changes the register select lines. If instead the lines change just after the AVR reads them, then it will spend 15 clock cycles producing the result for the old register, and 16 more cycles producing the result for the new register. So in practice, the AVR needs to be fast enough process its read loop twice within the register-select-to-read-data time of the Mac.

Maybe with better optimized code, or an overclocked AVR, or a PIC or Propeller or another high-speed microcontroller, it might be fast enough to act as a set of emulated drive control registers. But it would be sitting in a busy loop constantly watching the register select lines, providing zero additional time to read/write the SD card, or poll for user input buttons, or refresh a status LCD. Using interrupts to watch the register select lines would only make things worse, since then you’d have the interrupt latency on top of the 16 AVR instructions of processing to produce a result. I don’t really see how this approach could work.

HxC Floppy Emulator

The HxC Floppy Emulator project uses a PIC and an SD card to emulate a floppy drive, and works on many classic computers like the Amiga and Atari ST, but not the Macintosh. So how does it do it? Unfortunately as far as I can tell, it’s a closed design and the schematics and PIC firmware source aren’t available. I’ve posted a question in the forums to confirm. I think I can guess why it works, though. Unlike the Mac, those other computers use a parallel control interface for the floppy drive. In other words, all the control lines (step direction, step request, side to read, write data, etc.) and state lines (track 0 indicator, read data, write protect, etc.) are broken out with individual wires. That’s a lot easier to implement with a microcontroller, and there’s no need to constantly watch the register select lines and race to put the right value on the data line before the Mac reads it.

Now What?

I still won’t rule out the micrcontroller-only approach entirely, but it would definitely require a high-speed microcontroller, carefully-crafted loops for speed, and cycle counting to generate the output data and motor speed tachometer signal with exactly the correct timings. That doesn’t sound like much fun. I keep thinking that I must be overlooking something, and maybe there still is a way to do this easily with just a microcontroller, but so far I’m not seeing it.

If a lone microcontroller won’t work, what about a microcontroller with a few support chips? For example, the mcu could output the contents of all 16 control registers simultaneously on separate pins, and the register select lines connected to a 16-to-1 mux to select the desired register without any mcu intervention. Or the registers could be implemented in an external register file or latch of some kind. I think this approach could work, but would end up with half a dozen or more low-density 7400 series and similar chips. And at that point, I think it would be better to replace them all with a single CPLD.

That brings me to where I think this is all going: an emulator consisting of a CPLD and a microcontroller working in tandem. That’s not the worst design, but it’s not great if the goal is to design an emulator that anyone can build. A CPLD-based design would require a custom PCB, JTAG programming hardware, and other headaches. That’s not a problem for me, but I was hoping to design something usable by a wider audience who would probably balk at those requirements.

Read 8 comments and join the conversation 

8 Comments so far

  1. John_K - October 18th, 2011 2:46 pm

    Can you not use interrupts on those pins instead of polling for changes?

  2. Andrew Holmes - October 18th, 2011 3:51 pm

    I don’t think your normal small AVR has enough interrupts.

    It might be worth looking into an mbed – http://mbed.org/ – it has an LPC1768 ARM Cortex-M3 chip running at 100MHz with a lot more peripherals and interrupts, and likely has more than enough power to pull it off, with a C-based programming language very similar to AVR C.

  3. Dirk - October 19th, 2011 1:24 am

    Couldn’t you use DTACK of the 68000 when accessing the disk drive registers?

  4. Alex B - October 19th, 2011 4:53 am

    A CPLD with a PLCC package (e.g., XC9536 up through XC95108) with a through-hole socket can be reasonably done on perfboard.

  5. Steve - October 19th, 2011 8:12 am

    Perhaps interrupts would solve the problem, but I don’t exactly see how. You’d have some number of clock cycles of interrupt latency, then you’d have many more cycles to examine the pins, determine which one changed, and what to do about it. And while you were in the middle of doing that, another pin might change too. So while using interrupts could provide a way to do other work in the background, I don’t think it would make the actual response time any faster.

    A faster mcu like the ARM Cortex-M3 would certainly help, but if I’m worried about people not being able to solder a CPLD or not having the right programming equipment for it, the same concerns apply to the Cortex-M3. If it can’t be done with an AVR or PIC by itself, then I’d probably prefer to add a CPLD, rather than switch to some other type of microcontroller. But I really haven’t looked into it much, and maybe that’s not a good excuse for avoiding the Cortex-M3.

    There are other challenges to the mcu-only solution that I didn’t go in to, besides responding to register reads quickly enough. The biggest one is that disk data must be output at a constant rate of 2 microseconds per bit. I think that’s too fast to be done by an AVR interrupt, but I should double-check. AVR interrupts also don’t have a fixed latency, and while this can be addressed in software, it comes at the price of making the interrupt latency longer.

    No, I can’t play games with DTACK in this case, since this is a peripheral for a real Mac, not for Plus Too.

    I think it mainly comes down to a question of which approach I’m most confident would work. With the help of a CPLD, getting any necessary fixed timing or high speed response would be easy. With a mcu-only solution, it would be a game of carefully using interrupts in combination with rapid polling in some places, cycle counting, and other tricks. It might still work, but it would be more of a challenge. I’ll take another look a what the high-level program structure would look like for the mcu-only solution, and see where the bottlenecks would be and what it would really take to address them.

  6. Randy - October 19th, 2011 8:38 pm

    I’m thinking the Parallax Propeller might be good here – runs good and quick (80 MHz = 20 MIPS per core), 8 cores to split up the work, and available in a DIP40. Weird native language and a total lack of interrupts might be an issue though. SD card code already exists in Parllax’s object repository, I think.

  7. Big Mess o' Wires » Macintosh Floppy Emu - November 18th, 2011 11:29 pm

    […] I’ve been tinkering with this project for a while now, and wrote about it here several times before. Today I finally got read-only floppy emulation working from an SD card, in a rough […]

  8. Mark - January 4th, 2012 5:21 pm

    I’m late to the party, but sd2iec does this for the commodore 64 using a variety of different ATMega micros.

    It doesn’t emulate the full CPU of the 1541/1581 drive, just the wire protocol (IEC). It does support JiffyDOS and many other fast loaders.

    http://www.c64-wiki.com/index.php/SD2IEC

Leave a reply. For customer support issues, please use the Customer Support link instead of writing comments.