Hi, I am currently putting together a technical demo, and my demo requires that I switch banks. Like, alot. And I'm currently putting this demo together with NESASM, because my other assembler is a little more difficult to set up, and I'm not too familiar with some of the options. But I'm having trouble bankswitching with NESASM. Also, I'm not sure which bank to put what in while having multiple banks. Like if I set the inesprg bank number to 4, which bank does the vector go in? I've tried alot of things, and the screen just goes grey, and there's no graphics loaded, no pallete, no code was going on. I'm using CHR-RAM, incase that helps. Will someone help me? thanks.
On mappers with at least one hardwired PRG bank (i.e. just about everything but A*ROM, G*ROM, and Color Dreams), this hardwired bank is 1. the last bank in the ROM and 2. mapped into the areas where the 6502 CPU expects vectors. So put your vectors in the last bank.
You're using CHR RAM, but are you using CHR RAM on UNROM, SNROM, or AOROM? It makes a difference.
I'm using MMC1. One other thing I'm confused about is like SNROM and UNROM and stuff, I don't know where you guys figured that out, and what any of it means. Yeah, that's bad, I should've probably looked a while ago. So if I have 4 prg banks, I'd use bank 7 for vectors, and I tried using bank 6 to org at $C000, and that worked, but I'm not sure why. This is in NESASM terms, remember. I'm lost.
I've never heard of anyone making a PRG larger than 32kB with NESASM (seems like someone must have by now). So if noone can help you much, it's because you're doing something noones done before, heheh.
Myself, I never understand the purpose of NESASMs bank numbers even for small roms..
BTW, SNROM etc. are the names Nintendo gave their cart PCB types. See how many different types there are for MMC1? heheh
http://tripoint.org/kevtris/mappers/mmc1/
But from a coding point of view, they're mostly the same except the memory types, so don't worry about it too much.
So maybe I should just try making my demo on Wla-Dx, which is my other assembler? And when switching banks, you can just select a new bank, and org it at $8000 or $C000? And you just have one hard-wired bank of PRG, which is like bank 1, or whatever tepples said up there? So I could just go like this:
.bank 0
.org $8000
.....
.bank 1
.org $C000
....
.bank 2
.org $8000
....
.bank 3
.org $C000
.....
.bank 3
.org $FFFA
If that were my bank limit? Keep in mind, I'm using CHR-RAM. In the future, my project will be done with SUROM. But this is just a tech demo. I was wondering though, Why does it say 8k CHR RAM for SUROM on the MMC1 thing you showed me? Couldn't there be more CHR RAM? It's embedded in PRG, so what's the deal? Yeah, me and Bregalad are working on something really big, so it will need SUROM. He's doing the sound, I'm coming along on the engine for the game. But will that thing above work? I'm still a little lost. If I could be just a little more cleared up, I'll be good. Thanks a bunch!
NROM/CNROM: bank 0 at $8000, bank 1 at $A000, bank 2 at $C000, bank 3 at $E000
CHR RAM is always 8 KB, as this is the size of the pattern tables, unless you have one of those really crazy boards such as CPROM or Squeedo that has more.
Sorry, if anyone was dissapointed that I brought up this subject, but I am currently having problems with bankswitching. In Wla-Dx, I was able to first of all, make a 64k PRG 8k CHR Hello World demo, but I was also able to put my vectors in bank 1, and put my reset code in bank 0. But I'm still confused. Here is my set up:
bank 0 - reset $8000
bank 1 - code $C000
bank 2 - ? PRG space
bank 3 - ? PRG space
bank 4 - CHR data
How do I switch from bank 0 to bank 2/3? Can I just like randomly put "bank 2 org $8000" in the middle of my reset routine? or what?
EDIT: Is anyone alive anymore?
To see how to operate bankswitching, look at the docs for each
mapper. Usually it will consist of writes to ROM space.
If your assembler assumes 8 KB banks, and your mapper uses 16 KB banks, then you'll only be able to swap those banks in and out as a pair.
It would be cool if someone explained to me what these characters in these registers stand for/mean, that'd be really cool.
Code:
Addr 7654.3210 Function
$8000-$9FFF xxxC.FHMM Controls PRG/CHR switching sizes and mirroring
$A000-$BFFF xxxC.CCCC Selects the lower CHR bank
$C000-$DFFF xxxC.CCCC Selects the upper CHR bank
$E000-$FFFF xxxR.PPPP Selects a PRG bank and enables RAM
Celius wrote:
It would be cool if someone explained to me what these characters in these registers stand for/mean, that'd be really cool.
Code:
Addr 7654.3210 Function
$8000-$9FFF xxxC.FHMM Controls PRG/CHR switching sizes and mirroring
$A000-$BFFF xxxC.CCCC Selects the lower CHR bank
$C000-$DFFF xxxC.CCCC Selects the upper CHR bank
$E000-$FFFF xxxR.PPPP Selects a PRG bank and enables RAM
The page that you copied this table from has a description directly following the table. Spoiler: the capital letters represent bits or ranges of bits in the values written to the address ranges.
Okay, in both kevtris's and NESdevWiki's MMC1 docs, they talk about loading data into MMC1's registers. Okay, I get that, but what data are you writing to the registers? They don't say what to write to them. They just give you something like this:
LDA #$nn
STA $8000
LSR A
STA $8000
LSR A
STA $8000
LSR A
STA $8000
LSR A
STA $8000
What should #$nn be? And am I understanding correctly that you WRITE to the registers to LOAD them? And, this is kind of a dumb question, but why do you need to write to these registers?
Because it loads the registers serially (one bit at a time), as opposed to all bits in parallel. #$nn is the byte you're writing, look it up on that table you posted to see what to write.
You are writing a 5-bit number, one bit at a time. The number is interpreted depending on which address you write to last.
If you are writing to the CHR $0000 bank register, then write a CHR bank number that you want to switch into PPU $0000-$0FFF. If you are writing to the PRG bank register, write a PRG bank number that you want to switch into CPU $8000-$BFFF (usually).
As for "load" and "store": It's a store from the CPU's point of view but a load from the mapper's point of view.
Okay, I think I understand this mostly. I'm just confused about which address to write to. Like I don't know when to write to $8000 or $9FFF. So could you write say this to register 3:
lda #$03
sta $E000
lsr a
sta $E000
lsr a
sta $E000
lsr a
sta $E000
lsr a
sta $E000
To switch bank 3's data into $8000-$BFFF without any modifications to register 0? And could you just change swappable banks to 32k via register 0 to swap 2 16k banks at a time? Like swap banks 0 and 1 with 2 and 3? Not like swap 0 and 1 with 6 and 2, though, right? Am I understanding this correctly?
Yes.
Try configuring "reg0" with $0F. That gives you 16k swappable at $8000 like UOROM and 8k CHR swappable like CNROM, simple yet elegant.
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.
When you want to write to "register 0", you write to any address between $8000 and 9FFF, "reg 1" is $A000-BFFF etc
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!
You probably wouldn't want to since there are no bus-conflict issues but you can.
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.
Okay, I am currently having much trouble doing a simple bankswitch. Look here at my code:
Code:
.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?
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.
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.
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.
Okay, I still have to get it to work, and I'm wondering if you just do this:
Code:
.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?
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.
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.
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.
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:
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?
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.
If you do use 32kB banks, you'd have a copy of the code in the same place in every bank (including the reset vector). Or in RAM.
And SUROM I think uses one of the extra CHR page select bits for PRG.
Oh, I suppose you're right about the small routine thing. Yeah, I agree that that'd be alot better.
But when you're working on a project such as the one I'm working on, you NEED bankswitching. I'm working on a HUGE RPG, and when you get sucked into a battle, you'll want to switch banks, of course. And there'll be banks with enemy data in them that you'll want to copy data to RAM from, so bankswitching is absolutely neccisary.
Okay, I'm sorry, but really didn't understand what you guys were talking about by a copy of the same code in each bank in the same place when using 32k PRG banks. When you switch 32k PRG banks, is it like, you switch from bank 0 and 1 to 2 and 3 or something? Or like 0 and 1 to 4 and 5, or something like that? And you said that with SUROM they use one of the extra CHR bits to switch banks. How can you just manipulate the registers to use the CHR bits to bank switch? That doesn't make any sense. Please explain, if you will
.
Celius wrote:
Okay, I'm sorry, but really didn't understand what you guys were talking about by a copy of the same code in each bank in the same place when using 32k PRG banks. When you switch 32k PRG banks, is it like, you switch from bank 0 and 1 to 2 and 3 or something? Or like 0 and 1 to 4 and 5, or something like that?
You switch from any bank, to any bank. The point to having code at the same address is so you can just jump or JSR to it from any bank. What I did in that code on one program was keep track of the current bank, push it on the stack, set the new bank and JSR to the (banked) subroutine, then comes back, restores the old bank, and RTS's back to wherever.
Quote:
And you said that with SUROM they use one of the extra CHR bits to switch banks. How can you just manipulate the registers to use the CHR bits to bank switch? That doesn't make any sense. Please explain, if you will
.
It's just a matter of wiring on the board. They hooked one of the pins from the mapper up to the PRG instead of CHR chip, bankswitching output bits are just latched bits (basically one bit of memory) that could be hooked up to whatever.
Okay, so when using 32k banks, you can have 512k of PRG right? Because this is neccissary for my project. And it's just for bankswitching right? Like you still have 16k banks, but you switch 32k at a time? Or what?
And how would you code a game that runs with SUROM to use the 2 CHR bits to do bankswitching?
EDIT: Also, I don't know if JSRing to banks is that neccissary. I think that having a routine like this:
Code:
.org $8000
jmp +
ldx #5
;This is a routine that was jumped to with the value #$02 in A
- sta $E000
lsr a
dex
bne -
+
;whatever code you want here
I'd have that at the beggining of every bank, so I could jmp to it with a specific value in A so it would switch banks. But I should have a routine that takes saved High/Low adresses and jumps to them. That'd be helpful.
There was also a pirate MMC3 variant that uses the CHR bankswitcher to switch which 512k the MMC3 sees, so it can have up to 1024k PRG (with 8k chr ram). Fceu emulates it on standard mmc3, other emulators don't.
SUROM is needed for 512kb. No matter if you use 32kb or 16kb banks. If you use 32kb, the lowest bankswitching bit is "forced" to be zero, no matter how it actually is. So switch the 32kb bank 2 (or 3, no matter) in $8000-$ffff will switch the 16kb bank 2 in $8000-$bfff and 16kb bank 3 in $c000-$fffff. In my opinion, using 32kb bank is crazy in most cases, except if you're doing very tricky tricks, and I'll think to only use 16kb banks if I were you. I really ask how most Rare games does to use only 32kb bankswitching.
But, it's up to you to plan your own bankswitching strategies to get a larger rom. You don't have to think the most tricky it is, the best it is, because it isn't. If using SOROM, a particular bit in MMC1 reg 2 or reg 3 sets the MSB of bankswitching, so you'll need to upload 2 MMC1 regs when bankswitching. It isn't very complicated. Also, you won't need destroy a Dragon Warrior 3 or 4 card to get a real SUROM board fortunately. You can modify a simple Zelda cart to have a SUROM configuration.
Bregalad wrote:
In my opinion, using 32kb bank is crazy in most cases, except if you're doing very tricky tricks, and I'll think to only use 16kb banks if I were you. I really ask how most Rare games does to use only 32kb bankswitching.
GNROM, BNROM, and the Color Dreams board also have 32 KB PRG bankswitching. As long as you're not using DMC, it's easy to work around the bankswitching limitation using jump tables in RAM or jump tables duplicated through the last 1 KB of each PRG bank.
Yeah, it is do-able, but it still is much easier to work with one hardwired bank, I think. 32kb banks maybe allow you to place all data and code related together in the same bank.
For example, you'll have 32kb with all maps and all code that do something with the maps, 32kb with all music and you music replay code, 32kb with all text of the games and all programm that shows text, etc...
If you want more than 32kb, you'll have to be very tricky.
In a standard configuration, you'd rather have data in the bankswitched part and code in the hardwired place, OR have both code and data bankswitched.
Thanks for replies. But I'm just wondering if 32k banks are neccissary for SUROM? Do you NEED 32k banks for SUROM? If not, how would you CODE MMC1 to use the CHR bits for bankswitching?
No, you don't need to use 32 KB banks with the high bit mappers, but it'd be wise to have mapper init code in each "fixed" bank.
Celius wrote:
Thanks for replies. But I'm just wondering if 32k banks are neccissary for SUROM? Do you NEED 32k banks for SUROM? If not, how would you CODE MMC1 to use the CHR bits for bankswitching?
Read this again :
Quote:
--------------------------------------------------------------------------------
SUROM is needed for 512kb. No matter if you use 32kb or 16kb banks. If you use 32kb, the lowest bankswitching bit is "forced" to be zero, no matter how it actually is. So switch the 32kb bank 2 (or 3, no matter) in $8000-$ffff will switch the 16kb bank 2 in $8000-$bfff and 16kb bank 3 in $c000-$fffff. In my opinion, using 32kb bank is crazy in most cases, except if you're doing very tricky tricks, and I'll think to only use 16kb banks if I were you. I really ask how most Rare games does to use only 32kb bankswitching.
If you don't understand ask about what you don't understand and don't just re-ask the whole question.
Any I don't see what you mean by coding the MMC1. You just have to make sure to understand that one bits of the MMC1 registers that normally apply to CHR selection bits is the upper bit of the PRG-ROM selection value, and if you want more deail read the wiki or hack Dragon Warrior 3.
Oh! So because you're using CHR RAM, and have 0 CHR banks, if you write to the CHR switching bit, it'll swap PRG instead of CHR banks?
No, it's because the SUROM board is wired differently, such that the CHR high address pins go to PRG instead of CHR.
CHR RAM games using the MMC1 can be reconstructed from iNES files as follows:
- Mapper 1, no CHR ROM, PRG ROM 16-256 KB => SNROM
- Mapper 1, no CHR ROM, PRG ROM 512 KB => SUROM
Okay, I'm going to ask my question, hopefully for the last time, but way clearer.
How is one supposed to code a game that runs with SUROM, and have it run on an emulator? I know you can rewire it on an actual cartridge, but how do you make it run via an emulator? How do you tell the ROM to use the CHR bit for PRG bankswitching? You can't just magicly have the ROM use the CHR bit for switching PRG banks, you have to do something to the ROM to have it do that. What is that something?
Celius wrote:
How do you tell the ROM to use the CHR bit for PRG bankswitching?
You make the PRG ROM 512KB long. Seriously, this is how most (if not all) emulators support the NES-SUROM board when presented as iNES mapper 1.
Really? Okay. Thank you Quietustsan
. You have answered my question. Thanks =)!
Actually bankswitching under a SUROM board is just as simple as a normal MMC1 card. Just add a similar code :
Code:
Bankswitch
sta BankNmr
pha
and #$0f
jsr WriteMMC1Reg3
pla
and #$10
jmp WriteMMC1Reg1
WriteMMC1Reg1
sta $bfff
lsr A
sta $bfff
lsr A
sta $bfff
lsr A
sta $bfff
lsr A
sta $bfff
rts
WriteMMC1Reg3
sta $ffff
lsr A
sta $ffff
lsr A
sta $ffff
lsr A
sta $ffff
lsr A
sta $ffff
rts
Got it ?
Bregalad wrote:
Actually bankswitching under a SUROM board is just as simple as a normal MMC1 card.
Except as I understand it, the "fixed" bank normally present at $C000-$FFFF also gets bankswitched. Either you need to use identical "fixed" banks or you need to do some jump table stuff to move between the banks safely.
Huh ?? I didn't understood it that way. I was sure that the fixed bank was the last 16kb bank. Now you said it... I'll watch at DW 3 and 4 better.
The "fixed bank" is, in this case, the last 16KB of the current 256KB selected.
Awww.... that hurts. Thanks for clearing that.
So, the SUROM has some 32kb switching aspects... I mean the main PRGROM bank have to be swapped. Two options are to do everything with 32kb switching.
The option I'd do is to copy NMI, IRQ and very important routine in both main banks. Then, the non-important routines that are affilated with the first 256kb of data would come in bank 15 and the routines affilated with the second 256kb of data would code in bank 31.
SUROM looks a lot like a multicart mapper. In fact, the Final Fantasy multicart for Famicom used the same technique. So if you have two nearly separate game engines, stick them in separate banks. I don't know what Celius's demo is supposed to do, but in an RPG, you could stick all the battle related stuff in one bank and all the map related stuff in the other bank.
Great trick, tepples. Since your battle and menu routine would have nothing in common, not even the NMI routine, I think that really is a great idea. I'd stuck "rest" such as title screen and menus with battle, beacuse battle data is most probably getting a bit smaller than playfield data.
However, most FF1 and FF2 engine is the same. All the engine that move characters and playfield arround is the exact same in both games.
Only menu, music, intro and ending really differs (in an engine point of view, of course).
So what I'm understanding is that you have to have two banks with vectors in them. The 15th bank of PRG in the first 256k, and then the 15th bank in the second 256k? But I'm hearing about $C000-$FFFF being switched as well. Why would you do that? Why couldn't you just switch $8000-$BFFF, leaving $C000-$FFFF fixed to the 15th bank of whatever 256k your in? I don't think you have to be switching $C000-$FFFF. I see no reason why it would have to be switched.
My DEMO doesn't really require SUROM. My GAME requires SUROM. Many banks full of maps, like, MANY banks full of maps. And it also requires many banks full of graphics, and many banks full of enemy data. Don't forget text, and event data as well.
Yes. An NMI or especially a reset could happen at any time.
Celius wrote:
Why couldn't you just switch $8000-$BFFF, leaving $C000-$FFFF fixed to the 15th bank of whatever 256k your in? I don't think you have to be switching $C000-$FFFF. I see no reason why it would have to be switched.
The reason is that the MMC1 does the OR logic needed for that on it's PRG outputs, but not on its CHR outputs. Since PRG A18 is wirted to CHR A16, CHR A16 won't be ORed with PRG A14, which is the only way to have a hardwired bank (in other word, when the programm counter is above $c000, so bit 14 set, all bankswitching lines are forced to be one with the OR logic internal to MMC1 to have the last bank acceded).
I'd say to first code your game as a normal SNROM game. The day you'll run out of space (wich isn't probably today), you'll have to think about more complex SUROM bankswitching, and splitting your "hardwired" space in two banks. Since WLA has a special option to keep two track of the same code in two banks, it won't cause problem to duplicat some essencial code, such as the Reset code.
Okay, I'm sorry to keep this thread going, but I thought it'd be better to post here than to start a new one.
Is it possible to keep track of the Program Counter? Because I want to switch banks, and then jump back to the same place. Is it possible? Hey, Memblers, you were saying about jsring to banks. I said it wasn't neccissary. I lied. How do you do such a thing?
Celius wrote:
Is it possible to keep track of the Program Counter?
When you execute a JSR command the PC is stored on the stack. You could JSR to a routine that will pull that and use as you want. AFAIK, the only way to read the PC is getting it from the stack.
Celius wrote:
Hey, Memblers, you were saying about jsring to banks. I said it wasn't neccissary. I lied. How do you do such a thing?
What helped for me was having a byte in RAM that keeps track of your current selected bank. There's a couple JSR's needed (so the routine can be called from anywhere). Pretty much like this, with music code for example:
Code:
jsr playmusic ; .org anywhere
playmusic: ; .org in fixed bank, RAM or manually mirrored PRG for 32kB pages
lda current_bank
pha
lda #NSF_play_banknumber
sta current_bank
sta $8000 ; mapper write
jsr NSF_play
pla
sta $8000 ; insert mapper write here
rts
Whenever you bankswitch, then update the current_bank at the same time. Pushing it on the stack like that makes it recursive, so you could JSR between several banks within that routine and still return to the original (if you really wanted to). But it complicates the code a bit, it could be simplified if you don't need to do anything really fancy.
MMC1.
I took the game from the example (NESASM3 source) and added 1 bank of graphics to it.
Code:
.bank 13
.org $A000
Graphics2:
.incbin "graphics2.nes"
.incbin "graphics2.nes"
.bank 14
.org $C000 ;;8KB graphics in this fixed bank
Graphics:
.incbin "graphics1.nes"
.incbin "graphics1.nes"
Uncommented the following code:
Code:
bankvalues: ;;This is the old bank switching code for UNROM
.db 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
BankSwitch:
lda sourceBank
tay
sta bankvalues, y ;;make sure byte written = byte in ROM so there is no bus conflict
rts
What else should I do? How to switch bank of graphics to bank 13? Now the game shows the graphics from the bank 14.
No one will help?
bank switching in MMC1 is nothing like bankswitching in UNROM. You have to write the bits sequentially. Check the
wiki!
I can not write the working code for NESASM3 example (cyoammc1)...
Could you help with the working code? It is for this example.
I beg you to help, I almost made my game. And I lack only the correct code for switching banks of graphics. I can not write the code myself. I've already tried it ..
Have you tried the code snippets? there's nothing more to it, I mean, it's pretty straightforward, it's just:
Code:
lda #<VALUE> ; vertical mirroring, fixed $C000, 8 KB CHR pages
sta <REG> ; (use $0F instead for horizontal mirroring)
lsr a
sta <REG>
lsr a
sta <REG>
lsr a
sta <REG>
lsr a
sta <REG>
Where <REG> is the register address you want to write <VALUE> to. You can check the port addresses and what to write to them here
http://wiki.nesdev.com/w/index.php/MMC1You first set up everything writing to port $8000 (mirroring a bank mode). You can change your CHR ROM banks individually using $A000 and $C000, and you can set your PRG bank writing to port $E000.
Help me to insert the code here:
http://forums.nesdev.com/download/file.php?id=9998It will take you 1 minute. (You will spend more time if you try to explain to me how to do it).
Do you think I have not tried to do this? I can not do it. Help me please not by advice, but by working example. I wrote - I can not do anything on my own. (Forgive me if I do not write clearly, I know English very badly ...)
I could give my own project, but there all the comments are in Russian. I built my game based on the example from NESASM3.
Sorry, I don't use NESASM3, nor really code in assembly, nor have the time to try and understand a whole bunch of assembly code written by somebody else
I understood you want to page in bank 13 to copy CHR data to CHR-RAM, so paging in bank 13 of PRG in MMC1:
Code:
lda #13 ; Set bank 13
sta $E000 ; $E000 = set PRG bank.
lsr a
sta $E000
lsr a
sta $E000
lsr a
sta $E000
lsr a
sta $E000
Alas ... This code does not work for me in this rom.
In my example:
Code:
.inesprg 8 ; 8x 16KB PRG code = 128KB
.ineschr 0 ; 0x 8KB CHR data = CHR RAM
.inesmap 1 ; mapper 1 = MMC1
Graphics are taken from the penultimate bank. And I do not know how to change the bank of graphics to another one or add one more and switch him.
This is a CHR-RAM board, so you have to page in the bank with the graphics and copy them to VRAM via $2006/$2007 writes. The code I posted is for the first part (page in a PRG-ROM bank). You have then top copy the pattern data to the VRAM.
Learn about CHR-RAM here
http://wiki.nesdev.com/w/index.php/CHR_ ... to_CHR_RAM