From 4e17913823c84f7cee8674d7852c73a7c16aeefe Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Mon, 25 Feb 2019 16:04:15 -0500 Subject: [PATCH] fixed params when using vcs.mame; fixed tests; fixed nes start/select --- presets/nes/bcd16.s | 122 +++++++++++++++++++++++++++++++++++++++ presets/nes/climber.c | 53 +++++++++-------- presets/nes/neslib1.c | 34 ----------- presets/nes/neslib2.c | 94 ------------------------------ presets/nes/neslib3.c | 93 ----------------------------- presets/nes/neslib4.c | 117 ------------------------------------- src/platform/nes.ts | 10 ++-- src/worker/workermain.ts | 22 +++++-- test/cli/testworker.js | 2 +- 9 files changed, 174 insertions(+), 373 deletions(-) create mode 100644 presets/nes/bcd16.s delete mode 100644 presets/nes/neslib1.c delete mode 100644 presets/nes/neslib2.c delete mode 100644 presets/nes/neslib3.c delete mode 100644 presets/nes/neslib4.c diff --git a/presets/nes/bcd16.s b/presets/nes/bcd16.s new file mode 100644 index 00000000..22630ad1 --- /dev/null +++ b/presets/nes/bcd16.s @@ -0,0 +1,122 @@ +; bcd16.s +; version 20060201 +; +; Copyright (C) 2006 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 in any source +; code copies. This file is offered as-is, without any warranty. +; + +.p02 + +.exportzp bcdNum, bcdResult +.export bcdConvert + +; bcdConvert +; +; Given a number in bcdNum (16-bit), converts it to 5 decimal digits +; in bcdResult. Unlike most 6502 binary-to-decimal converters, this +; subroutine doesn't use the decimal mode that was removed from the +; 2A03 variant of the 6502 processor. +; +; For each value of n from 4 to 1, it compares the number to 8*10^n, +; then 4*10^n, then 2*10^n, then 1*10^n, each time subtracting if +; possible. After finishing all the comparisons and subtractions in +; each decimal place value, it writes the digit to the output array +; as a byte value in the range [0, 9]. Finally, it writes the +; remainder to element 0. +; +; Extension to 24-bit and larger numbers is straightforward: +; Add a third bcdTable, increase BCD_BITS, and extend the +; trial subtraction. + +; Constants _________________________________________________________ +; BCD_BITS +; The highest possible number of bits in the BCD output. Should +; roughly equal 4 * log10(2) * x, where x is the width in bits +; of the largest binary number to be put in bcdNum. +; bcdTableLo[y], bcdTableHi[y] +; Contains (1 << y) converted from BCD to binary. +BCD_BITS = 19 + +; Variables _________________________________________________________ +; bcdNum (input) +; Number to be converted to decimal (16-bit little endian). +; Overwritten. +; bcdResult (output) +; Decimal digits of result (5-digit little endian). +; X +; Offset of current digit being worked on. +; Y +; Offset into bcdTable*. +; curDigit +; The lower holds the digit being constructed. +; The upper nibble contains a sentinel value; when a 1 is shifted +; out, the byte is complete and should be copied to result. +; (This behavior is called a "ring counter".) +; Overwritten. +; b +; Low byte of the result of trial subtraction. +; Overwritten. +bcdNum = 0 +bcdResult = 2 +curDigit = 7 +b = 2 + +; +; Completes within 670 cycles. +; + +bcdConvert: + lda #$80 >> ((BCD_BITS - 1) & 3) + sta curDigit + ldx #(BCD_BITS - 1) >> 2 + ldy #BCD_BITS - 5 + +@loop: + ; Trial subtract this bit to A:b + sec + lda bcdNum + sbc bcdTableLo,y + sta b + lda bcdNum+1 + sbc bcdTableHi,y + + ; If A:b > bcdNum then bcdNum = A:b + bcc @trial_lower + sta bcdNum+1 + lda b + sta bcdNum +@trial_lower: + + ; Copy bit from carry into digit and pick up + ; end-of-digit sentinel into carry + rol curDigit + dey + bcc @loop + + ; Copy digit into result + lda curDigit + sta bcdResult,x + lda #$10 ; Empty digit; sentinel at 4 bits + sta curDigit + ; If there are digits left, do those + dex + bne @loop + lda bcdNum + sta bcdResult + rts + +bcdTableLo: + .byt <10, <20, <40, <80 + .byt <100, <200, <400, <800 + .byt <1000, <2000, <4000, <8000 + .byt <10000, <20000, <40000 + +bcdTableHi: + .byt >10, >20, >40, >80 + .byt >100, >200, >400, >800 + .byt >1000, >2000, >4000, >8000 + .byt >10000, >20000, >40000 diff --git a/presets/nes/climber.c b/presets/nes/climber.c index 1429c3d5..b0eb80fd 100644 --- a/presets/nes/climber.c +++ b/presets/nes/climber.c @@ -28,6 +28,7 @@ extern char danger_streets_music_data[]; //#link "demosounds.s" extern char demo_sounds[]; +// indices of sound effects (0..3) typedef enum { SND_START, SND_HIT, SND_COIN, SND_JUMP } SFXIndex; ///// DEFINES @@ -156,13 +157,13 @@ const unsigned char* const playerRunSeq[16] = { // struct definition for a single floor typedef struct Floor { - byte ypos; - byte height; // TODO: why does bitmask not work? - int gap:4; - int ladder1:4; - int ladder2:4; - int objtype:4; - int objpos:4; + byte ypos; // # of tiles from ground + int height:4; // # of tiles to next floor + int gap:4; // X position of gap + int ladder1:4; // X position of first ladder + int ladder2:4; // X position of second ladder + int objtype:4; // item type (FloorItem) + int objpos:4; // X position of object } Floor; // various items the player can pick up @@ -222,9 +223,9 @@ void make_floors() { floors[MAX_FLOORS-1].objtype = 0; } -void create_actors_on_floor(byte i); +void create_actors_on_floor(byte floor_index); -// draw a nsmetable line into the frame buffer at +// draw a nametable line into the frame buffer at // 0 == bottom of stage void draw_floor_line(byte screen_y) { char buf[COLS]; @@ -364,17 +365,17 @@ typedef enum ActorType { }; typedef struct Actor { - word yy; - byte x; - byte name; // TODO - byte floor; - int state:4; - int dir:1; - int onscreen:1; + word yy; // Y position in pixels (16 bit) + byte x; // X position in pixels (8 bit) + byte floor; // floor index + byte state; // ActorState + int name:2; // ActorType + int dir:1; // direction (0=right, 1=left) + int onscreen:1; // is actor onscreen? union { - struct { - sbyte yvel; - sbyte xvel; + struct { // when jumping... + sbyte yvel; // Y velocity + sbyte xvel; // X velocity } jumping; } u; } Actor; @@ -388,7 +389,7 @@ void create_actors_on_floor(byte floor_index) { Floor *floor = &floors[floor_index]; a->state = STANDING; a->name = ACTOR_ENEMY; - a->x = floor->ladder1 ^ (floor->ladder2<<3) ^ (floor->gap<<6); + a->x = rand8(); a->yy = get_floor_yy(floor_index); a->floor = floor_index; a->onscreen = 1; @@ -633,12 +634,17 @@ byte iabs(int x) { bool check_collision(Actor* a) { byte i; - if (a->floor == 0) return false; + byte afloor = a->floor; + // can't fall through basement + if (afloor == 0) return false; + // can't fall if already falling if (a->state == FALLING) return false; + // iterate through entire list of actors for (i=1; ifloor == b->floor && + if (b->onscreen && + afloor == b->floor && iabs(a->yy - b->yy) < 8 && iabs(a->x - b->x) < 8) { return true; @@ -659,7 +665,8 @@ void type_message(const char* charptr) { char ch; byte x,y; x = 2; - y = ROWS*3 + 39 - scroll_tile_y; // TODO + // compute message y position relative to scroll + y = ROWS*3 + 39 - scroll_tile_y; while ((ch = *charptr++)) { while (y >= 60) y -= 60; if (ch == '\n') { diff --git a/presets/nes/neslib1.c b/presets/nes/neslib1.c deleted file mode 100644 index 8f6e14b8..00000000 --- a/presets/nes/neslib1.c +++ /dev/null @@ -1,34 +0,0 @@ - -#include "neslib.h" -#include - -// link the pattern table into CHR ROM -//#link "chr_generic.s" - -// function to write a string into the name table -// adr = start address in name table -// str = pointer to string -void put_str(unsigned int adr, const char *str) { - vram_adr(adr); // set PPU read/write address - vram_write(str, strlen(str)); // write bytes to PPU -} - -// main function, run after console reset -void main(void) { - // set palette colors - pal_col(1,0x04); - pal_col(2,0x20); - pal_col(3,0x30); - - // write text to name table - put_str(NTADR_A(2,2),"HELLO, WORLD!"); - put_str(NTADR_A(2,4),"THIS CODE PRINTS SOME TEXT"); - put_str(NTADR_A(2,5),"USING ASCII-ENCODED CHARACTER"); - put_str(NTADR_A(2,6),"SET WITH CAPITAL LETTERS ONLY"); - - // enable PPU rendering (turn on screen) - ppu_on_all(); - - // infinite loop - while (1) ; -} diff --git a/presets/nes/neslib2.c b/presets/nes/neslib2.c deleted file mode 100644 index f3beda90..00000000 --- a/presets/nes/neslib2.c +++ /dev/null @@ -1,94 +0,0 @@ - -//this example shows how to set up a palette and use 8x8 HW sprites -//also shows how fast (or slow) C code is - -#include "neslib.h" - -//#link "tileset1.c" - -// palette for balls, there are four sets for different ball colors -extern unsigned char palSprites[16]; - -// tile set, two planes for 4 colors -extern unsigned char TILESET[8*256]; - -//general purpose vars -static unsigned char i,j; -static unsigned char spr; - -//total number of balls on the screen -//since there are 64 HW sprites, it is absolute max - -#define BALLS_MAX 64 - -//balls parameters - -static unsigned char ball_x[BALLS_MAX]; -static unsigned char ball_y[BALLS_MAX]; -static unsigned char ball_dx[BALLS_MAX]; -static unsigned char ball_dy[BALLS_MAX]; - - - - - -void main(void) -{ - //copy tileset to RAM - vram_adr(0x0); - vram_write((unsigned char*)TILESET, sizeof(TILESET)); - - pal_spr(palSprites);//set palette for sprites - oam_size(1); - ppu_on_all();//enable rendering - - //initialize balls parameters - - for(i=0;i=(256-8)) ball_dx[i]=-ball_dx[i]; - if(ball_y[i]>=(240-8)) ball_dy[i]=-ball_dy[i]; - } - } -} diff --git a/presets/nes/neslib3.c b/presets/nes/neslib3.c deleted file mode 100644 index d621a5e3..00000000 --- a/presets/nes/neslib3.c +++ /dev/null @@ -1,93 +0,0 @@ - -//this example shows how to set up a palette and use 8x8 HW sprites -//also shows how fast (or slow) C code is - -#include - -#include "neslib.h" - -//#link "tileset1.c" - -// tile set, two planes for 4 colors -extern unsigned char TILESET[8*256]; - -//this example shows how to poll the gamepad -//and how to use nametable update system that allows to modify nametable -//while rendering is enabled - -//these macro are needed to simplify defining update list constants - -#define NTADR(x,y) ((0x2000|((y)<<5)|x)) - -#define MSB(x) (((x)>>8)) -#define LSB(x) (((x)&0xff)) - -//variables - -static unsigned char i; -static unsigned char x,y; - -//the update list, it is for 6 tiles, 3 bytes per tile - -static unsigned char list[6*3]; - -//init data for the update list, it contains MSB and LSB of a tile address -//in the nametable, then the tile number - -const unsigned char list_init[6*3+1]={ - MSB(NTADR(2,2)),LSB(NTADR(2,2)),0, - MSB(NTADR(3,2)),LSB(NTADR(3,2)),0, - MSB(NTADR(4,2)),LSB(NTADR(4,2)),0, - MSB(NTADR(6,2)),LSB(NTADR(6,2)),0, - MSB(NTADR(7,2)),LSB(NTADR(7,2)),0, - MSB(NTADR(8,2)),LSB(NTADR(8,2)),0, - NT_UPD_EOF -}; - -void main(void) -{ - //copy tileset to RAM - vram_adr(0x0); - vram_write((unsigned char*)TILESET, sizeof(TILESET)); - - pal_col(1,0x21);//blue color for text - pal_col(17,0x30);//white color for sprite - - memcpy(list,list_init,sizeof(list_init)); - set_vram_update(list); - - ppu_on_all();//enable rendering - - x=124; - y=116; - - //now the main loop - - while(1) - { - ppu_wait_nmi();//wait for next TV frame - - oam_spr(x,y,0x41,0,0);//put sprite - - //poll the pad and change coordinates according to pressed buttons - - i=pad_poll(0); - - if(i&PAD_LEFT &&x> 0) x-=2; - if(i&PAD_RIGHT&&x<248) x+=2; - if(i&PAD_UP &&y> 0) y-=2; - if(i&PAD_DOWN &&y<232) y+=2; - - //put x 3-digit number into the update list - - list[2]=0x10+x/100; - list[5]=0x10+x/10%10; - list[8]=0x10+x%10; - - //put y 3-digit number into the update list - - list[11]=0x10+y/100; - list[14]=0x10+y/10%10; - list[17]=0x10+y%10; - } -} diff --git a/presets/nes/neslib4.c b/presets/nes/neslib4.c deleted file mode 100644 index fc8e83fc..00000000 --- a/presets/nes/neslib4.c +++ /dev/null @@ -1,117 +0,0 @@ - -#include "neslib.h" - -//#link "tileset1.c" - -// tile set, two planes for 4 colors -extern unsigned char TILESET[8*256]; - -//variables - -static unsigned char i; -static unsigned char pad,spr; -static unsigned char touch; -static unsigned char frame; - -//two players coords - -static unsigned char cat_x[2]; -static unsigned char cat_y[2]; - - -//first player metasprite, data structure explained in neslib.h - -const unsigned char metaCat1[]={ - 0, 0, 0x50, 0, - 8, 0, 0x51, 1, - 16, 0, 0x52, 0, - 0, 8, 0x60, 0, - 8, 8, 0x61, 0, - 16, 8, 0x62, 0, - 0, 16, 0x70, 0, - 8, 16, 0x71, 0, - 16, 16, 0x72, 0, - 128 -}; - -//second player metasprite, the only difference is palette number - -const unsigned char metaCat2[]={ - 0, 0, 0x50, 0, - 8, 0, 0x51, 1, - 16, 0, 0x52, 0, - 0, 8, 0x60, 1, - 8, 8, 0x61, 1, - 16, 8, 0x62, 1, - 0, 16, 0x70, 1, - 8, 16, 0x71, 1, - 16, 16, 0x72, 1, - 128 -}; - - - -void main(void) -{ - //copy tileset to RAM - vram_adr(0x0); - vram_write((unsigned char*)TILESET, sizeof(TILESET)); - - ppu_on_all();//enable rendering - - //set initial coords - - cat_x[0]=52; - cat_y[0]=100; - cat_x[1]=180; - cat_y[1]=100; - - //init other vars - - touch=0;//collision flag - frame=0;//frame counter - - //now the main loop - - while(1) - { - ppu_wait_nmi();//wait for next TV frame - - //flashing color for touch - - i=frame&1?0x30:0x2a; - - pal_col(17,touch?i:0x21);//set first sprite color - pal_col(21,touch?i:0x26);//set second sprite color - - //process players - - spr=0; - - for(i=0;i<2;++i) - { - //display metasprite - - spr=oam_meta_spr(cat_x[i],cat_y[i],spr,!i?metaCat1:metaCat2); - - //poll pad and change coordinates - - pad=pad_poll(i); - - if(pad&PAD_LEFT &&cat_x[i]> 0) cat_x[i]-=2; - if(pad&PAD_RIGHT&&cat_x[i]<232) cat_x[i]+=2; - if(pad&PAD_UP &&cat_y[i]> 0) cat_y[i]-=2; - if(pad&PAD_DOWN &&cat_y[i]<212) cat_y[i]+=2; - } - - //check for collision for a smaller bounding box - //metasprite is 24x24, collision box is 20x20 - - if(!(cat_x[0]+22< cat_x[1]+2 || - cat_x[0]+ 2>=cat_x[1]+22|| - cat_y[0]+22< cat_y[1]+2 || - cat_y[0]+ 2>=cat_y[1]+22)) touch=1; else touch=0; - - frame++; - } -} diff --git a/src/platform/nes.ts b/src/platform/nes.ts index 521a76e8..2d8732ee 100644 --- a/src/platform/nes.ts +++ b/src/platform/nes.ts @@ -1,7 +1,7 @@ "use strict"; import { Platform, Base6502Platform, BaseMAMEPlatform, getOpcodeMetadata_6502, cpuStateToLongString_6502, getToolForFilename_6502, dumpStackToString } from "../baseplatform"; -import { PLATFORMS, RAM, newAddressDecoder, padBytes, noise, setKeyboardFromMap, AnimationTimer, RasterVideo, Keys, makeKeycodeMap, dumpRAM } from "../emu"; +import { PLATFORMS, RAM, newAddressDecoder, padBytes, noise, setKeyboardFromMap, AnimationTimer, RasterVideo, Keys, makeKeycodeMap, dumpRAM, KeyFlags } from "../emu"; import { hex, lpad, lzgmini } from "../util"; import { CodeAnalyzer_nes } from "../analysis"; import { SampleAudio } from "../audio"; @@ -54,8 +54,8 @@ const NES_CONIO_PRESETS = [ const JSNES_KEYCODE_MAP = makeKeycodeMap([ [Keys.VK_Z, 0, 0], [Keys.VK_X, 0, 1], - [Keys.VK_2, 0, 2], - [Keys.VK_1, 0, 3], + [Keys.VK_SPACE, 0, 2], + [Keys.VK_ENTER, 0, 3], [Keys.VK_UP, 0, 4], [Keys.VK_DOWN, 0, 5], [Keys.VK_LEFT, 0, 6], @@ -138,9 +138,9 @@ const _JSNESPlatform = function(mainElement) { timer = new AnimationTimer(60, this.nextFrame.bind(this)); // set keyboard map setKeyboardFromMap(video, [], JSNES_KEYCODE_MAP, function(o,key,code,flags) { - if (flags & 1) + if (flags & KeyFlags.KeyDown) nes.buttonDown(o.index+1, o.mask); // controller, button - else + else if (flags & KeyFlags.KeyUp) nes.buttonUp(o.index+1, o.mask); // controller, button }); } diff --git a/src/worker/workermain.ts b/src/worker/workermain.ts index d3755228..dab3e89d 100644 --- a/src/worker/workermain.ts +++ b/src/worker/workermain.ts @@ -37,6 +37,16 @@ function moduleInstFn(module_id:string) { } } +// get platform ID without . emulator +function getBasePlatform(platform : string) : string { + return platform.split('.')[0]; +} + +// get platform ID without - specialization +function getRootPlatform(platform : string) : string { + return platform.split('-')[0]; +} + var PLATFORM_PARAMS = { 'vcs': { code_start: 0x1000, @@ -856,7 +866,7 @@ function assembleCA65(step:BuildStep) { printErr:msvcErrorMatcher(errors), }); var FS = CA65['FS']; - setupFS(FS, '65-'+step.platform.split('-')[0]); + setupFS(FS, '65-'+getRootPlatform(step.platform)); populateFiles(step, FS); execMain(step, CA65, ['-v', '-g', '-I', '/share/asminc', '-o', objpath, '-l', lstpath, step.path]); if (errors.length) @@ -890,7 +900,7 @@ function linkLD65(step:BuildStep) { }); var FS = LD65['FS']; var cfgfile = '/' + platform + '.cfg'; - setupFS(FS, '65-'+platform.split('-')[0]); + setupFS(FS, '65-'+getRootPlatform(platform)); populateFiles(step, FS); populateExtraFiles(step, FS, params.extra_link_files); var libargs = params.libargs; @@ -1028,7 +1038,7 @@ function compileCC65(step:BuildStep) { printErr:match_fn, }); var FS = CC65['FS']; - setupFS(FS, '65-'+step.platform.split('-')[0]); + setupFS(FS, '65-'+getRootPlatform(step.platform)); populateFiles(step, FS); fixParamsWithDefines(step.path, params.libargs); execMain(step, CC65, ['-T', '-g', @@ -1326,7 +1336,7 @@ function makeCPPSafe(s:string) : string { function preprocessMCPP(step:BuildStep) { load("mcpp"); var platform = step.platform; - var params = PLATFORM_PARAMS[platform]; + var params = PLATFORM_PARAMS[getBasePlatform(platform)]; if (!params) throw Error("Platform not supported: " + platform); // :2: error: Can't open include file "foo.h" var errors = []; @@ -1839,7 +1849,7 @@ function executeBuildSteps() { var platform = step.platform; var toolfn = TOOLS[step.tool]; if (!toolfn) throw "no tool named " + step.tool; - step.params = PLATFORM_PARAMS[platform]; + step.params = PLATFORM_PARAMS[getBasePlatform(platform)]; console.log(step.platform + " " + step.tool); try { step.result = toolfn(step); @@ -1896,7 +1906,7 @@ function handleMessage(data : WorkerMessage) : WorkerResult { if (data.preload) { var fs = TOOL_PRELOADFS[data.preload]; if (!fs && data.platform) - fs = TOOL_PRELOADFS[data.preload+'-'+data.platform.split('-')[0]]; + fs = TOOL_PRELOADFS[data.preload+'-'+getRootPlatform(data.platform)]; if (fs && !fsMeta[fs]) loadFilesystem(fs); return; diff --git a/test/cli/testworker.js b/test/cli/testworker.js index af4335a2..cb7798cd 100644 --- a/test/cli/testworker.js +++ b/test/cli/testworker.js @@ -104,7 +104,7 @@ describe('Worker', function() { compile('cc65', 'int main() {\nint x=1;\nprintf("%d",x);\nreturn x+2;\n}', 'nes-conio', done, 0, 0, 1); }); it('should NOT compile CC65 (link error)', function(done) { - compile('cc65', 'extern void bad();\nint main() {\nbad();\nreturn 0;\n}', 'nes-conio', done, 0, 0, 1, {ignoreErrorPath:true}); + compile('cc65', 'extern void bad();\nint main() {\nbad();\nreturn 0;\n}', 'nes-conio', done, 0, 0, 3, {ignoreErrorPath:true}); }); it('should NOT compile CC65 (preproc error)', function(done) { compile('cc65', '#include "NOSUCH.file"\n', 'nes-conio', done, 0, 0, 1, {ignoreErrorPath:true});