Author
|
Topic: What am I doing wrong? (6502 related) (Read 2 times)
|
Aeris130
Guest
|
|
« on: May 01, 2008, 10:06:48 am » |
|
I've been tinkering around with assembly a little in Dragon Warrior III, but I can't seem to get it to work. (Newbie alert. I barely have any ASM experience.) As far as I can tell, the game writes text through the adress $72 in ram (I'm talking to the soldier to the left when you enter the castle). I've found what I think might be the ASM for this in the rom at $7EBC4: 'A0 00 B1 72' 0F/EBB4: A0 00 LDY #$00 ;$7EBC4 0F/EBB6: B1 72 LDA ($72),Y ;$7EBC6 I tried changing the value 72 to something else, and the text stopped loading. Then I rewrote the ASM in windhex into a loop (starting at $7EBC6), making the game freeze on the same spot: A0 00 [my loop->] 4C B6 8B (JMP -> EBC6) I'm not sure, but I think I'm in bank 8000. DW3 uses 32KB banks. Anyway, I wanted to add some more code inbetween, so I located some empty space in RAM @ $4000 during the freeze/loop. This, unless I'm mistaken, would mean $74000* in rom. Isn't it? In any case, there's a lot of empty space here. *8000 x 0F (bank number) + 4000 - 8000 Then I figured I'd do a JSR to this space, and continue working from there. 20 00 40 EA (JSR $4000 NOP) ^ I replaced 'A0 00 B1 72' (LDY #$00; LDA ($72),Y) from $7EBC4 with this. Just to be sure, I would type back A0 00 B1 72 (with an RTS at the end) to $74000 in order to see if the game continued like normal, but my rom keeps resetting itself every time a piece of dialogue is about to be loaded. And I can't really figure out why. Did I miscalculate any addresses between rom <> ram? To sum it up: 1. Game goes to $7EBC4 expecting to find A0 00 B1 72. 2. Game is instructed to jump to $74000 instead. 3. game finds A0 00 B1 72 60 at $74000 (60 = RTS). 4. :cookie: That is, if I could make it work.
|
|
« Last Edit: May 01, 2008, 11:21:23 am by Aeris130 »
|
|
|
|
KingMike
Guest
|
|
« Reply #1 on: May 01, 2008, 11:41:57 am » |
|
DW3 (US) is a 512KB MMC1 ROM. That is a somewhat unique case.
$7EBC4 is near the end of the ROM, so actually, $7C000-7FFFF (add $10 for the header) is always located in $C000-FFFF of the CPU address space, so actually, the jump would need to be to $EBB6, no BBB6.
Also, the unique part is that both $3C000-3FFFF and $7C000-7FFFF can be mapped into that part of CPU . (which is used depends on the MMC1's 256KB bank select register) Not sure if DW3 uses both locations, so if the code suddenly breaks, you might need to check $3EBB6's code too.
Also, RAM only uses $0000-07FF for the NES internal RAM and $6000-7FFF for the cart RAM. $4000-4017 are register for sound and a few I/O registers. The rest is unmapped space. (well, the FDS uses $402x and $403x, but that's besides this topic)
|
|
« Last Edit: May 01, 2008, 11:47:01 am by KingMike »
|
|
|
|
Nightcrawler
Guest
|
|
« Reply #2 on: May 01, 2008, 11:46:56 am » |
|
Also, you need a NOP after your new JMP. Your JMP takes up 3 bytes, but the original instructions were 4. So, when it returns from your new routine it starts executing at that fourth byte which is now some OTHER instruction and proceeds to misalign every instruction from that point forward which I'm positive would cause a crash.
If you use a debugger, you should be able to see exactly what I'm talking about. The game will jump to your code, and then foul up greatly when it returns. I'd recommend getting used to using a debugger, it will save you a lot of time. You can see exactly what happens when the game executes your code. All you need to do is set a breakpoint.
|
|
|
|
KingMike
Guest
|
|
« Reply #3 on: May 01, 2008, 11:54:12 am » |
|
Another thing I should add is that if you're looking to write some code, you should look between $8000-BFFF (some 16KB bank in the ROM) and $C000-FFFF (which is either ROM $3C010-4000F or ROM $7C010-8000F depending on the previously-mentioned register).
If there's no free space, you could use bankswaps if there's free space elsewhere in the ROM (and a little free space in the CPU $C000-FFFF region), but that is a little more advanced topic.
|
|
|
|
Aeris130
Guest
|
|
« Reply #4 on: May 02, 2008, 09:53:16 am » |
|
Thanks for the replies. $7C010-8000F seems to be available, but I'll probably have to take it piece by piece in a debugger to make any sense out of this.
|
|
|
|
syntax error
Guest
|
|
« Reply #5 on: May 02, 2008, 10:54:51 am » |
|
There are plenty much documents for the 6502 and similar CPUs. More or less commented game disassemblies are on the net. Romhacking.net has Metroid and Super Mario Bros. DASM to download. Also the same CPU is used in Atari 2600,5200,7800,PC-Engine and C64 or Apple 2 and other systems.The 6502 is a very restricted CPU and thus easy to understand. Thats why Master System or MSX hacking is more difficult.
|
|
|
|
KaioShin
Guest
|
|
« Reply #6 on: May 02, 2008, 11:26:34 am » |
|
The 6502 is a very restricted CPU and thus easy to understand.
Actually I disagree. A CPU with some more possibilities is much easier to understand since even simple code sometimes has to be quite obscured on very primitive CPUs. For example since you always have to go through the accumulator. I think it's much easier to deal with and nicer to read and understand if you have a 3-Address machine where you can take any register you like and any operants you like. On the NES specifically there is also the whole mapper business. Honestly, I don't understand why the NES is often recommended as a good beginner system.
|
|
|
|
UglyJoe
Guest
|
|
« Reply #7 on: May 02, 2008, 11:30:39 am » |
|
Honestly, I don't understand why the NES is often recommended as a good beginner system.
I always thought it was because of the small table sizes and general lack of graphics/script compression.
|
|
|
|
KaioShin
Guest
|
|
« Reply #8 on: May 02, 2008, 11:32:26 am » |
|
Honestly, I don't understand why the NES is often recommended as a good beginner system.
I always thought it was because of the small table sizes and general lack of graphics/script compression. Ah, I never considered that viewpoint before. That makes sense.
|
|
|
|
Karatorian
Guest
|
|
« Reply #9 on: May 03, 2008, 05:46:25 pm » |
|
While the primative nature of the 6502 can make some assembly operations tricky (have you ever done mulitplation or division on the thing?), I think the primary advantage of it and the rest of the NES is that it's relatively small size makes it easy to keep the state of the system in your head.
With only a handful of CPU registers and a (relatively) small number of graphics and sound registers, I find it fairly easy to remember what's stored where and what not. On more complex systems, keeping track of it all can be a pain.
The biggest drawback of the NES is that it's eight bit. This makes doing anything involving large numbers or addresses (which are 16 or 24 bit) more complex than they would be on a wider CPU. However, the small instruction set makes it easy to learn (if not, neccessarily easy to code). I've found that I've memorized the whole ISA without even conciously trying to do so. (Which isn't the case on other archtectures I've coded ASM on.)
On the other tentacle, a nice orthoganal RISC architechture would be the bomb. However, the systems that uses such CPUs have so many other complications that most of them are a poor choice for a beginner. (With the possible exception of the GBA. The ARM instruction set has some strange complications, but it's pretty clean and the GBA's additional hardware is simple, like old school consoles, rather than super complex, like most modern machines.)
The other reason that the NES is good for newbies is the vast ammount of documentation, utilities, tutorials, etc. that exist for it. Furthermore, it seems that most hackers have some experiance with it, so when you ask for help, there are a large number of people out there willing (and able) to help you.
|
|
|
|
BRPXQZME
Guest
|
|
« Reply #10 on: May 03, 2008, 06:15:15 pm » |
|
While the primative nature of the 6502 can make some assembly operations tricky (have you ever done mulitplation or division on the thing?), ...
Yes, and it can be argh. Thank goodness you’ll rarely need it on game systems that use a 6502, though... Of course, taking the easy way out doesn’t give you any demoscene cred
|
|
|
|
KingMike
Guest
|
|
« Reply #11 on: May 03, 2008, 09:00:37 pm » |
|
I actually tried to do multiplication on the NES, using some manner of shifts, though a loop would accomplish the job (slowly). (like 6x5 = 6x4 + 6x1 = (6 left-shift 2) + 6 instead of 6+6+6+6+6). Don't remember if even finished a routine, though. (yeah, I'm talking about integer multiplications. Floating point could be a mess, and would definitely be slow.)
Not sure if there's a simple way to do division, aside from a subtraction loop (would probably have to settle for an integer and remainder result).
Too bad nobody's figured out how the low level behavior of the SNES mult/div registers.
|
|
|
|
Nightcrawler
Guest
|
|
« Reply #12 on: May 03, 2008, 09:31:45 pm » |
|
I do large number fixed point math on 8-bit microntrollers at work. It takes some doing, but it can't be done easy enough. A bunch of loops and shifts really. Typically, the speed if much faster than the NES though.
|
|
|
|
Karatorian
Guest
|
|
« Reply #13 on: May 03, 2008, 09:57:17 pm » |
|
I wouldn't even consider doing floating point on a 6502, if you need subdecimal numbers, simply use fixed point. Multiplication and division are, as mentioned above, simply a series of shifts and additions or subtractions. I actually learned how by discovering the routines in my Final Fantasy dissasembly commenting project.
It's not true that you don't need multiplication or division in NES games. RPGs need both, and often at 16 bit or more. However, the algorithms for (somewhat) fast routines to handle advanced math on restrictive architectures are well documented, so it's not that bad. (I even saw a routine for square roots in 6502. (Although not in a game.) Eww.)
|
|
|
|
BRPXQZME
Guest
|
|
« Reply #14 on: May 03, 2008, 11:35:17 pm » |
|
It's not true that you don't need multiplication or division in NES games. RPGs need both, and often at 16 bit or more. However, the algorithms for (somewhat) fast routines to handle advanced math on restrictive architectures are well documented, so it's not that bad.
You rarely need multiplication, it just makes things nicer if you need an exact value. You can just as easily use lookup tables, if you’re restricting exactly what kind of operations you do and you have the room to spare. Generic multiplication in software is slow, but even this can be alleviated with plenty of other dirty tricks depending on what you’re doing (self-modifying code and other such nonummy). Action games can often get by with mere shifts and addition. But not all shortcuts occur to all people, and you’ll find inefficient routines all over the place because there was no pressing need to optimize....
|
|
|
|
|