summaryrefslogtreecommitdiff
path: root/usr/src/lib/efcode/engine
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/efcode/engine
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/efcode/engine')
-rw-r--r--usr/src/lib/efcode/engine/Makefile29
-rw-r--r--usr/src/lib/efcode/engine/Makefile.com38
-rw-r--r--usr/src/lib/efcode/engine/actions.c399
-rw-r--r--usr/src/lib/efcode/engine/alarm.c101
-rw-r--r--usr/src/lib/efcode/engine/cleanup.c52
-rw-r--r--usr/src/lib/efcode/engine/debug.c1601
-rw-r--r--usr/src/lib/efcode/engine/env.c863
-rw-r--r--usr/src/lib/efcode/engine/extend.c147
-rw-r--r--usr/src/lib/efcode/engine/fb8.c54
-rw-r--r--usr/src/lib/efcode/engine/fcode.c1031
-rw-r--r--usr/src/lib/efcode/engine/font.c48
-rw-r--r--usr/src/lib/efcode/engine/forth.c2675
-rw-r--r--usr/src/lib/efcode/engine/framebuffer.c71
-rw-r--r--usr/src/lib/efcode/engine/init.c139
-rw-r--r--usr/src/lib/efcode/engine/instance.c117
-rw-r--r--usr/src/lib/efcode/engine/interactive.c808
-rw-r--r--usr/src/lib/efcode/engine/interface.c273
-rw-r--r--usr/src/lib/efcode/engine/interp.c121
-rw-r--r--usr/src/lib/efcode/engine/log.c361
-rw-r--r--usr/src/lib/efcode/engine/mcookie.c237
-rw-r--r--usr/src/lib/efcode/engine/package.c1077
-rw-r--r--usr/src/lib/efcode/engine/prims64.c464
-rw-r--r--usr/src/lib/efcode/engine/print.c265
-rw-r--r--usr/src/lib/efcode/engine/properties.c808
-rw-r--r--usr/src/lib/efcode/engine/resource.c134
-rw-r--r--usr/src/lib/efcode/engine/signal.c91
-rw-r--r--usr/src/lib/efcode/engine/sparcv9/Makefile34
-rw-r--r--usr/src/lib/efcode/engine/tracing.c223
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)(&quote_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(&quote_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(&quote_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