Close

Methods and Structures

A project log for XiAleste

XiAleste Next is an 8-bit home computer, which is compatible with software for the Amstrad CPC6128 released on 13 June 1985

h2wh2w 02/11/2026 at 16:320 Comments

In bare metal assembly, structures don't exist. There are only addresses and offsets you keep in your head. Add a field at the start — now you get to hunt down every `LD (IX+2)` and turn it into `(IX+4)`. On a good day, you'll only miss a few. The debugger won't care.

We made structures real.

Here's how it works. Define the type:

```lisp
(deftype vec3 (structure)
  ((x int16) 
   (y int16) 
   (z int16))
 (:methods
  (clear () none)))
```

Use it like you mean it:

```lisp
(defmethod clear ((self vec3))
  (rlet ((v :reg ix :source self))
    (zasm 
      (.ld (-> v x) 0)
      (.ld (-> v y) 0)
      (.ld (-> v z) 0))))
```

No magic numbers. The language knows `y` lives at offset 2, and `ix` currently points at the object. Compiler plugs in the right addresses, spits this out:

```
DD 36 00 00 | LD (IX+0), $00
DD 36 02 00 | LD (IX+2), $00
DD 36 04 00 | LD (IX+4), $00
```

**What you actually get:**

- **No offset bookkeeping.** Write `(-> v y)`, compiler handles the math.
- **Errors where they belong.** Typo in field name? Assembly fails right there, not after three hours of debugging.
- **Register independence.** Want `iy` instead of `ix`? Change one line in `rlet`, the whole block retargets.

This isn't about making Z80 look like Lisp. It's about using macros to bridge the gap between how humans think about code and what the CPU actually executes. Names, types, checks — without leaving the metal.

Discussions