VRC6 CHR Bank Malformed?

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

puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

VRC6 CHR Bank Malformed?

Post by puppydrum64 »

I've noticed the following issue with loading graphics into my VRC6 test rom. The graphics are there, but only half of them. It seems that pattern B isn't loaded into the NES.

Sorry, I hit some key by mistake and it submitted the post too early. Will update with the rest of what I was going to say.

The original setup of banks looks like this (I left out all the code in those banks for brevity)

Code: Select all

	.bank 0
	.org $c000
	
	.bank 1
	.org $e000

	.bank 2
	.org $0000
	.incbin "mario.chr"

Now that being said, the end result when opening the game in FCEUX's PPU viewer (right) shows only pattern A (the sprites) but when I open the same file in NES Screen Tool I can look at both pattern tables.

Image

I'm not familiar with how the VRC6 handles graphics to be honest. Getting the chr file to even be visible in the game was hard enough. But now it seems like I only have half the data that should be there.
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: VRC6 CHR Bank Malformed?

Post by puppydrum64 »

Hang on, I think I know what's wrong.

"When bit 5 of $B003 is clear, CHR/CIRAM A10 will be controlled directly by the register LSB, causing 2 KiB banks to have duplicate 1 KiB halves. Existing Konami games did not use this configuration. This was intended for a different PCB (never used) where PPU A10 directly controls CHR A10 instead, permitting 512 KiB of CHR-ROM."

This might be the problem right here.

EDIT: I tried writing #%00100000 to $B003 but it doesn't seem to do anything.
Last edited by puppydrum64 on Wed May 12, 2021 8:21 am, edited 1 time in total.
User avatar
Controllerhead
Posts: 314
Joined: Tue Nov 13, 2018 4:58 am
Location: $4016
Contact:

Re: VRC6 CHR Bank Malformed?

Post by Controllerhead »

You sure are busy. If your header size and data locations are OK, you have to manually set each graphic bank according to what PPU banking style you are in:
https://wiki.nesdev.com/w/index.php/VRC ... .24B003.29
Image
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: VRC6 CHR Bank Malformed?

Post by tokumaru »

Remember to never trust the boot up state of *anything*! If you don't setup all the banking options via the mapper registers in your initialization code, you can't expect things to be mapped reliably.
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: VRC6 CHR Bank Malformed?

Post by puppydrum64 »

Controllerhead wrote: Wed May 12, 2021 8:19 am You sure are busy. If your header size and data locations are OK, you have to manually set each graphic bank according to what PPU banking style you are in:
https://wiki.nesdev.com/w/index.php/VRC ... .24B003.29
Yeah, definitely. I do ask a lot of questions haha. The music of Castlevania 3's Japanese version just blew me away with how good it is and I want to make a game that can have music like that. But it's hard to find documentation on the VRC6 that I can understand.

Code: Select all

pressA:
	rts
pressB:
	rts
pressSelect:
	rts
pressStart:
	lda #$20	;#%00100000		
	sta $b003	;  W.PN MMDD, nametables come from CHR-ROM
	rts
pressUp:
	lda #$01
	sta $D000	;ppu register R0
	rts
pressDown:
	lda #$01
	sta $D001	;ppu register R1
	rts
pressLeft:
	rts
pressRight:
	rts
Based on the setup I have, what I believe SHOULD happen is that pressing Start will stop the nametable mirroring that I see in my test rom, pressing UP switches to the CHR bank 0 (PPU $0000-$03FF) and DOWN will switch to CHR bank 1 (PPU $0400-$07FF).

For reference, after my interrupt vectors I have changed the CHR-ROM to the following:

Code: Select all

	.bank 2
	.org $0000
	.incbin "castlevania.chr"
	
	.bank 3
	.org $0400
	.incbin "mario.chr"
It seems to not make a difference whether "bank 3" is directed to start at $0000 or $0400; either way my bank switching command has no effect. Perhaps I don't understand the CHR select table and how to use it. It doesn't say how to switch them, just which ones are mapped to which registers. The wiki is a little vague about this but my understanding is:

