So, we have rendered frames of our BoingBall, as described in Part 1. What you want to do next is check if the animation is seamless – that is, if it loops without glitches. Best way is to convert the frames into a .gif or .avi animation (in my experience GIF works better) with your favorite photo / video editor. You will also need to reduce the number of colors of your frames, I used just two colors (white & red) + background. I needed a few tries to get this right:

Once the animation looks good, you need to first decide on what kind of Amiga resolution the animation will be shown – either hires or lores. The difference is that on hires the pixels are not square, but are twice as high as they are long, so you need to ‘squash’ the ball vertically:

Now you need to somehow convert the animation data to be used on the Amiga. You have to remember that contrary to PCs of today which use so called ‘chunky‘ pixels, Amiga uses a planar graphics display, which splits each bit of the pixel data into a separate plane – that allows it to save memory & bandwidth, if for example you only needed two colors you would only require one bit per pixel instead of 8 (or even 16 or 32!).
For the conversion, I wrote a simple Python script which takes a GIF animation, splits it into frames, splits the frames into bitplanes and writes the result into a source file that can be used in AsmOne assembler on the Amiga. The script is attached bellow.
I also made a minimig logo, which you can see below:
![]()
Now comes the fun part – writing a program that will show this animation on the Amiga – or in this case, the Minimig board. We want this animation to work very early in the Minimig bootup, when no operating system is available, actually even the CPU is not available as it is in reset.
Luckily, hitting the hardware registers directly is nothing special on the Amiga as everyone was (is!) doing it, from demo coders (check out the Amiga Demoscene Archive for some amazing demos) to games. The Amiga chipset is quite complex, so I won’t go into too much details about how to set it up. If you want some great tutorials about writing hardware-hitting Amiga software, you might want to check out Photon’s great coding page and Youtube channel, it was certainly a great help for me to freshen up my Amiga coding 😉
So, we have no OS and no CPU, how can we play an animation? Well, the custom chips of the Amiga will help here. Amiga has some very interesting hardware, but for this animation we are interested in two particularly: the Blitter and the Copper. The Blitter’s name comes from Blit, which is short for block image transfer. Simply put, the Blitter is a configurable DMA engine that can transfer images in memory (it is much more capable, but let’s leave it at that). The Copper, short for co-processor, is a very basic processor that only has three commands: MOVE, WAIT and SKIP, but it is also tied to the video beam. Since the Copper can write Blitter’s registers, they together form a sort of a Turing-complete system, certainly capable enough to play back this animation.
Since you don’t want to write this ‘blind’, you need a way to test that everything works while you’re working on it. I used ASMOne, which is a great assembler for the Amiga, and WinUAE, a windows Amiga emulator. Our program is using the CPU to set up the custom chipset, and once set up, the chipset runs by itself. The CPU part will be replaced with custom code on the minimig, since on minimig the control CPU can write custom registers when the CPU is in reset. For the test program, we need a little more setup than is required for minimig, especially saving enabled interrupts and DMAs, which are restored on exit. The CPU must also copy the minimig logo and the boingball animation data to the proper place in chipram, then it enters a loop waiting for the mouse button press, cleans up and exits. The required part is setting up bitplane DMAs, copper, screen, blitter and the color values:
SysSetup: move.w #$0000,$dff1fc ; FMODE, slow fetch mode for AGA compatibility move.w #$0002,$dff02e ; COPCON, enable danger mode move.l #Copper1,$dff080 ; COP1LCH, copper 1 pointer move.l #Copper2,$dff084 ; CPO2LCH, copper 2 pointer move.w #$0000,$dff088 ; COPJMP1, restart copper at location 1 move.w #$2c81,$dff08e ; DIWSTRT, screen upper left corner move.w #$f4c1,$dff090 ; DIWSTOP, screen lower right corner move.w #$003c,$dff092 ; DDFSTRT, display data fetch start move.w #$00d4,$dff094 ; DDFSTOP, display data fetch stop ;move.w #$7fff,$dff096 ; DMACON, disable all DMAs move.w #$87c0,$dff096 ; DMACON, enable important bits move.w #$0000,$dff098 ; CLXCON, TODO move.w #$7fff,$dff09a ; INTENA, disable all interrupts move.w #$7fff,$dff09c ; INTREQ, disable all interrupts move.w #$0000,$dff09e ; ADKCON, TODO move.w #$a200,$dff100 ; BPLCON0, two bitplanes & colorburst enabled move.w #$0000,$dff102 ; BPLCON1, bitplane control scroll value move.w #$0000,$dff104 ; BPLCON2, misc bitplane bits move.w #$0000,$dff106 ; BPLCON3, TODO move.w #$0000,$dff108 ; BPL1MOD, bitplane modulo for odd planes move.w #$0000,$dff10a ; BPL2MOD, bitplane modulo for even planes move.w #$09f0,$dff040 ; BLTCON0 move.w #$0000,$dff042 ; BLTCON1 move.w #$ffff,$dff044 ; BLTAFWM, blitter first word mask for srcA move.w #$ffff,$dff046 ; BLTALWM, blitter last word mask for srcA move.w #$0000,$dff064 ; BLTAMOD move.w #BLITS,$dff066 ; BLTDMOD move.w #$0000,$dff180 ; COLOR00 move.w #$0aaa,$dff182 ; COLOR01 move.w #$0a00,$dff184 ; COLOR02 move.w #$0000,$dff186 ; COLOR03 move.w #(bpl1>>16)&$ffff,$dff0e0 ; BPL1PTH move.w #bpl1&$ffff,$dff0e2 ; BPL1PTL move.w #(bpl2>>16)&$ffff,$dff0e4 ; BPL2PTH move.w #bpl2&$ffff,$dff0e6 ; BPL2PTL
We set up the space for the bitplanes at $80000:
ORG $80000 EVEN Screen: bpl1: dcb.b BPLSIZE bpl1E: bpl2: dcb.b BPLSIZE bpl2E:
Most of the work is done with the copper and blitter. Since the minimig logo is fixed in place, it only needs moving to the proper position in the bitplanes. The rotating ball is also not moving around, so there is no need to clear the bitplanes, we just write new data over the old one. If we want to show the boingball animation with the correct speed, one frame of the animation must be shown for 5 minimig frames (minimig has a refresh rate of 50Hz for PAL). That means quite a long copper list, moving the copper pointer around each frame and the blitter pointer every five frames, since we don’t have a CPU to do any of that. Below is copper code for a single frame of animation, spanning 5 Amiga screen refreshes:
EVEN Copper2: c2f00: dc.w $0050,(f0p0>>16)&$ffff dc.w $0052,(f0p0)&$ffff dc.w $0054,((bpl1+BALLOFF)>>16)&$ffff dc.w $0056,((bpl1+BALLOFF))&$ffff dc.w $0058,(BLITH<<6+BLITW) dc.w $0107,$7ffe dc.w $0050,(f0p1>>16)&$ffff dc.w $0052,(f0p1)&$ffff dc.w $0054,((bpl2+BALLOFF)>>16)&$ffff dc.w $0056,((bpl2+BALLOFF))&$ffff dc.w $0058,(BLITH<<6+BLITW) dc.w $0084,(c2f01>>16)&$ffff dc.w $0086,(c2f01)&$ffff dc.w $ffff,$fffe c2f01: dc.w $0084,(c2f02>>16)&$ffff dc.w $0086,(c2f02)&$ffff dc.w $ffff,$fffe c2f02: dc.w $0084,(c2f03>>16)&$ffff dc.w $0086,(c2f03)&$ffff dc.w $ffff,$fffe c2f03: dc.w $0084,(c2f04>>16)&$ffff dc.w $0086,(c2f04)&$ffff dc.w $ffff,$fffe c2f04: dc.w $0084,(c2f10>>16)&$ffff dc.w $0086,(c2f10)&$ffff dc.w $ffff,$fffe
This code is repeated eight times for each frame of the animation.
So, after these two long posts, does it work at all? It sure does:
Whole AsmOne source code is here:
Be First to Comment