/*****************************************************************************
 *  Softech P-System decompiler                                              *
 *                                                                           *
 *****************************************************************************
 * Module:      Main application                                             *
 * File:        pcode_dasm.c	                                             *
 * Description: Reads a supplied binary file containing pcode Opcodes and    *
 *              outputs a disassemble listing for them.                      *
 * Version:     1.0                                                          *
 * Info:        http://www.waldbauer.com/vb/forumdisplay.php?f=57            *
 *****************************************************************************

 See manual at:
 http://bitsavers.trailing-edge.com/pdf/softech/1-140.41.A_pSysInternArc_83.pdf

*/
#include <stdio.h>

#define SH_B	/* If set, hex bytes are also printed */

#ifdef SH_B
#include <stdarg.h>

static char idt;

static void output(char *prfx, ...)
{
	va_list ap;
	int i;

	for (i=0; i<idt; i++) printf ("   ");
	va_start(ap, prfx);
	vprintf (prfx, ap);
	va_end(ap);
}
#else
#define output printf
#endif


static short B(FILE *fp)
{
	short w;
	unsigned char c = (unsigned char)fgetc(fp);

#ifdef SH_B
	idt--;
	printf ("%02X ", c);
#endif
	if (c<128) return c;
	c&=0x7F;
	w=((short)c<<8);
	c=fgetc(fp);
#ifdef SH_B
	idt--;
	printf ("%02X ", c);
#endif
	w|=c;
	return w;
}

static short W(FILE *fp)
{
	short w;

	fread (&w, sizeof(w), 1, fp);
#ifdef SH_B
	idt-=2;
	printf ("%02X %02X ", w&0xFF, (w>>8)&0xFF);
#endif
	return w;
}

static char *PROC(char c)
{
	switch (c)
	{
	case 34: return "UNITCLEAR";
	case 36: return "UNITSTATUS";
	case 18: return "UNITREAD";
	case 19: return "UNITWRITE";
	case 33: return "UNITWAIT";
	case 31: return "UNITBUSY";
	case 30: return "IORESULT";
	case 23: return "IOCHECK";
	case 15: return "MOVELEFT";
	case 16: return "MOVERIGHT";
	case 21: return "FILLCHAR";
	case 22: return "SCAN";
	case 38: return "TREESEARCH";
	case 37: return "IDSEARCH";
	case  4: return "RELOCSEG";
	case 14: return "MOVESEG";
	case 24: return "GETPOOLBYTES";
	case 25: return "PUTPOOLBYTES";
	case 26: return "FLIPSEGBYTES";
	case 39: return "READSEG";
	case 27: return "QUIET";
	case 28: return "ENABLE";
	case 29: return "ATTACH";
	case 20: return "TIME";
	case 32: return "POWEROFTEN";
	}
	return "";
}

#ifdef SH_B
static char DB (FILE *fp)
{
	char c=fgetc(fp);
	idt--;
	printf ("%02X ", (unsigned char)c);
	return c&0x7F;
}

static char UB(FILE *fp)
{
	unsigned char c = (unsigned char)fgetc(fp);
	idt--;
	printf ("%02X ", c);
	return c;
}

static char SB(FILE *fp)
{
	char c = (char)fgetc(fp);
	idt--;
	printf ("%02X ", (unsigned char)c);
	return c;
}
#else
#define DB(fp) (fgetc(fp)&0x7F)
#define UB(fp) (unsigned char)fgetc(fp)
#define SB(fp) (char)fgetc(fp)
#endif

