A fast, small, and general purpose CRC-16/xmodem checksum algorithm that can be called from BASIC on the TRS-80 Model 100 computer and the like.
Download crcbas.do to your Model-T and run it. Usage is meant to be simple and self-explanatory.
-
crcbas.do (1 KB) is a BASIC program which loads gencrc (see below) and demonstrates how to execute it. It relocates the code into a string and does not interfere with any .co program loaded in ALTLCD or high memory.
-
gencrc.co (55 Bytes) is gencrc.asm assembled to run at memory location 61024. Usage:
CLEAR 256,61024 LOADM "gencrc.co" i%[0] = 12345 REM buffer start address i%[1] = 256 REM buffer length i%[2] = 0 REM (initial checksum / result) CALL 61024, 0, VARPTR(i%[0]) PRINT "Result:" i%[2]
A large file can be processed in blocks by simply leaving the result in
i%[2]instead of resetting it to zero. The final checksum will be the same as if it had been processed as a single piece. -
gencrc.asm is the source code for gencrc.co. It is merely a BASIC interface wrapped around crc16-pushpop.asm, an implementation of CRC-16 in 34 bytes of 8080 machine language. The push-pop algorithm is relatively fast, requiring an eighth of a second per kilobyte. (See crc16-8080 for faster, larger alternatives.)
The CRC-16/Xmodem algorithm is a Cyclic Redundancy Checksum from the 8-bit era of computing. There are actually many CRC-16 variations, and this one happens to be the flavor used by the Xmodem protocol.
If the calculated CRC-16 matches the published value for a file, then there is 99.9985% certainty that the file was received without error. CRC-16 only checks for accidental changes, unlike modern message digests, such as SHA-3, which are also secure against malicious adversaries. Please see crc16-8080 for a better understanding of the algorithm.
The crcbas.do version loads gencrc to a BASIC string buffer, which has two benefits:
- Coexists with any binary blobs you may have loaded into high memory (or ALTLCD).
- All code is kept in one file for easy distribution and use.
But that comes at a cost:
- crcbas.do adds about 400 bytes to your program, which seems excessive when gencrc.co is a 55 byte file. However, see the section on gencrc below for why crcbas.do may still come out ahead.
Note that the non-ASCII characters in crcbas.do are treated as text by
the Kyotronic sisters (the M100 et al.). Crcbas.do can be loaded over
the serial port (RUN "COM:88N1") as if it was a normal BASIC listing
in ASCII.
The M/L string is encoded in a custom variant of bang-code
that hijacks the ! (bang) character to encode addresses as relative
offsets (±32) in the following byte. [Offset byte = Target -
Current + 80 (decimal), where Current is the address of the
relevant opcode.]
Gencrc is meant to be used from a BASIC program, so if one decides to
use gencrc.co directly, instead of from a loader like crcbas.do, both
the BASIC program and gencrc.co will need to be distributed to end
users. The program should start with CLEAR 256, 61024 and LOADM "gencrc.co".
Because the value of MAXRAM (highest usable RAM address, plus one) varies on different models, the gencrc.asm file is "ORG'd" to run at memory location 61024. On a Tandy 200, where MAXRAM is 61104, an extra 25 bytes are reserved and unused. However, on a Model 100 or Tandy 102, where MAXRAM is 62960, 1881 bytes are wasted — a consequential amount on 8K machines. For this reason, the fact that gencrc.co is only 55 bytes is not relevant when comparing its memory footprint against the 400 bytes from crcbas.do's BASIC loader.
The choice was made to use an array of integers to pass the three input arguments instead of the original design of multiple calls to different addresses. This greatly simplified usage and saved many bytes. There are two costs to this choice:
-
Any program that CALLs gencrc must use VARPTR to get the address of the array. That makes it trickier to use on the NEC PC-8201 and PC-8300 which do not have a built-in VARPTR function. (See below.)
-
BASIC integers (signified by
%) are signed, and it is a fatal error to assign a value over 32767. [Sigh.]i%=32768 ?OV Error Ok
To refer to memory addresses above 32767, one must subtract 65536. For instance,
READ P$ V=VARPTR(P$): P=PEEK(V+1)+256*PEEK(V+2) IF P>=32768 THEN P=P-65536 i%[0] = P i%[1] = LEN(P$) i%[2] = 0 CALL S, 0, P
Gencrc.co works on a NEC, but the method of calling it from BASIC differs in two ways: VARPTR and HL.
- As noted above, N82 BASIC lacks VARPTR.
-
One solution is to use a shim that implements VARPTR, such as this one from Gary Weber:
39999 'VARPTR by Gary Weber for NEC 8201/8300 40000 A=64448 40010 POKEA,205:POKEA+1,175:POKEA+2,73:POKEA+3,235 40020 POKEA+4,58:POKEA+5,139:POKEA+6,250:POKEA+8,201 40030 IFVY$=""THENPRINT"VY$ not defined!":STOP 40035 A=64457 ' HL register for EXEC = 201/251 40040 FORH=1TOLEN(VY$):POKEA,ASC(MID\$(VY$,H,1)):A=A+1:NEXT:POKEA,0:POKE64464,0 40050 POKE63912,201:POKE63913,251:EXEC64448 40060 L=PEEK(63912):H=PEEK(63913):TY=PEEK(63911) 40070 RETURN
However, that's a lot of work to do a job — finding the address of an array of BASIC integers — that we can skip.
-
A better alternative would be to POKE to reserved, unused memory.
For example, the addresses from 61096 to 61101 are available. gencrc will use those addresses as input, if we set the HL register to 61096 before EXEC:
Variable Low High Start address 61096 61097 Length 61098 61099 Init/Result 61100 61101
-
- N82's
EXECrequires HL to be set via POKE:Register Location A 63911 L 63912 H 63913 For example,
POKE 63912, 168: POKE 63913, 238configures HL to contain the number 61096.A theoretical advantage of this method is that one can also PEEK those locations to see results, but it is moot for this program as we return the results by writing directly into memory.
Here is an example that performs a CRC check of the NEC PC-8201's 32K ROM:
CLEAR 256,61024
BLOAD "gencrc"
POKE 63912, 168: POKE 63913, 238 REM HL = 61096
POKE 61096, 0: POKE 61097, 0 REM Buffer address = 0000
POKE 61098, 0: POKE 61099, 128 REM Buffer length = 32768
POKE 61100, 0: POKE 61101, 0 REM Initial sum = 0
EXEC 61024
?PEEK(61100)+256*PEEK(61101) REM CRC-16 resultTODO: Create a NEC version of crcbas.do.