view menu.s68 @ 989:d70000fdff0b

Implemented IR and undefined bits of info word for address error exception frames
author Michael Pavone <pavone@retrodev.com>
date Wed, 27 Apr 2016 21:39:17 -0700
parents fbd783ccbadb
children 4360cb5960c8
line wrap: on
line source
	dc.l $0, start
	dc.l empty_handler
	dc.l empty_handler
	;$10
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	;$20
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	;$30
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	;$40
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	;$50
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	;$60
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	;$70
	dc.l int_4
	dc.l empty_handler
	dc.l int_6
	dc.l empty_handler
	;$80
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	;$90
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	;$A0
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	;$B0
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	;$C0
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	;$D0
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	;$E0
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	;$F0
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	dc.l empty_handler
	dc.b "SEGA GENESIS    "
	dc.b "(c) 2015.JULY   "
	dc.b "Menu            "
	dc.b "                "
	dc.b "                "
	dc.b "Menu            "
	dc.b "                "
	dc.b "                "
	dc.b "MP BlstMenu-00", 0, 0
	dc.b "                "
	dc.l $0, rom_end-1, $FF0000, $FFFFFF
	dc.b "                "
	dc.b "                "
	dc.b "                "
	dc.b "                "
	dc.b "JUE "

;register addresses
VDP_DATA  equ $C00000
VDP_CTRL  equ $C00004
VDP_HV    equ $C00008
Z80_RAM   equ $A00000
IO_AREA   equ $A10000
PAD1_DATA equ (IO_AREA + 3)
PAD2_DATA equ (IO_AREA + 5)
EXT_DATA  equ (IO_AREA + 7)
PAD1_CTRL equ (IO_AREA + 9)
PAD2_CTRL equ (IO_AREA + 11)
EXT_CTRL  equ (IO_AREA + 13)

MODE_1   equ 0
MODE_2   equ 1
SCROLL_A equ 2
WINDOW   equ 3
SCROLL_B equ 4
SAT      equ 5
BG_COLOR equ 7
HINT     equ $A
MODE_3   equ $B
MODE_4   equ $C
HSCROLL  equ $D
AUTOINC  equ $F
SCROLL   EQU $10
WINDOW_H equ $11
WINDOW_V equ $12
DMALEN_L equ $13
DMALEN_H equ $14
DMASRC_L equ $15
DMASRC_M equ $16
DMASRC_H equ $17

VDP_VRAM_WRITE equ $40000000
VDP_CRAM_WRITE equ $C0000000
VDP_VSRAM_WRITE equ $40000010
VDP_DMA_FLAG equ $80

vdpregset macro
	move.w #(((\1) << 8) | $8000 | (\2)), (a1)
	endm

vdpreg macro
	dc.w (((\1) << 8) | $8000 | (\2))
	endm

;Writes a normal VDP command to the control port
;\1 - VDP address
;\2 - Access type
vdpaccess macro
	ifeq NARG-2
	move.l #((\2) | (\1) << 16 & $3FFF0000 | (\1) >> 14 & 3), (a1)
	else
	move.l #((\2) | (\1) << 16 & $3FFF0000 | (\1) >> 14 & 3), \3
	endif
	endm

;Writes a DMA command to the control port
;\1 - Destination address
;\2 - Destination type
startdma macro
	move.l #(\2 | VDP_DMA_FLAG | (\1 << 16) & $3FFF0000 | (\1 >> 14) & 3), (a1)
	endm

DMA_SRC_68K  equ 0
DMA_SRC_VRAM equ $C0
DMA_SRC_FILL equ $80

dmasrc macro
	move.l #($95009600 + (\1) << 15 & $FF0000 + (\1) >> 9 & $FF), (a1)
	move.w #($9700 + (\1) >> 17 & $7F | (\2)), (a1)
	endm

dir_buffer equ $100000
menu_port  equ $180000

MAX_DISPLAY equ 24

	rsset $FFFF8000
