Free SNES assembler

0. Contents

This is the documentation of snescom-1.8.1.
   1. Purpose
      1.1. History
   2. Linker
   3. Supported syntax
      3.1. Mnemonics
      3.2. Addressing modes
      3.3. Operand size control
      3.4. Expression evaluation
      3.5. Segments
      3.6. Comments
      3.7. Command separation
      3.8. Code pointer relocation
      3.9. Branch labels
      3.10. Preprocessor
      3.11. Object file format
      3.12. Automatic jump size detection
      3.13. IPS output support
      3.14. Linkage selection
   4. Examples and more documentation
   5. Changelog
   6. Known bugs
   7. Copying
   8. Requirements
   9. Downloading

1. Purpose

This program reads symbolic 65816 or 65c816 machine code and compiles (assembles) it into a relocatable object file, into an IPS patch, or directly into a raw file.

The produced object file is binary-compatible with those made with XA65.

1.1. History

This program was born when Bisqwit needed a relocatable object -producing snes assembler and XA65 had too many bugs in it.
He was unable to fix the XA65 source so he started his own project, aiming for enough compatibility to be able to use the assembly files already written in the XA65 syntax.
Since that, this program has been growing to meet the needs in SNES game and patch development.

2. Linker

This package also contains a linker.
See http://bisqwit.iki.fi/src/snescom-demo/ - there's a demo explaining how this all works.

The linker can also be used to convert IPS patches into binary files (an empty space is assumed to be the original file), with the following command: sneslink input.ips -o result.bin -f raw

3. Supported syntax

3.1. Mnemonics

The following mnemonics are supported:

adc, and, asl, bcc, bcs, beq, bit, bmi, bne, bpl, bra, brk, brl, bvc, bvs, clc, cld, cli, clv, cmp, cop, cpx, cpy, db , dec, dex, dey, eor, inc, inx, iny, jml, jmp, jsl, jsr, lda, ldx, ldy, lsr, mvn, mvp, nop, ora, pea, pei, per, pha, phb, phd, phk, php, phx, phy, pla, plb, pld, plp, plx, ply, rep, rol, ror, rti, rtl, rts, sbc, sec, sed, sei, sep, sta, stp, stx, sty, stz, tax, tay, tcd, tcs, tdc, trb, tsb, tsc, tsx, txa, txs, txy, tya, tyx, wai, xba, xce

3.2. Addressing modes

All the standard addressing modes of the 65816 cpu are supported.

Syntax:
Name Examples Functionally equivalent to (not snescom syntax, provided for illustration only)
Implied: nop; clc
Immediate: lda #value; rep #value etc
(size may depend on an operand size setting)
a = value
Short relative: bra end
Long relative: brl end; per end+2
Direct: lda $12 a = ram[$00 : d + $0012]
Direct indexed: lda $12,x
lda $12,y
a = ram[$00 : d + $0012 + x]
a = ram[$00 : d + $0012 + y]
Direct indirect: lda ($12); pei ($12) a = ram[db: ramw[$00 : d + $0012]]
Direct indexed indirect: lda ($12,x) a = ram[db: ramw[$00 : d + $0012 + x]]
Direct indirect indexed: lda ($12),y a = ram[db: ramw[$00 : d + $0012] + y]
Direct indirect long: lda [$12] a = ram[raml[$00 : d + $0012]]
Direct indirect indexed long: lda [$12],y a = ram[raml[$00 : d + $0012] + y]
Absolute: lda $1234 a = ram[db : $1234]
Absolute indexed: lda $1234,x
lda $1234,y
a = ram[db : $1234 + x]
a = ram[db : $1234 + y]
Absolute long: lda $123456 a = ram[$12 : $3456]
Absolute indexed long: lda $123456,x a = ram[$12 : $3456 + x]
Stack-relative: lda $12,s a = ram[$00 : $0012 + s]
Stack-relative indirect indexed: lda ($12,s),y a = ram[db : ramb[$00 : $0012 + s] + y]
Absolute indirect: lda ($1234) a = ram[db : ramw[db : $1234]]
Absolute indirect long: lda [$1234] a = ram[raml[db : $1234]]
Absolute indexed indirect: lda ($1234,x) a = ram[raml[db : $1234 + x]]
MVN/MVP: mvn $7E,$7F
Note: "ram", "ramb", "ramw" and "raml" in the table refer to generic address space access (RAM, I/O ports, ROM etc). "ramb" means 8-bit read access, "ramw" means 16-bit read access, "raml" means 24-bit read access, but the meaning of "ram" depends on the context. It can be a read, write or a jump target, and 8-bit or 16-bit depending on instruction and the state of the X/M CPU flags. The leftside part of the address (like $00 : ) refers to the page selection (i.e. the 8 most significant bits of the 24-bit address).

