Splitting the Atom |
|
page 45 to 50 |
CHAPTER 7
TAPE FILES, CRC AND PRINTER USAGE
The Tape
The Atom normally store information to tape at 300 baud. Some
chips on the market, such as DISATOM allow 1200 baud, but in all
cases the format of the files is the same. It is useful to study
this format in case there is some corruption of the tape that
prevents loading. The bulk of the information can often be
recovered.
There are three types of SAVE command used in the Atom.
- *SAVE named file
- Save named file
- Save unnamed file
The Atom manual gives details of how these are used. In the
first two cases the block header format is identical. The diagram
below shows the individual bytes on the tape header for a file
called ADVENTURE which will begin at #2900, finish at #3BFF, and
have a GO (*RUN) address of #3B50. This file has been *SAVED as a
named file using *SAVE"ADVENTURE 2900 3C00 3B50.
* |
* |
* |
* |
A |
D |
V |
E |
N |
T |
U |
R |
E |
0D |
E3 |
00 |
00 |
FF |
3B |
50 |
29 |
00 |
As can be seen, the operating system always places four stars
in front of the file name. If any of these stars are corrupted
the file cannot be loaded. The title of the file can be up to 13
characters (bytes) long, and so the actual length of the header
is variable depending on the size of the title. It can be as
short as 14 bytes, or as long as 26. The title is always
terminated by 0D (Carriage Return). It is possible to get up to
some real tricks with the title (see program protection).
Next byte is the header checksum, to insure that the header
itself has not been corrupted.
The next two bytes are the block number, which is given during
a *CAT. The first block in a file is always numbered zero (by the
way, you can abbreviate * CAT as simply *. and it works fine).
The next byte in the header holds the number of bytes in this
block of information (excluding the header itself and the
checksum). Normally this is FF, since the block contains a full
page of memory. However, it may be less than FF if either (1) you
save a very short program or (2) it is the last block in a file
that does not finish at the end of a page.
The next two bytes are the GO address. If you were to RUN the
program, the operating system would automatically jump to this
address and begin executing the machine code that should be
there. In our example the address is 3B50.
The final two bytes of the header is the location where this
block will be placed. For BASIC programs this is normally 2900
for the first block, filling up from there. Of course you may
change this in either the SAVE or LOAD command. Since our example
block is FF bytes long, it will be loaded into the memory
beginning at 2900 and finishing at 29FF.
The last byte of any block is the CHECKSUM, which includes the
header and the program proper, but not the checksum itself. As
the tape is read in the operating system executes ?DC with the
checksum at the end, and gives SUM ERROR 6 if they do not match.
Since this is not a true CRC check, it is possible to get no SUM
error if there are errors which exactly cancel out, and the
program will be loaded but corrupt.
If we had saved this file using the BASIC command SAVE
"ADVENTURE" the header would be of exactly the same
format, but BASIC would fill in the missing details of the title
before actually saving it. Thus it would find the value of TOP,
and would save to tape all memory from (?#12), which contains a
pointer to the bottom of the program, to TOP. It would use C2B2
as the GO address, which when executed just places you in Command
mode. This would be catastrophic in our example, since it
contains machine code AFTER the BASIC program, and is designed to
have this accomplished starting at 3B50. This is quite a common
fault when people copy programs. If there is any machine code
that is not within the BASIC program, or written by it in the
course of execution, then it is not saved, and the copied program
will fail.
The unnamed file is the fastest way to save memory, but does
not have any checksums, and the header is extremely brief. Since
the memory is not divided into blocks, the information is as one
continuous stream, and the header is needed only once. If our
example were saved thus: *SAVE 2900 3C00, the header would be
3C |
00 |
29 |
00 |
and that's all. |
If a tape is corrupted, it is possible to write machine code
subroutines that bring the entire contents of the tape, including
the header and checksum, into memory (or use the TAPEXXXX
function on DISATOM). It is stored in a temporary area, such as
8200. The memory at that are is then inspected, and the block of
FF bytes of actual program is then COPYed to its correct address,
say at 2900. Let us assume we captured the corrupt first block of
our example above at 8200. Since the actual program begins at
8217 we would then type COPY #8216, (#8216+#FF), #2900. This
would put the first block in its rightful place, but has left
behind the tape header and checksum. It does not of course insure
that there is no corruption in the program itself.
CRC for the Atom
CRC is short for 'Cyclic Redundancy Check'. There is no real
need to understand the mathematical theory of why it works, but
it is useful to see how it works, and we'll deal with this later.
It can be especially important to Atom owners, since we have no
CRC on the tape input routine, and it is thus possible to load a
program without getting an error message, but in fact there is an
(undetected) error. This is because the tape header stores a
checksum that is just the sum (modulo 256) of all the bytes in
that block, and so it is possible to get two (or more) errors
that exactly cancel each other out by giving the same sum as the
correct version. There are really two check bytes, one for the
tape header itself, and one for the block of information,
Most machines use a true CRC check, and so the chance of
getting an undetected error are very much smaller (indeed almost
0) than for a simple sum check. Further, since the check is in
ROM as part of the operating system, it is never lost on
power-down. The best that Atom users can do is to 'hide' a CRC in
an area of RAM that is not normally used, but of course this will
have to be reloaded each time the machine is powered up.
What is the advantage of this CRC? Well, just this: most
programs are resident from address #2900 to #3BFF in the expanded
Atom, and once a program is SAVEd there is no way to load it back
and run it without destroying the original (assuming the program
uses the graphics area). Therefore, if there was an error on the
taped version, you have lost the original by over-writing it. Now
if you had, say, a BBC machine you could have sent your program
to tape the LOAD it back into a ROM area. Of course, the program
will not actually be remembered by the computer as you can't
write to the ROM. However, the point is that as the program is
read from tape it is checked with CRC. If we get no errors we can
thus be assured that it was saved correctly. If we do get errors,
we still have the original in RAM, and so can save it again.
Using the CRC program below, it is also possible to do this
with the Atom, but it is slightly more laborious. The procedure
is this:
- Load in the CRC program to an out-of-the-way area.
- Write or load a program into the normal text area.
- Save your main program to tape.
- *LOAD your program back, starting at #8200.
- Run a RC on both versions of the program.
If CRC gives the same result, you can be assured that the
programs are identical, and that you have correctly saved it.
But what if they are not identical? This is harder to work
out. Here are the possible reasons:
- The program was correctly saved to tape, but there was an
error in reloading (recorder volume wrong etc.)
- The program was correctly saved to tape and correctly
loaded back, but there is a fault in RAM (rare).
- The program was not correctly saved to tape (usually a
fault of the tape material or recorder).
You must now go through the various diagnostic procedures to
find out just what the problem is. This is the rub. CRC is
excellent at telling you that things are not right, but tells you
nothing about where the error is. You can of course be lucky and
have an error where it doesn't make any difference anyway (such
as in a REM statement)! One of the few things that can be done
with CRC is to divide the program in half and use CRC on each
half, then repeat this until the error is located (a binary
search method).
How CRC works
Imagine any area of memory as a long tape, on which is printed
a series of 0's and 1's. Each 0 or 1 is called a bit, and each
block of eight bits is called a byte. Now imagine that you had
this tape in front of you, and that you had a square of card with
a window cut in it, so that you could view 16 bits (2 bytes) at a
time:
START |
Window |
END |
|
10110101 |
00100111 |
10100101 |
10111000 |
1011001 |
11010010 |
10010011 |
|
|
moves --> |
|
Start moving the window to the right. Each time a 1 appears
off the left side of the window, EOR the right side 8 bits with
#2D. When the window bumps up against the end, the number left in
it is the 'signature' of that area of meory. In practice, we will
use locations #A0, #A1 as the window, and the accumulator is used
to put the next 8 bits of memory into the window. Doing it in
this way, the memory is not disturbed.
10110101 |
00100111 |
10100101 |
10111000 |
1011001 |
11010010 |
10010011 |
|
V |
|
Accum. |
V |
|
|
|
A1 |
A0 |
Locations #90, #91 will be used to 'point' at the area of
memory under scrutiny, and #92,#93 to hold the address of END.
Locating the CRC program
So far as we know, the memory area from #3CA to #3FC is free,
and so is the area from #21C to #23F. It is possible to squeeze a
CRC program into these areas by putting the input and control
part at #3CA, and the main subroutine at #21C. We have tested
these areas out, and so far neither the operating system nor
application programs have 'stomped' on them.
The source program
This program uses ROM calls that are described in
"Splitting the Atom", and sets up the DISATOM command x
to point at it.
10 DIM JJ4; P.$12,$21; !#180=#3CA Set up labels, screen off
20 F.I=0 TO 4; JJI=-1;N. Point DIASATOM
30 F.I=0 TO 2; P= #3CA;[ Two passes, put this at #3CA, start assembler
40 LDA @CH"S"; JSR #CD0F Prompt S, in, START address
50 LDY @0; LDX @#90; JSR #F893 Store it at #90,#91
60 LDA @CH"E"; JSR #CD0F Prompt E, in, END address
70 LDY @0; LDX @#92; JSR #F893 Store it at #92,#93
80 LDY @0; LDX @#A0; STY #A1 Wipe the window
90:JJ1 JSR JJ2 Control area, moves the
100 LDX @#90; JSR #FA08 window from start to end
110 BNE JJ1
120 JSR JJ2 We've hit the end, so
130 LDX @#A0; JSR #F7F1 Print window
140 JMP #C55B;] Back to BASIC
150 P=#21C;[ Assemble at #21C
160:JJ2 LDX @8; CLC Set up for 8 bits
170 LDA (#90),Y Get a byte from memory
180:JJ3 LSR A; ROL#A0;ROL #A1; BCC JJ4
190 PHA
200 LDA #A0; EOR @#2D; STA #A0 EOR the piece of window
210 PLA
220:JJ4 DEX; BNE JJ3 Next bit
230 RTS Back to control area
240 ]; N.;P.$6"ASSEMBLY COMPLETE";E. Screen on, end assembly
Since this source code is in BASIC you can SAVE it in the
usual was as "CRCSOURCE" after having RUN it. The
machine code is now at #3CA and #21C, so you have a choice of
either saving #21C to #3FF as one big block (most of which isn't
wanted), or alternatively save the two areas #21C to #23F and
#3CA to #3FF as separate blocks. Only shutting off the machine
will remove the machine code, so you are safe after hitting
<BREAK>.
Using the program
If you have a DISATOM ROM fitted, you need only type x after
running the source code. When reloading the machine code, type
!#180=#3CA
and this will point DISATOM's x at the routine again. for
those without the chip, type LINK #3CA each time you want CRC.
The letter S (meaning Start) should appear on the screen. Type in
the four-digit hex address where you want CRC to begin, then hit
<RETURN>. CAUTION! - there was not enough room for input
error checks, so that while you are allowed to edit your input
before hitting <RETURN>, you cannot do so afterwards. An E
(for END) now appears on the screen. Type in the four-digit hex
address of the last byte you want checked, then hit
<RETURN>. Within a few seconds the four-digit hex
'signature' of that area of memory appears on screen. From your
Atom manual page 93, you will see that a BASIC program of this
type takes many minutes, so we have a big time saving in addition
to everything else. Try these tests on your resident ROMs to
confirm correct operation of the program:
ROM name |
Start |
End |
Signature |
Integer BASIC |
C000 |
CFFF |
D67D |
Integer BASIC |
F000 |
FFFF |
E386 |
Floating BASIC |
D000 |
DFFF |
AAA1 |
If you have a COPY function such as the one in DISATOM, you
can also use CRC to test RAM. Do this by CPYing one area of RAM
to another, then checking both areas with CRC, which should give
the same signature. As already mentioned, you can dump a program
to tape then *LOAD it to #8200 and use the CRC to confirm correct
saving. With this confirmation ability, we have taken to writing
down the CRC signature next to the title of the program, and
SAVEd our programs as unnamed files. This gives a greater
reduction in loading time. further, if you have a 1200 baud
SAVE/LOAD facility such as in DISATOM, you can use unnamed 1200
files. It is now possible to load in a big games program
extending from #2800 to #3BFF in just 40 seconds and be assured
of a correct load!
The Printer
The Atom is initialised such that line feed characters (0A)
are not sent to the parallel printer port used for operation of a
Centronics-type printer. It assumes that the printer has been
configured to give an auto-line-feed on receiving a carriage
return (0D).
Where this is inconvenient, the Atom can be made to pass the
line feed character by setting ?FE=FF. The address location FE
normally contains the character which will not be sent to the
printer, and setting it to FF will ensure all ASCII codes and
characters are transmitted.
You can check whether the printer is connected or not by
testing bit 7 of #B800 (handshake signal). You can then avoid
locking up the machine, by executing $2 only after a positive
handshake test.
|