mirror of
https://github.com/bobbimanners/EightBall.git
synced 2024-05-29 03:41:32 +00:00
v0.68: compiler bug fixes, improved efficiency
- Fixed indentation of VM code. Turned on stack checks for GCC only. - Added new `VM_DISCARD` VM instruction (and compiler support). This makes the VM significantly more efficient. - Configured Linux VM to be compatible with Apple II environment. - Added line to force to interpret mode to prevent surprises. - Compiler: fixed bug when exiting `for` loop using `return`. The compiler was leaking a word on the evalutation stack after jumping out of the body of the `for` loop.
This commit is contained in:
parent
43d45a06dd
commit
ea3a6a83e2
BIN
8ball20.prg
BIN
8ball20.prg
Binary file not shown.
BIN
8ball64.prg
BIN
8ball64.prg
Binary file not shown.
BIN
8ballvm20.prg
BIN
8ballvm20.prg
Binary file not shown.
BIN
8ballvm64.prg
BIN
8ballvm64.prg
Binary file not shown.
6
Makefile
6
Makefile
|
@ -104,13 +104,17 @@ test.d64: 8ball20.prg 8ballvm20.prg 8ball64.prg 8ballvm64.prg unittest.8bp sieve
|
|||
c1541 -attach test.d64 -write unittest.8bp unit.8b,s
|
||||
c1541 -attach test.d64 -write sieve4.8bp sieve4.8b,s
|
||||
|
||||
test.dsk: eightball.system ebvm.system sieve4.8b
|
||||
test.dsk: eightball.system ebvm.system sieve4.8b tetris.8b bytecode
|
||||
java -jar $(APPLECMDR) -d test.dsk e8ball.system
|
||||
java -jar $(APPLECMDR) -d test.dsk ebvm.system
|
||||
java -jar $(APPLECMDR) -d test.dsk sieve4.8b
|
||||
java -jar $(APPLECMDR) -d test.dsk tetris.8b
|
||||
java -jar $(APPLECMDR) -d test.dsk bytecode
|
||||
java -jar $(APPLECMDR) -p test.dsk e8ball.system sys <eightball.system
|
||||
java -jar $(APPLECMDR) -p test.dsk ebvm.system sys <ebvm.system
|
||||
java -jar $(APPLECMDR) -p test.dsk sieve4.8b txt <sieve4.8b
|
||||
java -jar $(APPLECMDR) -p test.dsk tetris.8b txt <tetris.8b
|
||||
java -jar $(APPLECMDR) -p test.dsk bytecode txt <bytecode
|
||||
|
||||
xvic: test.d64
|
||||
xvic -mem all -drive8type 1541 -8 test.d64
|
||||
|
|
BIN
ebvm.system
BIN
ebvm.system
Binary file not shown.
49
eightball.c
49
eightball.c
|
@ -1232,9 +1232,11 @@ unsigned char *heap2PtrBttm; /* Arena 2: bottom-up heap */
|
|||
* Heap 2: Program text
|
||||
*/
|
||||
#define HEAP1TOP (char*)0xb7ff
|
||||
#define HEAP1LIM (char*)0x9800
|
||||
//#define HEAP1LIM (char*)0x9800
|
||||
#define HEAP1LIM (char*)0xa800
|
||||
|
||||
#define HEAP2TOP (char*)0x97ff
|
||||
//#define HEAP2TOP (char*)0x97ff
|
||||
#define HEAP2TOP (char*)0xa7ff
|
||||
#define HEAP2LIM (char*)0x8a00
|
||||
/* HEAP2LIM HAS TO BE ADJUSTED TO NOT
|
||||
* TRASH THE CODE, WHICH LOADS FROM $2000 UP
|
||||
|
@ -2560,7 +2562,7 @@ void doif(unsigned char arg)
|
|||
push_return(IFFRAME);
|
||||
|
||||
if (compile) {
|
||||
/* **** Value of IF expression is on the VM stack **** */
|
||||
/* **** Value of IF expression is on the eval stack **** */
|
||||
emit(VM_NOT);
|
||||
push_return(rtPC + 1);
|
||||
emitldi(0xffff); /* To be filled in later */
|
||||
|
@ -2828,10 +2830,10 @@ unsigned char assignorcreate(unsigned char mode)
|
|||
* When compiling:
|
||||
*
|
||||
* - Magic value FORFRAME_B or FORFRAME_W.
|
||||
* - 0 if absolute addressing, 1 if relative addressing
|
||||
* - Runtime PC
|
||||
* - Pointer to loop control variable.
|
||||
* - Dummy word
|
||||
* - Dummy word
|
||||
*/
|
||||
|
||||
/* Get the address of the variable */
|
||||
|
@ -2849,10 +2851,11 @@ unsigned char assignorcreate(unsigned char mode)
|
|||
/* Find out if it is a local or a global */
|
||||
findintvar(name, &local);
|
||||
push_return(local && compilingsub); /* 0: absolute, 1: relative addr */
|
||||
push_return(rtPC); /* Store PC for compile case */
|
||||
emit(VM_DUP);
|
||||
|
||||
/* Loop limit k should be on the runtime VM stack already */
|
||||
/* Loop limit k should be on the runtime eval stack, move it to call stack */
|
||||
emit(VM_PSHWORD);
|
||||
|
||||
push_return(rtPC); /* Store PC so we know where to come back to */
|
||||
push_return(j);
|
||||
push_return(0); /* Dummy */
|
||||
} else {
|
||||
|
@ -2925,13 +2928,19 @@ unsigned char doendfor()
|
|||
}
|
||||
|
||||
if (compile) {
|
||||
/* **** Loop limit is on the VM stack **** */
|
||||
emitldi(return_stack[returnSP + 2]);
|
||||
if (return_stack[returnSP + 4]) {
|
||||
/* **** Loop limit is on the call stack **** */
|
||||
emit(VM_POPWORD);
|
||||
emit(VM_DUP);
|
||||
emit(VM_PSHWORD);
|
||||
|
||||
emitldi(return_stack[returnSP + 2]); /* Pointer to loop variable */
|
||||
if (return_stack[returnSP + 4]) { /* Rel or abs */
|
||||
emit((type == TYPE_WORD) ? VM_LDRWORD : VM_LDRBYTE);
|
||||
} else {
|
||||
emit((type == TYPE_WORD) ? VM_LDAWORD : VM_LDABYTE);
|
||||
}
|
||||
|
||||
/* Increment and store loop variable */
|
||||
emit(VM_INC);
|
||||
emit(VM_DUP);
|
||||
emitldi(return_stack[returnSP + 2]);
|
||||
|
@ -2940,9 +2949,14 @@ unsigned char doendfor()
|
|||
} else {
|
||||
emit((type == TYPE_WORD) ? VM_STAWORD : VM_STABYTE);
|
||||
}
|
||||
|
||||
/* Compare with loop limit already on eval stack */
|
||||
emit(VM_GTE);
|
||||
emitldi(return_stack[returnSP + 3]);
|
||||
emitldi(return_stack[returnSP + 3]); /* Branch destination */
|
||||
emit(VM_BRNCH);
|
||||
|
||||
/* Drop loop limit from call stack */
|
||||
emit(VM_POPWORD);
|
||||
emit(VM_DROP);
|
||||
goto unwind;
|
||||
}
|
||||
|
@ -3010,7 +3024,7 @@ void dowhile(char *startTxtPtr, unsigned char arg)
|
|||
|
||||
if (compile) {
|
||||
push_return(rtPCBeforeEval);
|
||||
/* **** Value of WHILE expression is on the VM stack **** */
|
||||
/* **** Value of WHILE expression is on the eval stack **** */
|
||||
emit(VM_NOT);
|
||||
push_return(rtPC + 1); /* Address of dummy 0xffff */
|
||||
emitldi(0xffff);
|
||||
|
@ -3623,10 +3637,12 @@ unsigned char docall()
|
|||
|
||||
/* Caller must drop the arguments
|
||||
* pushed to call stack above */
|
||||
for (j = 0; j < argbytes; ++j) {
|
||||
emit(VM_POPBYTE);
|
||||
emit(VM_DROP);
|
||||
}
|
||||
emitldi(argbytes);
|
||||
emit(VM_DISCARD);
|
||||
//for (j = 0; j < argbytes; ++j) {
|
||||
// emit(VM_POPBYTE);
|
||||
// emit(VM_DROP);
|
||||
//}
|
||||
} else {
|
||||
/* Stash pointer to just after the call stmt */
|
||||
push_return((int) txtPtr);
|
||||
|
@ -4975,6 +4991,7 @@ main()
|
|||
#endif
|
||||
}
|
||||
|
||||
compile = 0;
|
||||
getln(lnbuf, 255);
|
||||
|
||||
switch (editmode) {
|
||||
|
|
BIN
eightball.system
BIN
eightball.system
Binary file not shown.
|
@ -37,7 +37,7 @@
|
|||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#define VERSIONSTR "0.67"
|
||||
#define VERSIONSTR "0.68"
|
||||
|
||||
void print(char *str);
|
||||
|
||||
|
|
BIN
eightballvm
BIN
eightballvm
Binary file not shown.
107
eightballvm.c
107
eightballvm.c
|
@ -51,7 +51,11 @@
|
|||
*/
|
||||
|
||||
/* Define STACKCHECKS to enable paranoid stack checking */
|
||||
#ifdef __GNUC__
|
||||
#define STACKCHECKS
|
||||
#else
|
||||
#undef STACKCHECKS
|
||||
#endif
|
||||
|
||||
#include "eightballvm.h"
|
||||
#include "eightballutils.h"
|
||||
|
@ -180,7 +184,8 @@ void checkstackunderflow(unsigned char bytes)
|
|||
{
|
||||
if ((MEMORYSZ - sp) < bytes) {
|
||||
print("Call stack underflow\nPC=");
|
||||
printhex(pc); printchar('\n');
|
||||
printhex(pc);
|
||||
printchar('\n');
|
||||
while (1);
|
||||
}
|
||||
}
|
||||
|
@ -227,12 +232,19 @@ void execute_instruction()
|
|||
#ifdef DEBUGREGS
|
||||
unsigned int i;
|
||||
print("\n");
|
||||
print("--->PC "); printhex(pc); print("\n");
|
||||
print("--->SP "); printhex(sp); print("\n");
|
||||
print("--->FP "); printhex(fp); print("\n");
|
||||
print("--->PC ");
|
||||
printhex(pc);
|
||||
print("\n");
|
||||
print("--->SP ");
|
||||
printhex(sp);
|
||||
print("\n");
|
||||
print("--->FP ");
|
||||
printhex(fp);
|
||||
print("\n");
|
||||
print("Call Stk: ");
|
||||
for(i = sp+1; i <= RTCALLSTACKTOP; ++i) {
|
||||
printhexbyte(memory[i]); printchar(' ');
|
||||
for (i = sp + 1; i <= RTCALLSTACKTOP; ++i) {
|
||||
printhexbyte(memory[i]);
|
||||
printchar(' ');
|
||||
}
|
||||
print("\nEval Stk: ");
|
||||
printhex(XREG);
|
||||
|
@ -293,25 +305,25 @@ void execute_instruction()
|
|||
* Miscellaneous
|
||||
*/
|
||||
case VM_END: /* Terminate execution */
|
||||
if (evalptr > 0) {
|
||||
print("WARNING: evalptr ");
|
||||
printdec(evalptr);
|
||||
printchar('\n');
|
||||
}
|
||||
if (evalptr > 0) {
|
||||
print("WARNING: evalptr ");
|
||||
printdec(evalptr);
|
||||
printchar('\n');
|
||||
}
|
||||
#ifdef __GNUC__
|
||||
exit(0);
|
||||
#else
|
||||
for (delay = 0; delay < 25000; ++delay);
|
||||
exit(0);
|
||||
exit(0);
|
||||
#endif
|
||||
break;
|
||||
|
||||
/*
|
||||
* Load Immediate
|
||||
*/
|
||||
/*
|
||||
* Load Immediate
|
||||
*/
|
||||
case VM_LDIMM: /* Pushes the following 16 bit word to the evaluation stack */
|
||||
++evalptr;
|
||||
CHECKOVERFLOW();
|
||||
CHECKOVERFLOW();
|
||||
/* Note: Word is stored in little endian format! */
|
||||
tempword = memory[++pc];
|
||||
tempword += memory[++pc] * 256;
|
||||
|
@ -364,7 +376,9 @@ void execute_instruction()
|
|||
printchar('\n');
|
||||
#endif
|
||||
|
||||
XREG = memory[(XREG + fp + 1) & 0xffff] + 256 * memory[(XREG + fp + 2) & 0xffff];
|
||||
XREG =
|
||||
memory[(XREG + fp + 1) & 0xffff] +
|
||||
256 * memory[(XREG + fp + 2) & 0xffff];
|
||||
break;
|
||||
case VM_LDRBYTE: /* Replaces X with 8 bit value pointed to by X. */
|
||||
CHECKUNDERFLOW(1);
|
||||
|
@ -446,10 +460,11 @@ void execute_instruction()
|
|||
XREG = memory[sp];
|
||||
break;
|
||||
case VM_PSHWORD: /* Push 16 bit value in X onto call stack. Drop X. */
|
||||
CHECKUNDERFLOW(1);
|
||||
|
||||
#ifdef DEBUGSTACK
|
||||
print("\n Push word to ");
|
||||
printhex(sp-1);
|
||||
printhex(sp - 1);
|
||||
printchar('\n');
|
||||
#endif
|
||||
|
||||
|
@ -462,6 +477,7 @@ void execute_instruction()
|
|||
--evalptr;
|
||||
break;
|
||||
case VM_PSHBYTE: /* Push 8 bit value in X onto call stack. Drop X. */
|
||||
CHECKUNDERFLOW(1);
|
||||
|
||||
#ifdef DEBUGSTACK
|
||||
print("\n Push byte to ");
|
||||
|
@ -474,17 +490,22 @@ void execute_instruction()
|
|||
CHECKSTACKOVERFLOW();
|
||||
--evalptr;
|
||||
break;
|
||||
case VM_DISCARD: /* Discard X bytes from call stack. Drop X. */
|
||||
CHECKUNDERFLOW(1);
|
||||
sp += XREG;
|
||||
--evalptr;
|
||||
break;
|
||||
case VM_SPTOFP: /* Copy stack pointer to frame pointer. (Enter function scope) */
|
||||
|
||||
#ifdef DEBUGSTACK
|
||||
print("\n SPTOFP FP before ");
|
||||
printhex(fp);
|
||||
print(" SP ");
|
||||
print(" SP ");
|
||||
printhex(sp);
|
||||
printchar('\n');
|
||||
#endif
|
||||
|
||||
/* Push old FP to stack */
|
||||
/* Push old FP to stack */
|
||||
memory[sp] = (fp & 0xff00) >> 8;
|
||||
--sp;
|
||||
CHECKSTACKOVERFLOW();
|
||||
|
@ -499,14 +520,14 @@ void execute_instruction()
|
|||
#ifdef DEBUGSTACK
|
||||
print("\n FPTOSP SP before ");
|
||||
printhex(sp);
|
||||
print(" FP ");
|
||||
print(" FP ");
|
||||
printhex(fp);
|
||||
printchar('\n');
|
||||
#endif
|
||||
|
||||
sp = fp;
|
||||
|
||||
/* Pop old FP from stack -> FP */
|
||||
/* Pop old FP from stack -> FP */
|
||||
CHECKSTACKUNDERFLOW(2);
|
||||
sp += 2;
|
||||
CHECKOVERFLOW();
|
||||
|
@ -514,17 +535,17 @@ void execute_instruction()
|
|||
|
||||
#ifdef DEBUGSTACK
|
||||
print(" Recovered FP ");
|
||||
printhex(fp);
|
||||
print(" from stack\n");
|
||||
printhex(fp);
|
||||
print(" from stack\n");
|
||||
#endif
|
||||
|
||||
break;
|
||||
case VM_ATOR: /* Convert absolute address in X to relative address */
|
||||
XREG = (XREG - fp - 1) & 0xffff;
|
||||
break;
|
||||
break;
|
||||
case VM_RTOA: /* Convert relative address in X to absolute address */
|
||||
XREG = (XREG + fp + 1) & 0xffff;
|
||||
break;
|
||||
break;
|
||||
/*
|
||||
* Integer math
|
||||
*/
|
||||
|
@ -699,20 +720,20 @@ void execute_instruction()
|
|||
CHECKUNDERFLOW(1);
|
||||
printchar((unsigned char) XREG);
|
||||
--evalptr;
|
||||
break;
|
||||
break;
|
||||
case VM_PRSTR: /* Print null terminated string pointed to by X. Drop X */
|
||||
CHECKUNDERFLOW(1);
|
||||
while(memory[XREG]) {
|
||||
printchar(memory[XREG++]);
|
||||
}
|
||||
while (memory[XREG]) {
|
||||
printchar(memory[XREG++]);
|
||||
}
|
||||
--evalptr;
|
||||
break;
|
||||
break;
|
||||
case VM_PRMSG: /* Print literal string at PC (null terminated) */
|
||||
++pc;
|
||||
while(memory[pc]) {
|
||||
printchar(memory[pc++]);
|
||||
}
|
||||
break;
|
||||
++pc;
|
||||
while (memory[pc]) {
|
||||
printchar(memory[pc++]);
|
||||
}
|
||||
break;
|
||||
case VM_KBDCH: /* Push character from keyboard onto eval stack */
|
||||
CHECKUNDERFLOW(1);
|
||||
++evalptr;
|
||||
|
@ -723,15 +744,15 @@ void execute_instruction()
|
|||
while (!(*(char *) XREG = cbm_k_getin()));
|
||||
#else
|
||||
/* TODO: Unimplemented in Linux */
|
||||
XREG = 0;
|
||||
XREG = 0;
|
||||
#endif
|
||||
break;
|
||||
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. */
|
||||
break;
|
||||
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. */
|
||||
CHECKUNDERFLOW(2);
|
||||
getln((char *) &memory[YREG], XREG);
|
||||
evalptr -= 2;
|
||||
break;
|
||||
evalptr -= 2;
|
||||
break;
|
||||
/*
|
||||
* Unsupported instruction
|
||||
*/
|
||||
|
@ -786,7 +807,7 @@ int main()
|
|||
videomode(VIDEOMODE_80COL);
|
||||
clrscr();
|
||||
#elif defined(CBM)
|
||||
printchar(147); /* Clear */
|
||||
printchar(147); /* Clear */
|
||||
#endif
|
||||
execute();
|
||||
return 0;
|
||||
|
|
278
eightballvm.h
278
eightballvm.h
|
@ -68,140 +68,142 @@
|
|||
* stack, and also to release the locals on return from sub.)
|
||||
*/
|
||||
enum bytecode {
|
||||
/**** Miscellaneous ********************************************************/
|
||||
VM_END, /* Terminate execution */
|
||||
/**** Load Immediate *******************************************************/
|
||||
VM_LDIMM, /* Pushes the following 16 bit word to the evaluation stack */
|
||||
/* Absolute addressing: */
|
||||
VM_LDAWORD,/* Replaces X with 16 bit value pointed to by X. */
|
||||
VM_LDABYTE,/* Replaces X with 8 bit value pointed to by X. */
|
||||
VM_STAWORD,/* Stores 16 bit value Y in addr pointed to by X. Drops X and Y.*/
|
||||
VM_STABYTE,/* Stores 8 bit value Y in addr pointed to by X. Drops X and Y. */
|
||||
/* Relative to Frame Pointer addressing: */
|
||||
VM_LDRWORD,/* Replaces X with 16 bit value pointed to by X. */
|
||||
VM_LDRBYTE,/* Replaces X with 8 bit value pointed to by X. */
|
||||
VM_STRWORD,/* Stores 16 bit value Y in addr pointed to by X. Drops X and Y.*/
|
||||
VM_STRBYTE,/* Stores 8 bit value Y in addr pointed to by X. Drops X and Y. */
|
||||
/**** Manipulate evaluation stack ******************************************/
|
||||
VM_SWAP, /* Swaps X and Y */
|
||||
VM_DUP, /* Duplicates X -> X, Y */
|
||||
VM_DUP2, /* Duplicates X -> X,Z; Y -> Y,T */
|
||||
VM_DROP, /* Drops X */
|
||||
VM_OVER, /* Duplicates Y -> X,Z */
|
||||
VM_PICK, /* Duplicates stack level specified in X+1 -> X */
|
||||
/**** Manipulate call stack ************************************************/
|
||||
VM_POPWORD,/* Pop 16 bit value from call stack, push onto eval stack [X] */
|
||||
VM_POPBYTE,/* Pop 8 bit value from call stack, push onto eval stack [X] */
|
||||
VM_PSHWORD,/* Push 16 bit value in X onto call stack. Drop X. */
|
||||
VM_PSHBYTE,/* Push 8 bit value in X onto call stack. Drop X. */
|
||||
VM_SPTOFP, /* Copy stack pointer to frame pointer. (Enter function scope) */
|
||||
VM_FPTOSP, /* Copy frame pointer to stack pointer. (Release local vars) */
|
||||
VM_ATOR, /* Convert absolute address in X to relative address */
|
||||
VM_RTOA, /* Convert relative address in X to absolute address */
|
||||
/**** Integer math *********************************************************/
|
||||
VM_INC, /* X = X+1. */
|
||||
VM_DEC, /* X = X-1. */
|
||||
VM_ADD, /* X = Y+X. Y is dropped. */
|
||||
VM_SUB, /* X = Y-X. Y is dropped. */
|
||||
VM_MUL, /* X = Y*X. Y is dropped. */
|
||||
VM_DIV, /* X = Y/X. Y is dropped. */
|
||||
VM_MOD, /* X = Y%X. Y is dropped . */
|
||||
VM_NEG, /* X = -X */
|
||||
/**** Comparisons **********************************************************/
|
||||
VM_GT, /* X = Y>X. Y is dropped. */
|
||||
VM_GTE, /* X = Y>=X. Y is dropped. */
|
||||
VM_LT, /* X = Y<X. Y is dropped. */
|
||||
VM_LTE, /* X = Y<=X. Y is dropped. */
|
||||
VM_EQL, /* X = Y==X. Y is dropped. */
|
||||
VM_NEQL, /* X = Y!=X. Y is dropped. */
|
||||
/**** Logical operations ***************************************************/
|
||||
VM_AND, /* X = Y&&X. Y is dropped. */
|
||||
VM_OR, /* X = Y||X. Y is dropped. */
|
||||
VM_NOT, /* X = !X */
|
||||
/**** Bitwise operations ***************************************************/
|
||||
VM_BITAND, /* X = Y&X. Y is dropped. */
|
||||
VM_BITOR, /* X = Y|X. Y is dropped. */
|
||||
VM_BITXOR, /* X = Y^X. Y is dropped. */
|
||||
VM_BITNOT, /* X = ~X. */
|
||||
VM_LSH, /* X = Y<<X. Y is dropped. */
|
||||
VM_RSH, /* X = Y>>X. Y is dropped. */
|
||||
/**** Flow control *********************************************************/
|
||||
VM_JMP, /* Jump to address X. Drop X. */
|
||||
VM_BRNCH, /* If Y!= 0, jump to address X. Drop X, Y. */
|
||||
VM_JSR, /* Push PC to call stack. Jump to address X. Drop X. */
|
||||
VM_RTS, /* Pop call stack, jump to the address popped. */
|
||||
/**** Input / Output *******************************************************/
|
||||
VM_PRDEC, /* Print 16 bit decimal in X. Drop X */
|
||||
VM_PRHEX, /* Print 16 bit hex in X. Drop X */
|
||||
VM_PRCH, /* Print character in X. Drop X */
|
||||
VM_PRSTR, /* Print null terminated string pointed to by X. Drop X */
|
||||
VM_PRMSG, /* Print literal string at PC (null terminated) */
|
||||
VM_KBDCH, /* Push character from keyboard onto eval stack */
|
||||
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. */
|
||||
/***************************************************************************/
|
||||
/**** Miscellaneous *************************************************************************/
|
||||
VM_END, /* Terminate execution */
|
||||
/**** Load Immediate ************************************************************************/
|
||||
VM_LDIMM, /* Pushes the following 16 bit word to the evaluation stack */
|
||||
/* Absolute addressing: */
|
||||
VM_LDAWORD, /* Replaces X with 16 bit value pointed to by X. */
|
||||
VM_LDABYTE, /* Replaces X with 8 bit value pointed to by X. */
|
||||
VM_STAWORD, /* Stores 16 bit value Y in addr pointed to by X. Drops X and Y.*/
|
||||
VM_STABYTE, /* Stores 8 bit value Y in addr pointed to by X. Drops X and Y. */
|
||||
/* Relative to Frame Pointer addressing: */
|
||||
VM_LDRWORD, /* Replaces X with 16 bit value pointed to by X. */
|
||||
VM_LDRBYTE, /* Replaces X with 8 bit value pointed to by X. */
|
||||
VM_STRWORD, /* Stores 16 bit value Y in addr pointed to by X. Drops X and Y.*/
|
||||
VM_STRBYTE, /* Stores 8 bit value Y in addr pointed to by X. Drops X and Y. */
|
||||
/**** Manipulate evaluation stack ***********************************************************/
|
||||
VM_SWAP, /* Swaps X and Y */
|
||||
VM_DUP, /* Duplicates X -> X, Y */
|
||||
VM_DUP2, /* Duplicates X -> X,Z; Y -> Y,T */
|
||||
VM_DROP, /* Drops X */
|
||||
VM_OVER, /* Duplicates Y -> X,Z */
|
||||
VM_PICK, /* Duplicates stack level specified in X+1 -> X */
|
||||
/**** Manipulate call stack *****************************************************************/
|
||||
VM_POPWORD, /* Pop 16 bit value from call stack, push onto eval stack [X] */
|
||||
VM_POPBYTE, /* Pop 8 bit value from call stack, push onto eval stack [X] */
|
||||
VM_PSHWORD, /* Push 16 bit value in X onto call stack. Drop X. */
|
||||
VM_PSHBYTE, /* Push 8 bit value in X onto call stack. Drop X. */
|
||||
VM_DISCARD, /* Discard X bytes from call stack. Drop X. */
|
||||
VM_SPTOFP, /* Copy stack pointer to frame pointer. (Enter function scope) */
|
||||
VM_FPTOSP, /* Copy frame pointer to stack pointer. (Release local vars) */
|
||||
VM_ATOR, /* Convert absolute address in X to relative address */
|
||||
VM_RTOA, /* Convert relative address in X to absolute address */
|
||||
/**** Integer math **************************************************************************/
|
||||
VM_INC, /* X = X+1. */
|
||||
VM_DEC, /* X = X-1. */
|
||||
VM_ADD, /* X = Y+X. Y is dropped. */
|
||||
VM_SUB, /* X = Y-X. Y is dropped. */
|
||||
VM_MUL, /* X = Y*X. Y is dropped. */
|
||||
VM_DIV, /* X = Y/X. Y is dropped. */
|
||||
VM_MOD, /* X = Y%X. Y is dropped . */
|
||||
VM_NEG, /* X = -X */
|
||||
/**** Comparisons ***************************************************************************/
|
||||
VM_GT, /* X = Y>X. Y is dropped. */
|
||||
VM_GTE, /* X = Y>=X. Y is dropped. */
|
||||
VM_LT, /* X = Y<X. Y is dropped. */
|
||||
VM_LTE, /* X = Y<=X. Y is dropped. */
|
||||
VM_EQL, /* X = Y==X. Y is dropped. */
|
||||
VM_NEQL, /* X = Y!=X. Y is dropped. */
|
||||
/**** Logical operations ********************************************************************/
|
||||
VM_AND, /* X = Y&&X. Y is dropped. */
|
||||
VM_OR, /* X = Y||X. Y is dropped. */
|
||||
VM_NOT, /* X = !X */
|
||||
/**** Bitwise operations ********************************************************************/
|
||||
VM_BITAND, /* X = Y&X. Y is dropped. */
|
||||
VM_BITOR, /* X = Y|X. Y is dropped. */
|
||||
VM_BITXOR, /* X = Y^X. Y is dropped. */
|
||||
VM_BITNOT, /* X = ~X. */
|
||||
VM_LSH, /* X = Y<<X. Y is dropped. */
|
||||
VM_RSH, /* X = Y>>X. Y is dropped. */
|
||||
/**** Flow control **************************************************************************/
|
||||
VM_JMP, /* Jump to address X. Drop X. */
|
||||
VM_BRNCH, /* If Y!= 0, jump to address X. Drop X, Y. */
|
||||
VM_JSR, /* Push PC to call stack. Jump to address X. Drop X. */
|
||||
VM_RTS, /* Pop call stack, jump to the address popped. */
|
||||
/**** Input / Output ************************************************************************/
|
||||
VM_PRDEC, /* Print 16 bit decimal in X. Drop X */
|
||||
VM_PRHEX, /* Print 16 bit hex in X. Drop X */
|
||||
VM_PRCH, /* Print character in X. Drop X */
|
||||
VM_PRSTR, /* Print null terminated string pointed to by X. Drop X */
|
||||
VM_PRMSG, /* Print literal string at PC (null terminated) */
|
||||
VM_KBDCH, /* Push character from keyboard onto eval stack */
|
||||
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. */
|
||||
/********************************************************************************************/
|
||||
};
|
||||
|
||||
/* Order must match enum bytecode */
|
||||
char *bytecodenames[] = {
|
||||
"END",
|
||||
"LDI",
|
||||
"LDAW",
|
||||
"LDAB",
|
||||
"STAW",
|
||||
"STAB",
|
||||
"LDRW",
|
||||
"LDRB",
|
||||
"STRW",
|
||||
"STRB",
|
||||
"SWP",
|
||||
"DUP",
|
||||
"DUP2",
|
||||
"DRP",
|
||||
"OVER",
|
||||
"PICK",
|
||||
"POPW",
|
||||
"POPB",
|
||||
"PSHW",
|
||||
"PSHB",
|
||||
"SPFP",
|
||||
"FPSP",
|
||||
"ATOR",
|
||||
"RTOA",
|
||||
"INC",
|
||||
"DEC",
|
||||
"ADD",
|
||||
"SUB",
|
||||
"MUL",
|
||||
"DIV",
|
||||
"MOD",
|
||||
"NEG",
|
||||
"GT",
|
||||
"GTE",
|
||||
"LT",
|
||||
"LTE",
|
||||
"EQL",
|
||||
"NEQL",
|
||||
"AND",
|
||||
"OR",
|
||||
"NOT",
|
||||
"BAND",
|
||||
"BOR",
|
||||
"BXOR",
|
||||
"BNOT",
|
||||
"LSH",
|
||||
"RSH",
|
||||
"JMP",
|
||||
"BRC",
|
||||
"JSR",
|
||||
"RTS",
|
||||
"PRDEC",
|
||||
"PRHEX",
|
||||
"PRCH",
|
||||
"PRSTR",
|
||||
"PRMSG",
|
||||
"KBDCH",
|
||||
"KBDLN"
|
||||
"END",
|
||||
"LDI",
|
||||
"LDAW",
|
||||
"LDAB",
|
||||
"STAW",
|
||||
"STAB",
|
||||
"LDRW",
|
||||
"LDRB",
|
||||
"STRW",
|
||||
"STRB",
|
||||
"SWP",
|
||||
"DUP",
|
||||
"DUP2",
|
||||
"DRP",
|
||||
"OVER",
|
||||
"PICK",
|
||||
"POPW",
|
||||
"POPB",
|
||||
"PSHW",
|
||||
"PSHB",
|
||||
"DISC",
|
||||
"SPFP",
|
||||
"FPSP",
|
||||
"ATOR",
|
||||
"RTOA",
|
||||
"INC",
|
||||
"DEC",
|
||||
"ADD",
|
||||
"SUB",
|
||||
"MUL",
|
||||
"DIV",
|
||||
"MOD",
|
||||
"NEG",
|
||||
"GT",
|
||||
"GTE",
|
||||
"LT",
|
||||
"LTE",
|
||||
"EQL",
|
||||
"NEQL",
|
||||
"AND",
|
||||
"OR",
|
||||
"NOT",
|
||||
"BAND",
|
||||
"BOR",
|
||||
"BXOR",
|
||||
"BNOT",
|
||||
"LSH",
|
||||
"RSH",
|
||||
"JMP",
|
||||
"BRC",
|
||||
"JSR",
|
||||
"RTS",
|
||||
"PRDEC",
|
||||
"PRHEX",
|
||||
"PRCH",
|
||||
"PRSTR",
|
||||
"PRMSG",
|
||||
"KBDCH",
|
||||
"KBDLN"
|
||||
};
|
||||
|
||||
#ifdef A2E
|
||||
|
@ -211,7 +213,7 @@ char *bytecodenames[] = {
|
|||
*/
|
||||
#define RTCALLSTACKTOP 0xb7ff
|
||||
#define RTCALLSTACKLIM 0x9800
|
||||
#define RTPCSTART 0x5000 /* TBC */
|
||||
#define RTPCSTART 0x5000 /* TBC */
|
||||
|
||||
#elif defined(C64)
|
||||
|
||||
|
@ -220,7 +222,7 @@ char *bytecodenames[] = {
|
|||
*/
|
||||
#define RTCALLSTACKTOP 0xbfff
|
||||
#define RTCALLSTACKLIM 0xa000
|
||||
#define RTPCSTART 0x3000 /* TBC */
|
||||
#define RTPCSTART 0x3000 /* TBC */
|
||||
|
||||
#elif defined(VIC20)
|
||||
|
||||
|
@ -229,7 +231,7 @@ char *bytecodenames[] = {
|
|||
*/
|
||||
#define RTCALLSTACKTOP 0xbfff
|
||||
#define RTCALLSTACKLIM 0xa000
|
||||
#define RTPCSTART 0x4000 /* TBC */
|
||||
#define RTPCSTART 0x4000 /* TBC */
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
|
@ -237,8 +239,10 @@ char *bytecodenames[] = {
|
|||
* Linux
|
||||
*/
|
||||
//#define RTCALLSTACKTOP 64 * 1024 - 1
|
||||
#define RTCALLSTACKTOP 48 * 1024 - 1 // FOR TESTING
|
||||
#define RTCALLSTACKLIM 32 * 1024
|
||||
#define RTPCSTART 0
|
||||
//#define RTCALLSTACKTOP 48 * 1024 - 1 // FOR TESTING
|
||||
#define RTCALLSTACKTOP 0xb7ff
|
||||
//#define RTCALLSTACKLIM 32 * 1024
|
||||
#define RTCALLSTACKLIM 0x9800
|
||||
//#define RTPCSTART 0
|
||||
#define RTPCSTART 0x5000 // SO THINGS WORK ON APPLE II :)
|
||||
#endif
|
||||
|
||||
|
|
306
tetris.8b
Normal file
306
tetris.8b
Normal file
|
@ -0,0 +1,306 @@
|
|||
' Apple II Low Res Tetris
|
||||
' Bobbi 2018
|
||||
|
||||
word addrs[24]={$400,$480,$500,$580,$600,$680,$700,$780,$428,$4a8,$528,$5a8,$628,$6a8,$728,$7a8,$450,$4d0,$550,$5d0,$650,$6d0,$750,$7d0}
|
||||
|
||||
const lhs=14
|
||||
const rhs=lhs+11
|
||||
const top=10
|
||||
const bttm=top+22
|
||||
const spkr=$c030
|
||||
const kbdata=$c000
|
||||
const kbstrb=$c010
|
||||
|
||||
byte col=18
|
||||
byte row=5
|
||||
byte rot=0
|
||||
byte key=0
|
||||
byte ocol=18
|
||||
byte orow=5
|
||||
byte orot=0
|
||||
byte piece=0
|
||||
|
||||
byte canl=1
|
||||
byte canr=1
|
||||
|
||||
call lores()
|
||||
call clrlo()
|
||||
call frame()
|
||||
|
||||
while 1
|
||||
key=getkey()
|
||||
orow=row;ocol=col;orot=rot
|
||||
if key=='s'
|
||||
if rot==3
|
||||
rot=0
|
||||
else
|
||||
rot=rot+1
|
||||
endif
|
||||
else
|
||||
if (key=='a')&&canl
|
||||
col=col-1
|
||||
else
|
||||
if (key=='d')&&canr
|
||||
col=col+1
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
key=^spkr
|
||||
row=row+1
|
||||
canl=1
|
||||
canr=1
|
||||
call drawPiece(ocol,orow,orot,1); 'Erase
|
||||
if drawPiece(col,row,rot,0)
|
||||
call checkframe(row)
|
||||
col=18;row=5;rot=0
|
||||
piece=piece+1
|
||||
if piece==4
|
||||
piece=0
|
||||
endif
|
||||
endif
|
||||
endwhile
|
||||
call text()
|
||||
end
|
||||
|
||||
sub getkey()
|
||||
if ^kbdata<128
|
||||
return 0
|
||||
endif
|
||||
^kbstrb=0
|
||||
return ^kbdata
|
||||
endsub
|
||||
|
||||
sub lores()
|
||||
^$c050=0
|
||||
^$c052=0
|
||||
^$c054=0
|
||||
^$c056=0
|
||||
endsub
|
||||
|
||||
sub loresmix()
|
||||
^$c050=0
|
||||
^$c053=0
|
||||
^$c054=0
|
||||
^$c056=0
|
||||
endsub
|
||||
|
||||
sub text()
|
||||
^$c051=0
|
||||
^$c054=0
|
||||
endsub
|
||||
|
||||
sub clrlo()
|
||||
byte r=0
|
||||
byte c=0
|
||||
for r=0:23
|
||||
for c=0:39
|
||||
^(addrs[r]+c)=0
|
||||
endfor
|
||||
endfor
|
||||
endsub
|
||||
|
||||
sub plot(byte c,byte r,byte color)
|
||||
word a=addrs[r/2]+c
|
||||
if r%2
|
||||
^a=(^a&$0f)|(color<<4)
|
||||
else
|
||||
^a=(^a&$f0)|color
|
||||
endif
|
||||
endsub
|
||||
|
||||
sub readpix(byte c,byte r)
|
||||
word a=addrs[r/2]+c
|
||||
if r%2
|
||||
return (^a&$f0)>>4
|
||||
else
|
||||
return ^a&$0f
|
||||
endif
|
||||
endsub
|
||||
|
||||
sub hlin(byte c1,byte c2,byte r,byte color)
|
||||
byte i=0
|
||||
for i=c1:c2
|
||||
call plot(i,r,color)
|
||||
endfor
|
||||
endsub
|
||||
|
||||
sub vlin(byte c,byte r1,byte r2,byte color)
|
||||
byte i=0
|
||||
for i=r1:r2
|
||||
call plot(c,i,color)
|
||||
endfor
|
||||
endsub
|
||||
|
||||
sub frame()
|
||||
call hlin(lhs,rhs,bttm,4)
|
||||
call vlin(lhs,top,bttm,4)
|
||||
call vlin(rhs,top,bttm,4)
|
||||
endsub
|
||||
|
||||
sub drawPiece(byte c,byte r,byte rot,byte erase)
|
||||
if piece==0
|
||||
return drawT(c,r,rot,erase)
|
||||
else; if piece==1
|
||||
return drawZ(c,r,rot,erase)
|
||||
else; if piece==2
|
||||
return drawSq(c,r,rot,erase)
|
||||
else
|
||||
return drawI(c,r,rot,erase)
|
||||
endif;endif;endif
|
||||
endsub
|
||||
|
||||
sub drawT(byte c,byte r,byte rot,byte erase)
|
||||
byte color=1
|
||||
if erase
|
||||
color=0
|
||||
endif
|
||||
if rot==0
|
||||
call plot(c,r+1,color)
|
||||
call plot(c+1,r+1,color)
|
||||
call plot(c+2,r+1,color)
|
||||
call plot(c+1,r+2,color)
|
||||
canl=!(readpix(c-1,r+1)||readpix(c,r+2))
|
||||
canr=!(readpix(c+3,r+1)||readpix(c+2,r+2))
|
||||
return readpix(c,r+2)||readpix(c+1,r+3)||readpix(c+2,r+2)
|
||||
else
|
||||
if rot==1
|
||||
call plot(c+1,r,color)
|
||||
call plot(c,r+1,color)
|
||||
call plot(c+1,r+1,color)
|
||||
call plot(c+1,r+2,color)
|
||||
canl=!(readpix(c,r)||readpix(c-1,r+1)||readpix(c,r+2))
|
||||
canr=!(readpix(c+2,r)||readpix(c+2,r+1)||readpix(c+2,r+2))
|
||||
return readpix(c,r+2)||readpix(c+1,r+3)
|
||||
else
|
||||
if rot==2
|
||||
call plot(c+1,r,color)
|
||||
call plot(c,r+1,color)
|
||||
call plot(c+1,r+1,color)
|
||||
call plot(c+2,r+1,color)
|
||||
canl=!(readpix(c,r)||readpix(c-1,r+1))
|
||||
canr=!(readpix(c+2,r)||readpix(c+3,r+1))
|
||||
return readpix(c,r+2)||readpix(c+1,r+2)||readpix(c+2,r+2)
|
||||
else
|
||||
if rot==3
|
||||
call plot(c+1,r,color)
|
||||
call plot(c+1,r+1,color)
|
||||
call plot(c+2,r+1,color)
|
||||
call plot(c+1,r+2,color)
|
||||
canl=!(readpix(c,r)||readpix(c,r+1)||readpix(c,r+2))
|
||||
canr=!(readpix(c+2,r)||readpix(c+3,r+1)||readpix(c+2,r+2))
|
||||
return readpix(c+1,r+3)||readpix(c+2,r+2)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endsub
|
||||
|
||||
sub drawZ(byte c,byte r,byte rot,byte erase)
|
||||
byte color=2
|
||||
if erase
|
||||
color=0
|
||||
endif
|
||||
if (rot==0)||(rot==2)
|
||||
call plot(c+1,r,color)
|
||||
call plot(c+1,r+1,color)
|
||||
call plot(c+2,r+1,color)
|
||||
call plot(c+2,r+2,color)
|
||||
canl=!(readpix(c,r)||readpix(c,r+1)||readpix(c,r+2))
|
||||
canr=!(readpix(c+2,r)||readpix(c+3,r+1)||readpix(c+3,r+2))
|
||||
return readpix(c+2,r+3)
|
||||
else
|
||||
if (rot==1)||(rot==3)
|
||||
call plot(c+1,r+1,color)
|
||||
call plot(c+2,r+1,color)
|
||||
call plot(c,r+2,color)
|
||||
call plot(c+1,r+2,color)
|
||||
canl=!(readpix(c,r+1)||readpix(c-1,r+2))
|
||||
canr=!(readpix(c+3,r+1)||readpix(c+2,r+2))
|
||||
return readpix(c,r+3)||readpix(c+1,r+3)
|
||||
endif
|
||||
endif
|
||||
endsub
|
||||
|
||||
sub drawI(byte c,byte r,byte rot,byte erase)
|
||||
byte color=14
|
||||
if erase
|
||||
color=0
|
||||
endif
|
||||
if (rot==0)||(rot==2)
|
||||
call plot(c,r+2,color)
|
||||
call plot(c+1,r+2,color)
|
||||
call plot(c+2,r+2,color)
|
||||
call plot(c+3,r+2,color)
|
||||
canl=!readpix(c-1,r+2)
|
||||
canr=!readpix(c+4,r+2)
|
||||
return readpix(c,r+3)||readpix(c+1,r+3)||readpix(c+2,r+3)||readpix(c+3,r+3)
|
||||
else
|
||||
if (rot==1)||(rot==3)
|
||||
call plot(c+2,r,color)
|
||||
call plot(c+2,r+1,color)
|
||||
call plot(c+2,r+2,color)
|
||||
call plot(c+2,r+3,color)
|
||||
canl=!(readpix(c+1,r)||readpix(c+1,r+1)||readpix(c+1,r+2)||readpix(c+1,r+3))
|
||||
canr=!(readpix(c+3,r)||readpix(c+3,r+1)||readpix(c+3,r+2)||readpix(c+3,r+3))
|
||||
return readpix(c+2,r+4)
|
||||
endif
|
||||
endif
|
||||
endsub
|
||||
|
||||
sub drawSq(byte c,byte r,byte rot,byte erase)
|
||||
byte color=13
|
||||
if erase
|
||||
color=0
|
||||
endif
|
||||
call plot(c+1,r+1,color)
|
||||
call plot(c+2,r+1,color)
|
||||
call plot(c+1,r+2,color)
|
||||
call plot(c+2,r+2,color)
|
||||
canl=!(readpix(c,r+1)||readpix(c,r+2))
|
||||
canr=!(readpix(c+3,r+1)||readpix(c+3,r+2))
|
||||
return readpix(c+1,r+3)||readpix(c+2,r+3)
|
||||
endsub
|
||||
|
||||
sub checkframe(byte r)
|
||||
byte rr=r+3
|
||||
if rr>bttm-1
|
||||
rr=bttm-1
|
||||
endif
|
||||
while rr>=r
|
||||
if checkline(rr)
|
||||
pr.ch 7; 'Beep
|
||||
else
|
||||
rr=rr-1
|
||||
endif
|
||||
endwhile
|
||||
endsub
|
||||
|
||||
sub checkline(byte r)
|
||||
byte c=0
|
||||
for c=lhs+1:rhs-1
|
||||
if !readpix(c,r)
|
||||
return 0
|
||||
endif
|
||||
endfor
|
||||
call deleterow(r)
|
||||
return 1
|
||||
endsub
|
||||
|
||||
sub deleterow(byte r)
|
||||
byte i=r
|
||||
byte c=0
|
||||
byte v=0
|
||||
byte empty=0
|
||||
while (i>top+1)&&(!empty)
|
||||
empty=1
|
||||
for c=lhs+1:rhs-1
|
||||
v=readpix(c,i-1)
|
||||
if v
|
||||
empty=0
|
||||
endif
|
||||
call plot(c,i,v)
|
||||
endfor
|
||||
i=i-1
|
||||
endwhile
|
||||
endsub
|
||||
|
Loading…
Reference in New Issue
Block a user