; Memory to save
; Low memory area:  Addr=$7000 / Len=$12
; High memory area: Addr=$BD00 / Len=$43F

; ---------------------- MEMORY MAPPING ----------------------------------------
; Address of relocated loader code
LOADER_REL_ADDRESS		EQU	$BD00
; $8000-$8EAC loading screen bitmap
LDSCR_BITMAP			EQU	$8000
LDSCR_BITMAP_LEN		EQU	$0EAD
; $8EAD-$908F loading screen ULA Plus attributes
LDSCR_ULAPLUS_ATTR		EQU	LDSCR_BITMAP+LDSCR_BITMAP_LEN
LDSCR_ULAPLUS_ATTR_LEN	EQU	$01E3
; $9090-$91F2 loading screen normal ZX attributes
LDSCR_NORMCOL_ATTR		EQU	LDSCR_ULAPLUS_ATTR+LDSCR_ULAPLUS_ATTR_LEN
LDSCR_NORMCOL_ATTR_LEN	EQU	$0163
LDSCR_BLOCK_LEN		EQU	LDSCR_BITMAP_LEN+LDSCR_ULAPLUS_ATTR_LEN+LDSCR_NORMCOL_ATTR_LEN
; $8000-
LD_MAIN_CODE_ADDR		EQU	$8000
LD_MAIN_CODE_HIGH_LEN	EQU	$1FA2
LD_MAIN_CODE_HIGH_ADDR	EQU	LD_MAIN_CODE_ADDR
MAIN_CODE_HIGH_ADDR		EQU	$C1B1
LD_MAIN_CODE_LOW_ADDR	EQU	LD_MAIN_CODE_ADDR+LD_MAIN_CODE_HIGH_LEN
LD_MAIN_CODE_LOW_LEN	EQU	$11CD
MAIN_CODE_LOW_ADDR		EQU	$6000
LD_MAIN_CODE_BLOCK_LEN	EQU	LD_MAIN_CODE_LOW_LEN+LD_MAIN_CODE_HIGH_LEN
MAIN_CODE_START_ADDR	EQU	$6EC8
; --------------------------- LOADING ADDRESSES --------------------------------
SCR_BITMAP_ADDR		EQU	$4000	; Screen bitmap area address
SCR_BITMAP_LEN			EQU	$1800	; Screen bitmap area length
SCR_ATTR_ADDR			EQU	$5800	; Screen attributes area address
SCR_ATTR_LEN			EQU	$300		; Screen attributes area length
SCR_LINE_LEN			EQU	$20		; Screen line's length

; ---------------------- NORMAL ZX / ULA PLUS CONSTANTS ------------------------
NORMCOL_CLS_ATTR		EQU	$0E		; Normal colors empty screen attribute
ULAPLUS_CLS_ATTR		EQU	$86		; ULA Plus colors empty screen attribute

; ---------------------- ROM ROUTINES ENTRY ADDRESS ----------------------------
ROM_CHANOPEN			EQU	$1601	; ROM routine: CHANOPEN
ROM_PRINT				EQU	$203C	; ROM routine: PRINT
ROM_LD_BYTES			EQU	$0556	; ROM routine: LD_BYTES

; ---------------------- SYSTEM VARIABLES --------------------------------------
SYS_CHARS				EQU	$5C36	; 256 less than address of character set
								; (which starts with space and carries on
								; to the copyright symbol). Normally in
								; ROM, but you can set up your own in
								; RAM and make CHARS point to it.

; ---------------------- STRING SPECIAL CHARACTERS -----------------------------
CHAR_CR				EQU	$0D		; Carriage return character
CHAR_EOS				EQU	$00		; End of string character

ORG	$7000 ;28672	; BASIC REM space: 23899 ($5D5B)
; copy $7000/$12->$BD00/$440
MAIN:
	ld	h,b
	ld	l,c
	ld	bc,MAIN_END-MAIN
	add	hl,bc
	ld	d,LOADER_REL_ADDRESS >> 8	; must avoid $10-$13 bytes in loader
	ld	e,LOADER_REL_ADDRESS AND $FF	; because they are INK, PAPER, FLASH
								; and BRIGHT control character codes
								; and ruins BASIC REM lookout
								; DJNZ, LD DE,nnnn, LD (DE),A, INC DE
								; RL B, RL C, RL D, RL E are forbidden
	ld	bc,END_OF_RELOCATED_CODE-RELOCATED_CODE
	ldir
	jp	LOADER_REL_ADDRESS
