* for Emacs: -*- mode:indented-text; mode:outline-minor -*-

            ZCN v1.2 - (c) 1994-1999 Russell Marks

       A free CP/M-like operating system for the Amstrad NC100.

* License

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

[The GNU GPL is in the file `COPYING'.]

* About ZCN

ZCN is an alternative operating system for the NC100. Features

- a high level of CP/M compatibility
- fast switching between ZCN and the ROM software, and file transfer
  between the two
- can run BBC Basic (from ROM) as if it were a native ZCN program
- command processor (shell) with many internal commands
- many external commands and third-party programs
- optional online help (using `man')
- 46k free for programs to run in
- terminal emulator with 120x10 text resolution
- keyboard handler with 128-char keyboard buffer
- context saving while power is off
- support for the serial port at speeds up to 19200 baud
- printer (i.e. parallel port) support
- auto power-off after a given idle time
- warnings when main, backup, or memory card batteries are low
- console redirection to serial port or printer
- washes whiter than other powders

ZCN is modelled quite closely on the CP/M operating system common on
8080 and Z80 machines in the late 70s and early 80s. (It is most
common in the UK today on Amstrad PCWs.) I decided to do this as there
is a great deal of public domain and other zero cost software for
CP/M, including text editors, simple C compilers, Z80 assemblers, a
few games, etc. CP/M is also, in my opinion, well suited to running on
small Z80 systems. ZCN's CP/M compatibility is sufficient to run most
CP/M 2.2 programs.

** Should I use ZCN?

You should probably consider using ZCN if you like the idea of a
portable CP/M box, or want to use the NC100 as something a bit closer
to a `real computer'. These are the two reasons I originally started
writing ZCN.

** Warning!

If you want to still be able to use the built-in ROM software without
losing any of your current data, you *MUST* transfer and run the
`rrinit' program before trying to run ZCN. If you don't, you'll lose
any data held in the 64k of internal memory! (This means losing not
only any files in both the upper and lower memory, but also any

If you don't care about the ROM software, or don't care about losing
currently-held data, you shouldn't bother with `rrinit'.

(There's more on `rrinit' at the appropriate point below.)

** Requirements

ZCN needs the following to install and run successfully:

- An Amstrad NC100 Notepad

- At least one PCMCIA memory card, which will need to be reformatted
  in ZCN's format

- A computer with a serial link to the NC100, and the
  capability to send files using the XMODEM protocol

If you want to save the data currently in the internal memory, the
memory card must be at least 128k (64k of it will be used to save the

You will also need a basic knowledge of using CP/M, though a
reasonably capable MS-DOS and/or Unix user should be able to get along
ok. (Hey, it worked for me... :-))

* Installing ZCN

The installation guide below assumes you are installing from a Unix or
MS-DOS machine. It should be clear what to do on other machines
though; you just need to know how to XMODEM a file across, and how to
send a plain ASCII file. Normally the easiest way is to use a serial
comms program of some sort.

** Getting ZCN up and running for the first time

*** Saving your existing data

[If you don't care about using the ROM software, or don't mind losing
all the data in the internal memory, skip ahead to the next section,
`Booting ZCN via a Serial Link'.]

ZCN uses the NC100's 64k of RAM as more normal computers generally use
RAM - as an area to load programs into, and an area to use for
temporary workspace, etc. Unfortunately, this is not compatible with
the way the built-in software works, so you'll lose all your existing
data in memory unless you save it first. `rrinit' is a program which
lets you save your data like this. (You'll be able to restore it later
using `runrom'. More on that later on.)

To run `rrinit', you'll need a memory card of at least 128k in size.
It should probably be the card you intend to copy ZCN onto, but it
doesn't have to be. Bear in mind that the card will be reformatted in
ZCN's format, and any data currently on it will be lost!

You must also have at least one file stored in memory on your NC100,
as the ROM software doesn't let you do serial file transfers
otherwise. (If you haven't got any files in memory, just create a
small file with the word processor. It doesn't matter what's in it or
what it's called, just that it's there.)

First you need to setup the serial link. You should set the baud rate
to 2400 baud on the `remote' computer, as transfers seem to be a bit
hairy (for the ROM software at least) at higher speeds.

After that, *make sure there isn't any memory card in the NC100's
slot*, then do the following:

Key                     Reason
---                     ------

Function + S                  go to terminal program
Menu, down*3, left*2, Stop    use 2400 baud
                        (you may need more or less lefts,
                        depending on the current setting)
<type a few characters on the NC100 and `remote' computer to check
 the link is working ok>
<start XMODEM send (or `upload') of `rrinit.bin' on `remote' computer>
Stop                    quit terminal program
Function + L                  load document
Menu, T, M, rrinit, return    XMODEM receive `rrinit'
<wait for transfer to finish>
Stop                    return to file selector
<now insert the memory card>
Menu, F, <possibly Y>, Stop   format card (answer `Y' if it prompts you)
<make sure the `rrinit' file is the currently-highlighted one>
Menu, T, P, Stop        write rrinit to memory card
Stop                    exit file selector
Function + X                  run rrinit

[NB: `rrinit.bin' is in the `bin' subdirectory.]

Almost immediately after you do the function-X, rrinit should say
"Snapshot written - press Stop". Pressing Stop then returns you to the
NC100's main menu.

Now you should be ready to run ZCN, so here goes...

*** Booting ZCN via a Serial Link

[If you are upgrading an existing version of ZCN, skip ahead to
`Installing a new version using an old one', which will be rather more

First you need to setup the serial link. You should set the baud rate
to 2400 baud on the `remote' computer, as transfers seem to be a bit
hairy at higher speeds. (ZCN itself can cope with file transfers at up
to 19200, but the ROM software seems to be more picky. So for this
transfer, it's best to stick with 2400.)

Now you should cold-boot the NC100. Do this by turning it off and,
while holding down Function, Stop and `<-Del', turning it back on.

Next you should do the following:

Key                     Reason
---                     ------
Function + S                  go to terminal program
Menu, down*3, left*2, Stop    set speed to 2400 baud
<type a few characters on the NC100 and `remote' computer to check
 the link is working ok>
<start XMODEM send (or `upload') of `zcn.bin' on `remote' computer>
Stop                    quit terminal program
Function + N, x, return       create junk document
x                       put junk in it
Function + L                  load document
Menu, T, M, tmp, return       XMODEM receive `tmp'
<wait for transfer to finish>
Function + B                  enter basic
"*LOAD TMP 6000"        load system (omit the quotes :-))
"CALL &6000"                  start ZCN   (ditto)

[NB: `zcn.bin' is in the `bin' subdirectory.]

(It was necessary to create the junk file above so that Function-L
would work; there's no way to get the menu which lets you XMODEM
receive a file without any files in memory. Yuck.)

(Also, note that you will need a reasonably complete serial lead for
the ROM software's XMODEM transfer to work (this doesn't apply to ZCN
itself, which needs only the minimal out/in/gnd connection (plus CTS
if serial output is to work, though that can just be soldered to
RTS)). Any lead you *buy* should be fine, but if you've knocked up
your own only-three-pins-connected job you'll need to borrow a better
lead from someone for this transfer. :-) However, for an alternative
approach, see `badlead.txt'.)

You should then end up with a screen looking something like:

      ZCN v1.2 (1999-03-03 16:20) ROM v1.06


(The version numbers and date/time of assembly may vary - don't worry,
that's because I don't often update the above `screenshot'. :-))

The `A>' is the ZCN command processor's prompt. It'll probably be
there twice because you pressed enter at the end of "CALL &6000" and
it was still pressed the first time ZCN prompted for a command line,
so it just prompted again. (ZCN didn't know that it was pressed before
- it wasn't running then.)

If you ran `rrinit' before booting ZCN, skip the next paragraph. Let
me put that another way - IF YOU RAN `rrinit', DO *NOT* DO `format a:'
OR YOU WILL LOSE THE DATA IT SAVED. (`format b:' etc. is fine,

Those of you who didn't run `rrinit' should now make sure you have
your PCMCIA card in the card slot, and type `format a:'. If it prompts
you asking if you want to reformat it, press `y'. You should see the
message `Formatting complete' almost immediately (formatting memory
cards is a very simple operation).

If the card you're using is 512k or 1024k, type `format b:', which
formats the 2nd logical drive (the 2nd 256k of the card).

If the card is 1024k, follow this by typing `format c:' and finally
`format d:'.

If the card is larger than 1024k, you've got more money than sense, as
the NC100 can't access the rest. :-)

Now you can make a bootable ZCN drive on your card. Do this by typing
`sys a:'.

Since this is the first time you've added the system to this card,
you'll get lots of `addblk..' messages. This means that ZCN is moving
the whole logical drive up 1k (one block). This is necessary to ensure
that you can add a new version of ZCN to a card without having to
reformat it. If you ever want to add a new version of ZCN to the card,
you can just boot it via the serial link as you did here and then do
`sys a:' again. In fact, you can also do it without ever leaving ZCN -
see the section `Installing a new version using an old one' below.

When the message `copying...done.' appears, the card is bootable.

You may have noticed, while the system was being copied, there was a
rather curious small black bar at the bottom-left of the screen. This
is the `drive light' for logical drive A:. Whenever this bar appears,
part of the card's memory is paged in that belongs to that logical
drive, i.e. the `disk' is being accessed. The `drive light' for
logical drive B: is to the right of that, C:'s is to the right of
that, as is D:'s. It won't usually be `on' as much in general as it
was for the `sys a:' command; don't worry about this, it's perfectly

You should now check that the system is bootable. This gives you an
opportunity to learn the booting procedure. As the NC100 remembers
what you were doing when you turn it off, you should only ever need to
reboot the system from scratch like this to: 1. check bootable cards,
2. reboot after a crash, or 3. reboot after changing the lithium
backup battery. (When you change normal batteries, there's no need to
reboot - the backup battery takes over until the new batteries are

*** Rebooting to test a bootable card, or after a crash

Going from when the NC100 is still on, you should:

1. Press the on/off switch to turn the computer off. If it didn't turn
off, remove the main batteries (not the lithium one) and disconnect
from the mains adaptor, and then reinstall/reconnect. (The on/off
switch will work fine usually, but sometimes when the NC100 crashes it
stops working because of memory corruption.)

2. Hold down the Function, Stop and `<-Del' keys and press the on/off
switch. This restarts the machine from scratch.

Assuming you're now at the `enter time' screen or the main menu, it
doesn't matter which:

3. Make sure your bootable ZCN card is in the slot, and press
`Function' and `X'. This should boot ZCN and leave you at the `A>'

An alternative method (for testing a bootable card) is to use the
`cboot' command.

**** Ye Olde Boot Method

Just for hysterical raisins, I've left in the instructions detailing
how you *used* to have to reboot. Not much fun. :-)

Skip this unless you're interested.

Steps 1 and 2 were as above, and then...

3. Press `Function' and `B'.

4. Make sure you have a bootable ZCN card in the card slot.

5. Type in any one of the following lines, whichever is most
convenient. (Type only one of them, and type them exactly as shown.)

P%=102:[:LD A,128:OUT (16),A:]

6. Press the on/off switch.

ZCN should now boot from logical drive A: on the card. If it doesn't,
PANIC. :-)

(You'll probably have to transfer ZCN via serial link again to get it
to boot, if it really won't boot off the card.)

As to the choice of which lines to type in in step 5... The latter two
aren't too bad to write down if your memory isn't really up to
remembering any of them. The first one is probably fairly memorable if
you've done much Z80 programming.

That said, I've managed to memorise the last one, so it might be worth
trying that if you can.

Now, aren't you glad you don't have to do that any more? :-)

*** Getting the first program across

So you've got your shiny new operating system across, and it's there,
and... it's not doing very much really, is it? To fix that, you'll
need to get some interesting programs across to your ZCN system. But
in order to do that, you first need to get a reasonable comms program
across which will make serial transfer easier.

This implies that getting the first program across is hard. :-)

Well, it's harder, at any rate. ZCN has a simple `internal command' (a
program already in memory, which doesn't need to be loaded off the
card) called `rexec' which reads a uuencoded file from the serial port
and writes it to the memory card under the filename given. Now, a
uuencoded file is a binary file, such as a program, converted to
`normal' readable ASCII characters by a program called, reasonably
enough, `uuencode'. :-)

On a Unix machine, `uuencode' will usually be part of the system - it
was originally written to help with transferring binary files across
7-bit links between Unix machines. For example, from my Linux box I
could do:

uuencode wibble.com wibble.com >/dev/ttyS1

...to send the program `wibble.com' to my NC100, which is connected to
my second serial port.

One of the best `first programs' in my experience is QTERM. A version
patched for use under ZCN is in the `support' directory. There is also
a copy of this already uuencoded, called `qterm.uue'.

What you should do to send the program is to first type `rexec
qterm.com' on the NC100, then start the uuencode (if Unix) or `ASCII
upload' the `qterm.uue' file (if MS-DOS). (It's easiest to again do
this transfer at 2400 baud on your `remote' computer, as ZCN defaults
to 2400 baud - but that's a bit slow, and you can use `stty' to change
speed if you want, e.g. `stty 19200' sets the speed to 19200 baud.)

If it works, you should get a dot printed as each line is processed,
then a short delay at the end while the file is written.

(If it doesn't work, try pressing both ctrl and C (i.e. ^C) to abort
the `rexec' and start again.)

(If you're using MS-DOS and your comms program doesn't have any `ASCII
upload' facility: 1. do something like `copy qterm.uue com2:' from the
DOS prompt, and 2. get a new comms program.)

Once you get QTERM across, you can run it by giving the command
`qterm'. You'll need to read the QTERM documentation in
`support/qterm' to learn about all its features, but here's the bare
minimum for transferring things to/from the NC100:

You can type Control+\ followed by Q to quit QTERM. More usefully, you
can type Control+\ then R to receive a file (this is what you'll want
first off) and type something like `x wibble.com' in answer to the
prompt `Mode?'. Control+\ then S sends a file and works the same way.

(If you used `rrinit' to save your data, now would be a good time to
make a backup copy of the `runrom.ram' file it created, by sending it
to your main machine using QTERM.)

You can find many free CP/M programs on the oak.oakland.edu ftp site
under /pub/cpm. That's where I got QTERM from, for example. Note that
some of the programs there, particularly those that use the BIOS disk
routines, may not work under ZCN. Since many of the programs there are
stored in .LBR format, you'll probably want to use the `lar' program
in the `support' directory. Look at the README there for more info.

** Installing a new version using an old one

I noted earlier that you could actually install a new version of ZCN
using an old one - i.e. without ever leaving ZCN. Here's how to do

First, you need to get the `zcn.bin' file across. You can do this with
`rexec' or (better) `qterm', as described above. At the NC100 end you
should give it a filename ending in `.com', as it acts just like a
normal executable program. `zcn.com' is a good name, for example.

Then after getting `zcn.com' (or whatever) across, you simply run it,
in this case by typing `zcn'. When the new version boots, test it out
a bit to make sure it's working ok; you can then delete the `.com'
file and install it on the card with `era zcn.com' and `sys a:'.

** Installation epilogue

By now, you should have a running ZCN system with a bootable card and
some file transfer program. You may now want to transfer other
programs in the `bin' and `support' directories, which together make
what I would consider a fully functional ZCN system. None of the
programs are necessary, but you're likely to find many useful:

- Programs you should transfer if at all possible are `ls', `optdir',
  `zde', `pipe', `submit', `pmarc', `pmext', `bbcbas', `runrom', and

- If you want online help, and it's better than you might think,
  you'll want `man' (be sure to transfer `manpages.pma' too, or it
  won't work - see the `MAN' section under `External Commands' for

- `spell' may be useful if yu kant spel wurth a dam. :-)

- `calc' runs the ROM calculator program under ZCN, and since
  floating-point calculators for CP/M are few and far between, this
  can be quite handy.

- `nswp' is a file manager which may be worth a look; alternatively,
  `zselx' is a simpler file manager which is somewhat like nswp but
  full-screen, and also has the advantage that the .com file is less
  than half the size.

- `rogue' can be a nice time-waster - oh sorry, "game" - especially
  for AD&D fans. :-)

- `cpmtris' is a reasonable tetris clone.

- If you own a microsoft-compatible serial mouse, you might want to
  take a look at `zcnpaint', a mouse-based paint program I wrote a
  while back. Documentation is in the `External Commands' section,
  later on.

- If you like the idea of a graphical front-end which works a bit like
  the ROM software's menus (but which is hugely more flexible), you
  may want to try `zap' (but be sure to transfer `zapdesc.bin' too -
  see the `ZAP' section under `External Commands' for details).

- And somewhat inevitably, there are many more. :-)

Frankly, it might be a good idea to simply transfer the lot, if you
have room. The programs in `bin' are described later on in `External
Commands'; the programs in `support' are described in the README

The rest of the documentation in this file covers using ZCN and
programming for it, as well as details of some of the internals.

As such, while I've tried to assume little previous experience or
knowledge throughout this section of the documentation, the rest of
this file will assume varying amounts. It should be possible for
anyone with experience of CP/M to follow most of the ZCN Manual, but
some is intended for programmers or simply for whoever is interested.

Those of you who ran `rrinit' to save your data and are now beginning
to panic because I've said so little about how you get it back into
memory :-) should probably skip ahead to the section `Running the ROM
software from ZCN' and read that before reading the manual proper.

If you're a Z80 programmer new to CP/M and/or ZCN, you may want to
look at `zcnprog.txt', my guide to programming CP/M and ZCN. It
documents all the CP/M 2.2 BDOS calls, and all the `zcnlib' routines.

If you have any problems, feel free to write/email (addresses are at
the end of this file), and I'll do my best to help. If you're writing,
please include an SAE if you can, it saves me time and trouble.

* The ZCN Manual

** Rationale

The ZCN Manual tends to concentrate on differences from normal CP/M in
everyday use. I've tried to cover some of how CP/M works, but not all
that much. Parts of it may be in a rather confusing and messed-up
order, as to a certain extent I've just scrawled down documentation
for commands etc. as I've added them.

I recommend that you read at least up until the `ZCN for hackers'
section. I know it's a lot to read, but it will almost certainly be
worth it, as ZCN is quite an oddball mix of ideas and programs, and
there will almost certainly be something there that's new to you.

Also be sure to read the `Q&A' section below.

The manual is more than a little informal, as you may already have
noticed. In my humble opinion, far too many manuals are stuffy and
unreadable. In stark contrast, the ZCN manual is chatty and
unreadable. Much better. :-)

** Q&A

This section attempts to cover some of the more astonishing things ZCN
does. As for what I mean by `astonishing':

"A program should follow the `Law of Least Astonishment'. What is this
law? It is simply that the program should always respond to the user
in the way that astonishes him least."
      -- James Geoffrey, "The Tao of Programming"

ZCN, ah, bends this law at times. :-)

*** Why do some programs show the file FOO.TXT as FOO.TwT?

This is to do with, and yes I know this sounds bizarre, ZCN's support
for the power on/off switch. Turning the machine off is actually done
under software control, and the way it needs to work, combined with
the way CP/M works, means that with some programs you may see
filenames with `w' as the second character of the extension. A few
programs may even force the actual files to have a `w' there (this is
very unlikely, but there might be one or two programs that do it).

For technical reasons, there's little I can do to prevent either of
the problems. The NC100 simply wasn't designed to run CP/M, and ZCN
just does the best it can with what it's got. For a more technical
explanation of why this happens, see the section `The Power On/off
Switch' near the end of this file.

*** Why do I get rubbish from the serial port?

Whenever you turn on the NC100 under ZCN, the serial port is enabled.
During this process, a spurious `serial input' interrupt is generated
which is difficult to filter out for various reasons. This usually
ends up putting a random character in the serial input buffer. This is
harmless and can be ignored.

If you get a whole load of rubbish chars, you probably either have
parity enabled at the other end or are using the wrong baud rate.

*** Why are the letters so SMALL!?

I wanted to get as many lines as possible. I think it's worth the
smaller characters to get 10 lines rather than 8 with the ROM
software. I hope the characters are readable; I think they are, but
I'm obviously rather biased. They're narrow to keep the aspect ratio
as `normal' as possible, and because 4-bit wide characters are much
easier and faster to draw than 6-bit wide ones such as the ROM
software uses.

*** Why does zero look round, and O rectangular?

Before ZCN v1.1, you simply couldn't tell zero and O apart in ZCN's
font (both were round). Since, unfortunately, the characters were too
small to:

- put a slash through the zero;
- put a dot in the centre of the zero (it makes it look like an 8!);
- make the zero more diamond-like;
- make the zero narrower;

...I decided to make the O rectangular instead. (This is an unusual
approach, but isn't entirely without precedent.) It's not ideal, but
at least you can tell which is which.

If you really can't stand this, and you'd rather they were both round,
do this, but be careful to type it in correctly!

      poke ebda 44
      poke ebde 44

(Note that this causes problems with the copy cursor in `bbcbas'
though - it'll think both 0 and O are zeroes. And it'll affect
`dmp2txt' in much the same way.)

You could put these commands in your `autoexec.sub' if you wanted this
all the time (more on SUB files later), or you could just rewrite ZCN
with the altered font using `sys a:'.

*** Why do some characters look like random blotches?

ZCN only has character bitmaps for characters in the range 32-126, the
so-called `printable characters'. If a character outside this range is
printed which is not a control code, an effectively random collection
of pixels is printed.

This usually happens when a character was printed which had the high
bit set. If the offending character was received from the serial port,
try disabling parity on the other machine.

*** It says `Disk Full', but I've got plenty of room left!

This probably means that the drive's directory table is full. Usually
under ZCN there's a maximum of 64 files per drive (but see below).
When you run out of directory space, it's often interpreted by
programs as `disk full'. It does have the same effect, as in order to
write any more you'll have to move or delete one or more files.

You may, in fact, be allowed less than 64 files. If a file is larger
than 16k, it will take up more than one directory space - it'll use
one for each 16k of the file.

*** Why is QTERM's display when sending/receiving files messed up?

QTERM's file transfer display is designed for a terminal with 12 lines
or more. ZCN only has 10, so the line which shows the number of errors
sometimes overprints the line showing the number of packets done so
far. I'm afraid there isn't much that can be done about this without
patching QTERM - but hopefully it's not that much of a problem.

*** How can I patch programs without DDT/SID?

Unfortunately, the (possibly unusual, since they were for fairly `odd'
machines and may have been modified) copies of DDT and SID I've tried
didn't work on ZCN; or rather, they worked to a certain extent, but
they seemed to overwrite the call at 0030h, which is a Bad Thing on

Personally, I don't think this is that much of a problem. I use `wade'
instead (look in the `support' directory for a copy) which is, dare I
say it, rather nicer than DDT and SID. :-)

*** Why does the ROM ask me to set the time when I turn the NC on?

NC100s with ROM v1.00 seem to be quite pedantic about having the time
set. If the time *isn't* set, the ROM demands you set it, which loses
you any saved context - and if ZCN was running, it resets the machine
into the bargain. :-( This is a bug in the original ROM, and although
it was fixed in the later v1.06 (which is in my NC100, for example),
this doesn't help you if you have machine with the earlier ROM (you
can check which ROM you have with ZCN's `ver' command).

The only way to `fix' it is to set the time, as you might imagine.
(You can do this either with the ROM's time setting screen or with
ZCN's `timeset' command.) Fortunately, once the time is set it tends
to stay that way. :-)

** Running the ROM software from ZCN

[This is deliberately early on in the manual (earlier than it might
otherwise make sense for it to be) so that it isn't too hard to find
for anyone skipping ahead from `Installation epilogue'.]

*** About `runrom'

To run the ROM software from ZCN, just use the `runrom' program - i.e.
do `runrom' and it boots the ROM software. If you have an existing
`runrom.ram' file - this file is a snapshot of an already-booted
machine, usually with files in memory etc. - be sure to start with
that in the current drive and user area. If no `runrom.ram' file is
found in the current drive/user, the memory is zeroed and the ROM
booted from scratch.

Note that you can only run `runrom' from a bootable card. (It'll exit
with an error if you try to run it on one which isn't.) It's
complicated to fully explain why, but the basic reason it's necessary
is so that there's a safe way back to ZCN from the ROM software.

You also need either an existing `runrom.ram' snapshot file, or 64k
free on the current drive in order to create one. The reason for this
latter requirement is much easier to explain - a snapshot is always
saved when you return to ZCN, and the disk space for it is allocated
in advance.

When the ROM software is started, you can use it exactly as you
normally would.

(If you used `rrinit' to save your existing memory, the `rrinit' file
will still be there when you do `runrom'. Feel free to delete it; it's
not needed any more.)

When you want to return to ZCN, *make sure the card you ran `runrom'
from is in the card slot*, then press `Function' and `X'. (It's
probably best to leave this card in the slot throughout so you don't
need to worry about whether it's in or not - but you may find this
inconvenient. It's up to you.)

When you return to ZCN (in fact just before), a snapshot of the memory
is saved in `runrom.ram'. After that, ZCN is rebooted.

So in summary, it's:

- `runrom' on a bootable card to go from ZCN to the ROM s/w.

- Function-X *with the same card in the slot* to return to ZCN.

By the way, you may notice that the screen is corrupted for a (very)
short while when switching between ZCN and the ROM or vice versa. This
is meant to happen, and is nothing to worry about.

There is one extra detail to cover. Imagine this situation - when
using the ROM software, something terrible happens and you manage to
make it crash. (This isn't that difficult if you're messing about with
machine code in BBC Basic; also, there are one or two bugs in the ROM
which can lead to crashes in certain obscure situations.) The only way
out, as usual with a crash, is to reboot. Obviously, in this situation
you're not going to want a snapshot to be saved when you do
function-X! No problem. Just make sure you're holding both shift keys
when you do function-X - i.e. while holding down both shifts and the
function key, press X - and no snapshot will be saved. So the next
time you do `runrom', your previous data will still be intact.

Now you know how to switch between ZCN and the ROM software, you may
be wondering how useful this really is without the ability to copy
files between the two. That's where `rrxfer' comes in.

*** About `rrxfer'

`rrxfer' lets you copy files to/from a `runrom.ram' snapshot file, and
thus to effectively copy files to/from your ROM software setup.

Rrxfer uses an 80-column-friendly layout and no inverse video if the
console output is going to the serial port or printer.

**** How to use it

The program is relatively straightforward to use. You start it up with
plain `rrxfer', then when the menu line comes up (it'll take a little
while as it has to load most of the snapshot first), press one of
these keys:

- `r' to list the ROM files (i.e. the files in the snapshot). Files in
both the ROM's `upper' and `lower' memory areas are listed.

- `z' to list the ZCN files (i.e. the files in the current
drive/user). I'm afraid there's no way to transfer files to/from a
different drive or user area than the one the snapshot is in. (You can
probably get around this, though, by copying files or using `umv'
before/after running rrxfer, as appropriate.)

- `g' to get a file - to copy a ROM file to ZCN. Note that any
existing ZCN file with the same name will be overwritten. The filename
you type must exactly match the ROM file's name - case is significant
in ROM filenames. The copy made is automatically given a reasonable
ZCN name; non-printable ASCII chars, spaces, colons, asterisks and
question marks are all converted to underscores. If you choose `g'
then change your mind, just type in an empty filename (that is, just
press enter) to abort.

If the ROM file isn't found, or there isn't enough room on the ZCN
drive to write the copy, you'll get an error message saying so.

- `p' to put a file - to copy a ZCN file to the ROM's file area. Note
that any existing ROM file with the same name will be overwritten
(more precisely, the existing file is deleted first, whether in upper
or lower memory). The copy is always written in lower memory. (Again,
you can enter an empty filename to abort.) The copy made is given a
ROM filename which matches how you typed the ZCN file's name, which
means you have a degree of control over the ROM file's name.

Here's an example of what that means - say you have a file `foo.txt'.
If you type the name as `foo.txt', the ROM file written is `foo.txt'.
Simple enough. But you could also type it as `Foo.txt', as that still
refers to the same ZCN file, and the ROM file will then be called
that. (As I mentioned above, case is significant for ROM files.)
`FOO.TXT', `fOo.TxT', and `foo     .txt' are other possibilities.

If the NC100's real-time clock has been set (either via the ROM or
with ZCN's `timeset'), the file is written with the current time/date.
If the clock isn't set, however, they're written with a `zero'
time/date. The ROM interprets this as midnight on "90-00-00" [sic].

If the ZCN file isn't found, or there isn't enough room in the
snapshot's lower memory to write the copy, you'll get an error message
saying so.

- finally, `q' quits rrxfer. This may take a little while if you wrote
any files to the lower memory (i.e. used `put'), as the lower memory
part of the snapshot has to be rewritten.

The menu line lists these keys with a (very) brief description of what
they do.

**** Problems

There's one main problem when transferring files between the ROM
software and ZCN - the ROM software stores file sizes exactly, while
ZCN (being CP/M-like) only stores them to the nearest 128-byte

For file tranfers in the ROM -> ZCN direction, this is usually not a
problem. Rrxfer always makes sure an extra ^Z is added to end of any
files transferred, so text files are ok. (This can cause some
difficulties for binary files assumed to be of a given size though -
screen dumps are probably the main example, and how to deal with those
is covered in the `Hints and tips' section below.)

The problem is in the ZCN -> ROM direction. Now, if you think about
it, this doesn't seem like it should be a problem for the ROM stuff -
XMODEM file transfers work with 128-byte records too, and it has no
problems dealing with those! Unfortunately, it seems to be the XMODEM
receive routine which deals with them (probably by stripping trailing
^Z's), rather than being some general capacity of the file I/O.

This means that we need to check each of the ROM software's programs
in turn to see how it copes with it. Now, the only ones with which you
can get at files written by rrxfer are the word processor and BBC
Basic. The word processor shows any trailing ^Z's literally, as a
series of little right-arrows. These are then easily deleted. As for
BBC Basic, it seems to simply ignore junk at the end of its Basic
files. If you *EXEC a file, it'll leave right-arrows on the screen,
but as with the word processor these are easy enough to delete (in
Basic pressing Stop is probably easiest). Note also that BBC Basic can
be run natively on ZCN (and is 10% faster), so running it under the
ROM software probably isn't that attractive anyway.

Text files written by some CP/M programs may cause more problems than
others. For example, since you need only one ^Z to end a CP/M text
file, some programs only write one, and don't worry about whatever
junk may be in the rest of the record. If you have this problem, and
the junk causes difficulties, there's an easy solution - just load the
file up into ZDE and save it before transferring with rrxfer. (ZDE
always fills up the remainder of the last record with ^Z's. By the
way, it'll prompt you because the file is unchanged - just press `Y'.)

**** An example session

Here's an example of an rrxfer session:

Reading lower memory from snapshot...
 [R]OM files, [Z]CN files, [G]et (ROM->ZCN), [P]ut (ZCN->ROM), [Q]uit
ADDRESS BOOK   1k  foobar         1k  new2           1k  new6           1k
autoexec.sub   1k  HELLO.BAS      1k  new3           1k  new7           1k
COPY.BAS       1k  hello.bas      1k  new4           1k  sw.txt         2k
FILLER         9k  new1           1k  new5           1k  TRY.BAS        1k
 36k free in lower memory
 [R]OM files, [Z]CN files, [G]et (ROM->ZCN), [P]ut (ZCN->ROM), [Q]uit
radfreq.txt    1k  runrom.ram    64k  sw.txt         2k
 13k free on drive
 [R]OM files, [Z]CN files, [G]et (ROM->ZCN), [P]ut (ZCN->ROM), [Q]uit
Get which ROM file? hello.bas
File copied OK.
 [R]OM files, [Z]CN files, [G]et (ROM->ZCN), [P]ut (ZCN->ROM), [Q]uit
Get which ROM file? flurgle
Error writing ZCN file! (ROM file not found, or ZCN disk full)
 [R]OM files, [Z]CN files, [G]et (ROM->ZCN), [P]ut (ZCN->ROM), [Q]uit
Put which ZCN file? radfreq.txt
File copied OK.
 [R]OM files, [Z]CN files, [G]et (ROM->ZCN), [P]ut (ZCN->ROM), [Q]uit
Put which ZCN file? wibble
Error writing file! (ZCN file not found, or not enough low memory)
 [R]OM files, [Z]CN files, [G]et (ROM->ZCN), [P]ut (ZCN->ROM), [Q]uit
ADDRESS BOOK   1k  HELLO.BAS      1k  new4           1k  sw.txt         2k
autoexec.sub   1k  hello.bas      1k  new5           1k  TRY.BAS        1k
COPY.BAS       1k  new1           1k  new6           1k
FILLER         9k  new2           1k  new7           1k
foobar         1k  new3           1k  radfreq.txt    1k
 35k free in lower memory
 [R]OM files, [Z]CN files, [G]et (ROM->ZCN), [P]ut (ZCN->ROM), [Q]uit
hello.bas      1k  radfreq.txt    1k  runrom.ram    64k  sw.txt         2k
 12k free on drive
 [R]OM files, [Z]CN files, [G]et (ROM->ZCN), [P]ut (ZCN->ROM), [Q]uit
Writing lower memory to snapshot...

**** Bugs

There's one bug in rrxfer that I'm aware of:

- You can't `put' an address book (due to the filename required). This
probably isn't that big a deal, as address books are in a funny format

*** Hints and tips

`runrom.ram' is just a normal file. If you make a backup of this file,
you're backing up your ROM software setup and all the files it has in
memory. Backing up all your files has rarely been *this* easy... :-)

Equally, because it's a normal file, you can save space if (like me)
you don't use the ROM software much by compressing the snapshot with
pmarc (using something like `pmarc snap runrom.ram'). You'll have to
decompress it again (with pmext) before using `runrom', of course, but
it could save you quite a bit of disk space in the meantime.

ROM software screen dumps can't be viewed as-is on ZCN, because rrxfer
adds an extra record to the ZCN copy to allow for the ^Z it always
adds. (This means that trying to view it the usual `get f000' way will
crash the machine!) So the full sequence for getting a ROM s/w screen
dump and loading it on ZCN goes like this:

- Make sure you have at least 9k free on the ZCN drive with
  `runrom.ram' on.
- On ZCN, do `runrom' to start the ROM stuff.
- Make sure there's at least 4608 bytes free in the upper memory.
- Do whatever it is you need to, to get the screen right for the dump.
- Do Ctrl-Shift-S. This saves `s.a' and `s.b'.
- Do Function-X to return to ZCN.
- Start up rrxfer.
- Get `s.b', and quit. (`s.a' isn't of interest.)
- Do `get 100 s.b', then `save 16 dump'.
- `get f000 dump' now loads the screen dump.
- Delete `s.b' if you want, you don't need it any more.

** Command Prompt

When ZCN is waiting for you to issue a command, it gives a short
prompt ending in `>'. This prompt tells you which drive is the default
drive; the drive which files are assumed to be on unless you
explicitly specify another.

If drive A is current the prompt would normally be `A>'. This may not
always be the case however - there may be a number or `*' displayed
between the drive letter and the `>'. See `User Numbers' for more

If you like, you can redefine the prompt ZCN uses to suit your own
tastes. See the description of the `%' command (listed as
`%prompt_string') in the `Internal Commands' section for details.

** Wildcards

Wildcards in ZCN (and CP/M, and even MS-DOS) have a curious quirk that
you may not be aware of. When you specify part of a filename or
extension then use a wildcard, it matches even files that have no more
characters after the part you specified.

This is fine for wildcards like `foo*.txt', which matches `foo.txt',
`foo2.txt' and `foobar.txt'. Where it gets weird is for `foo?.txt',
which obviously matches `foo2.txt' but (perhaps unexpectedly) also
matches `foo.txt'! The reason for this is that the file isn't really
called `foo.txt' as far as the system is concerned; it sees it as
`foo_____txt' (I'm using underscores to represent spaces for clarity).
The wildcard `foo?.txt', or `foo?____txt', matches this as the `?' by
definition matches any character.

Rational or not, having `foo?.txt' match `foo.txt' is bound to confuse
anyone who's used to Unix, where it wouldn't match, and might even
confuse some MS-DOS or CP/M users who haven't noticed it before. I
thought it was a bug the first time I noticed it. :-)

** The Keyboard

The NC100's keyboard is, shall we say, a little odd. Certainly some
keys are in the `wrong' place.

The way ZCN fixes this and maps the non-obvious keys is shown below:

Key         Acts like   ASCII code  Reason
---         ---------   ----------  ------

Function    Control           <none>            Nice big key
Stop        Escape            27          In the right place
<-Del       Delete            127         In the right place
Del->       ^G          7           WordStar-like
Menu        `           96          No real backquote key
Cursor Up   ^E          5           WordStar-like
Cursor Left ^S          19          WordStar-like
Cursor Right      ^D          4           WordStar-like
Cursor Down ^X          24          WordStar-like

The `symbol' key acts as a Meta key - it sets bit 7 of any key
pressed. (PC folks should think of it as analogous to `Alt', but

Ctrl+Space returns ASCII 0 (i.e. NUL). Note that this may not be sent
by some terminal programs (though QTERM seems to be ok). The built-in
command `sertest' does send it, so you could always use that.

It is possible to make the `Caps Lock' key act like a control key, if
you like that - see `CAPSCTRL' in the `Internal Commands' section for

You cannot stop a program's output by using ^S. However, you can pause
a program's output at any time by holding both the `control' and
`symbol' keys simultaneously. The output starts again when you let go.

You can get a dump of the current screen at any time by pressing
Control-LeftShift-S (you must use the real Control key for this). The
middle 60 pixel lines of the screen memory are simply saved to the
file `screen.dmp', including the `wasted' bytes, giving 64 bytes per
line. The top two and the last-but-one pixel lines are used as
temporary storage during the screen dump, so don't worry if they
appear corrupted for a second or two. You'll get a screen flash (or
beep) when the dump has been written, and you can then carry on with
whatever you were doing.

On a Unix box with the `netpbm' or `pbmplus' utilities installed, you
can convert a `screen.dmp' file to a PBM file with something like this:

(echo P4;echo 512 60;cat screen.dmp) | pnmcut 0 0 480 60 >foo.pbm

You can then convert to other formats with things like ppmtogif, etc.

** The Screen

The NC100's screen has a pixel resolution of 480x64. ZCN provides a
character screen of 120x10 with 4x6 character cells, leaving two pixel
lines at the top and bottom free. The leftmost 32 pixels on the bottom
pixel line are used by the `drive lights' (see `Logical Drives').

