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:
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;