ref: 47ec5de29e56c4cf223e0582b930b88ca2a589ee
dir: /sys/src/cmd/aux/na/na.y/
/* 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); }