dmolony-DiskBrowser/src/com/bytezone/diskbrowser/applefile/PascalCodeStatement.java

352 lines
9.8 KiB
Java
Raw Normal View History

2015-06-01 09:35:51 +00:00
package com.bytezone.diskbrowser.applefile;
import java.util.ArrayList;
import java.util.List;
2016-02-24 21:11:14 +00:00
import com.bytezone.diskbrowser.utilities.HexFormatter;
2015-06-01 09:35:51 +00:00
public class PascalCodeStatement implements PascalConstants
{
2016-08-02 10:37:27 +00:00
private static final String[] compValue =
{ "invalid", "", "REAL", "", "STR", "", "BOOL", "", "POWR", "", "BYT", "", "WORD" };
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
int length;
int val;
int p1, p2, p3;
String mnemonic;
String extras = "";
String description;
String text;
int ptr; // temp
byte[] buffer;
boolean jumpTarget;
List<Jump> jumps = new ArrayList<Jump> ();
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
public PascalCodeStatement (byte[] buffer, int ptr, int procPtr)
{
this.ptr = ptr;
this.buffer = buffer;
length = 1;
val = buffer[ptr] & 0xFF;
if (val <= 127)
{
mnemonic = "SLDC";
extras = "#" + val;
description = "Short load constant - push #" + val;
}
else if (val >= 248)
{
mnemonic = "SIND";
extras = "#" + (val - 248);
description = "Short index load - push word *ToS + #" + (val - 248);
}
else if (val >= 232)
{
mnemonic = "SLDO";
extras = "#" + (val - 231);
description = "Short load global - push BASE + #" + (val - 231);
}
else if (val >= 216)
{
mnemonic = "SLDL";
extras = "#" + (val - 215);
description = "Short load local - push MP + #" + (val - 215);
}
else
{
mnemonic = mnemonics[val - 128];
description = descriptions[val - 128];
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
length = mnemonicSize[val - 128];
if (length != 1)
{
switch (val)
{
// W1, W2, W3, <table> - word aligned case jump
case 172: //XJP
int padding = (ptr % 2) == 0 ? 1 : 0;
p1 = getWord (buffer, ptr + padding + 1);
p2 = getWord (buffer, ptr + padding + 3);
p3 = getWord (buffer, ptr + padding + 5);
length = (p2 - p1 + 1) * 2 + 7 + padding;
setParameters (p1, p2, String.format ("%04X", p3));
int v = p1;
int min = ptr + padding + 7;
int max = min + (p2 - p1) * 2;
for (int i = min; i <= max; i += 2)
{
jumps.add (new Jump (i,
i - HexFormatter.intValue (buffer[i], buffer[i + 1]), v++));
}
break;
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
// UB, <block> - word aligned
case 179: //LDC
p1 = buffer[ptr + 1] & 0xFF;
padding = ptr % 2 == 0 ? 0 : 1;
length = p1 * 2 + padding + 2;
setParameters (p1);
break;
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
// UB, <chars>
case 166: // LSA
case 208: // LPA
p1 = buffer[ptr + 1] & 0xFF;
length = p1 + 2;
if (val == 166)
{
text = HexFormatter.getPascalString (buffer, ptr + 1);
description += ": " + text;
}
break;
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
// W
case 199: // LDCI
p1 = getWord (buffer, ptr + 1);
setParameters (p1);
break;
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
// B
case 162: // INC
case 163: // IND
case 164: // IXA
case 165: // LAO
case 168: // MOV
case 169: // LDO
case 171: // SRO
case 198: // LLA
case 202: // LDL
case 204: // STL
case 213: // BPT
length = getLengthOfB (buffer[ptr + 1]) + 1;
p1 = getValueOfB (buffer, ptr + 1, length - 1);
setParameters (p1);
break;
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
// DB, B or UB, B
case 157: // LDE
case 167: // LAE
case 178: // LDA
case 182: // LOD
case 184: // STR
case 209: // STE
length = getLengthOfB (buffer[ptr + 2]) + 2;
p1 = buffer[ptr + 1] & 0xFF;
p2 = getValueOfB (buffer, ptr + 2, length - 2);
setParameters (p1, p2);
break;
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
// UB1, UB2
case 192: // IXP
case 205: // CXP
p1 = buffer[ptr + 1] & 0xFF;
p2 = buffer[ptr + 2] & 0xFF;
setParameters (p1, p2);
break;
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
// SB or DB
case 161: // FJP
case 173: // RNP
case 185: // UJP
case 193: // RBP
case 211: // EFJ
case 212: // NFJ
p1 = buffer[ptr + 1];
if (val == 173 || val == 193) // return from procedure
setParameters (p1);
else if (p1 < 0)
{
// look up jump table entry
int address = procPtr + p1;
int ptr2 = address
- ((buffer[address + 1] & 0xFF) * 256 + (buffer[address] & 0xFF));
extras = String.format ("$%04X", ptr2);
jumps.add (new Jump (ptr, ptr2));
}
else
{
int address = ptr + length + p1;
extras = String.format ("$%04X", address);
jumps.add (new Jump (ptr, address));
}
break;
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
// UB
case 160: // AOJ
case 170: // SAS
case 174: // CIP
case 188: // LDM
case 189: // STM
case 194: // CBP
case 206: // CLP
case 207: // CGP
p1 = buffer[ptr + 1] & 0xFF;
setParameters (p1);
break;
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
// CSP
case 158:
p1 = buffer[ptr + 1] & 0xFF;
if (p1 < CSP.length)
description = "Call standard procedure - " + CSP[p1];
else
description = "Call standard procedure - index out of bounds";
break;
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
// Non-integer comparisons
case 175:
case 176:
case 177:
case 180:
case 181:
case 183:
p1 = buffer[ptr + 1] & 0xFF; // 2/4/6/8/10/12
if (p1 < 0 || p1 >= compValue.length)
{
System.out.printf ("%d %d %d%n", val, p1, ptr);
mnemonic += "******************************";
break;
}
mnemonic += compValue[p1];
if (p1 == 10 || p1 == 12)
{
length = getLengthOfB (buffer[ptr + 2]) + 2;
p2 = getValueOfB (buffer, ptr + 2, length - 2);
setParameters (p2);
}
break;
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
default:
System.out.println ("Forgot : " + val);
}
}
}
}
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
private int getWord (byte[] buffer, int ptr)
{
return (buffer[ptr + 1] & 0xFF) * 256 + (buffer[ptr] & 0xFF);
}
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
private int getLengthOfB (byte b)
{
return (b & 0x80) == 0x80 ? 2 : 1;
}
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
private int getValueOfB (byte[] buffer, int ptr, int length)
{
if (length == 2)
return (buffer[ptr] & 0x7F) * 256 + (buffer[ptr + 1] & 0xFF);
return buffer[ptr] & 0xFF;
}
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
private void setParameters (int p1)
{
description = description.replaceFirst (":1", p1 + "");
extras = "#" + p1;
}
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
private void setParameters (int p1, int p2)
{
setParameters (p1);
extras += ", #" + p2;
description = description.replaceFirst (":2", p2 + "");
}
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
private void setParameters (int p1, int p2, String p3)
{
setParameters (p1, p2);
description = description.replaceFirst (":3", p3);
}
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
@Override
public String toString ()
{
String hex = getHex (buffer, ptr, length > 4 ? 4 : length);
StringBuilder text = new StringBuilder ();
2017-06-17 22:10:55 +00:00
text.append (String.format ("%2s%05X: %-11s %-6s %-10s %s%n",
jumpTarget ? "->" : "", ptr, hex, mnemonic, extras, description));
2016-08-02 10:37:27 +00:00
if (length > 4)
{
int bytesLeft = length - 4;
int jmp = 0;
int p = ptr + 4;
while (bytesLeft > 0)
{
String line = getHex (buffer, p, (bytesLeft > 4) ? 4 : bytesLeft);
text.append (" " + line);
if (jumps.size () > 0)
{
if (jmp < jumps.size ())
text.append (" " + jumps.get (jmp++));
if (jmp < jumps.size ())
text.append (" " + jumps.get (jmp++));
}
text.append ("\n");
bytesLeft -= 4;
p += 4;
}
}
return text.toString ();
}
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
private String getHex (byte[] buffer, int offset, int length)
{
if ((offset + length) >= buffer.length)
{
System.out.println ("too many");
return "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
}
StringBuilder text = new StringBuilder ();
for (int i = 0; i < length; i++)
text.append (String.format ("%02X ", buffer[offset + i]));
if (text.length () > 0)
text.deleteCharAt (text.length () - 1);
return text.toString ();
}
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
class Jump
{
int addressFrom;
int addressTo;
boolean caseJump;
int caseValue;
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
public Jump (int addressFrom, int addressTo)
{
this.addressFrom = addressFrom;
this.addressTo = addressTo;
}
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
public Jump (int addressFrom, int addressTo, int value)
{
this (addressFrom, addressTo);
this.caseValue = value;
this.caseJump = true;
}
2015-06-01 09:35:51 +00:00
2016-08-02 10:37:27 +00:00
@Override
public String toString ()
{
if (caseJump)
return String.format ("%3d: %04X", caseValue, addressTo);
return String.format ("%04X", addressTo);
}
}
2016-08-03 11:32:47 +00:00
}
/* from Wizardry info 1.txt
LDC instruction
---------------
Earlier today I noticed the LDC pcode instruction seems to display
differently at times. Then I realized that it is operating with WORD
values and needs to have them aligned on an even BYTE boundary. For
example:
5004 B3 02 8C 3F CD CC
LDC. PUSH 02 WORDS
5017 B3 02 (02)8C 3F CD CC
LDC. PUSH 02 WORDS
*/