/// <summary> /// Creates a new instance of the CPU with the given instruction memory. /// </summary> /// <param name="iMem">instruction memory, mapping memory location to instruction</param> public Cpu(Dictionary<ushort, uint> iMem) { this.instructionMemory = new uint[0x400]; for (ushort i = 0; i < 0x400; i++) { if (iMem.ContainsKey(i)) instructionMemory[i] = iMem[i]; } this.state = new CpuState(); this.SleepTickInterval = DefaultSleepTickInterval; }
private void test(CpuState state, byte aVal, byte bVal) { state.ZeroFlag = (aVal & bVal) == 0; //odd parity for C flag var xor = aVal ^ bVal; int count = 0; int mask = 0x80; while (mask != 0) { if ((mask & xor) != 0) count++; mask = mask >> 1; } state.CarryFlag = (count % 2) == 0; }
private bool flowControlConditional(CpuState state, FlowControlCondition cond) { switch (cond) { case FlowControlCondition.Z: return state.ZeroFlag; case FlowControlCondition.NZ: return !state.ZeroFlag; case FlowControlCondition.C: return state.CarryFlag; case FlowControlCondition.NC: return !state.CarryFlag; default: throw new NotSupportedException("Invalid flag."); } }
private void doShifter(CpuState state, byte reg, byte typeBits) { bool oldCarry; ShifterOps type = (ShifterOps)typeBits; byte val = state.RegisterFile[reg]; switch (type) { case ShifterOps.RL: state.CarryFlag = (0x80 & val) != 0; val = (byte)(val << 1); if (state.CarryFlag) val++; break; case ShifterOps.RR: state.CarryFlag = (0x01 & val) == 1; val = (byte)(val >> 1); val |= (byte)(state.CarryFlag ? 0x80 : 0x0); break; case ShifterOps.SL0: state.CarryFlag = (0x80 & val) != 0; val = (byte)(val << 1); break; case ShifterOps.SL1: state.CarryFlag = (0x80 & val) != 0; val = (byte)(val << 1); val |= 0x01; break; case ShifterOps.SLA: oldCarry = state.CarryFlag; state.CarryFlag = (0x80 & val) != 0; val = (byte)(val << 1); val |= (byte)(oldCarry ? 0x01 : 0x00); break; case ShifterOps.SLX: bool oldBottomBit = (0x01 & val) == 1; state.CarryFlag = (0x80 & val) != 0; val = (byte)(val << 1); val |= (byte)(oldBottomBit ? 0x01 : 0x00); break; case ShifterOps.SR0: state.CarryFlag = (0x01 & val) != 0; val = (byte)(val >> 1); break; case ShifterOps.SR1: state.CarryFlag = (0x01 & val) != 0; val = (byte)(val >> 1); val |= 0x80; break; case ShifterOps.SRA: oldCarry = state.CarryFlag; state.CarryFlag = (0x01 & val) != 0; val = (byte)(val >> 1); val |= (byte)(oldCarry ? 0x80 : 0x00); break; case ShifterOps.SRX: bool oldTopBit = (0x80 & val) == 1; state.CarryFlag = (0x01 & val) != 0; val = (byte)(val >> 1); val |= (byte)(oldTopBit ? 0x80 : 0x00); break; default: throw new NotSupportedException("Unsupported shifter operation."); } state.RegisterFile[reg] = val; }
private byte doLogic(CpuState state, int value) { state.ZeroFlag = value == 0; state.CarryFlag = false; return (byte)value; }
private void compare(CpuState state, byte aVal, byte bVal) { state.ZeroFlag = aVal == bVal; state.CarryFlag = aVal < bVal; }
private ushort call(CpuState state, ushort addr) { state.CallStack.Push(++state.ProgramCounter); return addr; }
private static byte sub(CpuState state, byte a, int b, bool cy) { int ret = a - b - (cy && state.CarryFlag ? 1 : 0); state.CarryFlag = ret < 0; state.ZeroFlag = (ret == 0) || (ret == -256); return (byte)(0xFF & ret); }
private static byte add(CpuState state, byte a, int b, bool cy) { int ret = a + b + (cy && state.CarryFlag ? 1 : 0); state.CarryFlag = ret > 255; state.ZeroFlag = (ret == 0) || ((ret + (state.CarryFlag ? 1 : 0)) == 256); return (byte)(0xFF & ret); }
/// <summary> /// Executes the operation on the given CPU state with the given arguments. /// </summary> /// <param name="state"></param> /// <param name="args"></param> public abstract void Do(CpuState state, ushort args);
/// <summary> /// Stops and resets the processor. /// </summary> /// <returns>The the instructions per second executed.</returns> public double Reset() { this.isRunning = false; runThread.Join(); this.state = new CpuState(); foreach (var dev in devices) { hookupDevice(dev); } return tickCount / (endTime.Subtract(startTime).TotalSeconds); }