/// <summary> /// Returns VAT and VATless fees /// </summary> /// <returns></returns> public string ToString(ShowFormat fmt) { if (fmt == ShowFormat.withoutVAT) { return(String.Format(new NumberFormatInfo(), $"{VATLess,10:C2}")); } else if (fmt == ShowFormat.withVAT) { return(String.Format(new NumberFormatInfo(), $"{WithVAT,10:C2}")); } return(String.Format(new NumberFormatInfo(), $"{VATLess,10:C2} / {WithVAT,10:C2}")); }
/// <summary> /// Main execution /// </summary> public string Disassemble(ref ushort OpCodeAddress) { ushort Address; ushort IOAddress; byte opcode; ShowFormat DataFormat = ShowFormat.Decimal; // Fetch next instruction opcode = _Memory.ReadByte(OpCodeAddress++); if (opcode == 0x76) // HALT { // The first check is for HALT otherwise it could be // interpreted as LD (HL),(HL) return("HALT"); } else if ((opcode & 0xC0) == 0x40) // LD r,r { string reg1 = GetHalfRegister((byte)(opcode >> 3)); string reg2 = GetHalfRegister(opcode); return(string.Format("LD {0},{1}", reg1, reg2)); } else if ((opcode & 0xC0) == 0x80) { // Operation beetween accumulator and other registers // Usually are identified by 10 ooo rrr where ooo is the operation and rrr is the source register string reg = GetHalfRegister(opcode); switch (opcode & 0xF8) { case 0x80: // ADD A,r return(string.Format("ADD A,{0}", reg)); case 0x88: // ADC A,r return(string.Format("ADC A,{0}", reg)); case 0x90: // SUB r return(string.Format("SUB {0}", reg)); case 0x98: // SBC A,r return(string.Format("SBC A,{0}", reg)); case 0xA0: // AND r return(string.Format("AND {0}", reg)); case 0xA8: // XOR r return(string.Format("XOR {0}", reg)); case 0xB0: // OR r return(string.Format("OR {0}", reg)); case 0xB8: // CP r return(string.Format("CP {0}", reg)); default: throw new Exception("Wrong place in the right time..."); } } else if ((opcode & 0xC7) == 0x04) // INC r { string reg = GetHalfRegister((byte)(opcode >> 3)); return(string.Format("INC {0}", reg)); } else if ((opcode & 0xC7) == 0x05) // DEC r { string reg = GetHalfRegister((byte)(opcode >> 3)); return(string.Format("DEC {0}", reg)); } else if ((opcode & 0xC7) == 0x06) // LD r,nn { string reg = GetHalfRegister((byte)(opcode >> 3)); byte Value = _Memory.ReadByte(OpCodeAddress++); return(string.Format("LD {0},{1}", reg, ShowData(Value))); } else if ((opcode & 0xC7) == 0xC0) // RET cc { return(string.Format("RET {0}", CheckFlag(opcode))); } else if ((opcode & 0xC7) == 0xC2) // JP cc,nn { Address = _Memory.ReadWord(OpCodeAddress); string retValue = string.Format("JP {0},{1}", CheckFlag(opcode), ShowData(Address)); OpCodeAddress += 2; return(retValue); } else if ((opcode & 0xC7) == 0xC4) // CALL cc,nn { Address = _Memory.ReadWord(OpCodeAddress); string retValue = string.Format("JP {0},{1}", CheckFlag(opcode), ShowData(Address)); OpCodeAddress += 2; return(retValue); } else if ((opcode & 0xC7) == 0xC7) // RST p { return(string.Format("RST {0}", ShowData((opcode & 0x38)))); } else if ((opcode & 0xCF) == 0x01) // LD dd,nn { string reg = GetRegister(opcode, true); ushort Value = _Memory.ReadWord(OpCodeAddress); OpCodeAddress += 2; return(string.Format("LD {0},{1}", reg, ShowData(Value))); } else if ((opcode & 0xCF) == 0x03) // INC ss { string reg = GetRegister(opcode, true); return(string.Format("INC {0}", reg)); } else if ((opcode & 0xCF) == 0x09) // ADD HL,ss { string reg = GetRegister(opcode, true); return(string.Format("ADD HL,{0}", reg)); } else if ((opcode & 0xCF) == 0x0B) // DEC ss { string reg = GetRegister(opcode, true); return(string.Format("DEC {0}", reg)); } else if ((opcode & 0xCF) == 0xC5) // PUSH qq { string reg = GetRegister(opcode, false); return(string.Format("PUSH {0}", reg)); } else if ((opcode & 0xCF) == 0xC1) // POP qq { string reg = GetRegister(opcode, false); return(string.Format("POP {0}", reg)); } else { switch (opcode) { case 0x00: // NOP return("NOP"); case 0x02: // LD (BC),A return("LD (BC),A"); case 0x07: // RLCA return("RLCA"); case 0x08: // EX AF,AF' return("EX AF,AF'"); case 0x0A: // LD A,(BC) return("LD A,(BC)"); case 0x0F: // RRCA return("RRCA"); case 0x10: // DJNZ offset return(string.Format("DJNZ {0}", ShowData((sbyte)_Memory.ReadByte(OpCodeAddress++) + OpCodeAddress))); case 0x12: // LD (DE),A return("LD (DE),A"); case 0x17: // RLA return("RLA"); case 0x18: // JR offset return(string.Format("JR {0}", ShowData((sbyte)_Memory.ReadByte(OpCodeAddress++) + OpCodeAddress))); case 0x1A: // LD A,(DE) return("LD A,(DE)"); case 0x1F: // RRA return("RRA"); case 0x20: // JR NZ,offset return(string.Format("JR NZ,{0}", ShowData((sbyte)_Memory.ReadByte(OpCodeAddress++) + OpCodeAddress))); case 0x22: // LD (nnnn),HL Address = _Memory.ReadWord(OpCodeAddress); OpCodeAddress += 2; return(string.Format("LD ({0}),HL", ShowData(Address))); case 0x27: // DAA return("DAA"); case 0x28: // JR Z,offset return(string.Format("JR Z,{0}", ShowData((sbyte)_Memory.ReadByte(OpCodeAddress++) + OpCodeAddress))); case 0x2A: // LD HL,(nnnn) Address = _Memory.ReadWord(OpCodeAddress); OpCodeAddress += 2; return(string.Format("LD HL,({0})", ShowData(Address))); case 0x2F: // CPL return("CPL"); case 0x30: // JR NC,offset return(string.Format("JR NC,{0}", ShowData((sbyte)_Memory.ReadByte(OpCodeAddress++) + OpCodeAddress))); case 0x32: // LD (nnnn),A Address = _Memory.ReadWord(OpCodeAddress); OpCodeAddress += 2; return(string.Format("LD ({0}),A", ShowData(Address))); case 0x37: // SCF return("SCF"); case 0x38: // JR C,offset return(string.Format("JR C,{0}", ShowData((sbyte)_Memory.ReadByte(OpCodeAddress++) + OpCodeAddress))); case 0x3A: // LD A,(nnnn) Address = _Memory.ReadWord(OpCodeAddress); OpCodeAddress += 2; return(string.Format("LD A,({0})", ShowData(Address))); case 0x3F: // CCF return("CCF"); case 0xC3: // JP nnnn Address = _Memory.ReadWord(OpCodeAddress); OpCodeAddress += 2; return(string.Format("JP {0}", ShowData(Address))); case 0xC6: // ADD A,nn return(string.Format("ADD A,{0}", ShowData(_Memory.ReadByte(OpCodeAddress++)))); case 0xC9: // RET return("RET"); case 0xCB: // CBxx opcodes return(Disassemble_CB(_Memory.ReadByte(OpCodeAddress++))); case 0xCD: // CALL nnnn Address = _Memory.ReadWord(OpCodeAddress); OpCodeAddress += 2; return(string.Format("CALL {0}", ShowData(Address))); case 0xCE: // ADC A,nn return(string.Format("ADC A,{0}", ShowData(_Memory.ReadByte(OpCodeAddress++)))); case 0xD3: // OUT (nn),A IOAddress = _Memory.ReadByte(OpCodeAddress++); return(string.Format("OUT ({0}),A", ShowData(IOAddress))); case 0xD6: // SUB nn return(string.Format("SUB {0}", _Memory.ReadByte(OpCodeAddress++))); case 0xD9: // EXX // Each 2-byte value in register pairs BC, DE, and HL is exchanged with the // 2-byte value in BC', DE', and HL', respectively. return("EXX"); case 0xDB: // IN A,(nn) // The operand n is placed on the bottom half (A0 through A7) of the address // bus to select the I/O device at one of 256 possible ports. The contents of the // Accumulator also appear on the top half (A8 through A15) of the address // bus at this time. Then one byte from the selected port is placed on the data // bus and written to the Accumulator (register A) in the CPU. IOAddress = _Memory.ReadByte(OpCodeAddress++); return(string.Format("IN A,({0})", ShowData(IOAddress))); case 0xDD: // DDxx opcodes return(Disassemble_DDFD("IX", ref OpCodeAddress)); case 0xDE: // SBC A,nn return(string.Format("SBC A,{0}", _Memory.ReadByte(OpCodeAddress++))); case 0xE3: // EX (SP),HL return("EX (SP),HL"); case 0xE6: // AND nn return(string.Format("AND {0}", _Memory.ReadByte(OpCodeAddress++))); case 0xE9: // JP HL return("JP HL"); case 0xEB: // EX DE,HL return("EX DE,HL"); case 0xed: // EDxx opcodes return(Disassemble_ED(ref OpCodeAddress)); case 0xEE: // XOR A,nn return(string.Format("XOR A,{0}", _Memory.ReadByte(OpCodeAddress++))); case 0xF3: // DI return("DI"); case 0xF6: // OR nn return(string.Format("OR {0}", _Memory.ReadByte(OpCodeAddress++))); case 0xF9: // LD SP,HL return("LD SP,HL"); case 0xFB: // EI return("EI"); case 0xFD: // FDxx opcodes return(Disassemble_DDFD("IY", ref OpCodeAddress)); case 0xFE: // CP nn return(string.Format("CP {0}", _Memory.ReadByte(OpCodeAddress++))); default: throw new Exception(string.Format("Internal disassembler error. Opcode {0} not implemented.", opcode)); } } }