MAIN_END:

ORG	LOADER_REL_ADDRESS
RELOCATED_CODE:
	ld	sp,0
	; detect ULA Plus and set its palette if it presents
RC_RA_CallSetULAPlus:
	call	SET_ULAPLUS_PALETTE
	di
	jr	nc,RC_NoULAPlus
	; ULA Plus detected
	ld	a,1
	ld	(ULAPlusDetectedFlag),a

	xor	a
	ld	(COLOR_BORDER_COMMON),a

	ld	hl,ULAPlusDetectedText
	ld	(RC_ULAPlusDetText+2),hl
	
	ld	hl,LDSCR_ULAPLUS_ATTR
	ld	(CM_LDSCR_ATTR),hl

	ld	a,ULAPLUS_CLS_ATTR
	jr	RC_ULAPlusDecectCont
RC_NoULAPlus:
	; Normal ZX detected
	xor	a
	ld	(ULAPlusDetectedFlag),a

	inc	a
	ld	(COLOR_BORDER_COMMON),a

	ld	hl,ULAPlusNotDetectedText
	ld	(RC_ULAPlusDetText+2),hl

	ld	hl,LDSCR_NORMCOL_ATTR
	ld	(CM_LDSCR_ATTR),hl

	ld	a,NORMCOL_CLS_ATTR
RC_ULAPlusDecectCont:
	ld	(COLOR_BACKGROUND_ATTR),a
	call	CLEAR_SCREEN
RC_ULAPlusDetText:
	ld	ix,$1313				; #selfmod: addr. of
							; ULA Plus detected / not detected text
	ld	d,(SCR_BITMAP_ADDR+$21) >> 8
	ld	e,(SCR_BITMAP_ADDR+$21) AND $FF
	call	WRITE_TEXT

	ld	ix,LoadingText
	ld	d,(SCR_BITMAP_ADDR + (6*SCR_LINE_LEN) + 1) >> 8
	ld	e,(SCR_BITMAP_ADDR + (6*SCR_LINE_LEN) + 1) AND $FF
	call	WRITE_TEXT

	ld	hl,XMasTreeChar		; write X-Mas tree
	ld	bc,$8FF