$D000 = R0
$D001 = R1
$D002 = R2
$D003 = R3
$E000 = R4
$E001 = R5
$E002 = R6
$E003 = R7
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: VRC6 CHR Bank Malformed?

Post by puppydrum64 »

tokumaru wrote: Wed May 12, 2021 8:24 am Remember to never trust the boot up state of *anything*! If you don't setup all the banking options via the mapper registers in your initialization code, you can't expect things to be mapped reliably.

You mean like the .inesprg and .ineschr directives? Or the PPU banking style? Either way I can't get it to work once I've accounted for all that. But it could be an error on my part still so I'll continue tweaking it until I get a result.
User avatar
Controllerhead
Posts: 314
Joined: Tue Nov 13, 2018 4:58 am
Location: $4016
Contact:

Re: VRC6 CHR Bank Malformed?

Post by Controllerhead »

puppydrum64 wrote: Wed May 12, 2021 8:40 am You mean like the .inesprg and .ineschr directives?
Nah. Like writing initial values to the mapper registers in your boot up code. Code that will run on most emulators may fail on real hardware because these values are not guaranteed.

I would check the debugger / memory viewer and verify the code you think should be in memory is actually in memory. Remember that you have to set initial PRG banks as well, and as those values are not guaranteed, your initialization code should be done in the $E000-$FFFF range.
Image
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: VRC6 CHR Bank Malformed?

Post by puppydrum64 »

Controllerhead wrote: Wed May 12, 2021 9:25 am
puppydrum64 wrote: Wed May 12, 2021 8:40 am You mean like the .inesprg and .ineschr directives?
Nah. Like writing initial values to the mapper registers in your boot up code. Code that will run on most emulators may fail on real hardware because these values are not guaranteed.

I would check the debugger / memory viewer and verify the code you think should be in memory is actually in memory. Remember that you have to set initial PRG banks as well, and as those values are not guaranteed, your initialization code should be done in the $E000-$FFFF range.
I must have something set up very wrong because although my init code does start at $E000 it's also mirrored at $A000!
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: VRC6 CHR Bank Malformed?

Post by Quietust »

puppydrum64 wrote: Wed May 12, 2021 9:48 am I must have something set up very wrong because although my init code does start at $E000 it's also mirrored at $A000!
With the VRC6, you map a single 16KB PRG ROM bank at $8000-$BFFF, an 8KB PRG ROM bank at $C000-$DFFF, and the last 8KB of PRG ROM always appears at $E000-$FFFF. Because your entire PRG ROM is only 16KB long, whatever code/data you specified in .bank 0 and .bank 1 will always appear at $8000-$9FFF and $A000-$BFFF because that's literally the only option available to it.

However, there is no guarantee that "bank 0" will also appear at $C000-$DFFF, because your emulator might initialize its VRC6 code with the equivalent of LDA #$FF; STA $C000 which would put "bank 1" at $C000-$DFFF, and this is why your program needs to initialize everything.

