| var IMem = require('./imem'); | |||||
| const IO = require('../common/io.js'); | |||||
| const IMem = require('./imem'); | |||||
| class Listener{ | |||||
| constructor(){ | |||||
| this.__listeners = {}; | |||||
| } | |||||
| on(n, fn){ | |||||
| if (typeof(fn) !== 'function') | |||||
| throw new TypeErrpr("Expected a callback function."); | |||||
| if (!(n in this.__listeners)) | |||||
| this.__listeners[n] = []; | |||||
| this.__listeners[n].push(fn); | |||||
| } | |||||
| trigger(n, data){ | |||||
| if (n in this.__listeners){ | |||||
| this.__listeners[n].forEach((l)=>{ | |||||
| l(data); | |||||
| }); | |||||
| } | |||||
| } | |||||
| } | |||||
| class ROM extends IMem{ | class ROM extends IMem{ | ||||
| constructor(pages){ | constructor(pages){ | ||||
| super(); | super(); | ||||
| this.__addr = 0; | this.__addr = 0; | ||||
| this.__map = new Uint8Array(pages * 256); | this.__map = new Uint8Array(pages * 256); | ||||
| this.__rlisteners = new Listener(); | |||||
| // Allow writable events because RAM will inherit ROM and use the same | |||||
| // __io object. | |||||
| this.__io = new IO([], []); | |||||
| } | } | ||||
| get pages(){return this.__map.length / 256;} | get pages(){return this.__map.length / 256;} | ||||
| } | } | ||||
| get byte(){ | get byte(){ | ||||
| this.__rlisteners.trigger(this.__addr); | |||||
| this.__io.triggerRead(this.__addr); | |||||
| return this.__map[this.__addr]; | return this.__map[this.__addr]; | ||||
| } | } | ||||
| set byte(b){} | set byte(b){} | ||||
| onAddressRead(addr, fn){ | onAddressRead(addr, fn){ | ||||
| if (addr < 0 || addr >= this.size) | if (addr < 0 || addr >= this.size) | ||||
| throw new RangeError("Memory address is out of bounds."); | throw new RangeError("Memory address is out of bounds."); | ||||
| this.__rlisteners.on(addr, fn); | |||||
| this.__io.onRead(addr, fn); | |||||
| return this; | return this; | ||||
| } | } | ||||
| class RAM extends ROM { | class RAM extends ROM { | ||||
| constructor(pages){ | constructor(pages){ | ||||
| super(pages); | super(pages); | ||||
| this.__wlisteners = new Listener(); | |||||
| } | } | ||||
| get pages(){return this.__map.length/256;} | get pages(){return this.__map.length/256;} | ||||
| } | } | ||||
| get byte(){ | get byte(){ | ||||
| this.__rlisteners.trigger(this.__addr); | |||||
| this.__io.triggerRead(this.__addr); | |||||
| return this.__map[this.__addr]; | return this.__map[this.__addr]; | ||||
| } | } | ||||
| set byte(b){ | set byte(b){ | ||||
| this.__map[this.__addr] = b & 0xFF; | this.__map[this.__addr] = b & 0xFF; | ||||
| this.__wlisteners.trigger(this.__addr, b & 0xFF); | |||||
| this.__io.triggerWrite(this.__addr, b & 0xFF); | |||||
| } | } | ||||
| onAddressWrite(addr, fn){ | onAddressWrite(addr, fn){ | ||||
| if (addr < 0 || addr >= this.size) | if (addr < 0 || addr >= this.size) | ||||
| throw new RangeError("Memory address is out of bounds."); | throw new RangeError("Memory address is out of bounds."); | ||||
| this.__wlisteners.on(addr, fn); | |||||
| this.__io.onWrite(addr, fn); | |||||
| return this; | return this; | ||||
| } | } | ||||
| this.__addr = 0; | this.__addr = 0; | ||||
| this.__size = pages * 256; | this.__size = pages * 256; | ||||
| this.__rlisteners = new Listener(); | |||||
| this.__wlisteners = new Listener(); | |||||
| this.__io = new IO([], []); | |||||
| } | } | ||||
| get pages(){return this.__size/256;} | get pages(){return this.__size/256;} | ||||
| get byte(){ | get byte(){ | ||||
| let a = this.__addr % this.__map.length; | let a = this.__addr % this.__map.length; | ||||
| this.__rlisteners.trigger(this.__addr); | |||||
| this.__io.triggerRead(this.__addr); | |||||
| return this.__map[a]; | return this.__map[a]; | ||||
| } | } | ||||
| set byte(b){ | set byte(b){ | ||||
| if (this.__addr >= 0 && this.__addr < this.__map.length){ | if (this.__addr >= 0 && this.__addr < this.__map.length){ | ||||
| this.__map[this.__addr] = b & 0xFF; | this.__map[this.__addr] = b & 0xFF; | ||||
| this.__wlisteners.trigger(this.__addr, b & 0xFF); | |||||
| this.__io.triggerWrite(this.__addr, b & 0xFF); | |||||
| } | } | ||||
| } | } | ||||
| onAddressRead(addr, fn){ | onAddressRead(addr, fn){ | ||||
| if (addr < 0 || addr >= this.size) | if (addr < 0 || addr >= this.size) | ||||
| throw new RangeError("Memory address is out of bounds."); | throw new RangeError("Memory address is out of bounds."); | ||||
| this.__rlisteners.on(addr, fn); | |||||
| this.__io.onRead(addr, fn); | |||||
| return this; | return this; | ||||
| } | } | ||||
| if (addr < 0 || addr >= this.size) | if (addr < 0 || addr >= this.size) | ||||
| throw new RangeError("Memory address is out of bounds."); | throw new RangeError("Memory address is out of bounds."); | ||||
| let a = this.__addr % this.__map.length; | let a = this.__addr % this.__map.length; | ||||
| this.__wlisteners.on(a, fn); | |||||
| this.__io.onWrite(a, fn); | |||||
| return this; | return this; | ||||
| } | } | ||||