broken-neees
Version:
A really broken NEEES emulator that introduces glitches and random bugs on purpose!
89 lines (87 loc) • 3.23 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _Register = require("./Register");
var _FlagsRegister = _interopRequireDefault(require("./FlagsRegister"));
var _Stack = _interopRequireDefault(require("./Stack"));
var _instructions = _interopRequireDefault(require("./instructions"));
var _addressingModes = _interopRequireDefault(require("./addressingModes"));
var _defineOperations = _interopRequireDefault(require("../lib/cpu/defineOperations"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
class CPU {
constructor(cpuMemory) {
this.memory = cpuMemory;
this.cycle = 0;
this.extraCycles = 0;
this.a = new _Register.Register8Bit();
this.x = new _Register.Register8Bit();
this.y = new _Register.Register8Bit();
this.sp = new _Register.Register8Bit();
this.pc = new _Register.Register16Bit();
this.flags = new _FlagsRegister.default();
this.stack = new _Stack.default(this.memory, this.sp);
this.operations = (0, _defineOperations.default)(_instructions.default, _addressingModes.default);
}
step() {
const originalPC = this.pc.getValue();
const operation = this._fetchOperation();
const input = this._fetchInput(operation);
const argument = this._fetchArgument(operation, input);
if (this.logger != null) {
this.logger(this, originalPC, operation, input, argument);
}
operation.instruction.run(this, argument);
return this._addCycles(operation);
}
interrupt(interrupt, withBFlag) {
if (interrupt.id === "IRQ" && this.flags.i) return 0;
this.stack.push16(this.pc.getValue());
this.stack.push(this.flags.getValue() | (withBFlag && 0b00010000));
this.cycle += 7;
this.flags.i = true;
this.pc.setValue(this.memory.read16(interrupt.vector));
return 7;
}
_fetchOperation() {
const opcode = this.memory.read(this.pc.getValue());
const operation = this.operations[opcode];
if (operation == null) throw new Error("Invalid opcode: 0x" + opcode.toString(16));
this.pc.increment();
return operation;
}
_fetchInput(operation) {
let input = null;
if (operation.addressingMode.inputSize === 1) {
input = this.memory.read(this.pc.getValue());
this.pc.increment();
} else if (operation.addressingMode.inputSize === 2) {
input = this.memory.read16(this.pc.getValue());
this.pc.increment();
this.pc.increment();
}
return input;
}
_fetchArgument(operation, input) {
const arg = operation.instruction.argument === "value" ? operation.addressingMode.getValue(this, input, operation.hasPageCrossPenalty) : operation.addressingMode.getAddress(this, input, operation.hasPageCrossPenalty);
// [!!!]
if (!this.unbroken) {
if (Math.random() < 0.0005 && operation.id === 0x69 /* adc immediate */) return arg + 1;
}
return arg;
}
_addCycles(operation) {
let cycles;
if (this.unbroken) {
cycles = operation.cycles + this.extraCycles;
} else {
// [!!!]
cycles = Math.floor(Math.random() * 10);
}
this.cycle += cycles;
this.extraCycles = 0;
return cycles;
}
}
exports.default = CPU;