commit b517afbfad4465ae124f5420b545a753d7d684de Author: Nishi Date: Tue Aug 11 20:24:22 2026 +0900 import diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f1d4283 --- /dev/null +++ b/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 1993 Paul Mackerras. +Copyright (c) 2002 The NetBSD Foundation, Inc. +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. 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. + diff --git a/gsp_act.c b/gsp_act.c new file mode 100644 index 0000000..7b45286 --- /dev/null +++ b/gsp_act.c @@ -0,0 +1,209 @@ +/* $NetBSD: gsp_act.c,v 1.6 2025/11/24 08:04:28 nia Exp $ */ +/* + * 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. 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. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: gsp_act.c,v 1.6 2025/11/24 08:04:28 nia Exp $"); +#endif + +#include +#include +#include +#include "gsp_ass.h" + +void +free_operands(operand l) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + operand o; + + o = reg_ind(reg, M_INDEX); + o->op_u.value = disp; + return o; +} + +expr +id_expr(char *id) +{ + 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) +{ + expr x; + +/* printf("num_expr val=%d\n", val); */ + new(x); + x->e_op = CONST; + x->e_val = val; + return x; +} + +expr +here_expr() +{ + expr x; + +/* printf("here_expr()\n"); */ + new(x); + x->e_op = '.'; + return x; +} + +expr +bexpr(int op, expr l, expr r) +{ + 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(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/gsp_ass.h b/gsp_ass.h new file mode 100644 index 0000000..30d30c8 --- /dev/null +++ b/gsp_ass.h @@ -0,0 +1,179 @@ +/* $NetBSD: gsp_ass.h,v 1.14 2025/11/24 08:04:28 nia Exp $ */ +/* + * 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. 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. + */ + +#include +#include +#include + +#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 GSPA_A0 0x20 +#define GSPA_B0 0x50 +#define GSPA_SP 0x6F /* (r1 & r2 & REGFILE) != 0 iff */ +#define GSPA_REGFILE 0x60 /* r1 and r2 are in the same file */ + +/* Prototypes */ +operand abs_adr(expr); +operand add_operand(operand, operand); +expr bexpr(int, expr, expr); +void do_asg(char *, expr, int flags); +void do_list_pc(void); +void do_show_val(int32_t); +int eval_expr(expr, int32_t *, unsigned *); +operand expr_op(expr); +expr fold(expr); +void free_expr(expr); +void free_operands(operand); +int get_line(char *lp, int maxlen); +expr here_expr(void); +expr id_expr(char *); +void lex_init(char *line); +void list_error(char *); +void listing(void); +symbol lookup(char *id, bool makeit); +expr num_expr(int); +void p1err(const char *fmt, ...) __printflike(1, 2); +void perr(const char *fmt, ...) __printflike(1, 2); +void pseudo(int code, operand operands); +void push_input(char *fn); +void putcode(u_int16_t *, int); +operand reg_ind(int, int); +operand reg_index(int, expr); +operand reg_indxy(int, char *); +operand reg_op(int reg); +void reset_numeric_labels(void); +void set_label(char *); +void set_numeric_label(int); +void start_at(u_int32_t); +void statement(char *opcode, operand operands); +operand string_op(char *); +void ucasify(char *); +__dead void yyerror(const char *err); +int yylex(void); + + +extern unsigned pc; +extern short pass2; + +extern unsigned lineno; +extern int err_count; +extern char line[], *lineptr; + +#if defined(sparc) && !defined(__NetBSD__) +#include +#else +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif +#endif + +#define new(x) ((x) = emalloc(sizeof(*(x)))) diff --git a/gsp_code.h b/gsp_code.h new file mode 100644 index 0000000..37f8676 --- /dev/null +++ b/gsp_code.h @@ -0,0 +1,39 @@ +/* $NetBSD: gsp_code.h,v 1.4 2025/11/24 08:04:28 nia Exp $ */ +/* + * 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. 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. + */ + +/*#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/gsp_eval.c b/gsp_eval.c new file mode 100644 index 0000000..f3af2fd --- /dev/null +++ b/gsp_eval.c @@ -0,0 +1,143 @@ +/* $NetBSD: gsp_eval.c,v 1.5 2025/11/24 08:04:28 nia Exp $ */ +/* + * 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. 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. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: gsp_eval.c,v 1.5 2025/11/24 08:04:28 nia Exp $"); +#endif + +#include +#include "gsp_ass.h" +#include "gsp_gram.h" + +int32_t eval_op(int, int32_t, int32_t); +int32_t eval_subtree(expr, unsigned *); + +expr +fold(expr x) +{ + int32_t l; + 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, int32_t l, 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) +{ + 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/gsp_gram.y b/gsp_gram.y new file mode 100644 index 0000000..737cd9b --- /dev/null +++ b/gsp_gram.y @@ -0,0 +1,126 @@ +/* $NetBSD: gsp_gram.y,v 1.4 2025/11/24 08:04:28 nia Exp $ */ +/* + * 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. 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. + */ + +/* declarations */ + +%{ +#include +#ifndef lint +__RCSID("$NetBSD: gsp_gram.y,v 1.4 2025/11/24 08:04:28 nia Exp $"); +#endif + +#include +#include "gsp_ass.h" +%} + +%union { + long y_int; + char *y_id; + expr y_expr; + operand y_opnd; +} + +%token LEFT_SHIFT, RIGHT_SHIFT + +%term ID, STRING +%term 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 expr +%type 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/gsp_inst.c b/gsp_inst.c new file mode 100644 index 0000000..3dde934 --- /dev/null +++ b/gsp_inst.c @@ -0,0 +1,760 @@ +/* $NetBSD: gsp_inst.c,v 1.12 2025/11/24 08:04:28 nia Exp $ */ +/* + * 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. 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. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: gsp_inst.c,v 1.12 2025/11/24 08:04:28 nia Exp $"); +#endif + +#include +#include +#include "gsp_ass.h" +#include "gsp_code.h" + +struct inst { + const 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, 0, 0, {0, 0, 0, 0}} +}; + +int check_spec(int spec, const char *valid, const char *what); +void do_statement(char *opcode, operand operands); +int encode_instr(struct inst *ip, operand ops, int *spec, u_int16_t *iwords); +int specifier(operand op); + +void +statement(char *opcode, operand operands) +{ + do_statement(opcode, operands); + free_operands(operands); +} + +void +do_statement(char *opcode, operand operands) +{ + struct inst *ip; + int i, req; + unsigned nop; + 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 %u", nop+1); + return; + } + if( (req & ~OPTOPRN) == SPEC ) { + if (nop >= sizeof(spec) / sizeof(spec[0])) { + perr("Spec out of bounds"); + return; + } + /* 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); +} + +const char *specs[] = { "B", "L", "W", "XY", NULL }; + +int +specifier(operand op) +{ + const char **sl; + 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, const char *valid, const char *what) +{ + 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) +{ + int rs, rd; + int opc, nw, class, flags, ms, md, off; + int mask, file, bit, i; + operand op0, op1; + unsigned eline[2]; + int32_t val[2]; + + rs = rd = 0; + 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], &eline[0]); + op1 = ops->next; + if( op1 != NULL && spec[1] == 0 && USES_EXPR(op1) ) + eval_expr(op1->op_u.value, &val[1], &eline[1]); + } else + op1 = NULL; + class = ip->class & CLASS; + flags = ip->class & ~CLASS; + if (class == MOVE && op0 && op1 && op1->type == REG) { + if (op0->type == REG) { + class = DYADIC; + if ((op0->reg_no & op1->reg_no & GSPA_REGFILE) == 0) { + opc += 0x0200; + op1->reg_no ^= GSPA_A0 ^ GSPA_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 && eline[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 && 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 & GSPA_REGFILE) == 0) + perr("Registers must be in the same register file"); + /* force SP to the file of the other operand */ + if (rs == GSPA_SP) + rs |= rd; + if (rd == GSPA_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 && eline[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 && op0->type == REG ){ + opc |= rs & 0x1F; + break; + } + off = (int)(val[0] - pc - 0x20) >> 4; + if( opc == 0x0920 ){ /* CALL */ + if( eline[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 && 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 & GSPA_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 & GSPA_A0 & GSPA_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 && op0->type == REG? M_REG: op0->mode; + assert(op1 != NULL); + 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", class); + } + iwords[0] = opc; + return nw; +} + diff --git a/gsp_lex.c b/gsp_lex.c new file mode 100644 index 0000000..39becc1 --- /dev/null +++ b/gsp_lex.c @@ -0,0 +1,191 @@ +/* $NetBSD: gsp_lex.c,v 1.10 2025/11/24 08:04:28 nia Exp $ */ +/* + * 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. 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. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: gsp_lex.c,v 1.10 2025/11/24 08:04:28 nia Exp $"); +#endif + +#include +#include +#include +#include + +#include "gsp_ass.h" +#include "gsp_gram.h" + +char *lineptr; + +char idents[MAXLINE]; +char *idptr; + +extern YYSTYPE yylval; + +int str_match(const char *, const char **); + +const 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[] = { + GSPA_A0+0, GSPA_A0+1, GSPA_A0+2, GSPA_A0+3, + GSPA_A0+4, GSPA_A0+5, GSPA_A0+6, GSPA_A0+7, + GSPA_A0+8, GSPA_A0+9, GSPA_A0+10, GSPA_A0+11, + GSPA_A0+12, GSPA_A0+13, GSPA_A0+14, GSPA_SP, + GSPA_B0+0, GSPA_B0+1, GSPA_B0+2, GSPA_B0+3, + GSPA_B0+4, GSPA_B0+5, GSPA_B0+6, GSPA_B0+7, + GSPA_B0+8, GSPA_B0+9, GSPA_B0+10, GSPA_B0+11, + GSPA_B0+12, GSPA_B0+13, GSPA_B0+14, GSPA_B0+15, +}; + +void +lex_init(char *lline) +{ + lineptr = lline; + idptr = idents; +} + +int +yylex() +{ + int c, tok, x, len; + 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((unsigned char)lp[1]) || lp[1] == '_') ){ + /* reference to numeric label */ + c = toupper(c); + sprintf(idptr, "%ld%c", (long)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(char *p) +{ + int c; + + for( ; (c = *p) != 0; p++ ) + if( islower(c) ) + *p = toupper(c); +} + +int +str_match(const char *id, const char **names) +{ + const char **np; + + for( np = names; *np != NULL; ++np ) + if( strcmp(id, *np) == 0 ) + return np - names; + return -1; +} diff --git a/gsp_out.c b/gsp_out.c new file mode 100644 index 0000000..ced2b06 --- /dev/null +++ b/gsp_out.c @@ -0,0 +1,250 @@ +/* $NetBSD: gsp_out.c,v 1.11 2025/11/24 08:04:28 nia Exp $ */ +/* + * 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. 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. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: gsp_out.c,v 1.11 2025/11/24 08:04:28 nia Exp $"); +#endif + +#include +#include +#include +#include +#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[]; + +extern char *c_name; +u_int16_t c_buf[4096]; +u_int32_t c_bufptr, c_binads; + +void c_checkbuf(void); +void c_dumpbuf(void); + +struct error { + struct error *next; + char string[1]; +}; + +struct error *error_list, *error_last; + +void do_list_pc(void); +void do_show_val(int32_t); +void listing_line(void); +void put1code(u_int16_t); +void show_errors(void); + +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 ){ + if (c_name) { + if (c_bufptr > 0) + c_dumpbuf(); + c_binads = pc; + c_bufptr = 0; + } else { + /* 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) && !c_name) + fprintf(objfile, " "); + } + if (c_name) { + c_checkbuf(); + c_buf[c_bufptr++] = v; + } else + fprintf(objfile, "%.4X", v & 0xFFFF); + obj_addr += 0x10; + if((ncode % 8 == 7) && !c_name) + fprintf(objfile, "\n"); + } + ++ncode; + ++code_idx; + pc += 0x10; + show_pc = TRUE; +} + +void +c_checkbuf() +{ + if (c_bufptr > (sizeof(c_buf)/sizeof(*c_buf))) + c_dumpbuf(); +} + +void +c_dumpbuf() +{ + uint32_t i; + + fprintf(objfile, "\n\n\t%d, 0x%04x, 0x%04x, /* new block */", + c_bufptr, (int)(c_binads >> 16), (int)(c_binads & 0xffff)); + + for (i=0; i < c_bufptr; ++i) { + if (i%8 == 0) + fprintf(objfile, "\n\t"); + fprintf(objfile, "0x%04x, ", c_buf[i]); + } + c_binads += c_bufptr; + c_bufptr = 0; +} + +void +start_at(u_int32_t val) +{ + if( objfile != NULL ) { + if (c_name) { + c_checkbuf(); + fprintf(objfile, + "\n\n\t2, 0xffff, 0xfee0, 0x%04x, 0x%04x," + "\n\t2, 0xffff, 0xffe0, 0x%04x, 0x%04x,\n", + val & 0xffff, val >> 16, val & 0xffff, val >> 16); + } else + fprintf(objfile, ":%lX\n", (long)val); + } +} + +void +do_list_pc() +{ + if( pass2 ) + show_pc = TRUE; +} + +void +do_show_val(int32_t v) +{ + if( ncode == 0 ){ + val_to_show = v; + show_val = TRUE; + show_pc = FALSE; + } +} + +void +list_error(char *string) +{ + struct error *p; + int l; + + if( listfile == NULL ) + return; + l = strlen(string); + p = emalloc(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; +} + +void +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; +} + +void +listing() +{ + if( objfile != NULL && ncode % 8 != 0 && !c_name) + fprintf(objfile, "\n"); + listing_line(); + show_errors(); + ncode = 0; + show_pc = FALSE; +} + +void +listing_line() +{ + unsigned 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/gsp_pseu.c b/gsp_pseu.c new file mode 100644 index 0000000..6865a5a --- /dev/null +++ b/gsp_pseu.c @@ -0,0 +1,152 @@ +/* $NetBSD: gsp_pseu.c,v 1.4 2025/11/24 08:04:28 nia Exp $ */ +/* + * 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. 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. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: gsp_pseu.c,v 1.4 2025/11/24 08:04:28 nia Exp $"); +#endif + +#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/gsp_sym.c b/gsp_sym.c new file mode 100644 index 0000000..d16047d --- /dev/null +++ b/gsp_sym.c @@ -0,0 +1,204 @@ +/* $NetBSD: gsp_sym.c,v 1.10 2025/11/24 08:04:28 nia Exp $ */ +/* + * 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. 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. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: gsp_sym.c,v 1.10 2025/11/24 08:04:28 nia Exp $"); +#endif + +#include +#include +#include +#include "gsp_ass.h" + +#define NHASH 64 /* must be power of 2 */ + +symbol symbol_hash[NHASH]; + +void define_sym(char *, unsigned, unsigned, int); + +symbol +lookup(char *id, bool makeit) +{ + symbol ptr, p, *pp; + int h; + 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 = emalloc(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 lno, int flags) +{ + 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 = lno; +} + +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 lno; + + if( eval_expr(value, &val, &lno) ) + flags |= DEFINED; + if( lno < lineno ) + lno = lineno; + define_sym(name, val, lno, flags); + if( pass2 ) + do_show_val(val); +} + +void +set_numeric_label(int lnum) +{ + symbol bp, fp; + 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() +{ + symbol p; + struct numlab *nl; + 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/gspa.8 b/gspa.8 new file mode 100644 index 0000000..f1987bf --- /dev/null +++ b/gspa.8 @@ -0,0 +1,87 @@ +.\" $NetBSD: gspa.8,v 1.4 2008/04/30 13:11:02 martin Exp $ +.\" +.\" Copyright (c) 2002 The NetBSD Foundation, Inc. +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``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 FOUNDATION OR CONTRIBUTORS +.\" 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. +.\" +.Dd May 27, 2002 +.Dt GSPA 8 +.Os +.Sh NAME +.Nm gspa +.Nd assembler for the GSP chip +.Sh SYNOPSIS +.Nm +.Op Fl c Ar c_array_name +.Op Fl l Ar list_file +.Op Fl o Ar hex_file +.Op infile +.Sh DESCRIPTION +.Nm +is an assembler for the TMS34010 and TMS34020 graphics processor +chips. +.Pp +The supported options are: +.Bl -tag -width xxxlistname -compact +.It Fl c Ar c_array_name +Create a pre-initialized C-structure +.Ar c_array_name +with the hex code of the assembler output. +.It Fl l Ar list_file +Create commented (with the input file) hex code of the assembler +output in +.Ar list_file . +.It Fl o Ar hex_file +Create the output in +.Ar hex_file . +If +.Fl c +is used, C code will be written to +.Ar hex_file , +otherwise uncommented hex code of the assembler output will be +written. +.El +.Pp +If no +.Fl o +option is given, output will be written to stdout. +.Pp +If no +.Ar infile +is given, input will be read from stdin. +.Sh HISTORY +.Nm +appeared in +.Nx 1.1 . +.Sh AUTHORS +.Nm +was written by +.An Paul Mackerras . +The +.Fl c +mode was added by +.An Ignatios Souvatzis +.Aq is@NetBSD.org . +This man page was written by +.An Thomas Klausner +.Aq wiz@NetBSD.org . diff --git a/gspa.c b/gspa.c new file mode 100644 index 0000000..1250708 --- /dev/null +++ b/gspa.c @@ -0,0 +1,293 @@ +/* $NetBSD: gspa.c,v 1.16 2025/11/24 08:04:28 nia Exp $ */ +/* + * 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. 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. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: gspa.c,v 1.16 2025/11/24 08:04:28 nia Exp $"); +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gsp_ass.h" +#include "gsp_gram.h" + +#define YYDEBUG_VALUE 0 + +extern YYSTYPE yylval; +int err_count; + +char line[MAXLINE]; +unsigned lineno; + +extern int yydebug; +short pass2; + +unsigned pc; +unsigned highest_pc; +unsigned line_pc; + +FILE *infile; +FILE *current_infile; +FILE *objfile; +FILE *listfile; + +char *c_name; +char in_name[PATH_MAX + 1]; + +struct input { + FILE *fp; + struct input *next; + int lineno; + char name[128]; +} *pending_input; + +jmp_buf synerrjmp; + +void setext(char *, const char *, const char *); +__dead static void usage(void); +int yyparse(void); + +void c_dumpbuf(void); + +int +main(int argc, char **argv) +{ + char * volatile hex_name; + char * volatile list_name; + int c; + + hex_name = list_name = 0; + + /* parse options */ + while ((c = getopt(argc, argv, "o:l:c:")) != -1) { + switch (c) { + case 'o': + if (hex_name) + usage(); + hex_name = optarg; + break; + case 'c': + if (c_name) + usage(); + c_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; + strlcpy(in_name, "", sizeof(in_name)); + } else if (argc == 1) { + strlcpy(in_name, *argv, sizeof(in_name)); + 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 (c_name) { + fprintf(objfile, "/*\n" + " * This file was automatically created from\n" + " * a TMS34010 assembler output file.\n" + " * Do not edit manually.\n" + " */\n" + "#include \n" + "u_int16_t %s[] = {\n\t", c_name); + } + 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(); + } + + if (c_name) { + c_dumpbuf(); + fprintf(objfile, "\n\t0\n};\n"); + } + + exit(err_count != 0); +} + +void +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); + } +} + +void +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; + strlcpy(p->name, in_name, sizeof(p->name)); + p->next = pending_input; + current_infile = f; + lineno = 1; + strlcpy(in_name, fn, sizeof(in_name)); + 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; + strlcpy(in_name, p->name, sizeof(in_name)); + lineno = p->lineno; + pending_input = p->next; + free(p); + } + ++lineno; + return 1; +} + +void +perr(const 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(const 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(const char *errs) +{ + + perr("%s", errs); + longjmp(synerrjmp, 1); +} + +static void +usage(void) +{ + fprintf(stderr, + "Usage: gspa [-c c_array_name] [-l list_file] [-o hex_file] [infile]\n"); + exit(1); +}