mirror of
https://github.com/bobbimanners/EightBall.git
synced 2026-04-19 17:16:27 +00:00
v0.70: disassembler, immediate mode VM ops
- VM now prompts for filename to load bytecode from - Added new EightBall disassembler (`disass`), removed disassembly printout from compiler - Fixes to interpreter / compiler error reporting. Should no longer report completely incorrect line numbers! - Added new immediate mode VM instructions for load (`LDAWI`, `LDABI`, `LDRWI`, `LDRBI`), store (`STAWI`, `STABI`, `STRWI`, `STRBI`), and flow control (`JSRI`, `JMPI`, `BRCI`). Modified compiler to use these new instructions. This significantly improves code density and VM execution speed.
This commit is contained in:
committed by
GitHub
parent
13df8be29f
commit
6dbf45c39c
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -10,7 +10,7 @@ CC65BINDIR = $(CC65DIR)/bin
|
||||
CC65LIBDIR = $(CC65DIR)/lib
|
||||
APPLECMDR = ~/Desktop/Apple2/AppleCommander-1.3.5.jar
|
||||
|
||||
all: eightball eightballvm 8ball20.prg 8ballvm20.prg 8ball64.prg 8ballvm64.prg eightball.system ebvm.system test.d64 test.dsk
|
||||
all: eightball eightballvm disass 8ball20.prg 8ballvm20.prg 8ball64.prg 8ballvm64.prg eightball.system ebvm.system test.d64 test.dsk
|
||||
|
||||
clean:
|
||||
rm -f eightball eightballvm *.o 8ball20.* 8ball64.* eightball*.s eightball.system test.d64 *.map *.vice
|
||||
@@ -23,6 +23,10 @@ eightballvm.o: eightballvm.c eightballutils.h eightballvm.h
|
||||
# 32 bit so sizeof(int*) = sizeof(int) [I am lazy]
|
||||
gcc -m32 -Wall -Wextra -g -c -o eightballvm.o eightballvm.c -lm
|
||||
|
||||
disass.o: disass.c eightballutils.h eightballvm.h
|
||||
# 32 bit so sizeof(int*) = sizeof(int) [I am lazy]
|
||||
gcc -m32 -Wall -Wextra -g -c -o disass.o disass.c -lm
|
||||
|
||||
eightballutils.o: eightballutils.c eightballutils.h
|
||||
# 32 bit so sizeof(int*) = sizeof(int) [I am lazy]
|
||||
gcc -m32 -Wall -Wextra -g -c -o eightballutils.o eightballutils.c -lm
|
||||
@@ -35,6 +39,10 @@ eightballvm: eightballvm.o eightballutils.o
|
||||
# 32 bit so sizeof(int*) = sizeof(int) [I am lazy]
|
||||
gcc -m32 -Wall -Wextra -g -o eightballvm eightballvm.o eightballutils.o -lm
|
||||
|
||||
disass: disass.o eightballutils.o
|
||||
# 32 bit so sizeof(int*) = sizeof(int) [I am lazy]
|
||||
gcc -m32 -Wall -Wextra -g -o disass disass.o eightballutils.o -lm
|
||||
|
||||
eightball_20.o: eightball.c eightballutils.h eightballvm.h
|
||||
$(CC65BINDIR)/cc65 -Or -t vic20 -D VIC20 -o eightball_20.s eightball.c
|
||||
$(CC65BINDIR)/ca65 -t vic20 eightball_20.s
|
||||
@@ -90,7 +98,7 @@ ebvm.system: eightballvm_a2e.o eightballutils_a2e.o
|
||||
$(CC65BINDIR)/ld65 -m 8ballvma2e.map -o ebvm.system -C apple2enh-system.cfg eightballvm_a2e.o eightballutils_a2e.o apple2enh-iobuf-0800.o $(CC65LIBDIR)/apple2enh.lib
|
||||
|
||||
unittest.8bp: unittest.8b
|
||||
tr {} [] <unittest.8b | \\100-\\132 \\300-\\332 | tr \\140-\\172 \\100-\\132 > unittest.8bp # ASCII -> PETSCII
|
||||
tr {} [] <unittest.8b | tr \\100-\\132 \\300-\\332 | tr \\140-\\172 \\100-\\132 > unittest.8bp # ASCII -> PETSCII
|
||||
|
||||
sieve4.8bp: sieve4.8b
|
||||
tr {} [] <sieve4.8b | tr \\100-\\132 \\300-\\332 | tr \\140-\\172 \\100-\\132 > sieve4.8bp # ASCII -> PETSCII
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
/**************************************************************************/
|
||||
/* EightBall Disassembler */
|
||||
/* */
|
||||
/* The Eight Bit Algorithmic Language */
|
||||
/* For Apple IIe/c/gs (64K), Commodore 64, VIC-20 +32K RAM expansion */
|
||||
/* (also builds for Linux as 32 bit executable (gcc -m32) only) */
|
||||
/* */
|
||||
/* Compiles with cc65 v2.15 for VIC-20, C64, Apple II */
|
||||
/* and gcc 7.3 for Linux */
|
||||
/* */
|
||||
/* cc65: Define symbol VIC20 to build for Commodore VIC-20 + 32K. */
|
||||
/* Define symbol C64 to build for Commodore 64. */
|
||||
/* Define symbol A2E to build for Apple //e. */
|
||||
/* */
|
||||
/* Copyright Bobbi Webber-Manners 2018 */
|
||||
/* EightBall VM disassembler */
|
||||
/* */
|
||||
/* Formatted with indent -kr -nut */
|
||||
/**************************************************************************/
|
||||
|
||||
/**************************************************************************/
|
||||
/* GNU PUBLIC LICENCE v3 OR LATER */
|
||||
/* */
|
||||
/* This program is free software: you can redistribute it and/or modify */
|
||||
/* it under the terms of the GNU General Public License as published by */
|
||||
/* the Free Software Foundation, either version 3 of the License, or */
|
||||
/* (at your option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will be useful, */
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
|
||||
/* GNU General Public License for more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public License */
|
||||
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "eightballvm.h"
|
||||
#include "eightballutils.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef A2E
|
||||
#include <conio.h>
|
||||
#endif
|
||||
|
||||
/* Order must match enum bytecode */
|
||||
char *bytecodenames[] = {
|
||||
"END",
|
||||
"LDI",
|
||||
"LDAW",
|
||||
"LDAWI",
|
||||
"LDAB",
|
||||
"LDABI",
|
||||
"STAW",
|
||||
"STAWI",
|
||||
"STAB",
|
||||
"STABI",
|
||||
"LDRW",
|
||||
"LDRWI",
|
||||
"LDRB",
|
||||
"LDRBI",
|
||||
"STRW",
|
||||
"STRWI",
|
||||
"STRB",
|
||||
"STRBI",
|
||||
"SWP",
|
||||
"DUP",
|
||||
"DUP2",
|
||||
"DRP",
|
||||
"OVER",
|
||||
"PICK",
|
||||
"POPW",
|
||||
"POPB",
|
||||
"PSHW",
|
||||
"PSHB",
|
||||
"DISC",
|
||||
"SPFP",
|
||||
"FPSP",
|
||||
"ATOR",
|
||||
"RTOA",
|
||||
"INC",
|
||||
"DEC",
|
||||
"ADD",
|
||||
"SUB",
|
||||
"MUL",
|
||||
"DIV",
|
||||
"MOD",
|
||||
"NEG",
|
||||
"GT",
|
||||
"GTE",
|
||||
"LT",
|
||||
"LTE",
|
||||
"EQL",
|
||||
"NEQL",
|
||||
"AND",
|
||||
"OR",
|
||||
"NOT",
|
||||
"BAND",
|
||||
"BOR",
|
||||
"BXOR",
|
||||
"BNOT",
|
||||
"LSH",
|
||||
"RSH",
|
||||
"JMP",
|
||||
"JMPI",
|
||||
"BRC",
|
||||
"BRCI",
|
||||
"JSR",
|
||||
"JSRI",
|
||||
"RTS",
|
||||
"PRDEC",
|
||||
"PRHEX",
|
||||
"PRCH",
|
||||
"PRSTR",
|
||||
"PRMSG",
|
||||
"KBDCH",
|
||||
"KBDLN"
|
||||
};
|
||||
|
||||
/*
|
||||
* Call stack grows down from top of memory.
|
||||
* If it hits CALLSTACKLIM then VM will quit with error
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
#define MEMORYSZ (64 * 1024)
|
||||
#else
|
||||
/* Has to be 64K minus a byte otherwise winds up being zero! */
|
||||
#define MEMORYSZ (64 * 1024) - 1
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
unsigned char memory[MEMORYSZ];
|
||||
#else
|
||||
unsigned char *memory = 0;
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define UINT16 unsigned short
|
||||
#else
|
||||
#define UINT16 unsigned int
|
||||
#endif
|
||||
|
||||
UINT16 pc = RTPCSTART; /* Program counter */
|
||||
UINT16 lastpc;
|
||||
|
||||
/*
|
||||
* Print a value as hex
|
||||
*/
|
||||
void _printhexbyte(unsigned char val) {
|
||||
|
||||
printchar(hexval2char((val>>4) & 0x0f));
|
||||
printchar(hexval2char(val & 0x0f));
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch, decode and disassemble a VM instruction, then advance the program counter.
|
||||
*/
|
||||
void disassemble_instruction()
|
||||
{
|
||||
printhex(pc);
|
||||
print(": ");
|
||||
_printhexbyte(memory[pc]);
|
||||
printchar(' ');
|
||||
switch(memory[pc++]) {
|
||||
case VM_LDIMM:
|
||||
case VM_LDAWORDIMM:
|
||||
case VM_LDABYTEIMM:
|
||||
case VM_LDRWORDIMM:
|
||||
case VM_LDRBYTEIMM:
|
||||
case VM_STAWORDIMM:
|
||||
case VM_STABYTEIMM:
|
||||
case VM_STRWORDIMM:
|
||||
case VM_STRBYTEIMM:
|
||||
case VM_JMPIMM:
|
||||
case VM_BRNCHIMM:
|
||||
case VM_JSRIMM:
|
||||
_printhexbyte(memory[pc++]);
|
||||
printchar(' ');
|
||||
_printhexbyte(memory[pc++]);
|
||||
print(" ");
|
||||
print(bytecodenames[memory[pc-3]]);
|
||||
printchar(' ');
|
||||
printhex(memory[pc-2] + (memory[pc-1] << 8));
|
||||
print(" (");
|
||||
printdec(memory[pc-2] + (memory[pc-1] << 8));
|
||||
print(")");
|
||||
break;
|
||||
case VM_PRMSG:
|
||||
print("...00 ");
|
||||
print(bytecodenames[memory[pc-1]]);
|
||||
print(" \"");
|
||||
while(memory[pc]) {
|
||||
printchar(memory[pc++]);
|
||||
}
|
||||
++pc;
|
||||
printchar('"');
|
||||
break;
|
||||
default:
|
||||
print(" ");
|
||||
if (memory[pc-1] <= VM_KBDLN) {
|
||||
print(bytecodenames[memory[pc-1]]);
|
||||
} else {
|
||||
print("**ILLEGAL**");
|
||||
}
|
||||
}
|
||||
#ifdef A2E
|
||||
printchar('\r');
|
||||
#else
|
||||
printchar('\n');
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* Disassemble the program!
|
||||
*/
|
||||
void disassemble()
|
||||
{
|
||||
while (pc < lastpc) {
|
||||
disassemble_instruction();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Load bytecode into memory[].
|
||||
*/
|
||||
void load()
|
||||
{
|
||||
FILE *fp;
|
||||
char ch;
|
||||
|
||||
pc = RTPCSTART;
|
||||
do {
|
||||
print("\nBytecode file (CR for default)>");
|
||||
getln((char*)memory, 15);
|
||||
if (strlen((char*)memory) == 0) {
|
||||
strcpy((char*)memory, "bytecode");
|
||||
}
|
||||
print("Loading '");
|
||||
print((char*)memory);
|
||||
print("'\n");
|
||||
fp = fopen((char*)memory, "r");
|
||||
} while (!fp);
|
||||
while (!feof(fp)) {
|
||||
ch = fgetc(fp);
|
||||
memory[pc++] = ch;
|
||||
/* Print dot for each page */
|
||||
if (pc%0xff == 0) {
|
||||
printchar('.');
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
lastpc = pc - 1;
|
||||
pc = RTPCSTART;
|
||||
#ifdef A2E
|
||||
printchar(7);
|
||||
#endif
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
print("EightBall Disassembler v" VERSIONSTR "\n");
|
||||
print("(c)Bobbi, 2018\n");
|
||||
print("Free Software.\n");
|
||||
print("Licenced under GPL.\n\n");
|
||||
|
||||
load();
|
||||
#ifdef __GNUC__
|
||||
print(" Done.\n\n");
|
||||
#endif
|
||||
#ifdef A2E
|
||||
videomode(VIDEOMODE_80COL);
|
||||
clrscr();
|
||||
#elif defined(CBM)
|
||||
printchar(147); /* Clear */
|
||||
#endif
|
||||
disassemble();
|
||||
return 0;
|
||||
}
|
||||
BIN
Binary file not shown.
+125
-52
@@ -1069,7 +1069,6 @@ unsigned char P()
|
||||
if (compile) {
|
||||
compiletimelookup = 1;
|
||||
if (getintvar(key, idx, &arg, &type, addressmode)) {
|
||||
error(ERR_VAR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1080,7 +1079,6 @@ unsigned char P()
|
||||
}
|
||||
|
||||
if (getintvar(key, idx, &arg, &type, addressmode)) {
|
||||
error(ERR_VAR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1237,7 +1235,7 @@ unsigned char *heap2PtrBttm; /* Arena 2: bottom-up heap */
|
||||
|
||||
//#define HEAP2TOP (char*)0x97ff
|
||||
#define HEAP2TOP (char*)0xa7ff
|
||||
#define HEAP2LIM (char*)0x8a00
|
||||
#define HEAP2LIM (char*)0x8900
|
||||
/* HEAP2LIM HAS TO BE ADJUSTED TO NOT
|
||||
* TRASH THE CODE, WHICH LOADS FROM $2000 UP
|
||||
* USE THE MAPFILE! */
|
||||
@@ -1258,7 +1256,7 @@ unsigned char *heap2PtrBttm; /* Arena 2: bottom-up heap */
|
||||
#define HEAP1LIM (char*)0xa000
|
||||
|
||||
#define HEAP2TOP (char*)0x9fff - 0x0400 /* Leave $800 for the C stack */
|
||||
#define HEAP2LIM (char*)0x7100
|
||||
#define HEAP2LIM (char*)0x6f00
|
||||
/* HEAP2LIM HAS TO BE ADJUSTED TO NOT
|
||||
* TRASH THE CODE, WHICH LOADS FROM $0800 UP
|
||||
* USE THE MAPFILE! */
|
||||
@@ -1282,12 +1280,12 @@ unsigned char *heap2PtrBttm; /* Arena 2: bottom-up heap */
|
||||
//#define HEAP1LIM (char*)0xa000
|
||||
|
||||
//#define HEAP2TOP (char*)0x7fff - 0x0400 /* Leave $400 for the C stack */
|
||||
//#define HEAP2LIM (char*)0x7c00 /* HEAP2LIM HAS TO BE ADJUSTED TO NOT
|
||||
//#define HEAP2LIM (char*)0x7600 /* HEAP2LIM HAS TO BE ADJUSTED TO NOT
|
||||
// * TRASH THE CODE, WHICH LOADS FROM $1200 UP
|
||||
// * USE THE MAPFILE! */
|
||||
|
||||
// Everything in BLK5 for now
|
||||
// BLK3 is totally full of code!
|
||||
// BLK3 is almost totally full of code!
|
||||
// Man ... we really need more memory!!
|
||||
#define HEAP1TOP (char*)0xbfff
|
||||
#define HEAP1LIM (char*)0xb000
|
||||
@@ -1458,28 +1456,53 @@ int getfreespace2()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compiler: Emit bytecode (used for everything except VM_LDIMM)
|
||||
* Compiler: Emit simple one byte code
|
||||
* Used for everything except immediate mode opcodes
|
||||
* Stores using codeptr.
|
||||
*/
|
||||
void emit(enum bytecode code)
|
||||
{
|
||||
/*
|
||||
unsigned char c = code;
|
||||
*/
|
||||
|
||||
*codeptr = code;
|
||||
++codeptr;
|
||||
|
||||
/*
|
||||
printhex(rtPC);
|
||||
print(": ");
|
||||
printhexbyte(c);
|
||||
print(" : ");
|
||||
print(bytecodenames[c]);
|
||||
printchar('\n');
|
||||
*/
|
||||
++rtPC;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compiler: Emit opcode and 16 bit word argument
|
||||
* Stores using codeptr.
|
||||
*/
|
||||
void emit_imm(enum bytecode code, int word)
|
||||
{
|
||||
unsigned char *p = (unsigned char *) &word;
|
||||
|
||||
*codeptr = code;
|
||||
++codeptr;
|
||||
*codeptr = *p;
|
||||
++codeptr;
|
||||
++p;
|
||||
*codeptr = *p;
|
||||
++codeptr;
|
||||
rtPC += 3;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Compiler: Emit word argument (VM_LDIMM opcode)
|
||||
* Stores using codeptr.
|
||||
* TODO: Eventually we can remove this
|
||||
*/
|
||||
void emitldi(int word)
|
||||
{
|
||||
@@ -1494,6 +1517,7 @@ void emitldi(int word)
|
||||
*codeptr = *p;
|
||||
++codeptr;
|
||||
|
||||
/*
|
||||
printhex(rtPC);
|
||||
print(": ");
|
||||
printhexbyte(c);
|
||||
@@ -1504,6 +1528,7 @@ void emitldi(int word)
|
||||
printchar(' ');
|
||||
printhex(word);
|
||||
printchar('\n');
|
||||
*/
|
||||
rtPC += 3;
|
||||
}
|
||||
|
||||
@@ -1517,18 +1542,23 @@ void emitprmsg(void)
|
||||
char *p = readbuf;
|
||||
emit(VM_PRMSG);
|
||||
++rtPC;
|
||||
/*
|
||||
printchar('"');
|
||||
*/
|
||||
while (*p) {
|
||||
*codeptr = *p;
|
||||
++rtPC;
|
||||
/*
|
||||
printchar(*p);
|
||||
*/
|
||||
++codeptr;
|
||||
++p;
|
||||
}
|
||||
*codeptr = 0;
|
||||
++codeptr;
|
||||
|
||||
/*
|
||||
print("\"\n");
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1547,10 +1577,12 @@ void emit_fixup(int address, int word)
|
||||
++p;
|
||||
*ptr = *p;
|
||||
|
||||
/*
|
||||
printhex(address);
|
||||
print(": ");
|
||||
printhex(word);
|
||||
print(" ; Fixup\n");
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1563,6 +1595,7 @@ void writebytecode()
|
||||
unsigned char *p;
|
||||
p = (unsigned char *) CODESTART;
|
||||
strcpy(readbuf, "bytecode");
|
||||
printchar('\n');
|
||||
openfile(1);
|
||||
print("...\n");
|
||||
while (p < end) {
|
||||
@@ -2019,8 +2052,7 @@ unsigned char createintvar(char *name,
|
||||
emit((type == TYPE_WORD) ? VM_PSHWORD : VM_PSHBYTE);
|
||||
emitldi(0);
|
||||
emit(VM_NEQL);
|
||||
emitldi(rtPC - 10);
|
||||
emit(VM_BRNCH);
|
||||
emit_imm(VM_BRNCHIMM, rtPC - 10);
|
||||
emit(VM_DROP);
|
||||
|
||||
/*
|
||||
@@ -2034,9 +2066,7 @@ unsigned char createintvar(char *name,
|
||||
for (i = 0; i < sz; ++i) {
|
||||
if (arrinitmode == STRG_INIT) {
|
||||
emitldi((*txtPtr == '"') ? 0 : *txtPtr);
|
||||
((type ==
|
||||
TYPE_WORD) ? civ_st_rel_word(i) :
|
||||
civ_st_rel_byte(i));
|
||||
((type == TYPE_WORD) ? civ_st_rel_word(i) : civ_st_rel_byte(i));
|
||||
if (*txtPtr == '"') {
|
||||
break;
|
||||
}
|
||||
@@ -2228,6 +2258,22 @@ void siv_st_rel(unsigned char type)
|
||||
((type == TYPE_WORD) ? emit(VM_STRWORD) : emit(VM_STRBYTE));
|
||||
}
|
||||
|
||||
/* Factored out to save a few bytes
|
||||
* Used by setintvar() only.
|
||||
*/
|
||||
void siv_st_abs_imm(unsigned int addr, unsigned char type)
|
||||
{
|
||||
emit_imm(((type & 0x0f) == TYPE_WORD) ? VM_STAWORDIMM : VM_STABYTEIMM, addr);
|
||||
}
|
||||
|
||||
/* Factored out to save a few bytes
|
||||
* Used by setintvar() only.
|
||||
*/
|
||||
void siv_st_rel_imm(unsigned int addr, unsigned char type)
|
||||
{
|
||||
emit_imm(((type & 0x0f) == TYPE_WORD) ? VM_STRWORDIMM : VM_STRBYTEIMM, addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set existing integer variable
|
||||
* name is the variable name
|
||||
@@ -2277,11 +2323,10 @@ unsigned char setintvar(char *name, int idx, int value)
|
||||
* ABSOLUTE addressing, but locals are addressed RELATIVE
|
||||
* to the frame pointer.
|
||||
*/
|
||||
emitldi(*getptrtoscalarword(ptr));
|
||||
if (local && compilingsub) {
|
||||
siv_st_rel(type);
|
||||
siv_st_rel_imm(*getptrtoscalarword(ptr), type);
|
||||
} else {
|
||||
siv_st_abs(type);
|
||||
siv_st_abs_imm(*getptrtoscalarword(ptr), type);
|
||||
}
|
||||
} else {
|
||||
if (type == TYPE_WORD) {
|
||||
@@ -2299,8 +2344,7 @@ unsigned char setintvar(char *name, int idx, int value)
|
||||
error(ERR_SUBSCR);
|
||||
return 1;
|
||||
}
|
||||
bodyptr =
|
||||
(void *) *(int *) ((unsigned char *) ptr + sizeof(var_t));
|
||||
bodyptr = (void *) *(int *) ((unsigned char *) ptr + sizeof(var_t));
|
||||
|
||||
if (compile) {
|
||||
/* *** Index is on the stack (X) */
|
||||
@@ -2360,6 +2404,22 @@ void giv_ld_rel(unsigned char type)
|
||||
(((type & 0x0f) == TYPE_WORD) ? emit(VM_LDRWORD) : emit(VM_LDRBYTE));
|
||||
}
|
||||
|
||||
/* Factored out to save a few bytes
|
||||
* Used by getintvar() only.
|
||||
*/
|
||||
void giv_ld_abs_imm(unsigned int addr, unsigned char type)
|
||||
{
|
||||
emit_imm(((type & 0x0f) == TYPE_WORD) ? VM_LDAWORDIMM : VM_LDABYTEIMM, addr);
|
||||
}
|
||||
|
||||
/* Factored out to save a few bytes
|
||||
* Used by getintvar() only.
|
||||
*/
|
||||
void giv_ld_rel_imm(unsigned int addr, unsigned char type)
|
||||
{
|
||||
emit_imm(((type & 0x0f) == TYPE_WORD) ? VM_LDRWORDIMM : VM_LDRBYTEIMM, addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get existing integer variable
|
||||
* name is the variable name
|
||||
@@ -2423,11 +2483,10 @@ unsigned char getintvar(char *name,
|
||||
emit(VM_RTOA);
|
||||
}
|
||||
} else {
|
||||
emitldi(*getptrtoscalarword(ptr));
|
||||
if (local && compilingsub) {
|
||||
giv_ld_rel(*type);
|
||||
giv_ld_rel_imm(*getptrtoscalarword(ptr), *type);
|
||||
} else {
|
||||
giv_ld_abs(*type);
|
||||
giv_ld_abs_imm(*getptrtoscalarword(ptr), *type);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -2565,8 +2624,7 @@ void doif(unsigned char arg)
|
||||
/* **** Value of IF expression is on the eval stack **** */
|
||||
emit(VM_NOT);
|
||||
push_return(rtPC + 1);
|
||||
emitldi(0xffff); /* To be filled in later */
|
||||
emit(VM_BRNCH);
|
||||
emit_imm(VM_BRNCHIMM, 0xffff); /* To be filled in later */
|
||||
push_return(0);
|
||||
} else {
|
||||
if (skipFlag) {
|
||||
@@ -2599,8 +2657,7 @@ unsigned char doelse()
|
||||
* Code to jump over ELSE block when IF condition is true
|
||||
*/
|
||||
return_stack[returnSP + 1] = rtPC;
|
||||
emitldi(0xffff); /* To be filled in later */
|
||||
emit(VM_JMP);
|
||||
emit_imm(VM_JMPIMM, 0xffff); /* To be filled in later */
|
||||
|
||||
/*
|
||||
* Fixup the dummy destination address initialized by
|
||||
@@ -2841,7 +2898,6 @@ unsigned char assignorcreate(unsigned char mode)
|
||||
compiletimelookup = 1;
|
||||
}
|
||||
if (getintvar(name, i, &j, &type, 1)) {
|
||||
error(ERR_VAR);
|
||||
return RET_ERROR;
|
||||
}
|
||||
|
||||
@@ -2933,27 +2989,27 @@ unsigned char doendfor()
|
||||
emit(VM_DUP);
|
||||
emit(VM_PSHWORD);
|
||||
|
||||
emitldi(return_stack[returnSP + 2]); /* Pointer to loop variable */
|
||||
//emitldi(return_stack[returnSP + 2]); /* Pointer to loop variable */
|
||||
if (return_stack[returnSP + 4]) { /* Rel or abs */
|
||||
emit((type == TYPE_WORD) ? VM_LDRWORD : VM_LDRBYTE);
|
||||
/* Pointer to loop var */
|
||||
emit_imm((type == TYPE_WORD) ? VM_LDRWORDIMM : VM_LDRBYTEIMM, return_stack[returnSP + 2]);
|
||||
} else {
|
||||
emit((type == TYPE_WORD) ? VM_LDAWORD : VM_LDABYTE);
|
||||
/* Pointer to loop var */
|
||||
emit_imm((type == TYPE_WORD) ? VM_LDAWORDIMM : VM_LDABYTEIMM, return_stack[returnSP + 2]);
|
||||
}
|
||||
|
||||
/* Increment and store loop variable */
|
||||
emit(VM_INC);
|
||||
emit(VM_DUP);
|
||||
emitldi(return_stack[returnSP + 2]);
|
||||
if (return_stack[returnSP + 4]) {
|
||||
emit((type == TYPE_WORD) ? VM_STRWORD : VM_STRBYTE);
|
||||
emit_imm((type == TYPE_WORD) ? VM_STRWORDIMM : VM_STRBYTEIMM, return_stack[returnSP + 2]);
|
||||
} else {
|
||||
emit((type == TYPE_WORD) ? VM_STAWORD : VM_STABYTE);
|
||||
emit_imm((type == TYPE_WORD) ? VM_STAWORDIMM : VM_STABYTEIMM, return_stack[returnSP + 2]);
|
||||
}
|
||||
|
||||
/* Compare with loop limit already on eval stack */
|
||||
emit(VM_GTE);
|
||||
emitldi(return_stack[returnSP + 3]); /* Branch destination */
|
||||
emit(VM_BRNCH);
|
||||
emit_imm(VM_BRNCHIMM, return_stack[returnSP + 3]); /* Branch destination */
|
||||
|
||||
/* Drop loop limit from call stack */
|
||||
emit(VM_POPWORD);
|
||||
@@ -3027,8 +3083,7 @@ void dowhile(char *startTxtPtr, unsigned char arg)
|
||||
/* **** Value of WHILE expression is on the eval stack **** */
|
||||
emit(VM_NOT);
|
||||
push_return(rtPC + 1); /* Address of dummy 0xffff */
|
||||
emitldi(0xffff);
|
||||
emit(VM_BRNCH);
|
||||
emit_imm(VM_BRNCHIMM, 0xffff);
|
||||
push_return(0); /* Dummy */
|
||||
} else {
|
||||
if (skipFlag) {
|
||||
@@ -3062,8 +3117,8 @@ unsigned char doendwhile()
|
||||
/*
|
||||
* Jump back and re-evaluate the WHILE argument.
|
||||
*/
|
||||
emitldi(return_stack[returnSP + 3]);
|
||||
emit(VM_JMP);
|
||||
emit_imm(VM_JMPIMM, return_stack[returnSP + 3]);
|
||||
|
||||
/*
|
||||
* Fixup the dummy destination address initialized by
|
||||
* dowhile() to point to the ENDWHILE.
|
||||
@@ -3166,9 +3221,9 @@ unsigned char dosubr()
|
||||
|
||||
compilingsub = 1;
|
||||
|
||||
print("\nsub ");
|
||||
print("\n[");
|
||||
print(readbuf);
|
||||
print("\n");
|
||||
print("]");
|
||||
|
||||
/*
|
||||
* Create entry in subroutine table
|
||||
@@ -3367,10 +3422,14 @@ unsigned char docall()
|
||||
strncpy(s->name, readbuf, SUBRNUMCHARS);
|
||||
}
|
||||
|
||||
counter = -1;
|
||||
if (!compile) {
|
||||
counter = -1;
|
||||
}
|
||||
while (l) {
|
||||
p = l->line;
|
||||
++counter;
|
||||
if (!compile) {
|
||||
++counter;
|
||||
}
|
||||
|
||||
skipFlag = 0;
|
||||
|
||||
@@ -3408,6 +3467,7 @@ unsigned char docall()
|
||||
*/
|
||||
eatspace();
|
||||
if (expect('(')) {
|
||||
counter = origcounter;
|
||||
return RET_ERROR;
|
||||
}
|
||||
|
||||
@@ -3512,10 +3572,12 @@ unsigned char docall()
|
||||
|
||||
/* If end of line, error */
|
||||
if (!(*txtPtr)) {
|
||||
counter = origcounter;
|
||||
error(ERR_ARG);
|
||||
return RET_ERROR;
|
||||
}
|
||||
if (*txtPtr == ')') {
|
||||
counter = origcounter;
|
||||
error(ERR_ARG);
|
||||
return RET_ERROR;
|
||||
}
|
||||
@@ -3529,6 +3591,7 @@ unsigned char docall()
|
||||
}
|
||||
if (eval(0, &arg)) {
|
||||
/* No expression found */
|
||||
counter = origcounter;
|
||||
error(ERR_ARG);
|
||||
return RET_ERROR;
|
||||
}
|
||||
@@ -3565,12 +3628,14 @@ unsigned char docall()
|
||||
varslocal = oldvarslocal;
|
||||
array = findintvar(name2, &local);
|
||||
if (!array) {
|
||||
counter = origcounter;
|
||||
error(ERR_VAR);
|
||||
return RET_ERROR;
|
||||
}
|
||||
/* j holds number of dimensions */
|
||||
j = (array->type & 0xf0) >> 4;
|
||||
if (((array->type & 0x0f) != type) || (j == 0)) {
|
||||
counter = origcounter;
|
||||
error(ERR_TYPE);
|
||||
return RET_ERROR;
|
||||
}
|
||||
@@ -3585,6 +3650,7 @@ unsigned char docall()
|
||||
} else {
|
||||
if (eval(0, &arg)) {
|
||||
/* No expression found */
|
||||
counter = origcounter;
|
||||
error(ERR_ARG);
|
||||
return RET_ERROR;
|
||||
}
|
||||
@@ -3614,11 +3680,14 @@ unsigned char docall()
|
||||
|
||||
eatspace();
|
||||
if (expect(')')) {
|
||||
counter = origcounter;
|
||||
return RET_ERROR;
|
||||
}
|
||||
|
||||
if (compile) {
|
||||
emitldi(0xffff);
|
||||
|
||||
emit_imm(VM_JSRIMM, 0xffff);
|
||||
|
||||
/*
|
||||
* Create entry in call table
|
||||
*/
|
||||
@@ -3633,8 +3702,6 @@ unsigned char docall()
|
||||
callsbegin = s;
|
||||
}
|
||||
|
||||
emit(VM_JSR);
|
||||
|
||||
/* Caller must drop the arguments
|
||||
* pushed to call stack above */
|
||||
if (argbytes) {
|
||||
@@ -3658,8 +3725,8 @@ unsigned char docall()
|
||||
}
|
||||
l = l->next;
|
||||
}
|
||||
error(ERR_NOSUB);
|
||||
counter = origcounter;
|
||||
error(ERR_NOSUB);
|
||||
return RET_ERROR;
|
||||
}
|
||||
|
||||
@@ -4204,8 +4271,7 @@ unsigned char parseline()
|
||||
emitldi(0x8000);
|
||||
emit(VM_BITAND);
|
||||
emit(VM_NOT);
|
||||
emitldi(rtPC + 9); /* Jump over printing of '-' */
|
||||
emit(VM_BRNCH);
|
||||
emit_imm(VM_BRNCHIMM, rtPC + 9); /* Jump over printing of '-' */
|
||||
emitldi('-');
|
||||
emit(VM_PRCH);
|
||||
emit(VM_NEG);
|
||||
@@ -4315,13 +4381,15 @@ unsigned char parseline()
|
||||
callsbegin = callsend = NULL;
|
||||
CLEARRTCALLSTACK();
|
||||
run(0);
|
||||
emit(VM_END);
|
||||
linksubs();
|
||||
writebytecode();
|
||||
if (compile) {
|
||||
emit(VM_END);
|
||||
linksubs();
|
||||
writebytecode();
|
||||
compile = 0;
|
||||
}
|
||||
#ifndef __GNUC__
|
||||
CLEARHEAP2TOP(); /* Clear the linkage table */
|
||||
#endif
|
||||
compile = 0;
|
||||
break;
|
||||
case TOK_NEW:
|
||||
new();
|
||||
@@ -4810,6 +4878,9 @@ void run(unsigned char cont)
|
||||
current = program;
|
||||
}
|
||||
while (current && !status) {
|
||||
if (compile) {
|
||||
printchar('.');
|
||||
}
|
||||
txtPtr = current->line;
|
||||
status = parseline();
|
||||
/* parseline() can set current to NULL when return is to
|
||||
@@ -4827,6 +4898,7 @@ void run(unsigned char cont)
|
||||
printchar('\n');
|
||||
returnSP = (RETSTACKSZ - 1);
|
||||
skipFlag = 0;
|
||||
compile = 0;
|
||||
break;
|
||||
case 3:
|
||||
print("\nBrk at ");
|
||||
@@ -4834,6 +4906,7 @@ void run(unsigned char cont)
|
||||
printchar('\n');
|
||||
returnSP = (RETSTACKSZ - 1);
|
||||
skipFlag = 0;
|
||||
compile = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
+1
-1
@@ -37,7 +37,7 @@
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#define VERSIONSTR "0.69"
|
||||
#define VERSIONSTR "0.70"
|
||||
|
||||
void print(char *str);
|
||||
|
||||
|
||||
BIN
Binary file not shown.
+176
-53
@@ -62,6 +62,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef A2E
|
||||
#include <conio.h>
|
||||
@@ -84,7 +85,7 @@
|
||||
#ifdef __GNUC__
|
||||
#define UINT16 unsigned short
|
||||
#else
|
||||
#define UINT16 unsigned int
|
||||
#define UINT16 unsigned short
|
||||
#endif
|
||||
|
||||
UINT16 pc = RTPCSTART; /* Program counter */
|
||||
@@ -116,11 +117,11 @@ unsigned char *memory = 0;
|
||||
#define TREG evalstack[evalptr - 4] /* Only valid if evalptr >= 4 */
|
||||
|
||||
/*
|
||||
* Error checks are called through macros to make it easy to
|
||||
* disable them in production. We should not need these checks
|
||||
* in production (assuming no bugs in the compiler!) ... but they
|
||||
* are helpful for debugging!
|
||||
*/
|
||||
* Error checks are called through macros to make it easy to
|
||||
* disable them in production. We should not need these checks
|
||||
* in production (assuming no bugs in the compiler!) ... but they
|
||||
* are helpful for debugging!
|
||||
*/
|
||||
|
||||
#ifdef STACKCHECKS
|
||||
|
||||
@@ -148,10 +149,11 @@ unsigned char *memory = 0;
|
||||
/* Handler for unsupported bytecode */
|
||||
#define UNSUPPORTED() unsupported()
|
||||
|
||||
#ifdef STACKCHECKS
|
||||
/*
|
||||
* Check for evaluation stack underflow.
|
||||
* level - Number of 16 bit operands required on eval stack.
|
||||
*/
|
||||
* Check for evaluation stack underflow.
|
||||
* level - Number of 16 bit operands required on eval stack.
|
||||
*/
|
||||
void checkunderflow(unsigned char level)
|
||||
{
|
||||
if (evalptr < level) {
|
||||
@@ -163,9 +165,9 @@ void checkunderflow(unsigned char level)
|
||||
}
|
||||
|
||||
/*
|
||||
* Check evaluation stack is not going to overflow.
|
||||
* Assumes evalptr has already been advanced.
|
||||
*/
|
||||
* Check evaluation stack is not going to overflow.
|
||||
* Assumes evalptr has already been advanced.
|
||||
*/
|
||||
void checkoverflow()
|
||||
{
|
||||
if (evalptr > EVALSTACKSZ - 1) {
|
||||
@@ -177,9 +179,9 @@ void checkoverflow()
|
||||
}
|
||||
|
||||
/*
|
||||
* Check call stack is not going to underflow.
|
||||
* bytes - Number of bytes required on call stack.
|
||||
*/
|
||||
* Check call stack is not going to underflow.
|
||||
* bytes - Number of bytes required on call stack.
|
||||
*/
|
||||
void checkstackunderflow(unsigned char bytes)
|
||||
{
|
||||
if ((MEMORYSZ - sp) < bytes) {
|
||||
@@ -191,9 +193,9 @@ void checkstackunderflow(unsigned char bytes)
|
||||
}
|
||||
|
||||
/*
|
||||
* Check call stack is not going to overflow.
|
||||
* Assumes sp has already been advanced.
|
||||
*/
|
||||
* Check call stack is not going to overflow.
|
||||
* Assumes sp has already been advanced.
|
||||
*/
|
||||
void checkstackoverflow()
|
||||
{
|
||||
if (sp < CALLSTACKLIM + 1) {
|
||||
@@ -203,10 +205,11 @@ void checkstackoverflow()
|
||||
while (1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handler for unsupported bytecodes
|
||||
*/
|
||||
* Handler for unsupported bytecodes
|
||||
*/
|
||||
void unsupported()
|
||||
{
|
||||
print("Unsupported instruction ");
|
||||
@@ -218,19 +221,20 @@ void unsupported()
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch, decode and execute a VM instruction, then advance the program counter.
|
||||
*/
|
||||
* Fetch, decode and execute a VM instruction, then advance the program counter.
|
||||
*/
|
||||
void execute_instruction()
|
||||
{
|
||||
unsigned int tempword;
|
||||
unsigned short tempword;
|
||||
unsigned short *wordptr;
|
||||
unsigned char *byteptr;
|
||||
#ifndef __GNUC__
|
||||
unsigned int delay;
|
||||
unsigned short delay;
|
||||
#endif
|
||||
|
||||
//print("--->PC "); printhex(pc); print(" eval stk: "); printhex(evalptr); print("\n");
|
||||
#ifdef DEBUGREGS
|
||||
unsigned int i;
|
||||
unsigned short i;
|
||||
print("\n");
|
||||
print("--->PC ");
|
||||
printhex(pc);
|
||||
@@ -266,9 +270,22 @@ void execute_instruction()
|
||||
printhex(pc);
|
||||
print(": ");
|
||||
print(bytecodenames[memory[pc]]);
|
||||
if (memory[pc] == VM_LDIMM) {
|
||||
/* TODO: Should encode immediate mode as one bit of opcode to make this more efficient */
|
||||
if ((memory[pc] == VM_LDIMM) ||
|
||||
(memory[pc] == VM_LDAWORDIMM) ||
|
||||
(memory[pc] == VM_LDABYTEIMM) ||
|
||||
(memory[pc] == VM_LDRWORDIMM) ||
|
||||
(memory[pc] == VM_LDRBYTEIMM) ||
|
||||
(memory[pc] == VM_STAWORDIMM) ||
|
||||
(memory[pc] == VM_STABYTEIMM) ||
|
||||
(memory[pc] == VM_STRWORDIMM) ||
|
||||
(memory[pc] == VM_STRBYTEIMM) ||
|
||||
(memory[pc] == VM_JMPIMM) ||
|
||||
(memory[pc] == VM_BRNCHIMM) ||
|
||||
(memory[pc] == VM_JSRIMM)) {
|
||||
printchar(' ');
|
||||
printhex(memory[pc + 1] + 256 * memory[pc + 2]);
|
||||
wordptr = (unsigned short *)&memory[pc + 1];
|
||||
printhex(*wordptr);
|
||||
printchar(' ');
|
||||
} else {
|
||||
print(" ");
|
||||
@@ -324,10 +341,9 @@ void execute_instruction()
|
||||
case VM_LDIMM: /* Pushes the following 16 bit word to the evaluation stack */
|
||||
++evalptr;
|
||||
CHECKOVERFLOW();
|
||||
/* Note: Word is stored in little endian format! */
|
||||
tempword = memory[++pc];
|
||||
tempword += memory[++pc] * 256;
|
||||
XREG = tempword;
|
||||
wordptr = (unsigned short *)&memory[++pc];
|
||||
++pc;
|
||||
XREG = *wordptr;
|
||||
break;
|
||||
/*
|
||||
* Absolute addressing:
|
||||
@@ -342,23 +358,56 @@ void execute_instruction()
|
||||
printchar('\n');
|
||||
#endif
|
||||
|
||||
XREG = memory[XREG] + 256 * memory[XREG + 1];
|
||||
wordptr = (unsigned short *)&memory[XREG];
|
||||
XREG = *wordptr;
|
||||
break;
|
||||
case VM_LDAWORDIMM: /* Imm mode - push 16 bit value pointed to by addr after opcode */
|
||||
++evalptr;
|
||||
CHECKOVERFLOW();
|
||||
wordptr = (unsigned short *)&memory[++pc]; /* Pointer to operand */
|
||||
wordptr = (unsigned short *)&memory[*wordptr]; /* Pointer to variable */
|
||||
++pc;
|
||||
XREG = *wordptr;
|
||||
break;
|
||||
case VM_LDABYTE: /* Replaces X with 8 bit value pointed to by X. */
|
||||
CHECKUNDERFLOW(1);
|
||||
XREG = memory[XREG];
|
||||
break;
|
||||
case VM_STAWORD: /* Stores 16 bit value Y in addr pointed to by X. Drops X and Y. */
|
||||
case VM_LDABYTEIMM: /* Imm mode - push byte pointed to by addr after opcode */
|
||||
++evalptr;
|
||||
CHECKOVERFLOW();
|
||||
wordptr = (unsigned short *)&memory[++pc]; /* Pointer to operand */
|
||||
byteptr = (unsigned char *)&memory[*wordptr]; /* Pointer to variable */
|
||||
++pc;
|
||||
XREG = *byteptr;
|
||||
break;
|
||||
case VM_STAWORD: /* Stores 16 bit value Y in addr pointed to by X. Drops X and Y.*/
|
||||
CHECKUNDERFLOW(2);
|
||||
memory[XREG] = YREG & 0x00ff;
|
||||
memory[XREG + 1] = (YREG & 0xff00) >> 8;
|
||||
wordptr = (unsigned short *)&memory[XREG];
|
||||
*wordptr = YREG;
|
||||
evalptr -= 2;
|
||||
break;
|
||||
case VM_STAWORDIMM: /* Imm mode - store 16 bit value X in addr after opcode. Drop X.*/
|
||||
CHECKUNDERFLOW(1);
|
||||
wordptr = (unsigned short *)&memory[++pc]; /* Pointer to operand */
|
||||
wordptr = (unsigned short *)&memory[*wordptr]; /* Pointer to variable */
|
||||
++pc;
|
||||
*wordptr = XREG;
|
||||
--evalptr;
|
||||
break;
|
||||
case VM_STABYTE: /* Stores 8 bit value Y in addr pointed to by X. Drops X and Y. */
|
||||
CHECKUNDERFLOW(2);
|
||||
memory[XREG] = YREG;
|
||||
evalptr -= 2;
|
||||
break;
|
||||
case VM_STABYTEIMM: /* Imm mode - store 8 bit value X in addr after opcode. Drop X.*/
|
||||
CHECKUNDERFLOW(1);
|
||||
wordptr = (unsigned short *)&memory[++pc]; /* Pointer to operand */
|
||||
byteptr = (unsigned char *)&memory[*wordptr]; /* Pointer to variable */
|
||||
++pc;
|
||||
*byteptr = XREG;
|
||||
--evalptr;
|
||||
break;
|
||||
/*
|
||||
* Relative to Frame Pointer addressing:
|
||||
* XREG points to address in system memory relative to the frame pointer.
|
||||
@@ -376,9 +425,16 @@ void execute_instruction()
|
||||
printchar('\n');
|
||||
#endif
|
||||
|
||||
XREG =
|
||||
memory[(XREG + fp + 1) & 0xffff] +
|
||||
256 * memory[(XREG + fp + 2) & 0xffff];
|
||||
wordptr = (unsigned short *)&memory[(XREG + fp + 1) & 0xffff];
|
||||
XREG = *wordptr;
|
||||
break;
|
||||
case VM_LDRWORDIMM: /* Imm mode - push 16 bit value pointed to by addr after opcode */
|
||||
++evalptr;
|
||||
CHECKOVERFLOW();
|
||||
wordptr = (unsigned short *)&memory[++pc]; /* Pointer to operand */
|
||||
wordptr = (unsigned short *)&memory[(*wordptr + fp + 1) & 0xffff]; /* Pointer to variable */
|
||||
++pc;
|
||||
XREG = *wordptr;
|
||||
break;
|
||||
case VM_LDRBYTE: /* Replaces X with 8 bit value pointed to by X. */
|
||||
CHECKUNDERFLOW(1);
|
||||
@@ -395,17 +451,41 @@ void execute_instruction()
|
||||
|
||||
XREG = memory[(XREG + fp + 1) & 0xffff];
|
||||
break;
|
||||
case VM_LDRBYTEIMM: /* Imm mode - push byte pointed to by addr after opcode */
|
||||
++evalptr;
|
||||
CHECKOVERFLOW();
|
||||
wordptr = (unsigned short *)&memory[++pc]; /* Pointer to operand */
|
||||
byteptr = (unsigned char *)&memory[(*wordptr + fp + 1) & 0xffff]; /* Pointer to variable */
|
||||
++pc;
|
||||
XREG = *byteptr;
|
||||
break;
|
||||
case VM_STRWORD: /* Stores 16 bit value Y in addr pointed to by X. Drops X and Y. */
|
||||
CHECKUNDERFLOW(2);
|
||||
memory[(XREG + fp + 1) & 0xffff] = YREG & 0x00ff;
|
||||
memory[(XREG + fp + 2) & 0xffff] = (YREG & 0xff00) >> 8;
|
||||
wordptr = (unsigned short *)&memory[(XREG + fp + 1) & 0xffff];
|
||||
*wordptr = YREG;
|
||||
evalptr -= 2;
|
||||
break;
|
||||
case VM_STRWORDIMM: /* Imm mode - store 16 bit value X in addr after opcode. Drop X.*/
|
||||
CHECKUNDERFLOW(1);
|
||||
wordptr = (unsigned short *)&memory[++pc]; /* Pointer to operand */
|
||||
wordptr = (unsigned short *)&memory[(*wordptr + fp + 1) & 0xffff]; /* Pointer to variable */
|
||||
++pc;
|
||||
*wordptr = XREG;
|
||||
--evalptr;
|
||||
break;
|
||||
case VM_STRBYTE: /* Stores 8 bit value Y in addr pointed to by X. Drops X and Y. */
|
||||
CHECKUNDERFLOW(2);
|
||||
memory[(XREG + fp + 1) & 0xffff] = YREG;
|
||||
evalptr -= 2;
|
||||
break;
|
||||
case VM_STRBYTEIMM: /* Imm mode - store 8 bit value X in addr after opcode. Drop X.*/
|
||||
CHECKUNDERFLOW(1);
|
||||
wordptr = (unsigned short *)&memory[++pc]; /* Pointer to operand */
|
||||
byteptr = (unsigned char *)&memory[(*wordptr + fp + 1) & 0xffff]; /* Pointer to variable */
|
||||
++pc;
|
||||
*byteptr = XREG;
|
||||
--evalptr;
|
||||
break;
|
||||
/*
|
||||
* Manipulate evaluation stack
|
||||
*/
|
||||
@@ -450,7 +530,8 @@ void execute_instruction()
|
||||
sp += 2;
|
||||
++evalptr;
|
||||
CHECKOVERFLOW();
|
||||
XREG = memory[sp - 1] + 256 * memory[sp];
|
||||
wordptr = (unsigned short *)&memory[sp - 1];
|
||||
XREG = *wordptr;
|
||||
break;
|
||||
case VM_POPBYTE: /* Pop 8 bit value from call stack, push onto eval stack [X] */
|
||||
CHECKSTACKUNDERFLOW(1);
|
||||
@@ -467,11 +548,11 @@ void execute_instruction()
|
||||
printhex(sp - 1);
|
||||
printchar('\n');
|
||||
#endif
|
||||
|
||||
memory[sp] = (XREG & 0xff00) >> 8;
|
||||
byteptr = (unsigned char *)&XREG;
|
||||
memory[sp] = *(byteptr + 1);
|
||||
--sp;
|
||||
CHECKSTACKOVERFLOW();
|
||||
memory[sp] = XREG & 0x00ff;
|
||||
memory[sp] = *byteptr;
|
||||
--sp;
|
||||
CHECKSTACKOVERFLOW();
|
||||
--evalptr;
|
||||
@@ -506,10 +587,11 @@ void execute_instruction()
|
||||
#endif
|
||||
|
||||
/* Push old FP to stack */
|
||||
memory[sp] = (fp & 0xff00) >> 8;
|
||||
byteptr = (unsigned char *)&fp;
|
||||
memory[sp] = *(byteptr + 1);
|
||||
--sp;
|
||||
CHECKSTACKOVERFLOW();
|
||||
memory[sp] = fp & 0x00ff;
|
||||
memory[sp] = *byteptr;
|
||||
--sp;
|
||||
CHECKSTACKOVERFLOW();
|
||||
|
||||
@@ -531,7 +613,8 @@ void execute_instruction()
|
||||
CHECKSTACKUNDERFLOW(2);
|
||||
sp += 2;
|
||||
CHECKOVERFLOW();
|
||||
fp = memory[sp - 1] + 256 * memory[sp];
|
||||
wordptr = (unsigned short *)&memory[sp - 1];
|
||||
fp = *wordptr;
|
||||
|
||||
#ifdef DEBUGSTACK
|
||||
print(" Recovered FP ");
|
||||
@@ -676,6 +759,11 @@ void execute_instruction()
|
||||
pc = XREG;
|
||||
--evalptr;
|
||||
return; /* Do not advance program counter */
|
||||
case VM_JMPIMM: /* Imm mode - jump to 16 bit word following opcode */
|
||||
wordptr = (unsigned short *)&memory[++pc];
|
||||
++pc;
|
||||
pc = *wordptr;
|
||||
return;
|
||||
case VM_BRNCH: /* If Y!= 0, jump to address X. Drop X, Y. */
|
||||
CHECKUNDERFLOW(2);
|
||||
if (YREG) {
|
||||
@@ -685,22 +773,46 @@ void execute_instruction()
|
||||
}
|
||||
evalptr -= 2;
|
||||
return; /* Do not advance program counter */
|
||||
case VM_BRNCHIMM: /* Imm mode - if X!=0 branch to 16 bit word following opcode */
|
||||
wordptr = (unsigned short *)&memory[++pc];
|
||||
++pc;
|
||||
CHECKUNDERFLOW(1);
|
||||
if (XREG) {
|
||||
pc = *wordptr;
|
||||
} else {
|
||||
++pc;
|
||||
}
|
||||
--evalptr;
|
||||
return; /* Do not advance program counter */
|
||||
case VM_JSR: /* Push PC to call stack. Jump to address X. Drop X. */
|
||||
CHECKUNDERFLOW(1);
|
||||
byteptr = (unsigned char *) &pc;
|
||||
memory[sp] = *byteptr;
|
||||
memory[sp] = *(byteptr + 1);
|
||||
--sp;
|
||||
CHECKSTACKOVERFLOW();
|
||||
memory[sp] = *(byteptr + 1);
|
||||
memory[sp] = *byteptr;
|
||||
--sp;
|
||||
CHECKSTACKOVERFLOW();
|
||||
pc = XREG;
|
||||
--evalptr;
|
||||
return; /* Do not advance program counter */
|
||||
case VM_JSRIMM: /* Imm mode - push PC to calls stack, jump to 16 bit word */
|
||||
wordptr = (unsigned short *)&memory[++pc];
|
||||
++pc;
|
||||
byteptr = (unsigned char *) &pc;
|
||||
memory[sp] = *(byteptr + 1);
|
||||
--sp;
|
||||
CHECKSTACKOVERFLOW();
|
||||
memory[sp] = *byteptr;
|
||||
--sp;
|
||||
CHECKSTACKOVERFLOW();
|
||||
pc = *wordptr;
|
||||
return; /* Do not advance program counter */
|
||||
case VM_RTS: /* Pop call stack, jump to the address popped. */
|
||||
CHECKSTACKUNDERFLOW(2);
|
||||
++sp;
|
||||
pc = 256 * memory[sp] + memory[sp + 1];
|
||||
wordptr = (unsigned short *)&memory[sp];
|
||||
pc = *wordptr;
|
||||
++sp;
|
||||
break;
|
||||
/*
|
||||
@@ -775,14 +887,25 @@ void execute()
|
||||
|
||||
/*
|
||||
* Load bytecode into memory[].
|
||||
* TODO: This is POSIX-only at the moment. Need to add CBM support.
|
||||
*/
|
||||
void load()
|
||||
{
|
||||
FILE *fp;
|
||||
char ch;
|
||||
char *p = (char*)&memory[RTPCSTART];
|
||||
|
||||
pc = RTPCSTART;
|
||||
fp = fopen("bytecode", "r");
|
||||
do {
|
||||
print("\nBytecode file (CR for default)>");
|
||||
getln(p, 15);
|
||||
if (strlen(p) == 0) {
|
||||
strcpy(p, "bytecode");
|
||||
}
|
||||
print("Loading '");
|
||||
print(p);
|
||||
print("'\n");
|
||||
fp = fopen(p, "r");
|
||||
} while (!fp);
|
||||
while (!feof(fp)) {
|
||||
ch = fgetc(fp);
|
||||
memory[pc++] = ch;
|
||||
@@ -807,7 +930,7 @@ int main()
|
||||
print("(c)Bobbi, 2018\n");
|
||||
print("Free Software.\n");
|
||||
print("Licenced under GPL.\n\n");
|
||||
print("Loading bytecode: ");
|
||||
|
||||
load();
|
||||
#ifdef __GNUC__
|
||||
print(" Done.\n\n");
|
||||
|
||||
+11
-63
@@ -74,14 +74,22 @@ enum bytecode {
|
||||
VM_LDIMM, /* Pushes the following 16 bit word to the evaluation stack */
|
||||
/* Absolute addressing: */
|
||||
VM_LDAWORD, /* Replaces X with 16 bit value pointed to by X. */
|
||||
VM_LDAWORDIMM, /* Imm mode - push 16 bit value pointed to by addr after opcode */
|
||||
VM_LDABYTE, /* Replaces X with 8 bit value pointed to by X. */
|
||||
VM_LDABYTEIMM, /* Imm mode - push byte pointed to by addr after opcode */
|
||||
VM_STAWORD, /* Stores 16 bit value Y in addr pointed to by X. Drops X and Y.*/
|
||||
VM_STAWORDIMM, /* Imm mode - store 16 bit value X in addr after opcode. Drop X.*/
|
||||
VM_STABYTE, /* Stores 8 bit value Y in addr pointed to by X. Drops X and Y. */
|
||||
VM_STABYTEIMM, /* Imm mode - store 8 bit value X in addr after opcode. Drop X. */
|
||||
/* Relative to Frame Pointer addressing: */
|
||||
VM_LDRWORD, /* Replaces X with 16 bit value pointed to by X. */
|
||||
VM_LDRWORDIMM, /* Imm mode - push 16 bit value pointed to by addr after opcode */
|
||||
VM_LDRBYTE, /* Replaces X with 8 bit value pointed to by X. */
|
||||
VM_LDRBYTEIMM, /* Imm mode - push byte pointed to by addr after opcode */
|
||||
VM_STRWORD, /* Stores 16 bit value Y in addr pointed to by X. Drops X and Y.*/
|
||||
VM_STRWORDIMM, /* Imm mode - store 16 bit value X in addr after opcode. Drop X.*/
|
||||
VM_STRBYTE, /* Stores 8 bit value Y in addr pointed to by X. Drops X and Y. */
|
||||
VM_STRBYTEIMM, /* Imm mode - store 16 bit value X in addr after opcode. Drop X.*/
|
||||
/**** Manipulate evaluation stack ***********************************************************/
|
||||
VM_SWAP, /* Swaps X and Y */
|
||||
VM_DUP, /* Duplicates X -> X, Y */
|
||||
@@ -128,8 +136,11 @@ enum bytecode {
|
||||
VM_RSH, /* X = Y>>X. Y is dropped. */
|
||||
/**** Flow control **************************************************************************/
|
||||
VM_JMP, /* Jump to address X. Drop X. */
|
||||
VM_JMPIMM, /* Imm mode - jump to 16 bit word following opcode */
|
||||
VM_BRNCH, /* If Y!= 0, jump to address X. Drop X, Y. */
|
||||
VM_BRNCHIMM, /* Imm mode - if X!=0 branch to 16 bit word following opcode */
|
||||
VM_JSR, /* Push PC to call stack. Jump to address X. Drop X. */
|
||||
VM_JSRIMM, /* Imm mode - push PC to call stack, jump to 16 bit word */
|
||||
VM_RTS, /* Pop call stack, jump to the address popped. */
|
||||
/**** Input / Output ************************************************************************/
|
||||
VM_PRDEC, /* Print 16 bit decimal in X. Drop X */
|
||||
@@ -143,69 +154,6 @@ enum bytecode {
|
||||
/********************************************************************************************/
|
||||
};
|
||||
|
||||
/* Order must match enum bytecode */
|
||||
char *bytecodenames[] = {
|
||||
"END",
|
||||
"LDI",
|
||||
"LDAW",
|
||||
"LDAB",
|
||||
"STAW",
|
||||
"STAB",
|
||||
"LDRW",
|
||||
"LDRB",
|
||||
"STRW",
|
||||
"STRB",
|
||||
"SWP",
|
||||
"DUP",
|
||||
"DUP2",
|
||||
"DRP",
|
||||
"OVER",
|
||||
"PICK",
|
||||
"POPW",
|
||||
"POPB",
|
||||
"PSHW",
|
||||
"PSHB",
|
||||
"DISC",
|
||||
"SPFP",
|
||||
"FPSP",
|
||||
"ATOR",
|
||||
"RTOA",
|
||||
"INC",
|
||||
"DEC",
|
||||
"ADD",
|
||||
"SUB",
|
||||
"MUL",
|
||||
"DIV",
|
||||
"MOD",
|
||||
"NEG",
|
||||
"GT",
|
||||
"GTE",
|
||||
"LT",
|
||||
"LTE",
|
||||
"EQL",
|
||||
"NEQL",
|
||||
"AND",
|
||||
"OR",
|
||||
"NOT",
|
||||
"BAND",
|
||||
"BOR",
|
||||
"BXOR",
|
||||
"BNOT",
|
||||
"LSH",
|
||||
"RSH",
|
||||
"JMP",
|
||||
"BRC",
|
||||
"JSR",
|
||||
"RTS",
|
||||
"PRDEC",
|
||||
"PRHEX",
|
||||
"PRCH",
|
||||
"PRSTR",
|
||||
"PRMSG",
|
||||
"KBDCH",
|
||||
"KBDLN"
|
||||
};
|
||||
|
||||
#ifdef A2E
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user