arm β ARM/AArch64 ISA Implementation
Comprehensive ARM architecture support including AArch32, AArch64, TrustZone security extensions, SVE/SVE2 vector processing, PMU, and hardware transactional memory.
📚 What is this & why does it exist?
π‘ Think of it likeβ¦The ARM ISA implementation is like a Swiss Army knife β compact and versatile. The decoder flips between three blades: 32-bit ARM mode (the full-size knife), 16-bit Thumb mode (the compact tool), and 64-bit AArch64 mode (the modern multi-tool). TrustZone adds a lockbox (Secure World) that even the main blade can't access, while SVE extends the toolkit with adjustable-length vector tools that scale to any width.
Architecture Overview
gem5's ARM implementation is one of the most feature-complete ISA ports, supporting ARMv7 (AArch32) through ARMv8+ (AArch64). It models the full ARM exception model, security extensions, virtualization, and advanced SIMD/SVE vector processing.
graph TB
subgraph "Decoder"
ArmDec["ArmISA::Decoder"]
ARM32["ARM Mode\n(32-bit fixed)"]
Thumb["Thumb Mode\n(16/32-bit)"]
A64["AArch64 Mode\n(32-bit fixed)"]
ArmDec --> ARM32
ArmDec --> Thumb
ArmDec --> A64
end
subgraph "Security Model"
EL0["EL0 (User)"]
EL1["EL1 (Kernel)"]
EL2["EL2 (Hypervisor)"]
EL3["EL3 (Secure Monitor)"]
NS["Non-Secure World"]
S["Secure World\n(TrustZone)"]
end
subgraph "Extensions"
PMU["PMU\n(counters)"]
SVE["SVE/SVE2\n(scalable vectors)"]
HTM["HTM\n(transactions)"]
Semi["Semihosting\n(host I/O)"]
end
EL0 --> EL1 --> EL2 --> EL3
EL3 --> NS
EL3 --> S
Instruction Decoder
The ARM decoder handles three instruction sets within the same architecture: ARM (32-bit fixed-width), Thumb (16/32-bit variable), and AArch64 (32-bit fixed-width but different encoding). The current execution state determines which decoder path is used.
namespace ArmISA {
class Decoder : public InstDecoder
{
public:
void moreBytes(const PCStateBase &pc, Addr fetchPC) override;
bool instReady() const override;
StaticInstPtr decode(PCStateBase &nextPC) override;
private:
// Decode based on current execution state
StaticInstPtr decodeInst(ExtMachInst mach_inst);
// AArch32 decode paths
StaticInstPtr decodeArm(ExtMachInst mach_inst);
StaticInstPtr decodeThumb(ExtMachInst mach_inst);
// AArch64 decode path
StaticInstPtr decodeAArch64(ExtMachInst mach_inst);
bool bigThumb; // In second half of 32-bit Thumb
bool aarch64; // AArch64 execution state
ExtMachInst emi;
};
Exception Levels
ARM uses a hierarchical exception level model that cleanly separates privilege levels and security states:
| Level | Name | Typical Use | Key Registers |
|---|---|---|---|
| EL0 | User | Application code | SP_EL0 |
| EL1 | Kernel | OS kernel, device drivers | SCTLR_EL1, TTBR0_EL1, TTBR1_EL1 |
| EL2 | Hypervisor | Virtual machine manager | HCR_EL2, VTTBR_EL2 |
| EL3 | Secure Monitor | TrustZone firmware (ATF) | SCR_EL3 |
TrustZone Security
TrustZone partitions the system into Secure and Non-Secure worlds. EL3 (Secure Monitor) mediates transitions. gem5 models the full security extension including secure memory regions, secure interrupts, and world switching.
// Security state check
bool isSecure(ThreadContext *tc) {
SCR scr = tc->readMiscReg(MISCREG_SCR_EL3);
return !scr.ns; // NS bit = 0 means Secure
}
// Exception model considers security state for:
// - Memory access permissions (secure vs non-secure)
// - Interrupt routing (FIQ to Secure World)
// - Page table selection (secure/non-secure TTBR)
// - Device access (TrustZone-aware peripherals)
Fault Handling
ARM faults implement the full exception model including precise exception levels, syndrome registers, and fault address reporting.
namespace ArmISA {
class ArmFault : public FaultBase
{
protected:
ExceptionLevel toEL; // Target exception level
OperatingMode toMode; // Target mode (AArch32)
FaultSource faultSource; // Hardware or software fault
public:
void invoke(ThreadContext *tc, const StaticInstPtr &inst) override;
// ARM-specific: update syndrome register
virtual uint32_t iss() const = 0; // Instruction Specific Syndrome
virtual ExceptionClass ec() const = 0; // Exception Class
// Determine target EL based on routing rules
ExceptionLevel targetEL(ThreadContext *tc) const;
};
// Specific faults
class UndefinedInstruction : public ArmFault { /* EC=0x00 */ };
class SupervisorCall : public ArmFault { /* EC=0x15 (SVC) */ };
class HypervisorCall : public ArmFault { /* EC=0x16 (HVC) */ };
class SecureMonitorCall : public ArmFault { /* EC=0x17 (SMC) */ };
class DataAbort : public ArmFault {
Addr faultAddr; // FAR_ELx
bool isWrite;
/* EC=0x24 (lower EL) or 0x25 (same EL) */
};
class PrefetchAbort : public ArmFault { /* EC=0x20/0x21 */ };
} // namespace ArmISA
SVE/SVE2 β Scalable Vector Extension
gem5 supports ARM's Scalable Vector Extension with configurable vector lengths (128-2048 bits). SVE uses predication for per-element control and a programming model that is vector-length agnostic.
// SVE registers are scalable β width set at configuration time
// Z0-Z31: Vector registers (VL bits wide)
// P0-P15: Predicate registers (VL/8 bits wide)
// FFR: First Fault Register
// Vector length configuration (in Python config)
// system.cpu.isa.sve_vl = 256 # 256-bit vectors (4 doubles)
Hardware Transactional Memory
gem5 models ARM's TME (Transactional Memory Extension) including transaction start/commit/abort and conflict detection.
class HTMCheckpoint
{
public:
void save(ThreadContext *tc);
void restore(ThreadContext *tc);
// Transaction state
bool isValid() const;
int getNumRetries() const;
Addr getAbortAddress() const;
private:
std::array<RegVal, NumIntRegs> intRegs;
PCStateBase *pcState;
int nesting; // Transaction nesting depth
};
Performance Monitoring Unit
The ARM PMU models hardware performance counters that count architectural events. It uses the probe framework to attach to CPU events without modifying pipeline code.
// ARM PMU event types
enum PMUEvent {
SW_INCR = 0x00, // Software increment
L1I_CACHE_REFILL = 0x01, // L1 I-cache refill
L1D_CACHE_REFILL = 0x03, // L1 D-cache refill
L1D_CACHE = 0x04, // L1 D-cache access
INST_RETIRED = 0x08, // Instruction retired
EXC_TAKEN = 0x09, // Exception taken
BR_MIS_PRED = 0x10, // Branch misprediction
CPU_CYCLES = 0x11, // CPU cycle count
BR_PRED = 0x12, // Branch predicted
MEM_ACCESS = 0x13, // Data memory access
// ... many more event types
};
π Narrated Walkthrough: AArch64 Exception Entry
- Trigger β A DataAbort fault occurs when the CPU accesses an unmapped page at EL0 (user space).
- Target EL β The fault routing logic checks HCR_EL2 and SCR_EL3 to determine the target exception level. For a standard OS, data aborts route to EL1.
- State Save β The processor saves PSTATE to SPSR_EL1 and the return address to ELR_EL1. The faulting address is written to FAR_EL1.
- Syndrome β ESR_EL1 is loaded with the exception syndrome: EC (exception class = DataAbort), ISS (instruction-specific syndrome including DFSC, WnR bit).
- Vector Jump β PC is set to VBAR_EL1 + offset (0x000 for synchronous from lower EL using AArch64). Execution continues at the kernel's exception handler.
- Handler β The OS reads FAR_EL1 and ESR_EL1 to determine what happened, maps the page, then returns via ERET to resume the faulting instruction.
Key Components Reference
| Component | File | Purpose |
|---|---|---|
Decoder | decoder.hh | ARM/Thumb/AArch64 instruction decoder |
ArmISA::ISA | isa.hh | ARM ISA state (system registers, CPSR/PSTATE) |
ArmMMU | ArmMMU.py | ARM MMU with multi-level page table walk |
ArmFault | faults.hh | Exception hierarchy with syndrome generation |
Interrupts | interrupts.hh | GIC (Generic Interrupt Controller) interface |
PMU | ArmPMU.py | Performance counter unit using probe listeners |
HTMCheckpoint | htm.hh | Transactional memory checkpoint/restore |
ArmSystem | ArmSystem.py | ARM-specific system config (GIC, EL support) |
Glossary
| Term | Definition |
|---|---|
| AArch32 | 32-bit ARM execution state (ARMv7 compatible) |
| AArch64 | 64-bit ARM execution state (ARMv8+) |
| Thumb | Compact 16/32-bit instruction encoding for AArch32 |
| Exception Level (EL) | ARM privilege hierarchy: EL0 (user) through EL3 (secure monitor) |
| TrustZone | Hardware security extension partitioning Secure and Non-Secure worlds |
| SVE | Scalable Vector Extension β variable-length SIMD with predication |
| GIC | Generic Interrupt Controller β ARM's standard interrupt distribution mechanism |
| PSTATE | Processor State register in AArch64 (condition flags, exception mask, EL) |