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