📄 pcode.c
字号:
/***************************************************************************
* PCODE.C - P-Code interpereter modeled after a Pascal version by Kin-Man *
* Chung and Herbert Yuen from their October 1978 BYTE article, *
* 'A "Tiny" Pascal Compiler - Part 1: The p_code Interpereter'. *
* History: *
* 19-DEC-92 First MSC version Ron Chernich *
* 23-DEC-92 Disassembler and help added arcy *
* 25-DEC-92 Debugger made more usefull for development arcy *
* 3-JAN-93 Default pcode file extension to ".PCD" arcy *
**************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define VERS 1.12
#define FALSE 0
#define TRUE 1
#define ULIM 15
#define BPLIM 5
#define SIZE 500
#define SIZE1 480
#define BUFSIZE 1024
typedef unsigned char BYTE;
typedef unsigned int BOOL;
enum opcodes
{LIT, OPR, LOD, STO, CAL, INT, JMP,
JPC, CSP, LODX = 0x12, STOX = 0x13, ILLEGAL_PCD};
enum operargs
{_RET, _NEG, _ADD, _SUB, _MUL, _DIV, _LOW, _MOD, _EQ,
_NE, _LT, _GE, _GT, _LE, _OR, _AND, _XOR, _NOT, _SHL,
_SHR, _INC, _DEC, _CPY, ILLEGAL_OPR_ARG};
enum cspargs
{CHIN, CHOUT, NUMIN, NUMOUT, HEXIN, HEXOUT, STROUT=8, ILLEGAL_CSP_ARG};
/****************
* Globals...
*/
BOOL bStop;
BYTE MEM[BUFSIZE];
int ip, bp, sp, nBreaks, ipx, TrPtr, nStep;
int Stack[SIZE], Trace[ULIM], Bpoints[BPLIM];
/*************
* Protos..
*/
int Base (int);
void Init (void);
void Exec (void);
void DeCode (int, int);
void CkBp (void);
int LoadPcode(char*);
void ShowHelp (void);
void Disemble (int);
void Debug (void);
void main (int, char**);
/************************************************************************
* Backs up the stack by the passed number of "levels"
* RETURNS: value at current stack - <nLev> levels
*/
int Base (int nLevs)
{
int nVal = bp;
while (nLevs--)
nVal = Stack[nVal];
return(nVal);
}
/************
* Initialize the P machine
*/
void Init (void)
{
int i;
TrPtr = ULIM;
bp = 1;
bStop = FALSE;
sp = ipx = ip = nStep = 0;
Stack[0] = Stack[1] = 0;
Stack[2] = -1;
for (i = 0; i < ULIM; i++)
Trace[i] = -1;
}
/******************
* Execute a P-Code
*/
void Exec (void)
{
BYTE *p;
int wParam, bParam, Func, idx;
p = MEM + (ip << 2);
bParam = *(p+1);
wParam = (*(p+3) << 8) + *(p+2);
if (++TrPtr >= ULIM)
TrPtr = 0;
Trace[TrPtr] = ip;
++ip;
ipx = ip;
++nStep;
Func = *p;
if (Func <= CSP)
idx = 0;
else {
idx = 1;
Func -= 0x10;
}
switch (Func) {
case LIT:
++sp;
Stack[sp] = wParam;
break;
case OPR:
switch (wParam) {
case _RET:
sp = bp - 1;
bp = Stack[sp+2];
ip = Stack[sp+3];
break;
case _NEG:
Stack[sp] = -Stack[sp];
break;
case _ADD:
--sp;
Stack[sp] += Stack[sp+1];
break;
case _SUB:
--sp;
Stack[sp] -= Stack[sp+1];
break;
case _MUL:
--sp;
Stack[sp] *= Stack[sp+1];
break;
case _DIV:
--sp;
Stack[sp] /= Stack[sp+1];
break;
case _LOW:
Stack[sp] &= 1;
break;
case _MOD:
--sp;
Stack[sp] %= Stack[sp+1];
break;
case _EQ:
--sp;
Stack[sp] = (Stack[sp] == Stack[sp+1]);
break;
case _NE:
--sp;
Stack[sp] = (Stack[sp] != Stack[sp+1]);
break;
case _LT:
--sp;
Stack[sp] = (Stack[sp] < Stack[sp+1]);
break;
case _GE:
--sp;
Stack[sp] = (Stack[sp] >= Stack[sp+1]);
break;
case _GT:
--sp;
Stack[sp] = (Stack[sp] > Stack[sp+1]);
break;
case _LE:
--sp;
Stack[sp] = (Stack[sp] <= Stack[sp+1]);
break;
case _OR:
--sp;
Stack[sp] |= Stack[sp+1];
break;
case _AND:
--sp;
Stack[sp] &= Stack[sp+1];
break;
case _XOR:
--sp;
Stack[sp] ^= Stack[sp+1];
break;
case _NOT:
Stack[sp] = ~Stack[sp];
break;
case _SHL:
--sp;
Stack[sp] <<= Stack[sp+1];
break;
case _SHR:
--sp;
Stack[sp] >>= Stack[sp+1];
break;
case _INC:
++Stack[sp];
break;
case _DEC:
--Stack[sp];
break;
case _CPY:
++sp;
Stack[sp] = Stack[sp-1];
break;
default:
fprintf(stdout, "Illegal Opr\n");
bStop = TRUE;
break;
}
break;
case LOD:
if (bParam == 255)
Stack[sp] = MEM[Stack[sp]];
else {
if (idx)
wParam = wParam + Stack[sp];
sp += (1 - idx);
Stack[sp] = Stack[Base(bParam)+wParam];
}
break;
case STO:
if (bParam == 255) {
MEM[Stack[sp-1]] = Stack[sp];
sp -= 2;
}
else {
if (idx)
wParam += Stack[sp-1];
Stack[Base(bParam)+wParam] = Stack[sp];
sp -= (idx + 1);
}
break;
case CAL:
if (bParam == 255) {
/*CAL(Stack[sp]);*/
--sp;
}
else {
Stack[sp+1] = Base(bParam);
Stack[sp+2] = bp;
Stack[sp+3] = ip;
bp = sp + 1;
ip = wParam;
}
break;
case INT:
if (sp < SIZE1 - wParam)
sp += wParam;
else {
fprintf(stdout, "Stack Overflow!\n");
bStop = TRUE;
}
break;
case JMP:
ip = wParam;
break;
case JPC:
if (Stack[sp] == (int)*(p+1))
ip = wParam;
--sp;
break;
case CSP:
switch (wParam) {
case 0:
++sp; /* read CHAR */
fscanf(stdin, "%c", &Stack[sp]);
break;
case 1:
fprintf(stdout, "%c", Stack[sp]); /* write CHAR */
--sp;
break;
case 2:
++sp; /* read NUMBER */
fscanf(stdin, "%d", &Stack[sp]);
break;
case 3:
fprintf(stdout, " %d", Stack[sp]); /* write NUMBER */
--sp;
break;
case 4:
++sp; /* read HEX */
fscanf(stdin, "%x", &Stack[sp]);
break;
case 5:
fprintf(stdout, " %X", Stack[sp]); /* write HEX */
--sp;
break;
case 8:
idx = sp - Stack[sp]; /* write STRING */
while (idx <= (sp - 1))
fprintf(stdout, "%c", Stack[idx++]);
sp -= (Stack[sp] + 1);
break;
default:
fprintf(stdout, "Illegal CSP\n");
bStop = TRUE;
break;
}
break;
default:
fprintf(stdout, "Illegal OPCODE\n");
bStop = TRUE;
break;
}
}
/******************
* Decode and display the opcode at the passed address and its args.
*/
void DeCode (int pc, int bNln)
{
BYTE *p;
int m, k, *pw;
unsigned int *pa;
char st[24], *str;
static char *stMn[] =
{"LIT ","OPR ","LOD ","STO ","CAL ","INT ","JMP ",
"JPC ","CSP ","LODX","STOX","????"};
static char *OPRarg[] =
{"RET", "NEG", "ADD", "SUB", "MUL",
"DIV", "LOW", "MOD", "EQ", "NE", "LT",
"GE", "GT", "LE", "OR", "AND", "XOR",
"NOT", "SHL", "SHR", "INC", "DEC", "CPY", "???"};
static char *CSParg[] =
{"INCH", "OUTCH", "INNM", "OUTNM", "INHX", "OUTHX",
"", "", "OUTST", "????"};
str = st + 14;
p = MEM + (pc << 2);
pw = (int*)(MEM + (pc << 2) + 2);
pa = (unsigned int*)(MEM + (pc << 2) + 2);
if ((*p >= LIT) && (*p <= CSP))
k = *p;
else if ((*p == LODX) || (*p == STOX))
k = *p - 9;
else
k = ILLEGAL_PCD;
sprintf(st, "%4d: %s %2X,", pc, stMn[k], *(p+1));
switch (k) {
case OPR:
m = (((*pa >= _RET) && (*pa <= _CPY)) ? *pw : ILLEGAL_OPR_ARG);
sprintf(str, "%s", OPRarg[m]);
break;
case CSP:
m = (((*pa == STROUT) || ((*pa >= CHIN) && (*pa <= HEXOUT))) ? *pw :
ILLEGAL_CSP_ARG);
sprintf(str, "%s", CSParg[m]);
break;
default:
if ((k == LIT) && (*pw > 0))
sprintf(str, "0x%02X ", *pw);
else
sprintf(str, "%2d", *pw);
break;
}
if (bNln)
fprintf(stdout, "%s\n", st);
else {
while (strlen(st) < 20)
strcat(st, " ");
fprintf(stdout, st);
}
}
/***********************
* Look for a Break point at the current <ip> address
*/
void CkBp (void)
{
int i;
if (ip < 0)
bStop = TRUE;
else
for (i = 0; i < nBreaks; i++)
if (Bpoints[i] == ip) {
fprintf(stdout, "\nBreak at %d!\n", ip);
bStop = TRUE;
break;
}
}
/************
* load some p-codes (hopefully) from the passed file. If no extension
* given, default it to ".PCD"
*/
int LoadPcode(char *st)
{
FILE *fp;
char *cp;
int cnt = 0;
if ((strrchr(st, '.') == NULL) ||
(((cp = strrchr(st, '.')) != NULL) && (strchr(cp, '\\') == NULL)))
strcat(st, ".PCD");
if (fp = fopen(st, "r")) {
cnt = fread(MEM, sizeof(BYTE), BUFSIZE, fp);
fclose(fp);
}
return(cnt);
}
/**********
* available commands..
*/
void ShowHelp (void)
{
int i;
static char *stHelp[] =
{"Commands:","G: Go (resume)","S: Single Step",
"R: Reset","B: Set break-point","C: Clear all break-points",
"Y: Display break-points","X: Examine status","K: Show stack",
"L: List p-codes", "T: Trace back", "E: Examine memory",
"U: Backup PC", "N: Increment PC","Q: Quit program",
"?: Display help (this!)",
" ", NULL};
for (i = 0; stHelp[i]; i++)
fprintf(stdout, ((i) ? " %s\n" : "%s\n"), stHelp[i]);
}
/**********
* disassemble to standard out, 4 pcodes per line..
*/
void Disemble(int cnt)
{
int n = 0;
while (n < cnt)
if ((n+1)%4)
DeCode(n++, FALSE);
else
DeCode(n++, TRUE);
}
/*********
* The simple (VERY) interactive p-code debugger..
*/
void Debug (void)
{
int i, j, k = 0;
char st[32], Cmd, *cp;
ShowHelp();
nBreaks = 0;
DeCode(ip, TRUE);
while (ip >= 0) {
fprintf(stdout, ">");
fflush(stdin);
fgets(st, 32, stdin);
if (islower(*st))
Cmd = toupper(st[0]);
else
Cmd = st[0];
cp = st+1;
while (*cp && (*cp == ' '))
++cp;
strcpy(st, cp);
if (cp = strchr(st, '\n'))
*cp = '\0';
switch (Cmd) {
case 'G': bStop = FALSE;
while (!bStop) {
if (bp < 0) {
bStop = TRUE;
fprintf(stderr, "\nHalt!\n");
}
else {
Exec();
CkBp();
}
}
break;
case 'S': Exec(); /* note fall-thru to show pcode and regs */
case 'X': DeCode(ip, TRUE);
fprintf(stdout, " IP = %04d SP = %04d BP = %d", ip,sp,bp);
fprintf(stdout, " Stack[sp] = %04d Stack[sp-1] = %04d\n",
Stack[sp], Stack[sp-1]);
break;
case 'R': Init();
break;
case 'T': fprintf(stdout, "* TRACE *\n");
for (i = 0; i < ULIM; i++) {
if (++TrPtr >= ULIM)
TrPtr = 0;
if (Trace[TrPtr] >= 0)
DeCode(Trace[TrPtr], TRUE);
}
break;
case 'K': if (!isdigit(*st)) {
fprintf(stderr, "Stack offset? ");
fgets(st, 16, stdin);
if (cp = strchr(st, '\n'))
*cp = '\0';
}
i = ((strlen(st)) ? atoi(st) : sp+4);
if (_toupper(st[1]) == 'P')
if (_toupper(*st) == 'S')
i = sp;
else if (_toupper(*st) == 'B')
i = bp;
if (i == 0)
i = sp+8;
if ((j = i-16) < 0)
j = 0;
while (i >= j) {
if (i == sp)
fprintf(stderr, "%04d: %4d <-- sp\n", i, Stack[i]);
else if (i == bp)
fprintf(stderr, "%04d: %4d <-- bp\n", i, Stack[i]);
else
fprintf(stderr, "%04d: %4d\n", i, Stack[i]);
--i;
}
break;
case 'L': if (!isdigit(*st)) {
fprintf(stderr, "IP offset? ");
fgets(st, 16, stdin);
if (cp = strchr(st, '\n'))
*cp = '\0';
}
if (strlen(st) == 0)
i = k;
else
if ((_toupper(st[0]) == 'I') && (_toupper(st[1]) == 'P'))
i = ip;
else
i = atoi(st);
for (j = i; j < i + 16; j++)
if (j != ip)
DeCode(j, TRUE);
else {
DeCode(j, FALSE);
fprintf(stderr, " <-- ip\n");
}
k = j;
break;
case 'B': if (nBreaks < BPLIM) {
if (isdigit(*st)) {
Bpoints[nBreaks] = atoi(st);
fprintf(stderr, "%d: %d\n", nBreaks+1, Bpoints[nBreaks]);
}
else {
fprintf(stdout, "%d: ", nBreaks+1);
fscanf(stdin, "%d", &Bpoints[nBreaks]);
}
++nBreaks;
}
break;
case 'C': nBreaks = 0;
fprintf(stdout, "\n");
break;
case 'Y': for (i = 0; i < nBreaks; i++)
fprintf(stdout, "%d: %4d\n", i+1, Bpoints[i]);
break;
case 'E': if (!isdigit(*st)) {
fprintf(stderr, "PC? ");
fgets(st, 16, stdin);
if (cp = strchr(st, '\n'))
*cp = '\0';
}
ipx = atoi(st);
DeCode(ipx, TRUE);
break;
case 'U': if (ipx > 0) {
--ipx;
DeCode(ipx, TRUE);
}
break;
case 'N': ++ipx;
DeCode(ipx, TRUE);
break;
case 'Q': ip = -1;
break;
case '?': ShowHelp();
break;
default: fprintf(stdout, "??\n");
break;
}
}
fprintf(stdout, "%d instructions executed\n", nStep);
}
/****************************
* Main P-Code Intwerpreter..
*/
void main (int argc, char **argv)
{
int Pcnt = 0;
int bDump, bMonitor;
fprintf(stdout, "\nP-Code Intwerpreter V%.2f\n\n", VERS);
bDump = bMonitor = FALSE;
if (argc == 1)
fprintf(stdout, "Usage:\n pcode [-d|m] <filename>\n");
while (--argc)
if (*argv[argc] != '-')
Pcnt = LoadPcode(argv[1]);
else {
if ((argv[argc][1] == 'd') || (argv[argc][1] == 'D'))
bDump = TRUE;
if ((argv[argc][1] == 'm') || (argv[argc][1] == 'M'))
bMonitor = TRUE;
}
if (Pcnt == 0)
fprintf(stderr, "File not found, or empty!\n");
else {
Init();
if (bDump)
Disemble(Pcnt >> 2);
if (bMonitor)
Debug();
if (!(bDump || bMonitor))
while (bp >= 0)
Exec();
}
}
/********************************* EOF *********************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -