Skip to content

Instantly share code, notes, and snippets.

@Muzza
Last active December 5, 2019 21:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Muzza/4d94f5fcaac135f1da532488a78d5c3a to your computer and use it in GitHub Desktop.
Save Muzza/4d94f5fcaac135f1da532488a78d5c3a to your computer and use it in GitHub Desktop.
Amiga ASM example. Works on emulator, not real HW
; 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