blob: 0986cb14f0f6af3c7490e0c83408b2bca5f4ec17 [file] [log] [blame]
/*
* tag: dict management
*
* Copyright (C) 2003-2005 Stefan Reinauer, Patrick Mauritz
*
* See the file "COPYING" for further information about
* the copyright and warranty status of this work.
*/
#include "config.h"
#include "kernel/kernel.h"
#include "dict.h"
#ifdef BOOTSTRAP
#include <string.h>
#else
#include "libc/string.h"
#endif
#include "cross.h"
unsigned char *dict = NULL;
ucell *last;
cell dicthead = 0;
cell dictlimit = 0;
/* lfa2nfa
* converts a link field address to a name field address,
* i.e find pointer to a given words name
*/
ucell lfa2nfa(ucell ilfa)
{
/* get offset from dictionary start */
ilfa = ilfa - (ucell)pointer2cell(dict);
ilfa--; /* skip status */
while (dict[--ilfa] == 0); /* skip all pad bytes */
ilfa -= (dict[ilfa] - 128);
return ilfa + (ucell)pointer2cell(dict);
}
/* lfa2cfa
* converts a link field address to a code field address.
* in this forth implementation this is just a fixed offset
*/
static xt_t lfa2cfa(ucell ilfa)
{
return (xt_t)(ilfa + sizeof(cell));
}
/* fstrlen - returns length of a forth string. */
ucell fstrlen(ucell fstr)
{
fstr -= pointer2cell(dict)+1;
//fstr -= pointer2cell(dict); FIXME
while (dict[++fstr] < 128)
;
return dict[fstr] - 128;
}
/* to_lower - convert a character to lowecase */
static int to_lower(int c)
{
return ((c >= 'A') && (c <= 'Z')) ? (c - 'A' + 'a') : c;
}
/* fstrcmp - compare null terminated string with forth string. */
static int fstrcmp(const char *s1, ucell fstr)
{
char *s2 = (char*)cell2pointer(fstr);
while (*s1) {
if ( to_lower(*(s1++)) != to_lower(*(s2++)) )
return -1;
}
return 0;
}
/* fstrncpy - copy a forth string to a destination (with NULL termination) */
void fstrncpy(char *dest, ucell src, unsigned int maxlen)
{
int len = fstrlen(src);
if (fstrlen(src) >= maxlen) len = maxlen - 1;
memcpy(dest, cell2pointer(src), len);
*(dest + len) = '\0';
}
/* findword
* looks up a given word in the dictionary. This function
* is used by the c based interpreter and to find the "initialize"
* word.
*/
xt_t findword(const char *s1)
{
ucell tmplfa, len;
if (!last)
return 0;
tmplfa = read_ucell(last);
len = strlen(s1);
while (tmplfa) {
ucell nfa = lfa2nfa(tmplfa);
if (len == fstrlen(nfa) && !fstrcmp(s1, nfa)) {
return lfa2cfa(tmplfa);
}
tmplfa = read_ucell(cell2pointer(tmplfa));
}
return 0;
}
/* findsemis_wordlist
* Given a DOCOL xt and a wordlist, find the address of the semis
* word at the end of the word definition. We do this by finding
* the word before this in the dictionary, then counting back one
* from the NFA.
*/
static ucell findsemis_wordlist(ucell xt, ucell wordlist)
{
ucell tmplfa, nextlfa, nextcfa;
if (!wordlist)
return 0;
tmplfa = read_ucell(cell2pointer(wordlist));
nextcfa = lfa2cfa(tmplfa);
/* Catch the special case where the lfa of the word we
* want is the last word in the dictionary; in that case
* the end of the word is given by "here" - 1 */
if (nextcfa == xt)
return pointer2cell(dict) + dicthead - sizeof(cell);
while (tmplfa) {
/* Peek ahead and see if the next CFA in the list is the
* one we are searching for */
nextlfa = read_ucell(cell2pointer(tmplfa));
nextcfa = lfa2cfa(nextlfa);
/* If so, count back 1 cell from the current NFA */
if (nextcfa == xt)
return lfa2nfa(tmplfa) - sizeof(cell);
tmplfa = nextlfa;
}
return 0;
}
/* findsemis
* Given a DOCOL xt, find the address of the semis word at the end
* of the word definition by searching all vocabularies */
ucell findsemis(ucell xt)
{
ucell usesvocab = findword("vocabularies?") + sizeof(cell);
unsigned int i;
if (read_ucell(cell2pointer(usesvocab))) {
/* Vocabularies are in use, so search each one in turn */
ucell numvocabs = findword("#order") + sizeof(cell);
for (i = 0; i < read_ucell(cell2pointer(numvocabs)); i++) {
ucell vocabs = findword("vocabularies") + 2 * sizeof(cell);
ucell semis = findsemis_wordlist(xt, read_cell(cell2pointer(vocabs + (i * sizeof(cell)))));
/* If we get a non-zero result, we found the xt in this vocab */
if (semis)
return semis;
}
} else {
/* Vocabularies not in use */
return findsemis_wordlist(xt, read_ucell(last));
}
return 0;
}
/* findxtfromcell_wordlist
* Given a cell and a wordlist, determine the CFA of the word containing
* the cell or 0 if we are unable to return a suitable CFA
*/
ucell findxtfromcell_wordlist(ucell incell, ucell wordlist)
{
ucell tmplfa;
if (!wordlist)
return 0;
tmplfa = read_ucell(cell2pointer(wordlist));
while (tmplfa) {
if (tmplfa < incell)
return lfa2cfa(tmplfa);
tmplfa = read_ucell(cell2pointer(tmplfa));
}
return 0;
}
/* findxtfromcell
* Given a cell, determine the CFA of the word containing
* the cell by searching all vocabularies
*/
ucell findxtfromcell(ucell incell)
{
ucell usesvocab = findword("vocabularies?") + sizeof(cell);
unsigned int i;
if (read_ucell(cell2pointer(usesvocab))) {
/* Vocabularies are in use, so search each one in turn */
ucell numvocabs = findword("#order") + sizeof(cell);
for (i = 0; i < read_ucell(cell2pointer(numvocabs)); i++) {
ucell vocabs = findword("vocabularies") + 2 * sizeof(cell);
ucell semis = findxtfromcell_wordlist(incell, read_cell(cell2pointer(vocabs + (i * sizeof(cell)))));
/* If we get a non-zero result, we found the xt in this vocab */
if (semis)
return semis;
}
} else {
/* Vocabularies not in use */
return findxtfromcell_wordlist(incell, read_ucell(last));
}
return 0;
}
void dump_header(dictionary_header_t *header)
{
printk("OpenBIOS dictionary:\n");
printk(" version: %d\n", header->version);
printk(" cellsize: %d\n", header->cellsize);
printk(" endianess: %s\n", header->endianess?"big":"little");
printk(" compression: %s\n", header->compression?"yes":"no");
printk(" relocation: %s\n", header->relocation?"yes":"no");
printk(" checksum: %08x\n", target_long(header->checksum));
printk(" length: %08x\n", target_long(header->length));
printk(" last: %0" FMT_CELL_x "\n", target_cell(header->last));
}
ucell load_dictionary(const char *data, ucell len)
{
u32 checksum=0;
const char *checksum_walk;
ucell *walk, *reloc_table;
dictionary_header_t *header=(dictionary_header_t *)data;
/* assertions */
if (len <= (sizeof(dictionary_header_t)) || strncmp(DICTID, data, 8))
return 0;
#ifdef CONFIG_DEBUG_DICTIONARY
dump_header(header);
#endif
checksum_walk=data;
while (checksum_walk<data+len) {
checksum+=read_long(checksum_walk);
checksum_walk+=sizeof(u32);
}
if(checksum) {
printk("Checksum invalid (%08x)!\n", checksum);
return 0;
}
data += sizeof(dictionary_header_t);
dicthead = target_long(header->length);
memcpy(dict, data, dicthead);
reloc_table=(ucell *)(data+dicthead);
#ifdef CONFIG_DEBUG_DICTIONARY
printk("\nmoving dictionary (%x bytes) to %x\n",
(ucell)dicthead, (ucell)dict);
printk("\ndynamic relocation...");
#endif
for (walk = (ucell *) dict; walk < (ucell *) (dict + dicthead);
walk++) {
int pos, bit, l;
l=(walk-(ucell *)dict);
pos=l/BITS;
bit=l&~(-BITS);
if (reloc_table[pos] & target_ucell((ucell)1ULL << bit)) {
// printk("%lx, pos %x, bit %d\n",*walk, pos, bit);
write_ucell(walk, read_ucell(walk)+pointer2cell(dict));
}
}
#ifdef CONFIG_DEBUG_DICTIONARY
printk(" done.\n");
#endif
last = (ucell *)(dict + target_ucell(header->last));
return -1;
}