Help with noob problems in my noob code?

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

Skidlz wrote:I use FCEUXD/FCEU and it has always worked.
But you must make sure it runs elsewhere too. Trusting a single emulator is a bad idea.
Nestopia gives the error "CPU Jam!" when I add a NOP.
Yeah, "CPU Jam" is when things get really out of control and stuff that shouldn't be executed as code is.

I'm out of ideas now. If you post the ROM (the one that screws up) I'd take a quick look in a debugger to see if I can find the problem.
It also refuses to run with ".inesprg 2"
Yeah, I don't know much about NESASM, so I'm not sure what's happening here. Anyway, I'd be willing to take a look at the ROM if you post it.

EDIT: I'm taking a look at the ROM without the error to see if I can find something, but the one with the error would be more interesting.
User avatar
Skidlz
Posts: 50
Joined: Sun Nov 11, 2007 5:24 pm

Post by Skidlz »

EDIT: I'm taking a look at the ROM without the error to see if I can find something, but the one with the error would be more interesting.
Well that's easy enough to do. I just added a nop on line 191 just after:

Code: Select all

lda $4016  ; load RIGHT Status
and #1
http://www.mediafire.com/?sharekey=423a ... b9a8902bda

It looks like if you add any command anywhere and assemble, it will fail.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

Skidlz wrote:Well that's easy enough to do.
Only I don't use NESASM, so I can't assemble your sources...

Good news: I found the problem. It's a branch that's out of reach, and it scares me that NESASM will not throw an error because this!

Near the end of the moving logic you have "BNE infinite". Branches have a limited reach, and adding as much as a "nop" puts that command too far from the label "infinite", so the relative displacement is miscalculated (a good assembler would throw an error instead of miscalculating it!), and when this command is executed the program counter goes crazy and the program crashes.

The generic solution for when branches are out of reach is to check for the opposite condition, skipping over a JMP instruction to the place you wanted to branch to. So you could replace this:

Code: Select all

	BNE infinite
with this:

Code: Select all

	BEQ skip
	JMP infinite
skip:
But in your case it would probably be easier to change this:

Code: Select all

   BNE infinite
   dec Direction
   JMP infinite 
into this:

Code: Select all

	BNE skip
	DEC direction
skip:
	JMP infinite
Anyway, keep in mind for future reference that branches shouldn't be used to jump across large distances. And it scares the shit out of me that NESASM will assemble the program with an incorrect displacement rather than throw an error.

BTW, I seem to remember now that NESASM banks are 8KB in size, so you are in fact making a valid ROM with 16KB of PRG-ROM.
User avatar
Skidlz
Posts: 50
Joined: Sun Nov 11, 2007 5:24 pm

Post by Skidlz »

Only I don't use NESASM, so I can't assemble your sources...
Not that it matters but, I included NESASM.exe in the zip.

I remember running into this problem but I thought it was with all commands that goto an address. I didn't know branches were more limited than JMP's.

Everything you said makes perfect sense. Anything added inside of the infinite loop will push the branch further from the address it's branching to.
That *is* really miserable that the assembler doesn't say anything.

Thanks so much! I love when a problem gets resolved and you learn something.

Just wondering, how did you catch it?
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