RC_XMasTreeLoop:
	ldi
	dec	e
	ld	a,d
	inc	a
	ld	d,a
	dec	b
	jr	nz,RC_XMasTreeLoop

	ld	ix,HiddenPartText1		; write hidden part text
	ld	d,(SCR_BITMAP_ADDR + ($85*SCR_LINE_LEN) + 10) >> 8
	ld	e,(SCR_BITMAP_ADDR + ($85*SCR_LINE_LEN) + 10) AND $FF
	call	WRITE_TEXT
	ld	ix,HiddenPartText2
	ld	d,(SCR_BITMAP_ADDR + ($86*SCR_LINE_LEN)) >> 8
	ld	e,(SCR_BITMAP_ADDR + ($86*SCR_LINE_LEN)) AND $FF
	call	WRITE_TEXT

	; Load loading screen
	ld	ix,LDSCR_BITMAP		; load memory address
	ld	d,LDSCR_BLOCK_LEN >> 8	; load length to DE
	ld	e,LDSCR_BLOCK_LEN AND $FF
	ld	hl,$0022				; colors parameter; see at the subroutine
	ld	a,$06				; common border color
	call	LD_BYTES_ROUND_SCR_CORNERS
	; ld	de,LDSCR_BLOCK_LEN
	; ld	a,$FF
	; scf
	; call	ROM_LD_BYTES
	jp	nc,LOAD_ERROR

	ld	a,(COLOR_BORDER_COMMON)
	out	($FE),a
	; Decrunch loading screen ULA Plus / Normal color palette
	ld	hl,(CM_LDSCR_ATTR)
	ld	d,SCR_ATTR_ADDR >> 8
	ld	e,SCR_ATTR_ADDR AND $FF
	call	DEC40
	; Decrunch loading screen bitmap
	ld	hl,LDSCR_BITMAP
	ld	d,SCR_BITMAP_ADDR >> 8
	ld	e,SCR_BITMAP_ADDR AND $FF
	call	DEC40

	; Load main code
	ld	ix,LD_MAIN_CODE_ADDR	; load memory address
	ld	d,LD_MAIN_CODE_BLOCK_LEN >> 8 ; load length to DE
	ld	e,LD_MAIN_CODE_BLOCK_LEN AND $FF
	ld	hl,$0022				; colors parameter; see at the subroutine
	ld	a,$06				; common border color
	call	LD_BYTES_ROUND_SCR_CORNERS
	; ld	de,LD_MAIN_CODE_BLOCK_LEN
	; ld	a,$FF
	; scf
	; call	ROM_LD_BYTES
	jp	nc,LOAD_ERROR

	ld	a,(COLOR_BORDER_COMMON)	; set border to normal color
	out	($FE),a
	ld	hl,$4000
	call	ERASE_CORNER
	ld	hl,$401F
	call	ERASE_CORNER

	; Decrunch program - high area
	ld	hl,LD_MAIN_CODE_HIGH_ADDR
	ld	d,MAIN_CODE_HIGH_ADDR >> 8
	ld	e,MAIN_CODE_HIGH_ADDR AND $FF
	call	DEC40
	; Decrunch program - low area
	ld	hl,LD_MAIN_CODE_LOW_ADDR
	ld	d,MAIN_CODE_LOW_ADDR >> 8
	ld	e,MAIN_CODE_LOW_ADDR AND $FF
	call	DEC40

	ld	a,(ULAPlusDetectedFlag)
	jp	MAIN_CODE_START_ADDR

; Variables for ULA Plus / Normal color mode
ULAPlusDetectedFlag:
	defb	$13
CM_LDSCR_ATTR:
	defw	$1313
COLOR_BORDER_COMMON:
	defb	$13
COLOR_BACKGROUND_ATTR:
	defb	$13

ULAPlusDetectedText:
	defb	"ULA Plus detected. Nice!", CHAR_EOS
ULAPlusNotDetectedText:
	defb	"ULA Plus not detected.", CHAR_CR
	defb	" Try it in an emulator", CHAR_CR
	defb	" with ULA Plus enabled.", CHAR_EOS
HiddenPartText1:
	defb	"Try to find", CHAR_EOS
HiddenPartText2:
	defb	"L Break into program hidden part", CHAR_EOS
LoadingText:
	defb	"Loading KKU ", CHAR_EOS
XMasTreeChar:
	defb	%00011000
	defb	%00111100
	defb	%00111100
	defb	%01111110
	defb	%01111110
	defb	%11111111
	defb	%11111111
	defb	%00011000
LoadErrorText:
	defb	"R Tape loading error", CHAR_CR
	defb	"Press any key to reset.", CHAR_EOS

;-------------------------------------------------------------------------------
; Set ULA plus palette
; in:  -
; out: CF=true: ULA Plus detected (else CF=false)
; mod: a,f,b,c,h,l,a'
; stack: 0
; Original code by Andrew Owen, Copyright (c) 2009

SET_ULAPLUS_PALETTE:
	ld	bc,$BF3B				; register select
	ld	a,$40				; mode group
	out	(c),a
	ld	a,1
	ld	b,$FF				; choose register port
	out	(c),a				; turn palette mode on
	
	halt
	in	a,(c)
	cp	1
	jr	z,SUP_ULAPlusDetected
	; normal Speccy detected
	xor	a
	ret
SUP_ULAPlusDetected:
	; ULA Plus detected

	ld	hl,ULAPLUS_PALETTE
	xor	a					; first register

SUP_SetRegisters:
	ld	b,$BF				; choose register port
	out	(c),a				; select register
	ex	af,af'				; save current register select
	ld	a,(hl)				; get data
	ld	b,$FF				; choose data port
	out	(c),a				; set it
	ex	af, af'				; restore current register
	inc	hl					; advance pointer
	inc	a					; increase register
	cp	$40					; are we nearly there yet?
	jr	nz,SUP_SetRegisters		; repeat until all 64 have been done
	ccf				
	ret						; return

ULAPLUS_PALETTE:
	; Bright 0 / Flash 0
	defb	$20,$40,$60,$84,$B0,$D6,$FA,$FF,$6F,$21,$2C,$10,$18,$7C,$DC,$FF
	; Bright 1 / Flash 0
	defb	$20,$40,$60,$84,$B0,$D6,$FA,$FF,$6F,$40,$60,$84,$B0,$D6,$FA,$FF
	; Bright 0 / Flash 1
	defb	$6F,$60,$2C,$10,$18,$BC,$DC,$FF,$6F,$20,$2C,$10,$18,$7C,$FC,$FF
	; Bright 1 / Flash 1
	defb	$01,$10,$3C,$40,$65,$B9,$DD,$FF,$6F,$10,$40,$65,$80,$B9,$DD,$FF

;-------------------------------------------------------------------------------
; Write text to screen. Only bitmap, no attr. Works only if text is inside
; 1/3 screen, and text's top position mod 8 = 0
; in:  IX: 0 terminated text
;      DE: screen memory address to write to
; out: -
; mod: AF,BC,HL,IX
; stack: 1

WRITE_TEXT:

WT_TextLoop:
	ld	l,(ix+0)				; C=next character
	inc	ix
	
	ld	a,CHAR_CR				; if carriage return, then start new line
	cp	l
	jr	nz,WT_NoCR
	ld	a,e
	and	(SCR_LINE_LEN-1) XOR $FF
	add	a,SCR_LINE_LEN
	ld	e,a
	jr	WT_TextLoop
WT_NoCR:
	xor	a					; since CHAR_EOS=0
	cp	l
	ret	z

	ld	h,a					; BC=character to write
	add	hl,hl				; CF=false because of CP 0 before
	add	hl,hl				; Chr$(c)*8+SYS_CHARS=chr bitmap addr.
	add	hl,hl

	ld	bc,(SYS_CHARS)			; HL=characters gfx addr. - $100
	add	hl,bc
	push	de
	ld	bc,$900
WT_CharLoop:
	ldi
	dec	e
	ld	a,d
	inc	a
	ld	d,a
	dec	b
	jr	nz,WT_CharLoop
	
	pop	de
	inc	e
	jr	WT_TextLoop


;-------------------------------------------------------------------------------
; Clear screen and set border to paper color.
; in:  A: attribute to clear
; out: -
; mod: A, BC, DE, HL
; stack: 0

CLEAR_SCREEN:
	ld	hl,SCR_ATTR_ADDR		; CLS set attributes
	ld	(hl),a
	ld	e,l
	ld	d,h
	inc	e
	ld	bc,SCR_ATTR_LEN-1
	ldir

	and	%00111000
	rra
	rra
	rra
	out	($FE),a				; set border color

	ld	hl,SCR_BITMAP_ADDR		; CLS empty bitmap area
	ld	(hl),l
	ld	e,l
	ld	d,h
	inc	e
	ld	bc,SCR_BITMAP_LEN-1
	ldir

	ret

;-------------------------------------------------------------------------------
LOAD_ERROR:
	ld	a,(COLOR_BACKGROUND_ATTR)
	call CLEAR_SCREEN

	ld	ix,LoadErrorText		; Tape loading error and press key to reset
	ld	d,(SCR_BITMAP_ADDR+$20) >> 8
	ld	e,(SCR_BITMAP_ADDR+$20) AND $FF
	call	WRITE_TEXT
	ld	bc,$FE
LE_WaitForKeyPress:
	in	a,(c)
	or	$E0
	inc	a
	jr	z,LE_WaitForKeyPress
	rst	0

