BMOW title
Floppy Emu banner

Archive for the 'Floppy Emu' Category

Macintosh Floppy Emu

The Macintosh Floppy Emu works! No, not the flightless Australian bird, but the SD card 800K floppy drive emulator for classic Macintosh computers. 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 approximation of the originally intended design. That makes it possible to download disk images of classic Mac software from the web, copy them to an SD card, and load them onto a Mac Plus or other Macintosh using the Floppy Emu.

Pictured above is the Floppy Emu hardware. Clockwise from the top-left are a custom CPLD board, an Adafruit ATmega32u4 board, and an Adafruit 1.8-inch TFT display with micro-SD card holder underneath. You can just barely see the SD card peeking out under the left edge of the display. In the middle of it all is the big red disk insert button.

The CPLD implements all the timing-sensitive functions and communication with the Mac, but its behavior is simple. The ATmega AVR microcontroller is the brains of the operation. It uses SdFatLib to read 512-byte sectors from a disk image file on the SD card, then passes the bytes one at a time to the CPLD at a speed that mimics a normal external floppy drive. Due to the design of the Macintosh IWM floppy controller, it’s not possible to pass data at a faster bit rate than a real floppy would, although the emulated drive could theoretically be faster overall if its track-to-track step times were faster. In practice I’ve found it difficult to match the performance of a real floppy drive.  In its current state the Floppy Emu is actually somewhat slower than the real thing, but still fast enough to keep the floppy controller happy.

 

Signal Synchronization

Everything was nearly working two days ago, and I had a floppy emulator that worked much of the time, but not 100%. It worked enough so that I could often mount an emulated floppy disk in the Finder, but if I tried to open any of the files on the floppy it would fail with I/O errors. It took an agonizingly long time to isolate the last few bugs, the worst of which proved to be a sort of clock domain synchronization problem when writing to drive registers. The Mac performs a write to the floppy drive’s internal registers by putting the register address and data on the bus, and then asserting the LSTRB signal for a short time. These registers are emulated in the CPLD, but there’s no particular relationship between the timing of the LSTRB signal and the CPLD clock. One of the registers is STEP, and when a zero is written to the register, it moves the drive forward or back one track. My original code looked something like this:

always @(posedge clk) begin
  // was there a positive edge on lstrb?
  if (enable == 1 && reg == REG_STEP && lstrb == 1 && lstrbPrev == 0) begin
    track <= track + 1;
  end
end

The trouble was that the CPLD didn’t always see LSTRB cleanly transition between 0 and 1. Occasionally the CPLD clock would sample LSTRB just as its value was changing, and then funny things would happen. The signal would appear to change from 0 to 1 to 0 to 1 very quickly, causing a double-trigger of the code above, and stepping two tracks when it should only have stepped one. My fix was this:

always @(posedge clk) begin
  // left shift the current lstrb value into a history buffer
  lstrbHistory <= { lstrbHistory[4:0], lstrb };
end

