Weird Vectors issue

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
User avatar
battagline
Posts: 152
Joined: Wed Sep 05, 2018 11:13 am
Location: Colorado
Contact:

Weird Vectors issue

Post by battagline »

So I'm creating some new demo code and I've been playing around with the ca65 .cfg file to try and understand it better (as you may know if you've answered some of my previous questions on this forum).

In my Nesteroids game when I set up the vectors I was doing it the way I learned from rainwarrior's demo code.

It looked like this:

Code: Select all

.segment "VECTORS" ; THIS IS THE LAST 6 BYTES OF THE FILE, USED AS ADDRESSES FOR INTERRUPTS
.word nmi
.word reset
.word irq
For some reason in my new code, the irq was getting executed instead of the nmi, so I had to reverse the order in that segment like this:

Code: Select all

.segment "VECTORS" ; THIS IS THE LAST 6 BYTES OF THE FILE, USED AS ADDRESSES FOR INTERRUPTS
.word irq
.word reset
.word nmi
I had been playing around with the .cfg files to try and understand them better. Here is the original:

Code: Select all

MEMORY {
    ZP:     start = $00,    size = $0100, type = rw, file = "";
    OAM:    start = $0200,  size = $0100, type = rw, file = "";
    RAM:    start = $0300,  size = $0500, type = rw, file = "";
    HDR:    start = $0000,  size = $0010, type = ro, file = %O, fill = yes, fillval = $00;
    PRG:    start = $8000,  size = $8000, type = ro, file = %O, fill = yes, fillval = $00;
    CHR:    start = $0000,  size = $2000, type = ro, file = %O, fill = yes, fillval = $00;
}

SEGMENTS {
    ZEROPAGE: load = ZP,  type = zp;
    OAM:      load = OAM, type = bss, align = $100;
    BSS:      load = RAM, type = bss;
    HEADER:   load = HDR, type = ro;
    CODE:     load = PRG, type = ro,  start = $8000;
    TABLES:  load = PRG, type = ro,  start = $E000;
    RODATA:   load = PRG, type = ro;
    VECTORS:  load = PRG, type = ro,  start = $FFFA;
    TILES:    load = CHR, type = ro;
}
And this is the new version that was calling the irq instead of the nmi:

Code: Select all

MEMORY {
    ZP:     start = $00,    size = $0100, type = rw, file = "";
    OAM:    start = $0200,  size = $0100, type = rw, file = "";
    RAM:    start = $0300,  size = $0500, type = rw, file = "";
    HDR:    start = $0000,  size = $0010, type = ro, file = %O, fill = yes, fillval = $00;
    PRG:    start = $8000,  size = $8000, type = ro, file = %O, fill = yes, fillval = $00;
    CHR:    start = $0000,  size = $2000, type = ro, file = %O, fill = yes, fillval = $00;
}

SEGMENTS {
    FASTVARS: load = ZP,  type = zp;
    OAM:      load = OAM, type = bss, align = $100;
    VARS:     load = RAM, type = bss;
    HEADER:   load = HDR, type = ro;
    CODE:     load = PRG, type = ro,  start = $8000;
    ROMDATA:  load = PRG, type = ro,  start = $E000;
    VECTORS:  load = PRG, type = ro,  start = $FFFA;
    IMG:      load = CHR, type = ro;
}
Any idea why the vectors segment might work out differently?

Thanks
A few of my web games
https://www.embed.com
Or if you're bored at work
https://www.classicsolitaire.com
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Weird Vectors issue

Post by rainwarrior »

No, you can't rearrange the vectors like that, this order is built into the hardware.

If you're getting the IRQ or NMI happening unexpectedly, the problem is going to be either with your IRQ/NMI handler routines, or with your code that sets up (or disables) the IRQ devices or NMI.

Your CFG looks fine, though I'd recommend keeping the ZEROPAGE segment with that original name. That name is special and indicates to the assembler that the segment is in fact on the zero page.

You can tell it that other segments are on the zero page too, but it requires an annotation on your .segment directive:

Code: Select all

.segment "FASTVARS" : zeropage
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Weird Vectors issue

Post by koitsu »

Re: vectors: this is a 6502 architecture thing. The vectors must be at $FFFA-FFFF for any of them (NMI, RESET, IRQ/BRK) to work.

$FFFA-FFFB: NMI
$FFFC-FFFD: RESET
$FFFE-FFFF: IRQ/BRK

http://wiki.nesdev.com/w/index.php/CPU_memory_map

They cannot be rearranged or changed or moved. They must always reside at those addresses.

This probably helps explain why most (but not all!) mappers have a "fixed bank" that tends to be at $C000-FFFF. I'm intentionally avoiding talking about mappers that let you swap in/out $C000-FFFF. Not worth going into in this thread. But just wanted to point out the "why", re: fixed bank.

You can check to see what the values are at each respective vector in the ROM itself by using either a hex editor, or emulator with a debugger that will show you them.

If you had a situation where on NMI your IRQ/BRK handler was being called, or where in IRQ your NMI handler was being called, you have a bug of some sort in your program, or the addresses at those vectors are wrong (e.g. point to the wrong routines). There's no other possibility -- those are it.

Most emulators will let you debug this situation with NMI quite easily, but the failsafe way is to look at where the NMI vector points, examine the code there, and ensure it's correct (what's in your asm files vs. what's in the debugger). If it looks correct, add a breakpoint at the start of NMI routine and then in the emulator choose "Run one frame", or just do Continue/Run and wait until the breakpoint gets hit.
User avatar
battagline
Posts: 152
Joined: Wed Sep 05, 2018 11:13 am
Location: Colorado
Contact:

Re: Weird Vectors issue

Post by battagline »

rainwarrior wrote:If you're getting the IRQ or NMI happening unexpectedly, the problem is going to be either with your IRQ/NMI handler routines, or with your code that sets up (or disables) the IRQ devices or NMI.
I think you're right... stepping through the reset, it looks like it's hitting a BRK somewhere... not sure why.
A few of my web games
https://www.embed.com
Or if you're bored at work
https://www.classicsolitaire.com
User avatar
battagline
Posts: 152
Joined: Wed Sep 05, 2018 11:13 am
Location: Colorado
Contact:

Re: Weird Vectors issue

Post by battagline »

Ok, so I changed some macros in the reset vector to procedures. For some reason when the procedure calls the rts it jumps to address $0001. I'm trying to figure out what's going on there, but if someone has an idea of what I'm doing wrong, please let me know.

Thanks for all your help
A few of my web games
https://www.embed.com
Or if you're bored at work
https://www.classicsolitaire.com
User avatar
pubby
Posts: 583
Joined: Thu Mar 31, 2016 11:15 am

Re: Weird Vectors issue

Post by pubby »

I mean interrupts use RTI instead RTS. Is that the problem?

no wait I think I misunderstood what you were saying
User avatar
battagline
Posts: 152
Joined: Wed Sep 05, 2018 11:13 am
Location: Colorado
Contact:

Re: Weird Vectors issue

Post by battagline »

pubby wrote:I mean interrupts use RTI instead RTS. Is that the problem?

no wait I think I misunderstood what you were saying

So I changed my clear_ram procedure to the following and it worked:

Code: Select all

.proc clear_ram
	lda #0
	ldx #0
	clear_ram_loop:
		sta $0000, X
;		sta $0100, X
		sta $0200, X
		sta $0300, X
		sta $0400, X
		sta $0500, X
		sta $0600, X
		sta $0700, X
		inx
		bne clear_ram_loop
    rts
.endproc
I commented out the place where it's clearing the stack. I guess when it was a macro it didn't need the stack. I'm not sure if this would have been a problem before, or could be a problem now.

Any thoughts?
A few of my web games
https://www.embed.com
Or if you're bored at work
https://www.classicsolitaire.com
User avatar
pubby
Posts: 583
Joined: Thu Mar 31, 2016 11:15 am

Re: Weird Vectors issue

Post by pubby »

Yeah the return address is stored on the stack, so if you clear the stack then you're wiping away the return address.

RTS adds 1 to the value before jumping, so that's why it's going to $01.
User avatar
Memblers
Site Admin
Posts: 4044
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Re: Weird Vectors issue

Post by Memblers »

This is when a trace log comes in handy. FCEUX has one, other emus might.

You might need to create a break point so it will stop where you want, but the trace log will then let you look at the all the previous instructions that ran, up to that point.

Solved before I posted it, but yeah, trace logs.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Weird Vectors issue

Post by koitsu »

Re: any thoughts?: yup. If you were using the stack prior to zeroing it out, you'd lose what was previously pushed on. That affects ANYTHING that uses the stack, which includes stuff like JSR/RTS, RTI, and so on.

I'm not going to get into a debate about this, but in general this is why I don't subroutine-ise system init/setup routines, as all it takes is me moving a "clear RAM" routine to sometime *after* I've done something that uses the stack to potentially cause problems. I tend to just have a single macro or single bunch of code (tend to prefer the latter) that does it all. I get really ticked off when I see people over-analysing system init/setup routines and trying to "make them all super nice and modular and blah blah blah" -- it isn't worth worrying about/hem-hawing over. It's done once at reset.

In general, I recommend you **do** clear/zero RAM (including the stack), but do so ASAP -- i.e. before you start JSR'ing to routines or whatever else. It should be one of the first things you do. Same goes for pre-initialising PPU RAM and the like (be sure to set all the palette values to $0F ASAP too, so that any previous graphics not yet cleared out become black).

There's one case where zeroing ZP/RAM on RESET isn't desired: some games *intentionally* do not clear/zero parts of memory on RESET, allowing for fun easter eggs. A good one is Zanac's stage select: you RESET (soft reset, not hard power-cycle!) the system 13 times, then press Start at the main menu, then use Left/Right to pick what stage you want to start on. The way this works is pretty easy: they only clear memory location $019A (RAM) on power-on, otherwise on a soft RESET, they increment it by 1. There are some other variables involved too, so the code logic is not as obvious/simple as something like lda $019a / cmp #13 / beq AllowStageSelect -- it's more convoluted. How they differentiate power-on vs. RESET is cute but is a subject for another thread. There's only one risk involved here: they assume that the value, on a fresh power on (say, after a NES had been powered off for a few minutes), will contain 0. It's not necessarily guaranteed, but it's how the game was programmed, and a fun/cool easter egg. (I've never seen this fail/mess up on a real NES, but it's possible. There's no sense in discussing power-on values of ZP/RAM either, there is a massive thread on the subject already, and quality emulators let you pick how you want the memory to be initialised on power-on.)

