ARM: Hook the external data processing instructions into the Thumb decoder.
authorGabe Black <gblack@eecs.umich.edu>
Wed, 2 Jun 2010 17:58:02 +0000 (12:58 -0500)
committerGabe Black <gblack@eecs.umich.edu>
Wed, 2 Jun 2010 17:58:02 +0000 (12:58 -0500)
src/arch/arm/isa/decoder/thumb.isa
src/arch/arm/isa/formats/data.isa

index dfaca8f4292791890029af2ac63bc9868d35e129..9071649a249c4142503629526e830872e8d67795 100644 (file)
 1: decode BIGTHUMB {
     // 16 bit thumb instructions.
     0: decode TOPCODE_15_13 {
-        0x0, 0x1: decode TOPCODE_13_11 {
-            0x0: WarnUnimpl::lsl(); //immediate
-            0x1: WarnUnimpl::lsr(); //immediate
-            0x2: WarnUnimpl::asr(); //immediate
-            0x3: decode TOPCODE_10_9 {
-                0x0: WarnUnimpl::add(); //register
-                0x1: WarnUnimpl::sub(); //register
-                0x2: WarnUnimpl::add(); //3 bit immediate
-                0x3: WarnUnimpl::sub(); //3 bit immediate
-            }
-            0x4: WarnUnimpl::mov(); //immediate
-            0x5: WarnUnimpl::cmp(); //immediate
-            0x6: WarnUnimpl::add(); //8 bit immediate, thumb
-            0x7: WarnUnimpl::sub(); //8 bit immediate, thumb
-        }
+        0x0, 0x1: Thumb16ShiftAddSubMoveCmp::thumb16ShiftAddMoveCmp();
         0x2: decode TOPCODE_12_10 {
-            // Data processing
-            0x0: decode TOPCODE_9_6 {
-                0x0: WarnUnimpl::and(); //register
-                0x1: WarnUnimpl::eor(); //register
-                0x2: WarnUnimpl::lsl(); //register
-                0x3: WarnUnimpl::lsr(); //register
-                0x4: WarnUnimpl::asr(); //register
-                0x5: WarnUnimpl::adc(); //register
-                0x6: WarnUnimpl::sbc(); //register
-                0x7: WarnUnimpl::ror(); //register
-                0x8: WarnUnimpl::tst(); //register
-                0x9: WarnUnimpl::rsb(); //immediate
-                0xa: WarnUnimpl::cmp(); //register (high registers)
-                0xb: WarnUnimpl::cmn(); //register
-                0xc: WarnUnimpl::orr(); //register
-                0xd: WarnUnimpl::mul();
-                0xe: WarnUnimpl::bic(); //register
-                0xf: WarnUnimpl::mvn(); //register
-            }
-            // Special data instructions and branch and exchange
-            0x1: decode TOPCODE_9_6 {
-                0x0: WarnUnimpl::add(); //register (low registers)
-                0x1, 0x2, 0x3: WarnUnimpl::add(); //register (high registers)
-                0x4: WarnUnimpl::unpredictable(); //?
-                0x5, 0x6, 0x7: WarnUnimpl::cmp(); //register
-                0x8: WarnUnimpl::mov(); //register (low registers)
-                0x9, 0xa, 0xb: WarnUnimpl::mov(); //register (high registers)
-                0xc, 0xd: WarnUnimpl::bx();
-                0xe, 0xf: WarnUnimpl::blx(); //register
-            }
+            0x0: Thumb16DataProcessing::thumb16DataProcessing();
+            0x1: Thumb16SpecDataAndBx::thumb16SpecDataAndBx();
             0x2, 0x3: Thumb16MemLit::thumb16MemLit();
             default: Thumb16MemReg::thumb16MemReg();
         }
         0x3, 0x4: Thumb16MemImm::thumb16MemImm();
         0x5: decode TOPCODE_12_11 {
-            0x0: WarnUnimpl::adr();
-            0x1: WarnUnimpl::add(); //sp, immediate
-            0x2: decode TOPCODE_10_8 {
-                0x0: decode TOPCODE_7 {
-                    0x0: WarnUnimpl::add(); //sp, immediate
-                    0x1: WarnUnimpl::sub(); //sp, immediate
-                }
-                0x1, 0x3: WarnUnimpl::cbz(); //cbnz too...
-                0x2: decode TOPCODE_7_6 {
-                    0x0: WarnUnimpl::sxth();
-                    0x1: WarnUnimpl::sxtb();
-                    0x2: WarnUnimpl::uxth();
-                    0x3: WarnUnimpl::uxtb();
-                }
-                0x4, 0x5: WarnUnimpl::pop();
-                0x6: decode TOPCODE_7_5 {
-                    0x2: WarnUnimpl::setend();
-                    0x3: WarnUnimpl::cps();
-                }
-            }
-            0x3: decode TOPCODE_10_8 {
-                0x1, 0x3: WarnUnimpl::cbz(); //cbnz too...
-                0x2: decode TOPCODE_7_6 {
-                    0x0: WarnUnimpl::rev();
-                    0x1: WarnUnimpl::rev16();
-                    0x3: WarnUnimpl::revsh();
-                }
-                0x4, 0x5: WarnUnimpl::pop();
-                0x6: WarnUnimpl::bkpt();
-                0x7: decode TOPCODE_3_0 {
-                    0x0: WarnUnimpl::it();
-                    default: decode TOPCODE_7_4 {
-                        0x0: WarnUnimpl::nop();
-                        0x1: WarnUnimpl::yield();
-                        0x2: WarnUnimpl::wfe();
-                        0x3: WarnUnimpl::wfi();
-                        0x4: WarnUnimpl::sev();
-                        default: WarnUnimpl::unallocated_hint();
-                    }
-                }
-            }
+            0x0: Thumb16Adr::thumb16Adr();
+            0x1: Thumb16AddSp::thumb16AddSp(); //sp, immediate
+            0x2, 0x3: Thumb16Misc::thumb16Misc();
         }
         0x6: decode TOPCODE_12_11 {
             0x0, 0x1: Thumb16MacroMem::thumb16MacroMem();
                     }
                 }
             }
