6502 code assembler (6502ca)
TRANSCRIPT
6502 Code Assembler
(6502CA) Version 1.3.5
Written by M.Davies
Table of Contents Overview ........................................................................................................................................... 3
Editor ................................................................................................................................................ 4
Command-line Switches & Parameters .............................................................................................. 5
Labels & Variables ............................................................................................................................. 6
Variables (Symbols) ....................................................................................................................... 6
Labels ............................................................................................................................................ 7
Using a variable ............................................................................................................................. 8
Restrictions ................................................................................................................................... 9
Number types & Maths ................................................................................................................... 10
Number Types ............................................................................................................................. 10
Maths & Calculations ................................................................................................................... 11
Order of operator precedence ................................................................................................. 12
Macros ............................................................................................................................................ 13
Assembler Commands ..................................................................................................................... 16
Assert .......................................................................................................................................... 16
Include ........................................................................................................................................ 16
IncludeRoot ................................................................................................................................. 16
Import ......................................................................................................................................... 17
Fill ............................................................................................................................................... 17
Copy ............................................................................................................................................ 18
End .............................................................................................................................................. 18
SetMacro and ! ............................................................................................................................ 18
Overview
6502 Code Assembler (6502ca for short) is a 6502 code cross-assembler for Microsoft Windows.
It's primarily designed to be useful for those who wish to create their own "home brew" single-board
computers based on the 65c02 processor, but can be used to write application code to work in
assemblers or even old hardware.
Current Capabilities
Assemble all 6502 & WDC 65c02 instructions (complete)
All 6502 & WDC 65c02 addressing modes available (complete)
Support for data-type commands: String, Byte, Word (2 bytes), Double Word (4 bytes)
Labels & variables (both are treated the same)
Macros for repeating code easily
Ability to "Include" other source files so you can sub-divide source code into different files
Simple math supported on assemble: Add, Subtract, Multiply, Divide (integer and decimal), Mod
(remainder), OR, AND, XOR (EOR)
Command-line switches available to allow the following:
Save only a section of memory rather than the entire 64KB upon completion
Automatically overwrite existing binary file
Assemble (list in display), but do not save the resulting binary file
Pause at the end of assembly, but before 6502ca ends
Show variables, opcodes and macros created during the assembly process
Pipe the listing to a file (by default this goes to the display)
Multiple installation methods: Manual install, Single computer install, Mass deployment (GPO
deployable msi)
Command-line switches available for silent install
Editor
6502 Code Assembler is command-line based program and so does not come with a built-in editor.
As such, you need to use a text editor such as Notepad, Notepad++, etc.. Be sure to use an editor
that saves in basic text (ANSI).
My recommendation is to use Notepad++ as it has many capabilities and you can use the 6502CA
language extension which I’ve written. That can be downloaded from
https://6502ca.net/index.php?Editor
Installation instructions:
• Open notepad++
• Click the Language drop down menu
• Click User Defined Language
• Click Define Your Language
• Click Import
• Select the unzipped notepadplusplus_6502ca.xml file
• Close notepad++ and then reopen it
• Click the Language drop down menu
• Click User Defined Language
• Click 6502ca
When you save a file with the .6502ca file extension it will apply colour codes to your source code.
Here’s an example of the colour coding once the 6502CA language extension is installed:
Command-line Switches & Parameters
6502 Code Assembler supports a number of useful command-line switches. A list can be obtained by
typing ‘6502ca /?’ in a Command Prompt or PowerShell window once 6502ca is installed.
Syntax:
6502ca <source file> (options – see below)
Switch/parameter Description <source file> File which contains the 6502/65C02 source code to be assembled /o= Specify the output binary (object) code filename. If not specified then <source file> with an extension of .bin is assumed. Examples: /o=myfile.bin /overwrite= If the binary output file already exists then automatically overwrite or not
without asking Examples: /overwrite=y /overwrite=n /nobinary Do not attempt to output the binary file /debug Wait for a key to be pressed just before exiting after all operations have been
completed /range= Set the memory range (in hex, but without hex symbols) to be outputted to
the binary file Example: /range=3000-4000 /ver Show program version /console= Send the console (display) output to a file instead of the console window Example: /console=myoutput.txt /showvars At the completion of assembly show the value of all variables & labels /showopcodes Displays the opcodes file. All other switches are ignored. /showmacros At the completion of assembly show any macros declared and what they are
set to
Example usages:
6502ca mysrc
Assemble the source file mysrc.6502ca and output the binary file to mysrc.bin
6502ca mysrc.txt
Assemble the source file mysrc.txt and output the binary file to mysrc.bin
6502ca mysrc /o=obj.bin
Assemble the source file mysrc.6502ca and output the binary to obj.bin
6502ca mysrc /range=4000-4fff /console=mysrcout.txt
Assemble the source file mysrc.6502ca and output the binary to mysrc.bin, but only
6502 memory range $4000 to $4fff resulting in a mysrc.bin being a 4096 byte file.
The console output (the assembly listing) will be sent to the mysrcout.txt file and not
displayed.
Labels & Variables
Variables (Symbols)
6502ca supports up to 4000 variables (actually, these are symbols rather than variables, but I
refer to them as variables... because I wish to :) ).
Assigning (or re-assigning) a variable
To create a new variable simply type the name, put an equals sign and then the value. The
same as most other programming languages
Examples: OSroutineAddress = $4000
HelpCommand = "HELP"
To reassign the variable to a different value you just do the same.
Example: MyTestValue = 45
MyTestValue = Hello World
All variables, including numbers, are stored as strings. When the assembler encounters one
during assembly, it simply swaps the variable name for what the variable is set to.
Example: mydata = 65
LDA #mydata
Would convert to the follow and then be assembled in machine code: mydata = 65
LDA #65
When assigning a string, leading spaces between the ‘=’ sign and the value are removed as
are trailing spaces. If you need to include either category then encompass the string in a pair
of double quotes.
Example: Mydata = Hello World
Would result in mydata being set to ‘Hello World’
Mydata = " Hello World "
Would result in mydata being set to ‘ Hello World ’
To include a double quote and it be counted as part of the string, put two double quotes.
These will be treated as a single double quote.
Example:
Labels
Labels are actually variables, but are set by either putting a full stop (a period for those in the
U.S.) and then the label name -or- putting the label name then a colon. This will cause a
variable to be created (or have its value reassigned if it already exists) and the value set to the
current assembly address.
Example:
pc = $5000 ; you can use .org $5000 instead
LDX #10
.loop
INX
BNE loop
Would result in:
LDX #10 being assembled at $5000 & $5001
A label called "loop" being created and assigned the value of $5002
INX being assembled at $5002
BNE being assembled at $5003 & $5003, with the value in $5003 being an offset pointing to
the value of "loop" which, when calculated, points to $5002
Example:
pc = $5000 ; you can use .org $5000 instead
LDX #10
loop:
INX
BNE loop
Would result in:
LDX #10 being assembled at $5000 & $5001
A label called "loop" being created and assigned the value of $5002
INX being assembled at $5002
BNE being assembled at $5003 & $5003, with the value in $5003 being an offset pointing to
the value of "loop" which, when calculated, points to $5002
Using a variable
This works in the same way as any other language or script. Simply assign the variable (or
label) and then refer to it in another statement
Examples:
HW=Hello world
pc=$4000 ; you can use .org $4000 instead
EQUS HW
ALUE=42
pc=$4000 ; you can use .org $4000 instead
LDX #ALUE
A=5
B=10
C=2
pc=$4000 ; you can use .org $4000 instead
LDY #A+B*C ; this calculates as 5+(10*2) = 5+20 = 25
pc=$4000 ; you can use .org $4000 instead
temp = $e00
LDA age
STA temp
RTS
pc=$A01E ; you can use .org $A01E instead
.age
EQUB 21
Restrictions
Variable names must not contain any special character. These include:
! " # $ % ' ( ) * + , - . / : ; < = > ? @ \ ^
Variables may also not be named the same as any 6502 instruction (mnemonic) or assemble
reserved command.
Number types & Maths
Number Types
Three number types are supported: Decimal, Hexadecimal, Binary.
Hexadecimal numbers are, by default, designated by $, but can be set to & by using the
ASSERT command.
Examples:
x = $D0
JMP $4000
EQUW $A97F
ASSERT &
LDA #&7A
ASSERT $
LDA #$7B
Binary numbers are designated by %, with the most significant bit on the left and the least
significant bit on the right.
Examples:
index = %1001
LDA #%11000100
STX %100010
JMP %1011110000011100
The above is the equivalent of:
index = 9
LDA #196
STX 34
JMP 48156
Maths & Calculations
The following basic calculation & bitwise operators are available:
Action Symbol Example(s)
Multiply * x = 77 * 9 (would result in 693)
Divide (decimal) / d = 221 / 128 (would result in 1.7265625)
Divide (integer) \ d = 221 \ 128 (would result in 1)
Mod (remainder) mod r = 221 mod 128 (would result in 93)
Add + a = 23 + 99 (would result in 122)
Subtract - s = 23 - 99 (would result in -76)
Bitwise OR || o = 55 || 99 (would result in 119)
Bitwise AND && a = 55 && 99 (would result in 35)
Bitwise XOR (EOR) ~ x = 55 ~ 99 (would result in 84)
Calculations can be used anywhere, in any combination, and with a mixture of numbers and
variables.
Here are some further examples:
...would result in : LDA #16 adj = $100
STX $8000 + adj
...would result in : STX $8100
mycalc = 77 && 88
...would result in : mycalc = 72
divresult = 192 \ 128
remresult = 192 MOD 128
...would result in : divresult = 1 and remresult = 64 (There is one 128 in 192 and the
remainder is 64 after that)
divresult = 192 / 128
...would result in : divresult = 1.5 (decimal divide)
varA = 100
varB = 77
VarC = 10
JMP $1000 + VarA + VarB * VarC
...would result in : JMP $1366 (see order of operator precedence below as to why it's $1366
rather than $10B10)
Order of operator precedence Calculations within a given source code line are done as follows with the upper most ones done first: Multiplication
Division (decimal) Division (integer) Remainder (mod) Addition Subtraction Bitwise OR Bitwise AND Bitwise XOR
Example:
result = 99 + 5 * 10 / 4
EQUS result
...would result in:
99 + ((5 * 10) / 4)
= 99 + (50 / 4)
= 99 + 12.5
= 111.5
And would assemble as:
EQUS "111.5"
Macros
6502CA has a basic macro system which allows you to easily repeat code sections without
having to type them each time in your source code. All you need to do is declare the section
of code using the #setmacro reserved assembler command and then call the code with the ‘!’
command whenever you wish to repeat the code.
The system has a limit of 500 macros with 20 commands & 10 parameters per macro.
Syntax:
SetMacro <macro name> = <command>(@n)( | <command>(@n) | … )
!<command> (<parameter 1> (A<parameter 2> … ))
Example code:
; main code
#setmacro stacksave = PHA | PHX | PHY | PHP
#setmacro stackrestore = PLP | PLY | PLX | PLA
(some commands)
JSR mysubroutine
(more commands)
JSR anothersubroutine
RTS
; sub routines to do some stuff - each saves the
; registers & flags at the beginning and restores them
; afterwards
mysubroutine:
!stacksave
(commands)
!stackrestore
RTS
anothersubroutine:
!stacksave
(commands)
!stackrestore
RTS
Note that the above doesn't JSR, BRA or JMP to the macro commands; The assembler inserts
the commands to be assembled from the given macro as if they'd been typed in instead of the
! command.
Example:
#setmacro test=INX | LDA data,X
!test
INY
!test
...would assemble as:
INX
LDA data,X
INY
INX
LDA data,X
A feature of the macro system is the ability to pass parameters using the @ symbol. This
allows data to be supplied to the macro system when calling a given macro. Parameters are
declared within the #setmacro command by putting @ followed by a number between 0 and
9 representing the parameter number. When the ‘!’ command is used the parameters are then
listed after the macro name, ordered 0 to 9 separated by a pipe '|' character .
Example:
#setmacro test=LDA @0 | STA @1
LDX #0
!test #$7A | $900
!test #$23 | $901
RTS
...would assemble as:
LDX #0
LDA #$7A
STA $900
LDA #$23
STA $901
RTS
Note: Neither macro command is processed at all for variable names or maths. Such
processing is done on the commands inserted by the ‘!’ command.
Some useful macros:
bit0 = 1
bit1 = 2
bit2 = 4
bit3 = 8
bit4 = 16
bit5 = 32
bit6 = 64
bit7 = 128
#setmacro setbit = ORA @0
#setmacro flipbit = AND @0 ~ $FF
#setmacro clearbit = AND @0 && $FF
Some examples of how to use the above:
LDA #2
!setbit #4
Load 2 in to the A register (binary : 0000 0010)
Set bit 2 (which represents the value 4) of the A register (bit 2 in binary : 0000 0100)
Which results in A being 6 (binary : 0000 0110)
LDA #6
!clearbit #4
Load 6 in to the A register (binary : 0000 0110)
Clear bit 2 (which represents the value 4) of the A register (bit 2 in binary : 0000 0100)
Which results in A being 2 (binary : 0000 0010)
LDA #255
!flipbit #bit6
!flipbit #bit6
Load 255 in to the A register (binary : 1111 1111)
Flip bit 6 (which represents the value 64) of the A register to 0 (bit 6 in binary : 0100 0000)
Which results in A being 191 (binary : 1011 1111)
Flip bit 6 of the A register back to 1
Which results in A being 255 again (binary : 1111 1111)
Notice with that last example we used the variable 'bit6'. That variable is set to 64 which is
the value of bit 6. We could have used the number '64' instead of 'bit6' in the ! command, but
'bit6' more easily tells whoever is viewing the code that you're referring to bit 6.
Nesting Macros:
Macros can be nested to a depth of 20, allowing one macro to call another and that to call yet
another, and so on. The only restrictions are the nest (depth) limit of 20 and that a macro (or
any macros it calls) cannot call itself as this would cause a loop.
Example:
#setmacro LCD_E_set = LDA LCD_E_PORT | ORA #LCD_E | STA LCD_E_PORT
#setmacro LCD_RS_set = LDA LCD_RS_PORT | ORA #LCD_RS | STA LCD_RS_PORT
#setmacro LCD_RW_set = LDA LCD_RW_PORT | ORA #LCD_RW | STA LCD_RW_PORT
#setmacro LCD_CheckBusy = !LCD_E_set | !LCD_RS_set | !LCD_RW_set
Assembler Commands
The assembler has a number of built-in reserved commands. Apart from the '!' command, all
others need to start with a '#'.
Assert
The Assert command is used to control which character is used ot prefix hexadecimal value.
It's restricted to & and $. By default, 6502CA assumes $.
Syntax:
#ASSERT <character>
Examples:
#ASSERT &
#ASSERT $
Include The Include command is used to insert the source code from other files. This allows you to split a project into different files and allows for easier. The filename parameter can, optionally, be encased in double quotes if it contains spaces, otherwise only the first word will be used.
Syntax:
#INCLUDE <filename>
Examples: #INCLUDE "LCD routines.6502ca"
#INCLUDE SerialComms.6502ca
IncludeRoot The RootInclude command is used to set the path where a project’s include files are located. The path specified is prepended to the filename in any Include commands. The path parameter can, optionally, be encased in double quotes if it contains spaces, otherwise only the first word will be used. If '\' is not included at the end of path then one is added automatically.
Syntax:
#INCLUDEROOT <path>
Examples:
#INCLUDEROOT "c:\myproject\my includes\"
#INCLUDEROOT \\mynas\common_includes
Import The Import command instructs the assembler to import a binary file into the 6502 memory map at assembly time. You can optionally specify where in the imported file to start importing to (starting byte is address 0) and you can also specify the end byte. This allows a section of a file to be imported if desired.
Syntax:
#IMPORT <filename> <import address>
#IMPORT <filename> <import address> <file from-address>
#IMPORT <filename> <import address> <file from-address> TO <file to-address>
Examples: #IMPORT "memory-map-template.bin" $0
#IMPORT "RAMmap.bin" $3000 $1000
#IMPORT "RAMmap.bin" $3000 $1000 TO $9fff
Fill
Fill allows you to fill a section of 6502 RAM with a repeated series of bytes or a repeated
string. For s string with spaces, you will need to encase it with double quotes otherwise only
the first word will be used.
When the fill routine hits <address end> it will cease filling, even if the series of byte / string
is not been completed.
Syntax:
#FILL <address start> <address end> BYTE <byte> (<byte>) (<byte>) (<byte>) ...
#FILL <address start> <address end> STRING <string>
Examples:
#FILL $1000 $1FFF BYTE $ea
#FILL $1000 $1FFF BYTE 65 66 67
#FILL $1000 $1FFF STRING "Hello!"
Copy
Copy allows you to copy one section of 6502 RAM to another section of 6502 RAM.
Syntax:
#COPY <source address start> <source address end> TO <destination address>
Examples:
#COPY $1000 $1FFF TO $8000
#COPY $4000 $6FFF TO $A000
End
The End command causes the assembler to treat the command as the end of the source file,
ignoring any further source code beyond that point. The assembler will then process any
remaining passes (up to this command).
Syntax:
#END
SetMacro and !
Please see the Macro section for these command.