always @(posedge clk) begin
  // was there a positive edge on lstrb?
  if (enable == 1 && reg == REG_STEP && lstrbHistory == 6'b011111) begin
    track <= track + 1;
  end
end

Looking back on it now, the problem seems fairly clear, but it took me ages to discover what was going wrong.

 

On-the-Fly Sector Retrieval

I’ve examined the designs of a few other floppy disk emulators, and they all use a sensible technique in which an entire track of data is read into a RAM buffer, and then the sectors in that track are continuously “played” from the RAM buffer, over and over until the computer selects a new track. Since everything is in RAM, there are no sector-to-sector delays needed to fetch new data from from the memory card. The only downside to the technique is that it requires a RAM buffer large enough to hold an entire track’s worth of sectors at once. For the Macintosh that’s 6K, plus about 1.5K more for other buffers and SdFatLib. I wanted to use an 8-bit AVR microcontroller, but few of them have 8K+ of RAM, and nothing that I had handy has more than 2K.

To fit the limited memory available, I used an on-the-fly sector retrieval technique instead of the track-at-a-time technique. This technique only requires a single 512 byte buffer, enough for one sector. After the data bytes from a sector have been sent to the Mac, the AVR loads the next sector from the SD card, which takes about 2 milliseconds. On a real floppy the sector-to-sector padding is only about 0.25 milliseconds, but it turns out that the Mac is tolerant of much longer inter-sector delays as long as you keep sending it $FF sync bytes between sectors.

How much slower does this make Floppy Emu data transfers versus a real floppy? The numbers say about 16%. Assuming 10 sectors per track, 752 bytes per sector after GCR encoding, 2 microseconds per bit, then it takes about 122 milliseconds to transfer all the data in a track from a real floppy. Add an extra 2 ms delay between each sector for SD card access, and the total time increases to 142 ms.

In actual use, however, Floppy Emu appears closer to 3x slower than a real floppy disk. Using Disk Copy 4.2, I was able to read an entire 800K floppy in 41 seconds, and an emulated version of that same floppy in 2 minutes 10 seconds. As best as I can tell, the difference is due to some kind of bug that’s triggering the Mac’s retry mechanism, rather than the 20% SD card access overhead. The TFT display shows the emulated active track and side in real-time, so I can see that after every few tracks read during disk copying, the drive seeks down to track 0, then all the way back up to the track where it left off. This looks like some kind of mechanism for coping with unexpected data: the Mac concludes the drive isn’t where it thought it was, so it resyncs by returning to a known location (track 0) and then continuing. It never reports any errors to the OS or the application, though, so I’m not sure how I can determine what’s causing this behavior.

 

Further Steps

Encode On-the-Fly: The disk image data that’s stored on the SD card is pre-encoded using the GCR tool that I previously wrote for Plus Too. Now that I’ve got a microcontroller that can run plain old C code, it should be easy to do the GCR encoding on-the-fly in the microcontroller instead. That way the disk images on the SD card would be the exact same disk image files used with popular Mac emulators like Mini vMac.

Disk Image Selection: In its current form, there’s no UI for selecting which disk image file to use from the SD card. It simply looks for “floppy.dsk” and that’s it. It would be nice to have a simple UI for navigating the directories on the card, determining which disk image files are in a supported format, and selecting a file to use.

USB: The ATmega32u4 microcontroller that I’m using is USB-capable. Instead of loading the disk image data from an SD card, maybe it could be loaded from an attached PC over USB? I’m not sure it would be fast enough, and maybe it would be more hassle than it’s worth, but it’s an interesting idea.

Writable Floppy Emulation: The current technique is unsuitable for writes. It’s OK to be slower than a real floppy during reads, because Floppy Emu decides when to send the next sector’s worth of data. But for writes there’s no flow control mechanism– the emulator needs to receive, decode, and write to the SD card fast enough to keep up with the Mac, or else it will fail. That’s not possible with the on-the-fly sector method. To support writing to the emulated floppy, it will require an AVR with a large capacity RAM using the track-at-a-time method. Incoming data will be buffered in RAM, and then a full track of data will be written to the SD card during the period while the emulated drive is stepping to the next track.

Read 13 comments and join the conversation 

Classic Mac Floppy Emulator Boot-Up

Exciting news on the Classic Macintosh Floppy Disk Emulator: I successfully transferred two sectors from a virtual 800K floppy disk, and used it to boot a Mac Plus to the “Happy Mac” screen. This proves that all the trickiest parts are working: the drive RPM speed feedback signal, emulation of drive registers, GCR data encoding, correct sector headers / footers / checksums, and modulation of the read sense line to mimic magnetic disk media. Woohoo!

There’s not enough memory to hold a full disk image, so the Mac won’t boot all the way to the Finder yet. More work is needed to load a track’s worth of data at a time and buffer it in RAM, using the Mac’s drive step command to trigger loading of a new track. And of course there’s still the whole question of floppy disk writes in addition to reads… but now that the initial hurdle of basic data transfer has been cleared, I feel much more optimistic about the remaining work.

As described in my previous post, a CPLD implements all the timing-sensitive functions, and generates the signals that are sent to the Mac. It creates an RPM feedback square wave whose frequency varies according to the current track of the emulated floppy drive, in order to mimic the variable-speed behavior of the Mac 800K drive mechanism. It also ensures bits are sent at exactly 2 microsecond intervals, using the transition encoding method of a real drive. This method indicates a logical 1 as a high-to-low transition during a 2 microsecond bit window, and a logical 0 as no high-to-low transition during the window.

To the CPLD setup, I added an ATmega168 AVR microcontroller with 16KB of program Flash memory and 1KB of RAM. The AVR stores two sectors worth of pre-encoded GCR data in Flash memory, and passes it to the CPLD one byte at a time, using ready/ack control signaling. If the AVR doesn’t signal its readiness when the CPLD needs a new byte, then the CPLD will automatically insert a sync byte. This makes it possible to emulate the empty space between sectors on a floppy disk without actually storing or transferring the sync bytes that appear in the inter-sector space. The eventual plan is for the AVR to also load disk image data on-the-fly from an SD card, or possibly over a USB link from a PC, perform GCR encoding on the fly, and also perform GCR decoding to support disk writes as well as reads.

Luckily my first attempt at transferring data wasn’t far off the mark, because the emulator’s Mac interface is nearly impossible to debug. Ideally I could step through the floppy driver routines in the Mac’s ROM while floppy data was being loaded, and see what’s happening at a low level and troubleshoot problems. This is sort of possible, by installing the MacsBug debugger on the Mac, and setting breakpoints inside the ROM driver routines. Unfortunately the Mac’s 68000 CPU lacks hardware breakpoints, so breakpoints in ROM code must be implemented by setting a processor flag to invoke an interrupt handler after every instruction. (RAM breakpoints are implemented by dynamically patching the code.) This makes the Mac run 100-1000 times slower than normal when a breakpoint is set in ROM, rendering it virtually unusable. But even if you have the patience to wait 10 minutes for a breakpoint, I found that my ROM breakpoints didn’t always get hit, though I couldn’t explain why.

After setting up the AVR data transfer and discovering that it didn’t work, I scratched my head for a while, trying to find tools to help determine what was wrong. The first problem I found was that the disk RPM speed feedback I thought was working correctly earlier actually wasn’t. I was able to use MacsBug to see that the floppy driver was returning error -79 “can’t correctly adjust disk speed”, but I had to blindly experiment with different speed values until I hit on one that worked. Then the floppy driver was returning error -67 “can’t find an address mark”, which basically means it can’t make any sense of the data to determine where a sector begins. With zero other info to help troubleshoot, I methodically went through all my design assumptions one-by-one again looking for mistakes, and found a place in the IWM specification where I misinterpreted what Woz meant by a “transition” on the read sense line. At fist I thought a “falling transition in a bit window” meant any transition that falls in the window, but it turns out it literally meant a falling high-to-low transition. After fixing that, holy cow, it worked! I had fully expected needing to dig through half a dozen more problems after that one, so I was literally jumping around and shouting in excitement.

Read 7 comments and join the conversation 

Macintosh Floppy Drive Emulator Update

A couple of months ago, I posted a design sketch for an SD-card floppy disk drive emulator for classic Macintosh computers. Recently I finally got motivated enough to start building it. Using one of the oh-so-rare DB-19 connectors that I purchased a few weeks back, I rigged up a cable to connect the Mac’s external floppy port to a breadboard. Then I dug out an old CPLD board I built for an early Tiny CPU test, and wired all the floppy lines to the board’s I/O connector. The board is powered by the +5V from the floppy port.

This particular board has an Altera EPM7128S CPLD, which is so old that it actually runs at 5V (newer CPLDs run at 3.3V or below). That’s great for this purpose, because 5V is what the Mac provides and is also the voltage level on the Mac floppy data lines.

So far, I’ve built a successful blank disk emulator. It identifies itself as an 800K drive to the Mac, initially with no disk. Reading and writing of the interval drive registers works, as well as stepping the drive head. The PWM signal that tells the Mac the current drive motor RPM speed also works. By pushing a button on the board, you can “insert” a disk into the drive, but the disk is blank (it contains all 1’s).

If you push the button while the Mac is waiting for a boot disk, it thinks about it for a minute, then “ejects” the disk and shows the X-disk icon on the screen. If you boot from a regular floppy disk in the internal drive, then push the button to insert an external disk, the Mac asks “This disk is unreadable. Do you want to initialize it?” If you say yes, the Mac responds “Initialization failed! The disk is write-protected!”

It’s not very exciting yet, but it’s a good start. The next step will be to add a microcontroller and an SD card reader. With those pieces in place, I can start passing actual disk data to the CPLD, so it can pass the data on to the Mac.

Read 3 comments and join the conversation 

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 

An SD-card Floppy Emulator for Classic Compact Macs

While working on the “Plus Too” Mac Plus clone, I’ve started thinking further about a semi-related side project: a floppy drive emulator that works with actual classic compact Mac hardware (the Mac 128K, 512K/e, and Plus). These machines all have 400K or 800K floppy drives, and modern floppy drives are physically incapable of using disks in 400K/800K format. That means if you’ve got one of these classic Macs, you also need a second, slightly newer Mac with a high density floppy drive (Apple called them FDHD) so you can copy data back and forth between standard 1.4MB disks and 400K/800K disks. To get Mac software onto your Mac Plus, you need to download it from the web using a modern PC, copy it to a 1.4MB floppy, move that floppy to the FDHD-equipped Mac, use that Mac to copy the software to a 400K or 800K floppy, then finally move that floppy to the Plus. What a pain.

You could also use a modem, null-modem connection, or LocalTalk networking to get software onto the Plus, but the average hobbyist is even less likely to have the equipment necessary for those methods than for the floppy disk chain transfer.

The idea of a floppy emulator for compact Macs (using SD cards or similar media) has been discussed before in the Mac hobbyist community, but as far as I know, none exists. Maybe that means I’m the guy who should design one. I’ve spent a fair bit of time studying the details of the IWM controller chip and the floppy disk data encoding, and I understand enough to think that the project is feasible. Here are a couple of thoughts on what such an emulator would look like and how it would work.

DB-19

The emulator would be a small PCB with a DB-19 connector, that plugs directly into the floppy port. No cables required. It looks like finding a source for DB-19 connectors will be very difficult, though, so it might be necessary to make one somehow. None of the usual electronics supplies like Digi-Key have DB-19 connectors, and the few places on the web that do advertise them only have solder cup terminated connectors intended for making cables. And even those places look old and out of date, making me question whether they actually still have DB-19 connectors in stock.

Storage

My original idea was to put an SD card socket on the emulator, so you could fill the card with disk images using your PC, then put the card into the emulator. The main drawback is that not everyone has an SD card reader on their PC. Better would be a USB connector, and when connected to the PC the emulator would appear as a generic mass storage device. In that case, the actual storage still might be an SD card, or it could be generic flash ROM, or battery-backed RAM. I’m unsure if this would require worrying about wear-leveling and making a flash driver, though.

Supported Formats

The emulator would support 400K and 800K disk images in raw or DiskCopy 4.2 format. Maybe later it could also support 1.4MB formats, but that would require studying the SWIM design instead of IWM. And anyway if your Mac supports 1.4MB disks, it’s probably easier to just make them on a modern PC or Mac. The emulator would not support “super disks” larger than a real physical disk, because the floppy driver in the Mac’s ROM would not be able to use them. Although maybe this could be worked around with some kind of custom init that replaces the ROM floppy driver…

Number of Disks

The emulator would only emulate a single external disk drive. This is a bummer, but the floppy connector is only designed to connect to a single drive, and there are no pins for the Mac to select a specific drive or give a unique ID to a drive. Again, maybe this could be worked around with a custom floppy driver replacement and some non-standard use of the floppy data lines…

Read/Write

Both read and write operations would be supported. Read would probably be a lot easier to implement first, so the initial prototype would likely be read-only.

Variable Speed

The Mac 400K/800K drive was a variable speed drive, unlike PC floppy drives. This is why PC floppy drives are physically unable to read/write 400K or 800K floppies. For the purposes of emulation, though, I don’t think this matters at all. The emulator would ignore the drive RPM control signal coming from the Mac. The actual data rate is still constant, I believe. And even if it’s not constant, I think I can still work with it.

Implementation

The emulator would consist of an Atmel AVR microcontroller and SD card socket. The AVR would need about 12KB of internal RAM. The ATmega1284P looks good. A pre-existing SD-card FAT-reader library would be used to search the card for files with the .dsk extension, and read data chunks from them.

The AVR would use the 9 control/data lines on the floppy connector (documented by Apple) to communicate with the Mac, acting like a normal floppy drive. It would internally maintain the position of a virtual disk head, defined by the current track number and rotational position within the track. Track-to-track in/out movement of the virtual head would be performed by the Mac, using the control lines. When the emulator was instructed to step to a new track, it would load the data for the corresponding sectors from the SD card into a RAM buffer. This data would be GCR-encoded on the fly, and appropriate sector headers, lead-ins, lead-outs, checksums, and sync bytes would also be generated. The result would be a byte-for-byte replica of the low-level data format for that track on a real floppy disk.

Virtual rotational movement through the track would happen automatically, at a fixed rate (I think it’s 1 bit per 2 microseconds). When the Mac requested a read, the emulator would return the data at whatever rotational position was current. The Mac software would keep reading data until the sector it wanted came into position, just like for a real floppy. When the Mac requested a write, the emulator would overwrite data at whatever rotational position was current. This data would be GCR-decoded on the fly, headers/checksums/etc thrown-away, and the actual sector data written back to the SD card.

Read 10 comments and join the conversation 

« Newer Posts