| @@ -1,27 +1,7 @@ | |||
| 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{ | |||
| constructor(pages){ | |||
| @@ -30,7 +10,9 @@ class ROM extends IMem{ | |||
| super(); | |||
| this.__addr = 0; | |||
| 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;} | |||
| @@ -42,7 +24,7 @@ class ROM extends IMem{ | |||
| } | |||
| get byte(){ | |||
| this.__rlisteners.trigger(this.__addr); | |||
| this.__io.triggerRead(this.__addr); | |||
| return this.__map[this.__addr]; | |||
| } | |||
| set byte(b){} | |||
| @@ -51,7 +33,7 @@ class ROM extends IMem{ | |||
| onAddressRead(addr, fn){ | |||
| if (addr < 0 || addr >= this.size) | |||
| throw new RangeError("Memory address is out of bounds."); | |||
| this.__rlisteners.on(addr, fn); | |||
| this.__io.onRead(addr, fn); | |||
| return this; | |||
| } | |||
| @@ -93,7 +75,6 @@ class ROM extends IMem{ | |||
| class RAM extends ROM { | |||
| constructor(pages){ | |||
| super(pages); | |||
| this.__wlisteners = new Listener(); | |||
| } | |||
| get pages(){return this.__map.length/256;} | |||
| @@ -107,18 +88,18 @@ class RAM extends ROM { | |||
| } | |||
| get byte(){ | |||
| this.__rlisteners.trigger(this.__addr); | |||
| this.__io.triggerRead(this.__addr); | |||
| return this.__map[this.__addr]; | |||
| } | |||
| set byte(b){ | |||
| this.__map[this.__addr] = b & 0xFF; | |||
| this.__wlisteners.trigger(this.__addr, b & 0xFF); | |||
| this.__io.triggerWrite(this.__addr, b & 0xFF); | |||
| } | |||
| onAddressWrite(addr, fn){ | |||
| if (addr < 0 || addr >= this.size) | |||
| throw new RangeError("Memory address is out of bounds."); | |||
| this.__wlisteners.on(addr, fn); | |||
| this.__io.onWrite(addr, fn); | |||
| return this; | |||
| } | |||
| @@ -139,8 +120,7 @@ class Shadow extends IMem { | |||
| this.__addr = 0; | |||
| this.__size = pages * 256; | |||
| this.__rlisteners = new Listener(); | |||
| this.__wlisteners = new Listener(); | |||
| this.__io = new IO([], []); | |||
| } | |||
| get pages(){return this.__size/256;} | |||
| @@ -156,20 +136,20 @@ class Shadow extends IMem { | |||
| get byte(){ | |||
| let a = this.__addr % this.__map.length; | |||
| this.__rlisteners.trigger(this.__addr); | |||
| this.__io.triggerRead(this.__addr); | |||
| return this.__map[a]; | |||
| } | |||
| set byte(b){ | |||
| if (this.__addr >= 0 && this.__addr < this.__map.length){ | |||
| this.__map[this.__addr] = b & 0xFF; | |||
| this.__wlisteners.trigger(this.__addr, b & 0xFF); | |||
| this.__io.triggerWrite(this.__addr, b & 0xFF); | |||
| } | |||
| } | |||
| onAddressRead(addr, fn){ | |||
| if (addr < 0 || addr >= this.size) | |||
| throw new RangeError("Memory address is out of bounds."); | |||
| this.__rlisteners.on(addr, fn); | |||
| this.__io.onRead(addr, fn); | |||
| return this; | |||
| } | |||
| @@ -177,7 +157,7 @@ class Shadow extends IMem { | |||
| if (addr < 0 || addr >= this.size) | |||
| throw new RangeError("Memory address is out of bounds."); | |||
| let a = this.__addr % this.__map.length; | |||
| this.__wlisteners.on(a, fn); | |||
| this.__io.onWrite(a, fn); | |||
| return this; | |||
| } | |||