Compare commits

...

22 Commits

Author SHA1 Message Date
ISSOtm
76c1995559 Fix CI 2021-04-01 11:38:07 +02:00
Rangi
ae84570f04 Revise RGBASM manual 2021-03-31 18:35:09 -04:00
Rangi
094a31ef8c Update RGBASM command-line manual 2021-03-31 18:17:18 -04:00
ISSOtm
291dcf3b6c Update RGBASM manual 2021-04-01 00:11:41 +02:00
Rangi
a890bd072b Fix "INCBIN"
Examples: (...s are optional)

ld [b @:...] = "Dockerfile"
ld [b @:...] = "Dockerfile"[451:...]
ld [b @:...] = "Dockerfile"[23:5]
ld [b @:5] = "Dockerfile"[23:...]
2021-03-31 18:06:14 -04:00
Rangi
2f6c808ccb Revise instruction reference 2021-03-31 17:59:12 -04:00
ISSOtm
e80907abd0 Update instruction reference 2021-03-31 23:26:57 +02:00
Rangi
25d39155d3 Support ld a, a±c±LOW(bc) as well as ld a, a±c±c 2021-03-30 12:36:11 -04:00
Rangi
77021d229b Support ld [c], a and ld a, [c] 2021-03-30 12:02:29 -04:00
Rangi
1b250b90b2 Implement ds <len> ==> ld [b @:<len>], ? 2021-03-30 11:54:39 -04:00
Rangi
e2b4723489 Fix lexing @ 2021-03-30 11:52:25 -04:00
Rangi
2507413162 Fix lexing a., b., etc 2021-03-30 11:41:44 -04:00
Rangi
e023a84d04 Allow 'ld a, a±c±<r8>' or 'ld a, a±<r8>±c' for adc/sbc 2021-03-30 11:27:19 -04:00
Rangi
34c127d9c3 Allow ld [b @:<len>] = "file.bin"[<ofs>:...] 2021-03-30 10:51:48 -04:00
Rangi
9a930988c2 Implement db, dw, dl, ds, and INCBIN with ld
To do: let the `b` in `ld [b @]` be optional, and allow
`ld [b @:<len>] = "file.bin"[<ofs>:...]`
2021-03-30 10:47:05 -04:00
Rangi
8c4204c542 Make 'w' and '...' tokens, and make '@' a separate token
Now '@' is valid as a relocexpr_no_str, in 'BANK(@)', and
in 'DEF(@)', but not in general T_ID or T_LABEL contexts

This will make it easier to implement INCBIN with 'ld'
2021-03-30 10:17:09 -04:00
Rangi
663c1930ec Factor out 'ld a, a+c+' and 'ld a, a-c-' prefixes
This fixes all the shift/reduce and reduce/reduce conflicts
2021-03-30 09:57:08 -04:00
Rangi
30ccf43f44 Factor out individual 'ld <r16>,' prefixes 2021-03-30 09:43:34 -04:00
Rangi
fdc17adbcb Factor out common ld a, prefix 2021-03-30 09:19:58 -04:00
Rangi
cc196954f3 Consolidate some parser rules with reg_ss and reg_r
There are now 5 shift/reduce conflicts and 3 reduce/reduce conflicts
2021-03-29 20:52:24 -04:00
Rangi
55b6cfff84 Prevent GitHub Actions from running any workflows 2021-03-29 19:50:13 -04:00
Rangi
1fc73b04eb Parse ld instructions as discussed
There are 13 shift/reduce conflicts, so some instructions
may need different formats.

This also does not yet implement `db`, `dw`, `dl`, `ds`,
or `INCBIN` using `ld`.

The `lexerState->nextToken` solution to lexing something
like "a.2" as three tokens instead of one identifier
is taken from the first commit in rgbds PR #799.
2021-03-29 19:42:18 -04:00
17 changed files with 979 additions and 852 deletions

View File

