equi

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

commit 31166c8e7f9eeccf19ed1ee412efe94b42f3de72
parent 898f1f22d340085c7f1b42398c3a7f581ae858ad
Author: Luxferre <lux@ferre>
Date:   Tue,  9 Aug 2022 07:47:50 +0300

Temporarily commented out strip

Diffstat:
MMakefile | 2+-
Mequi.c | 72+++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
2 files changed, 54 insertions(+), 20 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/equi.c b/equi.c @@ -80,8 +80,8 @@ */ struct CLTEntry { - uchar name[CLT_ENTRY_LEN]; /* compiled word name */ - ushort loc; /* compiled word location */ + ushort nhash; /* compiled word name hash */ + ushort loc; /* compiled word location */ }; struct EquiRAM { @@ -121,6 +121,7 @@ enum EquiErrors { CLT_OVERFLOW, CMD_OVERFLOW, INVALID_INSTRUCTION, + INVALID_WORD, PORT_IO_ERROR }; @@ -147,6 +148,9 @@ void trapout(errcode) { case INVALID_INSTRUCTION: cerr("Invalid instruction"); break; + case INVALID_WORD: + cerr("Word not found in CLT"); + break; case PORT_IO_ERROR: cerr("Port I/O error"); break; @@ -216,16 +220,20 @@ void pushRet(ushort val) { /* pop a value from the main stack */ ushort popMain() { - if(ram.msp == 0) + if(ram.msp == 0) { trapout(STACK_UNDERFLOW); + return 0; + } else return ram.main_stack[--ram.msp]; } /* pop a value from the return stack */ ushort popRet() { - if(ram.rsp == 0) + if(ram.rsp == 0) { trapout(STACK_UNDERFLOW); + return 0; + } else return ram.return_stack[--ram.rsp]; } @@ -239,8 +247,10 @@ void pushLit(uchar c) { /* pop a character from the literal stack */ uchar popLit() { - if(ram.lsp == 0) + if(ram.lsp == 0) { trapout(STACK_UNDERFLOW); + return 0; + } else return ram.literal_stack[--ram.lsp]; } @@ -253,7 +263,7 @@ void clearLit() { /* shape 2-byte vlaue on the main stack from the 4 values of the literal stack */ void pushLitVal(strict) { uchar p1, p2, p3, p4; - if(ram.lsp < 4) { /* if we don't strictly expect 4 bytes, do nothing */ + if(ram.lsp < 4U) { /* if we don't strictly expect 4 bytes, do nothing */ if(strict) trapout(STACK_UNDERFLOW); else { ram.lsp = 0; /* clear the literal stack */ @@ -265,19 +275,33 @@ void pushLitVal(strict) { p3 = popLit(); p2 = popLit(); p1 = popLit(); - pushMain((p1<<12) | (p2<<8) | (p3<<4) | p4); + pushMain((p1<<12U) | (p2<<8U) | (p3<<4U) | p4); ram.lsp = 0; /* clear the literal stack */ } } +/* CCITT CRC16 helper */ + +ushort crc16(const uchar* data_p, uchar length) { + uchar x; + ushort crc = 0xFFFFu; + while(length--) { + x = crc>>8U ^ *data_p++; + x ^= x>>4U; + crc = (crc << 8U) ^ ((ushort)(x << 12U)) ^ ((ushort)(x << 5U)) ^ ((ushort)x); + } + return crc; +} + /* Main interpreter loop */ void equi_main_loop() { uchar instr, i; + ushort lhash, pbuf; /* reset all stacks before running and reinit CLT */ ram.msp = ram.rsp = ram.lsp = ram.cltp = 0; /* reset pc */ - ram.pc = 65535; + ram.pc = 65535U; while(1) { /* iterate over the instructions in the command buffer */ instr = ram.cmdbuf[++ram.pc]; /* first, check for II mode */ @@ -289,17 +313,16 @@ void equi_main_loop() { /* then, check for compilation mode */ if(ram.CM) { if(instr == INS_CMEND) { /* trigger word compilation logic as per the spec */ + if(ram.lsp < CLT_ENTRY_LEN) + trapout(STACK_UNDERFLOW); ram.cmdbuf[ram.pc] = INS_RET; /* in-place patch this instruction to R */ - /* compiled words are saved vice versa to save code size */ - for(i=0;i<CLT_ENTRY_LEN;++i) - ram.clt[ram.cltp].name[i] = popLit(); + /* hash and save compiled word */ + ram.clt[ram.cltp].nhash = crc16(&ram.literal_stack[ram.lsp-CLT_ENTRY_LEN], CLT_ENTRY_LEN); ram.lsp = 0; /* clear the literal stack */ ram.clt[ram.cltp].loc = ram.cbp; /* stored the compiled code location from the most recent CBP value */ ++ram.cltp; /* increase the word */ - if(ram.cltp == CLT_ENTRIES_MAX) { + if(ram.cltp == CLT_ENTRIES_MAX) trapout(CLT_OVERFLOW); - break; - } ram.CM = 0; /* unset compilation mode flag */ } continue; @@ -318,17 +341,28 @@ void equi_main_loop() { ram.II = 1; /* raise II flag */ break; case INS_CMSTART: /* compilation start */ - ram.cbp = ram.pc + 1; /* save CBP */ - ram.CM = 1; /* raise CM flag */ + ram.cbp = ram.pc + 1U; /* save CBP */ + ram.CM = 1U; /* raise CM flag */ break; case INS_QUIT: /* gracefully quit the interpretation mode */ goto brx; case INS_LITINT: /* literal stack -> main stack as short */ - pushLitVal(1); + pushLitVal(1U); break; case INS_LITSTR: break; - case INS_LITCALL: + case INS_LITCALL: /* call the saved word from the literal */ + if(ram.lsp < CLT_ENTRY_LEN) + trapout(STACK_UNDERFLOW); + lhash = crc16(&ram.literal_stack[ram.lsp-CLT_ENTRY_LEN], CLT_ENTRY_LEN); + for(pbuf=0;pbuf<CLT_ENTRIES_MAX;++pbuf) + if(ram.clt[pbuf].nhash == lhash) { + ram.pc = ram.clt[pbuf].loc; + break; + } + if(pbuf >= CLT_ENTRIES_MAX) + trapout(INVALID_WORD); + ram.lsp = 0; /* clear the literal stack */ break; case INS_RET: ram.pc = popRet(); @@ -421,7 +455,7 @@ int main(int argc, char* argv[]) { ram.cmd_size = CMD_BUF_SIZE; ram.II = ram.CM = ram.IM = 0; /* reset all flags */ /* Start both execution and input buffering from the start of command buffer (-1 because we use prefix increment) */ - ram.pc = ram.ibp = ram.cmd_start-1; + ram.pc = ram.ibp = 65535U; printf("Welcome to Equi v" EQUI_VER " by Luxferre, 2022\n\nCLT: 0x%X (%d bytes)\nGPD: 0x%X (%d bytes)\nCommand buffer: 0x%X (%d bytes)\nEqui ready\n\n", (uchar *)&ram.clt - (uchar *)&ram.main_stack,