-            0x1: decode HTOPCODE_8_5 {
-                0x0: decode LTRD {
-                    0xf: decode HTS {
-                        0x1: WarnUnimpl::tst(); // register
-                    }
-                    default: WarnUnimpl::and(); // register
-                }
-                0x1: WarnUnimpl::bic(); // register
-                0x2: decode HTRN {
-                    0xf: WarnUnimpl::mov(); // register
-                    default: WarnUnimpl::orr(); // register
-                }
-                0x3: decode HTRN {
-                    0xf: WarnUnimpl::mvn(); // register
-                    default: WarnUnimpl::orn(); // register
-                }
-                0x4: decode LTRD {
-                    0xf: decode HTS {
-                        0x1: WarnUnimpl::teq(); // register
-                    }
-                    default: WarnUnimpl::eor(); // register
-                }
-                0x6: WarnUnimpl::pkh();
-                0x8: decode LTRD {
-                    0xf: decode HTS {
-                        0x1: WarnUnimpl::cmn(); // register
-                    }
-                    default: WarnUnimpl::add(); // register
-                }
-                0xa: WarnUnimpl::adc(); // register
-                0xb: WarnUnimpl::sbc(); // register
-                0xd: decode LTRD {
-                    0xf: decode HTS {
-                        0x1: WarnUnimpl::cmp(); // register
-                    }
-                    default: WarnUnimpl::sub(); // register
-                }
-                0xe: WarnUnimpl::rsb(); // register
-            }
+            0x1: Thumb32DataProcShiftReg::thumb32DataProcShiftReg();
             default: decode HTOPCODE_9_8 {
                 0x2: decode LTOPCODE_4 {
                     0x0: decode LTCOPROC {
         }
         0x2: decode LTOPCODE_15 {
             0x0: decode HTOPCODE_9 {
-                0x0: decode HTOPCODE_8_5 {
-                    0x0: decode LTRD {
-                        0xf: decode HTS {
-                            0x1: DataModImmOp::tst({{
-                                resTemp = Rn & rotated_imm;
-                            }});
-                        }
-                        default: DataModImmOp::and({{
-                            Rs = resTemp = Rn & rotated_imm;
-                        }});
-                    }
-                    0x1: DataModImmOp::bic({{
-                        Rs = resTemp = Rn & ~rotated_imm;
-                    }});
-                    0x2: decode HTRN {
-                        0xf: DataModImmOp::mov({{
-                            Rs = resTemp = rotated_imm;
-                        }});
-                        default: DataModImmOp::orr({{
-                            Rs = resTemp = Rn | rotated_imm;
-                        }});
-                    }
-                    0x3: decode HTRN {
-                        0xf: DataModImmOp::mvn({{
-                            Rs = resTemp = ~rotated_imm;
-                        }});
-                        default: DataModImmOp::orn({{
-                            Rs = resTemp = Rn | ~rotated_imm;
-                        }});
-                    }
-                    0x4: decode LTRD {
-                        0xf: decode HTS {
-                            0x1: DataModImmOp::teq({{
-                                resTemp = Rn ^ rotated_imm;
-                            }});
-                        }
-                        default: DataModImmOp::eor({{
-                            Rs = resTemp = Rn ^ rotated_imm;
-                        }});
-                    }
-                    0x8: decode LTRD {
-                        0xf: decode HTS {
-                            0x1: DataModImmOp::cmn({{
-                                resTemp = Rn + rotated_imm;
-                            }}, add);
-                        }
-                        default: DataModImmOp::add({{
-                            Rs = resTemp = Rn + rotated_imm;
-                        }}, add);
-                    }
-                    0xa: DataModImmOp::adc({{
-                        Rs = resTemp = Rn + rotated_imm + CondCodes<29:>;
-                    }}, add);
-                    0xb: DataModImmOp::sbc({{
-                        Rs = resTemp = Rn - rotated_imm - !CondCodes<29:>;
-                    }}, sub);
-                    0xd: decode LTRD {
-                        0xf: decode HTS {
-                            0x1: DataModImmOp::cmp({{
-                                resTemp = Rn - rotated_imm;
-                            }}, sub);
-                        }
-                        default: DataModImmOp::sub({{
-                            Rs = resTemp = Rn - rotated_imm;
-                        }}, sub);
-                    }
-                    0xe: DataModImmOp::rsb({{
-                        Rs = resTemp = rotated_imm - Rn;
-                    }}, rsb);
-                }
+                0x0: Thumb32DataProcModImm::thumb32DataProcModImm();
                 0x1: WarnUnimpl::Data_processing_plain_binary_immediate();
             }
             0x1: WarnUnimpl::Branches_and_miscellaneous_control();
index 37a10f160f0576db54a9368a895e945de2976554..ee4e089f9a4b37f1ccbda478a148771e62d3e905 100644 (file)
@@ -40,28 +40,30 @@ def format ArmDataProcReg() {{
           case %(opcode)#x:
             if (immShift) {
                 if (setCc) {
-                    return new %(className)sDRegCc(machInst,
-                                                   rd, rn, rm, imm5, type);
+                    return new %(className)sDRegCc(machInst, %(dest)s, %(op1)s,
+                                                   rm, imm5, type);
                 } else {
-                    return new %(className)sDReg(machInst,
-                                                 rd, rn, rm, imm5, type);
+                    return new %(className)sDReg(machInst, %(dest)s, %(op1)s,
+                                                 rm, imm5, type);
                 }
             } else {
                 if (setCc) {
-                    return new %(className)sDRegRegCc(machInst,
-                                                      rd, rn, rm, rs, type);
+                    return new %(className)sDRegRegCc(machInst, %(dest)s,
+                                                      %(op1)s, rm, rs, type);
                 } else {
-                    return new %(className)sDRegReg(machInst,
-                                                    rd, rn, rm, rs, type);
+                    return new %(className)sDRegReg(machInst, %(dest)s,
+                                                    %(op1)s, rm, rs, type);
                 }
             }
             break;
     '''
 
-    def instCode(opcode, mnem):
+    def instCode(opcode, mnem, dest="rd", op1="rn"):
         global instDecode
         return instDecode % { "className": mnem.capitalize(),
-                              "opcode": opcode }
+                              "opcode": opcode,
+                              "dest": dest,
+                              "op1": op1 }
 
     decode_block = '''
     {
@@ -83,14 +85,14 @@ def format ArmDataProcReg() {{
     decode_block += instCode(0x5, "adc")
     decode_block += instCode(0x6, "sbc")
     decode_block += instCode(0x7, "rsc")
-    decode_block += instCode(0x8, "tst")
-    decode_block += instCode(0x9, "teq")
-    decode_block += instCode(0xa, "cmp")
-    decode_block += instCode(0xb, "cmn")
+    decode_block += instCode(0x8, "tst", dest="INTREG_ZERO")
+    decode_block += instCode(0x9, "teq", dest="INTREG_ZERO")
+    decode_block += instCode(0xa, "cmp", dest="INTREG_ZERO")
+    decode_block += instCode(0xb, "cmn", dest="INTREG_ZERO")
     decode_block += instCode(0xc, "orr")
-    decode_block += instCode(0xd, "mov")
+    decode_block += instCode(0xd, "mov", op1="INTREG_ZERO")
     decode_block += instCode(0xe, "bic")
-    decode_block += instCode(0xf, "mvn")
+    decode_block += instCode(0xf, "mvn", op1="INTREG_ZERO")
     decode_block += '''
           default:
             return new Unknown(machInst);
@@ -103,17 +105,21 @@ def format ArmDataProcImm() {{
     instDecode = '''
           case %(opcode)#x:
             if (setCc) {
-                return new %(className)sDImmCc(machInst, rd, rn, imm, rotC);
+                return new %(className)sDImmCc(machInst, %(dest)s, %(op1)s,
+                                               imm, rotC);
             } else {
-                return new %(className)sDImm(machInst, rd, rn, imm, rotC);
+                return new %(className)sDImm(machInst, %(dest)s, %(op1)s,
+                                             imm, rotC);
             }
             break;
     '''
 
-    def instCode(opcode, mnem):
+    def instCode(opcode, mnem, dest="rd", op1="rn"):
         global instDecode
         return instDecode % { "className": mnem.capitalize(),
-                              "opcode": opcode }
+                              "opcode": opcode,
+                              "dest": dest,
+                              "op1": op1 }
 
     decode_block = '''
     {
@@ -134,14 +140,14 @@ def format ArmDataProcImm() {{
     decode_block += instCode(0x5, "adc")
     decode_block += instCode(0x6, "sbc")
     decode_block += instCode(0x7, "rsc")
-    decode_block += instCode(0x8, "tst")
-    decode_block += instCode(0x9, "teq")
-    decode_block += instCode(0xa, "cmp")
-    decode_block += instCode(0xb, "cmn")
+    decode_block += instCode(0x8, "tst", dest="INTREG_ZERO")
+    decode_block += instCode(0x9, "teq", dest="INTREG_ZERO")
+    decode_block += instCode(0xa, "cmp", dest="INTREG_ZERO")
+    decode_block += instCode(0xb, "cmn", dest="INTREG_ZERO")
     decode_block += instCode(0xc, "orr")
-    decode_block += instCode(0xd, "mov")
+    decode_block += instCode(0xd, "mov", op1="INTREG_ZERO")
     decode_block += instCode(0xe, "bic")
-    decode_block += instCode(0xf, "mvn")
+    decode_block += instCode(0xf, "mvn", op1="INTREG_ZERO")
     decode_block += '''
           default:
             return new Unknown(machInst);
@@ -149,3 +155,404 @@ def format ArmDataProcImm() {{
     }
     '''
 }};
+
+def format Thumb16ShiftAddSubMoveCmp() {{
+    decode_block = '''
+    {
+        const uint32_t imm5 = bits(machInst, 10, 6);
+        const uint32_t imm3 = bits(machInst, 8, 6);
+        const uint32_t imm8 = bits(machInst, 7, 0);
+        const IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 2, 0);
+        const IntRegIndex rd8 = (IntRegIndex)(uint32_t)bits(machInst, 10, 8);
+        const IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 5, 3);
+        const IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 8, 6);
+        switch (bits(machInst, 13, 11)) {
+          case 0x0: // lsl
+            return new MovDReg(machInst, rd, INTREG_ZERO, rn, imm5, LSL);
+          case 0x1: // lsr
+            return new MovDReg(machInst, rd, INTREG_ZERO, rn, imm5, LSR);
+          case 0x2: // asr
+            return new MovDReg(machInst, rd, INTREG_ZERO, rn, imm5, ASR);
+          case 0x3:
+            switch (bits(machInst, 10, 9)) {
+              case 0x0:
+                return new AddDReg(machInst, rd, rn, rm, 0, LSL);
+              case 0x1:
+                return new SubDReg(machInst, rd, rn, rm, 0, LSL);
+              case 0x2:
+                return new AddDImm(machInst, rd, rn, imm3, true);
+              case 0x3:
+                return new SubDImm(machInst, rd, rn, imm3, true);
+            }
+          case 0x4:
+            return new MovDImm(machInst, rd8, INTREG_ZERO, imm8, true);
+          case 0x5:
+            return new CmpDImmCc(machInst, INTREG_ZERO, rd8, imm8, true);
+          case 0x6:
+            return new AddDImm(machInst, rd8, rd8, imm8, true);
+          case 0x7:
+            return new SubDImm(machInst, rd8, rd8, imm8, true);
+        }
+    }
+    '''
+}};
+
+def format Thumb16DataProcessing() {{
+    decode_block = '''
+    {
+        const IntRegIndex rdn = (IntRegIndex)(uint32_t)bits(machInst, 2, 0);
+        const IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 5, 3);
+        switch (bits(machInst, 9, 6)) {
+          case 0x0:
+            return new AndDReg(machInst, rdn, rdn, rm, 0, LSL);
+          case 0x1:
+            return new EorDReg(machInst, rdn, rdn, rm, 0, LSL);
+          case 0x2: //lsl
+            return new MovDRegReg(machInst, rdn, INTREG_ZERO, rdn, rm, LSL);
+          case 0x3: //lsr
+            return new MovDRegReg(machInst, rdn, INTREG_ZERO, rdn, rm, LSR);
+          case 0x4: //asr
+            return new MovDRegReg(machInst, rdn, INTREG_ZERO, rdn, rm, ASR);
+          case 0x5:
+            return new AdcDReg(machInst, rdn, rdn, rm, 0, LSL);
+          case 0x6:
+            return new SbcDReg(machInst, rdn, rdn, rm, 0, LSL);
+          case 0x7: // ror
+            return new MovDRegReg(machInst, rdn, INTREG_ZERO, rdn, rm, ROR);
+          case 0x8:
+            return new TstDReg(machInst, INTREG_ZERO, rdn, rm, 0, LSL);
+          case 0x9:
+            return new RsbDImm(machInst, rdn, rm, 0, true);
+          case 0xa:
+            return new CmpDReg(machInst, INTREG_ZERO, rdn, rm, 0, LSL);
+          case 0xb:
+            return new CmnDReg(machInst, INTREG_ZERO, rdn, rm, 0, LSL);
+          case 0xc:
+            return new OrrDReg(machInst, rdn, rdn, rm, 0, LSL);
+          case 0xd:
+            //XXX Implement me!
+            return new WarnUnimplemented("mul", machInst);
+          case 0xe:
+            return new BicDReg(machInst, rdn, rdn, rm, 0, LSL);
+          case 0xf:
+            return new MvnDReg(machInst, rdn, INTREG_ZERO, rm, 0, LSL);
+        }
+    }
+    '''
+}};
+
+def format Thumb16SpecDataAndBx() {{
+    decode_block = '''
+    {
+        const IntRegIndex rdn =
+            (IntRegIndex)(uint32_t)(bits(machInst, 2, 0) |
+                                    (bits(machInst, 7) << 3));
+        const IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 6, 3);
+        switch (bits(machInst, 9, 8)) {
+          case 0x0:
+            return new AddDReg(machInst, rdn, rdn, rm, 0, LSL);
+          case 0x1:
+            return new CmpDReg(machInst, INTREG_ZERO, rdn, rm, 0, LSL);
+          case 0x2:
+            return new MovDReg(machInst, rdn, INTREG_ZERO, rm, 0, LSL);
+          case 0x3:
+            if (bits(machInst, 7) == 0)
+                return new WarnUnimplemented("bx", machInst);
+            else
+                // The register version.
+                return new WarnUnimplemented("blx", machInst);
+        }
+    }
+    '''
+}};
+
+def format Thumb16Adr() {{
+    decode_block = '''
+    {
+        const IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 10, 8);
+        const uint32_t imm8 = bits(machInst, 7, 0) << 2;
+        return new AddDImm(machInst, rd, INTREG_PC, imm8, true);
+    }
+    '''
+}};
+
+def format Thumb16AddSp() {{
+    decode_block = '''
+    {
+        const IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 10, 8);
+        const uint32_t imm8 = bits(machInst, 7, 0) << 2;
+        return new AddDImm(machInst, rd, INTREG_SP, imm8, true);
+    }
+    '''
+}};
+
+def format Thumb16Misc() {{
+    decode_block = '''
+    {
+        switch (bits(machInst, 11, 8)) {
+          case 0x0:
+            if (bits(machInst, 7)) {
+                return new SubDImm(machInst, INTREG_SP, INTREG_SP,
+                                   bits(machInst, 6, 0) << 2, true);
+            } else {
+                return new AddDImm(machInst, INTREG_SP, INTREG_SP,
+                                   bits(machInst, 6, 0) << 2, true);
+            }
+          case 0x1:
+            return new WarnUnimplemented("cbz", machInst);
+          case 0x2:
+            switch (bits(machInst, 7, 6)) {
+              case 0x0:
+                return new WarnUnimplemented("sxth", machInst);
+              case 0x1:
+                return new WarnUnimplemented("sxtb", machInst);
+              case 0x2:
+                return new WarnUnimplemented("uxth", machInst);
+              case 0x3:
+                return new WarnUnimplemented("uxtb", machInst);
+            }
+          case 0x3:
+            return new WarnUnimplemented("cbnz", machInst);
+          case 0x4:
+          case 0x5:
+            return new WarnUnimplemented("push", machInst);
+          case 0x6:
+            {
+                const uint32_t opBits = bits(machInst, 7, 5);
+                if (opBits == 2) {
+                    return new WarnUnimplemented("setend", machInst);
+                } else if (opBits == 3) {
+                    return new WarnUnimplemented("cps", machInst);
+                }
+            }
+          case 0x9:
+            return new WarnUnimplemented("cbz", machInst);
+          case 0xa:
+            switch (bits(machInst, 7, 5)) {
+              case 0x0:
+                return new WarnUnimplemented("rev", machInst);
+              case 0x1:
+                return new WarnUnimplemented("rev16", machInst);
+              case 0x3:
+                return new WarnUnimplemented("revsh", machInst);
+              default:
+                break;
+            }
+            break;
+          case 0xb:
+            return new WarnUnimplemented("cbnz", machInst);
+          case 0xc:
+          case 0xd:
+            return new WarnUnimplemented("pop", machInst);
+          case 0xe:
+            return new WarnUnimplemented("bkpt", machInst);
+          case 0xf:
+            if (bits(machInst, 3, 0) != 0)
+                return new WarnUnimplemented("it", machInst);
+            switch (bits(machInst, 7, 4)) {
+              case 0x0:
+                return new WarnUnimplemented("nop", machInst);
+              case 0x1:
+                return new WarnUnimplemented("yield", machInst);
+              case 0x2:
+                return new WarnUnimplemented("wfe", machInst);
+              case 0x3:
+                return new WarnUnimplemented("wfi", machInst);
+              case 0x4:
+                return new WarnUnimplemented("sev", machInst);
+              default:
+                return new WarnUnimplemented("unallocated_hint", machInst);
+            }
+          default:
+            break;
+        }
+        return new Unknown(machInst);
+    }
+    '''
+}};
+
+def format Thumb32DataProcModImm() {{
+
+    def decInst(mnem, dest="rd", op1="rn"):
+        return '''
+            if (s) {
+                return new %(mnem)sDImmCc(machInst, %(dest)s,
+                                          %(op1)s, imm, true);
+            } else {
+                return new %(mnem)sDImm(machInst, %(dest)s,
+                                        %(op1)s, imm, true);
+            }
+        ''' % {"mnem" : mnem, "dest" : dest, "op1" : op1}
+
+    decode_block = '''
+    {
+        const uint32_t op = bits(machInst, 24, 21);
+        const bool s = (bits(machInst, 20) == 1);
+        const IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 19, 16);
+        const IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 11, 8);
+        const uint32_t ctrlImm = bits(machInst.instBits, 26) << 3 |
+                                 bits(machInst, 14, 12);
+        const uint32_t dataImm = bits(machInst, 7, 0);
+        const uint32_t imm = modified_imm(ctrlImm, dataImm);
+        switch (op) {
+          case 0x0:
+            if (rd == INTREG_PC) {
+                %(tst)s
+            } else {
+                %(and)s
+            }
+          case 0x1:
+            %(bic)s
+          case 0x2:
+            if (rn == INTREG_PC) {
+                %(mov)s
+            } else {
+                %(orr)s
+            }
+          case 0x3:
+            if (rn == INTREG_PC) {
+                %(mvn)s
+            } else {
+                %(orn)s
+            }
+          case 0x4:
+            if (rd == INTREG_PC) {
+                %(teq)s
+            } else {
+                %(eor)s
+            }
+          case 0x8:
+            if (rd == INTREG_PC) {
+                %(cmn)s
+            } else {
+                %(add)s
+            }
+          case 0xa:
+            %(adc)s
+          case 0xb:
+            %(sbc)s
+          case 0xd:
+            if (rd == INTREG_PC) {
+                %(cmp)s
+            } else {
+                %(sub)s
+            }
+          case 0xe:
+            %(rsb)s
+          default:
+            return new Unknown(machInst);
+        }
+    }
+    ''' % {
+        "tst" : decInst("Tst", "INTREG_ZERO"),
+        "and" : decInst("And"),
+        "bic" : decInst("Bic"),
+        "mov" : decInst("Mov", op1="INTREG_ZERO"),
+        "orr" : decInst("Orr"),
+        "mvn" : decInst("Mvn", op1="INTREG_ZERO"),
+        "orn" : decInst("Orn"),
+        "teq" : decInst("Teq", dest="INTREG_ZERO"),
+        "eor" : decInst("Eor"),
+        "cmn" : decInst("Cmn", dest="INTREG_ZERO"),
+        "add" : decInst("Add"),
+        "adc" : decInst("Adc"),
+        "sbc" : decInst("Sbc"),
+        "cmp" : decInst("Cmp", dest="INTREG_ZERO"),
+        "sub" : decInst("Sub"),
+        "rsb" : decInst("Rsb")
+    }
+}};
+
+def format Thumb32DataProcShiftReg() {{
+
+    def decInst(mnem, dest="rd", op1="rn"):
+        return '''
+            if (s) {
+                return new %(mnem)sDRegCc(machInst, %(dest)s,
+                                          %(op1)s, rm, amt, type);
+            } else {
+                return new %(mnem)sDReg(machInst, %(dest)s,
+                                        %(op1)s, rm, amt, type);
+            }
+        ''' % {"mnem" : mnem, "dest" : dest, "op1" : op1}
+
+    decode_block = '''
+    {
+        const uint32_t op = bits(machInst, 24, 21);
+        const bool s = (bits(machInst, 20) == 1);
+        const IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 19, 16);
+        const IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 11, 8);
+        const IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 3, 0);
+        const uint32_t amt = (bits(machInst, 14, 12) << 2) |
+                              bits(machInst, 7, 6);
+        const ArmShiftType type = (ArmShiftType)(uint32_t)bits(machInst, 5, 4);
+        switch (op) {
+          case 0x0:
+            if (rd == INTREG_PC) {
+                %(tst)s
+            } else {
+                %(and)s
+            }
+          case 0x1:
+            %(bic)s
+          case 0x2:
+            if (rn == INTREG_PC) {
+                %(mov)s
+            } else {
+                %(orr)s
+            }
+          case 0x3:
+            if (rn == INTREG_PC) {
+                %(mvn)s
+            } else {
+                %(orn)s
+            }
+          case 0x4:
+            if (rd == INTREG_PC) {
+                %(teq)s
+            } else {
+                %(eor)s
+            }
+          case 0x6:
+            return new WarnUnimplemented("pkh", machInst);
+          case 0x8:
+            if (rd == INTREG_PC) {
+                %(cmn)s
+            } else {
+                %(add)s
+            }
+          case 0xa:
+            %(adc)s
+          case 0xb:
+            %(sbc)s
+          case 0xd:
+            if (rd == INTREG_PC) {
+                %(cmp)s
+            } else {
+                %(sub)s
+            }
+          case 0xe:
+            %(rsb)s
+          default:
+            return new Unknown(machInst);
+        }
+    }
+    ''' % {
+        "tst" : decInst("Tst", "INTREG_ZERO"),
+        "and" : decInst("And"),
+        "bic" : decInst("Bic"),
+        "mov" : decInst("Mov", op1="INTREG_ZERO"),
+        "orr" : decInst("Orr"),
+        "mvn" : decInst("Mvn", op1="INTREG_ZERO"),
+        "orn" : decInst("Orn"),
+        "teq" : decInst("Teq", "INTREG_ZERO"),
+        "eor" : decInst("Eor"),
+        "cmn" : decInst("Cmn", "INTREG_ZERO"),
+        "add" : decInst("Add"),
+        "adc" : decInst("Adc"),
+        "sbc" : decInst("Sbc"),
+        "cmp" : decInst("Cmp", "INTREG_ZERO"),
+        "sub" : decInst("Sub"),
+        "rsb" : decInst("Rsb")
+    }
+}};