Added interface and demo code to run
This commit is contained in:
parent
bf769d0855
commit
f67b5c3e64
49
index.html
49
index.html
@ -2,8 +2,53 @@
|
||||
<head>
|
||||
<title>MatCat's 8SA1 CPU Simulator</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="js/main.js"></script>
|
||||
<body style="font-family: monospace; font-size: 1.5em;">
|
||||
<div>
|
||||
<span>ADDRESS: </span><span id="Address_BUS"></span>
|
||||
</div>
|
||||
<div>
|
||||
<span>DATA: </span><span id="Data_BUS"></span>
|
||||
</div>
|
||||
<div>
|
||||
<span>PC: </span><span id="PC_Register"></span>
|
||||
</div>
|
||||
<div>
|
||||
<span>MCC: </span><span id="MCC_Register"></span>
|
||||
</div>
|
||||
<div>
|
||||
<span>CO: </span><span id="CO_Register"></span>
|
||||
</div>
|
||||
<div>
|
||||
<span>SP: </span><span id="SP_Register"></span>
|
||||
</div>
|
||||
<div>
|
||||
<span>SR: </span><span id="SR_Register"></span>
|
||||
</div>
|
||||
<div>
|
||||
<span>IR: </span><span id="IR_Register"></span>
|
||||
</div>
|
||||
<div>
|
||||
<span>GPA: </span><span id="GPA_Register"></span>
|
||||
</div>
|
||||
<div>
|
||||
<span>GPB: </span><span id="GPB_Register"></span>
|
||||
</div>
|
||||
<div>
|
||||
<span>GPC: </span><span id="GPC_Register"></span>
|
||||
</div>
|
||||
<div>
|
||||
<span>GPD: </span><span id="GPD_Register"></span>
|
||||
</div>
|
||||
<div>
|
||||
<input type="button" id ="btn_clk" value="CLOCK" />
|
||||
<span id="clk_counter">0</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>RAM: </span><br /><span id="RAM"></brspan>
|
||||
</div>
|
||||
|
||||
<script src="js/cpu.js"></script>
|
||||
<script src="js/microcode_compiler.js"></script>
|
||||
<script src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
525
js/cpu.js
Normal file
525
js/cpu.js
Normal file
@ -0,0 +1,525 @@
|
||||
function formatHex(value,places) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
updateHTML();
|
||||
cpu.CLOCK(false);
|
||||
updateHTML();
|
||||
}
|
||||
}
|
||||
|
||||
function printRAM(ram) {
|
||||
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 = 0; a < 16; a++) {
|
||||
ramtext += "0x" + formatHex(a*16,4) + ": ";
|
||||
for (let b = 0; b < 16; b++) {
|
||||
if (cpu.ADDRBUS === (a*16)+b) ramtext += '<span style="background-color: #ffff55">';
|
||||
ramtext += formatHex(ram[(a*16)+b],4) + " ";
|
||||
if (cpu.ADDRBUS === (a*16)+b) ramtext += '</span>';
|
||||
}
|
||||
ramtext += "<br />";
|
||||
}
|
||||
sp_ram.innerHTML = ramtext;
|
||||
}
|
||||
|
||||
function updateHTML() {
|
||||
let sp_addr = document.getElementById("Address_BUS");
|
||||
sp_addr.innerText = "0x" + cpu.ADDRBUS.toString(16).toUpperCase();
|
||||
let sp_data = document.getElementById("Data_BUS");
|
||||
sp_data.innerText = "0x" + cpu.DATABUS.toString(16).toUpperCase();
|
||||
let sp_pc = document.getElementById("PC_Register");
|
||||
sp_pc.innerText = "0x" + cpu.PC.toString(16).toUpperCase();
|
||||
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.innerText = "0b" + cpu.MC_Controls.toString(2);
|
||||
let sp_sp = document.getElementById("SP_Register");
|
||||
sp_sp.innerText = "0x" + cpu.SP.toString(16).toUpperCase();
|
||||
let sp_sr = document.getElementById("SR_Register");
|
||||
sp_sr.innerText = "0b" + cpu.SR.toString(2);
|
||||
let sp_ir = document.getElementById("IR_Register");
|
||||
sp_ir.innerText = "0b" + cpu.IR.toString(2) + " (" + GetMnemonic(Instructions,cpu.IR) + ")";
|
||||
let sp_gpa = document.getElementById("GPA_Register");
|
||||
sp_gpa.innerText = "0x" + cpu.GPA.toString(16).toUpperCase();
|
||||
let sp_gpb = document.getElementById("GPB_Register");
|
||||
sp_gpb.innerText = "0x" + cpu.GPB.toString(16).toUpperCase();
|
||||
let sp_gpc = document.getElementById("GPC_Register");
|
||||
sp_gpc.innerText = "0x" + cpu.GPC.toString(16).toUpperCase();
|
||||
let sp_gpd = document.getElementById("GPD_Register");
|
||||
sp_gpd.innerText = "0x" + cpu.GPD.toString(16).toUpperCase();
|
||||
printRAM(cpu.RAM);
|
||||
}
|
||||
// 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
|
||||
|
||||
|
||||
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) << 15);
|
||||
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) << 15);
|
||||
MC_Controls = this.MCRAM[mcra];
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
440
js/main.js
440
js/main.js
@ -1,417 +1,31 @@
|
||||
// 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;
|
||||
let cpu = new CPU_8SA1();
|
||||
GenerateMicrocode(Instructions,cpu);
|
||||
cpu.RAM[0] = is_LDA_i.Bytecode;
|
||||
cpu.RAM[1] = 0;
|
||||
cpu.RAM[2] = is_LDB_i.Bytecode;
|
||||
cpu.RAM[3] = 100;
|
||||
cpu.RAM[4] = is_ADD.Bytecode;
|
||||
cpu.RAM[5] = is_BCC_i.Bytecode;
|
||||
cpu.RAM[6] = 4;
|
||||
cpu.RAM[7] = is_LDD_i.Bytecode;
|
||||
cpu.RAM[8] = 69;
|
||||
cpu.RAM[9] = is_STDL_i.Bytecode;
|
||||
cpu.RAM[10] = 0x69;
|
||||
|
||||
// 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 = 0b1000000000000000000000000000000; // Microcode Counter to 8
|
||||
updateHTML();
|
||||
|
||||
// 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 btn_clk = document.getElementById("btn_clk");
|
||||
let clk_counter = document.getElementById("clk_counter");
|
||||
let clk_count = 0;
|
||||
|
||||
btn_clk.addEventListener('mousedown', function(evt) {
|
||||
cpu.CLOCK(true);
|
||||
clk_count++;
|
||||
clk_counter.innerText = clk_count;
|
||||
updateHTML();
|
||||
});
|
||||
|
||||
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 = 0; // 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
|
||||
|
||||
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) this.DATABUS = this.RAM[this.ADDRBUS];
|
||||
}
|
||||
|
||||
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;
|
||||
let MC_Controls = this.MCRAM[((this.IR & 0b0000001111111111) << 4) | this.MCC | ((this.SR & 0b00000011) << 14)];
|
||||
if (MC_Controls & CONTROL_MCL0) this.MCC = 0;
|
||||
if (MC_Controls & CONTROL_MCL8) this.MCC = 8;
|
||||
|
||||
if (MC_Controls !== this.MC_Controls) {
|
||||
if (this.MC_Controls & CONTROL_OEME) {
|
||||
// Set the DATABUS based on whatever output we are controlling
|
||||
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;
|
||||
|
||||
switch (OUTMUX) {
|
||||
case OECONTROL_PC: {
|
||||
this.DATABUS = this.PC;
|
||||
break;
|
||||
}
|
||||
case OECONTROL_SP: {
|
||||
this.DATABUS = this.SP;
|
||||
break;
|
||||
}
|
||||
case OECONTROL_AL: {
|
||||
this.DATABUS = ((this.DATABUS & BITMASK_8) << 8) | (this.GPA & BITMASK_8);
|
||||
break;
|
||||
}
|
||||
case OECONTROL_AH: {
|
||||
this.DATABUS = ((this.GPA & BITMASK_8) << 8) | (this.DATABUS & BITMASK_8);
|
||||
break;
|
||||
}
|
||||
case OECONTROL_BL: {
|
||||
this.DATABUS = ((this.DATABUS & BITMASK_8) << 8) | (this.GPB & BITMASK_8);
|
||||
break;
|
||||
}
|
||||
case OECONTROL_BH: {
|
||||
this.DATABUS = ((this.GPB & BITMASK_8) << 8) | (this.DATABUS & BITMASK_8);
|
||||
break;
|
||||
}
|
||||
case OECONTROL_CL: {
|
||||
this.DATABUS = ((this.DATABUS & BITMASK_8) << 8) | (this.GPC & BITMASK_8);
|
||||
break;
|
||||
}
|
||||
case OECONTROL_CH: {
|
||||
this.DATABUS = ((this.GPC & BITMASK_8) << 8) | (this.DATABUS & BITMASK_8);
|
||||
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);
|
||||
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: {
|
||||
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;
|
||||
|
||||
let SHIFTING = false;
|
||||
if (MC_Controls & CONTROL_ALUSL) SHIFTING = true;
|
||||
if (MC_Controls & CONTROL_ALUSR) SHIFTING = true;
|
||||
|
||||
switch (ALUMUX) {
|
||||
case 0: { // ADD
|
||||
if (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 (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 (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 (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;
|
||||
break;
|
||||
}
|
||||
case OECONTROL_SR: {
|
||||
this.DATABUS = ((this.DATABUS & BITMASK_8) << 8) | (this.SR & BITMASK_8);
|
||||
break;
|
||||
}
|
||||
case OECONTROL_RO: {
|
||||
// We dont actually want to do anything here since ram outputs 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;
|
||||
}
|
||||
|
||||
GPA_In_HIGH_CLK() {
|
||||
this.GPA = (this.DATABUS & 0xff00) >> 8;
|
||||
}
|
||||
|
||||
GPB_In_LOW_CLK() {
|
||||
this.GPB = this.DATABUS & 0x00ff;
|
||||
}
|
||||
|
||||
GPB_In_HIGH_CLK() {
|
||||
this.GPB = (this.DATABUS & 0xff00) >> 8;
|
||||
}
|
||||
|
||||
GPC_In_LOW_CLK() {
|
||||
this.GPC = this.DATABUS & 0x00ff;
|
||||
}
|
||||
|
||||
GPC_In_HIGH_CLK() {
|
||||
this.GPC = (this.DATABUS & 0xff00) >> 8;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
btn_clk.addEventListener('mouseup', function(evt) {
|
||||
cpu.CLOCK(false);
|
||||
updateHTML();
|
||||
});
|
@ -33,6 +33,14 @@ const CONTROL_MCL8 = 0b10000000000000000000000000000000; // Micr
|
||||
*/
|
||||
const CONTROL_OUT_PC = CONTROL_OEME;
|
||||
const CONTROL_OUT_SP = CONTROL_OEME | CONTROL_OEM0;
|
||||
const CONTROL_OUT_AL = CONTROL_OEME | CONTROL_OEM1;
|
||||
const CONTROL_OUT_AH = CONTROL_OEME | CONTROL_OEM1 | CONTROL_OEM0;
|
||||
const CONTROL_OUT_BL = CONTROL_OEME | CONTROL_OEM2;
|
||||
const CONTROL_OUT_BH = CONTROL_OEME | CONTROL_OEM2 | CONTROL_OEM0;
|
||||
const CONTROL_OUT_CL = CONTROL_OEME | CONTROL_OEM2 | CONTROL_OEM1;
|
||||
const CONTROL_OUT_CH = CONTROL_OEME | CONTROL_OEM2 | CONTROL_OEM1 | CONTROL_OEM0;
|
||||
const CONTROL_OUT_DL = CONTROL_OEME | CONTROL_OEM3;
|
||||
const CONTROL_OUT_DH = CONTROL_OEME | CONTROL_OEM3 | CONTROL_OEM0;
|
||||
const CONTROL_OUT_AB = CONTROL_OEME | CONTROL_OEM3 | CONTROL_OEM1;
|
||||
const CONTROL_OUT_AE = CONTROL_OEME | CONTROL_OEM4 | CONTROL_OEM3 | CONTROL_OEM2;
|
||||
const CONTROL_OUT_AO = CONTROL_OEME | CONTROL_OEM4 | CONTROL_OEM3 | CONTROL_OEM2 | CONTROL_OEM0;
|
||||
@ -42,14 +50,29 @@ const CONTROL_ALU_ADD = CONTROL_OUT_AE;
|
||||
|
||||
let Instructions = new Array();
|
||||
|
||||
function GenerateMicrocode(mcarray) {
|
||||
function GenerateMicrocode(mcarray,cpu) {
|
||||
for (let a = 0; a < mcarray.length; a++) {
|
||||
for (let b = 0; b < 16; b++) {
|
||||
let bytecode = mcarray[a].Bytecode;
|
||||
let mca = mcarray[a].Bytecode << 4;
|
||||
mca |= b;
|
||||
let mcv = mcarray[a].Microcode[b];
|
||||
console.log(`[${bytecode.toString(16)}] ${mca.toString(16)}: ${mcv.toString(2)}`);
|
||||
|
||||
|
||||
for (let c = 0; c < 3; c++) {
|
||||
let offset = 0;
|
||||
if (c === 1) offset = 0b0100000000000000;
|
||||
if (c === 2) offset = 0b1000000000000000;
|
||||
|
||||
if (c === 0) console.log(`Now populating no-conditional instructions...`);
|
||||
if (c === 1) console.log(`Now populating conditional ZERO instructions...`);
|
||||
if (c === 2) console.log(`Now populating conditional Carry instructions...`);
|
||||
|
||||
for (let b = 0; b < 16; b++) {
|
||||
let bytecode = mcarray[a].Bytecode;
|
||||
let mca = mcarray[a].Bytecode << 4;
|
||||
mca |= b;
|
||||
let mcv = mcarray[a].Microcode[b];
|
||||
if (mcarray[a].UsesZero && c === 1) mcv = mcarray[a].MicrocodeZero[b];
|
||||
if (mcarray[a].UsesCarry && c === 2) mcv = mcarray[a].MicrocodeCarry[b];
|
||||
cpu.MCRAM[offset + mca] = mcv;
|
||||
//console.log(`[${bytecode.toString(16)}] ${mca.toString(16)}: ${mcv.toString(2)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -58,6 +81,7 @@ function GenerateMicrocode(mcarray) {
|
||||
class Microcode_Instruction {
|
||||
constructor() {
|
||||
this.Bytecode = 0x000; // MAX IS 0x3ff
|
||||
this.Mnemonic = "NOP";
|
||||
this.Microcode = new Array(16);
|
||||
|
||||
this.UsesCarry = false;
|
||||
@ -71,11 +95,11 @@ class Microcode_Instruction {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class IS_LDA_imm extends Microcode_Instruction {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.Bytecode = 0x000;
|
||||
this.Mnemonic = "LDA";
|
||||
this.Microcode[2] = CONTROL_OUT_PC | CONTROL_RRI;
|
||||
this.Microcode[3] = CONTROL_OUT_RO | CONTROL_RAIL | CONTROL_PCC;
|
||||
}
|
||||
@ -87,6 +111,7 @@ class IS_LDB_imm extends Microcode_Instruction {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.Bytecode = 0x001;
|
||||
this.Mnemonic = "LDB";
|
||||
this.Microcode[2] = CONTROL_OUT_PC | CONTROL_RRI;
|
||||
this.Microcode[3] = CONTROL_OUT_RO | CONTROL_RBIL | CONTROL_PCC;
|
||||
}
|
||||
@ -98,6 +123,7 @@ class IS_LDC_imm extends Microcode_Instruction {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.Bytecode = 0x002;
|
||||
this.Mnemonic = "LDC";
|
||||
this.Microcode[2] = CONTROL_OUT_PC | CONTROL_RRI;
|
||||
this.Microcode[3] = CONTROL_OUT_RO | CONTROL_RCIL | CONTROL_PCC;
|
||||
}
|
||||
@ -109,6 +135,7 @@ class IS_LDD_imm extends Microcode_Instruction {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.Bytecode = 0x003;
|
||||
this.Mnemonic = "LDD";
|
||||
this.Microcode[2] = CONTROL_OUT_PC | CONTROL_RRI;
|
||||
this.Microcode[3] = CONTROL_OUT_RO | CONTROL_RDIL | CONTROL_PCC;
|
||||
}
|
||||
@ -116,11 +143,117 @@ class IS_LDD_imm extends Microcode_Instruction {
|
||||
is_LDD_i = new IS_LDD_imm;
|
||||
Instructions.push(is_LDD_i);
|
||||
|
||||
class IS_STAL_imm extends Microcode_Instruction {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.Bytecode = 0x004;
|
||||
this.Mnemonic = "STAL";
|
||||
this.Microcode[2] = CONTROL_OUT_PC | CONTROL_RRI;
|
||||
this.Microcode[3] = CONTROL_OUT_RO | CONTROL_RRI | CONTROL_PCC;
|
||||
this.Microcode[4] = CONTROL_OUT_AL | CONTROL_RI;
|
||||
}
|
||||
}
|
||||
is_STAL_i = new IS_STAL_imm;
|
||||
Instructions.push(is_STAL_i);
|
||||
|
||||
class IS_STAH_imm extends Microcode_Instruction {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.Bytecode = 0x005;
|
||||
this.Mnemonic = "STAH";
|
||||
this.Microcode[2] = CONTROL_OUT_PC | CONTROL_RRI;
|
||||
this.Microcode[3] = CONTROL_OUT_RO | CONTROL_RRI | CONTROL_PCC;
|
||||
this.Microcode[4] = CONTROL_OUT_AH | CONTROL_RI;
|
||||
}
|
||||
}
|
||||
is_STAH_i = new IS_STAH_imm;
|
||||
Instructions.push(is_STAH_i);
|
||||
|
||||
class IS_STBL_imm extends Microcode_Instruction {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.Bytecode = 0x006;
|
||||
this.Mnemonic = "STBL";
|
||||
this.Microcode[2] = CONTROL_OUT_PC | CONTROL_RRI;
|
||||
this.Microcode[3] = CONTROL_OUT_RO | CONTROL_RRI | CONTROL_PCC;
|
||||
this.Microcode[4] = CONTROL_OUT_BL | CONTROL_RI;
|
||||
}
|
||||
}
|
||||
is_STBL_i = new IS_STBL_imm;
|
||||
Instructions.push(is_STBL_i);
|
||||
|
||||
class IS_STBH_imm extends Microcode_Instruction {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.Bytecode = 0x007;
|
||||
this.Mnemonic = "STBH";
|
||||
this.Microcode[2] = CONTROL_OUT_PC | CONTROL_RRI;
|
||||
this.Microcode[3] = CONTROL_OUT_RO | CONTROL_RRI | CONTROL_PCC;
|
||||
this.Microcode[4] = CONTROL_OUT_BH | CONTROL_RI;
|
||||
}
|
||||
}
|
||||
is_STBH_i = new IS_STBH_imm;
|
||||
Instructions.push(is_STBH_i);
|
||||
|
||||
class IS_STCL_imm extends Microcode_Instruction {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.Bytecode = 0x008;
|
||||
this.Mnemonic = "STCL";
|
||||
this.Microcode[2] = CONTROL_OUT_PC | CONTROL_RRI;
|
||||
this.Microcode[3] = CONTROL_OUT_RO | CONTROL_RRI | CONTROL_PCC;
|
||||
this.Microcode[4] = CONTROL_OUT_CL | CONTROL_RI;
|
||||
}
|
||||
}
|
||||
is_STCL_i = new IS_STCL_imm;
|
||||
Instructions.push(is_STCL_i);
|
||||
|
||||
class IS_STCH_imm extends Microcode_Instruction {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.Bytecode = 0x009;
|
||||
this.Mnemonic = "STCH";
|
||||
this.Microcode[2] = CONTROL_OUT_PC | CONTROL_RRI;
|
||||
this.Microcode[3] = CONTROL_OUT_RO | CONTROL_RRI | CONTROL_PCC;
|
||||
this.Microcode[4] = CONTROL_OUT_CH | CONTROL_RI;
|
||||
}
|
||||
}
|
||||
is_STCH_i = new IS_STCH_imm;
|
||||
Instructions.push(is_STCH_i);
|
||||
|
||||
class IS_STDL_imm extends Microcode_Instruction {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.Bytecode = 0x00A;
|
||||
this.Mnemonic = "STDL";
|
||||
this.Microcode[2] = CONTROL_OUT_PC | CONTROL_RRI;
|
||||
this.Microcode[3] = CONTROL_OUT_RO | CONTROL_RRI | CONTROL_PCC;
|
||||
this.Microcode[4] = CONTROL_OUT_DL | CONTROL_RI;
|
||||
}
|
||||
}
|
||||
is_STDL_i = new IS_STDL_imm;
|
||||
Instructions.push(is_STDL_i);
|
||||
|
||||
class IS_STDH_imm extends Microcode_Instruction {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.Bytecode = 0x00B;
|
||||
this.Mnemonic = "STDH";
|
||||
this.Microcode[2] = CONTROL_OUT_PC | CONTROL_RRI;
|
||||
this.Microcode[3] = CONTROL_OUT_RO | CONTROL_RRI | CONTROL_PCC;
|
||||
this.Microcode[4] = CONTROL_OUT_DH | CONTROL_RI;
|
||||
}
|
||||
}
|
||||
is_STDH_i = new IS_STDH_imm;
|
||||
Instructions.push(is_STDH_i);
|
||||
|
||||
|
||||
// This is a simple ADD command which will ADD GPA and GPB putting the sum in GPA
|
||||
class IS_ADD extends Microcode_Instruction {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.Bytecode = 0x100;
|
||||
this.Mnemonic = "ADD";
|
||||
this.Microcode[2] = CONTROL_ALU_ADD;
|
||||
this.Microcode[3] = CONTROL_RAIL | CONTROL_OUT_AO;
|
||||
}
|
||||
@ -128,11 +261,44 @@ class IS_ADD extends Microcode_Instruction {
|
||||
is_ADD = new IS_ADD;
|
||||
Instructions.push(is_ADD);
|
||||
|
||||
class IS_JMP_imm extends Microcode_Instruction {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.Bytecode = 0x200;
|
||||
this.Mnemonic = "JMP";
|
||||
this.Microcode[2] = CONTROL_OUT_PC | CONTROL_RRI;
|
||||
this.Microcode[3] = CONTROL_OUT_RO | CONTROL_PCI;
|
||||
}
|
||||
}
|
||||
is_JMP_i = new IS_JMP_imm;
|
||||
Instructions.push(is_JMP_i);
|
||||
|
||||
class IS_BCC_imm extends Microcode_Instruction {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.UsesCarry = true;
|
||||
this.Bytecode = 0x201;
|
||||
this.Mnemonic = "BCC";
|
||||
this.MicrocodeCarry = new Array(16);
|
||||
for (let a = 0; a < 16; a++) {
|
||||
this.MicrocodeCarry[a] = this.Microcode[a];
|
||||
}
|
||||
this.Microcode[2] = CONTROL_OUT_PC | CONTROL_RRI;
|
||||
this.Microcode[3] = CONTROL_OUT_RO | CONTROL_PCI;
|
||||
this.MicrocodeCarry[2] = CONTROL_PCC; // Step over the immediate value
|
||||
}
|
||||
}
|
||||
|
||||
is_BCC_i = new IS_BCC_imm;
|
||||
Instructions.push(is_BCC_i);
|
||||
|
||||
class IS_NOP extends Microcode_Instruction {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.Bytecode = 0x3ff;
|
||||
this.Mnemonic = "NOP";
|
||||
}
|
||||
}
|
||||
is_NOP = new IS_NOP;
|
||||
Instructions.push(is_NOP);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user