x_pos          rs.w 1
base_cmd       rs.l 1
sprite_list    rs.l 160
page_index     rs.l MAX_DISPLAY+1
page_stack     rs.l 1
page_pointers  rs.l 1024
mouse_sprite   rs.l 1
menu_functions rs.l 1
mouse_x        rs.w 1
selection_top  rs.w 1
selection_bot  rs.w 1
selection_mask rs.w 1
num_sprites    rs.b 1
last_pad1      rs.b 1
last_pad2      rs.b 1
selected       rs.b 1
more_pages     rs.b 1
mouse_buf      rs.b 3
mouse_shown    rs.b 1
last_mbuttons  rs.b 1
num_menu       rs.b 1
num_slots      rs.b 1
port_off       rs.b 1


int_6:
	dmasrc sprite_list, DMA_SRC_68K
	;set DMA length
	move.l #$94009300, d0
	moveq #0, d1
	move.b num_sprites.w, d1
	add.w d1, d1
	add.w d1, d1
	move.b d1, d0
	swap d0
	lsr.w #8, d1
	move.b d1, d0
	move.l d0, (a1)
	startdma $C000, VDP_VRAM_WRITE

	;read gamepad/mouse in port 1
	lea PAD1_DATA, a2

	bsr io_read

	cmp.b #3, d2
	beq .mouse

	move.b last_pad1.w, d1
	eor.b d0, d1
	and.b d0, d1
	move.b d0, last_pad1.w

	bsr handle_pad_buttons

	bra pad2
.mouse
	bsr handle_mouse

pad2:
	;read gamepad/mouse in port 2
	lea PAD2_DATA, a2

	bsr io_read

	cmp.b #3, d2
	beq .mouse

	move.b last_pad2.w, d1
	eor.b d0, d1
	and.b d0, d1
	move.b d0, last_pad2.w

	bsr handle_pad_buttons
	rte
.mouse
	bsr handle_mouse
	rte


;d0 = SACBRLUD
;d1 = newly pressed buttons
handle_pad_buttons:
	tst.b num_menu.w
	bne handle_buttons_menu
	tst.b num_slots.w
	bne handle_buttons_save
	moveq #16, d2


	btst #3, d1
	bne right
	btst #2, d1
	bne left
buttons_no_leftright
	btst #1, d1
	bne down
	btst #0, d1
	bne up
	btst #7, d1
	bne select_entry
	btst #5, d1
	bne select_entry
handle_done:
	rts
handle_buttons_menu
	moveq #48, d2
	bra buttons_no_leftright
handle_buttons_save
	moveq #32, d2
	bra buttons_no_leftright

down:
	
	;check if we are already at the bottom of the page
	moveq #1, d0
	add.b (selected).w, d0
	tst.b num_menu.w
	bne .menu
	tst.b num_slots.w
	bne .slots
	move.w d0, d1
	add.w d1, d1
	add.w d1, d1
	lea page_index.w, a2
	tst.l (0, a2, d1.w)
	beq handle_done
.do_move
	move.b d0, (selected).w

	add.w d2, (sprite_list).w
	add.w d2, (sprite_list+8).w
	rts
.menu:
	cmp.b num_menu.w, d0
	beq handle_done
	bra .do_move
.slots:
	cmp.b num_slots.w, d0
	beq handle_done
	bra .do_move
	
up:
	;check if we are already at the top of the page
	move.b (selected).w, d0
	beq handle_done
	subq #1, d0
	move.b d0, (selected).w

	sub.w d2, (sprite_list).w
	sub.w d2, (sprite_list+8).w
	rts

right:
	;check that we have another page to go to
	tst.b more_pages.w
	beq handle_done
	;switch to the next page
	move.l page_stack.w, a6
	move.l (-4, a6), a6

	addq #6, a7
	bra render_page

left:
	move.l page_stack.w, a5
	;check if we're already on the first page
	cmp.l #(page_pointers+8), a5
	beq handle_done
	;switch to previous page
	lea (-12, a5), a5
	move.l (a5)+, a6
	move.l a5, page_stack.w

	addq #6, a7
	bra render_page

select_entry:
	moveq #0, d0
	move.b (selected).w, d0
	add.w d0, d0
	add.w d0, d0
	tst.b num_menu.w
	bne .select_menu_button
	tst.b num_slots.w
	bne .select_save_slot
	lea page_index.w, a2
	move.l (0, a2, d0.w), a2
	tst.b (-1, a2)
	bne enter_dir
	;regular file
	lea menu_port+8, a3
	move.l a2, (a3)
	
	addq #6, a7
	bra show_pause_menu