** The Terminal Driver

*** Control Codes

Programs often have patch areas (or installation programs) which need
to know which sequences to send to do cursor movement, etc. For that
reason, and for programmers of course :-), the console control codes
are listed here. Those listed as `(reserved)' have no effect.

Code  Hex   Dec   Description

^@    00    0    (ignored)
^A    01    1    clear screen, home cursor
^B    02    2    bold off
^C    03    3    cursor on
^D    04    4    cursor off
^E    05    5    bold on
^F    06    6    clear to end of screen
^G    07    7    bell (by default, this flashes the screen)
^H    08    8    backspace
^I    09    9    tab (8 chars wide, i.e. 1,9,17,25,33,...)
^J    0A    10    linefeed
^K    0B    11    (reserved)
^L    0C    12    (ignored)
^M    0D    13    carriage return
^N    0E    14    italics ("underline") off
^O    0F    15    italics ("underline") on
^P    10    16    move cursor - 10h, then 20h+y, then 20h+x (see below)
^Q    11    17    (ignored)
^R    12    18    insert line
^S    13    19    (ignored)
^T    14    20    delete line
^U    15    21    scroll up
^V    16    22    (reserved)
^W    17    23    scroll down
^X    18    24    true video (i.e. turn off reverse video)
^Y    19    25    reverse video
^Z    1A    26    move cursor right one column
^[    1B    27    VT52 escape code prefix (see below)
^\    1C    28    (reserved)
^]    1D    29    move cursor up one line
^^    1E    30    home cursor without clearing screen
^_    1F    31    clear to end of line

In pre-v1.2 versions of ZCN, the y location for ^P was 46h+y. This is
still supported, but is deprecated and may not be supported by a
future version of ZCN - you should switch to using 20h+y instead.

Some VT52-like escape codes are supported, mostly so that Mallard
Basic will work comfortably on ZCN. These all start with ^[ (ESC).
Those supported are ESC-D to backspace, ESC-C to move the cursor right
one column, and ESC-K to clear to the end of the current line. (In
fact, at the moment, ESC followed by anything other than `D' or `C'
acts like ESC-K.) No other VT52 escape codes are implemented.

However, one extra feature of ESC is that it counteracts any CR/LF
output immediately after. So if you're writing a program where you
want to avoid the CR/LF which ZCN normally outputs when a program
exits, you can easily do this by just outputting an ESC before you
exit. (Be warned that this doesn't work on ZCN versions earlier than
v1.2, though, and obviously it won't work if console output is
redirected to the serial port.)

While I'm on the subject, here's another brief aside for programmery
types. :-) If for some reason you need to know the current cursor
location, you can use this bit of Z80 to read it (it reads the x
position into B and the y pos. into C):

      ld ix,(1)
      ld b,(ix-5)
      ld c,(ix-4)

Using this is a Bad Idea in general, and it won't work on old
(pre-v1.1) versions of ZCN, but it's there if you need it.

*** Unix termcap/terminfo entries

Skip this if you don't use any version of Unix.

Since the NC100 can be used as a convenient and portable terminal to
Unix systems, it's a good idea to have a termcap/terminfo entry to
hand so you can run full-screen programs on it. Note that they will
have to be able to cope with using such a small number of lines -
Emacs and Nethack can, for example (though Nethack isn't too happy
about it).

Here's a termcap entry for an NC100 running ZCN:

zcn|amstrad nc100 running zcn:\
      :cl=^A:co#120:li#10:cm=^P%+ %+ :le=^H:bs:am:sf=^U:sb=^W:sr=^W:\

However, termcap is rapidly falling into disuse these days, so most
people will probably want a terminfo entry instead. Here's the one I

zcn|amstrad nc100 running zcn,
      cols#120, lines#10, am, clear=^A, cr=^M, bel=^G,
      cub1=^H, cuf1=^Z, cuu1=^], cud1=^J, ind=^U, ri=^W,
      cup=^P%p1%' '%+%c%p2%' '%+%c, home=^^,
      el=^_, ed=^F, il1=^R, dl1=^T,
      smso=^Y, rmso=^X, smul=^O, rmul=^N, bold=^E, rev=^Y,
      sgr0=^B^N^X, msgr, civis=^D, cnorm=^C,
      ht=^I, it#8, km,

You may have problems using Emacs, for a couple of reasons. The common
problem with XON/XOFF flow control doesn't apply since ZCN avoids it
like the plague; instead, there are two other problems.

Because of the way the direct console I/O BDOS function works, some
CP/M terminal programs may not send ^@ (ASCII 0, or NUL). This'd be a
real pain when using Emacs. The simplest solution is to use the
built-in command `sertest', which has the added advantage of being
faster than most other terminal programs since it really is very
simple indeed, and can call functions in ZCN directly rather than
having to use the BDOS entry point. (My tests indicate that `sertest'
is nearly twice as fast as QTERM.)

You may also have problems getting the `Symbol' key to work as a Meta
key. There shouldn't be a problem if Emacs is using terminfo - the
terminfo entry above specifies `km' which should get it working
properly. (Certainly that works for me.) But if for whatever reason it
doesn't work, you might want to try putting this in your ~/.emacs file
to fix it:

      (if (equal (getenv "TERM") "nc100")
          (set-input-mode nil nil t))

(If that doesn't work, it could be down to the stty settings `cs8'
and/or `-istrip' not being set.)

** Rebooting

There are two main rebooting possiblities available when switching on
the NC100 running ZCN. They are:

1. Cold boot of the ROM software. Do this by holding down Function,
Stop and `<-Del' while turning the computer on. You should only need
to do this if a program crashes, etc. You should then use Function-X
to boot ZCN from your bootable card.

2. Cold boot of ZCN. (This isn't fully `cold', as it just restarts the
copy of ZCN in memory.) Do this by holding down both shift keys while
turning the computer on. Use this to clear any random wedgitude that
may have occurred, or to test your `autoexec.sub' (see later).

You can also, from the ZCN command-line, use `cboot' to do a fully
`cold' boot of ZCN from the memory card.

** CP/M Compatibility

ZCN aims at close CP/M compatibility - enough to get the majority of
freely available programs running. Most programs work. This section
describes what facilities are provided, and lists programs which are
known to not work under ZCN.

*** BDOS Functions

The following BDOS functions are provided, and are believed to be
working correctly:

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 29, 32, 33, 34, 36, 37.

These ones work but have known problems:

35 - gives incorrect results for files with holes.
40 - the same as function 34, i.e. it doesn't actually do the zero

These not done:

27, 28, 31.

There are some additional (ZCN-specific) functions; some are mentioned
later. Full descriptions are given in `zcnprog.txt', but the ultimate
reference is `zcnfunc.z' in the `src' directory. So, in other words,
RTFS. :-)

*** BIOS Functions

ZCN has a rather sparse BIOS jumptable which omits all the
disk-related functions. I am very reluctant to add them as it would
take a fair chunk of memory to implement. (ZCN's internals work
differently to CP/M, which would make writing them tricky, too.)
Still, the existing BIOS is enough for most programs.

*** Zero Page etc.

ZCN uses the memory at addresses 0000h-00FFh as follows:

address(es) description

00h-02h           jump to warm boot routine
03h         ZCN does not implement CP/M's IOBYTE; instead, this
            byte contains the contents of 80h when the last
            program finished (this lets you check the exit status
            of a Hitech C program)
04h-04h           unused (but set to zero by warm boot)
05h-07h           jump to BDOS
08h-2Fh           usable by user programs (as on CP/M)
30h-32h           jump to NMI poweroff routine (see note 1)
33h-37h           part of NMI poweroff routine
38h-3Ah           unused jump to maskable interrupt routine (see note 2);
            usable by user programs
3Bh-5Bh           reserved (actually unused)
5Ch-6Bh           initialised part of FCB 1 (see note 1)
6Ch-7Bh           initialised part of FCB 2
7Ch-7Fh           remainder of FCB 1
80h         size of command tail at 0081h
81h-FFh           command tail (command line minus command name)

Note to programmers: Please do not *depend* on any of the `unused'
sections above being available for your use (unless your program is
taking over control of the machine completely).

Note 1:

Pressing the on/off switch when the NC100 is on causes a non-maskable
interrupt - that is, it disables interrupts, puts pc on the stack, and
jumps to 0066h. This is the 2nd char. of the filename extension in FCB
1 - there's some ad hackery in ZCN to try and deal with the problems
this causes. As far as I know it's successful, except that sometimes
you will see a filename printed with the 2nd char. of the extension
appearing as a lowercase `w'. I don't think there's anything I can do
about that. Anyway, the value that's actually stored at 0066h is F7h -
`rst 30h'. The maskable interrupt routine and BDOS both fix this byte
if it's been changed.

Note 2:

The maskable interrupt routine is responsible for the following:

- Fixing 0066h if it's been changed (see note 1 for details).
- Keyboard input/buffering.
- Serial port input/buffering.
- Auto poweroff timeout and the actual auto poweroff itself.
- Updating `drive lights'.

See `Tight Interrupts' (in the hacker's guide section) for what
happens when minimal interrupts are in use.

The reason there's still a jump to the interrupt handler at 0038h is
in case there's some program out there which explicitly selects IM1
for some reason and expects ZCN to cope with this.

Note 3:

Although 0008h-002Fh is available for use by user programs, ZCN puts a
jump instruction at 0028h (which it's ok to overwrite). The jump at
0028h is to allow ZCN's internal commands to use `rst 28h' as an
indirect call to a inline string output routine, thus saving a few
bytes. It's not a good idea to call this yourself - it doesn't exist
on other CP/Ms, and didn't even exist on ZCN until v1.1. However, if
you're really determined to ignore my advice on this :-), look at
`ilprint' in `src/misc.z' for how to call it.

Unusually for a CP/M system, the BDOS entry point (the address at
0006h) is the very start of system code; all addresses from that one
upwards are used by ZCN, except for the screen memory which starts at
F000h. Programs which leave space for a CCP will still work, as will
those which don't - all parts of ZCN interact directly with each
other, and should never be overwritten. Note that this monolithic
approach means you will presumably never be able to run any version of
ZCPR on a ZCN system unless someone's prepared to hack up both

*** Non-working Programs

Essentially, programs which need disk BIOS functions don't work. This
included (the last time I tested) superdir, `dr24.com', and zx 3.1.

Another possible problem is the whole 66h thing (more on this
elsewhere) - usually this just results in the odd spurious `w' being
printed :-), but it can cause real problems with some odd programs.
The ones I've found so far that are affected are nulu and kermit.

** Tips on using certain programs with ZCN

*** Hitech C

**** Getting Hitech C

Native CP/M Hitech C is free. It's very slow and memory/disk hungry
and Z80-specific and the optimisation is quite awful, but it's very
ANSI-compatible (well, for a CP/M C compiler ;-)) and excellent for
compiling short (<2000 line) C programs. It's available from
oak.oakland.edu in /pub/cpm/hitech-c, and probably also available from
any decent CP/M PD distributor.

**** How to run it on ZCN

Programs compiled with Hitech C (which fit in memory!) work on ZCN
just fine, though any use of any exec() or system() call will fail. A
few of the programs in the `support' dir were compiled with Hitech C
using the excellent `cpm' CP/M emulator on my Linux box.

As for the compiler, things are more problematic. The compiler driver
`c.com' doesn't seem to work on ZCN for some reason, so you have to
run the passes by hand. Even then, most of the passes need a LOT of
memory to run. You'll need to use `bigrun' to run them. (Be sure to
read the warnings in the `bigrun' section first!) Here's an example
SUB file `hc.sub', designed to run on drive B: with `libc.lib' on
drive A:, which acts as a simple replacement for `c.com':

--------------------------- cut here ----------------------------
submit hc.sub *
defrag -q b:
cpp -DCPM -Dz80 -I $1 hctemp1
ifnpeek 3 0 quitsub era hctemp?
bigrun p1 hctemp1 hctemp2 hctemp3
ifnpeek 3 0 quitsub era hctemp?
era hctemp3
bigrun cgen hctemp2 hctemp1
ifnpeek 3 0 quitsub era hctemp?
era hctemp2
bigrun zas -N hctemp1
ifnpeek 3 0 quitsub ; era hctemp?;era hctemp1.obj
era hctemp1
link -Z -C100H -o$1om crtcpm.obj hctemp1.obj $2 $3 $4 a:libc.lib
ifnpeek 3 0 quitsub ; era hctemp1.obj;era $1om
era hctemp1.obj
"compiled ok.
--------------------------- cut here ----------------------------

All the `ifnpeek's make sure it quits and cleans up temporary files if
any pass fails. The last two `ifnpeek..quitsub' commands need `semi'
to be on your machine as `;.com' - failing that, you could replace
them respectively with `ifnpeek 3 0 quitsub era hctemp?' and `ifnpeek
3 0 quitsub era $1om' at the cost of possibly leaving a hctemp1.obj
file lying around.

For the SUB file to work, you'll also need much of Hitech C on your
machine (unsurprisingly :-)). Specifically, you need `cgen.com',
`cpp.com', `crtcpm.obj', `link.com', `p1.com', and `zas.com'. You'll
also need `libc.lib' on drive A:, as I mentioned above, and you'll
need any headers you want to use - certainly you'll want `stdio.h',
and probably `stdlib.h' and `string.h'. It may be a good idea to make
a .pma archive of all the header files, so you can get at any you
need. (Such an archive is 9k rather than the 30k the headers take

To compile with floating-point support, you'll also need `libf.lib',
and will need to compile with something like `hc foo.c libf.lib'.

You need an awful lot of disk space to run Hitech C. You can't
realistically run it on anything less than a 512k card, and a 1024k
card might be preferable if you want to have enough disk space free to
do other things too. When I last tried it on my 512k card, on the A:
drive I had `headers.pma' and `libc.lib' taking up 69k, and on B: I
had the various required COM files and headers taking up roughly 190k.
Total disk space required, 259k - and that didn't include the 32k
needed for `bigrun' to work, nor did it include the space needed for
Hitech C's temporary files. (Which can be 30 or 40k.) So it
effectively took about 330k.

Oh, and another point - as I've said, it's not exactly fast. On ZCN,
it takes 50 seconds to compile a "hello world" program!

Personally, I dumped it and use `bbcbas' instead when I want to
program on the NC100 itself. It's about 50 times smaller ;-), and
there's no waiting for things to compile.

**** Realistic System Requirements for Hitech C

For serious use, I personally wouldn't run the compiler itself on a
CP/M box of less than around 20MHz clock speed, 60k TPA, 1 Mb disk -
to run it with less than that you'd have to be pretty patient. A good
CP/M/Z80 emulator on a 486 or better is a perfect environment.
(Consider `zsim' for MS-DOS, `cpm' for Linux and presumably other
386-based Unix; others I'm not sure of (`cpm' uses 386 assembly to get
the high speed, and isn't CPU-portable). Some sort of emulation is
probably your only option - I don't know of any *real* CP/M system
which could run it at a reasonable speed.)

**** Bugs in the library

There's one bug I've noticed in Hitech C's libc library - fgets() will
not read lines longer than the buffer size correctly. I suspect it's
implemented as gets() from a stream, which is not ANSI at all. This
may not worry you, but if it does, here's something you could put
right at the end of stdio.h as a workaround (minus the `cut' lines of
course :-)):

--------------------------- cut here ----------------------------
char *myfgets(char *s,int size,FILE *stream)
char *ptr=s;
int f,c;

  if(c==EOF) break;
  if(c=='\n') break;

if(c==EOF) return(NULL);

#define fgets myfgets
--------------------------- cut here ----------------------------

I think this fits the ANSI standard. Certainly it's a lot better than
the Hitech C implementation, 'cos it works. :-)

If you're feeling adventurous, you could fix the library itself (not
too hard if you use `libr'), but this is left as an exercise for the
reader. :-)

*** Mallard Basic

Mallard Basic is, if nothing else, the first commercial program I've
got to run under ZCN. (Though it's a bit painful compared to BBC
Basic. :-))

