atari8: wait/dma events, new kbd
This commit is contained in:
parent
56e8fca270
commit
5735135add
|
@ -591,6 +591,8 @@ div.asset_toolbar {
|
||||||
}
|
}
|
||||||
.control-def {
|
.control-def {
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
|
white-space: nowrap;
|
||||||
|
line-height:2em;
|
||||||
}
|
}
|
||||||
.book-title {
|
.book-title {
|
||||||
font-size:12pt;
|
font-size:12pt;
|
||||||
|
|
|
@ -373,8 +373,9 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
||||||
<div class="emucontrols-atari8 text-center small control-insns" style="display:none">
|
<div class="emucontrols-atari8 text-center small control-insns" style="display:none">
|
||||||
<span class="control-def"><span class="control-key">←↑↓→</span> Joystick</span>
|
<span class="control-def"><span class="control-key">←↑↓→</span> Joystick</span>
|
||||||
<span class="control-def"><span class="control-key">Shift</span> Button</span>
|
<span class="control-def"><span class="control-key">Shift</span> Button</span>
|
||||||
<span class="control-def"><span class="control-key">Enter</span> Start</span>
|
<span class="control-def"><span class="control-key">F1</span> Start</span>
|
||||||
<span class="control-def"><span class="control-key">\</span> Select</span>
|
<span class="control-def"><span class="control-key">F2</span> Select</span>
|
||||||
|
<span class="control-def"><span class="control-key">F3</span> Option</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- -->
|
<!-- -->
|
||||||
<div id="emuoverlay" class="emuoverlay" style="display:none">
|
<div id="emuoverlay" class="emuoverlay" style="display:none">
|
||||||
|
|
|
@ -17,8 +17,6 @@ import { _MOS6502 } from "./cpu/MOS6502";
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|
||||||
declare var jt;
|
|
||||||
|
|
||||||
export interface OpcodeMetadata {
|
export interface OpcodeMetadata {
|
||||||
minCycles: number;
|
minCycles: number;
|
||||||
maxCycles: number;
|
maxCycles: number;
|
||||||
|
|
|
@ -156,11 +156,14 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
logDMAWrite(address:number, value:number);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProbeIO {
|
export interface ProbeIO {
|
||||||
|
@ -191,6 +194,9 @@ export class NullProbe implements ProbeAll {
|
||||||
logVRAMRead() {}
|
logVRAMRead() {}
|
||||||
logVRAMWrite() {}
|
logVRAMWrite() {}
|
||||||
logIllegal() {}
|
logIllegal() {}
|
||||||
|
logWait() {}
|
||||||
|
logDMARead() {}
|
||||||
|
logDMAWrite() {}
|
||||||
logData() {}
|
logData() {}
|
||||||
addLogBuffer(src: Uint32Array) {}
|
addLogBuffer(src: Uint32Array) {}
|
||||||
}
|
}
|
||||||
|
@ -296,6 +302,19 @@ export abstract class BasicHeadlessMachine implements HasCPU, Bus, AcceptsROM, P
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
probeDMABus(iobus:Bus) : Bus {
|
||||||
|
return {
|
||||||
|
read: (a) => {
|
||||||
|
let val = iobus.read(a);
|
||||||
|
this.probe.logDMARead(a,val);
|
||||||
|
return val;
|
||||||
|
},
|
||||||
|
write: (a,v) => {
|
||||||
|
this.probe.logDMAWrite(a,v);
|
||||||
|
iobus.write(a,v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
connectCPUIOBus(iobus:Bus) : void {
|
connectCPUIOBus(iobus:Bus) : void {
|
||||||
this.cpu['connectIOBus'](this.probeIOBus(iobus));
|
this.cpu['connectIOBus'](this.probeIOBus(iobus));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,6 @@ import { hex, clamp, lpad, RGBA } from "./util";
|
||||||
import { SourceLocation } from "./workertypes";
|
import { SourceLocation } from "./workertypes";
|
||||||
import { VirtualList } from "./vlist"
|
import { VirtualList } from "./vlist"
|
||||||
|
|
||||||
// external modules
|
|
||||||
declare var jt, Javatari;
|
|
||||||
|
|
||||||
// Emulator classes
|
// Emulator classes
|
||||||
|
|
||||||
export var PLATFORMS = {};
|
export var PLATFORMS = {};
|
||||||
|
@ -52,12 +49,9 @@ export enum KeyFlags {
|
||||||
|
|
||||||
export function _setKeyboardEvents(canvas:HTMLElement, callback:KeyboardCallback) {
|
export function _setKeyboardEvents(canvas:HTMLElement, callback:KeyboardCallback) {
|
||||||
canvas.onkeydown = (e) => {
|
canvas.onkeydown = (e) => {
|
||||||
callback(e.which, 0, KeyFlags.KeyDown|_metakeyflags(e));
|
let flags = _metakeyflags(e);
|
||||||
// eat backspace, tab, escape, slash, ' keys
|
callback(e.which, 0, KeyFlags.KeyDown|flags);
|
||||||
if (e.ctrlKey || e.which == 8 || e.which == 9 || e.which == 27
|
if (!flags) e.preventDefault(); // eat all keys that don't have a modifier
|
||||||
|| e.which == 191 || e.which == 191 || e.which == 222) {
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
canvas.onkeyup = (e) => {
|
canvas.onkeyup = (e) => {
|
||||||
callback(e.which, 0, KeyFlags.KeyUp|_metakeyflags(e));
|
callback(e.which, 0, KeyFlags.KeyUp|_metakeyflags(e));
|
||||||
|
@ -370,7 +364,7 @@ export const Keys = {
|
||||||
GP_D: {c: 67, n: "C", plyr:0, button:3},
|
GP_D: {c: 67, n: "C", plyr:0, button:3},
|
||||||
SELECT: {c: 220, n: "\\", plyr:0, button:8},
|
SELECT: {c: 220, n: "\\", plyr:0, button:8},
|
||||||
START: {c: 13, n: "Enter", plyr:0, button:9},
|
START: {c: 13, n: "Enter", plyr:0, button:9},
|
||||||
OPTION: {c: 9, n: "Tab", plyr:0, button:10},
|
OPTION: {c: 8, n: "Bcksp", plyr:0, button:10},
|
||||||
// gamepad and keyboard (player 1)
|
// gamepad and keyboard (player 1)
|
||||||
P2_UP: {c: 87, n: "W", plyr:1, yaxis:-1},
|
P2_UP: {c: 87, n: "W", plyr:1, yaxis:-1},
|
||||||
P2_DOWN: {c: 83, n: "S", plyr:1, yaxis:1},
|
P2_DOWN: {c: 83, n: "S", plyr:1, yaxis:1},
|
||||||
|
@ -458,6 +452,7 @@ export const Keys = {
|
||||||
VK_SLASH: {c: 191, n: "/"},
|
VK_SLASH: {c: 191, n: "/"},
|
||||||
VK_CONTROL: {c: 17, n: "Ctrl"},
|
VK_CONTROL: {c: 17, n: "Ctrl"},
|
||||||
VK_ALT: {c: 18, n: "Alt"},
|
VK_ALT: {c: 18, n: "Alt"},
|
||||||
|
VK_COMMAND: {c: 224, n: "Cmd"},
|
||||||
VK_SPACE: {c: 32, n: "Space"},
|
VK_SPACE: {c: 32, n: "Space"},
|
||||||
VK_INSERT: {c: 45, n: "Ins"},
|
VK_INSERT: {c: 45, n: "Ins"},
|
||||||
VK_DELETE: {c: 46, n: "Del"},
|
VK_DELETE: {c: 46, n: "Del"},
|
||||||
|
|
|
@ -4,6 +4,10 @@ import { Probeable, ProbeAll } from "./devices";
|
||||||
export enum ProbeFlags {
|
export enum ProbeFlags {
|
||||||
CLOCKS = 0x00000000,
|
CLOCKS = 0x00000000,
|
||||||
EXECUTE = 0x01000000,
|
EXECUTE = 0x01000000,
|
||||||
|
INTERRUPT = 0x08000000,
|
||||||
|
ILLEGAL = 0x09000000,
|
||||||
|
SP_PUSH = 0x0a000000,
|
||||||
|
SP_POP = 0x0b000000,
|
||||||
HAS_VALUE = 0x10000000,
|
HAS_VALUE = 0x10000000,
|
||||||
MEM_READ = 0x12000000,
|
MEM_READ = 0x12000000,
|
||||||
MEM_WRITE = 0x13000000,
|
MEM_WRITE = 0x13000000,
|
||||||
|
@ -11,10 +15,9 @@ export enum ProbeFlags {
|
||||||
IO_WRITE = 0x15000000,
|
IO_WRITE = 0x15000000,
|
||||||
VRAM_READ = 0x16000000,
|
VRAM_READ = 0x16000000,
|
||||||
VRAM_WRITE= 0x17000000,
|
VRAM_WRITE= 0x17000000,
|
||||||
INTERRUPT = 0x08000000,
|
DMA_READ = 0x18000000,
|
||||||
ILLEGAL = 0x09000000,
|
DMA_WRITE = 0x19000000,
|
||||||
SP_PUSH = 0x0a000000,
|
WAIT = 0x1f000000,
|
||||||
SP_POP = 0x0b000000,
|
|
||||||
SCANLINE = 0x7e000000,
|
SCANLINE = 0x7e000000,
|
||||||
FRAME = 0x7f000000,
|
FRAME = 0x7f000000,
|
||||||
}
|
}
|
||||||
|
@ -140,6 +143,15 @@ export class ProbeRecorder implements ProbeAll {
|
||||||
logIllegal(address:number) {
|
logIllegal(address:number) {
|
||||||
this.log(address | ProbeFlags.ILLEGAL);
|
this.log(address | ProbeFlags.ILLEGAL);
|
||||||
}
|
}
|
||||||
|
logWait(address:number) {
|
||||||
|
this.log(address | ProbeFlags.WAIT);
|
||||||
|
}
|
||||||
|
logDMARead(address:number, value:number) {
|
||||||
|
this.logValue(address, value, ProbeFlags.DMA_READ);
|
||||||
|
}
|
||||||
|
logDMAWrite(address:number, value:number) {
|
||||||
|
this.logValue(address, value, ProbeFlags.DMA_WRITE);
|
||||||
|
}
|
||||||
countEvents(op : number) : number {
|
countEvents(op : number) : number {
|
||||||
var count = 0;
|
var count = 0;
|
||||||
for (var i=0; i<this.idx; i++) {
|
for (var i=0; i<this.idx; i++) {
|
||||||
|
|
|
@ -402,8 +402,11 @@ export abstract class ProbeViewBaseBase {
|
||||||
case ProbeFlags.IO_WRITE: s = "IO Write"; break;
|
case ProbeFlags.IO_WRITE: s = "IO Write"; break;
|
||||||
case ProbeFlags.VRAM_READ: s = "VRAM Read"; break;
|
case ProbeFlags.VRAM_READ: s = "VRAM Read"; break;
|
||||||
case ProbeFlags.VRAM_WRITE: s = "VRAM Write"; break;
|
case ProbeFlags.VRAM_WRITE: s = "VRAM Write"; break;
|
||||||
|
case ProbeFlags.DMA_READ: s = "DMA Read"; break;
|
||||||
|
case ProbeFlags.DMA_WRITE: s = "DMA Write"; break;
|
||||||
case ProbeFlags.INTERRUPT: s = "Interrupt"; break;
|
case ProbeFlags.INTERRUPT: s = "Interrupt"; break;
|
||||||
case ProbeFlags.ILLEGAL: s = "Error"; break;
|
case ProbeFlags.ILLEGAL: s = "Error"; break;
|
||||||
|
case ProbeFlags.WAIT: s = "Wait"; break;
|
||||||
case ProbeFlags.SP_PUSH: s = "Stack Push"; break;
|
case ProbeFlags.SP_PUSH: s = "Stack Push"; break;
|
||||||
case ProbeFlags.SP_POP: s = "Stack Pop"; break;
|
case ProbeFlags.SP_POP: s = "Stack Pop"; break;
|
||||||
default: return "";
|
default: return "";
|
||||||
|
@ -420,10 +423,13 @@ export abstract class ProbeViewBaseBase {
|
||||||
case ProbeFlags.MEM_WRITE: return 0x010180;
|
case ProbeFlags.MEM_WRITE: return 0x010180;
|
||||||
case ProbeFlags.IO_READ: return 0x018080;
|
case ProbeFlags.IO_READ: return 0x018080;
|
||||||
case ProbeFlags.IO_WRITE: return 0xc00180;
|
case ProbeFlags.IO_WRITE: return 0xc00180;
|
||||||
|
case ProbeFlags.DMA_READ:
|
||||||
case ProbeFlags.VRAM_READ: return 0x808001;
|
case ProbeFlags.VRAM_READ: return 0x808001;
|
||||||
|
case ProbeFlags.DMA_WRITE:
|
||||||
case ProbeFlags.VRAM_WRITE: return 0x4080c0;
|
case ProbeFlags.VRAM_WRITE: return 0x4080c0;
|
||||||
case ProbeFlags.INTERRUPT: return 0x3fbf3f;
|
case ProbeFlags.INTERRUPT: return 0x3fbf3f;
|
||||||
case ProbeFlags.ILLEGAL: return 0x3f3fff;
|
case ProbeFlags.ILLEGAL: return 0x3f3fff;
|
||||||
|
case ProbeFlags.WAIT: return 0xff3f3f;
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -688,8 +694,9 @@ export class RasterStackMapView extends RasterPCHeatMapView implements ProjectVi
|
||||||
if (op == ProbeFlags.VRAM_WRITE) { this.rgb |= 0x003f80; }
|
if (op == ProbeFlags.VRAM_WRITE) { this.rgb |= 0x003f80; }
|
||||||
if (op == ProbeFlags.IO_WRITE) { this.rgb |= 0x1f3f80; }
|
if (op == ProbeFlags.IO_WRITE) { this.rgb |= 0x1f3f80; }
|
||||||
if (op == ProbeFlags.IO_READ) { this.rgb |= 0x001f00; }
|
if (op == ProbeFlags.IO_READ) { this.rgb |= 0x001f00; }
|
||||||
|
if (op == ProbeFlags.WAIT) { this.rgb = 0x008000; }
|
||||||
// draw pixels?
|
// draw pixels?
|
||||||
if (op == ProbeFlags.ILLEGAL || op == ProbeFlags.VRAM_READ) {
|
if (op == ProbeFlags.ILLEGAL || op == ProbeFlags.DMA_READ) {
|
||||||
this.datau32[iofs] = 0xff0f0f0f;
|
this.datau32[iofs] = 0xff0f0f0f;
|
||||||
} else {
|
} else {
|
||||||
let data = this.rgb;
|
let data = this.rgb;
|
||||||
|
|
|
@ -323,7 +323,7 @@ export class Atari7800 extends BasicMachine implements RasterFrameBased {
|
||||||
read : (a:number) => number;
|
read : (a:number) => number;
|
||||||
write : (a:number, v:number) => void;
|
write : (a:number, v:number) => void;
|
||||||
|
|
||||||
probeDMABus : Bus; // to pass to MARIA
|
dmaBus : Bus; // to pass to MARIA
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
@ -355,7 +355,7 @@ export class Atari7800 extends BasicMachine implements RasterFrameBased {
|
||||||
[0x0000, 0xffff, 0xffff, (a,v) => { this.probe && this.probe.logIllegal(a); }],
|
[0x0000, 0xffff, 0xffff, (a,v) => { this.probe && this.probe.logIllegal(a); }],
|
||||||
]);
|
]);
|
||||||
this.connectCPUMemoryBus(this);
|
this.connectCPUMemoryBus(this);
|
||||||
this.probeDMABus = this.probeIOBus(this);
|
this.dmaBus = this.probeDMABus(this);
|
||||||
this.handler = newKeyboardHandler(this.inputs, Atari7800_KEYCODE_MAP);
|
this.handler = newKeyboardHandler(this.inputs, Atari7800_KEYCODE_MAP);
|
||||||
this.pokey1 = new POKEYDeviceChannel();
|
this.pokey1 = new POKEYDeviceChannel();
|
||||||
this.audioadapter = new TssChannelAdapter(this.pokey1, audioOversample, audioSampleRate);
|
this.audioadapter = new TssChannelAdapter(this.pokey1, audioOversample, audioSampleRate);
|
||||||
|
@ -417,7 +417,7 @@ export class Atari7800 extends BasicMachine implements RasterFrameBased {
|
||||||
// is this scanline visible?
|
// is this scanline visible?
|
||||||
if (visible) {
|
if (visible) {
|
||||||
// do DMA for scanline?
|
// do DMA for scanline?
|
||||||
let dmaClocks = this.maria.doDMA(this.probeDMABus);
|
let dmaClocks = this.maria.doDMA(this.dmaBus);
|
||||||
this.probe.logClocks(dmaClocks >> 2); // TODO: logDMA
|
this.probe.logClocks(dmaClocks >> 2); // TODO: logDMA
|
||||||
mc += dmaClocks;
|
mc += dmaClocks;
|
||||||
// copy line to frame buffer
|
// copy line to frame buffer
|
||||||
|
@ -435,6 +435,7 @@ export class Atari7800 extends BasicMachine implements RasterFrameBased {
|
||||||
// post-DMA clocks
|
// post-DMA clocks
|
||||||
while (mc < colorClocksPerLine) {
|
while (mc < colorClocksPerLine) {
|
||||||
if (this.maria.WSYNC) {
|
if (this.maria.WSYNC) {
|
||||||
|
this.probe.logWait(0);
|
||||||
this.probe.logClocks((colorClocksPerLine - mc) >> 2);
|
this.probe.logClocks((colorClocksPerLine - mc) >> 2);
|
||||||
mc = colorClocksPerLine;
|
mc = colorClocksPerLine;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -10,9 +10,9 @@ import { CONSOL, GTIA, TRIG0 } from "./chips/gtia";
|
||||||
import { POKEY } from "./chips/pokey";
|
import { POKEY } from "./chips/pokey";
|
||||||
|
|
||||||
const ATARI8_KEYMATRIX_INTL_NOSHIFT = [
|
const ATARI8_KEYMATRIX_INTL_NOSHIFT = [
|
||||||
Keys.VK_L, Keys.VK_J, Keys.VK_SEMICOLON, Keys.VK_F1, Keys.VK_F2, Keys.VK_K, Keys.VK_BACK_SLASH, Keys.VK_TILDE,
|
Keys.VK_L, Keys.VK_J, Keys.VK_SEMICOLON, Keys.VK_F4, Keys.VK_F5, Keys.VK_K, Keys.VK_BACK_SLASH, Keys.VK_TILDE,
|
||||||
Keys.VK_O, null, Keys.VK_P, Keys.VK_U, Keys.VK_ENTER, Keys.VK_I, Keys.VK_MINUS2, Keys.VK_EQUALS2,
|
Keys.VK_O, null, Keys.VK_P, Keys.VK_U, Keys.VK_ENTER, Keys.VK_I, Keys.VK_MINUS2, Keys.VK_EQUALS2,
|
||||||
Keys.VK_V, Keys.VK_F8, Keys.VK_C, Keys.VK_F3, Keys.VK_F4, Keys.VK_B, Keys.VK_X, Keys.VK_Z,
|
Keys.VK_V, Keys.VK_F7, Keys.VK_C, Keys.VK_F6, Keys.VK_F4, Keys.VK_B, Keys.VK_X, Keys.VK_Z,
|
||||||
Keys.VK_4, null, Keys.VK_3, Keys.VK_6, Keys.VK_ESCAPE, Keys.VK_5, Keys.VK_2, Keys.VK_1,
|
Keys.VK_4, null, Keys.VK_3, Keys.VK_6, Keys.VK_ESCAPE, Keys.VK_5, Keys.VK_2, Keys.VK_1,
|
||||||
Keys.VK_COMMA, Keys.VK_SPACE, Keys.VK_PERIOD, Keys.VK_N, null, Keys.VK_M, Keys.VK_SLASH, null/*invert*/,
|
Keys.VK_COMMA, Keys.VK_SPACE, Keys.VK_PERIOD, Keys.VK_N, null, Keys.VK_M, Keys.VK_SLASH, null/*invert*/,
|
||||||
Keys.VK_R, null, Keys.VK_E, Keys.VK_Y, Keys.VK_TAB, Keys.VK_T, Keys.VK_W, Keys.VK_Q,
|
Keys.VK_R, null, Keys.VK_E, Keys.VK_Y, Keys.VK_TAB, Keys.VK_T, Keys.VK_W, Keys.VK_Q,
|
||||||
|
@ -26,7 +26,7 @@ var ATARI8_KEYCODE_MAP = makeKeycodeMap([
|
||||||
[Keys.DOWN, 0, 0x2],
|
[Keys.DOWN, 0, 0x2],
|
||||||
[Keys.LEFT, 0, 0x4],
|
[Keys.LEFT, 0, 0x4],
|
||||||
[Keys.RIGHT, 0, 0x8],
|
[Keys.RIGHT, 0, 0x8],
|
||||||
[Keys.VK_SHIFT, 2, 0x1],
|
[{c: 16, n: "Shift", plyr:0, button:0}, 2, 0x1],
|
||||||
/*
|
/*
|
||||||
[Keys.P2_UP, 0, 0x10],
|
[Keys.P2_UP, 0, 0x10],
|
||||||
[Keys.P2_DOWN, 0, 0x20],
|
[Keys.P2_DOWN, 0, 0x20],
|
||||||
|
@ -34,9 +34,9 @@ var ATARI8_KEYCODE_MAP = makeKeycodeMap([
|
||||||
[Keys.P2_RIGHT, 0, 0x80],
|
[Keys.P2_RIGHT, 0, 0x80],
|
||||||
[Keys.P2_A, 3, 0x1],
|
[Keys.P2_A, 3, 0x1],
|
||||||
*/
|
*/
|
||||||
[Keys.START, 3, 0x1], // START
|
[Keys.VK_F1, 3, 0x1], // START
|
||||||
[Keys.SELECT, 3, 0x2], // SELECT
|
[Keys.VK_F2, 3, 0x2], // SELECT
|
||||||
[Keys.OPTION, 3, 0x4], // OPTION
|
[Keys.VK_F3, 3, 0x4], // OPTION
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,6 +72,7 @@ export class Atari800 extends BasicScanlineMachine {
|
||||||
cart_80 = false;
|
cart_80 = false;
|
||||||
cart_a0 = false;
|
cart_a0 = false;
|
||||||
xexdata = null;
|
xexdata = null;
|
||||||
|
keyboard_active = true;
|
||||||
// TODO: save/load vars
|
// TODO: save/load vars
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -89,7 +90,7 @@ export class Atari800 extends BasicScanlineMachine {
|
||||||
this.audioadapter = new TssChannelAdapter(this.audio_pokey.pokey1, this.audioOversample, this.sampleRate);
|
this.audioadapter = new TssChannelAdapter(this.audio_pokey.pokey1, this.audioOversample, this.sampleRate);
|
||||||
this.handler = newKeyboardHandler(
|
this.handler = newKeyboardHandler(
|
||||||
this.inputs, ATARI8_KEYCODE_MAP, this.getKeyboardFunction(), true);
|
this.inputs, ATARI8_KEYCODE_MAP, this.getKeyboardFunction(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
newBus() {
|
newBus() {
|
||||||
return {
|
return {
|
||||||
|
@ -134,7 +135,7 @@ export class Atari800 extends BasicScanlineMachine {
|
||||||
// used by ANTIC
|
// used by ANTIC
|
||||||
readDMA(a) {
|
readDMA(a) {
|
||||||
let v = this.bus.read(a);
|
let v = this.bus.read(a);
|
||||||
this.probe.logVRAMRead(a, v);
|
this.probe.logDMARead(a, v);
|
||||||
this.lastdmabyte = v;
|
this.lastdmabyte = v;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
@ -192,6 +193,8 @@ export class Atari800 extends BasicScanlineMachine {
|
||||||
// ANTIC DMA cycle, update GTIA
|
// ANTIC DMA cycle, update GTIA
|
||||||
if (this.antic.h < 8)
|
if (this.antic.h < 8)
|
||||||
this.gtia.updateGfx(this.antic.h - 1, this.antic.v, this.lastdmabyte); // HALT pin
|
this.gtia.updateGfx(this.antic.h - 1, this.antic.v, this.lastdmabyte); // HALT pin
|
||||||
|
if (this.antic.isWSYNC())
|
||||||
|
this.probe.logWait(0);
|
||||||
this.probe.logClocks(1);
|
this.probe.logClocks(1);
|
||||||
} else {
|
} else {
|
||||||
super.advanceCPU();
|
super.advanceCPU();
|
||||||
|
@ -278,8 +281,9 @@ export class Atari800 extends BasicScanlineMachine {
|
||||||
}
|
}
|
||||||
getKeyboardFunction() {
|
getKeyboardFunction() {
|
||||||
return (o, key, code, flags) => {
|
return (o, key, code, flags) => {
|
||||||
|
if (!this.keyboard_active) return false;
|
||||||
if (flags & (KeyFlags.KeyDown | KeyFlags.KeyUp)) {
|
if (flags & (KeyFlags.KeyDown | KeyFlags.KeyUp)) {
|
||||||
//console.log(o, key, code, flags, hex(this.keycode));
|
console.log(o, key, code, flags, hex(this.keycode));
|
||||||
var keymap = ATARI8_KEYMATRIX_INTL_NOSHIFT;
|
var keymap = ATARI8_KEYMATRIX_INTL_NOSHIFT;
|
||||||
if (key == Keys.VK_F9.c) {
|
if (key == Keys.VK_F9.c) {
|
||||||
this.irq_pokey.generateIRQ(0x80); // break IRQ
|
this.irq_pokey.generateIRQ(0x80); // break IRQ
|
||||||
|
|
|
@ -109,7 +109,9 @@ export class ANTIC {
|
||||||
let s = "";
|
let s = "";
|
||||||
s += "H: " + lpad(state.h, 3) + " V: " + lpad(state.v, 3) + "\n";
|
s += "H: " + lpad(state.h, 3) + " V: " + lpad(state.v, 3) + "\n";
|
||||||
s += "DLIOp: " + hex(state.dliop, 2) + " Lines: " + state.yofs + "/" + state.linesleft;
|
s += "DLIOp: " + hex(state.dliop, 2) + " Lines: " + state.yofs + "/" + state.linesleft;
|
||||||
s += " DMA " + (state.dma_enabled ? "ON " : "off") + "\n";
|
s += " DMA " + (state.dma_enabled ? "ON " : "off")
|
||||||
|
if (state.dma_enabled) s += " idx " + state.dmaidx + " clk " + hex(state.dmaclock)
|
||||||
|
s += "\n"
|
||||||
s += "Addr: " + hex(state.scanaddr, 4) + "\n";
|
s += "Addr: " + hex(state.scanaddr, 4) + "\n";
|
||||||
s += dumpRAM(state.regs, 0, 16).replace('$00', 'Regs');
|
s += dumpRAM(state.regs, 0, 16).replace('$00', 'Regs');
|
||||||
return s;
|
return s;
|
||||||
|
@ -138,6 +140,7 @@ export class ANTIC {
|
||||||
processDLIEntry() {
|
processDLIEntry() {
|
||||||
if (this.mode == 0) { // N Blank Lines
|
if (this.mode == 0) { // N Blank Lines
|
||||||
this.linesleft = ((this.dliop >> 4) & 7) + 1;
|
this.linesleft = ((this.dliop >> 4) & 7) + 1;
|
||||||
|
this.dmaclock = 0;
|
||||||
} else {
|
} else {
|
||||||
this.linesleft = MODE_LINES[this.mode];
|
this.linesleft = MODE_LINES[this.mode];
|
||||||
this.period = MODE_PERIOD[this.mode];
|
this.period = MODE_PERIOD[this.mode];
|
||||||
|
@ -150,6 +153,7 @@ export class ANTIC {
|
||||||
this.linesleft = 1; //(248 - this.v) & 0xff; // TODO?
|
this.linesleft = 1; //(248 - this.v) & 0xff; // TODO?
|
||||||
this.dma_enabled = false;
|
this.dma_enabled = false;
|
||||||
}
|
}
|
||||||
|
this.dmaclock = 0;
|
||||||
} else if (this.lms) {
|
} else if (this.lms) {
|
||||||
this.scanaddr = this.dlarg_lo + (this.dlarg_hi << 8);
|
this.scanaddr = this.dlarg_lo + (this.dlarg_hi << 8);
|
||||||
//console.log('scanaddr', hex(this.scanaddr));
|
//console.log('scanaddr', hex(this.scanaddr));
|
||||||
|
@ -225,9 +229,12 @@ export class ANTIC {
|
||||||
isMissileDMAEnabled() {
|
isMissileDMAEnabled() {
|
||||||
return this.regs[DMACTL] & 0b1100;
|
return this.regs[DMACTL] & 0b1100;
|
||||||
}
|
}
|
||||||
|
isWSYNC() {
|
||||||
|
return this.regs[WSYNC] != 0;
|
||||||
|
}
|
||||||
|
|
||||||
clockPulse(): boolean {
|
clockPulse(): boolean {
|
||||||
let did_dma = this.regs[WSYNC] != 0;
|
let did_dma = this.isWSYNC();
|
||||||
if (!this.isVisibleScanline()) {
|
if (!this.isVisibleScanline()) {
|
||||||
this.doVBlank();
|
this.doVBlank();
|
||||||
} else {
|
} else {
|
||||||
|
@ -285,7 +292,7 @@ export class ANTIC {
|
||||||
this.output = 0; // background color (TODO: only for blank lines)
|
this.output = 0; // background color (TODO: only for blank lines)
|
||||||
if (this.mode >= 2 && this.period) {
|
if (this.mode >= 2 && this.period) {
|
||||||
let candma = this.h <= LAST_DMA_H;
|
let candma = this.h <= LAST_DMA_H;
|
||||||
this.dmaclock <<= 1;
|
this.dmaclock = (this.dmaclock << 1) & 0x1ff;
|
||||||
if (this.dmaclock & (1 << this.period)) {
|
if (this.dmaclock & (1 << this.period)) {
|
||||||
this.dmaclock |= 1;
|
this.dmaclock |= 1;
|
||||||
}
|
}
|
||||||
|
@ -346,6 +353,7 @@ export class ANTIC {
|
||||||
this.dma_enabled = this.dlDMAEnabled() != 0;
|
this.dma_enabled = this.dlDMAEnabled() != 0;
|
||||||
}
|
}
|
||||||
this.output = 2; // blank
|
this.output = 2; // blank
|
||||||
|
this.dmaclock = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
doPlayerMissileDMA(section: number) {
|
doPlayerMissileDMA(section: number) {
|
||||||
|
|
|
@ -80,6 +80,7 @@ export class GTIA {
|
||||||
this.regs.fill(0);
|
this.regs.fill(0);
|
||||||
this.readregs.fill(0); // TODO?
|
this.readregs.fill(0); // TODO?
|
||||||
this.readregs[0x14] = 0xf; // NTSC
|
this.readregs[0x14] = 0xf; // NTSC
|
||||||
|
this.readregs.fill(0xf, 0x15); // default value for write-only regs
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
}
|
}
|
||||||
saveState() {
|
saveState() {
|
||||||
|
|
|
@ -397,7 +397,7 @@ class VCSPlatform extends BasePlatform {
|
||||||
bus.oldWrite = bus.write;
|
bus.oldWrite = bus.write;
|
||||||
bus.write = function(a,v) {
|
bus.write = function(a,v) {
|
||||||
this.oldWrite(a,v);
|
this.oldWrite(a,v);
|
||||||
if (a == 0x02) probe.logIllegal(a); // WSYNC
|
if (a == 0x02) probe.logWait(a); // WSYNC
|
||||||
else if (a < 0x80) probe.logIOWrite(a,v);
|
else if (a < 0x80) probe.logIOWrite(a,v);
|
||||||
else if (a > 0x280 && a < 0x300) probe.logIOWrite(a,v);
|
else if (a > 0x280 && a < 0x300) probe.logIOWrite(a,v);
|
||||||
else probe.logWrite(a,v);
|
else probe.logWrite(a,v);
|
||||||
|
|
|
@ -367,16 +367,16 @@ describe('Platform Replay', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('Should run atari5200', async () => {
|
it('Should run atari5200', async () => {
|
||||||
await testPlatform('atari8-5200', 'acid5200.rom', 1100, (platform, frameno) => {
|
await testPlatform('atari8-5200', 'acid5200.rom', 1200, (platform, frameno) => {
|
||||||
if (frameno == 999) {
|
if (frameno == 1199) {
|
||||||
let s = '';
|
let s = '';
|
||||||
for (let i=0; i<40; i++) {
|
for (let i=0; i<40; i++) {
|
||||||
let c = platform.readAddress(0x722+i) & 0x7f;
|
let c = platform.readAddress(0x722+i-40) & 0x7f;
|
||||||
if (c < 0x40) c += 0x20;
|
if (c < 0x40) c += 0x20;
|
||||||
s += String.fromCharCode(c);
|
s += String.fromCharCode(c);
|
||||||
}
|
}
|
||||||
s = s.trim();
|
s = s.trim();
|
||||||
assert.equal(s, "Passed: 12 Failed: 34 Skipped: 1");
|
assert.equal(s, "Passed: 13 Failed: 33 Skipped: 1");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue