+  RHDN Forum Archive
|-+  Romhacking
| |-+  ROM Hacking Discussion
| | |-+  Trying to Unbreak an NES Game
Pages: [1] 2
Author Topic: Trying to Unbreak an NES Game  (Read 2 times)
Kagemusha
Guest
« on: August 26, 2007, 11:27:04 am »

So I've broken a game by overwriting some code to make a jump to some empty space in RAM, but when I try to get the game to unbreak, the text won't show up.

Original code: A2 00 B1 68
New code: 20 B6 BD EA
Code for RAM location in the ROM: A2 00 B1 68 60

When I jump to the empty RAM space, the game freezes indefinitely and when I put in the new code to try and unbreak it, the game will still freeze, but the music will play unlike before. Not quite sure what to do, but I probably made a mistake.
Gideon Zhi
Guest
« Reply #1 on: August 26, 2007, 12:29:11 pm »

Depending on the mapper you've got this could be wrong, but it occurs to me that BDB6 is usually ROM space in a currently-swapped-in bank. RAM is generally 0-7FFF, segmented differently and with various levels of access depending on the mapper.
Kagemusha
Guest
« Reply #2 on: August 26, 2007, 12:48:31 pm »

Hmm, I've been looking at KingMike's DTE doc and trying to use it with another game and basically trying to figure out the variables in the process. The mappers are definitely different as Ys III uses mapper 4 while my game uses mapper 80 and Ys III has 8 X16KB PRG ROM while my game has 16 X 16KB PRG ROM. I guess the biggest difference is the mapper, but it's beyond my knowledge of what it would affect that I would have to do different.

Quote from: Gideon Zhi on August 26, 2007, 12:29:11 pm
but it occurs to me that BDB6 is usually ROM space in a currently-swapped-in bank.

It looks like your correct about that as that what I found in RAM and ROM are exactly the same.
Disch
Guest
« Reply #3 on: August 26, 2007, 01:01:38 pm »

Jumping to a subroutine in another slot requires you to know exactly which page is selected into that slot.  On mapper 80, the only slot that is fixed to a specific page is $E000-FFFF.  Other slots have different 8k ($2000 byte) pages selected into them at different times.

If you're jumping to $BDB6, you need to be sure you know exactly what bank is selected at $A000-BFFF.... otherwise you could be jumping to any one of 32 different places in the ROM.

I wrote two technical docs on this very subject that may be useful to you

Also -- RAM is $0000-07FF and sometimes $6000-7FFF as well (not $0000-7FFF -- PPU/APU regs and stuff lie between there)
Kagemusha
Guest
« Reply #4 on: August 26, 2007, 03:19:14 pm »

I believe I would want to freeze the game when the specific text is loaded. I think that can be done by overwriting the ASM located at $1402B and jump to it's location in RAM which I believe is $802B. It causes the game to freeze, but the music still plays(not sure if that matters). From there I I view the RAM until I find some free space and then convert it to it's ROM location and make a jump to the RAM location overwriting the code at $1402B. Then I put the original code in the Rom of location that I jumped to and the game should work. Am I on the right track here?
Disch
Guest
« Reply #5 on: August 26, 2007, 03:38:09 pm »

If the game is locking up but the music still plays... I would wager the game is totally dead and the music is being driven by NMIs which are still occuring (though actual game flow logic is forever frozen).

This is almost certainly due to you jumping to the wrong address.

address $802B could be offset 0x0003B, or 0x0203B, or 0x0403B, or 0x0603B, etc, etc... there's no way to know which page is actually at $802B at any given time without snapping the debugger and looking.  To know for sure, go in the 'NES memory' hex editor in FCEUXD, right click on a target byte and select "go here in ROM file".  That will take you to the coresponding ROM offset.

From the code snippits you gave in your first post -- nothing in the game should be changing... it should be playing just as it did before you made the change.  If it's crashing, it's definately because of this address mixup.

You are definately on the right track, though.  You're just fumbling over address->offset conversions.


---- end useful part of post, begin pet peeve mini-rant ----

