|
|
@@ -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; |
|
|
|
} |
|
|
|
|