	.bank
	*=$3a00
;
; Quadrillion loader
;
; Test for presence of VBXE, 
; then setup banking and relocate program before game runs
;
rtclock = $12
ztemp1	= $80	; Pointer for RAM clear
zsource	= $82	; Pointer for source, data copy
zdest	= $84	; Pointer for dest, data copy
vbxe_ptr	= $e8	; Points to VBXE $D600 or $D700
test_location	= $6800	; location of 2 bytes to test VBXE presence
a_bitmap1 = $4000	; Bitmap for logo outline
a_bitmap2 = $4400	; Bitmap for logo pattern select
v_bitmap = $5000	; Logo Bitmap = $10000 in VRAM
v_scroller = $70a8	; Scroller text = $12000 in VRAM
v_instructions = $7800	; Instruction text = $12800 in VRAM
v_chset	= $9000		; = Character Set = $14000 in VRAM
;
ztemp2	= $f2
ztemp3	= $f4
mask	= $f6
fill_index = $f7
zcount	= $f8
attrib	= $f9
sdmctl	= $22f
sdslst	= $230
linecount = $400
savey	= $401
inbyte	= $402
vvbi	= $222
coldst	= $244
portb	= $d301	; PIA PortB
dmactl	= $d400
wsync	= $d40a

v_video_control	= $40 ; Video Control
v_xdl_adr0	= $41 ; XDL Address
v_csel		= $44 ; Colour select
v_psel		= $45 ; Palette select
v_cr		= $46 ; Red component
v_memac_control	= $5e ; MEMAC control
v_memac_bank_sel = $5f ; MEMAC bank selection

;
;
loader_init
	cld
	lda #0
	sta sdmctl	; Turn off Antic screen
	sta vbxe_ptr
	lda #$d5
	sta vbxe_ptr+1
	sta $d09e	; Reset VBXE
	lda #$ff
	sta coldst	; Set Coldst flag
	sta portb	; Set default Atari banking, BASIC disabled
	ldx #<dlist_start
	ldy #>dlist_start
	stx sdslst
	sty sdslst+1
;
	lda #$55
	sta test_location
	lda #$2c
	sta test_location+1	; Test values, should disappear if VBXE is installed
try_next_vbxe
	inc loader_vbxe
	inc vbxe_ptr+1
	lda #$d8
	cmp vbxe_ptr+1
	bne try_next2
	jmp vbxe_notfound
try_next2
	ldy #v_memac_control
	lda #$5f	
	sta (vbxe_ptr),y	; Initially use bank from $5000-$BFFF
; Enable banking before subsequent loading of full program
	ldy #v_memac_bank_sel
	lda #$80
	sta (vbxe_ptr),y
	lda test_location
	cmp #$55
	beq try_next_vbxe	; Test value still there, try D7 install
	lda test_location+1
	cmp #$2c
	beq try_next_vbxe
;
; fall through here when VBXE found
;
	ldy #v_memac_bank_sel
	lda #$90
	sta (vbxe_ptr),y	; Map VBXE RAM $10000 @ $5000
	ldx #0
; Copy character set, chars 0-7f = italic, 80-ff = normal
copy_chset
	lda $e000,x
	sta v_chset,x
	sta v_chset+$400,x
	lda $e100,x
	sta v_chset+$100,x
	sta v_chset+$500,x
	lda $e200,x
	sta v_chset+$200,x
	sta v_chset+$600,x
	lda $e300,x
	sta v_chset+$300,x
	sta v_chset+$700,x
	txa
	and #7
	cmp #4
	bcc copy_chs1
	asl v_chset+$400,x
	asl v_chset+$500,x
	asl v_chset+$600,x
	asl v_chset+$700,x
copy_chs1
	inx
	bne copy_chset
; 
; Copy instructions into VRAM, with colour attribute
;
;	jmp copy_ins_end	; *** testing
	lda #<v_instructions
	ldx #>v_instructions		; Destination address in VRAM
	sta ztemp2
	stx ztemp2+1
	lda #<instruction_start
	ldx #>instruction_start
	sta ztemp1
	stx ztemp1+1
	lda #10
	sta zcount	; line counter
	ldy #0
copy_ins
	lda (ztemp1),y
	sta attrib
	inc ztemp1
	bne copy_ins1
	inc ztemp1+1
copy_ins1
	ldx #58
