asm/dasm: Add support for calls/rets (untested)
authorMichael Buesch <mb@bu3sch.de>
Mon, 20 Sep 2010 16:30:51 +0000 (18:30 +0200)
committerMichael Buesch <mb@bu3sch.de>
Mon, 20 Sep 2010 16:30:51 +0000 (18:30 +0200)
Signed-off-by: Michael Buesch <mb@bu3sch.de>
assembler/README
assembler/main.c
assembler/parser.y
assembler/scanner.l
disassembler/main.c

index c64ab01bb4f8922ee67e7fec35b31e1ac04effb6..d9e1362b5525fe00676bfb238a4447bc273bcc44 100644 (file)
@@ -34,7 +34,9 @@ jge       | A,B,l      | Jump if greater or equal        | if(A>=B) PC=l
 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
index 461b0d8126cca3764300bf393fd1ce170122f253..b262276d2ee800305d6a192b42fd1e73b80cfdb3 100644 (file)
@@ -482,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)
@@ -855,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:
index 4ace3307cd8af11e278f300dd13d91e923fcfdf8..3e83c19597763320c4bfb8327aabdd46fb0c5ad2 100644 (file)
@@ -43,7 +43,7 @@ extern struct initvals_sect *cur_initvals_sect;
 
 %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
 
@@ -456,6 +456,13 @@ statement  : asmdir {
                        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);
@@ -463,6 +470,13 @@ statement  : asmdir {
                        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);
@@ -922,6 +936,24 @@ insn_call  : OP_CALL linkreg COMMA labelref {
                  }
                ;
 
+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));
@@ -943,6 +975,27 @@ insn_ret   : OP_RET linkreg COMMA linkreg {
                  }
                ;
 
+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;
index 80b204f6df33d3af0398838217c51e8fc29b9e19..436d3336c05795e7f10bcb36ebb3b62a9656829c 100644 (file)
@@ -127,7 +127,9 @@ jext                        { update_lineinfo(); return OP_JEXT; }
 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; }
index ba990ab007e3d0ea5b89913aae7605181e265b08..86ed1f483b2773cd7754224aabd18d886c55bc15 100644 (file)
@@ -515,30 +515,31 @@ static void disasm_constant_opcodes(struct disassembler_context *ctx,
                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;