Closed R1gh1 closed 5 years ago
Hi again,
In case someone is interested about the solution for my previous question here you have the details:
Define the right ROM type into _nrom_32kvert.cfg in the SYMBOLS as follow
NES_MAPPER: type = weak, value = 3; # mapper number, 0 = NROM , 3 for CNROM
In fact :
Define the number of CHR banks you want to use into the _nrom_32kvert.cfg SYMBOLS as follow:
NES_CHR_BANKS: type = weak, value = 2; # number of 8K CHR banks
Add an additional CHR section into SEGMENTS definition into _nrom_32kvert.cfg
CHARS: load = CHR, type = rw;
CHARS: load = CHR, type = rw;
Define the CHR segment into the crt0.s file and include the .chr file you need:
.segment "CHAR0"
.incbin "yourCHRFile0.chr"
.segment "CHAR1"
.incbin "yourCHRFile0.chr"
5. When you want to switch to the second CHR bank you can use the following function into your program:
```c
static void bankswitch(const unsigned char chrNum) {
static const unsigned char arr[] = {
0, 1, 2, 3, 4
};
(unsigned char) arr[chrNum] = chrNum;
}
void main (void) {
ppu_off(); // screen off
//switch to CHR bank 1
bankswitch(1);
ppu_on_all(); // turn on screen
while (1){
//Do stuff here ...
}
}
This normally should perform a bank switch and load the second CHR file.
As an annex, the full nrom_32k_vert.cfg:
MEMORY {
#RAM Addresses:
# Zero page
ZP: start = $00, size = $100, type = rw, define = yes;
#note, the c compiler + neslib + famitone2 use about 60 zp addresses, I think
#note OAM: start = $0200, size = $0100, define = yes;
#note, sprites stored here in the RAM
RAM: start = $0300, size = $0400, define = yes;
#note VRAM_BUFFER: start = $700, size = 128, define = yes;
#INES Header:
HEADER: start = $0, size = $10, file = %O ,fill = yes;
#ROM Addresses:
PRG: start = $8000, size = $8000, file = %O ,fill = yes, define = yes;
#1 Bank of 8K CHR ROM
CHR: start = $0000, size = $2000, file = %O, fill = yes;
CHR1: start = $0000, size = $2000, file = %O, fill = yes;
}
SEGMENTS {
HEADER: load = HEADER, type = ro;
STARTUP: load = PRG, type = ro, define = yes;
LOWCODE: load = PRG, type = ro, optional = yes;
INIT: load = PRG, type = ro, define = yes, optional = yes;
CODE: load = PRG, type = ro, define = yes;
RODATA: load = PRG, type = ro, define = yes;
DATA: load = PRG, run = RAM, type = rw, define = yes;
CHAR0: load = CHR, type = rw;
CHAR1: load = CHR1, type = rw;
BSS: load = RAM, type = bss, define = yes;
HEAP: load = RAM, type = bss, optional = yes;
ZEROPAGE: load = ZP, type = zp;
ONCE: load = PRG, type = ro, define = yes, optional = yes;
SAMPLES: load = PRG, start = $f000, type = ro, optional = yes;
VECTORS: load = PRG, start = $fffa, type = ro;
}
#removed CONDES features
SYMBOLS {
__STACKSIZE__: type = weak, value = $0100; # 1 page stack
__STACK_START__: type = weak, value = $0700;
NES_MAPPER: type = weak, value = 3; # mapper number, 0 = NROM , 3 for CNROM
NES_PRG_BANKS: type = weak, value = 2; # number of 16K PRG banks, change to 2 for NROM256
NES_CHR_BANKS: type = weak, value = 2; # number of 8K CHR banks
NES_MIRRORING: type = weak, value = 1; # 0 horizontal, 1 vertical, 8 four screen
}
And the crt0.s file :
; Startup code for cc65 and Shiru's NES library
; based on code by Groepaz/Hitmen <groepaz@gmx.net>, Ullrich von Bassewitz <uz@cc65.org>
FT_BASE_ADR = $0100 ;page in RAM, should be $xx00
FT_DPCM_OFF = $f000 ;$c000..$ffc0, 64-byte steps
FT_SFX_STREAMS = 1 ;number of sound effects played at once, 1..4
FT_THREAD = 1 ;undefine if you call sound effects in the same thread as sound update
FT_PAL_SUPPORT = 1 ;undefine to exclude PAL support
FT_NTSC_SUPPORT = 1 ;undefine to exclude NTSC support
FT_DPCM_ENABLE = 0 ;undefine to exclude all DMC code
FT_SFX_ENABLE = 1 ;undefine to exclude all sound effects code
;REMOVED initlib
;this called the CONDES function
.export _exit,__STARTUP__:absolute=1
.import push0,popa,popax,_main,zerobss,copydata
; Linker generated symbols
.import __STACK_START__ ,__STACKSIZE__ ;changed
.import __ROM0_START__ ,__ROM0_SIZE__
.import __STARTUP_LOAD__,__STARTUP_RUN__,__STARTUP_SIZE__
.import __CODE_LOAD__ ,__CODE_RUN__ ,__CODE_SIZE__
.import __RODATA_LOAD__ ,__RODATA_RUN__ ,__RODATA_SIZE__
.import NES_MAPPER, NES_PRG_BANKS, NES_CHR_BANKS, NES_MIRRORING
.importzp _PAD_STATE, _PAD_STATET ;added
.include "zeropage.inc"
PPU_CTRL =$2000
PPU_MASK =$2001
PPU_STATUS =$2002
PPU_OAM_ADDR=$2003
PPU_OAM_DATA=$2004
PPU_SCROLL =$2005
PPU_ADDR =$2006
PPU_DATA =$2007
PPU_OAM_DMA =$4014
PPU_FRAMECNT=$4017
DMC_FREQ =$4010
CTRL_PORT1 =$4016
CTRL_PORT2 =$4017
OAM_BUF =$0200
PAL_BUF =$01c0
VRAM_BUF =$0700
.segment "ZEROPAGE"
NTSC_MODE: .res 1
FRAME_CNT1: .res 1
FRAME_CNT2: .res 1
VRAM_UPDATE: .res 1
NAME_UPD_ADR: .res 2
NAME_UPD_ENABLE: .res 1
PAL_UPDATE: .res 1
PAL_BG_PTR: .res 2
PAL_SPR_PTR: .res 2
SCROLL_X: .res 1
SCROLL_Y: .res 1
SCROLL_X1: .res 1
SCROLL_Y1: .res 1
PAD_STATE: .res 2 ;one byte per controller
PAD_STATEP: .res 2
PAD_STATET: .res 2
PPU_CTRL_VAR: .res 1
PPU_CTRL_VAR1: .res 1
PPU_MASK_VAR: .res 1
RAND_SEED: .res 2
FT_TEMP: .res 3
TEMP: .res 11
PAD_BUF =TEMP+1
PTR =TEMP ;word
LEN =TEMP+2 ;word
NEXTSPR =TEMP+4
SCRX =TEMP+5
SCRY =TEMP+6
SRC =TEMP+7 ;word
DST =TEMP+9 ;word
RLE_LOW =TEMP
RLE_HIGH =TEMP+1
RLE_TAG =TEMP+2
RLE_BYTE =TEMP+3
;nesdoug code requires
VRAM_INDEX: .res 1
META_PTR: .res 2
DATA_PTR: .res 2
.segment "HEADER"
.byte $4e,$45,$53,$1a
.byte <NES_PRG_BANKS
.byte <NES_CHR_BANKS
.byte <NES_MIRRORING|(<NES_MAPPER<<4)
.byte <NES_MAPPER&$f0
.res 8,0
.segment "STARTUP"
start:
_exit:
sei
cld
ldx #$40
stx CTRL_PORT2
ldx #$ff
txs
inx
stx PPU_MASK
stx DMC_FREQ
stx PPU_CTRL ;no NMI
initPPU:
bit PPU_STATUS
@1:
bit PPU_STATUS
bpl @1
@2:
bit PPU_STATUS
bpl @2
clearPalette:
lda #$3f
sta PPU_ADDR
stx PPU_ADDR
lda #$0f
ldx #$20
@1:
sta PPU_DATA
dex
bne @1
clearVRAM:
txa
ldy #$20
sty PPU_ADDR
sta PPU_ADDR
ldy #$10
@1:
sta PPU_DATA
inx
bne @1
dey
bne @1
clearRAM:
txa
@1:
sta $000,x
sta $100,x
sta $200,x
sta $300,x
sta $400,x
sta $500,x
sta $600,x
sta $700,x
inx
bne @1
lda #4
jsr _pal_bright
jsr _pal_clear
jsr _oam_clear
jsr zerobss
jsr copydata
lda #<(__STACK_START__+__STACKSIZE__) ;changed
sta sp
lda #>(__STACK_START__+__STACKSIZE__)
sta sp+1 ; Set argument stack ptr
; jsr initlib
; removed. this called the CONDES function
lda #%10000000
sta <PPU_CTRL_VAR
sta PPU_CTRL ;enable NMI
lda #%00000110
sta <PPU_MASK_VAR
waitSync3:
lda <FRAME_CNT1
@1:
cmp <FRAME_CNT1
beq @1
detectNTSC:
ldx #52 ;blargg's code
ldy #24
@1:
dex
bne @1
dey
bne @1
lda PPU_STATUS
and #$80
sta <NTSC_MODE
jsr _ppu_off
lda #0
ldx #0
jsr _set_vram_update
ldx #<music_data
ldy #>music_data
lda <NTSC_MODE
jsr FamiToneInit
.if(FT_SFX_ENABLE)
ldx #<sounds_data
ldy #>sounds_data
jsr FamiToneSfxInit
.endif
lda #$fd
sta <RAND_SEED
sta <RAND_SEED+1
lda #0
sta PPU_SCROLL
sta PPU_SCROLL
jmp _main ;no parameters
.include "LIB/neslib.s"
.include "LIB/nesdoug.s"
.include "MUSIC/famitone2.s"
.segment "RODATA"
music_data:
; .include "music.s"
.if(FT_SFX_ENABLE)
sounds_data:
; .include "sounds.s"
.endif
.segment "SAMPLES"
; .incbin "music_dpcm.bin"
.segment "VECTORS"
.word nmi ;$fffa vblank nmi
.word start ;$fffc reset
.word irq ;$fffe irq / brk
.segment "CHAR0"
.incbin "yourCHRFile0.chr"
.segment "CHAR1"
.incbin "yourCHRFile0.chr"
Hello,
First of all a big big thanks for your awesome work on the NES development scene. The tutorials you wrote are great and really helpful !
I'm opening this issue as I would like to understand how it is possible for a game to include multiples .chr files. The main idea behind this question is the following scenario:
I hope my question is clear enough. If not don't hesitate to ask for more details.
Have a nice day,