1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-06-12 18:42:14 +00:00

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 { .tooltiptrack {
background-color: #666; background-color: #666;
color: #fff; color: #fff;
text-align: center; text-align: left;
border: 2px solid #999; border: 2px solid #999;
border-radius: 8px; border-radius: 8px;
padding: 5px; padding: 5px;

View File

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

View File

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

View File

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