; Prog8 definitions for the Neo6502 %option no_symbol_prefixing, ignore_unused neo { &uword NMI_VEC = $FFFA ; 6502 nmi vector, determined by the kernal if banked in &uword RESET_VEC = $FFFC ; 6502 reset vector, determined by the kernal if banked in &uword IRQ_VEC = $FFFE ; 6502 interrupt vector, determined by the kernal if banked in %asminclude "library:neo/neo6502.asm" } sys { ; ------- lowlevel system routines -------- const ubyte target = 7 ; compilation target specifier. 255=virtual, 128=C128, 64=C64, 32=PET, 16=CommanderX16, 8=atari800XL, 7=Neo6502 const ubyte sizeof_bool = 1 const ubyte sizeof_byte = 1 const ubyte sizeof_ubyte = 1 const ubyte sizeof_word = 2 const ubyte sizeof_uword = 2 const ubyte sizeof_float = 0 ; undefined, no floats supported asmsub reset_system() { ; Soft-reset the system back to initial power-on status ; TODO %asm {{ sei jmp (neo.RESET_VEC) }} } sub wait(uword jiffies) { ; --- wait approximately the given number of jiffies (1/60th seconds) ; TODO } asmsub waitvsync() clobbers(A) { ; --- busy wait till the next vsync has occurred (approximately), without depending on custom irq handling. ; TODO %asm {{ nop rts }} } asmsub internal_stringcopy(uword source @R0, uword target @AY) clobbers (A,Y) { ; Called when the compiler wants to assign a string value to another string. %asm {{ sta P8ZP_SCRATCH_W1 sty P8ZP_SCRATCH_W1+1 lda cx16.r0 ldy cx16.r0+1 jmp prog8_lib.strcpy }} } asmsub memcopy(uword source @R0, uword target @R1, uword count @AY) clobbers(A,X,Y) { ; note: only works for NON-OVERLAPPING memory regions! ; note: can't be inlined because is called from asm as well %asm {{ ldx cx16.r0 stx P8ZP_SCRATCH_W1 ; source in ZP ldx cx16.r0+1 stx P8ZP_SCRATCH_W1+1 ldx cx16.r1 stx P8ZP_SCRATCH_W2 ; target in ZP ldx cx16.r1+1 stx P8ZP_SCRATCH_W2+1 cpy #0 bne _longcopy ; copy <= 255 bytes tay bne _copyshort rts ; nothing to copy _copyshort dey beq + - lda (P8ZP_SCRATCH_W1),y sta (P8ZP_SCRATCH_W2),y dey bne - + lda (P8ZP_SCRATCH_W1),y sta (P8ZP_SCRATCH_W2),y rts _longcopy sta P8ZP_SCRATCH_B1 ; lsb(count) = remainder in last page tya tax ; x = num pages (1+) ldy #0 - lda (P8ZP_SCRATCH_W1),y sta (P8ZP_SCRATCH_W2),y iny bne - inc P8ZP_SCRATCH_W1+1 inc P8ZP_SCRATCH_W2+1 dex bne - ldy P8ZP_SCRATCH_B1 bne _copyshort rts }} } asmsub memset(uword mem @R0, uword numbytes @R1, ubyte value @A) clobbers(A,X,Y) { %asm {{ ldy cx16.r0 sty P8ZP_SCRATCH_W1 ldy cx16.r0+1 sty P8ZP_SCRATCH_W1+1 ldx cx16.r1 ldy cx16.r1+1 jmp prog8_lib.memset }} } asmsub memsetw(uword mem @R0, uword numwords @R1, uword value @AY) clobbers(A,X,Y) { %asm {{ ldx cx16.r0 stx P8ZP_SCRATCH_W1 ldx cx16.r0+1 stx P8ZP_SCRATCH_W1+1 ldx cx16.r1 stx P8ZP_SCRATCH_W2 ldx cx16.r1+1 stx P8ZP_SCRATCH_W2+1 jmp prog8_lib.memsetw }} } inline asmsub read_flags() -> ubyte @A { %asm {{ php pla }} } inline asmsub clear_carry() { %asm {{ clc }} } inline asmsub set_carry() { %asm {{ sec }} } inline asmsub clear_irqd() { %asm {{ cli }} } inline asmsub set_irqd() { %asm {{ sei }} } inline asmsub irqsafe_set_irqd() { %asm {{ php sei }} } inline asmsub irqsafe_clear_irqd() { %asm {{ plp }} } sub disable_caseswitch() { ; no-op } sub enable_caseswitch() { ; no-op } asmsub save_prog8_internals() { %asm {{ lda P8ZP_SCRATCH_B1 sta save_SCRATCH_ZPB1 lda P8ZP_SCRATCH_REG sta save_SCRATCH_ZPREG lda P8ZP_SCRATCH_W1 sta save_SCRATCH_ZPWORD1 lda P8ZP_SCRATCH_W1+1 sta save_SCRATCH_ZPWORD1+1 lda P8ZP_SCRATCH_W2 sta save_SCRATCH_ZPWORD2 lda P8ZP_SCRATCH_W2+1 sta save_SCRATCH_ZPWORD2+1 rts save_SCRATCH_ZPB1 .byte 0 save_SCRATCH_ZPREG .byte 0 save_SCRATCH_ZPWORD1 .word 0 save_SCRATCH_ZPWORD2 .word 0 ; !notreached! }} } asmsub restore_prog8_internals() { %asm {{ lda save_prog8_internals.save_SCRATCH_ZPB1 sta P8ZP_SCRATCH_B1 lda save_prog8_internals.save_SCRATCH_ZPREG sta P8ZP_SCRATCH_REG lda save_prog8_internals.save_SCRATCH_ZPWORD1 sta P8ZP_SCRATCH_W1 lda save_prog8_internals.save_SCRATCH_ZPWORD1+1 sta P8ZP_SCRATCH_W1+1 lda save_prog8_internals.save_SCRATCH_ZPWORD2 sta P8ZP_SCRATCH_W2 lda save_prog8_internals.save_SCRATCH_ZPWORD2+1 sta P8ZP_SCRATCH_W2+1 rts }} } asmsub exit(ubyte returnvalue @A) { ; -- immediately exit the program with a return code in the A register %asm {{ sta cleanup_at_exit._exitcode ldx prog8_lib.orig_stackpointer txs jmp cleanup_at_exit }} } asmsub exit2(ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y) { ; -- immediately exit the program with result values in the A, X and Y registers. %asm {{ sta cleanup_at_exit._exitcode stx cleanup_at_exit._exitcodeX sty cleanup_at_exit._exitcodeY ldx prog8_lib.orig_stackpointer txs jmp cleanup_at_exit }} } asmsub exit3(ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y, bool carry @Pc) { ; -- immediately exit the program with result values in the A, X and Y registers, and the Carry flag in the status register. %asm {{ sta cleanup_at_exit._exitcode lda #0 rol a sta cleanup_at_exit._exitcodeCarry stx cleanup_at_exit._exitcodeX sty cleanup_at_exit._exitcodeY ldx prog8_lib.orig_stackpointer txs jmp cleanup_at_exit }} } inline asmsub progend() -> uword @AY { %asm {{ lda #prog8_program_end }} } inline asmsub progstart() -> uword @AY { %asm {{ lda #prog8_program_start }} } inline asmsub push(ubyte value @A) { %asm {{ pha }} } inline asmsub pushw(uword value @AY) { %asm {{ pha tya pha }} } inline asmsub pop() -> ubyte @A { %asm {{ pla }} } inline asmsub popw() -> uword @AY { %asm {{ pla tay pla }} } } cx16 { ; the sixteen virtual 16-bit registers that the CX16 has defined in the zeropage ; the sixteen virtual 16-bit registers in both normal unsigned mode and signed mode (s) &uword r0 = $0002 &uword r1 = $0004 &uword r2 = $0006 &uword r3 = $0008 &uword r4 = $000a &uword r5 = $000c &uword r6 = $000e &uword r7 = $0010 &uword r8 = $0012 &uword r9 = $0014 &uword r10 = $0016 &uword r11 = $0018 &uword r12 = $001a &uword r13 = $001c &uword r14 = $001e &uword r15 = $0020 &word r0s = $0002 &word r1s = $0004 &word r2s = $0006 &word r3s = $0008 &word r4s = $000a &word r5s = $000c &word r6s = $000e &word r7s = $0010 &word r8s = $0012 &word r9s = $0014 &word r10s = $0016 &word r11s = $0018 &word r12s = $001a &word r13s = $001c &word r14s = $001e &word r15s = $0020 &ubyte r0L = $0002 &ubyte r1L = $0004 &ubyte r2L = $0006 &ubyte r3L = $0008 &ubyte r4L = $000a &ubyte r5L = $000c &ubyte r6L = $000e &ubyte r7L = $0010 &ubyte r8L = $0012 &ubyte r9L = $0014 &ubyte r10L = $0016 &ubyte r11L = $0018 &ubyte r12L = $001a &ubyte r13L = $001c &ubyte r14L = $001e &ubyte r15L = $0020 &ubyte r0H = $0003 &ubyte r1H = $0005 &ubyte r2H = $0007 &ubyte r3H = $0009 &ubyte r4H = $000b &ubyte r5H = $000d &ubyte r6H = $000f &ubyte r7H = $0011 &ubyte r8H = $0013 &ubyte r9H = $0015 &ubyte r10H = $0017 &ubyte r11H = $0019 &ubyte r12H = $001b &ubyte r13H = $001d &ubyte r14H = $001f &ubyte r15H = $0021 &byte r0sL = $0002 &byte r1sL = $0004 &byte r2sL = $0006 &byte r3sL = $0008 &byte r4sL = $000a &byte r5sL = $000c &byte r6sL = $000e &byte r7sL = $0010 &byte r8sL = $0012 &byte r9sL = $0014 &byte r10sL = $0016 &byte r11sL = $0018 &byte r12sL = $001a &byte r13sL = $001c &byte r14sL = $001e &byte r15sL = $0020 &byte r0sH = $0003 &byte r1sH = $0005 &byte r2sH = $0007 &byte r3sH = $0009 &byte r4sH = $000b &byte r5sH = $000d &byte r6sH = $000f &byte r7sH = $0011 &byte r8sH = $0013 &byte r9sH = $0015 &byte r10sH = $0017 &byte r11sH = $0019 &byte r12sH = $001b &byte r13sH = $001d &byte r14sH = $001f &byte r15sH = $0021 asmsub save_virtual_registers() clobbers(A,Y) { %asm {{ ldy #31 - lda cx16.r0,y sta _cx16_vreg_storage,y dey bpl - rts _cx16_vreg_storage .word 0,0,0,0,0,0,0,0 .word 0,0,0,0,0,0,0,0 ; !notreached! }} } asmsub restore_virtual_registers() clobbers(A,Y) { %asm {{ ldy #31 - lda save_virtual_registers._cx16_vreg_storage,y sta cx16.r0,y dey bpl - rts }} } sub cpu_is_65816() -> bool { ; Returns true when you have a 65816 cpu, false when it's a 6502. return false } } p8_sys_startup { ; program startup and shutdown machinery. Needs to reside in normal system ram. asmsub init_system() { ; Initializes the machine to a sane starting state. ; Called automatically by the loader program logic. %asm {{ sei cld clc ; TODO reset screen mode etc etc? clv ; TODO what about IRQ handler? cli rts }} } asmsub init_system_phase2() { %asm {{ rts ; no phase 2 steps on the Neo6502 }} } asmsub cleanup_at_exit() { ; executed when the main subroutine does rts %asm {{ _exitcodeCarry = *+1 lda #0 lsr a _exitcode = *+1 lda #0 ; exit code possibly modified in exit() _exitcodeX = *+1 ldx #0 _exitcodeY = *+1 ldy #0 rts }} } }