7800: TIA/RIOT wastes a cycle; fixed NES probe; messed with views

This commit is contained in:
Steven Hugg 2019-08-27 13:26:25 -04:00
parent ca7d488f1c
commit 236c4bd0dd
4 changed files with 72 additions and 40 deletions

View File

@ -51,7 +51,7 @@
.tooltiptrack {
background-color: #666;
color: #fff;
text-align: center;
text-align: left;
border: 2px solid #999;
border-radius: 8px;
padding: 5px;

View File

@ -1,6 +1,6 @@
import { MOS6502, MOS6502State } from "../cpu/MOS6502";
import { BasicMachine, Bus, ProbeAll } from "../devices";
import { BasicMachine, RasterFrameBased, Bus, ProbeAll } from "../devices";
import { KeyFlags, newAddressDecoder, padBytes, Keys, makeKeycodeMap, newKeyboardHandler, EmuHalt, dumpRAM } from "../emu";
import { TssChannelAdapter, MasterAudio, POKEYDeviceChannel } from "../audio";
import { hex, rgb2bgr } from "../util";
@ -201,7 +201,6 @@ class MARIA {
let dlofs = this.dlstart & 0xff;
do {
// read DL entry
//profiler && profiler.logRead(dlhi + ((dlofs+0) & 0x1ff));
let b0 = bus.read(dlhi + ((dlofs+0) & 0x1ff));
let b1 = bus.read(dlhi + ((dlofs+1) & 0x1ff));
if (b1 == 0) break; // end of DL
@ -293,7 +292,7 @@ class MARIA {
// Atari 7800
export class Atari7800 extends BasicMachine {
export class Atari7800 extends BasicMachine implements RasterFrameBased {
cpuFrequency = 1789772;
canvasWidth = 320;
@ -312,6 +311,7 @@ export class Atari7800 extends BasicMachine {
audioadapter;
lastFrameCycles = 0;
xtracyc = 0;
read : (a:number) => number;
write : (a:number, v:number) => void;
@ -322,26 +322,26 @@ export class Atari7800 extends BasicMachine {
super();
this.cpu = new MOS6502();
this.read = newAddressDecoder([
[0x0008, 0x000d, 0x0f, (a) => { return this.readInput(a); }],
[0x0000, 0x001f, 0x1f, (a) => { return this.tia.read(a); }],
[0x0020, 0x003f, 0x1f, (a) => { return this.maria.read(a); /*this.profiler && this.profiler.logRead(a+0x20);*/ }],
[0x0008, 0x000d, 0x0f, (a) => { this.xtracyc++; return this.readInput(a); }],
[0x0000, 0x001f, 0x1f, (a) => { this.xtracyc++; return this.tia.read(a); }],
[0x0020, 0x003f, 0x1f, (a) => { return this.maria.read(a); }],
[0x0040, 0x00ff, 0xff, (a) => { return this.ram[a + 0x800]; }],
[0x0100, 0x013f, 0xff, (a) => { return this.read(a); }], // shadow
[0x0140, 0x01ff, 0x1ff, (a) => { return this.ram[a + 0x800]; }],
[0x0280, 0x02ff, 0x3, (a) => { return this.inputs[a]; }],
[0x0280, 0x02ff, 0x3, (a) => { this.xtracyc++; return this.inputs[a]; }],
[0x1800, 0x27ff, 0xffff, (a) => { return this.ram[a - 0x1800]; }],
[0x2800, 0x3fff, 0x7ff, (a) => { return this.read(a | 0x2000); }], // shadow
[0x4000, 0xffff, 0xffff, (a) => { return this.rom ? this.rom[a - 0x4000] : 0; }],
[0x0000, 0xffff, 0xffff, (a) => { return 0; }], // TODO
]);
this.write = newAddressDecoder([
[0x0015, 0x001A, 0x1f, (a,v) => { this.pokey1.setTIARegister(a, v); }],
[0x0000, 0x001f, 0x1f, (a,v) => { this.tia.write(a,v); /*this.profiler && this.profiler.logWrite(a);*/ }],
[0x0020, 0x003f, 0x1f, (a,v) => { this.maria.write(a,v); /*this.profiler && this.profiler.logWrite(a+0x20);*/ }],
[0x0015, 0x001A, 0x1f, (a,v) => { this.xtracyc++; this.pokey1.setTIARegister(a, v); }],
[0x0000, 0x001f, 0x1f, (a,v) => { this.xtracyc++; this.tia.write(a,v); }],
[0x0020, 0x003f, 0x1f, (a,v) => { this.maria.write(a,v); }],
[0x0040, 0x00ff, 0xff, (a,v) => { this.ram[a + 0x800] = v; }],
[0x0100, 0x013f, 0xff, (a,v) => { this.write(a,v); }], // shadow
[0x0140, 0x01ff, 0x1ff, (a,v) => { this.ram[a + 0x800] = v; }],
[0x0280, 0x02ff, 0x3, (a,v) => { this.regs6532[a] = v; /*TODO*/ }],
[0x0280, 0x02ff, 0x3, (a,v) => { this.xtracyc++; this.regs6532[a] = v; /*TODO*/ }],
[0x1800, 0x27ff, 0xffff, (a,v) => { this.ram[a - 0x1800] = v; }],
[0x2800, 0x3fff, 0x7ff, (a,v) => { this.write(a | 0x2000, v); }], // shadow
[0xbfff, 0xbfff, 0xffff, (a,v) => { }], // TODO: bank switching?
@ -357,7 +357,6 @@ export class Atari7800 extends BasicMachine {
readConst(a) { return this.read(a); } //TODO?
readInput(a:number) : number {
//this.profiler && this.profiler.logRead(a+0x20);
switch (a) {
case 0xc: return ~this.inputs[0x8] & 0x80; //INPT4
case 0xd: return ~this.inputs[0x9] & 0x80; //INPT5
@ -365,8 +364,15 @@ export class Atari7800 extends BasicMachine {
}
}
//TODO this.bios = new Uint8Array(0x1000);
// TODO: TIA access wastes a cycle
advanceCPU() : number {
var clk = super.advanceCPU();
if (this.xtracyc) {
clk += this.xtracyc;
this.probe.logClocks(this.xtracyc);
this.xtracyc = 0;
}
return clk;
}
advanceFrame(maxClocks, trap) : number {
var idata = this.pixels;
@ -446,11 +452,7 @@ export class Atari7800 extends BasicMachine {
if (data.length == 0xc080) data = data.slice(0x80); // strip header
this.rom = padBytes(data, this.defaultROMSize, true);
}
/*
loadBIOS(data) {
this.bios = padBytes(data, 0x1000);
}
*/
reset() {
super.reset();
this.tia.reset();
@ -458,10 +460,9 @@ export class Atari7800 extends BasicMachine {
this.inputs.fill(0x0);
this.inputs[SWCHA] = 0xff;
this.inputs[SWCHB] = 1+2+8;
//this.cpu.advanceClock(); // TODO: needed for test to pass?
//this.cpu.advanceClock(); // needed for test to pass?
}
// TODO: don't log if profiler active
readAddress(addr : number) {
return this.read(addr) | 0;
}

View File

@ -222,7 +222,7 @@ class JSNESPlatform extends Base6502Platform implements Platform, Probeable {
this.nes.loadROM(romstr);
this.frameindex = 0;
// intercept bus calls, unless we did it already
if (!this.nes.mmap.load) {
if (!this.nes.mmap.haveProxied) {
var oldload = this.nes.mmap.load.bind(this.nes.mmap);
var oldwrite = this.nes.mmap.write.bind(this.nes.mmap);
//var oldregLoad = this.nes.mmap.regLoad.bind(this.nes.mmap);
@ -247,6 +247,7 @@ class JSNESPlatform extends Base6502Platform implements Platform, Probeable {
oldregWrite(addr, val);
}
*/
this.nes.mmap.haveProxied = true;
}
}
newCodeAnalyzer() {
@ -281,9 +282,6 @@ class JSNESPlatform extends Base6502Platform implements Platform, Probeable {
getRasterScanline() : number {
return this.nes.ppu.scanline;
}
readVRAMAddress(addr : number) : number {
return this.nes.ppu.vramMem[addr & 0x7fff];
}
getCPUState() {
var c = this.nes.cpu.toJSON();
@ -328,6 +326,9 @@ class JSNESPlatform extends Base6502Platform implements Platform, Probeable {
readAddress(addr) {
return this.nes.cpu.mem[addr] & 0xff;
}
readVRAMAddress(addr : number) : number {
return this.nes.ppu.vramMem[addr & 0x7fff] & 0xff;
}
copy6502REGvars(c) {
c.T = 0;
c.PC = c.REG_PC;

View File

@ -940,7 +940,7 @@ abstract class ProbeViewBase {
canvas.height = height;
canvas.classList.add('pixelated');
canvas.style.width = '100%';
canvas.style.height = '100vh'; // i hate css
canvas.style.height = '90vh'; // i hate css
canvas.style.backgroundColor = 'black';
canvas.style.cursor = 'crosshair';
canvas.onmousemove = (e) => {
@ -998,14 +998,12 @@ abstract class ProbeViewBase {
ctx.globalAlpha = 1.0;
ctx.globalCompositeOperation = 'lighter';
}
tick() {
redraw( eventfn:(op,addr,col,row) => void ) {
var p = this.probe;
if (!p || !p.idx) return; // if no probe, or if empty
var row=0;
var col=0;
var ctx = this.ctx;
this.clear();
for (var i=0; i<p.idx; i++) {
var word = p.buf[i];
var addr = word & 0xffffff;
@ -1015,11 +1013,17 @@ abstract class ProbeViewBase {
case ProbeFlags.FRAME: row=0; col=0; break;
case ProbeFlags.CLOCKS: col += addr; break;
default:
this.drawEvent(op, addr, col, row);
eventfn(op, addr, col, row);
break;
}
}
if (!p.singleFrame) p.reset();
}
tick() {
var ctx = this.ctx;
this.clear();
this.redraw(this.drawEvent.bind(this));
if (this.probe && !this.probe.singleFrame) this.probe.reset();
}
setContextForOp(op) {
@ -1048,8 +1052,8 @@ abstract class ProbeBitmapViewBase extends ProbeViewBase {
var width = 160;
var height = 262;
try {
width = platform['machine']['cpuCyclesPerLine'] || 160; // TODO
height = platform['machine']['numTotalScanlines'] || 262; // TODO
width = Math.ceil(platform['machine']['cpuCyclesPerLine']) || 256; // TODO
height = Math.ceil(platform['machine']['numTotalScanlines']) || 262; // TODO
} catch (e) {
}
return this.createCanvas(parent, width, height);
@ -1058,6 +1062,33 @@ abstract class ProbeBitmapViewBase extends ProbeViewBase {
this.imageData = this.ctx.createImageData(this.canvas.width, this.canvas.height);
this.datau32 = new Uint32Array(this.imageData.data.buffer);
}
getTooltipText(x:number, y:number) : string {
x = x|0;
y = y|0;
var s = "";
this.redraw( (op,addr,col,row) => {
if (col == x && row == y) {
s += "\n" + this.opToString(op, addr);
}
} );
return '(' + x + ',' + y + ')' + s;
}
opToString(op:number, addr:number) {
var s = "";
switch (op) {
case ProbeFlags.EXECUTE: s = "Exec"; break;
case ProbeFlags.MEM_READ: s = "Read"; break;
case ProbeFlags.MEM_WRITE: s = "Write"; break;
case ProbeFlags.IO_READ: s = "IO Read"; break;
case ProbeFlags.IO_WRITE: s = "IO Write"; break;
case ProbeFlags.VRAM_READ: s = "VRAM Read"; break;
case ProbeFlags.VRAM_WRITE: s = "VRAM Write"; break;
case ProbeFlags.INTERRUPT: s = "Interrupt"; break;
default: s = ""; break;
}
return s + " $" + hex(addr);
}
refresh() {
this.tick();
this.datau32.fill(0xff000000);
@ -1115,6 +1146,7 @@ export class AddressHeatMapView extends ProbeBitmapViewBase implements ProjectVi
}
}
/*
export class RasterHeatMapView extends ProbeBitmapViewBase implements ProjectView {
drawEvent(op, addr, col, row) {
@ -1123,22 +1155,20 @@ export class RasterHeatMapView extends ProbeBitmapViewBase implements ProjectVie
if (!rgb) return;
var iofs = col + row * this.canvas.width;
var data = this.datau32[iofs];
data = (data & 0x7f7f7f) << 1;
data = data | rgb | 0xff000000;
this.datau32[iofs] = data;
}
}
*/
export class RasterPCHeatMapView extends ProbeBitmapViewBase implements ProjectView {
drawEvent(op, addr, col, row) {
// if (op != ProbeFlags.EXECUTE) return;
var iofs = col + row * this.canvas.width;
//var rgb = addr << 8;
var rgb = this.getOpRGB(op) << 1;
var rgb = this.getOpRGB(op);
if (!rgb) return;
var data = this.datau32[iofs];
rgb |= addr & 0x3f3f;
data = data | rgb | 0xff000000;
this.datau32[iofs] = data;
}