@@ -163,16 +163,20 @@ static struct KeywordMapping {
{"DE", T_MODE_DE}, {"DE", T_MODE_DE},
{"HL", T_MODE_HL}, {"HL", T_MODE_HL},
{"SP", T_MODE_SP}, {"SP", T_MODE_SP},
{"PC", T_MODE_PC},
{"HLD", T_MODE_HL_DEC}, {"HLD", T_MODE_HL_DEC},
{"HLI", T_MODE_HL_INC}, {"HLI", T_MODE_HL_INC},
{"IME", T_MODE_IME},
{"A", T_TOKEN_A}, {"A", T_TOKEN_A},
{"F", T_TOKEN_F},
{"B", T_TOKEN_B}, {"B", T_TOKEN_B},
{"C", T_TOKEN_C}, {"C", T_TOKEN_C},
{"D", T_TOKEN_D}, {"D", T_TOKEN_D},
{"E", T_TOKEN_E}, {"E", T_TOKEN_E},
{"H", T_TOKEN_H}, {"H", T_TOKEN_H},
{"L", T_TOKEN_L}, {"L", T_TOKEN_L},
{"W", T_TOKEN_W},
{"DEF", T_OP_DEF}, {"DEF", T_OP_DEF},
@@ -290,6 +294,7 @@ static struct KeywordMapping {
{"OPT", T_POP_OPT}, {"OPT", T_POP_OPT},
{".", T_PERIOD}, {".", T_PERIOD},
{"...", T_ELLIPSIS},
}; };
static bool isWhitespace(int c) static bool isWhitespace(int c)
@@ -350,6 +355,7 @@ struct LexerState {
uint32_t lineNo; uint32_t lineNo;
uint32_t colNo; uint32_t colNo;
int lastToken; int lastToken;
int nextToken;
struct IfStack *ifStack; struct IfStack *ifStack;
@@ -374,6 +380,7 @@ static void initState(struct LexerState *state)
state->mode = LEXER_NORMAL; state->mode = LEXER_NORMAL;
state->atLineStart = true; /* yylex() will init colNo due to this */ state->atLineStart = true; /* yylex() will init colNo due to this */
state->lastToken = T_EOF; state->lastToken = T_EOF;
state->nextToken = 0;
state->ifStack = NULL; state->ifStack = NULL;
@@ -586,7 +593,7 @@ struct KeywordDictNode {
uint16_t children[0x60 - ' ']; uint16_t children[0x60 - ' '];
struct KeywordMapping const *keyword; struct KeywordMapping const *keyword;
/* Since the keyword structure is invariant, the min number of nodes is known at compile time */ /* 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 */ /* Convert a char into its index into the dict */
static inline uint8_t dictIndex(char c) 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", dbgPrint("Lexing in normal mode, line=%" PRIu32 ", col=%" PRIu32 "\n",
lexer_GetLineNo(), lexer_GetColNo()); lexer_GetLineNo(), lexer_GetColNo());
if (lexerState->nextToken) {
int token = lexerState->nextToken;
lexerState->nextToken = 0;
return token;
}
for (;;) { for (;;) {
int c = nextChar(); int c = nextChar();
char secondChar; char secondChar;
@@ -1890,7 +1905,7 @@ static int yylex_NORMAL(void)
case '@': case '@':
yylval.tzSym[0] = '@'; yylval.tzSym[0] = '@';
yylval.tzSym[1] = '\0'; yylval.tzSym[1] = '\0';
return T_ID; return T_TOKEN_AT;
case '[': case '[':
return T_LBRACK; return T_LBRACK;
@@ -1903,6 +1918,11 @@ static int yylex_NORMAL(void)
case ',': case ',':
return T_COMMA; return T_COMMA;
case '\'':
return T_PRIME;
case '?':
return T_QUESTION;
/* Handle ambiguous 1- or 2-char tokens */ /* Handle ambiguous 1- or 2-char tokens */
case '*': /* Either MUL or EXP */ case '*': /* Either MUL or EXP */
@@ -1953,6 +1973,10 @@ static int yylex_NORMAL(void)
return T_OP_LOGICGE; return T_OP_LOGICGE;
case '>': case '>':
shiftChars(1); shiftChars(1);
if (peek(0) == '>') {
shiftChars(1);
return T_OP_SHRL;
}
return T_OP_SHR; return T_OP_SHR;
default: default:
return T_OP_LOGICGT; return T_OP_LOGICGT;
@@ -1980,25 +2004,6 @@ static int yylex_NORMAL(void)
case '$': case '$':
yylval.nConstValue = 0; yylval.nConstValue = 0;
readHexNumber(); 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; return T_NUMBER;
case '0': /* Decimal number */ case '0': /* Decimal number */
@@ -2067,8 +2072,83 @@ static int yylex_NORMAL(void)
readLineContinuation(); readLineContinuation();
break; 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 */ /* Handle identifiers... or report garbage characters */
normal_identifier:
default: default:
if (startsIdentifier(c)) { if (startsIdentifier(c)) {
int tokenType = readIdentifier(c); int tokenType = readIdentifier(c);

File diff suppressed because it is too large Load Diff

View File

@@ -83,7 +83,7 @@ Add an include path.
Disable the optimization that turns loads of the form Disable the optimization that turns loads of the form
.Ic LD [$FF00+n8],A .Ic LD [$FF00+n8],A
into the opcode 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. 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 .It Fl M Ar depend_file , Fl Fl dependfile Ar depend_file
Print Print
@@ -244,7 +244,7 @@ Use a division by 2^N instead.
Warn when a shift's operand is negative or greater than 32. Warn when a shift's operand is negative or greater than 32.
.It Fl Wno-truncation .It Fl Wno-truncation
Warn when an implicit truncation (for example, Warn when an implicit truncation (for example,
.Ic db ) .Ic LD [B @] )
loses some bits. loses some bits.
.It Fl Wno-user .It Fl Wno-user
Warn when the Warn when the

View File

@@ -63,7 +63,7 @@ X = /* the value of x
Sometimes lines can be too long and it may be necessary to split them. 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: To do so, put a backslash at the end of the line:
.Bd -literal -offset indent .Bd -literal -offset indent
DB 1, 2, 3,\ \[rs] LD [B @:...], 1, 2, 3,\ \[rs]
4, 5, 6,\ \[rs]\ ;\ Put it before any comments 4, 5, 6,\ \[rs]\ ;\ Put it before any comments
7, 8, 9 7, 8, 9
.Ed .Ed
@@ -73,7 +73,7 @@ To split strings it is needed to use
.Fn STRCAT .Fn STRCAT
like this: like this:
.Bd -literal -offset indent .Bd -literal -offset indent
db STRCAT("Hello ",\ \[rs] LD [B @:], STRCAT("Hello ",\ \[rs]
"world!") "world!")
.Ed .Ed
.Sh EXPRESSIONS .Sh EXPRESSIONS
@@ -226,7 +226,7 @@ For example:
; (shifted and scaled from the range [-1.0, 1.0]) ; (shifted and scaled from the range [-1.0, 1.0])
ANGLE = 0.0 ANGLE = 0.0
REPT 256 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 ANGLE = ANGLE + 256.0 ; 256.0 = 65536 degrees / 256 entries
ENDR ENDR
.Ed .Ed
@@ -417,9 +417,9 @@ CHARMAP "&iacute", 20
CHARMAP "A", 128 CHARMAP "A", 128
.Ed .Ed
This would result in This would result in
.Ql db \(dqAmen<LF>\(dq .Ql ld [b @:...], \(dqAmen<LF>\(dq
being equivalent to being equivalent to
.Ql db 128, 109, 101, 110, 10 . .Ql ld [b @:...], 128, 109, 101, 110, 10 .
.Pp .Pp
Any characters in a string without defined mappings will be copied directly, using the source file's encoding of characters to bytes. Any characters in a string without defined mappings will be copied directly, using the source file's encoding of characters to bytes.
.Pp .Pp
@@ -574,15 +574,15 @@ While
will automatically optimize will automatically optimize
.Ic ld .Ic ld
instructions to the smaller and faster instructions to the smaller and faster
.Ic ldh .Ic ld\ h
(see (see
.Xr gbz80 7 ) .Xr gbz80 7 )
whenever possible, it is generally unable to do so when a label is involved. whenever possible, it is generally unable to do so when a label is involved.
Using the Using the
.Ic ldh .Ic ld\ h
instruction directly is recommended. instruction directly is recommended.
This forces the assembler to emit a 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. instruction and the linker to check if the value is in the correct range.
.El .El
.Pp .Pp
@@ -699,11 +699,11 @@ CopyCode:
ld c, RAMLocation.end - RAMLocation ld c, RAMLocation.end - RAMLocation
\&.loop \&.loop
ld a, [de] ld a, [de]
inc de ld de+
ld [hli], a ld [hli], a
dec c ld c-
jr nz, .loop ld nz pc, b .loop
ret ld pc,[sp++]
RAMCode: RAMCode:
LOAD "RAM code", WRAM0 LOAD "RAM code", WRAM0
@@ -713,13 +713,13 @@ RAMLocation:
\&.copy \&.copy
ld a, [hli] ld a, [hli]
ld [de], a ld [de], a
inc de ld de+
and a ld a,a&a
jr nz, .copy ld nz pc, b .copy
ret ld pc,[sp++]
\&.string \&.string
db "Hello World!", 0 ld [b @:...], "Hello World!", 0
\&.end \&.end
ENDL ENDL
.Ed .Ed
@@ -929,14 +929,14 @@ references the one before the expression;
and so on. and so on.
.Bd -literal -offset indent .Bd -literal -offset indent
ld hl, :++ ld hl, :++
: ld a, [hli] ; referenced by "jr nz" : ld a, [hli] ; referenced by "ld nz pc"
ldh [c], a ld [h c], a
dec c ld c-
jr nz, :- ld nz pc,b :-
ret ld pc,[sp++]
: ; referenced by "ld hl" : ; referenced by "ld hl"
dw $7FFF, $1061, $03E0, $58A5 ld [w @:], $7FFF, $1061, $03E0, $58A5
.Ed .Ed
.Pp .Pp
A label's location (and thus value) is usually not determined until the linking stage, so labels usually cannot be used as constants. 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 ld a,COUNTREG
DEF PLAYER_NAME EQUS "\[rs]"John\[rs]"" DEF PLAYER_NAME EQUS "\[rs]"John\[rs]""
db PLAYER_NAME ld [b @:], PLAYER_NAME
.Ed .Ed
.Pp .Pp
This will be interpreted as: This will be interpreted as:
.Bd -literal -offset indent .Bd -literal -offset indent
ld a,[hl+] ld a,[hl+]
db "John" ld [b @:], "John"
.Ed .Ed
.Pp .Pp
String equates can also be used to define small one-line macros: String equates can also be used to define small one-line macros:
.Bd -literal -offset indent .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 .Ed
.Pp .Pp
Note that colons Note that colons
@@ -1135,7 +1135,7 @@ constructs.
.Bd -literal -offset indent .Bd -literal -offset indent
MACRO MyMacro MACRO MyMacro
ld a, 80 ld a, 80
call MyFunc ld[--sp],pc, MyFunc
ENDM ENDM
.Ed .Ed
.Pp .Pp
@@ -1208,9 +1208,9 @@ ExportedLabelB2:
.Ql c.asm : .Ql c.asm :
.Bd -literal -compact .Bd -literal -compact
SECTION "C", ROM0[0] SECTION "C", ROM0[0]
dw LabelA ld [w @], LabelA
dw ExportedLabelB1 ld [w @], ExportedLabelB1
dw ExportedLabelB2 ld [w @], ExportedLabelB2
.Ed .Ed
.Pp .Pp
Then Then
@@ -1281,18 +1281,20 @@ Refer to the spec at
.Lk https://reproducible-builds.org/docs/source-date-epoch/ . .Lk https://reproducible-builds.org/docs/source-date-epoch/ .
.Sh DEFINING DATA .Sh DEFINING DATA
.Ss Declaring variables in a RAM section .Ss Declaring variables in a RAM section
.Ic DS .Ic LD [B @:<len>]
allocates a number of empty bytes. allocates a number of empty bytes.
This is the preferred method of allocating space in a RAM section. This is the preferred method of allocating space in a RAM section.
You can also use You can also use
.Ic DB , DW .Ic LD [B @] , LD [W @]
and and
.Ic DL .Ic LD [L @]
without any arguments instead (see with
.Ql \&?
instead (see
.Sx Defining constant data .Sx Defining constant data
below). below).
.Bd -literal -offset indent .Bd -literal -offset indent
DS 42 ;\ Allocates 42 bytes LD [B @:42], ? ;\ Allocates 42 bytes
.Ed .Ed
.Pp .Pp
Empty space in RAM sections will not be initialized. 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 command-line option, except when using overlays with
.Fl O . .Fl O .
.Ss Defining constant data .Ss Defining constant data
.Ic DB .Ic LD [B @]
defines a list of bytes that will be stored in the final image. defines a list of bytes that will be stored in the final image.
Ideal for tables and text. Ideal for tables and text.
.Bd -literal -offset indent .Bd -literal -offset indent
DB 1,2,3,4,"This is a string" LD [B @:...], 1,2,3,4,"This is a string"
.Ed .Ed
.Pp .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 Alternatively, you can use
.Ic DW .Ic LD [W @]
to store a list of words (16-bit) or to store a list of words (16-bit) or
.Ic DL .Ic LD [L @]
to store a list of double-words/longs (32-bit). to store a list of double-words/longs (32-bit).
.Pp .Pp
Strings are handled a little specially: they first undergo charmap conversion (see 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. then each resulting character is output individually.
For example, under the default charmap, the following two lines are identical: For example, under the default charmap, the following two lines are identical:
.Bd -literal -offset indent .Bd -literal -offset indent
DW "Hello!" LD [W @:], "Hello!"
DW "H", "e", "l", "l", "o", "!" LD [W @:], "H", "e", "l", "l", "o", "!"
.Ed .Ed
.Pp .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. If you do not want this special handling, enclose the string in parentheses.
.Pp .Pp
.Ic DS .Ic LD [B @:<len>]
can also be used to fill a region of memory with some repeated values. can also be used to fill a region of memory with some repeated values.
For example: For example:
.Bd -literal -offset indent .Bd -literal -offset indent
; outputs 3 bytes: $AA, $AA, $AA ; outputs 3 bytes: $AA, $AA, $AA
DS 3, $AA LD [B @:3], $AA
; outputs 7 bytes: $BB, $CC, $BB, $CC, $BB, $CC, $BB ; outputs 7 bytes: $BB, $CC, $BB, $CC, $BB, $CC, $BB
DS 7, $BB, $CC LD [B @:7], $BB, $CC
.Ed .Ed
.Pp .Pp
You can also use You can also use
.Ic DB , DW .Ic LD [B @] , LD [W @]
and and
.Ic DL .Ic LD [L @]
without arguments. with
.Ql \&?
as its sole argument (in which case neither the colon nor an ellipsis may be present).
This works exactly like This works exactly like
.Ic DS 1 , DS 2 .Ic LD [B @:1] , LD [B @:2]
and and
.Ic DS 4 .Ic LD [B @:4]
respectively. respectively.
Consequently, no-argument Consequently, these forms of
.Ic DB , DW .Ic LD [B @] , LD [W @]
and and
.Ic DL .Ic LD [L @]
can be used in a can be used in a
.Ic WRAM0 .Ic WRAM0
/ /
@@ -1363,23 +1378,25 @@ section.
.Ss Including binary files .Ss Including binary files
You probably have some graphics, level data, etc. you'd like to include. You probably have some graphics, level data, etc. you'd like to include.
Use Use
.Ic INCBIN .Ic LD [B @:...] =
to include a raw binary file as it is. 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 If the file isn't found in the current directory, the include-path list passed to
.Xr rgbasm 1 .Xr rgbasm 1
(see the (see the
.Fl i .Fl i
option) on the command line will be searched. option) on the command line will be searched.
.Bd -literal -offset indent .Bd -literal -offset indent
INCBIN "titlepic.bin" LD [B @:] = "titlepic.bin"
INCBIN "sprites/hero.bin" LD [B @:...] = "sprites/hero.bin"
.Ed .Ed
.Pp .Pp
You can also include only part of a file with You can also include only part of a file with
.Ic INCBIN . .Ic LD [B @:] .
The example below includes 256 bytes from data.bin, starting from byte 78. The examples below include 256 bytes from data.bin, starting from byte 78.
.Bd -literal -offset indent .Bd -literal -offset indent
INCBIN "data.bin",78,256 LD [B @:] = "data.bin"[78:256]
LD [B @:256] = "data.bin"[78:]
.Ed .Ed
.Pp .Pp
The length argument is optional. 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 ; Let's say PC = $C0DE here
UNION UNION
; Here, PC = $C0DE ; Here, PC = $C0DE
Name: ds 8 Name: ld [b @:8], ?
; PC = $C0E6 ; PC = $C0E6
Nickname: ds 8 Nickname: ld [b @:8], ?
; PC = $C0EE ; PC = $C0EE
NEXTU NEXTU
; PC is back to $C0DE ; PC is back to $C0DE
Health: dw Health: ld [w @], ?
; PC = $C0E0 ; PC = $C0E0
Something: ds 6 Something: ld [b @:6], ?
; And so on ; And so on
Lives: db Lives: ld [b @], ?
NEXTU NEXTU
VideoBuffer: ds 19 VideoBuffer: ld [b @:19], ?
ENDU ENDU
.Ed .Ed
.Pp .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. Nesting unions is possible, with each inner union's size being considered as described above.
.Pp .Pp
Unions may be used in any section, but inside them may only be Unions may be used in any section, but inside them may only be
.Ic DS - .Ic LD\ [B\ @],\ ? Ns - Ns
like commands (see like commands (see
.Sx Declaring variables in a RAM section ) . .Sx Declaring variables in a RAM section ) .
.Sh THE MACRO LANGUAGE .Sh THE MACRO LANGUAGE
.Ss Invoking macros .Ss Invoking macros
You execute the macro by inserting its name. You execute the macro by inserting its name.
.Bd -literal -offset indent .Bd -literal -offset indent
add a,b ld a,a+b
ld sp,hl ld sp,hl
MyMacro ;\ This will be expanded MyMacro ;\ This will be expanded
sub a,87 ld a,a-87
.Ed .Ed
.Pp .Pp
It's valid to call a macro from a macro (yes, even the same one). 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. Suppose your macro contains a loop.
.Bd -literal -offset indent .Bd -literal -offset indent
MACRO LoopyMacro MACRO LoopyMacro
xor a,a ld a,a^a
\&.loop ld [hl+],a \&.loop ld [hl+],a
dec c ld c-
jr nz,.loop ld nz pc,b .loop
ENDM ENDM
.Ed .Ed
.Pp .Pp
@@ -1476,10 +1493,10 @@ also works in
blocks. blocks.
.Bd -literal -offset indent .Bd -literal -offset indent
MACRO LoopyMacro MACRO LoopyMacro
xor a,a ld a,a^a
\&.loop\[rs]@ ld [hl+],a \&.loop\[rs]@ ld [hl+],a
dec c ld c-
jr nz,.loop\[rs]@ ld nz pc,b .loop\[rs]@
ENDM ENDM
.Ed .Ed
.Pp .Pp
@@ -1507,10 +1524,10 @@ being the first argument specified on the macro invocation.
MACRO LoopyMacro MACRO LoopyMacro
ld hl,\[rs]1 ld hl,\[rs]1
ld c,\[rs]2 ld c,\[rs]2
xor a,a ld a,a^a
\&.loop\[rs]@ ld [hl+],a \&.loop\[rs]@ ld [hl+],a
dec c ld c-
jr nz,.loop\[rs]@ ld nz pc,b .loop\[rs]@
ENDM ENDM
.Ed .Ed
.Pp .Pp
@@ -1622,7 +1639,7 @@ The following example will assemble
four times: four times:
.Bd -literal -offset indent .Bd -literal -offset indent
REPT 4 REPT 4
add a,c ld a,a+c
ENDR ENDR
.Ed .Ed
.Pp .Pp
@@ -1634,7 +1651,7 @@ to generate tables on the fly:
; (shifted and scaled from the range [-1.0, 1.0]) ; (shifted and scaled from the range [-1.0, 1.0])
ANGLE = 0.0 ANGLE = 0.0
REPT 256 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 ANGLE = ANGLE + 256.0 ; 256.0 = 65536 degrees / 256 entries
ENDR ENDR
.Ed .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: For example, this code will produce a table of squared values from 0 to 255:
.Bd -literal -offset indent .Bd -literal -offset indent
FOR N, 256 FOR N, 256
dw N * N ld [w @], N * N
ENDR ENDR
.Ed .Ed
.Pp .Pp
It acts just as if you had done: It acts just as if you had done:
.Bd -literal -offset ident .Bd -literal -offset ident
N = 0 N = 0
dw N * N ld [w @], N * N
N = 1 N = 1
dw N * N ld [w @], N * N
N = 2 N = 2
dw N * N ld [w @], N * N
; ... ; ...
N = 255 N = 255
dw N * N ld [w @], N * N
N = 256 N = 256
.Ed .Ed
.Pp .Pp
@@ -1763,18 +1780,18 @@ and
Syntax examples are given below: Syntax examples are given below:
.Bd -literal -offset indent .Bd -literal -offset indent
Function: Function:
xor a ld a,a^a
ASSERT LOW(Variable) == 0 ASSERT LOW(Variable) == 0
ld h, HIGH(Variable) ld h, HIGH(Variable)
ld l, a ld l, a
ld a, [hli] ld a, [hli]
; You can also indent this! ; You can also indent this!
ASSERT BANK(OtherFunction) == BANK(Function) ASSERT BANK(OtherFunction) == BANK(Function)
call OtherFunction ld [--sp], pc,OtherFunction
; Lowercase also works ; Lowercase also works
assert Variable + 1 == OtherVariable assert Variable + 1 == OtherVariable
ld c, [hl] ld c, [hl]
ret ld pc,[sp++]
\&.end \&.end
; If you specify one, a message will be printed ; If you specify one, a message will be printed
STATIC_ASSERT .end - Function < 256, "Function is too large!" 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 .Bd -literal -offset indent
PUSHO PUSHO
OPT g.oOX ;Set the GB graphics constants to use these characters OPT g.oOX ;Set the GB graphics constants to use these characters
DW `..ooOOXX LD [W @], `..ooOOXX
POPO POPO
DW `00112233 LD [W @], `00112233
.Ed .Ed
.Pp .Pp
The options that OPT can modify are currently: The options that OPT can modify are currently:

File diff suppressed because it is too large Load Diff