mirror of
https://git.sr.ht/~crc_/retroforth
synced 2024-11-16 19:48:56 +01:00
retro-extend: output format cleanups
FossilOrigin-Name: e620aaa2cdb559c9413983a02c93a0221336f7624de5bf4b73b18595481de94d
This commit is contained in:
parent
cd1b64729a
commit
165ca5119b
4 changed files with 15 additions and 266 deletions
2
Makefile
2
Makefile
|
@ -114,7 +114,7 @@ bin/retro-ri: io ioforth bin/retro-embedimage bin/retro-extend interfaces/image.
|
|||
./bin/retro-extend ri.image interfaces/ri.forth
|
||||
./bin/retro-embedimage ri.image >interfaces/ri_image.c
|
||||
rm ri.image
|
||||
cd interfaces && $(CC) $(CFLAGS) $(LDFLAGS) -o ../bin/retro-ri $(LIBCURSES) $(LIBM) ri.c io/filesystem.o io/floatingpoint.o io/gopher.o io/unix.o
|
||||
cd interfaces && $(CC) $(CFLAGS) $(LDFLAGS) -o ../bin/retro-ri $(LIBCURSES) $(LIBM) ri.c image-functions.c io/filesystem.o io/floatingpoint.o io/gopher.o io/unix.o
|
||||
|
||||
bin/retro: io ioforth bin/retro-embedimage bin/retro-extend interfaces/image.c interfaces/rre.c interfaces/rre.forth
|
||||
cp ngaImage rre.image
|
||||
|
|
|
@ -19,42 +19,11 @@
|
|||
#include <math.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
First, a few constants relating to the image format and
|
||||
memory layout. If you modify the kernel (Rx.md), these will
|
||||
need to be altered to match your memory layout.
|
||||
---------------------------------------------------------- */
|
||||
|
||||
#define TIB 1025
|
||||
#define D_OFFSET_LINK 0
|
||||
#define D_OFFSET_XT 1
|
||||
#define D_OFFSET_CLASS 2
|
||||
#define D_OFFSET_NAME 3
|
||||
|
||||
#include "image-functions.h"
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
Next we get into some things that relate to the Nga virtual
|
||||
machine that RETRO runs on.
|
||||
---------------------------------------------------------- */
|
||||
|
||||
#define CELL int32_t /* Cell size (32 bit, signed integer */
|
||||
#define IMAGE_SIZE 524288 * 8 /* Amount of RAM. 4MiB by default. */
|
||||
#define STACK_DEPTH 4096 /* Depth of data stack */
|
||||
#define ADDRESSES STACK_DEPTH * 3 /* Depth of address stack */
|
||||
|
||||
extern CELL sp, rp, ip; /* Data, address, instruction pointers */
|
||||
extern CELL data[STACK_DEPTH]; /* The data stack */
|
||||
extern CELL address[ADDRESSES]; /* The address stack */
|
||||
extern CELL memory[IMAGE_SIZE + 1]; /* The memory for the image */
|
||||
|
||||
#define TOS data[sp] /* Shortcut for top item on stack */
|
||||
#define NOS data[sp-1] /* Shortcut for second item on stack */
|
||||
#define TORS address[rp] /* Shortcut for top item on address stack */
|
||||
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
Moving forward, a few variables. These are updated to point
|
||||
to the latest values in the image.
|
||||
A few variables. These are updated to point to the latest
|
||||
corresponding values in the image.
|
||||
---------------------------------------------------------- */
|
||||
|
||||
CELL Dictionary;
|
||||
|
@ -62,27 +31,6 @@ CELL NotFound;
|
|||
CELL interpret;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
Function prototypes.
|
||||
---------------------------------------------------------- */
|
||||
|
||||
CELL stack_pop();
|
||||
void stack_push(CELL value);
|
||||
CELL string_inject(char *str, CELL buffer);
|
||||
char *string_extract(CELL at);
|
||||
CELL d_link(CELL dt);
|
||||
CELL d_xt(CELL dt);
|
||||
CELL d_class(CELL dt);
|
||||
CELL d_name(CELL dt);
|
||||
CELL d_lookup(CELL Dictionary, char *name);
|
||||
CELL d_xt_for(char *Name, CELL Dictionary);
|
||||
void update_rx();
|
||||
void execute(CELL cell);
|
||||
void ngaProcessOpcode(CELL opcode);
|
||||
void ngaProcessPackedOpcodes(CELL opcode);
|
||||
int ngaValidatePackedOpcodes(CELL opcode);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
Now to the fun stuff: interfacing with the virtual machine.
|
||||
There are a things I like to have here:
|
||||
|
|
206
interfaces/ri.c
206
interfaces/ri.c
|
@ -44,29 +44,7 @@
|
|||
#include <string.h>
|
||||
#include <ncurses.h>
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
First, a few constants relating to the image format and memory
|
||||
layout. If you modify the kernel (Rx.md), these will need to be
|
||||
altered to match your memory layout.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
#define TIB 1025
|
||||
#define D_OFFSET_LINK 0
|
||||
#define D_OFFSET_XT 1
|
||||
#define D_OFFSET_CLASS 2
|
||||
#define D_OFFSET_NAME 3
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Next we get into some things that relate to the Nga virtual machine
|
||||
that RETRO runs on.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
#define CELL int32_t /* Cell size (32 bit, signed integer */
|
||||
#define IMAGE_SIZE 524288 /* Amount of RAM. 512k cells */
|
||||
#define ADDRESSES 1024 /* Depth of address stack */
|
||||
#define STACK_DEPTH 128 /* Depth of data stack */
|
||||
#include "image-functions.h"
|
||||
|
||||
CELL sp, rp, ip; /* Data, address, instruction pointers */
|
||||
CELL data[STACK_DEPTH]; /* The data stack */
|
||||
|
@ -85,10 +63,6 @@ RetroInstance Instances[5];
|
|||
|
||||
int ActiveInstance;
|
||||
|
||||
#define TOS data[sp] /* Shortcut for top item on stack */
|
||||
#define NOS data[sp-1] /* Shortcut for second item on stack */
|
||||
#define TORS address[rp] /* Shortcut for top item on address stack */
|
||||
|
||||
|
||||
void generic_output();
|
||||
void generic_output_query();
|
||||
|
@ -155,54 +129,10 @@ WINDOW *output, *input, *stack, *back;
|
|||
/*---------------------------------------------------------------------
|
||||
Function prototypes.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
CELL stack_pop();
|
||||
void stack_push(CELL value);
|
||||
CELL string_inject(char *str, CELL buffer);
|
||||
char *string_extract(CELL at);
|
||||
CELL d_link(CELL dt);
|
||||
CELL d_xt(CELL dt);
|
||||
CELL d_class(CELL dt);
|
||||
CELL d_name(CELL dt);
|
||||
CELL d_lookup(CELL Dictionary, char *name);
|
||||
CELL d_xt_for(char *Name, CELL Dictionary);
|
||||
void update_rx();
|
||||
void execute(CELL cell);
|
||||
void evaluate(char *s);
|
||||
CELL ngaLoadImage(char *imageFile);
|
||||
void ngaPrepare();
|
||||
void ngaProcessOpcode(CELL opcode);
|
||||
void ngaProcessPackedOpcodes(CELL opcode);
|
||||
int ngaValidatePackedOpcodes(CELL opcode);
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Now to the fun stuff: interfacing with the virtual machine. There are
|
||||
a things I like to have here:
|
||||
|
||||
- push a value to the stack
|
||||
- pop a value off the stack
|
||||
- extract a string from the image
|
||||
- inject a string into the image.
|
||||
- lookup dictionary headers and access dictionary fields
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Stack push/pop is easy. I could avoid these, but it aids in keeping
|
||||
the code readable, so it's worth the slight overhead.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
CELL stack_pop() {
|
||||
sp--;
|
||||
return data[sp + 1];
|
||||
}
|
||||
|
||||
void stack_push(CELL value) {
|
||||
sp++;
|
||||
data[sp] = value;
|
||||
}
|
||||
|
||||
char *output_cache(int n) {
|
||||
switch(n) {
|
||||
case 0: return "/tmp/ri.output1"; break;
|
||||
|
@ -252,129 +182,6 @@ void swap_image(int to) {
|
|||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Strings are next. RETRO uses C-style NULL terminated strings. So I
|
||||
can easily inject or extract a string. Injection iterates over the
|
||||
string, copying it into the image. This also takes care to ensure
|
||||
that the NULL terminator is added.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
CELL string_inject(char *str, CELL buffer) {
|
||||
CELL i = 0;
|
||||
while (*str) {
|
||||
memory[buffer + i] = (CELL)*str++;
|
||||
memory[buffer + i + 1] = 0;
|
||||
i++;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Extracting a string is similar, but I have to iterate over the VM
|
||||
memory instead of a C string and copy the charaters into a buffer.
|
||||
This uses a static buffer (`string_data`) as I prefer to avoid using
|
||||
`malloc()`.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
char string_data[1025];
|
||||
char *string_extract(CELL at) {
|
||||
CELL starting = at;
|
||||
CELL i = 0;
|
||||
while(memory[starting] && i < 1024)
|
||||
string_data[i++] = (char)memory[starting++];
|
||||
string_data[i] = 0;
|
||||
return (char *)string_data;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Continuing along, I now define functions to access the dictionary.
|
||||
|
||||
RETRO's dictionary is a linked list. Each entry is setup like:
|
||||
|
||||
0000 Link to previous entry (NULL if this is the root entry)
|
||||
0001 Pointer to definition start
|
||||
0002 Pointer to class handler
|
||||
0003 Start of a NULL terminated string with the word name
|
||||
|
||||
First, functions to access each field. The offsets were defineed at
|
||||
the start of the file.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
CELL d_link(CELL dt) {
|
||||
return dt + D_OFFSET_LINK;
|
||||
}
|
||||
|
||||
CELL d_xt(CELL dt) {
|
||||
return dt + D_OFFSET_XT;
|
||||
}
|
||||
|
||||
CELL d_class(CELL dt) {
|
||||
return dt + D_OFFSET_CLASS;
|
||||
}
|
||||
|
||||
CELL d_name(CELL dt) {
|
||||
return dt + D_OFFSET_NAME;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Next, a more complext word. This will walk through the entries to
|
||||
find one with a name that matches the specified name. This is *slow*,
|
||||
but works ok unless you have a really large dictionary. (I've not
|
||||
run into issues with this in practice).
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
CELL d_lookup(CELL Dictionary, char *name) {
|
||||
CELL dt = 0;
|
||||
CELL i = Dictionary;
|
||||
char *dname;
|
||||
while (memory[i] != 0 && i != 0) {
|
||||
dname = string_extract(d_name(i));
|
||||
if (strcmp(dname, name) == 0) {
|
||||
dt = i;
|
||||
i = 0;
|
||||
} else {
|
||||
i = memory[i];
|
||||
}
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
My last dictionary related word returns the `xt` pointer for a word.
|
||||
This is used to help keep various important bits up to date.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
CELL d_xt_for(char *Name, CELL Dictionary) {
|
||||
return memory[d_xt(d_lookup(Dictionary, Name))];
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
This interface tracks a few words and variables in the image. These
|
||||
are:
|
||||
|
||||
Dictionary - the latest dictionary header
|
||||
NotFound - called when a word is not found
|
||||
Interpret - the heart of the interpreter/compiler
|
||||
Compiler - the compiler state
|
||||
|
||||
I have to call this periodically, as the Dictionary will change as
|
||||
new words are defined, and the user might write a new error handler
|
||||
or interpreter.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
void update_rx() {
|
||||
Dictionary = memory[2];
|
||||
Compiler = d_xt_for("Compiler", Dictionary);
|
||||
NotFound = d_xt_for("err:notfound", Dictionary);
|
||||
Interpret = d_xt_for("interpret", Dictionary);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
With these out of the way, I implement `execute`, which takes an
|
||||
address and runs the code at it. This has a couple of interesting
|
||||
|
@ -397,7 +204,7 @@ void generic_output_query() {
|
|||
stack_push(0);
|
||||
}
|
||||
|
||||
void execute(CELL cell) {
|
||||
void ri_execute(CELL cell) {
|
||||
CELL opcode;
|
||||
rp = 1;
|
||||
ip = cell;
|
||||
|
@ -428,12 +235,12 @@ void execute(CELL cell) {
|
|||
calls `interpret` to process it.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
void evaluate(char *s) {
|
||||
void ri_evaluate(char *s) {
|
||||
if (strlen(s) == 0) return;
|
||||
update_rx();
|
||||
string_inject(s, TIB);
|
||||
stack_push(TIB);
|
||||
execute(Interpret);
|
||||
ri_execute(Interpret);
|
||||
}
|
||||
|
||||
|
||||
|
@ -473,9 +280,6 @@ void setup_interface() {
|
|||
cbreak();
|
||||
|
||||
back = newwin(LINES - 1, COLS, 0, 0);
|
||||
// output = newwin(LINES - 1, COLS, 0, 0);
|
||||
// input = newwin(1, COLS / 2, LINES - 1, 0);
|
||||
// stack = newwin(1, COLS / 2, LINES - 1, COLS / 2);
|
||||
output = newwin(LINES - 2, COLS, 0, 0);
|
||||
input = newwin(1, COLS, LINES - 1, 0);
|
||||
stack = newwin(1, COLS, LINES - 2, 0);
|
||||
|
@ -609,7 +413,7 @@ int main() {
|
|||
dump_stack();
|
||||
wrefresh(stack);
|
||||
}
|
||||
evaluate(c);
|
||||
ri_evaluate(c);
|
||||
n = 0;
|
||||
c[0] = '\0';
|
||||
update_rx();
|
||||
|
|
|
@ -136,12 +136,6 @@ int include_file(char *fname) {
|
|||
return tokens;
|
||||
}
|
||||
|
||||
void stats() {
|
||||
update_rx();
|
||||
printf("-> Image Size: %d\n", Heap);
|
||||
printf("MAX SP: %d, RP: %d\n", max_sp, max_rsp);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int tokens;
|
||||
FILE *fp;
|
||||
|
@ -151,12 +145,15 @@ int main(int argc, char **argv) {
|
|||
max_sp = 0;
|
||||
max_rsp = 0;
|
||||
ngaLoadImage(argv[1]);
|
||||
stats();
|
||||
update_rx();
|
||||
printf("Initial Image Size: %d\n", Heap);
|
||||
dump_stack();
|
||||
printf("-> Process code from %s\n", argv[2]);
|
||||
printf(" Process code from %s\n", argv[2]);
|
||||
tokens = include_file(argv[2]);
|
||||
printf(" %d tokens\n", tokens);
|
||||
stats();
|
||||
update_rx();
|
||||
printf("New Image Size: %d\n", Heap);
|
||||
printf("MAX SP: %d, RP: %d\n", max_sp, max_rsp);
|
||||
if ((fp = fopen(argv[1], "wb")) == NULL) {
|
||||
printf("Unable to save the ngaImage!\n");
|
||||
exit(2);
|
||||
|
|
Loading…
Reference in a new issue