let intval = null;
let breakpt = null;
let ramlines = {value: 1};
let iterations = 0;
let totalstart = performance.now();
let lastiteration = 0;
let cyclecount = 0;
let cycleavg = new Array(10);
let cycleavgval = 0;
let cycleavgpos = 0;
for (let a = 0; a < cycleavg.length; a++) {
cycleavg[a] = 0;
}
function stringToRAM(rstring,ram,address) {
for (let a = 0; a < rstring.length; a++) {
ram[address+a] = rstring.charCodeAt(a);
}
}
function generateClocks(clk_cnt) {
for (let a = 0; a < clk_cnt; a++) {
cpu.CLOCK(true);
clk_count++;
clk_counter.innerText = clk_count;
cpu.CLOCK(false);
}
}
function generateClocks_Interval(cycles_per_run=1) {
/* if (cpu._CLK) {
cpu.CLOCK(false);
} else {
cpu.CLOCK(true);
}*/
let perfStart = performance.now();
let perfEnd = 0;
let perftotal = 0;
for (let a = 0; a < cycles_per_run; a++) {
cpu.CLOCK(true);
clk_count++;
clk_counter.innerText = clk_count;
cpu.CLOCK(false);
if (cpu.ADDRBUS === breakpt) {
btn_stopclk.disabled = true;
clearInterval(intval);
updateHTML();
perfEnd = performance.now();
perftotal = perfEnd - perfStart;
//console.log(`Performance: ${perftotal}`);
return;
}
}
updateHTML();
perfEnd = performance.now();
perftotal = perfEnd - perfStart;
iterations += 1;
let totalnow = performance.now();
let timesince = totalnow - lastiteration;
lastiteration = totalnow;
cycleavg[cycleavgpos] = ((cycles_per_run / (timesince/1000))/1000);
cycleavgpos++;
if (cycleavgpos > cycleavg.length) cycleavgpos = 0;
cyclecount++;
if (cyclecount === 10) {
let avg = 0;
for (let a = 0; a < cycleavg.length; a++) {
avg += cycleavg[a];
}
cycleavgval = avg/cycleavg.length;
//console.log(`[${iterations} +${timesince}ms] Performance: ${perftotal}, CPS: ${cycleavgval}KHz`);
cyclecount = 0;
}
//console.log(`[${iterations} +${timesince}ms] Performance: ${perftotal}, CPS: ${cps}`);
}
function drawCPUInfo() {
updateHTML();
window.requestAnimationFrame(drawCPUInfo);
}
function RunUntilBreak(addr,cycles = 1) {
breakpt = addr;
intval = setInterval(function(){
generateClocks_Interval(cycles);
}, parseInt(clkinterval.value));
}
function printTextOut(ram,startaddr,endaddr) {
let outString = "";
for (let a = startaddr; a <= endaddr; a++) {
if (ram[a] === 0) {
outString += " ";
} else {
outString += String.fromCharCode(ram[a]);
}
}
return outString;
}
function printRAM(ram) {
let addrSpan = parseInt(ramlines.value);
let startADDR = (cpu.ADDRBUS & 0xfffff0) - ((Math.floor(addrSpan/2)*16));
if (startADDR < 0) startADDR = 0;
//if (startADDR > 0xFFFEFF) startADDR = (0xFF00 + (addrSpan*16));
let sp_ram = document.getElementById("RAM");
let ramtext = "ADDR : 0 1 2 3 4 5 6 7 8 9 A B C D E F
";
for (let a = startADDR; a < (startADDR+(addrSpan*16)); a+=16) {
ramtext += "0x" + formatHex(a,6) + ": ";
for (let b = 0; b < 16; b++) {
if (cpu.ADDRBUS === (a)+b) {
let bgcolor = "#ffff55";
if ((cpu.MC_Controls & CONTROL_OUT_RO) === CONTROL_OUT_RO) bgcolor = "#55ff55";
if (cpu.MC_Controls & CONTROL_RI) bgcolor = "#ff5555";
ramtext += ``;
}
ramtext += formatHex(ram[(a)+b],4) + " ";
if (cpu.ADDRBUS === (a)+b) ramtext += '';
}
ramtext += "
";
}
sp_ram.innerHTML = ramtext;
let sp_stackram = document.getElementById("STACK-RAM");
ramtext = "ADDR : 0 1 2 3 4 5 6 7 8 9 A B C D E F
";
for (let a = (0xffe0 | cpu.SPP << 16); a < ((0xffe0 | cpu.SPP << 16)+0x20); a+=16) {
ramtext += "0x" + formatHex(a,6) + ": ";
for (let b = 0; b < 16; b++) {
if (cpu.ADDRBUS === (a)+b) ramtext += '';
ramtext += formatHex(ram[(a)+b],4) + " ";
if (cpu.ADDRBUS === (a)+b) ramtext += '';
}
ramtext += "
";
}
sp_stackram.innerHTML = ramtext;
}
function updateHTML() {
let sp_addr = document.getElementById("Address_BUS");
sp_addr.innerText = "0x" + formatHex(cpu.ADDRBUS,6);
let sp_data = document.getElementById("Data_BUS");
sp_data.innerText = "0x" + formatHex(cpu.DATABUS,4);
let sp_pc = document.getElementById("PC_Register");
sp_pc.innerText = "0x" + formatHex(cpu.PC,4);
sp_pc.style.backgroundColor = "transparent";
if (cpu.MC_Controls & CONTROL_PCC) sp_pc.style.backgroundColor = "#55ff55";
if (cpu.MC_Controls & CONTROL_PCI) sp_pc.style.backgroundColor = "#ff5555";
let sp_mcc = document.getElementById("MCC_Register");
sp_mcc.innerText = "0x" + cpu.MCC.toString(16).toUpperCase();
let sp_ic = document.getElementById("IC_Register");
sp_ic.innerText = "0x" + cpu.IC.toString(16).toUpperCase();
let sp_co = document.getElementById("CO_Register");
sp_co.innerHTML = "0b" + formatBinary(cpu.MC_Controls,32,4,["Microcode Counter Reset to 8","Microcode Counter Reset to 0","Instruction Register Input Enable","RAM Input Enable","","Output MUX Enable","Output Enable MUX4","Output Enable MUX3","Output Enable MUX2","Output Enable MUX1","Output Enable MUX0","ALU Shift Right","ALU Shift Left","ALU Carry","ALU Invert B","ALU MUX1","ALU MUX0","RAM Address High Byte Input Enable","RAM Address Register Input Enable","GPD High Byte Input Enable","GPD Low Byte Input Enable","GPC High Byte Input Enable","GPC Low Byte Input Enable","GPB High Byte Input Enable","GPB Low Byte Input Enable","GPA High Byte Input Enable","GPA Low Byte Input Enable","SP Input Enable","SP Counter Clock","SP Decrement","PC Input Enable","PC Increment"]);
let sp_sp = document.getElementById("SP_Register");
sp_sp.style.backgroundColor = "transparent";
if (cpu.MC_Controls & CONTROL_SPI) sp_sp.style.backgroundColor = "#ff5555";
if (cpu.MC_Controls & CONTROL_SPC) sp_sp.style.backgroundColor = "#55ff55";
if (cpu.MC_Controls & CONTROL_SPD) sp_sp.style.backgroundColor = "#7777ff";
sp_sp.innerText = "0x" + formatHex(cpu.SP | cpu.SPP << 16,6);
let sp_sr = document.getElementById("SR_Register");
sp_sr.innerHTML = "0b" + formatBinary(cpu.SR,8,4,["","","","","Negative","Overflow","Zero","Carry"]);
let sp_ir = document.getElementById("IR_Register");
sp_ir.innerText = `[0x${formatHex(cpu.IR,4)}] 0b` + formatBinary(cpu.IR,16,4) + " (" + GetMnemonic(Instructions,cpu.IR) + ")";
sp_ir.style.backgroundColor = "transparent";
if (cpu.MC_Controls & CONTROL_IRI) sp_ir.style.backgroundColor = "#ff5555";
let sp_ir2 = document.getElementById("IR2_Register");
sp_ir2.innerText = `[0x${formatHex(cpu.IR2,4)}] 0b` + formatBinary(cpu.IR2,16,4);
sp_ir2.style.backgroundColor = "transparent";
if (cpu.OUTMUX === OECONTROL_I2) sp_ir2.style.backgroundColor = "#ff5555";
if (cpu.OUTMUX === OECONTROL_2O) sp_ir2.style.backgroundColor = "#55ff55";
let sp_gpa = document.getElementById("GPA_Register");
sp_gpa.innerText = "0x" + formatHex(cpu.GPA,2);
sp_gpa.style.backgroundColor = "transparent";
if (cpu.MC_Controls & CONTROL_RAIL) sp_gpa.style.backgroundColor = "#cc5555";
if (cpu.MC_Controls & CONTROL_RAIH) sp_gpa.style.backgroundColor = "#ff5555";
if (cpu.OUTMUX === OECONTROL_AB || cpu.OUTMUX === OECONTROL_AC || cpu.OUTMUX === OECONTROL_AD || cpu.OUTMUX === OECONTROL_AL) sp_gpa.style.backgroundColor = "#55cc55";
if (cpu.OUTMUX === OECONTROL_BA || cpu.OUTMUX === OECONTROL_CA || cpu.OUTMUX === OECONTROL_DA || cpu.OUTMUX === OECONTROL_AH) sp_gpa.style.backgroundColor = "#55ff55";
let sp_gpb = document.getElementById("GPB_Register");
sp_gpb.innerText = "0x" + formatHex(cpu.GPB,2);
sp_gpb.style.backgroundColor = "transparent";
if (cpu.MC_Controls & CONTROL_RBIL) sp_gpb.style.backgroundColor = "#cc5555";
if (cpu.MC_Controls & CONTROL_RBIH) sp_gpb.style.backgroundColor = "#ff5555";
if (cpu.OUTMUX === OECONTROL_BA || cpu.OUTMUX === OECONTROL_BC || cpu.OUTMUX === OECONTROL_BD || cpu.OUTMUX === OECONTROL_BL) sp_gpb.style.backgroundColor = "#55cc55";
if (cpu.OUTMUX === OECONTROL_AB || cpu.OUTMUX === OECONTROL_CB || cpu.OUTMUX === OECONTROL_DB || cpu.OUTMUX === OECONTROL_BH) sp_gpb.style.backgroundColor = "#55ff55";
let sp_gpc = document.getElementById("GPC_Register");
sp_gpc.innerText = "0x" + formatHex(cpu.GPC,2);
sp_gpc.style.backgroundColor = "transparent";
if (cpu.MC_Controls & CONTROL_RCIL) sp_gpc.style.backgroundColor = "#cc5555";
if (cpu.MC_Controls & CONTROL_RCIH) sp_gpc.style.backgroundColor = "#ff5555";
if (cpu.OUTMUX === OECONTROL_CA || cpu.OUTMUX === OECONTROL_CB || cpu.OUTMUX === OECONTROL_CD || cpu.OUTMUX === OECONTROL_CL) sp_gpc.style.backgroundColor = "#55cc55";
if (cpu.OUTMUX === OECONTROL_AC || cpu.OUTMUX === OECONTROL_BC || cpu.OUTMUX === OECONTROL_DC || cpu.OUTMUX === OECONTROL_CH) sp_gpc.style.backgroundColor = "#55ff55";
let sp_gpd = document.getElementById("GPD_Register");
sp_gpd.innerText = "0x" + formatHex(cpu.GPD,2);
sp_gpd.style.backgroundColor = "transparent";
if (cpu.MC_Controls & CONTROL_RDIL) sp_gpd.style.backgroundColor = "#cc5555";
if (cpu.MC_Controls & CONTROL_RDIH) sp_gpd.style.backgroundColor = "#ff5555";
if (cpu.OUTMUX === OECONTROL_DA || cpu.OUTMUX === OECONTROL_DB || cpu.OUTMUX === OECONTROL_DC || cpu.OUTMUX === OECONTROL_DL) sp_gpd.style.backgroundColor = "#55cc55";
if (cpu.OUTMUX === OECONTROL_AD || cpu.OUTMUX === OECONTROL_BD || cpu.OUTMUX === OECONTROL_CD || cpu.OUTMUX === OECONTROL_DH) sp_gpd.style.backgroundColor = "#55ff55";
let sp_cf = document.getElementById("clk_freq");
sp_cf.innerText = Math.floor(cycleavgval) + "KHz";
let sp_ramaddr = document.getElementById("txt_ramaddr");
let sp_ramval = document.getElementById("txt_ramval");
sp_ramval.value = formatHex(cpu.RAM[parseInt(sp_ramaddr.value)],4);
printRAM(cpu.RAM);
let sp_textout = document.getElementById("TEXT_OUT");
sp_textout.innerText = printTextOut(cpu.RAM,0xd00000,0xd00000 + (80*24));
}
class CPU_8SA1 {
constructor() {
this.DATABUS = 0;
this.ADDRBUS = 0;
this.PC = 0; // Set PC register to 0
this.SP = BITMASK_16; // Set SP register to 0xFFFF
this.SPP = BITMASK_8;
this.SR = 0; // Set the STATUS register
this.RR = 0; // Set lower RAM register to 0
this.RH = 0; // Set higher RAM register to 0
this.GPA = 0; // Set the 4 GP registers
this.GPB = 0;
this.GPC = 0;
this.GPD = 0;
this.MCC = 0xF; // Set the microcode counter
this.IC = 0x0; // Set Instruction Counter to 0
this.IR = 0; // Set the initial IR
this.IR2 = 0; // IR2 is used for 3 word instructions
this.MC_Controls = 0; // Set the control output lines
this.ALUSUM = 0; // ALU Register to hold SUM
this.MCRAM = new Array(2 ** 16); // Initialize the microcode RAM
this.RAM = new Array(2 ** 24); // Initialize the main RAM array
let RAMSIZE = 2**24;
while(RAMSIZE--) this.RAM[RAMSIZE] = 0;
this._CLK = false;
}
CLOCK(clk_val) {
if (clk_val && !this._CLK) {
// Clock going HIGH
this._CLK = true;
this._CLOCK_HIGH();
} else {
if (!clk_val && this._CLK) {
// Clock going LOW
this._CLK = false;
this.DATABUS = 0;
this._CLOCK_LOW();
}
}
}
_CLOCK_HIGH() {
// Call anything that needs to be called on positive clock edge
let OUTMUX = false;
if (this.MC_Controls & CONTROL_OEME) {
OUTMUX = (this.MC_Controls & CONTROL_OEM4) ? 0b10000 : 0;
OUTMUX |= (this.MC_Controls & CONTROL_OEM3) ? 0b01000 : 0;
OUTMUX |= (this.MC_Controls & CONTROL_OEM2) ? 0b00100 : 0;
OUTMUX |= (this.MC_Controls & CONTROL_OEM1) ? 0b00010 : 0;
OUTMUX |= (this.MC_Controls & CONTROL_OEM0) ? 0b00001 : 0;
if (OUTMUX === OECONTROL_RO) {
this.DATABUS = this.RAM[this.ADDRBUS];
if (this.DATABUS === undefined) this.DATABUS = 0;
}
if (OUTMUX === OECONTROL_I2) {
this.DATABUS = this.RAM[this.ADDRBUS];
if (this.DATABUS === undefined) this.DATABUS = 0;
this.IR2 = this.DATABUS;
}
if (OUTMUX === OECONTROL_HS) {
this.DATABUS = this.RAM[this.ADDRBUS];
if (this.DATABUS === undefined) this.DATABUS = 0;
this.SPP = this.DATABUS & BITMASK_8;
}
if (OUTMUX === OECONTROL_SS) {
if (this.DATABUS === undefined) this.DATABUS = 0;
this.SR = this.DATABUS & BITMASK_8;
}
}
if (this.MC_Controls & CONTROL_PCC ) this.PC_CLK();
if (this.MC_Controls & CONTROL_PCI ) this.PC_In_CLK();
if (this.MC_Controls & CONTROL_SPC ) this.SP_CLK();
if (this.MC_Controls & CONTROL_SPI ) this.SP_In_CLK();
if (this.MC_Controls & CONTROL_RI ) this.RAM_In_CLK();
if (this.MC_Controls & CONTROL_IRI ) this.IR_In_CLK();
if (this.MC_Controls & CONTROL_RRI ) this.RR_In_CLK();
if (this.MC_Controls & CONTROL_RHI ) this.RH_In_CLK();
if ((OUTMUX === OECONTROL_SP) && (this.MC_Controls & CONTROL_RRI)) this.ADDRBUS = (this.ADDRBUS & BITMASK_16) | (this.SPP << 16);
if (this.MC_Controls & CONTROL_RAIL) this.GPA_In_LOW_CLK();
if (this.MC_Controls & CONTROL_RAIH) this.GPA_In_HIGH_CLK();
if (this.MC_Controls & CONTROL_RBIL) this.GPB_In_LOW_CLK();
if (this.MC_Controls & CONTROL_RBIH) this.GPB_In_HIGH_CLK();
if (this.MC_Controls & CONTROL_RCIL) this.GPC_In_LOW_CLK();
if (this.MC_Controls & CONTROL_RCIH) this.GPC_In_HIGH_CLK();
if (this.MC_Controls & CONTROL_RDIL) this.GPD_In_LOW_CLK();
if (this.MC_Controls & CONTROL_RDIH) this.GPD_In_HIGH_CLK();
if (this.MC_Controls & CONTROL_AE ) this.ALU_CLK();
if (this.ADDRBUS === 0xff0000 && this.DATABUS > 0) {
// clear the display
for (let a = 0xd00000; a < 0xdfffff; a++) {
this.RAM[a] = 0;
}
//console.log("Display Cleared");
}
if (this.ADDRBUS === 0xff0001 && this.DATABUS > 0) {
// Force an update
updateHTML();
}
}
_CLOCK_LOW() {
// Call anything that needs to be called on low going clock edge
this._FetchDecode_CLK_neg();
}
ALU_CLK() {
//console.log("ALU Enable");
let ALU_A = this.DATABUS & BITMASK_8;
let ALU_B = (this.DATABUS & (BITMASK_8 << 8)) >> 8;
let ALU_Result = 0;
let ALUMUX = (this.MC_Controls & CONTROL_ALUM1) ? 0b10 : 0;
ALUMUX |= (this.MC_Controls & CONTROL_ALUM0) ? 0b01 : 0;
//console.log(`ALU: A=${ALU_A}, B=${ALU_B}, MUX: ${ALUMUX}`);
//if (this.MC_Controls & CONTROL_ALUI) console.log("ALU Inverting B");
let SHIFTING = false;
if (this.MC_Controls & CONTROL_ALUSL) SHIFTING = true;
if (this.MC_Controls & CONTROL_ALUSR) SHIFTING = true;
switch (ALUMUX) {
case 0: { // ADD
if (this.MC_Controls & CONTROL_ALUI) ALU_B = ~ALU_B;
ALU_Result = ALU_A + ALU_B;
if (this.MC_Controls & CONTROL_ALUC && !SHIFTING) ALU_Result += 1;
//if (this.MC_Controls & CONTROL_ALUC && !SHIFTING) console.log("We are carrying in!");
break;
}
case 1: { // AND
ALU_Result = ALU_A & ALU_B;
if (this.MC_Controls & CONTROL_ALUI) ALU_Result = ~ALU_Result;
if (this.MC_Controls & CONTROL_ALUC && !SHIFTING) ALU_Result += 1;
break;
}
case 2: { // OR
ALU_Result = ALU_A | ALU_B;
//console.log(`ALU OR: A: ${ALU_A}, B: ${ALU_B}, Result: ${ALU_Result}`);
if (this.MC_Controls & CONTROL_ALUI) ALU_Result = ~ALU_Result;
if (this.MC_Controls & CONTROL_ALUC && !SHIFTING) ALU_Result += 1;
break;
}
case 3: { // XOR
ALU_Result = ALU_A ^ ALU_B;
if (this.MC_Controls & CONTROL_ALUI) ALU_Result = ~ALU_Result;
if (this.MC_Controls & CONTROL_ALUC && !SHIFTING) ALU_Result += 1;
break;
}
}
if (this.MC_Controls & CONTROL_ALUSL) ALU_Result = ALU_Result << 1;
if ((this.MC_Controls & CONTROL_ALUSL) && (this.MC_Controls & CONTROL_ALUC)) ALU_Result = ALU_Result | 0b00000001;
if (this.MC_Controls & CONTROL_ALUSR) ALU_Result = ALU_Result >> 1;
if ((this.MC_Controls & CONTROL_ALUSR) && (this.MC_Controls & CONTROL_ALUC)) ALU_Result = ALU_Result | 0b10000000;
if (ALU_Result & 0b100000000) {
// We have a carry
this.SR = this.SR | 0b00000001;
} else {
this.SR = this.SR & 0b11111110;
}
if (ALU_Result === 0) {
// We have a ZERO
this.SR = this.SR | 0b00000010;
} else {
this.SR = this.SR & 0b11111101;
}
if (~(((ALU_A & 0b10000000)>>7) ^ ((ALU_B & 0b10000000)>>7)) === -1) {
if ((ALU_A & 0b10000000) !== (ALU_Result & 0b10000000)) {
// We have an OVERFLOW
//console.log("overflow");
//console.log(((ALU_A & 0b10000000)>>7));
//console.log(((ALU_B & 0b10000000)>>7));
//console.log(((ALU_Result & 0b10000000)>>7));
this.SR = this.SR | 0b00000100;
}
} else {
this.SR = this.SR & 0b11111011;
}
if ((ALU_Result & 0b10000000) === 0b10000000) {
// We have a NEGATIVE
this.SR = this.SR | 0b00001000;
} else {
this.SR = this.SR & 0b11110111;
}
this.ALUSUM = ALU_Result & BITMASK_8;
}
_FetchDecode_CLK_neg() {
// We actually setup all of our fetch and decode logic during the clocks low phase
this.DATABUS = 0;
this.MCC += 1;
if (this.MCC > 15) this.MCC = 0;
let lSR = 0;
if ((this.IR & 0b0000010000000000) !== 0) {
// We are going to make the ZERO line a NEGATIVE line
lSR = ((this.SR & 0b00000001) << 14);
lSR |= ((this.SR & 0b00001000) << 12);
//console.log("We are doing a NEGATIVE instead of ZERO");
//console.log(formatBinary(lSR,16));
//console.log(formatHex(((this.IR & 0b0000001111111111) << 4) | this.MCC | lSR,4));
} else {
lSR = ((this.SR & 0b00000011) << 14);
}
let mcra = ((this.IR & 0b0000001111111111) << 4) | this.MCC | lSR;
let MC_Controls = this.MCRAM[mcra];
if (MC_Controls & CONTROL_MCL0) this.MCC = 0;
if (MC_Controls & CONTROL_MCL8) this.MCC = 8;
if (this.MCC === 0 && (this.SR & 0b10000000)) {
// The task interupt enable is set, so we will count instructions
this.IC += 1;
if (this.IC === 256) {
// Rollover, we will setup the IR to handle this
this.IC = 0;
this.IR = 0x3FE;
}
}
//if (MC_Controls & CONTROL_MCL0) console.log(`Reset microcode counter to 0`);
//if (MC_Controls & CONTROL_MCL8) console.log(`Reset microcode counter to 8`);
if ((this.IR & 0b0000010000000000) !== 0) {
// We are going to make the ZERO line a NEGATIVE line
lSR = ((this.SR & 0b00000001) << 14);
lSR |= ((this.SR & 0b00001000) << 12);
//console.log("We are doing a NEGATIVE instead of ZERO");
//console.log(formatBinary(lSR,16,4));
} else {
lSR = ((this.SR & 0b00000011) << 14);
}
mcra = ((this.IR & 0b0000001111111111) << 4) | this.MCC | lSR;
MC_Controls = this.MCRAM[mcra];
//if (this.IR === 0x711) console.log(formatHex(mcra,4));
if (MC_Controls === undefined) MC_Controls = 0;
//console.log(`[${mcra.toString(2)}] Control Lines: ${MC_Controls.toString(2)}`);
if (MC_Controls !== this.MC_Controls) {
if (MC_Controls & CONTROL_OEME) {
// Set the DATABUS based on whatever output we are controlling
let OUTMUX = (MC_Controls & CONTROL_OEM4) ? 0b10000 : 0;
OUTMUX |= (MC_Controls & CONTROL_OEM3) ? 0b01000 : 0;
OUTMUX |= (MC_Controls & CONTROL_OEM2) ? 0b00100 : 0;
OUTMUX |= (MC_Controls & CONTROL_OEM1) ? 0b00010 : 0;
OUTMUX |= (MC_Controls & CONTROL_OEM0) ? 0b00001 : 0;
this.OUTMUX = OUTMUX;
//console.log(`OUTPUT MUX: ${OUTMUX.toString(2)}`);
switch (OUTMUX) {
case OECONTROL_PC: {
this.DATABUS = this.PC;
//console.log("DATABUS = PC");
break;
}
case OECONTROL_SP: {
this.DATABUS = this.SP;
if (OECONTROL_SP && (MC_Controls & CONTROL_RRI)) this.ADDRBUS = (this.ADDRBUS & BITMASK_16) | (this.SPP << 16);
break;
}
case OECONTROL_AL: {
this.DATABUS = ((this.DATABUS & BITMASK_8) << 8) | (this.GPA & BITMASK_8);
//console.log("DATABUS LOW = A");
break;
}
case OECONTROL_AH: {
this.DATABUS = ((this.GPA & BITMASK_8) << 8) | (this.DATABUS & BITMASK_8);
//console.log("DATABUS HIGH = A");
break;
}
case OECONTROL_BL: {
this.DATABUS = ((this.DATABUS & BITMASK_8) << 8) | (this.GPB & BITMASK_8);
//console.log("DATABUS LOW = B");
break;
}
case OECONTROL_BH: {
this.DATABUS = ((this.GPB & BITMASK_8) << 8) | (this.DATABUS & BITMASK_8);
// console.log("DATABUS HIGH = B");
break;
}
case OECONTROL_CL: {
this.DATABUS = ((this.DATABUS & BITMASK_8) << 8) | (this.GPC & BITMASK_8);
//console.log("DATABUS LOW = C");
break;
}
case OECONTROL_CH: {
this.DATABUS = ((this.GPC & BITMASK_8) << 8) | (this.DATABUS & BITMASK_8);
//console.log("DATABUS HIGH = C");
break;
}
case OECONTROL_DL: {
this.DATABUS = ((this.DATABUS & BITMASK_8) << 8) | (this.GPD & BITMASK_8);
break;
}
case OECONTROL_DH: {
this.DATABUS = ((this.GPD & BITMASK_8) << 8) | (this.DATABUS & BITMASK_8);
break;
}
case OECONTROL_AB: {
this.DATABUS = ((this.GPB & BITMASK_8) << 8) | (this.GPA & BITMASK_8);
//console.log("DATABUS = AB");
break;
}
case OECONTROL_AC: {
this.DATABUS = ((this.GPC & BITMASK_8) << 8) | (this.GPA & BITMASK_8);
break;
}
case OECONTROL_AD: {
this.DATABUS = ((this.GPD & BITMASK_8) << 8) | (this.GPA & BITMASK_8);
break;
}
case OECONTROL_BA: {
this.DATABUS = ((this.GPA & BITMASK_8) << 8) | (this.GPB & BITMASK_8);
break;
}
case OECONTROL_BC: {
this.DATABUS = ((this.GPC & BITMASK_8) << 8) | (this.GPB & BITMASK_8);
break;
}
case OECONTROL_BD: {
this.DATABUS = ((this.GPD & BITMASK_8) << 8) | (this.GPB & BITMASK_8);
break;
}
case OECONTROL_CA: {
this.DATABUS = ((this.GPA & BITMASK_8) << 8) | (this.GPC & BITMASK_8);
break;
}
case OECONTROL_CB: {
this.DATABUS = ((this.GPB & BITMASK_8) << 8) | (this.GPC & BITMASK_8);
break;
}
case OECONTROL_CD: {
this.DATABUS = ((this.GPD & BITMASK_8) << 8) | (this.GPC & BITMASK_8);
break;
}
case OECONTROL_DA: {
this.DATABUS = ((this.GPA & BITMASK_8) << 8) | (this.GPD & BITMASK_8);
break;
}
case OECONTROL_DB: {
this.DATABUS = ((this.GPB & BITMASK_8) << 8) | (this.GPD & BITMASK_8);
break;
}
case OECONTROL_DC: {
this.DATABUS = ((this.GPC & BITMASK_8) << 8) | (this.GPD & BITMASK_8);
break;
}
case OECONTROL_TI: {
//console.log(`Storing PC [${formatHex(this.PC,6)}] to SP [${formatHex(this.SP,6)}]`);
this.DATABUS = 0x7F;
break;
}
case OECONTROL_I2: {
if (OECONTROL_I2 && (MC_Controls & CONTROL_SPC)) this.ADDRBUS = (this.ADDRBUS & BITMASK_16) | (this.SPP << 16);
break;
}
case OECONTROL_2O: {
this.DATABUS = this.IR2;
break;
}
case OECONTROL_HO: {
this.DATABUS = this.RH;
break;
}
case OECONTROL_HS: {
// this is done @ clock
break;
}
case OECONTROL_SS: {
this.DATABUS = ((this.DATABUS & BITMASK_8) << 8) | (this.GPA & BITMASK_8);
break;
}
case OECONTROL_AO: {
this.DATABUS = (this.DATABUS & (BITMASK_8 << 8)) | this.ALUSUM;
//console.log("DATABUS = SUM");
break;
}
case OECONTROL_SR: {
this.DATABUS = ((this.DATABUS & BITMASK_8) << 8) | (this.SR & BITMASK_8);
//console.log("DATABUS = STATUS REGISTER");
break;
}
case OECONTROL_RO: {
// We dont actually want to do anything here since ram outputs on CLK
//console.log("DATABUS = RAM (on CLK)");
break;
}
}
}
}
this.MC_Controls = MC_Controls;
}
_FetchDecode_CLK_pos() {
}
PC_CLK() {
this.PC += 1;
if (this.PC > BITMASK_16) this.PC = 0;
}
PC_In_CLK() {
this.PC = this.DATABUS;
}
SP_CLK() {
if (this.MC_Controls & CONTROL_SPD) {
this.SP -= 1;
if (this.SP < 0) this.SP = BITMASK_16;
} else {
this.SP += 1;
if (this.SP > BITMASK_16) this.SP = 0;
}
}
SP_In_CLK() {
this.SP = this.DATABUS;
}
RAM_In_CLK() {
this.RAM[this.ADDRBUS] = this.DATABUS;
}
IR_In_CLK() {
this.IR = this.DATABUS;
}
RR_In_CLK() {
this.RR = this.DATABUS;
this.ADDRBUS = this.RR | this.RH << 16;
}
RH_In_CLK() {
this.RH = (this.DATABUS & BITMASK_8);
this.ADDRBUS = this.RR | this.RH << 16;
}
GPA_In_LOW_CLK() {
this.GPA = this.DATABUS & 0x00ff;
//console.log(`GPA = DATABUS LOW`);
}
GPA_In_HIGH_CLK() {
this.GPA = (this.DATABUS & 0xff00) >> 8;
//console.log(`GPA = DATABUS HIGH`);
}
GPB_In_LOW_CLK() {
this.GPB = this.DATABUS & 0x00ff;
//console.log(`GPB = DATABUS LOW`);
}
GPB_In_HIGH_CLK() {
this.GPB = (this.DATABUS & 0xff00) >> 8;
//console.log(`GPB = DATABUS HIGH`);
}
GPC_In_LOW_CLK() {
this.GPC = this.DATABUS & 0x00ff;
//console.log(`GPC = DATABUS LOW`);
}
GPC_In_HIGH_CLK() {
this.GPC = (this.DATABUS & 0xff00) >> 8;
//console.log(`GPC = DATABUS HIGH`);
}
GPD_In_LOW_CLK() {
this.GPD = this.DATABUS & 0x00ff;
}
GPD_In_HIGH_CLK() {
this.GPD = (this.DATABUS & 0xff00) >> 8;
}
PrintDebug() {
// We want to print out all the registers in a way that makes sense
}
}