Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

%{
#include "a.h"
%}
%union
{
        Sym     *sym;
        long    lval;
        double  dval;
        char    sval[8];
        Gen     gen;
}
%left   '|'
%left   '^'
%left   '&'
%left   '<' '>'
%left   '+' '-'
%left   '*' '/' '%'
%token  <lval>  LMOVW LMOVB LABS LLOGW LSHW LADDW LCMP LCROP
%token  <lval>  LBRA LFMOV LFCONV LFCMP LFADD LFMA LTRAP LXORW
%token  <lval>  LNOP LEND LRETT LWORD LTEXT LDATA LRETRN
%token  <lval>  LCONST LSP LSB LFP LPC LCREG LFLUSH
%token  <lval>  LREG LFREG LR LCR LF LFPSCR
%token  <lval>  LLR LCTR LSPR LSPREG LSEG LMSR LDCR
%token  <lval>  LSCHED LXLD LXST LXOP LXMV
%token  <lval>  LRLWM LMOVMW LMOVEM LMOVFL LMTFSB LMA LFMOVX
%token  <dval>  LFCONST
%token  <sval>  LSCONST
%token  <sym>   LNAME LLAB LVAR
%type   <lval>  con expr pointer offset sreg
%type   <gen>   addr rreg regaddr name creg freg xlreg lr ctr
%type   <gen>   imm ximm fimm rel psr lcr cbit fpscr fpscrf seg msr mask
%%
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;
        }
|       LSCHED ';'
        {
                nosched = $1;
        }
|       ';'
|       inst ';'
|       error ';'

inst:
/*
 * load ints and bytes
 */
        LMOVW rreg ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVW addr ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVW regaddr ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVB rreg ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVB addr ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVB regaddr ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
/*
 * load and store floats
 */
|       LFMOV addr ',' freg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LFMOV regaddr ',' freg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LFMOV fimm ',' freg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LFMOV freg ',' freg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LFMOV freg ',' addr
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LFMOV freg ',' regaddr
        {
                outcode($1, &$2, NREG, &$4);
        }
/*
 * load and store floats, indexed only
 */
|       LFMOVX regaddr ',' freg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LFMOVX freg ',' regaddr
        {
                outcode($1, &$2, NREG, &$4);
        }
/*
 * store ints and bytes
 */
|       LMOVW rreg ',' addr
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVW rreg ',' regaddr
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVB rreg ',' addr
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVB rreg ',' regaddr
        {
                outcode($1, &$2, NREG, &$4);
        }
/*
 * store floats
 */
|       LMOVW freg ',' addr
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVW freg ',' regaddr
        {
                outcode($1, &$2, NREG, &$4);
        }
/*
 * floating point status
 */
|       LMOVW fpscr ',' freg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVW freg ','  fpscr
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVW freg ',' imm ',' fpscr
        {
                outgcode($1, &$2, NREG, &$4, &$6);
        }
|       LMOVW fpscr ',' creg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVW imm ',' fpscrf
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMTFSB imm ',' con
        {
                outcode($1, &$2, $4, &nullgen);
        }
/*
 * field moves (mtcrf)
 */
|       LMOVW rreg ',' imm ',' lcr
        {
                outgcode($1, &$2, NREG, &$4, &$6);
        }
|       LMOVW rreg ',' creg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVW rreg ',' lcr
        {
                outcode($1, &$2, NREG, &$4);
        }
/*
 * integer operations
 * logical instructions
 * shift instructions
 * unary instructions
 */
|       LADDW rreg ',' sreg ',' rreg
        {
                outcode($1, &$2, $4, &$6);
        }
|       LADDW imm ',' sreg ',' rreg
        {
                outcode($1, &$2, $4, &$6);
        }
|       LADDW rreg ',' imm ',' rreg
        {
                outgcode($1, &$2, NREG, &$4, &$6);
        }
|       LADDW rreg ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LADDW imm ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LLOGW rreg ',' sreg ',' rreg
        {
                outcode($1, &$2, $4, &$6);
        }
|       LLOGW rreg ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LSHW rreg ',' sreg ',' rreg
        {
                outcode($1, &$2, $4, &$6);
        }
|       LSHW rreg ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LSHW imm ',' sreg ',' rreg
        {
                outcode($1, &$2, $4, &$6);
        }
|       LSHW imm ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LABS rreg ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LABS rreg
        {
                outcode($1, &$2, NREG, &$2);
        }
/*
 * multiply-accumulate
 */
|       LMA rreg ',' sreg ',' rreg
        {
                outcode($1, &$2, $4, &$6);
        }
/*
 * move immediate: macro for cau+or, addi, addis, and other combinations
 */
|       LMOVW imm ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVW ximm ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
/*
 * condition register operations
 */
|       LCROP cbit ',' cbit
        {
                outcode($1, &$2, $4.reg, &$4);
        }
|       LCROP cbit ',' con ',' cbit
        {
                outcode($1, &$2, $4, &$6);
        }
/*
 * condition register moves
 * move from machine state register
 */
|       LMOVW creg ',' creg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVW psr ',' creg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVW lcr ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVW psr ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVW seg ',' rreg
        {
                int r;
                r = $2.offset;
                $2.offset = 0;
                outcode($1, &$2, r, &$4);
        }
|       LMOVW rreg ',' seg
        {
                int r;
                r = $4.offset;
                $4.offset = 0;
                outcode($1, &$2, r, &$4);
        }
|       LMOVW xlreg ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVW rreg ',' xlreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVW creg ',' psr
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVW rreg ',' psr
        {
                outcode($1, &$2, NREG, &$4);
        }
/*
 * branch, branch conditional
 * branch conditional register
 * branch conditional to count register
 */
|       LBRA rel
        {
                outcode($1, &nullgen, NREG, &$2);
        }
|       LBRA addr
        {
                outcode($1, &nullgen, NREG, &$2);
        }
|       LBRA '(' xlreg ')'
        {
                outcode($1, &nullgen, NREG, &$3);
        }
|       LBRA ',' rel
        {
                outcode($1, &nullgen, NREG, &$3);
        }
|       LBRA ',' addr
        {
                outcode($1, &nullgen, NREG, &$3);
        }
|       LBRA ',' '(' xlreg ')'
        {
                outcode($1, &nullgen, NREG, &$4);
        }
|       LBRA creg ',' rel
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LBRA creg ',' addr
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LBRA creg ',' '(' xlreg ')'
        {
                outcode($1, &$2, NREG, &$5);
        }
|       LBRA con ',' rel
        {
                outcode($1, &nullgen, $2, &$4);
        }
|       LBRA con ',' addr
        {
                outcode($1, &nullgen, $2, &$4);
        }
|       LBRA con ',' '(' xlreg ')'
        {
                outcode($1, &nullgen, $2, &$5);
        }
|       LBRA con ',' con ',' rel
        {
                Gen g;
                g = nullgen;
                g.type = D_CONST;
                g.offset = $2;
                outcode($1, &g, $4, &$6);
        }
|       LBRA con ',' con ',' addr
        {
                Gen g;
                g = nullgen;
                g.type = D_CONST;
                g.offset = $2;
                outcode($1, &g, $4, &$6);
        }
|       LBRA con ',' con ',' '(' xlreg ')'
        {
                Gen g;
                g = nullgen;
                g.type = D_CONST;
                g.offset = $2;
                outcode($1, &g, $4, &$7);
        }
/*
 * conditional trap
 */
|       LTRAP rreg ',' sreg
        {
                outcode($1, &$2, $4, &nullgen);
        }
|       LTRAP imm ',' sreg
        {
                outcode($1, &$2, $4, &nullgen);
        }
|       LTRAP rreg comma
        {
                outcode($1, &$2, NREG, &nullgen);
        }
|       LTRAP comma
        {
                outcode($1, &nullgen, NREG, &nullgen);
        }
