; 80x24 and 80x32 text mode example, 2009 KMK/DLT

	opt ?+

dmactls = $022f

chbas	= $02f4

iccmd	= $0342
icbufa	= $0344
icbufl	= $0348
icax1	= $034a
icax2	= $034b

jciov	= $e456

bptr	= $80
srcv	= $82
dstv	= $84
temp	= $86
temp2	= $87	;2 bytes
crs_x	= $89
crs_y	= $8a
foreground_color = $8b
background_color = $8c
math	= $8d	;2 bytes
mode	= $8f
maxy	= $90
maxy1	= $91

; VBXE MEMAC B bank numbers
MEMAC_B_BANK = $00

; addresses at Atari side
SCR_AD	= $4000
BCB_AD	= $5400
XDL_AD	= $5480
FNT_AD	= $6000

; adresses at VBXE side
VBXE_SCR_AD = SCR_AD-$4000
VBXE_BCB_AD = BCB_AD-$4000
VBXE_XDL_AD = XDL_AD-$4000
VBXE_FNT_AD = FNT_AD-$4000
VBXE_FNT_OF = VBXE_FNT_AD/8

; other constants
BCB_SIZE = 21

; VBXE core registers
;
; read
;
VBXE_CR_VERSION		= $40		;core version ($10 = FX)
VBXE_CR_REVISION	= $41		;core revision
VBXE_CR_COLDETECT	= $4a		;collision detect
VBXE_CR_BLT_BUSY	= $53		;blitter status/busy
VBXE_CR_IRQ_STAT	= $54		;IRQ status
;
; write
;
VBXE_CR_VCTL		= $40		;video control
VBXE_CR_XDL_ADR0	= $41		;XDL pointer
VBXE_CR_XDL_ADR1	= $42		;
VBXE_CR_XDL_ADR2	= $43		;
VBXE_CR_CSEL		= $44		;colour select
VBXE_CR_PSEL		= $45		;colour select
VBXE_CR_CR		= $46		;component R
VBXE_CR_CG		= $47		;component G
VBXE_CR_CB		= $48		;component B
VBXE_CR_COLMASK		= $49		;collision mask
VBXE_CR_COLCLR		= $4a		;collision clear
;
VBXE_CR_BLT_ADR0	= $50		;BCB pointer
VBXE_CR_BLT_ADR1	= $51		;
VBXE_CR_BLT_ADR2	= $52		;
VBXE_CR_BLT_START	= $53		;blitter start
VBXE_CR_IRQ_CTL		= $54		;IRQ control
VBXE_CR_PRIOR_0		= $55		;priority 0
VBXE_CR_PRIOR_1		= $56		;priority 1
VBXE_CR_PRIOR_2		= $57		;priority 2
VBXE_CR_PRIOR_3		= $58		;priority 3
;
VBXE_CR_MB_CTL		= $5d		;MEMAC B control
VBXE_CR_MA_CTL		= $5e		;MEMAC A control
VBXE_CR_MA_BSEL		= $5f		;MEMAC A bank selection

	org $2000

start	jsr vbxe_detect
	bcc ?gver

?novbxe	lda #<no_vbxe_msg
	ldy #>no_vbxe_msg
	jmp putline

?gver	ldx #$01
	lda #$20
?ver	cmp VBXE_CR_VERSION+$d600,x
	bne ?novbxe
	lsr
	dex
	bpl ?ver

; VBXE reset

again	sta $d080

; display mode-selection menu

	ldx #$00
?gmnu	stx temp
	lda mainv,x
	ldy mainv+1,x
	beq ?gk
	jsr putline
	ldx temp
	inx
	inx
	bne ?gmnu

?quit	rts

?gk	jsr getkey
	cmp #'Q'
	beq ?quit
	cmp #'q'
	beq ?quit
	sec
	sbc #'1'
	bmi ?gk
	cmp #$04
	bcs ?gk

;	sta mode

	tax

	lda mode_lln_lo,x	;last line offset
	clc
	adc #<VBXE_SCR_AD
	sta bcb_scr.?lln
	lda mode_lln_hi,x
	adc #>VBXE_SCR_AD
	sta bcb_scr.?lln+1

	ldy mode_nln,x		;number of lines
	tya
	sty maxy1		;maxy + 1
	dey
	sty maxy		;maximum Y value
	sty bcb_cls.?nln
	dey
	sty bcb_scr.?nln

	asl
	asl
	asl
	tay
	dey
	sty xdl0.?nln		;only valid for mode 1 and 2

	lda mode_border,x
	sta xdl0.?border
	sta xdl1.?border

; enable MEMAC B bank 0

	ldy #VBXE_CR_MB_CTL
	lda #MEMAC_B_BANK+$80
	jsr _vbxe_write

; copy BCB blocks

	ldy #bcb_scr.?end-bcb_fnt-1
?b0	lda bcb_fnt,y
	sta BCB_AD,y
	dey
	bpl ?b0

; make XDL
; for 80x24 simply copy it over

	cpx #$02
	bcs ?ext

	ldy #xdl0.?end-xdl0-1
?b1	lda xdl0,y
	sta XDL_AD,y
	dey
	bpl ?b1
	jmp ?xdone

; for 80x32 create it

?ext	lda #$00
	sta xdl1.?fin

;	lda #$00
	sta math
	sta math+1
	lda #<XDL_AD
	sta dstv
	lda #>XDL_AD
	sta dstv+1

; copy XDL header

	ldy #$00
?xc0	lda xdl1,y
	sta (dstv),y
	iny
	cpy #xdl1.?line-xdl1
	bcc ?xc0

	jsr fixdst	;add Y to dstv

	ldx #$00

; now make XDL records for lines

?mkrec	lda #<VBXE_SCR_AD
	clc
	adc math
	sta xdl1.?scrp
	lda #>VBXE_SCR_AD
	adc math+1
	sta xdl1.?scrp+1

	lda math
	clc
	adc #160
	sta math
	bcc ?sc1
	inc math+1
?sc1

	ldy #$00
?xc1	lda xdl1.?line,y
	sta (dstv),y
	iny
	cpy #xdl1.?end-xdl1.?line
	bcc ?xc1

	jsr fixdst

	inx
	cpx maxy
	bcc ?mkrec

	lda #$80	;mark last record as end record
	sta xdl1.?fin

	cpx maxy1
	bne ?mkrec

?xdone

; copy CLS pattern

	lda #$20
	sta BCB_AD+$70
	lda #$65
	sta BCB_AD+$70+1

; copy font

	lda #<FNT_AD
	sta dstv
	lda #>FNT_AD
	sta dstv+1

	ldx #$00
	stx srcv
	stx bptr
	lda chbas
	sta bptr+1

	clc

?floop	lda bptr+1
	adc fntordr,x
	sta srcv+1

	ldy #$00
?fp0	lda (srcv),y
	sta (dstv),y
	iny
	bne ?fp0

	inc dstv+1

	inx
	cpx #$04
	bcc ?floop

; disable MEMAC B bank 0

	ldy #VBXE_CR_MB_CTL
	lda #$00
	jsr _vbxe_write

; make font for ASCII >= 128

	ldx #(0*BCB_SIZE)	;offset to bcb_font
	jsr _blit

; clear screen (must go before palette initialization)

	jsr cls

; setup palette for ASCII 0-127

	lda #$02		;fetching step
	sta temp
	lda #$00		;starting index
	tax			;starting intensity
	ldy #$80		;ending index
	jsr load_palette

; setup palette for ASCII 128-255

	ldx background_color
	lda #$80		;starting index
	ldy #$00		;ending index
	sty temp		;fetching step ($00 - one color selected by X)
	jsr load_palette

; initialize display

	lda dmactls
	pha

	lda #$00
	sta dmactls

	ldy #VBXE_CR_XDL_ADR0
?sxdla	lda vbxe_xdl_v-VBXE_CR_XDL_ADR0,y
	jsr _vbxe_write
	iny
	cpy #VBXE_CR_XDL_ADR2+1
	bcc ?sxdla

; display enable

	lda #$07
	ldy #VBXE_CR_VCTL
	jsr _vbxe_write

