I have a little n00b question regarding the MMC1. When I bankswitch the CHR background like this
LDA #%00000010 ;Swap background
JSR Background_Select ;Go to $C000 bankswitching subroutine
;Rest of code here
Background_Select:
STA $C000
LSR A
STA $C000
LSR A
STA $C000
LSR A
STA $C000
LSR A
STA $C000
RTS
It works fine on an emulator. However, on real hardware, it seems like there is no such thing, the name entry screen of Deal or no Deal keeps the title background CHR bank. What am I doing wrong?
Here are the pics
Emu
Real Hardware
(Uses the title screen CHR bank)
Have you also configured the other MMC1 registers?
You mean the PRG bank, Sprites CHR bank and $8000? I did.
Here it is (sorry for the pic. My Iphone didn't want to select the text...)
If you're using a flash cart to test, make sure the number of CHR banks in your ROM is a power of two (1, 2, 4, 8, and so on).
Are you trying to use different background banks in different parts of the screen?
lidnariq wrote:
Are you trying to use different background banks in different parts of the screen?
Nope. I think Fox is right though, I have 5 CHR banks in my game. Gonna fix that this evening and I'll update you guys
You also need to initialize the first background, too. Boot state is random, y ou have to set up everything how you want it first before you can assume any graphics will show.
3gengames wrote:
You also need to initialize the first background, too. Boot state is random, y ou have to set up everything how you want it first before you can assume any graphics will show.
I assume that's what this is for:
Code:
LDA #%00000001
JSR Sprite_Select
Hey,
It seems like it works now... Kinda. I still have one bankswitching problem. At some point in the game, you have to select a character. There are 6 banks with five characters in each bank. On an emulator, it works as it should (Starts at bank 03, then goes to bank 04, etc. until bank 8). On real hardware (Tried the Everdrive and the PowerPak), it starts at bank 03, then goes back to bank 00 for some reason, then bank 01, but finishes with bank 08 as it should. Anyone knows what's wrong?
Code:
LDA buttons
AND #%00000001
BEQ NoCharRightUnpressed ;Not the best way of doing this, I know
LDA rightpressed ;If right is already pressed, don't do the folowing
BNE NoCharRight ;There are better ways to do this, I should change it...
INC rightpressed
INC CharNumber
LDA CaseCharacter ;Characters are like 3x6 metatiles, this seems to work
CLC
ADC #$03
STA CaseCharacter
CMP #$6E
BCC .nochange3
LDA #$60
STA CaseCharacter
INC CaseGraphicBank ;Here's the main culprit >:(. On real hardware, goes back to zero...
LDA CaseGraphicBank
CMP #$09 ;If higher than $08, set $03
BNE .chrbankok3
LDA #$03
STA CaseGraphicBank
.chrbankok3 ;There used to be the CHR bank switch subroutine here, but I put it at the beginning of the char selection routine in order to fix a minor glitch
.nochange3
LDA Character_Palette ;Sets the palette for the characters. This seems to work too
CLC
ADC #$03
CMP #PALETTEEND
BCC .nopalend
LDA #$00
.nopalend
STA Character_Palette
This is the routine to go to the next character. The routine when pressed left looks similar except it's kind of the opposite thing that happens. Tell me if you need me to post more code. I'll take my src with me today
Thanks everyone! You've been of great help so far.
Rewrote my routine, but I have the same problem on real hardware using flashcarts... Please help me
Code:
LDX CharNumber
LDA case_bank,x
JSR Background_Select ;$C000 MMC1 writes
;Blahblahblahworkingcodeblahblahblah
case_bank:
.db $03,$03,$03,$03,$03,$04,$04,$04,$04,$04,$05,$05,$05,$05,$05
.db $06,$06,$06,$06,$06,$07,$07,$07,$07,$07,$08,$08,$08,$08,$08
Do you know what's wrong?
--Vec
Pehaps you shoud describe us more in detail what
1) what you are trying to do
2) what do you exepct your results to be
and
3) what is wrong with your actual results
so we can have a clue how to help you ? Just some code is not enough.
The only 2 tricks with the MMC1 are
1) You need to "reset" the mapper at startup (but you only have to do it once, as long as you're sure you always write in bulks of 5 writes)
2) You should not use the mapper in the interrupt routine at the same time you use it in the main program. If you do that, both writes can (and will) conflict. Even if you don't write to the same MMC1 register : The MMC1 has only one "shift register" for input, and the 4 real (internal) registers are written to after the last write of the bunch of 5.
PS : Also you didn't mention which emulators you used, but you should really debug with Nintendulator which is the most accurate to real hardware. When there is a different between real hardware and normal emulators, often Nintendulator and Nestopia are the 2 only ones to emulate the "correct" behaviour (but Nestopia has no debugger).
The number of PRG or CHR banks must be a power or 2. So you can't have 5 banks, need to pad it with empty banks to 8.
Also, base 0, not base 1 ... if you have eight banks, they're numbered 0 through 7.
Actually, it was the number of banks again. Thanks for the replies
Bregalad wrote:
Pehaps you shoud describe us more in detail what
1) what you are trying to do
2) what do you exepct your results to be
and
3) what is wrong with your actual results
so we can have a clue how to help you ? Just some code is not enough.
The only 2 tricks with the MMC1 are
1) You need to "reset" the mapper at startup (but you only have to do it once, as long as you're sure you always write in bulks of 5 writes)
2) You should not use the mapper in the interrupt routine at the same time you use it in the main program. If you do that, both writes can (and will) conflict. Even if you don't write to the same MMC1 register : The MMC1 has only one "shift register" for input, and the 4 real (internal) registers are written to after the last write of the bunch of 5.
PS : Also you didn't mention which emulators you used, but you should really debug with Nintendulator which is the most accurate to real hardware. When there is a different between real hardware and normal emulators, often Nintendulator and Nestopia are the 2 only ones to emulate the "correct" behaviour (but Nestopia has no debugger).
I used FCEUX and NEStopia. I'm gonna give Nintendulator a go, thanks for the advice. I also heard about puNes being accurate, is that the case?
As for next time, I'm going to ask questions in a better way, sorry for the confusion
PS : Tu viens du Canton de Vaud toi aussi?
Oui
Vectrex2809 wrote:
I used FCEUX and NEStopia. I'm gonna give Nintendulator a go, thanks for the advice. I also heard about puNes being accurate, is that the case?
Accurate is a general term. Most emulators are alot more accurate than the used to be for the NES. This is thanks to more detailed information becoming available. The author of puNES could tell you some things about how it emulates. In the past, emulator programmers had to guess, assume, and just try things out to get games working. Some information was available but it was incomplete and sometimes not entirely correct. But now we know most of the important details to emulate it with a high degree of accuracy.
It's important to note that most software isn't going to require extremely accurate emulation. Only a small percentage of games are programmed in a way that requires precise simulation.
MottZilla wrote:
Only a small percentage of games are programmed in a way that requires precise simulation.
Including your game that ends up inadvertently depending on an emulator bug. Emulators for developers need to be a lot more accurate to be useful for testing things that push the NES harder. For game logic and simple graphics updates, FCEUX plus testing on an NES about once a day is fine. But if you're trying raster effects or pushing a
lot of data to the PPU each frame, you might want to be able to test without having to go to the NES (which lacks a step debugger and RAM viewer) every single time.
On this Thanksgiving day, I'm thankful that we're not stuck with NESticle anymore.
I have a question about switching MMC1 banks when the PRG ROM has 512KB (SUROM). At Nesdev wiki, he writes:
https://wiki.nesdev.com/w/index.php/Programming_MMC1Quote:
Then to switch PRG ROM banks, load the bank number (0-15) into A and call this subroutine:
mmc1_load_prg_bank:
sta $E000
lsr a
sta $E000
lsr a
sta $E000
lsr a
sta $E000
lsr a
sta $E000
rts
0-15 means the maximum number of banks 16 x 16kb - 256KB PRG. Is it not clear whether by loading a value greater than 15 the code will automatically switch banks 16-31?
No, it will not.
You must write the MSbit into the register at $A000:
(nesdevwiki)
Thanks.
Can anyone explain this to me:
"The 256 KB PRG bank selection applies to all the PRG area, including the supposedly "fixed" bank."
I guess that if I set the second 256KB of banks, the last bank will also be replaced with a new one? So I need to make a copy of a fixed bank?
LDA #%00000000 ;banks 0-15 (15fixed)
STA $A000
;switch banks
LDA #%00001000 ;banks 16-31 (31 fixed - copy)
STA $A000
;switch banks
?
Either banks 0-15 are used in the first slot and bank 15 in the second slot, or banks 16-31 are used in the first slot and bank 31 in the second slot. You can have bank 31 being an exact copy of bank 15 or not, depending on what you want to do. The advantage of it being an exact copy is that it's easier to use, and you can bankswitch banks 0-30 in the first slot without worrying about anything, but you have less PRG-ROM as you effectively loose 16kb.
If you have different banks, you have to keep track of everything with bankswitching, just like how you keep track of what is swapped in the swappable bank. You can also have part of the fixed bank being an exact copy, and part of it being different. I think that's what Dragon Warrior III and IV does, if I'm not mistaken.
Or you could just use 32k bankswitching and have 16 banks of 32k.
That's weird indeed, but keep in mind that SUROM is basically a hack. Someone went "hey, we've got this CHR address line we're not using, how about we use it to select which half of a 512KB PRG chip will be used as a regular 256KB MMC1 PRG chip". SUROM is basically 2 independent 256KB MMC1 ROMs, but you get to switch between them.
It's hard for me to understand this, because earlier I used only UNROM, which is very simple.
For example. So if I have a code in the last SUROM fixed bank 31:
Code:
SomeCode: ;code in fixed bank 31
LDA #%00001000 ;select PRG slot 2
STA $A000 ;(***)
LDA #$20 ;switch to bank 20 (example)
STA MMC1_BankNumber
JSR MMC1_PRGBankWrite
JSR SomeCodeInBank20
LDA #%00000000 ;select PRG Slot 1
STA $A000
LDA #$00 ;back to bank 00
STA MMC1_BankNumber
JSR MMC1_PRGBankWrite
RTS
(***) - At the moment the code in bank 31 (fixed) will disappear (the code will hang) because the entire 256KB PRG has been "changed" to another one?? (Of course, such code in UNROM-512 will work without any problems.)
Sory, for stupid questions, but I'm stubborn and I often find it difficult to understand many things: /
The register at $A000 works just like any other register in the MMC1: you still have to write to it serially.
Because with SUROM there's only two useful values, you may wish to have functions like:
Code:
SUROM_select_high_256k:
ldx #1
stx $A000
stx $A000
stx $A000
stx $A000
stx $A000
rts
SUROM_select_low_256k:
ldx #0
stx $A000
stx $A000
stx $A000
stx $A000
stx $A000
rts
You may wish to instead have a function that takes a number between 0 and 31 and automatically does
both writes:
Code:
SUROM_unified_bankswitch:
sta $E000
lsr
sta $E000
lsr
sta $E000
lsr
sta $E000
ldx PRG_RAM_DISABLED
stx $E000
stx $A000 ; these writes must still happen despite having no other effect
stx $A000
stx $A000
stx $A000
lsr
sta $A000
rts
Warning: In your example the comment says you're swapping bank 20, but you're actually swapping bank $20 which does not exist so bank 0 will be swapped instead. Also, I'm pretty sure none of us used SUROM-style banking either in our projects - we just know the theoretical whereabouts of it.
Personally I've never used much PRG bankswitching other than just testing (my only large project so far uses 32kb PRG), so I can't comment on what good practices are. However I'd go for two approaches if I were to make a large MMC1 games:
- Approach A: Just say "screw it", and make bank 15 and bank 31 (the fixed banks) exact twins of eachother. You can now freely swap banks 0-14 and 16-30 in the first slot without worrying about anything. This is definitely what you should be doing if you're used to UNROM-style bankswitching. You "loose" 16k because one bank is duplicated
- Approach B : Use 32kb bankswitching so that the problem does not even appears. You use 16 banks of 32kb. You need to make your own "fixed bank" trampoline code replicated in each of the 16 banks, where the bare minimum for IRQ, NMI and RESET handling should be done as well as bankswitching code. This should take about 1k, so you effectively "loose" 15k.
- Approach C : I don't recommend this, but you go crazy and fully use the bankswitching sheme: You have two sets of 16 banks, and 2 fixed banks, and you make full usage of this. For example if you're making an RPG, you can have one set of banks dedicated to battle and overworld, and the other set of banks dedicated to towns and dungeons and script. It sounds like it wouldn't be that practical to use, but at least you don't loose anything because nothing is duplicated.
Approach C.2, inspired by how storage ended up split in larger projects that I've been involved in:
Use all of the first 256K for CHR and map storage, with CHR and map decompression in the first fixed bank. This frees up all of the second fixed bank for your game logic.
It's probably that I will skip using SUROM. In general, UNROM only lacks WRAM and controls mirroring from the level of the code / program. Apparently it will be better to try MMC3. Is there probably all PRG space available without any problems?
Yes, the MMC3 is a much nicer mapper, both in capabilities and programming friendliness. Lots of people assume that the MMC1 is the next logical step up from discrete logic mappers, but the truth is it's extremely awkward to use, and doesn't really offer much in terms of features.
Unless for academic reasons (wants to know more about MMC1) it would be a lot easier to use MMC3. There is no serial bit thing and you just write 1 byte to select action then 1 byte for bank and it's done. A lot more easier to manage. And the bank format is easier too.
Thanks for the explanation.
I also see that MMC3 has switching CHR banks of 1KB, while MMC1 4KB. I have not tried the MMC3 yet, so occasionally I will ask if the MMC3 needs to be specially initiated at the beginning of the code? I am talking about switching on a method similar to UNROM.
MMC3 init is 28 bytes and needs to be somewhere in $E000-$FFFF.
Last I checked, the biggest advantage of MMC1 (or the similarly capable Action 53 mapper) over MMC3 was that MMC3 needed a more expensive CPLD. Is this still the case?
Well, in my current codebase, after I finish to init the nes, I init my banks because I want to access specific data but except for that, the last bank it set at $E000 and second last bank at $C000 (default setting, it could be at $8000 if you set differently).
As for chr, if I was stuck at 4k switch, that would be a pain ^^;;; I use 2k/2k for BG and 1k/1k/1k/1k for sprites but the opposite is possible too.
Tepples mentioned the price but unless you plan to mass produce it and have some kind of super hit or something.. Don't worry about that
Most of the time people now run with an emulator and with those flash cartridge, compare to 10+ years ago, the need to make carts is different. But it always depends what is your goal. In my case, I prefer a mapper that offer more flexibility than price since I'm not expecting cart release anyway.
Is it correct?
Code:
reset: ; reset routine moved to $E000-$FFFF
sei ; ignore IRQs
cld ; disable decimal mode
ldx #$40
stx $4017 ; disable APU frame IRQ
ldx #$ff
txs ; Set up stack
; inx ; now X = 0
ldx #$07
loop:
stx $8000
lda mmc3tbl,x
sta $8001
dex
bpl loop
sta $A000 ; set vertical mirroring, or use stx for horizontal
; jmp rest_of_reset
; A=$00 and X=$FF at end, so ready for $2000/$2001 writes and TXS
stx $2000 ; disable NMI
stx $2001 ; disable rendering
stx $4010 ; disable DMC IRQs
bit $2002
@vblankwait1:
bit $2002
bpl @vblankwait1
txa
@clrmem:
sta $000,x
sta $100,x
sta $300,x
sta $400,x
sta $500,x
sta $600,x
sta $700,x
inx
bne @clrmem
@vblankwait2:
bit $2002
bpl @vblankwait2
;(...)
mmc3tbl:
.byt 0,2,4,5,6,7,0,1
I want to change the unrom and use a mapper that has WRAM and mirroring control. And the most important thing is to be able to use 512KB PRG (when needed).
Mapper 2 (UxROM) can be extended to 512KB without problems, and WRAM can be added to any cartridge regardless of the mapper. May I ask why you need mirroring control?
I believe that even with the classic iNES header you can specify a mapper 2 ROM with 512KB of PRG-ROM, WRAM and 4-screen. In some cases, 4-screen eliminates the need for configurable mirroring, and it's extremely simple to implement on hardware if you're already using CHR-RAM.
To control the direction of screen scrolling (H/V).
Unrom equires a soldering iron to switch mirroring.
I am currently using UNROM-512. However, I have a project in which I use WRAM, and needs mirroring control.
Somewhere is a diagram on how to connect WRAM to unrom? (If it requires adding something more than the wram itself.)
Although I would rather use a mapper, which is commercial and generally available so that if necessary you do not have to combine too much to write the game on the card. (example: MMC1 when PRG up to 256, MMC3 when 512).
sdm wrote:
To control the direction of screen scrolling (H/V).
The reason I'm asking is because there's no rule saying that you have to use a particular type of mirroring to achieve a particular type of scrolling... After all, there are games using 2 name tables that scroll in 8 directions just fine without ever changing the mirroring. You may need to use a few tricks to make 8-way scrolling 100% glitch-free, but it's possible.
I also mentioned 4-screen as an alternative to mirroring control. With 4 screens, you can have glitchless scrolling in any direction without tricks, and it's incredibly simple to add to a CHR-RAM cartridge: use a 16KB or 32KB CHR-RAM chip (which are way easier to find than 8KB anyway) and solder a wire to tell the NES not to use its internal RAM for name tables. It's a permanent setting, and the same chip will be used for pattern tables and name tables (4 of them).
Quote:
Somewhere is a diagram on how to connect WRAM to unrom? (If it requires adding something more than the wram itself.)
You do need a chip to handle the logic of when to enable the WRAM chip. The wiki has a page about this:
https://wiki.nesdev.com/w/index.php/PRG_RAM_circuitQuote:
Although I would rather use a mapper, which is commercial and generally available so that if necessary you do not have to combine too much to write the game on the card. (example: MMC1 when PRG up to 256, MMC3 when 512).
The MMC3 is a very nice mapper overall, but it may increase manufacturing costs unnecessarily if you you're not using some of its more advanced features, such as the fine CHR switching or scanline IRQs.
tokumaru wrote:
The MMC3 is a very nice mapper overall, but it may increase manufacturing costs unnecessarily if you you're not using some of its more advanced features, such as the fine CHR switching or scanline IRQs.
The features you don't use don't increase manufacturing costs, though. If you don't need the IRQ you wouldn't need to accomodate it in the CPLD. If you don't need all the bankswitching register they can be omitted. Etc.
I think some subsets of MMC3 are actually really sensible to build.
Yeah, it's worth remembering that if you just need an UNROM-like subset of MMC3 ... it will only be roughly as expensive as INL's SNROM repro cart, and the programmer's interface will be nicer.
The same is true for every mapper: choosing a subset of an existing mapper makes development easier, and hardware cheaper.
Yeah, if whoever is manufacturing carts for you can customize the mapper yo remove unused features and bring costs down, that's great.