/// <summary> /// Constructor. /// </summary> public Processor() { // Initialize the RAM with 64K ram = new Memory(256 * 256); // Initialize the internal Registers instruction = new InstructionRegister(); programCounter = new Register16(); // Initialize the ALU Registers a = new Register(); b = new Register(); c = new Register(); // Initialize the 8-bit General Purpose Registers d = new Register(); e = new Register(); f = new Register(); g = new Register(); h = new Register(); xl = new Register(); xh = new Register(); // Initialize the 16-bit General Purpose Registers m = new Register16(); j = new Register16(); sp = new Register16(); bp = new Register16(); y = new Register16(); z = new Register16(); // Initialize the Flags Register flags = new Register(); flagsSaved = new Register(); // Initialize the breakpoint Array breakpointAddresses = new List <string>(); // Initialize the individual Carry Flags carryADD = false; carrySUB = false; carrySHL = false; carrySHR = false; }
/// <summary> /// Executes the next Instruction and increments the Program Counter. /// </summary> private CPUExecution ExecuteNextInstruction(out string OutputPortC, out string OutputPortD) { bool incrementProgramCounter = true; OutputPortC = string.Empty; OutputPortD = string.Empty; // Check if we are at a breakpoint if (!breakpointAddresses.Contains(programCounter.GetString())) { // Fetch the current instruction from the RAM instruction.SetBits(ram.ReadValue(programCounter.GetInt())); switch (instruction.GetOpCode()) { case OpCode.HLT: { // We have finished the end of the program execution return(CPUExecution.FINISHED); } case OpCode.INT: { // We have to raise an software based interrupt... return(CPUExecution.INTERRUPT); } case OpCode.SET_A: { a = new Register(); // Extract the lower Nibble and store it in A a.SetBit(3, Helper.IsBitSet(instruction.GetByte(), 3)); a.SetBit(2, Helper.IsBitSet(instruction.GetByte(), 2)); a.SetBit(1, Helper.IsBitSet(instruction.GetByte(), 1)); a.SetBit(0, Helper.IsBitSet(instruction.GetByte(), 0)); break; } case OpCode.SET_B: { b = new Register(); // Extract the lower Nibble and store it in B b.SetBit(3, Helper.IsBitSet(instruction.GetByte(), 3)); b.SetBit(2, Helper.IsBitSet(instruction.GetByte(), 2)); b.SetBit(1, Helper.IsBitSet(instruction.GetByte(), 1)); b.SetBit(0, Helper.IsBitSet(instruction.GetByte(), 0)); break; } case OpCode.MOV8: { c = new Register(); // Upper Nibble c.SetBit(7, b.Value[3]); c.SetBit(6, b.Value[2]); c.SetBit(5, b.Value[1]); c.SetBit(4, b.Value[0]); // Lower Nibble c.SetBit(3, a.Value[3]); c.SetBit(2, a.Value[2]); c.SetBit(1, a.Value[1]); c.SetBit(0, a.Value[0]); // Calculate Flags SetFlags(); break; } case OpCode.AND: { c = new Register(); // Upper Nibble c.SetBit(7, a.Value[7] & b.Value[7]); c.SetBit(6, a.Value[6] & b.Value[6]); c.SetBit(5, a.Value[5] & b.Value[5]); c.SetBit(4, a.Value[4] & b.Value[4]); // Lower Nibble c.SetBit(3, a.Value[3] & b.Value[3]); c.SetBit(2, a.Value[2] & b.Value[2]); c.SetBit(1, a.Value[1] & b.Value[1]); c.SetBit(0, a.Value[0] & b.Value[0]); // Calculate Flags SetFlags(); break; } case OpCode.OR: { c = new Register(); // Upper Nibble c.SetBit(7, a.Value[7] | b.Value[7]); c.SetBit(6, a.Value[6] | b.Value[6]); c.SetBit(5, a.Value[5] | b.Value[5]); c.SetBit(4, a.Value[4] | b.Value[4]); // Lower Nibble c.SetBit(3, a.Value[3] | b.Value[3]); c.SetBit(2, a.Value[2] | b.Value[2]); c.SetBit(1, a.Value[1] | b.Value[1]); c.SetBit(0, a.Value[0] | b.Value[0]); // Calculate Flags SetFlags(); break; } case OpCode.XOR: { c = new Register(); // Upper Nibble c.SetBit(7, a.Value[7] ^ b.Value[7]); c.SetBit(6, a.Value[6] ^ b.Value[6]); c.SetBit(5, a.Value[5] ^ b.Value[5]); c.SetBit(4, a.Value[4] ^ b.Value[4]); // Lower Nibble c.SetBit(3, a.Value[3] ^ b.Value[3]); c.SetBit(2, a.Value[2] ^ b.Value[2]); c.SetBit(1, a.Value[1] ^ b.Value[1]); c.SetBit(0, a.Value[0] ^ b.Value[0]); // Calculate Flags SetFlags(); break; } case OpCode.SHL: { c = new Register(); c.SetBit(7, a.Value[6]); c.SetBit(6, a.Value[5]); c.SetBit(5, a.Value[4]); c.SetBit(4, a.Value[3]); c.SetBit(3, a.Value[2]); c.SetBit(2, a.Value[1]); c.SetBit(1, a.Value[0]); c.SetBit(0, false); carrySHL = a.Value.Get(7); // Calculate Flags SetFlags(); break; } case OpCode.SHR: { c = new Register(); c.SetBit(7, false); c.SetBit(6, a.Value[7]); c.SetBit(5, a.Value[6]); c.SetBit(4, a.Value[5]); c.SetBit(3, a.Value[4]); c.SetBit(2, a.Value[3]); c.SetBit(1, a.Value[2]); c.SetBit(0, a.Value[1]); carrySHR = a.Value.Get(0); // Calculate Flags SetFlags(); break; } case OpCode.ADD: { c = new Register(); int result = a.GetInt() + b.GetInt(); byte byteResult = (byte)result; c.SetBit(7, Helper.IsBitSet(byteResult, 7)); c.SetBit(6, Helper.IsBitSet(byteResult, 6)); c.SetBit(5, Helper.IsBitSet(byteResult, 5)); c.SetBit(4, Helper.IsBitSet(byteResult, 4)); c.SetBit(3, Helper.IsBitSet(byteResult, 3)); c.SetBit(2, Helper.IsBitSet(byteResult, 2)); c.SetBit(1, Helper.IsBitSet(byteResult, 1)); c.SetBit(0, Helper.IsBitSet(byteResult, 0)); if (result > 256) { carryADD = true; } // Calculate Flags SetFlags(); break; } case OpCode.SUB: { c = new Register(); int result = a.GetInt() - b.GetInt(); byte byteResult = (byte)result; c.SetBit(7, Helper.IsBitSet(byteResult, 7)); c.SetBit(6, Helper.IsBitSet(byteResult, 6)); c.SetBit(5, Helper.IsBitSet(byteResult, 5)); c.SetBit(4, Helper.IsBitSet(byteResult, 4)); c.SetBit(3, Helper.IsBitSet(byteResult, 3)); c.SetBit(2, Helper.IsBitSet(byteResult, 2)); c.SetBit(1, Helper.IsBitSet(byteResult, 1)); c.SetBit(0, Helper.IsBitSet(byteResult, 0)); if (result < 0) { carrySUB = true; } // Calculate Flags SetFlags(); break; } case OpCode.NOT: { c = new Register(); c.SetBit(7, !a.Value[7]); c.SetBit(6, !a.Value[6]); c.SetBit(5, !a.Value[5]); c.SetBit(4, !a.Value[4]); c.SetBit(3, !a.Value[3]); c.SetBit(2, !a.Value[2]); c.SetBit(1, !a.Value[1]); c.SetBit(0, !a.Value[0]); // Calculate Flags SetFlags(); break; } case OpCode.MOV_ALU_IN_A_D: { a = d; break; } case OpCode.MOV_ALU_IN_A_E: { a = e; break; } case OpCode.MOV_ALU_IN_A_F: { a = f; break; } case OpCode.MOV_ALU_IN_A_G: { a = g; break; } case OpCode.MOV_ALU_IN_A_H: { a = h; break; } case OpCode.MOV_ALU_IN_A_XL: { a = xl; break; } case OpCode.MOV_ALU_IN_A_XH: { a = xh; break; } case OpCode.MOV_ALU_IN_B_D: { b = d; break; } case OpCode.MOV_ALU_IN_B_E: { b = e; break; } case OpCode.MOV_ALU_IN_B_F: { b = f; break; } case OpCode.MOV_ALU_IN_B_G: { b = g; break; } case OpCode.MOV_ALU_IN_B_H: { b = h; break; } case OpCode.MOV_ALU_IN_B_XL: { b = xl; break; } case OpCode.MOV_ALU_IN_B_XH: { b = xh; break; } case OpCode.MOV_ALU_OUT_D: { d = c; break; } case OpCode.MOV_ALU_OUT_E: { e = c; break; } case OpCode.MOV_ALU_OUT_F: { f = c; break; } case OpCode.MOV_ALU_OUT_G: { g = c; break; } case OpCode.MOV_ALU_OUT_H: { h = c; break; } case OpCode.MOV_ALU_OUT_XL: { xl = c; break; } case OpCode.MOV_ALU_OUT_XH: { xh = c; break; } case OpCode.MOV_D_TO_E: { e = d; break; } case OpCode.MOV_D_TO_F: { f = d; break; } case OpCode.MOV_D_TO_G: { g = d; break; } case OpCode.MOV_D_TO_H: { h = d; break; } case OpCode.MOV_D_TO_XL: { xl = d; break; } case OpCode.MOV_D_TO_XH: { xh = d; break; } case OpCode.MOV_E_TO_D: { d = e; break; } case OpCode.MOV_E_TO_F: { f = e; break; } case OpCode.MOV_E_TO_G: { g = e; break; } case OpCode.MOV_E_TO_H: { h = e; break; } case OpCode.MOV_E_TO_XL: { xl = e; break; } case OpCode.MOV_E_TO_XH: { xh = e; break; } case OpCode.MOV_F_TO_D: { d = f; break; } case OpCode.MOV_F_TO_E: { e = f; break; } case OpCode.MOV_F_TO_G: { g = f; break; } case OpCode.MOV_F_TO_H: { h = f; break; } case OpCode.MOV_F_TO_XL: { xl = f; break; } case OpCode.MOV_G_TO_D: { d = g; break; } case OpCode.MOV_G_TO_E: { e = g; break; } case OpCode.MOV_G_TO_F: { f = g; break; } case OpCode.MOV_G_TO_H: { h = g; break; } case OpCode.MOV_G_TO_XL: { xl = g; break; } case OpCode.MOV_G_TO_XH: { xh = g; break; } case OpCode.MOV_H_TO_D: { d = h; break; } case OpCode.MOV_H_TO_E: { e = h; break; } case OpCode.MOV_H_TO_F: { f = h; break; } case OpCode.MOV_H_TO_G: { g = h; break; } case OpCode.MOV_H_TO_XL: { xl = h; break; } case OpCode.MOV_H_TO_XH: { xh = h; break; } case OpCode.MOV_XL_TO_D: { d = xl; break; } case OpCode.MOV_XL_TO_E: { e = xl; break; } case OpCode.MOV_XL_TO_F: { f = xl; break; } case OpCode.MOV_XL_TO_G: { g = xl; break; } case OpCode.MOV_XL_TO_H: { h = xl; break; } case OpCode.MOV_XL_TO_XH: { xh = xl; break; } case OpCode.MOV_XH_TO_D: { d = xh; break; } case OpCode.MOV_XH_TO_E: { e = xh; break; } case OpCode.MOV_XH_TO_F: { f = xh; break; } case OpCode.MOV_XH_TO_G: { g = xh; break; } case OpCode.MOV_XH_TO_H: { h = xh; break; } case OpCode.MOV_XH_TO_XL: { xl = xh; break; } case OpCode.MOV_M_TO_X: { X = m; break; } case OpCode.MOV_M_TO_J: { j = m; break; } case OpCode.MOV_M_TO_SP: { sp = m; break; } case OpCode.MOV_M_TO_BP: { bp = m; break; } case OpCode.MOV_M_TO_Y: { y = m; break; } case OpCode.MOV_M_TO_Z: { z = m; break; } case OpCode.MOV_M_TO_PC: { programCounter = m; break; } case OpCode.MOV_X_TO_M: { m = X; break; } case OpCode.MOV_X_TO_J: { j = X; break; } case OpCode.MOV_X_TO_SP: { sp = X; break; } case OpCode.MOV_X_TO_BP: { bp = X; break; } case OpCode.MOV_X_TO_Y: { y = X; break; } case OpCode.MOV_X_TO_Z: { z = X; break; } case OpCode.MOV_J_TO_M: { m = j; break; } case OpCode.MOV_J_TO_X: { X = j; break; } case OpCode.MOV_J_TO_SP: { sp = j; break; } case OpCode.MOV_J_TO_BP: { bp = j; break; } case OpCode.MOV_J_TO_Y: { y = j; break; } case OpCode.MOV_J_TO_Z: { z = j; break; } case OpCode.MOV_SP_TO_M: { m = sp; break; } case OpCode.MOV_SP_TO_X: { X = sp; break; } case OpCode.MOV_SP_TO_J: { j = sp; break; } case OpCode.MOV_SP_TO_BP: { bp = sp; break; } case OpCode.MOV_SP_TO_Y: { y = sp; break; } case OpCode.MOV_SP_TO_Z: { z = sp; break; } case OpCode.MOV_PC_TO_X: { X = programCounter; break; } case OpCode.MOV_BP_TO_M: { m = bp; break; } case OpCode.MOV_BP_TO_X: { X = bp; break; } case OpCode.MOV_BP_TO_J: { j = bp; break; } case OpCode.MOV_BP_TO_SP: { sp = bp; break; } case OpCode.MOV_BP_TO_Y: { y = bp; break; } case OpCode.MOV_BP_TO_Z: { z = bp; break; } case OpCode.MOV_Y_TO_M: { m = y; break; } case OpCode.MOV_Y_TO_X: { X = y; break; } case OpCode.MOV_Y_TO_J: { j = y; break; } case OpCode.MOV_Y_TO_SP: { sp = y; break; } case OpCode.MOV_Y_TO_BP: { bp = y; break; } case OpCode.MOV_Y_TO_Z: { z = y; break; } case OpCode.MOV_Z_TO_M: { m = z; break; } case OpCode.MOV_Z_TO_X: { X = z; break; } case OpCode.MOV_Z_TO_J: { j = z; break; } case OpCode.MOV_Z_TO_SP: { sp = z; break; } case OpCode.MOV_Z_TO_BP: { bp = z; break; } case OpCode.MOV_Z_TO_Y: { y = z; break; } case OpCode.MOV_ALU_C_TO_A: { a = c; break; } case OpCode.MOV_ALU_C_TO_B: { b = c; break; } case OpCode.LOAD_D: { d.SetBits(ram.ReadValue(M.GetInt())); break; } case OpCode.LOAD_E: { e.SetBits(ram.ReadValue(M.GetInt())); break; } case OpCode.LOAD_F: { f.SetBits(ram.ReadValue(M.GetInt())); break; } case OpCode.LOAD_G: { g.SetBits(ram.ReadValue(M.GetInt())); break; } case OpCode.LOAD_H: { h.SetBits(ram.ReadValue(M.GetInt())); break; } case OpCode.LOAD_XL: { xl.SetBits(ram.ReadValue(M.GetInt())); break; } case OpCode.LOAD_XH: { xh.SetBits(ram.ReadValue(M.GetInt())); break; } case OpCode.STORE_D: { ram.WriteValue(M.GetInt(), d.GetByte()); break; } case OpCode.STORE_E: { ram.WriteValue(M.GetInt(), e.GetByte()); break; } case OpCode.STORE_F: { ram.WriteValue(M.GetInt(), f.GetByte()); break; } case OpCode.STORE_G: { ram.WriteValue(M.GetInt(), g.GetByte()); break; } case OpCode.STORE_H: { ram.WriteValue(M.GetInt(), h.GetByte()); break; } case OpCode.STORE_XL: { ram.WriteValue(M.GetInt(), xl.GetByte()); break; } case OpCode.STORE_XH: { ram.WriteValue(M.GetInt(), xh.GetByte()); break; } case OpCode.SAVE_FLAGS: { flagsSaved = flags; break; } case OpCode.RESTORE_FLAGS: { flags = flagsSaved; break; } case OpCode.JMP: { programCounter = j; incrementProgramCounter = false; break; } case OpCode.JZ: { // The Jump is only performed if the Zero Flag is set to 1 if (flags.Value.Get(1)) { programCounter = j; incrementProgramCounter = false; } else { incrementProgramCounter = true; } break; } case OpCode.JNZ: { // The Jump is only performed if the Zero Flag is set to 0 if (!flags.Value.Get(1)) { programCounter = j; incrementProgramCounter = false; } else { incrementProgramCounter = true; } break; } case OpCode.JNS: { // The Jump is only performed if the Sign Flag is set to 0 if (!flags.Value.Get(0)) { programCounter = j; incrementProgramCounter = false; } else { incrementProgramCounter = true; } break; } case OpCode.ADDER_16BIT: { int result = X.GetInt() + J.GetInt(); Register16 temp = new Register16(); temp.SetBits(result); X = temp; break; } case OpCode.OUT_C: { OutputPortC = xl.GetString(); break; } case OpCode.OUT_D: { OutputPortD = xl.GetString(); break; } case OpCode.IN_A: { programCounter.Increment(); return(CPUExecution.IN_A); } case OpCode.IN_B: { programCounter.Increment(); return(CPUExecution.IN_B); } } } else { // We hit a breakpoint! return(CPUExecution.BREAKPOINT_HIT); } // Increment the Program Counter, if necessary if (incrementProgramCounter) { programCounter.Increment(); } // There are more CPU instructions available for execution... return(CPUExecution.MORE_INSTRUCTIONS_AVAILABLE); }