UTTORI ASM · IN DEVELOPMENT
Expressions and defines
Compute assembly values with defines, operators, functions, and binary directives.
On this page
Try expressions and binary data
Edit the define and arithmetic operands in this raw 6502 example. db emits bytes, while dw emits a little-endian word.
Expected output
SNES behavior
Defines
Defines are textual values prefixed by !:
!Lives = 3
!Message = "READY"
db !Lives
db "!Message"
Supported assignment operators are:
| Operator | Behavior |
|---|---|
= |
Store the value. Pure math-looking values may be folded |
+= |
Append text to the current value |
:= |
Resolve referenced defines before storing |
#= |
Resolve and evaluate as a math expression, then store decimal text |
?= |
Assign only if the define does not already exist |
Remove a define with undef Name, undef !Name, or undef "Name".
Nested define names use braces:
!slot = 2
!value2 = $40
db !{value!slot}
In string data, \!Name emits a literal !Name, while \\ emits one backslash. Defines can expand to comma-separated data lists and can appear in include filenames.
Operators
Higher rows bind more tightly:
| Precedence | Operators | Meaning |
|---|---|---|
| 6 | ** |
exponentiation |
| 5 | *, /, % |
multiply, divide, modulo |
| 4 | +, - |
add, subtract |
| 3 | <<, >>, &, |, ^ |
shifts and bitwise operations |
| 2 | <, >, <=, >=, ==, =, != |
comparisons, returning 0 or 1 |
| 1 | && |
logical AND |
| 0 | || |
logical OR |
Operators at the same level are left-associative. Parentheses override precedence. Division or modulo by zero is an assembly error.
Core Built-In Functions
| Family | Functions |
|---|---|
| Numeric | sqrt, sin, cos, tan, asin/arcsin, acos/arccos, atan/arctan, log, log10, log2, ceil, floor, round |
| Selection | min, max, clamp, safediv, select |
| Logical comparison | not, equal, notequal, less, lessequal, greater, greaterequal, and, or, nand, nor, xor |
| Address helpers | bank(value), offset(from,to), pc(), realbase() |
| Strings and symbols | stringsequal, stringsequalnocase, defined, sizeof, objectsize, datasize, countof, bytesof, startof, endof |
| Files | filesize, getfilestatus, canreadfile1...canreadfile4, canreadfile, readfile1...readfile4 |
File reads are little-endian. readfileN(filename, position[, default]) accepts a fallback for an unavailable range. canreadfile(filename, position, size) handles an arbitrary byte count. getfilestatus() returns the host's status code. The supported fixture treats 0 as present.
SNES Expression Functions
| Function | Current behavior |
|---|---|
snestopc(address) |
Convert a mapped CPU address to a ROM offset |
pctosnes(offset) |
Convert a ROM offset to a preferred mapped CPU address |
canread1...canread4 |
Test a fixed-size range against the base/output image length |
canread(position,size) |
Test an arbitrary range against the base/output image length |
read1...read4 |
Map a logical SNES address and read a little-endian value |
readN(position, default) returns the fallback when the mapped range is unavailable. Without a fallback, reads are disabled until check title appears, matching the plugin's selected compatibility policy:
check title
assert read1($00FFD5) == $20, "Expected LoROM header"
When patching, these functions read baseImage. On a fresh build they read the current output buffer. canread* takes range positions; mapped read* functions take logical addresses. Use the address form required by each function.
User Functions
function lowbyte(value) = value & $FF
function tilebytes(count, bpp) = count * 8 * bpp
db lowbyte($1234)
dw tilebytes(16, 4)
Definitions may continue with backslash-newline. Parameters are substituted into the expression, and a later definition with the same name replaces the earlier one. Functions return numeric expression values.
6502 family behavior
Native Defines
On 65xx.raw, defines are textual values prefixed by !:
!Lives = 3
!Message = "READY"
db !Lives
Supported assignment operators are =, +=, :=, #=, and ?=. undef Name removes a define. Nested names use !{value!slot}. See the SNES defines section for the shared engine.
ca65 Symbols
ca65 targets use := / = symbol assignment rather than ! defines for ordinary constants. .undefine ident removes a symbol. .ifdef / .ifndef test whether a name exists.
Operators
Higher rows bind more tightly:
| Precedence | Operators | Meaning |
|---|---|---|
| 6 | ** |
exponentiation |
| 5 | *, /, % |
multiply, divide, modulo |
| 4 | +, - |
add, subtract |
| 3 | <<, >>, &, |, ^ |
shifts and bitwise operations |
| 2 | <, >, <=, >=, ==, =, !=, <> |
comparisons, returning 0 or 1. <> is ca65 inequality |
| 1 | && |
logical AND |
| 0 | || |
logical OR |
Operators at the same level are left-associative. Parentheses override precedence. Division or modulo by zero is an assembly error.
Core Built-In Functions
Native sources have the shared numeric, selection, logical, address, string, and file helpers documented in the SNES expression section: sqrt, min, bank, defined, filesize, readfile1, and so on.
ca65 Expression Functions
Installed only on ca65-profile targets:
| Function | Current behavior |
|---|---|
lobyte(value) / .lobyte(value) |
value & $FF |
hibyte(value) / .hibyte(value) |
(value >> 8) & $FF |
bankbyte(value) / .bankbyte(value) |
(value >> 16) & $FF |
loword(value) / .loword(value) |
value & $FFFF |
hiword(value) / .hiword(value) |
(value >> 16) & $FFFF |
.defined(name) |
rewritten to defined(name) |
.byte @17, .lobyte($1234), .hibyte($1234), .bankbyte($123456)
.word .loword($12345678), .hiword($12345678)
lda #<Label
lda #>Label
User Functions
Native function name(args) = expression is available on 65xx.raw. ca65 token-list functions (.mid, .left, .match, .xmatch, .concat, .sprintf, …) are not implemented.