From e29c5808b42e5316258614c9ed9a9e4de28b1cdb Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Sun, 27 Apr 2014 13:41:54 -0700 Subject: [PATCH 01/44] Initial import of PLASMA compiler and portable VM --- PLASMA/src/codegen.c | 775 +++++++++++++++++++++++++ PLASMA/src/codegen.h | 58 ++ PLASMA/src/lex.c | 363 ++++++++++++ PLASMA/src/lex.h | 10 + PLASMA/src/makefile | 42 ++ PLASMA/src/parse.c | 1294 ++++++++++++++++++++++++++++++++++++++++++ PLASMA/src/parse.h | 1 + PLASMA/src/plasm.c | 17 + PLASMA/src/plvm.c | 895 +++++++++++++++++++++++++++++ PLASMA/src/samplib.s | 147 +++++ PLASMA/src/symbols.h | 39 ++ PLASMA/src/test.pla | 40 ++ PLASMA/src/tokens.h | 106 ++++ 13 files changed, 3787 insertions(+) create mode 100755 PLASMA/src/codegen.c create mode 100755 PLASMA/src/codegen.h create mode 100755 PLASMA/src/lex.c create mode 100755 PLASMA/src/lex.h create mode 100755 PLASMA/src/makefile create mode 100755 PLASMA/src/parse.c create mode 100755 PLASMA/src/parse.h create mode 100755 PLASMA/src/plasm.c create mode 100755 PLASMA/src/plvm.c create mode 100755 PLASMA/src/samplib.s create mode 100755 PLASMA/src/symbols.h create mode 100755 PLASMA/src/test.pla create mode 100755 PLASMA/src/tokens.h diff --git a/PLASMA/src/codegen.c b/PLASMA/src/codegen.c new file mode 100755 index 00000000..319872f4 --- /dev/null +++ b/PLASMA/src/codegen.c @@ -0,0 +1,775 @@ +#include +#include "tokens.h" +#include "symbols.h" +#include "codegen.h" +/* + * Symbol table and fixup information. + */ +static int consts = 0; +static int externs = 0; +static int globals = 0; +static int locals = 0; +static int defs = 0; +static int codetags = 0; +static int fixups = 0; +static char idconst_name[1024][17]; +static int idconst_value[1024]; +static char idglobal_name[1024][17]; +static int idglobal_type[1024]; +static int idglobal_tag[1024]; +static int localsize = 0; +static char idlocal_name[128][17]; +static int idlocal_type[128]; +static int idlocal_offset[128]; +static char fixup_size[255]; +static int fixup_type[255]; +static int fixup_tag[255]; +#define FIXUP_BYTE 0x00 +#define FIXUP_WORD 0x80 +int id_match(char *name, int len, char *id) +{ + if (len == id[0]) + { + if (len > 16) len = 16; + while (len--) + { + if (name[len] != id[1 + len]) + return (0); + } + return (1); + } + return (0); +} +int idconst_lookup(char *name, int len) +{ + int i; + for (i = 0; i < consts; i++) + if (id_match(name, len, &(idconst_name[i][0]))) + return (i); + return (-1); +} +int idlocal_lookup(char *name, int len) +{ + int i; + for (i = 0; i < locals; i++) + if (id_match(name, len, &(idlocal_name[i][0]))) + return (i); + return (-1); +} +int idglobal_lookup(char *name, int len) +{ + int i; + for (i = 0; i < globals; i++) + if (id_match(name, len, &(idglobal_name[i][0]))) + return (i); + return (-1); +} +int idconst_add(char *name, int len, int value) +{ + if (consts > 1024) + { + printf("Constant count overflow\n"); + return (0); + } + char c = name[len]; + name[len] = '\0'; + emit_idconst(name, value); + name[len] = c; + idconst_name[consts][0] = len; + if (len > 16) len = 16; + while (len--) + idconst_name[consts][1 + len] = name[len]; + idconst_value[consts] = value; + consts++; + return (1); +} +int idlocal_add(char *name, int len, int type, int size) +{ + if (localsize > 255) + { + printf("Local variable size overflow\n"); + return (0); + } + char c = name[len]; + name[len] = '\0'; + emit_idlocal(name, localsize); + name[len] = c; + idlocal_name[locals][0] = len; + if (len > 16) len = 16; + while (len--) + idlocal_name[locals][1 + len] = name[len]; + idlocal_type[locals] = type | LOCAL_TYPE; + idlocal_offset[locals] = localsize; + localsize += size; + locals++; + return (1); +} +int idglobal_add(char *name, int len, int type, int size) +{ + if (globals > 1024) + { + printf("Global variable count overflow\n"); + return (0); + } + char c = name[len]; + name[len] = '\0'; + name[len] = c; + idglobal_name[globals][0] = len; + if (len > 16) len = 16; + while (len--) + idglobal_name[globals][1 + len] = name[len]; + idglobal_type[globals] = type; + if (!(type & EXTERN_TYPE)) + { + emit_idglobal(globals, size, name); + idglobal_tag[globals] = globals++; + } + else + { + printf("\t\t\t\t\t; %s -> X%03d\n", &idglobal_name[globals][1], externs); + idglobal_tag[globals++] = externs++; + } + return (1); +} +int id_add(char *name, int len, int type, int size) +{ + return ((type & LOCAL_TYPE) ? idlocal_add(name, len, type, size) : idglobal_add(name, len, type, size)); +} +int idfunc_add(char *name, int len, int type, int tag) +{ + if (globals > 1024) + { + printf("Global variable count overflow\n"); + return (0); + } + idglobal_name[globals][0] = len; + if (len > 16) len = 16; + while (len--) + idglobal_name[globals][1 + len] = name[len]; + idglobal_type[globals] = type; + idglobal_tag[globals++] = tag; + if (type & EXTERN_TYPE) + printf("\t\t\t\t\t; %s -> X%03d\n", &idglobal_name[globals - 1][1], tag); + return (1); +} +int idfunc_set(char *name, int len, int type) +{ + int i; + if (((i = idglobal_lookup(name, len)) >= 0) && (idglobal_type[i] & FUNC_TYPE)) + { + idglobal_type[i] = type; + return (idglobal_type[i]); + } + parse_error("Undeclared identifier"); + return (0); +} +void idglobal_size(int type, int size, int constsize) +{ + if (size > constsize) + emit_data(0, 0, 0, size - constsize); + else if (size) + emit_data(0, 0, 0, size); +} +int idlocal_size(void) +{ + return (localsize); +} +void idlocal_reset(void) +{ + locals = 0; + localsize = 2; +} +int id_tag(char *name, int len) +{ + int i; + if ((i = idlocal_lookup(name, len)) >= 0) + return (idlocal_offset[i]); + if ((i = idglobal_lookup(name, len)) >= 0) + return (idglobal_tag[i]); + parse_error("Undeclared identifier"); + return (-1); +} +int id_const(char *name, int len) +{ + int i; + if ((i = idconst_lookup(name, len)) >= 0) + return (idconst_value[i]); + parse_error("Undeclared constant"); + return (0); +} +int id_type(char *name, int len) +{ + int i; + if ((i = idconst_lookup(name, len)) >= 0) + return (CONST_TYPE); + if ((i = idlocal_lookup(name, len)) >= 0) + return (idlocal_type[i] | LOCAL_TYPE); + if ((i = idglobal_lookup(name, len)) >= 0) + return (idglobal_type[i]); + parse_error("Undeclared identifier"); + return (0); +} +int tag_new(int type) +{ + if (type & EXTERN_TYPE) + return (externs++); + if (type & ASM_TYPE) + return (globals); + if (type & DEF_TYPE) + return (defs++); + if (type & BRANCH_TYPE) + return (codetags++); + return globals++; +} +int fixup_new(int tag, int type, int size) +{ + if (fixups > 255) + { + printf("External variable count overflow\n"); + return (0); + } + fixup_tag[fixups] = tag; + fixup_type[fixups] = type; + fixup_size[fixups] = size; + return (fixups++); +} +/* + * Emit assembly code. + */ +#define BYTECODE_SEG 2 +static int outflags = 0; +static char *DB = ".BYTE"; +static char *DW = ".WORD"; +static char *DS = ".RES"; +static char LBL = ':'; +char *tag_string(int tag, int type) +{ + static char str[16]; + char t; + + if (type & EXTERN_TYPE) + t = 'X'; + else if (type & DEF_TYPE) + t = 'C'; + else if (type & ASM_TYPE) + t = 'A'; + else if (type & BRANCH_TYPE) + t = 'B'; + else + t = 'D'; + sprintf(str, "_%c%03d", t, tag); + return str; +} +void emit_flags(int flags) +{ + outflags = flags; + if (outflags & ACME) + { + DB = "!BYTE"; + DW = "!WORD"; + DS = "!FILL"; + LBL = ' '; + } +} +void emit_header(void) +{ + if (outflags & ACME) + printf("; ACME COMPATIBLE OUTPUT\n"); + else + printf("; CA65 COMPATIBLE OUTPUT\n"); + printf("_SEGBEGIN%c\n", LBL); + printf("\t%s\t_SEGEND-_SEGBEGIN\t; LENGTH OF HEADER + CODE/DATA + BYTECODE SEGMENT\n", DW); + printf("\t%s\t$DA7E\t\t\t; MAGIC #\n", DW); + printf("\t%s\t_SUBSEG\t\t\t; BYTECODE SUB-SEGMENT\n", DW); +} +void emit_trailer(void) +{ + if (!(outflags & BYTECODE_SEG)) + emit_bytecode_seg(); + printf("_SEGEND%c\n", LBL); +} +char *supper(char *s) +{ + static char su[80]; + int i; + for (i = 0; s[i]; i++) + su[i] = toupper(s[i]); + su[i] = '\0'; + return su; +} +void emit_dci(char *str, int len) +{ + if (len--) + { + printf("\t; DCI STRING: %s\n", supper(str)); + printf("\t%s\t$%02X", DB, toupper(*str++) | (len ? 0x80 : 0x00)); + while (len--) + printf(",$%02X", toupper(*str++) | (len ? 0x80 : 0x00)); + printf("\n"); + } +} +void emit_moddep(char *name, int len) +{ + if (name) + emit_dci(name, len); + else + printf("\t%s\t$00\t\t\t; END OF MODULE DEPENDENCIES\n", DB); +} +void emit_bytecode_seg(void) +{ + if (!(outflags & BYTECODE_SEG)) + printf("_SUBSEG%c\t\t\t\t; BYTECODE STARTS\n", LBL); + outflags |= BYTECODE_SEG; +} +void emit_comment(char *s) +{ + printf("\t\t\t\t\t; %s\n", s); +} +void emit_asm(char *s) +{ + printf("%s\n", s); +} +void emit_idlocal(char *name, int value) +{ + printf("\t\t\t\t\t; %s -> [%d]\n", name, value); +} +void emit_idglobal(int tag, int size, char *name) +{ + if (size == 0) + printf("_D%03d%c\t\t\t\t\t; %s\n", tag, LBL, name); + else + printf("_D%03d%c\t%s\t%d\t\t\t; %s\n", tag, LBL, DS, size, name); +} +void emit_idfunc(int tag, int type, char *name) +{ + printf("%s%c\t\t\t\t\t; %s()\n", tag_string(tag, type), LBL, name); +} +void emit_idconst(char *name, int value) +{ + printf("\t\t\t\t\t; %s = %d\n", name, value); +} +int emit_data(int vartype, int consttype, long constval, int constsize) +{ + int datasize, i; + char *str; + if (consttype == 0) + { + datasize = constsize; + printf("\t%s\t$%02X\n", DS, constsize); + } + else if (consttype & STRING_TYPE) + { + datasize = constsize; + str = (char *)constval; + printf("\t%s\t$%02X\n", DB, --constsize); + while (constsize-- > 0) + { + printf("\t%s\t$%02X", DB, *str++); + for (i = 0; i < 7; i++) + { + if (constsize-- > 0) + printf(",$%02X", *str++); + else + break; + } + printf("\n"); + } + } + else if (consttype & ADDR_TYPE) + { + if (vartype == WORD_TYPE) + { + int fixup = fixup_new(constval, consttype, FIXUP_WORD); + datasize = 2; + if (consttype & EXTERN_TYPE) + printf("_F%03d%c\t%s\t0\t\t\t; %s\n", fixup, LBL, DW, tag_string(constval, consttype)); + else + printf("_F%03d%c\t%s\t%s\n", fixup, LBL, DW, tag_string(constval, consttype)); + } + else + { + int fixup = fixup_new(constval, consttype, FIXUP_BYTE); + datasize = 1; + if (consttype & EXTERN_TYPE) + printf("_F%03d%c\t%s\t0\t\t\t; %s\n", fixup, LBL, DB, tag_string(constval, consttype)); + else + printf("_F%03d%c\t%s\t%s\n", fixup, LBL, DB, tag_string(constval, consttype)); + } + } + else + { + if (vartype == WORD_TYPE) + { + datasize = 2; + printf("\t%s\t$%04lX\n", DW, constval & 0xFFFF); + } + else + { + datasize = 1; + printf("\t%s\t$%02lX\n", DB, constval & 0xFF); + } + } + return (datasize); +} +void emit_codetag(int tag) +{ + printf("_B%03d%c\n", tag, LBL); +} +void emit_const(int cval) +{ + if (cval == 0) + printf("\t%s\t$00\t\t\t; ZERO\n", DB); + else if (cval > 0 && cval < 256) + printf("\t%s\t$2A,$%02X\t\t\t; CB\t%d\n", DB, cval, cval); + else + printf("\t%s\t$2C,$%02X,$%02X\t\t; CW\t%d\n", DB, cval&0xFF,(cval>>8)&0xFF, cval); +} +void emit_lb(void) +{ + printf("\t%s\t$60\t\t\t; LB\n", DB); +} +void emit_lw(void) +{ + printf("\t%s\t$62\t\t\t; LW\n", DB); +} +void emit_llb(int index) +{ + printf("\t%s\t$64,$%02X\t\t\t; LLB\t[%d]\n", DB, index, index); +} +void emit_llw(int index) +{ + printf("\t%s\t$66,$%02X\t\t\t; LLW\t[%d]\n", DB, index, index); +} +void emit_lab(int tag, int type) +{ + int fixup = fixup_new(tag, type, FIXUP_WORD); + char *taglbl = tag_string(tag, type); + printf("\t%s\t$68\t\t\t; LAB\t%s\n", DB, taglbl); + printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl); +} +void emit_law(int tag, int type) +{ + int fixup = fixup_new(tag, type, FIXUP_WORD); + char *taglbl = tag_string(tag, type); + printf("\t%s\t$6A\t\t\t; LAW\t%s\n", DB, taglbl); + printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl); +} +void emit_sb(void) +{ + printf("\t%s\t$70\t\t\t; SB\n", DB); +} +void emit_sw(void) +{ + printf("\t%s\t$72\t\t\t; SW\n", DB); +} +void emit_slb(int index) +{ + printf("\t%s\t$74,$%02X\t\t\t; SLB\t[%d]\n", DB, index, index); +} +void emit_slw(int index) +{ + printf("\t%s\t$76,$%02X\t\t\t; SLW\t[%d]\n", DB, index, index); +} +void emit_dlb(int index) +{ + printf("\t%s\t$6C,$%02X\t\t\t; DLB\t[%d]\n", DB, index, index); +} +void emit_dlw(int index) +{ + printf("\t%s\t$6E,$%02X\t\t\t; DLW\t[%d]\n", DB, index, index); +} +void emit_sab(int tag, int type) +{ + int fixup = fixup_new(tag, type, FIXUP_WORD); + char *taglbl = tag_string(tag, type); + printf("\t%s\t$78\t\t\t; SAB\t%s\n", DB, taglbl); + printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl); +} +void emit_saw(int tag, int type) +{ + int fixup = fixup_new(tag, type, FIXUP_WORD); + char *taglbl = tag_string(tag, type); + printf("\t%s\t$7A\t\t\t; SAW\t%s\n", DB, taglbl); + printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl); +} +void emit_dab(int tag, int type) +{ + int fixup = fixup_new(tag, type, FIXUP_WORD); + char *taglbl = tag_string(tag, type); + printf("\t%s\t$7C\t\t\t; DAB\t%s\n", DB, taglbl); + printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl); +} +void emit_daw(int tag, int type) +{ + int fixup = fixup_new(tag, type, FIXUP_WORD); + char *taglbl = tag_string(tag, type); + printf("\t%s\t$7E\t\t\t; DAW\t%s\n", DB, taglbl); + printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl); +} +void emit_localaddr(int index) +{ + printf("\t%s\t$28,$%02X\t\t\t; LLA\t[%d]\n", DB, index, index); +} +void emit_globaladdr(int tag, int type) +{ + int fixup = fixup_new(tag, type, FIXUP_WORD); + char *taglbl = tag_string(tag, type); + printf("\t%s\t$26\t\t\t; LA\t%s\n", DB, taglbl); + printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl); +} +void emit_globaladdrofst(int tag, int ofst, int type) +{ + int fixup = fixup_new(tag, type, FIXUP_WORD); + char *taglbl = tag_string(tag, type); + printf("\t%s\t$26\t\t\t; LA\t%s+%d\n", DB, taglbl, ofst); + printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "" : taglbl, ofst); +} +void emit_indexbyte(void) +{ + printf("\t%s\t$02\t\t\t; IDXB\n", DB); +} +void emit_indexword(void) +{ + printf("\t%s\t$1E\t\t\t; IDXW\n", DB); +} +void emit_brfls(int tag) +{ + printf("\t%s\t$4C\t\t\t; BRFLS\t_B%03d\n", DB, tag); + printf("\t%s\t_B%03d-*\n", DW, tag); +} +void emit_brtru(int tag) +{ + printf("\t%s\t$4E\t\t\t; BRTRU\t_B%03d\n", DB, tag); + printf("\t%s\t_B%03d-*\n", DW, tag); +} +void emit_brnch(int tag) +{ + printf("\t%s\t$50\t\t\t; BRNCH\t_B%03d\n", DB, tag); + printf("\t%s\t_B%03d-*\n", DW, tag); +} +void emit_breq(int tag) +{ + printf("\t%s\t$3C\t\t\t; BREQ\t_B%03d\n", DB, tag); + printf("\t%s\t_B%03d-*\n", DW, tag); +} +void emit_brne(int tag) +{ + printf("\t%s\t$3E\t\t\t; BRNE\t_B%03d\n", DB, tag); + printf("\t%s\t_B%03d-*\n", DW, tag); +} +void emit_brlt(int tag) +{ + printf("\t%s\t$38\t\t\t; BRLT\t_B%03d\n", DB, tag); + printf("\t%s\t_B%03d-*\n", DW, tag); +} +void emit_brgt(int tag) +{ + printf("\t%s\t$3A\t\t\t; BRGT\t_B%03d\n", DB, tag); + printf("\t%s\t_B%03d-*\n", DW, tag); +} +void emit_call(int tag, int type) +{ + int fixup = fixup_new(tag, type, FIXUP_WORD); + char *taglbl = tag_string(tag, type); + printf("\t%s\t$54\t\t\t; CALL\t%s\n", DB, taglbl); + printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl); +} +void emit_ical(void) +{ + printf("\t%s\t$56\t\t\t; ICAL\n", DB); +} +void emit_leave(int framesize) +{ + if (framesize > 2) + printf("\t%s\t$5A\t\t\t; LEAVE\n", DB); + else + printf("\t%s\t$5C\t\t\t; RET\n", DB); +} +void emit_ret(void) +{ + printf("\t%s\t$5C\t\t\t; RET\n", DB); +} +void emit_def(int defopt) +{ +} +void emit_enter(int framesize, int cparams) +{ + if (framesize > 2) + printf("\t%s\t$58,$%02X,$%02X\t\t; ENTER\t%d,%d\n", DB, framesize, cparams, framesize, cparams); +} +void emit_start(void) +{ +} +void emit_dup(void) +{ + printf("\t%s\t$32\t\t\t; DUP\n", DB); +} +void emit_push(void) +{ + printf("\t%s\t$34\t\t\t; PUSH\n", DB); +} +void emit_pull(void) +{ + printf("\t%s\t$36\t\t\t; PULL\n", DB); +} +void emit_swap(void) +{ + printf("\t%s\t$2E\t\t\t; SWAP\n", DB); +} +void emit_drop(void) +{ + printf("\t%s\t$30\t\t\t; DROP\n", DB); +} +int emit_unaryop(int op) +{ + switch (op) + { + case NEG_TOKEN: + printf("\t%s\t$10\t\t\t; NEG\n", DB); + break; + case COMP_TOKEN: + printf("\t%s\t$12\t\t\t; COMP\n", DB); + break; + case LOGIC_NOT_TOKEN: + printf("\t%s\t$20\t\t\t; NOT\n", DB); + break; + case INC_TOKEN: + printf("\t%s\t$0C\t\t\t; INCR\n", DB); + break; + case DEC_TOKEN: + printf("\t%s\t$0E\t\t\t; DECR\n", DB); + break; + case BPTR_TOKEN: + emit_lb(); + break; + case WPTR_TOKEN: + emit_lw(); + break; + default: + printf("emit_unaryop(%c) ???\n", op & 0x7F); + return (0); + } + return (1); +} +int emit_op(t_token op) +{ + switch (op) + { + case MUL_TOKEN: + printf("\t%s\t$06\t\t\t; MUL\n", DB); + break; + case DIV_TOKEN: + printf("\t%s\t$08\t\t\t; DIV\n", DB); + break; + case MOD_TOKEN: + printf("\t%s\t$0A\t\t\t; MOD\n", DB); + break; + case ADD_TOKEN: + printf("\t%s\t$02\t\t\t; ADD\n", DB); + break; + case SUB_TOKEN: + printf("\t%s\t$04\t\t\t; SUB\n", DB); + break; + case SHL_TOKEN: + printf("\t%s\t$1A\t\t\t; SHL\n", DB); + break; + case SHR_TOKEN: + printf("\t%s\t$1C\t\t\t; SHR\n", DB); + break; + case AND_TOKEN: + printf("\t%s\t$14\t\t\t; AND\n", DB); + break; + case OR_TOKEN: + printf("\t%s\t$16\t\t\t; IOR\n", DB); + break; + case EOR_TOKEN: + printf("\t%s\t$18\t\t\t; XOR\n", DB); + break; + case EQ_TOKEN: + printf("\t%s\t$40\t\t\t; ISEQ\n", DB); + break; + case NE_TOKEN: + printf("\t%s\t$42\t\t\t; ISNE\n", DB); + break; + case GE_TOKEN: + printf("\t%s\t$48\t\t\t; ISGE\n", DB); + break; + case LT_TOKEN: + printf("\t%s\t$46\t\t\t; ISLT\n", DB); + break; + case GT_TOKEN: + printf("\t%s\t$44\t\t\t; ISGT\n", DB); + break; + case LE_TOKEN: + printf("\t%s\t$4A\t\t\t; ISLE\n", DB); + break; + case LOGIC_OR_TOKEN: + printf("\t%s\t$22\t\t\t; LOR\n", DB); + break; + case LOGIC_AND_TOKEN: + printf("\t%s\t$24\t\t\t; LAND\n", DB); + break; + case COMMA_TOKEN: + break; + default: + return (0); + } + return (1); +} +void emit_rld(void) +{ + int i; + + printf(";\n; RE-LOCATEABLE DICTIONARY\n;\n"); + /* + * First emit the bytecode definition entrypoint information. + */ + for (i = 0; i < globals; i++) + if (!(idglobal_type[i] & EXTERN_TYPE) && (idglobal_type[i] & DEF_TYPE)) + { + printf("\t%s\t$02\t\t\t; CODE TABLE FIXUP\n", DB); + printf("\t%s\t_C%03d\t\t\n", DW, idglobal_tag[i]); + printf("\t%s\t$00\n", DB); + } + /* + * Now emit the fixup table. + */ + for (i = 0; i < fixups; i++) + { + if (fixup_type[i] & EXTERN_TYPE) + { + printf("\t%s\t$%02X\t\t\t; EXTERNAL FIXUP\n", DB, 0x11 + fixup_size[i]); + printf("\t%s\t_F%03d\t\t\n", DW, i); + printf("\t%s\t%d\t\t\t; ESD INDEX\n", DB, fixup_tag[i]); + } + else + { + printf("\t%s\t$%02X\t\t\t; INTERNAL FIXUP\n", DB, 0x01 + fixup_size[i]); + printf("\t%s\t_F%03d\t\t\n", DW, i); + printf("\t%s\t$00\n", DB); + } + } + printf("\t%s\t$00\t\t\t; END OF RLD\n", DB); +} +void emit_esd(void) +{ + int i; + + printf(";\n; EXTERNAL/ENTRY SYMBOL DICTIONARY\n;\n"); + for (i = 0; i < globals; i++) + { + if (idglobal_type[i] & EXTERN_TYPE) + { + emit_dci(&idglobal_name[i][1], idglobal_name[i][0]); + printf("\t%s\t$10\t\t\t; EXTERNAL SYMBOL FLAG\n", DB); + printf("\t%s\t%d\t\t\t; ESD INDEX\n", DW, idglobal_tag[i]); + } + else if (idglobal_type[i] & EXPORT_TYPE) + { + emit_dci(&idglobal_name[i][1], idglobal_name[i][0]); + printf("\t%s\t$08\t\t\t; ENTRY SYMBOL FLAG\n", DB); + printf("\t%s\t%s\t\t\n", DW, tag_string(idglobal_tag[i], idglobal_type[i])); + } + } + printf("\t%s\t$00\t\t\t; END OF ESD\n", DB); +} \ No newline at end of file diff --git a/PLASMA/src/codegen.h b/PLASMA/src/codegen.h new file mode 100755 index 00000000..667edee8 --- /dev/null +++ b/PLASMA/src/codegen.h @@ -0,0 +1,58 @@ +#define ACME 1 +void emit_flags(int flags); +void emit_header(void); +void emit_trailer(void); +void emit_moddep(char *name, int len); +void emit_bytecode_seg(void); +void emit_comment(char *s); +void emit_asm(char *s); +void emit_idlocal(char *name, int value); +void emit_idglobal(int value, int size, char *name); +void emit_idfunc(int tag, int type, char *name); +void emit_idconst(char *name, int value); +int emit_data(int vartype, int consttype, long constval, int constsize); +void emit_codetag(int tag); +void emit_const(int cval); +void emit_lb(void); +void emit_lw(void); +void emit_llb(int index); +void emit_llw(int index); +void emit_lab(int tag, int type); +void emit_law(int tag, int type); +void emit_sb(void); +void emit_sw(void); +void emit_slb(int index); +void emit_slw(int index); +void emit_dlb(int index); +void emit_dlw(int index); +void emit_sab(int tag, int type); +void emit_saw(int tag, int type); +void emit_dab(int tag, int type); +void emit_daw(int tag, int type); +void emit_call(int tag, int type); +void emit_ical(void); +void emit_localaddr(int index); +void emit_globaladdr(int tag, int type); +void emit_globaladdrofst(int tag, int offset, int type); +void emit_indexbyte(void); +void emit_indexword(void); +int emit_unaryop(int op); +int emit_op(t_token op); +void emit_brtru(int tag); +void emit_brfls(int tag); +void emit_brgt(int tag); +void emit_brlt(int tag); +void emit_brne(int tag); +void emit_brnch(int tag); +void emit_swap(void); +void emit_dup(void); +void emit_push(void); +void emit_pull(void); +void emit_drop(void); +void emit_leave(int framesize); +void emit_ret(void); +void emit_def(int defopt); +void emit_enter(int framesize, int cparams); +void emit_start(void); +void emit_rld(void); +void emit_esd(void); diff --git a/PLASMA/src/lex.c b/PLASMA/src/lex.c new file mode 100755 index 00000000..6ae5e85d --- /dev/null +++ b/PLASMA/src/lex.c @@ -0,0 +1,363 @@ +#include +#include +#include "tokens.h" +#include "symbols.h" + +char *statement, *scanpos, *tokenstr; +t_token scantoken, prevtoken; +int tokenlen; +long constval; +int lineno = 0; +t_token keywords[] = { + IF_TOKEN, 'I', 'F', + ELSE_TOKEN, 'E', 'L', 'S', 'E', + ELSEIF_TOKEN, 'E', 'L', 'S', 'I', 'F', + FIN_TOKEN, 'F', 'I', 'N', + WHILE_TOKEN, 'W', 'H', 'I', 'L', 'E', + LOOP_TOKEN, 'L', 'O', 'O', 'P', + CASE_TOKEN, 'W', 'H', 'E', 'N', + OF_TOKEN, 'I', 'S', + DEFAULT_TOKEN, 'O', 'T', 'H', 'E', 'R', 'W', 'I', 'S', 'E', + ENDCASE_TOKEN, 'W', 'E', 'N', 'D', + FOR_TOKEN, 'F', 'O', 'R', + TO_TOKEN, 'T', 'O', + DOWNTO_TOKEN, 'D', 'O', 'W', 'N', 'T', 'O', + STEP_TOKEN, 'S', 'T', 'E', 'P', + NEXT_TOKEN, 'N', 'E', 'X', 'T', + REPEAT_TOKEN, 'R', 'E', 'P', 'E', 'A', 'T', + UNTIL_TOKEN, 'U', 'N', 'T', 'I', 'L', + BREAK_TOKEN, 'B', 'R', 'E', 'A', 'K', + ASM_TOKEN, 'A', 'S', 'M', + DEF_TOKEN, 'D', 'E', 'F', + EXPORT_TOKEN, 'E', 'X', 'P', 'O', 'R', 'T', + IMPORT_TOKEN, 'I', 'M', 'P', 'O', 'R', 'T', + RETURN_TOKEN, 'R', 'E', 'T', 'U', 'R', 'N', + END_TOKEN, 'E', 'N', 'D', + START_TOKEN, 'S', 'T', 'A', 'R', 'T', + EXIT_TOKEN, 'E', 'X', 'I', 'T', + DONE_TOKEN, 'D', 'O', 'N', 'E', + LOGIC_NOT_TOKEN, 'N', 'O', 'T', + LOGIC_AND_TOKEN, 'A', 'N', 'D', + LOGIC_OR_TOKEN, 'O', 'R', + BYTE_TOKEN, 'B', 'Y', 'T', 'E', + WORD_TOKEN, 'W', 'O', 'R', 'D', + CONST_TOKEN, 'C', 'O', 'N', 'S', 'T', + PREDEF_TOKEN, 'P', 'R', 'E', 'D', 'E', 'F', + EOL_TOKEN +}; + +void parse_error(char *errormsg) +{ + char *error_carrot = statement; + + fprintf(stderr, "\n%4d: %s\n ", lineno, statement); + for (error_carrot = statement; error_carrot != tokenstr; error_carrot++) + putc(*error_carrot == '\t' ? '\t' : ' ', stderr); + fprintf(stderr, "^\nError: %s\n", errormsg); + exit(1); +} +t_token scan(void) +{ + prevtoken = scantoken; + /* + * Skip whitespace. + */ + while (*scanpos && (*scanpos == ' ' || *scanpos == '\t')) scanpos++; + tokenstr = scanpos; + /* + * Scan for token based on first character. + */ + if (*scanpos == '\0' || *scanpos == '\n' || *scanpos == ';') + scantoken = EOL_TOKEN; + else if ((scanpos[0] >= 'a' && scanpos[0] <= 'z') + || (scanpos[0] >= 'A' && scanpos[0] <= 'Z') + || (scanpos[0] == '_')) + { + /* + * ID, either variable name or reserved word. + */ + int keypos = 0, matchpos = 0; + + do + { + scanpos++; + } + while ((*scanpos >= 'a' && *scanpos <= 'z') + || (*scanpos >= 'A' && *scanpos <= 'Z') + || (*scanpos == '_') + || (*scanpos >= '0' && *scanpos <= '9')); + scantoken = ID_TOKEN; + tokenlen = scanpos - tokenstr; + /* + * Search for matching keyword. + */ + while (keywords[keypos] != EOL_TOKEN) + { + while (keywords[keypos + 1 + matchpos] == toupper(tokenstr[matchpos])) + matchpos++; + if (IS_TOKEN(keywords[keypos + 1 + matchpos]) && (matchpos == tokenlen)) + { + /* + * A match. + */ + scantoken = keywords[keypos]; + break; + } + else + { + /* + * Find next keyword. + */ + keypos += matchpos + 1; + matchpos = 0; + while (!IS_TOKEN(keywords[keypos])) keypos++; + } + } + } + else if (scanpos[0] >= '0' && scanpos[0] <= '9') + { + /* + * Number constant. + */ + for (constval = 0; *scanpos >= '0' && *scanpos <= '9'; scanpos++) + constval = constval * 10 + *scanpos - '0'; + scantoken = INT_TOKEN; + } + else if (scanpos[0] == '$') + { + /* + * Hexadecimal constant. + */ + constval = 0; + while (scanpos++) + { + if (*scanpos >= '0' && *scanpos <= '9') + constval = constval * 16 + *scanpos - '0'; + else if (*scanpos >= 'A' && *scanpos <= 'F') + constval = constval * 16 + *scanpos - 'A' + 10; + else if (*scanpos >= 'a' && *scanpos <= 'f') + constval = constval * 16 + *scanpos - 'a' + 10; + else + break; + } + scantoken = INT_TOKEN; + } + else if (scanpos[0] == '\'') + { + /* + * Character constant. + */ + scantoken = CHAR_TOKEN; + if (scanpos[1] != '\\') + { + constval = scanpos[1]; + if (scanpos[2] != '\'') + { + parse_error("Bad character constant"); + return (-1); + } + scanpos += 3; + } + else + { + switch (scanpos[2]) + { + case 'n': + constval = '\n'; + break; + case 'r': + constval = '\r'; + break; + case 't': + constval = '\t'; + break; + case '\'': + constval = '\''; + break; + case '\\': + constval = '\\'; + break; + case '0': + constval = '\0'; + break; + default: + parse_error("Bad character constant"); + return (-1); + } + if (scanpos[3] != '\'') + { + parse_error("Bad character constant"); + return (-1); + } + scanpos += 4; + } + } + else if (scanpos[0] == '\"') + { + char *scanshift; + /* + * String constant. + */ + scantoken = STRING_TOKEN; + constval = (long)++scanpos; + while (*scanpos && *scanpos != '\"') + { + if (*scanpos == '\\') + { + switch (scanpos[1]) + { + case 'n': + *scanpos = '\n'; + break; + case 'r': + *scanpos = '\r'; + break; + case 't': + *scanpos = '\t'; + break; + case '\'': + *scanpos = '\''; + break; + case '\\': + *scanpos = '\\'; + break; + case '0': + *scanpos = '\0'; + break; + default: + parse_error("Bad string constant"); + return (-1); + } + for (scanshift = scanpos + 1; *scanshift; scanshift++) + scanshift[0] = scanshift[1]; + } + else + scanpos++; + } + if (!*scanpos++) + { + parse_error("Unterminated string"); + return (-1); + } + } + else + { + /* + * Potential two and three character tokens. + */ + switch (scanpos[0]) + { + case '>': + if (scanpos[1] == '>') + { + scantoken = SHR_TOKEN; + scanpos += 2; + } + else if (scanpos[1] == '=') + { + scantoken = GE_TOKEN; + scanpos += 2; + } + else + { + scantoken = GT_TOKEN; + scanpos++; + } + break; + case '<': + if (scanpos[1] == '<') + { + scantoken = SHL_TOKEN; + scanpos += 2; + } + else if (scanpos[1] == '=') + { + scantoken = LE_TOKEN; + scanpos += 2; + } + else if (scanpos[1] == '>') + { + scantoken = NE_TOKEN; + scanpos += 2; + } + else + { + scantoken = LT_TOKEN; + scanpos++; + } + break; + case '=': + if (scanpos[1] == '=') + { + scantoken = EQ_TOKEN; + scanpos += 2; + } + else + { + scantoken = SET_TOKEN; + scanpos++; + } + break; + case '+': + if (scanpos[1] == '+') + { + scantoken = INC_TOKEN; + scanpos += 2; + } + else + { + scantoken = ADD_TOKEN; + scanpos++; + } + break; + case '-': + if (scanpos[1] == '-') + { + scantoken = DEC_TOKEN; + scanpos += 2; + } + else + { + scantoken = SUB_TOKEN; + scanpos++; + } + break; + default: + /* + * Simple single character tokens. + */ + scantoken = TOKEN(*scanpos++); + } + } + tokenlen = scanpos - tokenstr; + return (scantoken); +} +void scan_rewind(char *backptr) +{ + scanpos = backptr; +} +int scan_lookahead(void) +{ + char *backpos = scanpos; + char *backstr = tokenstr; + int prevtoken = scantoken; + int prevlen = tokenlen; + int look = scan(); + scanpos = backpos; + tokenstr = backstr; + scantoken = prevtoken; + tokenlen = prevlen; + return (look); +} +char inputline[512]; +int next_line(void) +{ + gets(inputline); + lineno++; + statement = inputline; + scanpos = inputline; + scantoken = EOL_TOKEN; + scan(); + printf("; %03d: %s\n", lineno, inputline); + return (1); +} diff --git a/PLASMA/src/lex.h b/PLASMA/src/lex.h new file mode 100755 index 00000000..5bfbda75 --- /dev/null +++ b/PLASMA/src/lex.h @@ -0,0 +1,10 @@ +extern char *statement, *scanpos, *tokenstr; +extern t_token scantoken, prevtoken; +extern int tokenlen; +extern long constval; +extern char inputline[]; +void parse_error(char *errormsg); +int next_line(void); +void scan_rewind(char *backptr); +int scan_lookahead(void); +t_token scan(void); diff --git a/PLASMA/src/makefile b/PLASMA/src/makefile new file mode 100755 index 00000000..d94909d2 --- /dev/null +++ b/PLASMA/src/makefile @@ -0,0 +1,42 @@ +.SUFFIXES = +AFLAGS = -o $@ +LFLAGS = -C default.cfg +PLVM = plvm +PLASM = plasm +INCS = tokens.h symbols.h lex.h parse.h codegen.h +OBJS = plasm.c parse.o lex.o codegen.o +# +# Image filetypes for Virtual ][ +# +PLATYPE = .\$$ED +BINTYPE = .BIN +SYSTYPE = .SYS +TXTTYPE = .TXT +# +# Image filetypes for CiderPress +# +#PLATYPE = \#ed0000 +#BINTYPE = \#060000 +#SYSTYPE = \#ff0000 +#TXTTYPE = \#040000 + +all: $(PLASM) $(PLVM) + +clean: + -rm *.o *~ *.a *.BIN + +$(PLASM): $(OBJS) $(INCS) + cc $(OBJS) -o $(PLASM) + +$(PLVM): plvm.c + cc plvm.c -o $(PLVM) + +test: test.pla $(PLVM) $(PLASM) + ./$(PLASM) -A < test.pla > test.a + acme --setpc 4096 -o TEST.BIN test.a + ./$(PLVM) TEST.BIN MAIN + +debug: test.pla $(PLVM) $(PLASM) + ./$(PLASM) -A < test.pla > test.a + acme --setpc 4096 -o TEST.BIN test.a + ./$(PLVM) -s TEST.BIN MAIN diff --git a/PLASMA/src/parse.c b/PLASMA/src/parse.c new file mode 100755 index 00000000..e49d90de --- /dev/null +++ b/PLASMA/src/parse.c @@ -0,0 +1,1294 @@ +#include +#include "tokens.h" +#include "symbols.h" +#include "lex.h" +#include "codegen.h" +#include "parse.h" + +int infunc = 0, break_tag = 0, stack_loop = 0; +t_token prevstmnt; + +t_token binary_ops_table[] = { + /* Highest precedence */ + MUL_TOKEN, DIV_TOKEN, MOD_TOKEN, + ADD_TOKEN, SUB_TOKEN, + SHR_TOKEN, SHL_TOKEN, + AND_TOKEN, + EOR_TOKEN, + OR_TOKEN, + GT_TOKEN, GE_TOKEN, LT_TOKEN, LE_TOKEN, + EQ_TOKEN, NE_TOKEN, + LOGIC_AND_TOKEN, + LOGIC_OR_TOKEN + /* Lowest precedence */ +}; +t_token binary_ops_precedence[] = { + /* Highest precedence */ + 1, 1, 1, + 2, 2, + 3, 3, + 4, + 5, + 6, + 7, 7, 7, 7, + 8, 8, + 9, + 10 + /* Lowest precedence */ +}; + +t_token opstack[16]; +int precstack[16]; +int opsptr = -1; +void push_op(t_token op, int prec) +{ + if (++opsptr == 16) + { + parse_error("Stack overflow\n"); + return; + } + opstack[opsptr] = op; + precstack[opsptr] = prec; +} +t_token pop_op(void) +{ + if (opsptr < 0) + { + parse_error("Stack underflow\n"); + return (0); + } + return opstack[opsptr--]; +} +t_token tos_op(void) +{ + return opsptr < 0 ? 0 : opstack[opsptr]; +} +int tos_op_prec(int tos) +{ + return opsptr <= tos ? 100 : precstack[opsptr]; +} +int parse_expr(void); +int parse_term(void) +{ + /* + * Parse terminal tokens. + */ + switch (scan()) + { + case CHAR_TOKEN: + case INT_TOKEN: + case FLOAT_TOKEN: + case ID_TOKEN: + case STRING_TOKEN: + break; + case OPEN_PAREN_TOKEN: + if (!parse_expr()) + { + parse_error("Bad expression in parenthesis"); + return (0); + } + if (scantoken != CLOSE_PAREN_TOKEN) + { + parse_error("Missing closing parenthesis"); + return (0); + } + break; + default: + /* + * Non-terminal token. + */ + return (0); + } + return (1); +} +int parse_constval(long *value, int *size) +{ + int mod = 0, type = 0; + *value = 0; + while (!parse_term()) + { + switch (scantoken) + { + case ADD_TOKEN: + /* + * Just ignore unary plus, it is a no-op. + */ + break; + case NEG_TOKEN: + mod |= 1; + break; + case COMP_TOKEN: + mod |= 2; + break; + case LOGIC_NOT_TOKEN: + mod |= 4; + break; + case AT_TOKEN: + mod |= 8; + break; + default: + return (0); + } + } + /* + * Determine which terminal type. + */ + if (scantoken == STRING_TOKEN) + { + *value = constval; + *size = tokenlen - 1; + type = STRING_TYPE; + if (mod) + { + parse_error("Invalid string modifiers"); + return (0); + } + } + else if (scantoken == CHAR_TOKEN) + { + *value = constval; + *size = 1; + type = CONST_TYPE; + } + else if (scantoken == INT_TOKEN) + { + *value = constval; + *size = 2; + type = CONST_TYPE; + } + else if (scantoken == ID_TOKEN) + { + type = id_type(tokenstr, tokenlen); + if (type & CONST_TYPE) + *value = id_const(tokenstr, tokenlen); + else if ((type & (FUNC_TYPE | EXTERN_TYPE)) || ((type & ADDR_TYPE) && (mod & 8))) + *value = id_tag(tokenstr, tokenlen); + else + { + parse_error("Invalid constant"); + return (0); + } + } + else + { + parse_error("Invalid constant"); + return (0); + } + if (mod & 1) + *value = -*value; + if (mod & 2) + *value = ~*value; + if (mod & 4) + *value = *value ? 0 : -1; + return (type); +} +int parse_value(int rvalue) +{ + int cparams; + int deref = rvalue; + int optos = opsptr; + int type = 0, value = 0, emit_value = 0; + /* + * Parse pre operand operators. + */ + while (!parse_term()) + { + switch (scantoken) + { + case ADD_TOKEN: + /* + * Just ignore unary plus, it is a no-op. + */ + break; + case BPTR_TOKEN: + if (deref) + push_op(scantoken, 0); + else + { + type |= BPTR_TYPE; + deref++; + } + break; + case WPTR_TOKEN: + if (deref) + push_op(scantoken, 0); + else + { + type |= WPTR_TYPE; + deref++; + } + break; + case AT_TOKEN: + deref--; + break; + case NEG_TOKEN: + case COMP_TOKEN: + case LOGIC_NOT_TOKEN: + push_op(scantoken, 0); + break; + default: + return (0); + } + } + /* + * Determine which terminal type. + */ + if (scantoken == INT_TOKEN || scantoken == CHAR_TOKEN) + { + value = constval; + type |= CONST_TYPE; + } + else if (scantoken == ID_TOKEN) + { + if ((type |= id_type(tokenstr, tokenlen)) & CONST_TYPE) + value = id_const(tokenstr, tokenlen); + else if (type & VAR_TYPE) + value = id_tag(tokenstr, tokenlen); + else if (type & FUNC_TYPE) + value = id_tag(tokenstr, tokenlen); + else + { + printf("Bad ID type\n"); + return (0); + } + } + else if (scantoken == CLOSE_PAREN_TOKEN) + { + // type |= WORD_TYPE; + emit_value = 1; + } + else + return (0); + if (type & CONST_TYPE) + { + /* + * Quick optimizations + */ + while ((optos < opsptr) + && ((tos_op() == NEG_TOKEN) || (tos_op() == COMP_TOKEN) || (tos_op() == LOGIC_NOT_TOKEN))) + { + switch (pop_op()) + { + case NEG_TOKEN: + value = -value; + break; + case COMP_TOKEN: + value = ~value; + break; + case LOGIC_NOT_TOKEN: + value = value ? 0 : -1; + break; + } + } + } + /* + * Parse post operand operators. + */ + while (scan() == OPEN_PAREN_TOKEN + || scantoken == OPEN_BRACKET_TOKEN + || scantoken == DOT_TOKEN + || scantoken == COLON_TOKEN) + { + if (scantoken == OPEN_BRACKET_TOKEN) + { + /* + * Array + */ + if (!emit_value) + { + if (type & ADDR_TYPE) + { + if (type & LOCAL_TYPE) + emit_localaddr(value); + else + emit_globaladdr(value, type); + } + else if (type & CONST_TYPE) + { + emit_const(value); + } + emit_value = 1; + } + if (type & PTR_TYPE) + emit_lw(); + if (!parse_expr()) + { + parse_error("Bad expression"); + return (0); + } + if (scantoken != CLOSE_BRACKET_TOKEN) + { + parse_error("Missing closing bracket"); + return (0); + } + if (type & WORD_TYPE) + { + //type |= WPTR_TYPE; + type = WPTR_TYPE; + emit_indexword(); + } + else + { + //type |= BPTR_TYPE; + type = BPTR_TYPE; + emit_indexbyte(); + } + //type &= ~(ADDR_TYPE | CONST_TYPE); + } + else if (scantoken == DOT_TOKEN || scantoken == COLON_TOKEN) + { + /* + * Structure member offset or array of arrays + */ + int elem_size; + int elem_type = (scantoken == DOT_TOKEN) ? BPTR_TYPE : WPTR_TYPE; + long elem_offset = 0; + if (parse_constval(&elem_offset, &elem_size)) + { + /* + * Constant member offset + */ + if (!emit_value) + { + if (type & VAR_TYPE) + { + if (type & LOCAL_TYPE) + emit_localaddr(value + elem_offset); + else + emit_globaladdrofst(value, elem_offset, type); + } + else if (type & CONST_TYPE) + { + value += elem_offset; + emit_const(value); + } + else // FUNC_TYPE + { + emit_globaladdr(value, type); + emit_const(elem_offset); + emit_op(ADD_TOKEN); + } + emit_value = 1; + } + else + { + if (elem_offset != 0) + { + emit_const(elem_offset); + emit_op(ADD_TOKEN); + } + } + } + else if (scantoken == OPEN_BRACKET_TOKEN) + { + /* + * Array of arrays + */ + if (!emit_value) + { + if (type & ADDR_TYPE) + { + if (type & LOCAL_TYPE) + emit_localaddr(value); + else + emit_globaladdr(value, type); + } + else if (type & CONST_TYPE) + { + emit_const(value); + } + emit_value = 1; + } + while (parse_expr()) + { + if (scantoken != COMMA_TOKEN) + break; + emit_indexword(); + emit_lw(); + } + if (scantoken != CLOSE_BRACKET_TOKEN) + { + parse_error("Missing closing bracket"); + return (0); + } + if (elem_type & WPTR_TYPE) + emit_indexword(); + else + emit_indexbyte(); + } + else + { + parse_error("Invalid member offset"); + return (0); + } + type = elem_type; //(type & ~(ADDR_TYPE | CONST_TYPE)) | elem_type; + } + else if (scantoken == OPEN_PAREN_TOKEN) + { + /* + * Function call + */ + if (!emit_value && (type & VAR_TYPE)) + { + if (type & LOCAL_TYPE) + emit_localaddr(value); + else + emit_globaladdr(value, type); + } + //if (type & (VAR_TYPE | PTR_TYPE)) + // emit_lw(); + if (!(type & (FUNC_TYPE | CONST_TYPE))) + { + if (scan_lookahead() != CLOSE_PAREN_TOKEN) + emit_push(); + } + cparams = 0; + while (parse_expr()) + { + cparams++; + if (scantoken != COMMA_TOKEN) + break; + } + if (scantoken != CLOSE_PAREN_TOKEN) + { + parse_error("Missing closing parenthesis"); + return (0); + } + if (type & (FUNC_TYPE | CONST_TYPE)) + emit_call(value, type); + else + { + if (cparams) + emit_pull(); + emit_ical(); + } + emit_value = 1; + type = WORD_TYPE; //(type & ~(FUNC_TYPE | CONST_TYPE)) | WORD_TYPE; + } + } + if (emit_value) + { + if (rvalue && deref && (type & PTR_TYPE)) + (type & BPTR_TYPE) ? emit_lb() : emit_lw(); + } + else + { + if (type & CONST_TYPE) + emit_const(value); + else if (deref) + { + if (type & FUNC_TYPE) + emit_call(value, type); + else if (type & VAR_TYPE) + { + if (type & LOCAL_TYPE) + (type & BYTE_TYPE) ? emit_llb(value) : emit_llw(value); + else + (type & BYTE_TYPE) ? emit_lab(value, type) : emit_law(value, type); + } + else if (type & PTR_TYPE) + (type & BPTR_TYPE) ? emit_lb() : emit_lw(); + } + else + { + if (type & LOCAL_TYPE) + emit_localaddr(value); + else + emit_globaladdr(value, type); + } + } + while (optos < opsptr) + { + if (!emit_unaryop(pop_op())) + { + parse_error(": Invalid unary operation"); + return (0); + } + } + return (type ? type : WORD_TYPE); +} +int parse_constexpr(long *value, int *size) +{ + long val1, val2; + int type, size1, size2 = 0; + + if (!(type = parse_constval(&val1, &size1))) + return (0); + if (scan() == ADD_TOKEN) + { + if (!parse_constval(&val2, &size2)) + return (0); + *value = val1 + val2; + } + else if (scantoken == SUB_TOKEN) + { + if (!parse_constval(&val2, &size2)) + return (0); + *value = val1 - val2; + } + else if (scantoken == MUL_TOKEN) + { + if (!parse_constval(&val2, &size2)) + return (0); + *value = val1 * val2; + } + else if (scantoken == DIV_TOKEN) + { + if (!parse_constval(&val2, &size2)) + return (0); + *value = val1 / val2; + } + else if (scantoken == AND_TOKEN) + { + if (!parse_constval(&val2, &size2)) + return (0); + *value = val1 & val2; + } + else if (scantoken == OR_TOKEN) + { + if (!parse_constval(&val2, &size2)) + return (0); + *value = val1 | val2; + } + else if (scantoken == EOR_TOKEN) + { + if (!parse_constval(&val2, &size2)) + return (0); + *value = val1 ^ val2; + } + else + *value = val1; + *size = size1 > size2 ? size1 : size2; + return (type); +} +int parse_expr() +{ + int prevmatch; + int matchop = 0; + int optos = opsptr; + int i; + int prevtype, type = 0; + do + { + /* + * Parse sequence of double operand operations. + */ + prevmatch = matchop; + matchop = 0; + if (parse_value(1)) + { + matchop = 1; + for (i = 0; i < sizeof(binary_ops_table); i++) + if (scantoken == binary_ops_table[i]) + { + matchop = 2; + if (binary_ops_precedence[i] >= tos_op_prec(optos)) + if (!emit_op(pop_op())) + { + parse_error(": Invalid binary operation"); + return (0); + } + push_op(scantoken, binary_ops_precedence[i]); + break; + } + } + } + while (matchop == 2); + if (matchop == 0 && prevmatch == 2) + { + parse_error("Missing operand"); + return (0); + } + while (optos < opsptr) + if (!emit_op(pop_op())) + { + parse_error(": Invalid binary operation"); + return (0); + } + return (matchop || prevmatch); +} +int parse_stmnt(void) +{ + int tag_prevbrk, tag_else, tag_endif, tag_while, tag_wend, tag_repeat, tag_for, tag_choice, type, addr, step; + char *idptr; + + /* + * Optimization for last function LEAVE + */ + if (scantoken != END_TOKEN && scantoken != DONE_TOKEN) + prevstmnt = scantoken; + + switch (scantoken) + { + case IF_TOKEN: + if (!parse_expr()) + { + parse_error("Bad expression"); + return (0); + } + tag_else = tag_new(BRANCH_TYPE); + tag_endif = tag_new(BRANCH_TYPE); + emit_brfls(tag_else); + scan(); + do { + while (parse_stmnt()) next_line(); + if (scantoken != ELSEIF_TOKEN) + break; + emit_brnch(tag_endif); + emit_codetag(tag_else); + if (!parse_expr()) + { + parse_error("Bad expression"); + return (0); + } + tag_else = tag_new(BRANCH_TYPE); + emit_brfls(tag_else); + } + while (1); + if (scantoken == ELSE_TOKEN) + { + emit_brnch(tag_endif); + emit_codetag(tag_else); + scan(); + while (parse_stmnt()) next_line(); + emit_codetag(tag_endif); + } + else + { + emit_codetag(tag_else); + emit_codetag(tag_endif); + } + if (scantoken != FIN_TOKEN) + { + parse_error("Missing IF/FIN"); + return (0); + } + break; + case WHILE_TOKEN: + tag_while = tag_new(BRANCH_TYPE); + tag_wend = tag_new(BRANCH_TYPE); + tag_prevbrk = break_tag; + break_tag = tag_wend; + emit_codetag(tag_while); + if (!parse_expr()) + { + parse_error("Bad expression"); + return (0); + } + emit_brfls(tag_wend); + while (parse_stmnt()) next_line(); + if (scantoken != LOOP_TOKEN) + { + parse_error("Missing WHILE/END"); + return (0); + } + emit_brnch(tag_while); + emit_codetag(tag_wend); + break_tag = tag_prevbrk; + break; + case REPEAT_TOKEN: + tag_prevbrk = break_tag; + break_tag = tag_new(BRANCH_TYPE); + tag_repeat = tag_new(BRANCH_TYPE); + emit_codetag(tag_repeat); + scan(); + while (parse_stmnt()) next_line(); + if (scantoken != UNTIL_TOKEN) + { + parse_error("Missing REPEAT/UNTIL"); + return (0); + } + if (!parse_expr()) + { + parse_error("Bad expression"); + return (0); + } + emit_brfls(tag_repeat); + emit_codetag(break_tag); + break_tag = tag_prevbrk; + break; + case FOR_TOKEN: + stack_loop++; + tag_prevbrk = break_tag; + break_tag = tag_new(BRANCH_TYPE); + tag_for = tag_new(BRANCH_TYPE); + if (scan() != ID_TOKEN) + { + parse_error("Missing FOR variable"); + return (0); + } + type = id_type(tokenstr, tokenlen); + addr = id_tag(tokenstr, tokenlen); + if (scan() != SET_TOKEN) + { + parse_error("Missing FOR ="); + return (0); + } + if (!parse_expr()) + { + parse_error("Bad FOR expression"); + return (0); + } + emit_codetag(tag_for); + if (type & LOCAL_TYPE) + type & BYTE_TYPE ? emit_dlb(addr) : emit_dlw(addr); + else + type & BYTE_TYPE ? emit_dab(addr, type) : emit_daw(addr, type); + if (scantoken == TO_TOKEN) + step = 1; + else if (scantoken == DOWNTO_TOKEN) + step = -1; + else + { + parse_error("Missing FOR TO"); + return (0); + } + if (!parse_expr()) + { + parse_error("Bad FOR TO expression"); + return (0); + } + step > 0 ? emit_brgt(break_tag) : emit_brlt(break_tag); + if (scantoken == STEP_TOKEN) + { + if (!parse_expr()) + { + parse_error("Bad FOR STEP expression"); + return (0); + } + emit_op(step > 0 ? ADD_TOKEN : SUB_TOKEN); + } + else + emit_unaryop(step > 0 ? INC_TOKEN : DEC_TOKEN); + while (parse_stmnt()) next_line(); + if (scantoken != NEXT_TOKEN) + { + parse_error("Missing FOR/NEXT "); + return (0); + } + emit_brnch(tag_for); + emit_codetag(break_tag); + emit_drop(); + break_tag = tag_prevbrk; + stack_loop--; + break; + case CASE_TOKEN: + stack_loop++; + tag_prevbrk = break_tag; + break_tag = tag_new(BRANCH_TYPE); + tag_choice = tag_new(BRANCH_TYPE); + if (!parse_expr()) + { + parse_error("Bad CASE expression"); + return (0); + } + next_line(); + while (scantoken != ENDCASE_TOKEN) + { + if (scantoken == OF_TOKEN) + { + if (!parse_expr()) + { + parse_error("Bad CASE OF expression"); + return (0); + } + emit_brne(tag_choice); + while (parse_stmnt()) next_line(); + emit_brnch(break_tag); + emit_codetag(tag_choice); + tag_choice = tag_new(BRANCH_TYPE); + } + else if (scantoken == DEFAULT_TOKEN) + { + scan(); + while (parse_stmnt()) next_line(); + if (scantoken != ENDCASE_TOKEN) + { + parse_error("Bad CASE DEFAULT clause"); + return (0); + } + } + else + { + parse_error("Bad CASE clause"); + return (0); + } + } + emit_codetag(break_tag); + emit_drop(); + break_tag = tag_prevbrk; + stack_loop--; + break; + case BREAK_TOKEN: + if (break_tag) + emit_brnch(break_tag); + else + { + parse_error("BREAK without loop"); + return (0); + } + break; + case RETURN_TOKEN: + if (infunc) + { + int i; + for (i = 0; i < stack_loop; i++) + emit_drop(); + if (!parse_expr()) + emit_const(0); + emit_leave(idlocal_size()); + } + else + { + parse_error("RETURN outside of function"); + return (0); + } + break; + case EOL_TOKEN: + case COMMENT_TOKEN: + return (1); + case ELSE_TOKEN: + case ELSEIF_TOKEN: + case FIN_TOKEN: + case LOOP_TOKEN: + case UNTIL_TOKEN: + case NEXT_TOKEN: + case OF_TOKEN: + case DEFAULT_TOKEN: + case ENDCASE_TOKEN: + case END_TOKEN: + case DONE_TOKEN: + case DEF_TOKEN: + return (0); + case ID_TOKEN: + idptr = tokenstr; + type = id_type(tokenstr, tokenlen); + if (type & (VAR_TYPE | FUNC_TYPE)) + { + addr = id_tag(tokenstr, tokenlen); + if (scan() == SET_TOKEN) + { + if (type & VAR_TYPE) + { + if (!parse_expr()) + { + parse_error("Bad expression"); + return (0); + } + if (type & LOCAL_TYPE) + (type & BYTE_TYPE) ? emit_slb(addr) : emit_slw(addr); + else + (type & BYTE_TYPE) ? emit_sab(addr, type) : emit_saw(addr, type); + break; + } + } + else if ((scantoken == EOL_TOKEN) && (type & FUNC_TYPE)) + { + emit_call(addr, type); + emit_drop(); + break; + } + } + tokenstr = idptr; + default: + scan_rewind(tokenstr); + if ((type = parse_value(0)) != 0) + { + if (scantoken == SET_TOKEN) + { + if (!parse_expr()) + { + parse_error("Bad expression"); + return (0); + } + if (type & LOCAL_TYPE) + (type & (BYTE_TYPE | BPTR_TYPE)) ? emit_sb() : emit_sw(); + else + (type & (BYTE_TYPE | BPTR_TYPE)) ? emit_sb() : emit_sw(); + } + else + { + if (type & BPTR_TYPE) + emit_lb(); + else if (type & WPTR_TYPE) + emit_lw(); + emit_drop(); + } + } + else + { + parse_error("Syntax error"); + return (0); + } + } + if (scan() != EOL_TOKEN && scantoken != COMMENT_TOKEN) + { + parse_error("Extraneous characters"); + return (0); + } + return (1); +} +int parse_var(int type) +{ + char *idstr; + long constval; + int consttype, constsize, arraysize, idlen = 0; + long size = 1; + + if (scan() == ID_TOKEN) + { + idstr = tokenstr; + idlen = tokenlen; + if (scan() == OPEN_BRACKET_TOKEN) + { + size = 0; + parse_constexpr(&size, &constsize); + if (scantoken != CLOSE_BRACKET_TOKEN) + { + parse_error("Missing closing bracket"); + return (0); + } + scan(); + } + } + if (type & WORD_TYPE) + size *= 2; + if (scantoken == SET_TOKEN) + { + if (type & (EXTERN_TYPE | LOCAL_TYPE)) + { + parse_error("Cannot initiallize local/external variables"); + return (0); + } + if (idlen) + idglobal_add(idstr, idlen, type, 0); + if ((consttype = parse_constexpr(&constval, &constsize))) + { + /* + * Variable initialization. + */ + arraysize = emit_data(type, consttype, constval, constsize); + while (scantoken == COMMA_TOKEN) + { + if ((consttype = parse_constexpr(&constval, &constsize))) + arraysize += emit_data(type, consttype, constval, constsize); + else + { + parse_error("Bad array declaration"); + return (0); + } + } + if (size > arraysize) + idglobal_size(PTR_TYPE, size, arraysize); + } + else + { + parse_error("Bad variable initializer"); + return (0); + } + } + else if (idlen) + id_add(idstr, idlen, type, size); + return (1); +} +int parse_vars(int type) +{ + long value; + int idlen, size; + char *idstr; + + switch (scantoken) + { + case CONST_TOKEN: + if (scan() != ID_TOKEN) + { + parse_error("Missing variable"); + return (0); + } + idstr = tokenstr; + idlen = tokenlen; + if (scan() != SET_TOKEN) + { + parse_error("Bad LValue"); + return (0); + } + if (!parse_constexpr(&value, &size)) + { + parse_error("Bad constant"); + return (0); + } + idconst_add(idstr, idlen, value); + break; + case EXPORT_TOKEN: + if (type & (EXTERN_TYPE | LOCAL_TYPE)) + { + parse_error("Cannot export local/imported variables"); + return (0); + } + type = EXPORT_TYPE; + idstr = tokenstr; + if (scan() != BYTE_TOKEN && scantoken != WORD_TOKEN) + { + /* + * This could be an exported definition. + */ + scan_rewind(idstr); + scan(); + return (0); + } + /* + * Fall through to BYTE or WORD declaration. + */ + case BYTE_TOKEN: + case WORD_TOKEN: + type |= (scantoken == BYTE_TOKEN) ? BYTE_TYPE : WORD_TYPE; + if (!parse_var(type)) + return (0); + while (scantoken == COMMA_TOKEN) + { + if (!parse_var(type)) + return (0); + } + break; + case PREDEF_TOKEN: + /* + * Pre definition. + */ + if (scan() == ID_TOKEN) + { + type |= DEF_TYPE; + idstr = tokenstr; + idlen = tokenlen; + idfunc_add(tokenstr, tokenlen, type, tag_new(type)); + while (scan() == COMMA_TOKEN) + { + if (scan() == ID_TOKEN) + { + idstr = tokenstr; + idlen = tokenlen; + idfunc_add(tokenstr, tokenlen, type, tag_new(type)); + } + else + { + parse_error("Bad function pre-declaration"); + return (0); + } + } + } + else + { + parse_error("Bad function pre-declaration"); + return (0); + } + case EOL_TOKEN: + case COMMENT_TOKEN: + return (1); + default: + return (0); + } + return (1); +} +int parse_imps(void) +{ + if (scantoken == IMPORT_TOKEN) + { + if (scan() != ID_TOKEN) + { + parse_error("Bad import definition"); + return (0); + } + emit_moddep(tokenstr, tokenlen); + scan(); + while (parse_vars(EXTERN_TYPE)) next_line(); + if (scantoken != END_TOKEN) + { + parse_error("Syntax error"); + return (0); + } + if (scan() != EOL_TOKEN && scantoken != COMMENT_TOKEN) + { + parse_error("Extraneous characters"); + return (0); + } + } + if (scantoken == EOL_TOKEN || scantoken == COMMENT_TOKEN) + return (1); + emit_moddep(0, 0); + return (0); +} +int parse_defs(void) +{ + char c; + int func_tag, cfnparms, type = GLOBAL_TYPE; + static char bytecode = 0; + if (scantoken == EXPORT_TOKEN) + { + if (scan() != DEF_TOKEN && scantoken != ASM_TOKEN) + { + parse_error("Bad export definition"); + return 0; + } + type = EXPORT_TYPE; + } + if (scantoken == DEF_TOKEN) + { + if (scan() != ID_TOKEN) + { + parse_error("Missing function name"); + return (0); + } + emit_bytecode_seg(); + bytecode = 1; + cfnparms = 0; + infunc = 1; + type |= DEF_TYPE; + if (idglobal_lookup(tokenstr, tokenlen) >= 0) + { + if (!(id_type(tokenstr, tokenlen) & DEF_TYPE)) + { + parse_error("Mismatch function type"); + return (0); + } + idfunc_set(tokenstr, tokenlen, type); // Override any predef type + func_tag = id_tag(tokenstr, tokenlen); + } + else + { + func_tag = tag_new(type); + idfunc_add(tokenstr, tokenlen, type, func_tag); + } + c = tokenstr[tokenlen]; + tokenstr[tokenlen] = '\0'; + emit_idfunc(func_tag, type, tokenstr); + tokenstr[tokenlen] = c; + idlocal_reset(); + if (scan() == OPEN_PAREN_TOKEN) + { + do + { + if (scan() == ID_TOKEN) + { + cfnparms++; + idlocal_add(tokenstr, tokenlen, WORD_TYPE, 2); + scan(); + } + } while (scantoken == COMMA_TOKEN); + if (scantoken != CLOSE_PAREN_TOKEN) + { + parse_error("Bad function parameter list"); + return (0); + } + scan(); + } + while (parse_vars(LOCAL_TYPE)) next_line(); + emit_enter(idlocal_size(), cfnparms); + prevstmnt = 0; + while (parse_stmnt()) next_line(); + infunc = 0; + if (scantoken != END_TOKEN) + { + parse_error("Syntax error"); + return (0); + } + if (scan() != EOL_TOKEN && scantoken != COMMENT_TOKEN) + { + parse_error("Extraneous characters"); + return (0); + } + if (prevstmnt != RETURN_TOKEN) + { + emit_const(0); + emit_leave(idlocal_size()); + } + return (1); + } + else if (scantoken == ASM_TOKEN) + { + if (scan() != ID_TOKEN) + { + parse_error("Missing function name"); + return (0); + } + if (bytecode) + { + parse_error("ASM code only allowed before DEF code"); + return (0); + } + cfnparms = 0; + infunc = 1; + type |= ASM_TYPE; + if (idglobal_lookup(tokenstr, tokenlen) >= 0) + { + idfunc_set(tokenstr, tokenlen, type); // Override any predef type + func_tag = id_tag(tokenstr, tokenlen); + } + else + { + func_tag = tag_new(type); + idfunc_add(tokenstr, tokenlen, type, func_tag); + } + c = tokenstr[tokenlen]; + tokenstr[tokenlen] = '\0'; + emit_idfunc(func_tag, type, tokenstr); + tokenstr[tokenlen] = c; + if (scan() == OPEN_PAREN_TOKEN) + { + do + { + if (scan() == ID_TOKEN) + { + cfnparms++; + idlocal_add(tokenstr, tokenlen, WORD_TYPE, 2); + scan(); + } + } + while (scantoken == COMMA_TOKEN); + if (scantoken != CLOSE_PAREN_TOKEN) + { + parse_error("Bad function parameter list"); + return (0); + } + scan(); + } + emit_def(1); + do + { + if (scantoken == EOL_TOKEN || scantoken == COMMENT_TOKEN) + next_line(); + else if (scantoken != END_TOKEN) + { + emit_asm(inputline); + next_line(); + } + } + while (scantoken != END_TOKEN); + return (1); + } + if (scantoken == EOL_TOKEN || scantoken == COMMENT_TOKEN) + return (1); + return (0); +} +int parse_module(void) +{ + emit_header(); + if (next_line()) + { + while (parse_imps()) next_line(); + while (parse_vars(GLOBAL_TYPE)) next_line(); + while (parse_defs()) next_line(); + if (scantoken != DONE_TOKEN && scantoken != EOF_TOKEN) + { + emit_start(); + prevstmnt = 0; + while (parse_stmnt()) next_line(); + if (scantoken != DONE_TOKEN) + parse_error("Missing DONE statement"); + emit_const(0); + emit_ret(); + } + } + emit_trailer(); + emit_rld(); + emit_esd(); + return (0); +} diff --git a/PLASMA/src/parse.h b/PLASMA/src/parse.h new file mode 100755 index 00000000..94930b76 --- /dev/null +++ b/PLASMA/src/parse.h @@ -0,0 +1 @@ +int parse_module(void); diff --git a/PLASMA/src/plasm.c b/PLASMA/src/plasm.c new file mode 100755 index 00000000..de5e0e01 --- /dev/null +++ b/PLASMA/src/plasm.c @@ -0,0 +1,17 @@ +#include +#include "tokens.h" +#include "lex.h" +#include "codegen.h" +#include "parse.h" + +int main(int argc, char **argv) +{ + + if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'A') + emit_flags(ACME); + if (parse_module()) + { + fprintf(stderr, "Compilation complete.\n"); + } + return (0); +} diff --git a/PLASMA/src/plvm.c b/PLASMA/src/plvm.c new file mode 100755 index 00000000..d2fdfbf2 --- /dev/null +++ b/PLASMA/src/plvm.c @@ -0,0 +1,895 @@ +#include +#include +#include +#include + +typedef unsigned char code; +typedef unsigned char byte; +typedef signed short word; +typedef unsigned short uword; +typedef unsigned short address; +/* + * Debug + */ +int show_state = 0; +/* + * Bytecode memory + */ +#define BYTE_PTR(bp) ((byte)(*bp++)) +#define WORD_PTR(bp) ((word)(*bp++|(*++bp << 8))) +#define UWORD_PTR(bp) ((uword)(*bp++|(*++bp << 8))) +#define MOD_ADDR 0x1000 +#define DEF_CALL 0x0800 +#define DEF_CALLSZ 0x0800 +#define DEF_ENTRYSZ 6 +#define MEM_SIZE 65536 +byte mem_data[MEM_SIZE], mem_code[MEM_SIZE]; +byte *mem_bank[2] = {mem_data, mem_code}; +uword sp = 0x01FE, fp = 0xBEFF, heap = 0x6000, xheap = 0x0800, deftbl = DEF_CALL, lastdef = DEF_CALL; + +#define EVAL_STACKSZ 16 +#define PUSH(v) (*(--esp))=(v) +#define POP (*(esp++)) +#define UPOP ((uword)(*(esp++))) +#define TOS (esp[0]) +word eval_stack[EVAL_STACKSZ]; +word *esp = eval_stack + EVAL_STACKSZ; + +#define SYMTBLSZ 1024 +#define SYMSZ 16 +#define MODTBLSZ 128 +#define MODSZ 16 +#define MODLSTSZ 32 +byte symtbl[SYMTBLSZ]; +byte *lastsym = symtbl; +byte modtbl[MODTBLSZ]; +byte *lastmod = modtbl; +/* + * Utility routines. + * + * A DCI string is one that has the high bit set for every character except the last. + * More efficient than C or Pascal strings. + */ +int dcitos(byte *dci, char *str) +{ + int len = 0; + do + str[len] = *dci & 0x7F; + while ((len++ < 15) && (*dci++ & 0x80)); + str[len] = 0; + return len; +} +int stodci(char *str, byte *dci) +{ + int len = 0; + do + dci[len] = toupper(*str) | 0x80; + while (*str++ && (len++ < 15)); + dci[len - 1] &= 0x7F; + return len; +} + +/* + * Heap routines. + */ +uword avail_heap(void) +{ + return fp - heap; +} +uword alloc_heap(int size) +{ + uword addr = heap; + heap += size; + if (heap >= fp) + { + printf("Error: heap/frame collision.\n"); + exit (1); + } + return addr; +} +uword free_heap(int size) +{ + heap -= size; + return fp - heap; +} +uword mark_heap(void) +{ + return heap; +} +int release_heap(uword newheap) +{ + heap = newheap; + return fp - heap; +} +uword avail_xheap(void) +{ + return 0xC000 - xheap; +} +uword alloc_xheap(int size) +{ + uword addr = xheap; + xheap += size; + if (xheap >= 0xC000) + { + printf("Error: xheap extinguished.\n"); + exit (1); + } + return addr; +} +uword free_xheap(int size) +{ + xheap -= size; + return 0xC000 - heap; +} +uword mark_xheap(void) +{ + return xheap; +} +int release_xheap(uword newxheap) +{ + xheap = newxheap; + return 0xC000 - xheap; +} +/* + * Copy from data mem to code mem. + */ +void xmemcpy(uword src, uword dst, uword size) +{ + while (size--) + mem_code[dst + size] = mem_data[src + size]; +} +/* + * Copy from code mem to data mem. + */ +void memxcpy(uword src, uword dst, uword size) +{ + while (size--) + mem_data[dst + size] = mem_code[src + size]; +} +/* + * DCI table routines, + */ +void dump_tbl(byte *tbl) +{ + int len; + byte *entbl; + while (*tbl) + { + len = 0; + while (*tbl & 0x80) + { + putchar(*tbl++ & 0x7F); + len++; + } + putchar(*tbl++); + putchar(':'); + while (len++ < 15) + putchar(' '); + printf("$%04X\n", tbl[0] | (tbl[1] << 8)); + tbl += 2; + } +} +uword lookup_tbl(byte *dci, byte *tbl) +{ + char str[20]; + byte *match, *entry = tbl; + while (*entry) + { + match = dci; + while (*entry == *match) + { + if ((*entry & 0x80) == 0) + return entry[1] | (entry[2] << 8); + entry++; + match++; + } + while (*entry++ & 0x80); + entry += 2; + } + dcitos(dci, str); + return 0; +} +int add_tbl(byte *dci, int val, byte *tbl, byte **last) +{ + while (*dci & 0x80) + *(*last)++ = *dci++; + *(*last)++ = *dci++; + *(*last)++ = val; + *(*last)++ = val >> 8; +} + +/* + * Symbol table routines. + */ +void dump_sym(void) +{ + printf("\nSystem Symbol Table:\n"); + dump_tbl(symtbl); +} +uword lookup_sym(byte *sym) +{ + return lookup_tbl(sym, symtbl); +} +int add_sym(byte *sym, int addr) +{ + return add_tbl(sym, addr, symtbl, &lastsym); +} + +/* + * Module routines. + */ +void dump_mod(void) +{ + printf("\nSystem Module Table:\n"); + dump_tbl(modtbl); +} +uword lookup_mod(byte *mod) +{ + return lookup_tbl(mod, modtbl); +} +int add_mod(byte *mod, int addr) +{ + return add_tbl(mod, addr, symtbl, &lastmod); +} +defcall_add(int bank, int addr) +{ + mem_data[lastdef] = bank ? 2 : 1; + mem_data[lastdef + 1] = addr; + mem_data[lastdef + 2] = addr >> 8; + return lastdef++; +} +int def_lookup(byte *cdd, int defaddr) +{ + int i, calldef = 0; + for (i = 0; cdd[i * 4] == 0x02; i++) + { + if ((cdd[i * 4 + 1] | (cdd[i * 4 + 2] << 8)) == defaddr) + { + calldef = cdd + i * 4 - mem_data; + break; + } + } + return calldef; +} +int extern_lookup(byte *esd, int index) +{ + byte *sym; + char string[32]; + while (*esd) + { + sym = esd; + esd += dcitos(esd, string); + if ((esd[0] & 0x10) && (esd[1] == index)) + return lookup_sym(sym); + esd += 3; + } + printf("\nError: extern index %d not found in ESD.\n", index); + return 0; +} +int load_mod(byte *mod) +{ + int len, size, end, magic, bytecode, fixup, addr, modaddr = mark_heap(); + byte *moddep, *rld, *esd, *cdd, *sym; + byte header[128]; + char filename[32], string[17]; + + dcitos(mod, filename); + printf("Load module %s\n"); + int fd = open(filename, O_RDONLY, 0); + if ((fd > 0) && (len = read(fd, header, 128)) > 0) + { + magic = header[2] | (header[3] << 8); + if (magic == 0xDA7E) + { + /* + * This is a relocatable bytecode module. + */ + bytecode = header[4] | (header[5] << 8); + moddep = header + 6; + if (*moddep) + { + /* + * Load module dependencies. + */ + close(fd); + while (*moddep) + { + if (lookup_mod(moddep) == 0) + load_mod(moddep); + moddep += dcitos(moddep, string); + } + modaddr = mark_heap(); + fd = open(filename, O_RDONLY, 0); + len = read(fd, mem_data + modaddr, 128); + } + else + memcpy(mem_data + modaddr, header, len); + } + addr = modaddr + len; + while ((len = read(fd, mem_data + addr, 4096)) > 0) + addr += len; + close(fd); + size = addr - modaddr; + len = mem_data[modaddr + 0] | (mem_data[modaddr + 1] << 8); + end = modaddr + len; + rld = mem_data + modaddr + len; // Re-Locatable Directory + esd = rld; // Extern+Entry Symbol Directory + bytecode += modaddr - MOD_ADDR; + while (*esd != 0x00) // Scan to end of RLD + esd += 4; + esd++; + cdd = rld; + if (show_state) + { + /* + * Dump different parts of module. + */ + printf("Module size: %d\n", size); + printf("Module code+data size: %d\n", len); + printf("Module magic: $%04X\n", magic); + printf("Module bytecode: $%04X\n", bytecode); + } + /* + * Print out the Re-Location Dictionary. + */ + if (show_state) + printf("\nRe-Location Dictionary:\n"); + while (*rld) + { + if (rld[0] == 0x02) + { + if (show_state) printf("\tDEF CODE"); + addr = rld[1] | (rld[2] << 8); + addr += modaddr - MOD_ADDR; + rld[1] = addr; + rld[2] = addr >> 8; + end = rld - mem_data + 4; + } + else + { + addr = rld[1] | (rld[2] << 8); + addr += modaddr - MOD_ADDR; + if (rld[0] & 0x80) + fixup = mem_data[addr] | (mem_data[addr + 1] << 8); + else + fixup = mem_data[addr]; + if (rld[0] & 0x10) + { + if (show_state) printf("\tEXTERN[$%02X] ", rld[3]); + fixup += extern_lookup(esd, rld[3]); + } + else + { + if (show_state) printf("\tINTERN "); + fixup += modaddr - MOD_ADDR; + if (fixup >= bytecode) + /* + * Replace with call def dictionary. + */ + fixup = def_lookup(cdd, fixup); + } + if (rld[0] & 0x80) + { + if (show_state) printf("WORD"); + mem_data[addr] = fixup; + mem_data[addr + 1] = fixup >> 8; + } + else + { + if (show_state) printf("BYTE"); + mem_data[addr] = fixup; + } + + } + if (show_state) printf("@$%04X\n", addr); + rld += 4; + } + if (show_state) printf("\nExternal/Entry Symbol Directory:\n"); + while (*esd) + { + sym = esd; + esd += dcitos(esd, string); + if (esd[0] & 0x10) + { + if (show_state) printf("\tIMPORT %s[$%02X]\n", string, esd[1]); + } + else if (esd[0] & 0x08) + { + addr = esd[1] | (esd[2] << 8); + addr += modaddr - MOD_ADDR; + if (show_state) printf("\tEXPORT %s@$%04X\n", string, addr); + if (addr >= bytecode) + addr = def_lookup(cdd, addr); + add_sym(sym, addr); + } + esd += 3; + } + } + else + { + printf("Error: Unable to load module %s\n", filename); + exit (1); + } + /* + * Reserve heap space for relocated module. + */ + alloc_heap(end - modaddr); + return (fd > 0); +} +void interp(code *ip); + +void call(word pc) +{ + int i, s; + char sz[64]; + + switch (mem_data[pc++]) + { + case 0: // NULL call + printf("NULL call code\n"); + break; + case 1: // BYTECODE in mem_code + interp(mem_code + (mem_data[pc] + (mem_data[pc + 1] << 8))); + break; + case 2: // BYTECODE in mem_data + interp(mem_data + (mem_data[pc] + (mem_data[pc + 1] << 8))); + break; + case 3: // LIBRARY STDLIB::VIEWPORT + printf("Set Window %d, %d, %d, %n/n", POP, POP, POP, POP); + PUSH(0); + break; + case 4: // LIBRARY STDLIB::PUTC + putchar(POP); + PUSH(0); + break; + case 5: // LIBRARY STDLIB::PUTS + s = POP; + i = mem_data[s++]; + PUSH(i); + while (i--) + putchar(mem_data[s++]); + break; + case 6: // LIBRARY STDLIB::PUTSZ + s = POP; + while (i = mem_data[s++]) + { + if (i == '\r') + i = '\n'; + putchar(i); + } + PUSH(0); + break; + case 7: // LIBRARY STDLIB::GETC + PUSH(getchar()); + break; + case 8: // LIBRARY STDLIB::GETS + gets(sz); + i = 0; + while (sz[i]) + mem_data[0x200 + i++] = sz[i]; + mem_data[0x200 + i] = 0; + mem_data[0x1FF] = i; + PUSH(i); + break; + case 9: // LIBRARY STDLIB::CLS + puts("\033[2J"); + fflush(stdout); + PUSH(0); + PUSH(0); + case 10: // LIBRARY STDLIB::GOTOXY + s = POP + 1; + i = POP + 1; + printf("\033[%d;%df", s, i); + fflush(stdout); + PUSH(0); + break; + default: + printf("Bad call code\n"); + } +} + +/* + * OPCODE TABLE + * +OPTBL: DW ZERO,ADD,SUB,MUL,DIV,MOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E + DW NEG,COMP,AND,IOR,XOR,SHL,SHR,IDXW ; 10 12 14 16 18 1A 1C 1E + DW NOT,LOR,LAND,LA,LLA,CB,CW,SWAP ; 20 22 24 26 28 2A 2C 2E + DW DROP,DUP,PUSH,PULL,BRGT,BRLT,BREQ,BRNE ; 30 32 34 36 38 3A 3C 3E + DW ISEQ,ISNE,ISGT,ISLT,ISGE,ISLE,BRFLS,BRTRU ; 40 42 44 46 48 4A 4C 4E + DW BRNCH,IBRNCH,CALL,ICAL,ENTER,LEAVE,RET,??? ; 50 52 54 56 58 5A 5C 5E + DW LB,LW,LLB,LLW,LAB,LAW,DLB,DLW ; 60 62 64 66 68 6A 6C 6E + DW SB,SW,SLB,SLW,SAB,SAW,DAB,DAW ; 70 72 74 76 78 7A 7C 7E +*/ +void interp(code *ip) +{ + word val, ea, frmsz, parmcnt; + + while (1) + { + if (show_state) + { + word *dsp = &eval_stack[EVAL_STACKSZ - 1]; + printf("$%04X: $%02X [ ", ip - mem_data, *ip); + while (dsp >= esp) + printf("$%04X ", (*dsp--) & 0xFFFF); + printf("]\n"); + } + switch (*ip++) + { + /* + * 0x00-0x0F + */ + case 0x00: // ZERO : TOS = 0 + PUSH(0); + break; + case 0x02: // ADD : TOS = TOS + TOS-1 + val = POP; + ea = POP; + PUSH(ea + val); + break; + case 0x04: // SUB : TOS = TOS-1 - TOS + val = POP; + ea = POP; + PUSH(ea - val); + break; + case 0x06: // MUL : TOS = TOS * TOS-1 + val = POP; + ea = POP; + PUSH(ea * val); + break; + case 0x08: // DIV : TOS = TOS-1 / TOS + val = POP; + ea = POP; + PUSH(ea / val); + break; + case 0x0A: // MOD : TOS = TOS-1 % TOS + val = POP; + ea = POP; + PUSH(ea % val); + break; + case 0x0C: // INCR : TOS = TOS + 1 + TOS++; + break; + case 0x0E: // DECR : TOS = TOS - 1 + TOS--; + break; + /* + * 0x10-0x1F + */ + case 0x10: // NEG : TOS = -TOS + TOS = -TOS; + break; + case 0x12: // COMP : TOS = ~TOS + TOS = ~TOS; + break; + case 0x14: // AND : TOS = TOS & TOS-1 + val = POP; + ea = POP; + PUSH(ea & val); + break; + case 0x16: // IOR : TOS = TOS ! TOS-1 + val = POP; + ea = POP; + PUSH(ea | val); + break; + case 0x18: // XOR : TOS = TOS ^ TOS-1 + val = POP; + ea = POP; + PUSH(ea ^ val); + break; + case 0x1A: // SHL : TOS = TOS-1 << TOS + val = POP; + ea = POP; + PUSH(ea << val); + break; + case 0x1C: // SHR : TOS = TOS-1 >> TOS + val = POP; + ea = POP; + PUSH(ea >> val); + break; + case 0x1E: // IDXW : TOS = TOS * 2 + TOS *= 2; + break; + /* + * 0x20-0x2F + */ + case 0x20: // NOT : TOS = !TOS + TOS = !TOS; + break; + case 0x22: // LOR : TOS = TOS || TOS-1 + val = POP; + ea = POP; + PUSH(ea || val); + break; + case 0x24: // LAND : TOS = TOS && TOS-1 + val = POP; + ea = POP; + PUSH(ea && val); + break; + case 0x26: // LA : TOS = @VAR ; equivalent to CW ADDRESSOF(VAR) + PUSH(WORD_PTR(ip)); + break; + case 0x28: // LLA : TOS = @LOCALVAR ; equivalent to CW FRAMEPTR+OFFSET(LOCALVAR) + PUSH(fp + BYTE_PTR(ip)); + break; + case 0x2A: // CB : TOS = CONSTANTBYTE (IP) + PUSH(BYTE_PTR(ip)); + break; + case 0x2C: // CW : TOS = CONSTANTWORD (IP) + PUSH(WORD_PTR(ip)); + break; + case 0x2E: // SWAP : TOS = TOS-1, TOS-1 = TOS + val = POP; + ea = POP; + PUSH(val); + PUSH(ea); + break; + /* + * 0x30-0x3F + */ + case 0x30: // DROP : TOS = + esp++;; + break; + case 0x32: // DUP : TOS = TOS + val = TOS; + PUSH(val); + break; + case 0x34: // PUSH : TOSP = TOS + val = POP; + mem_data[sp--] = val >> 8; + mem_data[sp--] = val; + break; + case 0x36: // PULL : TOS = TOSP + PUSH(mem_data[++sp] | (mem_data[++sp] << 8)); + break; + case 0x38: // BRGT : TOS-1 > TOS ? IP += (IP) + val = POP; + ea = POP; + if (ea <= val) + ip += WORD_PTR(ip) - 2; + else + ip += 2; + break; + case 0x3A: // BRLT : TOS-1 < TOS ? IP += (IP) + val = POP; + ea = TOS; + if (ea >= val) + ip += WORD_PTR(ip) - 2; + else + ip += 2; + break; + case 0x3C: // BREQ : TOS == TOS-1 ? IP += (IP) + val = POP; + ea = TOS; + if (ea == val) + ip += WORD_PTR(ip) - 2; + else + ip += 2; + break; + case 0x3E: // BRNE : TOS != TOS-1 ? IP += (IP) + val = POP; + ea = TOS; + if (ea != val) + ip += WORD_PTR(ip) - 2; + else + ip += 2; + break; + /* + * 0x40-0x4F + */ + case 0x40: // ISEQ : TOS = TOS == TOS-1 + val = POP; + ea = POP; + PUSH(ea == val); + break; + case 0x42: // ISNE : TOS = TOS != TOS-1 + val = POP; + ea = POP; + PUSH(ea != val); + break; + case 0x44: // ISGT : TOS = TOS-1 > TOS + val = POP; + ea = POP; + PUSH(ea <= val); + break; + case 0x46: // ISLT : TOS = TOS-1 < TOS + val = POP; + ea = POP; + PUSH(ea >= val); + break; + case 0x48: // ISGE : TOS = TOS-1 >= TOS + val = POP; + ea = POP; + PUSH(ea < val); + break; + case 0x4A: // ISLE : TOS = TOS-1 <= TOS + val = POP; + ea = POP; + PUSH(ea > val); + break; + case 0x4C: // BRFLS : !TOS ? IP += (IP) + if (!POP) + ip += WORD_PTR(ip) - 2; + else + ip += 2; + break; + case 0x4E: // BRTRU : TOS ? IP += (IP) + if (POP) + ip += WORD_PTR(ip) - 2; + else + ip += 2; + break; + /* + * 0x50-0x5F + */ + case 0x50: // BRNCH : IP += (IP) + ip += WORD_PTR(ip) - 2; + break; + case 0x52: // IBRNCH : IP += TOS + ip += POP; + break; + case 0x54: // CALL : TOFP = IP, IP = (IP) ; call + call(UWORD_PTR(ip)); + break; + case 0x56: // ICALL : TOFP = IP, IP = (TOS) ; indirect call + val = POP; + ea = mem_data[val] | (mem_data[val + 1] << 8); + call(ea); + break; + case 0x58: // ENTER : NEW FRAME, FOREACH PARAM LOCALVAR = TOS + frmsz = BYTE_PTR(ip); + mem_data[fp - frmsz] = fp; + mem_data[fp - frmsz + 1] = fp >> 8; + fp -= frmsz; + parmcnt = BYTE_PTR(ip); + while (parmcnt--) + { + val = POP; + mem_data[fp + parmcnt + 2] = val; + mem_data[fp + parmcnt + 3] = val >> 8; + } + break; + case 0x5A: // LEAVE : DEL FRAME, IP = TOFP + fp = mem_data[fp] | (mem_data[fp + 1] << 8); + case 0x5C: // RET : IP = TOFP + return; + case 0x5E: // ??? + break; + /* + * 0x60-0x6F + */ + case 0x60: // LB : TOS = BYTE (TOS) + val = UPOP; + PUSH(mem_data[val]); + break; + case 0x62: // LW : TOS = WORD (TOS) + ea = POP; + PUSH(mem_data[ea] | (mem_data[ea + 1] << 8)); + break; + case 0x64: // LLB : TOS = LOCALBYTE [IP] + PUSH(mem_data[fp + BYTE_PTR(ip)]); + break; + case 0x66: // LLW : TOS = LOCALWORD [IP] + ea = fp + BYTE_PTR(ip); + PUSH(mem_data[ea] | (mem_data[ea + 1] << 8)); + break; + case 0x68: // LAB : TOS = BYTE (IP) + PUSH(mem_data[UWORD_PTR(ip)]); + break; + case 0x6A: // LAW : TOS = WORD (IP) + ea = UWORD_PTR(ip); + PUSH(mem_data[ea] | (mem_data[ea + 1] << 8)); + break; + case 0x6C: // DLB : TOS = TOS, LOCALBYTE [IP] = TOS + mem_data[fp + BYTE_PTR(ip)] = TOS; + break; + case 0x6E: // DLW : TOS = TOS, LOCALWORD [IP] = TOS + ea = fp + BYTE_PTR(ip); + mem_data[ea] = TOS; + mem_data[ea + 1] = TOS >> 8; + break; + /* + * 0x70-0x7F + */ + case 0x70: // SB : BYTE (TOS) = TOS-1 + val = POP; + ea = POP; + mem_data[ea] = val; + break; + case 0x72: // SW : WORD (TOS) = TOS-1 + val = POP; + ea = POP; + mem_data[ea] = val; + mem_data[ea + 1] = val >> 8; + break; + case 0x74: // SLB : LOCALBYTE [TOS] = TOS-1 + mem_data[fp + BYTE_PTR(ip)] = POP; + break; + case 0x76: // SLW : LOCALWORD [TOS] = TOS-1 + ea = fp + BYTE_PTR(ip); + val = POP; + mem_data[ea] = val; + mem_data[ea + 1] = val >> 8; + break; + case 0x78: // SAB : BYTE (IP) = TOS + mem_data[WORD_PTR(ip)] = POP; + break; + case 0x7A: // SAW : WORD (IP) = TOS + ea = WORD_PTR(ip); + val = POP; + mem_data[ea] = val; + mem_data[ea + 1] = val >> 8; + break; + case 0x7C: // DAB : TOS = TOS, BYTE (IP) = TOS + mem_data[WORD_PTR(ip)] = TOS; + break; + case 0x7E: // DAW : TOS = TOS, WORD (IP) = TOS + ea = WORD_PTR(ip); + mem_data[ea] = TOS; + mem_data[ea + 1] = TOS >> 8; + break; + /* + * Odd codes and everything else are errors. + */ + default: + fprintf(stderr, "Illegal opcode 0x%02X @ 0x%04X\n", ip[-1], ip - mem_code); + } + } +} + +char *stdlib_exp[] = { + "VIEWPORT", + "PUTC", + "PUTS", + "PUTSZ", + "GETC", + "GETS", + "CLS", + "GOTOXY" +}; + +byte stdlib[] = { + 0x00 +}; + +int main(int argc, char **argv) +{ + byte dci[32]; + int i; + + if (--argc) + { + argv++; + if ((*argv)[0] == '-' && (*argv)[1] == 's') + { + show_state = 1; + argc--; + argv++; + } + /* + * Add default library. + */ + stodci("STDLIB", dci); + add_mod(dci, 0xFFFF); + for (i = 0; i < 8; i++) + { + mem_data[i] = i + 3; + stodci(stdlib_exp[i], dci); + add_sym(dci, i); + } + if (argc) + { + stodci(*argv, dci); + load_mod(dci); + if (show_state) dump_sym(); + argc--; + argv++; + } + if (argc) + { + stodci(*argv, dci); + call(lookup_sym(dci)); + } + } + return 0; +} \ No newline at end of file diff --git a/PLASMA/src/samplib.s b/PLASMA/src/samplib.s new file mode 100755 index 00000000..210ed6a8 --- /dev/null +++ b/PLASMA/src/samplib.s @@ -0,0 +1,147 @@ +; +; Sample PLASMA library. +; +!TO "samplib.bin", PLAIN +* = $1000 +; +; DATA/CODE SEGMENT +; +_SEGBEGIN + !WORD _SEGEND-_SEGBEGIN ; LENGTH OF HEADER + CODE/DATA + BYTECODE SEGMENT +; +; MODULE HEADER +; + !WORD $DA7E ; MAGIC # + !WORD _SUBSEG ; BYTECODE SUB-SEGMENT +; +; MODULE DEPENDENCY LIST +; NOTE: DCI = PSUEDO OP FOR ASCII STRING WITH HI BIT SET EXCEPT LAST CHAR +; + ;DCI "STDLIB" + !CT "hi.ascii" + !TX "STDLI" + !CT RAW + !TX 'B' + ;DCI "FILEIO" + !CT "hi.ascii" + !TX "FILEI" + !CT RAW + !TX 'O' + !BYTE 0 +; +; NATIVE CODE + GLOBAL DATA +; +COUNT !WORD 0 +INCCNT +FIXUP1 INC COUNT + BNE XINIT +FIXUP2 INC COUNT+1 +XINIT RTS +; +; BYTECODE SUB-SEGMENT +; +_SUBSEG +MYFUNC !BYTE $58, $01, $16 ; ENTER 1,16 + !BYTE $66, $02 ; LLW 2 + !BYTE $2A, $01 ; CB 1 + !BYTE $54 ; CALL EXTERN(1) "OPEN" +FIXUP4 !WORD $0000 + !BYTE $6E, $04 ; DLW 4 + !BYTE $54 ; CALL EXTERN(3) "READ" +FIXUP5 !WORD $0000 + !BYTE $30 ; DROP + !BYTE $66, $04 ; LLW 4 + !BYTE $54 ; CALL EXTERN(2) ; "CLOSE" +FIXUP6 !WORD $0000 + !BYTE $30 ; DROP + !BYTE $6A ; LAW COUNT +FIXUP7 !WORD $0000 + !BYTE $54 ; CALL INCNT +FIXUP8 !WORD $0000 + !BYTE $5A ; LEAVE +; +; END OF CODE/DATA + BYTECODE SEGMENT +; +_SEGEND +; +; BYTCODE FUNCTION DICTIONARY +; + !BYTE $A1 ; FIXUP FLAGS + !WORD MYFUNC ; FIXUP OFFSET + !BYTE $00 ; FIXUP LO BYTE (OF HI BYTE)/IMPORT INDEX +; +; RE-LOCATION DICTIONARY (FIXUP TABLE) +; + !BYTE $81 ; FIXUP FLAGS + !WORD FIXUP1+1 ; FIXUP OFFSET + !BYTE $00 ; FIXUP LO BYTE (OF HI BYTE)/IMPORT INDEX + !BYTE $81 + !WORD FIXUP2+1 + !BYTE $00 + !BYTE $91 ; IMPORT FIXUP + !WORD FIXUP4 + !BYTE $01 ; IMPORT INDEX 1 + !BYTE $91 + !WORD FIXUP5 + !BYTE $03 + !BYTE $91 + !WORD FIXUP6 + !BYTE $02 + !BYTE $81 + !WORD FIXUP7 + !BYTE $00 + !BYTE $81 + !WORD FIXUP8 + !BYTE $00 + !BYTE 0 ; END OF RLD +; +; EXTERNAL/ENTRY SYMBOL DIRECTORY +;; +; IMPORT TABLE +; +IMPTBL ;DCI "OPEN" ; EXTERNAL SYMBOL NAME + !CT "hi.ascii" + !TX "OPE" + !CT RAW + !TX 'N' + !BYTE $10 ; EXTERNAL SYMBOL FLAG + !WORD 1 ; SYMBOL INDEX + ;DCI "CLOSE" + !CT "hi.ascii" + !TX "CLOS" + !CT RAW + !TX 'E' + !BYTE $10 + !WORD 2 + ;DCI "READ" + !CT "hi.ascii" + !TX "REA" + !CT RAW + !TX 'D' + !BYTE $10 + !WORD 3 + ;DCI "MEMSET" + !CT "hi.ascii" + !TX "MEMSE" + !CT RAW + !TX 'T' + !BYTE $10 + !WORD 4 +; +; EXPORT TABLE +; +EXPTBL ;DCI "INCNT" ; ENTRY SYMBOL NAME + !CT "hi.ascii" + !TX "INCN" + !CT RAW + !TX 'T' + !BYTE $08 ; ENTRY SYMBOL FLAG + !WORD INCCNT ; OFFSET + ;DCI "MYFUNC" + !CT "hi.ascii" + !TX "MYFUN" + !CT RAW + !TX 'C' + !BYTE $08 + !WORD MYFUNC + !BYTE 0 ; END OF ESD diff --git a/PLASMA/src/symbols.h b/PLASMA/src/symbols.h new file mode 100755 index 00000000..bbd62b1b --- /dev/null +++ b/PLASMA/src/symbols.h @@ -0,0 +1,39 @@ +/* + * Symbol table types. + */ +#define GLOBAL_TYPE (0) +#define CONST_TYPE (1 << 0) +#define WORD_TYPE (1 << 1) +#define BYTE_TYPE (1 << 2) +#define VAR_TYPE (WORD_TYPE | BYTE_TYPE) +#define ASM_TYPE (1 << 3) +#define DEF_TYPE (1 << 4) +#define BRANCH_TYPE (1 << 5) +#define FUNC_TYPE (ASM_TYPE | DEF_TYPE) +#define LOCAL_TYPE (1 << 6) +#define EXTERN_TYPE (1 << 7) +#define ADDR_TYPE (VAR_TYPE | FUNC_TYPE | EXTERN_TYPE) +#define WPTR_TYPE (1 << 8) +#define BPTR_TYPE (1 << 9) +#define PTR_TYPE (BPTR_TYPE | WPTR_TYPE) +#define STRING_TYPE (1 << 10) +#define TAG_TYPE (1 << 11) +#define EXPORT_TYPE (1 << 12) + +int id_match(char *name, int len, char *id); +int idlocal_lookup(char *name, int len); +int idglobal_lookup(char *name, int len); +int idconst_lookup(char *name, int len); +int idlocal_add(char *name, int len, int type, int size); +int idglobal_add(char *name, int len, int type, int size); +int id_add(char *name, int len, int type, int size); +int idfunc_set(char *name, int len, int type); +int idfunc_add(char *name, int len, int type, int tag); +int idconst_add(char *name, int len, int value); +int id_tag(char *name, int len); +int id_const(char *name, int len); +int id_type(char *name, int len); +void idglobal_size(int type, int size, int constsize); +int idlocal_size(void); +void idlocal_reset(void); +int tag_new(int type); diff --git a/PLASMA/src/test.pla b/PLASMA/src/test.pla new file mode 100755 index 00000000..e795c027 --- /dev/null +++ b/PLASMA/src/test.pla @@ -0,0 +1,40 @@ +; +; Declare all imported modules and their data/functions. +; +import stdlib + predef cls, gotoxy, puts, putc +end +; +; Predeclare and functions called before defined. +; +predef main +; +; Declare all global variables for this module. +; +byte hello[] = "Hello, world.\n\n" +word defptr = main +; +; Define functions. +; + +export def ascii + byte i + cls() + for i = 32 to 127 + putc(i) + next +end + +export def main + cls() + gotoxy(35,15) + return puts(@hello) +end + +export def indirect + word mainptr + mainptr = @main + mainptr() +end + +done diff --git a/PLASMA/src/tokens.h b/PLASMA/src/tokens.h new file mode 100755 index 00000000..afe259aa --- /dev/null +++ b/PLASMA/src/tokens.h @@ -0,0 +1,106 @@ + +#define TOKEN(c) (0x80|(c)) +#define IS_TOKEN(c) (0x80&(c)) +/* + * Identifier and constant tokens. + */ +#define ID_TOKEN TOKEN('V') +#define CHAR_TOKEN TOKEN('Y') +#define INT_TOKEN TOKEN('Z') +#define FLOAT_TOKEN TOKEN('F') +#define STRING_TOKEN TOKEN('S') +/* + * Keyword tokens. + */ +#define CONST_TOKEN TOKEN(1) +#define BYTE_TOKEN TOKEN(2) +#define WORD_TOKEN TOKEN(3) +#define IF_TOKEN TOKEN(4) +#define ELSEIF_TOKEN TOKEN(5) +#define ELSE_TOKEN TOKEN(6) +#define FIN_TOKEN TOKEN(7) +#define END_TOKEN TOKEN(8) +#define WHILE_TOKEN TOKEN(9) +#define LOOP_TOKEN TOKEN(10) +#define CASE_TOKEN TOKEN(11) +#define OF_TOKEN TOKEN(12) +#define DEFAULT_TOKEN TOKEN(13) +#define ENDCASE_TOKEN TOKEN(14) +#define FOR_TOKEN TOKEN(15) +#define TO_TOKEN TOKEN(16) +#define DOWNTO_TOKEN TOKEN(17) +#define STEP_TOKEN TOKEN(18) +#define NEXT_TOKEN TOKEN(19) +#define REPEAT_TOKEN TOKEN(20) +#define UNTIL_TOKEN TOKEN(21) +#define PREDEF_TOKEN TOKEN(22) +#define DEF_TOKEN TOKEN(23) +#define ASM_TOKEN TOKEN(24) +#define IMPORT_TOKEN TOKEN(25) +#define EXPORT_TOKEN TOKEN(26) +#define DONE_TOKEN TOKEN(27) +#define RETURN_TOKEN TOKEN(28) +#define BREAK_TOKEN TOKEN(29) +#define START_TOKEN TOKEN(30) +#define EXIT_TOKEN TOKEN(31) +#define EVAL_TOKEN TOKEN(32) +/* + * Double operand operators. + */ +#define SET_TOKEN TOKEN('=') +#define ADD_TOKEN TOKEN('+') +#define ADD_SELF_TOKEN TOKEN('a') +#define SUB_TOKEN TOKEN('-') +#define SUB_SELF_TOKEN TOKEN('u') +#define MUL_TOKEN TOKEN('*') +#define MUL_SELF_TOKEN TOKEN('m') +#define DIV_TOKEN TOKEN('/') +#define DIV_SELF_TOKEN TOKEN('d') +#define MOD_TOKEN TOKEN('%') +#define OR_TOKEN TOKEN('|') +#define OR_SELF_TOKEN TOKEN('o') +#define EOR_TOKEN TOKEN('^') +#define EOR_SELF_TOKEN TOKEN('x') +#define AND_TOKEN TOKEN('&') +#define AND_SELF_TOKEN TOKEN('n') +#define SHR_TOKEN TOKEN('R') +#define SHR_SELF_TOKEN TOKEN('r') +#define SHL_TOKEN TOKEN('L') +#define SHL_SELF_TOKEN TOKEN('l') +#define GT_TOKEN TOKEN('>') +#define GE_TOKEN TOKEN('H') +#define LT_TOKEN TOKEN('<') +#define LE_TOKEN TOKEN('B') +#define NE_TOKEN TOKEN('U') +#define EQ_TOKEN TOKEN('E') +#define LOGIC_AND_TOKEN TOKEN('N') +#define LOGIC_OR_TOKEN TOKEN('O') +/* + * Single operand operators. + */ +#define NEG_TOKEN TOKEN('-') +#define COMP_TOKEN TOKEN('~') +#define LOGIC_NOT_TOKEN TOKEN('!') +#define INC_TOKEN TOKEN('P') +#define DEC_TOKEN TOKEN('K') +#define BPTR_TOKEN TOKEN('^') +#define WPTR_TOKEN TOKEN('*') +#define POST_INC_TOKEN TOKEN('p') +#define POST_DEC_TOKEN TOKEN('k') +#define OPEN_PAREN_TOKEN TOKEN('(') +#define CLOSE_PAREN_TOKEN TOKEN(')') +#define OPEN_BRACKET_TOKEN TOKEN('[') +#define CLOSE_BRACKET_TOKEN TOKEN(']') +/* + * Misc. tokens. + */ +#define AT_TOKEN TOKEN('@') +#define DOT_TOKEN TOKEN('.') +#define COLON_TOKEN TOKEN(':') +#define POUND_TOKEN TOKEN('#') +#define COMMA_TOKEN TOKEN(',') +#define COMMENT_TOKEN TOKEN(';') +#define EOL_TOKEN TOKEN(0) +#define EOF_TOKEN TOKEN(0x7F) + +typedef unsigned char t_token; From ffdc8732d94bb1d97327d245e5f37b3f98d96c81 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Sun, 27 Apr 2014 14:25:56 -0700 Subject: [PATCH 02/44] Fix printf errors --- PLASMA/src/plvm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PLASMA/src/plvm.c b/PLASMA/src/plvm.c index d2fdfbf2..a9db52b3 100755 --- a/PLASMA/src/plvm.c +++ b/PLASMA/src/plvm.c @@ -274,7 +274,7 @@ int load_mod(byte *mod) char filename[32], string[17]; dcitos(mod, filename); - printf("Load module %s\n"); + printf("Load module %s\n", filename); int fd = open(filename, O_RDONLY, 0); if ((fd > 0) && (len = read(fd, header, 128)) > 0) { @@ -435,7 +435,7 @@ void call(word pc) interp(mem_data + (mem_data[pc] + (mem_data[pc + 1] << 8))); break; case 3: // LIBRARY STDLIB::VIEWPORT - printf("Set Window %d, %d, %d, %n/n", POP, POP, POP, POP); + printf("Set Window %d, %d, %d, %d/n", POP, POP, POP, POP); PUSH(0); break; case 4: // LIBRARY STDLIB::PUTC From 63d34c52bb87fbc32f6358fd7eea1ca6e5f77b6a Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 14:48:05 -0700 Subject: [PATCH 03/44] Clean binaries --- PLASMA/src/makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PLASMA/src/makefile b/PLASMA/src/makefile index d94909d2..56ec5fa2 100755 --- a/PLASMA/src/makefile +++ b/PLASMA/src/makefile @@ -23,7 +23,7 @@ TXTTYPE = .TXT all: $(PLASM) $(PLVM) clean: - -rm *.o *~ *.a *.BIN + -rm *.o *~ *.a *.BIN $(PLASM) $(PLVM) $(PLASM): $(OBJS) $(INCS) cc $(OBJS) -o $(PLASM) From 8807fbcbc2a2116511eacaf49cc0345f236da966 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 17:10:15 -0700 Subject: [PATCH 04/44] Sample library --- PLASMA/src/testlib.pla | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100755 PLASMA/src/testlib.pla diff --git a/PLASMA/src/testlib.pla b/PLASMA/src/testlib.pla new file mode 100755 index 00000000..4e4dda9b --- /dev/null +++ b/PLASMA/src/testlib.pla @@ -0,0 +1,23 @@ +; +; Declare all imported modules and their data/functions. +; +import stdlib + predef cls, gotoxy, puts, putc +end +; +; Define functions. +; +export def puti(i) + if i < 0 + putc('-') + i = -i + fin + if i < 10 + putc(i + '0') + else + puti(i / 10) + putc(i % 10 + '0') + fin +end + +done From 4b3de4e458d0a3e8027fbb57240a19c87c305d50 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 17:11:28 -0700 Subject: [PATCH 05/44] Bug fixes for VM and code generator --- PLASMA/src/codegen.c | 12 ++++---- PLASMA/src/makefile | 12 +++++--- PLASMA/src/plvm.c | 73 +++++++++++++++++++++++--------------------- PLASMA/src/test.pla | 18 +++++++++-- 4 files changed, 68 insertions(+), 47 deletions(-) diff --git a/PLASMA/src/codegen.c b/PLASMA/src/codegen.c index 319872f4..13ad12df 100755 --- a/PLASMA/src/codegen.c +++ b/PLASMA/src/codegen.c @@ -557,14 +557,14 @@ void emit_brne(int tag) printf("\t%s\t$3E\t\t\t; BRNE\t_B%03d\n", DB, tag); printf("\t%s\t_B%03d-*\n", DW, tag); } -void emit_brlt(int tag) -{ - printf("\t%s\t$38\t\t\t; BRLT\t_B%03d\n", DB, tag); - printf("\t%s\t_B%03d-*\n", DW, tag); -} void emit_brgt(int tag) { - printf("\t%s\t$3A\t\t\t; BRGT\t_B%03d\n", DB, tag); + printf("\t%s\t$38\t\t\t; BRGT\t_B%03d\n", DB, tag); + printf("\t%s\t_B%03d-*\n", DW, tag); +} +void emit_brlt(int tag) +{ + printf("\t%s\t$3A\t\t\t; BRLT\t_B%03d\n", DB, tag); printf("\t%s\t_B%03d-*\n", DW, tag); } void emit_call(int tag, int type) diff --git a/PLASMA/src/makefile b/PLASMA/src/makefile index 56ec5fa2..dc7d868f 100755 --- a/PLASMA/src/makefile +++ b/PLASMA/src/makefile @@ -20,10 +20,10 @@ TXTTYPE = .TXT #SYSTYPE = \#ff0000 #TXTTYPE = \#040000 -all: $(PLASM) $(PLVM) +all: $(PLASM) $(PLVM) TESTLIB clean: - -rm *.o *~ *.a *.BIN $(PLASM) $(PLVM) + -rm *.o *~ *.a *.BIN TESTLIB $(PLASM) $(PLVM) $(PLASM): $(OBJS) $(INCS) cc $(OBJS) -o $(PLASM) @@ -31,12 +31,16 @@ $(PLASM): $(OBJS) $(INCS) $(PLVM): plvm.c cc plvm.c -o $(PLVM) -test: test.pla $(PLVM) $(PLASM) +TESTLIB: testlib.pla $(PLVM) $(PLASM) + ./$(PLASM) -A < testlib.pla > testlib.a + acme --setpc 4096 -o TESTLIB testlib.a + +test: test.pla TESTLIB $(PLVM) $(PLASM) ./$(PLASM) -A < test.pla > test.a acme --setpc 4096 -o TEST.BIN test.a ./$(PLVM) TEST.BIN MAIN -debug: test.pla $(PLVM) $(PLASM) +debug: test.pla TESTLIB $(PLVM) $(PLASM) ./$(PLASM) -A < test.pla > test.a acme --setpc 4096 -o TEST.BIN test.a ./$(PLVM) -s TEST.BIN MAIN diff --git a/PLASMA/src/plvm.c b/PLASMA/src/plvm.c index a9db52b3..d3a90f40 100755 --- a/PLASMA/src/plvm.c +++ b/PLASMA/src/plvm.c @@ -17,7 +17,8 @@ int show_state = 0; */ #define BYTE_PTR(bp) ((byte)(*bp++)) #define WORD_PTR(bp) ((word)(*bp++|(*++bp << 8))) -#define UWORD_PTR(bp) ((uword)(*bp++|(*++bp << 8))) +#define UWORD_PTR(bp) ((uword)((*bp++|(*++bp << 8))&0xFFFF)) +#define TO_UWORD(w) ((w)&0xFFFF) #define MOD_ADDR 0x1000 #define DEF_CALL 0x0800 #define DEF_CALLSZ 0x0800 @@ -502,17 +503,19 @@ OPTBL: DW ZERO,ADD,SUB,MUL,DIV,MOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E */ void interp(code *ip) { - word val, ea, frmsz, parmcnt; + int val, ea, frmsz, parmcnt; while (1) { if (show_state) { + char cmdline[16]; word *dsp = &eval_stack[EVAL_STACKSZ - 1]; printf("$%04X: $%02X [ ", ip - mem_data, *ip); while (dsp >= esp) printf("$%04X ", (*dsp--) & 0xFFFF); printf("]\n"); + gets(cmdline); } switch (*ip++) { @@ -548,7 +551,7 @@ void interp(code *ip) PUSH(ea % val); break; case 0x0C: // INCR : TOS = TOS + 1 - TOS++; + TOS++;; break; case 0x0E: // DECR : TOS = TOS - 1 TOS--; @@ -644,32 +647,28 @@ void interp(code *ip) break; case 0x38: // BRGT : TOS-1 > TOS ? IP += (IP) val = POP; - ea = POP; - if (ea <= val) + if (TOS > val) ip += WORD_PTR(ip) - 2; else ip += 2; break; case 0x3A: // BRLT : TOS-1 < TOS ? IP += (IP) val = POP; - ea = TOS; - if (ea >= val) + if (TOS < val) ip += WORD_PTR(ip) - 2; else ip += 2; break; case 0x3C: // BREQ : TOS == TOS-1 ? IP += (IP) val = POP; - ea = TOS; - if (ea == val) + if (TOS == val) ip += WORD_PTR(ip) - 2; else ip += 2; break; case 0x3E: // BRNE : TOS != TOS-1 ? IP += (IP) val = POP; - ea = TOS; - if (ea != val) + if (TOS != val) ip += WORD_PTR(ip) - 2; else ip += 2; @@ -680,32 +679,32 @@ void interp(code *ip) case 0x40: // ISEQ : TOS = TOS == TOS-1 val = POP; ea = POP; - PUSH(ea == val); + PUSH((ea == val) ? -1 : 0); break; case 0x42: // ISNE : TOS = TOS != TOS-1 val = POP; ea = POP; - PUSH(ea != val); + PUSH((ea != val) ? -1 : 0); break; case 0x44: // ISGT : TOS = TOS-1 > TOS val = POP; ea = POP; - PUSH(ea <= val); + PUSH((ea > val) ? -1 : 0); break; case 0x46: // ISLT : TOS = TOS-1 < TOS val = POP; ea = POP; - PUSH(ea >= val); + PUSH((ea < val) ? -1 : 0); break; case 0x48: // ISGE : TOS = TOS-1 >= TOS val = POP; ea = POP; - PUSH(ea < val); + PUSH((ea >= val) ? -1 : 0); break; case 0x4A: // ISLE : TOS = TOS-1 <= TOS val = POP; ea = POP; - PUSH(ea > val); + PUSH((ea <= val) ? -1 : 0); break; case 0x4C: // BRFLS : !TOS ? IP += (IP) if (!POP) @@ -740,14 +739,20 @@ void interp(code *ip) frmsz = BYTE_PTR(ip); mem_data[fp - frmsz] = fp; mem_data[fp - frmsz + 1] = fp >> 8; + if (show_state) + printf("< $%04X: $%04X > ", fp - frmsz, fp); fp -= frmsz; parmcnt = BYTE_PTR(ip); while (parmcnt--) { val = POP; - mem_data[fp + parmcnt + 2] = val; - mem_data[fp + parmcnt + 3] = val >> 8; + mem_data[fp + parmcnt * 2 + 2] = val; + mem_data[fp + parmcnt * 2 + 3] = val >> 8; + if (show_state) + printf("< $%04X: $%04X > ", fp + parmcnt * 2 + 2, mem_data[fp + parmcnt * 2 + 2] | (mem_data[fp + parmcnt * 2 + 3] >> 8)); } + if (show_state) + printf("\n"); break; case 0x5A: // LEAVE : DEL FRAME, IP = TOFP fp = mem_data[fp] | (mem_data[fp + 1] << 8); @@ -759,18 +764,18 @@ void interp(code *ip) * 0x60-0x6F */ case 0x60: // LB : TOS = BYTE (TOS) - val = UPOP; - PUSH(mem_data[val]); + ea = TO_UWORD(POP); + PUSH(mem_data[ea]); break; case 0x62: // LW : TOS = WORD (TOS) - ea = POP; + ea = TO_UWORD(POP); PUSH(mem_data[ea] | (mem_data[ea + 1] << 8)); break; case 0x64: // LLB : TOS = LOCALBYTE [IP] - PUSH(mem_data[fp + BYTE_PTR(ip)]); + PUSH(mem_data[TO_UWORD(fp + BYTE_PTR(ip))]); break; case 0x66: // LLW : TOS = LOCALWORD [IP] - ea = fp + BYTE_PTR(ip); + ea = TO_UWORD(fp + BYTE_PTR(ip)); PUSH(mem_data[ea] | (mem_data[ea + 1] << 8)); break; case 0x68: // LAB : TOS = BYTE (IP) @@ -781,10 +786,10 @@ void interp(code *ip) PUSH(mem_data[ea] | (mem_data[ea + 1] << 8)); break; case 0x6C: // DLB : TOS = TOS, LOCALBYTE [IP] = TOS - mem_data[fp + BYTE_PTR(ip)] = TOS; + mem_data[TO_UWORD(fp + BYTE_PTR(ip))] = TOS; break; case 0x6E: // DLW : TOS = TOS, LOCALWORD [IP] = TOS - ea = fp + BYTE_PTR(ip); + ea = TO_UWORD(fp + BYTE_PTR(ip)); mem_data[ea] = TOS; mem_data[ea + 1] = TOS >> 8; break; @@ -793,38 +798,38 @@ void interp(code *ip) */ case 0x70: // SB : BYTE (TOS) = TOS-1 val = POP; - ea = POP; + ea = TO_UWORD(POP); mem_data[ea] = val; break; case 0x72: // SW : WORD (TOS) = TOS-1 val = POP; - ea = POP; + ea = TO_UWORD(POP); mem_data[ea] = val; mem_data[ea + 1] = val >> 8; break; case 0x74: // SLB : LOCALBYTE [TOS] = TOS-1 - mem_data[fp + BYTE_PTR(ip)] = POP; + mem_data[TO_UWORD(fp + BYTE_PTR(ip))] = POP; break; case 0x76: // SLW : LOCALWORD [TOS] = TOS-1 - ea = fp + BYTE_PTR(ip); + ea = TO_UWORD(fp + BYTE_PTR(ip)); val = POP; mem_data[ea] = val; mem_data[ea + 1] = val >> 8; break; case 0x78: // SAB : BYTE (IP) = TOS - mem_data[WORD_PTR(ip)] = POP; + mem_data[TO_UWORD(WORD_PTR(ip))] = POP; break; case 0x7A: // SAW : WORD (IP) = TOS - ea = WORD_PTR(ip); + ea = TO_UWORD(WORD_PTR(ip)); val = POP; mem_data[ea] = val; mem_data[ea + 1] = val >> 8; break; case 0x7C: // DAB : TOS = TOS, BYTE (IP) = TOS - mem_data[WORD_PTR(ip)] = TOS; + mem_data[TO_UWORD(WORD_PTR(ip))] = TOS; break; case 0x7E: // DAW : TOS = TOS, WORD (IP) = TOS - ea = WORD_PTR(ip); + ea = TO_UWORD(WORD_PTR(ip)); mem_data[ea] = TOS; mem_data[ea + 1] = TOS >> 8; break; diff --git a/PLASMA/src/test.pla b/PLASMA/src/test.pla index e795c027..6e625a30 100755 --- a/PLASMA/src/test.pla +++ b/PLASMA/src/test.pla @@ -4,6 +4,10 @@ import stdlib predef cls, gotoxy, puts, putc end + +import testlib + predef puti +end ; ; Predeclare and functions called before defined. ; @@ -16,7 +20,6 @@ word defptr = main ; ; Define functions. ; - export def ascii byte i cls() @@ -25,10 +28,19 @@ export def ascii next end +export def nums + word i + for i = -10 to 10 + puti(i) + putc('\n') + next +end + export def main cls() - gotoxy(35,15) - return puts(@hello) + gotoxy(35,5) + puts(@hello) + return nums end export def indirect From def38e3c3a358c78fa4d81c1950cc1f35b7ad02a Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 17:16:16 -0700 Subject: [PATCH 06/44] unexport some defs --- PLASMA/src/test.pla | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PLASMA/src/test.pla b/PLASMA/src/test.pla index 6e625a30..454a3d11 100755 --- a/PLASMA/src/test.pla +++ b/PLASMA/src/test.pla @@ -9,7 +9,7 @@ import testlib predef puti end ; -; Predeclare and functions called before defined. +; Predeclare any functions called before defined. ; predef main ; @@ -20,15 +20,14 @@ word defptr = main ; ; Define functions. ; -export def ascii +def ascii byte i - cls() for i = 32 to 127 putc(i) next end -export def nums +def nums word i for i = -10 to 10 puti(i) @@ -38,6 +37,7 @@ end export def main cls() + ascii() gotoxy(35,5) puts(@hello) return nums From 1c569ff9091216d4de24300ad87345cbf882fa3e Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 17:29:10 -0700 Subject: [PATCH 07/44] Fix indirect call address TO_UWORD --- PLASMA/src/plvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PLASMA/src/plvm.c b/PLASMA/src/plvm.c index d3a90f40..d8f0c700 100755 --- a/PLASMA/src/plvm.c +++ b/PLASMA/src/plvm.c @@ -731,7 +731,7 @@ void interp(code *ip) call(UWORD_PTR(ip)); break; case 0x56: // ICALL : TOFP = IP, IP = (TOS) ; indirect call - val = POP; + val = TO_UWORD(POP); ea = mem_data[val] | (mem_data[val + 1] << 8); call(ea); break; From 48dea91662ff72ea2eec2176be6a6f32e0379bda Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 18:11:03 -0700 Subject: [PATCH 08/44] Create README.md --- PLASMA/README.md | 555 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 555 insertions(+) create mode 100644 PLASMA/README.md diff --git a/PLASMA/README.md b/PLASMA/README.md new file mode 100644 index 00000000..ec251e81 --- /dev/null +++ b/PLASMA/README.md @@ -0,0 +1,555 @@ + + +PLASMA + + + +Introduction + +PLASMA is a combination of virtual machine and assembler/compiler matched closely to the 6502 architecture. It is an attempt to satisfy a few challenges surrounding code size, efficient execution, small runtime and fast just-in-time compilation. By architecting a unique bytecode that maps nearly one-to-one to the higher level representation, the compiler/assembler can be very simple and execute quickly on the Apple II for a self-hosted environment. A modular approach provides for incremental development and code reuse. Different projects have led to the architecture of PLASMA, most notably Apple Pascal, FORTH, and my own Java VM for the 6502, VM02. Each has tried to map a generic VM to the 6502 with varying levels of success. Apple Pascal, based on the USCD Pascal using the p-code interpreter, was a very powerful system and ran fast enough on the Apple II to be interactive but didn't win any speed contests. FORTH was the poster child for efficiency and obtuse syntax. Commonly referred to as a write only language, it was difficult to come up to speed as a developer, especially when using other's code. My own project in creating a Java VM for the Apple II uncovered the folly of shoehorning a large system into something never intended to run 32 bit applications. + + +Low Level Implementation + +Both the Pascal and Java VMs used a bytecode to hide the underlying CPU architecture and offer platform agnostic application execution. The application and tool chains were easily moved from platform to platform by simply writing a bytecode interpreter and small runtime to translate the higher level constructs to the underlying hardware. The performance of the system was dependent on the actual hardware and efficiency of the interpreter. Just-in-time compilation wasn't really an option on small, 8 bit systems. FORTH, on the other hand, was usually implemented as a threaded interpreter. A threaded interpreter will use the address of functions to call as the code stream instead of a bytecode, eliminating one level of indirection with a slight increase in code size. The threaded approach can be made faster at the expense of another slight increase in size by inserting an actual Jump SubRoutine opcode before each address, thus removing the interpreter's inner loop altogether. + + +All three systems were implemented using stack architecture. Pascal and Java were meant to be compiled high level languages, using a stack machine as a simple compilation target. FORTH was meant to be written directly as a stack oriented language, similar to RPN on HP calculators. The 6502 is a challenging target due to it's unusual architecture so writing a bytecode interpreter for Pascal and Java results in some inefficiencies and limitations. FORTH's inner interpreter loop on the 6502 tends to be less efficient than most other CPUs. Another difference is how each system creates and manipulates it's stack. Pascal and Java use the 6502 hardware stack for all stack operations. Unfortunately the 6502 stack is hard-limited to 256 bytes. However, in normal usage this isn't too much of a problem as the compilers don't put undue pressure on the stack size by keeping most values in global or local variables. FORTH creates a small stack using a portion of the 6502's zero page, a 256 byte area of low memory that can be accessed with only a byte address and indexed using either of the X or Y registers. With zero page, the X register can be used as an indexed, indirect address and the Y register can be used as an indirect, indexed address. + + +A New Approach + +PLASMA takes an approach that uses the best of all the above implementations to create a unique, powerful and efficient platform for developing new applications on the Apple II. One goal was to create a very small VM runtime, bytecode interpreter, and module loader that could adjust the code size vs. performance optimizations to allow for interpreted code, threaded code, or efficiently compiled native code. The decision was made early on to implement a stack based architecture duplicating the approach taken by FORTH. Space in the zero page would be assigned to a 16 bit, 32 element evaluation stack, indexed by the X register. The stack is purposely not split between low and high values so as to allow reading and writing addresses stored directly on the stack. The trade off is that the stack pointer has to be incremented and decremented by two for every push/pop operation. A simple compiler was written so that higher level constructs could be used and global/local variables would hold values instead of using clever stack manipulation. Function/procedure frames would allow for local variables, but with a limitation - the frame could be no larger than 256 bytes. By enforcing this limitation, the function frame could easily be accessed through a frame pointer value in zero page, indexed by the Y register. The call stack uses the 6502's hardware stack resulting in the same 256 byte limitation imposed by the hardware. However, this limitation could be lifted by extending the call sequence to save and restore the return address in the function frame. This was not done initially for performance reasons and simplicity of implementation. One of the goals of PLASMA was to allow for intermixing of functions implemented as bytecode, threaded code, or native code. Taking a page from the FORTH play book, a function call is implemented as a native subroutine call to an address. If the function is in bytecode, the first thing it does is call back into the interpreter to execute the following bytecode. Functions can be selectively expanded as bytecode, threaded code, or natively compiled, all at load time. Threaded code expands to about 3X the size of bytecode with about 3X the performance. Native code is about 5X-10X the size with a significant improvement in performance. The native code compiler uses a strategy of caching the Top-Of-Stack value in the Y and A registers of the 6502. The compiler also tracks the TOS pointer and adjusts the address accordingly to avoid actual manipulation of the X register. The X register in effect becomes the frame pointer for the evaluation stack. Function call parameters are pushed onto the evaluation stack in order they are written. The first operation inside of the function call is to pull the parameters off the evaluation stack and put them in local frame storage. Function callers and callees must agree on the number of parameters to avoid stack underflow/overflow. All functions return a value on the evaluation stack regardless of it being used or not. Lastly, PLASMA is not a typed language. Just like assembly, any value can represent a character, integer, or address. It's the programmer's job to know the type. Only bytes and words are known to PLASMA. Bytes are unsigned 8 bit quantities, words are signed 16 bit quantities. All stack operations involve 16 bits of precision. + + +The PLASMA low level operations are defined as: + + + +OP Description + +ZERO push zero on the stack + +DROP drop top stack value + +DUP duplicate top stack value + +OVER duplicate next from top stack value + +SWAP swap two topmost stack values + +ADD add top two values, leave result on top + +SUB subtract next from top from top, leave result on top + +MUL multiply two topmost stack values, leave result on top + +DIV divide next from top by top, leave result on top + +MOD divide next from top by top, leave remainder on top + +INCR increment top of stack + +DECR decrement top of stack + +NEG negate top of stack + +COMP compliment top of stack + +BAND bit wise AND top two values, leave result on top + +IOR bit wise inclusive OR top two values, leave result on top + +XOR bit wise exclusive OR top two values, leave result on top + +NOT logical NOT of top of stack + +LOR logical OR top two values, leave result on top + +LAND logical AND top two values, leave result on top + +SHL shift left next from top by top, leave result on top + +SHR shift right next from top by top, leave result on top + +IDXB add top of stack to next from top, leave result on top + +IDXW add 2X top of stack to next from top, leave result on top + +LAA load absolute address + +LLA load local address from frame offset + +CB constant byte + +CW constant word + +LB load byte from top of stack address + +LW load word from top of stack address + +LLB load byte from frame offset + +LLW load word from frame offset + +LAB load byte from absolute address + +LAW load word from absolute address + +SB store top of stack byte into next from top address + +SW store top of stack word into next from top address + +SLB store top of stack into local byte at frame offset + +SLW store top of stack into local word at frame offset + +SAB store top of stack into byte at absolute address + +SAW store top of stack into word at absolute address + +DLB duplicate top of stack into local byte at frame offset + +DLW duplicate top of stack into local word at frame offset + +DAB duplicate top of stack into byte at absolute address + +DAW duplicate top of stack into word at absolute address + +BRGT branch next from top greater than top + +BRLT branch next from top less than top + +BREQ branch next from top equal to top + +BRNE branch next from top not equal to top + +ISEQ if next from top is equal to top, set top true + +ISNE if next from top is not equal to top, set top true + +ISGT if next from top is greater than top, set top true + +ISLT if next from top is less than top, set top true + +ISGE if next from top is greater than or equal to top, set top true + +ISLE if next from top is less than or equal to top, set top true + +BRFLS branch if top of stack is zero + +BRTRU branch if top of stack is non-zero + +BRNCH branch to address + +CALL sub routine call with stack parameters + +ICAL sub routine call to indirect address on stack top with stack parameters + +ENTER allocate frame size and copy stack parameters to local frame + +LEAVE deallocate frame and return from sub routine call + +RET return from sub routine call + +PUSH push top to call stack + +PULL pull from call stack + +PLASMA Compiler/Assembler + +Although the low-level operations could easily by coded by hand, they were chosen to be an easy target for a simple compiler. Think along the lines of an advanced assembler or stripped down C compiler ( C--). Taking concepts from BASIC, Pascal, C and assembler, the PLASMA compiler is simple yet expressive. + + +Comments are allowed throughout the source, starting with the ‘;’ character. The rest of the line is ignored. + + +; Data and text buffer constants + + +Hexadecimal constants are preceded with a ‘$’ to identify them as such. + + +$C030 ; Speaker address + + +Constants, Variables and Functions + +The source code of a PLASMA module first defines constants, variables and data. Constants must be initialized with a value. Variables can have sizes associated with them to declare storage space. Data can be declared with or without a variable name associated with it. Arrays, tables, strings and any predeclared data can be created and accessed in multiple ways. + + +; + +; Constants used for hardware and flags + +; + +const speaker = $C030 + +const changed = 1 + +const insmode = 2 + +; + +; Array declaration of screen row addresses + +; + +word txtscrn[] = [$0400,$0480,$0500,$0580,$0600,$0680,$0700,$0780] + +word = [$0428,$04A8,$0528,$05A8,$0628,$06A8,$0728,$07A8] + +word = [$0450,$04D0,$0550,$05D0,$0650,$06D0,$0750,$07D0] + +; + +; Misc global variables + +; + +byte flags = 0 + +word numlines = 0 + +byte cursx, cursy + +word cursrow, scrntop, cursptr + + +Variables can have optional brackets; empty brackets don’t reserve any space for the variable but are useful as a label for data that is defined following the variable. Brackets with a constant inside defines a minimum size reserved for the variable. Any data following the variable will take at least the amount of reserved space, but potentially more. + +Strings are defined like Pascal strings, a length byte followed by the string characters so they can be a maximum of 255 characters long. Strings can only appear in the variable definitions of a module. String constants can’t be used in expressions or statements. + + +; + +; An initialized string of 64 characters + +; + +byte txtfile[64] = "UNTITLED" + + +Functions are defined after all constants, variables and data. Functions can be forward declared with a func type in the constant and variable declarations. Functions have optional parameters and always return a value. By using one of three function declarations (def, deft and defn) you can have the function loaded as interpreted bytecode, threaded calls into the interpreter, or natively compiled code. There are space and time tradeoffs between the three choices. Bytecode is the best choice for the majority of functions. It has decent performance and is extremely compact. Threaded code would be the choice for functions that are called often but are not leaf routines, i.e. they themselves call other functions. Native code is a good choice for small, leaf functions that are called often and need the highest performance. Simply altering the definition is all that is required to set the function code implementation. Functions can have their own variable declarations. However, unlike the global declarations, no data can be predeclared, only storage space. There is also a limit of 256 bytes of local storage. Each parameter takes two bytes of local storage, plus two bytes for the previous frame pointer. If a function has no parameters or local variables, no local frame will be created, improving performance. A function can specify a value to return. If no return value is specified, a default of 0 will be returned. + + +After functions are defined, the main code for the module follows. There is no option to declare how the main code is loaded - it is always bytecode. The last statement in the module must be done, or else a compile error is issued. + + +There are four basic types of data that can be manipulated: constants, variables, addresses, and functions. Memory can only be read or written as either a byte or a word. Bytes are unsigned 8 bit quantities, words are signed 16 bit quantities. Everything on the evaluation stack is treated as a word. Other than that, any value can be treated as a pointer, address, function, character, integer, etc. There are convenience operations in PLASMA to easily manipulate addresses and expressions as pointers, arrays, structures, functions, or combinations thereof. If a variable is declared as a byte, it can be accessed as a simple, single dimension byte array by using brackets to indicate the offset. Any expression can calculate the indexed offset. A word variable can be accessed as a word array in the same fashion. In order to access expressions or constants as arrays, a type identifier has to be inserted before the brackets. a ‘.’ character denotes a byte type, a ‘:’ character denotes a word type. Along with brackets to calculate an indexed offset, a constant can be used after the ‘.’ or ‘:’ and will be added to the base address. The constant can be a defined const to allow for structure style syntax. If the offset is a known constant, using the constant offset is a much more efficient way to address the elements over an array index. Multidimensional arrays are treated as arrays of array pointers. Multiple brackets can follow the ‘.’ or ‘:’ type identifier, but all but the last index will be treated as a pointer to an array. + + +word hgrscan[] = [$2000,$2400,$2800,$2C00,$3000,$3400,$3800,$3C00] + +word = [$2080,$2480,$2880,$2C80,$3080,$3480,$3880,$3C80] + + + +hgrscan:[yscan][xscan] = fillval + + +Values can be treated as pointers by preceding them with a ‘^’ for byte pointers, ‘*’ for word pointers. + + +strlen = ^(srcstr) + + +Addresses of variables and functions can be taken with a preceding ‘@’, address-of operator. Parenthesis can surround an expression to be used as a pointer, but not address-of. + + +Functions can have optional parameters when called. Defined functions without parameters can be called simply: + + +def redraw + + cursoff + + drawscrn(scrntop, scrnleft) + + curson + +end + + +redraw + + +Functions with parameters or expressions to be used as a function address to call must use parenthesis, even if empty. + + +word keyin + +byte key + + +keyin = @keyin2plus ; address-of keyin2plus function + +key = (keyin)() + + +Expressions and Statements + +Expressions are algebraic. Data is free-form, but all operations on the evaluation stack use 16 bits of precision with the exception of byte load and stores. A stand-alone expression will be evaluated and read from or called. This allows for easy access to the Apple’s soft switches and other memory mapped hardware. The value of the expression is dropped. + + +const speaker=$C030 + +^speaker ; click speaker + + +close(refnum) + + +More complex expressions can be built up using algebraic unary and binary operations. + + + +OP Unary Operation + +^ byte pointer + +* word pointer + +@ address of + +- negate + +# bitwise compliment + +! logical NOT + + + + +OP Binary Operation + +* multiply + +/ divide + +% modulo + ++ add + +- subtract + +<< shift left + +>> shift right + +& bitwise AND + +| bitwise OR + +^ bitwise XOR + +== equals + +<> not equal + +>= greater than or equal + +> greater than + +<= less than or equal + +< less than + +OR logical OR + +AND logical AND + + + +Statements are built up from expressions and control flow keywords. Simplicity of syntax took precedence over flexibility and complexity. The simplest statement is the basic assignment using ‘=’. + + +byte numchars + +numchars = 0 + + +Expressions can be built up with constants, variables, function calls, addresses, and pointers/arrays. Comparison operators evaluate to 0 or -1 instead of the more traditional 0 or 1. The use of -1 allows binary operations to be applied to other non-zero values and still retain a non-zero result. Any conditional tests check only for zero and non-zero values. + + +Control structures affect the flow of control through the program. There are conditional and looping constructs. The most widely used is probably the if/elsif/else/fin construct. + + +if ^pushbttn3 < 128 + + if key == $C0 + + key = $D0 ; P + + elsif key == $DD + + key = $CD ; M + + elsif key == $DE + + key = $CE ; N + + fin + +else + + key = key ? $E0 + +fin + + +The case/of/otherwise/merge statement is similar to the if/elsif/else/fin construct except that it is more efficient. It selects one path based on the evaluated expressions, then merges the code path back together at the end. However only the case value is compared against a list of expressions. The expressions do not need to be constants, they can be any valid expression. The list of expressions is evaluated in order, so for efficiency sake, place the most common cases earlier in the list. + + +when keypressed + + is keyarrowup + + cursup + + is keyarrowdown + + cursdown + + is keyarrowleft + + cursleft + + is keyarrowright + + cursright + + is keyctrlx + + cutline + + is keyctrlv + + pasteline + + is keyescape + + cursoff + + cmdmode + + redraw + + otherwise + + bell + +wend + + +The most common looping statement is the for/next construct. + + +for xscan = 0 to 19 + + (scanptr):[xscan] = val + +next + + +The for/next statement will efficiently increment or decrement a variable form the starting value to the ending value. The increment/decrement amount can be set with the step option after the ending value; the default is one. If the ending value is less than the starting value, use downto instead of to to progress in the negative direction. Only use positive step values. The to or downto will add or subtract the step value appropriately. + + +for i = heapmapsz - 1 downto 0 + + if sheapmap.[i] <> $FF + + mapmask = szmask + + fin + +next + + +while/loop statements will continue looping as long as the while expression is non-zero. + + +while !(mask & 1) + + addr = addr + 16 + + mask = mask >> 1 + +loop + + +Lastly, the repeat/until statement will continue looping as long as the until expression is zero. + + +repeat + + txtbuf = read(refnum, @txtbuf + 1, maxlnlen) + + numlines = numlines + 1 + +until txtbuf == 0 or numlines == maxlines + + +Runtime + +PLASMA includes a very minimal runtime that nevertheless provides a great deal of functionality to the system. Two system calls are provided to access native 6502 routines (usually in ROM) and ProDOS. + + +call6502(aReg, xReg, yReg, statusReg, addr) returns a pointer to a four byte structure containing the A,X,Y and STATUS register results. + + +const xreg = 1 + +const getlin = $FD6A + +numchars = (call6502(0, 0, 0, 0, getlin)).xreg ; return char count in X reg + + +prodos(cmd, params)calls ProDOS, returning the status value. + + +def read(refnum, buff, len) + + byte params[8] + + + params.0 = 4 + + params.1 = refnum + + params:2 = buff + + params:4 = len + + perr = prodos($CA, @params) + + return params:6 + +end + + +cout(char), prstr(string), prstrz(stringz) are handy utility routines for printing to the standard Apple II COUT routine. + + +cout('.') + +byte okstr[] = "OK" + +prstr(@okstr) + + +memset(val16, addr, len) will fill memory with a 16 bit value. memcpy(srcaddr, dstaddr, len) will copy memory from one address to another, taking care to copy in the proper direction. + + +byte nullstr[] = "" + +memset(@nullstr, strlinbuf, maxfill * 2) ; fill line buff with pointer to null string + +memcpy(strptr + ofst + 1, scrnptr, numchars) + + +Implementation Details + +The original design concept was to create an efficient, flexible, and expressive environment for building applications directly on the Apple II. Choosing a stack based architecture was easy after much experience with other stack based implementations. It also makes the compiler simple to implement. The first take on the stack architecture was to make it a very strict stack architecture in that everything had to be on the stack. The only opcode with operands was the CONSTANT opcode. This allowed for a very small bytecode interpreter and a very easy compile target. However, only when adding an opcode with operands that would greatly improved performance, native code generation or code size was it done. The opcode table grew slowly over time but still retains a small runtime interpreter with good native code density. + From 75285b94b7d04df5f90d1c1d9d7808c1f5d5be37 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 18:26:23 -0700 Subject: [PATCH 09/44] Update README.md Add some formatting mark-down --- PLASMA/README.md | 218 +++++++++++------------------------------------ 1 file changed, 50 insertions(+), 168 deletions(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index ec251e81..74ca4dc6 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -1,16 +1,14 @@ - PLASMA +====== - - Introduction - +------------ PLASMA is a combination of virtual machine and assembler/compiler matched closely to the 6502 architecture. It is an attempt to satisfy a few challenges surrounding code size, efficient execution, small runtime and fast just-in-time compilation. By architecting a unique bytecode that maps nearly one-to-one to the higher level representation, the compiler/assembler can be very simple and execute quickly on the Apple II for a self-hosted environment. A modular approach provides for incremental development and code reuse. Different projects have led to the architecture of PLASMA, most notably Apple Pascal, FORTH, and my own Java VM for the 6502, VM02. Each has tried to map a generic VM to the 6502 with varying levels of success. Apple Pascal, based on the USCD Pascal using the p-code interpreter, was a very powerful system and ran fast enough on the Apple II to be interactive but didn't win any speed contests. FORTH was the poster child for efficiency and obtuse syntax. Commonly referred to as a write only language, it was difficult to come up to speed as a developer, especially when using other's code. My own project in creating a Java VM for the Apple II uncovered the folly of shoehorning a large system into something never intended to run 32 bit applications. Low Level Implementation - +------------------------ Both the Pascal and Java VMs used a bytecode to hide the underlying CPU architecture and offer platform agnostic application execution. The application and tool chains were easily moved from platform to platform by simply writing a bytecode interpreter and small runtime to translate the higher level constructs to the underlying hardware. The performance of the system was dependent on the actual hardware and efficiency of the interpreter. Just-in-time compilation wasn't really an option on small, 8 bit systems. FORTH, on the other hand, was usually implemented as a threaded interpreter. A threaded interpreter will use the address of functions to call as the code stream instead of a bytecode, eliminating one level of indirection with a slight increase in code size. The threaded approach can be made faster at the expense of another slight increase in size by inserting an actual Jump SubRoutine opcode before each address, thus removing the interpreter's inner loop altogether. @@ -18,13 +16,13 @@ All three systems were implemented using stack architecture. Pascal and Java we A New Approach - +-------------- PLASMA takes an approach that uses the best of all the above implementations to create a unique, powerful and efficient platform for developing new applications on the Apple II. One goal was to create a very small VM runtime, bytecode interpreter, and module loader that could adjust the code size vs. performance optimizations to allow for interpreted code, threaded code, or efficiently compiled native code. The decision was made early on to implement a stack based architecture duplicating the approach taken by FORTH. Space in the zero page would be assigned to a 16 bit, 32 element evaluation stack, indexed by the X register. The stack is purposely not split between low and high values so as to allow reading and writing addresses stored directly on the stack. The trade off is that the stack pointer has to be incremented and decremented by two for every push/pop operation. A simple compiler was written so that higher level constructs could be used and global/local variables would hold values instead of using clever stack manipulation. Function/procedure frames would allow for local variables, but with a limitation - the frame could be no larger than 256 bytes. By enforcing this limitation, the function frame could easily be accessed through a frame pointer value in zero page, indexed by the Y register. The call stack uses the 6502's hardware stack resulting in the same 256 byte limitation imposed by the hardware. However, this limitation could be lifted by extending the call sequence to save and restore the return address in the function frame. This was not done initially for performance reasons and simplicity of implementation. One of the goals of PLASMA was to allow for intermixing of functions implemented as bytecode, threaded code, or native code. Taking a page from the FORTH play book, a function call is implemented as a native subroutine call to an address. If the function is in bytecode, the first thing it does is call back into the interpreter to execute the following bytecode. Functions can be selectively expanded as bytecode, threaded code, or natively compiled, all at load time. Threaded code expands to about 3X the size of bytecode with about 3X the performance. Native code is about 5X-10X the size with a significant improvement in performance. The native code compiler uses a strategy of caching the Top-Of-Stack value in the Y and A registers of the 6502. The compiler also tracks the TOS pointer and adjusts the address accordingly to avoid actual manipulation of the X register. The X register in effect becomes the frame pointer for the evaluation stack. Function call parameters are pushed onto the evaluation stack in order they are written. The first operation inside of the function call is to pull the parameters off the evaluation stack and put them in local frame storage. Function callers and callees must agree on the number of parameters to avoid stack underflow/overflow. All functions return a value on the evaluation stack regardless of it being used or not. Lastly, PLASMA is not a typed language. Just like assembly, any value can represent a character, integer, or address. It's the programmer's job to know the type. Only bytes and words are known to PLASMA. Bytes are unsigned 8 bit quantities, words are signed 16 bit quantities. All stack operations involve 16 bits of precision. The PLASMA low level operations are defined as: - + OP Description @@ -156,80 +154,61 @@ PUSH push top to call stack PULL pull from call stack -PLASMA Compiler/Assembler + +PLASMA Compiler/Assembler +========================= Although the low-level operations could easily by coded by hand, they were chosen to be an easy target for a simple compiler. Think along the lines of an advanced assembler or stripped down C compiler ( C--). Taking concepts from BASIC, Pascal, C and assembler, the PLASMA compiler is simple yet expressive. Comments are allowed throughout the source, starting with the ‘;’ character. The rest of the line is ignored. - + ; Data and text buffer constants - + Hexadecimal constants are preceded with a ‘$’ to identify them as such. - + $C030 ; Speaker address - + Constants, Variables and Functions - +---------------------------------- The source code of a PLASMA module first defines constants, variables and data. Constants must be initialized with a value. Variables can have sizes associated with them to declare storage space. Data can be declared with or without a variable name associated with it. Arrays, tables, strings and any predeclared data can be created and accessed in multiple ways. - + ; - ; Constants used for hardware and flags - ; - const speaker = $C030 - const changed = 1 - const insmode = 2 - ; - ; Array declaration of screen row addresses - ; - word txtscrn[] = [$0400,$0480,$0500,$0580,$0600,$0680,$0700,$0780] - word = [$0428,$04A8,$0528,$05A8,$0628,$06A8,$0728,$07A8] - word = [$0450,$04D0,$0550,$05D0,$0650,$06D0,$0750,$07D0] - ; - ; Misc global variables - ; - byte flags = 0 - word numlines = 0 - byte cursx, cursy - word cursrow, scrntop, cursptr - + Variables can have optional brackets; empty brackets don’t reserve any space for the variable but are useful as a label for data that is defined following the variable. Brackets with a constant inside defines a minimum size reserved for the variable. Any data following the variable will take at least the amount of reserved space, but potentially more. Strings are defined like Pascal strings, a length byte followed by the string characters so they can be a maximum of 255 characters long. Strings can only appear in the variable definitions of a module. String constants can’t be used in expressions or statements. - + ; - ; An initialized string of 64 characters - ; - byte txtfile[64] = "UNTITLED" - + Functions are defined after all constants, variables and data. Functions can be forward declared with a func type in the constant and variable declarations. Functions have optional parameters and always return a value. By using one of three function declarations (def, deft and defn) you can have the function loaded as interpreted bytecode, threaded calls into the interpreter, or natively compiled code. There are space and time tradeoffs between the three choices. Bytecode is the best choice for the majority of functions. It has decent performance and is extremely compact. Threaded code would be the choice for functions that are called often but are not leaf routines, i.e. they themselves call other functions. Native code is a good choice for small, leaf functions that are called often and need the highest performance. Simply altering the definition is all that is required to set the function code implementation. Functions can have their own variable declarations. However, unlike the global declarations, no data can be predeclared, only storage space. There is also a limit of 256 bytes of local storage. Each parameter takes two bytes of local storage, plus two bytes for the previous frame pointer. If a function has no parameters or local variables, no local frame will be created, improving performance. A function can specify a value to return. If no return value is specified, a default of 0 will be returned. @@ -239,315 +218,218 @@ After functions are defined, the main code for the module follows. There is no There are four basic types of data that can be manipulated: constants, variables, addresses, and functions. Memory can only be read or written as either a byte or a word. Bytes are unsigned 8 bit quantities, words are signed 16 bit quantities. Everything on the evaluation stack is treated as a word. Other than that, any value can be treated as a pointer, address, function, character, integer, etc. There are convenience operations in PLASMA to easily manipulate addresses and expressions as pointers, arrays, structures, functions, or combinations thereof. If a variable is declared as a byte, it can be accessed as a simple, single dimension byte array by using brackets to indicate the offset. Any expression can calculate the indexed offset. A word variable can be accessed as a word array in the same fashion. In order to access expressions or constants as arrays, a type identifier has to be inserted before the brackets. a ‘.’ character denotes a byte type, a ‘:’ character denotes a word type. Along with brackets to calculate an indexed offset, a constant can be used after the ‘.’ or ‘:’ and will be added to the base address. The constant can be a defined const to allow for structure style syntax. If the offset is a known constant, using the constant offset is a much more efficient way to address the elements over an array index. Multidimensional arrays are treated as arrays of array pointers. Multiple brackets can follow the ‘.’ or ‘:’ type identifier, but all but the last index will be treated as a pointer to an array. - + word hgrscan[] = [$2000,$2400,$2800,$2C00,$3000,$3400,$3800,$3C00] - word = [$2080,$2480,$2880,$2C80,$3080,$3480,$3880,$3C80] - - hgrscan:[yscan][xscan] = fillval - + Values can be treated as pointers by preceding them with a ‘^’ for byte pointers, ‘*’ for word pointers. - + strlen = ^(srcstr) - + def redraw - cursoff - drawscrn(scrntop, scrnleft) - curson - end - redraw - + Functions with parameters or expressions to be used as a function address to call must use parenthesis, even if empty. - + word keyin - byte key - keyin = @keyin2plus ; address-of keyin2plus function - key = (keyin)() - + Expressions and Statements Expressions are algebraic. Data is free-form, but all operations on the evaluation stack use 16 bits of precision with the exception of byte load and stores. A stand-alone expression will be evaluated and read from or called. This allows for easy access to the Apple’s soft switches and other memory mapped hardware. The value of the expression is dropped. - + const speaker=$C030 ^speaker ; click speaker - - close(refnum) - + More complex expressions can be built up using algebraic unary and binary operations. - + OP Unary Operation ^ byte pointer - * word pointer - @ address of - - negate - # bitwise compliment - ! logical NOT - - OP Binary Operation * multiply - / divide - % modulo - + add - - subtract - << shift left - >> shift right - & bitwise AND - | bitwise OR - ^ bitwise XOR - == equals - <> not equal - >= greater than or equal - > greater than - <= less than or equal - < less than - OR logical OR - AND logical AND - - + Statements are built up from expressions and control flow keywords. Simplicity of syntax took precedence over flexibility and complexity. The simplest statement is the basic assignment using ‘=’. - + byte numchars - numchars = 0 - + Expressions can be built up with constants, variables, function calls, addresses, and pointers/arrays. Comparison operators evaluate to 0 or -1 instead of the more traditional 0 or 1. The use of -1 allows binary operations to be applied to other non-zero values and still retain a non-zero result. Any conditional tests check only for zero and non-zero values. Control structures affect the flow of control through the program. There are conditional and looping constructs. The most widely used is probably the if/elsif/else/fin construct. - + if ^pushbttn3 < 128 - if key == $C0 - key = $D0 ; P - elsif key == $DD - key = $CD ; M - elsif key == $DE - key = $CE ; N - fin - else - key = key ? $E0 - fin + +The when/is/otherwise/merge statement is similar to the if/elsif/else/fin construct except that it is more efficient. It selects one path based on the evaluated expressions, then merges the code path back together at the end. However only the 'when' value is compared against a list of expressions. The expressions do not need to be constants, they can be any valid expression. The list of expressions is evaluated in order, so for efficiency sake, place the most common cases earlier in the list. -The case/of/otherwise/merge statement is similar to the if/elsif/else/fin construct except that it is more efficient. It selects one path based on the evaluated expressions, then merges the code path back together at the end. However only the case value is compared against a list of expressions. The expressions do not need to be constants, they can be any valid expression. The list of expressions is evaluated in order, so for efficiency sake, place the most common cases earlier in the list. - - + when keypressed - is keyarrowup - cursup - is keyarrowdown - cursdown - is keyarrowleft - cursleft - is keyarrowright - cursright - is keyctrlx - cutline - is keyctrlv - pasteline - is keyescape - cursoff - cmdmode - redraw - otherwise - bell - wend - + The most common looping statement is the for/next construct. - + for xscan = 0 to 19 - (scanptr):[xscan] = val - next - + The for/next statement will efficiently increment or decrement a variable form the starting value to the ending value. The increment/decrement amount can be set with the step option after the ending value; the default is one. If the ending value is less than the starting value, use downto instead of to to progress in the negative direction. Only use positive step values. The to or downto will add or subtract the step value appropriately. - + for i = heapmapsz - 1 downto 0 - if sheapmap.[i] <> $FF - mapmask = szmask - fin - next - + while/loop statements will continue looping as long as the while expression is non-zero. - + while !(mask & 1) - addr = addr + 16 - mask = mask >> 1 - loop - + Lastly, the repeat/until statement will continue looping as long as the until expression is zero. - + repeat - txtbuf = read(refnum, @txtbuf + 1, maxlnlen) - numlines = numlines + 1 - until txtbuf == 0 or numlines == maxlines - + Runtime PLASMA includes a very minimal runtime that nevertheless provides a great deal of functionality to the system. Two system calls are provided to access native 6502 routines (usually in ROM) and ProDOS. - call6502(aReg, xReg, yReg, statusReg, addr) returns a pointer to a four byte structure containing the A,X,Y and STATUS register results. - + const xreg = 1 - const getlin = $FD6A numchars = (call6502(0, 0, 0, 0, getlin)).xreg ; return char count in X reg - - prodos(cmd, params)calls ProDOS, returning the status value. - def read(refnum, buff, len) - byte params[8] - params.0 = 4 - params.1 = refnum - params:2 = buff - params:4 = len - perr = prodos($CA, @params) - return params:6 - end - + cout(char), prstr(string), prstrz(stringz) are handy utility routines for printing to the standard Apple II COUT routine. - + cout('.') - byte okstr[] = "OK" - prstr(@okstr) - + memset(val16, addr, len) will fill memory with a 16 bit value. memcpy(srcaddr, dstaddr, len) will copy memory from one address to another, taking care to copy in the proper direction. - + byte nullstr[] = "" - memset(@nullstr, strlinbuf, maxfill * 2) ; fill line buff with pointer to null string - memcpy(strptr + ofst + 1, scrnptr, numchars) - + Implementation Details From d2083d19a1568ec2c9b3dacf9c00b69d42675d5f Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 19:42:47 -0700 Subject: [PATCH 10/44] Update README.md --- PLASMA/README.md | 408 +++++++++++++++++++---------------------------- 1 file changed, 164 insertions(+), 244 deletions(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index 74ca4dc6..5f8e326e 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -1,307 +1,227 @@ +###PLASMA +##Introduction -PLASMA -====== - -Introduction ------------- PLASMA is a combination of virtual machine and assembler/compiler matched closely to the 6502 architecture. It is an attempt to satisfy a few challenges surrounding code size, efficient execution, small runtime and fast just-in-time compilation. By architecting a unique bytecode that maps nearly one-to-one to the higher level representation, the compiler/assembler can be very simple and execute quickly on the Apple II for a self-hosted environment. A modular approach provides for incremental development and code reuse. Different projects have led to the architecture of PLASMA, most notably Apple Pascal, FORTH, and my own Java VM for the 6502, VM02. Each has tried to map a generic VM to the 6502 with varying levels of success. Apple Pascal, based on the USCD Pascal using the p-code interpreter, was a very powerful system and ran fast enough on the Apple II to be interactive but didn't win any speed contests. FORTH was the poster child for efficiency and obtuse syntax. Commonly referred to as a write only language, it was difficult to come up to speed as a developer, especially when using other's code. My own project in creating a Java VM for the Apple II uncovered the folly of shoehorning a large system into something never intended to run 32 bit applications. +#Low Level Implementation -Low Level Implementation ------------------------- Both the Pascal and Java VMs used a bytecode to hide the underlying CPU architecture and offer platform agnostic application execution. The application and tool chains were easily moved from platform to platform by simply writing a bytecode interpreter and small runtime to translate the higher level constructs to the underlying hardware. The performance of the system was dependent on the actual hardware and efficiency of the interpreter. Just-in-time compilation wasn't really an option on small, 8 bit systems. FORTH, on the other hand, was usually implemented as a threaded interpreter. A threaded interpreter will use the address of functions to call as the code stream instead of a bytecode, eliminating one level of indirection with a slight increase in code size. The threaded approach can be made faster at the expense of another slight increase in size by inserting an actual Jump SubRoutine opcode before each address, thus removing the interpreter's inner loop altogether. - All three systems were implemented using stack architecture. Pascal and Java were meant to be compiled high level languages, using a stack machine as a simple compilation target. FORTH was meant to be written directly as a stack oriented language, similar to RPN on HP calculators. The 6502 is a challenging target due to it's unusual architecture so writing a bytecode interpreter for Pascal and Java results in some inefficiencies and limitations. FORTH's inner interpreter loop on the 6502 tends to be less efficient than most other CPUs. Another difference is how each system creates and manipulates it's stack. Pascal and Java use the 6502 hardware stack for all stack operations. Unfortunately the 6502 stack is hard-limited to 256 bytes. However, in normal usage this isn't too much of a problem as the compilers don't put undue pressure on the stack size by keeping most values in global or local variables. FORTH creates a small stack using a portion of the 6502's zero page, a 256 byte area of low memory that can be accessed with only a byte address and indexed using either of the X or Y registers. With zero page, the X register can be used as an indexed, indirect address and the Y register can be used as an indirect, indexed address. +#A New Approach -A New Approach --------------- PLASMA takes an approach that uses the best of all the above implementations to create a unique, powerful and efficient platform for developing new applications on the Apple II. One goal was to create a very small VM runtime, bytecode interpreter, and module loader that could adjust the code size vs. performance optimizations to allow for interpreted code, threaded code, or efficiently compiled native code. The decision was made early on to implement a stack based architecture duplicating the approach taken by FORTH. Space in the zero page would be assigned to a 16 bit, 32 element evaluation stack, indexed by the X register. The stack is purposely not split between low and high values so as to allow reading and writing addresses stored directly on the stack. The trade off is that the stack pointer has to be incremented and decremented by two for every push/pop operation. A simple compiler was written so that higher level constructs could be used and global/local variables would hold values instead of using clever stack manipulation. Function/procedure frames would allow for local variables, but with a limitation - the frame could be no larger than 256 bytes. By enforcing this limitation, the function frame could easily be accessed through a frame pointer value in zero page, indexed by the Y register. The call stack uses the 6502's hardware stack resulting in the same 256 byte limitation imposed by the hardware. However, this limitation could be lifted by extending the call sequence to save and restore the return address in the function frame. This was not done initially for performance reasons and simplicity of implementation. One of the goals of PLASMA was to allow for intermixing of functions implemented as bytecode, threaded code, or native code. Taking a page from the FORTH play book, a function call is implemented as a native subroutine call to an address. If the function is in bytecode, the first thing it does is call back into the interpreter to execute the following bytecode. Functions can be selectively expanded as bytecode, threaded code, or natively compiled, all at load time. Threaded code expands to about 3X the size of bytecode with about 3X the performance. Native code is about 5X-10X the size with a significant improvement in performance. The native code compiler uses a strategy of caching the Top-Of-Stack value in the Y and A registers of the 6502. The compiler also tracks the TOS pointer and adjusts the address accordingly to avoid actual manipulation of the X register. The X register in effect becomes the frame pointer for the evaluation stack. Function call parameters are pushed onto the evaluation stack in order they are written. The first operation inside of the function call is to pull the parameters off the evaluation stack and put them in local frame storage. Function callers and callees must agree on the number of parameters to avoid stack underflow/overflow. All functions return a value on the evaluation stack regardless of it being used or not. Lastly, PLASMA is not a typed language. Just like assembly, any value can represent a character, integer, or address. It's the programmer's job to know the type. Only bytes and words are known to PLASMA. Bytes are unsigned 8 bit quantities, words are signed 16 bit quantities. All stack operations involve 16 bits of precision. - The PLASMA low level operations are defined as: - +OP | Description +----------------------------------------- +ZERO | push zero on the stack +DROP | drop top stack value +DUP | duplicate top stack value +OVER | duplicate next from top stack value +SWAP | swap two topmost stack values +ADD | add top two values, leave result on top +SUB | subtract next from top from top, leave result on top +MUL | multiply two topmost stack values, leave result on top +DIV | divide next from top by top, leave result on top +MOD | divide next from top by top, leave remainder on top +INCR | increment top of stack +DECR | decrement top of stack +NEG | negate top of stack +COMP | compliment top of stack +BAND | bit wise AND top two values, leave result on top +IOR | bit wise inclusive OR top two values, leave result on top +XOR | bit wise exclusive OR top two values, leave result on top +NOT | logical NOT of top of stack +LOR | logical OR top two values, leave result on top +LAND | logical AND top two values, leave result on top +SHL | shift left next from top by top, leave result on top +SHR | shift right next from top by top, leave result on top +IDXB | add top of stack to next from top, leave result on top +IDXW | add 2X top of stack to next from top, leave result on top +LAA | load absolute address +LLA | load local address from frame offset +CB | constant byte +CW | constant word +LB | load byte from top of stack address +LW | load word from top of stack address +LLB | load byte from frame offset +LLW | load word from frame offset +LAB | load byte from absolute address +LAW | load word from absolute address +SB | store top of stack byte into next from top address +SW | store top of stack word into next from top address +SLB | store top of stack into local byte at frame offset +SLW | store top of stack into local word at frame offset +SAB | store top of stack into byte at absolute address +SAW | store top of stack into word at absolute address +DLB | duplicate top of stack into local byte at frame offset +DLW | duplicate top of stack into local word at frame offset +DAB | duplicate top of stack into byte at absolute address +DAW | duplicate top of stack into word at absolute address +BRGT | branch next from top greater than top +BRLT | branch next from top less than top +BREQ | branch next from top equal to top +BRNE | branch next from top not equal to top +ISEQ | if next from top is equal to top, set top true +ISNE | if next from top is not equal to top, set top true +ISGT | if next from top is greater than top, set top true +ISLT | if next from top is less than top, set top true +ISGE | if next from top is greater than or equal to top, set top true +ISLE | if next from top is less than or equal to top, set top true +BRFLS | branch if top of stack is zero +BRTRU | branch if top of stack is non-zero +BRNCH | branch to address +CALL | sub routine call with stack parameters +ICAL | sub routine call to indirect address on stack top with stack parameters +ENTER | allocate frame size and copy stack parameters to local frame +LEAVE | deallocate frame and return from sub routine call +RET | return from sub routine call +PUSH | push top to call stack +PULL | pull from call stack + + +##PLASMA Compiler/Assembler -OP Description - -ZERO push zero on the stack - -DROP drop top stack value - -DUP duplicate top stack value - -OVER duplicate next from top stack value - -SWAP swap two topmost stack values - -ADD add top two values, leave result on top - -SUB subtract next from top from top, leave result on top - -MUL multiply two topmost stack values, leave result on top - -DIV divide next from top by top, leave result on top - -MOD divide next from top by top, leave remainder on top - -INCR increment top of stack - -DECR decrement top of stack - -NEG negate top of stack - -COMP compliment top of stack - -BAND bit wise AND top two values, leave result on top - -IOR bit wise inclusive OR top two values, leave result on top - -XOR bit wise exclusive OR top two values, leave result on top - -NOT logical NOT of top of stack - -LOR logical OR top two values, leave result on top - -LAND logical AND top two values, leave result on top - -SHL shift left next from top by top, leave result on top - -SHR shift right next from top by top, leave result on top - -IDXB add top of stack to next from top, leave result on top - -IDXW add 2X top of stack to next from top, leave result on top - -LAA load absolute address - -LLA load local address from frame offset - -CB constant byte - -CW constant word - -LB load byte from top of stack address - -LW load word from top of stack address - -LLB load byte from frame offset - -LLW load word from frame offset - -LAB load byte from absolute address - -LAW load word from absolute address - -SB store top of stack byte into next from top address - -SW store top of stack word into next from top address - -SLB store top of stack into local byte at frame offset - -SLW store top of stack into local word at frame offset - -SAB store top of stack into byte at absolute address - -SAW store top of stack into word at absolute address - -DLB duplicate top of stack into local byte at frame offset - -DLW duplicate top of stack into local word at frame offset - -DAB duplicate top of stack into byte at absolute address - -DAW duplicate top of stack into word at absolute address - -BRGT branch next from top greater than top - -BRLT branch next from top less than top - -BREQ branch next from top equal to top - -BRNE branch next from top not equal to top - -ISEQ if next from top is equal to top, set top true - -ISNE if next from top is not equal to top, set top true - -ISGT if next from top is greater than top, set top true - -ISLT if next from top is less than top, set top true - -ISGE if next from top is greater than or equal to top, set top true - -ISLE if next from top is less than or equal to top, set top true - -BRFLS branch if top of stack is zero - -BRTRU branch if top of stack is non-zero - -BRNCH branch to address - -CALL sub routine call with stack parameters - -ICAL sub routine call to indirect address on stack top with stack parameters - -ENTER allocate frame size and copy stack parameters to local frame - -LEAVE deallocate frame and return from sub routine call - -RET return from sub routine call - -PUSH push top to call stack - -PULL pull from call stack - - - -PLASMA Compiler/Assembler -========================= Although the low-level operations could easily by coded by hand, they were chosen to be an easy target for a simple compiler. Think along the lines of an advanced assembler or stripped down C compiler ( C--). Taking concepts from BASIC, Pascal, C and assembler, the PLASMA compiler is simple yet expressive. - Comments are allowed throughout the source, starting with the ‘;’ character. The rest of the line is ignored. - -; Data and text buffer constants - +``` + ; Data and text buffer constants +``` Hexadecimal constants are preceded with a ‘$’ to identify them as such. - -$C030 ; Speaker address - +``` + $C030 ; Speaker address +``` + +#Constants, Variables and Functions -Constants, Variables and Functions ----------------------------------- The source code of a PLASMA module first defines constants, variables and data. Constants must be initialized with a value. Variables can have sizes associated with them to declare storage space. Data can be declared with or without a variable name associated with it. Arrays, tables, strings and any predeclared data can be created and accessed in multiple ways. - -; -; Constants used for hardware and flags -; -const speaker = $C030 -const changed = 1 -const insmode = 2 -; -; Array declaration of screen row addresses -; -word txtscrn[] = [$0400,$0480,$0500,$0580,$0600,$0680,$0700,$0780] -word = [$0428,$04A8,$0528,$05A8,$0628,$06A8,$0728,$07A8] -word = [$0450,$04D0,$0550,$05D0,$0650,$06D0,$0750,$07D0] -; -; Misc global variables -; -byte flags = 0 -word numlines = 0 -byte cursx, cursy -word cursrow, scrntop, cursptr - +``` + ; + ; Constants used for hardware and flags + ; + const speaker = $C030 + const changed = 1 + const insmode = 2 + ; + ; Array declaration of screen row addresses + ; + word txtscrn[] = [$0400,$0480,$0500,$0580,$0600,$0680,$0700,$0780] + word = [$0428,$04A8,$0528,$05A8,$0628,$06A8,$0728,$07A8] + word = [$0450,$04D0,$0550,$05D0,$0650,$06D0,$0750,$07D0] + ; + ; Misc global variables + ; + byte flags = 0 + word numlines = 0 + byte cursx, cursy + word cursrow, scrntop, cursptr +``` Variables can have optional brackets; empty brackets don’t reserve any space for the variable but are useful as a label for data that is defined following the variable. Brackets with a constant inside defines a minimum size reserved for the variable. Any data following the variable will take at least the amount of reserved space, but potentially more. Strings are defined like Pascal strings, a length byte followed by the string characters so they can be a maximum of 255 characters long. Strings can only appear in the variable definitions of a module. String constants can’t be used in expressions or statements. - -; -; An initialized string of 64 characters -; -byte txtfile[64] = "UNTITLED" - +``` + ; + ; An initialized string of 64 characters + ; + byte txtfile[64] = "UNTITLED" +``` Functions are defined after all constants, variables and data. Functions can be forward declared with a func type in the constant and variable declarations. Functions have optional parameters and always return a value. By using one of three function declarations (def, deft and defn) you can have the function loaded as interpreted bytecode, threaded calls into the interpreter, or natively compiled code. There are space and time tradeoffs between the three choices. Bytecode is the best choice for the majority of functions. It has decent performance and is extremely compact. Threaded code would be the choice for functions that are called often but are not leaf routines, i.e. they themselves call other functions. Native code is a good choice for small, leaf functions that are called often and need the highest performance. Simply altering the definition is all that is required to set the function code implementation. Functions can have their own variable declarations. However, unlike the global declarations, no data can be predeclared, only storage space. There is also a limit of 256 bytes of local storage. Each parameter takes two bytes of local storage, plus two bytes for the previous frame pointer. If a function has no parameters or local variables, no local frame will be created, improving performance. A function can specify a value to return. If no return value is specified, a default of 0 will be returned. - After functions are defined, the main code for the module follows. There is no option to declare how the main code is loaded - it is always bytecode. The last statement in the module must be done, or else a compile error is issued. - There are four basic types of data that can be manipulated: constants, variables, addresses, and functions. Memory can only be read or written as either a byte or a word. Bytes are unsigned 8 bit quantities, words are signed 16 bit quantities. Everything on the evaluation stack is treated as a word. Other than that, any value can be treated as a pointer, address, function, character, integer, etc. There are convenience operations in PLASMA to easily manipulate addresses and expressions as pointers, arrays, structures, functions, or combinations thereof. If a variable is declared as a byte, it can be accessed as a simple, single dimension byte array by using brackets to indicate the offset. Any expression can calculate the indexed offset. A word variable can be accessed as a word array in the same fashion. In order to access expressions or constants as arrays, a type identifier has to be inserted before the brackets. a ‘.’ character denotes a byte type, a ‘:’ character denotes a word type. Along with brackets to calculate an indexed offset, a constant can be used after the ‘.’ or ‘:’ and will be added to the base address. The constant can be a defined const to allow for structure style syntax. If the offset is a known constant, using the constant offset is a much more efficient way to address the elements over an array index. Multidimensional arrays are treated as arrays of array pointers. Multiple brackets can follow the ‘.’ or ‘:’ type identifier, but all but the last index will be treated as a pointer to an array. - -word hgrscan[] = [$2000,$2400,$2800,$2C00,$3000,$3400,$3800,$3C00] -word = [$2080,$2480,$2880,$2C80,$3080,$3480,$3880,$3C80] +``` + word hgrscan[] = [$2000,$2400,$2800,$2C00,$3000,$3400,$3800,$3C00] + word = [$2080,$2480,$2880,$2C80,$3080,$3480,$3880,$3C80] -hgrscan:[yscan][xscan] = fillval - + hgrscan:[yscan][xscan] = fillval +``` Values can be treated as pointers by preceding them with a ‘^’ for byte pointers, ‘*’ for word pointers. - -strlen = ^(srcstr) - -def redraw - cursoff - drawscrn(scrntop, scrnleft) - curson -end +``` + def redraw + cursoff + drawscrn(scrntop, scrnleft) + curson + end -redraw - + redraw +``` Functions with parameters or expressions to be used as a function address to call must use parenthesis, even if empty. - -word keyin -byte key +``` + word keyin + byte key -keyin = @keyin2plus ; address-of keyin2plus function -key = (keyin)() - + keyin = @keyin2plus ; address-of keyin2plus function + key = (keyin)() +``` Expressions and Statements Expressions are algebraic. Data is free-form, but all operations on the evaluation stack use 16 bits of precision with the exception of byte load and stores. A stand-alone expression will be evaluated and read from or called. This allows for easy access to the Apple’s soft switches and other memory mapped hardware. The value of the expression is dropped. - -const speaker=$C030 +``` + const speaker=$C030 -^speaker ; click speaker -close(refnum) - + ^speaker ; click speaker + close(refnum) +``` More complex expressions can be built up using algebraic unary and binary operations. - - -OP Unary Operation - -^ byte pointer -* word pointer -@ address of -- negate -# bitwise compliment -! logical NOT +OP | Unary Operation +-------------------------- +^ | byte pointer +* | word pointer +@ | address of +- | negate +# | bitwise compliment +! | logical NOT -OP Binary Operation - -* multiply -/ divide -% modulo -+ add -- subtract -<< shift left ->> shift right -& bitwise AND -| bitwise OR -^ bitwise XOR -== equals -<> not equal ->= greater than or equal -> greater than -<= less than or equal -< less than -OR logical OR -AND logical AND - +OP | Binary Operation +--------------------------- +* | multiply +/ | divide +% | modulo ++ | add +- | subtract +<< | shift left +>> | shift right +& | bitwise AND +| | bitwise OR +^ | bitwise XOR +== | equals +<> | not equal +>= | greater than or equal +> | greater than +<= | less than or equal +< | less than +OR | logical OR +AND | logical AND Statements are built up from expressions and control flow keywords. Simplicity of syntax took precedence over flexibility and complexity. The simplest statement is the basic assignment using ‘=’. @@ -431,7 +351,7 @@ memset(@nullstr, strlinbuf, maxfill * 2) ; fill line buff with pointer to null s memcpy(strptr + ofst + 1, scrnptr, numchars) -Implementation Details +#Implementation Details The original design concept was to create an efficient, flexible, and expressive environment for building applications directly on the Apple II. Choosing a stack based architecture was easy after much experience with other stack based implementations. It also makes the compiler simple to implement. The first take on the stack architecture was to make it a very strict stack architecture in that everything had to be on the stack. The only opcode with operands was the CONSTANT opcode. This allowed for a very small bytecode interpreter and a very easy compile target. However, only when adding an opcode with operands that would greatly improved performance, native code generation or code size was it done. The opcode table grew slowly over time but still retains a small runtime interpreter with good native code density. From 1c96bcf3c891d885f540d953a96f0b70ceaa2368 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 19:51:48 -0700 Subject: [PATCH 11/44] Update README.md --- PLASMA/README.md | 363 +++++++++++++++++++++++------------------------ 1 file changed, 181 insertions(+), 182 deletions(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index 5f8e326e..cfe209a7 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -15,72 +15,72 @@ PLASMA takes an approach that uses the best of all the above implementations to The PLASMA low level operations are defined as: -OP | Description +|OP | Description ----------------------------------------- -ZERO | push zero on the stack -DROP | drop top stack value -DUP | duplicate top stack value -OVER | duplicate next from top stack value -SWAP | swap two topmost stack values -ADD | add top two values, leave result on top -SUB | subtract next from top from top, leave result on top -MUL | multiply two topmost stack values, leave result on top -DIV | divide next from top by top, leave result on top -MOD | divide next from top by top, leave remainder on top -INCR | increment top of stack -DECR | decrement top of stack -NEG | negate top of stack -COMP | compliment top of stack -BAND | bit wise AND top two values, leave result on top -IOR | bit wise inclusive OR top two values, leave result on top -XOR | bit wise exclusive OR top two values, leave result on top -NOT | logical NOT of top of stack -LOR | logical OR top two values, leave result on top -LAND | logical AND top two values, leave result on top -SHL | shift left next from top by top, leave result on top -SHR | shift right next from top by top, leave result on top -IDXB | add top of stack to next from top, leave result on top -IDXW | add 2X top of stack to next from top, leave result on top -LAA | load absolute address -LLA | load local address from frame offset -CB | constant byte -CW | constant word -LB | load byte from top of stack address -LW | load word from top of stack address -LLB | load byte from frame offset -LLW | load word from frame offset -LAB | load byte from absolute address -LAW | load word from absolute address -SB | store top of stack byte into next from top address -SW | store top of stack word into next from top address -SLB | store top of stack into local byte at frame offset -SLW | store top of stack into local word at frame offset -SAB | store top of stack into byte at absolute address -SAW | store top of stack into word at absolute address -DLB | duplicate top of stack into local byte at frame offset -DLW | duplicate top of stack into local word at frame offset -DAB | duplicate top of stack into byte at absolute address -DAW | duplicate top of stack into word at absolute address -BRGT | branch next from top greater than top -BRLT | branch next from top less than top -BREQ | branch next from top equal to top -BRNE | branch next from top not equal to top -ISEQ | if next from top is equal to top, set top true -ISNE | if next from top is not equal to top, set top true -ISGT | if next from top is greater than top, set top true -ISLT | if next from top is less than top, set top true -ISGE | if next from top is greater than or equal to top, set top true -ISLE | if next from top is less than or equal to top, set top true -BRFLS | branch if top of stack is zero -BRTRU | branch if top of stack is non-zero -BRNCH | branch to address -CALL | sub routine call with stack parameters -ICAL | sub routine call to indirect address on stack top with stack parameters -ENTER | allocate frame size and copy stack parameters to local frame -LEAVE | deallocate frame and return from sub routine call -RET | return from sub routine call -PUSH | push top to call stack -PULL | pull from call stack +|ZERO | push zero on the stack +|DROP | drop top stack value +|DUP | duplicate top stack value +|OVER | duplicate next from top stack value +|SWAP | swap two topmost stack values +|ADD | add top two values, leave result on top +|SUB | subtract next from top from top, leave result on top +|MUL | multiply two topmost stack values, leave result on top +|DIV | divide next from top by top, leave result on top +|MOD | divide next from top by top, leave remainder on top +|INCR | increment top of stack +|DECR | decrement top of stack +|NEG | negate top of stack +|COMP | compliment top of stack +|BAND | bit wise AND top two values, leave result on top +|IOR | bit wise inclusive OR top two values, leave result on top +|XOR | bit wise exclusive OR top two values, leave result on top +|NOT | logical NOT of top of stack +|LOR | logical OR top two values, leave result on top +|LAND | logical AND top two values, leave result on top +|SHL | shift left next from top by top, leave result on top +|SHR | shift right next from top by top, leave result on top +|IDXB | add top of stack to next from top, leave result on top +|IDXW | add 2X top of stack to next from top, leave result on top +|LAA | load absolute address +|LLA | load local address from frame offset +|CB | constant byte +|CW | constant word +|LB | load byte from top of stack address +|LW | load word from top of stack address +|LLB | load byte from frame offset +|LLW | load word from frame offset +|LAB | load byte from absolute address +|LAW | load word from absolute address +|SB | store top of stack byte into next from top address +|SW | store top of stack word into next from top address +|SLB | store top of stack into local byte at frame offset +|SLW | store top of stack into local word at frame offset +|SAB | store top of stack into byte at absolute address +|SAW | store top of stack into word at absolute address +|DLB | duplicate top of stack into local byte at frame offset +|DLW | duplicate top of stack into local word at frame offset +|DAB | duplicate top of stack into byte at absolute address +|DAW | duplicate top of stack into word at absolute address +|BRGT | branch next from top greater than top +|BRLT | branch next from top less than top +|BREQ | branch next from top equal to top +|BRNE | branch next from top not equal to top +|ISEQ | if next from top is equal to top, set top true +|ISNE | if next from top is not equal to top, set top true +|ISGT | if next from top is greater than top, set top true +|ISLT | if next from top is less than top, set top true +|ISGE | if next from top is greater than or equal to top, set top true +|ISLE | if next from top is less than or equal to top, set top true +|BRFLS | branch if top of stack is zero +|BRTRU | branch if top of stack is non-zero +|BRNCH | branch to address +|CALL | sub routine call with stack parameters +|ICAL | sub routine call to indirect address on stack top with stack parameters +|ENTER | allocate frame size and copy stack parameters to local frame +|LEAVE | deallocate frame and return from sub routine call +|RET | return from sub routine call +|PUSH | push top to call stack +|PULL | pull from call stack ##PLASMA Compiler/Assembler @@ -192,164 +192,163 @@ Expressions are algebraic. Data is free-form, but all operations on the evaluat More complex expressions can be built up using algebraic unary and binary operations. -OP | Unary Operation --------------------------- -^ | byte pointer -* | word pointer -@ | address of -- | negate -# | bitwise compliment -! | logical NOT +|OP | Unary Operation +|-------------------------- +|^ | byte pointer +|* | word pointer +|@ | address of +|- | negate +|# | bitwise compliment +|! | logical NOT -OP | Binary Operation ---------------------------- -* | multiply -/ | divide -% | modulo -+ | add -- | subtract -<< | shift left ->> | shift right -& | bitwise AND -| | bitwise OR -^ | bitwise XOR -== | equals -<> | not equal ->= | greater than or equal -> | greater than -<= | less than or equal -< | less than -OR | logical OR -AND | logical AND +|OP | Binary Operation +|--------------------------- +|* | multiply +|/ | divide +|% | modulo +|+ | add +|- | subtract +|<< | shift left +|>> | shift right +|& | bitwise AND +|| | bitwise OR +|^ | bitwise XOR +|== | equals +|<> | not equal +|>= | greater than or equal +|> | greater than +|<= | less than or equal +|< | less than +|OR | logical OR +|AND | logical AND Statements are built up from expressions and control flow keywords. Simplicity of syntax took precedence over flexibility and complexity. The simplest statement is the basic assignment using ‘=’. - -byte numchars -numchars = 0 - +``` + byte numchars + numchars = 0 +``` Expressions can be built up with constants, variables, function calls, addresses, and pointers/arrays. Comparison operators evaluate to 0 or -1 instead of the more traditional 0 or 1. The use of -1 allows binary operations to be applied to other non-zero values and still retain a non-zero result. Any conditional tests check only for zero and non-zero values. - Control structures affect the flow of control through the program. There are conditional and looping constructs. The most widely used is probably the if/elsif/else/fin construct. - -if ^pushbttn3 < 128 - if key == $C0 - key = $D0 ; P - elsif key == $DD - key = $CD ; M - elsif key == $DE - key = $CE ; N +``` + if ^pushbttn3 < 128 + if key == $C0 + key = $D0 ; P + elsif key == $DD + key = $CD ; M + elsif key == $DE + key = $CE ; N + fin + else + key = key ? $E0 fin -else - key = key ? $E0 -fin - +``` The when/is/otherwise/merge statement is similar to the if/elsif/else/fin construct except that it is more efficient. It selects one path based on the evaluated expressions, then merges the code path back together at the end. However only the 'when' value is compared against a list of expressions. The expressions do not need to be constants, they can be any valid expression. The list of expressions is evaluated in order, so for efficiency sake, place the most common cases earlier in the list. - -when keypressed - is keyarrowup - cursup - is keyarrowdown - cursdown - is keyarrowleft - cursleft - is keyarrowright - cursright - is keyctrlx - cutline - is keyctrlv - pasteline - is keyescape - cursoff - cmdmode - redraw - otherwise - bell -wend - +``` + when keypressed + is keyarrowup + cursup + is keyarrowdown + cursdown + is keyarrowleft + cursleft + is keyarrowright + cursright + is keyctrlx + cutline + is keyctrlv + pasteline + is keyescape + cursoff + cmdmode + redraw + otherwise + bell + wend +``` The most common looping statement is the for/next construct. - -for xscan = 0 to 19 - (scanptr):[xscan] = val -next - +``` + for xscan = 0 to 19 + (scanptr):[xscan] = val + next +``` The for/next statement will efficiently increment or decrement a variable form the starting value to the ending value. The increment/decrement amount can be set with the step option after the ending value; the default is one. If the ending value is less than the starting value, use downto instead of to to progress in the negative direction. Only use positive step values. The to or downto will add or subtract the step value appropriately. - -for i = heapmapsz - 1 downto 0 - if sheapmap.[i] <> $FF - mapmask = szmask - fin -next - +``` + for i = heapmapsz - 1 downto 0 + if sheapmap.[i] <> $FF + mapmask = szmask + fin + next +``` while/loop statements will continue looping as long as the while expression is non-zero. - -while !(mask & 1) - addr = addr + 16 - mask = mask >> 1 -loop - +``` + while !(mask & 1) + addr = addr + 16 + mask = mask >> 1 + loop +``` Lastly, the repeat/until statement will continue looping as long as the until expression is zero. - -repeat - txtbuf = read(refnum, @txtbuf + 1, maxlnlen) - numlines = numlines + 1 -until txtbuf == 0 or numlines == maxlines - +``` + repeat + txtbuf = read(refnum, @txtbuf + 1, maxlnlen) + numlines = numlines + 1 + until txtbuf == 0 or numlines == maxlines +``` -Runtime +#Runtime PLASMA includes a very minimal runtime that nevertheless provides a great deal of functionality to the system. Two system calls are provided to access native 6502 routines (usually in ROM) and ProDOS. call6502(aReg, xReg, yReg, statusReg, addr) returns a pointer to a four byte structure containing the A,X,Y and STATUS register results. - -const xreg = 1 -const getlin = $FD6A +``` + const xreg = 1 + const getlin = $FD6A -numchars = (call6502(0, 0, 0, 0, getlin)).xreg ; return char count in X reg -prodos(cmd, params)calls ProDOS, returning the status value. + numchars = (call6502(0, 0, 0, 0, getlin)).xreg ; return char count in X reg + prodos(cmd, params)calls ProDOS, returning the status value. -def read(refnum, buff, len) - byte params[8] + def read(refnum, buff, len) + byte params[8] - params.0 = 4 - params.1 = refnum - params:2 = buff - params:4 = len - perr = prodos($CA, @params) - return params:6 -end - + params.0 = 4 + params.1 = refnum + params:2 = buff + params:4 = len + perr = prodos($CA, @params) + return params:6 + end +``` cout(char), prstr(string), prstrz(stringz) are handy utility routines for printing to the standard Apple II COUT routine. - -cout('.') -byte okstr[] = "OK" -prstr(@okstr) - +``` + cout('.') + byte okstr[] = "OK" + prstr(@okstr) +``` memset(val16, addr, len) will fill memory with a 16 bit value. memcpy(srcaddr, dstaddr, len) will copy memory from one address to another, taking care to copy in the proper direction. - -byte nullstr[] = "" -memset(@nullstr, strlinbuf, maxfill * 2) ; fill line buff with pointer to null string -memcpy(strptr + ofst + 1, scrnptr, numchars) - +``` + byte nullstr[] = "" + memset(@nullstr, strlinbuf, maxfill * 2) ; fill line buff with pointer to null string + memcpy(strptr + ofst + 1, scrnptr, numchars) +``` #Implementation Details From 9196c0e71a2f8c865bd6c29aefbefaf19e78d61c Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 19:56:10 -0700 Subject: [PATCH 12/44] Update README.md --- PLASMA/README.md | 64 ++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index cfe209a7..5fd3268e 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -1,15 +1,15 @@ -###PLASMA +#PLASMA ##Introduction PLASMA is a combination of virtual machine and assembler/compiler matched closely to the 6502 architecture. It is an attempt to satisfy a few challenges surrounding code size, efficient execution, small runtime and fast just-in-time compilation. By architecting a unique bytecode that maps nearly one-to-one to the higher level representation, the compiler/assembler can be very simple and execute quickly on the Apple II for a self-hosted environment. A modular approach provides for incremental development and code reuse. Different projects have led to the architecture of PLASMA, most notably Apple Pascal, FORTH, and my own Java VM for the 6502, VM02. Each has tried to map a generic VM to the 6502 with varying levels of success. Apple Pascal, based on the USCD Pascal using the p-code interpreter, was a very powerful system and ran fast enough on the Apple II to be interactive but didn't win any speed contests. FORTH was the poster child for efficiency and obtuse syntax. Commonly referred to as a write only language, it was difficult to come up to speed as a developer, especially when using other's code. My own project in creating a Java VM for the Apple II uncovered the folly of shoehorning a large system into something never intended to run 32 bit applications. -#Low Level Implementation +##Low Level Implementation Both the Pascal and Java VMs used a bytecode to hide the underlying CPU architecture and offer platform agnostic application execution. The application and tool chains were easily moved from platform to platform by simply writing a bytecode interpreter and small runtime to translate the higher level constructs to the underlying hardware. The performance of the system was dependent on the actual hardware and efficiency of the interpreter. Just-in-time compilation wasn't really an option on small, 8 bit systems. FORTH, on the other hand, was usually implemented as a threaded interpreter. A threaded interpreter will use the address of functions to call as the code stream instead of a bytecode, eliminating one level of indirection with a slight increase in code size. The threaded approach can be made faster at the expense of another slight increase in size by inserting an actual Jump SubRoutine opcode before each address, thus removing the interpreter's inner loop altogether. All three systems were implemented using stack architecture. Pascal and Java were meant to be compiled high level languages, using a stack machine as a simple compilation target. FORTH was meant to be written directly as a stack oriented language, similar to RPN on HP calculators. The 6502 is a challenging target due to it's unusual architecture so writing a bytecode interpreter for Pascal and Java results in some inefficiencies and limitations. FORTH's inner interpreter loop on the 6502 tends to be less efficient than most other CPUs. Another difference is how each system creates and manipulates it's stack. Pascal and Java use the 6502 hardware stack for all stack operations. Unfortunately the 6502 stack is hard-limited to 256 bytes. However, in normal usage this isn't too much of a problem as the compilers don't put undue pressure on the stack size by keeping most values in global or local variables. FORTH creates a small stack using a portion of the 6502's zero page, a 256 byte area of low memory that can be accessed with only a byte address and indexed using either of the X or Y registers. With zero page, the X register can be used as an indexed, indirect address and the Y register can be used as an indirect, indexed address. -#A New Approach +##A New Approach PLASMA takes an approach that uses the best of all the above implementations to create a unique, powerful and efficient platform for developing new applications on the Apple II. One goal was to create a very small VM runtime, bytecode interpreter, and module loader that could adjust the code size vs. performance optimizations to allow for interpreted code, threaded code, or efficiently compiled native code. The decision was made early on to implement a stack based architecture duplicating the approach taken by FORTH. Space in the zero page would be assigned to a 16 bit, 32 element evaluation stack, indexed by the X register. The stack is purposely not split between low and high values so as to allow reading and writing addresses stored directly on the stack. The trade off is that the stack pointer has to be incremented and decremented by two for every push/pop operation. A simple compiler was written so that higher level constructs could be used and global/local variables would hold values instead of using clever stack manipulation. Function/procedure frames would allow for local variables, but with a limitation - the frame could be no larger than 256 bytes. By enforcing this limitation, the function frame could easily be accessed through a frame pointer value in zero page, indexed by the Y register. The call stack uses the 6502's hardware stack resulting in the same 256 byte limitation imposed by the hardware. However, this limitation could be lifted by extending the call sequence to save and restore the return address in the function frame. This was not done initially for performance reasons and simplicity of implementation. One of the goals of PLASMA was to allow for intermixing of functions implemented as bytecode, threaded code, or native code. Taking a page from the FORTH play book, a function call is implemented as a native subroutine call to an address. If the function is in bytecode, the first thing it does is call back into the interpreter to execute the following bytecode. Functions can be selectively expanded as bytecode, threaded code, or natively compiled, all at load time. Threaded code expands to about 3X the size of bytecode with about 3X the performance. Native code is about 5X-10X the size with a significant improvement in performance. The native code compiler uses a strategy of caching the Top-Of-Stack value in the Y and A registers of the 6502. The compiler also tracks the TOS pointer and adjusts the address accordingly to avoid actual manipulation of the X register. The X register in effect becomes the frame pointer for the evaluation stack. Function call parameters are pushed onto the evaluation stack in order they are written. The first operation inside of the function call is to pull the parameters off the evaluation stack and put them in local frame storage. Function callers and callees must agree on the number of parameters to avoid stack underflow/overflow. All functions return a value on the evaluation stack regardless of it being used or not. Lastly, PLASMA is not a typed language. Just like assembly, any value can represent a character, integer, or address. It's the programmer's job to know the type. Only bytes and words are known to PLASMA. Bytes are unsigned 8 bit quantities, words are signed 16 bit quantities. All stack operations involve 16 bits of precision. @@ -99,7 +99,7 @@ Hexadecimal constants are preceded with a ‘$’ to identify them as such. $C030 ; Speaker address ``` -#Constants, Variables and Functions +###Constants, Variables and Functions The source code of a PLASMA module first defines constants, variables and data. Constants must be initialized with a value. Variables can have sizes associated with them to declare storage space. Data can be declared with or without a variable name associated with it. Arrays, tables, strings and any predeclared data can be created and accessed in multiple ways. @@ -192,36 +192,36 @@ Expressions are algebraic. Data is free-form, but all operations on the evaluat More complex expressions can be built up using algebraic unary and binary operations. -|OP | Unary Operation +| OP | Unary Operation |-------------------------- -|^ | byte pointer -|* | word pointer -|@ | address of -|- | negate -|# | bitwise compliment -|! | logical NOT +| ^ | byte pointer +| * | word pointer +| @ | address of +| - | negate +| # | bitwise compliment +| ! | logical NOT -|OP | Binary Operation +| OP | Binary Operation |--------------------------- -|* | multiply -|/ | divide -|% | modulo -|+ | add -|- | subtract -|<< | shift left -|>> | shift right -|& | bitwise AND -|| | bitwise OR -|^ | bitwise XOR -|== | equals -|<> | not equal -|>= | greater than or equal -|> | greater than -|<= | less than or equal -|< | less than -|OR | logical OR -|AND | logical AND +| * | multiply +| / | divide +| % | modulo +| + | add +| - | subtract +| << | shift left +| >> | shift right +| & | bitwise AND +| | | bitwise OR +| ^ | bitwise XOR +| == | equals +| <> | not equal +| >= | greater than or equal +| > | greater than +| <= | less than or equal +| < | less than +| OR | logical OR +| AND | logical AND Statements are built up from expressions and control flow keywords. Simplicity of syntax took precedence over flexibility and complexity. The simplest statement is the basic assignment using ‘=’. @@ -309,7 +309,7 @@ Lastly, the repeat/until statement will continue looping as long as the until ex until txtbuf == 0 or numlines == maxlines ``` -#Runtime +###Runtime PLASMA includes a very minimal runtime that nevertheless provides a great deal of functionality to the system. Two system calls are provided to access native 6502 routines (usually in ROM) and ProDOS. @@ -350,7 +350,7 @@ memset(val16, addr, len) will fill memory with a 16 bit value. memcpy(srcaddr, memcpy(strptr + ofst + 1, scrnptr, numchars) ``` -#Implementation Details +###Implementation Details The original design concept was to create an efficient, flexible, and expressive environment for building applications directly on the Apple II. Choosing a stack based architecture was easy after much experience with other stack based implementations. It also makes the compiler simple to implement. The first take on the stack architecture was to make it a very strict stack architecture in that everything had to be on the stack. The only opcode with operands was the CONSTANT opcode. This allowed for a very small bytecode interpreter and a very easy compile target. However, only when adding an opcode with operands that would greatly improved performance, native code generation or code size was it done. The opcode table grew slowly over time but still retains a small runtime interpreter with good native code density. From 7685ed02b41982d1e50769cb0363be7d9838c204 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 19:58:13 -0700 Subject: [PATCH 13/44] Update README.md --- PLASMA/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index 5fd3268e..e90b09a6 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -16,7 +16,7 @@ PLASMA takes an approach that uses the best of all the above implementations to The PLASMA low level operations are defined as: |OP | Description ------------------------------------------ +|------|----------------------------------- |ZERO | push zero on the stack |DROP | drop top stack value |DUP | duplicate top stack value @@ -193,7 +193,7 @@ Expressions are algebraic. Data is free-form, but all operations on the evaluat More complex expressions can be built up using algebraic unary and binary operations. | OP | Unary Operation -|-------------------------- +|------|-------------------- | ^ | byte pointer | * | word pointer | @ | address of @@ -203,7 +203,7 @@ More complex expressions can be built up using algebraic unary and binary operat | OP | Binary Operation -|--------------------------- +|------|--------------------- | * | multiply | / | divide | % | modulo From 0f2844bb20a2f049a87324aabf4f55e637a4d7d7 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 20:00:57 -0700 Subject: [PATCH 14/44] Update README.md --- PLASMA/README.md | 132 +++++++++++++++++++++++------------------------ 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index e90b09a6..ad85d25f 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -15,72 +15,72 @@ PLASMA takes an approach that uses the best of all the above implementations to The PLASMA low level operations are defined as: -|OP | Description -|------|----------------------------------- -|ZERO | push zero on the stack -|DROP | drop top stack value -|DUP | duplicate top stack value -|OVER | duplicate next from top stack value -|SWAP | swap two topmost stack values -|ADD | add top two values, leave result on top -|SUB | subtract next from top from top, leave result on top -|MUL | multiply two topmost stack values, leave result on top -|DIV | divide next from top by top, leave result on top -|MOD | divide next from top by top, leave remainder on top -|INCR | increment top of stack -|DECR | decrement top of stack -|NEG | negate top of stack -|COMP | compliment top of stack -|BAND | bit wise AND top two values, leave result on top -|IOR | bit wise inclusive OR top two values, leave result on top -|XOR | bit wise exclusive OR top two values, leave result on top -|NOT | logical NOT of top of stack -|LOR | logical OR top two values, leave result on top -|LAND | logical AND top two values, leave result on top -|SHL | shift left next from top by top, leave result on top -|SHR | shift right next from top by top, leave result on top -|IDXB | add top of stack to next from top, leave result on top -|IDXW | add 2X top of stack to next from top, leave result on top -|LAA | load absolute address -|LLA | load local address from frame offset -|CB | constant byte -|CW | constant word -|LB | load byte from top of stack address -|LW | load word from top of stack address -|LLB | load byte from frame offset -|LLW | load word from frame offset -|LAB | load byte from absolute address -|LAW | load word from absolute address -|SB | store top of stack byte into next from top address -|SW | store top of stack word into next from top address -|SLB | store top of stack into local byte at frame offset -|SLW | store top of stack into local word at frame offset -|SAB | store top of stack into byte at absolute address -|SAW | store top of stack into word at absolute address -|DLB | duplicate top of stack into local byte at frame offset -|DLW | duplicate top of stack into local word at frame offset -|DAB | duplicate top of stack into byte at absolute address -|DAW | duplicate top of stack into word at absolute address -|BRGT | branch next from top greater than top -|BRLT | branch next from top less than top -|BREQ | branch next from top equal to top -|BRNE | branch next from top not equal to top -|ISEQ | if next from top is equal to top, set top true -|ISNE | if next from top is not equal to top, set top true -|ISGT | if next from top is greater than top, set top true -|ISLT | if next from top is less than top, set top true -|ISGE | if next from top is greater than or equal to top, set top true -|ISLE | if next from top is less than or equal to top, set top true -|BRFLS | branch if top of stack is zero -|BRTRU | branch if top of stack is non-zero -|BRNCH | branch to address -|CALL | sub routine call with stack parameters -|ICAL | sub routine call to indirect address on stack top with stack parameters -|ENTER | allocate frame size and copy stack parameters to local frame -|LEAVE | deallocate frame and return from sub routine call -|RET | return from sub routine call -|PUSH | push top to call stack -|PULL | pull from call stack +| OP | Description +|-------|----------------------------------- +| ZERO | push zero on the stack +| DROP | drop top stack value +| DUP | duplicate top stack value +| OVER | duplicate next from top stack value +| SWAP | swap two topmost stack values +| ADD | add top two values, leave result on top +| SUB | subtract next from top from top, leave result on top +| MUL | multiply two topmost stack values, leave result on top +| DIV | divide next from top by top, leave result on top +| MOD | divide next from top by top, leave remainder on top +| INCR | increment top of stack +| DECR | decrement top of stack +| NEG | negate top of stack +| COMP | compliment top of stack +| BAND | bit wise AND top two values, leave result on top +| IOR | bit wise inclusive OR top two values, leave result on top +| XOR | bit wise exclusive OR top two values, leave result on top +| NOT | logical NOT of top of stack +| LOR | logical OR top two values, leave result on top +| LAND | logical AND top two values, leave result on top +| SHL | shift left next from top by top, leave result on top +| SHR | shift right next from top by top, leave result on top +| IDXB | add top of stack to next from top, leave result on top +| IDXW | add 2X top of stack to next from top, leave result on top +| LAA | load absolute address +| LLA | load local address from frame offset +| CB | constant byte +| CW | constant word +| LB | load byte from top of stack address +| LW | load word from top of stack address +| LLB | load byte from frame offset +| LLW | load word from frame offset +| LAB | load byte from absolute address +| LAW | load word from absolute address +| SB | store top of stack byte into next from top address +| SW | store top of stack word into next from top address +| SLB | store top of stack into local byte at frame offset +| SLW | store top of stack into local word at frame offset +| SAB | store top of stack into byte at absolute address +| SAW | store top of stack into word at absolute address +| DLB | duplicate top of stack into local byte at frame offset +| DLW | duplicate top of stack into local word at frame offset +| DAB | duplicate top of stack into byte at absolute address +| DAW | duplicate top of stack into word at absolute address +| BRGT | branch next from top greater than top +| BRLT | branch next from top less than top +| BREQ | branch next from top equal to top +| BRNE | branch next from top not equal to top +| ISEQ | if next from top is equal to top, set top true +| ISNE | if next from top is not equal to top, set top true +| ISGT | if next from top is greater than top, set top true +| ISLT | if next from top is less than top, set top true +| ISGE | if next from top is greater than or equal to top, set top true +| ISLE | if next from top is less than or equal to top, set top true +| BRFLS | branch if top of stack is zero +| BRTRU | branch if top of stack is non-zero +| BRNCH | branch to address +| CALL | sub routine call with stack parameters +| ICAL | sub routine call to indirect address on stack top with stack parameters +| ENTER | allocate frame size and copy stack parameters to local frame +| LEAVE | deallocate frame and return from sub routine call +| RET | return from sub routine call +| PUSH | push top to call stack +| PULL | pull from call stack ##PLASMA Compiler/Assembler From ed0eafadf45e971c0802f966a60fbd9bba093b4b Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 20:15:05 -0700 Subject: [PATCH 15/44] Update README.md --- PLASMA/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index ad85d25f..fc8f7252 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -350,7 +350,7 @@ memset(val16, addr, len) will fill memory with a 16 bit value. memcpy(srcaddr, memcpy(strptr + ofst + 1, scrnptr, numchars) ``` -###Implementation Details +##Implementation Details The original design concept was to create an efficient, flexible, and expressive environment for building applications directly on the Apple II. Choosing a stack based architecture was easy after much experience with other stack based implementations. It also makes the compiler simple to implement. The first take on the stack architecture was to make it a very strict stack architecture in that everything had to be on the stack. The only opcode with operands was the CONSTANT opcode. This allowed for a very small bytecode interpreter and a very easy compile target. However, only when adding an opcode with operands that would greatly improved performance, native code generation or code size was it done. The opcode table grew slowly over time but still retains a small runtime interpreter with good native code density. From bb6b641fc26df150fb14617ec2375a39374e6b16 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 20:21:10 -0700 Subject: [PATCH 16/44] Update README.md --- PLASMA/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index fc8f7252..a900ec56 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -198,7 +198,7 @@ More complex expressions can be built up using algebraic unary and binary operat | * | word pointer | @ | address of | - | negate -| # | bitwise compliment +| ~ | bitwise compliment | ! | logical NOT @@ -244,7 +244,7 @@ Control structures affect the flow of control through the program. There are co key = $CE ; N fin else - key = key ? $E0 + key = key | $E0 fin ``` From c4c137af4e6034f8f1e81598f12deb1cfe2ab466 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 20:25:12 -0700 Subject: [PATCH 17/44] Update README.md --- PLASMA/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index a900ec56..bc16a3ac 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -342,12 +342,12 @@ cout(char), prstr(string), prstrz(stringz) are handy utility routines for printi prstr(@okstr) ``` -memset(val16, addr, len) will fill memory with a 16 bit value. memcpy(srcaddr, dstaddr, len) will copy memory from one address to another, taking care to copy in the proper direction. +memset(val16, addr, len) will fill memory with a 16 bit value. memcpy(dstaddr, srcaddr, len) will copy memory from one address to another, taking care to copy in the proper direction. ``` byte nullstr[] = "" memset(@nullstr, strlinbuf, maxfill * 2) ; fill line buff with pointer to null string - memcpy(strptr + ofst + 1, scrnptr, numchars) + memcpy(scrnptr, strptr + ofst + 1, numchars) ``` ##Implementation Details From 4389c236fd763f490be645d9c354c372143193a8 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 20:26:12 -0700 Subject: [PATCH 18/44] Update README.md --- PLASMA/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index bc16a3ac..e06c5fa4 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -113,9 +113,9 @@ The source code of a PLASMA module first defines constants, variables and data. ; ; Array declaration of screen row addresses ; - word txtscrn[] = [$0400,$0480,$0500,$0580,$0600,$0680,$0700,$0780] - word = [$0428,$04A8,$0528,$05A8,$0628,$06A8,$0728,$07A8] - word = [$0450,$04D0,$0550,$05D0,$0650,$06D0,$0750,$07D0] + word txtscrn[] = $0400,$0480,$0500,$0580,$0600,$0680,$0700,$0780 + word = $0428,$04A8,$0528,$05A8,$0628,$06A8,$0728,$07A8 + word = $0450,$04D0,$0550,$05D0,$0650,$06D0,$0750,$07D0 ; ; Misc global variables ; From d1d4005c8be362f871a31d4e3d33bc22ca40df79 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 20:27:29 -0700 Subject: [PATCH 19/44] Update README.md --- PLASMA/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index e06c5fa4..e87c368e 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -143,8 +143,8 @@ After functions are defined, the main code for the module follows. There is no There are four basic types of data that can be manipulated: constants, variables, addresses, and functions. Memory can only be read or written as either a byte or a word. Bytes are unsigned 8 bit quantities, words are signed 16 bit quantities. Everything on the evaluation stack is treated as a word. Other than that, any value can be treated as a pointer, address, function, character, integer, etc. There are convenience operations in PLASMA to easily manipulate addresses and expressions as pointers, arrays, structures, functions, or combinations thereof. If a variable is declared as a byte, it can be accessed as a simple, single dimension byte array by using brackets to indicate the offset. Any expression can calculate the indexed offset. A word variable can be accessed as a word array in the same fashion. In order to access expressions or constants as arrays, a type identifier has to be inserted before the brackets. a ‘.’ character denotes a byte type, a ‘:’ character denotes a word type. Along with brackets to calculate an indexed offset, a constant can be used after the ‘.’ or ‘:’ and will be added to the base address. The constant can be a defined const to allow for structure style syntax. If the offset is a known constant, using the constant offset is a much more efficient way to address the elements over an array index. Multidimensional arrays are treated as arrays of array pointers. Multiple brackets can follow the ‘.’ or ‘:’ type identifier, but all but the last index will be treated as a pointer to an array. ``` - word hgrscan[] = [$2000,$2400,$2800,$2C00,$3000,$3400,$3800,$3C00] - word = [$2080,$2480,$2880,$2C80,$3080,$3480,$3880,$3C80] + word hgrscan[] = $2000,$2400,$2800,$2C00,$3000,$3400,$3800,$3C00 + word = $2080,$2480,$2880,$2C80,$3080,$3480,$3880,$3C80 hgrscan:[yscan][xscan] = fillval ``` From 15ca92747f2818d79bdbe6a92a5c568d8d8a97f8 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 20:28:59 -0700 Subject: [PATCH 20/44] Update README.md --- PLASMA/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index e87c368e..079d891e 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -152,7 +152,7 @@ There are four basic types of data that can be manipulated: constants, variables Values can be treated as pointers by preceding them with a ‘^’ for byte pointers, ‘*’ for word pointers. ``` - strlen = ^(srcstr) + strlen = ^srcstr ``` Addresses of variables and functions can be taken with a preceding ‘@’, address-of operator. Parenthesis can surround an expression to be used as a pointer, but not address-of. @@ -176,7 +176,7 @@ Functions with parameters or expressions to be used as a function address to cal byte key keyin = @keyin2plus ; address-of keyin2plus function - key = (keyin)() + key = keyin() ``` Expressions and Statements From b5fd4febff077a86820d76d4e9bac0ac88f496e3 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 20:38:41 -0700 Subject: [PATCH 21/44] Update README.md --- PLASMA/README.md | 51 ++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index 079d891e..9afd713e 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -18,10 +18,6 @@ The PLASMA low level operations are defined as: | OP | Description |-------|----------------------------------- | ZERO | push zero on the stack -| DROP | drop top stack value -| DUP | duplicate top stack value -| OVER | duplicate next from top stack value -| SWAP | swap two topmost stack values | ADD | add top two values, leave result on top | SUB | subtract next from top from top, leave result on top | MUL | multiply two topmost stack values, leave result on top @@ -31,36 +27,25 @@ The PLASMA low level operations are defined as: | DECR | decrement top of stack | NEG | negate top of stack | COMP | compliment top of stack -| BAND | bit wise AND top two values, leave result on top +| AND | bit wise AND top two values, leave result on top | IOR | bit wise inclusive OR top two values, leave result on top | XOR | bit wise exclusive OR top two values, leave result on top -| NOT | logical NOT of top of stack | LOR | logical OR top two values, leave result on top | LAND | logical AND top two values, leave result on top | SHL | shift left next from top by top, leave result on top | SHR | shift right next from top by top, leave result on top -| IDXB | add top of stack to next from top, leave result on top +| IDXB | add top of stack to next from top, leave result on top (ADD) | IDXW | add 2X top of stack to next from top, leave result on top -| LAA | load absolute address +| NOT | logical NOT of top of stack +| LA | load address | LLA | load local address from frame offset | CB | constant byte | CW | constant word -| LB | load byte from top of stack address -| LW | load word from top of stack address -| LLB | load byte from frame offset -| LLW | load word from frame offset -| LAB | load byte from absolute address -| LAW | load word from absolute address -| SB | store top of stack byte into next from top address -| SW | store top of stack word into next from top address -| SLB | store top of stack into local byte at frame offset -| SLW | store top of stack into local word at frame offset -| SAB | store top of stack into byte at absolute address -| SAW | store top of stack into word at absolute address -| DLB | duplicate top of stack into local byte at frame offset -| DLW | duplicate top of stack into local word at frame offset -| DAB | duplicate top of stack into byte at absolute address -| DAW | duplicate top of stack into word at absolute address +| SWAP | swap two topmost stack values +| DROP | drop top stack value +| DUP | duplicate top stack value +| PUSH | push top to call stack +| PULL | pull from call stack | BRGT | branch next from top greater than top | BRLT | branch next from top less than top | BREQ | branch next from top equal to top @@ -79,8 +64,22 @@ The PLASMA low level operations are defined as: | ENTER | allocate frame size and copy stack parameters to local frame | LEAVE | deallocate frame and return from sub routine call | RET | return from sub routine call -| PUSH | push top to call stack -| PULL | pull from call stack +| LB | load byte from top of stack address +| LW | load word from top of stack address +| LLB | load byte from frame offset +| LLW | load word from frame offset +| LAB | load byte from absolute address +| LAW | load word from absolute address +| SB | store top of stack byte into next from top address +| SW | store top of stack word into next from top address +| SLB | store top of stack into local byte at frame offset +| SLW | store top of stack into local word at frame offset +| SAB | store top of stack into byte at absolute address +| SAW | store top of stack into word at absolute address +| DLB | duplicate top of stack into local byte at frame offset +| DLW | duplicate top of stack into local word at frame offset +| DAB | duplicate top of stack into byte at absolute address +| DAW | duplicate top of stack into word at absolute address ##PLASMA Compiler/Assembler From 018d65b5f71451ca6158e0d2f37f9ae89c1f7aa4 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 20:41:42 -0700 Subject: [PATCH 22/44] Update README.md --- PLASMA/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index 9afd713e..a5df6659 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -84,7 +84,7 @@ The PLASMA low level operations are defined as: ##PLASMA Compiler/Assembler -Although the low-level operations could easily by coded by hand, they were chosen to be an easy target for a simple compiler. Think along the lines of an advanced assembler or stripped down C compiler ( C--). Taking concepts from BASIC, Pascal, C and assembler, the PLASMA compiler is simple yet expressive. +Although the low-level operations could easily by coded by hand, they were chosen to be an easy target for a simple compiler. Think along the lines of an advanced assembler or stripped down C compiler ( C--). Taking concepts from BASIC, Pascal, C and assembler, the PLASMA compiler is simple yet expressive. The syntax is line oriented; there is no statement delimiter except newline. Comments are allowed throughout the source, starting with the ‘;’ character. The rest of the line is ignored. From 4415045c6bcc8515c4428a2c039d3efe626938e5 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 20:46:44 -0700 Subject: [PATCH 23/44] Update README.md --- PLASMA/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index a5df6659..db628b48 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -247,7 +247,7 @@ Control structures affect the flow of control through the program. There are co fin ``` -The when/is/otherwise/merge statement is similar to the if/elsif/else/fin construct except that it is more efficient. It selects one path based on the evaluated expressions, then merges the code path back together at the end. However only the 'when' value is compared against a list of expressions. The expressions do not need to be constants, they can be any valid expression. The list of expressions is evaluated in order, so for efficiency sake, place the most common cases earlier in the list. +The when/is/otherwise/wend statement is similar to the if/elsif/else/fin construct except that it is more efficient. It selects one path based on the evaluated expressions, then merges the code path back together at the end. However only the 'when' value is compared against a list of expressions. The expressions do not need to be constants, they can be any valid expression. The list of expressions is evaluated in order, so for efficiency sake, place the most common cases earlier in the list. ``` when keypressed From 4786ac16de791c6db4fe190da79969f556ab599c Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 20:55:37 -0700 Subject: [PATCH 24/44] Update README.md --- PLASMA/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index db628b48..dc0a4136 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -319,8 +319,11 @@ call6502(aReg, xReg, yReg, statusReg, addr) returns a pointer to a four byte str const getlin = $FD6A numchars = (call6502(0, 0, 0, 0, getlin)).xreg ; return char count in X reg - prodos(cmd, params)calls ProDOS, returning the status value. +``` +prodos(cmd, params) calls ProDOS, returning the status value. + +``` def read(refnum, buff, len) byte params[8] From e3578e66882e04e5b96f635d463657d62bc2d5e8 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 29 Apr 2014 21:05:47 -0700 Subject: [PATCH 25/44] Update README.md --- PLASMA/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index dc0a4136..9bdbbb79 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -11,7 +11,7 @@ All three systems were implemented using stack architecture. Pascal and Java we ##A New Approach -PLASMA takes an approach that uses the best of all the above implementations to create a unique, powerful and efficient platform for developing new applications on the Apple II. One goal was to create a very small VM runtime, bytecode interpreter, and module loader that could adjust the code size vs. performance optimizations to allow for interpreted code, threaded code, or efficiently compiled native code. The decision was made early on to implement a stack based architecture duplicating the approach taken by FORTH. Space in the zero page would be assigned to a 16 bit, 32 element evaluation stack, indexed by the X register. The stack is purposely not split between low and high values so as to allow reading and writing addresses stored directly on the stack. The trade off is that the stack pointer has to be incremented and decremented by two for every push/pop operation. A simple compiler was written so that higher level constructs could be used and global/local variables would hold values instead of using clever stack manipulation. Function/procedure frames would allow for local variables, but with a limitation - the frame could be no larger than 256 bytes. By enforcing this limitation, the function frame could easily be accessed through a frame pointer value in zero page, indexed by the Y register. The call stack uses the 6502's hardware stack resulting in the same 256 byte limitation imposed by the hardware. However, this limitation could be lifted by extending the call sequence to save and restore the return address in the function frame. This was not done initially for performance reasons and simplicity of implementation. One of the goals of PLASMA was to allow for intermixing of functions implemented as bytecode, threaded code, or native code. Taking a page from the FORTH play book, a function call is implemented as a native subroutine call to an address. If the function is in bytecode, the first thing it does is call back into the interpreter to execute the following bytecode. Functions can be selectively expanded as bytecode, threaded code, or natively compiled, all at load time. Threaded code expands to about 3X the size of bytecode with about 3X the performance. Native code is about 5X-10X the size with a significant improvement in performance. The native code compiler uses a strategy of caching the Top-Of-Stack value in the Y and A registers of the 6502. The compiler also tracks the TOS pointer and adjusts the address accordingly to avoid actual manipulation of the X register. The X register in effect becomes the frame pointer for the evaluation stack. Function call parameters are pushed onto the evaluation stack in order they are written. The first operation inside of the function call is to pull the parameters off the evaluation stack and put them in local frame storage. Function callers and callees must agree on the number of parameters to avoid stack underflow/overflow. All functions return a value on the evaluation stack regardless of it being used or not. Lastly, PLASMA is not a typed language. Just like assembly, any value can represent a character, integer, or address. It's the programmer's job to know the type. Only bytes and words are known to PLASMA. Bytes are unsigned 8 bit quantities, words are signed 16 bit quantities. All stack operations involve 16 bits of precision. +PLASMA takes an approach that uses the best of all the above implementations to create a unique, powerful and efficient platform for developing new applications on the Apple II. One goal was to create a very small VM runtime, bytecode interpreter, and module loader that could adjust the code size vs. performance optimizations to allow for interpreted code, threaded code, or efficiently compiled native code. The decision was made early on to implement a stack based architecture duplicating the approach taken by FORTH. Space in the zero page would be assigned to a 16 bit, 32 element evaluation stack, indexed by the X register. The stack is purposely not split between low and high values so as to allow reading and writing addresses stored directly on the stack. The trade off is that the stack pointer has to be incremented and decremented by two for every push/pop operation. A simple compiler was written so that higher level constructs could be used and global/local variables would hold values instead of using clever stack manipulation. Function/procedure frames would allow for local variables, but with a limitation - the frame could be no larger than 256 bytes. By enforcing this limitation, the function frame could easily be accessed through a frame pointer value in zero page, indexed by the Y register. The call stack uses the 6502's hardware stack resulting in the same 256 byte limitation imposed by the hardware. However, this limitation could be lifted by extending the call sequence to save and restore the return address in the function frame. This was not done initially for performance reasons and simplicity of implementation. One of the goals of PLASMA was to allow for intermixing of functions implemented as bytecode, or native code. Taking a page from the FORTH play book, a function call is implemented as a native subroutine call to an address. If the function is in bytecode, the first thing it does is call back into the interpreter to execute the following bytecode. Function call parameters are pushed onto the evaluation stack in order they are written. The first operation inside of the function call is to pull the parameters off the evaluation stack and put them in local frame storage. Function callers and callees must agree on the number of parameters to avoid stack underflow/overflow. All functions return a value on the evaluation stack regardless of it being used or not. Lastly, PLASMA is not a typed language. Just like assembly, any value can represent a character, integer, or address. It's the programmer's job to know the type. Only bytes and words are known to PLASMA. Bytes are unsigned 8 bit quantities, words are signed 16 bit quantities. All stack operations involve 16 bits of precision. The PLASMA low level operations are defined as: From 87ecc6df9c24cfb3808c6e4904322b8e8ccbb5ac Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Sun, 4 May 2014 16:15:45 -0700 Subject: [PATCH 26/44] Initial import for 6502 VM --- PLASMA/src/plvm02.s | 1612 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1612 insertions(+) create mode 100644 PLASMA/src/plvm02.s diff --git a/PLASMA/src/plvm02.s b/PLASMA/src/plvm02.s new file mode 100644 index 00000000..a101f24a --- /dev/null +++ b/PLASMA/src/plvm02.s @@ -0,0 +1,1612 @@ +.PC02 +.DEFINE EQU = +.DEFINE DB .BYTE +.DEFINE DW .WORD +.DEFINE DS .RES +.DEFINE ORG .ORG +.DEFINE STKCHK 1 +.DEFINE TMRCHK 1 +;********************************************************** +;* +;* SYSTEM ROUTINES AND LOCATIONS +;* +;********************************************************** +;* +;* MONITOR SPECIAL LOCATIONS AND PRODOS MLI +;* +CSWL EQU $36 +CSWH EQU $37 +PROMPTCHAR EQU $33 +PRODOS EQU $BF00 +MACHID EQU $BF98 +;* +;* HARDWARE ADDRESSES +;* +KEYBD EQU $C000 +CLRKBD EQU $C010 +SPKR EQU $C030 +ROMIN EQU $C081 +LCBNK2 EQU $C083 +LCBNK1 EQU $C08B +ALTZPOFF EQU $C008 +ALTZPON EQU $C009 +ALTRAMRDOFF EQU $C002 +ALTRAMRDON EQU $C003 +ALTRAMWROFF EQU $C004 +ALTRAMWRON EQU $C005 +;* +;* AUXMEM ACCESS MACROS +;* +.IF IS65C02 +.MACRO AUXZP_ACCESS_ON + STA ALTZPON ; TURN ON ALT ZP AND LC +.ENDMACRO +.MACRO AUXZP_ACCESS_OFF + STA ALTZPOFF ; TURN OFF ALT ZP AND LC +.ENDMACRO +.MACRO AUXMEM_RDACCESS_ON + STA ALTRAMRDON +.ENDMACRO +.MACRO AUXMEM_RDACCESS_OFF + STA ALTRAMRDOFF +.ENDMACRO +.MACRO AUXMEM_WRACCESS_ON + STA ALTRAMWRON +.ENDMACRO +.MACRO AUXMEM_WRACCESS_OFF + STA ALTRAMWROFF +.ENDMACRO +.ELSE +.MACRO AUXZP_ACCESS_ON + SEI ; TURN INTERRUPTS OFF + STA ALTZPON ; TURN ON ALT ZP AND LC +.ENDMACRO +.MACRO AUXZP_ACCESS_OFF + STA ALTZPOFF ; TURN OFF ALT ZP AND LC + CLI ; TURN INTERRUPTS BACK ON +.ENDMACRO +.MACRO AUXMEM_RDACCESS_ON + SEI + STA ALTRAMRDON +.ENDMACRO +.MACRO AUXMEM_RDACCESS_OFF + STA ALTRAMRDOFF + CLI +.ENDMACRO +.MACRO AUXMEM_WRACCESS_ON + SEI + STA ALTRAMWRON +.ENDMACRO +.MACRO AUXMEM_WRACCESS_OFF + STA ALTRAMWROFF + CLI +.ENDMACRO +.ENDIF +;* +;* SIMPLIFUED ACCESS MACROS +;* +.IF IS65C02 +.MACRO LDA_IPC + LDA (PC) +.ENDMACRO +.MACRO LDA_ITMPL + LDA (TMP) +.ENDMACRO +.MACRO LDA_ITMPH + LDY #$01 + LDA (TMP),Y +.ENDMACRO +.MACRO LDA0 + LDA #$00 +.ENDMACRO +.MACRO STA_ITMPL + STA (TMP) +.ENDMACRO +.MACRO STA_ITMPH + LDY #$01 + STA (TMP),Y +.ENDMACRO +.MACRO ST0 ADDR + STZ ADDR +.ENDMACRO +.MACRO CLRY +.ENDMACRO +.ELSE +.MACRO LDA_IPC + LDA (PC),Y +.ENDMACRO +.MACRO LDA_ITMPL + LDA (TMP),Y +.ENDMACRO +.MACRO LDA_ITMPH + INY + LDA (TMP),Y + DEY +.ENDMACRO +.MACRO LDA0 + TYA +.ENDMACRO +.MACRO STA_ITMPL + STA (TMP),Y +.ENDMACRO +.MACRO STA_ITMPH + INY + STA (TMP),Y + DEY +.ENDMACRO +.MACRO ST0 ADDR + STY ADDR +.ENDMACRO +.MACRO CLRY + LDY #$00 +.ENDMACRO +.ENDIF + +;********************************************************** +;* +;* VM ZERO PAGE LOCATIONS +;* +;********************************************************** +ESTKSZ EQU $20 +ESTK EQU $C0 +ESTKL EQU ESTK +ESTKH EQU ESTK+ESTKSZ/2 +VMZP EQU ESTK+ESTKSZ +FRMP EQU VMZP+$00 +FRMPL EQU FRMP +FRMPH EQU FRMP+1 +PC EQU VMZP+$02 +PCL EQU PC +PCH EQU PC+1 +TICK EQU VMZP+$04 +ESP EQU VMZP+$05 + +TMP EQU VMZP+$0A +TMPL EQU TMP +TMPH EQU TMP+1 +TMPX EQU TMP+2 +NPARMS EQU TMPL +FRMSZ EQU TMPH +DVSIGN EQU TMPX +JSROP EQU VMZP+$0D + + ORG $D000 +;* +;* OPCODE TABLE +;* +OPTBL: DW ZERO,ADD,SUB,MUL,DIV,DIVMOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E + DW NEG,COMP,BAND,IOR,XOR,SHL,SHR,IDXW ; 10 12 14 16 18 1A 1C 1E + DW NOT,LOR,LAND,LA,LLA,CB,CW,SWAP ; 20 22 24 26 28 2A 2C 2E + DW DROP,DUP,PUSH,PULL,SKPLT,SKPGT,SKPEQ,SKPNE ; 30 32 34 36 38 3A 3C 3E + DW ISEQ,ISNE,ISGT,ISLT,ISGE,ISLE,SKPFLS,SKPTRU ; 40 42 44 46 48 4A 4C 4E + DW SKIP,ISKIP,CALL,ICAL,ENTER,LEAVE,RET,INT ; 50 52 54 56 58 5A 5C 5E + DW LB,LW,LLB,LLW,LAB,LAW,DLB,DLW ; 60 62 64 66 68 6A 6C 6E + DW SB,SW,SLB,SLW,SAB,SAW,DAB,DAW ; 70 72 74 76 78 7A 7C 7E +;* +;* OPXCODE TABLE +;* +OPXTBL: DW ZERO,ADD,SUB,MUL,DIV,DIVMOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E + DW NEG,COMP,BAND,IOR,XOR,SHL,SHR,IDXW ; 10 12 14 16 18 1A 1C 1E + DW NOT,LOR,LAND,LAX,LLAX,CBX,CWX,SWAP ; 20 22 24 26 28 2A 2C 2E + DW DROP,DUP,PUSH,PULL,SKPLTX,SKPGTX,SKPEQX,SKPNEX ; 30 32 34 36 38 3A 3C 3E + DW ISEQ,ISNE,ISGT,ISLT,ISGE,ISLE,SKPFLSX,SKPTRUX ; 40 42 44 46 48 4A 4C 4E + DW SKIPX,ISKIPX,CALLX,ICAL,ENTER,LEAVE,RET,INTX ; 50 52 54 56 58 5A 5C 5E + DW LB,LW,LLBX,LLWX,LABX,LAWX,DLBX,DLWX ; 60 62 64 66 68 6A 6C 6E + DW SB,SW,SLBX,SLWX,SABX,SAWX,DABX,DAWX ; 70 72 74 76 78 7A 7C 7E +;* +;* COMMAND LOADER CODE +;* + CLD + CLV + BVC :+ + JMP PLASMA +: + .INCLUDE "cmd.byte" + +;*********************************************** +;* +;* INTERPRETER INITIALIZATION +;* +;*********************************************** +;* +;* INIT AND ENTER INTO PLASMA BYTECODE INTERPRETER +;* X:Y:A = ADDRESS OF INITAL ENTRYPOINT +;* +PLASMA: STA PCL + STY PCH + STX TMP + CLD + LDY #$20 +: LDA PAGE3,Y + STA $03D0,Y + DEY + BPL :- + LDX #ESTKSZ/2 + INY ; LDY #$00 + STY TICK + LDA #$6C + STA JSROP + LDA #>OPTBL + STA JSROP+2 + LDA TMP + BEQ FETCHOP + LDA MACHID + AND #$30 + CMP #$30 + BEQ FETCHOPX +_RTS: RTS +_BRK: BRK +;* +;* PAGE 3 VECTORS INTO INTERPRETER +;* +PAGE3: BIT $C080 ; $03D0 - INTERP ENTRY + JMP _INTERP + BIT $C080 ; $03D6 - INTERPX ENTRY + JMP _INTERPX + BIT $C080 ; $03DC - LEAVE ENTRY + JMP _LEAVE + BIT $C080 ; $03E2 - ENTER ENTRY + JMP _ENTER + DW _RTS ; $03E8 - PERIODIC VECTOR + DW _BRK ; $03EA - INT VECTOR +TMRVEC EQU $03E8 +INTVEC EQU $03EA +;* +;* ENTER INTO INLINE BYTECODE +;* +_INTERP: PLA + STA PCL + PLA + STA PCH + LDY #$00 + BEQ NEXTOP +TOCKOP: JSR TICKTOCK +FETCHOP: +.IF TMRCHK + DEC TICK + BEQ TOCKOP +.ENDIF + LDA_IPC + STA JSROP+1 + JSR JSROP +.IF STKCHK + CPX #ESTKSZ/2+1 + BCS STKINT +.ENDIF +NEXTOP: INC PCL + BNE FETCHOP + INC PCH + BNE FETCHOP +STKINT: LDA #$FF +INTJMP: JMP (INTVEC) +TICKTOCK: JMP (TMRVEC) +TMPJMP: JMP (TMP) +;* +;* ENTER INTO EXTERNAL BYTECODE +;* +_INTERPX: PLA + STA TMPL + PLA + STA TMPH + LDY #$01 + LDA (TMP),Y + STA PCL + INY + LDA (TMP),Y + STA PCH + INY + LDA (TMP),Y + TAY + BNE FETCHOPX + BEQ FETCHOP +TOCKOPX: JSR TICKTOCK +FETCHOPX: +.IF TMRCHK + DEC TICK + BEQ TOCKOPX +.ENDIF + AUXMEM_RDACCESS_ON + LDA_IPC + AUXMEM_RDACCESS_OFF + ORA #$80 ; SELECT OPX CODES + STA JSROP+1 + JSR JSROP +.IF STKCHK + CPX #ESTKSZ/2+1 + BCS STKINT +.ENDIF +NEXTOPX: INC PCL + BNE FETCHOPX + INC PCH + BNE FETCHOPX +;* +;* ADD TOS TO TOS-1 +;* +ADD: LDA ESTKL,X + CLC + ADC ESTKL+1,X + STA ESTKL+1,X + LDA ESTKH,X + ADC ESTKH+1,X + STA ESTKH+1,X + INX + RTS +;* +;* SUB TOS FROM TOS-1 +;* +SUB: LDA ESTKL+1,X + SEC + SBC ESTKL,X + STA ESTKL+1,X + LDA ESTKH+1,X + SBC ESTKH,X + STA ESTKH+1,X + INX + RTS +;* +;* SHIFT TOS-1 LEFT BY 1, ADD TO TOS-1 +;* +IDXW: LDA ESTKL,X + ASL + ROL ESTKH,X + CLC + ADC ESTKL+1,X + STA ESTKL+1,X + LDA ESTKH,X + ADC ESTKH+1,X + STA ESTKH+1,X + INX + RTS +;* +;* MUL TOS-1 BY TOS +;* +MUL: ST0 TMPL ; PRODL + ST0 TMPH ; PRODH + LDY #$10 +MUL1: LSR ESTKH,X ; MULTPLRH + ROR ESTKL,X ; MULTPLRL + BCC MUL2 + LDA ESTKL+1,X ; MULTPLNDL + CLC + ADC TMPL ; PRODL + STA TMPL + LDA ESTKH+1,X ; MULTPLNDH + ADC TMPH ; PRODH + STA TMPH +MUL2: ASL ESTKL+1,X ; MULTPLNDL + ROL ESTKH+1,X ; MULTPLNDH + DEY + BNE MUL1 + INX + LDA TMPL ; PRODL + STA ESTKL,X + LDA TMPH ; PRODH + STA ESTKH,X + RTS +;* +;* INTERNAL DIVIDE ALGORITHM +;* +_DIV: LDA ESTKH,X + AND #$80 + STA DVSIGN + BPL _DIV1 + JSR NEG + INC DVSIGN +_DIV1: LDA ESTKH+1,X + BPL _DIV2 + INX + JSR NEG + DEX + INC DVSIGN + BNE _DIV3 +_DIV2: ORA ESTKL+1,X ; DVDNDL + BNE _DIV3 + STA TMPL + STA TMPH + RTS +_DIV3: LDY #$11 ; #BITS+1 + LDA #$00 + STA TMPL ; REMNDRL + STA TMPH ; REMNDRH +_DIV4: ASL ESTKL+1,X ; DVDNDL + ROL ESTKH+1,X ; DVDNDH + DEY + BCC _DIV4 + STY ESTKL-1,X +_DIV5: ROL TMPL ; REMNDRL + ROL TMPH ; REMNDRH + LDA TMPL ; REMNDRL + SEC + SBC ESTKL,X ; DVSRL + TAY + LDA TMPH ; REMNDRH + SBC ESTKH,X ; DVSRH + BCC _DIV6 + STA TMPH ; REMNDRH + STY TMPL ; REMNDRL +_DIV6: ROL ESTKL+1,X ; DVDNDL + ROL ESTKH+1,X ; DVDNDH + DEC ESTKL-1,X + BNE _DIV5 + CLRY + RTS +;* +;* DIV TOS-1 BY TOS +;* +DIV: JSR _DIV + INX + LSR DVSIGN ; SIGN(RESULT) = (SIGN(DIVIDEND) + SIGN(DIVISOR)) & 1 + BCS NEG + RTS +;* +;* NEGATE TOS +;* +NEG: LDA0 + SEC + SBC ESTKL,X + STA ESTKL,X + LDA0 + SBC ESTKH,X + STA ESTKH,X + RTS +;* +;* DIV,MOD TOS-1 BY TOS +;* +DIVMOD: JSR _DIV + LDA TMPL ; REMNDRL + STA ESTKL,X + LDA TMPH ; REMNDRH + STA ESTKH,X + LDA DVSIGN ; REMAINDER IS SIGN OF DIVIDEND + BPL DIVMOD1 + JSR NEG +DIVMOD1: LSR DVSIGN + BCC DIVMOD2 ; DIV RESULT TOS-1 + INX + JSR NEG + DEX +DIVMOD2: RTS +;* +;* INCREMENT TOS +;* +INCR: INC ESTKL,X + BNE INCR1 + INC ESTKH,X +INCR1: RTS +;* +;* DECREMENT TOS +;* +DECR: LDA ESTKL,X + BNE DECR1 + DEC ESTKH,X +DECR1: DEC ESTKL,X + RTS +;* +;* BITWISE COMPLIMENT TOS +;* +COMP: LDA #$FF + EOR ESTKL,X + STA ESTKL,X + LDA #$FF + EOR ESTKH,X + STA ESTKH,X + RTS +;* +;* BITWISE AND TOS TO TOS-1 +;* +BAND: LDA ESTKL+1,X + AND ESTKL,X + STA ESTKL+1,X + LDA ESTKH+1,X + AND ESTKH,X + STA ESTKH+1,X + INX + RTS +;* +;* INCLUSIVE OR TOS TO TOS-1 +;* +IOR: LDA ESTKL+1,X + ORA ESTKL,X + STA ESTKL+1,X + LDA ESTKH+1,X + ORA ESTKH,X + STA ESTKH+1,X + INX + RTS +;* +;* EXLUSIVE OR TOS TO TOS-1 +;* +XOR: LDA ESTKL+1,X + EOR ESTKL,X + STA ESTKL+1,X + LDA ESTKH+1,X + EOR ESTKH,X + STA ESTKH+1,X + INX + RTS +;* +;* SHIFT TOS-1 LEFT BY TOS +;* +SHL: LDA ESTKL,X + CMP #$08 + BCC SHL1 + LDY ESTKL+1,X + STY ESTKH+1,X + LDY #$00 + STY ESTKL+1,X + SBC #$08 +SHL1: TAY + BEQ SHL3 +SHL2: ASL ESTKL+1,X + ROL ESTKH+1,X + DEY + BNE SHL2 +SHL3: INX + RTS +;* +;* SHIFT TOS-1 RIGHT BY TOS +;* +SHR: LDA ESTKL,X + CMP #$08 + BCC SHR2 + LDY ESTKH+1,X + STY ESTKL+1,X + CPY #$80 + LDY #$00 + BCC SHR1 + DEY +SHR1: STY ESTKH+1,X + SEC + SBC #$08 +SHR2: TAY + BEQ SHR4 + LDA ESTKH+1,X +SHR3: CMP #$80 + ROR + ROR ESTKL+1,X + DEY + BNE SHR3 + STA ESTKH+1,X +SHR4: INX + RTS +;* +;* LOGICAL NOT +;* +NOT: LDA ESTKL,X + ORA ESTKH,X + BNE NOT1 + LDA #$FF + STA ESTKL,X + STA ESTKH,X + RTS +NOT1: ST0 {ESTKL,X} + ST0 {ESTKH,X} + RTS +;* +;* LOGICAL AND +;* +LAND: LDA ESTKL,X + ORA ESTKH,X + BEQ LAND1 + LDA ESTKL+1,X + ORA ESTKH+1,X + BEQ LAND1 + LDA #$FF +LAND1: STA ESTKL+1,X + STA ESTKH+1,X + INX + RTS +;* +;* LOGICAL OR +;* +LOR: LDA ESTKL,X + ORA ESTKH,X + ORA ESTKL+1,X + ORA ESTKH+1,X + BEQ LOR1 + LDA #$FF +LOR1: STA ESTKL+1,X + STA ESTKH+1,X +;* +;* DROP TOS +;* +DROP: INX + RTS +;* +;* SWAP TOS WITH TOS-1 +;* +SWAP: LDA ESTKL,X + LDY ESTKL+1,X + STA ESTKL+1,X + STY ESTKL,X + LDA ESTKH,X + LDY ESTKH+1,X + STA ESTKH+1,X + STY ESTKH,X + CLRY + RTS +;* +;* DUPLICATE TOS +;* +DUP: DEX + LDA ESTKL+1,X + STA ESTKL,X + LDA ESTKH+1,X + STA ESTKH,X + RTS +;* +;* PUSH FROM EVAL STACK TO CALL STACK +;* +PUSH: PLA + STA TMPH + PLA + STA TMPL + LDA ESTKL,X + PHA + LDA ESTKH,X + PHA + INX + LDA TMPL + PHA + LDA TMPH + PHA + RTS +;* +;* PULL FROM CALL STACK TO EVAL STACK +;* +PULL: PLA + STA TMPH + PLA + STA TMPL + DEX + PLA + STA ESTKH,X + PLA + STA ESTKL,X + LDA TMPL + PHA + LDA TMPH + PHA + RTS +;* +;* CONSTANT +;* +ZERO: DEX + ST0 {ESTKL,X} + ST0 {ESTKH,X} + RTS +CB: DEX + INC PCL + BNE CB1 + INC PCH +CB1: LDA_IPC + STA ESTKL,X + ST0 {ESTKH,X} + RTS +;* +;* LOAD ADDRESS - CHECK FOR DATA OR CODE SPACE +;* +LA: +CW: DEX + INC PCL + BNE CW1 + INC PCH +CW1: LDA_IPC + STA ESTKL,X + INC PCL + BNE CW2 + INC PCH +CW2: LDA_IPC + STA ESTKH,X + RTS +;* +;* LOAD VALUE FROM ADDRESS TAG +;* +LB: LDA ESTKL,X + STA TMPL + LDA ESTKH,X + STA TMPH + LDA_ITMPL + STA ESTKL,X + ST0 {ESTKH,X} + RTS +LW: LDA ESTKL,X + STA TMPL + LDA ESTKH,X + STA TMPH + LDA_ITMPL + STA ESTKL,X + LDA_ITMPH + STA ESTKH,X + RTS +;* +;* LOAD ADDRESS OF LOCAL FRAME OFFSET +;* +LLA: INC PCL + BNE LLA1 + INC PCH +LLA1: LDA_IPC + DEX + CLC + ADC FRMPL + STA ESTKL,X + LDA0 + ADC FRMPH + STA ESTKH,X + RTS +;* +;* LOAD VALUE FROM LOCAL FRAME OFFSET +;* +LLB: INC PCL + BNE LLB1 + INC PCH +LLB1: LDA_IPC + TAY + DEX + LDA (FRMP),Y + STA ESTKL,X + CLRY + ST0 {ESTKH,X} + RTS +LLW: INC PCL + BNE LLW1 + INC PCH +LLW1: LDA_IPC + TAY + DEX + LDA (FRMP),Y + STA ESTKL,X + INY + LDA (FRMP),Y + STA ESTKH,X + CLRY + RTS +;* +;* LOAD VALUE FROM ABSOLUTE ADDRESS +;* +LAB: INC PCL + BNE LAB1 + INC PCH +LAB1: LDA_IPC + STA TMPL + INC PCL + BNE LAB2 + INC PCH +LAB2: LDA_IPC + STA TMPH + LDA_ITMPL + DEX + STA ESTKL,X + ST0 {ESTKH,X} + RTS +LAW: INC PCL + BNE LAW1 + INC PCH +LAW1: LDA_IPC + STA TMPL + INC PCL + BNE LAW2 + INC PCH +LAW2: LDA_IPC + STA TMPH + LDA_ITMPL + DEX + STA ESTKL,X + LDA_ITMPH + STA ESTKH,X + RTS +;* +;* STORE VALUE TO ADDRESS +;* +SB: LDA ESTKL+1,X + STA TMPL + LDA ESTKH+1,X + STA TMPH + LDA ESTKL,X + STA_ITMPL + INX + INX + RTS +SW: LDA ESTKL+1,X + STA TMPL + LDA ESTKH+1,X + STA TMPH + LDA ESTKL,X + STA_ITMPL + LDA ESTKH,X + STA_ITMPH + INX + INX + RTS +;* +;* STORE VALUE TO LOCAL FRAME OFFSET +;* +SLB: INC PCL + BNE SLB1 + INC PCH +SLB1: LDA_IPC + TAY + LDA ESTKL,X + STA (FRMP),Y + INX + CLRY + RTS +SLW: INC PCL + BNE SLW1 + INC PCH +SLW1: LDA_IPC + TAY + LDA ESTKL,X + STA (FRMP),Y + INY + LDA ESTKH,X + STA (FRMP),Y + INX + CLRY + RTS +;* +;* STORE VALUE TO LOCAL FRAME OFFSET WITHOUT POPPING STACK +;* +DLB: INC PCL + BNE DLB1 + INC PCH +DLB1: LDA_IPC + TAY + LDA ESTKL,X + STA (FRMP),Y + CLRY + RTS +DLW: INC PCL + BNE DLW1 + INC PCH +DLW1: LDA_IPC + TAY + LDA ESTKL,X + STA (FRMP),Y + INY + LDA ESTKH,X + STA (FRMP),Y + CLRY + RTS +;* +;* STORE VALUE TO ABSOLUTE ADDRESS +;* +SAB: INC PCL + BNE SAB1 + INC PCH +SAB1: LDA_IPC + STA TMPL + INC PCL + BNE SAB2 + INC PCH +SAB2: LDA_IPC + STA TMPH + LDA ESTKL,X + STA_ITMPL + INX + RTS +SAW: INC PCL + BNE SAW1 + INC PCH +SAW1: LDA_IPC + STA TMPL + INC PCL + BNE SAW2 + INC PCH +SAW2: LDA_IPC + STA TMPH + LDA ESTKL,X + STA_ITMPL + LDA ESTKH,X + STA_ITMPH + INX + RTS +;* +;* STORE VALUE TO ABSOLUTE ADDRESS WITHOUT POPPING STACK +;* +DAB: INC PCL + BNE DAB1 + INC PCH +DAB1: LDA_IPC + STA TMPL + INC PCL + BNE DAB2 + INC PCH +DAB2: LDA_IPC + STA TMPH + LDA ESTKL,X + STA_ITMPL + RTS +DAW: INC PCL + BNE DAW1 + INC PCH +DAW1: LDA_IPC + STA TMPL + INC PCL + BNE DAW2 + INC PCH +DAW2: LDA_IPC + STA TMPH + LDA ESTKL,X + STA_ITMPL + LDA ESTKH,X + STA_ITMPH + RTS +;* +;* COMPARES +;* +ISEQ: +.IF IS65C02 + LDY #$00 +.ENDIF + LDA ESTKL,X + CMP ESTKL+1,X + BNE ISEQ1 + LDA ESTKH,X + CMP ESTKH+1,X + BNE ISEQ1 + DEY +ISEQ1: STY ESTKL+1,X + STY ESTKH+1,X + INX + CLRY + RTS +ISNE: +.IF IS65C02 + LDY #$FF +.ELSE + DEY ; LDY #$FF +.ENDIF + LDA ESTKL,X + CMP ESTKL+1,X + BNE ISNE1 + LDA ESTKH,X + CMP ESTKH+1,X + BNE ISNE1 + INY +ISNE1: STY ESTKL+1,X + STY ESTKH+1,X + INX + CLRY + RTS +ISGE: +.IF IS65C02 + LDY #$00 +.ELSE + ; LDY #$00 +.ENDIF + LDA ESTKL+1,X + CMP ESTKL,X + LDA ESTKH+1,X + SBC ESTKH,X + BVC ISGE1 + EOR #$80 +ISGE1: BMI ISGE2 + DEY +ISGE2: STY ESTKL+1,X + STY ESTKH+1,X + INX + CLRY + RTS +ISGT: +.IF IS65C02 + LDY #$00 +.ELSE + ; LDY #$00 +.ENDIF + LDA ESTKL,X + CMP ESTKL+1,X + LDA ESTKH,X + SBC ESTKH+1,X + BVC ISGT1 + EOR #$80 +ISGT1: BPL ISGT2 + DEY +ISGT2: STY ESTKL+1,X + STY ESTKH+1,X + INX + CLRY + RTS +ISLE: +.IF IS65C02 + LDY #$00 +.ELSE + ; LDY #$00 +.ENDIF + LDA ESTKL,X + CMP ESTKL+1,X + LDA ESTKH,X + SBC ESTKH+1,X + BVC ISLE1 + EOR #$80 +ISLE1: BMI ISLE2 + DEY +ISLE2: STY ESTKL+1,X + STY ESTKH+1,X + INX + CLRY + RTS +ISLT: +.IF IS65C02 + LDY #$00 +.ELSE + ; LDY #$00 +.ENDIF + LDA ESTKL+1,X + CMP ESTKL,X + LDA ESTKH+1,X + SBC ESTKH,X + BVC ISLT1 + EOR #$80 +ISLT1: BPL ISLT2 + DEY +ISLT2: STY ESTKL+1,X + STY ESTKH+1,X + INX + CLRY + RTS +;* +;* SKIPS +;* +SKPTRU: INX + LDA ESTKH-1,X + ORA ESTKL-1,X + BEQ NOSKIP +SKIP: +.IF IS65C02 + LDY #$01 +.ELSE + INY ; LDY #$01 +.ENDIF + LDA (PC),Y + PHA + INY + LDA (PC),Y + STA PCH + PLA + STA PCL + PLA + PLA + CLRY + JMP FETCHOP +SKPFLS: INX + LDA ESTKH-1,X + ORA ESTKL-1,X + BEQ SKIP +NOSKIP: LDA #$02 + CLC + ADC PCL + STA PCL + BCC NOSK1 + INC PCH +NOSK1: RTS +SKPEQ: INX + LDA ESTKL-1,X + CMP ESTKL,X + BNE NOSKIP + LDA ESTKL-1,X + CMP ESTKL,X + BEQ SKIP + BNE NOSKIP +SKPNE: INX + LDA ESTKL-1,X + CMP ESTKL,X + BNE SKIP + LDA ESTKL-1,X + CMP ESTKL,X + BEQ NOSKIP + BNE SKIP +SKPGT: INX + LDA ESTKL-1,X + CMP ESTKL,X + LDA ESTKH-1,X + SBC ESTKH,X + BMI SKIP + BPL NOSKIP +SKPLT: INX + LDA ESTKL,X + CMP ESTKL-1,X + LDA ESTKH,X + SBC ESTKH-1,X + BMI SKIP + BPL NOSKIP +;* +;* INDIRECT SKIP TO ADDRESS +;* +ISKIP: PLA + PLA + LDA ESTKL,X + STA PCL + LDA ESTKH,X + STA PCH + INX + JMP FETCHOP +;* +;* EXTERNAL SYS CALL +;* +INT: INC PCL + BNE INT1 + INC PCH +INT1: LDA_IPC + JSR INTJMP + CLRY + RTS +;* +;* CALL INTO ABSOLUTE ADDRESS (NATIVE CODE) +;* +CALL: INC PCL + BNE CALL1 + INC PCH +CALL1: LDA_IPC + STA TMPL + INC PCL + BNE CALL2 + INC PCH +CALL2: LDA_IPC + STA TMPH + LDA PCH + PHA + LDA PCL + PHA + JSR TMPJMP + PLA + STA PCL + PLA + STA PCH + CLRY + RTS +;* +;* INDIRECT CALL TO ADDRESS (NATIVE CODE) +;* +ICAL: LDA ESTKL,X + STA TMPL + LDA ESTKH,X + STA TMPH + INX + LDA PCH + PHA + LDA PCL + PHA + JSR TMPJMP + PLA + STA PCL + PLA + STA PCH + CLRY + RTS +;* +;* ENTER FUNCTION WITH FRAME SIZE AND PARAM COUNT +;* +_ENTER: STY FRMSZ + JMP ENTER3 +ENTER: INC PCL + BNE ENTER1 + INC PCH +ENTER1: LDA_IPC + STA FRMSZ + INC PCL + BNE ENTER2 + INC PCH +ENTER2: LDA_IPC +ENTER3: STA NPARMS + LDA FRMPL + PHA + SEC + SBC FRMSZ + STA FRMPL + LDA FRMPH + PHA + SBC #$00 + STA FRMPH + LDY #$01 + PLA + STA (FRMP),Y + DEY + PLA + STA (FRMP),Y + LDA NPARMS + BEQ ENTER5 + ASL + TAY + INY +ENTER4: LDA ESTKH,X + STA (FRMP),Y + DEY + LDA ESTKL,X + STA (FRMP),Y + DEY + INX + DEC TMPL + BNE ENTER4 +ENTER5: LDY #$00 + RTS +;* +;* LEAVE FUNCTION +;* +LEAVE: PLA + PLA +_LEAVE: LDY #$01 + LDA (FRMP),Y + DEY + PHA + LDA (FRMP),Y + STA FRMPL + PLA + STA FRMPH + RTS +RET: PLA + PLA + RTS +;*********************************************** +;* +;* XMOD VERSIONS OF BYTECODE OPS +;* +;*********************************************** +;* +;* CONSTANT +;* +CBX: DEX + INC PCL + BNE CBX1 + INC PCH +CBX1: AUXMEM_RDACCESS_ON + LDA_IPC + AUXMEM_RDACCESS_OFF + STA ESTKL,X + STY ESTKH,X + RTS +;* +;* LOAD ADDRESS +;* +LAX: +CWX: DEX + INC PCL + BNE CWX1 + INC PCH +CWX1: AUXMEM_RDACCESS_ON + LDA_IPC + STA ESTKL,X + INC PCL + BNE CWX2 + INC PCH +CWX2: LDA_IPC + AUXMEM_RDACCESS_OFF + STA ESTKH,X + RTS +;* +;* LOAD ADDRESS OF LOCAL FRAME OFFSET +;* +LLAX: INC PCL + BNE LLAX1 + INC PCH +LLAX1: AUXMEM_RDACCESS_ON + LDA_IPC + AUXMEM_RDACCESS_OFF + DEX + CLC + ADC FRMPL + STA ESTKL,X + LDA0 + ADC FRMPH + STA ESTKH,X + RTS +;* +;* LOAD VALUE FROM LOCAL FRAME OFFSET +;* +LLBX: INC PCL + BNE LLBX1 + INC PCH +LLBX1: AUXMEM_RDACCESS_ON + LDA_IPC + AUXMEM_RDACCESS_OFF + TAY + DEX + LDA (FRMP),Y + STA ESTKL,X + CLRY + ST0 {ESTKH,X} + RTS +LLWX: INC PCL + BNE LLWX1 + INC PCH +LLWX1: AUXMEM_RDACCESS_ON + LDA_IPC + AUXMEM_RDACCESS_OFF + TAY + DEX + LDA (FRMP),Y + STA ESTKL,X + INY + LDA (FRMP),Y + STA ESTKH,X + CLRY + RTS +;* +;* LOAD VALUE FROM ABSOLUTE ADDRESS +;* +LABX: INC PCL + BNE LABX1 + INC PCH +LABX1: AUXMEM_RDACCESS_ON + LDA_IPC + STA TMPL + INC PCL + BNE LABX2 + INC PCH +LABX2: LDA_IPC + AUXMEM_RDACCESS_OFF + STA TMPH + DEX + LDA_ITMPL + STA ESTKL,X + ST0 {ESTKH,X} + RTS +LAWX: INC PC + BNE LAWX1 + INC PCH +LAWX1: AUXMEM_RDACCESS_ON + LDA_IPC + STA TMPL + INC PCL + BNE LAWX2 + INC PCH + DEX +LAWX2: LDA_IPC + STA TMPH + LDA_ITMPL + STA ESTKL,X + LDA_ITMPH + AUXMEM_RDACCESS_OFF + STA ESTKH,X + RTS +;* +;* STORE VALUE TO LOCAL FRAME OFFSET +;* +SLBX: INC PCL + BNE SLBX1 + INC PCH +SLBX1: AUXMEM_RDACCESS_ON + LDA_IPC + AUXMEM_RDACCESS_OFF + TAY + LDA ESTKL,X + STA (FRMP),Y + INX + CLRY + RTS +SLWX: INC PCL + BNE SLWX1 + INC PCH +SLWX1: AUXMEM_RDACCESS_ON + LDA_IPC + AUXMEM_RDACCESS_OFF + TAY + LDA ESTKL,X + STA (FRMP),Y + INY + LDA ESTKH,X + STA (FRMP),Y + INX + CLRY + RTS +;* +;* STORE VALUE TO LOCAL FRAME OFFSET WITHOUT POPPING STACK +;* +DLBX: INC PCL + BNE DLBX1 + INC PCH +DLBX1: AUXMEM_RDACCESS_ON + LDA_IPC + AUXMEM_RDACCESS_OFF + TAY + LDA ESTKL,X + STA (FRMP),Y + CLRY + RTS +DLWX: INC PCL + BNE DLWX1 + INC PCH +DLWX1: AUXMEM_RDACCESS_ON + LDA_IPC + AUXMEM_RDACCESS_OFF + TAY + LDA ESTKL,X + STA (FRMP),Y + INY + LDA ESTKH,X + STA (FRMP),Y + CLRY + RTS +;* +;* STORE VALUE TO ABSOLUTE ADDRESS +;* +SABX: INC PCL + BNE SABX1 + INC PCH +SABX1: AUXMEM_RDACCESS_ON + LDA_IPC + STA TMPL + INC PCL + BNE SABX2 + INC PCH +SABX2: LDA_IPC + AUXMEM_RDACCESS_OFF + STA TMPH + LDA ESTKL,X + STA_ITMPL + INX + RTS +SAWX: INC PCL + BNE SAWX1 + INC PCH +SAWX1: AUXMEM_RDACCESS_ON + LDA_IPC + STA TMPL + INC PCL + BNE SAWX2 + INC PCH +SAWX2: LDA_IPC + AUXMEM_RDACCESS_OFF + STA TMPH + LDA ESTKL,X + STA_ITMPL + LDA ESTKH,X + STA_ITMPH + INX + RTS +;* +;* STORE VALUE TO ABSOLUTE ADDRESS WITHOUT POPPING STACK +;* +DABX: INC PCL + BNE DABX1 + INC PCH +DABX1: AUXMEM_RDACCESS_ON + LDA_IPC + STA TMPL + INC PCL + BNE DABX2 + INC PCH +DABX2: LDA_IPC + AUXMEM_RDACCESS_OFF + STA TMPH + LDA ESTKL,X + STA_ITMPL + RTS +DAWX: INC PCL + BNE DAWX1 + INC PCH +DAWX1: AUXMEM_RDACCESS_ON + LDA_IPC + STA TMPL + INC PCL + BNE DAWX2 + INC PCH +DAWX2: LDA_IPC + AUXMEM_RDACCESS_OFF + STA TMPH + LDA ESTKL,X + STA_ITMPL + LDA ESTKH,X + STA_ITMPH + RTS +;* +;* SKIPS +;* +SKPTRUX: INX + LDA ESTKH-1,X + ORA ESTKL-1,X + BEQ NOSKIPX +SKIPX: +.IF IS65C02 + LDY #$01 +.ELSE + INY ; LDY #$01 +.ENDIF + AUXMEM_RDACCESS_ON + LDA_IPC + PHA + INY + LDA_IPC + AUXMEM_RDACCESS_OFF + STA PCH + PLA + STA PCL + PLA + PLA + CLRY + CLRY + JMP FETCHOPX +SKPFLSX: INX + LDA ESTKH-1,X + ORA ESTKL-1,X + BEQ SKIPX +NOSKIPX: LDA #$02 + CLC + ADC PCL + STA PCL + BCC NOSKX1 + INC PCH +NOSKX1: RTS +SKPEQX: INX + ; INX + LDA ESTKL-1,X + CMP ESTKL,X + BNE NOSKIPX + LDA ESTKL-1,X + CMP ESTKL,X + BEQ SKIPX + BNE NOSKIPX +SKPNEX: INX + ; INX + LDA ESTKL-1,X + CMP ESTKL,X + BNE SKIPX + LDA ESTKL-1,X + CMP ESTKL,X + BEQ NOSKIPX + BNE SKIPX +SKPGTX: INX + ; INX + LDA ESTKL-1,X + CMP ESTKL,X + LDA ESTKH-1,X + SBC ESTKH,X + BMI SKIPX + BPL NOSKIPX +SKPLTX: INX + ; INX + LDA ESTKL,X + CMP ESTKL-1,X + LDA ESTKH,X + SBC ESTKH-1,X + BMI SKIPX + BPL NOSKIPX +;* +;* INDIRECT SKIP TO ADDRESS +;* +ISKIPX: PLA + PLA + LDA ESTKL,X + STA PCL + LDA ESTKH,X + STA PCH + INX + JMP FETCHOPX +;* +;* EXTERNAL SYS CALL +;* +INTX: INC PCL + BNE INTX1 + INC PCH +INTX1: AUXMEM_RDACCESS_ON + LDA_IPC + AUXMEM_RDACCESS_OFF + JSR INTJMP + CLRY + RTS +;* +;* CALL TO ABSOLUTE ADDRESS (NATIVE CODE) +;* +CALLX: INC PCL + BNE CALLX1 + INC PCH +CALLX1: AUXMEM_RDACCESS_ON + LDA_IPC + STA TMPL + INC PCL + BNE CALLX2 + INC PCH +CALLX2: LDA_IPC + AUXMEM_RDACCESS_OFF + STA TMPH + LDA PCH + PHA + LDA PCL + PHA + JSR TMPJMP + PLA + STA PCL + PLA + STA PCH + CLRY + RTS From 74f475251070064397012d7378e95deabf240242 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Mon, 5 May 2014 13:16:35 -0700 Subject: [PATCH 27/44] Add References --- PLASMA/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/PLASMA/README.md b/PLASMA/README.md index 9bdbbb79..909d7a0a 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -356,3 +356,8 @@ memset(val16, addr, len) will fill memory with a 16 bit value. memcpy(dstaddr, The original design concept was to create an efficient, flexible, and expressive environment for building applications directly on the Apple II. Choosing a stack based architecture was easy after much experience with other stack based implementations. It also makes the compiler simple to implement. The first take on the stack architecture was to make it a very strict stack architecture in that everything had to be on the stack. The only opcode with operands was the CONSTANT opcode. This allowed for a very small bytecode interpreter and a very easy compile target. However, only when adding an opcode with operands that would greatly improved performance, native code generation or code size was it done. The opcode table grew slowly over time but still retains a small runtime interpreter with good native code density. +## References +B Programming Language USer Manual http://cm.bell-labs.com/cm/cs/who/dmr/kbman.html +FORTH http://en.wikipedia.org/wiki/Forth_(programming_language) +UCSD Pascal http://wiki.freepascal.org/UCSD_Pascal + From e2863418b3343bd956ad630c283a886207d94b7e Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Mon, 5 May 2014 13:17:08 -0700 Subject: [PATCH 28/44] Update README.md --- PLASMA/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/PLASMA/README.md b/PLASMA/README.md index 909d7a0a..cc02acd9 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -358,6 +358,8 @@ The original design concept was to create an efficient, flexible, and expressive ## References B Programming Language USer Manual http://cm.bell-labs.com/cm/cs/who/dmr/kbman.html + FORTH http://en.wikipedia.org/wiki/Forth_(programming_language) + UCSD Pascal http://wiki.freepascal.org/UCSD_Pascal From a044e3b6e2839754bc466c8f8d1e1cb85dcfeefd Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Mon, 5 May 2014 13:20:03 -0700 Subject: [PATCH 29/44] Update README.md --- PLASMA/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/PLASMA/README.md b/PLASMA/README.md index cc02acd9..c4969068 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -363,3 +363,7 @@ FORTH http://en.wikipedia.org/wiki/Forth_(programming_language) UCSD Pascal http://wiki.freepascal.org/UCSD_Pascal +p-code https://www.princeton.edu/~achaney/tmve/wiki100k/docs/P-code_machine.html + + + From ba37d7f3ef0023c47be360fae73550dbadcc57cf Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Mon, 5 May 2014 13:20:16 -0700 Subject: [PATCH 30/44] Update README.md --- PLASMA/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index c4969068..790216cb 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -357,7 +357,7 @@ memset(val16, addr, len) will fill memory with a 16 bit value. memcpy(dstaddr, The original design concept was to create an efficient, flexible, and expressive environment for building applications directly on the Apple II. Choosing a stack based architecture was easy after much experience with other stack based implementations. It also makes the compiler simple to implement. The first take on the stack architecture was to make it a very strict stack architecture in that everything had to be on the stack. The only opcode with operands was the CONSTANT opcode. This allowed for a very small bytecode interpreter and a very easy compile target. However, only when adding an opcode with operands that would greatly improved performance, native code generation or code size was it done. The opcode table grew slowly over time but still retains a small runtime interpreter with good native code density. ## References -B Programming Language USer Manual http://cm.bell-labs.com/cm/cs/who/dmr/kbman.html +B Programming Language User Manual http://cm.bell-labs.com/cm/cs/who/dmr/kbman.html FORTH http://en.wikipedia.org/wiki/Forth_(programming_language) From 18b41b82bdd26f540ff09919d96b93c4b4906eae Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Mon, 5 May 2014 13:22:12 -0700 Subject: [PATCH 31/44] Update README.md --- PLASMA/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PLASMA/README.md b/PLASMA/README.md index 790216cb..57edfa54 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -365,5 +365,5 @@ UCSD Pascal http://wiki.freepascal.org/UCSD_Pascal p-code https://www.princeton.edu/~achaney/tmve/wiki100k/docs/P-code_machine.html - +VM02: Apple II Java VM http://sourceforge.net/projects/vm02/ From 9efb6468228620a369e266ac90707ba9a4227db9 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Mon, 5 May 2014 13:54:19 -0700 Subject: [PATCH 32/44] Update README.md --- PLASMA/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/PLASMA/README.md b/PLASMA/README.md index 57edfa54..904e0b35 100644 --- a/PLASMA/README.md +++ b/PLASMA/README.md @@ -367,3 +367,4 @@ p-code https://www.princeton.edu/~achaney/tmve/wiki100k/docs/P-code_machine.htm VM02: Apple II Java VM http://sourceforge.net/projects/vm02/ +Threaded code http://en.wikipedia.org/wiki/Threaded_code From 680cdc557afdb4dd05e854e6d537381829a95204 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Mon, 5 May 2014 18:19:51 -0700 Subject: [PATCH 33/44] ACME-ize the VM and bring it up to speed with C model --- PLASMA/src/plvm02.s | 2257 ++++++++++++++++++++++++------------------- 1 file changed, 1242 insertions(+), 1015 deletions(-) diff --git a/PLASMA/src/plvm02.s b/PLASMA/src/plvm02.s index a101f24a..a3e2c823 100644 --- a/PLASMA/src/plvm02.s +++ b/PLASMA/src/plvm02.s @@ -1,11 +1,3 @@ -.PC02 -.DEFINE EQU = -.DEFINE DB .BYTE -.DEFINE DW .WORD -.DEFINE DS .RES -.DEFINE ORG .ORG -.DEFINE STKCHK 1 -.DEFINE TMRCHK 1 ;********************************************************** ;* ;* SYSTEM ROUTINES AND LOCATIONS @@ -14,26 +6,26 @@ ;* ;* MONITOR SPECIAL LOCATIONS AND PRODOS MLI ;* -CSWL EQU $36 -CSWH EQU $37 -PROMPTCHAR EQU $33 -PRODOS EQU $BF00 -MACHID EQU $BF98 +CSWL = $36 +CSWH = $37 +PROMPT = $33 +PRODOS = $BF00 +MACHID = $BF98 ;* ;* HARDWARE ADDRESSES ;* -KEYBD EQU $C000 -CLRKBD EQU $C010 -SPKR EQU $C030 -ROMIN EQU $C081 -LCBNK2 EQU $C083 -LCBNK1 EQU $C08B -ALTZPOFF EQU $C008 -ALTZPON EQU $C009 -ALTRAMRDOFF EQU $C002 -ALTRAMRDON EQU $C003 -ALTRAMWROFF EQU $C004 -ALTRAMWRON EQU $C005 +KEYBD = $C000 +CLRKBD = $C010 +SPKR = $C030 +ROMIN = $C081 +LCBNK2 = $C083 +LCBNK1 = $C08B +ALTZPOFF= $C008 +ALTZPON = $C009 +ALTRDOFF= $C002 +ALTRDON = $C003 +ALTWROFF= $C004 +ALTWRON = $C005 ;* ;* AUXMEM ACCESS MACROS ;* @@ -44,16 +36,16 @@ ALTRAMWRON EQU $C005 .MACRO AUXZP_ACCESS_OFF STA ALTZPOFF ; TURN OFF ALT ZP AND LC .ENDMACRO -.MACRO AUXMEM_RDACCESS_ON +.MACRO AUXMEM_RDON STA ALTRAMRDON .ENDMACRO -.MACRO AUXMEM_RDACCESS_OFF +.MACRO STA ALTRAMRDOFF STA ALTRAMRDOFF .ENDMACRO -.MACRO AUXMEM_WRACCESS_ON +.MACRO AUXMEM_WRON STA ALTRAMWRON .ENDMACRO -.MACRO AUXMEM_WRACCESS_OFF +.MACRO AUXMEM_WROFF STA ALTRAMWROFF .ENDMACRO .ELSE @@ -65,143 +57,54 @@ ALTRAMWRON EQU $C005 STA ALTZPOFF ; TURN OFF ALT ZP AND LC CLI ; TURN INTERRUPTS BACK ON .ENDMACRO -.MACRO AUXMEM_RDACCESS_ON +.MACRO AUXMEM_RDON SEI STA ALTRAMRDON .ENDMACRO -.MACRO AUXMEM_RDACCESS_OFF +.MACRO STA ALTRAMRDOFF STA ALTRAMRDOFF CLI .ENDMACRO -.MACRO AUXMEM_WRACCESS_ON +.MACRO AUXMEM_WRON SEI STA ALTRAMWRON .ENDMACRO -.MACRO AUXMEM_WRACCESS_OFF +.MACRO AUXMEM_WROFF STA ALTRAMWROFF CLI .ENDMACRO .ENDIF -;* -;* SIMPLIFUED ACCESS MACROS -;* -.IF IS65C02 -.MACRO LDA_IPC - LDA (PC) -.ENDMACRO -.MACRO LDA_ITMPL - LDA (TMP) -.ENDMACRO -.MACRO LDA_ITMPH - LDY #$01 - LDA (TMP),Y -.ENDMACRO -.MACRO LDA0 - LDA #$00 -.ENDMACRO -.MACRO STA_ITMPL - STA (TMP) -.ENDMACRO -.MACRO STA_ITMPH - LDY #$01 - STA (TMP),Y -.ENDMACRO -.MACRO ST0 ADDR - STZ ADDR -.ENDMACRO -.MACRO CLRY -.ENDMACRO -.ELSE -.MACRO LDA_IPC - LDA (PC),Y -.ENDMACRO -.MACRO LDA_ITMPL - LDA (TMP),Y -.ENDMACRO -.MACRO LDA_ITMPH - INY - LDA (TMP),Y - DEY -.ENDMACRO -.MACRO LDA0 - TYA -.ENDMACRO -.MACRO STA_ITMPL - STA (TMP),Y -.ENDMACRO -.MACRO STA_ITMPH - INY - STA (TMP),Y - DEY -.ENDMACRO -.MACRO ST0 ADDR - STY ADDR -.ENDMACRO -.MACRO CLRY - LDY #$00 -.ENDMACRO -.ENDIF - ;********************************************************** ;* ;* VM ZERO PAGE LOCATIONS ;* ;********************************************************** -ESTKSZ EQU $20 -ESTK EQU $C0 -ESTKL EQU ESTK -ESTKH EQU ESTK+ESTKSZ/2 -VMZP EQU ESTK+ESTKSZ -FRMP EQU VMZP+$00 -FRMPL EQU FRMP -FRMPH EQU FRMP+1 -PC EQU VMZP+$02 -PCL EQU PC -PCH EQU PC+1 -TICK EQU VMZP+$04 -ESP EQU VMZP+$05 - -TMP EQU VMZP+$0A -TMPL EQU TMP -TMPH EQU TMP+1 -TMPX EQU TMP+2 -NPARMS EQU TMPL -FRMSZ EQU TMPH -DVSIGN EQU TMPX -JSROP EQU VMZP+$0D - - ORG $D000 -;* -;* OPCODE TABLE -;* -OPTBL: DW ZERO,ADD,SUB,MUL,DIV,DIVMOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E - DW NEG,COMP,BAND,IOR,XOR,SHL,SHR,IDXW ; 10 12 14 16 18 1A 1C 1E - DW NOT,LOR,LAND,LA,LLA,CB,CW,SWAP ; 20 22 24 26 28 2A 2C 2E - DW DROP,DUP,PUSH,PULL,SKPLT,SKPGT,SKPEQ,SKPNE ; 30 32 34 36 38 3A 3C 3E - DW ISEQ,ISNE,ISGT,ISLT,ISGE,ISLE,SKPFLS,SKPTRU ; 40 42 44 46 48 4A 4C 4E - DW SKIP,ISKIP,CALL,ICAL,ENTER,LEAVE,RET,INT ; 50 52 54 56 58 5A 5C 5E - DW LB,LW,LLB,LLW,LAB,LAW,DLB,DLW ; 60 62 64 66 68 6A 6C 6E - DW SB,SW,SLB,SLW,SAB,SAW,DAB,DAW ; 70 72 74 76 78 7A 7C 7E -;* -;* OPXCODE TABLE -;* -OPXTBL: DW ZERO,ADD,SUB,MUL,DIV,DIVMOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E - DW NEG,COMP,BAND,IOR,XOR,SHL,SHR,IDXW ; 10 12 14 16 18 1A 1C 1E - DW NOT,LOR,LAND,LAX,LLAX,CBX,CWX,SWAP ; 20 22 24 26 28 2A 2C 2E - DW DROP,DUP,PUSH,PULL,SKPLTX,SKPGTX,SKPEQX,SKPNEX ; 30 32 34 36 38 3A 3C 3E - DW ISEQ,ISNE,ISGT,ISLT,ISGE,ISLE,SKPFLSX,SKPTRUX ; 40 42 44 46 48 4A 4C 4E - DW SKIPX,ISKIPX,CALLX,ICAL,ENTER,LEAVE,RET,INTX ; 50 52 54 56 58 5A 5C 5E - DW LB,LW,LLBX,LLWX,LABX,LAWX,DLBX,DLWX ; 60 62 64 66 68 6A 6C 6E - DW SB,SW,SLBX,SLWX,SABX,SAWX,DABX,DAWX ; 70 72 74 76 78 7A 7C 7E +ESTKSZ = $20 +ESTK = $C0 +ESTKL = ESTK +ESTKH = ESTK+ESTKSZ/2 +VMZP = ESTK+ESTKSZ +IFP = VMZP +IFPL = IFP +IFPH = IFP+1 +IP = IFP+2 +IPL = IP +IPH = IP+1 +IPY = IP+2 +TMP = IP+3 +TMPL = TMP +TMPH = TMP+1 +TMPX = TMP+2 +NPARMS = TMPL +FRMSZ = TMPH +DVSIGN = TMPX ;* ;* COMMAND LOADER CODE ;* CLD CLV - BVC :+ + BVC + JMP PLASMA -: - .INCLUDE "cmd.byte" ;*********************************************** ;* @@ -210,119 +113,108 @@ OPXTBL: DW ZERO,ADD,SUB,MUL,DIV,DIVMOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E ;*********************************************** ;* ;* INIT AND ENTER INTO PLASMA BYTECODE INTERPRETER -;* X:Y:A = ADDRESS OF INITAL ENTRYPOINT +;* X Y A = ADDRESS OF INITAL ENTRYPOINT ;* -PLASMA: STA PCL +PLASMA STA PCL STY PCH STX TMP CLD LDY #$20 -: LDA PAGE3,Y + LDA PAGE3,Y STA $03D0,Y DEY - BPL :- + BPL - LDX #ESTKSZ/2 - INY ; LDY #$00 - STY TICK - LDA #$6C - STA JSROP - LDA #>OPTBL - STA JSROP+2 + INY ; LDY #$00 LDA TMP BEQ FETCHOP LDA MACHID AND #$30 CMP #$30 BEQ FETCHOPX -_RTS: RTS -_BRK: BRK + + !PSEUDOPC $03D0 { + ;* ;* PAGE 3 VECTORS INTO INTERPRETER ;* -PAGE3: BIT $C080 ; $03D0 - INTERP ENTRY - JMP _INTERP - BIT $C080 ; $03D6 - INTERPX ENTRY - JMP _INTERPX - BIT $C080 ; $03DC - LEAVE ENTRY - JMP _LEAVE - BIT $C080 ; $03E2 - ENTER ENTRY - JMP _ENTER - DW _RTS ; $03E8 - PERIODIC VECTOR - DW _BRK ; $03EA - INT VECTOR -TMRVEC EQU $03E8 -INTVEC EQU $03EA +PAGE3 BIT $C080 ; $03D0 - INTERP ENTRY + JMP INTERP +} + + !PSEUDOPC $D000 { ;* -;* ENTER INTO INLINE BYTECODE +;* OPCODE TABLE ;* -_INTERP: PLA - STA PCL - PLA - STA PCH - LDY #$00 - BEQ NEXTOP -TOCKOP: JSR TICKTOCK -FETCHOP: -.IF TMRCHK - DEC TICK - BEQ TOCKOP -.ENDIF - LDA_IPC - STA JSROP+1 - JSR JSROP -.IF STKCHK - CPX #ESTKSZ/2+1 - BCS STKINT -.ENDIF -NEXTOP: INC PCL - BNE FETCHOP - INC PCH - BNE FETCHOP -STKINT: LDA #$FF -INTJMP: JMP (INTVEC) -TICKTOCK: JMP (TMRVEC) -TMPJMP: JMP (TMP) +OPTBL !WORD ZERO,ADD,SUB,MUL,DIV,DIVMOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E + !WORD NEG,COMP,BAND,IOR,XOR,SHL,SHR,IDXW ; 10 12 14 16 18 1A 1C 1E + !WORD NOT,LOR,LAND,LA,LLA,CB,CW,SWAP ; 20 22 24 26 28 2A 2C 2E + !WORD DROP,DUP,PUSH,PULL,BRLT,BRGT,BREQ,BRNE ; 30 32 34 36 38 3A 3C 3E + !WORD ISEQ,ISNE,ISGT,ISLT,ISGE,ISLE,BRFLS,BRTRU ; 40 42 44 46 48 4A 4C 4E + !WORD BRNCH,IBRNCH,CALL,ICAL,ENTER,LEAVE,RET,NEXTOP ; 50 52 54 56 58 5A 5C 5E + !WORD LB,LW,LLB,LLW,LAB,LAW,DLB,DLW ; 60 62 64 66 68 6A 6C 6E + !WORD SB,SW,SLB,SLW,SAB,SAW,DAB,DAW ; 70 72 74 76 78 7A 7C 7E ;* -;* ENTER INTO EXTERNAL BYTECODE +;* ENTER INTO BYTECODE INTERPRETER ;* -_INTERPX: PLA +INTERP PLA STA TMPL PLA STA TMPH - LDY #$01 + LDY #$03 LDA (TMP),Y - STA PCL - INY + STA IPH + DEY LDA (TMP),Y - STA PCH - INY + STA IPL + DEY LDA (TMP),Y TAY - BNE FETCHOPX BEQ FETCHOP -TOCKOPX: JSR TICKTOCK -FETCHOPX: -.IF TMRCHK - DEC TICK - BEQ TOCKOPX -.ENDIF - AUXMEM_RDACCESS_ON - LDA_IPC - AUXMEM_RDACCESS_OFF - ORA #$80 ; SELECT OPX CODES - STA JSROP+1 - JSR JSROP -.IF STKCHK - CPX #ESTKSZ/2+1 - BCS STKINT -.ENDIF -NEXTOPX: INC PCL + LDY #$00 + BEQ FETCHOPX +;* +;* INTERP BYTECODE IN MAIN MEM +;* +FETCHOP LDA (IP),Y + STA *+5 + JMP (OPTBL) +NEXTOP INY + BNE FETCHOP + INC IPH + BNE FETCHOP +;* +;* INTERP BYTECODE IN AUX MEM +;* +FETCHOPX SEI + STA ALTRAMRDON + LDA (IP),Y + STA *+5 + JMP (OPTBLX) +NEXTOPX CLI + INY BNE FETCHOPX - INC PCH + INC IPH BNE FETCHOPX ;* +;* ALIGN TO NEXT PAGE +;* + !FILL 255 +;* +;* OPXCODE TABLE +;* +OPXTBL !WORD ZEROX,ADDX,SUBX,MULX,DIVX,MODX,INCRX,DECRX ; 00 02 04 06 08 0A 0C 0E + !WORD NEGX,COMPX,BANDX,IORX,XORX,SHLX,SHRX,IDXWX ; 10 12 14 16 18 1A 1C 1E + !WORD NOTX,LORX,LANDX,LAX,LLAX,CBX,CWX,SWAPX ; 20 22 24 26 28 2A 2C 2E + !WORD DROPX,DUPX,PUSHX,PULLX,BRLTX,BRGTX,BREQX,BRNEX ; 30 32 34 36 38 3A 3C 3E + !WORD ISEQX,ISNEX,ISGTX,ISLTX,ISGEX,ISLEX,BRFLSX,BRTRUX; 40 42 44 46 48 4A 4C 4E + !WORD BRNCHX,IBRNCHX,CALLX,ICALX,ENTERX,LEAVEX,RETX,NEXTOPX; 50 52 54 56 58 5A 5C 5E + !WORD LBX,LWX,LLBX,LLWX,LABX,LAWX,DLBX,DLWX ; 60 62 64 66 68 6A 6C 6E + !WORD SBX,SWX,SLBX,SLWX,SABX,SAWX,DABX,DAWX ; 70 72 74 76 78 7A 7C 7E +;* ;* ADD TOS TO TOS-1 ;* -ADD: LDA ESTKL,X +ADD LDA ESTKL,X CLC ADC ESTKL+1,X STA ESTKL+1,X @@ -330,11 +222,21 @@ ADD: LDA ESTKL,X ADC ESTKH+1,X STA ESTKH+1,X INX - RTS + JMP NEXTOP +; +ADDX LDA ESTKL,X + CLC + ADC ESTKL+1,X + STA ESTKL+1,X + LDA ESTKH,X + ADC ESTKH+1,X + STA ESTKH+1,X + INX + JMP NEXTOPX ;* ;* SUB TOS FROM TOS-1 ;* -SUB: LDA ESTKL+1,X +SUB LDA ESTKL+1,X SEC SBC ESTKL,X STA ESTKL+1,X @@ -342,11 +244,21 @@ SUB: LDA ESTKL+1,X SBC ESTKH,X STA ESTKH+1,X INX - RTS + JMP NEXTOP +; +SUBX LDA ESTKL+1,X + SEC + SBC ESTKL,X + STA ESTKL+1,X + LDA ESTKH+1,X + SBC ESTKH,X + STA ESTKH+1,X + INX + JMP NEXTOPX ;* ;* SHIFT TOS-1 LEFT BY 1, ADD TO TOS-1 ;* -IDXW: LDA ESTKL,X +IDXW LDA ESTKL,X ASL ROL ESTKH,X CLC @@ -356,14 +268,28 @@ IDXW: LDA ESTKL,X ADC ESTKH+1,X STA ESTKH+1,X INX - RTS + JMP NEXTOP +; +IDXWX LDA ESTKL,X + ASL + ROL ESTKH,X + CLC + ADC ESTKL+1,X + STA ESTKL+1,X + LDA ESTKH,X + ADC ESTKH+1,X + STA ESTKH+1,X + INX + JMP NEXTOPX ;* -;* MUL TOS-1 BY TOS +;* INTERNAL MULTIPLY ALGORITHM ;* -MUL: ST0 TMPL ; PRODL - ST0 TMPH ; PRODH +_MUL STY IPY + LDY #$00 + STY TMPL ; PRODL + STY TMPH ; PRODH LDY #$10 -MUL1: LSR ESTKH,X ; MULTPLRH +MUL1 LSR ESTKH,X ; MULTPLRH ROR ESTKL,X ; MULTPLRL BCC MUL2 LDA ESTKL+1,X ; MULTPLNDL @@ -373,7 +299,7 @@ MUL1: LSR ESTKH,X ; MULTPLRH LDA ESTKH+1,X ; MULTPLNDH ADC TMPH ; PRODH STA TMPH -MUL2: ASL ESTKL+1,X ; MULTPLNDL +MUL2 ASL ESTKL+1,X ; MULTPLNDL ROL ESTKH+1,X ; MULTPLNDH DEY BNE MUL1 @@ -382,38 +308,56 @@ MUL2: ASL ESTKL+1,X ; MULTPLNDL STA ESTKL,X LDA TMPH ; PRODH STA ESTKH,X + LDY IPY RTS ;* +;* MUL TOS-1 BY TOS +;* +MUL JSR _MUL + JMP NEXTOP +; +MULX JSR _MUL + JMP NEXTOPX +;* ;* INTERNAL DIVIDE ALGORITHM ;* -_DIV: LDA ESTKH,X +_NEG LDA #$00 + SEC + SBC ESTKL,X + STA ESTKL,X + LDA #$00 + SBC ESTKH,X + STA ESTKH,X + RTS +_DIV STY IPY + LDA ESTKH,X AND #$80 STA DVSIGN BPL _DIV1 - JSR NEG + JSR _NEG INC DVSIGN -_DIV1: LDA ESTKH+1,X +_DIV1 LDA ESTKH+1,X BPL _DIV2 INX - JSR NEG + JSR _NEG DEX INC DVSIGN BNE _DIV3 -_DIV2: ORA ESTKL+1,X ; DVDNDL +_DIV2 ORA ESTKL+1,X ; DVDNDL BNE _DIV3 STA TMPL STA TMPH RTS -_DIV3: LDY #$11 ; #BITS+1 +_DIV3 LDY #$11 ; #BITS+1 LDA #$00 STA TMPL ; REMNDRL STA TMPH ; REMNDRH -_DIV4: ASL ESTKL+1,X ; DVDNDL +_DIV4 ASL ESTKL+1,X ; DVDNDL ROL ESTKH+1,X ; DVDNDH DEY BCC _DIV4 STY ESTKL-1,X -_DIV5: ROL TMPL ; REMNDRL +_DIV5 ROL TMPL ; REMNDRL ROL TMPH ; REMNDRH LDA TMPL ; REMNDRL SEC @@ -424,110 +368,177 @@ _DIV5: ROL TMPL ; REMNDRL BCC _DIV6 STA TMPH ; REMNDRH STY TMPL ; REMNDRL -_DIV6: ROL ESTKL+1,X ; DVDNDL +_DIV6 ROL ESTKL+1,X ; DVDNDL ROL ESTKH+1,X ; DVDNDH DEC ESTKL-1,X BNE _DIV5 - CLRY - RTS -;* -;* DIV TOS-1 BY TOS -;* -DIV: JSR _DIV - INX - LSR DVSIGN ; SIGN(RESULT) = (SIGN(DIVIDEND) + SIGN(DIVISOR)) & 1 - BCS NEG + LDY IPY RTS ;* ;* NEGATE TOS ;* -NEG: LDA0 +NEG LDA #$00 SEC SBC ESTKL,X STA ESTKL,X - LDA0 + LDA #$00 SBC ESTKH,X STA ESTKH,X - RTS + JMP NEXTOP +; +NEGX LDA #$00 + SEC + SBC ESTKL,X + STA ESTKL,X + LDA #$00 + SBC ESTKH,X + STA ESTKH,X + JMP NEXTOPX ;* -;* DIV,MOD TOS-1 BY TOS +;* DIV TOS-1 BY TOS ;* -DIVMOD: JSR _DIV +DIV JSR _DIV + INX + LSR DVSIGN ; SIGN(RESULT) = (SIGN(DIVIDEND) + SIGN(DIVISOR)) & 1 + BCS NEG + JMP NEXTOP +; +DIVX JSR _DIV + INX + LSR DVSIGN ; SIGN(RESULT) = (SIGN(DIVIDEND) + SIGN(DIVISOR)) & 1 + BCS NEGX + JMP NEXTOPX +;* +;* MOD TOS-1 BY TOS +;* +MOD JSR _DIV + INX LDA TMPL ; REMNDRL STA ESTKL,X LDA TMPH ; REMNDRH STA ESTKH,X LDA DVSIGN ; REMAINDER IS SIGN OF DIVIDEND - BPL DIVMOD1 - JSR NEG -DIVMOD1: LSR DVSIGN - BCC DIVMOD2 ; DIV RESULT TOS-1 + BMI NEG + JMP NEXTOP +; +MODX JSR _DIV INX - JSR NEG - DEX -DIVMOD2: RTS + LDA TMPL ; REMNDRL + STA ESTKL,X + LDA TMPH ; REMNDRH + STA ESTKH,X + LDA DVSIGN ; REMAINDER IS SIGN OF DIVIDEND + BMI NEGX + JMP NEXTOPX ;* ;* INCREMENT TOS ;* -INCR: INC ESTKL,X +INCR INC ESTKL,X BNE INCR1 INC ESTKH,X -INCR1: RTS +INCR1 JMP NEXTOP +; +INCRX INC ESTKL,X + BNE INCRX1 + INC ESTKH,X +INCRX1 JMP NEXTOPX ;* ;* DECREMENT TOS ;* -DECR: LDA ESTKL,X +DECR LDA ESTKL,X BNE DECR1 DEC ESTKH,X -DECR1: DEC ESTKL,X - RTS +DECR1 DEC ESTKL,X + JMP NEXTOP +; +DECRX LDA ESTKL,X + BNE DECRX1 + DEC ESTKH,X +DECRX1 DEC ESTKL,X + JMP NEXTOPX ;* ;* BITWISE COMPLIMENT TOS ;* -COMP: LDA #$FF +COMP LDA #$FF EOR ESTKL,X STA ESTKL,X LDA #$FF EOR ESTKH,X STA ESTKH,X - RTS + JMP NEXTOP +; +COMPX LDA #$FF + EOR ESTKL,X + STA ESTKL,X + LDA #$FF + EOR ESTKH,X + STA ESTKH,X + JMP NEXTOPX ;* ;* BITWISE AND TOS TO TOS-1 ;* -BAND: LDA ESTKL+1,X +BAND LDA ESTKL+1,X AND ESTKL,X STA ESTKL+1,X LDA ESTKH+1,X AND ESTKH,X STA ESTKH+1,X INX - RTS + JMP NEXTOP +; +BANDX LDA ESTKL+1,X + AND ESTKL,X + STA ESTKL+1,X + LDA ESTKH+1,X + AND ESTKH,X + STA ESTKH+1,X + INX + JMP NEXTOPX ;* ;* INCLUSIVE OR TOS TO TOS-1 ;* -IOR: LDA ESTKL+1,X +IOR LDA ESTKL+1,X ORA ESTKL,X STA ESTKL+1,X LDA ESTKH+1,X ORA ESTKH,X STA ESTKH+1,X INX - RTS + JMP NEXTOP +; +IORX LDA ESTKL+1,X + ORA ESTKL,X + STA ESTKL+1,X + LDA ESTKH+1,X + ORA ESTKH,X + STA ESTKH+1,X + INX + JMP NEXTOPX ;* ;* EXLUSIVE OR TOS TO TOS-1 ;* -XOR: LDA ESTKL+1,X +XOR LDA ESTKL+1,X EOR ESTKL,X STA ESTKL+1,X LDA ESTKH+1,X EOR ESTKH,X STA ESTKH+1,X INX - RTS + JMP NEXTOP +; +XORX LDA ESTKL+1,X + EOR ESTKL,X + STA ESTKL+1,X + LDA ESTKH+1,X + EOR ESTKH,X + STA ESTKH+1,X + INX + NEXTOPX ;* ;* SHIFT TOS-1 LEFT BY TOS ;* -SHL: LDA ESTKL,X +SHL STY IPY + LDA ESTKL,X CMP #$08 BCC SHL1 LDY ESTKL+1,X @@ -535,18 +546,39 @@ SHL: LDA ESTKL,X LDY #$00 STY ESTKL+1,X SBC #$08 -SHL1: TAY +SHL1 TAY BEQ SHL3 -SHL2: ASL ESTKL+1,X +SHL2 ASL ESTKL+1,X ROL ESTKH+1,X DEY BNE SHL2 -SHL3: INX - RTS +SHL3 INX + LDY IPY + NEXTOP +; +SHLX STY IPY + LDA ESTKL,X + CMP #$08 + BCC SHLX1 + LDY ESTKL+1,X + STY ESTKH+1,X + LDY #$00 + STY ESTKL+1,X + SBC #$08 +SHLX1 TAY + BEQ SHLX3 +SHLX2 ASL ESTKL+1,X + ROL ESTKH+1,X + DEY + BNE SHLX2 +SHLX3 INX + LDY IPY + NEXTOPX ;* ;* SHIFT TOS-1 RIGHT BY TOS ;* -SHR: LDA ESTKL,X +SHR STY IPY + LDA ESTKL,X CMP #$08 BCC SHR2 LDY ESTKH+1,X @@ -555,67 +587,122 @@ SHR: LDA ESTKL,X LDY #$00 BCC SHR1 DEY -SHR1: STY ESTKH+1,X +SHR1 STY ESTKH+1,X SEC SBC #$08 -SHR2: TAY +SHR2 TAY BEQ SHR4 LDA ESTKH+1,X -SHR3: CMP #$80 +SHR3 CMP #$80 ROR ROR ESTKL+1,X DEY BNE SHR3 STA ESTKH+1,X -SHR4: INX - RTS +SHR4 INX + LDY IPY + JMP NEXTOP +; +SHRX STY IPY + LDA ESTKL,X + CMP #$08 + BCC SHRX2 + LDY ESTKH+1,X + STY ESTKL+1,X + CPY #$80 + LDY #$00 + BCC SHRX1 + DEY +SHRX1 STY ESTKH+1,X + SEC + SBC #$08 +SHRX2 TAY + BEQ SHRX4 + LDA ESTKH+1,X +SHRX3 CMP #$80 + ROR + ROR ESTKL+1,X + DEY + BNE SHRX3 + STA ESTKH+1,X +SHRX4 INX + LDY IPY + JMP NEXTOPX ;* ;* LOGICAL NOT ;* -NOT: LDA ESTKL,X +NOT LDA ESTKL,X ORA ESTKH,X - BNE NOT1 + BEQ NOT1 LDA #$FF +NOT1 EOR #$FF STA ESTKL,X STA ESTKH,X - RTS -NOT1: ST0 {ESTKL,X} - ST0 {ESTKH,X} - RTS + JMP NEXTOP +; +NOTX LDA ESTKL,X + ORA ESTKH,X + BEQ NOTX1 + LDA #$FF +NOTX1 EOR #$FF + STA ESTKL,X + STA ESTKH,X + JMP NEXTOPX ;* ;* LOGICAL AND ;* -LAND: LDA ESTKL,X +LAND LDA ESTKL,X ORA ESTKH,X BEQ LAND1 LDA ESTKL+1,X ORA ESTKH+1,X BEQ LAND1 LDA #$FF -LAND1: STA ESTKL+1,X +LAND1 STA ESTKL+1,X STA ESTKH+1,X INX - RTS + JMP NEXTOP +; +LANDX LDA ESTKL,X + ORA ESTKH,X + BEQ LANDX1 + LDA ESTKL+1,X + ORA ESTKH+1,X + BEQ LANDX1 + LDA #$FF +LANDX1 STA ESTKL+1,X + STA ESTKH+1,X + INX + JMP NEXTOPX ;* -;* LOGICAL OR +;* LOGICAL OR & DROP TOS ;* -LOR: LDA ESTKL,X +LOR LDA ESTKL,X ORA ESTKH,X ORA ESTKL+1,X ORA ESTKH+1,X BEQ LOR1 LDA #$FF -LOR1: STA ESTKL+1,X +LOR1 STA ESTKL+1,X STA ESTKH+1,X -;* -;* DROP TOS -;* -DROP: INX - RTS +DROP INX + JMP NEXTOP +; +LORX LDA ESTKL,X + ORA ESTKH,X + ORA ESTKL+1,X + ORA ESTKH+1,X + BEQ LORX1 + LDA #$FF +LORX1 STA ESTKL+1,X + STA ESTKH+1,X +DROPX INX + JMP NEXTOPX ;* ;* SWAP TOS WITH TOS-1 ;* -SWAP: LDA ESTKL,X +SWAP STY IPY + LDA ESTKL,X LDY ESTKL+1,X STA ESTKL+1,X STY ESTKL,X @@ -623,218 +710,390 @@ SWAP: LDA ESTKL,X LDY ESTKH+1,X STA ESTKH+1,X STY ESTKH,X - CLRY - RTS + LDY IPY + JMP NEXTOP +; +SWAPX STY IPY + LDA ESTKL,X + LDY ESTKL+1,X + STA ESTKL+1,X + STY ESTKL,X + LDA ESTKH,X + LDY ESTKH+1,X + STA ESTKH+1,X + STY ESTKH,X + LDY IPY + JMP NEXTOPX ;* ;* DUPLICATE TOS ;* -DUP: DEX +DUP DEX LDA ESTKL+1,X STA ESTKL,X LDA ESTKH+1,X STA ESTKH,X - RTS + JMP NEXTOP +; +DUPX DEX + LDA ESTKL+1,X + STA ESTKL,X + LDA ESTKH+1,X + STA ESTKH,X + JMP NEXTOPX + ;* ;* PUSH FROM EVAL STACK TO CALL STACK ;* -PUSH: PLA - STA TMPH - PLA - STA TMPL - LDA ESTKL,X +PUSH LDA ESTKL,X PHA LDA ESTKH,X PHA INX - LDA TMPL + JMP NEXTOP +; +PUSHX LDA ESTKL,X PHA - LDA TMPH + LDA ESTKH,X PHA - RTS + INX + JMP NEXTOPX ;* ;* PULL FROM CALL STACK TO EVAL STACK ;* -PULL: PLA - STA TMPH - PLA - STA TMPL - DEX +PULL DEX PLA STA ESTKH,X PLA STA ESTKL,X - LDA TMPL - PHA - LDA TMPH - PHA - RTS + JMP NEXTOP +; +PULLX DEX + PLA + STA ESTKH,X + PLA + STA ESTKL,X + JMP NEXTOPX ;* ;* CONSTANT ;* -ZERO: DEX - ST0 {ESTKL,X} - ST0 {ESTKH,X} - RTS -CB: DEX - INC PCL - BNE CB1 - INC PCH -CB1: LDA_IPC +ZERO DEX + LDA #$00 STA ESTKL,X - ST0 {ESTKH,X} - RTS -;* -;* LOAD ADDRESS - CHECK FOR DATA OR CODE SPACE -;* -LA: -CW: DEX - INC PCL - BNE CW1 - INC PCH -CW1: LDA_IPC - STA ESTKL,X - INC PCL - BNE CW2 - INC PCH -CW2: LDA_IPC STA ESTKH,X - RTS + JMP NEXTOP +CB DEX + INC_IP + LDA (IP),Y + STA ESTKL,X + LDA #$00 + STA ESTKH,X + JMP NEXTOP +; +ZEROX DEX + LDA #$00 + STA ESTKL,X + STA ESTKH,X + JMP NEXTOPX +CBX DEX + INC_IP + LDA (IP),Y + STA ESTKL,X + LDA #$00 + STA ESTKH,X + JMP NEXTOPX +;* +;* LOAD ADDRESS & LOAD CONSTANT WORD (SAME THING, WITH OR WITHOUT FIXUP) +;* +LA +CW DEX + INC_IP + LDA (IP),Y + STA ESTKL,X + INC_IP + LDA (IP),Y + STA ESTKH,X + JMP NEXTOP +; +LAX +CWX DEX + INC_IP + LDA (IP),Y + STA ESTKL,X + INC_IP + LDA (IP),Y + STA ESTKH,X + JMP NEXTOPX ;* ;* LOAD VALUE FROM ADDRESS TAG ;* -LB: LDA ESTKL,X +LB LDA ESTKL,X STA TMPL LDA ESTKH,X STA TMPH - LDA_ITMPL + STY IPY + LDY #$00 + LDA (TMP),Y STA ESTKL,X - ST0 {ESTKH,X} - RTS -LW: LDA ESTKL,X + STY ESTKH,X + LDY IPY + JMP NEXTOP +LW LDA ESTKL,X STA TMPL LDA ESTKH,X STA TMPH - LDA_ITMPL + STY IPY + LDY #$00 + LDA (TMP),Y STA ESTKL,X - LDA_ITMPH + INY + LDA (TMP),Y STA ESTKH,X - RTS + LDY IPY + JMP NEXTOP +; +LBX STA ALTRAMRDOFF + LDA ESTKL,X + STA TMPL + LDA ESTKH,X + STA TMPH + STY IPY + LDY #$00 + LDA (TMP),Y + STA ESTKL,X + STY ESTKH,X + LDY IPY + JMP NEXTOPX +LWX STA ALTRAMRDOFF + LDA ESTKL,X + STA TMPL + LDA ESTKH,X + STA TMPH + STY IPY + LDY #$00 + LDA (TMP),Y + STA ESTKL,X + INY + LDA (TMP),Y + STA ESTKH,X + LDY IPY + JMP NEXTOPX ;* ;* LOAD ADDRESS OF LOCAL FRAME OFFSET ;* -LLA: INC PCL - BNE LLA1 - INC PCH -LLA1: LDA_IPC +LLA INC_IP + LDA (IP),Y DEX CLC - ADC FRMPL + ADC IFPL STA ESTKL,X - LDA0 - ADC FRMPH + LDA #$00 + ADC IFPH STA ESTKH,X - RTS + JMP NEXTOP +; +LLAX INC_IP + LDA (IP),Y + DEX + CLC + ADC IFPL + STA ESTKL,X + LDA #$00 + ADC IFPH + STA ESTKH,X + JMP NEXTOPX ;* ;* LOAD VALUE FROM LOCAL FRAME OFFSET ;* -LLB: INC PCL - BNE LLB1 - INC PCH -LLB1: LDA_IPC +LLB INC_IP + LDA (IP),Y + STY IPY TAY DEX - LDA (FRMP),Y + LDA (IFP),Y STA ESTKL,X - CLRY - ST0 {ESTKH,X} - RTS -LLW: INC PCL - BNE LLW1 - INC PCH -LLW1: LDA_IPC + LDA #$00 + STA ESTKH,X + LDY IPY + JMP NEXTOP +LLW INC_IP + LDA (IP),Y + STY IPY TAY DEX - LDA (FRMP),Y + LDA (IFP),Y STA ESTKL,X INY - LDA (FRMP),Y + LDA (IFP),Y STA ESTKH,X - CLRY - RTS + LDY IPY + JMP NEXTOP +; +LLBX INC_IP + LDA (IP),Y + STY IPY + TAY + DEX + STA ALTRAMRDOFF + LDA (IFP),Y + STA ESTKL,X + LDA #$00 + STA ESTKH,X + LDY IPY + JMP NEXTOP +LLWX INC_IP + LDA (IP),Y + STY IPY + TAY + DEX + STA ALTRAMRDOFF + LDA (IFP),Y + STA ESTKL,X + INY + LDA (IFP),Y + STA ESTKH,X + LDY IPY + JMP NEXTOP ;* ;* LOAD VALUE FROM ABSOLUTE ADDRESS ;* -LAB: INC PCL - BNE LAB1 - INC PCH -LAB1: LDA_IPC +LAB INC_IP + LDA (IP),Y STA TMPL - INC PCL - BNE LAB2 - INC PCH -LAB2: LDA_IPC + INC_IP + LDA (IP),Y STA TMPH - LDA_ITMPL + STY IPY + LDY #$00 + LDA (TMP),Y DEX STA ESTKL,X - ST0 {ESTKH,X} - RTS -LAW: INC PCL - BNE LAW1 - INC PCH -LAW1: LDA_IPC + STY ESTKH,X + LDY IPY + JMP NEXTOP +LAW INC_IP + LDA (IP),Y STA TMPL - INC PCL - BNE LAW2 - INC PCH -LAW2: LDA_IPC + INC_IP + LDA (IP),Y STA TMPH - LDA_ITMPL + STY IPY + LDY #$00 + LDA (TMP),Y DEX STA ESTKL,X - LDA_ITMPH + INY + LDA (TMP),Y STA ESTKH,X - RTS + LDY IPY + JMP NEXTOP +; +LABX INC_IP + LDA (IP),Y + STA TMPL + INC_IP + LDA (IP),Y + STA TMPH + STY IPY + STA ALTRAMRDOFF + LDY #$00 + LDA (TMP),Y + DEX + STA ESTKL,X + STY ESTKH,X + LDY IPY + JMP NEXTOPX +LAWX INC_IP + LDA (IP),Y + STA TMPL + INC_IP + LDA (IP),Y + STA TMPH + STY IPY + STA ALTRAMRDOFF + LDY #$00 + LDA (TMP),Y + DEX + STA ESTKL,X + INY + LDA (TMP),Y + STA ESTKH,X + LDY IPY + JMP NEXTOPX ;* ;* STORE VALUE TO ADDRESS ;* -SB: LDA ESTKL+1,X +SB LDA ESTKL+1,X STA TMPL LDA ESTKH+1,X STA TMPH LDA ESTKL,X - STA_ITMPL + STY IPY + LDY #$00 + STA (TMP),Y INX INX - RTS -SW: LDA ESTKL+1,X + LDY IPY + JMP NEXTOP +SW LDA ESTKL+1,X STA TMPL LDA ESTKH+1,X STA TMPH + STY IPY + LDY #$00 LDA ESTKL,X - STA_ITMPL + STA (TMP),Y + INY LDA ESTKH,X - STA_ITMPH + STA (TMP),Y INX INX - RTS + LDY IPY + JMP NEXTOP +; +SBX LDA ESTKL+1,X + STA TMPL + LDA ESTKH+1,X + STA TMPH + LDA ESTKL,X + STY IPY + STA ALTRAMRDOFF + LDY #$00 + STA (TMP),Y + INX + INX + LDY IPY + JMP NEXTOPX +SWX LDA ESTKL+1,X + STA TMPL + LDA ESTKH+1,X + STA TMPH + STY IPY + STA ALTRAMRDOFF + LDY #$00 + LDA ESTKL,X + STA (TMP),Y + INY + LDA ESTKH,X + STA (TMP),Y + INX + INX + LDY IPY + JMP NEXTOPX ;* ;* STORE VALUE TO LOCAL FRAME OFFSET ;* -SLB: INC PCL - BNE SLB1 - INC PCH -SLB1: LDA_IPC +SLB INC_IP + LDA (IP),Y + STY IPY TAY LDA ESTKL,X - STA (FRMP),Y + STA (IFP),Y INX - CLRY - RTS -SLW: INC PCL - BNE SLW1 - INC PCH -SLW1: LDA_IPC + LDY IPY + JMP NEXTOP +SLW INC_IP + LDA (IP),Y + STY IPY TAY LDA ESTKL,X STA (FRMP),Y @@ -842,103 +1101,205 @@ SLW1: LDA_IPC LDA ESTKH,X STA (FRMP),Y INX - CLRY - RTS + LDY IPY + JMP NEXTOP +; +SLBX INC_IP + LDA (IP),Y + STY IPY + STA ALTRAMRDOFF + TAY + LDA ESTKL,X + STA (IFP),Y + INX + LDY IPY + JMP NEXTOPX +SLWX INC_IP + LDA (IP),Y + STY IPY + STA ALTRAMRDOFF + TAY + LDA ESTKL,X + STA (FRMP),Y + INY + LDA ESTKH,X + STA (FRMP),Y + INX + LDY IPY + JMP NEXTOPX ;* ;* STORE VALUE TO LOCAL FRAME OFFSET WITHOUT POPPING STACK ;* -DLB: INC PCL - BNE DLB1 - INC PCH -DLB1: LDA_IPC +DLB INC_IP + LDA (IP),Y + STY IPY TAY LDA ESTKL,X - STA (FRMP),Y - CLRY - RTS -DLW: INC PCL - BNE DLW1 - INC PCH -DLW1: LDA_IPC + STA (IFP),Y + LDY IPY + JMP NEXTOP +DLW INC_IP + LDA (IP),Y + STY IPY TAY LDA ESTKL,X - STA (FRMP),Y + STA (IFP),Y INY LDA ESTKH,X - STA (FRMP),Y - CLRY - RTS + STA (IFP),Y + LDY IPY + JMP NEXTOP +; +DLBX INC_IP + LDA (IP),Y + STY IPY + STA ALTRAMRDOFF + TAY + LDA ESTKL,X + STA (IFP),Y + LDY IPY + JMP NEXTOPX +DLWX INC_IP + LDA (IP),Y + STY IPY + STA ALTRAMRDOFF + TAY + LDA ESTKL,X + STA (IFP),Y + INY + LDA ESTKH,X + STA (IFP),Y + LDY IPY + JMP NEXTOPX ;* ;* STORE VALUE TO ABSOLUTE ADDRESS ;* -SAB: INC PCL - BNE SAB1 - INC PCH -SAB1: LDA_IPC +SAB INC_IP + LDA (IP),Y STA TMPL - INC PCL - BNE SAB2 - INC PCH -SAB2: LDA_IPC + INC_IP + LDA (IP),Y STA TMPH LDA ESTKL,X - STA_ITMPL + STY IPY + LDY #$00 + STA (TMP),Y INX - RTS -SAW: INC PCL - BNE SAW1 - INC PCH -SAW1: LDA_IPC + LDY IPY + JMP NEXTOP +SAW INC_IP + LDA (IP),Y STA TMPL - INC PCL - BNE SAW2 - INC PCH -SAW2: LDA_IPC + INC_IP + LDA (IP),Y STA TMPH + STY IPY + LDY #$00 LDA ESTKL,X - STA_ITMPL + STA (TMP),Y + INY LDA ESTKH,X - STA_ITMPH + STA (TMP),Y INX - RTS + LDY IPY + JMP NEXTOP +; +SABX INC_IP + LDA (IP),Y + STA TMPL + INC_IP + LDA (IP),Y + STA TMPH + LDA ESTKL,X + STY IPY + STA ALTRAMRDOFF + LDY #$00 + STA (TMP),Y + INX + LDY IPY + JMP NEXTOPX +SAWX INC_IP + LDA (IP),Y + STA TMPL + INC_IP + LDA (IP),Y + STA TMPH + STY IPY + STA ALTRAMRDOFF + LDY #$00 + LDA ESTKL,X + STA (TMP),Y + INY + LDA ESTKH,X + STA (TMP),Y + INX + LDY IPY + JMP NEXTOPX ;* ;* STORE VALUE TO ABSOLUTE ADDRESS WITHOUT POPPING STACK ;* -DAB: INC PCL - BNE DAB1 - INC PCH -DAB1: LDA_IPC +DAB INC_IP + LDA (IP),Y STA TMPL - INC PCL - BNE DAB2 - INC PCH -DAB2: LDA_IPC + INC_IP + LDA (IP),Y STA TMPH + STY IPY + LDY #$00 LDA ESTKL,X - STA_ITMPL - RTS -DAW: INC PCL - BNE DAW1 - INC PCH -DAW1: LDA_IPC + STA (TMP),Y + LDY IPY + JMP NEXTOP +DAW INC_IP + LDA (IP),Y STA TMPL - INC PCL - BNE DAW2 - INC PCH -DAW2: LDA_IPC + INC_IP + LDA (IP),Y STA TMPH + STY IPY + LDY #$00 LDA ESTKL,X - STA_ITMPL + STA (TMP),Y + INY LDA ESTKH,X - STA_ITMPH - RTS + STA (TMP),Y + LDY IPY + JMP NEXTOP +; +DABX INC_IP + LDA (IP),Y + STA TMPL + INC_IP + LDA (IP),Y + STA TMPH + STY IPY + STA ALTRAMRDOFF + LDY #$00 + LDA ESTKL,X + STA (TMP),Y + LDY IPY + JMP NEXTOPX +DAWX INC_IP + LDA (IP),Y + STA TMPL + INC_IP + LDA (IP),Y + STA TMPH + STY IPY + STA ALTRAMRDOFF + LDY #$00 + LDA ESTKL,X + STA (TMP),Y + INY + LDA ESTKH,X + STA (TMP),Y + LDY IPY + JMP NEXTOPX ;* ;* COMPARES ;* -ISEQ: -.IF IS65C02 +ISEQ STY IPY LDY #$00 -.ENDIF LDA ESTKL,X CMP ESTKL+1,X BNE ISEQ1 @@ -946,17 +1307,29 @@ ISEQ: CMP ESTKH+1,X BNE ISEQ1 DEY -ISEQ1: STY ESTKL+1,X +ISEQ1 STY ESTKL+1,X STY ESTKH+1,X INX - CLRY - RTS -ISNE: -.IF IS65C02 + LDY IPY + JMP NEXTOP +; +ISEQX STY IPY + LDY #$00 + LDA ESTKL,X + CMP ESTKL+1,X + BNE ISEQ1 + LDA ESTKH,X + CMP ESTKH+1,X + BNE ISEQX1 + DEY +ISEQX1 STY ESTKL+1,X + STY ESTKH+1,X + INX + LDY IPY + JMP NEXTOPX +; +ISNE STY IPY LDY #$FF -.ELSE - DEY ; LDY #$FF -.ENDIF LDA ESTKL,X CMP ESTKL+1,X BNE ISNE1 @@ -964,649 +1337,503 @@ ISNE: CMP ESTKH+1,X BNE ISNE1 INY -ISNE1: STY ESTKL+1,X +ISNE1 STY ESTKL+1,X STY ESTKH+1,X INX - CLRY - RTS -ISGE: -.IF IS65C02 + LDY IPY + JMP NEXTOP +; +ISNEX STY IPY + LDY #$FF + LDA ESTKL,X + CMP ESTKL+1,X + BNE ISNE1 + LDA ESTKH,X + CMP ESTKH+1,X + BNE ISNEX1 + INY +ISNEX1 STY ESTKL+1,X + STY ESTKH+1,X + INX + LDY IPY + JMP NEXTOPX +; +ISGE STY IPY LDY #$00 -.ELSE - ; LDY #$00 -.ENDIF LDA ESTKL+1,X CMP ESTKL,X LDA ESTKH+1,X SBC ESTKH,X BVC ISGE1 EOR #$80 -ISGE1: BMI ISGE2 +ISGE1 BMI ISGE2 DEY -ISGE2: STY ESTKL+1,X +ISGE2 STY ESTKL+1,X STY ESTKH+1,X INX - CLRY - RTS -ISGT: -.IF IS65C02 + LDY IPY + JMP NEXTOP +; +ISGEX STY IPY + LDY #$00 + LDA ESTKL+1,X + CMP ESTKL,X + LDA ESTKH+1,X + SBC ESTKH,X + BVC ISGEX1 + EOR #$80 +ISGEX1 BMI ISGEX2 + DEY +ISGEX2 STY ESTKL+1,X + STY ESTKH+1,X + INX + LDY IPY + JMP NEXTOPX +; +ISGT STY IPY LDY #$00 -.ELSE - ; LDY #$00 -.ENDIF LDA ESTKL,X CMP ESTKL+1,X LDA ESTKH,X SBC ESTKH+1,X BVC ISGT1 EOR #$80 -ISGT1: BPL ISGT2 +ISGT1 BPL ISGT2 DEY -ISGT2: STY ESTKL+1,X +ISGT2 STY ESTKL+1,X STY ESTKH+1,X INX - CLRY - RTS -ISLE: -.IF IS65C02 + LDY IPY + JMP NEXTOP +; +ISGTX STY IPY + LDY #$00 + LDA ESTKL,X + CMP ESTKL+1,X + LDA ESTKH,X + SBC ESTKH+1,X + BVC ISGTX1 + EOR #$80 +ISGTX1 BPL ISGTX2 + DEY +ISGTX2 STY ESTKL+1,X + STY ESTKH+1,X + INX + LDY IPY + JMP NEXTOPX +; +ISLE STY IPY LDY #$00 -.ELSE - ; LDY #$00 -.ENDIF LDA ESTKL,X CMP ESTKL+1,X LDA ESTKH,X SBC ESTKH+1,X BVC ISLE1 EOR #$80 -ISLE1: BMI ISLE2 +ISLE1 BMI ISLE2 DEY -ISLE2: STY ESTKL+1,X +ISLE2 STY ESTKL+1,X STY ESTKH+1,X INX - CLRY - RTS -ISLT: -.IF IS65C02 + LDY IPY + JMP NEXTOP +; +ISLEX STY IPY + LDY #$00 + LDA ESTKL,X + CMP ESTKL+1,X + LDA ESTKH,X + SBC ESTKH+1,X + BVC ISLEX1 + EOR #$80 +ISLEX1 BMI ISLEX2 + DEY +ISLEX2 STY ESTKL+1,X + STY ESTKH+1,X + INX + LDY IPY + JMP NEXTOPX +; +ISLT STY IPY LDY #$00 -.ELSE - ; LDY #$00 -.ENDIF LDA ESTKL+1,X CMP ESTKL,X LDA ESTKH+1,X SBC ESTKH,X BVC ISLT1 EOR #$80 -ISLT1: BPL ISLT2 +ISLT1 BPL ISLT2 DEY -ISLT2: STY ESTKL+1,X +ISLT2 STY ESTKL+1,X STY ESTKH+1,X INX - CLRY - RTS + LDY IPY + JMP NEXTOP +; +ISLTX STY IPY + LDY #$00 + LDA ESTKL+1,X + CMP ESTKL,X + LDA ESTKH+1,X + SBC ESTKH,X + BVC ISLTX1 + EOR #$80 +ISLTX1 BPL ISLTX2 + DEY +ISLTX2 STY ESTKL+1,X + STY ESTKH+1,X + INX + LDY IPY + JMP NEXTOPX ;* -;* SKIPS +;* BRANCHES ;* -SKPTRU: INX +BRTRU INX LDA ESTKH-1,X ORA ESTKL-1,X - BEQ NOSKIP -SKIP: -.IF IS65C02 - LDY #$01 -.ELSE - INY ; LDY #$01 -.ENDIF - LDA (PC),Y - PHA - INY - LDA (PC),Y - STA PCH - PLA - STA PCL - PLA - PLA - CLRY - JMP FETCHOP -SKPFLS: INX + BNE BRNCH +NOBRNCH INC_IP + INC_IP + JMP NEXTOP +BRFLS INX LDA ESTKH-1,X ORA ESTKL-1,X - BEQ SKIP -NOSKIP: LDA #$02 + BNE NOBRNCH +BRNCH STY IPY + LDA IPH + STA TMPH + LDA IPL + INC_IP CLC - ADC PCL - STA PCL - BCC NOSK1 - INC PCH -NOSK1: RTS -SKPEQ: INX + ADC (IP),Y + STA TMPL + LDA TMPH + INC_IP + ADC (IP),Y + STA IPH + LDA TMPL + STA IPL + LDY IPY + JMP FETCHOP +BREQ INX LDA ESTKL-1,X CMP ESTKL,X - BNE NOSKIP + BNE NOBRNCH LDA ESTKL-1,X CMP ESTKL,X - BEQ SKIP - BNE NOSKIP -SKPNE: INX + BEQ BRNCH + BNE NOBRNCH +BRNE INX LDA ESTKL-1,X CMP ESTKL,X - BNE SKIP + BNE BRNCH LDA ESTKL-1,X CMP ESTKL,X - BEQ NOSKIP - BNE SKIP -SKPGT: INX + BEQ NOBRNCH + BNE BRNCH +BRGT INX LDA ESTKL-1,X CMP ESTKL,X LDA ESTKH-1,X SBC ESTKH,X - BMI SKIP - BPL NOSKIP -SKPLT: INX + BMI BRNCH + BPL NOBRNCH +BRLT INX LDA ESTKL,X CMP ESTKL-1,X LDA ESTKH,X SBC ESTKH-1,X - BMI SKIP - BPL NOSKIP -;* -;* INDIRECT SKIP TO ADDRESS -;* -ISKIP: PLA - PLA - LDA ESTKL,X - STA PCL - LDA ESTKH,X - STA PCH + BMI BRNCH + BPL NOBRNCH +IBRNCH LDA IPL + CLC + ADC ESTKL,X + STA IPL + LDA IPH + ADC ESTKH,X + STA IPH INX JMP FETCHOP -;* -;* EXTERNAL SYS CALL -;* -INT: INC PCL - BNE INT1 - INC PCH -INT1: LDA_IPC - JSR INTJMP - CLRY - RTS +; +BRTRUX INX + LDA ESTKH-1,X + ORA ESTKL-1,X + BNE BRNCHX +NOBRNCHX INC_IP + INC_IP + JMP NEXTOPX +BRFLSX INX + LDA ESTKH-1,X + ORA ESTKL-1,X + BNE NOBRNCHX +BRNCHX STY IPY + LDA IPH + STA TMPH + LDA IPL + INC_IP + CLC + ADC (IP),Y + STA TMPL + LDA TMPH + INC_IP + ADC (IP),Y + STA IPH + LDA TMPL + STA IPL + LDY IPY + JMP FETCHOPX +BREQX INX + LDA ESTKL-1,X + CMP ESTKL,X + BNE NOBRNCHX + LDA ESTKL-1,X + CMP ESTKL,X + BEQ BRNCHX + BNE NOBRNCHX +BRNEX INX + LDA ESTKL-1,X + CMP ESTKL,X + BNE BRNCHX + LDA ESTKL-1,X + CMP ESTKL,X + BEQ NOBRNCHX + BNE BRNCHX +BRGTX INX + LDA ESTKL-1,X + CMP ESTKL,X + LDA ESTKH-1,X + SBC ESTKH,X + BMI BRNCHX + BPL NOBRNCHX +BRLTX INX + LDA ESTKL,X + CMP ESTKL-1,X + LDA ESTKH,X + SBC ESTKH-1,X + BMI BRNCHX + BPL NOBRNCHX +IBRNCHX LDA IPL + CLC + ADC ESTKL,X + STA IPL + LDA IPH + ADC ESTKH,X + STA IPH + INX + JMP FETCHOPX ;* ;* CALL INTO ABSOLUTE ADDRESS (NATIVE CODE) ;* -CALL: INC PCL - BNE CALL1 - INC PCH -CALL1: LDA_IPC +CALL INC_IP + LDA (IP),Y STA TMPL - INC PCL - BNE CALL2 - INC PCH -CALL2: LDA_IPC + INC_IP + LDA (IP),Y STA TMPH - LDA PCH + LDA IPH PHA - LDA PCL + LDA IPL + PHA + TYA PHA JSR TMPJMP PLA - STA PCL + TAY PLA - STA PCH - CLRY - RTS + STA IPL + PLA + STA IPH + JMP NEXTOP +; +CALLX INC_IP + LDA (IP),Y + STA TMPL + INC_IP + LDA (IP),Y + STA TMPH + LDA IPH + PHA + LDA IPL + PHA + TYA + PHA + STA ALTRAMRDOFF + CLI + JSR TMPJMP + PLA + TAY + PLA + STA IPL + PLA + STA IPH + JMP NEXTOPX ;* ;* INDIRECT CALL TO ADDRESS (NATIVE CODE) ;* -ICAL: LDA ESTKL,X +ICAL LDA ESTKL,X STA TMPL LDA ESTKH,X STA TMPH INX - LDA PCH + LDA IPH PHA - LDA PCL + LDA IPL PHA + TYA + PHA + LDY #$00 + LDA (TMP),Y + PHA + INY + LDA (TMP),Y + STA TMPH + PLA + STA TMPL + CLI JSR TMPJMP PLA - STA PCL + TAY PLA - STA PCH - CLRY - RTS + STA IPL + PLA + STA IPH + JMP NEXTOP +; +ICALX LDA ESTKL,X + STA TMPL + LDA ESTKH,X + STA TMPH + INX + LDA IPH + PHA + LDA IPL + PHA + TYA + PHA + STA ALTRAMRDOFF + LDY #$00 + LDA (TMP),Y + PHA + INY + LDA (TMP),Y + STA TMPH + PLA + STA TMPL + CLI + JSR TMPJMP + PLA + TAY + PLA + STA IPL + PLA + STA IPH + JMP NEXTOPX ;* ;* ENTER FUNCTION WITH FRAME SIZE AND PARAM COUNT ;* -_ENTER: STY FRMSZ - JMP ENTER3 -ENTER: INC PCL - BNE ENTER1 - INC PCH -ENTER1: LDA_IPC +ENTER INC_IP + LDA (IP),Y STA FRMSZ - INC PCL - BNE ENTER2 - INC PCH -ENTER2: LDA_IPC -ENTER3: STA NPARMS - LDA FRMPL + INC_IP + LDA (IP),Y + STA NPARMS + STY IPY + LDA IFPL PHA SEC SBC FRMSZ - STA FRMPL - LDA FRMPH + STA IFPL + LDA IFPH PHA SBC #$00 - STA FRMPH + STA IFPH LDY #$01 PLA - STA (FRMP),Y + STA (IFP),Y DEY PLA - STA (FRMP),Y + STA (IFP),Y LDA NPARMS BEQ ENTER5 ASL TAY INY -ENTER4: LDA ESTKH,X - STA (FRMP),Y +ENTER4 LDA ESTKH,X + STA (IFP),Y DEY LDA ESTKL,X - STA (FRMP),Y + STA (IFP),Y DEY INX DEC TMPL BNE ENTER4 -ENTER5: LDY #$00 - RTS +ENTER5 LDY IPY + JMP NEXTOP +; +ENTERX INC_IP + LDA (IP),Y + STA FRMSZ + INC_IP + LDA (IP),Y + STA NPARMS + STY IPY + STA ALTRAMRDOFF + LDA IFPL + PHA + SEC + SBC FRMSZ + STA IFPL + LDA IFPH + PHA + SBC #$00 + STA IFPH + LDY #$01 + PLA + STA (IFP),Y + DEY + PLA + STA (IFP),Y + LDA NPARMS + BEQ ENTERX5 + ASL + TAY + INY +ENTERX4 LDA ESTKH,X + STA (IFP),Y + DEY + LDA ESTKL,X + STA (IFP),Y + DEY + INX + DEC TMPL + BNE ENTERX4 +ENTERX5 LDY IPY + JMP NEXTOPX ;* ;* LEAVE FUNCTION ;* -LEAVE: PLA - PLA -_LEAVE: LDY #$01 - LDA (FRMP),Y +LEAVE LDY #$01 + LDA (IFP),Y DEY PHA - LDA (FRMP),Y - STA FRMPL + LDA (IFP),Y + STA IFPL PLA - STA FRMPH - RTS -RET: PLA - PLA - RTS -;*********************************************** -;* -;* XMOD VERSIONS OF BYTECODE OPS -;* -;*********************************************** -;* -;* CONSTANT -;* -CBX: DEX - INC PCL - BNE CBX1 - INC PCH -CBX1: AUXMEM_RDACCESS_ON - LDA_IPC - AUXMEM_RDACCESS_OFF - STA ESTKL,X - STY ESTKH,X - RTS -;* -;* LOAD ADDRESS -;* -LAX: -CWX: DEX - INC PCL - BNE CWX1 - INC PCH -CWX1: AUXMEM_RDACCESS_ON - LDA_IPC - STA ESTKL,X - INC PCL - BNE CWX2 - INC PCH -CWX2: LDA_IPC - AUXMEM_RDACCESS_OFF - STA ESTKH,X - RTS -;* -;* LOAD ADDRESS OF LOCAL FRAME OFFSET -;* -LLAX: INC PCL - BNE LLAX1 - INC PCH -LLAX1: AUXMEM_RDACCESS_ON - LDA_IPC - AUXMEM_RDACCESS_OFF - DEX - CLC - ADC FRMPL - STA ESTKL,X - LDA0 - ADC FRMPH - STA ESTKH,X - RTS -;* -;* LOAD VALUE FROM LOCAL FRAME OFFSET -;* -LLBX: INC PCL - BNE LLBX1 - INC PCH -LLBX1: AUXMEM_RDACCESS_ON - LDA_IPC - AUXMEM_RDACCESS_OFF - TAY - DEX - LDA (FRMP),Y - STA ESTKL,X - CLRY - ST0 {ESTKH,X} - RTS -LLWX: INC PCL - BNE LLWX1 - INC PCH -LLWX1: AUXMEM_RDACCESS_ON - LDA_IPC - AUXMEM_RDACCESS_OFF - TAY - DEX - LDA (FRMP),Y - STA ESTKL,X - INY - LDA (FRMP),Y - STA ESTKH,X - CLRY - RTS -;* -;* LOAD VALUE FROM ABSOLUTE ADDRESS -;* -LABX: INC PCL - BNE LABX1 - INC PCH -LABX1: AUXMEM_RDACCESS_ON - LDA_IPC - STA TMPL - INC PCL - BNE LABX2 - INC PCH -LABX2: LDA_IPC - AUXMEM_RDACCESS_OFF - STA TMPH - DEX - LDA_ITMPL - STA ESTKL,X - ST0 {ESTKH,X} - RTS -LAWX: INC PC - BNE LAWX1 - INC PCH -LAWX1: AUXMEM_RDACCESS_ON - LDA_IPC - STA TMPL - INC PCL - BNE LAWX2 - INC PCH - DEX -LAWX2: LDA_IPC - STA TMPH - LDA_ITMPL - STA ESTKL,X - LDA_ITMPH - AUXMEM_RDACCESS_OFF - STA ESTKH,X - RTS -;* -;* STORE VALUE TO LOCAL FRAME OFFSET -;* -SLBX: INC PCL - BNE SLBX1 - INC PCH -SLBX1: AUXMEM_RDACCESS_ON - LDA_IPC - AUXMEM_RDACCESS_OFF - TAY - LDA ESTKL,X - STA (FRMP),Y - INX - CLRY - RTS -SLWX: INC PCL - BNE SLWX1 - INC PCH -SLWX1: AUXMEM_RDACCESS_ON - LDA_IPC - AUXMEM_RDACCESS_OFF - TAY - LDA ESTKL,X - STA (FRMP),Y - INY - LDA ESTKH,X - STA (FRMP),Y - INX - CLRY - RTS -;* -;* STORE VALUE TO LOCAL FRAME OFFSET WITHOUT POPPING STACK -;* -DLBX: INC PCL - BNE DLBX1 - INC PCH -DLBX1: AUXMEM_RDACCESS_ON - LDA_IPC - AUXMEM_RDACCESS_OFF - TAY - LDA ESTKL,X - STA (FRMP),Y - CLRY - RTS -DLWX: INC PCL - BNE DLWX1 - INC PCH -DLWX1: AUXMEM_RDACCESS_ON - LDA_IPC - AUXMEM_RDACCESS_OFF - TAY - LDA ESTKL,X - STA (FRMP),Y - INY - LDA ESTKH,X - STA (FRMP),Y - CLRY - RTS -;* -;* STORE VALUE TO ABSOLUTE ADDRESS -;* -SABX: INC PCL - BNE SABX1 - INC PCH -SABX1: AUXMEM_RDACCESS_ON - LDA_IPC - STA TMPL - INC PCL - BNE SABX2 - INC PCH -SABX2: LDA_IPC - AUXMEM_RDACCESS_OFF - STA TMPH - LDA ESTKL,X - STA_ITMPL - INX - RTS -SAWX: INC PCL - BNE SAWX1 - INC PCH -SAWX1: AUXMEM_RDACCESS_ON - LDA_IPC - STA TMPL - INC PCL - BNE SAWX2 - INC PCH -SAWX2: LDA_IPC - AUXMEM_RDACCESS_OFF - STA TMPH - LDA ESTKL,X - STA_ITMPL - LDA ESTKH,X - STA_ITMPH - INX - RTS -;* -;* STORE VALUE TO ABSOLUTE ADDRESS WITHOUT POPPING STACK -;* -DABX: INC PCL - BNE DABX1 - INC PCH -DABX1: AUXMEM_RDACCESS_ON - LDA_IPC - STA TMPL - INC PCL - BNE DABX2 - INC PCH -DABX2: LDA_IPC - AUXMEM_RDACCESS_OFF - STA TMPH - LDA ESTKL,X - STA_ITMPL - RTS -DAWX: INC PCL - BNE DAWX1 - INC PCH -DAWX1: AUXMEM_RDACCESS_ON - LDA_IPC - STA TMPL - INC PCL - BNE DAWX2 - INC PCH -DAWX2: LDA_IPC - AUXMEM_RDACCESS_OFF - STA TMPH - LDA ESTKL,X - STA_ITMPL - LDA ESTKH,X - STA_ITMPH - RTS -;* -;* SKIPS -;* -SKPTRUX: INX - LDA ESTKH-1,X - ORA ESTKL-1,X - BEQ NOSKIPX -SKIPX: -.IF IS65C02 + STA IFPH +RET RTS +; +LEAVEX STA ALTRAMRDOFF LDY #$01 -.ELSE - INY ; LDY #$01 -.ENDIF - AUXMEM_RDACCESS_ON - LDA_IPC + LDA (IFP),Y + DEY PHA - INY - LDA_IPC - AUXMEM_RDACCESS_OFF - STA PCH + LDA (IFP),Y + STA IFPL PLA - STA PCL - PLA - PLA - CLRY - CLRY - JMP FETCHOPX -SKPFLSX: INX - LDA ESTKH-1,X - ORA ESTKL-1,X - BEQ SKIPX -NOSKIPX: LDA #$02 - CLC - ADC PCL - STA PCL - BCC NOSKX1 - INC PCH -NOSKX1: RTS -SKPEQX: INX - ; INX - LDA ESTKL-1,X - CMP ESTKL,X - BNE NOSKIPX - LDA ESTKL-1,X - CMP ESTKL,X - BEQ SKIPX - BNE NOSKIPX -SKPNEX: INX - ; INX - LDA ESTKL-1,X - CMP ESTKL,X - BNE SKIPX - LDA ESTKL-1,X - CMP ESTKL,X - BEQ NOSKIPX - BNE SKIPX -SKPGTX: INX - ; INX - LDA ESTKL-1,X - CMP ESTKL,X - LDA ESTKH-1,X - SBC ESTKH,X - BMI SKIPX - BPL NOSKIPX -SKPLTX: INX - ; INX - LDA ESTKL,X - CMP ESTKL-1,X - LDA ESTKH,X - SBC ESTKH-1,X - BMI SKIPX - BPL NOSKIPX -;* -;* INDIRECT SKIP TO ADDRESS -;* -ISKIPX: PLA - PLA - LDA ESTKL,X - STA PCL - LDA ESTKH,X - STA PCH - INX - JMP FETCHOPX -;* -;* EXTERNAL SYS CALL -;* -INTX: INC PCL - BNE INTX1 - INC PCH -INTX1: AUXMEM_RDACCESS_ON - LDA_IPC - AUXMEM_RDACCESS_OFF - JSR INTJMP - CLRY + STA IFPH + CLI RTS -;* -;* CALL TO ABSOLUTE ADDRESS (NATIVE CODE) -;* -CALLX: INC PCL - BNE CALLX1 - INC PCH -CALLX1: AUXMEM_RDACCESS_ON - LDA_IPC - STA TMPL - INC PCL - BNE CALLX2 - INC PCH -CALLX2: LDA_IPC - AUXMEM_RDACCESS_OFF - STA TMPH - LDA PCH - PHA - LDA PCL - PHA - JSR TMPJMP - PLA - STA PCL - PLA - STA PCH - CLRY +RETX STA ALTRAMRDOFF + CLI RTS +} \ No newline at end of file From e230d98e8cb58e7912422867835baa59b2018c71 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 6 May 2014 09:43:14 -0700 Subject: [PATCH 34/44] assembling... --- PLASMA/src/plvm02.s | 365 +++++++++++++++++++------------------------- 1 file changed, 157 insertions(+), 208 deletions(-) diff --git a/PLASMA/src/plvm02.s b/PLASMA/src/plvm02.s index a3e2c823..82b95981 100644 --- a/PLASMA/src/plvm02.s +++ b/PLASMA/src/plvm02.s @@ -17,63 +17,18 @@ MACHID = $BF98 KEYBD = $C000 CLRKBD = $C010 SPKR = $C030 -ROMIN = $C081 -LCBNK2 = $C083 -LCBNK1 = $C08B +LCRDEN = $C080 +LCWTEN = $C081 +ROMEN = $C082 +LCRWEN = $C083 +LCBNK2 = $00 +LCBNK1 = $08 ALTZPOFF= $C008 ALTZPON = $C009 ALTRDOFF= $C002 ALTRDON = $C003 ALTWROFF= $C004 ALTWRON = $C005 -;* -;* AUXMEM ACCESS MACROS -;* -.IF IS65C02 -.MACRO AUXZP_ACCESS_ON - STA ALTZPON ; TURN ON ALT ZP AND LC -.ENDMACRO -.MACRO AUXZP_ACCESS_OFF - STA ALTZPOFF ; TURN OFF ALT ZP AND LC -.ENDMACRO -.MACRO AUXMEM_RDON - STA ALTRAMRDON -.ENDMACRO -.MACRO STA ALTRAMRDOFF - STA ALTRAMRDOFF -.ENDMACRO -.MACRO AUXMEM_WRON - STA ALTRAMWRON -.ENDMACRO -.MACRO AUXMEM_WROFF - STA ALTRAMWROFF -.ENDMACRO -.ELSE -.MACRO AUXZP_ACCESS_ON - SEI ; TURN INTERRUPTS OFF - STA ALTZPON ; TURN ON ALT ZP AND LC -.ENDMACRO -.MACRO AUXZP_ACCESS_OFF - STA ALTZPOFF ; TURN OFF ALT ZP AND LC - CLI ; TURN INTERRUPTS BACK ON -.ENDMACRO -.MACRO AUXMEM_RDON - SEI - STA ALTRAMRDON -.ENDMACRO -.MACRO STA ALTRAMRDOFF - STA ALTRAMRDOFF - CLI -.ENDMACRO -.MACRO AUXMEM_WRON - SEI - STA ALTRAMWRON -.ENDMACRO -.MACRO AUXMEM_WROFF - STA ALTRAMWROFF - CLI -.ENDMACRO -.ENDIF ;********************************************************** ;* ;* VM ZERO PAGE LOCATIONS @@ -98,57 +53,51 @@ TMPX = TMP+2 NPARMS = TMPL FRMSZ = TMPH DVSIGN = TMPX +;********************************************************** ;* -;* COMMAND LOADER CODE +;* INTERPRETER INSTRUCTION POINTER INCREMENT MACRO ;* - CLD - CLV - BVC + - JMP PLASMA - +;********************************************************** + !MACRO INC_IP { + INY + BNE * + 4 + INC IPH + } ;*********************************************** ;* ;* INTERPRETER INITIALIZATION ;* ;*********************************************** -;* -;* INIT AND ENTER INTO PLASMA BYTECODE INTERPRETER -;* X Y A = ADDRESS OF INITAL ENTRYPOINT -;* -PLASMA STA PCL - STY PCH - STX TMP +* = $2000 CLD - LDY #$20 - LDA PAGE3,Y + BIT LCRWEN+LCBNK2 + BIT LCRWEN+LCBNK2 + LDY #$10 +- LDA PAGE3,Y STA $03D0,Y DEY BPL - LDX #ESTKSZ/2 - INY ; LDY #$00 - LDA TMP - BEQ FETCHOP - LDA MACHID - AND #$30 - CMP #$30 - BEQ FETCHOPX - +PAGE3 = * !PSEUDOPC $03D0 { - ;* ;* PAGE 3 VECTORS INTO INTERPRETER ;* -PAGE3 BIT $C080 ; $03D0 - INTERP ENTRY + BIT LCRDEN+LCBNK2 ; $03D0 - INTERP ENTRY JMP INTERP +CALL3 BIT ROMEN +CALLADR JSR $0000 + BIT LCRDEN+LCBNK2 + RTS } - +PLASMA = * !PSEUDOPC $D000 { ;* ;* OPCODE TABLE ;* -OPTBL !WORD ZERO,ADD,SUB,MUL,DIV,DIVMOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E +OPTBL !WORD ZERO,ADD,SUB,MUL,DIV,MOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E !WORD NEG,COMP,BAND,IOR,XOR,SHL,SHR,IDXW ; 10 12 14 16 18 1A 1C 1E - !WORD NOT,LOR,LAND,LA,LLA,CB,CW,SWAP ; 20 22 24 26 28 2A 2C 2E + !WORD LNOT,LOR,LAND,LA,LLA,CB,CW,SWAP ; 20 22 24 26 28 2A 2C 2E !WORD DROP,DUP,PUSH,PULL,BRLT,BRGT,BREQ,BRNE ; 30 32 34 36 38 3A 3C 3E !WORD ISEQ,ISNE,ISGT,ISLT,ISGE,ISLE,BRFLS,BRTRU ; 40 42 44 46 48 4A 4C 4E !WORD BRNCH,IBRNCH,CALL,ICAL,ENTER,LEAVE,RET,NEXTOP ; 50 52 54 56 58 5A 5C 5E @@ -176,36 +125,38 @@ INTERP PLA ;* ;* INTERP BYTECODE IN MAIN MEM ;* +NEXTOPH INC IPH + BNE FETCHOP +DROP INX +NEXTOP INY + BEQ NEXTOPH FETCHOP LDA (IP),Y STA *+5 JMP (OPTBL) -NEXTOP INY - BNE FETCHOP - INC IPH - BNE FETCHOP ;* ;* INTERP BYTECODE IN AUX MEM ;* -FETCHOPX SEI - STA ALTRAMRDON - LDA (IP),Y - STA *+5 - JMP (OPTBLX) +NEXTOPHX INC IPH + BNE FETCHOPX +DROPX INX NEXTOPX CLI INY - BNE FETCHOPX - INC IPH - BNE FETCHOPX + BEQ NEXTOPHX +FETCHOPX SEI + STA ALTRDON + LDA (IP),Y + STA *+5 + JMP (OPXTBL) ;* ;* ALIGN TO NEXT PAGE ;* - !FILL 255 + !ALIGN 255, 0 ;* ;* OPXCODE TABLE ;* OPXTBL !WORD ZEROX,ADDX,SUBX,MULX,DIVX,MODX,INCRX,DECRX ; 00 02 04 06 08 0A 0C 0E !WORD NEGX,COMPX,BANDX,IORX,XORX,SHLX,SHRX,IDXWX ; 10 12 14 16 18 1A 1C 1E - !WORD NOTX,LORX,LANDX,LAX,LLAX,CBX,CWX,SWAPX ; 20 22 24 26 28 2A 2C 2E + !WORD LNOTX,LORX,LANDX,LAX,LLAX,CBX,CWX,SWAPX ; 20 22 24 26 28 2A 2C 2E !WORD DROPX,DUPX,PUSHX,PULLX,BRLTX,BRGTX,BREQX,BRNEX ; 30 32 34 36 38 3A 3C 3E !WORD ISEQX,ISNEX,ISGTX,ISLTX,ISGEX,ISLEX,BRFLSX,BRTRUX; 40 42 44 46 48 4A 4C 4E !WORD BRNCHX,IBRNCHX,CALLX,ICALX,ENTERX,LEAVEX,RETX,NEXTOPX; 50 52 54 56 58 5A 5C 5E @@ -533,7 +484,7 @@ XORX LDA ESTKL+1,X EOR ESTKH,X STA ESTKH+1,X INX - NEXTOPX + JMP NEXTOPX ;* ;* SHIFT TOS-1 LEFT BY TOS ;* @@ -554,7 +505,7 @@ SHL2 ASL ESTKL+1,X BNE SHL2 SHL3 INX LDY IPY - NEXTOP + JMP NEXTOP ; SHLX STY IPY LDA ESTKL,X @@ -573,7 +524,7 @@ SHLX2 ASL ESTKL+1,X BNE SHLX2 SHLX3 INX LDY IPY - NEXTOPX + JMP NEXTOPX ;* ;* SHIFT TOS-1 RIGHT BY TOS ;* @@ -631,20 +582,20 @@ SHRX4 INX ;* ;* LOGICAL NOT ;* -NOT LDA ESTKL,X +LNOT LDA ESTKL,X ORA ESTKH,X - BEQ NOT1 + BEQ LNOT1 LDA #$FF -NOT1 EOR #$FF +LNOT1 EOR #$FF STA ESTKL,X STA ESTKH,X JMP NEXTOP ; -NOTX LDA ESTKL,X +LNOTX LDA ESTKL,X ORA ESTKH,X - BEQ NOTX1 + BEQ LNOTX1 LDA #$FF -NOTX1 EOR #$FF +LNOTX1 EOR #$FF STA ESTKL,X STA ESTKH,X JMP NEXTOPX @@ -675,7 +626,7 @@ LANDX1 STA ESTKL+1,X INX JMP NEXTOPX ;* -;* LOGICAL OR & DROP TOS +;* LOGICAL OR ;* LOR LDA ESTKL,X ORA ESTKH,X @@ -685,7 +636,7 @@ LOR LDA ESTKL,X LDA #$FF LOR1 STA ESTKL+1,X STA ESTKH+1,X -DROP INX + INX JMP NEXTOP ; LORX LDA ESTKL,X @@ -696,7 +647,7 @@ LORX LDA ESTKL,X LDA #$FF LORX1 STA ESTKL+1,X STA ESTKH+1,X -DROPX INX + INX JMP NEXTOPX ;* ;* SWAP TOS WITH TOS-1 @@ -782,7 +733,7 @@ ZERO DEX STA ESTKH,X JMP NEXTOP CB DEX - INC_IP + +INC_IP LDA (IP),Y STA ESTKL,X LDA #$00 @@ -795,7 +746,7 @@ ZEROX DEX STA ESTKH,X JMP NEXTOPX CBX DEX - INC_IP + +INC_IP LDA (IP),Y STA ESTKL,X LDA #$00 @@ -804,22 +755,22 @@ CBX DEX ;* ;* LOAD ADDRESS & LOAD CONSTANT WORD (SAME THING, WITH OR WITHOUT FIXUP) ;* -LA +LA = * CW DEX - INC_IP + +INC_IP LDA (IP),Y STA ESTKL,X - INC_IP + +INC_IP LDA (IP),Y STA ESTKH,X JMP NEXTOP ; -LAX +LAX = * CWX DEX - INC_IP + +INC_IP LDA (IP),Y STA ESTKL,X - INC_IP + +INC_IP LDA (IP),Y STA ESTKH,X JMP NEXTOPX @@ -851,7 +802,7 @@ LW LDA ESTKL,X LDY IPY JMP NEXTOP ; -LBX STA ALTRAMRDOFF +LBX STA ALTRDOFF LDA ESTKL,X STA TMPL LDA ESTKH,X @@ -863,7 +814,7 @@ LBX STA ALTRAMRDOFF STY ESTKH,X LDY IPY JMP NEXTOPX -LWX STA ALTRAMRDOFF +LWX STA ALTRDOFF LDA ESTKL,X STA TMPL LDA ESTKH,X @@ -880,7 +831,7 @@ LWX STA ALTRAMRDOFF ;* ;* LOAD ADDRESS OF LOCAL FRAME OFFSET ;* -LLA INC_IP +LLA +INC_IP LDA (IP),Y DEX CLC @@ -891,7 +842,7 @@ LLA INC_IP STA ESTKH,X JMP NEXTOP ; -LLAX INC_IP +LLAX +INC_IP LDA (IP),Y DEX CLC @@ -904,7 +855,7 @@ LLAX INC_IP ;* ;* LOAD VALUE FROM LOCAL FRAME OFFSET ;* -LLB INC_IP +LLB +INC_IP LDA (IP),Y STY IPY TAY @@ -915,7 +866,7 @@ LLB INC_IP STA ESTKH,X LDY IPY JMP NEXTOP -LLW INC_IP +LLW +INC_IP LDA (IP),Y STY IPY TAY @@ -928,24 +879,24 @@ LLW INC_IP LDY IPY JMP NEXTOP ; -LLBX INC_IP +LLBX +INC_IP LDA (IP),Y STY IPY TAY DEX - STA ALTRAMRDOFF + STA ALTRDOFF LDA (IFP),Y STA ESTKL,X LDA #$00 STA ESTKH,X LDY IPY JMP NEXTOP -LLWX INC_IP +LLWX +INC_IP LDA (IP),Y STY IPY TAY DEX - STA ALTRAMRDOFF + STA ALTRDOFF LDA (IFP),Y STA ESTKL,X INY @@ -956,10 +907,10 @@ LLWX INC_IP ;* ;* LOAD VALUE FROM ABSOLUTE ADDRESS ;* -LAB INC_IP +LAB +INC_IP LDA (IP),Y STA TMPL - INC_IP + +INC_IP LDA (IP),Y STA TMPH STY IPY @@ -970,10 +921,10 @@ LAB INC_IP STY ESTKH,X LDY IPY JMP NEXTOP -LAW INC_IP +LAW +INC_IP LDA (IP),Y STA TMPL - INC_IP + +INC_IP LDA (IP),Y STA TMPH STY IPY @@ -987,14 +938,14 @@ LAW INC_IP LDY IPY JMP NEXTOP ; -LABX INC_IP +LABX +INC_IP LDA (IP),Y STA TMPL - INC_IP + +INC_IP LDA (IP),Y STA TMPH STY IPY - STA ALTRAMRDOFF + STA ALTRDOFF LDY #$00 LDA (TMP),Y DEX @@ -1002,14 +953,14 @@ LABX INC_IP STY ESTKH,X LDY IPY JMP NEXTOPX -LAWX INC_IP +LAWX +INC_IP LDA (IP),Y STA TMPL - INC_IP + +INC_IP LDA (IP),Y STA TMPH STY IPY - STA ALTRAMRDOFF + STA ALTRDOFF LDY #$00 LDA (TMP),Y DEX @@ -1056,7 +1007,7 @@ SBX LDA ESTKL+1,X STA TMPH LDA ESTKL,X STY IPY - STA ALTRAMRDOFF + STA ALTRDOFF LDY #$00 STA (TMP),Y INX @@ -1068,7 +1019,7 @@ SWX LDA ESTKL+1,X LDA ESTKH+1,X STA TMPH STY IPY - STA ALTRAMRDOFF + STA ALTRDOFF LDY #$00 LDA ESTKL,X STA (TMP),Y @@ -1082,7 +1033,7 @@ SWX LDA ESTKL+1,X ;* ;* STORE VALUE TO LOCAL FRAME OFFSET ;* -SLB INC_IP +SLB +INC_IP LDA (IP),Y STY IPY TAY @@ -1091,46 +1042,46 @@ SLB INC_IP INX LDY IPY JMP NEXTOP -SLW INC_IP +SLW +INC_IP LDA (IP),Y STY IPY TAY LDA ESTKL,X - STA (FRMP),Y + STA (IFP),Y INY LDA ESTKH,X - STA (FRMP),Y + STA (IFP),Y INX LDY IPY JMP NEXTOP ; -SLBX INC_IP +SLBX +INC_IP LDA (IP),Y STY IPY - STA ALTRAMRDOFF + STA ALTRDOFF TAY LDA ESTKL,X STA (IFP),Y INX LDY IPY JMP NEXTOPX -SLWX INC_IP +SLWX +INC_IP LDA (IP),Y STY IPY - STA ALTRAMRDOFF + STA ALTRDOFF TAY LDA ESTKL,X - STA (FRMP),Y + STA (IFP),Y INY LDA ESTKH,X - STA (FRMP),Y + STA (IFP),Y INX LDY IPY JMP NEXTOPX ;* ;* STORE VALUE TO LOCAL FRAME OFFSET WITHOUT POPPING STACK ;* -DLB INC_IP +DLB +INC_IP LDA (IP),Y STY IPY TAY @@ -1138,7 +1089,7 @@ DLB INC_IP STA (IFP),Y LDY IPY JMP NEXTOP -DLW INC_IP +DLW +INC_IP LDA (IP),Y STY IPY TAY @@ -1150,19 +1101,19 @@ DLW INC_IP LDY IPY JMP NEXTOP ; -DLBX INC_IP +DLBX +INC_IP LDA (IP),Y STY IPY - STA ALTRAMRDOFF + STA ALTRDOFF TAY LDA ESTKL,X STA (IFP),Y LDY IPY JMP NEXTOPX -DLWX INC_IP +DLWX +INC_IP LDA (IP),Y STY IPY - STA ALTRAMRDOFF + STA ALTRDOFF TAY LDA ESTKL,X STA (IFP),Y @@ -1174,10 +1125,10 @@ DLWX INC_IP ;* ;* STORE VALUE TO ABSOLUTE ADDRESS ;* -SAB INC_IP +SAB +INC_IP LDA (IP),Y STA TMPL - INC_IP + +INC_IP LDA (IP),Y STA TMPH LDA ESTKL,X @@ -1187,10 +1138,10 @@ SAB INC_IP INX LDY IPY JMP NEXTOP -SAW INC_IP +SAW +INC_IP LDA (IP),Y STA TMPL - INC_IP + +INC_IP LDA (IP),Y STA TMPH STY IPY @@ -1204,28 +1155,28 @@ SAW INC_IP LDY IPY JMP NEXTOP ; -SABX INC_IP +SABX +INC_IP LDA (IP),Y STA TMPL - INC_IP + +INC_IP LDA (IP),Y STA TMPH LDA ESTKL,X STY IPY - STA ALTRAMRDOFF + STA ALTRDOFF LDY #$00 STA (TMP),Y INX LDY IPY JMP NEXTOPX -SAWX INC_IP +SAWX +INC_IP LDA (IP),Y STA TMPL - INC_IP + +INC_IP LDA (IP),Y STA TMPH STY IPY - STA ALTRAMRDOFF + STA ALTRDOFF LDY #$00 LDA ESTKL,X STA (TMP),Y @@ -1238,10 +1189,10 @@ SAWX INC_IP ;* ;* STORE VALUE TO ABSOLUTE ADDRESS WITHOUT POPPING STACK ;* -DAB INC_IP +DAB +INC_IP LDA (IP),Y STA TMPL - INC_IP + +INC_IP LDA (IP),Y STA TMPH STY IPY @@ -1250,10 +1201,10 @@ DAB INC_IP STA (TMP),Y LDY IPY JMP NEXTOP -DAW INC_IP +DAW +INC_IP LDA (IP),Y STA TMPL - INC_IP + +INC_IP LDA (IP),Y STA TMPH STY IPY @@ -1266,27 +1217,27 @@ DAW INC_IP LDY IPY JMP NEXTOP ; -DABX INC_IP +DABX +INC_IP LDA (IP),Y STA TMPL - INC_IP + +INC_IP LDA (IP),Y STA TMPH STY IPY - STA ALTRAMRDOFF + STA ALTRDOFF LDY #$00 LDA ESTKL,X STA (TMP),Y LDY IPY JMP NEXTOPX -DAWX INC_IP +DAWX +INC_IP LDA (IP),Y STA TMPL - INC_IP + +INC_IP LDA (IP),Y STA TMPH STY IPY - STA ALTRAMRDOFF + STA ALTRDOFF LDY #$00 LDA ESTKL,X STA (TMP),Y @@ -1492,8 +1443,8 @@ BRTRU INX LDA ESTKH-1,X ORA ESTKL-1,X BNE BRNCH -NOBRNCH INC_IP - INC_IP +NOBRNCH +INC_IP + +INC_IP JMP NEXTOP BRFLS INX LDA ESTKH-1,X @@ -1503,12 +1454,12 @@ BRNCH STY IPY LDA IPH STA TMPH LDA IPL - INC_IP + +INC_IP CLC ADC (IP),Y STA TMPL LDA TMPH - INC_IP + +INC_IP ADC (IP),Y STA IPH LDA TMPL @@ -1559,8 +1510,8 @@ BRTRUX INX LDA ESTKH-1,X ORA ESTKL-1,X BNE BRNCHX -NOBRNCHX INC_IP - INC_IP +NOBRNCHX +INC_IP + +INC_IP JMP NEXTOPX BRFLSX INX LDA ESTKH-1,X @@ -1570,12 +1521,12 @@ BRNCHX STY IPY LDA IPH STA TMPH LDA IPL - INC_IP + +INC_IP CLC ADC (IP),Y STA TMPL LDA TMPH - INC_IP + +INC_IP ADC (IP),Y STA IPH LDA TMPL @@ -1624,19 +1575,19 @@ IBRNCHX LDA IPL ;* ;* CALL INTO ABSOLUTE ADDRESS (NATIVE CODE) ;* -CALL INC_IP +CALL +INC_IP LDA (IP),Y - STA TMPL - INC_IP + STA CALLADR+1 + +INC_IP LDA (IP),Y - STA TMPH + STA CALLADR+2 LDA IPH PHA LDA IPL PHA TYA PHA - JSR TMPJMP + JSR CALL3 PLA TAY PLA @@ -1645,21 +1596,23 @@ CALL INC_IP STA IPH JMP NEXTOP ; -CALLX INC_IP +CALLX +INC_IP LDA (IP),Y - STA TMPL - INC_IP + PHA + +INC_IP LDA (IP),Y - STA TMPH + STA ALTRDOFF + STA CALLADR+2 + PLA + STA CALLADR+1 LDA IPH PHA LDA IPL PHA TYA PHA - STA ALTRAMRDOFF CLI - JSR TMPJMP + JSR CALL3 PLA TAY PLA @@ -1683,14 +1636,12 @@ ICAL LDA ESTKL,X PHA LDY #$00 LDA (TMP),Y - PHA + STA CALLADR+1 INY LDA (TMP),Y - STA TMPH - PLA - STA TMPL + STA CALLADR+2 CLI - JSR TMPJMP + JSR CALL3 PLA TAY PLA @@ -1710,17 +1661,15 @@ ICALX LDA ESTKL,X PHA TYA PHA - STA ALTRAMRDOFF + STA ALTRDOFF LDY #$00 LDA (TMP),Y - PHA + STA CALLADR+1 INY LDA (TMP),Y - STA TMPH - PLA - STA TMPL + STA CALLADR+2 CLI - JSR TMPJMP + JSR CALL3 PLA TAY PLA @@ -1731,10 +1680,10 @@ ICALX LDA ESTKL,X ;* ;* ENTER FUNCTION WITH FRAME SIZE AND PARAM COUNT ;* -ENTER INC_IP +ENTER +INC_IP LDA (IP),Y STA FRMSZ - INC_IP + +INC_IP LDA (IP),Y STA NPARMS STY IPY @@ -1770,14 +1719,14 @@ ENTER4 LDA ESTKH,X ENTER5 LDY IPY JMP NEXTOP ; -ENTERX INC_IP +ENTERX +INC_IP LDA (IP),Y STA FRMSZ - INC_IP + +INC_IP LDA (IP),Y STA NPARMS STY IPY - STA ALTRAMRDOFF + STA ALTRDOFF LDA IFPL PHA SEC @@ -1822,7 +1771,7 @@ LEAVE LDY #$01 STA IFPH RET RTS ; -LEAVEX STA ALTRAMRDOFF +LEAVEX STA ALTRDOFF LDY #$01 LDA (IFP),Y DEY @@ -1833,7 +1782,7 @@ LEAVEX STA ALTRAMRDOFF STA IFPH CLI RTS -RETX STA ALTRAMRDOFF +RETX STA ALTRDOFF CLI RTS } \ No newline at end of file From 385872852889a2839887132cad1355f98c68b174 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 6 May 2014 15:26:12 -0700 Subject: [PATCH 35/44] Updates for code generation and module initialization --- PLASMA/src/cmd.pla | 500 +++++++++++++++++++++++++++++++++++++++++ PLASMA/src/codegen.c | 208 ++++++++++------- PLASMA/src/codegen.h | 5 +- PLASMA/src/loadcmd.s | 62 +++++ PLASMA/src/makefile | 6 +- PLASMA/src/parse.c | 61 +++-- PLASMA/src/plasm.c | 32 ++- PLASMA/src/plvm.c | 18 +- PLASMA/src/plvm02.s | 119 ++++++++-- PLASMA/src/samplib.s | 3 + PLASMA/src/test.pla | 1 + PLASMA/src/testlib.pla | 2 + 12 files changed, 883 insertions(+), 134 deletions(-) create mode 100644 PLASMA/src/cmd.pla create mode 100644 PLASMA/src/loadcmd.s diff --git a/PLASMA/src/cmd.pla b/PLASMA/src/cmd.pla new file mode 100644 index 00000000..92894936 --- /dev/null +++ b/PLASMA/src/cmd.pla @@ -0,0 +1,500 @@ +const iobuffer = $0800 +const databuff = $0C00 +const autorun = $01FF +byte version[] = "PLASMA VM VERSION 0.9" +byte errorstr[] = "ERROR: $" +byte okstr[] = "OK" +byte prefix[32] = "" +byte perr +word cmdptr + +; +; Utility functions +; +; CALL PRODOS +; SYSCALL(CMD, PARAMS) +; +asm prodos + LDA ESTKL,X + LDY ESTKH,X + STA PARAMS + STY PARAMS+1 + INX + LDA ESTKL,X + STA CMD + STX ESP + JSR $BF00 +CMD: !BYTE 00 +PARAMS: !WORD 0000 + BIT LCBNK2 + LDX ESP + STA ESTKL,X + LDY #$00 + STY ESTKH,X + RTS +end +; +; CALL LOADED SYSTEM PROGRAM +; +asm exec + LDX #$FF + TXS + BIT ROMEN + JMP $2000 +end +; +; SET MEMORY TO 0 +; MEMCLR(ADDR, SIZE) +; +asm memclr + LDY #$00 + LDA ESTKL+1,X + STA DSTL + LDA ESTKH+1,X + STA DSTH + INC ESTKL,X + INC ESTKH,X + TYA +SETMLP DEC ESTKL,X + BNE + + DEC ESTKH,X + BEQ ++ ++ STA (DST),Y + INY + BNE SETMLP + INC DSTH + BNE SETMLP ++ INX + INX + RTS +end +; +; COPY MEMORY +; MEMCPY(DSTADDR, SRCADDR, SIZE) +; +asm memcpy + LDY #$00 + LDA ESTKL,X + BNE + + LDA ESTKH,X + BEQ MEMEXIT ++ LDA ESTKL+2,X + STA DSTL + LDA ESTKH+2,X + STA DSTH + LDA ESTKL+1,X + STA SRCL + LDA ESTKH+1,X + STA SRCH + CMP DSTH + BCC REVCPY + BNE FORCPY + LDA SRCL + CMP DSTL + BCS FORCPY +REVCPY ; REVERSE DIRECTION COPY +; CLC + LDA ESTKL,X + ADC DSTL + STA DSTL + LDA ESTKH,X + ADC DSTH + STA DSTH + CLC + LDA ESTKL,X + ADC SRCL + STA SRCL + LDA ESTKH,X + ADC SRCH + STA SRCH + INC ESTKH,X +REVCPYLP + LDA DSTL + BNE + + DEC DSTH ++ DEC DSTL + LDA SRCL + BNE + + DEC SRCH ++ DEC SRCL + LDA (SRC),Y + STA (DST),Y + DEC ESTKL,X + BNE REVCPYLP + DEC ESTKH,X + BNE REVCPYLP + BEQ MEMEXIT +FORCPY INC ESTKH,X +FORCPYLP + LDA (SRC),Y + STA (DST),Y + INC DSTL + BNE + + INC DSTH ++ INC SRCL + BNE + + INC SRCH ++ DEC ESTKL,X + BNE FORCPYLP + DEC ESTKH,X + BNE FORCPYLP +MEMEXIT INX + INX + INX + RTS +end +; +; CHAR OUT +; COUT(CHAR) +; +asm cout + LDA ESTKL,X + INX + ORA #$80 + BIT ROMIN + JSR $FDED + BIT LCBNK2 + RTS +end +; +; CHAR IN +; RDKEY() +; +asm cin + BIT ROMIN + STX ESP + JSR $FD0C + LDX ESP + BIT LCBNK2 + DEX + STA ESTKL,X + LDY #$00 + STY ESTKH,X + RTS +end +; +; PRINT STRING +; PRSTR(STR) +; +asm prstr + LDY #$00 + LDA ESTKL,X + STA SRCL + LDA ESTKH,X + STA SRCH + BIT ROMIN + LDA (SRC),Y + STA ESTKL,X + BEQ + +- INY + LDA (SRC),Y + ORA #$80 + JSR $FDED + TYA + CMP ESTKL,X + BNE - ++ INX + BIT LCBNK2 + RTS +end +; +; PRINT BYTE +; +asm prbyte + LDA ESTKL,X + INX + STX ESP + BIT ROMIN + JSR $FDDA + BIT LCBNK2 + LDX ESP + RTS +end +; +; READ STRING +; STR = RDSTR(PROMPTCHAR) +; +asm rdstr + LDA ESTKL,X + STA $33 + STX ESP + BIT ROMIN + JSR $FD6A + BIT LCBNK2 + STX $01FF +- LDA $01FF,X + AND #$7F + STA $01FF,X + DEX + BPL - + LDX ESP + LDA #$FF + STA ESTKL,X + LDA #$01 + STA ESTKH,X + RTS +end +asm toupper + LDA ESTKL,X + CMP #'a' + BCC + + CMP #'z'+1 + BCS + + SEC + SBC #$20 + STA ESTKL,X ++ RTS +end +; +; EXIT +; +asm reboot + BIT ROMIN + LDA #$00 + STA $3F4 ; INVALIDATE POWER-UP BYTE + JMP ($FFFC) ; RESET +end +def crout + cout($0D) +end +; +; ProDOS routines +; +def getpfx(path) + byte params[3] + + ^path = 0 + params.0 = 1 + params:1 = path + perr = prodos($C7, @params) + return path +end +def setpfx(path) + byte params[3] + + params.0 = 1 + params:1 = path + perr = prodos($C6, @params) + return path +end +def online + byte params[4] + + params.0 = 2 + params.1 = 0 + params:2 = $2000 + perr = prodos($C5, @params) + return $2000 +end +def open(path, buff) + byte params[6] + + params.0 = 3 + params:1 = path + params:3 = buff + params.5 = 0 + perr = prodos($C8, @params) + return params.5 +end +def close(refnum) + byte params[2] + + params.0 = 1 + params.1 = refnum + perr = prodos($CC, @params) + return perr +end +def read(refnum, buff, len) + byte params[8] + + params.0 = 4 + params.1 = refnum + params:2 = buff + params:4 = len + params:6 = 0 + perr = prodos($CA, @params) + return params:6 +end +; +; Command mode +; +def volumes + word strbuf + byte i + + strbuf = online() + for i = 0 to 15 + ^strbuf = ^strbuf & $0F + if ^strbuf + cout('/') + prstr(strbuf) + crout() + fin + strbuf = strbuf + 16 + next +end +def catalog(optpath) + byte path[64] + byte refnum + byte firstblk + byte entrylen, entriesblk + byte i, type, len + word entry, filecnt + + if ^optpath + memcpy(optpath, @path, ^optpath + 1) + else + getpfx(@path) + prstr(@path) + crout() + fin + refnum = open(@path, iobuffer); + if perr + return perr + fin + firstblk = 1 + repeat + if read(refnum, databuff, 512) == 512 + entry = databuff + 4 + if firstblk + entrylen = databuff.$23 + entriesblk = databuff.$24 + filecnt = databuff:$25 + entry = entry + entrylen + fin + for i = firstblk to entriesblk + type = ^entry + if type <> 0 + len = type & $0F + ^entry = len + prstr(entry) + if type & $F0 == $D0 ; Is it a directory? + cout('/') + len = len + 1 + elsif (entry).$10 == $FF + cout('*') + len = len + 1 + fin + for len = 19 - len downto 0 + cout(' ') + next + filecnt = filecnt - 1 + fin + entry = entry + entrylen + next + firstblk = 0 + else + filecnt = 0 + fin + until filecnt == 0 + close(refnum) + crout() + return 0 +end +def stripchars(strptr) + while ^strptr and ^(strptr + 1) <> ' ' + memcpy(strptr + 2, strptr + 1, ^strptr) + ^strptr = ^strptr - 1 + loop + return ^strptr +end +def stripspaces(strptr) + while ^strptr and ^(strptr + ^strptr) <= ' ' + ^strptr = ^strptr - 1 + loop + while ^strptr and ^(strptr + 1) <= ' ' + memcpy(strptr + 2, strptr + 1, ^strptr) + ^strptr = ^strptr - 1 + loop +end +def striptrail(strptr) + byte i + + for i = 1 to ^strptr + if (strptr)[i] == ' ' + ^strptr = i - 1 + return + fin + next +end +def parsecmd(strptr) + byte cmd + + cmd = 0 + stripspaces(strptr) + if ^strptr + cmd = ^(strptr + 1) + memcpy(strptr + 2, strptr + 1, ^strptr) + ^strptr = ^strptr - 1 + fin + stripspaces(strptr) + return cmd +end +def resetmemfiles + ; + ; Close all files + ; + ^$BFD8 = 0 + close(0) + ; + ; Set memory bitmap + ; + memclr($BF58, 24) + ^$BF58 = $CF + ^$BF6F = $01 +end +def execsys(sysfile) + byte refnum + word len + + if ^sysfile + memcpy(sysfile, $280, ^sysfile + 1) + striptrail(sysfile) + refnum = open(sysfile, iobuffer) + if refnum + len = read(refnum, $2000, $FFFF) + resetmemfiles() + if len + memcpy($280, sysfile, ^$280 + 1) + if stripchars(sysfile) and ^$2000 == $4C and *$2003 == $EEEE + stripspaces(sysfile) + if ^$2006 <= ^sysfile + memcpy(sysfile, $2006, ^sysfile + 1) + fin + fin + striptrail($280) + exec() + fin + fin + fin +end + +resetmemfiles() +execsys(autorun) +prstr(@version) +crout(); +while 1 + prstr(getpfx(@prefix)) + cmdptr = rdstr($BA) + when toupper(parsecmd(cmdptr)) + is 'Q' + reboot() + is 'C' + catalog(cmdptr) + is 'P' + setpfx(cmdptr) + is 'V' + volumes(); + is '-' + execsys(cmdptr) + perr = $46 + wend + if perr + prstr(@errorstr) + prbyte(perr) + else + prstr(@okstr) + fin + crout() +loop +done \ No newline at end of file diff --git a/PLASMA/src/codegen.c b/PLASMA/src/codegen.c index 13ad12df..e0fe4d15 100755 --- a/PLASMA/src/codegen.c +++ b/PLASMA/src/codegen.c @@ -236,12 +236,22 @@ int fixup_new(int tag, int type, int size) /* * Emit assembly code. */ -#define BYTECODE_SEG 2 +#define BYTECODE_SEG 8 +#define INIT 16 static int outflags = 0; static char *DB = ".BYTE"; static char *DW = ".WORD"; static char *DS = ".RES"; static char LBL = ':'; +char *supper(char *s) +{ + static char su[80]; + int i; + for (i = 0; s[i]; i++) + su[i] = toupper(s[i]); + su[i] = '\0'; + return su; +} char *tag_string(int tag, int type) { static char str[16]; @@ -260,6 +270,17 @@ char *tag_string(int tag, int type) sprintf(str, "_%c%03d", t, tag); return str; } +void emit_dci(char *str, int len) +{ + if (len--) + { + printf("\t; DCI STRING: %s\n", supper(str)); + printf("\t%s\t$%02X", DB, toupper(*str++) | (len ? 0x80 : 0x00)); + while (len--) + printf(",$%02X", toupper(*str++) | (len ? 0x80 : 0x00)); + printf("\n"); + } +} void emit_flags(int flags) { outflags = flags; @@ -277,35 +298,83 @@ void emit_header(void) printf("; ACME COMPATIBLE OUTPUT\n"); else printf("; CA65 COMPATIBLE OUTPUT\n"); - printf("_SEGBEGIN%c\n", LBL); - printf("\t%s\t_SEGEND-_SEGBEGIN\t; LENGTH OF HEADER + CODE/DATA + BYTECODE SEGMENT\n", DW); - printf("\t%s\t$DA7E\t\t\t; MAGIC #\n", DW); - printf("\t%s\t_SUBSEG\t\t\t; BYTECODE SUB-SEGMENT\n", DW); + if (outflags & MODULE) + { + printf("_SEGBEGIN%c\n", LBL); + printf("\t%s\t_SEGEND-_SEGBEGIN\t; LENGTH OF HEADER + CODE/DATA + BYTECODE SEGMENT\n", DW); + printf("\t%s\t$DA7E\t\t\t; MAGIC #\n", DW); + printf("\t%s\t_SUBSEG\t\t\t; BYTECODE SUB-SEGMENT\n", DW); + printf("\t%s\t_INIT\t\t\t; MODULE INITIALIZATION ROUTINE\n", DW); + } +} +void emit_rld(void) +{ + int i; + + printf(";\n; RE-LOCATEABLE DICTIONARY\n;\n"); + /* + * First emit the bytecode definition entrypoint information. + */ + for (i = 0; i < globals; i++) + if (!(idglobal_type[i] & EXTERN_TYPE) && (idglobal_type[i] & DEF_TYPE)) + { + printf("\t%s\t$02\t\t\t; CODE TABLE FIXUP\n", DB); + printf("\t%s\t_C%03d\t\t\n", DW, idglobal_tag[i]); + printf("\t%s\t$00\n", DB); + } + /* + * Now emit the fixup table. + */ + for (i = 0; i < fixups; i++) + { + if (fixup_type[i] & EXTERN_TYPE) + { + printf("\t%s\t$%02X\t\t\t; EXTERNAL FIXUP\n", DB, 0x11 + fixup_size[i]); + printf("\t%s\t_F%03d\t\t\n", DW, i); + printf("\t%s\t%d\t\t\t; ESD INDEX\n", DB, fixup_tag[i]); + } + else + { + printf("\t%s\t$%02X\t\t\t; INTERNAL FIXUP\n", DB, 0x01 + fixup_size[i]); + printf("\t%s\t_F%03d\t\t\n", DW, i); + printf("\t%s\t$00\n", DB); + } + } + printf("\t%s\t$00\t\t\t; END OF RLD\n", DB); +} +void emit_esd(void) +{ + int i; + + printf(";\n; EXTERNAL/ENTRY SYMBOL DICTIONARY\n;\n"); + for (i = 0; i < globals; i++) + { + if (idglobal_type[i] & EXTERN_TYPE) + { + emit_dci(&idglobal_name[i][1], idglobal_name[i][0]); + printf("\t%s\t$10\t\t\t; EXTERNAL SYMBOL FLAG\n", DB); + printf("\t%s\t%d\t\t\t; ESD INDEX\n", DW, idglobal_tag[i]); + } + else if (idglobal_type[i] & EXPORT_TYPE) + { + emit_dci(&idglobal_name[i][1], idglobal_name[i][0]); + printf("\t%s\t$08\t\t\t; ENTRY SYMBOL FLAG\n", DB); + printf("\t%s\t%s\t\t\n", DW, tag_string(idglobal_tag[i], idglobal_type[i])); + } + } + printf("\t%s\t$00\t\t\t; END OF ESD\n", DB); } void emit_trailer(void) { if (!(outflags & BYTECODE_SEG)) emit_bytecode_seg(); - printf("_SEGEND%c\n", LBL); -} -char *supper(char *s) -{ - static char su[80]; - int i; - for (i = 0; s[i]; i++) - su[i] = toupper(s[i]); - su[i] = '\0'; - return su; -} -void emit_dci(char *str, int len) -{ - if (len--) + if (!(outflags & INIT)) + printf("_INIT\t=\t0\n"); + if (outflags & MODULE) { - printf("\t; DCI STRING: %s\n", supper(str)); - printf("\t%s\t$%02X", DB, toupper(*str++) | (len ? 0x80 : 0x00)); - while (len--) - printf(",$%02X", toupper(*str++) | (len ? 0x80 : 0x00)); - printf("\n"); + printf("_SEGEND%c\n", LBL); + emit_rld(); + emit_esd(); } } void emit_moddep(char *name, int len) @@ -317,7 +386,7 @@ void emit_moddep(char *name, int len) } void emit_bytecode_seg(void) { - if (!(outflags & BYTECODE_SEG)) + if ((outflags & MODULE) && !(outflags & BYTECODE_SEG)) printf("_SUBSEG%c\t\t\t\t; BYTECODE STARTS\n", LBL); outflags |= BYTECODE_SEG; } @@ -411,6 +480,19 @@ int emit_data(int vartype, int consttype, long constval, int constsize) } return (datasize); } +void emit_def(char *name, int is_bytecode) +{ + if (!(outflags & MODULE)) + { + printf("%s%c\n", name, LBL); + if (is_bytecode) + { + printf("\tJSR $03D0\n"); + printf("\t%s\t$00\n", DB); + printf("\t%s\t*+2\n", DW); + } + } +} void emit_codetag(int tag) { printf("_B%03d%c\n", tag, LBL); @@ -492,6 +574,20 @@ void emit_saw(int tag, int type) printf("\t%s\t$7A\t\t\t; SAW\t%s\n", DB, taglbl); printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl); } +void emit_sab_ofst(int tag, int offset, int type) +{ + int fixup = fixup_new(tag, type, FIXUP_WORD); + char *taglbl = tag_string(tag, type); + printf("\t%s\t$78\t\t\t; SAB\t%s\n", DB, taglbl); + printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl, offset); +} +void emit_saw_ofst(int tag, int offset, int type) +{ + int fixup = fixup_new(tag, type, FIXUP_WORD); + char *taglbl = tag_string(tag, type); + printf("\t%s\t$7A\t\t\t; SAW\t%s\n", DB, taglbl); + printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl, offset); +} void emit_dab(int tag, int type) { int fixup = fixup_new(tag, type, FIXUP_WORD); @@ -589,9 +685,6 @@ void emit_ret(void) { printf("\t%s\t$5C\t\t\t; RET\n", DB); } -void emit_def(int defopt) -{ -} void emit_enter(int framesize, int cparams) { if (framesize > 2) @@ -599,6 +692,8 @@ void emit_enter(int framesize, int cparams) } void emit_start(void) { + printf("_INIT%c\n", LBL); + outflags |= INIT; } void emit_dup(void) { @@ -716,60 +811,3 @@ int emit_op(t_token op) } return (1); } -void emit_rld(void) -{ - int i; - - printf(";\n; RE-LOCATEABLE DICTIONARY\n;\n"); - /* - * First emit the bytecode definition entrypoint information. - */ - for (i = 0; i < globals; i++) - if (!(idglobal_type[i] & EXTERN_TYPE) && (idglobal_type[i] & DEF_TYPE)) - { - printf("\t%s\t$02\t\t\t; CODE TABLE FIXUP\n", DB); - printf("\t%s\t_C%03d\t\t\n", DW, idglobal_tag[i]); - printf("\t%s\t$00\n", DB); - } - /* - * Now emit the fixup table. - */ - for (i = 0; i < fixups; i++) - { - if (fixup_type[i] & EXTERN_TYPE) - { - printf("\t%s\t$%02X\t\t\t; EXTERNAL FIXUP\n", DB, 0x11 + fixup_size[i]); - printf("\t%s\t_F%03d\t\t\n", DW, i); - printf("\t%s\t%d\t\t\t; ESD INDEX\n", DB, fixup_tag[i]); - } - else - { - printf("\t%s\t$%02X\t\t\t; INTERNAL FIXUP\n", DB, 0x01 + fixup_size[i]); - printf("\t%s\t_F%03d\t\t\n", DW, i); - printf("\t%s\t$00\n", DB); - } - } - printf("\t%s\t$00\t\t\t; END OF RLD\n", DB); -} -void emit_esd(void) -{ - int i; - - printf(";\n; EXTERNAL/ENTRY SYMBOL DICTIONARY\n;\n"); - for (i = 0; i < globals; i++) - { - if (idglobal_type[i] & EXTERN_TYPE) - { - emit_dci(&idglobal_name[i][1], idglobal_name[i][0]); - printf("\t%s\t$10\t\t\t; EXTERNAL SYMBOL FLAG\n", DB); - printf("\t%s\t%d\t\t\t; ESD INDEX\n", DW, idglobal_tag[i]); - } - else if (idglobal_type[i] & EXPORT_TYPE) - { - emit_dci(&idglobal_name[i][1], idglobal_name[i][0]); - printf("\t%s\t$08\t\t\t; ENTRY SYMBOL FLAG\n", DB); - printf("\t%s\t%s\t\t\n", DW, tag_string(idglobal_tag[i], idglobal_type[i])); - } - } - printf("\t%s\t$00\t\t\t; END OF ESD\n", DB); -} \ No newline at end of file diff --git a/PLASMA/src/codegen.h b/PLASMA/src/codegen.h index 667edee8..9ef4297f 100755 --- a/PLASMA/src/codegen.h +++ b/PLASMA/src/codegen.h @@ -1,4 +1,5 @@ #define ACME 1 +#define MODULE 2 void emit_flags(int flags); void emit_header(void); void emit_trailer(void); @@ -10,6 +11,7 @@ void emit_idlocal(char *name, int value); void emit_idglobal(int value, int size, char *name); void emit_idfunc(int tag, int type, char *name); void emit_idconst(char *name, int value); +void emit_def(char *name, int is_bytecode); int emit_data(int vartype, int consttype, long constval, int constsize); void emit_codetag(int tag); void emit_const(int cval); @@ -27,6 +29,8 @@ void emit_dlb(int index); void emit_dlw(int index); void emit_sab(int tag, int type); void emit_saw(int tag, int type); +void emit_sab_ofst(int tag, int offset, int type); +void emit_saw_ofst(int tag, int ofset, int type); void emit_dab(int tag, int type); void emit_daw(int tag, int type); void emit_call(int tag, int type); @@ -51,7 +55,6 @@ void emit_pull(void); void emit_drop(void); void emit_leave(int framesize); void emit_ret(void); -void emit_def(int defopt); void emit_enter(int framesize, int cparams); void emit_start(void); void emit_rld(void); diff --git a/PLASMA/src/loadcmd.s b/PLASMA/src/loadcmd.s new file mode 100644 index 00000000..7f95ead9 --- /dev/null +++ b/PLASMA/src/loadcmd.s @@ -0,0 +1,62 @@ +SRC = TMP +SRCL = SRC +SRCH = SRC+1 +DST = SRC+2 +DSTL = DST +DSTH = DST+1 +ESP = DST+2 + !PSEUDOPC $1000 { +;* +;* CLEAR COMMAND LINE LENGTH BYTE IF CALLED FROM 'BYE' +;* + LDY #$00 + LDX #$FE ; LEAVE ROOM FOR COMMAND LINE LENGTH BYTE + TXS + BVS + + STY $01FF ; CLEAR AUTORUN COMMAND WHEN CALLED FROM 'BYE' +;* +;* MOVE REST OF CMD FROM LANGUAGE CARD +;* ++ STY $06 + STY $08 + LDA #$D2 + STA $07 + LDA #$11 + STA $09 + BIT LCRDEN+LCBNK2 +- LDA ($06),Y + STA ($08),Y + INY + BNE - + INC $07 + INC $09 + LDA $07 + CMP #$E0 + BNE - +;* +;* DEACTIVATE 80 COL CARDS +;* + BIT ROMEN + LDY #4 +- LDA DISABLE80,Y + JSR $FDED + DEY + BPL - + BIT $C054 ; SET TEXT MODE + BIT $C051 + BIT $C058 + JSR $FC58 ; HOME +;* +;* JUMP TO INTERPRETER +;* + BIT LCRDEN+LCBNK2 + LDX #$00 + LDA #$BF + STX IFPL + STA IFPH + JSR INTERP + !BYTE 0 + !WORD START +DISABLE80 !BYTE 21, 13, '1', 26, 13 + !SOURCE "cmd.a" +} \ No newline at end of file diff --git a/PLASMA/src/makefile b/PLASMA/src/makefile index dc7d868f..af6aac25 100755 --- a/PLASMA/src/makefile +++ b/PLASMA/src/makefile @@ -32,15 +32,15 @@ $(PLVM): plvm.c cc plvm.c -o $(PLVM) TESTLIB: testlib.pla $(PLVM) $(PLASM) - ./$(PLASM) -A < testlib.pla > testlib.a + ./$(PLASM) -AM < testlib.pla > testlib.a acme --setpc 4096 -o TESTLIB testlib.a test: test.pla TESTLIB $(PLVM) $(PLASM) - ./$(PLASM) -A < test.pla > test.a + ./$(PLASM) -AM < test.pla > test.a acme --setpc 4096 -o TEST.BIN test.a ./$(PLVM) TEST.BIN MAIN debug: test.pla TESTLIB $(PLVM) $(PLASM) - ./$(PLASM) -A < test.pla > test.a + ./$(PLASM) -AM < test.pla > test.a acme --setpc 4096 -o TEST.BIN test.a ./$(PLVM) -s TEST.BIN MAIN diff --git a/PLASMA/src/parse.c b/PLASMA/src/parse.c index e49d90de..ca908b63 100755 --- a/PLASMA/src/parse.c +++ b/PLASMA/src/parse.c @@ -863,32 +863,54 @@ int parse_stmnt(void) case ID_TOKEN: idptr = tokenstr; type = id_type(tokenstr, tokenlen); - if (type & (VAR_TYPE | FUNC_TYPE)) + addr = id_tag(tokenstr, tokenlen); + if (type & VAR_TYPE) { - addr = id_tag(tokenstr, tokenlen); - if (scan() == SET_TOKEN) + int elem_type = type; + long elem_offset = 0; + if (scan() == DOT_TOKEN || scantoken == COLON_TOKEN) { - if (type & VAR_TYPE) - { - if (!parse_expr()) - { - parse_error("Bad expression"); - return (0); - } - if (type & LOCAL_TYPE) - (type & BYTE_TYPE) ? emit_slb(addr) : emit_slw(addr); - else - (type & BYTE_TYPE) ? emit_sab(addr, type) : emit_saw(addr, type); - break; - } + /* + * Structure member offset + */ + int elem_size; + elem_type = (scantoken == DOT_TOKEN) ? BYTE_TYPE : WORD_TYPE; + if (!parse_constval(&elem_offset, &elem_size)) + scantoken = ID_TOKEN; + else + scan(); + printf("Structure offset = %d\n", elem_offset); } - else if ((scantoken == EOL_TOKEN) && (type & FUNC_TYPE)) + if (scantoken == SET_TOKEN) + { + if (!parse_expr()) + { + parse_error("Bad expression"); + return (0); + } + if (type & LOCAL_TYPE) + (elem_type & BYTE_TYPE) ? emit_slb(addr + elem_offset) : emit_slw(addr + elem_offset); + else if (elem_offset) + (elem_type & BYTE_TYPE) ? emit_sab_ofst(addr, elem_offset, type) : emit_saw_ofst(addr, elem_offset, type); + else + (elem_type & BYTE_TYPE) ? emit_sab(addr, type) : emit_saw(addr, type); + break; + } + } + else if (type & FUNC_TYPE) + { + if (scan() == EOL_TOKEN) { emit_call(addr, type); emit_drop(); break; } } + else + { + parse_error("Syntax error"); + return (0); + } tokenstr = idptr; default: scan_rewind(tokenstr); @@ -1160,6 +1182,7 @@ int parse_defs(void) c = tokenstr[tokenlen]; tokenstr[tokenlen] = '\0'; emit_idfunc(func_tag, type, tokenstr); + emit_def(tokenstr, 1); tokenstr[tokenlen] = c; idlocal_reset(); if (scan() == OPEN_PAREN_TOKEN) @@ -1230,6 +1253,7 @@ int parse_defs(void) c = tokenstr[tokenlen]; tokenstr[tokenlen] = '\0'; emit_idfunc(func_tag, type, tokenstr); + emit_def(tokenstr, 0); tokenstr[tokenlen] = c; if (scan() == OPEN_PAREN_TOKEN) { @@ -1250,7 +1274,6 @@ int parse_defs(void) } scan(); } - emit_def(1); do { if (scantoken == EOL_TOKEN || scantoken == COMMENT_TOKEN) @@ -1288,7 +1311,5 @@ int parse_module(void) } } emit_trailer(); - emit_rld(); - emit_esd(); return (0); } diff --git a/PLASMA/src/plasm.c b/PLASMA/src/plasm.c index de5e0e01..24164569 100755 --- a/PLASMA/src/plasm.c +++ b/PLASMA/src/plasm.c @@ -6,12 +6,30 @@ int main(int argc, char **argv) { - - if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'A') - emit_flags(ACME); - if (parse_module()) - { - fprintf(stderr, "Compilation complete.\n"); + int j, i, flags = 0; + for (i = 1; i < argc; i++) + { + if (argv[i][0] == '-') + { + j = 1; + while (argv[i][j]) + { + switch(argv[i][j++]) + { + case 'A': + flags |= ACME; + break; + case 'M': + flags |= MODULE; + break; + } + } } - return (0); + } + emit_flags(flags); + if (parse_module()) + { + fprintf(stderr, "Compilation complete.\n"); + } + return (0); } diff --git a/PLASMA/src/plvm.c b/PLASMA/src/plvm.c index d8f0c700..99994db8 100755 --- a/PLASMA/src/plvm.c +++ b/PLASMA/src/plvm.c @@ -45,6 +45,10 @@ byte symtbl[SYMTBLSZ]; byte *lastsym = symtbl; byte modtbl[MODTBLSZ]; byte *lastmod = modtbl; +/* + * Predef. + */ +void interp(code *ip); /* * Utility routines. * @@ -269,7 +273,7 @@ int extern_lookup(byte *esd, int index) } int load_mod(byte *mod) { - int len, size, end, magic, bytecode, fixup, addr, modaddr = mark_heap(); + int len, size, end, magic, bytecode, fixup, addr, init = 0, modaddr = mark_heap(); byte *moddep, *rld, *esd, *cdd, *sym; byte header[128]; char filename[32], string[17]; @@ -286,7 +290,8 @@ int load_mod(byte *mod) * This is a relocatable bytecode module. */ bytecode = header[4] | (header[5] << 8); - moddep = header + 6; + init = header[6] | (header[7] << 8); + moddep = header + 8; if (*moddep) { /* @@ -329,6 +334,7 @@ int load_mod(byte *mod) printf("Module code+data size: %d\n", len); printf("Module magic: $%04X\n", magic); printf("Module bytecode: $%04X\n", bytecode); + printf("Module init: $%04X\n", init); } /* * Print out the Re-Location Dictionary. @@ -415,6 +421,14 @@ int load_mod(byte *mod) * Reserve heap space for relocated module. */ alloc_heap(end - modaddr); + /* + * Call init routine. + */ + if (init) + { + interp(mem_data + init + modaddr - MOD_ADDR); + POP; + } return (fd > 0); } void interp(code *ip); diff --git a/PLASMA/src/plvm02.s b/PLASMA/src/plvm02.s index 82b95981..5603aa6d 100644 --- a/PLASMA/src/plvm02.s +++ b/PLASMA/src/plvm02.s @@ -72,12 +72,97 @@ DVSIGN = TMPX CLD BIT LCRWEN+LCBNK2 BIT LCRWEN+LCBNK2 +;* +;* INSTALL PAGE 3 VECTORS +;* LDY #$10 - LDA PAGE3,Y STA $03D0,Y DEY BPL - +;* +;* MOVE VM INTO LANGUAGE CARD +;* + LDA #VMCORE + STA $07 + LDA #$00 + STA $08 + LDA #$D0 + STA $09 + LDY #$00 +- LDA ($06),Y ; COPY VM+CMD INTO LANGUAGE CARD + STA ($08),Y + INY + BNE - + INC $07 + INC $09 + LDA $09 + CMP #$E0 + BNE - +;* +;* INIT STACKS, FRAMES, AND HEAPS +;* + LDX #$FE + TXS + LDX #$00 + STX $01FF LDX #ESTKSZ/2 +;* +;* LOOK FOR STARTUP FILE +;* + JSR PRODOS ; OPEN AUTORUN + !BYTE $C8 + !WORD OPENPARMS + BCC + + JMP EXIT ++ LDA REFNUM + STA NLPARMS+1 + JSR PRODOS + !BYTE $C9 + !WORD NLPARMS + BCC + + JMP EXIT ++ LDA REFNUM + STA READPARMS+1 + JSR PRODOS + !BYTE $CA + !WORD READPARMS + BCC + + JMP EXIT ++ LDX READPARMS+6 + STX $01FF +EXIT JSR PRODOS + !BYTE $CC + !WORD CLOSEPARMS + LDY #$00 + STY $06 + LDA #$D1 + STA $07 +- LDA ($06),Y ; LOAD FIRST PAGE OF CMD INTO PLACE + STA $1000,Y + INY + BNE - + LDA #$7F + ADC #$01 ; SET V FLAG + JMP $1007 ; CALL CMD +AUTORUN !BYTE 7,"AUTORUN" +OPENPARMS !BYTE 3 + !WORD AUTORUN + !WORD $0800 +REFNUM !BYTE 0 +NLPARMS !BYTE 3 + !BYTE 0 + !BYTE $7F + !BYTE $0D +READPARMS !BYTE 4 + !BYTE 0 + !WORD $0200 + !WORD $0080 + !WORD 0 +CLOSEPARMS !BYTE 1 + !BYTE 0 PAGE3 = * !PSEUDOPC $03D0 { ;* @@ -90,7 +175,7 @@ CALLADR JSR $0000 BIT LCRDEN+LCBNK2 RTS } -PLASMA = * +VMCORE = * !PSEUDOPC $D000 { ;* ;* OPCODE TABLE @@ -104,6 +189,22 @@ OPTBL !WORD ZERO,ADD,SUB,MUL,DIV,MOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E !WORD LB,LW,LLB,LLW,LAB,LAW,DLB,DLW ; 60 62 64 66 68 6A 6C 6E !WORD SB,SW,SLB,SLW,SAB,SAW,DAB,DAW ; 70 72 74 76 78 7A 7C 7E ;* +;* OPXCODE TABLE +;* +OPXTBL !WORD ZEROX,ADDX,SUBX,MULX,DIVX,MODX,INCRX,DECRX ; 00 02 04 06 08 0A 0C 0E + !WORD NEGX,COMPX,BANDX,IORX,XORX,SHLX,SHRX,IDXWX ; 10 12 14 16 18 1A 1C 1E + !WORD LNOTX,LORX,LANDX,LAX,LLAX,CBX,CWX,SWAPX ; 20 22 24 26 28 2A 2C 2E + !WORD DROPX,DUPX,PUSHX,PULLX,BRLTX,BRGTX,BREQX,BRNEX ; 30 32 34 36 38 3A 3C 3E + !WORD ISEQX,ISNEX,ISGTX,ISLTX,ISGEX,ISLEX,BRFLSX,BRTRUX; 40 42 44 46 48 4A 4C 4E + !WORD BRNCHX,IBRNCHX,CALLX,ICALX,ENTERX,LEAVEX,RETX,NEXTOPX; 50 52 54 56 58 5A 5C 5E + !WORD LBX,LWX,LLBX,LLWX,LABX,LAWX,DLBX,DLWX ; 60 62 64 66 68 6A 6C 6E + !WORD SBX,SWX,SLBX,SLWX,SABX,SAWX,DABX,DAWX ; 70 72 74 76 78 7A 7C 7E +;* +;* COMMAND PROCESSING +;* + !SOURCE loadcmd.s +; !BINARY CMDLINE.BIN +;* ;* ENTER INTO BYTECODE INTERPRETER ;* INTERP PLA @@ -145,24 +246,10 @@ NEXTOPX CLI FETCHOPX SEI STA ALTRDON LDA (IP),Y + ORA #$80 ; SELECT OPX OPCODES STA *+5 JMP (OPXTBL) ;* -;* ALIGN TO NEXT PAGE -;* - !ALIGN 255, 0 -;* -;* OPXCODE TABLE -;* -OPXTBL !WORD ZEROX,ADDX,SUBX,MULX,DIVX,MODX,INCRX,DECRX ; 00 02 04 06 08 0A 0C 0E - !WORD NEGX,COMPX,BANDX,IORX,XORX,SHLX,SHRX,IDXWX ; 10 12 14 16 18 1A 1C 1E - !WORD LNOTX,LORX,LANDX,LAX,LLAX,CBX,CWX,SWAPX ; 20 22 24 26 28 2A 2C 2E - !WORD DROPX,DUPX,PUSHX,PULLX,BRLTX,BRGTX,BREQX,BRNEX ; 30 32 34 36 38 3A 3C 3E - !WORD ISEQX,ISNEX,ISGTX,ISLTX,ISGEX,ISLEX,BRFLSX,BRTRUX; 40 42 44 46 48 4A 4C 4E - !WORD BRNCHX,IBRNCHX,CALLX,ICALX,ENTERX,LEAVEX,RETX,NEXTOPX; 50 52 54 56 58 5A 5C 5E - !WORD LBX,LWX,LLBX,LLWX,LABX,LAWX,DLBX,DLWX ; 60 62 64 66 68 6A 6C 6E - !WORD SBX,SWX,SLBX,SLWX,SABX,SAWX,DABX,DAWX ; 70 72 74 76 78 7A 7C 7E -;* ;* ADD TOS TO TOS-1 ;* ADD LDA ESTKL,X diff --git a/PLASMA/src/samplib.s b/PLASMA/src/samplib.s index 210ed6a8..8f837e96 100755 --- a/PLASMA/src/samplib.s +++ b/PLASMA/src/samplib.s @@ -13,6 +13,7 @@ _SEGBEGIN ; !WORD $DA7E ; MAGIC # !WORD _SUBSEG ; BYTECODE SUB-SEGMENT + !WORD _INIT ; BYTECODE INIT ROUTINE ; ; MODULE DEPENDENCY LIST ; NOTE: DCI = PSUEDO OP FOR ASCII STRING WITH HI BIT SET EXCEPT LAST CHAR @@ -59,6 +60,8 @@ FIXUP7 !WORD $0000 !BYTE $54 ; CALL INCNT FIXUP8 !WORD $0000 !BYTE $5A ; LEAVE +_INIT + !BYTE $5C ; RET ; ; END OF CODE/DATA + BYTECODE SEGMENT ; diff --git a/PLASMA/src/test.pla b/PLASMA/src/test.pla index 454a3d11..2d78516f 100755 --- a/PLASMA/src/test.pla +++ b/PLASMA/src/test.pla @@ -49,4 +49,5 @@ export def indirect mainptr() end +ascii done diff --git a/PLASMA/src/testlib.pla b/PLASMA/src/testlib.pla index 4e4dda9b..737ecaef 100755 --- a/PLASMA/src/testlib.pla +++ b/PLASMA/src/testlib.pla @@ -4,6 +4,7 @@ import stdlib predef cls, gotoxy, puts, putc end +byte loadstr[] = "testlib loaded!\n" ; ; Define functions. ; @@ -20,4 +21,5 @@ export def puti(i) fin end +puts(@loadstr); done From 689e0542cee072c8c51d0ab273758b2f8a5260de Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 6 May 2014 19:18:36 -0700 Subject: [PATCH 36/44] simple command launch for BYE command --- PLASMA/src/cmd.pla | 29 ++--- PLASMA/src/cmdexec.pla | 234 +++++++++++++++++++++++++++++++++++++++++ PLASMA/src/codegen.c | 6 ++ PLASMA/src/loadcmd.s | 62 ----------- PLASMA/src/makefile | 11 +- PLASMA/src/parse.c | 1 - PLASMA/src/plvm02.s | 175 +++++++++++++++++++----------- 7 files changed, 373 insertions(+), 145 deletions(-) create mode 100644 PLASMA/src/cmdexec.pla delete mode 100644 PLASMA/src/loadcmd.s diff --git a/PLASMA/src/cmd.pla b/PLASMA/src/cmd.pla index 92894936..dabe7ec7 100644 --- a/PLASMA/src/cmd.pla +++ b/PLASMA/src/cmd.pla @@ -37,8 +37,9 @@ end ; CALL LOADED SYSTEM PROGRAM ; asm exec - LDX #$FF + LDX #$FE TXS + LDX ESTKSZ/2 BIT ROMEN JMP $2000 end @@ -64,8 +65,7 @@ SETMLP DEC ESTKL,X BNE SETMLP INC DSTH BNE SETMLP -+ INX - INX +++ INX RTS end ; @@ -139,7 +139,6 @@ FORCPYLP DEC ESTKH,X BNE FORCPYLP MEMEXIT INX - INX INX RTS end @@ -149,11 +148,9 @@ end ; asm cout LDA ESTKL,X - INX ORA #$80 - BIT ROMIN + BIT ROMEN JSR $FDED - BIT LCBNK2 RTS end ; @@ -161,11 +158,10 @@ end ; RDKEY() ; asm cin - BIT ROMIN + BIT ROMEN STX ESP JSR $FD0C LDX ESP - BIT LCBNK2 DEX STA ESTKL,X LDY #$00 @@ -182,7 +178,7 @@ asm prstr STA SRCL LDA ESTKH,X STA SRCH - BIT ROMIN + BIT ROMEN LDA (SRC),Y STA ESTKL,X BEQ + @@ -193,20 +189,16 @@ asm prstr TYA CMP ESTKL,X BNE - -+ INX - BIT LCBNK2 - RTS ++ RTS end ; ; PRINT BYTE ; asm prbyte LDA ESTKL,X - INX STX ESP - BIT ROMIN + BIT ROMEN JSR $FDDA - BIT LCBNK2 LDX ESP RTS end @@ -218,9 +210,8 @@ asm rdstr LDA ESTKL,X STA $33 STX ESP - BIT ROMIN + BIT ROMEN JSR $FD6A - BIT LCBNK2 STX $01FF - LDA $01FF,X AND #$7F @@ -249,7 +240,7 @@ end ; EXIT ; asm reboot - BIT ROMIN + BIT ROMEN LDA #$00 STA $3F4 ; INVALIDATE POWER-UP BYTE JMP ($FFFC) ; RESET diff --git a/PLASMA/src/cmdexec.pla b/PLASMA/src/cmdexec.pla new file mode 100644 index 00000000..6a12c377 --- /dev/null +++ b/PLASMA/src/cmdexec.pla @@ -0,0 +1,234 @@ +const iobuffer = $0800 +const databuff = $0C00 +const memmap = $BF58 +const autorun = $01FF +byte cmdline[] = "CMD" +word cmd = @cmdline +byte syshalt[] = "SYSTEM HALTED..." +byte perr + +; +; Utility functions +; +; CALL PRODOS +; SYSCALL(CMD, PARAMS) +; +asm prodos + LDA ESTKL,X + LDY ESTKH,X + STA PARAMS + STY PARAMS+1 + INX + LDA ESTKL,X + STA CMD + STX ESP + JSR $BF00 +CMD: !BYTE 00 +PARAMS: !WORD 0000 + LDX ESP + STA ESTKL,X + LDY #$00 + STY ESTKH,X + RTS +end +; +; CALL LOADED SYSTEM PROGRAM +; +asm exec + LDX #$FE + TXS + LDX ESTKSZ/2 + BIT ROMEN + JMP $2000 +end +; +; SET MEMORY TO 0 +; MEMCLR(ADDR, SIZE) +; +asm memclr + LDY #$00 + LDA ESTKL+1,X + STA DSTL + LDA ESTKH+1,X + STA DSTH + INC ESTKL,X + INC ESTKH,X + TYA +SETMLP DEC ESTKL,X + BNE + + DEC ESTKH,X + BEQ ++ ++ STA (DST),Y + INY + BNE SETMLP + INC DSTH + BNE SETMLP +++ INX + RTS +end +; +; COPY MEMORY +; MEMCPY(DSTADDR, SRCADDR, SIZE) +; +asm memcpy + LDY #$00 + LDA ESTKL,X + BNE + + LDA ESTKH,X + BEQ MEMEXIT ++ LDA ESTKL+2,X + STA DSTL + LDA ESTKH+2,X + STA DSTH + LDA ESTKL+1,X + STA SRCL + LDA ESTKH+1,X + STA SRCH + INC ESTKH,X +CPYLP LDA (SRC),Y + STA (DST),Y + INC DSTL + BNE + + INC DSTH ++ INC SRCL + BNE + + INC SRCH ++ DEC ESTKL,X + BNE CPYLP + DEC ESTKH,X + BNE CPYLP +MEMEXIT INX + INX + RTS +end +; +; CHAR OUT +; COUT(CHAR) +; +asm cout + LDA ESTKL,X + ORA #$80 + BIT ROMEN + JSR $FDED + RTS +end +; +; CHAR IN +; RDKEY() +; +asm cin + BIT ROMEN + STX ESP + JSR $FD0C + LDX ESP + DEX + STA ESTKL,X + LDY #$00 + STY ESTKH,X + RTS +end +; +; PRINT STRING +; PRSTR(STR) +; +asm prstr + LDY #$00 + LDA ESTKL,X + STA SRCL + LDA ESTKH,X + STA SRCH + BIT ROMEN + LDA (SRC),Y + STA ESTKL,X + BEQ + +- INY + LDA (SRC),Y + ORA #$80 + JSR $FDED + TYA + CMP ESTKL,X + BNE - ++ RTS +end +; +; EXIT +; +asm reboot + BIT ROMEN + LDA #$00 + STA $3F4 ; INVALIDATE POWER-UP BYTE + JMP ($FFFC) ; RESET +end +def crout + cout($0D) +end +; +; ProDOS routines +; +def open(path, buff) + byte params[6] + + params.0 = 3 + params:1 = path + params:3 = buff + params.5 = 0 + perr = prodos($C8, @params) + return params.5 +end +def close(refnum) + byte params[2] + + params.0 = 1 + params.1 = refnum + perr = prodos($CC, @params) + return perr +end +def read(refnum, buff, len) + byte params[8] + + params.0 = 4 + params.1 = refnum + params:2 = buff + params:4 = len + params:6 = 0 + perr = prodos($CA, @params) + return params:6 +end +def resetmemfiles + ; + ; Close all files + ; + ^$BFD8 = 0 + close(0) + ; + ; Set memory bitmap + ; + memclr(memmap, 24) + ^memmap.0 = $CF + ^memmap.23 = $01 +end +def execsys(sysfile) + byte refnum + + if ^sysfile + memcpy($280, sysfile, ^sysfile + 1) + refnum = open(sysfile, iobuffer) + if refnum + if read(refnum, $2000, $FFFF) + resetmemfiles() + memcpy($280, sysfile, ^$280 + 1) + exec() + fin + fin + fin +end + +resetmemfiles() +if ^autorun + cmd = autorun +fin +execsys(cmd) +prstr(@syshalt) +cin() +reboot() +done \ No newline at end of file diff --git a/PLASMA/src/codegen.c b/PLASMA/src/codegen.c index e0fe4d15..9b58a3b5 100755 --- a/PLASMA/src/codegen.c +++ b/PLASMA/src/codegen.c @@ -306,6 +306,12 @@ void emit_header(void) printf("\t%s\t_SUBSEG\t\t\t; BYTECODE SUB-SEGMENT\n", DW); printf("\t%s\t_INIT\t\t\t; MODULE INITIALIZATION ROUTINE\n", DW); } + else + { + printf("\tJSR\t$3D0\n"); + printf("\t%s\t$00\t\t\t; MODULE INITIALIZATION ROUTINE\n", DB); + printf("\t%s\t_INIT\t\t\t;\n", DW); + } } void emit_rld(void) { diff --git a/PLASMA/src/loadcmd.s b/PLASMA/src/loadcmd.s deleted file mode 100644 index 7f95ead9..00000000 --- a/PLASMA/src/loadcmd.s +++ /dev/null @@ -1,62 +0,0 @@ -SRC = TMP -SRCL = SRC -SRCH = SRC+1 -DST = SRC+2 -DSTL = DST -DSTH = DST+1 -ESP = DST+2 - !PSEUDOPC $1000 { -;* -;* CLEAR COMMAND LINE LENGTH BYTE IF CALLED FROM 'BYE' -;* - LDY #$00 - LDX #$FE ; LEAVE ROOM FOR COMMAND LINE LENGTH BYTE - TXS - BVS + - STY $01FF ; CLEAR AUTORUN COMMAND WHEN CALLED FROM 'BYE' -;* -;* MOVE REST OF CMD FROM LANGUAGE CARD -;* -+ STY $06 - STY $08 - LDA #$D2 - STA $07 - LDA #$11 - STA $09 - BIT LCRDEN+LCBNK2 -- LDA ($06),Y - STA ($08),Y - INY - BNE - - INC $07 - INC $09 - LDA $07 - CMP #$E0 - BNE - -;* -;* DEACTIVATE 80 COL CARDS -;* - BIT ROMEN - LDY #4 -- LDA DISABLE80,Y - JSR $FDED - DEY - BPL - - BIT $C054 ; SET TEXT MODE - BIT $C051 - BIT $C058 - JSR $FC58 ; HOME -;* -;* JUMP TO INTERPRETER -;* - BIT LCRDEN+LCBNK2 - LDX #$00 - LDA #$BF - STX IFPL - STA IFPH - JSR INTERP - !BYTE 0 - !WORD START -DISABLE80 !BYTE 21, 13, '1', 26, 13 - !SOURCE "cmd.a" -} \ No newline at end of file diff --git a/PLASMA/src/makefile b/PLASMA/src/makefile index af6aac25..9683aa75 100755 --- a/PLASMA/src/makefile +++ b/PLASMA/src/makefile @@ -2,6 +2,7 @@ AFLAGS = -o $@ LFLAGS = -C default.cfg PLVM = plvm +PLVM02 = PLVM02.SYS PLASM = plasm INCS = tokens.h symbols.h lex.h parse.h codegen.h OBJS = plasm.c parse.o lex.o codegen.o @@ -20,10 +21,10 @@ TXTTYPE = .TXT #SYSTYPE = \#ff0000 #TXTTYPE = \#040000 -all: $(PLASM) $(PLVM) TESTLIB +all: $(PLASM) $(PLVM) $(PLVM02) TESTLIB clean: - -rm *.o *~ *.a *.BIN TESTLIB $(PLASM) $(PLVM) + -rm *.o *~ *.a *.SYM *.SYS *.BIN TESTLIB $(PLASM) $(PLVM) $(PLASM): $(OBJS) $(INCS) cc $(OBJS) -o $(PLASM) @@ -31,6 +32,12 @@ $(PLASM): $(OBJS) $(INCS) $(PLVM): plvm.c cc plvm.c -o $(PLVM) +cmdexec.a: cmdexec.pla $(PLASM) + ./$(PLASM) -A < cmdexec.pla > cmdexec.a + +$(PLVM02): plvm02.s cmdexec.a + acme -o $(PLVM02) -l PLVM02.SYM plvm02.s + TESTLIB: testlib.pla $(PLVM) $(PLASM) ./$(PLASM) -AM < testlib.pla > testlib.a acme --setpc 4096 -o TESTLIB testlib.a diff --git a/PLASMA/src/parse.c b/PLASMA/src/parse.c index ca908b63..a5eafe79 100755 --- a/PLASMA/src/parse.c +++ b/PLASMA/src/parse.c @@ -879,7 +879,6 @@ int parse_stmnt(void) scantoken = ID_TOKEN; else scan(); - printf("Structure offset = %d\n", elem_offset); } if (scantoken == SET_TOKEN) { diff --git a/PLASMA/src/plvm02.s b/PLASMA/src/plvm02.s index 5603aa6d..35562840 100644 --- a/PLASMA/src/plvm02.s +++ b/PLASMA/src/plvm02.s @@ -42,7 +42,7 @@ VMZP = ESTK+ESTKSZ IFP = VMZP IFPL = IFP IFPH = IFP+1 -IP = IFP+2 +IP = IFP+2 IPL = IP IPH = IP+1 IPY = IP+2 @@ -53,6 +53,13 @@ TMPX = TMP+2 NPARMS = TMPL FRMSZ = TMPH DVSIGN = TMPX +SRC = $06 +SRCL = SRC +SRCH = SRC+1 +DST = SRC+2 +DSTL = DST +DSTH = DST+1 +ESP = DST+2 ;********************************************************** ;* ;* INTERPRETER INSTRUCTION POINTER INCREMENT MACRO @@ -69,9 +76,8 @@ DVSIGN = TMPX ;* ;*********************************************** * = $2000 - CLD - BIT LCRWEN+LCBNK2 - BIT LCRWEN+LCBNK2 + LDX #$FE + TXS ;* ;* INSTALL PAGE 3 VECTORS ;* @@ -83,86 +89,81 @@ DVSIGN = TMPX ;* ;* MOVE VM INTO LANGUAGE CARD ;* + BIT LCRWEN+LCBNK2 + BIT LCRWEN+LCBNK2 LDA #VMCORE - STA $07 + STA SRCH LDA #$00 - STA $08 + STA DSTL LDA #$D0 - STA $09 + STA DSTH LDY #$00 -- LDA ($06),Y ; COPY VM+CMD INTO LANGUAGE CARD - STA ($08),Y +- LDA (SRC),Y ; COPY VM+CMD INTO LANGUAGE CARD + STA (DST),Y INY BNE - - INC $07 - INC $09 - LDA $09 + INC SRCH + INC DSTH + LDA DSTH CMP #$E0 BNE - ;* -;* INIT STACKS, FRAMES, AND HEAPS -;* - LDX #$FE - TXS - LDX #$00 - STX $01FF - LDX #ESTKSZ/2 -;* ;* LOOK FOR STARTUP FILE ;* - JSR PRODOS ; OPEN AUTORUN - !BYTE $C8 - !WORD OPENPARMS - BCC + - JMP EXIT -+ LDA REFNUM - STA NLPARMS+1 - JSR PRODOS - !BYTE $C9 - !WORD NLPARMS - BCC + - JMP EXIT -+ LDA REFNUM - STA READPARMS+1 - JSR PRODOS - !BYTE $CA - !WORD READPARMS - BCC + - JMP EXIT -+ LDX READPARMS+6 - STX $01FF -EXIT JSR PRODOS - !BYTE $CC - !WORD CLOSEPARMS + JSR PRODOS ; OPEN AUTORUN + !BYTE $C8 + !WORD OPENPARMS + BCC + + JMP NOAUTO ++ LDA REFNUM + STA NLPARMS+1 + JSR PRODOS + !BYTE $C9 + !WORD NLPARMS + BCC + + JMP NOAUTO ++ LDA REFNUM + STA READPARMS+1 + JSR PRODOS + !BYTE $CA + !WORD READPARMS + BCC + + JMP NOAUTO ++ LDX READPARMS+6 + STX $01FF +NOAUTO JSR PRODOS + !BYTE $CC + !WORD CLOSEPARMS LDY #$00 - STY $06 + STY SRCL LDA #$D1 - STA $07 -- LDA ($06),Y ; LOAD FIRST PAGE OF CMD INTO PLACE + STA SRCH +- LDA (SRC),Y ; LOAD FIRST PAGE OF CMD INTO PLACE STA $1000,Y INY BNE - LDA #$7F ADC #$01 ; SET V FLAG JMP $1007 ; CALL CMD -AUTORUN !BYTE 7,"AUTORUN" +AUTORUN !BYTE 7 + !TEXT "AUTORUN" OPENPARMS !BYTE 3 - !WORD AUTORUN - !WORD $0800 + !WORD AUTORUN + !WORD $0800 REFNUM !BYTE 0 NLPARMS !BYTE 3 - !BYTE 0 - !BYTE $7F - !BYTE $0D + !BYTE 0 + !BYTE $7F + !BYTE $0D READPARMS !BYTE 4 - !BYTE 0 - !WORD $0200 - !WORD $0080 - !WORD 0 + !BYTE 0 + !WORD $0200 + !WORD $0080 + !WORD 0 CLOSEPARMS !BYTE 1 - !BYTE 0 + !BYTE 0 PAGE3 = * !PSEUDOPC $03D0 { ;* @@ -202,8 +203,59 @@ OPXTBL !WORD ZEROX,ADDX,SUBX,MULX,DIVX,MODX,INCRX,DECRX ; 00 02 04 06 08 0 ;* ;* COMMAND PROCESSING ;* - !SOURCE loadcmd.s -; !BINARY CMDLINE.BIN + !PSEUDOPC $1000 { +;* +;* CLEAR COMMAND LINE LENGTH BYTE IF CALLED FROM 'BYE' +;* + LDY #$00 + LDX #$FE ; LEAVE ROOM FOR COMMAND LINE LENGTH BYTE + TXS + BVS + + STY $01FF ; CLEAR AUTORUN COMMAND WHEN CALLED FROM 'BYE' +;* +;* MOVE REST OF CMD FROM LANGUAGE CARD +;* ++ STY SRCL + STY DSTL + LDA #$D2 + STA SRCH + LDA #$11 + STA DSTH + BIT LCRDEN+LCBNK2 +- LDA (SRC),Y + STA (DST),Y + INY + BNE - + INC SRCL + INC DSTL + LDA SRCL + CMP #$E0 + BNE - +;* +;* DEACTIVATE 80 COL CARDS +;* + BIT ROMEN + LDY #4 +- LDA DISABLE80,Y + JSR $FDED + DEY + BPL - + BIT $C054 ; SET TEXT MODE + BIT $C051 + BIT $C058 + JSR $FC58 ; HOME + JMP START +DISABLE80 !BYTE 21, 13, '1', 26, 13 +;* +;* JUMP TO INTERPRETER +;* +START LDA #$00 + STA IFPL + LDA #$BF + STA IFPH + LDX ESTKSZ/2 + !SOURCE "cmdexec.a" +} ;* ;* ENTER INTO BYTECODE INTERPRETER ;* @@ -1872,4 +1924,5 @@ LEAVEX STA ALTRDOFF RETX STA ALTRDOFF CLI RTS +VMEND = * } \ No newline at end of file From f0b629510e0ba7bc0b6862a1e369db8755897b8f Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 6 May 2014 20:19:59 -0700 Subject: [PATCH 37/44] Prepare for boot.. --- PLASMA/src/cmd.pla | 51 +++++++++++++++++++++++++++++++++--------- PLASMA/src/cmdexec.pla | 17 ++++++-------- PLASMA/src/makefile | 7 +++++- PLASMA/src/plvm02.s | 25 ++++++++++++--------- 4 files changed, 67 insertions(+), 33 deletions(-) diff --git a/PLASMA/src/cmd.pla b/PLASMA/src/cmd.pla index dabe7ec7..d4984e58 100644 --- a/PLASMA/src/cmd.pla +++ b/PLASMA/src/cmd.pla @@ -1,6 +1,5 @@ const iobuffer = $0800 const databuff = $0C00 -const autorun = $01FF byte version[] = "PLASMA VM VERSION 0.9" byte errorstr[] = "ERROR: $" byte okstr[] = "OK" @@ -11,6 +10,39 @@ word cmdptr ; ; Utility functions ; +asm equates +;* +;* BANK SWITCHED MEM +;* +LCRDEN = $C080 +LCWTEN = $C081 +ROMEN = $C082 +LCRWEN = $C083 +LCBNK2 = $00 +LCBNK1 = $08 +;* +;* ZERO PAGE USEAGE +;* +ESTKSZ = $20 +ESTK = $C0 +ESTKL = ESTK +ESTKH = ESTK+ESTKSZ/2 +VMZP = ESTK+ESTKSZ +IFP = VMZP +IFPL = IFP +IFPH = IFP+1 +IP = IFP+2 +IPL = IP +IPH = IP+1 +IPY = IP+2 +SRC = $06 +SRCL = SRC +SRCH = SRC+1 +DST = SRC+2 +DSTL = DST +DSTH = DST+1 +ESP = DST+2 +end ; CALL PRODOS ; SYSCALL(CMD, PARAMS) ; @@ -26,7 +58,6 @@ asm prodos JSR $BF00 CMD: !BYTE 00 PARAMS: !WORD 0000 - BIT LCBNK2 LDX ESP STA ESTKL,X LDY #$00 @@ -40,7 +71,6 @@ asm exec LDX #$FE TXS LDX ESTKSZ/2 - BIT ROMEN JMP $2000 end ; @@ -333,7 +363,7 @@ def catalog(optpath) word entry, filecnt if ^optpath - memcpy(optpath, @path, ^optpath + 1) + memcpy(@path, optpath, ^optpath + 1) else getpfx(@path) prstr(@path) @@ -384,7 +414,7 @@ def catalog(optpath) end def stripchars(strptr) while ^strptr and ^(strptr + 1) <> ' ' - memcpy(strptr + 2, strptr + 1, ^strptr) + memcpy(strptr + 1, strptr + 2, ^strptr) ^strptr = ^strptr - 1 loop return ^strptr @@ -394,7 +424,7 @@ def stripspaces(strptr) ^strptr = ^strptr - 1 loop while ^strptr and ^(strptr + 1) <= ' ' - memcpy(strptr + 2, strptr + 1, ^strptr) + memcpy(strptr + 1, strptr + 2, ^strptr) ^strptr = ^strptr - 1 loop end @@ -415,7 +445,7 @@ def parsecmd(strptr) stripspaces(strptr) if ^strptr cmd = ^(strptr + 1) - memcpy(strptr + 2, strptr + 1, ^strptr) + memcpy(strptr + 1, strptr + 2, ^strptr) ^strptr = ^strptr - 1 fin stripspaces(strptr) @@ -439,18 +469,18 @@ def execsys(sysfile) word len if ^sysfile - memcpy(sysfile, $280, ^sysfile + 1) + memcpy($280, sysfile, ^sysfile + 1) striptrail(sysfile) refnum = open(sysfile, iobuffer) if refnum len = read(refnum, $2000, $FFFF) resetmemfiles() if len - memcpy($280, sysfile, ^$280 + 1) + memcpy(sysfile, $280, ^$280 + 1) if stripchars(sysfile) and ^$2000 == $4C and *$2003 == $EEEE stripspaces(sysfile) if ^$2006 <= ^sysfile - memcpy(sysfile, $2006, ^sysfile + 1) + memcpy($2006, sysfile, ^sysfile + 1) fin fin striptrail($280) @@ -461,7 +491,6 @@ def execsys(sysfile) end resetmemfiles() -execsys(autorun) prstr(@version) crout(); while 1 diff --git a/PLASMA/src/cmdexec.pla b/PLASMA/src/cmdexec.pla index 6a12c377..600ceeb1 100644 --- a/PLASMA/src/cmdexec.pla +++ b/PLASMA/src/cmdexec.pla @@ -1,9 +1,7 @@ const iobuffer = $0800 const databuff = $0C00 const memmap = $BF58 -const autorun = $01FF -byte cmdline[] = "CMD" -word cmd = @cmdline +const sysfile = $0280 byte syshalt[] = "SYSTEM HALTED..." byte perr @@ -35,6 +33,10 @@ end ; CALL LOADED SYSTEM PROGRAM ; asm exec + LDA #$00 + STA IFPL + LDA #$BF + STA IFPH LDX #$FE TXS LDX ESTKSZ/2 @@ -207,16 +209,14 @@ def resetmemfiles ^memmap.0 = $CF ^memmap.23 = $01 end -def execsys(sysfile) +def execsys byte refnum if ^sysfile - memcpy($280, sysfile, ^sysfile + 1) refnum = open(sysfile, iobuffer) if refnum if read(refnum, $2000, $FFFF) resetmemfiles() - memcpy($280, sysfile, ^$280 + 1) exec() fin fin @@ -224,10 +224,7 @@ def execsys(sysfile) end resetmemfiles() -if ^autorun - cmd = autorun -fin -execsys(cmd) +execsys prstr(@syshalt) cin() reboot() diff --git a/PLASMA/src/makefile b/PLASMA/src/makefile index 9683aa75..6cd3e6bf 100755 --- a/PLASMA/src/makefile +++ b/PLASMA/src/makefile @@ -3,6 +3,7 @@ AFLAGS = -o $@ LFLAGS = -C default.cfg PLVM = plvm PLVM02 = PLVM02.SYS +CMD = CMD.SYS PLASM = plasm INCS = tokens.h symbols.h lex.h parse.h codegen.h OBJS = plasm.c parse.o lex.o codegen.o @@ -21,7 +22,7 @@ TXTTYPE = .TXT #SYSTYPE = \#ff0000 #TXTTYPE = \#040000 -all: $(PLASM) $(PLVM) $(PLVM02) TESTLIB +all: $(PLASM) $(PLVM) $(PLVM02) $(CMD) TESTLIB clean: -rm *.o *~ *.a *.SYM *.SYS *.BIN TESTLIB $(PLASM) $(PLVM) @@ -38,6 +39,10 @@ cmdexec.a: cmdexec.pla $(PLASM) $(PLVM02): plvm02.s cmdexec.a acme -o $(PLVM02) -l PLVM02.SYM plvm02.s +$(CMD): cmd.pla $(PLVM) $(PLASM) + ./$(PLASM) -A < cmd.pla > cmd.a + acme --setpc 8192 -o $(CMD) cmd.a + TESTLIB: testlib.pla $(PLVM) $(PLASM) ./$(PLASM) -AM < testlib.pla > testlib.a acme --setpc 4096 -o TESTLIB testlib.a diff --git a/PLASMA/src/plvm02.s b/PLASMA/src/plvm02.s index 35562840..c7ddac05 100644 --- a/PLASMA/src/plvm02.s +++ b/PLASMA/src/plvm02.s @@ -76,7 +76,7 @@ ESP = DST+2 ;* ;*********************************************** * = $2000 - LDX #$FE + LDX #$FF TXS ;* ;* INSTALL PAGE 3 VECTORS @@ -132,7 +132,7 @@ ESP = DST+2 BCC + JMP NOAUTO + LDX READPARMS+6 - STX $01FF + STX $0280 NOAUTO JSR PRODOS !BYTE $CC !WORD CLOSEPARMS @@ -144,9 +144,7 @@ NOAUTO JSR PRODOS STA $1000,Y INY BNE - - LDA #$7F - ADC #$01 ; SET V FLAG - JMP $1007 ; CALL CMD + JMP CMDEXEC ; CALL CMD AUTORUN !BYTE 7 !TEXT "AUTORUN" OPENPARMS !BYTE 3 @@ -159,7 +157,7 @@ NLPARMS !BYTE 3 !BYTE $0D READPARMS !BYTE 4 !BYTE 0 - !WORD $0200 + !WORD $0281 !WORD $0080 !WORD 0 CLOSEPARMS !BYTE 1 @@ -201,21 +199,24 @@ OPXTBL !WORD ZEROX,ADDX,SUBX,MULX,DIVX,MODX,INCRX,DECRX ; 00 02 04 06 08 0 !WORD LBX,LWX,LLBX,LLWX,LABX,LAWX,DLBX,DLWX ; 60 62 64 66 68 6A 6C 6E !WORD SBX,SWX,SLBX,SLWX,SABX,SAWX,DABX,DAWX ; 70 72 74 76 78 7A 7C 7E ;* -;* COMMAND PROCESSING +;* 'BYE' COMMAND PROCESSING ;* !PSEUDOPC $1000 { ;* ;* CLEAR COMMAND LINE LENGTH BYTE IF CALLED FROM 'BYE' ;* - LDY #$00 + LDY DEFCMD + STY $0280 ; SET DEFAULT COMMAND WHEN CALLED FROM 'BYE' +- LDA DEFCMD,Y + STA $0280,Y + DEY + BNE - LDX #$FE ; LEAVE ROOM FOR COMMAND LINE LENGTH BYTE TXS - BVS + - STY $01FF ; CLEAR AUTORUN COMMAND WHEN CALLED FROM 'BYE' ;* ;* MOVE REST OF CMD FROM LANGUAGE CARD ;* -+ STY SRCL +CMDEXEC STY SRCL STY DSTL LDA #$D2 STA SRCH @@ -246,6 +247,8 @@ OPXTBL !WORD ZEROX,ADDX,SUBX,MULX,DIVX,MODX,INCRX,DECRX ; 00 02 04 06 08 0 JSR $FC58 ; HOME JMP START DISABLE80 !BYTE 21, 13, '1', 26, 13 +DEFCMD !BYTE 3 + !TEXT "CMD" ;* ;* JUMP TO INTERPRETER ;* From 0854c721337af69ba82cd464bffc22271c923eb1 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 6 May 2014 22:09:29 -0700 Subject: [PATCH 38/44] Try 64 bit fixes --- PLASMA/src/codegen.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/PLASMA/src/codegen.c b/PLASMA/src/codegen.c index 9b58a3b5..f6f67766 100755 --- a/PLASMA/src/codegen.c +++ b/PLASMA/src/codegen.c @@ -1,5 +1,7 @@ #include +#include #include "tokens.h" +#include "lex.h" #include "symbols.h" #include "codegen.h" /* @@ -122,7 +124,8 @@ int idglobal_add(char *name, int len, int type, int size) if (!(type & EXTERN_TYPE)) { emit_idglobal(globals, size, name); - idglobal_tag[globals] = globals++; + idglobal_tag[globals] = globals; + globals++; } else { @@ -335,13 +338,13 @@ void emit_rld(void) { if (fixup_type[i] & EXTERN_TYPE) { - printf("\t%s\t$%02X\t\t\t; EXTERNAL FIXUP\n", DB, 0x11 + fixup_size[i]); + printf("\t%s\t$%02X\t\t\t; EXTERNAL FIXUP\n", DB, 0x11 + fixup_size[i] & 0xFF); printf("\t%s\t_F%03d\t\t\n", DW, i); printf("\t%s\t%d\t\t\t; ESD INDEX\n", DB, fixup_tag[i]); } else { - printf("\t%s\t$%02X\t\t\t; INTERNAL FIXUP\n", DB, 0x01 + fixup_size[i]); + printf("\t%s\t$%02X\t\t\t; INTERNAL FIXUP\n", DB, 0x01 + fixup_size[i] & 0xFF); printf("\t%s\t_F%03d\t\t\n", DW, i); printf("\t%s\t$00\n", DB); } From b0e291b1f66e6b1a6d7f53d3f4f3b7d17f51ea3f Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Wed, 7 May 2014 09:27:19 -0700 Subject: [PATCH 39/44] Clean up some susceptible expressions --- PLASMA/src/plvm.c | 63 ++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/PLASMA/src/plvm.c b/PLASMA/src/plvm.c index 99994db8..cf90cef8 100755 --- a/PLASMA/src/plvm.c +++ b/PLASMA/src/plvm.c @@ -15,9 +15,9 @@ int show_state = 0; /* * Bytecode memory */ -#define BYTE_PTR(bp) ((byte)(*bp++)) -#define WORD_PTR(bp) ((word)(*bp++|(*++bp << 8))) -#define UWORD_PTR(bp) ((uword)((*bp++|(*++bp << 8))&0xFFFF)) +#define BYTE_PTR(bp) ((byte)((bp)[0])) +#define WORD_PTR(bp) ((word)((bp)[0] | ((bp)[1] << 8))) +#define UWORD_PTR(bp) ((uword)((bp)[0] | ((bp)[1] << 8))) #define TO_UWORD(w) ((w)&0xFFFF) #define MOD_ADDR 0x1000 #define DEF_CALL 0x0800 @@ -31,7 +31,7 @@ uword sp = 0x01FE, fp = 0xBEFF, heap = 0x6000, xheap = 0x0800, deftbl = DEF_CALL #define EVAL_STACKSZ 16 #define PUSH(v) (*(--esp))=(v) #define POP (*(esp++)) -#define UPOP ((uword)(*(esp++))) +#define UPOP ((uword)(*(esp++)&0xFFFF)) #define TOS (esp[0]) word eval_stack[EVAL_STACKSZ]; word *esp = eval_stack + EVAL_STACKSZ; @@ -273,7 +273,7 @@ int extern_lookup(byte *esd, int index) } int load_mod(byte *mod) { - int len, size, end, magic, bytecode, fixup, addr, init = 0, modaddr = mark_heap(); + unsigned int len, size, end, magic, bytecode, fixup, addr, init = 0, modaddr = mark_heap(); byte *moddep, *rld, *esd, *cdd, *sym; byte header[128]; char filename[32], string[17]; @@ -433,9 +433,9 @@ int load_mod(byte *mod) } void interp(code *ip); -void call(word pc) +void call(uword pc) { - int i, s; + unsigned int i, s; char sz[64]; switch (mem_data[pc++]) @@ -625,15 +625,19 @@ void interp(code *ip) break; case 0x26: // LA : TOS = @VAR ; equivalent to CW ADDRESSOF(VAR) PUSH(WORD_PTR(ip)); + ip += 2; break; case 0x28: // LLA : TOS = @LOCALVAR ; equivalent to CW FRAMEPTR+OFFSET(LOCALVAR) PUSH(fp + BYTE_PTR(ip)); + ip++; break; case 0x2A: // CB : TOS = CONSTANTBYTE (IP) PUSH(BYTE_PTR(ip)); + ip++; break; case 0x2C: // CW : TOS = CONSTANTWORD (IP) PUSH(WORD_PTR(ip)); + ip += 2; break; case 0x2E: // SWAP : TOS = TOS-1, TOS-1 = TOS val = POP; @@ -662,28 +666,28 @@ void interp(code *ip) case 0x38: // BRGT : TOS-1 > TOS ? IP += (IP) val = POP; if (TOS > val) - ip += WORD_PTR(ip) - 2; + ip += WORD_PTR(ip); else ip += 2; break; case 0x3A: // BRLT : TOS-1 < TOS ? IP += (IP) val = POP; if (TOS < val) - ip += WORD_PTR(ip) - 2; + ip += WORD_PTR(ip); else ip += 2; break; case 0x3C: // BREQ : TOS == TOS-1 ? IP += (IP) val = POP; if (TOS == val) - ip += WORD_PTR(ip) - 2; + ip += WORD_PTR(ip); else ip += 2; break; case 0x3E: // BRNE : TOS != TOS-1 ? IP += (IP) val = POP; if (TOS != val) - ip += WORD_PTR(ip) - 2; + ip += WORD_PTR(ip); else ip += 2; break; @@ -722,13 +726,13 @@ void interp(code *ip) break; case 0x4C: // BRFLS : !TOS ? IP += (IP) if (!POP) - ip += WORD_PTR(ip) - 2; + ip += WORD_PTR(ip) ; else ip += 2; break; case 0x4E: // BRTRU : TOS ? IP += (IP) if (POP) - ip += WORD_PTR(ip) - 2; + ip += WORD_PTR(ip); else ip += 2; break; @@ -736,27 +740,30 @@ void interp(code *ip) * 0x50-0x5F */ case 0x50: // BRNCH : IP += (IP) - ip += WORD_PTR(ip) - 2; + ip += WORD_PTR(ip); break; case 0x52: // IBRNCH : IP += TOS ip += POP; break; case 0x54: // CALL : TOFP = IP, IP = (IP) ; call call(UWORD_PTR(ip)); + ip += 2; break; case 0x56: // ICALL : TOFP = IP, IP = (TOS) ; indirect call - val = TO_UWORD(POP); + val = UPOP; ea = mem_data[val] | (mem_data[val + 1] << 8); call(ea); break; case 0x58: // ENTER : NEW FRAME, FOREACH PARAM LOCALVAR = TOS frmsz = BYTE_PTR(ip); + ip++; mem_data[fp - frmsz] = fp; mem_data[fp - frmsz + 1] = fp >> 8; if (show_state) printf("< $%04X: $%04X > ", fp - frmsz, fp); fp -= frmsz; parmcnt = BYTE_PTR(ip); + ip++; while (parmcnt--) { val = POP; @@ -782,70 +789,82 @@ void interp(code *ip) PUSH(mem_data[ea]); break; case 0x62: // LW : TOS = WORD (TOS) - ea = TO_UWORD(POP); + ea = UPOP; PUSH(mem_data[ea] | (mem_data[ea + 1] << 8)); break; case 0x64: // LLB : TOS = LOCALBYTE [IP] PUSH(mem_data[TO_UWORD(fp + BYTE_PTR(ip))]); + ip++; break; case 0x66: // LLW : TOS = LOCALWORD [IP] ea = TO_UWORD(fp + BYTE_PTR(ip)); PUSH(mem_data[ea] | (mem_data[ea + 1] << 8)); + ip++; break; case 0x68: // LAB : TOS = BYTE (IP) PUSH(mem_data[UWORD_PTR(ip)]); + ip += 2; break; case 0x6A: // LAW : TOS = WORD (IP) ea = UWORD_PTR(ip); PUSH(mem_data[ea] | (mem_data[ea + 1] << 8)); + ip += 2; break; case 0x6C: // DLB : TOS = TOS, LOCALBYTE [IP] = TOS mem_data[TO_UWORD(fp + BYTE_PTR(ip))] = TOS; + ip++; break; case 0x6E: // DLW : TOS = TOS, LOCALWORD [IP] = TOS ea = TO_UWORD(fp + BYTE_PTR(ip)); mem_data[ea] = TOS; mem_data[ea + 1] = TOS >> 8; + ip++; break; /* * 0x70-0x7F */ case 0x70: // SB : BYTE (TOS) = TOS-1 val = POP; - ea = TO_UWORD(POP); + ea = UPOP; mem_data[ea] = val; break; case 0x72: // SW : WORD (TOS) = TOS-1 val = POP; - ea = TO_UWORD(POP); + ea = UPOP; mem_data[ea] = val; mem_data[ea + 1] = val >> 8; break; case 0x74: // SLB : LOCALBYTE [TOS] = TOS-1 mem_data[TO_UWORD(fp + BYTE_PTR(ip))] = POP; + ip++; break; case 0x76: // SLW : LOCALWORD [TOS] = TOS-1 ea = TO_UWORD(fp + BYTE_PTR(ip)); val = POP; mem_data[ea] = val; mem_data[ea + 1] = val >> 8; + ip++; break; case 0x78: // SAB : BYTE (IP) = TOS - mem_data[TO_UWORD(WORD_PTR(ip))] = POP; + mem_data[UWORD_PTR(ip)] = POP; + ip += 2; break; case 0x7A: // SAW : WORD (IP) = TOS - ea = TO_UWORD(WORD_PTR(ip)); + ea = UWORD_PTR(ip); val = POP; mem_data[ea] = val; mem_data[ea + 1] = val >> 8; + ip += 2; break; case 0x7C: // DAB : TOS = TOS, BYTE (IP) = TOS - mem_data[TO_UWORD(WORD_PTR(ip))] = TOS; + mem_data[UWORD_PTR(ip)] = TOS; + ip += 2; break; case 0x7E: // DAW : TOS = TOS, WORD (IP) = TOS - ea = TO_UWORD(WORD_PTR(ip)); + ea = UWORD_PTR(ip); mem_data[ea] = TOS; mem_data[ea + 1] = TOS >> 8; + ip += 2; break; /* * Odd codes and everything else are errors. From 23ac5a36f0f00fab48f773031c490edc2ff6be27 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Wed, 7 May 2014 14:25:19 -0700 Subject: [PATCH 40/44] Fix many VM issues, especially 6502 version. Now boots! --- PLASMA/src/cmd.pla | 46 ++++++++++------ PLASMA/src/cmdexec.pla | 75 +++++++++++++------------- PLASMA/src/codegen.c | 10 +--- PLASMA/src/parse.c | 1 + PLASMA/src/plvm.c | 13 ++--- PLASMA/src/plvm02.s | 120 +++++++++++++++++++++++++---------------- 6 files changed, 153 insertions(+), 112 deletions(-) diff --git a/PLASMA/src/cmd.pla b/PLASMA/src/cmd.pla index d4984e58..2ddf67f4 100644 --- a/PLASMA/src/cmd.pla +++ b/PLASMA/src/cmd.pla @@ -41,8 +41,12 @@ SRCH = SRC+1 DST = SRC+2 DSTL = DST DSTH = DST+1 -ESP = DST+2 +;* +;* ASM VARIABLES +;* +ESP !BYTE 0 end +; ; CALL PRODOS ; SYSCALL(CMD, PARAMS) ; @@ -68,12 +72,26 @@ end ; CALL LOADED SYSTEM PROGRAM ; asm exec - LDX #$FE + LDA #$00 + STA IFPL + LDA #$BF + STA IFPH + LDX #$FF TXS - LDX ESTKSZ/2 + LDX #ESTKSZ/2 + BIT ROMEN JMP $2000 end ; +; EXIT +; +asm reboot + BIT ROMEN + LDA #$00 + STA $3F4 ; INVALIDATE POWER-UP BYTE + JMP ($FFFC) ; RESET +end +; ; SET MEMORY TO 0 ; MEMCLR(ADDR, SIZE) ; @@ -181,6 +199,7 @@ asm cout ORA #$80 BIT ROMEN JSR $FDED + BIT LCRDEN+LCBNK2 RTS end ; @@ -196,6 +215,7 @@ asm cin STA ESTKL,X LDY #$00 STY ESTKH,X + BIT LCRDEN+LCBNK2 RTS end ; @@ -219,7 +239,8 @@ asm prstr TYA CMP ESTKL,X BNE - -+ RTS ++ BIT LCRDEN+LCBNK2 + RTS end ; ; PRINT BYTE @@ -230,6 +251,7 @@ asm prbyte BIT ROMEN JSR $FDDA LDX ESP + BIT LCRDEN+LCBNK2 RTS end ; @@ -253,6 +275,7 @@ asm rdstr STA ESTKL,X LDA #$01 STA ESTKH,X + BIT LCRDEN+LCBNK2 RTS end asm toupper @@ -266,15 +289,6 @@ asm toupper STA ESTKL,X + RTS end -; -; EXIT -; -asm reboot - BIT ROMEN - LDA #$00 - STA $3F4 ; INVALIDATE POWER-UP BYTE - JMP ($FFFC) ; RESET -end def crout cout($0D) end @@ -303,9 +317,9 @@ def online params.0 = 2 params.1 = 0 - params:2 = $2000 + params:2 = databuff perr = prodos($C5, @params) - return $2000 + return databuff end def open(path, buff) byte params[6] @@ -492,7 +506,7 @@ end resetmemfiles() prstr(@version) -crout(); +crout() while 1 prstr(getpfx(@prefix)) cmdptr = rdstr($BA) diff --git a/PLASMA/src/cmdexec.pla b/PLASMA/src/cmdexec.pla index 600ceeb1..797ad432 100644 --- a/PLASMA/src/cmdexec.pla +++ b/PLASMA/src/cmdexec.pla @@ -25,7 +25,7 @@ CMD: !BYTE 00 PARAMS: !WORD 0000 LDX ESP STA ESTKL,X - LDY #$00 + LDY #$00 STY ESTKH,X RTS end @@ -39,24 +39,33 @@ asm exec STA IFPH LDX #$FE TXS - LDX ESTKSZ/2 + LDX #ESTKSZ/2 BIT ROMEN JMP $2000 end ; +; EXIT +; +asm reboot + BIT ROMEN + LDA #$00 + STA $3F4 ; INVALIDATE POWER-UP BYTE + JMP ($FFFC) ; RESET +end +; ; SET MEMORY TO 0 ; MEMCLR(ADDR, SIZE) ; asm memclr LDY #$00 - LDA ESTKL+1,X - STA DSTL - LDA ESTKH+1,X - STA DSTH + LDA ESTKL+1,X + STA DSTL + LDA ESTKH+1,X + STA DSTH INC ESTKL,X - INC ESTKH,X + INC ESTKH,X TYA -SETMLP DEC ESTKL,X +SETMLP DEC ESTKL,X BNE + DEC ESTKH,X BEQ ++ @@ -75,18 +84,18 @@ end asm memcpy LDY #$00 LDA ESTKL,X - BNE + + BNE + LDA ESTKH,X BEQ MEMEXIT + LDA ESTKL+2,X - STA DSTL + STA DSTL LDA ESTKH+2,X - STA DSTH + STA DSTH LDA ESTKL+1,X - STA SRCL + STA SRCL LDA ESTKH+1,X - STA SRCH - INC ESTKH,X + STA SRCH + INC ESTKH,X CPYLP LDA (SRC),Y STA (DST),Y INC DSTL @@ -95,7 +104,7 @@ CPYLP LDA (SRC),Y + INC SRCL BNE + INC SRCH -+ DEC ESTKL,X ++ DEC ESTKL,X BNE CPYLP DEC ESTKH,X BNE CPYLP @@ -109,9 +118,10 @@ end ; asm cout LDA ESTKL,X - ORA #$80 + ORA #$80 BIT ROMEN JSR $FDED + BIT LCRDEN+LCBNK2 RTS end ; @@ -121,12 +131,13 @@ end asm cin BIT ROMEN STX ESP - JSR $FD0C + JSR $FD0C LDX ESP DEX - STA ESTKL,X + STA ESTKL,X LDY #$00 - STY ESTKH,X + STY ESTKH,X + BIT LCRDEN+LCBNK2 RTS end ; @@ -135,14 +146,14 @@ end ; asm prstr LDY #$00 - LDA ESTKL,X - STA SRCL - LDA ESTKH,X - STA SRCH + LDA ESTKL,X + STA SRCL + LDA ESTKH,X + STA SRCH BIT ROMEN - LDA (SRC),Y - STA ESTKL,X - BEQ + + LDA (SRC),Y + STA ESTKL,X + BEQ + - INY LDA (SRC),Y ORA #$80 @@ -150,16 +161,8 @@ asm prstr TYA CMP ESTKL,X BNE - -+ RTS -end -; -; EXIT -; -asm reboot - BIT ROMEN - LDA #$00 - STA $3F4 ; INVALIDATE POWER-UP BYTE - JMP ($FFFC) ; RESET ++ BIT LCRDEN+LCBNK2 + RTS end def crout cout($0D) diff --git a/PLASMA/src/codegen.c b/PLASMA/src/codegen.c index f6f67766..a6986655 100755 --- a/PLASMA/src/codegen.c +++ b/PLASMA/src/codegen.c @@ -311,9 +311,7 @@ void emit_header(void) } else { - printf("\tJSR\t$3D0\n"); - printf("\t%s\t$00\t\t\t; MODULE INITIALIZATION ROUTINE\n", DB); - printf("\t%s\t_INIT\t\t\t;\n", DW); + printf("\tJMP\t_INIT\t\t\t; MODULE INITIALIZATION ROUTINE\n"); } } void emit_rld(void) @@ -493,13 +491,9 @@ void emit_def(char *name, int is_bytecode) { if (!(outflags & MODULE)) { - printf("%s%c\n", name, LBL); + //printf("%s%c\n", name, LBL); if (is_bytecode) - { printf("\tJSR $03D0\n"); - printf("\t%s\t$00\n", DB); - printf("\t%s\t*+2\n", DW); - } } } void emit_codetag(int tag) diff --git a/PLASMA/src/parse.c b/PLASMA/src/parse.c index a5eafe79..7dd1a621 100755 --- a/PLASMA/src/parse.c +++ b/PLASMA/src/parse.c @@ -1301,6 +1301,7 @@ int parse_module(void) if (scantoken != DONE_TOKEN && scantoken != EOF_TOKEN) { emit_start(); + emit_def("_INIT", 1); prevstmnt = 0; while (parse_stmnt()) next_line(); if (scantoken != DONE_TOKEN) diff --git a/PLASMA/src/plvm.c b/PLASMA/src/plvm.c index cf90cef8..2163f960 100755 --- a/PLASMA/src/plvm.c +++ b/PLASMA/src/plvm.c @@ -16,9 +16,9 @@ int show_state = 0; * Bytecode memory */ #define BYTE_PTR(bp) ((byte)((bp)[0])) -#define WORD_PTR(bp) ((word)((bp)[0] | ((bp)[1] << 8))) +#define WORD_PTR(bp) ((word)((bp)[0] | ((bp)[1] << 8))) #define UWORD_PTR(bp) ((uword)((bp)[0] | ((bp)[1] << 8))) -#define TO_UWORD(w) ((w)&0xFFFF) +#define TO_UWORD(w) ((uword)((w))) #define MOD_ADDR 0x1000 #define DEF_CALL 0x0800 #define DEF_CALLSZ 0x0800 @@ -30,8 +30,8 @@ uword sp = 0x01FE, fp = 0xBEFF, heap = 0x6000, xheap = 0x0800, deftbl = DEF_CALL #define EVAL_STACKSZ 16 #define PUSH(v) (*(--esp))=(v) -#define POP (*(esp++)) -#define UPOP ((uword)(*(esp++)&0xFFFF)) +#define POP ((word)(*(esp++))) +#define UPOP ((uword)(*(esp++))) #define TOS (esp[0]) word eval_stack[EVAL_STACKSZ]; word *esp = eval_stack + EVAL_STACKSZ; @@ -649,7 +649,7 @@ void interp(code *ip) * 0x30-0x3F */ case 0x30: // DROP : TOS = - esp++;; + POP; break; case 0x32: // DUP : TOS = TOS val = TOS; @@ -661,7 +661,8 @@ void interp(code *ip) mem_data[sp--] = val; break; case 0x36: // PULL : TOS = TOSP - PUSH(mem_data[++sp] | (mem_data[++sp] << 8)); + PUSH(mem_data[sp] | (mem_data[sp + 1] << 8)); + sp += 2; break; case 0x38: // BRGT : TOS-1 > TOS ? IP += (IP) val = POP; diff --git a/PLASMA/src/plvm02.s b/PLASMA/src/plvm02.s index c7ddac05..d0290ae1 100644 --- a/PLASMA/src/plvm02.s +++ b/PLASMA/src/plvm02.s @@ -110,6 +110,17 @@ ESP = DST+2 CMP #$E0 BNE - ;* +;* MOVE FIRST PAGE OF 'BYE' INTO PLACE +;* + LDY #$00 + STY SRCL + LDA #$D1 + STA SRCH +- LDA (SRC),Y + STA $1000,Y + INY + BNE - +;* ;* LOOK FOR STARTUP FILE ;* JSR PRODOS ; OPEN AUTORUN @@ -133,18 +144,11 @@ ESP = DST+2 JMP NOAUTO + LDX READPARMS+6 STX $0280 -NOAUTO JSR PRODOS + JSR PRODOS !BYTE $CC !WORD CLOSEPARMS - LDY #$00 - STY SRCL - LDA #$D1 - STA SRCH -- LDA (SRC),Y ; LOAD FIRST PAGE OF CMD INTO PLACE - STA $1000,Y - INY - BNE - - JMP CMDEXEC ; CALL CMD + JMP CMDEXEC ; CALL CM +NOAUTO JMP BYE AUTORUN !BYTE 7 !TEXT "AUTORUN" OPENPARMS !BYTE 3 @@ -167,12 +171,10 @@ PAGE3 = * ;* ;* PAGE 3 VECTORS INTO INTERPRETER ;* - BIT LCRDEN+LCBNK2 ; $03D0 - INTERP ENTRY + BIT LCRDEN+LCBNK2 ; $03D0 - DIRECT INTERP ENTRY JMP INTERP -CALL3 BIT ROMEN -CALLADR JSR $0000 - BIT LCRDEN+LCBNK2 - RTS + BIT LCRDEN+LCBNK2 ; $03D6 - INDIRECT INTERP ENTRY + JMP INTERPX } VMCORE = * !PSEUDOPC $D000 { @@ -182,7 +184,7 @@ VMCORE = * OPTBL !WORD ZERO,ADD,SUB,MUL,DIV,MOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E !WORD NEG,COMP,BAND,IOR,XOR,SHL,SHR,IDXW ; 10 12 14 16 18 1A 1C 1E !WORD LNOT,LOR,LAND,LA,LLA,CB,CW,SWAP ; 20 22 24 26 28 2A 2C 2E - !WORD DROP,DUP,PUSH,PULL,BRLT,BRGT,BREQ,BRNE ; 30 32 34 36 38 3A 3C 3E + !WORD DROP,DUP,PUSH,PULL,BRGT,BRLT,BREQ,BRNE ; 30 32 34 36 38 3A 3C 3E !WORD ISEQ,ISNE,ISGT,ISLT,ISGE,ISLE,BRFLS,BRTRU ; 40 42 44 46 48 4A 4C 4E !WORD BRNCH,IBRNCH,CALL,ICAL,ENTER,LEAVE,RET,NEXTOP ; 50 52 54 56 58 5A 5C 5E !WORD LB,LW,LLB,LLW,LAB,LAW,DLB,DLW ; 60 62 64 66 68 6A 6C 6E @@ -193,7 +195,7 @@ OPTBL !WORD ZERO,ADD,SUB,MUL,DIV,MOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E OPXTBL !WORD ZEROX,ADDX,SUBX,MULX,DIVX,MODX,INCRX,DECRX ; 00 02 04 06 08 0A 0C 0E !WORD NEGX,COMPX,BANDX,IORX,XORX,SHLX,SHRX,IDXWX ; 10 12 14 16 18 1A 1C 1E !WORD LNOTX,LORX,LANDX,LAX,LLAX,CBX,CWX,SWAPX ; 20 22 24 26 28 2A 2C 2E - !WORD DROPX,DUPX,PUSHX,PULLX,BRLTX,BRGTX,BREQX,BRNEX ; 30 32 34 36 38 3A 3C 3E + !WORD DROPX,DUPX,PUSHX,PULLX,BRGTX,BRLTX,BREQX,BRNEX ; 30 32 34 36 38 3A 3C 3E !WORD ISEQX,ISNEX,ISGTX,ISLTX,ISGEX,ISLEX,BRFLSX,BRTRUX; 40 42 44 46 48 4A 4C 4E !WORD BRNCHX,IBRNCHX,CALLX,ICALX,ENTERX,LEAVEX,RETX,NEXTOPX; 50 52 54 56 58 5A 5C 5E !WORD LBX,LWX,LLBX,LLWX,LABX,LAWX,DLBX,DLWX ; 60 62 64 66 68 6A 6C 6E @@ -205,14 +207,12 @@ OPXTBL !WORD ZEROX,ADDX,SUBX,MULX,DIVX,MODX,INCRX,DECRX ; 00 02 04 06 08 0 ;* ;* CLEAR COMMAND LINE LENGTH BYTE IF CALLED FROM 'BYE' ;* - LDY DEFCMD +BYE LDY DEFCMD STY $0280 ; SET DEFAULT COMMAND WHEN CALLED FROM 'BYE' - LDA DEFCMD,Y STA $0280,Y DEY BNE - - LDX #$FE ; LEAVE ROOM FOR COMMAND LINE LENGTH BYTE - TXS ;* ;* MOVE REST OF CMD FROM LANGUAGE CARD ;* @@ -256,13 +256,25 @@ START LDA #$00 STA IFPL LDA #$BF STA IFPH - LDX ESTKSZ/2 + LDX #$FF + TXS + LDX #ESTKSZ/2 !SOURCE "cmdexec.a" } ;* ;* ENTER INTO BYTECODE INTERPRETER ;* -INTERP PLA +INTERP STA LCRWEN+LCBNK2 ; WRITE ENABLE LANGUAGE CARD + STA LCRWEN+LCBNK2 + PLA + STA IPL + PLA + STA IPH + LDY #$01 + BNE FETCHOP +INTERPX STA LCRWEN+LCBNK2 ; WRITE ENABLE LANGUAGE CARD + STA LCRWEN+LCBNK2 + PLA STA TMPL PLA STA TMPH @@ -287,7 +299,7 @@ DROP INX NEXTOP INY BEQ NEXTOPH FETCHOP LDA (IP),Y - STA *+5 + STA *+4 JMP (OPTBL) ;* ;* INTERP BYTECODE IN AUX MEM @@ -302,9 +314,13 @@ FETCHOPX SEI STA ALTRDON LDA (IP),Y ORA #$80 ; SELECT OPX OPCODES - STA *+5 + STA *+4 JMP (OPXTBL) ;* +;* INDIRECT JUMP TO (TMP) +;* +JMPTMP JMP (TMP) +;* ;* ADD TOS TO TOS-1 ;* ADD LDA ESTKL,X @@ -1592,8 +1608,7 @@ BRFLS INX LDA ESTKH-1,X ORA ESTKL-1,X BNE NOBRNCH -BRNCH STY IPY - LDA IPH +BRNCH LDA IPH STA TMPH LDA IPL +INC_IP @@ -1606,8 +1621,9 @@ BRNCH STY IPY STA IPH LDA TMPL STA IPL - LDY IPY - JMP FETCHOP + DEY + DEY + JMP NEXTOP BREQ INX LDA ESTKL-1,X CMP ESTKL,X @@ -1646,7 +1662,7 @@ IBRNCH LDA IPL ADC ESTKH,X STA IPH INX - JMP FETCHOP + JMP NEXTOP ; BRTRUX INX LDA ESTKH-1,X @@ -1659,8 +1675,7 @@ BRFLSX INX LDA ESTKH-1,X ORA ESTKL-1,X BNE NOBRNCHX -BRNCHX STY IPY - LDA IPH +BRNCHX LDA IPH STA TMPH LDA IPL +INC_IP @@ -1673,8 +1688,9 @@ BRNCHX STY IPY STA IPH LDA TMPL STA IPL - LDY IPY - JMP FETCHOPX + DEY + DEY + JMP NEXTOPX BREQX INX LDA ESTKL-1,X CMP ESTKL,X @@ -1713,29 +1729,31 @@ IBRNCHX LDA IPL ADC ESTKH,X STA IPH INX - JMP FETCHOPX + JMP NEXTOPX ;* ;* CALL INTO ABSOLUTE ADDRESS (NATIVE CODE) ;* CALL +INC_IP LDA (IP),Y - STA CALLADR+1 + STA TMPL +INC_IP LDA (IP),Y - STA CALLADR+2 + STA TMPH LDA IPH PHA LDA IPL PHA TYA PHA - JSR CALL3 + JSR JMPTMP PLA TAY PLA STA IPL PLA STA IPH + STA LCRWEN+LCBNK2 ; WRITE ENABLE LANGUAGE CARD + STA LCRWEN+LCBNK2 JMP NEXTOP ; CALLX +INC_IP @@ -1744,9 +1762,9 @@ CALLX +INC_IP +INC_IP LDA (IP),Y STA ALTRDOFF - STA CALLADR+2 + STA TMPH PLA - STA CALLADR+1 + STA TMPL LDA IPH PHA LDA IPL @@ -1754,13 +1772,15 @@ CALLX +INC_IP TYA PHA CLI - JSR CALL3 + JSR JMPTMP PLA TAY PLA STA IPL PLA STA IPH + STA LCRWEN+LCBNK2 ; WRITE ENABLE LANGUAGE CARD + STA LCRWEN+LCBNK2 JMP NEXTOPX ;* ;* INDIRECT CALL TO ADDRESS (NATIVE CODE) @@ -1778,18 +1798,22 @@ ICAL LDA ESTKL,X PHA LDY #$00 LDA (TMP),Y - STA CALLADR+1 + PHA INY LDA (TMP),Y - STA CALLADR+2 + STA TMPH + PLA + STA TMPL CLI - JSR CALL3 + JSR JMPTMP PLA TAY PLA STA IPL PLA STA IPH + STA LCRWEN+LCBNK2 ; WRITE ENABLE LANGUAGE CARD + STA LCRWEN+LCBNK2 JMP NEXTOP ; ICALX LDA ESTKL,X @@ -1806,18 +1830,22 @@ ICALX LDA ESTKL,X STA ALTRDOFF LDY #$00 LDA (TMP),Y - STA CALLADR+1 + PHA INY LDA (TMP),Y - STA CALLADR+2 + STA TMPH + PLA + STA TMPL CLI - JSR CALL3 + JSR JMPTMP PLA TAY PLA STA IPL PLA STA IPH + STA LCRWEN+LCBNK2 ; WRITE ENABLE LANGUAGE CARD + STA LCRWEN+LCBNK2 JMP NEXTOPX ;* ;* ENTER FUNCTION WITH FRAME SIZE AND PARAM COUNT From b496256a8797df0ce842263a3eedae93bca8ab94 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Thu, 8 May 2014 13:31:27 -0700 Subject: [PATCH 41/44] Add module loading to cmd, fix extraneous statements in plvm.c --- PLASMA/src/cmd.pla | 500 ++++++++++++++++++++++++++++++++++++++++++-- PLASMA/src/plvm.c | 7 +- PLASMA/src/plvm02.s | 31 +-- 3 files changed, 481 insertions(+), 57 deletions(-) diff --git a/PLASMA/src/cmd.pla b/PLASMA/src/cmd.pla index 2ddf67f4..54be127d 100644 --- a/PLASMA/src/cmd.pla +++ b/PLASMA/src/cmd.pla @@ -1,12 +1,20 @@ const iobuffer = $0800 const databuff = $0C00 -byte version[] = "PLASMA VM VERSION 0.9" +const MOD_ADDR = $1000 +byte version[] = "PLASMA VERSION 0.9" byte errorstr[] = "ERROR: $" byte okstr[] = "OK" +byte heaperr[] = "ERR: HEAP/FRAME COLLISION.\n" byte prefix[32] = "" +word heap = $6000 +byte modtbl[256] +word lastmod = @modtbl +byte symtbl[1024] +word lastsym = @symtbl +byte deftbl[2048] +word lastdef = @deftbl byte perr word cmdptr - ; ; Utility functions ; @@ -20,27 +28,7 @@ ROMEN = $C082 LCRWEN = $C083 LCBNK2 = $00 LCBNK1 = $08 -;* -;* ZERO PAGE USEAGE -;* -ESTKSZ = $20 -ESTK = $C0 -ESTKL = ESTK -ESTKH = ESTK+ESTKSZ/2 -VMZP = ESTK+ESTKSZ -IFP = VMZP -IFPL = IFP -IFPH = IFP+1 -IP = IFP+2 -IPL = IP -IPH = IP+1 -IPY = IP+2 -SRC = $06 -SRCL = SRC -SRCH = SRC+1 -DST = SRC+2 -DSTL = DST -DSTH = DST+1 + !SOURCE "plvm02zp.inc" ;* ;* ASM VARIABLES ;* @@ -255,6 +243,22 @@ asm prbyte RTS end ; +; PRINT WORD +; +asm prword + LDA ESTKH,X + TAY + LDA ESTKL,X + STX ESP + TAX + TYA + BIT ROMEN + JSR $F941 + LDX ESP + BIT LCRDEN+LCBNK2 + RTS +end +; ; READ STRING ; STR = RDSTR(PROMPTCHAR) ; @@ -289,6 +293,66 @@ asm toupper STA ESTKL,X + RTS end +asm uword_isge + STY IPY + LDY #$00 + LDA ESTKL+1,X + CMP ESTKL,X + LDA ESTKH+1,X + SBC ESTKH,X ++ BCC + + DEY ++ STY ESTKL+1,X + STY ESTKH+1,X + INX + LDY IPY + RTS +end +asm uword_isle + STY IPY + LDY #$00 + LDA ESTKL,X + CMP ESTKL+1,X + LDA ESTKH,X + SBC ESTKH+1,X ++ BCC + + DEY ++ STY ESTKL+1,X + STY ESTKH+1,X + INX + LDY IPY + RTS +end +asm uword_isgt + STY IPY + LDY #$FF + LDA ESTKL,X + CMP ESTKL+1,X + LDA ESTKH,X + SBC ESTKH+1,X ++ BCC + + INY ++ STY ESTKL+1,X + STY ESTKH+1,X + INX + LDY IPY + RTS +end +asm uword_islt + STY IPY + LDY #$FF + LDA ESTKL+1,X + CMP ESTKL,X + LDA ESTKH+1,X + SBC ESTKH,X ++ BCC + + INY ++ STY ESTKL+1,X + STY ESTKH+1,X + INX + LDY IPY + RTS +end def crout cout($0D) end @@ -350,6 +414,356 @@ def read(refnum, buff, len) perr = prodos($CA, @params) return params:6 end + +; +; Utility routines. +; +; A DCI string is one that has the high bit set for every character except the last. +; More efficient than C or Pascal strings. +; +def dcitos(dci, str) + byte len + len = 0 + repeat + str.[len] = dci.[len] & $7F + len = len + 1 + until len > 15 or !(dci.[len - 1] & $80) + str.[len] = 0 + return len +end +def stodci(str, dci) + byte len + len = 0 + while len < 16 and str.[len] + dci.[len] = toupper(str.[len]) | $80 + len = len + 1 + loop + dci.[len - 1] = dci.[len - 1] & $7F; + return len; +end +; +; Heap routines. +; +def avail_heap + byte fp + return @fp - heap +end +def alloc_heap(size) + word addr + addr = heap + heap = heap + size +; if heap >= @addr +; puts(@heaperr) +; exit(1) +; fin + return addr +end +def free_heap(size) + heap = heap - size; + return @size - heap; +end +def mark_heap + return heap; +end +def release_heap(newheap) + heap = newheap; + return @newheap - heap; +end +;def avail_xheap(void) +; return 0xC000 - xheap; +;end +;def alloc_xheap(int size) +; uword addr = xheap; +; xheap += size; +; if (xheap >= 0xC000) +; { +; printf("Error: xheap extinguished.\n"); +; exit (1); +; } +; return addr; +;end +;def free_xheap(int size) +; xheap -= size; +; return 0xC000 - heap; +;end +;def mark_xheap(void) +; return xheap; +;end +;def release_xheap(uword newxheap) +; xheap = newxheap; +; return 0xC000 - xheap; +;end +; +; Copy from data mem to code mem. +; +;def xmemcpy(uword src, uword dst, uword size) +; while (size--) +; mem_code[dst + size] = mem_data[src + size]; +;end +; +; Copy from code mem to data mem. +; +;def memxcpy(uword src, uword dst, uword size) +; while (size--) +; mem_data[dst + size] = mem_code[src + size]; +;end +; +; DCI table routines, +; +def dump_tbl(tbl) + byte len + word entbl + while ^tbl + len = 0 + while ^tbl & $80 + cout(^tbl & $7F) + tbl = tbl + 1 + len = len + 1 + loop + cout(^tbl) + tbl = tbl + 1 + cout(':') + while len < 15 + cout(' ') + len = len + 1 + loop + cout('$') + prbyte((tbl).1) + prbyte((tbl).0) + tbl = tbl + 2 + loop +end +def lookup_tbl(dci, tbl) + byte str[20] + word match, entry + entry = tbl + while ^entry + match = dci + while ^entry == ^match + if !(^entry & $80) + return (entry):1 + fin + entry = entry + 1 + match = match + 1 + loop + while ^entry & $80 + entry = entry + 1 + loop + entry = entry + 2 + loop + return 0 +end +def add_tbl(dci, val, last) + while ^dci & $80 + ^(*last) = ^dci + *last = *last + 1 + dci = dci + 1 + loop + ^(*last) = ^dci + *last = *last + 1 + dci = dci + 1 + ^(*last) = val + *last = *last + 2 +end +; +; Symbol table routines. +; +def dump_sym + ;printf("\nSystem Symbol Table:\n"); + dump_tbl(symtbl) +end +def lookup_sym(sym) + return lookup_tbl(sym, symtbl) +end +def add_sym(sym, addr) + return add_tbl(sym, addr, @lastsym); +end +; +; Module routines. +; +def dump_mod + ;printf("\nSystem Module Table:\n"); + dump_tbl(modtbl) +end +def lookup_mod(mod) + return lookup_tbl(mod, modtbl) +end +def add_mod(mod, addr) + return add_tbl(mod, addr, @lastmod) +end +def defcall_add(bank, addr) + (lastdef).0 = $20 ; JSR $03D6 + (lastdef):1 = $03D6 + (lastdef).3 = bank + (lastdef):4 = addr + lastdef = lastdef + 6 +end +def def_lookup(cdd, defaddr) + word i + i = 0 + while (cdd).[i] == $02 + if (cdd):[i + 1] == defaddr) + return cdd + i + fin + i = i + 4 + loop + return 0 +end +def extern_lookup(esd, index) + word sym + byte str[17] + while ^esd + sym = esd; + esd = esd + dcitos(esd, str) + if (esd).0 & $10 and (esd).1 == index + return lookup_sym(sym) + fin + esd = esd + 3 + loop + return 0 +end +def load_mod(mod) + word refnum, len, size,modend, bytecode, fixup, addr, init, modaddr, modfix + word moddep, rld, esd, cdd, sym; + byte header[128] + byte filename[32] + byte str[17] + + init = 0 + modaddr = mark_heap + dcitos(mod, filename) + ;printf("Load module %s\n", filename) + refnum = open(filename) + if refnum > 0 + len = read(refnum, @header, 128) + if len > 4 and header:2 == $DA7E ; DAVE + ; + ; This is a relocatable bytecode module. + ; + bytecode = header:4 + init = header:6 + moddep = @header + 8 + if ^moddep + ; + ; Load module dependencies. + ; + close(refnum) + while ^moddep + if lookup_mod(moddep) == 0 + load_mod(moddep) + fin + moddep = moddep + dcitos(moddep, str) + loop + modaddr = mark_heap + refnum = open(filename) + len = read(refnum, modaddr, 128) + fin + else + memcpy(modaddr, header, len) + fin + addr = modaddr + len; + repeat + len = read(refnum, addr, 4096) + addr = addr + len + until len > 0 + close(refnum) + size = addr - modaddr + len = *modaddr + modend = modaddr + len + modfix = modaddr - MOD_ADDR + bytecode = bytecode + modfix + rld = modaddr + len ; Re-Locatable Directory + cdd = rld ; Code Definition Directory + esd = rld ; Extern+Entry Symbol Directory + while ^esd <> $00 ; Scan to end of RLD + esd = esd + 4 + loop + esd = esd + 1 + ;if show_state + ; + ; Dump different parts of module. + ; + ;printf("Module size: %d\n", size); + ;printf("Module code+data size: %d\n", len); + ;printf("Module magic: $%04X\n", magic); + ;printf("Module bytecode: $%04X\n", bytecode); + ;printf("Module init: $%04X\n", init); + ;fin + ; + ; Print out the Re-Location Dictionary. + ; + ;if show_state + ;printf("\nRe-Location Dictionary:\n") + ;fin + while ^rld + if ^rld == $02 + ;if show_state prstr("\tDEF CODE") + (rld):1 = (rld):1 + modfix + modend = rld + 4 + else + addr = (rld):1 + modfix + if (rld).0 & $80 + fixup = *addr + else + fixup = ^addr + fin + if (^rld & $10) + ;if show_state printf("\tEXTERN[$%02X] ", rld[3]); + fixup = fixup + extern_lookup(esd, rld[3]); + else + ;if (show_state) printf("\tINTERN ") + fixup = fixup + modfix + if uword_isge(fixup, bytecode) + ; + ; Replace with call def dictionary. + ; + fixup = def_lookup(cdd, fixup) + fin + fin + if ^rld & $80 + ;if show_state printf("WORD") + *addr = fixup + else + ;if show_state printf("BYTE") + ^addr = fixup + fin + + fin + ;if show_state printf("@$%04X\n", addr) + rld = rld + 4; + loop + ;if show_state printf("\nExternal/Entry Symbol Directory:\n") + while ^esd + sym = esd + esd = esd + dcitos(esd, str) + if ^esd & $10 + ;if show_state printf("\tIMPORT %s[$%02X]\n", string, esd[1]) + elsif ^esd & $08 + addr = (esd):1 + modfix + ;if show_state printf("\tEXPORT %s@$%04X\n", string, addr) + if uword_isge(addr, bytecode) + addr = def_lookup(cdd, addr) + fin + add_sym(sym, addr) + fin + esd = esd + 3 + loop + else + ;printf("Error: Unable to load module %s\n", filename); + return -1 + fin + ; + ; Reserve heap space for relocated module. + ; + alloc_heap(modend - modaddr) + ; + ; Call init routine. + ; + if init + return (init + modfix)() + fin + return 0 +end ; ; Command mode ; @@ -504,9 +918,49 @@ def execsys(sysfile) fin end +def prucomp(a, b) + if uword_isgt(a, b) + prword(a) + cout('>') + prword(b) + crout + fin + if uword_isge(a, b) + prword(a) + cout('>') + cout('=') + prword(b) + crout + fin + if uword_islt(a, b) + prword(a) + cout('<') + prword(b) + crout + fin + if uword_isle(a, b) + prword(a) + cout('<') + cout('=') + prword(b) + crout + fin +end + resetmemfiles() prstr(@version) crout() +prucomp($1, $2) +prucomp($2, $1) +prucomp($100, $200) +prucomp($200, $100) +prucomp($9000, $A000) +prucomp($A000, $9000) +prucomp($E000, $E000) +prucomp($E001, $E000) +prucomp($E000, $E001) +prucomp($FFFF, $FFFE) +prucomp($FFFE, $FFFF) while 1 prstr(getpfx(@prefix)) cmdptr = rdstr($BA) diff --git a/PLASMA/src/plvm.c b/PLASMA/src/plvm.c index 2163f960..c1492f49 100755 --- a/PLASMA/src/plvm.c +++ b/PLASMA/src/plvm.c @@ -191,10 +191,9 @@ uword lookup_tbl(byte *dci, byte *tbl) while (*entry++ & 0x80); entry += 2; } - dcitos(dci, str); return 0; } -int add_tbl(byte *dci, int val, byte *tbl, byte **last) +int add_tbl(byte *dci, int val, byte **last) { while (*dci & 0x80) *(*last)++ = *dci++; @@ -217,7 +216,7 @@ uword lookup_sym(byte *sym) } int add_sym(byte *sym, int addr) { - return add_tbl(sym, addr, symtbl, &lastsym); + return add_tbl(sym, addr, &lastsym); } /* @@ -234,7 +233,7 @@ uword lookup_mod(byte *mod) } int add_mod(byte *mod, int addr) { - return add_tbl(mod, addr, symtbl, &lastmod); + return add_tbl(mod, addr, &lastmod); } defcall_add(int bank, int addr) { diff --git a/PLASMA/src/plvm02.s b/PLASMA/src/plvm02.s index d0290ae1..9e2f2639 100644 --- a/PLASMA/src/plvm02.s +++ b/PLASMA/src/plvm02.s @@ -29,36 +29,7 @@ ALTRDOFF= $C002 ALTRDON = $C003 ALTWROFF= $C004 ALTWRON = $C005 -;********************************************************** -;* -;* VM ZERO PAGE LOCATIONS -;* -;********************************************************** -ESTKSZ = $20 -ESTK = $C0 -ESTKL = ESTK -ESTKH = ESTK+ESTKSZ/2 -VMZP = ESTK+ESTKSZ -IFP = VMZP -IFPL = IFP -IFPH = IFP+1 -IP = IFP+2 -IPL = IP -IPH = IP+1 -IPY = IP+2 -TMP = IP+3 -TMPL = TMP -TMPH = TMP+1 -TMPX = TMP+2 -NPARMS = TMPL -FRMSZ = TMPH -DVSIGN = TMPX -SRC = $06 -SRCL = SRC -SRCH = SRC+1 -DST = SRC+2 -DSTL = DST -DSTH = DST+1 + !SOURCE "plvm02zp.inc" ESP = DST+2 ;********************************************************** ;* From 97529baec339eb33b593a7b43996813899d4c363 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Thu, 8 May 2014 13:32:17 -0700 Subject: [PATCH 42/44] Pull out zero page useage into seperate file for inclusion --- PLASMA/src/plvm02zp.inc | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 PLASMA/src/plvm02zp.inc diff --git a/PLASMA/src/plvm02zp.inc b/PLASMA/src/plvm02zp.inc new file mode 100644 index 00000000..b081ddab --- /dev/null +++ b/PLASMA/src/plvm02zp.inc @@ -0,0 +1,30 @@ +;********************************************************** +;* +;* VM ZERO PAGE LOCATIONS +;* +;********************************************************** +ESTKSZ = $20 +ESTK = $C0 +ESTKL = ESTK +ESTKH = ESTK+ESTKSZ/2 +VMZP = ESTK+ESTKSZ +IFP = VMZP +IFPL = IFP +IFPH = IFP+1 +IP = IFP+2 +IPL = IP +IPH = IP+1 +IPY = IP+2 +TMP = IP+3 +TMPL = TMP +TMPH = TMP+1 +TMPX = TMP+2 +NPARMS = TMPL +FRMSZ = TMPH +DVSIGN = TMPX +SRC = $06 +SRCL = SRC +SRCH = SRC+1 +DST = SRC+2 +DSTL = DST +DSTH = DST+1 From 579fcf0c7e4f9777e02cd3c2d9a4e3f45672c162 Mon Sep 17 00:00:00 2001 From: Brendan Robert Date: Thu, 8 May 2014 22:01:49 -0500 Subject: [PATCH 43/44] Changeing DragDropHelper to be a more general utility, TransferHelper, in anticipation of moving some copy/paste utility functions in there too. Started working on better image clipboard functionality --- .../ApplicationUIControllerImpl.java | 2 +- .../org/badvision/outlaweditor/ImageClip.java | 96 +++++++++++++++++++ .../org/badvision/outlaweditor/MapEditor.java | 4 +- ...ragDropHelper.java => TransferHelper.java} | 12 ++- 4 files changed, 107 insertions(+), 7 deletions(-) create mode 100644 OutlawEditor/src/main/java/org/badvision/outlaweditor/ImageClip.java rename OutlawEditor/src/main/java/org/badvision/outlaweditor/{DragDropHelper.java => TransferHelper.java} (91%) diff --git a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ApplicationUIControllerImpl.java b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ApplicationUIControllerImpl.java index 9e243e5d..94dcc8ae 100644 --- a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ApplicationUIControllerImpl.java +++ b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ApplicationUIControllerImpl.java @@ -845,7 +845,7 @@ public class ApplicationUIControllerImpl extends ApplicationUIController { UIAction.editScript(event.getSource().getItems().get(event.getIndex())); } }); - final DragDropHelper