64tass v1.46 manual

Original written for DOS by Marek Matula of Taboo, then ported to ansi C by BigFoot/Breeze, and finally added 65816 support, CPU64, DTV, illegal opcodes, optimizations, multi pass compile and a lot of features by Soci/Singular.

Compile it with "make", if argp is missing or search.h then try to add -DWIN32 to CFLAGS. (that workarounds these, but there's a small performance loss)

On non-GNU systems try "make -f Makefile2" to compile.

Syntax is the same as the well known Turbo Assembler on c64, so you can port your sources easy by only replacing the CR at the end of each line.

Maintainer: soci at c64.rulez.org

Latest development version: http://sourceforge.net/projects/tass64/develop

Added 8 alias illegal opcodes, and fixed addressing mode of shx and shy.
Added experimental CPU64 support, local label bugfix, message cache, nop illegal addressing modes, .warn, lot of listing improvements, .enc, performance improvement for win32, .binary fix for win32
Added .rta, .char, .int, .null, .shift, .elsif, .cerror, .cwarn, .align, and .cpu, nested conditional compile bugfix, added .ifeq, .ifne, .ifpl, .ifmi and .endif for compatibility, label list fixes, offset and maximum size for .binary, anonymous forward and backward reference (+-), initial 65DTV02 support (needs more info), added missing 65c02 opcodes.
Compile fixes for SunOs and other non-GNU systems. (no stdint.h there...)
Bank byte operator, label before conditional compile instruction bugfix cop # and brk # fix, empty macro parameter fix, added .long, some constant too large bugfix, jmp/jsr ($ffff,x) must be in the same bank, now .cerror and .cwarn accepts parameter, upper byte of negative number correct now
Win32 binary: ftp://c64.rulez.org/pub/c64/IDE64/source/64tass_v1.46.zip
OSX.3 binary: ftp://c64.rulez.org/pub/c64/IDE64/source/64tass_v1.45_osx.3.zip
Sources (for other platforms): ftp://c64.rulez.org/pub/c64/IDE64/source/64tass_v1.46.tar.bz2

Usage tips

64tass is a command line compiler, the source can be written in any text editor. As a minimum the source filename must be given on command line.

64tass src.asm

There are also some useful parameters which are described later.

For comfortable compiling I use such "Makefile"s (for make):

demo.prg: source.asm makros.asm pic.drp music.bin
	64tass -C -a -B -i source.asm -o demo.prg

This way demo.prg is recreated whenever source.asm, makros.asm, pic.drp or music.bin had changed. For cross development with VICE here's another Makefile example:

demo.prg: source.asm makros.asm pic.drp music.bin
	64tass -C -a -B -i source.asm -o demo.tmp
	pucrunch -ffast -x 2048 demo.tmp >demo.prg
	killall x64 || true
	x64 demo.prg

Of course it's not much harder to create something similar for win32 (make.bat):

64tass.exe -C -a -B -i source.asm -o demo.tmp
pucrunch.exe -ffast -x 2048 demo.tmp >demo.prg
x64.exe demo.prg

Another useful thing is to add a basic header to your source files like the one below, so that the resulting file is directly runnable without additional compression:

	.word ss,2005
	.null $9e,^start;will be sys 4096
ss	.word 0


start	rts

The assembler supports anonymous labels, also called as forward (+) and backward (-) references. "-" means one backward, "--" means two backward, etc. also the same for forward, but with "+".

	ldy #4
-	ldx #0
-	txa
	cmp #3
	bcc +
	adc #44
+	sta $400,x
	bne -
	bne --

These references are also useful in macros, but this can create some nice traps, as macros are copied into the code, with the internal references.

	bne +		
	#somemakro	;let's hope that this macro does
+	nop		;not contain forward references...

For writing short code (4k intro, whatever) there are some special pseudo instructions. These are automatically compiled as relative branches when the distance is short and as jumps when longer. (GEQ, GNE, GCC, GCS, GPL, GMI, GVC, GVS) There's one more called GRA for CPUs supporting BRA, which is expanded to BRL (if available) or JMP (otherwise).

	lda #3
	gne label	;compiled as bne, or jmp

To avoid branch too long errors the assembler also supports long branches, it can automatically convert conditional relative branches to it's opposite and a JMP. This have to be enabled on the command line using the "--long-branch" option.

	bcc veryfar	;compiled as "bcc veryfar" or
			;	bcs sk
			;	jmp veryfar

There are some other tips below in the descriptions.

Command line options

Operation options

-a, --ascii Convert ASCII to PETASCII

Normally no conversion takes place, this is for backwards compatibility with a DOS based Turbo Assembler editor, which could create petscii files for 6502tass. (with control characters also of course)

Using this option will convert 'a'-'z' and 'A'-'Z' into the correct petscii range of $41-$5A and $C1-$DA, which is more suitable for an ascii editor.

64tass a.asm
lda #"a"	-> result: $A9, $61
.text "1aA"	-> result: $31, $61, $41

64tass --ascii a.asm
lda #"a"	-> result: $A9, $41
.text "1aA"	-> result: $31, $41, $C1

-b, --nostart Strip starting address

Strips the 2 or 3 byte starting address before the resulting binary. Usefull for creating ROM images.

-B, --long-branch Automatic bxx *+3 jmp $xxxx

Branch too long messages can be annoying sometimes, usually they'll result in an bxx *+5 jmp rewrite. 64tass can do this automatically if this option is used. But BRA is not converted.
64tass a.asm
bcc $1233 ;error...

64tass a.asm
bcs *+5   ;opposite condition
jmp $1233 ;as simple workaround

64tass --long-branch a.asm
bcc $1233 ;no error, automatically converted to the above one.

-C, --case-sensitive Case sensitive labels

Labels are non case sensitive by default, this option changes that. If defining labels by "-D", this option must be first.
64tass a.asm
label nop
Label nop	;double defined...

64tass --case-sensitive a.asm
label nop
Label nop	;Ok, it's a different label...

-D <label>=<value> Define <label> to <value>

Defines a label to a value. Only decimal numbers are allowed. If using case sensitive labels, that option must be used before.
64tass -D ii=2 a.asm
lda #ii ;result: $a9, $02

-n, --nonlinear Generate nonlinear output file

Generates non-linear output for linkers. Format: length, address, code, length, ...
64tass --nonlinear a.asm
lda #2
$02, $00 ;little endian length, 2 bytes
$00, $10 ;little endian start $1000
$a9, $02 ;code
$01, $00 ;little endian length, 1 byte
$00, $20 ;little endian start $2000
$ea	 ;code
$00, $00 ;end marker (length=0)

-o <file> Place output into <file>

The default output filename is "a.out". This option changes it.
64tass a.asm -o a.prg

-w, --no-warn Suppress warnings

Disables warnings during compile.
64tass --no-warn a.asm

-W, --wordstart Force 2 byte start address

It 16 MiB address space is used for 65816 or CPU64, then the starting address of file will be 3 bytes long. This option makes it 2 bytes long.
64tass --wordstart --m65816 a.asm

Target selection on command line

These options will select the default architecture. It can be overridden by using the .cpu directive in the source.

-c, --m65c02 CMOS 65C02

Selects 65c02. Enables extra opcodes and addressing modes specific to this CPU.
64tass --m65c02 a.asm
stz $d020	;65c02 instruction

-i, --m6502 NMOS 65xx

Selects NMOS 6502. Enables extra illegal opcodes. Useful for demo coding for C64, disk drive code, etc.
64tass --m6502 a.asm
lax $14		;illegal instruction

--m65xx Standard 65xx (default)

Selects standard 6502. For writing compatible code, no extra codes. This is the default.
64tass --m65xx a.asm
lda $14		;regular instructions

-t, --m65dtv02 65DTV02

Selects 65DTV02. Enables extra opcodes specific to DTV.
64tass --m65dtv02 a.asm
sac #$00

-x, --m65816 W65C816

Selects 65816. Enables extra opcodes, and full 16 MiB address space. Useful for SuperCPU projects. Don't forget to use "--word-start" for small ones ;)
64tass --m65816 a.asm
lda $123456,x

-X, --mcpu64 CPU64

Selects CPU64. Enables extra opcodes, and full 16 MiB address space. This CPU is not yet built, opcodes may change.
64tass --mcpu64 a.asm
ldx $123456

Source listing options

-l <file> List labels into <file>

List labels to a file. Local labels are commented out, unused ones are marked with a comment.
64tass -l labels.txt a.asm

result (labels.txt):
label           = $1000    ; *** unused

-L <file> List into <file>

Dumps source code and compiled code into file. Useful for debugging code, it's much easier to identify the code in memory within the source files.
64tass -L list.txt a.asm
	ldx #0
loop	dex
	bne loop

result (list.txt):

;6502/65C02/65816/CPU64/DTV Turbo Assembler V1.4x listing file of "a.asm"
;done on Fri Dec  9 19:08:55 2005

.1000	 a2 00		ldx #$00		ldx #0
.1002	 ca		dex		loop	dex
.1003	 d0 fd		bne $1002		bne loop
.1005	 60		rts			rts

;******  end of code

-m, --no-monitor Don't put monitor code into listing

There won't be any monitor listing in the list file.
64tass --no-monitor -L list.txt a.asm

result (list.txt):

;6502/65C02/65816/CPU64/DTV Turbo Assembler V1.4x listing file of "a.asm"
;done on Fri Dec  9 19:11:43 2005

.1000	 a2 00					ldx #0
.1002	 ca				loop	dex
.1003	 d0 fd					bne loop
.1005	 60					rts

;******  end of code

-s, --no-source Don't put source code into listing

There won't be any source listing in the list file.
64tass --no-source -L list.txt a.asm

result (list.txt):

;6502/65C02/65816/CPU64/DTV Turbo Assembler V1.4x listing file of "a.asm"
;done on Fri Dec  9 19:13:25 2005

.1000	 a2 00		ldx #$00
.1002	 ca		dex	
.1003	 d0 fd		bne $1002
.1005	 60		rts	

;******  end of code

Other options

-?, --help Give this help list

Prints help about command line options.

--usage Give a short usage message

Prints short help about command line options.

-V, --version Print program version

Prints program version.


Expressions can be used at a lot of places. Here's a list of available operators:

( )

lda #(4+2)*3

< – lower byte

> – higher byte

` – bank byte

lda #<label
ldy #>label
jsr $ab1e

= – equal

< – less

> – more

!= – non equal

>= – more or equal

<= – less or equal

	.if ntsc=1

+ – add

- – substract

* – multiply

/ – divide

// – modulo

| – or

^ – xor

& – and

<< – shift left

>> – shift right

- – negate

~ – invert

! – not

	lda #((bitmap & $2000) >> 10) | ((screen & $3c00) >> 6)
	sta $d018

Compiler directives:

Set current address
Include 8bit unsigned byte constants, same as .text
Include constants and strings:
	.text "oeU"	; text, "" means $22
	.text 'oeU'	; text, '' means $27
	.text 23, $33	; bytes
	.text %00011111	; more bytes
	.text ^OEU	; the decimal value as string (^23 is $32,$33)
Include 8bit signed integer constants
	.char -33, 57
Same as .text, but the last byte is "shifted". Characters in range $c0-$df are converted to $60-$7f, $ff is converted to $7e, and everything else >=$80 will cause an error. No conversion if screen encoding is done, >=$80 will always cause an error.
        ldx #0
loop	lda txt,x
        and #$7f
        jsr $ffd2
        bpl loop
txt	.shift "some text"
Same as .text, but adds a null at the end, null in string is an error
txt	.text "lot of stuff"
	.null "to write"
        lda #<txt
        ldy #>txt
        jsr $ab1e
Include return address constants
        lda #0
        lda rets+1,x
        lda rets,x
rets	.rta $fce2
Include 16bit unsigned word constants
	.word $2342, $4555
Include 16bit signed integer constants
	.int -533, 4433
Include 24bit unsigned constants
	.long $123456
Add compile offset to logical address
	.offs 100
Macro definition, it copies the macro content in. (so be careful with labels, better use anonymous ones)
name	.macro
	lda #\1 	;first parameter
	#name 23	;call macro
End of macro definition
Compile loop, only anonymous references are allowed as labels inside
	.for ue=0,ue<10,ue=ue+1
	.byte ue
End of compile loop (.rept or .for)
Conditional compile, if result!=0
Conditional compile, if result=0
Conditional compile, if result>=0
Conditional compile, if result<0
	.if oeu=1
	lda #1
The inverse condition
The inverse condition, if result!=0
	.if wait=2	;2 cycles
	.elsif wait=3	;3 cycles
	bit $ea
	.elsif wait=4	;4 cycles
	bit $eaea
	.else		;else 5 cycles
	inc $2
End of conditional compile
Repeated compile, only anonymous references are allowed as labels inside
	.rept 100
Include source file here
	.include macros.asm
Include binary data. Please note that loading address is ignored, and if not skipped then it's also loaded.
	.binary stuffz.bin ;simple include
	.binary "stuffz.bin",2 ;skip start address
	.binary "stuffz.bin",2,1000 ;skip start address, 1000 bytes max
	*=$1000			;load music to $1000 and
	.binary "music.dmc",2   ;strip load address
Comment block start
	lda #1		;this won't be compiled
	sta $d020
End of comment block
Gives an error on page boundary crossing, eg. for timing sensitive code.
table	.byte 0,1,2,3,4,5,6,7
End of page cross checking
Changes logical address. Can be nested.
	.logical $300
drive	lda #$80
	sta $00
	jmp drive	;jmp $300
Restore logical address to physical
Select 8 bit accu (65816)
Select 16 bit accu (65816)
	lda #$4322
Select 8 bit index (65816)
Select 16 bit index (65816)
	ldx #$1000
Exit with error
	.error "Unfinished here..."
	.warn "FIXME: handle negative values too!"
Conditional exit with error
	.cerror *>$1200,"Program too long!"
Conditional warning
	.cwarn *>$1200,"This may not work!"
Procedure start
ize	.proc 
cucc	nop
	jsr ize
        jmp ize.cucc
If "ize" is not referenced then the code won't be compiled at all! All labels inside are local.
End of procedure
Set databank (65816)
        .databank $10	;$10xxxx
Set directpage (65816/C128/DTV) (forced to page boundary for DTV)
        .dpage $400
Skip bytes, or fill with repeated bytes. For multibyte patterns use .repeat!
	.fill $100	;no fill, just skip $100 bytes
	.fill $4000,0	;16384 bytes of 0
Align code to a dividable address by skip or fill
	.align $100
irq	inc $d019	;this will be on a page boundary, after skipping bytes
	.align 4,$ea
loop	adc #1		;padding with "nop" for DTV burst mode
Text encoding, "none" or "screen" (screen code)
        .enc screen	;screencode mode
        .text "text with screencodes"
        cmp #"u"	;compare screencode
        .enc none	;normal again mode
        cmp #"u"	;compare ascii
Selects cpu
	.cpu 6502	;standard 65xx
	.cpu 65c02	;CMOS 65C02
	.cpu 6502i	;NMOS 65xx
	.cpu 65816	;W65C816
	.cpu cpu64	;CPU64
	.cpu 65dtv02	;65dtv02
	.cpu default	;cpu set on commandline
Do not use this, buggy!
Do not use these, the syntax will change in next version!



Top of memory excedeed
compile continues at the bottom ($0000)
Possibly incorrectly used A
do not use "a" as label
Memory bank excedeed
compile continues in the next 64 KiB bank, however execution may not
Possible jmp ($xxff) bug
yet another 65xx feature...
Long branch used
Branch too long, so long branch was used (bxx *+5 jmp)


Double defined
double use of label/macro
Not defined
not defined label
Extra characters on line
there's some garbage on the end of line
Constant too large
the number was too big
General syntax
can't do anything with this
X expected
X may be missing
Expression syntax
syntax error
Branch too far
can't relative branch that far
Missing argument
no argument given
Illegal operand
can't be used here
Unknown encoding
give screen or none as encoding
Requirements not met:
Not all features are provided, at least one is missing
at least one feature is provided, which shouldn't be there
Division by zero
Cannot calculate value

Fatal errors

Can't locate file
cannot open file
Out of memory
won't happen ;)
Can't write object file:
cannot write the result
Line too long
input line was too long
Can't write listing file:
cannot write the list file
Can't write label file:
cannot write the label file
File recursion
wrong use of .include
Macro recursion too deep
wrong use of nested macros
Unknown CPU
CPU type not known
Ooops! Too many passes...
With a carefuly crafted source file it's possible to create unresolvable situations. Fix your code.

6502 illegal opcodes

opcode hex
ANC $0b
ANE (XAA) $8b
ARR $6b
ASR (ALR) $4b
DCP (DCM) $c3, $c7, $cf, $d3, $d7, $db, $df
ISB (INS, ISC) $e3, $e7, $ef, $f3, $f7, $fb, $ff
JAM $02
LAE (LAS, LDS) $bb
LAX $a3, $a7, $ab, $af, $b3, $b7, $bf
LXA (LAX #) $ab
RLA $23, $27, $2f, $33, $37, $3b, $3f
RRA $63, $67, $6f, $73, $77, $7b, $7f
SAX $83, $87, $8f, $97
SBX (AXS) $cb
SHA (AHX) $93, $9f
SHS (TAS) $9b
SHX $9e
SHY $9c
SLO $03, $07, $0f, $13, $17, $1b, $1f
SRE $43, $47, $4f, $53, $57, $5b, $5f

65C02 extra opcodes

opcode hex
BRA $80
DEA $3a
INA $1a
PHX $da
PHY $5a
PLX $fa
PLY $7a
TRB $14, $1c
TSB $04, $0c
STZ $64, $74, $9c, $9e

65DTV02 extra and illegal opcodes

opcode hex
BRA $12
SAC $32
SIR $42
ANE (XAA) $8b
ARR $6b
ASR (ALR) $4b
DCP (DCM) $c3, $c7, $cf, $d3, $d7, $db, $df
ISB (INS, ISC) $e3, $e7, $ef, $f3, $f7, $fb, $ff
LAX $a3, $a7, $ab, $af, $b3, $b7, $bf
LXA (LAX #) $ab
RLA $23, $27, $2f, $33, $37, $3b, $3f
RRA $63, $67, $6f, $73, $77, $7b, $7f
SAX $83, $87, $8f, $97
SLO $03, $07, $0f, $13, $17, $1b, $1f
SRE $43, $47, $4f, $53, $57, $5b, $5f