NES Roms and hex editing questions
MrOddBall
Velociraptor
Joined: 3 Feb 2014
Age: 126
Gender: Male
Posts: 426
Location: Here, there, and everywhere
I was just wondering if I'm right about seeing the hex numbers for certain assembly op-codes and their operands in a retro NES Rom file when I'm viewing it in a hex editor ? If I'm right and it is op-codes and data that I'm seeing, then there'll also be addresses in there too, right ? I know there's addressing modes in 6502 that allows you to manipulate data and addresses as well ...
Is this correct ? This would help me a long way as I was confused and wasn't really sure, also I guess I could disassemble a NES Rom manually or write one in C or even Python ...
MrOddBall
Velociraptor
Joined: 3 Feb 2014
Age: 126
Gender: Male
Posts: 426
Location: Here, there, and everywhere
This zip file has both a txt and doc file that give a list of opcode conversions for the instructions and their addressing modes--I prefer the txt file:
http://nesdev.com/6502jsm.zip
It's from nesdev.com
Looking at your example, are you sure you copied the machine code correctly?
From A9 05 8D 00 00 04 you would get:
LDA #$05 ; absolute addressing, yes, and you got this right
STA $0000 ; you got this wrong; now you are correct that this is accesses the value at the 16-bit address (in this case $0000), but 04 comes after the end of the instruction
; 04 is not a valid op code so if the program came up on this 04, there would be an unpredictable effect (a crash most likely)
Now, I'm guessing you only intended to put 1 00 in there, so it would be A9 05 8D 00 04, which would dissassemble to:
LDA #$05
STA $0400
(EDIT 3: This bit of code loads the value $05 into the accumulator and then stores the accumulator's value (which now is $05 thanks to the previous instruction) at the 16-bit address $0400.)
Remember that 6502 machine code is always little-endian, which means that for 16-bit values, the least significant byte comes first. So 00 04 combines to $0400 (00 is least significant and 04 is most significant), while 04 00 combines to $0004.
Source: Me. I have considerable experience doing ASM hacking of NES/FDS ROMS, to include manual assembly and disassembly and even have worked on my own disassembly of a game, this one of SMB2j:
http://sm2.beneficii.net/
EDIT: I also created the SMB3 Map Editor and the ASM hack of the start spaces that accompanies the editor as an IPS patch.
EDIT 2: Corrected my own opcode, do'h! ![]()
_________________
"You have a responsibility to consider all sides of a problem and a responsibility to make a judgment and a responsibility to care for all involved." --Ian Danskin
MrOddBall
Velociraptor
Joined: 3 Feb 2014
Age: 126
Gender: Male
Posts: 426
Location: Here, there, and everywhere
http://nesdev.com/6502jsm.zip
It's from nesdev.com
Thanks for the op-code list
Actually I just made that up as an example of what I was trying to explain
LDA #$05 ; absolute addressing, yes, and you got this right
STA $0000 ; you got this wrong; now you are correct that this is accesses the value at the 16-bit address (in this case $0000), but 04 comes after the end of the instruction
; 04 is not a valid op code so if the program came up on this 04, there would be an unpredictable effect (a crash most likely)
Now, I'm guessing you only intended to put 1 00 in there, so it would be A9 05 8D 00 04, which would dissassemble to:
LDA #$05
STA $0400
(EDIT 3: This bit of code loads the value $05 into the accumulator and then stores the accumulator's value (which now is $05 thanks to the previous instruction) at the 16-bit address $0400.)
So too many 0's ?
That's been a really hard thing for me to remember that the least significant byte comes first instead of the most significant byte
http://sm2.beneficii.net/
EDIT: I also created the SMB3 Map Editor and the ASM hack of the start spaces that accompanies the editor as an IPS patch.
EDIT 2: Corrected my own opcode, do'h!
I've checked out your site and think it's pretty cool myself
Yes, been around both. Zophar's Domain is an oldy, but still good for getting things like the soundtracks of video games in their original code form so you can play them over and over again.
Remember, when you use 16-bit addressing, the instruction will only be 3 bytes long:
byte 0: opcode
byte 1: least significant byte
byte 2: most significant byte
If using absolute, zero-page (8-bit addressing), or branch-on-condition (e.g. BCC, BEQ):
byte 0: opcode
byte 1: absolute value, zero-page address, or (for branching instructions) the distance from the first byte following this current byte we're talking about of the address to where you're supposed to branch if the condition tested by the branching instruction is true (this is a signed integer, so you can go backwards or forwards)*. Some examples are BCC, which means branch if carry (C) flag is cleared (otherwise, don't branch and simply move onto next instruction), and BEQ, which means branch if zero (Z) flag is set (otherwise, don't branch '').
And of course for all those op-codes that don't have an addressing mode at all:
byte 0: opcode
Again, no instruction takes up more than 3 bytes (and this includes the opcode itself).
*Signed integers are integers that can be either positive or negative. In 6502, signed integers, whether they are negative or not, are determined by the most significant bit (if the most significant bit is 1, then it's negative; if it's 0, then it's positive). Basically, it follows this pattern (for 8-bit signed integers):
+5 = $05 = %00000005
+4 = $04 = %00000004
+3 = $03 = %00000003
+2 = $02 = %00000002
+1 = $01 = %00000001
0 = $00 = %00000000
-1 = $FF = %11111111
-2 = $FE = %11111110
-3 = $FD = %11111101
-4 = $FC = %11111100
-5 = $FB = %11111011
(Notice the most significant bit, which is the leftmost bit when written in binary, is set to 1 for negative numbers.)
For 16-bit signed integers, which are not used for anything in the instructions, but which may be useful still in programming, go like this:
+5 = $0005
+4 = $0004
+3 = $0003
+2 = $0002
+1 = $0001
0 = $0000
-1 = $FFFF
-2 = $FFFE
-3 = $FFFD
-4 = $FFFC
-5 = $FFFB
(Basically, to get the correct way of storing negative values, you need to know the width (e.g. 8-bit, 16-bit) of the integer.)
This is known as the two's complement way of representing signed integers, and is the way you should use when programming with 6502, as it is best designed for that. More on signed integers here, as well as the overflow (V) flag which is relevant to addition and subtraction of signed integers (as, to be honest, even I don't fully understand it):
http://www.6502.org/tutorials/vflag.html
EDIT: Corrections and adjustments
_________________
"You have a responsibility to consider all sides of a problem and a responsibility to make a judgment and a responsibility to care for all involved." --Ian Danskin
