* for
Emacs: -*- mode:indented-text; mode:outline-minor -*-
ZCN v1.2 - (c) 1994-1999 Russell
Marks
A free CP/M-like
operating system for the Amstrad NC100.
* License
This
program is free software; you can redistribute it and/or modify
it under
the terms of the GNU General Public License as published by
the Free
Software Foundation; either version 2 of the License, or (at
your option)
any later version.
This program is distributed in the hope that it
will be useful, but
WITHOUT ANY WARRANTY; without even the implied
warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for
more details.
You should have received a copy of the GNU General
Public License
along with this program; if not, write to the Free
Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA.
[The GNU GPL is in the file `COPYING'.]
*
About ZCN
ZCN is an alternative operating system for the NC100.
Features
include:
- a high level of CP/M compatibility
-
fast switching between ZCN and the ROM software, and file transfer
between the two
- can run BBC Basic
(from ROM) as if it were a native ZCN program
- command processor (shell)
with many internal commands
- many external commands and third-party
programs
- optional online help (using `man')
- 46k free for programs
to run in
- terminal emulator with 120x10 text resolution
- keyboard
handler with 128-char keyboard buffer
- context saving while power is
off
- support for the serial port at speeds up to 19200 baud
-
printer (i.e. parallel port) support
- auto power-off after a given idle
time
- warnings when main, backup, or memory card batteries are low
-
console redirection to serial port or printer
- washes whiter than other
powders
ZCN is modelled quite closely on the CP/M operating system
common on
8080 and Z80 machines in the late 70s and early 80s. (It is
most
common in the UK today on Amstrad PCWs.) I decided to do this as
there
is a great deal of public domain and other zero cost software
for
CP/M, including text editors, simple C compilers, Z80 assemblers,
a
few games, etc. CP/M is also, in my opinion, well suited to running
on
small Z80 systems. ZCN's CP/M compatibility is sufficient to run
most
CP/M 2.2 programs.
** Should I use ZCN?
You
should probably consider using ZCN if you like the idea of a
portable CP/M
box, or want to use the NC100 as something a bit closer
to a `real
computer'. These are the two reasons I originally started
writing
ZCN.
** Warning!
If you want to still be able to
use the built-in ROM software without
losing any of your current data, you
*MUST* transfer and run the
`rrinit' program before trying to run ZCN. If
you don't, you'll lose
any data held in the 64k of internal memory! (This
means losing not
only any files in both the upper and lower memory, but
also any
configuration.)
If you don't care about the ROM
software, or don't care about losing
currently-held data, you shouldn't
bother with `rrinit'.
(There's more on `rrinit' at the appropriate
point below.)
** Requirements
ZCN needs the
following to install and run successfully:
- An Amstrad NC100
Notepad
- At least one PCMCIA memory card, which will need to be
reformatted
in ZCN's format
-
A computer with a serial link to the NC100, and the
capability to send files using the XMODEM
protocol
If you want to save the data currently in the internal
memory, the
memory card must be at least 128k (64k of it will be used to
save the
memory).
You will also need a basic knowledge of using
CP/M, though a
reasonably capable MS-DOS and/or Unix user should be able
to get along
ok. (Hey, it worked for me... :-))
*
Installing ZCN
The installation guide below assumes you are
installing from a Unix or
MS-DOS machine. It should be clear what to do on
other machines
though; you just need to know how to XMODEM a file across,
and how to
send a plain ASCII file. Normally the easiest way is to use a
serial
comms program of some sort.
** Getting ZCN up and
running for the first time
*** Saving your existing data
[If
you don't care about using the ROM software, or don't mind losing
all the
data in the internal memory, skip ahead to the next section,
`Booting ZCN
via a Serial Link'.]
ZCN uses the NC100's 64k of RAM as more normal
computers generally use
RAM - as an area to load programs into, and an
area to use for
temporary workspace, etc. Unfortunately, this is not
compatible with
the way the built-in software works, so you'll lose all
your existing
data in memory unless you save it first. `rrinit' is a
program which
lets you save your data like this. (You'll be able to
restore it later
using `runrom'. More on that later on.)
To run
`rrinit', you'll need a memory card of at least 128k in size.
It should
probably be the card you intend to copy ZCN onto, but it
doesn't have to
be. Bear in mind that the card will be reformatted in
ZCN's format, and
any data currently on it will be lost!
You must also have at least
one file stored in memory on your NC100,
as the ROM software doesn't let
you do serial file transfers
otherwise. (If you haven't got any files in
memory, just create a
small file with the word processor. It doesn't
matter what's in it or
what it's called, just that it's there.)
First
you need to setup the serial link. You should set the baud rate
to 2400
baud on the `remote' computer, as transfers seem to be a bit
hairy (for
the ROM software at least) at higher speeds.
After that, *make sure
there isn't any memory card in the NC100's
slot*, then do the
following:
Key Reason
--- ------
Function
+ S go to terminal program
Menu,
down*3, left*2, Stop use 2400
baud
(you may
need more or less lefts,
depending
on the current setting)
<type a few characters on the NC100 and
`remote' computer to check
the
link is working ok>
<start XMODEM send (or `upload') of `rrinit.bin'
on `remote' computer>
Stop quit
terminal program
Function + L load
document
Menu, T, M, rrinit, return XMODEM
receive `rrinit'
<wait for transfer to finish>
Stop return to file
selector
<now insert the memory card>
Menu, F, <possibly
Y>, Stop format card (answer `Y' if
it prompts you)
<make sure the `rrinit' file is the
currently-highlighted one>
Menu, T, P, Stop write rrinit to memory card
Stop exit file selector
Function + X run rrinit
[NB:
`rrinit.bin' is in the `bin' subdirectory.]
Almost immediately after
you do the function-X, rrinit should say
"Snapshot written - press
Stop". Pressing Stop then returns you to the
NC100's main menu.
Now
you should be ready to run ZCN, so here goes...
*** Booting
ZCN via a Serial Link
[If you are upgrading an existing version of
ZCN, skip ahead to
`Installing a new version using an old one', which will
be rather more
appropriate.]
First you need to setup the serial
link. You should set the baud rate
to 2400 baud on the `remote' computer,
as transfers seem to be a bit
hairy at higher speeds. (ZCN itself can cope
with file transfers at up
to 19200, but the ROM software seems to be more
picky. So for this
transfer, it's best to stick with 2400.)
Now
you should cold-boot the NC100. Do this by turning it off and,
while
holding down Function, Stop and `<-Del', turning it back on.
Next
you should do the following:
Key Reason
--- ------
Function + S go to terminal program
Menu,
down*3, left*2, Stop set speed to 2400
baud
<type a few characters on the NC100 and `remote' computer to
check
the link is working
ok>
<start XMODEM send (or `upload') of `zcn.bin' on `remote'
computer>
Stop quit
terminal program
Function + N, x, return create
junk document
x put
junk in it
Function + L load
document
Menu, T, M, tmp, return XMODEM
receive `tmp'
<wait for transfer to finish>
Function + B enter basic
"*LOAD
TMP 6000" load system (omit
the quotes :-))
"CALL &6000" start
ZCN (ditto)
[NB: `zcn.bin'
is in the `bin' subdirectory.]
(It was necessary to create the junk
file above so that Function-L
would work; there's no way to get the menu
which lets you XMODEM
receive a file without any files in memory.
Yuck.)
(Also, note that you will need a reasonably complete serial
lead for
the ROM software's XMODEM transfer to work (this doesn't apply to
ZCN
itself, which needs only the minimal out/in/gnd connection (plus
CTS
if serial output is to work, though that can just be soldered to
RTS)).
Any lead you *buy* should be fine, but if you've knocked up
your own
only-three-pins-connected job you'll need to borrow a better
lead from
someone for this transfer. :-) However, for an alternative
approach, see
`badlead.txt'.)
You should then end up with a screen looking
something like:
ZCN v1.2
(1999-03-03 16:20) ROM v1.06
A>
A>
(The version numbers and
date/time of assembly may vary - don't worry,
that's because I don't often
update the above `screenshot'. :-))
The `A>' is the ZCN command
processor's prompt. It'll probably be
there twice because you pressed
enter at the end of "CALL &6000" and
it was still pressed
the first time ZCN prompted for a command line,
so it just prompted again.
(ZCN didn't know that it was pressed before
- it wasn't running
then.)
If you ran `rrinit' before booting ZCN, skip the next
paragraph. Let
me put that another way - IF YOU RAN `rrinit', DO *NOT* DO
`format a:'
OR YOU WILL LOSE THE DATA IT SAVED. (`format b:' etc. is
fine,
though.)
Those of you who didn't run `rrinit' should now
make sure you have
your PCMCIA card in the card slot, and type `format
a:'. If it prompts
you asking if you want to reformat it, press `y'. You
should see the
message `Formatting complete' almost immediately
(formatting memory
cards is a very simple operation).
If the
card you're using is 512k or 1024k, type `format b:', which
formats the
2nd logical drive (the 2nd 256k of the card).
If the card is 1024k,
follow this by typing `format c:' and finally
`format d:'.
If
the card is larger than 1024k, you've got more money than sense, as
the
NC100 can't access the rest. :-)
Now you can make a bootable ZCN
drive on your card. Do this by typing
`sys a:'.
Since this is
the first time you've added the system to this card,
you'll get lots of
`addblk..' messages. This means that ZCN is moving
the whole logical drive
up 1k (one block). This is necessary to ensure
that you can add a new
version of ZCN to a card without having to
reformat it. If you ever want
to add a new version of ZCN to the card,
you can just boot it via the
serial link as you did here and then do
`sys a:' again. In fact, you can
also do it without ever leaving ZCN -
see the section `Installing a new
version using an old one' below.
When the message `copying...done.'
appears, the card is bootable.
You may have noticed, while the
system was being copied, there was a
rather curious small black bar at the
bottom-left of the screen. This
is the `drive light' for logical drive A:.
Whenever this bar appears,
part of the card's memory is paged in that
belongs to that logical
drive, i.e. the `disk' is being accessed. The
`drive light' for
logical drive B: is to the right of that, C:'s is to the
right of
that, as is D:'s. It won't usually be `on' as much in general as
it
was for the `sys a:' command; don't worry about this, it's
perfectly
normal.
You should now check that the system is
bootable. This gives you an
opportunity to learn the booting procedure. As
the NC100 remembers
what you were doing when you turn it off, you should
only ever need to
reboot the system from scratch like this to: 1. check
bootable cards,
2. reboot after a crash, or 3. reboot after changing the
lithium
backup battery. (When you change normal batteries, there's no need
to
reboot - the backup battery takes over until the new batteries
are
in.)
*** Rebooting to test a bootable card, or after
a crash
Going from when the NC100 is still on, you should:
1.
Press the on/off switch to turn the computer off. If it didn't turn
off,
remove the main batteries (not the lithium one) and disconnect
from the
mains adaptor, and then reinstall/reconnect. (The on/off
switch will work
fine usually, but sometimes when the NC100 crashes it
stops working
because of memory corruption.)
2. Hold down the Function, Stop and
`<-Del' keys and press the on/off
switch. This restarts the machine from
scratch.
Assuming you're now at the `enter time' screen or the main
menu, it
doesn't matter which:
3. Make sure your bootable ZCN
card is in the slot, and press
`Function' and `X'. This should boot ZCN
and leave you at the `A>'
prompt.
An alternative method (for
testing a bootable card) is to use the
`cboot' command.
****
Ye Olde Boot Method
Just for hysterical raisins, I've left in the
instructions detailing
how you *used* to have to reboot. Not much fun.
:-)
Skip this unless you're interested.
Steps 1 and 2
were as above, and then...
3. Press `Function' and `B'.
4.
Make sure you have a bootable ZCN card in the card slot.
5. Type in
any one of the following lines, whichever is most
convenient. (Type only
one of them, and type them exactly as shown.)
P%=102:[:LD A,128:OUT
(16),A:]
!102=&10D3803E
!102=282296382
6. Press the
on/off switch.
ZCN should now boot from logical drive A: on the
card. If it doesn't,
PANIC. :-)
(You'll probably have to
transfer ZCN via serial link again to get it
to boot, if it really won't
boot off the card.)
As to the choice of which lines to type in in
step 5... The latter two
aren't too bad to write down if your memory isn't
really up to
remembering any of them. The first one is probably fairly
memorable if
you've done much Z80 programming.
That said, I've
managed to memorise the last one, so it might be worth
trying that if you
can.
Now, aren't you glad you don't have to do that any more?
:-)
*** Getting the first program across
So you've
got your shiny new operating system across, and it's there,
and... it's
not doing very much really, is it? To fix that, you'll
need to get some
interesting programs across to your ZCN system. But
in order to do that,
you first need to get a reasonable comms program
across which will make
serial transfer easier.
This implies that getting the first program
across is hard. :-)
Well, it's harder, at any rate. ZCN has a simple
`internal command' (a
program already in memory, which doesn't need to be
loaded off the
card) called `rexec' which reads a uuencoded file from the
serial port
and writes it to the memory card under the filename given.
Now, a
uuencoded file is a binary file, such as a program, converted
to
`normal' readable ASCII characters by a program called,
reasonably
enough, `uuencode'. :-)
On a Unix machine,
`uuencode' will usually be part of the system - it
was originally written
to help with transferring binary files across
7-bit links between Unix
machines. For example, from my Linux box I
could do:
uuencode
wibble.com wibble.com >/dev/ttyS1
...to send the program
`wibble.com' to my NC100, which is connected to
my second serial
port.
One of the best `first programs' in my experience is QTERM. A
version
patched for use under ZCN is in the `support' directory. There is
also
a copy of this already uuencoded, called `qterm.uue'.
What
you should do to send the program is to first type `rexec
qterm.com' on
the NC100, then start the uuencode (if Unix) or `ASCII
upload' the
`qterm.uue' file (if MS-DOS). (It's easiest to again do
this transfer at
2400 baud on your `remote' computer, as ZCN defaults
to 2400 baud - but
that's a bit slow, and you can use `stty' to change
speed if you want,
e.g. `stty 19200' sets the speed to 19200 baud.)
If it works, you
should get a dot printed as each line is processed,
then a short delay at
the end while the file is written.
(If it doesn't work, try pressing
both ctrl and C (i.e. ^C) to abort
the `rexec' and start again.)
(If
you're using MS-DOS and your comms program doesn't have any `ASCII
upload'
facility: 1. do something like `copy qterm.uue com2:' from the
DOS prompt,
and 2. get a new comms program.)
Once you get QTERM across, you can
run it by giving the command
`qterm'. You'll need to read the QTERM
documentation in
`support/qterm' to learn about all its features, but
here's the bare
minimum for transferring things to/from the NC100:
You
can type Control+\ followed by Q to quit QTERM. More usefully, you
can
type Control+\ then R to receive a file (this is what you'll want
first
off) and type something like `x wibble.com' in answer to the
prompt
`Mode?'. Control+\ then S sends a file and works the same way.
(If
you used `rrinit' to save your data, now would be a good time to
make a
backup copy of the `runrom.ram' file it created, by sending it
to your
main machine using QTERM.)
You can find many free CP/M programs on
the oak.oakland.edu ftp site
under /pub/cpm. That's where I got QTERM
from, for example. Note that
some of the programs there, particularly
those that use the BIOS disk
routines, may not work under ZCN. Since many
of the programs there are
stored in .LBR format, you'll probably want to
use the `lar' program
in the `support' directory. Look at the README there
for more info.
** Installing a new version using an old
one
I noted earlier that you could actually install a new version of
ZCN
using an old one - i.e. without ever leaving ZCN. Here's how to
do
that.
First, you need to get the `zcn.bin' file across. You
can do this with
`rexec' or (better) `qterm', as described above. At the
NC100 end you
should give it a filename ending in `.com', as it acts just
like a
normal executable program. `zcn.com' is a good name, for
example.
Then after getting `zcn.com' (or whatever) across, you
simply run it,
in this case by typing `zcn'. When the new version boots,
test it out
a bit to make sure it's working ok; you can then delete the
`.com'
file and install it on the card with `era zcn.com' and `sys
a:'.
** Installation epilogue
By now, you should
have a running ZCN system with a bootable card and
some file transfer
program. You may now want to transfer other
programs in the `bin' and
`support' directories, which together make
what I would consider a fully
functional ZCN system. None of the
programs are necessary, but you're likely
to find many useful:
- Programs you should transfer if at all
possible are `ls', `optdir',
`zde', `pipe', `submit', `pmarc', `pmext', `bbcbas', `runrom', and
`rrxfer'.
- If you want online
help, and it's better than you might think,
you'll want `man' (be sure to transfer `manpages.pma' too, or
it
won't work - see the `MAN'
section under `External Commands' for
details).
- `spell' may be useful if yu kant spel wurth a
dam. :-)
- `calc' runs the ROM calculator program under ZCN, and
since
floating-point calculators
for CP/M are few and far between, this
can be quite handy.
- `nswp' is a file manager which may be
worth a look; alternatively,
`zselx' is a simpler file manager which is somewhat like nswp but
full-screen, and also has the advantage that
the .com file is less
than half
the size.
- `rogue' can be a nice time-waster - oh sorry,
"game" - especially
for
AD&D fans. :-)
- `cpmtris' is a reasonable tetris clone.
-
If you own a microsoft-compatible serial mouse, you might want to
take a look at `zcnpaint', a mouse-based
paint program I wrote a
while
back. Documentation is in the `External Commands' section,
later on.
- If you like the idea
of a graphical front-end which works a bit like
the ROM software's menus (but which is hugely more flexible),
you
may want to try `zap' (but be
sure to transfer `zapdesc.bin' too -
see the `ZAP' section under `External Commands' for details).
-
And somewhat inevitably, there are many more. :-)
Frankly, it might
be a good idea to simply transfer the lot, if you
have room. The programs
in `bin' are described later on in `External
Commands'; the programs in
`support' are described in the README
there.
The rest of the
documentation in this file covers using ZCN and
programming for it, as
well as details of some of the internals.
As such, while I've tried
to assume little previous experience or
knowledge throughout this section
of the documentation, the rest of
this file will assume varying amounts.
It should be possible for
anyone with experience of CP/M to follow most of
the ZCN Manual, but
some is intended for programmers or simply for whoever
is interested.
Those of you who ran `rrinit' to save your data and
are now beginning
to panic because I've said so little about how you get
it back into
memory :-) should probably skip ahead to the section `Running
the ROM
software from ZCN' and read that before reading the manual
proper.
If you're a Z80 programmer new to CP/M and/or ZCN, you may
want to
look at `zcnprog.txt', my guide to programming CP/M and ZCN.
It
documents all the CP/M 2.2 BDOS calls, and all the `zcnlib'
routines.
If you have any problems, feel free to write/email
(addresses are at
the end of this file), and I'll do my best to help. If
you're writing,
please include an SAE if you can, it saves me time and
trouble.
* The ZCN Manual
** Rationale
The
ZCN Manual tends to concentrate on differences from normal CP/M in
everyday
use. I've tried to cover some of how CP/M works, but not all
that much.
Parts of it may be in a rather confusing and messed-up
order, as to a
certain extent I've just scrawled down documentation
for commands etc. as
I've added them.
I recommend that you read at least up until the
`ZCN for hackers'
section. I know it's a lot to read, but it will almost
certainly be
worth it, as ZCN is quite an oddball mix of ideas and
programs, and
there will almost certainly be something there that's new to
you.
Also be sure to read the `Q&A' section below.
The
manual is more than a little informal, as you may already have
noticed. In
my humble opinion, far too many manuals are stuffy and
unreadable. In
stark contrast, the ZCN manual is chatty and
unreadable. Much better.
:-)
** Q&A
This section attempts to cover some
of the more astonishing things ZCN
does. As for what I mean by
`astonishing':
"A program should follow the `Law of Least
Astonishment'. What is this
law? It is simply that the program should
always respond to the user
in the way that astonishes him
least."
-- James Geoffrey,
"The Tao of Programming"
ZCN, ah, bends this law at times.
:-)
*** Why do some programs show the file FOO.TXT as FOO.TwT?
This
is to do with, and yes I know this sounds bizarre, ZCN's support
for the
power on/off switch. Turning the machine off is actually done
under software
control, and the way it needs to work, combined with
the way CP/M works,
means that with some programs you may see
filenames with `w' as the second
character of the extension. A few
programs may even force the actual files
to have a `w' there (this is
very unlikely, but there might be one or two
programs that do it).
For technical reasons, there's little I can do
to prevent either of
the problems. The NC100 simply wasn't designed to run
CP/M, and ZCN
just does the best it can with what it's got. For a more
technical
explanation of why this happens, see the section `The Power
On/off
Switch' near the end of this file.
*** Why do I get
rubbish from the serial port?
Whenever you turn on the NC100 under
ZCN, the serial port is enabled.
During this process, a spurious `serial
input' interrupt is generated
which is difficult to filter out for various
reasons. This usually
ends up putting a random character in the serial
input buffer. This is
harmless and can be ignored.
If you get a
whole load of rubbish chars, you probably either have
parity enabled at
the other end or are using the wrong baud rate.
*** Why are the
letters so SMALL!?
I wanted to get as many lines as possible. I
think it's worth the
smaller characters to get 10 lines rather than 8 with
the ROM
software. I hope the characters are readable; I think they are,
but
I'm obviously rather biased. They're narrow to keep the aspect
ratio
as `normal' as possible, and because 4-bit wide characters are
much
easier and faster to draw than 6-bit wide ones such as the ROM
software
uses.
*** Why does zero look round, and O rectangular?
Before
ZCN v1.1, you simply couldn't tell zero and O apart in ZCN's
font (both
were round). Since, unfortunately, the characters were too
small to:
-
put a slash through the zero;
- put a dot in the centre of the zero (it
makes it look like an 8!);
- make the zero more diamond-like;
- make
the zero narrower;
...I decided to make the O rectangular instead.
(This is an unusual
approach, but isn't entirely without precedent.) It's
not ideal, but
at least you can tell which is which.
If you
really can't stand this, and you'd rather they were both round,
do this,
but be careful to type it in correctly!
poke ebda 44
poke
ebde 44
(Note that this causes problems with the copy cursor in
`bbcbas'
though - it'll think both 0 and O are zeroes. And it'll
affect
`dmp2txt' in much the same way.)
You could put these
commands in your `autoexec.sub' if you wanted this
all the time (more on
SUB files later), or you could just rewrite ZCN
with the altered font
using `sys a:'.
*** Why do some characters look like random
blotches?
ZCN only has character bitmaps for characters in the range
32-126, the
so-called `printable characters'. If a character outside this
range is
printed which is not a control code, an effectively random
collection
of pixels is printed.
This usually happens when a
character was printed which had the high
bit set. If the offending
character was received from the serial port,
try disabling parity on the
other machine.
*** It says `Disk Full', but I've got plenty of room
left!
This probably means that the drive's directory table is full.
Usually
under ZCN there's a maximum of 64 files per drive (but see
below).
When you run out of directory space, it's often interpreted
by
programs as `disk full'. It does have the same effect, as in order
to
write any more you'll have to move or delete one or more files.
You
may, in fact, be allowed less than 64 files. If a file is larger
than 16k,
it will take up more than one directory space - it'll use
one for each 16k
of the file.
*** Why is QTERM's display when sending/receiving files
messed up?
QTERM's file transfer display is designed for a terminal
with 12 lines
or more. ZCN only has 10, so the line which shows the number
of errors
sometimes overprints the line showing the number of packets done
so
far. I'm afraid there isn't much that can be done about this
without
patching QTERM - but hopefully it's not that much of a
problem.
*** How can I patch programs without DDT/SID?
Unfortunately,
the (possibly unusual, since they were for fairly `odd'
machines and may
have been modified) copies of DDT and SID I've tried
didn't work on ZCN;
or rather, they worked to a certain extent, but
they seemed to overwrite
the call at 0030h, which is a Bad Thing on
ZCN.
Personally, I
don't think this is that much of a problem. I use `wade'
instead (look in
the `support' directory for a copy) which is, dare I
say it, rather nicer
than DDT and SID. :-)
*** Why does the ROM ask me to set the time when
I turn the NC on?
NC100s with ROM v1.00 seem to be quite pedantic
about having the time
set. If the time *isn't* set, the ROM demands you
set it, which loses
you any saved context - and if ZCN was running, it
resets the machine
into the bargain. :-( This is a bug in the original
ROM, and although
it was fixed in the later v1.06 (which is in my NC100,
for example),
this doesn't help you if you have machine with the earlier
ROM (you
can check which ROM you have with ZCN's `ver' command).
The
only way to `fix' it is to set the time, as you might imagine.
(You can do
this either with the ROM's time setting screen or with
ZCN's `timeset'
command.) Fortunately, once the time is set it tends
to stay that way.
:-)
** Running the ROM software from ZCN
[This is
deliberately early on in the manual (earlier than it might
otherwise make
sense for it to be) so that it isn't too hard to find
for anyone skipping
ahead from `Installation epilogue'.]
*** About `runrom'
To
run the ROM software from ZCN, just use the `runrom' program - i.e.
do
`runrom' and it boots the ROM software. If you have an existing
`runrom.ram'
file - this file is a snapshot of an already-booted
machine, usually with
files in memory etc. - be sure to start with
that in the current drive and
user area. If no `runrom.ram' file is
found in the current drive/user, the
memory is zeroed and the ROM
booted from scratch.
Note that you
can only run `runrom' from a bootable card. (It'll exit
with an error if
you try to run it on one which isn't.) It's
complicated to fully explain
why, but the basic reason it's necessary
is so that there's a safe way
back to ZCN from the ROM software.
You also need either an existing
`runrom.ram' snapshot file, or 64k
free on the current drive in order to
create one. The reason for this
latter requirement is much easier to
explain - a snapshot is always
saved when you return to ZCN, and the disk
space for it is allocated
in advance.
When the ROM software is
started, you can use it exactly as you
normally would.
(If you
used `rrinit' to save your existing memory, the `rrinit' file
will still
be there when you do `runrom'. Feel free to delete it; it's
not needed any
more.)
When you want to return to ZCN, *make sure the card you ran
`runrom'
from is in the card slot*, then press `Function' and `X'.
(It's
probably best to leave this card in the slot throughout so you
don't
need to worry about whether it's in or not - but you may find
this
inconvenient. It's up to you.)
When you return to ZCN (in
fact just before), a snapshot of the memory
is saved in `runrom.ram'.
After that, ZCN is rebooted.
So in summary, it's:
-
`runrom' on a bootable card to go from ZCN to the ROM s/w.
-
Function-X *with the same card in the slot* to return to ZCN.
By the
way, you may notice that the screen is corrupted for a (very)
short while
when switching between ZCN and the ROM or vice versa. This
is meant to
happen, and is nothing to worry about.
There is one extra detail to
cover. Imagine this situation - when
using the ROM software, something terrible
happens and you manage to
make it crash. (This isn't that difficult if
you're messing about with
machine code in BBC Basic; also, there are one
or two bugs in the ROM
which can lead to crashes in certain obscure
situations.) The only way
out, as usual with a crash, is to reboot.
Obviously, in this situation
you're not going to want a snapshot to be
saved when you do
function-X! No problem. Just make sure you're holding
both shift keys
when you do function-X - i.e. while holding down both
shifts and the
function key, press X - and no snapshot will be saved. So
the next
time you do `runrom', your previous data will still be
intact.
Now you know how to switch between ZCN and the ROM
software, you may
be wondering how useful this really is without the ability
to copy
files between the two. That's where `rrxfer' comes in.
***
About `rrxfer'
`rrxfer' lets you copy files to/from a `runrom.ram'
snapshot file, and
thus to effectively copy files to/from your ROM
software setup.
Rrxfer uses an 80-column-friendly layout and no
inverse video if the
console output is going to the serial port or
printer.
**** How to use it
The program is relatively
straightforward to use. You start it up with
plain `rrxfer', then when the
menu line comes up (it'll take a little
while as it has to load most of
the snapshot first), press one of
these keys:
- `r' to list the
ROM files (i.e. the files in the snapshot). Files in
both the ROM's
`upper' and `lower' memory areas are listed.
- `z' to list the ZCN
files (i.e. the files in the current
drive/user). I'm afraid there's no
way to transfer files to/from a
different drive or user area than the one
the snapshot is in. (You can
probably get around this, though, by copying
files or using `umv'
before/after running rrxfer, as appropriate.)
-
`g' to get a file - to copy a ROM file to ZCN. Note that any
existing ZCN
file with the same name will be overwritten. The filename
you type must
exactly match the ROM file's name - case is significant
in ROM filenames.
The copy made is automatically given a reasonable
ZCN name; non-printable
ASCII chars, spaces, colons, asterisks and
question marks are all
converted to underscores. If you choose `g'
then change your mind, just
type in an empty filename (that is, just
press enter) to abort.
If
the ROM file isn't found, or there isn't enough room on the ZCN
drive to
write the copy, you'll get an error message saying so.
- `p' to put
a file - to copy a ZCN file to the ROM's file area. Note
that any existing
ROM file with the same name will be overwritten
(more precisely, the
existing file is deleted first, whether in upper
or lower memory). The
copy is always written in lower memory. (Again,
you can enter an empty
filename to abort.) The copy made is given a
ROM filename which matches
how you typed the ZCN file's name, which
means you have a degree of
control over the ROM file's name.
Here's an example of what that
means - say you have a file `foo.txt'.
If you type the name as `foo.txt',
the ROM file written is `foo.txt'.
Simple enough. But you could also type
it as `Foo.txt', as that still
refers to the same ZCN file, and the ROM
file will then be called
that. (As I mentioned above, case is significant
for ROM files.)
`FOO.TXT', `fOo.TxT', and `foo .txt' are other possibilities.
If the NC100's
real-time clock has been set (either via the ROM or
with ZCN's `timeset'),
the file is written with the current time/date.
If the clock isn't set,
however, they're written with a `zero'
time/date. The ROM interprets this
as midnight on "90-00-00" [sic].
If the ZCN file isn't
found, or there isn't enough room in the
snapshot's lower memory to write
the copy, you'll get an error message
saying so.
- finally, `q'
quits rrxfer. This may take a little while if you wrote
any files to the
lower memory (i.e. used `put'), as the lower memory
part of the snapshot
has to be rewritten.
The menu line lists these keys with a (very)
brief description of what
they do.
**** Problems
There's
one main problem when transferring files between the ROM
software and ZCN
- the ROM software stores file sizes exactly, while
ZCN (being CP/M-like)
only stores them to the nearest 128-byte
`record'.
For file
tranfers in the ROM -> ZCN direction, this is usually not a
problem.
Rrxfer always makes sure an extra ^Z is added to end of any
files
transferred, so text files are ok. (This can cause some
difficulties for
binary files assumed to be of a given size though -
screen dumps are
probably the main example, and how to deal with those
is covered in the
`Hints and tips' section below.)
The problem is in the ZCN -> ROM
direction. Now, if you think about
it, this doesn't seem like it should be
a problem for the ROM stuff -
XMODEM file transfers work with 128-byte
records too, and it has no
problems dealing with those! Unfortunately, it
seems to be the XMODEM
receive routine which deals with them (probably by
stripping trailing
^Z's), rather than being some general capacity of the
file I/O.
This means that we need to check each of the ROM
software's programs
in turn to see how it copes with it. Now, the only
ones with which you
can get at files written by rrxfer are the word
processor and BBC
Basic. The word processor shows any trailing ^Z's
literally, as a
series of little right-arrows. These are then easily
deleted. As for
BBC Basic, it seems to simply ignore junk at the end of
its Basic
files. If you *EXEC a file, it'll leave right-arrows on the
screen,
but as with the word processor these are easy enough to delete
(in
Basic pressing Stop is probably easiest). Note also that BBC Basic can
be
run natively on ZCN (and is 10% faster), so running it under the
ROM
software probably isn't that attractive anyway.
Text files written
by some CP/M programs may cause more problems than
others. For example,
since you need only one ^Z to end a CP/M text
file, some programs only
write one, and don't worry about whatever
junk may be in the rest of the
record. If you have this problem, and
the junk causes difficulties,
there's an easy solution - just load the
file up into ZDE and save it
before transferring with rrxfer. (ZDE
always fills up the remainder of the
last record with ^Z's. By the
way, it'll prompt you because the file is
unchanged - just press `Y'.)
**** An example session
Here's
an example of an rrxfer session:
rus@amnesia:/b/0>rrxfer
Reading
lower memory from snapshot...
[R]OM files, [Z]CN files, [G]et (ROM->ZCN), [P]ut
(ZCN->ROM), [Q]uit
ADDRESS BOOK
1k foobar 1k
new2 1k new6 1k
autoexec.sub
1k HELLO.BAS 1k
new3 1k new7 1k
COPY.BAS
1k hello.bas 1k
new4 1k sw.txt 2k
FILLER
9k new1 1k
new5 1k TRY.BAS 1k
36k free in
lower memory
[R]OM files, [Z]CN
files, [G]et (ROM->ZCN), [P]ut (ZCN->ROM), [Q]uit
radfreq.txt 1k
runrom.ram 64k sw.txt 2k
13k free
on drive
[R]OM files, [Z]CN files,
[G]et (ROM->ZCN), [P]ut (ZCN->ROM), [Q]uit
Get which ROM file?
hello.bas
File copied OK.
[R]OM files, [Z]CN files, [G]et (ROM->ZCN), [P]ut
(ZCN->ROM), [Q]uit
Get which ROM file? flurgle
Error writing ZCN
file! (ROM file not found, or ZCN disk full)
[R]OM files, [Z]CN files, [G]et (ROM->ZCN), [P]ut
(ZCN->ROM), [Q]uit
Put which ZCN file? radfreq.txt
File copied
OK.
[R]OM files, [Z]CN files,
[G]et (ROM->ZCN), [P]ut (ZCN->ROM), [Q]uit
Put which ZCN file?
wibble
Error writing file! (ZCN file not found, or not enough low
memory)
[R]OM files, [Z]CN files,
[G]et (ROM->ZCN), [P]ut (ZCN->ROM), [Q]uit
ADDRESS BOOK 1k
HELLO.BAS 1k new4 1k sw.txt 2k
autoexec.sub
1k hello.bas 1k
new5 1k TRY.BAS 1k
COPY.BAS
1k new1 1k
new6 1k
FILLER 9k
new2 1k new7 1k
foobar
1k new3 1k
radfreq.txt 1k
35k free in lower memory
[R]OM files, [Z]CN files, [G]et
(ROM->ZCN), [P]ut (ZCN->ROM), [Q]uit
hello.bas 1k
radfreq.txt 1k runrom.ram 64k sw.txt 2k
12k free on drive
[R]OM files, [Z]CN files, [G]et (ROM->ZCN), [P]ut
(ZCN->ROM), [Q]uit
Writing lower memory to snapshot...
done.
****
Bugs
There's one bug in rrxfer that I'm aware of:
- You
can't `put' an address book (due to the filename required). This
probably
isn't that big a deal, as address books are in a funny format
anyway.
***
Hints and tips
`runrom.ram' is just a normal file. If you make a
backup of this file,
you're backing up your ROM software setup and all the
files it has in
memory. Backing up all your files has rarely been *this*
easy... :-)
Equally, because it's a normal file, you can save space
if (like me)
you don't use the ROM software much by compressing the
snapshot with
pmarc (using something like `pmarc snap runrom.ram'). You'll
have to
decompress it again (with pmext) before using `runrom', of course,
but
it could save you quite a bit of disk space in the meantime.
ROM
software screen dumps can't be viewed as-is on ZCN, because rrxfer
adds an
extra record to the ZCN copy to allow for the ^Z it always
adds. (This
means that trying to view it the usual `get f000' way will
crash the
machine!) So the full sequence for getting a ROM s/w screen
dump and
loading it on ZCN goes like this:
- Make sure you have at least 9k
free on the ZCN drive with
`runrom.ram' on.
- On ZCN, do `runrom' to start the ROM
stuff.
- Make sure there's at least 4608 bytes free in the upper
memory.
- Do whatever it is you need to, to get the screen right for the
dump.
- Do Ctrl-Shift-S. This saves `s.a' and `s.b'.
- Do Function-X
to return to ZCN.
- Start up rrxfer.
- Get `s.b', and quit. (`s.a'
isn't of interest.)
- Do `get 100 s.b', then `save 16 dump'.
- `get
f000 dump' now loads the screen dump.
- Delete `s.b' if you want, you
don't need it any more.
** Command Prompt
When ZCN
is waiting for you to issue a command, it gives a short
prompt ending in
`>'. This prompt tells you which drive is the default
drive; the drive
which files are assumed to be on unless you
explicitly specify
another.
If drive A is current the prompt would normally be `A>'.
This may not
always be the case however - there may be a number or `*'
displayed
between the drive letter and the `>'. See `User Numbers' for
more
details.
If you like, you can redefine the prompt ZCN uses
to suit your own
tastes. See the description of the `%' command (listed
as
`%prompt_string') in the `Internal Commands' section for details.
**
Wildcards
Wildcards in ZCN (and CP/M, and even MS-DOS) have a
curious quirk that
you may not be aware of. When you specify part of a
filename or
extension then use a wildcard, it matches even files that have
no more
characters after the part you specified.
This is fine
for wildcards like `foo*.txt', which matches `foo.txt',
`foo2.txt' and
`foobar.txt'. Where it gets weird is for `foo?.txt',
which obviously
matches `foo2.txt' but (perhaps unexpectedly) also
matches `foo.txt'! The
reason for this is that the file isn't really
called `foo.txt' as far as
the system is concerned; it sees it as
`foo_____txt' (I'm using
underscores to represent spaces for clarity).
The wildcard `foo?.txt', or
`foo?____txt', matches this as the `?' by
definition matches any
character.
Rational or not, having `foo?.txt' match `foo.txt' is
bound to confuse
anyone who's used to Unix, where it wouldn't match, and
might even
confuse some MS-DOS or CP/M users who haven't noticed it before.
I
thought it was a bug the first time I noticed it. :-)
**
The Keyboard
The NC100's keyboard is, shall we say, a little odd.
Certainly some
keys are in the `wrong' place.
The way ZCN fixes
this and maps the non-obvious keys is shown below:
Key Acts
like ASCII code Reason
--- --------- ---------- ------
Function Control <none> Nice big key
Stop Escape 27 In the right place
<-Del Delete 127 In the right place
Del-> ^G 7 WordStar-like
Menu ` 96 No real backquote key
Cursor Up ^E 5 WordStar-like
Cursor Left ^S 19 WordStar-like
Cursor Right ^D 4 WordStar-like
Cursor Down ^X 24 WordStar-like
The
`symbol' key acts as a Meta key - it sets bit 7 of any key
pressed. (PC
folks should think of it as analogous to `Alt', but
different.)
Ctrl+Space
returns ASCII 0 (i.e. NUL). Note that this may not be sent
by some
terminal programs (though QTERM seems to be ok). The built-in
command
`sertest' does send it, so you could always use that.
It is possible
to make the `Caps Lock' key act like a control key, if
you like that - see
`CAPSCTRL' in the `Internal Commands' section for
details.
You
cannot stop a program's output by using ^S. However, you can pause
a
program's output at any time by holding both the `control' and
`symbol'
keys simultaneously. The output starts again when you let go.
You
can get a dump of the current screen at any time by pressing
Control-LeftShift-S
(you must use the real Control key for this). The
middle 60 pixel lines of
the screen memory are simply saved to the
file `screen.dmp', including the
`wasted' bytes, giving 64 bytes per
line. The top two and the last-but-one
pixel lines are used as
temporary storage during the screen dump, so don't
worry if they
appear corrupted for a second or two. You'll get a screen flash
(or
beep) when the dump has been written, and you can then carry on
with
whatever you were doing.
On a Unix box with the `netpbm'
or `pbmplus' utilities installed, you
can convert a `screen.dmp' file to a
PBM file with something like this:
(echo P4;echo 512 60;cat
screen.dmp) | pnmcut 0 0 480 60 >foo.pbm
You can then convert to
other formats with things like ppmtogif, etc.
** The
Screen
The NC100's screen has a pixel resolution of 480x64. ZCN
provides a
character screen of 120x10 with 4x6 character cells, leaving
two pixel
lines at the top and bottom free. The leftmost 32 pixels on the
bottom
pixel line are used by the `drive lights' (see `Logical
Drives').
** The Terminal Driver
*** Control
Codes
Programs often have patch areas (or installation programs)
which need
to know which sequences to send to do cursor movement, etc. For
that
reason, and for programmers of course :-), the console control
codes
are listed here. Those listed as `(reserved)' have no effect.
Code Hex Dec Description
^@ 00
0 (ignored)
^A 01
1 clear screen, home cursor
^B 02
2 bold off
^C 03
3 cursor on
^D 04
4 cursor off
^E 05
5 bold on
^F 06
6 clear to end of screen
^G 07
7 bell (by default, this flashes the
screen)
^H 08 8 backspace
^I 09
9 tab (8 chars wide, i.e.
1,9,17,25,33,...)
^J 0A 10 linefeed
^K 0B 11 (reserved)
^L 0C 12 (ignored)
^M 0D 13 carriage return
^N 0E 14 italics ("underline") off
^O 0F 15 italics ("underline") on
^P 10 16 move cursor - 10h, then 20h+y, then 20h+x
(see below)
^Q 11 17 (ignored)
^R 12 18 insert line
^S 13 19 (ignored)
^T 14 20 delete line
^U 15 21 scroll up
^V 16 22 (reserved)
^W 17 23 scroll down
^X 18 24 true video (i.e. turn off reverse
video)
^Y 19 25 reverse
video
^Z 1A 26 move cursor right one
column
^[ 1B 27 VT52
escape code prefix (see below)
^\ 1C 28 (reserved)
^] 1D 29 move cursor up one line
^^ 1E 30 home cursor without clearing screen
^_ 1F 31 clear to end of line
In pre-v1.2
versions of ZCN, the y location for ^P was 46h+y. This is
still supported,
but is deprecated and may not be supported by a
future version of ZCN -
you should switch to using 20h+y instead.
Some VT52-like escape
codes are supported, mostly so that Mallard
Basic will work comfortably on
ZCN. These all start with ^[ (ESC).
Those supported are ESC-D to backspace,
ESC-C to move the cursor right
one column, and ESC-K to clear to the end
of the current line. (In
fact, at the moment, ESC followed by anything
other than `D' or `C'
acts like ESC-K.) No other VT52 escape codes are
implemented.
However, one extra feature of ESC is that it
counteracts any CR/LF
output immediately after. So if you're writing a
program where you
want to avoid the CR/LF which ZCN normally outputs when
a program
exits, you can easily do this by just outputting an ESC before
you
exit. (Be warned that this doesn't work on ZCN versions earlier
than
v1.2, though, and obviously it won't work if console output is
redirected
to the serial port.)
While I'm on the subject, here's another brief
aside for programmery
types. :-) If for some reason you need to know the
current cursor
location, you can use this bit of Z80 to read it (it reads
the x
position into B and the y pos. into C):
ld ix,(1)
ld b,(ix-5)
ld
c,(ix-4)
Using this is a Bad Idea in general, and it won't work on
old
(pre-v1.1) versions of ZCN, but it's there if you need it.
***
Unix termcap/terminfo entries
Skip this if you don't use any version
of Unix.
Since the NC100 can be used as a convenient and portable
terminal to
Unix systems, it's a good idea to have a termcap/terminfo
entry to
hand so you can run full-screen programs on it. Note that they
will
have to be able to cope with using such a small number of lines
-
Emacs and Nethack can, for example (though Nethack isn't too happy
about
it).
Here's a termcap entry for an NC100 running ZCN:
zcn|amstrad
nc100 running zcn:\
:cl=^A:co#120:li#10:cm=^P%+
%+ :le=^H:bs:am:sf=^U:sb=^W:sr=^W:\
:ce=^_:so=^Y:mr=^Y:se=^X:us=^O:ue=^N:me=^X^N:al=^R:dl=^T:it#8:\
:cr=^M:do=^J:nl=^J:ms:vi=^D:ve=^C:ta=^I:up=^]:nd=^Z:cd=^F:
However,
termcap is rapidly falling into disuse these days, so most
people will
probably want a terminfo entry instead. Here's the one I
use:
zcn|amstrad
nc100 running zcn,
cols#120,
lines#10, am, clear=^A, cr=^M, bel=^G,
cub1=^H,
cuf1=^Z, cuu1=^], cud1=^J, ind=^U, ri=^W,
cup=^P%p1%'
'%+%c%p2%' '%+%c, home=^^,
el=^_,
ed=^F, il1=^R, dl1=^T,
smso=^Y,
rmso=^X, smul=^O, rmul=^N, bold=^E, rev=^Y,
sgr0=^B^N^X, msgr, civis=^D, cnorm=^C,
ht=^I, it#8, km,
You may have
problems using Emacs, for a couple of reasons. The common
problem with
XON/XOFF flow control doesn't apply since ZCN avoids it
like the plague;
instead, there are two other problems.
Because of the way the direct
console I/O BDOS function works, some
CP/M terminal programs may not send
^@ (ASCII 0, or NUL). This'd be a
real pain when using Emacs. The simplest
solution is to use the
built-in command `sertest', which has the added
advantage of being
faster than most other terminal programs since it
really is very
simple indeed, and can call functions in ZCN directly
rather than
having to use the BDOS entry point. (My tests indicate that
`sertest'
is nearly twice as fast as QTERM.)
You may also have
problems getting the `Symbol' key to work as a Meta
key. There shouldn't
be a problem if Emacs is using terminfo - the
terminfo entry above
specifies `km' which should get it working
properly. (Certainly that works
for me.) But if for whatever reason it
doesn't work, you might want to try
putting this in your ~/.emacs file
to fix it:
(if (equal (getenv "TERM")
"nc100")
(set-input-mode nil nil t))
(If
that doesn't work, it could be down to the stty settings `cs8'
and/or
`-istrip' not being set.)
** Rebooting
There are
two main rebooting possiblities available when switching on
the NC100
running ZCN. They are:
1. Cold boot of the ROM software. Do this by
holding down Function,
Stop and `<-Del' while turning the computer on.
You should only need
to do this if a program crashes, etc. You should then
use Function-X
to boot ZCN from your bootable card.
2. Cold
boot of ZCN. (This isn't fully `cold', as it just restarts the
copy of ZCN
in memory.) Do this by holding down both shift keys while
turning the
computer on. Use this to clear any random wedgitude that
may have
occurred, or to test your `autoexec.sub' (see later).
You can also,
from the ZCN command-line, use `cboot' to do a fully
`cold' boot of ZCN
from the memory card.
** CP/M Compatibility
ZCN
aims at close CP/M compatibility - enough to get the majority of
freely
available programs running. Most programs work. This section
describes
what facilities are provided, and lists programs which are
known to not
work under ZCN.
*** BDOS Functions
The following BDOS
functions are provided, and are believed to be
working correctly:
0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21,
22, 23, 24, 25, 26, 29, 32, 33, 34, 36, 37.
These ones work but have
known problems:
35 - gives incorrect results for files with
holes.
40 - the same as function 34, i.e. it doesn't actually do the zero
fill.
These not done:
27,
28, 31.
There are some additional (ZCN-specific) functions;
some are mentioned
later. Full descriptions are given in `zcnprog.txt',
but the ultimate
reference is `zcnfunc.z' in the `src' directory. So, in
other words,
RTFS. :-)
*** BIOS Functions
ZCN
has a rather sparse BIOS jumptable which omits all the
disk-related
functions. I am very reluctant to add them as it would
take a fair chunk
of memory to implement. (ZCN's internals work
differently to CP/M, which
would make writing them tricky, too.)
Still, the existing BIOS is enough
for most programs.
*** Zero Page etc.
ZCN uses the
memory at addresses 0000h-00FFh as follows:
address(es) description
00h-02h jump to warm boot routine
03h ZCN does not implement CP/M's IOBYTE;
instead, this
byte
contains the contents of 80h when the last
program finished (this lets you check the exit
status
of a Hitech C
program)
04h-04h unused
(but set to zero by warm boot)
05h-07h jump
to BDOS
08h-2Fh usable by
user programs (as on CP/M)
30h-32h jump
to NMI poweroff routine (see note 1)
33h-37h part of NMI poweroff routine
38h-3Ah unused jump to maskable interrupt
routine (see note 2);
usable
by user programs
3Bh-5Bh reserved
(actually unused)
5Ch-6Bh initialised
part of FCB 1 (see note 1)
6Ch-7Bh initialised
part of FCB 2
7Ch-7Fh remainder
of FCB 1
80h size of command
tail at 0081h
81h-FFh command
tail (command line minus command name)
Note to programmers: Please
do not *depend* on any of the `unused'
sections above being available for
your use (unless your program is
taking over control of the machine
completely).
Note 1:
Pressing the on/off switch when the
NC100 is on causes a non-maskable
interrupt - that is, it disables
interrupts, puts pc on the stack, and
jumps to 0066h. This is the 2nd
char. of the filename extension in FCB
1 - there's some ad hackery in ZCN
to try and deal with the problems
this causes. As far as I know it's
successful, except that sometimes
you will see a filename printed with the
2nd char. of the extension
appearing as a lowercase `w'. I don't think
there's anything I can do
about that. Anyway, the value that's actually
stored at 0066h is F7h -
`rst 30h'. The maskable interrupt routine and
BDOS both fix this byte
if it's been changed.
Note
2:
The maskable interrupt routine is responsible for the
following:
- Fixing 0066h if it's been changed (see note 1 for
details).
- Keyboard input/buffering.
- Serial port
input/buffering.
- Auto poweroff timeout and the actual auto poweroff
itself.
- Updating `drive lights'.
See `Tight Interrupts' (in
the hacker's guide section) for what
happens when minimal interrupts are
in use.
The reason there's still a jump to the interrupt handler at
0038h is
in case there's some program out there which explicitly selects
IM1
for some reason and expects ZCN to cope with this.
Note
3:
Although 0008h-002Fh is available for use by user programs, ZCN
puts a
jump instruction at 0028h (which it's ok to overwrite). The jump
at
0028h is to allow ZCN's internal commands to use `rst 28h' as an
indirect
call to a inline string output routine, thus saving a few
bytes. It's not
a good idea to call this yourself - it doesn't exist
on other CP/Ms, and
didn't even exist on ZCN until v1.1. However, if
you're really determined
to ignore my advice on this :-), look at
`ilprint' in `src/misc.z' for how
to call it.
Unusually for a CP/M system, the BDOS entry point
(the address at
0006h) is the very start of system code; all addresses
from that one
upwards are used by ZCN, except for the screen memory which
starts at
F000h. Programs which leave space for a CCP will still work, as
will
those which don't - all parts of ZCN interact directly with
each
other, and should never be overwritten. Note that this
monolithic
approach means you will presumably never be able to run any
version of
ZCPR on a ZCN system unless someone's prepared to hack up
both
programs.
*** Non-working Programs
Essentially,
programs which need disk BIOS functions don't work. This
included (the
last time I tested) superdir, `dr24.com', and zx 3.1.
Another
possible problem is the whole 66h thing (more on this
elsewhere) - usually
this just results in the odd spurious `w' being
printed :-), but it can
cause real problems with some odd programs.
The ones I've found so far
that are affected are nulu and kermit.
** Tips on using
certain programs with ZCN
*** Hitech C
**** Getting
Hitech C
Native CP/M Hitech C is free. It's very slow and
memory/disk hungry
and Z80-specific and the optimisation is quite awful, but
it's very
ANSI-compatible (well, for a CP/M C compiler ;-)) and excellent
for
compiling short (<2000 line) C programs. It's available from
oak.oakland.edu
in /pub/cpm/hitech-c, and probably also available from
any decent CP/M PD
distributor.
**** How to run it on ZCN
Programs compiled
with Hitech C (which fit in memory!) work on ZCN
just fine, though any use
of any exec() or system() call will fail. A
few of the programs in the
`support' dir were compiled with Hitech C
using the excellent `cpm' CP/M
emulator on my Linux box.
As for the compiler, things are more
problematic. The compiler driver
`c.com' doesn't seem to work on ZCN for
some reason, so you have to
run the passes by hand. Even then, most of the
passes need a LOT of
memory to run. You'll need to use `bigrun' to run
them. (Be sure to
read the warnings in the `bigrun' section first!) Here's
an example
SUB file `hc.sub', designed to run on drive B: with `libc.lib'
on
drive A:, which acts as a simple replacement for `c.com':
---------------------------
cut here ----------------------------
submit hc.sub *
defrag -q
b:
'cpp:
cpp -DCPM -Dz80 -I $1 hctemp1
ifnpeek 3 0 quitsub era
hctemp?
'p1:
bigrun p1 hctemp1 hctemp2 hctemp3
ifnpeek 3 0
quitsub era hctemp?
era hctemp3
'cgen:
bigrun cgen hctemp2 hctemp1
ifnpeek
3 0 quitsub era hctemp?
era hctemp2
'zas:
bigrun zas -N
hctemp1
ifnpeek 3 0 quitsub ; era hctemp?;era hctemp1.obj
era
hctemp1
'link:
link -Z -C100H -o$1om crtcpm.obj hctemp1.obj $2 $3 $4
a:libc.lib
ifnpeek 3 0 quitsub ; era hctemp1.obj;era $1om
era
hctemp1.obj
"compiled ok.
--------------------------- cut here
----------------------------
All the `ifnpeek's make sure it quits
and cleans up temporary files if
any pass fails. The last two
`ifnpeek..quitsub' commands need `semi'
to be on your machine as `;.com' -
failing that, you could replace
them respectively with `ifnpeek 3 0
quitsub era hctemp?' and `ifnpeek
3 0 quitsub era $1om' at the cost of
possibly leaving a hctemp1.obj
file lying around.
For the SUB
file to work, you'll also need much of Hitech C on your
machine
(unsurprisingly :-)). Specifically, you need `cgen.com',
`cpp.com',
`crtcpm.obj', `link.com', `p1.com', and `zas.com'. You'll
also need
`libc.lib' on drive A:, as I mentioned above, and you'll
need any headers
you want to use - certainly you'll want `stdio.h',
and probably `stdlib.h'
and `string.h'. It may be a good idea to make
a .pma archive of all the
header files, so you can get at any you
need. (Such an archive is 9k
rather than the 30k the headers take
uncompressed.)
To compile
with floating-point support, you'll also need `libf.lib',
and will need to
compile with something like `hc foo.c libf.lib'.
You need an awful
lot of disk space to run Hitech C. You can't
realistically run it on
anything less than a 512k card, and a 1024k
card might be preferable if
you want to have enough disk space free to
do other things too. When I
last tried it on my 512k card, on the A:
drive I had `headers.pma' and
`libc.lib' taking up 69k, and on B: I
had the various required COM files
and headers taking up roughly 190k.
Total disk space required, 259k - and
that didn't include the 32k
needed for `bigrun' to work, nor did it
include the space needed for
Hitech C's temporary files. (Which can be 30
or 40k.) So it
effectively took about 330k.
Oh, and another
point - as I've said, it's not exactly fast. On ZCN,
it takes 50 seconds
to compile a "hello world" program!
Personally, I dumped
it and use `bbcbas' instead when I want to
program on the NC100 itself.
It's about 50 times smaller ;-), and
there's no waiting for things to
compile.
**** Realistic System Requirements for Hitech C
For
serious use, I personally wouldn't run the compiler itself on a
CP/M box
of less than around 20MHz clock speed, 60k TPA, 1 Mb disk -
to run it with
less than that you'd have to be pretty patient. A good
CP/M/Z80 emulator
on a 486 or better is a perfect environment.
(Consider `zsim' for MS-DOS,
`cpm' for Linux and presumably other
386-based Unix; others I'm not sure
of (`cpm' uses 386 assembly to get
the high speed, and isn't
CPU-portable). Some sort of emulation is
probably your only option - I
don't know of any *real* CP/M system
which could run it at a reasonable
speed.)
**** Bugs in the library
There's one bug I've
noticed in Hitech C's libc library - fgets() will
not read lines longer
than the buffer size correctly. I suspect it's
implemented as gets() from
a stream, which is not ANSI at all. This
may not worry you, but if it
does, here's something you could put
right at the end of stdio.h as a
workaround (minus the `cut' lines of
course :-)):
---------------------------
cut here ----------------------------
char *myfgets(char *s,int size,FILE
*stream)
{
char *ptr=s;
int f,c;
for(f=0;f<size-1;f++)
{
c=fgetc(stream);
if(c==EOF) break;
*ptr++=c;
if(c=='\n')
break;
}
*ptr=0;
if(c==EOF) return(NULL);
return(s);
}
#define
fgets myfgets
--------------------------- cut here
----------------------------
I think this fits the ANSI standard.
Certainly it's a lot better than
the Hitech C implementation, 'cos it
works. :-)
If you're feeling adventurous, you could fix the library
itself (not
too hard if you use `libr'), but this is left as an exercise
for the
reader. :-)
*** Mallard Basic
Mallard
Basic is, if nothing else, the first commercial program I've
got to run
under ZCN. (Though it's a bit painful compared to BBC
Basic. :-))
I
added a couple of extra control codes to the terminal driver to cope
with
MB's expectation of a VT52 - namely, ESC-C, ESC-D and ESC-K. (I'm
surprised
it uses them, really. You can implement all it needs with
straight ascii
codes like BS and CR. It'd be slower, but would work on
everything.)
If
you want basic to use the full width of the screen and correctly
wrap long
lines, do `width 120,120' after starting up.
My +3 CP/M manual only
describes the keys MB uses in terms of the
unusual +3 keyboard - in case
the PCW manual does something similar,
I'll describe what the keys are on
the NC100 here:
Key
Function
^A
Move back along line being written/edited
^F Move forward along line
^_ Move up on multi-line line (if you see
what I mean)
^^ Move down on
multi-line line
<-Del Delete
char to left of cursor
^G
Delete char under cursor (NB: Del-> also sends ^G)
^W
<char> Moves forward to specified character
^S <char> Delete
all between cursor and specified character
^S enter To delete to end of line
^I Toggle between insert and overstrike
(NB: Tab also sends ^I)
Stop
Abandon changes to program line
Basic (my copy at least) only
has around 16k available on startup.
This is unfortunate, but there isn't
much I can do about that with
only 64k total! (Note that MB *does not*
work with `bigrun', it
crashes the machine, so don't even think about
trying that!)
*** QTERM
Assuming you have QTERM
4.3f patched for ZCN (there's a copy in the
`support' directory), an easy
way to take backups is using YMODEM
batch transfers.
For
example, when logged into my Linux box I would run `rb' - a YMODEM
batch
receive program - then do ^\ s to send, then `xy *.*' to send
all the
files on the current drive. At 19200 baud on a full (256k)
drive this
takes between 3 and 5 minutes.
You may want to do `user 255' before
running QTERM if you have files
on the drive in other user areas - this
will make sure you backup all
files in all user areas. Be sure to see
`User Numbers' for more about
user area 255, as there are some potential
problems associated with
using it, particularly if two different files
exist on the same drive
in different user areas with the same
filename.
** Logical Drives
Cards of 256k or less
have only one drive, drive A:. 512k cards have
two - A: and B:. 1024k
cards, the largest allowed, have four, A:, B:,
C: and D:. These logical
drives are completely independent of one
another, but drive A: must be
formatted for drives B:, C: and D: to be
readable.
You make a
drive current by typing its name, e.g. `b:'.
** User
Numbers
[Note that I use `user', `user number' and `user area'
pretty much
interchangeably. Sorry if this makes it sound more confusing
than it
need be. :-)]
ZCN supports CP/M user numbers 0 to 15.
You can change user numbers
with the `user' command, but not (yet) in the
`0a:', `a0:' or `0:'
manner. This gives you a little more than a flat
filesystem (or disk);
you might describe it as a segmented filesystem, but
that sounds like
the partitioning scheme used on PCs, which it definitely
isn't
anything like. It's more like having 16 different directories - all
at
the same level - rather than one, and having them numbered rather than
named.
0 is the default `directory', or user area.
For the uninitiated -
user numbers were in CP/M to allow different
users of a CP/M machine to
keep their files separate. The way it
worked meant that they would have to
keep not just data files, but
also any programs they wanted to run, in
that single user area.
It gets worse; the way the feature was used
in practice meant that you
had a single user wanting to move files across
user areas, run
programs from other user areas, etc.
I'll admit
now that ZCN doesn't handle user areas very well at all.
However, this
section tells you what it does different from generic
CP/M.
(Note
that user numbers are separate from drives - i.e. if you do
`a:', `user
1', `dir b:' it will show all files in user area 1 of
drive B:.)
***
Prompt
The `A>'-style prompt is actually only used in the default
user area
0. In user areas 1 to 15, the user area is printed before the
`>', as
in `A1>'. In user area 255, it becomes `A*>', with the
`*' meant to
indicate the wildcard-like action of user 255 (see below for
more on
this user area).
*** Execution
When running
a COM or SUB file, ZCN tries the following things:
1. Try
current/specified drive and current user.
2. Try current/specified drive
and user 0.
3. If no drive was specified, try drive A: and user 0.
This
means that user area 0 (and especially user 0 on A:, if you're
using a
card larger than 256k) is a good place to put programs.
*** User
Area 255
In addition to the usual 0-15, ZCN allows you to use user
area 255.
This isn't a user area as such, but acts like all the files on
the
drive are in the current user.
User area 255 is mostly
read-only, though it does allow `umv' (see
below), and file deletion. The
reasoning behind it being read-only is
that files in different user areas
are allowed to have the same name.
If the file is written to, it's not
clear which file should be changed
or added to. Having two files with the
same name also causes problems
when reading from user area 255. You would
get (effectively)
randomly-chosen 16k chunks from any files with the same
name.
In general, you should only read files in user area 255 if
they only
appear in the directory listing once. The `ls' program, which
you
should probably be using in preference to `dir' anyway, will report
`***
WARNING: duplicate files found! ***' if two or more files share
the same
filename. (The warning will only appear once, no matter how
many filename
conflicts there are.)
This probably all sounds rather worrying, but
the situation's not
really that bad. If you make sure no filenames occur
more than once
across all user areas, you have absolutely nothing to worry
about.
Even if you don't, you just have to be sure to not read the
offending
files from user area 255. (You couldn't do this and get meaningful
results
in any case - how could ZCN tell which file you're referring
to?)
***
UMV internal command
This command allows you to move files matching
a given filespec from
the current user area to another, e.g. `umv *.com 0'
would move all
COM files in the current area to user area 0. An easy way
to put all
files in user area 0 is `user 255' then `umv *.* 0'.
**
Warning about using the Serial and Parallel ports
There is no
timeout when, say, the printer is busy or serial data
cannot be sent. ZCN
will simply keep trying. To interrupt this if it
happens, I'm afraid
you'll have to do a cold boot - turn the machine
off, then hold down both
shift keys while turning it back on.
Apologies for the inconvenience.
:-(
** Using the Serial Port or Printer as the Console
Under
ZCN it's possible to use the serial port (instead of the
keyboard/screen)
for console input and/or output. To use the serial
port for console output
you should use the command `>s'. For serial
input do `<s'. To use
the serial port for both input and output, use
`|s' (that's a pipe
character, as given by shift-\, then an `s').
To redirect console
input/output back to the NC100 itself, just use
the above without the
trailing `s', e.g. use `|' (pipe) alone to
restore normality. You can also
use `<' and `>' to only restore normal
input or output
respectively.
As well as serial redirection, you can direct console
output to a
printer connected to the parallel port. This is *as well as*
output to
the screen though, so you can see what you're doing. :-) For
printer
output of this kind do `>p'. You can also use `|p', which has
the same
effect as doing `|' then `>p'. (`<p' is also accepted, but
simply does
the same as `<'.) Again, you should use `|' to return to
normal.
A brief note in case it's not obvious - redirecting to the
printer
won't have the desired effect if you're printing to a
PostScript
printer. (ZCN's console output doesn't make much sense at the
best of
times, but it makes far less sense as a PostScript program,
trust
me...) Then again, if you're using a PS printer with an NC100
you're
probably completely insane, so maybe it won't matter to you.
:-)
Using the `semi' external command described later, a crude
but
effective way to print a text file is:
semi >p; cat file.txt; |
(The
`semi' should be replaced with a semicolon if you rename the
command as I
do; see the description of `semi' for details.)
ZCN makes the
following demands of a terminal (or terminal emulator,
or printer):
-
It must use ASCII encoding for characters 32-126 inclusive.
- When a CR
(13) is sent, it must move the cursor to the leftmost
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, lest you think I'm
incredibly dim or
some such... :-)]
*** Command Line Editing
The only
command line editing available is delete-previous-char, and
there is no
way to recall previous commands. Sorry.
You can abort the entered
command line without executing it by
pressing ^C.
*** Battery
level warnings
The low battery level warnings are part of the CCP -
if any of the
batteries are low, you get a warning printed before each CCP
prompt.
For example, if the main batteries are low, you get something
like:
*** Main batteries
low ***
A>
You
can keep using the NC100 under ZCN while batteries are low, but
you run
the risk of losing data etc. in memory should the battery
level get too
low.
If you do keep using the NC100 when batteries are low, you
should note
that if you need to use any of the builtin software (to reboot
from a
memory card after a crash, for example), it will demand that
you
replace the main/backup batteries (whichever is low) before
continuing.
(You could just run it off the mains adaptor for a while
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 512k
memory card says this:
The
battery condition is output from the card as a signal that some
computers can read. This signal will
indicate one of three states:-
1. Battery good.
2. Battery low, should be changed as soon as
possible. Data
maintained.
3. Battery
discharged, data LOST.
I strongly suspect that the NC100 treats
states 1 and 2 above as
`battery ok' and treats state 3 as `battery low'!
(Experimentation
seems to support this theory.)]
No battery
level warnings occur at any other time than when displaying
the CCP
prompt. If you have been using a program continuously for a
long time and
suspect that batteries may be low, you should quit to
the CCP to
check.
You can disable battery warning messages by doing `batwarn
0'.
By the way, the tests I've tried suggest that rechargeable
batteries
give roughly 8 hours use between rechargings (possibly more,
depending
on the type). It's more difficult to tell how long you generally
have
between the `batteries low' warning and effectively dead
batteries,
but it seems to be something like 30 minutes for
`conventional'
rechargeables. It's much shorter and more variable for
the
chargeable-in-two-hours kind - anything between 1 and 5 minutes.
***
Internal Commands
ZCN has several of the normal internal commands
provided by CP/M's
CCP, such as `dir'. It also provides many extra
commands which I found
useful, and modifies the behaviour of others. This
section lists the
internal commands (in alphabetical order), what they do,
and how to
use them.
Note that a few internal commands which
require args (a filename, for
example), such as `note' and `ren', will
just say "Args?" if they're
used without any.
****
!! [command args]
Jump to 100h, effectively running the previous
command again with new
arguments. You must *only* do this if you know the
command is
re-entrant, or if you like living dangerously. It can also be
used to
run a command previously loaded with `get' (see below).
****
"any text
Echo the text after the double quote (") exactly
as it appears (except
that the `$' character will terminate the line, if
it arises). This
one of the very few commands that does not have its
command tail
uppercased before it sees it (the others being ' and `%').
It's
intended for use in SUB files (see `SUB files' below).
A
variant of this command is similar but starts with a single quote
(').
This also echoes the text exactly, but omits the CCP's CR/LF
after echoing
it, meaning that the cursor stays on the same line.
****
%prompt_string
Set the CCP's prompt. (While you can use this command
anywhere, it's
really intended to be used in `autoexec.sub' so that ZCN
uses the
specified prompt all the time.) The maximum allowed prompt size
is 25
chars - if you try to specify one larger than that, it is
silently
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
use on my machine -
`rus@amnesia:/%e/%a>'. It gives a prompt not
dissimilar from the prompt
I use on my Linux box, and shows one way
you can get something which looks
a bit like a `path' into the prompt.
(MS-DOS users might like to try
`%d:\%a>' or `%d:\%b>' for a similar
effect.)
****
BATWARN <0 or 1>
Disables/re-enable low battery warnings. You
should use this like
`batwarn 0' to disable battery warnings if you
appreciate that the
main batteries are low (for example), but want to
carry on without
getting `*** Main batteries are low ***' in your face all
the time. Be
careful when doing this, because it's an inherently dangerous
thing to
do, and be sure to change the relevant batteries as soon as
possible.
**** BDOSDBUG <0 or 1>
Enable (or
disable) display of which BDOS function is being called as
it is called.
The function number is displayed in hex - for example,
`[0A]' would
indicate that the program is reading a line of text from
the console.
Enabling this output can be useful when debugging
programs. For various
reasons, functions 2 (console output) and 46
(get disk free space) are
treated slightly differently from other BDOS
functions, and as a result
are not reported on.
**** CAT filename
Display a
^Z-terminated text file from beginning to end, without
pausing. (^C
quits.)
(This means it's not a true `cat' command - that is, it
doesn't
concatenate files - but simply a synonym for `type'. Still, it's
handy
for Unix fans like me. :-))
**** CAPSCTRL <0 or
1>
Disable/enable swapping the functions of the `Caps Lock' and
`Control'
keys. (It's off by default - i.e. the keys do what they say they
do.)
This option may be useful if you like having a control key above
the
left shift key (rather than below it). That said, the `Function'
key
always acts like a control key no matter what.
Note that
this swaps the functions of the keys at quite a low level -
if you've
enabled the key-swapping, then whenever ZCN requires you to
press the
physical `Control' key (for screen dumps and for pausing
output) you will
*have* to use the `Caps Lock' key instead.
**** CBOOT
Cold
boot ZCN from the memory card. If the card is not bootable, or
there's no card
in the slot, ZCN will say "Bad crd/drv/format" rather
than
booting.
**** CD n
Set current user area to number `n',
or to number 255 if `n' is an
asterisk. If `n' is omitted, acts like `cd
0'. This alias for `user'
should make slightly more sense to MS-DOS and
Unix users, though the
flat `directory' structure in CP/M makes their `cd'
commands a poor
analogy, to be honest. Still, at least it's easier to
type, right? :-)
**** CRLF <0 or 1>
Disable (or
re-enable) the line-break (CR/LF) after a program exits.
Generally you'll
always want this on, but it can be useful to turn it
off temporarily in a
SUB file. (An easy way to get a CR/LF should you
need one after `crlf 0'
is to use `"' or `vdu 13 10'.) Just make sure
you remember to
re-enable it afterwards, or it'll all be a bit
confusing. :-)
Note
that this doesn't affect the CR/LF always output after you type
in a
command, so the effects of a `crlf 0' may not be immediately
obvious.
Doing `ver' should clarify matters.
**** CLS
This clears
the screen. (NB: this clears the entire screen, including
the top two and
bottom two pixel lines.)
**** DF
Report how much space is
free on all available drives. An example of
what the output's like: `A:=2k
B:=43k'. (The values will probably be
different for your card.) Only
drives which exist on the card are
reported on.
**** DIR
[filespec]
List the files in the current drive/user. If a filespec
is given, it
only shows files matching the filespec. The wildcards `*' and
`?' can
be used. If no file is found/matches, then the error `No
file'
results.
`dir' exists primarily for CP/M compatiblity,
and so that there's some
internal command to list files - see the `LS'
external command for how
to get a much better (sorted, and optionally with
file sizes)
directory listing.
**** DUMP filename
Give
a hex and ASCII dump of the specified file, pausing after every
128 bytes.
Bugs: if the file position is greater than 65535, it'll be
shown
incorrectly.
**** ERA (or RM) filespec
The CP/M-style
delete command. (ERASE and DELETE are not recognised.)
Delete all files
matching the filespec. Bugs: does not prompt when
deleting multiple files,
which it should really.
**** FORMAT d:
Format the given
drive. Cards of 256k or less are formatted as a
single A: drive. Cards
larger than that (512k and 1024k) are formatted
as two 256k logical drives
A:/B: or four drives A:/B:/C:/D:
respectively. On these larger cards, the
A: drive must formatted in
order to format and use any of the others. (The
logical drives are
formatted on an individual basis.) You can reformat one
of the logical
drives without harming any others.
So to fully
format a card of 256k or less, use `format a:'.
For a 512k card, do
`format a:' then `format b:'.
And for 1024k cards, do `format a:',
`format b:', `format c:', and
`format d:' in turn.
If the drive
is already formatted in ZCN format, you will be asked
whether to reformat
it. (It should if the drive is already formatted
in the ROM software's
format too, but I haven't tested this.)
**** GET hex_address
filename
Load a file in at the specified address (in hex). This is
useful for a
variety of things:
- Loading a COM file off one
card, then executing it with another in
the slot, e.g. `get 100 foo.com',
change cards, then `!!'.
- Patching a COM file after it's loaded.
You normally do this by
loading the COM file, then loading a small patch
over some part of it.
- Loading a previously saved screen dump, e.g.
`get f080 screen.dmp'.
This command makes it easy to crash the
machine if you don't know what
you're doing, so be careful, and check your
typing. If you miss out
the `1' in `get 100 foo.com', you'll soon know
about it. :-)
**** IFNPEEK addr val command [args]
If
byte at (hex) `addr' *does not* equal (hex) `val', run command,
otherwise
do nothing. This is primarily of use in SUB files.
See `ifpeek'
below for details.
**** IFPEEK addr val command [args]
If
byte at (hex) `addr' equals (hex) `val', run command, otherwise do
nothing.
This is primarily of use in SUB files.
Note that using a print
command (' or ") will result in all-caps text,
since ZCN didn't see
the command until after the `ifpeek' took place.
This is unfortunate, but
there's nothing I can do about it. (It also
applies to the `%'
prompt-setting command, but you're much less likely
to want to use that as
the command in an `ifpeek'.)
To abort a SUB file if some command
goes wrong, use `ifpeek ...
quitsub'. Obviously there has to be a byte in
memory which indicates
if the command worked or not!
To check
the value of 80h after the last command finished, use 3 as
the `addr'.
This is primarily intended to be used to check the exit
status of programs
compiled with Hitech C; however, there's no reason
you couldn't use it to
return an exit status from your own programs.
If you want to check if a
Hitech C command returned a non-zero exit
status - for C programs this
usually means it failed somehow - then
use ifnpeek instead, like this:
`ifnpeek 3 0 ...'.
The only command which does not have 80h copied
after it exits is
`rem'. (The same applies to a blank command-line, of
course, but
that's not really a command as such.) *ALL* other commands
and
programs have it copied when they exit, whether they change it or
not.
**** K3
Show how many K are free. :-) In other
words, show the amount of
memory available for running programs in, or the
transient program
area (TPA) as CP/M calls it. At the time of writing,
this will be 46k.
For any techies out there who may be interested,
the number given is
int((bdos_address-512)/1024). 256 of the 512
subtracted is to discount
the zero page, and the other 256 is to allow for
stack space. So it's
a realistic estimate of the maximum program
size.
**** MEMDUMP address
Show 128 bytes of memory, in
hex and ascii, from the address given.
The address should be given in
hex.
I consider this command to eliminate the need for a `peek'
command,
which you might otherwise expect as a counterpart to
`poke'.
**** MORE filename
Essentially, this is `cat' but
pausing after every ten lines. In order
to show as much at a time as
possible, you aren't prompted to press a
key to continue, as such; instead
the cursor is moved to the
bottom-right hand corner of the screen to
indicate that there is more
text waiting to be shown. There is no way of
moving back through the
file. (^C quits.)
**** NOTE
filename
This command lets you type text into a file. (Any existing
file will
be overwritten.) There's no editing, and no prompt - it's quite
crude,
but being an internal command it is at least always there. You
just
keep typing text until you're done, then type in a line
consisting
solely of a single `.' (full stop).
Mainly this is
handy for those awkward situations where you for some
reason don't have a
text editor like ZDE handy, but need to make a
quick note or something
like that.
Don't do a ^C to exit - if you do, the text isn't saved
(`note' builds
the text up in memory, and saves when you're finished). If
you should
do this, though, you could salvage the text with `save', as the
text
starts at 0100h.
**** POKE addr val
Set the
byte at address `addr' to value `val'. The address and value
must be in
hex.
I said this in the description of `get', but it applies equally
to
`poke', so I'll repeat it: This command makes it easy to crash
the
machine if you don't know what you're doing, so be careful, and
check
your typing.
Using the internal commands `get', `poke',
`memdump', and `save' is a
bearable way to patch programs and other files
if you haven't got a
better way of doing it. (And of course, Real
Programmers write all
their programs using `poke'. :-)) However, I
recommend using `wade'
for patching programs/files if at all
possible.
**** QUITSUB [command [args]]
Abort any
currently-running SUB file. This is only useful in SUB
files (of course
:-)), and usually only useful in combination with
`ifpeek' or `ifnpeek'.
If a command is specified, that command is run
afterwards.
****
REALBEEP <0 or 1>
This disables/enables a real (noisy) beep in
place of the `visual'
one. If you like having a real beep you could put
`realbeep 1' in
`autoexec.sub' to have it automatically enabled.
****
REM (or #) [any text]
This command does exactly nothing. It allows
you to put comments in
SUB files.
**** REN file1 file2
Rename
file from file1 to file2. Wildcards are not permitted.
Note that
this is *not* the way the command works in CP/M - on that,
the syntax is
rather strange, effectively `REN file2=file1' [sic].
**** REXEC
filename
This reads a uuencoded file from the serial port, decodes
it, and
writes the resulting binary file under the filename given. (It
outputs
a `.' for each line received.) The name stands for `Remote
EXECute',
as the command used to just execute the (command) file after it
was
transferred. That dates back to the time when I was running ZCN with
a
16k TPA, a 32k ramdisk, no PCMCIA card and my fingers crossed. :-)
After
ZCN stabilised a bit, I changed `rexec' to work as it does now,
which is
almost certainly more useful. (In any case, you could get the
old
behaviour if you really needed it by removing the card, doing
`rexec foo'
(it'll say "No file" but the copy in memory is fine), then
doing
`!!'.)
It's intended for getting a real serial transfer program
across, such
as QTERM (which I recommend). It won't work (will probably
crash!) if
files bigger than TPA are transferred.
**** SAVE n
filename
Save `n' pages of memory, starting from 0100h, to file
specified. A
page, in the context of this command, is 256 bytes. This
is
traditionally used to save COM files after patching, but can be
useful
for other things too.
**** SERTEST
A very simple
terminal program. It just echoes serial input, and sends
keyboard input to
the serial port. This can actually be very, very
useful if you're using
your NC100 as a terminal to a Unix box with a
suitable termcap/terminfo
entry as given earlier. You can use ^\ then
q (or ^\ then ^C) to quit; ^\
then ^\ sends a literal ^\.
**** SETBAUD [digit] (removed in ZCN
v1.2)
In versions of ZCN prior to v1.2, `setbaud' set the baud rate
the
serial port ran at, using a single digit (`4' for 2400, `5' for
4800,
`6' for 9600, etc.). It was replaced with the rather less
inscrutable
`stty', but for masochists, an emulation of the old `setbaud'
is
available in the `utils' directory, as `setbaud.sub'.
****
STAT (removed in ZCN v1.1)
In versions of ZCN prior to v1.1, `stat'
gave a few bits of useful
information, for example:
Sys upgrd
spc: 15 bytes
Max prog size: 45k
Free on drivs: A:=2k B:=43k
As
you may already realise, the second line was replaced by `k3', and
the
last line by `df'. (Most people won't miss the first line. :-))
In
case there's anyone who misses `stat', or thinks it sounds useful,
I
knocked up an external command `stat' (i.e. stat.com) which emulates
it.
(Note
for those who want to hack ZCN: `Sys upgrd spc' reported the
amount of
unused space between the ZCN system code and the ZCN static
data area
(starting at E600h) allowed for upgrading before the origin
(in main.z)
has to be moved down. You *can* still get at this number -
it's stored at
start+15 (see main.z) - but it's more tricky now. Do
`memdump 7', then do
memdump for 256 times the byte displayed there
plus 15; so e.g. for BBh,
you'd do `memdump bb0f'. The word there
(though the high byte should
always be zero) is the number you want.
It's probably easier to just use
stat.com instead... :-))
**** STTY baud_rate
Set baud
rate of serial port. The default is 2400 baud. Supported
speeds are 150,
300, 600, 1200, 2400, 4800, 9600, and 19200 baud.
Which baud rate is
best to use depends on what equipment you're using,
what you'll be doing,
etc. Assuming the `other end' is capable of
anything up to 19200 baud,
here are some guidelines:
If you want to do file transfers, you
should be able to do so without
losing any packets even at 19200 baud. (If
you get too many errors,
use 9600 baud instead - that should definitely
work. But I've never
had any problems with 19200.)
If you want
to use the `other end' interactively, i.e. if you want to
use a terminal
emulator, then you may need to use a lower speed to
avoid losing
characters.
Now, consider these facts:
- ZCN has a
768-byte serial input buffer.
- The screen driver can only write
characters at a speed of between
about 110 and 800 chars/sec, depending on line length (i.e. how
often it needs to scroll). (This is as
tested with the built-in
`sertest'
program; with an external program like QTERM there is
system call overhead, etc.)
- ZCN
uses one start bit, 8 data bits and 1 stop bit which means that
the maximum number of chars/sec you can
transfer at a given baud
rate is
baud_rate/10.
If you assume a short line length (which slows things
down because of
the more frequent scrolling required), you get these
results (I
haven't bothered with speeds lower than 1200 baud; using such
speeds
makes watching paint dry seem like a exciting spectator sport):
baud
rate chars/sec time to first lost character (sec)
1200
120 768/( 120-110) = 76.80
2400 240 768/( 240-110) = 5.91
4800 480 768/(
480-110) = 2.08
9600
960 768/( 960-110) = 0.90
19200 1920 768/(1920-110)
= 0.42
Note that the `time to
first lost character' indicates the time to the
first time the buffer is
full when a character needs to be added
(which causes a lost character)
rather than the time to when the
display catches up and the lost character
is noticeable, which may
well be rather longer.
Assuming a more
reasonable line length (about 78 chars/line) you end
up with:
baud
rate chars/sec time to first lost character (sec)
1200
120 768/( 120-800) = (never)
2400 240 768/( 240-800) = (never)
4800 480 768/(
480-800) = (never)
9600
960 768/( 960-800) = 4.80
19200 1920 768/(1920-800)
= 0.69
So, what does this all
mean? Well, it depends on how you look at it.
In my experience, 2400 is
reliable except in extreme cases (the
extreme case being long bursts of short
lines - you need about 1500
bytes of short lines continuously to start
losing chars at 2400). 4800
can usually keep up too, though it's more
prone to buffer overruns.
You can use higher speeds if you want - they'll
work, but you'll lose
characters increasingly frequently as the buffer
fills up. Personally,
I just use 19200 the whole time. It's great for file
transfers, and
the input buffer can generally handle the bursts of output
when I use
it as a terminal at that speed.
One final note: If
there's no more than a screen full of text
transmitted at a time - for
example, if you're just using an editor on
the remote host - then you can
probably get away with using any baud
rate. The reason is, assuming only
80 columns are used and 10 lines,
you get a max of 800 chars per screen
refresh (usually less due to
status line(s) etc.), and a single burst of
that size can (just
about!) be dealt with every second or two.
****
SYS d:
Add the system to a drive and make it bootable. I recommend
you only
make A: drives bootable, as booting from B:, C: or D: means
remembering
different, awkward, boot procedures. Cards can be made
bootable (and
unbootable again - see `UNSYS' below) without harming
any files held on
them. The system blocks needed are effectively taken
from the end of the
drive. If this is not possible an error message is
given. (You may want to
try `defrag' on the drive then try `sys'
again, if `sys' fails when you
think it should have worked.)
**** TIMEOUT [mins]
Set the
auto-poweroff timeout in minutes. Use `timeout 0' to disable
auto-poweroff.
The default setting is 5 minutes. The maximum possible
setting is 10
minutes.
**** TYPE filename
Display a ^Z-terminated text
file from beginning to end, without
pausing. (^C quits.)
****
UMV filespec n
Move files matching `filespec' to user number `n'.
Wildcards are
permitted. If any files with the same names as those to be
moved exist
in user `n', then the error "File exists" is given
and *none* of the
files are moved. (Sorry if this is a pain but it seemed
like the best
way to do it, all things considered.)
**** UNSYS
d:
Remove any system blocks from a drive, returning them to the
normal
data blocks area, and makes the drive unbootable. Like `sys',
this
doesn't harm any files on the drive.
**** USER [n | * |
-]
Set current user area to number `n', or to number 255 if `n' is
an
asterisk. (`CD' does the same.) If `n' is omitted, i.e. if plain
`user'
or `cd' is used, then it acts like `user 0'. If `n' is a dash
(`-'), then
the user area most recently set by `user' or `cd' is used.
**** VDU
char_value [char_value]
Output one or two characters, given their
ASCII value. This is
primarily useful for outputting control codes in SUB
files.
**** VER
Report ZCN and ROM version numbers, and
the date/time (in YYYY-MM-DD
HH:MM format) the running copy of ZCN was
assembled.
The ROM version is reported by looking for the text `ROM
v' in the
first 16k of ROM, then printing the version number found there.
If the
text `ROM v' isn't found, then the ROM version number isn't
reported.
(The version number is from the built-in test program though, so
this
should be ok. Certainly it works on my machine. :-) By the way,
you
can run the (undocumented) diagnostic test program by holding
down
Function and Symbol when turning on. You have to reset the
machine
before doing this (or use `runrom') if you were previously using
ZCN -
it's a bit picky.)
**** XYZZY
Traditional.
:-)
It displays the message `Nothing happens.' If you want to know
*why*
it does that, read on:
:xyzzy: /X-Y-Z-Z-Y/, /X-Y-ziz'ee/,
/ziz'ee/, or /ik-ziz'ee/
adj. [from the ADVENT game] The
{canonical} `magic
word'. This comes from {ADVENT}, in which the idea
is to
explore an underground
cave with many rooms and to collect the
treasures you find there. If you
type `xyzzy' at the appropriate
time, you can move instantly between two otherwise distant points.
If, therefore, you encounter some bit of
{magic}, you might
remark on
this quite succinctly by saying simply "Xyzzy!"
"Ordinarily you can't look at someone
else's screen if he has
protected it, but if you type quadruple-bucky-clear the system
will
let you do it
anyway." "Xyzzy!"
Xyzzy has actually been implemented as an
undocumented no-op
command on
several OSes; in Data General's AOS/VS, for example, it
would typically respond "Nothing
happens", just as {ADVENT}
did if the magic was invoked at the wrong spot or before a player
had performed the action that enabled the
word. In more recent
32-bit versions, by the way, AOS/VS
responds "Twice as much
happens". ...
--
The Jargon File, version 3.2.0; every so often a version
is published as "The New Hacker's
Dictionary".
I hope ZCN breaks new ground by being the first OS
to *document* an
xyzzy command, but I expect someone else beat me to it
somewhere. :-)
*** External Commands
Of course,
external commands (i.e. separate programs) are generally
much more useful
than the simple internal commands provided. You can
run two different
kinds of external commands - COM files or SUB files.
Both are invoked by
simply typing the filename (without the `.com' or
`.sub') and any
arguments.
To run an external command with the same name as an
internal command -
say, for example, you have a `dir.com' you want to run
- give an
explicit drive specification (e.g. run it with `a:dir'). This
prevents
ZCN from trying to interpret the command name as an internal
command.
If you want to get straight to the list of external
commands ZCN has,
then skip the next few sections. (You should probably
come back to
them later, though.)
**** COM files
These
are binary executables loaded in at, and started from, 0100h. If
a program
is too big for the transient memory, ZCN gives a `too big'
message.
Execution of a program can be aborted after the command is
given, i.e.
while it's loading, by pressing ^C. This will be
acknowledged after the
COM file has loaded. (ZCN only tests for ^C
once, after it's finishing
loading the program, to avoid slowing down
the loading process.) Pressing
^C while the program is loading also
terminates any currently running SUB
file.
**** SUB files
These are normal text files which
give lists of command lines to
execute. Any commands can be run from a SUB
file, including all the
internal commands. Unlike CP/M, ZCN does not
display each line as if
it was entered. (It does still print a CR/LF after
each command by
default, but you can use `crlf' to disable (and re-enable)
this.)
ZCN runs a SUB file called `autoexec.sub' (on drive A: in
user 0) on
bootup if it can find it.
**** SUB files with
parameters
ZCN itself doesn't allow you to pass any parameters to
the commands in
a SUB file. However, you can use the external program
`submit' to do
this. Submit translates `$1' in a SUB file to the 1st
argument given
to the submit program (after the SUB file's name), `$2' to
the 2nd,
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.
Just consider it
a gedanken example. :-))
You can get a single `$' character in the
output file by using `$$' as
you can see above. Note that aside from that,
`$1' is translated to
`bar' and `$2' to `baz' throughout the file, even in
the `rem'
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 ZDE by typing ' then ^P then ^L.
In CP/M
submit, you must specify at least as many arguments as the SUB
file uses,
otherwise it'll bomb out with the error `Missing argument'.
In ZCN v0.3,
submit worked this way. I changed it to be similar to
MS-DOS batch file
and Unix shell script behaviour in ZCN v0.3a - ZCN
submit now replaces
unspecified args with a space - as the CP/M
behaviour is almost always not
what you actually want. (Ironically,
the above `print.sub' is a notable
exception. :-))
Note that the format of `$$$.sub' is exactly the
same as that of
ordinary SUB files - a normal text file with one command
per line. I
don't think this is the case with CP/M, so generic CP/M
programs which
generate `$$$.sub' files are unlikely to work as intended.
I might add
support for CP/M-style `$$$.sub' files at some point. With
emphasis on
the `might'. :-)
**** ZCN external
commands
ZCN comes with several (optional) external commands,
described below
in alphabetical order. I recommend you copy at least `ls',
`optdir',
and probably `submit', across to your NC100; those are certainly
the
most useful, and they're all under 1K. Makes a change from most
programs
these days. :-)
***** BBCBAS [-H] [filename]
[This
is a *BIG* section - it takes up about 20% of this file! You may
want to
skip through most/all of it if you're not interested in BBC
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.
******
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. This
is FAR more
useful than `EDIT' and considerably more flexible. Essentially
it lets
you copy text from anywhere on the screen, from lots of
different
lines if you like, and you can copy *any* text, not just
pre-existing
parts of your program. See the section `The copy cursor'
below for
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.
- Online help of sorts.
Specifically, lists of the PLOT commands and
VDU codes, and a brief
example of how to use the built-in Z80
assembler. See the section `Online
help' below for details.
- A more fitting *CAT (a.k.a. *.) command,
based on `ls'.
- You can use it via the serial port. (Though
graphics commands still
only work on the NC's screen, of course.) There
are a couple of
problems with this, unfortunately; see the `Bugs' section
below.
- When you use EDIT, the cursor starts at the end of the line
rather
than the start, which is more likely to be what you'd want. The
copy
cursor is much better for editing than EDIT though, so it's
questionable
how much use this really is. :-)
- Values of certain keys returned
by INKEY make more sense. ^H returns
8, not 227; ^P returns 16, not 222;
and Del-> returns 7, not 33.
****** Disadvantages of
running BBC Basic in ZCN
- OPENUP does not allow writing to files;
it instead acts like OPENIN.
I think OPENIN/OPENOUT should be sufficient
for the great majority of
file operations, but all the same this is
probably the biggest single
disadvantage with running BBC Basic on
ZCN.
- The "COM:" file (which, when used with
OPENIN/OUT/UP under the ROM
software, accesses the serial port) is not
supported. However, you can
still use the serial port as a printer with
e.g. `*PRINTER 1' then
`VDU 2'. (The default printer is the parallel port
one, of course.)
- There's no support for text windows. (Graphics
windows still work.)
- There's no way to access files in different
user areas than the one
Basic is started in. (Strictly speaking this isn't
a disadvantage
relative to the ROM s/w as that doesn't have user areas
:-), but it's
a problem all the same.)
- A maximum of three
files can be open at once, rather than the ROM's
usual seven. This limit
is at the file I/O interface level rather than
being anything to do with
Basic, so e.g. if you do *LOAD or *SAVE from
a program when three files
are already open, the *LOAD/SAVE won't
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. Even if you
don't think that, you could always write the
Basic as a text file in ZDE,
then load it with *EXEC. (Neat little bit
of buck-passing there, don't you
think? :-))
- Keyboard `typeahead' is limited. If you press a key
while Basic is
grinding away at some calculation, it won't be buffered,
and the
keypress is ignored (except for Esc, which is dealt with
specially).
In particular, it means that I've had to make `INKEY(0)' take
up to
1/100th-sec to ensure that it doesn't miss any keys. I'd imagine
this
is unlikely to be a problem for most programs, but it could be
a
problem for, say, games.
- *KEY is not supported. Any attempt
to use *KEY will give a "Bad key"
error. (Apart from *KEY0 to
*KEY3, which give various help texts.)
- The time cannot be set with
the TIME$="..." construction. (Any
attempt to set it is
ignored.) You'll have to use ZCN's `timeset'
command to do that. However,
you can still *read* the time via TIME$.
- The values returned by
INKEY for the cursor keys are the same as the
keys generate in ZCN. This
means the values vary from those returned
under the ROM s/w. This is
probably a disadvantage, not least because
you can't tell the difference
between e.g. cursor-left and
control-cursor-left (you can on the ROM
s/w).
- ZCN's auto-poweroff timeout may run down very slowly if you
leave a
program running which doesn't do any I/O or use ZCN at all (a
simple
example is REPEAT:UNTIL 0). So if you think that's a problem, don't
do
that. :-) The timeout runs down ok if a program isn't running, or
if
(say) the program is left waiting for input.
******
Other differences and things to note
- *DELETE works for wildcards,
too. Be careful!
- In ZCN, you have to use either *BYE or *QUIT to
exit. These work
when running under the ROM s/w too, of course, but
they're the *only*
way to exit in ZCN. (Well, unless you want to reboot...
:-))
- BBC Basic's graphics commands normally use the full 480x64
screen.
ZCN, however, uses a 32x1 area in the bottom-left of the screen
to
show its "drive lights". The way this is dealt with is that
these are
only shown when ZCN is paged in, and the previous contents of
that
area are restored when BBC Basic is in control again.
-
While ZCN itself normally only has character bitmaps for printable
ASCII
chars (those in the range 32 to 126), `bbcbas' contains some
extra code
and character bitmaps so that it provides Basic with the
same characters
in the range 128 to 255 as Basic has when running
under the ROM software.
You can do `FOR F=128 TO 255:VDU F:NEXT' to
see them all. (The various
accented characters are rather indistinct,
I'm afraid, but most of the
characters are perfectly usable.) You
can't enter these non-ASCII chars
direct from the keyboard (with the
exception of the pound sign (shift-3)),
so to print the square root
symbol for example you'd have to use VDU 251
or PRINT CHR$(251).
- In ZCN, caps lock isn't set when running BBC
Basic. Instead what
happens is that any keys input have their case
inverted (upper to
lower and vice versa). This is generally preferable, as
this approach
even works when running via serial, but I'm just mentioning
it here in
case anyone wondered how it worked.
******
Bugs
- When using BBC Basic via the serial port, it's possible
to
occasionally `hang' the machine. What's actually happening is that
the
serial hardware has got confused (the weird things I have to do to
get
the Basic running seem to cause this every so often) and stopped
reading
from the port, not that the machine has actually hung as such;
turning the
machine off then on again resets the serial hardware, and
should clear the
problem.
- When running via the serial port, normal ZCN control
codes are sent
for clear screen, cursor movement, cursor on/off etc., so
the
appropriate commands in Basic won't work. You may also get some
funny
chars appearing (usually the cursor on/off codes) depending on
your
terminal or terminal emulator.
- PTR# and EXT# do not give
correct results for text files; this is
due to CP/M (and ZCN) not storing
the length of text files exactly,
and (for PTR#) due to the CR <->
CR/LF conversion involved. *However*,
saving a PTR# value to return to
later works ok, which should cover
most uses of it with text files.
-
The copy cursor doesn't work for chars in the 128-255 range, such as
the
pound sign and line-drawing chars.
- The copy cursor doesn't flash.
This makes it a bit easy to `lose' if
you're not careful.
-
Finally, here's a bug I found in BBC Basic itself, which applies
equally
when running under ZCN or the ROM s/w. In immediate mode, i.e.
when not
running a program, it seems that if you type a string of more
than a
certain length (five chars, I think) after `INPUT A$' (or any
other string
input), you get prompted again. It's quite strange. It's
probably largely
harmless though, as INPUT works ok when a program is
running.
******
The copy cursor
The original BBC Basic - yes, the one on the BBC :-)
- had a
remarkable feature which made editing on it easier and more
flexible
than on most other Basics at the time, and I think it still
stands up
well today. It was the ability to copy text from anywhere on
the
screen and insert it as if you'd typed it from the keyboard.
This
worked by you moving a second cursor around the screen and
pressing
`copy' whenever you wanted to copy a character.
`bbcbas'
supports this. It works in exactly the same way, except you
use the tab
key as the `copy' key, and you can use ^E/^S/^D/^X instead
of the cursor
keys if you prefer.
For those of you not already familiar with the
idea, here's how it
works in detail. Normally when you type text in, you
have a cursor
which shows you where new characters will be inserted.
Simple enough,
and everyone's used to that. But under this scheme, when
you press a
cursor key you get two cursors. One remains where the normal
cursor
was (in fact, it *is* the normal cursor :-)), showing you where
new
chars will go. But the other, which looks like an underscore and
can
be moved around the screen with the cursor keys, shows you where
a
char will be copied from if you press `copy' (tab). Both cursors
are
advanced when you press this key, and the copy cursor wraps at
the
edge of the screen in the same way as the normal one (and even
moves
up the screen if it scrolls) meaning you can hold down the key to
copy
many chars.
You can move the cursor around as much or as
little as you want, and
copy anything. You can copy a bit, type a bit,
copy a bit - it all
works in a pretty sane manner and does what you'd
expect. The only
limitation is that the text must not have been
`corrupted' - for
example, if you draw graphics all over some text, you
won't be able to
copy it. (Also, I'm afraid you can't copy italic or bold
text and the
like; only normal text works.) If you *do* try to copy
corrupted text,
or something which isn't text at all, the character
inserted is a
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"
Yes,
I'm afraid you really do have to enter it, no matter how much you
may
disagree. (cough) Besides, we're just about to `correct' it... :-)
To
edit it, move the copy cursor up to the start of the line. (If the
line
weren't already onscreen, you'd first list it with `LIST 10' or
similar.)
A single cursor up should do. Then press tab several times
(or hold it
down), with the last character you copy being the space
before the `S'.
Now type `IS COOL'. You may have noticed that the copy
cursor didn't move
when you typed that. (Not too surprising - after
all, we didn't copy those
last few chars from it.) To compensate for
that, press cursor right five
times (skipping the `SUCKS'), and finish
off by copying the rest of the
line by pressing tab a few more times
(or holding it down), then pressing
enter.
So, after the editing, do `LIST' and you should have:
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.
Once you've used to
using the copy cursor, you'll wonder how you ever
got by without it.
Really. Trust me. :-)
(By the way, as a final note on the copy
cursor, I should just point
out that the cursor appearances may be a
little odd to someone used to
a BBC. On the beeb, the usual cursor is an
underscore-ish one, and
when you press a cursor this becomes the copy
cursor, with the usual
cursor being replaced by a block one. With `bbcbas',
you still get a
block cursor and an underscore cursor, but the current
(block) cursor
stays where it is. I don't know if this makes sense or not,
but it was
easier to code that way so that's how I did it. :-))
******
About text files
As you may or may not know, text files in CP/M are
stored with a `soft
EOF' marker, ^Z. This is used because files are always
a multiple of
128 bytes long in CP/M, and this is inconvenient for text
files. Also,
while (on the NC100 at least) BBC Basic's OPENIN and OPENOUT
expect CR
as an end-of-line marker, CP/M uses CR/LF.
Now, BBC
Basic itself has no facility for distinguishing between text
and binary
files (because it doesn't normally need one), so I had to
use an unusual
way of allowing you to read/write a file as text. I had
to use something
in the filename.
The way it works is this:
- If you give
a normal filename, the file is read/written as binary.
This is how you
should use LOAD, SAVE, *LOAD, and *SAVE.
- If you give a filename
starting with colon (`:'), the file specified
by the rest of the filename
is read/written as text. (^Z is treated as
EOF on reading, one or more
^Z's are written by CLOSE on writing, and
CR is converted to CR/LF or vice
versa as needed.) This is how you
should use *EXEC and *SPOOL, and is also
how you should use OPENIN or
OPENOUT when the file is a text file.
Here
are examples of both. First, some commands using binary files:
SAVE "FOO"
*LOAD WIBBLE 4000
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 ZDE, deleting
the
extraneous bytes (if any), and saving. (If there aren't any junk
bytes
at the end, which is actually quite likely given how defensively
I
wrote the I/O code, just save it. You'll need to answer yes when
ZDE
reminds you that it's unchanged - it may indeed be unchanged, but
ZDE
writes it as a CR/LF file with ^Z at EOF, so you *do* want to
save
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.
****** Online
help
There's a small amount of online help provided. Since BBC Basic
is in
ROM and doesn't have a *HELP command nor any way to provide
one,
there's no way I could have provided it like that - sorry.
Instead,
you get the help using *KEY.
`*KEY' (or `*KEY0')
brings up a brief message saying what `*KEY1',
`*KEY2', and `*KEY3'
do.
`*KEY1' lists what the various PLOT commands do. It may not come
as a
surprise to find that being able to always have this list handy
was
the main reason for implementing this online help feature. ;-)
`*KEY2'
lists what the VDU codes in the range 0 to 31 do.
`*KEY3' gives a
brief example of how to use the built-in assembler.
Unfortunately,
these help texts are only printed to the console - even
after `VDU 2' they
won't appear on the printer, nor are they
susceptible to *SPOOL (which is
a pity for the *KEY3 text in
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 <key
is ignored>
Control-Tab 9 (^I) 225
Control-Menu 0 212
Control-Del-> 7
(^G)
5
Control-<-Del 31
(^_) 212
Control-up 5
(^E) 248
Control-down 24 (^X) 249
Control-left 19 (^S) 250
Control-right 4
(^D) 251
Note that,
unfortunately, you can't tell a control+cursor keypress
apart from a
normal cursor keypress on ZCN. (Symbol+cursor works
though; that just adds
128.) Also, many control+key keypresses return
strange values in the ROM,
and many control+shift+key keypresses are
simply ignored.
-
How to pause a LIST (or anything else)
Since the NC100's version of
BBC Basic doesn't support the BBC's
page-mode VDU codes, there's a need
for an alternative means of
pausing (say) LIST. When running under the ROM
software you can press
Esc to pause, then any other key (other than Esc)
to continue. When
running under ZCN you can use ZCN's usual ctrl-symbol
technique to
pause it - i.e. you can pause the output by holding both the
`control'
and `symbol' keys simultaneously, and the output starts again
when you
let go. ZCN's approach has the advantage that Esc always does the
same
as it would on a BBC, and you can pause with ctrl-symbol even during
a
GET or INKEY (which under the ROM s/w you can't, as in those
situations
a single Esc escapes immediately).
- What the values used with
`LISTO' mean
The manual mentions LISTO but not what the values mean.
Here's a table
showing them:
value space after line no.? indent
FOR..NEXT? indent REPEAT..UNTIL?
0 no no no
1 yes no no
2 no yes no
3 yes yes no
4 no no yes
5 yes no yes
6 no yes yes
7 yes yes yes
The
NC's BBC Basic defaults to format 7. I think generally you would
want to
use either format 7 or format 1, but obviously it's up to you.
To
set the default LISTO setting for `bbcbas', set the byte at offset
4 in
the file to your preferred LISTO value. The easiest way is to use
wade,
doing something like this:
A>wade
bbcbas.com
WADE 1.5 - Wagner
85-04-27 (TurboDos & CP/M 2
Version)
Low=0100 High=1F7F
Max=1F7F Top=85FF
:s104
x <-- replace `x' with
your LISTO value
:w l h <-- the middle char is an
L, not a one!
:g0
A>
After
doing that, you can use `bbcbas -h' to check the default is now
your
preferred LISTO value.
- How `RND' *really* works
The
manual only describes 3 of the 5 possible ways to use BBC Basic's
terribly
nice RND function (that it failed to mention the vitally
important RND(1)
is almost beyond belief!), and its description of
what `RND' by itself
does is wrong.
Here's a quote from the Electron manual which applies
equally to the
NC100:
(notes in square brackets are mine)
"RND
by itself generates a random whole number between -2147483648 and
2147483647.
[i.e. between -(2^31) and (2^31)-1]
RND(-X) gives the value -X and
resets the random number generator to a
number based on X. [i.e. sets the
seed]
RND(0) repeats the last random number given by RND(1).
RND(1)
generates a random number between 0 and 0.999999. [More
strictly, >=0
and <1. Given the limits of Basic's floating-point
accuracy, the
maximum possible random number is about
0.99999999976716935635, though
this would normally be printed as 1 -
if you set `@%' to &2020, it's
printed as 0.9999999996.]
RND(X) generates a random whole number
between (and possibly
including) 1 and X."
NB: One
important detail not mentioned above is that RND(0) gives an
incorrect
value if a different form of RND (other than RND(0)) was
used since the
last RND(1). (This is the case on the BBC and Electron
too, by the
way.)
- CLOSE#0
CLOSE#0 closes all currently open
files. It works even if no files are
open.
- TOP
The
manual mentions the variables PAGE, LOMEM, and HIMEM, but not TOP.
To
quote the Electron manual, TOP contains "the address of the first
free
memory location after the top of the BASIC program. TOP-PAGE will
give the
length of your BASIC program in bytes."
TOP usually has the
same value as LOMEM.
- COUNT
The manual mentions
POS, but not COUNT. While POS is the current
horizontal char position,
COUNT is the number of chars output on this
line. (This may differ after a
PRINT TAB or whatever.)
- About `ON' and `ON ERROR'
The
manual incompletely describes `ON', so let's just fill in the
gaps...
Normal
`ON' (which picks a line number to GOTO based on the value of
the
expression tested) does not work the way it does on, say,
Microsoft Basic.
Here it gives an error if the expression is outside
the range for which
line numbers are specified - on most other Basics
it simply `falls
through' in that case. However, a more flexible `ON X
GOTO ... ELSE ...'
form is allowed by BBC Basic, which can be used
like this:
ON X GOTO 100,200,300 ELSE 400
...but
also for other commands, for example:
ON X GOTO 100,200,300 ELSE PRINT "Bad
option":ENDPROC
To make it `fall through' like on other Basics,
you can use:
ON X GOTO
100,200,300 ELSE
A different form of ON is `ON ERROR', which says
what to do when Basic
would normally stop and report an error. The manual
describes `ON
ERROR GOTO' and `ON ERROR GOSUB', but says no more than
that. Well,
the first thing to say is that you can turn error trapping off
with
`ON ERROR OFF'. But probably more important is that the `ON ERROR
foo'
form of the statement (for all cases except foo="OFF") is
treated a
bit like a hypothetical `IF ERROR THEN foo' statement would be;
that
is, you can have *any* statement after the `ON ERROR'. You can
even
have multiple statements, like this:
ON ERROR PRINT "Oh dear...":PROCerrorhandle:END
But
the NC100's BBC Basic seems very easy to inexplicably lock up with
exotic
forms of `ON ERROR' (it seems to forget to cancel the error) -
in fact,
the only form which seems at all reliable in my experience is
`ON ERROR
GOTO'...!
- `REPEAT UNTIL FALSE', `CLS PRINT "FOO"',
etc.
This is an odd, but kind of useful, feature of BBC Basic which
doesn't
usually seem to be very well documented.
If you have a
Basic statement which is complete unto itself and could
not possibly be
extended, such as arg-less keywords (e.g. `REPEAT',
`CLS') or keywords
with a fixed number of args (e.g. `CLOSE#',
`DRAW'), then the colon to
separate the statement from one which
follows it can be replaced by a
space. Here are some examples:
REPEAT
UNTIL INKEY$="Q"
MOVE
0,0 DRAW 50,0 DRAW 50,50 DRAW 0,50 DRAW 0,0 REM square
It's not
clear whether taking advantage of this is a good idea or not
in general.
It seems reasonable to use it for empty loops, but much
more than that
would probably be confusing, I think.
By the way - it can, it seems,
be extended to *any* context where its
use is unambiguous, e.g.:
FOR F=1 TO 4500 NEXT REM wait about 3
seconds
A=TIME FOR F=1 TO 10000
NEXT F PRINT TIME-A REM time the loop
...but I'm pretty sure that's
simply *too* confusing, full stop. :-)
Only the uses described in
the initial paragraph above seem to work on
other versions of BBC Basic -
the looser uses immediately above won't
necessarily work. If this sounds
confusing, you may be best off
avoiding this slightly shady area
entirely... :-)
- OS commands (e.g. `*ESC OFF') can't be
followed by Basic statements
What I mean by that is that this kind
of thing won't have the desired
effect:
*ESC OFF:PRINT "FOO"
If you need a
multi-statement line with an OS call somewhere other
than the end, you
could use OSCLI instead, e.g.:
OSCLI("ESC
OFF"):PRINT "FOO"
- Integer variables
(Integer
variables are mentioned only implicitly and fleetingly in the
manual
(blink and you'll miss it), and don't seem to be mentioned at
all in
"NC100 Magic".)
Use a `%' suffix on a variable name and
the variable referred to is a
32-bit signed integer (variables are
floating-point by default). These
are considerably faster than the default
FP variables and take up
slightly less memory. (But that extra `%' on
every reference means
that, in practice, using integer variables takes
*more* memory, not
less.) Note that `FOO%' and `FOO' are different
variables.
- `&'
You can prefix a number with
`&' to indicate that the number is in
hex. For example, `A=&2A' is
the same as `A=42'.
You can print in hex with, say, `PRINT ~A'. This
is mentioned in the
NC100 manual, but this is a good place to put a
reminder. :-) One
related point which *isn't* mentioned there is that you
get a string
with a hex representation in with something like `A$=STR$~A'.
Note the
syntax; `STR$(~A)' doesn't work.
- How to do
`peek' and `poke'
This is only hinted at in the manual, so here's
some examples showing
the various ways you can get directly at
memory:
First, the various `poke' operations:
?&4000=42 put the byte 42 at 4000h.
!&4000=A% write A% (a 32-bit integer) at 4000h
$&4000="FOO" write "FOO" followed by a CR
(0Dh) at 4000h
Now the `peek's:
A%=?&4000 assign to A% the value of the byte at
4000h
A%=!&4000 A% = the 32-bit
integer at 4000h
A$=$&4000 A$ =
the string at 4000h (must end with a CR (0Dh))
As you might imagine,
you can use any expression (as long as it's the
right type; normally
numeric, but string on the relevant side of the
`$' ops) with these
operators, and the result of the `peek' ops could
be e.g. printed rather
than put in a variable, etc.
The `!' ops read/write little-endian
(LSB first) signed 32-bit
integers.
- @% (or "How to
change the numeric print format" :-))
(Firstly I should say
that if all you want to do is get it printing
numbers more like other
Basics do, you should prefix any number to
print with a semicolon, even if
it isn't after another PRINT item. For
example, `PRINT ;42' prints simply
`42', with no leading spaces. What
`@%' does is more like what PRINT USING
allows you to do in most other
Basics.)
@% is a variable which
controls how numbers are printed. It is
easiest to think of it in hex, as
then it breaks down like this:
@%=&XYYZZ
...where
X is the format used, Y is the number of decimal places to
print, and Z is
the width of the field it is printed into. X=0 is the
default format
(standard form or conventional representation depending
on the size of the
number); X=1 uses standard form all the time; X=2
uses conventional
representation all the time. The default setting of
@% is 0090Ah.
For
those of you familiar with C's printf(), setting @% makes any
subsequent
PRINT of a number into something like what these printf
calls would do (if
Y and Z were written in decimal):
for
X=0, printf("%Z.YG",number);
for
X=1, printf("%Z.YE",number);
for
X=2, printf("%Z.Yf",number);
(There are some minor
differences, but that gives you the basic idea.)
- DIM without
brackets (e.g. DIM FOO 42)
You can reserve an area of memory by
using `DIM var size' (note the
lack of brackets) to reserve size+1 (yes,
size+1) bytes of memory.
`var' is then set to the start address of this
area.
If size is -1, no memory is reserved, and `var' is set to the
address
of the last byte of memory used by the variables area (or possibly
the
first byte not used by it - it's not entirely clear which).
-
Finally, one feature criminally ignored in the manual...
******* The
built-in Z80 assembler (and how CALL and USR work)
(Both the NC100
manual and "NC100 Magic" carefully avoid discussing
this area.
Bloody wimps. ;-) The Electron manual is far more helpful,
and most of
what it says applies to the NC's BBC Basic too.)
The assembler works
by you using `[' to switch into assembler mode,
then using fairly
conventional assembly syntax, and using `]' to
re-enter normal Basic mode.
The assembly is put at P% (which is just a
normal Basic variable, which
the assembler modifies as it goes); the
default value of P% is zero, so
it's VITAL that you assign it a value
before using the assembler.
The
assembler is a one-pass assembler, but due to the interesting way
it works
it can be made to work like a normal two-pass assembler with
deft use of
the pseudo-op "OPT" and a FOR loop. Before we come to how
that
works, here's a description of the options which can be set with
OPT,
which is usually used at the start of the assembly (just after
`[' in
fact):
OPT 0 No errors, no
listing.
OPT 1 No errors, listing
given.
OPT 2 Errors, no
listing.
OPT 3 Errors, listing
given.
(The default is OPT 3. Unlike the BBC and Electron, the NC
doesn't
allow e.g. "OPT3" - it demands a space after
"OPT".)
(There are also OPT 4 to OPT 7, which are more
complicated and are
covered later.)
Back to how to do two-pass
assembly then. The idea is to run through
once with OPT 0, then again with
OPT 3 (or OPT 2 if you don't want a
listing).
Here's a simple
example of how to do this:
10 Q%=&4000
20
FOR I=0 TO 3 STEP 3
30 P%=Q%
40 [OPT I
50 \ This is a comment
60 CALL ROUTINE
70
RET \ Return to Basic
80 :
90 .ROUTINE
100 \ Not a terribly useful routine;
110 \
it does, however, prove it's making two passes.
120 RET
130 ]
140
NEXT
(Notice how you can insert comments, and the somewhat unusual
format
of labels.)
Running this gives the following output:
4000 OPT I
4000 \ This is a comment
4000 CD
04 40 CALL ROUTINE
4003 C9 RET \ Return to Basic
4004 .ROUTINE
4004 \ Not a terribly useful routine;
4004 \ it does, however, prove it's
making two passes.
4004 C9
RET
And to run the (rather useless :-)) program which has
been assembled,
call it with `CALL &4000' (`CALL 16384' would work
just as well, of
course). Or, you could use something like
`A%=USR(&4000)'. This
returns a value; more on that in a moment.
That's
the essential basics of how to use the assembler and call your
own m/c
routines. You could probably get by if you just knew that
much. But
there's a bit more to it than that:
- Since labels are just
variables, there's no warning if you define
one twice, so be
careful!
- There's a gotcha relating to the `\' comments - a colon
ends the
current statement, so you have to be careful not to use colons in
any
comments.
- You can use all the usual registers in your
code - there's no need
to save any.
- Basic variables (well,
numeric ones, at least) can be used as
constants in your assembly.
-
You can reserve an area of memory in which to assemble (which is
usually
more sensible then just assembling to a specific address) by
using
something like `DIM Q% 500' (note the lack of brackets) to
reserve 501
[sic] bytes. This was covered in more detail earlier on.
- Labels
are, in fact, just ordinary Basic variables which contain the
relevant
address. (They're floating-point though, rather than being
integers as you
might expect.)
- You can put multiple instructions on a single line
in the same way
you can in Basic - so things like "PUSH AF:CALL
THINGY:POP AF" are
possible.
- The Electron manual
describes equivalents of most assemblers'
defb/defw/etc. called EQUB,
EQUW, EQUD, and EQUS. (Respectively, these
let you insert a byte, a word
(16 bits), a `double-word' (32 bits),
and a string into your routine.)
However, these seem to be absent on
the NC's BBC Basic. :-(
-
When running under ZCN, you can call 0105h to call ZCN's BDOS, and
you can
call 0110h to call a routine at IX with the screen paged in at
F000h.
(Ordinarily, the BBC Basic ROM is paged in at C000h-FFFFh
during a CALL or
USR, and the screen is not directly accessible.)
- You can assemble
code at O% as if it were being assembled at P% (a
bit like using `phase'
on some assemblers) by using `OPT 4' and `OPT
7' (normally by either using
`[OPT I+4' at the start of the loop or
changing the loop itself to `FOR
I=4 TO 7 STEP 3'). (OPTs 5&6 also
work, being like 1&2
respectively.) Be sure to set O% to the physical
address, and P% to the
(for want of a better term) logical address -
and don't forget that O%
needs to be set *for each pass* just like P%
does!
- There are
better (if more complicated) ways of getting numbers etc.
in and out of
your routine than using the peek/poke commands. These
are described
below.
(This is one fair old chunk of text coming up, so I hope
you're
sitting comfortably... :-))
The easiest way to get
numbers *in* is to use the variables which
preset the registers. A%, F%,
B%, C%, D%, E%, H%, L% all exist and set
the value of the corresponding
register when a CALL or USR is done.
(I'm afraid there's no BC%, DE% etc.
- you have to set all the
registers one by one. Also, there's no IX% or
IY%, nor any way to set
the alternate register set.) Unfortunately, they
*aren't* set to the
values of the registers when your routine returns. You
need a
different way to get numbers out...
The easiest way to
get numbers out is to use the return value of USR.
When your routine
exits, the return value of USR is HL*65536+HL'. This
is a little awkward,
as HL is clearly the most convenient register
pair to use to return a
value, but that then makes the value more
awkward to get at from Basic.
There are two main ways of dealing with
this:
- use HL'
instead. Once you've got the value into HL, use something
like `PUSH
HL:EXX:POP HL:EXX:LD HL,0' to put it in HL'. (The final `LD
HL,0' makes
sure the number is easy to deal with from Basic.)
- use HL, and sort
out the number in Basic, with something like:
A%=USR(foo)
HL%=((A% AND &FFFF0000) DIV &10000) AND &FFFF
(The
`AND &FFFF' looks unnecessary, but isn't.)
If you want to get at
HL' too, add this:
ALTHL%=A%
AND &FFFF
So I've talked about these "easiest" ways to
get numbers in and out,
which implies there's a harder way, right?
Exactly. But while it's
undeniably harder to deal with, it's a lot more
flexible, not least
because you can use it for both input and output,
*and* you can even
deal with strings and (for grade A mad scientists only
:-))
floating-point numbers with it.
The way it works is that
you add extra arguments after the CALL. A
simple example is `CALL
&4000,NUM%'. You can have "any number of
parameters"
(according to the Electron manual - however, there's a
practical limit of
around 80), and you access them from your m/c via
the `parameter block'.
On the NC100 this is located at A100h, and is
in the following
format:
address description
A100h number
of args
A101h 1st arg's type (if there's one or more args)
A102h 1st arg's address (if there's one or more args)
A104h 1st arg's type (if
there's two or more args)
A105h 1st
arg's address (if there's two or more
args)
...and so on.
(Anyone used to the way this works on the
6502 should note that this
format is *not* the same as that one. Here, the
type comes *before*
the address, not after. Yes, really. No idea
why.)
IX is set to A100h when your m/c is called, so it's probably
easiest
to use that to get at the parameter block.
The
following types are supported:
type number description
0 a byte (as accessed with `?', e.g.
`CALL &4000,?42')
4 an integer variable (32-bit) (e.g.
`A%', `!42')
5 a floating-point variable (5 bytes)
(e.g. `A')
129 a string
variable (terminated by a CR) (e.g. `A$')
(Again, 6502 types :-)
will notice a difference - literal strings are
not supported.)
For
integer and floating-point variables, the address is simply the
address of
the number itself. (Floating-point variables seem to be
stored as a
four-byte mantissa, then a one-byte signed exponent -
that's about as much
as I could figure out from a quick
investigation.) For strings, it seems
to return the address of a
structure where the first two bytes are *both*
the length of the
string (!?), and the second two bytes are the address of
the string
itself.
***** BBCMIN [-H] [filename]
A
cut-down version of `bbcbas', which has a much smaller executable
yet has
similar functionality. However, it's much less usable for
program
development. Basically (no pun intended) it's good for when
you just want
to run existing Basic programs, rather than writing new
ones. The
intention is for a kind of `runtime' version of bbcbas, if
that makes
sense.
One other advantage is that it provides 39k for Basic, about
3k more
than bbcbas manages, and within 1k of the absolute maximum you
could
possibly get the ROM BBC Basic to allow.
Here's a
breakdown of what it lacks relative to bbcbas:
- There's no copy
cursor.
- The help pages (those obtained with *KEY) are
absent.
- *CAT does nothing.
- There's no serial/parallel
support. (You can still use it with the
serial/parallel port with console redirection, but that's all.)
-
There are no bitmaps for chars in the 128-255 range; outputting such
chars doesn't print any useful symbols. For
this reason, the pound
sign
cannot be entered when typing a program line.
- There is no
customisable LISTO setting. On startup it defaults to
LISTO format 7, just like Basic does under
the ROM software.
***** BIGRUN [d:] command [args]
Run
a command in a 62k TPA, using 32k of disk space as extra memory to
achieve
this. This may be useful for very memory-hungry programs like
Hitech C.
The drive, if specified, says which drive to allocate the
extra memory on
(the default drive is the current one).
WARNING: BIGRUN IS AN
*EXPERIMENTAL* PROGRAM, AND MAY CRASH YOUR MACHINE.
DON'T RUN IT IF YOU DON'T HAVE A
BACKUP!
Don't run ZCN-specific programs under bigrun - they won't
work. In
particular, programs which draw graphics or otherwise modify
the
screen directly will almost certainly *crash* if run with
bigrun.
Don't try to turn the machine off when running a program
under bigrun;
if you do, it may crash. Also, you mustn't remove the memory
card
while it is running. Remember the "my mind is going" scene
in 2001?
That's what you'll be doing to the NC100 if you remove the memory
card
when bigrun is running. :-)
I recommend that you only run
a program under bigrun if you absolutely
have to in order for the program
to run.
Bigrun uses the last 32k on a drive as extra memory (it
temporarily
creates a file `$$bigrun' in user 15 containing the relevant
area of
the drive in order to reserve it) so that it can keep ZCN paged
out
most of the time. This is pretty complicated, so there are some
problems
with it. There are only two problems which have yet to be
mentioned.
Firstly, programs run significantly slower under bigrun,
largely because
of the overhead involved in paging ZCN back in (which
involves more work
than you might think) for various OS calls. And
secondly, since interrupts
are effectively disabled when ZCN is paged
out, serial input will be
ignored.
While bigrun should run most generic CP/M programs, it
was
specifically written so that the Hitech C compiler would work on
ZCN.
(See the `Hitech C' section under `Tips on using certain programs
with
ZCN' for details of how to use bigrun to do that.)
*****
BMP bitmap_spec
Draw one or more character bitmaps. This is
primarily useful for
drawing graphics in SUB files.
`bitmap_spec'
defines the bitmaps like so:
- Any group of six consecutive hex
`digits' (0..9, A..F) defines a
character bitmap line-by-line, which is
printed as a char at the
current cursor position (for example,
"F9999F" would print a
rectangle). If there are fewer than six
in a row, the character is
printed with the remaining lines set to
zero.
- `_' prints a space.
- `.' causes a line-break
(CR/LF).
- `=' prints the most recently defined character
again.
Any other characters are ignored. So, for example, you can
use spaces
to separate consecutive char bitmaps, to make things a bit
easier to
follow.
While there is a limit to how many bitmaps
you can print with `bmp'
from a single command-line, `bmp' is re-entrant,
so you can use `!!'
for consecutive runs. If you do `crlf 0' beforehand,
you can build up
even quite a large graphic using multiple runs.
Indeed,
ZCN comes with a utility to convert PBMs to equivalent
`bmp'-using SUB
files (this is likely to only be useful to Unix users,
though - it's not
much use without netpbm). The C source is in
utils/pbmtosub.c.
*****
CAL [-H] [-O output_file] [month] [year]
Cal outputs a calendar. If
no month/year is specified, then the
current month (and a month either
side) are shown. (This requires the
time/date to be set - see `TIMESET'
below.) If only a month is
specified (e.g. `cal 10' for October), that
month of the current year
is shown (again, with a month either side). This
also requires the
time/date to have been set.
If either of the
above options were used and the time/date wasn't set,
cal gives usage
help. There two other ways of running cal, which don't
require the
time/date to be set:
- specify (only) a year (e.g. `cal 1998'). This
gives a full calendar
for that year. (You must specify the year in full -
`cal 98' gives a
calendar for the year 98. :-))
- specify both
the month and year. This gives a calendar for that
month and a month
either side.
***** CALC
Runs the NC100's ROM
calculator as if it were a ZCN program. None of
the weirdness needed for
`runrom' etc. is needed for this - just type
`calc' and you're away.
There
are five differences between the calculator as used from the ROM
itself,
and `calc':
- There's no border around the edge of the screen.
-
There's no "use the green keys" text when you start it up.
-
The memory and the number onscreen when you exit can be saved to a
file.
-
By default, `calc' uses the REAL keys (0-9, +, -, *, /, etc.) rather
than
the `green keys'. However, for those of you who prefer using a
keypad,
pressing Tab toggles between keypad mode and the default
non-keypad mode.
If keypad mode is on, this is indicated at the
bottom-left of the
screen.
- The normal text used (for the "M", the
"K", and the "E" error box
when you try to divide by
zero etc.), which is 6x8 when running from
the ROM, is ZCN's usual 4x6
when running `calc'.
Here's a list of how the keys used in the
non-keypad mode compare with
the keypad ones:
Non-keypad Keypad
0 to 9, ., =,
del, enter, Stop same as in keypad
mode
+, -, *, /, % "+",
"-", "x", "[divide-sign]", "%"
_
(underscore) "+/-"
c "CE/C"
r "MRC"
p "M+"
s "M-"
x clear memory (no keypad
equivalent)
q "[square-root-sign]"
By
the way, the keys on the left aren't just keys I've made up - these
are
the keys the ROM calculator *actually uses*. The keypad just maps
other
keys to these, to the extent that I had to write my own support
for it!
:-/
As for saving the numbers to a file, there are two different
ways to
do this. Immediately after exiting `calc', you should do one of
these:
- `save 1 foo'. This saves the numbers to a file called
`foo'. They'll
be prefixed by the characters "0~|8" -
unfortunate but necessary.
- `!!'. This saves the numbers to
`calcnums.txt'. There's no junk
characters prefixing the numbers if you
save them like this.
The latter is probably preferable, but the
former allows you to
specify the filename, which may be useful if you have
an existing
`calcnums.txt' you don't want to lose.
Note that if
you use `!!' it *MUST* be the very next command after
exiting `calc' or
you may risk a crash!
If you simply forgot the number you calculated
and want to see it
again, but don't particularly need to save it to a file
(or don't have
enough disk space to do so), `memdump 100' might be worth a
try
instead.
The numbers are stored as plain ASCII text. The
first line contains
the number in the memory, or zero if there wasn't one
- the second
contains the number that was displayed onscreen when you
exited
`calc'.
Finally, I should point out that there are two
problems with `calc':
- There's no way of reloading previously-saved
numbers into `calc'.
(This is definitely possible, but would be pretty
complicated.)
- `calc' will only run correctly if the console is not
redirected to
the serial or parallel ports. This isn't terribly surprising
:-), but
since `calc' doesn't actually check for console redirection (I
removed
this to keep it under 1k), it's worth mentioning. (If you run it
when
running via serial by accident, you can still press Esc to
quit.)
When running via serial, using `bbcbas' (or perhaps `expr') is
a
reasonable substitute.
***** CODES
Show a
table of ZCN terminal driver control codes.
***** CPMTRIS [termtype
[mhz10]]
A tetris clone for CP/M machines. This should work on any
Z80-based
CP/M, but has special support for ZCN. The way it works means
that it
should run on ZCN, PCWs, and +3 CP/M as-is; for other systems, a
bit
of patching may be required.
You can run it on a VT100
serial console with `cpmtris 1'.
See the README in the `cpmtris' dir
for more details.
***** DCLOCK
A simple clock program, a
cut-down version of zcnclock. (It's 1k
instead of 5k.) Press Esc to
exit.
Note that, as with zcnclock, the auto-poweroff timeout is
effectively
disabled by the constant updating. (Despite appearances, even
the date
is updated every second.) This is probably a good thing if
your
machine is running off the mains adaptor, but watch out if
you're
running off batteries.
***** DEFRAG [-Q] d:
Defragment
free space on the specified drive (without the running
commentary if you
use `-q'). MS-DOS/Windoze users who haven't thought
too hard about how a
memory card works should note that THIS DOES NOT
SPEED THE DRIVE UP. :-)
(Hint: there's no seek time on a memory card.
Or rather, the `seek time'
that exists (the access time) is very
small, and constant.) This is why it
doesn't defragment files
themselves, only the free space not used by
files, you see. Use
`optdir' if you want to speed a drive up in roughly
the same kind of
way as `defrag' does on a DOS or Windoze box.
The
only reason you would want to use `defrag' is if `sys' or `bigrun'
fail
when you have enough free disk space for them to work, but not
enough of
it is at the end of the drive. `defrag' puts all the free
space in one big
uninterrupted lump at the end of the drive, making
sure that
`sys'/`bigrun' *will* work if you have enough disk space.
***** DIAL
phone_number
A DTMF tone-dialler. It uses the sound chip to generate
the
appropriate tones. I haven't had any luck with this - I expect
the
sound is too distorted. Amstrad seem to have a talent for making
machines
with distorted sound; ask any Spectrum +3 owner... :-)
For what it's
worth, `dial' supports all `digits', including `*' and
`#' as well as the
rather obscure `A', `B', `C' and `D'.
***** DMP2TXT input.dmp
output.txt
This converts a screen dump file created by ZCN (usually
screen.dmp
unless it's been renamed) to a text file. The text file is
simple,
plain ASCII - no attempt is made to represent attributes.
It
uses a real brute-force comparison approach, and so can be
relatively slow
- around five seconds for an average screen.
Dmp2txt does pretty
well at interpreting the screen dump in most
cases. However, it's usually
fooled by text displayed when two (or
more) attributes were on at once
(e.g. inverse bold) since - after
checking against the normal characters -
it (only) checks for each
attribute individually.
***** DU
[filespec]
Shows how much disk space is used in total by the files
matching the
specified wildcard (or `*.*', all files in the current user
area, if
you don't specify one).
***** EXPR expression
`expr'
is an expression evaluator, a sort-of-clone of the Unix command
of the
same name. It only does integer arithmetic, but does at least
use 32-bit
integers to do the maths (giving a range of -2147483648 to
2147483647).
All tokens (numbers, operators, brackets) must be
separated by spaces,
e.g. `expr 1 + 2 * 3'. Precedence is of the usual
type, so the previous
expression evaluates to 7.
***** HEAD filename
Display
the first 8 lines of a (text) file.
***** HELP [command] (removed in
ZCN 1.2)
The old external `help' command used to give very terse
(one-line)
usage help for commands. It was dropped as `man' is vastly
better, and
I didn't like the idea of maintaining a separate, inferior
help
program.
***** INVADERS
`Invaders' is an
unfinished game. It's reasonably playable as is
though - Z moves left, X
moves right, Space fires, and Q quits. The
invaders gradually grow
invisible because it starts updating faster
than the NC100's LCD screen
can handle. That's the main reason why I
haven't bothered finishing it.
:-/ You should be able to get by if you
crank up the intensity
control.
***** LS [-L] [filespec]
Like `dir' but displays
the file list sorted vertically by filename,
with .com and .sub files in
italics, and if the `-l' option is given,
with file sizes (in K). It also
uses an 80-column-friendly layout (and
no italics) if the console output
is going to the serial port or
printer, unlike `dir'.
ZCN's
`get file size' function is fairly slow, so this command isn't
very quick
if you give the `-l' option. Try it and you'll see what I
mean.
*****
OPTDIR [-Q] d:
The management summary on this one is `makes drives
quicker'. :-)
Optdir optimises the directory blocks on a drive by
putting the
entries matching the larger 16k chunks (extents) of files
nearest the
beginning. Pretty confusing stuff, but it makes large files
much
faster to read, at least three times faster in some cases, mostly
due
to the stateless, unbuffered way ZCN works with files. You might
like
to think of it as the performance-increasing equivalent of a
defragmentation
tool for MS-DOS, only more so. Believe me, you really
want this
program.
I run it from my `autoexec.sub', but you can obviously also
run it by
hand, perhaps after copying some large files. You should run it
as
(for example) `optdir a:' to optimise the A: drive. It'll list the
new
order of extents, which probably won't mean that much to you. It
means
precious little to me, anyway. :-) It only does it so you know
it's
done something, as much as anything else. You can run it with
something
like `optdir -q a:' to stop it printing out all that junk.
*****
PLAY1B/PLAY2B/PLAY4B filename
These play (respectively) 1, 2 and
4-bit sample files at 8kHz. You can
generate these samples from an raw
8-bit unsigned source on a Unix box
with the mk[124]bit filters (C source
in the `utils' directory). I
would have liked to include a few example
sample files, but it's
almost impossible to find any non-copyright
material which would sound
reasonable. (Classical music tends to distort
easily with low
bit-depth samples, and almost all recordings are
copyrighted anyway.)
Note that 1-bit samples sound terrible, 2-bit
ones sound only a bit
better, and although 4-bit samples can sound quite
good, you can only
play up to 11 seconds worth of 4-bit sample.
Keyboard
input is ignored while the programs are running. However, you
can use the
power on/off button to abort playback.
BEWARE! The programs don't
(yet) stop loading the sample if it gets
larger than available memory, so
don't try to run it on a file any
bigger than 43k!
Bugs:
`play4b', at least, plays samples back slightly too slowly, not
quite
managing the full 8kHz.
***** MAKEZAPD
Make
a0:zapdesc.bin (required by zap) from all .zap files in the
current
drive/user, overwriting any existing a0:zapdesc.bin. It shows
a dot for
each .zap file processed.
****** About zap files
Zap
files are text files containing a program description - the
program's
name, the COM filename, and so on. It's fairly
straightforward to create
your own zap files, a description of the
format follows...
Blank
lines and lines starting with `#' (comment lines) are ignored.
Other lines
should be one of the following:
- "progname name", where
`name' is the name which zap will display
above the program's icon. A maximum of 15 chars is allowed.
No
spaces are permitted - to have
zap print a space in the name, use an
underscore (`_') instead.
- "progfile program.com",
where `program.com' is the program to run.
It MUST be a COM file (or the NC100 will most likely crash when
zap
attempts to run it!).
`progname'
and `progfile' are required. The rest are optional:
- "filetype
ext", where `ext' is an extension to associate with the
program (so that files matching `*.ext'
would be listed in its file
list). You can specify up to 32 extensions using multiple
`filetype'
lines. To match all
files, use `filetype *'.
- "filetype ?" tells zap to give
a list of possible drives to start
the program on, rather than a list of files. (After the drive is
chosen, you'll then choose a user number to
use.)
- "filetype ?d" is much the same, but you only pick
the drive. Only in
rare cases is
this likely to be useful (e.g. for zdbe).
- "opt option",
where `option' is one of the following options:
- "noret" stops zap restarting
after the program has finished.
Useful for programs which exit by rebooting, such as runrom.
- "keywait" makes zap wait for a
key after the program has run.
Mainly useful for non-interactive programs.
- "needfile" tells zap that the
program *must* be run on a file.
This means that zap doesn't a "<new>" entry in the file
list, and
if there are no
matching files, the program isn't shown.
The other possible lines
define a 32x24 icon bitmap to be used. This
is optional, but the listing
will look a bit odd if you don't supply
an icon. The icon starts off
blank, and the first `bmphex' or `bmpbin'
line defines the first row of
pixels, the second defines the second,
and so on. You don't have to
specify all 24 lines - any remainder is
left blank. Here's how `bmphex'
and `bmpbin' work:
- "bmpbin binary_data", where
`binary_data' is exactly 32 bits (0s and
1s) specifying a line of pixels in left-to-right order. A zero
represents white, a one represents
black.
- "bmphex hex_data", where `hex_data' is exactly
eight hex `digits'
specifying a
line of pixels in left-to-right (big-endian) order.
This is intended for use by programs which
generate zap files (more
on this
in the next section); when writing a zap entirely by hand,
you would normally use `bmpbin'. `bmphex'
lines take up a lot less
space,
however, so any Real Programmers out there are bound to use
them anyway. ;-)
****** Example
zap file
The above probably makes zap files sound rather confusing.
But they're
pretty simple really. Here's an example, the zap file for
`bbcbas':
progname BBC_Basic
progfile bbcbas.com
filetype
bas
bmphex 07ffffc0
bmphex 06aaaae0
bmphex 077d7dc0
bmphex
06eeeee0
[...many `bmphex'
lines deleted...]
bmphex 07ffffc0
bmphex 02aaaaa0
Some of
the `bmphex' lines have been cut, but other than that this is
the complete
`bbcbas.zap'.
****** Designing zap file icons
The
simplest way to design the zap file's icon is to use a text editor
and
`bmpbin' lines. This is a bit awkward, but works well enough. (I
hope to
write an icon editor for ZCN in future, though.)
For ambitious types
with Unix boxes, however, you could use a paint
program (I'd recommend X's
`bitmap' program, which is a bit `clunky'
but is good for designing
B&W icons) to create the 32x24 bitmap,
convert that to a PBM using
netpbm (you'd want to run it through
xbmtopbm if using `bitmap', for
example), then convert the PBM to a
skeletal zap file using
zap/pbmtozap.c. You then need to edit that to
make the finished zap file.
So you see what I mean about using a text
editor being the simplest way?
:-)
***** MAN [page]
ZCN's online help system.
`man' is modelled (very) loosely on Unix's
`man' program. You do `man foo'
to get help on a command (or topic)
`foo' - for example, `man man' gives
help on man itself, and is a good
place to start.
Note that for
man to work, you MUST have the `manpages.pma' file from
the `bin'
directory on your A: drive in user area 0. This archive
contains all the
help files (or as they're more usually known, man
pages).
*****
RRXFER
Transfer files to/from a `runrom.ram' snapshot file created
by
`runrom'. See the section `Running the ROM software from ZCN' above
for
details.
***** RULER
Display a ruler (labelled in cm) at
the top of the screen. (It's
accurate to within 1mm, but is only labelled
every 5mm.)
One notable thing about the ruler is that the top two
pixel lines stay
onscreen until you do `cls', so you could (for example)
do `ruler',
then run a text editor to note down some measurements. (As
long as
you're prepared to count the lines/dots, that is. :-) And it
doesn't
work with ZDE, as that clears the screen on startup - `note' would
do
the job though.)
If you'd like to be able to modify the
ruler (perhaps to display
inches, or mm), a better approach might be to
write your own custom
BBC Basic program. Here's one which gives similar
output to `ruler'
which you could use as a starting point, much as I did
for `ruler'
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
(like `submit') which contains each of the
semicolon-separated commands
you gave on the command-line, on a
separate line. Due to the way it works,
it's not a good idea to call
this from a SUB file as-is - you should
instead prefix it with
`quitsub'. (This will also abort the SUB file, I'm
afraid.)
On my machine, I have this renamed to `;.com' to make it
easier to
run/type. This should explain why it's called `semi'. :-)
*****
SLIDE
A slide-rule emulator. The upper and lower parts of the rule
remain
static, but the middle part can be moved with `,' and `.' (use
shift
to move more slowly), or cursor left/right. The cursor, a line
which
helps you read the rule more accurately, can be moved with `z' and
`x'
(again, use shift to move slowly). Esc exits.
Since nobody
uses slide-rules any more, here's a very simple
explanation of what they
are, and how to use one for simple
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.)
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.
All in all, it's fair to say that most people
would prefer to use
`calc'. :-)
***** SPELL
filename
Interactively spellcheck a (text) file (uses the ROM
spellchecker).
After invoking spell, the file specified is renamed
to have a `.bak'
extension (with any existing `.bak' file deleted first).
This file is
then read from, with spellchecked output going to `filename'.
This new
file will be on the same drive as the `.bak' file, even if it's
not
the current drive.
If spell thinks there won't be enough
disk space to write the new
file, it tells you before it starts, giving
you the option to abort
the spellcheck or carry on anyway. The space
that'll be needed can't
be determined for *certain* though, since
replacing short words with
longer ones could make the file bigger, so it
may be best to check for
yourself before running spell to make sure you
have a reasonable
amount of disk space.
Once spell is up and
running, it shows you how far it's got with a
display of the form `XX/YY'.
XX is where it's got to in the file (in
128-byte records), YY is how big
the file is.
If it finds a word it doesn't recognise, it removes
this display and
shows the word (highlighted), along with the previous and
current
lines. You're then given a menu like this:
[L]ookup,
[A]uto-lookup (toggle), [R]eplace (edit), SPC - ignore
`L' looks up
alternatives which might be the word you meant. If none
were found, it
says so; otherwise, it lists them like so (this example
shows the result
of looking up `addr'):
0) add
1) adder 2) adds
You
can press 0 (zero) to replace the word with (in this case) `add',
1 (one)
for `adder', etc. (If more than 10 possible choices are given,
they use A,
B, C and so on - be sure to use an UPPERCASE letter if you
want to choose
any of those.)
`A' enables looking up of alternatives automatically,
so you don't
have to press `L' every time. This can slow things down
though, as
looking up words takes a little while. Pressing `A' again
disables
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.
***** STAT
This emulates
almost exactly the behaviour of the old internal `stat'
command. The only
problem is it uses a $$$.SUB file to run df etc., so
for now at least it
gives a slightly incorrect result for free space
on the current drive. :-}
See `STAT (removed in ZCN v1.1)' in the
`Internal Commands' section above
for details.
***** SUBMIT filename [* | [arg1 [arg2 ... ]]]
See
the section `SUB files with parameters' above for details of this
command.
*****
TIME
Display the time as reported by the NC100's real-time clock.
You
should previously have set it with `timeset' (see below). If the
time
is not set, `time' says so; otherwise it displays the time in
the
format YYYY-MM-DD HH:MM:SS, e.g. `1995-06-17 20:58:55'.
*****
TIMESET [[YYMMDD] HHMM[SS]]
Set the time (and optionally the date)
of the NC100's real-time clock.
ZCN only currently uses the time/date for
`cal' (where having it set
is optional), `time', `rrxfer' (optional), and
`dclock' and `zcnclock'
(which are essentially just prettier versions of
`time'). No file
date/time stamps exist in ZCN - this is the same as CP/M
2.2. (CP/M 3
does have them, but they eat a quarter of your directory
entries!)
You can specify either the time (in 24-hr format padded
with zeroes if
need be), the time with seconds, the date and time, or the
date and
time with seconds. To give a few examples:
timeset (give
usage help)
timeset 0730 (set time to 7:30 a.m.)
timeset 950528 090125 (set date to 28th May 1995, time to 9:01:25 a.m.)
timeset 010114 2112 (set date to 14th Jan 2001, time to 9:12 p.m.)
The
NC100's real-time clock doesn't support dates before 1st Jan 1990,
nor
does it support dates after 31st Dec 2099. If you're using ZCN in
the 22nd
century, apologies for the inconvenience. :-)
Since ZCN has only
existed since 1994, ZCN treats all dates in 1990 as
`clock not set'. (The
reason being that if the clock isn't set, the
clock only runs when the
machine is turned on, and it always starts at
zero, i.e. 1st Jan
1990.)
***** ZAP
A simple graphical front-end for
ZCN. It essentially shows a list of
programs you can run (shown by icons
with the program's name above),
and for each program, a list of files you
can run it on.
****** Requirements
Before going on to
describe how to use zap, there's one important
detail which I need to
mention. Zap requires a file `zapdesc.bin'
(which must be on drive A: in
user 0) in order to operate. You can use
`makezapd' to generate one of
these from `*.zap' (there are many zap
files in the `zap/zapfiles' dir in
the ZCN distribution), or (much
easier) just use the pre-generated
`zapdesc.bin' included with ZCN (in
the `bin' directory). See the
`MAKEZAPD' section above for more on zap
files.
****** Using
Zap
When zap starts up, it reads `zapdesc.bin', finds any
programs
mentioned in there which exist anywhere on the card (any drive,
any
user), and finds any files which have been associated with them
(also
in any drive/user). It then displays a screen looking (very roughly!)
like
this ASCII representation:
(Zap really shows six icons across, but I
can only show four in the
mock-up here. If you have something which can
view GIF files, look at
zap/zapscrn.gif for a genuine screenshot.)
-,
,- . . ___________
/_ \_
|\| [_BBC_Basic_] Calc Zcnclock
ZDE
.------. .------. ,------. _
15:19 |^o^^o^| |'====`| | 1200 |
__--//
|`\\\
|| | oooo | |______| `. |/`-.
-->
|_,_/_\| |_oooo_| _====_ `._,-'
_______________ _______________
A: 10
|[_<new>_____]|#| |
<new> |#|
B: 37 |b0:try.bas |#| |a0:bar.txt |#|
C:--- | |#| |b2:foo.sub | |
D:--- | |#| |a0:wibble.txt| |
`-------------'-'
`-------------'-'
Ignoring the `sidebar' at the left for the
moment, you can see the
various program icons along with their names, and
some have
accompanying lists of files below the icon. Each file list has
a
scrollbar, showing which part of the file list is displayed, and
how
much of the list it is. For Basic's one all files are displayed
so
it's `full'; for ZDE's, we can see that we're at the top of the
file
list, and that about half of the list is onscreen.
The
arrow to the right shows that there are more icons off-screen;
moving the
cursor (currently on "BBC Basic") right a few times would
make
those visible.
Returning to the sidebar, it shows the time (or
"--:--" if the time
isn't set), and how much disk space is free
on each drive (or "---" if
the drive isn't present). Also,
though it isn't shown here, zap shows
you warnings about any batteries
which are low in the gap between the
time and disk-space displays.
So,
enough of what zap *looks* like. How do you use it? The answer is
simple
enough. You move the icon cursor (the one at the top) to the
program you
want to run, then (if the program has one) move the file
cursor (the one
in the file list) to the file you want to run it on.
In addition to normal
files, there are some special `files' you can
choose:
-
`<new>'. This runs the program without giving it any filename. It
lets
you pick the drive and user to start the program in. It defaults
to any
previously-selected drive/user, or if none have been selected
yet, the
drive/user that were current when you ran zap.
- `a:', `b:', `c:',
and `d:'. These do much the same, but after
selecting one of these (which
specifies the drive to use) you then
only need pick the user to start the
program in. This `d:'-style way
of working is used when the program is
never run with a filename (or
more precisely, when the program has only
the special filetype `?'
given in its zap file).
After the
program you've run exits, you return to zap.
And there it is, that's
pretty much all you need to know to use zap.
Well, if you're prepared to
guess the keys, that is. :-) Just in case
you're not...
******
Keys
Some keys used in zap are pretty obvious (e.g. cursor
left/right move
the (icon) cursor left/right), some are less obvious. Here's
a list of
all of them.
(Note that `Sym' is short for the
shift-like key `Symbol'.)
Key Description
Esc Exit zap
Enter Run the currently-selected program
on any
currently-selected file
Cursor
left, or ^S Move icon cursor
left
Cursor right, or ^D Move
icon cursor right
Sym-Cursor left, or ^R Move
icon cursor left a `page'
Sym-Cursor right, or ^C Move icon cursor right a `page'
< or , Move icon cursor to the
start
> or . Move
icon cursor to the end
<letter> Move
to program name starting with <letter>
Cursor up, or ^E Move file-list cursor up
Cursor down, or
^X Move file-list cursor down
Sym-Cursor
up Move file-list cursor up a
`page'
Sym-Cursor down Move
file-list cursor down a `page'
Sym-< or Sym-, Move icon cursor to the start
Sym-> or Sym-. Move icon cursor to the end
Sym-<letter> Move to file starting with
<letter>
Sym-Esc Write
full 64-line screen-dump to `screen.dmp'
(Admittedly the last one
was mainly for my convenience when developing
zap :-), and may well
disappear at some point.)
The idea behind the file-list movement
keys being generally more
`difficult' than the icon cursor ones is that
not all programs have
file lists.
****** Adding icons for other
programs
To add another program to zap's list, you need to make a
.zap file for
it, and use makezapd to make a new `zapdesc.bin'. See the
`MAKEZAPD'
section above for details.
****** How zap
works
Fair warning - this section is mainly intended for those of
the geeky
persuasion. :-)
Zap works by making a $$$.SUB file
which reads the program using
`get', uses `!! filename.ext' to run it with
the file, then does
`quitsub zap -#...' to remove the $$$.SUB and re-run
zap, with the
`...' specifying various things like the
most-recently-chosen
drive/user, the position in the icon list, and
whether the program
chosen had the `keywait' option set.
When
zap is run again (by the SUB), it does the `keywait' if that was
asked
for, and puts all the `-#' context back in place - and there you
are, back
in zap.
****** Zap Limitations
"GUIs normally make
it simple to accomplish simple actions and
impossible to accomplish
complex actions."
-- Doug
Gwyn on comp.unix.wizards
Zap isn't really a GUI as such, but it's
certainly prone to this
accusation. It's only a program launcher, after
all; you'll have to
exit to the ZCN prompt to do some things, such as work
on PMA files or
set the time.
(I did consider having some sort
of `shelling out' option - but since
zap starts up quite quickly and can
be exited instantly, I didn't
really see the point. Just treat Esc as a
shell-out option and `zap'
as if it were `exit'. :-))
Also, at
the moment you can only run external programs (COM files)
from zap. There
is no way to run internal commands, which is a pain as
some of them can be
quite useful (e.g. sertest), and you can't run SUB
files either.
Finally,
the way `man.zap' describes man as being associated with
COM files is a
kludge, since zap has no way of reading manpages.pma
(even if it did, it
would be unacceptably slow).
****** Zap Bugs
Zap is quite
a young program and has some known bugs. These should
hopefully be removed
in the next ZCN release:
- zap tries to run any file mentioned as a
`progfile' as a COM file.
SUB
files (and any other non-COM files for that matter) will almost
certainly cause a crash, and internal
commands will probably just
result in an error from ZCN before returning to zap. (This bug is
only an issue if you write your own zap
files.)
- zap always tries to write its $$$.SUB to the current
drive, and
exits with an error
message if it can't. (This is considered a bug
as it should probably try other drives too (if others exist),
and
give some sort of error
dialog if it still fails.)
- zap doesn't currently check for the
memory card being removed, which
is
a bit crap.
- the "working..." display is a bit naff, and
should be replaced with
some sort
of percent-complete-bar thing.
- the flashing underlines shown below
battery-low warnings flash in a
very strange way, due to interactions between two differently-timed
loops. I consider this to be a bit of a
feature though, because you
probably want a "your batteries are dying" message to be
as
eye-catching as possible.
:-)
****** YABA Department
Yes, zap is an acronym I'm
afraid. FWIW, it stands for "ZCN
Associative Program-launcher",
which is possibly the most contrived
acronym ever. :-)
*****
ZCNBROT
A simple program to plot the Mandelbrot set, a famous
fractal. It uses
fixed-point 32-bit integer maths and an estimation method
similar to
the `tesseral' method in the excellent free PC program
"fractint".
It only plots the complete set, and doesn't
allow any zooming in. This
is the case as, while this program is quicker
than any other 8-bit
fractal program I know of, it is very slow. It takes
12 minutes to
draw the full set at the 128x64 resolution it uses.
When
it's finished, it waits for a keypress. Press ctrl-shift-s then
to dump
the screen, if you want to do that.
Note there is no abort key. To
quit before it finishes, do a cold
reboot by turning the machine off, then
holding both shifts while
turning it on again.
*****
ZCNCLOCK
A clock program which continuously updates both analogue
and digital
time displays, as well as the current date, and supports
displaying
the time in various cities around the world. Press ^S (or
cursor left)
and ^D (or cursor right) to change city. Exit the program
with Esc.
Be the envy of your friends! Run it and nail your NC100 to
the wall as
a stylish clock. :-)
Note that the auto-poweroff
timeout is effectively disabled by the
constant updating. (Despite
appearances, even the date is updated
every second.) This is probably a
good thing if your machine is
running off the mains adaptor, but watch out
if you're running off
batteries.
There's a known bug in zcnclock,
which is that the `world time'
business is inflexible and horribly
UK-centric. (The world time stuff
will currently be pretty useless to
anyone outside the UK.) Oh, and of
course DST changes take place at
differing times around the world, so
some world times will probably be
wrong by an hour for short periods
even for UK-based users, but this is
probably true of most such
programs.
The bitmaps used in
zcnclock to display where each city is on the
planet were produced by
xearth.
The font used for the large digits in zcnclock (and dclock)
is from X;
specifically it's a conversion of the 100dpi helvR24.bdf font.
It's
free but the terms of use require me to include the copyright
in
supporting documentation, so here it is:
> Copyright
1984-1989, 1994 Adobe Systems Incorporated.
> Copyright 1988, 1994
Digital Equipment Corporation.
>
> Adobe is a trademark of
Adobe Systems Incorporated which may be
> registered in certain
jurisdictions.
> Permission to use these trademarks is hereby granted
only in
> association with the images described in this file.
>
> Permission to use, copy, modify, distribute and sell this
software
> and its documentation for any purpose and without fee is
hereby
> granted, provided that the above copyright notices appear in
all
> copies and that both those copyright notices and this
permission
> notice appear in supporting documentation, and that the
names of
> Adobe Systems and Digital Equipment Corporation not be used
in
> advertising or publicity pertaining to distribution of the software
>
without specific, written prior permission.
Adobe Systems and
> Digital Equipment Corporation make no
representations about the
> suitability of this software for any
purpose. It is provided "as
>
is" without express or implied warranty.
***** ZCNPAINT
A
mouse-based paint program. You need a microsoft-compatible serial
mouse to
use it.
BEWARE! Zcnpaint is incomplete, and there are still bugs,
though to
the best of my knowledge there are no unknown bugs. :-)
Known
bugs include:
- Flood-fill always fills in black, whatever the
currently selected
pattern is.
- If you press return at the
save or load file prompt without typing
any name in, it'll save a file
which has a filename consisting
entirely of spaces; you can spot this by
there being a blank space in
the file listing given by `ls' or `dir'. You
can't do much with this
file, but you *can* delete it - just type `era'
(with no filename) at
the ZCN prompt.
Also, though it's not
really a bug, the mouse pointer can be easy to
lose track of, so you may
want to turn up the intensity to try and
avoid this problem. (This
`disappearing pointer' is due to the
rather persistent LCD display, of
course.)
With all that out of the way...
Zcnpaint works
in a fairly similar fashion to most paint programs on
8-bit machines,
except that the pointer is obviously controlled by the
mouse and not the
keyboard. All the controls are on the "icon panel",
which you
can drag to another position onscreen by click-and-dragging
the
"title bar". The icons are rather small and nondescript, so
here's
a guide to the icon panel:
+-----------------------------------------------------+
|
Z C N P A
I N T
|
|
|
+--------+--------+--------+--------+-----------------+
| single |freehand| eraser |flood- |start new file |
| pixel |
line | | fill |(i.e. clear scrn)|
+--------+--------+--------+--------+-----------------+
| rubber |multi- | undo
|hide |load file |
|bandline| line |
| panel | |
+--------+--------+--------+--------+-----------------+
|hollow |filled |window |text
|save file |
|rectangl|rectangl| (NYI)|
(NYI)| |
+--------+--------+--------+--------+-----------------+
|hollow |filled |choose |brshsize|exit program |
|circle |circle |pattern |
(NYI)|(does NOT prompt)|
+--------+--------+--------+--------+-----------------+
The
icons marked "(NYI)" above do nothing, as the feature is not
yet
implemented (and, to be honest, is unlikely to be).
Note
also that exit program does *not* prompt you whether you want the
save the
current file - if you haven't saved the picture and you exit,
you've lost
it. Well, this isn't entirely true. The undo screen, which
will almost
certainly have a recent copy of the picture, is at 7000h.
If you haven't
run any program since, or at least not one which uses
the area
7000h-7fffh, you might still be able to get at it. One way to
do that, if
you have 36k or more available on a disk, would go like
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 at the moment. Esc,
which acts like `exit', and
Menu, which toggles the icon panel on/off.
The way the tools work is
that the icon most recently clicked on sets
the drawing mode. The default
mode, active when you start zcnpaint, is
the `single pixel' mode.
Now,
to cover each of the tools (drawing modes) in turn:
- Single pixel.
This draws a pixel whenever the left button is pressed
or held down. You
might think this would result in a line being drawn
when you hold down the
button and move the mouse - it doesn't, since
the mouse can easily move
large distances between samples. If you want
a continuous freehand line,
use...
- Freehand line. This draws a continuous line when the left
button is
pressed/held. Note that the line gets rather ragged when the
mouse is
moved slowly, due to the way the tool is implemented. For these
kind
of slow movements, `single pixel' mode may give better results.
-
Rubber-band line. This lets you click-and-drag to draw a line.
-
Multi-line. This lets you draw a long series of connected lines by
clicking
the left button at each start/end point. To start a new
series of lines,
select the multi-line icon again.
- Hollow/filled rectangle/circle.
These work like rubber-band line by
dragging the shape out. With circles
there is a certain maximum size
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. Only a few patterns
are defined in zcnpaint itself; eventually
there'll be a pattern
editor, but for now you're stuck with the five pre-defined
ones.
- Flood-fill. This fills in the surrounding shape, which must
have a
solid outline. Click somewhere inside the shape to fill it.
-
New file clears the screen.
- Load file lets you load a
previously-saved file. You can also load
screendumps produced by
Ctrl-Shift-S, though since these are slightly
smaller than the full 64
lines normally loaded/saved by zcnpaint, you
should do `new'
beforehand.
- Save file lets you save the current image. The file
format used is a
simple binary dump of the screen - all 64 lines. You can
load a saved
file direct from ZCN with `get f000 filename'.
-
Exit exits the program.
If you'd like me to develop zcnpaint any
further than it is now, you
should contact me (see near the end of the
file for details). I'm
probably quite unlikely to do any more on it unless
anyone else is
going to use it. (And even then I might need some
convincing... :-))
***** ZDBE
A disk block editor.
It allows you to view and navigate a drive, and
shows a map of the
allocated blocks. If you use `M' to enable
read/write mode, you can also
edit the data in hex/ascii.
Although `zdbe' uses the full 120-column
screen, it detects when
you're running the console via the serial port and
alters output to
work correctly on an 80x24 VT100 or compatible
terminal.
The screen is split up into two panels. The left one (or
top one if
running via serial) shows the hex/ascii dump of 128 bytes of
the
current block. The right one (bottom one if via serial) shows a map
of
the blocks on the drive, and the current drive, block number, and
offset
of the cursor within the block. Only one of these two panels
can be used
at a time - Tab selects which is active. The active one is
indicated by
dashes surrounding the panel's title bar (at the top);
also, the cursor
will be on the active panel somewhere. When you start
up zdbe, you're in
the block-map panel.
The block-map panel lets you choose which block
to display/edit. Boot
blocks are shown as `B', system blocks as `S',
directory blocks as
`D', used data blocks as `#', and free data blocks as
`.'. The
following keys can be used in this panel:
Esc quit the program
Tab switch panels
Space page forward through entire
disk
Del page backward
through entire disk
cursor keys move
^E/^S/^D/^X move up/left/right/down
respectively
h/j/k/l move
left/down/up/right respectively
d go
to first directory block
< or , go
to start of drive
> or . go
to end of drive
M (shift-m) switch
between read-only and read-write modes
^L switch
to (`login') a new drive
w write edited block to drive
To
further explain some of the above:
- Space/Del are supported in both
panels, and let you navigate through
the drive's data sequentially without
having to mess around switching
panels all the time.
- In
read-only mode (the default), no data on the drive can be edited.
In
read-write mode, data can be edited (though you're still prompted
before
data is ever written). Only the currently selected block can be
edited.
When you switch blocks (or press Esc, etc.) you're given the
chance to
write edits to the drive, but you can also do this
explicitly by using
`w'.
The hex/ascii view/edit panel lets you look through or edit
the
current block. When not editing, the following keys can be used:
Esc quit the program
Tab switch panels
Space page forward through entire
disk
Del page backward
through entire disk
cursor keys move
^E/^S/^D/^X move up/left/right/down
respectively
h/j/k/l move
left/down/up/right respectively
g go
to data block referenced by byte at cursor
b go to previous block
d go to first directory block
< or , go to start of block
>
or . go to end of
block
^C or ^V page down
(move 128 bytes forward)
^R or ^U page
up (move 128 bytes backward)
M
(shift-m) switch between read-only
and read-write modes
^L switch
to (`login') a new drive
e enter
ASCII edit mode
E (shift-e) enter
hex edit mode
w write
edited block to drive
`g' can be used in a directory block to jump
to a block used by a
file, if you know enough about the CP/M directory
format.
(Essentially, the line of hex underneath the filename gives up to
16
data block numbers. Put the cursor on one of these and press `g'
to
get a data block. Which block of the file it actually is depends
on
which extent of the file the directory entry is for, which is a
bit
complicated to go into here - for files of 16k or less though,
the
first byte on the line represents the first 1k of the file, the
second
the 2nd, etc.) `b' is intended to be used to return to the
correct
directory block after a `g', but might conceivably be useful in
other
circumstances too.
(While on the topic of directory
blocks, it's possible to undelete a
file by changing the E5h just before
the filename back to a user
number to put the file in - say, zero. You can
use the hex edit mode
to do this. Again though, the picture is more
complicated for files of
over 16k. And you should bear in mind that - if
the drive has been
written to since you deleted the file, or if you've run
`defrag' on it
since - the file when undeleted may turn out to be
corrupt.)
The hex and ascii edit modes let you change the data in
the block.
These operate on the copy in memory, as you may have gathered,
and you
can use `w' after the edit to save the changes to the drive.
The
keys for hex edit mode are largely the same as those for the
non-editing
mode, except that 0-9 and a-f/A-F enter hex at the cursor
position. You
have to enter a byte at a time - once you've entered one
`hexit', you have
to enter another (to complete the byte) before you
can do anything else.
Other keys: Del backspaces a byte, and ^Q exits
edit mode.
The
keys for ASCII edit mode are again largely like the non-editing
mode,
except that all printable ASCII characters enter themselves at
the cursor
position. Other keys are as for hex edit mode (see above).
*****
ZRX filename
XMODEM receive a file from the serial port. Normally
you'd use QTERM
or a similar program for such a task, but there is one
situation in
which most of these programs don't work properly; when
console I/O is
redirected to the serial port. In this situation, you can
instead use
zrx to send files to your NC100, as it does no console I/O at
all.
There is no analogous `zsx' to send a file.
Bugs:
the XMODEM implementation is somewhat naive, and only supports
the old
`checksum' method.
***** ZSELX [termtype [du:]]
Zselx
is a simple file manager which lets you copy/move/delete/view
multiple
files.
Even if you don't like file managers, zselx might possibly be
of
interest since it allows you to copy files from any drive/user to
any
other directly (e.g. from A: user 0 to B: user 3).
[The
remainder of this description is from the (non-ZCN-specific)
zselx readme,
so don't be surprised if it tries to tell you things you
already know,
such as what user numbers are.]
****** About zselx
Zselx
lets you pick files from a certain drive/user and do one of
these
things:
- copy or move them to another drive/user;
- delete
them;
- view them.
Like cpmtris, zselx works as is on VT52s
(PCW and +3) and ZCN boxes,
works with VT100s with `zselx 1', and is
patchable for other machines
and terminals. (It uses the same patch area
layout, so you can use a
cpmtris patch with zselx.)
It's a
conversion of my original Unix version, modified to use
internal
cp/mv/rm/more-like `commands'. Unix zselx is free too (public
domain in
fact, as writing it on Unix was considerably simpler) and
available on
request.
Zselx was inspired by a useful little program for MS-DOS
called `co'.
Zselx is essentially a clone of `co', with certain details
modified to
suit CP/M.
****** User numbers
The term
`user' in this file means `user area' or `user number'. If
you don't know
what that means, check your CP/M manual. They're a
little bit like
directories on other OS's. For those people without a
CP/M manual, here's
the definition from the CP/M 2.2 manual:
"user number: Number
assigned to files in the disk directory so that
different users need only
deal with their own files and have their own
directories, even though they
are all working from the same disk. In
CP/M, files can be divided into 16
user groups."
On a single-user system, then, they can be used
rather like
directories. They're numbered from 0 to 15, with 0 the default
user.
You can use the `user n' command to switch to user n.
Drive/user
specifications are far from standard, and different forms are
used by
different programs, among them (for, say, drive B: user 4) 4/B:,
4B:,
and B4:. Zselx uses the last one, as that seems to be the most
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
version which aren't supported in
this CP/M version.]
Esc x q quit
h
k ^p ^e move cursor up
l j ^n ^x move cursor down
0 < go to top of file list
$ G > go to end of file list
^b ^u ^r move cursor back a page
^f ^v ^c move cursor forward a page
c 1 copy the files to a given
drive/user
d 2 delete the
files, prompting for confirmation
m 3 move
the files to a given drive/user
a 4 untag
all files
v view the files
(press Esc/q/x to exit file view)
f not
supported (edit the files)
o 6 not
supported (run a given command on the files)
n 7 sort file list by name
e 8 sort file list by extension
s 9 sort file list by size
t not supported (sort file list by `time' (date))
+ = tag file at cursor
- untag file at cursor
Space toggle tagged status of file at
cursor
~ not supported (tag
files ending in `~')
In short, it supports both vi and Emacs keys
(and the wordstar-style
^E and ^X), and if you have cursor keys, they'll
probably work (unless
you're using a VT100, I'm afraid).
When
specifying drive/user to copy/move to, you can use any of the
forms a:,
0:, or a0:. If you don't give a drive/user, i.e. you just
press return,
then no copy/move is performed.
Some notes on the way the copy,
move, etc. commands work:
- copy/move test for copying to the same
drive/user, and don't
copy/move if this is the case.
- move
works by copying then deleting, even if you're only moving a
file from one
user to another on the same drive. This means that, if
you're moving a
file between users on the same drive, you temporarily
need enough room for
two copies of any file you want to move. There's
no such problem when
moving between different drives.
[Note to hackers: Why do I
implement file move this way when it would
be quicker to just change the
user number in the disk's directory?
Well, because it's more portable. CP/M
emulators translating native
directories on the fly (like Michael
Bischoff's excellent `cpm'
emulator for Linux) can't possibly handle this
kind of thing. Also,
ZCN doesn't have much of a BIOS, so it wouldn't have
worked on that.]
- view is designed only for text files. It strips
the high bit (for
wordstar files), then displays control codes in ^x form,
so don't
count on the control codes necessarily meaning anything in
binary
files. A more serious problem with using it to display binary files
is
that it treats ^Z as EOF; so, as I say, it only really works for
text
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 built-in support for a few terminals. These
are:
Type Terminal
0 as defined in patch area
1 VT100
2 VT52 (PCW, +3, etc.) - this is the default
3 ZCN (this is auto-detected)
4 VC404
The idea behind being able
to specify terminal type when you run zselx
is that it's more convenient
if you sometimes use your machine via a
terminal or terminal emulator.
With most programs you have to devise
some method of patching them when
you want to use something other than
the default configuration. With
zselx, if (for example) I'm using my
ZCN box via kermit on my Linux box -
not uncommon - then it's just a
matter of using `zselx 1'.
See
the source (zselx.z) for details of the patch area.
******
Bugs
The screen-redrawing code is pretty much pessimal. :-( In
particular,
scrolling is done `by hand', rather than using any
insert/delete line
capability the terminal might have. This can really
hurt on a slow
serial link.
Doesn't yet support `co' option 5,
`mark blank'.
****** Acknowledgements
The original
`co' utility.
Hawkwind's "Warrior on the Edge of Time" and
"Hall of the Mountain
Grill" albums. I listened to them
constantly while hacking up zselx.
Well, one at a time of course, so not
*really* constantly, but... :-)
**** Third-party programs
included with ZCN
I've included several pre-patched versions of
third-party programs
such as QTERM, ZDE etc. in the `support' directory.
See the README
there for more info, and pointers to where to find the
original
versions. You may well find these programs useful, and you
should
definitely try them out.
** Limitations and
Bugs
*** Screen
ZCN only has a ten-line screen, and there
is no generic provision for
emulating a 24-line one. Many CP/M programs
assume a 24-line screen.
The cursor still flashes on/off when output
is redirected to the
serial port. `Fixing' this would slow down normal
output, so I'm
reluctant to do that.
*** Keyboard
The
NC100's keyboard hardware is less-than-perfect (see the top of
src/keyread.z
for a more detailed explanation), and ZCN tries very
hard to fix the
problems with it. It does better than the ROM does,
but may still not
quite be perfect.
Here's a more low-tech explanation of what the
problem is than the one
in keyread.z. Given the nature of the NC100's
keyboard, reasonably
fast typists such as myself can end up pressing two
or three keys at
once. If you press three keys at once, a spurious
keypress is
generated *at the hardware level*. The ROM software has
problems with
this - try typing the word "really" a few times in
the word processor
or BBC Basic. If you type it at a reasonable speed, it
comes out as
"reslly". The reason I wrote ZCN's
keyboard-input-fixing code was to
avoid this reslly annoying problem.
:-))
The only place in ZCN where shift-3 (the pounds-sterling
symbol) does
anything sensible is in BBC Basic (the `bbcbas' version, not
the
cut-down `bbcmin') - everywhere else, it's essentially
unsupported.
*** Storage
The largest PCMCIA memory card
size usable on the NC100 is 1024k, so
that's the maximum card size ZCN
supports. The maximum drive size
supported by ZCN is 256k, so larger cards
are split into either 2 or 4
drives. Blocks are always 1k (8 records) in
length. Yes, ZCN dates
back to the heady days of CP/M 1.4 in this respect.
:-) There is an
arbitrary limit of 4 directory blocks per drive. The
`format' command
always formats drives so they have 2 directory blocks
though (for a
maximum of 64 files). The `optdir' and `runrom' programs
assume there
are exactly 2 directory blocks, though they won't actually
damage
anything unless there's only one. (In practice, `runrom' is
extremely
unlikely to damage anything even in that case.)
If
the memory card is set to read-only via the switch on the side
(mine has
one, I'm not sure if they all do), this is completely
ignored by ZCN.
That's not to say the card isn't read-only - that's
done at the hardware
level so ZCN can't mess with the card no matter
what - but rather that ZCN
will pretend write operations have worked
etc.
The add-on disk
drive available for the NC100 (the RangerDisk3 from
Ranger) is not
supported, and for various reasons would be difficult
to support directly.
I could probably write a program for ZCN to
transfer files to/from an
MS-DOS format disk in the drive if someone
lends (or gives ;-)) me a
drive, though. Anyone willing to do that
should contact me, and I'll see
what I can do. (I've already written a
C program to read/write MS-DOS disk
images on a Unix box (I wrote it
before I'd heard of `mtools'), so I'd
only need to write absolute disk
read/write routines to get it working
under ZCN. It probably wouldn't
take long.)
*** Speed
ZCN's
file operations have turned out slower than I had expected when
I started
writing it. The speed is bearable IMHO, but very slow
considering it's
running off a ramdisk. You can generally speed things
up by running
`optdir' to optimise the directory blocks on a drive,
which can give
file-reading speeds of up to about 18k/sec for the best
case, about half
the speed of the hard disk on an average 8086-based
PC (arguably :-)).
This still isn't incredibly quick, but I doubt I'll
get it going any
faster.
The NC100 has a Z80 capable of running at 6MHz (a Z84C0006,
to be
precise), but the clock rate it runs at is about 4.606MHz. This
sounds
strange, but since Zilog apparently don't make CMOS Z80s of a
lower
spec than the Z84C0006 any more, it's not *that* weird to just run
a
6MHz chip slow. Presumably it's run at this lower speed to reduce
power
consumption.
Due to the interrupt burden of reading and decoding the
keyboard 100
times a second, the effective processor speed for normal
programs
running with interrupts enabled is about 4.491Mhz if one or more
keys
were pressed during a given interrupt, or about 3.626MHz if not.
(In
`tight interrupts' mode (more on this later), it's about 4MHz
whether
a key is pressed or not. Yes, this is sub-optimal, and no,
there's
nothing I can do about it.) This makes ZCN slightly quicker than
the
ROM software if no keys are pressed (the ROM manages about
4.359MHz
whether keys are pressed or not), but slower if a key's
pressed.
However, since the ROM doesn't actually interpret the keyboard
input
into a keypress until a program asks for the keyboard to be checked,
this
isn't a fair comparison.
It came as quite a shock when I realised
the NC100 really did run at
rather less than 6MHz, as I'd originally
thought... :-)
*** The NC200
Amstrad's followup to the
NC100, the NC200, may or may not run ZCN. I
would need to have an NC200 to
know for sure... :-) (I've had
third-hand notice that it does run ZCN
since originally writing this,
but without any detail as to how well it
runs. Presumably it's
something like what is outlined below, but I'd
welcome any more
specific confirmation of what works and what doesn't,
etc.)
In theory it *might* work. It wouldn't support the builtin
disk drive,
wouldn't use the extra memory, would only use half the screen,
and
would only work if the NC200 still has a PCMCIA slot and has the
screen
memory in the same place (unlikely). The various ROM-based ZCN
utils
(spell, calc, bbcbas, etc.) would have quite a good chance of
not working,
I expect. :-)
I'm not particularly interested in upgrading ZCN to
support the NC200.
(The reason is that I wouldn't buy one - it seems like
a reasonable
machine, but has always been seriously overpriced IMHO. If
someone
gives me an NC200, I'll do it.) If anyone wants to donate an NC200
or
write support themselves, please contact me.
***
Miscellaneous
If you read a file into the file being edited (with ^K
R) in ZDE, when
you next write the file the 2nd char. of the file type
(extension)
will have changed to that of the file that was loaded. A
kludgey
workaround is to always explicitly reset the current file's name
(with
^K N) after any `second file' operations such as ^K R and ^K W,
or
only to do second file operations on files with the same file type.
I
don't know if it's possible to fix this; it's related to the NMI
handling
and the whole problem with byte (0066h). Oh well, I suppose
it could have
been worse... (sigh). As Fermat might have said, I have
a truly marvellous
fix to this problem which this margin is too narrow
to contain. :-)
A
SUB file with args cannot be successfully executed from user 255.
This is
pretty obvious when you think about it (user 255 is read-only,
remember,
and `submit' needs to write out a $$$.sub to work), but is
still
weird.
** ZCN for hackers
This section is intended
for those who want to program for ZCN
specifically (rather than CP/M in
general), or are mad enough to try
hacking on ZCN itself.
If
you're new to programming CP/M, have a look at `zcnprog.txt' in the
`doc'
directory. It also covers zcnlib in detail. (Zcnlib makes
programming for
ZCN and CP/M a hell of a lot easier, quite frankly.)
*** The
Screen
The NC100's screen is 480 pixels wide by 64 pixels down. In
the memory
configuration used by ZCN, the screen memory is always placed
at
F000h. The screen is arranged so that each group of 8 pixels is
combined
into one byte with the most significant bit of each byte
being the
leftmost of the 8. If a bit is set, it appears as a black
pixel in the
relevant position. Each pixel line comprises 60 bytes,
giving the 480
pixels (bits).
This gives a screen memory size of 60*64=3840 bytes.
Since 60 is an
awkward number to handle in hardware, there are four
(wasted) bytes
after each 60-byte line. So 64*64=4096, i.e. the screen
carries on up
to the top of memory.
(Before you start getting
funny ideas, it's not a good idea to use
these wasted bytes - the terminal
driver uses plenty of block copies
when scrolling etc. It is in theory
possible to use the bytes in the
range FFFCh-FFFFh, but these are reserved
for use by ZCN.)
ZCN uses a character cell size of 4x6. This gives a
character
resolution of 120x10, and leaves four unused pixel lines. That
is, the
first two and last two pixel lines are normally unused by the
system
(although they are cleared by the internal command `cls', the
`drive
lights' use part of the bottom line, and they are temporarily
used
while writing a screen dump).
Under ZCN, the screen can be
directly modified by simply writing to
the display memory. (You'll want to
turn the cursor off while doing
this.) There is no mechanism provided to
restore any previous
contents, though, so you'll have to do that yourself
if it's required.
ZCN itself provides no functions for drawing
graphics. Look in the
`zcnlib' directory for several public domain library
routines,
including graphics ones, which you can use in your own
programs.
*** Tight Interrupts
In (for example) an action
game, you would want to read more than one
key at once. This is a
completely alien concept to vanilla CP/M, but
ZCN provides a feature
called `tight interrupts' which makes doing
this possible.
Now,
generally on a machine with a simple port-mapped keyboard you
would just
read the ports directly. On ZCN and the NC100 in general
there are a few
problems with this:
1. ZCN enables interrupts whenever a BDOS
function is called. (You
would probably have wanted to disable
them.)
2. The NC100's keyboard ports are only readable after an
`interrupt
cause' port (90h) is read - and any maskable interrupt routine
*must*
read the keyboard in this way (or at least acknowledge the
interrupt)
or the machine will hang. [NB: I wrote this a long time ago. It
may
not be the case. It's difficult to test properly. Reading the
keyboard
directly is a real pain, in any case.]
The `tight
interrupts' mode fixes this problem by making ZCN's
maskable interrupt
routine do the bare minimum it is required to do;
as such, your game (or
whatever) gets the maximum share of CPU time
possible and can also read
the (fairly) raw keyboard map set up by the
interrupt routine.
Unfortunately, since you need to be able to read
all of the keys rather
than just one as is normally the case, the
interrupt routine must clear
the raw keyboard map on each interrupt.
Still, you should get an
reasonable (and constant) effective processor
speed, whether keys are
pressed or not.
If you want the full 4.606MHz, you might want to run
with interrupts
disabled and call an `interrupt routine' regularly `by
hand'. Look at
`inthndl.z' and `keyread.z' to see what's required. I've
used a
similar approach successfully in patches to get a couple of
ZX
Spectrum games (Elite and IK+) to run on ZCN. It's a pain to have
to
write your own interrupt handler though, and using tight ints mode
is
far easier.
To use tight interrupts mode, you have to call
two of ZCN's extra BDOS
functions (by calling address 0005h), as described
below:
Function #129 - Set Tight Interrupts
Entry: C=129, E=1
to set tight mode, E=0 to set normal interrupt mode.
Exit: none
Function #130 - Get Keyboard
Rawmap Address
Entry: C=130
Exit:
HL=address of rawmap
(As usual with the BDOS, registers not
mentioned above may have their
values changed.)
So to set tight
interrupts mode you would do something like this:
ld e,1
ld
c,129
call 5
Tight interrupts mode has its drawbacks of course.
Serial input is
ignored. Auto-poweroff is disabled (the timer is frozen).
The drive
lights are not updated. Normal BDOS and BIOS key-reading
functions
will not work correctly and may hang the machine if called. The
byte
at (66h) is not set to F7h if the value has changed. (However,
any
BDOS call will cause this check to happen.) Remember to turn
tight
ints mode back off again before doing a `ret' to ZCN; just doing
`jp
0' instead may be easier, as a warm boot also disables tight
ints
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:
krawmap: defw 0
...
ld c,130
call
5
ld (krawmap),hl
You should only do this once, of course, to
avoid the overhead of
calling the BDOS every time.
The keyboard
map is 256 bytes long. Each byte in the map is non-zero
if that key is
pressed, and zero if it is not. Each key is converted
by ZCN into the
ASCII equivalent (apart from a few `weird' keys such
as the cursors, which
give ^E/^S/^D/^X), and this is where it will
appear in the table.
Continuing the previous example, if we wanted to
see if the `q' key is
pressed:
ld hl,(krawmap)
ld e,'q'
ld d,0
add
hl,de
ld a,(hl)
and a
...etc.
You could do this more
quickly and easily with IX or IY, if the key to
test is constant (as in
this case) with something like:
ld ix,(krawmap)
ld
a,(ix+'q')
and a
...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
In ZCN v0.3
and up, you can just use the `halt' instruction to wait
for the next
interrupt. This is usually the 1/100th-sec interrupt, but
could also be an
interrupt caused by serial input (even if serial
input is being ignored,
as it is in tight ints mode, the interrupt
would still happen).
***
The Power On/off Switch
The power switch on the NC100 does not
directly control whether the
computer is on or off.
When the
button is pressed to turn the machine off, a non-maskable
interrupt is
generated. This has the effect of disabling maskable
interrupts, pushing
the program counter onto the stack, and jumping to
address 66h.
This
is extremely awkward for a CP/M-like OS - 66h is the address used
to hold
the 2nd character in the extension field of the 1st FCB
provided by the
system.
ZCN attempts to get around this problem by putting the value
F7h (i.e.
RST 30h) at 66h and putting a jump to the NMI/poweroff handler
at 30h.
In addition, any value which would ordinarily be put at or read
from
66h by ZCN's BDOS etc. is actually put somewhere different
(labelled
`real66' in the ZCN source - not directly accessible to
programs).
To further handle things which a program using ZCN might
do, such as
copying the filename from the FCB and using it, or clearing
the high
bits of the filename, ZCN actually compares the low seven bits
of any
appropriate character with the low seven bits of F7h. As well as
this,
any characters output to the console are checked - if the char. is
F7h
then the `real66' value is used instead.
Both the BDOS and
the maskable interrupt handler update the `real66'
value and reset (66h)
to F7h if the value in 66h has changed.
This is not perfect of
course - it means that programs might display
filenames which appear to
have a lowercase `w' as the 2nd character of
their extension. This can
happen if the filename was read from the
FCB, and the top bits of the
characters were cleared before display.
This is a little annoying (if
harmless), but impossible to work
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 is fairly unlikely to happen in
practice. :-)
***
Sound Hardware
[NB: See nciospec.doc on ftp.nvg.unit.no in
/pub/cpc/nc100 for a
better description of the sound hardware. There's
also a copy of the
relevant part in the `support' directory.
I
wrote this section before I knew of this document. In fact, I wrote
most
of ZCN before I knew about it. :-)]
The NC100's sound hardware is a
simple two-channel chip. I expect
Amstrad were originally going to put an
auto-dialler in the built-in
software; it's pretty pointless having a
two-channel chip just for a
beep.
The chip works by you telling
it what tone to play, and it playing it.
No volume control or anything
like that, just tone or no tone. The
ports to write the tone value to are
50h/51h for the first channel,
and 52h/53h for the second. You write the
low byte of the tone value
to the lower port number, and the high byte to
the higher.
As for tone values, here are some I worked out by ear.
They might not
be perfect, but they're good enough, I think. The values
are for
octave four... on my keyboard, at least. :-) At any rate, you
can
double these up to move down an octave, or halve them to move up
an
octave.
Note Value
(hex)
---- -----------
c 024C
c# 022B
d 020B
d# 01EF
e 01D2
f 01B8
f# 019F
g 0188
g# 0172
a 015D
a# 014A
b 0137
You
can turn a channel off by writing 80h to the higher of the two
port
numbers for either channel, e.g. 51h for the first.
You can get a
crude on/off speaker arrangement (similar to what you
get on a ZX
Spectrum) by writing a zero to the lower port number(s),
then writing the
higher one(s) with 00h for on, 80h for off. By no
means elegant, but
surprisingly effective. The `play1b', `play2b' and
`play4b' programs use
this technique.
*** Battery levels
If you want to
test battery levels yourself for some reason, it's
quite simple:
Get
a byte from port A0h.
If bit 2 is set then the lithium backup
battery is low.
If bit 3 is set then the main batteries are low.
If
bit 4 is *zero* then the PCMCIA card's battery is low.
(This bit is set if not, or if no card is
in the slot.)
(Note that as
mentioned in the `Battery level warnings'
section,
this particular battery-level test doesn't actually
seem to work properly.)
Other
things indicated by port A0h are:
Bit 1 is set when the printer is
busy.
Bit 6 is set if the card is write-protected.
Bit 7 is set when
there is no card in the slot.
*** PCMCIA Card Format
The
general format of a card is:
logical_drive_A [...
logical_drive_D].
Cards with a capacity of <=256k have a single
logical drive. 512k
cards have two. 1024k cards have four. Each must be
formatted
separately. Each is entirely self-contained, but drive A: must
always
be formatted for drives B:, C: or D: to be accessible.
Each
logical drive has the format:
boot_block [system_block_1 ... system_block_N]
data_block_1 ... data_block_N
(But remember that
data blocks are really numbered from zero. :-))
At least one, and
not more than four, consecutive blocks are used at
the start of the data
blocks section for directory entries. (ZCN's
`format' command always puts
exactly two directory blocks on the
formatted drive.) Each block contains
space for 32 directory entries,
with each entry taking 32 bytes. There are
zero system blocks if the
card is not bootable, and no more than 15 if it
is.
The format of the boot block is as follows:
name offset description
cf1jump1 0 18h if bootable,
otherwise C9h
cf1jump2 1 7Eh
cf1magic 2
ASCII for "ZCN1"
cf1size 6 word containing
total size of card in K
cf1sysb
8 number of system blocks
(0..15)
cf1dirb 9 number of directory blocks
(1..4)
cf1junk 10 reserved
cf1zero 64
64 bytes, set to zero
cf1boot
128 boot program, if
bootable (128 bytes max.)
cf1rrcode 256 256 bytes reserved for use by `runrom'
cf1fnx 512
Function-X-style boot program, if bootable (128
bytes)
cf1xtra 640
reserved (128 bytes)
cf1pairs
768 256 bytes reserved for
use by `runrom'
Only the first logical drive on a card is normally
booted from. That
said, it is possible to boot from a second (or third, or
fourth)
logical drive by using the old-style BBC Basic bootstrap command,
but
slightly modifying it so A is loaded with 90h for drive B:, A0h
for
C:, or B0h for D: (instead of the usual `ld a,80h' for A:).
The
format of directory entries is as follows:
(It's a simplified CP/M
2.2 format, almost the same as CP/M 1.4's, I
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 at the moment. Calling any other entries
gives
the error message `BIOS error' followed by a warm boot (i.e. a
return
to the CCP prompt).
The BDOS provides most of the
facilities that CP/M 2.2 does. (The
`version number' function pretends ZCN
is CP/M 2.2, in fact.) Programs
which attempt to calculate the disk space
free will give incorrect
results, as ZCN doesn't use or emulate disk
vectors etc. The AUX:
functions from CP/M 3 (`plus') replace the usual
CP/M 2.2 paper tape
punch/reader support - AUX: is hardcoded to be the
serial port.
*** Static Data Area
There are a
little over 2k of buffers and other storage areas:
[taken from the
`memory.txt' static memory registration file]
e600h-e6ffh used for
IM2 jump table
e700h also
used for jump table (while computer is on)
e7e7h-e7e9h jump to interrupt
handler (while computer is on)
e700h-e7ffh used to store old contents of
b300h-b3ffh by powrhndl.z
e800h-e87fh 128-byte keyboard buffer
e880h-e97fh
256-byte scratch area used by `find free block'
(note that this overwrites the ccp cmdline
buffer!)
e900h-e97fh 128-byte cmdline buffer used by ccp
e980h-e9ffh
128-byte card read/write buffer (needed 'cos of paging)
ea00h-eabfh
internal stack used by bdos functions.
eac0h-ecffh font data (`fontdata'
set to ea00h, but nowt written there)
ed00h-efffh 768-byte serial input
buffer (while computer is on)
ed00h-efffh used to store old contents of
b000h-b2ffh by powrhndl.z
These are followed by the screen memory
running from F000h to FFFFh,
as explained previously.
The
addresses of the font data (at EAC0h) and of the screen (at F000h)
can be
depended upon to stay the same if necessary. (Both can be quite
convenient
to know the location of, for some ZCN-specific stuff. Note
also that the
screen can be moved - see `nciohw.txt' in the `support'
directory for
details.) They may change if ZCN ever supports the
NC200, but that's
relatively unlikely to happen. After all, I haven't
even got an NC200. :-)
***
ZCN's use of the user stack
ZCN has to use the currently running
program's stack in some
situations. Here is a list of those situations,
and how many
words/bytes ZCN requires in each case:
situation words bytes
Call to BDOS 1 2
Call to BIOS 2 4
Interrupt 1 2
These
figures include the 2 bytes of stack used by the return address;
the BDOS
and interrupt handler don't actually use any more user stack
space
themselves.
These don't mount up - for example, if an interrupt
occurs during a
call to the BIOS, the two bytes of `user stack' used by
the interrupt
routine is actually on the internal BDOS/BIOS stack.
For
portability's sake, it's probably best if you don't squeeze your
stack too
tight. A sensible minimum, IMHO, is 80 bytes. I only made
ZCN depend on
the user stack this little so that particularly naive
programs would work,
e.g. PIPE v1.7.
** Copying and Modifying ZCN
ZCN is
distributed under the terms of the GNU General Public License.
However, I
feel that the GNU GPL could appear disconcerting to some
ZCN users. As
such, I provide reassurance below. :-)
First, a couple of questions
license pedants may have:
*** Why not make ZCN public domain?
Truly
public domain software is the property of the public at large.
Sounds
great. But, what this actually means is that anybody can do
anything they
want with it. Just think about what that means for a few
seconds.
To
me, the most important advantages the GPL has are that the program
always
remains free, that you get source and can modify it, and that
it allows
sensible commercial distribution, even if a profit is made.
Besides,
I do make things public domain sometimes, especially
libraries which I
think programmers will find useful. Zcnlib is a good
example.
***
Why allow commercial distribution?
Not-for-profit distribution is a
great thing, but it's not all that
common except on the Internet. Great if
you have access, a real pain
if you don't. (Even then, *somebody* pays for
your access, which a lot
of (for example) students tend to forget. Course
fees pay for a lot of
things, and net access tends to be one of
them.)
Whatever difficulties I might personally have with people
making money
off my work, the fact is that they usually don't make huge
amounts
because the software is always available for less by definition,
and
often they're small companies in the business because they're
interested
in free software anyway. (A good example - a German Linux
CD distributor
(S.u.S.E.) has over time sent me many free CD-ROMs as I
wrote something a
few people use (zgv) which they include on their
Linux distribution. As I
understand it, they ask all developers who
have written free software they
distribute if they'd like free CDs
like this, and any who would like them,
get them. That's the kind of
people I think we're talking about
here.)
Bottom line: All I would really do by prohibiting
commercial
distribution is stop some people who would otherwise use
and/or
distribute ZCN from doing so. Why bother?
***
Running ZCN
To quote from the GPL, "Activities other than
copying, distribution
and modification are not covered by this
License". This means that you
are free to run ZCN, write programs
while using it, etc.
*** Copying and Distribution
If
you've read the license (please do, if you haven't before) you may
think
it says that you must always copy the source to a program
whenever you
copy the program in binary or executable form. This is
not the case! (See
Section 3 of the license for more on this.) In
particular, when
transferring the ZCN binary `zcn.bin' to your NC100,
there is no need to
copy the source - this would be stupid on such a
small machine with such
limited and expensive storage, so that's just
as well. :-) Since you
already have the source on the machine you
transferred the binary from - or
at the very least, you know where to
get it - you are perfectly entitled
to copy only the executable code.
A rather common misconception, I
have found, is believing that the GPL
states that you must provide copies
of the program to anybody who asks
for one. This, again, is wrong. You
don't *have* to give/sell a copy
of ZCN to anyone - from the GPL,
"You are not required to accept this
License" but it says, as
you might imagine, "nothing else grants you
permission to modify or
distribute the Program". All this means is
that if you do want to
make a copy of ZCN, you must do so under the
terms of the GPL. This is
intended to give the person receiving a copy
of ZCN from you the same
rights you had when you obtained a copy.
***
Modification
This is a tricky subject, so it's best if I leave
Section 2 of the
license to *fully* explain this; but essentially, you
need to insert
prominent notices (comments) in any source files you change
saying
that you changed the file and when you changed it. In addition,
I
would be grateful if you could also do the following things:
1.
Say what it was you changed, and preferably why.
2. Use the date
format YYYY-MM-DD for numeric dates, e.g. 1994-04-01
is April 1, 1994.
YY-MM-DD is acceptable for years up to 1999, but
would look a bit odd for
2000, and be confusing for 2001 onwards.
3. I urge you to contribute
your changes to me to be included as part
of the `official' distribution
of ZCN. Do this by creating a context
diff with `diff -c oldfile newfile'
(`diff -u' style diffs are also
ok). If you absolutely *can't* do that,
please send the source files
which have changed and describe your changes
as completely as
possible. Please say which version of ZCN these changes
were made to
when sending them, in any case.
4. *Please* don't
use macros. They can get confusing very easily, and
tend to result in
greater memory use, which we can ill afford in ZCN.
These things are
optional, of course, but it would be nice if you
could do them.
Note
that source files tend to have old version numbers if they
haven't been
changed since that version. This is intentional, as the
file date/time
stamps then better reflect how long it's been since I
changed the file. I
think this is a Good Thing. For example, `boot.z'
hasn't changed since August
16th 1995, when I updated the header to
read `ZCN v0.3'. But in reality,
the rest of the file hasn't changed
since v0.1 in 1994!
Look at
the top of this file or do `ver' to find the true version
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.
*** Building ZCN
itself (the `kernel')
You need the free Z80 cross-assembler `zmac'
to assemble ZCN. (A copy
of the source is included with ZCN in the `zmac'
dir.) This compiles
on Unix and MS-DOS - it may or may not work on other
systems. (The
main requirements, at least for compilation :-), are an ANSI
C
compiler and either bison or yacc.)
In case you're using an
MS-DOS/Windows box, where it's less likely
that you'll be able to compile
it yourself, an MS-DOS executable of
zmac 1.1 is included in the
`dosutils' dir. This directory also
contains source and MS-DOS executable
for the `mkasmver' program
required to build ZCN on MS-DOS/Windows. (This
program is needed to
replace a bit of code in the Makefile which uses
`grep', `awk' and
`date'.)
If you want to make sure you have
the latest version of zmac, you can
check out
ftp://sunsite.unc.edu/pub/Linux/devel/lang/assemblers on the
net, which
should contain the latest copy. (But the copy included with
ZCN works well
enough, and is probably up to date anyway. :-))
After you've
compiled and installed `zmac' (if needed), doing `make'
(or `dosmake' on
MS-DOS/Windows) in the src directory should assemble
ZCN. You can transfer
the new `zcn.bin' binary from `../bin' across as
you did previously - this
is described near the start of this file.
[By the way, it's
theoretically possible to build ZCN under ZCN. But
I've yet to find a free
CP/M Z80 assembler which could handle this.
More to the point, it would be
incredibly slow and painful and would
require a good 512k or so of drive
space.]
*** Building ZCN as a whole (including utilities etc.)
Building
the whole of ZCN and associated programs requires rather
more. You'll
*definitely* need a Unix box (a Linux box is ideal -
that's what I use,
anyway :-)), which should have these things:
- zmac (bundled with
ZCN)
- awk, cat, cc, cut, date, dc, grep, mv, rm, sed, sh, sort, tee, tr,
uniq
(unlikely
to be a problem :-))
- GNU make
To be able to rebuild
`manpages.pma' and `zapdesc.bin', you'll need
the `cpm' CP/M emulator.
(See below for where to get it.) If you can't
run this, comment out the
HAVE_CPM_EMU line in `config.mk'.
If you want to be able to rebuild
zcnclock's `cities.mrf' (there isn't
any point usually), you'll need
xearth and netpbm installed. To avoid
this requirement, comment out the
HAVE_XEARTH_AND_NETPBM line in
`config.mk'.
Finally, if you
want to actually make a ZCN distribution, you'll need
the portable `zip'
program in order for the top-level Makefile's `make
dist' to work.
Now,
back to where to get `cpm'. Try looking in the directory pointed
to by
this URL:
ftp://sunsite.unc.edu/pub/Linux/system/emulators
At
the time of writing you'll need both `cpm-0.2.1.tar.gz' and
`cpm-0.2.1-glibc-rjm.patch.gz';
the patch makes it work on glibc-based
Linux systems, and also fixes
several bugs.
* Contributions welcome
Things that
would help with the development of ZCN are:
** Technical information
on the NC100 and on CP/M internals
Info. on the NC100 would be most
helpful. (I think I know most things
about it now, but I'm interested in
anything not covered in Amstrad's
`nciospec.doc'.)
Knowing
about any dubious or otherwise `tricky' assumptions CP/M
programs might
make which I should cater for would help. I think I've
got most of these
covered, though.
** Contact me if you use ZCN
This is
another thing I would appreciate. In my experience with the
other free
software I've made available that required significant time
and effort to
develop (probably the best example is zgv, a picture
viewer for Linux),
knowing that other people are using the program too
really helps. (Sure,
"what a piece of work is Man", but at least I'm
honest about
it.) In this case it's more important, because I doubt
many people will
use ZCN - there can't be many people who own an
NC100, and I imagine few
of them would want to run a CP/M clone on it.
Except possibly PCW owners.
:-)
** Suggest ideas for features and report bugs
I
welcome any suggestions for enhancements to ZCN. I can't say whether
I'd
actually implement them or not, memory is getting a little tight
to put in
all the bells and whistles I'd like :-(, but I'd certainly
consider any idea.
With
ZCN's aim of close CP/M compatibility, I could do with knowing
about
programs that don't work with it so that I can try to find out
what the
problem is.
* Acknowledgements
** Programs and
routines written by others
All of the programs in the `support'
directory (apart from crapmext.c)
were written by others. Details are in
each program's documentation.
`cal' is a port of a C original by
Martin Minow.
`expr' is a rather hacked-around port of a C original
by Erik
Baalbergen.
`man' uses Yoshihiko Mino's decompression
code from `pmexe2'.
`zap' uses a modified port of the GNU libc's
qsort routine (which is
actually called `msort'). The original C version
was by Mike Haertel.
** General thanks
[Or, "an
exercise in self-indulgence". :-)]
Graham Richards for sounding
interested, and being impressed at the
smallest of achievements in the
early days. (Also, the filled triangle
drawing routine in zcnlib is a
transliteration of one of his old
hacks.)
Cliff Lawson at
Amstrad for sending me a copy of `nciospec.doc' and
helping me with
various NC100 hardware questions.
Linux, a slightly less obscure
GPL'd OS. :-) (great for development,
even in Z80)
ZSIM
(running Superdos). I used this early on to test out `what does
CP/M do
when I do this?' scenarios.
The Linux DOS emulator `dosemu' which I
used to run ZSIM. :-)
Michael Bischoff for his `cpm' emulator, which
I now use instead of
ZSIM, and for posting me CP/M docs. (And for not
screaming at me when
I bought a CP/M manual soon after. :-})
Steven
Flintham for getting an up-to-date version of ZCN on the net
for me - and
for (many moons ago) writing to me for a current version
of ZCN despite
not having an NC100, which I think says something,
though I'm not sure
what. :-) He also gave helpful hints on the BBCBAS
section.
Locomotive
CP/M Plus for the Sinclair ZX Spectrum +3 - for getting me
interested in
CP/M in the first place.
"An Introduction to Z80 Machine
Code" by R. A. and J. W. Penfold (the
omnipresent R. A. Penfold
strikes again), and "A Z80 Workshop Manual"
by E. A. Parr.
The
"BBC Basic features not covered in the NC100 manual" section
would
probably not have been possible without considerable reference to
the
NC100 manual, "NC100 Magic" by Vic Gerhardi and Dave
Hampson, and the
Acorn Electron manual.
Games played between
sessions of pulling hair out: Tetris Attack,
Wipeout 2097, Tekken 2,
Nethack, DOOM, Tempest 2000 (and X3), Sensible
Soccer, V-Rally, Super
Bomberman 3, Stunt Race FX, Elite, CP/M Rogue,
and Mille Bournes (BSD
version).
Music played incessantly while hacking ZCN:
"Counterparts"
by Rush
"Different Stages" by Rush
"Hemispheres"
by Rush
"Hold Your Fire" by Rush
"Moving
Pictures" by Rush
"Signals" by Rush
"Test For
Echo" by Rush
[Yow! Am I a Rush fan yet? :-)]
"Close To The
Edge" by Yes
"The Yes Album" by Yes
"Tempest
2000" soundtrack (PC ver.) by (IIRC) Ian Howe and Imagitec
"Victor"
by Victor
"Wish" by The Cure
"PXR5" by
Hawkwind
"Foo Fighters" by Foo Fighters
"Superunknown"
by Soundgarden
"Debussy: Piano Music", a compilation of Debussy
works
"Tubular Bells II" by Mike Oldfield
"Zoolook"
by Jean-Michel Jarre
"I heartily endorse this event or
product."
-- Krusty the
Clown
:-)
All trademarks are acknowledged as belonging to their
respective
owners.
* Epilogue
The observant
will no doubt have noticed that as yet, I haven't
revealed or even hinted
at what ZCN stands for; and with good reason.
ZCN originally stood for
"Zgedneil's CP/M for the NC100", a rather
crap tongue-in-cheek
name I hastily thought up when designing ZCN's
drive format (while
computerless during 2nd year exam re-takes,
scrawling notes on a rather
more low-tech notepad by the fountain in
Woolwich town centre) as I needed
something meaningful to put in the
`cf1magic' field. Sad but true. Now it
just stands, for, well, ZCN
really. :-)
Why `zgedneil'? Oh,
well that's an old Rush-influenced password I used
ages ago, which I
adopted in 1992 as a standard pseudonym for where
such things are the norm
(some BBS-like systems, for example). I had
used `z' as a prefix to program
names a couple of times in the
"zgedneil's foo" sense, as a
(slightly crap) way of making them less
likely to conflict with existing
ones, and GDR pointed out that
"every" program I wrote now
started with a `z'. In response, I then
started *really* naming lots of
things `zfoo'. :-)
* The future of ZCN
I'm
reasonably happy with ZCN now, and I regard it as `finished',
pretty much.
Any future releases are unlikely to contain much more
than bugfixes. This
only applies to ZCN itself (the `kernel', if you
like) - I might add extra
utilities, or hack on existing ones, etc. at
some stage. (Indeed, this was
essentially what I did for v1.1 and
v1.2.)
In other words,
while there might possibly be ZCN releases after this
one, I doubt
there'll ever be sufficient change to justify a ZCN v2.0.
Then
again, I thought it was `finished' in 1995, so who knows? :-)
*
Getting ZCN
ZCN should be available on the net if you have anonymous
ftp access,
on ftp.nvg.unit.no in /pub/cpc/nc100. Don't expect it to
*necessarily*
be the most recent version, as I don't have any net access
at the
moment. (Though thanks to Steven it's an awful lot more recent than
it
was. :-))
I'll send a copy of the latest version of ZCN to
anyone who sends me a
3.5" disk and an SAE. Be sure to say you want
ZCN, though. :-) My
address is below. You can do this again at some point
in the future if
you'd then like a copy of the latest version, but please
don't do this
any more often than once every 6 months, and bear in mind
that ZCN may
not have been updated since you last got a copy. (I don't
tend to
update ZCN very often these days - not long before the release of
v1.1
it had been a year before I'd made any changes at all!)
Disks
can only be sent in MS-DOS, minix, and ext2 formats, and it'd
save me some
trouble if the disk was already formatted. I'll send ZCN
as a zip file
unless you specify a different format to use. ZCN fits
(compressed) onto a
single 1440k disk (just! :-)), but won't fit on a
720k one any more.
I
can send ZCN in most archive formats (zip, lzh, tar, tar.Z, tar.gz,
tar.bz2,
arc, zoo) but I can't (won't) send it in arj format due to
the lack of a
free utility to create arj files.
In addition, don't forget the
slightly fragile nature of the postal
service. If you don't get the disk
back within two weeks, you can
reasonably assume it got lost in the post.
It only happens quite
rarely, but it *does* happen. There's nothing I can
do to help this,
and all you can realistically do is try again.
You
can also contact me if you have any queries or problems with ZCN,
or,
well, any reason really. :-) If you're writing via snail-mail, be
sure to
include an SAE or other suitable return postage if you want to
guarantee a
reply.
* Contacting the Author
You can email me at
rus@forfree.at but since I'm not on the net, mail
received there is just
posted to me at regular intervals by a friend
(and similarly I post
responses back to be emailed). It could take as
long as six weeks for you
to get a response - if that's a problem,
then you could write to me
directly instead (more hassle, but usually
quicker).
You can
write to me at:
Russell
Marks,
3 Rapley
Close,
Camberley,
Surrey,
GU15 4ER,
United
Kingdom.