CPU Addressing space is not RAM.  Only a small fraction of addresses corespond to RAM... most of it is ROM, some of it is registers, etc.  I want to stab docs that say things like "RAM address" for CPU addresses.
Kagemusha
Guest
« Reply #6 on: August 27, 2007, 07:10:44 pm »

I think I know why the game's not working after I make my jump to the ROM Space that swapped in a bank. I'm jumping to the right place as if I change some of my code at the ROM space that's used by the bank, the games behaves differently. In order for the game to work after jumping, would I need to put in all code of the particular routine? I think I've only been putting in part of the code in. I think that might be the reason, but I'm not too sure. Also if this is the case, how do I distinguish what's part of the routine and what's not?
« Last Edit: August 27, 2007, 07:16:03 pm by Pennywise »
Disch
Guest
« Reply #7 on: August 27, 2007, 07:48:42 pm »

Quote from: Pennywise on August 27, 2007, 07:10:44 pm
In order for the game to work after jumping, would I need to put in all code of the particular routine? I think I've only been putting in part of the code in. I think that might be the reason, but I'm not too sure. Also if this is the case, how do I distinguish what's part of the routine and what's not?

The only thing you have to do it make sure you return to the original game code with everything as it was before you jumped to your own routine.  That is... if your routine changes A, X, or Y... you should make sure you return them back to what the original game had them before returning to the original code.  This isn't necessary 100% of the time, though.  Like if you're sure that X and Y aren't used by the game in the routine then you don't need to restore them (you can determine this by examining code further into the routine).

The only additional worry would be time issues.  If your code is too long and disrupts some timing by the game.  Though I sincerely doubt this wouldn't cause a deadlock -- but it would cause some graphical issues.  But this would usually only be an issue if you're interrupting drawing code -- which, from what I've been reading in this thread, I doubt you're doing.  I'm just really mentioning this for completeness... I'm sure this isn't an issue for you.
Kagemusha
Guest
« Reply #8 on: August 27, 2007, 09:00:24 pm »

Well at the very least I've got the game to run again, but the text doesn't show up. Just a push of a button and the text box disappears with a quick flash of garbled graphics and plays on normally. Anyway when you say A, X, and Y, do you LDA, LDY, and LDX? I don't really know what I'm doing wrong, but would it matter if I jumped to a different RAM bank than the one the original code is already in? Also might I be jumping from the wrong place in the code. I used to overwrite LDX $00 and LDA $68 , but I went back a few places and tried LDX $00 and LDX, etc.
Disch
Guest
« Reply #9 on: August 27, 2007, 09:53:36 pm »

Quote from: Pennywise on August 27, 2007, 09:00:24 pm
Anyway when you say A, X, and Y, do you LDA, LDY, and LDX?

Err... I meant the A,X,Y regs.  You can set them with LDA, LDY and LDX instructions.

How much 6502 do you know?  I may have been assuming you know more than you do.

Quote
I don't really know what I'm doing wrong, but would it matter if I jumped to a different RAM bank than the one the original code is already in?

It might.  It depends what page is swapped in.  If you're jumping to code that isn't swapped in when you expect it to be... then yeah, that'd be a big problem.  To be "safe"... you can always jump within the same 8k ($2000 byte) slot (so if the code is currently at $ADF6, you can safely jump anywhere in $A000-BFFF).   You can also jump safely to the fixed slot (address $E000-FFFF)... since that slot never swaps.

also....   Grr @ "RAM bank".  You're talking about ROM and CPU addresses, not RAM  </pet peeve>

EDIT:  stupid mistake -- had the wrong page mentioned in my example  >_<

Quote
Also might I be jumping from the wrong place in the code. I used to overwrite LDX $00 and LDA $68 , but I went back a few places and tried LDX $00 and LDX, etc.

I can't know what that code is doing out of context.
« Last Edit: August 28, 2007, 11:02:38 am by Disch »
Kagemusha
Guest
« Reply #10 on: August 27, 2007, 10:30:36 pm »

