Asar User Manual

# Asar

A multi-architecture SNES assembler by Alcaro, modelled after xkas v0.06 by byuu.
This manual was written by RPG Hacker, so if you find something that is wrong or weird, make sure to blame me instead of Alcaro.

As a general rule, the manual uses `{}` to denote required parameters and `[]` to denote optional parameters (where optional parameters ending in `...` mean "zero or more" of that parameter). Everything else refers to keywords/names.

### Table of Contents

- Usage
  - Standard Includes
  - Standard Defines
- Architectures
  - Number Literals
  - Opcode Length Specification
  - Pseudo Opcodes
  - rep
  - spcblock
- Mapping Modes
- Compatibility Settings
  - xkas
  - asar
  - warn xkas
  - math pri
  - math round
  - namespace nested
- Code Formatting
  - Comments
  - Brackets
  - Multi-Line Operators
  - Single-Line Operator
- Program Counter
  - org
  - base
  - skip
  - warnpc
  - bank
  - dpbase
  - optimize dp
  - optimize address
  - pushpc/pullpc
  - pushbase/pullbase
- Math
- Labels
  - Main Labels
  - Sub Labels
  - +/- Labels
  - Macro Labels
  - Structs
  - Namespaces
  - pushns/pullns
  - Global labels
- Defines
  - Nested Defines
  - Built-in Defines
- Macros
- Functions
  - Built-in Functions
- Conditional Compilation
  - if/elseif/else/endif
  - while
  - for
- Binary Data
  - Tables
  - fillbyte/fill
  - padbyte/pad
  - incbin
- Includes
  - incsrc
  - include/includefrom
  - includeonce
- Freespace
  - freespace/freecode/freedata
  - freespacebyte
  - autoclean
  - prot
- Text Output
  - print
  - warn
  - error
  - assert
- Checks
  - check title
  - check bankcross
- Warnings
  - Disabled Warnings
  - warnings {push/pull}
  - warnings {enable/disable}
  - List of all warnings
- List of all errors

### Usage

    	asar.exe [options] {asm_file} [rom_file]

Argument | Type | Details | Examples
--- | --- | --- | ---
`[options]` |  | List of optional arguments. The following options are supported: |
`--version` | Input | Displays Asar version information. |
    asar.exe --version C:/homebrew/my_game/main.asm
`-v` `--verbose` | Input | Enables verbose mode. |
    asar.exe -v C:/homebrew/my_game/main.asm
    asar.exe --verbose C:/homebrew/my_game/main.asm
`--no-title-check` | Input | Disables input ROM title and checksum verification when using Asar to apply a patch to an existing ROM file. Note that irresponsible use of this option will likely corrupt your ROM. |
    asar.exe --no-title-check C:/homebrew/my_game/main.asm
`--pause-mode={mode}` | Input | Sets Asar's pause mode, specifying when Asar should pause the application before exit, where `{mode}` can be one of the following: `never`: Don't pause the application (default). `on-error`: Pause the application if an error was thrown. `on-warning`: Pause the application if an error or a warning was thrown. `always`: Always pause the application. |
    asar.exe --pause-mode=always C:/homebrew/my_game/main.asm
`-I{path}` `--include {path}` | Input | Adds an include search path for file-based commands to Asar. Normally, commands like incsrc, incbin etc. look for files relative to the ASM file that is currently being compiled. If those files aren't found, an error is thrown, unless you specify include search paths, in which case Asar will look for the file in each respective directory before throwing an error. For example, imagine you compiled the file
    C:/homebrew/my_game.asm
with Asar, adding the include search path
    -I"C:/homebrew/binary data"
and the ASM file included the line:
    incbin "data/player_gfx.bin"
Asar would now look for a file:
    C:/homebrew/data/player_gfx.bin
If this file didn't exist, it would then look for a file:
    C:/homebrew/binary data/data/player_gfx.bin
If this file didn't exist, Asar would throw an error, otherwise Asar would include it. See section Includes for details on Asar's handling of file names. |
    asar.exe -IC:/homebrew/my_game/includes -IC:/homebrew/shared
    	C:/homebrew/my_game/main.asm C:/homebrew/my_game/bin/my_game.sfc
    asar.exe --include C:/homebrew/my_game/includes
    	C:/homebrew/my_game/main.asm C:/homebrew/my_game/bin/my_game.sfc
`-D{identifier}[=value]` `--define {identifier}[=value]` | Input | Adds a define to Asar. When no value is provided, the define is set to an empty string. See section Defines for details. |
    asar.exe -Ddebug -Dskip_title_screen=0
    	C:/homebrew/my_game/main.asm C:/homebrew/my_game/bin/my_game.sfc
    asar.exe --define debug=1 --define mytext=" value with whitespace "
    	C:/homebrew/my_game/main.asm C:/homebrew/my_game/bin/my_game.sfc
`--symbols={format}` | Input | Specifies the format of the symbols output file generated by Asar. The following values are supported for {format}: `none`: Don't generate a symbols file (default). `wla`: Generate a symbols file in the WLA format. This format additionally includes an address-to-line mapping which can be used by some debuggers to provide source-level debugging. `nocash`: Generate a symbols file in the no$sns format. |
    asar.exe --symbols=wla C:/homebrew/my_game/main.asm
`--symbols-path={path}` | Output | Specifies the path and file name to use for generating the symbols output file. By default, the path is the path of `[rom_file]` and the file name is the base name of `[rom_file]` with an extension of `.sym`. Ignored when `--symbols` is set to `none`. Note that relative paths here are relative from the current working directory, not relative from `{asm_file}` or `[rom_file]`. |
    asar.exe --symbols=wla
    	--symbols-path=C:/homebrew/my_game/symbols/main.symbols
    	C:/homebrew/my_game/main.asm
`-w{name}` | Input | Enables the warning with the specified name. See section Warnings for details. |
    asar.exe -wWimplicitly_sized_immediate C:/homebrew/my_game/main.asm
`-wno{name}` | Input | Disables the warning with the specified name. See section Warnings for details. |
    asar.exe -wnoWfreespace_leaked C:/homebrew/my_game/main.asm
`--fix-checksum={on/off}` | Input | Overrides Asar's default behavior of enabling or disabling checksum generation based on context. When set to `on`, Asar always generates a checksum. When set to `off`, Asar never generates a checksum. |
    asar.exe --fix-checksum=on C:/homebrew/my_game/main.asm
`--error-limit={n}` | Input | Sets the maximum number of errors that Asar will print before stopping. The default is 20. |
    asar.exe --error-limit=500 C:/homebrew/my_game/main.asm
`{asm_file}` | Input | Path to the ASM source file. |
    asar.exe C:/homebrew/my_game/main.asm C:/homebrew/my_game/bin/my_game.sfc
`[rom_file]` | Input, output | Path to the ROM file that is modified by Asar. If this file doesn't exist yet, Asar creates a new ROM file instead. When omitted, Asar checks if asm_file_name.sfc or asm_file_name.smc exists and uses the one it finds. When zero or two ROMs with that filename are found, Asar defaults to the .sfc extension. As a convention, Asar always treats .smc files as headered and .sfc files as unheadered ROMs. This means that headered .sfc files or unheadered .smc files cannot be used with Asar unless their extension is changed. This is by design and meant to encourage compliance with the convention. |
    asar.exe C:/homebrew/my_game/main.asm C:/homebrew/my_game/bin/my_game.sfc
    asar.exe C:/homebrew/my_game/main.asm C:/homebrew/my_game/bin/my_game.smc
    asar.exe C:/homebrew/my_game/main.asm

For convenience, double-clicking the Asar executable will prompt you to enter paths to an ASM file and a ROM file and thus allow you to directly use Asar without passing any command line arguments to it.

#### Standard Includes

Aside from passing include search paths to Asar via the command line, it's possible to also do so via a file called `stdincludes.txt`. When a file with this name exists next to the Asar executable, Asar automatically opens it and adds every line in it as an include search path (trailing and leading whitespace on a line is ignored, as are lines containing only whitespace). Absolute and relative paths are supported. Relative paths are considered relative to the TXT file. The purpose of this file is to make it easier to distribute standard code libraries for use with Asar by making it possible to just unpack the contents of a ZIP file or similar directly into the Asar directory. Note that include search paths passed in via the command line get priority over paths parsed from this TXT file. See section Includes for details on include search paths.
All of the examples below are valid:

    C:/asm/stdlib

        ./debug
    ../../my_game/libraries
    		test/

#### Standard Defines

Aside from passing additional defines to Asar via the command line, it's possible to also do so via a file called `stddefines.txt`. When a file with this name exists next to the Asar executable, Asar automatically opens it and adds every line in it as an additional define. The syntax is similar to Asar's regular define syntax, with a few notable differences. There are no spaces required around the `=`, the `!` of the identifier is optional, whitespace around the identifier is ignored, so is whitespace around the value (unless the value is delimited by double quotes, in which case any whitespace inside is kept in the define), the value itself is optional (when left out, it is set to an emptry string). Lines containing only whitespace are ignored. The purpose of this file is to make it easier to distribute standard code libraries for use with Asar by making it possible to just unpack the contents of a ZIP file or similar directly into the Asar directory. See section Defines for details on defines.
All of the examples below are valid:

    !stddefined1=1
     stddefined2=1

    stddefined3
    stddefined4 = 1
    stddefined5 = " $60,$50,$40 "

Return to top

### Architectures

Asar supports a number of different target architectures for code compilation. They can be activated via the command `arch {name}`. Going into detail on any of the supported architectures is beyond the scope of this manual. For that, it's recommended to check the SNES Dev Manual or other specialized resources. Asar tries as much as possible to always stick to the known conventions and specifications of each respective architecture (with a few notable exceptions that are hopefully all covered somewhere in this manual).

Architecture | Command | Supported Opcodes | Details
--- | --- | --- | ---
65c816 | `arch 65816` | [+] Expand
    ADC #$00
    ADC #$0000
    ADC $00
    ADC $00,s
    ADC $00,x
    ADC $0000
    ADC $0000,x
    ADC $0000,y
    ADC $000000
    ADC $000000,x
    ADC ($00)
    ADC ($00),y
    ADC ($00,s),y
    ADC ($00,x)
    ADC [$00]
    ADC [$00],y
    AND #$00
    AND #$0000
    AND $00
    AND $00,s
    AND $00,x
    AND $0000
    AND $0000,x
    AND $0000,y
    AND $000000
    AND $000000,x
    AND ($00)
    AND ($00),y
    AND ($00,s),y
    AND ($00,x)
    AND [$00]
    AND [$00],y
    ASL $00
    ASL $00,x
    ASL $0000
    ASL $0000,x
    ASL A
    BCC $00
    BCS $00
    BEQ $00
    BIT #$00
    BIT #$0000
    BIT $00
    BIT $00,x
    BIT $0000
    BIT $0000,x
    BMI $00
    BNE $00
    BPL $00
    BRA $00
    BRK
    BRK #$00
    BRL $0000
    BVC $00
    BVS $00
    CLC
    CLD
    CLI
    CLV
    CMP #$00
    CMP #$0000
    CMP $00
    CMP $00,s
    CMP $00,x
    CMP $0000
    CMP $0000,x
    CMP $0000,y
    CMP $000000
    CMP $000000,x
    CMP ($00)
    CMP ($00),y
    CMP ($00,s),y
    CMP ($00,x)
    CMP [$00]
    CMP [$00],y
    COP
    COP #$00
    CPX #$00
    CPX #$0000
    CPX $00
    CPX $0000
    CPY #$00
    CPY #$0000
    CPY $00
    CPY $0000
    DEC $00
    DEC $00,x
    DEC $0000
    DEC $0000,x
    DEC A
    DEX
    DEY
    EOR #$00
    EOR #$0000
    EOR $00
    EOR $00,s
    EOR $00,x
    EOR $0000
    EOR $0000,x
    EOR $0000,y
    EOR $000000
    EOR $000000,x
    EOR ($00)
    EOR ($00),y
    EOR ($00,s),y
    EOR ($00,x)
    EOR [$00]
    EOR [$00],y
    INC $00
    INC $00,x
    INC $0000
    INC $0000,x
    INC A
    INX
    INY
    JML $000000
    JML [$0000]
    JMP $0000
    JMP ($0000)
    JMP ($0000,x)
    JSL $000000
    JSR $0000
    JSR ($0000,x)
    LDA #$00
    LDA #$0000
    LDA $00
    LDA $00,s
    LDA $00,x
    LDA $0000
    LDA $0000,x
    LDA $0000,y
    LDA $000000
    LDA $000000,x
    LDA ($00)
    LDA ($00),y
    LDA ($00,s),y
    LDA ($00,x)
    LDA [$00]
    LDA [$00],y
    LDX #$00
    LDX #$0000
    LDX $00
    LDX $00,y
    LDX $0000
    LDX $0000,y
    LDY #$00
    LDY #$0000
    LDY $00
    LDY $00,x
    LDY $0000
    LDY $0000,x
    LSR $00
    LSR $00,x
    LSR $0000
    LSR $0000,x
    LSR A
    MVN $00,$00
    (Note: destination, source)
    MVN $0000
    MVP $00,$00
    (Note: destination, source))
    MVP $0000
    NOP
    ORA #$00
    ORA #$0000
    ORA $00
    ORA $00,s
    ORA $00,x
    ORA $0000
    ORA $0000,x
    ORA $0000,y
    ORA $000000
    ORA $000000,x
    ORA ($00)
    ORA ($00),y
    ORA ($00,s),y
    ORA ($00,x)
    ORA [$00]
    ORA [$00],y
    PEA $0000
    PEI ($00)
    PER $0000
    PHA
    PHB
    PHD
    PHK
    PHP
    PHX
    PHY
    PLA
    PLB
    PLD
    PLP
    PLX
    PLY
    REP #$00
    ROL $00
    ROL $00,x
    ROL $0000
    ROL $0000,x
    ROL A
    ROR $00
    ROR $00,x
    ROR $0000
    ROR $0000,x
    ROR A
    RTI
    RTL
    RTS
    SBC #$00
    SBC #$0000
    SBC $00
    SBC $00,s
    SBC $00,x
    SBC $0000
    SBC $0000,x
    SBC $0000,y
    SBC $000000
    SBC $000000,x
    SBC ($00)
    SBC ($00),y
    SBC ($00,s),y
    SBC ($00,x)
    SBC [$00]
    SBC [$00],y
    SEC
    SED
    SEI
    SEP #$00
    STA $00
    STA $00,s
    STA $00,x
    STA $0000
    STA $0000,x
    STA $0000,y
    STA $000000
    STA $000000,x
    STA ($00)
    STA ($00),y
    STA ($00,s),y
    STA ($00,x)
    STA [$00]
    STA [$00],y
    STP
    STX $00
    STX $00,y
    STX $0000
    STY $00
    STY $00,x
    STY $0000
    STZ $00
    STZ $00,x
    STZ $0000
    STZ $0000,x
    TAX
    TAY
    TCD
    TCS
    TDC
    TRB $00
    TRB $0000
    TSB $00
    TSB $0000
    TSC
    TSX
    TXA
    TXS
    TXY
    TYA
    TYX
    WAI
    WDM
    WDM #$00
    XBA
    XCE
| Default setting. Compiles code for the 65c816 architecture.
SPC700 | `arch spc700` | [+] Expand
    ADC $00,#$00
    ADC $00,$00
    ADC (X),(Y)
    ADC A,#$00
    ADC A,$00
    ADC A,$00+X
    ADC A,$0000
    ADC A,$0000+X
    ADC A,$0000+Y
    ADC A,($00)+Y
    ADC A,($00+X)
    ADC A,(X)
    ADDW YA,$00
    AND $00,#$00
    AND $00,$00
    AND (X),(Y)
    AND A,#$00
    AND A,$00
    AND A,$00+X
    AND A,$0000
    AND A,$0000+X
    AND A,$0000+Y
    AND A,($00)+Y
    AND A,($00+X)
    AND A,(X)
    AND1 C,!$0000
    AND1 C,$0000
    ASL $00
    ASL $00+X
    ASL $0000
    ASL A
    BBC0 $00,$00
    BBC1 $00,$00
    BBC2 $00,$00
    BBC3 $00,$00
    BBC4 $00,$00
    BBC5 $00,$00
    BBC6 $00,$00
    BBC7 $00,$00
    BBS0 $00,$00
    BBS1 $00,$00
    BBS2 $00,$00
    BBS3 $00,$00
    BBS4 $00,$00
    BBS5 $00,$00
    BBS6 $00,$00
    BBS7 $00,$00
    BCC $00
    BCS $00
    BEQ $00
    BMI $00
    BNE $00
    BPL $00
    BRA $00
    BRK
    BVC $00
    BVS $00
    CALL $0000
    CBNE $00+x,$00
    CBNE $00,$00
    CLR0 $00
    CLR1 $00
    CLR2 $00
    CLR3 $00
    CLR4 $00
    CLR5 $00
    CLR6 $00
    CLR7 $00
    CLRC
    CLRP
    CLRV
    CMP $00,#$00
    CMP $00,$00
    CMP (X),(Y)
    CMP A,#$00
    CMP A,$00
    CMP A,$00+X
    CMP A,$0000
    CMP A,$0000+X
    CMP A,$0000+Y
    CMP A,($00)+Y
    CMP A,($00+X)
    CMP A,(X)
    CMP X,#$00
    CMP X,$00
    CMP X,$0000
    CMP Y,#$00
    CMP Y,$00
    CMP Y,$0000
    CMPW YA,$00
    DAA A
    DAS A
    DBNZ $00,$00
    DBNZ Y,$00
    DEC $00
    DEC $00+X
    DEC $0000
    DEC A
    DEC X
    DEC Y
    DECW $00
    DI
    DIV YA,X
    EI
    EOR $00,#$00
    EOR $00,$00
    EOR (X),(Y)
    EOR A,#$00
    EOR A,$00
    EOR A,$00+X
    EOR A,$0000
    EOR A,$0000+X
    EOR A,$0000+Y
    EOR A,($00)+Y
    EOR A,($00+X)
    EOR A,(X)
    EOR1 C,$0000
    INC $00
    INC $00+X
    INC $0000
    INC A
    INC X
    INC Y
    INCW $00
    JMP $0000
    JMP ($0000+X)
    LSR $00
    LSR $00+X
    LSR $0000
    LSR A
    MOV $00+X,A
    MOV $00+X,Y
    MOV $00+Y,X
    MOV $00,#$00
    MOV $00,$00
    MOV $00,A
    MOV $00,X
    MOV $00,Y
    MOV $0000+X,A
    MOV $0000+Y,A
    MOV $0000,A
    MOV $0000,X
    MOV $0000,Y
    MOV ($00)+Y,A
    MOV ($00+X),A
    MOV (X),A
    MOV (X+),A
    MOV A,#$00
    MOV A,$00
    MOV A,$00+X
    MOV A,$0000
    MOV A,$0000+X
    MOV A,$0000+Y
    MOV A,($00)+Y
    MOV A,($00+X)
    MOV A,(X)
    MOV A,(X+)
    MOV A,X
    MOV A,Y
    MOV SP,X
    MOV X,#$00
    MOV X,$00
    MOV X,$00+Y
    MOV X,$0000
    MOV X,A
    MOV X,SP
    MOV Y,#$00
    MOV Y,$00
    MOV Y,$00+X
    MOV Y,$0000
    MOV Y,A
    MOV1 $0000,C
    MOV1 C,$0000
    MOVW $00,YA
    MOVW YA,$00
    MUL YA
    NOP
    NOT1 $0000
    NOTC
    OR $00,#$00
    OR $00,$00
    OR (X),(Y)
    OR A,#$00
    OR A,$00
    OR A,$00+X
    OR A,$0000
    OR A,$0000+X
    OR A,$0000+Y
    OR A,($00)+Y
    OR A,($00+X)
    OR A,(X)
    OR1 C,!$0000
    OR1 C,$0000
    PCALL $00
    POP A
    POP P
    POP X
    POP Y
    PUSH A
    PUSH P
    PUSH X
    PUSH Y
    RET
    RETI
    ROL $00
    ROL $00+X
    ROL $0000
    ROL A
    ROR $00
    ROR $00+X
    ROR $0000
    ROR A
    SBC $00,#$00
    SBC $00,$00
    SBC (X),(Y)
    SBC A,#$00
    SBC A,$00
    SBC A,$00+X
    SBC A,$0000
    SBC A,$0000+X
    SBC A,$0000+Y
    SBC A,($00)+Y
    SBC A,($00+X)
    SBC A,(X)
    SET0 $00
    SET1 $00
    SET2 $00
    SET3 $00
    SET4 $00
    SET5 $00
    SET6 $00
    SET7 $00
    SETC
    SETP
    SLEEP
    STOP
    SUBW YA,$00
    TCALL 0
    TCALL 1
    TCALL 2
    TCALL 3
    TCALL 4
    TCALL 5
    TCALL 6
    TCALL 7
    TCALL 8
    TCALL 9
    TCALL 10
    TCALL 11
    TCALL 12
    TCALL 13
    TCALL 14
    TCALL 15
    TCLR $0000,a
    TSET $0000,a
    XCN A
| Compiles code for the SPC700 architecture. Follows the format the SNES Dev Manual recommends, with the exception of mov (x)+,a and mov a,(x)+, which are moved to mov (x+),a and mov a,(x+). See the spcblock section for an alternative way of assembling SPC700 code.
Super FX | `arch superfx` | [+] Expand
    ADC #0
    ADC #0
    ADC #1
    ADC #2
    ADC #3
    ADC #4
    ADC #5
    ADC #6
    ADC #7
    ADC #8
    ADC #9
    ADC #10
    ADC #11
    ADC #12
    ADC #13
    ADC #14
    ADC #15
    ADC R0
    ADC R1
    ADC R2
    ADC R3
    ADC R4
    ADC R5
    ADC R6
    ADC R7
    ADC R8
    ADC R9
    ADC R10
    ADC R11
    ADC R12
    ADC R13
    ADC R14
    ADC R15
    ADD #0
    ADD #1
    ADD #2
    ADD #3
    ADD #4
    ADD #5
    ADD #6
    ADD #7
    ADD #8
    ADD #9
    ADD #10
    ADD #11
    ADD #12
    ADD #13
    ADD #14
    ADD #15
    ADD R0
    ADD R1
    ADD R2
    ADD R3
    ADD R4
    ADD R5
    ADD R6
    ADD R7
    ADD R8
    ADD R9
    ADD R10
    ADD R11
    ADD R12
    ADD R13
    ADD R14
    ADD R15
    ALT1
    ALT2
    ALT3
    AND #1
    AND #2
    AND #3
    AND #4
    AND #5
    AND #6
    AND #7
    AND #8
    AND #9
    AND #10
    AND #11
    AND #12
    AND #13
    AND #14
    AND #15
    AND R1
    AND R2
    AND R3
    AND R4
    AND R5
    AND R6
    AND R7
    AND R8
    AND R9
    AND R10
    AND R11
    AND R12
    AND R13
    AND R14
    AND R15
    ASR
    BCC $00
    BCS $00
    BEQ $00
    BGE $00
    BIC #1
    BIC #2
    BIC #3
    BIC #4
    BIC #5
    BIC #6
    BIC #7
    BIC #8
    BIC #9
    BIC #10
    BIC #11
    BIC #12
    BIC #13
    BIC #14
    BIC #15
    BIC R1
    BIC R2
    BIC R3
    BIC R4
    BIC R5
    BIC R6
    BIC R7
    BIC R8
    BIC R9
    BIC R10
    BIC R11
    BIC R12
    BIC R13
    BIC R14
    BIC R15
    BLT $00
    BMI $00
    BNE $00
    BPL $00
    BRA $00
    BVC $00
    BVS $00
    CACHE
    CMODE
    CMP R0
    CMP R1
    CMP R2
    CMP R3
    CMP R4
    CMP R5
    CMP R6
    CMP R7
    CMP R8
    CMP R9
    CMP R10
    CMP R11
    CMP R12
    CMP R13
    CMP R14
    CMP R15
    COLOR
    DEC R0
    DEC R1
    DEC R2
    DEC R3
    DEC R4
    DEC R5
    DEC R6
    DEC R7
    DEC R8
    DEC R9
    DEC R10
    DEC R11
    DEC R12
    DEC R13
    DEC R14
    DIV2
    FMULT
    FROM R0
    FROM R1
    FROM R2
    FROM R3
    FROM R4
    FROM R5
    FROM R6
    FROM R7
    FROM R8
    FROM R9
    FROM R10
    FROM R11
    FROM R12
    FROM R13
    FROM R14
    FROM R15
    GETB
    GETBH
    GETBL
    GETBS
    GETC
    HIB
    IBT R0,#$00
    IBT R1,#$00
    IBT R2,#$00
    IBT R3,#$00
    IBT R4,#$00
    IBT R5,#$00
    IBT R6,#$00
    IBT R7,#$00
    IBT R8,#$00
    IBT R9,#$00
    IBT R10,#$00
    IBT R11,#$00
    IBT R12,#$00
    IBT R13,#$00
    IBT R14,#$00
    IBT R15,#$00
    INC R0
    INC R1
    INC R2
    INC R3
    INC R4
    INC R5
    INC R6
    INC R7
    INC R8
    INC R9
    INC R10
    INC R11
    INC R12
    INC R13
    INC R14
    IWT R0,#0000
    IWT R1,#0000
    IWT R2,#0000
    IWT R3,#0000
    IWT R4,#0000
    IWT R5,#0000
    IWT R6,#0000
    IWT R7,#0000
    IWT R8,#0000
    IWT R9,#0000
    IWT R10,#0000
    IWT R11,#0000
    IWT R12,#0000
    IWT R13,#0000
    IWT R14,#0000
    IWT R15,#0000
    JMP R8
    JMP R9
    JMP R10
    JMP R11
    JMP R12
    JMP R13
    LDB (R0)
    LDB (R1)
    LDB (R2)
    LDB (R3)
    LDB (R4)
    LDB (R5)
    LDB (R6)
    LDB (R7)
    LDB (R8)
    LDB (R9)
    LDB (R10)
    LDB (R11)
    LDW (R0)
    LDW (R1)
    LDW (R2)
    LDW (R3)
    LDW (R4)
    LDW (R5)
    LDW (R6)
    LDW (R7)
    LDW (R8)
    LDW (R9)
    LDW (R10)
    LDW (R11)
    LEA R0,$0000
    LINK #1
    LINK #2
    LINK #3
    LINK #4
    LJMP R8
    LJMP R9
    LJMP R10
    LJMP R11
    LJMP R12
    LJMP R13
    LM R0,($0000)
    LM R1,($0000)
    LM R2,($0000)
    LM R3,($0000)
    LM R4,($0000)
    LM R5,($0000)
    LM R6,($0000)
    LM R7,($0000)
    LM R8,($0000)
    LM R9,($0000)
    LM R10,($0000)
    LM R11,($0000)
    LM R12,($0000)
    LM R13,($0000)
    LM R14,($0000)
    LM R15,($0000)
    LMS R0,($00)
    LMS R1,($00)
    LMS R2,($00)
    LMS R3,($00)
    LMS R4,($00)
    LMS R5,($00)
    LMS R6,($00)
    LMS R7,($00)
    LMS R8,($00)
    LMS R9,($00)
    LMS R10,($00)
    LMS R11,($00)
    LMS R12,($00)
    LMS R13,($00)
    LMS R14,($00)
    LMS R15,($00)
    LMULT
    LOB
    LOOP
    LSR
    MERGE
    MOVE ($00),R0
    MOVE R0,#$00
    MOVE R0,($00)
    MOVE R0,R0
    MOVEB (R0),R0
    MOVEB R0,(R0)
    MOVES R0,R0
    MOVEW (R0),R0
    MOVEW R0,(R0)
    MULT #0
    MULT #1
    MULT #2
    MULT #3
    MULT #4
    MULT #5
    MULT #6
    MULT #7
    MULT #8
    MULT #9
    MULT #10
    MULT #11
    MULT #12
    MULT #13
    MULT #14
    MULT #15
    MULT R0
    MULT R1
    MULT R2
    MULT R3
    MULT R4
    MULT R5
    MULT R6
    MULT R7
    MULT R8
    MULT R9
    MULT R10
    MULT R11
    MULT R12
    MULT R13
    MULT R14
    MULT R15
    NOP
    NOT
    OR #1
    OR #2
    OR #3
    OR #4
    OR #5
    OR #6
    OR #7
    OR #8
    OR #9
    OR #10
    OR #11
    OR #12
    OR #13
    OR #14
    OR #15
    OR R1
    OR R2
    OR R3
    OR R4
    OR R5
    OR R6
    OR R7
    OR R8
    OR R9
    OR R10
    OR R11
    OR R12
    OR R13
    OR R14
    OR R15
    PLOT
    RAMB
    ROL
    ROMB
    ROR
    RPIX
    SBC R0
    SBC R1
    SBC R2
    SBC R3
    SBC R4
    SBC R5
    SBC R6
    SBC R7
    SBC R8
    SBC R9
    SBC R10
    SBC R11
    SBC R12
    SBC R13
    SBC R14
    SBC R15
    SBK
    SEX
    SM ($0000),R0
    SM ($0000),R1
    SM ($0000),R2
    SM ($0000),R3
    SM ($0000),R4
    SM ($0000),R5
    SM ($0000),R6
    SM ($0000),R7
    SM ($0000),R8
    SM ($0000),R9
    SM ($0000),R10
    SM ($0000),R11
    SM ($0000),R12
    SM ($0000),R13
    SM ($0000),R14
    SM ($0000),R15
    SMS ($00),R0
    SMS ($00),R1
    SMS ($00),R2
    SMS ($00),R3
    SMS ($00),R4
    SMS ($00),R5
    SMS ($00),R6
    SMS ($00),R7
    SMS ($00),R8
    SMS ($00),R9
    SMS ($00),R10
    SMS ($00),R11
    SMS ($00),R12
    SMS ($00),R13
    SMS ($00),R14
    SMS ($00),R15
    STB (R0)
    STB (R1)
    STB (R2)
    STB (R3)
    STB (R4)
    STB (R5)
    STB (R6)
    STB (R7)
    STB (R8)
    STB (R9)
    STB (R10)
    STB (R11)
    STOP
    STW (R0)
    STW (R1)
    STW (R2)
    STW (R3)
    STW (R4)
    STW (R5)
    STW (R6)
    STW (R7)
    STW (R8)
    STW (R9)
    STW (R10)
    STW (R11)
    SUB #0
    SUB #1
    SUB #2
    SUB #3
    SUB #4
    SUB #5
    SUB #6
    SUB #7
    SUB #8
    SUB #9
    SUB #10
    SUB #11
    SUB #12
    SUB #13
    SUB #14
    SUB #15
    SUB R0
    SUB R1
    SUB R2
    SUB R3
    SUB R4
    SUB R5
    SUB R6
    SUB R7
    SUB R8
    SUB R9
    SUB R10
    SUB R11
    SUB R12
    SUB R13
    SUB R14
    SUB R15
    SWAP
    TO R0
    TO R1
    TO R2
    TO R3
    TO R4
    TO R5
    TO R6
    TO R7
    TO R8
    TO R9
    TO R10
    TO R11
    TO R12
    TO R13
    TO R14
    TO R15
    UMULT #0
    UMULT #1
    UMULT #2
    UMULT #3
    UMULT #4
    UMULT #5
    UMULT #6
    UMULT #7
    UMULT #8
    UMULT #9
    UMULT #10
    UMULT #11
    UMULT #12
    UMULT #13
    UMULT #14
    UMULT #15
    UMULT R0
    UMULT R1
    UMULT R2
    UMULT R3
    UMULT R4
    UMULT R5
    UMULT R6
    UMULT R7
    UMULT R8
    UMULT R9
    UMULT R10
    UMULT R11
    UMULT R12
    UMULT R13
    UMULT R14
    UMULT R15
    WITH R0
    WITH R1
    WITH R2
    WITH R3
    WITH R4
    WITH R5
    WITH R6
    WITH R7
    WITH R8
    WITH R9
    WITH R10
    WITH R11
    WITH R12
    WITH R13
    WITH R14
    WITH R15
    XOR #1
    XOR #2
    XOR #3
    XOR #4
    XOR #5
    XOR #6
    XOR #7
    XOR #8
    XOR #9
    XOR #10
    XOR #11
    XOR #12
    XOR #13
    XOR #14
    XOR #15
    XOR R1
    XOR R2
    XOR R3
    XOR R4
    XOR R5
    XOR R6
    XOR R7
    XOR R8
    XOR R9
    XOR R10
    XOR R11
    XOR R12
    XOR R13
    XOR R14
    XOR R15
