fixed params when using vcs.mame; fixed tests; fixed nes start/select

This commit is contained in:
Steven Hugg 2019-02-25 16:04:15 -05:00
parent db60c8e380
commit 4e17913823
9 changed files with 174 additions and 373 deletions

122
presets/nes/bcd16.s Normal file
View File

@ -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

View File

@ -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 <screen_y>
// draw a nametable line into the frame buffer at <screen_y>
// 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; i<MAX_ACTORS; i++) {
Actor* b = &actors[i];
// actors must be on same floor and within 8 pixels
if (a->floor == 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') {

View File

@ -1,34 +0,0 @@
#include "neslib.h"
#include <string.h>
// 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) ;
}

View File

@ -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<BALLS_MAX;++i)
{
//starting coordinates
ball_x[i]=rand8();
ball_y[i]=rand8();
//direction bits
j=rand8();
//horizontal speed -3..-3, excluding 0
spr=1+(rand8()%3);
ball_dx[i]=j&1?-spr:spr;
//vertical speed
spr=1+(rand8()%3);
ball_dy[i]=j&2?-spr:spr;
}
//now the main loop
while(1)
{
ppu_wait_nmi();//wait for next TV frame
spr=0;
for(i=0;i<BALLS_MAX;++i)
{
//set a sprite for current ball
spr=oam_spr(ball_x[i],ball_y[i],0x40,i&3,spr);//0x40 is tile number, i&3 is palette
//move the ball
ball_x[i]+=ball_dx[i];
ball_y[i]+=ball_dy[i];
//bounce the ball off the edges
if(ball_x[i]>=(256-8)) ball_dx[i]=-ball_dx[i];
if(ball_y[i]>=(240-8)) ball_dy[i]=-ball_dy[i];
}
}
}

View File

@ -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 <string.h>
#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;
}
}

View File

@ -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++;
}
}

View File

@ -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
});
}

View File

@ -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);
// <stdin>: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;

View File

@ -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});