mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-12-23 03:29:39 +00:00
7800: TIA/RIOT wastes a cycle; fixed NES probe; messed with views
This commit is contained in:
parent
ca7d488f1c
commit
236c4bd0dd
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
58
src/views.ts
58
src/views.ts
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user