Just something to keep in mind if you ever consider something cute like this.
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Weird Vectors issue

Post by rainwarrior »

Since you've noticed that a BRK triggers an IRQ, I might point out that this is the reason I set fillval=$00 in my example. The $00 is the BRK opcode, and until your ROM starts to get full the majority of accidents with the stack will end up making an RTS to somewhere filled with $00 and immediately causing a BRK. Clearing RAM to 0 similarly helps with this, as you've just discovered.

If you're not otherwise using IRQ for anything, I find this is a convenient way to catch some kinds of errors during development (usually problems with PHA/PLA). You can put a breakpoint on your IRQ handler, or maybe some infinite loop in there will make it easy to spot when that happens. In my last project I actually put a crash diagnostic screen in my IRQ handler.
User avatar
dougeff
Posts: 3079
Joined: Fri May 08, 2015 7:17 pm

Re: Weird Vectors issue

Post by dougeff »

BRK was designed with debugging in mind.

On 6502 computers, they would have the BRK vector jump to some code that prints an error message on the screen and print the contents of the registers, and maybe pop the last address off the stack (where the BRK was) and print that. Or print the contents of a RAM address that you're watching.

This would aid in debugging a program, as they would intentionally insert / patch 0s (BRK) at specific points in the program to halt the program at that point.

These BRKs were called "breakpoints".
nesdoug.com -- blog/tutorial on programming for the NES
User avatar
battagline
Posts: 152
Joined: Wed Sep 05, 2018 11:13 am
Location: Colorado
Contact:

Re: Weird Vectors issue

Post by battagline »

Thanks everyone. It turned out not to be the issue I thought it was, but once again I feel like my understanding has been advanced.
A few of my web games
https://www.embed.com
Or if you're bored at work
https://www.classicsolitaire.com
Post Reply