| Compiles code for the Super FX architecture.

All of Asar's features should be compatible with all of the supported target architectures, but it's not recommended to mix labels between different architectures as that will lead to undefined behavior. Opcodes in Asar are case-insensitive, which means that `LDA` and `lda` will be treated equally.

    arch 65816
    lda $00

    arch spc700
    mov a,$00

#### Number Literals

Asar supports decimal, hexadecimal and binary number literals. Hexadecimal literals use `$` as a prefix, binary literals use `%` as a prefix. Number literals can be made positive or negative by prefixing a `+` or a `-` (without a sign, positive is assumed). They can also be prefixed with a `~` to get their unary complement (a 32-bit integer with all the bits inverted).

    lda $00
    clc
    adc #-10
    and #%01111111
    lda #~$80	; Equal to lda #$FFFFFF7F

Aditionally, Asar supports character literals by delimiting a single ASCII character with `'`. Asar will automatically convert them to the integer value currently mapped to them (by default their ASCII value). They can be used in all places where number literals can be used. See section Tables for details on ASCII character mapping.

    lda #'a'
    sta $00

    db 'x','x'+1,'x'+2

#### Opcode Length Specification

By appending `.b`, `.w` or `.l` to an opcode, you can specify that opcode's length. This is recommended in cases where the length could be ambiguous.

    lda #0		; Could be either lda #$00 or lda #$0000
    lda.b #0	; Always lda #$00
    lda.w #0	; Always lda #$0000

When no length is specified, Asar tries to guess the length based on the operand. Note that Asar does not use the standard `<>` for length specifications to avoid ambiguity with other uses of these symbols (such as in macros or math statements). Opcode length specifications are currently supported for the 65c816 and SPC700 architectures.

#### Pseudo Opcodes

Pseudo opcodes are a convenience method of repeatedly using opcodes that don't take an operand. Instead of using the opcode multiple times, the following syntax can be used:

    {opcode} #{num}

This assembles `opcode` `num` times in succession. This means that

    nop #3

    inx #2

is the same as

    nop
    nop
    nop

    inx
    inx

#### rep

    rep {num} : {code}

Warning: this command is deprecated due to conflicting with the 65816 assembly `REP` instruction. In most cases, you can achieve the same effect with a for loop.

The rep command lets you compile any bit of code `num` times. It functions similarly to pseudo opcodes, but without being limited to certain opcodes only. Instead, you can repeat almost any bit of code supported by Asar, even macro calls. Note that in xkas compatibility mode, `rep 0` will compile the following code once, whereas `rep -1` (or any number `< 0`) won't compile the following code at all. This is to keep compatibility with old patches, which occasionally used the rep command as a replacement for conditionals. Also note that stacking multiple rep commands is not supported (only the most recent rep will take effect).

    macro writeval(val)
    	db <val>
    endmacro

    macro memset(val, num)
    	rep <num> : %writeval(<val>)
    endmacro

    rep 16 : %memset($00, 16)

#### spcblock

SPC blocks are a convenient way of defining command data meant to be sent to the SPC700 in games using well-known SPC engines (though at this time, only the `N-SPC` engine is supported). The general format looks like this:

    spcblock {target_address} [{engine_type}]
    	[spc700_instruction...]
    endspcblock [execute {execution_address}]

Inside an `spcblock`, `arch spc700` is automatically active (see section Architectures for details). The `target_address` parameter specifies the target address (in ARAM) for the command data. The optional `execute` parameter tells Asar to generate a "start execution" command immediately after this SPC block, with `execution_address` as the ARAM address to start execution at. The `engine_type` parameter specifies which SPC engine to use. When omitted, the default value of `nspc` is used. The following engine types are supported:

Parameter | Engine Type | Description | Output Format | Example Code | Example Output
--- | --- | --- | --- | --- | ---
`nspc` | N-SPC | Implements the format used by the N-SPC engine found in most Nintendo games, as well as by the SPC700's initial program loader. |
    dw <block_length>
    dw <target_address>
    <instructions...>
    [dw $0000, <execution_address>]
    spcblock $6000 nspc
    	db $00,$01,$02,$03
    	exec_start:
    	mov $33,#$44
    endspcblock execute exec_start
    dw $0007            ; block_length (4 bytes for db + 3 bytes for mov)
    dw $6000            ; target_address (argument passed to spcblock)
    db $00,$01,$02,$03  ; db $00,$01,$02,$03
    db $8F,$44,$33      ; mov $33,#$44

    dw $0000,$6004      ; execution_address (exec_start label position)

Return to top

### Mapping Modes

Asar supports a number of different mapping modes. They control the address translation used by Asar during compilation (aka where in the output file Asar writes to). Historically, SNES cartridges used a number of different mappers to address data in ROM. Those mappers can be supported by using the respective mapping mode in Asar. It's possible, but not recommended, to use different mapping modes on the same ROM. Detailed explanations on each mapping mode are beyond the scope of this manual, so please check the SNES Dev Manual or other specialized resources for that.
NOTE: Changing the mapper after having previously set it will generate warning `Wmapper_already_set`.

Command | Details
--- | ---
`lorom` | Switch to LoROM mapping mode.
`hirom` | Switch to HiROM mapping mode.
`exlorom` | Switch to ExLoROM mapping mode.
`exhirom` | Switch to ExHiROM mapping mode.
`sa1rom [bank_1,bank_2,bank_3,bank_4]` | Switch to hybrid SA-1 mapping mode. To tell which banks are mapped in (maximum is 7) use the optional parameter, like so:
    sa1rom 0,1,4,6
The default is 0,1,2,3.
`fullsa1rom` | Switch to full SA-1 mapping mode.
`sfxrom` | Switch to Super FX mapping mode.
`norom` | Disable Asar's address translation; the SNES address is equal to the PC address. Can be combined with `base` and macros to implement your own address translation.

When no mapping mode is specified, Asar tries to determine the mapping mode from the output ROM. If that isn't possible, Asar defaults to lorom.

    lorom
    org $008000
    db $FF		; Will write to PC address 0x000000

    hirom
    org $008000
    db $FF		; Will write to PC address 0x008000

Return to top

### Compatibility Settings

Compatibility settings determine how Asar operates in certain situations. They can be changed via a number of commands.

#### xkas

The `xkas` command enables Asar's xkas compatibility mode. In this mode, Asar tries to replicate the behavior of xkas as much as possible and throws warnings whenever it detects the usage of Asar-specific features that are not compatible with xkas. This command has to be used before any other command in the same patch. The intended purpose of the xkas command is to use it in conjunction with `;@` to write patches that can be assembled with both, Asar and xkas. See section Comments for details. Note that as of Asar version 1.40, xkas backwards compatibility is officially deprecated and is no longer guaranteed to work as expected. New features introduced into Asar since then might not throw warnings when attempted to use in xkas compatibility mode and old xkas patches might not assemble correctly with Asar anymore, even when xkas compatibility mode is used. xkas compatibility mode will be fully removed in Asar 2.0, along with the `;@` comments.

    ;@xkas

    !is_asar=0
    ;@!is_asar=1

    ;@if !is_asar == 0
    	macro do_something()
    		; Do something xkas-specific here
    	endmacro
    ;@else
    ;@	macro do_something()
    ;@		; Do something asar-specific here
    ;@	endmacro
    ;@endif

    do_something()

#### asar

    asar {ver}

The `asar` command can be used to specify the minimum Asar version your patch is compatible with. The `ver` parameter specifies the minimum required Asar version. When a user tries to assemble the patch in an older version of Asar, an error will be thrown, stating that the used Asar version is too old. This should be the first command in your patch, otherwise an error will be thrown.

    ; This patch uses features from Asar 1.40, so it makes sense to require it as a minimum.
    asar 1.40

    if readfile1("data.bin", 0) == 1
    	; Do something
    else
    	; Do something else
    endif

#### warn xkas

    warn xkas {on/off}

The `warn xkas` command determines whether Asar should throw warnings on behavior that is known to be different between xkas and Asar. Use `warn xkas on` to enable these warnings and `warn xkas off` to disable them. It's recommended to only enable them when not using xkas compatibility mode. Note that some behavioral changes throw warnings or errors regardless of this setting.

#### math pri

    math pri {on/off}

The `math pri` command tells Asar which order of operations to use in math experssions. When set to off (default), Asar uses left-to-right math, just like xkas v0.06. When set to on, Asar follows the conventional order of operations (exponentiation before multiplication & division, multiplication & division before addition & subtraction etc.). Parentheses can be used in either mode and tell Asar to calculate the expression inside first. For most intents and purposes, working with this flag enabled is more practical and predictable. It is disabled by default solely for the purpose of xkas backwards compatibility, unless `asar 1.9` or a higher version is specified at the start of the file, which will change the default to `math pri on`. This command will be removed in Asar 2.0, after which `math pri on` will be the only possible behavior.

    math pri off
    db 1+(6/3)*5	; db 15

    math pri on
    db 1+(6/3)*5	; db 11

#### math round

    math round {on/off}

The `math round` command tells Asar which rounding behavior to use in math expressions. When set to on (default), Asar truncates all numbers immediately, whereas when set to off, Asar only truncates numbers whenever they need to be cast to an integer type. Note that having this flag enabled will make it practically impossible to work with floating point numbers since calculations will lead to unexpected and impractical results. It is the default setting solely for the purpose of xkas backwards compatibility. When writing patches specifially for Asar, it is recommended to always disable this flag. If you specify a minimum supported Asar version using `asar 1.9` or higher, the default will be `math round off`. This command will be removed in Asar 2.0, after which `math round off` will be the only possible behavior.

    math round on
    ; 1.75 is immediately truncated to 1, resulting in (3/4)+1
    ; 3/4 would result in 0.75, which is immediately truncated to 0, resulting in 0+1
    ; Thus leading to the final result of "db 1"
    db (3/4)+1.75

    ; !some_number contains 0 after this line
    !some_number #= 0.75

    math round off
    ; As expected will result in 0.75+1.75, which will result in 2.5
    ; 2.5 is truncated to 2
    ; Thus leading to the final result of "db 2"
    db (3/4)+1.75

    ; !some_number contains 0.75 after this line
    !some_number #= 0.75

#### namespace nested

    namespace nested {on/off}

The `namespace nested` command enables (`on`) or disables (`off`) nested namespaces. The default is `off`. See section Namespaces for details.
Return to top

