714 lines
31 KiB
JavaScript
714 lines
31 KiB
JavaScript
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<br />";
|
|
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 += `<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 | 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 += '<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_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
|
|
}
|
|
}
|
|
|