diff options
Diffstat (limited to 'src/cmd/5a')
-rw-r--r-- | src/cmd/5a/Makefile | 25 | ||||
-rw-r--r-- | src/cmd/5a/a.h | 200 | ||||
-rw-r--r-- | src/cmd/5a/a.y | 710 | ||||
-rw-r--r-- | src/cmd/5a/doc.go | 14 | ||||
-rw-r--r-- | src/cmd/5a/lex.c | 704 |
5 files changed, 1653 insertions, 0 deletions
diff --git a/src/cmd/5a/Makefile b/src/cmd/5a/Makefile new file mode 100644 index 000000000..f4463c97b --- /dev/null +++ b/src/cmd/5a/Makefile @@ -0,0 +1,25 @@ +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +include ../../Make.inc +O:=$(HOST_O) + +TARG=5a + +HFILES=\ + a.h\ + y.tab.h\ + ../5l/5.out.h\ + +OFILES=\ + y.tab.$O\ + lex.$O\ + ../5l/enam.$O\ + +YFILES=\ + a.y\ + +include ../../Make.ccmd + +lex.$O: ../cc/macbody ../cc/lexbody diff --git a/src/cmd/5a/a.h b/src/cmd/5a/a.h new file mode 100644 index 000000000..a2c87cf48 --- /dev/null +++ b/src/cmd/5a/a.h @@ -0,0 +1,200 @@ +// Inferno utils/5a/a.h +// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.h +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include <bio.h> +#include "../5l/5.out.h" + +#ifndef EXTERN +#define EXTERN extern +#endif + +#undef getc +#undef ungetc +#undef BUFSIZ + +#define getc ccgetc +#define ungetc ccungetc + +typedef struct Sym Sym; +typedef struct Gen Gen; +typedef struct Io Io; +typedef struct Hist Hist; + +#define MAXALIGN 7 +#define FPCHIP 1 +#define NSYMB 8192 +#define BUFSIZ 8192 +#define HISTSZ 20 +#ifndef EOF +#define EOF (-1) +#endif +#define IGN (-2) +#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff) +#define NHASH 503 +#define STRINGSZ 200 +#define NMACRO 10 + +struct Sym +{ + Sym* link; + char* macro; + int32 value; + ushort type; + char *name; + char sym; +}; +#define S ((Sym*)0) + +EXTERN struct +{ + char* p; + int c; +} fi; + +struct Io +{ + Io* link; + char b[BUFSIZ]; + char* p; + short c; + short f; +}; +#define I ((Io*)0) + +EXTERN struct +{ + Sym* sym; + short type; +} h[NSYM]; + +struct Gen +{ + Sym* sym; + int32 offset; + short type; + short reg; + short name; + double dval; + char sval[8]; +}; + +struct Hist +{ + Hist* link; + char* name; + int32 line; + int32 offset; +}; +#define H ((Hist*)0) + +enum +{ + CLAST, + CMACARG, + CMACRO, + CPREPROC, + + Always = 14, +}; + +EXTERN char debug[256]; +EXTERN Sym* hash[NHASH]; +EXTERN char** Dlist; +EXTERN int nDlist; +EXTERN Hist* ehist; +EXTERN int newflag; +EXTERN Hist* hist; +EXTERN char* hunk; +EXTERN char** include; +EXTERN Io* iofree; +EXTERN Io* ionext; +EXTERN Io* iostack; +EXTERN int32 lineno; +EXTERN int nerrors; +EXTERN int32 nhunk; +EXTERN int ninclude; +EXTERN int32 nsymb; +EXTERN Gen nullgen; +EXTERN char* outfile; +EXTERN int pass; +EXTERN char* pathname; +EXTERN int32 pc; +EXTERN int peekc; +EXTERN int32 stmtline; +EXTERN int sym; +EXTERN char* symb; +EXTERN int thechar; +EXTERN char* thestring; +EXTERN int32 thunk; +EXTERN Biobuf obuf; + +void* alloc(int32); +void* allocn(void*, int32, int32); +void ensuresymb(int32); +void errorexit(void); +void pushio(void); +void newio(void); +void newfile(char*, int); +Sym* slookup(char*); +Sym* lookup(void); +void syminit(Sym*); +int32 yylex(void); +int getc(void); +int getnsc(void); +void unget(int); +int escchar(int); +void cinit(void); +void pinit(char*); +void cclean(void); +int isreg(Gen*); +void outcode(int, int, Gen*, int, Gen*); +void zname(char*, int, int); +void zaddr(Gen*, int); +void ieeedtod(Ieee*, double); +int filbuf(void); +Sym* getsym(void); +void domacro(void); +void macund(void); +void macdef(void); +void macexpand(Sym*, char*); +void macinc(void); +void maclin(void); +void macprag(void); +void macif(int); +void macend(void); +void outhist(void); +void dodefine(char*); +void prfile(int32); +void linehist(char*, int); +void gethunk(void); +void yyerror(char*, ...); +int yyparse(void); +void setinclude(char*); +int assemble(char*); diff --git a/src/cmd/5a/a.y b/src/cmd/5a/a.y new file mode 100644 index 000000000..9a0efd5e0 --- /dev/null +++ b/src/cmd/5a/a.y @@ -0,0 +1,710 @@ +// Inferno utils/5a/a.y +// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.y +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +%{ +#include <u.h> +#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */ +#include <libc.h> +#include "a.h" +%} +%union +{ + Sym *sym; + int32 lval; + double dval; + char sval[8]; + Gen gen; +} +%left '|' +%left '^' +%left '&' +%left '<' '>' +%left '+' '-' +%left '*' '/' '%' +%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5 +%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA +%token <lval> LTYPEB LTYPEC LTYPED LTYPEE LTYPEF +%token <lval> LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK +%token <lval> LTYPEL LTYPEM LTYPEN LTYPEBX +%token <lval> LCONST LSP LSB LFP LPC +%token <lval> LTYPEX LR LREG LF LFREG LC LCREG LPSR LFCR +%token <lval> LCOND LS LAT +%token <dval> LFCONST +%token <sval> LSCONST +%token <sym> LNAME LLAB LVAR +%type <lval> con expr oexpr pointer offset sreg spreg creg +%type <lval> rcon cond reglist +%type <gen> gen rel reg regreg freg shift fcon frcon +%type <gen> imm ximm name oreg ireg nireg ioreg imsr +%% +prog: +| prog + { + stmtline = lineno; + } + line + +line: + LLAB ':' + { + if($1->value != pc) + yyerror("redeclaration of %s", $1->name); + $1->value = pc; + } + line +| LNAME ':' + { + $1->type = LLAB; + $1->value = pc; + } + line +| LNAME '=' expr ';' + { + $1->type = LVAR; + $1->value = $3; + } +| LVAR '=' expr ';' + { + if($1->value != $3) + yyerror("redeclaration of %s", $1->name); + $1->value = $3; + } +| ';' +| inst ';' +| error ';' + +inst: +/* + * ADD + */ + LTYPE1 cond imsr ',' spreg ',' reg + { + outcode($1, $2, &$3, $5, &$7); + } +| LTYPE1 cond imsr ',' spreg ',' + { + outcode($1, $2, &$3, $5, &nullgen); + } +| LTYPE1 cond imsr ',' reg + { + outcode($1, $2, &$3, NREG, &$5); + } +/* + * MVN + */ +| LTYPE2 cond imsr ',' reg + { + outcode($1, $2, &$3, NREG, &$5); + } +/* + * MOVW + */ +| LTYPE3 cond gen ',' gen + { + outcode($1, $2, &$3, NREG, &$5); + } +/* + * B/BL + */ +| LTYPE4 cond comma rel + { + outcode($1, $2, &nullgen, NREG, &$4); + } +| LTYPE4 cond comma nireg + { + outcode($1, $2, &nullgen, NREG, &$4); + } +/* + * BX + */ +| LTYPEBX comma ireg + { + outcode($1, Always, &nullgen, NREG, &$3); + } +/* + * BEQ + */ +| LTYPE5 comma rel + { + outcode($1, Always, &nullgen, NREG, &$3); + } +/* + * SWI + */ +| LTYPE6 cond comma gen + { + outcode($1, $2, &nullgen, NREG, &$4); + } +/* + * CMP + */ +| LTYPE7 cond imsr ',' spreg comma + { + outcode($1, $2, &$3, $5, &nullgen); + } +/* + * MOVM + */ +| LTYPE8 cond ioreg ',' '[' reglist ']' + { + Gen g; + + g = nullgen; + g.type = D_CONST; + g.offset = $6; + outcode($1, $2, &$3, NREG, &g); + } +| LTYPE8 cond '[' reglist ']' ',' ioreg + { + Gen g; + + g = nullgen; + g.type = D_CONST; + g.offset = $4; + outcode($1, $2, &g, NREG, &$7); + } +/* + * SWAP + */ +| LTYPE9 cond reg ',' ireg ',' reg + { + outcode($1, $2, &$5, $3.reg, &$7); + } +| LTYPE9 cond reg ',' ireg comma + { + outcode($1, $2, &$5, $3.reg, &$3); + } +| LTYPE9 cond comma ireg ',' reg + { + outcode($1, $2, &$4, $6.reg, &$6); + } +/* + * RET + */ +| LTYPEA cond comma + { + outcode($1, $2, &nullgen, NREG, &nullgen); + } +/* + * TEXT/GLOBL + */ +| LTYPEB name ',' imm + { + outcode($1, Always, &$2, NREG, &$4); + } +| LTYPEB name ',' con ',' imm + { + outcode($1, Always, &$2, $4, &$6); + } +/* + * DATA + */ +| LTYPEC name '/' con ',' ximm + { + outcode($1, Always, &$2, $4, &$6); + } +/* + * CASE + */ +| LTYPED cond reg comma + { + outcode($1, $2, &$3, NREG, &nullgen); + } +/* + * word + */ +| LTYPEH comma ximm + { + outcode($1, Always, &nullgen, NREG, &$3); + } +/* + * floating-point coprocessor + */ +| LTYPEI cond freg ',' freg + { + outcode($1, $2, &$3, NREG, &$5); + } +| LTYPEK cond frcon ',' freg + { + outcode($1, $2, &$3, NREG, &$5); + } +| LTYPEK cond frcon ',' LFREG ',' freg + { + outcode($1, $2, &$3, $5, &$7); + } +| LTYPEL cond freg ',' freg comma + { + outcode($1, $2, &$3, $5.reg, &nullgen); + } +/* + * MCR MRC + */ +| LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr + { + Gen g; + + g = nullgen; + g.type = D_CONST; + g.offset = + (0xe << 24) | /* opcode */ + ($1 << 20) | /* MCR/MRC */ + ($2 << 28) | /* scond */ + (($3 & 15) << 8) | /* coprocessor number */ + (($5 & 7) << 21) | /* coprocessor operation */ + (($7 & 15) << 12) | /* arm register */ + (($9 & 15) << 16) | /* Crn */ + (($11 & 15) << 0) | /* Crm */ + (($12 & 7) << 5) | /* coprocessor information */ + (1<<4); /* must be set */ + outcode(AWORD, Always, &nullgen, NREG, &g); + } +/* + * MULL hi,lo,r1,r2 + */ +| LTYPEM cond reg ',' reg ',' regreg + { + outcode($1, $2, &$3, $5.reg, &$7); + } +/* + * MULA hi,lo,r1,r2 + */ +| LTYPEN cond reg ',' reg ',' reg ',' spreg + { + $7.type = D_REGREG; + $7.offset = $9; + outcode($1, $2, &$3, $5.reg, &$7); + } +/* + * END + */ +| LTYPEE comma + { + outcode($1, Always, &nullgen, NREG, &nullgen); + } + +cond: + { + $$ = Always; + } +| cond LCOND + { + $$ = ($1 & ~C_SCOND) | $2; + } +| cond LS + { + $$ = $1 | $2; + } + +comma: +| ',' comma + +rel: + con '(' LPC ')' + { + $$ = nullgen; + $$.type = D_BRANCH; + $$.offset = $1 + pc; + } +| LNAME offset + { + $$ = nullgen; + if(pass == 2) + yyerror("undefined label: %s", $1->name); + $$.type = D_BRANCH; + $$.sym = $1; + $$.offset = $2; + } +| LLAB offset + { + $$ = nullgen; + $$.type = D_BRANCH; + $$.sym = $1; + $$.offset = $1->value + $2; + } + +ximm: '$' con + { + $$ = nullgen; + $$.type = D_CONST; + $$.offset = $2; + } +| '$' oreg + { + $$ = $2; + $$.type = D_CONST; + } +| '$' '*' '$' oreg + { + $$ = $4; + $$.type = D_OCONST; + } +| '$' LSCONST + { + $$ = nullgen; + $$.type = D_SCONST; + memcpy($$.sval, $2, sizeof($$.sval)); + } +| fcon + +fcon: + '$' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = $2; + } +| '$' '-' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = -$3; + } + +reglist: + spreg + { + $$ = 1 << $1; + } +| spreg '-' spreg + { + int i; + $$=0; + for(i=$1; i<=$3; i++) + $$ |= 1<<i; + for(i=$3; i<=$1; i++) + $$ |= 1<<i; + } +| spreg comma reglist + { + $$ = (1<<$1) | $3; + } + +gen: + reg +| ximm +| shift +| shift '(' spreg ')' + { + $$ = $1; + $$.reg = $3; + } +| LPSR + { + $$ = nullgen; + $$.type = D_PSR; + $$.reg = $1; + } +| LFCR + { + $$ = nullgen; + $$.type = D_FPCR; + $$.reg = $1; + } +| con + { + $$ = nullgen; + $$.type = D_OREG; + $$.offset = $1; + } +| oreg +| freg + +nireg: + ireg +| name + { + $$ = $1; + if($1.name != D_EXTERN && $1.name != D_STATIC) { + } + } + +ireg: + '(' spreg ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.reg = $2; + $$.offset = 0; + } + +ioreg: + ireg +| con '(' sreg ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.reg = $3; + $$.offset = $1; + } + +oreg: + name +| name '(' sreg ')' + { + $$ = $1; + $$.type = D_OREG; + $$.reg = $3; + } +| ioreg + +imsr: + reg +| imm +| shift + +imm: '$' con + { + $$ = nullgen; + $$.type = D_CONST; + $$.offset = $2; + } + +reg: + spreg + { + $$ = nullgen; + $$.type = D_REG; + $$.reg = $1; + } + +regreg: + '(' spreg ',' spreg ')' + { + $$ = nullgen; + $$.type = D_REGREG; + $$.reg = $2; + $$.offset = $4; + } + +shift: + spreg '<' '<' rcon + { + $$ = nullgen; + $$.type = D_SHIFT; + $$.offset = $1 | $4 | (0 << 5); + } +| spreg '>' '>' rcon + { + $$ = nullgen; + $$.type = D_SHIFT; + $$.offset = $1 | $4 | (1 << 5); + } +| spreg '-' '>' rcon + { + $$ = nullgen; + $$.type = D_SHIFT; + $$.offset = $1 | $4 | (2 << 5); + } +| spreg LAT '>' rcon + { + $$ = nullgen; + $$.type = D_SHIFT; + $$.offset = $1 | $4 | (3 << 5); + } + +rcon: + spreg + { + if($$ < 0 || $$ >= 16) + print("register value out of range\n"); + $$ = (($1&15) << 8) | (1 << 4); + } +| con + { + if($$ < 0 || $$ >= 32) + print("shift value out of range\n"); + $$ = ($1&31) << 7; + } + +sreg: + LREG +| LPC + { + $$ = REGPC; + } +| LR '(' expr ')' + { + if($3 < 0 || $3 >= NREG) + print("register value out of range\n"); + $$ = $3; + } + +spreg: + sreg +| LSP + { + $$ = REGSP; + } + +creg: + LCREG +| LC '(' expr ')' + { + if($3 < 0 || $3 >= NREG) + print("register value out of range\n"); + $$ = $3; + } + +frcon: + freg +| fcon + +freg: + LFREG + { + $$ = nullgen; + $$.type = D_FREG; + $$.reg = $1; + } +| LF '(' con ')' + { + $$ = nullgen; + $$.type = D_FREG; + $$.reg = $3; + } + +name: + con '(' pointer ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = $3; + $$.sym = S; + $$.offset = $1; + } +| LNAME offset '(' pointer ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = $4; + $$.sym = $1; + $$.offset = $2; + } +| LNAME '<' '>' offset '(' LSB ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = D_STATIC; + $$.sym = $1; + $$.offset = $4; + } + +offset: + { + $$ = 0; + } +| '+' con + { + $$ = $2; + } +| '-' con + { + $$ = -$2; + } + +pointer: + LSB +| LSP +| LFP + +con: + LCONST +| LVAR + { + $$ = $1->value; + } +| '-' con + { + $$ = -$2; + } +| '+' con + { + $$ = $2; + } +| '~' con + { + $$ = ~$2; + } +| '(' expr ')' + { + $$ = $2; + } + +oexpr: + { + $$ = 0; + } +| ',' 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/src/cmd/5a/doc.go b/src/cmd/5a/doc.go new file mode 100644 index 000000000..a0d2c4c64 --- /dev/null +++ b/src/cmd/5a/doc.go @@ -0,0 +1,14 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* + +5a is a version of the Plan 9 assembler. The original is documented at + + http://plan9.bell-labs.com/magic/man2html/1/2a + +Its target architecture is the ARM, referred to by these tools as arm. + +*/ +package documentation diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c new file mode 100644 index 000000000..ad7ed05dd --- /dev/null +++ b/src/cmd/5a/lex.c @@ -0,0 +1,704 @@ +// Inferno utils/5a/lex.c +// http://code.google.com/p/inferno-os/source/browse/utils/5a/lex.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#define EXTERN +#include <u.h> +#include <libc.h> +#include "a.h" +#include "y.tab.h" + +enum +{ + Plan9 = 1<<0, + Unix = 1<<1, + Windows = 1<<2, +}; + +int +systemtype(int sys) +{ + return sys&Plan9; +} + +void +main(int argc, char *argv[]) +{ + char *p; + int c; + + thechar = '5'; + thestring = "arm"; + + ensuresymb(NSYMB); + memset(debug, 0, sizeof(debug)); + cinit(); + outfile = 0; + setinclude("."); + ARGBEGIN { + default: + c = ARGC(); + if(c >= 0 || c < sizeof(debug)) + debug[c] = 1; + break; + + case 'o': + outfile = ARGF(); + break; + + case 'D': + p = ARGF(); + if(p) { + if (nDlist%8 == 0) + Dlist = allocn(Dlist, nDlist*sizeof(char *), + 8*sizeof(char *)); + Dlist[nDlist++] = p; + } + break; + + case 'I': + p = ARGF(); + setinclude(p); + break; + case 't': + thechar = 't'; + thestring = "thumb"; + break; + } ARGEND + if(*argv == 0) { + print("usage: %ca [-options] file.s\n", thechar); + errorexit(); + } + if(argc > 1){ + print("can't assemble multiple files\n"); + errorexit(); + } + if(assemble(argv[0])) + errorexit(); + exits(0); +} + +int +assemble(char *file) +{ + char *ofile, *p; + int i, of; + + ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar) + strcpy(ofile, file); + p = utfrrune(ofile, '/'); + if(p) { + include[0] = ofile; + *p++ = 0; + } else + p = ofile; + if(outfile == 0) { + outfile = p; + if(outfile){ + p = utfrrune(outfile, '.'); + if(p) + if(p[1] == 's' && p[2] == 0) + p[0] = 0; + p = utfrune(outfile, 0); + p[0] = '.'; + p[1] = thechar; + p[2] = 0; + } else + outfile = "/dev/null"; + } + + of = create(outfile, OWRITE, 0664); + if(of < 0) { + yyerror("%ca: cannot create %s", thechar, outfile); + errorexit(); + } + Binit(&obuf, of, OWRITE); + + pass = 1; + pinit(file); + + Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion()); + + for(i=0; i<nDlist; i++) + dodefine(Dlist[i]); + yyparse(); + if(nerrors) { + cclean(); + return nerrors; + } + + Bprint(&obuf, "\n!\n"); + + pass = 2; + outhist(); + pinit(file); + for(i=0; i<nDlist; i++) + dodefine(Dlist[i]); + yyparse(); + cclean(); + return nerrors; +} + +struct +{ + char *name; + ushort type; + ushort value; +} itab[] = +{ + "SP", LSP, D_AUTO, + "SB", LSB, D_EXTERN, + "FP", LFP, D_PARAM, + "PC", LPC, D_BRANCH, + + "R", LR, 0, + "R0", LREG, 0, + "R1", LREG, 1, + "R2", LREG, 2, + "R3", LREG, 3, + "R4", LREG, 4, + "R5", LREG, 5, + "R6", LREG, 6, + "R7", LREG, 7, + "R8", LREG, 8, + "R9", LREG, 9, + "R10", LREG, 10, + "R11", LREG, 11, + "R12", LREG, 12, + "R13", LREG, 13, + "R14", LREG, 14, + "R15", LREG, 15, + + "F", LF, 0, + + "F0", LFREG, 0, + "F1", LFREG, 1, + "F2", LFREG, 2, + "F3", LFREG, 3, + "F4", LFREG, 4, + "F5", LFREG, 5, + "F6", LFREG, 6, + "F7", LFREG, 7, + "F8", LFREG, 8, + "F9", LFREG, 9, + "F10", LFREG, 10, + "F11", LFREG, 11, + "F12", LFREG, 12, + "F13", LFREG, 13, + "F14", LFREG, 14, + "F15", LFREG, 15, + + "C", LC, 0, + + "C0", LCREG, 0, + "C1", LCREG, 1, + "C2", LCREG, 2, + "C3", LCREG, 3, + "C4", LCREG, 4, + "C5", LCREG, 5, + "C6", LCREG, 6, + "C7", LCREG, 7, + "C8", LCREG, 8, + "C9", LCREG, 9, + "C10", LCREG, 10, + "C11", LCREG, 11, + "C12", LCREG, 12, + "C13", LCREG, 13, + "C14", LCREG, 14, + "C15", LCREG, 15, + + "CPSR", LPSR, 0, + "SPSR", LPSR, 1, + + "FPSR", LFCR, 0, + "FPCR", LFCR, 1, + + ".EQ", LCOND, 0, + ".NE", LCOND, 1, + ".CS", LCOND, 2, + ".HS", LCOND, 2, + ".CC", LCOND, 3, + ".LO", LCOND, 3, + ".MI", LCOND, 4, + ".PL", LCOND, 5, + ".VS", LCOND, 6, + ".VC", LCOND, 7, + ".HI", LCOND, 8, + ".LS", LCOND, 9, + ".GE", LCOND, 10, + ".LT", LCOND, 11, + ".GT", LCOND, 12, + ".LE", LCOND, 13, + ".AL", LCOND, Always, + + ".U", LS, C_UBIT, + ".S", LS, C_SBIT, + ".W", LS, C_WBIT, + ".P", LS, C_PBIT, + ".PW", LS, C_WBIT|C_PBIT, + ".WP", LS, C_WBIT|C_PBIT, + + ".F", LS, C_FBIT, + + ".IBW", LS, C_WBIT|C_PBIT|C_UBIT, + ".IAW", LS, C_WBIT|C_UBIT, + ".DBW", LS, C_WBIT|C_PBIT, + ".DAW", LS, C_WBIT, + ".IB", LS, C_PBIT|C_UBIT, + ".IA", LS, C_UBIT, + ".DB", LS, C_PBIT, + ".DA", LS, 0, + + "@", LAT, 0, + + "AND", LTYPE1, AAND, + "EOR", LTYPE1, AEOR, + "SUB", LTYPE1, ASUB, + "RSB", LTYPE1, ARSB, + "ADD", LTYPE1, AADD, + "ADC", LTYPE1, AADC, + "SBC", LTYPE1, ASBC, + "RSC", LTYPE1, ARSC, + "ORR", LTYPE1, AORR, + "BIC", LTYPE1, ABIC, + + "SLL", LTYPE1, ASLL, + "SRL", LTYPE1, ASRL, + "SRA", LTYPE1, ASRA, + + "MUL", LTYPE1, AMUL, + "MULA", LTYPEN, AMULA, + "DIV", LTYPE1, ADIV, + "MOD", LTYPE1, AMOD, + + "MULL", LTYPEM, AMULL, + "MULAL", LTYPEM, AMULAL, + "MULLU", LTYPEM, AMULLU, + "MULALU", LTYPEM, AMULALU, + + "MVN", LTYPE2, AMVN, /* op2 ignored */ + + "MOVB", LTYPE3, AMOVB, + "MOVBU", LTYPE3, AMOVBU, + "MOVH", LTYPE3, AMOVH, + "MOVHU", LTYPE3, AMOVHU, + "MOVW", LTYPE3, AMOVW, + + "MOVD", LTYPE3, AMOVD, + "MOVDF", LTYPE3, AMOVDF, + "MOVDW", LTYPE3, AMOVDW, + "MOVF", LTYPE3, AMOVF, + "MOVFD", LTYPE3, AMOVFD, + "MOVFW", LTYPE3, AMOVFW, + "MOVWD", LTYPE3, AMOVWD, + "MOVWF", LTYPE3, AMOVWF, + + "LDREX", LTYPE3, ALDREX, + "LDREXD", LTYPE3, ALDREXD, + "STREX", LTYPE9, ASTREX, + "STREXD", LTYPE9, ASTREXD, + +/* + "ABSF", LTYPEI, AABSF, + "ABSD", LTYPEI, AABSD, + "NEGF", LTYPEI, ANEGF, + "NEGD", LTYPEI, ANEGD, + "SQTF", LTYPEI, ASQTF, + "SQTD", LTYPEI, ASQTD, + "RNDF", LTYPEI, ARNDF, + "RNDD", LTYPEI, ARNDD, + "URDF", LTYPEI, AURDF, + "URDD", LTYPEI, AURDD, + "NRMF", LTYPEI, ANRMF, + "NRMD", LTYPEI, ANRMD, +*/ + + "SQRTF", LTYPEI, ASQRTF, + "SQRTD", LTYPEI, ASQRTD, + "CMPF", LTYPEL, ACMPF, + "CMPD", LTYPEL, ACMPD, + "ADDF", LTYPEK, AADDF, + "ADDD", LTYPEK, AADDD, + "SUBF", LTYPEK, ASUBF, + "SUBD", LTYPEK, ASUBD, + "MULF", LTYPEK, AMULF, + "MULD", LTYPEK, AMULD, + "DIVF", LTYPEK, ADIVF, + "DIVD", LTYPEK, ADIVD, + + "B", LTYPE4, AB, + "BL", LTYPE4, ABL, + "BX", LTYPEBX, ABX, + + "BEQ", LTYPE5, ABEQ, + "BNE", LTYPE5, ABNE, + "BCS", LTYPE5, ABCS, + "BHS", LTYPE5, ABHS, + "BCC", LTYPE5, ABCC, + "BLO", LTYPE5, ABLO, + "BMI", LTYPE5, ABMI, + "BPL", LTYPE5, ABPL, + "BVS", LTYPE5, ABVS, + "BVC", LTYPE5, ABVC, + "BHI", LTYPE5, ABHI, + "BLS", LTYPE5, ABLS, + "BGE", LTYPE5, ABGE, + "BLT", LTYPE5, ABLT, + "BGT", LTYPE5, ABGT, + "BLE", LTYPE5, ABLE, + "BCASE", LTYPE5, ABCASE, + + "SWI", LTYPE6, ASWI, + + "CMP", LTYPE7, ACMP, + "TST", LTYPE7, ATST, + "TEQ", LTYPE7, ATEQ, + "CMN", LTYPE7, ACMN, + + "MOVM", LTYPE8, AMOVM, + + "SWPBU", LTYPE9, ASWPBU, + "SWPW", LTYPE9, ASWPW, + + "RET", LTYPEA, ARET, + "RFE", LTYPEA, ARFE, + + "TEXT", LTYPEB, ATEXT, + "GLOBL", LTYPEB, AGLOBL, + "DATA", LTYPEC, ADATA, + "CASE", LTYPED, ACASE, + "END", LTYPEE, AEND, + "WORD", LTYPEH, AWORD, + "NOP", LTYPEI, ANOP, + + "MCR", LTYPEJ, 0, + "MRC", LTYPEJ, 1, + 0 +}; + +void +cinit(void) +{ + Sym *s; + int i; + + nullgen.sym = S; + nullgen.offset = 0; + nullgen.type = D_NONE; + nullgen.name = D_NONE; + nullgen.reg = NREG; + if(FPCHIP) + nullgen.dval = 0; + for(i=0; i<sizeof(nullgen.sval); i++) + nullgen.sval[i] = 0; + + nerrors = 0; + iostack = I; + iofree = I; + peekc = IGN; + nhunk = 0; + for(i=0; i<NHASH; i++) + hash[i] = S; + for(i=0; itab[i].name; i++) { + s = slookup(itab[i].name); + s->type = itab[i].type; + s->value = itab[i].value; + } + + pathname = allocn(pathname, 0, 100); + if(getwd(pathname, 99) == 0) { + pathname = allocn(pathname, 100, 900); + if(getwd(pathname, 999) == 0) + strcpy(pathname, "/???"); + } +} + +void +syminit(Sym *s) +{ + + s->type = LNAME; + s->value = 0; +} + +int +isreg(Gen *g) +{ + + USED(g); + return 1; +} + +void +cclean(void) +{ + + outcode(AEND, Always, &nullgen, NREG, &nullgen); + Bflush(&obuf); +} + +void +zname(char *n, int t, int s) +{ + + Bputc(&obuf, ANAME); + Bputc(&obuf, t); /* type */ + Bputc(&obuf, s); /* sym */ + while(*n) { + Bputc(&obuf, *n); + n++; + } + Bputc(&obuf, 0); +} + +void +zaddr(Gen *a, int s) +{ + int32 l; + int i; + char *n; + Ieee e; + + Bputc(&obuf, a->type); + Bputc(&obuf, a->reg); + Bputc(&obuf, s); + Bputc(&obuf, a->name); + switch(a->type) { + default: + print("unknown type %d\n", a->type); + exits("arg"); + + case D_NONE: + case D_REG: + case D_FREG: + case D_PSR: + case D_FPCR: + break; + + case D_REGREG: + Bputc(&obuf, a->offset); + break; + + case D_OREG: + case D_CONST: + case D_BRANCH: + case D_SHIFT: + l = a->offset; + Bputc(&obuf, l); + Bputc(&obuf, l>>8); + Bputc(&obuf, l>>16); + Bputc(&obuf, l>>24); + break; + + case D_SCONST: + n = a->sval; + for(i=0; i<NSNAME; i++) { + Bputc(&obuf, *n); + n++; + } + break; + + case D_FCONST: + ieeedtod(&e, a->dval); + Bputc(&obuf, e.l); + Bputc(&obuf, e.l>>8); + Bputc(&obuf, e.l>>16); + Bputc(&obuf, e.l>>24); + Bputc(&obuf, e.h); + Bputc(&obuf, e.h>>8); + Bputc(&obuf, e.h>>16); + Bputc(&obuf, e.h>>24); + break; + } +} + +static int bcode[] = +{ + ABEQ, + ABNE, + ABCS, + ABCC, + ABMI, + ABPL, + ABVS, + ABVC, + ABHI, + ABLS, + ABGE, + ABLT, + ABGT, + ABLE, + AB, + ANOP, +}; + +void +outcode(int a, int scond, Gen *g1, int reg, Gen *g2) +{ + int sf, st, t; + Sym *s; + + /* hack to make B.NE etc. work: turn it into the corresponding conditional */ + if(a == AB){ + a = bcode[scond&0xf]; + scond = (scond & ~0xf) | Always; + } + + if(pass == 1) + goto out; +jackpot: + sf = 0; + s = g1->sym; + while(s != S) { + sf = s->sym; + if(sf < 0 || sf >= NSYM) + sf = 0; + t = g1->name; + if(h[sf].type == t) + if(h[sf].sym == s) + break; + zname(s->name, t, sym); + s->sym = sym; + h[sym].sym = s; + h[sym].type = t; + sf = sym; + sym++; + if(sym >= NSYM) + sym = 1; + break; + } + st = 0; + s = g2->sym; + while(s != S) { + st = s->sym; + if(st < 0 || st >= NSYM) + st = 0; + t = g2->name; + if(h[st].type == t) + if(h[st].sym == s) + break; + zname(s->name, t, sym); + s->sym = sym; + h[sym].sym = s; + h[sym].type = t; + st = sym; + sym++; + if(sym >= NSYM) + sym = 1; + if(st == sf) + goto jackpot; + break; + } + Bputc(&obuf, a); + Bputc(&obuf, scond); + Bputc(&obuf, reg); + Bputc(&obuf, stmtline); + Bputc(&obuf, stmtline>>8); + Bputc(&obuf, stmtline>>16); + Bputc(&obuf, stmtline>>24); + zaddr(g1, sf); + zaddr(g2, st); + +out: + if(a != AGLOBL && a != ADATA) + pc++; +} + +void +outhist(void) +{ + Gen g; + Hist *h; + char *p, *q, *op, c; + int n; + + g = nullgen; + c = '/'; + for(h = hist; h != H; h = h->link) { + p = h->name; + op = 0; + /* on windows skip drive specifier in pathname */ + if(systemtype(Windows) && p && p[1] == ':'){ + p += 2; + c = *p; + } + if(p && p[0] != c && h->offset == 0 && pathname){ + /* on windows skip drive specifier in pathname */ + if(systemtype(Windows) && pathname[1] == ':') { + op = p; + p = pathname+2; + c = *p; + } else if(pathname[0] == c){ + op = p; + p = pathname; + } + } + while(p) { + q = strchr(p, c); + if(q) { + n = q-p; + if(n == 0){ + n = 1; /* leading "/" */ + *p = '/'; /* don't emit "\" on windows */ + } + q++; + } else { + n = strlen(p); + q = 0; + } + if(n) { + Bputc(&obuf, ANAME); + Bputc(&obuf, D_FILE); /* type */ + Bputc(&obuf, 1); /* sym */ + Bputc(&obuf, '<'); + Bwrite(&obuf, p, n); + Bputc(&obuf, 0); + } + p = q; + if(p == 0 && op) { + p = op; + op = 0; + } + } + g.offset = h->offset; + + Bputc(&obuf, AHISTORY); + Bputc(&obuf, Always); + Bputc(&obuf, 0); + Bputc(&obuf, h->line); + Bputc(&obuf, h->line>>8); + Bputc(&obuf, h->line>>16); + Bputc(&obuf, h->line>>24); + zaddr(&nullgen, 0); + zaddr(&g, 0); + } +} + +#include "../cc/lexbody" +#include "../cc/macbody" |