;-------------------------------------------------------------------------------
; Load bytes from tape, to memory.
; - Cannot be BREAKed.
; - VERIFY removed.
; - Header loading removed.
; - Colors
; in:  IX: load memory address
;      DE: length of data to load
;      A:  common border color
;      L:  bit 0-2: 0-7 for AND n instruction when getting the border color
;          bit 3-5: 0-7 for OR n instruction when getting the border color
;      H:  bit 0-2: 0-7 for one of border colors during pulse signal
;          bit 3-5: 0-7 for one of border colors during data block
;          (other color is calculated by: AND L && 7 / OR L >> 3)
; out: CF: TRUE if load was successful
; mod: AF,BC,DE,HL,IX,AF',BC',DE',HL'
; stack: 6
LD_BYTES_ROUND_SCR_CORNERS:
	; di						; The maskable interrupt is now disabled
							; (Mostly not needed, because interrupts are
							; already disabled until load routine is
							; called.)
	out	($FE),a				; The border colour is set to parameter in
							; A register
	xor	a					; This resets the zero flag. Also resets
	dec	a					; carry flag, but CF is not a used input
	ex	af,af'				; parameter this loader, so no prob.
							; A=$FF for data loading
	ld	a,l					; Set self modified code, AND n for keeping
	and	$07					; only the color.
	ld	(LD_SAMPLE_COLOR_AND_A+1),a
	ld	a,l					; Also self modified code, OR n for "mic off'
	and	$38					; and setting border color.
	rra
	rra
	rra
	or	$08
	ld	(LD_SAMPLE_COLOR_OR_A+1),a
	ld	a,h					; Another self modified code, OR n for
	and	$38					; setting border color during program/data
	rra						; block.
	rra
	rra
	ld	(LD_DATA_BORDER_COLOR_A+1),a
	ld	a,h					; Set H to pulse border color.
	and	$07
	ld	h,a
	in	a,($FE)				; Make an initial read of port 254
	and	$40					; but keep only the EAR bit
	
	or	h					; Signal pulse border color.
	ld	c,a					; Store the value in the C register
							; ($22 for 'off' and $02 for 'on' - the
							; present EAR state)
	exx						; Draw rounded corners
	ld	de,LD_BYTES_LEFT_ROUND
	ld	hl,$4000
	call	LD_BYTES_DRAW_CORNER
	ld	de,LD_BYTES_RIGHT_ROUND
	ld	hl,$401F
	call	LD_BYTES_DRAW_CORNER

	ld	a,($5800)				; Save corner's paper and bright/flash
	and	$F8
	ld	(LD_SAMPLE_LEFTTOP_OR_A+1),a
	ld	a,($581F)
	and	$F8
	ld	(LD_SAMPLE_RIGHTTOP_OR_A+1),a
	ld	a,($5AE0)
	and	$F8
	ld	(LD_SAMPLE_LEFTBOTTOM_OR_A+1),a
	ld	a,($5AFF)
	and	$F8
	ld	(LD_SAMPLE_RIGHTBOTTOM_OR_A+1),a
	exx

; The first stage of reading a tape involves showing that a pulsing signal
; actually exists. (i.e. 'on/off' or 'off/on' edges.)

LD_START:
	call	LD_EDGE_1				; Return with the carry flag reset if
	jr	nc,LD_START			; 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
LD_WAIT:						; be almost one second in duration.
	djnz	LD_WAIT
	dec	hl
	ld	a,h
	or	l
	jr	nz,LD_WAIT
	call	LD_EDGE_2				; continue only if two edges are found
	jr   nc,LD_START			; within the allowed time period.

; Now accept only a 'leader signal'.

LD_LEADER:
	ld	b,$A1				; The timing constant
	call LD_EDGE_2				; Continue only if two edges are found
	jr	nc,LD_START			; within the allowed time period
	ld	a,$C6				; However the edges must have been found
	cp	b					; within about 3000T states of each
	jr	nc,LD_START			; other
	inc	h					; Count the pair of edges in the H
	jr	nz,LD_LEADER			; register until 256 pairs have been found

; After the leader come the 'off' and 'on' parts of the sync pulse.

LD_SYNC:
	ld	b,$CB				; The timing constant
	call	LD_EDGE_1				; Every edge is considered until two edges
	jr	nc,LD_START			; are found close together - these will be
	ld	a,b					; the start and finishing edges of the
	cp	$D4					; 'off' sync pulse
	jr	nc,LD_SYNC
	call	LD_EDGE_1				; The finishing edge of the 'on' pulse
	ret	nc					; must exist
							; (Return carry flag reset)

; The bytes of the program/data block can now be LOADed.
; But the first byte is the flag byte.

	ld	a,c					; The border colours from now on will be
	and	$07					; BLUE & YELLOW or set by the parameters
