Skip to content
Game 1 Unit 1 of 64 1 hr learning time

Hello Amiga

Your first Amiga program. Copper display. Hardware sprite. Custom chipset in action.

2% of Signal

What You’re Building

Your first Amiga program. A complete Frogger-style playfield with a hardware sprite frog.

By the end of this unit:

  • A coloured playfield appears on screen
  • A frog sprite sits in the start zone
  • You can change colours and positions
  • You’ve experienced the Amiga’s custom chipset

Unit 1 Screenshot

The Amiga’s Secret Weapon

The Amiga wasn’t just another computer. It had custom silicon—three chips working together to create graphics and sound that seemed impossible in 1985.

Agnus handles memory and timing. It orchestrates everything, making sure graphics data flows at exactly the right moment.

Denise draws the display. Sprites, playfields, colours—all handled by dedicated hardware, not the CPU.

Paula manages sound and some I/O. Four channels of 8-bit audio, hardware-mixed.

This custom chipset is why Amiga games looked and sounded better than anything else at the time. And you’re about to use it.

Run It First

Before we look at any code, get this running.

Step 1: Build the Executable

vasmm68k_mot -Fhunkexe -kick1hunks -o signal signal.asm

This creates signal—an AmigaDOS executable.

Step 2: Create a Bootable Disk

The Amiga boots from floppy disks. We need to create an ADF (Amiga Disk File) image using xdftool (from the amitools package—install with pip install amitools):

# Create and format a blank disk
xdftool signal.adf create
xdftool signal.adf format "Signal"

# Make it bootable with a startup script
xdftool signal.adf makedir s
xdftool signal.adf boot install
echo "signal" > startup-sequence
xdftool signal.adf write startup-sequence s/startup-sequence
rm startup-sequence

# Copy our program to the disk
xdftool signal.adf write signal

Step 3: Run in an Emulator

Use FS-UAE or WinUAE with:

  • Kickstart 1.3 ROM (required—the Amiga’s operating system)
  • A500 configuration (standard Amiga 500)
  • signal.adf in drive DF0:

The emulator will boot from the disk and run your program automatically.

You should see coloured horizontal bands representing the game zones, and a bright green frog in the start area.

To exit: Click the left mouse button. On real hardware, you’ll need to reset—this program takes over the machine completely.

The Playfield

Look at what’s on screen:

  • Green at top — the home zone (where frogs want to reach)
  • Blue bands — the river with wave highlights
  • Green strip — the safe median
  • Grey bands — the road with lane markings
  • Green at bottom — the start zone (where you begin)
  • Black — borders

This is all done with the Copper—a programmable display co-processor that can change colours at specific screen positions. No bitmap required for these solid colour bands.

The Frog

That bright green blob in the start zone? That’s a hardware sprite. The Amiga has eight of them, and we’re using one for the frog.

Hardware sprites are brilliant:

  • The custom chipset draws them automatically
  • They overlay the playfield without affecting it
  • Moving them is just changing a few numbers
  • No need to erase and redraw

Experiment: Change the Values

Open signal.asm and find the TWEAKABLE VALUES section at the top:

FROG_X          equ 160         ; Frog horizontal position (try 64-280)
FROG_Y          equ 180         ; Frog vertical position (try 44-220)

COLOUR_HOME     equ $0080       ; Home zone: green
COLOUR_WATER    equ $0048       ; Water: dark blue
COLOUR_FROG     equ $0f0        ; Frog body: bright green

Try these experiments:

Move the frog:

  • Change FROG_X to 64 (left edge) or 280 (right edge)
  • Change FROG_Y to 100 (puts the frog on the road)

Change colours:

  • COLOUR_WATER equ $0f00 — red water (lava level?)
  • COLOUR_FROG equ $00ff — blue frog
  • COLOUR_HOME equ $0ff0 — yellow home zone

Colours are in $0RGB format—one hex digit each for red, green, blue. Values 0-F (0-15).

Rebuild after each change. See immediate results.

What’s Happening (Preview)

Don’t worry about understanding all the code yet—Unit 3 will break it down. But here’s what the program does:

  1. Takes over the machine — disables the operating system
  2. Sets up the Copper list — tells the hardware what colours to use at each screen position
  3. Positions the sprite — writes the frog’s location to the Copper list
  4. Enables DMA — turns on the custom chipset’s automatic display
  5. Loops forever — the hardware does all the work

The CPU barely does anything once it’s set up. That’s the beauty of the Amiga’s custom chipset—dedicated hardware handles the graphics.

The Code

Here’s the complete scaffold. Skim it now, study it later:

;──────────────────────────────────────────────────────────────
; SIGNAL - A Frogger-style game for the Commodore Amiga
; Unit 1: Hello Amiga
;
; This is your scaffold. Run it, see the frog, change the values.
;──────────────────────────────────────────────────────────────

;══════════════════════════════════════════════════════════════
; TWEAKABLE VALUES - Change these and see what happens!
;══════════════════════════════════════════════════════════════

FROG_X          equ 160         ; Frog horizontal position (try 64-280)
FROG_Y          equ 140         ; Frog vertical position (try 44-220)

; Colours are $0RGB (0-15 for each component)
COLOUR_HOME     equ $0080       ; Home zone: green
COLOUR_WATER    equ $0048       ; Water: dark blue
COLOUR_WAVE     equ $006b       ; Water highlight: lighter blue
COLOUR_MEDIAN   equ $0080       ; Safe median: green
COLOUR_ROAD     equ $0444       ; Road: dark grey
COLOUR_MARKER   equ $0666       ; Road marking: light grey
COLOUR_START    equ $0080       ; Start zone: green
COLOUR_BORDER   equ $0070       ; Border: darker green

; Frog colours (sprite palette: colours 17-19)
COLOUR_FROG     equ $0f0        ; Frog body: bright green (contrasts with dark green zones)
COLOUR_EYES     equ $ff0        ; Frog eyes: yellow
COLOUR_OUTLINE  equ $000        ; Frog outline: black

;══════════════════════════════════════════════════════════════
; HARDWARE REGISTERS
;══════════════════════════════════════════════════════════════

CUSTOM      equ $dff000

; Custom chip register offsets
DMACONR     equ $002
DMACON      equ $096
INTENA      equ $09a
INTREQ      equ $09c
COP1LC      equ $080
COPJMP1     equ $088
VPOSR       equ $004
COLOR00     equ $180
SPR0PTH     equ $120
SPR0PTL     equ $122

;══════════════════════════════════════════════════════════════
; CODE SECTION (in chip RAM for sprites/copper to work)
;══════════════════════════════════════════════════════════════
            section code,code_c

start:
            lea     CUSTOM,a5           ; Custom chip base in A5

            ; --- Take over the machine ---
            move.w  #$7fff,INTENA(a5)   ; Disable all interrupts
            move.w  #$7fff,INTREQ(a5)   ; Clear pending interrupts
            move.w  #$7fff,DMACON(a5)   ; Disable all DMA

            ; --- Set sprite pointer in copper list ---
            lea     frog_data,a0        ; A0 = sprite data address
            move.l  a0,d0               ; D0 = sprite data address
            swap    d0                  ; High word first
            lea     sprpth_val,a1
            move.w  d0,(a1)             ; Write high word
            swap    d0                  ; Low word
            lea     sprptl_val,a1
            move.w  d0,(a1)             ; Write low word

            ; --- Install copper list ---
            lea     copperlist,a0
            move.l  a0,COP1LC(a5)       ; Point copper at our list
            move.w  d0,COPJMP1(a5)      ; Strobe to start copper

            ; --- Enable DMA ---
            move.w  #$83a0,DMACON(a5)   ; Master + copper + sprites (+ bitplanes)

            ; === Main Loop ===
mainloop:
            ; Wait for vertical blank
            move.l  #$1ff00,d1
.vbwait:
            move.l  VPOSR(a5),d0
            and.l   d1,d0
            bne.s   .vbwait

            ; Check left mouse button (run until reset)
            btst    #6,$bfe001
            bne.s   mainloop

            ; Button pressed - loop forever (machine takeover, reset to exit)
            bra.s   mainloop

;══════════════════════════════════════════════════════════════
; CHIP RAM DATA (copper list and sprites - same section as code)
;══════════════════════════════════════════════════════════════

copperlist:
            dc.w    COLOR00,$0000       ; Black border at top

            ; --- Sprite 0 palette (colours 17-19) ---
            dc.w    $01a2,COLOUR_FROG   ; Colour 17: body
            dc.w    $01a4,COLOUR_EYES   ; Colour 18: eyes
            dc.w    $01a6,COLOUR_OUTLINE ; Colour 19: outline

            ; --- Sprite 0 pointer (filled by CPU) ---
            dc.w    SPR0PTH             ; SPR0PTH register
sprpth_val: dc.w    $0000               ; High word (patched by code)
            dc.w    SPR0PTL             ; SPR0PTL register
sprptl_val: dc.w    $0000               ; Low word (patched by code)

            ; === HOME ZONE ===
            dc.w    $2c07,$fffe
            dc.w    COLOR00,COLOUR_HOME

            ; === WATER ZONE (5 lanes) ===
            dc.w    $4007,$fffe
            dc.w    COLOR00,COLOUR_WATER    ; Lane 1

            dc.w    $4c07,$fffe
            dc.w    COLOR00,COLOUR_WAVE     ; Wave highlight

            dc.w    $5407,$fffe
            dc.w    COLOR00,COLOUR_WATER    ; Lane 2

            dc.w    $5c07,$fffe
            dc.w    COLOR00,COLOUR_WAVE     ; Wave highlight

            dc.w    $6407,$fffe
            dc.w    COLOR00,COLOUR_WATER    ; Lane 3

            ; === MEDIAN (safe zone) ===
            dc.w    $6c07,$fffe
            dc.w    COLOR00,COLOUR_MEDIAN

            ; === ROAD ZONE (4 lanes) ===
            dc.w    $7807,$fffe
            dc.w    COLOR00,COLOUR_ROAD     ; Lane 1

            dc.w    $8407,$fffe
            dc.w    COLOR00,COLOUR_MARKER   ; Road marking

            dc.w    $8807,$fffe
            dc.w    COLOR00,COLOUR_ROAD     ; Lane 2

            dc.w    $9407,$fffe
            dc.w    COLOR00,COLOUR_MARKER   ; Road marking

            dc.w    $9807,$fffe
            dc.w    COLOR00,COLOUR_ROAD     ; Lane 3

            dc.w    $a407,$fffe
            dc.w    COLOR00,COLOUR_MARKER   ; Road marking

            dc.w    $a807,$fffe
            dc.w    COLOR00,COLOUR_ROAD     ; Lane 4

            ; === START ZONE ===
            dc.w    $b407,$fffe
            dc.w    COLOR00,COLOUR_START

            dc.w    $c007,$fffe
            dc.w    COLOR00,COLOUR_BORDER   ; Bottom border

            ; === BOTTOM ===
            dc.w    $f007,$fffe
            dc.w    COLOR00,$0000           ; Black

            ; End of copper list
            dc.w    $ffff,$fffe

;──────────────────────────────────────────────────────────────
; SPRITE DATA
;──────────────────────────────────────────────────────────────
            even
frog_data:
            ; Control words: Y=180 ($B4), X=160/2=80 ($50)
            dc.w    $b450               ; VSTART<<8 | HSTART
            dc.w    $c400               ; VSTOP<<8 | control bits

            ; 16 lines of sprite data (plane0, plane1)
            ; Colours: 00=transparent, 01=green, 10=yellow, 11=black
            dc.w    $0000,$0000         ; ................
            dc.w    $07e0,$0000         ; .....XXXXXX.....
            dc.w    $1ff8,$0420         ; ...XXXXXXXXXX...
            dc.w    $3ffc,$0a50         ; ..XXXXXXXXXXXX..
            dc.w    $7ffe,$1248         ; .XXXXXXXXXXXXXX.
            dc.w    $7ffe,$1008         ; .XXXXXXXXXXXXXX.
            dc.w    $ffff,$2004         ; XXXXXXXXXXXXXXXX
            dc.w    $ffff,$0000         ; XXXXXXXXXXXXXXXX
            dc.w    $ffff,$0000         ; XXXXXXXXXXXXXXXX
            dc.w    $7ffe,$2004         ; .XXXXXXXXXXXXXX.
            dc.w    $7ffe,$1008         ; .XXXXXXXXXXXXXX.
            dc.w    $3ffc,$0810         ; ..XXXXXXXXXXXX..
            dc.w    $1ff8,$0420         ; ...XXXXXXXXXX...
            dc.w    $07e0,$0000         ; .....XXXXXX.....
            dc.w    $0000,$0000         ; ................
            dc.w    $0000,$0000         ; ................

            ; End marker (required for hardware)
            dc.w    $0000,$0000

Build It

vasmm68k_mot -Fhunkexe -kick1hunks -o signal signal.asm

The -kick1hunks flag ensures compatibility with Kickstart 1.x (the A500’s operating system).

Key Takeaways

  • The Amiga has custom chips (Agnus, Denise, Paula) that handle graphics and sound
  • The Copper can change display settings mid-screen
  • Hardware sprites are drawn automatically by the chipset
  • Colours use $0RGB format (4 bits per component)
  • Once set up, the CPU does almost nothing—the hardware runs the show

What’s Next

In Unit 2, we’ll read the joystick and move the frog around the screen. The custom chipset handles the display—now let’s add interactivity.