Picked apart from http://stingray.untergrund.net/MiniStartup.s
graph TD open_gfx[Open the Graphics library] get_current_view[Get the current ActiView] load_view_null[LoadView NULL] waittof_twice[WaitTOF twice] store_old_copperlists[Store old Copperlists] get_cpu_type[Get CPU Type] 68010_or_above{68010 or above?} get_010_vector_base_register[Get 010 Vector Base Register] return_0_for_vector_base_register[Return 0 for Vector Base Register] store_old_registers[Store old custom chip registers -- ADKCON, INTENA, DMA] wait_for_raster[Wait for end of raster beam] disable_and_clear_registers[Disable and clear registers -- Interrupts, DMA, INTREQ] install_custom_vertical_blank_interrupt_handler[Install custom vertical blank interrupt handler] set_up_new_dma_interrupts[Set up new DMA and interrupts] open_gfx --> get_current_view --> load_view_null --> waittof_twice waittof_twice --> store_old_copperlists --> get_cpu_type --> 68010_or_above 68010_or_above -- yes --> get_010_vector_base_register 68010_or_above -- no --> return_0_for_vector_base_register get_010_vector_base_register --> store_old_registers return_0_for_vector_base_register --> store_old_registers --> wait_for_raster --> disable_and_clear_registers --> install_custom_vertical_blank_interrupt_handler --> set_up_new_dma_interrupts
clear_custom_vertical_blank_interrupt_store[Clear custom vertical blank interrupt store] wait_for_raster[Wait for raster] restore_interrupts_dma[Restore Interrupts and DMA] restore_vertical_blank_interrupt_handler[Restore vertical blank interrupt handler] restore_copperlists[Restore copperlists] start_old_copperlist[Start old copperlist] restore_registers[Restore registers -- Interrupts, DMA, ADK] restore_viewport[Restore viewport] close_graphics[Close graphics library]
You need to own the machine if you want to hit the custom chips directly. This requires:
OpenLibrary MACRO MOVE.L $4,A6 MOVE.L #\1,A1 MOVE.L #\2,D0 CALLLIB _LVOOpenLibrary ENDM INCLUDE "graphics/gfxbase.i" INCLUDE "graphics_lvo.i" ; requires fd2pragma to create INCLUDE "exec/exec_lib.i" ; preserve registers code is below PreserveViewAndCopperList: OpenLibrary GraphicsLibrary,0 MOVE.L D0,GraphicsBase MOVE.L D0,A6 MOVE.L gb_ActiView(A6),OldView MOVE.L gb_copinit(A6),OldCopper TakeOwnership: MOVE.L #0,A1 CALLLIB _LVOLoadView ; nuke the view CALLLIB _LVOWaitTOF ; wait two vertical blanks CALLLIB _LVOWaitTOF CALLLIB _LVOOwnBlitter CALLLIB _LVOWaitBlit ; wait... MOVE.L $4,A6 CALLLIB _LVOForbid ; the system is ours CNOP 0,4 OldView dc.l 0 OldCopper dc.l 0 GraphicsBase dc.l 0 CNOP 0,4 GraphicsLibrary GRAPHICSNAME
Based on https://github.com/weiju/amiga_hardware_in_c/blob/master/episode-004/example_04.c
#include <clib/exec_protos.h> #include <clib/intuition_protos.h> #include <clib/graphics_protos.h> #include <graphics/gfxbase.h> #include <hardware/custom.h> extern struct GfxBase *GfxBase; extern far struct Custom custom; int main(void) { struct View *OldView = ((struct GfxBase *)GfxBase)->ActiView; ULONG OldCopper = (ULONG)((struct GfxBase *)GfxBase)->copinit; LoadView(NULL); WaitTOF(); WaitTOF(); OwnBlitter(); WaitBlit(); Forbid(); }
To undo this:
ReturnOwnership: RestoreRegister DMACON RestoreRegister INTENA RestoreRegister INTREQ RestoreRegister ADKCON MOVE.L OldCopper,COP1LC MOVE.L GraphicsBase,A6 MOVE.L OldView,A1 CALLLIB _LVOLoadView ; restore the view CALLLIB _LVOWaitTOF CALLLIB _LVOWaitTOF CALLLIB _LVOWaitBlit CALLLIB _LVODisownBlitter MOVE.L $4,A6 CALLLIB _LVOPermit
int main(void) { custom.cop1lc = OldCopper; LoadView(OldView); WaitTOF(); WaitTOF(); WaitBlit(); DisownBlitter(); Permit(); }
If you're preserving registers:
This is done with:
PreserveRegister MACRO MOVE.W \1R,D0 OR.W #$8000,D0 MOVE.W D0,Old\1 ENDM RestoreRegister MACRO MOVE.W #$7FFF,\1 MOVE.W Old\1,\1 ENDM PreserveRegisters: PreserveRegister DMACON PreserveRegister INTENA PreserveRegister INTREQ PreserveRegister ADKCON ReturnOwnership: RestoreRegister DMACON RestoreRegister INTENA RestoreRegister INTREQ RestoreRegister ADKCON CNOP 0,4 OldDMACON dc.w 0 OldINTENA dc.w 0 OldINTREQ dc.w 0 OldADKCON dc.w 0
int main(void) { UWORD OldDMACON,OldINTENA,OldINTREQ,OldADKCON; OldDMACON = custom.dmaconr | 0x8000; OldINTENA = custom.intenar | 0x8000; OldINTREQ = custom.intreqr | 0x8000; OldADKCON = custom.adkconr | 0x8000; custom.dmacon = 0x7FFF; custom.dmacon = OldDMACON; custom.intena = 0x7FFF; custom.intena = OldINTENA; custom.intreq = 0x7FFF; custom.intreq = OldINTREQ; custom.adkcon = 0x7FFF; custom.adkcon = OldADKCON; }
Use BPLCON1.
INTENA.MASTER EQU %0100000000000000 MOVE.W #%1100000000000000,INTENA MOVE.W #%0011111111111111,INTENA
custom.intena = 0xc000; custom.intena = 0x3fff;
hardware/cia.i
will provide addresses and constants for working with the CIA chips.
Buttons are 1 when up and 0 when pushed.
CIAAPRA EQU $BFE001 Port1Fire EQU 6 Port2Fire EQU 7 WaitForMouse: BTST.B #Port1Fire,CIAAPRA BEQ Done BTST #Port2Fire,CIAAPRA BEQ Done BRA WaitForMouse Done:
#include <hardware/cia.h> extern struct CIA far ciaa,ciab; int main(void) { while ((ciaa.ciaapra >> 6) == 3) {} // both buttons are up. }
It doesn't seem possible to detect the following:
The CIA A SDR value will change to the second key + key down, then to first key + key up when you let go. There's no way to get the final second key up.