Reading M20 floppies with modern controllers
By Benjamin Eberhardt
When reading M20 floppies under Linux with a standard pc controller (48 tracks per inch, sector size 256 bytes, 16 sectors per track, MFM) one likely has to skip the first 4 kiB/ track0, as many PC controllers cannot read the FM track:
$ setfdprm /dev/fd1 tpi=48 ssize=256 sect=16 dd ds
$ sdd -noerror try=5 iseek=4096 oseek=4096 if=/dev/fd1 of=floppy.img bs=256 count=1104
The first 4 kiB of this image will be zero. More information about setfdprm/ fdutils and the sdd
tool can be found here. The main reason to use sdd
over dd
was the additional seek parameter on the input side.
Other options, using modern USB-floppy-controllers, are also able to read the FM track:
Controller options
-
- Can not write *.img files back to floppy directly (need to convert to raw flux files first with e.g. the HxC Floppy Emulator).
- Mainly made for reading floppies, writing floppies is possible, but considered a "bonus" and is not officially supported (e.g. if one needs help in the support forums)
- Reading M20 floppies works and is described e.g. here.
-
- Can read and write IMG and IMD files.
- Can read and write mixed FM/MFM floppies to sector formats (since v1.6).
- Supports FM data padding in IMG files (since v1.8), to be compatible with the file size of the original pc-controller approach.
Greaseweazel setup
(Text based on Greaseweazel v1.8, a Teac FD-55BR drive and Mame v.251, all running on Ubuntu 22.10)
Get all necessary parts and set up the Greaseweazel v4 according to the documentation.
Now one has to issue only a single command to the gw
-tool and it will take care of handling the mixed format and padding the lower density FM data all by itself:
gw read --format="olivetti.m20" floppy.img
gw write --format="olivetti.m20" floppy.img
When reading with a 1.2 MB HD drive one has to pass an additional --tracks='step=2'
parameter.
This produces an image with the size of 280 kiB. One has to keep in mind that the FM track is only 2 kiB in size, while the MFM tracks are 4 kiB. The total amount of userdata is only 278 kiB. The additional 2 kiB are padding.
It seems to be a de-facto standard to pad the lower density FM data to 4 kiB to achieve a homogeneous track size in the img file. This might be historically motivated. The original method of imaging with a pc controller seeked over the first track in "MFM mode", which automatically created a 4 kiB offset. This resulted in a 280 kiB file.
In order to do the padding while also reading the FM part, one has two options:
- Per track: Pad the entire track0 with an additional 2 kiB (usually used in manual conversion approaches where FM and MFM are read separately and joined by
dd
) - Per sector: Pad every single FM sector with an additional 128 Bytes (MAME and GW use this).
Alternatively it is also possible to write directly into IMD files, which is a somewhat "smarter" image format, supporting per-sector metadata. Padding is only done in IMG files, since they are plain sector representations of the floppy. Let's look into reading, writing, and padding in more detail (usually one you should not need this):
Manual config and padding options
To have some more control over how the img file is created from the floppy flux data, one can create a custom diskdefs.cfg
config for M20 floppies. The following reproduces the original behaviour:
# Greaseweazel v1.8 diskdefs.cfg for Olivetti M20 360 kB DD floppies
disk olivetti.m20
cyls = 35
heads = 2
tracks 0.0 ibm.fm
secs = 16
bps = 128
rate = 125
img_bps = 256
end
tracks * ibm.mfm
secs = 16
bps = 256
rate = 250
end
end
Then, add the diskdefs
parameter to the arguemnts:
gw read --diskdefs diskdefs.cfg --format="olivetti.m20" floppy.img
The img_bps
parameter in the config file controls the target size of the sectors in the IMG file. By default, gw will attempt to create an equal size of 256 Bytes for all sectors, hence padding every single FM track with another 128 Bytes.
As a practice example, let's remove the img_bps
parameter, which will deactivate sector padding. Subsequently we will use manual track padding, to pad the entire FM track to 4 kiB:
Reading
Reading the floppy content into an img file without any extra padding (img_bps
parameter removed):
gw read --diskdefs diskdefs.cfg --format="olivetti.m20" floppy_unpadded.img
This produces an image with the size of 278 kiB. In order to convert the image to the homogeneous the 4 kiB / track sizing, one needs to add an additional 2 kiB of zeros to pad the first track:
dd if=floppy_unpadded.img of=floppy.img bs=2048 count=1
dd if=floppy_unpadded.img of=floppy.img bs=2048 skip=1 seek=2
As a sidenote: Mame actually assumes every one of the 16 sectors in the FM track to be padded with 128 Bytes, instead of padding the entire track0 with an additional 2 kiB (like done here). The resulting track-padded image can however still be loaded into MAME, since only the very first sector in the FM track on the floppies seems to contain data anayways. Due to this, the difference between track and sector padding vanishes.
Writing
For writing a 280 kiB image back to floppy, one has to reverse the procedure and remove the track padding:
dd if=floppy.img of=floppy_unpadded.img bs=2048 count=1
dd if=floppy.img of=floppy_unpadded.img bs=2048 skip=2 seek=1
Then the image can be written with a single command, based on the mixed floppy composition defined in the config:
gw write --diskdefs diskdefs.cfg --format="olivetti.m20" floppy_unpadded.img
Another MAME sidenote: While we use 0s for the padding, MAME seems to use 1s to pad the sectors. If the image has previously been created/ converted in MAME one can investigate the original image e.g. with dd and hexdump. By increasing the skip parameter to odd numbers one can skip to the padding data:
dd if=floppy.img bs=128 skip=1 count=1 |hexdump -v -C
When writing back the first 2 kiB of such a mame-created image file, one would write some of the non-zero sector-padding data back to the disk, which does not technically belong there. Assuming again that for the M20 only the first sector contains data, the conversion can also be done by only copying the first sector to the image, and then skipping the rest of the first track:
dd if=floppy_mame.img of=floppy.img bs=128 count=1
dd if=floppy_mame.img of=floppy.img bs=4096 skip=1 seek=1
None of the known (non-dos) images contain any data other than in the first sector/ first 128 bytes, so the method should be safe to use, but better double check.
Note: In any case, an M20 image created/ converted by MAME, will end up having a different checksum once it has been written to floppy and read back. This is simply because the padding data is different.
Drive
Should be a 360kB 40 track drive. Options include:
The newer 1.2 MB, 80 track HD drives are able to read the M20 35 track floppies, but might not write them well, due to narrower track size.
Media
- Use 5+1⁄4-inch DD 360 kB floppies.
- Possible to use 720 kB QD? They are supported by the M20 natively, but I have never seen such a floppy.
- Possible to use 1.2M HD? According to this article it might be possible to re-format this media for DD for use in the M20.
Reading and writing BASIC codes
An IMG disk image can now be explored with the m20floppy tool. When extracting BASIC codes from the floppy image, it is usually obtained in a "tokenized" form (unless saved with SAVE,A under pcos). In order to decypher the BASIC codes, one can use the "Basic De-Tokenizer for M20 - Basdetok", to tranlate into ASCII. After conversion, the files can be modified on the host machine. The files can also be written back to the image file in ASCII format, given that there is enough space left on the floppy. When writing back, one needs to make sure that line breaks are single "CR". A helpful script to compile basdetok can be found here.
The character set for the M20 was country dependent. A (incomplete) list to translate some of the obtained characters can be found here or here as sed rules.
Example for reading a basic file from an IMG originally created with a West German charset:
m20 floppy.img get program
basdetok -m20 program |tr "\r" "\n" |sed '{s/{/ä/g;s/|/ö/g;s/}/ü/g;s/\[/Ä/g;s/\\/Ö/g;s/]/Ü/g;s/~/ß/g;s/@/§/g}' > program.bas
Now program.bas
can be edited and written back to the image:
cat program.bas |tr "\n" "\r" |tr -d "\n" | sed '{s/ä/{/g;s/ö/|/g;s/ü/}/g;s/Ä/\[/g;s/Ö/\\/g;s/Ü/]/g;s/ß/~/g;s/§/@/g}' > program
m20 floppy.img put program
Then write the image back to floppy or run with MAME.
Using floppy images directly on the M20
It is possible to connect the well-known Gotek floppy emulator directly to the M20. If you are interested to explore this possibility, read this article.
Page log
- November 9, 2024 - Moved (and expanded) Gotek content in a specifically dedicated page.
- February, 19, 2024 - Updated information about the Gotek. Added related pictures.
- January, 14, 2024 - Updated information about the Flashfloppy firmware and track padding.
- July 26, 2023 - Added section about the Gotek drive.
- May 27, 2023 - First version of the page.
Olivetti is a registered trademark of Telecom Italia. This site is not related to Olivetti nor to Telecom Italia. The material presented is meant for personal use only and is shared in a "fair use" spirit. If you own the copyright of some of the stuff presented here and you think it should be removed, please contact the webmaster.