I added a couple of extra control codes to the terminal driver to cope
with MB's expectation of a VT52 - namely, ESC-C, ESC-D and ESC-K. (I'm
surprised it uses them, really. You can implement all it needs with
straight ascii codes like BS and CR. It'd be slower, but would work on

If you want basic to use the full width of the screen and correctly
wrap long lines, do `width 120,120' after starting up.

My +3 CP/M manual only describes the keys MB uses in terms of the
unusual +3 keyboard - in case the PCW manual does something similar,
I'll describe what the keys are on the NC100 here:

Key       Function

^A        Move back along line being written/edited
^F        Move forward along line
^_        Move up on multi-line line (if you see what I mean)
^^        Move down on multi-line line
<-Del     Delete char to left of cursor
^G        Delete char under cursor (NB: Del-> also sends ^G)
^W <char> Moves forward to specified character
^S <char> Delete all between cursor and specified character
^S enter  To delete to end of line
^I        Toggle between insert and overstrike (NB: Tab also sends ^I)
Stop      Abandon changes to program line

Basic (my copy at least) only has around 16k available on startup.
This is unfortunate, but there isn't much I can do about that with
only 64k total! (Note that MB *does not* work with `bigrun', it
crashes the machine, so don't even think about trying that!)


Assuming you have QTERM 4.3f patched for ZCN (there's a copy in the
`support' directory), an easy way to take backups is using YMODEM
batch transfers.

For example, when logged into my Linux box I would run `rb' - a YMODEM
batch receive program - then do ^\ s to send, then `xy *.*' to send
all the files on the current drive. At 19200 baud on a full (256k)
drive this takes between 3 and 5 minutes.

You may want to do `user 255' before running QTERM if you have files
on the drive in other user areas - this will make sure you backup all
files in all user areas. Be sure to see `User Numbers' for more about
user area 255, as there are some potential problems associated with
using it, particularly if two different files exist on the same drive
in different user areas with the same filename.

** Logical Drives

Cards of 256k or less have only one drive, drive A:. 512k cards have
two - A: and B:. 1024k cards, the largest allowed, have four, A:, B:,
C: and D:. These logical drives are completely independent of one
another, but drive A: must be formatted for drives B:, C: and D: to be

You make a drive current by typing its name, e.g. `b:'.

** User Numbers

[Note that I use `user', `user number' and `user area' pretty much
interchangeably. Sorry if this makes it sound more confusing than it
need be. :-)]

ZCN supports CP/M user numbers 0 to 15. You can change user numbers
with the `user' command, but not (yet) in the `0a:', `a0:' or `0:'
manner. This gives you a little more than a flat filesystem (or disk);
you might describe it as a segmented filesystem, but that sounds like
the partitioning scheme used on PCs, which it definitely isn't
anything like. It's more like having 16 different directories - all at
the same level - rather than one, and having them numbered rather than
named. 0 is the default `directory', or user area.

For the uninitiated - user numbers were in CP/M to allow different
users of a CP/M machine to keep their files separate. The way it
worked meant that they would have to keep not just data files, but
also any programs they wanted to run, in that single user area.

It gets worse; the way the feature was used in practice meant that you
had a single user wanting to move files across user areas, run
programs from other user areas, etc.

I'll admit now that ZCN doesn't handle user areas very well at all.
However, this section tells you what it does different from generic

(Note that user numbers are separate from drives - i.e. if you do
`a:', `user 1', `dir b:' it will show all files in user area 1 of
drive B:.)

*** Prompt

The `A>'-style prompt is actually only used in the default user area
0. In user areas 1 to 15, the user area is printed before the `>', as
in `A1>'. In user area 255, it becomes `A*>', with the `*' meant to
indicate the wildcard-like action of user 255 (see below for more on
this user area).

*** Execution

When running a COM or SUB file, ZCN tries the following things:

1. Try current/specified drive and current user.
2. Try current/specified drive and user 0.
3. If no drive was specified, try drive A: and user 0.

This means that user area 0 (and especially user 0 on A:, if you're
using a card larger than 256k) is a good place to put programs.

*** User Area 255

In addition to the usual 0-15, ZCN allows you to use user area 255.
This isn't a user area as such, but acts like all the files on the
drive are in the current user.

User area 255 is mostly read-only, though it does allow `umv' (see
below), and file deletion. The reasoning behind it being read-only is
that files in different user areas are allowed to have the same name.
If the file is written to, it's not clear which file should be changed
or added to. Having two files with the same name also causes problems
when reading from user area 255. You would get (effectively)
randomly-chosen 16k chunks from any files with the same name.

In general, you should only read files in user area 255 if they only
appear in the directory listing once. The `ls' program, which you
should probably be using in preference to `dir' anyway, will report
`*** WARNING: duplicate files found! ***' if two or more files share
the same filename. (The warning will only appear once, no matter how
many filename conflicts there are.)

This probably all sounds rather worrying, but the situation's not
really that bad. If you make sure no filenames occur more than once
across all user areas, you have absolutely nothing to worry about.
Even if you don't, you just have to be sure to not read the offending
files from user area 255. (You couldn't do this and get meaningful
results in any case - how could ZCN tell which file you're referring

*** UMV internal command

This command allows you to move files matching a given filespec from
the current user area to another, e.g. `umv *.com 0' would move all
COM files in the current area to user area 0. An easy way to put all
files in user area 0 is `user 255' then `umv *.* 0'.

** Warning about using the Serial and Parallel ports

There is no timeout when, say, the printer is busy or serial data
cannot be sent. ZCN will simply keep trying. To interrupt this if it
happens, I'm afraid you'll have to do a cold boot - turn the machine
off, then hold down both shift keys while turning it back on.
Apologies for the inconvenience. :-(

** Using the Serial Port or Printer as the Console

Under ZCN it's possible to use the serial port (instead of the
keyboard/screen) for console input and/or output. To use the serial
port for console output you should use the command `>s'. For serial
input do `<s'. To use the serial port for both input and output, use
`|s' (that's a pipe character, as given by shift-\, then an `s').

To redirect console input/output back to the NC100 itself, just use
the above without the trailing `s', e.g. use `|' (pipe) alone to
restore normality. You can also use `<' and `>' to only restore normal
input or output respectively.

As well as serial redirection, you can direct console output to a
printer connected to the parallel port. This is *as well as* output to
the screen though, so you can see what you're doing. :-) For printer
output of this kind do `>p'. You can also use `|p', which has the same
effect as doing `|' then `>p'. (`<p' is also accepted, but simply does
the same as `<'.) Again, you should use `|' to return to normal.

A brief note in case it's not obvious - redirecting to the printer
won't have the desired effect if you're printing to a PostScript
printer. (ZCN's console output doesn't make much sense at the best of
times, but it makes far less sense as a PostScript program, trust
me...) Then again, if you're using a PS printer with an NC100 you're
probably completely insane, so maybe it won't matter to you. :-)

Using the `semi' external command described later, a crude but
effective way to print a text file is:

      semi >p; cat file.txt; |

(The `semi' should be replaced with a semicolon if you rename the
command as I do; see the description of `semi' for details.)

ZCN makes the following demands of a terminal (or terminal emulator,
or printer):

- It must use ASCII encoding for characters 32-126 inclusive.
- When a CR (13) is sent, it must move the cursor to the leftmost
- When an LF (10) is sent, it must move the cursor to the next line.
Preferably it should do this without moving the cursor to the leftmost
column, but ZCN itself does not require this.
- For the `buffered line input' function to work (as used for the
command-line and by many programs), BS (8) must move the cursor back
one character non-destructively and space (32) must erase any
character previously shown.

These are pretty minimal requirements. However, the last requirement
means that a printer can't properly implement the BS/space/BS ZCN uses
to backspace destructively - usually the new characters will simply be
printed over the old.

You should also note that the `cls' internal command works by simply
clearing the screen memory and homing the cursor, so it can't clear
the screen of a terminal.

** The Command Shell (CCP)

[CCP really stands for Console Command Processor, lest you think I'm
incredibly dim or some such... :-)]

*** Command Line Editing

The only command line editing available is delete-previous-char, and
there is no way to recall previous commands. Sorry.

You can abort the entered command line without executing it by
pressing ^C.

*** Battery level warnings

The low battery level warnings are part of the CCP - if any of the
batteries are low, you get a warning printed before each CCP prompt.
For example, if the main batteries are low, you get something like:

      *** Main batteries low ***

You can keep using the NC100 under ZCN while batteries are low, but
you run the risk of losing data etc. in memory should the battery
level get too low.

If you do keep using the NC100 when batteries are low, you should note
that if you need to use any of the builtin software (to reboot from a
memory card after a crash, for example), it will demand that you
replace the main/backup batteries (whichever is low) before
continuing. (You could just run it off the mains adaptor for a while

For some sorts of batteries this may happen even if you're not using
the ROM - what seems to happen is that the voltage goes too low for
the NC to work, so the power flickers off, in response to which the
voltage goes up slightly, enough for the NC to come back on (into the
ROM OS, as it had effectively crashed). This can happen several times.

As far as I know, the ROM software does not check for low memory card
batteries as ZCN does. I suspect that this feature of the NC100, while
documented, was not correctly implemented, and you should not rely on
the NC100 to report when a memory card's battery is low. Instead, you
should replace memory card batteries at the interval suggested by the
manufacturer (often once a year). In my case, my card started randomly
losing data about 6 months after I should have changed the battery.

[The documentation for my 512k memory card says this:

  The battery condition is output from the card as a signal that some
  computers can read. This signal will indicate one of three states:-

  1. Battery good.
  2. Battery low, should be changed as soon as possible. Data
  3. Battery discharged, data LOST.

I strongly suspect that the NC100 treats states 1 and 2 above as
`battery ok' and treats state 3 as `battery low'! (Experimentation
seems to support this theory.)]

No battery level warnings occur at any other time than when displaying
the CCP prompt. If you have been using a program continuously for a
long time and suspect that batteries may be low, you should quit to
the CCP to check.

You can disable battery warning messages by doing `batwarn 0'.

By the way, the tests I've tried suggest that rechargeable batteries
give roughly 8 hours use between rechargings (possibly more, depending
on the type). It's more difficult to tell how long you generally have
between the `batteries low' warning and effectively dead batteries,
but it seems to be something like 30 minutes for `conventional'
rechargeables. It's much shorter and more variable for the
chargeable-in-two-hours kind - anything between 1 and 5 minutes.

*** Internal Commands

ZCN has several of the normal internal commands provided by CP/M's
CCP, such as `dir'. It also provides many extra commands which I found
useful, and modifies the behaviour of others. This section lists the
internal commands (in alphabetical order), what they do, and how to
use them.

Note that a few internal commands which require args (a filename, for
example), such as `note' and `ren', will just say "Args?" if they're
used without any.

**** !! [command args]

Jump to 100h, effectively running the previous command again with new
arguments. You must *only* do this if you know the command is
re-entrant, or if you like living dangerously. It can also be used to
run a command previously loaded with `get' (see below).

**** "any text

Echo the text after the double quote (") exactly as it appears (except
that the `$' character will terminate the line, if it arises). This
one of the very few commands that does not have its command tail
uppercased before it sees it (the others being ' and `%'). It's
intended for use in SUB files (see `SUB files' below).

A variant of this command is similar but starts with a single quote
('). This also echoes the text exactly, but omits the CCP's CR/LF
after echoing it, meaning that the cursor stays on the same line.

**** %prompt_string

Set the CCP's prompt. (While you can use this command anywhere, it's
really intended to be used in `autoexec.sub' so that ZCN uses the
specified prompt all the time.) The maximum allowed prompt size is 25
chars - if you try to specify one larger than that, it is silently

The text after the initial `%' is printed verbatim apart from these

Code  Translates as...

%a    current user area
%b    current user area, if non-zero (otherwise, prints nothing)
%c    space left on current drive
%d    current drive letter
%e    current drive letter in lowercase
%%    a literal percent sign

(The `%c' number takes a little time to appear, so may not be such a
good thing to put into the prompt as you might initially think.
Personally, I find the slight delay distracting.)

Other two-char combinations starting with `%' don't output anything
(though you shouldn't depend on this). A `%' right at the end of the
prompt string is printed as a literal percent sign.

The default prompt string is `%d%b>' (which could be defined with the
command `%%d%b>'). Here's another example prompt string, the prompt I
use on my machine - `rus@amnesia:/%e/%a>'. It gives a prompt not
dissimilar from the prompt I use on my Linux box, and shows one way
you can get something which looks a bit like a `path' into the prompt.
(MS-DOS users might like to try `%d:\%a>' or `%d:\%b>' for a similar

**** BATWARN <0 or 1>

Disables/re-enable low battery warnings. You should use this like
`batwarn 0' to disable battery warnings if you appreciate that the
main batteries are low (for example), but want to carry on without
getting `*** Main batteries are low ***' in your face all the time. Be
careful when doing this, because it's an inherently dangerous thing to
do, and be sure to change the relevant batteries as soon as possible.

**** BDOSDBUG <0 or 1>

Enable (or disable) display of which BDOS function is being called as
it is called. The function number is displayed in hex - for example,
`[0A]' would indicate that the program is reading a line of text from
the console. Enabling this output can be useful when debugging
programs. For various reasons, functions 2 (console output) and 46
(get disk free space) are treated slightly differently from other BDOS
functions, and as a result are not reported on.

**** CAT filename

Display a ^Z-terminated text file from beginning to end, without
pausing. (^C quits.)

(This means it's not a true `cat' command - that is, it doesn't
concatenate files - but simply a synonym for `type'. Still, it's handy
for Unix fans like me. :-))

**** CAPSCTRL <0 or 1>

Disable/enable swapping the functions of the `Caps Lock' and `Control'
keys. (It's off by default - i.e. the keys do what they say they do.)
This option may be useful if you like having a control key above the
left shift key (rather than below it). That said, the `Function' key
always acts like a control key no matter what.

Note that this swaps the functions of the keys at quite a low level -
if you've enabled the key-swapping, then whenever ZCN requires you to
press the physical `Control' key (for screen dumps and for pausing
output) you will *have* to use the `Caps Lock' key instead.

**** CBOOT

Cold boot ZCN from the memory card. If the card is not bootable, or
there's no card in the slot, ZCN will say "Bad crd/drv/format" rather
than booting.

**** CD n

Set current user area to number `n', or to number 255 if `n' is an
asterisk. If `n' is omitted, acts like `cd 0'. This alias for `user'
should make slightly more sense to MS-DOS and Unix users, though the
flat `directory' structure in CP/M makes their `cd' commands a poor
analogy, to be honest. Still, at least it's easier to type, right? :-)

**** CRLF <0 or 1>

Disable (or re-enable) the line-break (CR/LF) after a program exits.
Generally you'll always want this on, but it can be useful to turn it
off temporarily in a SUB file. (An easy way to get a CR/LF should you
need one after `crlf 0' is to use `"' or `vdu 13 10'.) Just make sure
you remember to re-enable it afterwards, or it'll all be a bit
confusing. :-)

Note that this doesn't affect the CR/LF always output after you type
in a command, so the effects of a `crlf 0' may not be immediately
obvious. Doing `ver' should clarify matters.

**** CLS

This clears the screen. (NB: this clears the entire screen, including
the top two and bottom two pixel lines.)

**** DF

Report how much space is free on all available drives. An example of
what the output's like: `A:=2k B:=43k'. (The values will probably be
different for your card.) Only drives which exist on the card are
reported on.

**** DIR [filespec]

List the files in the current drive/user. If a filespec is given, it
only shows files matching the filespec. The wildcards `*' and `?' can
be used. If no file is found/matches, then the error `No file'

`dir' exists primarily for CP/M compatiblity, and so that there's some
internal command to list files - see the `LS' external command for how
to get a much better (sorted, and optionally with file sizes)
directory listing.

**** DUMP filename

Give a hex and ASCII dump of the specified file, pausing after every
128 bytes. Bugs: if the file position is greater than 65535, it'll be
shown incorrectly.

**** ERA (or RM) filespec

The CP/M-style delete command. (ERASE and DELETE are not recognised.)
Delete all files matching the filespec. Bugs: does not prompt when
deleting multiple files, which it should really.

**** FORMAT d:

Format the given drive. Cards of 256k or less are formatted as a
single A: drive. Cards larger than that (512k and 1024k) are formatted
as two 256k logical drives A:/B: or four drives A:/B:/C:/D:
respectively. On these larger cards, the A: drive must formatted in
order to format and use any of the others. (The logical drives are
formatted on an individual basis.) You can reformat one of the logical
drives without harming any others.

So to fully format a card of 256k or less, use `format a:'.

For a 512k card, do `format a:' then `format b:'.

And for 1024k cards, do `format a:', `format b:', `format c:', and
`format d:' in turn.

If the drive is already formatted in ZCN format, you will be asked
whether to reformat it. (It should if the drive is already formatted
in the ROM software's format too, but I haven't tested this.)

**** GET hex_address filename

Load a file in at the specified address (in hex). This is useful for a
variety of things:

- Loading a COM file off one card, then executing it with another in
the slot, e.g. `get 100 foo.com', change cards, then `!!'.

- Patching a COM file after it's loaded. You normally do this by
loading the COM file, then loading a small patch over some part of it.

- Loading a previously saved screen dump, e.g. `get f080 screen.dmp'.

This command makes it easy to crash the machine if you don't know what
you're doing, so be careful, and check your typing. If you miss out
the `1' in `get 100 foo.com', you'll soon know about it. :-)

**** IFNPEEK addr val command [args]

If byte at (hex) `addr' *does not* equal (hex) `val', run command,
otherwise do nothing. This is primarily of use in SUB files.

See `ifpeek' below for details.

**** IFPEEK addr val command [args]

If byte at (hex) `addr' equals (hex) `val', run command, otherwise do
nothing. This is primarily of use in SUB files.

Note that using a print command (' or ") will result in all-caps text,
since ZCN didn't see the command until after the `ifpeek' took place.
This is unfortunate, but there's nothing I can do about it. (It also
applies to the `%' prompt-setting command, but you're much less likely
to want to use that as the command in an `ifpeek'.)

To abort a SUB file if some command goes wrong, use `ifpeek ...
quitsub'. Obviously there has to be a byte in memory which indicates
if the command worked or not!

To check the value of 80h after the last command finished, use 3 as
the `addr'. This is primarily intended to be used to check the exit
status of programs compiled with Hitech C; however, there's no reason
you couldn't use it to return an exit status from your own programs.
If you want to check if a Hitech C command returned a non-zero exit
status - for C programs this usually means it failed somehow - then
use ifnpeek instead, like this: `ifnpeek 3 0 ...'.

The only command which does not have 80h copied after it exits is
`rem'. (The same applies to a blank command-line, of course, but
that's not really a command as such.) *ALL* other commands and
programs have it copied when they exit, whether they change it or not.

**** K3

Show how many K are free. :-) In other words, show the amount of
memory available for running programs in, or the transient program
area (TPA) as CP/M calls it. At the time of writing, this will be 46k.

For any techies out there who may be interested, the number given is
int((bdos_address-512)/1024). 256 of the 512 subtracted is to discount
the zero page, and the other 256 is to allow for stack space. So it's
a realistic estimate of the maximum program size.

**** MEMDUMP address

Show 128 bytes of memory, in hex and ascii, from the address given.
The address should be given in hex.

I consider this command to eliminate the need for a `peek' command,
which you might otherwise expect as a counterpart to `poke'.

**** MORE filename

Essentially, this is `cat' but pausing after every ten lines. In order
to show as much at a time as possible, you aren't prompted to press a
key to continue, as such; instead the cursor is moved to the
bottom-right hand corner of the screen to indicate that there is more
text waiting to be shown. There is no way of moving back through the
file. (^C quits.)

**** NOTE filename

This command lets you type text into a file. (Any existing file will
be overwritten.) There's no editing, and no prompt - it's quite crude,
but being an internal command it is at least always there. You just
keep typing text until you're done, then type in a line consisting
solely of a single `.' (full stop).

Mainly this is handy for those awkward situations where you for some
reason don't have a text editor like ZDE handy, but need to make a
quick note or something like that.

Don't do a ^C to exit - if you do, the text isn't saved (`note' builds
the text up in memory, and saves when you're finished). If you should
do this, though, you could salvage the text with `save', as the text
starts at 0100h.

**** POKE addr val

Set the byte at address `addr' to value `val'. The address and value
must be in hex.

I said this in the description of `get', but it applies equally to
`poke', so I'll repeat it: This command makes it easy to crash the
machine if you don't know what you're doing, so be careful, and check
your typing.

Using the internal commands `get', `poke', `memdump', and `save' is a
bearable way to patch programs and other files if you haven't got a
better way of doing it. (And of course, Real Programmers write all
their programs using `poke'. :-)) However, I recommend using `wade'
for patching programs/files if at all possible.

**** QUITSUB [command [args]]

Abort any currently-running SUB file. This is only useful in SUB
files (of course :-)), and usually only useful in combination with
`ifpeek' or `ifnpeek'. If a command is specified, that command is run

**** REALBEEP <0 or 1>

This disables/enables a real (noisy) beep in place of the `visual'
one. If you like having a real beep you could put `realbeep 1' in
`autoexec.sub' to have it automatically enabled.

**** REM (or #) [any text]

This command does exactly nothing. It allows you to put comments in
SUB files.

**** REN file1 file2

Rename file from file1 to file2. Wildcards are not permitted.

Note that this is *not* the way the command works in CP/M - on that,
the syntax is rather strange, effectively `REN file2=file1' [sic].

**** REXEC filename

This reads a uuencoded file from the serial port, decodes it, and
writes the resulting binary file under the filename given. (It outputs
a `.' for each line received.) The name stands for `Remote EXECute',
as the command used to just execute the (command) file after it was
transferred. That dates back to the time when I was running ZCN with a
16k TPA, a 32k ramdisk, no PCMCIA card and my fingers crossed. :-)
After ZCN stabilised a bit, I changed `rexec' to work as it does now,
which is almost certainly more useful. (In any case, you could get the
old behaviour if you really needed it by removing the card, doing
`rexec foo' (it'll say "No file" but the copy in memory is fine), then
doing `!!'.)

It's intended for getting a real serial transfer program across, such
as QTERM (which I recommend). It won't work (will probably crash!) if
files bigger than TPA are transferred.

**** SAVE n filename

Save `n' pages of memory, starting from 0100h, to file specified. A
page, in the context of this command, is 256 bytes. This is
traditionally used to save COM files after patching, but can be useful
for other things too.


A very simple terminal program. It just echoes serial input, and sends
keyboard input to the serial port. This can actually be very, very
useful if you're using your NC100 as a terminal to a Unix box with a
suitable termcap/terminfo entry as given earlier. You can use ^\ then
q (or ^\ then ^C) to quit; ^\ then ^\ sends a literal ^\.

**** SETBAUD [digit] (removed in ZCN v1.2)

In versions of ZCN prior to v1.2, `setbaud' set the baud rate the
serial port ran at, using a single digit (`4' for 2400, `5' for 4800,
`6' for 9600, etc.). It was replaced with the rather less inscrutable
`stty', but for masochists, an emulation of the old `setbaud' is
available in the `utils' directory, as `setbaud.sub'.

**** STAT (removed in ZCN v1.1)

In versions of ZCN prior to v1.1, `stat' gave a few bits of useful
information, for example:

Sys upgrd spc: 15 bytes
Max prog size: 45k
Free on drivs: A:=2k B:=43k

As you may already realise, the second line was replaced by `k3', and
the last line by `df'. (Most people won't miss the first line. :-))

In case there's anyone who misses `stat', or thinks it sounds useful,
I knocked up an external command `stat' (i.e. stat.com) which emulates

(Note for those who want to hack ZCN: `Sys upgrd spc' reported the
amount of unused space between the ZCN system code and the ZCN static
data area (starting at E600h) allowed for upgrading before the origin
(in main.z) has to be moved down. You *can* still get at this number -
it's stored at start+15 (see main.z) - but it's more tricky now. Do
`memdump 7', then do memdump for 256 times the byte displayed there
plus 15; so e.g. for BBh, you'd do `memdump bb0f'. The word there
(though the high byte should always be zero) is the number you want.
It's probably easier to just use stat.com instead... :-))

**** STTY baud_rate

Set baud rate of serial port. The default is 2400 baud. Supported
speeds are 150, 300, 600, 1200, 2400, 4800, 9600, and 19200 baud.

Which baud rate is best to use depends on what equipment you're using,
what you'll be doing, etc. Assuming the `other end' is capable of
anything up to 19200 baud, here are some guidelines:

If you want to do file transfers, you should be able to do so without
losing any packets even at 19200 baud. (If you get too many errors,
use 9600 baud instead - that should definitely work. But I've never
had any problems with 19200.)

If you want to use the `other end' interactively, i.e. if you want to
use a terminal emulator, then you may need to use a lower speed to
avoid losing characters.

Now, consider these facts:

- ZCN has a 768-byte serial input buffer.

- The screen driver can only write characters at a speed of between
  about 110 and 800 chars/sec, depending on line length (i.e. how
  often it needs to scroll). (This is as tested with the built-in
  `sertest' program; with an external program like QTERM there is
  system call overhead, etc.)

- ZCN uses one start bit, 8 data bits and 1 stop bit which means that
  the maximum number of chars/sec you can transfer at a given baud
  rate is baud_rate/10.

If you assume a short line length (which slows things down because of
the more frequent scrolling required), you get these results (I
haven't bothered with speeds lower than 1200 baud; using such speeds
makes watching paint dry seem like a exciting spectator sport):

baud rate   chars/sec   time to first lost character (sec)

 1200       120        768/( 120-110) =  76.80
 2400       240        768/( 240-110) =  5.91
 4800       480        768/( 480-110) =  2.08
 9600       960        768/( 960-110) =  0.90
19200       1920        768/(1920-110) =  0.42

