8SA1Sim/js/cpu.js

661 lines
31 KiB
JavaScript

// Setup a few bitmasks we can use in the code that are handy to clean inputs to registers
const BITMASK_8 = 0x00000000000000ff;
const BITMASK_16 = 0x000000000000ffff;
const BITMASK_24 = 0x0000000000ffffff;
// These are the control lines that are controlled by the microcode RAM output
const CONTROL_PCC = 0b00000000000000000000000000000001; // PC CLK UP
const CONTROL_PCI = 0b00000000000000000000000000000010; // PC Input Enable
const CONTROL_SPD = 0b00000000000000000000000000000100; // SP Count Down
const CONTROL_SPC = 0b00000000000000000000000000001000; // SP CLK (UP / DOWN)
const CONTROL_SPI = 0b00000000000000000000000000010000; // SP Input Enable
const CONTROL_RAIL = 0b00000000000000000000000000100000; // GPA LOW Input Enable
const CONTROL_RAIH = 0b00000000000000000000000001000000; // GPA HIGH Input Enable
const CONTROL_RBIL = 0b00000000000000000000000010000000; // GPB LOW Input Enable
const CONTROL_RBIH = 0b00000000000000000000000100000000; // GPB HIGH Input Enable
const CONTROL_RCIL = 0b00000000000000000000001000000000; // GPC LOW Input Enable
const CONTROL_RCIH = 0b00000000000000000000010000000000; // GPC HIGH Input Enable
const CONTROL_RDIL = 0b00000000000000000000100000000000; // GPD LOW Input Enable
const CONTROL_RDIH = 0b00000000000000000001000000000000; // GPD HIGH Input Enable
const CONTROL_RRI = 0b00000000000000000010000000000000; // LOW Ram Register Input Enable
const CONTROL_RHI = 0b00000000000000000100000000000000; // HIGH Ram Register Input Enable
const CONTROL_ALUM0 = 0b00000000000000001000000000000000; // ALU MUX 0
const CONTROL_ALUM1 = 0b00000000000000010000000000000000; // ALU MUX 1
const CONTROL_ALUI = 0b00000000000000100000000000000000; // ALU Invert (high side)
const CONTROL_ALUC = 0b00000000000001000000000000000000; // ALU Carry Input
const CONTROL_ALUSL = 0b00000000000010000000000000000000; // ALU Shift Left
const CONTROL_ALUSR = 0b00000000000100000000000000000000; // ALU Shift Right
const CONTROL_OEM0 = 0b00000000001000000000000000000000; // Output Enable MUX 0
const CONTROL_OEM1 = 0b00000000010000000000000000000000; // Output Enable MUX 1
const CONTROL_OEM2 = 0b00000000100000000000000000000000; // Output Enable MUX 2
const CONTROL_OEM3 = 0b00000001000000000000000000000000; // Output Enable MUX 3
const CONTROL_OEM4 = 0b00000010000000000000000000000000; // Output Enable MUX 4
const CONTROL_OEME = 0b00000100000000000000000000000000; // Output Enable MUX Enable
const CONTROL_RI = 0b00010000000000000000000000000000; // RAM Input Enable
const CONTROL_IRI = 0b00100000000000000000000000000000; // Instruction Register Input Enable
const CONTROL_MCL0 = 0b01000000000000000000000000000000; // Microcode Counter to 0
const CONTROL_MCL8 = 0b10000000000000000000000000000000; // Microcode Counter to 8
// These are the output enable control lines, they are muxed since none of them can ever be on together
const OECONTROL_PC = 0b00000 // PC Register
const OECONTROL_SP = 0b00001 // SP Register
const OECONTROL_AL = 0b00010 // GPA to LOW
const OECONTROL_AH = 0b00011 // GPA to HIGH
const OECONTROL_BL = 0b00100 // GPB to LOW
const OECONTROL_BH = 0b00101 // GPB to HIGH
const OECONTROL_CL = 0b00110 // GPC to LOW
const OECONTROL_CH = 0b00111 // GPC to HIGH
const OECONTROL_DL = 0b01000 // GPD to LOW
const OECONTROL_DH = 0b01001 // GPD to HIGH
const OECONTROL_AB = 0b01010 // GPB to HIGH, GPA to LOW
const OECONTROL_AC = 0b01011 // GPC to HIGH, GPA to LOW
const OECONTROL_AD = 0b01100 // GPD to HIGH, GPA to LOW
const OECONTROL_BA = 0b01101 // GPA to HIGH, GPB to LOW
const OECONTROL_BC = 0b01110 // GPC to HIGH, GPB to LOW
const OECONTROL_BD = 0b01111 // GPD to HIGH, GPB to LOW
const OECONTROL_CA = 0b10000 // GPA to HIGH, GPC to LOW
const OECONTROL_CB = 0b10001 // GPB to HIGH, GPC to LOW
const OECONTROL_CD = 0b10010 // GPD to HIGH, GPC to LOW
const OECONTROL_DA = 0b10011 // GPA to HIGH, GPD to LOW
const OECONTROL_DB = 0b10100 // GPB to HIGH, GPD to LOW
const OECONTROL_DC = 0b10101 // GPC to HIGH, GPD to LOW
const OECONTROL_AE = 0b11100 // ALU Enable
const OECONTROL_AO = 0b11101 // ALU Output to LOW
const OECONTROL_SR = 0b11110 // Status Register to LOW
const OECONTROL_RO = 0b11111 // RAM to DATABUS Enable
let intval = null;
let breakpt = null;
function stringToRAM(rstring,ram,address) {
for (let a = 0; a < rstring.length; a++) {
ram[address+a] = rstring.charCodeAt(a);
}
}
function reverseString(str) {
return str.split("").reverse().join("");
}
function formatHex(value,places,spaces=0) {
let hexval = parseInt(value,10).toString(16).toUpperCase();
if (hexval.length < places) {
let placecount = (places - hexval.length);
for (let a = 0; a < placecount; a++) {
hexval = "0" + hexval;
}
}
if (spaces > 0) {
hexval = reverseString(hexval);
let newhexval = "";
for (let a = 0; a < hexval.length; a++) {
newhexval += hexval.substring(a,a+1);
if ((a % spaces) === 3 && a !== hexval.length-1) newhexval += " ";
}
hexval = reverseString(newhexval);
}
return hexval;
}
function formatBinary(value,places,spaces=0,labels = false) {
let hexval = parseInt(value,10).toString(2);
if (hexval.length < places) {
let placecount = (places - hexval.length);
for (let a = 0; a < placecount; a++) {
hexval = "0" + hexval;
}
}
if (spaces > 0) {
hexval = reverseString(hexval);
let newhexval = "";
for (let a = 0; a < hexval.length; a++) {
if (labels) {
newhexval += reverseString(`</span>`) + hexval.substring(a,a+1) + reverseString(`<span title="${labels[(places-1)-a]}">`);
} else {
newhexval += hexval.substring(a,a+1);
}
if ((a % spaces) === 3 && a !== hexval.length-1) newhexval += " ";
}
hexval = reverseString(newhexval);
}
return hexval;
}
function GetMnemonic(mcarray,instruction) {
for (let a = 0; a < mcarray.length; a++) {
if (mcarray[a] === instruction || mcarray[a].Bytecode === instruction) {
return mcarray[a].Mnemonic;
}
}
}
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() {
/* if (cpu._CLK) {
cpu.CLOCK(false);
} else {
cpu.CLOCK(true);
}*/
cpu.CLOCK(true);
clk_count++;
clk_counter.innerText = clk_count;
cpu.CLOCK(false);
if (cpu.ADDRBUS === breakpt) clearInterval(intval);
}
function drawCPUInfo() {
updateHTML();
window.requestAnimationFrame(drawCPUInfo);
}
function RunUntilBreak(addr) {
breakpt = addr;
intval = setInterval(function(){
generateClocks_Interval();
}, parseInt(clkinterval.value));
}
function printTextOut(ram,startaddr,endaddr) {
let outString = "";
for (let a = startaddr; a <= endaddr; a++) {
if (ram[a] === 0) return outString; // kill on null
outString += String.fromCharCode(ram[a]);
}
}
function printRAM(ram) {
let startADDR = (cpu.ADDRBUS & 0xfff0) - 0x80;
if (startADDR < 0) startADDR = 0;
if (startADDR > 0xFEFF) startADDR = 0xFF00;
let sp_ram = document.getElementById("RAM");
let ramtext = "ADDR&nbsp;&nbsp;:&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;6&nbsp;&nbsp;&nbsp;&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;A&nbsp;&nbsp;&nbsp;&nbsp;B&nbsp;&nbsp;&nbsp;&nbsp;C&nbsp;&nbsp;&nbsp;&nbsp;D&nbsp;&nbsp;&nbsp;&nbsp;E&nbsp;&nbsp;&nbsp;&nbsp;F<br />";
for (let a = startADDR; a < (startADDR+255); a+=16) {
ramtext += "0x" + formatHex(a,4) + ": ";
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 += `<span style="background-color: ${bgcolor}">`;
}
ramtext += formatHex(ram[(a)+b],4) + " ";
if (cpu.ADDRBUS === (a)+b) ramtext += '</span>';
}
ramtext += "<br />";
}
sp_ram.innerHTML = ramtext;
let sp_stackram = document.getElementById("STACK-RAM");
ramtext = "ADDR&nbsp;&nbsp;:&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;6&nbsp;&nbsp;&nbsp;&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;A&nbsp;&nbsp;&nbsp;&nbsp;B&nbsp;&nbsp;&nbsp;&nbsp;C&nbsp;&nbsp;&nbsp;&nbsp;D&nbsp;&nbsp;&nbsp;&nbsp;E&nbsp;&nbsp;&nbsp;&nbsp;F<br />";
for (let a = 0xffe0; a < 0x10000; a+=16) {
ramtext += "0x" + formatHex(a,4) + ": ";
for (let b = 0; b < 16; b++) {
if (cpu.ADDRBUS === (a)+b) ramtext += '<span style="background-color: #ffff55">';
ramtext += formatHex(ram[(a)+b],4) + " ";
if (cpu.ADDRBUS === (a)+b) ramtext += '</span>';
}
ramtext += "<br />";
}
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_PCI) sp_pc.style.backgroundColor = "#ff5555";
if (cpu.MC_Controls & CONTROL_PCC) sp_pc.style.backgroundColor = "#55ff55";
let sp_mcc = document.getElementById("MCC_Register");
sp_mcc.innerText = "0x" + cpu.MCC.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,4);
let sp_sr = document.getElementById("SR_Register");
sp_sr.innerHTML = "0b" + formatBinary(cpu.SR,8,4,["","","","","","Negative","Zero","Carry"]);
let sp_ir = document.getElementById("IR_Register");
sp_ir.innerText = "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_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";
printRAM(cpu.RAM);
let sp_textout = document.getElementById("TEXT_OUT");
sp_textout.innerText = printTextOut(cpu.RAM,0x8000,0x83ff);
}
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.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.IR = 0; // Set the initial IR
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._CLOCK_LOW();
}
}
}
_CLOCK_HIGH() {
// Call anything that needs to be called on positive clock edge
if (this.MC_Controls & CONTROL_OEME) {
let 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) {
//console.log("DATABUS = RAM");
this.DATABUS = this.RAM[this.ADDRBUS];
if (this.DATABUS === undefined) this.DATABUS = 0;
}
}
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 (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();
}
_CLOCK_LOW() {
// Call anything that needs to be called on low going clock edge
this._FetchDecode_CLK_neg();
}
_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 mcra = ((this.IR & 0b0000001111111111) << 4) | this.MCC | ((this.SR & 0b00000011) << 14);
let MC_Controls = this.MCRAM[mcra];
if (MC_Controls & CONTROL_MCL0) this.MCC = 0;
if (MC_Controls & CONTROL_MCL8) this.MCC = 8;
//if (MC_Controls & CONTROL_MCL0) console.log(`Reset microcode counter to 0`);
//if (MC_Controls & CONTROL_MCL8) console.log(`Reset microcode counter to 8`);
mcra = ((this.IR & 0b0000001111111111) << 4) | this.MCC | ((this.SR & 0b00000011) << 14);
MC_Controls = this.MCRAM[mcra];
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;
//console.log("DATABUS = SP");
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_AE: {
//console.log("ALU Enable");
this.DATABUS = (this.GPB << 8) | this.GPA;
let ALU_A = this.DATABUS & BITMASK_8;
let ALU_B = (this.DATABUS & (BITMASK_8 << 8)) >> 8;
let ALU_Result = 0;
let ALUMUX = (MC_Controls & CONTROL_ALUM1) ? 0b10 : 0;
ALUMUX |= (MC_Controls & CONTROL_ALUM0) ? 0b01 : 0;
//console.log(`ALU: A=${ALU_A}, B=${ALU_B}, MUX: ${ALUMUX}`);
if (MC_Controls & CONTROL_ALUI) console.log("ALU Inverting B");
let SHIFTING = false;
if (MC_Controls & CONTROL_ALUSL) SHIFTING = true;
if (MC_Controls & CONTROL_ALUSR) SHIFTING = true;
switch (ALUMUX) {
case 0: { // ADD
if (MC_Controls & CONTROL_ALUI) ALU_B = ~ALU_B;
ALU_Result = ALU_A + ALU_B;
if (MC_Controls & CONTROL_ALUC && !SHIFTING) ALU_Result += 1;
break;
}
case 1: { // AND
ALU_Result = ALU_A & ALU_B;
if (MC_Controls & CONTROL_ALUI) ALU_Result = ~ALU_Result;
if (MC_Controls & CONTROL_ALUC && !SHIFTING) ALU_Result += 1;
break;
}
case 2: { // OR
ALU_Result = ALU_A | ALU_B;
if (MC_Controls & CONTROL_ALUI) ALU_Result = ~ALU_Result;
if (MC_Controls & CONTROL_ALUC && !SHIFTING) ALU_Result += 1;
break;
}
case 3: { // XOR
ALU_Result = ALU_A ^ ALU_B;
if (MC_Controls & CONTROL_ALUI) ALU_Result = ~ALU_Result;
if (MC_Controls & CONTROL_ALUC && !SHIFTING) ALU_Result += 1;
break;
}
}
if (MC_Controls & CONTROL_ALUSL) ALU_Result = ALU_Result << 1;
if ((MC_Controls & CONTROL_ALUSL) && (MC_Controls & CONTROL_ALUC)) ALU_Result = ALU_Result | 0b00000001;
if (MC_Controls & CONTROL_ALUSR) ALU_Result = ALU_Result >> 1;
if ((MC_Controls & CONTROL_ALUSR) && (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;
}
this.ALUSUM = ALU_Result & 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;
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
}
}