db5a0365c1
FossilOrigin-Name: 2bfc22912d317df529dc6210f76599b995451204999236e31ba4665da9ad3827
491 lines
9.8 KiB
C
491 lines
9.8 KiB
C
/* RETRO -------------------------------------------------------------
|
|
A personal, minimalistic forth
|
|
Copyright (c) 2016 - 2019 Charles Childers
|
|
---------------------------------------------------------------------*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "image-functions.h"
|
|
|
|
CELL sp, rp, ip; /* Data, address, instruction pointers */
|
|
CELL data[STACK_DEPTH]; /* The data stack */
|
|
CELL address[ADDRESSES]; /* The address stack */
|
|
CELL memory[IMAGE_SIZE + 1]; /* The memory for the image */
|
|
|
|
void generic_output();
|
|
void generic_output_query();
|
|
void io_keyboard_handler();
|
|
void io_keyboard_query();
|
|
void io_filesystem_query();
|
|
void io_filesystem_handler();
|
|
void io_unix_query();
|
|
void io_unix_handler();
|
|
void io_floatingpoint_query();
|
|
void io_floatingpoint_handler();
|
|
void io_gopher_query();
|
|
void io_gopher_handler();
|
|
void io_scripting_handler();
|
|
void io_scripting_query();
|
|
void io_image();
|
|
void io_image_query();
|
|
|
|
#define NUM_DEVICES 7
|
|
|
|
typedef void (*Handler)(void);
|
|
|
|
Handler IO_deviceHandlers[NUM_DEVICES + 1] = {
|
|
generic_output,
|
|
io_keyboard_handler,
|
|
io_filesystem_handler,
|
|
io_floatingpoint_handler,
|
|
io_unix_handler,
|
|
io_gopher_handler,
|
|
io_image
|
|
};
|
|
|
|
Handler IO_queryHandlers[NUM_DEVICES + 1] = {
|
|
generic_output_query,
|
|
io_keyboard_query,
|
|
io_filesystem_query,
|
|
io_floatingpoint_query,
|
|
io_unix_query,
|
|
io_gopher_query,
|
|
io_image_query
|
|
};
|
|
|
|
|
|
|
|
void loadEmbeddedImage(char *arg);
|
|
void ngaPrepare();
|
|
|
|
void generic_output() {
|
|
putc(stack_pop(), stdout);
|
|
fflush(stdout);
|
|
}
|
|
|
|
void generic_output_query() {
|
|
stack_push(0);
|
|
stack_push(0);
|
|
}
|
|
|
|
void io_keyboard_handler() {
|
|
stack_push(getc(stdin));
|
|
if (TOS == 127) TOS = 8;
|
|
}
|
|
|
|
void io_keyboard_query() {
|
|
stack_push(0);
|
|
stack_push(1);
|
|
}
|
|
|
|
|
|
void io_image() {
|
|
FILE *fp;
|
|
char *f = string_extract(stack_pop());
|
|
if ((fp = fopen(f, "wb")) == NULL) {
|
|
printf("Unable to save the image: %s!\n", f);
|
|
exit(2);
|
|
}
|
|
fwrite(&memory, sizeof(CELL), memory[3] + 1, fp);
|
|
fclose(fp);
|
|
}
|
|
|
|
void io_image_query() {
|
|
stack_push(0);
|
|
stack_push(1000);
|
|
}
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
ngaPrepare();
|
|
loadEmbeddedImage(argv[0]);
|
|
update_rx();
|
|
execute(0);
|
|
exit(0);
|
|
}
|
|
|
|
|
|
/* Nga ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
Copyright (c) 2008 - 2018, Charles Childers
|
|
Copyright (c) 2009 - 2010, Luke Parrish
|
|
Copyright (c) 2010, Marc Simpson
|
|
Copyright (c) 2010, Jay Skeer
|
|
Copyright (c) 2011, Kenneth Keating
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
enum vm_opcode {
|
|
VM_NOP, VM_LIT, VM_DUP, VM_DROP, VM_SWAP, VM_PUSH, VM_POP,
|
|
VM_JUMP, VM_CALL, VM_CCALL, VM_RETURN, VM_EQ, VM_NEQ, VM_LT,
|
|
VM_GT, VM_FETCH, VM_STORE, VM_ADD, VM_SUB, VM_MUL, VM_DIVMOD,
|
|
VM_AND, VM_OR, VM_XOR, VM_SHIFT, VM_ZRET, VM_END, VM_IE,
|
|
VM_IQ, VM_II
|
|
};
|
|
#define NUM_OPS VM_II + 1
|
|
|
|
#ifndef NUM_DEVICES
|
|
#define NUM_DEVICES 0
|
|
#endif
|
|
|
|
void ngaPrepare() {
|
|
ip = sp = rp = 0;
|
|
for (ip = 0; ip < IMAGE_SIZE; ip++)
|
|
memory[ip] = VM_NOP;
|
|
for (ip = 0; ip < STACK_DEPTH; ip++)
|
|
data[ip] = 0;
|
|
for (ip = 0; ip < ADDRESSES; ip++)
|
|
address[ip] = 0;
|
|
}
|
|
|
|
void inst_nop() {
|
|
}
|
|
|
|
void inst_lit() {
|
|
sp++;
|
|
ip++;
|
|
TOS = memory[ip];
|
|
}
|
|
|
|
void inst_dup() {
|
|
sp++;
|
|
data[sp] = NOS;
|
|
}
|
|
|
|
void inst_drop() {
|
|
data[sp] = 0;
|
|
if (--sp < 0)
|
|
ip = IMAGE_SIZE;
|
|
}
|
|
|
|
void inst_swap() {
|
|
CELL a;
|
|
a = TOS;
|
|
TOS = NOS;
|
|
NOS = a;
|
|
}
|
|
|
|
void inst_push() {
|
|
rp++;
|
|
TORS = TOS;
|
|
inst_drop();
|
|
}
|
|
|
|
void inst_pop() {
|
|
sp++;
|
|
TOS = TORS;
|
|
rp--;
|
|
}
|
|
|
|
void inst_jump() {
|
|
ip = TOS - 1;
|
|
inst_drop();
|
|
}
|
|
|
|
void inst_call() {
|
|
rp++;
|
|
TORS = ip;
|
|
ip = TOS - 1;
|
|
inst_drop();
|
|
}
|
|
|
|
void inst_ccall() {
|
|
CELL a, b;
|
|
a = TOS; inst_drop(); /* False */
|
|
b = TOS; inst_drop(); /* Flag */
|
|
if (b != 0) {
|
|
rp++;
|
|
TORS = ip;
|
|
ip = a - 1;
|
|
}
|
|
}
|
|
|
|
void inst_return() {
|
|
ip = TORS;
|
|
rp--;
|
|
}
|
|
|
|
void inst_eq() {
|
|
NOS = (NOS == TOS) ? -1 : 0;
|
|
inst_drop();
|
|
}
|
|
|
|
void inst_neq() {
|
|
NOS = (NOS != TOS) ? -1 : 0;
|
|
inst_drop();
|
|
}
|
|
|
|
void inst_lt() {
|
|
NOS = (NOS < TOS) ? -1 : 0;
|
|
inst_drop();
|
|
}
|
|
|
|
void inst_gt() {
|
|
NOS = (NOS > TOS) ? -1 : 0;
|
|
inst_drop();
|
|
}
|
|
|
|
void inst_fetch() {
|
|
switch (TOS) {
|
|
case -1: TOS = sp - 1; break;
|
|
case -2: TOS = rp; break;
|
|
case -3: TOS = IMAGE_SIZE; break;
|
|
default: TOS = memory[TOS]; break;
|
|
}
|
|
}
|
|
|
|
void inst_store() {
|
|
if (TOS <= IMAGE_SIZE && TOS >= 0) {
|
|
memory[TOS] = NOS;
|
|
inst_drop();
|
|
inst_drop();
|
|
} else {
|
|
ip = IMAGE_SIZE;
|
|
}
|
|
}
|
|
|
|
void inst_add() {
|
|
NOS += TOS;
|
|
inst_drop();
|
|
}
|
|
|
|
void inst_sub() {
|
|
NOS -= TOS;
|
|
inst_drop();
|
|
}
|
|
|
|
void inst_mul() {
|
|
NOS *= TOS;
|
|
inst_drop();
|
|
}
|
|
|
|
void inst_divmod() {
|
|
CELL a, b;
|
|
a = TOS;
|
|
b = NOS;
|
|
TOS = b / a;
|
|
NOS = b % a;
|
|
}
|
|
|
|
void inst_and() {
|
|
NOS = TOS & NOS;
|
|
inst_drop();
|
|
}
|
|
|
|
void inst_or() {
|
|
NOS = TOS | NOS;
|
|
inst_drop();
|
|
}
|
|
|
|
void inst_xor() {
|
|
NOS = TOS ^ NOS;
|
|
inst_drop();
|
|
}
|
|
|
|
void inst_shift() {
|
|
CELL y = TOS;
|
|
CELL x = NOS;
|
|
if (TOS < 0)
|
|
NOS = NOS << (TOS * -1);
|
|
else {
|
|
if (x < 0 && y > 0)
|
|
NOS = x >> y | ~(~0U >> y);
|
|
else
|
|
NOS = x >> y;
|
|
}
|
|
inst_drop();
|
|
}
|
|
|
|
void inst_zret() {
|
|
if (TOS == 0) {
|
|
inst_drop();
|
|
ip = TORS;
|
|
rp--;
|
|
}
|
|
}
|
|
|
|
void inst_end() {
|
|
ip = IMAGE_SIZE;
|
|
}
|
|
|
|
void inst_ie() {
|
|
sp++;
|
|
TOS = NUM_DEVICES;
|
|
}
|
|
|
|
void inst_iq() {
|
|
CELL Device = TOS;
|
|
inst_drop();
|
|
IO_queryHandlers[Device]();
|
|
}
|
|
|
|
void inst_ii() {
|
|
CELL Device = TOS;
|
|
inst_drop();
|
|
IO_deviceHandlers[Device]();
|
|
}
|
|
|
|
Handler instructions[NUM_OPS] = {
|
|
inst_nop, inst_lit, inst_dup, inst_drop, inst_swap, inst_push, inst_pop,
|
|
inst_jump, inst_call, inst_ccall, inst_return, inst_eq, inst_neq, inst_lt,
|
|
inst_gt, inst_fetch, inst_store, inst_add, inst_sub, inst_mul, inst_divmod,
|
|
inst_and, inst_or, inst_xor, inst_shift, inst_zret, inst_end, inst_ie,
|
|
inst_iq, inst_ii
|
|
};
|
|
|
|
void ngaProcessOpcode(CELL opcode) {
|
|
if (opcode != 0)
|
|
instructions[opcode]();
|
|
}
|
|
|
|
int ngaValidatePackedOpcodes(CELL opcode) {
|
|
CELL raw = opcode;
|
|
CELL current;
|
|
int valid = -1;
|
|
int i;
|
|
for (i = 0; i < 4; i++) {
|
|
current = raw & 0xFF;
|
|
if (!(current >= 0 && current <= 29))
|
|
valid = 0;
|
|
raw = raw >> 8;
|
|
}
|
|
return valid;
|
|
}
|
|
|
|
void ngaProcessPackedOpcodes(CELL opcode) {
|
|
CELL raw = opcode;
|
|
int i;
|
|
for (i = 0; i < 4; i++) {
|
|
ngaProcessOpcode(raw & 0xFF);
|
|
raw = raw >> 8;
|
|
}
|
|
}
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
|
|
#pragma pack(push,1)
|
|
#pragma pack(pop)
|
|
|
|
#define EI_NIDENT 16
|
|
|
|
/* 32-bit ELF base types. */
|
|
typedef unsigned int Elf32_Addr;
|
|
typedef unsigned short Elf32_Half;
|
|
typedef unsigned int Elf32_Off;
|
|
typedef signed int Elf32_Sword;
|
|
typedef unsigned int Elf32_Word;
|
|
|
|
/* 64-bit ELF base types. */
|
|
typedef unsigned long long Elf64_Addr;
|
|
typedef unsigned short Elf64_Half;
|
|
typedef signed short Elf64_SHalf;
|
|
typedef unsigned long long Elf64_Off;
|
|
typedef signed int Elf64_Sword;
|
|
typedef unsigned int Elf64_Word;
|
|
typedef unsigned long long Elf64_Xword;
|
|
typedef signed long long Elf64_Sxword;
|
|
|
|
typedef struct elf32_hdr{
|
|
unsigned char e_ident[EI_NIDENT];
|
|
Elf32_Half e_type;
|
|
Elf32_Half e_machine;
|
|
Elf32_Word e_version;
|
|
Elf32_Addr e_entry; /* Entry point */
|
|
Elf32_Off e_phoff;
|
|
Elf32_Off e_shoff;
|
|
Elf32_Word e_flags;
|
|
Elf32_Half e_ehsize;
|
|
Elf32_Half e_phentsize;
|
|
Elf32_Half e_phnum;
|
|
Elf32_Half e_shentsize;
|
|
Elf32_Half e_shnum;
|
|
Elf32_Half e_shstrndx;
|
|
} Elf32_Ehdr;
|
|
|
|
typedef struct elf32_shdr {
|
|
Elf32_Word sh_name;
|
|
Elf32_Word sh_type;
|
|
Elf32_Word sh_flags;
|
|
Elf32_Addr sh_addr;
|
|
Elf32_Off sh_offset;
|
|
Elf32_Word sh_size;
|
|
Elf32_Word sh_link;
|
|
Elf32_Word sh_info;
|
|
Elf32_Word sh_addralign;
|
|
Elf32_Word sh_entsize;
|
|
} Elf32_Shdr;
|
|
|
|
typedef struct elf64_hdr {
|
|
unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
|
|
Elf64_Half e_type;
|
|
Elf64_Half e_machine;
|
|
Elf64_Word e_version;
|
|
Elf64_Addr e_entry; /* Entry point virtual address */
|
|
Elf64_Off e_phoff; /* Program header table file offset */
|
|
Elf64_Off e_shoff; /* Section header table file offset */
|
|
Elf64_Word e_flags;
|
|
Elf64_Half e_ehsize;
|
|
Elf64_Half e_phentsize;
|
|
Elf64_Half e_phnum;
|
|
Elf64_Half e_shentsize;
|
|
Elf64_Half e_shnum;
|
|
Elf64_Half e_shstrndx;
|
|
} Elf64_Ehdr;
|
|
|
|
typedef struct elf64_shdr {
|
|
Elf64_Word sh_name; /* Section name, index in string tbl */
|
|
Elf64_Word sh_type; /* Type of section */
|
|
Elf64_Xword sh_flags; /* Miscellaneous section attributes */
|
|
Elf64_Addr sh_addr; /* Section virtual addr at execution */
|
|
Elf64_Off sh_offset; /* Section file offset */
|
|
Elf64_Xword sh_size; /* Size of section in bytes */
|
|
Elf64_Word sh_link; /* Index of another section */
|
|
Elf64_Word sh_info; /* Additional section information */
|
|
Elf64_Xword sh_addralign; /* Section alignment */
|
|
Elf64_Xword sh_entsize; /* Entry size if section holds table */
|
|
} Elf64_Shdr;
|
|
|
|
|
|
|
|
void loadEmbeddedImage(char *arg) {
|
|
FILE* ElfFile = NULL;
|
|
char* SectNames = NULL;
|
|
Elf64_Ehdr elfHdr;
|
|
Elf64_Shdr sectHdr;
|
|
uint32_t idx;
|
|
|
|
if((ElfFile = fopen(arg, "r")) == NULL) {
|
|
perror("[E] Error opening file:");
|
|
exit(1);
|
|
}
|
|
|
|
fread(&elfHdr, 1, sizeof(Elf64_Ehdr), ElfFile);
|
|
fseek(ElfFile, elfHdr.e_shoff + elfHdr.e_shstrndx * sizeof(sectHdr), SEEK_SET);
|
|
fread(§Hdr, 1, sizeof(sectHdr), ElfFile);
|
|
|
|
SectNames = malloc(sectHdr.sh_size);
|
|
fseek(ElfFile, sectHdr.sh_offset, SEEK_SET);
|
|
fread(SectNames, 1, sectHdr.sh_size, ElfFile);
|
|
|
|
int a;
|
|
|
|
for (idx = 0; idx < elfHdr.e_shnum; idx++)
|
|
{
|
|
const char* name = "";
|
|
|
|
fseek(ElfFile, elfHdr.e_shoff + idx * sizeof(sectHdr), SEEK_SET);
|
|
fread(§Hdr, 1, sizeof(sectHdr), ElfFile);
|
|
name = SectNames + sectHdr.sh_name;
|
|
if (strcmp(name, ".ngaImage") == 0) {
|
|
fseek(ElfFile, sectHdr.sh_offset, SEEK_SET);
|
|
for (int i = 0; i < (int)sectHdr.sh_size; i++) {
|
|
fread(&a, 1, sizeof(int), ElfFile);
|
|
memory[i] = a;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|