; initial message

	ldx #$00
?hello	lda hello,x
	beq ?ehlo
	stx temp
	jsr txt_write
	ldx temp
	inx
	bne ?hello
?ehlo

; main loop

main	jsr txt_get_char
	eor #$80
	sec
	jsr txt_put_char

	jsr getkey

	pha
	jsr txt_get_char
	eor #$80
	sec
	jsr txt_put_char
	pla

	cmp #27
	beq ?exit
	cmp #28
	beq ?up
	cmp #29
	beq ?down
	cmp #30
	beq ?left
	cmp #31
	beq ?right
	cmp #125
	beq ?cls
	cmp #127
	beq ?tab

	jsr txt_write
	jmp main

?up	lda crs_y
	beq ?maxy
	dec crs_y
	jmp main
?maxy	lda maxy
	sta crs_y
	bne main

?down	lda crs_y
	cmp maxy
	beq ?nuly
	inc crs_y
	jmp main
?nuly	lda #$00
	sta crs_y
	beq main

?left	lda crs_x
	beq ?maxx
	dec crs_x
	jmp main
?maxx	lda #79
	sta crs_x
	bne main

?right	lda crs_x
	cmp #79
	beq ?nulx
	inc crs_x
	jmp main
?nulx	lda #$00
	sta crs_x
	beq main

?cls	jsr cls
	jmp main

?tab	inc foreground_color
	inc foreground_color
	jmp main

; overlay display off

?exit	ldy #VBXE_CR_VCTL
	lda #$00
	jsr _vbxe_write

	pla
	sta dmactls
	jmp again

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

hello	.byte 'Video Board XE - Memo pad.',$9b
	.byte '[Tab] changes color, [Esc] quits to menu. Happy typing.',$9b,0

; get char, return in A

txt_get_char
	ldy crs_y
	lda t160l,y
	sta dstv
	lda txthi,y
	sta dstv+1
	lda crs_x
	asl
	tay
	ldx #$80
?fix1	stx VBXE_CR_MB_CTL+$d600
	lda (dstv),y		
	ldx #$00
?fix2	stx VBXE_CR_MB_CTL+$d600
	rts

; put char passed in A, get color from foreground_color

txt_put_char
	php
	tax
	ldy crs_y
	lda t160l,y
	sta dstv
	lda txthi,y
	sta dstv+1
	lda crs_x
	asl
	tay
	txa
?put	ldx #$80
?fix1	stx VBXE_CR_MB_CTL+$d600
	sta (dstv),y		
	plp
	bcs ?off
	iny
	lda foreground_color
	lsr
	sta (dstv),y
?off	ldx #$00
?fix2	stx VBXE_CR_MB_CTL+$d600
	rts

txt_write
	cmp #155
	beq eol
	clc
	jsr txt_put_char

	inc crs_x
	lda crs_x
	cmp #80
	bcc eol.?x
eol	lda #$00
	sta crs_x
	lda crs_y
	cmp maxy
	bcc ?i
	ldx #(2*BCB_SIZE)	;scroll up
	jmp _blit
?i	inc crs_y
?x	rts

cls	lda #$00
	sta crs_x
	sta crs_y
	lda #$94
	sta background_color
	lda #$ca
	sta foreground_color
	ldx #(1*BCB_SIZE)	;offset to bcb_cls
	jmp _blit

t160l	.byte <$0000,<$00a0,<$0140,<$01e0,<$0280,<$0320,<$03c0,<$0460
	.byte <$0500,<$05a0,<$0640,<$06e0,<$0780,<$0820,<$08c0,<$0960
	.byte <$0a00,<$0aa0,<$0b40,<$0be0,<$0c80,<$0d20,<$0dc0,<$0e60
	.byte <$0f00,<$0fa0,<$1040,<$10e0,<$1180,<$1220,<$12c0,<$1360

