Please note this content is from the original WoS site, and may no longer be relevant. If you have any queries, please contact us.
The entire disassembly was taken from ‘The Complete Spectrum ROM Disassembly’ by Dr. Ian Logan and Dr. Frank O’Hara, as published by Melbourne House in 1983
This is the tape loading routine as in the Spectrum ROM. Note that all addresses and operands are in hexadecimal.
All timings are given in T states. 1 T state is 1 clock cycle = 1/3,500,000 seconds (on a 16K or 48K machine).
The routine starts at address 0556 and requires the following register settings:
IX | Start of the block, |
DE | Length of the block, |
A | Flag byte (normally +00 for the header and +FF for a data block), |
carry flag | set for LOAD, reset for VERIFY. |
It returns with the carry flag reset if an error occured. Possible errors are:
- Flag byte incorrect
- BREAK key pressed (D BREAK – CONT repeats)
- Time-out (R Tape Loading Error)
- Parity byte incorrect (R Tape Loading Error)
The following tape timing values are used by the ROM:
- Each leader halfpulse takes 2,168 T
- The first sync halfpulse takes 667 T
- The second sync halfpulse takes 735 T
- A ‘0’ bit takes two 855 T halfpulses
- A ‘1’ bit takes two 1,710 T halfpulses (twice the length of a ‘0’ bit)
Notice that the data bits are built from 2 equal ‘edges’ (full pulses), the leader and syncs are made up from single ‘edges’ (halfpulses).
THE DISASSEMBLY
THE 'SA/LD-RET' SUBROUTINE This subroutine is common to both SAVEing and LOADing. The border is set to its original colour and the BREAK key tested for a last time. 053F SA/LD-RET PUSH AF Save the carry flag (It is reset after a LOADing error) LD A,(BORDCR) Fetch the original border colour from AND +38 its system variable RRCA Move the border colour to bits 2, 1 & 0 RRCA RRCA OUT (+FE),A Set the border to its original colour LD A,+7F Read the BREAK key for a last time IN A,(+FE) RRA EI Enable the maskable interrupt JR C,0554,SA/LD-END Jump unless a break is to be made Report D - BREAK-CONT repeats 0552 REPORT-D RST 0008,ERROR-1 Call the error handling routine DEFB +0C Continue here. 0554 SA/LD-END POP AF Retrieve the carry flag RET Return to the calling routine THE 'LD-BYTES' SUBROUTINE This subroutine is called to LOAD the header information (from 076E) and later LOAD, or VERIFY, an actual block of data (from 0802). 0556 LD-BYTES INC D This resets the zero flag (D cannot hold +FF) EX AF,AF' The A register holds +00 for a header and +FF for a block of data The carry flag is reset for VERIFYing and set for LOADing DEC D Restore D to its original value DI The maskable interrupt is now disabled LD A,+0F The border is made WHITE OUT (+FE),A LD HL,+053F Pre-load the machine stack with the PUSH HL address - SA/LD-RET IN A,(+FE) Make an initial read of port 254 RRA Rotate the byte obtained AND +20 but keep only the EAR bit OR +02 Signal RED border LD C,A Store the value in the C register (+22 for 'off' and +02 for 'on' - the present EAR state) CP A Set the zero flag The first stage of reading a tape involves showing that a pulsing signal actually exists. (i.e. 'On/off' or 'off/on' edges.) 056B LD-BREAK RET NZ Return if the BREAK key is being pressed 056C LD-START CALL 05E7,LD-EDGE-1 Return with the carry flag reset if JR NC,056B,LD-BREAK there is no 'edge' within approx. 14,000 T states. But if an 'edge' is found the border will go CYAN The next stage involves waiting a while and then showing that the signal is still pulsing. LD HL,+0415 The length of this waiting period will 0574 LD-WAIT DJNZ 0574,LD-WAIT be almost one second in duration. DEC HL LD A,H OR L JR NZ,0574,LD-WAIT CALL 05E3,LD-EDGE-2 Continue only if two edges are found JR NC,056B,LD-BREAK within the allowed time period. Now accept only a 'leader signal'. 0580 LD-LEADER LD B,+9C The timing constant CALL 05E3,LD-EDGE-2 Continue only if two edges are found JR NC,056B,LD-BREAK within the allowed time period LD A,+C6 However the edges must have been found CP B within about 3,000 T states of each JR NC,056C,LD-START other INC H Count the pair of edges in the H JR NZ,0580,LD-LEADER register until 256 pairs have been found After the leader come the 'off' and 'on' parts of the sync pulse. 058F LD-SYNC LD B,+C9 The timing constant CALL 05E7,LD-EDGE-1 Every edge is considered until two edges JR NC,056B,LD-BREAK are found close together - these will be LD A,B the start and finishing edges of the CP +D4 'off' sync pulse JR NC,058F,LD-SYNC CALL 05E7,LD-EDGE-1 The finishing edge of the 'on' pulse RET NC must exist (Return carry flag reset) The bytes of the header or the program/data block can now be LOADed or VERIFied. But the first byte is the flag byte. LD A,C The border colours from now on will be XOR +03 BLUE & YELLOW LD C,A LD H,+00 Initialize the 'parity matching' byte to zero LD B,+B0 Set the timing constant for the flag byte. JR 05C8,LD-MARKER Jump forward into the byte LOADing loop The byte LOADing loop is used to fetch the bytes one at a time. The flag byte is first. This is followed by the data bytes and the last byte is the 'parity' byte. 05A9 LD-LOOP EX AF,AF' Fetch the flags JR NZ,05B3,LD-FLAG Jump forward only when handling the first byte JR NC,05BD,LD-VERIFY Jump forward is VERIFYing a tape LD (IX+00),L Make the actual LOAD when required JR 05C2,LD-NEXT Jump forward to LOAD the next byte 05B3 LD-FLAG RL C Keep the carry flag in a safe place temporarily XOR L Return now if the flag byte does not RET NZ match the first byte on the tape (Carry flag reset) LD A,C Restore the carry flag now RRA LD C,A INC DE Increase the counter to compensate for JR 05C4,LD-DEC its decrease after the jump If a data block is being verified then the freshly loaded byte is tested against the original byte. 05BD LD-VERIFY LD A,(IX+00) Fetch the original byte XOR L Match it against the new byte RET NZ Return if 'no match' (Carry flag reset) A new byte can now be collected from the tape. 05C2 LD-NEXT INC IX Increase the 'destination' 05C4 LD-DEC DEC DE Decrease the 'counter' EX AF,AF' Save the flags LD B,+B2 Set the timing constant 05C8 LD-MARKER LD L,+01 Clear the 'object' register apart from a 'marker' bit The 'LD-8-BITS' loop is used to build up a byte in the L register. 05CA LD-8-BITS CALL 05E3,LD-EDGE-2 Find the length of the 'off' and 'on' pulses of the next bit RET NC Return if the time period is exceeded (Carry flag reset) LD A,+CB Compare the length against approx. CP B 2,400 T states; resetting the carry flag for a '0' and setting it for a '1' RL L Include the new bit in the L register LD B,+B0 Set the timing constant for the next bit JP NC,05CA,LD-8-BITS Jump back whilst there are still bits to be fetched The 'parity matching' byte has to be updated with each new byte. LD A,H Fetch the 'parity matching' byte and XOR L include the new byte LD H,A Save it once again Passes round the loop are made until the 'counter' reaches zero. At that point the 'parity matching' byte should be holding zero. LD A,D Make a furter pass if the DE register OR E pair does not hold zero JR NZ,05A9,LD-LOOP LD A,H Fetch the 'parity matching' byte CP +01 Return with the carry flag set if the RET value is zero (Carry flag reset if in error) THE 'LD-EDGE-2' and 'LD-EDGE-1' SUBROUTINES These two subroutines form the most important part of the LOAD/VERIFY operation. The subroutines are entered with a timing constant in the B register, and the previous border colour and 'edge-type' in the C register. The subroutines return with the carry flag set if the required number of 'edges' have been found in the time allowed; and the change to the value in the B register shows just how long it took to find the 'edge(s)'. The carry flag will be reset if there is an error. The zero flag then signals 'BREAK pressed' by being reset, or 'time-up' by being set. The entry point LD-EDGE-2 is used when the length of a complete pulse is required and LD-EDGE-1 is used to find the time before the next 'edge'. 05E3 LD-EDGE-2 CALL 05E7,LD-EDGE-1 In effect call LD-EDGE-1 twice; RET NC returning in between in there is an error. 05E7 LD-EDGE-1 LD A,+16 Wait 358 T states before entering the 05E9 LD-DELAY DEC A sampling loop JR NZ,05E9,LD-DELAY AND A The sampling loop is now entered. The value in the B register is incremented for each pass; 'time-up' is given when B reaches zero. 05ED LD-SAMPLE INC B Count each pass RET Z Return carry reset & zero set if 'time-up'. LD A,+7F Read from port +7FFE IN A,(+FE) i.e. BREAK and EAR RRA Shift the byte RET NC Return carry reset & zero reset if BREAK was pressed XOR C Now test the byte against the 'last AND +20 edge-type' JR Z,05ED,LD-SAMPLE Jump back unless it has changed A new 'edge' has been found within the time period allowed for the search. So change the border colour and set the carry flag. LD A,C Change the 'last edge-type' and border CPL colour LD C,A AND +07 Keep only the border colour OR +08 Signal 'MIC off' OUT (+FE),A Change the border colour (RED/CYAN or BLUE/YELLOW) SCF Signal the successful search before RET returning Note: The LD-EDGE-1 subroutine takes 464 T states, plus an additional 59 T states for each unsuccessful pass around the sampling loop. For example, therefore, when awaiting the sync pulse (see LD-SYNC at 058F) allowance is made for ten additional passes through the sampling loop. The search is thereby for the next edge to be found within, roughly, 1,100 T states (464 + 10 * 59 overhead). This will prove successful for the sync 'off' pulse that comes after the long 'leader pulses'.