|
NAMErgbasm —
language documentation
DESCRIPTIONThis is the full description of the language used by rgbasm(1). The description of the instructions supported by the Game Boy CPU is in gbz80(7).It is strongly recommended to have some familiarity with the Game Boy hardware before reading this document. RGBDS is specifically targeted at the Game Boy, and thus a lot of its features tie directly to its concepts. This document is not intended to be a Game Boy hardware reference. Generally, “the linker” will refer to rgblink(1), but any program that processes RGBDS object files (described in rgbds(5)) can be used in its place. SYNTAXThe syntax is line-based, just as in any other assembler, meaning that you do one instruction or directive per line:[label]
[instruction]
[; comment] Example: John: ld a,87 ;Weee All reserved keywords (directives, mnemonics, registers, etc.) are case-insensitive; all identifiers (symbol names) are case-sensitive. Comments are used to give humans information about the code, such as explanations. The assembler always ignores comments and their contents. There are two syntaxes for comments. The most common is that
anything that follows a semicolon ‘ X = /* the value of x should be 3 */ 3 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: DB 1, 2, 3, \ 4, 5, 6, \ ; Put it before any comments 7, 8, 9 DB "Hello, \ ; Space before the \ is included world!" ; Any leading space is included Symbol interpolationA funky feature is ‘{symbol} ’ within a
string, called “symbol interpolation”. This will paste the
contents of ‘symbol ’ as if they were
part of the source file. If it is a string symbol, its characters are simply
inserted as-is. If it is a numeric symbol, its value is converted to
hexadecimal notation with a dollar sign ‘$’ prepended.
Symbol interpolations can be nested, too! DEF topic EQUS "life, the universe, and \"everything\"" DEF meaning EQUS "answer" ; Defines answer = 42 DEF {meaning} = 42 ; Prints "The answer to life, the universe, and "everything" is $2A" PRINTLN "The {meaning} to {topic} is {{meaning}}" PURGE topic, meaning, {meaning} Symbols can be interpolated even in the contexts
that disable automatic expansion of string constants:
‘ It's possible to change the way symbols are printed by specifying
a print format like so:
‘
All the format specifier parts are optional except the
‘
Examples: SECTION "Test", ROM0[2] X: ; This works with labels **whose address is known** Y = 3 ; This also works with variables SUM equ X + Y ; And likewise with numeric constants ; Prints "%0010 + $3 == 5" PRINTLN "{#05b:X} + {#x:Y} == {d:SUM}" rsset 32 PERCENT rb 1 ; Same with offset constants VALUE = 20 RESULT = MUL(20.0, 0.32) ; Prints "32% of 20 = 6.40" PRINTLN "{d:PERCENT}% of {d:VALUE} = {f:RESULT}" WHO equs STRLWR("WORLD") ; Prints "Hello world!" PRINTLN "Hello {s:WHO}!" Although, for these examples, EXPRESSIONSAn expression can be composed of many things. Numeric expressions are always evaluated using signed 32-bit math. Zero is considered to be the only "false" number, all non-zero numbers (including negative) are "true".An expression is said to be "constant" if
The instructions in the macro-language generally require constant expressions. Numeric formatsThere are a number of numeric formats.
Underscores are also accepted in numbers, except at the beginning
of one. This can be useful for grouping digits, like
‘ The "character constant" form yields the value the character maps to in the current charmap. For example, by default (refer to ascii(7)) ‘"A"’ yields 65. See Character maps for information on charmaps. The last one, Gameboy graphics, is quite interesting and useful. After the backtick, 8 digits between 0 and 3 are expected, corresponding to pixel values. The resulting value is the two bytes of tile data that would produce that row of pixels. For example, ‘`01012323’ is equivalent to ‘$0F55’. You can also use symbols, which are implicitly replaced with their value. OperatorsA great number of operators you can use in expressions are available (listed from highest to lowest precedence):
Shifting works by shifting all bits in the left operand either left (‘<<’) or right (‘>>’) by the right operand's amount. When shifting left, all newly-inserted bits are reset; when shifting right, they are copies of the original most significant bit instead. This makes ‘a << b’ and ‘a >> b’ equivalent to multiplying and dividing by 2 to the power of b, respectively. Comparison operators return 0 if the comparison is false, and 1 otherwise. Unlike in a lot of languages, and for technical reasons,
Fixed-point expressionsFixed-point numbers are basically normal (32-bit) integers, which count 65536ths instead of entire units, offering better precision than integers but limiting the range of values. The upper 16 bits are used for the integer part and the lower 16 bits are used for the fraction (65536ths). Since they are still akin to integers, you can use them in normal integer expressions, and some integer operators like ‘+’ and ‘-’ don't care whether the operands are integers or fixed-point. You can easily truncate a fixed-point number into an integer by shifting it right by 16 bits. It follows that you can convert an integer to a fixed-point number by shifting it left.The following functions are designed to operate with fixed-point numbers:
The trigonometry functions ( These functions are useful for automatic generation of various tables. For example: ; Generate a 256-byte sine table with values in the range [0, 128] ; (shifted and scaled from the range [-1.0, 1.0]) ANGLE = 0.0 REPT 256 db (MUL(64.0, SIN(ANGLE)) + 64.0) >> 16 ANGLE = ANGLE + 256.0 ; 256.0 = 65536 degrees / 256 entries ENDR String expressionsThe most basic string expression is any number of characters contained in double quotes (‘"for instance" ’). The
backslash character ‘\ ’ is special in
that it causes the character following it to be “escaped”,
meaning that it is treated differently from normal. There are a number of
escape sequences you can use within a string:
Multi-line strings are contained in triple quotes
(‘ The following functions operate on string expressions. Most of them return a string, however some of these functions actually return an integer and can be used as part of an integer expression!
Character mapsWhen writing text strings that are meant to be displayed on the Game Boy, the character encoding in the ROM may need to be different than the source file encoding. For example, the tiles used for uppercase letters may be placed starting at tile index 128, which differs from ASCII starting at 65.Character maps allow mapping strings to arbitrary 8-bit values: CHARMAP "<LF>", 10 CHARMAP "í", 20 CHARMAP "A", 128 db
"Amen<LF>" ’ being equivalent to
‘db 128, 109, 101, 110, 10 ’.
Any characters in a string without defined mappings will be copied directly, using the source file's encoding of characters to bytes. It is possible to create multiple character maps and then switch between them as desired. This can be used to encode debug information in ASCII and use a different encoding for other purposes, for example. Initially, there is one character map called ‘main’ and it is automatically selected as the current character map from the beginning. There is also a character map stack that can be used to save and restore which character map is currently active.
Note: Modifications to a character map take effect immediately from that point onward. Other functionsThere are a few other functions that do various useful things:
SECTIONSBefore you can start writing code, you must define a section. This tells the assembler what kind of information follows and, if it is code, where to put it.SECTION name,
type SECTION name,
type, options SECTION name,
type[addr] SECTION name,
type[addr],
options name is a string enclosed in double quotes, and can be a new name or the name of an existing section. If the type doesn't match, an error occurs. All other sections must have a unique name, even in different source files, or the linker will treat it as an error. Possible section types are as follows:
Since RGBDS produces ROMs, code and data can only be placed in
options are comma-separated and may include:
If [addr] is not specified, the section is
considered “floating”; the linker will automatically calculate
an appropriate address for the section. Similarly, if
Sections can also be placed by using a linker script file. The format is described in rgblink(5). They allow the user to place floating sections in the desired bank in the order specified in the script. This is useful if the sections can't be placed at an address manually because the size may change, but they have to be together. Section examples:
Section stackPOPS and PUSHS provide the
interface to the section stack. The number of entries in the stack is limited
only by the amount of memory in your machine.
RAM codeSometimes you want to have some code in RAM. But then you can't simply put it in a RAM section, you have to store it in ROM and copy it to RAM at some point.This means the code (or data) will not be stored in the place it
gets executed. Luckily, SECTION "LOAD example", ROMX CopyCode: ld de, RAMCode ld hl, RAMLocation ld c, RAMLocation.end - RAMLocation .loop ld a, [de] inc de ld [hli], a dec c jr nz, .loop ret RAMCode: LOAD "RAM code", WRAM0 RAMLocation: ld hl, .string ld de, $9864 .copy ld a, [hli] ld [de], a inc de and a jr nz, .copy ret .string db "Hello World!", 0 .end ENDL A In the example above, all of the code and data will end up in the "LOAD example" section. You will notice the ‘RAMCode’ and ‘RAMLocation’ labels. The former is situated in ROM, where the code is stored, the latter in RAM, where the code will be loaded. You cannot nest
Unionized sectionsWhen you're tight on RAM, you may want to define overlapping static memory allocations, as explained in the Unions section. However, aUNION only works within a single
file, so it can't be used e.g. to define temporary variables across several
files, all of which use the same statically allocated memory. Unionized
sections solve this problem. To declare an unionized section, add a
UNION keyword after the
SECTION one; the declaration is otherwise not
different. Unionized sections follow some different rules from normal
sections:
Different declarations of the same unionized section are not appended, but instead overlaid on top of eachother, just like Unions. Similarly, the size of an unionized section is the largest of all its declarations. Section fragmentsSection fragments are sections with a small twist: when several of the same name are encountered, they are concatenated instead of producing an error. This works within the same file (paralleling the behavior "plain" sections has in previous versions), but also across object files. To declare an section fragment, add aFRAGMENT keyword after the
SECTION one; the declaration is otherwise not
different. However, similarly to
Unionized sections, some rules
must be followed:
When RGBASM merges two fragments, the one encountered later is appended to the one encountered earlier. When RGBLINK merges two fragments, the one whose file was
specified last is appended to the one whose file was specified first. For
example, assuming ‘ rgblink -o rom.gb baz.o foo.o
bar.o baz.o ’
first, followed by the one from ‘foo.o ’,
and the one from ‘bar.o ’ last.
SYMBOLSRGBDS supports several types of symbols:
Symbol names can contain ASCII letters, numbers, underscores
‘_’, hashes ‘#’ and at signs ‘@’.
However, they must begin with either a letter or an underscore.
Additionally, label names can contain up to a single dot
‘ A symbol cannot have the same name as a reserved keyword. LabelsOne of the assembler's main tasks is to keep track of addresses for you, so you can work with meaningful names instead of “magic” numbers. Labels enable just that: a label ties a name to a specific location within a section. A label resolves to a bank and address, determined at the same time as its parent section's (see further in this section).A label is defined by writing its name at the beginning of a line,
followed by one or two colons, without any whitespace between the label name
and the colon(s). Declaring a label (global or local) with two colons
‘ A label is said to be local if its name contains
a dot ‘ For convenience, local labels can use a shorthand syntax: when a symbol name starting with a dot is found (for example, inside an expression, or when declaring a label), then the current “label scope” is implicitly prepended. Defining a global label sets it as the current “label scope”, until the next global label definition, or the end of the current section. Here are some examples of label definitions: GlobalLabel: AnotherGlobal: .locallabel ; This defines "AnotherGlobal.locallabel" .another_local: AnotherGlobal.with_another_local: ThisWillBeExported:: ; Note the two colons ThisWillBeExported.too:: In a numeric expression, a label evaluates to its address in
memory. (To obtain its bank, use the
‘ SECTION "Player tiles", VRAM PlayerTiles: ds 6 * 16 A label's location (and thus value) is usually not determined until the linking stage, so labels usually cannot be used as constants. However, if the section in which the label is defined has a fixed base address, its value is known at assembly time. Also, while Anonymous labelsAnonymous labels are useful for short blocks of code. They are defined like normal labels, but without a name before the colon. Anonymous labels are independent of label scoping, so defining one does not change the scoped label, and referencing one is not affected by the current scoped label.Anonymous labels are referenced using a colon
‘ ld hl, :++ : ld a, [hli] ; referenced by "jr nz" ldh [c], a dec c jr nz, :- ret : ; referenced by "ld hl" dw $7FFF, $1061, $03E0, $58A5 VariablesAn equal sign= is used to define mutable numeric
symbols. Unlike the other symbols described below, variables can be redefined.
This is useful for internal symbols in macros, for counters, etc.
DEF ARRAY_SIZE EQU 4 DEF COUNT = 2 DEF COUNT = 3 DEF COUNT = ARRAY_SIZE + COUNT COUNT = COUNT*2 ; COUNT now has the value 14 Note that colons ‘ Variables can be conveniently redefined by compound assignment operators like in C:
Examples: DEF x = 10 DEF x += 1 ; x == 11 DEF y = x - 1 ; y == 10 DEF y *= 2 ; y == 20 DEF y >>= 1 ; y == 10 DEF x ^= y ; x == 1 Numeric constantsEQU is used to define immutable numeric symbols. Unlike
= above, constants defined this way cannot be
redefined. These constants can be used for unchanging values such as
properties of the hardware.
def SCREEN_WIDTH equ 160 ; In pixels def SCREEN_HEIGHT equ 144 Note that colons ‘ If you really need to, the
def NUM_ITEMS equ 0 MACRO add_item redef NUM_ITEMS equ NUM_ITEMS + 1 def ITEM_{02x:NUM_ITEMS} equ \1 ENDM add_item 1 add_item 4 add_item 9 add_item 16 assert NUM_ITEMS == 4 assert ITEM_04 == 16 Offset constantsThe RS group of commands is a handy way of defining structure offsets:RSRESET DEF str_pStuff RW 1 DEF str_tData RB 256 DEF str_bCount RB 1 DEF str_SIZEOF RB 0 The example defines four constants as if by: DEF str_pStuff EQU 0 DEF str_tData EQU 2 DEF str_bCount EQU 258 DEF str_SIZEOF EQU 259 There are five commands in the RS group of commands:
If the argument to Note that colons ‘ String constantsEQUS is used to define string constant symbols. Wherever
the assembler reads a string constant, it gets expanded: the
symbol's name is replaced with its contents. If you are familiar with C, you
can think of it as similar to #define . This expansion
is disabled in a few contexts:
‘DEF(name) ’,
‘DEF name EQU/=/EQUS/etc ... ’,
‘PURGE name ’, and
‘MACRO name ’ will not expand string
constants in their names.
DEF COUNTREG EQUS "[hl+]" ld a,COUNTREG DEF PLAYER_NAME EQUS "\"John\"" db PLAYER_NAME This will be interpreted as: ld a,[hl+] db "John" String constants can also be used to define small one-line macros: DEF pusha EQUS "push af\npush bc\npush de\npush hl\n" Note that colons ‘ String constants can't be exported or imported. String constants, like numeric constants, cannot be redefined.
However, the DEF s EQUS "Hello, " REDEF s EQUS "{s}world!" ; prints "Hello, world!" PRINTLN "{s}0 Important note: When a string constant is
expanded, its expansion may contain another string constant, which will be
expanded as well. If this creates an infinite loop,
The examples above for
‘ X EQUS "Y" ; this defines Y, not X! X EQU 42 ; prints "Y $2A" PRINTLN "{X} {Y}" MacrosOne of the best features of an assembler is the ability to write macros for it. Macros can be called with arguments, and can react depending on input usingIF constructs.
MACRO MyMacro ld a, 80 call MyFunc ENDM The example above defines
‘ Macros can't be exported or imported. Plainly nesting macro definitions is not allowed, but this can be
worked around using MACRO outer MACRO inner PRINTLN "Hello!" ENDM ENDM But this will: MACRO outer DEF definition EQUS "MACRO inner\nPRINTLN \"Hello!\"\nENDM" definition PURGE definition ENDM Macro arguments support all the escape sequences of strings, as
well as ‘ Exporting and importing symbolsImporting and exporting of symbols is a feature that is very useful when your project spans many source files and, for example, you need to jump to a routine defined in another file.Exporting of symbols has to be done manually, importing is done
automatically if The following will cause symbol1, symbol2 and so on to be accessible to other files during the link process:
For example, if you have the following three files: ‘ SECTION "a", WRAM0 LabelA: ‘ SECTION "b", WRAM0 ExportedLabelB1:: ExportedLabelB2: EXPORT ExportedLabelB2 ‘ SECTION "C", ROM0[0] dw LabelA dw ExportedLabelB1 dw ExportedLabelB2 Then ‘ $ rgbasm -o a.o a.asm $ rgbasm -o b.o b.asm $ rgbasm -o c.o c.asm $ rgblink a.o b.o c.o error: c.asm(2): Unknown symbol "LabelA" Linking failed with 1 error Note also that only exported symbols will appear in symbol and map files produced by rgblink(1). Purging symbolsPURGE allows you to completely remove a symbol from the
symbol table as if it had never existed. USE WITH EXTREME
CAUTION!!! I can't stress this enough, you seriously need to
know what you are doing. DON'T purge a symbol that you use in expressions
the linker needs to calculate. When not sure, it's probably not safe to purge
anything other than variables, numeric or string constants, or macros.
DEF Kamikaze EQUS "I don't want to live anymore" DEF AOLer EQUS "Me too" PURGE Kamikaze, AOLer String constants are not expanded within the symbol names. Predeclared symbolsThe following symbols are defined by the assembler:
The current time values will be taken from the
DEFINING DATAStatically allocating space in RAMDS statically allocates a number of empty bytes. This is
the preferred method of allocating space in a RAM section. You can also use
DB , DW and
DL without any arguments instead (see
Defining constant data in
ROM below).
DS 42 ; Allocates 42 bytes Empty space in RAM sections will not be initialized. In ROM
sections, it will be filled with the value passed to the
Defining constant data in ROMDB defines a list of bytes that will be stored in the
final image. Ideal for tables and text.
DB 1,2,3,4,"This is a string" Alternatively, you can use Strings are handled a little specially: they first undergo charmap conversion (see Character maps), then each resulting character is output individually. For example, under the default charmap, the following two lines are identical: DW "Hello!" DW "H", "e", "l", "l", "o", "!" If you do not want this special handling, enclose the string in parentheses.
; outputs 3 bytes: $AA, $AA, $AA DS 3, $AA ; outputs 7 bytes: $BB, $CC, $BB, $CC, $BB, $CC, $BB DS 7, $BB, $CC You can also use Including binary filesYou probably have some graphics, level data, etc. you'd like to include. UseINCBIN to include a raw binary file as it is. If the
file isn't found in the current directory, the include-path list passed to
rgbasm(1)
(see the -i option) on the command line will be
searched.
INCBIN "titlepic.bin" INCBIN "sprites/hero.bin" You can also include only part of a file with
INCBIN "data.bin",78,256 The length argument is optional. If only the start position is specified, the bytes from the start position until the end of the file will be included. UnionsUnions allow multiple static memory allocations to overlap, like unions in C. This does not increase the amount of memory available, but allows re-using the same memory region for different purposes.A union starts with a ; Let's say PC = $C0DE here UNION ; Here, PC = $C0DE Name: ds 8 ; PC = $C0E6 Nickname: ds 8 ; PC = $C0EE NEXTU ; PC is back to $C0DE Health: dw ; PC = $C0E0 Something: ds 6 ; And so on Lives: db NEXTU VideoBuffer: ds 19 ENDU In the example above, ‘Name, Health, VideoBuffer’
all have the same value, as do ‘Nickname’ and
‘Lives’. Thus, keep in mind that The size of this union is 19 bytes, as this is the size of the largest block (the last one, containing ‘VideoBuffer’). Nesting unions is possible, with each inner union's size being considered as described above. Unions may be used in any section, but inside them may only be
THE MACRO LANGUAGEInvoking macrosYou execute the macro by inserting its name.add a,b ld sp,hl MyMacro ; This will be expanded sub a,87 It's valid to call a macro from a macro (yes, even the same one). When Suppose your macro contains a loop. MACRO LoopyMacro xor a,a .loop ld [hl+],a dec c jr nz,.loop ENDM This is fine, but only if you use the macro no more than once per
scope. To get around this problem, there is the escape sequence
MACRO LoopyMacro xor a,a .loop\@ ld [hl+],a dec c jr nz,.loop\@ ENDM Important note: Since a macro can call itself
(or a different macro that calls the first one), there can be circular
dependency problems. If this creates an infinite loop,
It's possible to pass arguments to macros as well! You retrieve
the arguments by using the escape sequences MACRO LoopyMacro ld hl,\1 ld c,\2 xor a,a .loop\@ ld [hl+],a dec c jr nz,.loop\@ ENDM Now you can call the macro specifying two arguments, the first being the address and the second being a byte count. The generated code will then reset all bytes in this range. LoopyMacro MyVars,54 Arguments are passed as string constants, although there's no need
to enclose them in quotes. Thus, an expression will not be evaluated first
but kind of copy-pasted. This means that it's probably a very good idea to
use brackets around MACRO print_double PRINTLN \1 * 2 ENDM print_double 1 + 2 The Line continuations work as usual inside macros or lists of macro arguments. However, some characters need to be escaped, as in the following example: MACRO PrintMacro1 PRINTLN STRCAT(\1) ENDM PrintMacro1 "Hello "\, \ "world" MACRO PrintMacro2 PRINT \1 ENDM PrintMacro2 STRCAT("Hello ", \ "world\n") The comma in ‘ Since there are only nine digits, you can only access the first
nine macro arguments like this. To use the rest, you need to put the
multi-digit argument number in angle brackets, like
‘ Other macro arguments and symbol interpolations will be expanded
inside the angle brackets. For example, if
‘ Another way to access more than nine macro arguments is the
Printing things during assemblyThePRINT and PRINTLN commands
print text and values to the standard output. Useful for debugging macros, or
wherever you may feel the need to tell yourself some important information.
PRINT "Hello world!\n" PRINTLN "Hello world!" PRINT _NARG, " arguments\n" PRINTLN "sum: ", 2+3, " product: ", 2*3 PRINTLN "Line #", __LINE__ PRINTLN STRFMT("E = %f", 2.718) Automatically repeating blocks of codeSuppose you want to unroll a time consuming loop without copy-pasting it.REPT is here for that purpose. Everything between
REPT and the matching ENDR
will be repeated a number of times just as if you had done a copy/paste
operation yourself. The following example will assemble
‘add a,c ’ four times:
REPT 4 add a,c ENDR You can also use ; Generate a 256-byte sine table with values in the range [0, 128] ; (shifted and scaled from the range [-1.0, 1.0]) ANGLE = 0.0 REPT 256 db (MUL(64.0, SIN(ANGLE)) + 64.0) >> 16 ANGLE = ANGLE + 256.0 ; 256.0 = 65536 degrees / 256 entries ENDR As in macros, you can also use the escape sequence
A common pattern is to repeat a block for each value in some
range. FOR N, 256 dw N * N ENDR It acts just as if you had done: N = 0 dw N * N N = 1 dw N * N N = 2 dw N * N ; ... N = 255 dw N * N N = 256 You can customize the range of
The FOR V, 4, 25, 5 PRINT "{d:V} " ENDR PRINTLN "done {d:V}" This will print: 4 9 14 19 24 done 29 Just like with You can stop a repeating block with the
FOR V, 1, 100 PRINT "{d:V}" IF V == 5 PRINT " stop! " BREAK ENDC PRINT ", " ENDR PRINTLN "done {d:V}" This will print: 1, 2, 3, 4, 5 stop! done 5 Aborting the assembly processFAIL and WARN can be used to
print errors and warnings respectively during the assembly process. This is
especially useful for macros that get an invalid argument.
FAIL and WARN take a string as
the only argument and they will print this string out as a normal error with a
line number.
If you need to ensure some assumption is correct when compiling,
you can use Function: xor a ASSERT LOW(MyByte) == 0 ld h, HIGH(MyByte) ld l, a ld a, [hli] ; You can also indent this! ASSERT BANK(OtherFunction) == BANK(Function) call OtherFunction ; Lowercase also works ld hl, FirstByte ld a, [hli] assert FirstByte + 1 == SecondByte ld b, [hl] ret .end ; If you specify one, a message will be printed STATIC_ASSERT .end - Function < 256, "Function is too large!" First, the difference between Second, as shown above, a string can be optionally added at the end, to give insight into what the assertion is checking. Finally, you can add one of Including other source filesUseINCLUDE to process another assembler file and then
return to the current file when done. If the file isn't found in the current
directory, the include path list (see the -i option in
rgbasm(1))
will be searched. You may nest INCLUDE calls
infinitely (or until you run out of memory, whichever comes first).
INCLUDE "irq.inc" Conditional assemblingThe four commandsIF , ELIF ,
ELSE , and ENDC let you have
rgbasm skip over parts of your code depending on a
condition. This is a powerful feature commonly used in macros.
IF NUM < 0 PRINTLN "NUM < 0" ELIF NUM == 0 PRINTLN "NUM == 0" ELSE PRINTLN "NUM > 0" ENDC The Note that if an MISCELLANEOUSChanging options while assemblingOPT can be used to change some of the options during
assembling from within the source, instead of defining them on the
command-line.
PUSHO OPT g.oOX, Wdiv, L ; acts like command-line -g.oOX -Wdiv -L DW `..ooOOXX ; uses the graphics constant characters from OPT g PRINTLN $80000000/-1 ; prints a warning about division LD [$FF88], A ; encoded as LD, not LDH POPO DW `00112233 ; uses the default graphics constant characters PRINTLN $80000000/-1 ; no warning by default LD [$FF88], A ; optimized to use LDH by default The options that OPT can modify are currently:
Requesting alignmentWhileALIGN as presented in
SECTIONS is often useful as-is, sometimes
you instead want a particular piece of data (or code) in the middle of the
section to be aligned. This is made easier through the use of mid-section
ALIGN align,
offset. It will alter the section's attributes to ensure
that the location the ALIGN directive is at, has its
align lower bits equal to offset.
If the constraint cannot be met (for example because the section
is fixed at an incompatible address), an error is produced. Note that
SEE ALSOrgbasm(1), rgblink(1), rgblink(5), rgbds(5), rgbds(7), gbz80(7)HISTORYrgbasm was originally written by Carsten Sørensen
as part of the ASMotor package, and was later packaged in RGBDS by Justin
Lloyd. It is now maintained by a number of contributors at
https://github.com/gbdev/rgbds.
Visit the GSP FreeBSD Man Page Interface. |