mirror of
https://github.com/bobbimanners/EightBall.git
synced 2024-09-27 13:56:07 +00:00
v0.75: performance improvements to VM (especially for Apple II)
This commit is contained in:
parent
e3f5558b00
commit
da7dea8906
9
Makefile
9
Makefile
@ -114,9 +114,12 @@ eightball_a2e.o: eightball.c eightballutils.h eightballvm.h
|
|||||||
$(CC65BINDIR)/ca65 -t apple2enh eightball_a2e.s
|
$(CC65BINDIR)/ca65 -t apple2enh eightball_a2e.s
|
||||||
|
|
||||||
eightballvm_a2e.o: eightballvm.c eightballutils.h eightballvm.h
|
eightballvm_a2e.o: eightballvm.c eightballutils.h eightballvm.h
|
||||||
$(CC65BINDIR)/cc65 -Or -t apple2enh -D A2E -o eightballvm_a2e.s eightballvm.c
|
$(CC65BINDIR)/cc65 -r -Oirs -t apple2enh -D A2E -o eightballvm_a2e.s eightballvm.c
|
||||||
$(CC65BINDIR)/ca65 -t apple2enh eightballvm_a2e.s
|
$(CC65BINDIR)/ca65 -t apple2enh eightballvm_a2e.s
|
||||||
|
|
||||||
|
eightballvmzp_a2e.o: eightballvmzp_a2e.S
|
||||||
|
$(CC65BINDIR)/ca65 -t apple2enh eightballvmzp_a2e.S
|
||||||
|
|
||||||
disass_a2e.o: disass.c eightballutils.h eightballvm.h
|
disass_a2e.o: disass.c eightballutils.h eightballvm.h
|
||||||
$(CC65BINDIR)/cc65 -Or -t apple2enh -D A2E -o disass_a2e.s disass.c
|
$(CC65BINDIR)/cc65 -Or -t apple2enh -D A2E -o disass_a2e.s disass.c
|
||||||
$(CC65BINDIR)/ca65 -t apple2enh disass_a2e.s
|
$(CC65BINDIR)/ca65 -t apple2enh disass_a2e.s
|
||||||
@ -128,8 +131,8 @@ eightballutils_a2e.o: eightballutils.c eightballutils.h
|
|||||||
bin/eb: eightball_a2e.o eightballutils_a2e.o
|
bin/eb: eightball_a2e.o eightballutils_a2e.o
|
||||||
$(CC65BINDIR)/ld65 -m 8balla2e.map -o bin/eb -C apple2enh.cfg -D __HIMEM__=0xbf00 eightball_a2e.o eightballutils_a2e.o $(CC65LIBDIR)/apple2enh.lib
|
$(CC65BINDIR)/ld65 -m 8balla2e.map -o bin/eb -C apple2enh.cfg -D __HIMEM__=0xbf00 eightball_a2e.o eightballutils_a2e.o $(CC65LIBDIR)/apple2enh.lib
|
||||||
|
|
||||||
bin/ebvm: eightballvm_a2e.o eightballutils_a2e.o
|
bin/ebvm: eightballvm_a2e.o eightballutils_a2e.o eightballvmzp_a2e.o
|
||||||
$(CC65BINDIR)/ld65 -m 8ballvma2e.map -o bin/ebvm -C apple2enh.cfg -D __HIMEM__=0xbf00 eightballvm_a2e.o eightballutils_a2e.o $(CC65LIBDIR)/apple2enh.lib
|
$(CC65BINDIR)/ld65 -m 8ballvma2e.map -o bin/ebvm -C apple2enh.cfg -D __HIMEM__=0xbf00 eightballvm_a2e.o eightballutils_a2e.o eightballvmzp_a2e.o $(CC65LIBDIR)/apple2enh.lib
|
||||||
|
|
||||||
bin/ebdiss: disass_a2e.o eightballutils_a2e.o
|
bin/ebdiss: disass_a2e.o eightballutils_a2e.o
|
||||||
$(CC65BINDIR)/ld65 -m disassa2e.map -o bin/ebdiss -C apple2enh.cfg -D __HIMEM__=0xbf00 disass_a2e.o eightballutils_a2e.o $(CC65LIBDIR)/apple2enh.lib
|
$(CC65BINDIR)/ld65 -m disassa2e.map -o bin/ebdiss -C apple2enh.cfg -D __HIMEM__=0xbf00 disass_a2e.o eightballutils_a2e.o $(CC65LIBDIR)/apple2enh.lib
|
||||||
|
BIN
bin/8ball20.prg
BIN
bin/8ball20.prg
Binary file not shown.
BIN
bin/8ball64.prg
BIN
bin/8ball64.prg
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
bin/disass
BIN
bin/disass
Binary file not shown.
BIN
bin/disass20.prg
BIN
bin/disass20.prg
Binary file not shown.
BIN
bin/disass64.prg
BIN
bin/disass64.prg
Binary file not shown.
BIN
bin/eightball
BIN
bin/eightball
Binary file not shown.
BIN
bin/eightballvm
BIN
bin/eightballvm
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -37,7 +37,7 @@
|
|||||||
/* */
|
/* */
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
|
|
||||||
#define VERSIONSTR "0.74"
|
#define VERSIONSTR "0.76"
|
||||||
|
|
||||||
void print(char *str);
|
void print(char *str);
|
||||||
|
|
||||||
|
267
eightballvm.c
267
eightballvm.c
@ -88,29 +88,62 @@
|
|||||||
#define UINT16 unsigned short
|
#define UINT16 unsigned short
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
UINT16 pc = RTPCSTART; /* Program counter */
|
#ifndef A2E
|
||||||
UINT16 sp = RTCALLSTACKTOP; /* Stack pointer */
|
|
||||||
UINT16 fp = RTCALLSTACKTOP; /* Frame pointer */
|
|
||||||
|
|
||||||
/* Evaluation stack - 16 bit ints. Addressed by evalptr */
|
unsigned char evalptr; /* Points to the empty slot above top of eval stack */
|
||||||
UINT16 evalstack[EVALSTACKSZ];
|
UINT16 pc; /* Program counter */
|
||||||
|
UINT16 sp; /* Stack pointer */
|
||||||
|
UINT16 fp; /* Frame pointer */
|
||||||
|
unsigned short *wordptr; /* Temp used in execute() */
|
||||||
|
unsigned char *byteptr; /* Temp used in execute() */
|
||||||
|
UINT16 evalstack[EVALSTACKSZ]; /* Evaluation stack - 16 bit ints. Addressed by evalptr */
|
||||||
|
|
||||||
/* evalptr points to the empty slot above the top of the evaluation stack */
|
#else
|
||||||
unsigned char evalptr = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* System memory - addressed in bytes.
|
* Zero page variables used on Apple II only at present
|
||||||
* Used for program storage. Addressed by pc.
|
*/
|
||||||
* - Programs are stored from address 0 upwards.
|
|
||||||
* Used for callstack. Addressed by sp.
|
extern unsigned char evalptr;
|
||||||
* - Callstack grows down from top of memory.
|
extern UINT16 pc;
|
||||||
*/
|
extern UINT16 sp;
|
||||||
|
extern UINT16 fp;
|
||||||
|
extern unsigned short *wordptr;
|
||||||
|
extern unsigned char *byteptr;
|
||||||
|
extern UINT16 evalstack[EVALSTACKSZ];
|
||||||
|
|
||||||
|
#pragma zpsym ("evalptr");
|
||||||
|
#pragma zpsym ("pc");
|
||||||
|
#pragma zpsym ("sp");
|
||||||
|
#pragma zpsym ("fp");
|
||||||
|
#pragma zpsym ("wordptr");
|
||||||
|
#pragma zpsym ("byteptr");
|
||||||
|
#pragma zpsym ("evalstack");
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* System memory - addressed in bytes.
|
||||||
|
* Used for program storage. Addressed by pc.
|
||||||
|
* - Programs are stored from address 0 upwards.
|
||||||
|
* Used for callstack. Addressed by sp.
|
||||||
|
* - Callstack grows down from top of memory.
|
||||||
|
*/
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
unsigned char memory[MEMORYSZ];
|
unsigned char memory[MEMORYSZ];
|
||||||
#else
|
#else
|
||||||
unsigned char *memory = 0;
|
unsigned char *memory = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macro to ensure efficient code generation on cc65 when accessing memory
|
||||||
|
*/
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define MEM(x) memory[x]
|
||||||
|
#else
|
||||||
|
#define MEM(x) (*(unsigned char*)x)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define XREG evalstack[evalptr - 1] /* Only valid if evalptr >= 1 */
|
#define XREG evalstack[evalptr - 1] /* Only valid if evalptr >= 1 */
|
||||||
#define YREG evalstack[evalptr - 2] /* Only valid if evalptr >= 2 */
|
#define YREG evalstack[evalptr - 2] /* Only valid if evalptr >= 2 */
|
||||||
#define ZREG evalstack[evalptr - 3] /* Only valid if evalptr >= 3 */
|
#define ZREG evalstack[evalptr - 3] /* Only valid if evalptr >= 3 */
|
||||||
@ -213,7 +246,7 @@ void checkstackoverflow()
|
|||||||
void unsupported()
|
void unsupported()
|
||||||
{
|
{
|
||||||
print("Unsupported instruction ");
|
print("Unsupported instruction ");
|
||||||
printhexbyte(memory[pc]);
|
printhexbyte(MEM(pc));
|
||||||
print("\nPC=");
|
print("\nPC=");
|
||||||
printhex(pc);
|
printhex(pc);
|
||||||
printchar('\n');
|
printchar('\n');
|
||||||
@ -221,20 +254,26 @@ void unsupported()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fetch, decode and execute a VM instruction, then advance the program counter.
|
* Fetch, decode and execute a VM instruction.
|
||||||
|
* Advance program counter and loop until VM_END.
|
||||||
*/
|
*/
|
||||||
void execute_instruction()
|
void execute()
|
||||||
{
|
{
|
||||||
unsigned short tempword;
|
unsigned short d;
|
||||||
unsigned short *wordptr;
|
#ifdef DEBUGREGS
|
||||||
unsigned char *byteptr;
|
unsigned short i;
|
||||||
#ifndef __GNUC__
|
|
||||||
unsigned short delay;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
evalptr = 0;
|
||||||
|
pc = RTPCSTART;
|
||||||
|
sp = fp = RTCALLSTACKTOP;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
nextinstr:
|
||||||
|
|
||||||
//print("--->PC "); printhex(pc); print(" eval stk: "); printhex(evalptr); print("\n");
|
//print("--->PC "); printhex(pc); print(" eval stk: "); printhex(evalptr); print("\n");
|
||||||
#ifdef DEBUGREGS
|
#ifdef DEBUGREGS
|
||||||
unsigned short i;
|
|
||||||
print("\n");
|
print("\n");
|
||||||
print("--->PC ");
|
print("--->PC ");
|
||||||
printhex(pc);
|
printhex(pc);
|
||||||
@ -247,7 +286,7 @@ void execute_instruction()
|
|||||||
print("\n");
|
print("\n");
|
||||||
print("Call Stk: ");
|
print("Call Stk: ");
|
||||||
for (i = sp + 1; i <= RTCALLSTACKTOP; ++i) {
|
for (i = sp + 1; i <= RTCALLSTACKTOP; ++i) {
|
||||||
printhexbyte(memory[i]);
|
printhexbyte(MEM(i));
|
||||||
printchar(' ');
|
printchar(' ');
|
||||||
}
|
}
|
||||||
print("\nEval Stk: ");
|
print("\nEval Stk: ");
|
||||||
@ -269,22 +308,22 @@ void execute_instruction()
|
|||||||
#endif
|
#endif
|
||||||
printhex(pc);
|
printhex(pc);
|
||||||
print(": ");
|
print(": ");
|
||||||
print(bytecodenames[memory[pc]]);
|
print(bytecodenames[MEM(pc)]);
|
||||||
/* TODO: Should encode immediate mode as one bit of opcode to make this more efficient */
|
/* TODO: Should encode immediate mode as one bit of opcode to make this more efficient */
|
||||||
if ((memory[pc] == VM_LDIMM) ||
|
if ((MEM(pc) == VM_LDIMM) ||
|
||||||
(memory[pc] == VM_LDAWORDIMM) ||
|
(MEM(pc) == VM_LDAWORDIMM) ||
|
||||||
(memory[pc] == VM_LDABYTEIMM) ||
|
(MEM(pc) == VM_LDABYTEIMM) ||
|
||||||
(memory[pc] == VM_LDRWORDIMM) ||
|
(MEM(pc) == VM_LDRWORDIMM) ||
|
||||||
(memory[pc] == VM_LDRBYTEIMM) ||
|
(MEM(pc) == VM_LDRBYTEIMM) ||
|
||||||
(memory[pc] == VM_STAWORDIMM) ||
|
(MEM(pc) == VM_STAWORDIMM) ||
|
||||||
(memory[pc] == VM_STABYTEIMM) ||
|
(MEM(pc) == VM_STABYTEIMM) ||
|
||||||
(memory[pc] == VM_STRWORDIMM) ||
|
(MEM(pc) == VM_STRWORDIMM) ||
|
||||||
(memory[pc] == VM_STRBYTEIMM) ||
|
(MEM(pc) == VM_STRBYTEIMM) ||
|
||||||
(memory[pc] == VM_JMPIMM) ||
|
(MEM(pc) == VM_JMPIMM) ||
|
||||||
(memory[pc] == VM_BRNCHIMM) ||
|
(MEM(pc) == VM_BRNCHIMM) ||
|
||||||
(memory[pc] == VM_JSRIMM)) {
|
(MEM(pc) == VM_JSRIMM)) {
|
||||||
printchar(' ');
|
printchar(' ');
|
||||||
wordptr = (unsigned short *)&memory[pc + 1];
|
wordptr = (unsigned short *)&MEM(pc + 1);
|
||||||
printhex(*wordptr);
|
printhex(*wordptr);
|
||||||
printchar(' ');
|
printchar(' ');
|
||||||
} else {
|
} else {
|
||||||
@ -317,7 +356,7 @@ void execute_instruction()
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (memory[pc]) {
|
switch (MEM(pc)) {
|
||||||
/*
|
/*
|
||||||
* Miscellaneous
|
* Miscellaneous
|
||||||
*/
|
*/
|
||||||
@ -330,7 +369,7 @@ void execute_instruction()
|
|||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
exit(0);
|
exit(0);
|
||||||
#else
|
#else
|
||||||
for (delay = 0; delay < 25000; ++delay);
|
for (d = 0; d < 25000; ++d);
|
||||||
exit(0);
|
exit(0);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
@ -341,7 +380,7 @@ void execute_instruction()
|
|||||||
case VM_LDIMM: /* Pushes the following 16 bit word to the evaluation stack */
|
case VM_LDIMM: /* Pushes the following 16 bit word to the evaluation stack */
|
||||||
++evalptr;
|
++evalptr;
|
||||||
CHECKOVERFLOW();
|
CHECKOVERFLOW();
|
||||||
wordptr = (unsigned short *)&memory[++pc];
|
wordptr = (unsigned short *)&MEM(++pc);
|
||||||
++pc;
|
++pc;
|
||||||
XREG = *wordptr;
|
XREG = *wordptr;
|
||||||
break;
|
break;
|
||||||
@ -358,52 +397,52 @@ void execute_instruction()
|
|||||||
printchar('\n');
|
printchar('\n');
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
wordptr = (unsigned short *)&memory[XREG];
|
wordptr = (unsigned short *)&MEM(XREG);
|
||||||
XREG = *wordptr;
|
XREG = *wordptr;
|
||||||
break;
|
break;
|
||||||
case VM_LDAWORDIMM: /* Imm mode - push 16 bit value pointed to by addr after opcode */
|
case VM_LDAWORDIMM: /* Imm mode - push 16 bit value pointed to by addr after opcode */
|
||||||
++evalptr;
|
++evalptr;
|
||||||
CHECKOVERFLOW();
|
CHECKOVERFLOW();
|
||||||
wordptr = (unsigned short *)&memory[++pc]; /* Pointer to operand */
|
wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */
|
||||||
wordptr = (unsigned short *)&memory[*wordptr]; /* Pointer to variable */
|
wordptr = (unsigned short *)&MEM(*wordptr); /* Pointer to variable */
|
||||||
++pc;
|
++pc;
|
||||||
XREG = *wordptr;
|
XREG = *wordptr;
|
||||||
break;
|
break;
|
||||||
case VM_LDABYTE: /* Replaces X with 8 bit value pointed to by X. */
|
case VM_LDABYTE: /* Replaces X with 8 bit value pointed to by X. */
|
||||||
CHECKUNDERFLOW(1);
|
CHECKUNDERFLOW(1);
|
||||||
XREG = memory[XREG];
|
XREG = MEM(XREG);
|
||||||
break;
|
break;
|
||||||
case VM_LDABYTEIMM: /* Imm mode - push byte pointed to by addr after opcode */
|
case VM_LDABYTEIMM: /* Imm mode - push byte pointed to by addr after opcode */
|
||||||
++evalptr;
|
++evalptr;
|
||||||
CHECKOVERFLOW();
|
CHECKOVERFLOW();
|
||||||
wordptr = (unsigned short *)&memory[++pc]; /* Pointer to operand */
|
wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */
|
||||||
byteptr = (unsigned char *)&memory[*wordptr]; /* Pointer to variable */
|
byteptr = (unsigned char *)&MEM(*wordptr); /* Pointer to variable */
|
||||||
++pc;
|
++pc;
|
||||||
XREG = *byteptr;
|
XREG = *byteptr;
|
||||||
break;
|
break;
|
||||||
case VM_STAWORD: /* Stores 16 bit value Y in addr pointed to by X. Drops X and Y.*/
|
case VM_STAWORD: /* Stores 16 bit value Y in addr pointed to by X. Drops X and Y.*/
|
||||||
CHECKUNDERFLOW(2);
|
CHECKUNDERFLOW(2);
|
||||||
wordptr = (unsigned short *)&memory[XREG];
|
wordptr = (unsigned short *)&MEM(XREG);
|
||||||
*wordptr = YREG;
|
*wordptr = YREG;
|
||||||
evalptr -= 2;
|
evalptr -= 2;
|
||||||
break;
|
break;
|
||||||
case VM_STAWORDIMM: /* Imm mode - store 16 bit value X in addr after opcode. Drop X.*/
|
case VM_STAWORDIMM: /* Imm mode - store 16 bit value X in addr after opcode. Drop X.*/
|
||||||
CHECKUNDERFLOW(1);
|
CHECKUNDERFLOW(1);
|
||||||
wordptr = (unsigned short *)&memory[++pc]; /* Pointer to operand */
|
wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */
|
||||||
wordptr = (unsigned short *)&memory[*wordptr]; /* Pointer to variable */
|
wordptr = (unsigned short *)&MEM(*wordptr); /* Pointer to variable */
|
||||||
++pc;
|
++pc;
|
||||||
*wordptr = XREG;
|
*wordptr = XREG;
|
||||||
--evalptr;
|
--evalptr;
|
||||||
break;
|
break;
|
||||||
case VM_STABYTE: /* Stores 8 bit value Y in addr pointed to by X. Drops X and Y. */
|
case VM_STABYTE: /* Stores 8 bit value Y in addr pointed to by X. Drops X and Y. */
|
||||||
CHECKUNDERFLOW(2);
|
CHECKUNDERFLOW(2);
|
||||||
memory[XREG] = YREG;
|
MEM(XREG) = YREG;
|
||||||
evalptr -= 2;
|
evalptr -= 2;
|
||||||
break;
|
break;
|
||||||
case VM_STABYTEIMM: /* Imm mode - store 8 bit value X in addr after opcode. Drop X.*/
|
case VM_STABYTEIMM: /* Imm mode - store 8 bit value X in addr after opcode. Drop X.*/
|
||||||
CHECKUNDERFLOW(1);
|
CHECKUNDERFLOW(1);
|
||||||
wordptr = (unsigned short *)&memory[++pc]; /* Pointer to operand */
|
wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */
|
||||||
byteptr = (unsigned char *)&memory[*wordptr]; /* Pointer to variable */
|
byteptr = (unsigned char *)&MEM(*wordptr); /* Pointer to variable */
|
||||||
++pc;
|
++pc;
|
||||||
*byteptr = XREG;
|
*byteptr = XREG;
|
||||||
--evalptr;
|
--evalptr;
|
||||||
@ -425,14 +464,22 @@ void execute_instruction()
|
|||||||
printchar('\n');
|
printchar('\n');
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
wordptr = (unsigned short *)&memory[(XREG + fp + 1) & 0xffff];
|
wordptr = (unsigned short *)&memory[(XREG + fp + 1) & 0xffff];
|
||||||
|
#else
|
||||||
|
wordptr = (unsigned short *)&memory[XREG + fp + 1];
|
||||||
|
#endif
|
||||||
XREG = *wordptr;
|
XREG = *wordptr;
|
||||||
break;
|
break;
|
||||||
case VM_LDRWORDIMM: /* Imm mode - push 16 bit value pointed to by addr after opcode */
|
case VM_LDRWORDIMM: /* Imm mode - push 16 bit value pointed to by addr after opcode */
|
||||||
++evalptr;
|
++evalptr;
|
||||||
CHECKOVERFLOW();
|
CHECKOVERFLOW();
|
||||||
wordptr = (unsigned short *)&memory[++pc]; /* Pointer to operand */
|
wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */
|
||||||
|
#ifdef __GNUC__
|
||||||
wordptr = (unsigned short *)&memory[(*wordptr + fp + 1) & 0xffff]; /* Pointer to variable */
|
wordptr = (unsigned short *)&memory[(*wordptr + fp + 1) & 0xffff]; /* Pointer to variable */
|
||||||
|
#else
|
||||||
|
wordptr = (unsigned short *)&memory[*wordptr + fp + 1]; /* Pointer to variable */
|
||||||
|
#endif
|
||||||
++pc;
|
++pc;
|
||||||
XREG = *wordptr;
|
XREG = *wordptr;
|
||||||
break;
|
break;
|
||||||
@ -449,39 +496,63 @@ void execute_instruction()
|
|||||||
printchar('\n');
|
printchar('\n');
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
XREG = memory[(XREG + fp + 1) & 0xffff];
|
#ifdef __GNUC__
|
||||||
|
XREG = MEM((XREG + fp + 1) & 0xffff);
|
||||||
|
#else
|
||||||
|
XREG = MEM(XREG + fp + 1);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case VM_LDRBYTEIMM: /* Imm mode - push byte pointed to by addr after opcode */
|
case VM_LDRBYTEIMM: /* Imm mode - push byte pointed to by addr after opcode */
|
||||||
++evalptr;
|
++evalptr;
|
||||||
CHECKOVERFLOW();
|
CHECKOVERFLOW();
|
||||||
wordptr = (unsigned short *)&memory[++pc]; /* Pointer to operand */
|
wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */
|
||||||
|
#ifdef __GNUC__
|
||||||
byteptr = (unsigned char *)&memory[(*wordptr + fp + 1) & 0xffff]; /* Pointer to variable */
|
byteptr = (unsigned char *)&memory[(*wordptr + fp + 1) & 0xffff]; /* Pointer to variable */
|
||||||
|
#else
|
||||||
|
byteptr = (unsigned char *)&memory[*wordptr + fp + 1]; /* Pointer to variable */
|
||||||
|
#endif
|
||||||
++pc;
|
++pc;
|
||||||
XREG = *byteptr;
|
XREG = *byteptr;
|
||||||
break;
|
break;
|
||||||
case VM_STRWORD: /* Stores 16 bit value Y in addr pointed to by X. Drops X and Y. */
|
case VM_STRWORD: /* Stores 16 bit value Y in addr pointed to by X. Drops X and Y. */
|
||||||
CHECKUNDERFLOW(2);
|
CHECKUNDERFLOW(2);
|
||||||
|
#ifdef __GNUC__
|
||||||
wordptr = (unsigned short *)&memory[(XREG + fp + 1) & 0xffff];
|
wordptr = (unsigned short *)&memory[(XREG + fp + 1) & 0xffff];
|
||||||
|
#else
|
||||||
|
wordptr = (unsigned short *)&memory[XREG + fp + 1];
|
||||||
|
#endif
|
||||||
*wordptr = YREG;
|
*wordptr = YREG;
|
||||||
evalptr -= 2;
|
evalptr -= 2;
|
||||||
break;
|
break;
|
||||||
case VM_STRWORDIMM: /* Imm mode - store 16 bit value X in addr after opcode. Drop X.*/
|
case VM_STRWORDIMM: /* Imm mode - store 16 bit value X in addr after opcode. Drop X.*/
|
||||||
CHECKUNDERFLOW(1);
|
CHECKUNDERFLOW(1);
|
||||||
wordptr = (unsigned short *)&memory[++pc]; /* Pointer to operand */
|
wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */
|
||||||
|
#ifdef __GNUC__
|
||||||
wordptr = (unsigned short *)&memory[(*wordptr + fp + 1) & 0xffff]; /* Pointer to variable */
|
wordptr = (unsigned short *)&memory[(*wordptr + fp + 1) & 0xffff]; /* Pointer to variable */
|
||||||
|
#else
|
||||||
|
wordptr = (unsigned short *)&memory[*wordptr + fp + 1]; /* Pointer to variable */
|
||||||
|
#endif
|
||||||
++pc;
|
++pc;
|
||||||
*wordptr = XREG;
|
*wordptr = XREG;
|
||||||
--evalptr;
|
--evalptr;
|
||||||
break;
|
break;
|
||||||
case VM_STRBYTE: /* Stores 8 bit value Y in addr pointed to by X. Drops X and Y. */
|
case VM_STRBYTE: /* Stores 8 bit value Y in addr pointed to by X. Drops X and Y. */
|
||||||
CHECKUNDERFLOW(2);
|
CHECKUNDERFLOW(2);
|
||||||
|
#ifdef __GNUC__
|
||||||
memory[(XREG + fp + 1) & 0xffff] = YREG;
|
memory[(XREG + fp + 1) & 0xffff] = YREG;
|
||||||
|
#else
|
||||||
|
memory[XREG + fp + 1] = YREG;
|
||||||
|
#endif
|
||||||
evalptr -= 2;
|
evalptr -= 2;
|
||||||
break;
|
break;
|
||||||
case VM_STRBYTEIMM: /* Imm mode - store 8 bit value X in addr after opcode. Drop X.*/
|
case VM_STRBYTEIMM: /* Imm mode - store 8 bit value X in addr after opcode. Drop X.*/
|
||||||
CHECKUNDERFLOW(1);
|
CHECKUNDERFLOW(1);
|
||||||
wordptr = (unsigned short *)&memory[++pc]; /* Pointer to operand */
|
wordptr = (unsigned short *)&MEM(++pc); /* Pointer to operand */
|
||||||
|
#ifdef __GNUC__
|
||||||
byteptr = (unsigned char *)&memory[(*wordptr + fp + 1) & 0xffff]; /* Pointer to variable */
|
byteptr = (unsigned char *)&memory[(*wordptr + fp + 1) & 0xffff]; /* Pointer to variable */
|
||||||
|
#else
|
||||||
|
byteptr = (unsigned char *)&memory[*wordptr + fp + 1]; /* Pointer to variable */
|
||||||
|
#endif
|
||||||
++pc;
|
++pc;
|
||||||
*byteptr = XREG;
|
*byteptr = XREG;
|
||||||
--evalptr;
|
--evalptr;
|
||||||
@ -491,9 +562,9 @@ void execute_instruction()
|
|||||||
*/
|
*/
|
||||||
case VM_SWAP: /* Swaps X and Y */
|
case VM_SWAP: /* Swaps X and Y */
|
||||||
CHECKUNDERFLOW(2);
|
CHECKUNDERFLOW(2);
|
||||||
tempword = XREG;
|
d = XREG;
|
||||||
XREG = YREG;
|
XREG = YREG;
|
||||||
YREG = tempword;
|
YREG = d;
|
||||||
break;
|
break;
|
||||||
case VM_DUP: /* Duplicates X -> X, Y */
|
case VM_DUP: /* Duplicates X -> X, Y */
|
||||||
CHECKUNDERFLOW(1);
|
CHECKUNDERFLOW(1);
|
||||||
@ -538,7 +609,7 @@ void execute_instruction()
|
|||||||
++sp;
|
++sp;
|
||||||
++evalptr;
|
++evalptr;
|
||||||
CHECKOVERFLOW();
|
CHECKOVERFLOW();
|
||||||
XREG = memory[sp];
|
XREG = MEM(sp);
|
||||||
break;
|
break;
|
||||||
case VM_PSHWORD: /* Push 16 bit value in X onto call stack. Drop X. */
|
case VM_PSHWORD: /* Push 16 bit value in X onto call stack. Drop X. */
|
||||||
CHECKUNDERFLOW(1);
|
CHECKUNDERFLOW(1);
|
||||||
@ -549,11 +620,9 @@ void execute_instruction()
|
|||||||
printchar('\n');
|
printchar('\n');
|
||||||
#endif
|
#endif
|
||||||
byteptr = (unsigned char *)&XREG;
|
byteptr = (unsigned char *)&XREG;
|
||||||
memory[sp] = *(byteptr + 1);
|
MEM(sp--) = *(byteptr + 1);
|
||||||
--sp;
|
|
||||||
CHECKSTACKOVERFLOW();
|
CHECKSTACKOVERFLOW();
|
||||||
memory[sp] = *byteptr;
|
MEM(sp--) = *byteptr;
|
||||||
--sp;
|
|
||||||
CHECKSTACKOVERFLOW();
|
CHECKSTACKOVERFLOW();
|
||||||
--evalptr;
|
--evalptr;
|
||||||
break;
|
break;
|
||||||
@ -566,8 +635,7 @@ void execute_instruction()
|
|||||||
printchar('\n');
|
printchar('\n');
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
memory[sp] = XREG & 0x00ff;
|
MEM(sp--) = XREG & 0x00ff;
|
||||||
--sp;
|
|
||||||
CHECKSTACKOVERFLOW();
|
CHECKSTACKOVERFLOW();
|
||||||
--evalptr;
|
--evalptr;
|
||||||
break;
|
break;
|
||||||
@ -588,11 +656,9 @@ void execute_instruction()
|
|||||||
|
|
||||||
/* Push old FP to stack */
|
/* Push old FP to stack */
|
||||||
byteptr = (unsigned char *)&fp;
|
byteptr = (unsigned char *)&fp;
|
||||||
memory[sp] = *(byteptr + 1);
|
MEM(sp--) = *(byteptr + 1);
|
||||||
--sp;
|
|
||||||
CHECKSTACKOVERFLOW();
|
CHECKSTACKOVERFLOW();
|
||||||
memory[sp] = *byteptr;
|
MEM(sp--) = *byteptr;
|
||||||
--sp;
|
|
||||||
CHECKSTACKOVERFLOW();
|
CHECKSTACKOVERFLOW();
|
||||||
|
|
||||||
fp = sp;
|
fp = sp;
|
||||||
@ -624,10 +690,18 @@ void execute_instruction()
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case VM_ATOR: /* Convert absolute address in X to relative address */
|
case VM_ATOR: /* Convert absolute address in X to relative address */
|
||||||
|
#ifdef __GNUC__
|
||||||
XREG = (XREG - fp - 1) & 0xffff;
|
XREG = (XREG - fp - 1) & 0xffff;
|
||||||
|
#else
|
||||||
|
XREG = XREG - fp - 1;
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case VM_RTOA: /* Convert relative address in X to absolute address */
|
case VM_RTOA: /* Convert relative address in X to absolute address */
|
||||||
|
#ifdef __GNUC__
|
||||||
XREG = (XREG + fp + 1) & 0xffff;
|
XREG = (XREG + fp + 1) & 0xffff;
|
||||||
|
#else
|
||||||
|
XREG = XREG + fp + 1;
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
/*
|
/*
|
||||||
* Integer math
|
* Integer math
|
||||||
@ -758,12 +832,12 @@ void execute_instruction()
|
|||||||
CHECKUNDERFLOW(1);
|
CHECKUNDERFLOW(1);
|
||||||
pc = XREG;
|
pc = XREG;
|
||||||
--evalptr;
|
--evalptr;
|
||||||
return; /* Do not advance program counter */
|
goto nextinstr; /* Do not advance program counter */
|
||||||
case VM_JMPIMM: /* Imm mode - jump to 16 bit word following opcode */
|
case VM_JMPIMM: /* Imm mode - jump to 16 bit word following opcode */
|
||||||
wordptr = (unsigned short *)&memory[++pc];
|
wordptr = (unsigned short *)&MEM(++pc);
|
||||||
++pc;
|
++pc;
|
||||||
pc = *wordptr;
|
pc = *wordptr;
|
||||||
return;
|
goto nextinstr; /* Do not advance program counter */
|
||||||
case VM_BRNCH: /* If Y!= 0, jump to address X. Drop X, Y. */
|
case VM_BRNCH: /* If Y!= 0, jump to address X. Drop X, Y. */
|
||||||
CHECKUNDERFLOW(2);
|
CHECKUNDERFLOW(2);
|
||||||
if (YREG) {
|
if (YREG) {
|
||||||
@ -772,9 +846,9 @@ void execute_instruction()
|
|||||||
++pc;
|
++pc;
|
||||||
}
|
}
|
||||||
evalptr -= 2;
|
evalptr -= 2;
|
||||||
return; /* Do not advance program counter */
|
goto nextinstr; /* Do not advance program counter */
|
||||||
case VM_BRNCHIMM: /* Imm mode - if X!=0 branch to 16 bit word following opcode */
|
case VM_BRNCHIMM: /* Imm mode - if X!=0 branch to 16 bit word following opcode */
|
||||||
wordptr = (unsigned short *)&memory[++pc];
|
wordptr = (unsigned short *)&MEM(++pc);
|
||||||
++pc;
|
++pc;
|
||||||
CHECKUNDERFLOW(1);
|
CHECKUNDERFLOW(1);
|
||||||
if (XREG) {
|
if (XREG) {
|
||||||
@ -783,35 +857,35 @@ void execute_instruction()
|
|||||||
++pc;
|
++pc;
|
||||||
}
|
}
|
||||||
--evalptr;
|
--evalptr;
|
||||||
return; /* Do not advance program counter */
|
goto nextinstr; /* Do not advance program counter */
|
||||||
case VM_JSR: /* Push PC to call stack. Jump to address X. Drop X. */
|
case VM_JSR: /* Push PC to call stack. Jump to address X. Drop X. */
|
||||||
CHECKUNDERFLOW(1);
|
CHECKUNDERFLOW(1);
|
||||||
byteptr = (unsigned char *) &pc;
|
byteptr = (unsigned char *) &pc;
|
||||||
memory[sp] = *(byteptr + 1);
|
MEM(sp) = *(byteptr + 1);
|
||||||
--sp;
|
--sp;
|
||||||
CHECKSTACKOVERFLOW();
|
CHECKSTACKOVERFLOW();
|
||||||
memory[sp] = *byteptr;
|
MEM(sp) = *byteptr;
|
||||||
--sp;
|
--sp;
|
||||||
CHECKSTACKOVERFLOW();
|
CHECKSTACKOVERFLOW();
|
||||||
pc = XREG;
|
pc = XREG;
|
||||||
--evalptr;
|
--evalptr;
|
||||||
return; /* Do not advance program counter */
|
goto nextinstr; /* Do not advance program counter */
|
||||||
case VM_JSRIMM: /* Imm mode - push PC to calls stack, jump to 16 bit word */
|
case VM_JSRIMM: /* Imm mode - push PC to calls stack, jump to 16 bit word */
|
||||||
wordptr = (unsigned short *)&memory[++pc];
|
wordptr = (unsigned short *)&MEM(++pc);
|
||||||
++pc;
|
++pc;
|
||||||
byteptr = (unsigned char *) &pc;
|
byteptr = (unsigned char *) &pc;
|
||||||
memory[sp] = *(byteptr + 1);
|
MEM(sp) = *(byteptr + 1);
|
||||||
--sp;
|
--sp;
|
||||||
CHECKSTACKOVERFLOW();
|
CHECKSTACKOVERFLOW();
|
||||||
memory[sp] = *byteptr;
|
MEM(sp) = *byteptr;
|
||||||
--sp;
|
--sp;
|
||||||
CHECKSTACKOVERFLOW();
|
CHECKSTACKOVERFLOW();
|
||||||
pc = *wordptr;
|
pc = *wordptr;
|
||||||
return; /* Do not advance program counter */
|
goto nextinstr; /* Do not advance program counter */
|
||||||
case VM_RTS: /* Pop call stack, jump to the address popped. */
|
case VM_RTS: /* Pop call stack, jump to the address popped. */
|
||||||
CHECKSTACKUNDERFLOW(2);
|
CHECKSTACKUNDERFLOW(2);
|
||||||
++sp;
|
++sp;
|
||||||
wordptr = (unsigned short *)&memory[sp];
|
wordptr = (unsigned short *)&MEM(sp);
|
||||||
pc = *wordptr;
|
pc = *wordptr;
|
||||||
++sp;
|
++sp;
|
||||||
break;
|
break;
|
||||||
@ -835,15 +909,15 @@ void execute_instruction()
|
|||||||
break;
|
break;
|
||||||
case VM_PRSTR: /* Print null terminated string pointed to by X. Drop X */
|
case VM_PRSTR: /* Print null terminated string pointed to by X. Drop X */
|
||||||
CHECKUNDERFLOW(1);
|
CHECKUNDERFLOW(1);
|
||||||
while (memory[XREG]) {
|
while (MEM(XREG)) {
|
||||||
printchar(memory[XREG++]);
|
printchar(MEM(XREG++));
|
||||||
}
|
}
|
||||||
--evalptr;
|
--evalptr;
|
||||||
break;
|
break;
|
||||||
case VM_PRMSG: /* Print literal string at PC (null terminated) */
|
case VM_PRMSG: /* Print literal string at PC (null terminated) */
|
||||||
++pc;
|
++pc;
|
||||||
while (memory[pc]) {
|
while (MEM(pc)) {
|
||||||
printchar(memory[pc++]);
|
printchar(MEM(pc++));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VM_KBDCH: /* Push character from keyboard onto eval stack */
|
case VM_KBDCH: /* Push character from keyboard onto eval stack */
|
||||||
@ -862,7 +936,7 @@ void execute_instruction()
|
|||||||
case VM_KBDLN: /* Obtain line from keyboard and write to memory pointed to by */
|
case VM_KBDLN: /* Obtain line from keyboard and write to memory pointed to by */
|
||||||
/* Y. X contains the max number of bytes in buf. Drop X, Y. */
|
/* Y. X contains the max number of bytes in buf. Drop X, Y. */
|
||||||
CHECKUNDERFLOW(2);
|
CHECKUNDERFLOW(2);
|
||||||
getln((char *) &memory[YREG], XREG);
|
getln((char *) &MEM(YREG), XREG);
|
||||||
evalptr -= 2;
|
evalptr -= 2;
|
||||||
break;
|
break;
|
||||||
/*
|
/*
|
||||||
@ -873,17 +947,8 @@ void execute_instruction()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
++pc;
|
++pc;
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Run the program!
|
|
||||||
*/
|
|
||||||
void execute()
|
|
||||||
{
|
|
||||||
while (1) {
|
|
||||||
execute_instruction();
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load bytecode into memory[].
|
* Load bytecode into memory[].
|
||||||
@ -892,7 +957,7 @@ void load()
|
|||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char ch;
|
char ch;
|
||||||
char *p = (char*)&memory[RTPCSTART];
|
char *p = (char*)&MEM(RTPCSTART);
|
||||||
|
|
||||||
pc = RTPCSTART;
|
pc = RTPCSTART;
|
||||||
do {
|
do {
|
||||||
@ -913,7 +978,7 @@ void load()
|
|||||||
} while (!fp);
|
} while (!fp);
|
||||||
while (!feof(fp)) {
|
while (!feof(fp)) {
|
||||||
ch = fgetc(fp);
|
ch = fgetc(fp);
|
||||||
memory[pc++] = ch;
|
MEM(pc++) = ch;
|
||||||
/* Print dot for each page */
|
/* Print dot for each page */
|
||||||
if (pc%0xff == 0) {
|
if (pc%0xff == 0) {
|
||||||
printchar('.');
|
printchar('.');
|
||||||
|
Loading…
Reference in New Issue
Block a user