VRC7 Help (Really more about mappers that support multiple banks in general)
Moderator: Moderators
Re: VRC7 Help (Really more about mappers that support multiple banks in general)
Your ROM can't be 3x 16KB because that adds up to a chip size that doesn't exist. Valid PRG-ROM sizes are 16KB, 32KB, 64KB, 128KB, and so on. This means that if you want to extend your ROM past 32KB, you need to add *two* 16KB banks so the total size is 64KB. If later you want more than 64KB, then you'll need *four* new banks to go all the way up to 128KB. Every time you need more space, you have to double the amount of ROM. This is also true for CHR-ROM.
Re: VRC7 Help (Really more about mappers that support multiple banks in general)
I don't think this forum disallows necroposting, and digging up old discussions can be a good thing if done right. In my opinion necroposting is totally fine and better than creating a new thread if what you have to add is directly related to the discussion and you want to continue it. If it's only loosely connected you are better off creating a new thread, especially if you can't find the the thing you want to discuss anywhere else after searching for a bit. In this case it was a direct continuation of the discussion so it was fine IMHO.puppydrum64 wrote: ↑Sat May 22, 2021 5:53 pm I asked a similar question in another thread and realized it was over ten years old so I basically created a zombie thread
-
- Posts: 160
- Joined: Sat Apr 24, 2021 7:25 am
Re: VRC7 Help (Really more about mappers that support multiple banks in general)
I guess I find the VRC6 in particular confusing because it has a switchable 16k bank, a switchable 8k bank, and a fixed 8k bank. Since this adds up to 32k I would need at a minimum 2 16k banks. That seems to make sense. What doesn't make sense is why my code that's anywhere except the fixed bank doesn't appear in MESEN's debugger. Nor does it seem that I can add more banks without making the rom impossible to load.tokumaru wrote: ↑Sat May 22, 2021 6:52 pm Your ROM can't be 3x 16KB because that adds up to a chip size that doesn't exist. Valid PRG-ROM sizes are 16KB, 32KB, 64KB, 128KB, and so on. This means that if you want to extend your ROM past 32KB, you need to add *two* 16KB banks so the total size is 64KB. If later you want more than 64KB, then you'll need *four* new banks to go all the way up to 128KB. Every time you need more space, you have to double the amount of ROM. This is also true for CHR-ROM.
EDIT: Rereading my old thread "My cart runs differently in different emulators" showed me what was wrong with the code outside the fixed bank not loading:
"No. The program counter starts at the address that the NES's CPU loads from the cart.
In the same way that NMI jumps to the address at $FFFA, reset jumps to the address at $FFFC.
The VRC6 only guarantees that the last 8KB of the PRG ROM is accessible at addresses $E000-$FFFF, so your code must write to the VRC6 registers before you access anything at $8000-$DFFF.
(And your PRG ROM must be a power of 2 in size)"
I had accidentally had the bank register selecting bank 1 when there was no bank 1. That's what made my code in the 16k bank seem to vanish. But that shouldn't have anything to do with the apparent inability to add more banks. There must be an error with my formatting of the base and pad directives but I don't know what it is.
I tried doing the following and I can't get it to boot.
Code: Select all
PRG_COUNT = 4 ;1 = 16KB, 2 = 32KB
CHR_COUNT = 4 ;1 = 8KB, 2 = 16KB, ETC
MAPPER_LOW = $80
MAPPER_HIGH = $10 ;together these make mapper 24
FAMICOM_NES = %0000
PLAY_CHOICE_TEN = %0010
VS_SYSTEM = %0001
MIRRORING = %0001 ;%0000 = horizontal, %0001 = vertical, %1000 = four-screen
.org $7FF0
;----------------------------------------------------------------
; iNES header
;----------------------------------------------------------------
.db "NES", $1a ;identification of the iNES header
.db PRG_COUNT ;number of 16KB PRG-ROM pages
.db CHR_COUNT ;number of 8KB CHR-ROM pages
.db MAPPER_LOW|MIRRORING ;mapper bottom 4 bits and mirroring
.db MAPPER_HIGH|FAMICOM_NES ;mapper top 4 bits, NES
.dsb 8, $00 ;clear the remaining bytes
.pad $8000, $00
;BANK 0 16K
.base $8000 ;16k switchable 16k PRG-ROM bank
; BANK CONTENTS GO HERE
.pad $C000
; BANK 1 16K
.base $8000 ;16k switchable 16k PRG-ROM bank
; this breaks the game right now.
.pad $C000
;BANK 0 8K
.base $C000 ;8K switchable PRG-ROM bank
; BANK CONTENTS GO HERE
include "CollisionMaps.asm"
include "collision_Subroutines.asm"
.pad $E000
;BANK 1 8K
.base $C000
; this breaks the game right now.
.pad $E000
.base $E000 ;8K fixed PRG-ROM bank
Reset:
...
.org $fffa
.dw NMI
.dw Reset
.dw IRQ
;----------------------------------------------------------------
; CHR-ROM banks
;----------------------------------------------------------------
.incbin "astrobirds_00.chr"
.incbin "astrobirds_01.chr"
.incbin "astrobirds_02.chr"
.incbin "astrobirds_03.chr"
Re: VRC7 Help (Really more about mappers that support multiple banks in general)
You specify 4 x 16 = 64 kB PRG and 4 x 8 = 32 kB CHR in the header. But you only have (2 x 16) + (2 x 8) = 48 kB PRG ROM. You need one more 16 kB bank or two more 8 kB banks. You also call your four PRG banks 0 and 1 twice, but I guess that's a typo.
Also what is the size of those CHR files? The total size must be 32 kB as you specified in the header. If it's less you must pad to 32 kB or change the header.
Initializing all mapper registers (and all hardware in the NES) is another thing, but I guess the init code is just omitted.
Also what is the size of those CHR files? The total size must be 32 kB as you specified in the header. If it's less you must pad to 32 kB or change the header.
Initializing all mapper registers (and all hardware in the NES) is another thing, but I guess the init code is just omitted.
Re: VRC7 Help (Really more about mappers that support multiple banks in general)
Actually, they're labeled "BANK 0 16K"/"BANk 1 16K" and "BANK 0 8K"/"BANK 1 8K", which I suspect is part of a larger misunderstanding which I'm going to try and clear up.
The VRC6 does not have separate "16K banks" and "8K banks" - it only has 8KB banks, and the "16KB bank" at $8000-$BFFF is merely two consecutive banks which are selected by a single register with the further restriction that the first 8KB bank must be an even one. That is, if you write "3" to $8000 (to map "16KB bank #3" to $8000-$BFFF), you are actually mapping "8KB bank #6" to $8000-$9FFF and "8KB bank #7" to $A000-$BFFF.puppydrum64 wrote: ↑Sun May 23, 2021 10:54 am I guess I find the VRC6 in particular confusing because it has a switchable 16k bank, a switchable 8k bank, and a fixed 8k bank. Since this adds up to 32k I would need at a minimum 2 16k banks. That seems to make sense.
Similarly, it's also possible to map either "half" of a 16KB bank to $C000-$DFFF by using the appropriate bank number - as above, writing "6" or "7" to $C000 will map the first or second half (respectively) of "16KB bank #3" to $C000-$DFFF.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
P.S. If you don't get this note, let me know and I'll write you another.
-
- Posts: 160
- Joined: Sat Apr 24, 2021 7:25 am
Re: VRC7 Help (Really more about mappers that support multiple banks in general)
Ohhh I see! That explains why Mesen showed $01 at A000 and why my code at $C000 was mirrored at $8000. Thank you! I really wish the wiki explained thatQuietust wrote: ↑Sun May 23, 2021 1:05 pmActually, they're labeled "BANK 0 16K"/"BANk 1 16K" and "BANK 0 8K"/"BANK 1 8K", which I suspect is part of a larger misunderstanding which I'm going to try and clear up.
The VRC6 does not have separate "16K banks" and "8K banks" - it only has 8KB banks, and the "16KB bank" at $8000-$BFFF is merely two consecutive banks which are selected by a single register with the further restriction that the first 8KB bank must be an even one. That is, if you write "3" to $8000 (to map "16KB bank #3" to $8000-$BFFF), you are actually mapping "8KB bank #6" to $8000-$9FFF and "8KB bank #7" to $A000-$BFFF.puppydrum64 wrote: ↑Sun May 23, 2021 10:54 am I guess I find the VRC6 in particular confusing because it has a switchable 16k bank, a switchable 8k bank, and a fixed 8k bank. Since this adds up to 32k I would need at a minimum 2 16k banks. That seems to make sense.
Similarly, it's also possible to map either "half" of a 16KB bank to $C000-$DFFF by using the appropriate bank number - as above, writing "6" or "7" to $C000 will map the first or second half (respectively) of "16KB bank #3" to $C000-$DFFF.
-
- Posts: 160
- Joined: Sat Apr 24, 2021 7:25 am
Re: VRC7 Help (Really more about mappers that support multiple banks in general)
So now with that new understanding in mind I'm a little bit more confused why this works:
If all the banks are really 8k and the "16k bank" is just two consecutive 8k banks in sequence when loaded at $8000, why does this setup of directives make the game boot where having ".base $8000 .pad $C000" doesn't?
Code: Select all
;BANK 0 16K
.base $8000 ;16k switchable 16k PRG-ROM bank
; BANK CONTENTS GO HERE
include "CollisionMaps.asm"
include "collision_Subroutines.asm"
.pad $C000
;BANK 1 8k
.base $C000
.pad $E000
.base $E000 ;8K fixed PRG-ROM bank
-
- Posts: 160
- Joined: Sat Apr 24, 2021 7:25 am
Re: VRC7 Help (Really more about mappers that support multiple banks in general)
At long last I finally got bankswitching to work! Thank you all for your help. I'll go ahead and share what I've learned for anyone who has the same question later. Just to clarify this is for VRC6 and I'm using ASM6 so you might need to change your directive syntax accordingly if you're using a different assembler.
EDIT: Minor changes for clarification.
Code: Select all
;----------------------------------------------------------------
; constants
;----------------------------------------------------------------
;HEADER CONSTANTS
PRG_COUNT = 4 ;1 = 16KB, 2 = 32KB, etc. This number should equal exactly half your total number of banks. Both should be even.
CHR_COUNT = 4 ;1 = 8KB, 2 = 16KB, etc. This must equal the number of .chr files at the end of your code.
MAPPER_LOW = $80
MAPPER_HIGH = $10 ;together these make mapper 24
FAMICOM_NES = %0000
PLAY_CHOICE_TEN = %0010
VS_SYSTEM = %0001
MIRRORING = %0001 ;%0000 = horizontal, %0001 = vertical, %1000 = four-screen
;----------------------------------------------------------------
; variables
;----------------------------------------------------------------
enum $0000 ;ZERO PAGE RAM
;zero page ram goes here
.ende
;----------------------------------------------------------------
;NOTE: you can also split the variable declarations into individual pages, like this:
;.enum $0400
;.ende
;.enum $0600
;.ende
.org $7FF0
;----------------------------------------------------------------
; iNES header
;----------------------------------------------------------------
.db "NES", $1a ;identification of the iNES header
.db PRG_COUNT ;number of 16KB PRG-ROM pages
.db CHR_COUNT ;number of 8KB CHR-ROM pages
.db MAPPER_LOW|MIRRORING ;mapper bottom 4 bits and mirroring
.db MAPPER_HIGH|FAMICOM_NES ;mapper top 4 bits, NES
.dsb 8, $00 ;clear the remaining bytes
.pad $8000, $00
;----------------------------------------------------------------
; MACRO LISTS
;----------------------------------------------------------------
;MACROS GO HERE
;----------------------------------------------------------------
; program bank(s)
;----------------------------------------------------------------
;BANK 0
.base $8000
; BANK CONTENTS GO HERE
.pad $A000
;BANK 1
.base $A000
;BANK CONTENTS GO HERE
.pad $C000
;BANK 2
.base $C000
; BANK CONTENTS GO HERE
.pad $E000
;BANK 3
.base $8000
; BANK CONTENTS GO HERE
.pad $A000
;BANK 4
.base $A000
; BANK CONTENTS GO HERE
.pad $C000
;BANK 5
.base $C000
; BANK CONTENTS GO HERE
.pad $E000
;BANK 6
.base $8000
.; BANK CONTENTS GO HERE
.pad $A000
;FIXED BANK 7
.base $E000 ;8K fixed PRG-ROM bank
;------------------------------------------------------------
; Reset and Initialization Code
;------------------------------------------------------------
Reset:
;YOUR RESET CODE GOES HERE
;This part sets up your CHR-ROM like a typical NES game
LDA #$00
STA $D000
LDA #$01
STA $D001
LDA #$02
STA $D002
LDA #$03
STA $D003
LDA #$04
STA $E000
LDA #$05
STA $E001
LDA #$06
STA #$E002
LDA #$07
STA #$E003
;SET UP DEFAULT SWITCHABLE BANKS - IT'S A GOOD IDEA TO HAVE SHADOW REGISTERS FOR THE CURRENT BANK AND THE PREVIOUS BANK
LDA #$00
STA $8000 ;SETS $8000-$A000 TO BANK 0 AND $A000-$C000 TO BANK 1. BANK NUMBERS WRITTEN TO THIS ADDRESS
;ARE AUTOMATICALLY DOUBLED.
LDA #$02
STA $C000 ;SETS $C000-$E000 TO BANK 2 (NO AUTOMATIC DOUBLING)
;ADD THIS PART TO ENABLE IRQs
LDA #$FF
STA $F000
CLI
;------------------------------------------------------------
; main
;------------------------------------------------------------
MainGameLoop:
;-----------------------------------------------------
;WRITING #%00000010 TO $F001 TRIGGERS AN IRQ
LDA #%00000010
STA $F001
;-----------------------------------------------------
JMP MainGameLoop
;------------------------------------------------------------
; interrupt handlers
;------------------------------------------------------------
NMI:
PHA ;save registers
TXA
PHA
TYA
PHA
;NMI ROUTINE GOES HERE
PLA ;restore registers
TAY
PLA
TAX
PLA
RTI
IRQ:
PHA
TXA
PHA
TYA
PHA
;IRQ ROUTINE GOES HERE
STA $F002 ;without this the IRQ will never end. What's in the accumulator at this line doesn't matter.
PLA
TAY
PLA
TAX
PLA
RTI
;----------------------------------------------------------------
; interrupt vectors
;----------------------------------------------------------------
.org $fffa
.dw NMI
.dw Reset
.dw IRQ
;----------------------------------------------------------------
; CHR-ROM banks
;----------------------------------------------------------------
.incbin "astrobirds_00.chr" ;USE THE NAME OF YOUR CHR FILE, NOT MINE! :P
.incbin "astrobirds_01.chr"
.incbin "astrobirds_02.chr"
.incbin "astrobirds_03.chr"
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Re: VRC7 Help (Really more about mappers that support multiple banks in general)
Congratulations!
Maybe, if you want to save reset space, you could do this instead:
^that’s 16 bytes compared to your *meant* 40 bytes
Note: Also, it’s around 85 cycles compared with your *meant* 56 cycles, but size of code matters in reset.
Oooh, this only works if the ROM addresses don’t need to be written to consecutively. Aaand, interested, please read and understand how the code works instead of just copy pasting. You’ll improve your coding-self.
EDIT: ^Our code is untested; but, it seems to be logically valid.
FINAL-EDIT: ^code attempts to do this:
Maybe, if you want to save reset space, you could do this instead:
Code: Select all
ldx #03
- txa
eor #00000100b ;<invert 4-value bit in accumulator
sta $E000, x
eor #00000100b
sta $D000, x
dex ;2-ff
bpl -
Note: Also, it’s around 85 cycles compared with your *meant* 56 cycles, but size of code matters in reset.
Oooh, this only works if the ROM addresses don’t need to be written to consecutively. Aaand, interested, please read and understand how the code works instead of just copy pasting. You’ll improve your coding-self.
EDIT: ^Our code is untested; but, it seems to be logically valid.
FINAL-EDIT: ^code attempts to do this:
puppydrum64 wrote: ↑Tue May 25, 2021 12:45 pmCode: Select all
LDA #$00 STA $D000 LDA #$01 STA $D001 LDA #$02 STA $D002 LDA #$03 STA $D003 LDA #$04 STA $E000 LDA #$05 STA $E001 LDA #$06 STA #$E002 LDA #$07 STA #$E003
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Re: VRC7 Help (Really more about mappers that support multiple banks in general)
Sigh, the code can probably be reduced even more:
If that does work, it would be only 14 bytes and around 77 cycles.
If we do $D000 store first, the values are already correct; then the txa at the top eliminates the need to invert accumulator back to normal bc it’s already normal (due to txa).
Code: Select all
ldx #03
- txa
sta $D000, x
eor #00000100b ;<invert 4-value bit in accumulator
sta $E000, x
dex ;2-ff
bpl -
If we do $D000 store first, the values are already correct; then the txa at the top eliminates the need to invert accumulator back to normal bc it’s already normal (due to txa).
-
- Posts: 160
- Joined: Sat Apr 24, 2021 7:25 am
Re: VRC7 Help (Really more about mappers that support multiple banks in general)
It's interesting how it's actually quicker to load everything backwards due to the fewer commands required to check if a number equals zero or is greater than $80. I'm sure that wasn't an intentional design of the 6502. I wrote my template the way I did for simplicity's sake because although slower it is much easier to understand the intent of the code. Loading the banks the way I did matches how CHR-ROM works in most cartridges that don't have CHR bankswitching. That way the user has some easy-to-understand groundwork to start from. I feel that the documentation on VRC6 is currently very poor for the beginner programmer.
EDIT: My actual code uses shadow regs for D000-D003 & E000-E003. I never directly write to the actual registers, only the shadow registers and then copy to the real ones every NMI. I tried making your compact loop work but unfortunately STY addr,x isn't allowed by the 6502.
I've taken a bit of a break from the NES for now, I find it frustrating to work with. I guess the old phrase "Genesis does what Nintendon't" really was true after all. (Well technically I'm working with NEOGEO now but they use the same processor.)
EDIT: My actual code uses shadow regs for D000-D003 & E000-E003. I never directly write to the actual registers, only the shadow registers and then copy to the real ones every NMI. I tried making your compact loop work but unfortunately STY addr,x isn't allowed by the 6502.
I've taken a bit of a break from the NES for now, I find it frustrating to work with. I guess the old phrase "Genesis does what Nintendon't" really was true after all. (Well technically I'm working with NEOGEO now but they use the same processor.)
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Re: VRC7 Help (Really more about mappers that support multiple banks in general)
Hmmm… my compact loop also wouldn’t work with sty addr,x bc eor only works on the accumulator. You’d have to tax or tay and that adds more cycles so the loop would no longer be compact, imo.puppydrum64 wrote: ↑Sat Jun 19, 2021 8:41 am I tried making your compact loop work but unfortunately STY addr,x isn't allowed by the 6502.
I've taken a bit of a break from the NES for now, I find it frustrating to work with. I guess the old phrase "Genesis does what Nintendon't" really was true after all. (Well technically I'm working with NEOGEO now but they use the same processor.)
In my experience, a needed sty addr,x can be replaced if you just spend a bit of effort using the registers different. Usually it works out.
Enjoy the neogeo!
EDIT:
Totally understand; however, your code is actually faster than my loop. Just your code’s massive size is unwelcome in the midst of reset, bc that pushes your main loop’s start further into your fixed bank; at least, that’s how large code in my reset affected me.puppydrum64 wrote: ↑Sat Jun 19, 2021 8:41 am I wrote my template the way I did for simplicity's sake because although slower it is much easier to understand the intent of the code.