Bank Switching

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

Celius
Posts: 2158
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

Thank you very much. But still, how do you know when to write to $8000 or $9FFF? or $C000 or $DFFF? I still don't get that.
User avatar
kyuusaku
Posts: 1665
Joined: Mon Sep 27, 2004 2:13 pm

Post by kyuusaku »

When you want to write to "register 0", you write to any address between $8000 and 9FFF, "reg 1" is $A000-BFFF etc
Celius
Posts: 2158
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

Really? I could just write to like $8325 or something random like that? I don't know why you'd want to, but oh. Thanks!
User avatar
kyuusaku
Posts: 1665
Joined: Mon Sep 27, 2004 2:13 pm

Post by kyuusaku »

You probably wouldn't want to since there are no bus-conflict issues but you can.
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

For clarity, you usually want to write only to $8000, $A000, $C000, and $E000, unless you want to obfuscate your crazy bankswitching for copy-protection, but that's an advanced topic.
Celius
Posts: 2158
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

Okay, I am currently having much trouble doing a simple bankswitch. Look here at my code:

Code: Select all


.8bit
.bank 0 slot 3
.section "reset" FREE

reset:
   cld
   sei
   ldx #$FF
   txs
   lda #$02
   sta $E000
   lsr a
   sta $E000
   lsr a
   sta $E000
   lsr a
   sta $E000
   lsr a
   sta $E000
.ends

.bank 2 slot 3
.section "bott" FREE

   lda #$00
   sta $2000
   sta $2001
....


.bank 4 slot 5
.section "graphics" FREE
.incbin "finalfantasyvii.chr"
.ends

.bank 3 slot 4
.orga $FFFA
.section "vectors" FORCE
.dw 0
.dw reset
.dw 0
.ends
The bank is actually switching into $8000-$BFFF. The data will work correctly if you don't switch banks, so it's not something wrong with the code in bank 2. For some reason, the data just isn't being read. It's sitting there in bank 2. Nice working data, not being read. What's the deal here? A blank screen shows up, and it's just supposed to display "Hello World!" on the screen, but it's just a blank screen. If I take the bankswitch out of there, it works just fine. But for some reason, I do the bankswitch and nothing happens. The point of the demo is so I can understand how to bankswitch. Obviosly the bankswitch isn't neccissary, but you get the point. What's the deal, man?

EDIT: Hmm, the code works as soon as I do a soft reset, but when I do a hard reset, it doesn't work. What is up with that? Does it have something to do with the reset bit in $8000?
User avatar
Memblers
Site Admin
Posts: 4044
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Post by Memblers »

Celius wrote: EDIT: Hmm, the code works as soon as I do a soft reset, but when I do a hard reset, it doesn't work. What is up with that? Does it have something to do with the reset bit in $8000?
Yeah, you really better reset it first. I don't know if that's the exact problem, but on the real system I'd reset it and configure all the registers at start-up.
Celius
Posts: 2158
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

Yeah, it still makes me reset it. Does something wierd happen to the Program Counter? What exactly happens on soft reset that doesn't happen on hard reset? I know that the variables in RAM don't change from what they were when the system was running, unless you clear them at the beggining of your reset routine. And also pretty much whatever you stored in anything doesn't change unless you clear/change it at the beggining of your routine. Does anything wierd happen to the PC when you do a hard reset and switch banks?

EDIT: I have to say that this is really odd, because the data is being read, but nothing's happening. There are no graphics or anything, but the PC is at $8049, where the endless loop is, so it has to be doing something. When you do a soft reset, the graphics show up, and the pallete shows up, and "Hello World!" shows up in the middle of the screen. So it's like the endless loop works, but the pallete won't show up, and the graphics aren't there. This really stumps me. I have NO idea what's wrong.
Last edited by Celius on Sun Feb 26, 2006 4:43 pm, edited 1 time in total.
User avatar
Quietust
Posts: 1918
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Post by Quietust »

It would help a bit if you described exactly where each code block was located in memory.

Is your "reset" section at $8000-$BFFF or $C000-$FFFF? If $C000-$FFFF, it must be in the same bank as the vectors - on powerup/reset, the MMC1 drops the last 16KB of PRG ROM at $C000-$FFFF and a random (?) bank at $8000-$BFFF. If your startup code is located within $8000-$BFFF, it would not surprise me one bit if it worked in an emulator but crashed on a real cartridge.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
Celius
Posts: 2158
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

Okay, I still have to get it to work, and I'm wondering if you just do this:

Code: Select all


.bank 3
.org $C000
.section "reset" FREE

reset:
cld
sei
ldx #$FF
txs

lda #$00
sta $E000
sta $E000
sta $E000
sta $E000
sta $E000

.ends

....

.bank 0
.org $8000
.section "continue" FREE

blah blah blah reset routine code

Where does the PC go? Because if I do that in my code, the PC goes to $0000. I'm obviously missing something here. Can someone tell me what's wrong here? What am I missing?
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

If you are using an assembler that assumes 8 KB banks, then $C000 must be assigned to the second to last bank in the cart, and $E000 must be assigned to the last bank. For a 32 KB S*ROM, $C000 should be bank 2 and $E000 should be bank 3.
Celius
Posts: 2158
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

Hey! Sweet! All I had to do was put jmp $8000 after the switch to set the PC to $8000 after the switch in $C000-$FFFF. Thanks for all your help. I have one question though. Say your in bank 1 at $8342. When you switch to bank 2, would the PC still be at $8342? Or does it reset itself?

EDIT: Also, tepples, I use WLA-DX, so I tell the assembler to go by 16k PRG banks. I was fed up with NESASM's shit banks.
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Celius wrote:Say your in bank 1 at $8342. When you switch to bank 2, would the PC still be at $8342?
Yes. The program counter is a register internal to the CPU, which doesn't know nor care about banks. For an example of code that exploits this fact heavily, see The Wonderful World of NES/Fami Cart Copy Protection.
Celius
Posts: 2158
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

So would you have to have the bankswitching routine in the very beggining of each bank, and just jump past that if the PC is $8000? Like this:

Code: Select all

jmp past

switch1:
;switch to bank 1

jmp past

switch2:
;switch to bank 2

jmp past

switch3:
;switch to bank 3

....

switch16:
;switch to bank 16

past:
......
Would it be safe to have that at the beggining of every bank? If you want to switch to bank 2, you could just jump there, and switch to bank 2, and the PC would still be the same, and you'd have it jmp the the "past" lable, which is the lable that defines the beggining of the useful bank data. And does MMC1 only allow 256k of PRG? Because as I can see, there are only $0F banks you can switch to with MMC1. How does SUROM work then?
User avatar
Quietust
Posts: 1918
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Post by Quietust »

Why would you need a unique routine for each bank switch? You could just have one routine which takes the desired bank number via the accumulator.

Generally speaking, you shouldn't ever need to switch banks from the code you're currently executing (unless you're using a mapper which only supports 32KB PRG ROM banks).

All code+data related to a particular aspect of the game should reside in its own bank OR in the 'permanent' bank (if there's enough room) - if an aspect has more than 1 bank worth of data, then put its code in the permanent bank (so you can switch in the desired data) OR put a copy of the code in each switchable bank along with as much data as you can fit.

If, for some reason, you do need to switch banks from within a swappable code block, you should either have a copy of your current routine in the destination bank OR copy a code stub into RAM which performs the bankswitch and then jumps into the desired entrypoint in the new bank.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
Post Reply