Note that the `time to first lost character' indicates the time to the
first time the buffer is full when a character needs to be added
(which causes a lost character) rather than the time to when the
display catches up and the lost character is noticeable, which may
well be rather longer.

Assuming a more reasonable line length (about 78 chars/line) you end
up with:

baud rate   chars/sec   time to first lost character (sec)

 1200       120        768/( 120-800) =  (never)
 2400       240        768/( 240-800) =  (never)
 4800       480        768/( 480-800) =  (never)
 9600       960        768/( 960-800) =  4.80
19200       1920        768/(1920-800) =  0.69

So, what does this all mean? Well, it depends on how you look at it.
In my experience, 2400 is reliable except in extreme cases (the
extreme case being long bursts of short lines - you need about 1500
bytes of short lines continuously to start losing chars at 2400). 4800
can usually keep up too, though it's more prone to buffer overruns.
You can use higher speeds if you want - they'll work, but you'll lose
characters increasingly frequently as the buffer fills up. Personally,
I just use 19200 the whole time. It's great for file transfers, and
the input buffer can generally handle the bursts of output when I use
it as a terminal at that speed.

One final note: If there's no more than a screen full of text
transmitted at a time - for example, if you're just using an editor on
the remote host - then you can probably get away with using any baud
rate. The reason is, assuming only 80 columns are used and 10 lines,
you get a max of 800 chars per screen refresh (usually less due to
status line(s) etc.), and a single burst of that size can (just
about!) be dealt with every second or two.

**** SYS d:

Add the system to a drive and make it bootable. I recommend you only
make A: drives bootable, as booting from B:, C: or D: means
remembering different, awkward, boot procedures. Cards can be made
bootable (and unbootable again - see `UNSYS' below) without harming
any files held on them. The system blocks needed are effectively taken
from the end of the drive. If this is not possible an error message is
given. (You may want to try `defrag' on the drive then try `sys'
again, if `sys' fails when you think it should have worked.)

**** TIMEOUT [mins]

Set the auto-poweroff timeout in minutes. Use `timeout 0' to disable
auto-poweroff. The default setting is 5 minutes. The maximum possible
setting is 10 minutes.

**** TYPE filename

Display a ^Z-terminated text file from beginning to end, without
pausing. (^C quits.)

**** UMV filespec n

Move files matching `filespec' to user number `n'. Wildcards are
permitted. If any files with the same names as those to be moved exist
in user `n', then the error "File exists" is given and *none* of the
files are moved. (Sorry if this is a pain but it seemed like the best
way to do it, all things considered.)

**** UNSYS d:

Remove any system blocks from a drive, returning them to the normal
data blocks area, and makes the drive unbootable. Like `sys', this
doesn't harm any files on the drive.

**** USER [n | * | -]

Set current user area to number `n', or to number 255 if `n' is an
asterisk. (`CD' does the same.) If `n' is omitted, i.e. if plain
`user' or `cd' is used, then it acts like `user 0'. If `n' is a dash
(`-'), then the user area most recently set by `user' or `cd' is used.

**** VDU char_value [char_value]

Output one or two characters, given their ASCII value. This is
primarily useful for outputting control codes in SUB files.

**** VER

Report ZCN and ROM version numbers, and the date/time (in YYYY-MM-DD
HH:MM format) the running copy of ZCN was assembled.

The ROM version is reported by looking for the text `ROM v' in the
first 16k of ROM, then printing the version number found there. If the
text `ROM v' isn't found, then the ROM version number isn't reported.
(The version number is from the built-in test program though, so this
should be ok. Certainly it works on my machine. :-) By the way, you
can run the (undocumented) diagnostic test program by holding down
Function and Symbol when turning on. You have to reset the machine
before doing this (or use `runrom') if you were previously using ZCN -
it's a bit picky.)

**** XYZZY

Traditional. :-)

It displays the message `Nothing happens.' If you want to know *why*
it does that, read on:

:xyzzy: /X-Y-Z-Z-Y/, /X-Y-ziz'ee/, /ziz'ee/, or /ik-ziz'ee/
   adj.  [from the ADVENT game] The {canonical} `magic
   word'.  This comes from {ADVENT}, in which the idea is to
   explore an underground cave with many rooms and to collect the
   treasures you find there.  If you type `xyzzy' at the appropriate
   time, you can move instantly between two otherwise distant points.
   If, therefore, you encounter some bit of {magic}, you might
   remark on this quite succinctly by saying simply "Xyzzy!"
   "Ordinarily you can't look at someone else's screen if he has
   protected it, but if you type quadruple-bucky-clear the system will
   let you do it anyway."  "Xyzzy!"

   Xyzzy has actually been implemented as an undocumented no-op
   command on several OSes; in Data General's AOS/VS, for example, it
   would typically respond "Nothing happens", just as {ADVENT}
   did if the magic was invoked at the wrong spot or before a player
   had performed the action that enabled the word.  In more recent
   32-bit versions, by the way, AOS/VS responds "Twice as much
   happens". ...

      -- The Jargon File, version 3.2.0; every so often a version
      is published as "The New Hacker's Dictionary".

I hope ZCN breaks new ground by being the first OS to *document* an
xyzzy command, but I expect someone else beat me to it somewhere. :-)

*** External Commands

Of course, external commands (i.e. separate programs) are generally
much more useful than the simple internal commands provided. You can
run two different kinds of external commands - COM files or SUB files.
Both are invoked by simply typing the filename (without the `.com' or
`.sub') and any arguments.

To run an external command with the same name as an internal command -
say, for example, you have a `dir.com' you want to run - give an
explicit drive specification (e.g. run it with `a:dir'). This prevents
ZCN from trying to interpret the command name as an internal command.

If you want to get straight to the list of external commands ZCN has,
then skip the next few sections. (You should probably come back to
them later, though.)

**** COM files

These are binary executables loaded in at, and started from, 0100h. If
a program is too big for the transient memory, ZCN gives a `too big'
message. Execution of a program can be aborted after the command is
given, i.e. while it's loading, by pressing ^C. This will be
acknowledged after the COM file has loaded. (ZCN only tests for ^C
once, after it's finishing loading the program, to avoid slowing down
the loading process.) Pressing ^C while the program is loading also
terminates any currently running SUB file.

**** SUB files

These are normal text files which give lists of command lines to
execute. Any commands can be run from a SUB file, including all the
internal commands. Unlike CP/M, ZCN does not display each line as if
it was entered. (It does still print a CR/LF after each command by
default, but you can use `crlf' to disable (and re-enable) this.)

ZCN runs a SUB file called `autoexec.sub' (on drive A: in user 0) on
bootup if it can find it.

**** SUB files with parameters

ZCN itself doesn't allow you to pass any parameters to the commands in
a SUB file. However, you can use the external program `submit' to do
this. Submit translates `$1' in a SUB file to the 1st argument given
to the submit program (after the SUB file's name), `$2' to the 2nd,

For example, if you did `submit foo bar baz' and the file `foo.sub'

      rem submit demo - guess what happens to $1 and $2 here?
      "This is a demonstration of using submit with $$1=$1 and $$2=$2.
      "I wonder if you have a file called $2...
      ls $2
      "Hmm. How exciting. :-)

...then submit would create a file `$$$.sub' containing:

      rem submit demo - guess what happens to bar and baz here?
      "This is a demonstration of using submit with $1=bar and $2=baz.
      "I wonder if you have a file called baz...
      ls baz
      "Hmm. How exciting. :-)

(Note that the `$' character terminates any string output by the `"'
command, so the above example is actually a bit silly in practice.
Just consider it a gedanken example. :-))

You can get a single `$' character in the output file by using `$$' as
you can see above. Note that aside from that, `$1' is translated to
`bar' and `$2' to `baz' throughout the file, even in the `rem'

Writing the `$$$.sub' file doesn't seem that useful unless you know
that, after a warm boot (which submit does after writing the file),
ZCN looks for the file `$$$.sub' and runs it if it's readable. After
it's run through all the commands in `$$$.sub', or if the running of
the SUB file is aborted with ^C when `between commands', it deletes
it. As you might imagine, this behaviour means that `submit' can be
quite a useful program.

In fact, you don't have to type out `submit' every time you want to
run, say, `submit foo bar baz' as in the example above. Say we
modified the `foo.sub' file to this:

      submit foo *
      rem submit demo - guess what happens to $1 and $2 here?
      "This is a demonstration of using submit with $$1=$1 and $$2=$2.
      "I wonder if you have a file called $2...
      ls $2
      "Hmm. How exciting. :-)

...that is, we add the line `submit foo *' at the beginning. (You can
also use a `?' instead of the `*', due to the way submit reads the
command-line. It makes no difference which you use.) Now you can
simply run `foo.sub' as `foo bar baz' and the submit program will sort
things out. The `*' is necessary to inform `submit' that we're running
it in this way - specifically, it causes it to skip the first line of
the input file and use the old command line, which is saved in a
temporary buffer by ZCN for this purpose, and also to `find' the SUB
file in the same way ZCN does when it runs a SUB (or COM). (See
`Execution' in the `User Numbers' section above for details.) The
`submit filename *' line must be the first line of the SUB file for
this to work. This `submit filename *' hack is ZCN-specific and won't
work on CP/M.

Here's another, more practical example of a SUB file with parameters:

      submit print *
      rem print.sub, a crude file-print utility
      cat $1