txthi	.byte >$4000,>$40a0,>$4140,>$41e0,>$4280,>$4320,>$43c0,>$4460
	.byte >$4500,>$45a0,>$4640,>$46e0,>$4780,>$4820,>$48c0,>$4960
	.byte >$4a00,>$4aa0,>$4b40,>$4be0,>$4c80,>$4d20,>$4dc0,>$4e60
	.byte >$4f00,>$4fa0,>$5040,>$50e0,>$5180,>$5220,>$52c0,>$5360

getkey	ldx #$10
	lda #$0c
	jsr cioexe
	lda #<kname
	sta icbufa,x
	lda #>kname
	sta icbufa+1,x
	lda #$04
	sta icax1,x
	lda #$00
	sta icax2,x
	lda #$03
	jsr cioexe
	lda #$00
	sta icbufl,x
	sta icbufl+1,x
	lda #$07
	jsr cioexe
	pha
	lda #$0c
	jsr cioexe
	pla
	rts

kname	.byte 'K:',$9b

; A - starting palette index
; TEMP - fetching step (1 for 256 colors, 2 for 128 etc.)
; Y - ending palette index + 1

load_palette
	sty temp2

	pha
	ldy #VBXE_CR_PSEL	;PSEL - palette select
	lda #$01
	jsr _vbxe_write
	pla

?l0	ldy #VBXE_CR_CSEL	;CSEL - color number
	jsr _vbxe_write
	iny
	sta temp2+1

	iny
	lda x_pal_r,x
	jsr _vbxe_write	;MB1	- R
	iny
	lda x_pal_g,x
	jsr _vbxe_write	;MB2	- G
	iny
	lda x_pal_b,x
	jsr _vbxe_write	;MB3	- B

	txa
	clc
	adc temp
	tax
	inc temp2+1
	lda temp2+1
	cmp temp2
	bne ?l0
	rts

_blit	ldy #VBXE_CR_BLT_BUSY		;$53 - wait for blitter ready
	jsr ?wbe

	ldy #VBXE_CR_BLT_ADR0
	clc
?setup	txa
	adc vbxe_bcb_v-VBXE_CR_BLT_ADR0,y
	jsr _vbxe_write
	ldx #$00
	iny
	tya
	eor #VBXE_CR_BLT_ADR2+1
	bne ?setup

;	ldy #VBXE_CR_BLT_START
	lda #$01
	jsr _vbxe_write

?wbe	lda $d600,y
	bne ?wbe
	rts

vbxe_bcb_v
	.long VBXE_BCB_AD
vbxe_xdl_v
	.long VBXE_XDL_AD

fntordr	.byte 2,0,1,3,6,4,5,7

no_vbxe_msg
	.byte 'No VBXE or improper core',$9b

vbxe_detect
	jsr ?try
	bcc ?fnd

	inc start.?ver+2
	inc _vbxe_write+2
	inc _blit.?wbe+2
	inc txt_get_char.?fix1+2
	inc txt_get_char.?fix2+2
	inc txt_put_char.?fix1+2
	inc txt_put_char.?fix2+2

?try	ldx $4000
	ldy #VBXE_CR_MB_CTL
	lda #$80
	jsr _vbxe_write
	cpx $4000
	bne ?fnd
	jsr ?clr
	inx
	stx $4000
	lda #$80
	jsr _vbxe_write
	cpx $4000
	bne ?fnd
	sec
	.byte $24
?fnd	clc
?clr	lda #$00
_vbxe_write
	sta $d600,y
	rts

fixdst	tya
	clc
	adc dstv
	sta dstv
	bcc ?sc0
	inc dstv+1
?sc0	rts

putline	ldx #$00
	sta icbufa,x
	tya
	sta icbufa+1,x
	lda #$ff
	sta icbufl,x
	lda #$09
cioexe	sta iccmd,x
	jmp jciov

bcb_fnt
; make inverse-video copy of font
	.long VBXE_FNT_AD ;src adr
	.word 512	;src step y
	.byte 1		;src step x
	.long VBXE_FNT_AD+$0400 ;dst adr
	.word 512	;dst step y
	.byte 1		;dst step x
	.word 512-1	;width
	.byte 2-1	;height
	.byte $ff	;and mask
	.byte $ff	;xor mask
	.byte $00	;collision mask
	.byte 0		;zoom
	.byte 0		;pattern
	.byte 0		;copymode

