Browse Source

Memory now has a peek() and poke() method; like read() and write() respectively, but will not trigger listeners.

master
Bryan Miller 5 years ago
parent
commit
c1f1f23ec4
4 changed files with 119 additions and 1 deletions
  1. +26
    -0
      src/memory/imem.js
  2. +23
    -0
      src/memory/memory.js
  3. +23
    -0
      src/memory/mmc.js
  4. +47
    -1
      test/unit.src.memory.memory.spec.js

+ 26
- 0
src/memory/imem.js View File

get byte(){return -1;} get byte(){return -1;}
set byte(b){} set byte(b){}


// Shorthand method for accessing an address and returning a byte.
// Same as...
//
// mem.address = <16 bit value>
// let res = mem.byte
//
// NOTE: This will trigger read listeners.
read(a){ read(a){
this.address = a; this.address = a;
return this.byte; return this.byte;
} }


// Shorthand method for accessing an address and setting it's byte.
// Same as...
//
// mem.address = <16 bit value>
// mem.byte = <1 byte value>
//
// NOTE: This will trigger write listeners.
write(a, b){ write(a, b){
if (this.writable){ if (this.writable){
this.address = a; this.address = a;
return this; return this;
} }


// Same as .read() but will NOT trigger read listeners.
peek(a){return 0;}
// Same as .write() but will NOT trigger write listeners.
poke(a, b){return this;}

// Starting at <address> will fill memory (regardless of whether
// it's ROM or RAM) with the values in <data>
// NOTE: <data> is assumed to only contain byte values.
load(address, data){ load(address, data){
return this; return this;
} }


// Clears 256 bytes of memory starting from <page> * 256
// NOTE: This affects both RAM and ROM.
clearPage(page){ clearPage(page){
return this; return this;
} }


// Clears all memory
// NOTE: This affects both RAM and ROM.
clear(){ clear(){
return this; return this;
} }

+ 23
- 0
src/memory/memory.js View File

} }




peek(a){
a = Math.min(this.__map.length - 1, Math.max(0, a));
return this.__map[a];
}


load(address, data){ load(address, data){
let dc = data; let dc = data;
if (address < 0 || address >= this.__map.length) if (address < 0 || address >= this.__map.length)
this.__wlisteners.on(addr, fn); this.__wlisteners.on(addr, fn);
return this; return this;
} }

poke(a, b){
a = Math.min(this.__map.length - 1, Math.max(0, a));
this.__map[a] = b & 0xFF;
return this;
}
} }




return this; return this;
} }


peek(a){
a = Math.min(this.__size - 1, Math.max(0, a)) % this.__map.length;
return this.__map[a];
}

poke(a, b){
if (a >= 0 && a < this.__map.length)
this.__map[a] = b & 0xFF;
return this;
}

load(addr, data){ load(addr, data){
let dc = data; let dc = data;
if (addr < 0 || addr >= this.__size) if (addr < 0 || addr >= this.__size)

+ 23
- 0
src/memory/mmc.js View File

} }
} }


peek(a){
let v = 0;
if (this.__switches.length > 0){
let oa = this.address;
this.address = a; // Let this do ALL the work for me.
a = this.__switches[this.__sidx].mem.address;
v = this.__switches[this.__sidx].mem.peek(a);
this.address = oa;
}
return v;
}

poke(a, b){
if (this.__switches.length > 0){
let oa = this.address;
this.address = a;
a = this.__switches[this.__sidx].mem.address;
this.__switches[this.__sidx].mem.poke(a, b);
this.address = oa;
}
return this;
}

load(addr, data){ load(addr, data){
if (addr < 0 || addr > this.size) if (addr < 0 || addr > this.size)
throw new RangeError("Memory address out of range."); throw new RangeError("Memory address out of range.");

+ 47
- 1
test/unit.src.memory.memory.spec.js View File

expect(cb.callCount).to.equal(2); expect(cb.callCount).to.equal(2);
}); });


it("Peek", function(){
var cb = sinon.fake();
m2.onAddressRead(0x0101, cb);
expect(m2.peek(0x0101)).to.equal(0x77);
expect(cb.callCount).to.equal(0);
expect(m2.read(0x0101)).to.equal(0x77);
expect(cb.callCount).to.equal(1);
m2.peek(0x0101);
expect(cb.callCount).to.equal(1);
});

it("Clear Page", function(){ it("Clear Page", function(){
m2.clearPage(2); m2.clearPage(2);
expect(m2.read(0x0200)).to.equal(0x00); expect(m2.read(0x0200)).to.equal(0x00);
expect(cb.callCount).to.equal(2); expect(cb.callCount).to.equal(2);
}); });


it("Peek", function(){
var cb = sinon.fake();
m2.onAddressRead(0x0101, cb);
expect(m2.peek(0x0101)).to.equal(0x77);
expect(cb.callCount).to.equal(0);
expect(m2.read(0x0101)).to.equal(0x77);
expect(cb.callCount).to.equal(1);
m2.peek(0x0101);
expect(cb.callCount).to.equal(1);
});

it("Poke", function(){
var cb = sinon.fake();
m2.onAddressWrite(0x0130, cb);
m2.poke(0x0130, 0x42);
expect(cb.callCount).to.equal(0);
expect(m2.peek(0x0130)).to.equal(0x42);
m2.write(0x0130, 0x46);
expect(cb.callCount).to.equal(1);
expect(m2.peek(0x0130)).to.equal(0x46);
m2.poke(0x0130, 0x42);
expect(cb.callCount).to.equal(1);
});

it("Clear Page", function(){ it("Clear Page", function(){
m2.clearPage(2); m2.clearPage(2);
expect(m2.read(0x0200)).to.equal(0x00); expect(m2.read(0x0200)).to.equal(0x00);
expect(cb1.lastArg).to.equal(0x22); expect(cb1.lastArg).to.equal(0x22);
}); });


it("Peek");
it("Poke");

it("Clear Page", function(){ it("Clear Page", function(){
sm.clearPage(0); sm.clearPage(0);
expect(sm.read(0x00)).to.equal(0x00); expect(sm.read(0x00)).to.equal(0x00);


describe("Memory Management Controller (MMC) Class", function(){ describe("Memory Management Controller (MMC) Class", function(){
var mmc = new Mem.MMC(); var mmc = new Mem.MMC();
mmc.connectMemory(new Mem.Memory.RAM(1));
var rcb = sinon.fake();
var wcb = sinon.fake();
let m1 = new Mem.Memory.RAM(1);
m1.onAddressRead(0x31, rcb);
m1.onAddressWrite(0x31, wcb);
mmc.connectMemory(m1);
mmc.connectMemory(new Mem.Memory.RAM(2)); mmc.connectMemory(new Mem.Memory.RAM(2));
mmc.connectMemory(new Mem.Memory.RAM(1)); mmc.connectMemory(new Mem.Memory.RAM(1));


expect(mmc.address).to.equal(0x03FF); expect(mmc.address).to.equal(0x03FF);
}); });


it("Peek");
it("Poke");

it("Clear Page", function(){ it("Clear Page", function(){
expect(mmc.read(0x0200)).to.equal(0x11); expect(mmc.read(0x0200)).to.equal(0x11);
expect(mmc.read(0x0201)).to.equal(0x22); expect(mmc.read(0x0201)).to.equal(0x22);

Loading…
Cancel
Save