Files
equi/equi.c
T

585 lines
17 KiB
C
Raw Normal View History

2022-08-06 00:08:17 +03:00
/*
* Equi platform reference implementation
*
* Created in 2022 by Luxferre, released into public domain
*
* See equi.md file for the specification and manual
*
* @license Unlicense <https://unlicense.org>
* @author Luxferre
*/
2022-08-06 09:34:32 +03:00
/* Standard includes with size optimizations for TCC */
2022-08-06 00:08:17 +03:00
2022-08-06 09:34:32 +03:00
#ifdef __TINYC__
#include <tcclib.h>
2022-08-08 06:48:46 +03:00
#define stderr 2
2022-08-06 09:34:32 +03:00
#else
2022-08-06 00:08:17 +03:00
#include <stdlib.h>
#include <stdio.h>
2022-08-06 09:34:32 +03:00
#endif
/*
* Non-standard includes
* To save space, we emulate necessary conio functions on non-6502 systems, not vice versa
*/
#ifdef __CC65__
#include <conio.h>
#else
2022-08-07 22:20:48 +03:00
#define cgetc() (getchar())
#define cputc(c) (putchar(c))
2022-08-06 09:34:32 +03:00
#endif
2022-08-06 00:08:17 +03:00
/* Definitions section */
#define EQUI_VER "0.0.1"
2022-08-07 22:20:48 +03:00
#define cerr(s) (fputs(s, stderr))
2022-08-06 00:08:17 +03:00
#define ushort unsigned short /* basic 16-bit integer */
#define uchar unsigned char /* basic 8-bit integer */
#define WS sizeof(ushort) /* Equi word size in bytes */
#define BS 8u /* Backspace character code */
2022-08-07 22:20:48 +03:00
#define CR 13u /* Character return code */
#define LF 10u /* Line feed code */
2022-08-06 00:08:17 +03:00
/* Configuration section (constants overridable at compile-time) */
/* Main and return stack size in bytes */
#ifndef STACK_SIZE
2022-08-06 13:35:10 +03:00
#define STACK_SIZE 256u
2022-08-06 00:08:17 +03:00
#endif
/* Literal stack size in bytes */
#ifndef LIT_STACK_SIZE
2022-08-06 13:35:10 +03:00
#define LIT_STACK_SIZE 32u
2022-08-06 00:08:17 +03:00
#endif
/* Command buffer size in bytes */
#ifndef GPD_AREA_SIZE
#define GPD_AREA_SIZE 6400u
2022-08-06 00:08:17 +03:00
#endif
/* Command buffer size in bytes */
#ifndef CMD_BUF_SIZE
2022-08-06 13:35:10 +03:00
#define CMD_BUF_SIZE 15600u
2022-08-06 00:08:17 +03:00
#endif
/* Maximum amount of CLT entries */
#ifndef CLT_ENTRIES_MAX
#define CLT_ENTRIES_MAX 512u
#endif
2022-08-06 00:08:17 +03:00
/* Some necessary constants and offsets derived from the above values */
#define STACK_SIZE_WORDS (STACK_SIZE / WS) /* Main and return stack size in words */
/*
* Structures that describe Equi machine RAM using the above configuration
*/
struct CLTEntry {
2022-08-09 07:47:50 +03:00
ushort nhash; /* compiled word name hash */
ushort loc; /* compiled word location */
2022-08-06 00:08:17 +03:00
};
struct EquiRAM {
ushort main_stack[STACK_SIZE_WORDS];
ushort return_stack[STACK_SIZE_WORDS];
uchar literal_stack[LIT_STACK_SIZE];
ushort pc; /* program counter */
ushort msp; /* main stack pointer */
ushort rsp; /* return stack pointer */
uchar lsp; /* literal stack pointer */
2022-08-06 00:08:17 +03:00
ushort cbp; /* compilation buffer pointer */
ushort cltp; /* compilation lookup table pointer */
unsigned int II:1; /* instruction ignore mode */
unsigned int CM:1; /* compilation mode */
unsigned int IM:1; /* interpretation mode */
2022-08-06 00:08:17 +03:00
ushort gpd_start;
ushort cmd_start;
ushort cmd_size;
ushort ibp; /* input buffer pointer */
2022-08-06 00:08:17 +03:00
struct CLTEntry clt[CLT_ENTRIES_MAX]; /* compilation lookup table */
uchar gpd[GPD_AREA_SIZE];
uchar cmdbuf[CMD_BUF_SIZE];
};
2022-08-06 09:34:32 +03:00
/* Before running the main code, instantiate the machine RAM */
static struct EquiRAM ram;
2022-08-06 00:08:17 +03:00
/* Also create an alternative view of the same RAM area for direct offset-based access */
static uchar* flatram = (uchar *)&ram;
2022-08-07 22:20:48 +03:00
/* Error reporting codes */
enum EquiErrors {
SUCCESS=0,
STACK_OVERFLOW,
STACK_UNDERFLOW,
DIV_BY_ZERO,
CLT_OVERFLOW,
CMD_OVERFLOW,
INVALID_INSTRUCTION,
2022-08-09 07:47:50 +03:00
INVALID_WORD,
2022-08-07 22:20:48 +03:00
PORT_IO_ERROR
};
/* Error reporting method */
void trapout(errcode) {
if(errcode > 0) {
fprintf(stderr, "\nError %d at 0x%x (instruction %c): ", errcode, ram.pc, ram.cmdbuf[ram.pc]);
2022-08-07 22:20:48 +03:00
switch(errcode) {
case STACK_OVERFLOW:
cerr("Stack overflow\n");
2022-08-07 22:20:48 +03:00
break;
case STACK_UNDERFLOW:
cerr("Stack underflow\n");
2022-08-07 22:20:48 +03:00
break;
case DIV_BY_ZERO:
cerr("Division by zero\n");
2022-08-07 22:20:48 +03:00
break;
case CLT_OVERFLOW:
cerr("Compilation lookup table full\n");
2022-08-07 22:20:48 +03:00
break;
case CMD_OVERFLOW:
cerr("Command buffer full\n");
2022-08-07 22:20:48 +03:00
break;
case INVALID_INSTRUCTION:
cerr("Invalid instruction\n");
2022-08-07 22:20:48 +03:00
break;
2022-08-09 07:47:50 +03:00
case INVALID_WORD:
cerr("Word not found in CLT\n");
2022-08-09 07:47:50 +03:00
break;
2022-08-07 22:20:48 +03:00
case PORT_IO_ERROR:
cerr("Port I/O error\n");
2022-08-07 22:20:48 +03:00
break;
}
exit(errcode);
}
}
/* Equi instructions enum */
enum EquiInstructions {
INS_IISTART='(',
INS_IIEND=')',
INS_CMSTART=':',
INS_CMEND=';',
INS_LITINT='#',
INS_LITSTR='"',
INS_LITCALL='\'',
INS_RET='R',
INS_M2R=']', /* main -> return */
INS_R2M='[', /* return -> main */
INS_LOAD='L',
INS_STORE='S',
INS_STOREBYTE='W',
INS_DROP='!',
INS_DUP='$',
INS_SWAP='%',
INS_ROT='@',
INS_OVER='\\',
INS_JUMP='J',
INS_IF='I',
INS_EXPOINT='X', /* locate execution point */
INS_GT='>',
INS_LT='<',
INS_EQ='=',
INS_ADD='+',
INS_SUB='-',
INS_MUL='*',
INS_DIV='/',
INS_NEG='N',
INS_SHIFT='T',
2022-08-07 22:20:48 +03:00
INS_NOT='~',
INS_AND='&',
INS_OR='|',
INS_XOR='^',
INS_COUT='.', /* character output */
INS_NHOUT='H', /* numeric hex output */
2022-08-07 22:20:48 +03:00
INS_NBKIN=',', /* non-blocking key input */
INS_BKIN='?', /* blocking key input */
INS_PORTIO='P',
INS_PERSIST_WRITE='}',
INS_PERSIST_READ='{',
INS_QUIT='Q'
};
/* push a value onto the main stack */
void pushMain(ushort val) {
ram.main_stack[ram.msp++] = val;
if(ram.msp >= STACK_SIZE_WORDS)
trapout(STACK_OVERFLOW);
}
/* push a value onto the return stack */
void pushRet(ushort val) {
ram.return_stack[ram.rsp++] = val;
if(ram.rsp >= STACK_SIZE_WORDS)
trapout(STACK_OVERFLOW);
}
/* pop a value from the main stack */
ushort popMain() {
2022-08-09 07:47:50 +03:00
if(ram.msp == 0) {
2022-08-07 22:20:48 +03:00
trapout(STACK_UNDERFLOW);
2022-08-09 07:47:50 +03:00
return 0;
}
2022-08-07 22:20:48 +03:00
else
return ram.main_stack[--ram.msp];
}
/* pop a value from the return stack */
ushort popRet() {
2022-08-09 07:47:50 +03:00
if(ram.rsp == 0) {
2022-08-07 22:20:48 +03:00
trapout(STACK_UNDERFLOW);
2022-08-09 07:47:50 +03:00
return 0;
}
2022-08-07 22:20:48 +03:00
else
return ram.return_stack[--ram.rsp];
}
/* push a character to the literal stack */
2022-08-07 22:20:48 +03:00
void pushLit(uchar c) {
ram.literal_stack[ram.lsp++] = c;
if(ram.lsp >= LIT_STACK_SIZE)
trapout(STACK_OVERFLOW);
2022-08-07 22:20:48 +03:00
}
/* pop a character from the literal stack */
uchar popLit() {
2022-08-09 07:47:50 +03:00
if(ram.lsp == 0) {
2022-08-07 22:20:48 +03:00
trapout(STACK_UNDERFLOW);
2022-08-09 07:47:50 +03:00
return 0;
}
2022-08-07 22:20:48 +03:00
else
return ram.literal_stack[--ram.lsp];
}
/* convert ASCII code of a hex digit to the digit value */
uchar a2d(uchar a) {
return (a < 0x3aU) ? (a - 0x30U) : (a - 55U);
2022-08-08 11:07:24 +03:00
}
2022-08-07 22:20:48 +03:00
/* shape 2-byte vlaue on the main stack from up to 4 values of the literal stack */
void pushLitVal() {
uchar p[4U] = {0,0,0,0}, i, thr = 4U;
if(ram.lsp < 4U) thr = ram.lsp;
for(i=0;i<thr;++i)
p[3-i] = a2d(popLit());
pushMain((p[0]<<12U) | (p[1]<<8U) | (p[2]<<4U) | p[3]);
ram.lsp = 0; /* clear the literal stack */
2022-08-07 22:20:48 +03:00
}
2022-08-09 07:47:50 +03:00
/* 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;
}
/* persistent operation handler */
ushort persistOp(maddr, dataLen, adl, adh, isWrite) {
return 0;
}
2022-08-07 22:20:48 +03:00
/* Main interpreter loop */
void equi_main_loop() {
2022-08-08 11:07:24 +03:00
uchar instr, i;
ushort lhash, pbuf, pbuf2;
2022-08-08 11:07:24 +03:00
/* reset all stacks before running and reinit CLT */
ram.msp = ram.rsp = ram.lsp = ram.cltp = 0;
/* reset pc */
2022-08-09 07:47:50 +03:00
ram.pc = 65535U;
2022-08-07 22:20:48 +03:00
while(1) { /* iterate over the instructions in the command buffer */
instr = ram.cmdbuf[++ram.pc];
2022-08-10 17:53:10 +03:00
/* silently exit on zero or FF */
if(instr == 0 || instr == 0xFFu) break;
2022-08-07 22:20:48 +03:00
/* first, check for II mode */
if(ram.II) {
2022-08-08 11:07:24 +03:00
if(instr == INS_IIEND)
2022-08-07 22:20:48 +03:00
ram.II = 0; /* unset instruction ignore mode flag */
continue;
}
/* then, check for compilation mode */
if(ram.CM) {
2022-08-08 11:07:24 +03:00
if(instr == INS_CMEND) { /* trigger word compilation logic as per the spec */
if(ram.lsp < 1)
2022-08-09 07:47:50 +03:00
trapout(STACK_UNDERFLOW);
2022-08-08 11:07:24 +03:00
ram.cmdbuf[ram.pc] = INS_RET; /* in-place patch this instruction to R */
2022-08-09 07:47:50 +03:00
/* hash and save compiled word */
ram.clt[ram.cltp].nhash = crc16(&ram.literal_stack[0], ram.lsp);
2022-08-08 11:07:24 +03:00
ram.lsp = 0; /* clear the literal stack */
2022-08-07 22:20:48 +03:00
ram.clt[ram.cltp].loc = ram.cbp; /* stored the compiled code location from the most recent CBP value */
++ram.cltp; /* increase the word */
2022-08-09 07:47:50 +03:00
if(ram.cltp == CLT_ENTRIES_MAX)
2022-08-07 22:20:48 +03:00
trapout(CLT_OVERFLOW);
ram.CM = 0; /* unset compilation mode flag */
}
continue;
}
/* other than that, continue with interpretation mode */
/* first, detect lowercase, underscore, digit and A to F */
if((instr >= '0' && instr <= '9') || (instr >= 'A' && instr <= 'F') || instr == '_' || (instr >= 'a' && instr <= 'z')) {
pushLit(instr);
continue;
}
/* then trigger literal auto-push if applicable */
2022-08-08 11:07:24 +03:00
if(ram.lsp > 0 && instr != INS_LITSTR && instr != INS_LITCALL && instr != INS_LITINT && instr != INS_CMSTART)
pushLitVal();
2022-08-08 11:07:24 +03:00
switch(instr) { /* then perform all main interpretation logic */
case INS_IISTART: /* instruction ignore start */
ram.II = 1; /* raise II flag */
break;
case INS_CMSTART: /* compilation start */
2022-08-09 07:47:50 +03:00
ram.cbp = ram.pc + 1U; /* save CBP */
ram.CM = 1U; /* raise CM flag */
2022-08-08 11:07:24 +03:00
break;
case CR:
case LF:
case '\t':
case ' ': /* all nops in interpretation mode */
break;
2022-08-08 11:07:24 +03:00
case INS_QUIT: /* gracefully quit the interpretation mode */
goto brx;
case INS_LITINT: /* literal stack -> main stack as short */
pushLitVal();
2022-08-08 11:07:24 +03:00
break;
case INS_LITSTR: /* literal stack -> each char at main stack as short */
while(ram.lsp)
pushMain((ushort)popLit());
ram.lsp = 0;
2022-08-08 11:07:24 +03:00
break;
2022-08-09 07:47:50 +03:00
case INS_LITCALL: /* call the saved word from the literal */
if(ram.lsp < 1)
2022-08-09 07:47:50 +03:00
trapout(STACK_UNDERFLOW);
lhash = crc16(&ram.literal_stack[0], ram.lsp);
2022-08-09 07:47:50 +03:00
for(pbuf=0;pbuf<CLT_ENTRIES_MAX;++pbuf)
if(ram.clt[pbuf].nhash == lhash) {
2022-08-10 17:53:10 +03:00
pushRet(ram.pc); /* first, save the PC into the return stack */
ram.pc = ram.clt[pbuf].loc; /* then jump to the word location */
2022-08-09 07:47:50 +03:00
break;
}
if(pbuf >= CLT_ENTRIES_MAX)
trapout(INVALID_WORD);
ram.lsp = 0; /* clear the literal stack */
2022-08-08 11:07:24 +03:00
break;
case INS_RET: /* jump to the instruction at ret stack */
2022-08-08 11:07:24 +03:00
ram.pc = popRet();
break;
case INS_M2R: /* main -> ret stack */
pushRet(popMain());
2022-08-08 11:07:24 +03:00
break;
case INS_R2M: /* ret -> main stack */
pushMain(popRet());
2022-08-08 11:07:24 +03:00
break;
case INS_LOAD: /* mem -> main stack */
pbuf = popMain();
pushMain((flatram[pbuf] << 8)|flatram[pbuf+1U]);
2022-08-08 11:07:24 +03:00
break;
case INS_STORE: /* main stack -> mem (word) */
pbuf = popMain();
pbuf2 = popMain();
flatram[pbuf] = pbuf2 >> 8U;
flatram[pbuf + 1U] = pbuf2 & 255U;
2022-08-08 11:07:24 +03:00
break;
case INS_STOREBYTE: /* main stack -> mem (byte) */
pbuf = popMain();
flatram[pbuf] = popMain() & 255U;
2022-08-08 11:07:24 +03:00
break;
case INS_DROP: /* ( a -- ) */
pbuf = popMain();
2022-08-08 11:07:24 +03:00
break;
case INS_DUP: /* ( a -- a a ) */
if(ram.msp < 1)
trapout(STACK_UNDERFLOW);
pushMain(ram.main_stack[ram.msp-1]);
2022-08-08 11:07:24 +03:00
break;
case INS_SWAP: /* ( a b -- b a ) */
if(ram.msp < 2)
trapout(STACK_UNDERFLOW);
pbuf = ram.main_stack[ram.msp-2];
ram.main_stack[ram.msp-2] = ram.main_stack[ram.msp-1];
ram.main_stack[ram.msp-1] = pbuf;
2022-08-08 11:07:24 +03:00
break;
case INS_ROT: /* ( a b c -- b c a ) */
if(ram.msp < 3)
trapout(STACK_UNDERFLOW);
pbuf = ram.main_stack[ram.msp-3];
pbuf2 = ram.main_stack[ram.msp-1];
ram.main_stack[ram.msp-3] = ram.main_stack[ram.msp-2];
ram.main_stack[ram.msp-2] = pbuf2;
ram.main_stack[ram.msp-1] = pbuf;
2022-08-08 11:07:24 +03:00
break;
case INS_OVER: /* ( a b -- a b a ) */
if(ram.msp < 2)
trapout(STACK_UNDERFLOW);
pushMain(ram.main_stack[ram.msp-2]);
2022-08-08 11:07:24 +03:00
break;
case INS_JUMP: /* unconditional signed jump: ( rel -- ) */
ram.pc = (ushort) (ram.pc + (signed short) popMain());
2022-08-08 11:07:24 +03:00
break;
case INS_IF: /* conditional signed jump if cond is not zero: ( cond rel -- ) */
pbuf = popMain(); /* reladdr */
pbuf2 = popMain(); /* cond */
if(pbuf2 != 0)
ram.pc = (ushort) (ram.pc + (signed short) pbuf);
2022-08-08 11:07:24 +03:00
break;
case INS_EXPOINT: /* Locate execution point */
pushMain(ram.pc + 1);
break;
case INS_GT: /* ( a b -- a>b ) */
pushMain((popMain() < popMain()) ? 1u : 0u);
2022-08-08 11:07:24 +03:00
break;
case INS_LT: /* ( a b -- a<b ) */
pushMain((popMain() > popMain()) ? 1u : 0u);
2022-08-08 11:07:24 +03:00
break;
case INS_EQ: /* ( a b -- a==b ) */
pushMain((popMain() == popMain()) ? 1u : 0u);
2022-08-08 11:07:24 +03:00
break;
case INS_ADD: /* ( a b -- a+b ) */
pushMain((popMain() + popMain())&65535U);
2022-08-08 11:07:24 +03:00
break;
case INS_SUB: /* ( a b -- a-b ) */
pushMain((-popMain() + popMain())&65535U);
2022-08-08 11:07:24 +03:00
break;
case INS_MUL: /* ( a b -- a*b ) */
pushMain((ushort)(popMain() * popMain())&65535U);
2022-08-08 11:07:24 +03:00
break;
case INS_DIV: /* ( a b -- a/b rem ) */
pbuf2 = popMain();
pbuf = popMain();
pushMain((ushort) pbuf/pbuf2);
pushMain((ushort) pbuf%pbuf2);
2022-08-08 11:07:24 +03:00
break;
case INS_NEG: /* ( a -- -a ) */
pushMain((ushort)-popMain());
2022-08-08 11:07:24 +03:00
break;
case INS_SHIFT: /* ( a XY -- [a >> X] << Y ) */
pbuf = popMain();
pushMain((ushort)(popMain() >> (pbuf&15U)) << (pbuf>>4U));
2022-08-08 11:07:24 +03:00
break;
case INS_NOT: /* ( a -- ~a ) */
pushMain((ushort)(~popMain()&65535U));
2022-08-08 11:07:24 +03:00
break;
case INS_AND: /* ( a b -- a&b ) */
pushMain(popMain() & popMain());
2022-08-08 11:07:24 +03:00
break;
case INS_OR: /* ( a b -- a|b ) */
pushMain(popMain() | popMain());
2022-08-08 11:07:24 +03:00
break;
case INS_XOR: /* ( a b -- a^b ) */
pushMain(popMain() ^ popMain());
2022-08-08 11:07:24 +03:00
break;
case INS_COUT: /* output a character, no Unicode support for now */
cputc((uchar)(popMain()&255U));
2022-08-08 11:07:24 +03:00
break;
case INS_NHOUT: /* output the hex number from the stack top */
printf("%04X", popMain());
2022-08-08 11:07:24 +03:00
break;
case INS_NBKIN: /* non-blocking key input - in this implementation it's equal to: */
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());
2022-08-08 11:07:24 +03:00
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);
break;
case INS_PERSIST_READ: /* ( adh adl len maddr -- status) */
pushMain(persistOp(popMain(), popMain(), popMain(), popMain(), 0));
break;
case INS_PERSIST_WRITE: /* ( adh adl len maddr -- status) */
pushMain(persistOp(popMain(), popMain(), popMain(), popMain(), 1));
2022-08-08 11:07:24 +03:00
break;
default: /* all characters not processed before are invalid instructions */
trapout(INVALID_INSTRUCTION);
2022-08-07 22:20:48 +03:00
goto brx;
}
if(ram.msp >= STACK_SIZE_WORDS || ram.rsp >= STACK_SIZE_WORDS) /* check for stack overflow after any operation */
trapout(STACK_OVERFLOW);
2022-08-07 22:20:48 +03:00
continue;
brx: break;
}
/* unset interpretation mode flag and exit */
ram.IM = 0;
ram.pc = ram.ibp = 65535U;
/* clear all stacks and CLT */
ram.msp = ram.rsp = ram.lsp = ram.cltp = 0;
2022-08-07 22:20:48 +03:00
}
/* Equi VM entry point */
2022-08-06 00:08:17 +03:00
int main(int argc, char* argv[]) {
2022-08-07 22:20:48 +03:00
/* _attempt_ to disable buffering for char input/output */
2022-08-08 06:48:46 +03:00
#if !defined __CC65__ && !defined __TINYC__
2022-08-07 22:20:48 +03:00
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
#endif
uchar instr;
2022-08-06 09:34:32 +03:00
/* 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;
2022-08-06 09:34:32 +03:00
ram.cmd_size = CMD_BUF_SIZE;
2022-08-07 22:20:48 +03:00
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) */
2022-08-09 07:47:50 +03:00
ram.pc = ram.ibp = 65535U;
2022-08-06 00:08:17 +03:00
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",
(unsigned int) ((uchar *)&ram.clt - (uchar *)&ram.main_stack),
(unsigned int) ((uchar *)&ram.gpd - (uchar *)&ram.clt),
ram.gpd_start,
ram.cmd_start - ram.gpd_start,
ram.cmd_start, ram.cmd_size);
cputc('>');
2022-08-07 22:20:48 +03:00
cputc(' ');
2022-08-06 00:08:17 +03:00
2022-08-07 22:20:48 +03:00
while(1) { /* Now, we're in the command mode loop */
instr = ram.cmdbuf[++ram.ibp] = cgetc(); /* Fetch the next instruction from the keyboard */
2022-08-10 17:53:10 +03:00
if(instr == 0xFFU || instr == 0U) /* exit */
break;
else if(instr == BS && ram.ibp > ram.cmd_start) { /* process the backspace */
2022-08-07 22:20:48 +03:00
#ifdef __CC65__
cputc(instr); /* echo it */
#endif
--ram.ibp;
2022-08-08 11:07:24 +03:00
} else if(instr == INS_IISTART) { /* process II just to avoid quitting in command mode */
2022-08-07 22:20:48 +03:00
#ifdef __CC65__
cputc(instr); /* echo it */
#endif
ram.II = 1;
2022-08-08 11:07:24 +03:00
} else if(instr == INS_IIEND) { /* process II just to avoid quitting in command mode */
2022-08-07 22:20:48 +03:00
#ifdef __CC65__
cputc(instr); /* echo it */
#endif
ram.II = 0;
} else if(instr == CR || instr == LF) { /* process carriage return or linefeed */
cputc(CR); /* echo it */
cputc(LF); /* echo it */
ram.cmdbuf[ram.ibp] = 0; /* replace itself with 0 */
2022-08-07 22:20:48 +03:00
ram.IM = 1; /* set the mandatory interpretation mode flag */
equi_main_loop(); /* and run the interpreter loop */
cputc(CR); /* echo it */
cputc(LF); /* echo it */
2022-08-07 22:20:48 +03:00
cputc('>');
cputc(' ');
}
#ifdef __CC65__
else cputc(instr); /* echo it */
#endif
} /* command mode loop end */
2022-08-06 00:08:17 +03:00
return 0;
}