2021-03-15 19:51:40 +00:00
|
|
|
import { allocMem, debug } from '../util';
|
|
|
|
import { Card, Restorable, byte, memory } from '../types';
|
|
|
|
import { rom } from '../roms/cards/ramfactor';
|
|
|
|
|
|
|
|
const LOC = {
|
|
|
|
// Disk II Stuff
|
|
|
|
RAMLO: 0x80,
|
|
|
|
RAMMID: 0x81,
|
|
|
|
RAMHI: 0x82,
|
|
|
|
RAMDATA: 0x83,
|
|
|
|
_RAMLO: 0x84,
|
|
|
|
_RAMMID: 0x85,
|
|
|
|
_RAMHI: 0x86,
|
|
|
|
_RAMDATA: 0x87,
|
|
|
|
BANK: 0x8F
|
|
|
|
} as const;
|
|
|
|
|
|
|
|
export class RAMFactorState {
|
2021-11-29 00:20:25 +00:00
|
|
|
loc: number;
|
|
|
|
firmware: byte;
|
|
|
|
mem: memory;
|
2021-03-15 19:51:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export default class RAMFactor implements Card, Restorable<RAMFactorState> {
|
|
|
|
private mem: memory;
|
|
|
|
|
|
|
|
private firmware = 0;
|
|
|
|
private ramlo = 0;
|
|
|
|
private rammid = 0;
|
|
|
|
private ramhi = 0;
|
|
|
|
|
|
|
|
private loc = 0;
|
|
|
|
|
|
|
|
constructor(size: number) {
|
|
|
|
debug('RAMFactor card');
|
|
|
|
|
|
|
|
this.mem = allocMem(size);
|
|
|
|
for (let off = 0; off < size; off++) {
|
|
|
|
this.mem[off] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private sethi(val: byte) {
|
|
|
|
this.ramhi = (val & 0xff);
|
|
|
|
}
|
|
|
|
|
|
|
|
private setmid(val: byte) {
|
|
|
|
if (((this.rammid & 0x80) !== 0) && ((val & 0x80) === 0)) {
|
|
|
|
this.sethi(this.ramhi + 1);
|
|
|
|
}
|
|
|
|
this.rammid = (val & 0xff);
|
|
|
|
}
|
|
|
|
|
|
|
|
private setlo(val: byte) {
|
|
|
|
if (((this.ramlo & 0x80) !== 0) && ((val & 0x80) === 0)) {
|
|
|
|
this.setmid(this.rammid + 1);
|
|
|
|
}
|
|
|
|
this.ramlo = (val & 0xff);
|
|
|
|
}
|
|
|
|
|
|
|
|
private access(off: byte, val: byte) {
|
|
|
|
let result = 0;
|
|
|
|
switch (off & 0x8f) {
|
|
|
|
case LOC.RAMLO:
|
|
|
|
case LOC._RAMLO:
|
|
|
|
if (val !== undefined) {
|
|
|
|
this.setlo(val);
|
|
|
|
} else {
|
|
|
|
result = this.ramlo;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOC.RAMMID:
|
|
|
|
case LOC._RAMMID:
|
|
|
|
if (val !== undefined) {
|
|
|
|
this.setmid(val);
|
|
|
|
} else {
|
|
|
|
result = this.rammid;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOC.RAMHI:
|
|
|
|
case LOC._RAMHI:
|
|
|
|
if (val !== undefined) {
|
|
|
|
this.sethi(val);
|
|
|
|
} else {
|
|
|
|
result = this.ramhi;
|
|
|
|
result |= 0xf0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOC.RAMDATA:
|
|
|
|
case LOC._RAMDATA:
|
|
|
|
if (val !== undefined) {
|
|
|
|
this.mem[this.loc % this.mem.length] = val;
|
|
|
|
} else {
|
|
|
|
result = this.mem[this.loc % this.mem.length];
|
|
|
|
}
|
|
|
|
this.setlo(this.ramlo + 1);
|
|
|
|
break;
|
|
|
|
case LOC.BANK:
|
|
|
|
if (val !== undefined) {
|
|
|
|
this.firmware = val & 0x01;
|
|
|
|
} else {
|
|
|
|
result = this.firmware;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
this.loc = (this.ramhi << 16) | (this.rammid << 8) | (this.ramlo);
|
|
|
|
|
|
|
|
/*
|
|
|
|
if (val === undefined) {
|
|
|
|
debug("Read: " + toHex(result) + " from " + toHex(off) + " (loc = " + _loc + ")");
|
|
|
|
} else {
|
|
|
|
debug("Wrote: " + toHex(val) + " to " + toHex(off) + " (loc = " + _loc + ")");
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
ioSwitch(off: byte, val: byte) {
|
|
|
|
return this.access(off, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
read(page: byte, off: byte) {
|
|
|
|
return rom[this.firmware << 12 | (page - 0xC0) << 8 | off];
|
|
|
|
}
|
|
|
|
|
|
|
|
write() {}
|
|
|
|
|
|
|
|
reset() {
|
|
|
|
this.firmware = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
getState() {
|
|
|
|
return {
|
|
|
|
loc: this.loc,
|
|
|
|
firmware: this.firmware,
|
|
|
|
mem: new Uint8Array(this.mem)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
setState(state: RAMFactorState) {
|
|
|
|
this.loc = state.loc;
|
|
|
|
this.firmware = state.firmware;
|
|
|
|
this.mem = new Uint8Array(state.mem);
|
|
|
|
|
|
|
|
this.ramhi = (this.loc >> 16) & 0xff;
|
|
|
|
this.rammid = (this.loc >> 8) & 0xff;
|
|
|
|
this.ramlo = (this.loc) & 0xff;
|
|
|
|
}
|
|
|
|
}
|