int main (int argc, char **argv)
{
	FILE *fp;
	int c;
	short a[3];

	if (argc<2)
	{
		printf ("Usage: %s [File with bytecode to dasm]\n", argv[0]);
		return -1;
	}
	if (!(fp=fopen(argv[1], "rb")))
	{
		perror("Cannot open file");
		return -1;
	}
	while ((c=fgetc(fp))!=EOF)
	{
		printf ("%08d ", ftell(fp)-1);
#ifdef SH_B
		printf ("%02X ", c);
		idt = 4;
#endif
		if (c<32)
		{
			output ("SLDC%d\n", c);
		}
		else if (c<48)
		{
			output ("SLDL%d\n", c-31);
		}
		else if (c<64)
		{
			output ("SLDO%d\n", c-47);
		}
		else if (c<96)
		{
			output ("??? (0x%02X)\n", c);
		}
		else if (c<104)
		{
			output ("SLLA%d\n", c-95);
		}
		else if (c<112)
		{
			output ("SSTL%d\n", c-103);
		}
		else if (c<120)
		{
			output ("SCXG%d %s\n", c-111, PROC(c-111));
		}
		else if (c<128)
		{
			output ("SIND%d\n", c-120);
		}
		else if (c>=250)
		{
			output ("RESERVE%d\n", c-250);
		}
		else if (c>=245)
		{
			output ("UNUSED (0x%02X)\n", c);
		}
		else
		{
			switch (c)
			{
			case 0xE0:
				output ("ABI\n");
				break;
			case 0xE3:
				output ("ABR\n");
				break;
			case 0xA2:
				output ("ADI\n");
				break;
			case 0xC7:
				output ("ADJ %d\n", UB(fp));
				break;
			case 0xC0:
				output ("ADR\n");
				break;
			case 0xEB:
				a[0] = UB(fp);
				a[1] = UB(fp);
				output ("ASTR %d, %d\n", a[0], a[1]);
				break;
			case 0x9F:
				output ("BNOT\n");
				break;
			case 0x9E:
				output ("BPT\n");
				break;
			case 0xAB:
				output ("CAP %d\n", B(fp));
				break;
			case 0x97:
				output ("CFP %d\n", UB(fp));
				break;
			case 0x91:
				output ("CGP %d\n", UB(fp));
				break;
			case 0xCB:
				output ("CHK\n");
				break;
			case 0x92:
				a[0] = DB(fp);
				a[1] = UB(fp);
				output ("CIP %d, %d\n", a[0], a[1]);
				break;
			case 0x90:
				output ("CLP %d\n", UB(fp));
				break;
			case 0xAC:
				output ("CSP %d\n", UB(fp));
				break;
			case 0xEC:
				output ("CSTR\n");
				break;
			case 0x94:
				a[0] = UB(fp);
				a[1] = UB(fp);
				output ("CXG %d %s, %d\n", a[0], PROC(a[0]), a[1]);
				break;
			case 0x95:
				a[0] = UB(fp);
				a[1] = DB(fp);
				a[2] = UB(fp);
				output ("CXI %d, %d, %d\n", a[0], a[1], a[2]);
				break;
			case 0x93:
				a[0] = UB(fp);
				a[1] = UB(fp);
				output ("CXL %d, %d\n", a[0], a[1]);
				break;
			case 0xEE:
				output ("DECI\n");
				break;
			case 0xDD:
				output ("DIF\n");
				break;
			case 0xE2:
				output ("DUP1\n");
				break;
			case 0xC6:
				output ("DUPR\n");
				break;
			case 0x8D:
				output ("DVI\n");
				break;
			case 0xC3:
				output ("DVR\n");
				break;
			case 0xD2:
				output ("EFJ %d\n", SB(fp));
				break;
			case 0xB9:
				a[0] = UB(fp);
				a[1] = UB(fp);
				a[2] = B(fp);
				output ("EQBYT %d, %d, %d\n", a[0], a[1], a[2]);
				break;
			case 0xB6:
				output ("EQPWR\n");
				break;
			case 0xCD:
				output ("EQREAL\n");
				break;
			case 0xE8:
				a[0] = UB(fp);
				a[1] = UB(fp);
				output ("EQSTR %d, %d\n", a[0], a[1]);
				break;
			case 0xB0:
				output ("EQUI\n");
				break;
			case 0xD4:
				a[0] = SB(fp);
				output ("FJP %d (->%d)\n", a[0], ftell(fp)+a[0]);
				break;
			case 0xD5:
				a[0] = W(fp);
				output ("FJPL %d (->%d)\n", a[0], ftell(fp)+a[0]);
				break;
			case 0xCC:
				output ("FLT\n");
				break;
			case 0xBB:
				a[0] = UB(fp);
				a[1] = UB(fp);
				a[2] = B(fp);
				output ("GEBYT %d, %d, %d\n", a[0], a[1], a[2]);
				break;
			case 0xB8:
				output ("GEPWR\n");
				break;
			case 0xB3:
				output ("GEQI\n");
				break;
			case 0xCF:
				output ("GEREAL\n");
				break;
			case 0xEA:
				a[0] = UB(fp);
				a[1] = UB(fp);
				output ("GESTR %d, %d\n", a[0], a[1]);
				break;
			case 0xB5:
				output ("GEUSW\n");
				break;
			case 0xE7:
				output ("INC %d\n", B(fp));
				break;
			case 0xED:
				output ("INCI\n");
				break;
			case 0xE6:
				output ("IND %d\n", B(fp));
				break;
			case 0xDA:
				output ("INN\n");
				break;
			case 0xDC:
				output ("INT\n");
				break;
			case 0xD7:
				output ("IXA %d\n", B(fp));
				break;
			case 0xD8:
				a[0] = UB(fp);
				a[1] = UB(fp);
				output ("IXP %d, %d\n", a[0], a[1]);
				break;
			case 0x9B:
				a[0] = UB(fp);
				a[1] = B(fp);
				output ("LAE %d, %d\n", a[0], a[1]);
				break;
			case 0xA1:
				output ("LAND\n");
				break;
			case 0x86:
				output ("LAO %d\n", B(fp));
				break;
			case 0x82:
				output ("LCO %d\n", B(fp));
				break;
			case 0x88:
				a[0] = DB(fp);
				a[1] = B(fp);
				output ("LDA %d, %d\n", a[0], a[1]);
				break;
			case 0xA7:
				output ("LDB\n");
				break;
			case 0x83:
				a[0] = UB(fp);
				a[1] = B(fp);
				a[2] = UB(fp);
				output ("LDC %d, %d, %d\n", a[0], a[1], a[2]);
				break;
			case 0x80:
				output ("LDCB %d\n", UB(fp));
				break;
			case 0x81:
				output ("LDCI %d\n", W(fp));
				break;
			case 0x98:
				output ("LDCN\n");
				break;
			case 0xF2:
				output ("LDCRL %d\n", B(fp));
				break;
			case 0x9A:
				a[0] = UB(fp);
				a[1] = B(fp);
				output ("LDE %d, %d\n", a[0], a[1]);
				break;
			case 0x87:
				output ("LDL %d\n", B(fp));
				break;
			case 0xD0:
				output ("LDM %d\n", UB(fp));
				break;
			case 0x85:
				output ("LDO %d\n", B(fp));
				break;
			case 0xC9:
				output ("LDP\n");
				break;
			case 0xF3:
				output ("LDRL\n");
				break;
			case 0xBA:
				a[0] = UB(fp);
				a[1] = UB(fp);
				a[2] = B(fp);
				output ("LEBYT %d, %d, %d", a[0], a[1], a[2]);
				break;
			case 0xB7:
				output ("LEPWR\n");
				break;
			case 0xB2:
				output ("LEQI\n");
				break;
			case 0xCE:
				output ("LEREAL\n");
				break;
			case 0xE9:
				a[0] = UB(fp);
				a[1] = UB(fp);
				output ("LESTR %d, %d\n", a[0], a[1]);
				break;
			case 0xB4:
				output ("LEUSW\n");
				break;
			case 0x84:
				output ("LLA %d\n", B(fp));
				break;
			case 0xE5:
				output ("LNOT\n");
				break;
			case 0x89:
				a[0] = DB(fp);
				a[1] = B(fp);
				output ("LOD %d, %d\n", a[0], a[1]);
				break;
			case 0xA0:
				output ("LOR\n");
				break;
			case 0x9D:
				output ("LPR\n");
				break;
			case 0x99:
				output ("LSL %d\n", DB(fp));
				break;
			case 0x8F:
				output ("MODI\n");
				break;
			case 0xC5:
				a[0] = UB(fp);
				a[1] = B(fp);
				output ("MOV %d, %d\n", a[0], a[1]);
				break;
			case 0x8C:
				output ("MPI\n");
				break;
			case 0xC2:
				output ("MPR\n");
				break;
			case 0xA8:
				output ("NAT\n");
				break;
			case 0xA9:
				output ("NAT-INFO %d\n", B(fp));
				break;
			case 0xB1:
				output ("NEQI\n");
				break;
			case 0xD3:
				output ("NFJ %d\n", DB(fp));
				break;
			case 0xE1:
				output ("NGI\n");
				break;
			case 0xE4:
				output ("NGR\n");
				break;
			case 0x9C:
				output ("NOP\n");
				break;
			case 0xBF:
				output ("RND\n");
				break;
			case 0x96:
				output ("RPU %d\n", B(fp));
				break;
			case 0xA3:
				output ("SBI\n");
				break;
			case 0xC1:
				output ("SBR\n");
				break;
			case 0xEF:
			case 0xF0:
				output ("SCIP%d\n", c-0xEF);
				break;
			case 0xDE:
				output ("SIGNAL\n");
				break;
			case 0xAD:
			case 0xAE:
				output ("SLOD%d %d\n", c-0xAD, B(fp));
				break;
			case 0xD1:
				output ("SPR\n");
				break;
			case 0xA5:
				output ("SRO %d\n", B(fp));
				break;
			case 0xBC:
				output ("SRS\n");
				break;
			case 0xC8:
				output ("STB\n");
				break;
			case 0xD9:
				a[0] = UB(fp);
				a[1] = B(fp);
				output ("STE %d, %d\n", a[0], a[1]);
				break;
			case 0xA4:
				output ("STL %d\n", B(fp));
				break;
			case 0x8E:
				output ("STM %d\n", UB(fp));
				break;
			case 0xC4:
				output ("STO\n");
				break;
			case 0xCA:
				output ("STP\n");
				break;
			case 0xA6:
				a[0] = DB(fp);
				a[1] = B(fp);
				output ("STR %d, %d\n", a[0], a[1]);
				break;
			case 0xF4:
				output ("STRL\n");
				break;
			case 0xBD:
				output ("SWAP\n");
				break;
			case 0xF1:
				a[0] = SB(fp);
				output ("TJP %d (->%d)\n", a[0], ftell(fp)+a[0]);
				break;
			case 0xBE:
				output ("TNC\n");
				break;
			case 0x8A:
				a[0] = SB(fp);
				output ("UJP %d (->%d)\n", a[0], ftell(fp)+a[0]);
				break;
			case 0x8B:
				a[0] = W(fp);
				output ("UJPL %d (->%d)\n", a[0], ftell(fp)+a[0]);
				break;
			case 0xDB:
				output ("UNI\n");
				break;
			case 0xDF:
				output ("WAIT\n");
				break;
			case 0xD6:
				a[0] = B(fp);
				output ("XJP %d (->%d)\n", a[0], ftell(fp)+a[0]);
				break;
			}
		}
	}
	fclose(fp);
	printf ("\n");
}
