X-Git-Url: https://jxself.org/git/?p=b43-tools.git;a=blobdiff_plain;f=assembler%2Fmain.c;h=8abe03c8fbbe51ac3371b0c9990ce313f6aa6dd3;hp=6b294a4c46d5ddf825a9924fadbe815d04dea500;hb=bcf9f0184d616b059b84643bb4296f713a2070e7;hpb=d1a8976facb28d18ef9d3a29de5bd1bd721f3394 diff --git a/assembler/main.c b/assembler/main.c index 6b294a4..8abe03c 100644 --- a/assembler/main.c +++ b/assembler/main.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2007 Michael Buesch + * Copyright (C) 2006-2010 Michael Buesch * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -117,6 +117,7 @@ static void eval_directives(struct assembler_context *ctx) struct label *l; int have_start_label = 0; int have_arch = 0; + unsigned int arch_fallback = 0; for_each_statement(ctx, s) { if (s->type == STMT_ASMDIR) { @@ -126,6 +127,17 @@ static void eval_directives(struct assembler_context *ctx) if (have_arch) asm_error(ctx, "Multiple %%arch definitions"); ctx->arch = ad->u.arch; + if (ctx->arch > 5 && ctx->arch < 15) + arch_fallback = 5; + if (ctx->arch > 15) + arch_fallback = 15; + if (arch_fallback) { + asm_warn(ctx, "Using %%arch %d is incorrect. " + "The wireless core revision %d uses the " + "firmware architecture %d. So use %%arch %d", + ctx->arch, ctx->arch, arch_fallback, arch_fallback); + ctx->arch = arch_fallback; + } if (ctx->arch != 5 && ctx->arch != 15) { asm_error(ctx, "Architecture version %u unsupported", ctx->arch); @@ -169,6 +181,17 @@ static bool is_possible_imm(unsigned int imm) return 1; } +static unsigned int immediate_nr_bits(struct assembler_context *ctx) +{ + switch (ctx->arch) { + case 5: + return 10; /* 10 bits */ + case 15: + return 11; /* 11 bits */ + } + asm_error(ctx, "Internal error: immediate_nr_bits unknown arch\n"); +} + static bool is_valid_imm(struct assembler_context *ctx, unsigned int imm) { @@ -189,14 +212,7 @@ static bool is_valid_imm(struct assembler_context *ctx, return 0; imm &= 0xFFFF; - if (ctx->arch == 5) { - immediate_size = 10; /* 10bit */ - } else if (ctx->arch == 15) { - immediate_size = 11; /* 11bit */ - } else { - asm_error(ctx, "Unknown immediate size for arch %u", - ctx->arch); - } + immediate_size = immediate_nr_bits(ctx); /* First create a mask with all possible bits for * an immediate value unset. */ @@ -253,8 +269,6 @@ static unsigned int generate_imm_operand(struct assembler_context *ctx, unsigned int val, tmp; unsigned int mask; - /* format: 0b11ii iiii iiii */ - val = 0xC00; if (ctx->arch == 15) val <<= 1; @@ -262,9 +276,9 @@ static unsigned int generate_imm_operand(struct assembler_context *ctx, if (!is_valid_imm(ctx, tmp)) { asm_warn(ctx, "IMMEDIATE 0x%X (%d) too long " - "(> 9 bits + sign). Did you intend to " + "(> %u bits + sign). Did you intend to " "use implicit sign extension?", - tmp, (int)tmp); + tmp, (int)tmp, immediate_nr_bits(ctx) - 1); } if (ctx->arch == 15) @@ -283,16 +297,14 @@ static unsigned int generate_reg_operand(struct assembler_context *ctx, switch (reg->type) { case GPR: - /* format: 0b1011 11rr rrrr */ val |= 0xBC0; if (ctx->arch == 15) val <<= 1; - if (reg->nr & ~0x3F) //FIXME 128 regs for v15 arch possible? + if (reg->nr & ~0x3F) /* REVISIT: 128 regs for v15 arch possible? Probably not... */ asm_error(ctx, "GPR-nr too big"); val |= reg->nr; break; case SPR: - /* format: 0b100. .... .... */ val |= 0x800; if (ctx->arch == 15) val <<= 1; @@ -301,7 +313,6 @@ static unsigned int generate_reg_operand(struct assembler_context *ctx, val |= reg->nr; break; case OFFR: - /* format: 0b1000 0110 0rrr */ val |= 0x860; if (ctx->arch == 15) val <<= 1; @@ -319,11 +330,10 @@ static unsigned int generate_reg_operand(struct assembler_context *ctx, static unsigned int generate_mem_operand(struct assembler_context *ctx, const struct memory *mem) { - unsigned int val = 0, off, reg; + unsigned int val = 0, off, reg, off_mask, reg_shift; switch (mem->type) { case MEM_DIRECT: - /* format: 0b0mmm mmmm mmmm */ off = mem->offset; switch (ctx->arch) { case 5: @@ -344,25 +354,38 @@ static unsigned int generate_mem_operand(struct assembler_context *ctx, val |= off; break; case MEM_INDIRECT: - /* format: 0b101r rroo oooo */ + switch (ctx->arch) { + case 5: + val = 0xA00; + off_mask = 0x3F; + reg_shift = 6; + break; + case 15: + val = 0x1400; + off_mask = 0x7F; + reg_shift = 7; + break; + default: + asm_error(ctx, "Internal error: MEM_INDIRECT invalid arch\n"); + } + off = mem->offset; reg = mem->offr_nr; - val |= 0xA00; - //FIXME what about v15 arch? - if (off & ~0x3F) { - asm_warn(ctx, "INDIRECT memoffset 0x%X too long (> 6 bits)", off); - off &= 0x3F; + if (off & ~off_mask) { + asm_warn(ctx, "INDIRECT memoffset 0x%X too long (> %u bits)", + off, reg_shift); + off &= off_mask; } if (reg > 6) { /* Assembler bug. The parser shouldn't pass this value. */ asm_error(ctx, "OFFR-nr too big"); } - if (reg == 6 && ctx->arch == 5) { + if (reg == 6) { asm_warn(ctx, "Using offset register 6. This register is broken " - "on architecture 5 devices. Use off0 to off5 only."); + "on certain devices. Use off0 to off5 only."); } val |= off; - val |= (reg << 6); + val |= (reg << reg_shift); break; default: asm_error(ctx, "generate_mem_operand() memtype"); @@ -459,6 +482,27 @@ static struct code_output * do_assemble_insn(struct assembler_context *ctx, return out; } +static void do_assemble_ret(struct assembler_context *ctx, + struct instruction *insn, + unsigned int opcode) +{ + struct code_output *out; + + /* Get the previous instruction and check whether it + * is a jump instruction. */ + list_for_each_entry_reverse(out, &ctx->output, list) { + /* Search the last insn. */ + if (out->type == OUT_INSN) { + if (out->is_jump_insn) { + asm_warn(ctx, "RET instruction directly after " + "jump instruction. The hardware won't like this."); + } + break; + } + } + do_assemble_insn(ctx, insn, opcode); +} + static unsigned int merge_ext_into_opcode(struct assembler_context *ctx, unsigned int opbase, struct instruction *insn) @@ -832,22 +876,24 @@ static void assemble_instruction(struct assembler_context *ctx, out->is_jump_insn = 1; break; case OP_CALL: + if (ctx->arch != 5) + asm_error(ctx, "'call' instruction is only supported on arch 5"); do_assemble_insn(ctx, insn, 0x002); break; + case OP_CALLS: + if (ctx->arch != 15) + asm_error(ctx, "'calls' instruction is only supported on arch 15"); + do_assemble_insn(ctx, insn, 0x004); + break; case OP_RET: - /* Get the previous instruction and check whether it - * is a jump instruction. */ - list_for_each_entry_reverse(out, &ctx->output, list) { - /* Search the last insn. */ - if (out->type == OUT_INSN) { - if (out->is_jump_insn) { - asm_warn(ctx, "RET instruction directly after " - "jump instruction. The hardware won't like this."); - } - break; - } - } - do_assemble_insn(ctx, insn, 0x003); + if (ctx->arch != 5) + asm_error(ctx, "'ret' instruction is only supported on arch 5"); + do_assemble_ret(ctx, insn, 0x003); + break; + case OP_RETS: + if (ctx->arch != 15) + asm_error(ctx, "'rets' instruction is only supported on arch 15"); + do_assemble_insn(ctx, insn, 0x005); break; case OP_TKIPH: case OP_TKIPHS: @@ -1058,7 +1104,7 @@ static void emit_code(struct assembler_context *ctx) exit(1); } if (IS_VERBOSE_DEBUG) - fprintf(stderr, "\nCode:\n"); + printf("\nCode:\n"); list_for_each_entry(c, &ctx->output, list) { switch (c->type) { @@ -1070,7 +1116,7 @@ static void emit_code(struct assembler_context *ctx) } } - switch (output_format) { + switch (cmdargs.outformat) { case FMT_RAW_LE32: case FMT_RAW_BE32: /* Nothing */ @@ -1106,7 +1152,7 @@ static void emit_code(struct assembler_context *ctx) switch (c->type) { case OUT_INSN: if (IS_VERBOSE_DEBUG) { - fprintf(stderr, "%03X %03X,%03X,%03X\n", + printf("%03X %04X,%04X,%04X\n", c->opcode, c->operands[0].u.operand, c->operands[1].u.operand, @@ -1133,7 +1179,7 @@ static void emit_code(struct assembler_context *ctx) ctx->arch); } - switch (output_format) { + switch (cmdargs.outformat) { case FMT_B43: case FMT_RAW_BE32: code = ((code & (uint64_t)0xFFFFFFFF00000000ULL) >> 32) | @@ -1169,7 +1215,7 @@ static void emit_code(struct assembler_context *ctx) } } - if (arg_print_sizes) { + if (cmdargs.print_sizes) { printf("%s: text = %u instructions (%u bytes)\n", fn, insn_count, (unsigned int)(insn_count * sizeof(uint64_t)));