.select_menu_button:
	movea.l menu_functions.w, a2
	move.l (0, a2, d0.w), a2
	addq #6, a7
	jmp (a2)
.select_save_slot:
	lea menu_port, a3
	moveq #0, d0
	move.b port_off.w, d0
	add.w d0, a3
	move.b selected.w, d0
	move.l d0, (a3)
	addq #6, a7
	jmp show_pause_menu
	
enter_dir:
	lea menu_port+4, a3
	move.l a2, (a3)
.wait_complete
	tst.w (a3)
	bne .wait_complete
	addq #6, a7
	bra menu_start

handle_mouse:
	move.b last_mbuttons.w, d4
	eor.b d3, d4
	and.b d3, d4
	move.b d3, last_mbuttons.w

	move.b d0, d2
	or.b d1, d2
	beq .no_mouse_move


	tst.b mouse_shown.w
	bne .skip_show_check

	moveq #0, d2
	move.b num_sprites.w, d2
	move.w d2, d4
	lsl.w #3, d4
	lea sprite_list.w, a2
	move.b d2, (-5, a2, d4.w)
	lea (0, a2, d4.w), a2
	move.l a2, mouse_sprite.w
	move.l #$01000500, (a2)+
	move.w #$8083, (a2)
	move.w #$100, mouse_x.w
	addq #1, d2
	move.b d2, num_sprites.w

	move.b #1, mouse_shown.w

.skip_show_check
	neg.w d1
	move.l mouse_sprite.w, a2
	add.w d1, (a2)
	add.w d0, mouse_x.w
	move.w mouse_x.w, d0
	asr.w #1, d0
	move.w d0, (6, a2)
	move.w (a2), d1
	cmp.w selection_top.w, d1
	blo .done
	cmp.w selection_bot.w, d1
	bhi .done
	tst.b num_menu.w
	bne .handle_menu
	tst.b num_slots.w
	bne .handle_slots
	and.w #$FFF0, d1
	subq #8, d1
	move.w d1, (sprite_list).w
	move.w d1, (sprite_list+8).w

	sub.w #264, d1
	lsr.w #4, d1
	move.b d1, selected.w
	bra .no_mouse_move
.handle_menu
	;TODO: FIXME
	and.w #$FFF0, d1
	moveq #0, d0
	move.w d1, d0
	sub.w selection_top.w, d0
	divu.w #48, d0
	swap d0
	tst.w d0
	beq .no_adjust
	
	cmp.w #16, d0
	bne .round_up
	swap d0
	sub.w #16, d1
	bra .set_cursor_pos
	
.round_up
	swap d0
	addq #1, d0
	add.w #16, d1
	bra .set_cursor_pos
	
.no_adjust
	swap d0
.set_cursor_pos
	move.w d1, (sprite_list).w
	move.w d1, (sprite_list+8).w

	move.b d0, selected.w
	
	bra .no_mouse_move
.handle_slots
	and.w #$FFE0, d1
	subq #8, d1
	move.w d1, (sprite_list).w
	move.w d1, (sprite_list+8).w

	sub.w #264, d1
	lsr.w #5, d1
	move.b d1, selected.w
.no_mouse_move
	btst #0, d4
	bne select_entry
.done
	rts
int_4:
empty_handler:
	rte

id_lookup:
	dc.b $0, $1, $4, $5
	dc.b $2, $3, $6, $7
	dc.b $8, $9, $C, $D
	dc.b $A, $B, $E, $F

io_read:
	;read TH=1
	move.b (a2), d0
	;read TH=0
	move.b #0, (a2)
	nop
	nop
	move.b (a2), d1
	;reset TH to 1
	move.b #$40, (a2)

	moveq #0, d2   ;4

	;calculate Mega Drive peripheral ID
	move.b d1, d2  ;4
	lsr.b #1, d2   ;8, 12
	or.b d1, d2    ;4, 16
	and.b #5, d2   ;8, 24

	move.b d0, d3  ;4
	add.b d3, d3   ;4, 8
	or.b d0, d3    ;4, 12
	and.b #$A, d3  ;8, 20

	or.b d3, d2    ;4
	move.b (id_lookup, pc, d2.w), d2 ;14


	cmp.b #$3, d2
	beq .mouse

	cmp.b #$D, d2
	bne .not_pad

	and.b #$3F, d0
	and.b #$30, d1
	add.b d1, d1
	add.b d1, d1
	or.b d1, d0
	not.b d0
	rts