Skidlz wrote:I love when a problem gets resolved and you learn something.
That is the idea! =)
Skidlz wrote:Just wondering, how did you catch it?
FCEUXD's debugger. When the ball approached the paddle I started tracing instruction by instruction, until that branch sent the PC forward (as opposed to backwards, as expected) to a place with lots of 0's (which the CPU interprets as BRK's). As consequence of the BRK command the CPU jumped to the location pointed by the IRQ vector, $0000 in your case (although I advised you to have and actual IRQ routine with just an RTI instruction in it, not that it would save in this case, as the CPU was already lost when the IRQ happened, but still). well by that time the CPU was already completely lost and was trying to execute your variables as code, which is never good.
User avatar
Skidlz
Posts: 50
Joined: Sun Nov 11, 2007 5:24 pm

Post by Skidlz »

tokumaru wrote:well by that time the CPU was already completely lost and was trying to execute your variables as code, which is never good
Ha ha ha. True and hilarious.
FCEUXD's debugger
I'm going to have to learn how to use that.

Thanks a ton.
User avatar
Kasumi
Posts: 1293
Joined: Wed Apr 02, 2008 2:09 pm

Post by Kasumi »

For the record: You're using an old version of nesasm. The newest one (nesasm3) says the branch is out of range when one adds a nop there as expected. http://www.nespowerpak.com/nesasm/NESASM3.zip
User avatar
Skidlz
Posts: 50
Joined: Sun Nov 11, 2007 5:24 pm

Post by Skidlz »

Kasumi wrote:For the record: I'm pretty sure you're using an old version of nesasm. The one I have (nesasm3) says the branch is out of range when I add a nop there. http://www.nespowerpak.com/nesasm/NESASM3.zip
Yeah, I've got multiple versions floating around my hard drive and I was in fact using the older one. Find and replace time.
Thanks for brining that up. Might save me and the forums some headaches.
User avatar
bigjt_2
Posts: 82
Joined: Wed Feb 10, 2010 4:00 pm
Location: Indianapolis, IN

Post by bigjt_2 »

tokumaru wrote:
Skidlz wrote:I saw something in another post about NESASM treating banks as 32K instead of 16K, or some such thing.
It doesn't really matter how NESASM treats them, iNES files always counts PRG banks in 16KB units. Anyway, it's a fact that you are trying to assemble 32KB of PRG ROM, and if ".inesprg 1" writes a 1 to the PRG bank count field in the header, it's wrong. Try using a 2 here and see if it makes any difference.
Hey tokumaru;

How precisely do I tell if I have more than one bank? My asm file for a collision test I'm working on right now is 16.2 KB, but does an assembler count all my ;comments as part of the memory?

Also, my collision test is running on FCEUXD, but is running very buggy on Nestopia and Nintendulator. I suspect it might be the case you mentioned above, where I am trying to run too much memory on one bank. I tried changing the ".inesprg 1" to ".inesprg 2" just in case my .prg is too large, but now all I get is a blank screen in all three emulators. Is there anything additional I need to add to the code besides changing the inesprg in the header?

Keep in mind I'm also using NESASM 3, which might also be part of the problem. I know you and many on here use ASM6 instead of NESASM, and I'm thinking of making the switch.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

bigjt_2 wrote:How precisely do I tell if I have more than one bank?
Does NESASM have the capability to output a table of debugging symbols? Usually you can estimate the ROM size from that. Otherwise look at it in a hex editor.
My asm file for a collision test I'm working on right now is 16.2 KB, but does an assembler count all my ;comments as part of the memory?
No. Each line of assembly language code becomes 1 to 3 bytes of object code, except for bulk data directives like .byt, .addr, or .incbin. Indentation doesn't show up in the object code, nor do comments.
Also, my collision test is running on FCEUXD, but is running very buggy on Nestopia and Nintendulator.
Are you exceeding vertical blank time to update the VRAM?
I suspect it might be the case you mentioned above, where I am trying to run too much memory on one bank. I tried changing the ".inesprg 1" to ".inesprg 2" just in case my .prg is too large, but now all I get is a blank screen in all three emulators. Is there anything additional I need to add to the code besides changing the inesprg in the header?
As I understand it, you need to put something in at least bank 0 and bank 3 if you plan to use .inesprg 2. (Each unit of .inesprg size is worth two 8 KiB banks.) Interrupt handlers (nmi, reset, irq) and vectors go in the last bank.
Keep in mind I'm also using NESASM 3, which might also be part of the problem. I know you and many on here use ASM6 instead of NESASM, and I'm thinking of making the switch.
Everyone ends up on CA65 eventually. It's the only 6502 assembler toolchain whose name is a valid hexadecimal number :-)
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

bigjt_2 wrote:How precisely do I tell if I have more than one bank?
Having more than 1 bank is not something that "just happens", it's something you have to plan for. If your code spills out of the bank there should be an error message somewhere (even though NESASM is known for generating invalid ROMs instead of reporting errors in some cases). Once you run into this problem you have to start writing code in another bank, and update the iNES header when necessary.
My asm file for a collision test I'm working on right now is 16.2 KB, but does an assembler count all my ;comments as part of the memory?
No, the size of the source file has no direct relation to the size of the resulting binary. Assembled code is usually much smaller than the source code that generated it.
Also, my collision test is running on FCEUXD, but is running very buggy on Nestopia and Nintendulator. I suspect it might be the case you mentioned above, where I am trying to run too much memory on one bank.
It's hard to say without looking at the ROM, but there are several other things that could have gone wrong. FCEUXD is not very accurate, so if your code has bugs they are more likely to show up on Nintendulator and Nestopia.
I tried changing the ".inesprg 1" to ".inesprg 2" just in case my .prg is too large, but now all I get is a blank screen in all three emulators. Is there anything additional I need to add to the code besides changing the inesprg in the header?
I don't know much about NESASM, so I can't give you a straight answer... I think you have to specify where each bank starts, using ".bank" followed by the number (0, 1, etc) but I'm not sure.
Keep in mind I'm also using NESASM 3, which might also be part of the problem. I know you and many on here use ASM6 instead of NESASM, and I'm thinking of making the switch.
Yeah, it's hard to make anything serious with NESASM. It's not impossible, but you have to learn how to circumvent a few problems if you want to succeed with it.

ASM6 is great, because it's really easy to use. You don't have to configure anything, just ask it to assemble a file and it does, and as long as your source code is correctly structured, a complete NES ROM is output. It is a generic 6502 assembler though, it's not specific to the NES, so it doesn't have automatic header generation or things like that. It's your responsability to make sure the iNES header is valid and correctly placed, and the same goes for each PRG and CHR bank. But if you have a good understanding of the structure of a NES file, this is not a problem.

The problem with CA65 and other "professional" assemblers is that you have to configure a lot of things before being able to assemble anything, and for each project that uses a different mapper you are likely to change these configurations. You also have to deal with object files an linking, something that to this day I do not understand. Too much bureaucracy for me, I like to go straight to what matters.
User avatar
MetalSlime
Posts: 186
Joined: Tue Aug 19, 2008 11:01 pm
Location: Japan

Post by MetalSlime »

If it's running in FCEUX then it sounds like NESASM3 is producing a .nes file that will load and run. If I understand you correctly, you said that Nestopia and Nintendulator can load the .nes file too but that the collision detection is buggy? It sounds like it's a bug in your program logic rather than a problem with assembling the ROM.

Could you attach your .asm source file?
MetalSlime runs away.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

MetalSlime wrote:Could you attach your .asm source file?
If the collision detection alone is over 16KB it will be very hard for us to catch anything wrong.
User avatar
MetalSlime
Posts: 186
Joined: Tue Aug 19, 2008 11:01 pm
Location: Japan

Post by MetalSlime »

tokumaru wrote:
MetalSlime wrote:Could you attach your .asm source file?
If the collision detection alone is over 16KB it will be very hard for us to catch anything wrong.
Could be, but it might be less code than you expect. He said his .asm file was 16k, which includes comments. I think I recognize his name from the nintendoage forums, so if he is working off the Nerdy Nights tutorials a lot of that space is likely data (eg, .db of a full background).

Even if we don't get into his collision code, at the very least we can check his iNES header and bank layout.
MetalSlime runs away.
User avatar
bigjt_2
Posts: 82
Joined: Wed Feb 10, 2010 4:00 pm
Location: Indianapolis, IN

Post by bigjt_2 »

tepples wrote: Does NESASM have the capability to output a table of debugging symbols? Usually you can estimate the ROM size from that. Otherwise look at it in a hex editor.

No. Each line of assembly language code becomes 1 to 3 bytes of object code, except for bulk data directives like .byt, .addr, or .incbin. Indentation doesn't show up in the object code, nor do comments.
Thanks, tepples. I didn't think the comments would be part of the object code, but it's good to have an expert confirm it.
tepples wrote: Are you exceeding vertical blank time to update the VRAM?
Actually, this didn't end up being the problem. But this is something I need to teach myself so I'm glad you brought it up. I understand what vblank is, but not how to calculate the update time. It's one of the many things on my list to figure out.
tokumaru wrote: If the collision detection alone is over 16KB it will be very hard for us to catch anything wrong.
No worries. From what you and tepples described I now know how to find my PRG size, and I can tell you this is definitely under 16 KiB.

Please keep in mind as you read this (and especially if you look at my amatuerish code in the .asm files) that I am a VERY green noob and not a programmer.

This is an uber-simple beginner collision test I made just to practice the basics. You basically are moving the blue square, and my goal was to make it stop whenever it collided with the reddish-brown square. I've been working on it a few days, and just now (finally) got it to work as I expected. Woo-hoo! I know, nothing too impressive, but one small step at a time! :-)

I have two versions of this file. At first, all my collision tests for right, left, down, up were in the sections for those respective keys. (That's the collision.asm file, and now it's working on all three emulators.) My collision wasn't working right at first, so I moved the relevant code to subroutines. Partly because I thought the code might be interfering with each other and subs might help, and partly because I wanted to practice writing subroutines and finding out what works and what doesn't.

It turns out that I was doing something wrong with writing the subs. Either I have typos or they're placed in the wrong place or something else altogether. If you assemble the collision_subroutines.asm and run it on Nintendulator or Nestopia, you'll see what I mean. Those two emulators scream, "this ROM is stupid! For God's sakes just make it stop!" FCEU, as I've been warned, is just like "Sure, man, do whatever ya want. I'm just gonna sit here and chill while your incorrect rom runs as though its flawless..." I think from now on I'm definitely testing my stuff on the first two, as I've read a comment from Sivak on Nintendo Age forums saying they're more accurate to a real NES. I've also seen plenty of people on this forum say the same thing, like tokumaru.

Anyway, I guess what I need to figure out now is what I'm doing wrong with my subroutines, as I mentioned above.

If any of you want to look at this, please feel free. My collision test code is very beginner, like I said. So if you have any tips on cleaning it up I'll be glad to take it. I know I've got a long way to go and a LOT to learn. And I imagine I'll have to change it for a second collision object. That's actually my next goal.

http://www.mediafire.com/?jxdjdznjmog
metalslime wrote: I think I recognize his name from the nintendoage forums, so if he is working off the Nerdy Nights tutorials a lot of that space is likely data (eg, .db of a full background).
I am actually using bunnyboy's tutorials, metalslime, as you'll see in the code. I've been bouncing between Nintendo Age and Nesdev here since I started getting into this a couple weeks ago. I've also been checking out your tummai games site, as well. Very cool, but most of is beyond my skill level at this point. I especially liked the button combos write up.

PS- Am I too off-topic for this thread? Do you guys need me to ask an admin to move it somewhere else?

PPS- Oh yeah, I also forgot to mention that I've noticed that annoying grey tile in the upper left-hand corner. For the life of me I can't figure out why the hell that thing is there. I know it's something I did, but I've just been kicking it down the road in regards to fixing it.
Post Reply