floppy.cafe

MFM Encoding

There have been many encoding methods devised over the years, some can be applied to floppy disks and help reduce the magnetic flux transitions within this type of media. Common methods include FM, MFM, and MMFM. Each with its own pros and cons. Here we'll talk specifically about MFM encoding and how it pertains to your average 3.5" Floppy Disk.

Some facts:

Table of Contents

Pulses
The Algorithm
MFM Pulse Encoder
MFM Pulse Decoder
Further Reading

Pulses

When we talk about pulses, we're referring specifically to the timing of a flux transition. Floppy disks work by magnetizing a section of a physically spinning disk and the time between magnetic transitions indicate how many zeros there are in the signal. For example

The specific logic for timing can be represented with the following psuedocode.

# 2.5 microseconds (in clock cycles)
T_25 = 2.5 * F_CPU_HZ / 1000000

# 3.5 microseconds (in clock cycles)
T_35 = 3.5 * F_CPU_HZ / 1000000
  
def read_symbol:
  counter = 0
  while data_pin is low:
    counter++
  while data_pin is high:
    counter++

  if counter < T_25:
    return 0
  else if counter < T_35:
    return 1
  else 
    return 2

In this example, we are counting clock cycles. The timing needs to be very precise and you'll have to be very familiar with the clock speed of your particular device.

A cautionary tale: check the generated assembly (yeah, I know that's a bit intense) and make sure the compiler didn't inject 10,000 lines of boundary checks. Simple things like that can be enough to ruin your timing. When I wrote my original controller, I had to bust out some basic assembly to get it perfect.

The Algorithm

At it's core, the algorithm to produce an MFM encoded signal works as follows: to encode x, y, z the resulting signal would be generated like (x, x nor y, y, y nor z, z, ...)

Implementing this may seem easy, but there's a catch! The last bit of the signal will depend on the subsequent bit of the next signal. What this means in practice is that you can't really encode one byte at a time. Instead, you must stream the bits in a sequence, letting all of them flow together for your entire payload.

I think this is why most (all?) floppy disk controllers require you to write an entire sector at once. You can't just change the 3rd byte in place and call it good because that might have a cascading effect, ruining the timing of downstream bits. Instead, you must rewrite the whole sector at once to keep the timing information consistent.

MFM Pulse Encoder

Enter a comma delimmited list of hexadecimal values. For example: 0xA1, 0x13, 0x37. The encoded signal and accompanying pulses will be rendered below.



Encoded Signal

Flux Pulses

MFM Pulse Decoder

Enter a sequence of pulses in the form of S, M, or L. For example: LMSSMMSMMMSMMSLSSS. The value parsed from the signal will be rendered below.



Decoded data

Further Reading

Next, let's check out some FUNCTIONS that can be implemented for your floppy drive.