.not_pad:
	moveq #0, d0
	rts

.mouse:

	move.b #$60, (a2)
	move.b #$60, (PAD1_CTRL-PAD1_DATA, a2)
	move.b #$60, (a2)

	moveq #$f, d4
wait_hi_init:
	btst #4, (a2)
	beq wait_hi_init
	nop
	nop
	move.b #$20, (a2)
	nop
	nop
	moveq #$f, d4
	move.b #0, (a2)
.wait_lo
	btst #4, (a2)
	bne .wait_lo
	moveq #$f, d4
	move.b #$20, (a2)
.wait_hi
	btst #4, (a2)
	beq .wait_hi

	lea mouse_buf.w, a3
	move.l a3, a4
	moveq #2, d3
	moveq #0, d0
loop:
	moveq #$f, d4
	move.b #0, (a2)
.wait_lo
	btst #4, (a2)
	bne .wait_lo
	move.b (a2), d0
	lsl.b #4, d0
	moveq #$f, d4
	move.b #$20, (a2)
.wait_hi
	btst #4, (a2)
	beq .wait_hi
	move.b (a2), d1
	and.b #$f, d1
	or.b d1, d0
	move.b d0, (a3)+

	dbra d3, loop

	;end request
	move.b #$60, (a2)


	;massage data
	moveq #0, d1
	move.b d0, d1
	move.b (a4)+, d3
	move.b (a4), d0

	btst #4, d3
	beq xpos
	or.w #$FF00, d0
xpos
	btst #5, d3
	beq ypos
	or.w #$FF00, d1
ypos
	;set port config back to normal controller mode
	move.b #$40, (PAD1_CTRL-PAD1_DATA, a2)
	rts

topcorner equ (button-font)/64 + 32
topmiddle equ topcorner+1
botcorner equ topmiddle+1
botmiddle equ botcorner+1
horiz_flip equ $800
vert_flip equ $1000

; draws a button
; d0.w - x in cells
; d1.w - y in cells
; d2.w - width in cells
;
; clobbers a6
draw_button:
	;multiply x by 2
	add.w d0, d0
	;multiply y by 128
	lsl.w #7, d1
	add.w d1, d0
	add.w #$A000, d0
	move.w d0, d1
	and.w #$3FFF, d0
	rol.w #2, d1
	and.w #3, d1
	ori.w #(VDP_VRAM_WRITE >> 16), d0
	swap d0
	move.w d1, d0
	move.l d0, (a1)
	move.w d2, d1
	;top left corner
	move.w #topcorner, (a0)
	subq #3, d1
	bmi .notopmiddle
.toploop:
	;top middle
	move.w #topmiddle, (a0)
	dbra d1, .toploop
.notopmiddle
	;top right corner
	move.w #(topcorner | horiz_flip), (a0)
	;go to next row in name table
	add.l #((2*64) << 16), d0
	move.l d0, (a1)
	;bottom left corner
	move.w #botcorner, (a0)
	subq #3, d2
	bmi .nomiddlebot
.botloop:
	;bottom middle
	move.w #botmiddle, (a0)
	dbra d2, .botloop
.nomiddlebot
	;bottom right corner
	move.w #(botcorner | horiz_flip), (a0)
	rts

;a5 - menu pointer
;d6 - initial Y position of menu
draw_menu:
	moveq #0, d7
	moveq #0, d5
	;select first item
	move.b d7, selected.w
	;save menu pointer for second pass
	movea.l a5, a4
	;adjust arrow mask
	move.w #$FFE0, selection_mask.w
.lenloop	
	tst.b (a5)
	beq .lendone
	addq #1, d5
	movea.l a5, a6
	bsr strlen
	cmp.w d7, d0
	blo .nochange
	move.w d0, d7
.nochange
	lea (1, a5, d0.w), a5
	bra .lenloop
