Good news, everyone! I’ve just made a computer nobody’s ever heard of load a program from a floppy disk!

Update, 2017-12-08: I actually got this wrong — I mean, it worked, but it would only load programs smaller than 512 bytes (one sector). Turns out that the bootloader in ROM has an exciting bug which needs a workaround, making life much more complex. I’ve updated the document.

Context

…so the backstory is: I’m the proud owner of possibly one of the best Z80 portable computers ever made, the Amstrad NC200. It’s actually my second, but I forgot to take the five C batteries out of my old one, and they burst and spewed corrosive gunk all over the motherboard, wrecking it. My new one arrived a few weeks ago.

[Terrible picture of an NC200]

I’m not going to go into the history — it’s complicated and I tend to get enthusiastic — but this machine is a Z80 with 128kB RAM expandable up to 1128kB (I have the upgrade), a 720kB floppy disk drive, a pretty good 80x16 character monochrome screen, an excellent keyboard, and would run for up to ten hours on a set of five C batteries (I use a power supply). In onboard ROM was a set of excellent productivity software including a word processor, spreadsheet, and a copy of R.T. Russell’s superb BBC Basic to write your own programs with.

The only problem is that as the software’s all in ROM, trying to run, say, a Unix on it is hard. But it turns out that Amstrad put enough escape hatches in that it’s possible.

Needless to say, don’t do any of this if you have data you want on your machine. It’ll be a dead loss.

Running a program from floppy

(As far as I can tell, I am the first person ever to figure this out. It only took about two weeks of poring through ROM disassembly. Go me.)

The undocumented Function+R key sequence causes the NC200 to load and run a program from a specially-formatted floppy disk. Making such a floppy disk is dead easy once you know the secret, and practically impossible if you don’t. The secret is: it’s a FAT12 filesystem with one extra reserved sector, inside which there is a second copy of the boot sector. If these both look good, then the file called AUTO.PRG in the root directory will be loaded at 0x4000 and run.

No, I don’t know why Ranger (who Amstrad subcontracted to do the floppy disk routines) did it like that.

But there’s more to it than that.

That extra reserved sector pushes the rest of the filesystem up by one sector. This means that the DOS clusters aren’t aligned with track boundaries any more. This shouldn’t be a problem, but… Ranger’s software is unable to access these clusters, and will error out if you try to make it access one. So in order to load files which span multiple tracks, you need to mark these clusters as bad so that your file avoids them. This actually adds up to 1/9th of the disk’s capacity.

So, what I have is a carefully hand-tooled filesystem image, with all the bad clusters marked in the right place. It’s as small as I could make it and still have enough space for a boot program and two 16kB data files (which is what I need to load Fuzix). The boot block contains a partition table for easy access to the rest of the disk, on which you could put a proper filesystem.

The easiest way to create such an image is to use Linux and this precanned boot block.

bootblock.img.gz 140 bytes

A pregenerated bootable disk image for the NC200.

bootblock.asm.gz 800 bytes

z80asm source code to generate the disk image.

Do this:

$ zcat bootblock.img.gz | dd of=/dev/fd0 bs=512 count=2
$ mount /dev/fd0 /mnt -t vfat
$ cp auto.prg /mnt/auto.prg
$ umount /mnt

…and that’s all you need.

The resulting file system cannot be mounted by the NC200’s filer itself — it doesn’t understand the extra reserved sector, and will complain it’s not formatted. But Linux will mount it fine, so use your favourite tool to assemble the program below and copy it onto the floppy, calling it AUTO.PRG. Insert the floppy into the NC200 and press Function+R. It’ll load and run. Note that this program is different to the SRAM example above.

txtoutput:   equ 0xb81e ; prints a string
diskservice: equ 0xba5e ; FDD routines

    org 0x4000
main:
    ld c, 0x30 ; r_finish
    call diskservice
loop:
    ld hl, .str.hello
    call txtoutput
    jr loop

.str.hello: db "Hello, world! ", 0
hello-fdd.bin 28 bytes