(You may recognise this as being the same as the `semi' command shown
in the `Using the Serial Port or Printer as the Console' section.)

You could also add a line after the `cat' one to print a formfeed, to
make the util slightly nicer - the line `'^L' (an apostrophe followed
by a literal control-L) would achieve this. This is easily entered
with ZDE by typing ' then ^P then ^L.

In CP/M submit, you must specify at least as many arguments as the SUB
file uses, otherwise it'll bomb out with the error `Missing argument'.
In ZCN v0.3, submit worked this way. I changed it to be similar to
MS-DOS batch file and Unix shell script behaviour in ZCN v0.3a - ZCN
submit now replaces unspecified args with a space - as the CP/M
behaviour is almost always not what you actually want. (Ironically,
the above `print.sub' is a notable exception. :-))

Note that the format of `$$$.sub' is exactly the same as that of
ordinary SUB files - a normal text file with one command per line. I
don't think this is the case with CP/M, so generic CP/M programs which
generate `$$$.sub' files are unlikely to work as intended. I might add
support for CP/M-style `$$$.sub' files at some point. With emphasis on
the `might'. :-)

**** ZCN external commands

ZCN comes with several (optional) external commands, described below
in alphabetical order. I recommend you copy at least `ls', `optdir',
and probably `submit', across to your NC100; those are certainly the
most useful, and they're all under 1K. Makes a change from most
programs these days. :-)

***** BBCBAS [-H] [filename]

[This is a *BIG* section - it takes up about 20% of this file! You may
want to skip through most/all of it if you're not interested in BBC

Runs BBC Basic from ROM as if it were a ZCN program. None of the
weirdness needed for `runrom' etc. is needed for this, just do
`bbcbas' to run it.

BBC Basic on ZCN is largely the same as it is when running under the
ROM software. However, there are various advantages and disadvantages
to using BBC Basic from ZCN; these are described in the subsections

If you use file I/O, the differences you'll most need to bear in mind
are that you can't write to files with OPENUP (on ZCN it does the same
as OPENIN), and that text files should be referred to as if their
names started with a colon (`:'). See `About text files' below for
more details on the latter point.

****** Advantages of running BBC Basic in ZCN

- It's in ZCN. :-) This is surely more convenient than having to use

- It runs roughly 10% faster. (This is due to an optimisation in my
emulation of the ROM's testescape routine, which is called by Basic
very often indeed.)

- It supports a second `copy' cursor like on the BBC. This is FAR more
useful than `EDIT' and considerably more flexible. Essentially it lets
you copy text from anywhere on the screen, from lots of different
lines if you like, and you can copy *any* text, not just pre-existing
parts of your program. See the section `The copy cursor' below for

- You can read/write files of up to 253k, rather than files of less
than 64k on the ROM software. (However, PTR# and EXT# only work
correctly for files of less than 64k, due to a restriction imposed by
the ROM.)

- You consistently get 36k of free memory for Basic programs. (On the
ROM s/w it varies depending on whether you have files in the low
memory or not, and if so how big they are.) Though admittedly, this is
only slightly more than the maximum possible under the ROM (35.25k).

- You can automatically load and run a Basic file with any name using
`bbcbas filename'. (On the ROM only a file called "AUTO" runs
automatically - and it does so whether you want it to or not.)

- Greater text resolution, as it uses ZCN's 120x10 screen rather than
the ROM's 80x8.

- Online help of sorts. Specifically, lists of the PLOT commands and
VDU codes, and a brief example of how to use the built-in Z80
assembler. See the section `Online help' below for details.

- A more fitting *CAT (a.k.a. *.) command, based on `ls'.

- You can use it via the serial port. (Though graphics commands still
only work on the NC's screen, of course.) There are a couple of
problems with this, unfortunately; see the `Bugs' section below.

- When you use EDIT, the cursor starts at the end of the line rather
than the start, which is more likely to be what you'd want. The copy
cursor is much better for editing than EDIT though, so it's
questionable how much use this really is. :-)

- Values of certain keys returned by INKEY make more sense. ^H returns
8, not 227; ^P returns 16, not 222; and Del-> returns 7, not 33.

****** Disadvantages of running BBC Basic in ZCN

- OPENUP does not allow writing to files; it instead acts like OPENIN.
I think OPENIN/OPENOUT should be sufficient for the great majority of
file operations, but all the same this is probably the biggest single
disadvantage with running BBC Basic on ZCN.

- The "COM:" file (which, when used with OPENIN/OUT/UP under the ROM
software, accesses the serial port) is not supported. However, you can
still use the serial port as a printer with e.g. `*PRINTER 1' then
`VDU 2'. (The default printer is the parallel port one, of course.)

- There's no support for text windows. (Graphics windows still work.)

- There's no way to access files in different user areas than the one
Basic is started in. (Strictly speaking this isn't a disadvantage
relative to the ROM s/w as that doesn't have user areas :-), but it's
a problem all the same.)

- A maximum of three files can be open at once, rather than the ROM's
usual seven. This limit is at the file I/O interface level rather than
being anything to do with Basic, so e.g. if you do *LOAD or *SAVE from
a program when three files are already open, the *LOAD/SAVE won't

- The line-editing facilities (which you use to enter Basic programs)
don't support the cursor movement ops that the ROM does. Personally I
don't think this is a problem; the copy cursor is a more than capable
replacement. Even if you don't think that, you could always write the
Basic as a text file in ZDE, then load it with *EXEC. (Neat little bit
of buck-passing there, don't you think? :-))

- Keyboard `typeahead' is limited. If you press a key while Basic is
grinding away at some calculation, it won't be buffered, and the
keypress is ignored (except for Esc, which is dealt with specially).
In particular, it means that I've had to make `INKEY(0)' take up to
1/100th-sec to ensure that it doesn't miss any keys. I'd imagine this
is unlikely to be a problem for most programs, but it could be a
problem for, say, games.

- *KEY is not supported. Any attempt to use *KEY will give a "Bad key"
error. (Apart from *KEY0 to *KEY3, which give various help texts.)

- The time cannot be set with the TIME$="..." construction. (Any
attempt to set it is ignored.) You'll have to use ZCN's `timeset'
command to do that. However, you can still *read* the time via TIME$.

- The values returned by INKEY for the cursor keys are the same as the
keys generate in ZCN. This means the values vary from those returned
under the ROM s/w. This is probably a disadvantage, not least because
you can't tell the difference between e.g. cursor-left and
control-cursor-left (you can on the ROM s/w).

- ZCN's auto-poweroff timeout may run down very slowly if you leave a
program running which doesn't do any I/O or use ZCN at all (a simple
example is REPEAT:UNTIL 0). So if you think that's a problem, don't do
that. :-) The timeout runs down ok if a program isn't running, or if
(say) the program is left waiting for input.

****** Other differences and things to note

- *DELETE works for wildcards, too. Be careful!

- In ZCN, you have to use either *BYE or *QUIT to exit. These work
when running under the ROM s/w too, of course, but they're the *only*
way to exit in ZCN. (Well, unless you want to reboot... :-))

- BBC Basic's graphics commands normally use the full 480x64 screen.
ZCN, however, uses a 32x1 area in the bottom-left of the screen to
show its "drive lights". The way this is dealt with is that these are
only shown when ZCN is paged in, and the previous contents of that
area are restored when BBC Basic is in control again.

- While ZCN itself normally only has character bitmaps for printable
ASCII chars (those in the range 32 to 126), `bbcbas' contains some
extra code and character bitmaps so that it provides Basic with the
same characters in the range 128 to 255 as Basic has when running
under the ROM software. You can do `FOR F=128 TO 255:VDU F:NEXT' to
see them all. (The various accented characters are rather indistinct,
I'm afraid, but most of the characters are perfectly usable.) You
can't enter these non-ASCII chars direct from the keyboard (with the
exception of the pound sign (shift-3)), so to print the square root
symbol for example you'd have to use VDU 251 or PRINT CHR$(251).

- In ZCN, caps lock isn't set when running BBC Basic. Instead what
happens is that any keys input have their case inverted (upper to
lower and vice versa). This is generally preferable, as this approach
even works when running via serial, but I'm just mentioning it here in
case anyone wondered how it worked.

****** Bugs

- When using BBC Basic via the serial port, it's possible to
occasionally `hang' the machine. What's actually happening is that the
serial hardware has got confused (the weird things I have to do to get
the Basic running seem to cause this every so often) and stopped
reading from the port, not that the machine has actually hung as such;
turning the machine off then on again resets the serial hardware, and
should clear the problem.

- When running via the serial port, normal ZCN control codes are sent
for clear screen, cursor movement, cursor on/off etc., so the
appropriate commands in Basic won't work. You may also get some funny
chars appearing (usually the cursor on/off codes) depending on your
terminal or terminal emulator.

- PTR# and EXT# do not give correct results for text files; this is
due to CP/M (and ZCN) not storing the length of text files exactly,
and (for PTR#) due to the CR <-> CR/LF conversion involved. *However*,
saving a PTR# value to return to later works ok, which should cover
most uses of it with text files.

- The copy cursor doesn't work for chars in the 128-255 range, such as
the pound sign and line-drawing chars.

- The copy cursor doesn't flash. This makes it a bit easy to `lose' if
you're not careful.

- Finally, here's a bug I found in BBC Basic itself, which applies
equally when running under ZCN or the ROM s/w. In immediate mode, i.e.
when not running a program, it seems that if you type a string of more
than a certain length (five chars, I think) after `INPUT A$' (or any
other string input), you get prompted again. It's quite strange. It's
probably largely harmless though, as INPUT works ok when a program is

****** The copy cursor

The original BBC Basic - yes, the one on the BBC :-) - had a
remarkable feature which made editing on it easier and more flexible
than on most other Basics at the time, and I think it still stands up
well today. It was the ability to copy text from anywhere on the
screen and insert it as if you'd typed it from the keyboard. This
worked by you moving a second cursor around the screen and pressing
`copy' whenever you wanted to copy a character.

`bbcbas' supports this. It works in exactly the same way, except you
use the tab key as the `copy' key, and you can use ^E/^S/^D/^X instead
of the cursor keys if you prefer.

For those of you not already familiar with the idea, here's how it
works in detail. Normally when you type text in, you have a cursor
which shows you where new characters will be inserted. Simple enough,
and everyone's used to that. But under this scheme, when you press a
cursor key you get two cursors. One remains where the normal cursor
was (in fact, it *is* the normal cursor :-)), showing you where new
chars will go. But the other, which looks like an underscore and can
be moved around the screen with the cursor keys, shows you where a
char will be copied from if you press `copy' (tab). Both cursors are
advanced when you press this key, and the copy cursor wraps at the
edge of the screen in the same way as the normal one (and even moves
up the screen if it scrolls) meaning you can hold down the key to copy
many chars.

You can move the cursor around as much or as little as you want, and
copy anything. You can copy a bit, type a bit, copy a bit - it all
works in a pretty sane manner and does what you'd expect. The only
limitation is that the text must not have been `corrupted' - for
example, if you draw graphics all over some text, you won't be able to
copy it. (Also, I'm afraid you can't copy italic or bold text and the
like; only normal text works.) If you *do* try to copy corrupted text,
or something which isn't text at all, the character inserted is a

Once enabled with a cursor key, the copy cursor stays visible until
you enter the line (or press Esc).

Now, let me give you a very simple example of how you can take
advantage of this to edit a program. First, enter this program:


Yes, I'm afraid you really do have to enter it, no matter how much you
may disagree. (cough) Besides, we're just about to `correct' it... :-)

To edit it, move the copy cursor up to the start of the line. (If the
line weren't already onscreen, you'd first list it with `LIST 10' or
similar.) A single cursor up should do. Then press tab several times
(or hold it down), with the last character you copy being the space
before the `S'. Now type `IS COOL'. You may have noticed that the copy
cursor didn't move when you typed that. (Not too surprising - after
all, we didn't copy those last few chars from it.) To compensate for
that, press cursor right five times (skipping the `SUCKS'), and finish
off by copying the rest of the line by pressing tab a few more times
(or holding it down), then pressing enter.

So, after the editing, do `LIST' and you should have:


Ah yes. Much better. :-)

(An alternative approach would be to (in this case) copy up to just
before the comma, delete the `SUCKS', then type the replacement text
and copy the rest. This approach saves you having to move the copy
cursor on by hand.)

Obviously this is only a simple (and rather 70s-esque) example of what
you can do. You can copy from several lines; use it to correct an
`immediate' statement rather than a program line; use it to copy the
result of a lengthy calculation into a program line as a literal
number; all kinds of things. You can even use it in an INPUT command.

Once you've used to using the copy cursor, you'll wonder how you ever
got by without it. Really. Trust me. :-)

(By the way, as a final note on the copy cursor, I should just point
out that the cursor appearances may be a little odd to someone used to
a BBC. On the beeb, the usual cursor is an underscore-ish one, and
when you press a cursor this becomes the copy cursor, with the usual
cursor being replaced by a block one. With `bbcbas', you still get a
block cursor and an underscore cursor, but the current (block) cursor
stays where it is. I don't know if this makes sense or not, but it was
easier to code that way so that's how I did it. :-))

****** About text files

As you may or may not know, text files in CP/M are stored with a `soft
EOF' marker, ^Z. This is used because files are always a multiple of
128 bytes long in CP/M, and this is inconvenient for text files. Also,
while (on the NC100 at least) BBC Basic's OPENIN and OPENOUT expect CR
as an end-of-line marker, CP/M uses CR/LF.

Now, BBC Basic itself has no facility for distinguishing between text
and binary files (because it doesn't normally need one), so I had to
use an unusual way of allowing you to read/write a file as text. I had
to use something in the filename.

The way it works is this:

- If you give a normal filename, the file is read/written as binary.
This is how you should use LOAD, SAVE, *LOAD, and *SAVE.

- If you give a filename starting with colon (`:'), the file specified
by the rest of the filename is read/written as text. (^Z is treated as
EOF on reading, one or more ^Z's are written by CLOSE on writing, and
CR is converted to CR/LF or vice versa as needed.) This is how you
should use *EXEC and *SPOOL, and is also how you should use OPENIN or
OPENOUT when the file is a text file.

Here are examples of both. First, some commands using binary files:

      SAVE "FOO"
      *LOAD WIBBLE 4000

Now examples of some commands using text files:

      *EXEC :BLARG

It's not absolutely *vitally* important that you read/write text as a
text file, but it's usually a Good Idea. If you didn't, you'd tend to
end up with an effectively random amount of unpredictable junk at the
end of the file, and your text files wouldn't be read correctly by
many CP/M programs. (Also, any normal CP/M text files you read would
appear to have LFs at the start of all lines apart from the first.)

If you write a text file as if it were a binary file by accident (by
mistyping the colon or omitting it, say), you should be able to remove
the junk at the end of the file by loading it into ZDE, deleting the
extraneous bytes (if any), and saving. (If there aren't any junk bytes
at the end, which is actually quite likely given how defensively I
wrote the I/O code, just save it. You'll need to answer yes when ZDE
reminds you that it's unchanged - it may indeed be unchanged, but ZDE
writes it as a CR/LF file with ^Z at EOF, so you *do* want to save

A final note - I'm afraid you can't explicitly write an LF to a text
file. Disallowing explicit LFs was an unfortunate necessity, mostly
due to the way *SPOOL works.

****** About writing to the printer as "LPT:"

In BBC Basic you can write to the printer using the filename "LPT:".
This works in both ZCN and under the ROM s/w.

However, in both there is a problem with it. Unlike the printout you
get from using `VDU 2', which outputs both CR and LF so you get normal
printer output, "LPT:" outputs only CR (and not LF) at the end of a
line, which on most printers will result in a single line being
overprinted over and over again, which is not very useful and can be a
Bad Thing.

Unfortunately, there's no easy way to fix this. There are two slightly
cumbersome solutions I can think of:

- Use BPUT to output a 10 byte (LF) after every line output, for
example `PRINT #FD%,A$:BPUT #FD%,10'.

- Use VDU 2 and 3 instead to `open'/`close' the printer, along with a
combination of VDU codes 1, 6, and 21 to print to it.

****** Online help

There's a small amount of online help provided. Since BBC Basic is in
ROM and doesn't have a *HELP command nor any way to provide one,
there's no way I could have provided it like that - sorry. Instead,
you get the help using *KEY.

`*KEY' (or `*KEY0') brings up a brief message saying what `*KEY1',
`*KEY2', and `*KEY3' do.

`*KEY1' lists what the various PLOT commands do. It may not come as a
surprise to find that being able to always have this list handy was
the main reason for implementing this online help feature. ;-)

`*KEY2' lists what the VDU codes in the range 0 to 31 do.

`*KEY3' gives a brief example of how to use the built-in assembler.

Unfortunately, these help texts are only printed to the console - even
after `VDU 2' they won't appear on the printer, nor are they
susceptible to *SPOOL (which is a pity for the *KEY3 text in

****** BBC Basic features not covered in the NC100 manual

This section applies both to running it in ZCN and under the ROM
software, and is mostly based on having read the NC100 manual, the
book "NC100 Magic", and the Acorn Electron manual. (The Electron uses
BBC Basic.) A couple of details (e.g. where the CALL parameters are
stored) are based on my own investigation.

- "AUTO"

As mentioned earlier, when run under the ROM, Basic auto-runs a file
called "AUTO" on startup, if present. In ZCN, `bbcbas' uses this
mechanism to load any file you want, but *only* when you want. (That
is, it won't load a file called "AUTO" unless you tell it to.)

- Abbreviations

The NC100 manual completely fails to mention that BBC Basic allows
many abbreviations of commands and functions. It would take a good
deal of space (and effort ;-)) to list them all, but the most useful
ones are probably:

      `*.' for *CAT
      `L.' for LIST
      `P.' for PRINT (*not* `?')
      `CH.' for CHAIN
      `F.' for FOR
      `N.' for NEXT
      `E.' for ENDPROC
      `REP.' for REPEAT
      `UN.' for UNTIL
      `REN.' for RENUMBER
      `DEL.' for DELETE (and `*DEL.' for *DELETE)
      `I.' for INPUT

- Behaviour of multi-statement `IF'

A statement like the following can do different things on different


All will print "FOO" and "BAR" if A is 1. (Assuming they support
multi-statement program lines, that is. :-)) However, some will print
"BAR" even if A is not 1.

Fortunately, BBC Basic not only does the Right Thing for the above (it
prints "BAR" only if A is 1), but can even accept more flexible use
like the following:

      IF A=1 THEN P."A":P."B" ELSE P."C":P."D"

Here, "A" and "B" are printed only if A=1, and "C" and "D" are printed
only if A<>1.

- Characters returned by INKEY and GET

(GET$ and INKEY$ are (roughly) just like CHR$(GET) and CHR$(INKEY), so
they're not explicitly dealt with here.)

The values of most key codes returned by INKEY and GET are fairly
obvious; for printable ASCII characters, it's the ASCII value, etc.

But some of the values are not quite so obvious, and the most useful
of those are listed here. Some keys return different values under ZCN
and under the ROM software, so the values returned are listed in
separate columns.

key         ZCN value   ROM value

Esc         27         27   (only after *ESC OFF, of course!)
Tab           9 (^I)      9
Menu        96 (backquote)   134
Del->         7 (^G)    33
<-Del       127         127
Cursor up     5 (^E)    240
Cursor down 24 (^X)    241
Cursor left 19 (^S)    242
Cursor right        4 (^D)    243
Control-Esc 27         <key is ignored>
Control-Tab   9 (^I)    225
Control-Menu        0         212
Control-Del->       7 (^G)      5
Control-<-Del     31 (^_)    212
Control-up    5 (^E)    248
Control-down      24 (^X)    249
Control-left      19 (^S)    250
Control-right       4 (^D)    251

Note that, unfortunately, you can't tell a control+cursor keypress
apart from a normal cursor keypress on ZCN. (Symbol+cursor works
though; that just adds 128.) Also, many control+key keypresses return
strange values in the ROM, and many control+shift+key keypresses are
simply ignored.

- How to pause a LIST (or anything else)

Since the NC100's version of BBC Basic doesn't support the BBC's
page-mode VDU codes, there's a need for an alternative means of
pausing (say) LIST. When running under the ROM software you can press
Esc to pause, then any other key (other than Esc) to continue. When
running under ZCN you can use ZCN's usual ctrl-symbol technique to
pause it - i.e. you can pause the output by holding both the `control'
and `symbol' keys simultaneously, and the output starts again when you
let go. ZCN's approach has the advantage that Esc always does the same
as it would on a BBC, and you can pause with ctrl-symbol even during a
GET or INKEY (which under the ROM s/w you can't, as in those
situations a single Esc escapes immediately).

- What the values used with `LISTO' mean

The manual mentions LISTO but not what the values mean. Here's a table
showing them:

value space after line no.?  indent FOR..NEXT?  indent REPEAT..UNTIL?

0           no              no                  no
1           yes             no                  no
2           no              yes                 no
3           yes             yes                 no
4           no              no                  yes
5           yes             no                  yes
6           no              yes                 yes
7           yes             yes                 yes

The NC's BBC Basic defaults to format 7. I think generally you would
want to use either format 7 or format 1, but obviously it's up to you.

To set the default LISTO setting for `bbcbas', set the byte at offset
4 in the file to your preferred LISTO value. The easiest way is to use
wade, doing something like this:

      A>wade bbcbas.com
      WADE 1.5 - Wagner 85-04-27  (TurboDos & CP/M 2 Version)
      Low=0100   High=1F7F   Max=1F7F   Top=85FF
      :s104 x                 <-- replace `x' with your LISTO value
      :w l h                  <-- the middle char is an L, not a one!

After doing that, you can use `bbcbas -h' to check the default is now
your preferred LISTO value.

- How `RND' *really* works

The manual only describes 3 of the 5 possible ways to use BBC Basic's
terribly nice RND function (that it failed to mention the vitally
important RND(1) is almost beyond belief!), and its description of
what `RND' by itself does is wrong.

Here's a quote from the Electron manual which applies equally to the

(notes in square brackets are mine)

"RND by itself generates a random whole number between -2147483648 and
2147483647. [i.e. between -(2^31) and (2^31)-1]

RND(-X) gives the value -X and resets the random number generator to a
number based on X. [i.e. sets the seed]

RND(0) repeats the last random number given by RND(1).

RND(1) generates a random number between 0 and 0.999999. [More
strictly, >=0 and <1. Given the limits of Basic's floating-point
accuracy, the maximum possible random number is about
0.99999999976716935635, though this would normally be printed as 1 -
if you set `@%' to &2020, it's printed as 0.9999999996.]

RND(X) generates a random whole number between (and possibly
including) 1 and X."

NB: One important detail not mentioned above is that RND(0) gives an
incorrect value if a different form of RND (other than RND(0)) was
used since the last RND(1). (This is the case on the BBC and Electron
too, by the way.)


CLOSE#0 closes all currently open files. It works even if no files are


The manual mentions the variables PAGE, LOMEM, and HIMEM, but not TOP.
To quote the Electron manual, TOP contains "the address of the first
free memory location after the top of the BASIC program. TOP-PAGE will
give the length of your BASIC program in bytes."

TOP usually has the same value as LOMEM.


The manual mentions POS, but not COUNT. While POS is the current
horizontal char position, COUNT is the number of chars output on this
line. (This may differ after a PRINT TAB or whatever.)

- About `ON' and `ON ERROR'

The manual incompletely describes `ON', so let's just fill in the

Normal `ON' (which picks a line number to GOTO based on the value of
the expression tested) does not work the way it does on, say,
Microsoft Basic. Here it gives an error if the expression is outside
the range for which line numbers are specified - on most other Basics
it simply `falls through' in that case. However, a more flexible `ON X
GOTO ... ELSE ...' form is allowed by BBC Basic, which can be used
like this:

      ON X GOTO 100,200,300 ELSE 400

...but also for other commands, for example:

      ON X GOTO 100,200,300 ELSE PRINT "Bad option":ENDPROC

To make it `fall through' like on other Basics, you can use:

      ON X GOTO 100,200,300 ELSE

A different form of ON is `ON ERROR', which says what to do when Basic
would normally stop and report an error. The manual describes `ON
ERROR GOTO' and `ON ERROR GOSUB', but says no more than that. Well,
the first thing to say is that you can turn error trapping off with
`ON ERROR OFF'. But probably more important is that the `ON ERROR foo'
form of the statement (for all cases except foo="OFF") is treated a
bit like a hypothetical `IF ERROR THEN foo' statement would be; that
is, you can have *any* statement after the `ON ERROR'. You can even
have multiple statements, like this:

      ON ERROR PRINT "Oh dear...":PROCerrorhandle:END

But the NC100's BBC Basic seems very easy to inexplicably lock up with
exotic forms of `ON ERROR' (it seems to forget to cancel the error) -
in fact, the only form which seems at all reliable in my experience is


This is an odd, but kind of useful, feature of BBC Basic which doesn't
usually seem to be very well documented.

If you have a Basic statement which is complete unto itself and could
not possibly be extended, such as arg-less keywords (e.g. `REPEAT',
`CLS') or keywords with a fixed number of args (e.g. `CLOSE#',
`DRAW'), then the colon to separate the statement from one which
follows it can be replaced by a space. Here are some examples:

      MOVE 0,0 DRAW 50,0 DRAW 50,50 DRAW 0,50 DRAW 0,0 REM square

It's not clear whether taking advantage of this is a good idea or not
in general. It seems reasonable to use it for empty loops, but much
more than that would probably be confusing, I think.

By the way - it can, it seems, be extended to *any* context where its
use is unambiguous, e.g.:

      FOR F=1 TO 4500 NEXT REM wait about 3 seconds
      A=TIME FOR F=1 TO 10000 NEXT F PRINT TIME-A REM time the loop

...but I'm pretty sure that's simply *too* confusing, full stop. :-)

Only the uses described in the initial paragraph above seem to work on
other versions of BBC Basic - the looser uses immediately above won't
necessarily work. If this sounds confusing, you may be best off
avoiding this slightly shady area entirely... :-)

- OS commands (e.g. `*ESC OFF') can't be followed by Basic statements

What I mean by that is that this kind of thing won't have the desired


If you need a multi-statement line with an OS call somewhere other
than the end, you could use OSCLI instead, e.g.:


- Integer variables

(Integer variables are mentioned only implicitly and fleetingly in the
manual (blink and you'll miss it), and don't seem to be mentioned at
all in "NC100 Magic".)

Use a `%' suffix on a variable name and the variable referred to is a
32-bit signed integer (variables are floating-point by default). These
are considerably faster than the default FP variables and take up
slightly less memory. (But that extra `%' on every reference means
that, in practice, using integer variables takes *more* memory, not
less.) Note that `FOO%' and `FOO' are different variables.

- `&'

You can prefix a number with `&' to indicate that the number is in
hex. For example, `A=&2A' is the same as `A=42'.

You can print in hex with, say, `PRINT ~A'. This is mentioned in the
NC100 manual, but this is a good place to put a reminder. :-) One
related point which *isn't* mentioned there is that you get a string
with a hex representation in with something like `A$=STR$~A'. Note the
syntax; `STR$(~A)' doesn't work.

- How to do `peek' and `poke'

This is only hinted at in the manual, so here's some examples showing
the various ways you can get directly at memory:

First, the various `poke' operations:

?&4000=42   put the byte 42 at 4000h.
!&4000=A%   write A% (a 32-bit integer) at 4000h
$&4000="FOO"      write "FOO" followed by a CR (0Dh) at 4000h

Now the `peek's:

A%=?&4000   assign to A% the value of the byte at 4000h
A%=!&4000   A% = the 32-bit integer at 4000h
A$=$&4000   A$ = the string at 4000h (must end with a CR (0Dh))

As you might imagine, you can use any expression (as long as it's the
right type; normally numeric, but string on the relevant side of the
`$' ops) with these operators, and the result of the `peek' ops could
be e.g. printed rather than put in a variable, etc.

The `!' ops read/write little-endian (LSB first) signed 32-bit

- @% (or "How to change the numeric print format" :-))

(Firstly I should say that if all you want to do is get it printing
numbers more like other Basics do, you should prefix any number to
print with a semicolon, even if it isn't after another PRINT item. For
example, `PRINT ;42' prints simply `42', with no leading spaces. What
`@%' does is more like what PRINT USING allows you to do in most other

@% is a variable which controls how numbers are printed. It is
easiest to think of it in hex, as then it breaks down like this:


...where X is the format used, Y is the number of decimal places to
print, and Z is the width of the field it is printed into. X=0 is the
default format (standard form or conventional representation depending
on the size of the number); X=1 uses standard form all the time; X=2
uses conventional representation all the time. The default setting of
@% is 0090Ah.

For those of you familiar with C's printf(), setting @% makes any
subsequent PRINT of a number into something like what these printf
calls would do (if Y and Z were written in decimal):

      for X=0, printf("%Z.YG",number);
      for X=1, printf("%Z.YE",number);
      for X=2, printf("%Z.Yf",number);

(There are some minor differences, but that gives you the basic idea.)

- DIM without brackets (e.g. DIM FOO 42)

You can reserve an area of memory by using `DIM var size' (note the
lack of brackets) to reserve size+1 (yes, size+1) bytes of memory.
`var' is then set to the start address of this area.

If size is -1, no memory is reserved, and `var' is set to the address
of the last byte of memory used by the variables area (or possibly the
first byte not used by it - it's not entirely clear which).

- Finally, one feature criminally ignored in the manual...

******* The built-in Z80 assembler (and how CALL and USR work)

(Both the NC100 manual and "NC100 Magic" carefully avoid discussing
this area. Bloody wimps. ;-) The Electron manual is far more helpful,
and most of what it says applies to the NC's BBC Basic too.)

The assembler works by you using `[' to switch into assembler mode,
then using fairly conventional assembly syntax, and using `]' to
re-enter normal Basic mode. The assembly is put at P% (which is just a
normal Basic variable, which the assembler modifies as it goes); the
default value of P% is zero, so it's VITAL that you assign it a value
before using the assembler.

The assembler is a one-pass assembler, but due to the interesting way
it works it can be made to work like a normal two-pass assembler with
deft use of the pseudo-op "OPT" and a FOR loop. Before we come to how
that works, here's a description of the options which can be set with
OPT, which is usually used at the start of the assembly (just after
`[' in fact):

OPT 0 No errors, no listing.
OPT 1 No errors, listing given.
OPT 2 Errors, no listing.
OPT 3 Errors, listing given.

(The default is OPT 3. Unlike the BBC and Electron, the NC doesn't
allow e.g. "OPT3" - it demands a space after "OPT".)

(There are also OPT 4 to OPT 7, which are more complicated and are
covered later.)

Back to how to do two-pass assembly then. The idea is to run through
once with OPT 0, then again with OPT 3 (or OPT 2 if you don't want a

Here's a simple example of how to do this:

 10 Q%=&4000
 20 FOR I=0 TO 3 STEP 3
 30 P%=Q%
 40 [OPT I
 50 \ This is a comment
 70 RET          \ Return to Basic
 80 :
100 \ Not a terribly useful routine;
110 \ it does, however, prove it's making two passes.
120 RET
130 ]
140 NEXT

(Notice how you can insert comments, and the somewhat unusual format
of labels.)

Running this gives the following output:

4000              OPT I
4000              \ This is a comment
4000 CD 04 40     CALL ROUTINE
4003 C9           RET          \ Return to Basic
4004              .ROUTINE
4004              \ Not a terribly useful routine;
4004              \ it does, however, prove it's making two passes.
4004 C9           RET

And to run the (rather useless :-)) program which has been assembled,
call it with `CALL &4000' (`CALL 16384' would work just as well, of
course). Or, you could use something like `A%=USR(&4000)'. This
returns a value; more on that in a moment.

That's the essential basics of how to use the assembler and call your
own m/c routines. You could probably get by if you just knew that
much. But there's a bit more to it than that:

- Since labels are just variables, there's no warning if you define
one twice, so be careful!

- There's a gotcha relating to the `\' comments - a colon ends the
current statement, so you have to be careful not to use colons in any

- You can use all the usual registers in your code - there's no need
to save any.

- Basic variables (well, numeric ones, at least) can be used as
constants in your assembly.

- You can reserve an area of memory in which to assemble (which is
usually more sensible then just assembling to a specific address) by
using something like `DIM Q% 500' (note the lack of brackets) to
reserve 501 [sic] bytes. This was covered in more detail earlier on.

- Labels are, in fact, just ordinary Basic variables which contain the
relevant address. (They're floating-point though, rather than being
integers as you might expect.)

- You can put multiple instructions on a single line in the same way
you can in Basic - so things like "PUSH AF:CALL THINGY:POP AF" are

- The Electron manual describes equivalents of most assemblers'
defb/defw/etc. called EQUB, EQUW, EQUD, and EQUS. (Respectively, these
let you insert a byte, a word (16 bits), a `double-word' (32 bits),
and a string into your routine.) However, these seem to be absent on
the NC's BBC Basic. :-(

- When running under ZCN, you can call 0105h to call ZCN's BDOS, and
you can call 0110h to call a routine at IX with the screen paged in at
F000h. (Ordinarily, the BBC Basic ROM is paged in at C000h-FFFFh
during a CALL or USR, and the screen is not directly accessible.)

- You can assemble code at O% as if it were being assembled at P% (a
bit like using `phase' on some assemblers) by using `OPT 4' and `OPT
7' (normally by either using `[OPT I+4' at the start of the loop or
changing the loop itself to `FOR I=4 TO 7 STEP 3'). (OPTs 5&6 also
work, being like 1&2 respectively.) Be sure to set O% to the physical
address, and P% to the (for want of a better term) logical address -
and don't forget that O% needs to be set *for each pass* just like P%

- There are better (if more complicated) ways of getting numbers etc.
in and out of your routine than using the peek/poke commands. These
are described below.

(This is one fair old chunk of text coming up, so I hope you're
sitting comfortably... :-))

The easiest way to get numbers *in* is to use the variables which
preset the registers. A%, F%, B%, C%, D%, E%, H%, L% all exist and set
the value of the corresponding register when a CALL or USR is done.
(I'm afraid there's no BC%, DE% etc. - you have to set all the
registers one by one. Also, there's no IX% or IY%, nor any way to set
the alternate register set.) Unfortunately, they *aren't* set to the
values of the registers when your routine returns. You need a
different way to get numbers out...

The easiest way to get numbers out is to use the return value of USR.
When your routine exits, the return value of USR is HL*65536+HL'. This
is a little awkward, as HL is clearly the most convenient register
pair to use to return a value, but that then makes the value more
awkward to get at from Basic. There are two main ways of dealing with

- use HL' instead. Once you've got the value into HL, use something
like `PUSH HL:EXX:POP HL:EXX:LD HL,0' to put it in HL'. (The final `LD
HL,0' makes sure the number is easy to deal with from Basic.)

- use HL, and sort out the number in Basic, with something like:

      HL%=((A% AND &FFFF0000) DIV &10000) AND &FFFF

(The `AND &FFFF' looks unnecessary, but isn't.)

If you want to get at HL' too, add this:


So I've talked about these "easiest" ways to get numbers in and out,
which implies there's a harder way, right? Exactly. But while it's
undeniably harder to deal with, it's a lot more flexible, not least
because you can use it for both input and output, *and* you can even
deal with strings and (for grade A mad scientists only :-))
floating-point numbers with it.

The way it works is that you add extra arguments after the CALL. A
simple example is `CALL &4000,NUM%'. You can have "any number of
parameters" (according to the Electron manual - however, there's a
practical limit of around 80), and you access them from your m/c via
the `parameter block'. On the NC100 this is located at A100h, and is
in the following format:

address           description

A100h       number of args
A101h       1st arg's type          (if there's one or more args)
A102h       1st arg's address (if there's one or more args)
A104h       1st arg's type          (if there's two or more args)
A105h       1st arg's address (if there's two or more args)
...and so on.

(Anyone used to the way this works on the 6502 should note that this
format is *not* the same as that one. Here, the type comes *before*
the address, not after. Yes, really. No idea why.)

IX is set to A100h when your m/c is called, so it's probably easiest
to use that to get at the parameter block.

The following types are supported:

type number description

  0         a byte (as accessed with `?', e.g. `CALL &4000,?42')
  4         an integer variable (32-bit) (e.g. `A%', `!42')
  5         a floating-point variable (5 bytes) (e.g. `A')
129         a string variable (terminated by a CR) (e.g. `A$')

(Again, 6502 types :-) will notice a difference - literal strings are
not supported.)

For integer and floating-point variables, the address is simply the
address of the number itself. (Floating-point variables seem to be
stored as a four-byte mantissa, then a one-byte signed exponent -
that's about as much as I could figure out from a quick
investigation.) For strings, it seems to return the address of a
structure where the first two bytes are *both* the length of the
string (!?), and the second two bytes are the address of the string

***** BBCMIN [-H] [filename]

A cut-down version of `bbcbas', which has a much smaller executable
yet has similar functionality. However, it's much less usable for
program development. Basically (no pun intended) it's good for when
you just want to run existing Basic programs, rather than writing new
ones. The intention is for a kind of `runtime' version of bbcbas, if
that makes sense.

One other advantage is that it provides 39k for Basic, about 3k more
than bbcbas manages, and within 1k of the absolute maximum you could
possibly get the ROM BBC Basic to allow.

Here's a breakdown of what it lacks relative to bbcbas:

- There's no copy cursor.

- The help pages (those obtained with *KEY) are absent.

- *CAT does nothing.

- There's no serial/parallel support. (You can still use it with the
  serial/parallel port with console redirection, but that's all.)

- There are no bitmaps for chars in the 128-255 range; outputting such
  chars doesn't print any useful symbols. For this reason, the pound
  sign cannot be entered when typing a program line.

- There is no customisable LISTO setting. On startup it defaults to
  LISTO format 7, just like Basic does under the ROM software.

***** BIGRUN [d:] command [args]

Run a command in a 62k TPA, using 32k of disk space as extra memory to
achieve this. This may be useful for very memory-hungry programs like
Hitech C. The drive, if specified, says which drive to allocate the
extra memory on (the default drive is the current one).


Don't run ZCN-specific programs under bigrun - they won't work. In
particular, programs which draw graphics or otherwise modify the
screen directly will almost certainly *crash* if run with bigrun.

Don't try to turn the machine off when running a program under bigrun;
if you do, it may crash. Also, you mustn't remove the memory card
while it is running. Remember the "my mind is going" scene in 2001?
That's what you'll be doing to the NC100 if you remove the memory card
when bigrun is running. :-)

I recommend that you only run a program under bigrun if you absolutely
have to in order for the program to run.

Bigrun uses the last 32k on a drive as extra memory (it temporarily
creates a file `$$bigrun' in user 15 containing the relevant area of
the drive in order to reserve it) so that it can keep ZCN paged out
most of the time. This is pretty complicated, so there are some
problems with it. There are only two problems which have yet to be
mentioned. Firstly, programs run significantly slower under bigrun,
largely because of the overhead involved in paging ZCN back in (which
involves more work than you might think) for various OS calls. And
secondly, since interrupts are effectively disabled when ZCN is paged
out, serial input will be ignored.

While bigrun should run most generic CP/M programs, it was
specifically written so that the Hitech C compiler would work on ZCN.
(See the `Hitech C' section under `Tips on using certain programs with
ZCN' for details of how to use bigrun to do that.)

***** BMP bitmap_spec

Draw one or more character bitmaps. This is primarily useful for
drawing graphics in SUB files.

`bitmap_spec' defines the bitmaps like so:

- Any group of six consecutive hex `digits' (0..9, A..F) defines a
character bitmap line-by-line, which is printed as a char at the
current cursor position (for example, "F9999F" would print a
rectangle). If there are fewer than six in a row, the character is
printed with the remaining lines set to zero.

- `_' prints a space.

- `.' causes a line-break (CR/LF).

- `=' prints the most recently defined character again.

Any other characters are ignored. So, for example, you can use spaces
to separate consecutive char bitmaps, to make things a bit easier to

While there is a limit to how many bitmaps you can print with `bmp'
from a single command-line, `bmp' is re-entrant, so you can use `!!'
for consecutive runs. If you do `crlf 0' beforehand, you can build up
even quite a large graphic using multiple runs.

Indeed, ZCN comes with a utility to convert PBMs to equivalent
`bmp'-using SUB files (this is likely to only be useful to Unix users,
though - it's not much use without netpbm). The C source is in

***** CAL [-H] [-O output_file] [month] [year]

Cal outputs a calendar. If no month/year is specified, then the
current month (and a month either side) are shown. (This requires the
time/date to be set - see `TIMESET' below.) If only a month is
specified (e.g. `cal 10' for October), that month of the current year
is shown (again, with a month either side). This also requires the
time/date to have been set.

If either of the above options were used and the time/date wasn't set,
cal gives usage help. There two other ways of running cal, which don't
require the time/date to be set:

- specify (only) a year (e.g. `cal 1998'). This gives a full calendar
for that year. (You must specify the year in full - `cal 98' gives a
calendar for the year 98. :-))

- specify both the month and year. This gives a calendar for that
month and a month either side.

***** CALC

Runs the NC100's ROM calculator as if it were a ZCN program. None of
the weirdness needed for `runrom' etc. is needed for this - just type
`calc' and you're away.

There are five differences between the calculator as used from the ROM
itself, and `calc':

- There's no border around the edge of the screen.

- There's no "use the green keys" text when you start it up.

- The memory and the number onscreen when you exit can be saved to a

- By default, `calc' uses the REAL keys (0-9, +, -, *, /, etc.) rather
than the `green keys'. However, for those of you who prefer using a
keypad, pressing Tab toggles between keypad mode and the default
non-keypad mode. If keypad mode is on, this is indicated at the
bottom-left of the screen.

- The normal text used (for the "M", the "K", and the "E" error box
when you try to divide by zero etc.), which is 6x8 when running from
the ROM, is ZCN's usual 4x6 when running `calc'.

Here's a list of how the keys used in the non-keypad mode compare with
the keypad ones:

Non-keypad              Keypad

0 to 9, ., =, del, enter, Stop      same as in keypad mode
+, -, *, /, %                 "+", "-", "x", "[divide-sign]", "%"
_ (underscore)                "+/-"
c                       "CE/C"
r                       "MRC"
p                       "M+"
s                       "M-"
x                       clear memory (no keypad equivalent)
q                       "[square-root-sign]"

By the way, the keys on the left aren't just keys I've made up - these
are the keys the ROM calculator *actually uses*. The keypad just maps
other keys to these, to the extent that I had to write my own support
for it! :-/

As for saving the numbers to a file, there are two different ways to
do this. Immediately after exiting `calc', you should do one of these:

- `save 1 foo'. This saves the numbers to a file called `foo'. They'll
be prefixed by the characters "0~|8" - unfortunate but necessary.

- `!!'. This saves the numbers to `calcnums.txt'. There's no junk
characters prefixing the numbers if you save them like this.

The latter is probably preferable, but the former allows you to
specify the filename, which may be useful if you have an existing
`calcnums.txt' you don't want to lose.

Note that if you use `!!' it *MUST* be the very next command after
exiting `calc' or you may risk a crash!

If you simply forgot the number you calculated and want to see it
again, but don't particularly need to save it to a file (or don't have
enough disk space to do so), `memdump 100' might be worth a try

The numbers are stored as plain ASCII text. The first line contains
the number in the memory, or zero if there wasn't one - the second
contains the number that was displayed onscreen when you exited

Finally, I should point out that there are two problems with `calc':

- There's no way of reloading previously-saved numbers into `calc'.
(This is definitely possible, but would be pretty complicated.)

- `calc' will only run correctly if the console is not redirected to
the serial or parallel ports. This isn't terribly surprising :-), but
since `calc' doesn't actually check for console redirection (I removed
this to keep it under 1k), it's worth mentioning. (If you run it when
running via serial by accident, you can still press Esc to quit.)
When running via serial, using `bbcbas' (or perhaps `expr') is a
reasonable substitute.

***** CODES

Show a table of ZCN terminal driver control codes.

***** CPMTRIS [termtype [mhz10]]

A tetris clone for CP/M machines. This should work on any Z80-based
CP/M, but has special support for ZCN. The way it works means that it
should run on ZCN, PCWs, and +3 CP/M as-is; for other systems, a bit
of patching may be required.

You can run it on a VT100 serial console with `cpmtris 1'.

See the README in the `cpmtris' dir for more details.

***** DCLOCK

A simple clock program, a cut-down version of zcnclock. (It's 1k
instead of 5k.) Press Esc to exit.

Note that, as with zcnclock, the auto-poweroff timeout is effectively
disabled by the constant updating. (Despite appearances, even the date
is updated every second.) This is probably a good thing if your
machine is running off the mains adaptor, but watch out if you're
running off batteries.

***** DEFRAG [-Q] d:

Defragment free space on the specified drive (without the running
commentary if you use `-q'). MS-DOS/Windoze users who haven't thought
too hard about how a memory card works should note that THIS DOES NOT
SPEED THE DRIVE UP. :-) (Hint: there's no seek time on a memory card.
Or rather, the `seek time' that exists (the access time) is very
small, and constant.) This is why it doesn't defragment files
themselves, only the free space not used by files, you see. Use
`optdir' if you want to speed a drive up in roughly the same kind of
way as `defrag' does on a DOS or Windoze box.

The only reason you would want to use `defrag' is if `sys' or `bigrun'
fail when you have enough free disk space for them to work, but not
enough of it is at the end of the drive. `defrag' puts all the free
space in one big uninterrupted lump at the end of the drive, making
sure that `sys'/`bigrun' *will* work if you have enough disk space.

***** DIAL phone_number

A DTMF tone-dialler. It uses the sound chip to generate the
appropriate tones. I haven't had any luck with this - I expect the
sound is too distorted. Amstrad seem to have a talent for making
machines with distorted sound; ask any Spectrum +3 owner... :-)