The same would apply if your PRG ROM was 32KB (with 4 banks) - you could end up with $8000-$FFFF containing {bank 0, bank 1, bank 2, bank 3}, or you could get {bank 2, bank 3, bank 3, bank 3}, or you could get anything else in between - the last bank (#3) being at the end is the only guarantee you have.
puppydrum64 wrote: Wed May 12, 2021 8:38 am For reference, after my interrupt vectors I have changed the CHR-ROM to the following:

Code: Select all

	.bank 2
	.org $0000
	.incbin "castlevania.chr"
	
	.bank 3
	.org $0400
	.incbin "mario.chr"
Assuming you're using NESASM, I'm pretty sure that code is incorrect since each "bank" is 8KB in size. You should just have one single bank followed by a series of .incbin directives.
Last edited by Quietust on Wed May 12, 2021 10:29 am, edited 2 times in total.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: VRC6 CHR Bank Malformed?

Post by puppydrum64 »

Quietust wrote: Wed May 12, 2021 10:04 am
puppydrum64 wrote: Wed May 12, 2021 9:48 am I must have something set up very wrong because although my init code does start at $E000 it's also mirrored at $A000!
With the VRC6, you map a single 16KB PRG ROM bank at $8000-$BFFF, an 8KB PRG ROM bank at $C000-$DFFF, and the last 8KB of PRG ROM always appears at $E000-$FFFF. Because your entire PRG ROM is only 16KB long, your init code at $E000-$FFFF will also appear at $A000-$BFFF (and possibly also at $C000-$DFFF, depending on your emulator's mapper initialization logic).

Now, if your PRG ROM was actually 32KB or larger, it's still possible you could've seen this if your emulator decided to initialize the VRC6 with a simulated write of #$FF to $8000, and this is why you always have to initialize everything.
puppydrum64 wrote: Wed May 12, 2021 8:38 am For reference, after my interrupt vectors I have changed the CHR-ROM to the following:

Code: Select all

	.bank 2
	.org $0000
	.incbin "castlevania.chr"
	
	.bank 3
	.org $0400
	.incbin "mario.chr"
Assuming you're using NESASM, I'm pretty sure that code is incorrect since each "bank" is 8KB in size. You should just have one single bank followed by a series of .incbin directives.
Since I'm using NESASM3, would my header need to look like this?

Code: Select all

.inesprg 2
.ineschr 2
.inesmap 24
.inesmir 1
  .bank 0
  .org $8000
  .org $c000
  .org $e000
RESET:
; insert init code here

loop:
  Jmp loop
  
NMI:
  rti
 IRQ:
  rti
 
 .org $fffa
  dw NMI
  dw RESET
  dw IRQ
  
  .bank 2
  .org $0000
  .incbin "test0.chr"
  
  .org $0400
  .incbin "test1.chr"
  
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: VRC6 CHR Bank Malformed?

Post by Quietust »

puppydrum64 wrote: Wed May 12, 2021 10:25 am Since I'm using NESASM3, would my header need to look like this?

Code: Select all

.inesprg 2
.ineschr 2
.inesmap 24 1
  .bank 0
  .org $8000
  .org $c000
  .org $e000
RESET:
; insert init code here

loop:
  Jmp loop
  
NMI:
  rti
 IRQ:
  rti
 
 .org $fffa
  dw NMI
  dw RESET
  dw IRQ
  
  .bank 2
  .org $0000
  .incbin "test0.chr"
  
  .org $0400
  .incbin "test1.chr"
  
First of all, .inesprg 2 means you have 32KB of PRG ROM, and this means you must have 4 .banks containing PRG ROM:

Code: Select all

.bank 0
.org $x000 ; this could be $8000, $A000, or $C000
...

.bank 1
.org $x000; see above
...

.bank 2
.org $x000; see above
...

.bank 3
.org $E000 ; this one has to be $e000
; init code MUST be in this bank!
...
Also, .ineschr 2 means you need to have 16KB of CHR ROM, which would correspond to 2 .banks, and since they're not actually in the CPU's address space, I don't think you need any .org directives in them.

Under the assumption that "castlevania.chr" and "mario.chr" are both 8KB in length, you should have this:

Code: Select all

.bank 4
.incbin "castlevania.chr"
.bank 5
.incbin "mario.chr"
If they are smaller, then you would put them in the same bank. If they are larger than 8KB, then I'm pretty sure you'll have to split them into 8KB chunks and put each one in its own bank.

If it's not clear already, the "bank numbers" used by NESASM have no direct relation to the numbers you write to your mapper's PRG bank registers. This is because NESASM was based on the "MagicKit" assembler for the TurboGrafx-16 game console (which used the HuC6280 CPU which was based on the 6502). The TG16 supported 8KB ROM banking within the game console itself, so its assembler had special support for it.

By comparison, the NES has no builtin support for PRG ROM banking, so each cartridge has to handle it on its own. Since it still effectively supports banking, NESASM retained the "bank" directive out of convenience, though it's not necessarily as flexible as it would need to be. Other assemblers (such as ca65) will give you that added flexibility at the cost of increased complexity.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: VRC6 CHR Bank Malformed?

Post by puppydrum64 »

Quietust wrote: Wed May 12, 2021 10:35 am
puppydrum64 wrote: Wed May 12, 2021 10:25 am Since I'm using NESASM3, would my header need to look like this?

Code: Select all

.inesprg 2
.ineschr 2
.inesmap 24 1
  .bank 0
  .org $8000
  .org $c000
  .org $e000
RESET:
; insert init code here

loop:
  Jmp loop
  
NMI:
  rti
 IRQ:
  rti
 
 .org $fffa
  dw NMI
  dw RESET
  dw IRQ
  
  .bank 2
  .org $0000
  .incbin "test0.chr"
  
  .org $0400
  .incbin "test1.chr"
  
First of all, .inesprg 2 means you have 32KB of PRG ROM, and this means you must have 4 .banks containing PRG ROM:

Code: Select all

.bank 0
.org $x000 ; this could be $8000, $A000, or $C000
...

.bank 1
.org $x000; see above
...

.bank 2
.org $x000; see above
...

.bank 3
.org $E000 ; this one has to be $e000
; init code MUST be in this bank!
...
Also, .ineschr 2 means you need to have 16KB of CHR ROM, which would correspond to 2 .banks, and since they're not actually in the CPU's address space, I don't think you need any .org directives in them.

Under the assumption that "castlevania.chr" and "mario.chr" are both 8KB in length, you should have this:

Code: Select all

.bank 4
.incbin "castlevania.chr"
.bank 5
.incbin "mario.chr"
If they are smaller, then you would put them in the same bank. If they are larger than 8KB, then I'm pretty sure you'll have to split them into 8KB chunks and put each one in its own bank.

If it's not clear already, the "bank numbers" used by NESASM have no direct relation to the numbers you write to your mapper's PRG bank registers. This is because NESASM was based on the "MagicKit" assembler for the TurboGrafx-16 game console (which used the HuC6280 CPU which was based on the 6502). The TG16 supported 8KB ROM banking within the game console itself, so its assembler had special support for it.

By comparison, the NES has no builtin support for PRG ROM banking, so each cartridge has to handle it on its own. Since it still effectively supports banking, NESASM retained the "bank" directive out of convenience, though it's not necessarily as flexible as it would need to be. Other assemblers (such as ca65) will give you that added flexibility at the cost of increased complexity.
That's probably where my confusion is coming from; the "bank" directive not lining up with the NES's banks. As for why I used "inesprg 2", I figured since the VRC6 has the following:

$8000-$BFFF: 16 KB switchable PRG ROM bank
$C000-$DFFF: 8 KB switchable PRG ROM bank
$E000-$FFFF: 8 KB PRG ROM bank, fixed to the last bank

This adds up to 32K so I would need more than 16K of PRG ROM, no? At any rate I couldn't get your version or the one I had posted to actually show anything other than a blank screen. This is what I have now and it works (I will include my entire source document just in case there's some other issue going on there but for simplicity I'll list only the directives first:

Code: Select all


  .inesprg 1    ; 1x 16KB PRG code
  .ineschr 2    ; 2x  8KB CHR data
  .inesmap 24	; Konami VRC6 Version 1 (Akumajou Densetsu)
  .inesmir 1    ; background mirroring (Vertical mirroring for Horizontal Scrolling)
  
	.bank 0
	.org $c000
	
	.include "pad8k.asm"
	
	.bank 1
	.org $e000
	
	RESET:
	
	loop:
		jmp loop
		
	NMI:
		rti
	IRQ:
		rti
	
	.org $FFFA
	dw nmihandler			;FFFA - Interrupt handler
	dw RESET				;FFFC - Entry point
	dw irqhandler			;FFFE - IRQ Handler
	
	.bank 2
	.incbin "castlevania.chr"	;8k .chr file
	
	.bank 3
	.incbin "mario.chr"		;8k .chr file
The source document is below:

Code: Select all

  .inesprg 1    ; 1x 16KB PRG code
  .ineschr 2    ; 2x  8KB CHR data
  .inesmap 24	; Konami VRC6 Version 1 (Akumajou Densetsu)
  .inesmir 1    ; background mirroring (Vertical mirroring for Horizontal Scrolling)

  
  .include "NESmacros.asm"                     ;no macros used in this document right now.
  
BUTTON_A EQU $80
BUTTON_B EQU $40
BUTTON_SELECT EQU $20
BUTTON_START EQU $10
BUTTON_UP	EQU $08
BUTTON_DOWN EQU $04
BUTTON_LEFT EQU $02
BUTTON_RIGHT EQU $01

  


	.rsset $0000	;ZERO PAGE RAM
vblanked 		.rs 1	;vBlank timer
soft2000 		.rs 1	;PPUCTRL buffer
soft2001		.rs 1	;PPUMASK buffer
joypad1 		.rs 1   ;button states for the current frame
joypad1_old 	.rs 1   ;last frame's button states
joypad1_pressed .rs 1   ;current frame's off_to_on transitions
pointerLo		.rs 1	
pointerHi		.rs 1
scroll			.rs 1	;PPUSCROLL buffer
nametable		.rs 1	;which nametable is in the top left, to be EOR'd with PPUCTRL ($2000)
temp16Lo		.rs 1
temp16Hi		.rs 1
currentBank16k	.rs 1	;currently active 16k PRG-ROM bank from $8000 to $BFFF
currentBank8k	.rs 1	;currently active 8k  PRG-ROM bank from $C000 to $DFFF
prevBank16k		.rs 1	;most recent 16k PRG-ROM bank for bank switching
prevBank8k		.rs 1	;most recent 8k  PRG-ROM bank for bank switching 

	;$0200-02ff reserved for OAM

	.rsset $0300	;sound ram
soft4000	.rs 1
soft4001	.rs 1
soft4002	.rs 1
soft4003	.rs 1
soft4004	.rs 1
soft4005	.rs 1
soft4006	.rs 1
soft4007	.rs 1
soft4008	.rs 1

soft400A	.rs 1
soft400B	.rs 1
soft400C	.rs 1

soft400E	.rs 1
soft400F	.rs 1
soft4010	.rs 1
soft4011	.rs 1
soft4012	.rs 1
soft4013	.rs 1
soft4015	.rs 1
soft4017	.rs 1
	
soft9000	.rs 1
soft9001	.rs 1
soft9002	.rs 1
softA000	.rs 1
softA001	.rs 1
softA002	.rs 1
softB000	.rs 1
softB001	.rs 1
softB002	.rs 1


;MEMORY MAPPED ADDRESSES - THESE LOCATIONS WERE NOT DECIDED BY ME.
;STANDARD NES - COMMON TO ALL GAMES
PPUCTRL				equ $2000	;VPHB SINN
PPUMASK				equ $2001	;BGRs bMmG
PPUSTATUS			equ $2002	;VSO- ----
OAMADDR				equ $2003
OAMDATA				equ $2004
PPUSCROLL			equ $2005
PPUADDR				equ $2006
PPUDATA				equ $2007
OAMDMA				equ $4014
APUCTRL				equ $4015
CONTROLLER1			equ $4016
CONTROLLER2			equ $4017
APUIRQ				equ $4017

;KONAMI VRC6 MEMORY MAPPED LOCATIONS
PULSE1_CTRL	   equ $9000
PULSE1_FREQ_LO equ $9001
PULSE1_FREQ_HI equ $9002

PULSE2_CTRL    equ $A000
PULSE2_FREQ_LO equ $A001
PULSE2_FREQ_HI equ $A002

SAW_ACCUM 	   equ $B000
SAW_FREQ_LO    equ $B001
SAW_FREQ_HI    equ $B002

PPU_BANKING_STYLE equ $B003

R0 EQU $D000
R1 EQU $D001
R2 EQU $D002
R3 EQU $D003
R4 EQU $E000
R5 EQU $E001
R6 EQU $E002
R7 EQU $E003

IRQ_LATCH	equ $F000
IRQ_CTRL	equ $F001
IRQ_ACK		equ $F002

	.bank 0
	.org $c000
	
	.include "pad8k.asm"   ;contains "db $00" a total of $2000 times to fill this bank with #$00 instead of #$ff.
	
	.bank 1
	.org $e000
RESET:		;this section of code written by Joe Granato www.thenew8bitheroes.com
	SEI		;ignore interrupts for the reset
	LDA #$00	; load the number 00
	STA $2000	; disables NMI
	STA $2001	; disables rendering
	STA $4010	; disables DMC IRQ 
	STA $4015	; disables APU sound
	LDA #$40	; Loads the number 64
	STA $4017	; disables the APU IRQ
	CLD			; disables decimal mode 
	LDX	#$FF		
	TXS			; initializes the stack
	

	JSR vBlankWait
	
	LDA #$00
	
;6. Clear all ram 
	LDX #$00
clrMemLoop:
	LDA #$00
	STA $0000,x
	STA $0100,x 
	;; skip 200, this is where the sprites are drawn
	;; we'll set them to $FE to draw them off screen
	STA $0300,x
	STA $0400,x
	STA $0500,x
	STA $0600,x
	STA $0700,x
	LDA #$FE		; instead of zero, write #$FE to 0200,x
	STA $0200,x		; to place sprites off screen
	INX
	BNE clrMemLoop
	
;7. Second vblank 
	JSR vBlankWait
	
;7.5 Initialize banks
	LDA $00		;bank 0
	STA currentBank16k
	STA prevBank16k
	STA $8000 	;16k
	
	STA currentBank8k
	STA prevBank8k
	STA $C000


;8 Enable audio
	LDA #0
	STA $9003	;enable VRC6 audio
	
	LDA #$1F
	STA $4015	;enable square 1, square 2, triangle, noise, and DPCM

	lda #$20
	sta PPU_BANKING_STYLE	;set bit 5 disabling PPU mirroring
	
; Draw initial background
	lda #LOW(background)
	sta pointerLo
	lda #HIGH(background)
	sta pointerHi
	
	JSR LoadBackground
	

;9 Load Palettes
LoadPalettes:
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA #$3F
  STA $2006             ; write the high byte of $3F00 address
  LDA #$00
  STA $2006             ; write the low byte of $3F00 address
  LDX #$00              ; start out at 0
LoadPalettesLoop:
  LDA palette, x        ; load data from address (palette + the value in x)
                          ; 1st time through loop it will load palette+0
                          ; 2nd time through loop it will load palette+1
                          ; 3rd time through loop it will load palette+2
                          ; etc
  STA $2007             ; write to PPU
  INX                   ; X = X + 1
  CPX #$20              ; Compare X to hex $10, decimal 16 - copying 16 bytes = 4 sprites
  BNE LoadPalettesLoop  ; Branch to LoadPalettesLoop if compare was Not Equal to zero
                        ; if compare was equal to 32, keep going down
						
LoadAttributeData:
	lda $2002
	lda #$23
	sta $2006
	lda #$c0
	sta $2006
	
	ldx #0
	ldy #0
	
AttributeOuterLoop:

AttributeInnerLoop:
	lda attribute,x
	sta $2007
	inx
	cpx #$08
	bne AttributeInnerLoop
	
	ldx #0
	iny
	cpy #$08
	bne AttributeOuterLoop
	
	

;10 Enable NMI
	LDA #%10010000	; turn on NMI, set sprites $0000, bkg to $1000
	STA $2000
	STA soft2000
	LDA #%00011110
	sta soft2001
	STA $2001
	
	LDA #$00
	STA $2005
	STA $2005
	;;DON'T TURN ON RENDERING UNTIL FIRST GRAPHICS ARE DRAWN.

	
	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAIN GAME LOOP;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


MainGameLoop:
	jsr read_joypad
	jsr handle_input
	jmp MainGameLoop
	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  INTERRUPTS  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	
nmihandler:				;This procuedure runs after each frame (See footer.asm)
	php
	pha     ;save registers
    txa
    pha
    tya
    pha
	
	
	
	LDA #0
	STA vblanked
	
PerformOAMDMA:
	LDA #$00
	STA $2003  ; set the low byte (00) of the RAM address
	LDA #$02
	STA $4014  ; set the high byte (02) of the RAM address, start the transfer
	

	

	INC scroll            ; add one to our scroll variable each frame


NTSwapCheck:
	LDA scroll            ; check if the scroll just wrapped from 255 to 0
	BNE NTSwapCheckDone  
NTSwap:
	LDA nametable         ; load current nametable number (0 or 1)
	EOR #$01              ; exclusive OR of bit 0 will flip that bit
	STA nametable         ; so if nametable was 0, now 1
                        ;    if nametable was 1, now 0
NTSwapCheckDone:
  
	lda scroll
	sta $2005
	lda #0
	sta $2005
	
	lda soft2000
	eor nametable
	sta soft2000
	sta $2000

	
loop_vrc6:
	lda soft9000
	sta $9000
	lda soft9001
	sta $9001
	lda soft9002
	sta $9002
	
	
	
	
	
	pla     ;restore registers
    tay
    pla
    tax
    pla
	plp
	rti

irqhandler:
	rti					;Do nothing
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SUBROUTINES;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
vBlankWait:
	bit $2002
	BPL vBlankWait
	RTS

read_joypad:
    lda joypad1
    sta joypad1_old ;save last frame's joypad button states
    
    lda #1
    sta $4016
    lda #0
    sta $4016
    
    ldx #8
.loop:    
    lda $4016
    lsr a
    rol joypad1  ;A, B, select, start, up, down, left, right
    dex
    bne .loop
    
    lda joypad1_old ;what was pressed last frame.  EOR to flip all the bits to find ...
    eor #$FF    ;what was not pressed last frame
    and joypad1 ;what is pressed this frame
    sta joypad1_pressed ;stores off-to-on transitions
    

;---------------------
; handle_input will perform actions based on input:
handle_input:

.check_A:
    lda joypad1_pressed
    and #BUTTON_A	;BUTTON A
    beq .check_B
    ;;;UR CODE FOR WHAT HAPPENS WHEN U PRESS A GOES HERE
	jsr pressA
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;	
.check_B:
    lda joypad1_pressed
    and #BUTTON_B
    beq .check_select
    ;;;UR CODE FOR WHAT HAPPENS WHEN U PRESS B GOES HERE
	jsr pressB
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;		
.check_select
	lda joypad1_pressed
	and #BUTTON_SELECT
	beq .check_start
	;;;UR CODE FOR WHAT HAPPENS WHEN U PRESS SELECT GOES HERE
	jsr pressSelect
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;		
.check_start:
	lda joypad1_pressed
	and #BUTTON_START
	beq .check_up
	;;;UR CODE FOR WHAT HAPPENS WHEN U PRESS START GOES HERE
	jsr pressStart
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;		
.check_up:
	lda joypad1
	and #BUTTON_UP
	beq .check_down
	;;;UR CODE FOR WHAT HAPPENS WHEN U PRESS UP GOES HERE
	jsr pressUp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;		
.check_down:
	lda joypad1
	and #BUTTON_DOWN
	beq .check_left
	;;;UR CODE FOR WHAT HAPPENS WHEN U PRESS DOWN GOES HERE
	jsr pressDown
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;	
.check_left:
	lda joypad1
	and #BUTTON_LEFT
	beq .check_right
	;;;UR CODE FOR WHAT HAPPENS WHEN U PRESS LEFT GOES HERE
	jsr pressLeft
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;		
.check_right:
	lda joypad1_pressed
	and #BUTTON_RIGHT
	beq .done
	;;;UR CODE FOR WHAT HAPPENS WHEN U PRESS RIGHT GOES HERE
	jsr pressRight
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;	
.done:
	rts
pressA:
	rts
pressB:
	rts
pressSelect:
	rts
pressStart:
	lda #$20	;#%00100000		
	sta $b003	;  W.PN MMDD, nametables come from CHR-ROM
	rts
pressUp:
	lda #$01
	sta $D000	;ppu register R0
	rts
pressDown:
	lda #$01
	sta $D001	;ppu register R1
	rts
pressLeft:
	rts
pressRight:
	rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

LoadBackground:
	LDA $2002
	LDA #$20
	STA $2006
	LDA #$00
	STA $2006
	
	LDX #4
	LDY #0
LoadBackgroundLoop:
	
InnerBackgroundLoop:
	LDA [pointerLo],y
	STA $2007
	
	INY
	BNE InnerBackgroundLoop
	
	INC pointerHi
	
	DEX
	BNE LoadBackgroundLoop
	
	rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;BANK SWITCH SUBROUTINE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SwitchBank16k:
	STA $
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;TILEMAPS ETC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

background:
	.include "title2.asm"
palette:
  .db $22,$29,$1A,$0F,  $22,$36,$17,$0F,  $22,$30,$21,$0F,  $22,$27,$17,$0F   ;;background palette
  .db $22,$1C,$15,$14,  $22,$02,$38,$3C,  $22,$1C,$15,$14,  $22,$02,$38,$3C   ;;sprite palette

attribute:
  .db $55, $55, $55, $55, $55, $55, $55, $55		;#%01010101 - all 4 corners using palette 1
  
sprites:
     ;vert tile attr horiz
  .db $80, $32, $00, $80   ;sprite 0
  .db $80, $33, $00, $88   ;sprite 1
  .db $88, $34, $00, $80   ;sprite 2
  .db $88, $35, $00, $88   ;sprite 3


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;FOOTER;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	.org $FFFA
	dw nmihandler			;FFFA - Interrupt handler
	dw RESET				;FFFC - Entry point
	dw irqhandler			;FFFE - IRQ Handler
	
	.bank 2
	.incbin "castlevania.chr"
	
	.bank 3
	.incbin "mario.chr"

EDIT: I reread your earlier reply and saw some more details I missed earlier. So I tried it again with the following directives (I only changed the directives so I'll leave out the rest of the source code):

Code: Select all

	.bank 0
	.org $8000
	
	.include "pad8k.asm"		;this is just a bunch of zeroes that takes up 8k.
	
	.bank 1
	.org $A000
	
	.include "pad8k.asm"
	
	.bank 2
	.org $C000
	.include "pad8k.asm"
	
	.bank 3
	.org $E000
RESET:

loop:
	jmp loop
	
NMI:
	rti
	
IRQ:
	rti
	
	.org $fffa
	dw NMI
	dw RESET
	dw IRQ
	
	.bank 4
	.incbin "castlevania.chr"
	
	.bank 5
	.incbin "mario.chr"
	
This seems to work, but I still have the same issue with the mirroring of the CHR file. Even though I initialized it by setting $B003 to #$20. Not sure why that is. Also I still haven't figured out how to actually switch banks on the VRC6
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: VRC6 CHR Bank Malformed?

Post by Quietust »

A few observations:
1. You have symbolic constants for a bunch of different registers, but you never use any of them (except for the VRC6 "PPU_BANKING_STYLE" in one place)
2. At the very end of your init code is a comment ";;DON'T TURN ON RENDERING UNTIL FIRST GRAPHICS ARE DRAWN.", but the code immediately preceding that comment ignores it and does "LDA #%00011110" and "STA $2001" (which turns on rendering).
3. Your NMI handler should probably be doing "LDA soft2001" + "STA $2001".
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: VRC6 CHR Bank Malformed?

Post by puppydrum64 »

Quietust wrote: Wed May 12, 2021 2:01 pm A few observations:
1. You have symbolic constants for a bunch of different registers, but you never use any of them (except for the VRC6 "PPU_BANKING_STYLE" in one place)
2. At the very end of your init code is a comment ";;DON'T TURN ON RENDERING UNTIL FIRST GRAPHICS ARE DRAWN.", but the code immediately preceding that comment ignores it and does "LDA #%00011110" and "STA $2001" (which turns on rendering).
3. Your NMI handler should probably be doing "LDA soft2001" + "STA $2001".
I chose not to use them because I felt I would forget what they were and how to use them if I didn't. As for the second point, I thought that I had already drawn the background prior to that point so there was no issue. I'll go and look at these and fix them either way

Edit: I had already drawn the background just after audio init. I didn't number it in the list, that was poor documentation on my part.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: VRC6 CHR Bank Malformed?

Post by tokumaru »

puppydrum64 wrote: Wed May 12, 2021 2:07 pm

Code: Select all

.include "pad8k.asm"
There's no need to use external files for padding... Any decent assembler will have a directive to fill memory. It looks like NESASM uses DS for this (e.g. .ds 8192 to generate 8KB of zeros). But with NESASM's mandatory BANK directives, I don't think you even need to do any manual padding, each "bank" will be 8KB no matter what you put on it.
Post Reply