Hopefully fixed literals and implemented most instructions

This commit is contained in:
Luxferre
2022-08-09 20:59:08 +03:00
parent 31166c8e7f
commit 0be72ee3fd
2 changed files with 143 additions and 61 deletions
+2 -1
View File
@@ -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)
+141 -60
View File
@@ -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(' ');
}