x65 Assembler

The assembler is the core tool of building 6502 code and assets into a binary executable. There isn't much that distinguishes one assembler from others as the entire process is to convert keywords and parameters into a sequence of bytes that can run on the target CPU.

The x65 assembler is a previous side project that I built and the current project exists partially for the purpose of validating the assembler. The assembler is open source and can be downloaded from github.com/Sakrac/x65.

That said there are some features I get mileage out of from this assembler.

The assembler has its own object format that can be linked, the linker and assembler is the same executable. Linking object files means that I can have more and smaller source files.

C-like brace scoping reduces the need for local labels which are substitued for '!' and '%' where '!' is the address of the preceeding open brace ( '{' ) and '%' the address of the suceeding close brace ( '}' ), for example:

    sta $d027,x
    bpl !

Assembler listings used to be how code was reviewed and debugged. x65 has a pretty useful listing output that includes clock cycles which adds up the clock cycles within braces to make it easier to determine total execution time for loops.

$0027 b9 00 00    lda $0000,y    4+       lda PlayerMoney,y
$002a 48          pha            3        pha
$002b be 00 00    ldx $0000,y    4+       ldx PlayerMoney + PlayerIndex.Count,y
$002e b9 00 00    lda $0000,y    4+       lda PlayerMoney + PlayerIndex.Count * 2,y

$0031 a8          tay            2        tay
$0032 68          pla            4        pla
$0033 60          rts            6        rts

The label pool is a simple temporary zero page allocator. Declare a pool by specifying a memory range and assign local or global labels from the pool. Exiting a brace scope returns the labels assigned within it, and prefixing the labels with a period makes the label local to the scope as well

  pool zpGlobal $80-$f8 ; create a global pool
  zpGlobal pool zpUtility 8 ; create a pool of 8 bytes from the global pool
  zpGlobal pool zpLocal 10 ; create a pool of 10 bytes from the global pool

{ ; allocate function parameter / result from the utility pool.
  zpUtility zpHex2Dec.t ; .t = byte triplet
  zpUtility zpH2DResult.t

  zpLocal .zpLocal.w ; .w = word (two bytes)