mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 02:02:06 +00:00
Compare commits
22 Commits
v0.6.0-rc2
...
race-car2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76c1995559 | ||
|
|
ae84570f04 | ||
|
|
094a31ef8c | ||
|
|
291dcf3b6c | ||
|
|
a890bd072b | ||
|
|
2f6c808ccb | ||
|
|
e80907abd0 | ||
|
|
25d39155d3 | ||
|
|
77021d229b | ||
|
|
1b250b90b2 | ||
|
|
e2b4723489 | ||
|
|
2507413162 | ||
|
|
e023a84d04 | ||
|
|
34c127d9c3 | ||
|
|
9a930988c2 | ||
|
|
8c4204c542 | ||
|
|
663c1930ec | ||
|
|
30ccf43f44 | ||
|
|
fdc17adbcb | ||
|
|
cc196954f3 | ||
|
|
55b6cfff84 | ||
|
|
1fc73b04eb |
122
src/asm/lexer.c
122
src/asm/lexer.c
@@ -163,16 +163,20 @@ static struct KeywordMapping {
|
||||
{"DE", T_MODE_DE},
|
||||
{"HL", T_MODE_HL},
|
||||
{"SP", T_MODE_SP},
|
||||
{"PC", T_MODE_PC},
|
||||
{"HLD", T_MODE_HL_DEC},
|
||||
{"HLI", T_MODE_HL_INC},
|
||||
{"IME", T_MODE_IME},
|
||||
|
||||
{"A", T_TOKEN_A},
|
||||
{"F", T_TOKEN_F},
|
||||
{"B", T_TOKEN_B},
|
||||
{"C", T_TOKEN_C},
|
||||
{"D", T_TOKEN_D},
|
||||
{"E", T_TOKEN_E},
|
||||
{"H", T_TOKEN_H},
|
||||
{"L", T_TOKEN_L},
|
||||
{"W", T_TOKEN_W},
|
||||
|
||||
{"DEF", T_OP_DEF},
|
||||
|
||||
@@ -290,6 +294,7 @@ static struct KeywordMapping {
|
||||
{"OPT", T_POP_OPT},
|
||||
|
||||
{".", T_PERIOD},
|
||||
{"...", T_ELLIPSIS},
|
||||
};
|
||||
|
||||
static bool isWhitespace(int c)
|
||||
@@ -350,6 +355,7 @@ struct LexerState {
|
||||
uint32_t lineNo;
|
||||
uint32_t colNo;
|
||||
int lastToken;
|
||||
int nextToken;
|
||||
|
||||
struct IfStack *ifStack;
|
||||
|
||||
@@ -374,6 +380,7 @@ static void initState(struct LexerState *state)
|
||||
state->mode = LEXER_NORMAL;
|
||||
state->atLineStart = true; /* yylex() will init colNo due to this */
|
||||
state->lastToken = T_EOF;
|
||||
state->nextToken = 0;
|
||||
|
||||
state->ifStack = NULL;
|
||||
|
||||
@@ -586,7 +593,7 @@ struct KeywordDictNode {
|
||||
uint16_t children[0x60 - ' '];
|
||||
struct KeywordMapping const *keyword;
|
||||
/* Since the keyword structure is invariant, the min number of nodes is known at compile time */
|
||||
} keywordDict[351] = {0}; /* Make sure to keep this correct when adding keywords! */
|
||||
} keywordDict[356] = {0}; /* Make sure to keep this correct when adding keywords! */
|
||||
|
||||
/* Convert a char into its index into the dict */
|
||||
static inline uint8_t dictIndex(char c)
|
||||
@@ -1862,6 +1869,14 @@ static int yylex_NORMAL(void)
|
||||
{
|
||||
dbgPrint("Lexing in normal mode, line=%" PRIu32 ", col=%" PRIu32 "\n",
|
||||
lexer_GetLineNo(), lexer_GetColNo());
|
||||
|
||||
if (lexerState->nextToken) {
|
||||
int token = lexerState->nextToken;
|
||||
|
||||
lexerState->nextToken = 0;
|
||||
return token;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
int c = nextChar();
|
||||
char secondChar;
|
||||
@@ -1890,7 +1905,7 @@ static int yylex_NORMAL(void)
|
||||
case '@':
|
||||
yylval.tzSym[0] = '@';
|
||||
yylval.tzSym[1] = '\0';
|
||||
return T_ID;
|
||||
return T_TOKEN_AT;
|
||||
|
||||
case '[':
|
||||
return T_LBRACK;
|
||||
@@ -1903,6 +1918,11 @@ static int yylex_NORMAL(void)
|
||||
case ',':
|
||||
return T_COMMA;
|
||||
|
||||
case '\'':
|
||||
return T_PRIME;
|
||||
case '?':
|
||||
return T_QUESTION;
|
||||
|
||||
/* Handle ambiguous 1- or 2-char tokens */
|
||||
|
||||
case '*': /* Either MUL or EXP */
|
||||
@@ -1953,6 +1973,10 @@ static int yylex_NORMAL(void)
|
||||
return T_OP_LOGICGE;
|
||||
case '>':
|
||||
shiftChars(1);
|
||||
if (peek(0) == '>') {
|
||||
shiftChars(1);
|
||||
return T_OP_SHRL;
|
||||
}
|
||||
return T_OP_SHR;
|
||||
default:
|
||||
return T_OP_LOGICGT;
|
||||
@@ -1980,25 +2004,6 @@ static int yylex_NORMAL(void)
|
||||
case '$':
|
||||
yylval.nConstValue = 0;
|
||||
readHexNumber();
|
||||
/* Attempt to match `$ff00+c` */
|
||||
if (yylval.nConstValue == 0xff00) {
|
||||
/* Whitespace is ignored anyways */
|
||||
while (isWhitespace(c = peek(0)))
|
||||
shiftChars(1);
|
||||
if (c == '+') {
|
||||
/* FIXME: not great due to large lookahead */
|
||||
uint8_t distance = 1;
|
||||
|
||||
do {
|
||||
c = peek(distance++);
|
||||
} while (isWhitespace(c));
|
||||
|
||||
if (c == 'c' || c == 'C') {
|
||||
shiftChars(distance);
|
||||
return T_MODE_HW_C;
|
||||
}
|
||||
}
|
||||
}
|
||||
return T_NUMBER;
|
||||
|
||||
case '0': /* Decimal number */
|
||||
@@ -2067,8 +2072,83 @@ static int yylex_NORMAL(void)
|
||||
readLineContinuation();
|
||||
break;
|
||||
|
||||
/* Handle 8-bit registers followed by a period */
|
||||
|
||||
case 'A':
|
||||
case 'a':
|
||||
if (peek(0) == '.') {
|
||||
shiftChars(1);
|
||||
lexerState->nextToken = T_PERIOD;
|
||||
return T_TOKEN_A;
|
||||
}
|
||||
goto normal_identifier;
|
||||
|
||||
case 'F':
|
||||
case 'f':
|
||||
if (peek(0) == '.') {
|
||||
shiftChars(1);
|
||||
lexerState->nextToken = T_PERIOD;
|
||||
return T_TOKEN_F;
|
||||
}
|
||||
goto normal_identifier;
|
||||
|
||||
case 'B':
|
||||
case 'b':
|
||||
if (peek(0) == '.') {
|
||||
shiftChars(1);
|
||||
lexerState->nextToken = T_PERIOD;
|
||||
return T_TOKEN_B;
|
||||
}
|
||||
goto normal_identifier;
|
||||
|
||||
case 'C':
|
||||
case 'c':
|
||||
if (peek(0) == '.') {
|
||||
shiftChars(1);
|
||||
lexerState->nextToken = T_PERIOD;
|
||||
return T_TOKEN_C;
|
||||
}
|
||||
goto normal_identifier;
|
||||
|
||||
case 'D':
|
||||
case 'd':
|
||||
if (peek(0) == '.') {
|
||||
shiftChars(1);
|
||||
lexerState->nextToken = T_PERIOD;
|
||||
return T_TOKEN_D;
|
||||
}
|
||||
goto normal_identifier;
|
||||
|
||||
case 'E':
|
||||
case 'e':
|
||||
if (peek(0) == '.') {
|
||||
shiftChars(1);
|
||||
lexerState->nextToken = T_PERIOD;
|
||||
return T_TOKEN_E;
|
||||
}
|
||||
goto normal_identifier;
|
||||
|
||||
case 'H':
|
||||
case 'h':
|
||||
if (peek(0) == '.') {
|
||||
shiftChars(1);
|
||||
lexerState->nextToken = T_PERIOD;
|
||||
return T_TOKEN_H;
|
||||
}
|
||||
goto normal_identifier;
|
||||
|
||||
case 'L':
|
||||
case 'l':
|
||||
if (peek(0) == '.') {
|
||||
shiftChars(1);
|
||||
lexerState->nextToken = T_PERIOD;
|
||||
return T_TOKEN_L;
|
||||
}
|
||||
/* fallthrough */
|
||||
|
||||
/* Handle identifiers... or report garbage characters */
|
||||
|
||||
normal_identifier:
|
||||
default:
|
||||
if (startsIdentifier(c)) {
|
||||
int tokenType = readIdentifier(c);
|
||||
|
||||
967
src/asm/parser.y
967
src/asm/parser.y
File diff suppressed because it is too large
Load Diff
@@ -83,7 +83,7 @@ Add an include path.
|
||||
Disable the optimization that turns loads of the form
|
||||
.Ic LD [$FF00+n8],A
|
||||
into the opcode
|
||||
.Ic LDH [$FF00+n8],A
|
||||
.Ic LD [H $FF00+n8],A
|
||||
in order to have full control of the result in the final ROM.
|
||||
.It Fl M Ar depend_file , Fl Fl dependfile Ar depend_file
|
||||
Print
|
||||
@@ -244,7 +244,7 @@ Use a division by 2^N instead.
|
||||
Warn when a shift's operand is negative or greater than 32.
|
||||
.It Fl Wno-truncation
|
||||
Warn when an implicit truncation (for example,
|
||||
.Ic db )
|
||||
.Ic LD [B @] )
|
||||
loses some bits.
|
||||
.It Fl Wno-user
|
||||
Warn when the
|
||||
|
||||
199
src/asm/rgbasm.5
199
src/asm/rgbasm.5
@@ -63,9 +63,9 @@ X = /* the value of x
|
||||
Sometimes lines can be too long and it may be necessary to split them.
|
||||
To do so, put a backslash at the end of the line:
|
||||
.Bd -literal -offset indent
|
||||
DB 1, 2, 3,\ \[rs]
|
||||
4, 5, 6,\ \[rs]\ ;\ Put it before any comments
|
||||
7, 8, 9
|
||||
LD [B @:...], 1, 2, 3,\ \[rs]
|
||||
4, 5, 6,\ \[rs]\ ;\ Put it before any comments
|
||||
7, 8, 9
|
||||
.Ed
|
||||
.Pp
|
||||
This works anywhere in the code except inside of strings.
|
||||
@@ -73,8 +73,8 @@ To split strings it is needed to use
|
||||
.Fn STRCAT
|
||||
like this:
|
||||
.Bd -literal -offset indent
|
||||
db STRCAT("Hello ",\ \[rs]
|
||||
"world!")
|
||||
LD [B @:], STRCAT("Hello ",\ \[rs]
|
||||
"world!")
|
||||
.Ed
|
||||
.Sh EXPRESSIONS
|
||||
An expression can be composed of many things.
|
||||
@@ -226,7 +226,7 @@ For example:
|
||||
; (shifted and scaled from the range [-1.0, 1.0])
|
||||
ANGLE = 0.0
|
||||
REPT 256
|
||||
db (MUL(64.0, SIN(ANGLE)) + 64.0) >> 16
|
||||
ld [b @], (MUL(64.0, SIN(ANGLE)) + 64.0) >> 16
|
||||
ANGLE = ANGLE + 256.0 ; 256.0 = 65536 degrees / 256 entries
|
||||
ENDR
|
||||
.Ed
|
||||
@@ -417,9 +417,9 @@ CHARMAP "í", 20
|
||||
CHARMAP "A", 128
|
||||
.Ed
|
||||
This would result in
|
||||
.Ql db \(dqAmen<LF>\(dq
|
||||
.Ql ld [b @:...], \(dqAmen<LF>\(dq
|
||||
being equivalent to
|
||||
.Ql db 128, 109, 101, 110, 10 .
|
||||
.Ql ld [b @:...], 128, 109, 101, 110, 10 .
|
||||
.Pp
|
||||
Any characters in a string without defined mappings will be copied directly, using the source file's encoding of characters to bytes.
|
||||
.Pp
|
||||
@@ -574,15 +574,15 @@ While
|
||||
will automatically optimize
|
||||
.Ic ld
|
||||
instructions to the smaller and faster
|
||||
.Ic ldh
|
||||
.Ic ld\ h
|
||||
(see
|
||||
.Xr gbz80 7 )
|
||||
whenever possible, it is generally unable to do so when a label is involved.
|
||||
Using the
|
||||
.Ic ldh
|
||||
.Ic ld\ h
|
||||
instruction directly is recommended.
|
||||
This forces the assembler to emit a
|
||||
.Ic ldh
|
||||
.Ic ld\ h
|
||||
instruction and the linker to check if the value is in the correct range.
|
||||
.El
|
||||
.Pp
|
||||
@@ -699,11 +699,11 @@ CopyCode:
|
||||
ld c, RAMLocation.end - RAMLocation
|
||||
\&.loop
|
||||
ld a, [de]
|
||||
inc de
|
||||
ld de+
|
||||
ld [hli], a
|
||||
dec c
|
||||
jr nz, .loop
|
||||
ret
|
||||
ld c-
|
||||
ld nz pc, b .loop
|
||||
ld pc,[sp++]
|
||||
|
||||
RAMCode:
|
||||
LOAD "RAM code", WRAM0
|
||||
@@ -713,13 +713,13 @@ RAMLocation:
|
||||
\&.copy
|
||||
ld a, [hli]
|
||||
ld [de], a
|
||||
inc de
|
||||
and a
|
||||
jr nz, .copy
|
||||
ret
|
||||
ld de+
|
||||
ld a,a&a
|
||||
ld nz pc, b .copy
|
||||
ld pc,[sp++]
|
||||
|
||||
\&.string
|
||||
db "Hello World!", 0
|
||||
ld [b @:...], "Hello World!", 0
|
||||
\&.end
|
||||
ENDL
|
||||
.Ed
|
||||
@@ -929,14 +929,14 @@ references the one before the expression;
|
||||
and so on.
|
||||
.Bd -literal -offset indent
|
||||
ld hl, :++
|
||||
: ld a, [hli] ; referenced by "jr nz"
|
||||
ldh [c], a
|
||||
dec c
|
||||
jr nz, :-
|
||||
ret
|
||||
: ld a, [hli] ; referenced by "ld nz pc"
|
||||
ld [h c], a
|
||||
ld c-
|
||||
ld nz pc,b :-
|
||||
ld pc,[sp++]
|
||||
|
||||
: ; referenced by "ld hl"
|
||||
dw $7FFF, $1061, $03E0, $58A5
|
||||
ld [w @:], $7FFF, $1061, $03E0, $58A5
|
||||
.Ed
|
||||
.Pp
|
||||
A label's location (and thus value) is usually not determined until the linking stage, so labels usually cannot be used as constants.
|
||||
@@ -1036,18 +1036,18 @@ DEF COUNTREG EQUS "[hl+]"
|
||||
ld a,COUNTREG
|
||||
|
||||
DEF PLAYER_NAME EQUS "\[rs]"John\[rs]""
|
||||
db PLAYER_NAME
|
||||
ld [b @:], PLAYER_NAME
|
||||
.Ed
|
||||
.Pp
|
||||
This will be interpreted as:
|
||||
.Bd -literal -offset indent
|
||||
ld a,[hl+]
|
||||
db "John"
|
||||
ld [b @:], "John"
|
||||
.Ed
|
||||
.Pp
|
||||
String equates can also be used to define small one-line macros:
|
||||
.Bd -literal -offset indent
|
||||
DEF pusha EQUS "push af\[rs]npush bc\[rs]npush de\[rs]npush hl\[rs]n"
|
||||
DEF ld_de_hl EQUS "ld d,h\[rs]n ld e,l\[rs]n"
|
||||
.Ed
|
||||
.Pp
|
||||
Note that colons
|
||||
@@ -1135,7 +1135,7 @@ constructs.
|
||||
.Bd -literal -offset indent
|
||||
MACRO MyMacro
|
||||
ld a, 80
|
||||
call MyFunc
|
||||
ld[--sp],pc, MyFunc
|
||||
ENDM
|
||||
.Ed
|
||||
.Pp
|
||||
@@ -1208,9 +1208,9 @@ ExportedLabelB2:
|
||||
.Ql c.asm :
|
||||
.Bd -literal -compact
|
||||
SECTION "C", ROM0[0]
|
||||
dw LabelA
|
||||
dw ExportedLabelB1
|
||||
dw ExportedLabelB2
|
||||
ld [w @], LabelA
|
||||
ld [w @], ExportedLabelB1
|
||||
ld [w @], ExportedLabelB2
|
||||
.Ed
|
||||
.Pp
|
||||
Then
|
||||
@@ -1281,18 +1281,20 @@ Refer to the spec at
|
||||
.Lk https://reproducible-builds.org/docs/source-date-epoch/ .
|
||||
.Sh DEFINING DATA
|
||||
.Ss Declaring variables in a RAM section
|
||||
.Ic DS
|
||||
.Ic LD [B @:<len>]
|
||||
allocates a number of empty bytes.
|
||||
This is the preferred method of allocating space in a RAM section.
|
||||
You can also use
|
||||
.Ic DB , DW
|
||||
.Ic LD [B @] , LD [W @]
|
||||
and
|
||||
.Ic DL
|
||||
without any arguments instead (see
|
||||
.Ic LD [L @]
|
||||
with
|
||||
.Ql \&?
|
||||
instead (see
|
||||
.Sx Defining constant data
|
||||
below).
|
||||
.Bd -literal -offset indent
|
||||
DS 42 ;\ Allocates 42 bytes
|
||||
LD [B @:42], ? ;\ Allocates 42 bytes
|
||||
.Ed
|
||||
.Pp
|
||||
Empty space in RAM sections will not be initialized.
|
||||
@@ -1301,17 +1303,24 @@ In ROM sections, it will be filled with the value passed to the
|
||||
command-line option, except when using overlays with
|
||||
.Fl O .
|
||||
.Ss Defining constant data
|
||||
.Ic DB
|
||||
.Ic LD [B @]
|
||||
defines a list of bytes that will be stored in the final image.
|
||||
Ideal for tables and text.
|
||||
.Bd -literal -offset indent
|
||||
DB 1,2,3,4,"This is a string"
|
||||
LD [B @:...], 1,2,3,4,"This is a string"
|
||||
.Ed
|
||||
.Pp
|
||||
Python slice syntax is used: for a single byte, close the brackets immediately after
|
||||
.Ql @ ;
|
||||
if more than one entry follows, a colon must be added after the
|
||||
.Ql @ ,
|
||||
optionally followed by an ellipsis
|
||||
.Ql ... .
|
||||
.Pp
|
||||
Alternatively, you can use
|
||||
.Ic DW
|
||||
.Ic LD [W @]
|
||||
to store a list of words (16-bit) or
|
||||
.Ic DL
|
||||
.Ic LD [L @]
|
||||
to store a list of double-words/longs (32-bit).
|
||||
.Pp
|
||||
Strings are handled a little specially: they first undergo charmap conversion (see
|
||||
@@ -1319,36 +1328,42 @@ Strings are handled a little specially: they first undergo charmap conversion (s
|
||||
then each resulting character is output individually.
|
||||
For example, under the default charmap, the following two lines are identical:
|
||||
.Bd -literal -offset indent
|
||||
DW "Hello!"
|
||||
DW "H", "e", "l", "l", "o", "!"
|
||||
LD [W @:], "Hello!"
|
||||
LD [W @:], "H", "e", "l", "l", "o", "!"
|
||||
.Ed
|
||||
.Pp
|
||||
Note that strings require a colon after the
|
||||
.Ql @
|
||||
in the directive.
|
||||
.Pp
|
||||
If you do not want this special handling, enclose the string in parentheses.
|
||||
.Pp
|
||||
.Ic DS
|
||||
.Ic LD [B @:<len>]
|
||||
can also be used to fill a region of memory with some repeated values.
|
||||
For example:
|
||||
.Bd -literal -offset indent
|
||||
; outputs 3 bytes: $AA, $AA, $AA
|
||||
DS 3, $AA
|
||||
LD [B @:3], $AA
|
||||
; outputs 7 bytes: $BB, $CC, $BB, $CC, $BB, $CC, $BB
|
||||
DS 7, $BB, $CC
|
||||
LD [B @:7], $BB, $CC
|
||||
.Ed
|
||||
.Pp
|
||||
You can also use
|
||||
.Ic DB , DW
|
||||
.Ic LD [B @] , LD [W @]
|
||||
and
|
||||
.Ic DL
|
||||
without arguments.
|
||||
.Ic LD [L @]
|
||||
with
|
||||
.Ql \&?
|
||||
as its sole argument (in which case neither the colon nor an ellipsis may be present).
|
||||
This works exactly like
|
||||
.Ic DS 1 , DS 2
|
||||
.Ic LD [B @:1] , LD [B @:2]
|
||||
and
|
||||
.Ic DS 4
|
||||
.Ic LD [B @:4]
|
||||
respectively.
|
||||
Consequently, no-argument
|
||||
.Ic DB , DW
|
||||
Consequently, these forms of
|
||||
.Ic LD [B @] , LD [W @]
|
||||
and
|
||||
.Ic DL
|
||||
.Ic LD [L @]
|
||||
can be used in a
|
||||
.Ic WRAM0
|
||||
/
|
||||
@@ -1363,23 +1378,25 @@ section.
|
||||
.Ss Including binary files
|
||||
You probably have some graphics, level data, etc. you'd like to include.
|
||||
Use
|
||||
.Ic INCBIN
|
||||
.Ic LD [B @:...] =
|
||||
to include a raw binary file as it is.
|
||||
.Pq The ellipsis are optional.
|
||||
If the file isn't found in the current directory, the include-path list passed to
|
||||
.Xr rgbasm 1
|
||||
(see the
|
||||
.Fl i
|
||||
option) on the command line will be searched.
|
||||
.Bd -literal -offset indent
|
||||
INCBIN "titlepic.bin"
|
||||
INCBIN "sprites/hero.bin"
|
||||
LD [B @:] = "titlepic.bin"
|
||||
LD [B @:...] = "sprites/hero.bin"
|
||||
.Ed
|
||||
.Pp
|
||||
You can also include only part of a file with
|
||||
.Ic INCBIN .
|
||||
The example below includes 256 bytes from data.bin, starting from byte 78.
|
||||
.Ic LD [B @:] .
|
||||
The examples below include 256 bytes from data.bin, starting from byte 78.
|
||||
.Bd -literal -offset indent
|
||||
INCBIN "data.bin",78,256
|
||||
LD [B @:] = "data.bin"[78:256]
|
||||
LD [B @:256] = "data.bin"[78:]
|
||||
.Ed
|
||||
.Pp
|
||||
The length argument is optional.
|
||||
@@ -1399,19 +1416,19 @@ separates each block of allocations, and you may use it as many times within a u
|
||||
; Let's say PC = $C0DE here
|
||||
UNION
|
||||
; Here, PC = $C0DE
|
||||
Name: ds 8
|
||||
Name: ld [b @:8], ?
|
||||
; PC = $C0E6
|
||||
Nickname: ds 8
|
||||
Nickname: ld [b @:8], ?
|
||||
; PC = $C0EE
|
||||
NEXTU
|
||||
; PC is back to $C0DE
|
||||
Health: dw
|
||||
Health: ld [w @], ?
|
||||
; PC = $C0E0
|
||||
Something: ds 6
|
||||
Something: ld [b @:6], ?
|
||||
; And so on
|
||||
Lives: db
|
||||
Lives: ld [b @], ?
|
||||
NEXTU
|
||||
VideoBuffer: ds 19
|
||||
VideoBuffer: ld [b @:19], ?
|
||||
ENDU
|
||||
.Ed
|
||||
.Pp
|
||||
@@ -1431,17 +1448,17 @@ The size of this union is 19 bytes, as this is the size of the largest block (th
|
||||
Nesting unions is possible, with each inner union's size being considered as described above.
|
||||
.Pp
|
||||
Unions may be used in any section, but inside them may only be
|
||||
.Ic DS -
|
||||
.Ic LD\ [B\ @],\ ? Ns - Ns
|
||||
like commands (see
|
||||
.Sx Declaring variables in a RAM section ) .
|
||||
.Sh THE MACRO LANGUAGE
|
||||
.Ss Invoking macros
|
||||
You execute the macro by inserting its name.
|
||||
.Bd -literal -offset indent
|
||||
add a,b
|
||||
ld a,a+b
|
||||
ld sp,hl
|
||||
MyMacro ;\ This will be expanded
|
||||
sub a,87
|
||||
ld a,a-87
|
||||
.Ed
|
||||
.Pp
|
||||
It's valid to call a macro from a macro (yes, even the same one).
|
||||
@@ -1458,10 +1475,10 @@ it will insert the macro definition (the code enclosed in
|
||||
Suppose your macro contains a loop.
|
||||
.Bd -literal -offset indent
|
||||
MACRO LoopyMacro
|
||||
xor a,a
|
||||
ld a,a^a
|
||||
\&.loop ld [hl+],a
|
||||
dec c
|
||||
jr nz,.loop
|
||||
ld c-
|
||||
ld nz pc,b .loop
|
||||
ENDM
|
||||
.Ed
|
||||
.Pp
|
||||
@@ -1476,10 +1493,10 @@ also works in
|
||||
blocks.
|
||||
.Bd -literal -offset indent
|
||||
MACRO LoopyMacro
|
||||
xor a,a
|
||||
ld a,a^a
|
||||
\&.loop\[rs]@ ld [hl+],a
|
||||
dec c
|
||||
jr nz,.loop\[rs]@
|
||||
ld c-
|
||||
ld nz pc,b .loop\[rs]@
|
||||
ENDM
|
||||
.Ed
|
||||
.Pp
|
||||
@@ -1507,10 +1524,10 @@ being the first argument specified on the macro invocation.
|
||||
MACRO LoopyMacro
|
||||
ld hl,\[rs]1
|
||||
ld c,\[rs]2
|
||||
xor a,a
|
||||
ld a,a^a
|
||||
\&.loop\[rs]@ ld [hl+],a
|
||||
dec c
|
||||
jr nz,.loop\[rs]@
|
||||
ld c-
|
||||
ld nz pc,b .loop\[rs]@
|
||||
ENDM
|
||||
.Ed
|
||||
.Pp
|
||||
@@ -1622,7 +1639,7 @@ The following example will assemble
|
||||
four times:
|
||||
.Bd -literal -offset indent
|
||||
REPT 4
|
||||
add a,c
|
||||
ld a,a+c
|
||||
ENDR
|
||||
.Ed
|
||||
.Pp
|
||||
@@ -1634,7 +1651,7 @@ to generate tables on the fly:
|
||||
; (shifted and scaled from the range [-1.0, 1.0])
|
||||
ANGLE = 0.0
|
||||
REPT 256
|
||||
db (MUL(64.0, SIN(ANGLE)) + 64.0) >> 16
|
||||
ld [b @], (MUL(64.0, SIN(ANGLE)) + 64.0) >> 16
|
||||
ANGLE = ANGLE + 256.0 ; 256.0 = 65536 degrees / 256 entries
|
||||
ENDR
|
||||
.Ed
|
||||
@@ -1658,21 +1675,21 @@ String equates are not expanded within the symbol name.
|
||||
For example, this code will produce a table of squared values from 0 to 255:
|
||||
.Bd -literal -offset indent
|
||||
FOR N, 256
|
||||
dw N * N
|
||||
ld [w @], N * N
|
||||
ENDR
|
||||
.Ed
|
||||
.Pp
|
||||
It acts just as if you had done:
|
||||
.Bd -literal -offset ident
|
||||
N = 0
|
||||
dw N * N
|
||||
ld [w @], N * N
|
||||
N = 1
|
||||
dw N * N
|
||||
ld [w @], N * N
|
||||
N = 2
|
||||
dw N * N
|
||||
ld [w @], N * N
|
||||
; ...
|
||||
N = 255
|
||||
dw N * N
|
||||
ld [w @], N * N
|
||||
N = 256
|
||||
.Ed
|
||||
.Pp
|
||||
@@ -1763,18 +1780,18 @@ and
|
||||
Syntax examples are given below:
|
||||
.Bd -literal -offset indent
|
||||
Function:
|
||||
xor a
|
||||
ld a,a^a
|
||||
ASSERT LOW(Variable) == 0
|
||||
ld h, HIGH(Variable)
|
||||
ld l, a
|
||||
ld a, [hli]
|
||||
; You can also indent this!
|
||||
ASSERT BANK(OtherFunction) == BANK(Function)
|
||||
call OtherFunction
|
||||
ld [--sp], pc,OtherFunction
|
||||
; Lowercase also works
|
||||
assert Variable + 1 == OtherVariable
|
||||
ld c, [hl]
|
||||
ret
|
||||
ld pc,[sp++]
|
||||
\&.end
|
||||
; If you specify one, a message will be printed
|
||||
STATIC_ASSERT .end - Function < 256, "Function is too large!"
|
||||
@@ -1883,9 +1900,9 @@ takes a comma-separated list of options as its argument:
|
||||
.Bd -literal -offset indent
|
||||
PUSHO
|
||||
OPT g.oOX ;Set the GB graphics constants to use these characters
|
||||
DW `..ooOOXX
|
||||
LD [W @], `..ooOOXX
|
||||
POPO
|
||||
DW `00112233
|
||||
LD [W @], `00112233
|
||||
.Ed
|
||||
.Pp
|
||||
The options that OPT can modify are currently:
|
||||
|
||||
539
src/gbz80.7
539
src/gbz80.7
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user