; Storing DMA/interrupt state and restoring it ; ; Written by Harry Sintonen ; ; WARNING ; ; This code does NOT store / restore system display, nor ; does it prevent mouse/keyboard input leaking to the OS ; if various dma/int bits are enabled without care. ; To prevent problems the first part should be using ; https://sintonen.fi/src/hwstartup/hwstartup.asm include "exec/execbase.i" include "hardware/custom.i" include "hardware/intbits.i" include "hardware/dmabits.i" include "hardware/adkbits.i" _LVOSupervisor EQU -30 _LVODisable EQU -120 _LVOEnable EQU -126 _main: move.l (4).w,a6 jsr _LVODisable(a6) btst #AFB_68010,AttnFlags+1(a6) beq.s .is68000 lea .getvbr(pc),a5 jsr _LVOSupervisor(a6) move.l d0,vectorbase .is68000: lea $dff000,a5 move.w #$7fff,d0 move.w intenar(a5),oldintena move.w d0,intena(a5) ; disable all ints move.w intreqr(a5),oldintreq move.w d0,intreq(a5) ; clear all pending ints move.w dmaconr(a5),olddmacon move.w d0,dmacon(a5) ; disable all dma move.w adkconr(a5),oldadkcon move.w d0,adkcon(a5) ; disable all adk addq.w #1,d0 ; d0 = $8000 or.w d0,oldintena or.w d0,oldintreq or.w d0,olddmacon or.w d0,oldadkcon bsr dostuff ; == CLEANUP == move.l (4).w,a6 lea $dff000,a5 ; first disable all ints, then dma/adk and finally ; clear any pending ints move.w #$7fff,d0 move.w d0,intena(a5) move.w d0,dmacon(a5) move.w d0,adkcon(a5) move.w d0,intreq(a5) bsr restoreautovecs ; restore the old state move.w olddmacon(pc),dmacon(a5) move.w oldadkcon(pc),adkcon(a5) move.w oldintreq(pc),intreq(a5) move.w oldintena(pc),intena(a5) jsr _LVOEnable(a6) moveq #0,d0 rts .getvbr: movec vbr,d0 nop rte vectorbase: ds.l 1 oldintena: ds.w 1 oldintreq: ds.w 1 olddmacon: ds.w 1 oldadkcon: ds.w 1 restoreautovecs: ; Here you restore any autovector(s) if you have changed them ; EXAMPLE: Restore level 3 autovector (copper, vertb, blitter) move.l vectorbase(pc),a0 move.l oldlevel3(pc),$6C(a0) rts dostuff: ; Set up autovectors etc ; EXAMPLE: Set new level 3 autovector move.l vectorbase(pc),a0 move.l $6C(a0),oldlevel3 move.l #level3int,$6C(a0) ; Set up display and whatever ; ... ; EXAMPLE: Enable display dma (raster) move.w #$8000|DMAF_MASTER|DMAF_RASTER,dmacon(a5) ; Enable any ints you use ; EXAMPLE: Enable vertical blanking interrupt move.w #$8000|INTF_INTEN|INTF_VERTB,intena(a5) ; EXAMPLE: Just blast some colours to the screen ; while our vertical blanking interrupt is counting ; frames move.l #2000000-1,d0 .lol: move.w d0,color(a5) subq.l #1,d0 bne.s .lol ; Stop the vertical blanking interrupt move.w #INTF_VERTB,intena(a5) rts oldlevel3: ds.l 1 level3int: ; WARNING: Interrupts must save all registers used or bad things ; will happen. You have been warned. ;;ori #$700,sr ; prevent higher level ints (optional) move.l d7,-(sp) move.w $dff000+intreqr,d7 ; Why are we here? btst #INTB_VERTB,d7 ; was this vertical blanking int? beq.s .notvbl ; Silly example, just count frames... addq.l #1,vblcounter .notvbl: ; These cannot happen since we only enable INTF_VERTB IFNE 0 btst #INTB_BLIT,d7 ; blitter interrupt? beq.s .notblit .notblit: btst #INTB_COPER,d7 ; copper interrupt? beq.s .notcop .notcop: ENDC and.w #INTF_VERTB|INTF_BLIT|INTF_COPER,d7 move.w d7,$dff000+intreq ; ACK the interrupt move.w d7,$dff000+intreq ; ... really ... move.l (sp)+,d7 nop rte vblcounter: ds.l 1