8bitworkshop/gen/common/devices.js

195 lines
5.4 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BasicScanlineMachine = exports.BasicMachine = exports.BasicHeadlessMachine = exports.NullProbe = void 0;
class NullProbe {
logClocks() { }
logNewScanline() { }
logNewFrame() { }
logExecute() { }
logInterrupt() { }
logRead() { }
logWrite() { }
logIORead() { }
logIOWrite() { }
logVRAMRead() { }
logVRAMWrite() { }
logIllegal() { }
logWait() { }
logDMARead() { }
logDMAWrite() { }
logData() { }
addLogBuffer(src) { }
}
exports.NullProbe = NullProbe;
class BasicHeadlessMachine {
constructor() {
this.inputs = new Uint8Array(32);
this.nullProbe = new NullProbe();
this.probe = this.nullProbe;
}
setKeyInput(key, code, flags) {
this.handler && this.handler(key, code, flags);
}
connectProbe(probe) {
this.probe = probe || this.nullProbe;
}
reset() {
this.cpu.reset();
}
loadROM(data, title) {
if (!this.rom)
this.rom = new Uint8Array(this.defaultROMSize);
if (data.length > this.rom.length)
throw new Error(`ROM too big: ${data.length} > ${this.rom.length}}`);
this.rom.set(data);
}
loadState(state) {
this.cpu.loadState(state.c);
this.ram.set(state.ram);
this.inputs.set(state.inputs);
}
saveState() {
return {
c: this.cpu.saveState(),
ram: this.ram.slice(0),
inputs: this.inputs.slice(0),
};
}
loadControlsState(state) {
this.inputs.set(state.inputs);
}
saveControlsState() {
return {
inputs: this.inputs.slice(0)
};
}
advanceCPU() {
var c = this.cpu;
var n = 1;
if (this.cpu.isStable()) {
this.probe.logExecute(this.cpu.getPC(), this.cpu.getSP());
}
if (c.advanceClock) {
c.advanceClock();
}
else if (c.advanceInsn) {
n = c.advanceInsn(1);
}
this.probe.logClocks(n);
return n;
}
probeMemoryBus(membus) {
return {
read: (a) => {
let val = membus.read(a);
this.probe.logRead(a, val);
return val;
},
write: (a, v) => {
this.probe.logWrite(a, v);
membus.write(a, v);
},
read32: (a) => {
let val = membus.read32(a);
this.probe.logRead(a, val);
return val;
},
write32: (a, v) => {
this.probe.logWrite(a, v);
membus.write32(a, v);
}
};
}
connectCPUMemoryBus(membus) {
this.cpu.connectMemoryBus(this.probeMemoryBus(membus));
}
probeIOBus(iobus) {
return {
read: (a) => {
let val = iobus.read(a);
this.probe.logIORead(a, val);
return val;
},
write: (a, v) => {
this.probe.logIOWrite(a, v);
iobus.write(a, v);
},
};
}
probeDMABus(iobus) {
return {
read: (a) => {
let val = iobus.read(a);
this.probe.logDMARead(a, val);
return val;
},
write: (a, v) => {
this.probe.logDMAWrite(a, v);
iobus.write(a, v);
}
};
}
connectCPUIOBus(iobus) {
this.cpu['connectIOBus'](this.probeIOBus(iobus));
}
}
exports.BasicHeadlessMachine = BasicHeadlessMachine;
class BasicMachine extends BasicHeadlessMachine {
constructor() {
super(...arguments);
this.overscan = false;
this.rotate = 0;
}
getAudioParams() {
return { sampleRate: this.sampleRate, stereo: false };
}
connectAudio(audio) {
this.audio = audio;
}
getVideoParams() {
return {
width: this.canvasWidth,
height: this.numVisibleScanlines,
aspect: this.aspectRatio,
overscan: this.overscan,
rotate: this.rotate
};
}
connectVideo(pixels) {
this.pixels = pixels;
}
}
exports.BasicMachine = BasicMachine;
class BasicScanlineMachine extends BasicMachine {
advanceFrame(trap) {
this.preFrame();
var endLineClock = 0;
var steps = 0;
this.probe.logNewFrame();
this.frameCycles = 0;
for (var sl = 0; sl < this.numTotalScanlines; sl++) {
endLineClock += this.cpuCyclesPerLine; // could be fractional
this.scanline = sl;
this.startScanline();
while (this.frameCycles < endLineClock) {
if (trap && trap()) {
sl = 999;
break;
}
this.frameCycles += this.advanceCPU();
steps++;
}
this.drawScanline();
this.probe.logNewScanline();
this.probe.logClocks(Math.floor(this.frameCycles - endLineClock)); // remainder of prev. line
}
this.postFrame();
return steps; // TODO: return steps, not clock? for recorder
}
preFrame() { }
postFrame() { }
getRasterY() { return this.scanline; }
getRasterX() { return this.frameCycles % this.cpuCyclesPerLine; }
}
exports.BasicScanlineMachine = BasicScanlineMachine;
//# sourceMappingURL=devices.js.map