equi

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

commit 859e4b31088adb0ae73dd63aa6abc957778c6005
parent f5fe3b6a151be0fbf25f44b6afc0511689c96237
Author: Luxferre <lux@ferre>
Date:   Tue, 16 Aug 2022 11:51:49 +0300

Figured out termios

Diffstat:
MREADME.md | 12+++++++-----
Mequi.c | 49+++++++++++++++++++++++++++++++------------------
2 files changed, 38 insertions(+), 23 deletions(-)

diff --git a/README.md b/README.md @@ -4,6 +4,8 @@ Equi is a general-purpose 16-bit stack-based platform (and a programming languag The name Equi comes from the fact each source code instruction is **equi**valent to a machine instruction. No, it isn't mapped to one machine instruction. It **is the** machine instruction. All the instructions and data in Equi are represented with printable ASCII characters only. This allows to bootstrap Equi code directly from the keyboard (any standard keyboard/keypad that allows serial input) using a tiny interpreter stored, for instance, in the hardware ROM. +This document describes a more-or-less formal specification. For a tutorial on how to use it, please read the [Programming in Equi](programming-in-equi.md) book. + ## Specification Main features of an Equi machine: @@ -84,16 +86,16 @@ Op |Stack state |Meaning `:`|`( -- )` |Compilation mode start: set CM flag and set CBP to PC+1 value `;`|`( -- )` |Compilation mode end: replace this instruction in-memory with `R` instruction, pop all characters from the literal stack, append the lookup table with their CRC16 hash and CBP value, unset the CM flag and increment CLTP value `'`|`( -- )` |Call the compiled word: pop all characters from the literal stack, compute their CRC16 hash, look it up in CLT for a CBP value, set PC to CBP if found, error out if not, then push PC to return stack and set PC to the CBP value -`R`|`( -- )` |**R**eturn: pop and assign the PC value from the return stack -`]`|`( a -- )` |Pop the value from main stack and push onto return stack -`[`|`( -- a )` |Pop the value from return stack and push onto main stack +`R`|R: `( a -- )` |**R**eturn: pop and assign the PC value from the return stack +`]`|M: `( a -- )` R: `( -- a )` |Pop the value from main stack and push onto return stack +`[`|M: `( -- a )` R: `( a -- )` |Pop the value from return stack and push onto main stack `L`|`( addr -- a` ) |**L**oad a 16-bit value from `addr` `S`|`( a addr -- )` |**S**tore a 16-bit value into `addr` `W`|`( a addr -- )` |**W**rite a 8-bit value into `addr` (note that both value and address still must be 16-bit, the higher byte of the value is discarded) `!`|`( a -- )` |Drop the top value from the stack `$`|`( a -- a a )` |Duplicate the top value on the stack -`%`|`( a b -- b a )` |Swap two top values on the stack -`@`|`( a b c -- b c a )` |Rotate three top values on the stack +`%`|`( a b -- b a )` |Swap top two values on the stack +`@`|`( a b c -- b c a )` |Rotate top three values on the stack `\`|`( a b -- a b a )` |Copy over the second value on the stack `J`|`( rel -- )` |**J**ump: increase or decrease PC according to the relative value (treated as signed, from -32768 to 32767) `I`|`( cond rel -- ) ` |Pop relative value and condition. **I**f the condition value is not zero, `J` to the relative value diff --git a/equi.c b/equi.c @@ -13,12 +13,19 @@ #ifdef __TINYC__ #include <tcclib.h> +#include <stdlib.h> +#include <stdio.h> +#include <time.h> +#include <termios.h> +#include <unistd.h> #define stderr 2 #define SEEK_SET 0 #else #include <stdlib.h> #include <stdio.h> #include <time.h> +#include <termios.h> +#include <unistd.h> #endif /* @@ -723,9 +730,11 @@ int main(int argc, char* argv[]) { int host_islittle = 1; host_islittle = (*((char *)&host_islittle) == 1) ? 1 : 0; /* _attempt_ to disable buffering for char input/output */ -#if !defined __CC65__ && !defined __TINYC__ - setvbuf(stdin, NULL, _IONBF, 0); - setvbuf(stdout, NULL, _IONBF, 0); +#if !defined __CC65__ + struct termios tty_opts_raw, tty_opts_backup; + tcgetattr(STDIN_FILENO, &tty_opts_backup); + cfmakeraw(&tty_opts_raw); + tcsetattr(STDIN_FILENO, TCSANOW, &tty_opts_raw); #endif /* initialize the PRNG */ srand((unsigned)time(NULL)); @@ -736,8 +745,10 @@ int main(int argc, char* argv[]) { ram.cmd_size = CMD_BUF_SIZE; ram.II = ram.MM = 0; /* reset all flags */ /* 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; + smode = 1; /* also behave as if in the silent mode */ + } else if(argc > 1 && argv[1][0] == 's') /* enter silent mode, don't print the banners and prompts */ smode = 1; /* Start input buffering from the start of command buffer (-1 because we use prefix increment) */ @@ -750,26 +761,25 @@ int main(int argc, char* argv[]) { #else /* VT100-compatible terminal init */ printf("\033c"); #endif - printf("Welcome to Equi v" EQUI_VER " by Luxferre, 2022\nSystem RAM: %d bytes\nEqui ready\n\n> ", (int) sizeof(ram)); + printf("Welcome to Equi v" EQUI_VER " by Luxferre, 2022\r\nSystem RAM: %d bytes\r\nEqui ready\r\n\r\n> ", (int) sizeof(ram)); } while(1) { /* Now, we're in the command mode loop */ instr = cgetc(); /* Fetch the next instruction from the keyboard/stdin */ - if(instr == 0xFFU || instr == 0U) /* exit on zero byte */ + if(instr == 0xFFU || instr == 0U || instr == 3U || instr == 4U) /* exit on zero byte or ctrl+C or ctrl+D */ break; else if(instr == BS || instr == CR || instr == LF || instr == ' ' || instr == '\t') { /* ignore the backspace or whitespaces */ -#ifdef __CC65__ - cputc(instr); /* echo it */ -#endif + if(!smode) + cputc(instr); /* echo it if not in silent mode */ + if(instr == CR) + cputc(LF); } else if(instr == INS_IISTART) { /* process II start */ -#ifdef __CC65__ - cputc(instr); /* echo it */ -#endif + if(!smode) + cputc(instr); /* echo it if not in silent mode */ ram.II = 1; } else if(instr == INS_IIEND) { /* process II end */ -#ifdef __CC65__ - cputc(instr); /* echo it */ -#endif + if(!smode) + cputc(instr); /* echo it if not in silent mode */ ram.II = 0; } else if(!ram.II && instr == INS_QUIT) { if(ram.MM) { /* output command buffer contents to stdout and exit */ @@ -798,10 +808,13 @@ int main(int argc, char* argv[]) { } else { /* append the instruction/character to the command buffer if and only if it doesn't match the above criteria and we're not in II mode */ if(!ram.II) ram.cmdbuf[++ram.ibp] = instr; -#ifdef __CC65__ - cputc(instr); /* echo it */ -#endif + if(!smode) + cputc(instr); /* echo it if not in silent mode */ } } /* command mode loop end */ +#if !defined __CC65__ && !defined __TINYC__ + /* restore the terminal settings */ + tcsetattr(STDIN_FILENO, TCSANOW, &tty_opts_backup); +#endif return 0; }