X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=assembler%2Fmain.c;h=255cabc88c74b6966d0c0a4262e374d2048cdf14;hb=e882e360ba16d2eed103adffdd1809076ee98017;hp=a2ace1df993217396e295579569780521cb52a3c;hpb=05e57ce6fbe1ebf597ab5a7e4d10e6f275f47e44;p=b43-tools.git diff --git a/assembler/main.c b/assembler/main.c index a2ace1d..255cabc 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, @@ -463,6 +470,9 @@ static unsigned int merge_external_jmp_into_opcode(struct assembler_context *ctx unsigned int opbase, struct instruction *insn) { + struct operand *fake; + struct registr *fake_reg; + struct operand *target; struct operlist *ol; unsigned int cond; unsigned int opcode; @@ -473,9 +483,21 @@ static unsigned int merge_external_jmp_into_opcode(struct assembler_context *ctx if (cond & ~0xFF) asm_error(ctx, "External jump condition value too big (> 0xFF)"); opcode |= cond; - ol->oper[0] = ol->oper[1]; - ol->oper[1] = ol->oper[2]; - ol->oper[2] = ol->oper[3]; + target = ol->oper[1]; + memset(ol->oper, 0, sizeof(ol->oper)); + + /* This instruction has two fake r0 operands + * at position 0 and 1. */ + fake = xmalloc(sizeof(*fake)); + fake_reg = xmalloc(sizeof(*fake_reg)); + fake->type = OPER_REG; + fake->u.reg = fake_reg; + fake_reg->type = GPR; + fake_reg->nr = 0; + + ol->oper[0] = fake; + ol->oper[1] = fake; + ol->oper[2] = target; return opcode; } @@ -549,19 +571,20 @@ static void emulate_jmp_insn(struct assembler_context *ctx, { struct instruction em_insn; struct operlist em_ol; - struct operand em_op; - struct immediate em_imm; - - /* This is a pseudo-OP. We emulate it by JE */ - - em_insn.op = OP_JE; - em_imm.imm = 1; - em_op.type = OPER_IMM; - em_op.u.imm = &em_imm; - em_ol.oper[0] = &em_op; - em_ol.oper[1] = &em_op; - em_ol.oper[2] = insn->operands->oper[0]; + struct immediate em_condition; + struct operand em_cond_op; + + /* This is a pseudo-OP. We emulate it with + * JEXT 0x7F, target */ + + em_insn.op = OP_JEXT; + em_condition.imm = 0x7F; /* Ext cond: Always true */ + em_cond_op.type = OPER_IMM; + em_cond_op.u.imm = &em_condition; + em_ol.oper[0] = &em_cond_op; + em_ol.oper[1] = insn->operands->oper[0]; /* Target */ em_insn.operands = &em_ol; + assemble_instruction(ctx, &em_insn); /* recurse */ } @@ -569,6 +592,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 +662,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 +747,88 @@ 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: + /* 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_error(ctx, "RET instruction directly after " + "jump instruction. The hardware won't like this."); + } + break; + } + } do_assemble_insn(ctx, insn, 0x003); break; case OP_TKIPH: @@ -1072,6 +1125,12 @@ static void emit_code(struct assembler_context *ctx) break; } } + + if (arg_print_sizes) { + printf("%s: text = %u instructions (%u bytes)\n", + fn, insn_count, insn_count * sizeof(uint64_t)); + } + fclose(fd); free(fn); }