Browse Source

Memory class is now being treated as an interface. Bank takes the place of Memory and Bank extends Memory. MMC also extends Memory.

master
Bryan Miller 5 years ago
parent
commit
99c67da1bf
3 changed files with 90 additions and 71 deletions
  1. +60
    -0
      src/bank.js
  2. +6
    -48
      src/memory.js
  3. +24
    -23
      src/mmc.js

+ 60
- 0
src/bank.js View File

@@ -0,0 +1,60 @@

var Memory = require('src/memory');

class Bank extends Memory{
constructor(size, ro){
super();
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 = Bank;

+ 6
- 48
src/memory.js View File

@@ -1,57 +1,15 @@


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 = {};
}
constructor(){}

get size(){return (this.__map) ? this.__map.length : 0;}
get size(){return 0;}

get address(){return this.__addr;}
set address(a){
if (this.__map)
this.__addr = Math.min(this.__map.length, Math.max(0, a));
}
get address(){return 0;}
set address(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;
}
}
get byte(){return -1;}
set byte(b){}
}



+ 24
- 23
src/mmc.js View File

@@ -1,7 +1,7 @@

var Memory = require('chip/memory');
var Memory = require('src/memory');

class Bank{
class Switch{
constructor(mem){
this.__mem = [mem];
this.__idx = 0;
@@ -28,60 +28,61 @@ class Bank{



class MMC{
class MMC extends Memory{
constructor(){
this.__banks = [];
super();
this.__switches = [];
this.__addr = 0;
this.__bnkidx = 0;
this.__sidx = 0;
}

get size(){
return this.__banks.reduce((acc, b)=>{
acc += b.mem.size;
return this.__switches.reduce((acc, s)=>{
acc += s.mem.size;
}, 0);
}

get banks(){return this.__banks.length;}
get switches(){return this.__switches.length;}

get address(){return this.__addr;}
set address(a){
if (a >= 0 && a < this.size){
this.__addr = a;
offset = 0;
for (let b=0; b < this.__banks.length; b++){
if (a >= offset && a < offset + this.__banks[b].mem.size){
this.__bnkidx = b;
this.__banks[b].mem.address = a - offset;
for (let s=0; s < this.__switches.length; s++){
if (a >= offset && a < offset + this.__switches[s].mem.size){
this.__sidx = b;
this.__switches[s].mem.address = a - offset;
break;
} else {
offset += this.__banks[b].mem.size;
offset += this.__switches[s].mem.size;
}
}
}
}

get byte(){return (this.__banks.length > 0) ? this.__banks[this.__bnkidx].mem.byte : -1;}
get byte(){return (this.__switches.length > 0) ? this.__switches[this.__sidx].mem.byte : -1;}
set byte(b){
if (this.__banks.length > 0){
this.__banks[this.__bnkidx].mem.byte = b;
if (this.__switches.length > 0){
this.__switches[this.__sidx].mem.byte = b;
}
}

connectMemory(mem, addroff){
addroff = (typeof(addroff) === 'number' && addroff >= 0) ? addroff : -1;
if (addroff < 0 || addroff === this.size){
this.__banks.push(new Bank(mem));
this.__switches.push(new Switch(mem));
} else {
offset = 0;
for (let b=0; b < this.__banks.length; b++){
for (let s=0; s < this.__switches.length; s++){
if (addroff === offset){
if (this.__banks[b].mem.size !== mem.size)
if (this.__switches[s].mem.size !== mem.size)
throw new RangeError("Memory modules assigned to the same bank must be the same byte size.");
this.__banks[b].addMemModule(mem);
this.__switches[s].addMemModule(mem);
offset = -1;
break;
} else {
offset += this.__banks[b].mem.size;
offset += this.__switches[s].mem.size;
}
}
if (offset >= 0)
@@ -93,8 +94,8 @@ class MMC{
mmSwitchRegister(){
return (function(byte){
let mmcidx = (byte & 0xF0) >> 4;
if (mmcidx < this.__banks.length){
this.__banks[mmcidx].idx = (byte & 0x0F);
if (mmcidx < this.__switches.length){
this.__switches[mmcidx].idx = (byte & 0x0F);
}
}).bind(this);
}

Loading…
Cancel
Save