1 /* RETRO ------------------------------------------------------
2   A personal, minimalistic forth
3   Copyright (c) 2016 - 2020 Charles Childers
4 
5   This is a minimalist implementation of an interactive
6   RETRO system with an embedded image and the listerner loop
7   being written in RETRO.
8 
9   Building:
10 
11     cp ngaImage barebones.image
12     retro-extend barebones.image interface/barebones.retro
13     retro-embedimage barebones.image >vm/nga-c/barebones_image.c
14     cd vm/nga-c
15     make barebones
16   ---------------------------------------------------------- */
17 
18 #include <stdio.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <limits.h>
22 
23 #define CELL int32_t
24 #define CELL_MIN INT_MIN + 1
25 #define CELL_MAX INT_MAX - 1
26 
27 #define IMAGE_SIZE   242000       /* Amount of RAM. 968kB by default.  */
28 #define ADDRESSES    256          /* Depth of address stack            */
29 #define STACK_DEPTH  128          /* Depth of data stack               */
30 
31 CELL memory[IMAGE_SIZE + 1];      /* The memory for the image          */
32 
33 #define TOS  cpu.data[cpu.sp]     /* Shortcut for top item on stack    */
34 #define NOS  cpu.data[cpu.sp-1]   /* Shortcut for second item on stack */
35 #define TORS cpu.address[cpu.rp]  /* Shortcut for top item on address stack */
36 
37 struct NgaCore {
38   CELL sp, rp, ip;                /* Stack & instruction pointers      */
39   CELL data[STACK_DEPTH];         /* The data stack                    */
40   CELL address[ADDRESSES];        /* The address stack                 */
41 } cpu;
42 
43 #define NUM_DEVICES  2
44 
45 typedef void (*Handler)(void);
46 
47 Handler IO_deviceHandlers[NUM_DEVICES + 1];
48 Handler IO_queryHandlers[NUM_DEVICES + 1];
49 
50 #include "barebones_image.c"
51 
52 CELL stack_pop();
53 void stack_push(CELL value);
54 void execute(CELL cell);
55 CELL load_image();
56 void prepare_vm();
57 void process_opcode(CELL opcode);
58 void process_opcode_bundle(CELL opcode);
59 int validate_opcode_bundle(CELL opcode);
60 
stack_pop()61 CELL stack_pop() {
62   cpu.sp--;
63   return cpu.data[cpu.sp + 1];
64 }
65 
stack_push(CELL value)66 void stack_push(CELL value) {
67   cpu.sp++;
68   cpu.data[cpu.sp] = value;
69 }
70 
generic_output()71 void generic_output() {
72   putc(stack_pop(), stdout);
73   fflush(stdout);
74 }
75 
generic_output_query()76 void generic_output_query() {
77   stack_push(0);
78   stack_push(0);
79 }
80 
generic_input()81 void generic_input() {
82   stack_push(getc(stdin));
83   if (TOS == 127) TOS = 8;
84 }
85 
generic_input_query()86 void generic_input_query() {
87   stack_push(0);
88   stack_push(1);
89 }
90 
execute(CELL cell)91 void execute(CELL cell) {
92   CELL opcode;
93   cpu.rp = 1;
94   cpu.ip = cell;
95   while (cpu.ip < IMAGE_SIZE) {
96     opcode = memory[cpu.ip];
97     if (validate_opcode_bundle(opcode) != 0) {
98       process_opcode_bundle(opcode);
99     } else {
100       printf("Invalid instruction!\n");
101       exit(1);
102     }
103     cpu.ip++;
104     if (cpu.rp == 0)
105       cpu.ip = IMAGE_SIZE;
106   }
107 }
108 
main(int argc,char ** argv)109 int main(int argc, char **argv) {
110   IO_deviceHandlers[0] = generic_output;
111   IO_deviceHandlers[1] = generic_input;
112   IO_queryHandlers[0] = generic_output_query;
113   IO_queryHandlers[1] = generic_input_query;
114   prepare_vm();
115   load_image();
116   execute(0);
117   exit(0);
118 }
119 
120 #include "nga.c"
121