jg | A,B,l | Jump if greater | if(A>B) PC=l
jle | A,B,l | Jump if less or equal | if(A<=B) PC=l
call | lrX,l | Store PC, call function | lrX=PC; PC=l
+calls | l | Store PC, call function | PC->stack; PC=l
ret | lrX,lrY | Store PC, ret from func | lrX=PC; PC=lrY
+rets | | ret from function | stack->PC
jzx | M,S,A,B,l | Jump if zero after shift + mask |
jnzx | M,S,A,B,l | Jump if nonzero after shift+msk |
jext | E,A,B,l | Jump if External Condition true | if(E) PC=l
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)
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:
%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
+%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_CALLS OP_RET OP_RETS OP_TKIPH OP_TKIPHS OP_TKIPL OP_TKIPLS OP_NAP RAW_CODE
%token IVAL_MMIO16 IVAL_MMIO32 IVAL_PHY IVAL_RADIO IVAL_SHM16 IVAL_SHM32 IVAL_TRAM
s->u.insn = $1;
$$ = s;
}
+ | insn_calls {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
| insn_ret {
struct statement *s = xmalloc(sizeof(struct statement));
INIT_LIST_HEAD(&s->list);
s->u.insn = $1;
$$ = s;
}
+ | insn_rets {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
| insn_tkiph {
struct statement *s = xmalloc(sizeof(struct statement));
INIT_LIST_HEAD(&s->list);
}
;
+insn_calls : OP_CALLS labelref {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ struct operlist *ol = xmalloc(sizeof(struct operlist));
+ struct operand *oper_r0 = xmalloc(sizeof(struct operand));
+ struct registr *r0 = xmalloc(sizeof(struct registr));
+ r0->type = GPR;
+ r0->nr = 0;
+ oper_r0->type = OPER_REG;
+ oper_r0->u.reg = r0;
+ ol->oper[0] = oper_r0;
+ ol->oper[1] = oper_r0;
+ ol->oper[2] = $2;
+ insn->op = OP_CALLS;
+ insn->operands = ol;
+ $$ = insn;
+ }
+ ;
+
insn_ret : OP_RET linkreg COMMA linkreg {
struct instruction *insn = xmalloc(sizeof(struct instruction));
struct operlist *ol = xmalloc(sizeof(struct operlist));
}
;
+insn_rets : OP_RETS {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ struct operlist *ol = xmalloc(sizeof(struct operlist));
+ struct operand *oper_r0 = xmalloc(sizeof(struct operand));
+ struct operand *oper_zero = xmalloc(sizeof(struct operand));
+ struct registr *r0 = xmalloc(sizeof(struct registr));
+ oper_zero->type = OPER_RAW;
+ oper_zero->u.raw = 0;
+ r0->type = GPR;
+ r0->nr = 0;
+ oper_r0->type = OPER_REG;
+ oper_r0->u.reg = r0;
+ ol->oper[0] = oper_r0;
+ ol->oper[1] = oper_r0;
+ ol->oper[2] = oper_zero;
+ insn->op = OP_RETS;
+ insn->operands = ol;
+ $$ = insn;
+ }
+ ;
+
insn_tkiph : OP_TKIPH operlist_2 {
struct instruction *insn = xmalloc(sizeof(struct instruction));
struct operlist *ol = $2;
jnext { update_lineinfo(); return OP_JNEXT; }
call { update_lineinfo(); return OP_CALL; }
+calls { update_lineinfo(); return OP_CALLS; }
ret { update_lineinfo(); return OP_RET; }
+rets { update_lineinfo(); return OP_RETS; }
tkiph { update_lineinfo(); return OP_TKIPH; }
tkiphs { update_lineinfo(); return OP_TKIPHS; }
stmt->u.insn.operands[2] = str;
break;
}
-//TODO also implement it in the assembler
-#if 0
case 0x004: {
if (cmdargs.arch != 15) {
- dasm_error("arch 15 call instruction found in arch %d binary",
+ dasm_error("arch 15 'calls' instruction found in arch %d binary",
cmdargs.arch);
}
- stmt->u.insn.name = "call";
+ stmt->u.insn.name = "calls";
stmt->u.insn.is_labelref = 0;
stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
if (stmt->u.insn.bin->operands[0] != 0x1780 ||
stmt->u.insn.bin->operands[1] != 0x1780)
- dasm_warn("r15 call: Invalid first or second argument");
+ dasm_warn("r15 calls: Invalid first or second argument");
break;
}
case 0x005: {
if (cmdargs.arch != 15) {
- dasm_error("arch 15 ret instruction found in arch %d binary",
+ dasm_error("arch 15 'rets' instruction found in arch %d binary",
cmdargs.arch);
}
- stmt->u.insn.name = "ret";
+ stmt->u.insn.name = "rets";
+ if (stmt->u.insn.bin->operands[0] != 0x1780 ||
+ stmt->u.insn.bin->operands[1] != 0x1780 ||
+ stmt->u.insn.bin->operands[2] != 0)
+ dasm_warn("r15 rets: Invalid argument(s)");
break;
}
-#endif
case 0x1E0: {
unsigned int flags, mask;