The Need for Data Integrity
When data is transferred over an unreliable medium (like a cassette tape or a network connection), or when code is loaded from disk, electrical noise or corruption can change the data bytes. A Checksum or CRC provides a simple way to verify that the data received is exactly what was sent.
Method 1: The Simple Checksum (The Fast Way)
A simple checksum is the fastest method. It involves adding up every byte in the data block.
The Principle: Sum every byte, and discard any overflow (carry). The final 8-bit sum is the checksum.
The Z80 Routine (Simplified):
CHECKSUM_ROUTINE:
LD HL, START_ADDRESS ; HL ← Address of the data block
LD BC, BLOCK_LENGTH ; BC ← Length of the block
LD A, 0 ; A ← The 8-bit accumulator (checksum result)
CHECK_LOOP:
ADD A, (HL) ; Add current byte ← A + (HL). Carry is discarded.
INC HL ; Move to the next byte
DEC BC ; Decrement counter
LD D, B ; Check if BC is zero (16-bit check)
OR C ; (D OR C) is zero only if BC=0
JP NZ, CHECK_LOOP ; Loop if BC is Not Zero
; The 8-bit checksum is now in the Accumulator (A).
RET
Method 2: Cyclic Redundancy Check (CRC)
The CRC is a much more robust error-checking method (used in networks and modern file systems) because it is based on polynomial long division, making it better at detecting bursts of errors.
The Challenge: CRC calculation is highly complex and requires many iterations of shifts, XORs, and conditional logic. It is typically too slow for real-time processing on the Z80 unless the data blocks are very small.
The Algorithm Focus: The code implements the polynomial division using the Z80’s XOR′ and **shifting** instructions (
SLA′, `RRCA′). The algorithm iteratively calculates the remainder of the division. The final remainder is the CRC value.
Verifying the Data
To verify data integrity, the receiving system:
- Calculates the checksum/CRC of the received data.
- Compares the calculated value to the original checksum/CRC byte appended to the data packet.
The Final Check:
CALL CHECKSUM_ROUTINE ; A ← calculated checksum
CP (CHECKSUM_ADDR) ; Compare calculated A with stored checksum
JP Z, DATA_GOOD ; Jump if Zero flag is set (match!)
CALL DATA_CORRUPTED ; Error handler