diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /usr.sbin/gspa |
initial import of NetBSD tree
Diffstat (limited to 'usr.sbin/gspa')
-rw-r--r-- | usr.sbin/gspa/Makefile | 3 | ||||
-rw-r--r-- | usr.sbin/gspa/Makefile.inc | 4 | ||||
-rw-r--r-- | usr.sbin/gspa/gspa/Makefile | 12 | ||||
-rw-r--r-- | usr.sbin/gspa/gspa/gsp_act.c | 204 | ||||
-rw-r--r-- | usr.sbin/gspa/gspa/gsp_ass.h | 180 | ||||
-rw-r--r-- | usr.sbin/gspa/gspa/gsp_code.h | 41 | ||||
-rw-r--r-- | usr.sbin/gspa/gspa/gsp_eval.c | 138 | ||||
-rw-r--r-- | usr.sbin/gspa/gspa/gsp_gram.y | 122 | ||||
-rw-r--r-- | usr.sbin/gspa/gspa/gsp_inst.c | 748 | ||||
-rw-r--r-- | usr.sbin/gspa/gspa/gsp_lex.c | 183 | ||||
-rw-r--r-- | usr.sbin/gspa/gspa/gsp_out.c | 182 | ||||
-rw-r--r-- | usr.sbin/gspa/gspa/gsp_pseu.c | 148 | ||||
-rw-r--r-- | usr.sbin/gspa/gspa/gsp_sym.c | 192 | ||||
-rw-r--r-- | usr.sbin/gspa/gspa/gspa.c | 273 | ||||
-rw-r--r-- | usr.sbin/gspa/gspahextoc/Makefile | 6 | ||||
-rw-r--r-- | usr.sbin/gspa/gspahextoc/README | 19 | ||||
-rw-r--r-- | usr.sbin/gspa/gspahextoc/gspahextoc.l | 123 |
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); +} |