Use debugger from submodule
This commit is contained in:
parent
1e79d9d59d
commit
45a5e63cf9
|
@ -12,6 +12,8 @@ import { Apple2IOState } from './apple2io';
|
||||||
import {
|
import {
|
||||||
CPU6502,
|
CPU6502,
|
||||||
CpuState,
|
CpuState,
|
||||||
|
Debugger,
|
||||||
|
DebuggerContainer,
|
||||||
FLAVOR_6502,
|
FLAVOR_6502,
|
||||||
FLAVOR_ROCKWELL_65C02,
|
FLAVOR_ROCKWELL_65C02,
|
||||||
} from '@whscullin/cpu6502';
|
} from '@whscullin/cpu6502';
|
||||||
|
@ -19,7 +21,6 @@ import MMU, { MMUState } from './mmu';
|
||||||
import RAM, { RAMState } from './ram';
|
import RAM, { RAMState } from './ram';
|
||||||
|
|
||||||
import SYMBOLS from './symbols';
|
import SYMBOLS from './symbols';
|
||||||
import Debugger, { DebuggerContainer } from './debugger';
|
|
||||||
|
|
||||||
import { ReadonlyUint8Array, Restorable, rom } from './types';
|
import { ReadonlyUint8Array, Restorable, rom } from './types';
|
||||||
import { processGamepad } from './ui/gamepad';
|
import { processGamepad } from './ui/gamepad';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
import { Debugger } from '@whscullin/cpu6502';
|
||||||
import Disk2 from 'js/cards/disk2';
|
import Disk2 from 'js/cards/disk2';
|
||||||
import SmartPort from 'js/cards/smartport';
|
import SmartPort from 'js/cards/smartport';
|
||||||
import Debugger from 'js/debugger';
|
|
||||||
import {
|
import {
|
||||||
BlockFormat,
|
BlockFormat,
|
||||||
BLOCK_FORMATS,
|
BLOCK_FORMATS,
|
||||||
|
@ -245,7 +245,7 @@ export class SmartStorageBroker implements MassStorage<unknown> {
|
||||||
constructor(
|
constructor(
|
||||||
private disk2: Disk2,
|
private disk2: Disk2,
|
||||||
private smartPort: SmartPort
|
private smartPort: SmartPort
|
||||||
) {}
|
) { }
|
||||||
|
|
||||||
setBinary(
|
setBinary(
|
||||||
driveNo: DriveNumber,
|
driveNo: DriveNumber,
|
||||||
|
|
380
js/debugger.ts
380
js/debugger.ts
|
@ -1,380 +0,0 @@
|
||||||
import { debug, toHex } from './util';
|
|
||||||
import { byte, word } from './types';
|
|
||||||
|
|
||||||
import { CPU6502, DebugInfo, flags, sizes } from '@whscullin/cpu6502';
|
|
||||||
|
|
||||||
export interface DebuggerContainer {
|
|
||||||
run: () => void;
|
|
||||||
stop: () => void;
|
|
||||||
isRunning: () => boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
type symbols = { [key: number]: string };
|
|
||||||
type breakpointFn = (info: DebugInfo) => boolean;
|
|
||||||
|
|
||||||
const alwaysBreak = (_info: DebugInfo) => {
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const dumpStatusRegister = (sr: byte) =>
|
|
||||||
[
|
|
||||||
sr & flags.N ? 'N' : '-',
|
|
||||||
sr & flags.V ? 'V' : '-',
|
|
||||||
sr & flags.X ? 'X' : '-',
|
|
||||||
sr & flags.B ? 'B' : '-',
|
|
||||||
sr & flags.D ? 'D' : '-',
|
|
||||||
sr & flags.I ? 'I' : '-',
|
|
||||||
sr & flags.Z ? 'Z' : '-',
|
|
||||||
sr & flags.C ? 'C' : '-',
|
|
||||||
].join('');
|
|
||||||
|
|
||||||
export default class Debugger {
|
|
||||||
private verbose = false;
|
|
||||||
private maxTrace = 256;
|
|
||||||
private trace: DebugInfo[] = [];
|
|
||||||
private breakpoints: Map<word, breakpointFn> = new Map();
|
|
||||||
private symbols: symbols = {};
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private cpu: CPU6502,
|
|
||||||
private container: DebuggerContainer
|
|
||||||
) {}
|
|
||||||
|
|
||||||
stepCycles(cycles: number) {
|
|
||||||
this.cpu.stepCyclesDebug(this.verbose ? 1 : cycles, () => {
|
|
||||||
const info = this.cpu.getDebugInfo();
|
|
||||||
|
|
||||||
if (this.breakpoints.get(info.pc)?.(info)) {
|
|
||||||
debug('breakpoint', this.printDebugInfo(info));
|
|
||||||
this.container.stop();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (this.verbose) {
|
|
||||||
debug(this.printDebugInfo(info));
|
|
||||||
} else {
|
|
||||||
this.updateTrace(info);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
break = () => {
|
|
||||||
this.container.stop();
|
|
||||||
};
|
|
||||||
|
|
||||||
step = () => {
|
|
||||||
this.cpu.step(() => {
|
|
||||||
const info = this.cpu.getDebugInfo();
|
|
||||||
debug(this.printDebugInfo(info));
|
|
||||||
this.updateTrace(info);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
continue = () => {
|
|
||||||
this.container.run();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restart at a given memory address.
|
|
||||||
*
|
|
||||||
* @param address Address to start execution
|
|
||||||
*/
|
|
||||||
|
|
||||||
runAt = (address: word) => {
|
|
||||||
this.cpu.reset();
|
|
||||||
this.cpu.setPC(address);
|
|
||||||
};
|
|
||||||
|
|
||||||
isRunning = () => this.container.isRunning();
|
|
||||||
|
|
||||||
setVerbose = (verbose: boolean) => {
|
|
||||||
this.verbose = verbose;
|
|
||||||
};
|
|
||||||
|
|
||||||
setMaxTrace = (maxTrace: number) => {
|
|
||||||
this.maxTrace = maxTrace;
|
|
||||||
};
|
|
||||||
|
|
||||||
getTrace = (count?: number) => {
|
|
||||||
return this.trace
|
|
||||||
.slice(count ? -count : undefined)
|
|
||||||
.map(this.printDebugInfo)
|
|
||||||
.join('\n');
|
|
||||||
};
|
|
||||||
|
|
||||||
printTrace = (count?: number) => {
|
|
||||||
debug(this.getTrace(count));
|
|
||||||
};
|
|
||||||
|
|
||||||
getStack = (size?: number) => {
|
|
||||||
const { sp } = this.cpu.getDebugInfo();
|
|
||||||
const stack = [];
|
|
||||||
|
|
||||||
let max = 255;
|
|
||||||
let min = 0;
|
|
||||||
if (size) {
|
|
||||||
if (sp - 3 >= 255 - size) {
|
|
||||||
min = Math.max(255 - size + 1, 0);
|
|
||||||
} else {
|
|
||||||
max = Math.min(sp + size - 4, 255);
|
|
||||||
min = Math.max(sp - 3, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let addr = max; addr >= min; addr--) {
|
|
||||||
const isSP = addr === sp ? '*' : ' ';
|
|
||||||
const addrStr = `$${toHex(0x0100 + addr)}`;
|
|
||||||
const valStr = toHex(this.cpu.read(0x01, addr));
|
|
||||||
if (!size || (sp + size > addr && addr > sp - size)) {
|
|
||||||
stack.push(`${isSP} ${addrStr} ${valStr}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return stack.join('\n');
|
|
||||||
};
|
|
||||||
|
|
||||||
setBreakpoint = (addr: word, exp?: breakpointFn) => {
|
|
||||||
this.breakpoints.set(addr, exp || alwaysBreak);
|
|
||||||
};
|
|
||||||
|
|
||||||
clearBreakpoint = (addr: word) => {
|
|
||||||
this.breakpoints.delete(addr);
|
|
||||||
};
|
|
||||||
|
|
||||||
listBreakpoints = () => {
|
|
||||||
for (const [addr, fn] of this.breakpoints.entries()) {
|
|
||||||
debug(toHex(addr, 4), fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
addSymbols = (symbols: symbols) => {
|
|
||||||
this.symbols = { ...this.symbols, ...symbols };
|
|
||||||
};
|
|
||||||
|
|
||||||
printDebugInfo = (info: DebugInfo) => {
|
|
||||||
const { pc, cmd } = info;
|
|
||||||
const symbol = this.padWithSymbol(pc);
|
|
||||||
|
|
||||||
return [
|
|
||||||
toHex(pc, 4),
|
|
||||||
'- ',
|
|
||||||
symbol,
|
|
||||||
this.dumpRegisters(info),
|
|
||||||
' ',
|
|
||||||
this.dumpRawOp(cmd),
|
|
||||||
' ',
|
|
||||||
this.dumpOp(pc, cmd),
|
|
||||||
].join('');
|
|
||||||
};
|
|
||||||
|
|
||||||
dumpPC = (pc: word) => {
|
|
||||||
const b = this.cpu.read(pc);
|
|
||||||
const op = this.cpu.getOpInfo(b);
|
|
||||||
const size = sizes[op.mode];
|
|
||||||
let result = toHex(pc, 4) + '- ';
|
|
||||||
|
|
||||||
result += this.padWithSymbol(pc);
|
|
||||||
|
|
||||||
const cmd = new Array<number>(size);
|
|
||||||
for (let idx = 0, jdx = pc; idx < size; idx++, jdx++) {
|
|
||||||
cmd[idx] = this.cpu.read(jdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
result += this.dumpRawOp(cmd) + ' ' + this.dumpOp(pc, cmd);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
dumpRegisters = (debugInfo?: DebugInfo) => {
|
|
||||||
if (debugInfo === undefined) {
|
|
||||||
debugInfo = this.cpu.getDebugInfo();
|
|
||||||
}
|
|
||||||
const { ar, xr, yr, sr, sp } = debugInfo;
|
|
||||||
return [
|
|
||||||
'A=' + toHex(ar),
|
|
||||||
' X=' + toHex(xr),
|
|
||||||
' Y=' + toHex(yr),
|
|
||||||
' P=' + toHex(sr),
|
|
||||||
' S=' + toHex(sp),
|
|
||||||
' ',
|
|
||||||
dumpStatusRegister(sr),
|
|
||||||
].join('');
|
|
||||||
};
|
|
||||||
|
|
||||||
dumpPage = (start: byte, end?: byte) => {
|
|
||||||
let result = '';
|
|
||||||
if (end === undefined) {
|
|
||||||
end = start;
|
|
||||||
}
|
|
||||||
for (let page = start; page <= end; page++) {
|
|
||||||
for (let idx = 0; idx < 16; idx++) {
|
|
||||||
result += toHex(page) + toHex(idx << 4) + ': ';
|
|
||||||
for (let jdx = 0; jdx < 16; jdx++) {
|
|
||||||
const b = this.cpu.read(page, idx * 16 + jdx);
|
|
||||||
result += toHex(b) + ' ';
|
|
||||||
}
|
|
||||||
result += ' ';
|
|
||||||
for (let jdx = 0; jdx < 16; jdx++) {
|
|
||||||
const b = this.cpu.read(page, idx * 16 + jdx) & 0x7f;
|
|
||||||
if (b >= 0x20 && b < 0x7f) {
|
|
||||||
result += String.fromCharCode(b);
|
|
||||||
} else {
|
|
||||||
result += '.';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result += '\n';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a range of memory. Will wrap at memory limit.
|
|
||||||
*
|
|
||||||
* @param address Starting address to read memory
|
|
||||||
* @param length Length of memory to read.
|
|
||||||
* @returns Byte array containing memory
|
|
||||||
*/
|
|
||||||
getMemory(address: word, length: word) {
|
|
||||||
const bytes = new Uint8Array(length);
|
|
||||||
for (let idx = 0; idx < length; idx++) {
|
|
||||||
address &= 0xffff;
|
|
||||||
bytes[idx] = this.cpu.read(address++);
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a range of memory. Will wrap at memory limit.
|
|
||||||
*
|
|
||||||
* @param address Starting address to write memory
|
|
||||||
* @param bytes Data to write
|
|
||||||
*/
|
|
||||||
setMemory(address: word, bytes: Uint8Array) {
|
|
||||||
for (const byte of bytes) {
|
|
||||||
address &= 0xffff;
|
|
||||||
this.cpu.write(address++, byte);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
list = (pc: word) => {
|
|
||||||
const results = [];
|
|
||||||
for (let idx = 0; idx < 20; idx++) {
|
|
||||||
const b = this.cpu.read(pc);
|
|
||||||
const op = this.cpu.getOpInfo(b);
|
|
||||||
results.push(this.dumpPC(pc));
|
|
||||||
pc += sizes[op.mode];
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
};
|
|
||||||
|
|
||||||
private updateTrace(info: DebugInfo) {
|
|
||||||
this.trace.push(info);
|
|
||||||
if (this.trace.length > this.maxTrace) {
|
|
||||||
this.trace.shift();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private padWithSymbol(pc: word): string {
|
|
||||||
const padding = ' ';
|
|
||||||
const symbol = this.symbols[pc];
|
|
||||||
|
|
||||||
let result: string = padding;
|
|
||||||
if (symbol) {
|
|
||||||
result = `${symbol}${padding.substring(symbol.length)}`;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private dumpRawOp(parts: byte[]) {
|
|
||||||
const result = new Array(4);
|
|
||||||
for (let idx = 0; idx < 4; idx++) {
|
|
||||||
if (idx < parts.length) {
|
|
||||||
result[idx] = toHex(parts[idx]);
|
|
||||||
} else {
|
|
||||||
result[idx] = ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result.join(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
private dumpOp(pc: word, parts: byte[]) {
|
|
||||||
const op = this.cpu.getOpInfo(parts[0]);
|
|
||||||
const lsb = parts[1];
|
|
||||||
const msb = parts[2];
|
|
||||||
const addr = (msb << 8) | lsb;
|
|
||||||
let val;
|
|
||||||
let off;
|
|
||||||
const toHexOrSymbol = (v: word, n?: number) =>
|
|
||||||
this.symbols[v] || '$' + toHex(v, n);
|
|
||||||
|
|
||||||
let result = op.name + ' ';
|
|
||||||
switch (op.mode) {
|
|
||||||
case 'implied':
|
|
||||||
break;
|
|
||||||
case 'immediate':
|
|
||||||
result += `#${toHexOrSymbol(lsb)}`;
|
|
||||||
break;
|
|
||||||
case 'absolute':
|
|
||||||
result += `${toHexOrSymbol(addr, 4)}`;
|
|
||||||
break;
|
|
||||||
case 'zeroPage':
|
|
||||||
result += `${toHexOrSymbol(lsb)}`;
|
|
||||||
break;
|
|
||||||
case 'relative':
|
|
||||||
{
|
|
||||||
off = lsb;
|
|
||||||
if (off > 127) {
|
|
||||||
off -= 256;
|
|
||||||
}
|
|
||||||
pc += off + 2;
|
|
||||||
result += `${toHexOrSymbol(pc, 4)} (${off})`;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'absoluteX':
|
|
||||||
result += `${toHexOrSymbol(addr, 4)},X`;
|
|
||||||
break;
|
|
||||||
case 'absoluteY':
|
|
||||||
result += `${toHexOrSymbol(addr, 4)},Y`;
|
|
||||||
break;
|
|
||||||
case 'zeroPageX':
|
|
||||||
result += `${toHexOrSymbol(lsb)},X`;
|
|
||||||
break;
|
|
||||||
case 'zeroPageY':
|
|
||||||
result += `${toHexOrSymbol(lsb)},Y`;
|
|
||||||
break;
|
|
||||||
case 'absoluteIndirect':
|
|
||||||
result += `(${toHexOrSymbol(addr, 4)})`;
|
|
||||||
break;
|
|
||||||
case 'zeroPageXIndirect':
|
|
||||||
result += `(${toHexOrSymbol(lsb)},X)`;
|
|
||||||
break;
|
|
||||||
case 'zeroPageIndirectY':
|
|
||||||
result += `(${toHexOrSymbol(lsb)},),Y`;
|
|
||||||
break;
|
|
||||||
case 'accumulator':
|
|
||||||
result += 'A';
|
|
||||||
break;
|
|
||||||
case 'zeroPageIndirect':
|
|
||||||
result += `(${toHexOrSymbol(lsb)})`;
|
|
||||||
break;
|
|
||||||
case 'absoluteXIndirect':
|
|
||||||
result += `(${toHexOrSymbol(addr, 4)},X)`;
|
|
||||||
break;
|
|
||||||
case 'zeroPage_relative':
|
|
||||||
val = lsb;
|
|
||||||
off = msb;
|
|
||||||
if (off > 127) {
|
|
||||||
off -= 256;
|
|
||||||
}
|
|
||||||
pc += off + 2;
|
|
||||||
result += `${toHexOrSymbol(val)},${toHexOrSymbol(
|
|
||||||
pc,
|
|
||||||
4
|
|
||||||
)} (${off})`;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 4e1031d1bfeaa930b95292269e02d5c31a3440a8
|
Subproject commit b14cb8a0e495d99877c2bef9f31bfadea6e6b68a
|
|
@ -1,103 +0,0 @@
|
||||||
import { CPU6502 } from '@whscullin/cpu6502';
|
|
||||||
import Debugger, { DebuggerContainer } from '../../js/debugger';
|
|
||||||
import { MemoryPages } from '../../js/types';
|
|
||||||
import { TestMemory } from '../util/memory';
|
|
||||||
import { bios } from '../util/bios';
|
|
||||||
|
|
||||||
describe('Debugger', () => {
|
|
||||||
let cpu: CPU6502;
|
|
||||||
let debuggerContainer: DebuggerContainer;
|
|
||||||
let theDebugger: Debugger;
|
|
||||||
let memory: MemoryPages;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
cpu = new CPU6502();
|
|
||||||
memory = new TestMemory(4);
|
|
||||||
|
|
||||||
cpu.addPageHandler(memory);
|
|
||||||
cpu.addPageHandler(bios);
|
|
||||||
|
|
||||||
debuggerContainer = {
|
|
||||||
run: jest.fn(),
|
|
||||||
stop: jest.fn(),
|
|
||||||
isRunning: jest.fn(),
|
|
||||||
};
|
|
||||||
theDebugger = new Debugger(cpu, debuggerContainer);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#utility', () => {
|
|
||||||
it('should list without symbols', () => {
|
|
||||||
const listing = theDebugger.list(0xff00);
|
|
||||||
expect(listing[0]).toEqual('FF00- 00 00 BRK #$00');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should list with symbols', () => {
|
|
||||||
theDebugger.addSymbols({ 0x00: 'ZERO', 0xff00: 'ENTRY' });
|
|
||||||
|
|
||||||
const listing = theDebugger.list(0xff00);
|
|
||||||
expect(listing[0]).toEqual('FF00- ENTRY 00 00 BRK #ZERO');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should dump page', () => {
|
|
||||||
const page = theDebugger.dumpPage(0xff);
|
|
||||||
expect(page).toContain(
|
|
||||||
'FF80: 48 45 4C 4C 4F 0D 00 00 00 00 00 00 00 00 00 00 HELLO...........'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should dump registers', () => {
|
|
||||||
const regs = theDebugger.dumpRegisters();
|
|
||||||
expect(regs).toEqual('A=00 X=00 Y=00 P=20 S=FF --X-----');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should dump the stack,', () => {
|
|
||||||
const stack = theDebugger.getStack();
|
|
||||||
const lines = stack.split('\n');
|
|
||||||
expect(lines).toHaveLength(256);
|
|
||||||
expect(lines[0]).toMatch('* $01FF 00');
|
|
||||||
expect(lines[1]).toMatch(' $01FE 00');
|
|
||||||
expect(lines[254]).toMatch(' $0101 00');
|
|
||||||
expect(lines[255]).toMatch(' $0100 00');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should dump the stack with size', () => {
|
|
||||||
const stack = theDebugger.getStack(32);
|
|
||||||
const lines = stack.split('\n');
|
|
||||||
expect(lines).toHaveLength(32);
|
|
||||||
expect(lines[0]).toMatch('* $01FF 00');
|
|
||||||
expect(lines[1]).toMatch(' $01FE 00');
|
|
||||||
expect(lines[30]).toMatch(' $01E1 00');
|
|
||||||
expect(lines[31]).toMatch(' $01E0 00');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should dump the stack within size', () => {
|
|
||||||
const registers = cpu.getState();
|
|
||||||
registers.sp = 0xe3;
|
|
||||||
cpu.setState(registers);
|
|
||||||
const stack = theDebugger.getStack(32);
|
|
||||||
const lines = stack.split('\n');
|
|
||||||
expect(lines).toHaveLength(32);
|
|
||||||
expect(lines[0]).toMatch(' $01FF 00');
|
|
||||||
expect(lines[1]).toMatch(' $01FE 00');
|
|
||||||
expect(lines[28]).toMatch('* $01E3 00');
|
|
||||||
expect(lines[29]).toMatch(' $01E2 00');
|
|
||||||
expect(lines[30]).toMatch(' $01E1 00');
|
|
||||||
expect(lines[31]).toMatch(' $01E0 00');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should dump the stack with size and move the window', () => {
|
|
||||||
const registers = cpu.getState();
|
|
||||||
registers.sp = 0xc3;
|
|
||||||
cpu.setState(registers);
|
|
||||||
const stack = theDebugger.getStack(32);
|
|
||||||
const lines = stack.split('\n');
|
|
||||||
expect(lines).toHaveLength(32);
|
|
||||||
expect(lines[0]).toMatch(' $01DF 00');
|
|
||||||
expect(lines[1]).toMatch(' $01DE 00');
|
|
||||||
expect(lines[28]).toMatch('* $01C3 00');
|
|
||||||
expect(lines[29]).toMatch(' $01C2 00');
|
|
||||||
expect(lines[30]).toMatch(' $01C1 00');
|
|
||||||
expect(lines[31]).toMatch(' $01C0 00');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,22 +0,0 @@
|
||||||
import type { CpuState } from '@whscullin/cpu6502';
|
|
||||||
import { toHex } from 'js/util';
|
|
||||||
import { dumpStatusRegister } from 'js/debugger';
|
|
||||||
|
|
||||||
const detail = !!process.env.JEST_DETAIL;
|
|
||||||
|
|
||||||
export function toReadableState(state: CpuState) {
|
|
||||||
if (detail) {
|
|
||||||
const { pc, sp, a, x, y, s } = state;
|
|
||||||
|
|
||||||
return {
|
|
||||||
pc: toHex(pc, 4),
|
|
||||||
sp: toHex(sp),
|
|
||||||
a: toHex(a),
|
|
||||||
x: toHex(x),
|
|
||||||
y: toHex(y),
|
|
||||||
s: dumpStatusRegister(s),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue