summaryrefslogtreecommitdiff
path: root/asm
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /asm
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'asm')
-rw-r--r--asm/NOTICE25
-rw-r--r--asm/asm.h149
-rw-r--r--asm/asm.y385
-rw-r--r--asm/assem.c672
-rw-r--r--asm/lex.c685
-rw-r--r--asm/mkfile21
6 files changed, 1937 insertions, 0 deletions
diff --git a/asm/NOTICE b/asm/NOTICE
new file mode 100644
index 00000000..84818206
--- /dev/null
+++ b/asm/NOTICE
@@ -0,0 +1,25 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory. If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below. It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+Copyright © 1995-1999 Lucent Technologies Inc.
+Portions Copyright © 1997-2000 Vita Nuova Limited
+Portions Copyright © 2000-2006 Vita Nuova Holdings Limited
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
diff --git a/asm/asm.h b/asm/asm.h
new file mode 100644
index 00000000..15150664
--- /dev/null
+++ b/asm/asm.h
@@ -0,0 +1,149 @@
+#include "lib9.h"
+#include <bio.h>
+#include <ctype.h>
+#include "../include/isa.h"
+
+enum
+{
+ Eof = -1,
+ False = 0,
+ True = 1,
+ Strsize = 1024,
+ Hashsize = 128
+};
+
+typedef struct Addr Addr;
+typedef struct Inst Inst;
+typedef struct String String;
+typedef struct Sym Sym;
+typedef struct Keywd Keywd;
+typedef struct Desc Desc;
+typedef struct Array Array;
+typedef struct List List;
+typedef struct Link Link;
+
+struct Addr
+{
+ uchar mode;
+ ushort off;
+ long val;
+ Sym* sym;
+};
+
+struct List
+{
+ List* link;
+ int addr;
+ int type;
+ union {
+ vlong ival;
+ double fval;
+ String* str;
+ Array* a;
+ }u;
+};
+
+struct Inst
+{
+ uchar op;
+ uchar type;
+ int size;
+ Addr* reg;
+ Addr* src;
+ Addr* dst;
+ ulong pc;
+ Sym* sym;
+ Inst* link;
+};
+
+struct String
+{
+ int len;
+ String* next;
+ char* string;
+};
+
+struct Sym
+{
+ char* name;
+ int lexval;
+ Sym* hash;
+ int value;
+ int ds;
+};
+
+struct Desc
+{
+ int id;
+ int size;
+ int np;
+ uchar* map;
+ Desc* link;
+};
+
+struct Array
+{
+ int i;
+ int size;
+};
+
+struct Link
+{
+ int desc;
+ int addr;
+ int type;
+ char* name;
+ Link* link;
+};
+
+Sym* enter(char*, int);
+Sym* lookup(char*);
+void yyerror(char*, ...);
+void fatal(char*, ...);
+void diag(char*, ...);
+int numsym(char);
+int mpatof(char*, double*);
+void kinit(void);
+Inst* ai(int);
+Addr* aa(int);
+void assem(Inst*);
+int iconv(Fmt*);
+int aconv(Fmt*);
+int opcode(Inst*);
+void heap(int, int, String*);
+List* newa(int, int);
+List* newi(vlong, List*);
+List* news(String*, List*);
+void data(int, int, List*);
+void dout(void);
+void ext(int, int, String*);
+void mklink(int, int, int, String*);
+vlong dtocanon(double);
+void ldts(int);
+void excs(int);
+void exc(int, int, int, int, int, int);
+void etab(String*, int);
+void source(String*);
+
+int yyparse(void);
+int yylex(void);
+
+extern Biobuf* bout;
+extern int nerr;
+extern int heapid;
+extern Desc* dlist;
+extern int dcount;
+extern int dseg;
+extern List* mdata;
+extern Sym* module;
+extern Link* links;
+extern Link* linkt;
+extern int nlink;
+extern int listing;
+extern int dontcompile;
+extern int mustcompile;
+extern int dentry;
+extern int pcentry;
+
+#pragma varargck type "i" Inst*
+#pragma varargck type "a" Addr*
diff --git a/asm/asm.y b/asm/asm.y
new file mode 100644
index 00000000..8a94c99b
--- /dev/null
+++ b/asm/asm.y
@@ -0,0 +1,385 @@
+%{
+#include "asm.h"
+union {
+ uvlong l;
+ double d;
+} u;
+%}
+
+%union
+{
+ Inst* inst;
+ Addr* addr;
+ vlong ival;
+ double fval;
+ String* string;
+ Sym* sym;
+ List* list;
+}
+
+%left '|'
+%left '^'
+%left '&'
+%left '<' '>'
+%left '+' '-'
+%left '*' '/' '%'
+
+%type<inst> label ilist inst
+%type<ival> con expr heapid
+%type<addr> addr raddr mem roff
+%type<list> elist
+%type<string> ptrs
+%token<ival> TOKI0 TOKI1 TOKI2 TOKI3 TCONST
+%token TOKSB TOKFP TOKHEAP TOKDB TOKDW TOKDL TOKDF TOKDS TOKVAR
+%token TOKEXT TOKMOD TOKLINK TOKENTRY TOKARRAY TOKINDIR TOKAPOP TOKLDTS TOKEXCS TOKEXC TOKETAB TOKSRC
+%token<sym> TID
+%token<fval> TFCONST
+%token<string> TSTRING
+
+%%
+prog : ilist
+ {
+ assem($1);
+ }
+ ;
+
+ilist :
+ { $$ = nil; }
+ | ilist label
+ {
+ if($2 != nil) {
+ $2->link = $1;
+ $$ = $2;
+ }
+ else
+ $$ = $1;
+ }
+ ;
+
+label : TID ':' inst
+ {
+ $3->sym = $1;
+ $$ = $3;
+ }
+ | TOKHEAP heapid ',' expr ptrs
+ {
+ heap($2, $4, $5);
+ $$ = nil;
+ }
+ | data
+ {
+ $$ = nil;
+ }
+ | inst
+ ;
+
+heapid : '$' expr
+ {
+ $$ = $2;
+ }
+ | TID
+ {
+ $1->value = heapid++;
+ $$ = $1->value;
+ }
+ ;
+
+ptrs :
+ { $$ = nil; }
+ | ',' TSTRING
+ {
+ $$ = $2;
+ }
+ ;
+
+elist : expr
+ {
+ $$ = newi($1, nil);
+ }
+ | elist ',' expr
+ {
+ $$ = newi($3, $1);
+ }
+ ;
+
+inst : TOKI3 addr ',' addr
+ {
+ $$ = ai($1);
+ $$->src = $2;
+ $$->dst = $4;
+ }
+ | TOKI3 addr ',' raddr ',' addr
+ {
+ $$ = ai($1);
+ $$->src = $2;
+ $$->reg = $4;
+ $$->dst = $6;
+ }
+ | TOKI2 addr ',' addr
+ {
+ $$ = ai($1);
+ $$->src = $2;
+ $$->dst = $4;
+ }
+ | TOKI1 addr
+ {
+ $$ = ai($1);
+ $$->dst = $2;
+ }
+ | TOKI0
+ {
+ $$ = ai($1);
+ }
+ ;
+
+data : TOKDB expr ',' elist
+ {
+ data(DEFB, $2, $4);
+ }
+ | TOKDW expr ',' elist
+ {
+ data(DEFW, $2, $4);
+ }
+ | TOKDL expr ',' elist
+ {
+ data(DEFL, $2, $4);
+ }
+ | TOKDF expr ',' TCONST
+ {
+ data(DEFF, $2, newi(dtocanon((double)$4), nil));
+ }
+ | TOKDF expr ',' TFCONST
+ {
+ data(DEFF, $2, newi(dtocanon($4), nil));
+ }
+ | TOKDF expr ',' TID
+ {
+ if(strcmp($4->name, "Inf") == 0 || strcmp($4->name, "Infinity") == 0) {
+ u.l = 0x7ff0000000000000;
+ data(DEFF, $2, newi(dtocanon(u.d), nil));
+ } else if(strcmp($4->name, "NaN") == 0) {
+ u.l = 0x7fffffffffffffff;
+ data(DEFF, $2, newi(dtocanon(u.d), nil));
+ } else
+ diag("bad value for real: %s", $4->name);
+ }
+ | TOKDF expr ',' '-' TCONST
+ {
+ data(DEFF, $2, newi(dtocanon(-(double)$5), nil));
+ }
+ | TOKDF expr ',' '-' TFCONST
+ {
+ data(DEFF, $2, newi(dtocanon(-$5), nil));
+ }
+ | TOKDF expr ',' '-' TID
+ {
+ if(strcmp($5->name, "Inf") == 0 || strcmp($5->name, "Infinity") == 0) {
+ u.l = 0xfff0000000000000;
+ data(DEFF, $2, newi(dtocanon(u.d), nil));
+ } else
+ diag("bad value for real: %s", $5->name);
+ }
+ | TOKDS expr ',' TSTRING
+ {
+ data(DEFS, $2, news($4, nil));
+ }
+ | TOKVAR TID ',' expr
+ {
+ if($2->ds != 0)
+ diag("%s declared twice", $2->name);
+ $2->ds = $4;
+ $2->value = dseg;
+ dseg += $4;
+ }
+ | TOKEXT expr ',' expr ',' TSTRING
+ {
+ ext($2, $4, $6);
+ }
+ | TOKLINK expr ',' expr ',' expr ',' TSTRING
+ {
+ mklink($2, $4, $6, $8);
+ }
+ | TOKMOD TID
+ {
+ if(module != nil)
+ diag("this module already defined as %s", $2->name);
+ else
+ module = $2;
+ }
+ | TOKENTRY expr ',' expr
+ {
+ if(pcentry >= 0)
+ diag("this module already has entry point %d, %d" , pcentry, dentry);
+ pcentry = $2;
+ dentry = $4;
+ }
+ | TOKARRAY expr ',' heapid ',' expr
+ {
+ data(DEFA, $2, newa($4, $6));
+ }
+ | TOKINDIR expr ',' expr
+ {
+ data(DIND, $2, newa($4, 0));
+ }
+ | TOKAPOP
+ {
+ data(DAPOP, 0, newa(0, 0));
+ }
+ | TOKLDTS TID ',' expr
+ {
+ ldts($4);
+ }
+ | TOKEXCS expr
+ {
+ excs($2);
+ }
+ | TOKEXC expr ',' expr ',' expr ',' expr ',' expr ',' expr
+ {
+ exc($2, $4, $6, $8, $10, $12);
+ }
+ | TOKETAB TSTRING ',' expr
+ {
+ etab($2, $4);
+ }
+ | TOKETAB '*' ',' expr
+ {
+ etab(nil, $4);
+ }
+ | TOKSRC TSTRING
+ {
+ source($2);
+ }
+ ;
+
+raddr : '$' expr
+ {
+ $$ = aa($2);
+ $$->mode = AXIMM;
+ if($$->val > 0x7FFF || $$->val < -0x8000)
+ diag("immediate %d too large for middle operand", $$->val);
+ }
+ | roff
+ {
+ if($1->mode == AMP)
+ $1->mode = AXINM;
+ else
+ $1->mode = AXINF;
+ if($1->mode == AXINM && (ulong)$1->val > 0xFFFF)
+ diag("register offset %d(mp) too large", $1->val);
+ if($1->mode == AXINF && (ulong)$1->val > 0xFFFF)
+ diag("register offset %d(fp) too large", $1->val);
+ $$ = $1;
+ }
+ ;
+
+addr : '$' expr
+ {
+ $$ = aa($2);
+ $$->mode = AIMM;
+ }
+ | TID
+ {
+ $$ = aa(0);
+ $$->sym = $1;
+ }
+ | mem
+ ;
+
+mem : '*' roff
+ {
+ $2->mode |= AIND;
+ $$ = $2;
+ }
+ | expr '(' roff ')'
+ {
+ $3->mode |= AIND;
+ if($3->val & 3)
+ diag("indirect offset must be word size");
+ if($3->mode == (AMP|AIND) && ((ulong)$3->val > 0xFFFF || (ulong)$1 > 0xFFFF))
+ diag("indirect offset %d(%d(mp)) too large", $1, $3->val);
+ if($3->mode == (AFP|AIND) && ((ulong)$3->val > 0xFFFF || (ulong)$1 > 0xFFFF))
+ diag("indirect offset %d(%d(fp)) too large", $1, $3->val);
+ $3->off = $3->val;
+ $3->val = $1;
+ $$ = $3;
+ }
+ | roff
+ ;
+
+roff : expr '(' TOKSB ')'
+ {
+ $$ = aa($1);
+ $$->mode = AMP;
+ }
+ | expr '(' TOKFP ')'
+ {
+ $$ = aa($1);
+ $$->mode = AFP;
+ }
+ ;
+
+con : TCONST
+ | TID
+ {
+ $$ = $1->value;
+ }
+ | '-' con
+ {
+ $$ = -$2;
+ }
+ | '+' con
+ {
+ $$ = $2;
+ }
+ | '~' con
+ {
+ $$ = ~$2;
+ }
+ | '(' expr ')'
+ {
+ $$ = $2;
+ }
+ ;
+
+expr: con
+ | expr '+' expr
+ {
+ $$ = $1 + $3;
+ }
+ | expr '-' expr
+ {
+ $$ = $1 - $3;
+ }
+ | expr '*' expr
+ {
+ $$ = $1 * $3;
+ }
+ | expr '/' expr
+ {
+ $$ = $1 / $3;
+ }
+ | expr '%' expr
+ {
+ $$ = $1 % $3;
+ }
+ | expr '<' '<' expr
+ {
+ $$ = $1 << $4;
+ }
+ | expr '>' '>' expr
+ {
+ $$ = $1 >> $4;
+ }
+ | expr '&' expr
+ {
+ $$ = $1 & $3;
+ }
+ | expr '^' expr
+ {
+ $$ = $1 ^ $3;
+ }
+ | expr '|' expr
+ {
+ $$ = $1 | $3;
+ }
+ ;
diff --git a/asm/assem.c b/asm/assem.c
new file mode 100644
index 00000000..9b12c503
--- /dev/null
+++ b/asm/assem.c
@@ -0,0 +1,672 @@
+#include "asm.h"
+#include "y.tab.h"
+
+typedef struct Exc Exc;
+typedef struct Etab Etab;
+typedef struct Ldts Ldts;
+typedef struct Ldt Ldt;
+
+struct Ldts
+{
+ int n;
+ Ldt *ldt;
+ Ldts *next;
+};
+
+struct Ldt{
+ int sign;
+ char *name;
+ Ldt *next;
+};
+
+struct Exc
+{
+ int n1, n2, n3, n4, n5, n6;
+ Etab *etab;
+ Exc *next;
+};
+
+struct Etab
+{
+ int n;
+ char *name;
+ Etab *next;
+};
+
+static int inldt;
+static int nldts;
+static Ldts *aldts;
+static Ldts *curl;
+static int nexcs;
+static Exc* aexcs;
+static Exc* cure;
+static char *srcpath;
+
+static void ldtw(int);
+static void ldte(int, char*);
+
+List*
+newa(int i, int size)
+{
+ List *l;
+ Array *a;
+
+ a = malloc(sizeof(Array));
+ a->i = i;
+ a->size = size;
+ l = malloc(sizeof(List));
+ l->u.a = a;
+ l->link = nil;
+
+ return l;
+}
+
+List*
+newi(vlong v, List *l)
+{
+ List *n, *t;
+
+ n = malloc(sizeof(List));
+ if(l == nil)
+ l = n;
+ else {
+ for(t = l; t->link; t = t->link)
+ ;
+ t->link = n;
+ }
+ n->link = nil;
+ n->u.ival = v;
+ n->addr = -1;
+
+ return l;
+}
+
+List*
+news(String *s, List *l)
+{
+ List *n;
+
+ n = malloc(sizeof(List));
+ n->link = l;
+ l = n;
+ n->u.str = s;
+ n->addr = -1;
+ return l;
+}
+
+int
+digit(char x)
+{
+ if(x >= 'A' && x <= 'F')
+ return x - 'A' + 10;
+ if(x >= 'a' && x <= 'f')
+ return x - 'a' + 10;
+ if(x >= '0' && x <= '9')
+ return x - '0';
+ diag("bad hex value in pointers");
+ return 0;
+}
+
+void
+heap(int id, int size, String *ptr)
+{
+ Desc *d, *f;
+ char *p;
+ int k, i;
+
+ d = malloc(sizeof(Desc));
+ d->id = id;
+ d->size = size;
+ size /= IBY2WD;
+ d->map = malloc(size);
+ d->np = 0;
+ if(dlist == nil)
+ dlist = d;
+ else {
+ for(f = dlist; f->link != nil; f = f->link)
+ ;
+ f->link = d;
+ }
+ d->link = nil;
+ dcount++;
+
+ if(ptr == 0)
+ return;
+ if(--ptr->len & 1) {
+ diag("pointer descriptor has bad length");
+ return;
+ }
+
+ k = 0;
+ p = ptr->string;
+ for(i = 0; i < ptr->len; i += 2) {
+ d->map[k++] = (digit(p[0])<<4)|digit(p[1]);
+ if(k > size) {
+ diag("pointer descriptor too long");
+ break;
+ }
+ p += 2;
+ }
+ d->np = k;
+}
+
+void
+conout(int val)
+{
+ if(val >= -64 && val <= 63) {
+ Bputc(bout, val & ~0x80);
+ return;
+ }
+ if(val >= -8192 && val <= 8191) {
+ Bputc(bout, ((val>>8) & ~0xC0) | 0x80);
+ Bputc(bout, val);
+ return;
+ }
+ if(val < 0 && ((val >> 29) & 0x7) != 7
+ || val > 0 && (val >> 29) != 0)
+ diag("overflow in constant 0x%lux\n", val);
+ Bputc(bout, (val>>24) | 0xC0);
+ Bputc(bout, val>>16);
+ Bputc(bout, val>>8);
+ Bputc(bout, val);
+}
+
+void
+aout(Addr *a)
+{
+ if(a == nil)
+ return;
+ if(a->mode & AIND)
+ conout(a->off);
+ conout(a->val);
+}
+
+void
+lout(void)
+{
+ char *p;
+ Link *l;
+
+ if(module == nil)
+ module = enter("main", 0);
+
+ for(p = module->name; *p; p++)
+ Bputc(bout, *p);
+ Bputc(bout, '\0');
+
+ for(l = links; l; l = l->link) {
+ conout(l->addr);
+ conout(l->desc);
+ Bputc(bout, l->type>>24);
+ Bputc(bout, l->type>>16);
+ Bputc(bout, l->type>>8);
+ Bputc(bout, l->type);
+ for(p = l->name; *p; p++)
+ Bputc(bout, *p);
+ Bputc(bout, '\0');
+ }
+}
+
+void
+ldtout(void)
+{
+ Ldts *ls;
+ Ldt *l;
+ char *p;
+
+ conout(nldts);
+ for(ls = aldts; ls != nil; ls = ls->next){
+ conout(ls->n);
+ for(l = ls->ldt; l != nil; l = l->next){
+ Bputc(bout, l->sign>>24);
+ Bputc(bout, l->sign>>16);
+ Bputc(bout, l->sign>>8);
+ Bputc(bout, l->sign);
+ for(p = l->name; *p; p++)
+ Bputc(bout, *p);
+ Bputc(bout, '\0');
+ }
+ }
+ conout(0);
+}
+
+void
+excout(void)
+{
+ Exc *e;
+ Etab *et;
+ char *p;
+
+ if(nexcs == 0)
+ return;
+ conout(nexcs);
+ for(e = aexcs; e != nil; e = e->next){
+ conout(e->n3);
+ conout(e->n1);
+ conout(e->n2);
+ conout(e->n4);
+ conout(e->n5|(e->n6<<16));
+ for(et = e->etab; et != nil; et = et->next){
+ if(et->name != nil){
+ for(p = et->name; *p; p++)
+ Bputc(bout, *p);
+ Bputc(bout, '\0');
+ }
+ conout(et->n);
+ }
+ }
+ conout(0);
+}
+
+void
+srcout(void)
+{
+ char *p;
+
+ for(p = srcpath; *p; p++)
+ Bputc(bout, *p);
+ Bputc(bout, '\0');
+}
+
+void
+assem(Inst *i)
+{
+ Desc *d;
+ Inst *f, *link;
+ int pc, n, hints, o;
+
+ f = 0;
+ while(i) {
+ link = i->link;
+ i->link = f;
+ f = i;
+ i = link;
+ }
+ i = f;
+
+ pc = 0;
+ for(f = i; f; f = f->link) {
+ f->pc = pc++;
+ if(f->sym != nil)
+ f->sym->value = f->pc;
+ }
+
+ if(pcentry >= pc)
+ diag("entry pc out of range");
+ if(dentry >= dcount)
+ diag("entry descriptor out of range");
+
+ conout(XMAGIC);
+ hints = 0;
+ if(mustcompile)
+ hints |= MUSTCOMPILE;
+ if(dontcompile)
+ hints |= DONTCOMPILE;
+ hints |= HASLDT;
+ if(nexcs > 0)
+ hints |= HASEXCEPT;
+ conout(hints); /* Runtime flags */
+ conout(1024); /* default stack size */
+ conout(pc);
+ conout(dseg);
+ conout(dcount);
+ conout(nlink);
+ conout(pcentry);
+ conout(dentry);
+
+ for(f = i; f; f = f->link) {
+ if(f->dst && f->dst->sym) {
+ f->dst->mode = AIMM;
+ f->dst->val = f->dst->sym->value;
+ }
+ o = opcode(f);
+ if(o == IRAISE){
+ f->src = f->dst;
+ f->dst = nil;
+ }
+ Bputc(bout, o);
+ n = 0;
+ if(f->src)
+ n |= SRC(f->src->mode);
+ else
+ n |= SRC(AXXX);
+ if(f->dst)
+ n |= DST(f->dst->mode);
+ else
+ n |= DST(AXXX);
+ if(f->reg)
+ n |= f->reg->mode;
+ else
+ n |= AXNON;
+ Bputc(bout, n);
+ aout(f->reg);
+ aout(f->src);
+ aout(f->dst);
+
+ if(listing)
+ print("%4ld %i\n", f->pc, f);
+ }
+
+ for(d = dlist; d; d = d->link) {
+ conout(d->id);
+ conout(d->size);
+ conout(d->np);
+ for(n = 0; n < d->np; n++)
+ Bputc(bout, d->map[n]);
+ }
+
+ dout();
+ lout();
+ ldtout();
+ excout();
+ srcout();
+}
+
+void
+data(int type, int addr, List *l)
+{
+ List *f;
+
+ if(inldt){
+ ldtw(l->u.ival);
+ return;
+ }
+
+ l->type = type;
+ l->addr = addr;
+
+ if(mdata == nil)
+ mdata = l;
+ else {
+ for(f = mdata; f->link != nil; f = f->link)
+ ;
+ f->link = l;
+ }
+}
+
+void
+ext(int addr, int type, String *s)
+{
+ int i;
+ char *p;
+ List *n;
+
+ if(inldt){
+ ldte(type, s->string);
+ return;
+ }
+
+ data(DEFW, addr, newi(type, nil));
+
+ n = nil;
+ p = s->string;
+ for(i = 0; i < s->len; i++)
+ n = newi(*p++, n);
+ data(DEFB, addr+IBY2WD, n);
+
+ if(addr+s->len > dseg)
+ diag("ext beyond mp");
+}
+
+void
+mklink(int desc, int addr, int type, String *s)
+{
+ Link *l;
+
+ for(l = links; l; l = l->link)
+ if(strcmp(l->name, s->string) == 0)
+ diag("%s already defined", s->string);
+
+ nlink++;
+ l = malloc(sizeof(Link));
+ l->desc = desc;
+ l->addr = addr;
+ l->type = type;
+ l->name = s->string;
+ l->link = nil;
+
+ if(links == nil)
+ links = l;
+ else
+ linkt->link = l;
+ linkt = l;
+}
+
+void
+dout(void)
+{
+ int n, i;
+ List *l, *e;
+
+ e = nil;
+ for(l = mdata; l; l = e) {
+ switch(l->type) {
+ case DEFB:
+ n = 1;
+ for(e = l->link; e && e->addr == -1; e = e->link)
+ n++;
+ if(n < DMAX)
+ Bputc(bout, DBYTE(DEFB, n));
+ else {
+ Bputc(bout, DBYTE(DEFB, 0));
+ conout(n);
+ }
+ conout(l->addr);
+ while(l != e) {
+ Bputc(bout, l->u.ival);
+ l = l->link;
+ }
+ break;
+ case DEFW:
+ n = 1;
+ for(e = l->link; e && e->addr == -1; e = e->link)
+ n++;
+ if(n < DMAX)
+ Bputc(bout, DBYTE(DEFW, n));
+ else {
+ Bputc(bout, DBYTE(DEFW, 0));
+ conout(n);
+ }
+ conout(l->addr);
+ while(l != e) {
+ n = (int)l->u.ival;
+ Bputc(bout, n>>24);
+ Bputc(bout, n>>16);
+ Bputc(bout, n>>8);
+ Bputc(bout, n);
+ l = l->link;
+ }
+ break;
+ case DEFL:
+ n = 1;
+ for(e = l->link; e && e->addr == -1; e = e->link)
+ n++;
+ if(n < DMAX)
+ Bputc(bout, DBYTE(DEFL, n));
+ else {
+ Bputc(bout, DBYTE(DEFL, 0));
+ conout(n);
+ }
+ conout(l->addr);
+ while(l != e) {
+ Bputc(bout, l->u.ival>>56);
+ Bputc(bout, l->u.ival>>48);
+ Bputc(bout, l->u.ival>>40);
+ Bputc(bout, l->u.ival>>32);
+ Bputc(bout, l->u.ival>>24);
+ Bputc(bout, l->u.ival>>16);
+ Bputc(bout, l->u.ival>>8);
+ Bputc(bout, l->u.ival);
+ l = l->link;
+ }
+ break;
+ case DEFF:
+ n = 1;
+ for(e = l->link; e && e->addr == -1; e = e->link)
+ n++;
+ if(n < DMAX)
+ Bputc(bout, DBYTE(DEFF, n));
+ else {
+ Bputc(bout, DBYTE(DEFF, 0));
+ conout(n);
+ }
+ conout(l->addr);
+ while(l != e) {
+ Bputc(bout, l->u.ival>>56);
+ Bputc(bout, l->u.ival>>48);
+ Bputc(bout, l->u.ival>>40);
+ Bputc(bout, l->u.ival>>32);
+ Bputc(bout, l->u.ival>>24);
+ Bputc(bout, l->u.ival>>16);
+ Bputc(bout, l->u.ival>>8);
+ Bputc(bout, l->u.ival);
+ l = l->link;
+ }
+ break;
+ case DEFS:
+ n = l->u.str->len-1;
+ if(n < DMAX && n != 0)
+ Bputc(bout, DBYTE(DEFS, n));
+ else {
+ Bputc(bout, DBYTE(DEFS, 0));
+ conout(n);
+ }
+ conout(l->addr);
+ for(i = 0; i < n; i++)
+ Bputc(bout, l->u.str->string[i]);
+
+ e = l->link;
+ break;
+ case DEFA:
+ Bputc(bout, DBYTE(DEFA, 1));
+ conout(l->addr);
+ Bputc(bout, l->u.a->i>>24);
+ Bputc(bout, l->u.a->i>>16);
+ Bputc(bout, l->u.a->i>>8);
+ Bputc(bout, l->u.a->i);
+ Bputc(bout, l->u.a->size>>24);
+ Bputc(bout, l->u.a->size>>16);
+ Bputc(bout, l->u.a->size>>8);
+ Bputc(bout, l->u.a->size);
+ e = l->link;
+ break;
+ case DIND:
+ Bputc(bout, DBYTE(DIND, 1));
+ conout(l->addr);
+ Bputc(bout, 0);
+ Bputc(bout, 0);
+ Bputc(bout, 0);
+ Bputc(bout, 0);
+ e = l->link;
+ break;
+ case DAPOP:
+ Bputc(bout, DBYTE(DAPOP, 1));
+ conout(0);
+ e = l->link;
+ break;
+ }
+ }
+
+ Bputc(bout, DBYTE(DEFZ, 0));
+}
+
+void
+ldts(int n)
+{
+ nldts = n;
+ inldt = 1;
+}
+
+static void
+ldtw(int n)
+{
+ Ldts *ls, *p;
+
+ ls = malloc(sizeof(Ldts));
+ ls->n = n;
+ ls->ldt = nil;
+ ls->next = nil;
+ if(aldts == nil)
+ aldts = ls;
+ else{
+ for(p = aldts; p->next != nil; p = p->next)
+ ;
+ p->next = ls;
+ }
+ curl = ls;
+}
+
+static void
+ldte(int n, char *s)
+{
+ Ldt *l, *p;
+
+ l = malloc(sizeof(Ldt));
+ l->sign = n;
+ l->name = s;
+ l->next = nil;
+ if(curl->ldt == nil)
+ curl->ldt = l;
+ else{
+ for(p = curl->ldt; p->next != nil; p = p->next)
+ ;
+ p->next = l;
+ }
+}
+
+void
+excs(int n)
+{
+ nexcs = n;
+}
+
+void
+exc(int n1, int n2, int n3, int n4, int n5, int n6)
+{
+ Exc *e, *es;
+
+ e = malloc(sizeof(Exc));
+ e->n1 = n1;
+ e->n2 = n2;
+ e->n3 = n3;
+ e->n4 = n4;
+ e->n5 = n5;
+ e->n6 = n6;
+ e->etab = nil;
+ e->next = nil;
+ if(aexcs == nil)
+ aexcs = e;
+ else{
+ for(es = aexcs; es->next != nil; es = es->next)
+ ;
+ es->next = e;
+ }
+ cure = e;
+}
+
+void
+etab(String *s, int n)
+{
+ Etab *et, *ets;
+
+ et = malloc(sizeof(Etab));
+ et->n = n;
+ if(s != nil)
+ et->name = s->string;
+ else
+ et->name = nil;
+ et->next = nil;
+ if(cure->etab == nil)
+ cure->etab = et;
+ else{
+ for(ets = cure->etab; ets->next != nil; ets = ets->next)
+ ;
+ ets->next = et;
+ }
+}
+
+void
+source(String *s)
+{
+ srcpath = s->string;
+}
diff --git a/asm/lex.c b/asm/lex.c
new file mode 100644
index 00000000..7fb5ec71
--- /dev/null
+++ b/asm/lex.c
@@ -0,0 +1,685 @@
+#include "asm.h"
+#include "y.tab.h"
+#include "../libinterp/tab.h"
+
+Biobuf* bin;
+Biobuf* bout;
+Biobuf output;
+int line;
+int heapid;
+char symbol[1024];
+int nerr;
+char cmap[256];
+char* file;
+Desc* dlist;
+int dcount;
+int dseg;
+List* mdata;
+Sym* module;
+Link* links;
+Link* linkt;
+int nlink;
+int listing;
+int mustcompile;
+int dontcompile;
+char *ofile;
+int dentry;
+int pcentry;
+
+void
+usage(void)
+{
+ fprint(2, "usage: asm [-l] file.s\n");
+ exits("usage");
+}
+
+static char*
+mkfile(char *file, char *oldext, char *ext)
+{
+ char *ofile;
+ int n, n2;
+
+ n = strlen(file);
+ n2 = strlen(oldext);
+ if(n >= n2 && strcmp(&file[n-n2], oldext) == 0)
+ n -= n2;
+ ofile = malloc(n + strlen(ext) + 1);
+ memmove(ofile, file, n);
+ strcpy(ofile+n, ext);
+ return ofile;
+}
+
+void
+main(int argc, char *argv[])
+{
+ int fd;
+ char *p;
+
+ ARGBEGIN{
+ case 'C':
+ dontcompile++;
+ break;
+ case 'c':
+ mustcompile++;
+ break;
+ case 'l':
+ listing++;
+ break;
+ default:
+ usage();
+ }ARGEND;
+
+ fmtinstall('i', iconv);
+ fmtinstall('a', aconv);
+ kinit();
+ pcentry = -1;
+ dentry = -1;
+
+ if(argc != 1)
+ usage();
+ file = argv[0];
+ bin = Bopen(file, OREAD);
+ if(bin == 0) {
+ nerr++;
+ print("open: %s: %r\n", file);
+ exits("errors");
+ }
+ p = strrchr(file, '/');
+ if(p == nil)
+ p = file;
+ else
+ p++;
+ ofile = mkfile(p, ".s", ".dis");
+ fd = create(ofile, OWRITE, 0666);
+ if(fd < 0) {
+ nerr++;
+ print("can't create: %s: %r\n", ofile);
+ exits("errors");
+ }
+ Binit(&output, fd, OWRITE);
+ bout = &output;
+ line = 1;
+ yyparse();
+ Bterm(bin);
+ Bterm(bout);
+ close(fd);
+
+ if(nerr != 0){
+ remove(ofile);
+ exits("errors");
+ }
+
+ exits(0);
+}
+
+int
+opcode(Inst *i)
+{
+ return keywds[i->op].op;
+}
+
+int
+iconv(Fmt *f)
+{
+ Inst *i;
+ char buf[128];
+
+ i = va_arg(f->args, Inst*);
+ if(i == nil)
+ return fmtstrcpy(f, "IZ");
+
+ switch(keywds[i->op].terminal) {
+ case TOKI0:
+ sprint(buf, "%s", keywds[i->op].name);
+ break;
+ case TOKI1:
+ sprint(buf, "%s\t%a", keywds[i->op].name, i->dst);
+ break;
+ case TOKI3:
+ if(i->reg != 0) {
+ char *pre = "";
+ char *post = "";
+ switch(i->reg->mode) {
+ case AXIMM:
+ pre = "$";
+ break;
+ case AXINF:
+ post = "(fp)";
+ break;
+ case AXINM:
+ post = "(mp)";
+ break;
+ }
+ sprint(buf, "%s\t%a, %s%ld%s, %a", keywds[i->op].name, i->src, pre, i->reg->val, post, i->dst);
+ break;
+ }
+ case TOKI2:
+ sprint(buf, "%s\t%a, %a", keywds[i->op].name, i->src, i->dst);
+ break;
+ }
+
+ return fmtstrcpy(f, buf);
+}
+
+int
+aconv(Fmt *f)
+{
+ Addr *a;
+ char buf[64];
+
+ a = va_arg(f->args, Addr*);
+
+ if(a == nil)
+ return fmtstrcpy(f, "AZ");
+
+ if(a->mode & AIND) {
+ switch(a->mode & ~AIND) {
+ case AFP:
+ sprint(buf, "%ld(%d(fp))", a->val, a->off);
+ break;
+ case AMP:
+ sprint(buf, "%ld(%d(mp))", a->val, a->off);
+ break;
+ }
+ }
+ else {
+ switch(a->mode) {
+ case AFP:
+ sprint(buf, "%ld(fp)", a->val);
+ break;
+ case AMP:
+ sprint(buf, "%ld(mp)", a->val);
+ break;
+ case AIMM:
+ sprint(buf, "$%ld", a->val);
+ break;
+ }
+ }
+
+ return fmtstrcpy(f, buf);
+}
+
+void
+kinit(void)
+{
+ int i;
+ Sym *s;
+
+ for(i = 0; keywds[i].name; i++) {
+ s = enter(keywds[i].name, keywds[i].terminal);
+ s->value = keywds[i].op;
+ }
+
+ enter("desc", TOKHEAP);
+ enter("mp", TOKSB);
+ enter("fp", TOKFP);
+
+ enter("byte", TOKDB);
+ enter("word", TOKDW);
+ enter("long", TOKDL);
+ enter("real", TOKDF);
+ enter("string", TOKDS);
+ enter("var", TOKVAR);
+ enter("ext", TOKEXT);
+ enter("module", TOKMOD);
+ enter("link", TOKLINK);
+ enter("entry", TOKENTRY);
+ enter("array", TOKARRAY);
+ enter("indir", TOKINDIR);
+ enter("apop", TOKAPOP);
+ enter("ldts", TOKLDTS);
+ enter("exceptions", TOKEXCS);
+ enter("exception", TOKEXC);
+ enter("exctab", TOKETAB);
+ enter("source", TOKSRC);
+
+ cmap['0'] = '\0'+1;
+ cmap['z'] = '\0'+1;
+ cmap['n'] = '\n'+1;
+ cmap['r'] = '\r'+1;
+ cmap['t'] = '\t'+1;
+ cmap['b'] = '\b'+1;
+ cmap['f'] = '\f'+1;
+ cmap['a'] = '\a'+1;
+ cmap['v'] = '\v'+1;
+ cmap['\\'] = '\\'+1;
+ cmap['"'] = '"'+1;
+}
+
+int
+escchar(char c)
+{
+ int n;
+ char buf[32];
+
+ if(c >= '0' && c <= '9') {
+ n = 1;
+ buf[0] = c;
+ for(;;) {
+ c = Bgetc(bin);
+ if(c == Eof)
+ fatal("%d: <eof> in escape sequence", line);
+ if(strchr("0123456789xX", c) == 0) {
+ Bungetc(bin);
+ break;
+ }
+ buf[n++] = c;
+ }
+ buf[n] = '\0';
+ return strtol(buf, 0, 0);
+ }
+
+ n = cmap[c];
+ if(n == 0)
+ return c;
+ return n-1;
+}
+
+static char *strbuf;
+static int bufmax;
+
+static void
+resizebuf(void)
+{
+ bufmax += Strsize;
+ strbuf = realloc(strbuf, bufmax);
+}
+
+void
+eatstring(void)
+{
+ String *s;
+ int esc, c, cnt;
+
+ esc = 0;
+ for(cnt = 0;;) {
+ c = Bgetc(bin);
+ switch(c) {
+ case Eof:
+ fatal("%d: <eof> in string constant", line);
+
+ case '\n':
+ line++;
+ diag("newline in string constant");
+ goto done;
+
+ case '\\':
+ if(esc) {
+ if(cnt >= bufmax)
+ resizebuf();
+ strbuf[cnt++] = c;
+ esc = 0;
+ break;
+ }
+ esc = 1;
+ break;
+
+ case '"':
+ if(esc == 0)
+ goto done;
+
+ /* Fall through */
+ default:
+ if(esc) {
+ c = escchar(c);
+ esc = 0;
+ }
+ if(cnt >= bufmax)
+ resizebuf();
+ strbuf[cnt++] = c;
+ break;
+ }
+ }
+done:
+ if(cnt >= bufmax)
+ resizebuf();
+ strbuf[cnt] = '\0';
+ s = malloc(sizeof(String));
+ s->len = cnt+1;
+ s->string = malloc(s->len);
+ memmove(s->string, strbuf, s->len);
+ yylval.string = s;
+}
+
+void
+eatnl(void)
+{
+ int c;
+
+ line++;
+ for(;;) {
+ c = Bgetc(bin);
+ if(c == Eof)
+ diag("eof in comment");
+ if(c == '\n')
+ return;
+ }
+}
+
+int
+yylex(void)
+{
+ int c;
+
+loop:
+ c = Bgetc(bin);
+ switch(c) {
+ case Eof:
+ return Eof;
+ case '"':
+ eatstring();
+ return TSTRING;
+ case ' ':
+ case '\t':
+ case '\r':
+ goto loop;
+ case '\n':
+ line++;
+ goto loop;
+ case '.':
+ c = Bgetc(bin);
+ Bungetc(bin);
+ if(isdigit(c))
+ return numsym('.');
+ return '.';
+ case '#':
+ eatnl();
+ goto loop;
+ case '(':
+ case ')':
+ case ';':
+ case ',':
+ case '~':
+ case '$':
+ case '+':
+ case '/':
+ case '%':
+ case '^':
+ case '*':
+ case '&':
+ case '=':
+ case '|':
+ case '<':
+ case '>':
+ case '-':
+ case ':':
+ return c;
+ case '\'':
+ c = Bgetrune(bin);
+ if(c == '\\')
+ yylval.ival = escchar(Bgetc(bin));
+ else
+ yylval.ival = c;
+ c = Bgetc(bin);
+ if(c != '\'') {
+ diag("missing '");
+ Bungetc(bin);
+ }
+ return TCONST;
+
+ default:
+ return numsym(c);
+ }
+}
+
+int
+numsym(char first)
+{
+ int c;
+ char *p;
+ Sym *s;
+ enum { Int, Hex, Frac, Expsign, Exp } state;
+
+ symbol[0] = first;
+ p = symbol;
+
+ if(first == '.')
+ state = Frac;
+ else
+ state = Int;
+
+ if(isdigit(*p++) || state == Frac) {
+ for(;;) {
+ c = Bgetc(bin);
+ if(c < 0)
+ fatal("%d: <eof> eating numeric", line);
+
+ switch(state) {
+ case Int:
+ if(strchr("01234567890", c))
+ break;
+ switch(c) {
+ case 'x':
+ case 'X':
+ state = Hex;
+ break;
+ case '.':
+ state = Frac;
+ break;
+ case 'e':
+ case 'E':
+ state = Expsign;
+ break;
+ default:
+ goto done;
+ }
+ break;
+ case Hex:
+ if(strchr("01234567890abcdefABCDEF", c) == 0)
+ goto done;
+ break;
+ case Frac:
+ if(strchr("01234567890", c))
+ break;
+ if(c == 'e' || c == 'E')
+ state = Expsign;
+ else
+ goto done;
+ break;
+ case Expsign:
+ state = Exp;
+ if(c == '-' || c == '+')
+ break;
+ /* else fall through */
+ case Exp:
+ if(strchr("01234567890", c) == 0)
+ goto done;
+ break;
+ }
+ *p++ = c;
+ }
+ done:
+ Bungetc(bin);
+ *p = '\0';
+ switch(state) {
+ default:
+ yylval.ival = strtoll(symbol, 0, 0);
+ return TCONST;
+ case Frac:
+ case Expsign:
+ case Exp:
+ yylval.fval = strtod(symbol, 0);
+ return TFCONST;
+ }
+ }
+
+ for(;;) {
+ c = Bgetc(bin);
+ if(c < 0)
+ fatal("%d <eof> eating symbols", line);
+ /* '$' and '/' can occur in fully-qualified Java class names */
+ if(c != '_' && c != '.' && c != '/' && c != '$' && !isalnum(c)) {
+ Bungetc(bin);
+ break;
+ }
+ *p++ = c;
+ }
+
+ *p = '\0';
+
+ s = enter(symbol, TID);
+ switch(s->lexval) {
+ default:
+ yylval.sym = s;
+ break;
+ case TOKI0:
+ case TOKI1:
+ case TOKI2:
+ case TOKI3:
+ yylval.ival = s->value;
+ break;
+ }
+ return s->lexval;
+}
+
+static Sym *hash[Hashsize];
+
+Sym *
+enter(char *name, int type)
+{
+ Sym *s;
+ ulong h;
+ char *p;
+
+ s = lookup(name);
+ if(s != nil)
+ return s;
+
+ h = 0;
+ for(p = name; *p; p++)
+ h = h*3 + *p;
+ h %= Hashsize;
+
+ s = malloc(sizeof(Sym));
+ memset(s, 0, sizeof(Sym));
+ s->name = strdup(name);
+ s->lexval = type;
+ s->hash = hash[h];
+ hash[h] = s;
+ return s;
+}
+
+Sym *
+lookup(char *name)
+{
+ Sym *s;
+ ulong h;
+ char *p;
+
+ h = 0;
+ for(p = name; *p; p++)
+ h = h*3 + *p;
+ h %= Hashsize;
+
+ for(s = hash[h]; s; s = s->hash)
+ if(strcmp(name, s->name) == 0)
+ return s;
+ return 0;
+}
+
+void
+yyerror(char *a, ...)
+{
+ va_list arg;
+ char buf[128];
+
+ if(strcmp(a, "syntax error") == 0) {
+ yyerror("syntax error, near symbol '%s'", symbol);
+ return;
+ }
+ va_start(arg, a);
+ vseprint(buf, buf+sizeof(buf), a, arg);
+ va_end(arg);
+ print("%s %d: %s\n", file, line, buf);
+ if(nerr++ > 10) {
+ fprint(2, "%s %d: too many errors, giving up\n", file, line);
+ remove(ofile);
+ exits("yyerror");
+ }
+}
+
+void
+fatal(char *fmt, ...)
+{
+ va_list arg;
+ char buf[512];
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ fprint(2, "asm: %d (fatal compiler problem) %s\n", line, buf);
+ exits(buf);
+}
+
+void
+diag(char *fmt, ...)
+{
+ int srcline;
+ va_list arg;
+ char buf[512];
+
+ srcline = line;
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ fprint(2, "%s %d: %s\n", file, srcline, buf);
+ if(nerr++ > 10) {
+ fprint(2, "%s %d: too many errors, giving up\n", file, line);
+ remove(ofile);
+ exits("errors");
+ }
+}
+
+Inst*
+ai(int op)
+{
+ Inst *i;
+
+ i = malloc(sizeof(Inst));
+ memset(i, 0, sizeof(Inst));
+ i->op = op;
+
+ return i;
+}
+
+Addr*
+aa(int val)
+{
+ Addr *a;
+
+ a = malloc(sizeof(Addr));
+ memset(a, 0, sizeof(Addr));
+ a->val = val;
+ if(val <= -1073741824 && val > 1073741823)
+ diag("offset out of range");
+
+ return a;
+}
+
+vlong
+dtocanon(double d)
+{
+ int swap;
+ ulong t;
+ union { double d; ulong ul[2]; } u1;
+ union { vlong v; ulong ul[2]; } u2;
+
+ u2.v = 1;
+ swap = u2.ul[0];
+ u1.d = 1.;
+ if(u1.ul[0]){
+ u1.d = d;
+ u2.ul[0] = u1.ul[0];
+ u2.ul[1] = u1.ul[1];
+ }else{
+ u1.d = d;
+ u2.ul[0] = u1.ul[1];
+ u2.ul[1] = u1.ul[0];
+ }
+ if(swap){
+ t = u2.ul[0];
+ u2.ul[0] = u2.ul[1];
+ u2.ul[1] = t;
+ }
+ return u2.v;
+}
diff --git a/asm/mkfile b/asm/mkfile
new file mode 100644
index 00000000..ca7eb4ec
--- /dev/null
+++ b/asm/mkfile
@@ -0,0 +1,21 @@
+<../mkconfig
+
+TARG=asm
+OFILES=\
+ lex.$O\
+ assem.$O\
+ y.tab.$O
+
+YFILES= asm.y
+
+HFILES=\
+ asm.h\
+ $ROOT/libinterp/tab.h\
+ $ROOT/include/isa.h\
+ y.tab.h
+
+LIBS=bio 9
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE