| #endif |
#endif |
| |
|
| #if defined(DIRECT_THREADED) |
#if defined(DIRECT_THREADED) |
| # define CA(n) (symbols[(n)]) |
/*# define CA(n) (symbols[(n)])*/ |
| |
# define CA(n) (symbols[(n)&~0x4000UL]) |
| |
#elif defined(DOUBLY_INDIRECT) |
| |
/* # define CA(n) ((Cell)(symbols+((n)&~0x4000UL))) */ |
| |
# define CA(n) ({Cell _n = (n); ((Cell)(((_n & 0x4000) ? symbols : xts)+(_n&~0x4000UL)));}) |
| #else |
#else |
| # define CA(n) ((Cell)(symbols+(n))) |
# define CA(n) ((Cell)(symbols+((n)&~0x4000UL))) |
| #endif |
#endif |
| |
|
| #define maxaligned(n) (typeof(n))((((Cell)n)+sizeof(Float)-1)&-sizeof(Float)) |
#define maxaligned(n) (typeof(n))((((Cell)n)+sizeof(Float)-1)&-sizeof(Float)) |
| int optind = 1; |
int optind = 1; |
| #endif |
#endif |
| |
|
| |
Address code_area=0; |
| |
Address code_here=0; /* does for code-area what HERE does for the dictionary */ |
| |
|
| #ifdef HAS_DEBUG |
#ifdef HAS_DEBUG |
| static int debug=0; |
static int debug=0; |
| #else |
#else |
| |
|
| ImageHeader *gforth_header; |
ImageHeader *gforth_header; |
| Label *vm_prims; |
Label *vm_prims; |
| |
#ifdef DOUBLY_INDIRECT |
| |
Label *xts; /* same content as vm_prims, but should only be used for xts */ |
| |
#endif |
| |
|
| #ifdef MEMCMP_AS_SUBROUTINE |
#ifdef MEMCMP_AS_SUBROUTINE |
| int gforth_memcmp(const char * s1, const char * s2, size_t n) |
int gforth_memcmp(const char * s1, const char * s2, size_t n) |
| * If the word =CF(DODOES), it's a DOES> CFA |
* If the word =CF(DODOES), it's a DOES> CFA |
| * If the word =CF(DOESJUMP), it's a DOES JUMP (2 Cells after DOES>, |
* If the word =CF(DOESJUMP), it's a DOES JUMP (2 Cells after DOES>, |
| * possibly containing a jump to dodoes) |
* possibly containing a jump to dodoes) |
| * If the word is <CF(DOESJUMP), it's a primitive |
* If the word is <CF(DOESJUMP) and bit 14 is set, it's the xt of a primitive |
| |
* If the word is <CF(DOESJUMP) and bit 14 is clear, |
| |
* it's the threaded code of a primitive |
| */ |
*/ |
| |
|
| void relocate(Cell *image, const char *bitstring, int size, Label symbols[]) |
void relocate(Cell *image, const char *bitstring, |
| |
int size, int base, Label symbols[]) |
| { |
{ |
| int i=0, j, k, steps=(size/sizeof(Cell))/RELINFOBITS; |
int i=0, j, k, steps=(size/sizeof(Cell))/RELINFOBITS; |
| Cell token; |
Cell token; |
| char bits; |
char bits; |
| Cell max_symbols; |
Cell max_symbols; |
| |
/* |
| |
* A virtial start address that's the real start address minus |
| |
* the one in the image |
| |
*/ |
| |
Cell *start = (Cell * ) (((void *) image) - ((void *) base)); |
| |
|
| |
|
| /* printf("relocating %x[%x]\n", image, size); */ |
/* printf("relocating to %x[%x] start=%x base=%x\n", image, size, start, base); */ |
| |
|
| for (max_symbols=DOESJUMP+1; symbols[max_symbols]!=0; max_symbols++) |
for (max_symbols=DOESJUMP+1; symbols[max_symbols]!=0; max_symbols++) |
| ; |
; |
| |
max_symbols--; |
| size/=sizeof(Cell); |
size/=sizeof(Cell); |
| |
|
| for(k=0; k<=steps; k++) { |
for(k=0; k<=steps; k++) { |
| /* fprintf(stderr,"relocate: image[%d]\n", i);*/ |
/* fprintf(stderr,"relocate: image[%d]\n", i);*/ |
| if((i < size) && (bits & (1U << (RELINFOBITS-1)))) { |
if((i < size) && (bits & (1U << (RELINFOBITS-1)))) { |
| /* fprintf(stderr,"relocate: image[%d]=%d of %d\n", i, image[i], size/sizeof(Cell)); */ |
/* fprintf(stderr,"relocate: image[%d]=%d of %d\n", i, image[i], size/sizeof(Cell)); */ |
| if((token=image[i])<0) |
token=image[i]; |
| |
if(token<0) |
| switch(token) |
switch(token) |
| { |
{ |
| case CF_NIL : image[i]=0; break; |
case CF_NIL : image[i]=0; break; |
| case CF(DOESJUMP): MAKE_DOES_HANDLER(image+i); break; |
case CF(DOESJUMP): MAKE_DOES_HANDLER(image+i); break; |
| #endif /* !defined(DOUBLY_INDIRECT) */ |
#endif /* !defined(DOUBLY_INDIRECT) */ |
| case CF(DODOES) : |
case CF(DODOES) : |
| MAKE_DOES_CF(image+i,(Xt *)(image[i+1]+((Cell)image))); |
MAKE_DOES_CF(image+i,(Xt *)(image[i+1]+((Cell)start))); |
| break; |
break; |
| default : |
default : |
| /* printf("Code field generation image[%x]:=CA(%x)\n", |
/* printf("Code field generation image[%x]:=CA(%x)\n", |
| i, CF(image[i])); */ |
i, CF(image[i])); */ |
| if (CF(token)<max_symbols) |
#if !defined(DOUBLY_INDIRECT) |
| |
if (((token | 0x4000) >= CF(DODOES)) && (token < -0x4000)) |
| |
fprintf(stderr,"Doer %d used in this image at $%lx is marked as Xt;\n executing this code will crash.\n",CF((token | 0x4000)),(long)&image[i],VERSION); |
| |
#endif |
| |
if (CF((token | 0x4000))<max_symbols) |
| image[i]=(Cell)CA(CF(token)); |
image[i]=(Cell)CA(CF(token)); |
| else |
else |
| fprintf(stderr,"Primitive %d used in this image at $%lx is not implemented by this\n engine (%s); executing this code will crash.\n",CF(token),(long)&image[i],VERSION); |
fprintf(stderr,"Primitive %d used in this image at $%lx is not implemented by this\n engine (%s); executing this code will crash.\n",CF(token),(long)&image[i],VERSION); |
| } |
} |
| else |
else { |
| image[i]+=(Cell)image; |
// if base is > 0: 0 is a null reference so don't adjust |
| |
if (token>=base) { |
| |
image[i]+=(Cell)start; |
| |
} |
| |
} |
| } |
} |
| } |
} |
| } |
} |
| header->fp_stack_base=my_alloc(fsize); |
header->fp_stack_base=my_alloc(fsize); |
| header->return_stack_base=my_alloc(rsize); |
header->return_stack_base=my_alloc(rsize); |
| header->locals_stack_base=my_alloc(lsize); |
header->locals_stack_base=my_alloc(lsize); |
| |
code_here = code_area = my_alloc(dictsize); |
| } |
} |
| |
|
| |
#warning You can ignore the warnings about clobbered variables in go_forth |
| int go_forth(Address image, int stack, Cell *entries) |
int go_forth(Address image, int stack, Cell *entries) |
| { |
{ |
| volatile ImageHeader *image_header = (ImageHeader *)image; |
volatile ImageHeader *image_header = (ImageHeader *)image; |
| Cell *sp0=(Cell*)(image_header->data_stack_base + dsize); |
Cell *sp0=(Cell*)(image_header->data_stack_base + dsize); |
| Float *fp0=(Float *)(image_header->fp_stack_base + fsize); |
|
| Cell *rp0=(Cell *)(image_header->return_stack_base + rsize); |
Cell *rp0=(Cell *)(image_header->return_stack_base + rsize); |
| |
Float *fp0=(Float *)(image_header->fp_stack_base + fsize); |
| |
#ifdef GFORTH_DEBUGGING |
| volatile Cell *orig_rp0=rp0; |
volatile Cell *orig_rp0=rp0; |
| |
#endif |
| Address lp0=image_header->locals_stack_base + lsize; |
Address lp0=image_header->locals_stack_base + lsize; |
| Xt *ip0=(Xt *)(image_header->boot_entry); |
Xt *ip0=(Xt *)(image_header->boot_entry); |
| #ifdef SYSSIGNALS |
#ifdef SYSSIGNALS |
| 1 << ((sizebyte >> 5) & 3)); |
1 << ((sizebyte >> 5) & 3)); |
| } |
} |
| |
|
| |
typedef struct { |
| |
Label start; |
| |
Cell length; /* excluding the jump */ |
| |
char super_end; /* true if primitive ends superinstruction, i.e., |
| |
unconditional branch, execute, etc. */ |
| |
} PrimInfo; |
| |
|
| |
PrimInfo *priminfos; |
| |
Cell npriminfos=0; |
| |
|
| |
void check_prims(Label symbols1[]) |
| |
{ |
| |
#if defined(IS_NEXT_JUMP) && !defined(DOUBLY_INDIRECT) |
| |
int i; |
| |
Label *symbols2=engine2(0,0,0,0,0); |
| |
static char superend[]={ |
| |
#include "prim_superend.i" |
| |
}; |
| |
|
| |
for (i=DOESJUMP+1; symbols1[i+1]!=0; i++) |
| |
; |
| |
priminfos = calloc(i,sizeof(PrimInfo)); |
| |
npriminfos = i; |
| |
for (i=DOESJUMP+1; symbols1[i+1]!=0; i++) { |
| |
int prim_len=symbols1[i+1]-symbols1[i]; |
| |
PrimInfo *pi=&priminfos[i]; |
| |
int j; |
| |
pi->super_end = superend[i-DOESJUMP-1]; |
| |
for (j=prim_len-IND_JUMP_LENGTH; ; j--) { |
| |
if (IS_NEXT_JUMP(symbols1[i]+j)) { |
| |
prim_len = j; |
| |
if (pi->super_end) |
| |
prim_len += IND_JUMP_LENGTH; /* include the jump */ |
| |
break; |
| |
} |
| |
if (j==0) { /* NEXT jump not found, e.g., execute */ |
| |
if (!pi->super_end && debug) |
| |
fprintf(stderr, "NEXT jump not found for primitive %d, making it super_end\n", i); |
| |
pi->super_end = 1; |
| |
break; |
| |
} |
| |
} |
| |
/* fprintf(stderr,"checking primitive %d: memcmp(%p, %p, %d)\n", |
| |
i, symbols1[i], symbols2[i], prim_len);*/ |
| |
if (memcmp(symbols1[i],symbols2[i],prim_len)!=0) { |
| |
if (debug) |
| |
fprintf(stderr,"Primitive %d not relocatable: memcmp(%p, %p, %d)\n", |
| |
i, symbols1[i], symbols2[i], prim_len); |
| |
} else { |
| |
pi->start = symbols1[i]; |
| |
pi->length = prim_len; |
| |
if (debug) |
| |
fprintf(stderr,"Primitive %d relocatable: start %p, length %ld, super_end %d\n", |
| |
i, pi->start, pi->length, pi->super_end); |
| |
} |
| |
} |
| |
#endif |
| |
} |
| |
|
| |
Label compile_prim(Label prim) |
| |
{ |
| |
#ifdef DOUBLY_INDIRECT |
| |
if (prim<((Label)(xts+DOESJUMP)) || prim>((Label)(xts+npriminfos))) { |
| |
fprintf(stderr,"compile_prim encountered xt %p\n", prim); |
| |
return prim; |
| |
} else |
| |
return prim-((Label)xts)+((Label)vm_prims); |
| |
#else /* !defined(DOUBLY_INDIRECT) */ |
| |
#ifdef IND_JUMP_LENGTH |
| |
int i; |
| |
Address old_code_here=code_here; |
| |
static Address last_jump=0; |
| |
|
| |
for (i=0; ; i++) { |
| |
if (i>=npriminfos) { /* not a relocatable prim */ |
| |
if (last_jump) { /* make sure the last sequence is complete */ |
| |
memcpy(code_here, last_jump, IND_JUMP_LENGTH); |
| |
code_here += IND_JUMP_LENGTH; |
| |
last_jump = 0; |
| |
} |
| |
return prim; |
| |
} |
| |
if (priminfos[i].start==prim) |
| |
break; |
| |
} |
| |
#ifdef ALIGN_CODE |
| |
ALIGN_CODE; |
| |
#endif |
| |
memcpy(code_here, (Address)prim, priminfos[i].length); |
| |
code_here += priminfos[i].length; |
| |
last_jump = (priminfos[i].super_end) ? 0 : (prim+priminfos[i].length); |
| |
return (Label)old_code_here; |
| |
#else |
| |
return prim; |
| |
#endif |
| |
#endif /* !defined(DOUBLY_INDIRECT) */ |
| |
} |
| |
|
| Address loader(FILE *imagefile, char* filename) |
Address loader(FILE *imagefile, char* filename) |
| /* returns the address of the image proper (after the preamble) */ |
/* returns the address of the image proper (after the preamble) */ |
| { |
{ |
| ; |
; |
| |
|
| vm_prims = engine(0,0,0,0,0); |
vm_prims = engine(0,0,0,0,0); |
| |
check_prims(vm_prims); |
| #ifndef DOUBLY_INDIRECT |
#ifndef DOUBLY_INDIRECT |
| check_sum = checksum(vm_prims); |
check_sum = checksum(vm_prims); |
| #else /* defined(DOUBLY_INDIRECT) */ |
#else /* defined(DOUBLY_INDIRECT) */ |
| imp=image+preamblesize; |
imp=image+preamblesize; |
| if (clear_dictionary) |
if (clear_dictionary) |
| memset(imp+header.image_size, 0, dictsize-header.image_size); |
memset(imp+header.image_size, 0, dictsize-header.image_size); |
| if(header.base==0) { |
if(header.base==0 || header.base == 0x100) { |
| Cell reloc_size=((header.image_size-1)/sizeof(Cell))/8+1; |
Cell reloc_size=((header.image_size-1)/sizeof(Cell))/8+1; |
| char reloc_bits[reloc_size]; |
char reloc_bits[reloc_size]; |
| fseek(imagefile, preamblesize+header.image_size, SEEK_SET); |
fseek(imagefile, preamblesize+header.image_size, SEEK_SET); |
| fread(reloc_bits, 1, reloc_size, imagefile); |
fread(reloc_bits, 1, reloc_size, imagefile); |
| relocate((Cell *)imp, reloc_bits, header.image_size, vm_prims); |
relocate((Cell *)imp, reloc_bits, header.image_size, header.base, vm_prims); |
| #if 0 |
#if 0 |
| { /* let's see what the relocator did */ |
{ /* let's see what the relocator did */ |
| FILE *snapshot=fopen("snapshot.fi","wb"); |
FILE *snapshot=fopen("snapshot.fi","wb"); |
| progname, (unsigned long)(header.checksum),(unsigned long)check_sum); |
progname, (unsigned long)(header.checksum),(unsigned long)check_sum); |
| exit(1); |
exit(1); |
| } |
} |
| |
#ifdef DOUBLY_INDIRECT |
| |
((ImageHeader *)imp)->xt_base = xts; |
| |
#endif |
| fclose(imagefile); |
fclose(imagefile); |
| |
|
| alloc_stacks((ImageHeader *)imp); |
alloc_stacks((ImageHeader *)imp); |