I have some simple questions about using mappers that I couldn't seem to find any answers to on the board.
What happens to program execution after bank switching?
How are programs that use bank switching setup. Does one bank contain the main code and the rest is used for various game data? What procedures are followed to load this data from a different bank and return to the main program?
mbrenaman wrote:
What happens to program execution after bank switching?
All reads and writes, including instruction fetches, in the switched area come from the new bank immediately.
Quote:
How are programs that use bank switching setup. Does one bank contain the main code and the rest is used for various game data?
Pretty much. Either a subroutine and all its data are stored in the switched bank, or the code is stored in the hardwired bank and its data is stored in a switched bank.
Ok, I understand.
Might as well throw out some more questions...
What should I do with the IRQ. Using mapper 0, I set the IRQ vector to just RTI. How is it used with MMC3? What can I do with it?
Other then that, where can I find a list of games that use NES-TKROM?
Most mappers will have any bank randomly selected when it starts, if that includes the reset vector then you'll need some boot code in each bank.
You could put some bankswitching code in the same area, so it's in the same address in every bank. Or you could copy a little code into RAM to do the same thing.
MMC3 IRQ can be set to trigger after a set amount of scanlines.
Here's a board list:
http://www.parodius.com/~veilleux/boardtable.txt
mbrenaman wrote:
How is it used with MMC3? What can I do with it?
Read Celius' topic on partial scrolling:
http://nesdev.com/bbs/viewtopic.php?t=761
It has everything you need to do MMC3 IRQ's, including a demo of his.
Memblers wrote:
Most mappers will have any bank randomly selected when it starts, if that includes the reset vector then you'll need some boot code in each bank.
You could put some bankswitching code in the same area, so it's in the same address in every bank. Or you could copy a little code into RAM to do the same thing.
I'm not sure what you mean. Every bank that's not bank 0 needs to switch to bank 0 to reach the startup code? Any idea how this might look in ca65?
Anonymous wrote:
Every bank that's not bank 0 needs to switch to bank 0 to reach the startup code?
Only in a 32 KB switching mapper that doesn't have a predictable reset state. This may include at least BNROM, GNROM, A*ROM, Color Dreams, and some versions of S*ROM. Other mappers that allow PRG switching have both a switchable section and a hardwired section (generally including at least $E000-$FFFF). This hardwired section is mapped to the last bank of the ROM and is always visible to the CPU, so the reset code goes there.
In the cc65 toolchain, you may want to try this:
- Expand the "VECTORS" section downward to cover about $FFC0 to $FFFF.
- Put your mapper init code and your vectors in a separate source code file 'vectors.s', and assemble it to 'vectors.o'.
- When you link each bank of the ROM, include 'vectors.o'.
tepples wrote:
Only in a 32 KB switching mapper that doesn't have a predictable reset state. This may include at least BNROM, GNROM, A*ROM, Color Dreams, and some versions of S*ROM.
A MMC1 (S*ROM) will automatically switch the last bank when reset, regardless of if the ROM switching size is 32kb or 16kb. So a reliable vector can be put in the last 16kb of any MMC1 game.
Bregalad wrote:
A MMC1 (S*ROM) will automatically switch the last bank when reset
But will it be reset (i.e. lda #$80 sta $8000) at power-on or when the reset button is pressed? And is the behavior the same on all revisions of MMC1?
I'm not sure if the strobe bit is actived when the card reset (effectively making the MMC take some initial stats, but I don't remember if it has effect on bankswitching or not).
But one sure thing is that the last bank is always switched in $c000-$ffff or in $8000-$ffff at power on or reset. Else, any commercial MMC1 game won't work.
Thanks everyone. I got a demo working, traced it through Nintendulator and it worked great.
All I'm doing is something like this to switch banks,
Code:
lda #6
sta $8000
lda #0
sta $8001
lda #7
sta $8000
lda #0
sta $8001
Anyways, I was just wondering if there's anything I need to do else (like at start up or something)? It works in Nintendulator though I find often that I need to do some weird voodoo before using some hardware.
Other then that... Thanks.
"Weird voodoo"? Make sure that you're doing what's needed and not
cargo cult. See also
this topic.
- One of the very first things you should do is disable the NMI generated by the PPU. Otherwise, your NMI handler will run and possibly get confused.
- Before writing anything to OAM or PPU VRAM, you have to wait for the PPU to warm up. It signals that it has warmed up by setting bit 7 of $2002 twice.
- There's a short delay between when you first turn on a tone generator after powerup and when it first plays notes. Turn on all four channels at startup.
- If you're using IRQs generated by the Game Pak, then you have to disable the APU IRQ.
- You should clear all RAM at reset, except that which should survive a soft reset (e.g. high scores). Usually this should be $00, but clear the CPU OAM buffer (usually stored at $0200) to $F0, not $00, so that unused sprites get hidden below the screen.
- If you want to store data in the low portion of page $100, or you want to detect stack over- or underflows in a debugger, then you should initialize the stack pointer to $01FF (ldx #$FF : txs) at each reset.
- If you're using a software-controlled lockout defeat (such as the Color Dreams charge pump circuit), you need to run that soon after powerup.
The following (untested) code demonstrates this:
Code:
; In A*/B*/G*/U*ROM boards and other 74xxx based mappers,
; RESET_BANK should be the bank that contains reset code.
; In MMC1, RESET_BANK should be $80.
RESET_BANK = $07
; VECTORS should be a 16-byte segment at $FFF0.
; More complex mappers are an exercise for the reader.
.segment "VECTORS"
reset_vector:
sei ; Hide IRQs
cld ; Turn off decimal mode in case you're using
; an in-circuit debugger that assumes a Real 6502
ldx #RESET_BANK ; Switch discrete mapper to the bank
; containing reset_continue
@busconflict:
stx @busconflict-1
jmp reset_continue
.word nmi_vector, reset_vector, irq_vector
.segment "CODE"
reset_continue:
; See http://nesdev.com/bbs/viewtopic.php?p=97#97
Ok, I got all of that but the bus conflict issue confuses me.
Bus conflicts only occur when writing to $8000-$FFFF, right? When would that happen? With SMC? I found this post
http://nesdev.com/bbs/viewtopic.php?t=270 but am still confused.
So getting the CPU and ROM values to match before bank switching with $8000/$8001 will prevent the bus conflict altogether. Right?
If by "CPU" value you mean the value that the CPU writes to $8000-$ffff (usually the Accumulator value, but it can actually also be X or Y register), so yeah, that's right.
Bregalad wrote:
...usually the Accumulator value, but it can actually also be X or Y register), so yeah, that's right.
Or any RMW opcode (ASL, LSR, INC, DEC, ROL, ROR).
Well...
ASL and LSR could work with $00, to write $00, but anyother value will output bus conflicts.
INC and DEC can ONLY lead to bus conflicts.
ROL and ROR would, well, work with $00 and carry clear OR with $ff and carry set, but that's rather crazy.
So yeah, a game could avoid having lda #$00; sta BusConflictZero, but instad have asl BusConflictsZero to switch bank zero, while crazy, it would in theory works.