show raster x/y crosshair when stopped (getRasterCanvasPosition)
This commit is contained in:
parent
c6345ec728
commit
de6250b0cd
|
@ -1 +1 @@
|
||||||
Subproject commit 9d124f087e1f0c7f74f9244b9679cc62e71fa524
|
Subproject commit 113cd5741e5c414bbbe47ef8be7a896652d48f64
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
import { RasterVideo, dumpRAM, AnimationTimer, ControllerPoller } from "./emu";
|
import { RasterVideo, dumpRAM, AnimationTimer, ControllerPoller, drawCrosshair } from "./emu";
|
||||||
import { hex, printFlags, invertMap, byteToASCII } from "./util";
|
import { hex, printFlags, invertMap, byteToASCII } from "./util";
|
||||||
import { CodeAnalyzer } from "./analysis";
|
import { CodeAnalyzer } from "./analysis";
|
||||||
import { Segment, FileData } from "./workertypes";
|
import { Segment, FileData } from "./workertypes";
|
||||||
|
@ -850,7 +850,7 @@ export abstract class BaseMachinePlatform<T extends Machine> extends BaseDebugPl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadROM(title, data) {
|
loadROM(title, data) {
|
||||||
this.machine.loadROM(data, title);
|
this.machine.loadROM(data, title);
|
||||||
this.reset();
|
this.reset();
|
||||||
|
@ -873,11 +873,26 @@ export abstract class BaseMachinePlatform<T extends Machine> extends BaseDebugPl
|
||||||
advance(novideo:boolean) {
|
advance(novideo:boolean) {
|
||||||
let trap = this.getDebugCallback();
|
let trap = this.getDebugCallback();
|
||||||
var steps = this.machine.advanceFrame(trap);
|
var steps = this.machine.advanceFrame(trap);
|
||||||
if (!novideo && this.video) this.video.updateFrame();
|
if (!novideo && this.video) {
|
||||||
if (!novideo && this.serialVisualizer) this.serialVisualizer.refresh();
|
this.video.updateFrame();
|
||||||
|
this.updateVideoDebugger();
|
||||||
|
}
|
||||||
|
if (!novideo && this.serialVisualizer) {
|
||||||
|
this.serialVisualizer.refresh();
|
||||||
|
}
|
||||||
return steps;
|
return steps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateVideoDebugger() {
|
||||||
|
if (!this.isRunning() && isRaster(this.machine) && this.machine.getRasterCanvasPosition) {
|
||||||
|
const {x,y} = this.machine.getRasterCanvasPosition();
|
||||||
|
if (x >= 0 || y >= 0) {
|
||||||
|
const ctx = this.video.getContext();
|
||||||
|
drawCrosshair(ctx, x, y, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
advanceFrameClock(trap, step) {
|
advanceFrameClock(trap, step) {
|
||||||
if (!(step > 0)) return;
|
if (!(step > 0)) return;
|
||||||
if (this.machine instanceof BaseWASMMachine) {
|
if (this.machine instanceof BaseWASMMachine) {
|
||||||
|
@ -915,7 +930,10 @@ export abstract class BaseMachinePlatform<T extends Machine> extends BaseDebugPl
|
||||||
|
|
||||||
// TODO: reset target clock counter
|
// TODO: reset target clock counter
|
||||||
getRasterScanline() {
|
getRasterScanline() {
|
||||||
return isRaster(this.machine) && this.machine.getRasterY();
|
return isRaster(this.machine) && this.machine.getRasterY ? this.machine.getRasterY() : -1;
|
||||||
|
}
|
||||||
|
getRasterLineClock() {
|
||||||
|
return isRaster(this.machine) && this.machine.getRasterX ? this.machine.getRasterX() : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
readAddress(addr : number) : number {
|
readAddress(addr : number) : number {
|
||||||
|
|
|
@ -1,115 +1,116 @@
|
||||||
|
|
||||||
export interface SavesState<S> {
|
export interface SavesState<S> {
|
||||||
saveState() : S;
|
saveState(): S;
|
||||||
loadState(state:S) : void;
|
loadState(state: S): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Bus {
|
export interface Bus {
|
||||||
read(a:number) : number;
|
read(a: number): number;
|
||||||
write(a:number, v:number) : void;
|
write(a: number, v: number): void;
|
||||||
readConst?(a:number) : number;
|
readConst?(a: number): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ClockBased {
|
export interface ClockBased {
|
||||||
advanceClock() : void;
|
advanceClock(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InstructionBased {
|
export interface InstructionBased {
|
||||||
advanceInsn() : number;
|
advanceInsn(): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TrapCondition = () => boolean;
|
export type TrapCondition = () => boolean;
|
||||||
|
|
||||||
export interface FrameBased {
|
export interface FrameBased {
|
||||||
advanceFrame(trap:TrapCondition) : number;
|
advanceFrame(trap: TrapCondition): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VideoSource {
|
export interface VideoSource {
|
||||||
getVideoParams() : VideoParams;
|
getVideoParams(): VideoParams;
|
||||||
connectVideo(pixels:Uint32Array) : void;
|
connectVideo(pixels: Uint32Array): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RasterFrameBased extends FrameBased, VideoSource {
|
export interface RasterFrameBased extends FrameBased, VideoSource {
|
||||||
getRasterY() : number;
|
getRasterY(): number;
|
||||||
getRasterX() : number;
|
getRasterX(): number;
|
||||||
|
getRasterCanvasPosition?(): { x: number, y: number };
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VideoParams {
|
export interface VideoParams {
|
||||||
width : number;
|
width: number;
|
||||||
height : number;
|
height: number;
|
||||||
overscan? : boolean;
|
overscan?: boolean;
|
||||||
rotate? : number;
|
rotate?: number;
|
||||||
videoFrequency? : number; // default = 60
|
videoFrequency?: number; // default = 60
|
||||||
aspect? : number;
|
aspect?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: frame buffer optimization (apple2, etc)
|
// TODO: frame buffer optimization (apple2, etc)
|
||||||
|
|
||||||
export interface SampledAudioParams {
|
export interface SampledAudioParams {
|
||||||
sampleRate : number;
|
sampleRate: number;
|
||||||
stereo : boolean;
|
stereo: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SampledAudioSink {
|
export interface SampledAudioSink {
|
||||||
feedSample(value:number, count:number) : void;
|
feedSample(value: number, count: number): void;
|
||||||
//sendAudioFrame(samples:Uint16Array) : void;
|
//sendAudioFrame(samples:Uint16Array) : void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SampledAudioSource {
|
export interface SampledAudioSource {
|
||||||
getAudioParams() : SampledAudioParams;
|
getAudioParams(): SampledAudioParams;
|
||||||
connectAudio(audio : SampledAudioSink) : void;
|
connectAudio(audio: SampledAudioSink): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AcceptsROM {
|
export interface AcceptsROM {
|
||||||
loadROM(data:Uint8Array, title?:string) : void;
|
loadROM(data: Uint8Array, title?: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AcceptsBIOS {
|
export interface AcceptsBIOS {
|
||||||
loadBIOS(data:Uint8Array, title?:string) : void;
|
loadBIOS(data: Uint8Array, title?: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Resettable {
|
export interface Resettable {
|
||||||
reset() : void;
|
reset(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MemoryBusConnected {
|
export interface MemoryBusConnected {
|
||||||
connectMemoryBus(bus:Bus) : void;
|
connectMemoryBus(bus: Bus): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IOBusConnected {
|
export interface IOBusConnected {
|
||||||
connectIOBus(bus:Bus) : void;
|
connectIOBus(bus: Bus): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CPU extends MemoryBusConnected, Resettable, SavesState<any> {
|
export interface CPU extends MemoryBusConnected, Resettable, SavesState<any> {
|
||||||
getPC() : number;
|
getPC(): number;
|
||||||
getSP() : number;
|
getSP(): number;
|
||||||
isStable() : boolean;
|
isStable(): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HasCPU extends Resettable {
|
export interface HasCPU extends Resettable {
|
||||||
cpu : CPU;
|
cpu: CPU;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Interruptable<IT> {
|
export interface Interruptable<IT> {
|
||||||
interrupt(type:IT) : void;
|
interrupt(type: IT): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SavesInputState<CS> {
|
export interface SavesInputState<CS> {
|
||||||
loadControlsState(cs:CS) : void;
|
loadControlsState(cs: CS): void;
|
||||||
saveControlsState() : CS;
|
saveControlsState(): CS;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AcceptsKeyInput {
|
export interface AcceptsKeyInput {
|
||||||
setKeyInput(key:number, code:number, flags:number) : void;
|
setKeyInput(key: number, code: number, flags: number): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AcceptsPaddleInput {
|
export interface AcceptsPaddleInput {
|
||||||
setPaddleInput(controller:number, value:number) : void;
|
setPaddleInput(controller: number, value: number): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: interface not yet used (setKeyInput() handles joystick)
|
// TODO: interface not yet used (setKeyInput() handles joystick)
|
||||||
export interface AcceptsJoyInput {
|
export interface AcceptsJoyInput {
|
||||||
setJoyInput(joy:number, bitmask:number) : void;
|
setJoyInput(joy: number, bitmask: number): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SERIAL I/O
|
// SERIAL I/O
|
||||||
|
@ -123,15 +124,15 @@ export interface SerialEvent {
|
||||||
// TODO: all these needed?
|
// TODO: all these needed?
|
||||||
export interface SerialIOInterface {
|
export interface SerialIOInterface {
|
||||||
// from machine to platform
|
// from machine to platform
|
||||||
clearToSend() : boolean;
|
clearToSend(): boolean;
|
||||||
sendByte(b : number);
|
sendByte(b: number);
|
||||||
// from platform to machine
|
// from platform to machine
|
||||||
byteAvailable() : boolean;
|
byteAvailable(): boolean;
|
||||||
recvByte() : number;
|
recvByte(): number;
|
||||||
// implement these too
|
// implement these too
|
||||||
reset() : void;
|
reset(): void;
|
||||||
advance(clocks: number) : void;
|
advance(clocks: number): void;
|
||||||
// refresh() : void;
|
// refresh() : void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HasSerialIO {
|
export interface HasSerialIO {
|
||||||
|
@ -143,62 +144,62 @@ export interface HasSerialIO {
|
||||||
/// PROFILER
|
/// PROFILER
|
||||||
|
|
||||||
export interface Probeable {
|
export interface Probeable {
|
||||||
connectProbe(probe: ProbeAll) : void;
|
connectProbe(probe: ProbeAll): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProbeTime {
|
export interface ProbeTime {
|
||||||
logClocks(clocks:number);
|
logClocks(clocks: number);
|
||||||
logNewScanline();
|
logNewScanline();
|
||||||
logNewFrame();
|
logNewFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProbeCPU {
|
export interface ProbeCPU {
|
||||||
logExecute(address:number, SP:number);
|
logExecute(address: number, SP: number);
|
||||||
logInterrupt(type:number);
|
logInterrupt(type: number);
|
||||||
logIllegal(address:number);
|
logIllegal(address: number);
|
||||||
logWait(address:number);
|
logWait(address: number);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProbeBus {
|
export interface ProbeBus {
|
||||||
logRead(address:number, value:number);
|
logRead(address: number, value: number);
|
||||||
logWrite(address:number, value:number);
|
logWrite(address: number, value: number);
|
||||||
logDMARead(address:number, value:number);
|
logDMARead(address: number, value: number);
|
||||||
logDMAWrite(address:number, value:number);
|
logDMAWrite(address: number, value: number);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProbeIO {
|
export interface ProbeIO {
|
||||||
logIORead(address:number, value:number);
|
logIORead(address: number, value: number);
|
||||||
logIOWrite(address:number, value:number);
|
logIOWrite(address: number, value: number);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProbeVRAM {
|
export interface ProbeVRAM {
|
||||||
logVRAMRead(address:number, value:number);
|
logVRAMRead(address: number, value: number);
|
||||||
logVRAMWrite(address:number, value:number);
|
logVRAMWrite(address: number, value: number);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProbeAll extends ProbeTime, ProbeCPU, ProbeBus, ProbeIO, ProbeVRAM {
|
export interface ProbeAll extends ProbeTime, ProbeCPU, ProbeBus, ProbeIO, ProbeVRAM {
|
||||||
logData(data:number); // entire 32 bits
|
logData(data: number); // entire 32 bits
|
||||||
addLogBuffer(src: Uint32Array);
|
addLogBuffer(src: Uint32Array);
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NullProbe implements ProbeAll {
|
export class NullProbe implements ProbeAll {
|
||||||
logClocks() {}
|
logClocks() { }
|
||||||
logNewScanline() {}
|
logNewScanline() { }
|
||||||
logNewFrame() {}
|
logNewFrame() { }
|
||||||
logExecute() {}
|
logExecute() { }
|
||||||
logInterrupt() {}
|
logInterrupt() { }
|
||||||
logRead() {}
|
logRead() { }
|
||||||
logWrite() {}
|
logWrite() { }
|
||||||
logIORead() {}
|
logIORead() { }
|
||||||
logIOWrite() {}
|
logIOWrite() { }
|
||||||
logVRAMRead() {}
|
logVRAMRead() { }
|
||||||
logVRAMWrite() {}
|
logVRAMWrite() { }
|
||||||
logIllegal() {}
|
logIllegal() { }
|
||||||
logWait() {}
|
logWait() { }
|
||||||
logDMARead() {}
|
logDMARead() { }
|
||||||
logDMAWrite() {}
|
logDMAWrite() { }
|
||||||
logData() {}
|
logData() { }
|
||||||
addLogBuffer(src: Uint32Array) {}
|
addLogBuffer(src: Uint32Array) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// CONVENIENCE
|
/// CONVENIENCE
|
||||||
|
@ -215,32 +216,32 @@ export interface BasicMachineState extends BasicMachineControlsState {
|
||||||
export abstract class BasicHeadlessMachine implements HasCPU, Bus, AcceptsROM, Probeable,
|
export abstract class BasicHeadlessMachine implements HasCPU, Bus, AcceptsROM, Probeable,
|
||||||
SavesState<BasicMachineState>, SavesInputState<BasicMachineControlsState> {
|
SavesState<BasicMachineState>, SavesInputState<BasicMachineControlsState> {
|
||||||
|
|
||||||
abstract cpuFrequency : number;
|
abstract cpuFrequency: number;
|
||||||
abstract defaultROMSize : number;
|
abstract defaultROMSize: number;
|
||||||
|
|
||||||
abstract cpu : CPU;
|
abstract cpu: CPU;
|
||||||
abstract ram : Uint8Array;
|
abstract ram: Uint8Array;
|
||||||
|
|
||||||
rom : Uint8Array;
|
rom: Uint8Array;
|
||||||
inputs : Uint8Array = new Uint8Array(32);
|
inputs: Uint8Array = new Uint8Array(32);
|
||||||
handler : (key,code,flags) => void; // keyboard handler
|
handler: (key, code, flags) => void; // keyboard handler
|
||||||
|
|
||||||
nullProbe = new NullProbe();
|
nullProbe = new NullProbe();
|
||||||
probe : ProbeAll = this.nullProbe;
|
probe: ProbeAll = this.nullProbe;
|
||||||
|
|
||||||
abstract read(a:number) : number;
|
|
||||||
abstract write(a:number, v:number) : void;
|
|
||||||
|
|
||||||
setKeyInput(key:number, code:number, flags:number) : void {
|
abstract read(a: number): number;
|
||||||
this.handler && this.handler(key,code,flags);
|
abstract write(a: number, v: number): void;
|
||||||
|
|
||||||
|
setKeyInput(key: number, code: number, flags: number): void {
|
||||||
|
this.handler && this.handler(key, code, flags);
|
||||||
}
|
}
|
||||||
connectProbe(probe: ProbeAll) : void {
|
connectProbe(probe: ProbeAll): void {
|
||||||
this.probe = probe || this.nullProbe;
|
this.probe = probe || this.nullProbe;
|
||||||
}
|
}
|
||||||
reset() {
|
reset() {
|
||||||
this.cpu.reset();
|
this.cpu.reset();
|
||||||
}
|
}
|
||||||
loadROM(data:Uint8Array, title?:string) : void {
|
loadROM(data: Uint8Array, title?: string): void {
|
||||||
if (!this.rom) this.rom = new Uint8Array(this.defaultROMSize);
|
if (!this.rom) this.rom = new Uint8Array(this.defaultROMSize);
|
||||||
this.rom.set(data);
|
this.rom.set(data);
|
||||||
}
|
}
|
||||||
|
@ -251,9 +252,9 @@ export abstract class BasicHeadlessMachine implements HasCPU, Bus, AcceptsROM, P
|
||||||
}
|
}
|
||||||
saveState() {
|
saveState() {
|
||||||
return {
|
return {
|
||||||
c:this.cpu.saveState(),
|
c: this.cpu.saveState(),
|
||||||
ram:this.ram.slice(0),
|
ram: this.ram.slice(0),
|
||||||
inputs:this.inputs.slice(0),
|
inputs: this.inputs.slice(0),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
loadControlsState(state) {
|
loadControlsState(state) {
|
||||||
|
@ -261,7 +262,7 @@ export abstract class BasicHeadlessMachine implements HasCPU, Bus, AcceptsROM, P
|
||||||
}
|
}
|
||||||
saveControlsState() {
|
saveControlsState() {
|
||||||
return {
|
return {
|
||||||
inputs:this.inputs.slice(0)
|
inputs: this.inputs.slice(0)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
advanceCPU() {
|
advanceCPU() {
|
||||||
|
@ -273,102 +274,104 @@ export abstract class BasicHeadlessMachine implements HasCPU, Bus, AcceptsROM, P
|
||||||
this.probe.logClocks(n);
|
this.probe.logClocks(n);
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
probeMemoryBus(membus:Bus) : Bus {
|
probeMemoryBus(membus: Bus): Bus {
|
||||||
return {
|
return {
|
||||||
read: (a) => {
|
read: (a) => {
|
||||||
let val = membus.read(a);
|
let val = membus.read(a);
|
||||||
this.probe.logRead(a,val);
|
this.probe.logRead(a, val);
|
||||||
return val;
|
return val;
|
||||||
},
|
},
|
||||||
write: (a,v) => {
|
write: (a, v) => {
|
||||||
this.probe.logWrite(a,v);
|
this.probe.logWrite(a, v);
|
||||||
membus.write(a,v);
|
membus.write(a, v);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
connectCPUMemoryBus(membus:Bus) : void {
|
connectCPUMemoryBus(membus: Bus): void {
|
||||||
this.cpu.connectMemoryBus(this.probeMemoryBus(membus));
|
this.cpu.connectMemoryBus(this.probeMemoryBus(membus));
|
||||||
}
|
}
|
||||||
probeIOBus(iobus:Bus) : Bus {
|
probeIOBus(iobus: Bus): Bus {
|
||||||
return {
|
return {
|
||||||
read: (a) => {
|
read: (a) => {
|
||||||
let val = iobus.read(a);
|
let val = iobus.read(a);
|
||||||
this.probe.logIORead(a,val);
|
this.probe.logIORead(a, val);
|
||||||
return val;
|
return val;
|
||||||
},
|
},
|
||||||
write: (a,v) => {
|
write: (a, v) => {
|
||||||
this.probe.logIOWrite(a,v);
|
this.probe.logIOWrite(a, v);
|
||||||
iobus.write(a,v);
|
iobus.write(a, v);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
probeDMABus(iobus:Bus) : Bus {
|
probeDMABus(iobus: Bus): Bus {
|
||||||
return {
|
return {
|
||||||
read: (a) => {
|
read: (a) => {
|
||||||
let val = iobus.read(a);
|
let val = iobus.read(a);
|
||||||
this.probe.logDMARead(a,val);
|
this.probe.logDMARead(a, val);
|
||||||
return val;
|
return val;
|
||||||
},
|
},
|
||||||
write: (a,v) => {
|
write: (a, v) => {
|
||||||
this.probe.logDMAWrite(a,v);
|
this.probe.logDMAWrite(a, v);
|
||||||
iobus.write(a,v);
|
iobus.write(a, v);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
connectCPUIOBus(iobus:Bus) : void {
|
connectCPUIOBus(iobus: Bus): void {
|
||||||
this.cpu['connectIOBus'](this.probeIOBus(iobus));
|
this.cpu['connectIOBus'](this.probeIOBus(iobus));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class BasicMachine extends BasicHeadlessMachine implements SampledAudioSource {
|
export abstract class BasicMachine extends BasicHeadlessMachine implements SampledAudioSource {
|
||||||
|
|
||||||
abstract canvasWidth : number;
|
abstract canvasWidth: number;
|
||||||
abstract numVisibleScanlines : number;
|
abstract numVisibleScanlines: number;
|
||||||
abstract sampleRate : number;
|
abstract sampleRate: number;
|
||||||
overscan : boolean = false;
|
overscan: boolean = false;
|
||||||
rotate : number = 0;
|
rotate: number = 0;
|
||||||
aspectRatio : number;
|
aspectRatio: number;
|
||||||
|
|
||||||
pixels : Uint32Array;
|
|
||||||
audio : SampledAudioSink;
|
|
||||||
|
|
||||||
scanline : number;
|
pixels: Uint32Array;
|
||||||
|
audio: SampledAudioSink;
|
||||||
getAudioParams() : SampledAudioParams {
|
|
||||||
return {sampleRate:this.sampleRate, stereo:false};
|
scanline: number;
|
||||||
|
|
||||||
|
getAudioParams(): SampledAudioParams {
|
||||||
|
return { sampleRate: this.sampleRate, stereo: false };
|
||||||
}
|
}
|
||||||
connectAudio(audio : SampledAudioSink) : void {
|
connectAudio(audio: SampledAudioSink): void {
|
||||||
this.audio = audio;
|
this.audio = audio;
|
||||||
}
|
}
|
||||||
getVideoParams() : VideoParams {
|
getVideoParams(): VideoParams {
|
||||||
return {width:this.canvasWidth,
|
return {
|
||||||
height:this.numVisibleScanlines,
|
width: this.canvasWidth,
|
||||||
aspect:this.aspectRatio,
|
height: this.numVisibleScanlines,
|
||||||
overscan:this.overscan,
|
aspect: this.aspectRatio,
|
||||||
rotate:this.rotate};
|
overscan: this.overscan,
|
||||||
|
rotate: this.rotate
|
||||||
|
};
|
||||||
}
|
}
|
||||||
connectVideo(pixels:Uint32Array) : void {
|
connectVideo(pixels: Uint32Array): void {
|
||||||
this.pixels = pixels;
|
this.pixels = pixels;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class BasicScanlineMachine extends BasicMachine implements RasterFrameBased {
|
export abstract class BasicScanlineMachine extends BasicMachine implements RasterFrameBased {
|
||||||
|
|
||||||
abstract numTotalScanlines : number;
|
abstract numTotalScanlines: number;
|
||||||
abstract cpuCyclesPerLine : number;
|
abstract cpuCyclesPerLine: number;
|
||||||
|
|
||||||
abstract startScanline() : void;
|
abstract startScanline(): void;
|
||||||
abstract drawScanline() : void;
|
abstract drawScanline(): void;
|
||||||
|
|
||||||
frameCycles : number;
|
frameCycles: number;
|
||||||
|
|
||||||
advanceFrame(trap: TrapCondition) : number {
|
advanceFrame(trap: TrapCondition): number {
|
||||||
this.preFrame();
|
this.preFrame();
|
||||||
var endLineClock = 0;
|
var endLineClock = 0;
|
||||||
var steps = 0;
|
var steps = 0;
|
||||||
this.probe.logNewFrame();
|
this.probe.logNewFrame();
|
||||||
this.frameCycles = 0;
|
this.frameCycles = 0;
|
||||||
for (var sl=0; sl<this.numTotalScanlines; sl++) {
|
for (var sl = 0; sl < this.numTotalScanlines; sl++) {
|
||||||
endLineClock += this.cpuCyclesPerLine; // could be fractional
|
endLineClock += this.cpuCyclesPerLine; // could be fractional
|
||||||
this.scanline = sl;
|
this.scanline = sl;
|
||||||
this.startScanline();
|
this.startScanline();
|
||||||
|
|
|
@ -215,6 +215,21 @@ export class VectorVideo extends RasterVideo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function drawCrosshair(ctx:CanvasRenderingContext2D, x:number, y:number, width:number) {
|
||||||
|
ctx.fillStyle = 'rgba(0,0,0,0.25)';
|
||||||
|
ctx.fillRect(x-2, 0, 5, 32767);
|
||||||
|
ctx.fillRect(0, y-2, 32767, 5);
|
||||||
|
ctx.lineWidth = width;
|
||||||
|
ctx.strokeStyle = 'rgba(255,255,255,0.75)';
|
||||||
|
ctx.setLineDash([width*2,width*2]);
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(x, 0);
|
||||||
|
ctx.lineTo(x, 32767);
|
||||||
|
ctx.moveTo(0, y);
|
||||||
|
ctx.lineTo(32767, y);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
export class RAM {
|
export class RAM {
|
||||||
mem : Uint8Array;
|
mem : Uint8Array;
|
||||||
constructor(size:number) {
|
constructor(size:number) {
|
||||||
|
|
|
@ -556,6 +556,7 @@ export class BallyAstrocade extends BasicScanlineMachine implements AcceptsPaddl
|
||||||
case 'Astro': return this.m.toLongString(state);
|
case 'Astro': return this.m.toLongString(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
getRasterCanvasPosition() { return { x: this.getRasterX(), y: this.getRasterY() }; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -516,6 +516,7 @@ export class Atari7800 extends BasicMachine implements RasterFrameBased {
|
||||||
var mc = 0;
|
var mc = 0;
|
||||||
var fc = 0;
|
var fc = 0;
|
||||||
var steps = 0;
|
var steps = 0;
|
||||||
|
this.lastFrameCycles = -1;
|
||||||
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
|
||||||
|
@ -530,6 +531,7 @@ export class Atari7800 extends BasicMachine implements RasterFrameBased {
|
||||||
if (trap && trap()) {
|
if (trap && trap()) {
|
||||||
trap = null;
|
trap = null;
|
||||||
sl = 999;
|
sl = 999;
|
||||||
|
this.lastFrameCycles = mc;
|
||||||
break; // TODO?
|
break; // TODO?
|
||||||
}
|
}
|
||||||
mc += this.advanceCPU() << 2;
|
mc += this.advanceCPU() << 2;
|
||||||
|
@ -567,6 +569,7 @@ export class Atari7800 extends BasicMachine implements RasterFrameBased {
|
||||||
if (trap && trap()) {
|
if (trap && trap()) {
|
||||||
trap = null;
|
trap = null;
|
||||||
sl = 999;
|
sl = 999;
|
||||||
|
this.lastFrameCycles = mc;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mc += this.advanceCPU() << 2;
|
mc += this.advanceCPU() << 2;
|
||||||
|
@ -583,13 +586,18 @@ 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]);
|
||||||
*/
|
*/
|
||||||
this.lastFrameCycles = fc;
|
|
||||||
return steps;
|
return steps;
|
||||||
}
|
}
|
||||||
|
|
||||||
getRasterX() { return this.lastFrameCycles % colorClocksPerLine; }
|
// TODO: doesn't work when breakpoint
|
||||||
|
getRasterX() { return (this.lastFrameCycles + colorClocksPerLine) % colorClocksPerLine; }
|
||||||
|
|
||||||
getRasterY() { return this.scanline; }
|
getRasterY() { return this.scanline; }
|
||||||
|
|
||||||
|
getRasterCanvasPosition() {
|
||||||
|
return { x: this.getRasterX(), y: this.getRasterY() };
|
||||||
|
}
|
||||||
|
|
||||||
loadROM(data) {
|
loadROM(data) {
|
||||||
if (data.length == 0xc080) data = data.slice(0x80); // strip header
|
if (data.length == 0xc080) data = data.slice(0x80); // strip header
|
||||||
this.rom = padBytes(data, this.defaultROMSize, true);
|
this.rom = padBytes(data, this.defaultROMSize, true);
|
||||||
|
|
|
@ -267,12 +267,18 @@ export class Atari800 extends BasicScanlineMachine implements AcceptsPaddleInput
|
||||||
keycode: this.keycode,
|
keycode: this.keycode,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
getRasterScanline() {
|
getRasterY() {
|
||||||
return this.antic.v;
|
return this.antic.v;
|
||||||
}
|
}
|
||||||
getRasterLineClock() {
|
getRasterX() {
|
||||||
return this.antic.h;
|
return this.antic.h;
|
||||||
}
|
}
|
||||||
|
getRasterCanvasPosition() {
|
||||||
|
return {
|
||||||
|
x: this.antic.h * 4 - this.firstVisibleClock,
|
||||||
|
y: this.antic.v - this.firstVisibleScanline,
|
||||||
|
}
|
||||||
|
}
|
||||||
getDebugCategories() {
|
getDebugCategories() {
|
||||||
return ['CPU', 'Stack', 'ANTIC', 'GTIA', 'POKEY'];
|
return ['CPU', 'Stack', 'ANTIC', 'GTIA', 'POKEY'];
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,9 +200,18 @@ export class C64_WASMMachine extends BaseWASMMachine
|
||||||
}
|
}
|
||||||
this.exports.c64_joystick(this.sys, this.joymask0, this.joymask1);
|
this.exports.c64_joystick(this.sys, this.joymask0, this.joymask1);
|
||||||
}
|
}
|
||||||
|
getRasterX() {
|
||||||
|
return this.statearr[0xf4];
|
||||||
|
}
|
||||||
getRasterY() {
|
getRasterY() {
|
||||||
return this.exports.machine_get_raster_line(this.sys);
|
return this.exports.machine_get_raster_line(this.sys);
|
||||||
}
|
}
|
||||||
|
getRasterCanvasPosition() {
|
||||||
|
return {
|
||||||
|
x: this.getRasterX() * 392/63,
|
||||||
|
y: this.getRasterY() - 14,
|
||||||
|
}
|
||||||
|
}
|
||||||
getDebugStateOffset(index: number) {
|
getDebugStateOffset(index: number) {
|
||||||
var p = this.exports.machine_get_debug_pointer(this.sys, index);
|
var p = this.exports.machine_get_debug_pointer(this.sys, index);
|
||||||
return p - this.sys;
|
return p - this.sys;
|
||||||
|
|
|
@ -69,6 +69,12 @@ export class CPC_WASMMachine extends BaseWASMMachine implements Machine {
|
||||||
getRasterY() {
|
getRasterY() {
|
||||||
return this.exports.machine_get_raster_line(this.sys);
|
return this.exports.machine_get_raster_line(this.sys);
|
||||||
}
|
}
|
||||||
|
getRasterCanvasPosition() {
|
||||||
|
return {
|
||||||
|
x: -1, // TODO?
|
||||||
|
y: this.getRasterY() - 14,
|
||||||
|
}
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
z80_tick_t tick_cb; // 0
|
z80_tick_t tick_cb; // 0
|
||||||
uint64_t bc_de_hl_fa; // 8
|
uint64_t bc_de_hl_fa; // 8
|
||||||
|
|
|
@ -93,6 +93,12 @@ export class VIC20_WASMMachine extends BaseWASMMachine implements Machine, Probe
|
||||||
getRasterY() {
|
getRasterY() {
|
||||||
return this.exports.machine_get_raster_line(this.sys);
|
return this.exports.machine_get_raster_line(this.sys);
|
||||||
}
|
}
|
||||||
|
getRasterCanvasPosition() {
|
||||||
|
return {
|
||||||
|
x: -1, // TODO?
|
||||||
|
y: this.getRasterY() - 14,
|
||||||
|
}
|
||||||
|
}
|
||||||
getCPUState() {
|
getCPUState() {
|
||||||
this.exports.machine_save_cpu_state(this.sys, this.cpustateptr);
|
this.exports.machine_save_cpu_state(this.sys, this.cpustateptr);
|
||||||
var s = this.cpustatearr;
|
var s = this.cpustatearr;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
import { Platform, BasePlatform, cpuStateToLongString_6502, dumpStackToString, DisasmLine, CpuState, getToolForFilename_6502 } from "../common/baseplatform";
|
import { Platform, BasePlatform, cpuStateToLongString_6502, dumpStackToString, DisasmLine, CpuState, getToolForFilename_6502 } from "../common/baseplatform";
|
||||||
import { PLATFORMS, dumpRAM, EmuHalt, RasterVideo, __createCanvas } from "../common/emu";
|
import { PLATFORMS, dumpRAM, EmuHalt, RasterVideo, __createCanvas, drawCrosshair } from "../common/emu";
|
||||||
import { hex, loadScript, lpad, tobin } from "../common/util";
|
import { hex, loadScript, lpad, tobin } from "../common/util";
|
||||||
import { CodeAnalyzer_vcs } from "../common/analysis";
|
import { CodeAnalyzer_vcs } from "../common/analysis";
|
||||||
import { disassemble6502 } from "../common/cpu/disasm6502";
|
import { disassemble6502 } from "../common/cpu/disasm6502";
|
||||||
|
@ -72,6 +72,7 @@ function getToolForFilename_vcs(fn: string) {
|
||||||
class VCSPlatform extends BasePlatform {
|
class VCSPlatform extends BasePlatform {
|
||||||
|
|
||||||
lastBreakState; // last breakpoint state
|
lastBreakState; // last breakpoint state
|
||||||
|
canvas : HTMLCanvasElement;
|
||||||
|
|
||||||
// TODO: super hack for ProbeBitmap view
|
// TODO: super hack for ProbeBitmap view
|
||||||
machine = {
|
machine = {
|
||||||
|
@ -92,10 +93,10 @@ class VCSPlatform extends BasePlatform {
|
||||||
// show console div and start
|
// show console div and start
|
||||||
$("#javatari-div").show();
|
$("#javatari-div").show();
|
||||||
Javatari.start();
|
Javatari.start();
|
||||||
var console = Javatari.room.console;
|
var jaconsole = Javatari.room.console;
|
||||||
// intercept clockPulse function
|
// intercept clockPulse function
|
||||||
console.oldClockPulse = console.clockPulse;
|
jaconsole.oldClockPulse = jaconsole.clockPulse;
|
||||||
console.clockPulse = function() {
|
jaconsole.clockPulse = function() {
|
||||||
self.updateRecorder();
|
self.updateRecorder();
|
||||||
self.probe.logNewFrame();
|
self.probe.logNewFrame();
|
||||||
this.oldClockPulse();
|
this.oldClockPulse();
|
||||||
|
@ -106,18 +107,19 @@ class VCSPlatform extends BasePlatform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// intercept TIA end of line
|
// intercept TIA end of line
|
||||||
var videoSignal = console.tia.getVideoOutput();
|
var videoSignal = jaconsole.tia.getVideoOutput();
|
||||||
videoSignal.oldNextLine = videoSignal.nextLine;
|
videoSignal.oldNextLine = videoSignal.nextLine;
|
||||||
videoSignal.nextLine = function(pixels, vsync) {
|
videoSignal.nextLine = function(pixels, vsync) {
|
||||||
self.probe.logNewScanline();
|
self.probe.logNewScanline();
|
||||||
return this.oldNextLine(pixels, vsync);
|
return this.oldNextLine(pixels, vsync);
|
||||||
}
|
}
|
||||||
// resize after added to dom tree
|
// resize after added to dom tree
|
||||||
var jacanvas = $("#javatari-screen").find("canvas");
|
var jacanvas = $("#javatari-screen").find("canvas")[0];
|
||||||
const resizeObserver = new ResizeObserver(entries => {
|
const resizeObserver = new ResizeObserver(entries => {
|
||||||
this.resize();
|
this.resize();
|
||||||
});
|
});
|
||||||
resizeObserver.observe(jacanvas[0]);
|
resizeObserver.observe(jacanvas);
|
||||||
|
this.canvas = jacanvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadROM(title, data) {
|
loadROM(title, data) {
|
||||||
|
@ -148,6 +150,16 @@ class VCSPlatform extends BasePlatform {
|
||||||
getRasterLineClock() : number {
|
getRasterLineClock() : number {
|
||||||
return this.getRasterPosition().x;
|
return this.getRasterPosition().x;
|
||||||
}
|
}
|
||||||
|
getRasterCanvasPosition() : {x:number,y:number} {
|
||||||
|
let p = Javatari.room.console.tia.getVideoOutput().monitor.getDisplayParameters();
|
||||||
|
let {x,y} = this.getRasterPosition();
|
||||||
|
let canvasPos = {
|
||||||
|
x: (x - p.displayOriginX) * p.displayWidth * p.displayScaleX / (p.signalWidth - p.displayOriginX),
|
||||||
|
y: (y - p.displayOriginY) * p.displayHeight * p.displayScaleY / p.displayHeight
|
||||||
|
};
|
||||||
|
console.log(x,y,canvasPos,p);
|
||||||
|
return canvasPos;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Clock changes this on event, so it may not be current
|
// TODO: Clock changes this on event, so it may not be current
|
||||||
isRunning() {
|
isRunning() {
|
||||||
|
@ -194,6 +206,8 @@ class VCSPlatform extends BasePlatform {
|
||||||
Javatari.room.speaker.mute();
|
Javatari.room.speaker.mute();
|
||||||
this.lastBreakState = state;
|
this.lastBreakState = state;
|
||||||
callback(state);
|
callback(state);
|
||||||
|
// TODO: we have to delay because javatari timer is still running
|
||||||
|
setTimeout(() => this.updateVideoDebugger(), 100);
|
||||||
}
|
}
|
||||||
Javatari.room.speaker.mute();
|
Javatari.room.speaker.mute();
|
||||||
}
|
}
|
||||||
|
@ -248,6 +262,7 @@ class VCSPlatform extends BasePlatform {
|
||||||
}
|
}
|
||||||
readAddress(addr) {
|
readAddress(addr) {
|
||||||
// TODO: shouldn't have to do this when debugging
|
// TODO: shouldn't have to do this when debugging
|
||||||
|
// TODO: don't read bank switch addresses
|
||||||
if (this.lastBreakState && addr >= 0x80 && addr < 0x100)
|
if (this.lastBreakState && addr >= 0x80 && addr < 0x100)
|
||||||
return this.getRAMForState(this.lastBreakState)[addr & 0x7f];
|
return this.getRAMForState(this.lastBreakState)[addr & 0x7f];
|
||||||
else if ((addr & 0x1280) === 0x280)
|
else if ((addr & 0x1280) === 0x280)
|
||||||
|
@ -419,6 +434,13 @@ class VCSPlatform extends BasePlatform {
|
||||||
var xt = (1 - scale) * 50;
|
var xt = (1 - scale) * 50;
|
||||||
$('#javatari-div').css('transform', `translateX(-${xt}%) translateY(-${xt}%) scale(${scale})`);
|
$('#javatari-div').css('transform', `translateX(-${xt}%) translateY(-${xt}%) scale(${scale})`);
|
||||||
}
|
}
|
||||||
|
updateVideoDebugger() {
|
||||||
|
const {x,y} = this.getRasterCanvasPosition();
|
||||||
|
if (x >= 0 || y >= 0) {
|
||||||
|
const ctx = this.canvas.getContext('2d');
|
||||||
|
drawCrosshair(ctx, x, y, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: mixin for Base6502Platform?
|
// TODO: mixin for Base6502Platform?
|
||||||
|
|
Loading…
Reference in New Issue