Splitting the Atom back exit forward 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.

  1. *SAVE named file
  2. Save named file
  3. 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:

  1. Load in the CRC program to an out-of-the-way area.
  2. Write or load a program into the normal text area.
  3. Save your main program to tape.
  4. *LOAD your program back, starting at #8200.
  5. 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:

  1. The program was correctly saved to tape, but there was an error in reloading (recorder volume wrong etc.)
  2. The program was correctly saved to tape and correctly loaded back, but there is a fault in RAM (rare).
  3. 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.

back exit forward