private Tms7000Instruction Decode(Opcode opcode, string format) { int iOp = 0; var instr = new Tms7000Instruction { Opcode = opcode, }; for (int i = 0; i < format.Length; ++i) { MachineOperand op; byte b; ushort w; switch (format[i]) { case ',': continue; case 'A': op = new RegisterOperand(arch.a); break; case 'B': op = new RegisterOperand(arch.b); break; case 'R': if (!rdr.TryReadByte(out b)) { return(Invalid()); } op = new RegisterOperand(arch.GpRegs[b]); break; case 'P': if (!rdr.TryReadByte(out b)) { return(Invalid()); } op = new RegisterOperand(arch.Ports[b]); break; case 'S': ; op = new RegisterOperand(arch.st); break; case 'i': if (!rdr.TryReadByte(out b)) { return(Invalid()); } op = ImmediateOperand.Byte(b); break; case 'I': if (!rdr.TryReadBeUInt16(out w)) { return(Invalid()); } op = ImmediateOperand.Word16(w); break; case 'j': // short PC-relative jump if (!rdr.TryReadByte(out b)) { return(Invalid()); } op = AddressOperand.Create(rdr.Address + (sbyte)b); break; case 'D': // direct, absolute address if (!rdr.TryReadBeUInt16(out w)) { return(Invalid()); } if (i < format.Length - 1 && format[i + 1] == 'B') { ++i; op = MemoryOperand.Indexed(Address.Ptr16(w), arch.b); } else { op = MemoryOperand.Direct(Address.Ptr16(w)); } break; case '*': // indirect if (!rdr.TryReadByte(out b)) { return(Invalid()); } op = MemoryOperand.Indirect(arch.GpRegs[b]); break; default: throw new NotImplementedException($"Addressing mode {format[i]}"); } switch (iOp++) { case 0: instr.op1 = op; break; case 1: instr.op2 = op; break; case 2: instr.op3 = op; break; } } return(instr); }