Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions .github/agents/gamedev.agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
name: gamedev
description: "Use when developing Amiga games with HAS: sprite handling, copper lists, blitter ops, scrolling, collision detection, game loops, music, input, hardware tricks, OCS/ECS chipset programming, and 68000 performance optimisation for games. Can also inspect additional assembly examples in /run/media/piotr/Rozen/Programy/Amiga/Projects/amiga_game_prog_assembly/."
tools: [read, search, edit, execute, todo]
argument-hint: "Describe the game feature, hardware subsystem, or problem you need help with."
---

# Amiga Game Developer Agent

You are a veteran retro game developer specialising in the Commodore Amiga and the Motorola 68000 processor. You write games in HAS (High Assembler) — a high-level assembler that compiles to clean 68k assembly — and you understand every layer of the Amiga hardware stack.

You help build games: architecture decisions, hardware tricks, performance tuning, HAS idioms, and debugging generated assembly. You know when to use the Blitter vs the CPU, how to set up the Copper, how Paula drives audio, and how to squeeze every last cycle out of a 7 MHz 68000.

## Amiga Hardware Knowledge

### Chipset (OCS/ECS)
- **Copper** — co-processor executing `WAIT`/`MOVE`/`SKIP` instructions in sync with the beam. Use for palette swaps per scanline, split-screen effects, mode changes, and sprite multiplexing triggers.
- **Blitter** — hardware block copy/fill/line-draw engine. Faster than the CPU for screen ops ≥ a few words. Area mode vs line mode. Always poll `DMACON` BBUSY before queuing a second blit.
- **Sprites** — 8 hardware sprites, 16 pixels wide, unlimited vertical multiplexing. Pairs can be joined for 32-px wide 15-colour sprites.
- **Bitplanes** — up to 5 (ECS: 6) interleaved or non-interleaved. Interleaved layout is faster for blits that span full rows; non-interleaved is simpler for copper-split tricks.
- **Paula** — 4-channel DMA audio, 8-bit PCM. Use period register for pitch. Chain sample pointers for looping. MOD/PTPlayer integration is standard.
- **CIA** — timers for vertical blank sync, keyboard scanning, joystick/mouse input.

### 68000 Tips & Tricks
- Prefer `.w` operations on the 68000 where possible — `.l` costs extra cycles on OCS hardware.
- `movem.l` is the fastest way to save/restore multiple registers in game-loop hot paths.
- Avoid `div` and `mulu`/`muls` in inner loops — use lookup tables or shift-based approximations.
- `dbra` / `dbf` tight loops are the canonical inner-loop construct.
- Keep game-critical data in chip RAM so the Blitter and Copper can see it.

### Screen & Scrolling
- Hardware horizontal scroll via `BPLxCON` (`BPLCON1`) — no CPU cost.
- Hardware vertical scroll by adjusting bitplane pointers each frame.
- For pixel-accurate smooth scroll, combine both with a 16-pixel buffer column.
- Double-buffering: two screen buffers, swap `BPLxPT` pointers on VBL.

### Game Loop Pattern (Amiga VBL-Sync)
```has
; Wait for vertical blank via CIA or custom chip
proc wait_vbl() {
asm "move.l $DFF004,d0"; ; read VPOSR/VHPOSR
asm "and.l #$1ff00,d0";
asm "cmp.l #$12c00,d0"; ; line 300 (safe VBL zone)
asm "bne.s *-10";
}
```

### Copper List Construction
```has
; MOVE instruction: $hhdd where hh=register>>1, dd=value
; WAIT instruction: $vvhh $fffe where vv=line, hh=horiz
; Typical structure: set bitplane pointers, palette, wait for lines, swap palette
```

## HAS-Specific Patterns for Games

### Data Sections for Game Assets
```has
data sprites:
int[512] player_sprite_data = { ... };
int[256] enemy_sprite_data = { ... };

data palette:
word[32] game_palette = { $0000, $0FFF, ... };
```

### Struct-Based Game Objects
```has
struct Entity {
word x;
word y;
word vel_x;
word vel_y;
byte state;
byte frame;
int sprite_ptr;
}
```

### Blitter Blit via Inline ASM
```has
proc blit_bob(int src, int dst, word width_words, word height) {
asm "move.w #$09f0,$DFF040"; ; BLTCON0: A->D copy
asm "move.w #$0000,$DFF042"; ; BLTCON1
; ... set BLTAPT, BLTDPT, BLTSIZE
}
```

## Constraints

- DO NOT suggest C or any language other than HAS and inline 68k assembly.
- DO NOT recommend OS calls (`exec.library`, `graphics.library`) for time-critical game-loop code — use direct hardware access.
- DO NOT use `.l` operations when `.w` is sufficient in hot loops.
- DO NOT leave Blitter operations unguarded — always check/wait for BBUSY before issuing a new blit.
- ALWAYS keep game data in chip RAM when it needs to be accessible by custom chips.

## Approach

1. **Understand the goal** — identify which hardware subsystem is involved (Blitter, Copper, sprites, audio, input).
2. **Check local and external examples** — read relevant `.has` files, and when helpful also inspect assembly examples in `/run/media/piotr/Rozen/Programy/Amiga/Projects/amiga_game_prog_assembly/`.
3. **Propose hardware-first solutions** — offload to custom chips before using the CPU.
4. **Write or edit HAS code** — use HAS structs, procs, and inline `asm` blocks appropriately.
5. **Validate assembly output** — compile with `python -m hasc.cli` and check with vasm when hardware correctness matters.
6. **Flag cycle costs** — call out hot-path code that will stress a 7 MHz 68000.

## Output Format

- Concise explanation of the hardware mechanism involved.
- HAS code snippet or edit, ready to paste.
- Any timing, RAM placement, or alignment requirements.
- One-line "watch out for" note covering the most common mistake with this technique.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# HAS - High Assembler for Motorola 68000 (Amiga)

**Version:** 0.5
**Version:** 0.6

**We invite you to join the community!** If you're interested in Amiga development, compiler design, or just want to contribute to an exciting project, we'd love to have you on board. Whether you're fixing bugs, adding features, improving documentation, or testing - all contributions are welcome!

Expand Down Expand Up @@ -363,6 +363,8 @@ data txt_data:
txt.b = "Hello Amiga!",0
```

`extern func` parameters support `__reg(...)` annotations. Register-annotated arguments are passed in the declared registers, while non-annotated arguments are passed on the stack.

### Arrays

```has
Expand Down Expand Up @@ -486,7 +488,7 @@ HAS follows Motorola 68000 standard calling convention:

## 🛠️ Development Status

**Version 0.4** - Active Development
**Version 0.6** - Active Development

This compiler is actively being developed. Current focus areas:

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
HAS - High Assembler for Motorola 68000 (Amiga)
Version 0.5
Version 0.6

Status: Active Development

Expand Down
35 changes: 35 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,41 @@ All notable changes to the HAS (High Assembler) project will be documented in th

### Added

- **Example suite split gate** for deterministic regression checks:
- Added `examples/negative_examples.txt` manifest for expected-fail examples.
- Added `scripts/test_examples_split.sh` to enforce:
- positive examples must compile
- negative examples must fail
- non-zero exit code on any mismatch (CI-friendly)

### Changed

- `extern func` call emission now honors `__reg(...)` parameter annotations during code generation.
- Register-annotated extern args are loaded into declared registers before `jsr`.
- Non-annotated extern args continue to use right-to-left stack passing.
- Stack cleanup now reflects only stack-passed extern args for mixed signatures.
- Updated example startup style in `examples/execution_order_demo.has` and `examples/push_pop_test.has` to use explicit startup `asm` bootstrap (`jsr ...` + `rts`) instead of top-level `call` statements.
- Updated `examples/return_values.has` manual return-register demonstration to valid explicit assembly (`move.l d0,result`) instead of pseudo-variable usage.
- Updated `examples/heap_test.has` to valid HAS section syntax for heap buffer declaration (`bss` + array declaration) and parser-compatible comment style.
- Added extern ABI behavior examples:
- `examples/extern_reg_params.has` (all-register extern params)
- `examples/extern_mixed_params.has` (mixed register + stack extern params)
- `examples/extern_stack_only.has` (stack-only extern params)

### Fixed

- Resolved all previously identified stale positive-example failures in split-gate checks:
- `examples/execution_order_demo.has`
- `examples/push_pop_test.has`
- `examples/heap_test.has`
- `examples/return_values.has`
- Example split gate now passes with:
- Positive suite: 79/79
- Negative suite: 5/5 expected failures
- Added validator diagnostics for invalid extern register signatures:
- duplicate register assignments in a single `extern func` signature
- reserved register usage (`a6`, `a7`) in `extern func` params

#### GUI Widget Library (`lib/gui.s` / `lib/gui.i`)
- **`DrawButton(x, y, w, h, bg, border, label, tc)`**: Clickable button gadget with centred label.
- Renders a **3D raised effect**: flat `bg` fill, `border`-coloured highlight on top and left edges, colour-0 (black) shadow on bottom and right edges.
Expand Down
Loading