3.3. Operand size control

The pseudo ops .as, .al, .xs & .xl are used to decide what size accumulator and index mode for the assembler to use. .as and .xs are for 8bit operands, and .al and .xl are for 16 bit operands.

I've found it handy to define these macroes:

#define SET_8_BIT_A()   sep #$20 : .as
#define SET_16_BIT_A()  rep #$20 : .al
#define SET_8_BIT_X()   sep #$10 : .xs
#define SET_16_BIT_X()  rep #$10 : .xl

#define SET_8_BIT_AX()  sep #$30 : .xs : .as
#define SET_16_BIT_AX() rep #$30 : .xl : .al
In addition to these modes, there are several operand prefixes that can be used to force a certain operand size/type.

3.4. Expression evaluation

Expressions are supported. These are valid code:

3.5. Segments

Code, labels and data can be generated to four segments: text, data, zero and bss.
Use .text, .data, .zero and .bss respectively to select the segment.
However, only the contents of text and data segments are saved into the o65 file. Labels are saved in all segments.

3.6. Comments

Comments begin with a semicolon (;) and end with a newline.
A colon is allowed to appear in comment.

3.7. Command separation

Commands are separated by newlines and colons (:).

3.8. Code pointer relocation

You can use a command like *= $34F200 to change where the code goes by default.
With IPS this is especially useful.
You can change the code pointer as many times as you wish, but unless you're generating an IPS file, all code must be a continuous block.

3.9. Branch labels

The label - can be defined for local branches backward and + for branches forward.
Example:
        ; Space-fill the buffer to end
        phx
         cpx #$0010
         bcs +     ;jumps to the next "+"
         SET_8_BIT_A()
         lda #$FF
-        sta $94A0,x
         sta $94B0,x
         inx
         cpx #$0010
         bcc -     ;jumps to the previous "-"
         SET_16_BIT_A()
+        lda W_VRAMADDR
         sta @$002116
        pla

3.10. Preprocessor

snescom uses GCC as a preprocessor.
You can use #ifdef, #ifndef, #define, #if, #endif and #include like in any C program. (See bugs)

3.11. Object file format

snescom produces relocatable object files (O65), non-relocatable patch files (IPS), or raw files.
The O65 file format has been documented by André Fachat for the XA65 project.

3.12. Automatic jump size detection

If --jumps option is enabled, all short jumps are automatically turned into near jumps when needed. (See bugs)

3.13. IPS output support

This version of snescom allows you to create IPS files.
This IPS format has been extended to allow you to specify global symbols and externs to be patched later.
In the generated format: If you only feed the IPS file to sneslink, you do not need to know about this extension.

3.14. Linkage selection

By default, O65 objects are linked to any free location in the ROM.
IPS files are linked to predefined locations.

With the .link statement, you can change that.

.link page $3F declares that this object should be placed into page $3F.

.link group 1 declares that this object should be placed to the same page together with all other objects that want to be linked in group 1. This is useful when you want to ensure that certain tables or routines go to the same page, even if they are not in the same compilation unit.
The actual page is determined during link time, and you can get the page by using 24-bit (@) or segment reference (^) to a symbol from those modules.