/*
 * floating point operate
 */
|       LFCONV freg ',' freg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LFADD freg ',' freg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LFADD freg ',' freg ',' freg
        {
                outcode($1, &$2, $4.reg, &$6);
        }
|       LFMA freg ',' freg ',' freg ',' freg
        {
                outgcode($1, &$2, $4.reg, &$6, &$8);
        }
|       LFCMP freg ',' freg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LFCMP freg ',' freg ',' creg
        {
                outcode($1, &$2, $6.reg, &$4);
        }
/*
 * CMP
 */
|       LCMP rreg ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LCMP rreg ',' imm
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LCMP rreg ',' rreg ',' creg
        {
                outcode($1, &$2, $6.reg, &$4);
        }
|       LCMP rreg ',' imm ',' creg
        {
                outcode($1, &$2, $6.reg, &$4);
        }
/*
 * rotate and mask
 */
|       LRLWM  imm ',' rreg ',' imm ',' rreg
        {
                outgcode($1, &$2, $4.reg, &$6, &$8);
        }
|       LRLWM  imm ',' rreg ',' mask ',' rreg
        {
                outgcode($1, &$2, $4.reg, &$6, &$8);
        }
|       LRLWM  rreg ',' rreg ',' imm ',' rreg
        {
                outgcode($1, &$2, $4.reg, &$6, &$8);
        }
|       LRLWM  rreg ',' rreg ',' mask ',' rreg
        {
                outgcode($1, &$2, $4.reg, &$6, &$8);
        }
/*
 * load/store multiple
 */
|       LMOVMW addr ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LMOVMW rreg ',' addr
        {
                outcode($1, &$2, NREG, &$4);
        }
/*
 * various indexed load/store
 * indexed unary (eg, cache clear)
 */
|       LXLD regaddr ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LXLD regaddr ',' imm ',' rreg
        {
                outgcode($1, &$2, NREG, &$4, &$6);
        }
|       LXST rreg ',' regaddr
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LXST rreg ',' imm ',' regaddr
        {
                outgcode($1, &$2, NREG, &$4, &$6);
        }
|       LXMV regaddr ',' rreg
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LXMV rreg ',' regaddr
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LXOP regaddr
        {
                outcode($1, &$2, NREG, &nullgen);
        }
/*
 * NOP
 */
|       LNOP comma
        {
                outcode($1, &nullgen, NREG, &nullgen);
        }
|       LNOP rreg comma
        {
                outcode($1, &$2, NREG, &nullgen);
        }
|       LNOP freg comma
        {
                outcode($1, &$2, NREG, &nullgen);
        }
|       LNOP ',' rreg
        {
                outcode($1, &nullgen, NREG, &$3);
        }
|       LNOP ',' freg
        {
                outcode($1, &nullgen, NREG, &$3);
        }
/*
 * word
 */
|       LWORD imm comma
        {
                outcode($1, &$2, NREG, &nullgen);
        }
|       LWORD ximm comma
        {
                outcode($1, &$2, NREG, &nullgen);
        }
/*
 * END
 */
|       LEND comma
        {
                outcode($1, &nullgen, NREG, &nullgen);
        }
/*
 * TEXT/GLOBL
 */
|       LTEXT name ',' imm
        {
                outcode($1, &$2, NREG, &$4);
        }
|       LTEXT name ',' con ',' imm
        {
                outcode($1, &$2, $4, &$6);
        }
|       LTEXT name ',' imm ':' imm
        {
                outgcode($1, &$2, NREG, &$6, &$4);
        }
|       LTEXT name ',' con ',' imm ':' imm
        {
                outgcode($1, &$2, $4, &$8, &$6);
        }
/*
 * DATA
 */
|       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);
        }
/*
 * RETURN
 */
|       LRETRN  comma
        {
                outcode($1, &nullgen, NREG, &nullgen);
        }

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;
        }

rreg:
        sreg
        {
                $$ = nullgen;
                $$.type = D_REG;
                $$.reg = $1;
        }

