SNES DevelopmentI trust that you have learned some other kind of assembly language. If you have not, I’m afraid that learning 65816 as your first assembly language may be extremely hard. However, I won’t stop you from trying. You will need other 65816 documents, because I do not teach much in this tutorial. These tutorials are for teaching you how to use 65816 with the SNES, so I’m trying to write the main material first. Maybe later I’ll really expand this part and make it full. But really, the 65816 documents I linked you to earlier teach everything, so it would be really redundant for me to write a 65816 tutorial. However, if I receive feedback asking for one, I will make an effort. Ok, let’s begin.
It’s the same as NES if you have coded NES before. In previous ASM languages you may have written in, you may have used $10 or 10h to say that the number is in hex, and [$10] to say that it’s a hex address. Well it’s a little different for the SNES. To use an immediate value (not an address, just a number), you place a # before the number. #16 = 16 decimal number. To use an immediate hex value, use #$. #$10 = 10 hex, or 16 decimal. To use an immediate binary value, use #%. #%00000011 = 3 decimal. To say the number is an address, use $. $2000 for example… We basically took out the #, which meant it was an immediate value. See? That’s that!
To alter bits in the Processor Status Register, simply use the opcodes SEP #xx or REP #xx. SEP sets bits (makes the bits 1) and REP resets bits (makes the bits 0). Assuming you read section 3.01 of the 65816 Primer, let’s go and make the accumulator 8 bits and the XY registers 16 bits in size.
rep #$10
sep #$20
I could also write (for visual simplicity)
rep #%00010000
sep #%00100000
nvMXdizc - these are simply helpful abbreviations of bits 0-7 of the Processor Status Register. See how we REP’d and SEP’d the P register to set A to 8 bits, and X/Y to 16 bits? Resetting the M or X bits (of nvmxdizc) makes the register(s) 16 bits, setting the bit makes it 8 bits.
This is another crappy listing, simply because the docs already out there are already enough to get you going. Nonetheless, here is a brief and crappy intro. There are many ways to use most opcodes, so I will only list a couple basic methods. I encourage you to look in Appendix A of the 65816 Primer for more addressing modes of each opcode. Appendix A tells you everything for almost every opcode, so be sure to check it out.
Notes: I’ve taken the syntax conventions from 65816 Primer for simplicity:
addr 2 byte address
const 1 or 2 byte constant (immediate number)
label label of code in same 64K bank as instruction
nearlabel label of code close enough to instruction to be reachable by a one-byte signed offset (-127/+127).
long 3-byte address (includes bank byte)
LDA : Load Accumulator with memory Usage:
LDA #const
LDA addr
LDA long
LDA addr,X
...- You will be using this a LOT to load values and values at addresses.
LDX, LDY - Same as above, but for X/Y.
Also, addressing modes are more limited when using X/Y. See the primer.
STA : Store A into memory Usage:
STA addr
STA long
STA addr,X
STA addr,Y
...- You will be using this a LOT to store values in A into addresses.
STY, STX - Same as Above, but for X/Y.
Also, addressing modes are more limited when using X/Y. See the primer.
STZ : Store zero byte to memory Usage:
STZ addr
STZ addr,X
...
- A good replacement for:
lda #$00
sta $xxxx
CLC : Clear Carry Flag
clc before adc
SEC : Set Carry Flag
sec before sbc>
ADC : Add with carry Usage:
ADC #const
ADC addr
ADC long
ADC addr,X
...- You should CLC before ADC'ing.
- Carry flag set if overflow.
SBC : Subtract with carry Usage:
SBC #const
SBC addr
SBC long
SBC addr,X
...- You should SEC before SBC-ing.
- Set if unsigned borrow not required.
Well that is enough for now don’t you agree?? Again please look at the primer and other CPU docs for some real opcode info.
Tutorial by bazz