;; Modified Topo soft loader
;;
;; Multi-colour bars in the border, aka "Spanish" style Spectrum variant loader.
;;
;; This loader uses standard Spectrum ROM timings. In fact it is essentially a CPC version of the
;; Spectrum ROM loader itself.
;;
;;
;; Loader form on cassette:
;; Pilot tone (min 256 pulses)
;; Sync pulse
;; 1 byte sync byte (on spectrum 0 for header and &ff for data)
;; n bytes of data (defined by DE register)
;; 1 byte parity checksum
;;
;; Original had the following bugs:
;; 1. bit 7 of R register had to be 1, otherwise it could change ram/rom configuration while loading
;; 2. flags were not returned, so you didn't know if the data was read incorrectly or not
;;
;; It also had extra code that was unnecessary:
;; 1. turning cassette motor on/off was complex, when in previous instructions they had turned it on anyway.
;; 2. code for changing border colour presumably on a read error. but didn't seem to be used.
;;
;;
;; Entry conditions:
;;
;; IX = start
;; DE = length (D must not be &ff)
;; A = sync byte expected
;;
;; Interrupts must be disabled
;;
;; Exit Conditions:
;; Alternative register set is corrupted. 
;;
;; carry clear - load ok
;; carry set, zero set - time up
;; carry set, zero reset - if esc pressed
;;
;; Use 2CDT to write Spectrum ROM blocks to a CDT. Note that at this time it will only write a sync byte of &ff.

topoload:

inc     d					;; reset the zero flag (D cannot hold &ff)
ex      af,af'				;; A register holds sync byte. 
dec     d					;; restore D

exx
;; we need B' to be so we can write to gate-array i/o port for colour change when loading

ld      bc,&7f00+&10		;; Gate-Array + border
out 	(c),c				;; select pen index to change while loading (&10 is border)
ld c,&54					;; set to black
out (c),c
exx

ld      bc,&f40e			;; select AY register 14 (for reading keyboard)
out     (c),c

ld      bc,&f600+&c0+&10	;; "AY write register" and enable tape motor
out     (c),c

ld      c,&10				;; "AY inactive" and enable tape motor (register is latched into AY)
out     (c),c

ld      bc,&f792			;; set PPI port A to read (so we can read keyboard data)
out     (c),c				;; this will also write 0 to port C and port A on CPC.

ld      bc,&f600+&40+&10+&8	;; tape motor enable, "AY read register", select keyboard row 8
							;; (keys on this row: z, caps lock, a, tab, q, esc, 2, 1)
							;; we are only interested in ESC
out     (c),c

;; make an initial read of cassette input
ld      a,&f5			;; PPI port B
in      a,(&00)			;; read port (tape read etc)
and     &80				;; isolate tape read data

ld      c,a
cp      a				;; set the zero flag
l8107: 
ret nz 					;; returns if esc key is pressed (was RET NZ)
l8108: 
call    l817b
jr      nc,l8107

;; the wait is meant to be almost one second
ld      hl,&415
l8110: 
djnz    l8110
dec     hl
ld      a,h
or      l
jr      nz,l8110
;; continue if only two edges are found within this allowed time period
call    l8177
jr      nc,l8107

;; only accept leader signal
l811c: 
ld      b,&9c
call    l8177
jr      nc,l8107
ld      a,&b9
cp      b
jr      nc,l8108
inc     h
jr      nz,l811c

;; on/off parts of sync pulse
l812b: 
ld      b,&c9
call    l817b
jr      nc,l8107
ld      a,b
cp      &d1
jr      nc,l812b
l8137: 
call    l817b
ret     nc

ld      h,&00			;; parity matching byte (checksum)
ld      b,&b0			;; timing constant for flag byte and data
jr      l815d

l8145: 
ex      af,af'			;; fetch the flags
jr      nz,l814d		;; jump if we are handling first byte
;; L = data byte read from cassette
;; store to RAM
ld      (ix+&00),l
jr      l8157

l814d: 
rr      c				;; keep carry in safe place
						;; NOTE: Bit 7 is cassette read previous state
						;; We need to do a right shift so that cassette read moves into bit 6,
						;; our stored carry then goes into bit 7
xor     l				;; check sync byte is as we expect
ret     nz

ld      a,c				;; restore carry flag now
rla     				;; bit 7 goes into carry restoring it, bit 6 goes back to bit 7 to restore tape input value
ld      c,a
inc     de			;; increase counter to compensate for it's decrease
jr      l8159

l8157: 
inc     ix			;; increase destination
l8159: 
dec     de			;; decrease counter
ex      af,af'		;; save the flags

ld      b,&b2		;; timing constant
l815d: 
ld      l,&01		;; marker bit (defines number of bits to read, and finally becomes value read)
l815f: 
call    l8177
ret     nc

ld      a,&c3		;; compare the length against approx 2,400T states, resetting the carry flag for a '0' and setting it for a '1