nes-emu
Version:
A NES emulator
98 lines (95 loc) • 4.86 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _indirect = require("../cpu/addressings/indirect");
var _helpers = require("../helpers");
var _lodash = _interopRequireDefault(require("lodash"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const hex = (value, length) => _lodash.default.padStart(value.toString(16).toUpperCase(), length, "0");
/** A logger that resembles Nintendulator's logs format, to use with nestest (a test ROM). */
class NESTestLogger {
constructor() {
this.lastLog = null;
}
/** Logs a CPU instruction. All the information is in `request`. */
log(request) {
const {
context,
pc,
operation,
initialArgument,
finalArgument
} = request;
try {
context.inDebugMode(() => {
const {
cpu
} = context;
const memory = cpu.memory;
const cycle = (value, length) => _lodash.default.padStart(value.toString(), length);
const section = (string, length) => _lodash.default.padEnd(string.substr(0, length), length);
const hexArgument = value => {
if (operation.addressing.parameterSize === 0) return "";
return operation.addressing.parameterSize === 2 ? hex(value, 4) : hex(value, 2);
};
const formatParameter = () => {
const instructionsWithValue = ["STA", "STX", "STY", "LDA", "LDX", "LDY", "BIT", "ORA", "AND", "EOR", "ADC", "SBC", "CMP", "CPX", "CPY", "LSR", "ASL", "ROR", "ROL", "INC", "DEC"];
const $initialArgument = hexArgument(initialArgument);
const $finalArgument = hexArgument(finalArgument);
let finalAddress = null;
try {
finalAddress = operation.addressing.getAddress(context, initialArgument);
} catch (e) {}
switch (operation.addressing.id) {
case "IMPLICIT":
return "";
case "IMMEDIATE":
return "#$".concat($finalArgument);
case "ABSOLUTE":
let $address = "$".concat($initialArgument);
if (_lodash.default.includes(instructionsWithValue, operation.instruction.id)) $address += " = ".concat(hex(memory.readAt(finalAddress), 2));
return $address;
case "ZERO_PAGE":
return "$".concat($initialArgument, " = ").concat(hex(memory.readAt(finalAddress), 2));
case "INDEXED_ABSOLUTE_X":
case "INDEXED_ZERO_PAGE_X":
return "$".concat($initialArgument, ",X @ ").concat(hexArgument(finalAddress), " = ").concat(hex(memory.readAt(finalAddress), 2));
case "INDEXED_ABSOLUTE_Y":
case "INDEXED_ZERO_PAGE_Y":
return "$".concat($initialArgument, ",Y @ ").concat(hexArgument(finalAddress), " = ").concat(hex(memory.readAt(finalAddress), 2));
case "INDIRECT":
return "($".concat($initialArgument, ") = ").concat(hex(finalAddress, 4));
case "INDEXED_INDIRECT_X":
return "($".concat($initialArgument, ",X) @ ").concat(hex(_helpers.Byte.force8Bit(initialArgument + cpu.registers.x.value), 2), " = ").concat(hex(finalAddress, 4), " = ").concat(hex(memory.readAt(finalAddress), 2));
case "INDEXED_INDIRECT_Y":
return "($".concat($initialArgument, "),Y = ").concat(hex((0, _indirect.getIndirectAddress)(context, initialArgument), 4), " @ ").concat(hex(finalAddress, 4), " = ").concat(hex(memory.readAt(finalAddress), 2));
case "ACCUMULATOR":
return "A";
default:
return "$".concat($finalArgument);
}
};
const $counter = section(hex(pc, 4), 6);
const $operation = hex(operation.id, 2);
let $arguments = " ";
if (operation.addressing.parameterSize > 0) {
$arguments += operation.addressing.parameterSize === 2 ? hex(_helpers.Byte.lowPartOf(initialArgument), 2) + " " + hex(_helpers.Byte.highPartOf(initialArgument), 2) : hex(initialArgument, 2);
}
const $commandHex = section($operation + $arguments, 10);
const $assembly = section(operation.instruction.id + " " + formatParameter(), 32);
const $registers = ["a", "x", "y"].map(register => {
return register.toUpperCase() + ":" + hex(cpu.registers[register].value, 2);
}).join(" ") + " P:" + hex(cpu.flags.toByte(), 2) + " SP:" + hex(cpu.sp.value, 2);
const $ppuCycle = "PPU:" + cycle(0, 3) + "," + cycle(1, 3);
const $cpuCycle = "CYC:" + cpu.cycle;
const $status = "".concat($registers, " ").concat($ppuCycle, " ").concat($cpuCycle);
this.lastLog = $counter + $commandHex + $assembly + $status;
});
} catch (e) {
console.error(e);
}
}
}
exports.default = NESTestLogger;