; Program shell with text console. Included before user code. ; Detect inclusion loops (otherwise ca65 goes crazy) .ifdef SHELL_INC .error "File included twice" .end .endif SHELL_INC = 1 ; ******************************************* Prefix .segment "CODE2" ; Temporary variables that ANY routine might modify, so ; only use them between routine calls. temp = <$A temp2 = <$B temp3 = <$C addr = <$E ; RAM that isn't cleared by init routine nv_ram = $7F0 ; Macros and constants .include "macros.inc" .include "nes.inc" ; Interrupt handlers are wrapped with these .define BEGIN_NMI nmi: .define END_NMI .define BEGIN_IRQ irq: .define END_IRQ ; Set undefined flags to 0, allowing simpler .if statements SET_DEFAULT BUILD_NSF,0 SET_DEFAULT BUILD_MULTI,0 SET_DEFAULT BUILD_DEVCART,0 ; Number of clocks devcart takes to jump to user reset SET_DEFAULT DEVCART_DELAY,0 ; ******************************************* Libraries .include "delay.s" .include "print.s" .include "crc.s" .include "testing.s" .if !BUILD_MULTI .include "serial.s" .endif ; Sets up environment, calls main, then exits with code 0 run_main: ; Initialize libraries jsr init_crc ; Establish consistent environment before ; running main jsr wait_vbl lda #PPUMASK_BG0 sta PPUMASK delay 2370+24 lda #$34 pha lda #0 sta SNDMODE tax tay clc clv plp jsr main ; Default to silent exit if main returns lda #0 ; FALL THROUGH ; Exits program and prints result code if non-zero exit: ; Reset stack ldx #$FF txs ; Disable interrupts sei pha jsr nmi_off pla jmp exit_ ; Reports internal error and exits program internal_error: print_str "Internal error" lda #1 jmp exit .if BUILD_NSF || BUILD_MULTI || BUILD_DEVCART console_init: console_show: console_hide: console_print: console_flush: rts .else .include "console.s" .endif ; ******************************************* Single Test .if !BUILD_MULTI print_char_: jsr console_print jmp serial_write ; Reset handler .ifndef CUSTOM_RESET reset = std_reset .endif .macro init_nes sei cld ldx #$FF txs .if !BUILD_NSF ; Init PPU lda #0 sta PPUCTRL sta PPUMASK .endif ; Clear RAM lda #0 ldx #7 ; last page ldy #@ascii @page: stx addr+1 : lda (addr),y sta PPUDATA iny bne :- inx cpx #>@ascii_end bne @page .pushseg .rodata @ascii: .incbin "ascii.chr" @ascii_end: .popseg .endif jsr console_init jsr serial_init jmp run_main ; Exit handler exit_: ; 0: "" cmp #1 jlt exit2 ; 1: "Failed" bne :+ print_str {newline,"Failed"} jmp exit2 ; n: "Error n" : pha print_str {newline,"Error "} jsr print_dec pla exit2: .if !BUILD_DEVCART ; Be sure output is visible pha print_str {newline,newline,newline} jsr console_show pla ; Report audibly as well jsr beep_bits .else ; Tell host to stop capturing serial lda #$1A jsr serial_write delay_msec 400 .endif ; Clear nv_ram lda #0 ldx #filename sta addr+1 jsr print_str_addr jsr print_newline rts .pushseg .segment "STRINGS" ; Filename terminated with zero byte, or just zero byte ; if filename isn't available. filename: .incbin "ram:rom.nes" .byte 0 .popseg .else print_filename: rts filename: .byte 0 .endif ; User code goes in main code segment .segment "CODE" nop