Last active
December 5, 2019 21:50
-
-
Save Muzza/4d94f5fcaac135f1da532488a78d5c3a to your computer and use it in GitHub Desktop.
Amiga ASM example. Works on emulator, not real HW
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; when TEST_ME is commented out, the program behaves correctly both in emulation and on a real A1200 | |
; when TEST_ME is uncommented, the program behaves correctly in emulation, but shows a blank screen on a real A1200 | |
;TEST_ME EQU 1 | |
DMACONR EQU $dff002 | |
ADKCONR EQU $dff010 | |
INTENAR EQU $dff01c | |
INTREQR EQU $dff01e | |
DMACON EQU $dff096 | |
ADKCON EQU $dff09e | |
INTENA EQU $dff09a | |
INTREQ EQU $dff09c | |
BPLCON0 EQU $dff100 | |
BPLCON1 EQU $dff102 | |
BPLCON3 EQU $dff106 ; for AGA | |
BPL1MOD EQU $dff108 | |
BPL2MOD EQU $dff10a | |
DIWSTRT EQU $dff08e | |
DIWSTOP EQU $dff090 | |
DDFSTRT EQU $dff092 | |
DDFSTOP EQU $dff094 | |
VPOSR EQU $dff004 | |
COP1LCH EQU $dff080 | |
FMODE EQU $dff1fc | |
BLTCON0 EQU $dff040 | |
BLTCON1 EQU $dff042 | |
BLTAFWM EQU $dff044 | |
BLTALWM EQU $dff046 | |
BLTCPTH EQU $dff048 | |
BLTBPTH EQU $dff04C | |
BLTAPTH EQU $dff050 | |
BLTDPTH EQU $dff054 | |
BLTSIZE EQU $dff058 | |
BLTBMOD EQU $dff062 | |
BLTCMOD EQU $dff060 | |
BLTAMOD EQU $dff064 | |
BLTDMOD EQU $dff066 | |
COLOR0 EQU $dff180 | |
CIAAPRA EQU $bfe001 | |
WINDOWW EQU 320 | |
DISPLAYW EQU 320+16 ; the add 16 is for horiz scrolling | |
PITCH EQU DISPLAYW/8 ; 40=(320bits) 80=640bits wide | |
NBITPLANES EQU 5 | |
TILES_WIDTH EQU 320 | |
TILE_SIZE EQU 16 | |
;----------------------------------------------------------------------------- | |
WAIT_BLITTER: MACRO | |
tst.b DMACONR | |
.1\@ btst #6,DMACONR | |
bne .1\@ | |
ENDM | |
;----------------------------------------------------------------------------- | |
init: | |
; store data in hardwareregisters ORed with $8000 | |
;(bit 15 is a write-set bit when values are written back into the system) | |
move.w DMACONR,d0 | |
or.w #$8000,d0 | |
move.w d0,olddmareq | |
move.w INTENAR,d0 | |
or.w #$8000,d0 | |
move.w d0,oldintena | |
move.w INTREQR,d0 | |
or.w #$8000,d0 | |
move.w d0,oldintreq | |
move.w ADKCONR,d0 | |
or.w #$8000,d0 | |
move.w d0,oldadkcon | |
move.l $4,a6 | |
move.l #gfxname,a1 | |
moveq #0,d0 | |
jsr -552(a6) | |
move.l d0,gfxbase | |
move.l d0,a6 | |
move.l 34(a6),oldview | |
move.l 38(a6),oldcopper | |
move.l #0,a1 | |
jsr -222(a6) ; LoadView | |
jsr -270(a6) ; WaitTOF | |
jsr -270(a6) ; WaitTOF | |
jsr -456(a6) ; OwnBlitter | |
jsr -228(a6) ; WaitBlit | |
move.l $4,a6 | |
jsr -132(a6) ; Forbid | |
move.w #%1000000111000000,DMACON ; DMA set ON, 6:Blitter DMA enable, 7:Copper DMA enable, 8:Bitplane DMA enable, 15:Set/clear control bit | |
move.w #%0000000000111111,DMACON ; DMA set OFF | |
; Disable interrupts - NOTE: do this before setting display registers | |
move.w #%1100000000000000,INTENA ; IRQ set ON | |
move.w #%0011111111111111,INTENA ; IRQ set OFF | |
move.w #$5200,BPLCON0 ; five bitplanes | |
; is AGA | |
jsr isAGA | |
cmp.w #1,d0 | |
beq.w AGASetup | |
bra SkipAGA | |
AGASetup: | |
;for aga machines reset fmode and bplcon3 | |
moveq #0,d0 | |
move.w d0,FMODE | |
move.w d0,BPLCON3 | |
SkipAGA: | |
move.w #$0,BPLCON1 ; horizontal scroll 0 | |
; the modulo specifies the data to skip in bytes, at the END of each line to reach the start of the next line | |
; NOTE: add 2 when using DDFSTRT 0x30 for horiz scrolling | |
move.w #(PITCH*NBITPLANES)-(DISPLAYW/8),BPL1MOD ; odd modulo Line pitch of 160 bytes (4 bitplanes) | |
move.w #(PITCH*NBITPLANES)-(DISPLAYW/8),BPL2MOD ; even modulo | |
; PAL | |
; 320x256 display window | |
move.w #$2c81,DIWSTRT ; DIWSTRT - topleft corner (2c81) | |
move.w #$2cc1,DIWSTOP ; DIWSTOP - bottomright corner (c8d1) | |
move.w #$0030,DDFSTRT ; DDFSTRT Wide will start one word (16 pixels) sooner for scrolling | |
move.w #$00d0,DDFSTOP ; DDFSTOP | |
; palette | |
jsr setpalette | |
move.l #copper,a6 | |
lea bitplanes,a0 | |
; bitplane 0 | |
move.l #PITCH*0,d0 | |
add.l a0,d0 | |
move.w #$00e2,(a6)+ ; LO-bits of start of bitplane (copies lo 15 bits of the address of #bitplanes). moves 00e2 into memory that the a6 address register points to, then increment the pointer a6 | |
move.w d0,(a6)+ ; go into $dff0e2 | |
swap d0 ; swap instruction swaps the 16-bit halves of the 32-bit register so that the low bits become high bits and vice versa | |
move.w #$00e0,(a6)+ ; HI-bits of start of bitplane (copies hi 3 bits of the address of #bitplanes). e0 comes from http://amigadev.elowar.com/read/ADCD_2.1/Hardware_Manual_guide/node0024.html (BPLxPTH) | |
move.w d0,(a6)+ ; go into $dff0e0 | |
; bitplane 1 | |
move.l #PITCH*1,d0 | |
add.l a0,d0 | |
move.w #$00e6,(a6)+ ; LO-bits of start of bitplane | |
move.w d0,(a6)+ ; go into $dff0e6 | |
swap d0 | |
move.w #$00e4,(a6)+ ; HI-bits of start of bitplane | |
move.w d0,(a6)+ ; go into $dff0e4 | |
; bitplane 2 | |
move.l #PITCH*2,d0 | |
add.l a0,d0 | |
move.w #$00ea,(a6)+ ; LO-bits of start of bitplane | |
move.w d0,(a6)+ ; go into $dff0e6 | |
swap d0 | |
move.w #$00e8,(a6)+ ; HI-bits of start of bitplane | |
move.w d0,(a6)+ ; go into $dff0e4 | |
; bitplane 3 | |
move.l #PITCH*3,d0 | |
add.l a0,d0 | |
move.w #$00ee,(a6)+ ; LO-bits of start of bitplane | |
move.w d0,(a6)+ ; go into $dff0e6 | |
swap d0 | |
move.w #$00ec,(a6)+ ; HI-bits of start of bitplane | |
move.w d0,(a6)+ ; go into $dff0e4 | |
; bitplane 4 | |
move.l #PITCH*4,d0 | |
add.l a0,d0 | |
move.w #$00f2,(a6)+ ; LO-bits of start of bitplane | |
move.w d0,(a6)+ ; go into $dff0e6 | |
swap d0 | |
move.w #$00f0,(a6)+ ; HI-bits of start of bitplane | |
move.w d0,(a6)+ ; go into $dff0e4 | |
; end of copperlist | |
move.l #$fffffffe,(a6)+ | |
IFND TEST_ME | |
; set copper list at the start - when we do this the program works | |
move.l #copper,a6 | |
move.l a6,COP1LCH | |
ENDIF | |
mainloop: | |
; set horiz scrolling using BLPCON1 | |
move.l frame,d0 ; copy the frame to d0 | |
and.l #$f,d0 ; AND it with 15 (the max scroll value) | |
move.l d0,d1 ; copy it | |
lsl.l #$04,d1 ; shift the copy 4 bits left | |
or.l d1,d0 ; or them together so we always have identical values for playfield 1 and 2 | |
move.w d0,BPLCON1 ; copy to BLPCON1 to control delay and thus horiz scrolling | |
jsr drawMap | |
; inc frame | |
move.l frame,d1 | |
addq.l #1,d1 | |
move.l d1,frame | |
; if mousebutton/joystick 1 or 2 pressed then exit | |
btst.b #6,CIAAPRA | |
beq exit | |
btst.b #7,CIAAPRA | |
beq exit | |
; Wait for vertical blanking before taking the copper list into use | |
waitVB: | |
move.l VPOSR,d0 | |
and.l #$1ff00,d0 | |
cmp.l #303<<8,d0 ; 300 or 303? | |
bne waitVB | |
IFD TEST_ME | |
; set copper list at the VBLANK - when we do this the program displays a blank screen | |
move.l #copper,a6 | |
move.l a6,COP1LCH | |
ENDIF | |
bra mainloop | |
drawMap: ; Draw the map using the blitter (21x16 tiles) | |
move.l #0,d5 ; Y | |
.loopY: | |
move.l #0,d4 ; X | |
.loopX: | |
move.l d5,d0 ; tile index | |
move.l d4,d2 ; x coord | |
lsl.w #4,d2 ; x*16 | |
move.l d5,d3 ; y coord | |
lsl.w #4,d3 ; y*16 | |
jsr BlitTile16 | |
add.l #1,d4 ; x++ | |
cmp.l #21,d4 | |
bne .loopX ; loop until x=21 | |
add.l #1,d5 ; y++ | |
cmp.l #16,d5 | |
bne .loopY ; loop until y=16 | |
rts | |
exit: | |
; exit gracefully - reverse everything done in init | |
move.w #$7fff,DMACON | |
move.w olddmareq,DMACON | |
move.w #$7fff,INTENA | |
move.w oldintena,INTENA | |
move.w #$7fff,INTREQ | |
move.w oldintreq,INTREQ | |
move.w #$7fff,ADKCON | |
move.w oldadkcon,ADKCON | |
move.l oldcopper,COP1LCH | |
move.l gfxbase,a6 | |
move.l oldview,a1 | |
jsr -222(a6) ; LoadView | |
jsr -270(a6) ; WaitTOF | |
jsr -270(a6) ; WaitTOF | |
jsr -228(a6) ; WaitBlit : wait for Blitter to finish running task (if any) | |
jsr -462(a6) ; DisownBlitter : release Blitter to system | |
move.l $4,a6 | |
jsr -138(a6) ; Permit | |
; end program | |
rts | |
; BlitTile16: d0 (long)=TileIndex [0,1,2..], d2=destX, d3=destY | |
BlitTile16: | |
lsl.w #1,d0 ; mul tile index by 2 (for 16 pixels) | |
add.l #tiles,d0 | |
; calculate dest byte offset | |
muls.w #(PITCH*NBITPLANES),d3 ; mul Y coord by pitch | |
lsr.w #3,d2 ; divide X coord by 8 | |
add.l d2,d3 | |
lea.l bitplanes,a0 | |
add.l a0,d3 | |
WAIT_BLITTER | |
move.l #$09f00000,BLTCON0 ;A->D copy, no shifts, ascending mode (27=UseA,24=UseD,[23-20]=LF - b11110000 meaning whenever A is 1, D outputs 1, when A is 0, D outputs 0) http://amigadev.elowar.com/read/ADCD_2.1/Hardware_Manual_guide/node011C.html | |
move.l #$ffffffff,BLTAFWM ;no masking of first/last word | |
; v2: does all bitplanes in 1 blit operation (max 1024 lines so 128pixels * 8 bitplanes) | |
move.w #TILES_WIDTH/8-(TILE_SIZE/16)*2,BLTAMOD ;A modulo=bytes to skip between lines | |
move.w #PITCH-(TILE_SIZE/16)*2,BLTDMOD ;D modulo, pitch of the output memory | |
move.l d0,BLTAPTH ;source graphic top left corner | |
move.l d3,BLTDPTH ;destination top left corner | |
move.w #TILE_SIZE*64*NBITPLANES+(TILE_SIZE/16),BLTSIZE ;rectangle size, starts blit (*64 shifts the height 6 bits left) | |
rts | |
; http://eab.abime.net/showthread.php?p=934704 | |
; call jsr isAGA d0 will be 1 if so | |
isAGA: | |
move.w $dff07c,d0 | |
moveq #31-1,d2 | |
and.w #$ff,d0 | |
check_loop: | |
move.w $dff07C,d1 | |
and.w #$ff,d1 | |
cmp.b d0,d1 | |
bne.b not_AGA | |
dbf d2,check_loop | |
or.b #$f0,d0 | |
cmp.b #$f8,d0 | |
bne.b not_AGA | |
moveq #1,d0 | |
rts | |
not_AGA: | |
moveq #0,d0 | |
rts | |
; http://coppershade.org/articles/AMIGA/Agnus/Programming_the_Blitter/ | |
; Wait for the Blitter to be ready | |
BlitWait: | |
tst DMACONR ;for compatibility | |
.waitblit: | |
btst #6,DMACONR | |
bne.s .waitblit | |
rts | |
setpalette: | |
move.w #$0000,BPLCON3 ; Set BPLCON3 to write to palette 0, high bits | |
move.w #$0755,COLOR0+0 ; color 0 | |
move.w #$0866,COLOR0+2 ; color 1 | |
move.w #$0533,COLOR0+4 ; color 2 | |
move.w #$0238,COLOR0+6 ; color 3 | |
move.w #$0349,COLOR0+8 ; color 4 | |
move.w #$0127,COLOR0+10 ; color 5 | |
move.w #$0422,COLOR0+12 ; color 6 | |
move.w #$0644,COLOR0+14 ; color 7 | |
move.w #$0024,COLOR0+16 ; color 8 | |
move.w #$0000,COLOR0+18 ; color 9 | |
move.w #$0bbd,COLOR0+20 ; color 10 | |
move.w #$077a,COLOR0+22 ; color 11 | |
move.w #$0ba9,COLOR0+24 ; color 12 | |
move.w #$0543,COLOR0+26 ; color 13 | |
move.w #$0fff,COLOR0+28 ; color 14 | |
move.w #$0b00,COLOR0+30 ; color 15 | |
move.w #$0dcb,COLOR0+32 ; color 16 | |
move.w #$0700,COLOR0+34 ; color 17 | |
move.w #$0987,COLOR0+36 ; color 18 | |
move.w #$0765,COLOR0+38 ; color 19 | |
move.w #$0f20,COLOR0+40 ; color 20 | |
move.w #$06b0,COLOR0+42 ; color 21 | |
move.w #$09f0,COLOR0+44 ; color 22 | |
move.w #$0270,COLOR0+46 ; color 23 | |
move.w #$0f90,COLOR0+48 ; color 24 | |
move.w #$0ff0,COLOR0+50 ; color 25 | |
move.w #$0ec0,COLOR0+52 ; color 26 | |
move.w #$0ba0,COLOR0+54 ; color 27 | |
move.w #$0200,BPLCON3 ; Set BPLCON3 to write to palette 0, low bits | |
move.w #$0000,COLOR0+0 ; color 0 | |
move.w #$0000,COLOR0+2 ; color 1 | |
move.w #$0000,COLOR0+4 ; color 2 | |
move.w #$0000,COLOR0+6 ; color 3 | |
move.w #$0000,COLOR0+8 ; color 4 | |
move.w #$0000,COLOR0+10 ; color 5 | |
move.w #$0000,COLOR0+12 ; color 6 | |
move.w #$0000,COLOR0+14 ; color 7 | |
move.w #$0000,COLOR0+16 ; color 8 | |
move.w #$0000,COLOR0+18 ; color 9 | |
move.w #$0000,COLOR0+20 ; color 10 | |
move.w #$0000,COLOR0+22 ; color 11 | |
move.w #$0000,COLOR0+24 ; color 12 | |
move.w #$0000,COLOR0+26 ; color 13 | |
move.w #$0000,COLOR0+28 ; color 14 | |
move.w #$0000,COLOR0+30 ; color 15 | |
move.w #$0000,COLOR0+32 ; color 16 | |
move.w #$0000,COLOR0+34 ; color 17 | |
move.w #$0000,COLOR0+36 ; color 18 | |
move.w #$0000,COLOR0+38 ; color 19 | |
move.w #$0000,COLOR0+40 ; color 20 | |
move.w #$0000,COLOR0+42 ; color 21 | |
move.w #$0000,COLOR0+44 ; color 22 | |
move.w #$0000,COLOR0+46 ; color 23 | |
move.w #$0000,COLOR0+48 ; color 24 | |
move.w #$0000,COLOR0+50 ; color 25 | |
move.w #$0000,COLOR0+52 ; color 26 | |
move.w #$0000,COLOR0+54 ; color 27 | |
rts | |
; ******************************************************************************* | |
; DATA | |
; ******************************************************************************* | |
; storage for 32-bit addresses and data | |
CNOP 0,4 | |
oldview: dc.l 0 | |
oldcopper: dc.l 0 | |
gfxbase: dc.l 0 | |
frame: dc.l 0 | |
oldsp: dc.l 0 | |
; storage for 16-bit data | |
CNOP 0,4 | |
olddmareq: dc.w 0 | |
oldintreq: dc.w 0 | |
oldintena: dc.w 0 | |
oldadkcon: dc.w 0 | |
CNOP 0,4 | |
gfxname: dc.b 'graphics.library',0 | |
Section ChipRAM,Data_c | |
CNOP 0,8 ; force 4 byte alignment - NOTE: changed to 8, AGA may require 64bit alignment for bitplanes, sprites and copperlists | |
bitplanes: | |
blk.b (DISPLAYW/8)*NBITPLANES*256,0 ; 320x256x8 planes of display data | |
tiles: ; just some random data to represent tile bitmaps | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,1 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,14 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,2 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,3 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,4 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,12 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,5 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,6 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,7 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,8 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,9 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,10 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,4 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,11 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,13 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,15 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,0 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,2 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,3 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,6 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,7 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,5 | |
blk.b (TILE_SIZE/8)*NBITPLANES*TILE_SIZE,8 | |
; datalists aligned to 32-bit | |
CNOP 0,8 ; NOTE: changed to 8, AGA may require 64bit alignment for bitplanes, sprites and copperlists | |
copper: | |
dc.l $ffffffe | |
blk.l 1023,0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment