mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
For some reason, `No` looks weird in the HTML version of the docs. Some other random fixes. Tables in src/asm/rgbasm.5 are still broken in the HTML docs. Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
1009 lines
29 KiB
Groff
1009 lines
29 KiB
Groff
.\" Copyright (c) 2017 Antonio Nino Diaz <antonio_nd@outlook.com>
|
||
.\"
|
||
.\" Permission to use, copy, modify, and distribute this software for any
|
||
.\" purpose with or without fee is hereby granted, provided that the above
|
||
.\" copyright notice and this permission notice appear in all copies.
|
||
.\"
|
||
.\" THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||
.\"
|
||
.Dd April 16, 2017
|
||
.Dt RGBASM 5
|
||
.Os RGBDS Manual
|
||
.Sh NAME
|
||
.Nm rgbasm
|
||
.Nd language documentation
|
||
.Sh DESCRIPTION
|
||
This is the full description of the language used by
|
||
.Xr rgbasm 1 .
|
||
The description of the instructions supported by the GameBoy CPU is in
|
||
.Xr gbz80 7 .
|
||
.Pp
|
||
.Sh GENERAL
|
||
.Ss Syntax
|
||
The syntax is line‐based, just as in any other assembler, meaning that you do
|
||
one instruction or pseudo‐op per line:
|
||
.Pp
|
||
.Dl Oo Ar label Oc Oo Ar instruction Oc Oo Ar \&;comment Oc
|
||
.Pp
|
||
Example:
|
||
.Pp
|
||
.Dl John: ld a,87 ;Weee
|
||
.Pp
|
||
All pseudo‐ops, mnemonics and registers (reserved keywords) are case‐insensitive
|
||
and all labels are case‐sensitive.
|
||
.Ss Sections
|
||
Before 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.
|
||
.Pp
|
||
.Dl SECTION \[dq]CoolStuff\[dq],ROMX
|
||
.Pp
|
||
This switches to the section called "CoolStuff" (or creates it if it doesn't
|
||
already exist) and it defines it as a code section.
|
||
All sections assembled at the same time that have the same name, type, etc, are
|
||
considered to be the same one, and their code is put together in the object file
|
||
generated by the assembler.
|
||
All other sections must have a unique name, even in different source files, or
|
||
the linker will treat it as an error.
|
||
.Pp
|
||
Possible section types are as follows:
|
||
.Pp
|
||
.Bl -tag
|
||
.It Sy ROM0
|
||
A ROM section.
|
||
Mapped to memory at $0000–$3FFF (or $0000-$7FFF if tiny ROM mode is enabled in
|
||
.Xr rgblink 1 ) .
|
||
.It Sy ROMX
|
||
A banked ROM section.
|
||
Mapped to memory at $4000–$7FFF.
|
||
Valid banks range from 1 to 511.
|
||
Not available if tiny ROM mode is enabled in
|
||
.Xr rgblink 1 .
|
||
.It Sy VRAM
|
||
A banked video RAM section.
|
||
Mapped to memory at $8000–$9FFF.
|
||
Can only allocate memory, not fill it.
|
||
Valid banks are 0 and 1 but bank 1 isn't available if DMG mode is enabled in
|
||
.Xr rgblink 1 .
|
||
.It Sy SRAM
|
||
A banked external (save) RAM section.
|
||
Mapped to memory at $A000–$BFFF.
|
||
Can only allocate memory, not fill it.
|
||
Valid banks range from 0 to 15.
|
||
.It Sy WRAM0
|
||
A general-purpose RAM section.
|
||
Mapped to memory at $C000–$CFFF, or $C000-$DFFF if DMG mode is enabled in
|
||
.Xr rgblink 1 .
|
||
Can only allocate memory, not fill it.
|
||
.It Sy WRAMX
|
||
A banked general-purpose RAM section.
|
||
Mapped to memory at $D000–$DFFF.
|
||
Can only allocate memory, not fill it.
|
||
Valid banks range from 1 to 7.
|
||
Not available if DMG mode is enabled in
|
||
.Xr rgblink 1 .
|
||
.It Sy OAM
|
||
An object attributes RAM section.
|
||
Mapped to memory at $FE00-$FE9F.
|
||
Can only allocate memory, not fill it.
|
||
.It Sy HRAM
|
||
A high RAM section.
|
||
Mapped to memory at $FF80–$FFFE.
|
||
Can only allocate memory, not fill it.
|
||
.Pp
|
||
NOTE: If you use this method of allocating HRAM the assembler will NOT choose
|
||
the short addressing mode in the LD instructions
|
||
.Sy LD [$FF00+n8],A
|
||
and
|
||
.Sy LD A,[$FF00+n8]
|
||
because the actual address calculation is done by the linker.
|
||
If you find this undesirable you can use
|
||
.Ic RSSET No / Ic RB No / Ic RW
|
||
instead or use the
|
||
.Sy LDH [$FF00+n8],A
|
||
and
|
||
.Sy LDH A,[$FF00+n8]
|
||
syntax instead.
|
||
This forces the assembler to emit the correct instruction and the linker to
|
||
check if the value is in the correct range.
|
||
.El
|
||
.Pp
|
||
A section is usually defined as a floating one, but the code can restrict where
|
||
the linker can place it.
|
||
.Pp
|
||
If a section is defined with no indications, it is a floating section.
|
||
The linker will decide where to place it in the final binary and it has no
|
||
obligation to follow any specific rules.
|
||
The following example defines a section that can be placed anywhere in any ROMX
|
||
bank:
|
||
.Pp
|
||
.Dl SECTION \[dq]CoolStuff\[dq],ROMX
|
||
.Pp
|
||
If it is needed, the following syntax can be used to fix the base address of the
|
||
section:
|
||
.Pp
|
||
.Dl SECTION \[dq]CoolStuff\[dq],ROMX[$4567]
|
||
.Pp
|
||
It won't, however, fix the bank number, which is left to the linker.
|
||
If you also want to specify the bank you can do:
|
||
.Pp
|
||
.Dl SECTION \[dq]CoolStuff\[dq],ROMX[$4567],BANK[3]
|
||
.Pp
|
||
And if you only want to force the section into a certain bank, and not it's
|
||
position within the bank, that's also possible:
|
||
.Pp
|
||
.Dl SECTION \[dq]CoolStuff\[dq],ROMX,BANK[7]
|
||
.Pp
|
||
In addition, you can specify byte alignment for a section.
|
||
This ensures that the section starts at a memory address where the given number
|
||
of least-significant bits are 0.
|
||
This can be used along with
|
||
.Ic BANK ,
|
||
if desired.
|
||
However, if an alignment is specified, the base address must be left unassigned.
|
||
This can be useful when using DMA to copy data or when it is needed to align the
|
||
start of an array to 256 bytes to optimize the code that accesses it.
|
||
.Pp
|
||
.Dl SECTION \[dq]OAM Data\[dq],WRAM0,ALIGN[8] ; align to 256 bytes
|
||
.Pp
|
||
.Dl SECTION \[dq]VRAM Data\[dq],ROMX,BANK[2],ALIGN[4] ; align to 16 bytes
|
||
.Pp
|
||
HINT: If you think this is a lot of typing for doing a simple
|
||
.Ic ORG
|
||
type thing you can quite easily write an intelligent macro (called
|
||
.Ic ORG
|
||
for example) that uses
|
||
.Ic \@
|
||
for the section name and determines
|
||
correct section type etc as arguments for
|
||
.Ic SECTION .
|
||
.Pp
|
||
.Ic POPS
|
||
and
|
||
.Ic PUSHS
|
||
provide the interface to the section stack.
|
||
.Ic PUSHS
|
||
will push the current section context on the section stack.
|
||
.Ic POPS
|
||
can then later be used to restore it.
|
||
Useful for defining sections in included files when you don't want to destroy
|
||
the section context for the program that included your file.
|
||
The number of entries in the stack is limited only by the amount of memory in
|
||
your machine.
|
||
.Pp
|
||
Sections can also be placed by using a linkerscript file.
|
||
The format is described in
|
||
.Xr 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.
|
||
.Pp
|
||
.Sh SYMBOLS
|
||
.Pp
|
||
.Ss Symbols
|
||
RGBDS supports several types of symbols:
|
||
.Pp
|
||
.Bl -hang
|
||
.It Sy Label
|
||
Used to assign a memory location with a name
|
||
.It Sy EQUate
|
||
Give a constant a name.
|
||
.It Sy SET
|
||
Almost the same as EQUate, but you can change the value of a SET during
|
||
assembling.
|
||
.It Sy Structure Po Sy the RS group Pc
|
||
Define a structure easily.
|
||
.It Sy String equate Pq Sy EQUS
|
||
Give a frequently used string a name.
|
||
Can also be used as a mini-macro, like #define in C.
|
||
.It Sy MACRO
|
||
A block of code or pseudo instructions that you invoke like any other mnemonic.
|
||
You can give them arguments too.
|
||
.El
|
||
.Pp
|
||
A symbol cannot have the same name as a reserved keyword.
|
||
.Bl -hang
|
||
.It Sy Label
|
||
.Pp
|
||
One of the assembler's main tasks is to keep track of addresses for you so you
|
||
don't have to remember obscure numbers but can make do with a meaningful name, a
|
||
label.
|
||
.Pp
|
||
This can be done in a number of ways:
|
||
.Pp
|
||
.Bd -literal -offset indent
|
||
GlobalLabel
|
||
AnotherGlobal:
|
||
\&.locallabel
|
||
\&.yet_a_local:
|
||
ThisWillBeExported:: ;note the two colons
|
||
.Ed
|
||
.Pp
|
||
In the line where a label is defined there musn't be any whitespace before it.
|
||
Local labels are only accessible within the scope they are defined.
|
||
A scope starts after a global label and ends at the next global label.
|
||
Declaring a normal label with :: does an EXPORT at the same time.
|
||
.Pp
|
||
Labels will normally change their value during the link process and are thus not
|
||
constant.
|
||
The exception is the case in which the base address of a section is fixed, so
|
||
the address of the label is known at assembly time.
|
||
.Pp
|
||
The subtraction of two labels is only constant (known at assembly time) if they
|
||
are two local labels that belong to the same scope, or they are two global
|
||
labels that belong to sections with fixed base addresses.
|
||
.Pp
|
||
.It Sy EQU
|
||
.Pp
|
||
EQUates are constant symbols.
|
||
They can, for example, be used for things such as bit-definitions of hardware
|
||
registers.
|
||
.Pp
|
||
.Dl EXIT_OK EQU $00
|
||
.Dl EXIT_FAILURE EQU $01
|
||
.Pp
|
||
Note that a colon (:) following the label-name is not allowed.
|
||
EQUates cannot be exported and imported.
|
||
They don't change their value during the link process.
|
||
.It Sy SET
|
||
.Pp
|
||
SETs are similar to EQUates.
|
||
They are also constant symbols in the sense that their values are defined during
|
||
the assembly process.
|
||
These symbols are normally used in macros.
|
||
.Pp
|
||
.Bd -literal -offset indent
|
||
ARRAY_SIZE EQU 4
|
||
COUNT SET 2
|
||
COUNT SET ARRAY_SIZE+COUNT
|
||
.Ed
|
||
.Pp
|
||
Note that a colon (:) following the label-name is not allowed.
|
||
SETs cannot be exported and imported.
|
||
Alternatively you can use = as a synonym for SET.
|
||
.Pp
|
||
.Dl COUNT = 2
|
||
.Pp
|
||
.It Sy RSSET , RERESET , RB , RW
|
||
.Pp
|
||
The RS group of commands is a handy way of defining structures:
|
||
.Pp
|
||
.Bd -literal -offset indent
|
||
RSRESET
|
||
str_pStuff RW 1
|
||
str_tData RB 256
|
||
str_bCount RB 1
|
||
str_SIZEOF RB 0
|
||
.Ed
|
||
.Pp
|
||
The example defines four equated symbols:
|
||
.Pp
|
||
.Bd -literal -offset indent
|
||
str_pStuff = 0
|
||
str_tData = 2
|
||
str_bCount = 258
|
||
str_SIZEOF = 259
|
||
.Ed
|
||
.Pp
|
||
There are four commands in the RS group of commands:
|
||
.Pp
|
||
.Bl -column ".Sy String" ".Sy String"
|
||
.It Sy Command Ta Ta Ta Sy Meaning
|
||
.It Ic RSRESET No Ta Ta Resets the _RS counter to zero.
|
||
.It Ic RSSET Ar constexpr Ta Sets the
|
||
.Ic _RS No counter to Ar constexpr .
|
||
.It Ic RB Ar constexpr Ta Sets the preceding symbol to
|
||
.Ic _RS No and adds Ar constexpr No to Ic _RS .
|
||
.It Ic RW Ar constexpr Ta Sets the preceding symbol to
|
||
.Ic _RS No and adds Ar constexpr No * 2 to Ic _RS.
|
||
.El
|
||
.Pp
|
||
Note that a colon (:) following the symbol-name is not allowed.
|
||
.Sy RS
|
||
symbols cannot be exported and imported.
|
||
They don't change their value during the link process.
|
||
.Pp
|
||
.It Sy EQUS
|
||
.Pp
|
||
EQUS is used to define string-symbols.
|
||
Wherever the assembler meets a string symbol its name is replaced with its
|
||
value.
|
||
If you are familiar with C you can think of it as the same as #define.
|
||
.Pp
|
||
.Bd -literal -offset indent
|
||
COUNTREG EQUS "[hl+]"
|
||
ld a,COUNTREG
|
||
|
||
PLAYER_NAME EQUS \[dq]\[rs]\[dq]John\[rs]\[dq]\[dq]
|
||
db PLAYER_NAME
|
||
.Ed
|
||
.Pp
|
||
Note that : following the label-name is not allowed, and that strings must be
|
||
quoted to be useful.
|
||
.Pp
|
||
This will be interpreted as:
|
||
.Pp
|
||
.Dl ld a,[hl+]
|
||
.Dl db \[dq]John\[dq]
|
||
.Pp
|
||
String-symbols can also be used to define small one-line macros:
|
||
.Pp
|
||
.Dl PUSHA EQUS \[dq]push af\[rs]npush bc\[rs]npush de\[rs]npush hl\[rs]n\[dq]
|
||
.Pp
|
||
Note that a colon (:) following the label-name is not allowed.
|
||
String equates can't be exported or imported.
|
||
.Pp
|
||
.It Sy MACRO
|
||
.Pp
|
||
One of the best features of an assembler is the ability to write macros for it.
|
||
Macros also provide a method of passing arguments to them and they can then
|
||
react to the input using IF-constructs.
|
||
.Pp
|
||
.Bd -literal -offset indent
|
||
MyMacro: MACRO
|
||
ld a,80
|
||
call MyFunc
|
||
ENDM
|
||
.Ed
|
||
.Pp
|
||
Note that a colon (:) following the macro-name is required.
|
||
Macros can't be exported or imported.
|
||
It's valid to call a macro from a macro (yes, even the same one).
|
||
.Pp
|
||
The above example is a very simple macro.
|
||
You execute the macro by typing its name.
|
||
.Pp
|
||
.Bd -literal -offset indent
|
||
add a,b
|
||
ld sp,hl
|
||
MyMacro ;This will be expanded
|
||
sub a,87
|
||
.Ed
|
||
.Pp
|
||
When the assembler meets MyMacro it will insert the macrodefinition (the text
|
||
enclosed in
|
||
.Ic MACRO
|
||
/
|
||
.Ic ENDM ) .
|
||
.Pp
|
||
Suppose your macro contains a loop.
|
||
.Pp
|
||
.Bd -literal -offset indent
|
||
LoopyMacro: MACRO
|
||
xor a,a
|
||
\&.loop ld [hl+],a
|
||
dec c
|
||
jr nz,.loop
|
||
ENDM
|
||
.Ed
|
||
.Pp
|
||
This is fine.
|
||
That is, if you only use the macro once per scope.
|
||
To get around this problem there is a special label string equate called
|
||
.Ic \[rs]\@
|
||
that you can append to your labels and it will then expand to a unique string.
|
||
.Pp
|
||
.Ic \[rs]\@
|
||
also works in REPT-blocks should you have any loops there.
|
||
.Bd -literal -offset indent
|
||
LoopyMacro: MACRO
|
||
xor a,a
|
||
\&.loop\[rs]\@ ld [hl+],a
|
||
dec c
|
||
jr nz,.loop\[rs]\@
|
||
ENDM
|
||
.Ed
|
||
.Pp
|
||
.Sy Macro Arguments
|
||
.Pp
|
||
I'd like LoopyMacro a lot better if I didn't have to pre-load the registers
|
||
with values and then call it.
|
||
What I'd like is the ability to pass it arguments and it then loaded the
|
||
registers itself.
|
||
.Pp
|
||
And I can do that.
|
||
In macros you can get the arguments by using the special macro string equates
|
||
.Ic \[rs]1
|
||
through
|
||
.Ic \[rs]9 ,
|
||
.Ic \[rs]1
|
||
being the first argument
|
||
specified on the calling of the macro.
|
||
.Pp
|
||
.Bd -literal -offset indent
|
||
LoopyMacro: MACRO
|
||
ld hl,\[rs]1
|
||
ld c,\[rs]2
|
||
xor a,a
|
||
\&.loop\[rs]\@ ld [hl+],a
|
||
dec c
|
||
jr nz,.loop\[rs]\@
|
||
ENDM
|
||
.Ed
|
||
.Pp
|
||
Now I can call the macro specifying two arguments.
|
||
The first being the address and the second being a bytecount.
|
||
The macro will then reset all bytes in this range.
|
||
.Pp
|
||
.Dl LoopyMacro MyVars,54
|
||
.Pp
|
||
Arguments are passed as string equates.
|
||
There's no need to enclose them in quotes.
|
||
An expression will not be evaluated first but passed directly.
|
||
This means that it's probably a very good idea to use brackets around
|
||
.Ic \[rs]1
|
||
to
|
||
.Ic \[rs]9
|
||
if you perform further calculations on them.
|
||
For instance, if you pass 1 + 2 as the first argument and then do
|
||
.Ic PRINTV
|
||
.Ic \[rs]1
|
||
* 2
|
||
you will get the value 5 on screen and not 6 as you might have expected.
|
||
.Pp
|
||
In reality, up to 256 arguments can be passed to a macro, but you can only use
|
||
the first 9 like this. If you want to use the rest, you need to use the keyword
|
||
.Ic SHIFT .
|
||
.Pp
|
||
.Ic SHIFT
|
||
is a special command only available in macros.
|
||
Very useful in REPT-blocks.
|
||
It will "shift" the arguments by one "to the left".
|
||
.Ic \[rs]1
|
||
will get the value of
|
||
.Ic \[rs]2 ,
|
||
.Ic \[rs]2
|
||
will get the value in
|
||
.Ic \[rs]3
|
||
and so forth.
|
||
.Pp
|
||
This is the only way of accessing the value of arguments from 10 to 256.
|
||
.Pp
|
||
.El
|
||
.Ss Exporting and importing symbols
|
||
Importing 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.
|
||
.Pp
|
||
Exporting of symbols has to be done manually, importing is done automatically
|
||
if the assembler doesn't know where a symbol is defined.
|
||
.Pp
|
||
.Ic EXPORT Ar label Bq , Ar label No , ...
|
||
.Pp
|
||
The assembler will make label accessible to other files during the link process.
|
||
.Pp
|
||
.Ic GLOBAL Ar label Bq , Ar label No , ...
|
||
.Pp
|
||
If label is defined during the assembly it will be exported, if not, it will be
|
||
imported.
|
||
Handy (very!) for include-files.
|
||
Note that, since importing is done automatically, this keyword has the same
|
||
effect as
|
||
.Ic EXPORT .
|
||
.Ss Purging symbols
|
||
.Ic PURGE
|
||
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 symbol that you use in expressions the linker needs to calculate.
|
||
In fact, it's probably not even safe to purge anything other than string symbols
|
||
and macros.
|
||
.Pp
|
||
.Bd -literal -offset indent
|
||
Kamikaze EQUS \[dq]I don't want to live anymore\[dq]
|
||
AOLer EQUS \[dq]Me too\[dq]
|
||
PURGE Kamikaze, AOLer
|
||
.Ed
|
||
.Pp
|
||
Note that string symbols that are part of a
|
||
.Ic PURGE
|
||
command WILL NOT BE EXPANDED as the ONLY exception to this rule.
|
||
.Ss Predeclared Symbols
|
||
The following symbols are defined by the assembler:
|
||
.Pp
|
||
.Bl -column -offset indent ".Sy String" ".Sy String" ".Sy String"
|
||
.It Sy Type Ta Sy Name Ta Ta Sy Contents
|
||
.It Ic EQU Ta Ic \@ Ta Ta PC value
|
||
.It Ic EQU Ta Ic _PI Ta Ta Fixed point \[*p]
|
||
.It Ic SET Ta Ic _RS Ta Ta _RS Counter
|
||
.It Ic EQU Ta Ic _NARG Ta Ta Number of arguments passed to macro
|
||
.It Ic EQU Ta Ic __LINE__ Ta Ta The current line number
|
||
.It Ic EQUS Ta Ic __FILE__ Ta Ta The current filename
|
||
.It Ic EQUS Ta Ic __DATE__ Ta Ta Today's date
|
||
.It Ic EQUS Ta Ic __TIME__ Ta Ta The current time
|
||
.It Ic EQUS Ta Ic __ISO_8601_LOCAL__ Ta ISO 8601 timestamp (local)
|
||
.It Ic EQUS Ta Ic __ISO_8601_UTC__ Ta ISO 8601 timestamp (UTC)
|
||
.El
|
||
.Pp
|
||
.Sh DEFINING DATA
|
||
.Ss Defining constant data
|
||
.Ic DB
|
||
defines a list of bytes that will be stored in the final image.
|
||
Ideal for tables and text.
|
||
.Pp
|
||
.Dl DB 1,2,3,4,\[dq]This is a string\[dq]
|
||
.Pp
|
||
Alternatively, you can use
|
||
.Ic DW
|
||
to store a list of words.
|
||
Strings are not allowed as arguments to
|
||
.Ic DW .
|
||
.Pp
|
||
You can also use
|
||
.Ic DB
|
||
and
|
||
.Ic DW
|
||
without arguments.
|
||
This works exactly like
|
||
.Sy DS 1
|
||
and
|
||
.Sy DS 2
|
||
respectively.
|
||
Consequently,
|
||
.Ic DB
|
||
and
|
||
.Ic DW
|
||
can be used in a
|
||
.Sy WRAM0 No / Sy WRAMX No / Sy HRAM No / Sy VRAM No / Sy SRAM
|
||
section.
|
||
.Ss Declaring variables in a RAM section
|
||
.Ic DS
|
||
allocates a number of bytes.
|
||
The content is undefined.
|
||
This is the preferred method of allocationg space in a RAM section.
|
||
You can, however, use
|
||
.Ic DB
|
||
and
|
||
.Ic DW
|
||
without any arguments instead.
|
||
.Pp
|
||
.Dl DS str_SIZEOF ;allocate str_SIZEOF bytes
|
||
.Pp
|
||
.Ss Including binary files
|
||
You probably have some graphics you'd like to include.
|
||
Use
|
||
.Ic INCBIN
|
||
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 the linker on the command line will be searched.
|
||
.Pp
|
||
.Dl INCBIN \[dq]titlepic.bin\[dq]
|
||
.Dl INCBIN \[dq]sprites/hero.bin\[dq]\ ; UNIX
|
||
.Dl INCBIN \[dq]sprites\[rs]\[rs]hero.bin\[dq]\ ; Windows
|
||
.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.
|
||
.Pp
|
||
.Dl INCBIN \[dq]data.bin\[dq],78,256
|
||
.Sh THE MACRO LANGUAGE
|
||
.Pp
|
||
.Ss Printing things during assembly
|
||
These three instructions type text and values to stdout.
|
||
Useful for debugging macros or wherever you may feel the need to tell yourself
|
||
some important information.
|
||
.Pp
|
||
.Bd -literal -offset indent
|
||
PRINTT \[dq]I'm the greatest programmer in the whole wide world\[rs]n\[dq]
|
||
PRINTV (2+3)/5
|
||
PRINTF MUL(3.14,3987.0)
|
||
.Ed
|
||
.Pp
|
||
.Bl -inset
|
||
.It Ic PRINTT
|
||
prints out a string.
|
||
.It Ic PRINTV
|
||
prints out an integer value or, as in the example, the result of a calculation.
|
||
Unsurprisingly, you can also print out a constant symbols value.
|
||
.It Ic PRINTF
|
||
prints out a fixed point value.
|
||
.El
|
||
.Ss Automatically repeating blocks of code
|
||
Suppose you're feeling lazy and you want to unroll a time consuming loop.
|
||
.Ic REPT
|
||
is here for that purpose.
|
||
Everything between
|
||
.Ic REPT
|
||
and
|
||
.Ic ENDR
|
||
will be repeated a number of times just as if you done a copy/paste operation
|
||
yourself.
|
||
The following example will assemble
|
||
.Sy add a,c
|
||
four times:
|
||
.Pp
|
||
.Bd -literal -offset indent
|
||
REPT 4
|
||
add a,c
|
||
ENDR
|
||
.Ed
|
||
.Pp
|
||
You can also use
|
||
.Ic REPT
|
||
to generate tables on the fly:
|
||
.Pp
|
||
.Bd -literal -offset indent
|
||
; --
|
||
; -- Generate a 256 byte sine table with values between 0 and 128
|
||
; --
|
||
ANGLE SET 0.0
|
||
REPT 256
|
||
DB (MUL(64.0,SIN(ANGLE))+64.0)>>16
|
||
ANGLE SET ANGLE+256.0
|
||
ENDR
|
||
.Ed
|
||
.Pp
|
||
.Ic REPT
|
||
is also very useful in recursive macros and, as in macros, you can also use the
|
||
special label operator
|
||
.Ic \[rs]\@ .
|
||
REPT-blocks can be nested.
|
||
.Ss Aborting the assembly process
|
||
.Ic FAIL
|
||
and
|
||
.Ic 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.
|
||
.Ic FAIL
|
||
and
|
||
.Ic WARN
|
||
take a string as the only argument and they will print this string out as a
|
||
normal error with a line number.
|
||
.Pp
|
||
.Ic FAIL
|
||
stops assembling immediately while
|
||
.Ic WARN
|
||
shows the message but continues afterwards.
|
||
.Ss Including other source files
|
||
Use
|
||
.Ic INCLUDE
|
||
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 will be
|
||
searched.
|
||
You may nest
|
||
.Ic INCLUDE
|
||
calls infinitely (or until you run out of memory, whichever comes first).
|
||
.Pp
|
||
.Dl INCLUDE \[dq]irq.inc\[dq]
|
||
.Pp
|
||
.Ss Conditional assembling
|
||
The three commands
|
||
.Ic IF ,
|
||
.Ic ELSE
|
||
and
|
||
.Ic ENDC
|
||
are used to conditionally assemble parts of your file.
|
||
This is a powerful feature commonly used in macros.
|
||
.Pp
|
||
.Bd -literal -offset indent
|
||
IF 2+2==4
|
||
PRINTT \[dq]2+2==4\[rs]n\[dq]
|
||
ELSE
|
||
PRINTT \[dq]2+2!=4\[rs]n\[dq]
|
||
ENDC
|
||
.Ed
|
||
.Pp
|
||
The
|
||
.Ic ELSE
|
||
block is optional.
|
||
.Ic IF No / Ic ELSE No / Ic ENDC
|
||
blocks can be nested.
|
||
.Ss Integer and Boolean expressions
|
||
An expression can be composed of many things.
|
||
Expressions are always evaluated using signed 32-bit math.
|
||
.Pp
|
||
The most basic expression is just a single number.
|
||
.Pp
|
||
.Sy Numeric Formats
|
||
.Pp
|
||
There are a number of numeric formats.
|
||
.Pp
|
||
.Bl -dash -compact
|
||
.It
|
||
Hexadecimal: \(Do0123456789ABCDEF. Case-insensitive
|
||
.It
|
||
Decimal: 0123456789
|
||
.It
|
||
Octal: \*(Am01234567
|
||
.It
|
||
Binary: %01
|
||
.It
|
||
Fixedpoint (16.16): 01234.56789
|
||
.It
|
||
Character constant: \[dq]ABYZ\[dq]
|
||
.It
|
||
Gameboy graphics: \`0123
|
||
.El
|
||
.Pp
|
||
The last one, Gameboy graphics, is quite interesting and useful.
|
||
The values are actually pixel values and it converts the
|
||
.Do chunky Dc data to Do planar Dc data as used in the Gameboy.
|
||
.Pp
|
||
.Dl DW \`01012323
|
||
.Pp
|
||
Admittedly, an expression with just a single number is quite boring.
|
||
To spice things up a bit there are a few operators you can use to perform
|
||
calculations between numbers.
|
||
.Pp
|
||
.Sy Operators
|
||
.Pp
|
||
A great number of operators you can use in expressions are available (listed in
|
||
order of precedence):
|
||
.Pp
|
||
.Bl -column -offset indent ".Sy String" ".Sy String"
|
||
.It Sy Operator Ta Sy Meaning
|
||
.It Li ( ) Ta Precedence override
|
||
.It Li FUNC() Ta Function call
|
||
.It Li ~ + - Ta Unary not/plus/minus
|
||
.It Li * / % Ta Multiply/divide/modulo
|
||
.It Li << >> Ta Shift left/right
|
||
.It Li & | ^ Ta Binary and/or/xor
|
||
.It Li + - Ta Add/subtract
|
||
.It Li != == <= Ta Boolean comparison
|
||
.It Li >= < > Ta Boolean comparison (Same precedence as the others)
|
||
.It Li && || Ta Boolean and/or
|
||
.It Li ! Ta Unary Boolean not
|
||
.El
|
||
.Pp
|
||
The result of the boolean operators is zero if when FALSE and non-zero when
|
||
TRUE.
|
||
It is legal to use an integer as the condition for IF blocks.
|
||
You can use symbols instead of numbers in your expression if you wish.
|
||
.Pp
|
||
An expression is said to be constant when it doesn't change its value during
|
||
linking.
|
||
This basically means that you can't use labels in those expressions.
|
||
The instructions in the macro-language all require expressions that are
|
||
constant.
|
||
The only exception is the subtraction of labels in the same section or labels
|
||
that belong to sections with a fixed base addresses, all of which must be
|
||
defined in the same source file (the calculation cannot be passed to the object
|
||
file generated by the assembler).
|
||
In this case, the result is a constant that can be calculated at assembly time.
|
||
.Pp
|
||
.Ss Fixed‐point Expressions
|
||
Fixed point constants are basically normal 32-bit constants where the upper 16
|
||
bits are used for the integer part and the lower 16 bits are used for the
|
||
fraction (65536ths).
|
||
This means that you can use them in normal integer expression, and some integer
|
||
operators like plus and minus don't care whether the operands are integer or
|
||
fixed-point.
|
||
You can easily convert a fixed-point number to an integer by shifting it right
|
||
16 bits.
|
||
It follows that you can convert an integer to a fixed-point number by shifting
|
||
it left.
|
||
.Pp
|
||
Some things are different for fixed-point math, though, which is why you have
|
||
the following functions to use:
|
||
.Pp
|
||
.Bl -column -offset indent ".Sy String" ".Sy String"
|
||
.It Sy Name Ta Ta Sy Operation
|
||
.It Li DIV(x,y) Ta Ta x/y
|
||
.It Li MUL(x,y) Ta Ta x*y
|
||
.It Li SIN(x) Ta Ta sin(x)
|
||
.It Li COS(x) Ta Ta cos(x)
|
||
.It Li TAN(x) Ta Ta tan(x)
|
||
.It Li ASIN(x) Ta Ta arcsin(x)
|
||
.It Li ACOS(x) Ta Ta arccos(x)
|
||
.It Li ATAN(x) Ta Ta arctan(x)
|
||
.It Li ATAN2(x,y) Ta Angle between (x,y) and (1,0)
|
||
.El
|
||
.Pp
|
||
These functions are extremely useful for automatic generation of various tables.
|
||
A circle has 65536.0 degrees.
|
||
Sine values are between
|
||
.Bq -1.0 ; 1.0 .
|
||
.Pp
|
||
.Bd -literal -offset indent
|
||
; --
|
||
; -- Generate a 256 byte sine table with values between 0 and 128
|
||
; --
|
||
ANGLE SET 0.0
|
||
REPT 256
|
||
DB (MUL(64.0,SIN(ANGLE))+64.0)>>16
|
||
ANGLE SET ANGLE+256.0
|
||
ENDR
|
||
.Ed
|
||
.Pp
|
||
.Ss String Expressions
|
||
The most basic string expression is any number of characters contained in double
|
||
quotes (\[dq]for instance\[dq]).
|
||
Like in C, the escape character is \[rs], and there are a number of commands you
|
||
can use within a string:
|
||
.Pp
|
||
.Bl -column -offset indent ".Sy String" ".Sy String"
|
||
.It Sy String Ta Sy Meaning
|
||
.It Li \[rs]\[rs] Ta Backslash
|
||
.It Li \[rs]\[dq] Ta Double quote
|
||
.It Li \[rs], Ta Comma
|
||
.It Li \[rs]\[lC] Ta Curly bracket left
|
||
.It Li \[rs]\[rC] Ta Curly bracket right
|
||
.It Li \[rs]n Ta Newline ($0A)
|
||
.It Li \[rs]t Ta Tab ($09)
|
||
.It Li \[rs]1 - \[rs]9 Ta Macro argument (Only the body of a macros)
|
||
.It Li \[rs]\@ Ta Label name suffix (Only in the body of macros and repts)
|
||
.El
|
||
.Pp
|
||
A funky feature is
|
||
.Sy \[lC]symbol\[rC]
|
||
withing a string.
|
||
This will examine the type of the symbol and insert its value accordingly.
|
||
If symbol is a string symbol, the symbols value is simply copied.
|
||
If it's a numeric symbol, the value is converted to hexadecimal notation and
|
||
inserted as a string.
|
||
.Pp
|
||
HINT: The
|
||
.Sy \[lC]symbol\[rC]
|
||
construct can also be used outside strings.
|
||
The symbol's value is again inserted as a string.
|
||
This is just a short way of doing \[dq]\[lC]symbol\[rC]\[dq].
|
||
.Pp
|
||
Whenever the macro-language expects a string you can actually use a string
|
||
expression.
|
||
This consists of one or more of these function (yes, you can nest them).
|
||
Note that some of these functions actually return an integer and can be used as
|
||
part of an integer expression!
|
||
.Pp
|
||
.Bl -column ".Sy String" ".Sy String"
|
||
.It Sy Name Ta Ta Ta Sy Operation
|
||
.It Li STRLEN(string) Ta Returns the number of characters in string
|
||
.It Li STRCAT(str1,str2) Ta Appends str2 to str1.
|
||
.It Li STRCMP(str1,str2) Ta Returns negative if str1 is alphabetically lower
|
||
than str2, zero if they match, positive if str1 is greater than str2.
|
||
.It Li STRIN(str1,str2) Ta Returns the position of str2 in str1 or zero if it's
|
||
not present (first character is position 1).
|
||
.It Li STRSUB(str,pos,len) Ta Returns a substring from str starting at pos
|
||
(first character is position 1) and with len characters.
|
||
.It Li STRUPR(str) Ta Converts all characters in str to capitals and returns the
|
||
new string.
|
||
.It Li STRLWR(str) Ta Converts all characters in str to lower case and returns
|
||
the new string.
|
||
.El
|
||
.Pp
|
||
.Ss Other functions
|
||
There are a few other functions that do various useful things:
|
||
.Pp
|
||
.Bl -column ".Sy String" ".Sy String"
|
||
.It Sy Name Ta Ta Ta Sy Operation
|
||
.It Li BANK(label) Ta Returns the bank number label is in.
|
||
The linker will have to resolve this so it can't be used when the expression has
|
||
to be constant.
|
||
.It Li DEF(label) Ta Returns TRUE if label has been defined.
|
||
.It Li HIGH(r16/cnst/lbl) Ta Returns the top 8 bits of the operand if it is a
|
||
label or constant, or the top 8-bit register if it is a 16-bit register.
|
||
.It Li LOW(r16/cnst/lbl) Ta Returns the bottom 8 bits of the operand if it is a
|
||
label or constant, or the bottom 8-bit register if it is a 16-bit register (AF
|
||
isn't a valid register for this function).
|
||
.El
|
||
.Pp
|
||
.Sh MISCELLANEOUS
|
||
.Ss Changing options while assembling
|
||
.Ic OPT
|
||
can be used to change some of the options during assembling the
|
||
source instead of defining them on the commandline.
|
||
.Pp
|
||
.Ic OPT
|
||
takes a comma-seperated list of options as its argument:
|
||
.Pp
|
||
.Bd -literal -offset indent
|
||
PUSHO
|
||
OPT g.oOX ;Set the GB graphics constants to use these characters
|
||
DW `..ooOOXX
|
||
POPO
|
||
DW `00112233
|
||
.Ed
|
||
.Pp
|
||
The options that OPT can modify are currently:
|
||
.Sy b , e
|
||
and
|
||
.Sy g .
|
||
.Pp
|
||
.Ic POPO
|
||
and
|
||
.Ic PUSHO
|
||
provide the interface to the option stack.
|
||
.Ic PUSHO
|
||
will push the current set of options on the option stack.
|
||
.Ic POPO
|
||
can then later be used to restore them.
|
||
Useful if you want to change some options in an include file and you don't want
|
||
to destroy the options set by the program that included your file.
|
||
The stacks number of entries is limited only by the amount of memory in your
|
||
machine.
|
||
.Sh ALPHABETICAL LIST OF KEYWORDS
|
||
.Bl -inset -compact
|
||
.It Sx @
|
||
.It Sx __DATE__
|
||
.It Sx __FILE__
|
||
.It Sx __ISO_8601_LOCAL__
|
||
.It Sx __ISO_8601_UTC__
|
||
.It Sx __LINE__
|
||
.It Sx __TIME__
|
||
.It Sx _NARG
|
||
.It Sx _PI
|
||
.It Sx _RS
|
||
.It Sx ACOS
|
||
.It Sx ASIN
|
||
.It Sx ATAN
|
||
.It Sx ATAN2
|
||
.It Sx BANK
|
||
.It Sx COS
|
||
.It Sx DB
|
||
.It Sx DEF
|
||
.It Sx DIV
|
||
.It Sx DS
|
||
.It Sx DW
|
||
.It Sx ELSE
|
||
.It Sx ENDC
|
||
.It Sx ENDM
|
||
.It Sx ENDR
|
||
.It Sx EQU
|
||
.It Sx EQUS
|
||
.It Sx EXPORT
|
||
.It Sx FAIL
|
||
.It Sx GLOBAL
|
||
.It Sx HIGH
|
||
.It Sx HRAM
|
||
.It Sx IF
|
||
.It Sx INCBIN
|
||
.It Sx INCLUDE
|
||
.It Sx LOW
|
||
.It Sx MACRO
|
||
.It Sx MUL
|
||
.It Sx OPT
|
||
.It Sx POPO
|
||
.It Sx POPS
|
||
.It Sx PRINTF
|
||
.It Sx PRINTT
|
||
.It Sx PRINTV
|
||
.It Sx PURGE
|
||
.It Sx PUSHO
|
||
.It Sx PUSHS
|
||
.It Sx REPT
|
||
.It Sx RB
|
||
.It Sx ROM0
|
||
.It Sx ROMX
|
||
.It Sx RSRESET
|
||
.It Sx RSSET
|
||
.It Sx RW
|
||
.It Sx SECTION
|
||
.It Sx SET
|
||
.It Sx SHIFT
|
||
.It Sx SIN
|
||
.It Sx SRAM
|
||
.It Sx STRCAT
|
||
.It Sx STRCMP
|
||
.It Sx STRIN
|
||
.It Sx STRLEN
|
||
.It Sx STRLWR
|
||
.It Sx STRSUB
|
||
.It Sx STRUPR
|
||
.It Sx TAN
|
||
.It Sx VRAM
|
||
.It Sx WRAM0
|
||
.It Sx WRAMX
|
||
.It Sx WARN
|
||
.El
|
||
.Sh SEE ALSO
|
||
.Xr rgbasm 1 ,
|
||
.Xr rgblink 1 ,
|
||
.Xr rgblink 5 ,
|
||
.Xr rgbds.rgbformat 5 ,
|
||
.Xr rgbds 7 ,
|
||
.Xr gbz80 7
|
||
.Sh HISTORY
|
||
.Nm rgbds
|
||
was originally written by Carsten S\(/orensen 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/rednex/rgbds.
|