copy_ins2
	lda (ztemp1),y	; Text byte
	sta (ztemp2),y	; Into VRAM
	inc ztemp1
	bne copy_ins3
	inc ztemp1+1	; Source +1
copy_ins3
	inc ztemp2
	bne copy_ins4
	inc ztemp2+1	; Dest +1
copy_ins4
	lda attrib
	sta (ztemp2),y	; Set attribute byte
	inc ztemp2
	bne copy_ins5
	inc ztemp2+1
copy_ins5
	dex
	bne copy_ins2
	ldx #44		; 22 *2 for remainder of 80 characters
; Fill remaining characters with spaces + zeroed attribute
	tya
copy_ins_zfill
	sta (ztemp2),y
	iny
	dex
	bne copy_ins_zfill
	ldy #0
	lda ztemp2
	clc
	adc #44
	sta ztemp2
	lda ztemp2+1
	adc #0
	sta ztemp2+1
	dec zcount	; Do this for 10 lines
	bne copy_ins

copy_ins_end
;
; Copy scroller into VRAM
;
	ldy #0
	tya
zero_scroller
	sta v_scroller-$100,y
	sta scrolltext_end,y
	sta scrolltext_end+$100,y
	iny
	bne zero_scroller	; Zero end of scroller data
	ldx #0
copy_scroller
	lda scrolltext_start,y
	sta v_scroller,x
	lda #$78
	sta v_scroller+1,x
	sta v_scroller+$101,x
	sta v_scroller+$201,x
	sta v_scroller+$301,x
	sta v_scroller+$401,x
	sta v_scroller+$501,x
	lda scrolltext_start+$80,y
	sta v_scroller+$100,x
	lda scrolltext_start+$100,y
	sta v_scroller+$200,x
	lda scrolltext_start+$180,y
	sta v_scroller+$300,x
	lda scrolltext_start+$200,y
	sta v_scroller+$400,x
	lda scrolltext_start+$280,y
	sta v_scroller+$500,x
	iny
	inx
	inx
	bne copy_scroller	; Copy $280 bytes worth of scroller data
	ldy #0
	lda #>v_bitmap
	sty ztemp1
	sty ztemp2
	sty ztemp3
	sta ztemp1+1	; VBXE bitmap
	lda #>a_bitmap1
	sta ztemp2+1	; Outline bitmap source
	lda #>a_bitmap2 
	sta ztemp3+1	; Filled bitmap source
	lda #22
	sta linecount
do_outline
	sty savey
	ldy #0
	lda (ztemp2),y	; Get outline byte
	ldy savey
	sta inbyte
	inc ztemp2
	bne do_o0
	inc ztemp2+1
do_o0
	lda #$80
	sta mask
do_o1
	ldx #0
	lda inbyte
	and mask
	beq no_pixel1
	ldx #1		; Colour 1 = outline
;	inx
no_pixel1
	txa
	sta (ztemp1),y	; Store to bitmap
	iny
	lsr mask
	bcc do_o1	; Do 8 pixels
	tya
	bne do_outline	; Do entire scanline
	inc ztemp1+1	; Dest = Dest + 256
	ldy #0
	dec linecount
	bne do_outline	; Do next scanline
;
	lda #>v_bitmap
	sta ztemp1+1	; Reset VBXE bitmap pointer
	lda #22
	sta linecount
	ldy #0
	sty fill_index
do_fill0
	ldx linecount
	lda initial_index_table,x
	sta fill_index
do_fill
	sty savey
	ldy #0
	lda (ztemp3),y	; Get fill byte
	ldy savey
	sta inbyte
	inc ztemp3
	bne do_f0
	inc ztemp3+1
do_f0
	lda #$80
	sta mask
do_fill2
	lda inbyte
	and mask
	beq no_pixel2
	ldx fill_index
	lda fill_data,x
	sta (ztemp1),y	; Fill data to VBXE bitmap
no_pixel2
	lda fill_index
	clc
	adc #1
	and #$f
	sta fill_index
	iny
	lsr mask
	bcc do_fill2
	tya
	bne do_fill
	inc ztemp1+1
	dec linecount
	beq fill_done
	jmp do_fill0
fill_done
	ldy #v_memac_control
	lda #$4f
	sta (vbxe_ptr),y	; Reset VBXE window to $4000, 32K
	iny
	lda #$80
	sta (vbxe_ptr),y	; Map $0000 to $4000
	ldy #0
	lda #$40
	sty ztemp1
	sta ztemp1+1
	ldx #$80	; Clear $8000 bytes RAM $4000-$BFFF
	tya
