diff options
| author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
|---|---|---|
| committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
| commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
| tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/efcode/engine | |
| download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz | |
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/efcode/engine')
28 files changed, 12261 insertions, 0 deletions
diff --git a/usr/src/lib/efcode/engine/Makefile b/usr/src/lib/efcode/engine/Makefile new file mode 100644 index 0000000000..29132d88a1 --- /dev/null +++ b/usr/src/lib/efcode/engine/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.subdirs diff --git a/usr/src/lib/efcode/engine/Makefile.com b/usr/src/lib/efcode/engine/Makefile.com new file mode 100644 index 0000000000..fc8c6135b5 --- /dev/null +++ b/usr/src/lib/efcode/engine/Makefile.com @@ -0,0 +1,38 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +OBJECTS = init.o interface.o signal.o forth.o fcode.o interp.o debug.o \ + env.o print.o properties.o actions.o package.o instance.o \ + alarm.o interactive.o framebuffer.o font.o fb8.o extend.o tracing.o \ + resource.o prims64.o mcookie.o log.o cleanup.o + +LIBRARY = fcode.a + +include ../../Makefile.efcode + +LDLIBS += -lrt diff --git a/usr/src/lib/efcode/engine/actions.c b/usr/src/lib/efcode/engine/actions.c new file mode 100644 index 0000000000..11fb96c363 --- /dev/null +++ b/usr/src/lib/efcode/engine/actions.c @@ -0,0 +1,399 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2000 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <string.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +#define NUM_DEFAULT_ACTIONS 7 + +/* + * value_fetch and value_store are the same as "fetch" and "store", but + * we'll leave them implemented here for now. + */ +static void +value_fetch(fcode_env_t *env) +{ + variable_t *addr; + + CHECK_DEPTH(env, 1, "value_fetch"); + addr = (variable_t *)POP(DS); + PUSH(DS, (variable_t)*addr); +} + +static void +value_store(fcode_env_t *env) +{ + variable_t *addr; + + CHECK_DEPTH(env, 1, "value_store"); + addr = (variable_t *)POP(DS); + *addr = (variable_t)POP(DS); +} + +void * +get_internal_address(fcode_env_t *env) +{ + int *ptr; + + CHECK_DEPTH(env, 1, "get_internal_address"); + ptr = (int *)POP(DS); + if (*ptr > 0) + return ((uchar_t *)env + *ptr); + return ((uchar_t *)MYSELF - *ptr); +} + +void +internal_env_fetch(fcode_env_t *env) +{ + instance_t **iptr; + + CHECK_DEPTH(env, 1, "internal_env_fetch"); + iptr = (instance_t **)get_internal_address(env); + PUSH(DS, (fstack_t)(*iptr)); +} + +void +internal_env_store(fcode_env_t *env) +{ + instance_t **iptr; + + CHECK_DEPTH(env, 2, "internal_env_store"); + iptr = (instance_t **)get_internal_address(env); + *iptr = (instance_t *)POP(DS); +} + +void +internal_env_addr(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 1, "internal_env_addr"); + d = (fstack_t)get_internal_address(env); + PUSH(DS, d); +} + +void +do_buffer_data(fcode_env_t *env, token_t *d, int instance) +{ + if (!*d) { /* check if buffer not alloc'ed yet */ + token_t *buf; + + if (instance) { + int n, off; + + n = TOKEN_ROUNDUP(d[1]); + buf = alloc_instance_data(env, UINIT_DATA, n, &off); + memset(buf, 0, d[1]); + } else { + buf = (token_t *)HERE; + set_here(env, HERE + d[1], "do_buffer_data"); + } + *d = (token_t)buf; + } + PUSH(DS, *d); +} + +void +ibuffer_init(fcode_env_t *env) +{ + token_t *d; + + d = get_instance_address(env); + do_buffer_data(env, d, 1); +} + +void +buffer_init(fcode_env_t *env) +{ + token_t *d; + + CHECK_DEPTH(env, 1, "buffer_init"); + d = (token_t *)POP(DS); + do_buffer_data(env, d, 0); +} + +void +do_defer(fcode_env_t *env) +{ + fetch(env); + execute(env); +} + +token_t *value_actions[NUM_DEFAULT_ACTIONS]; +token_t value_defines[NUM_DEFAULT_ACTIONS][3] = { + { (token_t)&value_fetch, (token_t)&value_store, (token_t)&noop }, + { (token_t)&fetch_instance_data, (token_t)&set_instance_data, + (token_t)&address_instance_data }, + { (token_t)&internal_env_fetch, (token_t)&internal_env_store, + (token_t)&internal_env_addr }, + { (token_t)&do_defer, (token_t)&store, (token_t)&noop }, + { (token_t)&idefer_exec, (token_t)&set_instance_data, + (token_t)&address_instance_data }, + { (token_t)&buffer_init, (token_t)&two_drop, (token_t)&noop, }, + { (token_t)&ibuffer_init, (token_t)&two_drop, + (token_t)&address_instance_data } +}; + +int +run_action(fcode_env_t *env, acf_t acf, int action) +{ + token_t *p = (token_t *)acf; + + if ((p[0] & 1) == 0) { + log_message(MSG_WARN, "run_action: acf: %p @acf: %p not" + " indirect\n", acf, p[0]); + return (1); + } + + p = (token_t *)(p[0] & ~1); + + if (action >= p[1] || action < 0) { + log_message(MSG_WARN, "run_action: acf: %p action: %d" + " out of range: 0-%d\n", acf, action, (int)p[1]); + return (1); + } + + if (p[0] == (token_t)&do_default_action) { + fstack_t d; + + d = (fstack_t)p[action+2]; + PUSH(DS, d); + execute(env); + return (0); + } + log_message(MSG_WARN, "run_action: acf: %p/%p not default action\n", + acf, p[0]); + return (1); +} + +void +do_default_action(fcode_env_t *env) +{ + acf_t a; + + CHECK_DEPTH(env, 1, "do_default_action"); + a = (acf_t)TOS; + (void) run_action(env, (a-1), 0); +} + +void +do_set_action(fcode_env_t *env) +{ + acf_t a = (acf_t)TOS; + + CHECK_DEPTH(env, 1, "do_set_action"); + TOS += sizeof (acf_t); + (void) run_action(env, a, 1); +} + +void +action_colon(fcode_env_t *env) +{ + token_roundup(env, "action_colon"); + env->action_ptr[env->action_count] = (token_t)HERE; + COMPILE_TOKEN(&do_colon); + env->action_count++; + env->state |= 1; +} + +void +actions(fcode_env_t *env) +{ + int n; + token_t *d; + + token_roundup(env, "actions"); + d = (token_t *)HERE; + *d++ = (token_t)&do_default_action; + n = (int)POP(DS); + *d++ = n; + env->num_actions = n; + env->action_count = 0; + env->action_ptr = d; + d += n; + set_here(env, (uchar_t *)d, "actions"); +} + +void +install_actions(fcode_env_t *env, token_t *table) +{ + acf_t *dptr; + token_t p; + + dptr = (acf_t *)LINK_TO_ACF(env->lastlink); + p = (token_t)table; + p -= (sizeof (token_t) + sizeof (acf_t)); + *dptr = (acf_t)(p | 1); +} + +void +use_actions(fcode_env_t *env) +{ + if (env->state) { + TODO; /* use-actions in compile state. */ + } else { + install_actions(env, env->action_ptr); + } +} + +void +perform_action(fcode_env_t *env) +{ + int n; + acf_t a; + + CHECK_DEPTH(env, 2, "perform_action"); + n = POP(DS); + a = (acf_t)POP(DS); + PUSH(DS, (fstack_t)ACF_TO_BODY(a)); + + if (run_action(env, a, n)) { + system_message(env, "Bad Object action"); + } +} + +void +define_actions(fcode_env_t *env, int n, token_t *array) +{ + int a; + + PUSH(DS, (fstack_t)n); + actions(env); + + a = 0; + while (n--) { + action_colon(env); + COMPILE_TOKEN(&array[a]); + env->state |= 8; + semi(env); + a++; + } +} + +/* + * This is for things like my-self which have meaning to the + * forth engine but I don't want to turn them into standard forth values + * that would make the 'C' variables hard to understand, instead these + * 'global' state variables will act directly upon the native 'C' structures. + */ + +void +set_internal_value_actions(fcode_env_t *env) +{ + ASSERT(value_actions[2]); + install_actions(env, value_actions[2]); +} + +void +set_value_actions(fcode_env_t *env, int which) +{ + ASSERT((which == 0) || (which == 1)); + ASSERT(value_actions[which]); + install_actions(env, value_actions[which]); +} + +void +set_defer_actions(fcode_env_t *env, int which) +{ + ASSERT((which == 0) || (which == 1)); + ASSERT(value_actions[which+3]); + install_actions(env, value_actions[which+3]); +} + +void +set_buffer_actions(fcode_env_t *env, int which) +{ + ASSERT((which == 0) || (which == 1)); + ASSERT(value_actions[which+5]); + install_actions(env, value_actions[which+5]); +} + +#if defined(DEBUG) + +void +do_get(fcode_env_t *env) +{ + PUSH(DS, 0); + perform_action(env); +} + +void +do_set(fcode_env_t *env) +{ + PUSH(DS, 1); + perform_action(env); +} + +void +do_addr(fcode_env_t *env) +{ + PUSH(DS, 2); + perform_action(env); +} + +void +dump_actions(fcode_env_t *env) +{ + int i; + for (i = 0; i < NUM_DEFAULT_ACTIONS; i++) { + log_message(MSG_INFO, "Action Set: %d = %p\n", i, + value_actions[i]); + } +} +#endif /* DEBUG */ + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + int i; + + ASSERT(env); + NOTICE; + + for (i = 0; i < NUM_DEFAULT_ACTIONS; i++) { + define_actions(env, 3, value_defines[i]); + value_actions[i] = env->action_ptr; + } + +#if defined(DEBUG) + FORTH(0, "get", do_get); + FORTH(0, "set", do_set); + FORTH(0, "addr", do_addr); + FORTH(0, "dump-actions", dump_actions); + FORTH(IMMEDIATE, "actions", actions); + FORTH(IMMEDIATE, "use-actions", use_actions); + FORTH(IMMEDIATE, "action:", action_colon); + FORTH(0, "perform-action", perform_action); +#endif /* DEBUG */ +} diff --git a/usr/src/lib/efcode/engine/alarm.c b/usr/src/lib/efcode/engine/alarm.c new file mode 100644 index 0000000000..c9d4550a9d --- /dev/null +++ b/usr/src/lib/efcode/engine/alarm.c @@ -0,0 +1,101 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> +#include <fcode/private.h> + +/* + * 'user-abort' Fcode + */ +void +user_abort(fcode_env_t *env) +{ + forth_abort(env, "user-abort called"); +} + +static fstack_t alarm_xt; +static fstack_t alarm_ms; +static fcode_env_t *alarm_env; + +static void +catch_alarm(int signo) +{ + fcode_env_t *env = alarm_env; + + if (env && alarm_xt && alarm_ms) { + PUSH(DS, alarm_xt); + execute(env); + signal(SIGALRM, catch_alarm); + alarm((alarm_ms + 999)/1000); + } +} + +/* + * 'alarm' Fcode + */ +void +do_alarm(fcode_env_t *env) +{ + fstack_t ms, xt; + + CHECK_DEPTH(env, 2, "alarm"); + ms = POP(DS); + xt = POP(DS); + if (ms == 0) { + alarm(0); + signal(SIGALRM, SIG_DFL); + alarm_xt = 0; + alarm_ms = 0; + alarm_env = 0; + } else { + signal(SIGALRM, catch_alarm); + alarm_xt = xt; + alarm_ms = ms; + alarm_env = env; + alarm((ms + 999)/1000); + } +} + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + ASSERT(env); + NOTICE; + + P1275(0x213, 0, "alarm", do_alarm); + + P1275(0x219, 0, "user-abort", user_abort); +} diff --git a/usr/src/lib/efcode/engine/cleanup.c b/usr/src/lib/efcode/engine/cleanup.c new file mode 100644 index 0000000000..898924f33a --- /dev/null +++ b/usr/src/lib/efcode/engine/cleanup.c @@ -0,0 +1,52 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +#pragma fini(_fini) + +static void +_fini(void) +{ + fcode_env_t *env = initial_env; + + ASSERT(env); + + debug_msg(DEBUG_EXIT_WORDS|DEBUG_TOKEN_USAGE, + "Dumping interpretter state\n"); + + DEBUGF(EXIT_WORDS, dump_words(env)); + DEBUGF(TOKEN_USAGE, verify_usage(env)); + + destroy_environment(env); +} diff --git a/usr/src/lib/efcode/engine/debug.c b/usr/src/lib/efcode/engine/debug.c new file mode 100644 index 0000000000..bcdd238b94 --- /dev/null +++ b/usr/src/lib/efcode/engine/debug.c @@ -0,0 +1,1601 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2000-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#include <unistd.h> +#include <errno.h> +#include <ctype.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +#ifndef DEBUG_LVL +#define DEBUG_LVL 0 +#endif + +struct bitab { + token_t bi_ptr; + char *bi_name; + int bi_type; +}; + +struct bitab *lookup_builtin(token_t); + +static int debug_level = DEBUG_LVL; + +void +set_interpreter_debug_level(long lvl) +{ + debug_level = lvl; +} + +long +get_interpreter_debug_level(void) +{ + return (debug_level); +} + +void +output_data_stack(fcode_env_t *env, int msglevel) +{ + int i; + + log_message(msglevel, "( "); + if (DS > env->ds0) { + for (i = 0; i < (DS - env->ds0); i++) + log_message(msglevel, "%llx ", + (uint64_t)(env->ds0[i + 1])); + } else + log_message(msglevel, "<empty> "); + log_message(msglevel, ") "); +} + +void +output_return_stack(fcode_env_t *env, int show_wa, int msglevel) +{ + int i; + int anyout = 0; + + log_message(msglevel, "R:( "); + if (show_wa) { + log_message(msglevel, "%s ", + acf_backup_search(env, (acf_t)WA)); + anyout++; + } + if (IP) { + anyout++; + log_message(msglevel, "%s ", acf_backup_search(env, IP)); + } + for (i = (RS - env->rs0) - 1; i > 0; i--) { + anyout++; + log_message(msglevel, "%s ", + acf_backup_search(env, (acf_t)env->rs0[i+1])); + } + if (!anyout) + log_message(msglevel, "<empty> "); + log_message(msglevel, ") "); +} + +void +dump_comma(fcode_env_t *env, char *type) +{ + xforth_t d; + + if (strcmp(type, "x,") == 0) + d = peek_xforth(env); + else + d = TOS; + log_message(MSG_FC_DEBUG, "%s %p, %llx\n", type, HERE, (uint64_t)d); +} + +static int ndebug_names; +#define MAXDEBUG_NAMES 10 +static char *debug_names[MAXDEBUG_NAMES]; + +static int ndebug_acfs; +#define MAXDEBUG_ACFS 10 +static acf_t debug_acfs[MAXDEBUG_ACFS]; + +void +add_debug_acf(fcode_env_t *env, acf_t acf) +{ + int i; + + for (i = 0; i < ndebug_acfs; i++) + if (acf == debug_acfs[i]) + return; + + if (!within_dictionary(env, acf)) + log_message(MSG_ERROR, "Can't debug builtin\n"); + else if (ndebug_acfs >= MAXDEBUG_ACFS) + log_message(MSG_ERROR, "Too many debug ACF's\n"); + else { + debug_acfs[ndebug_acfs++] = acf; + *LINK_TO_FLAGS(ACF_TO_LINK(acf)) |= FLAG_DEBUG; + } +} + +static void +paren_debug(fcode_env_t *env) +{ + acf_t acf; + + acf = (acf_t)POP(DS); + if (!within_dictionary(env, acf)) { + log_message(MSG_INFO, "acf: %llx not in dictionary\n", + (uint64_t)acf); + return; + } + if ((acf_t)_ALIGN(acf, token_t) != acf) { + log_message(MSG_INFO, "acf: %llx not aligned\n", + (uint64_t)acf); + return; + } + if (*acf != (token_t)(&do_colon)) { + log_message(MSG_INFO, "acf: %llx not a colon-def\n", + (uint64_t)acf); + return; + } + add_debug_acf(env, acf); +} + +static void +debug(fcode_env_t *env) +{ + fstack_t d; + char *word; + acf_t acf; + + parse_word(env); + dollar_find(env); + d = POP(DS); + if (d) { + acf = (acf_t)POP(DS); + add_debug_acf(env, acf); + } else if (ndebug_names >= MAXDEBUG_NAMES) { + log_message(MSG_ERROR, "Too many forward debug words\n"); + two_drop(env); + } else { + word = pop_a_duped_string(env, NULL); + log_message(MSG_INFO, "Forward defined word: %s\n", word); + debug_names[ndebug_names++] = word; + } +} + +/* + * Eliminate dups and add vocabulary forth to end if not already on list. + */ +static void +order_to_dict_list(fcode_env_t *env, token_t *order[]) +{ + int i, j, norder = 0; + + if (env->current) + order[norder++] = env->current; + for (i = env->order_depth; i >= 0; i--) { + for (j = 0; j < norder && order[j] != env->order[i]; j++) + ; + if (j == norder) + order[norder++] = env->order[i]; + } + for (j = 0; j < norder && order[j] != (token_t *)&env->forth_voc_link; + j++) + ; + if (j == norder) + order[norder++] = (token_t *)&env->forth_voc_link; + order[norder] = NULL; +} + +static acf_t +search_all_dictionaries(fcode_env_t *env, + acf_t (*fn)(fcode_env_t *, acf_t, void *), + void *arg) +{ + token_t *order[MAX_ORDER+1]; + int i; + token_t *dptr; + acf_t acf; + + order_to_dict_list(env, order); + for (i = 0; (dptr = order[i]) != NULL; i++) { + for (dptr = (token_t *)(*dptr); dptr; + dptr = (token_t *)(*dptr)) + if ((acf = (*fn)(env, LINK_TO_ACF(dptr), arg)) != NULL) + return (acf); + } + return (NULL); +} + +char * +acf_to_str(acf_t acf) +{ + static char msg[(sizeof (acf) * 2) + 3]; + + sprintf(msg, "(%08p)", acf); + return (msg); +} + +char * +get_name_or_acf(token_t *dptr) +{ + char *name; + + if ((name = get_name(dptr)) != NULL) + return (name); + return (acf_to_str(LINK_TO_ACF(dptr))); +} + +static void +output_acf_name(acf_t acf) +{ + char *name; + token_t *dptr; + static int acf_count = 0; + + if (acf == NULL) { + if (acf_count) + log_message(MSG_INFO, "\n"); + acf_count = 0; + return; + } + dptr = ACF_TO_LINK(acf); + if ((name = get_name(dptr)) == NULL) + name = "<noname>"; + + log_message(MSG_INFO, "%24s (%08p)", name, acf); + if (++acf_count >= 2) { + log_message(MSG_INFO, "\n"); + acf_count = 0; + } else + log_message(MSG_INFO, " "); +} + +static void +dot_debug(fcode_env_t *env) +{ + int i; + token_t *dptr; + + if (ndebug_names == 0) + log_message(MSG_INFO, "No forward debug words\n"); + else { + for (i = 0; i < ndebug_names; i++) + log_message(MSG_INFO, "%s Forward\n", debug_names[i]); + } + if (ndebug_acfs == 0) + log_message(MSG_INFO, "No debug words\n"); + else { + for (i = 0; i < ndebug_acfs; i++) + log_message(MSG_INFO, "%s\n", + get_name_or_acf(ACF_TO_LINK(debug_acfs[i]))); + } +} + +static void +do_undebug(fcode_env_t *env, char *name) +{ + int i; + + for (i = 0; i < ndebug_names; i++) { + if (strcmp(debug_names[i], name) == 0) { + log_message(MSG_INFO, "Undebugging forward word %s\n", + name); + FREE(debug_names[i]); + for (i++; i < ndebug_names; i++) + debug_names[i - 1] = debug_names[i]; + ndebug_names--; + break; + } + } +} + +static void +undebug(fcode_env_t *env) +{ + fstack_t d; + acf_t acf; + flag_t *flagp; + char *name; + int i, j; + + parse_word(env); + two_dup(env); + dollar_find(env); + d = POP(DS); + if (d) { + acf = (acf_t)POP(DS); + flagp = LINK_TO_FLAGS(ACF_TO_LINK(acf)); + if ((*flagp & FLAG_DEBUG) == 0) + log_message(MSG_WARN, "Word not debugged?\n"); + else { + log_message(MSG_INFO, "Undebugging acf: %p\n", acf); + *flagp &= ~FLAG_DEBUG; + for (i = 0; i < ndebug_acfs; i++) { + if (debug_acfs[i] == acf) { + for (j = i + 1; j < ndebug_acfs; j++) + debug_acfs[j-1] = debug_acfs[j]; + ndebug_acfs--; + break; + } + } + } + } else + two_drop(env); + name = pop_a_string(env, NULL); + do_undebug(env, name); +} + +int +name_is_debugged(fcode_env_t *env, char *name) +{ + int i; + + if (ndebug_names <= 0) + return (0); + for (i = 0; i < ndebug_names; i++) + if (strcmp(debug_names[i], name) == 0) + return (1); + return (0); +} + +/* + * This is complicated by being given ACF's to temporary compile words which + * don't have a header. + */ +int +is_debug_word(fcode_env_t *env, acf_t acf) +{ + flag_t *flagp; + int i; + + /* check to see if any words are being debugged */ + if (ndebug_acfs == 0) + return (0); + + /* only words in dictionary can be debugged */ + if (!within_dictionary(env, acf)) + return (0); + + /* check that word has "FLAG_DEBUG" on */ + flagp = LINK_TO_FLAGS(ACF_TO_LINK(acf)); + if ((*flagp & FLAG_DEBUG) == 0) + return (0); + + /* look in table of debug acf's */ + for (i = 0; i < ndebug_acfs; i++) + if (debug_acfs[i] == acf) + return (1); + return (0); +} + +#define MAX_DEBUG_STACK 100 +token_t debug_low[MAX_DEBUG_STACK], debug_high[MAX_DEBUG_STACK]; +int debug_prev_level[MAX_DEBUG_STACK]; +int debug_curr_level[MAX_DEBUG_STACK]; +int ndebug_stack = 0; + +void +debug_set_level(fcode_env_t *env, int level) +{ + debug_curr_level[ndebug_stack - 1] = level; + set_interpreter_debug_level(level); +} + +token_t +find_semi_in_colon_def(fcode_env_t *env, acf_t acf) +{ + for (; within_dictionary(env, acf); acf++) + if (*acf == (token_t)(&semi_ptr)) + return ((token_t)acf); + return (0); +} + +void +check_for_debug_entry(fcode_env_t *env) +{ + int top; + + if (is_debug_word(env, WA) && ndebug_stack < MAX_DEBUG_STACK) { + top = ndebug_stack++; + debug_prev_level[top] = get_interpreter_debug_level(); + debug_low[top] = (token_t)WA; + if (*WA == (token_t)(&do_colon)) { + debug_high[top] = + find_semi_in_colon_def(env, WA); + } else { + debug_high[top] = 0; /* marker... */ + } + debug_set_level(env, DEBUG_STEPPING); + output_step_message(env); + } +} + +void +check_for_debug_exit(fcode_env_t *env) +{ + if (ndebug_stack) { + int top = ndebug_stack - 1; + + if (debug_high[top] == 0) { + set_interpreter_debug_level(debug_prev_level[top]); + ndebug_stack--; + } else if ((token_t)IP >= debug_low[top] && + (token_t)IP <= debug_high[top]) { + set_interpreter_debug_level(debug_curr_level[top]); + } else { + set_interpreter_debug_level(debug_prev_level[top]); + } + } +} + +void +check_semi_debug_exit(fcode_env_t *env) +{ + if (ndebug_stack) { + int top = ndebug_stack - 1; + + if ((token_t)(IP - 1) == debug_high[top]) { + set_interpreter_debug_level(debug_prev_level[top]); + ndebug_stack--; + } + } +} + +/* + * Really entering do_run, since this may be a recursive entry to do_run, + * we need to set the debug level to what it was previously. + */ +int +current_debug_state(fcode_env_t *env) +{ + if (ndebug_stack) { + int top = ndebug_stack - 1; + set_interpreter_debug_level(debug_prev_level[top]); + } + return (ndebug_stack); +} + +void +clear_debug_state(fcode_env_t *env, int oldstate) +{ + if (ndebug_stack && oldstate <= ndebug_stack) { + set_interpreter_debug_level(debug_prev_level[oldstate]); + ndebug_stack = oldstate; + } +} + +void +unbug(fcode_env_t *env) +{ + int i; + token_t *link; + flag_t *flag; + + for (i = ndebug_stack - 1; i >= 0; i--) { + link = ACF_TO_LINK(debug_low[i]); + flag = LINK_TO_FLAGS(link); + *flag &= ~FLAG_DEBUG; + } + clear_debug_state(env, 0); +} + +void +output_vitals(fcode_env_t *env) +{ + log_message(MSG_FC_DEBUG, "IP=%p, *IP=%p, WA=%p, *WA=%p ", IP, + (IP ? *IP : 0), WA, (WA ? *WA : 0)); +} + +int +do_exec_debug(fcode_env_t *env, void *fn) +{ + int dl = debug_level; + int show_wa = 1; + + if ((dl & (DEBUG_EXEC_DUMP_DS | DEBUG_EXEC_DUMP_RS | + DEBUG_EXEC_SHOW_VITALS | DEBUG_EXEC_TRACE | DEBUG_TRACING | + DEBUG_STEPPING)) == 0) + return (0); + + if (dl & DEBUG_STEPPING) { + dl |= DEBUG_EXEC_DUMP_DS; + } + if (dl & (DEBUG_STEPPING | DEBUG_EXEC_TRACE)) { + log_message(MSG_FC_DEBUG, "%-15s ", acf_to_name(env, WA)); + show_wa = 0; + } + if (dl & DEBUG_EXEC_DUMP_DS) + output_data_stack(env, MSG_FC_DEBUG); + if (dl & DEBUG_EXEC_DUMP_RS) + output_return_stack(env, show_wa, MSG_FC_DEBUG); + if (dl & DEBUG_EXEC_SHOW_VITALS) + output_vitals(env); + if (dl & DEBUG_TRACING) + do_fclib_trace(env, (void *) fn); + log_message(MSG_FC_DEBUG, "\n"); + if (dl & DEBUG_STEPPING) + return (do_fclib_step(env)); + return (0); +} + +static void +smatch(fcode_env_t *env) +{ + int len; + char *str, *p; + + if ((str = parse_a_string(env, &len)) == NULL) + log_message(MSG_INFO, "smatch: no string\n"); + else { + for (p = (char *)env->base; p < (char *)HERE; p++) + if (memcmp(p, str, len) == 0) + log_message(MSG_DEBUG, "%p\n", p); + } +} + +void +check_vitals(fcode_env_t *env) +{ + int i; + token_t *dptr; + + dptr = env->current; + if (*dptr && !within_dictionary(env, (uchar_t *)*dptr)) + log_message(MSG_ERROR, "Current: %p outside dictionary\n", + *dptr); + for (i = env->order_depth; i >= 0; i--) { + dptr = env->order[i]; + if (!dptr) + continue; + if (*dptr && !within_dictionary(env, (uchar_t *)*dptr)) + log_message(MSG_ERROR, "Order%d: %p outside" + " dictionary\n", i, *dptr); + } + if (HERE < env->base || HERE >= env->base + dict_size) { + log_message(MSG_ERROR, "HERE: %p outside range\n", HERE); + } + if (DS < env->ds0 || DS >= &env->ds0[stack_size]) { + forth_abort(env, "DS: %p outside range\n", DS); + } + if (RS < env->rs0 || RS >= &env->rs0[stack_size]) { + log_message(MSG_ERROR, "RS: %p outside range\n", RS); + RS = env->rs0; + } + if (IP && !within_dictionary(env, IP)) + log_message(MSG_ERROR, "IP: %p outside dictionary\n", IP); + if (!within_dictionary(env, (void *)env->forth_voc_link)) + log_message(MSG_ERROR, "forth_voc_link: %p outside" + " dictionary\n", env->forth_voc_link); +} + +static void +dump_table(fcode_env_t *env) +{ + int i; + + for (i = 0; i < MAX_FCODE; i++) { + if (*(env->table[i].apf) != (token_t)(&f_error)) { + log_message(MSG_DEBUG, "Token: %4x %32s acf = %8p," + " %8p\n", i, env->table[i].name, env->table[i].apf, + *(env->table[i].apf)); + } + } + log_message(MSG_DEBUG, "%d FCODES implemented\n", fcode_impl_count); +} + +void +verify_usage(fcode_env_t *env) +{ + int i, untested = 0; + + for (i = 0; i < MAX_FCODE; i++) { + int verify; + + verify = env->table[i].flags & (ANSI_WORD|P1275_WORD); + if ((verify) && +#ifdef DEBUG + (env->table[i].usage == 0) && +#endif + (env->table[i].apf)) { + log_message(MSG_DEBUG, + "Untested: %4x %32s acf = %8p, %8p\n", i, + env->table[i].name, env->table[i].apf, + *(env->table[i].apf)); + untested++; + } + } + if (untested) + log_message(MSG_DEBUG, "%d untested tokens\n", untested); +} + +static void +debugf(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)&debug_level); +} + +static void +control(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)&env->control); +} + +struct bittab { + int b_bitval; + char *b_bitname; +} bittab[] = { + DEBUG_CONTEXT, "context", + DEBUG_BYTELOAD_DS, "byteload-ds", + DEBUG_BYTELOAD_RS, "byteload-rs", + DEBUG_BYTELOAD_TOKENS, "byteload-tokens", + DEBUG_NEW_TOKEN, "new-token", + DEBUG_EXEC_TRACE, "exec-trace", + DEBUG_EXEC_SHOW_VITALS, "exec-show-vitals", + DEBUG_EXEC_DUMP_DS, "exec-dump-ds", + DEBUG_EXEC_DUMP_RS, "exec-dump-rs", + DEBUG_COMMA, "comma", + DEBUG_HEADER, "header", + DEBUG_EXIT_WORDS, "exit-words", + DEBUG_EXIT_DUMP, "exit-dump", + DEBUG_DUMP_TOKENS, "dump-tokens", + DEBUG_COLON, "colon", + DEBUG_NEXT_VITALS, "next-vitals", + DEBUG_VOC_FIND, "voc-find", + DEBUG_DUMP_DICT_TOKENS, "dump-dict-tokens", + DEBUG_TOKEN_USAGE, "token-usage", + DEBUG_DUMP_TOKEN_TABLE, "dump-token-table", + DEBUG_SHOW_STACK, "show-stack", + DEBUG_SHOW_RS, "show-rs", + DEBUG_TRACING, "tracing", + DEBUG_TRACE_STACK, "trace-stack", + DEBUG_CALL_METHOD, "call-method", + DEBUG_ACTIONS, "actions", + DEBUG_STEPPING, "stepping", + DEBUG_REG_ACCESS, "reg-access", + DEBUG_ADDR_ABUSE, "addr-abuse", + DEBUG_FIND_FCODE, "find-fcode", + DEBUG_UPLOAD, "upload", + 0 +}; + +void +debug_flags_to_output(fcode_env_t *env, int flags) +{ + int first = 1, i; + + for (i = 0; bittab[i].b_bitval != 0; i++) + if (bittab[i].b_bitval & flags) { + if (!first) + log_message(MSG_INFO, ","); + first = 0; + log_message(MSG_INFO, bittab[i].b_bitname); + } + if (first) + log_message(MSG_INFO, "<empty>"); + log_message(MSG_INFO, "\n"); +} + +static void +dot_debugf(fcode_env_t *env) +{ + debug_flags_to_output(env, debug_level); +} + +static void +debugf_qmark(fcode_env_t *env) +{ + debug_flags_to_output(env, 0xffffffff); +} + +int +debug_flags_to_mask(char *str) +{ + int flags = 0; + char *p; + int i; + + if (isdigit(*str)) { + if (*str == '0') { + str++; + if (*str == 'x' || *str == 'X') { + sscanf(str + 1, "%x", &flags); + } else + sscanf(str, "%o", &flags); + } else + sscanf(str, "%d", &flags); + return (flags); + } + if (strcmp(str, "clear") == 0) + return (0); + if (strcmp(str, "all") == 0) + return (0xffffffff & ~DEBUG_STEPPING); + if (*str) { + do { + if (p = strchr(str, ',')) + *p++ = '\0'; + for (i = 0; bittab[i].b_bitname != 0; i++) + if (strcmp(str, bittab[i].b_bitname) == 0) { + flags |= bittab[i].b_bitval; + break; + } + if (bittab[i].b_bitname == 0) + log_message(MSG_WARN, + "Unknown debug flag: '%s'\n", str); + str = p; + } while (p); + } + return (flags); +} + +static void +set_debugf(fcode_env_t *env) +{ + char *str; + + str = parse_a_string(env, NULL); + debug_level = debug_flags_to_mask(str); +} + +static acf_t +show_a_word(fcode_env_t *env, acf_t acf, void *arg) +{ + static int nshow_words = 0; + + if (acf == NULL) { + if (nshow_words > 0) { + log_message(MSG_DEBUG, "\n"); + nshow_words = 0; + } + return (NULL); + } + log_message(MSG_DEBUG, "%15s ", get_name_or_acf(ACF_TO_LINK(acf))); + nshow_words++; + if (nshow_words >= 4) { + log_message(MSG_DEBUG, "\n"); + nshow_words = 0; + } + return (NULL); +} + +void +words(fcode_env_t *env) +{ + (void) search_all_dictionaries(env, show_a_word, NULL); + (void) show_a_word(env, NULL, NULL); +} + +static acf_t +dump_a_word(fcode_env_t *env, acf_t acf, void *arg) +{ + output_acf_name(acf); + return (NULL); +} + +void +dump_words(fcode_env_t *env) +{ + (void) search_all_dictionaries(env, dump_a_word, NULL); + output_acf_name(NULL); +} + +static void +dump_line(uchar_t *ptr) +{ + uchar_t *byte; + int i; + + log_message(MSG_INFO, "%p ", (uint32_t)ptr); + for (i = 0, byte = ptr; i < 16; i++) { + if (i == 8) + log_message(MSG_INFO, " "); + log_message(MSG_INFO, "%02.2x ", *byte++); + } + log_message(MSG_INFO, " "); + for (i = 0, byte = ptr; i < 16; i++, byte++) { + log_message(MSG_INFO, "%c", + ((*byte < 0x20) || (*byte > 0x7f)) ? '.' : *byte); + } + log_message(MSG_INFO, "\n"); +} + +void +dump_dictionary(fcode_env_t *env) +{ + uchar_t *ptr; + + log_message(MSG_INFO, "Dictionary dump: base: %p\n", env->base); + for (ptr = (uchar_t *)(((long)(env->base)) & ~0xf); ptr < HERE; + ptr += 16) + dump_line(ptr); +} + +static char * +acf_to_fcode_name(fcode_env_t *env, acf_t acf) +{ + int i; + + for (i = 0; i < MAX_FCODE; i++) + if (env->table[i].apf == acf) + return (env->table[i].name); + return (NULL); +} + +static acf_t +acf_match(fcode_env_t *env, acf_t sacf, void *macf) +{ + if (sacf == (acf_t)macf) + return (sacf); + return (NULL); +} + +/* + * Given an ACF, return ptr to name or "unknown" string. + */ +char * +acf_to_name(fcode_env_t *env, acf_t acf) +{ + struct bitab *bip; + static char name_buf[256]; + uchar_t *p, *np; + int i, n; + + if (!within_dictionary(env, acf)) { + if ((bip = lookup_builtin((token_t)acf)) != NULL) + return (bip->bi_name); + return (NULL); + } + return (get_name_or_acf(ACF_TO_LINK(acf))); +} + +int +within_dictionary(fcode_env_t *env, void *addr) +{ + return ((uchar_t *)addr >= env->base && + (uchar_t *)addr < env->base + dict_size); +} + +static int +within_word(fcode_env_t *env, acf_t acf, acf_t wacf) +{ + if (acf == wacf || acf + 1 == wacf) + return (1); + if (*acf == (token_t)(&do_colon)) { + do { + if (acf == wacf) + return (1); + } while (*acf++ != (token_t)(&semi_ptr)); + } + return (0); +} + +/* + * Given an ACF in the middle of a colon definition, search dictionary towards + * beginning for "colon" acf. If we find a "semi" acf first, we're not in + * the middle of a colon-def (temporary execute?). + */ +char * +acf_backup_search(fcode_env_t *env, acf_t acf) +{ + acf_t nacf; + char *name; + + if ((acf_t)_ALIGN(acf, token_t) == acf && within_dictionary(env, acf)) { + for (nacf = acf; nacf >= (acf_t)env->base; nacf--) + if (*nacf == (token_t)(&do_colon) || + *nacf == (token_t)(&semi_ptr)) + break; + if (nacf >= (acf_t)env->base && *nacf == (token_t)(&do_colon) && + (name = get_name(ACF_TO_LINK(nacf))) != NULL) + return (name); + } + return (acf_to_str(acf)); +} + +/* + * Print out current process's C stack using /usr/proc/bin/pstack + */ +void +ctrace(fcode_env_t *env) +{ + char buf[256]; + FILE *fd; + + log_message(MSG_DEBUG, "Interpreter C Stack:\n"); + sprintf(buf, "/usr/proc/bin/pstack %d", getpid()); + if ((fd = popen(buf, "r")) == NULL) + log_perror(MSG_ERROR, "Can't run: %s", buf); + else { + while (fgets(buf, sizeof (buf), fd)) + log_message(MSG_DEBUG, buf); + fclose(fd); + } +} + +/* + * Dump data, return stacks, try to unthread forth calling stack. + */ +void +ftrace(fcode_env_t *env) +{ + log_message(MSG_DEBUG, "Forth Interpreter Stacks:\n"); + output_data_stack(env, MSG_DEBUG); + output_return_stack(env, 1, MSG_DEBUG); + log_message(MSG_DEBUG, "\n"); +} + +int in_forth_abort; + +/* + * Handle fatal error, if interactive mode, return to ok prompt. + */ +void +forth_abort(fcode_env_t *env, char *fmt, ...) +{ + va_list ap; + char msg[256]; + + if (in_forth_abort) { + log_message(MSG_FATAL, "ABORT: abort within forth_abort\n"); + abort(); + } + in_forth_abort++; + + va_start(ap, fmt); + vsprintf(msg, fmt, ap); + log_message(MSG_ERROR, "ABORT: %s\n", msg); + + if (env) { + ctrace(env); + ftrace(env); + } + + return_to_interact(env); + /* + * If not in interactive mode, return_to_interact just returns. + */ + exit(1); +} + +/* + * Handle fatal system call error + */ +void +forth_perror(fcode_env_t *env, char *fmt, ...) +{ + va_list ap; + char msg[256]; + int save_errno = errno; /* just in case... */ + + va_start(ap, fmt); + vsprintf(msg, fmt, ap); + + forth_abort(env, "%s: %s", msg, strerror(save_errno)); +} + +static void +show_stack(fcode_env_t *env) +{ +#ifdef DEBUG + debug_level ^= DEBUG_SHOW_STACK; +#else + /*EMPTY*/ +#endif +} + +static void +print_bytes_header(int width, int offset) +{ + int i; + + for (i = 0; i < width; i++) + log_message(MSG_INFO, " "); + log_message(MSG_INFO, " "); + for (i = 0; i < 16; i++) { + if (i == 8) + log_message(MSG_INFO, " "); + if (i == offset) + log_message(MSG_INFO, "\\/ "); + else + log_message(MSG_INFO, "%2x ", i); + } + log_message(MSG_INFO, " "); + for (i = 0; i < 16; i++) { + if (i == offset) + log_message(MSG_INFO, "v"); + else + log_message(MSG_INFO, "%x", i); + } + log_message(MSG_INFO, "\n"); +} + +static void +dump(fcode_env_t *env) +{ + uchar_t *data; + int len, offset; + char buf[20]; + + len = POP(DS); + data = (uchar_t *)POP(DS); + offset = ((long)data) & 0xf; + len += offset; + data = (uchar_t *)((long)data & ~0xf); + sprintf(buf, "%p", (uint32_t)data); + print_bytes_header(strlen(buf), offset); + for (len += offset; len > 0; len -= 16, data += 16) + dump_line(data); +} + +static acf_t +do_sifting(fcode_env_t *env, acf_t acf, void *pat) +{ + char *name; + + if ((name = get_name(ACF_TO_LINK(acf))) != NULL && strstr(name, pat)) + output_acf_name(acf); + return (NULL); +} + +static void +sifting(fcode_env_t *env) +{ + char *pat; + + if ((pat = parse_a_string(env, NULL)) != NULL) { + (void) search_all_dictionaries(env, do_sifting, pat); + output_acf_name(NULL); + } +} + +void +print_level(int level, int *doprint) +{ + int i; + + if (*doprint) { + log_message(MSG_DEBUG, "\n "); + for (i = 0; i < level; i++) + log_message(MSG_DEBUG, " "); + *doprint = 0; + } +} + +#define BI_QUOTE 1 +#define BI_BLIT 2 +#define BI_BDO 3 +#define BI_QDO 4 +#define BI_BR 5 +#define BI_QBR 6 +#define BI_BOF 7 +#define BI_LOOP 8 +#define BI_PLOOP 9 +#define BI_TO 10 +#define BI_SEMI 11 +#define BI_COLON 12 +#define BI_NOOP 13 +#define BI_NOTYET 14 /* unimplented in "see" */ + +struct bitab bitab[] = { + (token_t)("e_ptr), "\"", BI_QUOTE, + (token_t)(&blit_ptr), "blit", BI_BLIT, + (token_t)(&do_bdo_ptr), "do", BI_BDO, + (token_t)(&do_bqdo_ptr), "?do", BI_QDO, + (token_t)(&bbranch_ptrs[0]), "br", BI_BR, + (token_t)(&bbranch_ptrs[1]), "qbr", BI_QBR, + (token_t)(&bbranch_ptrs[2]), "bof", BI_BOF, + (token_t)(&do_loop_ptr), "loop", BI_LOOP, + (token_t)(&do_ploop_ptr), "+loop", BI_PLOOP, + (token_t)(&to_ptr), "to", BI_NOOP, + (token_t)(&semi_ptr), ";", BI_SEMI, + (token_t)(&do_colon), ":", BI_COLON, + (token_t)(&tlit_ptr), "[']", BI_NOOP, + (token_t)(&do_leave_ptr), "leave", BI_NOTYET, + (token_t)(&create_ptr), "create", BI_NOTYET, + (token_t)(&does_ptr), "does>", BI_NOTYET, + (token_t)(&value_defines[0][0]), "a.@", BI_NOTYET, + (token_t)(&value_defines[0][1]), "a.!", BI_NOTYET, + (token_t)(&value_defines[0][2]), "a.nop", BI_NOTYET, + (token_t)(&value_defines[1][0]), "a.i@", BI_NOTYET, + (token_t)(&value_defines[1][1]), "a.i!", BI_NOTYET, + (token_t)(&value_defines[1][2]), "a.iad", BI_NOTYET, + (token_t)(&value_defines[2][0]), "a.defer", BI_NOTYET, + (token_t)(&value_defines[2][1]), "a.@", BI_NOTYET, + (token_t)(&value_defines[2][2]), "a.nop", BI_NOTYET, + (token_t)(&value_defines[3][0]), "a.defexec", BI_NOTYET, + (token_t)(&value_defines[3][1]), "a.iset", BI_NOTYET, + (token_t)(&value_defines[3][2]), "a.iad", BI_NOTYET, + (token_t)(&value_defines[4][0]), "a.binit", BI_NOTYET, + (token_t)(&value_defines[4][1]), "a.2drop", BI_NOTYET, + (token_t)(&value_defines[4][2]), "a.nop", BI_NOTYET, + (token_t)(&value_defines[5][0]), "a.ibinit", BI_NOTYET, + (token_t)(&value_defines[5][1]), "a.2drop", BI_NOTYET, + (token_t)(&value_defines[5][2]), "a.iad", BI_NOTYET, + 0 +}; + +struct bitab * +lookup_builtin(token_t builtin) +{ + int i; + + for (i = 0; bitab[i].bi_ptr; i++) + if (bitab[i].bi_ptr == builtin) + return (&bitab[i]); + return (NULL); +} + +static void +paren_see(fcode_env_t *env) +{ + acf_t save_acf = (acf_t)POP(DS); + acf_t acf = save_acf; + int i, n, pass; + token_t brtab[30], thentab[30], brstk[30]; + int nbrtab = 0, nthentab = 0, nbrstk = 0; + uchar_t *p; + int level = 0, doprintlevel = 1, nthen; + struct bitab *bip; + token_t last_lit = 0, case_lit = 0, endof_loc = 0, endcase_loc = 0; + + if ((bip = lookup_builtin(*acf)) == NULL || + bip->bi_type != BI_COLON) { + if (bip = lookup_builtin((token_t)acf)) + log_message(MSG_INFO, "%s: builtin\n", bip->bi_name); + else + log_message(MSG_INFO, "%s: builtin\n", + acf_to_name(env, acf)); + return; + } + log_message(MSG_INFO, ": %s", acf_to_name(env, acf)); + for (pass = 0; pass < 2; pass++) { + acf = save_acf; + for (acf++; ; acf++) { + if (pass) { + print_level(level, &doprintlevel); + for (nthen = 0; nthentab > 0 && + thentab[nthentab-1] == (token_t)acf; + nthentab--) + nthen++; + if (nthen) { + level -= nthen; + doprintlevel = 1; + print_level(level, &doprintlevel); + for (i = 0; i < nthen; i++) + log_message(MSG_INFO, "then "); + } + print_level(level, &doprintlevel); + for (i = 0; i < nbrtab; i += 2) + if ((token_t)acf == brtab[i]) { + log_message(MSG_INFO, "begin "); + brstk[nbrstk++] = brtab[i+1]; + level++; + doprintlevel = 1; + } + print_level(level, &doprintlevel); + if (case_lit == (token_t)acf) { + log_message(MSG_INFO, "case "); + doprintlevel = 1; + print_level(level, &doprintlevel); + } + if (endof_loc == (token_t)acf) { + log_message(MSG_INFO, "endof "); + doprintlevel = 1; + print_level(level, &doprintlevel); + } + if (endcase_loc == (token_t)acf) { + doprintlevel = 1; + print_level(level, &doprintlevel); + log_message(MSG_INFO, "endcase "); + } + } + if ((bip = lookup_builtin((token_t)*acf)) == 0) { + last_lit = (token_t)acf; + if (pass) + log_message(MSG_INFO, "%s ", + acf_to_name(env, (acf_t)*acf)); + continue; + } + if (bip->bi_type == BI_SEMI) { + if (pass) { + log_message(MSG_INFO, "\n"); + log_message(MSG_INFO, "%s\n", + bip->bi_name); + } + break; + } + switch (bip->bi_type) { + + case BI_NOOP: + case BI_NOTYET: + if (pass) + log_message(MSG_INFO, "%s ", + bip->bi_name); + break; + + case BI_QUOTE: + if (pass) + log_message(MSG_INFO, "\" "); + acf++; + p = (uchar_t *)acf; + n = *p++; + if (pass) + log_message(MSG_INFO, "%s\" ", p); + p += n + 1; + for (; ((token_t)(p)) & (sizeof (token_t) - 1); + p++) + ; + acf = (acf_t)p; + acf--; + break; + + case BI_BLIT: + acf++; + if (pass) + log_message(MSG_INFO, "%x ", *acf); + break; + + case BI_BDO: + case BI_QDO: + if (pass) { + log_message(MSG_INFO, "%s ", + bip->bi_name); + doprintlevel = 1; + level++; + } + acf++; + break; + + case BI_BR: + acf++; + if (pass) { + if (*acf < (token_t)acf) { + if (nbrstk) { + doprintlevel = 1; + level--; + print_level(level, + &doprintlevel); + log_message(MSG_INFO, + "repeat "); + nbrstk--; + } else + log_message(MSG_INFO, + "[br back?]"); + } else if (nthentab) { + doprintlevel = 1; + print_level(level - 1, + &doprintlevel); + log_message(MSG_INFO, "else "); + doprintlevel = 1; + thentab[nthentab - 1] = *acf; + } + } else { + if (*acf < (token_t)acf) { + brtab[nbrtab++] = *acf; + brtab[nbrtab++] = (token_t)acf; + } + if (endcase_loc == 0 && + case_lit) { + endcase_loc = *acf; + } + } + break; + + case BI_QBR: + acf++; + if (pass) { + if (*acf < (token_t)acf) { + if (nbrstk) { + doprintlevel = 1; + level--; + print_level(level, + &doprintlevel); + log_message(MSG_INFO, + "until "); + nbrstk--; + } else + log_message(MSG_INFO, + "[br back?]"); + } else if (nbrstk > 0 && + *acf >= brstk[nbrstk - 1]) { + doprintlevel = 1; + print_level(level - 1, + &doprintlevel); + log_message(MSG_INFO, + "while "); + doprintlevel = 1; + } else { + log_message(MSG_INFO, "if "); + doprintlevel = 1; + level++; + thentab[nthentab++] = *acf; + } + } else if (*acf < (token_t)acf) { + brtab[nbrtab++] = *acf; + brtab[nbrtab++] = (token_t)acf; + } + break; + + case BI_BOF: + acf++; + if (pass) { + log_message(MSG_INFO, "of "); + endof_loc = *acf; + } else if (case_lit == 0) { + case_lit = last_lit; + } + break; + + case BI_LOOP: + case BI_PLOOP: + if (pass) { + level--; + doprintlevel = 1; + print_level(level, &doprintlevel); + log_message(MSG_INFO, "%s ", + bip->bi_name); + } + acf++; + break; + + default: + log_message(MSG_ERROR, "Invalid builtin %s\n", + bip->bi_name); + } + } + } +} + +static void +see(fcode_env_t *env) +{ + fstack_t d; + + parse_word(env); + dollar_find(env); + d = POP(DS); + if (d) + paren_see(env); + else { + log_message(MSG_WARN, "?"); + two_drop(env); + } +} + +static acf_t +do_dot_calls(fcode_env_t *env, acf_t acf, void *cacf) +{ + token_t *dptr = ACF_TO_LINK(acf); + token_t *wptr = acf; + + if (*wptr == (token_t)(&do_colon)) { + do { + if ((acf_t)(*wptr) == (acf_t)cacf) + output_acf_name(acf); + } while (*wptr++ != (token_t)(&semi_ptr)); + } else if ((acf_t)(*wptr) == cacf) + output_acf_name(acf); + else if (wptr == (token_t *)cacf) + output_acf_name(acf); + return (NULL); +} + +static void +dot_calls(fcode_env_t *env) +{ + acf_t acf = (acf_t)POP(DS); + + search_all_dictionaries(env, do_dot_calls, acf); + output_acf_name(NULL); +} + +static void +dot_pci_space(fcode_env_t *env) +{ + fstack_t d = POP(DS); + + switch ((d >> 24) & 0x3) { + case 0: log_message(MSG_INFO, "Config,"); break; + case 1: log_message(MSG_INFO, "IO,"); break; + case 2: log_message(MSG_INFO, "Memory32,"); break; + case 3: log_message(MSG_INFO, "Memory64,"); break; + } + if (d & 0x80000000) + log_message(MSG_INFO, "Not_reloc,"); + if (d & 0x400000000) + log_message(MSG_INFO, "Prefetch,"); + if (d & 0x200000000) + log_message(MSG_INFO, "Alias,"); + log_message(MSG_INFO, "Bus%d,", (d >> 16) & 0xff); + log_message(MSG_INFO, "Dev%d,", (d >> 11) & 0x1f); + log_message(MSG_INFO, "Func%d,", (d >> 8) & 0x7); + log_message(MSG_INFO, "Reg%x", d & 0xff); + log_message(MSG_INFO, "\n"); +} + +void +fcode_debug(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)(&env->fcode_debug)); +} + +static void +base_addr(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)env->base); +} + +static int mw_valid; +static int mw_size; +static void *mw_addr; +static fstack_t mw_value; +static fstack_t mw_lastvalue; + +static fstack_t +mw_fetch(void) +{ + switch (mw_size) { + case 1: return (*((uint8_t *)mw_addr)); + case 2: return (*((uint16_t *)mw_addr)); + case 4: return (*((uint32_t *)mw_addr)); + case 8: return (*((uint64_t *)mw_addr)); + } + return (0); +} + +void +do_memory_watch(fcode_env_t *env) +{ + fstack_t value; + + if (!mw_valid) + return; + value = mw_fetch(); + if (value != mw_lastvalue) { + if (mw_valid == 1 || mw_value == value) { + log_message(MSG_INFO, + "memory-watch: %p/%d: %llx -> %llx\n", + mw_addr, mw_size, (uint64_t)mw_lastvalue, + (uint64_t)value); + do_fclib_step(env); + } + mw_lastvalue = value; + } +} + +static void +set_memory_watch(fcode_env_t *env, int type, int size, void *addr, + fstack_t value) +{ + switch (size) { + case 1: case 2: case 4: case 8: + break; + default: + log_message(MSG_ERROR, "set_memory_watch: invalid size: %d\n", + size); + return; + } + mw_valid = type; + mw_size = size; + mw_addr = addr; + mw_value = value; + mw_lastvalue = mw_fetch(); +} + +static void +memory_watch(fcode_env_t *env) +{ + int size = POP(DS); + void *addr = (void *)POP(DS); + + set_memory_watch(env, 1, size, addr, 0); +} + +static void +memory_watch_value(fcode_env_t *env) +{ + int size = POP(DS); + void *addr = (void *)POP(DS); + fstack_t value = POP(DS); + + set_memory_watch(env, 2, size, addr, value); +} + +static void +memory_watch_clear(fcode_env_t *env) +{ + mw_valid = 0; +} + +static void +vsearch(fcode_env_t *env) +{ + fstack_t value; + int size = POP(DS); + fstack_t match_value = POP(DS); + uchar_t *toaddr = (uchar_t *)POP(DS); + uchar_t *fromaddr = (uchar_t *)POP(DS); + + log_message(MSG_INFO, "%p to %p by %d looking for %llx\n", fromaddr, + toaddr, size, (uint64_t)match_value); + for (; fromaddr < toaddr; fromaddr += size) { + switch (size) { + case 1: value = *((uint8_t *)fromaddr); break; + case 2: value = *((uint16_t *)fromaddr); break; + case 4: value = *((uint32_t *)fromaddr); break; + case 8: value = *((uint64_t *)fromaddr); break; + default: + log_message(MSG_INFO, "Invalid size: %d\n", size); + return; + } + if (value == match_value) + log_message(MSG_INFO, "%p\n", fromaddr); + } +} + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + ASSERT(env); + NOTICE; + + FORTH(IMMEDIATE, "words", words); + FORTH(IMMEDIATE, "dump-words", dump_words); + FORTH(IMMEDIATE, "dump-dict", dump_dictionary); + FORTH(IMMEDIATE, "dump-table", dump_table); + FORTH(0, "debugf", debugf); + FORTH(0, ".debugf", dot_debugf); + FORTH(0, "set-debugf", set_debugf); + FORTH(0, "debugf?", debugf_qmark); + FORTH(0, "control", control); + FORTH(0, "dump", dump); + FORTH(IMMEDIATE, "showstack", show_stack); + FORTH(IMMEDIATE, "sifting", sifting); + FORTH(IMMEDIATE, "ctrace", ctrace); + FORTH(IMMEDIATE, "ftrace", ftrace); + FORTH(0, "see", see); + FORTH(0, "(see)", paren_see); + FORTH(0, "base-addr", base_addr); + FORTH(0, "smatch", smatch); + FORTH(0, ".calls", dot_calls); + FORTH(0, ".pci-space", dot_pci_space); + FORTH(0, "(debug)", paren_debug); + FORTH(0, "debug", debug); + FORTH(0, ".debug", dot_debug); + FORTH(0, "undebug", undebug); + FORTH(0, "memory-watch", memory_watch); + FORTH(0, "memory-watch-value", memory_watch_value); + FORTH(0, "memory-watch-clear", memory_watch_clear); + FORTH(0, "vsearch", vsearch); +} diff --git a/usr/src/lib/efcode/engine/env.c b/usr/src/lib/efcode/engine/env.c new file mode 100644 index 0000000000..e5d20ec882 --- /dev/null +++ b/usr/src/lib/efcode/engine/env.c @@ -0,0 +1,863 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <ctype.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> + +#include <fcode/private.h> +#include <fcode/log.h> + + +static variable_t verbose_emit; + +void +do_verbose_emit(fcode_env_t *env) +{ + verbose_emit ^= 1; +} + +/* + * Internal "emit". + * Note log_emit gathers up characters and issues a syslog or write to + * error log file if enabled. + */ +void +do_emit(fcode_env_t *env, uchar_t c) +{ + if (verbose_emit) + log_message(MSG_ERROR, "emit(%x)\n", c); + + if (c == '\n') { + env->output_column = 0; + env->output_line++; + } else if (c == '\r') + env->output_column = 0; + else + env->output_column++; + if (isatty(fileno(stdout))) { + if ((c >= 0x20 && c <= 0x7f) || c == '\n' || c == '\r' || + c == '\b') + putchar(c); + else if (c >= 0 && c < 0x20) + printf("@%c", c + '@'); + else + printf("\\%x", c); + fflush(stdout); + } + log_emit(c); +} + +void +system_message(fcode_env_t *env, char *msg) +{ + throw_from_fclib(env, 1, msg); +} + +void +emit(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 1, "emit"); + d = POP(DS); + do_emit(env, d); +} + +#include <sys/time.h> + +/* + * 'key?' - abort if stdin is not a tty. + */ +void +keyquestion(fcode_env_t *env) +{ + struct timeval timeval; + fd_set readfds; + int ret; + + if (isatty(fileno(stdin))) { + FD_ZERO(&readfds); + FD_SET(fileno(stdin), &readfds); + timeval.tv_sec = 0; + timeval.tv_usec = 1000; + ret = select(fileno(stdin) + 1, &readfds, NULL, NULL, &timeval); + if (FD_ISSET(fileno(stdin), &readfds)) + PUSH(DS, TRUE); + else + PUSH(DS, FALSE); + } else + forth_abort(env, "'key?' called in non-interactive mode"); +} + +/* + * 'key' - abort if stdin is not a tty, will block on read if char not avail. + */ +void +key(fcode_env_t *env) +{ + uchar_t c; + + if (isatty(fileno(stdin))) { + read(fileno(stdin), &c, 1); + PUSH(DS, c); + } else + forth_abort(env, "'key' called in non-interactive mode"); +} + +void +type(fcode_env_t *env) +{ + int len; + char *ptr; + + CHECK_DEPTH(env, 2, "type"); + ptr = pop_a_string(env, &len); + while (len--) + do_emit(env, *ptr++); +} + +void +paren_cr(fcode_env_t *env) +{ + do_emit(env, '\r'); +} + +void +fc_crlf(fcode_env_t *env) +{ + do_emit(env, '\n'); +} + +void +fc_num_out(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)(&env->output_column)); +} + +void +fc_num_line(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)(&env->output_line)); +} + +void +expect(fcode_env_t *env) +{ + char *buf, *rbuf; + int len; + + CHECK_DEPTH(env, 2, "expect"); + buf = pop_a_string(env, &len); + read_line(env); + rbuf = pop_a_string(env, NULL); + if (rbuf) { + strcpy(buf, rbuf); + env->span = strlen(buf); + } else + env->span = 0; +} + +void +span(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)&env->span); +} + +void +do_ms(fcode_env_t *env) +{ + fstack_t d; + timespec_t rqtp; + + CHECK_DEPTH(env, 1, "ms"); + d = POP(DS); + if (d) { + rqtp.tv_sec = 0; + rqtp.tv_nsec = d*1000*1000; + nanosleep(&rqtp, 0); + } +} + +void +do_get_msecs(fcode_env_t *env) +{ + struct timeval tp; + long ms; + timespec_t rqtp; + + gettimeofday(&tp, NULL); + ms = (tp.tv_usec/1000) + (tp.tv_sec * 1000); + PUSH(DS, (fstack_t)ms); + rqtp.tv_sec = 0; + rqtp.tv_nsec = 1000*1000; + nanosleep(&rqtp, 0); +} + +#define CMN_MSG_SIZE 256 +#define CMN_MAX_DIGITS 3 + +typedef struct CMN_MSG_T cmn_msg_t; + +struct CMN_MSG_T { + char buf[CMN_MSG_SIZE]; + int level; + int len; + cmn_msg_t *prev; + cmn_msg_t *next; +}; + +typedef struct CMN_FMT_T cmn_fmt_t; + +struct CMN_FMT_T { + int fwidth; /* format field width */ + int cwidth; /* column width specified in format */ + char format; /* format type */ +}; + +static cmn_msg_t *root = NULL; +static int cmn_msg_level = 0; + +/* + * validfmt() + * + * Called by fmt_str() function to validate and extract formatting + * information from the supplied input buffer. + * + * Supported formats are: + * %c - character + * %d - signed decimal + * %x - unsigned hex + * %s - string + * %ld - signed 64 bit data + * %lx - unsigned 64 bit data + * %p - unsigned 64 bit data(pointer) + * %% - print as single "%" character + * + * Return values are: + * 0 - valid formatting + * 1 - invalid formatting found in the input buffer + * -1 - NULL pointer passed in for caller's receptacle + * + * + * For valid formatting, caller's supplied cmn_fmt_t elements are + * filled in: + * fwidth: + * > 0 - returned value is the field width + * < 0 - returned value is negation of field width for + * 64 bit data formats + * cwidth: + * formatted column width(if specified), otherwise 0 + * + * format: + * contains the formatting(single) character + */ +static int +validfmt(char *fmt, cmn_fmt_t *cfstr) +{ + int isll = 0; + int *fwidth, *cwidth; + char *format; + char *dig1, *dig2; + char cdigs[CMN_MAX_DIGITS+1]; + + if (cfstr == NULL) + return (-1); + + fwidth = &cfstr->fwidth; + cwidth = &cfstr->cwidth; + format = &cfstr->format; + *fwidth = *cwidth = 0; + *format = NULL; + dig1 = dig2 = NULL; + + /* check for left justification character */ + if (*fmt == '-') { + fmt++; + (*fwidth)++; + + /* check for column width specification */ + if (isdigit(*fmt)) + dig1 = fmt; /* save ptr to first digit */ + while (isdigit(*fmt)) { + fmt++; + (*fwidth)++; + } + /* if ljust specified w/o size, return format error */ + if (*fwidth == 1) { + return (1); + } + dig2 = fmt; /* save ptr to last digit + 1 */ + } else { + /* check for column width specification */ + if (isdigit(*fmt)) { + dig1 = fmt; /* save ptr to first digit */ + while (isdigit(*fmt)) { + fmt++; + (*fwidth)++; + } + dig2 = fmt; /* save ptr to last digit + 1 */ + } + } + + /* if a column width was specified, save it in caller's struct */ + if (dig1) { + int nbytes; + + nbytes = dig2 - dig1; + /* if too many digits in the width return error */ + if (nbytes > CMN_MAX_DIGITS) + return (1); + strncpy(cdigs, dig1, nbytes); + cdigs[nbytes] = 0; + *cwidth = atoi(cdigs); + } + + /* check for long format specifier */ + if (*fmt == 'l') { + fmt++; + (*fwidth)++; + isll = 1; + } + + /* process by specific format type */ + switch (*fmt) { + case 'c': + case 's': + case '%': + if (isll) + return (1); + case 'd': + case 'x': + *format = *fmt; + (*fwidth)++; + break; + case 'p': + isll = 1; /* uses 64 bit format */ + *format = *fmt; + (*fwidth)++; + break; + default: + return (1); /* unknown format type */ + } + if (isll) { + *fwidth *= -1; + } + return (0); +} + +/* + * fmt_args() + * + * Called by fmt_str() to setup arguments for subsequent snprintf() + * calls. For cases not involving column width limitations, processing + * simply POPs the data stack as required to setup caller's arg(or + * llarg, as appropriate). When a column width is specified for output, + * a temporary buffer is constructed to contain snprintf() generated + * output for the argument. Testing is then performed to determine if + * the specified column width will require truncation of the output. + * If so, truncation of least significant digits is performed as + * necessary, and caller's arg(or llarg) is adjusted to obtain the + * specified column width. + * + */ + +static void +fmt_args(fcode_env_t *env, int cw, int fw, char format, long *arg, + long long *llarg) +{ + char *cbuf; + char snf[3]; + int cbsize; + int cnv = 10, ndigits = 0; + + if (fw > 0) { /* check for normal (not long) formats */ + + /* initialize format string for snprintf call */ + snf[0] = '%'; + snf[1] = format; + snf[2] = 0; + + /* process by format type */ + switch (format) { + case 'x': + cnv = 16; + case 'd': + case 'c': + case 'p': + *arg = POP(DS); + break; + case 's': + POP(DS); + *arg = POP(DS); + break; + case '%': + return; + default: + log_message(MSG_ERROR, + "fmt_args:invalid format type! (%s)\n", + &format); + return; + } + + /* check if a column width was specified */ + if (cw) { + /* allocate a scratch buffer */ + cbsize = 2*(sizeof (long long)) + 1; + cbuf = MALLOC(cbsize); + + if (snprintf(cbuf, cbsize, snf, *arg) < 0) + log_message(MSG_ERROR, + "fmt_args: snprintf output error\n"); + while ((cbuf[ndigits] != NULL) && + (ndigits < cbsize)) + ndigits++; + + /* if truncation is necessary, do it */ + if (ndigits > cw) { + cbuf[cw] = 0; + if (format == 's') { + char *str; + str = (char *)*arg; + str[cw] = 0; + } else + *arg = strtol(cbuf, + (char **)NULL, cnv); + } + free(cbuf); + } + + } else { /* process long formats */ + + *llarg = POP(DS); + + /* check if a column width was specified */ + if (cw) { + /* allocate a scratch buffer */ + cbsize = 2*(sizeof (long long)) + 1; + cbuf = MALLOC(cbsize); + + switch (format) { + case 'p': + cnv = 16; + if (snprintf(cbuf, cbsize, "%p", *llarg) < 0) + log_message(MSG_ERROR, + "fmt_args: snprintf error\n"); + break; + case 'x': + cnv = 16; + if (snprintf(cbuf, cbsize, "%lx", *llarg) < 0) + log_message(MSG_ERROR, + "fmt_args: snprintf error\n"); + break; + case 'd': + if (snprintf(cbuf, cbsize, "%ld", *llarg) < 0) + log_message(MSG_ERROR, + "fmt_args: snprintf error\n"); + break; + default: + log_message(MSG_ERROR, + "invalid long format type! (l%s)\n", + &format); + free(cbuf); + return; + } + while ((cbuf[ndigits] != NULL) && + (ndigits < cbsize)) { + ndigits++; + } + /* if truncation is necessary, do it */ + if (ndigits > cw) { + cbuf[cw] = 0; + *llarg = strtoll(cbuf, (char **)NULL, cnv); + } + free(cbuf); + } + } +} + +/* + * fmt_str() + * + * Extracts text from caller's input buffer, processes explicit + * formatting as necessary, and outputs formatted text to caller's + * receptacle. + * + * env - pointer to caller's fcode environment + * fmt - pointer to caller's input buffr + * fmtbuf - ponter to caller's receptacle buffer + * bsize - size of caller's fmtbuf buffer + * + * This function performs an initial test to determine if caller's + * input buffer contains formatting(specified by presence of "%") + * in the buffer. If so, validfmt() function is called to verify + * the formatting, after which the buffer is processed according + * to the field width specified by validfmt() output. Special + * processing is required when caller's buffer contains a double + * "%" ("%%"), in which case the second "%" is accepted as normal + * text. + */ + +static void +fmt_str(fcode_env_t *env, char *fmt, char *fmtbuf, int bsize) +{ + char tbuf[CMN_MSG_SIZE]; + char *fmptr, *pct; + int l, cw, fw, bytes; + long arg; + long long llarg; + + *fmtbuf = 0; + if ((pct = strchr(fmt, '%')) != 0) { + cmn_fmt_t cfstr; + int vferr; + + l = strlen(pct++); + vferr = validfmt(pct, &cfstr); + if (!vferr) { + fw = cfstr.fwidth; + cw = cfstr.cwidth; + fmptr = &cfstr.format; + } else { + if (vferr < 0) { + log_message(MSG_ERROR, + "fmt_str: NULL ptr supplied to validfmt()\n"); + return; + } + + bytes = pct - fmt; + strncpy(tbuf, fmt, bytes); + strncpy(tbuf+bytes, "%", 1); + strncpy(tbuf+bytes+1, fmt+bytes, 1); + bytes += 2; + tbuf[bytes] = 0; + + log_message(MSG_ERROR, + "fmt_str: invalid format type! (%s)\n", + tbuf+bytes-3); + + strncpy(fmtbuf, tbuf, bsize); + return; + } + + if (fw > 0) { /* process normal (not long) formats */ + bytes = pct - fmt + fw; + strncpy(tbuf, fmt, bytes); + tbuf[bytes] = 0; + } else { + /* if here, fw must be a long format */ + if (*fmptr == 'p') { + bytes = pct - fmt - fw; + strncpy(tbuf, fmt, bytes); + tbuf[bytes] = 0; + } else { + bytes = pct - fmt - fw - 2; + strncpy(tbuf, fmt, bytes); + tbuf[bytes] = 'l'; + strncpy(tbuf+bytes+1, fmt+bytes, 2); + tbuf[bytes+1+2] = 0; + } + } + + /* if more input buffer to process, recurse */ + if ((l - abs(fw)) != 0) { + fmt_str(env, pct+abs(fw), (tbuf + strlen(tbuf)), + CMN_MSG_SIZE - strlen(tbuf)); + } + + /* call to extract args for snprintf() calls below */ + fmt_args(env, cw, fw, *fmptr, &arg, &llarg); + + if (fw > 0) { /* process normal (not long) formats */ + switch (*fmptr) { + case 'd': + case 'x': + case 'c': + case 's': + case 'p': + (void) snprintf(fmtbuf, bsize, tbuf, arg); + break; + case '%': + (void) snprintf(fmtbuf, bsize, tbuf); + break; + default: + log_message(MSG_ERROR, + "fmt_str: invalid format (%s)\n", + fmptr); + return; + } + + } else /* process long formats */ + (void) snprintf(fmtbuf, bsize, tbuf, llarg); + + } else + strncpy(fmtbuf, fmt, bsize); +} + +/* + * fc_cmn_append() + * + * Pops data stack to obtain message text, and calls fmt_str() + * function to perform any message formatting necessary. + * + * This function is called from fc_cmn_end() or directly in + * processing a cmn-append token. Since a pre-existing message + * context is assumed, initial checking is performed to verify + * its existence. + */ + +void +fc_cmn_append(fcode_env_t *env) +{ + int len; + char *str; + + if (root == NULL) { + log_message(MSG_ERROR, + "fc_cmn_append: no message context for append\n"); + return; + } + + len = POP(DS); + str = (char *)POP(DS); + + if ((root->len + len) < CMN_MSG_SIZE) { + fmt_str(env, str, root->buf+root->len, CMN_MSG_SIZE - + root->len); + root->len += len; + } else + log_message(MSG_ERROR, + "fc_cmn_append: append exceeds max msg size\n"); +} + +/* + * fc_cmn_end() + * + * Process ]cmn-end token to log the message initiated by a preceeding + * fc_cmn_start() call. + * + * Since nested cmn-xxx[ calls are supported, a test is made to determine + * if this is the final cmn-end of a nested sequence. If so, or if + * there was no nesting, log_message() is called with the appropriate + * text buffer. Otherwise, the root variable is adjusted to point to + * the preceeding message in the sequence and links in the list are + * updated. No logging is performed until the final ]cmn-end of the + * sequence is processed; then, messages are logged in FIFO order. + */ +void +fc_cmn_end(fcode_env_t *env) +{ + cmn_msg_t *old; + + if (root == 0) { + log_message(MSG_ERROR, "]cmn-end call w/o buffer\n"); + return; + } + + fc_cmn_append(env); + + if (root->prev == 0) { + cmn_msg_t *next; + do { + log_message(root->level, "%s\n", root->buf); + next = root->next; + free(root); + root = next; + } while (root); + } else { + old = root->prev; + old->next = root; + root = old; + } +} + +/* + * fc_cmn_start() + * + * Generic function to begin a common message. + * + * Allocates a new cmn_msg_t to associate with the message, and sets + * up initial text as specified by callers' inputs: + * + * env - pointer to caller's fcode environment + * head - pointer to initial text portion of the message + * path - flag to indicate if a device path is to be generated + */ +static void +fc_cmn_start(fcode_env_t *env, char *head, int path) +{ + cmn_msg_t *new; + char *dpath; + + new = MALLOC(sizeof (cmn_msg_t)); + new->prev = root; + if (root != 0) + root->next = new; + strcpy(new->buf, head); + new->len = strlen(head); + if (path && env->current_device) { + dpath = get_path(env, env->current_device); + strcpy(new->buf+new->len, dpath); + new->len += strlen(dpath); + strncpy(new->buf+new->len++, ": ", 2); + ++new->len; + free(dpath); + } + new->level = cmn_msg_level; + new->next = NULL; + root = new; +} + +/* + * fc_cmn_type() + * + * Process cmn-type[ token. + * + * Invokes fc_cmn_start() to create a message containing blank + * header and no device path information. + */ +void +fc_cmn_type(fcode_env_t *env) +{ + cmn_msg_level = MSG_INFO; + fc_cmn_start(env, "", 0); +} + +/* + * fc_cmn_msg() + * + * Process cmn-msg[ token. + * + * Invokes fc_cmn_start() to create a message containing blank + * header but specifying device path information. + */ +void +fc_cmn_msg(fcode_env_t *env) +{ + + cmn_msg_level = MSG_INFO; + fc_cmn_start(env, "", 1); +} + +/* + * fc_cmn_note() + * + * Process cmn-note[ token. + * + * Invokes fc_cmn_start() to create a message with NOTICE stamping in + * the header and specification of device path information. + */ +void +fc_cmn_note(fcode_env_t *env) +{ + cmn_msg_level = MSG_NOTE; + fc_cmn_start(env, "NOTICE: ", 1); +} + +/* + * fc_cmn_warn() + * + * Process cmn-warn[ token. + * + * Invokes fc_cmn_start() to create a message with WARNING stamping in + * the header and specification of device path information. + */ +void +fc_cmn_warn(fcode_env_t *env) +{ + cmn_msg_level = MSG_WARN; + fc_cmn_start(env, "WARNING: ", 1); +} + +/* + * fc_cmn_error() + * + * Process cmn-error[ token. + * + * Invokes fc_cmn_start() to create a message with ERROR stamping in + * the header and specification of device path information. + */ +void +fc_cmn_error(fcode_env_t *env) +{ + cmn_msg_level = MSG_ERROR; + fc_cmn_start(env, "ERROR: ", 1); +} + +/* + * fc_cmn_fatal() + * + * Process cmn-fatal[ token. + * + * Invokes fc_cmn_start() to create a message with FATAL stamping in + * the header and specification of device path information. + */ +void +fc_cmn_fatal(fcode_env_t *env) +{ + cmn_msg_level = MSG_FATAL; + fc_cmn_start(env, "FATAL: ", 1); +} + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + ASSERT(env); + NOTICE; + + ANSI(0x088, 0, "span", span); + ANSI(0x08a, 0, "expect", expect); + + ANSI(0x08d, 0, "key?", keyquestion); + ANSI(0x08e, 0, "key", key); + ANSI(0x08f, 0, "emit", emit); + ANSI(0x090, 0, "type", type); + ANSI(0x091, 0, "(cr", paren_cr); + ANSI(0x092, 0, "cr", fc_crlf); + ANSI(0x093, 0, "#out", fc_num_out); + ANSI(0x094, 0, "#line", fc_num_line); + + FCODE(0x125, 0, "get-msecs", do_get_msecs); + FCODE(0x126, 0, "ms", do_ms); + + FORTH(0, "verbose-emit", do_verbose_emit); + FCODE(0x7e9, 0, "cmn-fatal[", fc_cmn_fatal); + FCODE(0x7ea, 0, "cmn-error[", fc_cmn_error); + FCODE(0x7eb, 0, "cmn-warn[", fc_cmn_warn); + FCODE(0x7ec, 0, "cmn-note[", fc_cmn_note); + FCODE(0x7ed, 0, "cmn-type[", fc_cmn_type); + FCODE(0x7ee, 0, "cmn-append", fc_cmn_append); + FCODE(0x7ef, 0, "]cmn-end", fc_cmn_end); + FCODE(0x7f0, 0, "cmn-msg[", fc_cmn_msg); +} diff --git a/usr/src/lib/efcode/engine/extend.c b/usr/src/lib/efcode/engine/extend.c new file mode 100644 index 0000000000..9e631012b2 --- /dev/null +++ b/usr/src/lib/efcode/engine/extend.c @@ -0,0 +1,147 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2000 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <sys/shm.h> +#include <dlfcn.h> +#include <fcode/private.h> + +static void +do_dlopen(fcode_env_t *env) +{ + char *name; + int mode; + void *pl; + + mode = POP(DS); + name = pop_a_string(env, NULL); + pl = dlopen(name, mode); + PUSH(DS, (fstack_t)pl); +} + +static void +do_extend(fcode_env_t *env) +{ + parse_word(env); + PUSH(DS, (fstack_t)RTLD_NOW); + do_dlopen(env); + drop(env); +} + +static void +do_dlclose(fcode_env_t *env) +{ + void *pl = (void *)POP(DS); + dlclose(pl); +} + +static void +do_dlsym(fcode_env_t *env) +{ + char *name; + fstack_t d; + + name = pop_a_string(env, NULL); + d = POP(DS); + d = (fstack_t)dlsym((void *) d, name); + PUSH(DS, d); +} + +static void +do_dlexec(fcode_env_t *env) +{ + int args; + fstack_t a, b, c, d; + fstack_t (*fn0)(void); + fstack_t (*fn1)(fstack_t); + fstack_t (*fn2)(fstack_t, fstack_t); + fstack_t (*fn3)(fstack_t, fstack_t, fstack_t); + fstack_t (*fn4)(fstack_t, fstack_t, fstack_t, fstack_t); + + args = POP(DS); + a = POP(DS); + switch (args) { + + case 0: + fn0 = (fstack_t (*)(void)) a; + a = fn0(); + PUSH(DS, a); + break; + + case 1: + fn1 = (fstack_t (*)(fstack_t)) a; + a = POP(DS); + a = fn1(a); + PUSH(DS, a); + break; + + case 2: + fn2 = (fstack_t (*)(fstack_t, fstack_t))a; + a = POP(DS); + b = POP(DS); + a = fn2(a, b); + PUSH(DS, a); + break; + + case 3: + fn3 = (fstack_t (*)(fstack_t, fstack_t, fstack_t))a; + a = POP(DS); + b = POP(DS); + c = POP(DS); + a = fn3(a, b, c); + PUSH(DS, a); + break; + + case 4: + fn4 = (fstack_t (*)(fstack_t, fstack_t, fstack_t, fstack_t))a; + a = POP(DS); + b = POP(DS); + c = POP(DS); + d = POP(DS); + a = fn4(a, b, c, d); + PUSH(DS, a); + break; + } +} + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + ASSERT(env); + NOTICE; + + FORTH(0, "dl-open", do_dlopen); + FORTH(0, "dl-close", do_dlclose); + FORTH(0, "dl-sym", do_dlsym); + FORTH(0, "dl-exec", do_dlexec); + FORTH(IMMEDIATE, "extend-from", do_extend); +} diff --git a/usr/src/lib/efcode/engine/fb8.c b/usr/src/lib/efcode/engine/fb8.c new file mode 100644 index 0000000000..777b9d0713 --- /dev/null +++ b/usr/src/lib/efcode/engine/fb8.c @@ -0,0 +1,54 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <fcode/private.h> + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + ASSERT(env); + NOTICE; + + FCODE(0x180, 0, "fb8-draw-character", fc_unimplemented); + FCODE(0x181, 0, "fb8-reset-screen", fc_unimplemented); + FCODE(0x182, 0, "fb8-toggle-cursor", fc_unimplemented); + FCODE(0x183, 0, "fb8-erase-screen", fc_unimplemented); + FCODE(0x184, 0, "fb8-blink-screen", fc_unimplemented); + FCODE(0x185, 0, "fb8-invert-screen", fc_unimplemented); + FCODE(0x186, 0, "fb8-insert-characters", fc_unimplemented); + FCODE(0x187, 0, "fb8-delete-characters", fc_unimplemented); + FCODE(0x188, 0, "fb8-insert-lines", fc_unimplemented); + FCODE(0x189, 0, "fb8-delete-lines", fc_unimplemented); + FCODE(0x18a, 0, "fb8-draw-logo", fc_unimplemented); + FCODE(0x18b, 0, "fb8-install", fc_unimplemented); +} diff --git a/usr/src/lib/efcode/engine/fcode.c b/usr/src/lib/efcode/engine/fcode.c new file mode 100644 index 0000000000..e8cedb3816 --- /dev/null +++ b/usr/src/lib/efcode/engine/fcode.c @@ -0,0 +1,1031 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2000 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +int fcode_impl_count = 0; + +void (*crash_ptr)(fcode_env_t *env) = do_crash; + +uchar_t +next_bytecode(fcode_env_t *env) +{ + uchar_t byte; + + byte = *env->fcode_ptr; + env->fcode_ptr += env->fcode_incr; + return (byte); +} + +ushort_t +get_next_token(fcode_env_t *env) +{ + ushort_t token = next_bytecode(env); + if ((token) && (token < 0x10)) { + token = (token << 8) | next_bytecode(env); + } + env->last_fcode = token; + return (token); +} + +ushort_t +get_short(fcode_env_t *env) +{ + ushort_t u; + + /* + * Logical or DOES NOT guarantee left to right evaluation... + */ + u = next_bytecode(env) << 8; + return (u | next_bytecode(env)); +} + +uint_t +get_int(fcode_env_t *env) +{ + uint_t u; + + /* + * Logical or DOES NOT guarantee left to right evaluation... + */ + u = get_short(env) << 16; + return (u | get_short(env)); +} + +void +expose_acf(fcode_env_t *env, char *name) +{ + if (name == NULL) + name = "<unknown>"; + EXPOSE_ACF; + debug_msg(DEBUG_CONTEXT, "CONTEXT:expose_acf: acf: %p/'%s' %p\n", + LINK_TO_ACF(env->lastlink), name, env->current); +} + +void +do_code(fcode_env_t *env, int token, char *name, void (*fn)(fcode_env_t *)) +{ + env->table[token].name = name; + if (fn == NULL) { + env->table[token].apf = NULL; + env->table[token].name = name; + } else { + header(env, name, strlen(name), 0); + env->table[token].apf = (acf_t)HERE; + COMPILE_TOKEN(fn); + expose_acf(env, name); + } +} + +void +define_word(fcode_env_t *env, int flag, char *name, void (*fn)(fcode_env_t *)) +{ + header(env, name, strlen(name), flag); + COMPILE_TOKEN(fn); + expose_acf(env, name); +} + +void +end0(fcode_env_t *env) +{ + env->interpretting = 0; +} + +static void +end1(fcode_env_t *env) +{ + env->interpretting = 0; +} + +void +blit(fcode_env_t *env) +{ + fstack_t d = (int)get_int(env); + PUSH(DS, d); + literal(env); +} + +void (*bbranch_ptrs[3])(fcode_env_t *env) = { + do_bbranch, + do_bqbranch, + do_bofbranch +}; + +void +branch_common(fcode_env_t *env, short direction, fstack_t which, int doswap) +{ + fstack_t *sp; + token_t *branch_loc; + + ASSERT((which < 3) && (which >= 0)); + which = (fstack_t)&bbranch_ptrs[which]; + set_temporary_compile(env); + COMPILE_TOKEN(which); + if (direction >= 0) { + bmark(env); + if (doswap) + swap(env); + PUSH(DS, 0); + compile_comma(env); + } else { + + /* + * We look down the stack for a branch location + * that isn't pointing to zero (i.e. a forward branch label). + * We move the first one we find to the top of the stack, + * which is what gets compiled in with 'compile_comma'. + * Not finding a valid branch label is bad. + */ + for (sp = env->ds; sp >= env->ds0; sp--) { + branch_loc = (token_t *)*sp; + if (branch_loc && *branch_loc) { + break; + } + } + if (sp < env->ds0) + log_message(MSG_ERROR, "branch_common: back: " + "no branch loc on stack\n"); + else { + /* Move branch_loc to top of data stack */ + for (; sp < env->ds; sp++) + *sp = sp[1]; + *sp = (fstack_t)branch_loc; + } + env->level--; + compile_comma(env); + temporary_execute(env); + } +} + +void +bbranch(fcode_env_t *env) +{ + short offset = (short)get_short(env); + + branch_common(env, offset, 0, 1); +} + +void +bqbranch(fcode_env_t *env) +{ + short offset = (short)get_short(env); + + branch_common(env, offset, 1, 0); +} + +void +do_quote(fcode_env_t *env) +{ + int len; + uchar_t *strptr; + + strptr = (uchar_t *)IP; + len = *strptr; + PUSH(DS, (fstack_t)strptr+1); + PUSH(DS, len); + strptr += TOKEN_ROUNDUP(len+2); + IP = (token_t *)strptr; +} + +void +bquote(fcode_env_t *env) +{ + char stringbuff[256]; + int len, count; + char *strptr; + + count = len = next_bytecode(env); + if (env->state) { + COMPILE_TOKEN("e_ptr); + strptr = (char *)HERE; + *strptr++ = len; + while (count--) + *strptr++ = next_bytecode(env); + *strptr++ = 0; + set_here(env, (uchar_t *)strptr, "bquote"); + token_roundup(env, "bquote"); + } else { + strptr = stringbuff; + while (count--) + *strptr++ = next_bytecode(env); + *strptr = 0; + push_string(env, stringbuff, len); + } +} + +char * +get_name(token_t *linkp) +{ + char *name, *p; + flag_t *fptr = LINK_TO_FLAGS(linkp); + int len; + char *cptr; + + if (*fptr & FLAG_NONAME) + return (NULL); + + cptr = (char *)fptr; + len = cptr[-1]; + if (len <= 0 || len > 64 || cptr[-2] != '\0') + return (NULL); + + name = cptr - (len+2); + + for (p = name; *p != '\0'; p++) + if (!isprint(*p)) + return (NULL); + + if ((p - name) != len) + return (NULL); + + return (name); +} + +void +header(fcode_env_t *env, char *name, int len, flag_t flag) +{ + char *strptr; + flag_t *fptr; + acf_t dptr; + extern void add_debug_acf(fcode_env_t *, acf_t); + + /* Now form the entry in the dictionary */ + token_roundup(env, "header"); + dptr = (acf_t)HERE; + if (len) { + int bytes = len+2+sizeof (flag_t); + dptr = (acf_t)(TOKEN_ROUNDUP(HERE+bytes)); + fptr = LINK_TO_FLAGS(dptr); + strptr = (char *)fptr - 1; + *strptr-- = len; + *strptr-- = 0; + while (len) + *strptr-- = name[--len]; + } else { + dptr++; + fptr = LINK_TO_FLAGS(dptr); + flag |= FLAG_NONAME; + } + *fptr = flag; + *dptr = *((acf_t)env->current); + env->lastlink = dptr++; + set_here(env, (uchar_t *)dptr, "header"); + + if (name_is_debugged(env, name)) { + log_message(MSG_INFO, "Turning debug on for %s\n", name); + add_debug_acf(env, LINK_TO_ACF(env->lastlink)); + } + debug_msg(DEBUG_HEADER, "Define: '%s' @ %p\n", name, HERE); +} + +void +token_common(fcode_env_t *env, int headered, int visible) +{ + char namebuff[32]; + int len, count, token; + char *strptr, c; + + strptr = namebuff; + if (headered) { + len = next_bytecode(env); + for (count = 0; count < len; count++) { + c = next_bytecode(env); + if (count < sizeof (namebuff)) + *strptr++ = c; + } + } + + if (!visible) + len = 0; + *strptr = 0; + token = get_short(env); + env->last_token = token; + + debug_msg(DEBUG_NEW_TOKEN, "Define %s token: '%s' (%x)\n", + (visible ? "named" : "headerless"), namebuff, token); + + header(env, namebuff, len, 0); + env->table[token].flags = 0; + if (len) { + env->table[token].name = MALLOC(len+1); + strncpy(env->table[token].name, namebuff, len); + } else { + env->table[token].name = NULL; + } + env->last_token = token; +} + +void +named_token(fcode_env_t *env) +{ + token_common(env, 1, env->fcode_debug); +} + +void +external_token(fcode_env_t *env) +{ + token_common(env, 1, 1); +} + +void +new_token(fcode_env_t *env) +{ + token_common(env, 0, 0); +} + +void +offset16(fcode_env_t *env) +{ + env->offset_incr = 2; +} + +void +minus_one(fcode_env_t *env) +{ + PUSH(DS, -1); +} + +void +zero(fcode_env_t *env) +{ + PUSH(DS, 0); +} + +void +one(fcode_env_t *env) +{ + PUSH(DS, 1); +} + +void +two(fcode_env_t *env) +{ + PUSH(DS, 2); +} + +void +three(fcode_env_t *env) +{ + PUSH(DS, 3); +} + +void +version1(fcode_env_t *env) +{ + env->fcode_incr = 1; +} + +static void +start0(fcode_env_t *env) +{ + env->fcode_incr = 1; +} + +static void +start1(fcode_env_t *env) +{ + env->fcode_incr = 1; +} + +void +start2(fcode_env_t *env) +{ + env->fcode_incr = 2; +} + +static void +start4(fcode_env_t *env) +{ + env->fcode_incr = 4; +} + +int +check_fcode_header(char *fname, uchar_t *header, int len) +{ + uint32_t length; + static char func_name[] = "check_fcode_header"; + + if (len <= 8) { + log_message(MSG_ERROR, "%s: '%s' fcode size (%d) <= 8\n", + func_name, fname, len); + return (0); + } + if (header[0] != 0xf1 && header[0] != 0xfd) { + log_message(MSG_ERROR, "%s: '%s' header[0] is 0x%02x not" + " 0xf1/0xfd\n", func_name, fname, header[0]); + return (0); + } + length = (header[4] << 24) | (header[5] << 16) | (header[6] << 8) | + header[7]; + if (length > len) { + log_message(MSG_ERROR, "%s: '%s' length (%d) >" + " fcode size (%d)\n", func_name, fname, length, len); + return (0); + } + if (length < len) { + log_message(MSG_WARN, "%s: '%s' length (%d) <" + " fcode size (%d)\n", func_name, fname, length, len); + } + return (1); +} + +void +byte_load(fcode_env_t *env) +{ + uchar_t *fcode_buffer; + uchar_t *fcode_ptr; + int fcode_incr; + int offset_incr; + int fcode_xt; + int interpretting; + int depth; + int length; + int past_eob = 0; + int db; + + /* save any existing interpret state */ + fcode_buffer = env->fcode_buffer; + fcode_ptr = env->fcode_ptr; + fcode_incr = env->fcode_incr; + offset_incr = env->offset_incr; + interpretting = env->interpretting; + depth = DEPTH-2; + + /* Now init them */ + CHECK_DEPTH(env, 2, "byte-load"); + fcode_xt = POP(DS); + env->fcode_ptr = env->fcode_buffer = (uchar_t *)POP(DS); + if (fcode_xt != 1) { + log_message(MSG_WARN, "byte-load: ignoring xt\n"); + } + + length = (env->fcode_buffer[4] << 24) | (env->fcode_buffer[5] << 16) | + (env->fcode_buffer[6] << 8) | env->fcode_buffer[7]; + if (!check_fcode_header("byte-load", env->fcode_ptr, length)) + log_message(MSG_WARN, "byte-load: header NOT OK\n"); + + env->fcode_incr = 1; + env->offset_incr = 1; + env->interpretting = 1; + env->level = 0; + + db = get_interpreter_debug_level() & + (DEBUG_BYTELOAD_DS|DEBUG_BYTELOAD_RS|DEBUG_BYTELOAD_TOKENS); + debug_msg(db, "byte_load: %p, %d\n", env->fcode_buffer, fcode_xt); + debug_msg(db, " header: %x, %x\n", + env->fcode_buffer[0], env->fcode_buffer[1]); + debug_msg(db, " crc: %x\n", + (env->fcode_buffer[2]<<8)|(env->fcode_buffer[3])); + debug_msg(db, " length: %x\n", length); + env->fcode_ptr += 8; + + debug_msg(db, "Interpretting: %d\n", env->interpretting); + + while (env->interpretting) { + int token; + fcode_token *entry; + acf_t apf; + + if (!past_eob && env->fcode_ptr >= env->fcode_buffer + length) { + log_message(MSG_WARN, "byte-load: past EOB\n"); + past_eob = 1; + } + + env->last_fcode_ptr = env->fcode_ptr; + token = get_next_token(env); + + entry = &env->table[token]; + apf = entry->apf; + + DEBUGF(BYTELOAD_DS, output_data_stack(env, MSG_FC_DEBUG)); + DEBUGF(BYTELOAD_RS, output_return_stack(env, 1, MSG_FC_DEBUG)); + DEBUGF(BYTELOAD_TOKENS, log_message(MSG_FC_DEBUG, + "%s: %04x %03x %s (%x)", + ((env->state && (entry->flags & IMMEDIATE) == 0)) ? + "Compile" : "Execute", + env->last_fcode_ptr - env->fcode_buffer, token, + entry->name ? entry->name : "???", entry->flags)); + if (db) + log_message(MSG_FC_DEBUG, "\n"); + if (apf) { + DEBUGF(TOKEN_USAGE, entry->usage++); + PUSH(DS, (fstack_t)apf); + if ((env->state) && + ((entry->flags & IMMEDIATE) == 0)) { + /* Compile in references */ + compile_comma(env); + } else { + execute(env); + } + } + } + if (DEPTH != depth) { + log_message(MSG_ERROR, "FCODE has net stack change of %d\n", + DEPTH-depth); + } + /* restore old state */ + env->fcode_ptr = fcode_ptr; + env->fcode_buffer = fcode_buffer; + env->fcode_incr = fcode_incr; + env->offset_incr = offset_incr; + env->interpretting = interpretting; +} + +void +btick(fcode_env_t *env) +{ + int token = get_next_token(env); + + PUSH(DS, (fstack_t)env->table[token].apf); + tick_literal(env); +} + +static void +show_fcode_def(fcode_env_t *env, char *type) +{ + int i = env->last_token; + + if (get_interpreter_debug_level() & DEBUG_DUMP_TOKENS) { + if (env->table[i].name) + log_message(MSG_INFO, "%s: %s %03x %p\n", type, + env->table[i].name, i, env->table[i].apf); + else + log_message(MSG_INFO, "%s: <noname> %03x %p\n", type, i, + env->table[i].apf); + } +} + +void +bcolon(fcode_env_t *env) +{ + if (env->state == 0) { + env->table[env->last_token].apf = (acf_t)HERE; + env->table[env->last_token].flags = 0; + show_fcode_def(env, "bcolon"); + } + env->state |= 1; + COMPILE_TOKEN(&do_colon); +} + +void +bcreate(fcode_env_t *env) +{ + env->table[env->last_token].apf = (acf_t)HERE; + show_fcode_def(env, "bcreate"); + COMPILE_TOKEN(&do_create); + expose_acf(env, "<bcreate>"); +} + +void +get_token_name(fcode_env_t *env, int token, char **name, int *len) +{ + *name = env->table[token].name; + if (*name) { + *len = strlen(*name); + } else + *len = 0; +} + +void +bvalue(fcode_env_t *env) +{ + env->table[env->last_token].apf = (acf_t)HERE; + show_fcode_def(env, "bvalue"); + make_common_access(env, 0, 0, 1, + env->instance_mode, &noop, &noop, &set_value_actions); +} + +void +bvariable(fcode_env_t *env) +{ + env->table[env->last_token].apf = (acf_t)HERE; + show_fcode_def(env, "bvariable"); + PUSH(DS, 0); + make_common_access(env, 0, 0, 1, + env->instance_mode, &instance_variable, &do_create, NULL); +} + +void +bconstant(fcode_env_t *env) +{ + env->table[env->last_token].apf = (acf_t)HERE; + show_fcode_def(env, "bconstant"); + make_common_access(env, 0, 0, 1, + env->instance_mode, &do_constant, &do_constant, NULL); +} + +void +bdefer(fcode_env_t *env) +{ + env->table[env->last_token].apf = (acf_t)HERE; + show_fcode_def(env, "bdefer"); + + PUSH(DS, (fstack_t)&crash_ptr); + make_common_access(env, 0, 0, 1, env->instance_mode, + &noop, &noop, &set_defer_actions); +} + +void +bbuffer_colon(fcode_env_t *env) +{ + env->table[env->last_token].apf = (acf_t)HERE; + show_fcode_def(env, "buffer:"); + PUSH(DS, 0); + make_common_access(env, 0, 0, 2, env->instance_mode, + &noop, &noop, &set_buffer_actions); +} + +void +do_field(fcode_env_t *env) +{ + fstack_t *d; + + d = (fstack_t *)WA; + TOS += *d; +} + +void +bfield(fcode_env_t *env) +{ + env->table[env->last_token].apf = (acf_t)HERE; + show_fcode_def(env, "bfield"); + COMPILE_TOKEN(&do_field); + over(env); + compile_comma(env); + add(env); + expose_acf(env, "<bfield>"); +} + +void +bto(fcode_env_t *env) +{ + btick(env); + + if (env->state) { + COMPILE_TOKEN(&to_ptr); + } else { + do_set_action(env); + } +} + +void +get_token(fcode_env_t *env) +{ + fstack_t tok; + fstack_t immediate = 0; + + CHECK_DEPTH(env, 1, "get-token"); + tok = POP(DS); + tok &= MAX_FCODE; + PUSH(DS, (fstack_t)env->table[tok].apf); + if (env->table[tok].flags & IMMEDIATE) immediate = 1; + PUSH(DS, immediate); +} + +void +set_token(fcode_env_t *env) +{ + fstack_t tok; + fstack_t immediate; + acf_t acf; + + CHECK_DEPTH(env, 3, "set-token"); + tok = POP(DS); + tok &= MAX_FCODE; + immediate = POP(DS); + acf = (acf_t)POP(DS); + if (immediate) + env->table[tok].flags |= IMMEDIATE; + else + env->table[tok].flags &= ~IMMEDIATE; + env->table[tok].apf = acf; + immediate = env->last_token; + env->last_token = tok; + show_fcode_def(env, "set_token"); + env->last_token = immediate; +} + +void +bof(fcode_env_t *env) +{ + short offset = get_short(env); + branch_common(env, offset, 2, 0); +} + +void +bcase(fcode_env_t *env) +{ + env->level++; + set_temporary_compile(env); + PUSH(DS, 0); +} + +void +bendcase(fcode_env_t *env) +{ + COMPILE_TOKEN(env->table[0x46].apf); /* Hack for now... */ + while (TOS) { + bresolve(env); + } + (void) POP(DS); + env->level--; + temporary_execute(env); +} + +void +bendof(fcode_env_t *env) +{ + short offset = get_short(env); + branch_common(env, offset, 0, 1); + bresolve(env); +} + +void +fcode_revision(fcode_env_t *env) +{ + /* We are Version 3.0 */ + PUSH(DS, 0x30000); +} + +void +alloc_mem(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "alloc-mem"); + TOS = (fstack_t)MALLOC((size_t)TOS); + if (!TOS) { + throw_from_fclib(env, 1, "alloc-mem failed"); + } +} + +void +free_mem(fcode_env_t *env) +{ + void *p; + + CHECK_DEPTH(env, 2, "free-mem"); + (void) POP(DS); + p = (void *) POP(DS); + FREE(p); +} + +void +parse_two_int(fcode_env_t *env) +{ + uint_t lo, hi; + char *str; + int len; + + CHECK_DEPTH(env, 2, "parse-2int"); + lo = 0; + hi = 0; + str = pop_a_string(env, &len); + if (len) { + if (sscanf(str, "%x,%x", &hi, &lo) != 2) { + throw_from_fclib(env, 1, "parse_2int"); + } + } + PUSH(DS, lo); + PUSH(DS, hi); +} + +void +left_parse_string(fcode_env_t *env) +{ + char sep, *cptr, *lstr, *rstr; + int len, llen, rlen; + + CHECK_DEPTH(env, 3, "left-parse-string"); + sep = (char)POP(DS); + if (TOS == 0) { + two_dup(env); + return; + } + lstr = pop_a_string(env, &llen); + len = 0; + cptr = NULL; + while (len < llen) { + if (lstr[len] == sep) { + cptr = lstr+len; + break; + } + len++; + } + if (cptr != NULL) { + rstr = cptr+1; + rlen = lstr + llen - rstr; + llen = len; + } else { + rlen = 0; + rstr = lstr; + } + PUSH(DS, (fstack_t)rstr); + PUSH(DS, rlen); + PUSH(DS, (fstack_t)lstr); + PUSH(DS, llen); +} + +/* + * (is-user-word) ( name-str name-len xt -- ) + */ +void +is_user_word(fcode_env_t *env) +{ + fstack_t xt; + char *name; + int len; + + CHECK_DEPTH(env, 3, "(is-user-word)"); + xt = POP(DS); + name = pop_a_string(env, &len); + header(env, name, len, 0); + COMPILE_TOKEN(&do_alias); + COMPILE_TOKEN(xt); + expose_acf(env, name); +} + +void +f_error(fcode_env_t *env) +{ +#if 0 + env->interpretting = 0; + log_message(MSG_ERROR, "Uniplemented FCODE token encountered %x\n", + env->last_fcode); +#else + forth_abort(env, "Unimplemented FCODE token: 0x%x\n", env->last_fcode); +#endif +} + +static void +fcode_buffer_addr(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)(env->fcode_buffer)); +} + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + ASSERT(env); + NOTICE; + + P1275(0x000, DEFINER, "end0", end0); + P1275(0x010, DEFINER, "b(lit)", blit); + P1275(0x011, DEFINER, "b(')", btick); + P1275(0x012, DEFINER, "b(\")", bquote); + P1275(0x013, DEFINER, "bbranch", bbranch); + P1275(0x014, DEFINER, "b?branch", bqbranch); + P1275(0x015, DEFINER, "b(loop)", bloop); + P1275(0x016, DEFINER, "b(+loop)", bplusloop); + P1275(0x017, DEFINER, "b(do)", bdo); + P1275(0x018, DEFINER, "b(?do)", bqdo); + P1275(0x01b, DEFINER, "b(leave)", bleave); + P1275(0x01c, DEFINER, "b(of)", bof); + + P1275(0x087, 0, "fcode-revision", fcode_revision); + + P1275(0x08b, 0, "alloc-mem", alloc_mem); + P1275(0x08c, 0, "free-mem", free_mem); + + P1275(0x0a4, 0, "-1", minus_one); + P1275(0x0a5, 0, "0", zero); + P1275(0x0a6, 0, "1", one); + P1275(0x0a7, 0, "2", two); + P1275(0x0a8, 0, "3", three); + + P1275(0x0ae, 0, "aligned", aligned); + P1275(0x0b1, DEFINER, "b(<mark)", bmark); + P1275(0x0b2, DEFINER, "b(>resolve)", bresolve); + FCODE(0x0b3, 0, "set-token-table", fc_historical); + FCODE(0x0b4, 0, "set-table", fc_historical); + P1275(0x0b5, 0, "new-token", new_token); + P1275(0x0b6, 0, "named-token", named_token); + P1275(0x0b7, DEFINER, "b(:)", bcolon); + P1275(0x0b8, DEFINER, "b(value)", bvalue); + P1275(0x0b9, DEFINER, "b(variable)", bvariable); + P1275(0x0ba, DEFINER, "b(constant)", bconstant); + P1275(0x0bb, DEFINER, "b(create)", bcreate); + P1275(0x0bc, DEFINER, "b(defer)", bdefer); + P1275(0x0bd, 0, "b(buffer:)", bbuffer_colon); + P1275(0x0be, 0, "b(field)", bfield); + FCODE(0x0bf, 0, "b(code)", fc_historical); + P1275(0x0c0, IMMEDIATE, "instance", instance); + + P1275(0x0c2, DEFINER, "b(;)", semi); + P1275(0x0c3, DEFINER, "b(to)", bto); + P1275(0x0c4, DEFINER, "b(case)", bcase); + P1275(0x0c5, DEFINER, "b(endcase)", bendcase); + P1275(0x0c6, DEFINER, "b(endof)", bendof); + + P1275(0x0ca, 0, "external-token", external_token); + P1275(0x0cc, 0, "offset16", offset16); + P1275(0x0cd, 0, "evaluate", evaluate); + + P1275(0x0da, 0, "get-token", get_token); + P1275(0x0db, 0, "set-token", set_token); + + P1275(0x0f0, 0, "start0", start0); + P1275(0x0f1, 0, "start1", start1); + P1275(0x0f2, 0, "start2", start2); + P1275(0x0f3, 0, "start4", start4); + + P1275(0x0fd, 0, "version1", version1); + FCODE(0x0fe, 0, "4-byte-id", fc_historical); + + P1275(0x0ff, 0, "end1", end1); + + /* Call it "old-dma-alloc" so no one gets confused */ + FCODE(0x101, 0, "old-dma-alloc", fc_historical); + + FCODE(0x104, 0, "memmap", fc_historical); + FCODE(0x105, 0, "free-virtual", fc_unimplemented); + + FCODE(0x106, 0, ">physical", fc_historical); + + FCODE(0x10f, 0, "my-params", fc_historical); + + P1275(0x11b, 0, "parse-2int", parse_two_int); + + FCODE(0x122, 0, "memory-test-suite", fc_unimplemented); + FCODE(0x123, 0, "group-code", fc_historical); + FCODE(0x124, 0, "mask", fc_unimplemented); + + FCODE(0x130, 0, "map-low", fc_unimplemented); + FCODE(0x131, 0, "sbus-intr>cpu", fc_unimplemented); + + FCODE(0x170, 0, "fb1-draw-character", fc_historical); + FCODE(0x171, 0, "fb1-reset-screen", fc_historical); + FCODE(0x172, 0, "fb1-toggle-cursor", fc_historical); + FCODE(0x173, 0, "fb1-erase-screen", fc_historical); + FCODE(0x174, 0, "fb1-blink-screen", fc_historical); + FCODE(0x175, 0, "fb1-invert-screen", fc_historical); + FCODE(0x176, 0, "fb1-insert-characters", fc_historical); + FCODE(0x177, 0, "fb1-delete-characters", fc_historical); + FCODE(0x178, 0, "fb1-insert-lines", fc_historical); + FCODE(0x179, 0, "fb1-delete-lines", fc_historical); + FCODE(0x17a, 0, "fb1-draw-logo", fc_historical); + FCODE(0x17b, 0, "fb1-install", fc_historical); + FCODE(0x17c, 0, "fb1-slide-up", fc_historical); + + FCODE(0x190, 0, "VME-bus Support", fc_obsolete); + FCODE(0x191, 0, "VME-bus Support", fc_obsolete); + FCODE(0x192, 0, "VME-bus Support", fc_obsolete); + FCODE(0x193, 0, "VME-bus Support", fc_obsolete); + FCODE(0x194, 0, "VME-bus Support", fc_obsolete); + FCODE(0x195, 0, "VME-bus Support", fc_obsolete); + FCODE(0x196, 0, "VME-bus Support", fc_obsolete); + + FCODE(0x1a0, 0, "return-buffer", fc_historical); + FCODE(0x1a1, 0, "xmit-packet", fc_historical); + FCODE(0x1a2, 0, "poll-packet", fc_historical); + + FCODE(0x210, 0, "processor-type", fc_historical); + FCODE(0x211, 0, "firmware-version", fc_historical); + FCODE(0x212, 0, "fcode-version", fc_historical); + + FCODE(0x214, 0, "(is-user-word)", is_user_word); + FCODE(0x215, 0, "suspend-fcode", fc_unimplemented); + + FCODE(0x229, 0, "adr-mask", fc_historical); + + FCODE(0x238, 0, "probe", fc_historical); + FCODE(0x239, 0, "probe-virtual", fc_historical); + + P1275(0x23e, 0, "byte-load", byte_load); + + P1275(0x240, 0, "left-parse-string", left_parse_string); + FORTH(0, "fcode-buffer", fcode_buffer_addr); +} diff --git a/usr/src/lib/efcode/engine/font.c b/usr/src/lib/efcode/engine/font.c new file mode 100644 index 0000000000..a38307480f --- /dev/null +++ b/usr/src/lib/efcode/engine/font.c @@ -0,0 +1,48 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <fcode/private.h> + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + ASSERT(env); + NOTICE; + + P1275(0x16a, 0, "default-font", fc_unimplemented); + P1275(0x16b, 0, "set-font", fc_unimplemented); + P1275(0x16c, 0, "char-height", fc_unimplemented); + P1275(0x16d, 0, "char-width", fc_unimplemented); + P1275(0x16e, 0, ">font", fc_unimplemented); + P1275(0x16f, 0, "fontbytes", fc_unimplemented); +} diff --git a/usr/src/lib/efcode/engine/forth.c b/usr/src/lib/efcode/engine/forth.c new file mode 100644 index 0000000000..b0b8005342 --- /dev/null +++ b/usr/src/lib/efcode/engine/forth.c @@ -0,0 +1,2675 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2000 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <ctype.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +void (*semi_ptr)(fcode_env_t *env) = do_semi; +void (*does_ptr)(fcode_env_t *env) = install_does; +void (*quote_ptr)(fcode_env_t *env) = do_quote; +void (*blit_ptr)(fcode_env_t *env) = do_literal; +void (*tlit_ptr)(fcode_env_t *env) = do_literal; +void (*do_bdo_ptr)(fcode_env_t *env) = do_bdo; +void (*do_bqdo_ptr)(fcode_env_t *env) = do_bqdo; +void (*create_ptr)(fcode_env_t *env) = do_creator; +void (*do_leave_ptr)(fcode_env_t *env) = do_bleave; +void (*do_loop_ptr)(fcode_env_t *env) = do_bloop; +void (*do_ploop_ptr)(fcode_env_t *env) = do_bploop; + +void unaligned_lstore(fcode_env_t *); +void unaligned_wstore(fcode_env_t *); +void unaligned_lfetch(fcode_env_t *); +void unaligned_wfetch(fcode_env_t *); + +/* start with the simple maths functions */ + + +void +add(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "+"); + d = POP(DS); + TOS += d; +} + +void +subtract(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "-"); + d = POP(DS); + TOS -= d; +} + +void +multiply(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "*"); + d = POP(DS); + TOS *= d; +} + +void +slash_mod(fcode_env_t *env) +{ + fstack_t d, o, t, rem; + int sign = 1; + + CHECK_DEPTH(env, 2, "/mod"); + d = POP(DS); + o = t = POP(DS); + + if (d == 0) { + throw_from_fclib(env, 1, "/mod divide by zero"); + } + sign = ((d ^ t) < 0); + if (d < 0) { + d = -d; + if (sign) { + t += (d-1); + } + } + if (t < 0) { + if (sign) { + t -= (d-1); + } + t = -t; + } + t = t / d; + if ((o ^ sign) < 0) { + rem = (t * d) + o; + } else { + rem = o - (t*d); + } + if (sign) { + t = -t; + } + PUSH(DS, rem); + PUSH(DS, t); +} + +/* + * 'u/mod' Fcode implementation. + */ +void +uslash_mod(fcode_env_t *env) +{ + u_lforth_t u1, u2; + + CHECK_DEPTH(env, 2, "u/mod"); + u2 = POP(DS); + u1 = POP(DS); + + if (u2 == 0) + forth_abort(env, "u/mod: divide by zero"); + PUSH(DS, u1 % u2); + PUSH(DS, u1 / u2); +} + +void +divide(fcode_env_t *env) +{ + CHECK_DEPTH(env, 2, "/"); + slash_mod(env); + nip(env); +} + +void +mod(fcode_env_t *env) +{ + CHECK_DEPTH(env, 2, "mod"); + slash_mod(env); + drop(env); +} + +void +and(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "and"); + d = POP(DS); + TOS &= d; +} + +void +or(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "or"); + d = POP(DS); + TOS |= d; +} + +void +xor(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "xor"); + d = POP(DS); + TOS ^= d; +} + +void +invert(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "invert"); + TOS = ~TOS; +} + +void +lshift(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "lshift"); + d = POP(DS); + TOS = TOS << d; +} + +void +rshift(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "rshift"); + d = POP(DS); + TOS = ((ufstack_t)TOS) >> d; +} + +void +rshifta(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, ">>a"); + d = POP(DS); + TOS = ((s_lforth_t)TOS) >> d; +} + +void +negate(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "negate"); + TOS = -TOS; +} + +void +f_abs(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "abs"); + if (TOS < 0) TOS = -TOS; +} + +void +f_min(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "min"); + d = POP(DS); + if (d < TOS) TOS = d; +} + +void +f_max(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "max"); + d = POP(DS); + if (d > TOS) TOS = d; +} + +void +to_r(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, ">r"); + PUSH(RS, POP(DS)); +} + +void +from_r(fcode_env_t *env) +{ + CHECK_RETURN_DEPTH(env, 1, "r>"); + PUSH(DS, POP(RS)); +} + +void +rfetch(fcode_env_t *env) +{ + CHECK_RETURN_DEPTH(env, 1, "r@"); + PUSH(DS, *RS); +} + +void +f_exit(fcode_env_t *env) +{ + CHECK_RETURN_DEPTH(env, 1, "exit"); + IP = (token_t *)POP(RS); +} + +#define COMPARE(cmp, rhs) ((((s_lforth_t)TOS) cmp((s_lforth_t)(rhs))) ? \ + TRUE : FALSE) +#define UCOMPARE(cmp, rhs) ((((u_lforth_t)TOS) cmp((u_lforth_t)(rhs))) ? \ + TRUE : FALSE) +#define EQUALS == +#define NOTEQUALS != +#define LESSTHAN < +#define LESSEQUALS <= +#define GREATERTHAN > +#define GREATEREQUALS >= + +void +zero_equals(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "0="); + TOS = COMPARE(EQUALS, 0); +} + +void +zero_not_equals(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "0<>"); + TOS = COMPARE(NOTEQUALS, 0); +} + +void +zero_less(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "0<"); + TOS = COMPARE(LESSTHAN, 0); +} + +void +zero_less_equals(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "0<="); + TOS = COMPARE(LESSEQUALS, 0); +} + +void +zero_greater(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "0>"); + TOS = COMPARE(GREATERTHAN, 0); +} + +void +zero_greater_equals(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "0>="); + TOS = COMPARE(GREATEREQUALS, 0); +} + +void +less(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "<"); + d = POP(DS); + TOS = COMPARE(LESSTHAN, d); +} + +void +greater(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, ">"); + d = POP(DS); + TOS = COMPARE(GREATERTHAN, d); +} + +void +equals(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "="); + d = POP(DS); + TOS = COMPARE(EQUALS, d); +} + +void +not_equals(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "<>"); + d = POP(DS); + TOS = COMPARE(NOTEQUALS, d); +} + + +void +unsign_greater(fcode_env_t *env) +{ + ufstack_t d; + + CHECK_DEPTH(env, 2, "u>"); + d = POP(DS); + TOS = UCOMPARE(GREATERTHAN, d); +} + +void +unsign_less_equals(fcode_env_t *env) +{ + ufstack_t d; + + CHECK_DEPTH(env, 2, "u<="); + d = POP(DS); + TOS = UCOMPARE(LESSEQUALS, d); +} + +void +unsign_less(fcode_env_t *env) +{ + ufstack_t d; + + CHECK_DEPTH(env, 2, "u<"); + d = POP(DS); + TOS = UCOMPARE(LESSTHAN, d); +} + +void +unsign_greater_equals(fcode_env_t *env) +{ + ufstack_t d; + + CHECK_DEPTH(env, 2, "u>="); + d = POP(DS); + TOS = UCOMPARE(GREATEREQUALS, d); +} + +void +greater_equals(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, ">="); + d = POP(DS); + TOS = COMPARE(GREATEREQUALS, d); +} + +void +less_equals(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "<="); + d = POP(DS); + TOS = COMPARE(LESSEQUALS, d); +} + +void +between(fcode_env_t *env) +{ + s_lforth_t hi, lo; + + CHECK_DEPTH(env, 3, "between"); + hi = (s_lforth_t)POP(DS); + lo = (s_lforth_t)POP(DS); + TOS = (((s_lforth_t)TOS >= lo) && ((s_lforth_t)TOS <= hi) ? -1 : 0); +} + +void +within(fcode_env_t *env) +{ + s_lforth_t lo, hi; + + CHECK_DEPTH(env, 3, "within"); + hi = (s_lforth_t)POP(DS); + lo = (s_lforth_t)POP(DS); + TOS = ((((s_lforth_t)TOS >= lo) && ((s_lforth_t)TOS < hi)) ? -1 : 0); +} + +void +do_literal(fcode_env_t *env) +{ + PUSH(DS, *IP); + IP++; +} + +void +literal(fcode_env_t *env) +{ + if (env->state) { + COMPILE_TOKEN(&blit_ptr); + compile_comma(env); + } +} + +void +do_also(fcode_env_t *env) +{ + token_t *d = *ORDER; + + if (env->order_depth < (MAX_ORDER - 1)) { + env->order[++env->order_depth] = d; + debug_msg(DEBUG_CONTEXT, "CONTEXT:also: %d/%p/%p\n", + env->order_depth, CONTEXT, env->current); + } else + log_message(MSG_WARN, "Vocabulary search order exceeds: %d\n", + MAX_ORDER); +} + +void +do_previous(fcode_env_t *env) +{ + if (env->order_depth) { + env->order_depth--; + debug_msg(DEBUG_CONTEXT, "CONTEXT:previous: %d/%p/%p\n", + env->order_depth, CONTEXT, env->current); + } +} + +#ifdef DEBUG +void +do_order(fcode_env_t *env) +{ + int i; + + log_message(MSG_INFO, "Order: Depth: %ld: ", env->order_depth); + for (i = env->order_depth; i >= 0 && env->order[i]; i--) + log_message(MSG_INFO, "%p ", (void *)env->order[i]); + log_message(MSG_INFO, "\n"); +} +#endif + +void +noop(fcode_env_t *env) +{ + /* what a waste of cycles */ +} + + +#define FW_PER_FL (sizeof (lforth_t)/sizeof (wforth_t)) + +void +lwsplit(fcode_env_t *env) +{ + union { + u_wforth_t l_wf[FW_PER_FL]; + u_lforth_t l_lf; + } d; + int i; + + CHECK_DEPTH(env, 1, "lwsplit"); + d.l_lf = POP(DS); + for (i = 0; i < FW_PER_FL; i++) + PUSH(DS, d.l_wf[(FW_PER_FL - 1) - i]); +} + +void +wljoin(fcode_env_t *env) +{ + union { + u_wforth_t l_wf[FW_PER_FL]; + u_lforth_t l_lf; + } d; + int i; + + CHECK_DEPTH(env, FW_PER_FL, "wljoin"); + for (i = 0; i < FW_PER_FL; i++) + d.l_wf[i] = POP(DS); + PUSH(DS, d.l_lf); +} + +void +lwflip(fcode_env_t *env) +{ + union { + u_wforth_t l_wf[FW_PER_FL]; + u_lforth_t l_lf; + } d, c; + int i; + + CHECK_DEPTH(env, 1, "lwflip"); + d.l_lf = POP(DS); + for (i = 0; i < FW_PER_FL; i++) + c.l_wf[i] = d.l_wf[(FW_PER_FL - 1) - i]; + PUSH(DS, c.l_lf); +} + +void +lbsplit(fcode_env_t *env) +{ + union { + uchar_t l_bytes[sizeof (lforth_t)]; + u_lforth_t l_lf; + } d; + int i; + + CHECK_DEPTH(env, 1, "lbsplit"); + d.l_lf = POP(DS); + for (i = 0; i < sizeof (lforth_t); i++) + PUSH(DS, d.l_bytes[(sizeof (lforth_t) - 1) - i]); +} + +void +bljoin(fcode_env_t *env) +{ + union { + uchar_t l_bytes[sizeof (lforth_t)]; + u_lforth_t l_lf; + } d; + int i; + + CHECK_DEPTH(env, sizeof (lforth_t), "bljoin"); + for (i = 0; i < sizeof (lforth_t); i++) + d.l_bytes[i] = POP(DS); + PUSH(DS, (fstack_t)d.l_lf); +} + +void +lbflip(fcode_env_t *env) +{ + union { + uchar_t l_bytes[sizeof (lforth_t)]; + u_lforth_t l_lf; + } d, c; + int i; + + CHECK_DEPTH(env, 1, "lbflip"); + d.l_lf = POP(DS); + for (i = 0; i < sizeof (lforth_t); i++) + c.l_bytes[i] = d.l_bytes[(sizeof (lforth_t) - 1) - i]; + PUSH(DS, c.l_lf); +} + +void +wbsplit(fcode_env_t *env) +{ + union { + uchar_t w_bytes[sizeof (wforth_t)]; + u_wforth_t w_wf; + } d; + int i; + + CHECK_DEPTH(env, 1, "wbsplit"); + d.w_wf = POP(DS); + for (i = 0; i < sizeof (wforth_t); i++) + PUSH(DS, d.w_bytes[(sizeof (wforth_t) - 1) - i]); +} + +void +bwjoin(fcode_env_t *env) +{ + union { + uchar_t w_bytes[sizeof (wforth_t)]; + u_wforth_t w_wf; + } d; + int i; + + CHECK_DEPTH(env, sizeof (wforth_t), "bwjoin"); + for (i = 0; i < sizeof (wforth_t); i++) + d.w_bytes[i] = POP(DS); + PUSH(DS, d.w_wf); +} + +void +wbflip(fcode_env_t *env) +{ + union { + uchar_t w_bytes[sizeof (wforth_t)]; + u_wforth_t w_wf; + } c, d; + int i; + + CHECK_DEPTH(env, 1, "wbflip"); + d.w_wf = POP(DS); + for (i = 0; i < sizeof (wforth_t); i++) + c.w_bytes[i] = d.w_bytes[(sizeof (wforth_t) - 1) - i]; + PUSH(DS, c.w_wf); +} + +void +upper_case(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "upc"); + TOS = toupper(TOS); +} + +void +lower_case(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "lcc"); + TOS = tolower(TOS); +} + +void +pack_str(fcode_env_t *env) +{ + char *buf; + size_t len; + char *str; + + CHECK_DEPTH(env, 3, "pack"); + buf = (char *)POP(DS); + len = (size_t)POP(DS); + str = (char *)TOS; + TOS = (fstack_t)buf; + *buf++ = (uchar_t)len; + strncpy(buf, str, (len&0xff)); +} + +void +count_str(fcode_env_t *env) +{ + uchar_t *len; + + CHECK_DEPTH(env, 1, "count"); + len = (uchar_t *)TOS; + TOS += 1; + PUSH(DS, *len); +} + +void +to_body(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, ">body"); + TOS = (fstack_t)(((acf_t)TOS)+1); +} + +void +to_acf(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "body>"); + TOS = (fstack_t)(((acf_t)TOS)-1); +} + +/* + * 'unloop' Fcode implementation, drop 3 loop ctrl elements off return stack. + */ +static void +unloop(fcode_env_t *env) +{ + CHECK_RETURN_DEPTH(env, 3, "unloop"); + RS -= 3; +} + +/* + * 'um*' Fcode implementation. + */ +static void +um_multiply(fcode_env_t *env) +{ + ufstack_t u1, u2; + dforth_t d; + + CHECK_DEPTH(env, 2, "um*"); + u1 = POP(DS); + u2 = POP(DS); + d = u1 * u2; + push_double(env, d); +} + +/* + * um/mod (d.lo d.hi u -- urem uquot) + */ +static void +um_slash_mod(fcode_env_t *env) +{ + u_dforth_t d; + uint32_t u, urem, uquot; + + CHECK_DEPTH(env, 3, "um/mod"); + u = (uint32_t)POP(DS); + d = pop_double(env); + urem = d % u; + uquot = d / u; + PUSH(DS, urem); + PUSH(DS, uquot); +} + +/* + * d+ (d1.lo d1.hi d2.lo d2.hi -- dsum.lo dsum.hi) + */ +static void +d_plus(fcode_env_t *env) +{ + dforth_t d1, d2; + + CHECK_DEPTH(env, 4, "d+"); + d2 = pop_double(env); + d1 = pop_double(env); + d1 += d2; + push_double(env, d1); +} + +/* + * d- (d1.lo d1.hi d2.lo d2.hi -- ddif.lo ddif.hi) + */ +static void +d_minus(fcode_env_t *env) +{ + dforth_t d1, d2; + + CHECK_DEPTH(env, 4, "d-"); + d2 = pop_double(env); + d1 = pop_double(env); + d1 -= d2; + push_double(env, d1); +} + +void +set_here(fcode_env_t *env, uchar_t *new_here, char *where) +{ + if (new_here < HERE) { + if (strcmp(where, "temporary_execute")) { + /* + * Other than temporary_execute, no one should set + * here backwards. + */ + log_message(MSG_WARN, "Warning: set_here(%s) back: old:" + " %p new: %p\n", where, HERE, new_here); + } + } + if (new_here >= env->base + dict_size) + forth_abort(env, "Here (%p) set past dictionary end (%p)", + new_here, env->base + dict_size); + HERE = new_here; +} + +static void +unaligned_store(fcode_env_t *env) +{ + extern void unaligned_xstore(fcode_env_t *); + + if (sizeof (fstack_t) == sizeof (lforth_t)) + unaligned_lstore(env); + else + unaligned_xstore(env); +} + +static void +unaligned_fetch(fcode_env_t *env) +{ + extern void unaligned_xfetch(fcode_env_t *); + + if (sizeof (fstack_t) == sizeof (lforth_t)) + unaligned_lfetch(env); + else + unaligned_xfetch(env); +} + +void +comma(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, ","); + DEBUGF(COMMA, dump_comma(env, ",")); + PUSH(DS, (fstack_t)HERE); + unaligned_store(env); + set_here(env, HERE + sizeof (fstack_t), "comma"); +} + +void +lcomma(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "l,"); + DEBUGF(COMMA, dump_comma(env, "l,")); + PUSH(DS, (fstack_t)HERE); + unaligned_lstore(env); + set_here(env, HERE + sizeof (u_lforth_t), "lcomma"); +} + +void +wcomma(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "w,"); + DEBUGF(COMMA, dump_comma(env, "w,")); + PUSH(DS, (fstack_t)HERE); + unaligned_wstore(env); + set_here(env, HERE + sizeof (u_wforth_t), "wcomma"); +} + +void +ccomma(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "c,"); + DEBUGF(COMMA, dump_comma(env, "c,")); + PUSH(DS, (fstack_t)HERE); + cstore(env); + set_here(env, HERE + sizeof (uchar_t), "ccomma"); +} + +void +token_roundup(fcode_env_t *env, char *where) +{ + if ((((token_t)HERE) & (sizeof (token_t) - 1)) != 0) { + set_here(env, (uchar_t *)TOKEN_ROUNDUP(HERE), where); + } +} + +void +compile_comma(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "compile,"); + DEBUGF(COMMA, dump_comma(env, "compile,")); + token_roundup(env, "compile,"); + PUSH(DS, (fstack_t)HERE); + unaligned_store(env); + set_here(env, HERE + sizeof (fstack_t), "compile,"); +} + +void +unaligned_lfetch(fcode_env_t *env) +{ + fstack_t addr; + int i; + + CHECK_DEPTH(env, 1, "unaligned-l@"); + addr = POP(DS); + for (i = 0; i < sizeof (lforth_t); i++, addr++) { + PUSH(DS, addr); + cfetch(env); + } + bljoin(env); + lbflip(env); +} + +void +unaligned_lstore(fcode_env_t *env) +{ + fstack_t addr; + int i; + + CHECK_DEPTH(env, 2, "unaligned-l!"); + addr = POP(DS); + lbsplit(env); + for (i = 0; i < sizeof (lforth_t); i++, addr++) { + PUSH(DS, addr); + cstore(env); + } +} + +void +unaligned_wfetch(fcode_env_t *env) +{ + fstack_t addr; + int i; + + CHECK_DEPTH(env, 1, "unaligned-w@"); + addr = POP(DS); + for (i = 0; i < sizeof (wforth_t); i++, addr++) { + PUSH(DS, addr); + cfetch(env); + } + bwjoin(env); + wbflip(env); +} + +void +unaligned_wstore(fcode_env_t *env) +{ + fstack_t addr; + int i; + + CHECK_DEPTH(env, 2, "unaligned-w!"); + addr = POP(DS); + wbsplit(env); + for (i = 0; i < sizeof (wforth_t); i++, addr++) { + PUSH(DS, addr); + cstore(env); + } +} + +/* + * 'lbflips' Fcode implementation. + */ +static void +lbflips(fcode_env_t *env) +{ + fstack_t len, addr; + int i; + + CHECK_DEPTH(env, 2, "lbflips"); + len = POP(DS); + addr = POP(DS); + for (i = 0; i < len; i += sizeof (lforth_t), + addr += sizeof (lforth_t)) { + PUSH(DS, addr); + unaligned_lfetch(env); + lbflip(env); + PUSH(DS, addr); + unaligned_lstore(env); + } +} + +/* + * 'wbflips' Fcode implementation. + */ +static void +wbflips(fcode_env_t *env) +{ + fstack_t len, addr; + int i; + + CHECK_DEPTH(env, 2, "wbflips"); + len = POP(DS); + addr = POP(DS); + for (i = 0; i < len; i += sizeof (wforth_t), + addr += sizeof (wforth_t)) { + PUSH(DS, addr); + unaligned_wfetch(env); + wbflip(env); + PUSH(DS, addr); + unaligned_wstore(env); + } +} + +/* + * 'lwflips' Fcode implementation. + */ +static void +lwflips(fcode_env_t *env) +{ + fstack_t len, addr; + int i; + + CHECK_DEPTH(env, 2, "lwflips"); + len = POP(DS); + addr = POP(DS); + for (i = 0; i < len; i += sizeof (lforth_t), + addr += sizeof (lforth_t)) { + PUSH(DS, addr); + unaligned_lfetch(env); + lwflip(env); + PUSH(DS, addr); + unaligned_lstore(env); + } +} + +void +base(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)&env->num_base); +} + +void +dot_s(fcode_env_t *env) +{ + output_data_stack(env, MSG_INFO); +} + +void +state(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)&env->state); +} + +int +is_digit(char digit, int num_base, fstack_t *dptr) +{ + int error = 0; + char base; + + if (num_base < 10) { + base = '0' + (num_base-1); + } else { + base = 'a' + (num_base - 10); + } + + *dptr = 0; + if (digit > '9') digit |= 0x20; + if (((digit < '0') || (digit > base)) || + ((digit > '9') && (digit < 'a') && (num_base > 10))) + error = 1; + else { + if (digit <= '9') + digit -= '0'; + else + digit = digit - 'a' + 10; + *dptr = digit; + } + return (error); +} + +void +dollar_number(fcode_env_t *env) +{ + char *buf; + fstack_t value; + int len, sign = 1, error = 0; + + CHECK_DEPTH(env, 2, "$number"); + buf = pop_a_string(env, &len); + if (*buf == '-') { + sign = -1; + buf++; + len--; + } + value = 0; + while (len-- && !error) { + fstack_t digit; + + if (*buf == '.') { + buf++; + continue; + } + value *= env->num_base; + error = is_digit(*buf++, env->num_base, &digit); + value += digit; + } + if (error) { + PUSH(DS, -1); + } else { + value *= sign; + PUSH(DS, value); + PUSH(DS, 0); + } +} + +void +digit(fcode_env_t *env) +{ + fstack_t base; + fstack_t value; + + CHECK_DEPTH(env, 2, "digit"); + base = POP(DS); + if (is_digit(TOS, base, &value)) + PUSH(DS, 0); + else { + TOS = value; + PUSH(DS, -1); + } +} + +void +space(fcode_env_t *env) +{ + PUSH(DS, ' '); +} + +void +backspace(fcode_env_t *env) +{ + PUSH(DS, '\b'); +} + +void +bell(fcode_env_t *env) +{ + PUSH(DS, '\a'); +} + +void +fc_bounds(fcode_env_t *env) +{ + fstack_t lo, hi; + + CHECK_DEPTH(env, 2, "bounds"); + lo = DS[-1]; + hi = TOS; + DS[-1] = lo+hi; + TOS = lo; +} + +void +here(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)HERE); +} + +void +aligned(fcode_env_t *env) +{ + ufstack_t a; + + CHECK_DEPTH(env, 1, "aligned"); + a = (TOS & (sizeof (lforth_t) - 1)); + if (a) + TOS += (sizeof (lforth_t) - a); +} + +void +instance(fcode_env_t *env) +{ + env->instance_mode |= 1; +} + +void +semi(fcode_env_t *env) +{ + + env->state &= ~1; + COMPILE_TOKEN(&semi_ptr); + + /* + * check if we need to supress expose action; + * If so this is an internal word and has no link field + * or it is a temporary compile + */ + + if (env->state == 0) { + expose_acf(env, "<semi>"); + } + if (env->state & 8) { + env->state ^= 8; + } +} + +void +do_create(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)WA); +} + +void +drop(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "drop"); + (void) POP(DS); +} + +void +f_dup(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 1, "dup"); + d = TOS; + PUSH(DS, d); +} + +void +over(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "over"); + d = DS[-1]; + PUSH(DS, d); +} + +void +swap(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "swap"); + d = DS[-1]; + DS[-1] = DS[0]; + DS[0] = d; +} + + +void +rot(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 3, "rot"); + d = DS[-2]; + DS[-2] = DS[-1]; + DS[-1] = TOS; + TOS = d; +} + +void +minus_rot(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 3, "-rot"); + d = TOS; + TOS = DS[-1]; + DS[-1] = DS[-2]; + DS[-2] = d; +} + +void +tuck(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "tuck"); + d = TOS; + swap(env); + PUSH(DS, d); +} + +void +nip(fcode_env_t *env) +{ + CHECK_DEPTH(env, 2, "nip"); + swap(env); + drop(env); +} + +void +qdup(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 1, "?dup"); + d = TOS; + if (d) + PUSH(DS, d); +} + +void +depth(fcode_env_t *env) +{ + fstack_t d; + + d = DS - env->ds0; + PUSH(DS, d); +} + +void +pick(fcode_env_t *env) +{ + fstack_t p; + + CHECK_DEPTH(env, 1, "pick"); + p = POP(DS); + if (p < 0 || p >= (env->ds - env->ds0)) + forth_abort(env, "pick: invalid pick value: %d\n", (int)p); + p = DS[-p]; + PUSH(DS, p); +} + +void +roll(fcode_env_t *env) +{ + fstack_t d, r; + + CHECK_DEPTH(env, 1, "roll"); + r = POP(DS); + if (r <= 0 || r >= (env->ds - env->ds0)) + forth_abort(env, "roll: invalid roll value: %d\n", (int)r); + + d = DS[-r]; + while (r) { + DS[-r] = DS[ -(r-1) ]; + r--; + } + TOS = d; +} + +void +two_drop(fcode_env_t *env) +{ + CHECK_DEPTH(env, 2, "2drop"); + DS -= 2; +} + +void +two_dup(fcode_env_t *env) +{ + CHECK_DEPTH(env, 2, "2dup"); + DS[1] = DS[-1]; + DS[2] = TOS; + DS += 2; +} + +void +two_over(fcode_env_t *env) +{ + fstack_t a, b; + + CHECK_DEPTH(env, 4, "2over"); + a = DS[-3]; + b = DS[-2]; + PUSH(DS, a); + PUSH(DS, b); +} + +void +two_swap(fcode_env_t *env) +{ + fstack_t a, b; + + CHECK_DEPTH(env, 4, "2swap"); + a = DS[-3]; + b = DS[-2]; + DS[-3] = DS[-1]; + DS[-2] = TOS; + DS[-1] = a; + TOS = b; +} + +void +two_rot(fcode_env_t *env) +{ + fstack_t a, b; + + CHECK_DEPTH(env, 6, "2rot"); + a = DS[-5]; + b = DS[-4]; + DS[-5] = DS[-3]; + DS[-4] = DS[-2]; + DS[-3] = DS[-1]; + DS[-2] = TOS; + DS[-1] = a; + TOS = b; +} + +void +two_slash(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "2/"); + TOS = TOS >> 1; +} + +void +utwo_slash(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "u2/"); + TOS = (ufstack_t)((ufstack_t)TOS) >> 1; +} + +void +two_times(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "2*"); + TOS = (ufstack_t)((ufstack_t)TOS) << 1; +} + +void +slash_c(fcode_env_t *env) +{ + PUSH(DS, sizeof (char)); +} + +void +slash_w(fcode_env_t *env) +{ + PUSH(DS, sizeof (wforth_t)); +} + +void +slash_l(fcode_env_t *env) +{ + PUSH(DS, sizeof (lforth_t)); +} + +void +slash_n(fcode_env_t *env) +{ + PUSH(DS, sizeof (fstack_t)); +} + +void +ca_plus(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "ca+"); + d = POP(DS); + TOS += d * sizeof (char); +} + +void +wa_plus(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "wa+"); + d = POP(DS); + TOS += d * sizeof (wforth_t); +} + +void +la_plus(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "la+"); + d = POP(DS); + TOS += d * sizeof (lforth_t); +} + +void +na_plus(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "na+"); + d = POP(DS); + TOS += d * sizeof (fstack_t); +} + +void +char_plus(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "char+"); + TOS += sizeof (char); +} + +void +wa1_plus(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "wa1+"); + TOS += sizeof (wforth_t); +} + +void +la1_plus(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "la1+"); + TOS += sizeof (lforth_t); +} + +void +cell_plus(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "cell+"); + TOS += sizeof (fstack_t); +} + +void +do_chars(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "chars"); +} + +void +slash_w_times(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "/w*"); + TOS *= sizeof (wforth_t); +} + +void +slash_l_times(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "/l*"); + TOS *= sizeof (lforth_t); +} + +void +cells(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "cells"); + TOS *= sizeof (fstack_t); +} + +void +do_on(fcode_env_t *env) +{ + variable_t *d; + + CHECK_DEPTH(env, 1, "on"); + d = (variable_t *)POP(DS); + *d = -1; +} + +void +do_off(fcode_env_t *env) +{ + variable_t *d; + + CHECK_DEPTH(env, 1, "off"); + d = (variable_t *)POP(DS); + *d = 0; +} + +void +fetch(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "@"); + TOS = *((variable_t *)TOS); +} + +void +lfetch(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "l@"); + TOS = *((lforth_t *)TOS); +} + +void +wfetch(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "w@"); + TOS = *((wforth_t *)TOS); +} + +void +swfetch(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "<w@"); + TOS = *((s_wforth_t *)TOS); +} + +void +cfetch(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "c@"); + TOS = *((uchar_t *)TOS); +} + +void +store(fcode_env_t *env) +{ + variable_t *dptr; + + CHECK_DEPTH(env, 2, "!"); + dptr = (variable_t *)POP(DS); + *dptr = POP(DS); +} + +void +addstore(fcode_env_t *env) +{ + variable_t *dptr; + + CHECK_DEPTH(env, 2, "+!"); + dptr = (variable_t *)POP(DS); + *dptr = POP(DS) + *dptr; +} + +void +lstore(fcode_env_t *env) +{ + lforth_t *dptr; + + CHECK_DEPTH(env, 2, "l!"); + dptr = (lforth_t *)POP(DS); + *dptr = (lforth_t)POP(DS); +} + +void +wstore(fcode_env_t *env) +{ + wforth_t *dptr; + + CHECK_DEPTH(env, 2, "w!"); + dptr = (wforth_t *)POP(DS); + *dptr = (wforth_t)POP(DS); +} + +void +cstore(fcode_env_t *env) +{ + uchar_t *dptr; + + CHECK_DEPTH(env, 2, "c!"); + dptr = (uchar_t *)POP(DS); + *dptr = (uchar_t)POP(DS); +} + +void +two_fetch(fcode_env_t *env) +{ + variable_t *d; + + CHECK_DEPTH(env, 1, "2@"); + d = (variable_t *)POP(DS); + PUSH(DS, (fstack_t)(d + 1)); + unaligned_fetch(env); + PUSH(DS, (fstack_t)d); + unaligned_fetch(env); +} + +void +two_store(fcode_env_t *env) +{ + variable_t *d; + + CHECK_DEPTH(env, 3, "2!"); + d = (variable_t *)POP(DS); + PUSH(DS, (fstack_t)d); + unaligned_store(env); + PUSH(DS, (fstack_t)(d + 1)); + unaligned_store(env); +} + +/* + * 'move' Fcode reimplemented in fcdriver to check for mapped addresses. + */ +void +fc_move(fcode_env_t *env) +{ + void *dest, *src; + size_t len; + + CHECK_DEPTH(env, 3, "move"); + len = (size_t)POP(DS); + dest = (void *)POP(DS); + src = (void *)POP(DS); + + memmove(dest, src, len); +} + +void +fc_fill(fcode_env_t *env) +{ + void *dest; + uchar_t val; + size_t len; + + CHECK_DEPTH(env, 3, "fill"); + val = (uchar_t)POP(DS); + len = (size_t)POP(DS); + dest = (void *)POP(DS); + memset(dest, val, len); +} + +void +fc_comp(fcode_env_t *env) +{ + char *str1, *str2; + size_t len; + int res; + + CHECK_DEPTH(env, 3, "comp"); + len = (size_t)POP(DS); + str1 = (char *)POP(DS); + str2 = (char *)POP(DS); + res = memcmp(str2, str1, len); + if (res > 0) + res = 1; + else if (res < 0) + res = -1; + PUSH(DS, res); +} + +void +set_temporary_compile(fcode_env_t *env) +{ + if (!env->state) { + token_roundup(env, "set_temporary_compile"); + PUSH(RS, (fstack_t)HERE); + env->state = 3; + COMPILE_TOKEN(&do_colon); + } +} + +void +bmark(fcode_env_t *env) +{ + set_temporary_compile(env); + env->level++; + PUSH(DS, (fstack_t)HERE); +} + +void +temporary_execute(fcode_env_t *env) +{ + uchar_t *saved_here; + + if ((env->level == 0) && (env->state & 2)) { + fstack_t d = POP(RS); + + semi(env); + + saved_here = HERE; + /* execute the temporary definition */ + env->state &= ~2; + PUSH(DS, d); + execute(env); + + /* now wind the dictionary back! */ + if (saved_here != HERE) { + debug_msg(DEBUG_COMMA, "Ignoring set_here in" + " temporary_execute\n"); + } else + set_here(env, (uchar_t *)d, "temporary_execute"); + } +} + +void +bresolve(fcode_env_t *env) +{ + token_t *prev = (token_t *)POP(DS); + + env->level--; + *prev = (token_t)HERE; + temporary_execute(env); +} + +#define BRANCH_IP(ipp) ((token_t *)(*((token_t *)(ipp)))) + +void +do_bbranch(fcode_env_t *env) +{ + IP = BRANCH_IP(IP); +} + +void +do_bqbranch(fcode_env_t *env) +{ + fstack_t flag; + + CHECK_DEPTH(env, 1, "b?branch"); + flag = POP(DS); + if (flag) { + IP++; + } else { + IP = BRANCH_IP(IP); + } +} + +void +do_bofbranch(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 2, "bofbranch"); + d = POP(DS); + if (d == TOS) { + (void) POP(DS); + IP++; + } else { + IP = BRANCH_IP(IP); + } +} + +void +do_bleave(fcode_env_t *env) +{ + CHECK_RETURN_DEPTH(env, 3, "do_bleave"); + (void) POP(RS); + (void) POP(RS); + IP = (token_t *)POP(RS); +} + +void +loop_inc(fcode_env_t *env, fstack_t inc) +{ + ufstack_t a; + + CHECK_RETURN_DEPTH(env, 2, "loop_inc"); + + /* + * Note: end condition is when the sign bit of R[0] changes. + */ + a = RS[0]; + RS[0] += inc; + if (((a ^ RS[0]) & SIGN_BIT) == 0) { + IP = BRANCH_IP(IP); + } else { + do_bleave(env); + } +} + +void +do_bloop(fcode_env_t *env) +{ + loop_inc(env, 1); +} + +void +do_bploop(fcode_env_t *env) +{ + fstack_t d; + + CHECK_DEPTH(env, 1, "+loop"); + d = POP(DS); + loop_inc(env, d); +} + +void +loop_common(fcode_env_t *env, fstack_t ptr) +{ + short offset = get_short(env); + + COMPILE_TOKEN(ptr); + env->level--; + compile_comma(env); + bresolve(env); +} + +void +bloop(fcode_env_t *env) +{ + loop_common(env, (fstack_t)&do_loop_ptr); +} + +void +bplusloop(fcode_env_t *env) +{ + loop_common(env, (fstack_t)&do_ploop_ptr); +} + +void +common_do(fcode_env_t *env, fstack_t endpt, fstack_t start, fstack_t limit) +{ + ufstack_t i, l; + + /* + * Same computation as OBP, sets up so that loop_inc will terminate + * when the sign bit of RS[0] changes. + */ + i = (start - limit) - SIGN_BIT; + l = limit + SIGN_BIT; + PUSH(RS, endpt); + PUSH(RS, l); + PUSH(RS, i); +} + +void +do_bdo(fcode_env_t *env) +{ + fstack_t lo, hi; + fstack_t endpt; + + CHECK_DEPTH(env, 2, "bdo"); + endpt = (fstack_t)BRANCH_IP(IP); + IP++; + lo = POP(DS); + hi = POP(DS); + common_do(env, endpt, lo, hi); +} + +void +do_bqdo(fcode_env_t *env) +{ + fstack_t lo, hi; + fstack_t endpt; + + CHECK_DEPTH(env, 2, "b?do"); + endpt = (fstack_t)BRANCH_IP(IP); + IP++; + lo = POP(DS); + hi = POP(DS); + if (lo == hi) { + IP = (token_t *)endpt; + } else { + common_do(env, endpt, lo, hi); + } +} + +void +compile_do_common(fcode_env_t *env, fstack_t ptr) +{ + set_temporary_compile(env); + COMPILE_TOKEN(ptr); + bmark(env); + COMPILE_TOKEN(0); + bmark(env); +} + +void +bdo(fcode_env_t *env) +{ + short offset = (short)get_short(env); + compile_do_common(env, (fstack_t)&do_bdo_ptr); +} + +void +bqdo(fcode_env_t *env) +{ + short offset = (short)get_short(env); + compile_do_common(env, (fstack_t)&do_bqdo_ptr); +} + +void +loop_i(fcode_env_t *env) +{ + fstack_t i; + + CHECK_RETURN_DEPTH(env, 2, "i"); + i = RS[0] + RS[-1]; + PUSH(DS, i); +} + +void +loop_j(fcode_env_t *env) +{ + fstack_t j; + + CHECK_RETURN_DEPTH(env, 5, "j"); + j = RS[-3] + RS[-4]; + PUSH(DS, j); +} + +void +bleave(fcode_env_t *env) +{ + + if (env->state) { + COMPILE_TOKEN(&do_leave_ptr); + } +} + +void +push_string(fcode_env_t *env, char *str, int len) +{ +#define NSTRINGS 16 + static int string_count = 0; + static int buflen[NSTRINGS]; + static char *buffer[NSTRINGS]; + char *dest; + + if (!len) { + PUSH(DS, 0); + PUSH(DS, 0); + return; + } + if (len != buflen[string_count]) { + if (buffer[string_count]) FREE(buffer[string_count]); + buffer[ string_count ] = (char *)MALLOC(len+1); + buflen[ string_count ] = len; + } + dest = buffer[ string_count++ ]; + string_count = string_count%NSTRINGS; + memcpy(dest, str, len); + *(dest+len) = 0; + PUSH(DS, (fstack_t)dest); + PUSH(DS, len); +#undef NSTRINGS +} + +void +parse_word(fcode_env_t *env) +{ + int len = 0; + char *next, *dest, *here = ""; + + if (env->input) { + here = env->input->scanptr; + while (*here == env->input->separator) here++; + next = strchr(here, env->input->separator); + if (next) { + len = next - here; + while (*next == env->input->separator) next++; + } else { + len = strlen(here); + next = here + len; + } + env->input->scanptr = next; + } + push_string(env, here, len); +} + +void +install_does(fcode_env_t *env) +{ + token_t *dptr; + + dptr = (token_t *)LINK_TO_ACF(env->lastlink); + + log_message(MSG_WARN, "install_does: Last acf at: %p\n", (void *)dptr); + + *dptr = ((token_t)(IP+1)) | 1; +} + +void +does(fcode_env_t *env) +{ + token_t *dptr; + + token_roundup(env, "does"); + + if (env->state) { + COMPILE_TOKEN(&does_ptr); + COMPILE_TOKEN(&semi_ptr); + } else { + dptr = (token_t *)LINK_TO_ACF(env->lastlink); + log_message(MSG_WARN, "does: Last acf at: %p\n", (void *)dptr); + *dptr = ((token_t)(HERE)) | 1; + env->state |= 1; + } + COMPILE_TOKEN(&do_colon); +} + +void +do_current(fcode_env_t *env) +{ + debug_msg(DEBUG_CONTEXT, "CONTEXT:pushing &CURRENT\n"); + PUSH(DS, (fstack_t)&env->current); +} + +void +do_context(fcode_env_t *env) +{ + debug_msg(DEBUG_CONTEXT, "CONTEXT:pushing &CONTEXT\n"); + PUSH(DS, (fstack_t)&CONTEXT); +} + +void +do_definitions(fcode_env_t *env) +{ + env->current = CONTEXT; + debug_msg(DEBUG_CONTEXT, "CONTEXT:definitions: %d/%p/%p\n", + env->order_depth, CONTEXT, env->current); +} + +void +make_header(fcode_env_t *env, int flags) +{ + int len; + char *name; + + name = parse_a_string(env, &len); + header(env, name, len, flags); +} + +void +do_creator(fcode_env_t *env) +{ + make_header(env, 0); + COMPILE_TOKEN(&do_create); + expose_acf(env, "<create>"); +} + +void +create(fcode_env_t *env) +{ + if (env->state) { + COMPILE_TOKEN(&create_ptr); + } else + do_creator(env); +} + +void +colon(fcode_env_t *env) +{ + make_header(env, 0); + env->state |= 1; + COMPILE_TOKEN(&do_colon); +} + +void +recursive(fcode_env_t *env) +{ + expose_acf(env, "<recursive>"); +} + +void +compile_string(fcode_env_t *env) +{ + int len; + uchar_t *str, *tostr; + + COMPILE_TOKEN("e_ptr); + len = POP(DS); + str = (uchar_t *)POP(DS); + tostr = HERE; + *tostr++ = len; + while (len--) + *tostr++ = *str++; + *tostr++ = '\0'; + set_here(env, tostr, "compile_string"); + token_roundup(env, "compile_string"); +} + +void +run_quote(fcode_env_t *env) +{ + char osep; + + osep = env->input->separator; + env->input->separator = '"'; + parse_word(env); + env->input->separator = osep; + + if (env->state) { + compile_string(env); + } +} + +void +does_vocabulary(fcode_env_t *env) +{ + CONTEXT = WA; + debug_msg(DEBUG_CONTEXT, "CONTEXT:vocabulary: %d/%p/%p\n", + env->order_depth, CONTEXT, env->current); +} + +void +do_vocab(fcode_env_t *env) +{ + make_header(env, 0); + COMPILE_TOKEN(does_vocabulary); + PUSH(DS, 0); + compile_comma(env); + expose_acf(env, "<vocabulary>"); +} + +void +do_forth(fcode_env_t *env) +{ + CONTEXT = (token_t *)(&env->forth_voc_link); + debug_msg(DEBUG_CONTEXT, "CONTEXT:forth: %d/%p/%p\n", + env->order_depth, CONTEXT, env->current); +} + +acf_t +voc_find(fcode_env_t *env) +{ + token_t *voc; + token_t *dptr; + char *find_name, *name; + + voc = (token_t *)POP(DS); + find_name = pop_a_string(env, NULL); + + for (dptr = (token_t *)(*voc); dptr; dptr = (token_t *)(*dptr)) { + if ((name = get_name(dptr)) == NULL) + continue; + if (strcmp(find_name, name) == 0) { + debug_msg(DEBUG_VOC_FIND, "%s -> %p\n", find_name, + LINK_TO_ACF(dptr)); + return (LINK_TO_ACF(dptr)); + } + } + debug_msg(DEBUG_VOC_FIND, "%s not found\n", find_name); + return (NULL); +} + +void +dollar_find(fcode_env_t *env) +{ + acf_t acf = NULL; + int i; + + CHECK_DEPTH(env, 2, "$find"); + for (i = env->order_depth; i >= 0 && env->order[i] && !acf; i--) { + two_dup(env); + PUSH(DS, (fstack_t)env->order[i]); + acf = voc_find(env); + } + if (acf) { + two_drop(env); + PUSH(DS, (fstack_t)acf); + PUSH(DS, TRUE); + } else + PUSH(DS, FALSE); +} + +void +interpret(fcode_env_t *env) +{ + char *name; + + parse_word(env); + while (TOS) { + two_dup(env); + dollar_find(env); + if (TOS) { + flag_t *flags; + + drop(env); + nip(env); + nip(env); + flags = LINK_TO_FLAGS(ACF_TO_LINK(TOS)); + + if ((env->state) && + ((*flags & IMMEDIATE) == 0)) { + /* Compile in references */ + compile_comma(env); + } else { + execute(env); + } + } else { + int bad; + drop(env); + dollar_number(env); + bad = POP(DS); + if (bad) { + two_dup(env); + name = pop_a_string(env, NULL); + log_message(MSG_INFO, "%s?\n", name); + break; + } else { + nip(env); + nip(env); + literal(env); + } + } + parse_word(env); + } + two_drop(env); +} + +void +evaluate(fcode_env_t *env) +{ + input_typ *old_input = env->input; + input_typ *eval_bufp = MALLOC(sizeof (input_typ)); + + CHECK_DEPTH(env, 2, "evaluate"); + eval_bufp->separator = ' '; + eval_bufp->maxlen = POP(DS); + eval_bufp->buffer = (char *)POP(DS); + eval_bufp->scanptr = eval_bufp->buffer; + env->input = eval_bufp; + interpret(env); + FREE(eval_bufp); + env->input = old_input; +} + +void +make_common_access(fcode_env_t *env, + char *name, int len, + int ncells, + int instance_mode, + void (*acf_instance)(fcode_env_t *env), + void (*acf_static)(fcode_env_t *env), + void (*set_action)(fcode_env_t *env, int)) +{ + if (instance_mode && !MYSELF) { + system_message(env, "No instance context"); + } + + debug_msg(DEBUG_ACTIONS, "make_common_access:%s '%s', %d\n", + (instance_mode ? "instance" : ""), + (name ? name : ""), ncells); + + if (len) + header(env, name, len, 0); + if (instance_mode) { + token_t *dptr; + int offset; + + COMPILE_TOKEN(acf_instance); + dptr = alloc_instance_data(env, INIT_DATA, ncells, &offset); + debug_msg(DEBUG_ACTIONS, "Data: %p, offset %d\n", (char *)dptr, + offset); + PUSH(DS, offset); + compile_comma(env); + while (ncells--) + *dptr++ = MYSELF->data[INIT_DATA][offset++] = POP(DS); + env->instance_mode = 0; + } else { + COMPILE_TOKEN(acf_static); + while (ncells--) + compile_comma(env); + } + expose_acf(env, name); + if (set_action) + set_action(env, instance_mode); +} + +void +do_constant(fcode_env_t *env) +{ + PUSH(DS, (variable_t)(*WA)); +} + +void +do_crash(fcode_env_t *env) +{ + forth_abort(env, "Unitialized defer"); +} + +/* + * 'behavior' Fcode retrieve execution behavior for a defer word. + */ +static void +behavior(fcode_env_t *env) +{ + acf_t defer_xt; + token_t token; + acf_t contents_xt; + + CHECK_DEPTH(env, 1, "behavior"); + defer_xt = (acf_t)POP(DS); + token = *defer_xt; + contents_xt = (token_t *)(token & ~1); + if ((token & 1) == 0 || *contents_xt != (token_t)&do_default_action) + forth_abort(env, "behavior: bad xt: %p indir: %x/%p\n", + defer_xt, token & 1, *contents_xt); + defer_xt++; + PUSH(DS, *((variable_t *)defer_xt)); +} + +void +fc_abort(fcode_env_t *env, char *type) +{ + forth_abort(env, "%s Fcode '%s' Executed", type, + acf_to_name(env, WA - 1)); +} + +void +f_abort(fcode_env_t *env) +{ + fc_abort(env, "Abort"); +} + +/* + * Fcodes chosen not to support. + */ +void +fc_unimplemented(fcode_env_t *env) +{ + fc_abort(env, "Unimplemented"); +} + +/* + * Fcodes that are Obsolete per P1275-1994. + */ +void +fc_obsolete(fcode_env_t *env) +{ + fc_abort(env, "Obsolete"); +} + +/* + * Fcodes that are Historical per P1275-1994 + */ +void +fc_historical(fcode_env_t *env) +{ + fc_abort(env, "Historical"); +} + +void +catch(fcode_env_t *env) +{ + error_frame *new; + + CHECK_DEPTH(env, 1, "catch"); + new = MALLOC(sizeof (error_frame)); + new->ds = DS-1; + new->rs = RS; + new->myself = MYSELF; + new->next = env->catch_frame; + new->code = 0; + env->catch_frame = new; + execute(env); + PUSH(DS, new->code); + env->catch_frame = new->next; + FREE(new); +} + +void +throw_from_fclib(fcode_env_t *env, fstack_t errcode, char *fmt, ...) +{ + error_frame *efp; + va_list ap; + char msg[256]; + + va_start(ap, fmt); + vsprintf(msg, fmt, ap); + + if (errcode) { + + env->last_error = errcode; + + /* + * No catch frame set => fatal error + */ + efp = env->catch_frame; + if (!efp) + forth_abort(env, "%s: No catch frame", msg); + + debug_msg(DEBUG_TRACING, "throw_from_fclib: throw: %s\n", msg); + + /* + * Setting IP=0 will force the unwinding of the calls + * (see execute) which is how we will return (eventually) + * to the test in catch that follows 'execute'. + */ + DS = efp->ds; + RS = efp->rs; + MYSELF = efp->myself; + IP = 0; + efp->code = errcode; + } +} + +void +throw(fcode_env_t *env) +{ + fstack_t t; + + CHECK_DEPTH(env, 1, "throw"); + t = POP(DS); + if (t >= -20 && t <= 20) + throw_from_fclib(env, t, "throw Fcode errcode: 0x%x", (int)t); + else { + if (t) + log_message(MSG_ERROR, "throw: errcode: 0x%x\n", + (int)t); + throw_from_fclib(env, t, "throw Fcode err: %s", (char *)t); + } +} + +void +tick_literal(fcode_env_t *env) +{ + if (env->state) { + COMPILE_TOKEN(&tlit_ptr); + compile_comma(env); + } +} + +void +do_tick(fcode_env_t *env) +{ + parse_word(env); + dollar_find(env); + invert(env); + throw(env); + tick_literal(env); +} + +void +bracket_tick(fcode_env_t *env) +{ + do_tick(env); +} + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + NOTICE; + ASSERT(env); + + ANSI(0x019, 0, "i", loop_i); + ANSI(0x01a, 0, "j", loop_j); + ANSI(0x01d, 0, "execute", execute); + ANSI(0x01e, 0, "+", add); + ANSI(0x01f, 0, "-", subtract); + ANSI(0x020, 0, "*", multiply); + ANSI(0x021, 0, "/", divide); + ANSI(0x022, 0, "mod", mod); + FORTH(0, "/mod", slash_mod); + ANSI(0x023, 0, "and", and); + ANSI(0x024, 0, "or", or); + ANSI(0x025, 0, "xor", xor); + ANSI(0x026, 0, "invert", invert); + ANSI(0x027, 0, "lshift", lshift); + ANSI(0x028, 0, "rshift", rshift); + ANSI(0x029, 0, ">>a", rshifta); + ANSI(0x02a, 0, "/mod", slash_mod); + ANSI(0x02b, 0, "u/mod", uslash_mod); + ANSI(0x02c, 0, "negate", negate); + ANSI(0x02d, 0, "abs", f_abs); + ANSI(0x02e, 0, "min", f_min); + ANSI(0x02f, 0, "max", f_max); + ANSI(0x030, 0, ">r", to_r); + ANSI(0x031, 0, "r>", from_r); + ANSI(0x032, 0, "r@", rfetch); + ANSI(0x033, 0, "exit", f_exit); + ANSI(0x034, 0, "0=", zero_equals); + ANSI(0x035, 0, "0<>", zero_not_equals); + ANSI(0x036, 0, "0<", zero_less); + ANSI(0x037, 0, "0<=", zero_less_equals); + ANSI(0x038, 0, "0>", zero_greater); + ANSI(0x039, 0, "0>=", zero_greater_equals); + ANSI(0x03a, 0, "<", less); + ANSI(0x03b, 0, ">", greater); + ANSI(0x03c, 0, "=", equals); + ANSI(0x03d, 0, "<>", not_equals); + ANSI(0x03e, 0, "u>", unsign_greater); + ANSI(0x03f, 0, "u<=", unsign_less_equals); + ANSI(0x040, 0, "u<", unsign_less); + ANSI(0x041, 0, "u>=", unsign_greater_equals); + ANSI(0x042, 0, ">=", greater_equals); + ANSI(0x043, 0, "<=", less_equals); + ANSI(0x044, 0, "between", between); + ANSI(0x045, 0, "within", within); + ANSI(0x046, 0, "drop", drop); + ANSI(0x047, 0, "dup", f_dup); + ANSI(0x048, 0, "over", over); + ANSI(0x049, 0, "swap", swap); + ANSI(0x04a, 0, "rot", rot); + ANSI(0x04b, 0, "-rot", minus_rot); + ANSI(0x04c, 0, "tuck", tuck); + ANSI(0x04d, 0, "nip", nip); + ANSI(0x04e, 0, "pick", pick); + ANSI(0x04f, 0, "roll", roll); + ANSI(0x050, 0, "?dup", qdup); + ANSI(0x051, 0, "depth", depth); + ANSI(0x052, 0, "2drop", two_drop); + ANSI(0x053, 0, "2dup", two_dup); + ANSI(0x054, 0, "2over", two_over); + ANSI(0x055, 0, "2swap", two_swap); + ANSI(0x056, 0, "2rot", two_rot); + ANSI(0x057, 0, "2/", two_slash); + ANSI(0x058, 0, "u2/", utwo_slash); + ANSI(0x059, 0, "2*", two_times); + ANSI(0x05a, 0, "/c", slash_c); + ANSI(0x05b, 0, "/w", slash_w); + ANSI(0x05c, 0, "/l", slash_l); + ANSI(0x05d, 0, "/n", slash_n); + ANSI(0x05e, 0, "ca+", ca_plus); + ANSI(0x05f, 0, "wa+", wa_plus); + ANSI(0x060, 0, "la+", la_plus); + ANSI(0x061, 0, "na+", na_plus); + ANSI(0x062, 0, "char+", char_plus); + ANSI(0x063, 0, "wa1+", wa1_plus); + ANSI(0x064, 0, "la1+", la1_plus); + ANSI(0x065, 0, "cell+", cell_plus); + ANSI(0x066, 0, "chars", do_chars); + ANSI(0x067, 0, "/w*", slash_w_times); + ANSI(0x068, 0, "/l*", slash_l_times); + ANSI(0x069, 0, "cells", cells); + ANSI(0x06a, 0, "on", do_on); + ANSI(0x06b, 0, "off", do_off); + ANSI(0x06c, 0, "+!", addstore); + ANSI(0x06d, 0, "@", fetch); + ANSI(0x06e, 0, "l@", lfetch); + ANSI(0x06f, 0, "w@", wfetch); + ANSI(0x070, 0, "<w@", swfetch); + ANSI(0x071, 0, "c@", cfetch); + ANSI(0x072, 0, "!", store); + ANSI(0x073, 0, "l!", lstore); + ANSI(0x074, 0, "w!", wstore); + ANSI(0x075, 0, "c!", cstore); + ANSI(0x076, 0, "2@", two_fetch); + ANSI(0x077, 0, "2!", two_store); + ANSI(0x078, 0, "move", fc_move); + ANSI(0x079, 0, "fill", fc_fill); + ANSI(0x07a, 0, "comp", fc_comp); + ANSI(0x07b, 0, "noop", noop); + ANSI(0x07c, 0, "lwsplit", lwsplit); + ANSI(0x07d, 0, "wljoin", wljoin); + ANSI(0x07e, 0, "lbsplit", lbsplit); + ANSI(0x07f, 0, "bljoin", bljoin); + ANSI(0x080, 0, "wbflip", wbflip); + ANSI(0x081, 0, "upc", upper_case); + ANSI(0x082, 0, "lcc", lower_case); + ANSI(0x083, 0, "pack", pack_str); + ANSI(0x084, 0, "count", count_str); + ANSI(0x085, 0, "body>", to_acf); + ANSI(0x086, 0, ">body", to_body); + + ANSI(0x089, 0, "unloop", unloop); + + ANSI(0x09f, 0, ".s", dot_s); + ANSI(0x0a0, 0, "base", base); + FCODE(0x0a1, 0, "convert", fc_historical); + ANSI(0x0a2, 0, "$number", dollar_number); + ANSI(0x0a3, 0, "digit", digit); + + ANSI(0x0a9, 0, "bl", space); + ANSI(0x0aa, 0, "bs", backspace); + ANSI(0x0ab, 0, "bell", bell); + ANSI(0x0ac, 0, "bounds", fc_bounds); + ANSI(0x0ad, 0, "here", here); + + ANSI(0x0af, 0, "wbsplit", wbsplit); + ANSI(0x0b0, 0, "bwjoin", bwjoin); + + P1275(0x0cb, 0, "$find", dollar_find); + + ANSI(0x0d0, 0, "c,", ccomma); + ANSI(0x0d1, 0, "w,", wcomma); + ANSI(0x0d2, 0, "l,", lcomma); + ANSI(0x0d3, 0, ",", comma); + ANSI(0x0d4, 0, "um*", um_multiply); + ANSI(0x0d5, 0, "um/mod", um_slash_mod); + + ANSI(0x0d8, 0, "d+", d_plus); + ANSI(0x0d9, 0, "d-", d_minus); + + ANSI(0x0dc, 0, "state", state); + ANSI(0x0de, 0, "behavior", behavior); + ANSI(0x0dd, 0, "compile,", compile_comma); + + ANSI(0x216, 0, "abort", f_abort); + ANSI(0x217, 0, "catch", catch); + ANSI(0x218, 0, "throw", throw); + + ANSI(0x226, 0, "lwflip", lwflip); + ANSI(0x227, 0, "lbflip", lbflip); + ANSI(0x228, 0, "lbflips", lbflips); + + ANSI(0x236, 0, "wbflips", wbflips); + ANSI(0x237, 0, "lwflips", lwflips); + + FORTH(0, "forth", do_forth); + FORTH(0, "current", do_current); + FORTH(0, "context", do_context); + FORTH(0, "definitions", do_definitions); + FORTH(0, "vocabulary", do_vocab); + FORTH(IMMEDIATE, ":", colon); + FORTH(IMMEDIATE, ";", semi); + FORTH(IMMEDIATE, "create", create); + FORTH(IMMEDIATE, "does>", does); + FORTH(IMMEDIATE, "recursive", recursive); + FORTH(0, "parse-word", parse_word); + FORTH(IMMEDIATE, "\"", run_quote); + FORTH(IMMEDIATE, "order", do_order); + FORTH(IMMEDIATE, "also", do_also); + FORTH(IMMEDIATE, "previous", do_previous); + FORTH(IMMEDIATE, "'", do_tick); + FORTH(IMMEDIATE, "[']", bracket_tick); + FORTH(0, "unaligned-l@", unaligned_lfetch); + FORTH(0, "unaligned-l!", unaligned_lstore); + FORTH(0, "unaligned-w@", unaligned_wfetch); + FORTH(0, "unaligned-w!", unaligned_wstore); +} diff --git a/usr/src/lib/efcode/engine/framebuffer.c b/usr/src/lib/efcode/engine/framebuffer.c new file mode 100644 index 0000000000..aaf3a44f53 --- /dev/null +++ b/usr/src/lib/efcode/engine/framebuffer.c @@ -0,0 +1,71 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <fcode/private.h> + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + ASSERT(env); + NOTICE; + + FCODE(0x11c, 0, "is-install", fc_unimplemented); + FCODE(0x11d, 0, "is-remove", fc_unimplemented); + FCODE(0x11e, 0, "is-selftest", fc_unimplemented); + + FCODE(0x121, 0, "display-status", fc_unimplemented); + + FCODE(0x150, 0, "#lines", fc_unimplemented); + FCODE(0x151, 0, "#columns", fc_unimplemented); + FCODE(0x152, 0, "line#", fc_unimplemented); + FCODE(0x153, 0, "column#", fc_unimplemented); + FCODE(0x154, 0, "inverse?", fc_unimplemented); + FCODE(0x155, 0, "inverse-screen?", fc_unimplemented); + FCODE(0x156, 0, "frame-buffer-busy?", fc_historical); + FCODE(0x157, 0, "draw-character", fc_unimplemented); + FCODE(0x158, 0, "reset-screen", fc_unimplemented); + FCODE(0x159, 0, "toggle-cursor", fc_unimplemented); + FCODE(0x15a, 0, "erase-screen", fc_unimplemented); + FCODE(0x15b, 0, "blink-screen", fc_unimplemented); + FCODE(0x15c, 0, "invert-screen", fc_unimplemented); + FCODE(0x15d, 0, "insert-characters", fc_unimplemented); + FCODE(0x15e, 0, "delete-characters", fc_unimplemented); + FCODE(0x15f, 0, "insert-lines", fc_unimplemented); + FCODE(0x160, 0, "delete-lines", fc_unimplemented); + FCODE(0x161, 0, "draw-logo", fc_unimplemented); + FCODE(0x162, 0, "frame-buffer-adr", fc_unimplemented); + FCODE(0x163, 0, "screen-height", fc_unimplemented); + FCODE(0x164, 0, "screen-width", fc_unimplemented); + FCODE(0x165, 0, "window-top", fc_unimplemented); + FCODE(0x166, 0, "window-left", fc_unimplemented); +} diff --git a/usr/src/lib/efcode/engine/init.c b/usr/src/lib/efcode/engine/init.c new file mode 100644 index 0000000000..128476cf4e --- /dev/null +++ b/usr/src/lib/efcode/engine/init.c @@ -0,0 +1,139 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +fcode_env_t *initial_env = 0; +int dict_size = 0x100000; /* 1Mb, hopefully big enough... */ +int stack_size = 0x200; + +void * +safe_malloc(size_t n, char *f, int l) +{ + void *p; + + p = malloc((size_t) n); +#if defined(__sparcv9) + /* + * For Ultrasparc, we must force addresses to be less than 4Gb, + * since Fcode assumes that addresses can be stored in 32 bits. + * To get around this would require turning all addresses into + * cookies, which is a lot of work. + */ + if (((uint64_t)p) >= 0x100000000) { + log_message(MSG_WARN, "Malloc returned address > 4Gb\n"); + } +#endif /* __sparcv9 */ + if (p) { + memset(p, 0, (size_t) n); + } else + log_message(MSG_ERROR, "%s:%d:Malloc(%llx) failed\n", f, l, + (uint64_t)n); + return (p); +} + +void * +safe_realloc(void *p, size_t n, char *f, int l) +{ + void *newp; + + if ((newp = safe_malloc(n, f, l)) == NULL) { + log_message(MSG_ERROR, "%s:%d:realloc(%p, %x) failed\n", f, l, + p, n); + safe_free(p, f, l); + return (NULL); + } + if (p) { + memcpy(newp, p, n); + safe_free(p, f, l); + } + return (newp); +} + +void +safe_free(void *p, char *f, int l) +{ + if (p) { + free(p); + } +} + +char * +safe_strdup(char *s, char *f, int l) +{ + char *p = strdup(s); + + return (p); +} + +#pragma init(_init) + +static void +_init(void) +{ + int i; + acf_t f_error_addr; + fcode_env_t *env; + + NOTICE; + + fcode_impl_count = 0; + env = MALLOC(sizeof (fcode_env_t)); + env->table = MALLOC((MAX_FCODE + 1) * sizeof (fcode_token)); + env->base = MALLOC(dict_size); + env->here = env->base; + env->ds = env->ds0 = MALLOC(stack_size * sizeof (fstack_t)); + env->rs = env->rs0 = MALLOC(stack_size * sizeof (fstack_t)); + env->order = MALLOC(MAX_ORDER * sizeof (token_t)); + env->input = MALLOC(sizeof (input_typ)); + env->num_base = 0x10; + + /* Setup the initial forth environment */ + do_forth(env); + do_definitions(env); + install_handlers(env); + + initial_env = env; + + /* + * Need to define this early because it is the default for + * all unimpl, FCODE functions + */ + P1275(0x0fc, IMMEDIATE, "ferror", f_error); + f_error_addr = LINK_TO_ACF(env->lastlink); + for (i = 0; i <= MAX_FCODE; i++) { + DEBUGF(ANY, env->table[i].usage = 0); + SET_TOKEN(i, IMMEDIATE, "ferror", f_error_addr); + } + fcode_impl_count = 0; +} diff --git a/usr/src/lib/efcode/engine/instance.c b/usr/src/lib/efcode/engine/instance.c new file mode 100644 index 0000000000..380d1d6297 --- /dev/null +++ b/usr/src/lib/efcode/engine/instance.c @@ -0,0 +1,117 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> + +#include <fcode/private.h> + +/* + * Return a pointer to the allocated instance data. + * If the data was initialised then return a pointer to the initialisation + * buffer otherwise return a pointer to the un-init data. + */ +token_t * +alloc_instance_data(fcode_env_t *env, int init, int n, int *offset) +{ + int ptr; + + *offset = ptr = MYSELF->device->data_size[init]; + MYSELF->device->data_size[init] += n; + if (init == INIT_DATA) + return (&MYSELF->device->init_data[ptr]); + else + return (&MYSELF->data[init][ptr]); +} + +token_t * +get_instance_address(fcode_env_t *env) +{ + int which; + token_t *ptr; + token_t offset; + + CHECK_DEPTH(env, 1, "get_instance_address"); + ptr = (token_t *) POP(DS); + offset = *ptr; + if (offset < 0) { + offset = -offset; + which = UINIT_DATA; + } else { + which = INIT_DATA; + } + return (&MYSELF->data[which][offset]); +} + +void +fetch_instance_data(fcode_env_t *env) +{ + token_t *ptr; + + CHECK_DEPTH(env, 1, "get_instance_data"); + ptr = get_instance_address(env); + PUSH(DS, *ptr); +} + +void +set_instance_data(fcode_env_t *env) +{ + token_t *ptr; + + CHECK_DEPTH(env, 2, "set_instance_data"); + ptr = get_instance_address(env); + *ptr = POP(DS); +} + +void +address_instance_data(fcode_env_t *env) +{ + token_t *ptr; + + CHECK_DEPTH(env, 1, "address_instance_data"); + ptr = get_instance_address(env); + PUSH(DS, (fstack_t) ptr); +} + +void +instance_variable(fcode_env_t *env) +{ + token_t *ptr; + + PUSH(DS, (fstack_t) WA); + ptr = get_instance_address(env); + PUSH(DS, (fstack_t) ptr); +} + +void +idefer_exec(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "idefer_exec"); + fetch_instance_data(env); + execute(env); +} diff --git a/usr/src/lib/efcode/engine/interactive.c b/usr/src/lib/efcode/engine/interactive.c new file mode 100644 index 0000000000..398f52a686 --- /dev/null +++ b/usr/src/lib/efcode/engine/interactive.c @@ -0,0 +1,808 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2000 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <setjmp.h> +#include <sys/stat.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +void (*to_ptr)(fcode_env_t *env) = do_set_action; +jmp_buf *jmp_buf_ptr = NULL; + +char * +parse_a_string(fcode_env_t *env, int *lenp) +{ + parse_word(env); + return (pop_a_string(env, lenp)); +} + +void +constant(fcode_env_t *env) +{ + char *name; + int len; + + name = parse_a_string(env, &len); + env->instance_mode = 0; + make_common_access(env, name, len, 1, 0, + &do_constant, &do_constant, NULL); +} + +void +buffer_colon(fcode_env_t *env) +{ + char *name; + int len; + + PUSH(DS, 0); + name = parse_a_string(env, &len); + make_common_access(env, name, len, 2, + env->instance_mode, &noop, &noop, &set_buffer_actions); +} + +void +value(fcode_env_t *env) +{ + char *name; + int len; + + name = parse_a_string(env, &len); + make_common_access(env, name, len, 1, + env->instance_mode, &noop, &noop, &set_value_actions); +} + +void +variable(fcode_env_t *env) +{ + char *name; + int len; + + PUSH(DS, 0); + name = parse_a_string(env, &len); + make_common_access(env, name, len, 1, + env->instance_mode, &instance_variable, &do_create, NULL); +} + +void +defer(fcode_env_t *env) +{ + static void (*crash_ptr)(fcode_env_t *env) = do_crash; + char *name; + int len; + + PUSH(DS, (fstack_t)&crash_ptr); + name = parse_a_string(env, &len); + make_common_access(env, name, len, 1, + env->instance_mode, &noop, &noop, &set_defer_actions); +} + +void +field(fcode_env_t *env) +{ + char *name; + int len; + + over(env); + name = parse_a_string(env, &len); + make_common_access(env, name, len, 1, 0, &do_field, &do_field, NULL); + add(env); +} + +void +bye(fcode_env_t *env) +{ + exit(0); +} + +void +do_resume(fcode_env_t *env) +{ + if (env->interactive) env->interactive--; + COMPLETE_INTERRUPT; +} + +/* + * In interactive mode, jmp_buf_ptr should be non-null. + */ +void +return_to_interact(fcode_env_t *env) +{ + if (jmp_buf_ptr) + longjmp(*jmp_buf_ptr, 1); +} + +void +do_interact(fcode_env_t *env) +{ + int level; + jmp_buf jmp_env; + jmp_buf *ojmp_ptr; + error_frame new; + input_typ *old_input = env->input; + + log_message(MSG_INFO, "Type resume to return\n"); + env->interactive++; + level = env->interactive; + + ojmp_ptr = jmp_buf_ptr; + jmp_buf_ptr = &jmp_env; + env->input->separator = ' '; + env->input->maxlen = 256; + env->input->buffer = MALLOC(env->input->maxlen); + env->input->scanptr = env->input->buffer; + + if (setjmp(jmp_env)) { + if (in_forth_abort > 1) { + RS = env->rs0; + DS = env->ds0; + MYSELF = 0; + IP = 0; + env->input = old_input; + env->order_depth = 0; + } else { + RS = new.rs; + DS = new.ds; + MYSELF = new.myself; + IP = new.ip; + env->input = old_input; + } + do_forth(env); + do_definitions(env); + in_forth_abort = 0; + } else { + new.rs = RS; + new.ds = DS; + new.myself = MYSELF; + new.ip = IP; + } + + while (env->interactive == level) { + int wlen; + char *p; + + DEBUGF(SHOW_RS, output_return_stack(env, 0, MSG_FC_DEBUG)); + DEBUGF(SHOW_STACK, output_data_stack(env, MSG_FC_DEBUG)); + +#define USE_READLINE +#ifdef USE_READLINE + { + char *line; + void read_line(fcode_env_t *); + + read_line(env); + if ((line = pop_a_string(env, NULL)) == NULL) + continue; + + env->input->scanptr = strcpy(env->input->buffer, line); + } +#else + if (isatty(fileno(stdin))) + printf("ok "); + + env->input->scanptr = fgets(env->input->buffer, + env->input->maxlen, stdin); + + if (feof(stdin)) + break; + + if (env->input->scanptr == NULL) + continue; +#endif + + if ((p = strpbrk(env->input->scanptr, "\n\r")) != NULL) + *p = '\0'; + + if ((wlen = strlen(env->input->scanptr)) == 0) + continue; + + PUSH(DS, (fstack_t)env->input->buffer); + PUSH(DS, wlen); + evaluate(env); + } + + jmp_buf_ptr = ojmp_ptr; + FREE(env->input->buffer); +} + +static void +temp_base(fcode_env_t *env, fstack_t base) +{ + fstack_t obase; + + obase = env->num_base; + env->num_base = base; + parse_word(env); + evaluate(env); + env->num_base = obase; +} + +static void +temp_decimal(fcode_env_t *env) +{ + temp_base(env, 10); +} + +static void +temp_hex(fcode_env_t *env) +{ + temp_base(env, 0x10); +} + +static void +temp_binary(fcode_env_t *env) +{ + temp_base(env, 2); +} + +static void +do_hex(fcode_env_t *env) +{ + env->num_base = 0x10; +} + +static void +do_decimal(fcode_env_t *env) +{ + env->num_base = 10; +} + +static void +do_binary(fcode_env_t *env) +{ + env->num_base = 2; +} + +static void +do_clear(fcode_env_t *env) +{ + DS = env->ds0; +} + +static void +action_one(fcode_env_t *env) +{ + + do_tick(env); + if (env->state) { + COMPILE_TOKEN(&to_ptr); + } else { + PUSH(DS, 1); + perform_action(env); + } +} + +void +do_if(fcode_env_t *env) +{ + branch_common(env, 1, 1, 0); +} + +void +do_else(fcode_env_t *env) +{ + branch_common(env, 1, 0, 1); + bresolve(env); +} + +void +do_then(fcode_env_t *env) +{ + bresolve(env); +} + +void +do_of(fcode_env_t *env) +{ + branch_common(env, 0, 2, 0); +} + +void +load_file(fcode_env_t *env) +{ + int fd; + int len, n; + char *name; + char *buffer; + struct stat buf; + + CHECK_DEPTH(env, 2, "load-file"); + name = pop_a_string(env, &len); + log_message(MSG_INFO, "load_file: '%s'\n", name); + fd = open(name, O_RDONLY); + if (fd < 0) { + forth_perror(env, "Can't open '%s'", name); + } + fstat(fd, &buf); + len = buf.st_size; + buffer = MALLOC(len); + if (buffer == 0) + forth_perror(env, "load_file: MALLOC(%d)", len); + + if ((n = read(fd, buffer, len)) < 0) + forth_perror(env, "read error '%s'", name); + + close(fd); + PUSH(DS, (fstack_t)buffer); + PUSH(DS, (fstack_t)n); +} + +void +load(fcode_env_t *env) +{ + parse_word(env); + if (TOS > 0) + load_file(env); +} + +void +fevaluate(fcode_env_t *env) +{ + char *buffer; + int bytes, len; + + two_dup(env); + buffer = pop_a_string(env, &len); + for (bytes = 0; bytes < len; bytes++) { + if ((buffer[bytes] == '\n') || (buffer[bytes] == '\r')) + buffer[bytes] = ' '; + } + evaluate(env); +} + +void +fload(fcode_env_t *env) +{ + char *buffer; + + load(env); + two_dup(env); + buffer = pop_a_string(env, NULL); + fevaluate(env); + FREE(buffer); +} + +#include <sys/termio.h> + +#define MAX_LINE_BUF 20 + +static char *history_lines[MAX_LINE_BUF]; +int num_lines = 0; + +static void +add_line_to_history(fcode_env_t *env, char *line) +{ + int i; + + if (num_lines < MAX_LINE_BUF) + history_lines[num_lines++] = STRDUP(line); + else { + FREE(history_lines[0]); + for (i = 0; i < MAX_LINE_BUF - 1; i++) + history_lines[i] = history_lines[i + 1]; + history_lines[MAX_LINE_BUF - 1] = STRDUP(line); + } +} + +static void +do_emit_chars(fcode_env_t *env, char c, int n) +{ + int i; + + for (i = 0; i < n; i++) + do_emit(env, c); +} + +static void +do_emit_str(fcode_env_t *env, char *str, int n) +{ + int i; + + for (i = 0; i < n; i++) + do_emit(env, *str++); +} + +static char * +find_next_word(char *cursor, char *eol) +{ + while (cursor < eol && *cursor != ' ') + cursor++; + while (cursor < eol && *cursor == ' ') + cursor++; + return (cursor); +} + +static char * +find_prev_word(char *buf, char *cursor) +{ + int skippedword = 0; + + if (cursor == buf) + return (cursor); + cursor--; + while (cursor > buf && *cursor == ' ') + cursor--; + while (cursor > buf && *cursor != ' ') { + skippedword++; + cursor--; + } + if (skippedword && *cursor == ' ') + cursor++; + return (cursor); +} + +void +redraw_line(fcode_env_t *env, char *prev_l, char *prev_cursor, char *prev_eol, + char *new_l, char *new_cursor, char *new_eol) +{ + int len; + + /* backup to beginning of previous line */ + do_emit_chars(env, '\b', prev_cursor - prev_l); + + /* overwrite new line */ + do_emit_str(env, new_l, new_eol - new_l); + + /* Output blanks to erase previous line chars if old line was longer */ + len = max(0, (prev_eol - prev_l) - (new_eol - new_l)); + do_emit_chars(env, ' ', len); + + /* Backup cursor for new line */ + do_emit_chars(env, '\b', len + (new_eol - new_cursor)); +} + +#define MAX_LINE_SIZE 256 + +static void +do_save_buf(char *save_buf, char *buf, int n) +{ + n = max(0, min(n, MAX_LINE_SIZE)); + memcpy(save_buf, buf, n); + save_buf[n] = '\0'; +} + +char prompt_string[80] = "ok "; + +void +read_line(fcode_env_t *env) +{ + char buf[MAX_LINE_SIZE+1], save_buf[MAX_LINE_SIZE+1]; + char save_line[MAX_LINE_SIZE+1]; + char *p, *cursor, *eol, *tp, *cp; + fstack_t d; + int saw_esc = 0, do_quote = 0, i, cur_line, len, my_line, save_cursor; + struct termio termio, savetermio; + + if (!isatty(fileno(stdin))) { + fgets(buf, sizeof (buf), stdin); + push_string(env, buf, strlen(buf)); + return; + } + printf(prompt_string); + fflush(stdout); + ioctl(fileno(stdin), TCGETA, &termio); + savetermio = termio; + termio.c_lflag &= ~(ICANON|ECHO|ECHOE|IEXTEN); + termio.c_cc[VTIME] = 0; + termio.c_cc[VMIN] = 1; + ioctl(fileno(stdin), TCSETA, &termio); + my_line = cur_line = num_lines; + save_buf[0] = '\0'; + for (cursor = eol = buf; ; ) { + for (d = FALSE; d == FALSE; d = POP(DS)) + keyquestion(env); + key(env); + d = POP(DS); + if (do_quote) { + do_quote = 0; + if ((cursor - buf) < MAX_LINE_SIZE) { + *cursor++ = d; + if (cursor > eol) + eol = cursor; + do_emit(env, d); + } + continue; + } + if (saw_esc) { + saw_esc = 0; + switch (d) { + + default: /* Ignore anything else */ + continue; + + case 'b': /* Move backward one word */ + case 'B': + tp = find_prev_word(buf, cursor); + if (tp < cursor) { + do_emit_chars(env, '\b', cursor - tp); + cursor = tp; + } + continue; + + case 'f': /* Move forward one word */ + case 'F': + tp = find_next_word(cursor, eol); + if (tp > cursor) { + do_emit_str(env, tp, tp - cursor); + cursor = tp; + } + continue; + + case 'h': /* Erase from beginning of word to */ + case 'H': /* just before cursor, saving chars */ + d = CTRL('w'); + break; + + case 'd': + case 'D': + tp = find_next_word(cursor, eol); + if (tp <= cursor) + continue; + len = tp - cursor; + do_save_buf(save_buf, cursor, len); + memmove(cursor, tp, eol - tp); + redraw_line(env, buf, cursor, eol, buf, cursor, + eol - len); + eol -= len; + continue; + } + } + switch (d) { + + default: + if ((cursor - buf) < MAX_LINE_SIZE) { + *cursor++ = d; + if (cursor > eol) + eol = cursor; + do_emit(env, d); + } + continue; + + case CTRL('['): /* saw esc. character */ + saw_esc = 1; + continue; + + case CTRL('f'): /* move forward one char */ + if (cursor < eol) + do_emit(env, *cursor++); + continue; + + case CTRL('a'): /* cursor to beginning of line */ + do_emit_chars(env, '\b', cursor - buf); + cursor = buf; + continue; + + case CTRL('e'): /* cursor to end of line */ + do_emit_str(env, cursor, eol - cursor); + cursor = eol; + continue; + + + case CTRL('n'): /* Move to next line in buffer */ + case CTRL('p'): /* Move to previous line in buffer */ + if (d == CTRL('p')) { + if (cur_line <= 0) + continue; + if (my_line == cur_line) { + do_save_buf(save_line, buf, eol - buf); + save_cursor = cursor - buf; + } + cur_line--; + } else { + if (cur_line >= num_lines) + continue; + cur_line++; + if (cur_line == num_lines) { + len = strlen(save_line); + redraw_line(env, buf, cursor, eol, + save_line, save_line + save_cursor, + save_line + len); + strcpy(buf, save_line); + eol = buf + len; + cursor = buf + save_cursor; + continue; + } + } + p = history_lines[cur_line]; + len = strlen(p); + redraw_line(env, buf, cursor, eol, p, p, p + len); + strcpy(buf, history_lines[cur_line]); + cursor = buf; + eol = buf + len; + continue; + + case CTRL('o'): /* Insert newline */ + continue; + + case CTRL('k'): /* Erase from cursor to eol, saving */ + /* chars, at eol, joins two lines */ + if (cursor == eol) { + if (cur_line >= num_lines) + continue; + if (cur_line == num_lines - 1) { + p = save_line; + len = strlen(save_line); + num_lines -= 1; + my_line = num_lines; + } else { + cur_line++; + p = history_lines[cur_line]; + len = strlen(p); + } + len = min(len, MAX_LINE_SIZE - (eol - buf)); + memcpy(eol, p, len); + redraw_line(env, buf, cursor, eol, buf, cursor, + eol + len); + eol += len; + continue; + } + do_save_buf(save_buf, cursor, eol - cursor); + redraw_line(env, buf, cursor, eol, buf, cursor, + cursor); + eol = cursor; + continue; + + case CTRL('w'): /* Erase word */ + tp = find_prev_word(buf, cursor); + if (tp == cursor) + continue; + len = cursor - tp; + do_save_buf(save_buf, tp, len); + memmove(tp, cursor, eol - cursor); + redraw_line(env, buf, cursor, eol, buf, cursor - len, + eol - len); + eol -= len; + cursor -= len; + continue; + + case CTRL('u'): /* Erases line, saving chars */ + do_save_buf(save_buf, buf, eol - buf); + redraw_line(env, buf, cursor, eol, buf, buf, buf); + cursor = buf; + eol = buf; + continue; + + case CTRL('y'): /* Insert save buffer before cursor */ + len = min(strlen(save_buf), + MAX_LINE_SIZE - (eol - buf)); + if (len == 0) + continue; + memmove(cursor + len, cursor, eol - cursor); + memcpy(cursor, save_buf, len); + redraw_line(env, buf, cursor, eol, buf, cursor + len, + eol + len); + cursor += len; + eol += len; + continue; + + case CTRL('q'): /* Quote next char */ + do_quote = 1; + continue; + + case CTRL('l'): /* Display edit buffer */ + do_emit(env, '\n'); + for (i = 0; i < num_lines; i++) { + do_emit_str(env, history_lines[i], + strlen(history_lines[i])); + do_emit(env, '\n'); + } + redraw_line(env, buf, buf, buf, buf, cursor, eol); + continue; + + case CTRL('r'): /* redraw line */ + redraw_line(env, buf, cursor, eol, buf, cursor, eol); + continue; + + case CTRL('c'): /* Exit script editor */ + continue; + + case CTRL('b'): /* backup cursor */ + if (cursor <= buf) + continue; + cursor--; + do_emit(env, '\b'); + continue; + + case CTRL('h'): /* Backspace */ + case 0x7f: /* DEL */ + if (cursor <= buf) + continue; + memmove(cursor - 1, cursor, eol - cursor); + redraw_line(env, buf, cursor, eol, buf, cursor - 1, + eol - 1); + cursor--; + eol--; + continue; + + case '\r': + case '\n': + *eol = '\0'; + do_emit(env, '\n'); + break; + } + break; + } + add_line_to_history(env, buf); + ioctl(fileno(stdin), TCSETA, &savetermio); + push_string(env, buf, strlen(buf)); +} + +static void +set_prompt(fcode_env_t *env) +{ + char *prompt; + + if ((prompt = parse_a_string(env, NULL)) != NULL) + strncpy(prompt_string, prompt, sizeof (prompt_string)); +} + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + ASSERT(env); + NOTICE; + + FORTH(IMMEDIATE, "if", do_if); + FORTH(IMMEDIATE, "else", do_else); + FORTH(IMMEDIATE, "then", do_then); + FORTH(IMMEDIATE, "case", bcase); + FORTH(IMMEDIATE, "of", do_of); + FORTH(IMMEDIATE, "endof", do_else); + FORTH(IMMEDIATE, "endcase", bendcase); + FORTH(IMMEDIATE, "value", value); + FORTH(IMMEDIATE, "variable", variable); + FORTH(IMMEDIATE, "constant", constant); + FORTH(IMMEDIATE, "defer", defer); + FORTH(IMMEDIATE, "buffer:", buffer_colon); + FORTH(IMMEDIATE, "field", field); + FORTH(IMMEDIATE, "struct", zero); + FORTH(IMMEDIATE, "to", action_one); + FORTH(IMMEDIATE, "d#", temp_decimal); + FORTH(IMMEDIATE, "h#", temp_hex); + FORTH(IMMEDIATE, "b#", temp_binary); + FORTH(0, "decimal", do_decimal); + FORTH(0, "hex", do_hex); + FORTH(0, "binary", do_binary); + FORTH(0, "clear", do_clear); + FORTH(IMMEDIATE, "bye", bye); + FORTH(0, "interact", do_interact); + FORTH(IMMEDIATE, "resume", do_resume); + FORTH(0, "fload", fload); + FORTH(0, "load", load); + FORTH(0, "read-line", read_line); + FORTH(0, "set-prompt", set_prompt); +} diff --git a/usr/src/lib/efcode/engine/interface.c b/usr/src/lib/efcode/engine/interface.c new file mode 100644 index 0000000000..31f0cc9e91 --- /dev/null +++ b/usr/src/lib/efcode/engine/interface.c @@ -0,0 +1,273 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2000 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +/* + * the external start point for this goo + */ + +void +push_ds(fcode_env_t *env, fstack_t d) +{ + PUSH(DS, d); +} + +fstack_t +pop_ds(fcode_env_t *env) +{ + return (POP(DS)); +} + +void +push_rs(fcode_env_t *env, fstack_t d) +{ + PUSH(RS, d); +} + +fstack_t +pop_rs(fcode_env_t *env) +{ + return (POP(RS)); +} + +/* + * Pushes a C string on the stack. + */ +void +push_a_string(fcode_env_t *env, char *str) +{ + if (str) { + PUSH(DS, (fstack_t)str); + PUSH(DS, strlen(str)); + } else { + PUSH(DS, 0); + PUSH(DS, 0); + } +} + +/* + * Pops a (potentially null) string off the stack. + */ +char * +pop_a_string(fcode_env_t *env, int *lenp) +{ + int len; + char *str; + + len = POP(DS); + str = (char *)POP(DS); + if (len == 0) + str = NULL; + else if (str == NULL) + len = 0; + if (lenp) + *lenp = len; + return (str); +} + +/* + * Pops & strdup's a string off the stack, handles NULL strings. + */ +char * +pop_a_duped_string(fcode_env_t *env, int *lenp) +{ + char *str; + + str = pop_a_string(env, lenp); + if (str) + return (STRDUP(str)); + return (NULL); +} + +/* + * Push Forth Double type. + */ +void +push_double(fcode_env_t *env, dforth_t d) +{ + fstack_t lo, hi; + + lo = DFORTH_LO(d); + hi = DFORTH_HI(d); + PUSH(DS, lo); + PUSH(DS, hi); +} + +/* + * Pop Forth Double type. + */ +dforth_t +pop_double(fcode_env_t *env) +{ + fstack_t lo, hi; + + hi = POP(DS); + lo = POP(DS); + return (MAKE_DFORTH(hi, lo)); +} + +/* + * Peek at top of stack Forth Double type. + */ +dforth_t +peek_double(fcode_env_t *env) +{ + dforth_t a; + + a = pop_double(env); + push_double(env, a); + return (a); +} + +void +run_fcode(fcode_env_t *env, uchar_t *buff, int len) +{ + int i; + + /* + * Really just checking to see if buff is all ascii characters. + * Fcode normally starts with 0xfd, so for fcode, this should be + * a fast check. + */ + for (i = 0; i < len; i++) + if (buff[i] >= 0x80) + break; + PUSH(DS, (fstack_t)buff); + if (i < len) { + /* Non-ascii found, probably Fcode */ + PUSH(DS, (fstack_t)1); + byte_load(env); + } else { + /* All ascii found, probably ascii */ + PUSH(DS, len); + fevaluate(env); + } +} + +void +run_fcode_from_file(fcode_env_t *env, char *fname, int aout_flag) +{ + uchar_t *p; + int len; + + push_a_string(env, fname); + load_file(env); + len = POP(DS); + p = (uchar_t *)POP(DS); + if (aout_flag) { + p += 0x20; + len -= 0x20; + } + run_fcode(env, p, len); +} + +fcode_env_t * +clone_environment(fcode_env_t *src, void *private) +{ + fcode_env_t *env; + + if (!src) { + src = initial_env; + src->private = private; + return (src); + } + +#if 0 + src->private = private; + if (src->my_self || src->state) { + log_message(MSG_WARN, "Can't clone an active instance or" + " compile state!\n"); + return (NULL); + } + + log_message(MSG_WARN, "Warning: Device-tree state is shared!\n"); +#endif + + env = MALLOC(sizeof (fcode_env_t)); + memcpy(env, src, sizeof (fcode_env_t)); + +#if 0 + env->table = MALLOC((MAX_FCODE + 1) * sizeof (fcode_token)); + memcpy(env->table, src->table, (MAX_FCODE + 1) * sizeof (fcode_token)); + + /* + * Note that cloning the dictionary doesn't make sense unless the + * ptrs + XT's in the dictionary are relative to BASE. + */ + env->base = MALLOC(dict_size); + memcpy(env->base, src->base, dict_size); + + env->here = src->base - (uchar_t *)src + env->base; +#endif + + env->ds0 = MALLOC(stack_size * sizeof (fstack_t)); + memcpy(env->ds0, src->ds0, stack_size * sizeof (fstack_t)); + env->ds = src->ds - src->ds0 + env->ds0; + + env->rs0 = MALLOC(stack_size * sizeof (fstack_t)); + memcpy(env->rs0, src->rs0, stack_size * sizeof (fstack_t)); + env->rs = src->rs - src->rs0 + env->rs0; + + env->order = MALLOC(MAX_ORDER * sizeof (token_t)); + memcpy(env->order, src->order, MAX_ORDER * sizeof (token_t)); + + env->input = MALLOC(sizeof (input_typ)); + + env->catch_frame = 0; + + IP = 0; + + return (env); +} + +void +destroy_environment(fcode_env_t *env) +{ + FREE(env->input); + FREE(env->order); + FREE(env->ds0); + FREE(env->rs0); +#if 0 + FREE(env->base); + FREE(env->table); +#endif + FREE(env); + + if (env == initial_env) { + /* This call only happens internally */ + + initial_env = NULL; + /* You had better not exercise the engine anymore! */ + } +} diff --git a/usr/src/lib/efcode/engine/interp.c b/usr/src/lib/efcode/engine/interp.c new file mode 100644 index 0000000000..e0e41dba01 --- /dev/null +++ b/usr/src/lib/efcode/engine/interp.c @@ -0,0 +1,121 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +void +do_run(fcode_env_t *env, int next) +{ + token_t target, indirect; + void (*fn)(fcode_env_t *env); + int debug_state = current_debug_state(env); + extern void do_memory_watch(fcode_env_t *env); + + for (; ; ) { + if (next) { + DEBUGF(NEXT_VITALS, output_vitals(env); + log_message(MSG_FC_DEBUG, "\n")); + CHECK_INTERRUPT; + if (IP == NULL) + break; + WA = (token_t *) *IP; + IP++; + } + check_for_debug_entry(env); + indirect = *WA; + if (indirect & 1) { + target = indirect & ~1; + target = *((token_t *)target); + } else + target = indirect; + fn = (void (*)(fcode_env_t *)) target; + if (do_exec_debug(env, (void *)fn)) + break; + if (indirect & 1) { + PUSH(DS, (fstack_t) (WA+1)); + WA = (token_t *) target; + } + WA++; + fn(env); + check_vitals(env); + check_for_debug_exit(env); + do_memory_watch(env); + next = 1; + } + clear_debug_state(env, debug_state); +} + +void +do_semi(fcode_env_t *env) +{ + CHECK_RETURN_DEPTH(env, 1, ";"); + check_semi_debug_exit(env); + IP = (token_t *) POP(RS); +} + +void +do_colon(fcode_env_t *env) +{ + PUSH(RS, (fstack_t) IP); + IP = WA; +} + +void +do_alias(fcode_env_t *env) +{ + token_t *ip; + + ip = IP; + IP = 0; + WA = (token_t *) *WA; + do_run(env, 0); + IP = ip; +} + +void +execute(fcode_env_t *env) +{ + token_t *ip, *wa; + + /* + * In order to ensure that only this token executes we + * force IP to zero after stashing it, then when the stack + * unwinds (do_run returns) we can restore the old value. + */ + CHECK_DEPTH(env, 1, "execute"); + ip = IP; + wa = WA; + IP = 0; + WA = (token_t *) POP(DS); + do_run(env, 0); + IP = ip; + WA = wa; +} diff --git a/usr/src/lib/efcode/engine/log.c b/usr/src/lib/efcode/engine/log.c new file mode 100644 index 0000000000..b17f38b8c4 --- /dev/null +++ b/usr/src/lib/efcode/engine/log.c @@ -0,0 +1,361 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Daemon log message. This can direct log messages to either stdout, + * an error log file or syslog (or any combination). + */ + +#include <stdarg.h> +#include <stdio.h> +#include <syslog.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +#define LOG_LINESIZE 256 +#define LOG_EMIT_BUFSIZE LOG_LINESIZE + +static FILE *error_log_fp = NULL; +static int syslog_opened = 0; +static int error_log_flags; +static int syslog_log_flags; +static int do_emit_flag = -1; +static int daemon_log_flag; +static int min_syslog_level = LOG_ERR; + +static int log_to_stdout(int); +static int log_to_error_log(int); +static int log_to_syslog(int); +static int msg_level_to_syslog(int); + +/* + * Complicated by not wanting to do any emit processing if no one's actually + * going to see it. + */ +void +log_emit(char c) +{ + static char emit_buf[LOG_EMIT_BUFSIZE]; + static char *emit_p = emit_buf; + static int lastnl = 1; + + /* + * No one has set the do_emit_flag, go ahead and figure it out. + */ + if (do_emit_flag < 0) { + do_emit_flag = (log_to_stdout(MSG_EMIT) | + log_to_error_log(MSG_EMIT) | log_to_syslog(MSG_EMIT)); + } + + if (!do_emit_flag) + return; + + /* + * Check for buffer overflow. + */ + if (emit_p >= &emit_buf[LOG_EMIT_BUFSIZE - 1]) { + *emit_p = '\0'; + log_message(MSG_EMIT, "emit: %s\n", emit_buf); + emit_p = emit_buf; + lastnl = 1; + } + + /* + * Fcode emit's may output both CR/LF, we go ahead and eat multiple + * ones in succession. + */ + if (c == '\n' || c == '\r') { + if (!lastnl) { + *emit_p = '\0'; + log_message(MSG_EMIT, "emit: %s\n", emit_buf); + emit_p = emit_buf; + } + lastnl = 1; + } else { + lastnl = 0; + *emit_p++ = c; + } +} + +/* + * If stdout is a tty and this is MSG_EMIT, we should have alredy output it. + * If running as daemon, output to stdout is a waste of time. + */ +static int +log_to_stdout(int msg_level) +{ + if (isatty(fileno(stdin)) && (msg_level & MSG_EMIT) != 0) + return (0); + return (daemon_log_flag == 0); +} + +/* + * Can't turn off FATAL or ERROR messages to error log file. + */ +static int +log_to_error_log(int msg_level) +{ + if (!error_log_fp) + return (0); + if (msg_level & (MSG_FATAL|MSG_ERROR)) + return (1); + return (msg_level & error_log_flags); +} + +/* + * Can't turn off FATAL or ERROR messages to syslog. + */ +static int +log_to_syslog(int msg_level) +{ + if (!syslog_opened) + return (0); + if (msg_level & (MSG_FATAL|MSG_ERROR)) + return (1); + return (msg_level & syslog_log_flags); +} + +/* + * Turn internal MSG level to syslog msg level. Don't return a msg level + * lower priority than min_syslog_level. + */ +static int +msg_level_to_syslog(int msg_level) +{ + if (min_syslog_level <= LOG_ERR) + return (min_syslog_level); + if (msg_level & (MSG_FATAL|MSG_ERROR)) + return (LOG_ERR); + if (min_syslog_level <= LOG_WARNING) + return (min_syslog_level); + if (msg_level & MSG_WARN) + return (LOG_WARNING); + if (min_syslog_level <= LOG_NOTICE) + return (min_syslog_level); + if (msg_level & MSG_NOTE) + return (LOG_NOTICE); + if (min_syslog_level <= LOG_INFO) + return (min_syslog_level); + if (msg_level & MSG_INFO) + return (LOG_INFO); + return (min(min_syslog_level, LOG_DEBUG)); +} + +/* + * Log a message to the appropriate places. + */ +void +log_message(int msg_level, char *fmt, ...) +{ + va_list ap; + char msg[LOG_LINESIZE], *p; + static char log_msg[LOG_LINESIZE]; + + va_start(ap, fmt); + + vsprintf(msg, fmt, ap); + + if (log_to_stdout(msg_level)) { + printf(msg); + fflush(stdout); + } + if (log_to_error_log(msg_level)) { + fprintf(error_log_fp, msg); + fflush(error_log_fp); + } + if (log_to_syslog(msg_level)) { + if (strlen(log_msg) + strlen(msg) > LOG_LINESIZE - 1) { + syslog(msg_level_to_syslog(msg_level), log_msg); + log_msg[0] = '\0'; + } + strcat(log_msg, msg); + if ((p = strchr(log_msg, '\n')) != NULL) { + *p = '\0'; + syslog(msg_level_to_syslog(msg_level), log_msg); + log_msg[0] = '\0'; + } + } +} + +/* + * Output debug message + */ +void +debug_msg(int debug_level, char *fmt, ...) +{ + va_list ap; + char msg[LOG_LINESIZE]; + + if ((debug_level & get_interpreter_debug_level()) == 0) + return; + + va_start(ap, fmt); + + vsprintf(msg, fmt, ap); + + log_message(MSG_DEBUG, msg); +} + +/* + * Log a perror message to the appropriate places. + */ +void +log_perror(int msg_level, char *fmt, ...) +{ + va_list ap; + char msg[LOG_LINESIZE], tmp[LOG_LINESIZE]; + + va_start(ap, fmt); + + vsprintf(msg, fmt, ap); + sprintf(tmp, "%s: %s\n", msg, strerror(errno)); + log_message(msg_level, tmp); +} + +void +set_min_syslog_level(int level) +{ + min_syslog_level = level; +} + +char *error_log_name; + +void +open_error_log(char *fname, int errflags) +{ + if ((error_log_fp = fopen(fname, "a")) == NULL) { + log_perror(MSG_FATAL, fname); + exit(1); + } + error_log_name = STRDUP(fname); + error_log_flags = errflags; + do_emit_flag = (log_to_stdout(MSG_EMIT) | log_to_error_log(MSG_EMIT) | + log_to_syslog(MSG_EMIT)); +} + +void +open_syslog_log(char *logname, int logflags) +{ + openlog(logname, LOG_PID, LOG_DAEMON); + syslog_log_flags = logflags; + do_emit_flag = (log_to_stdout(MSG_EMIT) | log_to_error_log(MSG_EMIT) | + log_to_syslog(MSG_EMIT)); + syslog_opened = 1; +} + +/* + * Turn on/off syslog LOG_DAEMON flag to syslog messages. Also controls + * outputting to stdout, which is a waste of time when we're running as a + * daemon. + */ +void +set_daemon_log_flag(int flag) +{ + if (flag) + daemon_log_flag = LOG_DAEMON; + else + daemon_log_flag = 0; +} + +int +parse_msg_flags(char *flags) +{ + int msgflags = 0; + char c; + + while ((c = *flags++) != '\0') { + switch (c) { + case 'f': msgflags |= MSG_FATAL; break; + case 'e': msgflags |= MSG_ERROR; break; + case 'w': msgflags |= MSG_WARN; break; + case 'i': msgflags |= MSG_INFO; break; + case 'd': msgflags |= MSG_DEBUG; break; + case 'D': msgflags |= MSG_FC_DEBUG; break; + + default: + log_message(MSG_ERROR, "Invalid msglvl flag: %c\n", c); + break; + } + } + return (msgflags); +} + +#define MAXERRBUF 256 +char error_buffer[MAXERRBUF]; + +static void +dot_error_buffer(fcode_env_t *env) +{ + log_message(MSG_INFO, "%s\n", error_buffer); +} + +static void +set_error_log(fcode_env_t *env) +{ + char *fname; + FILE *fp; + + parse_word(env); + fname = pop_a_string(env, NULL); + if (fname != NULL) { + if ((fp = fopen(fname, "a")) == NULL) { + log_perror(MSG_ERROR, "Can't open '%s'\n", fname); + return; + } + if (error_log_fp) + fclose(error_log_fp); + if (error_log_name) + FREE(error_log_name); + error_log_fp = fp; + error_log_name = STRDUP(fname); + error_log_flags = MSG_FATAL|MSG_ERROR|MSG_WARN|MSG_INFO| + MSG_DEBUG|MSG_FC_DEBUG; + } else if (error_log_name) + log_message(MSG_INFO, "%s\n", error_log_name); + else + log_message(MSG_INFO, "NULL\n"); +} + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + ASSERT(env); + NOTICE; + + FORTH(0, ".error-buffer", dot_error_buffer); + FORTH(0, "set-error-log", set_error_log); +} diff --git a/usr/src/lib/efcode/engine/mcookie.c b/usr/src/lib/efcode/engine/mcookie.c new file mode 100644 index 0000000000..8a12bf547a --- /dev/null +++ b/usr/src/lib/efcode/engine/mcookie.c @@ -0,0 +1,237 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2000-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +#include <fcdriver/fcdriver.h> + +#define MAX_MAPS 16 + +#define MAP_IS_VALID 0x01 + +struct map_table { + int map_flags; + uint64_t map_add; + size_t map_size; + uint64_t adj_virt; + size_t adj_length; +} map_table[MAX_MAPS]; + +/* + * Originally, this code translated kernel supplied virtual addresses into + * "memory cookies", which was a 32-bit number with ascii-M in the upper 8 + * bits, a 4-bit index and a 20-bit offset. However, this caused two + * problems: 1) the 20-bit offset was too small for some devices, esp. some + * with frame-buffers; 2) if the fcode used the cookie to program the + * hardware, there was no easy way for the software to detect that a + * translation needed to be done. + * + * For that reason, "memory cookies" are now just the kernel-supplied + * virtual address, and we now check each memory access to see if it's + * attempting to access kernel-supplied memory. The only important thing + * now is that "is_mcookie" returns 1 (or true) if the tested mcookie + * is a kernel virtual address. + * + * There is a potential bug if the kernel virtual address happens to + * conflict with a user virtual address. However, the current implementation + * of Solaris avoids this conflict. + */ + +fstack_t +mapping_to_mcookie(uint64_t req_add, size_t req_size, uint64_t adj_virt, + size_t adj_length) +{ + int i; + struct map_table *mp; + + for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++) + if ((mp->map_flags & MAP_IS_VALID) == 0) + break; + if (i == MAX_MAPS) { + log_message(MSG_WARN, "Warning: too many mappings\n"); + return (0); + } + debug_msg(DEBUG_REG_ACCESS, "Allocating mapping: %d add: 0x%llx" + " size: 0x%x\n", i, req_add, req_size); + mp->map_flags |= MAP_IS_VALID; + mp->map_add = req_add; + mp->map_size = req_size; + mp->adj_virt = adj_virt; + mp->adj_length = adj_length; + if (mp->adj_length != 0) + return (adj_virt); + else + return (req_add); +} + +void +delete_mapping(fstack_t mcookie) +{ + int i; + struct map_table *mp; + + for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++) { + if ((mp->map_flags & MAP_IS_VALID) && + mcookie >= mp->map_add && + mcookie < mp->map_add + mp->map_size) { + debug_msg(DEBUG_REG_ACCESS, "Deallocating mapping: %d" + " add: 0x%llx size: 0x%x\n", i, mp->map_add, + mp->map_size); + mp->map_flags &= ~MAP_IS_VALID; + mp->map_add = 0; + mp->map_size = 0; + mp->adj_virt = 0; + mp->adj_length = 0; + return; + } + } + log_message(MSG_WARN, "Warning: delete_mapping: invalid" + " mcookie: %llx\n", (uint64_t)mcookie); +} + +int +is_mcookie(fstack_t mcookie) +{ + struct map_table *mp; + int i; + + for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++) + if ((mp->map_flags & MAP_IS_VALID) && + mcookie >= mp->map_add && + mcookie < mp->map_add + mp->map_size) + return (1); + return (0); +} + +uint64_t +mcookie_to_addr(fstack_t mcookie) +{ + return (mcookie); +} + +fstack_t +mcookie_to_rlen(fstack_t mcookie) +{ + int i; + struct map_table *mp; + + for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++) { + if ((mp->map_flags & MAP_IS_VALID) && + mcookie >= mp->map_add && + mcookie < mp->map_add + mp->map_size) { + return (mp->map_size); + } + } + log_message(MSG_WARN, "Warning: mcookie_to_rlen: invalid" + " mcookie: %llx\n", (uint64_t)mcookie); +} + +fstack_t +mcookie_to_rvirt(fstack_t mcookie) +{ + int i; + struct map_table *mp; + + for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++) { + if ((mp->map_flags & MAP_IS_VALID) && + mcookie >= mp->map_add && + mcookie < mp->map_add + mp->map_size) { + return (mp->map_add); + } + } + log_message(MSG_WARN, "Warning: mcookie_to_rvirt: invalid" + " mcookie: %llx\n", (uint64_t)mcookie); +} + +static void +dot_maps(fcode_env_t *env) +{ + int i; + + log_message(MSG_DEBUG, "idx base-addr size\n"); + for (i = 0; i < MAX_MAPS; i++) { + if (map_table[i].map_flags & MAP_IS_VALID) + log_message(MSG_DEBUG, "%3d %016llx %8x\n", i, + map_table[i].map_add, map_table[i].map_size); + } +} + +static void +map_qmark(fcode_env_t *env) +{ + fstack_t d = POP(DS); + + if (!is_mcookie(d)) + log_message(MSG_INFO, "%llx: not mcookie\n", (uint64_t)d); + else + log_message(MSG_INFO, "%llx -> %llx\n", (uint64_t)d, + mcookie_to_addr(d)); +} + +static void +add_map(fcode_env_t *env) +{ + fstack_t size, addr; + + size = POP(DS); + addr = POP(DS); + addr = mapping_to_mcookie(addr, size, NULL, NULL); + PUSH(DS, addr); +} + +static void +del_map(fcode_env_t *env) +{ + fstack_t addr; + + addr = POP(DS); + delete_mapping(addr); +} + + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + ASSERT(env); + NOTICE; + + FORTH(0, ".maps", dot_maps); + FORTH(0, "map?", map_qmark); + FORTH(0, "add-map", add_map); + FORTH(0, "del-map", del_map); +} diff --git a/usr/src/lib/efcode/engine/package.c b/usr/src/lib/efcode/engine/package.c new file mode 100644 index 0000000000..b32773f45d --- /dev/null +++ b/usr/src/lib/efcode/engine/package.c @@ -0,0 +1,1077 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2000 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +#include <fcdriver/fcdriver.h> + +#define MIN_VALUES 100 + +static void +check_my_self(fcode_env_t *env, char *fn) +{ + if (!MYSELF) + forth_abort(env, "%s: MYSELF is NULL", fn); +} + +uint_t +get_number_of_parent_address_cells(fcode_env_t *env) +{ + uint_t ncells; + device_t *d; + static char func_name[] = "get_number_of_parent_address_cells"; + + if (MYSELF == NULL) /* Kludge for testing */ + return (2); + d = MYSELF->device; + ncells = d->parent_adr_cells; + if (ncells == 0) { + ncells = get_default_intprop(env, "#address-cells", d->parent, + 2); + if (ncells > MAX_MY_ADDR) { + log_message(MSG_ERROR, "%s: %s:" + " ncells (%d) > MAX_MY_ADDR (%d)\n", func_name, + get_path(env, d->parent), ncells, MAX_MY_ADDR); + ncells = MAX_MY_ADDR; + } + d->parent_adr_cells = ncells; + } + return (ncells); +} + +instance_t * +create_ihandle(fcode_env_t *env, device_t *phandle, instance_t *parent) +{ + instance_t *ihandle; + int i; + + ihandle = MALLOC(sizeof (instance_t)); + + i = max(phandle->data_size[INIT_DATA], MIN_VALUES); + ihandle->data[INIT_DATA] = MALLOC(sizeof (fstack_t) * i); + memcpy(ihandle->data[INIT_DATA], phandle->init_data, + (size_t) (sizeof (fstack_t) * i)); + + i = max(phandle->data_size[UINIT_DATA], MIN_VALUES); + ihandle->data[UINIT_DATA] = MALLOC(sizeof (fstack_t) * i); + + ihandle->my_space = phandle->my_space; + memcpy(ihandle->my_addr, phandle->my_addr, sizeof (ihandle->my_addr)); + ihandle->parent = parent; + ihandle->device = phandle; + return (ihandle); +} + +device_t * +create_phandle(fcode_env_t *env, device_t *parent) +{ + device_t *phandle; + + phandle = MALLOC(sizeof (device_t)); + phandle->init_data = MALLOC(sizeof (fstack_t) * MIN_VALUES); + phandle->data_size[INIT_DATA] = 0; + phandle->data_size[UINIT_DATA] = 0; + phandle->parent = parent; + return (phandle); +} + + +static void +do_push_package(fcode_env_t *env, device_t *d) +{ + do_previous(env); + do_also(env); + if (d != NULL) { + CONTEXT = (token_t *)(&d->vocabulary); + debug_msg(DEBUG_CONTEXT, "CONTEXT:push_package: %s%d/%p/%p\n", + get_path(env, d), env->order_depth, CONTEXT, env->current); + } +} + +static void +push_package(fcode_env_t *env) +{ + device_t *d; + phandle_t ph; + + CHECK_DEPTH(env, 1, "push-package"); + ph = POP(DS); + CONVERT_PHANDLE(env, d, ph); + do_push_package(env, d); +} + +static void +pop_package(fcode_env_t *env) +{ + do_previous(env); + do_definitions(env); +} + +static void +interpose(fcode_env_t *env) +{ + TODO; /* interpose - not yet implemented */ +} + +void +activate_device(fcode_env_t *env, device_t *d) +{ + env->current_device = d; + do_push_package(env, d); + do_definitions(env); +} + +void +deactivate_device(fcode_env_t *env, device_t *d) +{ + env->current_device = d; + do_previous(env); + if (d != NULL) { + CONTEXT = (token_t *)(&d->vocabulary); + debug_msg(DEBUG_CONTEXT, "CONTEXT:deactivate_device:" + " %s%d/%p/%p\n", get_path(env, d), env->order_depth, + CONTEXT, env->current); + } + do_definitions(env); +} + +/* + * Starfire hack to set '/' device_type to 'upa' + */ +#include <sys/systeminfo.h> +static void +starfire_hack(fcode_env_t *env) +{ + char platform[100]; + + sysinfo(SI_PLATFORM, platform, sizeof (platform)); + if (strcmp(platform, "SUNW,Ultra-Enterprise-10000") == 0 && + find_property(env->root_node, "device_type") == NULL) { + create_string_prop(env, "device_type", "upa"); + } +} + +void +root_node(fcode_env_t *env) +{ + do_also(env); + activate_device(env, env->root_node); + starfire_hack(env); +} + +void +child_node(fcode_env_t *env) +{ + device_t *d; + + CHECK_DEPTH(env, 1, "child"); + CONVERT_PHANDLE(env, d, TOS); + TOS = (fstack_t)d->child; + REVERT_PHANDLE(env, TOS, d->child); +} + +void +peer_node(fcode_env_t *env) +{ + device_t *d; + + CHECK_DEPTH(env, 1, "peer"); + CONVERT_PHANDLE(env, d, TOS); + REVERT_PHANDLE(env, TOS, d->peer); +} + +void +new_device(fcode_env_t *env) +{ + device_t *phandle, *parent; + device_t *peer; + + check_my_self(env, "new-device"); + + parent = MYSELF->device; + phandle = create_phandle(env, parent); + MYSELF = create_ihandle(env, phandle, MYSELF); + activate_device(env, phandle); + if (parent->child) { + /* Insert new child at end of peer list */ + for (peer = parent->child; peer->peer; peer = peer->peer) + ; + peer->peer = phandle; + } else + parent->child = phandle; /* First child */ + ALLOCATE_PHANDLE(env); +} + +void +finish_device(fcode_env_t *env) +{ + fstack_t *mem; + device_t *my_dev, *parent_dev; + instance_t *parent, *myself = MYSELF; + int n; + + check_my_self(env, "finish-device"); + ASSERT(myself->device); + ASSERT(env->current_device); + n = myself->device->data_size[INIT_DATA]; + + /* + * Paranoia.. reserve a little more instance data than we need + */ + mem = MALLOC(sizeof (fstack_t) * (n+8)); + memcpy(mem, MYSELF->device->init_data, sizeof (fstack_t) * n); + FREE(myself->device->init_data); + my_dev = myself->device; + my_dev->init_data = mem; + parent = MYSELF->parent; + parent_dev = env->current_device->parent; + FREE(MYSELF); + MYSELF = parent; + activate_device(env, parent_dev); +} + +static void +create_internal_value(fcode_env_t *env, char *name, int offset, int token) +{ + header(env, name, strlen(name), 0); + COMPILE_TOKEN(&noop); + EXPOSE_ACF; + if (token) { + SET_TOKEN(token, 0, name, LINK_TO_ACF(env->lastlink)); + } + PUSH(DS, offset); + lcomma(env); + set_internal_value_actions(env); +} + +static void +create_my_self(fcode_env_t *env) +{ + int offset = offsetof(fcode_env_t, my_self); + + create_internal_value(env, "my-self", offset, 0x203); +} + +static void +create_my_space(fcode_env_t *env) +{ + int offset = offsetof(instance_t, my_space); + + create_internal_value(env, "my-space", -offset, 0x103); +} + +void +my_address(fcode_env_t *env) +{ + fstack_t *adr_ptr; + uint_t ncells; + + check_my_self(env, "my-address"); + ncells = get_number_of_parent_address_cells(env); + adr_ptr = MYSELF->my_addr; + while (--ncells) { + PUSH(DS, *adr_ptr); + adr_ptr++; + } +} + +void +my_unit(fcode_env_t *env) +{ + check_my_self(env, "my-unit"); + my_address(env); + PUSH(DS, MYSELF->my_space); +} + +static void +my_args(fcode_env_t *env) +{ + check_my_self(env, "my-args"); + PUSH(DS, (fstack_t)MYSELF->my_args); + PUSH(DS, (fstack_t)MYSELF->my_args_len); +} + +int +call_my_parent(fcode_env_t *env, char *method) +{ + push_a_string(env, method); + dollar_call_parent(env); + return (env->last_error); +} + +void +set_args(fcode_env_t *env) +{ + int args_len; + common_data_t *cdp; + uint_t ncells; + fstack_t *adr_ptr, *adr_ptr1, space; + + CHECK_DEPTH(env, 4, "set-args"); + + check_my_self(env, "set-args"); + + /* + * Handle args argument of set-args. + */ + if (MYSELF->my_args) { + FREE(MYSELF->my_args); + MYSELF->my_args = NULL; + } + two_swap(env); + MYSELF->my_args = pop_a_duped_string(env, &args_len); + MYSELF->my_args_len = args_len; + + if (call_my_parent(env, "decode-unit")) + forth_abort(env, "set-args: decode-unit failed"); + + ncells = get_number_of_parent_address_cells(env); + + /* + * Kludge: For GP2, my-space comes from decode-unit hi.address. + * for PCI, my-space from decode-unit won't have the bus#, so we need + * to get it from config_address. Unfortunately, there is no easy + * way to figure out here which one we're looking at. We take the + * expediant of or'ing the two values together. + */ + space = POP(DS); /* pop phys.hi */ + if ((cdp = (common_data_t *)env->private) != NULL) + space |= cdp->fc.config_address; + + MYSELF->device->my_space = MYSELF->my_space = space; + + adr_ptr = MYSELF->my_addr; + adr_ptr1 = MYSELF->device->my_addr; + while (--ncells) { + *adr_ptr++ = *adr_ptr1++ = POP(DS); + } +} + +void +my_parent(fcode_env_t *env) +{ + check_my_self(env, "my-parent"); + PUSH(DS, (fstack_t)MYSELF->parent); +} + +instance_t * +open_instance_chain(fcode_env_t *env, device_t *phandle, int exec) +{ + instance_t *parent; + + if (!phandle) + return (NULL); + parent = open_instance_chain(env, phandle->parent, exec); + return (create_ihandle(env, phandle, parent)); +} + +void +close_instance_chain(fcode_env_t *env, instance_t *ihandle, int exec) +{ + instance_t *parent; + + if (ihandle) { + parent = ihandle->parent; + close_instance_chain(env, parent, exec); + if (ihandle->my_args) + FREE(ihandle->my_args); + FREE(ihandle); + } +} + +void +begin_package(fcode_env_t *env) +{ + fstack_t ok; + char *name; + + CHECK_DEPTH(env, 6, "begin-package"); + two_dup(env); + name = pop_a_string(env, NULL); + find_package(env); + ok = POP(DS); + if (ok) { + PUSH(DS, 0); + PUSH(DS, 0); + rot(env); + open_package(env); + MYSELF = (instance_t *)POP(DS); + check_my_self(env, "begin-package"); + new_device(env); + set_args(env); + } else { + log_message(MSG_INFO, "Package '%s' not found\n", name); + } +} + +void +open_package(fcode_env_t *env) +{ + device_t *phandle; + instance_t *ihandle; + int len; + + CHECK_DEPTH(env, 3, "open-package"); + CONVERT_PHANDLE(env, phandle, POP(DS)); + ihandle = open_instance_chain(env, phandle, 1); + ihandle->my_args = pop_a_duped_string(env, &len); + ihandle->my_args_len = len; + PUSH(DS, (fstack_t)ihandle); +} + +void +dollar_open_package(fcode_env_t *env) +{ + fstack_t ok; + + CHECK_DEPTH(env, 4, "$open-package"); + find_package(env); + ok = POP(DS); + if (ok) { + open_package(env); + } else { + PUSH(DS, 0); + } +} + +void +close_package(fcode_env_t *env) +{ + instance_t *ihandle; + + CHECK_DEPTH(env, 1, "close-package"); + ihandle = (instance_t *)POP(DS); + close_instance_chain(env, ihandle, 1); +} + +static void (*find_method_hook)(fcode_env_t *); + +void +set_find_method_hook(fcode_env_t *env, void (*hook)(fcode_env_t *)) +{ + find_method_hook = hook; +} + +void +find_method(fcode_env_t *env) +{ + fstack_t d; + device_t *device; + acf_t acf = 0; + + CHECK_DEPTH(env, 3, "find-method"); + if (find_method_hook) { + (*find_method_hook)(env); + if (TOS) /* Found it */ + return; + POP(DS); + } + + d = POP(DS); + CONVERT_PHANDLE(env, device, d); + PUSH(DS, (fstack_t)&device->vocabulary); + acf = voc_find(env); + PUSH(DS, (fstack_t)acf); + if (acf) { + PUSH(DS, TRUE); + } +} + +/* + * 'call-package' Fcode + */ +void +call_package(fcode_env_t *env) +{ + instance_t *ihandle, *saved_myself; + + CHECK_DEPTH(env, 2, "call-package"); + ihandle = (instance_t *)POP(DS); + saved_myself = MYSELF; + MYSELF = ihandle; + execute(env); + MYSELF = saved_myself; +} + +void +ihandle_to_phandle(fcode_env_t *env) +{ + instance_t *i; + + CHECK_DEPTH(env, 1, "ihandle>phandle"); + i = (instance_t *)TOS; + REVERT_PHANDLE(env, TOS, i->device); +} + +char * +get_package_name(fcode_env_t *env, device_t *d) +{ + char *name; + prop_t *prop; + + prop = lookup_package_property(env, "name", d); + if (prop == NULL) { + name = "<Unnamed>"; + } else { + name = (char *)prop->data; + } + return (name); +} + +static char *package_search_path = "/packages:/openprom"; + +device_t * +match_package_path(fcode_env_t *env, char *path) +{ + device_t *d; + char *name; + int len; + + if (*path == '/') { + d = env->root_node->child; + path++; + } else + d = env->current_device; + while (*path != '\0' && d != NULL) { + name = get_package_name(env, d); + len = strlen(name); + if (strncmp(name, path, len) == 0) { + path += len; + if (*path == '\0') { + return (d); + } + /* skip the '/' */ + if (*path++ != '/') + break; + d = d->child; + } else { + d = d->peer; + } + } + return (NULL); +} + +device_t * +locate_package(fcode_env_t *env, char *start) +{ + device_t *d; + char *p, *next_p; + char *tpath, *fpath; + + if ((d = match_package_path(env, start)) != NULL) + return (d); + + /* + * ignore starting '/' + */ + if (*start == '/') + *start++; + + fpath = STRDUP(package_search_path); + for (p = fpath; p != NULL; p = next_p) { + if ((next_p = strchr(p, ':')) != NULL) + *next_p++ = '\0'; + tpath = MALLOC(strlen(p) + strlen(start) + 2); + sprintf(tpath, "%s/%s", p, start); + if ((d = match_package_path(env, tpath)) != NULL) { + FREE(fpath); + FREE(tpath); + return (d); + } + FREE(tpath); + } + FREE(fpath); + return (NULL); +} + +void +find_package(fcode_env_t *env) +{ + char *path; + device_t *package; + fstack_t ph = 0; + + CHECK_DEPTH(env, 2, "find-package"); + if ((path = pop_a_duped_string(env, NULL)) != NULL) { + if (strcmp(path, "/") == 0) + package = env->root_node; + else + package = locate_package(env, path); + FREE(path); + REVERT_PHANDLE(env, ph, package); + } + PUSH(DS, ph); + if (package) + PUSH(DS, TRUE); +} + +static void +encode_unit_hack(fcode_env_t *env) +{ + int hi, i; + uint_t ncells = get_number_of_parent_address_cells(env); + + for (i = 0; i < ncells; i++) + POP(DS); + push_a_string(env, NULL); +} + +void +dollar_call_method(fcode_env_t *env) +{ + instance_t *old_myself; + instance_t *myself; + device_t *device; + char *method; + + CHECK_DEPTH(env, 3, "$call-method"); + check_my_self(env, "$call-method"); + old_myself = MYSELF; + myself = (instance_t *)POP(DS); + + method = (char *)DS[-1]; + debug_msg(DEBUG_CALL_METHOD, "$call_method %s\n", method); + + if (old_myself && !myself) { + /* We hit the root of our tree */ + device = old_myself->device; + return; + } + + MYSELF = myself; + check_my_self(env, "$call-method"); + device = MYSELF->device; + do_push_package(env, device); + PUSH(DS, (fstack_t)device); + REVERT_PHANDLE(env, TOS, device); + find_method(env); + if (TOS) { + (void) POP(DS); + execute(env); + } else if (strcmp(method, "encode-unit") == 0) { + encode_unit_hack(env); + } else { + throw_from_fclib(env, 1, "Unimplemented package method: %s%s", + get_path(env, device), method); + } + MYSELF = old_myself; + do_push_package(env, MYSELF->device); +} + +void +dollar_call_parent(fcode_env_t *env) +{ + CHECK_DEPTH(env, 2, "$call-parent"); + + check_my_self(env, "$call-parent"); + + PUSH(DS, (fstack_t)MYSELF->parent); + dollar_call_method(env); +} + +#ifdef DEBUG +void +current_device(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)&env->current_device); +} + +char * +get_path(fcode_env_t *env, device_t *d) +{ + char *pre_path, *name, *path; + int n; + + if (d->parent) + pre_path = get_path(env, d->parent); + else + pre_path = STRDUP(""); + + name = get_package_name(env, d); + n = strlen(pre_path) + strlen(name) + 1; + path = MALLOC(n); + strcpy(path, pre_path); + strcat(path, name); + if (d->child && d->parent) + strcat(path, "/"); + FREE(pre_path); + return (path); +} + +static void +pwd_dollar(fcode_env_t *env) +{ + if (env->current_device) + push_a_string(env, get_path(env, env->current_device)); + else + push_a_string(env, NULL); +} + +void +pwd(fcode_env_t *env) +{ + if (env->current_device) { + log_message(MSG_INFO, "%s\n", + get_path(env, env->current_device)); + } else { + log_message(MSG_INFO, "No device context\n"); + } +} + +void +do_ls(fcode_env_t *env) +{ + device_t *d; + + if (env->current_device == NULL) { + log_message(MSG_INFO, "No device context\n"); + return; + } + + d = env->current_device->child; + while (d) { + char *name; + fstack_t ph; + name = get_package_name(env, d); + REVERT_PHANDLE(env, ph, d); + log_message(MSG_INFO, "%llx %s\n", (uint64_t)ph, name); + d = d->peer; + } +} + +void +paren_cd(fcode_env_t *env) +{ + char *str; + device_t *p; + + str = pop_a_string(env, NULL); + if (strcmp(str, "/") == 0) { + root_node(env); + return; + } + + if (env->current_device == NULL) { + log_message(MSG_INFO, "No device context\n"); + return; + } + + if (strcmp(str, "..") == 0) + p = env->current_device->parent; + else { + device_t *n = env->current_device->child; + + p = NULL; + while (n) { + char *name; + + name = get_package_name(env, n); + if (strcmp(name, str) == 0) { + p = n; + break; + } + n = n->peer; + } + } + + if (p) { + activate_device(env, p); + } else { + log_message(MSG_INFO, "No such node: %s\n", str); + } +} + +void +do_cd(fcode_env_t *env) +{ + parse_word(env); + paren_cd(env); +} + +void +do_unselect_dev(fcode_env_t *env) +{ + check_my_self(env, "unselect-dev"); + PUSH(DS, (fstack_t)MYSELF); + close_package(env); + deactivate_device(env, NULL); +} + +void +do_select_dev(fcode_env_t *env) +{ + PUSH(DS, 0); + PUSH(DS, 0); + two_swap(env); + dollar_open_package(env); + if (TOS) { + MYSELF = (instance_t *)POP(DS); + check_my_self(env, "select-dev"); + activate_device(env, MYSELF->device); + } else { + drop(env); + log_message(MSG_INFO, "Can't open package\n"); + } +} + +void +device_end(fcode_env_t *env) +{ + if (env->current_device) { + deactivate_device(env, NULL); + } +} + +void +end_package(fcode_env_t *env) +{ + finish_device(env); + close_instance_chain(env, MYSELF, 0); + device_end(env); + MYSELF = NULL; +} + +void +exec_parent_method(fcode_env_t *env) +{ + instance_t *old_myself; + instance_t *myself; + device_t *device; + char *method; + fstack_t d; + + check_my_self(env, "exec-parent-method"); + old_myself = MYSELF; + MYSELF = MYSELF->parent; + + method = (char *)DS[-1]; + debug_msg(DEBUG_FIND_FCODE, "exec_parent_method: '%s'\n", method); + + check_my_self(env, "exec-parent-method"); + device = MYSELF->device; + do_push_package(env, device); + PUSH(DS, (fstack_t)device); + REVERT_PHANDLE(env, TOS, device); + find_method(env); + d = POP(DS); + if (d) { + debug_msg(DEBUG_FIND_FCODE, "exec-parent-method: '%s'/%x" + " execute\n", method, (int)TOS); + execute(env); + PUSH(DS, TRUE); + } else { + debug_msg(DEBUG_FIND_FCODE, "exec-parent-method: '%s'" + " not found\n", method); + PUSH(DS, FALSE); + } + MYSELF = old_myself; + do_push_package(env, MYSELF->device); +} + +void +dump_device(fcode_env_t *env) +{ + device_t *phandle; + int i; + + CONVERT_PHANDLE(env, phandle, POP(DS)); + log_message(MSG_DEBUG, "Node: %p\n", phandle); + log_message(MSG_DEBUG, " Parent: (%8p) %p\n", + &phandle->parent, phandle->parent); + log_message(MSG_DEBUG, " Child: (%8p) %p\n", + &phandle->child, phandle->child); + log_message(MSG_DEBUG, " Peer: (%8p) %p\n", + &phandle->peer, phandle->peer); + log_message(MSG_DEBUG, " Private: (%8p) %p\n", + &phandle->private, phandle->private); + log_message(MSG_DEBUG, " Props: (%8p) %p\n", + &phandle->properties, phandle->properties); + log_message(MSG_DEBUG, " Voc: (%8p) %p\n", + &phandle->vocabulary, phandle->vocabulary); + log_message(MSG_DEBUG, " sizes: (%8p) %d %d\n", + &phandle->data_size, + phandle->data_size[INIT_DATA], + phandle->data_size[UINIT_DATA]); + log_message(MSG_DEBUG, " my_space: %x\n", phandle->my_space); + log_message(MSG_DEBUG, " my_addr :"); + for (i = 0; i < MAX_MY_ADDR; i++) + log_message(MSG_DEBUG, " %x", (int)phandle->my_addr[i]); + log_message(MSG_DEBUG, "\n"); + log_message(MSG_DEBUG, " data: (%8p)\n", phandle->init_data); + for (i = 0; i < phandle->data_size[INIT_DATA]; i++) { + log_message(MSG_DEBUG, " %3d -> (%8p) %x\n", i, + &phandle->init_data[i], phandle->init_data[i]); + } +} + +void +dump_instance(fcode_env_t *env) +{ + int i; + instance_t *ihandle; + + ihandle = (instance_t *)POP(DS); + log_message(MSG_DEBUG, "Ihandle: %p\n", ihandle); + log_message(MSG_DEBUG, " Parent: (%8p) %p\n", + &ihandle->parent, ihandle->parent); + log_message(MSG_DEBUG, " Device: (%8p) %p\n", + &ihandle->device, ihandle->device); + log_message(MSG_DEBUG, " args: '%s'\n", + ((ihandle->my_args) ? ihandle->my_args : "")); + log_message(MSG_DEBUG, " my-space: %x\n", ihandle->my_space); + log_message(MSG_DEBUG, " my_addr :"); + for (i = 0; i < MAX_MY_ADDR; i++) + log_message(MSG_DEBUG, " %x", (int)ihandle->my_addr[i]); + log_message(MSG_DEBUG, "\n"); + log_message(MSG_DEBUG, " sizes: %d %d\n", + ihandle->device->data_size[INIT_DATA], + ihandle->device->data_size[UINIT_DATA]); + log_message(MSG_DEBUG, " data: (%8p) %x %x\n", + ihandle->data, ihandle->data[0], ihandle->data[1]); + if (ihandle->device->data_size[INIT_DATA]) { + log_message(MSG_DEBUG, " Initialised:\n"); + for (i = 0; i < ihandle->device->data_size[INIT_DATA]; i++) { + log_message(MSG_DEBUG, " %3d -> (%8p) %x\n", i, + &ihandle->data[INIT_DATA][i], + ihandle->data[INIT_DATA][i]); + } + } + if (ihandle->device->data_size[INIT_DATA]) { + log_message(MSG_DEBUG, " UnInitialised:\n"); + for (i = 0; i < ihandle->device->data_size[UINIT_DATA]; i++) { + log_message(MSG_DEBUG, " %3d -> (%8p) %x\n", i, + &ihandle->data[UINIT_DATA][i], + ihandle->data[UINIT_DATA][i]); + } + } +} + +#endif + +#pragma init(_init) + +#ifdef CONVERT_HANDLES +static device_t * +safe_convert_phandle(fcode_env_t *env, fstack_t d) +{ + return ((device_t *)d); +} + +static fstack_t +safe_revert_phandle(fcode_env_t *env, device_t *d) +{ + return ((fstack_t)d); +} + +static void +safe_allocate_phandle(fcode_env_t *env) +{ +} + +#endif + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + char *name = "/"; + device_t *d; + + ASSERT(env); + NOTICE; + +#ifdef CONVERT_HANDLES + env->convert_phandle = safe_convert_phandle; + env->revert_phandle = safe_revert_phandle; + env->allocate_phandle = safe_allocate_phandle; +#endif + + /* build the root node */ + d = create_phandle(env, NULL); + env->current_device = d; + env->root_node = d; + push_a_string(env, name); + device_name(env); + env->current_device = NULL; + + create_my_self(env); + create_my_space(env); + + P1275(0x102, 0, "my-address", my_address); + /* Fcode 0x103 "my-space" is created using create_internal_value */ + + P1275(0x11f, 0, "new-device", new_device); + + P1275(0x127, 0, "finish-device", finish_device); + + FCODE(0x129, 0, "push-package", push_package); + FCODE(0x12a, 0, "pop-package", pop_package); + FCODE(0x12b, 0, "interpose", interpose); + + P1275(0x202, 0, "my-args", my_args); + /* Fcode 0x203 "my-self" is created using create_internal_value */ + P1275(0x204, 0, "find-package", find_package); + P1275(0x205, 0, "open-package", open_package); + P1275(0x206, 0, "close-package", close_package); + P1275(0x207, 0, "find-method", find_method); + P1275(0x208, 0, "call-package", call_package); + P1275(0x209, 0, "$call-parent", dollar_call_parent); + P1275(0x20a, 0, "my-parent", my_parent); + P1275(0x20b, 0, "ihandle>phandle", ihandle_to_phandle); + + P1275(0x20d, 0, "my-unit", my_unit); + P1275(0x20e, 0, "$call-method", dollar_call_method); + P1275(0x20f, 0, "$open-package", dollar_open_package); + + P1275(0x23b, 0, "child", child_node); + P1275(0x23c, 0, "peer", peer_node); + + P1275(0x23f, 0, "set-args", set_args); + + FORTH(IMMEDIATE, "root-node", root_node); + FORTH(0, "current-device", current_device); + FORTH(0, "pwd$", pwd_dollar); + FORTH(IMMEDIATE, "pwd", pwd); + FORTH(IMMEDIATE, "ls", do_ls); + FORTH(IMMEDIATE, "(cd)", paren_cd); + FORTH(IMMEDIATE, "cd", do_cd); + FORTH(IMMEDIATE, "device-end", device_end); + FORTH(0, "select-dev", do_select_dev); + FORTH(0, "unselect-dev", do_unselect_dev); + FORTH(0, "begin-package", begin_package); + FORTH(0, "end-package", end_package); + FORTH(IMMEDIATE, "dump-device", dump_device); + FORTH(IMMEDIATE, "dump-instance", dump_instance); + FORTH(0, "exec-parent-method", exec_parent_method); +} diff --git a/usr/src/lib/efcode/engine/prims64.c b/usr/src/lib/efcode/engine/prims64.c new file mode 100644 index 0000000000..7a4f7fa9d1 --- /dev/null +++ b/usr/src/lib/efcode/engine/prims64.c @@ -0,0 +1,464 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2000 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcode/private.h> +#include <fcdriver/fcdriver.h> + +#define LF_PER_XF (sizeof (xforth_t)/sizeof (lforth_t)) +#define WF_PER_XF (sizeof (xforth_t)/sizeof (wforth_t)) + +void unaligned_xfetch(fcode_env_t *); +void unaligned_xstore(fcode_env_t *); +static void xbsplit(fcode_env_t *); + +xforth_t +pop_xforth(fcode_env_t *env) +{ + if (sizeof (xforth_t) == sizeof (fstack_t)) + return (POP(DS)); + return ((xforth_t)pop_double(env)); +} + +xforth_t +peek_xforth(fcode_env_t *env) +{ + xforth_t d; + + d = pop_xforth(env); + push_xforth(env, d); + return (d); +} + +void +push_xforth(fcode_env_t *env, xforth_t a) +{ + if (sizeof (xforth_t) == sizeof (fstack_t)) + PUSH(DS, a); + else + push_double(env, (dforth_t)a); +} + +/* + * bxjoin ( b.lo b.2 b.3 b.4 b.5 b.6 b.7 b.hi -- o ) + */ +static void +bxjoin(fcode_env_t *env) +{ + union { + uchar_t b_bytes[sizeof (xforth_t)]; + xforth_t b_xf; + } b; + int i; + + CHECK_DEPTH(env, sizeof (xforth_t), "bxjoin"); + for (i = 0; i < sizeof (xforth_t); i++) + b.b_bytes[i] = POP(DS); + push_xforth(env, b.b_xf); +} + +/* + * <l@ ( qaddr -- n ) + */ +static void +lsfetch(fcode_env_t *env) +{ + s_lforth_t *addr; + xforth_t a; + + CHECK_DEPTH(env, 1, "<l@"); + addr = (s_lforth_t *)POP(DS); + a = *addr; + push_xforth(env, a); +} + +/* + * lxjoin ( quad.lo quad.hi -- o ) + */ +static void +lxjoin(fcode_env_t *env) +{ + union { + lforth_t b_lf[LF_PER_XF]; + xforth_t b_xf; + } b; + int i; + + CHECK_DEPTH(env, LF_PER_XF, "lxjoin"); + for (i = 0; i < LF_PER_XF; i++) + b.b_lf[i] = POP(DS); + push_xforth(env, b.b_xf); +} + +/* + * wxjoin ( w.lo w.2 w.3 w.hi -- o ) + */ +static void +wxjoin(fcode_env_t *env) +{ + union { + wforth_t b_wf[WF_PER_XF]; + xforth_t b_xf; + } b; + int i; + + CHECK_DEPTH(env, WF_PER_XF, "wxjoin"); + for (i = 0; i < WF_PER_XF; i++) + b.b_wf[i] = POP(DS); + push_xforth(env, b.b_xf); +} + +/* + * x, ( o -- ) + */ +static void +xcomma(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "x,"); + DEBUGF(COMMA, dump_comma(env, "x,")); + PUSH(DS, (fstack_t)HERE); + unaligned_xstore(env); + set_here(env, HERE + sizeof (xforth_t), "xcomma"); +} + +/* + * x@ ( xaddr -- o ) + */ +void +xfetch(fcode_env_t *env) +{ + xforth_t *addr; + xforth_t a; + + CHECK_DEPTH(env, 1, "x@"); + addr = (xforth_t *)POP(DS); + a = *addr; + push_xforth(env, a); +} + +/* + * x! ( o xaddr -- ) + */ +void +xstore(fcode_env_t *env) +{ + xforth_t *addr; + xforth_t a; + + CHECK_DEPTH(env, 2, "x!"); + addr = (xforth_t *)POP(DS); + a = pop_xforth(env); + *addr = a; +} + +/* + * /x ( -- n ) + */ +static void +slash_x(fcode_env_t *env) +{ + PUSH(DS, sizeof (xforth_t)); +} + +/* + * /x* ( nu1 -- nu2 ) + */ +static void +slash_x_times(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "/x*"); + TOS *= sizeof (xforth_t); +} + +/* + * xa+ ( addr1 index -- addr2 ) + */ +static void +xa_plus(fcode_env_t *env) +{ + fstack_t index; + + CHECK_DEPTH(env, 2, "xa+"); + index = POP(DS); + TOS += index * sizeof (xforth_t); +} + +/* + * xa1+ ( addr1 -- addr2 ) + */ +static void +xa_one_plus(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "xa1+"); + TOS += sizeof (xforth_t); +} + +/* + * xbflip ( oct1 -- oct2 ) + */ +void +xbflip(fcode_env_t *env) +{ + union { + uchar_t b_bytes[sizeof (xforth_t)]; + xforth_t b_xf; + } b, c; + int i; + + CHECK_DEPTH(env, 1, "xbflip"); + b.b_xf = pop_xforth(env); + for (i = 0; i < sizeof (xforth_t); i++) + c.b_bytes[i] = b.b_bytes[(sizeof (xforth_t) - 1) - i]; + push_xforth(env, c.b_xf); +} + +void +unaligned_xfetch(fcode_env_t *env) +{ + fstack_t addr; + int i; + + CHECK_DEPTH(env, 1, "unaligned-x@"); + addr = POP(DS); + for (i = 0; i < sizeof (xforth_t); i++, addr++) { + PUSH(DS, addr); + cfetch(env); + } + bxjoin(env); + xbflip(env); +} + +void +unaligned_xstore(fcode_env_t *env) +{ + fstack_t addr; + int i; + + CHECK_DEPTH(env, 2, "unaligned-x!"); + addr = POP(DS); + xbsplit(env); + for (i = 0; i < sizeof (xforth_t); i++, addr++) { + PUSH(DS, addr); + cstore(env); + } +} + +/* + * xbflips ( xaddr len -- ) + */ +static void +xbflips(fcode_env_t *env) +{ + fstack_t len, addr; + int i; + + CHECK_DEPTH(env, 2, "xbflips"); + len = POP(DS); + addr = POP(DS); + for (i = 0; i < len; i += sizeof (xforth_t), + addr += sizeof (xforth_t)) { + PUSH(DS, addr); + unaligned_xfetch(env); + xbflip(env); + PUSH(DS, addr); + unaligned_xstore(env); + } +} + +/* + * xbsplit ( o -- b.lo b.2 b.3 b.4 b.5 b.6 b.7 b.hi ) + */ +static void +xbsplit(fcode_env_t *env) +{ + union { + uchar_t b_bytes[sizeof (xforth_t)]; + xforth_t b_xf; + } b; + int i; + + CHECK_DEPTH(env, 1, "xbsplit"); + b.b_xf = pop_xforth(env); + for (i = 0; i < sizeof (xforth_t); i++) + PUSH(DS, b.b_bytes[(sizeof (xforth_t) - 1) - i]); +} + +/* + * xlflip ( oct1 -- oct2 ) + */ +void +xlflip(fcode_env_t *env) +{ + union { + lforth_t b_lf[LF_PER_XF]; + xforth_t b_xf; + } b, c; + int i; + + CHECK_DEPTH(env, 1, "xlflip"); + b.b_xf = pop_xforth(env); + for (i = 0; i < LF_PER_XF; i++) + c.b_lf[i] = b.b_lf[(LF_PER_XF - 1) - i]; + push_xforth(env, c.b_xf); +} + +/* + * xlflips ( xaddr len -- ) + */ +static void +xlflips(fcode_env_t *env) +{ + fstack_t len, addr; + int i; + + CHECK_DEPTH(env, 2, "xlflips"); + len = POP(DS); + addr = POP(DS); + for (i = 0; i < len; i += sizeof (xforth_t), + addr += sizeof (xforth_t)) { + PUSH(DS, addr); + unaligned_xfetch(env); + xlflip(env); + PUSH(DS, addr); + unaligned_xstore(env); + } +} + +/* + * xlsplit ( o -- quad.lo quad.hi ) + */ +static void +xlsplit(fcode_env_t *env) +{ + union { + lforth_t b_lf[LF_PER_XF]; + xforth_t b_xf; + } b; + int i; + + CHECK_DEPTH(env, 1, "xlsplit"); + b.b_xf = pop_xforth(env); + for (i = 0; i < LF_PER_XF; i++) + PUSH(DS, b.b_lf[(LF_PER_XF - 1) - i]); +} + + +/* + * xwflip ( oct1 -- oct2 ) + */ +static void +xwflip(fcode_env_t *env) +{ + union { + wforth_t b_wf[WF_PER_XF]; + xforth_t b_xf; + } b, c; + int i; + + CHECK_DEPTH(env, 1, "xwflip"); + b.b_xf = pop_xforth(env); + for (i = 0; i < WF_PER_XF; i++) + c.b_wf[i] = b.b_wf[(WF_PER_XF - 1) - i]; + push_xforth(env, c.b_xf); +} + +/* + * xwflips ( xaddr len -- ) + */ +static void +xwflips(fcode_env_t *env) +{ + fstack_t len, addr; + int i; + + CHECK_DEPTH(env, 2, "xwflips"); + len = POP(DS); + addr = POP(DS); + for (i = 0; i < len; i += sizeof (xforth_t), + addr += sizeof (xforth_t)) { + PUSH(DS, addr); + unaligned_xfetch(env); + xwflip(env); + PUSH(DS, addr); + unaligned_xstore(env); + } +} + +/* + * xwsplit ( o -- w.lo w.2 w.3 w.hi ) + */ +static void +xwsplit(fcode_env_t *env) +{ + union { + wforth_t b_wf[WF_PER_XF]; + xforth_t b_xf; + } b; + int i; + + CHECK_DEPTH(env, 1, "xwsplit"); + b.b_xf = pop_xforth(env); + for (i = 0; i < WF_PER_XF; i++) + PUSH(DS, b.b_wf[(WF_PER_XF - 1) - i]); +} + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + ASSERT(env); + NOTICE; + P1275(0x241, 0, "bxjoin", bxjoin); + P1275(0x242, 0, "<l@", lsfetch); + P1275(0x243, 0, "lxjoin", lxjoin); + P1275(0x244, 0, "wxjoin", wxjoin); + P1275(0x245, 0, "x,", xcomma); + P1275(0x246, 0, "x@", xfetch); + P1275(0x247, 0, "x!", xstore); + P1275(0x248, 0, "/x", slash_x); + P1275(0x249, 0, "/x*", slash_x_times); + P1275(0x24a, 0, "xa+", xa_plus); + P1275(0x24b, 0, "xa1+", xa_one_plus); + P1275(0x24c, 0, "xbflip", xbflip); + P1275(0x24d, 0, "xbflips", xbflips); + P1275(0x24e, 0, "xbsplit", xbsplit); + P1275(0x24f, 0, "xlflip", xlflip); + P1275(0x250, 0, "xlflips", xlflips); + P1275(0x251, 0, "xlsplit", xlsplit); + P1275(0x252, 0, "xwflip", xwflip); + P1275(0x253, 0, "xwflips", xwflips); + P1275(0x254, 0, "xwsplit", xwsplit); + + FORTH(0, "unaligned-x@", unaligned_xfetch); + FORTH(0, "unaligned-x!", unaligned_xstore); +} diff --git a/usr/src/lib/efcode/engine/print.c b/usr/src/lib/efcode/engine/print.c new file mode 100644 index 0000000000..0db6d6bf49 --- /dev/null +++ b/usr/src/lib/efcode/engine/print.c @@ -0,0 +1,265 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcode/private.h> + +#define DIGIT(x) (((x) > 9) ? ((x) + 'a' - 10) : ((x) + '0')) + +void +to_digit(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, ">digit"); + TOS = DIGIT(TOS); +} + +void +pic_hold(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "hold"); + *(--env->picturebufpos) = (char) POP(DS); +} + +void +pic_start(fcode_env_t *env) +{ + env->picturebufpos = env->picturebuf + env->picturebuflen - 1; + *env->picturebufpos = 0; +} + +void +pic_ustop(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "u#>"); + (void) POP(DS); + push_string(env, env->picturebufpos, strlen(env->picturebufpos)); +} + +void +pic_unsigned(fcode_env_t *env) +{ + ufstack_t a, b; + + CHECK_DEPTH(env, 1, "u#"); + a = (ufstack_t) TOS; + b = a % env->num_base; + TOS = (fstack_t) (a / env->num_base); + *(--env->picturebufpos) = DIGIT(b); +} + +void +pic_sign(fcode_env_t *env) +{ + fstack_t s; + + CHECK_DEPTH(env, 1, "sign"); + s = POP(DS); + if (s < 0) { + PUSH(DS, '-'); + pic_hold(env); + } +} + +static void +pic_uremainder(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "u#s"); + do { + pic_unsigned(env); + } while (TOS); +} + +void +format_number(fcode_env_t *env, int neg, int width) +{ + pic_start(env); + if (width == 0) { + PUSH(DS, ' '); + pic_hold(env); + } + pic_uremainder(env); + if (env->num_base == 10 && neg) { + PUSH(DS, '-'); + pic_hold(env); + } + width -= strlen(env->picturebufpos); + while (width > 0) { + PUSH(DS, ' '); + pic_hold(env); + width--; + } + pic_ustop(env); +} + +static void +convert_num(fcode_env_t *env) +{ + int n; + + CHECK_DEPTH(env, 1, "(.)"); + n = 0; + if (env->num_base == 10 && TOS < 0) { + TOS = -TOS; + n = 1; + } + format_number(env, n, 0); +} + +void +do_dot_r(fcode_env_t *env) +{ + int w, n; + + CHECK_DEPTH(env, 2, ".r"); + n = 0; + w = (int) POP(DS); + if (env->num_base == 10 && TOS < 0) { + TOS = -TOS; + n = 1; + } + format_number(env, n, w); + type(env); +} + +void +do_udot_r(fcode_env_t *env) +{ + int w; + + CHECK_DEPTH(env, 2, "u.r"); + w = (int) POP(DS); + format_number(env, 0, w); + type(env); +} + +void +do_dot(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "."); + PUSH(DS, 0); + do_dot_r(env); +} + +void +do_dot_d(fcode_env_t *env) +{ + int base; + + CHECK_DEPTH(env, 1, ".d"); + base = env->num_base; + env->num_base = 10; + do_dot(env); + env->num_base = base; +} + +void +do_dot_x(fcode_env_t *env) +{ + int base; + + CHECK_DEPTH(env, 1, ".x"); + base = env->num_base; + env->num_base = 16; + do_dot(env); + env->num_base = base; +} + +void +do_udot(fcode_env_t *env) +{ + CHECK_DEPTH(env, 1, "u."); + PUSH(DS, 0); + do_udot_r(env); +} + +void +pic_dunsigned(fcode_env_t *env) +{ + ufstack_t b; + u_dforth_t a; + + CHECK_DEPTH(env, 2, "#"); + a = pop_double(env); + b = a % env->num_base; + a /= env->num_base; + push_double(env, a); + *(--env->picturebufpos) = DIGIT(b); +} + +void +pic_dremainder(fcode_env_t *env) +{ + CHECK_DEPTH(env, 2, "#s"); + do { + pic_dunsigned(env); + } while (peek_double(env)); +} + +void +pic_dstop(fcode_env_t *env) +{ + CHECK_DEPTH(env, 2, "#>"); + (void) pop_double(env); + push_string(env, env->picturebufpos, strlen(env->picturebufpos)); +} + + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + ASSERT(env); + NOTICE; + + env->picturebuflen = 0x100; + env->picturebuf = MALLOC(env->picturebuflen); + + ANSI(0x095, 0, "hold", pic_hold); + ANSI(0x096, 0, "<#", pic_start); + ANSI(0x097, 0, "u#>", pic_ustop); + ANSI(0x098, 0, "sign", pic_sign); + ANSI(0x099, 0, "u#", pic_unsigned); + ANSI(0x09a, 0, "u#s", pic_uremainder); + ANSI(0x09b, 0, "u.", do_udot); + P1275(0x09c, 0, "u.r", do_udot_r); + P1275(0x09d, 0, ".", do_dot); + ANSI(0x09e, 0, ".r", do_dot_r); + + ANSI(0x0c7, 0, "#", pic_dunsigned); + ANSI(0x0c8, 0, "#s", pic_dremainder); + ANSI(0x0c9, 0, "#>", pic_dstop); + + FORTH(0, ">digit", to_digit); + FORTH(0, "(.)", convert_num); + FORTH(0, ".d", do_dot_d); + FORTH(0, ".x", do_dot_x); +} diff --git a/usr/src/lib/efcode/engine/properties.c b/usr/src/lib/efcode/engine/properties.c new file mode 100644 index 0000000000..ff14c1f03c --- /dev/null +++ b/usr/src/lib/efcode/engine/properties.c @@ -0,0 +1,808 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2000 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +void +create_prop(fcode_env_t *env, char *name) +{ + push_a_string(env, name); + property(env); +} + +void +create_int_prop(fcode_env_t *env, char *name, int val) +{ + PUSH(DS, val); + encode_int(env); + create_prop(env, name); +} + +void +create_string_prop(fcode_env_t *env, char *name, char *val) +{ + push_a_string(env, val); + encode_string(env); + create_prop(env, name); +} + +static int +addr_cmp(void *a, void *b) +{ + return ((uchar_t *)a == (uchar_t *)b); +} + +static void * +add_property_buffer(fcode_env_t *env, int len) +{ + void *data = MALLOC(len+1); + return (add_resource(&env->propbufs, data, addr_cmp)); +} + +static void +free_property_buffer(fcode_env_t *env, void *buffer) +{ + free_resource(&env->propbufs, buffer, addr_cmp); + FREE(buffer); +} + +/* + * Golden Rule: + * DO NOT cache the value of the head of the property list *before* + * looking up a property. + * This routine is also responsible for purging dead properties + * and that *can* affect the head pointer. + * you have been warned! + */ +prop_t * +find_property(device_t *d, char *name) +{ + prop_t *p = d->properties, *prev; + prop_t *found = NULL; + + prev = NULL; + while (p && !found) { + if (p->name) { + if (strcmp(name, p->name) == 0) { + found = p; + } + prev = p; + p = p->next; + } else { + prop_t *dead; + + if (prev) + prev->next = p->next; + else { + /* last prop in chain */ + d->properties = p->next; + } + dead = p; + p = p->next; + FREE(dead->name); + FREE(dead->data); + FREE(dead); + } + } + return (found); +} + +static prop_t * +stack_find_property(fcode_env_t *env, device_t *d) +{ + char *propname; + + propname = pop_a_string(env, NULL); + return (find_property(d, propname)); +} + +void +property(fcode_env_t *env) +{ + int datalen; + char *propname, *srcptr; + prop_t *p; + device_t *d; + + CHECK_DEPTH(env, 4, "property"); + if (MYSELF) { + d = MYSELF->device; + } else { + d = env->current_device; + if (!d) { + void *buffer; + + two_drop(env); + if ((buffer = pop_a_string(env, NULL)) != NULL) + free_property_buffer(env, buffer); + return; + } + } + propname = pop_a_string(env, NULL); + p = find_property(d, propname); + if (p == NULL) { + p = MALLOC(sizeof (prop_t)); + p->next = d->properties; + d->properties = p; + p->name = STRDUP(propname); + } else if (p->data) + FREE(p->data); /* release old resources */ + srcptr = pop_a_string(env, &datalen); + p->data = MALLOC(datalen+1); + p->size = datalen; + memcpy(p->data, srcptr, datalen); + p->data[datalen] = 0; + if (srcptr) + free_property_buffer(env, srcptr); +} + +prop_t * +lookup_package_property(fcode_env_t *env, char *propname, device_t *d) +{ + prop_t *p; + + p = find_property(d, propname); + if (p) { + return (p); + } + if (d->vectors.get_package_prop) { + static prop_t sp; + fstack_t fail, n; + + /* recreate the FORTH environment for the remote call */ + push_a_string(env, propname); + REVERT_PHANDLE(env, n, d); + PUSH(DS, n); + d->vectors.get_package_prop(env); + fail = POP(DS); + if (fail) + return (NULL); + sp.size = POP(DS); + sp.data = (uchar_t *)POP(DS); + sp.name = propname; + sp.next = NULL; + return (&sp); + } + return (NULL); +} + +void +get_package_property(fcode_env_t *env) +{ + prop_t *p; + device_t *d; + char *propname; + + CHECK_DEPTH(env, 3, "get-package-property"); + CONVERT_PHANDLE(env, d, POP(DS)); + propname = pop_a_string(env, NULL); + p = lookup_package_property(env, propname, d); + if (p) { + PUSH(DS, (fstack_t)p->data); + PUSH(DS, p->size); + PUSH(DS, FALSE); + } else + PUSH(DS, TRUE); +} + +void +get_inherited_prop(fcode_env_t *env) +{ + instance_t *ih; + device_t *dev; + prop_t *prop; + char *pname; + int plen; + + /* + * First, we look thru the in-memory device tree for the property. + * If we don't find it, we call get_inherited_prop, which "knows" it's + * not going to find the property below the attachment point. + */ + + CHECK_DEPTH(env, 2, "get-inherited-property"); + pname = pop_a_string(env, &plen); + ih = MYSELF; + if (ih) { + for (; ih; ih = ih->parent) { + dev = ih->device; + prop = find_property(dev, pname); + if (prop) { + PUSH(DS, (fstack_t)prop->data); + PUSH(DS, (fstack_t)prop->size); + PUSH(DS, FALSE); + return; + } + } + if (dev->vectors.get_inherited_prop) { + push_a_string(env, pname); + dev->vectors.get_inherited_prop(env); + return; + } + } + PUSH(DS, TRUE); +} + +void +delete_property(fcode_env_t *env) +{ + CHECK_DEPTH(env, 2, "delete-property"); + if (MYSELF) { + prop_t *p; + + p = stack_find_property(env, MYSELF->device); + if (p) { + /* + * write the name as NULL; the space will be free'd + * the next time a property lookup passes this node + */ + p->name = NULL; + } + } else { + two_drop(env); + } +} + +void +get_my_property(fcode_env_t *env) +{ + CHECK_DEPTH(env, 2, "get-my-property"); + PUSH(DS, (fstack_t)MYSELF); + ihandle_to_phandle(env); + get_package_property(env); +} + +void +encode_string(fcode_env_t *env) +{ + char *str; + char *prop; + int len; + + CHECK_DEPTH(env, 2, "encode-string"); + str = pop_a_string(env, &len); + + prop = add_property_buffer(env, len); + memcpy(prop, str, len); + prop[len] = 0; + PUSH(DS, (fstack_t)prop); + PUSH(DS, len + 1); +} + +void +encode_int(fcode_env_t *env) +{ + uchar_t *ptr; + uint32_t p; + + CHECK_DEPTH(env, 1, "encode-int"); + p = POP(DS); + ptr = add_property_buffer(env, sizeof (uint32_t)); + + memcpy(ptr, (char *)&p, sizeof (uint32_t)); + PUSH(DS, (fstack_t)ptr); + PUSH(DS, sizeof (uint32_t)); +} + +void +encode_phys(fcode_env_t *env) +{ + uint_t ncells; + + ncells = get_number_of_parent_address_cells(env); + CHECK_DEPTH(env, ncells, "encode-phys"); + encode_int(env); + while (--ncells) { + rot(env); + encode_int(env); + encode_plus(env); + } +} + +static fstack_t +get_decoded_int(uchar_t *dp) +{ + uint32_t d; + + memcpy((char *)&d, dp, sizeof (uint32_t)); + return (d); +} + +int +get_default_intprop(fcode_env_t *env, char *name, device_t *d, int def) +{ + prop_t *p; + + if (!d) /* Kludge for testing */ + return (def); + p = lookup_package_property(env, name, d); + if (p == NULL) + return (def); + return (get_decoded_int(p->data)); +} + +int +get_num_addr_cells(fcode_env_t *env, device_t *d) +{ + return (get_default_intprop(env, "#address-cells", d, 2)); +} + +int +get_num_size_cells(fcode_env_t *env, device_t *d) +{ + return (get_default_intprop(env, "#size-cells", d, 1)); +} + +void +decode_phys(fcode_env_t *env) +{ + char *ptr; + int len; + int adr_cells; + int offset; + + CHECK_DEPTH(env, 2, "decode-phys"); + ptr = pop_a_string(env, &len); + + adr_cells = get_num_addr_cells(env, env->current_device->parent); + + offset = sizeof (uint32_t) * adr_cells; + + PUSH(DS, (fstack_t)(ptr + offset)); + PUSH(DS, len + offset); + + while (adr_cells--) { + fstack_t d; + offset -= sizeof (uint32_t); + d = get_decoded_int((uchar_t *)(ptr + offset)); + PUSH(DS, d); + } +} + +/* + * 'reg' Fcode 0x116 + */ +void +reg_prop(fcode_env_t *env) +{ + fstack_t size; + + CHECK_DEPTH(env, 1, "reg"); + size = POP(DS); + encode_phys(env); + PUSH(DS, size); + encode_int(env); + encode_plus(env); + create_prop(env, "reg"); +} + +void +encode_bytes(fcode_env_t *env) +{ + char *str; + char *prop; + int len; + + CHECK_DEPTH(env, 2, "encode-bytes"); + str = pop_a_string(env, &len); + prop = add_property_buffer(env, len); + memcpy(prop, str, len); + prop[len] = 0; + PUSH(DS, (fstack_t)prop); + PUSH(DS, len); +} + +void +decode_int(fcode_env_t *env) +{ + char *dp; + fstack_t d; + int len; + + CHECK_DEPTH(env, 2, "decode-int"); + dp = pop_a_string(env, &len); + PUSH(DS, (fstack_t)(dp + sizeof (uint32_t))); + PUSH(DS, len - sizeof (uint32_t)); + d = get_decoded_int((uchar_t *)dp); + PUSH(DS, d); +} + +void +decode_string(fcode_env_t *env) +{ + int plen, len; + char *dp; + + CHECK_DEPTH(env, 2, "decode-string"); + dp = pop_a_string(env, &plen); + len = strlen(dp) + 1; + PUSH(DS, (fstack_t)(dp + len)); + PUSH(DS, plen - len); + PUSH(DS, (fstack_t)dp); + PUSH(DS, len - 1); +} + +void +encode_plus(fcode_env_t *env) +{ + int len1, len2; + char *src1, *src2; + uchar_t *new; + + CHECK_DEPTH(env, 4, "encode+"); + src1 = pop_a_string(env, &len1); + src2 = pop_a_string(env, &len2); + new = add_property_buffer(env, len1 + len2); + if (src2) { + memcpy(new, src2, len2); + free_property_buffer(env, src2); + } + if (src1) { + memcpy(new + len2, src1, len1); + free_property_buffer(env, src1); + } + PUSH(DS, (fstack_t)new); + PUSH(DS, len1 + len2); +} + +static void +make_special_property(fcode_env_t *env, char *name) +{ + push_a_string(env, name); + property(env); +} + +void +device_name(fcode_env_t *env) +{ + CHECK_DEPTH(env, 2, "device-name"); + encode_string(env); + make_special_property(env, "name"); +} + +void +model_prop(fcode_env_t *env) +{ + CHECK_DEPTH(env, 2, "model"); + encode_string(env); + make_special_property(env, "model"); +} + +void +device_type(fcode_env_t *env) +{ + CHECK_DEPTH(env, 2, "device-type"); + encode_string(env); + make_special_property(env, "device_type"); +} + +/* + * 'next-property' Fcode implementation. + */ +void +next_property(fcode_env_t *env) +{ + device_t *phandle; + char *previous; + prop_t *p; + + CHECK_DEPTH(env, 3, "next-property"); + phandle = (device_t *)POP(DS); + previous = pop_a_string(env, NULL); + p = phandle->properties; + if (previous == NULL) + p = phandle->properties; + else if (p = find_property(phandle, previous)) + p = p->next; + + for (; p != NULL && p->name == NULL; p = p->next) + ; + + if (p) + push_a_string(env, p->name); + else + push_a_string(env, ""); + PUSH(DS, TRUE); +} + +void +get_property(fcode_env_t *env) +{ + if (MYSELF) + get_my_property(env); + else if (env->current_device) { + fstack_t d; + + REVERT_PHANDLE(env, d, env->current_device); + PUSH(DS, d); + get_package_property(env); + } else { + two_drop(env); + log_message(MSG_WARN, "No device context\n"); + } +} + +#ifdef DEBUG + +static void +print_indented(char *name) +{ + log_message(MSG_INFO, "%-28s", name); +} + +static void +print_string(fcode_env_t *env, uchar_t *data, int len) +{ + while (len > 0) { + int nlen = (strlen((char *)data)+1); + log_message(MSG_INFO, "%s\n", data); + len -= nlen; + data += nlen; + if (len > 0) + print_indented(""); + } +} + +static void +print_ints(uchar_t *data, int len, int crlf) +{ + uint32_t d; + + while (len--) { + d = get_decoded_int(data); + log_message(MSG_INFO, "%8.8lx ", d); + data += sizeof (uint32_t); + } + if (crlf) + log_message(MSG_INFO, "\n"); +} + +static void +print_integer(fcode_env_t *env, uchar_t *data, int len) +{ + print_ints(data, len/sizeof (uint32_t), 1); +} + +static void +print_bytes(fcode_env_t *env, uchar_t *data, int len) +{ + while (len--) { + log_message(MSG_INFO, "%2.2x ", *data++); + } + log_message(MSG_INFO, "\n"); +} + +static void +print_bytes_indented(fcode_env_t *env, uchar_t *data, int len) +{ + int nbytes; + + for (; ; ) { + nbytes = min(len, 16); + print_bytes(env, data, nbytes); + len -= nbytes; + data += nbytes; + if (len == 0) + break; + print_indented(""); + } +} + +static void +print_reg(fcode_env_t *env, uchar_t *data, int len) +{ + int pcells, nlen; + + if (env->current_device != NULL && + env->current_device->parent != NULL) { + pcells = get_num_size_cells(env, env->current_device->parent); + pcells += get_num_addr_cells(env, env->current_device->parent); + nlen = pcells*sizeof (uint32_t); + while (len > 0) { + print_ints(data, pcells, 1); + len -= nlen; + data += nlen; + if (len > 0) + print_indented(""); + } + } else + print_bytes_indented(env, data, len); +} + +static void +print_imap(fcode_env_t *env, uchar_t *dp, int len) +{ + int n, icells; + + if (env->current_device == NULL) { + print_bytes_indented(env, dp, len); + return; + } + n = get_num_addr_cells(env, env->current_device); + + while (len) { + int offset; + fstack_t data; + device_t *node; + + offset = 0; + data = get_decoded_int(dp+((n+1)*sizeof (uint32_t))); + CONVERT_PHANDLE(env, node, data); + offset += (n+2)*sizeof (uint32_t); + print_ints(dp, (n+2), 0); + icells = get_default_intprop(env, "#interrupt-cells", node, 1); + print_ints(dp+offset, icells, 1); + offset += icells*sizeof (uint32_t); + dp += offset; + len -= offset; + if (len) + print_indented(""); + } +} + +static void +print_ranges(fcode_env_t *env, uchar_t *data, int len) +{ + int pcells, nlen; + + if (env->current_device != NULL && + env->current_device->parent != NULL) { + pcells = get_num_addr_cells(env, env->current_device); + pcells += get_num_addr_cells(env, env->current_device->parent); + pcells += get_num_size_cells(env, env->current_device); + nlen = pcells*sizeof (uint32_t); + while (len > 0) { + print_ints(data, pcells, 1); + len -= nlen; + data += nlen; + if (len > 0) + print_indented(""); + } + } else + print_bytes_indented(env, data, len); +} + +typedef struct MAGIC_PROP { + char *name; + void (*fn)(fcode_env_t *env, uchar_t *data, int len); +} magic_prop_t; + +static magic_prop_t magic_props[] = { + { "name", print_string }, + { "device_type", print_string }, + { "model", print_string }, + { "reg", print_reg }, + { "assigned-addresses", print_reg }, + { "interrupt-map", print_imap }, + { "#interrupt-cells", print_integer }, + { "interrupt-map-mask", print_integer }, + { "#size-cells", print_integer }, + { "#address-cells", print_integer }, + { "ranges", print_ranges }, + { "device-id", print_integer }, + { "vendor-id", print_integer }, + { "class-code", print_integer }, + { "compatible", print_string }, + { "version", print_string }, + { "manufacturer", print_string }, + { NULL, NULL } +}; + +static void +print_content(fcode_env_t *env, char *prop, uchar_t *data, int len) +{ + magic_prop_t *p; + + for (p = magic_props; p->name; p++) + if (strcmp(prop, p->name) == 0) { + (*p->fn)(env, data, len); + return; + } + print_bytes_indented(env, data, len); +} + +void +print_property(fcode_env_t *env, prop_t *p, char *prepend) +{ + char buf[40]; + char *name = (p->name ? p->name : "<noname>"); + + if (prepend) { + sprintf(buf, "%s %s", prepend, name); + name = buf; + } + print_indented(name); + if (p->name) + print_content(env, p->name, p->data, p->size); + else + print_bytes_indented(env, p->data, p->size); +} + +void +dot_properties(fcode_env_t *env) +{ + prop_t *p; + instance_t *omyself; + + omyself = MYSELF; + MYSELF = NULL; + + if (env->current_device) { + for (p = env->current_device->properties; p; p = p->next) + print_property(env, p, NULL); + } else { + log_message(MSG_INFO, "No device context\n"); + } + MYSELF = omyself; +} + +#endif + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + ASSERT(env); + NOTICE; + + P1275(0x110, 0, "property", property); + P1275(0x111, 0, "encode-int", encode_int); + P1275(0x112, 0, "encode+", encode_plus); + P1275(0x113, 0, "encode-phys", encode_phys); + P1275(0x114, 0, "encode-string", encode_string); + P1275(0x115, 0, "encode-bytes", encode_bytes); + P1275(0x116, 0, "reg", reg_prop); + FCODE(0x117, 0, "intr", fc_obsolete); + FCODE(0x118, 0, "driver", fc_historical); + P1275(0x119, 0, "model", model_prop); + P1275(0x11a, 0, "device-type", device_type); + + P1275(0x128, 0, "decode-phys", decode_phys); + + P1275(0x201, 0, "device-name", device_name); + + P1275(0x21a, 0, "get-my-property", get_my_property); + P1275(0x21b, 0, "decode-int", decode_int); + P1275(0x21c, 0, "decode-string", decode_string); + P1275(0x21d, 0, "get-inherited-property", get_inherited_prop); + P1275(0x21e, 0, "delete-property", delete_property); + P1275(0x21f, 0, "get-package-property", get_package_property); + + P1275(0x23d, 0, "next-property", next_property); + + FORTH(0, "get-property", get_property); + FORTH(0, ".properties", dot_properties); +} diff --git a/usr/src/lib/efcode/engine/resource.c b/usr/src/lib/efcode/engine/resource.c new file mode 100644 index 0000000000..5ede6eea74 --- /dev/null +++ b/usr/src/lib/efcode/engine/resource.c @@ -0,0 +1,134 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +fc_resource_t * +find_resource(fc_resource_t **head, void *ptr, int (cmp)(void *, void *)) +{ + fc_resource_t *f, *prev, *r = *head; + + f = NULL; + prev = NULL; + while (r) { + if (r->data == NULL) { + fc_resource_t *dead; + + if (prev) + prev->next = r->next; + else { + *head = r->next; + } + dead = r; + r = r->next; + FREE(dead); + } else { + if (cmp(ptr, r->data)) { + f = r; + break; + } + prev = r; + r = r->next; + } + } + return (f); +} + +void * +add_resource(fc_resource_t **head, void *ptr, int (cmp)(void *, void *)) +{ + fc_resource_t *r; + + r = find_resource(head, ptr, cmp); + if (r == NULL) { + r = MALLOC(sizeof (fc_resource_t)); + r->data = ptr; + r->next = *head; + *head = r; + return (r->data); + } + log_message(MSG_ERROR, "add_resource: Duplicate entry: %p\n", ptr); + return (NULL); +} + +void +free_resource(fc_resource_t **head, void *ptr, int (cmp)(void *, void *)) +{ + fc_resource_t *r; + + if ((r = find_resource(head, ptr, cmp)) != NULL) + r->data = NULL; + else + log_message(MSG_ERROR, "free_resource: No such Entry: %p\n", + ptr); +} + +#ifdef DEBUG + +static int +dump_print(void *s, void *d) +{ + log_message(MSG_DEBUG, "Buffer: %p\n", d); + return (0); +} + +void +dump_resources(fcode_env_t *env) +{ + fc_resource_t **head; + + head = (fc_resource_t **) POP(DS); + (void) find_resource(head, NULL, dump_print); +} + +void +propbufs(fcode_env_t *env) +{ + PUSH(DS, (fstack_t) &env->propbufs); +} + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + NOTICE; + ASSERT(env); + + FORTH(0, "propbufs", propbufs); + FORTH(0, "dump-resource", dump_resources); +} + +#endif diff --git a/usr/src/lib/efcode/engine/signal.c b/usr/src/lib/efcode/engine/signal.c new file mode 100644 index 0000000000..a023bfd857 --- /dev/null +++ b/usr/src/lib/efcode/engine/signal.c @@ -0,0 +1,91 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> + +#include <sys/time.h> +#include <sys/termio.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +static fcode_env_t *saved_envp; +static struct termio saved_termio; + +static void +process_signal(int sig, siginfo_t *sip, void *addr) +{ + /* + * Format appropriate error message, want fault addr if Bus Error + * or Segmentation Violation. + */ + switch (sig) { + case SIGSEGV: + case SIGBUS: + case SIGILL: + case SIGFPE: + forth_abort(saved_envp, "%s: Fault Addr: 0x%08x", + strsignal(sig), sip->si_addr); + + case SIGQUIT: + ioctl(fileno(stdin), TCSETA, &saved_termio); + log_message(MSG_FATAL, "SIGQUIT\n"); + abort(); + + case SIGINT: + ioctl(fileno(stdin), TCSETA, &saved_termio); + break; + } + forth_abort(saved_envp, strsignal(sig)); +} + +void +install_handlers(fcode_env_t *env) +{ + struct sigaction sa; + + saved_envp = env; + + ioctl(fileno(stdin), TCGETA, &saved_termio); + + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO|SA_NODEFER; + sa.sa_handler = 0; + sa.sa_sigaction = process_signal; + + sigaction(SIGINT, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sigaction(SIGSEGV, &sa, NULL); + sigaction(SIGBUS, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGFPE, &sa, NULL); +} diff --git a/usr/src/lib/efcode/engine/sparcv9/Makefile b/usr/src/lib/efcode/engine/sparcv9/Makefile new file mode 100644 index 0000000000..af568ee0b3 --- /dev/null +++ b/usr/src/lib/efcode/engine/sparcv9/Makefile @@ -0,0 +1,34 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include $(SRC)/lib/Makefile.lib.64 + +sparcv9_C_PICFLAGS = -KPIC + +install: all $(ROOTLIBS64) diff --git a/usr/src/lib/efcode/engine/tracing.c b/usr/src/lib/efcode/engine/tracing.c new file mode 100644 index 0000000000..43ade86faa --- /dev/null +++ b/usr/src/lib/efcode/engine/tracing.c @@ -0,0 +1,223 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <dlfcn.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +#ifdef DEBUG + +static void (*trace_fn)(fcode_env_t *); + +void +set_tracer(fcode_env_t *env, void (*tracer)(fcode_env_t *)) +{ + trace_fn = tracer; +} + +void +set_level(long lvl) +{ + long debug; + + debug = get_interpreter_debug_level(); + set_interpreter_debug_level(debug | lvl); +} + +void +unset_level(long lvl) +{ + long debug; + + debug = get_interpreter_debug_level(); + set_interpreter_debug_level(debug & ~lvl); +} + +void +enable_trace(fcode_env_t *env) +{ + set_level(DEBUG_TRACING); +} + +void +enable_stack_trace(fcode_env_t *env) +{ + set_level(DEBUG_TRACE_STACK); +} + +void +disable_stack_trace(fcode_env_t *env) +{ + unset_level(DEBUG_TRACE_STACK); +} + +void +disable_trace(fcode_env_t *env) +{ + unset_level(DEBUG_TRACING); +} + +void +call_trace(fcode_env_t *env) +{ + set_level(DEBUG_CALL_METHOD); +} + +void +no_call_trace(fcode_env_t *env) +{ + unset_level(DEBUG_CALL_METHOD); +} + +void +do_fclib_trace(fcode_env_t *env, void *fn) +{ + void *address; + Dl_info dlip; + static char buf[80]; + + if (dladdr((void *) fn, &dlip)) { + int offset; + + address = dlsym(RTLD_DEFAULT, dlip.dli_sname); + offset = ((char *) fn) - ((char *) address); + if (offset == 0) { + log_message(MSG_FC_DEBUG, "%s: tracing %s()\n", + dlip.dli_fname, dlip.dli_sname); + } else { + log_message(MSG_FC_DEBUG, "%s: tracing %s%s0x%x()\n", + dlip.dli_fname, dlip.dli_sname, + ((offset < 0) ? "-" : "+"), + ((offset < 0) ? -offset : offset)); + } + } else { + log_message(MSG_FC_DEBUG, "do_fclib_trace: <Unknown> %p\n", fn); + } + if (trace_fn) + trace_fn(env); +} + +void +output_step_message(fcode_env_t *env) +{ + log_message(MSG_INFO, "Step keys: <space>, Continue, Forth, Go," + " Help, Step, Quit\n"); +} + +void +enable_step(fcode_env_t *env) +{ + output_step_message(env); + set_level(DEBUG_STEPPING); +} + + +void +disable_step(fcode_env_t *env) +{ + unset_level(DEBUG_STEPPING); +} + +/* + * Output of state info is done elsewhere + */ +int +do_fclib_step(fcode_env_t *env) +{ + int c; + fcode_env_t *new_env; + + for (; ; ) { + c = getchar(); + if (c != '\n') { + while (getchar() != '\n') + ; + } + switch (c) { + case EOF: + case 'q': + unbug(env); + IP = 0; + return (1); + + case 'c': + debug_set_level(env, + DEBUG_EXEC_TRACE|DEBUG_EXEC_DUMP_DS); + break; + + case 'g': + unbug(env); + break; + + case 'f': + unset_level(DEBUG_STEPPING); + new_env = clone_environment(env, NULL); + do_interact(new_env); + destroy_environment(new_env); + set_level(DEBUG_STEPPING); + continue; + + case ' ': + case '\n': + break; + + case 'd': /* Unimplemented */ + case 'u': /* Unimplemented */ + default: + output_step_message(env); + continue; + } + break; + } + return (0); +} + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + ASSERT(env); + NOTICE; + + + FORTH(0, "stack-trace", enable_stack_trace); + FORTH(0, "no-stack-trace", disable_stack_trace); + FORTH(0, "trace-on", enable_trace); + FORTH(0, "trace-off", disable_trace); + FORTH(0, "call-trace", call_trace); + FORTH(0, "no-call-trace", no_call_trace); + FORTH(0, "step-on", enable_step); + FORTH(0, "step-off", disable_step); +} + +#endif |
