1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2025-02-02 15:33:43 +00:00

nes: bank switching .cfg for MMC3 via NES_MAPPER=4; reverse A/B btns

This commit is contained in:
Steven Hugg 2019-03-13 14:52:30 -04:00
parent 1e44d05536
commit 98ccf2b26a
7 changed files with 178 additions and 16 deletions

76
presets/nes/bankswitch.c Normal file
View File

@ -0,0 +1,76 @@
// bank-switching configuration
#define NES_MAPPER 4 // Mapper 4 (MMC3)
#define NES_PRG_BANKS 4 // # of 16KB PRG banks
#define NES_CHR_BANKS 8 // # of 8KB CHR banks
#include <peekpoke.h>
#include <string.h>
#include "neslib.h"
// link the pattern table into CHR ROM
//#link "chr_generic.s"
#define MMC_MODE 0x00
#define MMC3_SET_REG(r,n)\
POKE(0x8000, MMC_MODE|(r));\
POKE(0x8001, (n));
#define MMC3_CHR_0000(n) MMC3_SET_REG(0,n)
#define MMC3_CHR_0800(n) MMC3_SET_REG(1,n)
#define MMC3_CHR_1000(n) MMC3_SET_REG(2,n)
#define MMC3_CHR_1400(n) MMC3_SET_REG(3,n)
#define MMC3_CHR_1800(n) MMC3_SET_REG(4,n)
#define MMC3_CHR_1C00(n) MMC3_SET_REG(5,n)
#define MMC3_PRG_8000(n) MMC3_SET_REG(6,n)
#define MMC3_PRG_A000(n) MMC3_SET_REG(7,n)
#define MMC3_MIRROR(n) POKE(0xa000, (n))
#pragma rodata-name("CODE0")
const unsigned char TEXT0[]={"Bank 0 @ 8000"};
#pragma rodata-name("CODE1")
const unsigned char TEXT1[]={"Bank 1 @ 8000"};
#pragma rodata-name("CODE5")
const unsigned char TEXT5[]={"Bank 5 @ A000"};
#pragma rodata-name("CODE6")
const unsigned char TEXT6[]={"Bank 6 @ C000"};
// put functions in bank 0
#pragma code-name("CODE1")
void draw_text(word addr, const char* text) {
vram_adr(addr);
vram_write(text, strlen(text));
}
// back to main code segment
#pragma code-name("CODE")
void main(void)
{
// set palette colors
pal_col(1,0x04);
pal_col(2,0x20);
pal_col(3,0x30);
// setup CHR bank switching for background
MMC3_CHR_0000(0);
MMC3_CHR_0800(1);
// select bank 0 in $8000-$9fff
MMC3_PRG_8000(0);
vram_adr(NTADR_A(2,2));
vram_write(TEXT0, 13);
// select bank 1 in $8000-$9fff
// also needed to call draw_text()
MMC3_PRG_8000(1);
draw_text(NTADR_A(2,3), TEXT1);
// select bank 5 in $a000-$bfff
MMC3_PRG_A000(5);
draw_text(NTADR_A(2,4), TEXT5);
// $c000-$dfff is fixed to bank 6
draw_text(NTADR_A(2,5), TEXT6);
//enable rendering
ppu_on_all();
while(1);//do nothing, infinite loop
}

View File

@ -47,3 +47,4 @@ void main(void)
show_title_screen(climbr_title_pal, climbr_title_rle);
while(1);//do nothing, infinite loop
}

View File

@ -33,6 +33,7 @@ const JSNES_PRESETS = [
{id:'scrollrt.asm', name:'Split Screen Scroll (ASM)'},
{id:'fami.c', name:'Famitone Demo'},
{id:'musicdemo.asm', name:'Famitone Demo (ASM)'},
{id:'bankswitch.c', name:'Bank Switching'},
];
const NES_NESLIB_PRESETS = [
@ -54,8 +55,8 @@ const NES_CONIO_PRESETS = [
/// JSNES
const JSNES_KEYCODE_MAP = makeKeycodeMap([
[Keys.VK_Z, 0, 0],
[Keys.VK_X, 0, 1],
[Keys.VK_X, 0, 0],
[Keys.VK_Z, 0, 1],
[Keys.VK_SPACE, 0, 2],
[Keys.VK_ENTER, 0, 3],
[Keys.VK_UP, 0, 4],

View File

@ -831,7 +831,7 @@ export class MemoryMapView implements ProjectView {
var curofs = 0;
for (var seg of segments) {
//var used = seg.last ? (seg.last-seg.start) : seg.size;
if (curofs != seg.start)
if (seg.start > curofs)
this.addSegment({name:'',start:curofs, size:seg.start-curofs});
this.addSegment(seg);
curofs = seg.start + seg.size;

View File

@ -0,0 +1,76 @@
SYMBOLS {
__STACKSIZE__: type = weak, value = $0300; # 3 pages stack
}
MEMORY {
ZP: file = "", start = $0002, size = $00FE, type = rw, define = yes;
# INES Cartridge Header
HEADER: file = %O, start = $0000, size = $0010, fill = yes;
# 5 16K ROM Banks @ $8000
PRG0: start = $8000, size = $2000, file = %O ,fill = yes, define = yes;
PRG1: start = $8000, size = $2000, file = %O ,fill = yes, define = yes;
PRG2: start = $8000, size = $2000, file = %O ,fill = yes, define = yes;
PRG3: start = $8000, size = $2000, file = %O ,fill = yes, define = yes;
PRG4: start = $8000, size = $2000, file = %O ,fill = yes, define = yes;
# fixed 16K ROM banks @ $a000 and $c000
PRG5: start = $a000, size = $2000, file = %O ,fill = yes, define = yes;
PRG6: start = $c000, size = $2000, file = %O ,fill = yes, define = yes;
# final bank has
# - startup
# - code
# - vectors
PRG7: file = %O, start = $E000, size = $1FFA, fill = yes, define = yes;
VECTORS: file = %O, start = $FFFA, size = $0006, fill = yes;
# 8 8k CHR Banks (64k)
CHR: file = %O, start = $0000, size = $10000, fill = yes;
# standard 2k SRAM (-zeropage)
# $0100-$0200 cpu stack
# $0200-$0500 3 pages for ppu memory write buffer
# $0500-$0800 3 pages for cc65 parameter stack
SRAM: file = "", start = $0500, size = __STACKSIZE__, define = yes;
# additional 8K SRAM Bank
# - data (run)
# - bss
# - heap
RAM: file = "", start = $6000, size = $2000, define = yes;
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp;
HEADER: load = HEADER, type = ro;
CODE0: load = PRG0, type = ro, define = yes, optional = yes;
CODE1: load = PRG1, type = ro, define = yes, optional = yes;
CODE2: load = PRG2, type = ro, define = yes, optional = yes;
CODE3: load = PRG3, type = ro, define = yes, optional = yes;
CODE4: load = PRG4, type = ro, define = yes, optional = yes;
CODE5: load = PRG5, type = ro, define = yes, optional = yes;
CODE6: load = PRG6, type = ro, define = yes, optional = yes;
RODATA: load = PRG6, type = ro, define = yes;
ONCE: load = PRG6, type = ro, optional = yes;
DATA: load = PRG6, run = RAM, type = rw, define = yes;
STARTUP: load = PRG6, type = ro, define = yes;
CODE: load = PRG7, type = ro, define = yes;
VECTORS: load = VECTORS, type = rw;
CHARS: load = CHR, type = rw;
BSS: load = SRAM, type = bss, define = yes;
}
FEATURES {
CONDES: type = constructor,
label = __CONSTRUCTOR_TABLE__,
count = __CONSTRUCTOR_COUNT__,
segment = ONCE;
CONDES: type = destructor,
label = __DESTRUCTOR_TABLE__,
count = __DESTRUCTOR_COUNT__,
segment = RODATA;
CONDES: type = interruptor,
label = __INTERRUPTOR_TABLE__,
count = __INTERRUPTOR_COUNT__,
segment = RODATA,
import = __CALLIRQ__;
}

View File

@ -168,12 +168,12 @@ var PLATFORM_PARAMS = {
define: '__NES__',
cfgfile: 'neslib.cfg',
libargs: ['crt0.o', 'nes.lib',
'-D', 'NES_MAPPER=0', // UxROM
'-D', 'NES_PRG_BANKS=2', // 2 PRG banks
'-D', 'NES_MAPPER=0', // NROM
'-D', 'NES_PRG_BANKS=2', // 2 16K PRG banks
'-D', 'NES_CHR_BANKS=1', // 1 CHR bank
'-D', 'NES_MIRRORING=0', // horizontal mirroring
],
extra_link_files: ['crt0.o'],
extra_link_files: ['crt0.o', 'nesbanked.cfg'],
extra_segments:[
//{name:'Work RAM',start:0x0,size:0x800,type:'ram'},
{name:'OAM Buffer',start:0x200,size:0x100,type:'ram'},
@ -492,7 +492,8 @@ function loadNative(modulename:string) {
// mount the filesystem at /share
function setupFS(FS, name:string) {
var WORKERFS = FS.filesystems['WORKERFS']
var WORKERFS = FS.filesystems['WORKERFS'];
if (!fsMeta[name]) throw "No filesystem for '" + name + "'";
FS.mkdir('/share');
FS.mount(WORKERFS, {
packages: [{ metadata: fsMeta[name], blob: fsBlob[name] }]
@ -901,16 +902,16 @@ function linkLD65(step:BuildStep) {
printErr:function(s) { errors.push({msg:s,line:0}); }
});
var FS = LD65['FS'];
var cfgfile = '/' + platform + '.cfg';
setupFS(FS, '65-'+getRootPlatform(platform));
populateFiles(step, FS);
populateExtraFiles(step, FS, params.extra_link_files);
var libargs = params.libargs;
var cfgfile = params.cfgfile;
var args = ['--cfg-path', '/share/cfg',
'--lib-path', '/share/lib',
'--lib-path', '/share/target/apple2/drv', // TODO
'-D', '__EXEHDR__=0', // TODO
'-C', params.cfgfile,
'-C', cfgfile,
'-Ln', 'main.vice',
//'--dbgfile', 'main.dbg',
'-o', 'main', '-m', 'main.map'].concat(step.args, libargs);
@ -944,7 +945,7 @@ function linkLD65(step:BuildStep) {
var seg_re = /^__(\w+)_SIZE__$/;
var segments = [].concat(params.extra_segments||[]);
segments.push({name:'CPU Stack',start:0x100,size:0x100,type:'ram'});
segments.push({name:'CPU Vectors',start:0xfffc,size:0x6,type:'rom'});
segments.push({name:'CPU Vectors',start:0xfffa,size:0x6,type:'rom'});
// TODO: CHR, banks, etc
for (let ident in symbolmap) {
let m = seg_re.exec(ident);
@ -953,9 +954,9 @@ function linkLD65(step:BuildStep) {
let segstart = symbolmap['__'+seg+'_RUN__'] || symbolmap['__'+seg+'_START__'];
let segsize = symbolmap['__'+seg+'_SIZE__'];
let seglast = symbolmap['__'+seg+'_LAST__'];
if (segstart >= 0 && segsize > 0 && seg != 'PRG' && seg != 'RAM') { // TODO
if (segstart >= 0 && segsize > 0 && !seg.startsWith('PRG') && seg != 'RAM') { // TODO
var type = null;
if (seg == 'CODE' || seg == 'STARTUP' || seg == 'RODATA') type = 'rom';
if (seg.startsWith('CODE') || seg == 'STARTUP' || seg == 'RODATA') type = 'rom';
else if (seg == 'ZP' || seg == 'RAM' || seg == 'DATA' || seg == 'BSS') type = 'ram';
segments.push({name:seg, start:segstart, size:segsize, last:seglast, type:type});
}
@ -986,7 +987,8 @@ function linkLD65(step:BuildStep) {
}
}
function fixParamsWithDefines(path:string, libargs:string[]){
function fixParamsWithDefines(path:string, params){
var libargs = params.libargs;
if (path && libargs) {
var code = getWorkFileAsString(path);
if (code) {
@ -999,7 +1001,7 @@ function fixParamsWithDefines(path:string, libargs:string[]){
}
}
// find #defines and replace them
var re = /^#define\s+(\w+)\s+(.+)/gmi;
var re = /^#define\s+(\w+)\s+(\S+)/gmi;
var m;
while (m = re.exec(code)) {
var ident = m[1];
@ -1007,7 +1009,12 @@ function fixParamsWithDefines(path:string, libargs:string[]){
var index = ident2index[ident];
if (index >= 0) {
libargs[index] = ident + "=" + value;
console.log(index, libargs[index]);
console.log('Using libargs', index, libargs[index]);
// TODO: MMC3 mapper switch
if (ident == 'NES_MAPPER' && value == '4') {
params.cfgfile = 'nesbanked.cfg';
console.log('Using config file', params.cfgfile);
}
}
}
}
@ -1044,7 +1051,7 @@ function compileCC65(step:BuildStep) {
var FS = CC65['FS'];
setupFS(FS, '65-'+getRootPlatform(step.platform));
populateFiles(step, FS);
fixParamsWithDefines(step.path, params.libargs);
fixParamsWithDefines(step.path, params);
execMain(step, CC65, ['-T', '-g',
'-Oirs',
'-Cl', // static locals

View File

@ -97,6 +97,7 @@ describe('Worker', function() {
compile('plasm', 'word x = ', 'apple2', done, 0, 0, 1);
});
*/
// TODO: test NES bank switching, mapper
it('should compile CC65', function(done) {
compile('cc65', 'int main() {\nint x=1;\nreturn x+2;\n}', 'nes-conio', done, 40976, 3);
});