clear_ram
	sta (ztemp1),y
	iny
	sta (ztemp1),y
	iny
	sta (ztemp1),y
	iny
	sta (ztemp1),y
	iny
	bne clear_ram
	inc ztemp1+1
	dex
	bne clear_ram
;
; Setup initial Palette 1 entries
;
	ldy #v_psel
	lda #1
	sta (vbxe_ptr),y	; Select Palette 1
	dey
	lda #0
	sta (vbxe_ptr),y	; Select Colour 0
	ldy #v_cr
	sta (vbxe_ptr),y
	iny
	sta (vbxe_ptr),y
	iny
	sta (vbxe_ptr),y	; Set Colour 0 =0,0,0
	lda #$e8		; Prime colour 1=e8,e8,e8 Bright white
	ldx #20
palette_loop
	ldy #v_cr
	sta (vbxe_ptr),y
	iny
	sta (vbxe_ptr),y
	iny
	sta (vbxe_ptr),y	; Colour 2-22 = black for now
	lda #0
	dex
	bne palette_loop
;
; Copy loader XDL
	ldy #xdl_size
copy_loader_xdl
	lda loader_xdl,y
	sta $7f00,y
	dey
	bpl copy_loader_xdl
	ldy #v_xdl_adr0
	lda #0
	sta (vbxe_ptr),y
	iny
	iny
	sta (vbxe_ptr),y
	dey
	lda #$3f
	sta (vbxe_ptr),y	; XDL = $03f00
	ldy #v_video_control
	lda #3
	sta (vbxe_ptr),y	; Video Control, ext colour, XDL enabled
	ldy #v_memac_control
	lda #$Bc		; Remainder of load, VBXE RAM @ $B000
	sta (vbxe_ptr),y
	lda #$83
	ldy #v_memac_bank_sel	; 
	sta (vbxe_ptr),y
	ldx #<vbi_loader
	ldy #>vbi_loader
	sta wsync
	stx vvbi
	sty vvbi+1
	rts		; Continue with load
vbi_loader
	lda $Bf05
	beq vbi_finish
	lda rtclock+2
	lsr a
	bcc vbi_finish
	dec $Bf05
vbi_finish
	jmp $e45f
vbxe_notfound
	lda #0
	sta coldst
	sta dlist_vbxe_location
	sta dlist_finish
	sta dlist_finish+1
	sta dlist_finish+2
	lda #$22
	sta sdmctl	; Enable Antic screen for message
halt
	jmp halt
;
; Game runs from here.  Setup banking and move program.
;
loader_run
	ldx #$5f
	ldy #$e4
	sta $d40a
	stx vvbi
	sty vvbi+1	; Reset VVBI

loader_run2
;	lda $d010
;	bne loader_run2	; *** Testing
	lda #$ff
	sta portb
	lda #$6f
	ldy #v_memac_control
	sta (vbxe_ptr),y	; Setup banking at $6000-$BFFF
	lda #$80
	ldy #v_memac_bank_sel
	sta (vbxe_ptr),y	; VBXE RAM from $000000
;
	ldy #0
	sty sdmctl
	sty dmactl
	sty zsource
	sty zdest
	lda #$40
	sta zsource+1		; $4000 souce
	lda #$90		; $9000 destination
	sta zdest+1
	ldx #32			; 32 pages = 8K
copy_program
	lda (zsource),y
	sta (zdest),y
	iny
	lda (zsource),y
	sta (zdest),y
	iny
	lda (zsource),y
	sta (zdest),y
	iny
	lda (zsource),y
	sta (zdest),y
	iny
	bne copy_program
	inc zsource+1
	inc zdest+1
	dex
	bne copy_program

	jmp run_game


;
;
;
dlist_start
	.byte $70,$70,$70,$70
	.byte $47
	.word loader_screen
	.byte $70
dlist_vbxe_location
	.byte $6
	.byte $20
dlist_finish
	.byte $41
	.word dlist_start
	.byte $42
	.word loader_notfound
	.byte 2
	.byte $41
	.word dlist_start
