From ArchaicPixels: HuC and PCEAS Documentation
;
; STARTUP.INC - MagicKit startup code equates and macros
;
; ----
; this block defines names for joypad
; direction and button bits
JOY_I = $01
JOY_II = $02
JOY_SEL = $04
JOY_RUN = $08
JOY_UP = $10
JOY_RIGHT = $20
JOY_DOWN = $40
JOY_LEFT = $80
JOY_TYPE6 = $50
JOY_III = $01
JOY_IV = $02
JOY_V = $04
JOY_VI = $08
JOY_BITI = $0
JOY_BITII = $1
JOY_BITSEL = $2
JOY_BITRUN = $3
JOY_BITUP = $4
JOY_BITRT = $5
JOY_BITDN = $6
JOY_BITLT = $7
JOY_BITIII = $0
JOY_BITIV = $1
JOY_BITV = $2
JOY_BITVI = $3
; ----
; this block defines names for interrupt
; vectors
;
IRQ2 = 0
IRQ1 = 1
TIMER = 2
NMI = 3
VSYNC = 4
HSYNC = 5
SOFT_RESET = 6
; ----
; setvec(num, addr)
; ----
; num, vector number (see defines above)
; addr, address of the new routine
; ----
setvec .macro
lda \1
ldx #LOW(\2)
ldy #HIGH(\2)
jsr set_intvec
.endm
; ----
; vec_on(num)
; ----
; num, vector to enable
; ----
vec_on .macro
.if (\1 = 5)
smb #6,<irq_m
.else
smb \1,<irq_m
.endif
.endm
; ----
; vec_off(num)
; ----
; num, vector to disable
; ----
vec_off .macro
.if (\1 = 5)
rmb #6,<irq_m
.else
rmb \1,<irq_m
.endif
.endm
; ----
; vsync([nb])
; ----
; nb, number of frames to be sync'ed on
; ----
vsync .macro
.if (\# = 0)
lda #1
.else
lda \1
.endif
jsr wait_vsync
.endm
;===================================================================
;
; STARTUP.ASM - MagicKit standard startup code
;
; first, set MOUSE to default on:
;
SUPPORT_MOUSE .equ 1
.list
.ifdef HUC
.include "huc.inc" ; HUC
.include "huc_opt.inc"
.endif ; HUC
.include "standard.inc" ; HUCARD
; ----
; setup flexible boundaries for startup code
; and user program's "main".
;
START_BANK .equ 0
LIB1_BANK .equ START_BANK
LIB2_BANK .equ START_BANK+1
.ifdef HUC
FONT_BANK .equ START_BANK+1
.if (CDROM)
CONST_BANK .equ START_BANK+2
DATA_BANK .equ START_BANK+3
.else
PSG_BANK .equ START_BANK+2
CONST_BANK .equ START_BANK+3
DATA_BANK .equ START_BANK+4
.endif
.else
; HuC (because of .proc/.endp) does not use MAIN_BANK
MAIN_BANK .equ START_BANK+2
.endif ; HUC
; ----
; if FONT_VADDR is not specified, then specify it
; (VRAM address to load font into)
;
.ifndef FONT_VADDR
FONT_VADDR .equ $0800
.endif
; ----
; system variables
;
.zp
zp_ptr1: .ds 2
.bss
.if (CDROM) ; CDROM def's in system.inc
.include "system.inc"
.else ; ie HuCard
.org $2200
user_jmptbl: ; user interrupt vectors
irq2_jmp: .ds 2 ; IRQ2 (BRK instruction and external IRQ)
irq1_jmp: .ds 2 ; IRQ1 (VDC interrupt)
timer_jmp: .ds 2 ; TIMER
nmi_jmp: .ds 2 ; NMI (unused)
vsync_hook: .ds 2 ; VDC vertical sync routine
hsync_hook: .ds 2 ; VDC horizontal sync rountine
bg_x1: .ds 2
bg_x2: .ds 2
bg_y1: .ds 2
bg_y2: .ds 2
.org $2227
joyena: .ds 1 ; soft reset enable (bit 0/pad 1, bit 1/pad2, etc.)
joy: .ds 5 ; 'current' pad values (pad #1-5)
joytrg: .ds 5 ; 'delta' pad values (new keys hit)
joyold: .ds 5 ; 'previous' pad values
.org $2241
irq_cnt: .ds 1 ; VDC interrupt counter; increased 60 times per second
; reset to zero when vsync() function called
vdc_mwr: .ds 1
vdc_dcr: .ds 1
.endif
.org $2244
scr_mode: .ds 1 ; screen mode and dimensions - set by <ex_scrmod>
scr_w: .ds 1
scr_h: .ds 1
.org $2284
soft_reset: .ds 2 ; soft reset jump loc (run+select)
.if !(CDROM)
.include "sound.inc"
.endif
.org $2680
vsync_cnt: .ds 1 ; counter for 'wait_vsync' routine
joybuf: .ds 5 ; 'delta' pad values collector
joyhook: .ds 2 ; 'read_joypad' routine hook
joycallback: .ds 6 ; joypad enhanced callback support
disp_cr: .ds 1 ; display control (1 = on, 0 = off)
clock_hh .ds 1 ; system clock, hours since startup (0-255)
clock_mm .ds 1 ; system clock, minutes since startup (0-59)
clock_ss .ds 1 ; system clock, seconds since startup (0-59)
clock_tt .ds 1 ; system clock, ticks (1/60th sec) since startup (0-59)
joy6: .ds 5 ; second byte for 6-button joysticks
joytrg6: .ds 5
joyold6: .ds 5
joybuf6: .ds 5
joytmp: .ds 5
joytmp6: .ds 5
.if (CDROM)
ovl_running .ds 1 ; overlay # that is currently running
cd_super .ds 1 ; Major CDROM version #
irq_storea .ds 1 ; CDROM IRQ-specific handling stuff
irq_storeb .ds 1
ram_vsync_hndl .ds 25
ram_hsync_hndl .ds 25
.endif ; (CDROM)
;±±±[ STARTUP CODE ]±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
; Let's prepare this secondary libray bank first, for use later.
; The reason, as you will see, is because code for a given function
; which sits together in a file, may have things in zero-page,
; bss, LIB1_BANK (ie. START_BANK), and LIB2_BANK.
;
; The assembler must know beforehand what address etc. to use as a basis.
;
.data
.bank LIB2_BANK,"Base Library 2/Font"
.org $6000
.include "font.inc"
.code
.bank LIB2_BANK
.org $A600
.data
.bank CONST_BANK,"Constants"
.data
.bank DATA_BANK,"User Program"
.org $6000
;
; place overlay array here
; 50 entries, each containing
; 2 bytes for start sector,
; 2 bytes for # sectors
;
ovlarray: .ds 200
.code
.bank START_BANK,"Base Library 1"
; A little introduction to the boot sequence:
;
; A HuCard has its origin at bank 0, and is mapped at $E000
; It needs to grab the interrupt vectors at $FFF6 and implement
; implement handlers for them
;
; A CDROM will load at bank $80 ($68 for SCD), and the initial
; loader will be mapped at $4000. The current MagicKit sequence
; also maps $C000 to this same bank. However, the initial boot
; sequence will execute at $4070, proceeding to load additional
; code and data, and then jump to a post-boot section called
; 'init_go'. This is the point at which the loader explicitly
; relinquishes the $4000 segment. It should be noted that there
; are library subroutines loaded as part of this initial segment,
; and those routines are located in the $C000 range as well.
;
; Sectors are loaded, up to and including the first "DATA_BANK",
; where the overlay array is stored - so that the CDROM error
; overlay can be located and executed in the event of a CDROM
; system version mismatch (ie. playing SCD games on CDROM)
;
; A second entry point is defined for overlays that are not
; being booted (ie. they are loaded and executed from another
; overlay). This entry point is at $4000, after the segments
; have all found their natural loading spots (ie. segment $68
; for Super CDROMs). This entry point maps the necessary
; segments and resets the stack, without clearing memory or
; performing other setup chores, and then maps and executes
; _main() to run the module. The user has no choice regarding
; this function, although he can pass values through the global
; variables which main() can use to decide what to do next.
;
; An additional "Hook" area has now been defined at $4028,
; which is used at initial load time, in case a SCD overlay
; program is run on plain CDROM hardware, and the author
; wishes to override the default text error message by
; loading and executing a plain CDROM program instead
;
; ----
; interrupt vectors
.if !(CDROM)
.org $FFF6
.dw _irq2
.dw _irq1
.dw _timer
.dw _nmi
.dw _reset
.endif ; !(CDROM)
; ----
; develo startup code
.if (DEVELO)
.org $6000
sei
map _reset
jmp _reset
_restart:
cla ; map the CD-ROM system bank
tam #7
jmp $4000 ; back to the Develo shell
.endif ; (DEVELO)
; ----
; reset
; ----
; things start here
; ----
; ----
; CDROM re-map library bank
;
;
; overlay entry point
;
; assume MMR0, MMR1, MMR6, MMR7 are set.
; set others & reset stack pointer
;
.if (CDROM)
.org $C000
; current overlay number that is running
; this is overwritten by the isolink prgram; the load
; statement must be the first in the block
;
ovlentry:
lda #1
sta ovl_running
lda #CONST_BANK+_bank_base
tam #2
lda #DATA_BANK+_bank_base
tam #3
lda #_call_bank
tam #4
stw #$4000,<__sp
ldx #$ff
txs
map _main
jsr _main
bra *
;
; CDROM error message alternate load entry point
;
.org $4028
cderr_override: .db 0
cderr_overlay_num: .db 0
cdrom_err_load:
; since CDROM program will load into same area in RAM,
; this load routine must be executed from scratch RAM
; re-use the ram interrupt handler areas (not yet initialized)
tii .load_cd_ovl, ram_vsync_hndl, 64
jmp ram_vsync_hndl
.load_cd_ovl:
lda cderr_overlay_num
asl A
asl A
tay
lda #DATA_BANK+$80
tam #3
ldx ovlarray,Y++
lda ovlarray,Y++
stz <_cl ; sector (offset from base of track)
sta <_ch
stx <_dl
lda ovlarray,Y
sta <_al ; # sectors
lda #$80
sta <_bl ; bank #
lda #3
sta <_dh ; MPR #
jsr cd_read
cmp #0
bne .error
lda #$80
tam #2
jmp _boot
.error: jmp cd_boot ; Can't load - reboot CDROM system card
;
; Proper Boot-time entry point
;
.org $4070
_boot:
stz $2680 ; clear program RAM
tii $2680,$2681,$197F
;
; Note: All CDROM boot loaders will load into MMR $80 region
; regardless of whether they are CD or SCD.
; Here, we will move the information to occupy
; base memory at MMR $68 if appropriate
;
.if (CDROM = SUPER_CD)
jsr ex_getver ; check if SCD program running
stx cd_super ; on SCD hardware
cpx #3 ; don't copy to _bank_base if
bne .nocopy ; memory doesn't exist there
lda #_bank_base+1 ; copy bank 2 to proper location
tam #6
tii $6000,$C000,$2000
tam #3 ; FONT_BANK now lives in SCD area ($69 exactly)
lda #_bank_base ; then copy bank 1
tam #6
tii $4000,$C000,$2000 ; then load rest of program
.nocopy:
.endif ; (CDROM = SUPER_CD)
.else ; (ie. if HuCard...)
.org $E010
_reset:
sei ; disable interrupts
csh ; select the 7.16 MHz clock
cld ; clear the decimal flag
ldx #$FF ; initialize the stack pointer
txs
lda #$FF ; map the I/O bank in the first page
tam #0
lda #$F8 ; and the RAM bank in the second page
tam #1
stz $2000 ; clear all the RAM
tii $2000,$2001,$1FFF
.endif ; (CDROM)
; ----
; initialize the hardware
_init:
.if (CDROM)
jsr ex_dspoff
jsr ex_rcroff
jsr ex_irqoff
jsr ad_reset
.else
stz timer_ctrl ; init timer
.endif ; (CDROM)
jsr init_psg ; init sound
jsr init_vdc ; init video
lda #$1F ; init joypad
sta joyena
; ----
; initialize interrupt vectors
.if (CDROM)
jsr ex_dspon
jsr ex_rcron
jsr ex_irqon
.else
ldx #4 ; user vector table
cly
.l2: lda #LOW(_rti)
sta user_jmptbl,Y
iny
lda #HIGH(_rti)
sta user_jmptbl,Y
iny
dex
bne .l2
stw #_reset,soft_reset ; soft reset
stw #_rts,vsync_hook ; user vsync routine
stw #_rts,hsync_hook ; user hsync routine
lda #$01 ; enable interrupts
sta irq_disable
stz irq_status
cli
; ----
; enable display and VSYNC interrupt
vreg #5
lda #$C8
sta <vdc_crl
sta video_data_l
st2 #$00
lda #$01
sta disp_cr
.endif ; (CDROM)
; ----
; init TIA instruction in RAM (fast BLiTter to hardware)
lda #$E3 ; TIA instruction opcode
sta _ram_hdwr_tia
lda #$60 ; RTS instruction opcode
sta _ram_hdwr_tia_rts
; ----
; init random number generator
lda #1
jsr wait_vsync ; wait for one frame & randomize _rndseed
stw #$03E7,<_cx ; set random seed
stw _rndseed,<_dx
jsr srand
.if (CDROM)
.if (CDROM = SUPER_CD)
lda cd_super ; don't load the program if SCD
cmp #3 ; program not running on SCD hrdware
beq loadprog
lda cderr_override
lbeq dontloadprog
jmp cdrom_err_load
.endif ; (SUPER_CD)
; ----
; load program
; ----
; CL/CH/DL = sector address
; DH = load mode - bank mode ($6000-$7FFF)
; BL = bank index
; AL = number of sectors
;
loadprog:
lda ovlentry+1 ; current overlay (as written by ISOLINK)
cmp #1 ; is it initial overlay ?
lbne _init_go ; if not initial overlay, somebody else already
; loaded us completely; do not try to load remainder
; (ie. executing CDROM error overlay)
stz <_cl ; initial boot doesn't load complete program;
stz <_ch ; prepare to load remainder
lda #10 ; 10th sector (0-1 are boot;
; 2-9 are this library...)
sta <_dl
lda #3 ; load mode (consecutive banks; use MPR 3)
sta <_dh
stw #(_bank_base+2),<_bx ; 2 banks are boot/base library
stw #(_nb_bank-2)*4,<_ax
jsr cd_read
cmp #$00
lbeq _init_go
; ----
jmp cd_boot ; reset
; This is the point in the CDROM loader where the code no longer
; executes in the $4000 segment, in favour of using the $C000
; segment (also used for the library subroutines)
.org $C130
; These routines will be run from RAM @ $2000 so we
; need to count bytes to determine how much to xfer
; (The total is 24 bytes, but we copy 25)
.bank LIB2_BANK
vsync_irq_ramhndlr:
php ; 1 byte
pha ; 1
tma #6 ; 2
sta irq_storea ; 3
lda #BANK(_vsync_hndl) ; 2
tam #6 ; 2
pla ; 1
pha ; 1
jsr _vsync_hndl ; 3
lda irq_storea ; 3
tam #6 ; 2
pla ; 1
plp ; 1
rts ; 1 = 24 bytes
hsync_irq_ramhndlr:
php ; 1 byte
pha ; 1
tma #6 ; 2
sta irq_storeb ; 3
lda #BANK(_hsync_hndl) ; 2
tam #6 ; 2
pla ; 1
pha ; 1
jsr _hsync_hndl ; 3
lda irq_storeb ; 3
tam #6 ; 2
pla ; 1
plp ; 1
rts ; 1 = 24 bytes
.bank LIB1_BANK
_init_go:
.if (CDROM = SUPER_CD)
dontloadprog:
.endif
.endif ; (CDROM)
; ----
; jump to main routine
; ----
; load font
.ifdef HUC
stw #$4000,<__sp ; init stack ptr first
stw #FONT_VADDR,<_di ; Load Font @ VRAM addr
;
; this section of font loading was stolen
; from _load_default_font because the default
; FONT segment number is not yet guaranteed
; if the SCD is being run on a plain CDROM system
; so we need to trick the segment pointer
; with a reliable one
;
__ldw <_di ; stolen from _load_default_font
; because segment# default not reliable
jsr _set_font_addr ; set VRAM
.if (CDROM)
stb #FONT_BANK+$80,<_bl ; guarantee FONT_BANK even if
; SCD on regular CDROM system
.else
stb #FONT_BANK+_bank_base,<_bl
.endif
stb #96,<_cl
stb _font_color+1,<_ah
lda _font_color
bne .fntld
inc A
.fntld: sta <_al
clx
lda font_table,X
sta <_si
inx
lda font_table,X
sta <_si+1
; Now, load the font
;
; Note for CDROM/Super CDROM:
;
; The 'REAL' mapping for the lib2_load_font function
; maybe doesn't exist yet (we are executing from bank $80,
; not from $68 if it's a Super CDROM)
;
; So we must map the version at bank ($80 + LIB2_BANK)
; before executing it. We remap the bank after completion,
; 'just in case'
.if (CDROM)
tma #page(lib2_load_font)
pha
lda #LIB2_BANK+$80
tam #page(lib2_load_font)
jsr lib2_load_font
pla
tam #page(lib2_load_font)
.else
jsr load_font
.endif
;
; END stolen font-load
;
jsr _cls
stz color_reg ; set color #0 = 0/0/0 rgb
stz color_reg+1
stz color_data
stz color_data+1
lda #1 ; set color #1 = 7/7/7 rgb
sta color_reg
stz color_reg+1
ldx #$ff
stx color_data
sta color_data+1
; ----
; Super CDROM error message
; ----
.if (CDROM)
.if (CDROM = SUPER_CD)
lda cd_super
cmp #3
lbeq .ok ; SCD running on Super system
lda #FONT_BANK+$80 ; guarantee FONT_BANK even if
; SCD on regular CDROM system
tam #PAGE(scdmsg1)
__ldwi scdmsg1
__phw 2,2
__ldwi $0180
call _put_string.2
__ldwi scdmsg2
__phw 2,2
__ldwi $0200
call _put_string.2
__ldwi scdmsg3
__phw 2,2
__ldwi $0383
call _put_string.2
__ldwi scdmsg4
__phw 2,2
__ldwi $0403
call _put_string.2
bra * ; otherwise loop on blank screen
.bank LIB2_BANK
scdmsg1: .db "This game was written for the"
.db 0
scdmsg2: .db "PC Engine Super CDROM System"
.db 0
scdmsg3: .db "Please use a PC Engine"
.db 0
scdmsg4: .db "Super CDROM System card"
.db 0
.bank LIB1_BANK
.ok:
.endif ; (CDROM = SUPER_CD)
.endif ; (CDROM)
.endif ; (HUC)
.ifdef SUPPORT_MOUSE
jsr mousinit ; check existence of mouse
.endif ; SUPPORT_MOUSE
.if (CDROM)
; Now, install the RAM-based version of the
; interrupt-handlers and activate them
tma #page(vsync_irq_ramhndlr)
pha
lda #bank(vsync_irq_ramhndlr)
tam #page(vsync_irq_ramhndlr)
tii vsync_irq_ramhndlr,ram_vsync_hndl,25
tii hsync_irq_ramhndlr,ram_hsync_hndl,25
pla
tam #page(vsync_irq_ramhndlr)
stw #ram_vsync_hndl,vsync_hook ; set VSYNC handler
smb #4,<irq_m ; enable new code
smb #5,<irq_m ; disable system card code
stw #ram_hsync_hndl,hsync_hook ; set HSYNC handler
smb #6,<irq_m ; enable new code
smb #7,<irq_m ; disable system card code
.endif ; (CDROM)
.ifdef HUC
; ----
; Map the final stuff before executing main()
; ----
lda #CONST_BANK+_bank_base ; map string constants bank
tam #2 ; (ie. $4000-$5FFF)
lda #_call_bank ; map call bank
tam #4 ; (ie. $8000-$9FFF)
; ---
.if (CDROM)
lda #1 ; first overlay to run at boot time
sta ovl_running ; store for later use
.endif
; ---
stz clock_hh ; clear clock
stz clock_mm
stz clock_ss
stz clock_tt
map _main
jsr _main ; go!
bra *
.else
map main
jmp main
.endif ; HUC
; ----
; system
; ----
; give back control to the Develo system
; ----
.if (DEVELO)
_system:
sei
csh
cld
ldx #$FF ; stack
txs
lda #$FF ; I/O bank
tam #0
lda #$F8 ; RAM bank
tam #1
lda #$80 ; Develo Bank
tam #2
tma #7 ; startup code bank
tam #3
; ----
; re-initialize the machine
;
stz $2000 ; clear RAM
tii $2000,$2001,$1FFF
stz timer_ctrl ; init timer
jsr init_psg ; init sound
jsr init_vdc ; init video
lda #$1F ; init joypad
sta joyena
lda #$07 ; set interrupt mask
sta irq_disable
stz irq_status ; reset timer interrupt
lda #$80 ; disable sound driver
sta <$20E7
st0 #5 ; enable display and vsync interrupt
lda #$C8
sta <vdc_crl
sta video_data_l
jmp _restart ; restart
.endif ; (DEVELO)
;±±±[ INTERRUPT CODE ]±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
_rts:
rts
_rti:
rti
; ----
; irq2
; ----
; IRQ2 interrupt handler
; ----
.if !(CDROM)
_irq2:
bbs0 <irq_m,.user
rti
.user:
jmp [irq2_jmp]
.endif ; !(CDROM)
; ----
; irq1
; ----
; VDC interrupt handler
; ----
.if !(CDROM)
_irq1:
bbs1 <irq_m,user_irq1 ; jump to the user irq1 vector if bit set
; --
pha ; save registers
phx
phy
; --
lda video_reg ; get VDC status register
sta <vdc_sr ; save a copy
; ----
; vsync interrupt
;
.vsync:
bbr5 <vdc_sr,.hsync
; --
inc irq_cnt ; increment IRQ counter
; --
st0 #5 ; update display control (bg/sp)
lda <vdc_crl
sta video_data_l
; --
bbs5 <irq_m,.l3
; --
jsr _vsync_hndl
; --
.l3: bbr4 <irq_m,.l4
jsr user_vsync ; call user vsync routine
.l4:
; ----
; hsync interrupt
;
.hsync:
bbr2 <vdc_sr,.exit
bbs7 <irq_m,.l5
; --
jsr _hsync_hndl
; --
.l5: bbr6 <irq_m,.exit
jsr user_hsync ; call user handler
; ----
; exit interrupt
;
.exit:
lda <vdc_reg ; restore VDC register index
sta video_reg
; --
ply
plx
pla
rti
; ----
; user routine hooks
;
user_irq1:
jmp [irq1_jmp]
user_hsync:
jmp [hsync_hook]
user_vsync:
jmp [vsync_hook]
.endif ; !(CDROM)
; ----
; _vsync_hndl
; ----
; Handle VSYNC interrupts
; ----
_vsync_hndl:
.if !(CDROM)
ldx disp_cr ; check display state (on/off)
bne .l1
and #$3F ; disable display
st0 #5 ; update display control (bg/sp)
sta video_data_l
bra .l2
; --
.endif
.l1: jsr rcr_init ; init display list
.l2: st0 #7 ; scrolling
stw bg_x1,video_data
st0 #8
stw bg_y1,video_data
; --
lda clock_tt ; keep track of time
inc A
cmp #60
bne .lcltt
lda clock_ss
inc A
cmp #60
bne .lclss
lda clock_mm
inc A
cmp #60
bne .lclmm
inc clock_hh
cla
.lclmm: sta clock_mm
cla
.lclss: sta clock_ss
cla
.lcltt: sta clock_tt
; --
.if (CDROM)
jsr ex_colorcmd
inc rndseed
jsr randomize
lda <$e7
cmp #$01
bne .skip_psg
jsr psg_driver
.skip_psg:
.endif
.ifdef SUPPORT_MOUSE
lda msflag ; if mouse supported, and exists
beq .l3 ; then read mouse instead of pad
jsr mousread
bra .out
.endif ; SUPPORT_MOUSE
.l3: jsr read_joypad ; else read joypad
.out: rts
; ----
; _hsync_hndl
; ----
; Handle HSYNC interrupts
; ----
; ----
; hsync scrolling handler
;
_hsync_hndl:
ldy s_idx
bpl .r1
; --
lda <vdc_crl
and #$3F
sta <vdc_crl
stz s_idx
ldx s_list
lda s_top,X
jsr rcr5
rts
; --
.r1: ldx s_list,Y
lda <vdc_crl
and #$3F
ora s_cr,X
sta <vdc_crl
; --
jsr rcr_set
; --
lda s_top,X
cmp #$FF
beq .out
; --
st0 #7
lda s_xl,X
ldy s_xh,X
sta video_data_l
sty video_data_h
st0 #8
lda s_yl,X
ldy s_yh,X
sub #1
bcs .r2
dey
.r2: sta video_data_l
sty video_data_h
.out: rts
; ----
; init display list
;
rcr_init:
maplibfunc build_disp_list
bcs .r3
rts
; --
.r3: smb #7,<vdc_crl
lda #$FF
sta s_idx
ldx s_list
ldy s_top,X
cpy #$FF
bne rcr5
; --
ldy s_xl,X
sty bg_x1
ldy s_xh,X
sty bg_x1+1
ldy s_yl,X
sty bg_y1
ldy s_yh,X
sty bg_y1+1
stz s_idx
bra rcr5
; ----
; program scanline interrupt
;
rcr_set:
iny
sty s_idx
lda s_list,Y
tay
lda s_top,Y
cmp scr_height
bhs rcr6
cmp s_bottom,X
blo rcr5
; --
lda s_bottom,X
rcr4: dec A
pha
lda #$F0
sta s_bottom,X
stz s_cr,X
dec s_idx
pla
; --
rcr5: st0 #6 ; set scanline counter
add #64
sta video_data_l
cla
adc #0
sta video_data_h
bra __rcr_on
;--
rcr6: lda s_bottom,X
cmp scr_height
blo rcr4
bra __rcr_off
; ----
; rcr_on
; ----
; enable scanline interrupt
; ----
rcr_on:
_rcr_on:
lda #5
sta <vdc_reg
__rcr_on:
st0 #5
lda <vdc_crl
ora #$04
sta <vdc_crl
sta video_data_l
rts
; ----
; rcr_off
; ----
; disable scanline interrupt
; ----
rcr_off:
_rcr_off:
lda #5
sta <vdc_reg
__rcr_off:
st0 #5
lda <vdc_crl
and #$FB
sta <vdc_crl
sta video_data_l
rts
; ----
; timer
; ----
; timer interrupt handler
; ----
.if !(CDROM)
_timer_user:
jmp [timer_jmp]
_timer:
bbs2 <irq_m,_timer_user
pha
phx
phy
sta irq_status ; acknowledge interrupt
lda <psg_irqflag ; is IRQ being serviced ?
bne .exit
inc <psg_irqflag ; IRQ being serviced
cli ; but allow other interrupts to be processed
lda <psg_inhibit ; if sound off, don't bother
bne .exit2
bsr psg_driver ; do all sound-related stuff
.exit2: stz <psg_irqflag ; allow IRQ processing again
.exit: ply
plx
pla
rti
psg_driver:
tma #page(psg_drive) ; map out the code segment
pha
lda #bank(psg_drive)
tam #page(psg_drive)
tma #4 ; save data banks
pha
tma #3
pha
lda psg_bank1 ; map PSG data banks
tam #3
lda psg_bank2
tam #4
jsr psg_drive
lda psg_tempo
bmi .noreset
sta timer_cnt
ora #$80
sta psg_tempo
.noreset:
pla ; restore data banks
tam #3
pla
tam #4
pla
tam #page(psg_drive) ; restore code bank
rts
.endif ; !(CDROM)
; ----
; nmi
; ----
; NMI interrupt handler
; ----
.if !(CDROM)
_nmi:
bbs3 <irq_m,.user
rti
.user:
jmp [nmi_jmp]
.endif ; !(CDROM)
;±±[ DATA ]±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
; ----
; font
; ----
.ifdef HUC
font_table:
.dw font_1
.dw font_2
.dw font_1
.dw font_1
.endif ; HUC
;±±[ LIBRARY ]±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
; ----
; standard library
; ----
.include "library.asm"
.include "scroll.asm"
.include "math.asm"
.ifdef HUC
.include "huc.asm"
.include "huc_gfx.asm"
.include "huc_math.asm"
.include "huc_bram.asm"
.include "huc_misc.asm"
.endif ; HUC
.ifdef SUPPORT_MOUSE
.include "mouse.asm"
.endif ; SUPPORT_MOUSE
.if (CDROM)
.include "cdrom.asm"
.else
.include "sound.asm"
.endif ; CDROM
; ----
; disp_on
; ----
; enable display
; ----
.ifdef HUC
_disp_on:
ldx disp_cr
lda #1
sta disp_cr
cla
rts
.else
disp_on:
lda #1
sta disp_cr
rts
.endif ; HUC
; ----
; disp_off
; ----
; disable display
; ----
.ifdef HUC
_disp_off:
ldx disp_cr
stz disp_cr
cla
rts
.else
disp_off:
stz disp_cr
rts
.endif ; HUC
; ----
; set_intvec
; ----
; set interrupt vector
; ----
; IN : A = vector number
; 0 IRQ2
; 1 IRQ1 (VDC)
; 2 TIMER
; 3 NMI
; 4 VSYNC
; 5 HSYNC
; 6 SOFT RESET (RUN + SELECT)
; X = vector address low byte
; Y = " " high byte
; ----
.if !(CDROM)
set_intvec:
php
sei
cmp #6
blo .vector
bne .exit
.reset:
stx soft_reset
sty soft_reset+1
bra .exit
.vector:
pha
asl A
sax
sta user_jmptbl,X
inx
tya
sta user_jmptbl,X
pla
.exit:
plp
rts
.endif ; !(CDROM)
; ----
; wait_vsync
; ----
; wait the next vsync
; ----
; IN : A = number of frames to be sync'ed on
; ----
; OUT: A = number of elapsed frames since last call
; ----
wait_vsync:
bbr1 <irq_m,.l1
cla ; return immediately if IRQ1 is redirected
.ifdef HUC
clx
.endif
rts
.l1: sei ; disable interrupts
cmp irq_cnt ; calculate how many frames to wait
beq .l2
bhs .l3
lda irq_cnt
.l2: inc A
.l3: sub irq_cnt
sta vsync_cnt
cli ; re-enable interrupts
.l4: lda irq_cnt ; wait loop
.l5: incw _rndseed
cmp irq_cnt
beq .l5
dec vsync_cnt
bne .l4
stz irq_cnt ; reset system interrupt counter
inc A ; return number of elapsed frames
.ifndef HUC
rts
.else
; ----
; callback support
pha
lda joycallback ; callback valid?
bpl .t3
bit #$01
bne .t3
lda joycallback+1 ; get events for all the
beq .t3 ; selected joypads
sta <_al
cly
cla
.t1: lsr <_al
bcc .t2
ora joybuf,Y
.t2: iny
cpy #5
blo .t1
and joycallback+2 ; compare with requested state
beq .t3
inc joycallback ; lock callback feature
tax ; call user routine
tma #5
pha
lda joycallback+3
tam #5
cla
jsr .callback
pla
tam #5
dec joycallback ; unlock
; --
.t3: plx
cla
rts
; ----
; user routine callback
;
.callback:
jmp [joycallback+4]
.endif ; ndef HUC
.include "joypad.asm" ; read joypad values
;±±[ USER PROGRAM ]±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
; .nomlist
; .list
;...
; .endif