nes-emu
Version:
A NES emulator
98 lines (90 loc) • 3.47 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _memory = require("../../memory");
var _constants = _interopRequireDefault(require("../../constants"));
var _helpers = require("../../helpers");
var _lodash = _interopRequireDefault(require("lodash"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/**
* An abstract class that represents a generic mapper.
* It has two memory segments:
* - One mapped at CPU $4020-$FFFF (for PRG ROM, PRG RAM, and mapper registers)
* - One mapped at PPU $0000-$1FFF (for CHR ROM / Pattern tables)
* It intercepts all CPU write operations.
*/
class Mapper {
static get id() {
throw new Error("not_implemented");
}
constructor() {
let prgRomPageSize = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _constants.default.PRG_ROM_PAGE_SIZE;
let chrRomPageSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _constants.default.CHR_ROM_PAGE_SIZE;
_helpers.WithContext.apply(this);
this.prgRomPageSize = prgRomPageSize;
this.chrRomPageSize = chrRomPageSize;
}
/** Creates a memory segment for CPU range $4020-$FFFF. */
createCPUSegment(context) {
throw new Error("not_implemented");
}
/** Creates a memory segment for PPU range $0000-$1FFF. */
createPPUSegment(context) {
throw new Error("not_implemented");
}
/** When a context is loaded. */
onLoad(context) {
const {
cartridge
} = context;
const prg = cartridge.prgRom;
const chr = cartridge.chrRom;
const totalPrgPages = Math.floor(prg.length / this.prgRomPageSize);
const totalChrPages = Math.floor(chr.length / this.chrRomPageSize);
this.prgPages = _lodash.default.range(0, totalPrgPages).map(page => this._getPage(prg, this.prgRomPageSize, page));
this.chrPages = _lodash.default.range(0, totalChrPages).map(page => this._getPage(chr, this.chrRomPageSize, page));
this.segments = {
cpu: this.createCPUSegment(context),
ppu: this.createPPUSegment(context)
};
}
/** Maps a CPU write operation. */
cpuWriteAt(address, byte) {
this.context.cpu.memory.writeAt(address, byte);
}
/** Runs at cycle 260 of every scanline (including preline). Returns a CPU interrupt or null. */
tick() {
return null;
}
/** Returns a snapshot of the current state. */
getSaveState() {
return {
chrPages: this.context.cartridge.header.usesChrRam ? this.chrPages.map(it => Array.from(it)) : null
};
}
/** Restores state from a snapshot. */
setSaveState(saveState) {
if (saveState.chrPages != null) this.chrPages = saveState.chrPages.map(it => new Uint8Array(it));
}
_newPrgBank() {
let id = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
return new _memory.MemoryChunk(this.prgPages[id]).asReadOnly();
}
_newChrBank(cartridge) {
let id = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
return new _memory.MemoryChunk(this.chrPages[id]).asReadOnly(!cartridge.header.usesChrRam);
}
_getPrgPage(page) {
return this.prgPages[Math.max(0, page % this.prgPages.length)];
}
_getChrPage(page) {
return this.chrPages[Math.max(0, page % this.chrPages.length)];
}
_getPage(memory, pageSize, page) {
const offset = page * pageSize;
return memory.slice(offset, offset + pageSize);
}
}
exports.default = Mapper;