xlreg:
        lr
|       ctr

lr:
        LLR
        {
                $$ = nullgen;
                $$.type = D_SPR;
                $$.offset = $1;
        }

lcr:
        LCR
        {
                $$ = nullgen;
                $$.type = D_CREG;
                $$.reg = NREG;  /* whole register */
        }

ctr:
        LCTR
        {
                $$ = nullgen;
                $$.type = D_SPR;
                $$.offset = $1;
        }

msr:
        LMSR
        {
                $$ = nullgen;
                $$.type = D_MSR;
        }

psr:
        LSPREG
        {
                $$ = nullgen;
                $$.type = D_SPR;
                $$.offset = $1;
        }
|       LSPR '(' con ')'
        {
                $$ = nullgen;
                $$.type = $1;
                $$.offset = $3;
        }
|       LDCR '(' con ')'
        {
                $$ = nullgen;
                $$.type = $1;
                $$.offset = $3;
        }
|       LDCR '(' sreg ')'
        {
                $$ = nullgen;
                $$.type = $1;
                $$.reg = $3;
                $$.offset = 0;
        }
|       msr

seg:
        LSEG '(' con ')'
        {
                if($3 < 0 || $3 > 15)
                        yyerror("segment register number out of range");
                $$ = nullgen;
                $$.type = D_SREG;
                $$.reg = $3;
                $$.offset = NREG;
        }
|       LSEG '(' sreg ')'
        {
                $$ = nullgen;
                $$.type = D_SREG;
                $$.reg = NREG;
                $$.offset = $3;
        }

fpscr:
        LFPSCR
        {
                $$ = nullgen;
                $$.type = D_FPSCR;
                $$.reg = NREG;
        }

fpscrf:
        LFPSCR '(' con ')'
        {
                $$ = nullgen;
                $$.type = D_FPSCR;
                $$.reg = $3;
        }

freg:
        LFREG
        {
                $$ = nullgen;
                $$.type = D_FREG;
                $$.reg = $1;
        }
|       LF '(' con ')'
        {
                $$ = nullgen;
                $$.type = D_FREG;
                $$.reg = $3;
        }

creg:
        LCREG
        {
                $$ = nullgen;
                $$.type = D_CREG;
                $$.reg = $1;
        }
|       LCR '(' con ')'
        {
                $$ = nullgen;
                $$.type = D_CREG;
                $$.reg = $3;
        }


cbit:   con
        {
                $$ = nullgen;
                $$.type = D_REG;
                $$.reg = $1;
        }

mask:
        con ',' con
        {
                int mb, me;
                ulong v;

                $$ = nullgen;
                $$.type = D_CONST;
                mb = $1;
                me = $3;
                if(mb < 0 || mb > 31 || me < 0 || me > 31){
                        yyerror("illegal mask start/end value(s)");
                        mb = me = 0;
                }
                if(mb <= me)
                        v = ((ulong)~0L>>mb) & (~0L<<(31-me));
                else
                        v = ~(((ulong)~0L>>(me+1)) & (~0L<<(31-(mb-1))));
                $$.offset = v;
        }

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;
        }

sreg:
        LREG
|       LR '(' con ')'
        {
                if($$ < 0 || $$ >= NREG)
                        print("register value out of range\n");
                $$ = $3;
        }

regaddr:
        '(' sreg ')'
        {
                $$ = nullgen;
                $$.type = D_OREG;
                $$.reg = $2;
                $$.offset = 0;
        }
|       '(' sreg '+' sreg ')'
        {
                $$ = nullgen;
                $$.type = D_OREG;
                $$.reg = $2;
                $$.xreg = $4;
                $$.offset = 0;
        }

addr:
        name
|       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;
        }

comma:
|       ','

offset:
        {
                $$ = 0;
        }
|       '+' con
        {
                $$ = $2;
        }
|       '-' con
        {
                $$ = -$2;
        }

pointer:
        LSB
|       LSP
|       LFP

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;
        }