.lendone
	
	addq #2, d7
	move.b d5, num_menu.w
	
	;calculate X position
	move.w d7, d4
	lsr.w #1, d4
	moveq #20, d5
	sub.w d4, d5
	;calculate left arrow X
	move.w d5, d4
	lsl.w #3, d4
	add.w #(128-24), d4
	move.w d4, (sprite_list+6).w
	;calculate right arrow x
	move.w d7, d3
	lsl.w #3, d3
	add.w d3, d4
	add.w #32, d4
	move.w d4, (sprite_list+6+8).w
	;update left arrow Y
	move.w d6, d4
	lsl.w #4, d4
	add.w #256, d4
	move.w d4, (sprite_list).w
	move.w d4, (sprite_list+8).w
	;update mouse top limit
	move.w d4, selection_top.w
	;restore menu pointer
	movea.l a4, a5
.drawloop
	tst.b (a5)
	beq .done
	;x pos
	move.w d5, d0
	;y pos
	move.w d6, d1
	;width
	move.w d7, d2
	bsr draw_button
	
	movea.l a5, a6
	bsr strlen
	movea.l a5, a6
	lea (1, a5, d0.w), a5
	;x pos
	move.w d7, d1
	lsr.w #1, d1
	add.w d5, d1
	lsr.w #1, d0
	sub.w d0, d1
	;y pos
	move.w d6, d2
	;base attribute
	move.w #$206B, d0
	bsr print_string_fixed
	
	addq #3, d6
	bra .drawloop
.done
	;update mouse bottom limit
	lsl.w #4, d6
	add.w #224, d6
	move.w d6, selection_bot.w
	rts
	
clear_screen:
	;clear name tables
	vdpaccess $8000, VDP_VRAM_WRITE
	moveq #32, d0
	swap d0
	move.b #32, d0
	move.w #(64*64-1), d1
ploop:
	move.l d0, (a0)
	dbra d1, ploop
	rts

initial_regs:
	vdpreg MODE_2, $4    ;Mode 5, everything turned off
	vdpreg MODE_1, $4
	vdpreg SCROLL_A, $20 ;Scroll a table $8000
	vdpreg SCROLL_B, $05 ;Scroll b table $A000
	vdpreg SAT, $60      ;SAT table $C000
	vdpreg BG_COLOR, 0
	vdpreg HINT, $FF
	vdpreg MODE_3, 0     ;full screen scroll
	vdpreg MODE_4, $87   ;40 cell mode, double-res interlace
	vdpreg HSCROLL, 0
	vdpreg AUTOINC, 2
	vdpreg SCROLL, 1     ;64x32 scroll size
end_initial_regs

start:
	lea $FF0000, a0
	moveq #0, d0
	move.w #($10000/8 - 1), d1
.clearloop:
	move.l d0, (a0)+
	move.l d0, (a0)+
	dbra d1, .clearloop

	lea $C00000, a0
	lea $C00004, a1

	moveq #(end_initial_regs-initial_regs-1), d0
	lea initial_regs.w, a2
.regloop
	move.w (a2)+, (a1)
	dbra d0, .regloop

	vdpaccess $0, VDP_CRAM_WRITE
	move.w #$020, (a0)
	move.w #$EEE, (a0)
	move.w #$222, (a0)

	;init scroll table
	vdpaccess $0, VDP_VRAM_WRITE
	move.w #0, (a0)
	move.w #0, (a0)
	
	
	;load tiles
	vdpaccess $800, VDP_VRAM_WRITE
	lea font(pc), a2
	move.w #((buttonend-font)/4 - 1), d0
tloop:
	move.l (a2)+, (a0)
	dbra d0, tloop
	move.w #((fontfixedend-fontfixed)/4 - 1), d0
dtloop:
	move.l (a2)+, d1
	move.l d1, (a0)
	move.l d1, (a0)
	dbra d0, dtloop


	;setup SAT
	;;vdpaccess $C000, VDP_VRAM_WRITE

	lea sprite_list.w, a2
	;left arrow
	move.l #$01080501, (a2)+
	move.l #$807F0086, (a2)+

	;right arrow
	move.l #$01080500, (a2)+
	move.l #$887F01AA, (a2)+
	move.b #2, num_sprites.w
	
show_main_menu:
	bsr clear_screen
	;init vertical scroll RAM
	vdpaccess $0, VDP_VSRAM_WRITE
	move.w #-4, (a0)
	move.w #0, (a0)
	
	moveq #8, d6
	move.l #main_menu_func, menu_functions.w
	lea main_menu(pc), a5
	bsr draw_menu
	bra gamepad_setup
	