### Code Formatting

#### Comments

You can use ; to add comments to your code, making it easier to read and understand for other people. Everything from the ; to the end of the line is silently ignored by Asar.

    	lda $00		; Asar only sees the lda $00 and ignores everything else

Previously, there were exceptions to this rule in the form of lines starting with `;@`, which are assembled normally. This functionality is deprecated, Asar 2.0 will treat these lines as regular comments. The purpose of this feature was to add code to your patch that can be used with both xkas and Asar. In xkas, lines with ;@ will simply be ignored, whereas in Asar, they would be assembled. If you don't care about backwards-compatibility, you can also just use `@`, which will make your patch only assemble with Asar and fail with xkas. (This too is deprecated.) Aditionally, when Asar finds any unknown command on a line starting with ;@ or @, it will only throw a warning instead of an error. This can, at least in theory, be used to include optional features from newer Asar versions and still have your patch be compatible with older Asar versions. See section Compatibility Settings for details on xkas compatibility.

Also note that comments starting with `;[[` are reserved for multi-line comments in a future version of Asar. You should either change the beginning or make sure that there's a `]]` (the comment terminator) at the end of the line.

#### Brackets

Brackets, { and }, may be used to help organize your code structurally. They're treated as commands by the assembler, which means they follow the same rules as other commands, but they otherwise have no effect on code assembly and are silently ignored. Since brackets have no effect on code assembly, they don't even have to match, either. It's entirely up to the coder whether, how and in what quantity brackets are used.

    	lda $00
    	beq .IsZero

    .GreaterThanZero
    	{
    		dec $00
    	}

    .IsZero
    	rts

#### Multi-Line Operators

The `,` and the `\` operator are formatting operators which make it possible to split commands in Asar into multiple lines. Both are put at the end of a line and work very similarly with only one key difference. During execution, Asar will concatenate subsequent lines to lines ending with either operator and treat them as a single line. When using the comma operator, the comma itself will actually remain a part of the concatenated string, whereas when using the backslash operator, the backslash itself will be removed from the concatenated string. When using the backslash operator, please note that all whitespace following it is ignored, whereas all whitespace preceeding it is preserved. This is by design, since some commands in Asar require spaces to work, whereas other commands (like math commands) only work without spaces.

    %some_macro(!arg1, !arg2, !arg3,
    	!arg4, !arg5, !arg6)
    ; This will be treated as "%some_macro(!arg1, !arg2, !arg3, !arg4, !arg5, !arg6)"

    lda \
    	$7F0000
    ; This will be treated as "lda $7F0000"

    function func(param) = ((param*param)+1000)\
    	/256
    ; This will be treated as "function func(param) = ((param*param)+1000)/256"

#### Single-Line Operator

Contrary to the multi-line operators, the single-line operator `:` is a formatting operator which makes it possible to treat a single line of code as multiple lines. It requires a space before and after usage to differentiate it from the : used with certain commands. When used between different commands, Asar interprets it similarly to a new line and treats each command as being on a separate line. This can be used to link multiple commands together into functional blocks and make the code more readable.

    lda #$00 : sta $00

    ; Treated as:
    lda #00
    sta $00

Return to top

### Program Counter

The program counter (short: pc) refers to the position in the ROM at which Asar currently writes assembled code and/or data. It advances automatically whenever Asar writes to the ROM and is affected by the current mapping mode, as well as a number of special commands. Note that all commands affecting the pc that take an address expect an SNES address and thus are also affected by the current mapping mode.

#### org

    org {snes_address}

The org command directly sets the pc to `snes_address`. Most commonly used inside patches to specify which code to hijack or which data to overwrite.

    org $008000
    MainEntryPoint:
    	; ...

#### base

    base {snes_address/off}

The base command makes Asar act as though the pc was currently set to `snes_address` without actually setting it; `base off` deactivates this behavior. This can be useful for writing code that you plan to execute from another location (such as RAM).

    org $008000
    MainEntryPoint:
    	; Some code which copies SomeRamRoutine to $7E0000 goes here
    	; ...
    	jsl $7E0000
    	; ...

    SomeRamRoutine:
    base $7E0000
    	; ...
    base off
    	rtl

#### skip

    skip {num_bytes}
    skip align {alignment} [offset {offset}]

The skip command moves the pc by `num_bytes` bytes. By specifying a negative value, the pc can be moved backwards. When `alignment` is given, skips to the next multiple of `alignment`, plus `offset` if it is specified. Note that the alignment must be a power of 2, if specified. Offset can also be negative, in that case it's treated exactly like `alignment+offset`. The seeked-to position will always be after the current SNES position, but it might be before the next multiple of `alignment`: see the last example.

    org $008000
    skip 5
    ; pc is now at $008005
    skip -1
    ; pc is now at $008004
    skip align 16
    ; pc is now at $008010
    skip align 16 offset 5
    ; pc is now at $008015
    skip align $20 offset $17
    ; pc is now at $008017

#### warnpc

    warnpc {snes_address}

DEPRECATED: you can achieve the exact same thing with `assert pc() <= {snes_address}`. The warnpc command checks if the current pc is `> snes_address`. If that's the case, it throws an error. This is useful for detecting overflow errors.

    org $008000
    incbin datafile.bin
    warnpc $008100		; Throws an error if datafile.bin is larger than $100 bytes.

#### bank

    bank {data_bank/noassume/auto}

The bank command makes Asar's label optimizer act as though the current data bank was set to `data_bank`. Consider the following example:

    bank $FF

    lda DataTable,x

    DataTable:
    	db $01,$02,$03,$04

Asar will always assemble the `lda DataTable,x` with 24-bit addressing, unless the current pc (or base address) is inside bank `$FF` itself. This is intended for code that uses a data bank register different from the code bank register. You can use `bank noassume` to make Asar act as though the data bank was always in a different bank. Using `bank auto` restores the default behavior of assuming that the data bank register and the code bank register are the same. Note that the bank command can't point to freespace areas.

    org $008000
    phb
    lda #$FF
    pha
    plb

    bank $FF
    ; ...
    bank auto

    plb

#### dpbase

    dpbase {snes_address}

The `dpbase` command makes Asar's label optimizer assume the Direct Page register is set to the specified address. When used with the `optimize dp` command, this will cause Asar to use 8-bit addressing where possible. For example, in the following code Asar can assemble `lda SpriteTable,x` as a direct page address.

    SpriteTable = $7E0200
    dpbase $0200
    optimize dp ram

    org $008000
    lda SpriteTable,x

#### optimize dp

    optimize dp {none/ram/always}

This command changes how aggressive Asar's direct page access optimizer is. With `optimize dp none` (the default), the direct page optimizer is disabled and direct page accesses will only be done with the `.b` instruction suffix or with explicit addresses like `lda $42`. With `optimize dp ram`, direct page optimization will be performed according to the dpbase setting, but only on labels in bank `$7E`. With `optimize dp always`, direct page optimization will be performed on all labels in banks that have RAM mirrors, i.e. 00-3F and 80-BF, and also on labels in bank 7E.

#### optimize address

    optimize address {default/ram/mirrors}

This command changes how aggressive Asar's label optimizer is. With `optimize address default`, references to labels will be shortened to 2 bytes only if the label is in the current data bank. With `optimize address ram`, additionally labels between `$7E:0000-$7E:1FFF` will be shortened to 2 bytes if the current data bank has RAM mirrors (`$00-$3F` and `$80-$BF`). With `optimize address mirrors`, additionally labels between `$00-3F:2000-7FFF` (that is, `$00:2000-$00:7FFF` all the way up to `$3F:2000-$3F:7FFF`) will be shortened to 2 bytes whenever the current data bank has RAM mirrors. Note that in freespace, the current bank will be assumed from whether the freespace was started as `freecode` or `freedata`, not where the freespace was actually placed in the end.

#### pushpc/pullpc

The pushpc command pushes the current pc to the stack, the pullpc command restores the pc by pulling its value from the stack. This can be useful for inserting code in another location and then continuing at the original location.

    org $008000

    Main:
    	jsl CodeInAnotherBank

    pushpc
    org $018000

    CodeInAnotherBank:
    	; ...
    	rtl

    pullpc

    bra Main

#### pushbase/pullbase

The pushbase command pushes the current base to the stack, the pullbase command restores the base by pulling its value from the stack.

    base $7E2000

    InsideRam:
    	jsl OutsideOfRam
    	; ...

    pushbase
    pushpc
    base off

    freecode

    OutsideOfRam:
    	; ...
    	jsl InRamAgain
    	rtl

    pullpc
    pullbase

    InRamAgain:
    	; ...
    	rtl

    base off

Return to top

### Math

Math is supported in all opcodes, functions and labels. By default, Asar uses left-to-right math for backwards-compatibility with xkas which means that it ignores operator precedence.

    lda #6*2+5	; the same as "lda #17"
    lda #5+6*2	; the same as "lda #22"

This behavior can be changed by using the command `math pri on`, which makes Asar apply conventional prioritization rules in all math statements. (See math pri)

    math pri on

    lda #6*2+5	; the same as "lda #17"
    lda #5+6*2	; the same as "lda #17"

In both modes, Asar supports parentheses for explicit control over the order of operations.

    math pri on

    lda #5+6*2	; the same as "lda #17"
    lda #(5+6)*2	; the same as "lda #22"

Math statements in Asar support the following operators:

    +  : Addition (Also valid as prefix, but a no-op)
    -  : Subtraction (Or negation prefix)
    *  : Multiplication
    /  : Division
    %  : Modulo (the remainder of a division, fmod() in C)
    << : Left-shift ( x << y formula: x = x * 2^y )
    >> : Right-shift ( x >> y formula: x = x / 2^y )
    &  : Bitwise AND
    |  : Bitwise OR
    ^  : Bitwise XOR (Note: not exponentials)
    ~  : Bitwise NOT (Prefix)
    <: : Bitshift right 16, shorthand for isolating address bank (Prefix)
    ** : Exponentials (2**4 = 2*2*2*2 = pow(2, 4) in C)

Note that whitespace is not supported inside math statements, but the multi-line operator \ can be used to split them into multiple lines. Using math in labels can be useful when you want to apply an offset to the label:

    lda .Data+3	; Will load $03 into A

    .Data
    	db $00,$01,$02
    	db $03,$02,$03

Return to top

### Labels

Labels are used to represent a position in the ROM and allow you to code without having to constantly update branches and jumps/calls. They can be used with any opcode, but were specifically designed to be used with branches, jumps, calls, pointer tables etc. When used with branches, they're automatically converted to offsets.

#### Main Labels

    [#]{identifier}:

Main labels are the top-most level of labels supported by Asar. They're global and thus can be directly acessed from anywhere. Their identifier can contain any of the following characters
`a-z A-Z 0-9 _`

    org $008000

    Main:
    	%do_frame()
    	jmp Main	; Equal to jmp $8000

An alternate form of defining main labels is by directly assigning a value to them. A common use-case for this is to make a label point to an existing address inside a ROM. Syntax:

    {identifier} = {snes_address}

where `snes_address` can be a number or any math statement evaluating to an SNES address. Note that defining a main label this way does not start a new sub label group.

    Main:
    ; ...

    SomewhereInRom = $04CA40

    .Sub:
    ; ...

    Table:
    	dl Main_Sub                 ; Okay!
    	dl SomewhereInRom_Sub       ; Error, label not found

Prefixing a label definition (except label assignments) with a `#` will define the label without modifying existing label hierarchies. This can be useful for defining global routines inside call-anywhere macros without having them break existing label hierarchies.

    macro my_new_routine()
    	jsl MyNewRoutine

    	!macro_routine_defined ?= 0

    	if !macro_routine_defined == 0
    		pushpc

    		freecode cleaned

    		#MyNewRoutine:
    			incsrc routines/mynewroutine.asm

    		pullpc

    		!macro_routine_defined = 1
    	endif
    endmacro

    Main:
    	%my_new_routine()
    .Sub

    	; Both of these are found
    	dl MyNewRoutine
    	dl Main_Sub

Asar includes a label optimizer which attempts to optimize performance by shortening opcodes accessing labels from 24-bit to 16-bit whenever possible. See section Program Counter for details.