bcb_cls
; clear screen and set attributes
	.long VBXE_BCB_AD+$70	;src adr
	.word 0		;src step y
	.byte 1		;src step x
	.long VBXE_SCR_AD ;dst adr
	.word 160	;dst step y
	.byte 1		;dst step x
	.word 160-1	;width
?nln	.byte 24-1	;height
	.byte $ff	;and mask
	.byte $00	;xor mask
	.byte $00	;collision mask
	.byte 0		;zoom
	.byte $81	;pattern
	.byte 0		;blt control

bcb_scr
; scroll txt screen up
	.long VBXE_SCR_AD+160	;src adr
	.word 160	;src step y
	.byte 1		;src step x
	.long VBXE_SCR_AD ;dst adr
	.word 160	;dst step y
	.byte 1		;dst step x
	.word 160-1	;width
?nln	.byte 23-1	;height
	.byte $ff	;and mask
	.byte $00	;xor mask
	.byte $00	;collision mask
	.byte 0		;zoom
	.byte 0		;pattern
	.byte 8		;copymode + NEXT

;clear bottom line and set attributes
	.long VBXE_BCB_AD+$70		;src adr
	.word 0		;src step y
	.byte 1		;src step x
?lln	.long VBXE_SCR_AD+(23*160) ;dst adr
	.word 160	;dst step y
	.byte 1		;dst step x
	.word 160-1	;width
	.byte 1-1	;height
	.byte $ff	;and mask
	.byte $00	;xor mask
	.byte $00	;collision mask
	.byte 0		;zoom
	.byte $81	;2-byte pattern
	.byte 0		;copymode
?end

mainv	.word main_tit,main_eol,main_1,main_2,main_3,main_4,main_eol,main_q,0

main_tit
	.byte 125,29,29,29,'Choose text mode:'
main_eol
	.byte $9b
main_1	.byte '1. Standard: 80x24',$9b
main_2	.byte '2. Standard: 80x25',$9b
main_3	.byte '3. Condensed: 80x30',$9b
main_4	.byte '4. Condensed: 80x32',$9b
main_q	.byte 'Q. Exit to DOS',$9b

mode_border
	.byte 23,19,15,7
mode_nln
	.byte 24,25,30,32
mode_lln_lo
	.byte <(23*160),<(24*160),<(29*160),<(31*160)
mode_lln_hi
	.byte >(23*160),>(24*160),>(29*160),>(31*160)

; XDL for standard text modes

xdl0	.byte %01110100		;ovl off + map off + repeat + set screen address
	.byte %00001001		;character base + palette/width/priority
?border	.byte 23		;repeat 24 times
	.long VBXE_SCR_AD	;screen address
	.word 160		;line length (80 chars + 80 attributes)
	.byte >VBXE_FNT_OF	;character generator address
	.byte $11		;PF palette 0, OVL palette 1, normal width (640 pixels)
	.byte $f0		;priority: overlay over PF, under PM

	.byte %00100001		;text mode + repeat
	.byte %10000000		;end record
?nln	.byte 191		;repeat in 192 consecutive lines
?end

; XDL stuff for condensed text modes

xdl1	.byte %00110100		;overlay off + map off + repeat + scroll
	.byte %00001001		;chbase + palette/width/priority
?border	.byte 7			;repeat appropriate number of times
	.byte >VBXE_FNT_OF	;character set base
	.byte $11		;PF palette 0, OVL palette 1, normal width (640 pixels)
	.byte $f0		;priority: overlay over PF, under PM

; this below is copied n times
?line	.byte %11100001		;text mode + repeat + set screen address + scroll
?fin	.byte %00000000		; 
	.byte 6			;repeat 7 times
?scrp	.long 0			;screen pointer
	.word 160		;memory scan step (aka line length)
	.byte $00,$01		;hscroll, vscroll
?end

x_pal_b	icl 'laoo_b.s'

x_pal_g	icl 'laoo_g.s'

x_pal_r	icl 'laoo_r.s'

	org $02e0
	.word start
