mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-12-23 03:29:39 +00:00
refactored mw8080 to use BasicZ80ScanlinePlatform
This commit is contained in:
parent
9699cea117
commit
d9de3981c9
@ -141,7 +141,7 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
||||
|
||||
<span class="dropdown">
|
||||
<a class="btn dropdown-toggle hidden-xs toolbarMenuButton" id="platformsMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
PLATFORMS <span class="caret"></span>
|
||||
<span>PLATFORMS</span> <span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="platformsMenuButton">
|
||||
<li class="dropdown dropdown-submenu">
|
||||
|
70
package-lock.json
generated
70
package-lock.json
generated
@ -240,6 +240,12 @@
|
||||
"graceful-readlink": ">= 1.0.0"
|
||||
}
|
||||
},
|
||||
"commandpost": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/commandpost/-/commandpost-1.4.0.tgz",
|
||||
"integrity": "sha512-aE2Y4MTFJ870NuB/+2z1cXBhSBBzRydVVjzhFC4gtenEhpnj15yu0qptWGJsO9YGrcPZ3ezX8AWb1VA391MKpQ==",
|
||||
"dev": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
@ -324,6 +330,26 @@
|
||||
"safer-buffer": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"editorconfig": {
|
||||
"version": "0.15.3",
|
||||
"resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz",
|
||||
"integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "^2.19.0",
|
||||
"lru-cache": "^4.1.5",
|
||||
"semver": "^5.6.0",
|
||||
"sigmund": "^1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "2.20.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
|
||||
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"encoding": {
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
|
||||
@ -669,6 +695,16 @@
|
||||
"integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
|
||||
"dev": true
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
|
||||
"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pseudomap": "^1.0.2",
|
||||
"yallist": "^2.1.2"
|
||||
}
|
||||
},
|
||||
"lzg": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lzg/-/lzg-1.0.0.tgz",
|
||||
@ -903,6 +939,12 @@
|
||||
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
|
||||
"dev": true
|
||||
},
|
||||
"pseudomap": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
|
||||
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
|
||||
"dev": true
|
||||
},
|
||||
"psl": {
|
||||
"version": "1.1.31",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz",
|
||||
@ -1014,6 +1056,18 @@
|
||||
"integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
|
||||
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
||||
"dev": true
|
||||
},
|
||||
"sigmund": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
|
||||
"integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=",
|
||||
"dev": true
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
@ -1120,6 +1174,16 @@
|
||||
"integrity": "sha512-Y21Xqe54TBVp+VDSNbuDYdGw0BpoR/Q6wo/+35M8PAU0vipahnyduJWirxxdxjsAkS7hue53x2zp8gz7F05u0A==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript-formatter": {
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript-formatter/-/typescript-formatter-7.2.2.tgz",
|
||||
"integrity": "sha512-V7vfI9XArVhriOTYHPzMU2WUnm5IMdu9X/CPxs8mIMGxmTBFpDABlbkBka64PZJ9/xgQeRpK8KzzAG4MPzxBDQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commandpost": "^1.0.0",
|
||||
"editorconfig": "^0.15.0"
|
||||
}
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
|
||||
@ -1231,6 +1295,12 @@
|
||||
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-1.3.1.tgz",
|
||||
"integrity": "sha512-tGkGJkN8XqCod7OT+EvGYK5Z4SfDQGD30zAa58OcnAa0RRWgzUEK72tkXhsX1FZd+rgnhRxFtmO+ihkp8LHSkw==",
|
||||
"dev": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
||||
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1091,6 +1091,7 @@ export abstract class BasicZ80ScanlinePlatform extends BaseZ80Platform {
|
||||
timer;
|
||||
audio;
|
||||
psg;
|
||||
pixels : Uint32Array;
|
||||
inputs = new Uint8Array(16);
|
||||
mainElement : HTMLElement;
|
||||
|
||||
@ -1117,6 +1118,7 @@ export abstract class BasicZ80ScanlinePlatform extends BaseZ80Platform {
|
||||
this.cpu = this.newCPU(this.membus, this.iobus);
|
||||
this.video = new RasterVideo(this.mainElement, this.canvasWidth, this.numVisibleScanlines, this.getVideoOptions());
|
||||
this.video.create();
|
||||
this.pixels = this.video.getFrameData();
|
||||
setKeyboardFromMap(this.video, this.inputs, this.getKeyboardMap(), this.getKeyboardFunction());
|
||||
this.timer = new AnimationTimer(60, this.nextFrame.bind(this));
|
||||
}
|
||||
|
@ -1,200 +1,154 @@
|
||||
"use strict";
|
||||
|
||||
import { Platform, BaseZ80Platform } from "../baseplatform";
|
||||
import { Platform, BasicZ80ScanlinePlatform, BaseZ80Platform } from "../baseplatform";
|
||||
import { PLATFORMS, RAM, newAddressDecoder, padBytes, noise, setKeyboardFromMap, AnimationTimer, RasterVideo, Keys, makeKeycodeMap } from "../emu";
|
||||
import { hex } from "../util";
|
||||
|
||||
// http://www.computerarcheology.com/Arcade/
|
||||
|
||||
const MW8080BW_PRESETS = [
|
||||
{id:'gfxtest.c', name:'Graphics Test'},
|
||||
{id:'shifter.c', name:'Sprite w/ Bit Shifter'},
|
||||
{id:'game2.c', name:'Cosmic Impalas'},
|
||||
{ id: 'gfxtest.c', name: 'Graphics Test' },
|
||||
{ id: 'shifter.c', name: 'Sprite w/ Bit Shifter' },
|
||||
{ id: 'game2.c', name: 'Cosmic Impalas' },
|
||||
];
|
||||
|
||||
const _Midway8080BWPlatform = function(mainElement) {
|
||||
const 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],
|
||||
]);
|
||||
|
||||
var cpu, ram, membus, iobus, rom;
|
||||
var probe;
|
||||
var video, timer, pixels, displayPCs;
|
||||
var inputs = [0xe,0x8,0x0];
|
||||
var bitshift_offset = 0;
|
||||
var bitshift_register = 0;
|
||||
var watchdog_counter;
|
||||
const cpuFrequency = 1996800;
|
||||
const cpuCyclesPerLine = cpuFrequency/(60*224); // TODO
|
||||
const INITIAL_WATCHDOG = 256;
|
||||
const PIXEL_ON = 0xffeeeeee;
|
||||
const PIXEL_OFF = 0xff000000;
|
||||
const INITIAL_WATCHDOG = 256;
|
||||
const PIXEL_ON = 0xffeeeeee;
|
||||
const PIXEL_OFF = 0xff000000;
|
||||
|
||||
const 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],
|
||||
]);
|
||||
|
||||
class Midway8080BWPlatform extends BaseZ80Platform implements Platform {
|
||||
|
||||
getPresets() {
|
||||
return MW8080BW_PRESETS;
|
||||
}
|
||||
class Midway8080BWPlatform extends BasicZ80ScanlinePlatform implements Platform {
|
||||
cpuFrequency = 1996800; // MHz
|
||||
canvasWidth = 256;
|
||||
numTotalScanlines = 262;
|
||||
numVisibleScanlines = 224;
|
||||
defaultROMSize = 0x2000;
|
||||
|
||||
start = function() {
|
||||
ram = new RAM(0x2000);
|
||||
//displayPCs = new Uint16Array(new ArrayBuffer(0x2000*2));
|
||||
membus = {
|
||||
bitshift_offset = 0;
|
||||
bitshift_register = 0;
|
||||
watchdog_counter;
|
||||
|
||||
getPresets() { return MW8080BW_PRESETS; }
|
||||
getKeyboardMap() { return SPACEINV_KEYCODE_MAP; }
|
||||
getVideoOptions() { return { rotate: -90 }; }
|
||||
newRAM() { return new Uint8Array(0x2000); }
|
||||
|
||||
newMembus() {
|
||||
return {
|
||||
read: newAddressDecoder([
|
||||
[0x0000, 0x1fff, 0x1fff, function(a) { return rom ? rom[a] : 0; }],
|
||||
[0x2000, 0x3fff, 0x1fff, function(a) { return ram.mem[a]; }],
|
||||
]),
|
||||
write: newAddressDecoder([
|
||||
[0x2000, 0x23ff, 0x3ff, function(a,v) { ram.mem[a] = v; }],
|
||||
[0x2400, 0x3fff, 0x1fff, function(a,v) {
|
||||
ram.mem[a] = v;
|
||||
var ofs = (a - 0x400)<<3;
|
||||
for (var i=0; i<8; i++)
|
||||
pixels[ofs+i] = (v & (1<<i)) ? PIXEL_ON : PIXEL_OFF;
|
||||
if (displayPCs) displayPCs[a] = cpu.getPC(); // save program counter
|
||||
}],
|
||||
]),
|
||||
[0x0000, 0x1fff, 0x1fff, (a) => { return this.rom ? this.rom[a] : 0; }],
|
||||
[0x2000, 0x3fff, 0x1fff, (a) => { return this.ram[a]; }],
|
||||
]),
|
||||
write: newAddressDecoder([
|
||||
[0x2000, 0x23ff, 0x3ff, (a, v) => { this.ram[a] = v; }],
|
||||
[0x2400, 0x3fff, 0x1fff, (a, v) => {
|
||||
this.ram[a] = v;
|
||||
var ofs = (a - 0x400) << 3;
|
||||
for (var i = 0; i < 8; i++) {
|
||||
this.pixels[ofs + i] = (v & (1 << i)) ? PIXEL_ON : PIXEL_OFF;
|
||||
}
|
||||
//if (displayPCs) displayPCs[a] = cpu.getPC(); // save program counter
|
||||
}],
|
||||
]),
|
||||
isContended: function() { return false; },
|
||||
};
|
||||
iobus = {
|
||||
read: function(addr) {
|
||||
addr &= 0x3;
|
||||
}
|
||||
|
||||
newIOBus() {
|
||||
return {
|
||||
read: (addr) => {
|
||||
addr &= 0x3;
|
||||
//console.log('IO read', hex(addr,4));
|
||||
switch (addr) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
return inputs[addr];
|
||||
return this.inputs[addr];
|
||||
case 3:
|
||||
return (bitshift_register >> (8-bitshift_offset)) & 0xff;
|
||||
return (this.bitshift_register >> (8 - this.bitshift_offset)) & 0xff;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
write: function(addr, val) {
|
||||
addr &= 0x7;
|
||||
val &= 0xff;
|
||||
},
|
||||
write: (addr, val) => {
|
||||
addr &= 0x7;
|
||||
val &= 0xff;
|
||||
//console.log('IO write', hex(addr,4), hex(val,2));
|
||||
switch (addr) {
|
||||
case 2:
|
||||
bitshift_offset = val & 0x7;
|
||||
this.bitshift_offset = val & 0x7;
|
||||
break;
|
||||
case 3:
|
||||
case 5:
|
||||
// TODO: sound
|
||||
break;
|
||||
case 4:
|
||||
bitshift_register = (bitshift_register >> 8) | (val << 8);
|
||||
this.bitshift_register = (this.bitshift_register >> 8) | (val << 8);
|
||||
break;
|
||||
case 6:
|
||||
watchdog_counter = INITIAL_WATCHDOG;
|
||||
this.watchdog_counter = INITIAL_WATCHDOG;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
cpu = this.newCPU(membus, iobus);
|
||||
video = new RasterVideo(mainElement,256,224,{rotate:-90});
|
||||
video.create();
|
||||
}
|
||||
|
||||
startScanline(sl: number) {
|
||||
}
|
||||
|
||||
drawScanline(sl: number) {
|
||||
// at end of scanline
|
||||
if (sl == 95)
|
||||
this.cpu.requestInterrupt(0x8); // RST $8
|
||||
else if (sl == 223)
|
||||
this.cpu.requestInterrupt(0x10); // RST $10
|
||||
}
|
||||
|
||||
advance(novideo: boolean) {
|
||||
super.advance(novideo);
|
||||
if (this.watchdog_counter-- <= 0) {
|
||||
console.log("WATCHDOG FIRED"); // TODO: alert on video
|
||||
this.reset();
|
||||
}
|
||||
}
|
||||
|
||||
loadState(state) {
|
||||
super.loadState(state);
|
||||
this.bitshift_register = state.bsr;
|
||||
this.bitshift_offset = state.bso;
|
||||
this.watchdog_counter = state.wdc;
|
||||
}
|
||||
saveState() {
|
||||
var state: any = super.saveState();
|
||||
state.bsr = this.bitshift_register;
|
||||
state.bso = this.bitshift_offset;
|
||||
state.wdc = this.watchdog_counter;
|
||||
return state;
|
||||
}
|
||||
reset() {
|
||||
super.reset();
|
||||
this.watchdog_counter = INITIAL_WATCHDOG;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
$(video.canvas).click(function(e) {
|
||||
var x = Math.floor(e.offsetX * video.canvas.width / $(video.canvas).width());
|
||||
var y = Math.floor(e.offsetY * video.canvas.height / $(video.canvas).height());
|
||||
var addr = (x>>3) + (y*32) + 0x400;
|
||||
if (displayPCs) console.log(x, y, hex(addr,4), "PC", hex(displayPCs[addr],4));
|
||||
});
|
||||
var idata = video.getFrameData();
|
||||
setKeyboardFromMap(video, inputs, SPACEINV_KEYCODE_MAP);
|
||||
pixels = video.getFrameData();
|
||||
timer = new AnimationTimer(60, this.nextFrame.bind(this));
|
||||
}
|
||||
*/
|
||||
|
||||
readAddress(addr) {
|
||||
return membus.read(addr);
|
||||
}
|
||||
|
||||
advance(novideo : boolean) {
|
||||
for (var sl=0; sl<224; sl++) {
|
||||
this.runCPU(cpu, cpuCyclesPerLine);
|
||||
if (sl == 95)
|
||||
cpu.requestInterrupt(0x8); // RST $8
|
||||
else if (sl == 223)
|
||||
cpu.requestInterrupt(0x10); // RST $10
|
||||
}
|
||||
if (!novideo) {
|
||||
video.updateFrame();
|
||||
}
|
||||
if (watchdog_counter-- <= 0) {
|
||||
console.log("WATCHDOG FIRED"); // TODO: alert on video
|
||||
this.reset();
|
||||
}
|
||||
}
|
||||
|
||||
loadROM(title, data) {
|
||||
rom = padBytes(data, 0x2000);
|
||||
this.reset();
|
||||
}
|
||||
|
||||
loadState(state) {
|
||||
cpu.loadState(state.c);
|
||||
ram.mem.set(state.b);
|
||||
bitshift_register = state.bsr;
|
||||
bitshift_offset = state.bso;
|
||||
watchdog_counter = state.wdc;
|
||||
inputs[0] = state.in0;
|
||||
inputs[1] = state.in1;
|
||||
inputs[2] = state.in2;
|
||||
}
|
||||
saveState() {
|
||||
return {
|
||||
c:this.getCPUState(),
|
||||
b:ram.mem.slice(0),
|
||||
bsr:bitshift_register,
|
||||
bso:bitshift_offset,
|
||||
wdc:watchdog_counter,
|
||||
in0:inputs[0],
|
||||
in1:inputs[1],
|
||||
in2:inputs[2],
|
||||
};
|
||||
}
|
||||
loadControlsState(state) {
|
||||
inputs[0] = state.in0;
|
||||
inputs[1] = state.in1;
|
||||
inputs[2] = state.in2;
|
||||
}
|
||||
saveControlsState() {
|
||||
return {
|
||||
in0:inputs[0],
|
||||
in1:inputs[1],
|
||||
in2:inputs[2],
|
||||
};
|
||||
}
|
||||
getCPUState() {
|
||||
return cpu.saveState();
|
||||
}
|
||||
|
||||
isRunning() {
|
||||
return timer && timer.isRunning();
|
||||
}
|
||||
pause() {
|
||||
timer.stop();
|
||||
}
|
||||
resume() {
|
||||
timer.start();
|
||||
}
|
||||
reset() {
|
||||
cpu.reset();
|
||||
cpu.setTstates(0);
|
||||
watchdog_counter = INITIAL_WATCHDOG;
|
||||
}
|
||||
}
|
||||
return new Midway8080BWPlatform();
|
||||
}
|
||||
|
||||
PLATFORMS['mw8080bw'] = _Midway8080BWPlatform;
|
||||
PLATFORMS['mw8080bw'] = Midway8080BWPlatform;
|
||||
|
@ -1842,6 +1842,7 @@ export function startUI(loadplatform : boolean) {
|
||||
platform_id = qs['platform'] = "vcs";
|
||||
}
|
||||
$("#item_platform_"+platform_id).addClass("dropdown-item-checked");
|
||||
$("#platform_name").text(platform_id);
|
||||
setupSplits();
|
||||
// create store
|
||||
store_id = repo_id || getBasePlatform(platform_id);
|
||||
|
Loading…
Reference in New Issue
Block a user