public void EXShouldErrorIfNotGivenHL_IX_IY(Reg16 operand2) { var machine = new Machine(); var exception = Record.Exception(() => machine.EX(valueAt(Reg16.SP), operand2)); Assert.IsType(typeof(System.InvalidOperationException), exception); }
public static OpCode FromName1W(string op, Reg16 op1) { switch (op) { case "push": return OpCode.NewBytes(Util.GetBytes2(0x66, (byte)(0x50 + op1))); case "pop": return OpCode.NewBytes(Util.GetBytes2(0x66, (byte)(0x58 + op1))); case "inc": return OpCode.NewBytes(Util.GetBytes2(0x66, (byte)(0x40 + op1))); case "dec": return OpCode.NewBytes(Util.GetBytes2(0x66, (byte)(0x48 + op1))); case "not": return OpCode.NewBytes(Util.GetBytes3(0x66, 0xf7, (byte)(0xd0 + op1))); case "neg": return OpCode.NewBytes(Util.GetBytes3(0x66, 0xf7, (byte)(0xd8 + op1))); case "mul": return OpCode.NewBytes(Util.GetBytes3(0x66, 0xf7, (byte)(0xe0 + op1))); case "imul": return OpCode.NewBytes(Util.GetBytes3(0x66, 0xf7, (byte)(0xe8 + op1))); case "div": return OpCode.NewBytes(Util.GetBytes3(0x66, 0xf7, (byte)(0xf0 + op1))); case "idiv": return OpCode.NewBytes(Util.GetBytes3(0x66, 0xf7, (byte)(0xf8 + op1))); default: throw new Exception("invalid operator: " + op); } }
public void EXShouldErrorIfNotGivenValueAtSP(Reg16 operand1) { var machine = new Machine(); var exception = Record.Exception(() => machine.EX(valueAt(operand1), Reg16.HL)); Assert.IsType(typeof(System.InvalidOperationException), exception); }
public static OpCode FromNameW(string op, Reg16 op1) { switch (op) { case "push": return new OpCode(new byte[] { 0x66, (byte)(0x50 + op1) }); case "pop": return new OpCode(new byte[] { 0x66, (byte)(0x58 + op1) }); case "inc": return new OpCode(new byte[] { 0x66, (byte)(0x40 + op1) }); case "dec": return new OpCode(new byte[] { 0x66, (byte)(0x48 + op1) }); case "not": return new OpCode(new byte[] { 0x66, 0xf7, (byte)(0xd0 + op1) }); case "neg": return new OpCode(new byte[] { 0x66, 0xf7, (byte)(0xd8 + op1) }); case "mul": return new OpCode(new byte[] { 0x66, 0xf7, (byte)(0xe0 + op1) }); case "imul": return new OpCode(new byte[] { 0x66, 0xf7, (byte)(0xe8 + op1) }); case "div": return new OpCode(new byte[] { 0x66, 0xf7, (byte)(0xf0 + op1) }); case "idiv": return new OpCode(new byte[] { 0x66, 0xf7, (byte)(0xf8 + op1) }); default: throw new Exception("invalid operator: " + op); } }
/// Usage: Exchanges the value pointed at by SP with one of the following registers: HL, IX or IY /// Flags: N/A public void EX(Value operand1, Reg16 operand2) { if (operand1.Register != Reg16.SP) { throw new InvalidOperationException("The first operand must be value at SP"); } if (operand2 != Reg16.HL && operand2 != Reg16.IX && operand2 != Reg16.IY) { throw new InvalidOperationException("The second operand must be value at HL, IX or IY"); } // What is the current memory address? var memoryAddress = this.Registers.Read(operand1.Register); // Read the current value at that address var higherOrderByte = this.Memory.Read((ushort)(memoryAddress + 1)); var lowerOrderByte = this.Memory.Read(memoryAddress); var valueForOperand1 = MakeWord(higherOrderByte, lowerOrderByte); // Read the current value from the register var valueForOperand2 = this.Registers.Read(operand2); var(h, l) = valueForOperand2.Split(); // Swap them this.Registers.Set(operand2, valueForOperand1); this.Memory.Set((ushort)(memoryAddress + 1), h); this.Memory.Set(memoryAddress, l); }
private void Sbb16Imm16(Reg16 reg) { registers.Set(reg, (ushort)(registers.Get(reg) - BinaryHelper.Read16Bit(_memory, _ip + 1) - (flagsRegister.HasFlag(Flags.Carry) ? 1 : 0))); _ip += 3; }
public static Value valueAt(Reg16 register) { return(new Value() { Register = register }); }
public override byte[] make() { PduBuffer = new byte[] { FuncNo, Reg16.hi(StartAddress), Reg16.lo(StartAddress), Reg16.hi(RegsQuant), Reg16.lo(RegsQuant) }; return(PduBuffer); }
private void XchgWithAx(Reg16 register) { var tmp = GetRegister(register); SetRegister(register, GetRegister(Reg16.ax)); SetRegister(Reg16.ax, tmp); _ip++; }
private void Cmp16Imm16(Reg16 reg) { var regValue = registers.Get(reg); var immValue = BinaryHelper.Read16Bit(_memory, _ip + 1); flagsRegister.SetFlagsFromInputAndResult(regValue - immValue, regValue, immValue); _ip += 3; }
public void ReadingA16BitRegisterCombinesItsHighAndLowOrderBytes(Reg16 register, Reg8 highRegister, Reg8 lowRegister) { var machine = new Machine(); machine.Registers.Set(highRegister, 0xAB); machine.Registers.Set(lowRegister, 0xCD); Assert.Equal(0xABCD, machine.Registers.Read(register)); }
private void Dec16(Reg16 reg) { var value = registers.Get(reg); value--; flagsRegister.SetFlagsFromInputAndResult(value, registers.Get(reg), 0, 2); registers.Set(reg, value); _ip++; }
public void SettingA16BitRegisterSetsTheHighValueIntoTheFirstRegister(Reg16 register, Reg8 highRegister) { ushort A_VALUE = 0xAABB; var machine = new Machine(); machine.Registers.Set(register, A_VALUE); Assert.Equal(0xAA, machine.Registers.Read(highRegister)); }
public void IsShouldBePossibleToWriteAndReadFromEvery16BitRegister(Reg16 register) { var ANY_VALUE = (ushort)0xABCD; var machine = new Machine(); machine.Registers.Set(register, ANY_VALUE); Assert.Equal(ANY_VALUE, machine.Registers.Read(register)); }
public void SettingA16BitRegisterSetsTheLowValueIntoTheSecondRegister(Reg16 register, Reg8 lowRegister) { ushort A_VALUE = 0xAABB; var machine = new Machine(); machine.Registers.Set(register, A_VALUE); Assert.Equal(0xBB, machine.Registers.Read(lowRegister)); }
public void EXXShouldSwapARegisterWithItsShadow(Reg16 register, Reg16Shadow shadow) { var machine = new Machine(); machine.Registers.Set(register, 0xAAAA); machine.Registers.Set(shadow, 0xBBBB); machine.EXX(); Assert.Equal(0xAAAA, machine.Registers.Read(shadow)); Assert.Equal(0xBBBB, machine.Registers.Read(register)); }
public void EXShouldErrorIfGivenAnyRegisterOtherThanAF(Reg16 register) { var machine = new Machine(); machine.Registers.Set(register, 0x1000); machine.Registers.Set(Reg16Shadow.AF, 0x2000); var exception = Record.Exception(() => machine.EX(register, Reg16Shadow.AF)); Assert.IsType(typeof(System.InvalidOperationException), exception); }
/// <summary> /// The value of the word found at the memory location pointed by SP is copied into reg16, then SP is increased by 2. /// No flags are affected (except for the case of popping into AF). /// </summary> /// <param name="register"></param> public void POP(Reg16 register) { var stackPointer = this.Registers.Read(Reg16.SP); var highOrderByte = this.Memory.Read((ushort)(stackPointer + 1)); var lowOrderByte = this.Memory.Read((ushort)(stackPointer)); var fullByte = (ushort)((ushort)(highOrderByte << 8) | lowOrderByte); this.Registers.Set(Reg16.SP, (ushort)(stackPointer + 2)); this.Registers.Set(register, fullByte); }
public void EXShouldErrorIfNotGivenDEandHL(Reg16 operand1, Reg16 operand2) { var machine = new Machine(); machine.Registers.Set(operand1, 0x1000); machine.Registers.Set(operand2, 0x2000); var exception = Record.Exception(() => machine.EX(operand1, operand2)); Assert.IsType(typeof(System.InvalidOperationException), exception); }
public void ShouldBeAbleToPOPaPUSHedValue(Reg16 register) { var machine = new Machine(); machine.Registers.Set(register, 0xAAAA); machine.PUSH(register); machine.Registers.Set(register, 0xBBBB); machine.POP(register); Assert.Equal(0xAAAA, machine.Registers.Read(register)); }
/// <summary> /// SP is decreased by two and the value of reg16 is copied to the memory location pointed by the new value of SP. /// It does not affect the flags. /// </summary> /// <param name="register"></param> public void PUSH(Reg16 register) { var value = this.Registers.Read(register); var(highOrderByte, lowOrderByte) = value.Split(); var stackPointer = this.Registers.Read(Reg16.SP); stackPointer = (ushort)(stackPointer - 2); this.Registers.Set(Reg16.SP, stackPointer); //The Z80 is little endian, so the lowest byte is stored in the lowest address this.Memory.Set((ushort)(stackPointer + 1), highOrderByte); this.Memory.Set((ushort)(stackPointer), lowOrderByte); }
public static OpCode FromNameB(string op, Reg16 op1, Reg8 op2) { byte b; switch (op) { case "movzx": b = 0xb6; break; case "movsx": b = 0xbe; break; default: throw new Exception("invalid operator: " + op); } return new OpCode(new byte[] { 0x66, 0x0f, b, (byte)(0xc0 + (((int)op1) << 3) + op2) }); }
public static OpCode FromNameB(string op, Reg16 op1, Addr32 op2) { byte b; switch (op) { case "movzx": b = 0xb6; break; case "movsx": b = 0xbe; break; default: throw new Exception("invalid operator: " + op); } return new OpCode(new byte[] { 0x66, 0x0f, b }, null, new Addr32(op2, (byte)op1)); }
public static OpCode FromNameWBA(string op, Reg16 op1, Addr32 op2) { byte b; switch (op) { case "movzx": b = 0xb6; break; case "movsx": b = 0xbe; break; default: throw new Exception("invalid operator: " + op); } return OpCode.NewA(Util.GetBytes3(0x66, 0x0f, b), Addr32.NewAdM(op2, (byte)op1)); }
public static OpCode FromNameW(string op, Reg32 op1, Reg16 op2) { byte b; switch (op) { case "movzx": b = 0xb7; break; case "movsx": b = 0xbf; break; default: throw new Exception("invalid operator: " + op); } return OpCode.NewBytes(Util.GetBytes3(0x0f, b, (byte)(0xc0 + (((int)op1) << 3) + op2))); }
/// <summary> /// Sets the value of a 16bit register /// </summary> /// <param name="register"></param> /// <param name="word"></param> public void Set(Reg16 register, ushort word) { var(highOrderByte, lowOrderByte) = word.Split(); switch (register) { case Reg16.AF: A = highOrderByte; F = lowOrderByte; break; case Reg16.BC: B = highOrderByte; C = lowOrderByte; break; case Reg16.DE: D = highOrderByte; E = lowOrderByte; break; case Reg16.HL: H = highOrderByte; L = lowOrderByte; break; case Reg16.IX: IX = word; break; case Reg16.IY: IY = word; break; case Reg16.PC: PC = word; break; case Reg16.SP: SP = word; break; default: throw new Exception("Unknown register " + register); } }
/// <summary> /// Usage: Exchanges the register DE with the register HL /// Flags: N/A /// </summary> /// <param name="operand1"></param> /// <param name="operand2"></param> public void EX(Reg16 operand1, Reg16 operand2) { if (operand1 != Reg16.DE) { throw new InvalidOperationException("The first operand must be DE"); } if (operand2 != Reg16.HL) { throw new InvalidOperationException("The second operand must be HL"); } var valueForOperand1 = this.Registers.Read(operand1); var valueForOperand2 = this.Registers.Read(operand2); this.Registers.Set(operand2, valueForOperand1); this.Registers.Set(operand1, valueForOperand2); }
public static byte[] make_frame(byte _slAddress, byte[] _pdu) { int _pduLen = _pdu.Length; int _aduLen = 1 + _pduLen + 2; byte[] _array = new byte[_aduLen]; _array[0] = _slAddress; Array.Copy(_pdu, 0, _array, 1, _pduLen); ushort _crc16 = crc16_est(_array, _aduLen - 2); _array[_aduLen - 2] = Reg16.lo(_crc16); _array[_aduLen - 1] = Reg16.hi(_crc16); return(_array); }
/// <summary> /// Usage: Adds 2 numbers together and stores the result in the first operand /// Flags: Preserves the S, Z and P/V flags, and H is undefined. Rest of flags modified by definition. /// </summary> /// <param name="reg1"></param> /// <param name="reg2"></param> public void ADD(Reg16 reg1, Reg16 reg2) { switch (reg1) { case Reg16.HL: case Reg16.IX: case Reg16.IY: break; default: throw new InvalidOperationException(); } switch (reg2) { case Reg16.AF: case Reg16.PC: throw new InvalidOperationException(); } if ((reg1 == Reg16.HL && reg2 == Reg16.IX) || (reg1 == Reg16.HL && reg2 == Reg16.IY) || (reg1 == Reg16.IX && reg2 == Reg16.HL) || (reg1 == Reg16.IX && reg2 == Reg16.IY) || (reg1 == Reg16.IY && reg2 == Reg16.HL) || (reg1 == Reg16.IY && reg2 == Reg16.IX)) { throw new InvalidOperationException(); } var value1 = this.Registers.Read(reg1); var value2 = this.Registers.Read(reg2); var total = (value1 + value2); if (total > ushort.MaxValue) { this.Flags.Set(Flag.C); total = total - 65536; } else { this.Flags.Clear(Flag.C); } this.Registers.Set(reg1, (ushort)total); }
/// <summary> /// Usage: Exchanges the register AF with its shadow register /// Flags: Yes as this is the F register /// </summary> /// <param name="operand1"></param> /// <param name="operand2"></param> public void EX(Reg16 operand1, Reg16Shadow operand2) { if (operand1 != Reg16.AF) { throw new InvalidOperationException("The only register supported is AF"); } if (operand2 != Reg16Shadow.AF) { throw new InvalidOperationException("The only shadow register supported is AF"); } var valueForOperand1 = this.Registers.Read(operand1); var valueForOperand2 = this.Registers.Read(operand2); this.Registers.Set(operand2, valueForOperand1); this.Registers.Set(operand1, valueForOperand2); }
/// <summary> /// Reads the value of a 16 bit register /// </summary> /// <param name="register"></param> /// <returns></returns> public ushort Read(Reg16 register) { var highOrderByte = default(byte); var lowOrderByte = default(byte); switch (register) { case Reg16.AF: highOrderByte = A; lowOrderByte = F; break; case Reg16.BC: highOrderByte = B; lowOrderByte = C; break; case Reg16.DE: highOrderByte = D; lowOrderByte = E; break; case Reg16.HL: highOrderByte = H; lowOrderByte = L; break; case Reg16.IX: return(IX); case Reg16.IY: return(IY); case Reg16.SP: return(SP); case Reg16.PC: return(PC); default: break; } return(MakeWord(highOrderByte, lowOrderByte)); }
public void EXShouldExchangeTheValueOfTheTwoOperands(Reg16 operand2) { var machine = new Machine(); //Following the SP pointer should give us AABB machine.Registers.Set(Reg16.SP, 0x1000); machine.Memory.Set(0x1001, 0xAA); machine.Memory.Set(0x1000, 0xBB); //Which we will swap with CCDD machine.Registers.Set(operand2, 0xCCDD); machine.EX(valueAt(Reg16.SP), operand2); Assert.Equal(0xCC, machine.Memory.Read(0x1001)); Assert.Equal(0xDD, machine.Memory.Read(0x1000)); Assert.Equal(0xAABB, machine.Registers.Read(operand2)); }
public bool wai; //raised during wai, cleared after interrupt triggered #endregion Fields #region Constructors public Regs() { Utility.InstantiateArrayElements(r); a = r[0]; x = r[1]; y = r[2]; z = r[3]; s = r[4]; d = r[5]; db = 0; e = false; irq = false; wai = false; mdr = 0; z.Assign(0); }
string Format(Reg16 reg) { switch (reg) { case Reg16.AX: return("ax"); case Reg16.BX: return("bx"); case Reg16.CX: return("cx"); case Reg16.DX: return("dx"); case Reg16.SI: return("si"); case Reg16.DI: return("di"); case Reg16.SP: return("sp"); case Reg16.BP: return("bp"); } throw new NotImplementedException(); }
public static OpCode ShiftW(string op, Reg16 op1, Reg8 op2) { byte b; switch (op) { case "shl": case "sal": b = (byte)(0xe0 + op1); break; case "shr": b = (byte)(0xe8 + op1); break; case "sar": b = (byte)(0xf8 + op1); break; default: throw new Exception("invalid operator: " + op); } if (op2 != Reg8.CL) throw new Exception("invalid register: " + op2); else return new OpCode(new byte[] { 0x66, 0xd3, b }); }
public static OpCode ShiftW(string op, Reg16 op1, byte op2) { byte b; switch (op) { case "shl": case "sal": b = (byte)(0xe0 + op1); break; case "shr": b = (byte)(0xe8 + op1); break; case "sar": b = (byte)(0xf8 + op1); break; default: throw new Exception("invalid operator: " + op); } if (op2 == 1) return OpCode.NewBytes(Util.GetBytes3(0x66, 0xd1, b)); else return OpCode.NewB(Util.GetBytes3(0x66, 0xc1, b), op2); }
public static OpCode AndWR(Reg16 op1, ushort op2) { return FromName2WR("and", op1, op2); }
public static OpCode AndW(Reg16 op1, Reg16 op2) { return FromName2W("and", op1, op2); }
public static OpCode AndWAR(Addr32 op1, Reg16 op2) { return FromName2WAR("and", op1, op2); }
public static OpCode SarWR(Reg16 op1, Reg8 op2) { return ShiftWR("sar", op1, op2); }
private void Add16Imm16(Reg16 reg) { registers.Set(reg, (ushort)(registers.Get(reg) + GetUInt16FromMemory(_ip + 1))); _ip += 3; }
public static OpCode CmpWAR(Addr32 op1, Reg16 op2) { return FromName2WAR("cmp", op1, op2); }
public static OpCode ShlWR(Reg16 op1, Reg8 op2) { return ShiftWR("shl", op1, op2); }
public static OpCode XchgWAR(Addr32 op1, Reg16 op2) { return XchgWRA(op2, op1); }
private void Xor16Imm16(Reg16 reg) { registers.Set(reg, (ushort)(registers.Get(reg) ^ BinaryHelper.Read16Bit(_memory, _ip + 1))); _ip += 3; }
public static OpCode TestWRA(Reg16 op1, Addr32 op2) { return TestWAR(op2, op1); }
public static OpCode XchgW(Reg16 op1, Reg16 op2) { return FromName2W("xchg", op1, op2); }
public static OpCode TestWR(Reg16 op1, ushort op2) { return FromName2WR("test", op1, op2); }
public static OpCode TestWAR(Addr32 op1, Reg16 op2) { return FromName2WAR("test", op1, op2); }
public static OpCode TestW(Reg16 op1, Reg16 op2) { return FromName2W("test", op1, op2); }
public static OpCode AndWRA(Reg16 op1, Addr32 op2) { return FromName2WRA("and", op1, op2); }
public static OpCode XorW(Reg16 op1, Reg16 op2) { return FromName2W("xor", op1, op2); }
public static OpCode CmpW(Reg16 op1, Reg16 op2) { return FromName2W("cmp", op1, op2); }
public static OpCode XorWAR(Addr32 op1, Reg16 op2) { return FromName2WAR("xor", op1, op2); }
// Shl, Shr, Sal, Sar public static OpCode ShlW(Reg16 op1, byte op2) { return ShiftW("shl", op1, op2); }
public static OpCode XorWR(Reg16 op1, ushort op2) { return FromName2WR("xor", op1, op2); }
public static OpCode SarW(Reg16 op1, byte op2) { return ShiftW("sar", op1, op2); }
public static OpCode XorWRA(Reg16 op1, Addr32 op2) { return FromName2WRA("xor", op1, op2); }
public static OpCode XchgWRA(Reg16 op1, Addr32 op2) { return FromName2WRA("xchg", op1, op2); }
private void Pop(Reg16 reg) { stack.Pop(reg); _ip++; }