This commit is contained in:
Nishi 2026-08-11 20:24:22 +09:00
commit b517afbfad
13 changed files with 2659 additions and 0 deletions

26
LICENSE Normal file
View file

@ -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.

209
gsp_act.c Normal file
View file

@ -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 <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: gsp_act.c,v 1.6 2025/11/24 08:04:28 nia Exp $");
#endif
#include <stdlib.h>
#include <string.h>
#include <util.h>
#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);
}

179
gsp_ass.h Normal file
View file

@ -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 <stddef.h>
#include <sys/types.h>
#include <err.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 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 <alloca.h>
#else
#ifdef __GNUC__
#define alloca __builtin_alloca
#endif
#endif
#define new(x) ((x) = emalloc(sizeof(*(x))))

39
gsp_code.h Normal file
View file

@ -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

143
gsp_eval.c Normal file
View file

@ -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 <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: gsp_eval.c,v 1.5 2025/11/24 08:04:28 nia Exp $");
#endif
#include <stdlib.h>
#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);
}
}

126
gsp_gram.y Normal file
View file

@ -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 <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: gsp_gram.y,v 1.4 2025/11/24 08:04:28 nia Exp $");
#endif
#include <stdio.h>
#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); }
;

760
gsp_inst.c Normal file
View file

@ -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 <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: gsp_inst.c,v 1.12 2025/11/24 08:04:28 nia Exp $");
#endif
#include <string.h>
#include <assert.h>
#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;
}

191
gsp_lex.c Normal file
View file

@ -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 <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: gsp_lex.c,v 1.10 2025/11/24 08:04:28 nia Exp $");
#endif
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#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;
}

250
gsp_out.c Normal file
View file

@ -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 <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: gsp_out.c,v 1.11 2025/11/24 08:04:28 nia Exp $");
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <util.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[];
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;
}

152
gsp_pseu.c Normal file
View file

@ -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 <sys/cdefs.h>
#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");
}

204
gsp_sym.c Normal file
View file

@ -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 <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: gsp_sym.c,v 1.10 2025/11/24 08:04:28 nia Exp $");
#endif
#include <stdio.h>
#include <string.h>
#include <util.h>
#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;
}
}
}
}
}

87
gspa.8 Normal file
View file

@ -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 .

293
gspa.c Normal file
View file

@ -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 <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: gspa.c,v 1.16 2025/11/24 08:04:28 nia Exp $");
#endif
#include <sys/param.h>
#include <err.h>
#include <errno.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <util.h>
#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, "<stdin>", 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 <sys/types.h>\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);
}