atari8: wait/dma events, new kbd

This commit is contained in:
Steven Hugg 2022-09-03 15:00:43 -05:00
parent 56e8fca270
commit 5735135add
13 changed files with 87 additions and 39 deletions

View File

@ -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;

View File

@ -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">&#x2190;&#x2191;&#x2193;&#x2192;</span> Joystick</span> <span class="control-def"><span class="control-key">&#x2190;&#x2191;&#x2193;&#x2192;</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">

View File

@ -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;

View File

@ -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));
} }

View File

@ -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"},

View File

@ -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++) {

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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) {

View File

@ -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() {

View File

@ -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);

View File

@ -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");
} }
}); });
}); });