Last Update: 2010/11/01 22:33 +0900
S (stack pointer) register always points new address you can write by PH? opecodes.
Return address points next CPU instruction.
Just "d" + "s".
Name | Size | Short for ... |
---|---|---|
A | 16 or 8 | Accum |
DB | 8 | Data bank |
X | 16 or 8 | X index |
Y | 16 or 8 | Y index |
D | 16 | Direct |
S | 16 | Stack |
P | 8 | Processor status |
PB | 8 | Program bank |
PC | 16 | Program counter |
"The Status Flags" section is useful. SNES Assembly Tutorial (Written By MarcTheMER) http://snescentral.edgeemu.com/Development/Tutorials/01asm.htm | |
Size of "A" register is affected by "bit 5: Memory/Accumlator size" of processor status. | |
Size of "X" and "Y" registers is affected by "bit 4: X/Y Register size" of processor status. |
Op | Name | Op. size | |
---|---|---|---|
4C |
JMP a |
3 | |
6C |
JMP(a) |
3 | |
7C |
JMP(a,x) |
3 | |
5C |
JMP al |
4 | |
80 |
BRA r |
2 | |
82 |
BRL rl |
3 | |
90 |
BCC r |
2 | |
B0 |
BCS r |
2 | |
F0 |
BEQ r |
2 | |
D0 |
BNE r |
2 | |
30 |
BMI r |
2 | |
10 |
BPL r |
2 | |
70 |
BVS r |
2 | |
50 |
BVC r |
2 | |
20 |
JSR a |
3 | |
FC |
JSR(a,x) |
3 | |
60 |
RTS s |
1 | |
22 |
JSL al |
4 | |
6B |
RTL s |
1 | |
40 |
RTI s |
1 |
See also "Table 8. Opcode Matrix" (opcodes.txt) "65816 docs" at http://www.zophar.net/tech/65816.html | |
Size of jump/call opecodes is NOT affected by processor status register. |
MVN: 54 yy xx
MVP: 44 yy xx
[xx:x] → [yy:y]
x+1 → x
y+1 → y
...
$00/98BF 54 3F 7E MVN 3F 7E A:0003 X:2000 Y:8000 D:0000 DB:7E S:1FCA P:envmxdIzcHC:1008 VC:070 00 FL:65503 $00/98BF 54 3F 7E MVN 3F 7E A:0002 X:2001 Y:8001 D:0000 DB:3F S:1FCA P:envmxdIzcHC:1060 VC:070 00 FL:65503 $00/98BF 54 3F 7E MVN 3F 7E A:0001 X:2002 Y:8002 D:0000 DB:3F S:1FCA P:envmxdIzcHC:1112 VC:070 00 FL:65503 $00/98BF 54 3F 7E MVN 3F 7E A:0000 X:2003 Y:8003 D:0000 DB:3F S:1FCA P:envmxdIzcHC:1164 VC:070 00 FL:65503 $00/98C2 86 10 STX $10 [$00:0010] A:FFFF X:2004 Y:8004 D:0000 DB:3F S:1FCA P:envmxdIzcHC:1216 VC:070 00 FL:65503
A → 0003 [7E:2000] → [3F:8000], X=2001, Y=8001, A → 0002 [7E:2001] → [3F:8001], X=2002, Y=8002, A → 0001 [7E:2002] → [3F:8002], X=2003, Y=8003, A → 0000 [7E:2003] → [3F:8003], X=2004, Y=8004, A → FFFF
Conversion from 7E:2000 ~ 7E:49FF
$00/98B1 8F 00 80 3F STA $3F8000[$3F:8000] A:0001 X:4A00 Y:0004 D:0000 DB:7E S:1FCA P:envMxdIzcHC:0100 VC:074 00 FL:65503 $00/98B5 C2 20 REP #$20 A:0001 X:4A00 Y:0004 D:0000 DB:7E S:1FCA P:envMxdIzcHC:0140 VC:074 00 FL:65503 $00/98B7 A6 10 LDX $10 [$00:0010] A:0001 X:4A00 Y:0004 D:0000 DB:7E S:1FCA P:envmxdIzcHC:0162 VC:074 00 FL:65503 $00/98B9 A0 00 80 LDY #$8000 A:0001 X:2000 Y:0004 D:0000 DB:7E S:1FCA P:envmxdIzcHC:0194 VC:074 00 FL:65503 $00/98BC A9 03 00 LDA #$0003 A:0001 X:2000 Y:8000 D:0000 DB:7E S:1FCA P:eNvmxdIzcHC:0218 VC:074 00 FL:65503 $00/98BF 54 3F 7E MVN 3F 7E A:0003 X:2000 Y:8000 D:0000 DB:7E S:1FCA P:envmxdIzcHC:0242 VC:074 00 FL:65503 $00/98BF 54 3F 7E MVN 3F 7E A:0002 X:2001 Y:8001 D:0000 DB:3F S:1FCA P:envmxdIzcHC:0294 VC:074 00 FL:65503 $00/98BF 54 3F 7E MVN 3F 7E A:0001 X:2002 Y:8002 D:0000 DB:3F S:1FCA P:envmxdIzcHC:0346 VC:074 00 FL:65503 $00/98BF 54 3F 7E MVN 3F 7E A:0000 X:2003 Y:8003 D:0000 DB:3F S:1FCA P:envmxdIzcHC:0398 VC:074 00 FL:65503
$00/990E 69 50 00 ADC #$0050 A:49AC X:49AC Y:801C D:0000 DB:3F S:1FCA P:envmxdIzcHC:0432 VC:153 00 FL:65503 $00/9911 AA TAX A:49FC X:49AC Y:801C D:0000 DB:3F S:1FCA P:envmxdIzcHC:0456 VC:153 00 FL:65503 $00/9912 A9 03 00 LDA #$0003 A:49FC X:49FC Y:801C D:0000 DB:3F S:1FCA P:envmxdIzcHC:0470 VC:153 00 FL:65503 $00/9915 54 3F 7E MVN 3F 7E A:0003 X:49FC Y:801C D:0000 DB:3F S:1FCA P:envmxdIzcHC:0494 VC:153 00 FL:65503 $00/9915 54 3F 7E MVN 3F 7E A:0002 X:49FD Y:801D D:0000 DB:3F S:1FCA P:envmxdIzcHC:0546 VC:153 00 FL:65503 $00/9915 54 3F 7E MVN 3F 7E A:0001 X:49FE Y:801E D:0000 DB:3F S:1FCA P:envmxdIzcHC:0598 VC:153 00 FL:65503 $00/9915 54 3F 7E MVN 3F 7E A:0000 X:49FF Y:801F D:0000 DB:3F S:1FCA P:envmxdIzcHC:0650 VC:153 00 FL:65503
x register points the range from 2000 to 49FF.
Usually high level procedure entrance/exit can be used to realize a procedure function of C language. Here is an example found in Dungeon Master SNES ver.
Entrance of procedure _03_a2de:
|03/A2DE| 30|0B |PHD … PHD Push Direct Register on Stack |03/A2DF| 30|3B |TSC … TSC* Transfer Stack Pointer Register to Accumulator |03/A2E0| 30|38 |SEC … SEC Set Carry Flag |03/A2E1| 30|E9 F3 00 |SBC #$00F3 … SBC Subtract Memory from Accumulator with Borrow |03/A2E4| 30|5B |TCD … TCD* Transfer Accumulator to Direct Register |03/A2E5| 30|69 EC 00 |ADC #$00EC … ADC Add Memory to Accumulator with Carry |03/A2E8| 30|1B |TCS … TCS* Transfer Accumulator to Stack Pointer Register
Entrance run example:
$03/A2DE 0B PHD A:C5A2 X:0009 Y:0004 D:1ED1 DB:7E S:1FA5 P:eNvmxdIzCHC:0310 VC:036 00 FL:00
$03/A2DF 3B TSC A:C5A2 X:0009 Y:0004 D:1ED1 DB:7E S:1FA3 P:eNvmxdIzCHC:0348 VC:036 00 FL:00
$03/A2E0 38 SEC A:1FA3 X:0009 Y:0004 D:1ED1 DB:7E S:1FA3 P:envmxdIzCHC:0370 VC:036 00 FL:00
$03/A2E1 E9 F3 00 SBC #$00F3 A:1FA3 X:0009 Y:0004 D:1ED1 DB:7E S:1FA3 P:envmxdIzCHC:0392 VC:036 00 FL:00
$03/A2E4 5B TCD A:1EB0 X:0009 Y:0004 D:1ED1 DB:7E S:1FA3 P:envmxdIzCHC:0424 VC:036 00 FL:00
$03/A2E5 69 EC 00 ADC #$00EC A:1EB0 X:0009 Y:0004 D:1EB0 DB:7E S:1FA3 P:envmxdIzCHC:0446 VC:036 00 FL:00
$03/A2E8 1B TCS A:1F9D X:0009 Y:0004 D:1EB0 DB:7E S:1FA3 P:envmxdIzcHC:0478 VC:036 00 FL:00
$03/A2E9 A0 04 00 LDY #$0004 A:1F9D X:0009 Y:0004 D:1EB0 DB:7E S:1F9D P:envmxdIzcHC:0500 VC:036 00 FL:00
Exit of procedure _03_a2de:
|03/A330| 30|3B |TSC … TSC* Transfer Stack Pointer Register to Accumulator |03/A331| 30|18 |CLC … CLC Clear Carry Flag |03/A332| 30|69 06 00 |ADC #$0006 … ADC Add Memory to Accumulator with Carry |03/A335| 30|1B |TCS … TCS* Transfer Accumulator to Stack Pointer Register |03/A336| 30|2B |PLD … PLD Pull Direct Register from Stack |03/A337| 30|6B |RTL … RTL Return from Subroutine Long
Exit run example:
$03/A330 3B TSC A:1F82 X:002F Y:1F82 D:1EB0 DB:7E S:1F9D P:envmxdIzcHC:1194 VC:203 00 FL:00
$03/A331 18 CLC A:1F9D X:002F Y:1F82 D:1EB0 DB:7E S:1F9D P:envmxdIzcHC:1216 VC:203 00 FL:00
$03/A332 69 06 00 ADC #$0006 A:1F9D X:002F Y:1F82 D:1EB0 DB:7E S:1F9D P:envmxdIzcHC:1238 VC:203 00 FL:00
$03/A335 1B TCS A:1FA3 X:002F Y:1F82 D:1EB0 DB:7E S:1F9D P:envmxdIzcHC:1270 VC:203 00 FL:00
$03/A336 2B PLD A:1FA3 X:002F Y:1F82 D:1EB0 DB:7E S:1FA3 P:envmxdIzcHC:1292 VC:203 00 FL:00
$03/A337 6B RTL A:1FA3 X:002F Y:1F82 D:1ED1 DB:7E S:1FA5 P:envmxdIzcHC:1336 VC:203 00 FL:00
S:1F9D
means
stack register is equivalent inside procedure between entrance and exit. Of
course stack register may be changed while inside procedure. It just means stack
register is get back to S:1F9D
at exit point ($03/A330
) finally.
In this case, a target of explanation procedure is named _03_a2de
to identify it. the name _03_a2de
brings the start address of the
procedure.
In C language representation, here is one example. The procedure content is omitted. This procedure brings 4 parameters. Each one occupies 2 byte. Totally 8 byte occupies. Usually procedure's parameters are brought through stack memory.
void _03_a2de(WORD aa, WORD bb, WORD c, WORD dd) {
...
}
Here is a procedure bit to call _03_a2de. In this code, it invokes 4 push
instructions, then call the procedure, then invoke 4 pop instructions (release
the parameters without fetching it). The caller seems to have responsibility to
manage the allocation and release of parameters.
Each push and pop instruction seems to access the memory in word unit (2 bytes
once).
|03/C533| 6|48 |PHA … PHA Push Accumulator on Stack |03/C534| 6|F4 DA CC |PEA $CCDA … PEA Push Effective Absolute Address on Stack (or Push Immediate Data on Stack) |03/C537| 6|AE 5C C2 |LDX $C25C … LDX Load Index X with Memory |03/C53A| 6|AD 5A C2 |LDA $C25A … LDA Load Accumulator with Memory |03/C53D| 6|DA |PHX … PHX Push Index X on Stack |03/C53E| 6|48 |PHA … PHA Push Accumulator on Stack |03/C53F| 6|22 DE A2 03 |JSL $03A2DE … JSL** Jump Subroutine Long | | | |L802.3: |03/C543| 6|7A |PLY … PLY Pull Index Y form Stack |03/C544| 6|7A |PLY … PLY Pull Index Y form Stack |03/C545| 6|7A |PLY … PLY Pull Index Y form Stack |03/C546| 6|7A |PLY … PLY Pull Index Y form Stack
Call run sample:
$03/C533 48 PHA A:0003 X:0000 Y:0004 D:1ED1 DB:7E S:1FB0 P:envmxdIzCHC:1356 VC:035 00 FL:65535 $03/C534 F4 DA CC PEA $CCDA [$7E:CCDA] A:0003 X:0000 Y:0004 D:1ED1 DB:7E S:1FAE P:envmxdIzCHC:0026 VC:036 00 FL:65535 $03/C537 AE 5C C2 LDX $C25C [$7E:C25C] A:0003 X:0000 Y:0004 D:1ED1 DB:7E S:1FAC P:envmxdIzCHC:0074 VC:036 00 FL:65535 $03/C53A AD 5A C2 LDA $C25A [$7E:C25A] A:0003 X:0009 Y:0004 D:1ED1 DB:7E S:1FAC P:envmxdIzCHC:0122 VC:036 00 FL:65535 $03/C53D DA PHX A:C5A2 X:0009 Y:0004 D:1ED1 DB:7E S:1FAC P:eNvmxdIzCHC:0170 VC:036 00 FL:65535 $03/C53E 48 PHA A:C5A2 X:0009 Y:0004 D:1ED1 DB:7E S:1FAA P:eNvmxdIzCHC:0208 VC:036 00 FL:65535 $03/C53F 22 DE A2 03 JSL $03A2DE[$03:A2DE] A:C5A2 X:0009 Y:0004 D:1ED1 DB:7E S:1FA8 P:eNvmxdIzCHC:0246 VC:036 00 FL:65535 $03/C543 7A PLY A:1FA3 X:002F Y:1F82 D:1ED1 DB:7E S:1FA8 P:envmxdIzcHC:0020 VC:204 00 FL:65535 $03/C544 7A PLY A:1FA3 X:002F Y:C5A2 D:1ED1 DB:7E S:1FAA P:eNvmxdIzcHC:0064 VC:204 00 FL:65535 $03/C545 7A PLY A:1FA3 X:002F Y:0009 D:1ED1 DB:7E S:1FAC P:envmxdIzcHC:0108 VC:204 00 FL:65535 $03/C546 7A PLY A:1FA3 X:002F Y:CCDA D:1ED1 DB:7E S:1FAE P:eNvmxdIzcHC:0152 VC:204 00 FL:65535 $03/C547 F4 0C 00 PEA $000C [$7E:000C] A:1FA3 X:002F Y:0003 D:1ED1 DB:7E S:1FB0 P:envmxdIzcHC:0196 VC:204 00 FL:65535
Memory dump (*4). The stack memory instructions read/write bank 00. The specific area of bank 00 is shadow of bank 7E. See *3
The parameters are stored in following status.
# | address | value |
---|---|---|
4 | $00/1FAF |
$0003 |
3 | $00/1FAC |
$CCDA |
2 | $00/1FAA |
$0009 |
1 | $00/1FA9 |
$C5A2 |
It points the return address $03/C542
. it'll be incremented to
the actual address $03/C543
in the process of RTL instruction.
...
I'm in the way to develop ObjDMv1. The problem is which RECT structure in 558
structure is used for rendering D3L,D3R,D3,D2L,D2R,D2,D1L,D1R,D1,D0L or D0R
wall.
In current research result, they say it is hard coded such as:
|03/B560| 26|A9 03 00 |LDA #$0003 |03/B563| 26|48 |PHA |03/B564| 26|F4 B2 CC |PEA $CCB2 |03/B567| 26|AE 54 C2 |LDX $C254 |03/B56A| 26|AD 52 C2 |LDA $C252 |03/B56D| 26|DA |PHX |03/B56E| 26|48 |PHA |03/B56F| 26|22 84 A2 03 |JSL $03A284 -> L906.1-1 | | | |L799.3: |03/B573| 26|7A |PLY |03/B574| 26|7A |PLY |03/B575| 26|7A |PLY |03/B576| 26|7A |PLY
The $03/CCB2
is a memory address which points the D3L RECT in
558 structure.
Known patterns:
Wall pos. | 558 rect addr | Hex | x1, x2, y1, y2, cx/2, cy, srcx, srcy |
---|---|---|---|
D3L | 03:CCB2 |
00 3E 19 4B 30 33 18 00 |
0, 62, 25, 75, 48, 51, 24, 0 |
D3R | 03:CCBA |
68 A6 19 4B 30 33 00 00 |
104,166, 25, 75, 48, 51, 0, 0 |
D3 | 03:CCAA |
38 70 19 4B 30 33 10 00 |
56,112, 25, 75, 48, 51, 16, 0 |
D2L | 03:CCCA |
00 38 14 5A 36 47 30 00 |
0, 56, 20, 90, 54, 71, 48, 0 |
D2R | 03:CCD2 |
70 A6 14 5A 36 47 00 00 |
112,166, 20, 90, 54, 71, 0, 0 |
D2 | 03:CCC2 |
2C 7C 14 5A 36 47 0C 00 |
44,124, 20, 90, 54, 71, 12, 0 |
D1L | 03:CCE2 |
00 2F 09 77 60 6F 90 00 |
0, 47, 9,119, 96,111,144, 0 |
D1R | 03:CCEA |
78 A7 09 77 60 6F 00 00 |
120,167, 9,119, 96,111, 0, 0 |
D1 | 03:CCDA |
18 8F 09 77 60 6F 24 00 |
24,143, 9,119, 96,111, 36, 0 |
D0L | 03:CCFA |
00 17 00 87 0C 88 00 00 |
0, 23, 0,135, 12,136, 0, 0 |
D0R | 03:CD02 |
90 A7 00 87 0C 88 00 00 |
144,167, 0,135, 12,136, 0, 0 |
Each RECT has 8 bytes. (x0, x1, y0, y1, width/2, height, xoffset, yoffset).
...
D2R: |
000F
would be the
source X offset of the vi altar. In below screenshot, left part of vi alter
hides.
00 20 25 49 18 25
is a rect6 structure. It will have same format which ADGE shows at Wall
Decoration Graphic Info Editor.
Then where is 000F
from?
Probably wall group may affect.
000F
is taken at
7th parameter. Track the write access for
$E2
.
|03/AA09| 8|F4 00 00 |PEA $0000 .8 |
I found interesting code below.
|03/A8D1| 8|A5 FF |LDA $FF |03/A8D3| 8|C9 07 00 |CMP #$0007 |03/A8D6| 8|D0 21 |BNE $A8F9 -> L1215.1-2 | | | |L1215.1: |03/A8D8| 4|A7 EE |LDA [$EE] |03/A8DA| 4|29 FF 00 |AND #$00FF |03/A8DD| 4|48 |PHA |03/A8DE| 4|A0 01 00 |LDY #$0001 |03/A8E1| 4|B7 EE |LDA [$EE],y |03/A8E3| 4|29 FF 00 |AND #$00FF |03/A8E6| 4|FA |PLX |03/A8E7| 4|86 F6 |STX $F6 |03/A8E9| 4|38 |SEC |03/A8EA| 4|E5 F6 |SBC $F6 |03/A8EC| 4|48 |PHA |03/A8ED| 4|A5 E2 |LDA $E2 |03/A8EF| 4|FA |PLX |03/A8F0| 4|86 F6 |STX $F6 |03/A8F2| 4|38 |SEC |03/A8F3| 4|E5 F6 |SBC $F6 |03/A8F5| 4|85 E2 |STA $E2 |03/A8F7| 4|80 02 |BRA $A8FB -> L1216.1-1 | | | |L1215.2: |03/A8F9| 4|64 E2 |STZ $E2 | | | |L1216.1: |
#$0007
would be
wall ornate group number. 7 means "D2 Left Wall", if it's right. I tried to read
the meaning of above code by rewriting in pseudo C language.
if ($FF == 0x0007) { |
It makes me happy if it can be read like following code.
srcX = Width/2; |
Posted source code is disassembled from DM SNES JP 1.0. Captured/Disassembled by Geiger's Snes9x Debugger. |
The mnemonic and help description in the code bit are brought from
mnemonic.txt in "65816 docs" distributed by zophar.net. http://www.zophar.net/tech/65816.html |
Super NES Programming/SNES memory map http://en.wikibooks.org/wiki/Super_NES_Programming/SNES_memory_map |
Memory dump and test run result are presented by Geiger's Snes9x Debugger (v1.43.ep9r8). |