A similar question was asked here but I read it and didn't really understand the solution.
What I'm trying to do here is make an NES ROM that uses Mapper 24, aka Konami VRC6 Version 1 (the one used by the Japanese Castlevania III with the extra sound channels.) I've had trouble getting this mapper to work in the past, but I've managed to get it running properly on NESASM3 and ASM6. However, ca65 poses a challenge since it doesn't really use .org to assign areas of code. I've created my own .cfg file for this mapper as well as the actual code but neither seems to work properly. The only thing that gets added to the rom is the palette data, which is supposed to be in the .rodata segment (assigned to address $A000) but gets placed at $E000 where my reset handler is supposed to go.
If you're not familiar with the VRC6, it has a fixed ROM bank in $E000, and a 16k switchable bank from $8000-$BFFF, and a 8k switchable bank from $C000-DFFF. This is the explanation that the NESDev Wiki gives, which is sort of misleading, because technically all banks are 8k, it's just that if you set the 16k bank to bank n, it displays bank n at $8000-$9fff and bank n+1 at $A000-$BFFF. Once I figured this out I got it working on other assemblers.
TL;DR:
- How do I set up multiple banks on an NES ROM using ca65/ld65?
- Since the banks can be slotted in at will at runtime, how can I tell ca65 that a particular segment is intended to be part of switchable ROM?
- How do I get the fixed section of ROM to go to $E000 where it belongs?
Here's my config file:
# ca65 configuration for Konami VRC6 Type 1 (Akumajou Densetsu)
# Defines areas where code/data is put into memory during linking
# fill=yes forces area to be padded to specified size in output
# Based on the following template:
#
# Linker script for NROM-128 games
# Copyright 2010-2014 Damian Yerrick
#
# Copying and distribution of this file, with or without
# modification, are permitted in any medium without royalty
# provided the copyright notice and this notice are preserved.
# This file is offered as-is, without any warranty.
#
MEMORY
{
# 2K RAM in NES
ZP: start = 0, size = $100, type = rw, file = %O;
# Skip the $100 bytes for stack
WRAM: start = $200, size = $600, type = rw, file = %O;
# Pseudo area for iNES header
HEADER: start = $7FF0, size = 16, type = ro, fill = yes, file = %O;
# ROM
PRGBANK_0: start = $8000, size = $2000, type = ro, fill = yes, file = %O;
PRGBANK_1: start = $A000, size = $2000, type = ro, fill = yes, file = %O;
FIXED: start = $E000, size = $1FFA, type = ro, fill = yes, file = %O;
VECTORS: start = $FFFA, size = 6, type = ro, fill = yes, file = %O;
# CHR_ROM
CHR_ROM: start = 0, size = $2000, type = ro, fill = yes, file = %O;
}
# Defines named segments you refer to in assembler, and sets up order
# of data in output file
# align=$100 allows use of .align directive with a value up to $100
SEGMENTS
{
ZEROPAGE: load = ZP, type = zp;
BSS: load = WRAM, type = bss;
HEADER: load = HEADER, type = ro;
CODE: load = PRGBANK_0, type = ro;
RODATA: load = PRGBANK_1, type = ro;
STARTUP: load = FIXED, type = ro;
VECTORS: load = VECTORS,type = ro;
CHR: load = CHR_ROM, type = ro, align = 16, optional = yes;
}
And here is my actual code.
.include "VasmCompatibility.inc"
.include "VRC6_Memory_Map.inc"
.include "C:\cc65\asminc\nes.inc"
; iNES header
.segment "HEADER"
INES_MAPPER = 24
INES_MIRROR = 0 ; 0 = horizontal mirroring, 1 = vertical mirroring
INES_SRAM = 0 ; 1 = battery backed SRAM at $6000-7FFF
INES_PRG = 1 ; 16k PRG-ROM bank count
INES_CHR = 1 ; 8k CHR-ROM file count
.byte 'N', 'E', 'S', $1A ; ID
.byte INES_PRG ; 16k PRG bank count
.byte INES_CHR ; 8k CHR bank count
.byte INES_MIRROR | (INES_SRAM << 1) | ((INES_MAPPER & $f) << 4)
.byte (INES_MAPPER & %11110000)
.byte $0, $0, $0, $0, $0, $0, $0, $0 ; padding
.zeropage
.bss
.segment "CODE"
.segment "RODATA"
palette:
.BYTE $0D,$29,$1A,$0D, $0D,$36,$17,$0D, $0D,$30,$21,$0D, $0D,$29,$27,$16 ;;background palette
.BYTE $0D,$1C,$15,$14, $0D,$02,$38,$3C, $0D,$1C,$15,$14, $0D,$02,$38,$3C ;;sprite palette
.segment "STARTUP"
reset_handler:
;reset code goes here
nmi_handler:
RTI
irq_handler:
RTI
.segment "VECTORS"
.addr nmi_handler, reset_handler, irq_handler
.segment "CHR"
.incbin "chicago_oblique_aka_ff6_font.chr"