8SA1Sim/js/microcode_compiler.js

318 lines
12 KiB
JavaScript

/*
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
*/
/*
Free Instructions:
0x000
0x001
0x003
0x005
0x007
0x009
*/
let Instructions = new Array();
const InstructionTypes = {
SingleWord: {
Name: `Singe Word`,
toString() {
return this.Name;
}
},
RTS16: {
Name: `JSR 16 Return`,
toString() {
return this.Name;
}
},
RTS24: {
Name: `JSR 24 Return`,
toString() {
return this.Name;
}
},
Immediate8: {
Name: `8 bit Immediate`,
toString() {
return this.Name;
}
},
Immediate16: {
Name: `16 bit Immediate`,
toString() {
return this.Name;
}
},
Immediate24: {
Name: `24 bit Immediate`,
toString() {
return this.Name;
}
},
Indirect16: {
Name: `16 bit Indirect`,
toString() {
return this.Name;
}
},
Indirect24: {
Name: `24 bit Indirect`,
toString() {
return this.Name;
}
},
Absolute16: {
Name: `16 bit Absolute`,
toString() {
return this.Name;
}
},
Absolute24: {
Name: `24 bit Absolute`,
toString() {
return this.Name;
}
},
Register: {
Name: `Register`,
toString() {
return this.Name;
}
},
RegisterImmediate: {
Name: `Register Immediate`,
toString() {
return this.Name;
}
},
RegisterAbsolute: {
Name: `Register Absolute`,
toString() {
return this.Name;
}
},
RegisterIndirect: {
Name: `Register Indirect`,
toString() {
return this.Name;
}
}
};
function IsRegister(reg) {
reg = reg.toLowerCase().replace("%","").replace("[","").replace("]","");
switch (reg) {
case "a":
case "b":
case "c":
case "d":
case "pc":
case "sp":
case "ab":
case "ac":
case "ad":
case "ba":
case "bc":
case "bd":
case "ca":
case "cb":
case "cd":
case "da":
case "db":
case "dc":
return true;
break;
}
return false;
}
function ValidateInstruction(line) {
let linearr = line.split(" ");
let label = false;
let type = false;
if (linearr[0] !== "") label = linearr[0];
if (linearr.length > 2) {
let operands = linearr[2].split(",");
if (operands.length > 0) {
if (operands.length === 1) {
if (operands[0].substring(0,1) === '$') type = InstructionTypes.Immediate;
if (operands[0].substring(0,1) === '[') type = InstructionTypes.Indirect;
if (IsRegister(operands[0])) type = InstructionTypes.Register;
if (type === false) type = InstructionTypes.Absolute;
} else {
// more then one operand
}
}
}
console.log(linearr[1]);
let foundinstruction = FindInstructon({Instruction: linearr[1]}, type);
return foundinstruction;
}
function FindInstructon(ins,type = false) {
for (let a = 0; a < Instructions.length; a++) {
if (Instructions[a].Mnemonic.toLowerCase() === ins.Instruction.toLowerCase()) {
if (type) {
if (Instructions[a].Type === type) return Instructions[a];
} else {
return Instructions[a];
}
}
}
return false;
}
function GenerateMicrocode(mcarray,cpu) {
for (let a = 0; a < mcarray.length; a++) {
for (let c = 0; c < 4; c++) {
let offset = 0;
if (c === 1) offset = 0b1000000000000000;
if (c === 2) offset = 0b0100000000000000;
if (c === 3) offset = 0b1100000000000000;
let bytecode = mcarray[a].Bytecode & 0b1111111111;
//if (c === 0 && (bytecode === 0x311)) console.log("Doing Normals");
//if (c === 1 && (bytecode === 0x311)) console.log("Doing Zero's");
//if (c === 2 && (bytecode === 0x311)) console.log("Doing Carry's");
//if (c === 3 && (bytecode === 0x311)) console.log("Doing ZC's");
for (let b = 0; b < 16; b++) {
let mca = 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];
if (mcarray[a].UsesCarry && mcarray[a].UsesZero && c === 3) mcv = mcarray[a].MicrocodeZC[b];
if (mcarray[a].UsesCarry && !mcarray[a].UsesZero && c === 3) mcv = mcarray[a].MicrocodeCarry[b];
cpu.MCRAM[offset + mca] = mcv;
mca = offset + mca;
//if (bytecode === 0x311) console.log(`[${bytecode.toString(16)}] ${mca.toString(16)}: ${mcv.toString(2)}`);
}
}
}
}
class Microcode_Instruction {
constructor() {
this.Bytecode = 0x000; // MAX IS 0x3ff
this.Mnemonic = "NOP";
this.LongName = "";
this.Aliases = new Array();
this.Microcode = new Array(16);
this.MicrocodeCarry = new Array(16);
this.MicrocodeZero = new Array(16);
this.MicrocodeZC = new Array(16);
this.Operands = new Array();
this.UsesCarry = false;
this.UsesZero = false;
this.Words = 1;
this.Cycles = 2;
this.CycleCount = 2;
this.CycleCountZero = 2;
this.CycleCountCarry = 2;
this.CycleCountZC = 2;
this.Type = InstructionTypes.SingleWord;
this.Microcode[0] = CONTROL_OUT_PC | CONTROL_RRI;
this.Microcode[1] = CONTROL_OUT_RO | CONTROL_IRI | CONTROL_PCC;
this.MicrocodeCarry[0] = CONTROL_OUT_PC | CONTROL_RRI;
this.MicrocodeCarry[1] = CONTROL_OUT_RO | CONTROL_IRI | CONTROL_PCC;
this.MicrocodeZero[0] = CONTROL_OUT_PC | CONTROL_RRI;
this.MicrocodeZero[1] = CONTROL_OUT_RO | CONTROL_IRI | CONTROL_PCC;
this.MicrocodeZC[0] = CONTROL_OUT_PC | CONTROL_RRI;
this.MicrocodeZC[1] = CONTROL_OUT_RO | CONTROL_IRI | CONTROL_PCC;
for (let a = 2; a < 16; a++) {
this.Microcode[a] = CONTROL_MCL0;
this.MicrocodeCarry[a] = CONTROL_MCL0;
this.MicrocodeZero[a] = CONTROL_MCL0;
this.MicrocodeZC[a] = CONTROL_MCL0;
}
}
CloneInstruction(fromtype,totype) {
// Simple function to clone instruction sets around
if ((typeof totype === 'string' || totype instanceof String)) {
if (totype.toLowerCase() === "all") {
for (let a = 0; a < fromtype.length; a++) {
if (fromtype !== this.Microcode) this.Microcode[a] = parseInt(fromtype[a]);
if (fromtype !== this.MicrocodeZero) this.MicrocodeZero[a] = parseInt(fromtype[a]);
if (fromtype !== this.MicrocodeCarry) this.MicrocodeCarry[a] = parseInt(fromtype[a]);
if (fromtype !== this.MicrocodeZC) this.MicrocodeZC[a] = parseInt(fromtype[a]);
}
//console.log("Cloned ALL!");
}
} else {
if (fromtype === totype) return false;
if (fromtype.length !== totype.length) return false;
for (let a = 0; a < fromtype.length; a++) {
totype[a] = parseInt(fromtype[a]);
}
}
}
AddInstruction(ins,type="") {
if (type.toLowerCase() === "") {
if (this.CycleCount > 15) return; // Cant find any more instructions!
this.Microcode[this.CycleCount] = ins;
this.CycleCount++;
this.Cycles = this.CycleCount;
}
if (type.toLowerCase() === "zero") {
if (this.CycleCountZero > 15) return; // Cant find any more instructions!
this.MicrocodeZero[this.CycleCountZero] = ins;
this.CycleCountZero++;
}
if (type.toLowerCase() === "carry") {
if (this.CycleCountCarry > 15) return; // Cant find any more instructions!
this.MicrocodeCarry[this.CycleCountCarry] = ins;
this.CycleCountCarry++;
}
if (type.toLowerCase() === "zc") {
if (this.CycleCountZC > 15) return; // Cant find any more instructions!
this.MicrocodeZC[this.CycleCountZC] = ins;
this.CycleCountZC++;
}
}
}