add path to (some) error msgs; fixed code analysis bugs (?)

This commit is contained in:
Steven Hugg 2018-08-17 20:46:55 -04:00
parent 662f8a057d
commit a9bd845800
8 changed files with 518 additions and 53 deletions

427
presets/nes/road.asm Normal file
View File

@ -0,0 +1,427 @@

include "nesdefs.asm"
;;;;; ZERO-PAGE VARIABLES
seg.u ZEROPAGE
org $0
TrackFrac .byte ; fractional position along track
Speed .byte ; speed of car
TimeOfDay .word ; 16-bit time of day counter
; Variables for preprocessing step
XPos .word ; 16-bit X position
XVel .word ; 16-bit X velocity
TPos .word ; 16-bit track position
TrackLookahead .byte ; current fractional track increment
; Variables for track generation
Random .byte ; random counter
GenTarget .byte ; target of current curve
GenDelta .byte ; curve increment
GenCur .byte ; current curve value
ZOfs .byte ; counter to draw striped center line
Weather .byte ; bitmask for weather
Heading .word ; sky scroll pos.
XCenter = 128
NumRoadSegments = 28
; Preprocessing result: X positions for all track segments
RoadX0 ds NumRoadSegments
; Generated track curve data
TrackLen equ 5
TrackData ds TrackLen
InitialSpeed equ 10 ; starting speed
;;;;; OTHER VARIABLES
seg.u RAM
org $300
;;;;; NES CARTRIDGE HEADER
NES_HEADER 0,2,1,0 ; mapper 0, 2 PRGs, 1 CHR, horiz. mirror
;;;;; START OF CODE
Start:
NES_INIT ; set up stack pointer, turn off PPU
jsr WaitSync ; wait for VSYNC
jsr ClearRAM ; clear RAM
jsr WaitSync ; wait for VSYNC (and PPU warmup)
jsr SetPalette ; set palette colors
jsr FillVRAM ; set PPU video RAM
jsr RoadSetup
lda #0
sta PPU_ADDR
sta PPU_ADDR ; PPU addr = $0000
sta PPU_SCROLL
sta PPU_SCROLL ; scroll = $0000
lda #CTRL_NMI
sta PPU_CTRL ; enable NMI
lda #MASK_BG|MASK_SPR
sta PPU_MASK ; enable rendering
.endless
jmp .endless ; endless loop
;;;;; ROAD SUBS
RoadSetup: subroutine
lda #1
sta Random
lda #InitialSpeed
sta Speed
lda #0
sta TimeOfDay+1
lda #0
sta Weather
rts
RoadPreSetup: subroutine
; Set up some values for road curve computation,
; since we have some scanline left over.
lda #0
sta XVel
sta XVel+1
sta XPos
sta XPos+1
lda TrackFrac
sta TPos
lda #0
sta TPos+1
lda #10 ; initial lookahead
sta TrackLookahead
rts
RoadPostFrame: subroutine
; Advance position on track
; TrackFrac += Speed
lda TrackFrac
clc
adc Speed
sta TrackFrac
bcc .NoGenTrack ; addition overflowed?
jsr GenTrack ; yes, generate new track segment
.NoGenTrack
; TimeOfDay += 1
inc TimeOfDay
bne .NoTODInc
inc TimeOfDay+1
lda TimeOfDay+1
; See if it's nighttime yet, and if the stars come out
clc
adc #8
and #$3f
cmp #$35
ror
sta Weather
.NoTODInc
lda Heading
sec
sbc XPos+1
sta Heading
bit XPos+1
bmi .NegHeading
lda Heading+1
sbc #0
sta Heading+1
rts
.NegHeading
lda Heading+1
sbc #$ff
sta Heading+1
rts
; Compute road curve from bottom of screen to horizon.
PreprocessCurve subroutine
ldx #NumRoadSegments-1
.CurveLoop
; Modify X position
; XPos += XVel (16 bit add)
lda XPos
clc
adc XVel
sta XPos
lda XPos+1
adc XVel+1
sta XPos+1
sta RoadX0,x ; store in RoadX0 array
; Modify X velocity (slope)
; XVel += TrackData[TPos]
ldy TPos+1
lda TrackData,y
clc ; clear carry for ADC
bmi .CurveLeft ; track slope negative?
adc XVel
sta XVel
lda XVel+1
adc #0 ; carry +1
jmp .NoCurveLeft
.CurveLeft
adc XVel
sta XVel
lda XVel+1
sbc #0 ; carry -1
nop ; make the branch timings are the same
.NoCurveLeft
sta XVel+1
; Advance TPos (TrackData index)
; TPos += TrackLookahead
lda TPos
clc
adc TrackLookahead
sta TPos
lda TPos+1
adc #0
sta TPos+1
; Go to next segment
inc TrackLookahead ; see further along track
dex
bpl .CurveLoop
rts
; Generate next track byte
GenTrack subroutine
; Shift the existing track data one byte up
; (a[i] = a[i+1])
ldx #0
.ShiftTrackLoop
lda TrackData+1,x
sta TrackData,x
inx
cpx #TrackLen-1
bne .ShiftTrackLoop
; Modify our current track value and
; see if it intersects the target value
lda GenCur
clc
adc GenDelta
cmp GenTarget
beq .ChangeTarget ; target == cur?
bit GenTarget ; we need the sign flag
bmi .TargetNeg ; target<0?
bcs .ChangeTarget ; target>=0 && cur>=target?
bcc .NoChangeTarget ; branch always taken
.TargetNeg
bcs .NoChangeTarget ; target<0 && cur<target?
; Generate a new target value and increment value,
; and make sure the increment value is positive if
; the target is above the current value, and negative
; otherwise
.ChangeTarget
lda Random
jsr NextRandom ; get a random value
sta Random
and #$3f ; range 0..63
sec
sbc #$1f ; range -31..32
sta GenTarget ; -> target
cmp GenCur
bmi .TargetBelow ; current > target?
lda Random
jsr NextRandom ; get a random value
sta Random
and #$f ; mask to 0..15
jmp .TargetAbove
.TargetBelow
lda Random
jsr NextRandom
sta Random
ora #$f0 ; mask to -16..0
.TargetAbove
ora #1 ; to avoid 0 values
sta GenDelta ; -> delta
lda GenCur
.NoChangeTarget
; Store the value in GenCur, and also
; at the end of the TrackData array
sta GenCur
sta TrackData+TrackLen-1
rts
; fill video RAM
FillVRAM: subroutine
txa
ldy #$20
sty PPU_ADDR
sta PPU_ADDR
ldy #$10
.loop:
sta PPU_DATA
adc #7
inx
bne .loop
dey
bne .loop
rts
; set palette colors
SetPalette: subroutine
ldy #$00
lda #$3f
sta PPU_ADDR
sty PPU_ADDR
ldx #32
.loop:
lda Palette,y
sta PPU_DATA
iny
dex
bne .loop
rts
; set sprite 0
SetSprite0: subroutine
sta $200 ;y
lda #1 ;code
sta $201
lda #0 ;flags
sta $202
lda #8 ;xpos
sta $203
rts
;;;;; COMMON SUBROUTINES
include "nesppu.asm"
;;;;; INTERRUPT HANDLERS
MAC SLEEP ;usage: SLEEP n (n>1)
.CYCLES SET {1}
IF .CYCLES < 2
ECHO "MACRO ERROR: 'SLEEP': Duration must be > 1"
ERR
ENDIF
IF .CYCLES & 1
bit $00
.CYCLES SET .CYCLES - 3
ENDIF
REPEAT .CYCLES / 2
nop
REPEND
ENDM
NMIHandler: subroutine
SAVE_REGS
; setup sky scroll
lda Heading+1
sta PPU_SCROLL
lda #0
sta PPU_SCROLL
; load sprites
lda #112
jsr SetSprite0
lda #$02
sta PPU_OAM_DMA
; do road calc
jsr RoadPreSetup
jsr PreprocessCurve
jsr RoadPostFrame
; wait for sprite 0
.wait0 bit PPU_STATUS
bvs .wait0
.wait1 bit PPU_STATUS
bvc .wait1
; alter horiz. scroll position for each scanline
ldy #0
.loop
tya
lsr
lsr
tax
lda RoadX0,x
sta PPU_SCROLL ; horiz byte
lda #0
sta PPU_SCROLL ; vert byte
SLEEP 84
iny
cpy #112
bne .loop
RESTORE_REGS
rti
;;;;; CONSTANT DATA
align $100
Palette:
hex 1f ;background
hex 09092c00 ;bg0
hex 09091900 ;bg1
hex 09091500 ;bg2
hex 09092500 ;bg3
;;;;; CPU VECTORS
NES_VECTORS
;;;;; TILE SETS
org $10000
; background (tile) pattern table
REPEAT 10
;;{w:8,h:8,bpp:1,count:48,brev:1,np:2,pofs:8,remap:[0,1,2,4,5,6,7,8,9,10,11,12]};;
hex 00000000000000000000000000000000
hex 7e42424646467e007e42424646467e00
hex 08080818181818000808081818181800
hex 3e22023e30303e003e22023e30303e00
hex 3c24041e06263e003c24041e06263e00
hex 4444447e0c0c0c004444447e0c0c0c00
hex 3c20203e06263e003c20203e06263e00
hex 3e22203e26263e003e22203e26263e00
hex 3e020206060606003e02020606060600
hex 3c24247e46467e003c24247e46467e00
hex 3e22223e060606003e22223e06060600
hex 3c24247e626262003c24247e62626200
hex 7c44447e62627e007c44447e62627e00
hex 7e42406060627e007e42406060627e00
hex 7e42426262627e007e42426262627e00
hex 7c40407c60607c007c40407c60607c00
hex 3c20203c303030003c20203c30303000
hex 7e42406e62627e007e42406e62627e00
hex 4242427e626262004242427e62626200
hex 10101018181818001010101818181800
hex 0404040606467e000404040606467e00
hex 4444447e626262004444447e62626200
hex 2020203030303e002020203030303e00
hex fe9292d2d2d2d200fe9292d2d2d2d200
hex 7e424262626262007e42426262626200
hex 7e46464242427e007e46464242427e00
hex 7e42427e606060007e42427e60606000
hex 7e424242424e7e007e424242424e7e00
hex 7c44447e626262007c44447e62626200
hex 7e42407e06467e007e42407e06467e00
hex 7e101018181818007e10101818181800
hex 4242426262627e004242426262627e00
hex 646464642c2c3c00646464642c2c3c00
hex 4949494969697f004949494969697f00
hex 4242423c626262004242423c62626200
hex 4242427e181818004242427e18181800
hex 7e42027e60627e007e42027e60427e00
hex 10101818180018001010181818001800
hex 187e407e067e1800187e407e067e1800
hex 00180018180000000018001818000000
hex 00003c3c0000000000003c3c00000000
hex 00000018180000000000001818000000
hex 18180810000000001818081000000000
hex 00000018180810000000001818081000
hex 7c7c7c7c7c7c7c007c7c7c7c7c7c7c00
hex 0000000000007c000000000000007c00
hex 00000000000000000000000000000000
hex 00000000000000000000000000000000
;;
REPEND
REPEAT 32
hex 00000000000000000000000000000000
REPEND

View File

@ -45,6 +45,7 @@ abstract class CodeAnalyzer6502 implements CodeAnalyzer {
WRAP_CLOCKS : boolean;
jsrresult = {};
platform : Platform;
MAX_CYCLES : number = 2000;
constructor(platform : Platform) {
this.platform = platform;
@ -57,28 +58,45 @@ abstract class CodeAnalyzer6502 implements CodeAnalyzer {
}
traceInstructions(pc:number, minclocks:number, maxclocks:number, subaddr:number, constraints) {
if (this.WRAP_CLOCKS) {
if (this.pc2minclocks[pc] !== undefined)
minclocks = Math.min(minclocks, this.pc2minclocks[pc]);
if (this.pc2maxclocks[pc] !== undefined)
maxclocks = Math.max(maxclocks, this.pc2maxclocks[pc]);
}
//console.log("trace", hex(pc), minclocks, maxclocks);
if (!minclocks) minclocks = 0;
if (!maxclocks) maxclocks = 0;
if (!constraints) constraints = {};
var modified = true;
var abort = false;
for (var i=0; i<1000 && modified && !abort; i++) {
for (var i=0; modified && !abort; i++) {
if (i >= this.MAX_CYCLES) {
console.log("too many cycles @", hex(pc), "routine", hex(subaddr));
break;
}
modified = false;
if (this.WRAP_CLOCKS && minclocks >= this.MAX_CLOCKS) {
// wrap clocks
minclocks = minclocks % this.MAX_CLOCKS;
maxclocks = maxclocks % this.MAX_CLOCKS;
} else {
// truncate clocks
minclocks = Math.min(this.MAX_CLOCKS, minclocks);
maxclocks = Math.min(this.MAX_CLOCKS, maxclocks);
}
var meta = this.getClockCountsAtPC(pc);
var lob = this.platform.readAddress(pc+1);
var hib = this.platform.readAddress(pc+2);
var addr = lob + (hib << 8);
var pc0 = pc;
if (!this.pc2minclocks[pc0] || minclocks < this.pc2minclocks[pc0]) {
if (!(minclocks >= this.pc2minclocks[pc0])) {
this.pc2minclocks[pc0] = minclocks;
modified = true;
}
if (!this.pc2maxclocks[pc0] || maxclocks > this.pc2maxclocks[pc0]) {
if (!(maxclocks <= this.pc2maxclocks[pc0])) {
this.pc2maxclocks[pc0] = maxclocks;
modified = true;
}
//console.log(hex(pc),minclocks,maxclocks,meta);
//console.log(hex(pc),minclocks,maxclocks,modified,meta,constraints);
if (!meta.insnlength) {
console.log("Illegal instruction!", hex(pc), hex(meta.opcode), meta);
break;
@ -94,13 +112,21 @@ abstract class CodeAnalyzer6502 implements CodeAnalyzer {
meta.maxCycles -= 1;
break;
*/
// TODO: don't do in NES
// TODO: only VCS
case 0x85:
if (lob == 0x2) { // STA WSYNC
minclocks = maxclocks = 0;
meta.minCycles = meta.maxCycles = 0;
}
break;
// TODO: only NES (sprite 0 poll)
case 0x2c:
if (lob == 0x02 && hib == 0x20) { // BIT $2002
minclocks = 0;
maxclocks = 4; // uncertainty b/c of assumed branch poll
meta.minCycles = meta.maxCycles = 0;
}
break;
case 0x20: // JSR
this.traceInstructions(addr, minclocks, maxclocks, addr, constraints);
var result = this.jsrresult[addr];
@ -115,6 +141,9 @@ abstract class CodeAnalyzer6502 implements CodeAnalyzer {
case 0x4c: // JMP
pc = addr; // TODO: make sure in ROM space
break;
case 0x40: // RTI
abort = true;
break;
case 0x60: // RTS
if (subaddr) { // TODO: 0 doesn't work
// TODO: combine with previous result
@ -142,11 +171,13 @@ abstract class CodeAnalyzer6502 implements CodeAnalyzer {
var cons = BRANCH_CONSTRAINTS[Math.floor((meta.opcode-0x10)/0x20)];
var cons0 = constraintEquals(oldconstraints, cons[0]);
var cons1 = constraintEquals(oldconstraints, cons[1]);
if (cons0 !== false) {
// recursively trace the taken branch
if (true || cons0 !== false) { // TODO?
this.traceInstructions(newpc, minclocks+meta.maxCycles, maxclocks+meta.maxCycles, subaddr, cons[0]);
}
// abort if we will always take the branch
if (cons1 === false) {
console.log("abort", hex(pc), oldconstraints, cons[1]);
console.log("branch always taken", hex(pc), oldconstraints, cons[1]);
abort = true;
}
constraints = cons[1]; // not taken
@ -156,12 +187,9 @@ abstract class CodeAnalyzer6502 implements CodeAnalyzer {
console.log("Instruction not supported!", hex(pc), hex(meta.opcode), meta); // TODO
return;
}
minclocks = Math.min(this.MAX_CLOCKS, minclocks + meta.minCycles);
maxclocks = Math.min(this.MAX_CLOCKS, maxclocks + meta.maxCycles);
if (this.WRAP_CLOCKS && maxclocks >= this.MAX_CLOCKS) {
minclocks = minclocks % this.MAX_CLOCKS;
maxclocks = maxclocks % this.MAX_CLOCKS;
}
// add min/max instruction time to min/max clocks bound
minclocks += meta.minCycles;
maxclocks += meta.maxCycles;
}
}
@ -178,7 +206,7 @@ abstract class CodeAnalyzer6502 implements CodeAnalyzer {
export class CodeAnalyzer_vcs extends CodeAnalyzer6502 {
constructor(platform : Platform) {
super(platform);
this.MAX_CLOCKS = this.START_CLOCKS = 76*2;
this.MAX_CLOCKS = this.START_CLOCKS = 76*2; // 2 scanlines
this.WRAP_CLOCKS = false;
}
}
@ -188,7 +216,7 @@ export class CodeAnalyzer_vcs extends CodeAnalyzer6502 {
export class CodeAnalyzer_nes extends CodeAnalyzer6502 {
constructor(platform : Platform) {
super(platform);
this.MAX_CLOCKS = 114; // ~341/3
this.MAX_CLOCKS = 114; // 341 clocks for 3 scanlines
this.START_CLOCKS = 0;
this.WRAP_CLOCKS = true;
}

View File

@ -306,11 +306,6 @@ var SampleAudio = function(clockfreq) {
self.filterNode=self.context.createBiquadFilter();
self.filterNode.frequency.value=6000;
// "LED filter" at 3275kHz - off by default
self.lowpassNode=self.context.createBiquadFilter();
self.lowpassNode.frequency.value=28867;
self.filter=false;
// mixer
if ( typeof self.context.createScriptProcessor === 'function') {
self.mixerNode=self.context.createScriptProcessor(self.bufferlen, 1, 1);
@ -326,8 +321,7 @@ var SampleAudio = function(clockfreq) {
// patch up some cables :)
self.mixerNode.connect(self.filterNode);
self.filterNode.connect(self.lowpassNode);
self.lowpassNode.connect(self.compressorNode);
self.filterNode.connect(self.compressorNode);
self.compressorNode.connect(self.context.destination);
}

View File

@ -287,6 +287,7 @@ var OPMETA_6502 = {
export function getOpcodeMetadata_6502(opcode, address) {
// TODO: more intelligent maximum cycles
// TODO: must always be new object, b/c we might modify it
return {
opcode:opcode,
minCycles:OPMETA_6502.cycletime[opcode],

View File

@ -11,17 +11,17 @@ var JSNES_PRESETS = [
{id:'ex0.asm', name:'Initialization (ASM)'},
{id:'ex1.asm', name:'Scrolling Demo (ASM)'},
{id:'ex2.asm', name:'Sprite Demo (ASM)'},
// {id:'hello.c', name:'C: Hello PPU'},
// {id:'conio.c', name:'C: Hello Console I/O'},
{id:'neslib1.c', name:'Text'},
{id:'neslib2.c', name:'Sprites'},
{id:'neslib3.c', name:'Cursor'},
{id:'neslib4.c', name:'Metasprites'},
{id:'neslib5.c', name:'RLE Unpack'},
{id:'music.c', name:'Music Player'},
{id:'musicdemo.asm', name:'Famitone Demo'},
{id:'siegegame.c', name:'Siege Game'},
{id:'shoot2.c', name:'Solarian Game'},
{id:'scrollrt.asm', name:'Split Screen Scroll (ASM)'},
{id:'road.asm', name:'3-D Road (ASM)'},
{id:'musicdemo.asm', name:'Famitone Demo (ASM)'},
];
var NES_NESLIB_PRESETS = [

View File

@ -216,7 +216,7 @@ export class SourceEditor implements ProjectView {
setTimingResult(result:CodeAnalyzer) : void {
this.editor.clearGutter("gutter-bytes");
// show the lines
for (const line in Object.keys(this.sourcefile.line2offset)) {
for (const line of Object.keys(this.sourcefile.line2offset)) {
var pc = this.sourcefile.line2offset[line];
var minclocks = result.pc2minclocks[pc];
var maxclocks = result.pc2maxclocks[pc];

View File

@ -399,7 +399,7 @@ var print_fn = function(s) {
// test.c(6) : warning 85: in function main unreferenced local variable : 'x'
// main.a (4): error: Unknown Mnemonic 'xxx'.
// at 2: warning 190: ISO C forbids an empty source file
var re_msvc = /([^(]+)\s*[(](\d+)[)]\s*:\s*(.+?):\s*(.*)/;
var re_msvc = /[/]*([^( ]+)\s*[(](\d+)[)]\s*:\s*(.+?):\s*(.*)/;
var re_msvc2 = /\s*(at)\s+(\d+)\s*(:)\s*(.*)/;
function msvcErrorMatcher(errors) {
@ -409,7 +409,7 @@ function msvcErrorMatcher(errors) {
var errline = parseInt(matches[2]);
errors.push({
line:errline,
//path:matches[1],
path:matches[1],
type:matches[3],
msg:matches[4]
});
@ -419,13 +419,14 @@ function msvcErrorMatcher(errors) {
}
}
function makeErrorMatcher(errors, regex, iline, imsg) {
function makeErrorMatcher(errors, regex, iline, imsg, path) {
return function(s) {
var matches = regex.exec(s);
if (matches) {
errors.push({
line:parseInt(matches[iline]) || 1,
msg:matches[imsg]
msg:matches[imsg],
path:path
});
} else {
console.log("??? "+s);
@ -433,9 +434,9 @@ function makeErrorMatcher(errors, regex, iline, imsg) {
}
}
function extractErrors(regex, strings) {
function extractErrors(regex, strings, path) {
var errors = [];
var matcher = makeErrorMatcher(errors, regex, 1, 2);
var matcher = makeErrorMatcher(errors, regex, 1, 2, path);
for (var i=0; i<strings.length; i++) {
matcher(strings[i]);
}
@ -539,6 +540,7 @@ function parseDASMListing(code, unresolved, mainFilename) {
var errm = re_msvc.exec(line);
if (errm) {
errors.push({
path:errm[1],
line:parseInt(errm[2]),
msg:errm[4]
})
@ -876,9 +878,10 @@ function assembleSDASZ80(step) {
function match_asm_fn(s) {
var matches = match_asm_re.exec(s);
if (matches) {
var errline = parseInt(matches[2]);
//var errline = parseInt(matches[2]);
errors.push({
line:1, // TODO: errline,
line:1, // TODO
path:step.path,
msg:matches[1]
});
}
@ -1062,7 +1065,7 @@ function preprocessMCPP(step) {
if (!params) throw Error("Platform not supported: " + platform);
// <stdin>:2: error: Can't open include file "foo.h"
var errors = [];
var match_fn = makeErrorMatcher(errors, /<stdin>:(\d+): (.+)/, 1, 2);
var match_fn = makeErrorMatcher(errors, /<stdin>:(\d+): (.+)/, 1, 2, step.path);
var MCPP = mcpp({
noInitialRun:true,
noFSInit:true,
@ -1092,7 +1095,7 @@ function preprocessMCPP(step) {
var errout = FS.readFile("mcpp.err", {encoding:'utf8'});
if (errout.length) {
// //main.c:2: error: Can't open include file "stdiosd.h"
var errors = extractErrors(/[^:]+:(\d+): (.+)/, errout.split("\n"));
var errors = extractErrors(/[^:]+:(\d+): (.+)/, errout.split("\n"), step.path);
if (errors.length == 0) {
errors = [{line:0, msg:errout}];
}

View File

@ -15,29 +15,36 @@ global.onmessage({data:{preload:'sdcc'}});
// TODO: check msg against spec
function compile(tool, code, platform, callback, outlen, nlines, nerrors) {
function compile(tool, code, platform, callback, outlen, nlines, nerrors, options) {
var msgs = [{code:code, platform:platform, tool:tool, path:'src.'+tool}];
doBuild(msgs, callback, outlen, nlines, nerrors);
doBuild(msgs, callback, outlen, nlines, nerrors, options);
}
function compileFiles(tool, files, platform, callback, outlen, nlines, nerrors) {
function compileFiles(tool, files, platform, callback, outlen, nlines, nerrors, options) {
var msg = {updates:[], buildsteps:[]};
for (var fn of files) {
var text = ab2str(fs.readFileSync('presets/'+platform+'/'+fn));
msg.updates.push({path:fn, data:text});
msg.buildsteps.push({path:fn, platform:platform, tool:tool});
}
doBuild([msg], callback, outlen, nlines, nerrors);
doBuild([msg], callback, outlen, nlines, nerrors, options);
}
function doBuild(msgs, callback, outlen, nlines, nerrors) {
function doBuild(msgs, callback, outlen, nlines, nerrors, options) {
var msgcount = msgs.length;
global.postMessage = function(msg) {
if (!msg.unchanged) {
if (msg.errors && msg.errors.length) {
console.log(msg.errors);
for (var err of msg.errors) {
console.log(err);
assert.ok(err.line >= 0);
if (options && !options.ignoreErrorPath) {
assert.equal(msgs[0].path, err.path);
}
assert.ok(err.msg);
}
assert.equal(nerrors, msg.errors.length, "errors");
} else {
assert.equal(nerrors||0, 0, "errors");
@ -97,7 +104,10 @@ 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);
compile('cc65', 'extern void bad();\nint main() {\nbad();\nreturn 0;\n}', 'nes-conio', done, 0, 0, 1, {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});
});
it('should assemble CA65', function(done) {
compile('ca65', '\t.segment "HEADER"\n\t.segment "STARTUP"\n\t.segment "CHARS"\n\t.segment "VECTORS"\n\tlda #0\n\tsta $1\n', 'nes-conio', done, 40976, 2);
@ -116,8 +126,8 @@ describe('Worker', function() {
it('should NOT assemble SDASZ80', function(done) {
compile('sdasz80', '\txxx hl,#0\n\tret\n', 'mw8080bw', done, 0, 0, 1);
});
it('should NOT assemble SDASZ80', function(done) {
compile('sdasz80', '\tcall divxxx\n', 'mw8080bw', done, 0, 0, 1);
it('should NOT link SDASZ80', function(done) {
compile('sdasz80', '\tcall divxxx\n', 'mw8080bw', done, 0, 0, 1, {ignoreErrorPath:true});
});
it('should compile SDCC', function(done) {
compile('sdcc', 'int foo=0; // comment\nint main(int argc) {\nint x=1;\nint y=2+argc;\nreturn x+y+argc;\n}\n', 'mw8080bw', done, 8192, 3, 0);
@ -167,6 +177,11 @@ describe('Worker', function() {
};
doBuild(msgs, done2, 2799, 0, 0);
});
it('should NOT compile verilog example', function(done) {
var csource = "foobar";
var msgs = [{code:csource, platform:"verilog", tool:"verilator", dependencies:[], path:'foomain.v'}];
doBuild(msgs, done, 0, 0, 1);
});
it('should compile verilog inline assembler (JSASM)', function(done) {
var csource = ab2str(fs.readFileSync('presets/verilog/racing_game_cpu.v'));
var dependfiles = ["hvsync_generator.v", "sprite_bitmap.v", "sprite_renderer.v", "cpu8.v"];
@ -280,14 +295,11 @@ describe('Worker', function() {
"buildsteps":[
{"path":"main.c", "platform":"mw8080bw", "tool":"sdcc"},
{"path":"fn.c", "platform":"mw8080bw", "tool":"sdcc"}
]
],
"path":"fn.c"
};
var msgs = [m];
doBuild(msgs, function(err, result) {
for (var msg of result.errors)
assert.equal(msg.path, "fn.c");
done();
}, 8192, [1,1], 2); // TODO: check error file
doBuild(msgs, done, 8192, [1,1], 2); // TODO: check error file
});
it('should compile vicdual skeleton', function(done) {
var files = ['skeleton.sdcc', 'cp437.c'];