show_pause_menu:
	bsr clear_screen
	;init vertical scroll RAM
	vdpaccess $0, VDP_VSRAM_WRITE
	move.w #-4, (a0)
	move.w #0, (a0)
	moveq #8, d6
	move.l #pause_menu_func, menu_functions.w
	lea pause_menu(pc), a5
	bsr draw_menu
	bra gamepad_setup
	
menu_start:
	;init vertical scroll RAM
	vdpaccess $0, VDP_VSRAM_WRITE
	move.w #0, (a0)
	move.w #0, (a0)
	
	;reset arrow position
	move.w #$0108, sprite_list.w
	move.w #$0108, (sprite_list + 8).w
	move.w #$0086, (sprite_list + 6).w
	move.w #$01AA, (sprite_list + 6 + 8).w
	
	;reset selection
	move.b #0, selected.w

	
	lea page_pointers.w, a5
	lea dir_buffer, a6
	move.l a6, (a5)+
	move.l a5, page_stack.w
	lea menu_port, a2
	move.l a6, (a2)

wait_complete:
	tst.w (a2)
	bne wait_complete

render_page:
	bsr clear_screen
	
	;clear menu state
	move.b #0, num_menu.w
	move.w #272, selection_top.w
	move.w #655, selection_bot.w
	move.w #$FFF0, selection_mask.w

	;init scroll table
	vdpaccess $0, VDP_VRAM_WRITE
	move.w #0, (a0)
	move.w #4, (a0)
	
	move.l #$40860002, d3
	move.l d3, (a1)
	move.l d3, base_cmd.w
	

	move.b #0, more_pages.w
	lea page_index.w, a3
	moveq #MAX_DISPLAY-1, d7
file_loop:
	tst.b (a6)+
	beq done_files
	addq #1, a6 ;TODO: Do something with directory flag

	;skip over entries starting with a dot except ..
	cmp.b #$2E, (a6)
	bne normal
	cmp.b #$2E, (1, a6)
	beq normal
	addq #1, a6
.skip_loop:
	tst.b (a6)+
	bne .skip_loop
	addq #1, d7
	move.l a6, d6
	bra skip
normal:
	;save entry pointer to page index
	move.l a6, (a3)+
	;print name on screen
	moveq #0, d0
	bsr print_string
	move.l a6, d6

	lea Newline(pc), a6
	bsr print_string

skip:
	;word align pointer
	addq #1, d6
	and.w #$FFFE, d6
	move.l d6, a6

	dbra d7, file_loop
	tst.b (a6)
	beq done_files
	move.b #1, more_pages.w
done_files:
	move.l page_stack.w, a5
	move.l a6, (a5)+
	move.l a5, page_stack.w

	;null terminate page_index
	moveq #0, d0
	move.l d0, (a3)

gamepad_setup:
	;setup gamepads
	move.b #$40, PAD1_CTRL
	move.b #$40, PAD2_CTRL

	move.w #$8174, (a1) ;enable display, vertical interrupts, DMA


wait_forever
	stop #2500
	bra wait_forever
	
show_about:
	bsr clear_screen
	moveq #1, d7
	lea about_text(pc), a6
	;base attribute
	move.w #$006B, d0
.loop
	tst.b (a6)
	beq .done
	;x pos
	moveq #1, d1
	;y pos
	move.w d7, d2
	bsr print_string_fixed
	addq #1, d7
	bra .loop
.done
	moveq #8, d6
	move.l #about_menu_func, menu_functions.w
	lea about_menu(pc), a5
	bsr draw_menu
.wait
	stop #$2500
	bra .wait
	
exit:
	move.l #1, menu_port+12
	bra exit
	
resume:
	move.l #2, menu_port+12
	bra show_pause_menu
	
show_save_slots:
	move.w #(256+26), sprite_list.w
	move.w #(256+26), (sprite_list+8).w
	move.w #(128+8), (sprite_list+6).w
	move.w #(128+320-24), (sprite_list+6+8).w
	move.w #(256+32), selection_top.w
	move.b #0, selected.w
	move.b #0, num_menu.w
	lea dir_buffer, a6
	lea menu_port+16, a3
	move.l a6, (a3)
.waitdone:
	tst.w (a3)
	bne .waitdone
	bsr clear_screen
	moveq #0, d0
	
	moveq #0, d6
	moveq #2, d7
