1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2026-04-21 21:16:51 +00:00

moved TS test files from src/test to test/unit

This commit is contained in:
Steven Hugg
2026-03-03 12:36:05 +01:00
parent fda7ae78a1
commit d634d4db70
10 changed files with 30 additions and 20 deletions
+116
View File
@@ -0,0 +1,116 @@
import { describe } from "mocha";
import { OpcodeMetadata, Platform } from "../../src/common/baseplatform";
import { CodeAnalyzer_vcs } from "../../src/common/analysis";
import { MOS6502 } from "../../src/common/cpu/MOS6502";
import assert from "assert";
class Test6502Platform implements Platform {
cpu = new MOS6502();
ram = new Uint8Array(65536);
start(): void | Promise<void> {
throw new Error("Method not implemented.");
}
reset(): void {
throw new Error("Method not implemented.");
}
isRunning(): boolean {
throw new Error("Method not implemented.");
}
getToolForFilename(s: string): string {
throw new Error("Method not implemented.");
}
getDefaultExtension(): string {
throw new Error("Method not implemented.");
}
pause(): void {
throw new Error("Method not implemented.");
}
resume(): void {
throw new Error("Method not implemented.");
}
loadROM(title: string, rom: any) {
throw new Error("Method not implemented.");
}
getOpcodeMetadata?(opcode: number, offset: number): OpcodeMetadata {
return this.cpu.cpu.getOpcodeMetadata(opcode, offset);
}
getOriginPC(): number {
return 0;
}
readAddress?(addr:number) : number {
return this.ram[addr] || 0;
}
}
describe('6502 analysis', function () {
it('Should analyze WSYNC', function () {
let platform = new Test6502Platform();
platform.ram.set([0xea,0x85,0x02,0xa9,0x60,0x20,0x04,0x00,0xea,0x4c,0x01,0x00]);
let analysis = new CodeAnalyzer_vcs(platform);
analysis.showLoopTimingForPC(0x0);
console.log(analysis.pc2clockrange);
assert.equal(analysis.pc2clockrange[0x0].minclocks, 0);
assert.equal(analysis.pc2clockrange[0x0].maxclocks, 0);
assert.equal(analysis.pc2clockrange[0x1].minclocks, 2);
assert.equal(analysis.pc2clockrange[0x1].maxclocks, 19);
assert.equal(analysis.pc2clockrange[0x3].minclocks, 0);
assert.equal(analysis.pc2clockrange[0x3].maxclocks, 0);
});
it('Should analyze loop', function () {
let platform = new Test6502Platform();
platform.ram.set([0xea,0x4c,0x00,0x00]); // 5 cycles
let analysis = new CodeAnalyzer_vcs(platform);
analysis.showLoopTimingForPC(0x0);
console.log(analysis.pc2clockrange);
assert.equal(analysis.pc2clockrange[0x0].minclocks, 0);
assert.equal(analysis.pc2clockrange[0x0].maxclocks, 75);
// TODO: should be 0-75
/*
assert.equal(analysis.pc2clockrange[0x1].minclocks, 1);
assert.equal(analysis.pc2clockrange[0x1].maxclocks, 72);
*/
});
it('Should wrap clocks', function () {
let platform = new Test6502Platform();
platform.ram.set([0xb1,0,0xb1,0,0xb1,0,0xb1,0,0xb1,0,0xb1,0,0xb1,0,0xb1,0,0xb1,0,0xb1,0,0xb1,0,0xb1,0,0xb1,0,0xb1,0,0xea,0x4c,0,0]);
let analysis = new CodeAnalyzer_vcs(platform);
analysis.showLoopTimingForPC(0x0);
console.log(analysis.pc2clockrange);
// TODO: should be 0-75
assert.equal(analysis.pc2clockrange[0x0].minclocks, 0);
assert.equal(analysis.pc2clockrange[0x0].maxclocks, 75);
assert.equal(analysis.pc2clockrange[0x2].minclocks, 5);
assert.equal(analysis.pc2clockrange[0x2].maxclocks, 6);
});
it('Should wrap RTS', function () {
let platform = new Test6502Platform();
platform.ram.set([0xb1,0x60,0x20,1,0,0x4c,0,0]);
let analysis = new CodeAnalyzer_vcs(platform);
analysis.showLoopTimingForPC(0x0);
console.log(analysis.pc2clockrange);
// TODO: should be 0-75
assert.equal(analysis.pc2clockrange[0x0].minclocks, 0);
assert.equal(analysis.pc2clockrange[0x0].maxclocks, 75);
});
it('Should not recurse', function () {
let platform = new Test6502Platform();
platform.ram.set([0xea,0x20,0x07,0x00,0x4c,0x00,0x00, 0xa4,0x88,0xea,0xd0,0xfb,0x60]);
let analysis = new CodeAnalyzer_vcs(platform);
analysis.showLoopTimingForPC(0x0);
console.log(analysis.pc2clockrange);
// TODO: should be 0-75
assert.equal(analysis.pc2clockrange[0x0].minclocks, 0);
assert.equal(analysis.pc2clockrange[0x0].maxclocks, 75);
});
it('Should not break', function () {
let platform = new Test6502Platform();
platform.ram.set([0x85,0x02,0x85,0x2a,0xa9,0x00,0x85,0x26,0x85,0x1b,0x85,0x1c,0x4c,0x00,0x00]);
let analysis = new CodeAnalyzer_vcs(platform);
analysis.showLoopTimingForPC(0x0);
console.log(analysis.pc2clockrange);
// TODO: should be 0-75
assert.equal(analysis.pc2clockrange[0x0].minclocks, 0);
assert.equal(analysis.pc2clockrange[0x0].maxclocks, 17);
});
});
+596
View File
@@ -0,0 +1,596 @@
import { describe, it } from "mocha";
import assert from "assert";
import { Assembler } from "../../src/worker/assembler";
describe('Assembler', function () {
describe('Basic Assembly', function () {
it('Should assemble simple 8-bit instructions', function () {
const spec = {
name: 'test8',
width: 8,
vars: {
reg: { bits: 3, toks: ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7'] },
imm8: { bits: 8 }
},
rules: [
{ fmt: 'nop', bits: ['00000000'] },
{ fmt: 'mov ~reg,~reg', bits: ['10', 0, 1] },
{ fmt: 'add ~reg,~imm8', bits: ['00001', 0, 1] }
]
};
const asm = new Assembler(spec);
asm.assemble('.org 0');
asm.assemble('.len 256');
asm.assemble('nop');
asm.assemble('mov r1,r2');
asm.assemble('add r3,$42');
const state = asm.finish();
assert.equal(state.errors.length, 0, 'Should have no errors');
assert.equal(state.output[0], 0x00, 'NOP should be 0x00');
assert.equal(state.output[1], 0b10001010, 'MOV r1,r2');
assert.equal(state.output[2], 0b00001011, 'ADD r3,imm first byte');
assert.equal(state.output[3], 0x42, 'ADD r3,imm second bytes');
});
it('Should handle labels', function () {
const spec = {
name: 'test8',
width: 8,
vars: {
imm8: { bits: 8 }
},
rules: [
{ fmt: 'jmp ~imm8', bits: ['11110000', 0] }
]
};
const asm = new Assembler(spec);
asm.assemble('.org 0');
asm.assemble('.len 256');
asm.assemble('jmp target');
asm.assemble('nop: jmp nop');
asm.assemble('target: jmp target');
const state = asm.finish();
assert.equal(state.errors.length, 0, 'Should have no errors');
assert.equal(state.output[0], 0xf0, 'JMP opcode');
assert.equal(state.output[1], 4, 'Should jump to address 4');
assert.equal(state.output[2], 0xf0, 'JMP opcode');
assert.equal(state.output[3], 2, 'Should jump to itself (address 2)');
assert.equal(state.output[4], 0xf0, 'JMP opcode');
assert.equal(state.output[5], 4, 'Should jump to itself (address 4)');
});
});
describe('PC-Relative Addressing', function () {
it('Should handle simple PC-relative branches', function () {
const spec = {
name: 'test8',
width: 8,
vars: {
rel8: { bits: 8, iprel: true, ipofs: 0, ipmul: 1 }
},
rules: [
{ fmt: 'br ~rel8', bits: ['10000000', 0] }
]
};
const asm = new Assembler(spec);
asm.assemble('.org 0');
asm.assemble('.len 256');
asm.assemble('br forward'); // offset 0
asm.assemble('br forward'); // offset 2
asm.assemble('br forward'); // offset 4
asm.assemble('forward: br forward'); // offset 6
const state = asm.finish();
assert.equal(state.errors.length, 0, 'Should have no errors');
assert.equal(state.output[1], 6, 'First branch offset should be 6');
assert.equal(state.output[3], 4, 'Second branch offset should be 4');
assert.equal(state.output[5], 2, 'Third branch offset should be 2');
assert.equal(state.output[7], 0, 'Fourth branch offset should be 0 (self)');
});
it('Should handle PC-relative with instruction multiplier', function () {
// Simulate word-addressed architecture where PC increments by 4
const spec = {
name: 'test32',
width: 32,
vars: {
rel13: { bits: 13, iprel: true, ipofs: 0, ipmul: 4 }
},
rules: [
{ fmt: 'beq ~rel13', bits: ['1100011000000000000', 0] }
]
};
const asm = new Assembler(spec);
asm.assemble('.org 0');
asm.assemble('.len 256');
asm.assemble('beq target'); // offset 0
asm.assemble('beq target'); // offset 4
asm.assemble('target: beq target'); // offset 8
const state = asm.finish();
assert.equal(state.errors.length, 0, 'Should have no errors');
// PC-relative offset = (target - current) * ipmul
// First: (8 - 0) * 1 = 8
// Second: (8 - 4) * 1 = 4
// Third: (8 - 8) * 1 = 0
const first = state.output[0];
const second = state.output[1];
const third = state.output[2];
// Extract the 13-bit immediate from the instruction
// It's in the lower 13 bits
const offset1 = first & 0x1fff;
const offset2 = second & 0x1fff;
const offset3 = third & 0x1fff;
assert.equal(offset1, 8, 'First branch offset should be 8');
assert.equal(offset2, 4, 'Second branch offset should be 4');
assert.equal(offset3, 0, 'Third branch offset should be 0');
});
});
describe('Bit Slicing', function () {
it('Should extract bit slices correctly', function () {
// RISC-V style branch with scrambled immediate
const spec = {
name: 'riscv',
width: 32,
vars: {
reg: { bits: 5, toks: ['x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7'] },
rel13: { bits: 13, iprel: true, ipofs: 0, ipmul: 1 }
},
rules: [
// beq rs1, rs2, offset
// Format: imm[12] | imm[10:5] | rs2 | rs1 | 000 | imm[4:1] | imm[11] | 1100011
{
fmt: 'beq ~reg,~reg,~rel13',
bits: [
{ a: 2, b: 12, n: 1 }, // imm[12]
{ a: 2, b: 5, n: 6 }, // imm[10:5]
1, // rs2
0, // rs1
'000', // funct3
{ a: 2, b: 1, n: 4 }, // imm[4:1]
{ a: 2, b: 11, n: 1 }, // imm[11]
'1100011' // opcode
]
}
]
};
const asm = new Assembler(spec);
asm.assemble('.org 0');
asm.assemble('.len 256');
asm.assemble('target: beq x1,x2,target'); // Self-branch with offset 0
const state = asm.finish();
assert.equal(state.errors.length, 0, 'Should have no errors');
const insn = state.output[0];
// Decode the instruction to verify bit positions
const opcode = insn & 0x7f;
const imm_11 = (insn >> 7) & 1;
const imm_4_1 = (insn >> 8) & 0xf;
const funct3 = (insn >> 12) & 0x7;
const rs1 = (insn >> 15) & 0x1f;
const rs2 = (insn >> 20) & 0x1f;
const imm_10_5 = (insn >> 25) & 0x3f;
const imm_12 = (insn >> 31) & 1;
assert.equal(opcode, 0x63, 'Opcode should be 0x63 (branch)');
assert.equal(funct3, 0, 'funct3 should be 0 (BEQ)');
assert.equal(rs1, 1, 'rs1 should be 1 (x1)');
assert.equal(rs2, 2, 'rs2 should be 2 (x2)');
// All immediate bits should be 0 for self-branch
assert.equal(imm_12, 0, 'imm[12] should be 0');
assert.equal(imm_11, 0, 'imm[11] should be 0');
assert.equal(imm_10_5, 0, 'imm[10:5] should be 0');
assert.equal(imm_4_1, 0, 'imm[4:1] should be 0');
});
it('Should handle non-zero bit slice offsets', function () {
const spec = {
name: 'riscv',
width: 32,
vars: {
brop: { bits: 3, toks: ["beq","bne","bx2","bx3","blt","bge","bltu","bgeu"] },
reg: { bits: 5, toks: ['x0', 'x1', 'x2'] },
rel13: { bits: 13, iprel: true, ipofs: 0, ipmul: 4 }
},
rules: [
{
fmt: '~brop ~reg,~reg,~rel13',
bits: [
{ a: 3, b: 12, n: 1 },
{ a: 3, b: 5, n: 6 },
2,
1,
'000',
{ a: 3, b: 1, n: 4 },
{ a: 3, b: 11, n: 1 },
'1100011'
]
}
]
};
const asm = new Assembler(spec);
asm.assemble('.org 4096');
asm.assemble('.len 1024');
asm.assemble('beq x1,x2,target'); // offset 0
asm.assemble('beq x1,x2,target'); // offset 4
asm.assemble('beq x1,x2,target'); // offset 8
asm.assemble('target: beq x1,x2,target'); // offset 12 (self)
asm.assemble('beq x1,x2,target'); // offset 16
asm.assemble('beq x1,x2,target'); // offset 20
/*
00208663
00208463
00208263
00208063
fe208ee3
fe208ce3
*/
const state = asm.finish();
assert.equal(state.errors.length, 0, 'Should have no errors');
assert.equal(state.output[0], 0x208663, 'insn 0');
assert.equal(state.output[1], 0x208463, 'insn 1');
assert.equal(state.output[2], 0x208263, 'insn 2');
assert.equal(state.output[3], 0x208063, 'insn 3');
assert.equal(state.output[4], 0xfe208ee3|0, 'insn 4');
assert.equal(state.output[5], 0xfe208ce3|0, 'insn 5');
// Check that offset 12 was correctly calculated and sliced
const insn0 = state.output[0];
// Reconstruct the immediate from the instruction
const imm_11 = (insn0 >> 7) & 1;
const imm_4_1 = (insn0 >> 8) & 0xf;
const imm_10_5 = (insn0 >> 25) & 0x3f;
const imm_12 = (insn0 >> 31) & 1;
//console.log('insn0: $', insn0.toString(16), 'imm_12:', imm_12, 'imm_11:', imm_11, 'imm_10_5:', imm_10_5, 'imm_4_1:', imm_4_1);
// Reconstruct the 13-bit signed offset (bit 0 is implicit 0)
const offset = (imm_12 << 12) | (imm_11 << 11) | (imm_10_5 << 5) | (imm_4_1 << 1);
assert.equal(offset, 12, 'Offset should be 12 bytes');
});
});
describe('Endianness', function () {
it('Should handle little-endian values', function () {
const spec = {
name: 'test8',
width: 8,
vars: {
imm16: { bits: 16, endian: 'little' as const }
},
rules: [
{ fmt: 'ldi ~imm16', bits: ['10000000', 0] }
]
};
const asm = new Assembler(spec);
asm.assemble('.org 0');
asm.assemble('.len 256');
asm.assemble('ldi $1234');
const state = asm.finish();
assert.equal(state.errors.length, 0, 'Should have no errors');
assert.equal(state.output[0], 0x80, 'Opcode');
assert.equal(state.output[1], 0x34, 'Low byte first (little-endian)');
assert.equal(state.output[2], 0x12, 'High byte second');
});
it('Should handle big-endian values', function () {
const spec = {
name: 'test8',
width: 8,
vars: {
imm16: { bits: 16, endian: 'big' as const }
},
rules: [
{ fmt: 'ldi ~imm16', bits: ['10000000', 0] }
]
};
const asm = new Assembler(spec);
asm.assemble('.org 0');
asm.assemble('.len 256');
asm.assemble('ldi $1234');
const state = asm.finish();
assert.equal(state.errors.length, 0, 'Should have no errors');
assert.equal(state.output[0], 0x80, 'Opcode');
assert.equal(state.output[1], 0x12, 'High byte first (big-endian)');
assert.equal(state.output[2], 0x34, 'Low byte second');
});
});
describe('Directives', function () {
it('Should handle .org directive', function () {
const spec = {
name: 'test8',
width: 8,
vars: {},
rules: [
{ fmt: 'nop', bits: ['00000000'] }
]
};
const asm = new Assembler(spec);
asm.assemble('.org 100');
asm.assemble('.len 256');
asm.assemble('nop');
const state = asm.finish();
assert.equal(state.origin, 100, 'Origin should be 100');
assert.equal(state.ip, 101, 'IP should be at 101');
assert.equal(state.output[0], 0x00, 'NOP at origin');
});
it('Should handle .data directive', function () {
const spec = {
name: 'test8',
width: 8,
vars: {},
rules: []
};
const asm = new Assembler(spec);
asm.assemble('.org 0');
asm.assemble('.len 256');
asm.assemble('.data 10 20 $30');
const state = asm.finish();
assert.equal(state.output[0], 10);
assert.equal(state.output[1], 20);
assert.equal(state.output[2], 0x30);
});
it('Should handle .string directive', function () {
const spec = {
name: 'test8',
width: 8,
vars: {},
rules: []
};
const asm = new Assembler(spec);
asm.assemble('.org 0');
asm.assemble('.len 256');
asm.assemble('.string HELLO');
const state = asm.finish();
assert.equal(state.output[0], 'H'.charCodeAt(0));
assert.equal(state.output[1], 'E'.charCodeAt(0));
assert.equal(state.output[2], 'L'.charCodeAt(0));
assert.equal(state.output[3], 'L'.charCodeAt(0));
assert.equal(state.output[4], 'O'.charCodeAt(0));
});
it('Should handle .align directive', function () {
const spec = {
name: 'test8',
width: 8,
vars: {},
rules: [
{ fmt: 'nop', bits: ['00000000'] }
]
};
const asm = new Assembler(spec);
asm.assemble('.org 0');
asm.assemble('.len 256');
asm.assemble('nop'); // offset 0
asm.assemble('nop'); // offset 1
asm.assemble('.align 4'); // align to 4
asm.assemble('nop'); // offset 4
const state = asm.finish();
assert.equal(state.lines[2].offset, 4, 'Should align to offset 4');
});
});
describe('Error Handling', function () {
it('Should detect undefined labels', function () {
const spec = {
name: 'test8',
width: 8,
vars: {
imm8: { bits: 8 }
},
rules: [
{ fmt: 'jmp ~imm8', bits: ['11110000', 0] }
]
};
const asm = new Assembler(spec);
asm.assemble('.org 0');
asm.assemble('.len 256');
asm.assemble('jmp undefined_label');
const state = asm.finish();
assert.equal(state.errors.length, 1, 'Should have one error');
assert(state.errors[0].msg.includes('undefined_label'), 'Error should mention undefined_label');
});
it('Should detect value overflow', function () {
const spec = {
name: 'test8',
width: 8,
vars: {
imm4: { bits: 4 }
},
rules: [
{ fmt: 'mov ~imm4', bits: ['1111', 0] }
]
};
const asm = new Assembler(spec);
asm.assemble('.org 0');
asm.assemble('.len 256');
asm.assemble('mov 20'); // 20 > 15 (max 4-bit value)
const state = asm.finish();
assert.equal(state.errors.length, 1, 'Should have one error');
assert(state.errors[0].msg.includes('does not fit'), 'Error should mention overflow');
});
it('Should detect invalid instructions', function () {
const spec = {
name: 'test8',
width: 8,
vars: {},
rules: [
{ fmt: 'nop', bits: ['00000000'] }
]
};
const asm = new Assembler(spec);
asm.assemble('.org 0');
asm.assemble('.len 256');
asm.assemble('invalid_instruction');
const state = asm.finish();
assert.equal(state.errors.length, 1, 'Should have one error');
assert(state.errors[0].msg.includes('Could not decode'), 'Error should mention decode failure');
});
});
describe('32-bit Width', function () {
it('Should handle 32-bit instructions', function () {
const spec = {
name: 'test32',
width: 32,
vars: {
reg: { bits: 5, toks: ['r0', 'r1', 'r2', 'r3', 'r4'] },
imm12: { bits: 12 }
},
rules: [
// RISC-V ADDI format: imm[11:0] | rs1 | 000 | rd | 0010011
{
fmt: 'addi ~reg,~reg,~imm12',
bits: [2, 1, '000', 0, '0010011']
}
]
};
const asm = new Assembler(spec);
asm.assemble('.org 0');
asm.assemble('.len 256');
asm.assemble('addi r1,r2,$123');
const state = asm.finish();
assert.equal(state.errors.length, 0, 'Should have no errors');
const insn = state.output[0];
const opcode = insn & 0x7f;
const rd = (insn >> 7) & 0x1f;
const funct3 = (insn >> 12) & 0x7;
const rs1 = (insn >> 15) & 0x1f;
const imm = (insn >> 20) & 0xfff;
assert.equal(opcode, 0x13, 'Opcode should be 0x13 (OP-IMM)');
assert.equal(rd, 1, 'rd should be 1');
assert.equal(rs1, 2, 'rs1 should be 2');
assert.equal(funct3, 0, 'funct3 should be 0 (ADDI)');
assert.equal(imm, 0x123, 'Immediate should be 0x123');
});
});
describe('Symbol Definition', function () {
it('Should allow symbol definition with .define', function () {
const spec = {
name: 'test8',
width: 8,
vars: {
imm8: { bits: 8 }
},
rules: [
{ fmt: 'ldi ~imm8', bits: ['10000000', 0] }
]
};
const asm = new Assembler(spec);
asm.assemble('.org 0');
asm.assemble('.len 256');
asm.assemble('.define MYCONST 42');
asm.assemble('ldi MYCONST');
const state = asm.finish();
assert.equal(state.errors.length, 0, 'Should have no errors');
assert.equal(state.output[1], 42, 'Should use defined constant');
});
});
describe('Complex Fixups', function () {
it('Should handle multiple fixups to same location', function () {
const spec = {
name: 'test8',
width: 8,
vars: {
imm8: { bits: 8 }
},
rules: [
{ fmt: 'jmp ~imm8', bits: ['11110000', 0] }
]
};
const asm = new Assembler(spec);
asm.assemble('.org 0');
asm.assemble('.len 256');
asm.assemble('jmp target');
asm.assemble('jmp target');
asm.assemble('target: jmp target');
const state = asm.finish();
assert.equal(state.errors.length, 0, 'Should have no errors');
assert.equal(state.output[1], 4, 'First jump to target');
assert.equal(state.output[3], 4, 'Second jump to target');
assert.equal(state.output[5], 4, 'Third jump to itself');
});
it('Should handle backward references', function () {
const spec = {
name: 'test8',
width: 8,
vars: {
rel8: { bits: 8, iprel: true, ipofs: 0, ipmul: 1 }
},
rules: [
{ fmt: 'br ~rel8', bits: ['10000000', 0] }
]
};
const asm = new Assembler(spec);
asm.assemble('.org 0');
asm.assemble('.len 256');
asm.assemble('start: br forward'); // offset 0
asm.assemble('br start'); // offset 2 (backward)
asm.assemble('forward: br start'); // offset 4 (backward)
const state = asm.finish();
assert.equal(state.errors.length, 0, 'Should have no errors');
assert.equal(state.output[1], 4, 'Forward branch');
// Backward branches: offset = target - current
// For offset 2: target=0, current=2, offset=-2 (0xfe in 8-bit signed)
assert.equal(state.output[3] & 0xff, 0xfe, 'Backward branch from offset 2');
// For offset 4: target=0, current=4, offset=-4 (0xfc in 8-bit signed)
assert.equal(state.output[5] & 0xff, 0xfc, 'Backward branch from offset 4');
});
});
});
+190
View File
@@ -0,0 +1,190 @@
import { spawnSync } from "child_process";
import { existsSync, readdirSync, readFileSync, writeFileSync } from "fs";
import { describe } from "mocha";
import { Bin, BoxConstraints, Packer } from "../../src/common/ecs/binpack";
import { ECSCompiler } from "../../src/common/ecs/compiler";
import { Dialect_CA65, EntityManager, SourceFileExport } from "../../src/common/ecs/ecs";
function testCompiler() {
let em = new EntityManager(new Dialect_CA65()); // TODO
let c = new ECSCompiler(em, true);
try {
c.parseFile(`
// comment
/*
mju,fjeqowfjqewiofjqe
*/
component Kernel
lines: 0..255
bgcolor: 0..255
end
component Bitmap
data: array of 0..255
end
component HasBitmap
bitmap: [Bitmap]
end
system SimpleKernel
locals 8
on preframe do with [Kernel] --- JUNK_AT_END
lda #5
sta #6
Label:
---
end
comment ---
---
scope Root
entity kernel [Kernel]
const lines = 0xc0
//const lines = $c0
end
entity nobmp [Bitmap]
const data = [4]
end
entity bmp [Bitmap]
const data = [1,2,3]
end
entity player1 [HasBitmap]
init bitmap = #bmp
end
end
`, 'foo.txt');
//console.log('json', c.em.toJSON());
let src = new SourceFileExport();
c.exportToFile(src);
// TODO: test?
console.log(src.toString());
return em;
} catch (e) {
console.log(e);
for (let err of c.errors) {
console.log(err);
}
console.log(c.tokens);
throw e;
}
}
// TODO: files in markdown?
// TODO: jsr OperModeExecutionTree?
describe('Tokenizer', function() {
it('Should use Compiler', function() {
testCompiler();
});
});
describe('Compiler', function() {
let testdir = './test/ecs/';
let files = readdirSync(testdir).filter(f => f.endsWith('.ecs'));
files.forEach((ecsfn) => {
it('Should compile ' + ecsfn, function() {
let asmfn = ecsfn.replace('.ecs','.asm');
let goodfn = ecsfn.replace('.ecs','.txt');
let ecspath = testdir + ecsfn;
let goodpath = testdir + goodfn;
let dialect = new Dialect_CA65();
let em = new EntityManager(dialect);
em.mainPath = ecspath;
let compiler = new ECSCompiler(em, true);
compiler.getImportFile = (path: string) => {
return readFileSync(testdir + path, 'utf-8');
}
let code = readFileSync(ecspath, 'utf-8');
var outtxt = '';
try {
compiler.parseFile(code, ecspath);
// TODO: errors
let out = new SourceFileExport();
em.exportToFile(out);
outtxt = out.toString();
} catch (e) {
outtxt = e.toString();
console.log(e);
}
if (compiler.errors.length)
outtxt = compiler.errors.map(e => `${e.line}:${e.msg}`).join('\n');
let goodtxt = existsSync(goodpath) ? readFileSync(goodpath, 'utf-8') : '';
if (outtxt.trim() != goodtxt.trim()) {
let asmpath = '/tmp/' + asmfn;
writeFileSync(asmpath, outtxt, 'utf-8');
console.log(spawnSync('/usr/bin/diff', [goodpath, asmpath], {encoding:'utf-8'}).stdout);
throw new Error(`files different; to fix: cp ${asmpath} ${goodpath}`);
}
});
});
});
function testPack(bins: Bin[], boxes: BoxConstraints[]) {
let packer = new Packer();
for (let bin of bins) packer.bins.push(bin);
for (let bc of boxes) packer.boxes.push(bc);
if (!packer.pack()) throw new Error('cannot pack')
//console.log(packer.boxes);
//console.log(packer.bins[0].free)
}
describe('Box Packer', function() {
it('Should pack boxes', function() {
testPack(
[
new Bin({ left:0, top:0, right:10, bottom:10 })
], [
{ width: 5, height: 5 },
{ width: 5, height: 5 },
{ width: 5, height: 5 },
{ width: 5, height: 5 },
]
);
});
it('Should pack top-aligned boxes', function() {
testPack(
[
new Bin({ left:0, top:0, right:10, bottom:10 })
], [
{ width: 5, height: 7, top: 0 },
{ width: 5, height: 7, top: 1 },
{ width: 5, height: 1 },
{ width: 5, height: 1 },
{ width: 5, height: 3 },
{ width: 5, height: 1 },
]
);
});
it('Should pack unaligned boxes', function() {
testPack(
[
new Bin({ left:0, top:0, right:10, bottom:10 })
], [
{ width: 3, height: 7, top: 0 },
{ width: 3, height: 7, top: 1 },
{ width: 3, height: 7, top: 2 },
{ width: 5, height: 1 },
{ width: 3, height: 1 },
]
);
});
it('Should pack multiple bins', function() {
testPack(
[
new Bin({ left:0, top:0, right:10, bottom:10 }),
new Bin({ left:0, top:0, right:10, bottom:10 })
], [
{ width: 5, height: 10 },
{ width: 5, height: 10 },
{ width: 5, height: 5 },
{ width: 5, height: 10 },
{ width: 5, height: 5 },
]
);
});
});
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2024 Steven E. Hugg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import assert from "assert";
import { DWARFParser, ELFParser } from "../../src/common/binutils";
describe('test ELFParser', () => {
const fs = require('fs');
const data = fs.readFileSync('./test/exes/arm32.elf');
const elfParser = new ELFParser(new Uint8Array(data));
it('should parse sections and symbols', () => {
/*
elfParser.sectionHeaders.forEach((section, index) => {
console.log('section', index, section.name, section.type, section.vaddr.toString(16), section.size.toString(16));
});
elfParser.getSymbols().forEach((symbol, index) => {
console.log('symbol', index, symbol.info, symbol.other, symbol.name, symbol.value.toString(16));
});
*/
assert.strictEqual(21, elfParser.sectionHeaders.length);
assert.strictEqual(29, elfParser.getSymbols().length);
assert.ok(elfParser.sectionHeaders.find((section) => section.name === '.text') != null);
assert.ok(elfParser.getSymbols().find((symbol) => symbol.name === 'main') != null);
});
it('should parse DWARF info', () => {
const dwarf = new DWARFParser(elfParser);
assert.strictEqual(2, dwarf.units.length);
const cu = dwarf.units[0];
// TODO: check info content
const li = dwarf.lineInfos[0];
assert.strictEqual('crt0.c', li.files[1].name);
/*
assert.ok(info != null);
assert.ok(info!.lineNumberProgram != null);
assert.ok(info!.lineNumberProgram!.length > 0);
assert.ok(info!.lineNumberProgram![0].file != null);
assert.ok(info!.lineNumberProgram![0].file!.name != null);
assert.ok(info!.lineNumberProgram![0].file!.name!.length > 0);
*/
});
});
+24
View File
@@ -0,0 +1,24 @@
import assert from "assert";
import * as fs from "fs";
import { LibRetroRunner } from "../../src/common/wasi/libretro";
async function loadLibretro() {
const wasmdata = fs.readFileSync(`./wasi/stella2014_libretro_2.wasm`);
let shim = new LibRetroRunner();
await shim.loadAsync(wasmdata);
return shim;
}
/*
describe('test WASI libretro', function () {
it('libretro init', async function () {
let shim = await loadLibretro();
assert.strictEqual(1, shim.retro_api_version());
shim.retro_init();
let romdata = fs.readFileSync(`./test/roms/vcs/brickgame.rom`);
shim.load_rom('brickgame.rom', romdata);
shim.reset();
shim.advance();
});
});
*/
+201
View File
@@ -0,0 +1,201 @@
import assert from "assert";
import { describe } from "mocha";
import { EmuHalt } from "../../src/common/emu"
import { lzgmini, isProbablyBinary, hex } from "../../src/common/util";
import { Tokenizer, TokenType } from "../../src/common/tokenizer";
import { OPS_6502 } from "../../src/common/cpu/disasm6502";
import { MOS6502 } from "../../src/common/cpu/MOS6502";
var NES_CONIO_ROM_LZG = [
76, 90, 71, 0, 0, 160, 16, 0, 0, 11, 158, 107, 131, 223, 83, 1, 9, 17, 21, 22, 78, 69, 83, 26, 2, 1, 3, 0, 22, 6, 120, 216,
162, 0, 134, 112, 134, 114, 134, 113, 134, 115, 154, 169, 32, 157, 0, 2, 157, 0, 3, 157, 0, 4, 232, 208, 244, 32, 134, 130, 32, 85, 129, 169,
0, 162, 8, 133, 2, 134, 3, 32, 93, 128, 32, 50, 129, 32, 73, 129, 76, 0, 128, 72, 152, 72, 138, 72, 169, 1, 133, 112, 230, 107, 208, 2,
230, 108, 32, 232, 129, 169, 32, 141, 6, 32, 169, 0, 22, 129, 141, 5, 22, 66, 104, 170, 104, 168, 104, 64, 160, 0, 240, 7, 169, 105, 162, 128,
76, 4, 96, 96, 162, 0, 21, 23, 0, 32, 22, 195, 1, 22, 194, 63, 21, 37, 21, 134, 22, 197, 41, 21, 27, 173, 41, 96, 201, 4, 32, 169,
129, 240, 3, 76, 158, 128, 76, 188, 128, 169, 184, 162, 130, 24, 109, 41, 96, 144, 1, 232, 160, 0, 32, 130, 129, 141, 7, 21, 36, 238, 41, 96,
21, 32, 76, 140, 128, 21, 47, 33, 21, 246, 201, 17, 14, 61, 15, 21, 253, 227, 128, 76, 1, 129, 169, 169, 17, 24, 61, 209, 21, 125, 17, 2,
180, 17, 10, 130, 5, 22, 201, 128, 17, 4, 172, 30, 141, 1, 32, 76, 46, 129, 22, 65, 96, 173, 0, 96, 174, 1, 96, 32, 112, 130, 173, 2,
96, 174, 3, 21, 65, 160, 4, 76, 105, 128, 17, 3, 228, 188, 162, 130, 17, 2, 228, 169, 188, 133, 10, 169, 130, 133, 11, 169, 0, 133, 12, 169,
96, 133, 13, 162, 214, 169, 255, 133, 18, 160, 0, 232, 240, 13, 177, 10, 145, 12, 200, 208, 246, 230, 11, 230, 13, 208, 240, 230, 18, 208, 239, 96,
133, 10, 134, 11, 162, 0, 177, 10, 96, 208, 42, 162, 0, 138, 96, 240, 36, 22, 163, 30, 48, 28, 22, 227, 2, 16, 20, 22, 227, 14, 144, 12,
21, 200, 176, 4, 22, 226, 162, 0, 169, 1, 96, 165, 115, 208, 252, 96, 169, 255, 197, 115, 240, 252, 96, 133, 118, 132, 116, 134, 117, 32, 193, 129,
164, 113, 165, 116, 153, 0, 2, 165, 117, 153, 0, 3, 165, 118, 153, 0, 4, 200, 132, 113, 230, 115, 96, 164, 115, 208, 1, 96, 166, 114, 169, 14,
141, 42, 96, 189, 0, 2, 141, 6, 32, 189, 0, 3, 22, 163, 4, 141, 7, 32, 232, 136, 240, 93, 17, 19, 14, 71, 17, 19, 14, 49, 17, 19,
14, 27, 17, 19, 14, 5, 206, 42, 96, 208, 141, 134, 114, 132, 115, 96, 169, 0, 162, 0, 72, 165, 2, 56, 233, 2, 133, 2, 176, 2, 198, 3,
160, 1, 138, 145, 2, 104, 136, 145, 2, 96, 169, 41, 133, 10, 169, 96, 17, 34, 41, 168, 162, 0, 240, 10, 145, 10, 200, 208, 251, 230, 11, 202,
208, 246, 192, 2, 240, 5, 21, 70, 247, 96, 78, 111, 32, 99, 97, 114, 116, 32, 108, 111, 97, 100, 101, 100, 0, 1, 0, 16, 32, 17, 66, 184,
141, 18, 96, 142, 19, 96, 141, 25, 96, 142, 26, 96, 136, 185, 255, 255, 141, 35, 22, 196, 34, 96, 140, 37, 96, 32, 255, 255, 160, 255, 208, 232,
96, 17, 71, 230, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 10, 53, 128, 0, 128, 92, 128,
17, 14, 14, 204, 204, 51, 51, 22, 106, 0, 24, 60, 126, 24, 22, 1, 22, 231, 16, 48, 127, 127, 48, 16, 0, 22, 230, 12, 18, 48, 124, 48,
98, 252, 22, 231, 0, 0, 3, 62, 118, 54, 54, 22, 231, 127, 127, 17, 4, 80, 22, 230, 224, 224, 96, 22, 3, 22, 230, 24, 24, 24, 248, 248,
21, 16, 22, 230, 204, 153, 51, 102, 22, 106, 51, 153, 204, 22, 107, 21, 27, 255, 255, 17, 4, 67, 22, 227, 3, 22, 13, 17, 6, 188, 22, 230,
17, 2, 172, 22, 13, 31, 31, 22, 236, 255, 255, 22, 236, 31, 31, 17, 4, 136, 22, 227, 22, 1, 248, 248, 21, 5, 22, 233, 17, 14, 123, 17,
3, 64, 22, 230, 17, 3, 64, 21, 248, 17, 8, 29, 21, 216, 17, 6, 88, 17, 3, 64, 22, 230, 240, 22, 13, 21, 233, 21, 243, 22, 230, 17,
6, 16, 22, 226, 192, 192, 48, 48, 22, 106, 15, 22, 1, 21, 84, 22, 230, 17, 10, 4, 22, 226, 17, 10, 52, 22, 230, 17, 6, 16, 17, 10,
44, 22, 6, 17, 35, 220, 0, 24, 22, 231, 102, 102, 17, 34, 107, 0, 22, 233, 255, 22, 33, 102, 22, 231, 24, 62, 96, 60, 6, 124, 21, 40,
22, 229, 0, 102, 12, 24, 48, 102, 70, 22, 231, 60, 102, 60, 56, 103, 102, 63, 22, 231, 6, 12, 17, 36, 59, 22, 230, 21, 30, 48, 48, 24,
12, 22, 231, 22, 97, 12, 21, 4, 22, 231, 0, 102, 60, 255, 60, 17, 2, 115, 22, 230, 24, 24, 126, 17, 35, 70, 22, 230, 17, 4, 173, 21,
33, 22, 231, 126, 21, 205, 22, 231, 21, 80, 22, 232, 3, 6, 12, 24, 48, 96, 22, 231, 60, 102, 110, 118, 102, 102, 60, 22, 231, 24, 24, 56,
24, 24, 24, 126, 22, 231, 60, 102, 6, 12, 48, 96, 22, 235, 28, 6, 21, 168, 22, 228, 6, 14, 30, 102, 127, 6, 6, 22, 231, 126, 96, 124,
6, 21, 80, 22, 230, 60, 102, 96, 124, 17, 4, 88, 22, 228, 126, 102, 12, 17, 35, 83, 22, 230, 60, 21, 13, 21, 216, 22, 231, 62, 21, 240,
22, 228, 17, 34, 124, 22, 66, 22, 236, 17, 2, 224, 22, 228, 14, 24, 48, 96, 48, 24, 14, 0, 22, 230, 17, 2, 239, 17, 4, 241, 22, 228,
112, 24, 12, 6, 12, 24, 112, 22, 231, 17, 2, 192, 24, 21, 52, 22, 232, 110, 110, 96, 98, 17, 3, 248, 22, 227, 24, 60, 102, 126, 17, 34,
228, 22, 230, 124, 102, 102, 22, 66, 22, 231, 60, 102, 96, 96, 96, 17, 4, 200, 22, 227, 120, 108, 21, 30, 108, 120, 22, 231, 126, 96, 96, 120,
96, 96, 126, 22, 237, 96, 22, 231, 21, 48, 110, 17, 37, 8, 22, 227, 21, 46, 17, 3, 96, 22, 230, 60, 17, 99, 19, 21, 24, 22, 229, 30,
12, 22, 1, 108, 56, 22, 231, 102, 108, 120, 112, 120, 108, 21, 40, 22, 229, 17, 132, 62, 126, 22, 231, 99, 119, 127, 107, 99, 99, 99, 22, 231,
102, 118, 126, 126, 110, 17, 2, 88, 22, 229, 60, 102, 22, 2, 17, 35, 88, 22, 227, 17, 2, 205, 21, 49, 22, 231, 21, 144, 60, 14, 22, 231,
21, 80, 17, 2, 96, 22, 230, 60, 102, 96, 60, 17, 37, 208, 22, 227, 17, 163, 13, 17, 34, 200, 22, 229, 21, 111, 17, 5, 208, 22, 232, 60,
17, 5, 16, 22, 225, 99, 99, 99, 107, 127, 119, 99, 22, 231, 21, 77, 60, 17, 3, 248, 22, 230, 21, 1, 17, 4, 64, 22, 227, 126, 17, 67,
159, 126, 22, 231, 60, 48, 22, 2, 60, 22, 231, 96, 48, 24, 12, 6, 3, 0, 22, 231, 60, 17, 34, 32, 12, 21, 24, 22, 229, 17, 34, 193,
17, 68, 244, 22, 229, 22, 3, 17, 165, 133, 22, 225, 17, 134, 203, 22, 230, 21, 58, 6, 62, 102, 62, 22, 232, 96, 17, 66, 176, 124, 22, 232,
0, 60, 96, 96, 96, 17, 66, 144, 22, 229, 6, 21, 31, 21, 96, 22, 230, 0, 60, 102, 126, 21, 216, 22, 228, 14, 24, 62, 17, 3, 84, 22,
230, 0, 21, 95, 6, 124, 22, 231, 17, 3, 80, 102, 17, 5, 88, 22, 225, 24, 0, 56, 17, 34, 240, 22, 231, 6, 0, 6, 22, 1, 60, 22,
231, 96, 96, 108, 17, 34, 128, 22, 231, 21, 30, 21, 160, 22, 230, 0, 102, 127, 127, 107, 99, 22, 233, 17, 2, 79, 21, 32, 22, 231, 17, 34,
210, 17, 4, 152, 22, 228, 17, 36, 242, 22, 232, 17, 3, 144, 6, 22, 232, 124, 17, 66, 226, 21, 160, 22, 228, 17, 131, 225, 22, 232, 17, 130,
127, 17, 98, 112, 22, 230, 17, 35, 226, 17, 34, 0, 22, 233, 60, 17, 2, 240, 22, 230, 99, 107, 127, 62, 17, 226, 24, 22, 230, 17, 35, 241,
22, 234, 21, 47, 12, 120, 22, 232, 126, 12, 24, 48, 17, 98, 194, 22, 228, 28, 48, 24, 112, 24, 48, 28, 22, 231, 17, 164, 159, 22, 3, 22,
227, 56, 12, 24, 14, 24, 12, 56, 0, 22, 230, 51, 255, 204, 17, 35, 206, 22, 230, 22, 14, 17, 194, 92, 22, 10, 17, 236, 246, 204, 204, 255,
231, 195, 129, 231, 22, 1, 22, 231, 239, 207, 128, 128, 207, 239, 255, 22, 230, 243, 237, 207, 131, 207, 157, 3, 22, 231, 255, 255, 252, 193, 137, 201,
201, 22, 231, 128, 128, 17, 4, 80, 22, 230, 31, 31, 159, 22, 3, 22, 230, 231, 231, 231, 7, 7, 21, 16, 22, 230, 17, 236, 246, 204, 17, 237,
246, 51, 153, 17, 227, 11, 17, 4, 67, 22, 227, 252, 22, 13, 17, 6, 188, 22, 230, 17, 2, 172, 22, 13, 224, 224, 22, 236, 0, 0, 22, 236,
224, 224, 17, 4, 136, 22, 227, 22, 1, 7, 7, 21, 5, 22, 233, 17, 14, 123, 17, 3, 64, 22, 230, 17, 3, 64, 21, 248, 17, 8, 29, 21,
216, 17, 6, 88, 17, 3, 64, 22, 230, 17, 226, 124, 22, 10, 17, 238, 244, 22, 226, 17, 6, 16, 22, 226, 63, 63, 207, 207, 22, 106, 17, 226,
192, 21, 84, 22, 230, 17, 10, 4, 17, 230, 220, 17, 14, 60, 17, 234, 252, 17, 6, 44, 22, 6, 17, 35, 220, 255, 231, 22, 231, 153, 153, 17,
34, 107, 255, 22, 233, 0, 22, 33, 153, 22, 231, 231, 193, 159, 195, 249, 131, 21, 40, 22, 229, 255, 153, 243, 231, 207, 153, 185, 22, 231, 195, 153,
195, 199, 152, 153, 192, 22, 231, 249, 243, 17, 36, 59, 22, 230, 21, 30, 207, 207, 231, 243, 22, 231, 22, 97, 243, 21, 4, 22, 231, 255, 153, 195,
0, 195, 17, 2, 115, 22, 230, 231, 231, 129, 17, 35, 70, 22, 230, 17, 4, 173, 21, 33, 22, 231, 129, 21, 205, 22, 231, 21, 80, 22, 232, 252,
249, 243, 231, 207, 159, 22, 231, 195, 153, 145, 137, 153, 153, 195, 22, 231, 231, 231, 199, 231, 231, 231, 129, 22, 231, 195, 153, 249, 243, 207, 159, 22,
235, 227, 249, 21, 168, 22, 228, 249, 241, 225, 153, 128, 249, 249, 22, 231, 129, 159, 131, 249, 21, 80, 22, 230, 195, 153, 159, 131, 17, 4, 88, 22,
228, 129, 153, 243, 17, 35, 83, 22, 230, 195, 21, 13, 21, 216, 22, 231, 193, 21, 240, 22, 228, 17, 34, 124, 22, 66, 22, 236, 17, 2, 224, 22,
228, 241, 231, 207, 159, 207, 231, 241, 255, 22, 230, 17, 2, 239, 17, 4, 241, 22, 228, 143, 231, 243, 249, 243, 231, 143, 22, 231, 17, 2, 192, 231,
21, 52, 22, 232, 145, 145, 159, 157, 17, 3, 248, 22, 227, 231, 195, 153, 129, 17, 34, 228, 22, 230, 131, 153, 153, 22, 66, 22, 231, 195, 153, 159,
159, 159, 17, 4, 200, 22, 227, 135, 147, 21, 30, 147, 135, 22, 231, 129, 159, 159, 135, 159, 159, 129, 22, 237, 159, 22, 231, 21, 48, 145, 17, 37,
8, 22, 227, 21, 46, 17, 3, 96, 22, 230, 195, 17, 99, 19, 21, 24, 22, 229, 225, 243, 22, 1, 147, 199, 22, 231, 153, 147, 135, 143, 135, 147,
21, 40, 22, 229, 17, 132, 62, 129, 22, 231, 156, 136, 128, 148, 156, 156, 156, 22, 231, 153, 137, 129, 129, 145, 17, 2, 88, 22, 229, 195, 153, 22,
2, 17, 35, 88, 22, 227, 17, 2, 205, 21, 49, 22, 231, 21, 144, 195, 241, 22, 231, 21, 80, 17, 2, 96, 22, 230, 195, 153, 159, 195, 17, 37,
208, 22, 227, 17, 163, 13, 17, 34, 200, 22, 229, 21, 111, 17, 5, 208, 22, 232, 195, 17, 5, 16, 22, 225, 156, 156, 156, 148, 128, 136, 156, 22,
231, 21, 77, 195, 17, 3, 248, 22, 230, 21, 1, 17, 4, 64, 22, 227, 129, 17, 67, 159, 129, 22, 231, 195, 207, 22, 2, 195, 22, 231, 159, 207,
231, 243, 249, 252, 255, 22, 231, 195, 17, 34, 32, 243, 21, 24, 22, 229, 17, 34, 193, 17, 68, 244, 22, 229, 22, 3, 17, 165, 133, 22, 225, 17,
134, 203, 22, 230, 21, 58, 249, 193, 153, 193, 22, 232, 159, 17, 66, 176, 131, 22, 232, 255, 195, 159, 159, 159, 17, 66, 144, 22, 229, 249, 21, 31,
21, 96, 22, 230, 255, 195, 153, 129, 21, 216, 22, 228, 241, 231, 193, 17, 3, 84, 22, 230, 255, 21, 95, 249, 131, 22, 231, 17, 3, 80, 153, 17,
5, 88, 22, 225, 231, 255, 199, 17, 34, 240, 22, 231, 249, 255, 249, 22, 1, 195, 22, 231, 159, 159, 147, 17, 34, 128, 22, 231, 21, 30, 21, 160,
22, 230, 255, 153, 128, 128, 148, 156, 22, 233, 17, 2, 79, 21, 32, 22, 231, 17, 34, 210, 17, 4, 152, 22, 228, 17, 36, 242, 22, 232, 17, 3,
144, 249, 22, 232, 131, 17, 66, 226, 21, 160, 22, 228, 17, 131, 225, 22, 232, 17, 130, 127, 17, 98, 112, 22, 230, 17, 35, 226, 17, 34, 0, 22,
233, 195, 17, 2, 240, 22, 230, 156, 148, 128, 193, 17, 226, 24, 22, 230, 17, 35, 241, 22, 234, 21, 47, 243, 135, 22, 232, 129, 243, 231, 207, 17,
98, 194, 22, 228, 227, 207, 231, 143, 231, 207, 227, 22, 231, 17, 164, 159, 22, 3, 22, 227, 199, 243, 231, 241, 231, 243, 199, 255, 22, 230, 204, 0,
51, 17, 35, 206, 22, 230, 22, 14, 9, 19, 0, 13, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 30, 22, 28
];
describe('LZG', function () {
it('Should decode LZG', function () {
var rom = new Uint8Array(new lzgmini().decode(NES_CONIO_ROM_LZG));
assert.equal(40976, rom.length);
});
});
describe('string functions', function () {
it('Should detect binary', function () {
assert.ok(!isProbablyBinary(null, [32, 32, 10, 13, 9, 32, 32, 10, 13]));
assert.ok(isProbablyBinary(null, [32, 32, 0x80]));
assert.ok(!isProbablyBinary(null, [32, 32, 0xc1, 0x81, 32, 32, 10, 13]));
assert.ok(isProbablyBinary(null, NES_CONIO_ROM_LZG));
assert.ok(isProbablyBinary('test.bin'));
assert.ok(isProbablyBinary('test.chr'));
assert.ok(!isProbablyBinary('test.txt'));
assert.ok(isProbablyBinary('test.dat'));
assert.ok(!isProbablyBinary(null, [0x20, 0xa9, 0x20, 0x31, 0x39, 0x38, 0x32]));
assert.ok(isProbablyBinary(null, [0x00, 0x00])); // 00 is binary
assert.ok(isProbablyBinary(null, [0x9f])); // 9f is binary
assert.ok(isProbablyBinary(null, [0xff])); // FF is binary
assert.ok(isProbablyBinary(null, [0xf0, 0x12])); // ran out of data
});
});
describe('EmuHalt', function () {
it('Should detect emuhalt', function () {
var e = new EmuHalt("?");
assert.ok(e instanceof EmuHalt);
assert.ok(e.hasOwnProperty('$loc'));
});
});
describe('Tokenizer', function () {
it('Should tokenize', function () {
var t = new Tokenizer();
t.setTokenRules([
{ type: 'ident', regex: /[$A-Za-z_][A-Za-z0-9_-]*/ },
{ type: 'delim', regex: /[\(\)\{\}\[\]]/ },
{ type: 'qstring', regex: /".*?"/ },
{ type: 'integer', regex: /[-]?\d+/ },
{ type: 'eol', regex: /\n+/ },
{ type: 'ignore', regex: /\s+/ },
]);
t.tokenizeFile("a\n{\"key\" value\n \"number\" 531\n\n \"f\" (fn [x] (+ x 2))}\n", "test.file");
assert.strictEqual(t.tokens.map(t => t.type).join(' '),
'ident delim qstring ident qstring integer qstring delim ident delim ident delim delim catch-all ident integer delim delim delim eof');
assert.strictEqual(t.tokens.map(t => t.str).join(' '),
'a { "key" value "number" 531 "f" ( fn [ x ] ( + x 2 ) ) } ');
assert.strictEqual(t.tokens.filter(t => t.eol).map(t => t.str).join(' '),
'a value 531 } ');
assert.strictEqual(t.tokens.map(t => t.$loc.line).join(' '),
'1 2 2 2 3 3 5 5 5 5 5 5 5 5 5 5 5 5 5 6');
assert.strictEqual(20, t.tokens.length);
assert.strictEqual('a', t.peekToken().str);
assert.strictEqual('a', t.expectToken('a').str);
t.expectTokens(['foo', '{']);
t.pushbackToken(t.consumeToken());
assert.strictEqual('"key"', t.consumeToken().str);
assert.deepStrictEqual({ 'value': true }, t.parseModifiers(['foo', 'value', 'bar']));
assert.deepStrictEqual([], t.errors);
t = new Tokenizer();
t.setTokenRules([
{ type: 'ident', regex: /[$A-Za-z_][A-Za-z0-9_-]*/ },
{ type: 'delim', regex: /[\(\)\{\}\[\]]/ },
{ type: 'code-fragment', regex: /---[^-]*---/ },
{ type: 'ignore', regex: /\s+/ },
]);
t.tokenizeFile("key value ---\nthis is\na fragment\n--- foo", "test.file");
assert.strictEqual(t.tokens.map(t => t.type).join(' '),
'ident ident code-fragment ident eof');
});
});
describe('EmuHalt', function () {
try {
throw new EmuHalt("test");
} catch (err) {
assert.ok(err instanceof EmuHalt);
assert.ok(err.squelchError);
}
});
describe('CPU metadata', function () {
let cpu = new MOS6502();
for (let i=0; i<256; i++) {
let meta1 = OPS_6502[i];
let meta2 = cpu.getOpcodeMetadata(i);
if (meta1.il > 0) continue;
// assert.strictEqual(meta1.mn, meta2.mnenomic, `mnemonic ${hex(i)}: ${meta1.mn} != ${meta2.mnenomic}`);
assert.strictEqual(meta1.nb, meta2.insnlength, `insnLength ${hex(i)}: ${meta1.nb} != ${meta2.insnlength}`);
assert.strictEqual(meta1.c1, meta2.minCycles, `minCycles ${hex(i)}: ${meta1.c1} != ${meta2.minCycles}`);
assert.strictEqual(meta1.c1+meta1.c2, meta2.maxCycles, `maxCycles ${hex(i)}: ${meta1.c1+meta1.c2} != ${meta2.maxCycles}`);
}
});
+107
View File
@@ -0,0 +1,107 @@
import assert from "assert";
import { WASIRunner } from "../../src/common/wasi/wasishim";
import * as fs from "fs";
import { loadWASIFilesystemZip, unzipWASIFilesystem } from "../../src/worker/wasiutils";
async function loadWASM(filename: string) {
const wasmdata = fs.readFileSync(`./src/worker/wasm/${filename}.wasm`);
let shim = new WASIRunner();
await shim.loadAsync(wasmdata);
return shim;
}
async function loadDASM() {
return loadWASM('dasm-wasisdk');
}
async function loadCC7800() {
return loadWASM('cc7800');
}
async function loadOscar64() {
return loadWASM('oscar64');
}
describe('test WASI DASM', function () {
it('dasm help', async function () {
let shim = await loadDASM();
let errno = shim.run();
assert.strictEqual(errno, 1);
});
it('dasm file not found', async function () {
let shim = await loadDASM();
shim.setArgs(["dasm", "file_not_found.asm"]);
let errno = shim.run();
assert.strictEqual(errno, 2);
});
it('dasm file not found 2', async function () {
let shim = await loadDASM();
shim.setArgs(["dasm", "/file.asm", "-d"]);
let errno = shim.run();
assert.strictEqual(errno, 2);
});
it('dasm bad args 1', async function () {
let shim = await loadDASM();
shim.setArgs(["dasm", "file_not_found.asm", "extra_arg.asm"]);
let errno = shim.run();
assert.strictEqual(errno, 1);
});
it('dasm bad args 2', async function () {
let shim = await loadDASM();
shim.setArgs(["dasm", "file_not_found.asm", "-E9"]);
let errno = shim.run();
assert.strictEqual(errno, 1);
});
it('dasm empty file', async function () {
let shim = await loadDASM();
shim.setArgs(["dasm", "empty.asm"]);
shim.addPreopenDirectory("/root");
shim.fs.putFile("/root/empty.asm", "");
let errno = shim.run();
assert.strictEqual(errno, 0);
});
it('dasm small file', async function () {
let shim = await loadDASM();
shim.setArgs(["dasm", "empty.asm"]);
shim.addPreopenDirectory("/root");
shim.fs.putFile("/root/empty.asm", " processor 6502\n org $100\n nop");
let errno = shim.run();
assert.strictEqual(errno, 0);
let aout = shim.fs.getFile("/root/a.out");
assert.deepStrictEqual(Array.from(aout.getBytes()), [0x00, 0x01, 0xea]);
});
});
describe('test WASI cc7800', function () {
it('cc7800 help', async function () {
let shim = await loadCC7800();
shim.setArgs(["cc7800", '-h']);
let errno = shim.run();
assert.strictEqual(errno, 0);
const stdout = shim.fds[1].getBytesAsString();
console.log(stdout);
assert.ok(stdout.indexOf('Usage: cc7800') >= 0);
});
});
/*
describe('test WASI oscar64', function () {
it('oscar64 compile', async function () {
let shim = await loadOscar64();
const zipdata = fs.readFileSync(`./src/worker/fs/oscar64-fs.zip`);
shim.fs = await unzipWASIFilesystem(zipdata, "/root/");
// https://github.com/WebAssembly/wasi-filesystem/issues/24
// https://github.com/WebAssembly/wasi-libc/pull/214
shim.addPreopenDirectory("/root");
shim.fs.putSymbolicLink("/proc/self/exe", "/root/bin/oscar64");
shim.fs.putFile("/root/main.c", `#include <stdio.h>\nint main() { printf("FOO"); return 0; }`);
shim.setArgs(["oscar64", '-v', '-g', '-O', '-o=foo.prg', 'main.c']);
let errno = shim.run();
const stdout = shim.fds[1].getBytesAsString();
console.log(stdout);
const stderr = shim.fds[2].getBytesAsString();
console.log(stderr);
assert.strictEqual(errno, 0);
assert.ok(stdout.indexOf('Starting oscar64') >= 0);
console.log(shim.fs.getFile("/root/foo.asm").getBytesAsString());
});
});
*/