/// <summary> /// The DisasmP function is used to disassemble a p-code opcode from /// memory, into the given buffer. /// </summary> /// <param name="buffer">The buffer to print the opcode into.</param> /// <param name="segNo">The segment number the code is within</param> /// <param name="ipcBase">The procedure base address (enter_ic).</param> /// <param name="ipc"> /// The instruction counter (address within segment) of the /// instruction to disassemble. /// </param> /// <param name="jTab"> /// The jump table (procedure attributes) of the procedure being /// executed, or disassembled. /// </param> /// <param name="sp">Stack pointer (?)</param> /// <returns></returns> public static ushort DisasmP(StringBuilder buffer, ushort segNo, ushort ipcBase, ushort ipc, ushort jTab, ushort sp) { var opCode = Memory.ReadByte(ipcBase, (short)ipc++); var s = PTrace.instructions[opCode]; int val; foreach (var ch in s) { switch (ch) { case 'A': // CXP Arguments { int seg = Memory.ReadByte(ipcBase, (short)ipc++); int proc = Memory.ReadByte(ipcBase, (short)ipc++); buffer.AppendFormat("{0},{1} ", seg, proc); buffer.Append(PTrace.ProcName(seg, proc, sp)); } break; case 'B': val = Memory.ReadByte(ipcBase, (short)ipc++); if ((val & 0x80) != 0) { val = ((val & 0x7f) << 8) + Memory.ReadByte(ipcBase, (short)ipc++); } buffer.Append(val); break; case 'C': val = Memory.ReadByte(ipcBase, (short)ipc++); buffer.AppendFormat("{0} ", val); buffer.Append(PTrace.ProcName(segNo, val, sp)); break; case 'D': case 'U': val = Memory.ReadByte(ipcBase, (short)ipc++); buffer.Append(val); break; case 'P': if (sp != 0) { buffer.Append(PTrace.PString(PTrace.ReadStack(sp, 0))); } break; case 'S': val = Memory.ReadByte(ipcBase, (short)ipc++); if ((val & 0x80) != 0) { val = -(0x100 - val); } buffer.Append(val); break; case 'T': val = Memory.ReadByte(ipcBase, (short)ipc++); switch (val) { case 2: buffer.Append("real"); break; case 4: buffer.Append("string"); break; case 6: buffer.Append("boolean"); break; case 8: buffer.Append("set"); break; case 10: val = Memory.ReadByte(ipcBase, (short)ipc++); if ((val & 0x80) != 0) { val = ((val & 0x7f) << 8) + Memory.ReadByte(ipcBase, (short)ipc++); } buffer.AppendFormat("byte array, {0} bytes", val); break; case 12: val = Memory.ReadByte(ipcBase, (short)ipc++); if ((val & 0x80) != 0) { val = ((val & 0x7f) << 8) + Memory.ReadByte(ipcBase, (short)ipc++); } buffer.AppendFormat("{0} words", val); break; default: buffer.Append(val); break; } break; case 'W': val = Memory.ReadByte(ipcBase, (short)ipc++); val |= Memory.ReadByte(ipcBase, (short)ipc++) << 8; buffer.Append(val); break; case 'R': // case arguments { ipc = (ushort)(ipc + 1 & ~1); int min = Memory.ReadByte(ipcBase, (short)ipc++); min |= Memory.ReadByte(ipcBase, (short)ipc++) << 8; int max = Memory.ReadByte(ipcBase, (short)ipc++); max |= Memory.ReadByte(ipcBase, (short)ipc++) << 8; ipc++; int defaultVal = Memory.ReadByte(ipcBase, (short)ipc++); if ((defaultVal & 0x80) != 0) // less than zero? { defaultVal = -(0x100 - defaultVal); defaultVal = -defaultVal; defaultVal = Memory.ReadByte(jTab, -2) + (Memory.ReadByte(jTab, -1) << 8) + 2 - (Memory.ReadByte(jTab, (short)-defaultVal) + (Memory.ReadByte(jTab, (short)(-defaultVal + 1)) << 8) + defaultVal); } else { defaultVal = ipc + defaultVal; } buffer.AppendFormat("{0},{1},{2} ", min, max, defaultVal); while (min < max + 1) { val = Memory.ReadByte(ipcBase, (short)ipc++); val |= Memory.ReadByte(ipcBase, (short)ipc++) << 8; buffer.AppendFormat(",{0}", ipc - 2 - val); min++; } } break; case 'Q': val = Memory.ReadByte(ipcBase, (short)ipc++); switch (val) { case 1: buffer.Append("new"); break; case 2: buffer.Append("Moveleft"); break; case 3: buffer.Append("Moveright"); break; case 4: buffer.Append("exit"); break; case 5: buffer.Append("unitread"); break; case 6: buffer.Append("unitwrite"); break; case 7: buffer.Append("idsearch"); break; case 8: buffer.Append("treesearch"); break; case 9: buffer.Append("time"); break; case 10: buffer.Append("fillchar"); break; case 11: buffer.AppendFormat("scan"); break; case 12: buffer.Append("unitstat"); break; case 21: buffer.Append("load_segment"); break; case 22: buffer.Append("unload_segment"); break; case 32: buffer.Append("mark"); break; case 33: buffer.Append("release"); break; case 34: buffer.Append("ioresult"); break; case 35: buffer.Append("unitbusy"); break; case 37: buffer.Append("unitwait"); break; case 38: buffer.Append("unitclear"); break; case 39: buffer.Append("halt"); break; case 40: buffer.Append("memavail"); break; default: buffer.Append(val); break; } break; case 'J': val = Memory.ReadByte(ipcBase, (short)ipc++); if ((val & 0x80) != 0) /* less than zero? */ { val = -(0x100 - val); val = -val; val = Memory.ReadByte(jTab, -2) + (Memory.ReadByte(jTab, -1) << 8) + 2 - (Memory.ReadByte(jTab, (short)-val) + (Memory.ReadByte(jTab, (short)(-val + 1)) << 8) + val); } else { val = ipc + val; } buffer.Append(val); break; case 'V': break; case 'X': val = Memory.ReadByte(ipcBase, (short)ipc++); buffer.Append(val); ipc = (ushort)(ipc + 1 & ~1); while (val-- != 0) { var w = Memory.ReadByte(ipcBase, (short)ipc) + (Memory.ReadByte(ipcBase, (short)(ipc + 1)) << 8); ipc += 2; buffer.AppendFormat(",{0:X4}", w); } break; case 'Y': val = Memory.ReadByte(ipcBase, (short)ipc++); buffer.AppendFormat("{0},'", val); while (val-- != 0) { buffer.Append((char)Memory.ReadByte(ipcBase, (short)ipc++)); } buffer.Append('\''); break; case 'Z': val = Memory.ReadByte(ipcBase, (short)ipc++); buffer.Append(val); ipc = (ushort)(ipc + 1 & ~1); while (val-- != 0) { buffer.AppendFormat(",{0:X2}", Memory.ReadByte(ipcBase, (short)ipc)); ipc++; } break; default: buffer.Append(ch); break; } } return(ipc); }
private static string ProcName(int seg, int proc, ushort sp) { if (seg != 0) { return(string.Empty); } StringBuilder sb = new(); switch (proc) { case 5: sb.Append("Rewrite"); if (sp == 0) { break; } sb.Append('('); sb.Append(PTrace.PString(PTrace.ReadStack(sp, 2))); sb.Append(')'); break; case 6: sb.Append("Close"); break; case 7: sb.Append("Get"); break; case 8: sb.Append("Put"); break; case 10: sb.Append("Eof"); break; case 11: sb.Append("Eoln"); break; case 12: sb.Append("ReadInteger"); break; case 13: sb.Append("WriteInteger"); break; case 16: sb.Append("ReadChar"); break; case 17: sb.Append("WriteChar"); break; case 18: sb.Append("ReadString"); break; case 19: sb.Append("WriteString"); if (sp == 0) { break; } sb.Append('('); sb.Append(PTrace.PString(PTrace.ReadStack(sp, 1))); sb.Append(')'); break; case 21: sb.Append("ReadLn"); break; case 22: sb.Append("WriteLn"); break; case 23: sb.Append("Concat"); if (sp == 0) { break; } sb.Append('('); sb.Append(PTrace.PString(PTrace.ReadStack(sp, 2))); sb.Append(','); sb.Append(PTrace.PString(PTrace.ReadStack(sp, 1))); sb.Append(')'); break; case 24: sb.Append("Insert"); if (sp == 0) { break; } sb.Append('('); sb.Append(PTrace.PString(PTrace.ReadStack(sp, 3))); sb.Append(','); sb.Append(PTrace.PString(PTrace.ReadStack(sp, 2))); sb.AppendFormat(", {0})", PTrace.ReadStack(sp, 0)); break; case 25: sb.Append("Copy"); if (sp == 0) { break; } sb.Append('('); sb.Append(PTrace.PString(PTrace.ReadStack(sp, 3))); sb.AppendFormat(", {0}, {1})", PTrace.ReadStack(sp, 1), PTrace.ReadStack(sp, 0)); break; case 26: sb.Append("Delete"); if (sp == 0) { break; } sb.Append('('); sb.Append(PTrace.PString(PTrace.ReadStack(sp, 2))); sb.AppendFormat(", {0}, {1})", PTrace.ReadStack(sp, 1), PTrace.ReadStack(sp, 0)); break; case 27: sb.Append("Pos"); if (sp == 0) { break; } sb.Append('('); sb.Append(PTrace.PString(PTrace.ReadStack(sp, 3))); sb.Append(','); sb.Append(PTrace.PString(PTrace.ReadStack(sp, 2))); sb.Append(')'); break; case 28: sb.Append("BlockRead/BlockWrite"); break; case 29: sb.Append("GotoXY"); if (sp != 0) { sb.AppendFormat("( {0}, {1})", PTrace.ReadStack(sp, 1), PTrace.ReadStack(sp, 0)); } break; } return(sb.ToString()); }