.slotloop
	tst.b (a6)
	beq .done
	addq #1, d6
	moveq #4, d1
	move.w d7, d2
	bsr print_string_fixed
	addq #2, d7
	bra .slotloop
.done
	lsl.w #4, d7
	add.w #248, d7
	move.w d7, selection_bot.w
	move.b d6, num_slots.w
	rts
	
save_state:
	move.b #(5*4), port_off.w
	bsr show_save_slots
.wait
	stop #$2500
	bra .wait
	
load_state:
	move.b #(6*4), port_off.w
	bsr show_save_slots
.wait
	stop #$2500
	bra .wait
	
about_text:
	dc.b "BlastEm v0.4.0", 0
	dc.b "Copyright 2011-2016 Michael Pavone", 0
	dc.b " ", 0
	dc.b "BlastEm is a high performance, open", 0
	dc.b "source (GPLv3) Genesis/Megadrive", 0
	dc.b "emulator.",0
	dc.b 0
	

Newline:
	dc.b $A, 0

	align 1

;Prints a null terminated string
;a6 - pointer to string
;a0 - VDP data port
;d0 - base tile attribute
;
;Clobbers: d1.w, d2.w, d3.l
print_string:
	lea widths(pc), a5
	move.w x_pos.w, d2
	move.l base_cmd.w, d3
.loop
	moveq #0, d1
	move.b (a6)+, d1
	beq .end
	cmp.b #$A, d1
	beq .newline
	tst.b (-32, a5, d1.w)
	beq .narrow
	add.w d0, d1
	move.w d1, (a0)
	addq #2, d2
	bra .loop
.narrow
	add.w d0, d1
	move.w d1, (a0)
	addq #1, d2
	move.l d2, d1
	;switch to other plane
	and.w #$FFFE, d1
	swap d1
	eor.l #$20000000, d3
	add.l d3, d1
	move.l d1, (a1)
	bra .loop
.newline
	moveq #0, d2
	;switch back to plane A
	and.l #$DFFFFFFF, d3
	;skip to next row
	add.l #$00800000, d3
	move.l d3, (a1)
	bra .loop
.end
	move.w d2, x_pos.w
	move.l d3, base_cmd.w
	rts
	
;Prints a null-terminated string with a fixed width font
;a6 - pointer to string
;a0 - VDP data port
;d0 - base tile attribute
;d1 - x col
;d2 - y col
;
print_string_fixed:
	;multiply x by 2
	add.w d1, d1
	;multiply y by 128
	lsl.w #7, d2
	add.w d2, d1
	add.w #$8000, d1
	move.w d1, d2
	and.w #$3FFF, d1
	rol.w #2, d2
	and.w #3, d2
	ori.w #(VDP_VRAM_WRITE >> 16), d1
	swap d1
	move.w d2, d1
	move.l d1, (a1)
.loop
	moveq #0, d1
	move.b (a6)+, d1
	beq .end
	add.w d0, d1
	move.w d1, (a0)
	bra .loop
.end
	rts
	
;Returns string length in d0
;a6 - pointer to string
strlen:
	moveq #-1, d0
.loop
	addq #1, d0
	tst.b (a6)+
	bne .loop
	rts

	align 1
font:
	incbin font_interlace_variable.tiles
fontend
arrow:
	incbin arrow.tiles
arrowend:
cursor:
	incbin cursor.tiles
cursorend:
button:
	incbin button.tiles
buttonend:
fontfixed:
	incbin font.tiles
fontfixedend:

widths:
	dc.b 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1
	dc.b 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0
	dc.b 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1
	dc.b 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
	dc.b 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1
	
main_menu:
	dc.b "Load ROM", 0
	dc.b "About", 0
	dc.b "Exit", 0
	dc.b 0
	
	align 1
main_menu_func:
	dc.l menu_start
	dc.l show_about
	dc.l exit
	
about_menu:
	dc.b "Return", 0
	dc.b 0
	
	align 1
about_menu_func:
	dc.l show_main_menu
	
pause_menu:
	dc.b "Resume", 0
	dc.b "Load ROM", 0
	dc.b "Save State", 0
	dc.b "Load State", 0
	dc.b "Exit", 0
	dc.b 0
	
	align 1
pause_menu_func
	dc.l resume
	dc.l menu_start
	dc.l save_state
	dc.l load_state
	dc.l exit

rom_end: