refactoring; xasm6809

This commit is contained in:
Steven Hugg 2017-01-21 08:13:36 -05:00
parent f696f22b5a
commit a82accf060
15 changed files with 194 additions and 173 deletions

View File

@ -193,7 +193,7 @@ canvas.pixelated {
<li><a class="dropdown-item" href="?platform=vcs" id="item_platform_vcs">Atari VCS</a></li>
<li><a class="dropdown-item" href="?platform=apple2" id="item_platform_apple2">Apple ][</a></li>
<li><a class="dropdown-item" href="?platform=atarivec" id="item_platform_atarivec">Asteroids</a></li>
<li><a class="dropdown-item" href="?platform=spaceinv" id="item_platform_spaceinv">Space Invaders</a></li>
<li><a class="dropdown-item" href="?platform=mw8080bw" id="item_platform_mw8080bw">Midway 8080 B/W</a></li>
</ul>
</li>
-->

View File

@ -15,7 +15,7 @@
},
"scripts": {
"test": "npm run test-node && npm run test-browser",
"test-node": "mocha --recursive test/cli",
"test-node": "mocha --recursive --timeout 5000 test/cli",
"test-browser": "mocha-phantomjs ./testemu.html"
},
"repository": {

View File

@ -8,10 +8,6 @@ function noise() {
return (Math.random() * 256) & 0xff;
}
function _metakeyflags(e) {
return (e.shiftKey?2:0) | (e.ctrlKey?4:0) | (e.altKey?8:0) | (e.metaKey?16:0);
}
function __createCanvas(mainElement, width, height) {
// TODO
var fsElement = document.createElement('div');
@ -55,6 +51,7 @@ var RasterVideo = function(mainElement, width, height, options) {
datau32 = new Uint32Array(buf);
}
// TODO: make common
this.setKeyboardEvents = function(callback) {
canvas.onkeydown = function(e) {
callback(e.which, 0, 1|_metakeyflags(e));
@ -131,7 +128,7 @@ var VectorVideo = function(mainElement, width, height) {
var persistenceAlpha = 0.5;
var jitter = 1.0;
this.start = function() {
this.create = function() {
canvas = __createCanvas(mainElement, width, height);
ctx = canvas.getContext('2d');
}
@ -666,7 +663,7 @@ var Base6809Platform = function() {
// TODO: 6809 opcodes
if (op == 0x9d || op == 0xad || op == 0xbd) // CALL
depth++;
else if (op == 0x3b || op == 0x39) // RET (TODO?)
else if (op == 0x3b || op == 0x39) // RET
--depth;
return false;
});
@ -675,11 +672,8 @@ var Base6809Platform = function() {
return cpuStateToLongString_6809(c);
}
this.getToolForFilename = function(fn) {
if (fn.endsWith(".c")) return "sdcc";
if (fn.endsWith(".s")) return "sdasz80";
return "z80asm";
return "xasm6809";
}
// TODO
this.disassemble = function(pc, read) {
// TODO: don't create new CPU
return new CPU6809().disasm(read(pc), read(pc+1), read(pc+2), read(pc+3), read(pc+4), pc);
@ -794,6 +788,32 @@ var Keys = {
VK_NUMPAD_CENTER: {c: 12, n: "Num Cntr"}
};
function _metakeyflags(e) {
return (e.shiftKey?2:0) | (e.ctrlKey?4:0) | (e.altKey?8:0) | (e.metaKey?16:0);
}
function setKeyboardFromMap(video, switches, map, func) {
video.setKeyboardEvents(function(key,code,flags) {
var o = map[key];
if (o && func) {
func(o, key, code, flags);
}
if (o) {
//console.log(key,code,flags,o);
var mask = o.mask;
if (mask < 0) { // negative mask == active low
mask = -mask;
flags ^= 1;
}
if (flags & 1) {
switches[o.index] |= mask;
} else {
switches[o.index] &= ~mask;
}
}
});
}
function makeKeycodeMap(table) {
var map = {};
for (var i=0; i<table.length; i++) {
@ -810,10 +830,13 @@ function padBytes(data, len) {
}
// TODO: better performance, check values
function AddressDecoder(table) {
function AddressDecoder(table, options) {
var self = this;
function makeFunction(lo, hi) {
var s = "";
if (options && options.gmask) {
s += "a&=" + options.gmask + ";";
}
for (var i=0; i<table.length; i++) {
var entry = table[i];
var start = entry[0];

View File

@ -286,9 +286,6 @@ var Apple2Platform = function(mainElement) {
lc:{s:auxRAMselected,b:auxRAMbank,w:writeinhibit},
};
}
this.getRAMForState = function(state) {
return ram.mem;
}
this.getCPUState = function() {
return cpu.saveState();
}

View File

@ -16,6 +16,19 @@ var AtariVectorPlatform = function(mainElement) {
this.__proto__ = new Base6502Platform();
var ASTEROIDS_KEYCODE_MAP = makeKeycodeMap([
[Keys.VK_SHIFT, 3, 0xff],
[Keys.VK_SPACE, 4, 0xff],
[Keys.VK_5, 8, 0xff],
[Keys.VK_6, 9, 0xff],
[Keys.VK_7, 10, 0xff],
[Keys.VK_1, 11, 0xff],
[Keys.VK_2, 12, 0xff],
[Keys.VK_UP, 13, 0xff],
[Keys.VK_RIGHT, 14, 0xff],
[Keys.VK_LEFT, 15, 0xff],
]);
this.getPresets = function() {
return ATARIVEC_PRESETS;
}
@ -28,38 +41,24 @@ var AtariVectorPlatform = function(mainElement) {
//switches[7] = 0xff;
// bus
bus = {
read: function(address) {
address &= 0x7fff;
if (address >= 0x6800 && address <= 0x7fff) {
return rom[address - 0x6800];
} else if (address <= 0x3ff) {
return cpuram.mem[address];
} else if (address >= 0x5000 && address <= 0x5fff) {
return vecrom[address - 0x5000];
} else if (address >= 0x4000 && address <= 0x5fff) {
return dvgram.mem[address - 0x4000];
} else if (address >= 0x2000 && address <= 0x3fff) {
if (address == 0x2001)
return ((clock/500) & 1) ? 0xff : 0x00;
else if (address >= 0x2000 && address <= 0x2007)
return switches[address - 0x2000];
else if (address >= 0x2400 && address <= 0x2407)
return switches[address - 0x2400 + 8];
}
return 0xff;
},
write: function(address, val) {
address &= 0x7fff;
if (address < 0x3ff) {
cpuram.mem[address] = val;
} else if (address >= 0x4000 && address <= 0x5fff) {
dvgram.mem[address - 0x4000] = val;
} else if (address >= 0x3000 && address <= 0x3fff) {
//console.log(address.toString(16), val);
if (address == 0x3000) dvg.runUntilHalt();
// TODO: draw asynchronous or allow poll of HALT ($2002)
}
}
read: new AddressDecoder([
[0x0, 0x3ff, 0x3ff, function(a) { return cpuram.mem[a]; }],
[0x2001, 0x2001, 0, function(a) { return ((clock/500) & 1) ? 0xff : 0x00; }],
[0x2000, 0x2007, 0x7, function(a) { return switches[a]; }],
[0x2400, 0x2407, 0x7, function(a) { return switches[a+8]; }],
[0x4000, 0x4fff, 0xfff, function(a) { return dvgram.mem[a]; }],
[0x5000, 0x5fff, 0xfff, function(a) { return vecrom[a]; }],
[0x6800, 0x7fff, 0, function(a) { return rom[a - 0x6800]; }],
], {gmask:0x7fff}),
write: new AddressDecoder([
[0x0, 0x3ff, 0x3ff, function(a,v) { cpuram.mem[a] = v; }],
[0x3000, 0x3000, 0, function(a,v) { dvg.runUntilHalt(); }],
// TODO: draw asynchronous or allow poll of HALT ($2002)
[0x4000, 0x5fff, 0x1fff, function(a,v) { dvgram.mem[a] = v; }],
], {gmask:0x7fff})
};
cpu.connectBus(bus);
// create video/audio
@ -89,25 +88,7 @@ var AtariVectorPlatform = function(mainElement) {
}
self.restartDebugState();
});
video.setKeyboardEvents(function(key,code,flags) {
var KEY2ADDR = {
16: 3, // shift
32: 4, // space
53: 8+0, // 5
54: 8+1, // 6
55: 8+2, // 7
49: 8+3, // 1
50: 8+4, // 2
38: 8+5,
39: 8+6,
37: 8+7,
};
var addr = KEY2ADDR[key];
//console.log(key,flags,addr);
if (addr >= 0) {
switches[addr] = (flags&1) ? 0xff : 0x00;
}
});
setKeyboardFromMap(video, switches, ASTEROIDS_KEYCODE_MAP);
}
this.loadROM = function(title, data) {
@ -154,9 +135,6 @@ var AtariVectorPlatform = function(mainElement) {
nmic:nmicount
}
}
this.getRAMForState = function(state) {
return state.cb;
}
this.getCPUState = function() {
return cpu.saveState();
}

View File

@ -32,6 +32,18 @@ var GalaxianPlatform = function(mainElement) {
for (var i=0; i<256; i++)
stars[i] = noise();
var GALAXIAN_KEYCODE_MAP = makeKeycodeMap([
[Keys.VK_SPACE, 0, 0x10], // P1
[Keys.VK_LEFT, 0, 0x4],
[Keys.VK_RIGHT, 0, 0x8],
[Keys.VK_S, 1, 0x10], // P2
[Keys.VK_A, 1, 0x4],
[Keys.VK_D, 1, 0x8],
[Keys.VK_5, 0, 0x1],
[Keys.VK_1, 1, 0x1],
[Keys.VK_2, 1, 0x2],
]);
function drawScanline(pixels, sl) {
if (sl < 16 && !showOffscreenObjects) return; // offscreen
if (sl >= 240 && !showOffscreenObjects) return; // offscreen
@ -127,18 +139,6 @@ var GalaxianPlatform = function(mainElement) {
}
}
var KEYCODE_MAP = {
32:{i:0,b:4}, // space bar (P1)
37:{i:0,b:2}, // left arrow (P1)
39:{i:0,b:3}, // right arrow (P1)
0x53:{i:1,b:4}, // S (P2)
0x41:{i:1,b:2}, // A (P2)
0x44:{i:1,b:3}, // D (P2)
53:{i:0,b:0}, // 5
49:{i:1,b:0}, // 1
50:{i:1,b:1}, // 2
}
this.getPresets = function() {
return GALAXIAN_PRESETS;
}
@ -187,16 +187,7 @@ var GalaxianPlatform = function(mainElement) {
audio = new SampleAudio(cpuFrequency);
video.create();
var idata = video.getFrameData();
video.setKeyboardEvents(function(key,code,flags) {
var o = KEYCODE_MAP[key];
if (o) {
if (flags & 1) {
inputs[o.i] |= (1<<o.b);
} else {
inputs[o.i] &= ~(1<<o.b);
}
}
});
setKeyboardFromMap(video, inputs, GALAXIAN_KEYCODE_MAP);
pixels = video.getFrameData();
timer = new AnimationTimer(60, function() {
if (!self.isRunning())
@ -295,9 +286,6 @@ var GalaxianPlatform = function(mainElement) {
in2:inputs[2],
};
}
this.getRAMForState = function(state) {
return ram.mem;
}
this.getCPUState = function() {
return cpu.saveState();
}

View File

@ -123,9 +123,6 @@ var KonamiSoundPlatform = function(mainElement) {
b:ram.mem.slice(0),
};
}
this.getRAMForState = function(state) {
return ram.mem;
}
this.getCPUState = function() {
return cpu.saveState();
}

View File

@ -1,8 +1,8 @@
"use strict";
// http://www.computerarcheology.com/Arcade/SpaceInvaders/Hardware.html
// http://www.computerarcheology.com/Arcade/
var SPACEINV_PRESETS = [
var MW8080BW_PRESETS = [
];
// TODO: global???
@ -10,7 +10,7 @@ window.buildZ80({
applyContention: false
});
var SpaceInvadersPlatform = function(mainElement) {
var Midway8080BWPlatform = function(mainElement) {
var self = this;
this.__proto__ = new BaseZ80Platform();
@ -26,20 +26,20 @@ var SpaceInvadersPlatform = function(mainElement) {
var PIXEL_ON = 0xffeeeeee;
var PIXEL_OFF = 0xff000000;
var KEYCODE_MAP = {
32:{i:1,b:4}, // space bar (P1)
37:{i:1,b:5}, // left arrow (P1)
39:{i:1,b:6}, // right arrow (P1)
0x53:{i:2,b:4}, // S (P2)
0x41:{i:2,b:5}, // A (P2)
0x44:{i:2,b:6}, // D (P2)
53:{i:1,b:0}, // 5
49:{i:1,b:2}, // 1
50:{i:1,b:1}, // 2
}
var SPACEINV_KEYCODE_MAP = makeKeycodeMap([
[Keys.VK_SPACE, 1, 0x10], // P1
[Keys.VK_LEFT, 1, 0x20],
[Keys.VK_RIGHT, 1, 0x40],
[Keys.VK_S, 2, 0x10], // P2
[Keys.VK_A, 2, 0x20],
[Keys.VK_D, 2, 0x40],
[Keys.VK_5, 1, 0x1],
[Keys.VK_1, 1, 0x4],
[Keys.VK_2, 1, 0x2],
]);
this.getPresets = function() {
return SPACEINV_PRESETS;
return MW8080BW_PRESETS;
}
this.start = function() {
@ -111,16 +111,7 @@ var SpaceInvadersPlatform = function(mainElement) {
console.log(x, y, hex(addr,4), "PC", hex(displayPCs[addr],4));
});
var idata = video.getFrameData();
video.setKeyboardEvents(function(key,code,flags) {
var o = KEYCODE_MAP[key];
if (o) {
if (flags & 1) {
inputs[o.i] |= (1<<o.b);
} else {
inputs[o.i] &= ~(1<<o.b);
}
}
});
setKeyboardFromMap(video, inputs, SPACEINV_KEYCODE_MAP);
pixels = video.getFrameData();
timer = new AnimationTimer(60, function() {
if (!self.isRunning())
@ -183,9 +174,6 @@ var SpaceInvadersPlatform = function(mainElement) {
in2:inputs[2],
};
}
this.getRAMForState = function(state) {
return ram.mem;
}
this.getCPUState = function() {
return cpu.saveState();
}
@ -209,4 +197,4 @@ var SpaceInvadersPlatform = function(mainElement) {
}
}
PLATFORMS['spaceinv'] = SpaceInvadersPlatform;
PLATFORMS['mw8080bw'] = Midway8080BWPlatform;

View File

@ -57,14 +57,14 @@ var VicDualPlatform = function(mainElement) {
}
}
var KEYCODE_MAP = {
37:{i:1,m:0x10,a:0}, // left arrow (P1)
39:{i:1,m:0x20,a:0}, // right arrow (P1)
49:{i:2,m:0x10,a:0}, // 1
32:{i:2,m:0x20,a:0}, // space bar (P1)
53:{i:3,m:0x08,a:1}, // 5
50:{i:3,m:0x20,a:0}, // 2
}
var CARNIVAL_KEYCODE_MAP = makeKeycodeMap([
[Keys.VK_SPACE, 2, -0x20], // P1
[Keys.VK_LEFT, 1, -0x10],
[Keys.VK_RIGHT, 1, -0x20],
[Keys.VK_1, 2, -0x10],
[Keys.VK_2, 3, -0x20],
[Keys.VK_5, 3, 0x8],
]);
this.getPresets = function() {
return VICDUAL_PRESETS;
@ -100,18 +100,10 @@ var VicDualPlatform = function(mainElement) {
audio = new SampleAudio(cpuFrequency);
video.create();
var idata = video.getFrameData();
video.setKeyboardEvents(function(key,code,flags) {
var o = KEYCODE_MAP[key];
if (o) {
if ((flags^o.a) & 1) {
inputs[o.i] &= ~o.m;
} else {
inputs[o.i] |= o.m;
}
// reset CPU when coin inserted
if (o.i==3 && o.m==0x8) cpu.reset();
}
});
setKeyboardFromMap(video, inputs, CARNIVAL_KEYCODE_MAP, function(o) {
// reset when coin inserted
if (o.index==3 && o.mask==0x8) cpu.reset();
});
pixels = video.getFrameData();
timer = new AnimationTimer(60, function() {
if (!self.isRunning())
@ -160,9 +152,6 @@ var VicDualPlatform = function(mainElement) {
in3:inputs[3],
};
}
this.getRAMForState = function(state) {
return ram.mem;
}
this.getCPUState = function() {
return cpu.saveState();
}

View File

@ -1,5 +1,5 @@
"use strict";
var WILLIAMS_PRESETS = [
];
@ -277,17 +277,7 @@ var WilliamsPlatform = function(mainElement) {
console.log(x, y, hex(addr,4), "PC", hex(displayPCs[addr],4));
});
var idata = video.getFrameData();
video.setKeyboardEvents(function(key,code,flags) {
var o = ROBOTRON_KEYCODE_MAP[key];
if (o) {
//console.log(key,code,flags,o);
if (flags & 1) {
pia6821[o.index] |= o.mask;
} else {
pia6821[o.index] &= ~o.mask;
}
}
});
setKeyboardFromMap(video, pia6821, ROBOTRON_KEYCODE_MAP);
pixels = video.getFrameData();
timer = new AnimationTimer(60, function() {
if (!self.isRunning())
@ -356,9 +346,6 @@ var WilliamsPlatform = function(mainElement) {
ps:portsel,
};
}
this.getRAMForState = function(state) {
return ram.mem;
}
this.getCPUState = function() {
return cpu.saveState();
}

View File

@ -463,7 +463,7 @@ l_main00101 = 0003, L: test
}
var PLATFORM_PARAMS = {
'spaceinv': {
'mw8080bw': {
code_start: 0x0,
code_size: 0x2000,
data_start: 0x2000,
@ -611,6 +611,53 @@ function compileSDCC(code, platform) {
return result;
}
function assembleXASM6809(code, platform) {
load("xasm6809");
var origin = 0; // TODO: configurable
var alst = "";
var lasterror = null;
msvc_errors = [];
function match_fn(s) {
alst += s;
alst += "\n";
if (lasterror) {
var line = parseInt(s.slice(0,5));
msvc_errors.push({
line:line,
msg:lasterror
});
lasterror = null;
}
else if (s.startsWith("***** ")) {
lasterror = s.slice(6);
}
}
var Module = xasm6809({
noInitialRun:true,
//logReadFiles:true,
print:match_fn,
printErr:print_fn
});
var FS = Module['FS'];
//setupFS(FS);
FS.writeFile("main.asm", code);
Module.callMain(["-c", "-l", "-s", "-y", "-o=main.bin", "main.asm"]);
console.log(alst);
try {
var aout = FS.readFile("main.bin", {encoding:'binary'});
// 00001 0000 [ 2] 1048 asld
var asmlines = parseListing(alst, /^\s*([0-9A-F]+)\s+([0-9A-F]+)\s+\[([0-9 ]+)\]\s+(\d+) (.*)/i, 1, 2, 4, 5, 3);
return {
output:aout,
errors:msvc_errors,
lines:asmlines,
intermediate:{listing:alst},
};
} catch(e) {
return {errors:msvc_errors}; // TODO
}
}
var TOOLS = {
'dasm': assembleDASM,
'acme': assembleACME,
@ -620,6 +667,7 @@ var TOOLS = {
'z80asm': assembleZ80ASM,
'sdasz80': assemblelinkSDASZ80,
'sdcc': compileSDCC,
'xasm6809': assembleXASM6809,
}
onmessage = function(e) {

23
src/worker/xasm6809.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -102,21 +102,24 @@ describe('Worker', function() {
compile('cc65', 'int main() {\nint x=1;\nprintf("%d",x);\nreturn x+2;\n}', 'apple2', done, 0, 0, 1);
});
it('should assemble Z80ASM', function(done) {
compile('z80asm', '\tMODULE test\n\tXREF _puts\n\tld hl,$0000\n\tret\n', 'spaceinv', done, 4, 2, 0);
compile('z80asm', '\tMODULE test\n\tXREF _puts\n\tld hl,$0000\n\tret\n', 'mw8080bw', done, 4, 2, 0);
});
it('should NOT assemble Z80ASM', function(done) {
compile('z80asm', 'ddwiuweq', 'none', done, 0, 0, 1);
});
it('should assemble SDASZ80', function(done) {
compile('sdasz80', '\tld hl,#0\n\tret\n', 'spaceinv', done, 8192, 2);
compile('sdasz80', '\tld hl,#0\n\tret\n', 'mw8080bw', done, 8192, 2);
});
it('should NOT assemble SDASZ80', function(done) {
compile('sdasz80', '\txxx hl,#0\n\tret\n', 'spaceinv', done, 0, 0, 1);
compile('sdasz80', '\txxx hl,#0\n\tret\n', 'mw8080bw', done, 0, 0, 1);
});
it('should compile SDCC', function(done) {
compile('sdcc', 'int foo=0;\nint main(int argc) {\nint x=1;\nint y=2+argc;\nreturn x+y+argc;\n}', 'spaceinv', done, 8192, 3, 0);
compile('sdcc', 'int foo=0;\nint main(int argc) {\nint x=1;\nint y=2+argc;\nreturn x+y+argc;\n}', 'mw8080bw', done, 8192, 3, 0);
});
it('should NOT compile SDCC', function(done) {
compile('sdcc', 'foobar', 'spaceinv', done, 0, 0, 1);
compile('sdcc', 'foobar', 'mw8080bw', done, 0, 0, 1);
});
it('should compile XASM6809', function(done) {
compile('xasm6809', '\tasld\n\tasld\n', 'mw8080bw', done, 4, 2, 0);
});
});

View File

@ -14,7 +14,7 @@ describe('Test VCS emulator', function() {
});
describe('Test Space Invaders emulator', function() {
var platform = new SpaceInvadersPlatform($('#emulator')[0]);
var platform = new Midway8080BWPlatform($('#emulator')[0]);
it('Should start', function(done) {
platform.start();
assert(!platform.isRunning());

View File

@ -35,7 +35,7 @@
<script src="src/util.js"></script>
<script src="src/disasm.js"></script>
<script src="src/platform/vcs.js"></script>
<script src="src/platform/spaceinv.js"></script>
<script src="src/platform/mw8080bw.js"></script>
<script src="test/ui/testemus.js"></script>