I've heard lots of great things about using breakpoints, and I really want to learn how to use them. But every time I try set one up, for some reason I can't ever get it to work. I'm just not sure how to go about doing it. For example, how would I go about setting it up to stop when it encounters "STX $102" or something like that?
The best approach would be to set a breakpoint on $102 write. Unfotunately, it would break on ANY $102 write, even if it's somwhere else.
Another alternative is to enable your favourite assembler's listing option (assuming it has one) and look at the adress of the stx $102 you're looking for, and set a breakpoint when the 6502 execute that adress.
If you're doing your stx $102 at different points of the code and do other writes to $102 you don't want to break, the only choise is to enter all of them separately which could be annoying, but in 90% of case this debugger has pretty much all you'd expect it to have.
Ah, I see. I was just thinking it worked differently. So I actually decided to stick with something like a write to $4500 or something really weird that you'd never write to. For anyone who's confused about how to set something like this up:
Go to Tools and then to Debug. After that, under the white textbox that says "breakpoints" click "Add". Then in the "Address" section, I write 4500 (Without the "$") on both sides, and check "write", and then OK. After that, it'll break whenever $4500 is written to. It's as easy as that.
Did I get it right? It broke for me...
Celius wrote:
I write 4500 (Without the "$") on both sides
I think you can write it just to the left side. The right one is only necessary if you want to specify a memory range.
Quote:
After that, it'll break whenever $4500 is written to. It's as easy as that.
I don't know if I'm doing something wrong, but sometimes it doesn't break for me, apparently with more complex addressing modes. There were times I was sure a certain address was written to with some indexed addressing and that didn't trigger the break.
Well, I'm not sure what the problem would be. I would normally just stick an STA $4500 in the code where I want it to break. But say if something is being written to in RAM and I don't know where from, I'd like to break on any write to that address. Maybe try the newest version of it? There was something like "The ultimate debugger" version of FCEUXD that just came out recently. Maybe you'd like to try that out. It can also break on certain conditions, like when A = 3, or X = A, etc.
I'd guess in most emulators breakpoints are attached to the read/write handlers. If that emulator doesn't emulate all execution cycles with a fetch (they instead directly access memory) they won't all trigger.
Celius wrote:
Well, I'm not sure what the problem would be. I would normally just stick an STA $4500 in the code where I want it to break. But say if something is being written to in RAM and I don't know where from, I'd like to break on any write to that address. Maybe try the newest version of it? There was something like "The ultimate debugger" version of FCEUXD that just came out recently. Maybe you'd like to try that out. It can also break on certain conditions, like when A = 3, or X = A, etc.
Lately, I've done something similar. I use FCE Ultra and check the box to "break on invalid opcodes". I have a ca65 macro called "CRASH" that puts into the code the invalid opcode "$03" followed by several NOPs. I thought about encoding the actual source line # immediately after the $03, but I have not bothered yet. Anway, I write my code with lots of "assert()" like statements so if at any point in the game a logic inconsistency is detected, the assert triggers and the emulation halts on the invalid opcode. All of this is controlled by a Makefile / ca65 directive so that I can still build my game without any of this baggage.
Maybe this approach would help you?
ps- my first post. Hello guys. I've been lurking for a while, and coding in 6502 asm since the mid-80s. So I'm not a 6502 noob, but I am new to NES dev.
I think for now I'm fine with just using something like STA $4500. I'm just starting to get into this debugger, and basically hardcore debugging in general. Can you believe that? I've been making games this whole time and debugging without using any break points! Oh, now coding is a heck of a lot easier! Sorry, it's just such a relief to be able to use these now. But I generally don't use my assembler for anything besides just making the .NES file. I don't ever use macros, though I might start doing that as I find myself typing the same things quite often.
And also, welcome to the NESdev community! I think you'll find the NES to be a very straight forward system. There aren't lots of things to learn about it, and since you know 6502 very well, you'll learn really really fast. Or, at least faster than I did (I didn't know how to program at all when I first came).
Celius wrote:
And also, welcome to the NESdev community! I think you'll find the NES to be a very straight forward system. There aren't lots of things to learn about it, and since you know 6502 very well, you'll learn really really fast. Or, at least faster than I did (I didn't know how to program at all when I first came).
Thanks. I've actually been experimenting with the NES for a few weeks. My current progress is here:
http://unwg.no-ip.com/~djenkins/nes-game.nes
(I admit, I stole the "hero" sprite from Faria. But the cheesy grass tiles I made!) The scrolling jumps a bit at the very end of the title-screen, and it really doesn't do anything after the title screen is displayed. I'm currently working on a "C" utility to compose my char-roms and compressed maps based on a high-level text input (I like to us programming language parsers and such).
Anyway, I hate to drag this thread off-topic so I'll stop here.
Break-points are very helpful debugging aides. Another thing that I do is reserve a chunk of memory (either in zero-page or near the bottom of the stack) to use as a "log buffer". That is, I'll store the results of internal computations there, even if the code doesn't need to preserve the temp value. That way I can watch the values change in near-realtime via the "debug -> hex dump" tool in FCE Ultra. I also test with Nintendulator and 80five.
That's a nice little demo!
My first demo was pure crap. If you want to view my current "best work", here:
http://www.freewebs.com/the_bott/game.nes
It's just a little game I made, though I'm working on much greater things than that!
About the jumping, don't worry, scrolling is a pain anyways. I'm almost done rewriting my scrolling engine to be completely universal and easy to use. My first one took me a very long time to write, but this one I've been working on for about 3 days, and it's very clean and easy to use, as well as nearly finished.
I never got into high level languages. Everyone says they're good for starting out, but sometimes I don't think so. True, if you use the standard libraries, you'll be able to much more easily do math related things and stuff like that. The 6502 makes you think exactly how to compute something, and you understand things more easily. But I'll be using something like Visual Basic to make my applications for making maps and stuff.
But getting back on topic, without using break points, I found myself stumped for long periods of time as to what the problem would be in a piece of code. Now I think I'll speed up the coding/debugging process by a long shot! What you said sounds kind of like what I do. I store the results of some computations somewhere where I can see them individually. But I usually do this without reserving sections. I'm sure you know tons more about the 6502 than I do, but I would never reserve something like that in the stack! That's somewhere I usually just don't touch. Even for saving the status of a register, I never do things like pla/pha, I just use a ZP temp var. I have like 8 reserved as plain temporary variables. I might add some, but the most I've used in routines is about 6. They're really handy.
Celius wrote:
I'm sure you know tons more about the 6502 than I do, but I would never reserve something like that in the stack! That's somewhere I usually just don't touch. Even for saving the status of a register, I never do things like pla/pha, I just use a ZP temp var. I have like 8 reserved as plain temporary variables. I might add some, but the most I've used in routines is about 6. They're really handy.
You assume much
I probably don't know as much asm as a real hard-core 6502 fan would (like figuring out the joypad reading using cpx to set the carry and ror to shift it in).
I learned 6502 on the Apple IIe. Applesoft BASIC was just too slow for what I wanted to do. So I wrote asm in page 3 ($0300-$03ff) using the built-in assembler (call -151). I disassembled the BASIC rom to figure out how it did floating point math (I remember finding a weird polynomial and figuring out that it was the taylor series for computing "cos(x)"). Anyway, that is about the extent of my 6502. And that was many years ago.
I don't store debugging info on the stack in "active" stack frames (if you could view the 6502 stack like that). I meant to say that I use $1ff down for the stack, but I never expect the stack to go very deep. So memory from $100 up through some safe range (like $180) should be safe for general use. Many real NES games use that memory for "production" purposes. My idea was to store debugging data there, so that it can easily be found and not conflict with my normal set of globals nor consume valuable zero-page spaces.
I just tried your game too. Pretty cool.
Does anyone have any other debugging suggestions other than breakpoints and ram watches? I use "ca65" as my assembler, and would love a source-level debugger that can work with ca65. However, I have yet to find one and emu development is a bit beyond my desires right now
Celius wrote:
I think for now I'm fine with just using something like STA $4500.
Yeah, Celius, I do that too when I'm debugging my own stuff, but that's just part of the reason breakpoints exist. Sometimes we wanto to study commercial games, stuff you didn't code, so you make use of more complex features. And it happens that I've seen a game perform an operation that should trigger a breakpoint but FCEUXD didn't catch it, probably because of the addressing mode used.
Oh I see. So you're saying things like indirect addressing don't break? Well that's too bad. Before, I thought studying game code would be near impossibly tedious and hard. But using break points and stuff makes it a lot easier, I suppose! That makes me want to go study a game's code now...
Hey Celius, something I was told about that I didn't understand, were conditions. That box you see that says 'Conditions' when you click to add a breakpoint, well, you can throw a value in there. So, if you want to check if a certain number is loaded into an address, you put that number in there.
So, I guess a decent example to talk about would be something in zeropage. If you have a byte set aside for something that only requires a #$01 or #$00, you can put one of those values in the 'Conditions' box. When that value is loaded into the address space that you set a point for, THEN it will break and let you see what's going on at that point. You might've already known that, but just in case I thought I'd say something : P
This is assuming we're talking about FCEUXDSP or whatever it's called. I've never used the Nintendulator debugger, myself.
Oh, I've never actually used that before. That's good to know, since I thought it was really complex to set up. I was thinking you had to make some big elaborate expression, but it's good to know you can just throw a value in there!
And yes, we are talking about the FCEUXD debugger. I really am not a fan of Nintendulator's debugging features compared to FCEUXD's either.
It's fun you say sta $4500, but myself I always found myself typing inc $ff for my breakpoints.
tokumaru wrote:
And it happens that I've seen a game perform an operation that should trigger a breakpoint but FCEUXD didn't catch it, probably because of the addressing mode used.
Could you add more precision ? I really found it weird. Normally it should always break no matter how it was read or write. Maybe I (or someone else) should try all ways to acess to a memory location. Maybe FCEU does ignore the tricky dummy read and dummy writes (for example if you do sta $4000,X with X = 15, $4015 is being read as well, but maybe that doesn't triger in FCEU).
Celius wrote:
Oh, I've never actually used that before. That's good to know, since I thought it was really complex to set up. I was thinking you had to make some big elaborate expression, but it's good to know you can just throw a value in there!
And yes, we are talking about the FCEUXD debugger. I really am not a fan of Nintendulator's debugging features compared to FCEUXD's either.
Something else I forgot to mention was that it's kind of picky with what you put into the Conditions box. For instance, on the values, you can't put the $ symbol. You can also use the && and || symbols to expand on things. So, some examples in the box would be:
A == #16
A == #0c || X == #03
X == #20 && Y == #04
I believe you can also use the greater-than/less-than signs, but don't hold me to it, as I can't remember for sure.