#### Sub Labels

    [#].{identifier}[:]

Sub labels are the second-most level of labels supported by Asar. They're local to the last main label declared and their identifiers can contain the same characters as main labels.

    Proc1:
    	nop
    .Sub
    	bra .Sub

    Proc2:
    	nop
    .Sub:	; Note that the colon is optional
    	bra .Sub

Sub labels allow you to reuse redundantly named labels such as Loop, End, etc. without causing label redefinition errors. A new sub label group is automatically started after a main label is declared. Internally, sub labels are converted to `MainLabel_SubLabel`, which can be used to access them from anywhere.

    Main1:
    	; ...
    .Sub1:
    	; ...
    .Sub2:
    	; ...

    Main2:
    	; ...
    .Sub1:
    	; ...
    .Sub2:
    	; ...

    Table:
    	dl Main1_Sub1
    	dl Main1_Sub2
    	dl Main2_Sub1
    	dl Main2_Sub2

Sub labels can themselves contain sub labels to an arbitrary depth by prepending additional dots.

    Main1:
    ; ...
    .Sub:
    ; ...
    ..Deeper:
    ; ...
    ...TheEnd:
    ; ...

    Table:
    	dl Main1_Sub_Deeper_TheEnd

Prefixing a sub label definition with a `#` will define the sub label without modifying existing label hierarchies, but there is probably no practical use for this and it's unintuitive, so it should be avoided.

#### +/- Labels

    +[+...][:]

    -[-...][:]

+/- labels are a special type of labels that are different from both main labels and sub labels in that they don't refer to a specific location in code, but rather to a location relative from where they are used. When used inside opcodes etc., `+` always refers to the next + label and `-` always refers to the previous - label. You can also chain an arbitrary number of + or an arbitrary number of - to create unique +/- labels that don't overwrite labels with a different number of +/-, for example `+++` or `-----`.

    	ldx.b #4

    --			; A
    	lda $10,x
    	beq +		; Branches to "C"

    	ldy.b #8

    -			; B
    	%do_something()

    	dey
    	bne -		; Branches to "B"

    +:			; C - note that +/- labels can also include an optional colon in their declaration
    	dex
    	bpl --		; Branches to "A"

+/- labels are useful in a number of situations. For example: inside a long routine with multiple short loops, where even a sub label like `.Loop` would get repetitive. +/- labels aren't bound to any scope, which means they can technically be used across different scopes. Just like sub labels, +/- labels are converted to main labels internally. Unlike sub labels, they can not be referenced from code directly since their names depend on where in the code they're used, making it impractical to directly refer to them. This is by design. They can, however, be accessed via the Asar DLL API, and their full name may appear in error messages printed by Asar. The naming format used for them is
`:pos_x_y`
for + labels and
`:neg_x_y`
for - labels, where
`x` = number of chained +/-
and
`y` = instance of this label within all +/- labels of the same name (starting from 0 for + labels and from 1 for - labels).

    lorom
    org $008000

    ---			; :neg_3_1
    -			; :neg_1_1
    	bra -
    --			; :neg_2_1
    -			; :neg_1_2
    	bra ---
    	bra --
    	bra -

    	bra ++
    	bra +
    	bra +++

    ++			; :pos_2_0
    +			; :pos_1_0
    	bra ++
    ++			; :pos_2_1
    +++			; :pos_3_0

#### Macro Labels

    [#]?{identifier}:

    ?{identifier} = {snes_address}

    [#]?.{identifier}[:]

    ?+[+...]

    ?-[-...]

Macro labels are special variations of the labels mentioned in the previous sections. Functionally, they behave the same as the other labels with the exception of being local to the macro they're used in. This means they can't be referenced from outside the respective macro. Macro labels are created by prefixing any of the other label types with a `?` .

    macro do_something()
    	?MacroMainLabel:
    	?.MacroSubLabel
    	?-
    		; All of these are fine!
    		dl ?MacroMainLabel
    		dl ?.MacroSubLabel
    		dl ?-
    		dl ?+
    		dl ?MacroMainLabel_MacroSubLabel
    	?+
    endmacro

    %do_something()

    ; ERROR! ?MacroMainLabel is undefined, because we're not inside %do_something() anymore.
    dl ?MacroMainLabel

Prefixing a macro label definition (except for macro label assignments and macro +/- labels) with a `#` will define the macro label without modifying existing label hierarchies, but there is probably no practical use for this, so it should be avoided. Like all other labels, macro labels are converted to main labels internally and prefixed with an identifier of
`:macro_x_`
where `x` = total macro call instance. They can't be referenced in code directly, except inside their respective macro and using the respective macro label syntax seen above. They can, however, be accessed via the Asar DLL API, and their full name may appear in error messages printed by Asar.

#### Structs

Structs are an advanced form of labels with the purpose of making access into structured data blocks easier. The general syntax is as follows

    struct {identifier} {snes_address}
    	[label...]
    endstruct [align num]

where `identifier` can contain any of the following characters:
`a-z A-Z 0-9 _`
The `snes_address` parameter can be any number literal or math statement evaluating to an SNES address. This address marks the start of the struct. The `label` parameter should be any number of labels, ideally coupled with skip commands. These labels become offsets into the struct. Internally, the struct command will do something similar to this

    pushpc
    base snes_address

whereas the endstruct command will do something similar to this

    base off
    pullpc

Take a look at the simple example below:

    struct ObjectList $7E0100
    	.Type: skip 1
    	.PosX: skip 2
    	.PosY: skip 2
    	.SizeX: skip 1
    	.SizeY: skip 1
    endstruct

This defines a struct called `ObjectList` at location `$7E0100` with a size of `7` (the sum of all skip commands). You can access into this struct like so:

    lda ObjectList.PosY

This is equal to:

    lda $7E0103		; $7E0100+1+2

The final address is calculated by taking the start of the struct (`$7E0100`) and adding to that all the skips preceding the `.PosY` label (`1` and `2`). Aside from accessing structs directly, it's also possible to access them as arrays. A simple example:

    lda ObjectList[2].PosY

The final address in this case is calculated by the equation:
`struct_start + (array_index * struct_size) + label_offset`
So in this case, our final address is `$7E0100 + (2 * 7) + (1 + 2) = $7E0111`. When using structs this way, the optional `align` parameter becomes relevant. This parameter controls the struct's alignment. Simply put, when setting a struct's alignment, Asar makes sure that its size is always a multiple of that alignment, increasing the size as necessary to make it a multiple. Let's take another look at the example above with an added alignment:

    struct ObjectList $7E0100
    	.Type: skip 1
    	.PosX: skip 2
    	.PosY: skip 2
    	.SizeX: skip 1
    	.SizeY: skip 1
    endstruct align 16

With an alignment of 16 enforced, this struct's size becomes 16 (the first multiple of 16 that 7 bytes fit into). So when accessing the struct like this

    lda ObjectList[2].PosY

the final address becomes `$7E0100 + (2 * 16) + (1 + 2) = $7E0123`. If we add some data into the struct

    struct ObjectList $7E0100
    	.Type: skip 1
    	.PosX: skip 2
    	.PosY: skip 2
    	.SizeX: skip 1
    	.SizeY: skip 1
    	.Properties: skip 10
    endstruct align 16

its original size becomes 17. Since a final size of 16 would now be too small to contain the entire struct, the alignment instead makes the struct's final size become 32 (the first multiple of 16 that 17 bytes fit into), so in our example of

    lda ObjectList[2].PosY

we now end up with a final address of `$7E0100 + (2 * 32) + (1 + 2) = $7E0143`.
Another feature that is unique to structs is the possibility of extending previously defined structs with new data. The general syntax for this is as follows:

    struct {extension_identifier} extends {parent_identifier}
    	[label...]
    endstruct [align num]

This adds the struct `extension_identifier` at the end of the previously defined struct `parent_identifier`. Consider the following example:

    struct ObjectList $7E0100
    	.Type: skip 1
    	.PosX: skip 2
    	.PosY: skip 2
    	.SizeX: skip 1
    	.SizeY: skip 1
    endstruct

    struct Properties extends ObjectList
    	.Palette: skip 1
    	.TileNumber: skip 2
    	.FlipX: skip 1
    	.FlipY: skip 1
    endstruct

The struct `ObjectList` now contains a child struct `Properties` which can be accessed like so:

    lda ObjectList.Properties.FlipX

Since extension structs are added at the end of their parent structs, the offset of `.FlipX` in this example is calculated as
`parent_struct_start_address + parent_struct_size + extension_struct_label_offset`,
in other words, our final address is `$7E0100 + 7 + (1 + 2) = $7E0109`. Note that extending a struct also changes its size, so in this example, the final size of the `ObjectList` struct becomes 12. Extended structs can also be accessed as arrays. This works on the parent struct, as well as the extension struct.

    lda ObjectList[2].Properties.FlipX

    lda ObjectList.Properties[2].FlipX

In the first example, our final address is calculated as
`parent_struct_start_address + (combined_struct_size * array_index) + parent_struct_size + extension_struct_label_offset`,
whereas in the second example, it's calculated as
`parent_struct_start_address + parent_struct_size + (extension_struct_size * array_index) + extension_struct_label_offset`,
so we end up with final addresses of `$7E0100 + (12 * 2) + 7 + (1 + 2) = $7E0122` and `$7E0100 + 7 + (5 * 2) + (1 + 2) = $7E0114`.
A few further things to note when using structs in Asar:

- It's possible to extend a single struct with multiple extension structs. However, this can be counter-intuitive. The size of the extended struct becomes the size of the parent struct plus the size of its largest extension struct, rather than the size of the parent struct plus the sizes of each of its extension structs. This also means that when accessing those extension structs, they all start at the same offset relative to the parent struct. This can be confusing and is often not what's actually intended, so for code clarity, it's recommended to only extend structs with at most a single other struct.
- It's possible to enforce alignments when using extension structs. However, this will only determine the alignment of the parent struct and/or the extension struct(s), depending on where it's specified. It won't determine the alignment of the combined struct. This can be confusing and is usually not what is intended. There currently is no universal workaround for this, so when a certain alignment is required for a struct, it's recommended to not use extension structs with it.
- It's not possible to access both, a parent struct and its extension struct, as arrays simultanously.
- An extension struct can't be extended itself.

#### Namespaces

Namespaces are a feature which makes it easier to avoid name conflicts between different labels without having to give them long or cryptic names. They work similarly to C++ namespaces and accomplish this by automatically adding a prefix to all labels declared or accessed within them. This prefix consists of an identifier, followed by an underscore `_` . Namespaces can be stacked if desired by enabling the namespace nested setting. When you try to access a label from within a namespace and Asar doesn't find it in there, it automatically looks in the upper namespaces (up to the global namespace). Use

    namespace {identifier}

to enter a namespace, where `identifier` can contain any of the following characters:
`a-z A-Z 0-9 _`
Use

    namespace off

to leave the current namespace (or immediately return to the global namespace when nested namespaces are not enabled).

    ; All of the below is valid

    namespace nested on

    Main:                           ; Main
    Main2:                          ; Main2

    namespace Deep

    	Main:                       ; Deep_Main

    	namespace Deeper

    		Main:                   ; Deep_Deeper_Main
    		Main3:                  ; Deep_Deeper_Main3

    		namespace Deepest

    			Main:               ; Deep_Deeper_Deepest_Main

    			dl Main             ; Deep_Deeper_Deepest_Main
    			dl Main2            ; Main2
    			dl Main3            ; Deep_Deeper_Main3

    		namespace off

    		dl Main                 ; Deep_Deeper_Main

    	namespace off

    	dl Main                     ; Deep_Main

    namespace off

    namespace nested off

    namespace TheFirst

    	Main:                       ; TheFirst_Main

    	dl Main                     ; TheFirst_Main

    namespace TheSecond

    	Main:                       ; TheSecond_Main

    	dl Main                     ; TheSecond_Main

    namespace TheThird

    	Main:                       ; TheThird_Main

    	dl Main                     ; TheThird_Main

    namespace off

    dl Main                         ; Main
    dl Deep_Main                    ; Deep_Main
    dl Deep_Deeper_Main             ; Deep_Deeper_Main
    dl Deep_Deeper_Deepest_Main     ; Deep_Deeper_Deepest_Main

    dl TheFirst_Main                ; TheFirst_Main
    dl TheSecond_Main               ; TheSecond_Main
    dl TheThird_Main                ; TheThird_Main

#### pushns/pullns

`pushns` saves the current namespace. `pullns` restores the last-pushed value of the namespace.

#### Global labels

While in a namespace, you can use the keyword `global` to define labels outside all namespaces. The syntax is `global [#]{identifier}:`. For example:

    namespace NS
    global GlobalLabel:
    .Sub: ; this is a sublabel of GlobalLabel

    LocalLabel:

    global #AnotherGlobal: ; this global won't modify the sublabel hierarchy

    .Sub: ; this is a sublabel of LocalLabel
    namespace off

    ; these are all valid:
    dl NS_LocalLabel
    dl NS_LocalLabel_Sub
    dl GlobalLabel
    dl GlobalLabel_Sub
    dl AnotherGlobal

Note that `#` acts the same way as it does for regular labels.
Note that you cannot use the `global` command with sublabels or macro labels. Outside of a namespace, `global` acts just like a regular label definition.
Return to top

### Defines

Asar supports a define system that functions similarly to defines in other programming languages, such as C++. Defines are identifiers that you can assign any kind of text to and use in other places as substitues for that text. During compilation, Asar replaces each define it encounters with the respective text assigned to it. Defines are prefixed with a `!` and declared as follows:

    !{identifier} = {value}

    !{identifier} = "{value}"

where `identifier` is a unique identifier that can contain any of the following characters:
`a-z A-Z 0-9 _`
The space on both sides of the = is required, which means that `!identifier=value` will not work. Since defines are really just placeholders for text, they can contain anything - labels, math formulas, even other defines.

    !x = $00

    lda !x		; Treated as "lda $00"
    lda #!x		; Treated as "lda #$00"
    lda [!x],y	; Treated as "lda [$00],y"

    !y = $12
    !x = !y$34

    lda !x		; Treated as "lda $12$34" (will throw error)

    !phr = "pha : phx : phy"

    !phr		; Treated as "pha : phx : phy"

To assign text containing whitespace to a define, you must delimit it with two `"` as shown above with !phr. Besides the regular define operator `=`, Asar also supports a number of additional define operators with slightly different functionality.

Operator | Functionality | Example
--- | --- | ---
`=` | The standard define operator. Directly assigns text to a define. |
    !define = 10
    !anotherdefine = !define+1
    ; !define now contains "10" and !anotherdefine now contains "!define+1"
`+=` | Appends text to the current value of a define. |
    !define = 10
    !define += 1
    ; !define now contains "101"
`:=` | Equal to the standard `=`, but resolves all defines in the text to assign before actually assigning it. This makes recursive defines possible. |
    !define = 10
    !define := !define+1
    ; !define now contains "10+1"
`#=` | Evalutes the text as though it was a math expression, calculates its result and assigns it to the define. The math is done in-place on the same line the operator is used on and is affected by all of Asar's math settings (such as prioritization rules and rouding behavior). |
    !define = 10
    !anotherdefine #= !define+1
    ; !anotherdefine now contains "11"
`?=` | Equal to the standard `=`, but only assigns text to a define that doesn't exist yet, otherwise does nothing. |
    !define ?= 10
    !define ?= 1
    ; !define now contains "10"

Similarly to C's ifdef and undef, Asar allows you to check for a define's existence using the `defined("{identifier}")` function and to delete a define using the `undef "{identifier}"` command. Make sure to leave the `!` out of the identifier when using these functions, as Asar would otherwise try to resolve the defines.

    !define = "hello"

    if defined("define")
    	print "This will be printed!"
    endif

    undef "define"

    if defined("define")
    	print "This won't be printed!"
    endif

Note that Asar tries to replace defines wherever possible, even inside strings. In some occasions, this might be undesirable. See section Tables for details on how to escape certain characters.

#### Nested Defines

By default, the define parser in Asar considers every supported character in a connected string to be a part of the define's name. This may not always be desired as it can lead to a certain define becoming inaccessible in a certain situation. In cases like that, the `{}` operator makes it possible to still use those defines by resovling everything inside the braces immediately.

    !hex = $

    db !hexFF     ; Error - define !hexFF not found
    db !{hex}FF   ; OK

Perhaps the more useful feature of this operator is that it can also be nested to allow for the creation of dynamic define names.

    ; Please specifiy a mode from 0 to 3
    !mode = 1

    assert !mode >= 0 && !mode <= 3, "Please specify a mode from 0 to 3!"

    !modename0 = "Default"
    !modename1 = "Debug"
    !modename2 = "Fast"
    !modename3 = "Small"

    !modenamestring = !{modename!{mode}}

    print "Building in mode: !modenamestring"

#### Built-in Defines

Aside from user defines, Asar also supports a number of built-in defines. These defines are read-only and any attempt to modify them will throw an error.

Define | Details | Example
--- | --- | ---
`!assembler` | Contains the value `asar`. Theoretically can be used to differentiate between different assemblers if other assemblers use this define and a syntax similar to Asar. |
    if not(stringsequal("!assembler", "asar"))
    	warn "This patch was written for Asar and may not be compatible with your current assembler."
    endif
`!assembler_ver` | Contains the version number of Asar in the format `(major_version * 10000) + (minor_version * 100) + revision`. For Asar version 1.60, this contains 10600. |
    if !assembler_ver < 10600
    	warn "This patch might not behave correctly due to a bug in Asar versions prior to 1.60."
    endif

Return to top

### Macros

Macros are a mechanism for recording a sequence of commands that can be used in other places. The main purpose of this is to include commonly used code in multiple places without actually having to rewrite or copy that code every time. Instead you can move it into a macro and write it only once. Macros, in concept, work similarly to defines in that they are a text-replacement mechanism, but they have a few key differences:

- Macros only record a sequence of commands rather than any kind of text.
- A macro call is itself considered a command and thus needs to go on its on line (or separated via the single-line operator ). This means that unlike a define, a macro can't just be used whereever.
- Macros can include parameters, which are identifiers that are replaced by a text value whenever the respective macro is called. For simplicity, you could consider parameters a macro-specific version of defines.

Use the following syntax to define a macro:

    macro {identifier}([parameter1_identifier[, parameter2_identifier...]][variadic_token])
    	[command1]
    	[command2...]
    endmacro

where all the identifiers can contain any of the following characters:
`a-z A-Z 0-9 _`
Use the syntax `<parameter_identifier>` to expand a parameter inside a macro. This works just like placing a `!define_identifier` anyhwere else in the code. Macros can be recursive (macros calling themselves) and/or nested up to 512 levels deep. This limit only serves the purpose of preventing infinite recursion. The first and last line of the macro definition need to go on their own lines (the single-line operator is not supported here). To call a macro that has already been defined, use the syntax

    %{identifier}([parameter1[, parameter2...]])

where each individual parameter may be wrapped in double quotes (which is required for parameters that contain any whitespace).

    macro mov(target, source)
    	lda <source>
    	sta <target>
    endmacro

    macro swap(first, second)
    	%mov($00, <first>)
    	%mov(<first>, <second>)
    	%mov(<second>, $00)
    endmacro

    macro use_x_safely(code)
    	phx
    	<code>
    	plx
    endmacro

    %swap($01, $02)
    %use_x_safely("ldx $10 : stx $11 : ldx #10 : stx $12")

In addition to named substitutions if the variadic token `...` is specified as the last parameter asar will allow an arbitrary number of parameters after all prior parameters have been satisfied. To access unnamed parameters of a variadic macro, use the syntax `<...[{math}]>`, where `math` is any math expression evaluating to the index of a variadic parameter. These are declared numerically starting from 0 up to the number of provided parameters. To access the number of provided variadic arguments one may use `sizeof(...)`. Lastly, it is important to note that while traditionally macros do not parse defines at their creation variadic macros will. This is to allow iteration of arguments by using defines.

    macro example0(...)
    	db sizeof(...), <...[0]>	;04 01
    endmacro

    macro example1(...)
    	!a #= 0
    	while !a < sizeof(...)
    		db <...[!a]>		;01 02 03
    		!a #= !a+1
    	endif
    endmacro

    macro example2(named_parameter, ...)
    	!a #= 0
    	while !a < sizeof(...)
    		db <...[!a]>		;02 03 04 05 06 07
    		!a #= !a+1
    	endif
    	db <named_parameter>	;01
    endmacro

    macro macro_with_optional_arguments(required, ...)
    	db <required>
    	if sizeof(...) > 0
    		db <...[0]>
    	end
    end

    %example0(1,2,3,4)
    %example1(1,2,3)
    %example2(1,2,3,4,5,6,7)
    %macro_with_optional_arguments(1)
    %macro_with_optional_arguments(2, 3)

Return to top

### Functions

Functions in Asar can be considered the math equivalent of macros. They are a convenient way of wrapping commonly used math statements, can include parameters and can be called in all places where math is supported. Use the following syntax to define a function:

    function {identifier}([parameter1_identifier[, parameter2_identifier...]]) = {some_math_statement}

where all the identifiers can contain any of the following characters
`a-z A-Z 0-9 _`
and where `some_math_statement` can be any math statement supported by Asar (including the use of other functions). Use a parameter's name to expand it inside a function.

    function kilobytes_to_bytes(kb) = kb*1024
    function megabytes_to_kilobytes(mb) = mb*1024
    function megabytes_to_bytes(mb) = kilobytes_to_bytes(megabytes_to_kilobytes(mb))

    ; Will print "4 MB = 4194304 bytes."
    print "4 MB = ",dec(megabytes_to_bytes(x))," bytes."

    function data_index_to_offset(index) = index*2

    lda .Data+data_index_to_offset(2)	; Will load $0002 into A

    .Data
    	dw $0000
    	dw $0001
    	dw $0002

Function definitions must be on a single line and can't include whitespace in their math statements, except when using the multi line operator \, which can be used to split long function definitions into multiple lines.

#### Built-in Functions

Aside from user-defined functions mentioned above, Asar also supports a number of built-in functions. Some built-in functions take string parameters, which must be wrapped in double quotes.

Function | Details | Example
--- | --- | ---
`read1(pos[, default]) read2(pos[, default]) read3(pos[, default]) read4(pos[, default])` | Read one/two/three/four byte(s) from the output ROM at SNES location pos. Mainly intended for detecting the presence of certain hijacks/patches in a ROM. Throws an error when given an invalid address, unless the optional parameter default is provided in which case it is returned. |
    if read1($00FFD5) == $23
    	!is_sa1_rom = 1
    else
    	!is_sa1_rom = 0
    endif
`readfile1(filename, pos[, default]) readfile2(filename, pos[, default]) readfile3(filename, pos[, default]) readfile4(filename, pos[, default])` | Read one/two/three/four byte(s) from file filename at position pos (see section Includes for details on Asar's handling of file names). Throws an error when the referenced file doesn't exist or the given position is out-of-bounds, unless the optional parameter default is provided in which case it is returned. |
    !readresult = readfile4("datafile.bin", 0, $FFFFFFFF)

    if !readresult != $FFFFFFFF
    	print "Read $",hex(!readresult)," from datafile.bin."
    endif
`canread1(pos) canread2(pos) canread3(pos) canread4(pos) canread(pos, num)` | Returns 1 if reading one/two/three/four/num bytes from the output ROM at SNES location pos would succeed and 0 otherwise. |
    if canread1($00FFD5) == 1
    	print "Detected ROM type: $",hex(read1($00FFD5))
    else
    	error "Failed to detect ROM type!"
    endif
`canreadfile1(filename, pos) canreadfile2(filename, pos) canreadfile3(filename, pos) canreadfile4(filename, pos) canreadfile(filename, pos, num)` | Returns 1 if reading one/two/three/four/num bytes from file filename at position pos would succeed and 0 otherwise (see section Includes for details on Asar's handling of file names). |
    if canreadfile4("datafile.bin", 512) == 1
    	print "Read $",hex(readfile4("datafile.bin", 512))," from datafile.bin at position 512."
    else
    	error "datafile.bin either doesn't exist or is too small."
    endif
`filesize(filename)` | Returns the size of file filename. Throws an error if the file doesn't exist. |
    !fsize #= filesize("datafile.bin")
    !fpos = 0

    assert !fsize >= 0, "datafile.bin doesn't exist or can't be opened".

    while !fpos < !fsize
    	; Do something with datafile.bin here, like calling readfile1("datafile.bin", !fpos)
    	;...

    	!fpos #= !fpos+1
    endif
`getfilestatus(filename)` | Checks the status of file filename. Returns 0 if the file exists and can be read from, returns 1 if the file doesn't exist and returns 2 if the file exists, but can't be read from for any other reason (like being read-protected, being locked etc.). |
    assert getfilestatus("datafile.bin") != 1, "datafile.bin doesn't seem to exist"
`sqrt(x)` | Computes the square root of x. |
`sin(x) cos(x) tan(x) asin(x) acos(x) atan(x) arcsin(x) arccos(x) arctan(x)` | Various trigonometric functions. Units are in radians. |
`log(x) log2(x) log10(x)` | Logarithmic functions (base-e, base-2 and base-10 respectively). |
`snestopc(address) pctosnes(address)` | Functions for converting between SNES and PC addresses. Affected by the current mapping mode. |
    print "SNES address $018000 in the current mapping mode is equivalent to PC address 0x",dec(snestopc($018000))
`min(a, b) max(a, b)` | Return the minimum/maximum of two numbers. |
    !start_index #= max(!current_index-1, 0)
`clamp(value, minimum, maximum)` | Makes sure that value stays within the bounds set by minimum and maximum. Equal to `min(max(value, minimum), maximum)`. |
    !used_amount #= clamp(!used_percentage, 0.0, 1.0)*!total_amount
`safediv(a, b, exception)` | Returns `a/b` unless b is 0 in which case exception is returned. Intended for avoiding division by zero errors in functions. |
    !single_sprite_memory = safediv(!total_sprite_memory, !max_num_sprites, 0)
`select(statement, true, false)` | Returns false if statement is 0 and true otherwise. Can be considered an if/else conditional that is usable within functions. NOTE: Asar always evaluates all parameters of a function before calling it, so if, for example, you pass an expression that divides by zero to select() as true, Asar will throw a division by zero error even if statement evalutes to 0 and thus false would be returned. To work around this, you can use the `safediv()` function in place of a regular division. |
    function sprite_size() = select(!extra_bytes_enabled, 16+4, 16)
`not(value)` | Returns 1 if value is 0 and 0 in any other case. Useful for negating statements in the `select()` function. |
    function required_sprite_memory(num_sprites) = not(!sprites_disabled)*sprite_size()*num_sprites
`bank(value)` | Returns `value>>16` |
    lda #bank(some_label)
`equal(value, comparand) notequal(value, comparand) less(value, comparand) lessequal(value, comparand) greater(value, comparand) greaterequal(value, comparand)` | Comparison functions. Return 1 if the respective comparison is true and 0 otherwise. Useful as statements in the `select()` function. |
    function abs(num) = select(less(num, 0), num*-1, num)
`and(a, b) or(a, b) nand(a, b) nor(a, b) xor(a, b)` | Perform the respective logical operation with a and b. Useful for chaining statements in the `select()` function. |
    function total_sprite_extra_bytes(num_sprites) = select(and(not(!sprites_disabled), !extra_bytes_enabled), 4, 0)*num_sprites
`round(number, precision)` | Rounds number to precision decimal places. Pass 0 as precision to round to the nearest integer. |
    if round(!distance, 2) == 0.0
    	error "Distance is zero or almost zero. Please choose a bigger value for distance as small values will cause problems."
    endif
`floor(number) ceil(number)` | Rounds a number up (in the case of `ceil`) or down (in the case of `floor`) to the nearest integer. |
    !banks_used #= ceil(!data_size/65536)
`defined(identifier)` | Takes an identifier as a string parameter and returns 1 if a define with that identifier exists, 0 otherwise. NOTE: Don't include the `!` in the identifier as Asar will otherwise try to expand it as a define before calling the function. |
    if defined("include_guard") == 0
    	!include_guard = 1
    	; ...
    endif
`sizeof(identifier)` | Takes the identifier of a struct as a parameter and returns the base size of that struct (without any extension structs). Throws an error if a struct with that name doesn't exist. For backwards compatibility, the identifier can be surrounded with quotes. |
    struct parent $0000
    	.data1: skip 2
    endstruct

    struct child extends parent
    	.data2: skip 3
    endstruct

    db sizeof(parent)             ; db 2
    db sizeof(parent.child)       ; db 3
`objectsize(identifier)` | Takes the identifier of a struct as a parameter and returns the object size of that struct. In the case of an extended struct, this will be the base size of the struct plus the size of its largest extension struct. Throws an error if a struct with that name doesn't exist. For backwards compatibility, the identifier can be surrounded with quotes. |
    struct parent $0000
    	.data1: skip 2
    endstruct

    struct child extends parent
    	.data2: skip 3
    endstruct

    db objectsize(parent)         ; db 5
    db objectsize(parent.child)   ; db 3
`datasize(label)` | Takes a given label and calculates the distance between it and the next label. It will throw a warning if the distance exceeds 0xFFFF or is the last label in the targeted assembly. |
    org $008000
    main:

    lda #datasize(my_table)		;3
    lda #datasize(other_label)	;0x7FF3 (last label, throws a warning. calculated as $FFFFFF-$00800C)
    lda #datasize(main)		;9

    my_table:
    	db $00, $00, $02
    other_label:
`stringsequal(string1, string2)` | Returns 1 if the given string parameters are equal and 0 otherwise. |
    if not(stringsequal("!assembler", "asar"))
    	warn "This patch was only tested in Asar and might not work correctly in your assembler."
    endif
`stringsequalnocase(string1, string2)` | Returns 1 if the given string parameters are equal and 0 otherwise. The comparison is case-insensitive. |
    if not(stringsequalnocase("!assembler", "ASAR"))
    	warn "This patch was only tested in Asar and might not work correctly in your assembler."
    endif
`pc()` | Returns the current SNES address. This is a shorthand for placing a label right before the current command. |
    assert pc() <= $008123
`realbase()` | Returns the current address in the ROM being written to. This is not the same as the value of a nearby label when the `base` command is active: it returns the actual address the code will end up at.

All built-in functions can be overridden by user-defined functions. Prepending an underscore (for example: `_read1()`) leads to the original function, which can be used to make an overridden function call its original function.

    function read1(x) = _read1(x+$010000)

While user-defined functions can't use string parameters themselves, passthrough of string parameters to built-in functions is supported.

    function readfilenormalized(filename, pos) = readfile4(filename, pos)/2147483648.0
    db readfilenormalizd("datafile.bin", 0)

Return to top

### Conditional Compilation

Conditional compilation allows you to only compile specific sections of code when certain conditions are met. This can be used in a number of ways, but is most commonly used in conjunction with defines to make code easily customizable and/or provide some simple configuration options to end users.

#### if/elseif/else/endif

The most basic form of conditionals are if conditionals. They are given a math statement and only compile their enclosed code if that statement evaluates to a value greater than 0.

    if {condition}
    	{codeblock}
    endif

To construct condition statements, you can also make use of a number of comparison operators specific to conditionals. They return 1 if their respective comparison is true and 0 otherwise.

Operator | Details
--- | ---
`a == b` | Returns 1 if `a` is equal to `b`
`a != b` | Returns 1 if `a` is not equal to `b`
`a > b` | Returns 1 if `a` is greater than `b`
`a < b` | Returns 1 if `a` is less than `b`
`a >= b` | Returns 1 if `a` is greater than or equal to `b`
`a <= b` | Returns 1 if `a` is less than or equal to `b`
`!a` | Returns 1 if `a` is 0, and 0 otherwise. Note: this is deprecated and will be removed in a future version. Please use `if not(a)` instead.

You can use logical operators to chain multiple conditions.

Operator | Details
--- | ---
`a || b` | Returns 1 if at least one of `a` and `b` evaluates to 1
`a && b` | Returns 1 if both of `a` and `b` evaluate to 1

Evaluation is lazy which means that the compiler will stop evaluating a condition as soon as the result can be determined (for example, in the condition `0 && my_function()`, my_function() will never be called). Note that only one kind of logical operator can be used in a single condition, but conditionals themselves can be nested to an arbitrary depth, which can be used as a workaround here. Optionally, if conditionals can contain an arbitrary number of elseif branches as well as a single else branch. The compiler checks the if and all elseif branches in succession until a single condition evaluates to `> 0` - if none does, the code inside the else branch is compiled.

    !mode = 0	; Supported modes: 0, 1, 2, 3
    !verbose = 0	; Set to 1 to enable verbose mode

    if !mode == 0
    	; ...
    elseif !mode == 1
    	; ...
    elseif !mode == 2
    	; ...
    elseif !mode == 3
    	if !verbose != 0
    		print "Oh boy, so you're going with mode 3 today!"
    	endif
    	; ...
    else
    	error "Unsupported mode! Please choose 0, 1, 2 or 3!"
    endif

Alternatively, if conditionals can also be constructed on a single line via the following syntax:

    if {condition} : {codeblock}[ : codeblock...] : endif

Note that else or elseif are unsupported when using this syntax. The `endif` used to be optional, but this functionality is deprecated. It's recommended to always add the endif at the end of the line.

    PressedY:
    	if !fireballs_enabled : %PlaySoundEffect(!fireball_sfx) : jsr ShootFireball : endif
    	rtl

If you plan to use labels in if commands, note that there's certain restrictions that apply. More specifically, only static labels can be used. That is, only labels whose address can't change between Asar's passes, as demonstrated by the following example:

    FirstLabel = $018000

    freecode
    	lda SecondLabel,x

    SecondLabel:
    	db $00,$01,$02,$03

    ; All good. FirstLabel was statically defined.
    if FirstLabel == 0
    endif

    ; Error. The label could move between passes.
    if SecondLabel == 0
    endif

#### while

A special variation of if conditionals are while loops. Instead of compiling their enclosed code only once, they compile it repeatedly until their condition evaluates to `<= 0`. Typically, this would be used with a define that is modified inside the loop. This can be useful for generating data tables.

    !counter = 0

    while !counter < $10
    	db (!counter<<8)|$00,(!counter<<8)|$01,(!counter<<8)|$02,(!counter<<8)|$03
    	db (!counter<<8)|$04,(!counter<<8)|$05,(!counter<<8)|$06,(!counter<<8)|$07
    	db (!counter<<8)|$08,(!counter<<8)|$09,(!counter<<8)|$0A,(!counter<<8)|$0B
    	db (!counter<<8)|$0C,(!counter<<8)|$0D,(!counter<<8)|$0E,(!counter<<8)|$0F

    	!counter #= !counter+1
    endwhile

Note that while loops can also end with `endif`, but this is deprecated. Be warned as improper use of while loops can lead to infinite loops and thus a dead-lock of the compiler, as Asar won't attempt to detect those.

#### for

For loops repeat the contents a specified number of times. In the for loop body, you have access to a loop counter as a define. The range is specified as start-inclusive and end-exclusive. For example:

    for i = 1..5
    	db !i
    	db 2*!i
    endfor

This will write the bytes 01 02 02 04 03 06 04 08.

You can also put for loops on a single line, however in this case due to the order in which Asar parses defines, you will not be able to use the loop counter. E.g. `for i = 0..10 : nop : endfor`.

Return to top

### Binary Data

Asar supports a number of commands which allow you to insert binary data directly into the ROM.

#### Tables

    db {value}[,value...]

    dw {value}[,value...]

    dl {value}[,value...]

    dd {value}[,value...]

Table commands let you insert a number or a list of numbers directly into the ROM as raw bytes. Use db for 8-bit numbers, dw for 16-bit numbers, dl for 24-bit numbers and dd for 32-bit numbers respectively, where `value` can be a number literal, a math statement, a label or an ASCII string delimited by double quotes. When using dw, dl or dd, each number is converted to little-endian. Big numbers are truncated to smaller integers as needed.

    org $0189AB
    Label:

    ; This will write the following data to the ROM:
    ; $01  $03  $07  $AB  $41 $42 $43
    db $01,$0203,$04050607,Label,"ABC"
    ; This will write the following data to the ROM:
    ; $01 $00  $03 $02  $07 $06  $AB $89  $41 $00 $42 $00 $43 $00
    dw $01,$0203,$04050607,Label,"ABC"
    ; $01 $00 $00  $03 $02 $00  $07 $06 $05  $AB $89 $01  $41 $00 $00 $42 $00 $00 $43 $00 $00
    dl $01,$0203,$04050607,Label,"ABC"
    ; $01 $00 $00 $00  $03 $02 $00 $00  $07 $06 $05 $04  $AB $89 $01 $00  $41 $00 $00 $00 $42 $00 $00 $00 $43 $00 $00 $00
    dd $01,$0203,$04050607,Label,"ABC"

By default, each character in an ASCII string used in in a table maps onto the respective ASCII value. This mapping can be customized via the table command:

    table {filename}[,rtl/ltr]

Note: this command is deprecated and will be removed in Asar 2.0, see below (direct character assignment syntax) for the replacement.

Where `filename` specifies the path to a table file (enclose in double quotes to use file names with spaces, see section Includes for details on Asar's handling of file names) and ltr/rtl specifies whether that file is in left-to-right or right-to left format (default: left-to-right).
Format of left-to-right table files:

    {character}={value}
    [character=value...]

Format of right-to-left table files:

    {value}={character}
    [value=character...]

where `character` represents an ASCII character and `value` represents a hexadecimal number literal (without a prefix) to map to that ASCII character. Note that the table command initializes the mapping to garbage, so when using it, it's recommended to provide mappings for all ASCII characters. It's also possible to directly map characters inline without using a table file by using the syntax

    '{character}' = {value}

where `value` can be any number literal or math statement. This will be the only way to set the table in Asar 2.0.
To reset the current table mapping to a direct ASCII mapping, use the command `cleartable`. Additionally, the `pushtable` command lets you push the current table mapping to the stack, whereas the `pulltable` command lets you restore the mapping from the stack.

    ; Contents of table1.txt:
    ;A=1A
    ;B=1B
    ;C=1C

    ; Contents of table2.txt:
    ;1D=A
    ;1E=B
    ;1F=C

    ; This writes $41 $42 $43
    db "ABC"

    table "table1.txt",ltr

    ; This writes $1A $1B $1C
    db "ABC"

    pushtable
    table "table2.txt",rtl

    ; This writes $1D $1E $1F
    db "ABC"

    pulltable

    ; This writes $1A $1B $1C
    db "ABC"

    cleartable

    ; This writes $41 $42 $43
    db "ABC"

    'A' = $20
    'B' = $20+1
    'C' = $20+2

    ; Those both write $20 $21 $22
    db "ABC"
    db 'A','B','C'

Note that Asar tries to replace defines wherever possible - even inside strings. Sometimes, this might be undesired. In those cases, you can prefix the `!` with a `\` to escape it. The `\` itself can be escaped with another `\`. In the case of a `"` it can be escaped with an additional `"`

    !define = "text"

    ; This writes "text" to the ROM
    db "!define"

    ; This writes "!define" to the ROM
    db "\!define"

    ; This writes "\text" to the ROM
    db "\\!define"
    ; This writes 'something "cool"' to the ROM
    db "something ""cool"""

#### fillbyte/fill

    fillbyte {byte}

    fill {num}
    fill align {alignment} [offset {offset}]

The fillbyte and fill commands let you write a specific byte value to the ROM multiple times. The `byte` parameter of fillbyte specifies which value to write, wheres fill writes that value to the output ROM `num` times. If `alignment` is specified, the value will be written repeatedly until the SNES address has the specified alignment, similar to `skip align`.

    fillbyte $FF
    ; This writes $FF $FF $FF $FF $FF $FF $FF $FF
    fill 8
    org $008005
    ; this writes $FF until SNES address $00800A (=$8008 + 2)
    fill align 8 offset 2

It's also possible to write 16-bit, 24-bit or 32-bit values with the fill command by using `fillword`, `filllong` or `filldword` instead of fillbyte. Note that the `num` parameter of fill still specifies the number of bytes to write in those cases. Values might get truncated as needed to exactly reach the specified number of bytes to write.

#### padbyte/pad

    padbyte {byte}

    pad {snes_address}

The padbyte and pad commands let you write a specific byte value to the ROM until the pc reaches a certain SNES address. The `byte` parameter of padbyte specifies which value to write, wheres pad writes that value to the output ROM until the pc reaches `snes_address`.

    org $008000
    padbyte $FF
    ; This writes $FF $FF $FF $FF
    pad $008004

It's also possible to write 16-bit, 24-bit or 32-bit values with the pad command by using `padword`, `padlong` or `paddword` instead of padbyte. Note that the `snes_address` parameter of pad still specifies the end offset of the write in those cases. Values might get truncated as needed to exactly reach the specified end offset.

#### incbin

    incbin {filename}[:range_start..range_end]

The incbin command copies a binary file directly into the output ROM. The `filename` parameter specifies which file to copy (enclose in double quotes to use file names with spaces, see section Includes for details on Asar's handling of file names) and the optional `range_start` and `range_end` parameters are math expressions which specify a range of data to copy from the file (a range_end of 0 copies data until the end of the file; not specifying a range copies the entire file). The older form of this command used `-` as the separator of start and end, which caused ambiguities and was thus deprecated.

    ; datafile.bin contains the following bytes:
    ; $00 $01 $02 $03 $04 $05 $06 $07 $08 $09 $0A $0B $0C $0D $0E $0F

    ; This writes $00 $01 $02 $03 $04 $05 $06 $07 $08 $09 $0A $0B $0C $0D $0E $0F
    incbin "datafile.bin"

    ; This writes $09 $0A $0B $0C $0D $0E
    incbin "datafile.bin":$9..$F
    ; Alternatively with the deprecated syntax:
    incbin "datafile.bin":9-F

    ; This writes $01 $02 $03 $04
    incbin "datafile.bin":$F-$E..2+3
    ; Old deprecated syntax:
    incbin "datafile.bin":($F-$E)-(2+3)

Another now-deprecated form is `incbin {filename}[range] -> {location}`, where location is either a label or a SNES address. If it is specified, the contents of the file are written to another location in the ROM. When set to a label identifier, this code behaves identically to

    pushpc
    freedata align

    {label_identifier}:
    incbin {filename}

    pullpc

with the exception that incbin gains special permission to cross bank borders. In this case, the size limit of the included file is 65536 bytes due to how freespace works. For files with a size of 32767 or lower, no alignment is enforced. When `label_name_or_sness_address` is set to an SNES address, the code behaves identically to

    pushpc

    org {snes_address}
    incbin {filename}

    pullpc

In this case there is no hard limitation on the size of your file.
Return to top

### Includes

Includes make it possible for your code to reference other files. This can be done for a number of reasons. The most common scenarios are to split code into multiple source files (see incsrc) or to separate code from data (see incbin). Whenever using a command or function referencing another file, Asar tries to locate that file by applying a set of rules to the file path in a specific order:

1. If the path is an absolute path:
   1. Asar tries to locate the file directly via the specified path.
   2. If this fails, an error is thrown.
2. If the path is a relative path:
   1. Asar tries to locate the file relatively to the file currently being assembled. (Caution: when used inside macros, paths are relative to the macro definition rather than to the macro call).
   2. If this fails, Asar tries to locate the file relatively to any of the include search paths that were specified, in the order they were specified in, until the file is found. (See section Usage for details on include search paths).
   3. If all of the previous fail, an error is thrown.

#### incsrc

    incsrc {filename}

The incsrc command makes Asar assemble the file referenced by the `filename` parameter (enclose in double quotes to use file names with spaces, see section Includes for details on Asar's handling of file names). The file is assembled in-place which means that Asar instantly switches to the new file and only returns to the previous file once assembling the new file has finished. All of Asar's state (labels, defines, functions, pc etc.) is shared between files. When including other files, there is a recursion limit of 512 levels. This limit only serves the purpose of preventing infinite recursion. For an easier understanding of incsrc, you can visualize it as a command which pastes the contents of another file directly into the current file (although that's not actually how it's implemented and there are differences in the way relative file paths are handled).

    ; Contents of routine.asm:
    ;AnotherRoutine:
    ;	lda #$FF
    ;	sta $00
    ;	rts

    Main:
    	jsr AnotherRoutine
    	bra Main

    incsrc "routine.asm"

#### include/includefrom

    include

    includefrom {filename}

The include and includefrom commands specify that a file is only to be included in another file and not to be assembled directly. When a user tries to assemble a file containing include or includefrom directly, an error is thrown. The includefrom command behaves identically to the include command with the exception that it is passed the name of the file it is meant to be included from (note that Asar doesn't verify whether it's actually included from that file, it only checks whether it's included from another file at all). When making use of include or includefrom, they must be the first command within their respective file and can't be used in combination with the asar or xkas command in the same file.

    ; Contents of shared.asm:
    ;includefrom main.asm
    ;
    ;if read1($00FFD5) == $23
    ;	!is_sa1_rom = 1
    ;else
    ;	!is_sa1_rom = 0
    ;endif

    asar 1.37

    incsrc "shared.asm"

    if !is_sa1_rom
    	; ...
    endif

#### includeonce

    includeonce

The includeonce command places an include guard on the file that is currently being assembled. This prevents it from being assembled again in the same pass. This is intended for shared files which may be included from multiple source files, but should only be assembled once to prevent redefinition errors etc.

    ; Contents of shared.asm:
    ;
    ;includeonce
    ;
    ;MyRoutine = $018000
    ;MyOtherRoutine = $028000

    ; Note that the second include does not throw
    ; redefinition errors, thanks to the "includeonce".
    incsrc "shared.asm"
    incsrc "shared.asm"

    jsl MyRoutine
    jsl MyOtherRoutine

Return to top

### Freespace

Freespace is a concept that comes into play when extending an existing ROM. To insert new code or data into a ROM, the ROM must contain enough continuous unused space for everything to fit into. Space like that is referred to as freespace. Many tools attempt to find freespace in a ROM by looking for continuous blocks of a certain value (most commonly $00). This method on its own isn't reliable as freespace finders could erroneously detect binary data or code with a certain pattern as freespace. For this reason, the RATS format was invented to protect data inserted into a ROM (see SMW Wiki for details on the RATS format). When placing RATS tags at the beginning of occupied memory blocks inside a ROM, freespace finders can search for them to know which parts of the ROM not to overwrite. Asar supports a number of commands for working with freespace directly, including freespace finders with automatic RATS tag generation.

#### freespace/freecode/freedata

    freespace {ram/noram}[,align][,cleaned][,static][,value]

    freecode [align][,cleaned][,static][,value]

    freedata [align][,cleaned][,static][,value]

The freespace command makes Asar search the output ROM for a freespace area large enough to contain the following section of code/data. If such an area is found, the pc is placed at its beginning and a RATS tag automatically written. If no such area is found, an error is thrown. The parameters control what kind of freespace to look for.

Parameter | Details
--- | ---
`ram` | The freespace finder searches for an area where RAM mirrors are available (banks $10 to $3F). Recommended when inserting code.
`noram` | The freespace finder searches for an area where RAM mirrors aren't available (banks $40 to $6F and $F0 to $FF). If no such area is found, it searches in the remaining banks ($10 to $3F). Recommended when inserting data.
`align` | The freespace finder searches for an area at the beginning of a bank.
`cleaned` | Suppresses the warning about freespace leaking. Useful when Asar's leak detection misbehaves on an autoclean with a complicated math statement or similar.
`static` | Prevents the freespace area from moving once assigned. This also prevents it from growing (an error is thrown if the area would need to grow). Useful in situations where data needs to remain in a certain location (for example: when another tool or another patch needs to access it).
`value` | A number literal or math statement specifying the byte value to look for when searching for freespace (default: $00). To find freespace, Asar will look for continuous areas of this value. When using autoclean on this freespace, this is also the value the area will be cleaned to. Note that specifying the byte like this is deprecated. You should use the separate `freespacebyte` command instead.

The freecode command is an alias of `freespace ram`, whreas the freedata command is an alias of `freespace noram`. There are a few things to note when working with freespace in Asar. First of all, if Asar places two freespace areas within the same bank, it will use 24-bit addressing in cases where they reference each other, despite 16-bit addressing being possible in theory. This can be worked around by only using a single freespace area instead. It's not recommended to explicitly use 16-bit addressing in these cases as the two freespace areas are not guaranteed to always end up in the same bank for all users. Secondly, when Asar places two freespace areas close to each other, a few bytes will be wasted between them for technical reasons. In most practical scenarios, the amount of wasted space should be reasonably small (< 1% of the code size), nevertheless this once again can be worked around by only using a single freespace area instead. Lastly, the number of freespace areas a single Asar patch can place is limited to a maximum of 125.

    ; Let's assume this to be some location in the ROM originally containing
    ;lda #$10
    ;sta $1F
    org $01A56B
    	autoclean jsl MyNewCode

    freecode

    MyNewCode:
    	; Do something here
    	; ...

    .Return:
    	; We overwrote some code from the original ROM with our org, so we have to restore it here
    	lda #$10
    	sta $1F

    	rtl

#### freespacebyte

    freespacebyte {value}

This command sets the byte which Asar considers to be free space. This value will be used for searching for freespace, as padding when resizing the ROM, or when cleaning up old freespaces.

#### autoclean

    autoclean jml/jsl/dl {label}

    autoclean {snes_address}

The autoclean command makes it possible for Asar to automatically clean up and reuse all of the freespace allocated by a patch when applying that patch again. The purpose of this is to prevent freespace leaks. Normally, applying a patch including a freespace (or similar) command to the same ROM multiple times would allocate a new freespace area each time. Since Asar automatically protects allocated freespace via RATS tags, all freespace areas previously allocated by the same patch would leak and become unusable, making the output ROM run out of freespace eventually. The autoclean command can prevent this by freeing up freespace areas previously allocated by the patch before allocating new ones. How it accomplishes this depends on how it is used:

- When used with a `jml` or `jsl`:
  The `label` parameter must be a label pointing to inside a freespace area. When the patch is applied and the autoclean is encountered, Asar checks whether the output ROM contains a jml/jsl at the current pc. If it does, Asar checks whether the jml/jsl points to the expanded area of the ROM (banks $10+). If it does, Asar checks whether the jml/jsl points to an area protected by a RATS tag (including the RATS tag itself). If it does, Asar cleans up that area and removes the RATS tag.
- When used with a `dl`:
  The `label` parameter must be a label pointing to inside a freespace area. When the patch is applied and the autoclean is encountered, Asar checks whether the output ROM contains an address pointing to the expanded area of the ROM (banks $10+) at the current pc. If it does, Asar checks whether that address points to an area protected by a RATS tag (including the RATS tag itself). If it does, Asar cleans up that area and removes the RATS tag.
- When used with just an address:
  The `snes_address` parameter must be any label, number literal or math statement evaluating to an SNES address pointing to inside a freespace area. When the patch is applied and the autoclean is encountered, Asar checks whether that address points to the expanded area of the ROM (banks $10+). If it does, Asar checks whether it points to an area protected by a RATS tag (including the RATS tag itself). If it does, Asar cleans up that area and removes the RATS tag.

When using autoclean with a jml, jsl or dl, Asar will also assemble the respective line of code at the current pc. For simplicity, you can treat the autoclean command like a modifier in those cases. A few more things to note when using the autoclean command:

- The autoclean command itself may not be used inside a freespace area. To automatically clean up freespace that is only referenced within another freespace area, you can use the prot command.
- It is safe to have multiple autoclean commands pointing to the same freespace area.
- You can not use autoclean with a label pointing to the very end of a freespace area.

    ; Let's assume this to be some location in the ROM containing a function pointer table or similar
    org $00A5F2
    	autoclean dl MyNewFunction1
    	autoclean dl MyNewFunction2

    freecode

    MyNewFunction1:
    	; ...
    	rtl

    MyNewFunction2:
    	; ...
    	rtl

#### prot

    prot {label}[,label...]

The prot command makes it possible for Asar to automatically clean up a freespace area that is only referenced within another freespace area and thus can't be cleaned via an autoclean directly. It must be used at the beginning of a freespace area (right after the freespace command), where the `label` parameter must be a label pointing to inside a freespace area (you can pass up to 85 labels separated by commas to a single prot). When a freespace area containing a prot is cleaned by an autoclean, all freespace areas referenced by the prot are also cleaned up.

    org $0194BC
    	autoclean jsl MyNewFunction

    freecode
    prot SomeLargeData

    MyNewFunction:
    	ldx.b #0

    .Loop:
    	{
    		lda SomeLargeData,x
    		cmp #$FF
    		beq .Return

    		; ...

    		inx

    		bra .Loop
    	}

    .Return:
    	rtl

    freedata

    SomeLargeData:
    	db $00,$01,$02,$03
    	; ...
    	db $FF

Return to top

### Text Output

Text output functions allow you to communicate certain information, states, warnings, errors etc. to end users of your code.

#### print

The print command lets you output general-purpose text to the user. Most commonly this is used to inform the user about certain states or to output debug information. Usage:

    print {text_or_function}[,text_or_function...]

where `text_or_function` can be either a string delimited by double quotes or one of the print-specific functions below:

Function | Details
--- | ---
`bin(x[, width])` | Prints x as a binary (base-2) integer, where x can be any math statement. If width is provided, the output is padded to at least this many digits using zeroes.
`dec(x[, width])` | Prints x as a decimal (base-10) integer, where x can be any math statement. If width is provided, the output is padded to at least this many digits using zeroes.
`hex(x[, width])` | Prints x as a hexadecimal (base-16) integer, where x can be any math statement. If width is provided, the output is padded to at least this many digits using zeroes.
`double(x[, precision])` | Prints x as a decimal number with precision decimal places (default: 5), where x can be any math statement. Affected by the math round setting.
`pc` | Prints the current PC.
`freespaceuse` | Prints the total number of bytes used by commands that acquire freespace (such as freespace, freecode, freedata etc.). You can use the command
    reset freespaceuse
to reset this value.
`bytes` | Prints the total number of bytes written to the output ROM. You can use the command
    reset bytes
to reset this value.

#### warn

The warn command lets you output a warning message to the user. Usage:

    warn [text_or_function...]

where `custom_warning_text` can be a custom warning text and uses the same format as the `print` command. A warning does not cause compilation to fail, so it can be used to inform the user about potential dangers. Warning messages are printed to stderr by default, but are printed to stdout if the Asar executable is renamed to xkas.exe. This is intended for compatibility purposes.

    if read1($00FFD5) == $23
    	warn "SA-1 compatibility of this patch is untested, use with caution!"
    endif

#### error

The error command lets you output an error message to the user. Usage:

    error [text_or_function...]

where `custom_error_text` can be a custom error text and uses the same format as the `print` command. An error causes compilation to fail, so it should be used to inform the user about irrecoverable error states. Error messages are printed to stderr by default, but are printed to stdout if the Asar executable is renamed to xkas.exe. This is intended for compatibility purposes.

    if read1($00FFD5) == $23
    	error "This patch is not SA-1 compatible!"
    endif

#### assert

An assert can be considered a short version of the code

    if {condition}
    else
    	error [text_or_function...]
    endif

and is used via the syntax

    assert {condition}[,text_or_function...]

where `custom_error_text` can be a custom error text and uses the same format as the `print` command. If `condition` evaluates to `<= 0`, an error is thrown, otherwise nothing happens.

    assert read1($00FFD5) != $23,"This patch is not SA-1 compatible!"

Return to top

### Checks

Checks allow Asar to monitor certain states and throw warnings or errors when certain criteria are met. This can be helpful for catching or preventing certain problems.

#### check title

    check title "{title}"

The check title command verifies that the title stored in the output ROM is identical to `title`. If it isn't, an error is thrown (unless `--no-title-check` is passed to the application, in which case only a warning is thrown - see section Usage for details). The purpose of this command is to assure that patches are applied to the correct output ROM.

    ; This patch is only for a Super Mario World ROM
    check title "SUPER MARIOWORLD     "

    ; Remove small bonus stars from game
    org $009053
    	nop #3

    org $009068
    	nop #3

#### check bankcross

    check bankcross {off/half/full}

The `check bankcross` command enables (`full` or `half`) or disables (`off`) throwing errors when a bank border is crossed while assembling a file. The default is `full`, which checks whether the code crosses from pc $FFFF to $0000 in the next bank, and throws an error if that happens. With `half`, Asar will additionally check crossings from $7FFF to $8000. Use `off` with caution as some features may not behave correctly with bank border checking disabled and some places may still check for bank borders, anyways.

    check bankcross off

    org $80FFFF

    	db $00,$00

    check bankcross on

    print pc	; Will print 818001 when using LoROM mapper

Return to top

### Warnings

Warnings are messages that Asar outputs to inform the user about potentially unintended or risky code that isn't critical and thus doesn't cause assembly to fail on its own. These messages can be useful for detecting potential problems in the code, but in some situations may be undesirable. For this reason, Asar supports a few methods of explicitly enabling or disabling certain warnings (see section Usage for details on how to configure warnings via the command line). Additionally, there are warnings which may be useful in some situations, but would be intrusive in most other situations. They are disabled by default and have to be enabled explicitly to be used. Commands that enable or disable warnings refer to them via their names. The easiest way of finding the name of a specific warning is to look at the console output of a patch producing it. Asar will always output the warning name along with the respective warning. Warnings also have ID numbers, but those are deprecated and will be removed in Asar 2.0. It is recommended to use the warning names instead (which are more descriptive anyways).

#### Disabled Warnings

This is a list of all warnings that are disabled by default and have to be enabled explicitly.

Warning Name | Details
--- | ---
`Wimplicitly_sized_immediate` | Thrown when opcodes are sized implicitly and Asar has to assume a size. An opcode is considered to be sized explicitly when either a length specifier is used or a simple hex constant that can be assumed to be of a specific size (that is, a hex constant with either two or four digits). Opcodes that don't support multiple sizes are always considered to be sized explicitly. Everything else is considered to be sized implicitly and will throw this warning when enabled.
`Wcheck_memory_file` | Only relevant for the DLL API. Thrown when a file is accessed that was either not provided as a memory file or that isn't found in memory. Mainly intended for debugging purposes and can be used to assure that files are actually read from the correct location.

#### warnings {push/pull}

    warnings {push/pull}

The `warnings push` command pushes the current state of enabled and disabled warnings to the stack. The `warnings pull` command pulls it back from the stack.

    warnings push
    ; Disable "freespace leaked" warning
    warnings disable Wfreespace_leaked

    freecode

    ; [...]

    warnings pull

#### warnings {enable/disable}

    warnings {enable/disable} {name}

The `warnings enable` command enables the warning with the specified name, the `warnings disable` command disables it. Warnings enabled or disabled via this command override warnings enabled or disabled via the command line (see section Usage for details). When using these commands inside shared code, it's recommended to do so in conjunction with warnings {push/pull} to prevent the modified settings from leaking into other files.

    warnings disable Wwarn_command

    warn "This text in invisible!"

    warn enable Wwarn_command

    warn "This text in visible!"

#### List of all warnings

Here is a list of all warnings Asar can emit (useful to know what to disable).

### List of all errors

Here is a list of all errors Asar can emit. This is really only useful when using the DLL API, where you can use the names to check which exact error was thrown. Note that error names might change between Asar versions.

Return to top