The linkage selection statement is only honored by the sneslink program, distributed in this archive.

sneslink has currently been tested only with HiROMs.

4. Examples and more documentation

In the source distribution there are some C++ modules that can be used to handle the o65 files.
There are also some example assembler files (copied from Chronotools).

There's also an example program demonstrating the linker at http://bisqwit.iki.fi/src/snescom-demo/.

5. Changelog

Sep 23 2003; 0.0.0 started working with the project.
Sep 28 2003; 1.0.0 initial release. All features working.
Sep 29 2003; 1.1.0 added feature: branch labels.
Sep 29 2003; 1.2.0 bugfix: didn't resolve correctly when different scopes had a label with the same name; added warning options
Oct 3 2003; 1.3.0 added feature: jump optimization.
Oct 8 2003; 1.3.1 bugfix: jump optimization only supports two passes. Requiring more now produces an error.
Oct 13 2003; 1.3.2 bugfix: accidentally had broke MVN/MVP some time ago
Nov 3 2003; 1.3.2.1 bugfix: undef; broken HTML in README.html
Nov 3 2003; 1.3.3 added some alternative methods (pea #$8000, mvn $7E7F)
Dec 30 2003; 1.3.4 bugfix; error-exit now deletes the broken output file
Jan 2 2004; 1.3.4.1 bugfix; added missing files
Jan 23 2004; 1.3.4.2 handles memory addressing a bit differently internally
Jan 24 2004; 1.4.0 adds IPS output support
Jan 24 2004; 1.4.1 added new program: IPS and O65 linker (BETA!)
Jan 24 2004; 1.4.1.1 added feature: string constants in .byt
Jan 28 2004; 1.4.1.2 IPS bugfixes; linker improved
Jan 31 2004; 1.4.1.3 some internal changes
Jan 31 2004; 1.4.1.4 more internal changes - aiming towards multisegment linking
Feb 3 2004; 1.4.2 improved expression parsing
Feb 22 2004; 1.5.0 added the linkage selection statement
Jan 30 2005; 1.5.0.1 adds a very hackish kludge to avoid three-pass jump fixing in a certain case
Nov 21 2005; 1.5.1 symbol support in disassembler (when given an O65 or IPS file)
Jun 20 2006; 1.6.0 raw output support. smartptr. More shortcut labels. The .nop macro.
Jul 26 2006; 1.7.0 smc,raw,o65 output in sneslink. "make" compatibility in error situations.
Jul 26 2006; 1.7.1 multisegment support (data, zero, bss) should work now fine.
Jul 27 2006; 1.7.2 adds some consistency to ROM vs SNES address space conversions.
Mar 04 2012; 1.7.3 adds some compilation fixes and an accidental memory address hack.
Jul 04 2012; 1.7.4 adds some compilation fixes.
Oct 15 2012; 1.7.4.1 fixes the memory address hack.
Jun 02 2018; 1.7.5 add support for $80 shadow bank.
Jun 04 2018; 1.8.0 partial rewrite in C++11, fix memory leaks & crashes, nicer code
Jun 04 2018; 1.8.1 proper support for HiROM memory mirroring; .link page directive actually works now, per segment

6. Known bugs

7. Copying

snescom has been written by Joel Yliluoma, a.k.a. Bisqwit,
and is distributed under the terms of the General Public License (GPL).

If you happen to see this program useful for you, I'd appreciate if you tell me :) Perhaps it would motivate me to enhance the program.

8. Requirements

snescom uses GCC as a slave in the preprocessing phase. Therefore, gcc must be installed and found in the PATH when running snescom.

9. Downloading

The official home page of snescom is at http://iki.fi/bisqwit/source/snescom.html.
Check there for new versions.

Generated from progdesc.php (last updated: Mon, 04 Jun 2018 22:28:24 +0300)
with docmaker.php (last updated: Mon, 04 Jun 2018 22:28:24 +0300)
at Mon, 04 Jun 2018 22:28:25 +0300