Allow inline %assert inside of complex immediates.
[b43-tools.git] / assembler / parser.y
index 65bd39dbe1796bbda4c44bf2db9fb0c28236124d..50065bab65e6b7f514c800052aaea51d0c393cf4 100644 (file)
@@ -28,6 +28,7 @@ extern int yyparse(void);
 extern int yylex(void);
 
 static struct operand * store_oper_sanity(struct operand *oper);
+static void assembler_assertion_failed(void);
 
 /* The current .section */
 extern int section;
@@ -38,9 +39,9 @@ extern struct initvals_sect *cur_initvals_sect;
 
 %token SECTION_TEXT SECTION_IVALS
 
-%token ASM_ARCH ASM_START SPR GPR OFFR LR COMMA BRACK_OPEN BRACK_CLOSE PAREN_OPEN PAREN_CLOSE HEXNUM DECNUM ARCH_NEWWORLD ARCH_OLDWORLD LABEL IDENT LABELREF
+%token ASM_ARCH ASM_START ASM_ASSERT SPR GPR OFFR LR COMMA SEMICOLON BRACK_OPEN BRACK_CLOSE PAREN_OPEN PAREN_CLOSE HEXNUM DECNUM ARCH_NEWWORLD ARCH_OLDWORLD LABEL IDENT LABELREF
 
-%token PLUS MINUS MULTIPLY DIVIDE BITW_OR BITW_AND BITW_XOR BITW_NOT LEFTSHIFT RIGHTSHIFT
+%token EQUAL NOT_EQUAL LOGICAL_OR LOGICAL_AND PLUS MINUS MULTIPLY DIVIDE BITW_OR BITW_AND BITW_XOR BITW_NOT LEFTSHIFT RIGHTSHIFT
 
 %token OP_ADD OP_ADDSC OP_ADDC OP_ADDSCC OP_SUB OP_SUBSC OP_SUBC OP_SUBSCC OP_SRA OP_OR OP_AND OP_XOR OP_SR OP_SRX OP_SL OP_RL OP_RR OP_NAND OP_ORX OP_MOV OP_JMP OP_JAND OP_JNAND OP_JS OP_JNS OP_JE OP_JNE OP_JLS OP_JGES OP_JGS OP_JLES OP_JL OP_JGE OP_JG OP_JLE OP_JZX OP_JNZX OP_JEXT OP_JNEXT OP_CALL OP_RET OP_TKIPH OP_TKIPHS OP_TKIPL OP_TKIPLS OP_NAP RAW_CODE
 
@@ -50,17 +51,21 @@ extern struct initvals_sect *cur_initvals_sect;
 
 %%
 
