class Memory{ constructor(size, ro){ this.__ro = (ro === true); this.__map = null; this.__addr = 0; if (size > 0){ this.__map = new Uint8Array(size); } this.__listeners = {}; } get size(){return (this.__map) ? this.__map.length : 0;} get address(){return this.__addr;} set address(a){ if (this.__map) this.__addr = Math.min(this.__map.length, Math.max(0, a)); } get byte(){return (this.__map) ? this.__map[this.__addr] : -1;} set byte(b){ if (!this.__ro && this.__map){ this.__map[this.__addr] = b; if (this.__addr in this.__listeners) this.__listeners[this.__addr].forEach((fn)=>{fn(b);}); } } onAddressWrite(addr, fn){ if (addr < 0 || addr >= this.size) throw new RangeError("Memory address is out of bounds."); if (typeof(fn) !== 'function') throw new TypeErrpr("Expected a callback function."); if (!(addr in this.__listeners)) this.__listeners[addr] = []; // WARNING: Not testing to see if using the same function more than once. this.__listeners[addr].push(fn); } // This method is intended for the emulator to fill a Read-Only memory module with data prior to // the start of execution. This method should never be used in a running system. sysStore(address, data){ if (this.__map){ let dc = data; if (address < 0 || address >= this.__map.length) throw new RangeError("Memory address out of range."); if (this.__map.length - address < dc.length) dc = dc.slice(0, this.__map.length - address); this.__map.set(address, dc); return dc.length; } } } module.exports = Memory;