diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /asm | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'asm')
| -rw-r--r-- | asm/NOTICE | 25 | ||||
| -rw-r--r-- | asm/asm.h | 149 | ||||
| -rw-r--r-- | asm/asm.y | 385 | ||||
| -rw-r--r-- | asm/assem.c | 672 | ||||
| -rw-r--r-- | asm/lex.c | 685 | ||||
| -rw-r--r-- | asm/mkfile | 21 |
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 |
