Appendix 4 — Built-in Functions
AZM has four built-in functions you can use in any expression: sizeof, offset, LSB and MSB. The assembler evaluates all four entirely at assemble time, so the Z80 sees a plain integer.
sizeof(TypeExpr)
Syntax:
sizeof(TypeName)
sizeof(TypeName[n])sizeof returns the exact packed byte count for a layout type. For a record, that is the sum of its field sizes. For a scalar type, it returns the built-in size. For an array form, it multiplies the element size by the count.
sizeof(byte) ; 1
sizeof(word) ; 2
sizeof(addr) ; 2
; Given: Sprite .type (x .field byte, y .field byte, flags .field byte, ptr .field word)
sizeof(Sprite) ; 5
sizeof(Sprite[16]) ; 80
sizeof(byte[32]) ; 32sizeof(TypeName) in an expression is equivalent to using the type name directly as a .ds size operand. The function form is useful when you need the constant outside a .ds context, or when the name alone would be ambiguous:
SPRITE_SIZE .equ sizeof(Sprite)
TOTAL_BYTES .equ MAX_COUNT * sizeof(Sprite) + sizeof(Header)The full layout system, including how records and unions define their sizes, is covered in Chapter 5.
offset(TypeExpr, path)
Syntax:
offset(TypeName, fieldName)
offset(TypeName, outerField.innerField)
offset(TypeName[n], [index].fieldName)
offset(TypeName[n], [index].outerField.innerField)offset returns the byte distance from the start of a type to the named field.
Sprite .type
x .field byte ; offset 0
y .field byte ; offset 1
flags .field byte ; offset 2
ptr .field word ; offset 3
.endtype
offset(Sprite, x) ; 0
offset(Sprite, y) ; 1
offset(Sprite, flags) ; 2
offset(Sprite, ptr) ; 3
offset(Sprite[16], [3].flags) ; offset of flags field in element 3Dot paths reach through nested record fields:
Actor .type
pos .field Sprite ; offsets 0-4
state .field byte ; offset 5
.endtype
offset(Actor, pos.x) ; 0
offset(Actor, pos.y) ; 1
offset(Actor, state) ; 5An index step in an offset path must be a numeric literal, and it must be the first step, applied to an array type expression. offset(Sprite[16], [3].flags) is valid; offset(Table, rows[0].x) is a parse error, because the path parser splits on . and takes its bracket at the start. Reach an array-valued field with a layout cast (Chapter 5) instead; layout-cast path expressions accept assembler-time constant expressions in index positions.
LSB(expr) and MSB(expr)
Syntax:
LSB(expression)
MSB(expression)LSB and MSB are acronyms (Least Significant Byte and Most Significant Byte) and are written in uppercase.
LSB(expr) returns the low byte of the value:
LSB(value) = value & $FFMSB(expr) returns the high byte:
MSB(value) = (value >> 8) & $FFA common use is splitting a 16-bit address or constant into its two bytes, either for loading into a register pair or for embedding in a data table:
TARGET .equ $C432
ld a, MSB(TARGET) ; A = $C4
ld h, a
ld a, LSB(TARGET) ; A = $32
ld l, a
; HL now holds $C432
; Stored as a little-endian address pair in a jump table:
JumpTable:
.db LSB(routine_a), MSB(routine_a)
.db LSB(routine_b), MSB(routine_b)
.db LSB(routine_c), MSB(routine_c)Source ported from assemblers that used LOW() or HIGH() requires the AZM names LSB and MSB.
Case sensitivity
All four functions are case-sensitive. SIZEOF, Sizeof, Offset, lsb and msb are parse errors.