Short: GB-Z80/Z80/6502/65C02/6510/65816/HUC6280/SPC-700 Macro Assembler Package Author: Ville Helin Uploader: Ventzislav Tzvetkov Type: dev/cross Version: 9.2 Architecture: ppc-amigaos >= 4.0.0 -------------------------------------------------------------------------------- - WLA DX GB-Z80/Z80/6502/65C02/6510/65816/HUC6280/SPC-700 Macro Assembler Package Written by 1998-2003 Ville Helin -------------------------------------------------------------------------------- - 1..... Introduction 2..... Assembler Directives 3..... Assembler Syntax 3.1.. Case Sensitivity 3.2.. Comments 3.3.. Labels 3.4.. Number Types 3.5.. Strings 3.6.. Mnemonics 3.7.. Brackets? 4..... Error Messages 5..... Supported ROM/RAM/Cartridge Types (WLA-GB) 5.1.. ROM Size 5.2.. RAM Size 5.3.. Cartridge Type 6..... Bugs 7..... Files 7.1.. 'examples' 7.2.. 'examples/gb-z80/lib' 8..... Temporary Files 9..... Compiling 9.1.. Compiling Object Files 9.2.. Compiling Library Files 10.... Linking 11.... Arithmetics 12.... Disassembling 13.... Binary to DB Conversion 14.... Things you should know about coding for... 14.1. Z80 14.2. 6502 14.3. 65C02 14.4. 6510 14.5. 65816 14.6. HUC6280 14.7. SPC-700 14.8. Pocket Voice (GB-Z80) 14.9. GB-Z80 15.... WLA Flags 16.... Extra compile time definitions 17.... Good things to know about WLA 18.... Author 19.... Thanks 20.... Future 21.... Support 22.... Legal Note ------------------------------------------------------------------------------ 1.... Introduction ------------------------------------------------------------------------------ I wrote this because I had never written an assembler before and I really needed a macro assembler which could compile the GB-Z80 code I wrote. ;) Gaelan Griffin needed real Z80 support for his SMS projects so I thought I could write WLA to be a little more open and nowadays it supports all the Z80 systems you can think of. You'll just have to define the memorymap of the destination machine for your project. After fixing some bugs I thought I could add support for 6502 systems so all NES-people would get their share of WLA as well. After finishing that few people said they'd like 65816 support (they had SNES developing in mind) so I added support for that. And then I thought I should write a 6510 version of WLA as well... Almost all rules that apply to Z80 compiling apply also to 6502, 65C02, 6510, 65816, HUC6280 and SPC-700. This is my ideal GB-Z80 macro assembler (not in final form, not yet). ;) Tastes differ. Thus WLA! Notice that WLA was initially made for Game Boy developers so the GB-Z80 version and the rest differ a little. Currently WLA can also be used as a patch tool. Just include the original ROM image into the project with .BACKGROUND and insert e.g., OVERWRITE .SECTIONs to patch the desired areas. Output the data into a new ROM image and there you have it. 100% readable (asm coded) patches are reality! Note that you can directly compile only object and library files. You must use WLALINK to link these (or only one, if you must) into a ROM/program file. About the names... WLA DX means all the tools covered in this documentation. So WLA DX includes WLA GB-Z80/Z80/6502/65C02/6510/65816/HUC6280/SPC-700 macro assembler (what a horribly long name), WLAB, WLAD and WLALINK GB-Z80/Z80/6502/65C02/6510/65816/HUC6280/SPC-700 linker. I use plain WLA to refer to the macro assembler. WLA DX's homepage: http://www.iki.fi/~vhelin/wla.html And if you happen to write something cool using WLA DX, please let me know, I want to see it! ------------------------------------------------------------------------------ 2.... Assembler Directives ------------------------------------------------------------------------------ Here's the order in which the data is placed into the output: 1. Data and group 3 directives outside sections. 2. Group 2 directives. 3. Data and group 3 directives inside sections. 4. Group 1 directives. Here are the supported directives (with examples) in WLA: [ALL] - All, GB-Z80, Z80, 6502, 65C02, 6510, 65816, HUC6280 and SPC-700 versions apply. [GB ] - Only the GB-Z80 version applies. [GB8] - Only the GB-Z80 and 65816 versions apply. [Z80] - Only the Z80 version applies. [658] - Only the 65816 version applies. [SPC] - Only the SPC-700 version applies. [65x] - Only the 6502, 65C02, 6510, 65816 and HUC6280 versions apply. [!GB] - Only the Z80, 6502, 65C02, 6510, 65816, HUC6280 and SPC-700 versions apply. Group 1: [GB ] .COMPUTEGBCHECKSUM [Z80] .COMPUTESMSCHECKSUM [658] .COMPUTESNESCHECKSUM [Z80] .SDSCTAG 1.0, "DUNGEON MAN", "A wild dungeon exploration game", "Ville Helin" [Z80] .SMSTAG Group 2: [GB ] .CARTRIDGETYPE 1 [GB ] .COMPUTEGBCOMPLEMENTCHECK [ALL] .EMPTYFILL $C9 [658] .ENDEMUVECTOR [658] .ENDNATIVEVECTOR [658] .ENDSNES [ALL] .EXPORT work_x [658] .FASTROM [658] .HIROM [GB ] .LICENSEECODENEW "1A" [GB ] .LICENSEECODEOLD $1A [658] .LOROM [GB8] .NAME "NAME OF THE ROM" [ALL] .OUTNAME "other.o" [GB ] .RAMSIZE 0 [GB ] .ROMDMG [GB ] .ROMGBC [GB ] .ROMSGB [658] .SLOWROM [658] .SMC [658] .SNESEMUVECTOR [658] .SNESHEADER [658] .SNESNATIVEVECTOR Group 3: [65x] .16BIT [658] .24BIT [65x] .8BIT [658] .ACCU 8 [ALL] .ASC "HELLO WORLD!" [ALL] .ASM [ALL] .BACKGROUND "parallax.gb" [ALL] .BANK 0 SLOT 1 [658] .BASE $80 [ALL] .BYT 100, $30, %1000, "HELLO WORLD!" [ALL] .ROMBANKSIZE $4000 [ALL] .DB 100, $30, %1000, "HELLO WORLD!" [ALL] .DBCOS 0.2, 10, 3.2, 120, 1.3 [ALL] .DBRND 20, 0, 10 [ALL] .DBSIN 0.2, 10, 3.2, 120, 1.3 [ALL] .DEFINE IF $FF0F [ALL] .DEF IF $FF0F [ALL] .DS 256, $10 [ALL] .DSB 256, $10 [ALL] .DSTRUCT waterdrop INSTANCEOF water DATA "tingle", 40, 120 [ALL] .DSW 128, 20 [ALL] .DW 16000, 10, 255 [ALL] .DWCOS 0.2, 10, 3.2, 1024, 1.3 [ALL] .DWRND 20, 0, 10 [ALL] .DWSIN 0.2, 10, 3.2, 1024, 1.3 [ALL] .ELSE [ALL] .ENDASM [ALL] .ENDE [ALL] .ENDIF [ALL] .ENDM [ALL] .ENDME [ALL] .ENDR [ALL] .ENDRO [ALL] .ENDS [ALL] .ENDST [ALL] .ENUM $C000 [ALL] .EQU IF $FF0F [ALL] .FAIL [ALL] .FCLOSE FP_DATABIN [ALL] .FOPEN "data.bin" FP_DATABIN [ALL] .FREAD FP_DATABIN DATA [ALL] .FSIZE FP_DATABIN SIZE [ALL] .IF DEBUG == 2 [ALL] .IFDEF IF [ALL] .IFDEFM \2 [ALL] .IFEQ DEBUG 2 [ALL] .IFEXISTS "main.s" [ALL] .IFGR DEBUG 2 [ALL] .IFGREQ DEBUG 1 [ALL] .IFLE DEBUG 2 [ALL] .IFLEEQ DEBUG 1 [ALL] .IFNDEF IF [ALL] .IFNDEFM \2 [ALL] .IFNEQ DEBUG 2 [ALL] .INCBIN "sorority.bin" [ALL] .INCDIR "/usr/programming/gb/include/" [ALL] .INCLUDE "cgb_hardware.i" [658] .INDEX 8 [ALL] .INPUT NAME [ALL] .MACRO TEST [ALL] .MEMORYMAP [ALL] .ORG $150 [ALL] .ORGA $150 [ALL] .PRINTT "Here we are...\n" [ALL] .PRINTV DEC DEBUG+1 [ALL] .RAMSECTION "Vars" BANK 0 SLOT 1 [ALL] .REDEFINE IF $F [ALL] .REDEF IF $F [ALL] .REPEAT 6 [ALL] .REPT 6 [ALL] .ROMBANKMAP [ALL] .ROMBANKS 2 [ALL] .SEED 123 [ALL] .SECTION "Init" FORCE [ALL] .SLOT 1 [ALL] .STRUCT enemy_object [ALL] .UNBACKGROUND $1000 $1FFF [ALL] .UNDEFINE DEBUG [ALL] .UNDEF DEBUG [ALL] .WORD 16000, 10, 255 Descriptions: ----- .8BIT ----- There are a few mnemonics that look identical, but take different sized arguments. Here's a list of such 6502 mnemonics: ADC, AND, ASL, BIT, CMP, CPX, CPY, DEC, EOR, INC, LDA, LDX, LDY, ORA, ROL, SBC, STA, STX and STY. For example: LSR 11 ; $46 $0B LSR $A000 ; $4E $00 $A0 The first one could also be LSR 11 ; $4E $0B $00 .8BIT is here to help WLA to decide to choose which one of the opcodes it selects. When you give .8BIT (default) no 8bit address/value is expanded to 16bits. By default WLA uses the smallest possible size. This is true also when WLA finds a computation it can't solve right away. WLA assumes the result will be inside the smallest possible bounds, which depends on the type of the mnemonic. You can also use the fixed argument size versions of such mnemonics by giving the size with the operand (i.e., operand hinting). Here are few examples: LSR 11.B ; $46 $0B LSR 11.W ; $46 $0B $00 In WLA-65816 .ACCU/.INDEX/SEP/REP override .8BIT/.16BIT/.24BIT when considering the immediate values, so be careful. Still, operand hints override all of these, so use them to be sure. This is not a compulsory directive. ------ .16BIT ------ Analogous to .8BIT. .16BIT forces all addresses and immediate values to be expanded into 16bit range, when possible, that is. LSR 11 ; $46 $0B that would be the case, normally, but after .16BIT it becomes LSR 11 ; $4E $0B $00 This is not a compulsory directive. ------ .24BIT ------ Analogous to .8BIT and .16BIT. .24BIT forces all addresses to be expanded into 24bit range, when possible, that is. AND $11 ; $25 $11 that would be the case, normally, but after .24BIT it becomes AND $11 ; $2F $11 $00 $00 If it is not possible to expand the address into .24BIT range, then WLA tries to expand it into 16bit range. This is not a compulsory directive. ------- .ACCU 8 ------- Forces WLA to override the accumulator size given with SEP/REP. .ACCU doesn't produce any code, it only affects the way WLA interprets the immediate values (8 for 8 bit operands, 16 for 16 bit operands) for opcodes dealing with the accumulator. So after giving .ACCU 8 AND #6 will produce $29 $06, and after giving .ACCU 16 AND #6 will yield $29 $00 $06. Note that SEP/REP again will in turn reset the accumulator/index register size. This is not a compulsory directive. -------- .INDEX 8 -------- Forces WLA to override the index (X/Y) register size given with SEP/REP. .INDEX doesn't produce any code, it only affects the way WLA interprets the immediate values (8 for 8 bit operands, 16 for 16 bit operands) for opcodes dealing with the index registers. So after giving .INDEX 8 CPX #10 will produce $E0 $A0, and after giving .INDEX 16 CPX #10 will yield $E0 $00 $A0. Note that SEP/REP again will in turn reset the accumulator/index register size. This is not a compulsory directive. ---- .ASM ---- Tells WLA to start assembling. Use .ASM to continue the work which has been disabled with .ENDASM. .ASM and .ENDASM can be used to mask away big blocks of code. This is analogous to the ANSI C -comments (/*...*/), but .ASM and .ENDASM can be nested, unlike the ANSI C -counterpart. This is not a compulsory directive. ------- .ENDASM ------- Tells WLA to stop assembling. Use .ASM to continue the work. This is not a compulsory directive. ---------------- .DBRND 20, 0, 10 ---------------- Defines bytes, just like .DSB does, only this time they are filled with (pseudo) random numbers. We use stdlib's rand() to generate the random numbers. If you want to seed the random number generator, use .SEED. The first parameter (20 in the example) defines the amount of numbers we want to generate. The next two tell the range of the random numbers, i.e. min and max. Here's how it works: .DBRND A, B, C for (i = 0; i < A; i++) output_data((rand() % (C-B+1)) + B); This is not a compulsory directive. ---------------- .DWRND 20, 0, 10 ---------------- Analogous to .DBRND (but defines words). This is not a compulsory directive. ----------------------------- .DBCOS 0.2, 10, 3.2, 120, 1.3 ----------------------------- Defines bytes just like .DSB does, only this time they are filled with cosine data. .DBCOS takes five arguments. The first argument is the starting angle. Angle value ranges from 0 to 359.999..., but you can supply WLA with values that are out of the range - WLA fixes them ok. The value can be integer or float. The second one descibes the amount of additional angles. The example will define 11 angles. The third one is the adder value which is added to the angle value when next angle is calculated. The value can be integer or float. The fourth and fifth ones can be seen from the pseudo code below, which also describes how .DBCOS works. The values can be integer or float. Remember that cos (and sin) here returns values ranging from -1 to 1. .DBCOS A, B, C, D, E for (B++; B > 0; B--) { output_data((D * cos(A)) + E) A = keep_in_range(A + C) } This is not a compulsory directive. ----------------------------- .DBSIN 0.2, 10, 3.2, 120, 1.3 ----------------------------- Analogous to .DBCOS, but does sin() instead of cos(). This is not a compulsory directive. ------------------------------ .DWCOS 0.2, 10, 3.2, 1024, 1.3 ------------------------------ Analogous to .DBCOS (but defines words). This is not a compulsory directive. ------------------------------ .DWSIN 0.2, 10, 3.2, 1024, 1.3 ------------------------------ Analogous to .DBCOS (but defines words and does sin() instead of cos()). This is not a compulsory directive. ----------------------- .NAME "NAME OF THE ROM" ----------------------- If .NAME is used with WLA-GB then the 16 bytes ranging from $0134 to $0143 are filled with the provided string. WLA-65816 fills the 21 bytes from $FFC0 to $FFD4 in HiROM- and from $7FC0 to $7FD4 in LoROM-mode with the name string (SNES ROM title). If the string is shorter than 16/21 bytes the remaining space is filled with $00. This is not a compulsory directive. ----------- .ROMBANKS 2 ----------- Indicates the size of the ROM in rombanks. This value is converted to a standard GB ROM size indicator value found at $148 in a GB ROM, and there this one is put into. This is a compulsory directive unless .ROMBANKMAP is defined. You can redefine .ROMBANKS as many times as you wish as long as the old and the new ROM bank maps match as much as possible. This way you can enlarge the size of the project on the fly. ---------- .RAMSIZE 0 ---------- Indicates the size of the RAM. This is a standard GB RAM size indicator value found at $149 in a GB ROM, and there this one is put to also. This is not a compulsory directive. -------------- .EMPTYFILL $C9 -------------- This byte is used in filling the unused areas of the ROM file. EMPTYFILL defaults to $00. This is not a compulsory directive. ---------------- .CARTRIDGETYPE 1 ---------------- Indicates the type of the cartridge (mapper and so on). This is a standard GB cartridge type indicator value found at $147 in a GB ROM, and there this one is put to also. This is not a compulsory directive. -------------------- .LICENSEECODEOLD $1A -------------------- This is a standard old licensee code found at $14B in a GB ROM, and there this one is put to also. .LICENSEECODEOLD cannot be defined with .LICENSEECODENEW. This is not a compulsory directive. --------------------- .LICENSEECODENEW "1A" --------------------- This is a standard new licensee code found at $144 and $145 in a GB ROM, and there this one is put to also. .LICENSEECODENEW cannot be defined with .LICENSEECODEOLD. $33 is inserted into $14B, as well. This is not a compulsory directive. ------------------ .COMPUTEGBCHECKSUM ------------------ When this directive is used WLA computes the ROM checksum found at $14E and $14F in a GB ROM. Note that this directive can only be used with wla-gb. Note that you can also write .COMPUTECHECKSUM (the old name for this directive), but it's not recommended. This is not a compulsory directive. ------------------- .COMPUTESMSCHECKSUM ------------------- When this directive is used WLA computes the ROM checksum found at $7FFA and $7FFB in a SMS/GG ROM. Note that this directive can only be used with wla-z80. Also note that the ROM size must be at least 32KB. Data beyond 256KB limit is not taken into account when calculating the SMS checksum, which should be the right way to do it. This is not a compulsory directive. -------------------- .COMPUTESNESCHECKSUM -------------------- When this directive is used WLA computes the SNES ROM checksum and inverse checksum found at $7FDC-$7FDF (LoROM) or $FFDC-$FFDF (HiROM). Note that this directive can only be used with wla-65816. Also note that the ROM size must be at least 32KB for LoROM images and 64KB for HiROM images. .LOROM or .HIROM must be issued before .COMPUTESNESCHECKSUM. This is not a compulsory directive. ------- .SMSTAG ------- .SMSTAG forces WLA to write an ordinary SMS/GG ROM tag to the ROM file. Currently only the string "TMR SEGA" and ROM checksum are written (meaning that .SMSTAG also defines .COMPUTESMSCHECKSUM). This is not a compulsory directive. ----------------------------------------------------------------------------- .SDSCTAG 1.0, "DUNGEON MAN", "A wild dungeon exploration game", "Ville Helin" ----------------------------------------------------------------------------- .SDSCTAG adds SDSC tag to your SMS/GG ROM file. The ROM size must be at least 32KB just like with .COMPUTESMSCHECKSUM and .SMSTAG, as the data goes into $7FE0-$7FEF of the ROM. For more information about this header take a look at http://www.smspower.org/dev/sdsc/. Here's an explanation of the arguments: .SDSCTAG {version number}, {program name}, {program release notes}, {program author} Note that program name, release notes and program author can also be pointers to strings instead of being only strings (which WLA terminates with zero, and places them into suitable locations inside the ROM file). So .SDSCTAG 0.8, PRGNAME, PRGNOTES, PRGAUTHOR ... PRGNAME: .DB "DUNGEON MAN", 0 PRGNOTES: .DB "A wild and totally crazy dungeon exploration game", 0 PRGAUTHOR:.DB "Ville Helin", 0 works also. All strings supplied explicitly to .SDSCTAG are placed somewhere in .BANK 0 SLOT 0. .SDSCTAG 1.0, "", "", "" .SDSCTAG 1.0, 0, 0, 0 are also valid, here 0 and "" mean the user doesn't want to use any descriptive strings. Version number can also be given as an integer, but then the minor version number defaults to zero. .SDSCTAG also defines .SMSTAG (as it's part of the SDSC ROM tag specification). This is not a compulsory directive. ------------------------- .COMPUTEGBCOMPLEMENTCHECK ------------------------- When this directive is used WLA computes the ROM complement check found at $14D in a GB ROM. Note that you can still use .COMPUTECOMPLEMENTCHECK (the old name for this directive), but it's not recommended. This is not a compulsory directive. -------------------------------------- .INCDIR "/usr/programming/gb/include/" -------------------------------------- Changes the current include root directory. Use this to specify main directory for the following .INCLUDE and .INCBIN directives. If you want to change to the current working directory (WLA also defaults to this), use .INCDIR "" This is not a compulsory directive. ------------------------- .INCLUDE "cgb_hardware.i" ------------------------- Includes the specified file to the source file. If the file's not found in the .INCDIR directory, WLA tries to find it in the current working directory. This is not a compulsory directive. ---------------------- .INCBIN "sorority.bin" ---------------------- Includes the specified data file into the source file. .INCBIN caches all files into memory, so you can .INCBIN any data file millions of times, but it is loaded from hard drive only once. You can optionally use SWAP after the file name, e.g., .INCBIN "kitten.bin" SWAP .INCBIN data is divided into blocks of two bytes, and inside every block the bytes are exchanged (like "SWAP r" does to nibbles). This requires that the size of the file is even. You can also force WLA to skip n bytes from the beginning of the file by writing for example: .INCBIN "kitten.bin" SKIP 4 Four bytes are skipped from the beginning of kitten.bin and the rest is incbinned. It is also possible to incbin only n bytes from a file: .INCBIN "kitten.bin" READ 10 Will read ten bytes from the beginning of kitten.bin. You can also force WLA to create a definition holding the size of the file: .INCBIN "kitten.bin" FSIZE size_of_kitten And you can combine all these four commands: .INCBIN "kitten.bin" SKIP 10 READ 8 SWAP FSIZE size_of_kitten This example shows how to incbin eight bytes (swapped) after skipping 10 bytes from the beginning of file "kitten.bin", and how to get the size of the file into a definition label "size_of_kitten". Note that the order of the extra commands is important. If the file's not found in the .INCDIR directory, WLA tries to find it in the current working directory. This is not a compulsory directive. ----------- .INPUT NAME ----------- .INPUT is much like any Basic-language input: .INPUT asks the user for a value or string. After .INPUT is the variable name used to store the data. .INPUT works like .REDEFINE, but the user gets to type in the data. Here are few examples how to use input: .PRINTT "The name of the ROM? " .INPUT NAME .NAME NAME ... .PRINTT "Give the .DB amount.\n" .INPUT S .PRINTT "Give .DB data one at a time.\n" .REPEAT S .INPUT B .DB B .ENDR ... This is not a compulsory directive. ------------------------- .BACKGROUND "parallax.gb" ------------------------- This chooses an existing ROM image (parallax.gb in this case) as a background data for the project. You can overwrite the data with OVERWRITE sections only, unless you first clear memory blocks with .UNBACKGROUND after which there's room for other sections as well. With .BACKGROUND defined you can leave away .ROMSIZE,.ROMTYPE and .RAMTYPE. .BACKGROUND can be used only when compiling an object file. .BACKGROUND is useful if you wish to patch an existing ROM image with new code or data. This is not a compulsory directive. ------------------------- .UNBACKGROUND $1000 $1FFF ------------------------- After issuing .BACKGROUND you might want to free some parts of the backgrounded ROM image for e.g., FREE sections. With .UNBACKGROUND you can define such regions. In the example a block starting at $1000 and ending at $1FFF was released (both ends included). You can issue .UNBACKGROUND as many times as you wish. This is not a compulsory directive. ----- .FAIL ----- Terminates the compiling process. This is not a compulsory directive. ------------------ .FCLOSE FP_DATABIN ------------------ Closes the filehandle FP_DATABIN. This is not a compulsory directive. ---------------------------- .FOPEN "data.bin" FP_DATABIN ---------------------------- Opens the file "data.bin" for reading and associates the filehandle with name "FP_DATABIN". This is not a compulsory directive. ---------------------- .FREAD FP_DATABIN DATA ---------------------- Reads one byte from "FP_DATABIN" and creates a definition called "DATA" to hold it. "DATA" is an ordinary definition label, so you can .UNDEFINE it. Here's an example on how to use .FREAD: .fopen "data.bin" fp .fsize fp t .repeat t .fread fp d .db d+26 .endr .undefine t, d This is not a compulsory directive. ---------------------- .FSIZE FP_DATABIN SIZE ---------------------- Creates a definition called "SIZE", which holds the size of the file associated with the filehandle "FP_DATABIN". "SIZE" is an ordinary definition label, so you can .UNDEFINE it. This is not a compulsory directive. ----------- .MACRO TEST ----------- Begins a macro called 'TEST'. You can use '\@' inside a macro to e.g., separate a label from the other macro 'TEST' occurrences. '\@' is replaced with an integer number indicating the amount of times the macro has been called previously so it is unique to every macro call. '\@' can also be used inside strings inside a macro or just as a plain value. Look at the following examples for more information. Also, if you want to use macro arguments in e.g., calculation, you can type '\X' where X is the number of the argument. Another way to refer to the arguments is to use their names given in the definition of the macro (see the examples for this). Remember to use .ENDM to finish the macro definition. Note that you cannot use .INCLUDE inside a macro. Note that WLA's macros are in fact more like procedures than real macros, because WLA doesn't substitute macro calls with macro data. Instead WLA jumps to the macro when it encounters a macro call at compile time. You can call macros from inside a macro. Note that the preprocessor does not expand the macros. WLA traverses through the code according to the macro calls, so macros really define a very simple programming language. Here are some examples: .MACRO NOPMONSTER .REPT 32 ; evil... NOP .ENDR .ENDM .MACRO LOAD_ABCD LD A, \1 LD B, \2 LD C, \3 LD D, \4 NOPMONSTER LD HL, 1<<\1 .INCBIN \5 .ENDM .MACRO QUEEN QUEEN\@: LD A, \1 LD B, \1 CALL QUEEN\@ .DB "\@", 0 ; will translate into a zero terminated string ; holding the amount of macro QUEEN calls. .DB "\\@", 0 ; will translate into a string containing ; \@. .DB \@ ; will translate into a number indicating ; the amount of macro QUEEN calls. .ENDM .MACRO LOAD_ABCD_2 ARGS ONE, TWO, THREE, FOUR, FIVE LD A, ONE LD B, TWO LD C, THREE LD D, FOUR NOPMONSTER LD HL, 1< - greater than >= - greater or equal to == - equals to != - doesn't equal to All IF (yes, including .IFDEF, .IFNDEF, etc) directives can be nested. This is not a compulsory directive. --------- .IFDEF IF --------- If "IF" is defined, then the following piece of code is acknowledged until .ENDIF/.ELSE occurs in the text, otherwise it is skipped. This is not a compulsory directive. ------------------ .IFEXISTS "main.s" ------------------ If "main.s" file can be found, then the following piece of code is acknowledged until .ENDIF/.LESE occurs in the text, otherwise it is skipped. By writing the following few lines you can include a file if it exists without breaking the compiling loop if it doesn't exist. .IFEXISTS FILE .INCLUDE FILE .ENDIF This is not a compulsory directive. --------------- .UNDEFINE DEBUG --------------- Removes the supplied definition label from system. If there is no such label as given no error is displayed as the result would be the same. You can undefine as many definitions as you wish with one .UNDEFINE: .UNDEFINE NUMBER, NAME, ADDRESS, COUNTRY .UNDEFINE NAME, AGE This is not a compulsory directive. ------------ .UNDEF DEBUG ------------ .UNDEF is an alias for .UNDEFINE. This is not a compulsory directive. ---------- .IFNDEF IF ---------- If "IF" is not defined, then the following piece of code is acknowledged until .ENDIF/.ELSE occurs in the text, otherwise it is skipped. This is not a compulsory directive. ---------- .IFDEFM \2 ---------- If the specified argument is defined (argument number two, in the example), then the following piece of code is acknowledged until .ENDIF/.ELSE occurs in the macro, otherwise it is skipped. This is not a compulsory directive. .IFDEFM works only inside a macro. ----------- .IFNDEFM \2 ----------- If the specified argument is not defined, then the following piece of code is acknowledged until .ENDIF/.ELSE occurs in the macro, otherwise it is skipped. This is not a compulsory directive. .IFNDEFM works only inside a macro. ------------- .IFEQ DEBUG 2 ------------- If the value of DEBUG equals to 2, then the following piece of code is acknowledged until .ENDIF/.ELSE occurs in the text, otherwise it is skipped. Both arguments can be computations, defines or immediate values. This is not a compulsory directive. -------------- .IFNEQ DEBUG 2 -------------- If the value of DEBUG doesn't equal to 2, then the following piece of code is acknowledged until .ENDIF/.ELSE occurs in the text, otherwise it is skipped. Both arguments can be computations, defines or immediate values. This is not a compulsory directive. ------------- .IFLE DEBUG 2 ------------- If the value of DEBUG is less than 2, then the following piece of code is acknowledged until .ENDIF/.ELSE occurs in the text, otherwise it is skipped. Both arguments can be computations, defines or immediate values. This is not a compulsory directive. --------------- .IFLEEQ DEBUG 2 --------------- If the value of DEBUG is less or equal to 2, then the following piece of code is acknowledged until .ENDIF/.ELSE occurs in the text, otherwise it is skipped. Both arguments can be computations, defines or immediate values. This is not a compulsory directive. ------------- .IFGR DEBUG 2 ------------- If the value of DEBUG is greater than 2, then the following piece of code is acknowledged until .ENDIF/.ELSE occurs in the text, otherwise it is skipped. Both arguments can be computations, defines or immediate values. This is not a compulsory directive. --------------- .IFGREQ DEBUG 2 --------------- If the value of DEBUG is greater or equal to 2, then the following piece of code is acknowledged until .ENDIF/.ELSE occurs in the text, otherwise it is skipped. Both arguments can be computations, defines or immediate values. This is not a compulsory directive. ----- .ELSE ----- If the previous .IFxxx failed then the following text until .ENDIF is acknowledged. This is not a compulsory directive. ------ .ENDIF ------ This terminates any .IFxxx directive. This is not a compulsory directive, but if you use any .IFxxx then you need also to apply this. --------- .REPEAT 6 --------- Repeats the text enclosed between ".REPEAT x" and ".ENDR" x times (6 in this example). You can use .REPEATs inside .REPEATs. 'x' must be >= 0. This is not a compulsory directive. ------- .REPT 6 ------- .REPT is an alias for .REPEAT. This is not a compulsory directive. ----- .ENDR ----- Ends the repetition. This is not a compulsory directive, but when .REPEAT is used this one is required to terminate it. ----------- .ENUM $C000 ----------- Starts enumeration from $C000. Very useful for defining variables. To start a descending enumeration, put "DESC" after the starting address. WLA defaults to "ASC" (ascending enumeration). You can also add "EXPORT" after these if you want to export all the generated definitions automatically. Here's an example of .ENUM: ... .STRUCT mon ; check out the documentation on name ds 2 ; .STRUCT age db .ENDST .ENUM $A000 _scroll_x DB ; db - define byte (byt and byte work also) _scroll_y DB player_x: DW ; dw - define word (word works also) player_y: DW map_01: DS 16 ; ds - define size (bytes) map_02 DSB 16 ; dsb - define size (bytes) map_03 DSW 8 ; dsw - define size (words) monster INSTANCEOF mon 3 ; three instances of structure mon dragon INSTANCEOF mon ; one mon .ENDE ... Previous example transforms into following definitions: .DEFINE _scroll_x $A000 .DEFINE _scroll_y $A001 .DEFINE player_x $A002 .DEFINE player_y $A004 .DEFINE map_01 $A006 .DEFINE map_02 $A016 .DEFINE map_03 $A026 .DEFINE monster $A036 .DEFINE monster.name $A036 .DEFINE monster.age $A038 .DEFINE monster.1 $A036 .DEFINE monster.1.name $A036 .DEFINE monster.1.age $A038 .DEFINE monster.2 $A039 .DEFINE monster.2.name $A039 .DEFINE monster.2.age $A03B .DEFINE monster.3 $A03C .DEFINE monster.3.name $A03C .DEFINE monster.3.age $A03E .DEFINE dragon $A03F .DEFINE dragon.name $A03F .DEFINE dragon.age $A041 DB, DW, DS, DSB, DSW and INSTANCEOF can also be in lowercase. You can also use a dotted version of the symbols, but it doesn't advance the memory address. Here's an exmple: .ENUM $C000 DESC EXPORT bigapple_h db bigapple_l db bigapple: .dw .ENDE And this is what is generated: .DEFINE bigapple_h $BFFF .DEFINE bigapple_l $BFFE .DEFINE bigapple $BFFE .EXPORT bigapple, bigapple_l, bigapple_h This way you can generate a 16bit variable address along with pointers to its parts. If you want more flexible variable positioning, take a look at .RAMSECTIONs. This is not a compulsory directive. ----- .ENDE ----- Ends the enumeration. This is not a compulsory directive, but when .ENUM is used this one is required to terminate it. -------------------- .STRUCT enemy_object -------------------- Begins the definition of a structure. These structures can be placed inside RAMSECTIONs and ENUMs. Here's an example: .STRUCT enemy_object id dw ; the insides of a .STRUCT are 1:1 like in .ENUM x db ; except that no structs inside structs are y db ; allowed. data ds 10 info dsb 16 stats dsw 4 .ENDST This also creates a definition "_sizeof_[struct name]", in our example this would be "_sizeof_enemy_object", and the value of this definition is the size of the object, in bytes (2+1+1+10+16+4*2 = 38 in the example). You'll get the following definitions as well: enemy_object.id (== 0) enemy_object.x (== 2) enemy_object.y (== 3) enemy_object.data (== 4) enemy_object.info (== 14) enemy_object.stats (== 30) After defining a .STRUCT you can create an instance of it in a .RAMSECTION / .ENUM by typing INSTANCEOF [optional, the number of structures] Here's an example: .RAMSECTION "enemies" BANK 4 SLOT 4 enemies INSTANCEOF enemy_object 4 enemyman INSTANCEOF enemy_object enemyboss INSTANCEOF enemy_object .ENDS This will create labels like "enemies", "enemies.id", "enemies.x", "enemies.y" and so on. Label "enemies" is followed by four "enemy_object" structures, and only the first one is labeled. After there four come "enemyman" and "enemyboss" instances. Take a look at the documentation on .RAMSECTION & .ENUM, they have more examples of how you can use .STRUCTs. A WORD OF WARNING: Don't use labels b, B, w and W inside a struct as e.g., WLA sees enemy.b as a byte sized reference to enemy. All other labels should be safe. lda enemy1.b ; load a byte from zeropage address enemy1 or from the address ; of enemy1.b??? i can't tell you, and WLA can't tell you... This is not a compulsory directive. ------ .ENDST ------ Ends the structure definition. This is not a compulsory directive, but when .STRUCT is used this one is required to terminate it. ---------- .MEMORYMAP ---------- Begins the memory map definition. Using .MEMORYMAP you must first describe the target system's memory architecture to WLA before it can start to compile the code. .MEMORYMAP gives you the freedom to use WLA Z80/6502/65C02/6510/65816/HUC6280/SPC-700 to compile data for numerous different real Z80/6502/65C02/6510/65816/HUC6280/SPC-700 based systems. Examples: .MEMORYMAP SLOTSIZE $4000 DEFAULTSLOT 2 SLOT 0 $0000 SLOT 1 $4000 .ENDME .MEMORYMAP DEFAULTSLOT 1 SLOTSIZE $6000 SLOT 0 $0000 SLOTSIZE $2000 SLOT 1 $6000 SLOT 2 $8000 .ENDME Here's a real life example from Adam Klotblixt. It should be interesting for all the ZX81 coders: ... .MEMORYMAP DEFAULTSLOT 1 SLOTSIZE $2000 SLOT 0 $0000 SLOTSIZE $6000 SLOT 1 $2000 .ENDME .ROMBANKMAP BANKSTOTAL 2 BANKSIZE $2000 BANKS 1 BANKSIZE $6000 BANKS 1 .ENDRO .BANK 1 SLOT 1 .ORGA $2000 ... SLOTSIZE defines the size of the following slots. You can redefine it as many times as you wish, like in the second example. DEFAULTSLOT describes the default slot for banks which aren't explicitly inserted anywhere. Check .BANK definition for more information. SLOT defines a slot and its starting address. SLOT numbering starts at 0 and ends to 255 so you have 256 slots at your disposal. This is a compulsory directive, and make sure all the object files share the same .MEMORYMAP or you can't link them together. ------ .ENDME ------ Ends the memorymap. This is not a compulsory directive, but when .MEMORYMAP is used this one is required to terminate it. ----------- .ROMBANKMAP ----------- Begins the ROM bank map definition. You can use this directive to describe the project's ROM banks. Use .ROMBANKMAP when not all the ROM banks are of equal size. Note that you can use .ROMBANKSIZE and .ROMBANKS instead of .ROMBANKMAP, but that's only when the ROM banks are equal in size. Some systems based on a real Z80 chip, 6502/65C02/6510/65816/HUC6280/SPC-700 CPUs and Pocket Voice cartridges for Game Boy require the usage of this directive. Examples: .ROMBANKMAP BANKSTOTAL 16 BANKSIZE $4000 BANKS 16 .ENDRO .ROMBANKMAP BANKSTOTAL 510 BANKSIZE $6000 BANKS 1 BANKSIZE $2000 BANKS 509 .ENDRO The first one describes an ordinary ROM image of 16 equal sized banks. The second one defines a 4MB Pocket Voice ROM image. In the PV ROM image the first bank is $6000 bytes and the remaining 509 banks are smaller ones, $2000 bytes each. BANKSTOTAL tells the total amount of ROM banks. It must be defined prior to anything else. BANKSIZE tells the size of the following ROM banks. You can supply WLA with BANKSIZE as many times as you wish. BANKS tells the amount of banks that follow and that are of the size BANKSIZE which has been previously defined. This is not a compulsory directive when .ROMBANKSIZE and .ROMBANKS are defined. You can redefine .ROMBANKMAP as many times as you wish as long as the old and the new ROM bank maps match as much as possible. This way you can enlarge the size of the project on the fly. ------ .ENDRO ------ Ends the rom bank map. This is not a compulsory directive, but when .ROMBANKMAP is used this one is required to terminate it. --------- .SEED 123 --------- Seeds the random number generator. This is not a compulsory directive. The random number generator is initially seeded with the output of time(), which is, according to the manual, "the time since the Epoch (00:00:00 UTC, January 1, 1970), measured in seconds". So if you don't .SEED the random number generator yourself with a constant value, .DBRND and .DWRND give you different values every time you run WLA. --------------------- .SECTION "Init" FORCE --------------------- Section is a continuous area of data which is placed into the output file according to the section type and .BANK and .ORG directive values. The example begins a section called "Init". Before a section can be declared, .BANK and .ORG must be used unless WLA is in library file output mode. Library file's sections must all be FREE ones. .BANK tells the bank number where this section will be later relocated into. .ORG tells the offset for the relocation from the beginning of .BANK. You can supply the preferred section size (bytes) inside the section name string. Here's an example: .SECTION "Init_100" FREE will create a section ("Init") with size of 100 bytes, unless the actual data overflows from the section, in which case the section size is enlarged to contain all the data. Note that the syntax for explicit section size defining is: "NAME_X", where "NAME" is the name of the section and "X" is the size (decimal or hexadecimal value). You can also give the size of the section the following way: .SECTION "Init" SIZE 100 FREE It's possible to force WLALINK to align the FREE, SEMIFREE and SUPERFREE sections by giving the alignment as follows: .SECTION "Init" SIZE 100 ALIGN 4 FREE And if you want that WLA returns the ORG to what it was before issuing the section, put RETURNORG at the end of the parameter list: .SECTION "Init" SIZE 100 ALIGN 4 FREE RETURNORG By default WLA advances the ORG, so, for example, if your ORG was $0 before a section of 16 bytes, then the ORG will be 16 after the section. Note also that if your section name begins with double underlines (e.g., "__UNIQUE_SECTION!!!") the section will be unique in the sense that when WLALINK recieves files containing sections which share the same name, WLALINK will save only the first of them for further processing, all others are deleted from memory with corresponding labels, references and calculations. If a section name begins with an exclamation mark ('!') it tells WLALINK to not to drop it, even if you use WLALINK's ability to discard all unreferenced sections and there are no references to the section. FORCE after the name of the section tells WLA that the section _must_ be inserted so it starts at .ORG. FORCE can be replaced with FREE which means that the section can be inserted somewhere in the defined bank, where there is room. You can also use OVERWRITE to insert the section into the memory regardless of data collisions. Using OVERWRITE you can easily patch an existing ROM image just by .BACKGROUND'ing the ROM image and inserting OVERWRITE sections into it. SEMIFREE sections are also possible and they behave much like FREE sections. The only difference is that they are positioned somewhere in the bank starting from .ORG. SUPERFREE sections are also available, and they will be positioned into the first suitable place inside the first suitable bank (candidates for these suitable banks have the same size with the slot of the section, no other banks are considered). You can also leave away the type specifier as the default type for the section is FREE. You can name the sections as you wish, but there is one special name. A section called "BANKHEADER" is placed in the front of the bank where it is defined. These sections contain data that is not in the memory map of the machine, so you can't refer to the data of a BANKHEADER section, but you can write references to outside. So no labels inside BANKHEADER sections. These special sections are useful when writing e.g., MSX programs. Note that library files don't take BANKHEADER sections. Here's an example of a "BANKHEADER" section: .BANK 0 .ORG 0 .SECTION "BANKHEADER" .DW MAIN .DW VBI .ENDS .SECTION "Program" MAIN: CALL MONTY_ON_THE_RUN VBI: PUSH HL ... POP HL RETI .ENDS Here's an example of an ordinary section: .BANK 0 .ORG $150 .SECTION "Init" FREE DI LD SP, $FFFE SUB A LD ($FF00+R_IE), A .ENDS This tells WLA that a FREE section called "Init" must be located somewhere in bank 0. If you replace FREE with SEMIFREE the section will be inserted somewhere in the bank 0, but not in the $0-$14F area. If you replace FREE with SUPERFREE the section will be inserted somewhere in the Here's the order in which WLA writes the sections: 1. FORCE 2. SEMIFREE & FREE 3. SUPERFREE 4. OVERWRITE Before the sections are inserted into the output file, they are sorted by size, so that the biggest section gets processed first and the smallest last. You can also create a RAM section. For more information about them, please read the .RAMSECTION directive explanation. This is not a compulsory directive. -------------------------------- .RAMSECTION "Vars" BANK 0 SLOT 1 -------------------------------- RAMSECTIONs accept only variable labels and variable sizes, and the syntax to define these is identical to .ENUM (all the syntax rules that apply to .ENUM apply also to .RAMSECTION). Additionally you can embed structures (.STRUCT) into a RAMSECTION. Here's an example: .RAMSECTION "Some of my variables" BANK 0 SLOT 1 vbi_counter: db player_lives: db .ENDS RAMSECTIONs behave like FREE sections, but instead of filling any banks RAM sections will occupy area inside slots. You can fill different slots with different variable labels. It's recommend that you create separate slots for holding variables (as ROM and RAM don't usually overlap). Here's another example: .MEMORYMAP SLOTSIZE $4000 DEFAULTSLOT 0 SLOT 0 $0000 ; ROM slot 0. SLOT 1 $4000 ; ROM slot 1. SLOT 2 $A000 ; variable RAM is here! .ENDME .STRUCT game_object x DB y DB .ENDST .RAMSECTION "vars 1" BANK 1 SLOT 2 moomin DW phantom DB nyanko DB enemy INSTANCEOF game_object .ENDS If no other RAM section is used, then this is what you will get: .DEFINE moomin $A000 .DEFINE phantom $A002 .DEFINE nyanko $A003 .DEFINE enemy $A004 .DEFINE enemy.x $A004 .DEFINE enemy.y $A005 Note that the BANK value is only used when referring labels using notation ":label". BANK in .RAMSECTION is optional so you can leave it away if you think you don't need to know the bank number for a label inside a RAM section. This is not a compulsory directive. ----- .ENDS ----- Ends the section. This is not a compulsory directive, but when .SECTION is used this one is required to terminate it. ------- .ROMGBC ------- Inserts data into the specific ROM location to mark the ROM as a GBC ROM ($C0 -> $0143, so ROM name is max. 15 characters long). This is not a compulsory directive. ------- .ROMDMG ------- Inserts data into the specific ROM location to mark the ROM as a DMG ROM ($00 -> $0146). This is not a compulsory directive. .ROMDMG cannot be used with .ROMSGB. ------- .ROMSGB ------- Inserts data into the specific ROM location to mark the ROM as a SGB enhanced ROM ($03 -> $0146). This is not a compulsory directive. .ROMSGB cannot be used with .ROMDMG. -------------- .EXPORT work_x -------------- Exports the definition "work_x" to outside world. Exported definitions are visible to all object files and libraries in the linking procedure. Note that you can only export value definitions, not string definitions. You can export as many definitions as you wish with one .EXPORT: .EXPORT NUMBER, NAME, ADDRESS, COUNTRY .EXPORT NAME, AGE This is not a compulsory directive. -------------------------- .PRINTT "Here we are...\n" -------------------------- Prints the given text into stdout. Good for debugging stuff. PRINTT takes only a string as argument, and the only supported formatting symbol is '\n' (line feed). This is not a compulsory directive. ------------------- .PRINTV DEC DEBUG+1 ------------------- Prints the value of the supplied definition or computation into stdout. Computation must be solvable at the time of printing (just like definitions values). PRINTV takes two parameters. The first describes the type of the print output. "DEC" means decimal, "HEX" means hexadecimal. Use PRINTV with PRINTT as PRINTV doesn't print linefeeds, only the result. Here's an example: .PRINTT "Value of \"DEBUG\" = $" .PRINTV HEX DEBUG .PRINTT "\n" This is not a compulsory directive. ------------------ .OUTNAME "other.o" ------------------ Changes the name of the output file. Here's and example: wla-gb -o test.s would normally output "test.o", but if you had written .OUTNAME "new.o" somewhere in the code WLA would write the output to new.o instead. This is not a compulsory directive. ----------- .SNESHEADER ----------- This begins the SNES header definition, and automatically defines .COMPUTESNESCHECKSUM. From here you may define any of the following: ID "ABCD" - inserts a one to four letter string starting at $7FB2 (lorom) or $FFB2 (hirom). NAME "Hello World!" - identical to a freestanding .NAME. LOROM - identical to a freestanding .LOROM. HIROM - identical to a freestanding .HIROM. SLOWROM - identical to a freestanding .SLOWROM. FASTROM - identical to a freestanding .FASTROM. CARTRIDGETYPE $00 - Places the given 8-bit value in $7FD6 ($FFD6 in HiROM). Some possible values I've come across but cannot guarantee the accuracy of: $00 ROM only $01 ROM and RAM $02 ROM and Save RAM $03 ROM and DSP1 chip $04 ROM, RAM and DSP1 chip $05 ROM, Save RAM and DSP1 chip $13 ROM and Super FX chip ROMSIZE $09 - Places the given 8-bit value in $7FD7 ($FFD7 in HiROM). Possible values include (but may not be limited to:) $08 - 2 Megabits $09 - 4 Megabits $0A - 8 Megabits $0B - 16 Megabits $0C - 32 Megabits SRAMSIZE $01 - Places the given 8-bit value into $7FD8 ($FFD8 in HiROM). I believe these are the only possible values: $00 - 0 kilobits $01 - 16 kilobits $02 - 32 kilobits $03 - 64 kilobits COUNTRY $00 - Places the given 8-bit value into $7FD9 ($FFD9 in HiROM). $00 is Japan and $01 is the United States, and there several more for other regions that I cannot recall off the top of my head. LICENSEECODE $00 - Places the given 8-bit value into $7FDA ($FFDA in HiROM.) You must find the legal values yourself as there are plenty of them. ;) VERSION $01 - Places the given 8-bit value into $7FDB ($FFDB in HiROM) This is supposedly interpreted as version 1.byte, so a $01 here would be version 1.01. This is not a compulsory directive. -------- .ENDSNES -------- This ends the SNES header definition. This is not a compulsory directive, but when .SNESHEADER is used this one is required to terminate it. ----------------- .SNESNATIVEVECTOR ----------------- Begins definition of the native mode interrupt vector table. .SNESNATIVEVECTOR COP COPHandler BRK BRKHandler ABORT ABORTHandler NMI VBlank UNUSED $0000 IRQ IRQHandler .ENDNATIVEVECTOR These can be defined in any order, but they will be placed into memory starting at $7FE4 ($FFE4 in HiROM) in the order listed above. All the vectors default to $0000. This is not a compulsory directive. ---------------- .ENDNATIVEVECTOR ---------------- Ends definition of the native mode interrupt vector table. This is not a compulsory directive, but when .SNESNATIVEVECTOR is used this one is required to terminate it. -------------- .SNESEMUVECTOR -------------- Begins definition of the emulation mode interrupt vector table. .SNESEMUVECTOR COP COPHandler UNUSED $0000 ABORT BRKHandler NMI VBlank RESET Main IRQBRK IRQBRKHandler .ENDEMUVECTOR These can be defined in any order, but they will be placed into memory starting at $7FF4 ($FFF4 in HiROM) in the order listed above. All the vectors default to $0000. This is not a compulsory directive. ------------- .ENDEMUVECTOR ------------- Ends definition of the emulation mode interrupt vector table. This is not a compulsory directive, but when .SNESEMUVECTOR is used this one is required to terminate it. ------------------------------------------------------------------------------ 3.... Assembler Syntax ------------------------------------------------------------------------------ 3.1. Case Sensitivity WLA is case sensitive, so be careful. 3.2. Comments Comments begin with ';' or '*' and end along with the line. ';' can be used anywhere, but '*' can be placed only at the beginning of a new line. Version 4.1 of WLA introduced ANSI-C -like commenting. This means you can start a multiline comment with "/*" and end it with "*/". Version 6.0 of WLA introduced .ASM and .ENDASM directives. These function much like ANSI-C comments, but unlike the ANSI-C comments these can be nested. 3.3. Labels Labels are ordinary strings (which can also end to a ':'). Labels starting with "_" are considered to be local labels and do not show outside sections where they were defined, or outside object files, if they were not defined inside a section. Here are few examples of different labels: VBI_IRQ: VBI_IRQ2 _VBI_LOOP: main: Note that when you place ':' in front of the label string when referring to it, you'll get the bank number of the label, instead of the label's address. Here's an example: LD A, :LOOP .BANK 2 SLOT 0 LOOP: Here "LD A, :LOOP" will be replaced with "LD A, 2" as the label LOOP is inside the bank number two. When you are referring to a label and you are adding something to its address (or subtracting, any arithmetics apply) the result will always be bytes. .org 20 DATA: .dw 100, 200, 300 ld a, DATA+1 ^^^^^^ = r So here the result r will be the address of DATA plus one, here 21. Some x86 assemblers would give here 22 as the result r as DATA points to an array or machine words, but WLA isn't that smart (and some people including me think this is the better solution). You can also use -, --, ---, +, ++, +++, ... as un-named labels. Labels consisting of '-' are meant for reverse jumps and labels consisting of '+' are meant for forward jumps. You can reuse un-named labels as much as you wish inside your source code. Here's an example of this: dec e beq ++ ; jump -> ? dec e beq + ; jump -> % ld d, 14 --- ld a, 10 ; ! -- ld b, c ; # - dec b ; * jp nz, - ; jump -> * dec c jp nz, -- ; jump -> # dec d jp nz, --- ; jump -> ! ld a, 20 - dec a ; $ jp nz, - ; jump -> $ + halt ; % ++ nop ; ? Note that "__" (that's two underline characters) serves also as a un-named label. You can refer to this label from both directions. Use "_b" when you are jumping backwards and "_f" when you are jumping forwards label "__". Example: dec e jp z, _f ; jump -> * dec e __ ldi a, (hl) ; * dec e jp nz, _b ; jump -> * CAVEAT! CAVEAT! CAVEAT! The following code doesn't work as it would if WLA would determine the distance lexically (but in practice it's WLALINK that does all the calculations and sees only the preprocessed output of WLA): .macro dummy - dec a ; # jp nz, - ; jump -> # .endm ... - nop ; * dummy dec e jp nz, - ; i'd like to jump to *, but i'll end up jumping ; to # as it's closest to me in the output WLA produces ; for WLALINK (so it's better to use \@ with labels inside ; a macro). 3.4. Number Types 1000 - decimal $100 - hexadecimal 100h - hexadecimal %100 - binary 'x' - character Remember that if you use the suffix 'h' to give a hexadecimal value, and the value begins with an alphabet, you must place a zero in front of it so WLA knows it's not a label (e.g., "0ah" instead of "ah"). 3.5. Strings Strings begin with and end to '"'. Note that no 0 is inserted to indicate the termination of the string like in e.g., ANSI C. You'll have to do it yourself. You can place quotation marks inside strings the way C preprocessors accept them. Here are some examples of strings: "Hello world!" "He said: \"Please, kiss me honey.\"" 3.6. Mnemonics You can give the operand size with the operand itself (and this is highly recommended) in WLA 6502/65C02/6510/HUC6280/65816: and #20.b and #20.w bit loop.b bit loop.w Additionally there is an extra mnemonic in the GB-Z80 version of WLA called "DEBUG" which will translate to $ED. This one is not used in real GB-Z80, but my Game Boy emulator, Wzonka-Lad, will invert the Amiga's power light mode when $ED is executed. Don't use DEBUG if you are going to use your code elsewhere! 3.7. Brackets? Brackets are also supported in the GB-Z80/Z80/6502/65C02/HUC6280/6510 syntax. So you can write LDI (HL), A or LDI [HL], A Yes, you could write LDI [HL), A but I don't recommend that. ;) Note that brackets have special meaning when dealing with a 65816/SPC-700 system so you can't use AND [$65] instead of AND ($65) as they mean different things. ------------------------------------------------------------------------------ 4.... Error Messages ------------------------------------------------------------------------------ There are quite a few of them in WLA, but most of them are not as informative as I would like them to be. This will be fixed in the future. Mean while, be careful. ;) ------------------------------------------------------------------------------ 5.... Supported ROM/RAM/Cartridge Types (WLA-GB) ------------------------------------------------------------------------------ 5.1. ROM Size GB-Z80 version of WLA supports the following ROM bank sizes. There's no such limit in the Z80/6502/65C02/6510/65816/HUC6280/SPC-700 version of WLA. Supply one of the following values to .ROMBANKS. $0 - 256Kbit = 32KByte = 2 banks $1 - 512Kbit = 64KByte = 4 banks $2 - 1Mbit = 128KByte = 8 banks $3 - 2Mbit = 256KByte = 16 banks $4 - 4Mbit = 512KByte = 32 banks $5 - 8Mbit = 1MByte = 64 banks $6 - 16Mbit = 2MByte = 128 banks $52 - 9Mbit = 1.1MByte = 72 banks $53 - 10Mbit = 1.2MByte = 80 banks $54 - 12Mbit = 1.5MByte = 96 banks 5.2. RAM Size Supply one of the following hex values to .RAMSIZE in the GB-Z80 version of WLA. $0 - None $1 - 16kbit = 2kByte = 1 bank $2 - 64kbit = 8kByte = 1 bank $3 - 256kbit = 32kByte = 4 banks $4 - 1Mbit = 128kByte = 16 banks 5.3. Cartridge Type It's up to the user to check that the cartridge type is valid and can be used combined with the supplied ROM and RAM sizes. Give one the the following values to .CARTRIDGETYPE in the GB-Z80 version of WLA. $0 - ROM ONLY $1 - ROM+MBC1 $2 - ROM+MBC1+RAM $3 - ROM+MBC1+RAM+BATT $5 - ROM+MBC2 $6 - ROM+MBC2+BATTERY $8 - ROM+RAM $9 - ROM+RAM+BATTERY $B - ROM+MMM01 $C - ROM+MMM01+SRAM $D - ROM+MMM01+SRAM+BATT $F - ROM+MBC3+TIMER+BATT $10 - ROM+MBC3+TIMER+RAM+BATT $11 - ROM+MBC3 $12 - ROM+MBC3+RAM $13 - ROM+MBC3+RAM+BATT $19 - ROM+MBC5 $1A - ROM+MBC5+RAM $1B - ROM+MBC5+RAM+BATT $1C - ROM+MBC5+RUMBLE $1D - ROM+MBC5+RUMBLE+SRAM $1E - ROM+MBC5+RUMBLE+SRAM+BATT $1F - Pocket Camera $BE - Pocket Voice $FD - Bandai TAMA5 $FE - Hudson HuC-3 $FF - Hudson HuC-1 ------------------------------------------------------------------------------ 6.... Bugs ------------------------------------------------------------------------------ If you find bugs, please let me know asap. Anything, small or big, send me email! I won't eat you for reporting a bug. Probably your name just ends up in the thanks-section of this documentation. ;) ------------------------------------------------------------------------------ 7.... Files ------------------------------------------------------------------------------ 7.1. 'examples' The main purpose of the files in the 'examples' directory is to teach people few things about WLA. If you feel a little uncertain with the syntax check out this place. 'examples' directory holds seven directories, 'gb-z80', 'z80', '6502', '65c02', '6510', '65816' and 'spc-700'. 'include' directory under 'gb-z80' could be very useful as the six include files there have all the Game Boy hardware register address and memory definitions you could ever need and more. 7.2. 'examples/gb-z80/lib' This folder holds few very useful libraries for you to use in your Game Boy projects. Instead of reinventing the wheel, use the stuff found in here. Remember to compile the libraries right after you've installed WLA by executing 'make' in the 'lib' directory. ------------------------------------------------------------------------------ 8.... Temporary Files ------------------------------------------------------------------------------ Note that WLA will generate two temporary files while it works. Both files are placed into the current working directory. Under Amiga: "wla_a.tmp" and "wla_b.tmp". Under MSDOS: "wla_a.tmp" and "wla_b.tmp". Under Win32: ".wla%PID%a" and ".wla%PID%b" (where %PID% is the process id). Under Unix: ".wla%PID%a" and ".wla%PID%b" (where %PID% is the process id). When WLA finishes its work these two files are deleted as they serve of no further use. ------------------------------------------------------------------------------ 9.... Compiling ------------------------------------------------------------------------------ 9.1. Compiling Object Files To compile an object file use: "wla -[itvx]o [DEFINITIONS] [OUTPUT FILE]" These object files can be linked together (or with library files) later with "wlalink". Name object files so that they can be recognized as object files. Normal suffix is ".o" (WLA default). This can also be changed with .OUTNAME. With object files you can reduce the amount of compiling when editing small parts of the program. Note also the possibility of using local labels (starting with "_"). Note! When you compile objects, group 1 directives are saved for linking time, when they are all compared and if they differ, an error message is shown. It is advisable to use something like an include file to hold all the group 1 directives for that particular project and include it to every object file. If you are interested in the WLA object file format, take a look at the file "txt/wla_file_formats.txt" which is included in the release archive. Here are some examples of definitions: -DIEXIST -DDAY=10 -DBASE=$10 -DNAME=elvis And here's an WLA example creating definitions on the command line: wla-gb -o -DDEBUG -DVERBOSE=5 -DNAME="math v1.0" math.s DEBUG's value will be 0, VERBOSE's 5 and NAME is a string definition with value "math v1.0". 9.2. Compiling Library Files To compile a library file use: "wla -[itvx]l [DEFINITIONS] [OUTPUT FILE]" Name object files so that they can be recognized as library files. Normal suffix is ".lib" (WLA default). With library files you can reduce the amount of compiling. Library files are meant to hold general functions that can be used in different projects. Note also the possibility of using local labels (starting with "_"). Library files consist only of FREE sections. ------------------------------------------------------------------------------ 10... Linking ------------------------------------------------------------------------------ After you have produced one or more object files and perhaps some library files, you might want to link them together to produce a ROM image / program file. "wlalink" is the program you use for that. Here's how you use it: "wlalink [-divs]{b/r} " Choose 'b' for program file or 'r' for ROM image linking. Link file is a text file that contains information about the files you want to link together. Here's the format: 1. You must define the group for the files. Put the name of the group inside brackets. Valid group definitions are [objects] [libraries] [header] [footer] [definitions] 2. Start to list the file names. [objects] main.o vbi.o level_01.o ... 3. Give parameters to the library files: [libraries] bank 0 slot 1 speed.lib bank 4 slot 2 map_data.lib ... Here you can also use "base" to define the 65816 CPU bank number (like .BASE works in WLA): [libraries] bank 0 slot 1 base $80 speed.lib bank 4 slot 2 base $80 map_data.lib ... You must tell WLALINK the bank and the slot for the library files. 4. If you want to use header and/or footer in your project, you can type the following: [header] header.dat [footer] footer.dat 5. If you want to make value definitions, here's your chance: [definitions] debug 1 max_str_len 128 start $150 ... If flag 'v' is used, WLALINK displays information about ROM file after a succesful linking. If flag 's' is used, WLALINK will produce a NO$GMB symbol file. It's useful when you work under MSDOS (NO$GMB is a very good Game Boy emulator for MSDOS/ Windows) as it contains information about the labels in your project. If flag 'd' is used, WLALINK discards all unreferenced FREE and SEMIFREE sections. This way you can link big libraries to your project and WLALINK will choose only the used sections, so you won't be linking any dead code/data. If flag 'i' is given, WLALINK will write list files. Note that you must compile the object and library files with -i flag as well. Otherwise WLALINK has no extra information it needs to build list files. Here is an example of a list file: Let's assume you've compiled a source file called "main.s" using the 'i' flag. After you've linked the result also with the 'i' flag WLALINK has created a list file called "main.lst". This file contains the source text and the result data the source compiled into. List files are good for debugging. Make sure you don't create duplicate labels in different places in the memory map as they break the linking loop. Duplicate labels are allowed when they overlap each other in the destination machine's memory. Look at the following example: ... .BANK 0 .ORG $150 ... LD A, 1 CALL LOAD_LEVEL ... LOAD_LEVEL: LD HL, $2000 LD (HL), A CALL INIT_LEVEL RET .BANK 1 .ORG 0 INIT_LEVEL: ... RET .BANK 2 .ORG $0 INIT_LEVEL: ... RET ... Here duplicate INIT_LEVEL labels are accepted as they both point to the same memory address (in the program's point of view). ------------------------------------------------------------------------------ 11... Arithmetics ------------------------------------------------------------------------------ WLA is able to solve really complex calculations like -((HELLO / 2) | 3) skeletor_end-skeletor 10/2.5 so you can write something like LD HL, data_end-data LD A, (pointer + 1) CP (TEST + %100) & %10101010 WLALINK also has this ability so it can compute the pending calculations WLA wasn't able to solve. The following operators are valid: (, ), | (or), & (and), ^ (power), << (shift left), >> (shift right), +, -, # (modulo), ~ (xor), *, /, < (get the low byte) and > (get the high byte). Note that you can do NOT using XOR: VALUE_A ~ $FF = 8bit NOT VALUE_B ~ $FFFF = 16bit NOT WLA computes internally with real numbers so (5/2)*2 produces 5, not 4. ------------------------------------------------------------------------------ 12... Disassembling ------------------------------------------------------------------------------ WLAD is a disassembler that can be used to disassemble an existing GB-ROM image into a WLA-syntax compatible source file. It won't produce very readable code as all the labels etc. are discarded in the last phase of linking when the ROM image is made. In the current state WLAD doesn't generate labels, but it will in the future. Here's how you use it: "wlad [-dsa] " Give it the binary file (usually the extension is .gb or .cgb) and WLAD will output the source code into stdout (the shell you are using). Here's an example what you can do if you want the source code into a file instead of the screen: "wlad tbp.cgb > tbp.s" WLAD has three option flags: a - Disable address output. d - The upper banks (1->) are disassembled as data. s - The upper banks (1->) are disassembled as data with string detection enabled. Use the 's'-flag if you intend to change texts in games. The flags 'd' and 's' cannot be used at the same time. Examples: [seravy@localhost parallax]# wlad -da parallax.gb > parallax.s [seravy@localhost parallax]# wlad -s parallax.gb > parallax.s WLAD supports both normal GB-ROMs and Pocket Voice (tm) ROM images. Only WLAD GB-Z80 exists curently. ------------------------------------------------------------------------------ 13... Binary to DB Conversion ------------------------------------------------------------------------------ WLAB converts binary files to WLA's byte definition strings. Here's how you use it: "wlab -[ap]{bdh} " Give it the binary file and WLAB will output the WLA DB formatted data of it into stdout. Here's an example from real life: "wlad -da gayskeletor.bin > gayskeletor.s" WLAB has three command flags of which one must be given to WLAB: b - Output data in binary format. d - Output data in decimal format. h - Output data in hexadecimal format. WLAB has also two option flags: a - Print the address (relative to the beginning of the data). p - Don't print file header. Examples: [seravy@localhost src]# wlab -bap iscandar.bin > iscandar.s [seravy@localhost src]# wlab -h starsha.bin > starsha.s ------------------------------------------------------------------------------ 14... Things you should know about coding for... ------------------------------------------------------------------------------ Please check out the source code examples (in 'examples' directory) for quick target system specific information. 14.1. Z80 Check the Z80 specific directives. All SMS/GG coders should find .SMSTAG, .SDSCTAG and .COMPUTESMSCHECKSUM very useful... 14.2. 6502 For example mnemonics ADC, AND, ASL, etc... cause problems to WLA, because they take different sized arguments. Take a look at this: LSR 11 ; $46 $0B LSR $A000 ; $4E $00 $A0 The first one could also be LSR 11 ; $4E $0B $00 To really get what you want, use .8BIT, .16BIT and .24BIT directives. Or even better, supply WLA the size of the argument: LSR 11.W ; $4E $0B $00 14.3. 65C02 Read 14.2. as the information applies also to 65C02 coding... 14.4. 6510 Read 14.2. as the information applies also to 6510 coding... 14.5. 65816 Read 14.2. as the information applies also to 65816 coding... WLA-65816 has also few SNES specific directives which are all very helpful. Remember that when you use .LOROM, .HIROM, .SLOWROM and .FASTROM WLA automatically writes the information into the output. .COMPUTESNESCHECKSUM, .SNESHEADER and few others could also be useful. Use .BASE to set the upmost eight bits of 24bit addresses. If possible, use operand hints to specify the size of the operand. WLA is able to deduce the accumulator/index mode to some extent from REP/SEP -mnemonics and .ACCU and .INDEX -directives, but just to be sure, terminate the operand with .B, .W or .L. AND #10 ; can be two different things, depending on the size of the accu. AND #10.B ; forces 8bit immediate value. AND #10.W ; forces 16bit immediate value. Or if you must, these work as well: AND.B #10 ; the same as "AND #10.B". AND.W #10 ; the same as "AND #10.W". 14.6. HUC6280 Read 14.2. as the information applies also to HUC6280 coding... 14.7. SPC-700 Nothing special so far... 14.8. Pocket Voice (GB-Z80) Pocket Voice uses its own MBC. You can enable Pocket Voice mode by selecting Pocket Voice cartridge type ($BE in $0147) and defining correct .ROMBANKMAP and .MEMORYMAP. In PV mode bank 0 is 24KB and the rest are 8KB. Note that WLA assumes that ROM offset is all the time 0. If you use something else as the offset, make sure to compute the jumps by hand as WLA cannot do that. Check out examples/gb-z80/include/pocket_voice.i for more information. 14.9. GB-Z80 WLA outputs only $10 when it decodes "STOP". Often it's necessary to put an extra "NOP" ($00) after a "STOP", and sometimes something else, but that's left entirely to the user. ------------------------------------------------------------------------------ 15... WLA Flags ------------------------------------------------------------------------------ Here are short descriptions for the flags you can give to WLA: You can supply WLA with some (or all or none) of the following option flags. i - Add list file information. Adds extra information to the output so WLALINK can produce list files. M - WLA generates makefile rules describing the dependencies of the main source file. Use only with flags 'o' and 'l'. q - Quiet mode. .PRINT* -directives output nothing. t - Test compile. Doesn't output any files. v - Verbose mode. Shows a lot of information about the compiling process. x - Extra compile time definitions. WLA does extra work by creating few helpful definitions on the fly. One (and only one) of the following command flags must be defined. l - Output a library file. o - Output an object file. Examples: [seravy@localhost tbp]# wla -voi testa.s [seravy@localhost tbp]# wla -oM testa.s [seravy@localhost tbp]# wla -l testb.s testb.lib Note that the first example produces file named "testa.o". ------------------------------------------------------------------------------ 16... Extra compile time definitions ------------------------------------------------------------------------------ When you supply WLA with the flag 'x' it will maintain few useful definitions while compiling your source codes. Please use the enhanced error reporting engine (so don't use flag 'f') in conjunction with flag 'x' as some of the definitions require extra information about the flow of the data which isn't available when using the old, crippled error reporting engine. Here's a list of what you get when you use flag 'x': WLA_FILENAME - A string definition holding the file name WLA is currently processing. WLA_TIME - A string definition holding the calendar time (obtained using C's ctime()). WLA_VERSION - A string definition holding the version number of WLA. So you can do for example something like .DB WLA_TIME to store the time when the build process started into the ROM file you are compiling. Definition "CADDR", which is present without supplying the flag 'x', contains the current 16bit memory address. So LD HL, CADDR will load the address of the operand data into registers H and L. CAVEAT: Remember when using defines that CADDR gets the address of the place where the definition is used, not the address of the definition, which contains the CADDR. Note that you'll also get all these definitions in lower case (e.g., "wla_filename"). ------------------------------------------------------------------------------ 17... Good things to know about WLA ------------------------------------------------------------------------------ - Is 64 bytes too little for a string (file names, labels, definition labels, etc)? Check out "MAX_NAME_LENGTH" in defines.h. - WLA preprocessor doesn't expand macros and repetitions. Those are actually traversed in the assembling phase. - WLA's source code is mainly a huge mess, but WLALINK is quite well structured and written. So beware! - Do not write ".E" into your sources as WLA uses it internally to mark the end of a file. ------------------------------------------------------------------------------ 18... Author ------------------------------------------------------------------------------ Ville Helin, the author of Wzonka-Lad, a Game Boy emulator for the Amiga machines, among other things. I work at the Helsinki University of Technology (http://www.hut.fi) as a researcher. I like Game Boy (goes without saying), anime soap operas, gym and hardcore video gaming. email: vhelin#iki.fi hpage: http://www.iki.fi/~vhelin smail: Ville Helin Dagmarinkatu 8 C 38 00100 Helsinki Finland ------------------------------------------------------------------------------ 19... Thanks ------------------------------------------------------------------------------ - Gaelan Griffin for endless suggestions and fast bug reports! Take one feature from WLA and you have a 40% propability that Gaelan bugged me to implement it. ;) - Aleksi Eeben for lots of good bug reports and feature ideas! - Nicolas Warren for few some serious bug reports (and even fixes to them!) and for the good ideas! - Madonna MkII (Matra Computer Corp.), Mike Blum, Anders Montonen, Robert Kihl, Martin Konrad, Arto Salmi, Maxim, Yoshiaki Ishida Tobias Pflug, Brad Jorsch and Michel Iwaniec for reporting bugs in WLA and providing me with great ideas. - Mark Knox, Igor Wronsky and Anders Montonen for helping me with the MSDOS port! - Gaelan Griffin for the Amiga port and valuable SPC-700 information! - FluBBa for crucial HuC6280 bug reports! - Christophe Iasci for the Win32 port! - Marc Dünster and Kevin Mantey for the big help and suggestions with wla-65816 and wla-spc700! - John Schneider for makefile enhancements! - Timo Jantunen for helping me with makefiles. - Adam Klotblix for documentation improvements and bug reports. - Zachary Keene for writing .SNESHEADER, .ENDSNES, .SNESNATIVEVECTOR, .ENDNATIVEVECTOR, .SNESEMUVECTOR and .ENDEMUVECTOR. I want more people like him! ;) - People at gameboy@vip.co.za, gameboydev@listbot.com, gbadev@yahoogroups.com and s8-dev for keeping up the good work! ;) ------------------------------------------------------------------------------ 20... Future ------------------------------------------------------------------------------ Future enhancements (if I get really inspired): - Listfiles. - Much more features to WLAD (I already know of three) and Z80/6502/65C02/6510/65816/HUC6280/SPC-700 support. - Other optimizations, bug fixes and new features. - You tell me. ------------------------------------------------------------------------------ 21... Support ------------------------------------------------------------------------------ The currently supported systems are MSDOS/x86, Win32/x86, AmigaOS/680x0 and Unix/xyz. If you'd like to see WLA for other platforms/configurations, send me email and we'll see what I can do about it (if compiling WLA DX binaries from the source release archive doesn't work for some reason). ------------------------------------------------------------------------------ 22... Legal Note ------------------------------------------------------------------------------ WLA DX (the whole package) was written by Ville Helin, except for those parts mentioned in section 19, in 1998-2004. WLA DX is GPL software. For more information about GPL, take a look at the LICENCE file. Game Boy and Game Boy Color are copyrighted by Nintendo. Pocket Voice is copyrighted by Bung HK.