import
This commit is contained in:
commit
b517afbfad
13 changed files with 2659 additions and 0 deletions
26
LICENSE
Normal file
26
LICENSE
Normal 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
209
gsp_act.c
Normal 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
179
gsp_ass.h
Normal 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
39
gsp_code.h
Normal 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
143
gsp_eval.c
Normal 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
126
gsp_gram.y
Normal 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
760
gsp_inst.c
Normal 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
191
gsp_lex.c
Normal 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
250
gsp_out.c
Normal 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
152
gsp_pseu.c
Normal 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
204
gsp_sym.c
Normal 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
87
gspa.8
Normal 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
293
gspa.c
Normal 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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue