// TODO: group similar instructions like for non-thumb static int thumb_assemble(ArmOpcode *ao, const char *str) { int reg, j; if (!strcmp (ao->op, "pop") && ao->a[0]) { ao->o = 0xbc; if (*ao->a[0]++=='{') { for (j=0; j<16; j++) { if (ao->a[j] && *ao->a[j]) { getrange (ao->a[j]); // XXX filter regname string reg = thumb_getreg (ao->a[j]); if (reg != -1) { if (reg<8) ao->o |= 1<<(8+reg); if (reg==8){ ao->o |= 1; } // else ignore... } } } } else ao->o |= getnum (ao->a[0])<<24; // ??? } else if (!strcmp (ao->op, "push") && ao->a[0]) { ao->o = 0xb4; if (*ao->a[0]++=='{') { for (j=0; j<16; j++) { if (ao->a[j] && *ao->a[j]) { getrange (ao->a[j]); // XXX filter regname string reg = thumb_getreg (ao->a[j]); if (reg != -1) { if (reg<8) ao->o |= 1<<(8+reg); if (reg==8) ao->o |= 1; // else ignore... } } } } else ao->o |= getnum (ao->a[0])<<24; // ??? } else if (!strcmp (ao->op, "ldmia")) { ao->o = 0xc8 + getreg (ao->a[0]); ao->o |= getlist(ao->opstr) << 8; } else if (!strcmp (ao->op, "stmia")) { ao->o = 0xc0 + getreg (ao->a[0]); ao->o |= getlist(ao->opstr) << 8; } else if (!strcmp (ao->op, "nop")) { ao->o = 0xbf; } else if (!strcmp (ao->op, "yield")) { ao->o = 0x10bf; } else if (!strcmp (ao->op, "wfe")) { ao->o = 0x20bf; } else if (!strcmp (ao->op, "wfi")) { ao->o = 0x30bf; } else if (!strcmp (ao->op, "sev")) { ao->o = 0x40bf; } else if (!strcmp (ao->op, "bkpt")) { ao->o = 0xbe; ao->o |= (0xff & getnum (ao->a[0]))<<8; } else if (!strcmp (ao->op, "and")) { ao->o = 0x40; ao->o |= (0xff & getreg (ao->a[0])) << 8; ao->o |= (0xff & getreg (ao->a[1])) << 11; } else if (!strcmp (ao->op, "svc")) { ao->o = 0xdf; ao->o |= (0xff & getnum (ao->a[0])) << 8; } else if (!strcmp (ao->op, "b") || !strcmp (ao->op, "b.n")) { ao->o = 0xe0; ao->o |= getnum (ao->a[0])<<8; } else if (!strcmp (ao->op, "bx")) { ao->o = 0x47; ao->o |= getreg (ao->a[0])<<11; } else if (!strcmp (ao->op, "bl")) { ao->o = 0x47; ao->o |= getnum (ao->a[0])<<8; // XXX: length = 4 } else if (*ao->op == 'b') { // conditional branch ao->o = 0xd0 | arm_opcode_cond (ao, 1); ao->o |= getnum (ao->a[0])<<8; } else if (!strcmp (ao->op, "mov")) { int reg = getreg (ao->a[1]); if (reg!=-1) { ao->o = 0x46; ao->o |= (getreg (ao->a[0]))<<8; ao->o |= reg<<11; } else { ao->o = 0x20; ao->o |= (getreg (ao->a[0])); ao->o |= (getnum (ao->a[1])&0xff)<<8; } } else if (!memcmp (ao->op, "ldr", 3)) { getrange (ao->a[1]); getrange (ao->a[2]); if (ao->op[3]=='h') { int a0 = getreg (ao->a[0]); int a1 = getreg (ao->a[1]); int a2 = getreg (ao->a[2]); if (a2 ==-1) { a2 = getnum (ao->a[2])/8; ao->o = 0x88; // | (8+(0xf & a0)); ao->o |= (7&a0)<<8; ao->o |= (7&a1)<<11; ao->o += (7&a2); } else return 0; } else if (ao->op[3]=='b') { int a0 = getreg (ao->a[0]); int a1 = getreg (ao->a[1]); int a2 = getreg (ao->a[2]); if (a2 ==-1) { a2 = getnum (ao->a[2])/8; ao->o = 0x78; // | (8+(0xf & a0)); ao->o |= (7&a0)<<8; ao->o |= (7&a1)<<11; ao->o |= (7&a2); } else return 0; } else { if (!strcmp (ao->a[1], "sp")) { // ldr r0, [sp, n] = a[r0-7][nn] if (getreg (ao->a[2]) == -1) { // ldr r0, [sp, n] ao->o = 0x98 + (0xf & getreg (ao->a[0])); ao->o |= (0xff & getnum (ao->a[2])/4)<<8; } else return 0; } else if (!strcmp (ao->a[1], "pc")) { // ldr r0, [pc, n] = 4[r0-8][nn*4] if (getreg (ao->a[2]) == -1) { ao->o = 0x40 | (8+(0xf & getreg (ao->a[0]))); ao->o |= (0xff & getnum (ao->a[2])/4)<<8; } else return 0; } else { // ldr r0, [rN, rN] = 58[7bits:basereg + 7bits:destreg] int a0 = getreg (ao->a[0]); int a1 = getreg (ao->a[1]); int a2 = getreg (ao->a[2]); ao->o = 0x58; // | (8+(0xf & a0)); ao->o |= (7&a0)<<8; ao->o |= (7&a1)<<11; ao->o |= (7&a2)<<14; } } } else if (!memcmp (ao->op, "str", 3)) { getrange (ao->a[1]); getrange (ao->a[2]); if (ao->op[3]=='h') { int a0 = getreg (ao->a[0]); int a1 = getreg (ao->a[1]); int a2 = getreg (ao->a[2]); if (a2 ==-1) { a2 = getnum (ao->a[2]); ao->o = 0x80; // | (8+(0xf & a0)); ao->o |= (7&a0)<<8; ao->o |= (7&a1)<<11; ao->o |= (7&(a2>>1)); } else return 0;
// TODO: group similar instructions like for non-thumb static int thumb_assemble(ArmOpcode *ao, const char *str) { int reg, j; ao->o = UT32_MAX; if (!strcmpnull (ao->op, "pop") && ao->a[0]) { ao->o = 0xbc; if (*ao->a[0]++=='{') { // XXX: inverse order? for (j=0; j<16; j++) { if (ao->a[j] && *ao->a[j]) { getrange (ao->a[j]); // XXX filter regname string reg = thumb_getreg (ao->a[j]); if (reg != -1) { if (reg<8) ao->o |= 1<<(8+reg); if (reg==8){ ao->o |= 1; } // else ignore... } } } } else ao->o |= getnum (ao->a[0])<<24; // ??? return 2; } else if (!strcmpnull (ao->op, "push") && ao->a[0]) { ao->o = 0xb4; if (*ao->a[0]++=='{') { for (j=0; j<16; j++) { if (ao->a[j] && *ao->a[j]) { getrange (ao->a[j]); // XXX filter regname string reg = thumb_getreg (ao->a[j]); if (reg != -1) { if (reg<8) ao->o |= 1<<(8+reg); if (reg==8) ao->o |= 1; // else ignore... } } } } else ao->o |= getnum (ao->a[0])<<24; // ??? return 2; } else if (!strcmpnull (ao->op, "ldmia")) { ao->o = 0xc8 + getreg (ao->a[0]); ao->o |= getlist(ao->opstr) << 8; return 2; } else if (!strcmpnull (ao->op, "stmia")) { ao->o = 0xc0 + getreg (ao->a[0]); ao->o |= getlist(ao->opstr) << 8; return 2; } else if (!strcmpnull (ao->op, "nop")) { ao->o = 0xbf; return 2; } else if (!strcmpnull (ao->op, "yield")) { ao->o = 0x10bf; return 2; } else if (!strcmpnull (ao->op, "udf")) { ao->o = 0xde; ao->o |= getnum (ao->a[0])<<8; return 2; } else if (!strcmpnull (ao->op, "wfe")) { ao->o = 0x20bf; return 2; } else if (!strcmpnull (ao->op, "wfi")) { ao->o = 0x30bf; return 2; } else if (!strcmpnull (ao->op, "sev")) { ao->o = 0x40bf; return 2; } else if (!strcmpnull (ao->op, "bkpt")) { ao->o = 0xbe; ao->o |= (0xff & getnum (ao->a[0]))<<8; return 2; } else #if 0 if (!strcmpnull (ao->op, "and")) { ao->o = 0x40; ao->o |= (0xff & getreg (ao->a[0])) << 8; ao->o |= (0xff & getreg (ao->a[1])) << 11; } else #endif if (!strcmpnull (ao->op, "svc")) { ao->o = 0xdf; ao->o |= (0xff & getnum (ao->a[0])) << 8; return 2; } else if (!strcmpnull (ao->op, "b") || !strcmpnull (ao->op, "b.n")) { //uncond branch : PC += 4 + (delta*2) int delta = getnum (ao->a[0]) - 4 - ao->off; if ((delta < -2048) || (delta > 2046) || (delta & 1)) { eprintf("branch out of range or not even\n"); return 0; } ut16 opcode = 0xe000 | ((delta / 2) & 0x7ff); //11bit offset>>1 ao->o = opcode >>8; ao->o |= (opcode & 0xff)<<8; // (ut32) ao->o holds the opcode in little-endian format !? return 2; } else