arch-arm: Add AArch32 HLT Semihosting interface

AArch32 HLT instruction is now able to issue Arm Semihosting commands as
the AArch64 counterpart in either Arm and Thumb mode.

Change-Id: I77da73d2e6a9288c704a5f646f4447022517ceb6
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/8372
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
diff --git a/src/arch/arm/isa/decoder/arm.isa b/src/arch/arm/isa/decoder/arm.isa
index 9b8b37a..1a32ce6 100644
--- a/src/arch/arm/isa/decoder/arm.isa
+++ b/src/arch/arm/isa/decoder/arm.isa
@@ -1,6 +1,6 @@
 // -*- mode:c++ -*-
 
-// Copyright (c) 2010-2013,2017 ARM Limited
+// Copyright (c) 2010-2013,2017-2018 ARM Limited
 // All rights reserved
 //
 // The license below extends only to copyright in the software and shall
@@ -76,7 +76,7 @@
                     0x5: ArmSatAddSub::armSatAddSub();
                     0x6: ArmERet::armERet();
                     0x7: decode OPCODE_22 {
-                        0: Breakpoint::bkpt();
+                        0: ArmBkptHlt::armBkptHlt();
                         1: ArmSmcHyp::armSmcHyp();
                     }
                 }
diff --git a/src/arch/arm/isa/formats/breakpoint.isa b/src/arch/arm/isa/formats/breakpoint.isa
index a22f2de..4db470b 100644
--- a/src/arch/arm/isa/formats/breakpoint.isa
+++ b/src/arch/arm/isa/formats/breakpoint.isa
@@ -1,6 +1,6 @@
 // -*- mode:c++ -*-
 
-// Copyright (c) 2010 ARM Limited
+// Copyright (c) 2010,2018 ARM Limited
 // All rights reserved
 //
 // The license below extends only to copyright in the software and shall
@@ -87,7 +87,17 @@
     }
 }};
 
-def format Breakpoint() {{
-    decode_block = 'return new Breakpoint(machInst);\n'
+def format ArmBkptHlt() {{
+    decode_block = '''
+    {
+        if (bits(machInst, 21)) {
+            return new Breakpoint(machInst);
+        } else {
+            uint32_t imm16 = (bits(machInst, 19, 8) << 4) |
+                             (bits(machInst,  3, 0) << 0);
+            return new Hlt(machInst, imm16);
+        }
+    }
+    '''
 }};
 
diff --git a/src/arch/arm/isa/formats/data.isa b/src/arch/arm/isa/formats/data.isa
index 909a525..eab0818 100644
--- a/src/arch/arm/isa/formats/data.isa
+++ b/src/arch/arm/isa/formats/data.isa
@@ -1,4 +1,4 @@
-// Copyright (c) 2010,2017 ARM Limited
+// Copyright (c) 2010,2017-2018 ARM Limited
 // All rights reserved
 //
 // The license below extends only to copyright in the software and shall
@@ -1199,17 +1199,25 @@
             }
           case 0xa:
             {
-                IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 2, 0);
-                IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 5, 3);
-                switch (bits(machInst, 7, 6)) {
-                  case 0x0:
-                    return new Rev(machInst, rd, rm);
-                  case 0x1:
-                    return new Rev16(machInst, rd, rm);
-                  case 0x3:
-                    return new Revsh(machInst, rd, rm);
-                  default:
-                    break;
+                const uint8_t op1 = bits(machInst, 7, 6);
+                if (op1 == 0x2) {
+                    return new Hlt(machInst, bits(machInst, 5, 0));
+                } else {
+                    IntRegIndex rd =
+                        (IntRegIndex)(uint32_t)bits(machInst, 2, 0);
+                    IntRegIndex rm =
+                        (IntRegIndex)(uint32_t)bits(machInst, 5, 3);
+
+                    switch (op1) {
+                      case 0x0:
+                        return new Rev(machInst, rd, rm);
+                      case 0x1:
+                        return new Rev16(machInst, rd, rm);
+                      case 0x3:
+                        return new Revsh(machInst, rd, rm);
+                      default:
+                        break;
+                    }
                 }
             }
             break;
diff --git a/src/arch/arm/isa/insts/misc.isa b/src/arch/arm/isa/insts/misc.isa
index 566ea4b..a183f5d 100644
--- a/src/arch/arm/isa/insts/misc.isa
+++ b/src/arch/arm/isa/insts/misc.isa
@@ -62,6 +62,31 @@
     decoder_output = SemihostConstructor.subst(svcIop)
     exec_output = PredOpExecute.subst(svcIop)
 
+    hltCode = '''
+    ThreadContext *tc = xc->tcBase();
+
+    const auto semihost_imm = Thumb? 0x3C : 0xF000;
+
+    if (ArmSystem::haveSemihosting(tc) && imm == semihost_imm) {
+        R0 = ArmSystem::callSemihosting32(tc, R0, R1);
+    } else {
+        // HLT instructions aren't implemented, so treat them as undefined
+        // instructions.
+        fault = std::make_shared<UndefinedInstruction>(
+            machInst, false, mnemonic);
+    }
+    '''
+
+    hltIop = InstObjParams("hlt", "Hlt", "ImmOp",
+                           { "code": hltCode,
+                             "predicate_test": predicateTest,
+                             "thumb_semihost": '0x3C',
+                             "arm_semihost": '0xF000' },
+                           ["IsNonSpeculative"])
+    header_output += ImmOpDeclare.subst(hltIop)
+    decoder_output += SemihostConstructor.subst(hltIop)
+    exec_output += PredOpExecute.subst(hltIop)
+
     smcCode = '''
     HCR  hcr  = Hcr;
     CPSR cpsr = Cpsr;