summaryrefslogtreecommitdiff
path: root/usr.sbin/gspa
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /usr.sbin/gspa
initial import of NetBSD tree
Diffstat (limited to 'usr.sbin/gspa')
-rw-r--r--usr.sbin/gspa/Makefile3
-rw-r--r--usr.sbin/gspa/Makefile.inc4
-rw-r--r--usr.sbin/gspa/gspa/Makefile12
-rw-r--r--usr.sbin/gspa/gspa/gsp_act.c204
-rw-r--r--usr.sbin/gspa/gspa/gsp_ass.h180
-rw-r--r--usr.sbin/gspa/gspa/gsp_code.h41
-rw-r--r--usr.sbin/gspa/gspa/gsp_eval.c138
-rw-r--r--usr.sbin/gspa/gspa/gsp_gram.y122
-rw-r--r--usr.sbin/gspa/gspa/gsp_inst.c748
-rw-r--r--usr.sbin/gspa/gspa/gsp_lex.c183
-rw-r--r--usr.sbin/gspa/gspa/gsp_out.c182
-rw-r--r--usr.sbin/gspa/gspa/gsp_pseu.c148
-rw-r--r--usr.sbin/gspa/gspa/gsp_sym.c192
-rw-r--r--usr.sbin/gspa/gspa/gspa.c273
-rw-r--r--usr.sbin/gspa/gspahextoc/Makefile6
-rw-r--r--usr.sbin/gspa/gspahextoc/README19
-rw-r--r--usr.sbin/gspa/gspahextoc/gspahextoc.l123
17 files changed, 2578 insertions, 0 deletions
diff --git a/usr.sbin/gspa/Makefile b/usr.sbin/gspa/Makefile
new file mode 100644
index 00000000000..95421eacf10
--- /dev/null
+++ b/usr.sbin/gspa/Makefile
@@ -0,0 +1,3 @@
+SUBDIR += gspa gspahextoc
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/gspa/Makefile.inc b/usr.sbin/gspa/Makefile.inc
new file mode 100644
index 00000000000..f2f379b4c11
--- /dev/null
+++ b/usr.sbin/gspa/Makefile.inc
@@ -0,0 +1,4 @@
+# from: @(#)Makefile.inc 5.1 (Berkeley) 5/11/90
+# $Id: Makefile.inc,v 1.1 1995/10/18 08:47:34 deraadt Exp $
+
+BINDIR?= /usr/sbin
diff --git a/usr.sbin/gspa/gspa/Makefile b/usr.sbin/gspa/gspa/Makefile
new file mode 100644
index 00000000000..d4cd1a01ac4
--- /dev/null
+++ b/usr.sbin/gspa/gspa/Makefile
@@ -0,0 +1,12 @@
+# $NetBSD: Makefile,v 1.1 1995/10/09 00:06:02 chopps Exp $
+
+PROG= gspa
+CFLAGS+=-I. -I${.CURDIR}
+HDRS= gsp_ass.h gsp_code.h
+SRCS= gspa.c gsp_out.c gsp_sym.c gsp_lex.c gsp_act.c gsp_eval.c \
+ gsp_inst.c gsp_pseu.c
+OBJS+= gsp_gram.o
+NOMAN= noman
+CLEANFILES= y.tab.h
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/gspa/gspa/gsp_act.c b/usr.sbin/gspa/gspa/gsp_act.c
new file mode 100644
index 00000000000..252ec79ae22
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_act.c
@@ -0,0 +1,204 @@
+/*
+ * GSP assembler - semantic actions
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "gsp_ass.h"
+
+void
+free_operands(operand l)
+{
+ register operand op, oq;
+
+ for( op = l; op != NULL; op = oq ){
+ oq = op->next;
+ if( op->type == EXPR || op->type == EA
+ && op->mode >= M_INDEX )
+ free_expr(op->op_u.value);
+ free(op);
+ }
+}
+
+operand
+add_operand(operand first, operand last)
+{
+ operand p;
+
+ for( p = first; p->next != NULL; p = p->next )
+ ;
+ p->next = last;
+ return first;
+}
+
+operand
+reg_op(int reg)
+{
+ register operand o;
+
+/* printf("reg_op reg=%d sign=%d\n", reg, sign); */
+ new(o);
+ o->type = REG;
+ o->reg_no = reg;
+ o->next = NULL;
+ return o;
+}
+
+operand
+expr_op(expr val)
+{
+ register operand o;
+
+/* printf("immed len=%d\n", len); */
+ new(o);
+ o->type = EXPR;
+ o->op_u.value = val;
+ o->next = NULL;
+ return o;
+}
+
+operand
+string_op(char *str)
+{
+ register operand o;
+
+/* printf("string_op str=%s\n", str); */
+ new(o);
+ o->type = STR_OPN;
+ o->op_u.string = str;
+ o->next = NULL;
+ return o;
+}
+
+operand
+abs_adr(expr adr)
+{
+ register operand o;
+
+/* printf("abs_adr len=%d\n", len); */
+ new(o);
+ o->type = EA;
+ o->mode = M_ABSOLUTE;
+ o->op_u.value = adr;
+ o->next = NULL;
+ return o;
+}
+
+operand
+reg_ind(int reg, int mode)
+{
+ register operand o;
+
+/* printf("reg_adr r1=%d r2=%d mode=%d\n", r1, r2, mode); */
+ new(o);
+ o->type = EA;
+ o->mode = mode;
+ o->reg_no = reg;
+ o->next = NULL;
+ return o;
+}
+
+operand
+reg_indxy(int reg, char *xy)
+{
+ register operand o;
+
+ ucasify(xy);
+ if( strcmp(xy, ".XY") != 0 )
+ perr("Register format must be .XY");
+ return reg_ind(reg, M_INDXY);
+}
+
+operand
+reg_index(int reg, expr disp)
+{
+ register operand o;
+
+ o = reg_ind(reg, M_INDEX);
+ o->op_u.value = disp;
+ return o;
+}
+
+expr
+id_expr(char *id)
+{
+ register expr x;
+
+/* printf("id_expr id=%s\n", id); */
+ new(x);
+ x->e_op = SYM;
+ x->e_sym = lookup(id, TRUE);
+ return x;
+}
+
+expr
+num_expr(int val)
+{
+ register expr x;
+
+/* printf("num_expr val=%d\n", val); */
+ new(x);
+ x->e_op = CONST;
+ x->e_val = val;
+ return x;
+}
+
+expr
+here_expr()
+{
+ register expr x;
+
+/* printf("here_expr()\n"); */
+ new(x);
+ x->e_op = '.';
+ return x;
+}
+
+expr
+bexpr(int op, expr l, expr r)
+{
+ register expr x;
+
+/* printf("bexpr op=%d\n", op); */
+ new(x);
+ x->e_op = op;
+ x->e_left = l;
+ x->e_right = r;
+ return x;
+}
+
+void
+free_expr(register expr x)
+{
+ if( x->e_op != SYM && x->e_op != CONST && x->e_op != '.' ){
+ free_expr(x->e_left);
+ if( x->e_right != NULL )
+ free_expr(x->e_right);
+ }
+ free(x);
+}
diff --git a/usr.sbin/gspa/gspa/gsp_ass.h b/usr.sbin/gspa/gspa/gsp_ass.h
new file mode 100644
index 00000000000..4201de43c94
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_ass.h
@@ -0,0 +1,180 @@
+/*
+ * GSP assembler - definitions
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <sys/types.h>
+/*#include <alloca.h>*/
+
+#define MAXLINE 133
+
+typedef char bool;
+#define TRUE 1
+#define FALSE 0
+
+#define YYDEBUG 1
+
+/* Structure for symbol in symbol table */
+typedef struct symbol {
+ int16_t flags;
+ int16_t ndefn;
+ unsigned value;
+ unsigned lineno;
+ struct symbol *next;
+ struct numlab *nlab;
+ char name[1];
+} *symbol;
+
+/* Values for flags */
+#define DEFINED 1
+#define SET_LABEL 2
+#define NUMERIC_LABEL 4
+
+#define NOT_YET 65535U /* line no. for `not defined yet' */
+
+/* Info about successive numeric labels */
+struct numlab {
+ unsigned value;
+ unsigned lineno;
+ struct numlab *next;
+};
+
+/* Structure for expressions */
+typedef struct expr {
+ int e_op;
+ union {
+ struct {
+ struct expr *left;
+ struct expr *right;
+ } e_s;
+ symbol sym;
+ int32_t val;
+ } e_u;
+} *expr;
+#define e_left e_u.e_s.left
+#define e_right e_u.e_s.right
+#define e_sym e_u.sym
+#define e_val e_u.val
+
+/* Operators other than '+', '-', etc. */
+#define SYM 1
+#define CONST 2
+#define NEG 3
+
+/* Structure for an operand */
+typedef struct operand {
+ char type;
+ char mode; /* EA mode */
+ int16_t reg_no;
+ union {
+ expr value;
+ char *string;
+ } op_u;
+ struct operand *next;
+} *operand;
+
+/* Values for operand type */
+#define REG 1 /* register operand */
+#define EXPR 2 /* expression operand */
+#define EA 4 /* effective address */
+#define STR_OPN 8 /* string operand */
+
+/* Addressing modes */
+/* NB codes for modes with an expression must be > other modes */
+#define M_REG 0 /* R */
+#define M_IND 1 /* *R */
+#define M_POSTINC 2 /* *R+ */
+#define M_PREDEC 3 /* *-R */
+#define M_INDXY 4 /* *R.XY (pixt only) */
+#define M_INDEX 5 /* *R(n) */
+#define M_ABSOLUTE 6 /* @adr */
+
+/* Register names */
+#define A0 0x20
+#define B0 0x50
+#define SP 0x6F /* (r1 & r2 & REGFILE) != 0 iff */
+#define REGFILE 0x60 /* r1 and r2 are in the same file */
+
+/* Prototypes */
+void statement(char *opcode, operand operands);
+void do_asg(char *, expr, int flags);
+void set_label(char *);
+void set_numeric_label(int);
+void reset_numeric_labels(void);
+operand reg_op(int reg);
+operand expr_op(expr);
+operand string_op(char *);
+operand abs_adr(expr);
+operand reg_ind(int, int);
+operand reg_indxy(int, char *);
+operand reg_index(int, expr);
+operand add_operand(operand, operand);
+expr id_expr(char *);
+expr num_expr(int);
+expr here_expr(void);
+expr bexpr(int, expr, expr);
+void free_operands(operand);
+void free_expr(expr);
+
+void perr(char *fmt, ...);
+void p1err(char *fmt, ...);
+int get_line(char *lp, int maxlen);
+char *alloc(size_t nbytes);
+
+symbol lookup(char *id, bool makeit);
+expr fold(expr);
+int eval_expr(expr, int32_t *, unsigned *);
+void pseudo(int code, operand operands);
+
+void putcode(u_int16_t *, int);
+
+extern unsigned pc;
+extern short pass2;
+
+extern int lineno;
+extern int err_count;
+extern char line[], *lineptr;
+
+#if defined(sparc) && !defined(__NetBSD__)
+#include <alloca.h>
+#else
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#endif
+#endif
+
+#ifndef BSD
+#ifndef amiga
+#define bcopy(s, d, l) memcpy(d, s, l)
+#endif
+#endif
+
+#define new(x) ((x) = (typeof (x)) alloc (sizeof(*(x))))
diff --git a/usr.sbin/gspa/gspa/gsp_code.h b/usr.sbin/gspa/gspa/gsp_code.h
new file mode 100644
index 00000000000..33719fa368b
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_code.h
@@ -0,0 +1,41 @@
+/*
+ * GSP assembler - codes for assembler directives
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*#define EQU 0*/
+#define ORG 1
+#define INCL 2
+#define WORD 3
+#define LONG 4
+#define BLKB 5
+#define BLKW 6
+#define BLKL 7
+#define START 8
diff --git a/usr.sbin/gspa/gspa/gsp_eval.c b/usr.sbin/gspa/gspa/gsp_eval.c
new file mode 100644
index 00000000000..bfc77f03ede
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_eval.c
@@ -0,0 +1,138 @@
+/*
+ * GSP assembler - expression evaluation
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "gsp_ass.h"
+#include "y.tab.h"
+
+int32_t eval_op(int, int32_t, int32_t);
+int32_t eval_subtree(expr, unsigned *);
+
+expr
+fold(register expr x)
+{
+ register int32_t l;
+ register expr lp, rp;
+
+ switch( x->e_op ){
+ case SYM:
+ case CONST:
+ case '.':
+ return x;
+ }
+ x->e_left = lp = fold(x->e_left);
+ if( x->e_right != NULL )
+ x->e_right = rp = fold(x->e_right);
+ else
+ rp = NULL;
+ if( lp->e_op == CONST && (rp == NULL || rp->e_op == CONST) ){
+ /* operator with constant subtree(s) */
+ if( rp != NULL ){
+ l = eval_op(x->e_op, lp->e_val, rp->e_val);
+ free(rp);
+ } else
+ l = eval_op(x->e_op, lp->e_val, 0);
+ free(lp);
+ x->e_op = CONST;
+ x->e_val = l;
+ }
+ return x;
+}
+
+int32_t
+eval_op(int op, register int32_t l, register int32_t r)
+{
+ switch( op ){
+ case NEG: l = -l; break;
+ case '~': l = ~l; break;
+ case '+': l += r; break;
+ case '-': l -= r; break;
+ case '*': l *= r; break;
+ case '&': l &= r; break;
+ case '|': l |= r; break;
+ case '^': l ^= r; break;
+ case '/':
+ if( r == 0 )
+ perr("Divide by zero");
+ else
+ l /= r;
+ break;
+ case ':':
+ l = (l << 16) | (r & 0xFFFF);
+ break;
+ case LEFT_SHIFT:
+ l <<= r;
+ break;
+ case RIGHT_SHIFT:
+ l >>= r;
+ break;
+ }
+ return l;
+}
+
+int
+eval_expr(expr e, int32_t *vp, unsigned *lp)
+{
+ e = fold(e);
+ *vp = eval_subtree(e, lp);
+ return (*lp < NOT_YET);
+}
+
+int32_t
+eval_subtree(expr e, unsigned *lp)
+{
+ register symbol s;
+ int32_t v1, v2;
+ unsigned l2;
+
+ switch( e->e_op ){
+ case SYM:
+ s = e->e_sym;
+ *lp = s->lineno;
+ if( (s->flags & DEFINED) != 0 )
+ return s->value;
+ perr("Undefined symbol %s", s->name);
+ return 0;
+ case CONST:
+ *lp = 0;
+ return e->e_val;
+ case '.':
+ *lp = lineno;
+ return pc;
+ default:
+ v1 = eval_subtree(e->e_left, lp);
+ if( e->e_right == NULL )
+ return eval_op(e->e_op, v1, 0);
+ v2 = eval_subtree(e->e_right, &l2);
+ if( l2 > *lp )
+ *lp = l2;
+ return eval_op(e->e_op, v1, v2);
+ }
+}
diff --git a/usr.sbin/gspa/gspa/gsp_gram.y b/usr.sbin/gspa/gspa/gsp_gram.y
new file mode 100644
index 00000000000..79cd885f68f
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_gram.y
@@ -0,0 +1,122 @@
+/*
+ * Yacc syntax for GSP assembler
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* declarations */
+
+%{
+#include "gsp_ass.h"
+%}
+
+%union {
+ long y_int;
+ char *y_id;
+ expr y_expr;
+ operand y_opnd;
+}
+
+%token LEFT_SHIFT, RIGHT_SHIFT
+
+%term <y_id> ID, STRING
+%term <y_int> NUMBER, REGISTER
+%term UMINUS
+
+/* operator precedences - lowest to highest */
+%nonassoc ':' /* concatenate y:x */
+%left LEFT_SHIFT, RIGHT_SHIFT
+%left '^' /* EXCLUSIVE OR operator */
+%left '|' /* OR operator */
+%left '&' /* AND operator */
+%left '+', '-'
+%left '*', '/'
+%nonassoc '~', UMINUS /* NOT operator */
+
+%start line
+
+/* types of non-terminals */
+%type <y_expr> expr
+%type <y_opnd> operand, operands, ea
+
+%%
+/* rules */
+
+line : label ID operands { statement($2, $3); }
+ | ID operands { statement($1, $2); }
+ | label
+ | ID '=' expr { do_asg($1, $3, 0); }
+ | /* empty */
+ | error
+ ;
+
+label : ID ':' { set_label($1); }
+ | NUMBER ':' { set_numeric_label($1); }
+ ;
+
+operands : /* empty */ { $$ = NULL; }
+ | operand { $$ = $1; }
+ | operands ',' operand { $$ = add_operand($1, $3); }
+ ;
+
+operand : REGISTER { $$ = reg_op($1); }
+ | ea { $$ = $1; }
+ | expr { $$ = expr_op($1); }
+ | STRING { $$ = string_op($1); }
+ ;
+
+ea : '@' expr { $$ = abs_adr($2); }
+ | '*' REGISTER { $$ = reg_ind($2, M_IND); }
+ | '*' REGISTER ID { $$ = reg_indxy($2, $3); }
+ | '*' REGISTER '+' { $$ = reg_ind($2, M_POSTINC); }
+ | '*' '-' REGISTER { $$ = reg_ind($3, M_PREDEC); }
+ | '-' '*' REGISTER { $$ = reg_ind($3, M_PREDEC); }
+ | '*' REGISTER '(' expr ')'
+ { $$ = reg_index($2, $4); }
+ ;
+
+expr : ID { $$ = id_expr($1); }
+ | NUMBER { $$ = num_expr($1); }
+ | '.' { $$ = here_expr(); }
+ | '(' expr ')' { $$ = $2; }
+ | '~' expr { $$ = bexpr('~', $2, NULL); }
+ | '-' expr %prec UMINUS
+ { $$ = bexpr(NEG, $2, NULL); }
+ | expr '*' expr { $$ = bexpr('*', $1, $3); }
+ | expr '/' expr { $$ = bexpr('/', $1, $3); }
+ | expr '+' expr { $$ = bexpr('+', $1, $3); }
+ | expr '-' expr { $$ = bexpr('-', $1, $3); }
+ | expr '&' expr { $$ = bexpr('&', $1, $3); }
+ | expr '|' expr { $$ = bexpr('|', $1, $3); }
+ | expr '^' expr { $$ = bexpr('^', $1, $3); }
+ | expr ':' expr { $$ = bexpr(':', $1, $3); }
+ | expr LEFT_SHIFT expr { $$ = bexpr(LEFT_SHIFT, $1, $3); }
+ | expr RIGHT_SHIFT expr { $$ = bexpr(RIGHT_SHIFT, $1, $3); }
+ ;
+
diff --git a/usr.sbin/gspa/gspa/gsp_inst.c b/usr.sbin/gspa/gspa/gsp_inst.c
new file mode 100644
index 00000000000..87838b9ada5
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_inst.c
@@ -0,0 +1,748 @@
+/*
+ * TMS34010 GSP assembler - Instruction encoding
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "gsp_ass.h"
+#include "gsp_code.h"
+#include <string.h>
+
+struct inst {
+ char *opname;
+ u_int16_t opcode;
+ u_char class; /* instruction class + flags */
+ u_char optypes[4]; /* permissible operand classes */
+};
+
+/* Values for flags in class field */
+#define NOIMM16 0x80 /* can't have 16-bit immediate */
+#define K32 0x40 /* values 1..32 for K-type constant */
+#define IMMCOM 0x20 /* immediate value is complemented */
+#define IMMNEG 0x80 /* immediate value is negated */
+#define NODSJS 0x80 /* can't use 5-bit branch offset */
+#define DSHORT 0x40 /* must use 5-bit offset */
+
+#define CLASS 0x1F
+
+/* Values for class */
+#define NOP 0 /* no operands */
+#define ONEREG 1 /* reg */
+#define TWOREG 2 /* reg, reg */
+#define DYADIC 3 /* immediate or reg, reg */
+#define ADD (DYADIC|K32)
+#define SUB (DYADIC|IMMCOM|K32)
+#define CMP (DYADIC|IMMCOM)
+#define AND (DYADIC|NOIMM16|IMMCOM)
+#define OR (DYADIC|NOIMM16)
+#define IMMREG 4 /* immediate, reg */
+#define IMMREGC (IMMREG|IMMCOM)
+#define LIMREG (IMMREG|NOIMM16)
+#define LIMREGC (LIMREG|IMMCOM)
+#define KREG 5 /* short immediate, reg */
+#define K32REG (KREG|K32)
+#define SRA (KREG|IMMNEG)
+#define BTST (KREG|IMMCOM)
+#define CALL 6 /* reg or address */
+#define JUMP 7
+#define CLR 8 /* reg appears twice in encoding */
+#define DSJ 9
+#define DSJEQ (DSJ|NODSJS)
+#define DSJS (DSJ|DSHORT)
+#define EXGF 10
+#define SETF 11
+#define FILL 12
+#define LINE 13
+#define PIXBLT 14
+#define PIXT 15
+#define MMFM 16
+#define MOVB 17
+#define MOVE 18
+#define MOVEK (MOVE|K32)
+#define RETS 19
+#define PSEUDO 20
+
+/* Composite operand classes */
+#define EXREG (REG|EXPR)
+#define EAREG (REG|EA)
+#define EXAREG (REG|EXPR|EA)
+#define OPTOPRN 0x80 /* signals optional operand */
+#define SPEC (0x10|EXPR) /* field or length specifier */
+#define OPTREG (OPTOPRN|REG)
+#define OPTEXPR (OPTOPRN|EXPR)
+#define OPTSPEC (OPTOPRN|SPEC)
+#define OPTXREG (OPTOPRN|EXREG)
+
+#define MIN(a, b) ((a) < (b)? (a): (b))
+
+/*
+ * N.B. This list must be sorted in order of opname.
+ */
+struct inst instructions[] = {
+ ".BLKB", BLKB, PSEUDO, {0, 0, 0, 0},
+ ".BLKL", BLKL, PSEUDO, {0, 0, 0, 0},
+ ".BLKW", BLKW, PSEUDO, {0, 0, 0, 0},
+#ifdef EQU
+ ".EQU", EQU, PSEUDO, {0, 0, 0, 0},
+#endif
+ ".INCLUDE", INCL, PSEUDO, {0, 0, 0, 0},
+ ".LONG",LONG, PSEUDO, {0, 0, 0, 0},
+ ".ORG", ORG, PSEUDO, {0, 0, 0, 0},
+ ".START",START, PSEUDO, {0, 0, 0, 0},
+ ".WORD",WORD, PSEUDO, {0, 0, 0, 0},
+ "ABS", 0x0380, ONEREG, {REG, 0, 0, 0},
+ "ADD", 0x4000, ADD, {EXREG, REG, OPTSPEC,0},
+ "ADDC", 0x4200, TWOREG, {REG, REG, 0, 0},
+ "ADDI", 0x0B20, IMMREG, {EXPR, REG, OPTSPEC,0},
+ "ADDK", 0x1000, K32REG, {EXPR, REG, 0, 0},
+ "ADDXY",0xE000, TWOREG, {REG, REG, 0, 0},
+ "AND", 0x5000, AND, {EXREG, REG, 0, 0},
+ "ANDI", 0x0B80, LIMREGC,{EXPR, REG, 0, 0},
+ "ANDN", 0x5200, OR, {EXREG, REG, 0, 0},
+ "ANDNI",0x0B80, LIMREG, {EXPR, REG, 0, 0},
+ "BTST", 0x1C00, BTST, {EXREG, REG, 0, 0},
+ "CALL", 0x0920, CALL, {EXREG, 0, 0, 0},
+ "CALLA",0x0D5F, CALL, {EXPR, 0, 0, 0},
+ "CALLR",0x0D3F, CALL, {EXPR, 0, 0, 0},
+ "CLR", 0x5600, CLR, {REG, 0, 0, 0},
+ "CLRC", 0x0320, NOP, {0, 0, 0, 0},
+ "CMP", 0x4800, CMP, {EXREG, REG, OPTSPEC,0},
+ "CMPI", 0x0B60, IMMREGC,{EXPR, REG, OPTSPEC,0},
+ "CMPXY",0xE400, TWOREG, {REG, REG, 0, 0},
+ "CPW", 0xE600, TWOREG, {REG, REG, 0, 0},
+ "CVXYL",0xE800, TWOREG, {REG, REG, 0, 0},
+ "DEC", 0x1420, ONEREG, {REG, 0, 0, 0},
+ "DINT", 0x0360, NOP, {0, 0, 0, 0},
+ "DIVS", 0x5800, TWOREG, {REG, REG, 0, 0},
+ "DIVU", 0x5A00, TWOREG, {REG, REG, 0, 0},
+ "DRAV", 0xF600, TWOREG, {REG, REG, 0, 0},
+ "DSJ", 0x0D80, DSJ, {REG, EXPR, 0, 0},
+ "DSJEQ",0x0DA0, DSJEQ, {REG, EXPR, 0, 0},
+ "DSJNE",0x0DC0, DSJEQ, {REG, EXPR, 0, 0},
+ "DSJS", 0x3800, DSJS, {REG, EXPR, 0, 0},
+ "EINT", 0x0D60, NOP, {0, 0, 0, 0},
+ "EMU", 0x0100, NOP, {0, 0, 0, 0},
+ "EXGF", 0xD500, EXGF, {REG, OPTSPEC,0, 0},
+ "EXGPC",0x0120, ONEREG, {REG, 0, 0, 0},
+ "FILL", 0x0FC0, FILL, {SPEC, 0, 0, 0},
+ "GETPC",0x0140, ONEREG, {REG, 0, 0, 0},
+ "GETST",0x0180, ONEREG, {REG, 0, 0, 0},
+ "INC", 0x1020, ONEREG, {REG, 0, 0, 0},
+ "JAB", 0xC880, JUMP, {EXPR, 0, 0, 0},
+ "JAC", 0xC880, JUMP, {EXPR, 0, 0, 0},
+ "JAEQ", 0xCA80, JUMP, {EXPR, 0, 0, 0},
+ "JAGE", 0xC580, JUMP, {EXPR, 0, 0, 0},
+ "JAGT", 0xC780, JUMP, {EXPR, 0, 0, 0},
+ "JAHI", 0xC380, JUMP, {EXPR, 0, 0, 0},
+ "JAHS", 0xC980, JUMP, {EXPR, 0, 0, 0},
+ "JALE", 0xC680, JUMP, {EXPR, 0, 0, 0},
+ "JALO", 0xC880, JUMP, {EXPR, 0, 0, 0},
+ "JALS", 0xC280, JUMP, {EXPR, 0, 0, 0},
+ "JALT", 0xC480, JUMP, {EXPR, 0, 0, 0},
+ "JAN", 0xCE80, JUMP, {EXPR, 0, 0, 0},
+ "JANB", 0xC980, JUMP, {EXPR, 0, 0, 0},
+ "JANC", 0xC980, JUMP, {EXPR, 0, 0, 0},
+ "JANE", 0xCB80, JUMP, {EXPR, 0, 0, 0},
+ "JANN", 0xCF80, JUMP, {EXPR, 0, 0, 0},
+ "JANV", 0xCD80, JUMP, {EXPR, 0, 0, 0},
+ "JANZ", 0xCB80, JUMP, {EXPR, 0, 0, 0},
+ "JAP", 0xC180, JUMP, {EXPR, 0, 0, 0},
+ "JAUC", 0xC080, JUMP, {EXPR, 0, 0, 0},
+ "JAV", 0xCC80, JUMP, {EXPR, 0, 0, 0},
+ "JAZ", 0xCA80, JUMP, {EXPR, 0, 0, 0},
+ "JRB", 0xC800, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRC", 0xC800, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JREQ", 0xCA00, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRGE", 0xC500, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRGT", 0xC700, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRHI", 0xC300, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRHS", 0xC900, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRLE", 0xC600, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRLO", 0xC800, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRLS", 0xC200, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRLT", 0xC400, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRN", 0xCE00, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRNB", 0xC900, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRNC", 0xC900, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRNE", 0xCB00, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRNN", 0xCF00, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRNV", 0xCD00, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRNZ", 0xCB00, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRP", 0xC100, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRUC", 0xC000, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRV", 0xCC00, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JRZ", 0xCA00, JUMP, {EXPR, OPTSPEC,0, 0},
+ "JUMP", 0x0160, JUMP, {EXREG, OPTSPEC,0, 0},
+ "LINE", 0xDF1A, LINE, {SPEC, 0, 0, 0},
+ "LMO", 0x6A00, TWOREG, {REG, REG, 0, 0},
+ "MMFM", 0x09A0, MMFM, {REG, OPTXREG,OPTREG, OPTREG},
+ "MMTM", 0x0980, MMFM, {REG, OPTXREG,OPTREG, OPTREG},
+ "MODS", 0x6C00, TWOREG, {REG, REG, 0, 0},
+ "MODU", 0x6E00, TWOREG, {REG, REG, 0, 0},
+ "MOVB", 0, MOVB, {EAREG, EAREG, 0, 0},
+ "MOVE", 0x4C00, MOVEK, {EXAREG,EAREG, OPTSPEC,0},
+ "MOVI", 0x09E0, IMMREG, {EXPR, REG, OPTSPEC,0},
+ "MOVK", 0x1800, K32REG, {EXPR, REG, 0, 0},
+ "MOVX", 0xEC00, TWOREG, {REG, REG, 0, 0},
+ "MOVY", 0xEE00, TWOREG, {REG, REG, 0, 0},
+ "MPYS", 0x5C00, TWOREG, {REG, REG, 0, 0},
+ "MPYU", 0x5E00, TWOREG, {REG, REG, 0, 0},
+ "NEG", 0x03A0, ONEREG, {REG, 0, 0, 0},
+ "NEGB", 0x03C0, ONEREG, {REG, 0, 0, 0},
+ "NOP", 0x0300, NOP, {0, 0, 0, 0},
+ "NOT", 0x03E0, ONEREG, {REG, 0, 0, 0},
+ "OR", 0x5400, OR, {EXREG, REG, 0, 0},
+ "ORI", 0x0BA0, LIMREG, {EXPR, REG, 0, 0},
+ "PIXBLT",0x0F00,PIXBLT, {SPEC, SPEC, 0, 0},
+ "PIXT", 0, PIXT, {EAREG, EAREG, 0, 0},
+ "POPST",0x01C0, NOP, {0, 0, 0, 0},
+ "PUSHST",0x01E0,NOP, {0, 0, 0, 0},
+ "PUTST",0x01A0, ONEREG, {REG, 0, 0, 0},
+ "RETI", 0x0940, NOP, {0, 0, 0, 0},
+ "RETS", 0x0960, RETS, {OPTEXPR,0, 0, 0},
+ "REV", 0x0020, ONEREG, {REG, 0, 0, 0},
+ "RL", 0x3000, KREG, {EXREG, REG, 0, 0},
+ "SETC", 0x0DE0, NOP, {0, 0, 0, 0},
+ "SETF", 0x0540, SETF, {EXPR, EXPR, OPTSPEC,0},
+ "SEXT", 0x0500, EXGF, {REG, OPTSPEC,0, 0},
+ "SLA", 0x2000, KREG, {EXREG, REG, 0, 0},
+ "SLL", 0x2400, KREG, {EXREG, REG, 0, 0},
+ "SRA", 0x2800, SRA, {EXREG, REG, 0, 0},
+ "SRL", 0x2C00, SRA, {EXREG, REG, 0, 0},
+ "SUB", 0x4400, SUB, {EXREG, REG, OPTSPEC,0},
+ "SUBB", 0x4600, TWOREG, {REG, REG, 0, 0},
+ "SUBI", 0x0D00, IMMREGC,{EXPR, REG, OPTSPEC,0},
+ "SUBK", 0x1400, K32REG, {EXPR, REG, 0, 0},
+ "SUBXY",0xE200, TWOREG, {REG, REG, 0, 0},
+ "TRAP", 0x0900, RETS, {EXPR, 0, 0, 0},
+ "XOR", 0x5600, OR, {EXREG, REG, 0, 0},
+ "XORI", 0x0BC0, LIMREG, {EXPR, REG, 0, 0},
+ "ZEXT", 0x0520, EXGF, {REG, OPTSPEC,0, 0},
+ NULL
+};
+
+
+void do_statement(char *opcode, operand operands);
+int encode_instr(struct inst *ip, operand ops,
+ int *spec, u_int16_t *iwords);
+
+void
+statement(char *opcode, operand operands)
+{
+ do_statement(opcode, operands);
+ free_operands(operands);
+}
+
+void
+do_statement(char *opcode, operand operands)
+{
+ register struct inst *ip;
+ register int i, nop, req;
+ register operand op;
+ int spec[3];
+ u_int16_t iwords[6];
+
+ ucasify(opcode);
+ i = 1;
+ for( ip = instructions; ip->opname != NULL; ++ip )
+ if( opcode[0] == ip->opname[0] ){
+ i = strcmp(opcode, ip->opname);
+ if( i <= 0 )
+ break;
+ }
+ if( i != 0 ){
+ perr("Unknown instruction code %s", opcode);
+ return;
+ }
+ if( ip->class == PSEUDO ){
+ pseudo(ip->opcode, operands);
+ return;
+ }
+
+ /* Check correspondence of operands with instruction requirements */
+ nop = 0;
+ spec[0] = spec[1] = spec[2] = 0;
+ for( op = operands; op != NULL; op = op->next ){
+ req = ip->optypes[MIN(nop, 3)];
+ if( req == 0 )
+ break;
+ if( (op->type & req) == 0 ){
+ perr("Inappropriate type for operand %d", nop+1);
+ return;
+ }
+ if( (req & ~OPTOPRN) == SPEC )
+ /* operand is a field/type/length specifier */
+ spec[nop] = specifier(op);
+ ++nop;
+ }
+ if( nop < 4 && ip->optypes[nop] != 0
+ && (ip->optypes[nop] & OPTOPRN) == 0 ){
+ perr("Insufficient operands");
+ return;
+ }
+ if( op != NULL )
+ perr("Extra operands ignored");
+
+ i = encode_instr(ip, operands, spec, iwords);
+
+ /* Pass 1 processing */
+ if( !pass2 ){
+ /* for pass 1, just work out the instruction size */
+/* printf("pc = %#x, size = %d\n", pc, i); */
+ pc += i << 4;
+ return;
+ }
+
+ /* Pass 2 processing */
+ if( i > 0 )
+ putcode(iwords, i);
+}
+
+char *specs[] = { "B", "L", "W", "XY", NULL };
+
+int
+specifier(operand op)
+{
+ register int i, k;
+ register char **sl;
+ register expr e;
+ char sp[4];
+
+ if( op->type != EXPR )
+ return '?';
+ e = op->op_u.value;
+ if( e->e_op == CONST ){
+ if( e->e_val == 0 || e->e_val == 1 )
+ return e->e_val + '0';
+ } else if( e->e_op == SYM ){
+ if( strlen(e->e_sym->name) > 2 )
+ return '?';
+ strcpy(sp, e->e_sym->name);
+ ucasify(sp);
+ for( sl = specs; *sl != NULL; ++sl )
+ if( strcmp(*sl, sp) == 0 )
+ return sp[0];
+ }
+ return '?';
+}
+
+int
+check_spec(int spec, char *valid, char *what)
+{
+ register char *p;
+
+ if( spec == 0 )
+ return 0;
+ p = strchr(valid, spec);
+ if( p == NULL ){
+ perr("Invalid %s specifier", what);
+ return 0;
+ }
+ return p - valid;
+}
+
+u_int16_t code_to_imm[] = {
+ 0x0B20, /* ADDI */
+ 0,
+ 0x0D00, /* SUBI */
+ 0,
+ 0x0B60, /* CMPI */
+ 0,
+ 0x09E0, /* MOVI */
+ 0,
+ 0x0B80, /* ANDI */
+ 0x0B80, /* ANDNI */
+ 0x0BA0, /* ORI */
+ 0x0BC0, /* XORI */
+};
+
+/* Opcodes for MOVE instruction */
+u_int16_t move_opc[7][7] = {
+/* Source */
+/* Reg *Reg *Reg+ *-Reg *Reg.XY *Reg(n) @addr Dest */
+ 0x4C00, 0x8400, 0x9400, 0xA400, 0, 0xB400, 0x05A0, /* R */
+ 0x8000, 0x8800, 0, 0, 0, 0, 0, /* *R */
+ 0x9000, 0, 0x9800, 0, 0, 0xD000, 0xD400, /* *R+ */
+ 0xA000, 0, 0, 0xA800, 0, 0, 0, /* *-R */
+ 0, 0, 0, 0, 0, 0, 0, /* *R.XY */
+ 0xB000, 0, 0, 0, 0, 0xB800, 0, /* *R(n) */
+ 0x0580, 0, 0, 0, 0, 0, 0x05C0, /* @adr */
+};
+
+/* Opcodes for MOVB instruction */
+u_int16_t movb_opc[7][7] = {
+/* Source */
+/* Reg *Reg *Reg+ *-Reg *Reg.XY *Reg(n) @addr Dest */
+ 0, 0x8E00, 0, 0, 0, 0xAE00, 0x07E0, /* R */
+ 0x8C00, 0x9C00, 0, 0, 0, 0, 0, /* *R */
+ 0, 0, 0, 0, 0, 0, 0, /* *R+ */
+ 0, 0, 0, 0, 0, 0, 0, /* *-R */
+ 0, 0, 0, 0, 0, 0, 0, /* *R.XY */
+ 0xAC00, 0, 0, 0, 0, 0xBC00, 0, /* *R(n) */
+ 0x05E0, 0, 0, 0, 0, 0, 0x0340, /* @adr */
+};
+
+/* Opcodes for PIXT instruction */
+u_int16_t pixt_opc[7][7] = {
+/* Source */
+/* Reg *Reg *Reg+ *-Reg *Reg.XY *Reg(n) @addr Dest */
+ 0, 0xFA00, 0, 0, 0xF200, 0, 0, /* R */
+ 0xF800, 0xFC00, 0, 0, 0, 0, 0, /* *R */
+ 0, 0, 0, 0, 0, 0, 0, /* *R+ */
+ 0, 0, 0, 0, 0, 0, 0, /* *-R */
+ 0xF000, 0, 0, 0, 0xF400, 0, 0, /* *R.XY */
+ 0, 0, 0, 0, 0, 0, 0, /* *R(n) */
+ 0, 0, 0, 0, 0, 0, 0, /* @adr */
+};
+
+#define USES_REG(op) ((op)->type == REG \
+ || (op)->type == EA && (op)->mode != M_ABSOLUTE)
+#define USES_EXPR(op) ((op)->type == EXPR \
+ || (op)->type == EA && (op)->mode >= M_INDEX)
+
+int
+encode_instr(struct inst *ip, operand ops, int *spec, u_int16_t *iwords)
+{
+ register int rs, rd;
+ int opc, nw, class, flags, ms, md, off;
+ int mask, file, bit, i;
+ register operand op0, op1;
+ unsigned line[2];
+ int32_t val[2];
+
+ opc = ip->opcode;
+ nw = 1;
+ op0 = ops;
+ if( op0 != NULL ){
+ if( spec[0] == 0 && USES_EXPR(op0) )
+ eval_expr(op0->op_u.value, &val[0], &line[0]);
+ op1 = ops->next;
+ if( op1 != NULL && spec[1] == 0 && USES_EXPR(op1) )
+ eval_expr(op1->op_u.value, &val[1], &line[1]);
+ } else
+ op1 = NULL;
+ class = ip->class & CLASS;
+ flags = ip->class & ~CLASS;
+ if( class == MOVE && op1->type == REG ){
+ if (op0->type == REG ){
+ class = DYADIC;
+ if( (op0->reg_no & op1->reg_no & REGFILE) == 0 ){
+ opc += 0x0200;
+ op1->reg_no ^= A0^B0;
+ }
+ } else if ( op0->type == EXPR )
+ class = DYADIC;
+ }
+ if( class == DYADIC ){
+ /* turn it into TWOREG, IMMREG or KREG */
+ if( op0->type == REG ){
+ class = TWOREG;
+ } else if( (flags & K32) != 0 && line[0] <= lineno
+ && spec[2] == 0
+ && 0 < val[0] && val[0] <= 32 ){
+ /* use 5-bit immediate */
+ class = KREG;
+ opc -= 0x3000;
+ if( opc == 0x1C00 )
+ opc = 0x1800;
+ flags &= ~IMMCOM;
+ } else {
+ class = IMMREG;
+ opc = code_to_imm[(opc - 0x4000) >> 9];
+ }
+ if( (class == TWOREG || class == KREG)
+ && spec[2] != 0 && op1->next->next == NULL )
+ perr("Extra operands ignored");
+ } else if( class == KREG ){
+ if( op0->type == REG ){
+ class = TWOREG;
+ if( opc < 0x2000 )
+ opc = 0x4A00; /* BTST */
+ else
+ opc = (opc >> 1) + 0x5000;
+ }
+ }
+
+ if( op0 != NULL )
+ rs = op0->reg_no;
+ if( op1 != NULL ){
+ rd = op1->reg_no;
+ if( USES_REG(op0) && USES_REG(op1) ){
+ if( (rs & rd & REGFILE) == 0 )
+ perr("Registers must be in the same register file");
+ /* force SP to the file of the other operand */
+ if( rs == SP )
+ rs |= rd;
+ if( rd == SP )
+ rd |= rs;
+ }
+ }
+
+ switch( class ){
+ case NOP: /* no operands */
+ break;
+ case ONEREG: /* reg */
+ opc |= rs & 0x1F;
+ break;
+ case TWOREG: /* reg, reg */
+ opc |= ((rs & 0x0F) << 5) | (rd & 0x1F);
+ break;
+ case IMMREG: /* immediate, reg */
+ opc |= rd & 0x1F;
+ if( (flags & IMMCOM) != 0 )
+ val[0] = ~ val[0];
+ i = check_spec(spec[2], " WL", "length");
+ if( i == 1
+ || i == 0 && (flags & NOIMM16) == 0 && line[0] <= lineno
+ && (int16_t)val[0] == val[0] ){
+ if( (int16_t) val[0] != val[0] )
+ perr("Value truncated to 16 bits");
+ opc -= 0x20;
+ if( opc == 0x0CE0 ) /* SUBI,W */
+ opc = 0x0BE0;
+ nw = 2;
+ } else {
+ iwords[2] = (val[0] >> 16);
+ nw = 3;
+ }
+ iwords[1] = val[0];
+ break;
+ case KREG: /* short immediate, reg */
+ opc |= rd & 0x1F;
+ if( val[0] < 0 || (flags & K32) == 0 && val[0] > 31
+ || (flags & K32) != 0 && val[0] <= 0 || val[0] > 32 )
+ perr("5-bit constant out of range");
+ rs = val[0];
+ if( (flags & IMMCOM) != 0 )
+ rs = ~rs;
+ else if( (flags & IMMNEG) != 0 )
+ rs = -rs;
+ opc |= (rs & 0x1F) << 5;
+ break;
+ case CALL: /* reg or address */
+ if( op0->type == REG ){
+ opc |= rs & 0x1F;
+ break;
+ }
+ off = (int)(val[0] - pc - 0x20) >> 4;
+ if( opc == 0x0920 ){ /* CALL */
+ if( line[0] <= lineno && (int16_t) off == off )
+ opc = 0x0D3F; /* CALLR */
+ else
+ opc = 0x0D5F; /* CALLA */
+ }
+ if( opc == 0x0D3F ){ /* CALLR */
+ if( (int16_t) off != off )
+ perr("Displacement too large");
+ iwords[1] = off;
+ nw = 2;
+ } else { /* CALLA */
+ iwords[1] = val[0];
+ iwords[2] = val[0] >> 16;
+ nw = 3;
+ }
+ break;
+ case JUMP:
+ if( op0->type == REG ){
+ opc |= rs & 0x1F;
+ break;
+ }
+ off = (int)(val[0] - pc - 0x10) >> 4;
+ if( (opc & 0x80) != 0 ) /* JAcc */
+ i = 2;
+ else
+ i = check_spec(spec[1], " WL", "length");
+ if( opc == 0x0160 ){ /* JUMP */
+ opc = 0xC000; /* JRUC */
+ if( i == 0 )
+ i = 1; /* ,W is the default for JUMP */
+ }
+ switch( i ){
+ case 2: /* JAcc */
+ iwords[1] = val[0];
+ iwords[2] = val[0] >> 16;
+ opc |= 0x80;
+ nw = 3;
+ break;
+ case 1:
+ --off;
+ if( (int16_t) off != off )
+ perr("Displacement too large (word)");
+ iwords[1] = off;
+ nw = 2;
+ break;
+ default:
+ if( off == 0 || off < -127 || off > 127 )
+ perr("Short displacement too large or 0");
+ opc |= off & 0xFF;
+ }
+ break;
+ case CLR: /* reg appears twice in encoding */
+ opc |= (rs & 0x1F) | ((rs & 0x0F) << 5);
+ break;
+ case DSJ:
+ off = (int)(val[1] - pc - 0x10) >> 4;
+ if( flags == 0 ){ /* DSJ */
+ if( off != 0 && off >= -31 && off <= 31 ){
+ flags = DSHORT;
+ opc = 0x3800; /* DSJS */
+ }
+ }
+ if( flags == DSHORT ){
+ if( off == 0 || off < -31 || off > 31 )
+ perr("DSJS displacement too large");
+ if( off > 0 )
+ opc |= (off & 0x1F) << 5;
+ else
+ opc |= 0x400 | ((-off & 0x1F) << 5);
+ } else {
+ --off;
+ if( (int16_t) off != off )
+ perr("Displacement too large (word)");
+ iwords[1] = off;
+ nw = 2;
+ }
+ opc |= rs & 0x1F;
+ break;
+ case EXGF:
+ opc |= rs & 0x1F;
+ opc |= check_spec(spec[1], "01", "field") << 9;
+ break;
+ case SETF:
+ rs = val[0];
+ rd = val[1];
+ if( rs <= 0 || rs > 32 )
+ perr("Field size must be 1..32");
+ if( rd != 0 && rd != 1 )
+ perr("Field extension must be 0 or 1");
+ opc |= (rs & 0x1F) | ((rd & 1) << 5);
+ opc |= check_spec(spec[2], "01", "field") << 9;
+ break;
+ case FILL:
+ opc |= check_spec(spec[0], "LX", "array type") << 5;
+ break;
+ case LINE:
+ opc |= check_spec(spec[0], "01", "algorithm") << 7;
+ break;
+ case PIXBLT:
+ rs = check_spec(spec[0], "LXB", "source array type");
+ rd = check_spec(spec[1], "LX", "destination array type");
+ opc |= (rs << 6) | (rd << 5);
+ break;
+ case MMFM:
+ opc |= rs & 0xF;
+ file = rs & REGFILE;
+ if( op1 == NULL )
+ mask = 0xFFFF;
+ else if( op1->type == REG ){
+ file &= rd;
+ mask = 0;
+ for( ; op1 != NULL; op1 = op1->next ){
+ rd = op1->reg_no;
+ bit = 1 << (~rd & 0xF);
+ if( file != 0 && (file &= rd) == 0 )
+ perr("Registers must all be in the same file");
+ if( file != 0 && (mask & bit) != 0 )
+ perr("Register name repeated");
+ mask |= bit;
+ }
+ } else {
+ if( val[1] < 0 || val[1] > 0xFFFFL )
+ perr("Mask value out of range");
+ mask = val[1];
+ if( op1->next != NULL )
+ perr("Extra operands ignored");
+ }
+ if( (file & A0 & REGFILE) == 0 )
+ opc |= 0x10;
+ if( (opc & 0x20) != 0 ){
+ /* mask reversed for MMFM */
+ rs = 0;
+ for( bit = 16; bit != 0; --bit ){
+ rs <<= 1;
+ rs |= mask & 1;
+ mask >>= 1;
+ }
+ mask = rs;
+ }
+ iwords[1] = mask;
+ nw = 2;
+ break;
+ case PIXT:
+ case MOVB:
+ case MOVE:
+ ms = op0->type == REG? M_REG: op0->mode;
+ md = op1->type == REG? M_REG: op1->mode;
+ opc = class == MOVE? move_opc[md][ms]:
+ class == MOVB? movb_opc[md][ms]: pixt_opc[md][ms];
+ if( opc == 0 ){
+ perr("Illegal combination of addressing modes");
+ nw = 0;
+ break;
+ }
+ if( ms == M_INDEX ){
+ if( (int16_t) val[0] != val[0] )
+ perr("Source displacement too large");
+ iwords[1] = val[0];
+ nw = 2;
+ } else if( ms == M_ABSOLUTE ){
+ iwords[1] = val[0];
+ iwords[2] = val[0] >> 16;
+ nw = 3;
+ rs = 0;
+ }
+ if( md == M_INDEX ){
+ if( (int16_t) val[1] != val[1] )
+ perr("Destination displacement too large");
+ iwords[nw] = val[1];
+ ++nw;
+ } else if( md == M_ABSOLUTE ){
+ iwords[nw] = val[1];
+ iwords[nw+1] = val[1] >> 16;
+ nw += 2;
+ rd = rs;
+ rs = 0;
+ }
+ opc |= (rd & 0x1F) | ((rs & 0xF) << 5);
+ opc |= check_spec(spec[2], "01", "field") << 9;
+ break;
+ case RETS:
+ if( op0 == NULL )
+ val[0] = 0;
+ else if( val[0] < 0 || val[0] > 31 )
+ perr("%s out of range",
+ (opc > 0x900? "Pop count": "Trap number"));
+ opc |= val[0] & 0x1F;
+ break;
+ default:
+ perr("BUG: unknown instruction class %d\n", class);
+ }
+ iwords[0] = opc;
+ return nw;
+}
+
diff --git a/usr.sbin/gspa/gspa/gsp_lex.c b/usr.sbin/gspa/gspa/gsp_lex.c
new file mode 100644
index 00000000000..6327f281fdc
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_lex.c
@@ -0,0 +1,183 @@
+/*
+ * Lexical analyser for GSP assembler
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include "gsp_ass.h"
+#include "y.tab.h"
+#include <ctype.h>
+#include <stdlib.h>
+/*#include <string.h>*/
+
+char *lineptr;
+
+char idents[MAXLINE];
+char *idptr;
+
+extern YYSTYPE yylval;
+
+void ucasify(char *);
+int str_match(char *, char **);
+
+char *regnames[] = {
+ "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
+ "A8", "A9", "A10", "A11", "A12", "A13", "A14", "SP",
+ "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7",
+ "B8", "B9", "B10", "B11", "B12", "B13", "B14", "B15",
+ NULL
+};
+
+short regnumbers[] = {
+ A0+0, A0+1, A0+2, A0+3, A0+4, A0+5, A0+6, A0+7,
+ A0+8, A0+9, A0+10, A0+11, A0+12, A0+13, A0+14, SP,
+ B0+0, B0+1, B0+2, B0+3, B0+4, B0+5, B0+6, B0+7,
+ B0+8, B0+9, B0+10, B0+11, B0+12, B0+13, B0+14, B0+15,
+};
+
+void
+lex_init(char *line)
+{
+ lineptr = line;
+ idptr = idents;
+}
+
+int
+yylex()
+{
+ register int c, tok, x, len;
+ register char *lp, *ip;
+ char *end;
+
+ lp = lineptr;
+ c = *lp;
+ while( c == ' ' || c == '\t' )
+ c = *++lp;
+ if( isalpha(c) || c == '_' || c == '.' ){
+ /* an identifier or register name */
+ ip = lp;
+ do {
+ c = *++lp;
+ } while( isalnum(c) || c == '_' );
+ len = lp - ip;
+ if( len == 1 && *ip == '.' )
+ tok = '.';
+ else {
+ strncpy(idptr, ip, len);
+ idptr[len] = 0;
+ ucasify(idptr);
+ x = str_match(idptr, regnames);
+ if( x == -1 ){
+ strncpy(idptr, ip, len);
+ yylval.y_id = idptr;
+ idptr += len + 1;
+ tok = ID;
+ } else {
+ yylval.y_int = regnumbers[x];
+ tok = REGISTER;
+ }
+ }
+ } else if( c == '$' ){
+ /* a hex number */
+ ++lp;
+ yylval.y_int = strtoul(lp, &end, 16);
+ if( end == lp )
+ perr("Bad number syntax");
+ else
+ lp = end;
+ tok = NUMBER;
+ } else if( isdigit(c) ){
+ yylval.y_int = strtoul(lp, &end, 0);
+ ip = lp;
+ lp = end;
+ c = *lp;
+ if( (c == 'f' || c == 'F' || c == 'b' || c == 'B')
+ && !(isalnum(lp[1]) || lp[1] == '_') ){
+ /* reference to numeric label */
+ c = toupper(c);
+ sprintf(idptr, "%d%c", yylval.y_int, c);
+ yylval.y_id = idptr;
+ idptr += strlen(idptr) + 1;
+ ++lp;
+ tok = ID;
+ } else
+ tok = NUMBER;
+ } else if( c == '\n' ){
+ tok = 0; /* eof */
+ } else if( c == ';' ){
+ /* comment - skip to end of line */
+ while( *++lp != 0 )
+ ;
+ tok = 0;
+ } else if( c == '"' ){
+ /* string */
+ yylval.y_id = idptr;
+ while( (c = *++lp) != '"' && c != '\n' && c != 0 )
+ *idptr++ = c;
+ *idptr++ = 0;
+ if( c != '"' )
+ perr("Unterminated string");
+ else
+ ++lp;
+ tok = STRING;
+ } else if( c == '<' && lp[1] == '<' ){
+ lp += 2;
+ tok = LEFT_SHIFT;
+ } else if( c == '>' && lp[1] == '>' ){
+ lp += 2;
+ tok = RIGHT_SHIFT;
+ } else {
+ if( c != 0 )
+ ++lp;
+ tok = c;
+ }
+ lineptr = lp;
+ return tok;
+}
+
+void
+ucasify(register char *p)
+{
+ register int c;
+
+ for( ; (c = *p) != 0; p++ )
+ if( islower(c) )
+ *p = toupper(c);
+}
+
+int
+str_match(register char *id, char **names)
+{
+ register char **np;
+
+ for( np = names; *np != NULL; ++np )
+ if( strcmp(id, *np) == 0 )
+ return np - names;
+ return -1;
+}
diff --git a/usr.sbin/gspa/gspa/gsp_out.c b/usr.sbin/gspa/gspa/gsp_out.c
new file mode 100644
index 00000000000..4dcf7b39270
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_out.c
@@ -0,0 +1,182 @@
+/*
+ * GSP assembler - binary & listing output
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include "gsp_ass.h"
+
+u_int16_t codes[5];
+unsigned ncode;
+unsigned code_idx;
+short show_pc;
+short show_val;
+int32_t val_to_show;
+extern unsigned line_pc;
+
+unsigned obj_addr = 0;
+
+extern FILE *objfile, *listfile;
+extern char line[];
+
+struct error {
+ struct error *next;
+ char string[1];
+};
+
+struct error *error_list, *error_last;
+
+void put1code(u_int16_t);
+
+void
+putcode(u_int16_t *v, int n)
+{
+ for( ; n > 0; --n )
+ put1code(*v++);
+}
+
+void
+put1code(u_int16_t v)
+{
+ if( code_idx >= 3 )
+ listing_line();
+ codes[code_idx] = v;
+ if( objfile != NULL ){
+ if( pc != obj_addr ){
+ /* expect this only when ncode == 0 */
+ if( ncode % 8 != 0 )
+ fprintf(objfile, "\n");
+ fprintf(objfile, "@%x\n", pc);
+ obj_addr = pc;
+ } else {
+ if( ncode % 8 != 0 )
+ fprintf(objfile, " ");
+ }
+ fprintf(objfile, "%.4X", v & 0xFFFF);
+ obj_addr += 0x10;
+ if( ncode % 8 == 7 )
+ fprintf(objfile, "\n");
+ }
+ ++ncode;
+ ++code_idx;
+ pc += 0x10;
+ show_pc = TRUE;
+}
+
+start_at(int32_t val)
+{
+ if( objfile != NULL )
+ fprintf(objfile, ":%.lX\n", val);
+}
+
+do_list_pc()
+{
+ if( pass2 )
+ show_pc = TRUE;
+}
+
+do_show_val(int32_t v)
+{
+ if( ncode == 0 ){
+ val_to_show = v;
+ show_val = TRUE;
+ show_pc = FALSE;
+ }
+}
+
+list_error(char *string)
+{
+ struct error *p;
+ int l;
+
+ if( listfile == NULL )
+ return;
+ l = strlen(string);
+ p = (struct error *) alloc(sizeof(struct error) + l);
+ strcpy(p->string, string);
+ p->next = NULL;
+ if( error_list == NULL )
+ error_list = p;
+ else
+ error_last->next = p;
+ error_last = p;
+}
+
+show_errors()
+{
+ struct error *p, *q;
+
+ for( p = error_list; p != NULL; p = q ){
+ if( listfile != NULL )
+ fprintf(listfile, "\t\t\t%s\n", p->string);
+ q = p->next;
+ free(p);
+ }
+ error_list = error_last = NULL;
+}
+
+listing()
+{
+ if( objfile != NULL && ncode % 8 != 0 )
+ fprintf(objfile, "\n");
+ listing_line();
+ show_errors();
+ ncode = 0;
+ show_pc = FALSE;
+}
+
+listing_line()
+{
+ register int i;
+
+ if( listfile == NULL ){
+ code_idx = 0;
+ return;
+ }
+ if( show_pc )
+ fprintf(listfile, "%.8X", line_pc);
+ else
+ fprintf(listfile, " ");
+ if( show_val ){
+ fprintf(listfile, " %.8X", val_to_show);
+ i = 2;
+ } else {
+ for( i = 0; i < code_idx; ++i )
+ fprintf(listfile, " %.4X", codes[i]);
+ }
+ if( ncode <= 3 ){
+ for( ; i < 3; ++i )
+ fprintf(listfile, " ");
+ fprintf(listfile, " %s", line);
+ } else
+ fprintf(listfile, "\n");
+ line_pc += code_idx << 4;
+ code_idx = 0;
+ show_val = FALSE;
+}
diff --git a/usr.sbin/gspa/gspa/gsp_pseu.c b/usr.sbin/gspa/gspa/gsp_pseu.c
new file mode 100644
index 00000000000..2c80639374a
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_pseu.c
@@ -0,0 +1,148 @@
+/*
+ * GSP assembler - assembler directives
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "gsp_ass.h"
+#include "gsp_code.h"
+
+extern unsigned highest_pc, line_pc;
+
+void
+pseudo(int code, operand ops)
+{
+ operand o;
+ int32_t val;
+ unsigned ln;
+ u_int16_t words[2];
+
+ switch( code ){
+ case ORG:
+ if( ops == NULL )
+ break;
+ if( ops->type != EXPR ){
+ perr("Inappropriate operand");
+ break;
+ }
+ if( !eval_expr(ops->op_u.value, &val, &ln) ){
+ p1err("ORG operand must be defined on pass 1");
+ break;
+ }
+ if( pc > highest_pc )
+ highest_pc = pc;
+ line_pc = pc = val;
+ do_list_pc();
+ break;
+#ifdef EQU
+ case EQU:
+ if( label == NULL ){
+ perr("Label required");
+ break;
+ }
+ if( ops == NULL )
+ break;
+ if( ops->type != EXPR ){
+ perr("Inappropriate operand");
+ break;
+ }
+ do_asg(label, ops->op_u.value, 0);
+ break;
+#endif /* EQU */
+ case WORD:
+ case LONG:
+ if( ops == NULL )
+ break;
+ for( o = ops; o != NULL; o = o->next ){
+ if( o->type != EXPR ){
+ perr("Inappropriate operand");
+ continue;
+ }
+ if( pass2 ){
+ eval_expr(o->op_u.value, &val, &ln);
+ words[0] = val;
+ if( code == LONG ){
+ words[1] = val >> 16;
+ putcode(words, 2);
+ } else {
+ if( val < -32768 || val > 65535 )
+ perr("Word value too large");
+ putcode(words, 1);
+ }
+ } else
+ pc += code == LONG? 0x20: 0x10;
+ }
+ return;
+ case INCL:
+ if( ops == NULL )
+ break;
+ if( ops->type != STR_OPN ){
+ perr("Require filename string");
+ break;
+ }
+ push_input(ops->op_u.string);
+ break;
+ case BLKB:
+ case BLKW:
+ case BLKL:
+ if( ops == NULL )
+ break;
+ if( ops->type != EXPR ){
+ perr("Inappropriate operand");
+ break;
+ }
+ if( !eval_expr(ops->op_u.value, &val, &ln) ){
+ p1err(".BLK%c operand must be defined on pass 1",
+ code==BLKB? 'B': code==BLKW? 'W': 'L');
+ break;
+ }
+ val *= 8;
+ if( code == BLKB )
+ val = (val + 8) & ~15; /* round to word */
+ else
+ val *= (code==BLKW? 2: 4);
+ pc += val;
+ do_list_pc();
+ break;
+ case START:
+ if( !pass2 || ops == NULL )
+ break;
+ if( ops->type != EXPR ){
+ perr("Inappropriate operand");
+ break;
+ }
+ eval_expr(ops->op_u.value, &val, &ln);
+ start_at(val);
+ do_show_val(val);
+ break;
+ }
+ if( ops == NULL )
+ perr("Insufficient operands");
+ else if( ops->next != NULL )
+ perr("Extra operands ignored");
+}
diff --git a/usr.sbin/gspa/gspa/gsp_sym.c b/usr.sbin/gspa/gspa/gsp_sym.c
new file mode 100644
index 00000000000..742348acb0e
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gsp_sym.c
@@ -0,0 +1,192 @@
+/*
+ * GSP assembler - symbol table
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "gsp_ass.h"
+
+#define NHASH 64 /* must be power of 2 */
+
+symbol symbol_hash[NHASH];
+
+symbol
+lookup(char *id, bool makeit)
+{
+ register symbol ptr, p, *pp;
+ register int h;
+ register char *ip;
+
+ h = 0;
+ for( ip = id; *ip != 0; )
+ h = (h << 1) + *ip++;
+ h &= NHASH-1;
+ for( pp = &symbol_hash[h]; (p = *pp) != NULL; pp = &p->next )
+ if( (h = strcmp(id, p->name)) == 0 )
+ return p;
+ else if( h < 0 )
+ break;
+ if( !makeit )
+ return NULL;
+ ptr = (symbol) alloc (sizeof(struct symbol) + strlen(id));
+ ptr->ndefn = 0;
+ ptr->flags = 0;
+ ptr->value = 0;
+ ptr->lineno = NOT_YET;
+ strcpy(ptr->name, id);
+ *pp = ptr;
+ ptr->next = p;
+ ptr->nlab = NULL;
+ return ptr;
+}
+
+void
+define_sym(char *id, unsigned val, unsigned lineno, int flags)
+{
+ register symbol ptr;
+
+ ptr = lookup(id, TRUE);
+ if( (ptr->flags & SET_LABEL) == 0 ){
+ if( ptr->ndefn >= 2 ){
+ perr("Multiply defined label %s", id);
+ if( (flags & SET_LABEL) != 0 )
+ return;
+ } else if( pass2 && ptr->value != val )
+ perr("Phase error on label %s (%#x -> %#x)",
+ id, ptr->value, val);
+ }
+ ptr->flags = flags;
+ ptr->ndefn += 1;
+ ptr->value = val;
+ ptr->lineno = lineno;
+}
+
+void
+set_label(char *id)
+{
+ if( id != NULL ){
+ define_sym(id, pc, lineno, DEFINED);
+ if( pass2 )
+ do_list_pc();
+ }
+}
+
+void
+do_asg(char *name, expr value, int flags)
+{
+ int32_t val;
+ unsigned line;
+
+ if( eval_expr(value, &val, &line) )
+ flags |= DEFINED;
+ if( line < lineno )
+ line = lineno;
+ define_sym(name, val, line, flags);
+ if( pass2 )
+ do_show_val(val);
+}
+
+void
+set_numeric_label(int lnum)
+{
+ register symbol bp, fp;
+ register struct numlab *nl;
+ char id[32];
+
+ /* define the backward reference symbol */
+ sprintf(id, "%dB", lnum);
+ bp = lookup(id, TRUE);
+ bp->flags = NUMERIC_LABEL | DEFINED;
+ bp->value = pc;
+ bp->lineno = lineno;
+
+ /* look up the forward reference symbol */
+ id[strlen(id) - 1] = 'F';
+ fp = lookup(id, TRUE);
+
+ if( !pass2 ){
+ /* Record a new numeric label and link it into the
+ chain. fp->nlab points to the head of the chain,
+ bp->nlab points to the tail. */
+ new(nl);
+ nl->value = pc;
+ nl->lineno = lineno;
+ nl->next = NULL;
+ if( bp->nlab == NULL )
+ fp->nlab = nl;
+ else
+ bp->nlab->next = nl;
+ bp->nlab = nl;
+ fp->flags = NUMERIC_LABEL;
+ } else {
+ /* Advance to the next numeric label entry in the chain
+ and update the value of the forward reference symbol. */
+ if( pc != fp->value )
+ perr("Phase error on numeric label %d (%#x -> %#x)",
+ lnum, fp->value, pc);
+ nl = fp->nlab;
+ nl = nl->next;
+ if( nl == NULL ){
+ /* no more labels of this number */
+ /* forward references are now undefined */
+ fp->flags &= ~DEFINED;
+ fp->lineno = NOT_YET;
+ fp->value = 0;
+ } else {
+ fp->lineno = nl->lineno;
+ fp->value = nl->value;
+ fp->nlab = nl;
+ }
+ do_list_pc();
+ }
+}
+
+/* At the beginning of pass 2, reset all of the numeric labels.
+ Backward references become undefined, forward references are defined
+ by the first instance of the label. */
+void
+reset_numeric_labels()
+{
+ register symbol p;
+ register struct numlab *nl;
+ register int h;
+
+ for( h = 0; h < NHASH; ++h )
+ for( p = symbol_hash[h]; p != NULL; p = p->next )
+ if( (p->flags & NUMERIC_LABEL) != 0 )
+ if( (p->flags & DEFINED) != 0 ){
+ /* a backward reference */
+ p->flags &= ~DEFINED;
+ } else {
+ /* a forward reference */
+ p->flags |= DEFINED;
+ nl = p->nlab;
+ p->value = nl->value;
+ p->lineno = nl->lineno;
+ }
+}
diff --git a/usr.sbin/gspa/gspa/gspa.c b/usr.sbin/gspa/gspa/gspa.c
new file mode 100644
index 00000000000..49c891175b0
--- /dev/null
+++ b/usr.sbin/gspa/gspa/gspa.c
@@ -0,0 +1,273 @@
+/*
+ * GSP assembler main program
+ *
+ * Copyright (c) 1993 Paul Mackerras.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Paul Mackerras.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <string.h>
+#include <errno.h>
+#include <err.h>
+#include <unistd.h>
+#include "gsp_ass.h"
+#include "y.tab.h"
+
+#define YYDEBUG_VALUE 0
+
+extern YYSTYPE yylval;
+int err_count;
+
+char line[MAXLINE];
+int lineno;
+
+extern int yydebug;
+short pass2;
+
+unsigned pc;
+unsigned highest_pc;
+unsigned line_pc;
+
+FILE *infile;
+FILE *current_infile;
+FILE *objfile;
+FILE *listfile;
+
+char in_name[PATH_MAX + 1];
+
+struct input {
+ FILE *fp;
+ struct input *next;
+ int lineno;
+ char name[128];
+} *pending_input;
+
+jmp_buf synerrjmp;
+
+main(int argc, char **argv)
+{
+ char *hex_name, *list_name;
+ short in_given, hex_given, list_given;
+ int i, v;
+ int c;
+ char *p;
+
+ hex_name = list_name = 0;
+
+ /* parse options */
+ while ((c = getopt(argc, argv, "o:l:")) != EOF) {
+ switch (c) {
+ case 'o':
+ if (hex_name)
+ usage();
+ hex_name = optarg;
+ break;
+ case 'l':
+ if (list_name)
+ usage();
+ list_name = optarg;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* get source file */
+ argc -= optind;
+ argv += optind;
+ if (argc == 0) {
+ infile = stdin;
+ strcpy(in_name, "<stdin>");
+ } else if (argc == 1) {
+ strncpy(in_name, *argv, PATH_MAX);
+ in_name[PATH_MAX] = 0;
+ if ((infile = fopen(in_name, "r")) == NULL)
+ err(1, "fopen");
+ } else
+ usage();
+
+ /* Pass 1 */
+ pending_input = NULL;
+ current_infile = infile;
+
+ yydebug = YYDEBUG_VALUE;
+ pass2 = 0;
+ pc = 0;
+ lineno = 0;
+ while( get_line(line, MAXLINE) ){
+ if( !setjmp(synerrjmp) ){
+ lex_init(line);
+ yyparse();
+ }
+ }
+ if( err_count > 0 )
+ exit(1);
+
+ /* Open output files */
+ if (hex_name == 0)
+ objfile = stdout;
+ else if ((objfile = fopen(hex_name, "w")) == NULL)
+ err(1, "fopen");
+ if (list_name)
+ if ((listfile = fopen(list_name, "w")) == NULL)
+ err(1, "fopen");
+
+ /* Pass 2 */
+ pass2 = 1;
+ rewind(infile);
+ current_infile = infile;
+ pc = 0;
+ lineno = 0;
+ reset_numeric_labels();
+ while( get_line(line, MAXLINE) ){
+ line_pc = pc;
+ if( !setjmp(synerrjmp) ){
+ lex_init(line);
+ yyparse();
+ }
+ listing();
+ }
+
+ exit(err_count != 0);
+}
+
+setext(char *out, const char *in, const char *ext)
+{
+ const char *p;
+
+ p = strrchr(in, '.');
+ if( p != NULL ){
+ memcpy(out, in, p - in);
+ strcpy(out + (p - in), ext);
+ } else {
+ strcpy(out, in);
+ strcat(out, ext);
+ }
+}
+
+push_input(char *fn)
+{
+ FILE *f;
+ struct input *p;
+
+ f = fopen(fn, "r");
+ if( f == NULL ){
+ p1err("Can't open input file %s", fn);
+ return;
+ }
+ new(p);
+ p->fp = current_infile;
+ p->lineno = lineno;
+ strcpy(p->name, in_name);
+ p->next = pending_input;
+ current_infile = f;
+ lineno = 1;
+ strcpy(in_name, fn);
+ pending_input = p;
+}
+
+int
+get_line(char *lp, int maxlen)
+{
+ struct input *p;
+
+ while( fgets(lp, maxlen, current_infile) == NULL ){
+ if( (p = pending_input) == NULL )
+ return 0;
+ /* pop the input stack */
+ fclose(current_infile);
+ current_infile = p->fp;
+ strcpy(in_name, p->name);
+ lineno = p->lineno;
+ pending_input = p->next;
+ free(p);
+ }
+ ++lineno;
+ return 1;
+}
+
+void
+perr(char *fmt, ...)
+{
+ va_list ap;
+ char error_string[256];
+
+ if( !pass2 )
+ return;
+ fprintf(stderr, "Error in line %d: ", lineno);
+ va_start(ap, fmt);
+ vsprintf(error_string, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "%s\n", error_string);
+ list_error(error_string);
+ ++err_count;
+}
+
+void
+p1err(char *fmt, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "Pass 1 error in line %d: ", lineno);
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ ++err_count;
+}
+
+void
+yyerror(char *err)
+{
+ extern char *lineptr;
+
+ perr(err);
+ longjmp(synerrjmp, 1);
+}
+
+char *
+alloc(size_t nbytes)
+{
+ register char *p;
+
+ if( (p = malloc(nbytes)) == NULL ){
+ fprintf(stderr, "Insufficient memory at line %d\n", lineno);
+ exit(1);
+ }
+ return p;
+}
+
+usage()
+{
+ fprintf(stderr,
+ "Usage: gspa [infile] [+o|-o hex_file] [+l|-l list_file]\n");
+ exit(1);
+}
diff --git a/usr.sbin/gspa/gspahextoc/Makefile b/usr.sbin/gspa/gspahextoc/Makefile
new file mode 100644
index 00000000000..f0b26756dde
--- /dev/null
+++ b/usr.sbin/gspa/gspahextoc/Makefile
@@ -0,0 +1,6 @@
+PROG= gspahextoc
+SRCS= gspahextoc.l
+NOMAN= noman
+LDADD= -ll
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/gspa/gspahextoc/README b/usr.sbin/gspa/gspahextoc/README
new file mode 100644
index 00000000000..27077e7915f
--- /dev/null
+++ b/usr.sbin/gspa/gspahextoc/README
@@ -0,0 +1,19 @@
+This is a small utility which is used to convert the hex output of Paul
+Mackerras' gspa to an initialized array of unsigned shorts.
+
+Input format:
+
+:hex -> start address
+@hex -> new load address
+hex -> load @load address & autoincrement
+
+Output format:
+
+Load blocks start with 16 bit count of the data without address, then
+high 16 bits of load address, then low 16 bits of load address, followed by
+count words of data. This sequence is repeated until count == 0.
+
+The start address is converted to two load blocks which set the
+NMI and the RESET vector.
+
+ Ignatios Souvatzis
diff --git a/usr.sbin/gspa/gspahextoc/gspahextoc.l b/usr.sbin/gspa/gspahextoc/gspahextoc.l
new file mode 100644
index 00000000000..dcd54bb165d
--- /dev/null
+++ b/usr.sbin/gspa/gspahextoc/gspahextoc.l
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 1995 Ignatios Souvatzis
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ignatios Souvatzis
+ * for the NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ int bufptr;
+ unsigned short buf[4096];
+
+ unsigned long binads;
+
+
+ void dumpstart __P((char *address));
+ void dumpbuf __P((void));
+ void initbuf __P((char *address));
+ void checkbuf __P((void));
+%%
+:[0-9A-Za-z]+ {if (bufptr>0) dumpbuf(); dumpstart(yytext+1);}
+@[0-9A-Za-z]+ {if (bufptr>0) dumpbuf(); initbuf(yytext+1);}
+[0-9A-Za-z]+ {checkbuf(); buf[bufptr++] = strtoul(yytext, 0, 16);}
+[ \t\n] ;
+%%
+
+void
+dumpbuf()
+{
+ int i;
+
+ printf("\n\n\t%d, 0x%04x, 0x%04x, /* new block */",
+ bufptr, binads >> 16, binads & 0xffff);
+ for (i=0; i<bufptr; ++i) {
+ if (i%8 == 0)
+ printf("\n\t");
+ printf("0x%04x, ", buf[i]);
+ }
+ binads += bufptr;
+ bufptr = 0;
+}
+
+void
+checkbuf()
+{
+ if (bufptr > (sizeof(buf)/sizeof(*buf)))
+ dumpbuf();
+}
+
+void
+initbuf(address)
+ char *address;
+{
+ binads = strtoul(address, 0, 16);
+ bufptr = 0;
+}
+
+void
+dumpstart(address)
+ char *address;
+{
+ u_int32_t startaddress;
+
+ startaddress = strtoul(address, 0, 16);
+
+ printf("\n\n\t2, 0xFFFF, 0xFEE0, 0x%04x, 0x%04x,\t/* start address */",
+ startaddress & 0xFFFF, startaddress >> 16);
+
+ printf("\n\t2, 0xFFFF, 0xFFE0, 0x%04x, 0x%04x,",
+ startaddress & 0xFFFF, startaddress >> 16);
+
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ ++argv; --argc;
+ if (argc > 0) {
+ yyin = fopen(argv[0], "r");
+ printf("/*\n"
+ " * This file was automatically created from %s,\n"\
+ " * a TMS34010 assembler output file.\n", argv[0]);
+ } else {
+ yyin = stdin;
+ printf("/*\n"
+ " * This file was automatically created from\n"\
+ " * a TMS34010 assembler output file.\n");
+ }
+
+ printf(" * Do not edit manually..\n");
+ printf(" */\n");
+ printf("u_int16_t tmscode[] = {\n\t");
+ yylex();
+ if (bufptr>0)
+ dumpbuf();
+ printf("\n\t0\n};\n");
+
+ exit(0);
+}