zx-generation
Version:
A high-fidelity ZX Spectrum emulator in JavaScript — fully generated by a large language model (LLM) to explore the boundaries of AI in systems programming.
125 lines (106 loc) • 3.89 kB
JavaScript
/**
* Z80 Debugger
* Simple debugging utilities for the emulator
*/
class Z80Debugger {
constructor(cpu) {
this.cpu = cpu;
this.breakpoints = new Set();
this.history = [];
this.historySize = 100;
}
/**
* Add a breakpoint at the specified address
*/
addBreakpoint(address) {
this.breakpoints.add(address & 0xffff);
}
/**
* Remove a breakpoint
*/
removeBreakpoint(address) {
this.breakpoints.delete(address & 0xffff);
}
/**
* Execute one instruction with debugging
*/
step() {
const pc = this.cpu.registers.getPC();
// Check breakpoint
if (this.breakpoints.has(pc)) {
console.log(`Breakpoint hit at ${pc.toString(16).padStart(4, '0').toUpperCase()}H`);
return false;
}
// Save state to history
this.saveState();
// Execute instruction
this.cpu.execute();
return true;
}
/**
* Save current CPU state to history
*/
saveState() {
const state = {
pc: this.cpu.registers.getPC(),
registers: { ...this.cpu.registers.data },
flags: this.cpu.registers.get('F'),
cycles: this.cpu.cycles,
};
this.history.push(state);
if (this.history.length > this.historySize) {
this.history.shift();
}
}
/**
* Print current CPU state
*/
printState() {
const regs = this.cpu.registers;
const flags = this.cpu.flags;
const f = regs.get('F');
console.log('\n--- CPU State ---');
console.log(
`PC: ${regs.getPC().toString(16).padStart(4, '0').toUpperCase()}H SP: ${regs.get16('SP').toString(16).padStart(4, '0').toUpperCase()}H`
);
console.log(
`AF: ${regs.getAF().toString(16).padStart(4, '0').toUpperCase()}H BC: ${regs.getBC().toString(16).padStart(4, '0').toUpperCase()}H DE: ${regs.getDE().toString(16).padStart(4, '0').toUpperCase()}H HL: ${regs.getHL().toString(16).padStart(4, '0').toUpperCase()}H`
);
console.log(
`IX: ${regs.get16('IX').toString(16).padStart(4, '0').toUpperCase()}H IY: ${regs.get16('IY').toString(16).padStart(4, '0').toUpperCase()}H I: ${regs.get('I').toString(16).padStart(2, '0').toUpperCase()}H R: ${regs.get('R').toString(16).padStart(2, '0').toUpperCase()}H`
);
const flagStr = [
flags.getFlag(f, flags.masks.S) ? 'S' : '-',
flags.getFlag(f, flags.masks.Z) ? 'Z' : '-',
flags.getFlag(f, flags.masks.F5) ? '5' : '-',
flags.getFlag(f, flags.masks.H) ? 'H' : '-',
flags.getFlag(f, flags.masks.F3) ? '3' : '-',
flags.getFlag(f, flags.masks.PV) ? 'P' : '-',
flags.getFlag(f, flags.masks.N) ? 'N' : '-',
flags.getFlag(f, flags.masks.C) ? 'C' : '-',
].join('');
console.log(`Flags: ${flagStr} Cycles: ${this.cpu.cycles}`);
}
/**
* Show memory dump
*/
memoryDump(address, lines = 8) {
console.log(
`\n--- Memory Dump from ${address.toString(16).padStart(4, '0').toUpperCase()}H ---`
);
for (let i = 0; i < lines; i++) {
const addr = (address + i * 16) & 0xffff;
const bytes = [];
const chars = [];
for (let j = 0; j < 16; j++) {
const byte = this.cpu.memory.readByte(addr + j);
bytes.push(byte.toString(16).padStart(2, '0').toUpperCase());
chars.push(byte >= 32 && byte <= 126 ? String.fromCharCode(byte) : '.');
}
console.log(
`${addr.toString(16).padStart(4, '0').toUpperCase()}H: ${bytes.join(' ')} ${chars.join('')}`
);
}
}
}
export { Z80Debugger };