summaryrefslogtreecommitdiff
path: root/utils/ia
diff options
context:
space:
mode:
authorRichard Miller <miller.research@gmail.com>2020-11-09 11:36:14 +0000
committerRichard Miller <miller.research@gmail.com>2020-11-09 11:36:14 +0000
commit6e84dc968bc4eaf047fbefcba2f670940718dda8 (patch)
tree523d2f81946b1e0abe4afddf1d2fce7e1525b7d7 /utils/ia
parent2a571cc0ece4073eb56d5ccfc3e061a09a353e13 (diff)
Add toolchain for riscv (ia ic il) and riscv64 (ja jc jl)
Because the rv64 ISA is very nearly a proper superset of rv32, the compilers ic and jc are actually the same program, which compiles to .i or .j depending on how it is invoked; similarly for ia/ja and il/jl. It is also possible to invoke ia/ic/il with a '-j' option to specify 64-bit behaviour.
Diffstat (limited to 'utils/ia')
-rw-r--r--utils/ia/a.h181
-rw-r--r--utils/ia/a.y514
-rw-r--r--utils/ia/lex.c642
-rw-r--r--utils/ia/mkfile31
4 files changed, 1368 insertions, 0 deletions
diff --git a/utils/ia/a.h b/utils/ia/a.h
new file mode 100644
index 00000000..32c27f17
--- /dev/null
+++ b/utils/ia/a.h
@@ -0,0 +1,181 @@
+#include <lib9.h>
+#include <bio.h>
+#include "../ic/i.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Sym Sym;
+typedef struct Gen Gen;
+typedef struct Io Io;
+typedef struct Hist Hist;
+
+#define MAXALIGN 7
+#define FPCHIP 1
+#define NSYMB 500
+#define BUFSIZ 8192
+#define HISTSZ 20
+#define NINCLUDE 10
+#define NHUNK 10000
+#define EOF (-1)
+#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;
+ long 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;
+ long offset;
+ short type;
+ short reg;
+ short name;
+ double dval;
+ char sval[8];
+ vlong vval;
+};
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ long line;
+ long offset;
+};
+#define H ((Hist*)0)
+
+enum
+{
+ CLAST,
+ CMACARG,
+ CMACRO,
+ CPREPROC,
+};
+
+EXTERN char debug[256];
+EXTERN Sym* hash[NHASH];
+EXTERN char* Dlist[30];
+EXTERN int nDlist;
+EXTERN Hist* ehist;
+EXTERN int newflag;
+EXTERN Hist* hist;
+EXTERN char* hunk;
+EXTERN char* include[NINCLUDE];
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN long lineno;
+EXTERN int nerrors;
+EXTERN long nhunk;
+EXTERN int ninclude;
+EXTERN int nosched;
+EXTERN Gen nullgen;
+EXTERN char* outfile;
+EXTERN int pass;
+EXTERN char* pathname;
+EXTERN long pc;
+EXTERN int peekc;
+EXTERN int sym;
+EXTERN char symb[NSYMB];
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN long thunk;
+EXTERN Biobuf obuf;
+
+void* alloc(long);
+void* allocn(void*, long, long);
+void errorexit(void);
+void pushio(void);
+void newio(void);
+void newfile(char*, int);
+Sym* slookup(char*);
+Sym* lookup(void);
+void syminit(Sym*);
+long yylex(void);
+int getc(void);
+int getnsc(void);
+void unget(int);
+int escchar(int);
+void cinit(void);
+void pinit(char*);
+void cclean(void);
+void outcode(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 macprag(void);
+void maclin(void);
+void macif(int);
+void macend(void);
+void dodefine(char*);
+void prfile(long);
+void outhist(void);
+void linehist(char*, int);
+void gethunk(void);
+void yyerror(char*, ...);
+int yyparse(void);
+void setinclude(char*);
+int assemble(char*);
+
+/*
+ * system-dependent stuff from ../cc/compat.c
+ */
+
+enum /* keep in synch with ../cc/cc.h */
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2
+};
+int mywait(int*);
+int mycreat(char*, int);
+int systemtype(int);
+int pathchar(void);
+char* mygetwd(char*, int);
+int myexec(char*, char*[]);
+int mydup(int, int);
+int myfork(void);
+int mypipe(int*);
+void* mysbrk(ulong);
diff --git a/utils/ia/a.y b/utils/ia/a.y
new file mode 100644
index 00000000..e7470860
--- /dev/null
+++ b/utils/ia/a.y
@@ -0,0 +1,514 @@
+%{
+#include "a.h"
+%}
+%union
+{
+ Sym *sym;
+ vlong lval;
+ double dval;
+ char sval[8];
+ Gen gen;
+}
+%left '|'
+%left '^'
+%left '&'
+%left '<' '>'
+%left '+' '-'
+%left '*' '/' '%'
+%token <lval> LADD LMUL LBEQ LBR LBRET LCALL LFLT2 LFLT3
+%token <lval> LMOVB LMOVBU LMOVW LMOVF LLUI LSYS LSYS0 LCSR LSWAP LAMO
+%token <lval> LCONST LSP LSB LFP LPC LREG LFREG LR FR LCTL
+%token <lval> LDATA LTEXT LWORD
+%token <sval> LSCONST
+%token <dval> LFCONST
+%token <sym> LNAME LLAB LVAR
+%type <lval> con expr pointer offset sreg freg oprrr
+%type <gen> rreg dreg ctlreg drreg
+%type <gen> addr name oreg rel imm ximm fimm
+%%
+prog:
+| prog 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:
+ LADD imm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| oprrr rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LADD imm ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| oprrr rreg ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+
+| LFLT2 drreg ',' drreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LFLT3 drreg ',' freg ',' drreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+
+| LBEQ rreg ',' sreg ',' rel
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+
+| LBEQ rreg ',' rel
+ {
+ Gen regzero;
+ regzero = nullgen;
+ regzero.type = D_REG;
+ regzero.reg = 0;
+ outcode($1, &regzero, $2.reg, &$4);
+ }
+
+| LBR rel
+ {
+ outcode($1, &nullgen, NREG, &$2);
+ }
+
+| LBR oreg
+ {
+ outcode($1, &nullgen, NREG, &$2);
+ }
+
+
+| LBRET
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+
+| LCALL sreg ',' addr
+ {
+ outcode($1, &nullgen, $2, &$4);
+ }
+| LCALL sreg ',' rel
+ {
+ outcode($1, &nullgen, $2, &$4);
+ }
+
+| LMOVB addr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVBU addr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVB rreg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+
+| LMOVF addr ',' dreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVF dreg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVF dreg ',' dreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+
+
+| LMOVW imm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW ximm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW rreg ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW addr ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW rreg ',' addr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LMOVW rreg ',' ctlreg
+ {
+ Gen regzero;
+ regzero = nullgen;
+ regzero.type = D_REG;
+ regzero.reg = 0;
+ outcode(ACSRRW, &$4, $2.reg, &regzero);
+ }
+| LMOVW imm ',' ctlreg
+ {
+ Gen regzero;
+ int r = $2.offset;
+ if(r < 0 || r >= NREG)
+ yyerror("immediate value out of range");
+ regzero = nullgen;
+ regzero.type = D_REG;
+ regzero.reg = 0;
+ outcode(ACSRRWI, &$4, r, &regzero);
+ }
+| LMOVW ctlreg ',' rreg
+ {
+ outcode(ACSRRS, &$2, REGZERO, &$4);
+ }
+
+| LLUI name ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LLUI imm ',' rreg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+
+
+| LSYS imm
+ {
+ outcode($1, &nullgen, NREG, &$2);
+ }
+
+| LSYS0
+ {
+ Gen syscon;
+ syscon = nullgen;
+ syscon.type = D_CONST;
+ syscon.offset = $1;
+ outcode(ASYS, &nullgen, NREG, &syscon);
+ }
+
+| LCSR ctlreg ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+
+| LCSR ctlreg ',' '$' con ',' rreg
+ {
+ if($5 < 0 || $5 >= NREG)
+ yyerror("immediate value out of range");
+ outcode($1 + (ACSRRWI-ACSRRW), &$2, $5, &$7);
+ }
+
+| LSWAP rreg ',' sreg ',' rreg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+
+| LAMO con ',' rreg ',' sreg ',' rreg
+ {
+ outcode($1, &$4, ($2<<16)|$6, &$8);
+ }
+
+| LTEXT name ',' imm
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LTEXT name ',' con ',' imm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+
+| LDATA name '/' con ',' imm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LDATA name '/' con ',' ximm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LDATA name '/' con ',' fimm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+
+| LWORD imm
+ {
+ outcode($1, &nullgen, NREG, &$2);
+ }
+
+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;
+ }
+
+oprrr:
+ LADD
+| LMUL
+
+addr:
+ oreg
+| name
+
+oreg:
+ '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $2;
+ $$.offset = 0;
+ }
+| con '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $3;
+ $$.offset = $1;
+ }
+
+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
+
+rreg:
+ sreg
+ {
+ $$ = nullgen;
+ $$.type = D_REG;
+ $$.reg = $1;
+ }
+
+dreg:
+ freg
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $1;
+ }
+
+drreg:
+ dreg
+| rreg
+
+sreg:
+ LREG
+| LR '(' expr ')'
+ {
+ if($3 < 0 || $3 >= NREG)
+ yyerror("register value out of range");
+ $$ = $3;
+ }
+
+freg:
+ LFREG
+| FR '(' expr ')'
+ {
+ if($3 < 0 || $3 >= NREG)
+ yyerror("register value out of range");
+ $$ = $3;
+ }
+
+ctlreg:
+ LCTL '(' expr ')'
+ {
+ if($3 < 0 || $3 >= 0xFFF)
+ yyerror("CSR value out of range");
+ $$ = nullgen;
+ $$.type = D_CTLREG;
+ $$.offset = $3;
+ }
+
+ximm:
+ '$' addr
+ {
+ $$ = $2;
+ $$.type = D_CONST;
+ }
+| '$' LSCONST
+ {
+ $$ = nullgen;
+ $$.type = D_SCONST;
+ memcpy($$.sval, $2, sizeof($$.sval));
+ }
+
+fimm:
+ '$' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $2;
+ }
+| '$' '-' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = -$3;
+ }
+
+imm:
+ '$' con
+ {
+ $$ = nullgen;
+ $$.type = D_CONST;
+ $$.offset = $2;
+ if(thechar == 'j' && (vlong)$$.offset != $2){
+ $$.type = D_VCONST;
+ $$.vval = $2;
+ }
+ }
+
+con:
+ LCONST
+| LVAR
+ {
+ $$ = $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/utils/ia/lex.c b/utils/ia/lex.c
new file mode 100644
index 00000000..ac12f42d
--- /dev/null
+++ b/utils/ia/lex.c
@@ -0,0 +1,642 @@
+#include <ctype.h>
+#define EXTERN
+#include "a.h"
+#include "y.tab.h"
+
+void
+main(int argc, char *argv[])
+{
+ char *p;
+ int nout, nproc, status, i, c;
+
+ thechar = 'i';
+ p = strrchr(argv[0], '/');
+ if(p == nil)
+ p = argv[0];
+ else
+ p++;
+ if(*p == 'j')
+ thechar = 'j';
+ memset(debug, 0, sizeof(debug));
+ cinit();
+ outfile = 0;
+ include[ninclude++] = ".";
+ 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)
+ Dlist[nDlist++] = p;
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+
+ } ARGEND
+ if(*argv == 0) {
+ print("usage: %ca [-options] file.s\n", thechar);
+ errorexit();
+ }
+ if(debug['j'])
+ thechar = 'j';
+ thestring = (thechar == 'j'? "riscv64" : "riscv");
+ if(argc > 1 && systemtype(Windows)){
+ print("can't assemble multiple files on windows\n");
+ errorexit();
+ }
+ if(argc > 1 && !systemtype(Windows)) {
+ nproc = 1;
+ if(p = getenv("NPROC"))
+ nproc = atol(p); /* */
+ c = 0;
+ nout = 0;
+ for(;;) {
+ while(nout < nproc && argc > 0) {
+ i = myfork();
+ if(i < 0) {
+ i = mywait(&status);
+ if(i < 0)
+ errorexit();
+ if(status)
+ c++;
+ nout--;
+ continue;
+ }
+ if(i == 0) {
+ print("%s:\n", *argv);
+ if(assemble(*argv))
+ errorexit();
+ exits(0);
+ }
+ nout++;
+ argc--;
+ argv++;
+ }
+ i = mywait(&status);
+ if(i < 0) {
+ if(c)
+ errorexit();
+ exits(0);
+ }
+ if(status)
+ c++;
+ nout--;
+ }
+ }
+ if(assemble(argv[0]))
+ errorexit();
+ exits(0);
+}
+
+int
+assemble(char *file)
+{
+ char ofile[100], incfile[20], *p;
+ int i, of;
+
+ strcpy(ofile, file);
+ p = utfrrune(ofile, pathchar());
+ 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";
+ }
+ p = getenv("INCLUDE");
+ if(p) {
+ setinclude(p);
+ } else {
+ if(systemtype(Plan9)) {
+ sprint(incfile,"/%s/include", thestring);
+ setinclude(strdup(incfile));
+ }
+ }
+
+ of = mycreat(outfile, 0664);
+ if(of < 0) {
+ yyerror("%ca: cannot create %s", thechar, outfile);
+ errorexit();
+ }
+ Binit(&obuf, of, OWRITE);
+
+ pass = 1;
+ pinit(file);
+ if(thechar == 'j')
+ dodefine("XLEN=8");
+ else
+ dodefine("XLEN=4");
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ if(nerrors) {
+ cclean();
+ return nerrors;
+ }
+
+ pass = 2;
+ outhist();
+ pinit(file);
+ if(thechar == 'j')
+ dodefine("XLEN=8");
+ else
+ dodefine("XLEN=4");
+ 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,
+ "R16", LREG, 16,
+ "R17", LREG, 17,
+ "R18", LREG, 18,
+ "R19", LREG, 19,
+ "R20", LREG, 20,
+ "R21", LREG, 21,
+ "R22", LREG, 22,
+ "R23", LREG, 23,
+ "R24", LREG, 24,
+ "R25", LREG, 25,
+ "R26", LREG, 26,
+ "R27", LREG, 27,
+ "R28", LREG, 28,
+ "R29", LREG, 29,
+ "R30", LREG, 30,
+ "R31", LREG, 31,
+
+ "F", FR, 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,
+ "F16", LFREG, 16,
+ "F17", LFREG, 17,
+ "F18", LFREG, 18,
+ "F19", LFREG, 19,
+ "F20", LFREG, 20,
+ "F21", LFREG, 21,
+ "F22", LFREG, 22,
+ "F23", LFREG, 23,
+ "F24", LFREG, 24,
+ "F25", LFREG, 25,
+ "F26", LFREG, 26,
+ "F27", LFREG, 27,
+ "F28", LFREG, 28,
+ "F29", LFREG, 29,
+ "F30", LFREG, 30,
+ "F31", LFREG, 31,
+
+ "CSR", LCTL, 0,
+
+ "ADD", LADD, AADD,
+ "SLL", LADD, ASLL,
+ "SLT", LADD, ASLT,
+ "SLTU", LADD, ASLTU,
+ "XOR", LADD, AXOR,
+ "SRL", LADD, ASRL,
+ "OR", LADD, AOR,
+ "AND", LADD, AAND,
+ "SRA", LADD, ASRA,
+ "ADDW", LADD, AADDW,
+ "SLLW", LADD, ASLLW,
+ "SRLW", LADD, ASRLW,
+ "SRAW", LADD, ASRAW,
+ "SUB", LADD, ASUB,
+ "SUBW", LADD, ASUBW,
+
+ "MUL", LMUL, AMUL,
+ "MULH", LMUL, AMULH,
+ "MULHSU", LMUL, AMULHSU,
+ "MULHU", LMUL, AMULHU,
+ "DIV", LMUL, ADIV,
+ "DIVU", LMUL, ADIVU,
+ "REM", LMUL, AREM,
+ "REMU", LMUL, AREMU,
+ "MULW", LMUL, AMULW,
+ "DIVW", LMUL, ADIVW,
+ "DIVUW", LMUL, ADIVUW,
+ "REMW", LMUL, AREMW,
+ "REMUW", LMUL, AREMUW,
+
+ "BEQ", LBEQ, ABEQ,
+ "BNE", LBEQ, ABNE,
+ "BLT", LBEQ, ABLT,
+ "BGE", LBEQ, ABGE,
+ "BLTU", LBEQ, ABLTU,
+ "BGEU", LBEQ, ABGEU,
+ "BGT", LBEQ, ABGT,
+ "BGTU", LBEQ, ABGTU,
+ "BLE", LBEQ, ABLE,
+ "BLEU", LBEQ, ABLEU,
+
+ "JMP", LBR, AJMP,
+
+ "RET", LBRET, ARET,
+ "FENCE_I", LBRET, AFENCE_I,
+ "NOP", LBRET, ANOP,
+ "END", LBRET, AEND,
+
+ "JAL", LCALL, AJAL,
+ "JALR", LCALL, AJAL,
+
+ "MOVB", LMOVB, AMOVB,
+ "MOVH", LMOVB, AMOVH,
+
+ "MOVF", LMOVF, AMOVF,
+ "MOVD", LMOVF, AMOVD,
+
+ "MOVBU", LMOVBU, AMOVBU,
+ "MOVHU", LMOVBU, AMOVHU,
+
+ "MOVW", LMOVW, AMOVW,
+
+ "MOVFD", LFLT2, AMOVFD,
+ "MOVDF", LFLT2, AMOVDF,
+ "MOVWF", LFLT2, AMOVWF,
+ "MOVUF", LFLT2, AMOVUF,
+ "MOVFW", LFLT2, AMOVFW,
+ "MOVWD", LFLT2, AMOVWD,
+ "MOVUD", LFLT2, AMOVUD,
+ "MOVDW", LFLT2, AMOVDW,
+ "ADDF", LFLT3, AADDF,
+ "ADDD", LFLT3, AADDD,
+ "SUBF", LFLT3, ASUBF,
+ "SUBD", LFLT3, ASUBD,
+ "MULF", LFLT3, AMULF,
+ "MULD", LFLT3, AMULD,
+ "DIVF", LFLT3, ADIVF,
+ "DIVD", LFLT3, ADIVD,
+ "CMPLTF", LFLT3, ACMPLTF,
+ "CMPLTD", LFLT3, ACMPLTD,
+ "CMPEQF", LFLT3, ACMPEQF,
+ "CMPEQD", LFLT3, ACMPEQD,
+ "CMPLEF", LFLT3, ACMPLEF,
+ "CMPLED", LFLT3, ACMPLED,
+
+ "LUI", LLUI, ALUI,
+
+ "SYS", LSYS, ASYS,
+ "ECALL", LSYS0, 0,
+ "EBREAK", LSYS0, 1,
+ "CSRRW", LCSR, ACSRRW,
+ "CSRRS", LCSR, ACSRRS,
+ "CSRRC", LCSR, ACSRRC,
+
+ "SWAP_W", LSWAP, ASWAP_W,
+ "SWAP_D", LSWAP, ASWAP_D,
+ "LR_W", LSWAP, ALR_W,
+ "LR_D", LSWAP, ALR_D,
+ "SC_W", LSWAP, ASC_W,
+ "SC_D", LSWAP, ASC_D,
+
+ "AMO_W", LAMO, AAMO_W,
+ "AMO_D", LAMO, AAMO_D,
+
+ "DATA", LDATA, ADATA,
+ "GLOBL", LTEXT, AGLOBL,
+ "TEXT", LTEXT, ATEXT,
+ "WORD", LWORD, AWORD,
+ "DWORD", LWORD, ADWORD,
+
+ "MOV", LMOVW, AMOV,
+ "MOVWU", LMOVBU, AMOVWU,
+
+ 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(mygetwd(pathname, 99) == 0) {
+ pathname = allocn(pathname, 100, 900);
+ if(mygetwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+}
+
+void
+syminit(Sym *s)
+{
+
+ s->type = LNAME;
+ s->value = 0;
+}
+
+void
+cclean(void)
+{
+
+ outcode(AEND, &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)
+{
+ vlong v;
+ long 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:
+ break;
+
+ case D_CTLREG:
+ case D_OREG:
+ case D_CONST:
+ case D_BRANCH:
+ l = a->offset;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ break;
+
+ case D_VCONST:
+ v = a->vval;
+ Bputc(&obuf, v);
+ Bputc(&obuf, v>>8);
+ Bputc(&obuf, v>>16);
+ Bputc(&obuf, v>>24);
+ Bputc(&obuf, v>>32);
+ Bputc(&obuf, v>>40);
+ Bputc(&obuf, v>>48);
+ Bputc(&obuf, v>>56);
+ 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;
+ }
+}
+
+void
+outcode(int a, Gen *g1, int reg, Gen *g2)
+{
+ int sf, st, t;
+ Sym *s;
+
+ 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, reg);
+ Bputc(&obuf, lineno);
+ Bputc(&obuf, lineno>>8);
+ Bputc(&obuf, lineno>>16);
+ Bputc(&obuf, lineno>>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 = pathchar();
+ 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, 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"
diff --git a/utils/ia/mkfile b/utils/ia/mkfile
new file mode 100644
index 00000000..05ccc4dc
--- /dev/null
+++ b/utils/ia/mkfile
@@ -0,0 +1,31 @@
+<../../mkconfig
+
+TARG=ia # also makes ja (for riscv64)
+
+OFILES=\
+ y.tab.$O\
+ lex.$O\
+
+HFILES=\
+ ../ic/i.out.h\
+ y.tab.h\
+ a.h\
+
+YFILES=a.y\
+
+LIBS=cc bio 9 # order is important
+
+BIN=$ROOT/$OBJDIR/bin
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+YFLAGS=-D1 -d
+CFLAGS= $CFLAGS -I../include
+
+lex.$O: ../cc/macbody ../cc/lexbody
+
+$ROOT/$OBJDIR/lib/libcc.a:
+ cd ../cc
+ mk $MKFLAGS install
+ mk $MKFLAGS clean
+
+install:V: $BIN/ja