Z80onMDR - ZX Spectrum Z80 to Microdrive Converter

With the growing popularity of the excellent vDrive I decided to adapt Z80onDSK to create Microdrive cartridges instead of disks from Z80 snapshots. Anybody that has tried to copy tapes to a Microdrive is aware of the challenges especially with the later custom loaders and the aim of this utility is to make it as easy as possible to get games onto cartridge, including the ability to create compilations with a nice menu etc...

Initially I was only going to make this 48k only as figured that would cover most users, however, I was quickly able to adapt it to cover all just in case somebody wanted to use a Microdrive on a Toastrack or early Amstrad +3.

Compared to Z80onDSK there are a few differences. For this utility I decided to stick to a basic loader rather than M/C as understanding the ROM routines wasn't as simple as for 3DOS, plus I found it easier to enable things like multi-Microdrive support. I also tweaked the menu system to take up a lot less space as Microdrive capacity is a lot lower than +3 Disk. I also removed a lot of the memory tweaking options and the ability to switch ROMs as these don't really make sense on the machines that are compatible with an Interface 1. For 48k snapshots the utility also always turns off bank switching so the Ultimate Games (and others like Match Day) will work fine on a 128k machine.

I've also quickly converted the utility to create OPUS Discovery & MGT Plus D Disks, basically the same utility just different output.

I received a couple of requests for a utility to just create the program loader menu I've used in Z80onMDR for transfer to disk, so I've created MenuDSK to do this. It can handle up to 20 menu entries using the mock 128k menu style (shown below). It is wrapped in a basic loader and this can then be output to a variety of disk types (PlusD, OPUS, +3) plus also to tape for easy transfer to real drives.

Z80onMDR v1.6

Windows, Linux
& Mac OSX

Version History

  • v1.3 initial release
  • v1.3a removed incorrect error message
  • v1.4 added option to put the launcher into the printer buffer to remove screen corruption. This may or may not work as some games do use this area of memory
  • v1.4a improved printer buffer launcher
  • v1.4c added filename checks to stop same filename twice
  • v1.5 bug fix & new option to suppress run file creation
  • v1.6 added option to create a blank cartridge, with or without a menu

Z80onOPD v0.5

Windows, Linux
& Mac OSX

Version History

  • v0.1 initial release
  • v0.2 added double density disk support (360kB) and added filename checks to stop same filename twice
  • v0.3 added double sided double density support (720kB) and expanded menu to support max 16 snapshots per disk
  • v0.4 improved bootsector so it should now match the disk option. Added ability for the bootsector to be from either ROM v2.22 or v2.31 Quick DOS.
  • v0.5 new option to suppress run file creation

Z80onMGT v0.1

Windows, Linux

Version History

  • v0.1 initial release (this has all the functionality of v0.5 of Z80onOPD)

MenuDSK v0.4

Windows, Linux

Version History

  • v0.4 initial release

Worked Example

Quick example to show how to convert a .Z80 to MDR

To convert Three Weeks in Paradise type:

z80onmdr "Three Weeks in Paradise (1986)(Mikro-Gen)(48K-128K).z80"

This will create a MDR file with the following output:

+-------------------------------------------------------------------------------
| Z80onMDR v1.3 (c) 2020 Tom Dalby
+-------------------------------------------------------------------------------
| Single Snapshot Mode: "Three Weeks in Paradise (1986)(Mikro-Gen)(48K-128K).z80"
| Microdrive Cartridge Name: "ThreeWeeks" -> Size 127kB [S:0xfe]
| Single Snapshot to transfer, no menu required
| - Writing File: "run       " (BASIC A:10 L:38) #Sectors Used:1
+-------------------------------------------------------------------------------
| Processing: "Three Weeks in Paradise (1986)(Mikro-Gen)(48K-128K).z80"
| - Options -> Screen:Default, Filename:Default, LaunchPos:Default(Top)
| - Z80 Size: 42142bytes
| Z80 Snapshot Decode: [v1-48k-C]
+-----------------+---------------+---------------+---------------+-------------
| a=0x3b          | f=0x08        | bc=0x311a     | hl=0xf72d     | pc=0x0038
| sp=0xfff8       | i=0x3f        | r=0x0e        | bcol=0        | de=0x1113
| bc'=0x8900      | de'=0x0000    | hl'=0x3264    | a'=0x00       | f'=0x45
| iy=$5c3a        | ix=$5bd8      | di            | im 1
+-----------------+---------------+---------------+---------------+-------------
| Extracting Pages from Z80:
| - 5(10056) 2(15705) 0(16347)
| - Full Memory-Screen Compressed to: [D3]32098bytes
|   - Copying 3bytes from end of code to end of launcher
| Adding Files to Microdrive Image:
| - Writing File: "ThreeWeeks" (BASIC A:10 L:119) #Sectors Used:1
| - Writing File: "ThreeWee.0" (CODE S:16384 L:6912) #Sectors Used:14
| - Writing File: "ThreeWee.1" (CODE S:33438 L:32098) #Sectors Used:63
| - Writing File: "ThreeWee.2" (CODE S:16384 L:137) #Sectors Used:1
| Total bytes written 39266 vs. 42142 ->  7% Saved [#Sectors Left:173]
+-------------------------------------------------------------------------------
| Writing Out "Three Weeks in Paradise (1986)(Mikro-Gen)(48K-128K).mdr"
+-------------------------------------------------------------------------------

The utility creates 5 files on the Cartridge. The first is run which allows you to load the game straight from a reboot by typing RUN and enter. The second is ThreeWeeks which is the basic loader and then 3 code files which are the loading screen, the compressed main code and the final one the launcher code which is put into screen memory as there is nowhere else for it to go.

This Z80 snapshot doesn't come with a loading screen, more the screen is the game screen. In order to have something nicer to look at while loading you can add a custom screen using the -l option:

z80onmdr "Three Weeks in Paradise (1986)(Mikro-Gen)(48K-128K).z80" -l 3weeks.scr

This will create a MDR file with the following output:

+-------------------------------------------------------------------------------
| Z80onMDR v1.3 (c) 2020 Tom Dalby
+-------------------------------------------------------------------------------
| Single Snapshot Mode: "Three Weeks in Paradise (1986)(Mikro-Gen)(48K-128K).z80"
| Microdrive Cartridge Name: "ThreeWeeks" -> Size 127kB [S:0xfe]
| Single Snapshot to transfer, no menu required
| - Writing File: "run       " (BASIC A:10 L:38) #Sectors Used:1
+-------------------------------------------------------------------------------
| Processing: "Three Weeks in Paradise (1986)(Mikro-Gen)(48K-128K).z80"
| - Options -> Screen:"3weeks.scr", Filename:Default, LaunchPos:Default(Top)
| - Z80 Size: 42142bytes (+Additional Screen 6912bytes)
| Z80 Snapshot Decode: [v1-48k-C]
+-----------------+---------------+---------------+---------------+-------------
| a=0x3b          | f=0x08        | bc=0x311a     | hl=0xf72d     | pc=0x0038
| sp=0xfff8       | i=0x3f        | r=0x0e        | bcol=0        | de=0x1113
| bc'=0x8900      | de'=0x0000    | hl'=0x3264    | a'=0x00       | f'=0x45
| iy=$5c3a        | ix=$5bd8      | di            | im 1
+-----------------+---------------+---------------+---------------+-------------
| Extracting Pages from Z80:
| - 5(10056) 2(15705) 0(16347)
| - Full Memory-Screen Compressed to: [D3]32098bytes
|   - Copying 3bytes from end of code to end of launcher
| Adding Files to Microdrive Image:
| - Writing File: "ThreeWeeks" (BASIC A:10 L:119) #Sectors Used:1
| - Writing File: "ThreeWee.0" (CODE S:16384 L:6912) #Sectors Used:14
| - Writing File: "ThreeWee.1" (CODE S:33438 L:32098) #Sectors Used:63
| - Writing File: "ThreeWee.2" (CODE S:16384 L:6912) #Sectors Used:14
| Total bytes written 46041 vs. 49054 ->  6% Saved [#Sectors Left:160]
+-------------------------------------------------------------------------------
| Writing Out "Three Weeks in Paradise (1986)(Mikro-Gen)(48K-128K).mdr"
+-------------------------------------------------------------------------------

Notice the final file written is now 6912bytes long, this is the game screen with the launcher imbedded already. The previous example was only 137bytes long as it just required the launcher code.

For 128k snapshots the process is the same, the utility will just create a few more files to cover the additional memory banks.

Let us try Chase HQ 128k. Again type:

z80onmdr "Chase H.Q. (1989)(Ocean)(128K)[a].z80" -n ChaseHQ

You will notice I added a new option -n. This simply renames the files on the Cartridge to ChaseHQ instead of taking it from the input which would've been ChaseHQ198 which isn't as nice. The output is now:

+-------------------------------------------------------------------------------
| Z80onMDR v1.3 (c) 2020 Tom Dalby
+-------------------------------------------------------------------------------
| Single Snapshot Mode: "Chase H.Q. (1989)(Ocean)(128K)[a].z80"
| Microdrive Cartridge Name: "ChaseHQ198" -> Size 127kB [S:0xfe]
| Single Snapshot to transfer, no menu required
| - Writing File: "run       " (BASIC A:10 L:38) #Sectors Used:1
+-------------------------------------------------------------------------------
| Processing: "Chase H.Q. (1989)(Ocean)(128K)[a].z80"
| - Options -> Screen:Default, Filename:"ChaseHQ   ", LaunchPos:Default(Top)
| - Z80 Size: 109247bytes
| Z80 Snapshot Decode: [v3(54)-128k]
+-----------------+---------------+---------------+---------------+-------------
| a=0x00          | f=0x54        | bc=0x0000     | hl=0x5d0a     | pc=0x1f3d
| sp=0x61a2       | i=0x3f        | r=0x2e        | bcol=0        | de=0x5d0f
| bc'=0x1721      | de'=0x369b    | hl'=0xf8ad    | a'=0x00       | f'=0x44
| iy=$5c3a        | ix=$03d4      | ei            | im 1          | 0x7ffd=0x10
+-----------------+---------------+---------------+---------------+-------------
| AY Chip Registers Set-up        | 0xfffd=0x08   | ay1=0x00      | ay2=0x00
| ay3=0x00        | ay4=0x00      | ay5=0x00      | ay6=0x00      | ay7=0x00
| ay8=0xff        | ay9=0x00      | ay10=0x00     | ay11=0x00     | ay12=0x00
| ay13=0x00       | ay14=0x00     | ay15=0xff     | ay16=0x00
+-----------------+---------------+---------------+---------------+-------------
| Extracting Pages from Z80:
| - 0(8314) 1(13548) 2(16384) 3(15870) 4(14291) 5(13848) 6(13673) 7(13209)
| - Full Memory-Screen Compressed to: [D3]33503bytes
|   - Copying 3bytes from end of code to end of launcher
| - Additional 128k Memory Compression:
|   - Page 1 Compressed to: 11223bytes + 77 for unpack code
|   - Page 3 Compressed to: 12162bytes
|   - Page 4 Compressed to: 11556bytes
|   - Page 6 Compressed to: 11000bytes
|   - Page 7 Compressed to: 10480bytes
| Adding Files to Microdrive Image:
| - Writing File: "ChaseHQ   " (BASIC A:10 L:211) #Sectors Used:1
| - Writing File: "ChaseHQ .0" (CODE S:16384 L:6912) #Sectors Used:14
| - Writing File: "ChaseHQ .1" (CODE S:32179 L:11300) #Sectors Used:23
| - Writing File: "ChaseHQ .2" (CODE S:32255 L:12162) #Sectors Used:24
| - Writing File: "ChaseHQ .3" (CODE S:32255 L:11556) #Sectors Used:23
| - Writing File: "ChaseHQ .4" (CODE S:32255 L:11000) #Sectors Used:22
| - Writing File: "ChaseHQ .5" (CODE S:32255 L:10480) #Sectors Used:21
| - Writing File: "ChaseHQ .6" (CODE S:32033 L:33503) #Sectors Used:66
| - Writing File: "ChaseHQ .7" (CODE S:16384 L:137) #Sectors Used:1
| Total bytes written 97261 vs. 109247 -> 11% Saved [#Sectors Left:57]
+-------------------------------------------------------------------------------
| Writing Out "Chase H.Q. (1989)(Ocean)(128K)[a].mdr"
+-------------------------------------------------------------------------------

Finally the utility can create compilations with a nice menu screen, see right.

To do this you just need to put the .Z80 names in the command line one after each other. The following example creates a compilation Cartridge called UPtG 01 with a few well known games on it

To create the compilation type:

./z80onmdr -m "UPtG 01" "Cookie (1983)(Ultimate Play The Game)(16K).z80" -n Cookie "Jetpac (1983)(Ultimate Play The Game)(16K).z80" -n JetPac "Pssst (1983)(Ultimate Play The Game)(16K).z80" -n PSSST "Tranz Am (1983)(Ultimate Play The Game)(16K).z80" -n TranzAm

+-------------------------------------------------------------------------------
| Z80onMDR v1.3 (c) 2020 Tom Dalby
+-------------------------------------------------------------------------------
| Entering Batch Mode:
| 1) "Cookie (1983)(Ultimate Play The Game)(16K).z80" [49182bytes]
| 2) "Jetpac (1983)(Ultimate Play The Game)(16K).z80" [14636bytes]
| 3) "Pssst (1983)(Ultimate Play The Game)(16K).z80" [15318bytes]
| 4) "Tranz Am (1983)(Ultimate Play The Game)(16K).z80" [14205bytes]
+-------------------------------------------------------------------------------
| Microdrive Cartridge Name: "UPtG 01   " -> Size 127kB [S:0xfe]
| 4 Snapshots to transfer, building menu
| - Writing File: "run       " (BASIC A:10 L:476) #Sectors Used:1
+-------------------------------------------------------------------------------
| Batch #1 -->
| Processing: "Cookie (1983)(Ultimate Play The Game)(16K).z80"
| - Options -> Screen:Default, Filename:"Cookie    ", LaunchPos:Default(Top)
| - Z80 Size: 49182bytes
| Z80 Snapshot Decode: [v1-48k-U]
+-----------------+---------------+---------------+---------------+-------------
| a=0x50          | f=0x4c        | bc=0x0700     | hl=0x408e     | pc=0x749a
| sp=0x5ef8       | i=0x3f        | r=0x00        | bcol=0        | de=0x6373
| bc'=0x0080      | de'=0x635f    | hl'=0x588e    | a'=0x80       | f'=0x47
| iy=$5c3a        | ix=$5c7a      | di            | im 1
+-----------------+---------------+---------------+---------------+-------------
| Extracting Pages from Z80:
| - 5(16384) 2(16384) 0(16384)
| - Full Memory-Screen Compressed to: [D3]7520bytes
|   - Copying 3bytes from end of code to end of launcher
| Adding Files to Microdrive Image:
| - Writing File: "Cookie    " (BASIC A:10 L:119) #Sectors Used:1
| - Writing File: "Cookie  .0" (CODE S:16384 L:6912) #Sectors Used:14
| - Writing File: "Cookie  .1" (CODE S:58016 L:7520) #Sectors Used:15
| - Writing File: "Cookie  .2" (CODE S:16384 L:137) #Sectors Used:1
| Total bytes written 14688 vs. 49182 -> 70% Saved [#Sectors Left:221]
+-------------------------------------------------------------------------------
| Batch #2 -->
| Processing: "Jetpac (1983)(Ultimate Play The Game)(16K).z80"
| - Options -> Screen:Default, Filename:"JetPac    ", LaunchPos:Default(Top)
| - Z80 Size: 14636bytes
| Z80 Snapshot Decode: [v1-48k-C]
+-----------------+---------------+---------------+---------------+-------------
| a=0x00          | f=0xdc        | bc=0x0000     | hl=0x5e6a     | pc=0x0038
| sp=0x5ff8       | i=0x3f        | r=0x36(b7)    | bcol=0        | de=0x5e6f
| bc'=0x1021      | de'=0x369b    | hl'=0x0000    | a'=0xff       | f'=0x01
| iy=$5c3a        | ix=$5b8e      | di            | im 1
+-----------------+---------------+---------------+---------------+-------------
| Extracting Pages from Z80:
| - 5(13834) 2(ovf:16576)(261) 0(507)
| - Full Memory-Screen Compressed to: [D3]8020bytes
|   - Copying 3bytes from end of code to end of launcher
| Adding Files to Microdrive Image:
| - Writing File: "JetPac    " (BASIC A:10 L:119) #Sectors Used:1
| - Writing File: "JetPac  .0" (CODE S:16384 L:6912) #Sectors Used:14
| - Writing File: "JetPac  .1" (CODE S:57516 L:8020) #Sectors Used:16
| - Writing File: "JetPac  .2" (CODE S:16384 L:137) #Sectors Used:1
| Total bytes written 15188 vs. 14636 ->  4% Larger [#Sectors Left:189]
+-------------------------------------------------------------------------------
| Batch #3 -->
| Processing: "Pssst (1983)(Ultimate Play The Game)(16K).z80"
| - Options -> Screen:Default, Filename:"PSSST     ", LaunchPos:Default(Top)
| - Z80 Size: 15318bytes
| Z80 Snapshot Decode: [v1-48k-C]
+-----------------+---------------+---------------+---------------+-------------
| a=0x00          | f=0xdc        | bc=0x0000     | hl=0x5dbc     | pc=0x0038
| sp=0x5ee4       | i=0x3f        | r=0x1c(b7)    | bcol=7        | de=0x5dc1
| bc'=0x0821      | de'=0x369b    | hl'=0x0000    | a'=0xff       | f'=0x01
| iy=$5c3a        | ix=$5c7a      | di            | im 1
+-----------------+---------------+---------------+---------------+-------------
| Extracting Pages from Z80:
| - 5(ovf:16635)(14531) 2(ovf:16571)(256) 0(497)
| - Full Memory-Screen Compressed to: [D3]8399bytes
|   - Copying 3bytes from end of code to end of launcher
| Adding Files to Microdrive Image:
| - Writing File: "PSSST     " (BASIC A:10 L:119) #Sectors Used:1
| - Writing File: "PSSST   .0" (CODE S:16384 L:6912) #Sectors Used:14
| - Writing File: "PSSST   .1" (CODE S:57137 L:8399) #Sectors Used:17
| - Writing File: "PSSST   .2" (CODE S:16384 L:137) #Sectors Used:1
| Total bytes written 15567 vs. 15318 ->  2% Larger [#Sectors Left:156]
+-------------------------------------------------------------------------------
| Batch #4 -->
| Processing: "Tranz Am (1983)(Ultimate Play The Game)(16K).z80"
| - Options -> Screen:Default, Filename:"TranzAm   ", LaunchPos:Default(Top)
| - Z80 Size: 14205bytes
| Z80 Snapshot Decode: [v1-48k-C]
+-----------------+---------------+---------------+---------------+-------------
| a=0x00          | f=0xdc        | bc=0x0000     | hl=0x5da6     | pc=0x0038
| sp=0x5ef8       | i=0x3f        | r=0x0c(b7)    | bcol=0        | de=0x5dab
| bc'=0x0f21      | de'=0x369b    | hl'=0x0000    | a'=0xff       | f'=0x01
| iy=$5c3a        | ix=$5c7a      | di            | im 1
+-----------------+---------------+---------------+---------------+-------------
| Extracting Pages from Z80:
| - 5(13416) 2(ovf:16575)(260) 0(495)
| - Full Memory-Screen Compressed to: [D3]8577bytes
|   - Copying 3bytes from end of code to end of launcher
| Adding Files to Microdrive Image:
| - Writing File: "TranzAm   " (BASIC A:10 L:119) #Sectors Used:1
| - Writing File: "TranzAm .0" (CODE S:16384 L:6912) #Sectors Used:14
| - Writing File: "TranzAm .1" (CODE S:56959 L:8577) #Sectors Used:17
| - Writing File: "TranzAm .2" (CODE S:16384 L:137) #Sectors Used:1
| Total bytes written 15745 vs. 14205 -> 11% Larger [#Sectors Left:123]
+-------------------------------------------------------------------------------
| Writing Out "UPtG01.mdr"
+-------------------------------------------------------------------------------

Command Line Arguments

+-------------------------------------------------------------------------------
| Z80onMDR v1.4a (c) 2020 Tom Dalby
+-------------------------------------------------------------------------------
| Usage: Z80onMDR [global options] snapshot.z80 [snapshot settings]
|
| [global options]
|   -m NAME - specify Microdrive Volume & Output Name, length 10 alphanumeric
|             only. Will truncate if >10 and remove non-alphanumeric chars.
|             This will also be the Menu name in batch.
|             
|   -s NUM  - # of sectors on Microdrive, min 170 (85kB) max/default 254 (127kB)
|   -o      - override estimated size check if showing Microdrive as oversized
|
| [snapshot settings]
|   -n NAME - specify filename, length 10 alphanumeric only.
|             Will truncate if >10 and remove non-alphanumeric chars.
|             
|   -l FILE - add a custom loading screen. Screen must be in binary .scr format
|             and exactly 6912bytes long.
|   -c m,b  - move the launcher code within the screen, m for middle or
|             b for bottom. Default (no -c argument) is put at the top
|   -p      - use PRTBUF (0x5b00-0x5bff) to store the launcher. This will
|             remove screen corruption but also probably not work as some
|             games do use this memory area, Lords of Midnight for example
|
| Batch Mode is activated if more than one z80 snapshot specified, example:
|
| Z80onMDR -m Games01 snapshot1.z80 -s screen1.scr snapshot2.z80 -n game1
|
| Which creates an MDR containing snapshot 1 & snapshot2. snapshot1 has an
| alternate loading screen, snapshot2 has the filenmae game1 and the output,
| menu & cartridge volume names are all Games01. Max 8 snapshots per cartridge
+-------------------------------------------------------------------------------