Take the following machine code for the 65c816 for the SNES (Super Nintendo):
00000000 ea ea 78 18 fb c2 18 a2 ff 1f 9a 20 fa 80 e2 20 |..x........ ... |
00000010 a9 80 8d 00 21 a9 e0 8d 22 21 a9 00 8d 22 21 a9 |....!..."!..."!.|
00000020 0f 8d 00 21 ea ea ea ea ea ea ea ea ea ea ea ea |...!............|
00000030 ea ea ea ea ea ea ea ea ea ea ea ea ea ea ea ea |................|
00000040 ea ea ea ea ea ea ea ea ea ea ea ea ea ea ea ea |................|
00000050 ea ea ea ea ea ea ea 4c 57 80 40 00 00 00 00 00 |.......LW.@.....|
00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000f0 00 00 00 00 00 00 00 00 00 40 e2 30 a9 8f 8d 00 |[email protected]....|
00000100 21 9c 01 21 9c 02 21 9c 03 21 9c 05 21 9c 06 21 |!..!..!..!..!..!|
00000110 9c 07 21 9c 08 21 9c 09 21 9c 0a 21 9c 0b 21 9c |..!..!..!..!..!.|
00000120 0c 21 9c 0d 21 9c 0d 21 a9 ff 8d 0e 21 8d 10 21 |.!..!..!....!..!|
00000130 8d 12 21 8d 14 21 a9 07 8d 0e 21 8d 10 21 8d 12 |..!..!....!..!..|
00000140 21 8d 14 21 9c 0f 21 9c 0f 21 9c 11 21 9c 11 21 |!..!..!..!..!..!|
00000150 9c 13 21 9c 13 21 a9 80 8d 15 21 9c 16 21 9c 17 |..!..!....!..!..|
00000160 21 9c 1a 21 9c 1b 21 a9 01 8d 1b 21 9c 1c 21 9c |!..!..!....!..!.|
00000170 1c 21 9c 1d 21 9c 1d 21 9c 1e 21 8d 1e 21 9c 1f |.!..!..!..!..!..|
00000180 21 9c 1f 21 9c 20 21 9c 20 21 9c 21 21 9c 23 21 |!..!. !. !.!!.#!|
00000190 9c 24 21 9c 25 21 9c 26 21 9c 27 21 9c 28 21 9c |.$!.%!.&!.'!.(!.|
000001a0 29 21 9c 2a 21 9c 2b 21 8d 2c 21 9c 2d 21 9c 2e |)!.*!.+!.,!.-!..|
000001b0 21 9c 2f 21 a9 30 8d 30 21 9c 31 21 a9 e0 8d 32 |!./!.0.0!.1!...2|
000001c0 21 9c 33 21 9c 00 42 a9 ff 8d 01 42 9c 02 42 9c |!.3!..B....B..B.|
000001d0 03 42 9c 04 42 9c 05 42 9c 06 42 9c 07 42 9c 08 |.B..B..B..B..B..|
000001e0 42 9c 09 42 9c 0a 42 9c 0b 42 9c 0c 42 9c 0d 42 |B..B..B..B..B..B|
000001f0 58 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |X`..............|
This is almost verbatim the assembled source from https://en.wikibooks.org/wiki/Super_NES_Programming/Initialization_Tutorial The only difference is some NOP instructions inserted at various places to make it more readable to myself.
I'm trying to write an emulator and I'm working on the JSR instruction at the moment.
From http://www.6502.org/tutorials/65c816opcodes.html#6.2.2.1 this is what I have:
"JSR pushes the 16-bit address (i.e. the program counter) of the JSR instruction plus 2 onto the stack, and jumps to an address within the current program bank. In other words, the address pushed is one less than the address of the next instruction. The high byte is pushed first, then the low byte is pushed."
So this is fine. The problem is this. Look at this line:
00000000 ea ea 78 18 fb c2 18 a2 ff 1f 9a 20 fa 80 e2 20 |..x........ ... |
0x20 is the opcode for JSR. It takes a two byte argument, i.e. 0xfa and 0x80 (little endian), so it basically jumps to the absolute address 0x80fa within bank 0 and pushes the return address for the next instruction (the one after the JSR and its operand) onto the stack.
However, from looking at the source code, I know that the JSR should jump to somewhere here:
000000f0 00 00 00 00 00 00 00 00 00 40 e2 30 a9 8f 8d 00 |[email protected]....|
This can be seen from this excerpt of the source:
.MACRO Snes_Init
sei ; Disabled interrupts
clc ; clear carry to switch to native mode
xce ; Xchange carry & emulation bit. native mode
rep #$18 ; Binary mode (decimal mode off), X/Y 16 bit
ldx #$1FFF ; set stack to $1FFF
txs
jsr Init
.ENDM
.bank 0
.section "Snes_Init" SEMIFREE
Init:
nop
sep #$30 ; X,Y,A are 8 bit numbers
nop
lda #$8F ; screen off, full brightness
sta $2100 ; brightness + screen enable register
stz $2101 ; Sprite register (size + address in VRAM)
stz $2102 ; Sprite registers (address of sprite memory [OAM])
stz $2103 ; "" ""
...
From this it makes sense to me that the target address should be 0x00fa (within bank 0), not 0x80fa (within bank 0).
Address 0x80fa seems to be part of the ROM, but at this address there is nothing, only null bytes.
Why is the machine code for "jsr Init" assembled to "20 fa 80"? I know this is little endian, again my question is why the operand address doesn't make sense.
I can only assume I'm missing some fundamentals about how the 65c816 works, overlook something obvious, or that the address is relative to some other address. But the RESET vector in this particular case is 0, so I'm not getting what it should be relative to.
As a bonus question:
Why is there a 0x40 (an RTI opcode, I believe) before the first nop at the Init: label?
More information:
The assembled and linked ROM runs fine in well-known emulators, there is nothing wrong with the assembled machine code itself. It was assembled using "WLA 65816 Macro Assembler v9.8a", if it matters.