diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/aux/na |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aux/na')
-rwxr-xr-x | sys/src/cmd/aux/na/mkfile | 13 | ||||
-rwxr-xr-x | sys/src/cmd/aux/na/na.h | 13 | ||||
-rwxr-xr-x | sys/src/cmd/aux/na/na.y | 1199 |
3 files changed, 1225 insertions, 0 deletions
diff --git a/sys/src/cmd/aux/na/mkfile b/sys/src/cmd/aux/na/mkfile new file mode 100755 index 000000000..bae1bad12 --- /dev/null +++ b/sys/src/cmd/aux/na/mkfile @@ -0,0 +1,13 @@ +</$objtype/mkfile + +TARG=na +HFILES=\ + na.h\ + +OFILES=\ + y.tab.$O\ + +YFILES=na.y\ + +BIN=/$objtype/bin/aux +</sys/src/cmd/mkone diff --git a/sys/src/cmd/aux/na/na.h b/sys/src/cmd/aux/na/na.h new file mode 100755 index 000000000..ef8bc3cde --- /dev/null +++ b/sys/src/cmd/aux/na/na.h @@ -0,0 +1,13 @@ +#ifndef NA_H +#define NA_H + +struct na_patch { + unsigned lwoff; + unsigned char type; +}; + +int na_fixup(unsigned long *script, unsigned long pa_script, unsigned long pa_reg, + struct na_patch *patch, int patches, + int (*externval)(int x, unsigned long *v)); + +#endif diff --git a/sys/src/cmd/aux/na/na.y b/sys/src/cmd/aux/na/na.y new file mode 100755 index 000000000..6350186d7 --- /dev/null +++ b/sys/src/cmd/aux/na/na.y @@ -0,0 +1,1199 @@ +/* NCR53c8xx assembler */ +%{ +#include <u.h> +#include <libc.h> +#include <stdio.h> +#include <ctype.h> + +#include "na.h" + +#define COND_WAIT (1L << 16) +#define COND_TRUE (1L << 19) +#define COND_INTFLY (1L << 20) +#define COND_CARRY (1L << 21) +#define COND_REL (1L << 23) +#define COND_PHASE (1L << 17) +#define COND_DATA (1L << 18) + +#define IO_REL (1L << 26) + +#define MOVE_MODE (1L << 27) + +int yylex(void); +int yyparse(void); +void assemble(void); +void yyerror(char *, ...); +void yywarn(char *, ...); +void p2error(int line, char *); + +struct addr { + int type; /* 0 - direct, 1 - indirect 2 - table indirect */ + unsigned long offset; +}; + +typedef enum Type { Const, Addr, Table, Extern, Reg, Unknown, Error } Type; + +struct sym { + char *name; + int set; + Type t; + long value; + struct sym *next; +}; + +struct sym *findsym(char *name); +struct sym *symlist; + +void newsym(struct sym *s, Type t, long v); + +struct binary { + char len; + unsigned long data[3]; + unsigned char patch[3]; +}; + +#define MAXCPPOPTS 30 +#define MAX_PATCHES 1000 +struct na_patch patch[MAX_PATCHES]; +int patches; + +struct binary out; + +struct expval { + Type t; + long value; +}; + +struct expval eval(struct expval a, struct expval b, char op); + +int patchtype(Type t); +void fixup(void); + +unsigned dot; +unsigned externs; +int errors, warnings; +struct sym *externp[100]; + +void regmove(unsigned char src_reg, unsigned char op, + unsigned char dst_reg, struct expval *imm); + +void preprocess(char *in, FILE *out); + +int mk24bitssigned(long *l); +long mkreladdr(long value, int len); +long chkreladdr(int d, struct expval *e, int len, long relrv); +int pass2; +FILE *in_f; + +int yyline = 0; +char yyfilename[200]; +char line[500]; +char *cppopts[MAXCPPOPTS]; +int ncppopts; +int wflag; +%} + +%union { + long n; + struct sym *s; + struct expval e; +} + +%token NUM MOVE WHEN SYMBOL SELECT WAIT DISCONNECT RESELECT SET CLEAR +%token DATA_OUT DATA_IN COMMAND STATUS RESERVED_OUT RESERVED_IN MESSAGE_OUT +%token MESSAGE_IN WITH ATN FAIL CARRY TARGET ACK COMMENT TO +%token SCNTL0 SCNTL1 SCNTL2 SCNTL3 SCID SXFER SDID GPREG +%token SFBR SOCL SSID SBCL DSTAT SSTAT0 SSTAT1 SSTAT2 +%token ISTAT CTEST0 CTEST1 CTEST2 CTEST3 TEMP DFIFO CTEST4 CTEST5 CTEST6 +%token DBC DCMD DNAD DSP DSPS DMODE DIEN DWT DCNTL ADDER +%token SIEN0 SIEN1 SIST0 SIST1 SLPAR MACNTL GPCNTL STIME0 STIME1 RESPID +%token STEST0 STEST1 STEST2 STEST3 SIDL SODL SBDL +%token SHL SHR AND OR XOR ADD ADDC +%token JUMP CALL RETURN INT INTFLY NOT ABSOLUTE MASK IF REL PTR +%token TABLE FROM MEMORY NOP EXTERN +%token SCRATCHA0 SCRATCHA1 SCRATCHA2 SCRATCHA3 +%token SCRATCHB0 SCRATCHB1 SCRATCHB2 SCRATCHB3 +%token SCRATCHC0 SCRATCHC1 SCRATCHC2 SCRATCHC3 +%token DSA0 DSA1 DSA2 DSA3 +%token DEFW + +%left '-' '+' +%left '*' '/' +%left NEG /* negation--unary minus */ +%right '^' /* exponentiation */ +%type <n> NUM phase .atn set_list set_bit regA reg +%type <n> set_cmd .cond condsfbr condphase +%type <n> jump_or_call .ptr +%type <s> SYMBOL +%type <e> exp byteexp regexp + +/* Grammar follows */ +%% +input: /* empty string */ + | input line +; + +line: .label .opcode .comment '\n' + { + if (pass2) { + int x; + for (x = 0; x < out.len; x++) { + printf("/* %.4x */ 0x%.8lxL,", + dot, out.data[x]); + if (x == 0) { + printf(" /*\t"); + fwrite(line, + strlen(line) - 1, 1, stdout); + printf(" */"); + } + printf("\n"); + if (out.patch[x]) { + patch[patches].lwoff = dot / 4; + patch[patches].type = out.patch[x]; + patches++; + } + dot += 4; + } + } + else + dot += 4 * out.len; + } + | ABSOLUTE SYMBOL '=' exp .comment '\n' + { + setsym($2, $4.t, $4.value); + if (pass2) { + printf("\t\t\t/*\t"); + fwrite(line, strlen(line) - 1, 1, stdout); + printf(" */\n"); + } + } + | SYMBOL '=' exp .comment '\n' + { + setsym($1, $3.t, $3.value); + if (pass2) { + printf("\t\t\t/*\t"); + fwrite(line, strlen(line) - 1, 1, stdout); + printf(" */\n"); + } + } + | EXTERN SYMBOL { + if (pass2) { + printf("\t\t\t/*\t"); + fwrite(line, strlen(line) - 1, 1, stdout); + printf(" */\n"); + } + else { + if (!pass2) + externp[externs] = $2; + setsym($2, Extern, externs++); + } + } + ; + +.comment: COMMENT + | /* nothing */ + ; + +.label: SYMBOL ':' { + if ($1->t != Unknown) + { + if (!pass2) + yyerror("multiply defined symbol"); + } + else { + $1->t = Addr; + $1->value = dot; + } + } + | /* nothing */ + ; + +set_cmd: SET { $$ = 3; } + | CLEAR { $$ = 4; } + ; + +set_bit: CARRY { $$ = 0x400; } + | TARGET { $$ = 0x200; } + | ACK { $$ = 0x40; } + | ATN { $$ = 0x8; } + ; + +set_list: set_list ',' set_bit { $$ = $1 | $3; } + | set_list AND set_bit { $$ = $1 | $3; } + | set_bit { $$ = $1; } + ; + +opcode: set_cmd set_list { + out.len = 2; + out.data[0] = (1L << 30) | ((long)$1 << 27) | $2; + out.data[1] = 0; + out.patch[0] = out.patch[1] = 0; + } + | DISCONNECT + { + out.len = 2; + out.data[0] = 0x48020000L; + out.data[1] = 0; + out.patch[0] = out.patch[1] = 0; + } + | INT exp .cond { + out.len = 2; + out.data[0] = $3 | 0x98000000L; + out.data[1] = $2.value; + out.patch[0] = out.patch[1] = 0; + } + | INTFLY exp .cond { + out.len = 2; + out.data[0] = $3 | 0x98000000L | COND_INTFLY; + out.data[1] = $2.value; + out.patch[0] = out.patch[1] = 0; + } + | jump_or_call exp .cond { + out.len = 2; + out.data[0] = $1 | $3 | chkreladdr(1, &$2, 2, COND_REL); + out.patch[0] = 0; + } + | jump_or_call REL '(' exp ')' .cond { + out.len = 2; + out.data[0] = $1 | $6 | COND_REL; + out.data[1] = mkreladdr($4.value, 2); + out.patch[0] = out.patch[1] = 0; + } + | MOVE exp ',' .ptr regexp ',' with_or_when phase { + out.len = 2; + out.data[0] = ($8 << 24) | $2.value | ($4 << 29) | MOVE_MODE; + out.data[1] = $5.value; + out.patch[0] = 0; + out.patch[1] = patchtype($5.t); + } + | MOVE FROM exp ',' with_or_when phase { + out.len = 2; + out.data[0] = ($6 << 24) | (1L << 28) | MOVE_MODE; + out.data[1] = $3.value; + out.patch[0] = 0; + out.patch[1] = patchtype($3.t); + } + | MOVE MEMORY exp ',' regexp ',' regexp { + out.len = 3; + out.data[0] = 0xc0000000L | $3.value; + out.data[1] = $5.value; + out.data[2] = $7.value; + out.patch[0] = 0; + out.patch[1] = patchtype($5.t); + out.patch[2] = patchtype($7.t); + } + | MOVE regA TO regA { regmove($2, 2, $4, 0); } /* do reg to sfbr moves using or 0 */ + | MOVE exp TO regA { regmove($4, 0, $4, &$2); } + | MOVE regA '|' exp TO regA { regmove($2, 2, $6, &$4); } + | MOVE regA '&' exp TO regA { regmove($2, 4, $6, &$4); } + | MOVE regA '+' exp TO regA { regmove($2, 6, $6, &$4); } + | MOVE regA '-' exp TO regA { regmove($2, 6, $6, &$4); } + | MOVE regA '+' exp TO regA WITH CARRY { + regmove($2, 7, $6, &$4); + } + | MOVE regA '-' exp TO regA WITH CARRY { + $4.value = -$4.value; + regmove($2, 7, $6, &$4); + } + | MOVE regA SHL TO regA { regmove($2, 1, $5, 0); } + | MOVE regA SHR TO regA { regmove($2, 5, $5, 0); } + | MOVE regA XOR exp TO regA { regmove($2, 3, $6, &$4); } + | NOP { + out.len = 2; + out.data[0] = 0x80000000L; + out.data[1] = 0; + out.patch[0] = out.patch[1] = 0; + } + | RESELECT exp ',' exp { + out.len = 2; + out.data[0] = 0x40000000L | ((long)$2.value << 16) | (1L << 9) | chkreladdr(1, &$4, 2, IO_REL); + out.patch[0] = 0; + } + | RESELECT exp ',' REL '(' exp ')' { + out.len = 2; + out.data[0] = 0x40000000L | IO_REL + | ((long)$2.value << 16) | (1L << 9); + out.data[1] = mkreladdr($6.value, 2); + out.patch[0] = out.patch[1] = 0; + } + | RESELECT FROM exp ',' exp { + out.len = 2; + out.data[0] = 0x40000000L | (1L << 25) | $3.value | chkreladdr(1, &$5, 2, IO_REL); + out.patch[0] = 5; + } + | RESELECT FROM exp ',' REL '(' exp ')' { + out.len = 2; + out.data[0] = 0x40000000L | (1L << 25) | IO_REL | $3.value; + out.patch[0] = 5; + out.data[1] = mkreladdr($7.value, 2); + out.patch[1] = 0; + } + | RETURN .cond { + + out.len = 2; + out.data[0] = 0x90000000L | $2; + out.data[1] = 0; + out.patch[0] = out.patch[1] = 0; + } + | SELECT .atn exp ',' exp { + out.len = 2; + out.data[0] = + 0x40000000L | ((long)$3.value << 16) | (1L << 9) | $2 | chkreladdr(1, &$5, 2, IO_REL); + out.patch[0] = 0; + } + | SELECT .atn exp ',' REL '(' exp ')' { + out.len = 2; + out.data[0] = 0x40000000L | (1L << 26) + | ((long)$3.value << 16) | (1L << 9) | $2; + out.data[1] = mkreladdr($7.value, 2); + out.patch[0] = out.patch[1] = 0; + } + | SELECT .atn FROM exp ',' exp { + out.len = 2; + out.data[0] = 0x40000000L | (1L << 25) | $4.value | $2 | chkreladdr(1, &$6, 2, IO_REL); + out.patch[0] = 5; + } + | SELECT .atn FROM exp ',' REL '(' exp ')' { + out.len = 2; + out.data[0] = 0x40000000L | (1L << 25) | IO_REL | $4.value | $2; + out.patch[0] = 5; + out.data[1] = mkreladdr($8.value, 2); + out.patch[1] = 0; + } + | WAIT DISCONNECT { + out.len = 2; + out.data[0] = 0x48000000L; + out.data[1] = 0; + out.patch[0] = out.patch[1] = 0; + } + | WAIT RESELECT exp { + out.len = 2; + out.data[0] = 0x50000000L | chkreladdr(1, &$3, 2, IO_REL); + out.patch[0] = 0; + } + | WAIT RESELECT REL '(' exp ')' { + out.len = 2; + out.data[0] = 0x50000000L | (1L << 26); + out.data[1] = mkreladdr($5.value, 2); + out.patch[0] = out.patch[1] = 0; + } + | WAIT SELECT exp { + out.len = 2; + out.data[0] = 0x40000000L | (1L << 9) | chkreladdr(1, &$3, 2, IO_REL); + out.patch[0] = 0; + } + | WAIT SELECT REL '(' exp ')' { + out.len = 2; + out.data[0] = 0x40000000L | (1L << 26) | (1L << 9); + out.data[1] = mkreladdr($5.value, 2); + out.patch[0] = out.patch[1] = 0; + } + | DEFW exp { + out.len = 1; + out.data[0] = $2.value; + out.patch[0] = patchtype($2.t); + } + ; + +.ptr: PTR { $$ = 1; } + | { $$ = 0; } + ; + +with_or_when: WITH + | WHEN + ; + +jump_or_call: JUMP { $$ = 0x80000000L; } + | CALL { $$ = 0x88000000L; } + ; + +condsfbr: byteexp { $$ = $1.value | COND_DATA; } + | byteexp AND MASK byteexp { $$ = ($4.value << 8) | $1.value | COND_DATA; } + ; + +condphase: phase { $$ = ($1 << 24) | COND_PHASE; } + +.cond: ',' IF ATN { $$ = COND_TRUE; } + | ',' IF condphase { $$ = $3 | COND_TRUE; } + | ',' IF CARRY { $$ = COND_CARRY | COND_TRUE; } + | ',' IF condsfbr { $$ = $3 | COND_TRUE; } + | ',' IF ATN AND condsfbr { $$ = $5 | COND_TRUE; } + | ',' IF condphase AND condsfbr { $$ = $3 | $5 | COND_TRUE; } + | ',' WHEN condphase { $$ = $3 | COND_WAIT | COND_TRUE; } + | ',' WHEN CARRY { $$ = COND_CARRY | COND_WAIT | COND_TRUE; } + | ',' WHEN condsfbr { $$ = $3 | COND_WAIT | COND_TRUE; } + | ',' WHEN condphase AND condsfbr { $$ = $3 | $5 | COND_WAIT | COND_TRUE; } + | ',' IF NOT ATN { $$ = 0; } + | ',' IF NOT condphase { $$ = $4; } + | ',' IF NOT CARRY { $$ = COND_CARRY; } + | ',' IF NOT condsfbr { $$ = $4; } + | ',' IF NOT ATN OR condsfbr { $$ = $6; } + | ',' IF NOT condphase OR condsfbr { $$ = $4 | $6; } + | ',' WHEN NOT condphase { $$ = $4 | COND_WAIT; } + | ',' WHEN NOT CARRY { $$ = COND_CARRY | COND_WAIT; } + | ',' WHEN NOT condsfbr { $$ = $4 | COND_WAIT; } + | ',' WHEN NOT condphase OR condsfbr { $$ = $4 | $6 | COND_WAIT; } + | { $$ = COND_TRUE; } + ; + +.opcode: opcode + | { out.len = 0; } + ; + +regA: reg + | SFBR { $$ = 8; } + ; + +reg: SCNTL0 { $$ = 0; } + | SCNTL1 { $$ = 1; } + | SCNTL2 { $$ = 2; } + | SCNTL3 { $$ = 3; } + | SCID { $$ = 4; } + | SXFER { $$ = 5; } + | SDID { $$ = 6; } + | GPREG { $$ = 7; } + | SOCL { $$ = 9; } + | SSID { $$ = 0xa; } + | SBCL { $$ = 0xb; } + | DSTAT { $$ = 0xc; } + | SSTAT0 { $$ = 0xd; } + | SSTAT1 { $$ = 0xe; } + | SSTAT2 { $$ = 0xf; } + | DSA0 { $$ = 0x10; } + | DSA1 { $$ = 0x11; } + | DSA2 { $$ = 0x12; } + | DSA3 { $$ = 0x13; } + | ISTAT { $$ = 0x14; } + | CTEST0 { $$ = 0x18; } + | CTEST1 { $$ = 0x19; } + | CTEST2 { $$ = 0x1a; } + | CTEST3 { $$ = 0x1b; } + | TEMP { $$ = 0x1c; } + | DFIFO { $$ = 0x20; } + | CTEST4 { $$ = 0x21; } + | CTEST5 { $$ = 0x22; } + | CTEST6 { $$ = 0x23; } + | DBC { $$ = 0x24; } + | DCMD { $$ = 0x27; } + | DNAD { $$ = 0x28; } + | DSP { $$ = 0x2c; } + | DSPS { $$ = 0x30; } + | SCRATCHA0 { $$ = 0x34; } + | SCRATCHA1 { $$ = 0x35; } + | SCRATCHA2 { $$ = 0x36; } + | SCRATCHA3 { $$ = 0x37; } + | DMODE { $$ = 0x38; } + | DIEN { $$ = 0x39; } + | DWT { $$ = 0x3a; } + | DCNTL { $$ = 0x3b; } + | ADDER { $$ = 0x3c; } + | SIEN0 { $$ = 0x40; } + | SIEN1 { $$ = 0x41; } + | SIST0 { $$ = 0x42; } + | SIST1 { $$ = 0x43; } + | SLPAR { $$ = 0x44; } + | MACNTL { $$ = 0x46; } + | GPCNTL { $$ = 0x47; } + | STIME0 { $$ = 0x48; } + | STIME1 { $$ = 0x49; } + | RESPID { $$ = 0x4a; } + | STEST0 { $$ = 0x4c; } + | STEST1 { $$ = 0x4d; } + | STEST2 { $$ = 0x4e; } + | STEST3 { $$ = 0x4f; } + | SIDL { $$ = 0x50; } + | SODL { $$ = 0x54; } + | SBDL { $$ = 0x58; } + | SCRATCHB0 { $$ = 0x5c; } + | SCRATCHB1 { $$ = 0x5d; } + | SCRATCHB2 { $$ = 0x5e; } + | SCRATCHB3 { $$ = 0x5f; } + | SCRATCHC0 { $$ = 0x60; } + | SCRATCHC1 { $$ = 0x61; } + | SCRATCHC2 { $$ = 0x62; } + | SCRATCHC3 { $$ = 0x63; } + ; + +.atn: ATN { $$ = (1 << 24); } + | /* nothing */ { $$ = 0; } +; + +phase: DATA_OUT { $$ = 0; } + | DATA_IN { $$ = 1; } + | COMMAND { $$ = 2; } + | STATUS { $$ = 3; } + | RESERVED_OUT { $$ = 4; } + | RESERVED_IN { $$ = 5; } + | MESSAGE_OUT { $$ = 6; } + | MESSAGE_IN { $$ = 7; } +; + +byteexp: exp + { + if (pass2 && ($1.value < 0 || $1.value > 255)) { + if (wflag) + yywarn("conversion causes truncation"); + $$.value = $1.value & 0xff; + } + else + $$.value = $1.value; + } + ; + +regexp: exp + | regA { $$.t = Reg; $$.value = $1; } + ; + +exp: NUM { $$.t = Const; $$.value = $1; } + | SYMBOL { + $$.t = $1->t; $$.value = $1->value; + if (pass2 && $1->t == Unknown) + { + yyerror("Undefined symbol %s", $1->name); + $1->t = Error; + $1->value = 0; + $$.t = Error; + $$.value = 0; + } + } + | exp '+' exp { $$ = eval($1, $3, '+'); } + | exp '-' exp { $$ = eval($1, $3, '-'); } + | exp '*' exp { $$ = eval($1, $3, '*'); } + | exp '/' exp { $$ = eval($1, $3, '/'); } + | '-' exp %prec NEG { $$ = eval($2, $2, '_'); } + | '(' exp ')' { $$ = $2; } + | '~' exp %prec NEG { $$ = eval($2, $2, '~'); } + ; +%% + +struct { + char *name; + int tok; +} toktab[] = +{ + { "when", WHEN }, + { "data_out", DATA_OUT }, + { "data_in", DATA_IN }, + { "msg_out", MESSAGE_OUT }, + { "msg_in", MESSAGE_IN }, + { "cmd", COMMAND }, + { "command", COMMAND }, + { "status", STATUS }, + { "move", MOVE }, + { "select", SELECT }, + { "reselect", RESELECT }, + { "disconnect", DISCONNECT }, + { "wait", WAIT }, + { "set", SET }, + { "clear", CLEAR }, + { "with", WITH }, + { "atn", ATN }, + { "fail", FAIL }, + { "carry", CARRY }, + { "target", TARGET }, + { "ack", ACK }, + { "scntl0", SCNTL0 }, + { "scntl1", SCNTL1 }, + { "scntl2", SCNTL2 }, + { "scntl3", SCNTL3 }, + { "scid", SCID }, + { "sxfer", SXFER }, + { "sdid", SDID }, + { "gpreg", GPREG }, + { "sfbr", SFBR }, + { "socl", SOCL }, + { "ssid", SSID }, + { "sbcl", SBCL }, + { "dstat", DSTAT }, + { "sstat0", SSTAT0 }, + { "sstat1", SSTAT1 }, + { "sstat2", SSTAT2 }, + { "dsa", DSA0 }, + { "dsa0", DSA0 }, + { "dsa1", DSA1 }, + { "dsa2", DSA2 }, + { "dsa3", DSA3 }, + { "istat", ISTAT }, + { "ctest0", CTEST0 }, + { "ctest1", CTEST1 }, + { "ctest2", CTEST2 }, + { "ctest3", CTEST3 }, + { "temp", TEMP }, + { "dfifo", DFIFO }, + { "ctest4", CTEST4 }, + { "ctest5", CTEST5 }, + { "ctest6", CTEST6 }, + { "dbc", DBC }, + { "dcmd", DCMD }, + { "dnad", DNAD }, + { "dsp", DSP }, + { "dsps", DSPS }, + { "scratcha", SCRATCHA0 }, + { "scratcha0", SCRATCHA0 }, + { "scratcha1", SCRATCHA1 }, + { "scratcha2", SCRATCHA2 }, + { "scratcha3", SCRATCHA3 }, + { "dmode", DMODE }, + { "dien", DIEN }, + { "dwt", DWT }, + { "dcntl", DCNTL }, + { "adder", ADDER }, + { "sien0", SIEN0 }, + { "sien1", SIEN1 }, + { "sist0", SIST0 }, + { "sist1", SIST1 }, + { "slpar", SLPAR }, + { "macntl", MACNTL }, + { "gpcntl", GPCNTL }, + { "stime0", STIME0 }, + { "stime1", STIME1 }, + { "respid", RESPID }, + { "stest0", STEST0 }, + { "stest1", STEST1 }, + { "stest2", STEST2 }, + { "stest3", STEST3 }, + { "sidl", SIDL }, + { "sodl", SODL }, + { "sbdl", SBDL }, + { "scratchb", SCRATCHB0 }, + { "scratchb0", SCRATCHB0 }, + { "scratchb1", SCRATCHB1 }, + { "scratchb2", SCRATCHB2 }, + { "scratchb3", SCRATCHB3 }, + { "scratchc", SCRATCHC0 }, + { "scratchc0", SCRATCHC0 }, + { "scratchc1", SCRATCHC1 }, + { "scratchc2", SCRATCHC2 }, + { "scratchc3", SCRATCHC3 }, + { "add", ADD }, + { "addc", ADDC }, + { "and", AND }, + { "or", OR }, + { "xor", XOR }, + { "shl", SHL }, + { "shr", SHR }, + { "jump", JUMP }, + { "call", CALL }, + { "return", RETURN }, + { "int", INT }, + { "intfly", INTFLY }, + { "not", NOT }, + { "absolute", ABSOLUTE }, + { "mask", MASK }, + { "if", IF }, + { "rel", REL }, + { "ptr", PTR }, + { "table", TABLE }, + { "from", FROM }, + { "memory", MEMORY }, + { "to", TO }, + { "nop", NOP }, + { "extern", EXTERN }, + { "defw", DEFW }, +}; + +#define TOKS (sizeof(toktab)/sizeof(toktab[0])) + +int lc; +int ll; + +void +yyrewind(void) +{ + rewind(in_f); + ll = lc = 0; + yyline = 0; + dot = 0; +} + +int +yygetc(void) +{ + if (lc == ll) + { + next: + if (fgets(line, 500, in_f) == 0) + return EOF; + /* do nasty check for #line directives */ + if (strncmp(line, "#line", 5) == 0) { + /* #line n "filename" */ + sscanf(line, "#line %d \"%[^\"]", &yyline, yyfilename); + yyline--; + goto next; + } + yyline++; + ll = strlen(line); + lc = 0; + } + return line[lc++]; +} + +void +yyungetc(void) +{ + if (lc <= 0) + exits("ungetc"); + lc--; +} + +int +yylex(void) +{ + char token[100]; + int tl = 0; + int c; + while ((c = yygetc()) != EOF && (c == ' ' || c == '\t')) + ; + if (c == EOF) + return 0; + if (isalpha(c) || c == '_') + { + int x; + do { + token[tl++] = c; + } while ((c = yygetc()) != EOF && (isalnum(c) || c == '_')); + if (c == EOF) + return 0; + yyungetc(); + token[tl] = 0; + for (x = 0; x < TOKS; x++) + if (strcmp(toktab[x].name, token) == 0) + return toktab[x].tok; + /* must be a symbol */ + yylval.s = findsym(token); + return SYMBOL; + } + else if (isdigit(c)) + { + /* accept 0x<digits> or 0b<digits> 0<digits> or <digits> */ + int prefix = c == '0'; + unsigned long n = c - '0'; + int base = 10; + for (;;) + { + c = yygetc(); + if (c == EOF) + return 0; + if (prefix) + { + prefix = 0; + if (c == 'x') { + base = 16; + continue; + } + else if (c == 'b') + { + base = 2; + continue; + } + else + base = 8; + } + if (isdigit(c)) + c -= '0'; + else if (isalpha(c) && base > 10) + { + if (isupper(c)) + c = tolower(c); + c = c - 'a' + 10; + } + else { + yyungetc(); + yylval.n = n; + return NUM; + } + if (c >= base) + yyerror("illegal format number"); + n = n * base + c; + } + } + else if (c == ';') { + /* skip to end of line */ + while ((c = yygetc()) != EOF && c != '\n') + ; + if (c != EOF) + yyungetc(); + return COMMENT; + } + return c; +} + +void +yyerror(char *s, ...) +{ + va_list ap; + + va_start(ap, s); + fprintf(stderr, "%s: %d: ", yyfilename, yyline); + vfprintf(stderr, s, ap); + if (putc('\n', stderr) < 0) + exits("io"); + errors++; + va_end(ap); +} + +void +yywarn(char *s, ...) +{ + va_list ap; + + va_start(ap, s); + fprintf(stderr, "%s: %d: warning: ", yyfilename, yyline); + vfprintf(stderr, s, ap); + if (putc('\n', stderr) < 0) + exits("io"); + warnings++; + va_end(ap); +} + +void +p2error(int line, char *s) +{ + USED(line); + printf("/*\t%s */\n", s); +} + +void +main(int argc, char *argv[]) +{ + int a; + for (a = 1; a < argc; a++) + { + if (argv[a][0] == '-') + switch (argv[a][1]) { + case 'D': + /* #defines for cpp */ + if (ncppopts >= MAXCPPOPTS) { + fprintf(stderr, "too many cpp options\n"); + exits("options"); + } + cppopts[ncppopts++] = argv[a]; + break; + default: + fprintf(stderr, "unrecognised option %s\n", + argv[a]); + exits("options"); + } + else + break; + } + if (a != argc - 1) + { + fprintf(stderr, "usage: na [options] file\n"); + exits("options"); + } + if (access(argv[a], 4) < 0) { + fprintf(stderr, "can't read %s\n", argv[a]); + exits(""); + } + in_f = tmpfile(); + preprocess(argv[a], in_f); + rewind(in_f); + strcpy(yyfilename, argv[a]); + yyparse(); + if (errors) + exits("pass1"); + pass2 = 1; + printf("unsigned long na_script[] = {\n"); + yyrewind(); + yyparse(); + printf("};\n"); + printf("\n"); + printf("#define NA_SCRIPT_SIZE %d\n", dot / 4); + printf("\n"); + fixup(); +/* + assemble(); +*/ + exits(errors ? "pass2" : ""); +} + +void +preprocess(char *in, FILE *out) +{ + Waitmsg *w; + char **argv; + + if (fork() == 0) { + /* child */ + dup(fileno(out), 1); + argv = (char **)malloc(sizeof(char *) * (ncppopts + 5)); + argv[0] = "cpp"; + memcpy(&argv[1], cppopts, sizeof(char *) * ncppopts); + argv[ncppopts + 1] = "-+"; + argv[ncppopts + 2] = "-N"; + argv[ncppopts + 3] = in; + argv[ncppopts + 4] = 0; + exec("/bin/cpp", argv); + fprintf(stderr, "failed to exec cpp (%R)\n"); + exits("exec"); + } + w = wait(); + free(w); +} + +struct sym * +findsym(char *name) +{ + struct sym *s; + for (s = symlist; s; s = s->next) + if (strcmp(name, s->name) == 0) + return s; + s = (struct sym *)malloc(sizeof(*s)); + s->name = strdup(name); + s->t = Unknown; + s->set = 0; + s->next = symlist; + symlist = s; + return s; +} + +void +setsym(struct sym *s, Type t, long v) +{ + if (pass2) { + if (t == Unknown || t == Error) + yyerror("can't resolve symbol"); + else { + s->t = t; + s->value = v; + } + } + else { + if (s->set) + yyerror("multiply defined symbol"); + s->set = 1; + s->t = t; + s->value = v; + } +} + +int +mk24bitssigned(long *l) +{ + if (*l < 0) { + if ((*l & 0xff800000L) != 0xff800000L) { + *l = 0; + return 0; + } + else + *l = (*l) & 0xffffffL; + } + else if (*l > 0xffffffL) { + *l = 0; + return 0; + } + return 1; +} + +static Type addresult[5][5] = { +/* Const Addr Table Extern Reg */ +/* Const */ Const, Addr, Table, Error, Reg, +/* Addr */ Addr, Error, Error, Error, Error, +/* Table */ Table, Error, Error, Error, Error, +/* Extern */ Error, Error, Error, Error, Error, +/* Reg */ Reg, Error, Error, Error, Error, +}; + +static Type subresult[5][5] = { +/* Const Addr Table Extern Reg */ +/* Const */ Const, Error, Error, Error, Error, +/* Addr */ Addr, Const, Error, Error, Error, +/* Table */ Table, Error, Const, Error, Error, +/* Extern */ Error, Error, Error, Const, Error, +/* Reg */ Error, Error, Error, Error, Error, +}; + +static Type muldivresult[5][5] = { +/* Const Addr Table Extern */ +/* Const */ Const, Error, Error, Error, Error, +/* Addr */ Error, Error, Error, Error, Error, +/* Table */ Error, Error, Error, Error, Error, +/* Extern */ Error, Error, Error, Error, Error, +/* Reg */ Error, Error, Error, Error, Error, +}; + +static Type negresult[] = { +/* Const */ Const, +/* Addr */ Error, +/* Table */ Error, +/* Extern */ Error, +/* Reg */ Error, +}; + +int +patchtype(Type t) +{ + switch (t) { + case Addr: + return 1; + case Reg: + return 2; + case Extern: + return 4; + default: + return 0; + } +} + +struct expval +eval(struct expval a, struct expval b, char op) +{ + struct expval c; + + if (a.t == Unknown || b.t == Unknown) { + c.t = Unknown; + c.value = 0; + } + else if (a.t == Error || b.t == Error) { + c.t = Error; + c.value = 0; + } + else { + switch (op) { + case '+': + c.t = addresult[a.t][b.t]; + break; + case '-': + c.t = subresult[a.t][b.t]; + break; + case '*': + case '/': + c.t = muldivresult[a.t][b.t]; + break; + case '_': + case '~': + c.t = negresult[a.t]; + break; + default: + c.t = Error; + break; + } + if (c.t == Error) { + if (pass2) + yyerror("type clash in evaluation"); + c.value = 0; + } + else { + switch (op) { + case '+': + c.value = a.value + b.value; + break; + case '-': + c.value = a.value - b.value; + break; + case '*': + c.value = a.value * b.value; + break; + case '/': + c.value = a.value / b.value; + break; + case '_': + c.value = -a.value; + break; + case '~': + c.value = ~a.value; + break; + } + } + } + return c; +} + +void +regmove(unsigned char src_reg, unsigned char op, + unsigned char dst_reg, struct expval *imm) +{ + unsigned char func, reg; + int immdata; + out.len = 2; + if (src_reg == 8) { + func = 5; + reg = dst_reg; + } + else if (dst_reg == 8) { + func = 6; + reg = src_reg; + } + else { + if (pass2 && src_reg != dst_reg) + yyerror("Registers must be the same"); + func = 7; + reg = src_reg; + } + immdata = imm ? (imm->value & 0xff) : 0; + out.data[0] = 0x40000000L + | ((long)func << 27) + | ((long)op << 24) + | ((long)reg << 16) + | ((long)(immdata) << 8); + out.data[1] = 0; + out.patch[0] = (imm && imm->t == Extern) ? 3 : 0; + out.patch[1] = 0; +} + +long +mkreladdr(long addr, int len) +{ + long rel; + rel = addr - (dot + 4 * len); + mk24bitssigned(&rel); + return rel; +} + +long +chkreladdr(int d, struct expval *e, int len, long relrv) +{ + if (e->t == Addr) { + out.data[d] = mkreladdr(e->value, len); + out.patch[d] = 0; + return relrv; + } else { + out.data[d] = e->value; + out.patch[d] = patchtype(e->t); + return 0; + } +} + +void +fixup(void) +{ + struct sym *s; + int p; + printf("struct na_patch na_patches[] = {\n"); + for (p = 0; p < patches; p++) { + printf("\t{ 0x%.4x, %d }, /* %.8lx */\n", + patch[p].lwoff, patch[p].type, patch[p].lwoff * 4L); + } + if (patches == 0) { + printf("\t{ 0, 0 },\n"); + } + printf("};\n"); + printf("#define NA_PATCHES %d\n", patches); + printf("\n"); + if (externs) { + printf("enum na_external {\n"); + for (p = 0; p < externs; p++) { + printf("\tX_%s,\n", externp[p]->name); + } + printf("};\n"); + } + /* dump all labels (symbols of type Addr) as E_<Name> */ + for (s = symlist; s; s = s->next) + if (s->t == Addr) + break; + if (s) { + printf("\nenum {\n"); + while (s) { + if (s->t == Addr) + printf("\tE_%s = %ld,\n", s->name, s->value); + s = s->next; + } + printf("};\n"); + } + /* dump all Consts as #define A_<Name> value */ + for (s = symlist; s; s = s->next) + if (s->t == Const) + printf("#define A_%s %ld\n", s->name, s->value); +} + |