661 lines
31 KiB
JavaScript
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 : 0 1 2 3 4 5 6 7 8 9 A B C D E 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 : 0 1 2 3 4 5 6 7 8 9 A B C D E 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
|
|
}
|
|
}
|
|
|