mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-06-28 03:29:35 +00:00
replay slider for some platforms; fixed williams audio
This commit is contained in:
parent
2b41164b66
commit
b386d2e87a
12
css/ui.css
12
css/ui.css
|
@ -122,6 +122,9 @@ div.mem_info a.selected {
|
||||||
.btn_stopped {
|
.btn_stopped {
|
||||||
color: #ff9933;
|
color: #ff9933;
|
||||||
}
|
}
|
||||||
|
.btn_recording {
|
||||||
|
color: #ff3333;
|
||||||
|
}
|
||||||
.seg_code { color: #ff9966; }
|
.seg_code { color: #ff9966; }
|
||||||
.seg_data { color: #66ff66; }
|
.seg_data { color: #66ff66; }
|
||||||
.seg_stack { color: #ffff66; }
|
.seg_stack { color: #ffff66; }
|
||||||
|
@ -285,3 +288,12 @@ canvas.pixelated {
|
||||||
content: '\2713';
|
content: '\2713';
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
div.replaydiv {
|
||||||
|
position:absolute;
|
||||||
|
padding:20px;
|
||||||
|
left:50%;
|
||||||
|
bottom:0;
|
||||||
|
width:50%;
|
||||||
|
background-color: #666;
|
||||||
|
margin-top: 20px auto 0;
|
||||||
|
}
|
||||||
|
|
|
@ -138,6 +138,9 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
||||||
<button id="dbg_profile" type="submit" title="Show Profile" style="display:none"><span class="glyphicon glyphicon-stats" aria-hidden="true"></span></button>
|
<button id="dbg_profile" type="submit" title="Show Profile" style="display:none"><span class="glyphicon glyphicon-stats" aria-hidden="true"></span></button>
|
||||||
<button id="dbg_bitmap" type="submit" title="Edit Bitmap"><span class="glyphicon glyphicon-camera" aria-hidden="true"></span></button>
|
<button id="dbg_bitmap" type="submit" title="Edit Bitmap"><span class="glyphicon glyphicon-camera" aria-hidden="true"></span></button>
|
||||||
</span>
|
</span>
|
||||||
|
<span class="btn_group view_group" id="replay_bar" style="display:none">
|
||||||
|
<button id="dbg_record" type="submit" title="Toggle Replay Buffer"><span class="glyphicon glyphicon-record" aria-hidden="true"></span></button>
|
||||||
|
</span>
|
||||||
<span class="dropdown" style="float:right">
|
<span class="dropdown" style="float:right">
|
||||||
<a class="btn btn-secondary dropdown-toggle" id="booksMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<a class="btn btn-secondary dropdown-toggle" id="booksMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
GET BOOKS <span class="caret"></span>
|
GET BOOKS <span class="caret"></span>
|
||||||
|
@ -174,6 +177,9 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
||||||
</div>
|
</div>
|
||||||
<div id="mem_info" class="mem_info" style="display:none">
|
<div id="mem_info" class="mem_info" style="display:none">
|
||||||
</div>
|
</div>
|
||||||
|
<div id="replaydiv" class="replaydiv" style="display:none">
|
||||||
|
<input type="range" min="0" max="0" value="0" class="slider" id="replayslider">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--
|
<!--
|
||||||
<div class="twitbtn">
|
<div class="twitbtn">
|
||||||
|
@ -273,6 +279,7 @@ function require(modname) {
|
||||||
<script src="gen/project.js"></script>
|
<script src="gen/project.js"></script>
|
||||||
<script src="gen/windows.js"></script>
|
<script src="gen/windows.js"></script>
|
||||||
<script src="gen/views.js"></script>
|
<script src="gen/views.js"></script>
|
||||||
|
<script src="gen/recorder.js"></script>
|
||||||
<script src="gen/ui.js"></script>
|
<script src="gen/ui.js"></script>
|
||||||
<!-- <script src="src/audio/votrax.js"></script> -->
|
<!-- <script src="src/audio/votrax.js"></script> -->
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,12 @@
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
var window = {};
|
var window = {};
|
||||||
|
var exports = {};
|
||||||
|
function require(modname) {
|
||||||
|
if (modname == 'jquery') return $;
|
||||||
|
else if (modname.startsWith('.')) return exports;
|
||||||
|
else { console.log("Unknown require()", modname); return exports; }
|
||||||
|
}
|
||||||
|
|
||||||
importScripts("../../gen/emu.js");
|
importScripts("../../gen/emu.js");
|
||||||
importScripts("../cpu/z80.js");
|
importScripts("../cpu/z80.js");
|
||||||
|
|
|
@ -12,15 +12,15 @@ export interface OpcodeMetadata {
|
||||||
opcode: number;
|
opcode: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CpuState {
|
export interface CpuState {
|
||||||
PC:number, T?:number, o?:number,/*opcode*/
|
PC:number, T?:number, o?:number,/*opcode*/
|
||||||
SP?:number
|
SP?:number
|
||||||
/*
|
/*
|
||||||
A:number, X:number, Y:number, SP:number, R:boolean,
|
A:number, X:number, Y:number, SP:number, R:boolean,
|
||||||
N,V,D,Z,C:boolean*/
|
N,V,D,Z,C:boolean*/
|
||||||
};
|
};
|
||||||
interface EmuState {c:CpuState, b?:number[]};
|
export interface EmuState {c:CpuState, b?:number[]};
|
||||||
type DisasmLine = {line:string, nbytes:number};
|
export type DisasmLine = {line:string, nbytes:number};
|
||||||
|
|
||||||
export interface Platform {
|
export interface Platform {
|
||||||
start() : void;
|
start() : void;
|
||||||
|
@ -57,6 +57,9 @@ export interface Platform {
|
||||||
|
|
||||||
getDebugCategories() : string[];
|
getDebugCategories() : string[];
|
||||||
getDebugInfo(category:string, state:EmuState) : string;
|
getDebugInfo(category:string, state:EmuState) : string;
|
||||||
|
|
||||||
|
setRecorder?(recorder : EmuRecorder) : void;
|
||||||
|
advance?(novideo? : boolean) : void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Preset {
|
export interface Preset {
|
||||||
|
@ -75,6 +78,11 @@ type DebugCondition = () => boolean;
|
||||||
type DebugEvalCondition = (c:CpuState) => boolean;
|
type DebugEvalCondition = (c:CpuState) => boolean;
|
||||||
type BreakpointCallback = (EmuState) => void;
|
type BreakpointCallback = (EmuState) => void;
|
||||||
|
|
||||||
|
export interface EmuRecorder {
|
||||||
|
frameRequested() : boolean;
|
||||||
|
recordFrame(platform : Platform, state : EmuState);
|
||||||
|
}
|
||||||
|
|
||||||
/////
|
/////
|
||||||
|
|
||||||
abstract class BaseDebugPlatform {
|
abstract class BaseDebugPlatform {
|
||||||
|
@ -84,6 +92,7 @@ abstract class BaseDebugPlatform {
|
||||||
debugBreakState : EmuState = null;
|
debugBreakState : EmuState = null;
|
||||||
debugTargetClock : number = 0;
|
debugTargetClock : number = 0;
|
||||||
debugClock : number = 0;
|
debugClock : number = 0;
|
||||||
|
recorder : EmuRecorder = null;
|
||||||
|
|
||||||
abstract getCPUState() : CpuState;
|
abstract getCPUState() : CpuState;
|
||||||
abstract saveState() : EmuState;
|
abstract saveState() : EmuState;
|
||||||
|
@ -117,6 +126,15 @@ abstract class BaseDebugPlatform {
|
||||||
this.debugBreakState = null;
|
this.debugBreakState = null;
|
||||||
this.resume();
|
this.resume();
|
||||||
}
|
}
|
||||||
|
setRecorder?(recorder : EmuRecorder) : void {
|
||||||
|
this.recorder = recorder;
|
||||||
|
}
|
||||||
|
updateRecorder() {
|
||||||
|
// are we recording and do we need to save a frame?
|
||||||
|
if (this.recorder && (<Platform><any>this).isRunning() && this.recorder.frameRequested()) {
|
||||||
|
this.recorder.recordFrame(<Platform><any>this, this.saveState());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class BaseFrameBasedPlatform extends BaseDebugPlatform {
|
abstract class BaseFrameBasedPlatform extends BaseDebugPlatform {
|
||||||
|
@ -128,11 +146,14 @@ abstract class BaseFrameBasedPlatform extends BaseDebugPlatform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
restartDebugState() {
|
restartDebugState() {
|
||||||
if (this.debugCondition && !this.debugBreakState) {
|
// save state every frame and rewind debug clocks
|
||||||
|
var debugging = this.debugCondition && !this.debugBreakState;
|
||||||
|
if (debugging) {
|
||||||
this.debugSavedState = this.saveState();
|
this.debugSavedState = this.saveState();
|
||||||
this.debugTargetClock -= this.debugClock;
|
this.debugTargetClock -= this.debugClock;
|
||||||
this.debugClock = 0;
|
this.debugClock = 0;
|
||||||
}
|
}
|
||||||
|
this.updateRecorder();
|
||||||
}
|
}
|
||||||
breakpointHit(targetClock : number) {
|
breakpointHit(targetClock : number) {
|
||||||
this.debugTargetClock = targetClock;
|
this.debugTargetClock = targetClock;
|
||||||
|
@ -389,6 +410,7 @@ export abstract class BaseZ80Platform extends BaseDebugPlatform {
|
||||||
this.debugSavedState.c.T = 0;
|
this.debugSavedState.c.T = 0;
|
||||||
this.loadState(this.debugSavedState);
|
this.loadState(this.debugSavedState);
|
||||||
}
|
}
|
||||||
|
this.updateRecorder();
|
||||||
}
|
}
|
||||||
breakpointHit(targetClock : number) {
|
breakpointHit(targetClock : number) {
|
||||||
this.debugTargetClock = targetClock;
|
this.debugTargetClock = targetClock;
|
||||||
|
|
|
@ -48,6 +48,7 @@ var Apple2Platform = function(mainElement) {
|
||||||
// value to add when reading & writing each of these banks
|
// value to add when reading & writing each of these banks
|
||||||
// bank 1 is E000-FFFF, bank 2 is D000-DFFF
|
// bank 1 is E000-FFFF, bank 2 is D000-DFFF
|
||||||
var bank2rdoffset=0, bank2wroffset=0;
|
var bank2rdoffset=0, bank2wroffset=0;
|
||||||
|
var grparams;
|
||||||
|
|
||||||
this.getPresets = function() {
|
this.getPresets = function() {
|
||||||
return APPLE2_PRESETS;
|
return APPLE2_PRESETS;
|
||||||
|
@ -177,37 +178,40 @@ var Apple2Platform = function(mainElement) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var idata = video.getFrameData();
|
var idata = video.getFrameData();
|
||||||
var grparams = {dirty:grdirty, grswitch:grswitch, mem:ram.mem};
|
grparams = {dirty:grdirty, grswitch:grswitch, mem:ram.mem};
|
||||||
ap2disp = new Apple2Display(idata, grparams);
|
ap2disp = new Apple2Display(idata, grparams);
|
||||||
var colors = [0xffff0000, 0xff00ff00];
|
timer = new AnimationTimer(60, this.advance.bind(this));
|
||||||
timer = new AnimationTimer(60, function() {
|
}
|
||||||
// 262.5 scanlines per frame
|
|
||||||
var clock = 0;
|
this.advance = function(novideo : boolean) {
|
||||||
var debugCond = self.getDebugCallback();
|
// 262.5 scanlines per frame
|
||||||
var rendered = false;
|
var clock = 0;
|
||||||
for (var sl=0; sl<262; sl++) {
|
var debugCond = this.getDebugCallback();
|
||||||
for (var i=0; i<cpuCyclesPerLine; i++) {
|
var rendered = false;
|
||||||
if (debugCond && debugCond()) {
|
for (var sl=0; sl<262; sl++) {
|
||||||
grparams.dirty = grdirty;
|
for (var i=0; i<cpuCyclesPerLine; i++) {
|
||||||
grparams.grswitch = grswitch;
|
if (debugCond && debugCond()) {
|
||||||
ap2disp.updateScreen();
|
grparams.dirty = grdirty;
|
||||||
debugCond = null;
|
grparams.grswitch = grswitch;
|
||||||
rendered = true;
|
ap2disp.updateScreen();
|
||||||
}
|
debugCond = null;
|
||||||
clock++;
|
rendered = true;
|
||||||
cpu.clockPulse();
|
|
||||||
audio.feedSample(soundstate, 1);
|
|
||||||
}
|
}
|
||||||
|
clock++;
|
||||||
|
cpu.clockPulse();
|
||||||
|
audio.feedSample(soundstate, 1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (!novideo) {
|
||||||
if (!rendered) {
|
if (!rendered) {
|
||||||
grparams.dirty = grdirty;
|
grparams.dirty = grdirty;
|
||||||
grparams.grswitch = grswitch;
|
grparams.grswitch = grswitch;
|
||||||
ap2disp.updateScreen();
|
ap2disp.updateScreen();
|
||||||
}
|
}
|
||||||
video.updateFrame();
|
video.updateFrame();
|
||||||
soundstate = 0; // to prevent clicking
|
}
|
||||||
self.restartDebugState(); // reset debug start state
|
//soundstate = 0; // to prevent clicking
|
||||||
});
|
this.restartDebugState(); // reset debug start state
|
||||||
}
|
}
|
||||||
|
|
||||||
function doLanguageCardIO(address, value)
|
function doLanguageCardIO(address, value)
|
||||||
|
|
|
@ -294,35 +294,36 @@ var GalaxianPlatform = function(mainElement, options) {
|
||||||
var idata = video.getFrameData();
|
var idata = video.getFrameData();
|
||||||
setKeyboardFromMap(video, inputs, keyMap);
|
setKeyboardFromMap(video, inputs, keyMap);
|
||||||
pixels = video.getFrameData();
|
pixels = video.getFrameData();
|
||||||
timer = new AnimationTimer(60, function() {
|
timer = new AnimationTimer(60, this.advance.bind(this));
|
||||||
if (!self.isRunning())
|
}
|
||||||
return;
|
|
||||||
var debugCond = self.getDebugCallback();
|
this.advance = function(novideo : boolean) {
|
||||||
var targetTstates = cpu.getTstates();
|
var debugCond = this.getDebugCallback();
|
||||||
// TODO: get raster position
|
var targetTstates = cpu.getTstates();
|
||||||
for (var sl=0; sl<scanlinesPerFrame; sl++) {
|
for (var sl=0; sl<scanlinesPerFrame; sl++) {
|
||||||
drawScanline(pixels, sl);
|
if (!novideo) {
|
||||||
targetTstates += cpuCyclesPerLine;
|
drawScanline(pixels, sl);
|
||||||
if (debugCond) {
|
}
|
||||||
while (cpu.getTstates() < targetTstates) {
|
targetTstates += cpuCyclesPerLine;
|
||||||
if (debugCond && debugCond()) { debugCond = null; }
|
if (debugCond) {
|
||||||
cpu.runFrame(cpu.getTstates() + 1);
|
while (cpu.getTstates() < targetTstates) {
|
||||||
}
|
if (debugCond && debugCond()) { debugCond = null; }
|
||||||
} else {
|
cpu.runFrame(cpu.getTstates() + 1);
|
||||||
cpu.runFrame(targetTstates);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
cpu.runFrame(targetTstates);
|
||||||
}
|
}
|
||||||
// visible area is 256x224 (before rotation)
|
}
|
||||||
video.updateFrame(0, 0, 0, 0, showOffscreenObjects ? 264 : 256, 264);
|
// visible area is 256x224 (before rotation)
|
||||||
frameCounter = (frameCounter + 1) & 0xff;
|
video.updateFrame(0, 0, 0, 0, showOffscreenObjects ? 264 : 256, 264);
|
||||||
if (watchdog_counter-- <= 0) {
|
frameCounter = (frameCounter + 1) & 0xff;
|
||||||
console.log("WATCHDOG FIRED, PC ", hex(cpu.getPC())); // TODO: alert on video
|
if (watchdog_counter-- <= 0) {
|
||||||
self.reset();
|
console.log("WATCHDOG FIRED, PC ", hex(cpu.getPC())); // TODO: alert on video
|
||||||
}
|
this.reset();
|
||||||
self.restartDebugState();
|
}
|
||||||
// NMI interrupt @ 0x66
|
// NMI interrupt @ 0x66
|
||||||
if (interruptEnabled) { cpu.nonMaskableInterrupt(); }
|
if (interruptEnabled) { cpu.nonMaskableInterrupt(); }
|
||||||
});
|
this.restartDebugState(); // TODO: after interrupt?
|
||||||
}
|
}
|
||||||
|
|
||||||
var bitcolors = [
|
var bitcolors = [
|
||||||
|
@ -397,7 +398,6 @@ var GalaxianPlatform = function(mainElement, options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var GalaxianScramblePlatform = function(mainElement) {
|
var GalaxianScramblePlatform = function(mainElement) {
|
||||||
var self = this;
|
|
||||||
this.__proto__ = new GalaxianPlatform(mainElement, {
|
this.__proto__ = new GalaxianPlatform(mainElement, {
|
||||||
romSize: 0x5020,
|
romSize: 0x5020,
|
||||||
gfxBase: 0x4000,
|
gfxBase: 0x4000,
|
||||||
|
|
|
@ -113,38 +113,40 @@ var Midway8080BWPlatform = function(mainElement) {
|
||||||
var idata = video.getFrameData();
|
var idata = video.getFrameData();
|
||||||
setKeyboardFromMap(video, inputs, SPACEINV_KEYCODE_MAP);
|
setKeyboardFromMap(video, inputs, SPACEINV_KEYCODE_MAP);
|
||||||
pixels = video.getFrameData();
|
pixels = video.getFrameData();
|
||||||
timer = new AnimationTimer(60, function() {
|
timer = new AnimationTimer(60, this.advance.bind(this));
|
||||||
if (!self.isRunning())
|
}
|
||||||
return;
|
|
||||||
var debugCond = self.getDebugCallback();
|
this.advance = function(novideo : boolean) {
|
||||||
var targetTstates = cpu.getTstates();
|
var debugCond = this.getDebugCallback();
|
||||||
for (var sl=0; sl<224; sl++) {
|
var targetTstates = cpu.getTstates();
|
||||||
targetTstates += cpuCyclesPerLine;
|
for (var sl=0; sl<224; sl++) {
|
||||||
if (debugCond) {
|
targetTstates += cpuCyclesPerLine;
|
||||||
while (cpu.getTstates() < targetTstates) {
|
if (debugCond) {
|
||||||
if (debugCond && debugCond()) {
|
while (cpu.getTstates() < targetTstates) {
|
||||||
debugCond = null;
|
if (debugCond && debugCond()) {
|
||||||
break;
|
debugCond = null;
|
||||||
}
|
|
||||||
cpu.runFrame(cpu.getTstates() + 1);
|
|
||||||
}
|
|
||||||
if (!debugCond)
|
|
||||||
break;
|
break;
|
||||||
} else {
|
}
|
||||||
cpu.runFrame(targetTstates);
|
cpu.runFrame(cpu.getTstates() + 1);
|
||||||
}
|
}
|
||||||
if (sl == 95)
|
if (!debugCond)
|
||||||
cpu.requestInterrupt(0x8); // RST $8
|
break;
|
||||||
else if (sl == 223)
|
} else {
|
||||||
cpu.requestInterrupt(0x10); // RST $10
|
cpu.runFrame(targetTstates);
|
||||||
}
|
}
|
||||||
|
if (sl == 95)
|
||||||
|
cpu.requestInterrupt(0x8); // RST $8
|
||||||
|
else if (sl == 223)
|
||||||
|
cpu.requestInterrupt(0x10); // RST $10
|
||||||
|
}
|
||||||
|
if (!novideo) {
|
||||||
video.updateFrame();
|
video.updateFrame();
|
||||||
if (watchdog_counter-- <= 0) {
|
}
|
||||||
console.log("WATCHDOG FIRED"); // TODO: alert on video
|
if (watchdog_counter-- <= 0) {
|
||||||
self.reset();
|
console.log("WATCHDOG FIRED"); // TODO: alert on video
|
||||||
}
|
this.reset();
|
||||||
self.restartDebugState();
|
}
|
||||||
});
|
this.restartDebugState();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadROM = function(title, data) {
|
this.loadROM = function(title, data) {
|
||||||
|
|
|
@ -127,6 +127,10 @@ var JSNESPlatform = function(mainElement) {
|
||||||
nes.buttonUp(o.index+1, o.mask); // controller, button
|
nes.buttonUp(o.index+1, o.mask); // controller, button
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.advance = function(novideo : boolean) {
|
||||||
|
nes.frame();
|
||||||
|
}
|
||||||
|
|
||||||
this.loadROM = function(title, data) {
|
this.loadROM = function(title, data) {
|
||||||
var romstr = String.fromCharCode.apply(null, data);
|
var romstr = String.fromCharCode.apply(null, data);
|
||||||
|
|
|
@ -142,23 +142,24 @@ var VicDualPlatform = function(mainElement) {
|
||||||
reset_disable_timer = setTimeout(function() { reset_disable = false; }, 1100);
|
reset_disable_timer = setTimeout(function() { reset_disable = false; }, 1100);
|
||||||
});
|
});
|
||||||
pixels = video.getFrameData();
|
pixels = video.getFrameData();
|
||||||
timer = new AnimationTimer(60, function() {
|
timer = new AnimationTimer(60, this.advance.bind(this));
|
||||||
if (!self.isRunning())
|
}
|
||||||
return;
|
|
||||||
var debugCond = self.getDebugCallback();
|
this.advance = function(novideo : boolean) {
|
||||||
var targetTstates = cpu.getTstates();
|
var targetTstates = cpu.getTstates();
|
||||||
for (var sl=0; sl<scanlinesPerFrame; sl++) {
|
for (var sl=0; sl<scanlinesPerFrame; sl++) {
|
||||||
inputs[2] &= ~0x8;
|
inputs[2] &= ~0x8;
|
||||||
inputs[2] |= ((cpu.getTstates() / cyclesPerTimerTick) & 1) << 3;
|
inputs[2] |= ((cpu.getTstates() / cyclesPerTimerTick) & 1) << 3;
|
||||||
drawScanline(pixels, sl);
|
if (!novideo) {
|
||||||
targetTstates += cpuCyclesPerLine;
|
drawScanline(pixels, sl);
|
||||||
if (sl == vblankStart) inputs[1] |= 0x8;
|
|
||||||
if (sl == vsyncEnd) inputs[1] &= ~0x8;
|
|
||||||
self.runCPU(cpu, targetTstates - cpu.getTstates());
|
|
||||||
}
|
}
|
||||||
video.updateFrame();
|
targetTstates += cpuCyclesPerLine;
|
||||||
self.restartDebugState();
|
if (sl == vblankStart) inputs[1] |= 0x8;
|
||||||
});
|
if (sl == vsyncEnd) inputs[1] &= ~0x8;
|
||||||
|
this.runCPU(cpu, targetTstates - cpu.getTstates());
|
||||||
|
}
|
||||||
|
video.updateFrame();
|
||||||
|
this.restartDebugState();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadROM = function(title, data) {
|
this.loadROM = function(title, data) {
|
||||||
|
|
|
@ -306,38 +306,38 @@ var WilliamsPlatform = function(mainElement, proto) {
|
||||||
var idata = video.getFrameData();
|
var idata = video.getFrameData();
|
||||||
setKeyboardFromMap(video, pia6821, ROBOTRON_KEYCODE_MAP);
|
setKeyboardFromMap(video, pia6821, ROBOTRON_KEYCODE_MAP);
|
||||||
pixels = video.getFrameData();
|
pixels = video.getFrameData();
|
||||||
timer = new AnimationTimer(60, function() {
|
timer = new AnimationTimer(60, this.advance.bind(this));
|
||||||
if (!self.isRunning())
|
}
|
||||||
return;
|
|
||||||
var cpuCyclesPerSection = Math.round(cpuCyclesPerFrame / 65);
|
this.advance = function(novideo:boolean) {
|
||||||
for (var sl=0; sl<256; sl+=4) {
|
var cpuCyclesPerSection = Math.round(cpuCyclesPerFrame / 65);
|
||||||
video_counter = sl;
|
for (var sl=0; sl<256; sl+=4) {
|
||||||
// interrupts happen every 1/4 of the screen
|
video_counter = sl;
|
||||||
if (sl == 0 || sl == 0x3c || sl == 0xbc || sl == 0xfc) {
|
// interrupts happen every 1/4 of the screen
|
||||||
if (membus.read != memread_defender || pia6821[7] == 0x3c) { // TODO?
|
if (sl == 0 || sl == 0x3c || sl == 0xbc || sl == 0xfc) {
|
||||||
if (cpu.interrupt)
|
if (membus.read != memread_defender || pia6821[7] == 0x3c) { // TODO?
|
||||||
cpu.interrupt();
|
if (cpu.interrupt)
|
||||||
if (cpu.requestInterrupt)
|
cpu.interrupt();
|
||||||
cpu.requestInterrupt();
|
if (cpu.requestInterrupt)
|
||||||
}
|
cpu.requestInterrupt();
|
||||||
}
|
}
|
||||||
self.runCPU(cpu, cpuCyclesPerSection);
|
|
||||||
if (sl < 256) video.updateFrame(0, 0, 256-4-sl, 0, 4, 304);
|
|
||||||
}
|
}
|
||||||
// last 6 lines
|
this.runCPU(cpu, cpuCyclesPerSection);
|
||||||
self.runCPU(cpu, cpuCyclesPerSection*2);
|
if (sl < 256) video.updateFrame(0, 0, 256-4-sl, 0, 4, 304);
|
||||||
if (screenNeedsRefresh) {
|
}
|
||||||
for (var i=0; i<0x9800; i++)
|
// last 6 lines
|
||||||
drawDisplayByte(i, ram.mem[i]);
|
this.runCPU(cpu, cpuCyclesPerSection*2);
|
||||||
screenNeedsRefresh = false;
|
if (screenNeedsRefresh && !novideo) {
|
||||||
}
|
for (var i=0; i<0x9800; i++)
|
||||||
if (watchdog_counter-- <= 0) {
|
drawDisplayByte(i, ram.mem[i]);
|
||||||
console.log("WATCHDOG FIRED, PC =", cpu.getPC().toString(16)); // TODO: alert on video
|
screenNeedsRefresh = false;
|
||||||
// TODO: self.breakpointHit(cpu.T());
|
}
|
||||||
self.reset();
|
if (watchdog_counter-- <= 0) {
|
||||||
}
|
console.log("WATCHDOG FIRED, PC =", cpu.getPC().toString(16)); // TODO: alert on video
|
||||||
self.restartDebugState();
|
// TODO: this.breakpointHit(cpu.T());
|
||||||
});
|
this.reset();
|
||||||
|
}
|
||||||
|
this.restartDebugState();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadSoundROM = function(data) {
|
this.loadSoundROM = function(data) {
|
||||||
|
|
46
src/ui.ts
46
src/ui.ts
|
@ -12,6 +12,7 @@ import { PLATFORMS } from "./emu";
|
||||||
import * as Views from "./views";
|
import * as Views from "./views";
|
||||||
import { createNewPersistentStore } from "./store";
|
import { createNewPersistentStore } from "./store";
|
||||||
import { getFilenameForPath, getFilenamePrefix, highlightDifferences, invertMap } from "./util";
|
import { getFilenameForPath, getFilenamePrefix, highlightDifferences, invertMap } from "./util";
|
||||||
|
import { StateRecorderImpl } from "./recorder";
|
||||||
|
|
||||||
// external libs (TODO)
|
// external libs (TODO)
|
||||||
declare var Octokat, ga, Tour, GIF, saveAs;
|
declare var Octokat, ga, Tour, GIF, saveAs;
|
||||||
|
@ -29,6 +30,7 @@ var current_project : CodeProject; // current CodeProject object
|
||||||
|
|
||||||
var projectWindows : ProjectWindows; // window manager
|
var projectWindows : ProjectWindows; // window manager
|
||||||
|
|
||||||
|
var stateRecorder : StateRecorderImpl = new StateRecorderImpl();
|
||||||
|
|
||||||
// TODO: codemirror multiplex support?
|
// TODO: codemirror multiplex support?
|
||||||
var TOOL_TO_SOURCE_STYLE = {
|
var TOOL_TO_SOURCE_STYLE = {
|
||||||
|
@ -460,6 +462,7 @@ function setDebugButtonState(btnid:string, btnstate:string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupBreakpoint(btnid? : string) {
|
function setupBreakpoint(btnid? : string) {
|
||||||
|
_disableRecording();
|
||||||
platform.setupDebug(function(state) {
|
platform.setupDebug(function(state) {
|
||||||
lastDebugState = state;
|
lastDebugState = state;
|
||||||
showDebugInfo(state);
|
showDebugInfo(state);
|
||||||
|
@ -541,6 +544,7 @@ function runStepBackwards() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearBreakpoint() {
|
function clearBreakpoint() {
|
||||||
|
_disableRecording();
|
||||||
lastDebugState = null;
|
lastDebugState = null;
|
||||||
if (platform.clearDebug) platform.clearDebug();
|
if (platform.clearDebug) platform.clearDebug();
|
||||||
showDebugInfo();
|
showDebugInfo();
|
||||||
|
@ -679,6 +683,33 @@ function traceTiming() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var recorderActive = false;
|
||||||
|
|
||||||
|
function _disableRecording() {
|
||||||
|
if (recorderActive) {
|
||||||
|
platform.setRecorder(null);
|
||||||
|
$("#dbg_record").removeClass("btn_recording");
|
||||||
|
$("#replaydiv").hide();
|
||||||
|
recorderActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _enableRecording() {
|
||||||
|
stateRecorder.reset();
|
||||||
|
platform.setRecorder(stateRecorder);
|
||||||
|
$("#dbg_record").addClass("btn_recording");
|
||||||
|
$("#replaydiv").show();
|
||||||
|
recorderActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _toggleRecording() {
|
||||||
|
if (recorderActive) {
|
||||||
|
_disableRecording();
|
||||||
|
} else {
|
||||||
|
_enableRecording();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function setupDebugControls(){
|
function setupDebugControls(){
|
||||||
$("#dbg_reset").click(resetAndDebug);
|
$("#dbg_reset").click(resetAndDebug);
|
||||||
$("#dbg_pause").click(pause);
|
$("#dbg_pause").click(pause);
|
||||||
|
@ -730,6 +761,21 @@ function setupDebugControls(){
|
||||||
$("#dbg_fastest").click(_fastestFrameRate);
|
$("#dbg_fastest").click(_fastestFrameRate);
|
||||||
}
|
}
|
||||||
updateDebugWindows();
|
updateDebugWindows();
|
||||||
|
// setup replay slider
|
||||||
|
if (platform.advance) {
|
||||||
|
$("#dbg_record").click(_toggleRecording);
|
||||||
|
var replayslider = $("#replayslider");
|
||||||
|
stateRecorder.callbackStateChanged = () => {
|
||||||
|
replayslider.attr('min', 0);
|
||||||
|
replayslider.attr('max', stateRecorder.numFrames()-1);
|
||||||
|
replayslider.attr('value', stateRecorder.numFrames()-1); // TODO: doesn't always move
|
||||||
|
};
|
||||||
|
replayslider.on('input', function(e) {
|
||||||
|
_pause();
|
||||||
|
stateRecorder.loadFrame(platform, (<any>e.target).value);
|
||||||
|
});
|
||||||
|
$("#replay_bar").show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showWelcomeMessage() {
|
function showWelcomeMessage() {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user