equi

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

commit 93f19d3a17cd100e1f391b6f68aed8518213712f
parent 132dcedc9e14ce02705eca7b746b5e40df3800f8
Author: Luxferre <lux@ferre>
Date:   Sun, 14 Aug 2022 15:58:45 +0300

Updated make target for a2enh

Diffstat:
MMakefile | 13+++++++++----
MREADME.md | 4+++-
Mequi.c | 27++++++++++++++++-----------
3 files changed, 28 insertions(+), 16 deletions(-)

diff --git a/Makefile b/Makefile @@ -4,17 +4,22 @@ PROJNAME=equi CFILES=equi.c PBTDIR=platform-build-tools PERSFILE=PERS.DAT +# Apple II target configuration +A2FLAGS=-DSTACK_SIZE=256 -DLIT_STACK_SIZE=32 -DGPD_AREA_SIZE=3072 -DCMD_BUF_SIZE=20000 -DCLT_ENTRIES_MAX=512 -DEQUI_TASKS_MAX=8 +# POSIX desktop target configuration +PDFLAGS=-DSTACK_SIZE=256 -DLIT_STACK_SIZE=32 -DGPD_AREA_SIZE=3072 -DCMD_BUF_SIZE=20000 -DCLT_ENTRIES_MAX=512 -DEQUI_TASKS_MAX=8 +# Common flags DFLAGS=-DPERSIST_FILE="\"$(PERSFILE)\"" desktopcc: perscopy - cc -std=c89 -Os -o $(PROJNAME) $(CFILES) $(DFLAGS) + cc -std=c89 -Os -o $(PROJNAME) $(CFILES) $(PDFLAGS) $(DFLAGS) # strip $(PROJNAME) tcc: perscopy - tcc -std=c89 -o $(PROJNAME) $(CFILES) $(DFLAGS) + tcc -std=c89 -o $(PROJNAME) $(CFILES) $(PDFLAGS) $(DFLAGS) apple2-build: - cl65 --standard c89 -O -Os -t apple2 -o $(PROJNAME).apple2 $(CFILES) $(DFLAGS) + cl65 --standard c89 -O -Os -t apple2 -C apple2-system.cfg -o $(PROJNAME).apple2 $(CFILES) $(A2FLAGS) $(DFLAGS) apple2: apple2-build cp $(PBTDIR)/apple2/tpl.dsk $(PROJNAME).dsk @@ -23,7 +28,7 @@ apple2: apple2-build java -jar $(PBTDIR)/apple2/ac.jar -dos $(PROJNAME).dsk $(PERSFILE) bin < $(PBTDIR)/$(PERSFILE) apple2enh-build: - cl65 --standard c89 -O -Os -t apple2enh -o $(PROJNAME).a2enh $(CFILES) $(DFLAGS) + cl65 --standard c89 -O -Os -t apple2enh -C apple2enh-system.cfg -o $(PROJNAME).a2enh $(CFILES) $(A2FLAGS) $(DFLAGS) apple2enh: apple2enh-build cp $(PBTDIR)/apple2/tpl.dsk $(PROJNAME)-enh.dsk diff --git a/README.md b/README.md @@ -118,6 +118,7 @@ Op |Stack state |Meaning `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 `}`|`( blk len maddr -- status)` |Persistent storage write operation. Stack parameters: block number (x1K), data length, RAM address `{`|`( blk len maddr -- status)` |Persistent storage read operation. Stack parameters: block number (x1K), data length, RAM address +`Y`|`( addr len priv -- taskid )` |Fork an area from the command buffer starting at `addr` into a new task, activate it (see below) and push the task ID onto the stack `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) Note that, due to the dynamic nature of word allocation and ability to reconfigure the runtime environment for different offsets depending on the target, absolute jumps are not directly supported in Equi and generally not recommended, although one can easily do them with `]R` sequence and/or calculate absolute positions using `X` instruction. @@ -147,7 +148,8 @@ The following constants can be adjusted at compile time: - `GPD_AREA_SIZE` - GPD area size in bytes; - `CMD_BUF_SIZE` - command buffer size in bytes (65535 max); - `CLT_ENTRIES_MAX` - size (in entries) of the compilation lookup table (CLT), each entry taking exactly 4 bytes; -- `PERSIST_FILE` - the name of persistent storage sandbox file (`PERS.DAT` by default). +- `PERSIST_FILE` - the name of persistent storage sandbox file (`PERS.DAT` by default); +- `EQUI_TASKS_MAX` - maximum amount of concurrently running tasks on the system. Please keep in mind that the reference implementation code primarily serves as a, well, reference on how the specification should be implemented, so it emphasizes on code portability and readability over performance whenever such a choice arises. diff --git a/equi.c b/equi.c @@ -139,6 +139,9 @@ static uchar* flatram = (uchar *)&ram; /* reference to the current task context */ static struct EquiCtx *curtask; +/* reference to the buffer task context */ +static struct EquiCtx *taskptr; + /* Error reporting codes */ enum EquiErrors { SUCCESS=0, @@ -201,7 +204,10 @@ void trapout(errcode) { cerr("All task slots busy and active\n"); break; } - exit(errcode); + if(curtask) /* if we're in a task, only terminate it */ + curtask->active=1; + else /* otherwise to a hard trapout */ + exit(errcode); } } @@ -257,7 +263,8 @@ enum EquiInstructions { 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 */ + PORT_CHECKSUM, /* checksum port: P1 = memAddr, P2 = length => R1=CRC16(memAddr, length), R2 = 0 */ + PORT_TASKCTL /* task control port: P1 = task id, P2 = operation => R1 = operation result, R2 = operation status */ }; /* push a value onto the main stack */ @@ -393,7 +400,7 @@ void portIO(ushort port, ushort p2, ushort p1) { 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); + fprintf(stderr, "[PORTIO] Unimplemented call to port 0x%X with P1=%X and P2=%X\n", port, p1, p2); } pushMain(r1); pushMain(r2); @@ -432,7 +439,7 @@ struct EquiCtx* equi_load_task(uchar priv, ushort len, ushort progStart) { /* don't allow to load privileged tasks from non-privileged ones */ if(curtask && !curtask->privileged) priv = 0; - struct EquiCtx *taskptr = &ram.tasks[tid]; /* refer to the next available entry */ + taskptr = &ram.tasks[tid]; /* refer to the next available entry */ taskptr->msp = taskptr->rsp = taskptr->lsp = taskptr->cltp = 0; /* init stacks and CLT */ taskptr->pc = progStart - 1U; /* init program counter for preincrement logic */ taskptr->cmd_start = progStart; /* actual command buffer start (from the start of vRAM) */ @@ -448,7 +455,6 @@ struct EquiCtx* equi_load_task(uchar priv, ushort len, ushort progStart) { void equi_main_loop() { uchar instr; ushort lhash, pbuf, pbuf2; - struct EquiCtx *newtaskptr; /* try to open the persistent sandbox file */ FILE *pfd = fopen(PERSIST_FILE, "r+b"); while(1) { /* iterate over the instructions in the command buffer */ @@ -664,9 +670,9 @@ void equi_main_loop() { pushMain(persistOp(pfd, popMain(), popMain(), popMain(), 1)); break; case INS_TASKLOAD: /* ( addr len priv -- taskid ) */ - newtaskptr = equi_load_task(popMain(), popMain(), popMain()); - newtaskptr->active = 1; - pushMain(newtaskptr->id); + taskptr = equi_load_task(popMain(), popMain(), popMain()); + taskptr->active = 1; + pushMain(taskptr->id); break; default: /* all characters not processed before are invalid instructions */ trapout(INVALID_INSTRUCTION); @@ -714,8 +720,7 @@ int main(int argc, char* argv[]) { #else /* VT100-compatible terminal init */ printf("\033c"); #endif - printf("Welcome to Equi v" EQUI_VER " by Luxferre, 2022\nStack size: %d bytes\nLiteral stack size: %d bytes\nCommand buffer: 0x%04X (%d bytes)\nEqui ready\n\n> ", - STACK_SIZE, LIT_STACK_SIZE, ram.cmd_start, ram.cmd_size); + printf("Welcome to Equi v" EQUI_VER " by Luxferre, 2022\nSystem RAM: %d bytes\nEqui ready\n\n> ", (int) sizeof(ram)); } while(1) { /* Now, we're in the command mode loop */ @@ -736,7 +741,7 @@ int main(int argc, char* argv[]) { cputc(instr); /* echo it */ #endif ram.II = 0; - } else if(!ram.II && (instr == 0xFFU || instr == INS_QUIT)) { + } else if(!ram.II && instr == INS_QUIT) { if(ram.MM) { /* output command buffer contents to stdout and exit */ ram.cmdbuf[++ram.ibp] = INS_QUIT; /* end program with INS_QUIT */ ram.cmdbuf[++ram.ibp] = 0; /* and zero terminator */