diff --git a/src/baseplatform.ts b/src/baseplatform.ts index 0fbc3e44..8309eed8 100644 --- a/src/baseplatform.ts +++ b/src/baseplatform.ts @@ -1197,10 +1197,11 @@ export abstract class BasicZ80ScanlinePlatform extends BaseZ80Platform { /// new style -import { Bus, Resettable, FrameBased, VideoSource, SampledAudioSource, AcceptsROM, AcceptsInput, SavesState, HasCPU } from "./devices"; +import { Bus, Resettable, FrameBased, VideoSource, SampledAudioSource, AcceptsROM, AcceptsKeyInput, SavesState, SavesInputState, HasCPU } from "./devices"; +import { CPUClockHook, LogCPU, RasterFrameBased } from "./devices"; import { SampledAudio } from "./audio"; -interface Machine extends Bus, Resettable, FrameBased, AcceptsROM, HasCPU, SavesState { +interface Machine extends Bus, Resettable, FrameBased, AcceptsROM, HasCPU, SavesState, SavesInputState { } function hasVideo(arg:any): arg is VideoSource { @@ -1209,8 +1210,11 @@ function hasVideo(arg:any): arg is VideoSource { function hasAudio(arg:any): arg is SampledAudioSource { return typeof arg.connectAudio === 'function'; } -function hasInput(arg:any): arg is AcceptsInput { - return typeof arg.setInput === 'function'; +function hasKeyInput(arg:any): arg is AcceptsKeyInput { + return typeof arg.setKeyInput === 'function'; +} +function isRaster(arg:any): arg is RasterFrameBased { + return typeof arg.getRasterY === 'function'; } export abstract class BaseMachinePlatform extends BaseDebugPlatform implements Platform { @@ -1238,15 +1242,15 @@ export abstract class BaseMachinePlatform extends BaseDebugPl getSP() { return this.machine.cpu.getSP(); } getPC() { return this.machine.cpu.getPC(); } getCPUState() { return this.machine.cpu.saveState(); } - loadControlsState(s) { if (hasInput(this.machine)) this.machine.loadControlsState(s); } - saveControlsState() { return hasInput(this.machine) && this.machine.saveControlsState(); } + loadControlsState(s) { this.machine.loadControlsState(s); } + saveControlsState() { return this.machine.saveControlsState(); } start() { var m = this.machine; this.timer = new AnimationTimer(60, this.nextFrame.bind(this)); if (hasVideo(m)) { var vp = m.getVideoParams(); - this.video = new RasterVideo(this.mainElement, vp.width, vp.height); + this.video = new RasterVideo(this.mainElement, vp.width, vp.height, {overscan:vp.overscan}); this.video.create(); m.connectVideo(this.video.getFrameData()); } @@ -1256,9 +1260,9 @@ export abstract class BaseMachinePlatform extends BaseDebugPl this.audio.start(); m.connectAudio(this.audio); } - if (hasInput(m)) { - this.video.setKeyboardEvents(m.setInput.bind(m)); - this.poller = new ControllerPoller(m.setInput.bind(m)); + if (hasKeyInput(m)) { + this.video.setKeyboardEvents(m.setKeyInput.bind(m)); + this.poller = new ControllerPoller(m.setKeyInput.bind(m)); } } @@ -1346,8 +1350,24 @@ export abstract class BaseMachinePlatform extends BaseDebugPl } }); } + getRasterScanline() { + return isRaster(this.machine) && this.machine.getRasterY(); + } + /* TODO + startProfilingCPU(log:LogCPU) { + new CPUClockHook(this.machine.cpu, log); + } + stopProfilingCPU() { + } + startProfilingMemory() { + } + stopProfilingMemory() { + } + */ } +// TODO: move debug info into CPU? + export abstract class Base6502MachinePlatform extends BaseMachinePlatform { getOpcodeMetadata = getOpcodeMetadata_6502; @@ -1372,3 +1392,30 @@ export abstract class Base6502MachinePlatform extends BaseMac } } + +export abstract class BaseZ80MachinePlatform extends BaseMachinePlatform { + + //getOpcodeMetadata = getOpcodeMetadata_z80; + getToolForFilename = getToolForFilename_z80; + + getDebugCategories() { + return ['CPU','Stack']; + } + getDebugInfo(category:string, state:EmuState) : string { + switch (category) { + case 'CPU': return cpuStateToLongString_Z80(state.c); + case 'Stack': { + var sp = (state.c.SP-1) & 0xffff; + var start = sp & 0xff00; + var end = start + 0xff; + if (sp == 0) sp = 0x10000; + console.log(sp,start,end); + return dumpStackToString(this, [], start, end, sp, 0xcd); + } + } + } + disassemble(pc:number, read:(addr:number)=>number) : DisasmLine { + return disassembleZ80(pc, read(pc), read(pc+1), read(pc+2), read(pc+3)); + } + +} diff --git a/src/devices.ts b/src/devices.ts index 8ccd9bd6..cb4cc15a 100644 --- a/src/devices.ts +++ b/src/devices.ts @@ -30,6 +30,8 @@ export interface VideoSource { } export interface RasterFrameBased extends FrameBased, VideoSource { + getRasterY() : number; + getRasterX() : number; } export interface VideoParams { @@ -86,13 +88,16 @@ export interface Interruptable { interrupt(type:IT) : void; } -// TODO -export interface AcceptsInput { - setInput(key:number, code:number, flags:number) : void; +export interface SavesInputState { loadControlsState(cs:CS) : void; saveControlsState() : CS; } +// TODO +export interface AcceptsKeyInput { + setKeyInput(key:number, code:number, flags:number) : void; +} + // TODO? export function noise(x : number) : number { x ^= x << 13; diff --git a/src/machine/apple2.ts b/src/machine/apple2.ts index 2998170a..8f170389 100644 --- a/src/machine/apple2.ts +++ b/src/machine/apple2.ts @@ -1,7 +1,6 @@ -"use strict"; import { MOS6502, MOS6502State } from "../cpu/MOS6502"; -import { Bus, RasterFrameBased, SavesState, AcceptsROM, AcceptsInput, noise, Resettable, SampledAudioSource, SampledAudioSink, HasCPU } from "../devices"; +import { Bus, RasterFrameBased, SavesState, SavesInputState, AcceptsROM, AcceptsKeyInput, noise, Resettable, SampledAudioSource, SampledAudioSink, HasCPU } from "../devices"; import { KeyFlags } from "../emu"; // TODO import { lzgmini } from "../util"; @@ -30,8 +29,8 @@ interface AppleIIState extends AppleIIStateBase, AppleIIControlsState { grswitch : number; } -export class AppleII implements HasCPU, Bus, RasterFrameBased, SampledAudioSource, AcceptsROM, - AppleIIStateBase, SavesState, AcceptsInput { +export class AppleII implements HasCPU, Bus, RasterFrameBased, SampledAudioSource, AcceptsROM, AcceptsKeyInput, + AppleIIStateBase, SavesState, SavesInputState { ram = new Uint8Array(0x13000); // 64K + 16K LC RAM - 4K hardware + 12K ROM rom : Uint8Array; @@ -53,6 +52,7 @@ export class AppleII implements HasCPU, Bus, RasterFrameBased, SampledAudioSourc // bank 1 is E000-FFFF, bank 2 is D000-DFFF bank2rdoffset=0; bank2wroffset=0; + lastFrameCycles=0; constructor() { this.rom = new lzgmini().decode(APPLEIIGO_LZG); @@ -219,14 +219,18 @@ export class AppleII implements HasCPU, Bus, RasterFrameBased, SampledAudioSourc advanceFrame(maxCycles, trap) : number { maxCycles = Math.min(maxCycles, cpuCyclesPerFrame); for (var i=0; i=0 && trap()) break; this.cpu.advanceClock(); this.audio.feedSample(this.soundstate, 1); } this.ap2disp && this.ap2disp.updateScreen(); - return i; + return (this.lastFrameCycles = i); } - setInput(key:number, code:number, flags:number) : void { + + getRasterX() { return this.lastFrameCycles % cpuCyclesPerLine; } + getRasterY() { return Math.floor(this.lastFrameCycles / cpuCyclesPerLine); } + + setKeyInput(key:number, code:number, flags:number) : void { if (flags & KeyFlags.KeyPress) { // convert to uppercase for Apple ][ if (code >= 0x61 && code <= 0x7a) diff --git a/src/machine/atari7800.ts b/src/machine/atari7800.ts index edab36d3..47b92158 100644 --- a/src/machine/atari7800.ts +++ b/src/machine/atari7800.ts @@ -1,7 +1,7 @@ "use strict"; import { MOS6502, MOS6502State } from "../cpu/MOS6502"; -import { Bus, RasterFrameBased, SavesState, AcceptsROM, AcceptsInput, noise, Resettable, SampledAudioSource, SampledAudioSink, HasCPU } from "../devices"; +import { Bus, RasterFrameBased, SavesState, SavesInputState, AcceptsROM, AcceptsKeyInput, noise, Resettable, SampledAudioSource, SampledAudioSink, HasCPU } from "../devices"; import { KeyFlags } from "../emu"; // TODO import { hex, lzgmini, stringToByteArray, lpad, rpad, rgb2bgr } from "../util"; @@ -300,8 +300,8 @@ class MARIA { // Atari 7800 -export class Atari7800 implements HasCPU, Bus, RasterFrameBased, SampledAudioSource, AcceptsROM, - Atari7800StateBase, SavesState, AcceptsInput { +export class Atari7800 implements HasCPU, Bus, RasterFrameBased, SampledAudioSource, AcceptsROM, AcceptsKeyInput, + Atari7800StateBase, SavesState, SavesInputState { cpu : MOS6502; ram : Uint8Array = new Uint8Array(0x1000); @@ -317,6 +317,7 @@ export class Atari7800 implements HasCPU, Bus, RasterFrameBased, SampledAudioSou pixels : Uint32Array; audio : SampledAudioSink; handler; // TODO: type, or use ControllerPoller + lastFrameCycles : number = 0; read : (a:number) => number; write : (a:number, v:number) => void; @@ -368,7 +369,7 @@ export class Atari7800 implements HasCPU, Bus, RasterFrameBased, SampledAudioSou } getVideoParams() { - return {width:320, height:numVisibleLines}; + return {width:320, height:numVisibleLines, overscan:true}; } getAudioParams() { return {sampleRate:linesPerFrame*60*oversampling, stereo:false}; @@ -383,11 +384,11 @@ export class Atari7800 implements HasCPU, Bus, RasterFrameBased, SampledAudioSou //TODO this.bios = new Uint8Array(0x1000); // TODO: TIA access wastes a cycle - setInput(key:number, code:number, flags:number) : void { + setKeyInput(key:number, code:number, flags:number) : void { this.handler(key,code,flags); } - advanceFrame(maxClocks, debugCond) : number { + advanceFrame(maxClocks, trap) : number { var idata = this.pixels; var iofs = 0; var rgb; @@ -406,24 +407,28 @@ export class Atari7800 implements HasCPU, Bus, RasterFrameBased, SampledAudioSou if (mariaClocks >= colorClocksPreDMA) { this.maria.WSYNC--; mariaClocks = colorClocksPreDMA; // 7 CPU cycles until DMA + // TODO: frameClocks } else { break; } } // next CPU clock - mariaClocks -= 4; - if (debugCond && debugCond()) { - debugCond = null; + if (trap && (this.lastFrameCycles=frameClocks)>=0 && trap()) { + trap = null; sl = 999; break; } + mariaClocks -= 4; + frameClocks += 4; this.cpu.advanceClock(); } mariaClocks += colorClocksPerLine; // is this scanline visible? if (visible) { // do DMA for scanline? - mariaClocks -= this.maria.doDMA(this); + let dmaClocks = this.maria.doDMA(this); + mariaClocks -= dmaClocks; + frameClocks += dmaClocks; // copy line to frame buffer if (idata) { for (var i=0; i<320; i++) { @@ -453,9 +458,12 @@ export class Atari7800 implements HasCPU, Bus, RasterFrameBased, SampledAudioSou // TODO $(this.video.canvas).css('background-color', COLORS_WEB[bkcol]); } */ - return frameClocks; + return (this.lastFrameCycles = frameClocks); } + getRasterX() { return this.lastFrameCycles % colorClocksPerLine; } + getRasterY() { return Math.floor(this.lastFrameCycles / colorClocksPerLine); } + loadROM(data) { if (data.length == 0xc080) data = data.slice(0x80); // strip header this.rom = padBytes(data, romLength, true); @@ -498,7 +506,7 @@ export class Atari7800 implements HasCPU, Bus, RasterFrameBased, SampledAudioSou in:this.inputs.slice(0) }; } - loadControlsState(state:Atari7800ControlsState) { + loadControlsState(state:Atari7800ControlsState) : void { this.inputs.set(state.in); } saveControlsState() : Atari7800ControlsState { diff --git a/src/vlist.ts b/src/vlist.ts index 287f39dc..260869c3 100644 --- a/src/vlist.ts +++ b/src/vlist.ts @@ -70,7 +70,7 @@ function VirtualList(config) { function onScroll(e) { var scrollTop = e.target.scrollTop; // Triggers reflow if (!lastRepaintY || Math.abs(scrollTop - lastRepaintY) > maxBuffer) { - var first = (scrollTop / itemHeight) - screenItemsLen; + var first = Math.floor(scrollTop / itemHeight) - screenItemsLen; self._renderChunk(self.container, first < 0 ? 0 : first); lastRepaintY = scrollTop; }