Preassembled version of the Floppy Hello World program.

We call r_finish in order to turn the floppy disk motor off before starting our program (otherwise it’ll run forever). Just like the SRAM version, you get to use all the standard system calls.

Running programs from SRAM card

This one’s been known about for years; but a lot of the documentation is subtly wrong, however, and is mostly aimed at the NC100, which didn’t have a floppy drive. So I’m focusing on how to achieve this from the NC200 here.

The undocumented Function+X key sequence causes the NC200 (and NC100 and NC150) to run a program written in a special format to the SRAM card. To make this work you can either copy the program directly to the card via a laptop with a PCMCIA slot, or use the NC200 itself. I’m going to cover the latter only, because my SRAM card has no battery in it so I have to leave it plugged in or it loses its contents.

What you do is you assemble a Z80 program with a special header, put it on a floppy, then use the NC200 to copy the program to the card. Here’s an example program, suitable for assembling with z80asm:

txtoutput: equ 0xb81e ; prints a string

    org 0xc210
    jp start
    ds 0xc220 - $

start:
    ld hl, .str.hello
    call txtoutput
    jr start

.str.hello: db "Hello, world! ", 0
hello-sram.bin 39 bytes

Preassembled version of the SRAM Hello World program.

The binary must be an image starting at 0xc210. The first 3 bytes must be a jp 0xc220 instruction. (The program won’t run if it’s not.) Note that this is not the same header that you need when writing a program directly to the card!

To install it, do Function+F to open the floppy drive browser, select the binary with SPACE, copy it to internal memory with C; then, switch to the RAM drive browser with Function+L, format the SRAM card with Menu, F, M, select your binary with SPACE and install it with Menu, T, P.

Once done, you can run the program with Function+X. The first 16kB of the card will be mapped in at 0xc000, in the upper ROM bank, and your entrypoint is called. You can make use of all the native OS services — the OS will bank switch automatically.

Cleaning up after yourself

If you’ve tried any of these, you’ll probably be wondering how to exit the programs. Good news — there’s an easily accessible hard reset function. Turn the machine off with the button above the keyboard. Then hold Function + Stop + <-Del, and press the power button again. The NC200 will beep and wipe its memory, ready for another go.

Extra bonus content!

While disassembling my way through the ROM, I found this:

$ strings ranger.bin
Copyright RANGER COMPUTERS, NORTHAMPTON, ENGLAND, NN5 6JG
Test bed software for disk i/f for NC200 V0.41 
New Interrupts 
English Language
0123456789ABCDEF 
           NC200 Disk Test Suite V0.41
   A - Reset disk            H - Spin speed
   B - Seek randomly
   C - Seek sequentially
   D - Write test         (wipes existing disk data)
   E - Format test        (wipes existing disk data)
   F - Head Alignment     (wipes existing disk data)
   G - Disk change
STOP - Quit

It turns out there’s a complete floppy disk drive test and diagnostics suite in there! And it’s really easy to get at from native code (but won’t run from BBC Basic). You need this program:

diskservice: equ 0xba5e ; FDD routines

    org 0x4000
main:
    ld c, 0x30 ; r_finish
    call diskservice
    ld c, 0x0 ; r_test
    jp diskservice
diagnostics.bin 10 bytes

Preassembled version of the diagnostics tool launcher.

Copy onto a bootable floppy, call it AUTO.PRG, and it’ll boot and enter the tool. The SRAM version is left as an exercise for the reader.

Other tools

Most programming documentation comes from NC100 IO Specification on cpcwiki, very kindly contributed by Cliff Lawson (the Amstrad project manager). It goes into reasonable detail of all the system call entry points as well as the IO ports, and should be enough to write useful programs. There’s also a NC 100/150/200 IO Specification which just lists the differences between the different machines which is somewhat sparser.

Back in 2003ish, I wrote a tool to extract files from SRAM cards (I had a battery in mine back then). This may be of interest to people wanting to recover data.

Believe it or not, there is still an NC user’s group.