Yet another RAM structure revamp for memory protection and future multitasking - to be reflected in README

This commit is contained in:
Luxferre
2022-08-13 18:48:31 +03:00
parent 79c0001293
commit b16e692e89
+138 -113
View File
@@ -29,7 +29,6 @@
#ifdef __CC65__ #ifdef __CC65__
#include <conio.h> #include <conio.h>
#else #else
#define cgetc() (getchar()) #define cgetc() (getchar())
#define cputc(c) (putchar(c)) #define cputc(c) (putchar(c))
#endif #endif
@@ -61,9 +60,9 @@
#define LIT_STACK_SIZE 32u #define LIT_STACK_SIZE 32u
#endif #endif
/* Command buffer size in bytes */ /* GPD area size in bytes */
#ifndef GPD_AREA_SIZE #ifndef GPD_AREA_SIZE
#define GPD_AREA_SIZE 5000u #define GPD_AREA_SIZE 4096u
#endif #endif
/* Command buffer size in bytes */ /* Command buffer size in bytes */
@@ -76,6 +75,11 @@
#define CLT_ENTRIES_MAX 512u #define CLT_ENTRIES_MAX 512u
#endif #endif
/* Maximum amount of task table entries */
#ifndef EQUI_TASKS_MAX
#define EQUI_TASKS_MAX 1
#endif
/* Persistent storage sandbox file name */ /* Persistent storage sandbox file name */
#ifndef PERSIST_FILE #ifndef PERSIST_FILE
#define PERSIST_FILE "PERS.DAT" #define PERSIST_FILE "PERS.DAT"
@@ -84,38 +88,44 @@
/* Some necessary constants and offsets derived from the above values */ /* Some necessary constants and offsets derived from the above values */
#define STACK_SIZE_WORDS (STACK_SIZE / WS) /* Main and return stack size in words */ #define STACK_SIZE_WORDS (STACK_SIZE / WS) /* Main and return stack size in words */
/* /* Structures that describe Equi machine RAM using the above configuration */
* Structures that describe Equi machine RAM using the above configuration
*/
struct CLTEntry { struct CLTEntry { /* one entry in the compilation lookup table */
ushort nhash; /* compiled word name hash */ ushort nhash; /* compiled word name hash */
ushort loc; /* compiled word location */ ushort loc; /* compiled word location */
}; };
struct EquiRAM { struct EquiCtx { /* one Equi program context */
ushort stack_size; /* main/return stack size in words */ ushort id; /* task ID */
uchar literal_stack_size; /* literal stack size in bytes */
uchar lsp; /* literal stack pointer */
ushort msp; /* main stack pointer */ ushort msp; /* main stack pointer */
ushort rsp; /* return stack pointer */ ushort rsp; /* return stack pointer */
ushort clt_start; /* compilation lookup table start */ ushort lsp; /* literal stack pointer */
ushort gpd_start; /* GPD area start */
ushort cmd_start; /* command buffer start */
ushort cmd_size; /* command buffer size in bytes */
ushort pc; /* program counter */
ushort cbp; /* compilation buffer pointer */
ushort cltp; /* compilation lookup table pointer */ ushort cltp; /* compilation lookup table pointer */
ushort ibp; /* input buffer pointer */ ushort gpd_start; /* GPD area start for this task */
uchar II; /* instruction ignore mode flag */ ushort cmd_start; /* command buffer start for this task */
uchar CM; /* compilation mode flag */ ushort cmd_size; /* size of loaded code in bytes for this task */
uchar IM; /* interpretation mode flag */ ushort pc; /* program counter */
uchar MM; /* minification bypass mode flag */
ushort main_stack[STACK_SIZE_WORDS]; ushort main_stack[STACK_SIZE_WORDS];
ushort return_stack[STACK_SIZE_WORDS]; ushort return_stack[STACK_SIZE_WORDS];
uchar literal_stack[LIT_STACK_SIZE]; uchar literal_stack[LIT_STACK_SIZE];
struct CLTEntry clt[CLT_ENTRIES_MAX]; /* compilation lookup table */ struct CLTEntry clt[CLT_ENTRIES_MAX]; /* compilation lookup table */
uchar gpd[GPD_AREA_SIZE]; uchar gpd[GPD_AREA_SIZE];
};
struct EquiRAM {
ushort stack_size; /* main/return stack size in words */
uchar literal_stack_size; /* literal stack size in bytes */
ushort cmd_start; /* (global) command buffer start */
ushort cmd_size; /* (global) command buffer size in bytes */
ushort cbp; /* compilation buffer pointer */
ushort ibp; /* input buffer pointer */
uchar II; /* instruction ignore mode flag */
uchar CM; /* compilation mode flag */
uchar IM; /* interpretation mode flag */
uchar MM; /* minification bypass mode flag */
ushort taskcount; /* count of active tasks */
ushort taskid; /* currently running task ID - necessary? */
struct EquiCtx tasks[EQUI_TASKS_MAX];
uchar cmdbuf[CMD_BUF_SIZE]; uchar cmdbuf[CMD_BUF_SIZE];
}; };
@@ -125,8 +135,8 @@ static struct EquiRAM ram;
/* Also create an alternative view of the same RAM area for direct offset-based access */ /* Also create an alternative view of the same RAM area for direct offset-based access */
static uchar* flatram = (uchar *)&ram; static uchar* flatram = (uchar *)&ram;
/* write protection threshold RAM address */ /* reference to the current task context */
static ushort write_protection_threshold = 0; static struct EquiCtx *curtask;
/* Error reporting codes */ /* Error reporting codes */
enum EquiErrors { enum EquiErrors {
@@ -140,13 +150,14 @@ enum EquiErrors {
INVALID_WORD, INVALID_WORD,
PORT_IO_ERROR, PORT_IO_ERROR,
PERSIST_IO_ERROR, PERSIST_IO_ERROR,
RESTRICTED_WRITE_ERROR RESTRICTED_WRITE_ERROR,
OUT_OF_BOUNDS_JUMP
}; };
/* Error reporting method */ /* Error reporting method */
void trapout(errcode) { void trapout(errcode) {
if(errcode > 0) { if(errcode > 0) {
fprintf(stderr, "\nError %d at 0x%x (instruction %c): ", errcode, ram.pc, ram.cmdbuf[ram.pc]); fprintf(stderr, "\nError %d at 0x%x (task 0x%x, instruction %c): ", errcode, curtask->pc, curtask->id, flatram[curtask->pc]);
switch(errcode) { switch(errcode) {
case STACK_OVERFLOW: case STACK_OVERFLOW:
cerr("Stack overflow\n"); cerr("Stack overflow\n");
@@ -178,13 +189,15 @@ void trapout(errcode) {
case RESTRICTED_WRITE_ERROR: case RESTRICTED_WRITE_ERROR:
cerr("Attempt to write to a restricted RAM area\n"); cerr("Attempt to write to a restricted RAM area\n");
break; break;
case OUT_OF_BOUNDS_JUMP:
cerr("Attempt to jump outside the task context\n");
break;
} }
exit(errcode); exit(errcode);
} }
} }
/* Equi instructions enum */ /* Equi instructions enum */
enum EquiInstructions { enum EquiInstructions {
INS_IISTART='(', INS_IISTART='(',
INS_IIEND=')', INS_IIEND=')',
@@ -232,7 +245,6 @@ enum EquiInstructions {
}; };
/* Equi known ports enum */ /* Equi known ports enum */
enum EquiPorts { enum EquiPorts {
PORT_ECHO = 0x0, /* echo port, used for testing: R1=P1, R2=P2 */ PORT_ECHO = 0x0, /* echo port, used for testing: R1=P1, R2=P2 */
PORT_RANDOM, /* RNG port: P1 = valueFrom, P2 = valueTo => R1=rand(from, to), R2 = rand(from, to) */ PORT_RANDOM, /* RNG port: P1 = valueFrom, P2 = valueTo => R1=rand(from, to), R2 = rand(from, to) */
@@ -241,53 +253,53 @@ enum EquiPorts {
/* push a value onto the main stack */ /* push a value onto the main stack */
void pushMain(ushort val) { void pushMain(ushort val) {
ram.main_stack[ram.msp++] = val; curtask->main_stack[curtask->msp++] = val;
if(ram.msp >= STACK_SIZE_WORDS) if(curtask->msp >= STACK_SIZE_WORDS)
trapout(STACK_OVERFLOW); trapout(STACK_OVERFLOW);
} }
/* push a value onto the return stack */ /* push a value onto the return stack */
void pushRet(ushort val) { void pushRet(ushort val) {
ram.return_stack[ram.rsp++] = val; curtask->return_stack[curtask->rsp++] = val;
if(ram.rsp >= STACK_SIZE_WORDS) if(curtask->rsp >= STACK_SIZE_WORDS)
trapout(STACK_OVERFLOW); trapout(STACK_OVERFLOW);
} }
/* pop a value from the main stack */ /* pop a value from the main stack */
ushort popMain() { ushort popMain() {
if(ram.msp == 0) { if(curtask->msp == 0) {
trapout(STACK_UNDERFLOW); trapout(STACK_UNDERFLOW);
return 0; return 0;
} }
else else
return ram.main_stack[--ram.msp]; return curtask->main_stack[--curtask->msp];
} }
/* pop a value from the return stack */ /* pop a value from the return stack */
ushort popRet() { ushort popRet() {
if(ram.rsp == 0) { if(curtask->rsp == 0) {
trapout(STACK_UNDERFLOW); trapout(STACK_UNDERFLOW);
return 0; return 0;
} }
else else
return ram.return_stack[--ram.rsp]; return curtask->return_stack[--curtask->rsp];
} }
/* push a character to the literal stack */ /* push a character to the literal stack */
void pushLit(uchar c) { void pushLit(uchar c) {
ram.literal_stack[ram.lsp++] = c; curtask->literal_stack[curtask->lsp++] = c;
if(ram.lsp >= LIT_STACK_SIZE) if(curtask->lsp >= LIT_STACK_SIZE)
trapout(STACK_OVERFLOW); trapout(STACK_OVERFLOW);
} }
/* pop a character from the literal stack */ /* pop a character from the literal stack */
uchar popLit() { uchar popLit() {
if(ram.lsp == 0) { if(curtask->lsp == 0) {
trapout(STACK_UNDERFLOW); trapout(STACK_UNDERFLOW);
return 0; return 0;
} }
else else
return ram.literal_stack[--ram.lsp]; return curtask->literal_stack[--curtask->lsp];
} }
/* convert ASCII code of a hex digit to the digit value */ /* convert ASCII code of a hex digit to the digit value */
@@ -298,15 +310,14 @@ uchar a2d(uchar a) {
/* shape 2-byte vlaue on the main stack from up to 4 values of the literal stack */ /* shape 2-byte vlaue on the main stack from up to 4 values of the literal stack */
void pushLitVal() { void pushLitVal() {
uchar p[4U] = {0,0,0,0}, i, thr = 4U; uchar p[4U] = {0,0,0,0}, i, thr = 4U;
if(ram.lsp < 4U) thr = ram.lsp; if(curtask->lsp < 4U) thr = curtask->lsp;
for(i=0;i<thr;++i) for(i=0;i<thr;++i)
p[3-i] = a2d(popLit()); p[3-i] = a2d(popLit());
pushMain((p[0]<<12U) | (p[1]<<8U) | (p[2]<<4U) | p[3]); pushMain((p[0]<<12U) | (p[1]<<8U) | (p[2]<<4U) | p[3]);
ram.lsp = 0; /* clear the literal stack */ curtask->lsp = 0; /* clear the literal stack */
} }
/* CCITT CRC16 helper */ /* CCITT CRC16 helper */
ushort crc16(const uchar* data_p, uchar length) { ushort crc16(const uchar* data_p, uchar length) {
uchar x; uchar x;
ushort crc = 0xFFFFu; ushort crc = 0xFFFFu;
@@ -319,13 +330,26 @@ ushort crc16(const uchar* data_p, uchar length) {
} }
/* Short endianness conversion helper */ /* Short endianness conversion helper */
ushort tobig(ushort val) { ushort tobig(ushort val) {
return (val>>8)|((val&255)<<8); return (val>>8)|((val&255)<<8);
} }
/* Persistent operation handler */ /* Task-based memory address jump checker */
uchar taskMemJumpAllowed(addr) {
/* task 0 is allowed to jump anywhere in the command buffer, others only in their own zone */
if(curtask->id)
return (addr >= curtask->cmd_start) && (addr < curtask->cmd_start + curtask->cmd_size);
else
return addr >= ram.cmd_start;
}
/* Task-based memory address write checker */
uchar taskMemWriteAllowed(addr) {
/* task 0 is allowed to write anywhere in the command buffer, others only in their own zone */
return (addr >= curtask->gpd_start && addr < (curtask->gpd_start + GPD_AREA_SIZE)) || taskMemJumpAllowed(addr);
}
/* Persistent operation handler */
ushort persistOp(FILE *pfd, ushort maddr, ushort dataLen, ushort blk, uchar isWrite) { ushort persistOp(FILE *pfd, ushort maddr, ushort dataLen, ushort blk, uchar isWrite) {
ushort status = 0, proc; ushort status = 0, proc;
if(pfd) { if(pfd) {
@@ -333,7 +357,7 @@ ushort persistOp(FILE *pfd, ushort maddr, ushort dataLen, ushort blk, uchar isWr
if(isWrite) /* writing to the persistent area from the memory */ if(isWrite) /* writing to the persistent area from the memory */
proc = (ushort) fwrite(&flatram[maddr], 1, dataLen, pfd); proc = (ushort) fwrite(&flatram[maddr], 1, dataLen, pfd);
else { /* reading from the persistent area into the memory */ else { /* reading from the persistent area into the memory */
if(maddr < write_protection_threshold) if(!taskMemWriteAllowed(maddr))
trapout(RESTRICTED_WRITE_ERROR); trapout(RESTRICTED_WRITE_ERROR);
proc = (ushort) fread(&flatram[maddr], 1, dataLen, pfd); proc = (ushort) fread(&flatram[maddr], 1, dataLen, pfd);
} }
@@ -345,7 +369,6 @@ ushort persistOp(FILE *pfd, ushort maddr, ushort dataLen, ushort blk, uchar isWr
} }
/* Port I/O handler */ /* Port I/O handler */
void portIO(ushort port, ushort p2, ushort p1) { void portIO(ushort port, ushort p2, ushort p1) {
ushort r1 = 0, r2 = 0, status = 0; ushort r1 = 0, r2 = 0, status = 0;
switch(port) { switch(port) {
@@ -368,19 +391,27 @@ void portIO(ushort port, ushort p2, ushort p1) {
pushMain(status); pushMain(status);
} }
/* Main interpreter loop */ /* Task loader method */
struct EquiCtx* equi_load_task(ushort progStart, ushort len) {
struct EquiCtx *taskptr = &ram.tasks[ram.taskcount]; /* refer to the last available entry */
taskptr->msp = taskptr->rsp = taskptr->lsp = taskptr->cltp = 0; /* init stacks and CLT */
taskptr->pc = progStart - 1U; /* init program counter for preincrement logic */
taskptr->cmd_start = progStart; /* actual command buffer start (from the start of vRAM) */
taskptr->cmd_size = len; /* actual command buffer size */
taskptr->id = ram.taskcount; /* assign task ID */
taskptr->gpd_start = (ushort) (taskptr->gpd - flatram); /* assign GPD area start */
++ram.taskcount; /* increase task count */
return taskptr;
}
/* Main interpreter loop */
void equi_main_loop() { void equi_main_loop() {
uchar instr; uchar instr;
ushort lhash, pbuf, pbuf2; ushort lhash, pbuf, pbuf2;
/* try to open the persistent sandbox file */ /* try to open the persistent sandbox file */
FILE *pfd = fopen(PERSIST_FILE, "r+b"); FILE *pfd = fopen(PERSIST_FILE, "r+b");
/* reset all stacks before running and reinit CLT */
ram.msp = ram.rsp = ram.lsp = ram.cltp = 0;
/* reset pc */
ram.pc = 65535U;
while(1) { /* iterate over the instructions in the command buffer */ while(1) { /* iterate over the instructions in the command buffer */
instr = ram.cmdbuf[++ram.pc]; instr = flatram[++curtask->pc];
/* silently exit on zero or FF */ /* silently exit on zero or FF */
if(instr == 0 || instr == 0xFFu) break; if(instr == 0 || instr == 0xFFu) break;
/* first, check for II mode */ /* first, check for II mode */
@@ -392,15 +423,15 @@ void equi_main_loop() {
/* then, check for compilation mode */ /* then, check for compilation mode */
if(ram.CM) { if(ram.CM) {
if(instr == INS_CMEND) { /* trigger word compilation logic as per the spec */ if(instr == INS_CMEND) { /* trigger word compilation logic as per the spec */
if(ram.lsp < 1) if(curtask->lsp < 1)
trapout(STACK_UNDERFLOW); trapout(STACK_UNDERFLOW);
ram.cmdbuf[ram.pc] = INS_RET; /* in-place patch this instruction to R */ flatram[curtask->pc] = INS_RET; /* in-place patch this instruction to R */
/* hash and save compiled word */ /* hash and save compiled word */
ram.clt[ram.cltp].nhash = crc16(&ram.literal_stack[0], ram.lsp); curtask->clt[curtask->cltp].nhash = crc16(&(curtask->literal_stack[0]), curtask->lsp);
ram.lsp = 0; /* clear the literal stack */ curtask->lsp = 0; /* clear the literal stack */
ram.clt[ram.cltp].loc = ram.cbp; /* stored the compiled code location from the most recent CBP value */ curtask->clt[curtask->cltp].loc = ram.cbp; /* stored the compiled code location from the most recent CBP value */
++ram.cltp; /* increase the word */ ++curtask->cltp; /* increase the word */
if(ram.cltp == CLT_ENTRIES_MAX) if(curtask->cltp == CLT_ENTRIES_MAX)
trapout(CLT_OVERFLOW); trapout(CLT_OVERFLOW);
ram.CM = 0; /* unset compilation mode flag */ ram.CM = 0; /* unset compilation mode flag */
} }
@@ -413,11 +444,11 @@ void equi_main_loop() {
continue; continue;
} }
/* then trigger literal auto-push if applicable */ /* then trigger literal auto-push if applicable */
if(ram.lsp > 0 && instr != INS_LITSTR && instr != INS_LITCALL && instr != INS_LITINT && instr != INS_CMSTART) if(curtask->lsp > 0 && instr != INS_LITSTR && instr != INS_LITCALL && instr != INS_LITINT && instr != INS_CMSTART)
pushLitVal(); pushLitVal();
switch(instr) { /* then perform all main interpretation logic */ switch(instr) { /* then perform all main interpretation logic */
case INS_CMSTART: /* compilation start */ case INS_CMSTART: /* compilation start */
ram.cbp = ram.pc + 1U; /* save CBP */ ram.cbp = curtask->pc + 1U; /* save CBP */
ram.CM = 1U; /* raise CM flag */ ram.CM = 1U; /* raise CM flag */
break; break;
case CR: case CR:
@@ -431,26 +462,26 @@ void equi_main_loop() {
pushLitVal(); pushLitVal();
break; break;
case INS_LITSTR: /* literal stack -> each char at main stack as short */ case INS_LITSTR: /* literal stack -> each char at main stack as short */
while(ram.lsp) while(curtask->lsp)
pushMain((ushort)popLit()); pushMain((ushort)popLit());
ram.lsp = 0; curtask->lsp = 0;
break; break;
case INS_LITCALL: /* call the saved word from the literal */ case INS_LITCALL: /* call the saved word from the literal */
if(ram.lsp < 1) if(curtask->lsp < 1)
trapout(STACK_UNDERFLOW); trapout(STACK_UNDERFLOW);
lhash = crc16(&ram.literal_stack[0], ram.lsp); lhash = crc16(&(curtask->literal_stack[0]), curtask->lsp);
for(pbuf=0;pbuf<CLT_ENTRIES_MAX;++pbuf) for(pbuf=0;pbuf<CLT_ENTRIES_MAX;++pbuf)
if(ram.clt[pbuf].nhash == lhash) { if(curtask->clt[pbuf].nhash == lhash) {
pushRet(ram.pc); /* first, save the PC into the return stack */ pushRet(curtask->pc); /* first, save the PC into the return stack */
ram.pc = ram.clt[pbuf].loc; /* then jump to the word location */ curtask->pc = curtask->clt[pbuf].loc; /* then jump to the word location */
break; break;
} }
if(pbuf >= CLT_ENTRIES_MAX) if(pbuf >= CLT_ENTRIES_MAX)
trapout(INVALID_WORD); trapout(INVALID_WORD);
ram.lsp = 0; /* clear the literal stack */ curtask->lsp = 0; /* clear the literal stack */
break; break;
case INS_RET: /* jump to the instruction at ret stack */ case INS_RET: /* jump to the instruction at ret stack */
ram.pc = popRet(); curtask->pc = popRet();
break; break;
case INS_M2R: /* main -> ret stack */ case INS_M2R: /* main -> ret stack */
pushRet(popMain()); pushRet(popMain());
@@ -465,7 +496,7 @@ void equi_main_loop() {
case INS_STORE: /* main stack -> mem (word) */ case INS_STORE: /* main stack -> mem (word) */
pbuf = popMain(); pbuf = popMain();
pbuf2 = popMain(); pbuf2 = popMain();
if(pbuf < write_protection_threshold) if(!taskMemWriteAllowed(pbuf))
trapout(RESTRICTED_WRITE_ERROR); trapout(RESTRICTED_WRITE_ERROR);
flatram[pbuf] = pbuf2 >> 8U; flatram[pbuf] = pbuf2 >> 8U;
flatram[pbuf + 1U] = pbuf2 & 255U; flatram[pbuf + 1U] = pbuf2 & 255U;
@@ -478,45 +509,50 @@ void equi_main_loop() {
pbuf = popMain(); pbuf = popMain();
break; break;
case INS_DUP: /* ( a -- a a ) */ case INS_DUP: /* ( a -- a a ) */
if(ram.msp < 1) if(curtask->msp < 1)
trapout(STACK_UNDERFLOW); trapout(STACK_UNDERFLOW);
pushMain(ram.main_stack[ram.msp-1]); pushMain(curtask->main_stack[curtask->msp-1]);
break; break;
case INS_SWAP: /* ( a b -- b a ) */ case INS_SWAP: /* ( a b -- b a ) */
if(ram.msp < 2) if(curtask->msp < 2)
trapout(STACK_UNDERFLOW); trapout(STACK_UNDERFLOW);
pbuf = ram.main_stack[ram.msp-2]; pbuf = curtask->main_stack[curtask->msp-2];
ram.main_stack[ram.msp-2] = ram.main_stack[ram.msp-1]; curtask->main_stack[curtask->msp-2] = curtask->main_stack[curtask->msp-1];
ram.main_stack[ram.msp-1] = pbuf; curtask->main_stack[curtask->msp-1] = pbuf;
break; break;
case INS_ROT: /* ( a b c -- b c a ) */ case INS_ROT: /* ( a b c -- b c a ) */
if(ram.msp < 3) if(curtask->msp < 3)
trapout(STACK_UNDERFLOW); trapout(STACK_UNDERFLOW);
pbuf = ram.main_stack[ram.msp-3]; pbuf = curtask->main_stack[curtask->msp-3];
pbuf2 = ram.main_stack[ram.msp-1]; pbuf2 = curtask->main_stack[curtask->msp-1];
ram.main_stack[ram.msp-3] = ram.main_stack[ram.msp-2]; curtask->main_stack[curtask->msp-3] = curtask->main_stack[curtask->msp-2];
ram.main_stack[ram.msp-2] = pbuf2; curtask->main_stack[curtask->msp-2] = pbuf2;
ram.main_stack[ram.msp-1] = pbuf; curtask->main_stack[curtask->msp-1] = pbuf;
break; break;
case INS_OVER: /* ( a b -- a b a ) */ case INS_OVER: /* ( a b -- a b a ) */
if(ram.msp < 2) if(curtask->msp < 2)
trapout(STACK_UNDERFLOW); trapout(STACK_UNDERFLOW);
pushMain(ram.main_stack[ram.msp-2]); pushMain(curtask->main_stack[curtask->msp-2]);
break; break;
case INS_JUMP: /* unconditional signed jump: ( rel -- ) */ case INS_JUMP: /* unconditional signed jump: ( rel -- ) */
ram.pc = (ushort) (ram.pc + (signed short) popMain()); curtask->pc = (ushort) (curtask->pc + (signed short) popMain());
if(!taskMemJumpAllowed(curtask->pc))
trapout(OUT_OF_BOUNDS_JUMP);
break; break;
case INS_IF: /* conditional signed jump if cond is not zero: ( cond rel -- ) */ case INS_IF: /* conditional signed jump if cond is not zero: ( cond rel -- ) */
pbuf = popMain(); /* reladdr */ pbuf = popMain(); /* reladdr */
pbuf2 = popMain(); /* cond */ pbuf2 = popMain(); /* cond */
if(pbuf2 != 0) if(pbuf2 != 0) {
ram.pc = (ushort) (ram.pc + (signed short) pbuf); curtask->pc = (ushort) (curtask->pc + (signed short) pbuf);
if(!taskMemJumpAllowed(curtask->pc))
trapout(OUT_OF_BOUNDS_JUMP);
}
break; break;
case INS_EXPOINT: /* Locate execution point */ case INS_EXPOINT: /* Locate execution point */
pushMain(ram.pc + 1); pushMain(curtask->pc + 1);
break; break;
case INS_GPDSTART: /* Locate GPD area start */ case INS_GPDSTART: /* Locate GPD area start */
pushMain(ram.gpd_start); pushMain(curtask->gpd_start);
break; break;
case INS_GT: /* ( a b -- a>b ) */ case INS_GT: /* ( a b -- a>b ) */
pushMain((popMain() < popMain()) ? 1u : 0u); pushMain((popMain() < popMain()) ? 1u : 0u);
@@ -572,7 +608,7 @@ void equi_main_loop() {
pushMain((ushort)cgetc()); pushMain((ushort)cgetc());
break; break;
case INS_PORTIO: /* ( p1 p2 port -- r1 r2 status ) - simulate/execute port I/O according to the spec */ case INS_PORTIO: /* ( p1 p2 port -- r1 r2 status ) - simulate/execute port I/O according to the spec */
if(ram.msp < 3) if(curtask->msp < 3)
trapout(STACK_UNDERFLOW); trapout(STACK_UNDERFLOW);
portIO(popMain(), popMain(), popMain()); portIO(popMain(), popMain(), popMain());
break; break;
@@ -586,7 +622,7 @@ void equi_main_loop() {
trapout(INVALID_INSTRUCTION); trapout(INVALID_INSTRUCTION);
goto brx; goto brx;
} }
if(ram.msp >= STACK_SIZE_WORDS || ram.rsp >= STACK_SIZE_WORDS) /* check for stack overflow after any operation */ if(curtask->msp >= STACK_SIZE_WORDS || curtask->rsp >= STACK_SIZE_WORDS) /* check for stack overflow after any operation */
trapout(STACK_OVERFLOW); trapout(STACK_OVERFLOW);
continue; continue;
brx: break; brx: break;
@@ -595,13 +631,12 @@ void equi_main_loop() {
if(pfd) fclose(pfd); if(pfd) fclose(pfd);
/* unset interpretation mode flag and exit */ /* unset interpretation mode flag and exit */
ram.IM = 0; ram.IM = 0;
ram.pc = ram.ibp = 65535U; curtask->pc = ram.ibp = 65535U;
/* clear all stacks and CLT */ /* clear all stacks and CLT */
ram.msp = ram.rsp = ram.lsp = ram.cltp = 0; curtask->msp = curtask->rsp = curtask->lsp = curtask->cltp = 0;
} }
/* Equi VM entry point */ /* Equi VM entry point */
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
uchar instr, bc, smode = 0; uchar instr, bc, smode = 0;
/* detect host endianness */ /* detect host endianness */
@@ -617,20 +652,17 @@ int main(int argc, char* argv[]) {
/* initialize the RAM in the most standard way */ /* initialize the RAM in the most standard way */
ram.stack_size = STACK_SIZE_WORDS; ram.stack_size = STACK_SIZE_WORDS;
ram.literal_stack_size = LIT_STACK_SIZE; ram.literal_stack_size = LIT_STACK_SIZE;
ram.clt_start = (uchar *)&ram.clt - (uchar *)&ram.stack_size; ram.cmd_start = (uchar *)&ram.cmdbuf - (uchar *)&ram;
ram.gpd_start = (uchar *)&ram.gpd - (uchar *)&ram.stack_size;
ram.cmd_start = (uchar *)&ram.cmdbuf - (uchar *)&ram.stack_size;
ram.cmd_size = CMD_BUF_SIZE; ram.cmd_size = CMD_BUF_SIZE;
ram.II = ram.CM = ram.IM = ram.MM = 0; /* reset all flags */ ram.II = ram.CM = ram.IM = ram.MM = 0; /* reset all flags */
write_protection_threshold = ram.gpd_start; /* setup write protection */ ram.taskcount = 0;
/* process command line params */ /* process command line params */
if(argc > 1 && argv[1][0] == 'm') /* enter minification mode, don't run the programs */ if(argc > 1 && argv[1][0] == 'm') /* enter minification mode, don't run the programs */
ram.MM = 1; ram.MM = 1;
else if(argc > 1 && argv[1][0] == 's') /* enter silent mode, don't print the banners and prompts */ else if(argc > 1 && argv[1][0] == 's') /* enter silent mode, don't print the banners and prompts */
smode = 1; smode = 1;
/* Start both execution and input buffering from the start of command buffer (-1 because we use prefix increment) */ /* Start input buffering from the start of command buffer (-1 because we use prefix increment) */
ram.pc = ram.ibp = 65535U; ram.ibp = 65535U;
if(!ram.MM && !smode) { /* skip the terminal init and the greeting if in minification or silent mode */ if(!ram.MM && !smode) { /* skip the terminal init and the greeting if in minification or silent mode */
/* CC65-specific terminal init */ /* CC65-specific terminal init */
#ifdef __CC65__ #ifdef __CC65__
@@ -639,16 +671,8 @@ int main(int argc, char* argv[]) {
#else /* VT100-compatible terminal init */ #else /* VT100-compatible terminal init */
printf("\033c"); printf("\033c");
#endif #endif
printf("Welcome to Equi v" EQUI_VER " by Luxferre, 2022\nStack size: %d bytes\nLiteral stack size: %d bytes\nCLT: 0x%04X (%d bytes)\nGPD: 0x%04X (%d bytes)\nCommand buffer: 0x%04X (%d bytes)\nEqui ready\n\n> ", printf("Welcome to Equi v" EQUI_VER " by Luxferre, 2022\nStack size: %d bytes\nLiteral stack size: %d bytes\nCommand buffer: 0x%04X (%d bytes)\nEqui ready\n\n> ",
STACK_SIZE, LIT_STACK_SIZE, ram.clt_start, ram.gpd_start - ram.clt_start, ram.gpd_start, ram.cmd_start - ram.gpd_start, ram.cmd_start, ram.cmd_size); STACK_SIZE, LIT_STACK_SIZE, ram.cmd_start, ram.cmd_size);
}
/* now, if necessary, convert the values that could be read by the program to big-endian */
if(host_islittle) {
ram.stack_size = tobig(ram.stack_size);
ram.clt_start = tobig(ram.clt_start);
ram.cmd_start = tobig(ram.cmd_start);
ram.cmd_size = tobig(ram.cmd_size);
} }
while(1) { /* Now, we're in the command mode loop */ while(1) { /* Now, we're in the command mode loop */
@@ -683,6 +707,7 @@ int main(int argc, char* argv[]) {
} }
ram.cmdbuf[++ram.ibp] = INS_QUIT; /* end program with INS_QUIT */ ram.cmdbuf[++ram.ibp] = INS_QUIT; /* end program with INS_QUIT */
ram.IM = 1; /* set the mandatory interpretation mode flag */ ram.IM = 1; /* set the mandatory interpretation mode flag */
curtask = equi_load_task((ushort)ram.cmd_start, ram.ibp + 1); /* load the code as task 0 */
equi_main_loop(); /* and run the interpreter loop */ equi_main_loop(); /* and run the interpreter loop */
if(!smode) { if(!smode) {
cputc(CR); /* echo CR */ cputc(CR); /* echo CR */