For what it's worth, `dial' supports all `digits', including `*' and
`#' as well as the rather obscure `A', `B', `C' and `D'.

***** DMP2TXT input.dmp output.txt

This converts a screen dump file created by ZCN (usually screen.dmp
unless it's been renamed) to a text file. The text file is simple,
plain ASCII - no attempt is made to represent attributes.

It uses a real brute-force comparison approach, and so can be
relatively slow - around five seconds for an average screen.

Dmp2txt does pretty well at interpreting the screen dump in most
cases. However, it's usually fooled by text displayed when two (or
more) attributes were on at once (e.g. inverse bold) since - after
checking against the normal characters - it (only) checks for each
attribute individually.

***** DU [filespec]

Shows how much disk space is used in total by the files matching the
specified wildcard (or `*.*', all files in the current user area, if
you don't specify one).

***** EXPR expression

`expr' is an expression evaluator, a sort-of-clone of the Unix command
of the same name. It only does integer arithmetic, but does at least
use 32-bit integers to do the maths (giving a range of -2147483648 to
2147483647). All tokens (numbers, operators, brackets) must be
separated by spaces, e.g. `expr 1 + 2 * 3'. Precedence is of the usual
type, so the previous expression evaluates to 7.

***** HEAD filename

Display the first 8 lines of a (text) file.

***** HELP [command] (removed in ZCN 1.2)

The old external `help' command used to give very terse (one-line)
usage help for commands. It was dropped as `man' is vastly better, and
I didn't like the idea of maintaining a separate, inferior help


`Invaders' is an unfinished game. It's reasonably playable as is
though - Z moves left, X moves right, Space fires, and Q quits. The
invaders gradually grow invisible because it starts updating faster
than the NC100's LCD screen can handle. That's the main reason why I
haven't bothered finishing it. :-/ You should be able to get by if you
crank up the intensity control.

***** LS [-L] [filespec]

Like `dir' but displays the file list sorted vertically by filename,
with .com and .sub files in italics, and if the `-l' option is given,
with file sizes (in K). It also uses an 80-column-friendly layout (and
no italics) if the console output is going to the serial port or
printer, unlike `dir'.

ZCN's `get file size' function is fairly slow, so this command isn't
very quick if you give the `-l' option. Try it and you'll see what I

***** OPTDIR [-Q] d:

The management summary on this one is `makes drives quicker'. :-)

Optdir optimises the directory blocks on a drive by putting the
entries matching the larger 16k chunks (extents) of files nearest the
beginning. Pretty confusing stuff, but it makes large files much
faster to read, at least three times faster in some cases, mostly due
to the stateless, unbuffered way ZCN works with files. You might like
to think of it as the performance-increasing equivalent of a
defragmentation tool for MS-DOS, only more so. Believe me, you really
want this program.

I run it from my `autoexec.sub', but you can obviously also run it by
hand, perhaps after copying some large files. You should run it as
(for example) `optdir a:' to optimise the A: drive. It'll list the new
order of extents, which probably won't mean that much to you. It means
precious little to me, anyway. :-) It only does it so you know it's
done something, as much as anything else. You can run it with
something like `optdir -q a:' to stop it printing out all that junk.

***** PLAY1B/PLAY2B/PLAY4B filename

These play (respectively) 1, 2 and 4-bit sample files at 8kHz. You can
generate these samples from an raw 8-bit unsigned source on a Unix box
with the mk[124]bit filters (C source in the `utils' directory). I
would have liked to include a few example sample files, but it's
almost impossible to find any non-copyright material which would sound
reasonable. (Classical music tends to distort easily with low
bit-depth samples, and almost all recordings are copyrighted anyway.)

Note that 1-bit samples sound terrible, 2-bit ones sound only a bit
better, and although 4-bit samples can sound quite good, you can only
play up to 11 seconds worth of 4-bit sample.

Keyboard input is ignored while the programs are running. However, you
can use the power on/off button to abort playback.

BEWARE! The programs don't (yet) stop loading the sample if it gets
larger than available memory, so don't try to run it on a file any
bigger than 43k!

Bugs: `play4b', at least, plays samples back slightly too slowly, not
quite managing the full 8kHz.


Make a0:zapdesc.bin (required by zap) from all .zap files in the
current drive/user, overwriting any existing a0:zapdesc.bin. It shows
a dot for each .zap file processed.

****** About zap files

Zap files are text files containing a program description - the
program's name, the COM filename, and so on. It's fairly
straightforward to create your own zap files, a description of the
format follows...

Blank lines and lines starting with `#' (comment lines) are ignored.
Other lines should be one of the following:

- "progname name", where `name' is the name which zap will display
  above the program's icon. A maximum of 15 chars is allowed. No
  spaces are permitted - to have zap print a space in the name, use an
  underscore (`_') instead.

- "progfile program.com", where `program.com' is the program to run.
  It MUST be a COM file (or the NC100 will most likely crash when zap
  attempts to run it!).

`progname' and `progfile' are required. The rest are optional:

- "filetype ext", where `ext' is an extension to associate with the
  program (so that files matching `*.ext' would be listed in its file
  list). You can specify up to 32 extensions using multiple `filetype'
  lines. To match all files, use `filetype *'.

- "filetype ?" tells zap to give a list of possible drives to start
  the program on, rather than a list of files. (After the drive is
  chosen, you'll then choose a user number to use.)

- "filetype ?d" is much the same, but you only pick the drive. Only in
  rare cases is this likely to be useful (e.g. for zdbe).

- "opt option", where `option' is one of the following options:

  - "noret" stops zap restarting after the program has finished.
    Useful for programs which exit by rebooting, such as runrom.

  - "keywait" makes zap wait for a key after the program has run.
    Mainly useful for non-interactive programs.

  - "needfile" tells zap that the program *must* be run on a file.
    This means that zap doesn't a "<new>" entry in the file list, and
    if there are no matching files, the program isn't shown.

The other possible lines define a 32x24 icon bitmap to be used. This
is optional, but the listing will look a bit odd if you don't supply
an icon. The icon starts off blank, and the first `bmphex' or `bmpbin'
line defines the first row of pixels, the second defines the second,
and so on. You don't have to specify all 24 lines - any remainder is
left blank. Here's how `bmphex' and `bmpbin' work:

- "bmpbin binary_data", where `binary_data' is exactly 32 bits (0s and
  1s) specifying a line of pixels in left-to-right order. A zero
  represents white, a one represents black.

- "bmphex hex_data", where `hex_data' is exactly eight hex `digits'
  specifying a line of pixels in left-to-right (big-endian) order.
  This is intended for use by programs which generate zap files (more
  on this in the next section); when writing a zap entirely by hand,
  you would normally use `bmpbin'. `bmphex' lines take up a lot less
  space, however, so any Real Programmers out there are bound to use
  them anyway. ;-)

****** Example zap file

The above probably makes zap files sound rather confusing. But they're
pretty simple really. Here's an example, the zap file for `bbcbas':

progname BBC_Basic
progfile bbcbas.com
filetype bas
bmphex 07ffffc0
bmphex 06aaaae0
bmphex 077d7dc0
bmphex 06eeeee0
      [...many `bmphex' lines deleted...]
bmphex 07ffffc0
bmphex 02aaaaa0

Some of the `bmphex' lines have been cut, but other than that this is
the complete `bbcbas.zap'.

****** Designing zap file icons

The simplest way to design the zap file's icon is to use a text editor
and `bmpbin' lines. This is a bit awkward, but works well enough. (I
hope to write an icon editor for ZCN in future, though.)

For ambitious types with Unix boxes, however, you could use a paint
program (I'd recommend X's `bitmap' program, which is a bit `clunky'
but is good for designing B&W icons) to create the 32x24 bitmap,
convert that to a PBM using netpbm (you'd want to run it through
xbmtopbm if using `bitmap', for example), then convert the PBM to a
skeletal zap file using zap/pbmtozap.c. You then need to edit that to
make the finished zap file. So you see what I mean about using a text
editor being the simplest way? :-)

***** MAN [page]

ZCN's online help system. `man' is modelled (very) loosely on Unix's
`man' program. You do `man foo' to get help on a command (or topic)
`foo' - for example, `man man' gives help on man itself, and is a good
place to start.

Note that for man to work, you MUST have the `manpages.pma' file from
the `bin' directory on your A: drive in user area 0. This archive
contains all the help files (or as they're more usually known, man

***** RRXFER

Transfer files to/from a `runrom.ram' snapshot file created by
`runrom'. See the section `Running the ROM software from ZCN' above
for details.

***** RULER

Display a ruler (labelled in cm) at the top of the screen. (It's
accurate to within 1mm, but is only labelled every 5mm.)

One notable thing about the ruler is that the top two pixel lines stay
onscreen until you do `cls', so you could (for example) do `ruler',
then run a text editor to note down some measurements. (As long as
you're prepared to count the lines/dots, that is. :-) And it doesn't
work with ZDE, as that clears the screen on startup - `note' would do
the job though.)

If you'd like to be able to modify the ruler (perhaps to display
inches, or mm), a better approach might be to write your own custom
BBC Basic program. Here's one which gives similar output to `ruler'
which you could use as a starting point, much as I did for `ruler'

   10 DEF FNmm(X)=X*480/211
   20 CLS
   30 FOR F=0 TO 21
   40   X=INT(FNmm(F*10)+0.5):MOVE X,63:DRAW X,58
   50   X=INT(FNmm(F*10+5)+0.5):MOVE X,63:DRAW X,62
   60   PRINT TAB(INT(FNmm(F*10)/4+(F>9)+0.5),1);F 
   70 NEXT
   80 PRINT TAB(0,3);

***** RUNROM

Run the ROM software. See the section `Running the ROM software from
ZCN' above for details.

***** SEMI command1 [args][; command2 [args][; command3 [args] ;...]]

This command lets you run multiple commands one after another. It
simply writes a $$$.sub (like `submit') which contains each of the
semicolon-separated commands you gave on the command-line, on a
separate line. Due to the way it works, it's not a good idea to call
this from a SUB file as-is - you should instead prefix it with
`quitsub'. (This will also abort the SUB file, I'm afraid.)

On my machine, I have this renamed to `;.com' to make it easier to
run/type. This should explain why it's called `semi'. :-)

***** SLIDE

A slide-rule emulator. The upper and lower parts of the rule remain
static, but the middle part can be moved with `,' and `.' (use shift
to move more slowly), or cursor left/right. The cursor, a line which
helps you read the rule more accurately, can be moved with `z' and `x'
(again, use shift to move slowly). Esc exits.

Since nobody uses slide-rules any more, here's a very simple
explanation of what they are, and how to use one for simple

The basic idea is that a slide rule has various logarithmic scales on
it. In the same way as you can add two numbers by moving two (linear)
number lines relative to each other, you can multiply two numbers by
similarly moving two logarithmic `number lines'.

So to do 2x3, you'd move the 1 on the `C' scale next to the 2 on the
`D' scale, then look up where the 3 on the C scale is on the D scale,
and that's your answer. (This isn't entirely accurate in `slide' due
to the NC's low resolution, but that's just a necessary problem with
`slide' I'm afraid.)

This approach works until you get an answer greater than 10. For such
cases you can either take the easy way out and use the x^2 scales (A
and B), or use the C and D scales the other way. For example, 9x8
would involve moving the C scale's 10 to the D scale's 9, then looking
up the D scale at the C scale's 8. This gives 7.2, which you multiply
by 10 to get the true result.

To do division, you need to use the C| and D scales. (Since these
scales aren't next to each other, this is the main case where you'll
find the cursor useful.) To divide 9 by 8, move the C| scale's 1
(or effectively the C scale's 10) to the D scale's 9, then look up the
C| scale at the D scale's 8. This gives around 1.123, quite close to
the correct answer (1.125).

You can multiply/divide arbitrary numbers by doing the mantissa
multiplication on the rule, and dealing with the exponents manually.
This isn't really practical with `slide' due to the low accuracy,

All in all, it's fair to say that most people would prefer to use
`calc'. :-)

***** SPELL filename

Interactively spellcheck a (text) file (uses the ROM spellchecker).

After invoking spell, the file specified is renamed to have a `.bak'
extension (with any existing `.bak' file deleted first). This file is
then read from, with spellchecked output going to `filename'. This new
file will be on the same drive as the `.bak' file, even if it's not
the current drive.

If spell thinks there won't be enough disk space to write the new
file, it tells you before it starts, giving you the option to abort
the spellcheck or carry on anyway. The space that'll be needed can't
be determined for *certain* though, since replacing short words with
longer ones could make the file bigger, so it may be best to check for
yourself before running spell to make sure you have a reasonable
amount of disk space.

Once spell is up and running, it shows you how far it's got with a
display of the form `XX/YY'. XX is where it's got to in the file (in
128-byte records), YY is how big the file is.

If it finds a word it doesn't recognise, it removes this display and
shows the word (highlighted), along with the previous and current
lines. You're then given a menu like this:

[L]ookup, [A]uto-lookup (toggle), [R]eplace (edit), SPC - ignore

`L' looks up alternatives which might be the word you meant. If none
were found, it says so; otherwise, it lists them like so (this example
shows the result of looking up `addr'):

0) add  1) adder  2) adds

You can press 0 (zero) to replace the word with (in this case) `add',
1 (one) for `adder', etc. (If more than 10 possible choices are given,
they use A, B, C and so on - be sure to use an UPPERCASE letter if you
want to choose any of those.)

`A' enables looking up of alternatives automatically, so you don't
have to press `L' every time. This can slow things down though, as
looking up words takes a little while. Pressing `A' again disables

`R' lets you type in a replacement for the highlighted word. After
pressing `R', type the text and press enter (or press Esc to abort and
return to the menu).

Pressing space ignores the highlighted word, leaving it unmodified.

Finally, though it's not listed on the menu, you can press ^C to
effectively end the run early, by writing the rest of the file
unmodified. You're prompted to check if you really want to do this or

***** SPELLWD word

Spellwd is a simple interface to the ROM spellchecker. You use it like
`spellwd word' and it tells you whether it found `word' in its
dictionary, i.e. whether it's spelt correctly or not. If it didn't
find the word in the dictionary, it lists alternatives which might be
the word you meant.

***** STAT

This emulates almost exactly the behaviour of the old internal `stat'
command. The only problem is it uses a $$$.SUB file to run df etc., so
for now at least it gives a slightly incorrect result for free space
on the current drive. :-} See `STAT (removed in ZCN v1.1)' in the
`Internal Commands' section above for details.

***** SUBMIT filename [* | [arg1 [arg2 ... ]]]

See the section `SUB files with parameters' above for details of this

***** TIME

Display the time as reported by the NC100's real-time clock. You
should previously have set it with `timeset' (see below). If the time
is not set, `time' says so; otherwise it displays the time in the
format YYYY-MM-DD HH:MM:SS, e.g. `1995-06-17 20:58:55'.


Set the time (and optionally the date) of the NC100's real-time clock.
ZCN only currently uses the time/date for `cal' (where having it set
is optional), `time', `rrxfer' (optional), and `dclock' and `zcnclock'
(which are essentially just prettier versions of `time'). No file
date/time stamps exist in ZCN - this is the same as CP/M 2.2. (CP/M 3
does have them, but they eat a quarter of your directory entries!)

You can specify either the time (in 24-hr format padded with zeroes if
need be), the time with seconds, the date and time, or the date and
time with seconds. To give a few examples:

  timeset         (give usage help)
  timeset 0730          (set time to 7:30 a.m.)
  timeset 950528 090125 (set date to 28th May 1995, time to 9:01:25 a.m.)
  timeset 010114 2112   (set date to 14th Jan 2001, time to 9:12 p.m.)

The NC100's real-time clock doesn't support dates before 1st Jan 1990,
nor does it support dates after 31st Dec 2099. If you're using ZCN in
the 22nd century, apologies for the inconvenience. :-)

Since ZCN has only existed since 1994, ZCN treats all dates in 1990 as
`clock not set'. (The reason being that if the clock isn't set, the
clock only runs when the machine is turned on, and it always starts at
zero, i.e. 1st Jan 1990.)

***** ZAP

A simple graphical front-end for ZCN. It essentially shows a list of
programs you can run (shown by icons with the program's name above),
and for each program, a list of files you can run it on.

****** Requirements

Before going on to describe how to use zap, there's one important
detail which I need to mention. Zap requires a file `zapdesc.bin'
(which must be on drive A: in user 0) in order to operate. You can use
`makezapd' to generate one of these from `*.zap' (there are many zap
files in the `zap/zapfiles' dir in the ZCN distribution), or (much
easier) just use the pre-generated `zapdesc.bin' included with ZCN (in
the `bin' directory). See the `MAKEZAPD' section above for more on zap

****** Using Zap

When zap starts up, it reads `zapdesc.bin', finds any programs
mentioned in there which exist anywhere on the card (any drive, any
user), and finds any files which have been associated with them (also
in any drive/user). It then displays a screen looking (very roughly!)
like this ASCII representation:

(Zap really shows six icons across, but I can only show four in the
mock-up here. If you have something which can view GIF files, look at
zap/zapscrn.gif for a genuine screenshot.)

-, ,- . .     ___________
/_ \_ |\|    [_BBC_Basic_]        Calc          Zcnclock           ZDE
                .------.        .------.        ,------.              _
  15:19         |^o^^o^|        |'====`|        | 1200 |         __--//
                |`\\\ ||        | oooo |        |______|        `.  |/`-.  -->
                |_,_/_\|        |_oooo_|         _====_           `._,-'
             _______________                                 _______________
  A: 10     |[_<new>_____]|#|                               |  <new>      |#|
  B: 37     |b0:try.bas   |#|                               |a0:bar.txt   |#|
  C:---     |             |#|                               |b2:foo.sub   | |
  D:---     |             |#|                               |a0:wibble.txt| |
            `-------------'-'                               `-------------'-'

Ignoring the `sidebar' at the left for the moment, you can see the
various program icons along with their names, and some have
accompanying lists of files below the icon. Each file list has a
scrollbar, showing which part of the file list is displayed, and how
much of the list it is. For Basic's one all files are displayed so
it's `full'; for ZDE's, we can see that we're at the top of the file
list, and that about half of the list is onscreen.

The arrow to the right shows that there are more icons off-screen;
moving the cursor (currently on "BBC Basic") right a few times would
make those visible.

Returning to the sidebar, it shows the time (or "--:--" if the time
isn't set), and how much disk space is free on each drive (or "---" if
the drive isn't present). Also, though it isn't shown here, zap shows
you warnings about any batteries which are low in the gap between the
time and disk-space displays.

So, enough of what zap *looks* like. How do you use it? The answer is
simple enough. You move the icon cursor (the one at the top) to the
program you want to run, then (if the program has one) move the file
cursor (the one in the file list) to the file you want to run it on.
In addition to normal files, there are some special `files' you can

- `<new>'. This runs the program without giving it any filename. It
lets you pick the drive and user to start the program in. It defaults
to any previously-selected drive/user, or if none have been selected
yet, the drive/user that were current when you ran zap.

- `a:', `b:', `c:', and `d:'. These do much the same, but after
selecting one of these (which specifies the drive to use) you then
only need pick the user to start the program in. This `d:'-style way
of working is used when the program is never run with a filename (or
more precisely, when the program has only the special filetype `?'
given in its zap file).

After the program you've run exits, you return to zap.

And there it is, that's pretty much all you need to know to use zap.
Well, if you're prepared to guess the keys, that is. :-) Just in case
you're not...

****** Keys

Some keys used in zap are pretty obvious (e.g. cursor left/right move
the (icon) cursor left/right), some are less obvious. Here's a list of
all of them.

(Note that `Sym' is short for the shift-like key `Symbol'.)

Key               Description

Esc               Exit zap

Enter             Run the currently-selected program on any
                    currently-selected file

Cursor left, or ^S      Move icon cursor left
Cursor right, or ^D     Move icon cursor right
Sym-Cursor left, or ^R  Move icon cursor left a `page'
Sym-Cursor right, or ^C Move icon cursor right a `page'
< or ,                  Move icon cursor to the start
> or .                  Move icon cursor to the end
<letter>          Move to program name starting with <letter>

Cursor up, or ^E  Move file-list cursor up
Cursor down, or ^X      Move file-list cursor down
Sym-Cursor up           Move file-list cursor up a `page'
Sym-Cursor down         Move file-list cursor down a `page'
Sym-< or Sym-,          Move icon cursor to the start
Sym-> or Sym-.          Move icon cursor to the end
Sym-<letter>            Move to file starting with <letter>

Sym-Esc                 Write full 64-line screen-dump to `screen.dmp'

(Admittedly the last one was mainly for my convenience when developing
zap :-), and may well disappear at some point.)

The idea behind the file-list movement keys being generally more
`difficult' than the icon cursor ones is that not all programs have
file lists.

****** Adding icons for other programs

To add another program to zap's list, you need to make a .zap file for
it, and use makezapd to make a new `zapdesc.bin'. See the `MAKEZAPD'
section above for details.

****** How zap works

Fair warning - this section is mainly intended for those of the geeky
persuasion. :-)

Zap works by making a $$$.SUB file which reads the program using
`get', uses `!! filename.ext' to run it with the file, then does
`quitsub zap -#...' to remove the $$$.SUB and re-run zap, with the
`...' specifying various things like the most-recently-chosen
drive/user, the position in the icon list, and whether the program
chosen had the `keywait' option set.

When zap is run again (by the SUB), it does the `keywait' if that was
asked for, and puts all the `-#' context back in place - and there you
are, back in zap.

****** Zap Limitations

"GUIs normally make it simple to accomplish simple actions and
impossible to accomplish complex actions."
      -- Doug Gwyn on comp.unix.wizards

Zap isn't really a GUI as such, but it's certainly prone to this
accusation. It's only a program launcher, after all; you'll have to
exit to the ZCN prompt to do some things, such as work on PMA files or
set the time.

(I did consider having some sort of `shelling out' option - but since
zap starts up quite quickly and can be exited instantly, I didn't
really see the point. Just treat Esc as a shell-out option and `zap'
as if it were `exit'. :-))

Also, at the moment you can only run external programs (COM files)
from zap. There is no way to run internal commands, which is a pain as
some of them can be quite useful (e.g. sertest), and you can't run SUB
files either.

Finally, the way `man.zap' describes man as being associated with
COM files is a kludge, since zap has no way of reading manpages.pma
(even if it did, it would be unacceptably slow).

****** Zap Bugs

Zap is quite a young program and has some known bugs. These should
hopefully be removed in the next ZCN release:

- zap tries to run any file mentioned as a `progfile' as a COM file.
  SUB files (and any other non-COM files for that matter) will almost
  certainly cause a crash, and internal commands will probably just
  result in an error from ZCN before returning to zap. (This bug is
  only an issue if you write your own zap files.)

- zap always tries to write its $$$.SUB to the current drive, and
  exits with an error message if it can't. (This is considered a bug
  as it should probably try other drives too (if others exist), and
  give some sort of error dialog if it still fails.)

- zap doesn't currently check for the memory card being removed, which
  is a bit crap.

- the "working..." display is a bit naff, and should be replaced with
  some sort of percent-complete-bar thing.

- the flashing underlines shown below battery-low warnings flash in a
  very strange way, due to interactions between two differently-timed
  loops. I consider this to be a bit of a feature though, because you
  probably want a "your batteries are dying" message to be as
  eye-catching as possible. :-)

****** YABA Department

Yes, zap is an acronym I'm afraid. FWIW, it stands for "ZCN
Associative Program-launcher", which is possibly the most contrived
acronym ever. :-)


A simple program to plot the Mandelbrot set, a famous fractal. It uses
fixed-point 32-bit integer maths and an estimation method similar to
the `tesseral' method in the excellent free PC program "fractint".

It only plots the complete set, and doesn't allow any zooming in. This
is the case as, while this program is quicker than any other 8-bit
fractal program I know of, it is very slow. It takes 12 minutes to
draw the full set at the 128x64 resolution it uses.

When it's finished, it waits for a keypress. Press ctrl-shift-s then
to dump the screen, if you want to do that.

Note there is no abort key. To quit before it finishes, do a cold
reboot by turning the machine off, then holding both shifts while
turning it on again.


A clock program which continuously updates both analogue and digital
time displays, as well as the current date, and supports displaying
the time in various cities around the world. Press ^S (or cursor left)
and ^D (or cursor right) to change city. Exit the program with Esc.

Be the envy of your friends! Run it and nail your NC100 to the wall as
a stylish clock. :-)

Note that the auto-poweroff timeout is effectively disabled by the
constant updating. (Despite appearances, even the date is updated
every second.) This is probably a good thing if your machine is
running off the mains adaptor, but watch out if you're running off

There's a known bug in zcnclock, which is that the `world time'
business is inflexible and horribly UK-centric. (The world time stuff
will currently be pretty useless to anyone outside the UK.) Oh, and of
course DST changes take place at differing times around the world, so
some world times will probably be wrong by an hour for short periods
even for UK-based users, but this is probably true of most such

The bitmaps used in zcnclock to display where each city is on the
planet were produced by xearth.