LD_DATA_BORDER_COLOR_A:
	or	$13					; #selfmod: border color during loading the
	ld	c,a					; program/data block
	; ld	h,$00				; Initialize the 'parity matching' byte
							; to zero - not needed, H=0 after LD_LEADER
	ld	b,$B5				; Set the timing constant for the flag
							; byte.
	jr	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.

LD_LOOP:
	ex	af,af'				; Fetch the flags
	jr	nz,LD_FLAG			; Jump forward only when handling the
							; first byte
	ld	(ix+00),l				; Make the actual LOAD when required
	jr	LD_NEXT				; Jump forward to LOAD the next byte
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	LD_DEC				; its decrease after the jump

; A new byte can now be collected from the tape.

LD_NEXT:
	inc	ix					; Increase the 'destination'
LD_DEC:
	dec	de					; Decrease the 'counter'
	ex	af,af'				; Save the flags
	ld	b,$B7				; Set the timing constant
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.

LD_8_BITS:
	call	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					; 2400T 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,$B5				; Set the timing constant for the next bit
	jp	nc,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 further pass if the DE register
	or	e					; pair does not hold zero
	jr	nz,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'.

LD_EDGE_2:
	call	LD_EDGE_1				; In effect call 'LD_EDGE_1' twice;
	ret	nc					; returning in between in there is an
							; error.
LD_EDGE_1:
	ld	a,$16				; Wait 358T states before entering the
LD_DELAY:						; sampling loop
	dec	a
	jr	nz,LD_DELAY

; 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.

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. EAR
	xor	c					; Now test the byte against the 'last
	and	$40					; edge-type'
	nop
	nop
	jr	z,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
LD_SAMPLE_COLOR_AND_A:
	and	$13					; Keep only the border colour
							; #selfmod: is set by parameter in L reg.
LD_SAMPLE_COLOR_OR_A:
	or	$13					; Signal 'MIC off'
	push	af
	exx
	and	$07
	ld	c,a
LD_SAMPLE_LEFTTOP_OR_A:
	or	$13
	ld	($5800),a				; Set the INK colour of the four corners
	ld	a,c					; of the screen.
LD_SAMPLE_RIGHTTOP_OR_A:
	or	$13
	ld	($581F),a
	pop	af
	out	($FE),a				; Change the border colour (RED/CYAN or
							; BLUE/YELLOW or anything by parameters)
	ld	a,c
LD_SAMPLE_LEFTBOTTOM_OR_A:
	or	$13
	ld	($5AE0),a
	ld	a,c
LD_SAMPLE_RIGHTBOTTOM_OR_A:
	or	$13
	ld	($5AFF),a
	exx

	scf						; Signal the successful search before
	ret						; returning


; Note: The 'LD_EDGE_1' subroutine takes 464T states, plus an additional 59T
; 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, 1100T
; states (464 + 10 * 59 overhead).
; This will prove successful for the sync 'off' pulse that comes after the long
; 'leader pulses'.

;-------------------------------------------------------------------------------
; Draw two rounded (CRT TV like) corners of the screen on one side.
; in:  DE: corner mask address
;      HL: screen char's top byte address (Y pos must be mod 8=0)
; out: -
; mod: AF,BC,DE,HL
; stack: 0
LD_BYTES_DRAW_CORNER:
	ld	b,8
LD_BytesTopRoundLoop:
	ld	a,(de)
	or	(hl)
	ld	(hl),a
	inc	h
	inc	de
	dec	b
	jr	nz,LD_BytesTopRoundLoop

	ld	bc,$8E0
	add	hl,bc
LD_BytesBottomRoundLoop:
	dec	de
	ld	a,(de)
	or	(hl)
	ld	(hl),a
	inc	h
	dec	b
	jr	nz,LD_BytesBottomRoundLoop
	ret

;-------------------------------------------------------------------------------
; Draw two rounded (CRT TV like) corners of the screen on one side.
; in:  DE: screen char's top byte address (Y pos must be mod 8=0)
; out: -
; mod: AF,BC,DE,HL
; stack: 2
ERASE_CORNER:
	xor	a
	ld	b,8
	call	EC_RoundLoop

	ld	bc,$8E0
	add	hl,bc