-line   : /* empty */
-       | line statement {
+line   : line_terminator {
+               /* empty */
+         }
+       | line statement line_terminator {
                struct statement *s = $2;
-               if (section != SECTION_TEXT)
-                       yyerror("Microcode text instruction in non .text section");
-               memcpy(&s->info, &cur_lineinfo, sizeof(struct lineinfo));
-               list_add_tail(&s->list, &infile.sl);
+               if (s) {
+                       if (section != SECTION_TEXT)
+                               yyerror("Microcode text instruction in non .text section");
+                       memcpy(&s->info, &cur_lineinfo, sizeof(struct lineinfo));
+                       list_add_tail(&s->list, &infile.sl);
+               }
          }
-       | line section_switch {
+       | line section_switch line_terminator {
          }
-       | line ivals_write {
+       | line ivals_write line_terminator {
                struct initval_op *io = $2;
                if (section != SECTION_IVALS)
                        yyerror("InitVals write in non .initvals section");
@@ -70,6 +75,11 @@ line : /* empty */
          }
        ;
 
+/* Allow terminating lines with the ";" char */
+line_terminator : /* Nothing */
+               | SEMICOLON line_terminator
+               ;
+
 section_switch : SECTION_TEXT {
                        section = SECTION_TEXT;
                  }
@@ -95,35 +105,35 @@ section_switch     : SECTION_TEXT {
                  }
                ;
 
-ivals_write    : IVAL_MMIO16 hexnum_decnum COMMA hexnum_decnum {
+ivals_write    : IVAL_MMIO16 imm_value COMMA imm_value {
                        struct initval_op *iop = xmalloc(sizeof(struct initval_op));
                        iop->type = IVAL_W_MMIO16;
                        iop->args[0] = (unsigned int)(unsigned long)$2;
                        iop->args[1] = (unsigned int)(unsigned long)$4;
                        $$ = iop;
                  }
-               | IVAL_MMIO32 hexnum_decnum COMMA hexnum_decnum {
+               | IVAL_MMIO32 imm_value COMMA imm_value {
                        struct initval_op *iop = xmalloc(sizeof(struct initval_op));
                        iop->type = IVAL_W_MMIO32;
                        iop->args[0] = (unsigned int)(unsigned long)$2;
                        iop->args[1] = (unsigned int)(unsigned long)$4;
                        $$ = iop;
                  }
-               | IVAL_PHY hexnum_decnum COMMA hexnum_decnum {
+               | IVAL_PHY imm_value COMMA imm_value {
                        struct initval_op *iop = xmalloc(sizeof(struct initval_op));
                        iop->type = IVAL_W_PHY;
                        iop->args[0] = (unsigned int)(unsigned long)$2;
                        iop->args[1] = (unsigned int)(unsigned long)$4;
                        $$ = iop;
                  }
-               | IVAL_RADIO hexnum_decnum COMMA hexnum_decnum {
+               | IVAL_RADIO imm_value COMMA imm_value {
                        struct initval_op *iop = xmalloc(sizeof(struct initval_op));
                        iop->type = IVAL_W_RADIO;
                        iop->args[0] = (unsigned int)(unsigned long)$2;
                        iop->args[1] = (unsigned int)(unsigned long)$4;
                        $$ = iop;
                  }
-               | IVAL_SHM16 hexnum_decnum COMMA hexnum_decnum COMMA hexnum_decnum {
+               | IVAL_SHM16 imm_value COMMA imm_value COMMA imm_value {
                        struct initval_op *iop = xmalloc(sizeof(struct initval_op));
                        iop->type = IVAL_W_SHM16;
                        iop->args[0] = (unsigned int)(unsigned long)$2;
@@ -131,7 +141,7 @@ ivals_write : IVAL_MMIO16 hexnum_decnum COMMA hexnum_decnum {
                        iop->args[2] = (unsigned int)(unsigned long)$6;
                        $$ = iop;
                  }
-               | IVAL_SHM32 hexnum_decnum COMMA hexnum_decnum COMMA hexnum_decnum {
+               | IVAL_SHM32 imm_value COMMA imm_value COMMA imm_value {
                        struct initval_op *iop = xmalloc(sizeof(struct initval_op));
                        iop->type = IVAL_W_SHM32;
                        iop->args[0] = (unsigned int)(unsigned long)$2;
@@ -142,11 +152,15 @@ ivals_write       : IVAL_MMIO16 hexnum_decnum COMMA hexnum_decnum {
                ;
 
 statement      : asmdir {
-                       struct statement *s = xmalloc(sizeof(struct statement));
-                       INIT_LIST_HEAD(&s->list);
-                       s->type = STMT_ASMDIR;
-                       s->u.asmdir = $1;
-                       $$ = s;
+                       struct asmdir *ad = $1;
+                       if (ad) {
+                               struct statement *s = xmalloc(sizeof(struct statement));
+                               INIT_LIST_HEAD(&s->list);
+                               s->type = STMT_ASMDIR;
+                               s->u.asmdir = $1;
+                               $$ = s;
+                       } else
+                               $$ = NULL;
                  }
                | label {
                        struct statement *s = xmalloc(sizeof(struct statement));
@@ -502,6 +516,48 @@ asmdir             : ASM_ARCH hexnum_decnum {
                        ad->u.start = label;
                        $$ = ad;
                  }
+               | asm_assert {
+                       $$ = NULL;
+                 }
+               ;
+
+asm_assert     : ASM_ASSERT assertion {
+                       unsigned int ok = (unsigned int)(unsigned long)$2;
+                       if (!ok)
+                               assembler_assertion_failed();
+                       $$ = NULL;
+                 }
+               ;
+
+assertion      : PAREN_OPEN assert_expr PAREN_CLOSE {
+                       $$ = $2;
+                 }
+               | PAREN_OPEN assertion LOGICAL_OR assertion PAREN_CLOSE {
+                       unsigned int a = (unsigned int)(unsigned long)$2;
+                       unsigned int b = (unsigned int)(unsigned long)$4;
+                       unsigned int result = (a || b);
+                       $$ = (void *)(unsigned long)result;
+                 }
+               | PAREN_OPEN assertion LOGICAL_AND assertion PAREN_CLOSE {
+                       unsigned int a = (unsigned int)(unsigned long)$2;
+                       unsigned int b = (unsigned int)(unsigned long)$4;
+                       unsigned int result = (a && b);
+                       $$ = (void *)(unsigned long)result;
+                 }
+               ;
+
+assert_expr    : imm_value EQUAL imm_value {
+                       unsigned int a = (unsigned int)(unsigned long)$1;
+                       unsigned int b = (unsigned int)(unsigned long)$3;
+                       unsigned int result = (a == b);
+                       $$ = (void *)(unsigned long)result;
+                 }
+               | imm_value NOT_EQUAL imm_value {
+                       unsigned int a = (unsigned int)(unsigned long)$1;
+                       unsigned int b = (unsigned int)(unsigned long)$3;
+                       unsigned int result = (a != b);
+                       $$ = (void *)(unsigned long)result;
+                 }
                ;
 
 label          : LABEL {
@@ -980,7 +1036,7 @@ raw_code   : RAW_CODE {
                  }
                ;
 
-extended_operlist : decnum COMMA decnum COMMA operand COMMA operand COMMA operand {
+extended_operlist : imm_value COMMA imm_value COMMA operand COMMA operand COMMA operand {
                        struct operlist *ol = xmalloc(sizeof(struct operlist));
                        struct operand *mask_oper = xmalloc(sizeof(struct operand));
                        struct operand *shift_oper = xmalloc(sizeof(struct operand));
@@ -997,15 +1053,13 @@ extended_operlist : decnum COMMA decnum COMMA operand COMMA operand COMMA operan
                  }
                ;
 
-external_jump_operands : hexnum COMMA operand COMMA operand COMMA labelref {
+external_jump_operands : imm COMMA labelref {
                        struct operlist *ol = xmalloc(sizeof(struct operlist));
                        struct operand *cond = xmalloc(sizeof(struct operand));
-                       cond->type = OPER_RAW;
-                       cond->u.raw = (unsigned long)$1;
+                       cond->type = OPER_IMM;
+                       cond->u.imm = $1;
                        ol->oper[0] = cond;
                        ol->oper[1] = $3;
-                       ol->oper[2] = $5;
-                       ol->oper[3] = $7;
                        $$ = ol;
                  }
                ;
@@ -1077,35 +1131,37 @@ reg             : GPR regnr {
                  }
                ;
 
-mem            : BRACK_OPEN hexnum_decnum BRACK_CLOSE {
+mem            : BRACK_OPEN imm BRACK_CLOSE {
                        struct memory *mem = xmalloc(sizeof(struct memory));
+                       struct immediate *offset_imm = $2;
                        mem->type = MEM_DIRECT;
-                       mem->offset = (unsigned long)$2;
+                       mem->offset = offset_imm->imm;
+                       free(offset_imm);
                        $$ = mem;
                  }
-               | BRACK_OPEN hexnum_decnum COMMA OFFR regnr BRACK_CLOSE {
+               | BRACK_OPEN imm COMMA OFFR regnr BRACK_CLOSE {
                        struct memory *mem = xmalloc(sizeof(struct memory));
+                       struct immediate *offset_imm = $2;
                        mem->type = MEM_INDIRECT;
-                       mem->offset = (unsigned long)$2;
+                       mem->offset = offset_imm->imm;
+                       free(offset_imm);
                        mem->offr_nr = (unsigned long)$5;
                        $$ = mem;
                  }
                ;
 
-imm            : hexnum {
+imm            : imm_value {
                        struct immediate *imm = xmalloc(sizeof(struct immediate));
                        imm->imm = (unsigned long)$1;
                        $$ = imm;
                  }
-               | decnum {
-                       struct immediate *imm = xmalloc(sizeof(struct immediate));
-                       imm->imm = (unsigned long)$1;
-                       $$ = imm;
+               ;
+
+imm_value      : hexnum_decnum {
+                       $$ = $1;
                  }
                | complex_imm {
-                       struct immediate *imm = xmalloc(sizeof(struct immediate));
-                       imm->imm = (unsigned long)$1;
-                       $$ = imm;
+                       $$ = $1;
                  }
                ;
 
@@ -1150,6 +1206,10 @@ complex_imm      : PAREN_OPEN complex_imm_arg complex_imm_oper complex_imm_arg PAREN_
                | PAREN_OPEN complex_imm PAREN_CLOSE {
                        $$ = $2;
                  }
+               | PAREN_OPEN asm_assert PAREN_CLOSE {
+                       /* Inline assertion. Always return zero */
+                       $$ = (void *)(unsigned long)(unsigned int)0;
+                 }
                | PAREN_OPEN BITW_NOT complex_imm PAREN_CLOSE {
                        unsigned long n = (unsigned long)$3;
                        n = ~n;
@@ -1301,3 +1361,8 @@ static struct operand * store_oper_sanity(struct operand *oper)
        }
        return oper;
 }
+
+static void assembler_assertion_failed(void)
+{
+       yyerror("Assembler %assert failed");
+}