The font used for the large digits in zcnclock (and dclock) is from X;
specifically it's a conversion of the 100dpi helvR24.bdf font. It's
free but the terms of use require me to include the copyright in
supporting documentation, so here it is:

> Copyright 1984-1989, 1994 Adobe Systems Incorporated.
> Copyright 1988, 1994 Digital Equipment Corporation.
> Adobe is a trademark of Adobe Systems Incorporated which may be
> registered in certain jurisdictions.
> Permission to use these trademarks is hereby granted only in
> association with the images described in this file.
> Permission to use, copy, modify, distribute and sell this software
> and its documentation for any purpose and without fee is hereby
> granted, provided that the above copyright notices appear in all
> copies and that both those copyright notices and this permission
> notice appear in supporting documentation, and that the names of
> Adobe Systems and Digital Equipment Corporation not be used in
> advertising or publicity pertaining to distribution of the software
> without specific, written prior permission.  Adobe Systems and
> Digital Equipment Corporation make no representations about the
> suitability of this software for any purpose.  It is provided "as
> is" without express or implied warranty.


A mouse-based paint program. You need a microsoft-compatible serial
mouse to use it.

BEWARE! Zcnpaint is incomplete, and there are still bugs, though to
the best of my knowledge there are no unknown bugs. :-)

Known bugs include:

- Flood-fill always fills in black, whatever the currently selected
pattern is.

- If you press return at the save or load file prompt without typing
any name in, it'll save a file which has a filename consisting
entirely of spaces; you can spot this by there being a blank space in
the file listing given by `ls' or `dir'. You can't do much with this
file, but you *can* delete it - just type `era' (with no filename) at
the ZCN prompt.

Also, though it's not really a bug, the mouse pointer can be easy to
lose track of, so you may want to turn up the intensity to try and
avoid this problem. (This `disappearing pointer' is due to the
rather persistent LCD display, of course.)

With all that out of the way...

Zcnpaint works in a fairly similar fashion to most paint programs on
8-bit machines, except that the pointer is obviously controlled by the
mouse and not the keyboard. All the controls are on the "icon panel",
which you can drag to another position onscreen by click-and-dragging
the "title bar". The icons are rather small and nondescript, so here's
a guide to the icon panel:

       |     Z   C   N   P   A   I   N   T                   |
       |                                                     |
       | single |freehand| eraser |flood-  |start new file   |
       |  pixel |  line  |        |  fill  |(i.e. clear scrn)|
       | rubber |multi-  | undo   |hide    |load file        |
       |bandline|  line  |        |  panel |                 |
       |hollow  |filled  |window  |text    |save file        |
       |rectangl|rectangl|   (NYI)|   (NYI)|                 |
       |hollow  |filled  |choose  |brshsize|exit program     |
       |circle  |circle  |pattern |   (NYI)|(does NOT prompt)|

The icons marked "(NYI)" above do nothing, as the feature is not yet
implemented (and, to be honest, is unlikely to be).

Note also that exit program does *not* prompt you whether you want the
save the current file - if you haven't saved the picture and you exit,
you've lost it. Well, this isn't entirely true. The undo screen, which
will almost certainly have a recent copy of the picture, is at 7000h.
If you haven't run any program since, or at least not one which uses
the area 7000h-7fffh, you might still be able to get at it. One way to
do that, if you have 36k or more available on a disk, would go like

A>save 127 foo
A>wade foo
WADE 1.5 - Wagner 85-04-27  (TurboDos & CP/M 2 Version)
Low=0100   High=7FFF   Max=7FFF  Top=83FF

:f mypic
:w 7000 7fff

A>era foo

After that your picture would be saved as `mypic'.

There are only two keyboard shortcuts in zcnpaint at the moment. Esc,
which acts like `exit', and Menu, which toggles the icon panel on/off.

The way the tools work is that the icon most recently clicked on sets
the drawing mode. The default mode, active when you start zcnpaint, is
the `single pixel' mode.

Now, to cover each of the tools (drawing modes) in turn:

- Single pixel. This draws a pixel whenever the left button is pressed
or held down. You might think this would result in a line being drawn
when you hold down the button and move the mouse - it doesn't, since
the mouse can easily move large distances between samples. If you want
a continuous freehand line, use...

- Freehand line. This draws a continuous line when the left button is
pressed/held. Note that the line gets rather ragged when the mouse is
moved slowly, due to the way the tool is implemented. For these kind
of slow movements, `single pixel' mode may give better results.

- Rubber-band line. This lets you click-and-drag to draw a line.

- Multi-line. This lets you draw a long series of connected lines by
clicking the left button at each start/end point. To start a new
series of lines, select the multi-line icon again.

- Hollow/filled rectangle/circle. These work like rubber-band line by
dragging the shape out. With circles there is a certain maximum size

- Eraser. This works like `single pixel' but rubs out a 3x3 block
rather than drawing a 1x1 one.

- Undo. This undoes all operations performed since a tool was last
selected. (It does not undo undo!)

- Choose pattern. This lets you choose the pattern which all
operations (except the eraser and flood-fill) use to draw with. To
select a pattern, click on it. To avoid selecting any pattern, click
outside all the various pattern boxes that appear. Only a few patterns
are defined in zcnpaint itself; eventually there'll be a pattern
editor, but for now you're stuck with the five pre-defined ones.

- Flood-fill. This fills in the surrounding shape, which must have a
solid outline. Click somewhere inside the shape to fill it.

- New file clears the screen.

- Load file lets you load a previously-saved file. You can also load
screendumps produced by Ctrl-Shift-S, though since these are slightly
smaller than the full 64 lines normally loaded/saved by zcnpaint, you
should do `new' beforehand.

- Save file lets you save the current image. The file format used is a
simple binary dump of the screen - all 64 lines. You can load a saved
file direct from ZCN with `get f000 filename'.

- Exit exits the program.

If you'd like me to develop zcnpaint any further than it is now, you
should contact me (see near the end of the file for details). I'm
probably quite unlikely to do any more on it unless anyone else is
going to use it. (And even then I might need some convincing... :-))

***** ZDBE

A disk block editor. It allows you to view and navigate a drive, and
shows a map of the allocated blocks. If you use `M' to enable
read/write mode, you can also edit the data in hex/ascii.

Although `zdbe' uses the full 120-column screen, it detects when
you're running the console via the serial port and alters output to
work correctly on an 80x24 VT100 or compatible terminal.

The screen is split up into two panels. The left one (or top one if
running via serial) shows the hex/ascii dump of 128 bytes of the
current block. The right one (bottom one if via serial) shows a map of
the blocks on the drive, and the current drive, block number, and
offset of the cursor within the block. Only one of these two panels
can be used at a time - Tab selects which is active. The active one is
indicated by dashes surrounding the panel's title bar (at the top);
also, the cursor will be on the active panel somewhere. When you start
up zdbe, you're in the block-map panel.

The block-map panel lets you choose which block to display/edit. Boot
blocks are shown as `B', system blocks as `S', directory blocks as
`D', used data blocks as `#', and free data blocks as `.'. The
following keys can be used in this panel:

Esc               quit the program
Tab               switch panels
Space             page forward through entire disk
Del               page backward through entire disk
cursor keys       move
^E/^S/^D/^X       move up/left/right/down respectively
h/j/k/l                 move left/down/up/right respectively
d                 go to first directory block
< or ,                  go to start of drive
> or .                  go to end of drive
M (shift-m)       switch between read-only and read-write modes
^L                switch to (`login') a new drive
w                 write edited block to drive

To further explain some of the above:

- Space/Del are supported in both panels, and let you navigate through
the drive's data sequentially without having to mess around switching
panels all the time.

- In read-only mode (the default), no data on the drive can be edited.
In read-write mode, data can be edited (though you're still prompted
before data is ever written). Only the currently selected block can be
edited. When you switch blocks (or press Esc, etc.) you're given the
chance to write edits to the drive, but you can also do this
explicitly by using `w'.

The hex/ascii view/edit panel lets you look through or edit the
current block. When not editing, the following keys can be used:

Esc               quit the program
Tab               switch panels
Space             page forward through entire disk
Del               page backward through entire disk
cursor keys       move
^E/^S/^D/^X       move up/left/right/down respectively
h/j/k/l                 move left/down/up/right respectively
g                 go to data block referenced by byte at cursor
b                 go to previous block
d                 go to first directory block
< or ,                  go to start of block
> or .                  go to end of block
^C or ^V          page down (move 128 bytes forward)
^R or ^U          page up   (move 128 bytes backward)
M (shift-m)       switch between read-only and read-write modes
^L                switch to (`login') a new drive
e                 enter ASCII edit mode
E (shift-e)       enter hex edit mode
w                 write edited block to drive

`g' can be used in a directory block to jump to a block used by a
file, if you know enough about the CP/M directory format.
(Essentially, the line of hex underneath the filename gives up to 16
data block numbers. Put the cursor on one of these and press `g' to
get a data block. Which block of the file it actually is depends on
which extent of the file the directory entry is for, which is a bit
complicated to go into here - for files of 16k or less though, the
first byte on the line represents the first 1k of the file, the second
the 2nd, etc.) `b' is intended to be used to return to the correct
directory block after a `g', but might conceivably be useful in other
circumstances too.

(While on the topic of directory blocks, it's possible to undelete a
file by changing the E5h just before the filename back to a user
number to put the file in - say, zero. You can use the hex edit mode
to do this. Again though, the picture is more complicated for files of
over 16k. And you should bear in mind that - if the drive has been
written to since you deleted the file, or if you've run `defrag' on it
since - the file when undeleted may turn out to be corrupt.)

The hex and ascii edit modes let you change the data in the block.
These operate on the copy in memory, as you may have gathered, and you
can use `w' after the edit to save the changes to the drive.

The keys for hex edit mode are largely the same as those for the
non-editing mode, except that 0-9 and a-f/A-F enter hex at the cursor
position. You have to enter a byte at a time - once you've entered one
`hexit', you have to enter another (to complete the byte) before you
can do anything else. Other keys: Del backspaces a byte, and ^Q exits
edit mode.

The keys for ASCII edit mode are again largely like the non-editing
mode, except that all printable ASCII characters enter themselves at
the cursor position. Other keys are as for hex edit mode (see above).

***** ZRX filename

XMODEM receive a file from the serial port. Normally you'd use QTERM
or a similar program for such a task, but there is one situation in
which most of these programs don't work properly; when console I/O is
redirected to the serial port. In this situation, you can instead use
zrx to send files to your NC100, as it does no console I/O at all.

There is no analogous `zsx' to send a file.

Bugs: the XMODEM implementation is somewhat naive, and only supports
the old `checksum' method.

***** ZSELX [termtype [du:]]

Zselx is a simple file manager which lets you copy/move/delete/view
multiple files.

Even if you don't like file managers, zselx might possibly be of
interest since it allows you to copy files from any drive/user to any
other directly (e.g. from A: user 0 to B: user 3).

[The remainder of this description is from the (non-ZCN-specific)
zselx readme, so don't be surprised if it tries to tell you things you
already know, such as what user numbers are.]

****** About zselx

Zselx lets you pick files from a certain drive/user and do one of
these things:

- copy or move them to another drive/user;
- delete them;
- view them.

Like cpmtris, zselx works as is on VT52s (PCW and +3) and ZCN boxes,
works with VT100s with `zselx 1', and is patchable for other machines
and terminals. (It uses the same patch area layout, so you can use a
cpmtris patch with zselx.)

It's a conversion of my original Unix version, modified to use
internal cp/mv/rm/more-like `commands'. Unix zselx is free too (public
domain in fact, as writing it on Unix was considerably simpler) and
available on request.

Zselx was inspired by a useful little program for MS-DOS called `co'.
Zselx is essentially a clone of `co', with certain details modified to
suit CP/M.

****** User numbers

The term `user' in this file means `user area' or `user number'. If
you don't know what that means, check your CP/M manual. They're a
little bit like directories on other OS's. For those people without a
CP/M manual, here's the definition from the CP/M 2.2 manual:

"user number: Number assigned to files in the disk directory so that
different users need only deal with their own files and have their own
directories, even though they are all working from the same disk. In
CP/M, files can be divided into 16 user groups."

On a single-user system, then, they can be used rather like
directories. They're numbered from 0 to 15, with 0 the default user.
You can use the `user n' command to switch to user n. Drive/user
specifications are far from standard, and different forms are used by
different programs, among them (for, say, drive B: user 4) 4/B:, 4B:,
and B4:. Zselx uses the last one, as that seems to be the most

****** Using zselx

Running zselx gives you a list of files in a given drive/user.
(Normally the current drive/user - see `Command-Line Options' below
for how to use another drive/user.) You can then choose files to
copy/move/delete/view, etc. The keys are:

[Below, ^x means control-x. Many operations can be obtained with more
than one key, and each key is listed. Where I say `the files', I'm
referring to the tagged (selected) files. If none are tagged, the
currently-pointed-to file is used. I also list keys used in the Unix
version which aren't supported in this CP/M version.]

Esc x q           quit
h k ^p ^e   move cursor up
l j ^n ^x   move cursor down
0 <         go to top of file list
$ G >       go to end of file list
^b ^u ^r    move cursor back a page
^f ^v ^c    move cursor forward a page
c 1         copy the files to a given drive/user
d 2         delete the files, prompting for confirmation
m 3         move the files to a given drive/user
a 4         untag all files
v           view the files (press Esc/q/x to exit file view)
f           not supported (edit the files)
o 6         not supported (run a given command on the files)
n 7         sort file list by name
e 8         sort file list by extension
s 9         sort file list by size
t           not supported (sort file list by `time' (date))
+ =         tag file at cursor
-           untag file at cursor
Space       toggle tagged status of file at cursor
~           not supported (tag files ending in `~')

In short, it supports both vi and Emacs keys (and the wordstar-style
^E and ^X), and if you have cursor keys, they'll probably work (unless
you're using a VT100, I'm afraid).

When specifying drive/user to copy/move to, you can use any of the
forms a:, 0:, or a0:. If you don't give a drive/user, i.e. you just
press return, then no copy/move is performed.

Some notes on the way the copy, move, etc. commands work:

- copy/move test for copying to the same drive/user, and don't
copy/move if this is the case.

- move works by copying then deleting, even if you're only moving a
file from one user to another on the same drive. This means that, if
you're moving a file between users on the same drive, you temporarily
need enough room for two copies of any file you want to move. There's
no such problem when moving between different drives.

[Note to hackers: Why do I implement file move this way when it would
be quicker to just change the user number in the disk's directory?
Well, because it's more portable. CP/M emulators translating native
directories on the fly (like Michael Bischoff's excellent `cpm'
emulator for Linux) can't possibly handle this kind of thing. Also,
ZCN doesn't have much of a BIOS, so it wouldn't have worked on that.]

- view is designed only for text files. It strips the high bit (for
wordstar files), then displays control codes in ^x form, so don't
count on the control codes necessarily meaning anything in binary
files. A more serious problem with using it to display binary files is
that it treats ^Z as EOF; so, as I say, it only really works for text

****** Command-Line Options

In Unix terms, the synopsis (usage) is `zselx [termtype] [du:]'.

If `du:' is specified, it must be a drive/user spec. to use instead of
the current drive/user.

Currently, on some CP/M-like systems, you may not be able to use the
`u:'-type form for the `du:' arg (i.e. just the user number) unless
you explicitly specify `termtype'. If you run into this problem, just
specify the drive too, using the `du:' form.

If `termtype' is specified, it must be a single digit corresponding to
a terminal type.

To explain this `terminal type' stuff: It's traditional for
full-screen CP/M programs to either include a configuration program,
or (more usually) document patches which need to be made to support
different terminals. Zselx does have a patch area (100h-17fh), but
also has built-in support for a few terminals. These are:

Type  Terminal
0     as defined in patch area
1     VT100
2     VT52 (PCW, +3, etc.) - this is the default
3     ZCN (this is auto-detected)
4     VC404

The idea behind being able to specify terminal type when you run zselx
is that it's more convenient if you sometimes use your machine via a
terminal or terminal emulator. With most programs you have to devise
some method of patching them when you want to use something other than
the default configuration. With zselx, if (for example) I'm using my
ZCN box via kermit on my Linux box - not uncommon - then it's just a
matter of using `zselx 1'.

See the source (zselx.z) for details of the patch area.

****** Bugs

The screen-redrawing code is pretty much pessimal. :-( In particular,
scrolling is done `by hand', rather than using any insert/delete line
capability the terminal might have. This can really hurt on a slow
serial link.

Doesn't yet support `co' option 5, `mark blank'.

****** Acknowledgements

The original `co' utility.

Hawkwind's "Warrior on the Edge of Time" and "Hall of the Mountain
Grill" albums. I listened to them constantly while hacking up zselx.
Well, one at a time of course, so not *really* constantly, but... :-)

**** Third-party programs included with ZCN

I've included several pre-patched versions of third-party programs
such as QTERM, ZDE etc. in the `support' directory. See the README
there for more info, and pointers to where to find the original
versions. You may well find these programs useful, and you should
definitely try them out.

** Limitations and Bugs

*** Screen

ZCN only has a ten-line screen, and there is no generic provision for
emulating a 24-line one. Many CP/M programs assume a 24-line screen.

The cursor still flashes on/off when output is redirected to the
serial port. `Fixing' this would slow down normal output, so I'm
reluctant to do that.

*** Keyboard

The NC100's keyboard hardware is less-than-perfect (see the top of
src/keyread.z for a more detailed explanation), and ZCN tries very
hard to fix the problems with it. It does better than the ROM does,
but may still not quite be perfect.

Here's a more low-tech explanation of what the problem is than the one
in keyread.z. Given the nature of the NC100's keyboard, reasonably
fast typists such as myself can end up pressing two or three keys at
once. If you press three keys at once, a spurious keypress is
generated *at the hardware level*. The ROM software has problems with
this - try typing the word "really" a few times in the word processor
or BBC Basic. If you type it at a reasonable speed, it comes out as
"reslly". The reason I wrote ZCN's keyboard-input-fixing code was to
avoid this reslly annoying problem. :-))

The only place in ZCN where shift-3 (the pounds-sterling symbol) does
anything sensible is in BBC Basic (the `bbcbas' version, not the
cut-down `bbcmin') - everywhere else, it's essentially unsupported.

*** Storage

The largest PCMCIA memory card size usable on the NC100 is 1024k, so
that's the maximum card size ZCN supports. The maximum drive size
supported by ZCN is 256k, so larger cards are split into either 2 or 4
drives. Blocks are always 1k (8 records) in length. Yes, ZCN dates
back to the heady days of CP/M 1.4 in this respect. :-) There is an
arbitrary limit of 4 directory blocks per drive. The `format' command
always formats drives so they have 2 directory blocks though (for a
maximum of 64 files). The `optdir' and `runrom' programs assume there
are exactly 2 directory blocks, though they won't actually damage
anything unless there's only one. (In practice, `runrom' is extremely
unlikely to damage anything even in that case.)

If the memory card is set to read-only via the switch on the side
(mine has one, I'm not sure if they all do), this is completely
ignored by ZCN. That's not to say the card isn't read-only - that's
done at the hardware level so ZCN can't mess with the card no matter
what - but rather that ZCN will pretend write operations have worked

The add-on disk drive available for the NC100 (the RangerDisk3 from
Ranger) is not supported, and for various reasons would be difficult
to support directly. I could probably write a program for ZCN to
transfer files to/from an MS-DOS format disk in the drive if someone
lends (or gives ;-)) me a drive, though. Anyone willing to do that
should contact me, and I'll see what I can do. (I've already written a
C program to read/write MS-DOS disk images on a Unix box (I wrote it
before I'd heard of `mtools'), so I'd only need to write absolute disk
read/write routines to get it working under ZCN. It probably wouldn't
take long.)

*** Speed

ZCN's file operations have turned out slower than I had expected when
I started writing it. The speed is bearable IMHO, but very slow
considering it's running off a ramdisk. You can generally speed things
up by running `optdir' to optimise the directory blocks on a drive,
which can give file-reading speeds of up to about 18k/sec for the best
case, about half the speed of the hard disk on an average 8086-based
PC (arguably :-)). This still isn't incredibly quick, but I doubt I'll
get it going any faster.

The NC100 has a Z80 capable of running at 6MHz (a Z84C0006, to be
precise), but the clock rate it runs at is about 4.606MHz. This sounds
strange, but since Zilog apparently don't make CMOS Z80s of a lower
spec than the Z84C0006 any more, it's not *that* weird to just run a
6MHz chip slow. Presumably it's run at this lower speed to reduce
power consumption.

Due to the interrupt burden of reading and decoding the keyboard 100
times a second, the effective processor speed for normal programs
running with interrupts enabled is about 4.491Mhz if one or more keys
were pressed during a given interrupt, or about 3.626MHz if not. (In
`tight interrupts' mode (more on this later), it's about 4MHz whether
a key is pressed or not. Yes, this is sub-optimal, and no, there's
nothing I can do about it.) This makes ZCN slightly quicker than the
ROM software if no keys are pressed (the ROM manages about 4.359MHz
whether keys are pressed or not), but slower if a key's pressed.
However, since the ROM doesn't actually interpret the keyboard input
into a keypress until a program asks for the keyboard to be checked,
this isn't a fair comparison.

It came as quite a shock when I realised the NC100 really did run at
rather less than 6MHz, as I'd originally thought... :-)

*** The NC200

Amstrad's followup to the NC100, the NC200, may or may not run ZCN. I
would need to have an NC200 to know for sure... :-) (I've had
third-hand notice that it does run ZCN since originally writing this,
but without any detail as to how well it runs. Presumably it's
something like what is outlined below, but I'd welcome any more
specific confirmation of what works and what doesn't, etc.)

In theory it *might* work. It wouldn't support the builtin disk drive,
wouldn't use the extra memory, would only use half the screen, and
would only work if the NC200 still has a PCMCIA slot and has the
screen memory in the same place (unlikely). The various ROM-based ZCN
utils (spell, calc, bbcbas, etc.) would have quite a good chance of
not working, I expect. :-)

I'm not particularly interested in upgrading ZCN to support the NC200.
(The reason is that I wouldn't buy one - it seems like a reasonable
machine, but has always been seriously overpriced IMHO. If someone
gives me an NC200, I'll do it.) If anyone wants to donate an NC200 or
write support themselves, please contact me.

*** Miscellaneous

If you read a file into the file being edited (with ^K R) in ZDE, when
you next write the file the 2nd char. of the file type (extension)
will have changed to that of the file that was loaded. A kludgey
workaround is to always explicitly reset the current file's name (with
^K N) after any `second file' operations such as ^K R and ^K W, or
only to do second file operations on files with the same file type. I
don't know if it's possible to fix this; it's related to the NMI
handling and the whole problem with byte (0066h). Oh well, I suppose
it could have been worse... (sigh). As Fermat might have said, I have
a truly marvellous fix to this problem which this margin is too narrow
to contain. :-)

A SUB file with args cannot be successfully executed from user 255.
This is pretty obvious when you think about it (user 255 is read-only,
remember, and `submit' needs to write out a $$$.sub to work), but is
still weird.

** ZCN for hackers

This section is intended for those who want to program for ZCN
specifically (rather than CP/M in general), or are mad enough to try
hacking on ZCN itself.

If you're new to programming CP/M, have a look at `zcnprog.txt' in the
`doc' directory. It also covers zcnlib in detail. (Zcnlib makes
programming for ZCN and CP/M a hell of a lot easier, quite frankly.)

*** The Screen

The NC100's screen is 480 pixels wide by 64 pixels down. In the memory
configuration used by ZCN, the screen memory is always placed at
F000h. The screen is arranged so that each group of 8 pixels is
combined into one byte with the most significant bit of each byte
being the leftmost of the 8. If a bit is set, it appears as a black
pixel in the relevant position. Each pixel line comprises 60 bytes,
giving the 480 pixels (bits).

This gives a screen memory size of 60*64=3840 bytes. Since 60 is an
awkward number to handle in hardware, there are four (wasted) bytes
after each 60-byte line. So 64*64=4096, i.e. the screen carries on up
to the top of memory.

(Before you start getting funny ideas, it's not a good idea to use
these wasted bytes - the terminal driver uses plenty of block copies
when scrolling etc. It is in theory possible to use the bytes in the
range FFFCh-FFFFh, but these are reserved for use by ZCN.)

ZCN uses a character cell size of 4x6. This gives a character
resolution of 120x10, and leaves four unused pixel lines. That is, the
first two and last two pixel lines are normally unused by the system
(although they are cleared by the internal command `cls', the `drive
lights' use part of the bottom line, and they are temporarily used
while writing a screen dump).

Under ZCN, the screen can be directly modified by simply writing to
the display memory. (You'll want to turn the cursor off while doing
this.) There is no mechanism provided to restore any previous
contents, though, so you'll have to do that yourself if it's required.

ZCN itself provides no functions for drawing graphics. Look in the
`zcnlib' directory for several public domain library routines,
including graphics ones, which you can use in your own programs.

*** Tight Interrupts

In (for example) an action game, you would want to read more than one
key at once. This is a completely alien concept to vanilla CP/M, but
ZCN provides a feature called `tight interrupts' which makes doing
this possible.

Now, generally on a machine with a simple port-mapped keyboard you
would just read the ports directly. On ZCN and the NC100 in general
there are a few problems with this:

1. ZCN enables interrupts whenever a BDOS function is called. (You
would probably have wanted to disable them.)

2. The NC100's keyboard ports are only readable after an `interrupt
cause' port (90h) is read - and any maskable interrupt routine *must*
read the keyboard in this way (or at least acknowledge the interrupt)
or the machine will hang. [NB: I wrote this a long time ago. It may
not be the case. It's difficult to test properly. Reading the keyboard
directly is a real pain, in any case.]

The `tight interrupts' mode fixes this problem by making ZCN's
maskable interrupt routine do the bare minimum it is required to do;
as such, your game (or whatever) gets the maximum share of CPU time
possible and can also read the (fairly) raw keyboard map set up by the
interrupt routine. Unfortunately, since you need to be able to read
all of the keys rather than just one as is normally the case, the
interrupt routine must clear the raw keyboard map on each interrupt.
Still, you should get an reasonable (and constant) effective processor
speed, whether keys are pressed or not.

If you want the full 4.606MHz, you might want to run with interrupts
disabled and call an `interrupt routine' regularly `by hand'. Look at
`inthndl.z' and `keyread.z' to see what's required. I've used a
similar approach successfully in patches to get a couple of ZX
Spectrum games (Elite and IK+) to run on ZCN. It's a pain to have to
write your own interrupt handler though, and using tight ints mode is
far easier.

To use tight interrupts mode, you have to call two of ZCN's extra BDOS
functions (by calling address 0005h), as described below:

Function #129 - Set Tight Interrupts
Entry: C=129, E=1 to set tight mode, E=0 to set normal interrupt mode.
Exit:  none