EC_RoundLoop:
	ld	(hl),a
	inc	h
	dec	b
	jr	nz,EC_RoundLoop
	ret

; rounded corner left side
LD_BYTES_LEFT_ROUND:
defb $FF, $FC, $F0, $E0, $C0, $C0, $80, $80
; rounded corner right side
LD_BYTES_RIGHT_ROUND:
defb $FF, $3F, $0F, $07, $03, $03, $01, $01


;-------------------------------------------------------------------------------
;Z80 depacker for megalz V4 packed files   (C) fyrex^mhm

; DESCRIPTION:
; Depacker is fully relocatable, not self-modifying, it's length is 110 bytes
; starting from DEC40.
; Register usage: AF,AF',BC,DE,HL. Must be CALL'ed, return is done by RET.
; Provide extra stack location for store 2 bytes (1 word). Depacker does not
; disable or enable interrupts, as well as could be interrupted at any time
; (no f*cking wicked stack usage :).
;
; USAGE:
; - put depacker anywhere you want,
; - put starting address of packed block in HL,
; - put location where you want data to be depacked in DE,
;   (much like LDIR command, but without BC)
; - make CALL to depacker (DEC40).
; - enjoy! ;)
;
; PRECAUTIONS:
;
; Be very careful if packed and depacked blocks coincide somewhere in memory.
; Here are some advices:
; 1. put packed block to the highest addresses possible.
;     Best if last byte of packed block has address #FFFF.
; 2. Leave some gap between ends of packed and depacked block.
;     For example, last byte of depacked block at #FF00,
;     last byte of packed block at #FFFF.
; 3. Place nonpackable data to the end of block.
; 4. Always check whether depacking occurs OK and neither corrupts depacked data
;     nor hangs computer.

DEC40:
	ld	a,$80
	ex	af,af'
DEC40_MS:
	ldi
DEC40_M0:
	ld	bc,$2FF
DEC40_M1:
	ex	af,af'
DEC40_M1X:
	add	a,a
	jr	nz,DEC40_M2
	ld	a,(hl)
	inc	hl
	rla
DEC40_M2:
	rl	c
	jr	nc,DEC40_M1X
	ex	af,af'
	djnz	DEC40_X2
	ld	a,2
	sra	c
	jr	c,DEC40_N1
	inc	a
	inc	c
	jr	z,DEC40_N2
	ld	bc,$33F
	jr	DEC40_M1
DEC40_X2:
	djnz	DEC40_x3
	srl	c
	jr	c,DEC40_MS
	inc	b
	jr	DEC40_M1
DEC40_X6:
	add	a,c
DEC40_N2:
	ld	bc,$4FF
	jr	DEC40_M1
DEC40_N1:
	inc	c
	jr	nz,DEC40_M4
	ex	af,af'
	inc	b
DEC40_N5:
	rr	c
	ret	c
	rl	b
	add	a,a
	jr	nz,DEC40_N6
	ld	a,(hl)
	inc	hl
	rla
DEC40_N6:
	jr	nc,DEC40_N5
	ex	af,af'
	add	a,b
	ld	b,6
	jr	DEC40_M1
DEC40_X3:
	djnz	DEC40_X4
	ld	a,1
	jr	DEC40_M3
DEC40_X4:
	djnz	DEC40_X5
	inc	c
	jr	nz,DEC40_M4
	ld	bc,$51F
	jr	DEC40_M1
DEC40_X5:
	djnz	DEC40_X6
	ld	b,c
DEC40_M4:
	ld	c,(hl)
	inc	hl
DEC40_M3:
	dec	b
	push	hl
	ld	l,c
	ld	h,b
	add	hl,de
	ld	c,a
	ld	b,0
	ldir
	pop	hl
	jr	DEC40_M0
END_DEC40:


END_OF_RELOCATED_CODE:

; ORG LDSCR_BITMAP
; INCBIN 'loading_screen_8x8_bitmap.mlz.bin'
; INCBIN 'loading_screen_8x8_ulaplus_attr.mlz.bin'
; INCBIN 'loading_screen_8x8_norm_zx_attr.mlz.bin'