Hopefully fixed literals and implemented most instructions
This commit is contained in:
@@ -99,6 +99,7 @@ CR |`( -- )` |In the command mode, output a line break an
|
||||
`*`|`( a b -- a*b )` |Product
|
||||
`/`|`( a b -- a/b rem )` |Integer division (with remainder)
|
||||
`N`|`( a -- -a )` |Single-instruction negation (complement to 65536)
|
||||
`T`|`( a XY -- [a >> X] << Y )` |Bitwise shif**t**: by the first nibble to the right and then by the second nibble to the left
|
||||
`~`|`( a -- ~a )` |Bitwise NOT
|
||||
`&`|`( a b -- a&b )` |Bitwise AND
|
||||
`\|`|`( a b -- a\|b )` |Bitwise OR
|
||||
@@ -106,7 +107,7 @@ CR |`( -- )` |In the command mode, output a line break an
|
||||
`.`|`( a -- ) ` |Output a character by the ASCII (or Unicode, if supported) value into the standard terminal
|
||||
`,`|`( -- a ) ` |Non-blocking key input of an ASCII (or Unicode, if supported) value from the standard terminal
|
||||
`?`|`( -- a ) ` |Blocking key input of an ASCII (or Unicode, if supported) value from the standard terminal
|
||||
`P`|`( p1 p2 port -- status r1 r2 )`|**P**ort I/O: pass two 16-bit parameters to the port and read the operation status and results into the words on the stack top
|
||||
`P`|`( p1 p2 port -- r1 r2 status )`|**P**ort I/O: pass two 16-bit parameters to the port and read the operation status and results into the words on the stack top
|
||||
`}`|`( adh adl len maddr -- status)`|Persistent storage write operation. Stack parameters: persistent address high 2 bytes, low 2 bytes, data length, RAM address
|
||||
`{`|`( adh adl len maddr -- status)`|Persistent storage read operation. Stack parameters: persistent address high 2 bytes, low 2 bytes, data length, RAM address
|
||||
`Q`|`( -- )` |**Q**uit the interpretation mode (unset IM flag if set), or the interpreter shell itself if in command mode (halt the machine when it's nowhere to exit to)
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#define CLT_ENTRY_SIZE (CLT_ENTRY_LEN + WS) /* Full size in bytes taken by one CLT entry */
|
||||
#define BS 8u /* Backspace character code */
|
||||
#define CR 13u /* Character return code */
|
||||
#define LF 10u /* Line feed code */
|
||||
|
||||
/* Configuration section (constants overridable at compile-time) */
|
||||
|
||||
@@ -131,28 +132,28 @@ void trapout(errcode) {
|
||||
fprintf(stderr, "Error %d at 0x%x (instruction %c): ", errcode, ram.pc, ram.cmdbuf[ram.pc]);
|
||||
switch(errcode) {
|
||||
case STACK_OVERFLOW:
|
||||
cerr("Stack overflow");
|
||||
cerr("Stack overflow\n");
|
||||
break;
|
||||
case STACK_UNDERFLOW:
|
||||
cerr("Stack underflow");
|
||||
cerr("Stack underflow\n");
|
||||
break;
|
||||
case DIV_BY_ZERO:
|
||||
cerr("Division by zero");
|
||||
cerr("Division by zero\n");
|
||||
break;
|
||||
case CLT_OVERFLOW:
|
||||
cerr("Compilation lookup table full");
|
||||
cerr("Compilation lookup table full\n");
|
||||
break;
|
||||
case CMD_OVERFLOW:
|
||||
cerr("Command buffer full");
|
||||
cerr("Command buffer full\n");
|
||||
break;
|
||||
case INVALID_INSTRUCTION:
|
||||
cerr("Invalid instruction");
|
||||
cerr("Invalid instruction\n");
|
||||
break;
|
||||
case INVALID_WORD:
|
||||
cerr("Word not found in CLT");
|
||||
cerr("Word not found in CLT\n");
|
||||
break;
|
||||
case PORT_IO_ERROR:
|
||||
cerr("Port I/O error");
|
||||
cerr("Port I/O error\n");
|
||||
break;
|
||||
}
|
||||
exit(errcode);
|
||||
@@ -191,11 +192,13 @@ enum EquiInstructions {
|
||||
INS_MUL='*',
|
||||
INS_DIV='/',
|
||||
INS_NEG='N',
|
||||
INS_SHIFT='T',
|
||||
INS_NOT='~',
|
||||
INS_AND='&',
|
||||
INS_OR='|',
|
||||
INS_XOR='^',
|
||||
INS_COUT='.',
|
||||
INS_COUT='.', /* character output */
|
||||
INS_NHOUT='H', /* numeric hex output */
|
||||
INS_NBKIN=',', /* non-blocking key input */
|
||||
INS_BKIN='?', /* blocking key input */
|
||||
INS_PORTIO='P',
|
||||
@@ -238,11 +241,11 @@ ushort popRet() {
|
||||
return ram.return_stack[--ram.rsp];
|
||||
}
|
||||
|
||||
/* push a character to the literal stack, auto-discarding overflown items */
|
||||
/* push a character to the literal stack */
|
||||
void pushLit(uchar c) {
|
||||
ram.literal_stack[ram.lsp++] = c;
|
||||
if(ram.lsp >= LIT_STACK_SIZE)
|
||||
ram.lsp = 0;
|
||||
trapout(STACK_OVERFLOW);
|
||||
}
|
||||
|
||||
/* pop a character from the literal stack */
|
||||
@@ -255,9 +258,9 @@ uchar popLit() {
|
||||
return ram.literal_stack[--ram.lsp];
|
||||
}
|
||||
|
||||
/* clear the literal stack */
|
||||
void clearLit() {
|
||||
ram.lsp = 0; /* clear the literal stack */
|
||||
/* convert ASCII code of a hex digit to the digit value */
|
||||
uchar a2d(uchar a) {
|
||||
return (a < 0x3aU) ? (a - 0x30U) : (a - 55U);
|
||||
}
|
||||
|
||||
/* shape 2-byte vlaue on the main stack from the 4 values of the literal stack */
|
||||
@@ -271,10 +274,10 @@ void pushLitVal(strict) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
p4 = popLit();
|
||||
p3 = popLit();
|
||||
p2 = popLit();
|
||||
p1 = popLit();
|
||||
p4 = a2d(popLit());
|
||||
p3 = a2d(popLit());
|
||||
p2 = a2d(popLit());
|
||||
p1 = a2d(popLit());
|
||||
pushMain((p1<<12U) | (p2<<8U) | (p3<<4U) | p4);
|
||||
ram.lsp = 0; /* clear the literal stack */
|
||||
}
|
||||
@@ -293,17 +296,25 @@ ushort crc16(const uchar* data_p, uchar length) {
|
||||
return crc;
|
||||
}
|
||||
|
||||
/* persistent operation handler */
|
||||
|
||||
ushort persistOp(maddr, dataLen, adl, adh, isWrite) {
|
||||
|
||||
}
|
||||
|
||||
/* Main interpreter loop */
|
||||
|
||||
void equi_main_loop() {
|
||||
uchar instr, i;
|
||||
ushort lhash, pbuf;
|
||||
ushort lhash, pbuf, pbuf2;
|
||||
/* 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 */
|
||||
instr = ram.cmdbuf[++ram.pc];
|
||||
/* silently exit on zero */
|
||||
if(instr == 0) break;
|
||||
/* first, check for II mode */
|
||||
if(ram.II) {
|
||||
if(instr == INS_IIEND)
|
||||
@@ -344,12 +355,19 @@ void equi_main_loop() {
|
||||
ram.cbp = ram.pc + 1U; /* save CBP */
|
||||
ram.CM = 1U; /* raise CM flag */
|
||||
break;
|
||||
case CR:
|
||||
case LF:
|
||||
case ' ': /* all nops in interpretation mode */
|
||||
break;
|
||||
case INS_QUIT: /* gracefully quit the interpretation mode */
|
||||
goto brx;
|
||||
case INS_LITINT: /* literal stack -> main stack as short */
|
||||
pushLitVal(1U);
|
||||
break;
|
||||
case INS_LITSTR:
|
||||
case INS_LITSTR: /* literal stack -> each char at main stack as short */
|
||||
while(ram.lsp)
|
||||
pushMain((ushort)popLit());
|
||||
ram.lsp = 0;
|
||||
break;
|
||||
case INS_LITCALL: /* call the saved word from the literal */
|
||||
if(ram.lsp < CLT_ENTRY_LEN)
|
||||
@@ -364,80 +382,149 @@ void equi_main_loop() {
|
||||
trapout(INVALID_WORD);
|
||||
ram.lsp = 0; /* clear the literal stack */
|
||||
break;
|
||||
case INS_RET:
|
||||
case INS_RET: /* jump to the instruction at ret stack */
|
||||
ram.pc = popRet();
|
||||
break;
|
||||
case INS_M2R:
|
||||
case INS_M2R: /* main -> ret stack */
|
||||
pushRet(popMain());
|
||||
break;
|
||||
case INS_R2M:
|
||||
case INS_R2M: /* ret -> main stack */
|
||||
pushMain(popRet());
|
||||
break;
|
||||
case INS_LOAD:
|
||||
case INS_LOAD: /* mem -> main stack */
|
||||
pbuf = popMain();
|
||||
pushMain((flatram[pbuf] << 8)|flatram[pbuf+1U]);
|
||||
break;
|
||||
case INS_STORE:
|
||||
case INS_STORE: /* main stack -> mem (word) */
|
||||
pbuf = popMain();
|
||||
pbuf2 = popMain();
|
||||
flatram[pbuf] = pbuf2 >> 8U;
|
||||
flatram[pbuf + 1U] = pbuf2 & 255U;
|
||||
break;
|
||||
case INS_STOREBYTE:
|
||||
case INS_STOREBYTE: /* main stack -> mem (byte) */
|
||||
pbuf = popMain();
|
||||
flatram[pbuf] = popMain() & 255U;
|
||||
break;
|
||||
case INS_DROP:
|
||||
case INS_DROP: /* ( a -- ) */
|
||||
pbuf = popMain();
|
||||
break;
|
||||
case INS_DUP:
|
||||
case INS_DUP: /* ( a -- a a ) */
|
||||
if(ram.msp < 1)
|
||||
trapout(STACK_UNDERFLOW);
|
||||
pushMain(ram.main_stack[ram.msp-1]);
|
||||
break;
|
||||
case INS_SWAP:
|
||||
case INS_SWAP: /* ( a b -- b a ) */
|
||||
if(ram.msp < 2)
|
||||
trapout(STACK_UNDERFLOW);
|
||||
pbuf = ram.main_stack[ram.msp-2];
|
||||
ram.main_stack[ram.msp-2] = ram.main_stack[ram.msp-1];
|
||||
ram.main_stack[ram.msp-1] = pbuf;
|
||||
break;
|
||||
case INS_ROT:
|
||||
case INS_ROT: /* ( a b c -- b c a ) */
|
||||
if(ram.msp < 3)
|
||||
trapout(STACK_UNDERFLOW);
|
||||
pbuf = ram.main_stack[ram.msp-3];
|
||||
pbuf2 = ram.main_stack[ram.msp-1];
|
||||
ram.main_stack[ram.msp-3] = ram.main_stack[ram.msp-2];
|
||||
ram.main_stack[ram.msp-2] = pbuf2;
|
||||
ram.main_stack[ram.msp-1] = pbuf;
|
||||
break;
|
||||
case INS_OVER:
|
||||
case INS_OVER: /* ( a b -- a b a ) */
|
||||
if(ram.msp < 2)
|
||||
trapout(STACK_UNDERFLOW);
|
||||
pushMain(ram.main_stack[ram.msp-2]);
|
||||
break;
|
||||
case INS_JUMP:
|
||||
case INS_JUMP: /* unconditional signed jump: ( rel -- ) */
|
||||
ram.pc = (ushort) (ram.pc + (signed short) popMain());
|
||||
break;
|
||||
case INS_IF:
|
||||
case INS_IF: /* conditional signed jump if cond is not zero: ( cond rel -- ) */
|
||||
pbuf = popMain(); /* reladdr */
|
||||
pbuf2 = popMain(); /* cond */
|
||||
if(pbuf2 != 0)
|
||||
ram.pc = (ushort) (ram.pc + (signed short) pbuf);
|
||||
break;
|
||||
case INS_EXPOINT: /* Locate execution point */
|
||||
pushMain(ram.pc + 1);
|
||||
break;
|
||||
case INS_GT:
|
||||
case INS_GT: /* ( a b -- a>b ) */
|
||||
pushMain((popMain() < popMain()) ? 1u : 0u);
|
||||
break;
|
||||
case INS_LT:
|
||||
case INS_LT: /* ( a b -- a<b ) */
|
||||
pushMain((popMain() > popMain()) ? 1u : 0u);
|
||||
break;
|
||||
case INS_EQ:
|
||||
case INS_EQ: /* ( a b -- a==b ) */
|
||||
pushMain((popMain() == popMain()) ? 1u : 0u);
|
||||
break;
|
||||
case INS_ADD:
|
||||
case INS_ADD: /* ( a b -- a+b ) */
|
||||
pushMain((popMain() + popMain())&65535U);
|
||||
break;
|
||||
case INS_SUB:
|
||||
case INS_SUB: /* ( a b -- a-b ) */
|
||||
pushMain((-popMain() + popMain())&65535U);
|
||||
break;
|
||||
case INS_MUL:
|
||||
case INS_MUL: /* ( a b -- a*b ) */
|
||||
pushMain((ushort)(popMain() * popMain())&65535U);
|
||||
break;
|
||||
case INS_DIV:
|
||||
case INS_DIV: /* ( a b -- a/b rem ) */
|
||||
pbuf2 = popMain();
|
||||
pbuf = popMain();
|
||||
pushMain((ushort) pbuf/pbuf2);
|
||||
pushMain((ushort) pbuf%pbuf2);
|
||||
break;
|
||||
case INS_NEG:
|
||||
case INS_NEG: /* ( a -- -a ) */
|
||||
pushMain((ushort)-popMain());
|
||||
break;
|
||||
case INS_NOT:
|
||||
case INS_SHIFT: /* ( a XY -- [a >> X] << Y ) */
|
||||
pbuf = popMain();
|
||||
pushMain((ushort)(popMain() >> (pbuf&15U)) << (pbuf>>4U));
|
||||
break;
|
||||
case INS_AND:
|
||||
case INS_NOT: /* ( a -- ~a ) */
|
||||
pushMain((ushort)(~popMain()&65535U));
|
||||
break;
|
||||
case INS_OR:
|
||||
case INS_AND: /* ( a b -- a&b ) */
|
||||
pushMain(popMain() & popMain());
|
||||
break;
|
||||
case INS_XOR:
|
||||
case INS_OR: /* ( a b -- a|b ) */
|
||||
pushMain(popMain() | popMain());
|
||||
break;
|
||||
case INS_COUT:
|
||||
case INS_XOR: /* ( a b -- a^b ) */
|
||||
pushMain(popMain() ^ popMain());
|
||||
break;
|
||||
case INS_NBKIN:
|
||||
case INS_BKIN:
|
||||
case INS_COUT: /* output a character, no Unicode support for now */
|
||||
cputc((uchar)(popMain()&255U));
|
||||
break;
|
||||
case INS_PORTIO:
|
||||
case INS_NHOUT: /* output the hex number from the stack top */
|
||||
printf("%04X", popMain());
|
||||
break;
|
||||
case INS_PERSIST_READ:
|
||||
case INS_NBKIN: /* non-blocking key input - in this implementation it's equal to: */
|
||||
case INS_BKIN: /* blocking key input (again, no Unicode support yet, assuming a single byte incoming to the 16-bit value on the stack) */
|
||||
pushMain((ushort)cgetc());
|
||||
break;
|
||||
case INS_PERSIST_WRITE:
|
||||
case INS_PORTIO: /* ( p1 p2 port -- r1 r2 status ) - simulate port I/O according to the spec */
|
||||
pbuf = popMain(); /* port */
|
||||
pbuf2 = popMain(); /* p2 */
|
||||
fprintf(stderr, "[PORTIO ] Call to port 0x%X with P1=%X and P2=%X, returning status=0, R1=0, R2=0\n", pbuf, pbuf2, popMain());
|
||||
pushMain(0u);
|
||||
pushMain(0u);
|
||||
pushMain(0u);
|
||||
break;
|
||||
case INS_PERSIST_READ: /* ( adh adl len maddr -- status) */
|
||||
pushMain(persistOp(popMain(), popMain(), popMain(), popMain(), 0));
|
||||
break;
|
||||
case INS_PERSIST_WRITE: /* ( adh adl len maddr -- status) */
|
||||
pushMain(persistOp(popMain(), popMain(), popMain(), popMain(), 1));
|
||||
break;
|
||||
default: /* all characters not processed before are invalid instructions */
|
||||
trapout(INVALID_INSTRUCTION);
|
||||
goto brx;
|
||||
}
|
||||
if(ram.msp >= STACK_SIZE_WORDS || ram.rsp >= STACK_SIZE_WORDS) /* check for stack overflow after any operation */
|
||||
trapout(STACK_OVERFLOW);
|
||||
continue;
|
||||
brx: break;
|
||||
}
|
||||
/* unset interpretation mode flag and exit */
|
||||
ram.IM = 0;
|
||||
ram.pc = ram.ibp = 65535U;
|
||||
}
|
||||
|
||||
/* Equi VM entry point */
|
||||
@@ -484,17 +571,11 @@ int main(int argc, char* argv[]) {
|
||||
cputc(instr); /* echo it */
|
||||
#endif
|
||||
ram.II = 0;
|
||||
} else if(instr == CR) { /* process carriage return */
|
||||
cputc(CR); /* echo it */
|
||||
#ifdef __CC65__
|
||||
cputc(10); /* echo it */
|
||||
#endif
|
||||
} else if(instr == LF) { /* process carriage return */
|
||||
cputc(LF); /* echo it */
|
||||
ram.IM = 1; /* set the mandatory interpretation mode flag */
|
||||
equi_main_loop(); /* and run the interpreter loop */
|
||||
cputc(CR); /* echo it */
|
||||
#ifdef __CC65__
|
||||
cputc(10); /* echo it */
|
||||
#endif
|
||||
cputc(LF); /* echo it */
|
||||
cputc('>');
|
||||
cputc(' ');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user