b43-asm: Throw error when using RET after a jump
authorMichael Buesch <mb@bu3sch.de>
Sat, 17 May 2008 19:41:56 +0000 (21:41 +0200)
committerMichael Buesch <mb@bu3sch.de>
Sat, 17 May 2008 19:41:56 +0000 (21:41 +0200)
Signed-off-by: Michael Buesch <mb@bu3sch.de>
assembler/main.c
assembler/scanner.l
assembler/test.asm

index a2ace1df993217396e295579569780521cb52a3c..1dac1c7cafa146068c38d027f82f41a1dcaf0a9a 100644 (file)
@@ -49,6 +49,11 @@ struct code_output {
                OUT_LABEL,
        } type;
 
+       /* Set to true, if this is a jump instruction.
+        * This is only used when assembling RET to check
+        * whether the previous instruction was a jump or not. */
+       bool is_jump_insn;
+
        unsigned int opcode;
        struct out_operand operands[3];
 
@@ -379,9 +384,9 @@ static void generate_operand(struct assembler_context *ctx,
        }
 }
 
-static void do_assemble_insn(struct assembler_context *ctx,
-                            struct instruction *insn,
-                            unsigned int opcode)
+static struct code_output * do_assemble_insn(struct assembler_context *ctx,
+                                            struct instruction *insn,
+                                            unsigned int opcode)
 {
        int i;
        struct operlist *ol;
@@ -432,6 +437,8 @@ static void do_assemble_insn(struct assembler_context *ctx,
                               "lowlevel do_assemble_insn");
 
        list_add_tail(&out->list, &ctx->output);
+
+       return out;
 }
 
 static unsigned int merge_ext_into_opcode(struct assembler_context *ctx,
@@ -569,6 +576,7 @@ static void emulate_jand_insn(struct assembler_context *ctx,
                              struct instruction *insn,
                              int inverted)
 {
+       struct code_output *out;
        struct instruction em_insn;
        struct operlist em_ol;
        struct operand em_op_shift;
@@ -638,14 +646,16 @@ static void emulate_jand_insn(struct assembler_context *ctx,
 
        /* Do a normal JAND/JNAND instruction */
        if (inverted)
-               do_assemble_insn(ctx, insn, 0x040 | 0x1);
+               out = do_assemble_insn(ctx, insn, 0x040 | 0x1);
        else
-               do_assemble_insn(ctx, insn, 0x040);
+               out = do_assemble_insn(ctx, insn, 0x040);
+       out->is_jump_insn = 1;
 }
 
 static void assemble_instruction(struct assembler_context *ctx,
                                 struct instruction *insn)
 {
+       struct code_output *out;
        unsigned int opcode;
 
        switch (insn->op) {
@@ -721,61 +731,85 @@ static void assemble_instruction(struct assembler_context *ctx,
                emulate_jand_insn(ctx, insn, 1);
                return;
        case OP_JS:
-               do_assemble_insn(ctx, insn, 0x050);
+               out = do_assemble_insn(ctx, insn, 0x050);
+               out->is_jump_insn = 1;
                break;
        case OP_JNS:
-               do_assemble_insn(ctx, insn, 0x050 | 0x1);
+               out = do_assemble_insn(ctx, insn, 0x050 | 0x1);
+               out->is_jump_insn = 1;
                break;
        case OP_JE:
-               do_assemble_insn(ctx, insn, 0x0D0);
+               out = do_assemble_insn(ctx, insn, 0x0D0);
+               out->is_jump_insn = 1;
                break;
        case OP_JNE:
-               do_assemble_insn(ctx, insn, 0x0D0 | 0x1);
+               out = do_assemble_insn(ctx, insn, 0x0D0 | 0x1);
+               out->is_jump_insn = 1;
                break;
        case OP_JLS:
-               do_assemble_insn(ctx, insn, 0x0D2);
+               out = do_assemble_insn(ctx, insn, 0x0D2);
+               out->is_jump_insn = 1;
                break;
        case OP_JGES:
-               do_assemble_insn(ctx, insn, 0x0D2 | 0x1);
+               out = do_assemble_insn(ctx, insn, 0x0D2 | 0x1);
+               out->is_jump_insn = 1;
                break;
        case OP_JGS:
-               do_assemble_insn(ctx, insn, 0x0D4);
+               out = do_assemble_insn(ctx, insn, 0x0D4);
+               out->is_jump_insn = 1;
                break;
        case OP_JLES:
-               do_assemble_insn(ctx, insn, 0x0D4 | 0x1);
+               out = do_assemble_insn(ctx, insn, 0x0D4 | 0x1);
+               out->is_jump_insn = 1;
                break;
        case OP_JL:
-               do_assemble_insn(ctx, insn, 0x0DA);
+               out = do_assemble_insn(ctx, insn, 0x0DA);
+               out->is_jump_insn = 1;
                break;
        case OP_JGE:
-               do_assemble_insn(ctx, insn, 0x0DA | 0x1);
+               out = do_assemble_insn(ctx, insn, 0x0DA | 0x1);
+               out->is_jump_insn = 1;
                break;
        case OP_JG:
-               do_assemble_insn(ctx, insn, 0x0DC);
+               out = do_assemble_insn(ctx, insn, 0x0DC);
                break;
        case OP_JLE:
-               do_assemble_insn(ctx, insn, 0x0DC | 0x1);
+               out = do_assemble_insn(ctx, insn, 0x0DC | 0x1);
+               out->is_jump_insn = 1;
                break;
        case OP_JZX:
                opcode = merge_ext_into_opcode(ctx, 0x400, insn);
-               do_assemble_insn(ctx, insn, opcode);
+               out = do_assemble_insn(ctx, insn, opcode);
+               out->is_jump_insn = 1;
                break;
        case OP_JNZX:
                opcode = merge_ext_into_opcode(ctx, 0x500, insn);
-               do_assemble_insn(ctx, insn, opcode);
+               out = do_assemble_insn(ctx, insn, opcode);
+               out->is_jump_insn = 1;
                break;
        case OP_JEXT:
                opcode = merge_external_jmp_into_opcode(ctx, 0x700, insn);
-               do_assemble_insn(ctx, insn, opcode);
+               out = do_assemble_insn(ctx, insn, opcode);
+               out->is_jump_insn = 1;
                break;
        case OP_JNEXT:
                opcode = merge_external_jmp_into_opcode(ctx, 0x600, insn);
-               do_assemble_insn(ctx, insn, opcode);
+               out = do_assemble_insn(ctx, insn, opcode);
+               out->is_jump_insn = 1;
                break;
        case OP_CALL:
                do_assemble_insn(ctx, insn, 0x002);
                break;
        case OP_RET:
+               if (!list_empty(&ctx->output)) {
+                       /* Get the previous instruction and check whether it
+                        * is a jump instruction. */
+                       out = list_entry(ctx->output.prev, struct code_output, list);
+                       if (out->is_jump_insn) {
+                               asm_error(ctx, "RET instruction directly after "
+                                         "jump instruction. The hardware won't like this.");
+                       }
+               }
                do_assemble_insn(ctx, insn, 0x003);
                break;
        case OP_TKIPH:
index bb866a93d1c7d302959d1e3617274dfb8a574414..16f375ca2d0fa974268b70ab6770d47a6312a213 100644 (file)
@@ -149,6 +149,7 @@ shm32                       { update_lineinfo(); return IVAL_SHM32; }
 %%
 
 struct lineinfo cur_lineinfo;
+//FIXME The linenumber sometimes is wrong.
 
 static void interpret_cppinfo(const char *str)
 {
@@ -175,7 +176,7 @@ static void interpret_cppinfo(const char *str)
        memset(tmp, 0, sizeof(tmp));
        memcpy(tmp, str, min(sizeof(tmp) - 1,
                             (int)(found - str)));
-       cur_lineinfo.lineno = strtoul(tmp, NULL, 10);
+       cur_lineinfo.lineno = strtoul(tmp, NULL, 10) - 1;
        str = found;
        str++;
 
index 873b7612847c887432d45dd0d4c1f8df861ee457..b1f3f147b01267d520f7ce287aefc3b36abe7c79 100644 (file)
@@ -1,27 +1,27 @@
-; This is a bcm43xx microcode assembly example.
-;
-; In this example file, r0 and r1 are always input
-; registers and r2 is output.
-; For input we can always have constant values or (one) memory
-; operand instead of the input registers shown here.
-;
-; Registers:
-     GPRs:                   r0 - r63
-     Offset Registers:       off0 - off5
-     SPRs:                   spr000
-;
-; To access memory, two methods can be used. Examples follow.
-; Direct linear:
-     mov r0,[0xCA]
-; Indirect through Offset Register (pointer):
-     mov r0,[0xCA,off0]
-;
-
-
-; The target architecture. Supported versions are 5 and 15
+/* This is a bcm43xx microcode assembly example.
+ *
+ * In this example file, r0 and r1 are always input
+ * registers and r2 is output.
+ * For input we can always have constant values or (one) memory
+ * operand instead of the input registers shown here.
+ *
+ * Registers:
+ *     GPRs:                   r0 - r63
+ *     Offset Registers:       off0 - off5
+ *     SPRs:                   spr000
+ *
+ * To access memory, two methods can be used. Examples follow.
+ * Direct linear:
+ *     mov r0,[0xCA]
+ * Indirect through Offset Register (pointer):
+ *     mov r0,[0xCA,off0]
+ */
+
+
+/* The target architecture. Supported versions are 5 and 15 */
 %arch  5
 
-; Program entry point
+/* Program entry point */
 %start testlabel
 
 #define        PSM_BRC         spr848
 .text
 
 label:
-       ; ADD instructions
-       add     r0,r1,r2        ; add
-       add.    r0,r1,r2        ; add, set carry
-       addc    r0,r1,r2        ; add with carry
-       addc.   r0,r1,r2        ; add with carry, set carry
+       /* ADD instructions */
+       add     r0,r1,r2        /* add */
+       add.    r0,r1,r2        /* add, set carry */
+       addc    r0,r1,r2        /* add with carry */
+       addc.   r0,r1,r2        /* add with carry, set carry */
 
+or 0x1000, r0, r0
 testlabel:
-       ; SUB instructions
-       sub     r0,r1,r2        ; sub
-       sub.    r0,r1,r2        ; sub, set carry
-       subc    r0,r1,r2        ; sub with carry
-       subc.   r0,r1,r2        ; sub with carry, set carry
-
-       sra     r0,r1,r2        ; arithmetic rightshift
-
-       ; Logical instructions
-       or      r0,r1,r2        ; bitwise OR
-       and     r0,r1,r2        ; bitwise AND
-       xor     r0,r1,r2        ; bitwise XOR
-       sr      r0,r1,r2        ; rightshift
-       sl      r0,r1,r2        ; leftshift
-
-       srx     7,8,r0,r1,r2    ; eXtended right shift (two input regs)
-
-       rl      r0,r1,r2        ; rotate left
-       rr      r0,r1,r2        ; rotate right
-       nand    r0,r1,r2        ; clear bits (notmask + and)
-
-       orx     7,8,r0,r1,r2    ; eXtended OR
-
-       ; Copy instruction. This is a virtual instruction
-       ; translated to more lowlevel stuff like OR.
-       mov     r0,r2           ; copy data
-
-       ; Jumps
-       jmp     label           ; unconditional jump
-       jand    r0,r1,label     ; jump if binary AND
-       jnand   r0,r1,label     ; jump if not binary AND
-       js      r0,r1,label     ; jump if all bits set
-       jns     r0,r1,label     ; jump if not all bits set
-       je      r0,r1,label     ; jump if equal
-       jne     r0,r1,label     ; jump if not equal
-       jls     r0,r1,label     ; jump if less (signed)
-       jges    r0,r1,label     ; jump if greater or equal (signed)
-       jgs     r0,r1,label     ; jump if greater (signed)
-       jles    r0,r1,label     ; jump if less or equal (signed)
-       jl      r0,r1,label     ; jump if less
-       jge     r0,r1,label     ; jump if greater or equal
-       jg      r0,r1,label     ; jump if greater
-       jle     r0,r1,label     ; jump if less or equal
-
-       jzx     7,8,r0,r1,label ; Jump if zero after shift and mask
-       jnzx    7,8,r0,r1,label ; Jump if nonzero after shift and mask
-
-       ; jump on external conditions
-       jext    ECOND_MAC_ON,r0,r0,label  ; jump if external condition is TRUE
-       jnext   ECOND_MAC_ON,r0,r0,label  ; jump if external condition is FALSE
-
-       ; Subroutines
-       call    lr0,label       ; store PC in lr0, call func at label
-       ret     lr0,lr1         ; store PC in lr0, return to lr1
-                               ; Both link registers can be the same
-                               ; and don't interfere.
-
-       ; TKIP sbox lookup
-       tkiph   r0,r2           ; Lookup high
-       tkiphs  r0,r2           ; Lookup high, byteswap
-       tkipl   r0,r2           ; Lookup low
-       tkipls  r0,r2           ; Lookup low, byteswap
-
-       nap                     ; sleep until event
-
-       ; raw instruction
-       @160    r0,r1,r2        ; equivalent to  or r0,r1,r2
+       /* SUB instructions */
+       sub     r0,r1,r2        /* sub */
+       sub.    r0,r1,r2        /* sub, set carry */
+       subc    r0,r1,r2        /* sub with carry */
+       subc.   r0,r1,r2        /* sub with carry, set carry */
+
+       sra     r0,r1,r2        /* arithmetic rightshift */
+
+       /* Logical instructions */
+       or      r0,r1,r2        /* bitwise OR */
+       and     r0,r1,r2        /* bitwise AND */
+       xor     r0,r1,r2        /* bitwise XOR */
+       sr      r0,r1,r2        /* rightshift */
+       sl      r0,r1,r2        /* leftshift */
+
+       srx     7,8,r0,r1,r2    /* eXtended right shift (two input regs) */
+
+       rl      r0,r1,r2        /* rotate left */
+       rr      r0,r1,r2        /* rotate right */
+       nand    r0,r1,r2        /* clear bits (notmask + and) */
+
+       orx     7,8,r0,r1,r2    /* eXtended OR */
+
+       /* Copy instruction. This is a virtual instruction
+        * translated to more lowlevel stuff like OR. */
+       mov     r0,r2           /* copy data */
+
+       /* Jumps */
+       jmp     label           /* unconditional jump */
+       jand    r0,r1,label     /* jump if binary AND */
+       jnand   r0,r1,label     /* jump if not binary AND */
+       js      r0,r1,label     /* jump if all bits set */
+       jns     r0,r1,label     /* jump if not all bits set */
+       je      r0,r1,label     /* jump if equal */
+       jne     r0,r1,label     /* jump if not equal */
+       jls     r0,r1,label     /* jump if less (signed) */
+       jges    r0,r1,label     /* jump if greater or equal (signed) */
+       jgs     r0,r1,label     /* jump if greater (signed) */
+       jles    r0,r1,label     /* jump if less or equal (signed) */
+       jl      r0,r1,label     /* jump if less */
+       jge     r0,r1,label     /* jump if greater or equal */
+       jg      r0,r1,label     /* jump if greater */
+       jle     r0,r1,label     /* jump if less or equal */
+
+       jzx     7,8,r0,r1,label /* Jump if zero after shift and mask */
+       jnzx    7,8,r0,r1,label /* Jump if nonzero after shift and mask */
+
+       /* jump on external conditions */
+       jext    ECOND_MAC_ON,r0,r0,label  /* jump if external condition is TRUE */
+       jnext   ECOND_MAC_ON,r0,r0,label  /* jump if external condition is FALSE */
+
+       /* Subroutines */
+       call    lr0,label       /* store PC in lr0, call func at label */
+       ret     lr0,lr1         /* store PC in lr0, return to lr1
+                                * Both link registers can be the same
+                                * and don't interfere. */
+
+       /* TKIP sbox lookup */
+       tkiph   r0,r2           /* Lookup high */
+       tkiphs  r0,r2           /* Lookup high, byteswap */
+       tkipl   r0,r2           /* Lookup low */
+       tkipls  r0,r2           /* Lookup low, byteswap */
+
+       nap                     /* sleep until event */
+
+       /* raw instruction */
+       @160    r0,r1,r2        /* equivalent to  or r0,r1,r2 */
        @1C0    @C11, @C22, @BC3
 
 
-       ; Support for directional jumps.
-       ; Directional jumps can be used to conveniently jump inside of
-       ; functions without using function specific label prefixes. Note
-       ; that this does not establish a sub-namespace, though. "loop"
-       ; and "out" are still in the global namespace and can't be used
-       ; anymore for absolute jumps (Assembler will warn about duplication).
+       /* Support for directional jumps.
+        * Directional jumps can be used to conveniently jump inside of
+        * functions without using function specific label prefixes. Note
+        * that this does not establish a sub-namespace, though. "loop"
+        * and "out" are still in the global namespace and can't be used
+        * anymore for absolute jumps (Assembler will warn about duplication).
+        */
 function_a:
        jl r0, r1, out+
  loop:
@@ -132,10 +134,11 @@ function_b:
        ret lr0, lr1
 
 
-; The assembler has support for fancy assemble-time
-; immediate constant expansion. This is called "complex immediates".
-; Complex immediates are _always_ clamped by parentheses. There is no
-; operator precedence. You must use parentheses to tell precedence.
+/* The assembler has support for fancy assemble-time
+ * immediate constant expansion. This is called "complex immediates".
+ * Complex immediates are _always_ clamped by parentheses. There is no
+ * operator precedence. You must use parentheses to tell precedence.
+ */
        mov     (2 + 3),r0
        mov     (6 - 2),r0
        mov     (2 * 3),r0
@@ -151,32 +154,36 @@ function_b:
        mov     (4 >> (((((~5 | 0x21)))) | (~((10) & 2)))),r0
 
 
-; Some regression testing for the assembler follows
-       mov     2,off0                  ; test memory stuff
-       xor     0x124,r1,[0x0,off0]     ; test memory stuff
-       xor     0x124,r0,[0x0]          ; test memory stuff
-       mov     -34,r0                  ; negative dec numbers are supported
-       or      r0,r1,@BC2              ; We also support single raw operands
-       mov     0xEEEE,r0               ; MOV supports up to 16bit
-       jand    0x3800,r0,label         ; This is emulated by jnzx
-       jnand   0x3800,r0,label         ; This is emulated by jzx
-       or      spr06c,0,spr06c         ; Can have one spr input and one spr output
-       or      [0],0,[0]               ; Can have one mem input and one mem output
-       mov     testlabel, r0           ; Can use label as immediate value
-       mov r0,r1|mov r2, r3            ; | does also seperate instructions
-       mov     [(1+1)],[(2+2),off0]    ; Can use complex immediates as memory offsets
-
-
-; The .initvals section generates an "Initial Values" file
-; with the name "foobar" in this example, which is uploaded
-; by the kernel driver on load. This is useful for writing ucode
-; specific values to the chip without bloating the small ucode
-; memory space with this initialization stuff.
-; Values are written in order they appear here.
+/* Some regression testing for the assembler follows */
+       mov     2,off0                  /* test memory stuff */
+       xor     0x124,r1,[0x0,off0]     /* test memory stuff */
+       xor     0x124,r0,[0x0]          /* test memory stuff */
+       mov     -34,r0                  /* negative dec numbers are supported */
+       or      r0,r1,@BC2              /* We also support single raw operands */
+       mov     0xEEEE,r0               /* MOV supports up to 16bit */
+       jand    0x3800,r0,label         /* This is emulated by jnzx */
+       jnand   0x3800,r0,label         /* This is emulated by jzx */
+       or      spr06c,0,spr06c         /* Can have one spr input and one spr output */
+       or      [0],0,[0]               /* Can have one mem input and one mem output */
+       mov     testlabel, r0           /* Can use label as immediate value */
+       mov r0,r1;mov r2, r3            /* ; does split instructions */
+       mov     [(1+1)],[(2+2),off0]    /* Can use complex immediates as memory offsets */
+
+
+/* The .initvals section generates an "Initial Values" file
+ * with the name "foobar" in this example, which is uploaded
+ * by the kernel driver on load. This is useful for writing ucode
+ * specific values to the chip without bloating the small ucode
+ * memory space with this initialization stuff.
+ * Values are written in order they appear here.
+ */
 .initvals(foobar)
-       mmio16  0x1234, 0xABC                   ; Write 0x1234 to MMIO register 0xABC
-       mmio32  0x12345678, 0xABC               ; Write 0x12345678 to MMIO register 0xABC
-       phy     0x1234, 0xABC                   ; Write 0x1234 to PHY register 0xABC
-       radio   0x1234, 0xABC                   ; Write 0x1234 to RADIO register 0xABC
-       shm16   0x1234, 0x0001, 0x0002          ; Write 0x1234 to SHM routing 0x0001, register 0x0002
-       shm32   0x12345678, 0x0001, 0x0002      ; Write 0x12345678 to SHM routing 0x0001, register 0x0002
+       mmio16  0x1234, 0xABC                   /* Write 0x1234 to MMIO register 0xABC */
+       mmio32  0x12345678, 0xABC               /* Write 0x12345678 to MMIO register 0xABC */
+       phy     0x1234, 0xABC                   /* Write 0x1234 to PHY register 0xABC */
+       radio   0x1234, 0xABC                   /* Write 0x1234 to RADIO register 0xABC */
+       shm16   0x1234, 0x0001, 0x0002          /* Write 0x1234 to SHM routing 0x0001, register 0x0002 */
+       shm32   0x12345678, 0x0001, 0x0002      /* Write 0x12345678 to SHM routing 0x0001, register 0x0002 */
+
+
+// vim: syntax=b43 ts=8