org $aa00

; Ints off

	di

; Set mode 

	ld     bc, $7f00
	ld     a, $8C + 0
	out    (c), a

; all blacks

	call blackenpal

; Load screen scrc.bin

	ld     ix, $6400
	ld     de, 8260
	ld     a, $ff
	call   topoload	

; Decompress

	ld     hl, $6400
	ld     de, $c000
	call   dzx7_standard

; Set palette

	call   setPal

; Load main block gamec.bin

	ld     ix, 20230
	ld     de, 23290
	ld     a, $ff
	call   topoload

; Decompress

	ld     hl, 20230
	ld     de, $400
	call   dzx7_standard

; all blacks

	call blackenpal
	
; Load arkos + sfx arkos_sfx.c.bin

	ld     ix, 49152
	ld     de, 1603
	ld     a, $FF
	call   topoload

; Decompress sfx

	ld     hl, 49152 + 1204
	ld     de, $EE00
	call   dzx7_standard

; Decompress arkos
	ld     hl, 49152
	ld     de, 34868
	call   dzx7_standard

; Load music m1.c.bin
	ld     ix, 52832
	ld     de, 404
	ld     a, $FF
	call   topoload

; Load music m2.c.bin
	ld     ix, 54849
	ld     de, 397
	ld     a, $FF
	call   topoload

; Run

	jp     $400

blackenpal:
	ld     de, 15	
	ld     b, $7f

loopBlackPal:

	out    (c), e    ; Select index
	ld     a, 20
	or     $40
	out    (c), a    ; Set colour
	dec    e
	jp     p, loopBlackPal

	ret

setPal:

; Set palette adapted from cpctelera

	ld     de, 15	
	ld     hl, palette
	add    hl, de
	ld     b, $7f

loopPal:

	out    (c), e    ; Select index
	ld     a, (hl)
	or     $40
	out    (c), a    ; Set colour
	dec    hl
	dec    e
	jp     p, loopPal

	ret

palette:
	defb 3, 20, 4, 21, 6, 0, 27, 18, 22, 28, 12, 14, 7, 5, 24, 11

;; 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'
cp      b
rl      l			;; include the new bit in the register
ld      b,&b0		;; set timing constant for next bit
jr      nc,l815f

;; L = data byte read
;; combine with checksum
ld      a,h
xor     l
ld      h,a

;; DE = count
ld      a,d
or      e
jr      nz,l8145

exx
ld c,&54						;; make border black
out (c),c
exx

ld      bc,&f782				;; set PPI port A for output
out     (c),c
ld      bc,&f600				;; tape motor off, "AY inactive"
out     (c),c

;; H = checksum byte
;; H = 0 means checksum ok
ld      a,h
cp      &01
;; return with carry flag set if the result is good
;; carry clear otherwise
ret     


;;------------------------------------------------------------
l8177: 
call    l817b			;; in effect call ld-edge-1 twice returning in between if there is an error
ret     nc

;; wait 358T states before entering sampling loop
l817b: 
ld      a,&16			;; [2]
l817d: 
dec     a				;; [1]
jr      nz,l817d		;; ([3]+[1])*&15+[2]

and     a
l8181: 
inc     b				;; count each pass
ret     z				;; return carry reset and zero set if time up.

;; read keyboard
ld      a,&f4			;; PPI port A 
in      a,(00h)			;; read port and read keyboard through AY register 14
and     &04				;; isolate state of bit 2 (ESC key)
						;; bit will be 0 if key is pressed
xor     &04				;; has key been pressed? 
ret     nz				;; quit (carry reset, zero reset)

ld      a,&f5			;; PPI port B
in      a,(&00)			;; read port (tape read etc)
xor     c
and     &80				;; isolate tape read
jr      z,l8181
ld      a,c				;; effectively toggle bit 7 of C
cpl     				;; which is the tape read state we want to see next
ld      c,a

exx     				;; swap to alternative register set so that we can change colour
;; this sets colour and gives us the multi colour border
ld 		a,r				;; get R register
and &1f					;; ensure it is in range of colour value
or &40					;; bit 7 = 0, bit 6 = 1
out (c),a				;; write colour value
nop						;; this is to ensure the number of cycles is the same
						;; compared to the replaced instructions
						;; (timings from toposoft loader)
exx     
scf     
ret     

; -----------------------------------------------------------------------------
; ZX7 decoder by Einar Saukas, Antonio Villena & Metalbrain
; "Standard" version (69 bytes only)
; -----------------------------------------------------------------------------
; Parameters:
;   HL: source address (compressed data)
;   DE: destination address (decompressing)
; -----------------------------------------------------------------------------

dzx7_standard:
        ld      a, $80
dzx7s_copy_byte_loop:
        ldi                             ; copy literal byte
dzx7s_main_loop:
        call    dzx7s_next_bit
        jr      nc, dzx7s_copy_byte_loop ; next bit indicates either literal or sequence
		
; determine number of bits used for length (Elias gamma coding)
		push 	de
        ld      bc, 0
        ld      d, b
dzx7s_len_size_loop:
        inc     d
        call    dzx7s_next_bit
        jr      nc, dzx7s_len_size_loop

; determine length
dzx7s_len_value_loop:
        call    nc, dzx7s_next_bit
        rl      c
        rl      b
        jr      c, dzx7s_exit           ; check end marker
        dec     d
        jr      nz, dzx7s_len_value_loop
        inc     bc                      ; adjust length

; determine offset
        ld      e, (hl)                 ; load offset flag (1 bit) + offset value (7 bits)
        inc     hl
        defb    $cb, $33                ; opcode for undocumented instruction "SLL E" aka "SLS E"
        jr      nc, dzx7s_offset_end    ; if offset flag is set, load 4 extra bits
        ld      d, $10                  ; bit marker to load 4 bits
dzx7s_rld_next_bit:
        call    dzx7s_next_bit
        rl      d                       ; insert next bit into D
        jr      nc, dzx7s_rld_next_bit  ; repeat 4 times, until bit marker is out
        inc     d                       ; add 128 to DE
        srl	d			; retrieve fourth bit from D
dzx7s_offset_end:
        rr      e                       ; insert fourth bit into E

; copy previous sequence
        ex      (sp), hl                ; store source, restore destination
        push    hl                      ; store destination
        sbc     hl, de                  ; HL = destination - offset - 1
        pop     de                      ; DE = destination
        ldir
dzx7s_exit:
        pop     hl                      ; restore source address (compressed data)
        jr      nc, dzx7s_main_loop
dzx7s_next_bit:
        add     a, a                    ; check next bit
        ret     nz                      ; no more bits left?
        ld      a, (hl)                 ; load another group of 8 bits
		inc	hl
		rla
		ret

; -----------------------------------------------------------------------------