Function #130 - Get Keyboard Rawmap Address
Entry: C=130
Exit:  HL=address of rawmap

(As usual with the BDOS, registers not mentioned above may have their
values changed.)

So to set tight interrupts mode you would do something like this:

ld e,1
ld c,129
call 5

Tight interrupts mode has its drawbacks of course. Serial input is
ignored. Auto-poweroff is disabled (the timer is frozen). The drive
lights are not updated. Normal BDOS and BIOS key-reading functions
will not work correctly and may hang the machine if called. The byte
at (66h) is not set to F7h if the value has changed. (However, any
BDOS call will cause this check to happen.) Remember to turn tight
ints mode back off again before doing a `ret' to ZCN; just doing `jp
0' instead may be easier, as a warm boot also disables tight ints

To read the keyboard then, you will also need to know the address of
ZCN's raw keyboard bytemap. You can do this with something like:

krawmap: defw 0
ld c,130
call 5
ld (krawmap),hl

You should only do this once, of course, to avoid the overhead of
calling the BDOS every time.

The keyboard map is 256 bytes long. Each byte in the map is non-zero
if that key is pressed, and zero if it is not. Each key is converted
by ZCN into the ASCII equivalent (apart from a few `weird' keys such
as the cursors, which give ^E/^S/^D/^X), and this is where it will
appear in the table. Continuing the previous example, if we wanted to
see if the `q' key is pressed:

ld hl,(krawmap)
ld e,'q'
ld d,0
add hl,de
ld a,(hl)
and a

You could do this more quickly and easily with IX or IY, if the key to
test is constant (as in this case) with something like:

ld ix,(krawmap)
ld a,(ix+'q')
and a

If you want to wait for the next 1/100th-sec interrupt, you can do it
by checking ZCN's 1/100th strobe which exists for this purpose and
still works in tight ints mode. Use this function:

Function #131 - Get 1/100th strobe address
Entry: C=131
Exit:  HL=address of 1/100th strobe byte - toggles between 0 and 255
      100 times a second.

...to get the address of the strobe byte once, when initialising stuff
in your program; and to wait for the next interrupt just wait until
the value changes. One way to do this follows:

strobe: defw 0
;get strobe address
ld c,131
call 5
ld (strobe),hl
;wait for next interrupt
ld hl,(strobe)
ld a,(hl)
ei          ;make sure interrupts are on!
cp (hl)
jr z,stloop

In ZCN v0.3 and up, you can just use the `halt' instruction to wait
for the next interrupt. This is usually the 1/100th-sec interrupt, but
could also be an interrupt caused by serial input (even if serial
input is being ignored, as it is in tight ints mode, the interrupt
would still happen).

*** The Power On/off Switch

The power switch on the NC100 does not directly control whether the
computer is on or off.

When the button is pressed to turn the machine off, a non-maskable
interrupt is generated. This has the effect of disabling maskable
interrupts, pushing the program counter onto the stack, and jumping to
address 66h.

This is extremely awkward for a CP/M-like OS - 66h is the address used
to hold the 2nd character in the extension field of the 1st FCB
provided by the system.

ZCN attempts to get around this problem by putting the value F7h (i.e.
RST 30h) at 66h and putting a jump to the NMI/poweroff handler at 30h.
In addition, any value which would ordinarily be put at or read from
66h by ZCN's BDOS etc. is actually put somewhere different (labelled
`real66' in the ZCN source - not directly accessible to programs).

To further handle things which a program using ZCN might do, such as
copying the filename from the FCB and using it, or clearing the high
bits of the filename, ZCN actually compares the low seven bits of any
appropriate character with the low seven bits of F7h. As well as this,
any characters output to the console are checked - if the char. is F7h
then the `real66' value is used instead.

Both the BDOS and the maskable interrupt handler update the `real66'
value and reset (66h) to F7h if the value in 66h has changed.

This is not perfect of course - it means that programs might display
filenames which appear to have a lowercase `w' as the 2nd character of
their extension. This can happen if the filename was read from the
FCB, and the top bits of the characters were cleared before display.
This is a little annoying (if harmless), but impossible to work

Another possibility is if a program not only resets the high bits of a
filename from the FCB around 66h, but also uppercases it, then the
file will actually be referred to with a `W' in the extension. As the
FCB is already uppercase, this is fairly unlikely to happen in
practice. :-)

*** Sound Hardware

[NB: See nciospec.doc on ftp.nvg.unit.no in /pub/cpc/nc100 for a
better description of the sound hardware. There's also a copy of the
relevant part in the `support' directory.

I wrote this section before I knew of this document. In fact, I wrote
most of ZCN before I knew about it. :-)]

The NC100's sound hardware is a simple two-channel chip. I expect
Amstrad were originally going to put an auto-dialler in the built-in
software; it's pretty pointless having a two-channel chip just for a

The chip works by you telling it what tone to play, and it playing it.
No volume control or anything like that, just tone or no tone. The
ports to write the tone value to are 50h/51h for the first channel,
and 52h/53h for the second. You write the low byte of the tone value
to the lower port number, and the high byte to the higher.

As for tone values, here are some I worked out by ear. They might not
be perfect, but they're good enough, I think. The values are for
octave four... on my keyboard, at least. :-) At any rate, you can
double these up to move down an octave, or halve them to move up an

Note  Value (hex)
----  -----------

c     024C
c#    022B
d     020B
d#    01EF
e     01D2
f     01B8
f#    019F
g     0188
g#    0172
a     015D
a#    014A
b     0137

You can turn a channel off by writing 80h to the higher of the two
port numbers for either channel, e.g. 51h for the first.

You can get a crude on/off speaker arrangement (similar to what you
get on a ZX Spectrum) by writing a zero to the lower port number(s),
then writing the higher one(s) with 00h for on, 80h for off. By no
means elegant, but surprisingly effective. The `play1b', `play2b' and
`play4b' programs use this technique.

*** Battery levels

If you want to test battery levels yourself for some reason, it's
quite simple:

Get a byte from port A0h.

If bit 2 is set then the lithium backup battery is low.
If bit 3 is set then the main batteries are low.
If bit 4 is *zero* then the PCMCIA card's battery is low.
      (This bit is set if not, or if no card is in the slot.)
      (Note that as mentioned in the `Battery level warnings'
      section, this particular battery-level test doesn't actually
      seem to work properly.)

Other things indicated by port A0h are:
Bit 1 is set when the printer is busy.
Bit 6 is set if the card is write-protected.
Bit 7 is set when there is no card in the slot.

*** PCMCIA Card Format

The general format of a card is:

logical_drive_A [... logical_drive_D].

Cards with a capacity of <=256k have a single logical drive. 512k
cards have two. 1024k cards have four. Each must be formatted
separately. Each is entirely self-contained, but drive A: must always
be formatted for drives B:, C: or D: to be accessible.

Each logical drive has the format:

boot_block [system_block_1 ...  system_block_N]
      data_block_1 ... data_block_N

(But remember that data blocks are really numbered from zero. :-))

At least one, and not more than four, consecutive blocks are used at
the start of the data blocks section for directory entries. (ZCN's
`format' command always puts exactly two directory blocks on the
formatted drive.) Each block contains space for 32 directory entries,
with each entry taking 32 bytes. There are zero system blocks if the
card is not bootable, and no more than 15 if it is.

The format of the boot block is as follows:

name      offset    description

cf1jump1  0         18h if bootable, otherwise C9h
cf1jump2  1         7Eh
cf1magic  2         ASCII for "ZCN1"
cf1size   6         word containing total size of card in K
cf1sysb   8         number of system blocks (0..15)
cf1dirb   9         number of directory blocks (1..4)
cf1junk   10        reserved
cf1zero   64        64 bytes, set to zero
cf1boot   128       boot program, if bootable (128 bytes max.)
cf1rrcode 256       256 bytes reserved for use by `runrom'
cf1fnx    512       Function-X-style boot program, if bootable (128
cf1xtra   640       reserved (128 bytes)
cf1pairs  768       256 bytes reserved for use by `runrom'

Only the first logical drive on a card is normally booted from. That
said, it is possible to boot from a second (or third, or fourth)
logical drive by using the old-style BBC Basic bootstrap command, but
slightly modifying it so A is loaded with 90h for drive B:, A0h for
C:, or B0h for D: (instead of the usual `ld a,80h' for A:).

The format of directory entries is as follows:

(It's a simplified CP/M 2.2 format, almost the same as CP/M 1.4's, I

offset    description

0         user number of file (or E5h if directory entry is unused)
1         filename in all-caps, padded to 8 chars with spaces
9         extension in all-caps, padded to 3 chars with spaces
12        extent number (a file has one extent for each 16k of data)
13        reserved (zero)
14        reserved (zero)
15        extent size in 128-byte records
16        sixteen block numbers, the data blocks used by the file.
          Any unallocated blocks are set to zero.

All data blocks other than the directory blocks contain file data.

*** The BDOS and BIOS

The BIOS only provides warm boot, console in/out/status, print, and
serial in/out routines at the moment. Calling any other entries gives
the error message `BIOS error' followed by a warm boot (i.e. a return
to the CCP prompt).

The BDOS provides most of the facilities that CP/M 2.2 does. (The
`version number' function pretends ZCN is CP/M 2.2, in fact.) Programs
which attempt to calculate the disk space free will give incorrect
results, as ZCN doesn't use or emulate disk vectors etc. The AUX:
functions from CP/M 3 (`plus') replace the usual CP/M 2.2 paper tape
punch/reader support - AUX: is hardcoded to be the serial port.

*** Static Data Area

There are a little over 2k of buffers and other storage areas:

[taken from the `memory.txt' static memory registration file]

e600h-e6ffh used for IM2 jump table
e700h       also used for jump table (while computer is on)
e7e7h-e7e9h jump to interrupt handler (while computer is on)
e700h-e7ffh used to store old contents of b300h-b3ffh by powrhndl.z
e800h-e87fh 128-byte keyboard buffer
e880h-e97fh 256-byte scratch area used by `find free block'
             (note that this overwrites the ccp cmdline buffer!)
e900h-e97fh 128-byte cmdline buffer used by ccp
e980h-e9ffh 128-byte card read/write buffer (needed 'cos of paging)
ea00h-eabfh internal stack used by bdos functions.
eac0h-ecffh font data (`fontdata' set to ea00h, but nowt written there)
ed00h-efffh 768-byte serial input buffer (while computer is on)
ed00h-efffh used to store old contents of b000h-b2ffh by powrhndl.z

These are followed by the screen memory running from F000h to FFFFh,
as explained previously.

The addresses of the font data (at EAC0h) and of the screen (at F000h)
can be depended upon to stay the same if necessary. (Both can be quite
convenient to know the location of, for some ZCN-specific stuff. Note
also that the screen can be moved - see `nciohw.txt' in the `support'
directory for details.) They may change if ZCN ever supports the
NC200, but that's relatively unlikely to happen. After all, I haven't
even got an NC200. :-)

*** ZCN's use of the user stack

ZCN has to use the currently running program's stack in some
situations. Here is a list of those situations, and how many
words/bytes ZCN requires in each case:

situation               words bytes

Call to BDOS                  1     2
Call to BIOS                  2     4
Interrupt               1     2

These figures include the 2 bytes of stack used by the return address;
the BDOS and interrupt handler don't actually use any more user stack
space themselves.

These don't mount up - for example, if an interrupt occurs during a
call to the BIOS, the two bytes of `user stack' used by the interrupt
routine is actually on the internal BDOS/BIOS stack.

For portability's sake, it's probably best if you don't squeeze your
stack too tight. A sensible minimum, IMHO, is 80 bytes. I only made
ZCN depend on the user stack this little so that particularly naive
programs would work, e.g. PIPE v1.7.

** Copying and Modifying ZCN

ZCN is distributed under the terms of the GNU General Public License.
However, I feel that the GNU GPL could appear disconcerting to some
ZCN users. As such, I provide reassurance below. :-)

First, a couple of questions license pedants may have:

*** Why not make ZCN public domain?

Truly public domain software is the property of the public at large.
Sounds great. But, what this actually means is that anybody can do
anything they want with it. Just think about what that means for a few

To me, the most important advantages the GPL has are that the program
always remains free, that you get source and can modify it, and that
it allows sensible commercial distribution, even if a profit is made.

Besides, I do make things public domain sometimes, especially
libraries which I think programmers will find useful. Zcnlib is a good

*** Why allow commercial distribution?

Not-for-profit distribution is a great thing, but it's not all that
common except on the Internet. Great if you have access, a real pain
if you don't. (Even then, *somebody* pays for your access, which a lot
of (for example) students tend to forget. Course fees pay for a lot of
things, and net access tends to be one of them.)

Whatever difficulties I might personally have with people making money
off my work, the fact is that they usually don't make huge amounts
because the software is always available for less by definition, and
often they're small companies in the business because they're
interested in free software anyway. (A good example - a German Linux
CD distributor (S.u.S.E.) has over time sent me many free CD-ROMs as I
wrote something a few people use (zgv) which they include on their
Linux distribution. As I understand it, they ask all developers who
have written free software they distribute if they'd like free CDs
like this, and any who would like them, get them. That's the kind of
people I think we're talking about here.)

Bottom line: All I would really do by prohibiting commercial
distribution is stop some people who would otherwise use and/or
distribute ZCN from doing so. Why bother?

*** Running ZCN

To quote from the GPL, "Activities other than copying, distribution
and modification are not covered by this License". This means that you
are free to run ZCN, write programs while using it, etc.

*** Copying and Distribution

If you've read the license (please do, if you haven't before) you may
think it says that you must always copy the source to a program
whenever you copy the program in binary or executable form. This is
not the case! (See Section 3 of the license for more on this.) In
particular, when transferring the ZCN binary `zcn.bin' to your NC100,
there is no need to copy the source - this would be stupid on such a
small machine with such limited and expensive storage, so that's just
as well. :-) Since you already have the source on the machine you
transferred the binary from - or at the very least, you know where to
get it - you are perfectly entitled to copy only the executable code.

A rather common misconception, I have found, is believing that the GPL
states that you must provide copies of the program to anybody who asks
for one. This, again, is wrong. You don't *have* to give/sell a copy
of ZCN to anyone - from the GPL, "You are not required to accept this
License" but it says, as you might imagine, "nothing else grants you
permission to modify or distribute the Program". All this means is
that if you do want to make a copy of ZCN, you must do so under the
terms of the GPL. This is intended to give the person receiving a copy
of ZCN from you the same rights you had when you obtained a copy.

*** Modification

This is a tricky subject, so it's best if I leave Section 2 of the
license to *fully* explain this; but essentially, you need to insert
prominent notices (comments) in any source files you change saying
that you changed the file and when you changed it. In addition, I
would be grateful if you could also do the following things:

1. Say what it was you changed, and preferably why.

2. Use the date format YYYY-MM-DD for numeric dates, e.g. 1994-04-01
is April 1, 1994. YY-MM-DD is acceptable for years up to 1999, but
would look a bit odd for 2000, and be confusing for 2001 onwards.

3. I urge you to contribute your changes to me to be included as part
of the `official' distribution of ZCN. Do this by creating a context
diff with `diff -c oldfile newfile' (`diff -u' style diffs are also
ok). If you absolutely *can't* do that, please send the source files
which have changed and describe your changes as completely as
possible. Please say which version of ZCN these changes were made to
when sending them, in any case.

4. *Please* don't use macros. They can get confusing very easily, and
tend to result in greater memory use, which we can ill afford in ZCN.

These things are optional, of course, but it would be nice if you
could do them.

Note that source files tend to have old version numbers if they
haven't been changed since that version. This is intentional, as the
file date/time stamps then better reflect how long it's been since I
changed the file. I think this is a Good Thing. For example, `boot.z'
hasn't changed since August 16th 1995, when I updated the header to
read `ZCN v0.3'. But in reality, the rest of the file hasn't changed
since v0.1 in 1994!

Look at the top of this file or do `ver' to find the true version

** Building ZCN

This section explains how to build (assemble) ZCN, should you wish to.
You might want to if, for example, you make some changes to ZCN and
want to try them out.

*** Building ZCN itself (the `kernel')

You need the free Z80 cross-assembler `zmac' to assemble ZCN. (A copy
of the source is included with ZCN in the `zmac' dir.) This compiles
on Unix and MS-DOS - it may or may not work on other systems. (The
main requirements, at least for compilation :-), are an ANSI C
compiler and either bison or yacc.)

In case you're using an MS-DOS/Windows box, where it's less likely
that you'll be able to compile it yourself, an MS-DOS executable of
zmac 1.1 is included in the `dosutils' dir. This directory also
contains source and MS-DOS executable for the `mkasmver' program
required to build ZCN on MS-DOS/Windows. (This program is needed to
replace a bit of code in the Makefile which uses `grep', `awk' and

If you want to make sure you have the latest version of zmac, you can
check out ftp://sunsite.unc.edu/pub/Linux/devel/lang/assemblers on the
net, which should contain the latest copy. (But the copy included with
ZCN works well enough, and is probably up to date anyway. :-))

After you've compiled and installed `zmac' (if needed), doing `make'
(or `dosmake' on MS-DOS/Windows) in the src directory should assemble
ZCN. You can transfer the new `zcn.bin' binary from `../bin' across as
you did previously - this is described near the start of this file.

[By the way, it's theoretically possible to build ZCN under ZCN. But
I've yet to find a free CP/M Z80 assembler which could handle this.
More to the point, it would be incredibly slow and painful and would
require a good 512k or so of drive space.]

*** Building ZCN as a whole (including utilities etc.)

Building the whole of ZCN and associated programs requires rather
more. You'll *definitely* need a Unix box (a Linux box is ideal -
that's what I use, anyway :-)), which should have these things:

- zmac                              (bundled with ZCN)
- awk, cat, cc, cut, date, dc, grep, mv, rm, sed, sh, sort, tee, tr, uniq
                              (unlikely to be a problem :-))
- GNU make

To be able to rebuild `manpages.pma' and `zapdesc.bin', you'll need
the `cpm' CP/M emulator. (See below for where to get it.) If you can't
run this, comment out the HAVE_CPM_EMU line in `config.mk'.

If you want to be able to rebuild zcnclock's `cities.mrf' (there isn't
any point usually), you'll need xearth and netpbm installed. To avoid
this requirement, comment out the HAVE_XEARTH_AND_NETPBM line in

Finally, if you want to actually make a ZCN distribution, you'll need
the portable `zip' program in order for the top-level Makefile's `make
dist' to work.

Now, back to where to get `cpm'. Try looking in the directory pointed
to by this URL:


At the time of writing you'll need both `cpm-0.2.1.tar.gz' and
`cpm-0.2.1-glibc-rjm.patch.gz'; the patch makes it work on glibc-based
Linux systems, and also fixes several bugs.

* Contributions welcome

Things that would help with the development of ZCN are:

** Technical information on the NC100 and on CP/M internals

Info. on the NC100 would be most helpful. (I think I know most things
about it now, but I'm interested in anything not covered in Amstrad's

Knowing about any dubious or otherwise `tricky' assumptions CP/M
programs might make which I should cater for would help. I think I've
got most of these covered, though.

** Contact me if you use ZCN

This is another thing I would appreciate. In my experience with the
other free software I've made available that required significant time
and effort to develop (probably the best example is zgv, a picture
viewer for Linux), knowing that other people are using the program too
really helps. (Sure, "what a piece of work is Man", but at least I'm
honest about it.) In this case it's more important, because I doubt
many people will use ZCN - there can't be many people who own an
NC100, and I imagine few of them would want to run a CP/M clone on it.
Except possibly PCW owners. :-)

** Suggest ideas for features and report bugs

I welcome any suggestions for enhancements to ZCN. I can't say whether
I'd actually implement them or not, memory is getting a little tight
to put in all the bells and whistles I'd like :-(, but I'd certainly
consider any idea.

With ZCN's aim of close CP/M compatibility, I could do with knowing
about programs that don't work with it so that I can try to find out
what the problem is.

* Acknowledgements

** Programs and routines written by others

All of the programs in the `support' directory (apart from crapmext.c)
were written by others. Details are in each program's documentation.

`cal' is a port of a C original by Martin Minow.

`expr' is a rather hacked-around port of a C original by Erik

`man' uses Yoshihiko Mino's decompression code from `pmexe2'.

`zap' uses a modified port of the GNU libc's qsort routine (which is
actually called `msort'). The original C version was by Mike Haertel.

** General thanks

[Or, "an exercise in self-indulgence". :-)]

Graham Richards for sounding interested, and being impressed at the
smallest of achievements in the early days. (Also, the filled triangle
drawing routine in zcnlib is a transliteration of one of his old

Cliff Lawson at Amstrad for sending me a copy of `nciospec.doc' and
helping me with various NC100 hardware questions.

Linux, a slightly less obscure GPL'd OS. :-) (great for development,
even in Z80)

ZSIM (running Superdos). I used this early on to test out `what does
CP/M do when I do this?' scenarios.

The Linux DOS emulator `dosemu' which I used to run ZSIM. :-)

Michael Bischoff for his `cpm' emulator, which I now use instead of
ZSIM, and for posting me CP/M docs. (And for not screaming at me when
I bought a CP/M manual soon after. :-})

Steven Flintham for getting an up-to-date version of ZCN on the net
for me - and for (many moons ago) writing to me for a current version
of ZCN despite not having an NC100, which I think says something,
though I'm not sure what. :-) He also gave helpful hints on the BBCBAS

Locomotive CP/M Plus for the Sinclair ZX Spectrum +3 - for getting me
interested in CP/M in the first place.

"An Introduction to Z80 Machine Code" by R. A. and J. W. Penfold (the
omnipresent R. A. Penfold strikes again), and "A Z80 Workshop Manual"
by E. A. Parr.

The "BBC Basic features not covered in the NC100 manual" section would
probably not have been possible without considerable reference to the
NC100 manual, "NC100 Magic" by Vic Gerhardi and Dave Hampson, and the
Acorn Electron manual.

Games played between sessions of pulling hair out: Tetris Attack,
Wipeout 2097, Tekken 2, Nethack, DOOM, Tempest 2000 (and X3), Sensible
Soccer, V-Rally, Super Bomberman 3, Stunt Race FX, Elite, CP/M Rogue,
and Mille Bournes (BSD version).

Music played incessantly while hacking ZCN:
"Counterparts" by Rush
"Different Stages" by Rush
"Hemispheres" by Rush
"Hold Your Fire" by Rush
"Moving Pictures" by Rush
"Signals" by Rush
"Test For Echo" by Rush
[Yow! Am I a Rush fan yet? :-)]
"Close To The Edge" by Yes
"The Yes Album" by Yes
"Tempest 2000" soundtrack (PC ver.) by (IIRC) Ian Howe and Imagitec
"Victor" by Victor
"Wish" by The Cure
"PXR5" by Hawkwind
"Foo Fighters" by Foo Fighters
"Superunknown" by Soundgarden
"Debussy: Piano Music", a compilation of Debussy works
"Tubular Bells II" by Mike Oldfield
"Zoolook" by Jean-Michel Jarre

"I heartily endorse this event or product."
      -- Krusty the Clown

All trademarks are acknowledged as belonging to their respective

* Epilogue

The observant will no doubt have noticed that as yet, I haven't
revealed or even hinted at what ZCN stands for; and with good reason.
ZCN originally stood for "Zgedneil's CP/M for the NC100", a rather
crap tongue-in-cheek name I hastily thought up when designing ZCN's
drive format (while computerless during 2nd year exam re-takes,
scrawling notes on a rather more low-tech notepad by the fountain in
Woolwich town centre) as I needed something meaningful to put in the
`cf1magic' field. Sad but true. Now it just stands, for, well, ZCN
really. :-)

Why `zgedneil'? Oh, well that's an old Rush-influenced password I used
ages ago, which I adopted in 1992 as a standard pseudonym for where
such things are the norm (some BBS-like systems, for example). I had
used `z' as a prefix to program names a couple of times in the
"zgedneil's foo" sense, as a (slightly crap) way of making them less
likely to conflict with existing ones, and GDR pointed out that
"every" program I wrote now started with a `z'. In response, I then
started *really* naming lots of things `zfoo'. :-)

* The future of ZCN

I'm reasonably happy with ZCN now, and I regard it as `finished',
pretty much. Any future releases are unlikely to contain much more
than bugfixes. This only applies to ZCN itself (the `kernel', if you
like) - I might add extra utilities, or hack on existing ones, etc. at
some stage. (Indeed, this was essentially what I did for v1.1 and

In other words, while there might possibly be ZCN releases after this
one, I doubt there'll ever be sufficient change to justify a ZCN v2.0.

Then again, I thought it was `finished' in 1995, so who knows? :-)

* Getting ZCN

ZCN should be available on the net if you have anonymous ftp access,
on ftp.nvg.unit.no in /pub/cpc/nc100. Don't expect it to *necessarily*
be the most recent version, as I don't have any net access at the
moment. (Though thanks to Steven it's an awful lot more recent than it
was. :-))

I'll send a copy of the latest version of ZCN to anyone who sends me a
3.5" disk and an SAE. Be sure to say you want ZCN, though. :-) My
address is below. You can do this again at some point in the future if
you'd then like a copy of the latest version, but please don't do this
any more often than once every 6 months, and bear in mind that ZCN may
not have been updated since you last got a copy. (I don't tend to
update ZCN very often these days - not long before the release of v1.1
it had been a year before I'd made any changes at all!)

Disks can only be sent in MS-DOS, minix, and ext2 formats, and it'd
save me some trouble if the disk was already formatted. I'll send ZCN
as a zip file unless you specify a different format to use. ZCN fits
(compressed) onto a single 1440k disk (just! :-)), but won't fit on a
720k one any more.

I can send ZCN in most archive formats (zip, lzh, tar, tar.Z, tar.gz,
tar.bz2, arc, zoo) but I can't (won't) send it in arj format due to
the lack of a free utility to create arj files.

In addition, don't forget the slightly fragile nature of the postal
service. If you don't get the disk back within two weeks, you can
reasonably assume it got lost in the post. It only happens quite
rarely, but it *does* happen. There's nothing I can do to help this,
and all you can realistically do is try again.

You can also contact me if you have any queries or problems with ZCN,
or, well, any reason really. :-) If you're writing via snail-mail, be
sure to include an SAE or other suitable return postage if you want to
guarantee a reply.

* Contacting the Author

You can email me at rus@forfree.at but since I'm not on the net, mail
received there is just posted to me at regular intervals by a friend
(and similarly I post responses back to be emailed). It could take as
long as six weeks for you to get a response - if that's a problem,
then you could write to me directly instead (more hassle, but usually

You can write to me at:
            Russell Marks,
            3 Rapley Close,
            GU15 4ER,
            United Kingdom.