p; cat file.txt; |
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
column.
- 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.]
*** Command Line Editing
The only command line editing available is delete-previous-char, and
there is no way to recall previous commands.
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 ***
A>
You can keep using the NC 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 computer 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
instead.)
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 old 512k memory card said 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
maintained.
3. Battery discharged, data LOST.
It seemed to me that the NC100 treated states 1 and 2 above as
`battery ok' and state 3 as `battery low'.]
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'.
Some notes on battery life - the tests I tried years ago on NiCad
rechargeable batteries with the NC100 suggested that they would give
roughly 8 hours use between rechargings (with some variation depending
on capacity). How long you generally had between the `batteries low'
warning and effectively dead batteries seemed to be something like 30
minutes for those.
NiMH batteries (as you might be expecting to use nowadays) are likely
to have higher capacity and longer battery life. (On the NC200 in
particular with those five substantial C batteries, if you're not
using the floppy, and have the backlight mostly turned off, you can
get dozens of hours of battery life out of them.) Just do bear in mind
that the voltage dropoff can be quite sudden, so any battery warning
will be minimal. I would say don't expect to get much more than a few
minutes.
(For the NC200, using rechargeables for the five main batteries does
mean that you need to use a charger which charges batteries on an
individual basis, rather than in pairs. Such chargers tend to be more
expensive.)
*** 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 arguments (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 present). This is
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 the `SUB files' section below for
more on those).
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
truncated.
The text after the initial `%' is printed verbatim apart from these
codes:
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
originally used on my NC100 - `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. (Those feeling nostalgic for MS-DOS might like to try
`%d:\%a>' or `%d:\%b>' for a similar effect.)
**** BATWARN <0 or 1>
Disable/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 risky 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
Card boot - boot ZCN from the memory card. If the card is not
bootable, or there's no card in the slot, ZCN gives an error 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, i.e. if plain `user' or `cd' is used,
then it acts like `user 0'. If `n' is a dash (`-'), then the previous
user area (as set by `user' or `cd') is used.
This alias for `user' should make slightly more sense to Unix users,
though the flat `directory' structure in CP/M makes the `cd' command 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
possible output: `A:=2k B:=43k'. Only drives which exist on the card
or ramdisk 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' is
given.
`dir' exists primarily for CP/M compatibility, 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:'. This also
works for a ramdisk.
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.
**** 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'
(NC100/NC150 only!).
This command makes it very easy to crash the machine if you don't know
what you're doing or make a mistake, 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.
(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, the other 256 is to allow for stack space, and it
rounds down. So it's a realistic estimate of the maximum program size.
**** LIGHT <0 or 1> (NC200 only)
Disable/re-enable the NC200's backlight. It's enabled by default, but
disabling it should prolong battery life considerably (actually
tripling it, if the NC200 manual is to be believed). There is no timed
"auto" mode available, it's just on or off.
**** 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 (every 21
on the NC200). 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 TED 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
up the text in memory, and saves when you're finished). That said, you
could salvage the text with `save', as the text starts at 0100h.
Bugs: limited to ASCII input, and does not accept the Tab character.
(These are limitations of the ZCN buffered-input function it uses.) It
also doesn't check for total input being bigger than available memory.
**** 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 very easy to crash
the machine if you don't know what you're doing or make a mistake, 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
afterwards.
**** RAMD <0 or 1> (NC200/NC150 only)
Disable/enable ramdisk. This command switches between the usual memory
card on A: to D:, and an internal ramdisk on a replacement A: drive.
The capacity is 61k on the NC150, and 45k on the NC200 due to the
larger screen memory. To simplify the implementation you cannot use
the ramdisk and memory card at the same time, though you can freely
switch between the two modes with RAMD at the command line.
(Unfortunately the original NC100 cannot reasonably support a ramdisk,
as it only has half as much RAM.)
The ramdisk is mostly of interest if you have an NC200 or NC150, but
don't have a memory card. It is obviously exceptionally limiting, but
less limiting than having nothing. :-)
***** Using the ramdisk
If you plan to use the internal ramdisk, note the following:
- Before using the ramdisk after booting, you'll need to do "ramd 1"
to enable it, and then "format a:". This also applies if you reboot
to the ROM OS, which you should assume will destroy or at least
corrupt any existing data on this A: drive.
(The one case where you should avoid running format is if you boot
from floppy disk on the NC200 - in that case, the ramdisk is set up
by the boot loader, and should not be formatted or you'll lose the
existing contents.)
- Note that it is important to run the "format a:" command *after*
running "ramd 1", as the ramd command changes what A: means to ZCN.
- "ramd 0" returns to the usual configuration, with A: to D: on the
memory card. Any existing ramdisk contents remain intact when you do
this, but cannot be accessed unless/until you do "ramd 1" again.
- The main way to get files to/from the ramdisk is serial transfer.
You can use the "rexec" command to receive a uuencoded file into
program memory (the TPA) and also save it as a file - you could use
this to e.g. send ZCN's `support/zx0alt/qterm.uue' file each time
you want to run QTERM to send/receive files (perhaps by using "rexec
c:c" which won't save a file - it gives an error which can be
ignored - then "!!" straight after that to run the copy in memory).
Another useful option for "rexec" is bin/zrx.uue, which only takes
1k of disk space and is reasonable to just keep on the drive as
normal - but it can only receive files, not send them. Still, in my
experience this is the simplest way to just get some files across.
(Be sure to read the `ZRX' section below before using it.)
As for files to transfer with QTERM or zrx, for initially getting a
number of files across you could consider using a self-extracting
archive as made with `pmarc' (pmarc2), perhaps made using a CP/M or
MSX emulator. One possible approach is "pmarc sfx.com=pmsfx2.com
b:*.*" requiring two different drives to make sfx.com containing
files from B:, but if you're careful enough you could do something
similar on a single drive. You could then run this sfx.com after
transferring it with "get 100 sfx.com", "era sfx.com", and "!!" -
doing it that way maximises the space available, but if you're using
the NC150, be careful not to "get 100" too large a file (45k should
be safe).
- It is technically possible to transfer smaller files (up to 45k)
between a memory card and the ramdisk by copying them via the main
memory, but this is a bit fiddly and precarious (e.g. to copy a 1k
ls.com you could do "get 100 ls.com", "ramd 1", "save 4 ls.com") so
I don't recommend it. In fact, ideally I'd recommend only using the
ramdisk if you're never using a memory card at all, simply to avoid
any confusion.
- You can't boot from the ramdisk, and "sys a:" will fail.
- The `cboot' command bypasses the ramdisk and will still try to boot
from a memory card.
- If you have B:/C:/D: as the current drive then do "ramd 1", the
drive is not automatically changed, but any attempt to use that
drive will fail.
- If the ramdisk is enabled and you do "format b:" (or c: or d:), it
will act exactly as if you'd done "format a:". This is due to a
quirk of the implementation.
- `runrom' and `rrxfer' won't work on the ramdisk.
***** Further details
Clearly, it's not ideal to add ramdisk support in this way by
redefining what the A: drive represents (!), but this approach
minimises low-level changes to a decades-old OS, which hopefully makes
it less likely to break everything. :-)
The ramdisk feature has had fairly limited testing on the NC200 (and
very minimal emulator-only testing on the NC150), so although the
principle by which it works is sensible enough - it's nearly the same
as the way I tested very early ZCN versions - I'd suggest treating it
with some caution and keeping backups.
**** 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.
The noise it makes is a little odd - I was trying to keep it from
being annoyingly loud, and this was the best `beep' I managed in that
respect. It's been memorably described (by Ian Miller) as "a sound
like someone gagging a piglet while they slammed its tail in the
door". :-)
**** 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).
Bugs: Doesn't check for the file being bigger than available memory.
**** 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.
**** SERIAL <0 or 1>
Disable/re-enable the serial line driver, which must be enabled for
RS232 serial I/O to work. It's enabled by default, but disabling it
should prolong battery life.
**** SERTEST
A very simple terminal program. It just echoes serial input, and sends
keyboard input to the serial port. This can actually be very useful if
you're using your NC as a terminal to a Unix/Linux box with a suitable
termcap/terminfo entry as given earlier. You can use ^\ then q (or ^\
then ^C) to quit; ^\ then ^\ sends a literal ^\.
**** STTY speed
Set speed of serial port. The default is 2400 bits per second.
Supported speeds are 150, 300, 600, 1200, 2400, 4800, 9600, and 19200.
Which speed 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 bps, here are some guidelines:
If you just want to do file transfers, you should be able to do so
without losing any packets even at 19200. (If you get too many errors,
use 9600 instead - that should work. But I've never had any problems
with using 19200.) Just make sure you use a non-streaming protocol
like XMODEM or YMODEM (not ZMODEM), and preferably stick to 128-byte
packets (so a whole packet fits in ZCN's serial input buffer).
If you want to use console output redirected to serial, again, 19200
should generally be fine. Just don't go pasting too much input at
once. :-)
Where it gets more complicated is if you want to use a terminal
emulator on the NC, to use the `other end' interactively. In that
case, 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 on the NC100, depending on line length,
i.e. how often it needs to scroll.
(This is as tested with the builtin `sertest' command; an external
program like QTERM will be slower due to system call overhead and so
on. The NC200 will also be slower, mostly due to the larger screen
meaning slower scrolling.)
- 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 speed is
speed/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 bps; using such speeds
makes watching paint dry seem like a exciting spectator sport):
speed 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:
speed 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.
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
on the NC100/NC150 you can probably get away with using any speed. The
reason is, assuming only 80 columns and 10 lines are used, 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. This approach doesn't really work on
the 21 lines of the NC200 though.
**** SYS a:
Add the system to a drive and make it bootable. Only the A: drive on a
memory card can be made bootable, and `format' always reserves space
for this.
If `sys a:' says "Too big", this probably means you're using a ramdisk
(which can't be booted from, so no space is ever reserved), or a
non-bootable drive formatted with an old version of ZCN. In the latter
case, you'd need to either make it bootable using that old version
first to reserve the space, or reformat the drive with the current
version (after saving any existing contents).
**** 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.
**** UNSYS d: (removed in ZCN 1.4)
In versions of ZCN prior to 1.4, `unsys' would make a drive
unbootable, freeing up the disk space previously reserved for system
blocks. This is no longer supported. System blocks are now always
permanently reserved when formatting A: on a memory card.
**** 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 previous user area (as 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.
This command skips the CCP's usual CR/LF output, so multiple `vdu'
commands can be used to build up multi-byte control codes.
**** VER
Report ZCN and ROM version numbers, and the local date/time (in
YYYY-MM-DD HH:MM format) when 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.
**** 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!" It's traditional for xyzzy to be
an {Easter egg} in games with text interfaces.
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 4.4.7
I hope ZCN broke new ground by being the first OS to *document* an
xyzzy command, but I expect someone else beat me to it somewhere. :-)
(The `Nothing happens' message is even reused by both the `note' and
`save' commands, in slightly dubious fashion, for an error opening the
output file. But this does save memory, and the error message is of
course technically correct - the best kind of correct.)
*** External Commands
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,
etc.
For example, if you did `submit foo bar baz' and the file `foo.sub'
was:
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...)
You can get a single `$' character in the output file by using `$$' as
you can see above. Aside from that, `$1' is translated to `bar' and
`$2' to `baz' throughout the file, even in the `rem' statement.
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
>p
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 VDE 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, unspecified args are replaced 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.
**** ZCN external commands
ZCN comes with several (optional) external commands, described below
in alphabetical order.
***** BBCBAS [-H] [filename]
[This is a *BIG* section - you may want to skip through most/all of it
if you're not interested in BBC Basic.]
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
below.
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.
If you'd prefer a *truly* native Basic, rather than merely a good
approximation of one :-), you can get the generic CP/M version of BBC
Basic (for free) from:
http://www.rtrussell.co.uk/bbcbasic/z80basic.html
You'll have less free RAM, won't have graphics or the copy cursor, and
the .com file is bigger, but it's there if you want it - and it does
let you avoid various issues with running the ROM version in ZCN.
There's also a BBC Basic manual available on that site; it's really
for a newer incarnation, but much of it applies equally to the NC and
CP/M ones. That's here:
http://www.rtrussell.co.uk/products/bbcbasic/manual/
****** Advantages of running BBC Basic in ZCN
- It's in ZCN. :-) This is surely more convenient than having to use
`runrom'.
- 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 (not available on
the NC200). This is much 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 details.
- 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. (Or 120x21 vs. 80x16.)
- Builtin help of sorts. Specifically, lists of the PLOT commands and
VDU codes, and a brief example of how to use the builtin Z80
assembler. See the section `Builtin 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 various 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
- Keyboard input at the Basic prompt is mostly limited to ASCII only.
- OPENUP does not allow writing to files; it instead acts like OPENIN.
I think OPENIN/OPENOUT should be sufficient for the majority of file
operations, but it's still a notable limitation.
- On the NC200, you cannot turn off the NC while Basic is busy, rather
than while it's using ZCN to e.g. wait for input. (But you can
always press Esc to return to the Basic prompt, and then turn off.
I'd recommend not using *ESC OFF.)
- On the NC200, the "drive lights" area in the bottom-left of the
screen is not really usable and remains mostly blank.
- 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 work.
- 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. (If it's available, at least.) Even if you
don't think that, you could always write the Basic as a text file in
TED, 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 (or
480x128) 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. (This issue is simply ignored on the NC200.)
- While by default ZCN itself 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 can be rather
indistinct, I'm afraid, but most of the characters are at least
usable.) You generally can't enter these non-ASCII chars direct from
the keyboard, so to print the square root symbol for example you'd
have to use VDU 251 or PRINT CHR$(251).
- If you run BBC Basic after redirecting output to the parallel port
with ">p" at the ZCN prompt, any characters in the range 128 to 255
are only sent to the printer, not the screen. (ZCN would ordinarily
send the character to both.) This is because those characters are
displayed in a non-standard way, leaving this as the least
unreasonable option.
- 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
- There are various serial port issues:
- When using BBC Basic via the serial port, it's possible to
occasionally `hang' the machine. I think what's 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.
(This workaround doesn't seem to work on the NC200, unfortunately.
In that case it seems the best you can do is hold both shifts
while turning on to reboot the ZCN in memory, losing any
loaded/entered Basic program if you hadn't saved it. In general
the NC200 seems to have real problems running Basic over serial,
so the generic CP/M version mentioned above is probably the only
sensible option in this case.)
- The check for Esc used while BBC Basic is busy only ever checks the
physical keyboard, even if you're running via the serial port.
- 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. Some of these will be
blocked on `bbcbas', but on `bbcmin', you may get weird characters
appearing (most often due to cursor on/off codes) depending on
your terminal or terminal emulator. (Minicom in particular seems
to love putting dots everywhere.)
- 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
accented chars, line-drawing chars, and the pound sign.
- 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 running.
- Well, one more BBC Basic bug - failing to manually close a *SPOOL
file (with "*SPOOL" alone) before doing *BYE means the file won't be
closed properly. In ZCN this "only" loses you the last up-to-127
bytes of output, while in the ROM s/w you usually seem to lose the
lot. (!)
****** The copy cursor
(This is not available on the NC200.)
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 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
space.
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:
10 PRINT "ZCN SUCKS, MAN"
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:
10 PRINT "ZCN IS COOL, MAN"
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.
(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 NC 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
LOAD "B:PROGRAM"
Now examples of some commands using text files:
*EXEC :BLARG
*SPOOL :A:TRY.BAS
FD%=OPENIN ":SOMETEXT.TXT"
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 VDE, 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 VDE
reminds you that it's unchanged - it may indeed be unchanged, but VDE
writes it as a CR/LF file with ^Z at EOF, so you *do* want to save
it.)
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.
****** Builtin help
There's a small amount of builtin 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 builtin 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 builtin 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
particular).
****** 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
Basics:
IF A=1 THEN PRINT "FOO":PRINT "BAR"
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 | || ~ | | | |
|Control |Ctrl|Symb| space | < | ` |left|rght|down|
`---------+----+----+-----------------------------+----+----+----+----+----'
The '/` key is a dead key, and Sym-2/3 are superscripts.
****** DK mapping
,----+----+----+----+----+----+----+----+----+----+----+----+----+----+----.
| | ! | " @|# pn| $ | % | & | / {| ( [| ) ]| = }| ? | ` || | |
|Esc | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | + | ' |Del>| \| ~ | | | |
|Control |Ctrl|Symb| space | < | ` |left|rght|down|
`---------+----+----+-----------------------------+----+----+----+----+----'
The '/` key is a dead key except with Symbol, and the "/^ key is a
dead key only when unshifted.
(This approach follows ROM OS behaviour.)
****** FR mapping
,----+----+----+----+----+----+----+----+----+----+----+----+----+----+----.
| | 1 |2 ~|3 #|4 {|5 [|6 ||7 `|8 \|9 ^|0 @|dg ]|+ }| | |
|Esc | & | 'e | " | ' | ( | - | `e | _ | ,c | `a | ) | = |Del>| | ~ | | | |
|Control |Ctrl|Symb| space | < | ` |left|rght|down|
`---------+----+----+-----------------------------+----+----+----+----+----'
The ^/" key is a dead key.
****** IT mapping
,----+----+----+----+----+----+----+----+----+----+----+----+----+----+----.
| | ! | " | pn |$ ~| % | & \| / |( {|) }| = | ? | ^ | | |
|Esc | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | ' | `i |Del>| || ~ | | | |
|Control |Ctrl|Symb| space | < | ` |left|rght|down|
`---------+----+----+-----------------------------+----+----+----+----+----'
The `a/or key is a dead key only when shifted.
(The locations for ~ \ | { } follow ROM OS behaviour.)
****** SE mapping
,----+----+----+----+----+----+----+----+----+----+----+----+----+----+----.
| | ! | " @|# pn| $ | % | & ^| / {| ( [| ) ]| = }| ? \| ` | | |
|Esc | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | + | ' |Del>| || ~ | | | |
|Control |Ctrl|Symb| space | < | ` |left|rght|down|
`---------+----+----+-----------------------------+----+----+----+----+----'
The '/` key is a dead key, and the "/^ key is a dead key only when
unshifted.
(This approach follows ROM OS behaviour.)
****** UK mapping
,----+----+----+----+----+----+----+----+----+----+----+----+----+----+----.
| | ! | " | pn |$ es| % | ^ | & | * | ( | ) | _ | + | | |
|Esc | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = |Del>| | ? | | |
| shift | Z | X | C | V | B | N | M | , | . | / | shift | up |
+----------+----+----+----+----+----+----+----+----+----+----+--------+----+
| | | | | | | ~ | | | |
|Control |Ctrl|Symb| space | \ | ` |left|rght|down|
`---------+----+----+-----------------------------+----+----+----+----+----'
The UK mapping is the default mapping used by ZCN.
****** UKDVORAK mapping
,----+----+----+----+----+----+----+----+----+----+----+----+----+----+----.
| | ! | @ |# pn|$ es| % | ^ | & | * | ( | ) | { | } | | |
|Esc | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | [ | ] |Del>| | | | | | | | | ? | + | |
|Tab | ' | , | . | P | Y | F | G | C | R | L | / | = | |
+------+----+----+----+----+----+----+----+----+----+----+----+----+\ |
|Caps | | | | | | | | | | | _ | | | Enter|
| Lock | A | O | E | U | I | D | H | T | N | S | - | \ | |
+-------+----+----+----+----+----+----+----+----+----+----+----+----+------+
| | : | | | | | | | | | | | |
| shift | ; | Q | J | K | X | B | M | W | V | Z | shift | up |
+----------+----+----+----+----+----+----+----+----+----+----+--------+----+
| | | | | > | ~ | | | |
|Control |Ctrl|Symb| space | < | ` |left|rght|down|
`---------+----+----+-----------------------------+----+----+----+----+----'
This is a Dvorak layout adapted to fit the NC keyboard, and given a
confusing name (originally based on it using the same physical key
layout as the UK mapping, but... they all do). It is not a native
layout for any NC.
****** US mapping
,----+----+----+----+----+----+----+----+----+----+----+----+----+----+----.
| | ! | @ | # | $ | % | ^ | & | * | ( | ) | _ | + | | |
|Esc | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = |Del>| | ? | | |
| shift | Z | X | C | V | B | N | M | , | . | / | shift | up |
+----------+----+----+----+----+----+----+----+----+----+----+--------+----+
| | | | | | ~ | | | |
|Control |Ctrl|Symb| space | BS | ` |left|rght|down|
`---------+----+----+-----------------------------+----+----+----+----+----'
This is a US layout adapted to fit the NC keyboard. As you can clearly
see, the extra key is BS. It is not a native layout for any NC - not
even if you count the NTS DreamWriter 225.
***** LFCONV infile outfile
Convert an LF-only (Unix format) text file to the CR/LF format used by
most CP/M and ZCN programs. (Some cope with LF-only files, but not
many.)
***** LS [-L] [filespec]
Like `dir' but displays the file list sorted vertically by filename,
and if the `-l' option is given, with file sizes (in K). It also uses
an 80-column-friendly layout if the console output is going to the
serial port or printer, unlike `dir'.
ZCN's `get file size' function is fairly slow, and so is this command
if you give the `-l' option.
In previous versions of ZCN, `ls' would use italics for .com and .sub
files. If you'd like to have that behaviour back, you can patch ls.com
as follows, but type carefully:
get 100 ls.com
poke 102 1
save 4 ls.com
Bugs: It sometimes displays fewer columns than you might expect.
***** MD5CPM [file1 [... fileN]]
Computes an MD5 message digest compatible with other implementations,
such as "md5sum" from GNU coreutils. The output can be used as
essentially a fancy checksum for files, but with a much lower risk of
failing to detect a corrupted file than with a simple checksum or CRC.
Wildcards like "*.*" are supported, as is output redirection - to
redirect output to the file foo, use ">foo".
There are various issues:
- md5cpm always just shows the result for each file. There is no
equivalent of md5sum's "-c" option to check against previous
results, you must do so manually or with another program.
- It's compiled with Hitech C, and is slow and large.
- As CP/M 2.2 and ZCN's files are always a multiple of 128 bytes long,
you can get misleading results if e.g. you transferred a file from a
computer that uses exact file sizes. So make sure you're comparing
what you think you're comparing. :-)
- md5cpm always reads files as binary, so if you convert the
line-endings on a text file it will differ. Also, anything after a
^Z (soft EOF) is still counted as part of the file.
- This text is really just quoting the man page. :-)
The ZX0-using version in `support/zx0alt' is far smaller than the
uncompressed version, and will usually be preferable.
NB: MD5 should not be used for anything involving security. That
should be completely irrelevant in this context, but I may as well
mention it for anyone that happens to be unaware. It remains useful
for detecting accidental/random corruption and non-malicious changes.
***** NCSPEED [-AHIS]
Test the effective speed of the NC's Z80 CPU. It should take just over
a minute, and a single run will give a fairly approximate result (only
accurate to within 0.075MHz or thereabouts).
The options are `-a' for a RAM test, rather than trying to use a blank
area of ROM, `-h' for usage help, `-i' to test with interrupts enabled
(this is mostly for testing ZCN's interrupt overhead and won't usually
be of interest), and `-s' to test in active screen memory (this forces
a RAM test and will result in a blank screen during the run).
(If the screen memory test option is chosen, the test will only run in
screen memory for about half of the time on the NC100/NC150. For a
better screen memory test you must run on the NC200.)
For increased accuracy, you should average the result of many runs - I
would recommend at least 30. But it does mean being very patient,
doing some maths, probably writing a SUB file to keep running it,
maybe capturing output as redirected over the serial port... to find
out that it's about 4.606MHz, which I can just tell you here.
(To be fair, that isn't necessarily the whole story. See the "Speed"
section below for more.)
***** NCTEST
Test which model of NC you're using. It also tests for some telltale
signs of the NC being emulated.
Usually of course, it will be obvious to you which model of NC you're
using. :-) But the result of `nctest' is (slightly) more likely to be
of interest if you're using an emulator.
Note that one test will change any clock seconds setting on the
NC100/NC150, though `nctest' should be able to restore that after.
Also, you shouldn't turn the NC off while the program is running, as
one test can potentially give an inaccurate result if you do (though
in practice this should be very rare).
***** 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.
Bugs: Only sorts correctly when there are exactly two directory blocks
(but it does at least abort if there's less). Drives formatted by ZCN
always have two, so this is unlikely to be a problem. :-)
***** PLAY1B/PLAY2B (removed in ZCN 1.4)
These were worse-sounding versions of `play4b'. Yes, you could play
longer samples, but you'd never want to because they sounded awful.
***** PLAY4B filename
Play 4-bit sample files at about 8kHz. You can generate these samples
from an raw 8-bit unsigned source on a Unix box with the mk4bit filter
(C source in the `utils' directory). Some sample files (in both
senses) are included in `support/samples'.
The sample file must fit in memory, which limits the maximum length to
just 11 seconds or so.
Keyboard input is ignored while the program is running. However, on
the NC100/NC150 you can use the power on/off button to abort playback.
The sample playback effectively uses pulse-width modulation on an 8kHz
tone, and the NC speaker will still convey that tone to some degree
despite having predictably terrible frequency response. While this
tone is always audible, you're likely to find it much more noticeable
on an emulator.
Bugs: the sample is actually played at 8010Hz, which is as close to
8kHz as the Z80's instruction timings will allow (while running faster
rather than slower).
***** MAN [page]
ZCN's 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.dat' file from
the `bin' directory on your A: drive in user area 0. This archive
contains a compressed version of all the help files (or as they're
more usually known, man pages).
Since the original source for these man pages is many simple text
files, they're also available in the `man/pages' directory.
***** 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 on the NC100, 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' (except on the NC200), so you could e.g.
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 any text editor which 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'
itself:
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' file (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.)
***** SLIDE
A slide-rule simulator, as inspired by the shape of the NC100's
screen. 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.
(Alternatively you can use s/d/k/l, with or without shift. These keys
may be more sensible on some keyboard layouts.)
Having a literal cursor not operated with literal cursor keys is one
of my more hilarious design decisions.
Since nobody uses slide-rules any more, here's a very simple
explanation of what they are, and how to use one for simple
calculations:
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. Though accuracy can be an issue with real slide
rules too.)
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,
though.
If you emerged from all that thinking "but why would anyone use a
slide rule?", ask yourself why you'd use an Amstrad computer. :-)
***** SPELL filename
Interactively spellcheck a (text) file (uses the ROM spellchecker).
NB: This doesn't work properly on NCs without English dictionaries; it
can check word spellings, but all word lookups will fail. Also, it
limits replacement words to ASCII only.
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
auto-lookup.
`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
not.
***** 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.
Unlike `spell', this should work on all NCs, though any word lookups
using sharp-s won't be displayed correctly even after running `keyb'.
Also, the word to check may have to be approximated using ASCII only.
***** STAT
This emulates almost exactly the behaviour of the old internal `stat'
command (since mostly replaced by `df' and `k3'). For example:
Sys upgrd spc: 121 bytes
Max prog size: 46k
Free on drivs: A:=91k B:=156k C:=213k D:=251k
The second line is like `k3', the last line is like `df', but the
first line is not available from any other command. That said, the
first line isn't something you'd ever really want to know...
Bugs: It creates a `$$$.sub' file to run `df' etc., so it gives a
slightly incorrect result for free space on the current drive. :-)
***** SUBMIT filename [* | [arg1 [arg2 ... ]]]
See the section `SUB files with parameters' above for details of this
command.
***** TIME
Display the time as reported by the NC's real-time clock. You should
previously have set it with `timeset' (see below) or via the ROM OS.
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'.
NB: The NC200 gets February wrong on even-numbered years, see below.
***** TIMESET [[YYMMDD] HHMM[SS]]
Set the time (and optionally the date) of the real-time clock. ZCN
only currently uses the time/date for `cal' (where having it set is
optional), `time', `rrxfer' (optional), and `dclock' (which is
essentially just a prettier version 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 the time (in 24-hour format padded with zeroes), 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 380119 2112 (set date to 19th Jan 2038, time to 9:12 p.m.)
The 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. :-) `timeset' itself is
slightly more limited, as years 90-99 are still treated as being
1990-1999, meaning that the latest supported year is 2089.
Since ZCN has only existed since 1994, ZCN treats all dates in 1990 as
`clock not set'. The reason for this is that if the clock isn't set,
the ROM starts it from zero (i.e. 1st Jan 1990) each time you turn on.
NB: The NC200 gets February wrong on even-numbered years, when
advancing from the 28th of February. The real-time clock hardware used
(or perhaps cloned) was originally intended to work with years 0-99
meaning 1900-1999. Amstrad/Arnor used this and added 1990 instead,
like they did on the NC100. But with this RTC hardware there is
apparently no "leap year digit" setting, so adding 1990 gets leap
years wrong because the usual four-year cycle is out of sync. So
overall the NC200 thinks 1990 was a leap year, 1992 wasn't, 1994 was,
1996 wasn't, and so on - meaning it drops/adds a day every two years.
(And yes, that does mean the RTC gets 1900 wrong even when used as
intended. Or that'd be true of the NC200's version at least.)
Now, this isn't as bad as it could be - the RTC also lets you manually
set the date to 29 Feb on any year, which then will rollover to 1 Mar
successfully. I originally intended to include the option of a
different year offset in ZCN to fix the issue, but when I noticed you
could just manually correct the date like this, it didn't really seem
sensible. Most people will probably still be using the ROM OS to some
extent, and would presumably rather be inconvenienced every two years
rather than *every time* they switch between ZCN and the ROM OS.
Ah, the joy of the arguably-least-bad option! :-)
***** ZAP (removed in ZCN 1.4)
(`makezapd' was also removed.)
zap was a simple graphical frontend which would run .com files. It
wasn't something I really used personally, and it was already looking
excessively awkward to get it into any sort of sensible state for 1.4.
So when I discovered that there had also been an intermittent
disappearing-icon bug since day one, zap got zapped.
***** ZCNBROT (removed in ZCN 1.4)
This was a simple program to plot the Mandelbrot set. Realistically,
it was much too slow and limited to be a sensible inclusion.
***** ZCNPAINT
A mouse-based paint program. You need a Microsoft-compatible serial
mouse to use it, which is now very limiting - these are rather less
ubiquitous than they used to be. Also, it doesn't work on the NC200.
Be warned that zcnpaint is incomplete, and there are 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 Enter 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
this:
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
:g0
A>era foo
After that your picture would be saved as `mypic'.
There are only two keyboard shortcuts in zcnpaint. 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
allowed.
- 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. Five patterns are
available.
- 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.
***** ZCSOLI [termtype[-]]
zcsoli is a one-player card game, playing the game usually called
Solitaire, Patience, or Klondike. It uses the (easier) 1-card draw
variant. This version defaults to using a display suited to the NC
model it's running on.
Note that on NC100/NC150, the usual play area has to be split in half,
with what would normally be the upper half shown on the left, and the
lower half shown to the right of that. This can be a bit confusing.
And even on NC200, the play area is slightly truncated.
If `termtype' is specified, it selects an alternative terminal type to
use. On ZCN, you'd probably only want to use this if output is
redirected to the serial port. The type is a single digit - 0=ZCN
(NC100), 1=VT100, 2=VT52, 3=ZCN (NC200), 4=VC404, 5=ADM-3A. If this is
followed by `-' then the onscreen instructions aren't shown.
The aim of the game is to get all the cards in each suit onto the
matching ace pile, in ascending order (with aces low) from ace to
king. To help you do this, you can move cards onto/between the seven
main piles of cards which are dealt when you start. Any face-up cards
on those must be in descending order (K, Q, J, 10, ... 2), and have
alternating red/black suit. When moving cards between the main piles,
you can only move entire runs (every face-up card on the pile). When
moving to a main pile which has no cards at all, you can only move a
king there (or the top card of the run you're moving must be a king).
The main card piles are shown at the top (growing downwards), with the
deck (and turned-over cards from it) in the bottom-left and the ace
piles to the right of that. Initially you can't see the ace piles, as
you have to move an ace to them before there'll be anything there.
The top of each card is indicated with two characters, the first being
a number or A/T/J/Q/K for ace/ten/jack/queen/king, the second being
H/D/s/c for hearts/diamonds/spades/clubs. While no colour is used in
the display, runs of cards can easily be found just using the
uppercase/lowercase display of the different suits.
When the game runs, it initially prompts you to press a key to
continue. This is to help set up the random number generator.
Once the game starts, the keys are:
Enter (CR) - turn over a card from the top of the deck. If the deck is
empty, it flips the turned-over cards back onto the deck first.
1 to 7, or D - pick a card (or run) to move from the numbered pile or
the deck (actually the topmost turned-over card). Once you've pressed
this first key, you then choose where to move it, with 1 to 7 and A
meaning either the numbered pile, or the relevant ace pile. If you
attempt a move which isn't allowed, it'll be ignored.
Control-R - restart, abandoning the current game, and reshuffle/deal
from scratch.
Control-L - redraw the screen.
Control-C - exit the game.
If you win, you get a congratulatory message - press a key at
that point to start another game.
***** 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.
`zrx' can also be useful simply due to the size - it only takes 1k.
There is no analogous `zsx' to send a file.
Note that there is no abort key. To quit before it finishes, do a cold
boot of the ZCN in memory by turning the machine off, then holding
both shifts while turning it on again.
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).
On the NC200, zselx's screen-redraw is very slow - try to use
page-based movement commands like ^f and ^b where possible.
[The remainder of this description is based on the 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.
I currently recommend that zselx only be used on ZCN, as I believe
there are some issues when running on real CP/M.
It's a conversion of my original Unix/Linux version, modified to use
internal cp/mv/rm/more-like `commands'.
Zselx was inspired by a useful program for MS-DOS called `co'. It's
essentially a clone of that, 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
popular.
****** 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/Linux 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 Enter, 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.
[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 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 files.
****** 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 builtin support for a few terminals. These are:
Type Terminal
0 as defined in patch area
1 VT100 (default)
2 VT52 (PCW, +3, etc.)
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.
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 - or on the NC200.
Doesn't support `co' option 5, `mark blank'.
***** ZX0COM.BIN
(Most people can freely skip this - it's just an explanation for those
that might find the file useful.)
Not an external command as such, but a simple loader which allows you
to run .com files in .zx0 format, as compressed with the ZX0
compression program (at least for version 2.2 included in the `man'
directory as zx0full.c). You simply concatenate zx0com.bin and the
.zx0 file together into a new .com file. So on Unix/Linux for example,
you could do "cat zx0com.bin old.com.zx0 >new.com".
Note that the .zx0 file itself MUST be 16384 bytes or less, and it can
be risky to use if the original .com file was more than about 30000
bytes. The loader does not know the length of the .zx0 file, so you
must ensure *yourself* that these limits are met.
You should not use this for programs you want to patch afterwards, nor
for programs which directly rely on the contents of the .com file in
any other way. It can be hard to tell which programs do the latter, so
unless you know for sure there can be an element of "just try it and
see if it crashes" involved. If this sounds like something you'd
prefer to avoid, well, that is certainly an option. :-)
While .zx0 files cannot reasonably be made on a CP/M system - the CPU
requirement for the compression side is far too high for this - it's
easy enough to do on any relatively modern computer.
A final note - if you plan to use zx0com.bin-based .com files on any
non-ZCN systems, bear in mind that the BDOS must be no lower than
B900h (i.e. the TPA must be >=46k, roughly), and that programs will
always exit with a warm boot.
**** Third-party programs included with ZCN
I've included several pre-patched versions of third-party programs
such as QTERM, TED, 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
probably try them out.
** Limitations and Bugs
This section is mostly concerned with ZCN itself, but also covers
the NC's hardware to some degree.
*** Screen
ZCN only has a 10 or 21-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 NC's keyboard hardware is less-than-perfect (see the top of
src/keyread.z for a more detailed explanation), and ZCN tries hard to
fix the problems with it. I'd say it does better than the ROM does, at
least.
Here's a more low-tech explanation of what the problem is than the one
in keyread.z. Given the nature of the NC 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. :-)
Probably the only place in ZCN where non-ASCII keyboard input does
anything sensible is in `bbcbas'. (And even there, I think it's only
properly supported by GET.)
*** 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, but the `format'
command always formats drives so they have 2 directory blocks (for a
maximum of 64 files). `optdir' only sorts the dir correctly when there
are exactly 2 dir blocks. `runrom' also assumes 2 dir blocks, and
could corrupt memory card data if there's only one (though this could
only actually happen if the boot block is modified and the first data
block contains "RUNROM RAM").
If the memory card is set to read-only (presumably using a physical
switch on the card), this is almost totally ignored by ZCN, with only
the `format' command checking for it. 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 e.g. pretend write
operations have worked.
Floppy disk drives are not supported by ZCN itself. ZCN's stateless
disk I/O design probably makes any reasonable native support
impossible.
*** Speed
ZCN's file operations have turned out slower than I had expected when
I started writing it. (This is mostly because they're deliberately
stateless; you can change cards at any time.) I think the speed is
bearable, but it's very slow for RAM-based storage. 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. That still isn't incredibly quick, but I doubt I'll
get it going any faster.
As for the CPU's speed, the NC100 has a Zilog Z84C0006FEC CPU which
seems to have an effective speed of 4.606MHz, at least according to my
testing many years ago on a single machine.
I haven't tested an NC150, but the PCB has the same CPU as the NC100
and the NC150 has much in common with that, so it seems likely that
it'd run at the same speed.
The NC200 doesn't seem to have a separate Z80 chip at all, instead it
presumably has the Z80 or clone of some description implemented within
the large chip labelled "Amstrad" - this approach seems very similar
to that used in Amstrad's PcW16. The way flag bits 3 and 5 respond to
SCF suggests that it behaves like a CMOS Z80 (as the NC100 has),
though in this case it seems likely to be using an implementation from
NEC. I tested an NC200's effective CPU speed in 2022 (averaging one
hundred runs of `ncspeed') which gave a result of 4.629MHz, which
might suggest a small difference from the NC100, or... might not. With
a difference of less than 1% from the NC100 result, and with the
hardware being nearly 30 years old, I suspect this could be clock
drift due to aging. Still, it's a pretty similar result either way.
The effective Z80 speed can easily be measured on all models, by
either running the large blocks of NOPs so helpfully left wasting
space on most ROMs :-) or just using RAM to do the same. (ZCN's
`ncspeed' can do both.) It doesn't seem to make any obvious difference
to the speed whether you use RAM, or ROM, or run the test in active
screen memory.
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 97.5% of full interrupts-off
speed if no keys were pressed during a given interrupt, otherwise it's
about 78.7%. (In the old `tight interrupts' mode (more on this later),
it's about 86% whether a key is pressed or not. Yes, this is
sub-optimal, and no, there's nothing I can really do about it.) This
makes ZCN slightly quicker than the ROM software if no keys are
pressed (the ROM manages about 94.6% 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 necessarily a fair comparison.
(I should note that the dead key support has probably made
key-handling slightly slower since I wrote the paragraph above.)
*** Miscellaneous
There are no timeouts when sending serial/parallel data, as mentioned
in the "Warning about using the Serial and Parallel ports" section.
This can result in ZCN effectively crashing.
The NC200 support still isn't as complete as the NC100 support. This
is always likely to be the case - ZCN *was* designed specifically for
the NC100, after all.
Similarly, the NC150 support is also slightly lacking. Although much
of the NC150's hardware is more like the NC100 than the NC200, the
differing ROM and 128k of RAM are enough to cause issues in some
cases.
If you read a file into the file being edited (with ^K R) in VDE, 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 the byte at 0066h.
(There's a related problem which can crop up (rarely) with QTERM's
YMODEM batch-sending.)
When the NC is turned off and on, any serial input in the buffer is
lost. On the NC100/NC150 this is probably the only reasonable
approach, due to the NMI for poweroff being non-maskable - one can
happen while the input buffer's state is only partly changed, so
resetting the buffer is the only way to ensure a consistent state (and
even then it's more involved than you might think).
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,
and `submit' needs to make a `$$$.sub' file to work), but is still
weird.
** CP/M Compatibility
ZCN aims at close CP/M compatibility - I believe my original goal was
to get the majority of freely available programs running, and I'd say
ZCN does that and more. But it's not perfect, and there are certainly
issues. This fairly technical section describes what facilities are
provided.
*** BDOS Functions
The following BDOS functions are provided, and are believed to be
working correctly:
0 to 26, 29, 32, 33, 34, 36, 37, 46.
These ones work but have known problems:
30 - claims success, though ZCN does not support file attributes.
35 - gives incorrect results for files with holes.
40 - same as function 34; it doesn't actually do the zero fill.
These are not implemented:
27, 28, 31.
27 and 31 basically expose CP/M internals to programs. They aren't
necessarily easy to support when the OS's internals don't work like
CP/M. The lack of these does cause problems, in some cases - see
"Non-working Programs" for details.
28 is a write-protect-disk function, which could probably be supported
but has never seemed necessary in practice.
Functions 38, 39, and >=41 are undefined under CP/M 2.2. Function 46
in ZCN acts like CP/M 3's free-disk-space function.
There are some additional (ZCN-specific) functions; a few are
mentioned later. Full descriptions of all are given in `zcnprog.txt',
but the ultimate reference is `zcnfunc.z' in the `src' directory. So
you can always 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 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 1:
Pressing the on/off button when the NC100/NC150 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 - ZCN goes to considerable lengths to try and deal
with the problems this causes. This is largely successful, but
sometimes you will see a filename printed with the 2nd char. of the
extension appearing as a lowercase `w'. 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.
(ZCN allows for all the above on the NC200 too, partly to remain
consistent with the NC100/NC150 behaviour.)
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'.
- (NC200 only) Handling the poweroff button.
See the `Tight Interrupts' 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. Such as, um,
`bbcbas' for example. :-)
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 2.2-ish 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. (The NC200 version uses a paging scheme to get at the
screen, but the normal memory layout is the same.) 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 programs.
** 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 is intended
to make programming in Z80 assembly for ZCN and CP/M easier.)
*** The Screen
The NC100/NC150'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.
(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 (on the NC100) 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 (on the NC100)
they are temporarily used while writing a screen dump).
Under ZCN on the NC100, 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.
Note that drawing graphics on the NC200 under ZCN is difficult - you
either need to page the usual NC200 screen memory into the 4000h-7FFFh
space, or reserve 8k in the TPA to use as a screen and regularly do an
OUT to port 00h to change the screen address (in case a poweroff
happens, which would reset it). If you really want to try this, see
utils/bigvfont.z and utils/dclock.z to get the basic idea of both
approaches. (Though arguably, dclock uses a sort of hybrid approach,
due to copying the date text from the usual screen.) Yet another
method is to use a custom font and draw graphics that way (like
cpmtris does on the NC100), which is slower and more limited but has
the advantage of having basically the same code usable on all NC
models, as long as you account for the differing screen sizes.
*** Tight Interrupts
In (for example) an action game, you might 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. If the IRQ mask is set to allow `keyboard' interrupts (really just
a 100Hz interrupt) through, and it usually is, you have to acknowledge
them when they happen to avoid hanging the machine.
In theory, 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 -
so this mode actually ends up being *slower* if no keys are pressed.
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' (mainly) and `keyread.z' (for interpreting data from the
keyboard ports) to see what's required. 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 mode.
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:
ld c,130
call 5
ld (krawmap),hl
...
krawmap: defw 0
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 etc. 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
...etc.
You could do this more 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
...etc.
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)
stloop:
ei ;make sure interrupts are on!
cp (hl)
jr z,stloop
Alternatively, 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 Button
The power button on the NC does not directly control whether the
computer is on or off.
On the NC100/NC150, 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
around.
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 should be unlikely to happen in
practice. :-)
On the NC200, the power button generates a normal interrupt instead,
so there's no real reason it couldn't run a perfectly normal CP/M
installation with a suitable BIOS. In ZCN though, all the same stuff
is done as on the NC100, to allow for an NMI that will never happen.
This clearly isn't ideal, but the reality is that quite a bit of code
depends on the old NC100-ish way of working in one way or another, so
in practice it's unlikely to change.
*** Sound Hardware
The NC100's sound hardware gives simple two-channel sound (of a very
harsh/distorted kind). There's 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, nciospec.doc gives a formula that can rearranged
to value=307200/frequency. Here are some example values - to my
considerable surprise, they're almost the same as the old values I
worked out by ear. :-) These are for the octave above middle C; if
middle C is C4, this one starts from C5. You can of course double
these values to move down an octave, or halve them to move up an
octave.
(As you might imagine, this is for A440 tuning - so the A listed for
this octave is at 880Hz.)
Value Value
Note (hex) (dec)
---- ----- -----
C 024B 587
C# 022A 554
D 020B 523
D# 01EE 494
E 01D2 466
F 01B8 440
F# 019F 415
G 0188 392
G# 0172 370
A 015D 349
A# 0149 329
B 0137 311
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 something like 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 `play4b'
program uses this technique.
*** Battery levels
If you want to test battery levels yourself for some reason, on the
NC100/NC150 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 on the NC100/NC150 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.
On the NC200, the bits used differ:
If bit 2 is set then the main batteries are low.
If bit 4 is *zero* then the PCMCIA card's battery is low (as above).
If bit 5 is set then the lithium backup battery is low.
Other things indicated by port A0h on the NC200 (that I know of) are:
Bit 0 is set when main batteries are too low to use the floppy.
Bit 7 is set when there is no card in the slot (as above).
(The NC200's printer-busy is on bit 0 of port 80h.)
*** Memory Card and Ramdisk Format
The general format of a memory card or ramdisk 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.
The ramdisk is limited to drive A: only, and is 48k on the NC200
(which uses RAM pages 45h/46h/47h) and 64k on the NC150 (which uses
RAM pages 44h/45/46h/47h).
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.
From ZCN 1.4, the `format' command preallocates exactly 12 system
blocks on drive A: of a memory card (which are always reserved,
whether or not the card is ever made bootable), and zero on all other
drives.
Ramdisks cannot be booted from.
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 (54 bytes)
cf1zero 64 64 bytes, set to zero
cf1boot 128 boot program, if bootable (128 bytes)
cf1rrcode 256 256 bytes reserved for use by `runrom'
cf1fnx 512 Function-X-style boot program, if bootable (128
bytes)
cf1xtra 640 reserved (128 bytes)
cf1pairs 768 256 bytes reserved for use by `runrom'
Only the first logical drive on a card can be booted from.
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
think.)
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. 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. Using the
usual CP/M 3 (`plus') approach works, though. The AUX: functions from
CP/M 3 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 (while computer is on)
e600h-e6ffh used to store old contents of b300h-b3ffh by powrhndl.z
e700h also used for IM2 jump table
e701h-e7e3h extra font data, if installed by `keyb'
e7e4h-e7e6h reserved
e7e7h-e7e9h jump to interrupt handler
e7eah-e7fbh extra font data, if installed by `keyb'
e7fch-e7ffh reserved
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 due to paging)
ea00h-eabfh internal stack used by bdos functions
eac0h-ecffh font data (`fontdata' set to ea00h)
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 (on NC100/NC150) or a reserved
4k area (on NC200) from F000h to FFFFh.
The addresses of the font data (at EAC0h) and of the NC100/NC150
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 address of the screen data
currently displayed can be changed - see `nciospec.doc' in the
`support' directory for details.)
*** 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
Non-Maskable Interrupt 2 4
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. Similarly, an NMI
during a normal interrupt will use the interrupt handler's 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
I think the GNU GPL is so widely used at this point that there's no
point reassuring people that it's fine, as I previously tried to do
here. Billions of people are using GPL software to some degree every
day, whether they know it or not.
The FSF do still have an FAQ for the older GPL version I prefer, at
https://www.gnu.org/licenses/old-licenses/gpl-2.0-faq.html - it's
worth a read if you happen to have any queries about the GPL.
One of the old notes I had here is still worth keeping, I think - that
source files in ZCN tend to have old version numbers if they haven't
been changed since that version. This is intentional, as the file
date/time stamps should then better reflect how long it's been since I
changed the file.
Look at the top of this file or do `ver' (which gives a result derived
from src/start.z) to find the true version number.
** 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. :-) Most people can safely skip this section.
You will need a Unix/Linux box to do this.
(Note that e.g. running Linux under modern Windows versions shouldn't
be too hard, if necessary.)
You need the free Z80 cross-assembler `zmac' to assemble ZCN. To build
it, you need gcc and bison (or equivalent). Various versions of zmac
are available, but I suggest using version 1.3, which comes with ZCN
in the `zmac' dir.
As well as zmac, you need:
- GNU make
- cpmtools (required to build memory card images)
- mtools (required to build NC200 boot floppy)
- Various standard POSIX utilities (e.g. awk, dc, truncate)
(It's not unheard of for e.g. some Linux distributions to lack "dc" by
default; there should at least be an installable package available.)
If you want to actually make a ZCN distribution zip file, you'll need
the portable `zip' program in order for the top-level Makefile's `make
dist' to work.
At the time of writing, cpmtools is here:
http://www.moria.de/~michael/cpmtools/
Since I had some trouble accessing that page when I checked
previously, I'll also just note that there's a Debian cpmtools
package. And even if you don't use Debian, that means the original
source they used can be downloaded here (download the most recent
cpmtools*.orig.tar.gz file):
http://deb.debian.org/debian/pool/main/c/cpmtools/
As for mtools, that should be available here:
https://www.gnu.org/software/mtools/
While ZCN's build process does require a version of mtools supporting
the "::" drive specifier, that's been supported for years now and
shouldn't be a problem.
Though some programs in the `support' directory do come with source,
they are not built as part of ZCN's build process, and - with the
obvious exception of TED, where it is required by the licence - the
source may or may not be buildable or an exact match for any .com
files.
* Acknowledgements
** Programs, routines, etc. by others
All of the programs in the `support' directory were (either entirely
or mostly) written by others. Details are primarily in
`support/README', and each program's documentation.
`cal' is a Z80 port of a public domain `calend' in C by Martin Minow,
posted to mod.sources in 1986.
`expr' is a rather hacked-around port of a C original by Erik
Baalbergen, posted to comp.os.minix in 1987.
The NC200 floppy disk boot code and boot disk setup is as
written/devised by David Given for FUZIX, with only minimal changes.
`md5cpm' is really just a tiny wrapper around the public domain MD5
implementation by Solar Designer (Alexander Peslyak).
The 4-bit samples in `support/samples' (playable with play4b) are all
converted excerpts of public domain music by Kevin MacLeod, from
freepd.com.
The random number generator routine in `zcsoli' is based on the C
original in George Marsaglia's "Xorshift RNGs".
The random number generator routine in `cpmtris' (and zcnlib's rand.z)
is based on the C++ original in Chris Doty-Humphrey's PractRand.
`man', `manpages.dat', the `zx0com.bin' loader, and all binaries in
the `support/zx0alt' directory use Einar Saukas's ZX0 format for
compression/decompression, via zx0 and the standard Z80 ZX0
decompressor. The (BSD) licence for ZX0 is included below, so if you
haven't read the word "TORT" all day, it's time to fix that. :-)
*** ZX0 licence
BSD 3-Clause License
Copyright (c) 2021, Einar Saukas
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*** expr licence
(The Minix licence for old versions applies, which was retrospectively
changed to the equivalent of BSD 3-clause in 2000.)
Copyright (c) 1987,1997, Prentice Hall
All rights reserved.
Redistribution and use of the MINIX operating system in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Prentice Hall nor the names of the software
authors or contributors may be used to endorse or promote
products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*** fish licence
Copyright (c) 1990 The Regents of the University of California.
All rights reserved.
This code is derived from software contributed to Berkeley by
Muffy Barkocy.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
*** helvR10.bdf and dcdigits.z licence
(This licence is for both utils/helvR10.bdf and utils/dcdigits.z, as
used by `bigv' and `dclock' respectively. Perhaps for DEC you could
these days read HP, at least for the five remaining minutes until a
single company owns literally everything. :-))
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.
** 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
hacks.)
Cliff Lawson at Amstrad (many years ago) 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 old Linux DOS emulator `dosemu' which I used to run ZSIM. :-)
Michael Bischoff for his `cpm' emulator, which I used quite a bit some
years ago, and for posting me CP/M docs. (And for not yelling at me
when I bought a CP/M manual soon after.)
Steven Flintham for getting an up-to-date version of ZCN online for me
back when I didn't have net access - and for (long 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 section.
Ian Miller for lots of NC200 testing. And for some cool `cp/m inside'
badges. :-)
Scott Chapman for giving me an NC200 (in 2022!).
Michael Perkonigg for the original version of the German keyboard
layout diagram, which was also the original starting point for the
German keyboard support.
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: Nethack, Tetris
Attack, Wipeout 2097, Tekken 2, DOOM, Tempest 2000 (and X3), Sensible
Soccer, V-Rally, Super Bomberman 3, Stunt Race FX, Elite, Minetest,
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 CD audio) by Imagitec Design
(usually credited to any or all of Ian Howe, Alastair Lindsay, Kevin
Saville, and Julian Hodgson)
"Victor" by Victor
"Wish" by The Cure
"PXR5" by Hawkwind
"Warrior On The Edge Of Time" 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
owners.
* Epilogue
The observant will no doubt have noticed that, so far, 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. :-)
As for `zgedneil', 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. 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 - and if I keep saying that for long enough, it might
even be true this time. :-)
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.
* Getting ZCN
As you'll probably know by now, ZCN is available here:
https://zgedneil.nfshost.com/zcn.html
Does it make sense to mention that at the end? Probably not. But it's
tradition at this point, so here it is.
* Contacting the Author
Feel free to contact me if you have any queries or problems with ZCN,
or, well, any reason really. :-)
You can email me at zgedneil@gmail.com.
Share and enjoy!
-Rus.