// ================================================ // // antic_nmien = $40 // // %01000000 $40 VBI // %10000000 $80 DLI // %11000000 $c0 VBI + DLI // // ================================================ // // pia_portb = $fe // // PORTB_BASIC_OFF + PORTB_SELFTEST_OFF + %01111100 // // PORTB_SELFTEST_OFF = %10000000; portb bit value to turn Self-Test off // PORTB_BASIC_OFF = %00000010; portb bit value to turn Basic off // PORTB_SYSTEM_ON = %00000001; portb bit value to turn System on // // ================================================ // // Now the routine that lets you get to // the RAM that is under the OS. // There are actually 2 memory areas // present: // 4K at $C000 to $CFFF, 49152 to 53247 // 10K at $D800 to $FFFF, 55296 to 65535 // // The last 6 bytes of the 10K area are not // usable, since that is where the interrupt // routines are located. Therefore do not // use any RAM above $FFF9 (65529) or you // will crash the system. // // ================================================ byte nmien = $c0 byte rti @ $15 // default routine for VBI & DLI word vbivec @ $10 // vector for VBI word vdslst @ $16 // vector for DLI // simple display list; LMS = $e000 const array(byte) dl align(32) = [ $70,$70,$70, $42,$00,$e0,2,2,$f0,2,2,2,$f0,2,2,2, $41,@word[dl.addr] ] // init procedure void system_off(){ asm { sei } // turn off IRQ antic_nmien = 0 // turn off NMI pia_portb = $fe // turn off ROM rti = $40 // set RTI opcode vbivec = rti.addr // set address for VBI routine vdslst = rti.addr // set address for DLI routine os_NMIVEC = nmi.addr // set address for custom NMI handler antic_nmien = nmien } // custom NMI handler asm void nmi(){ bit antic_nmist // test nmist bpl .vblclock // if 7-bit not set handle VBI jmp (vdslst) // indirect jump to DLI routine .vblclock: // RTCLOK maintainer inc os_RTCLOK.b2 bne .tickend inc os_RTCLOK.b1 bne .tickend inc os_RTCLOK.b0 .tickend: jmp (vbivec) // indirect jump to VBI routine } // example dli interrupt asm void dli_first(){ pha lda #$2a sta gtia_colpf2 sta antic_wsync lda #dli_second.addr sta vdslst.hi pla rti } // example dli interrupt void dli_second(){ gtia_colpf2 = $de antic_wsync = $de vdslst = dli_first.addr } // wait for VBLANK asm void pause() { lda os_RTCLOK.b2 .rt_check: cmp os_RTCLOK.b2 beq .rt_check rts } // wait 0-255 frames noinline asm void wait(byte register(a) f) { clc adc os_RTCLOK.b2 .rt_check: cmp os_RTCLOK.b2 bne .rt_check rts } // example vbi interrupt void vbi(){ gtia_colpf2 = os_RTCLOK.b2 } // main procedure void main(){ system_off() // turn off OS wait(100) // waint 2 sec on PAL for fun antic_dlist = dl.addr // set custom display list wait(100) // waint 2 sec on PAL for the lulz vbivec = vbi.addr // set custom VBI wait(100) // waint 2 sec on PAL because we can vdslst = dli_first.addr // set custom DLI while(true){ wait(100) nmien ^= %10000000 // toggle DLI antic_nmien = nmien } }