equi

A self-descriptive stack-based PC platform
git clone git://git.luxferre.top/equi.git
Log | Files | Refs | README | LICENSE

commit 4c7643decdd8efd12ddafcbfea21e4098b825b57
parent ac18f1499cd7987f3aac988a07c901cc8cbd9cbc
Author: Luxferre <lux@ferre>
Date:   Thu, 11 Aug 2022 15:36:39 +0300

Port I/O tested; strip unstable again, commented out

Diffstat:
MMakefile | 2+-
MREADME.md | 2+-
Mequi.c | 48++++++++++++++++++++++++++++++++++++++++--------
3 files changed, 42 insertions(+), 10 deletions(-)

diff --git a/Makefile b/Makefile @@ -7,7 +7,7 @@ DFLAGS= desktopcc: cc -std=c89 -Os -o $(PROJNAME) $(CFILES) $(DFLAGS) - strip $(PROJNAME) +# strip $(PROJNAME) tcc: tcc -std=c89 -o $(PROJNAME) $(CFILES) $(DFLAGS) diff --git a/README.md b/README.md @@ -132,7 +132,7 @@ Please also note that Equi doesn't specify any graphical or sound output capabil Being a purely PC-oriented low-level runtime/programming environment, Equi has the reference implementation emulator/VM written in C (ANSI C89 standard), `equi.c`, compilable and runnable on all the systems supporting standard I/O. Note that, for portability reasons, this emulator: -- doesn't fully implement `P` instruction but instead outputs its parameters to the standard error stream and puts three 0x0000 values back onto the stack, +- only implements three ports for `P` instruction: 0 as an echo port (returns passed parameters as corresponding result values), 1 as a random port (returns two random values in the results in the range between the two parameter values) and 2 as a CRC16 calculation port for a given memory location and its length, for any other port value it outputs its parameters to the standard error stream and puts three 0x0000 values back onto the stack, - doesn't implement non-blocking key input (the ',' instruction is identical to blocking key input instruction `?`), - sandboxes the `{` and `}` operations using the file you supply in the command-line parameter. If you don't supply the file, these operations will effectively do nothing except putting 0x0000 (success status) onto the stack. diff --git a/equi.c b/equi.c @@ -17,6 +17,7 @@ #else #include <stdlib.h> #include <stdio.h> +#include <time.h> #endif /* @@ -206,6 +207,14 @@ enum EquiInstructions { INS_QUIT='Q' }; +/* Equi known ports enum */ + +enum EquiPorts { + 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_CHECKSUM /* checksum port: P1 = memAddr, P2 = length => R1=CRC16(memAddr, length), R2 = 0 */ +}; + /* push a value onto the main stack */ void pushMain(ushort val) { ram.main_stack[ram.msp++] = val; @@ -285,12 +294,36 @@ ushort crc16(const uchar* data_p, uchar length) { return crc; } -/* persistent operation handler */ +/* Persistent operation handler */ ushort persistOp(maddr, dataLen, adl, adh, isWrite) { return 0; } +/* Port I/O handler */ + +void portIO(port, p2, p1) { + ushort r1 = 0, r2 = 0, status = 0; + switch(port) { + case PORT_ECHO: + r1 = p1; + r2 = p2; + break; + case PORT_RANDOM: + r1 = (ushort) (p1 + (rand()%p2)); + r2 = (ushort) (p1 + (rand()%p2)); + break; + case PORT_CHECKSUM: + r1 = crc16(&flatram[p1], p2); + break; + default: + fprintf(stderr, "[PORTIO] Unimplemented call to port 0x%X with P1=%X and P2=%X, returning status=0, R1=0, R2=0\n", port, p1, p2); + } + pushMain(r1); + pushMain(r2); + pushMain(status); +} + /* Main interpreter loop */ void equi_main_loop() { @@ -490,13 +523,10 @@ void equi_main_loop() { 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_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); + case INS_PORTIO: /* ( p1 p2 port -- r1 r2 status ) - simulate/execute port I/O according to the spec */ + if(ram.msp < 3) + trapout(STACK_UNDERFLOW); + portIO(popMain(), popMain(), popMain()); break; case INS_PERSIST_READ: /* ( adh adl len maddr -- status) */ pushMain(persistOp(popMain(), popMain(), popMain(), popMain(), 0)); @@ -534,6 +564,8 @@ int main(int argc, char* argv[]) { setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); #endif + /* initialize the PRNG */ + srand((unsigned)time(NULL)); /* initialize the RAM in the most standard way */ ram.gpd_start = (uchar *)&ram.gpd - (uchar *)&ram.main_stack; ram.cmd_start = (uchar *)&ram.cmdbuf - (uchar *)&ram.main_stack;