From: Michael Buesch Date: Sat, 17 May 2008 19:41:56 +0000 (+0200) Subject: b43-asm: Throw error when using RET after a jump X-Git-Tag: b43-fwcutter-013~58 X-Git-Url: https://jxself.org/git/?p=b43-tools.git;a=commitdiff_plain;h=1c0560b49eb2c403d0d0fa99f789f13f750a40d8 b43-asm: Throw error when using RET after a jump Signed-off-by: Michael Buesch --- diff --git a/assembler/main.c b/assembler/main.c index a2ace1d..1dac1c7 100644 --- a/assembler/main.c +++ b/assembler/main.c @@ -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: diff --git a/assembler/scanner.l b/assembler/scanner.l index bb866a9..16f375c 100644 --- a/assembler/scanner.l +++ b/assembler/scanner.l @@ -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++; diff --git a/assembler/test.asm b/assembler/test.asm index 873b761..b1f3f14 100644 --- a/assembler/test.asm +++ b/assembler/test.asm @@ -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 @@ -32,89 +32,91 @@ .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