;
loader_xdl
	.byte $20,0,3	; 4 blank
	.byte $20,0	; Repeat
	.byte 107	; 108 = about centre for logo
	.byte $62	; Overlay, Repeat, overlay adr
	.byte $88	; XDL end, map parms
	.byte 21	; repeat 22
	.byte 0,$00,1	; Overlay @ $10000
	.word 256	; Step 256
	.byte $10,255	; palette 1, priority
loader_xdl2
	.byte $20,0,37	; 38 Blank
; Text for top half of screen
	.byte $f1,$09	; Text mode, repeat
	.byte 47	; 48 scanlines repeated
	.byte 0,$28,1	; $12800 in VRAM
	.byte 160,0	; step 160
	.byte 0,0	; H/VScrol = 0
	.byte 40	; CHSET
	.byte 1,$ff	; Palettes=0,0 width normal, Priority to Overlay
;
	.byte $24,0,79	; 80 Blank
; Text for bottom half of screen
	.byte $f1,$89	; Text mode, repeat, end XDL
	.byte 31	; 32 scanlines repeated
	.byte $c0,$2b,1	; $12bc0 in VRAM is bottom half of text
	.byte 160,0	; step 160
	.byte 0,0	; H/VScrol = 0
	.byte 40	; CHSET
	.byte 1,$ff	; Palettes=0,0 width normal, Priority to Overlay
xdl_size	= *-loader_xdl



loader_screen
	.sbyte "    quadrillion     "
	.sbyte "  VBXE:  D"
loader_vbxe
	.sbyte "5         "
loader_notfound
	.sbyte "This game only works with a VBXE upgrade"
	.sbyte " or Altirra emulator with VBXE enabled. "
	.dc 4 0
fill_data
	.byte 3,4,5,6,7,8,9,10,10,9,8,7,6,5,4,3
initial_index_table
	.byte 0
	.byte 5,3,1,15,13,11,9,7,5,3,1
	.byte 0,2,4,6,8,10,12,14,0,2,4,6
;
; Bitmaps for logo
;
	*=$4000
	.byte 0
	.incbin quadg1.dat
;
	*=$4400
	.byte 0
	.incbin quadg2.dat
;
; Scroller text
;
	*=$4800
scrolltext_start
	.sbyte "Atari version of the Commodore Plus4 game.  "
	.sbyte +$80,"Conversion and VBXE enhancements by Gary "
	.sbyte +$80,34,"Rybags",34," Ryan, 2010.   "
	.sbyte +$80,"Original version by Csabo.   Music by Sal "
	.sbyte +$80,34
	.sbyte +$80,"kjmann"
	.sbyte +$80,34
	.sbyte +$80," Esquivel.    Hints:  To score well, use bank shots and "
	.sbyte +$80,"corner bounces to good effect.  Block score decreases with " 
	.sbyte +$80,"time during each level.  Extra life awarded for finishing a level, but not if you skip "
	.sbyte +$80,"it.    For best experience use on VBXE-equipped Atari with Core Revision 1.24 or later, "
	.sbyte +$80,"or the Altirra Emulator for Atari 1.8 or later.   "
	.sbyte "This program is Freeware and may not be sold in any form.   "
scrolltext_end
;
; Instruction text
;
instruction_start
	.byte $09
	.sbyte "   Move the ball left/right with joystick or keys , and . "
	.byte $0a
	.sbyte "      Press fire button or SHIFT key to start level       "
	.byte $0b
	.sbyte "      or resume from pause.  SPACE pauses the game.       "
	.byte $0b
	.sbyte "  TAB skips the current level if <8 or previously solved. "
	.byte $0a
	.sbyte "   ESC aborts & restarts the current level (costs a life) "
	.byte $09
	.sbyte "          SHIFT+ESC aborts the current game.              "
;
	.byte $1b
	.sbyte "           Clear each level of coloured blocks            "
	.byte $5a
	.sbyte "           Star blocks change which colours you can clear "
	.byte $7a
	.sbyte "           Disk blocks are movable                        "
	.byte $37
	.sbyte "                  Avoid the skulls, instant death         "

;
; Run the game.  This part sits at $600 so not to get wiped when the banking changes
;

	*=$6c0
run_game
	lda #$22
	sta sdmctl
	lda #$1f
	ldy #v_memac_control
	sta (vbxe_ptr),y	; Setup banking for $1000-$8FFF 32K window
	lda #$80
	ldy #v_memac_bank_sel
	sta (vbxe_ptr),y
	jmp $4000		; Run game
	
	.bank

;
	*=$2e0
	.word loader_run,loader_init