6502.Net documentation left below, unchanged, because it's good and helpful, and because I am lazy. This is a forked package with changes.
The intention of this fork is to make a cc65-compatible assembler that can be controlled programatically. This is to make it easier to write C# that patches 6502 binaries.
By the time you read this, this should be actively used in https://github.com/FiendsOfTheElements/FF1Randomizer.
- Local labels should be written as '@Loop', not '_Loop'.
- Anonymous labels should be written as ':', not '+' or '-'. You jump to them by referring to them as ':-' or ':+' (or ':--', ':---', etc.)
- As a user of this library, you should only really need to call PatchAssembler.Assemble(). See that class for (short and simple) documentation.
- You may programatically insert entries into the symbol table, pre-assemble-time, via that method.
- The above required a number of internal changes, obviously.
- Various things had their access modifiers changed so they could be read & written from subclasses, etc.
- The AsmCommandLineOptions class has been renamed AssemblyOptions and given an appropriate constructor etc.
- An event has been added, AssemblyController.OnBeginningOfPass, which gives you an opportunity to mess with the PC and the symbol table.
6502.Net documentation follows.
The 6502.Net Macro Assembler is a simple cross-assembler targeting the MOS 6502, WDC 65C02, WDC 65C816 and related CPU architectures. It is written for .Net (Version 4.5.1). It can assemble both legal (published) and illegal (undocumented) 6502 instructions, as well instructions from its successors the 65C02 and 65C816.
The 6502 was a popular choice for video game system and microcomputer manufacturers in the 1970s and mid-1980s, due to its cost and efficient design. Among hobbyists and embedded systems manufacturers today it still sees its share of use. For more information, see the wiki entry or 6502 resource page to learn more about this microprocessor.
The 65C02 is an enhancement to the 6502, offering some improvements, including unconditional relative branching and a fix to the infamous "indirect jump page wrap" defect. It was notable in the market as the brains behind the Apple IIe and Apple IIc home computers, as well as the NEC TurboGrafx-16/PC Engine game system.
The W65C816S (or 65816 for short), is a true successor to the 6502, a fully backward compatible 16-bit CPU. It is mostly known for powering the Apple IIgs and the Super Nintendo game console.
- 6502.Net (c) 2017, 2018 informedcitizenry
- System.CommandLine, a command-line argument parser (c) Microsoft Corporation
See LICENSE and LICENSE_third_party for licensing information.
The 6502.Net assembler is simple to use. Invoke it from a command line with the assembly source and (optionally) the output filename in the parameters. For instance, a /6502.Net.exe myprg.asm
command will output assembly listing in myprgm.asm
to binary output. To specify output file name use the -o <file>
or --output=<file>
option, otherwise the default output filename will be a.out
.
You can specify as many source files as assembly input as needed. For instance, 6502.Net.exe mylib.asm myprg.asm
will assemble both the mylib.asm
and myprgm.asm
files sequentially to output. Be aware that if both files define the same symbol an assembler error will result.
Integral constants can be expressed as decimal, hexadecimal, and binary. Decimal numbers are written as is, while hex numbers are prefixed with a $
and binary numbers are prefixed with a %
.
65490 = 65490
$ffd2 = 65490
%1111111111010010 = 65490
Negative numbers are assembled according to two's complement rules, with the highest bits set. Binary strings can alternatively be expressed as .
for 0
and #
for 1
, which is helpful for laying out pixel data:
number1 .byte %...###..
.byte %..####..
.byte %.#####..
.byte %...###..
.byte %...###..
.byte %...###..
.byte %...###..
.byte %.#######
When writing assembly code, hand-coding branches, addresses and constants can be time-consuming and lead to errors. Labels take care of this work for you! There is no restriction on name size, but all labels must begin with an underscore or letter, and can only contain underscores, letters, and digits, and they cannot be re-assigned:
black = 0
lda #black ; load black into acc.
beq setborder ; now set the border color
...
setborder: sta $d020 ; poke border color with acc.
Trailing colons for jump instructions are optional.
Once labels are defined they cannot be redinfed in other parts of code. This gets tricky as source grows, since one must choose a unique name for each label. There are a few ways to avoid this problem.
The first is to append the label with an underscore, making it a local label.
routine1 lda message,x
beq _done
jsr $ffd2
inx
jmp routine1
_done rts
routine2 ldy flag
beq _done
jmp dosomething
_done rts
In the routine above, there are two labels called _done
but the assembler will differentiate between them, since the second _done
follows a different non-local label than the first.
In addition to local labels, scope blocks can be used. All source inside a pair of .block
and .endblock
directives are considered local to that block, but can also be nested, making them much like namespaces.
A scope block looks like this:
...
endloop lda #$ff
rts
myblock .block
jsr endloop ; accumulator will be 0
... ; since endloop is local to myblock
endloop lda #0
rts
.endblock
Labels inside a named scope block can be referenced with dot notation from other places outside of the scope:
kernal .block
chrin = $ffcf
chrout = $ffd2
.endblock
jsr kernal.chrout ; call the subroutine whose label
; is defined in the kernal block
Any block not preceded by a label is an anonymous block. All symbols inside an anonymous block are only visible within the block, and are unavailable outside:
.block
jsr increment
...
increment inc mem
beq done
inc mem+1
done rts
.endblock
jsr increment ; will produce an assembler error
Anonymous labels allow one to do away with the need to think of unique label names altogether. There are two types of anonymous labels: forward and backward. Forward anonymous labels are declared with a +
, while backward anonymous labels are declared using a -
. They are forward or backward to the current assembly line and are referenced in the operand with one or more +
or -
symbols:
printmessage
ldx #0
- lda msg_ptr,x
beq + ; jump to first forward anonymous from here
jsr chrout
inx
bne - ; jump to first backward anonymous from here
+ rts
- nop
jmp -- ; jump to the second backward anonymous from here
As you can see anonymous labels, though convenient, would hinder readability if used too liberally. They are best for small branch jumps, though can be used in expressions:
- .byte $01, $02, $03
lda -,x
Another type of named symbol besides a label is a variable. Variables, like labels, are named references to values in operand expressions, but whose value can be changed as often as required. A variable is declared with the .let
directive, followed by an assignment expression. Variables and labels cannot share the same symbol name.
.let myvar = 34
lda #myvar
.let myvar = myvar + 1
ldx #myvar
Unlike labels, variables cannot be referenced in other expressions before they are declared, since variables are not preserved between passes.
.let y = x
.let x = 3
In the above example, the assembler would error assuming x
has never been declared before.
Adding comments to source promotes readability, particularly in assembly. Comments can be added to source code in one of two ways, as single-line trailing source code, or as a block. Single-line comments start with a semi-colon. Any text written after the semi-colon is ignored, unless it is being expressed as a string or constant character.
lda #0 ; 0 = color black
sta $d020 ; set border color to accumulator
lda #';' ; the first semi-colon is a char literal so will be assembled
jsr $ffd2
Block comments span multiple lines, enclosed in .comment
and .endcomment
directives. These are useful when you want to exclude unwanted code:
.comment
this will set the cpu on fire do not assemble!
lda #$ff
sta $5231
.endcomment
In addition to 6502 assembly, data can also be assembled. Expressions evaluate internally as 64-bit signed integers, but must fit to match the expected operand size; if the value given in the expression exceeds the data size, this will cause an illegal quantity error. The following pseudo-ops are available:
Directive | Size |
---|---|
.byte |
One byte unsigned |
.sbyte |
One byte signed |
.addr |
Two byte address |
.sint |
Two bytes signed |
.word |
Two bytes unsigned |
.rta |
Two byte return address |
.lint |
Three bytes signed |
.long |
Three bytes unsigned |
.dint |
Four bytes signed |
.dword |
Four bytes unsigned |
.align |
Zero or more bytes |
.fill |
One or more bytes |
Multi-byte directives assemble in little-endian order (the least significant byte first), which conforms to the 6502 architecture. Data is comma-separated, and each value can be a constant or expression:
sprite .byte %......##,%########,%##......
jump .word sub1, sub2, sub3, sub4
The .addr
and .rta
directives are the same as .word
, but .rta
is the expression minus one. This is useful for doing an "rts jump":
lda #>jump ; high byte ($07)
pha
lda #<jump ; low byte ($ff)
pha
rts ; do the jump
jump .rta $0800 ; = $07ff
For .fill
and .align
, the assembler accepts either one or two arguments. The first is the quantity, while the second is the value. If the second is not given then it is assumed to be uninitialized data (see below). For .fill
, quantity is number of bytes, for .align
it is the number of bytes by which the program counter can be divided with no remainder:
unused .fill 256,0 ; Assemble 256 bytes with the value 0
atpage .align 256 ; The program counter is guaranteed to be at a page boundary
Sometimes it is desirable to direct the assembler to make a label reference an address, but without assembling bytes at that address. For instance, for program variables. Use the ?
instead of an expression:
highscore .dword ? ; set the symbol highscore to the program counter,
; but do not output any bytes
Note that if uninitialized data is defined, but thereafter initialized data is defined, the output will fill bytes to the program counter from the occurrence of the uninitialized symbol:
highscore .dword ? ; uninitialized highscore variables
lda #0 ; The output is now 6 bytes in size
In addition to integral values, 6502.Net can assemble Unicode text. Text strings are enclosed in double quotes, character literals in single quotes.
Strings can be assembled in a few different ways, according to the needs of the programmer.
Directive | Meaning |
---|---|
.string |
A standard string literal |
.cstring |
A C-style null-terminated string |
.lsstring |
A string with output bytes left-shifted and the low bit set on its final byte |
.nstring |
A string with the negative (high) bit set on its final byte |
.pstring |
A Pascal-style string, its size in the first byte |
Since .pstring
strings use a single byte to denote size, no string can be greater than 255 bytes. Since .nstring
and .lsstring
make use of the high and low bits, bytes must not be greater in value than 127, nor less than 0.
There are two special string functions. The first, str()
, will convert an integral value to its equivalent in bytes:
start = $c000
startstr .string str(start) ; assembles as $34,$39,$31,$35,$32
; literally the digits "4","9","1","5","2"
The format()
function allows you to convert non-string data to string data using a .Net format string:
stdout = $ffd2
stdstring .string format("The stdout routine is at ${0:X4}", stdout)
;; will assemble to:
;; "The stdout routine is at $FFD2
Assembly source text is processed as UTF-8, and by default strings and character literals are encoded as such. You can change how text output with the .encoding
and .map
directives. Use .encoding
to select an encoding, either pre-defined or custom. The encoding name follows the same rules as labels. There are four pre-defined encodings:
Encoding | Output bytes |
---|---|
none |
UTF-8 |
atascreen |
Atari screen codes |
cbmscreen |
CBM screen codes |
petscii |
CBM PETSCII |
The default encoding is none
. It is worth noting that, for the Commodore-specific encodings, several of the glyphs in those platforms can be represented in Unicode counterparts. For instance, for Petscii encoding, ♥ outputs to D3
as is expected.
Text encodings are modified using the .map
and .unmap
directives. After selecting an encoding, you can map a Unicode character to a custom output code as follows:
;; select encoding
.encoding myencoding
;; map A to output 0
.map "A", 0
.string "ABC"
;; > 00 42 43
;; char literals are also affected
lda #'A' ;; a9 00
;; emoji will assemble too!
.string "😁" ;; f0 9f 98 81
The output can be one to four bytes. Entire character sets can also be mapped, with the re-mapped code treated as the first in the output range. The start and endpoints in the character set to be re-mapped can either be expressed as a two-character string literal or as expressions.
;; output lower-case chars as uppercase
.map "az", "A"
;; output digits as actual integral values
.map "0","9", 0
;; alternatively:
.map 48, 48+9, 0
;; escape sequences are acceptable too:
.map "\u21d4", $9f
Caution: Operand expressions containing a character literal mapped to a custom code will evaluate the character literal accordingly. This may produce unexpected results:
.map 'A', 'a'
.map 'a', 'A' ;; this is now the same as .map 'a', 'a'
Instead express character literals as one-character strings in double-quotes, which will resolve to UTF-8 values.
A further note about encodings and source files. As mentioned, source files are read and processed as UTF-8. While it is true that the .Net StreamReader class can auto-detect other encodings, this cannot be guaranteed (for instance if the BOM is lacking in a UTF-16-encoded source). If the source does not assemble as expected, consider converting it to UTF-8 or at least ASCII. This article offers a good overview on the issues concerning text encodings.
All .Net escape sequences will also output, including Unicode.
.string "He said, \"How are you?\""
.byte '\t', '\''
Here are a few recognized escape sequences:
Escape Sequence | ASCII/Unicode Representation |
---|---|
\n |
Newline |
\r |
Carriage return |
\t |
Tab |
\" |
Double quotation mark |
\unnnn |
Unicode U+nnnn |
Other files can be included in final assembly, either as 6502.Net-compatible source or as raw binary. Source files are included using the .include
and .binclude
directives. This is useful for libraries or other organized source you would not want to include in your main source file. The operand is the file name (and path) enclosed in quotes. .include
simply inserts the source at the directive.
;; inside "../lib/library.s"
.macro inc16 mem
inc \mem
bne +
inc \mem+1
+ .endmacro
...
This file called "library.s"
inside the path ../lib
contains a macro definition called inc16
(See the section below for more information about macros).
.include "../lib/library.s"
.inc16 $033c ; 16-bit increment value at $033c and $033d
If the included library file also contained its own symbols, caution would be required to ensure no symbol clashes. An alternative to .include
is .binclude
, which resolves this problem by enclosing the included source in its own scoped block.
lib .binclude "../lib/library.s" ; all symbols in "library.s"
; are in the "lib" scope
jsr lib.memcopy
If no label is prefixed to the .binclude
directive then the block is anonymous and labels are not visible to your code.
External files containing raw binary that will be needed to be included in your final output, such as .sid
files or sprite data, can be assembled using the .binary
directive.
* = $1000
.binary "../rsrc/sprites.raw"
...
lda #64 ; pointer to first sprite in "./rsrc/sprites.raw"
sta 2040 ; set first sprite to that sprite shape
You can also control how the binary will be included by specifying the offset (number of bytes from the start) and size to include.
* = $1000
.binary "../rsrc/music.sid", $7e ; skip first 126 bytes
; (SID header)
.binary "../lib/compiledlib.bin", 2, 256 ; skip load header
; and take 256 bytes
All non-string operands are treated as math or conditional expressions. Compound expressions are nested in paranetheses. There are several available operators for both binary and unary expressions.
Operator | Meaning |
---|---|
+ | Add |
- | Subtract |
* | Multiply |
/ | Divide |
% | Modulo (remainder) |
** | Raise to the power of |
& | Bitwise AND |
| | Bitwise OR |
^ | Bitwise XOR |
<< | Bitwise left shift |
>> | Bitwise right shift |
< | Less than |
<= | Less than or equal to |
== | Equal to |
!= | Not equal to |
>= | Greater than or equal to |
> | Greater than |
&& | Logical AND |
|| | Logical OR |
.addr HIGHSCORE + 3 * 2 ; the third address from HIGHSCORE
.byte * > $f000 ; if program counter > $f000, assemble as 1
; else 0
;; bounds check START_ADDR
.assert START_ADDR >= MIN && START_ADDR <= MAX
Operator | Meaning |
---|---|
~ | Bitwise complementary |
< | Least significant byte |
> | Most significant (second) byte |
& | Word (first two bytes) value |
^ | Bank (third) byte |
! | Logical NOT |
lda #>routine-1 ; routine MSB
pha
lda #<routine-1 ; routine LSB
pha
rts ; RTS jump to "routine"
routine lda &long_address ; load the absolute value of long_address
; (truncate bank byte) into accummulator
Several built-in math functions that can also be called as part of the expressions.
lda #sqrt(25)
See the section below on functions for a full list of available functions.
By default, programs start at address 0, but you can change this by setting the program counter before the first assembled byte. 6502.Net uses the *
symbol for the program counter. The assignment can be either a constant or expression:
* = ZP + 1000 ; program counter now 1000 bytes offset from
; the value of the constant ZP
(Be aware of the pesky trap of trying to square the program counter using the **
operator, i.e. ***
. This produces unexpected results. Instead consider the pow()
function as described in the section on math functions below.)
As assembly continues, the program counter advances automatically. You can manually move the program counter forward, but keep in mind doing so will create a gap that will be filled if any bytes are added to the assembly from that point forward. For instance, consider:
* = $1000
lda #0
jsr $1234
* = $2004
brk
This will output 4096 bytes, with 4091 zeros. So this generally is not recommended unless this is the desired result.
To move the program counter forward for the purposes having the symbols use an address space that code will be relocated to later, you can use the .relocate
directive:
* = $0200
newlocation = $a000
lda #<torelocate
sta $02
lda #>torelocate
sta $03
lda #<newlocation
sta $04
lda #>newlocation
sta $05
ldy #0
lda ($02),y
sta ($04),y
....
torelocate:
.relocate newlocation ; no gap created
jsr relocatedsub ; now in the "newlocation" address space
...
relocatedsub lda #0
...
To reset the program counter back to its regular position use the .endrelocate
directive:
jsr relocatedsub
...
jmp finish
torelocate:
relocate newlocation
...
.endrelocate
;; done with movable code, do final cleanup
finish rts
Because the 65xx architecture uses differing addressing modes for the same mnemonics, by default 6502.Net selects the appropriate instruction based on the minimum required size to express the operand. For instance lda 42
can either be interpreted to be zero-page or absolute addressing, but 6502.Net will choose zero-page. Similarly, for the 65C816 lda $c000
could either be an absolute or long address, but 6502.Net will again choose the shorter (and faster!) instruction to assemble. You can, however, force the assembler to choose the larger mode explicitly by pre-fixing the operand with the bit-size enclosed in square brackets.
$c000
;; zero-page loadA
lda 42 ; > .c000 a5 2a
;; absolute loadA
lda [16] 42 ; > .c002 ad 2a 00
;; long jsr to bank 0 $ffd2
jsr [24] $ffd2 ; > .c005 22 d2 ff 00
One of the more powerful features of the 6502.Net cross assembler is the ability to re-use code segments in multiple places in your source. You define a macro or segment once, and then can invoke it multiple times later in your source; the assembler simply expands the definition where it is invoked as if it is part of the source. Macros have the additional benefit of allowing you to pass parameters, so that the final outputted code can be easily modified for different contexts, behaving much like a function call in a high level language. For instance, one of the more common operations in 6502 assembly is to do a 16-bit increment. You could use a macro for this purpose like this:
inc16 .macro address
inc \address
bne +
inc \address+1
+ .endmacro
The macro is called inc16
and takes a parameter called address
. The code inside the macro references the parameter with a backslash \
followed by the parameter name. The parameter is a textual subsitution; whatever you pass will be expanded at the reference point. Note the anonymous forward symbol at the branch instruction will be local to the block, as would any symbols inside the macro definition when expanded. To invoke a macro simply reference the name with a .
in front:
myvariable .word ?
.inc16 myvariable
This macro expands to:
inc myvariable
bne +
inc myvariable+1
+ ...
Segments are conceptually identical to macros, except they do not accept parameters and are usually used as larger segments of relocatable code. Segments are defined between .segment
/.endsegment
blocks with the segment name after each closure directive.
.segment zp
zpvar1 .word ?
zpvar2 .word ?
...
.endsegment zp
.segment code
ldx #0
+ lda message,x
jsr chrout
inx
cpx #msgsize
bne +
...
.endsegment code
Then you would assemble defined segments as follows:
* = $02
.zp
.errorif * > $ff, ".zp segment outside of zero-page!"
* = $c000
.code
You can also define segments within other segment definitions. Note that doing this does not make them "nested." The above example would be re-written as:
.segment program
.segment zp
zpvar1 .word ?
zpvar2 .word ?
txtbuffer .fill 80
.endsegment zp
.segment code
ldx #0
...
.segment bss
variables .byte ?
...
.endsegment bss
.endsegment code
.endsegment program
* = $02
.zp
* = $033c
.bss
* = $c000
.code
Macros and segments must be defined before they can be invoked.
In cases where you want to control the flow of assembly, either based on certain conditions (environmental or target architecture) or in certain iterations, 6502.Net provides certain directives to handle this.
Conditional assembly is available using the .if
and related directive. Conditions can be nested, but expressions will be evaluated on first pass only.
lda #$41
.ifdef APPLE2 ; is the symbol APPLE2 defined?
jsr $fbfd
.else
jsr $ffd2
.endif
Caution: Be careful not to use the .end
directive inside a conditional block, which terminates assembly, otherwise the .endif
closure will never be reached, and the assembler will report an error.
On occasions where certain instructions will be repeatedly assembled, it is convenient to repeat their output in a loop. For instance, if you want to pad a series of nop
instructions. The .repeat
directive does just that.
;; will assemble $ea ten times
.repeat 10
nop
.endrepeat
These repetitions can also be nested, as shown below.
;; print each letter of the alphabet 3 times
* = $c000
lda #$41
.repeat 26
.repeat 3
jsr $ffd2
.endrepeat
tax
inx
txa
.endrepeat
.repeat 3
jsr $ffd2
.endrepeat
rts
Repetitions can also be handled in for/next loops, where source can be emitted repeatedly until a condition is met. An iteration variable can optionally be initialized, with the advantage is the variable itself can be referenced inside the loop.
lda #0
.for i = $0400, i < $0800, i = i + 1
sta i
.next
A minimum two operands are required: The initial expression and the condition expression. A third iteration expression is option. The iteration expression can be blank, however.
.let a = 0;
.let n = 1;
.for , n < 10
.if a == 3
.let n = n + 1;
.else
.let n = n + 5;
.endif
.echo format("{0}",n);
.next
.comment
outputs:
6
11
.endcomment
If required, loops can be broken out of using the .break
directive
.for i = 0, i < 256, i = i + 1
.if * >= $1000
.break ; make sure assembly does not go past $1000
.endif
lda #'A'
jsr $ffd2
.next
All expressions, including the condition, are only evaluated on the first pass.
Caution: Changing the value of the iteration variable inside the loop can cause the application to hang. 6502.Net does not restrict re-assigning the iteration variable inside its own or nested loops.
By default, 6502.Net "thinks" like a 6502 assembler, compiling only the published 56 mnemonics and 151 instructions of that microprocessor. As of Version 1.7, 6502.Net can also compile illegal instructions as well as those of the successor WDC 65C02 and W65C816S processors. The .cpu
directive tells the assembler the type of source and instruction set it is to assemble.
.cpu "6502i" ; enable illegal instructions
ldx #0
slo (zpvar,x)
There are four options for the .cpu
directive: 6502
, 6502i
, 65C02
and 65816
. 6502
is default. You can also select the cpu in the command line by passing the --cpu
option (detailed below). Note that only one CPU target can be selected at a time, though in the case of the 65816
selection this also includes 65C02 and 6502 (legal) instructions, since it is a superset of both.
Immediate mode on the 65816 differs based on register size. 6502.Net must be told which size to use for which register in order to assemble the correct number of bytes for immediate mode operations. Use .m8
for 8-bit accumulator and .m16
for 16-bit accumulator; .x8
for 8-bit index registers and .x16
for 16-bit index registers.
rep #%00110000
.m16
lda #$c000
ldx #$03
.x16
ldy #$1000
jml $1012000
Eight-bit modes for registers are default.
You can also set all registers to the same size with .mx8
and .mx16
respectively.
sep #%00110000
.mx8
lda #$00
ldx #$01
ldy #$02
By default, the 6502.Net only recognizes the 151 published instructions of the original MOS Technology 6502. The following mnemonics are recognized:
adc,and,asl,bcc,bcs,beq,bit,bmi,bne,bpl,brk,bvc,bvs,clc,
cld,cli,clv,cmp,cpx,cpy,dec,dex,dey,eor,inc,inx,iny,jmp,
jsr,lda,ldx,ldy,lsr,nop,ora,pha,php,pla,plp,rol,ror,rti,
rts,sbc,sec,sed,sei,sta,stx,sty,tax,tay,tsx,txa,txs,tya
65C02 support adds the following additional mnemonics:
bra,phx,phy,plx,ply,trb,tsb
For 65816 compatibility the following mnemonics are recognized:
brl,cop,jml,jsl,mvn,mvp,pea,pei,per,phb,phd,phk,plb,pld,
rep,rtl,sep,stp,tcd,tcs,tdc,tsc,txy,tyx,wai,wdm,xba,xce
Since they are technically undocumented, mnemonics for illegal instructions vary among assemblers. 6502.Net closely follows those used by VICE, a popular Commodore 64 emulator. Illegal mnemonics, operations and opcodes are as follows:
|
|
*-JAM
and STP
are essentially the same command; they both halt the CPU.
Note: Illegal mnemonics are only available if the 6502i
option is specified in the --cpu
commandline or .cpu
directive.
Following is the detail of each of the 6502.Net pseudo operations, or psuedo-ops. A pseudo-op is similar to a mnemonic in that it tells the assembler to output some number of bytes, but different in that it is not part of the CPU's instruction set. For each pseudo-op description is its name, any aliases, a definition, arguments, and examples of usage. Optional arguments are in square brackets ([
and ]
).
Note that every argument, unless specified, is a legal mathematical expression, and can include symbols such as labels (anonymous and named) and the program counter. If the expression evaluates to a value greater than the maximum value allowed by the pseudo-op, the assembler will issue an illegal quantity error.
Data/text insertions
Name | .addr |
Alias | .word |
Definition | Insert an unsigned 16-bit value or values between 0 and 65535 into the assembly. Multiple arguments can be passed as needed. If ? is passed then the data is uninitialized. |
Arguments | address[, address2[, ...] |
Example |
* = $c000 mysub lda #13 ; output newline jsr chrout rts .addr mysub ; >c006 00 c0 |
Name | .align |
Alias | None |
Definition | Set the program counter to a value divisible by the argument. If a second argument is specified, the expressed bytes will be assembled until the point the program counter reaches its new value, otherwise is treated as uninitialized memory. |
Arguments | amount[, fillvalue] |
Example |
* = $c023 .align $10,$ff ; >c023 ff ff ff ff ff ff ff ff ; >c02b ff ff ff ff ff .byte $23 ; >c030 23 |
Name | .binary |
Alias | None |
Definition | Insert a file as binary data into the assembly. Optional offset and file size arguments can be passed for greater flexibility. |
Arguments | filename[, offset[, size] |
Example |
.binary "subroutines.prg",2 ; strip off start address .binary "mybin.bin" ; include all of 'mybin.bin' .binary "soundtrack.sid",$7e ; skip SID-header .binary "subroutines.prg",2,1000 ;; strip off start address, only take first ;; 1000 bytes thereafter. |
Name | .byte |
Alias | None |
Definition | Insert an unsigned byte-sized value or values between 0 and 255 into the assembly. Multiple arguments can be passed as needed. If ? is passed then the data is uninitialized. |
Arguments | value[, value[, ...] |
Example |
* = $033c .byte $39, $38, $37, $36, $35, $34, $33, $32, $31 ;; >033c 39 38 37 36 35 34 33 32 ;; >0344 31 |
Name | .cstring |
Alias | None |
Definition | Insert a C-style null-terminated string into the assembly. Multiple arguments can be passed, with a null only inserted at the end of the argument list. If ? is passed then the data is an uninitialized byte. Enclosed text is assembled as string-literal while expressions are assembled to the minimum number of bytes required for storage, in little-endian byte order. |
Arguments | value[, value[, ...] |
Example |
* = 1000 .cstring "hello, world!" ; >1000 68 65 6c 6c 6f 2c 20 77 ; >1008 6f 72 6c 64 21 00 .cstring $93,"ALL CLEAR" ; >100e 93 41 4c 4c 20 43 4c 45 ; >1016 41 52 00 .cstring $ffd2 ; >1019 d2 ff 00 |
Name | .dint |
Alias | None |
Definition | Insert a signed 32-bit value or values between −2147483648 and 2147483647 into the assembly, little-endian. Multiple arguments can be passed as needed. If ? is passed then the data is uninitialized. |
Arguments | value[, value[, ...] |
Example |
* = $0801 .dint 18000000 ; >0801 80 a8 12 01 |
Name | .dword |
Alias | None |
Definition | Insert a signed 32-bit value or values between 0 and 4294967295 into the assembly, little-endian. Multiple arguments can be passed as needed. If ? is passed then the data is uninitialized. |
Arguments | value[, value[, ...] |
Example |
* = $0801 .dword $deadfeed ; >0801 ed fe ad de |
Name | .fill |
Alias | None |
Definition | Fill the assembly by the specified amount. Similar to align, that if only one argument is passed then space is merely reserved. Otherwise the optional second argument indicates the assembly should be filled with bytes making up the expression, in little-endian byte order. |
Arguments | amount[, fillvalue] |
Example |
.fill 23 ; reserve 23 bytes * = $1000 .fill 11,$ffd2 ; >1000 d2 ff d2 ff d2 ff d2 ff ; >1008 d2 ff d2 |
Name | .lint |
Alias | None |
Definition | Insert a signed 24-bit value or values between -8388608 and 8388607 into the assembly, little-endian. Multiple arguments can be passed as needed. If ? is passed then the data is uninitialized. |
Arguments | value[, value[, ...] |
Example |
* = $c100 .lint -80000 ; >c100 80 c7 fe |
Name | .long |
Alias | None |
Definition | Insert a signed 24-bit value or values between 0 and 16777215 into the assembly, little-endian. Multiple arguments can be passed as needed. If ? is passed then the data is uninitialized. |
Arguments | value[, value[, ...] |
Example |
* = $c100 .long $ffdd22 ; >c100 22 dd ff |
Name | .lsstring |
Alias | None |
Definition | Insert a string into the assembly, each byte shifted to the left, with the lowest bit set on the last byte. See example of how this format can be used. If the highest bit of any output byte is set, the assembler will error. Multiple arguments can be passed, with a null only inserted at the end of the argument list. If ? is passed then the data is an uninitialized byte. Enclosed text is assembled as string-literal while expressions are assembled to the minimum number of bytes required for storage, in little-endian byte order. |
Arguments | value[, value[, ...] |
Example |
ldx #0 - lda message,x lsr a ; shift right php ; save carry flag jsr chrout ; print plp ; restore carry flag bcs done ; if set we printed last char inx ; increment pointer jmp - ; get next ... * = $c100 message .lsstring "HELLO" ; >c100 90 8a 98 98 9f |
Name | .nstring |
Alias | None |
Definition | Insert a string into the assembly, the negative (highest) bit set on the last byte. See example of how this format can be used. If the highest bit of the last byte is already set, the assembler will error. Multiple arguments can be passed, with a null only inserted at the end of the argument list. If ? is passed then the data is an uninitialized byte. Enclosed text is assembled as string-literal while expressions are assembled to the minimum number of bytes required for storage, in little-endian byte order. |
Arguments | value[, value[, ...] |
Example |
ldx #0 - lda message,x php ; save negative flag and #%01111111 ; turn off high bit... jsr chrout ; and print plp ; restore negative flag bmi done ; if set we printed last char inx ; else increment pointer jmp - ; get next ... * = $c100 message .nstring "hello" ; >c100 68 65 6c 6c ef |
Name | .pstring |
Alias | None |
Definition | Insert a Pascal-style string into the assembly, the first byte indicating the full string size. Note this size includes all arguments in the expression. If the size is greater than 255, the assembler will error. If ? is passed then the data is an uninitialized byte. Enclosed text is assembled as string-literal while expressions are assembled to the minimum number of bytes required for storage, in little-endian byte order. |
Arguments | value[, value[, ...] |
Example |
* = $4000 .pstring $23,$24,$25,$26,1024 ; >4000 06 23 24 25 26 00 04 .pstring "hello" ; >4007 05 68 65 6c 6c 6f |
Name | .rta |
Alias | None |
Definition | Insert an unsigned 16-bit value or values between 0 and 65535 into the assembly. Similar to .addr and .word , except the value is decremented by one, yielding a return address. This is useful for building "rts jump" tables. Multiple arguments can be passed as needed. If ? is passed then the data is uninitialized. |
Arguments | address[, address2[, ...] |
Example | chrin = $ffcf chrout = $ffd2 * = $c000 rtsjmp txa ; .x := index of jump asl a ; double it tax lda jumptable+1,x ; push high byte pha lda jumptable,x ; push low byte pha rts ; do the jump jumptable .rta chrout, chrin ; >c00b d1 ff ce ff |
Name | .sbyte |
Alias | None |
Definition | Insert an unsigned byte-sized value or values between -128 and 127 into the assembly. Multiple arguments can be passed as needed. If ? is passed then the data is uninitialized. |
Arguments | value[, value[, ...] |
Example |
* = $033c .sbyte 127, -3 ; >033c 7f fd |
Name | .sint |
Alias | None |
Definition | Insert a signed 16-bit value or values between -32768 and 32767 into the assembly, little-endian. Multiple arguments can be passed as needed. If ? is passed then the data is uninitialized. |
Arguments | value[, value[, ...] |
Example |
* = $c000 mysub lda #13 ; output newline jsr chrout rts .sint -16384 ; >c006 00 c0 |
Name | .string |
Alias | None |
Definition | Insert a string into the assembly. Multiple arguments can be passed, with a null only inserted at the end of the argument list. If ? is passed then the data is an uninitialized byte. Enclosed text is assembled as string-literal while expressions are assembled to the minimum number of bytes required for storage, in little-endian byte order. |
Arguments | value[, value[, ...] |
Example |
* = 1000 .string "hello, world!" ; >1000 68 65 6c 6c 6f 2c 20 77 ; >1008 6f 72 6c 64 21 |
Assembler directives
Name | .assert |
Alias | None |
Definition | Asserts the truth of a given expression. If the assertion fails, an error is logged. A custom error can optionally be specified. |
Arguments | condition[, error] |
Example |
* = $0800 nop .assert 5 == 6 ; standard assertion error thrown .assert * < $0801, "Uh oh!" ; custom error output |
Name | .binclude |
Alias | None |
Definition | Include a source file and enclose the expanded source into a scoped block. The specified file is 6502.Net-compatible source. If no name is given in front of the directive then all symbols inside the included source will be inaccessible. Note that to prevent infinite recursion, a source file can only be included once in the entire source, including from other included files. |
Arguments | filename |
Example |
soundlib .binclude "sound.s" jsr soundlib.play ; Invoke the ; play subroutine ; inside the ; sound.s source ;; whereas... .binclude "sound.s" jsr play ; will not assemble! |
Name | .block /.endblock |
Alias | None |
Definition | Define a scoped block for symbols. Useful for preventing label definition clashes. Blocks can be nested as needed. Unnamed blocks are considered anonymous and all symbols defined within them are inaccessible outside the block. Otherwise symbols inside blocks can be accessed with dot-notation. |
Arguments | None |
Example |
kernal .block chrout = $ffd2 chrin = $ffcf .endblock ... chrout lda message,x jsr kernal.chrout ; this is a different ; chrout! done rts ; this is not the done ; below! .block beq done ; the done below! nop nop done rts .endblock |
Name | .break |
Alias | None |
Definition | Break out of the current for-next loop. |
Arguments | None |
Example |
.for n = 0, n < 1000, n = n + 1 .if * > $7fff ; unless address >= $8000 .break .endif nop ; do 1000 nops .next |
Name | .cpu |
Alias | None |
Definition | Set the assembler to target the supported CPU. See the --cpu option in the command-line notes below for the available options. |
Arguments | cpu |
Example |
.cpu "65816" clc xce rep #%00110000 |
Name | .comment /.endcomment |
Alias | None |
Definition | Set a multi-line comment block. |
Arguments | None |
Example |
.comment My code pre-amble .endcomment |
Name | .echo |
Alias | None |
Definition | Send a message to the console output. Note if the assembler is in quiet mode, no output will be given. |
Arguments | message |
Example |
.echo "hi there!" ;; console will output "hi there!" |
Name | .encoding |
Alias | None |
Definition | Select the text encoding for assembly output. Four encodings are pre-defined:
none is default and will not be affected by .map and .unmap directives.
|
Arguments | encoding |
Example |
.encoding petscii .string "hello" ; >> 45 48 4c 4c 4f |
Name | .end |
Alias | None |
Definition | Terminate the assembly. |
Arguments | None |
Example |
jsr $ffd2 beq done ; oops! rts .end ; stop everything done ... ; assembly will never ; reach here! |
Name | .eor |
Alias | None |
Definition | XOR output with 8-bit value. Quick and dirty obfuscation trick. |
Arguments | xormask |
Example |
.eor $ff .byte 0,1,2,3 ; > ff fe fd fc |
Name | .equ |
Alias | = |
Definition | Assign the label, anonymous symbol, or program counter to the expression. Note that there is an implied version of this directive, such that if the directive and expression are ommitted altogether, the label or symbol is set to the program counter. |
Arguments | symbol, value |
Example |
chrin .equ $ffcf chrout = $ffd2 * .equ $c000 - = 255 start ; same as start .equ * ldx #$00 |
Name | .error |
Alias | None |
Definition | Prints a custom error to the console. The error is treated like any assembler error and will cause failure of assembly. |
Arguments | error |
Example |
.error "We haven't fixed this yet!"
|
Name | .errorif |
Alias | None |
Definition | Prints a custom error to the console if the condition is met. Useful for sanity checks and assertions. The error is treated like any assembler error and will cause failure of assembly. The condition is any logical expression. |
Arguments | condition, error |
Example |
* = $0800 nop .errorif * > $0801, "Uh oh!" ; if program counter ; is greater than 2049, ; raise a custom error |
Name | .[el]if[[n]def] /.endif |
Alias | None |
Definition | All source inside condition blocks are assembled if evaluated to true on the first pass. Conditional expressions follow C-style conventions. The following directives are available:
|
Arguments | condition /symbol |
Example |
* = $0400 cycles = 1 .if cycles == 1 nop .elif cycles == 2 nop nop .endif ;; will result as: ;; ;; nop |
Name | .for /.next |
Alias | None |
Definition | Repeat until codition is met. The iteration variable can be used in source like any other variable. The initialization expression can be blank. Multiple iteration expressions can be specified. |
Arguments | [init_expression], condition[, iteration_expression[, ...] |
Example |
.let x = 0 .for pages = $100, pages < $800, pages = pages + $100, x = x + 1 ldx #x stx pages .next |
Name | .include |
Alias | None |
Definition | Include a source file into the assembly. The specified file is 6502.Net-compatible source. Note that to prevent infinite recursion, a source file can only be included once in the entire source, including from other included files. |
Arguments | filename |
Example |
.include "mylib.s" ;; mylib is now part of source |
Name | .let |
Alias | None |
Definition | Declares and assigns or re-assigns a variable to the given expression. Labels cannot be redefined as variables, and vice versa. In addition, variables cannot be forward-referenced, as they are reset each pass. |
Arguments | expression |
Example |
.let myvar = $ffd2 jsr myvar .let myvar = myvar-$1000 lda myvar |
Name | .m8 |
Alias | None |
Definition | Directs the assembler to treat immediate mode operations on the accumulator as 8-bit (one byte). Useful for when the assembler is in 65816 mode. |
Arguments | None |
Example |
sep #$20 .m8 lda #$13 |
Name | .m16 |
Alias | None |
Definition | Directs the assembler to treat immediate mode operations on the accumulator as 16-bit (two bytes). Useful for when the assembler is in 65816 mode. |
Arguments | None |
Example |
rep #$20 .m16 lda #$1234 |
Name | .mx8 |
Alias | None |
Definition | Directs the assembler to treat all immediate mode operations as 8-bit (one byte). Useful for when the assembler is in 65816 mode. |
Arguments | None |
Example |
sep #$30 .mx8 lda #$13 ldx #$14 ldy #$15 |
Name | .mx16 |
Alias | None |
Definition | Directs the assembler to treat all immediate mode operations as 16-bit (two bytes). Useful for when the assembler is in 65816 mode. |
Arguments | None |
Example |
rep #$30 .mx16 lda #$1234 ldx #$5678 ldy #$9abc |
Name | .macro /.endmacro |
Alias | None |
Definition | Define a macro that when invoked will expand into source. Must be named. Optional arguments are treated as parameters to pass as text substitutions in the macro source where referenced, with a leading backslash \ and either the macro name or the number in the parameter list. Parameters can be given default values to make them optional upon invocation. Macros are called by name with a leading "." All symbols in the macro definition are local, so macros can be re-used with no symbol clashes. |
Arguments | parameter[, parameter[, ...] |
Example |
inc16 .macro inc \1 bne + inc \1+1 + .endmacro .inc16 $c000 ;; expands to => inc $c000 bne + inc $c001 + print .macro value = 13, printsub = $ffd2 lda #\value ; or lda #\1 jsr \printsub ; or jsr \2 rts .endmacro .print ;; expands to => ;; lda #$0d ;; jsr $ffd2 ;; rts .print 'E',$fded ;; expands to => ;; lda #$45 ;; jsr $fded ;; rts |
Name | .map |
Alias | None |
Definition | Maps a character or range of characters to custom binary output in the selected encoding. Note: none is not affected by .map and .unmap directives. It is recommended to represent individual char literals as strings.
|
Arguments | start[, end] ,code /"<start><end>" ,code |
Example |
.encoding myencoding .map "A", "a" .map "π", $5e .byte 'A', 'π' ;; >> 61 5e .map "09", $00 .string "2017" ;; >> 02 00 01 07 |
Name | .relocate /.endrelocate |
Alias | .pseudopc /.realpc |
Definition | Sets the logical program counter to the specified address with the offset of the assembled output not changing. Useful for programs that relocate parts of themselves to different memory spaces. |
Arguments | address |
Example |
* = $0801 ;; create a Commodore BASIC stub ;; 10 SYS2061 SYS = $9e .word eob, 10 .cstring SYS, str(start) eob .word 0 start ldx #0 - lda highcode,x sta $c000,x inx bne - jmp $c000 highcode .relocate $c000 ldx #0 printloop lda message,x beq done jsr $ffd2 inx jmp printloop done rts message .cstring "HELLO, HIGH CODE!" .endrelocate ;; outputs the following => .comment >0801 0b 08 0a 00 >0805 9e 32 30 36 31 00 >080b 00 00 >080d a2 00 ; ldx #0 >080f bd 1b 08 ; - lda highcode,x >0812 9d 00 c0 ; sta $c000,x >0815 e8 ; inx >0816 d0 f7 ; bne - >0818 4c 00 c0 ; jmp $c000 >081b a2 00 ; ldx #$00 >081d bd 0f c0 ; printloop lda message,x >0820 f0 07 ; beq done >0822 20 d2 ff ; jsr $ffd2 >0825 e8 ; inx >0826 4c 02 c0 ; jmp printloop >0829 60 ; done rts ;; message >082a 48 45 4c 4c 4f 2c 20 48 >0832 49 47 48 20 43 4f 44 45 >083a 21 00 .endcomment |
Name | .repeat /.endrepeat |
Alias | None |
Definition | Repeat the specified source the specified number of times. Can be nested, but must be terminated with an .endrepeat . |
Arguments | repeatvalue |
Example |
* = $0400 ldx #$00 .repeat 3 inx .endrepeat rts ;; will assemble as: ;; ;; ldx #$00 ;; inx ;; inx ;; inx ;; rts |
Name | .segment /.endsegment |
Alias | None |
Definition | Defines a block of code as a segment, to be invoked and expanded elsewhere. Similar to macros but takes no parameters and symbols are not local. Useful for building large mix of source code and data without needing to relocate code manually. Segments can be defined within other segment block definitions, but are not considered "nested." Segment closures require the segment name after the directive. |
Arguments | segmentname |
Example |
.segment zp zpvar1 .word ? zpvar2 .word ? txtbuf .fill 80 .endsegment zp .segment bss variables .dword ?, ?, ?, ? .endsegment bss .segment code .segment data glyph ;12345678 .byte %....#### .byte %..#####. .byte %.#####.. .byte %#####... .byte %#####... .byte %.#####.. .byte %..#####. .byte %....#### .endsegment data .basic ; macro that creates BASIC stub sei cld jsr init .endsegment code * = $80 .zp * = $0100 .bss * = $0801 .code * = $0900 .data |
Name | .target |
Alias | None |
Definition | Set the target architecture for the assembly output. See the --arch option in the command-line notes below for the available architectures. |
Arguments | architecture |
Example |
.target "apple2" ;; the output binary will have an Apple DOS header ... |
Name | .typedef |
Note | This feature is currently disabled for now due to a technical issue that caused it not to work correctly in all cases. |
Name | .unmap |
Alias | None |
Definition | Unmaps a custom code for a character or range of characters in the selected encoding and reverts to UTF-8. Note: none is not affected by .map and .unmap directives. It is recommended to represent individual char literals as strings.
|
Arguments | start[, end] /"<start><end>" |
Example |
.encoding myencoding .unmap "A" .unmap "π" ;; revert to UTF-8 encoding .byte 'A', 'π' ;; >> 41 cf 80 .unmap "09" .string "2017" ;; >> 32 30 31 37 |
Name | .warn |
Alias | None |
Definition | Prints a custom warning to the console. The warning is treated like any assembler warning, and if warnings are treated as errors it will cause failure of assembly. |
Arguments | warning |
Example |
.warn "We haven't fixed this yet!"
|
Name | .warnif |
Alias | None |
Definition | Prints a custom warning to the console if the condition is met. The warning is treated like any assembler warning, and if warnings are treated as errors it will cause failure of assembly The condition is any logical expression. |
Arguments | condition, warning |
Example |
* = $0800 nop .warnif * > $0801, "Check bound" ;; if program counter ;; is greater than 2049, ;; raise a custom warning |
Name | .x8 |
Alias | None |
Definition | Directs the assembler to treat immediate mode operations on the index registers as 8-bit (one byte). Useful for when the assembler is in 65816 mode. |
Arguments | None |
Example |
sep #$10 .x8 ldx #$14 ldy #$15 |
Name | .x16 |
Alias | None |
Definition | Directs the assembler to treat immediate mode operations on the index registers as 8-bit (one byte). Useful for when the assembler is in 65816 mode. |
Arguments | None |
Example |
rep #$10 .x16 ldx #$5678 ldy #$9abc |
Name | abs |
Definition | The absolute (positive sign) value of the expression. |
Arguments | value |
Example | .word abs(-2234) ; > ba 08 |
Name | acos |
Definition | The arc cosine of the expression. |
Arguments | value |
Example | .byte acos(1.0) ; > 00 |
Name | atan |
Definition | The arc tangent of the expression. |
Arguments | value |
Example | .byte atan(0.0) ; > 00 |
Name | cbrt |
Definition | The cubed root of the expression. |
Arguments | value |
Example | .long cbrt(2048383) ; > 7f 00 00 |
Name | ceil |
Definition | Round up expression. |
Arguments | value |
Example | .byte ceil(1.1) ; > 02 |
Name | cos |
Definition | The cosine of the expression. |
Arguments | value |
Example | .byte cos(0.0) ; > 01 |
Name | cosh |
Definition | The hyperbolic cosine of the expression. |
Arguments | value |
Example | .byte cosh(0.0) ; > 01 |
Name | deg |
Definition | Degrees from radians. |
Arguments | radian |
Example | .byte deg(1.0) ; > 39 |
Name | exp |
Definition | Exponential of e. |
Arguments | power |
Example | .dint exp(16.0) ; > 5e 97 87 00 |
Name | floor |
Definition | Round down expression. |
Arguments | value |
Example | .sbyte floor(-4.8) ; > fb |
Name | format |
Definition | Converts objects to a string in the format specified. The format string must adhere to Microsoft .Net standards. Please see the documentation on standard .Net format strings for more information. |
Arguments | value |
Example | .echo format("Program counter is ${0:x4}", *) |
Name | frac |
Definition | The fractional part. |
Arguments | value |
Example | .byte frac(5.18)*100 ; > 12 |
Name | hypot |
Definition | Polar distance. |
Arguments | pole1, pole2 |
Example | .byte hypot(4.0, 3.0) ; > 05 |
Name | ln |
Definition | Natural logarithm. |
Arguments | value |
Example | .byte ln(2048.0) ; > 07 |
Name | log10 |
Definition | Common logarithm. |
Arguments | value |
Example | .byte log($7fffff) ; > 06 |
Name | pow |
Definition | Exponentiation. |
Arguments | base, power |
Example | .lint pow(2,16) ; > 00 00 01 |
Name | rad |
Definition | Radians from degrees. |
Arguments | degree |
Example | .word rad(79999.9) ; > 74 05 |
Name | random |
Definition | Generate a random number within the specified range of numbers. Both arguments can be negative or positive, but the second argument must be greater than the first, and the difference between them can be no greater than the maximum value of a signed 32-bit integer. This is a .Net limitation. |
Arguments | range1, range2 |
Example |
.word random(251,255) ; generate a random # between ; 251 and 255. |
Name | round |
Definition | Round number. |
Arguments | value |
Example | .byte round(18.21) ; > 12 |
Name | sgn |
Definition | The sign of the expression, returned as -1 for negative, 1 for positive, and 0 for no sign. |
Arguments | value |
Example |
.sbyte sgn(-8.0), sgn(14.0), sgn(0) ;; > ff 01 00 |
Name | sin |
Definition | The sine of the expression. |
Arguments | value |
Example | .sbyte sin(1003.9) * 14 ; > f2 |
Name | sinh |
Definition | The hyperbolic sine of the expression. |
Arguments | value |
Example | .byte sinh(0.0) ; > f2 |
Name | sqrt |
Definition | The square root of the expression. |
Arguments | value |
Example | .byte sqrt(65536) - 1 ; > ff |
Name | str |
Definition | The expression as a text string. Only available for use with the string pseudo-ops. |
Arguments | value |
Example | .string str($c000) ; > 34 39 31 35 32 |
Name | tan |
Definition | The tangent the expression. |
Arguments | value |
Example | .byte tan(444.0)*5.0 ; > 08 |
Name | tanh |
Definition | The hyperbolic tangent the expression. |
Arguments | value |
Example | .byte tanh(0.0) ; > 00 |
6502.Net accepts several arguments, requiring at least one. If no option flag precedes the argument, it is considered an input file. Multiple input files can be assembled. If no output file is specified, source is assembled to a.out
within the current working directory. Below are the available option flags and their parameters. Mono users note for the examples you must put mono
in front of the executable.
Option | -o |
Alias | --output |
Definition | Output the assembly to the specified output file. A valid output filename is a required parameter. |
Parameter | filename |
Example |
6502.Net.exe myasm.asm -o myoutput 6502.Net.exe myasm.asm -output=myoutput |
Option | --arch |
Alias | None |
Definition | Specify the target architecture of the binary output. Four options are available. If architecture not specified, the default is cbm . The options:
|
Parameter | architecture |
Example |
6502.Net.exe myasm.asm -b --arch=flat flat.bin |
Option | -b |
Alias | --big-endian |
Definition | Assemble multi-byte values in big-endian order (highest order magnitude first). |
Parameter | None |
Example |
6502.Net.exe myasm.asm -b -o bigend.bin |
Option | -C |
Alias | --case-sensitive |
Definition | Set the assembly mode to case-sensitive. All tokens, including assembly mnemonics, directives, and symbols, are treated as case-sensitive. By default, 6502.Net is not case-sensitive. |
Parameter | None |
Example |
6502.Net.exe mycsasm.asm -C 6502.Net.exe mycsasm.asm --case-sensitive |
Option | --cpu |
Alias | None |
Definition | Direct the assembler to the given cpu target By default, 6502.Net targets only legal 6502 instructions. The following options are available:
|
Parameter | cpu |
Example |
6502.Net.exe myillegalasm.asm --cpu=6502i |
Option | -D |
Alias | --define |
Definition | Assign a global label a value. Note that within the source the label cannot be redefined again. The value can be any expression 6502.Net can evaluate at assembly time. If no value is given the default value is 1. |
Parameter | <label>=<value> |
Example |
6502.Net.exe -D chrout=$ffd2 myasm.asm -o myoutput |
Option | -h |
Alias | -?, --help |
Definition | Print all command-line options to console output. |
Parameter | None |
Example |
6502.Net.exe -h 6502.Net.exe --help |
Option | -q |
Alias | --quiet |
Definition | Assemble in quiet mode, with no messages sent to console output, including errors and warnings. |
Parameter | None |
Example |
6502.Net.exe -q myasm.asm 6502.Net.exe --quiet myasm.asm |
Option | -w |
Alias | --no-warn |
Definition | Suppress the display of all warnings. |
Parameter | None |
Example |
6502.Net.exe -w myasm.asm 6502.Net.exe --no-warn myasm.asm |
Option | --wnoleft |
Alias | None |
Definition | Suppress warnings for lines where whitespaces precede labels. |
Parameter | None |
Example |
6502.Net.exe --wnoleft myasm.asm |
Option | --werror |
Alias | None |
Definition | Treat all warnings as errors. |
Parameter | None |
Example |
6502.Net.exe --werror myasm.asm |
Option | -l |
Alias | --labels |
Definition | Dump all label definitions to listing. |
Parameter | filename |
Example |
6502.Net.exe myasm.asm -l labels.asm 6502.Net.exe myasm.asm --labels=labels.asm |
Option | -L |
Alias | --list |
Definition | Output the assembly listing to the specified file. |
Parameter | filename |
Example |
6502.Net.exe myasm.asm -L listing.asm 6502.Net.exe myasm.asm --list=listing.asm |
Option | -a |
Alias | --no-assembly |
Definition | Suppress assembled bytes from assembly listing. |
Parameter | None |
Example |
6502.Net.exe myasm.asm -a -L mylist.asm 6502.Net.exe myasm.asm --no-assembly --list=mylist.asm |
Option | -d |
Alias | --no-disassembly |
Definition | Suppress disassembly from assembly listing. |
Parameter | None |
Example |
6502.Net.exe myasm.asm -d -L mylist.asm 6502.Net.exe myasm.asm --no-disassembly --list=mylist.asm |
Option | -s |
Alias | --no-source |
Definition | Do not list original source in the assembly listing. |
Parameter | None |
Example |
6502.Net.exe myasm.asm -s -L mylist.asm 6502.Net.exe myasm.asm --no-source --list=mylist.asm |
Option | --verbose-asm |
Alias | None |
Definition | Make the assembly listing verbose. If the verbose option is set then all non-assembled lines are included, such as blocks and comment blocks. |
Parameter | None |
Example |
6502.Net.exe myasm.asm --verbose-asm -L myverboselist.asm |
Option | -V |
Alias | --version |
Definition | Print the current version of 6502.Net to console output. |
Parameter | None |
Example |
6502.Net.exe -V 6502.Net.exe --version |
Assertion Failed
- An assertion failed due to the condition evaluating as false.
Attempted to divide by zero.
- The expression attempted a division by zero.
Cannot redefine type to <type> because it is already a type
- The type definition is already a type.
Cannot resolve anonymous label
- The assembler cannot find the reference to the anonymous label.
Closure does not close a block
- A block closure is present but no block opening.
Closure does not close a macro
- A macro closure is present but no macro definition.
Closure does not close a segment
- A segment closure is present but no segment definition.
Could not process binary file
- The binary file could not be opened or processed.
Directive takes no arguments
- An argument is present for a pseudo-op or directive that takes no arguments.
Encoding is not a name or option
- The encoding selected is not a valid name.
error: invalid option
- An invalid option was passed to the command-line.
error: option requires a value
- An option was passed in the command-line that expected an argument that was not supplied.
<Feature> is depricated
- The instruction or feature is depricated (this is a warning by default).
File previously included. Possible circular reference?
- An input file was given in the command-line or a directive was issued to include a source file that was previously include.
Filename not specified
- A directive expected a filename that was not provided.
Format is invalid.
- The format string passed to format()
is not valid
General syntax error
- A general syntax error.
Illegal quantity
- The expression value is larger than the allowable size.
Invalid constant assignment
- The constant could not be assigned to the expression.
Invalid CPU specified
- An invalid CPU option was given at the command line or in the directive
Invalid parameter reference
- The macro reference does not reference a defined parameter.
Invalid Program Counter assignment
- An attempt was made to set the program counter to an invalid value.
Label is not the leftmost character
- The label is not the leftmost character in the line (this is a warning by default).
Macro or segment is being called recursively
- A macro or segment is being invoked in its own definition.
Macro parameter not specified
- The macro expected a parameter that was not specified.
Macro parameter reference must be a letter or digit
- The macro parameter was in an invalid format.
Missing closure for block
- A block does not have a closure.
Missing closure for macro
- The macro does not have a closure.
Missing closure for segment
- A segment does not have a closure.
Program Counter overflow
- The program counter overflowed passed the allowable limit.
Pstring size too large
- The P-String size is more than the maximum 255 bytes.
Quote string not enclosed
- The quote string was not enclosed.
Redefinition of label
- A label is redefined or being re-assigned to a new value, which is not allowed.
Redefinition of macro
- An attempt was made to redefine a macro.
<Symbol> is not a valid symbol name
- The label or variable has one or more invalid characters.
Symbol not found
- The expression referenced a symbol that was not defined.
Index (zero based) must be greater than or equal to zero and less than the size of the argument list.
- A format item in the format string passed to format()
does not match the parameter.
The current CPU supports only 8-bit immediate mode instructions. The directive will not affect assembly
- Attempted use of the 65816-specific directives (this is a warning by default).
Too few arguments for directive
- The assembler directive expected more arguments than were provided.
Too many arguments for directive
- More arguments were provided to the directive than expected.
Too many characters in character literal
- The character literal has too many characters.
Type is unknown or not redefinable
- An attempt was made to define an unknown or non-definable type.
Type name is a reserved symbol name
- A type definition failed because the definition is a reserved name.
Unable to find binary file
- A directive was given to include a binary file, but the binary file was not found, either due to filesystem error or file not found.
Unable to open source file
- A source file could not be opened, either due to filesystem error or file not found.
Unknown architecture specified
- An invalid or unknown parameter was supplied to the --arch
option in the command-line.
Unknown instruction or incorrect parameters for instruction
- An directive or instruction was encountered that was unknown, or the operand provided is incorrect.
Unknown or invalid expression
- There was an error evaluating the expression.