hardware developers moved to the 68000, and those looking for a more
powerful 8 bit could move to the 6809, there was 'another
alternative'.... The 65816
Backwards compatible with the 65C02, and with full 16 bit capabilities, the 65816 (AKA W65C816) gave the 'best of both worlds'... although 1/3 slower than the 68000 mhz for mhz, the 65816 was powerful and capable, and was the driving force behind the SNES and APPLE IIGS...
It's 24 bit address bus gives it the capability to address 16 megabytes - like the 68000
The 65802 is essentially a 65816 with an 8 bit address bus.
|If you want to learn 6809 get the Cheatsheet! it has all the 6809 commands, It will give you a quick reference when you're stuck or confused, which will probably happen a lot in the early days!|
using Macroassembler AS for our assembly in these tutorials... VASM is
an assembler which supports rarer CPU's like 6809 and 65816 and many
also supports multiple syntax schemes...
You can get the source and documentation for AS from the official website HERE
probably think 64 kilobytes doesn't sound much when a small game now
takes 8 gigabytes, but that's 'cos modern games are sloppy,
inefficient, fat and lazy - like the basement dwelling losers
who wrote them!!!
ASM code is small, fast, and super efficient - with ASM you can do things in 1k that will amaze you!
will use a symbol to denote a hexadecimal number, in 6502
programming $ is typically used to denote hex, and # is used to tell
the assembler to tell the assembler something is a number (rather than
an address), so $# is used to tell the assembler a value is a Hex number
In this tutorial VASM will be used for all assembly, if you use something else, your syntax may be different!
|Digit Value (D)||128||64||32||16||8||4||2||1|
|Our number (N)||1||1||0||0||1||1||0||0|
|D x N||128||64||0||0||8||4||0||0|
|128+64+8+4= 204 So %11001100 = 204 !|
|If you ever get confused, look
at Windows Calculator, Switch to
'Programmer Mode' and it has binary and Hexadecimal view, so
change numbers from one form to another!
If you're an Excel fan, Look up the functions DEC2BIN and DEC2HEX... Excel has all the commands to you need to convert one thing to the other!
|Equivalent Byte value||255||254||253||251||246||236||206||2||1|
|Equivalent Hex Byte Value||FF||FE||FD||FB||F6||EC||CE||2||1|
these number types can be confusing, but don't worry! Your Assembler
will do the work for you!
You can type %11111111 , &FF , 255 or -1 ... but the assembler knows these are all the same thing! Type whatever you prefer in your ode and the assembler will work out what that means and put the right data in the compiled code!
NVMXDIZC / -------E
ZeroPage (ZP) has been renamed to the Direct Page (DP) - but it's
basically the same thing - its just now that it doesn't need to be at
$00xx they felt the need to rename it!... any addressing modes you're
used to with the ZeroPage will work EXACLY the same now with DP... and
in these tutorials we'll keep the DP in the same memory location as the
ZeroPage was to keep things simple!
Maybe we should call it "The addressing mode formally known as ZeroPage" or something! (TAMFKAZ!!)
|Because VASM doesn't support 65816, we're going to have to use Macro-AS for assembly, unfortunately, there's a few differences!||VASM||Macro-AS|
|1. Symbol definitions must preceed first use
In Vasm an EQU statement could come after it's first use
|2. #>label and #<label do not work
use #label/256 and #label&255 instead
|3. Macro definitions are different|
|4. we have to tell Macro AS we're defaulting to 8 bit mode|
|Mode||Description||Syntax||Sample Command||Z80 Equivalent||effective result|
|Implied / Inherant||A command that needs no paprameters||SEC (set carry)||SCF|
|Relative||A command which uses the program counter PC with and offset nn (-128 to +127)||#$nn||BEQ [label] (branch if equal)||JR Z,[label]|
|Accumulator||A command which uses the Accumulator as the parameter||ROL (ROtate bits Left)||RLCA|
|Immediate||A command which takes a byte nn as a parameter||#$nn||ADC #1||ADC 1||&nn|
|Absolute||Take a parameter from a two byte memory address $nnnn||$nnnn||LDA $2000||LD a,(&2000)||(&nnnn)|
|Absolute Indexed||Take a parameter from a two byte memory address $nnnn+X (or Y)||$nnnn,X||LDA $2000,X||(&nnnn+X)|
|Direct Page||Take a parameter from the direct page address $00nn||$nn||ADC $32||(&00nn)|
|Direct Page Indexed||Takes a parameter from memory address $00nn+X||$nn,X||ADC $32,X||(&00nn+X)|
|Indirect||Take a parameter from pointer at address $nnnn...
if $nnnn contains $1234 the parameter would come from the address at $1234
|indirect DP||The 65c02 has an extra feature, where it can read from an unindexed Zero page||($nn)||((&00nn))|
|Pre Indexed (Indirect,X)||Take a paramenter from pointer at address $nnnn+X
if $nnnn contains $1234, and X contained 4 the parameter would come from the address at $1238
|Postindexed (Indirect),Y||Take pointer from address $nnnn, add Y... get the
parameter from the result
if $nnnn contains $1234, and Y contained 4, the address would be read from $1234... then 4 would be added... and the parameter would be read from ther resulting address
|Mode||Description||Syntax||Sample Command||effective result|
|Direct page Indirect||Read from the address in the Direct page||($nn)||LDA ($10)
|Absolute indexed indirect||read from a 16 bit address with an X offsetr||($nnnn,x)||JMP ($1000,X)||(($nnnn))|
|Mode||Description||Syntax||Sample Command||effective result|
|Program Counter Relative Long||$nnnn||BRL Label|
|Stack Relative||$nn,S||LDA 3,S|
|Stack Relative Indirect Indexed with Y||($nn,S),Y||LDA (3,S),Y|
|Block Move||src,dest||MVP 0,0|
|Absolute Long||$nnnnnn||LDA $020000||($nnnnnn)|
|Absolute Indirect Long||[$nnnnnn]||JMP [$020000]||(($nnnnnn))|
|Absolute Long Indexed with X||$nnnnnn,X||LDA $020000,X|
|Absolute Indirect Long||[$nnnn]||JMP [$2000]|
|Direct Page Indirect Long||[$nn]||LDA [$20]||($nn) [16 bit]|
|Direct Page Indirect Long Indexed with Y||[$nn],Y||LDA [$20],Y|
|The top few bytes of the first 64k contain addresess to the handlers
for interupts - these contain a 16 bit address for the interrupt
handler (menaing the handler must be in the first 64k of ram)
Some of the handlers work in 8 and 16 bit mode, others are exclusive to one mode or the other
|Enable (16 bit)||Disable (8 bit)|
|1. Disable emulation (Turning the CPU into 65816 mode)
This enables the extra addressing modes and allows access to the full memory range, and SP/DP relocation (you can still use XBA to get to the B accumulator)
We have to do this by setting the carry flag, and exchanging it with the E flag via XCE
|2. Enable the 16 bit Accumulator
All accumulator operations will now work in 16 bits... this is done by setting bit 6 of the processor flags to 0
We also need to use ASSUME to tell the assembler to start compiling 16 bit values for commands containing the Accumulator (So LDA #$00 will compile to LDA #$0000)
|3. Enable the 16 bit X and Y registers
X and Y registers will now work in 16 bits... this is done by setting bit 5 of the processor flags to 0...
Turning this off will LOSE the top byte of X and Y
Again, we need to tell the assembler with ASSUME
|2+3. Enable16 bit for all 3 registers together
We can set both bits to1 together.... we still need two ASSUME commands, but these don't compile to bytecode
|BSR subprogram||PSR retaddr