| /* tag: forth bootstrap environment |
| * |
| * Copyright (C) 2003-2006 Stefan Reinauer, Patrick Mauritz |
| * |
| * See the file "COPYING" for further information about |
| * the copyright and warranty status of this work. |
| */ |
| |
| #include "openbios/sysinclude.h" |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <signal.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <termios.h> |
| #include <sys/stat.h> |
| |
| #ifdef __GLIBC__ |
| #define _GNU_SOURCE |
| #include <getopt.h> |
| #endif |
| |
| #include "openbios/config.h" |
| #include "openbios/stack.h" |
| #include "openbios/sysinclude.h" |
| #include "openbios/kernel.h" |
| #include "dict.h" |
| #include "cross.h" |
| |
| |
| #define MEMORY_SIZE (1024*1024) /* 1M ram for hosted system */ |
| #define DICTIONARY_SIZE (256*1024) /* 256k for the dictionary */ |
| #define TRAMPOLINE_SIZE (4*sizeof(cell)) /* 4 cells for the trampoline */ |
| |
| /* state variables */ |
| ucell *latest, *state, *base; |
| ucell *memory; |
| ucell *trampoline; |
| |
| /* local variables */ |
| static int errors = 0; |
| static int segfault = 0; |
| int verbose = 0; |
| |
| static FILE *srcfiles[128]; |
| static unsigned int cursrc = 0; |
| |
| #ifdef NATIVE_BITWIDTH_SMALLER_THAN_HOST_BITWIDTH |
| unsigned long base_address; |
| #endif |
| |
| /* include path handling */ |
| typedef struct include_path include; |
| struct include_path { |
| char *path; |
| include *next; |
| }; |
| |
| include includes = { ".", NULL }; |
| |
| static ucell * relocation_address=NULL; |
| static int relocation_length=0; |
| |
| /* the word names are used to generate the prim words in the |
| * dictionary. This is done by the C written interpreter. |
| */ |
| static const char *wordnames[] = { |
| "(semis)", "", "(lit)", "", "", "", "", "(do)", "(?do)", "(loop)", |
| "(+loop)", "", "", "", "dup", "2dup", "?dup", "over", "2over", "pick", "drop", |
| "2drop", "nip", "roll", "rot", "-rot", "swap", "2swap", ">r", "r>", |
| "r@", "depth", "depth!", "rdepth", "rdepth!", "+", "-", "*", "u*", |
| "mu/mod", "abs", "negate", "max", "min", "lshift", "rshift", ">>a", |
| "and", "or", "xor", "invert", "d+", "d-", "m*", "um*", "@", "c@", |
| "w@", "l@", "!", "+!", "c!", "w!", "l!", "=", ">", "<", "u>", "u<", |
| "sp@", "move", "fill", "(emit)", "(key?)", "(key)", "execute", |
| "here", "here!", "dobranch", "do?branch", "unaligned-w@", |
| "unaligned-w!", "unaligned-l@", "unaligned-l!", "ioc@", "iow@", |
| "iol@", "ioc!", "iow!", "iol!", "i", "j", "call", "sys-debug", |
| "$include", "$encode-file" |
| }; |
| |
| static void init_trampoline(void) |
| { |
| if (!trampoline) { |
| /* We're using side effects which is to some extent nasty */ |
| printf("WARNING: no trampoline!\n"); |
| return; |
| } |
| |
| trampoline[0]=DOCOL; |
| trampoline[1]=0; |
| trampoline[2]=target_ucell(pointer2cell(trampoline)+3*sizeof(ucell)); |
| trampoline[3]=0; |
| } |
| |
| /* |
| * dictionary related functions. |
| */ |
| |
| static void relocation_table(unsigned char * dict_one, unsigned char *dict_two, int length) |
| { |
| ucell *d1=(ucell *)dict_one, *d2=(ucell *)dict_two; |
| ucell *reloc_table; |
| int pos, bit; |
| int l=(length+(sizeof(cell)-1))/sizeof(ucell), i; |
| |
| /* prepare relocation table */ |
| relocation_length=(length+BITS-1)/BITS; |
| reloc_table = malloc(relocation_length*sizeof(cell)); |
| memset(reloc_table,0,relocation_length*sizeof(cell)); |
| |
| for (i=0; i<l; i++) { |
| |
| pos=i/BITS; |
| bit=i&~(-BITS); |
| |
| if(d1[i]==d2[i]) { |
| reloc_table[pos] &= target_ucell(~((ucell)1UL<<bit)); |
| |
| // This check might bring false positives in data. |
| //if(d1[i] >= pointer2cell(dict_one) && |
| // d1[i] <= pointer2cell(dict_one+length)) |
| // printk("\nWARNING: inconsistent relocation (%x:%x)!\n", d1[i], d2[i]); |
| } else { |
| /* This is a pointer, it needs relocation, d2==dict */ |
| reloc_table[pos] |= target_ucell((ucell)1UL<<bit); |
| d2[i] = target_ucell(target_ucell(d2[i]) - pointer2cell(d2)); |
| } |
| } |
| |
| #ifdef CONFIG_DEBUG_DICTIONARY |
| printk("dict1 %lx dict2 %lx dict %lx\n",dict_one, dict_two, dict); |
| for (i=0; i< relocation_length ; i++) |
| printk("reloc %d %lx\n",i+1, reloc_table[i]); |
| #endif |
| relocation_address=reloc_table; |
| } |
| |
| static void write_dictionary(char *filename) |
| { |
| FILE *f; |
| unsigned char *write_data, *walk_data; |
| int write_len; |
| dictionary_header_t *header; |
| u32 checksum=0; |
| |
| /* |
| * get memory for dictionary |
| */ |
| |
| write_len = sizeof(dictionary_header_t)+dicthead+relocation_length*sizeof(cell); |
| write_data = malloc(write_len); |
| if(!write_data) { |
| printk("panic: can't allocate memory for output dictionary (%d" |
| " bytes\n", write_len); |
| exit(1); |
| } |
| memset(write_data, 0, write_len); |
| |
| /* |
| * prepare dictionary header |
| */ |
| |
| header = (dictionary_header_t *)write_data; |
| *header = (dictionary_header_t){ |
| .signature = DICTID, |
| .version = 2, |
| .cellsize = sizeof(ucell), |
| #ifdef CONFIG_BIG_ENDIAN |
| .endianess = -1, |
| #else |
| .endianess = 0, |
| #endif |
| .checksum = 0, |
| .compression = 0, |
| .relocation = -1, |
| .length = target_ulong(dicthead), |
| .last = target_ucell(((unsigned long)last-(unsigned long)dict)), |
| .reserved[0] = 0, |
| .reserved[1] = 0, |
| .reserved[2] = 0, |
| }; |
| |
| /* |
| * prepare dictionary data |
| */ |
| |
| walk_data=write_data+sizeof(dictionary_header_t); |
| memcpy (walk_data, dict, dicthead); |
| |
| /* |
| * prepare relocation data. |
| * relocation_address is zero when writing a dictionary core. |
| */ |
| |
| if (relocation_address) { |
| #ifdef CONFIG_DEBUG_DICTIONARY |
| printk("writing %d reloc cells \n",relocation_length); |
| #endif |
| walk_data += dicthead; |
| memcpy(walk_data, relocation_address, |
| relocation_length*sizeof(cell)); |
| /* free relocation information */ |
| free(relocation_address); |
| relocation_address=NULL; |
| } else { |
| header->relocation=0; |
| } |
| |
| /* |
| * Calculate Checksum |
| */ |
| |
| walk_data=write_data; |
| while (walk_data<write_data+write_len) { |
| checksum+=read_long(walk_data); |
| walk_data+=sizeof(u32); |
| } |
| checksum=(u32)-checksum; |
| |
| header->checksum=target_long(checksum); |
| |
| dump_header(header); |
| |
| f = fopen(filename, "w"); |
| if (!f) { |
| printk("panic: can't write to dictionary '%s'.\n", filename); |
| exit(1); |
| } |
| |
| fwrite(write_data, write_len, 1, f); |
| |
| free(write_data); |
| fclose(f); |
| |
| #ifdef CONFIG_DEBUG_DICTIONARY |
| printk("wrote dictionary to file %s.\n", filename); |
| #endif |
| } |
| |
| static ucell read_dictionary(char *fil) |
| { |
| int ilen; |
| ucell ret; |
| char *mem; |
| FILE *f; |
| struct stat finfo; |
| |
| if (stat(fil, &finfo)) |
| return 0; |
| |
| ilen = finfo.st_size; |
| |
| if ((mem = malloc(ilen)) == NULL) { |
| printk("panic: not enough memory.\n"); |
| exit(1); |
| } |
| |
| f = fopen(fil, "r"); |
| if (!f) { |
| printk("panic: can't open dictionary.\n"); |
| exit(1); |
| } |
| |
| if (fread(mem, ilen, 1, f) != 1) { |
| printk("panic: can't read dictionary.\n"); |
| fclose(f); |
| exit(1); |
| } |
| fclose(f); |
| |
| ret = load_dictionary(mem, ilen); |
| |
| free(mem); |
| return ret; |
| } |
| |
| |
| /* |
| * C Parser related functions |
| */ |
| |
| /* |
| * skipws skips all whitespaces (space, tab, newline) from the input file |
| */ |
| |
| static void skipws(FILE * f) |
| { |
| int c; |
| while (!feof(f)) { |
| c = getc(f); |
| |
| if (c == ' ' || c == '\t' || c == '\n') |
| continue; |
| |
| ungetc(c, f); |
| break; |
| } |
| } |
| |
| /* |
| * parse gets the next word from the input stream, delimited by |
| * delim. If delim is 0, any word delimiter will end the stream |
| * word delimiters are space, tab and newline. The resulting word |
| * will be put zero delimited to the char array line. |
| */ |
| |
| static int parse(FILE * f, char *line, char delim) |
| { |
| int cnt = 0, c; |
| |
| while (!feof(f)) { |
| c = getc(f); |
| |
| if (delim && c == delim) |
| break; |
| |
| if ((!delim) && (c == ' ' || c == '\n' || c == '\t')) |
| break; |
| |
| line[cnt++] = c; |
| } |
| |
| line[cnt] = 0; |
| |
| return cnt; |
| } |
| |
| /* |
| * parse_word is a small helper that skips whitespaces before a word. |
| * it's behaviour is similar to the forth version parse-word. |
| */ |
| |
| static void parse_word(FILE * f, char *line) |
| { |
| skipws(f); |
| parse(f, line, 0); |
| } |
| |
| |
| static void writestring(const char *str) |
| { |
| unsigned int i; |
| for (i = 0; i < strlen(str); i++) { |
| dict[dicthead + i] = str[i]; |
| } |
| dicthead += i + 1; |
| dict[dicthead - 1] = (char) strlen(str) + 128; |
| } |
| |
| #define writebyte(value) {write_byte(dict+dicthead,value); dicthead++;} |
| #define writecell(value) {write_cell(dict+dicthead, value); dicthead+=sizeof(cell);} |
| |
| /* |
| * reveal a word, ie. make it visible. |
| */ |
| |
| static void reveal(void) |
| { |
| *last = *latest; |
| } |
| |
| /* |
| * dictionary padding |
| */ |
| |
| static void paddict(ucell align) |
| { |
| while (dicthead % align != 0) |
| writebyte(0); |
| } |
| |
| /* |
| * generic forth word creator function. |
| */ |
| |
| static void fcreate(char *word, ucell cfaval) |
| { |
| if (strlen(word) == 0) { |
| printk("WARNING: tried to create unnamed word.\n"); |
| return; |
| } |
| |
| writestring(word); |
| /* get us at least 1 byte for flags */ |
| writebyte(0); |
| paddict(sizeof(cell)); |
| /* set flags high bit. */ |
| dict[dicthead - 1] = 128; |
| /* lfa and cfa */ |
| writecell(read_ucell(latest)); |
| *latest = target_ucell(pointer2cell(dict) + dicthead - sizeof(cell)); |
| writecell(cfaval); |
| } |
| |
| |
| static ucell *buildvariable(char *name, cell defval) |
| { |
| fcreate(name, DOVAR); /* see dict.h for DOVAR and other CFA ids */ |
| writecell(defval); |
| return (ucell *) (dict + dicthead - sizeof(cell)); |
| } |
| |
| static void buildconstant(char *name, cell defval) |
| { |
| fcreate(name, DOCON); /* see dict.h for DOCON and other CFA ids */ |
| writecell(defval); |
| } |
| |
| static void builddefer(char *name) |
| { |
| fcreate(name, DODFR); /* see dict.h for DODFR and other CFA ids */ |
| writecell((ucell)0); |
| writecell((ucell)findword("(semis)")); |
| } |
| |
| /* |
| * Include file handling |
| */ |
| |
| static void add_includepath(char *path) |
| { |
| include *incl = &includes; |
| include *newpath; |
| |
| while (incl->next) |
| incl = incl->next; |
| |
| newpath = malloc(sizeof(include)); |
| if (!newpath) { |
| printk("panic: not enough memory for include path.\n"); |
| exit(1); |
| } |
| |
| incl->next = newpath; |
| newpath->path = path; |
| newpath->next = NULL; |
| } |
| |
| |
| static FILE *fopen_include(const char *fil) |
| { |
| #define MAX_PATH_LEN 256 |
| char fullpath[MAX_PATH_LEN]; |
| FILE *ret; |
| include *incl = &includes; |
| |
| while (incl) { |
| strncpy(fullpath, incl->path, MAX_PATH_LEN); |
| strncat(fullpath, "/", MAX_PATH_LEN); |
| strncat(fullpath, fil, MAX_PATH_LEN); |
| ret = fopen(fullpath, "r"); |
| if (ret != NULL) |
| return ret; |
| incl = incl->next; |
| } |
| return NULL; |
| } |
| |
| /* |
| * This is the C version of the forth interpreter |
| */ |
| |
| static int interpret_source(char *fil) |
| { |
| FILE *f; |
| char tib[160]; |
| long num; |
| char *test; |
| |
| const ucell SEMIS = (ucell)findword("(semis)"); |
| const ucell LIT = (ucell)findword("(lit)"); |
| const ucell DOBRANCH = (ucell)findword("dobranch"); |
| |
| if ((f = fopen_include(fil)) == NULL) { |
| printk("error while loading source file '%s'\n", fil); |
| errors++; |
| exit(1); |
| } |
| |
| /* FIXME: We should read this file at |
| * once. No need to get it char by char |
| */ |
| |
| while (!feof(f)) { |
| xt_t res; |
| parse_word(f, tib); |
| |
| /* if there is actually no word, we continue right away */ |
| if (strlen(tib) == 0) { |
| continue; |
| } |
| |
| /* Checking for builtin words that are needed to |
| * bootstrap the forth base dictionary. |
| */ |
| |
| if (!strcmp(tib, "(")) { |
| parse(f, tib, ')'); |
| continue; |
| } |
| |
| if (!strcmp(tib, "\\")) { |
| parse(f, tib, '\n'); |
| continue; |
| } |
| |
| if (!strcmp(tib, ":")) { |
| parse_word(f, tib); |
| |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| printk("create colon word %s\n\n", tib); |
| #endif |
| fcreate(tib, DOCOL); /* see dict.h for DOCOL and other CFA ids */ |
| *state = (ucell) (-1); |
| continue; |
| } |
| |
| if (!strcmp(tib, ";")) { |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| printk("finish colon definition\n\n"); |
| #endif |
| writecell((cell)SEMIS); |
| *state = (ucell) 0; |
| reveal(); |
| continue; |
| } |
| |
| if (!strcasecmp(tib, "variable")) { |
| parse_word(f, tib); |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| printk("defining variable %s\n\n", tib); |
| #endif |
| buildvariable(tib, 0); |
| reveal(); |
| continue; |
| } |
| |
| if (!strcasecmp(tib, "constant")) { |
| parse_word(f, tib); |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| printk("defining constant %s\n\n", tib); |
| #endif |
| buildconstant(tib, POP()); |
| reveal(); |
| continue; |
| } |
| |
| if (!strcasecmp(tib, "value")) { |
| parse_word(f, tib); |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| printk("defining value %s\n\n", tib); |
| #endif |
| buildconstant(tib, POP()); |
| reveal(); |
| continue; |
| } |
| |
| if (!strcasecmp(tib, "defer")) { |
| parse_word(f, tib); |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| printk("defining defer word %s\n\n", tib); |
| #endif |
| builddefer(tib); |
| reveal(); |
| continue; |
| } |
| |
| if (!strcasecmp(tib, "include")) { |
| parse_word(f, tib); |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| printk("including file %s\n\n", tib); |
| #endif |
| interpret_source(tib); |
| continue; |
| } |
| |
| if (!strcmp(tib, "[']")) { |
| xt_t xt; |
| parse_word(f, tib); |
| xt = findword(tib); |
| if (*state == 0) { |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| printk |
| ("writing address of %s to stack\n\n", |
| tib); |
| #endif |
| PUSH_xt(xt); |
| } else { |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| printk("writing lit, addr(%s) to dict\n\n", |
| tib); |
| #endif |
| writecell(LIT); /* lit */ |
| writecell((cell)xt); |
| } |
| continue; |
| /* we have no error detection here */ |
| } |
| |
| if (!strcasecmp(tib, "s\"")) { |
| int cnt; |
| cell loco; |
| |
| cnt = parse(f, tib, '"'); |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| printk("compiling string %s\n", tib); |
| #endif |
| loco = dicthead + (6 * sizeof(cell)); |
| writecell(LIT); |
| writecell(pointer2cell(dict) + loco); |
| writecell(LIT); |
| writecell((ucell)cnt); |
| writecell(DOBRANCH); |
| loco = cnt + sizeof(cell) - 1; |
| loco &= ~(sizeof(cell) - 1); |
| writecell(loco); |
| memcpy(dict + dicthead, tib, cnt); |
| dicthead += cnt; |
| paddict(sizeof(cell)); |
| continue; |
| } |
| |
| /* look if tib is in dictionary. */ |
| /* should the dictionary be searched before the builtins ? */ |
| res = findword(tib); |
| if (res) { |
| u8 flags = read_byte((u8*)cell2pointer(res) - |
| sizeof(cell) - 1); |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| printk("%s is 0x%p\n", tib, (ucell) res); |
| #endif |
| if (!(*state) || (flags & 3)) { |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| printk("executing %s, %p (flags: %s %s)\n", |
| tib, res, |
| (flags & 1) ? "immediate" : "", |
| (flags & 2) ? "compile-only" : ""); |
| #endif |
| PC = (ucell)res; |
| enterforth(res); |
| } else { |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| printk("writing %s to dict\n\n", tib); |
| #endif |
| writecell((cell)res); |
| } |
| continue; |
| } |
| |
| /* if not look if it's a number */ |
| if (tib[0] == '-') |
| num = strtol(tib, &test, read_ucell(base)); |
| else |
| num = strtoul(tib, &test, read_ucell(base)); |
| |
| |
| if (*test != 0) { |
| /* what is it?? */ |
| printk("%s is not defined.\n\n", tib); |
| errors++; |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| continue; |
| #else |
| return -1; |
| #endif |
| } |
| |
| if (*state == 0) { |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| printk("pushed %x to stack\n\n", num); |
| #endif |
| PUSH(num); |
| } else { |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| printk("writing lit, %x to dict\n\n", num); |
| #endif |
| writecell(LIT); /* lit */ |
| writecell(num); |
| } |
| } |
| fclose(f); |
| |
| return 0; |
| } |
| |
| static int build_dictionary(void) |
| { |
| ucell lfa = 0; |
| unsigned int i; |
| |
| /* we need a temporary place for latest outside the dictionary */ |
| latest = &lfa; |
| |
| /* starting a new dictionary: clear dicthead */ |
| dicthead = 0; |
| |
| #ifdef CONFIG_DEBUG_DICTIONARY |
| printk("building dictionary, %d primitives.\nbuilt words:", |
| sizeof(wordnames) / sizeof(void *)); |
| #endif |
| |
| for (i = 0; i < sizeof(wordnames) / sizeof(void *); i++) { |
| if (strlen(wordnames[i]) != 0) { |
| fcreate((char *) wordnames[i], i); |
| #ifdef CONFIG_DEBUG_DICTIONARY |
| printk(" %s", wordnames[i]); |
| #endif |
| } |
| } |
| #ifdef CONFIG_DEBUG_DICTIONARY |
| printk(".\n"); |
| #endif |
| |
| /* get last/latest and state */ |
| state = buildvariable("state", 0); |
| last = buildvariable("forth-last", 0); |
| latest = buildvariable("latest", 0); |
| |
| *latest = target_ucell(pointer2cell(latest)-2*sizeof(cell)); |
| |
| base=buildvariable("base", 10); |
| |
| buildconstant("/c", sizeof(u8)); |
| buildconstant("/w", sizeof(u16)); |
| buildconstant("/l", sizeof(u32)); |
| buildconstant("/n", sizeof(ucell)); |
| |
| reveal(); |
| printk("Dictionary initialization finished.\n"); |
| |
| return 0; |
| } |
| |
| /* |
| * functions used by primitives |
| */ |
| |
| int availchar(void) |
| { |
| int tmp; |
| if( cursrc < 1 ) { |
| runforth = 0; |
| /* return -1 in order to exit the loop in key() */ |
| return -1; |
| } |
| |
| tmp = getc( srcfiles[cursrc-1] ); |
| if (tmp != EOF) { |
| ungetc(tmp, srcfiles[cursrc-1]); |
| return -1; |
| } |
| fclose( srcfiles[--cursrc] ); |
| |
| return availchar(); |
| } |
| |
| int get_inputbyte( void ) |
| { |
| int tmp; |
| |
| if( cursrc < 1 ) { |
| runforth = 0; |
| return 0; |
| } |
| |
| tmp = getc( srcfiles[cursrc-1] ); |
| if (tmp != EOF) |
| return tmp; |
| fclose( srcfiles[--cursrc] ); |
| |
| return get_inputbyte(); |
| } |
| |
| /* |
| * segmentation fault handler. linux specific? |
| */ |
| |
| static void |
| segv_handler(int signo __attribute__ ((unused)), |
| siginfo_t * si, void *context __attribute__ ((unused))) |
| { |
| static int count = 0; |
| ucell addr = 0xdeadbeef; |
| |
| if (count) { |
| printk("Died while dumping forth dictionary core.\n"); |
| goto out; |
| } |
| |
| count++; |
| |
| if (PC >= pointer2cell(dict) && PC <= pointer2cell(dict) + dicthead) |
| addr = read_cell(cell2pointer(PC)); |
| |
| printk("panic: segmentation violation at %p\n", (char *)si->si_addr); |
| printk("dict=%p here=%p(dict+0x%" FMT_CELL_x ") pc=0x%" FMT_CELL_x "(dict+0x%" FMT_CELL_x ")\n", |
| dict, dict + dicthead, dicthead, PC, PC - pointer2cell(dict)); |
| printk("dstackcnt=%d rstackcnt=%d instruction=%" FMT_CELL_x "\n", |
| dstackcnt, rstackcnt, addr); |
| |
| printdstack(); |
| printrstack(); |
| |
| printk("Writing dictionary core file\n"); |
| write_dictionary("forth.dict.core"); |
| |
| out: |
| exit(1); |
| } |
| |
| /* |
| * allocate memory and prepare engine for memory management. |
| */ |
| |
| static void init_memory(void) |
| { |
| memset(memory, 0, MEMORY_SIZE); |
| |
| /* we push start and end of memory to the stack |
| * so that it can be used by the forth word QUIT |
| * to initialize the memory allocator. |
| * Add a cell to the start address so we don't end |
| * up with a start address of zero during bootstrap |
| */ |
| |
| PUSH(pointer2cell(memory)+sizeof(cell)); |
| PUSH(pointer2cell(memory) + MEMORY_SIZE-1); |
| } |
| |
| void exception(cell no) |
| { |
| switch (no) { |
| case -19: |
| printk(" undefined word.\n"); |
| break; |
| default: |
| printk("\nError %" FMT_CELL_d " occured.\n", no); |
| } |
| exit(1); |
| } |
| |
| |
| void |
| include_file( const char *name ) |
| { |
| FILE *file = fopen_include( name ); |
| if( !file ) { |
| printk("\npanic: Failed opening '%s'\n", name ); |
| exit(1); |
| } |
| if( cursrc >= sizeof(srcfiles)/sizeof(srcfiles[0]) ) { |
| printk("\npanic: Maximum include depth reached!\n"); |
| exit(1); |
| } |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| printk("Including '%s'\n", name ); |
| #endif |
| srcfiles[ cursrc++ ] = file; |
| } |
| |
| void |
| encode_file( const char *name ) |
| { |
| FILE *file = fopen_include(name); |
| int size; |
| |
| if( !file ) { |
| printk("\npanic: Can't open '%s'\n", name ); |
| exit(1); |
| } |
| fseek( file, 0, SEEK_END ); |
| size = ftell( file ); |
| fseek( file, 0, SEEK_SET ); |
| |
| printk("\nEncoding %s [%d bytes]\n", name, size ); |
| fread( dict + dicthead, size, 1, file ); |
| PUSH( pointer2cell(dict + dicthead) ); |
| PUSH( size ); |
| dicthead += size; |
| } |
| |
| |
| static void run_dictionary(char *basedict) |
| { |
| if(!basedict) |
| return; |
| |
| read_dictionary(basedict); |
| PC = (ucell)findword("initialize"); |
| |
| if (!PC) |
| return; |
| |
| if(!srcfiles[0]) { |
| cursrc = 1; |
| srcfiles[cursrc-1] = stdin; |
| } |
| |
| dstackcnt=0; |
| rstackcnt=0; |
| |
| init_memory(); |
| if (verbose) |
| printk("Jumping to dictionary..."); |
| |
| runforth=-1; |
| enterforth((xt_t)PC); |
| } |
| |
| static void new_dictionary(const char *source) |
| { |
| build_dictionary(); |
| |
| interpret_source((char *)source); |
| |
| printk("interpretion finished. %d errors occured.\n", |
| errors); |
| } |
| |
| /* |
| * main loop |
| */ |
| |
| #define BANNER "OpenBIOS bootstrap kernel. (C) 2003-2006 Patrick Mauritz, Stefan Reinauer\n"\ |
| "This software comes with absolutely no warranty. "\ |
| "All rights reserved.\n\n" |
| |
| #ifdef __GLIBC__ |
| #define USAGE "Usage: %s [options] [dictionary file|source file]\n\n" \ |
| " -h|--help show this help\n" \ |
| " -V|--version print version and exit\n" \ |
| " -v|--verbose print debugging information\n" \ |
| " -I|--include dir add dir to include path\n" \ |
| " -d|--source-dictionary bootstrap.dict\n" \ |
| " use this dictionary as base\n" \ |
| " -D|--target-dictionary output.dict\n" \ |
| " write to output.dict\n" \ |
| " -s|--segfault install segfault handler\n\n" |
| #else |
| #define USAGE "Usage: %s [options] [dictionary file|source file]\n\n" \ |
| " -h show this help\n" \ |
| " -V print version and exit\n" \ |
| " -v print debugging information\n" \ |
| " -I add dir to include path\n" \ |
| " -d bootstrap.dict\n" \ |
| " use this dictionary as base\n" \ |
| " -D output.dict\n" \ |
| " write to output.dict\n" \ |
| " -s install segfault handler\n\n" |
| |
| #endif |
| |
| int main(int argc, char *argv[]) |
| { |
| struct sigaction sa; |
| |
| unsigned char *ressources=NULL; /* All memory used by us */ |
| char *dictname = NULL; |
| char *basedict = NULL; |
| |
| unsigned char *bootstrapdict[2]; |
| int c, cnt; |
| |
| const char *optstring = "VvhsI:d:D:?"; |
| |
| printk(BANNER); |
| |
| while (1) { |
| #ifdef __GLIBC__ |
| int option_index = 0; |
| static struct option long_options[] = { |
| {"version", 0, NULL, 'V'}, |
| {"verbose", 0, NULL, 'v'}, |
| {"help", 0, NULL, 'h'}, |
| {"segfault", 0, NULL, 's'}, |
| {"include", 1, NULL, 'I'}, |
| {"source-dictionary", 1, NULL, 'd'}, |
| {"target-dictionary", 1, NULL, 'D'}, |
| }; |
| |
| /* |
| * option handling |
| */ |
| |
| c = getopt_long(argc, argv, optstring, long_options, |
| &option_index); |
| #else |
| c = getopt(argc, argv, optstring); |
| #endif |
| if (c == -1) |
| break; |
| |
| switch (c) { |
| case 'V': |
| printk("Version " VERSION "\n"); |
| return 0; |
| case 'h': |
| case '?': |
| printk("Version " VERSION "\n" USAGE, argv[0]); |
| return 0; |
| case 'v': |
| verbose = 1; |
| break; |
| case 's': |
| segfault = 1; |
| break; |
| case 'I': |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| printk("adding '%s' to include path\n", optarg); |
| #endif |
| add_includepath(optarg); |
| break; |
| case 'd': |
| if (!basedict) { |
| printk("Using source dictionary '%s'\n", optarg); |
| basedict = optarg; |
| } |
| case 'D': |
| if(!dictname) { |
| printk("Dumping final dictionary to '%s'\n", optarg); |
| dictname = optarg; |
| } |
| break; |
| default: |
| return 1; |
| } |
| } |
| |
| if (argc < optind + 1) { |
| printk(USAGE, argv[0]); |
| return 1; |
| } |
| |
| |
| /* |
| * Get all required resources |
| */ |
| |
| |
| ressources = malloc(MEMORY_SIZE + (2 * DICTIONARY_SIZE) + TRAMPOLINE_SIZE); |
| if (!ressources) { |
| printk("panic: not enough memory on host system.\n"); |
| return 1; |
| } |
| |
| #ifdef NATIVE_BITWIDTH_SMALLER_THAN_HOST_BITWIDTH |
| base_address=(unsigned long)ressources; |
| #endif |
| |
| memory = (ucell *)ressources; |
| |
| bootstrapdict[0] = ressources + MEMORY_SIZE; |
| bootstrapdict[1] = ressources + MEMORY_SIZE + DICTIONARY_SIZE; |
| trampoline = (ucell *)(ressources + MEMORY_SIZE + DICTIONARY_SIZE + DICTIONARY_SIZE); |
| |
| #ifdef CONFIG_DEBUG_INTERPRETER |
| printf("memory: %p\n",memory); |
| printf("dict1: %p\n",bootstrapdict[0]); |
| printf("dict2: %p\n",bootstrapdict[1]); |
| printf("trampoline: %p\n",trampoline); |
| printf("size=%d, trampoline_size=%d\n",MEMORY_SIZE + (2 * |
| DICTIONARY_SIZE) + TRAMPOLINE_SIZE, |
| TRAMPOLINE_SIZE); |
| #endif |
| |
| init_trampoline(); |
| |
| if (!segfault) { |
| if (verbose) |
| printk("Installing SIGSEGV handler..."); |
| |
| sa.sa_sigaction = segv_handler; |
| sigemptyset(&sa.sa_mask); |
| sa.sa_flags = SA_SIGINFO | SA_NODEFER; |
| sigaction(SIGSEGV, &sa, 0); |
| |
| if (verbose) |
| printk("done.\n"); |
| } |
| |
| /* |
| * Now do the real work |
| */ |
| |
| for (cnt=0; cnt<2; cnt++) { |
| printk("Compiling dictionary %d/%d\n", cnt+1, 2); |
| dict=bootstrapdict[cnt]; |
| if(!basedict) { |
| new_dictionary(argv[optind]); |
| } else { |
| for (c=argc-1; c>=optind; c--) |
| include_file(argv[c]); |
| |
| run_dictionary(basedict); |
| } |
| if(errors) |
| break; |
| } |
| |
| #ifndef CONFIG_DEBUG_INTERPRETER |
| if (errors) |
| printk("dictionary not dumped to file.\n"); |
| else |
| #endif |
| { |
| relocation_table( bootstrapdict[0], bootstrapdict[1], dicthead); |
| write_dictionary( dictname ? dictname : "bootstrap.dict"); |
| } |
| |
| free(ressources); |
| return 0; |
| } |