Quote from: Disch on August 27, 2007, 09:53:36 pm
Quote from: Pennywise on August 27, 2007, 09:00:24 pm
Anyway when you say A, X, and Y, do you LDA, LDY, and LDX?

Err... I meant the A,X,Y regs.  You can set them with LDA, LDY and LDX instructions.

How much 6502 do you know?  I may have been assuming you know more than you do.

Not too much right now. Right now it looks like I really understand JMP, JSR, NOP, and RTS. Those four ones and their opcodes. I'm trying to learn as I go. I might know a little more, but nothing else comes to mind that's significant. So far it's working out okay as I know much more than before.

Quote from: Disch on August 27, 2007, 09:53:36 pm
also....   Grr @ "RAM bank".  You're talking about ROM and CPU addresses, not RAM  </pet peeve>

I kinda knew that'd piss you off. I blame it on the doc I've been looking at.
RedComet
Guest
« Reply #11 on: August 27, 2007, 10:35:45 pm »

Code:
save_regs:
pha ;save A

tya ;save Y
pha

txa ;save X
pha

;code here

pla ;restore X
tax

pla ;restore Y
tay

pla ;restore A

;return to original code here

A little sample code. The stack is your friend. Use it wisely. Wink
Firlet
Guest
« Reply #12 on: August 28, 2007, 06:25:25 am »

Code:
;sample test

org $2500
base $8000+$500
;lda #$5e
;sta $0500

jsr dte_routine
nop #2


org $25500
base $c000+$1500

dte_routine:
; save ZNVC (for bcc later)
php

; save a,x (for later)
pha
txa
pha

; ----------------

; insert test code
nop

; ----------------

; restore regs
pla
tax
pla
plp

; OLD code
lda #$5e
sta $0500

; return to original code
rts
Kagemusha
Guest
« Reply #13 on: August 28, 2007, 05:16:49 pm »

Thanks for the code everyone.

RTS
LDA #$00
STA $0636 = #$00
LDY #$00
LDX #$00
LDA ($68),Y @ $A474 = #$FC
INY
CMP #$46
BCS $8039
CMP #$FE
BNE $804B
CMP #$FD
BNE $805D
CMP #$FC
BNE $8087
STX $0615 = #$04
JSR $F72F

This is the code I've replaced with a JSR to a location in a CPU or ROM bank.

LDY #$00
LDX #$00
LDA ($68),Y @ $A474 = #$FC
« Last Edit: August 28, 2007, 06:35:29 pm by Pennywise »
Firlet
Guest
« Reply #14 on: August 28, 2007, 08:45:41 pm »

Quote from: Pennywise on August 28, 2007, 05:16:49 pm
Thanks for the code everyone.

LDA #$00
STA $0636 = #$00
LDY #$00
LDX #$00

Y=0, X=0 are 'initialization' commands.
They are only done _once_.

Afterwards, y is bumped by 1 in a loop (to read the script).
Right here, intuition says that there's a loop label.

Quote
read_next_byte:
LDA ($68),Y @ $A474 = #$FC
INY

// check raw tiles (this is a guess)
CMP #$46
BCS $8039

// scripting codes (probably)
CMP #$FE
BNE $804B

CMP #$FD
BNE $805D

CMP #$FC
BNE $8087

STX $0615 = #$04
JSR $F72F

This is the code I've replaced with a JSR to a location in a CPU or ROM bank.

LDY #$00
LDX #$00
LDA ($68),Y @ $A474 = #$FC

You should replace some of the following code with a JSR.

Code:
read_next_byte:
LDA ($68),Y @ $A474 = #$FC
INY

-->

read_next_byte:
JSR $xxxx

That way, it'll handle those multiple jmp-back commands when the next script byte is read.

Otherwise, the game would be using the normal read routine, which we don't want.
Something like this:

Code:
xx xx LDY #$00
xx xx LDX #$00
xx xx LDA ($68),Y @ $A474 = #$FC

-->

JSR xx xx xx
NOP xx

read_next_byte:
NOP xx
NOP xx
Pages: [1] 2  


Powered by SMF 1.1.4 | SMF © 2006-2007, Simple Machines LLC