|
-
- var IMem = require('./imem.js');
-
- class Switch{
- constructor(mem){
- this.__mem = [mem];
- this.__idx = 0;
- }
-
- get mem(){return this.__mem[this.__idx];}
-
- get idx(){return this.__idx;}
- set idx(i){
- if (i >= 0 && i < this.__mem.length)
- this.__idx = i;
- }
-
- addMemModule(mem){
- if (!(mem instanceof IMem))
- throw new ValueError("Only IMem instances can be added to MMC Banks.");
- if (this.__mem.length >= 4)
- throw new RangeError("Bank handling maximum memory modules.");
- if (this.__mem.length > 0 && mem.size !== this.__mem[0].size)
- throw new RangeError("Memory module does not match size of already connected memory modules on this bank.");
- this.__mem.push(mem);
- }
- }
-
-
-
- class MMC extends IMem{
- constructor(){
- super();
- this.__switches = [];
- this.__addr = 0;
- this.__sidx = 0;
- }
-
- get pages(){
- return this.__switches.reduce((acc, s)=>{
- return acc + s.mem.pages;
- }, 0);
- }
-
- get size(){
- return this.__switches.reduce((acc, s)=>{
- return acc + s.mem.size;
- }, 0);
- }
-
- get writable(){
- let iw = false;
- for (let i=0; i < this.__switches.length; i++){
- if (this.__switches[i].mem.writable){
- iw = true; break;
- }
- }
- return iw;
- }
-
- get switches(){return this.__switches.length;}
-
- get address(){return this.__addr;}
- set address(a){
- this.__addr = Math.min(this.size - 1, Math.max(0, a));
- let offset = 0;
- for (let s=0; s < this.__switches.length; s++){
- if (this.__addr >= offset && this.__addr < offset + this.__switches[s].mem.size){
- this.__sidx = s;
- this.__switches[s].mem.address = this.__addr - offset;
- break;
- } else {
- offset += this.__switches[s].mem.size;
- }
- }
- }
-
- get byte(){
- return (this.__switches.length > 0) ? this.__switches[this.__sidx].mem.byte : -1;
- }
-
- set byte(b){
- if (this.__switches.length > 0){
- this.__switches[this.__sidx].mem.byte = b;
- }
- }
-
- load(addr, data){
- if (addr < 0 || addr > this.size)
- throw new RangeError("Memory address out of range.");
- let offset = 0;
- let doff = 0;
- let addre = addr + data.length;
- for (let s = 0; s < this.__switches.length; s++){
- let mem = this.__switches[s].mem;
- if (addr < offset + mem.size && addre >= offset){
- let a = (addr > offset) ? addr - offset : 0;
- let dlen = (mem.size - a < data.length - doff) ?
- mem.size - a : data.length - doff;
- mem.load(a, data.slice(doff, doff + dlen));
- doff += dlen;
- }
- offset += mem.size;
- }
- return this;
- }
-
- clearPage(paddr){
- for (let i=0; i < this.__switches.length; i++){
- let pgs = this.__switches[i].mem.pages;
- if (paddr < pgs){
- this.__switches[i].mem.clearPage(addr);
- break;
- }
- paddr -= pgs;
- }
- return this;
- }
-
- clear(){
- this.__switches.forEach((s)=>{
- s.clear();
- });
- return this;
- }
-
- connectMemory(mem, addroff){
- addroff = (typeof(addroff) === 'number' && addroff >= 0) ? addroff : -1;
- if (addroff < 0 || addroff === this.size){
- this.__switches.push(new Switch(mem));
- } else {
- let offset = 0;
- for (let s=0; s < this.__switches.length; s++){
- if (addroff === offset){
- 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.__switches[s].addMemModule(mem);
- offset = -1;
- break;
- } else {
- offset += this.__switches[s].mem.size;
- }
- }
- if (offset >= 0)
- throw new RangeError("Cannot align memory module to bank at address " + addroff);
- }
- return this;
- }
-
- switchBank(bank){
- // The variable <bank> contains two 4 bit offsets.
- // The upper 4 bits is the bank switch offset.
- // The lower 4 bits is the bank offset within the switch.
- let mmcidx = (bank & 0xF0) >> 4;
- if (mmcidx < this.__switches.length){
- this.__switches[mmcidx].idx = (bank & 0x0F);
- }
- }
- }
-
- module.exports = MMC;
|