| Routines

04C2: THE 'SA-BYTES' SUBROUTINE

Used by the routine at SA_CONTRL. This subroutine is called to save the header information and later the actual program/data block to tape.
Input
A | +00 (header block) or +FF (data block)
DE | Block length
IX | Start address
SA_BYTES | 04C2 | LD HL,$053F | Pre-load the machine stack with the address SA_LD_RET.
| 04C5 | PUSH HL
| 04C6 | LD HL,$1F80 | This constant will give a leader of about 5 seconds for a 'header'.
| 04C9 | BIT 7,A | Jump forward if saving a header.
| 04CB | JR Z,SA_FLAG
| 04CD | LD HL,$0C98 | This constant will give a leader of about 2 seconds for a program/data block.
SA_FLAG | 04D0 | EX AF,AF' | The flag is saved.
| 04D1 | INC DE | The 'length' is incremented and the 'base address' reduced to allow for the flag.
| 04D2 | DEC IX
| 04D4 | DI | The maskable interrupt is disabled during the save.
| 04D5 | LD A,$02 | Signal 'MIC on' and border to be red.
| 04D7 | LD B,A | Give a value to B.
A loop is now entered to create the pulses of the leader. Both the 'MIC on' and the 'MIC off' pulses are 2,168 T states in length. The colour of the border changes from red to cyan with each 'edge'. Note: an 'edge' will be a transition either from 'on' to 'off', or from 'off' to 'on'.
SA_LEADER | 04D8 | DJNZ SA_LEADER | The main timing period.
| 04DA | OUT ($FE),A | MIC on/off, border red/cyan, on each pass.
| 04DC | XOR $0F
| 04DE | LD B,$A4 | The main timing constant.
| 04E0 | DEC L | Decrease the low counter.
| 04E1 | JR NZ,SA_LEADER | Jump back for another pulse.
| 04E3 | DEC B | Allow for the longer path (reduce by 13 T states).
| 04E4 | DEC H | Decrease the high counter.
| 04E5 | JP P,SA_LEADER | Jump back for another pulse until completion of the leader.
A sync pulse is now sent.
| 04E8 | LD B,$2F |
SA_SYNC_1 | 04EA | DJNZ SA_SYNC_1 | MIC off for 667 T states from 'OUT to OUT'.
| 04EC | OUT ($FE),A | MIC on and red.
| 04EE | LD A,$0D | Signal 'MIC off and cyan'.
| 04F0 | LD B,$37 | MIC on for 735 T States from 'OUT to OUT'.
SA_SYNC_2 | 04F2 | DJNZ SA_SYNC_2
| 04F4 | OUT ($FE),A | Now MIC off and border cyan.
The header v. program/data flag will be the first byte to be saved.
| 04F6 | LD BC,$3B0E | +3B is a timing constant; +0E signals 'MIC off and yellow'.
| 04F9 | EX AF,AF' | Fetch the flag and pass it to the L register for 'sending'.
| 04FA | LD L,A
| 04FB | JP SA_START | Jump forward into the saving loop.
The byte saving loop is now entered. The first byte to be saved is the flag; this is followed by the actual data bytes and the final byte sent is the parity byte that is built up by considering the values of all the earlier bytes.
SA_LOOP | 04FE | LD A,D | The 'length' counter is tested and the jump taken when it has reached zero.
| 04FF | OR E
| 0500 | JR Z,SA_PARITY
| 0502 | LD L,(IX+$00) | Fetch the next byte that is to be saved.
SA_LOOP_P | 0505 | LD A,H | Fetch the current 'parity'.
| 0506 | XOR L | Include the present byte.
SA_START | 0507 | LD H,A | Restore the 'parity'. Note that on entry here the 'flag' value initialises 'parity'.
| 0508 | LD A,$01 | Signal 'MIC on and blue'.
| 050A | SCF | Set the carry flag. This will act as a 'marker' for the 8 bits of a byte.
| 050B | JP SA_8_BITS | Jump forward.
When it is time to send the 'parity' byte then it is transferred to the L register for saving.
SA_PARITY | 050E | LD L,H | Get final 'parity' value.
| 050F | JR SA_LOOP_P | Jump back.
The following inner loop produces the actual pulses. The loop is entered at SA_BIT_1 with the type of the bit to be saved indicated by the carry flag. Two passes of the loop are made for each bit thereby making an 'off pulse' and an 'on pulse'. The pulses for a reset bit are shorter by 855 T states.
SA_BIT_2 | 0511 | LD A,C | Come here on the second pass and fetch 'MIC off and yellow'.
| 0512 | BIT 7,B | Set the zero flag to show 'second pass'.
SA_BIT_1 | 0514 | DJNZ SA_BIT_1 | The main timing loop; always 801 T states on a second pass.
| 0516 | JR NC,SA_OUT | Jump, taking the shorter path, if saving a '0'.
| 0518 | LD B,$42 | However if saving a '1' then add 855 T states.
SA_SET | 051A | DJNZ SA_SET
SA_OUT | 051C | OUT ($FE),A | On the first pass 'MIC on and blue' and on the second pass 'MIC off and yellow'.
| 051E | LD B,$3E | Set the timing constant for the second pass.
| 0520 | JR NZ,SA_BIT_2 | Jump back at the end of the first pass; otherwise reclaim 13 T states.
| 0522 | DEC B
| 0523 | XOR A | Clear the carry flag and set A to hold +01 (MIC on and blue) before continuing into the '8 bit loop'.
| 0524 | INC A
The '8 bit loop' is entered initially with the whole byte in the L register and the carry flag set. However it is re-entered after each bit has been saved until the point is reached when the 'marker' passes to the carry flag leaving the L register empty.
SA_8_BITS | 0525 | RL L | Move bit 7 to the carry and the 'marker' leftwards.
| 0527 | JP NZ,SA_BIT_1 | Save the bit unless finished with the byte.
| 052A | DEC DE | Decrease the 'counter'.
| 052B | INC IX | Advance the 'base address'.
| 052D | LD B,$31 | Set the timing constant for the first bit of the next byte.
| 052F | LD A,$7F | Return (to SA_LD_RET) if the BREAK key is being pressed.
| 0531 | IN A,($FE)
| 0533 | RRA
| 0534 | RET NC
| 0535 | LD A,D | Otherwise test the 'counter' and jump back even if it has reached zero (so as to send the 'parity' byte).
| 0536 | INC A
| 0537 | JP NZ,SA_LOOP
| 053A | LD B,$3B | Exit when the 'counter' reaches +FFFF. But first give a short delay.
SA_DELAY | 053C | DJNZ SA_DELAY
| 053E | RET
Note: a reset bit will give a 'MIC off' pulse of 855 T states followed by a 'MIC on' pulse of 855 T states, whereas a set bit will give pulses of exactly twice as long. Note also that there are no gaps either between the sync pulse and the first bit of the flag, or between bytes.