retro-extend: output format cleanups

FossilOrigin-Name: e620aaa2cdb559c9413983a02c93a0221336f7624de5bf4b73b18595481de94d
This commit is contained in:
crc 2019-01-15 18:39:58 +00:00
parent cd1b64729a
commit 165ca5119b
4 changed files with 15 additions and 266 deletions

View file

@ -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

View file

@ -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:

View file

@ -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();

View file

@ -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);