mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-02-16 17:30:27 +00:00
testing out sub-frame replay slider, advanceFrameClock, fixed c64 memory corrupt
This commit is contained in:
parent
921d2b2253
commit
002aa41bad
20
index.html
20
index.html
@ -288,14 +288,24 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||||||
</div>
|
</div>
|
||||||
<div class="emulator disable-select" id="emulator">
|
<div class="emulator disable-select" id="emulator">
|
||||||
<!-- replay slider -->
|
<!-- replay slider -->
|
||||||
<div id="replaydiv" class="replaydiv" style="display:none">
|
<div id="replaydiv" class="replaydiv" style="display:none;color:#ccc;text-align:left">
|
||||||
<div style="display:flex">
|
<div style="display:flex; grid-gap:1em">
|
||||||
<button id="replay_min" class="btn" title="Start of replay"><span class="glyphicon glyphicon-fast-backward" aria-hidden="true"></span></button>
|
|
||||||
<button id="replay_back" class="btn" title="Back one frame"><span class="glyphicon glyphicon-backward" aria-hidden="true"></span></button>
|
<button id="replay_back" class="btn" title="Back one frame"><span class="glyphicon glyphicon-backward" aria-hidden="true"></span></button>
|
||||||
<span id="replay_frame" style="text-align:center;width:3em;margin-left:1em;color:#ccc">-</span>
|
<div>
|
||||||
|
Frame<br>
|
||||||
|
<span id="replay_frame" style="width:3em">-</span>
|
||||||
|
</div>
|
||||||
<input type="range" min="0" max="0" value="0" class="slider" id="replayslider">
|
<input type="range" min="0" max="0" value="0" class="slider" id="replayslider">
|
||||||
<button id="replay_fwd" class="btn" title="Ahead one frame"><span class="glyphicon glyphicon-forward" aria-hidden="true"></span></button>
|
<button id="replay_fwd" class="btn" title="Ahead one frame"><span class="glyphicon glyphicon-forward" aria-hidden="true"></span></button>
|
||||||
<button id="replay_max" class="btn" title="End of replay"><span class="glyphicon glyphicon-fast-forward" aria-hidden="true"></span></button>
|
</div>
|
||||||
|
<div style="display:flex; grid-gap:1em" id="clockdiv">
|
||||||
|
<button id="clock_back" class="btn" title="Back one step"><span class="glyphicon glyphicon-backward" aria-hidden="true"></span></button>
|
||||||
|
<div>
|
||||||
|
Step<br>
|
||||||
|
<span id="replay_clock" style="width:3em">-</span>
|
||||||
|
</div>
|
||||||
|
<input type="range" min="0" max="0" value="0" class="slider" id="clockslider">
|
||||||
|
<button id="clock_fwd" class="btn" title="Forward one step"><span class="glyphicon glyphicon-forward" aria-hidden="true"></span></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- emulator video -->
|
<!-- emulator video -->
|
||||||
|
@ -112,7 +112,8 @@ export interface Platform {
|
|||||||
getMemoryMap?() : MemoryMap;
|
getMemoryMap?() : MemoryMap;
|
||||||
|
|
||||||
setRecorder?(recorder : EmuRecorder) : void;
|
setRecorder?(recorder : EmuRecorder) : void;
|
||||||
advance?(novideo? : boolean) : void;
|
advance?(novideo? : boolean) : number;
|
||||||
|
advanceFrameClock?(trap:DebugCondition, step:number) : number;
|
||||||
showHelp?(tool:string, ident?:string) : void;
|
showHelp?(tool:string, ident?:string) : void;
|
||||||
resize?() : void;
|
resize?() : void;
|
||||||
|
|
||||||
@ -179,7 +180,7 @@ export abstract class BasePlatform {
|
|||||||
abstract saveState() : EmuState;
|
abstract saveState() : EmuState;
|
||||||
abstract pause() : void;
|
abstract pause() : void;
|
||||||
abstract resume() : void;
|
abstract resume() : void;
|
||||||
abstract advance(novideo? : boolean) : void;
|
abstract advance(novideo? : boolean) : number;
|
||||||
|
|
||||||
setRecorder(recorder : EmuRecorder) : void {
|
setRecorder(recorder : EmuRecorder) : void {
|
||||||
this.recorder = recorder;
|
this.recorder = recorder;
|
||||||
@ -267,8 +268,9 @@ export abstract class BaseDebugPlatform extends BasePlatform {
|
|||||||
this.pollControls();
|
this.pollControls();
|
||||||
this.updateRecorder();
|
this.updateRecorder();
|
||||||
this.preFrame();
|
this.preFrame();
|
||||||
this.advance(novideo);
|
var steps = this.advance(novideo);
|
||||||
this.postFrame();
|
this.postFrame();
|
||||||
|
return steps;
|
||||||
}
|
}
|
||||||
// default debugging
|
// default debugging
|
||||||
abstract getSP() : number;
|
abstract getSP() : number;
|
||||||
@ -1058,8 +1060,20 @@ export abstract class BaseMachinePlatform<T extends Machine> extends BaseDebugPl
|
|||||||
}
|
}
|
||||||
|
|
||||||
advance(novideo:boolean) {
|
advance(novideo:boolean) {
|
||||||
this.machine.advanceFrame(this.getDebugCallback());
|
var steps = this.machine.advanceFrame(this.getDebugCallback());
|
||||||
if (!novideo && this.video) this.video.updateFrame();
|
if (!novideo && this.video) this.video.updateFrame();
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
|
||||||
|
advanceFrameClock(trap, step) {
|
||||||
|
if (!(step > 0)) return;
|
||||||
|
if (this.machine instanceof BaseWASMMachine) {
|
||||||
|
return this.machine.advanceFrameClock(trap, step);
|
||||||
|
} else {
|
||||||
|
return this.machine.advanceFrame(() => {
|
||||||
|
return --step <= 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isRunning() {
|
isRunning() {
|
||||||
@ -1164,6 +1178,8 @@ export abstract class BaseWASMMachine {
|
|||||||
statearr : Uint8Array;
|
statearr : Uint8Array;
|
||||||
cpustateptr : number;
|
cpustateptr : number;
|
||||||
cpustatearr : Uint8Array;
|
cpustatearr : Uint8Array;
|
||||||
|
ctrlstateptr : number;
|
||||||
|
ctrlstatearr : Uint8Array;
|
||||||
cpu : CPU;
|
cpu : CPU;
|
||||||
romptr : number;
|
romptr : number;
|
||||||
romlen : number;
|
romlen : number;
|
||||||
@ -1215,6 +1231,9 @@ export abstract class BaseWASMMachine {
|
|||||||
var statesize = this.exports.machine_get_state_size();
|
var statesize = this.exports.machine_get_state_size();
|
||||||
this.stateptr = this.exports.malloc(statesize);
|
this.stateptr = this.exports.malloc(statesize);
|
||||||
this.statearr = new Uint8Array(this.exports.memory.buffer, this.stateptr, statesize);
|
this.statearr = new Uint8Array(this.exports.memory.buffer, this.stateptr, statesize);
|
||||||
|
var ctrlstatesize = this.exports.machine_get_controls_state_size();
|
||||||
|
this.ctrlstateptr = this.exports.malloc(ctrlstatesize);
|
||||||
|
this.ctrlstatearr = new Uint8Array(this.exports.memory.buffer, this.ctrlstateptr, ctrlstatesize);
|
||||||
var cpustatesize = this.exports.machine_get_cpu_state_size();
|
var cpustatesize = this.exports.machine_get_cpu_state_size();
|
||||||
this.cpustateptr = this.exports.malloc(cpustatesize);
|
this.cpustateptr = this.exports.malloc(cpustatesize);
|
||||||
this.cpustatearr = new Uint8Array(this.exports.memory.buffer, this.cpustateptr, cpustatesize);
|
this.cpustatearr = new Uint8Array(this.exports.memory.buffer, this.cpustateptr, cpustatesize);
|
||||||
@ -1271,12 +1290,14 @@ export abstract class BaseWASMMachine {
|
|||||||
}
|
}
|
||||||
// assume controls buffer is smaller than cpu buffer
|
// assume controls buffer is smaller than cpu buffer
|
||||||
saveControlsState() : any {
|
saveControlsState() : any {
|
||||||
this.exports.machine_save_controls_state(this.sys, this.cpustateptr);
|
//console.log(1, this.romptr, this.romlen, this.ctrlstateptr, this.romarr.slice(0,4), this.ctrlstatearr.slice(0,4));
|
||||||
return { controls:this.cpustatearr.slice(0, this.exports.machine_get_controls_state_size()) }
|
this.exports.machine_save_controls_state(this.sys, this.ctrlstateptr);
|
||||||
|
//console.log(2, this.romptr, this.romlen, this.ctrlstateptr, this.romarr.slice(0,4), this.ctrlstatearr.slice(0,4));
|
||||||
|
return { controls:this.ctrlstatearr.slice(0) }
|
||||||
}
|
}
|
||||||
loadControlsState(state) : void {
|
loadControlsState(state) : void {
|
||||||
this.cpustatearr.set(state.controls);
|
this.ctrlstatearr.set(state.controls);
|
||||||
this.exports.machine_load_controls_state(this.sys, this.cpustateptr);
|
this.exports.machine_load_controls_state(this.sys, this.ctrlstateptr);
|
||||||
}
|
}
|
||||||
connectAudio(audio : SampledAudioSink) : void {
|
connectAudio(audio : SampledAudioSink) : void {
|
||||||
this.audio = audio;
|
this.audio = audio;
|
||||||
|
@ -308,6 +308,7 @@ export abstract class BasicScanlineMachine extends BasicMachine implements Raste
|
|||||||
this.preFrame();
|
this.preFrame();
|
||||||
var clock = 0;
|
var clock = 0;
|
||||||
var endLineClock = 0;
|
var endLineClock = 0;
|
||||||
|
var steps = 0;
|
||||||
this.probe.logNewFrame();
|
this.probe.logNewFrame();
|
||||||
for (var sl=0; sl<this.numTotalScanlines; sl++) {
|
for (var sl=0; sl<this.numTotalScanlines; sl++) {
|
||||||
endLineClock += this.cpuCyclesPerLine;
|
endLineClock += this.cpuCyclesPerLine;
|
||||||
@ -320,13 +321,14 @@ export abstract class BasicScanlineMachine extends BasicMachine implements Raste
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
clock += this.advanceCPU();
|
clock += this.advanceCPU();
|
||||||
|
steps++;
|
||||||
}
|
}
|
||||||
this.drawScanline();
|
this.drawScanline();
|
||||||
this.probe.logNewScanline();
|
this.probe.logNewScanline();
|
||||||
this.probe.logClocks(clock-endLineClock);
|
this.probe.logClocks(clock-endLineClock);
|
||||||
}
|
}
|
||||||
this.postFrame();
|
this.postFrame();
|
||||||
return clock;
|
return steps; // TODO: return steps, not clock? for recorder
|
||||||
}
|
}
|
||||||
preFrame() { }
|
preFrame() { }
|
||||||
postFrame() { }
|
postFrame() { }
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
import { Platform, BasePlatform, EmuState, EmuControlsState, EmuRecorder } from "./baseplatform";
|
import { Platform, EmuState, EmuControlsState, EmuRecorder } from "./baseplatform";
|
||||||
import { BaseDebugPlatform } from "./baseplatform";
|
|
||||||
import { getNoiseSeed, setNoiseSeed } from "./emu";
|
import { getNoiseSeed, setNoiseSeed } from "./emu";
|
||||||
|
|
||||||
// RECORDER
|
// RECORDER
|
||||||
@ -8,16 +7,19 @@ import { getNoiseSeed, setNoiseSeed } from "./emu";
|
|||||||
type FrameRec = {controls:EmuControlsState, seed:number};
|
type FrameRec = {controls:EmuControlsState, seed:number};
|
||||||
|
|
||||||
export class StateRecorderImpl implements EmuRecorder {
|
export class StateRecorderImpl implements EmuRecorder {
|
||||||
checkpointInterval : number = 60;
|
|
||||||
|
checkpointInterval : number = 10;
|
||||||
callbackStateChanged : () => void;
|
callbackStateChanged : () => void;
|
||||||
callbackNewCheckpoint : (state:EmuState) => void;
|
callbackNewCheckpoint : (state:EmuState) => void;
|
||||||
maxCheckpoints : number = 120;
|
maxCheckpoints : number = 300;
|
||||||
|
|
||||||
platform : Platform;
|
platform : Platform;
|
||||||
checkpoints : EmuState[];
|
checkpoints : EmuState[];
|
||||||
framerecs : FrameRec[];
|
framerecs : FrameRec[];
|
||||||
frameCount : number;
|
frameCount : number;
|
||||||
lastSeekFrame : number;
|
lastSeekFrame : number;
|
||||||
|
lastSeekStep : number;
|
||||||
|
lastStepCount : number;
|
||||||
|
|
||||||
constructor(platform : Platform) {
|
constructor(platform : Platform) {
|
||||||
this.reset();
|
this.reset();
|
||||||
@ -29,6 +31,7 @@ export class StateRecorderImpl implements EmuRecorder {
|
|||||||
this.framerecs = [];
|
this.framerecs = [];
|
||||||
this.frameCount = 0;
|
this.frameCount = 0;
|
||||||
this.lastSeekFrame = 0;
|
this.lastSeekFrame = 0;
|
||||||
|
this.lastSeekStep = 0;
|
||||||
if (this.callbackStateChanged) this.callbackStateChanged();
|
if (this.callbackStateChanged) this.callbackStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,6 +53,7 @@ export class StateRecorderImpl implements EmuRecorder {
|
|||||||
requested = (this.frameCount++ % this.checkpointInterval) == 0;
|
requested = (this.frameCount++ % this.checkpointInterval) == 0;
|
||||||
}
|
}
|
||||||
this.lastSeekFrame++;
|
this.lastSeekFrame++;
|
||||||
|
this.lastSeekStep = 0;
|
||||||
if (this.callbackStateChanged) this.callbackStateChanged();
|
if (this.callbackStateChanged) this.callbackStateChanged();
|
||||||
return requested;
|
return requested;
|
||||||
}
|
}
|
||||||
@ -62,6 +66,10 @@ export class StateRecorderImpl implements EmuRecorder {
|
|||||||
return this.lastSeekFrame;
|
return this.lastSeekFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentStep() : number {
|
||||||
|
return this.lastSeekStep;
|
||||||
|
}
|
||||||
|
|
||||||
recordFrame(state : EmuState) {
|
recordFrame(state : EmuState) {
|
||||||
this.checkpoints.push(state);
|
this.checkpoints.push(state);
|
||||||
if (this.callbackNewCheckpoint) this.callbackNewCheckpoint(state);
|
if (this.callbackNewCheckpoint) this.callbackNewCheckpoint(state);
|
||||||
@ -82,22 +90,35 @@ export class StateRecorderImpl implements EmuRecorder {
|
|||||||
return {frame:foundframe, state:this.checkpoints[foundidx]};
|
return {frame:foundframe, state:this.checkpoints[foundidx]};
|
||||||
}
|
}
|
||||||
|
|
||||||
loadFrame(seekframe : number) : number {
|
loadFrame(seekframe : number, seekstep? : number) : number {
|
||||||
if (seekframe == this.lastSeekFrame)
|
seekframe |= 0;
|
||||||
|
seekstep |= 0;
|
||||||
|
if (seekframe == this.lastSeekFrame && seekstep == this.lastSeekStep) {
|
||||||
return seekframe; // already set to this frame
|
return seekframe; // already set to this frame
|
||||||
|
}
|
||||||
// TODO: what if < 1?
|
// TODO: what if < 1?
|
||||||
let {frame,state} = this.getStateAtOrBefore(seekframe-1);
|
let {frame,state} = this.getStateAtOrBefore(seekframe-1);
|
||||||
if (state) {
|
if (state) {
|
||||||
|
var numSteps = 0;
|
||||||
this.platform.pause();
|
this.platform.pause();
|
||||||
this.platform.loadState(state);
|
this.platform.loadState(state);
|
||||||
|
// seek to frame index
|
||||||
while (frame < seekframe) {
|
while (frame < seekframe) {
|
||||||
if (frame < this.framerecs.length) {
|
if (frame < this.framerecs.length) {
|
||||||
this.loadControls(frame);
|
this.loadControls(frame);
|
||||||
}
|
}
|
||||||
frame++;
|
frame++;
|
||||||
this.platform.advance(frame < seekframe); // TODO: infinite loop?
|
numSteps = this.platform.advance(frame < seekframe); // TODO: infinite loop?
|
||||||
}
|
}
|
||||||
|
// seek to step index
|
||||||
|
// TODO: what if advance() returns clocks, but steps use insns?
|
||||||
|
if (seekstep > 0 && this.platform.advanceFrameClock) {
|
||||||
|
seekstep = this.platform.advanceFrameClock(null, seekstep);
|
||||||
|
}
|
||||||
|
// record new values
|
||||||
this.lastSeekFrame = seekframe;
|
this.lastSeekFrame = seekframe;
|
||||||
|
this.lastSeekStep = seekstep;
|
||||||
|
this.lastStepCount = numSteps;
|
||||||
return seekframe;
|
return seekframe;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1261,6 +1261,7 @@ function clearBreakpoint() {
|
|||||||
|
|
||||||
function resetAndDebug() {
|
function resetAndDebug() {
|
||||||
if (!checkRunReady()) return;
|
if (!checkRunReady()) return;
|
||||||
|
var wasRecording = recorderActive;
|
||||||
_disableRecording();
|
_disableRecording();
|
||||||
if (platform.setupDebug && platform.readAddress) { // TODO??
|
if (platform.setupDebug && platform.readAddress) { // TODO??
|
||||||
clearBreakpoint();
|
clearBreakpoint();
|
||||||
@ -1274,6 +1275,7 @@ function resetAndDebug() {
|
|||||||
} else {
|
} else {
|
||||||
platform.reset();
|
platform.reset();
|
||||||
}
|
}
|
||||||
|
if (wasRecording) _enableRecording();
|
||||||
}
|
}
|
||||||
|
|
||||||
function _breakExpression() {
|
function _breakExpression() {
|
||||||
@ -1610,41 +1612,59 @@ function setupDebugControls() {
|
|||||||
|
|
||||||
function setupReplaySlider() {
|
function setupReplaySlider() {
|
||||||
var replayslider = $("#replayslider");
|
var replayslider = $("#replayslider");
|
||||||
|
var clockslider = $("#clockslider");
|
||||||
var replayframeno = $("#replay_frame");
|
var replayframeno = $("#replay_frame");
|
||||||
var updateFrameNo = (n) => {
|
var clockno = $("#replay_clock");
|
||||||
replayframeno.text(n+"");
|
if (!platform.advanceFrameClock) $("#clockdiv").hide(); // TODO: put this test in recorder?
|
||||||
|
var updateFrameNo = () => {
|
||||||
|
replayframeno.text(stateRecorder.lastSeekFrame+"");
|
||||||
|
clockno.text(stateRecorder.lastSeekStep+"");
|
||||||
};
|
};
|
||||||
var sliderChanged = (e) => {
|
var sliderChanged = (e) => {
|
||||||
_pause();
|
_pause();
|
||||||
var frame = (<any>e.target).value;
|
var frame : number = parseInt(replayslider.val().toString());
|
||||||
if (stateRecorder.loadFrame(frame)) {
|
var step : number = parseInt(clockslider.val().toString());
|
||||||
updateFrameNo(frame);
|
if (stateRecorder.loadFrame(frame, step)) {
|
||||||
projectWindows.tick();
|
clockslider.attr('min', 0);
|
||||||
showDebugInfo(platform.saveState());
|
clockslider.attr('max', stateRecorder.lastStepCount);
|
||||||
|
updateFrameNo();
|
||||||
|
uiDebugCallback(platform.saveState());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var setFrameTo = (frame:number) => {
|
var setFrameTo = (frame:number) => {
|
||||||
_pause();
|
_pause();
|
||||||
if (stateRecorder.loadFrame(frame)) {
|
if (stateRecorder.loadFrame(frame)) {
|
||||||
replayslider.val(frame);
|
replayslider.val(frame);
|
||||||
updateFrameNo(frame);
|
updateFrameNo();
|
||||||
projectWindows.tick();
|
uiDebugCallback(platform.saveState());
|
||||||
showDebugInfo(platform.saveState());
|
}
|
||||||
|
};
|
||||||
|
var setClockTo = (clock:number) => {
|
||||||
|
_pause();
|
||||||
|
var frame : number = parseInt(replayslider.val().toString());
|
||||||
|
if (stateRecorder.loadFrame(frame, clock)) {
|
||||||
|
clockslider.val(clock);
|
||||||
|
updateFrameNo();
|
||||||
|
uiDebugCallback(platform.saveState());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
stateRecorder.callbackStateChanged = () => {
|
stateRecorder.callbackStateChanged = () => {
|
||||||
replayslider.attr('min', 1);
|
replayslider.attr('min', 1);
|
||||||
replayslider.attr('max', stateRecorder.numFrames());
|
replayslider.attr('max', stateRecorder.numFrames());
|
||||||
replayslider.val(stateRecorder.currentFrame());
|
replayslider.val(stateRecorder.currentFrame());
|
||||||
updateFrameNo(stateRecorder.currentFrame());
|
clockslider.val(stateRecorder.currentStep());
|
||||||
|
updateFrameNo();
|
||||||
showDebugInfo(platform.saveState());
|
showDebugInfo(platform.saveState());
|
||||||
};
|
};
|
||||||
replayslider.on('input', sliderChanged);
|
replayslider.on('input', sliderChanged);
|
||||||
replayslider.on('change', sliderChanged);
|
clockslider.on('input', sliderChanged);
|
||||||
|
//replayslider.on('change', sliderChanged);
|
||||||
$("#replay_min").click(() => { setFrameTo(1) });
|
$("#replay_min").click(() => { setFrameTo(1) });
|
||||||
$("#replay_max").click(() => { setFrameTo(stateRecorder.numFrames()); });
|
$("#replay_max").click(() => { setFrameTo(stateRecorder.numFrames()); });
|
||||||
$("#replay_back").click(() => { setFrameTo(parseInt(replayslider.val().toString()) - 1); });
|
$("#replay_back").click(() => { setFrameTo(parseInt(replayslider.val().toString()) - 1); });
|
||||||
$("#replay_fwd").click(() => { setFrameTo(parseInt(replayslider.val().toString()) + 1); });
|
$("#replay_fwd").click(() => { setFrameTo(parseInt(replayslider.val().toString()) + 1); });
|
||||||
|
$("#clock_back").click(() => { setClockTo(parseInt(clockslider.val().toString()) - 1); });
|
||||||
|
$("#clock_fwd").click(() => { setClockTo(parseInt(clockslider.val().toString()) + 1); });
|
||||||
$("#replay_bar").show();
|
$("#replay_bar").show();
|
||||||
uitoolbar.add('ctrl+alt+0', 'Start/Stop Replay Recording', 'glyphicon-record', _toggleRecording).prop('id','dbg_record');
|
uitoolbar.add('ctrl+alt+0', 'Start/Stop Replay Recording', 'glyphicon-record', _toggleRecording).prop('id','dbg_record');
|
||||||
}
|
}
|
||||||
|
@ -394,6 +394,7 @@ export class Atari7800 extends BasicMachine implements RasterFrameBased {
|
|||||||
var rgb;
|
var rgb;
|
||||||
var mc = 0;
|
var mc = 0;
|
||||||
var fc = 0;
|
var fc = 0;
|
||||||
|
var steps = 0;
|
||||||
this.probe.logNewFrame();
|
this.probe.logNewFrame();
|
||||||
//console.log(hex(this.cpu.getPC()), hex(this.maria.dll));
|
//console.log(hex(this.cpu.getPC()), hex(this.maria.dll));
|
||||||
// visible lines
|
// visible lines
|
||||||
@ -411,6 +412,7 @@ export class Atari7800 extends BasicMachine implements RasterFrameBased {
|
|||||||
break; // TODO?
|
break; // TODO?
|
||||||
}
|
}
|
||||||
mc += this.advanceCPU() << 2;
|
mc += this.advanceCPU() << 2;
|
||||||
|
steps++;
|
||||||
}
|
}
|
||||||
// is this scanline visible?
|
// is this scanline visible?
|
||||||
if (visible) {
|
if (visible) {
|
||||||
@ -443,6 +445,7 @@ export class Atari7800 extends BasicMachine implements RasterFrameBased {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mc += this.advanceCPU() << 2;
|
mc += this.advanceCPU() << 2;
|
||||||
|
steps++;
|
||||||
}
|
}
|
||||||
// audio
|
// audio
|
||||||
this.audio && this.audioadapter.generate(this.audio);
|
this.audio && this.audioadapter.generate(this.audio);
|
||||||
@ -455,7 +458,8 @@ export class Atari7800 extends BasicMachine implements RasterFrameBased {
|
|||||||
// TODO let bkcol = this.maria.regs[0x0];
|
// TODO let bkcol = this.maria.regs[0x0];
|
||||||
// TODO $(this.video.canvas).css('background-color', COLORS_WEB[bkcol]);
|
// TODO $(this.video.canvas).css('background-color', COLORS_WEB[bkcol]);
|
||||||
*/
|
*/
|
||||||
return (this.lastFrameCycles = fc);
|
this.lastFrameCycles = fc;
|
||||||
|
return steps;
|
||||||
}
|
}
|
||||||
|
|
||||||
getRasterX() { return this.lastFrameCycles % colorClocksPerLine; }
|
getRasterX() { return this.lastFrameCycles % colorClocksPerLine; }
|
||||||
|
@ -40,6 +40,9 @@ class BallyAstrocadePlatform extends BaseZ80MachinePlatform<BallyAstrocade> impl
|
|||||||
{name:'Screen RAM',start:0x4000,size:0x1000,type:'ram'},
|
{name:'Screen RAM',start:0x4000,size:0x1000,type:'ram'},
|
||||||
{name:'BIOS Variables',start:0x4fce,size:0x5000-0x4fce,type:'ram'},
|
{name:'BIOS Variables',start:0x4fce,size:0x5000-0x4fce,type:'ram'},
|
||||||
] } };
|
] } };
|
||||||
|
showHelp(tool:string, ident:string) {
|
||||||
|
window.open("https://8bitworkshop.com/blog/platforms/astrocade/", "_help"); // TODO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BallyAstrocadeBIOSPlatform extends BallyAstrocadePlatform implements Platform {
|
class BallyAstrocadeBIOSPlatform extends BallyAstrocadePlatform implements Platform {
|
||||||
|
@ -489,12 +489,13 @@ const _Atari8Platform = function(mainElement) {
|
|||||||
jacanvas.mousedown(rasterPosBreakFn);
|
jacanvas.mousedown(rasterPosBreakFn);
|
||||||
}
|
}
|
||||||
|
|
||||||
advance(novideo : boolean) {
|
advance(novideo : boolean) : number {
|
||||||
var idata = video.getFrameData();
|
var idata = video.getFrameData();
|
||||||
var iofs = 0;
|
var iofs = 0;
|
||||||
var debugCond = this.getDebugCallback();
|
var debugCond = this.getDebugCallback();
|
||||||
var rgb;
|
var rgb;
|
||||||
var freeClocks = 0;
|
var freeClocks = 0;
|
||||||
|
var totalClocks = 0;
|
||||||
// load controls
|
// load controls
|
||||||
// TODO
|
// TODO
|
||||||
gtia.regs[0x10] = inputs[0] ^ 1;
|
gtia.regs[0x10] = inputs[0] ^ 1;
|
||||||
@ -518,6 +519,7 @@ const _Atari8Platform = function(mainElement) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cpu.clockPulse();
|
cpu.clockPulse();
|
||||||
|
totalClocks++;
|
||||||
}
|
}
|
||||||
// 4 ANTIC pulses = 8 pixels
|
// 4 ANTIC pulses = 8 pixels
|
||||||
if (antic.v >= 24 && antic.h >= 44 && antic.h < 44+176) { // TODO: const
|
if (antic.v >= 24 && antic.h >= 44 && antic.h < 44+176) { // TODO: const
|
||||||
@ -535,6 +537,7 @@ const _Atari8Platform = function(mainElement) {
|
|||||||
let bkcol = gtia.regs[COLBK];
|
let bkcol = gtia.regs[COLBK];
|
||||||
$(video.canvas).css('background-color', COLORS_WEB[bkcol]);
|
$(video.canvas).css('background-color', COLORS_WEB[bkcol]);
|
||||||
}
|
}
|
||||||
|
return totalClocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadROM(title, data) {
|
loadROM(title, data) {
|
||||||
|
@ -318,13 +318,14 @@ const _GalaxianPlatform = function(mainElement, options) {
|
|||||||
return (a == 0x7000 || a == 0x7800) ? null : membus.read(a); // ignore watchdog
|
return (a == 0x7000 || a == 0x7800) ? null : membus.read(a); // ignore watchdog
|
||||||
}
|
}
|
||||||
|
|
||||||
advance(novideo: boolean) {
|
advance(novideo: boolean) : number {
|
||||||
|
var steps = 0;
|
||||||
for (var sl = 0; sl < scanlinesPerFrame; sl++) {
|
for (var sl = 0; sl < scanlinesPerFrame; sl++) {
|
||||||
this.scanline = sl;
|
this.scanline = sl;
|
||||||
if (!novideo) {
|
if (!novideo) {
|
||||||
gfx.drawScanline(pixels, sl);
|
gfx.drawScanline(pixels, sl);
|
||||||
}
|
}
|
||||||
this.runCPU(cpu, cpuCyclesPerLine);
|
steps += this.runCPU(cpu, cpuCyclesPerLine);
|
||||||
}
|
}
|
||||||
// visible area is 256x224 (before rotation)
|
// visible area is 256x224 (before rotation)
|
||||||
if (!novideo) {
|
if (!novideo) {
|
||||||
@ -337,6 +338,7 @@ const _GalaxianPlatform = function(mainElement, options) {
|
|||||||
}
|
}
|
||||||
// NMI interrupt @ 0x66
|
// NMI interrupt @ 0x66
|
||||||
if (interruptEnabled) { cpu.NMI(); }
|
if (interruptEnabled) { cpu.NMI(); }
|
||||||
|
return steps;
|
||||||
}
|
}
|
||||||
|
|
||||||
getRasterScanline() { return this.scanline; }
|
getRasterScanline() { return this.scanline; }
|
||||||
|
@ -156,8 +156,9 @@ class JSNESPlatform extends Base6502Platform implements Platform, Probeable {
|
|||||||
|
|
||||||
pollControls() { this.poller.poll(); }
|
pollControls() { this.poller.poll(); }
|
||||||
|
|
||||||
advance(novideo : boolean) {
|
advance(novideo : boolean) : number {
|
||||||
this.nes.frame();
|
this.nes.frame();
|
||||||
|
return 29780; //TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDebugViews() {
|
updateDebugViews() {
|
||||||
@ -479,7 +480,7 @@ class JSNESPlatform extends Base6502Platform implements Platform, Probeable {
|
|||||||
] } };
|
] } };
|
||||||
|
|
||||||
showHelp(tool:string, ident:string) {
|
showHelp(tool:string, ident:string) {
|
||||||
window.open("https://8bitworkshop.com/blog/platforms/nintendo-nes.md.html", "_help"); // TODO
|
window.open("https://8bitworkshop.com/blog/platforms/nes/", "_help"); // TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,8 +135,9 @@ class VCSPlatform extends BasePlatform {
|
|||||||
Javatari.room.speaker.powerOff();
|
Javatari.room.speaker.powerOff();
|
||||||
Javatari.room.speaker.powerOn();
|
Javatari.room.speaker.powerOn();
|
||||||
}
|
}
|
||||||
advance() {
|
advance() : number {
|
||||||
Javatari.room.console.clockPulse();
|
Javatari.room.console.clockPulse();
|
||||||
|
return 0; //TODO
|
||||||
}
|
}
|
||||||
// for unit test
|
// for unit test
|
||||||
nextFrame() {
|
nextFrame() {
|
||||||
@ -303,7 +304,7 @@ class VCSPlatform extends BasePlatform {
|
|||||||
if (tool == 'bataribasic')
|
if (tool == 'bataribasic')
|
||||||
window.open("help/bataribasic/manual.html", "_help");
|
window.open("help/bataribasic/manual.html", "_help");
|
||||||
else
|
else
|
||||||
window.open("https://8bitworkshop.com/blog/platforms/atari-2600-vcs.md.html", "_help"); // TODO
|
window.open("https://8bitworkshop.com/blog/platforms/vcs/", "_help"); // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
getMemoryMap = function() { return {main:[
|
getMemoryMap = function() { return {main:[
|
||||||
|
@ -838,14 +838,16 @@ class VectrexPlatform extends Base6809Platform {
|
|||||||
this.psg.psg.register[14] = ~this.inputs[2];
|
this.psg.psg.register[14] = ~this.inputs[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
advance(novideo:boolean) {
|
advance(novideo:boolean) : number {
|
||||||
if (!novideo) this.video.clear();
|
if (!novideo) this.video.clear();
|
||||||
this.updateControls();
|
this.updateControls();
|
||||||
this.probe.logNewFrame();
|
this.probe.logNewFrame();
|
||||||
var cycles = 1500000 / 60;
|
var frameCycles = 1500000 / 60;
|
||||||
while (cycles > 0) {
|
var cycles = 0;
|
||||||
cycles -= this.step();
|
while (cycles < frameCycles) {
|
||||||
|
cycles += this.step();
|
||||||
}
|
}
|
||||||
|
return cycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
step() {
|
step() {
|
||||||
|
@ -460,13 +460,14 @@ var VerilogPlatform = function(mainElement, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: merge with prev func
|
// TODO: merge with prev func
|
||||||
advance(novideo : boolean) {
|
advance(novideo : boolean) : number {
|
||||||
this.setGenInputs();
|
this.setGenInputs();
|
||||||
this.updateVideoFrameCycles(cyclesPerFrame, true, false);
|
this.updateVideoFrameCycles(cyclesPerFrame, true, false);
|
||||||
gen.__unreset();
|
gen.__unreset();
|
||||||
if (!novideo) {
|
if (!novideo) {
|
||||||
this.refreshVideoFrame();
|
this.refreshVideoFrame();
|
||||||
}
|
}
|
||||||
|
return cyclesPerFrame; //TODO?
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshVideoFrame() {
|
refreshVideoFrame() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user