# Registers
Hexagon has general registers and control registers.
Control registers support special-purpose processor features such as
hardware loops and predicates.
## General registers
The Hexagon processor has thirty-two 32-bit general-purpose registers
(named R0 through R31). These registers store operands in the
instructions:
- Memory addresses for load/store instructions
- Data operands for arithmetic/logic instructions
- Vector operands for 32-bit and 64-bit vector instructions For example:
R1 = memh(R0) // Load from address R0
R4 = add(R2,R3) // Add
R28 = vaddh(R11,R10) // Vector add halfword
Copy to clipboard
**General registers**
### Aliased registers
Three of the general registers - R29 through R31 - support
subroutines ([calls](https://docs.qualcomm.com/doc/80-N2040-60/topic/program-flow.html#v79-prm-calls)) and the
[Software stack](https://docs.qualcomm.com/doc/80-N2040-60/topic/software-stack.html). The subroutine and stack instructions
implicitly modify the registers. R29-R31 are aliased to SP, FP, and LR respectively.
For example:
SP = add(SP, #-8) // SP is an alias of R29
allocframe // Modifies SP (R29) and FP (R30)
call init // Modifies LR (R31)
Copy to clipboard
General register aliases
| **Register** | **Alias** | **Name** | **Description** |
| --- | --- | --- | --- |
| R29 | SP | Stack pointer | Points to the topmost element of the stack in memory. |
| R30 | FP | Frame pointer | Points to the current stack frame. |
| R31 | LR | Link register | Stores the return address of a subroutine call. |
### Register pairs
The general registers can be specified as register pairs that
represent a single 64-bit register. For example:
R1:0 = memd(R3) // Load doubleword
R7:6 = valignb(R9:8,R7:6, #2) // Vector align
Copy to clipboard
The first register in a register pair is always odd-numbered
and the second is the next lower register.
| **Register** | **Register pair** |
| --- | --- |
| R0 | R1:0 |
| R1 | R1:0 |
| R2 | R3:2 |
| R3 | R3:2 |
| R4 | R5:4 |
| R5 | R5:4 |
| R6 | R7:6 |
| R7 | R7:6 |
| **…** | **…** |
| R24 | R25:24 |
| R25 | R25:24 |
| R26 | R27:26 |
| R27 | R27:26 |
| R28 | R29:28 |
| R29 (SP) | R29:28 |
| R30 (FP) | R31:30 (LR:FP) |
| R31 (LR) | R31:30 (LR:FP) |
| | |
## Control registers
The Hexagon processor includes a set of 32-bit control registers that
provide access to processor features such as the program counter,
hardware loops, and vector predicates.
Unlike general registers, control registers are used as instruction
operands only in the following cases:
- Instructions that require a specific control register as an operand
- Register transfer instructions For example:
R2 = memw(R0++M1) // Auto-increment addressing mode (M1)
R9 = PC // Get program counter (PC)
LC1 = R3 // Set hardware loop count (LC1)
Copy to clipboard
When a control register is used in a register transfer, the
other operand must be a general register.
**Control registers**
### Aliased registers
The control registers have numeric aliases (C0 through C31). The control register numbers (0 through 31)
specify the control registers in [Instruction encoding](https://docs.qualcomm.com/doc/80-N2040-60/topic/instruction-encoding.html).
Aliased control registers
| **Register** | **Alias** | **Name** |
| --- | --- | --- |
| SA0 | C0 | Loop start address register 0 |
| LC0 | C1 | Loop count register 0 |
| SA1 | C2 | Loop start address register 1 |
| LC1 | C3 | Loop count register 1 |
| P3:0 | C4 | Predicate registers 3:0 |
| reserved | C5 | |
| M0 | C6 | Modifier register 0 |
| M1 | C7 | Modifier register 1 |
| USR | C8 | User status register |
| PC | C9 | Program counter |
| UGP | C10 | User general pointer |
| GP | C11 | Global pointer |
| CS0 | C12 | Circular start register 0 |
| CS1 | C13 | Circular start register 1 |
| UPCYCLELO | C14 | Cycle count register (low) |
| UPCYCLEHI | C15 | Cycle count register (high) |
| UPCYCLE | C15:14 | Cycle count register |
| FRAMELIMIT | C16 | Frame limit register |
| FRAMEKEY | C17 | Frame key register |
| PKTCOUNTLO | C18 | Packet count register (low) |
| PKTCOUNTHI | C19 | Packet count register (high) |
| PKTCOUNT | C19:18 | Packet count register |
| reserved | C20-29 | |
| UTIMERLO | C30 | QTimer register (low) |
| UTIMERHI | C31 | QTimer register (high) |
| UTIMER | C31:30 | QTimer register |
### Control register pairs
The control registers can be specified as register pairs that
represent a single 64-bit register. Control registers specified as
pairs must use their numeric aliases. For example:
C1:0 = R5:4 / C1:0 specifies the LC0/SA0 register pair
Copy to clipboard
The first register in a control register pair must always
be odd-numbered, and the second must be the next lower register.
| **Register** | **Register pair** |
| --- | --- |
| C0 | C1:0 |
| C1 | C1:0 |
| C2 | C3:2 |
| C3 | C3:2 |
| C4 | C5:4 |
| C5 | C5:4 |
| C6 | C7:6 |
| C7 | C7:6 |
| **…** | **…** |
| C30 | C31:30 |
| C31 | C31:30 |
| | |
### Program counter
The program counter (PC) register points to the instruction
packet to execute ([instruction packets](https://docs.qualcomm.com/doc/80-N2040-60/topic/instructions.html#v79-prm-instruction-packets)).
The PC is read-only and updates when the current packet completes.
Instruction execution modifies the PC. For example:
R7 = PC // Get program counter
Copy to clipboard
### Loop registers
The Hexagon processor includes two sets of loop registers to support
nested [Hardware loops](https://docs.qualcomm.com/doc/80-N2040-60/topic/registers.html#hardware-loops). Each hardware loop is
implemented with a pair of registers containing the loop count and
loop start address. The loop instruction implicitly modifies the loop
registers, but the loop instructions can also be accessed directly.
For example:
loop0(start, R4) // Modifies LC0 and SA0 (LC0 = R4, SA0 = start)
LC1 = R22 // Set loop1 count
R9 = SA1 // Get loop1 start address
Copy to clipboard
Loop registers
| **Register** | **Name** | **Description** |
| --- | --- | --- |
| LC0, LC1 | Loop count | Number of loop iterations to execute. |
| SA0, SA1 | Loop start address | Address of first instruction in loop. |
### User status register
The user status register (USR) stores processor status and control
bits that user programs can access. The status bits contain the
status results of certain instructions, while the control bits
contain user-settable processor modes for hardware prefetching. For
example:
R9:8 = vaddw(R9:8, R3:2):sat // Vector add words
R6 = USR // Get saturation status
Copy to clipboard
USR stores the following status and control values:
- [Cache prefetch types supported by the Hexagon processor](https://docs.qualcomm.com/doc/80-N2040-60/topic/registers.html#cache-prefetch-types-supported-by-the-hexagon-processor) enable
- Cache prefetch status
- [Floating point](https://docs.qualcomm.com/doc/80-N2040-60/topic/registers.html#floating-point) modes
- Floating point status
- Floating point exception enable
- Hardware loop configuration ([hardware loops](https://docs.qualcomm.com/doc/80-N2040-60/topic/program-flow.html#v79-prm-hardware-loops))
- Sticky [Saturation](https://docs.qualcomm.com/doc/80-N2040-60/topic/registers.html#saturation) overflow
A user control register transfer to USR cannot be grouped
in an instruction packet with a
[Floating point](https://docs.qualcomm.com/doc/80-N2040-60/topic/registers.html#floating-point) instruction.
When a transfer to USR changes the enable trap bits [29:25], an isync
instruction ([memory ordering](https://docs.qualcomm.com/doc/80-N2040-60/topic/memory.html#v79-prm-memory-ordering)) must execute before
the new exception programming can take effect.
User status register
| **Name** | **RW** | **Bits** | **Field** | **Description** |
| --- | --- | --- | --- | --- |
| USR | | 32 | | User status register |
| | R | 31 | PFA | L2 prefetch active.
1: l2fetch instruction in progress
0: l2fetch finished (or inactive)
Set when the nonblocking l2fetch instruction prefetches therequested data.
Remains set until thel2fetch prefetch operation completes (or is inactive). |
| | R | 30 | reserved | Reserved. |
| | RW | 29 | FPINEE | Enable exception on IEEE inexact. |
| | RW | 28 | FPUNFE | Enable exception on IEEE underflow. |
| | RW | 27 | FPOVFE | Enable exception on IEEE overflow. |
| | RW | 26 | FPDBZE | Enable exception on IEEE divide-by-zero. |
| | RW | 25 | FPINVE | Enable exception on IEEE invalid. |
| | R | 24 | reserved | Reserved |
| | RW | 23:22 | FPRND | Rounding mode for floating point instructions.
00: Round to nearest, ties to even (default)
01: Toward zero
10: Downward (toward negative infinity)
11: Upward (toward positive infinity)
|
| | R | 21:20 | FPCOPROC | Controls IEEE-754 floating point behavior.
USR[20]: When set to 1, max exponent represents IEEE-754 Infinity or NaN
USR[21]: When set to 1, IEEE-754 Infinity and NaN representation is IEEE-754 compliant instead of a finite overflow.
Both bits set to 1 gives IEEE-754 behavior. |
| | R | 19:18 | reserved | Reserved |
| | R | 17 | reserved | Reserved. |
| | RW | 16:15 | HFI | L1 instruction prefetch.
00: Disable
01: Enable (1 line)
10: Enable (2 lines)
11: Reserved
|
| | RW | 14:13 | HFD | L1 data cache prefetch.
Four levels are defined from disabled to aggressive. Implementation defines how to interpret these levels.
Number of loop iterations (0 to 3) that remain before the pipeline predicate should be set. |
| | R | 7:6 | reserved | Reserved. |
| | RW | 5 | FPINPF | Floating-point IEEE inexact sticky fag. Remains set until explicitly cleared. |
| | RW | 4 | FPUNFF | Floating-point IEEE underflow sticky flag. Remains set until explicitly cleared. |
| | RW | 3 | FPOVFF | Floating-point IEEE overflow sticky flag. Remains set until explicitly cleared. |
| | RW | 2 | FPDBZF | Floating-point IEEE divide-by-zero sticky flag. Remains set until explicitly cleared. |
| | RW | 1 | FPINVF | Floating-point IEEE invalid sticky flag. Remains set until explicitly cleared. |
| | RW | 0 | OVF | Sticky saturation overflow.
1: saturation occurred for :sat instructions
0: no saturation
Remains set until explicitly cleared. |
### Modifier registers
The following addressing modes use the modifier registers (M0 and M1):
#### Indirect auto-increment
In [indirect with auto-increment register](https://docs.qualcomm.com/doc/80-N2040-60/topic/memory.html#v79-prm-indirect-with-auto-increment-register)
addressing, the modifier registers store a signed 32-bit value that specifies the
increment or decrement value.
R2 = memw(R0++M1)
Copy to clipboard
Modifier registers used in indirect auto-increment addressing
| **Register** | **Name** | **Description** |
| --- | --- | --- |
| M0, M1 | Increment | Signed auto-increment value. |
#### Circular
In [circular addressing](https://docs.qualcomm.com/doc/80-N2040-60/topic/memory.html#v79-prm-circular-with-auto-increment-immediate), the modifier
registers store the circular buffer length and related “I” values.
R2 = memw(R2++#8:circ(M0))
Copy to clipboard
Modifier registers as used in circular addressing
| **Name** | **RW** | **Bits** | **Field** | **Description** |
| --- | --- | --- | --- | --- |
| M0, M1 | | 32 | | Circular buffer specifier. |
| | RW | 31:28 | I[10:7] | I value (MSB - see [cirular with auto-increment](https://docs.qualcomm.com/doc/80-N2040-60/topic/memory.html#v79-prm-circular-with-auto-increment-register)) |
| | RW | 27:24 | | 0x0 |
| | RW | 23:17 | I[6:0] | I value (LSB) |
| | RW | 16:0 | Length | Circular buffer length |
#### Bit-reversed
In [bit-reversed addressing](https://docs.qualcomm.com/doc/80-N2040-60/topic/memory.html#v79-prm-bit-reversed-with-auto-increment-register),
the modifier registers store a signed 32-bit value that specifies
the increment or decrement value.
R2 = memw(R0++M1:brev)
Copy to clipboard
Modifier registers as used in bit-reversed addressing
| **Register** | **Name** | **Description** |
| --- | --- | --- |
| M0, M1 | Increment | Signed auto-increment value. |
### Predicate registers
The predicate registers (P0 through P3) store the status results of
the scalar and vector compare instructions
([Conditional execution](https://docs.qualcomm.com/doc/80-N2040-60/topic/conditional-execution.html)).
For example:
P1 = cmp.eq(R2, R3) // Scalar compare
if (P1) jump end // Jump to address (conditional)
R8 = P1 // Get compare status (P1 only)
P3:0 = R4 // Set compare status (P0 through P3)
Copy to clipboard
Unlike the other control registers, the predicate registers are only 8 bits wide
because instructions return a maximum of eight status results. The register
quadruple (P3:0) accesses the four 8-bit predicates as a single 32-bit register.
P3:0 = R4 // Set compare status (P0 through P3)
Copy to clipboard
Predicate registers
| **Register** | **Bits** | **Description** |
| --- | --- | --- |
| P0, P1, P2, P3 | 8 | Compare status results. |
| P3:0 | 32 | Compare status results. |
| | 31:24 | P3 register |
| | 23:16 | P2 register |
| | 15:8 | P1 register |
| | 7:0 | P0 register |
### Circular start registers
The circular start registers (CS0 and CS1) store the start
address of a circular buffer in
[circular addressing](https://docs.qualcomm.com/doc/80-N2040-60/topic/memory.html#v79-prm-circular-with-auto-increment-immediate).
For example:
CS0 = R5 // Set circ start register
M0 = R7 // Set modifier register
R0 = memb(R2++#4:circ(M0)) // Load from circ buffer pointed
// to by CS0 with size/K vals in M0
Copy to clipboard
Circular start registers
| **Register** | **Name** | **Description** |
| --- | --- | --- |
| CS0, CS1 | Circular start | Circular buffer start address. |
### User general pointer register
The user general pointer (UGP) register is a general-purpose control
register. For example:
R9 = UGP // Get UGP
UGP = R3 // Set UGP
Copy to clipboard
User general pointer register
| **Register** | **Name** | **Description** |
| --- | --- | --- |
| UGP | User general pointer | General-purpose control register. |
### Global pointer
GP-relative addressing uses the global pointer (GP). For
example:
GP = R7 // Set GP
R2 = memw(GP+#200) // GP-relative load
Copy to clipboard
Global pointer register
| **Name** | **R/W** | **Bits** | **Field** | **Description** |
| --- | --- | --- | --- | --- |
| GP | | 32 | | Global pointer register |
| | R/W | 31:6 | GDP | [Global data pointer](https://docs.qualcomm.com/doc/80-N2040-60/topic/memory.html#v79-prm-global-pointer-relative). |
| | R | 5:0 | reserved | Reserved. |
### Cycle count registers
The cycle count registers UPCYCLELO and UPCYCLEHI together store a 64-bit
value containing the current number of processor cycles executed
since the Hexagon processor was last reset. For example:
R5 = UPCYCLEHI // Get cycle count (high)
R4 = UPCYCLELO // Get cycle count (low)
R5:4 = UPCYCLE // Get cycle count
Copy to clipboard
System software controls access to these registers. When access is disabled, read operations return 0.
Cycle count registers
| **Register** | **Name** | **Description** |
| --- | --- | --- |
| UPCYCLELO | Cycle count (low) | Processor cycle count (low 32 bits) |
| UPCYCLEHI | Cycle count (high) | Processor cycle count (high 32 bits) |
| UPCYCLE | Cycle count | Processor cycle count (64 bits) |
### Frame limit register
The FRAMELIMIT register stores the low address of the
memory area reserved for the software stack
([stack bounds checking](https://docs.qualcomm.com/doc/80-N2040-60/topic/software-stack.html#v79-prm-stack-bounds-checking)).
For example:
R9 = FRAMELIMIT // Get frame limit register
FRAMELIMIT = R3 // Set frame limit register
Copy to clipboard
Frame limit register
| **Register** | **Name** | **Description** |
| --- | --- | --- |
| FRAMELIMIT | Frame limit | Low address of software stack area. |
### Frame key register
The processor XORs the return address with the FRAMEKEY when pushing the address
on the software stack ([stack smashing protection](https://docs.qualcomm.com/doc/80-N2040-60/topic/software-stack.html#v79-prm-stack-smashing-protection)).
For example:
R2 = FRAMEKEY // Get frame key register
FRAMEKEY = R1 // Set frame key register
Copy to clipboard
Frame key register
| **Register** | **Name** | **Description** |
| --- | --- | --- |
| FRAMEKEY | Frame key | Key to scramble return addresses stored on the software stack. |
### Packet count registers
The packet count registers PKTCOUNTLO and PKTCOUNTHI store a 64-bit
value containing the current number of instruction packets executed
since a packet count register was last written. For example:
R9 = PKTCOUNTHI // Get packet count (high)
R8 = PKTCOUNTLO // Get packet count (low)
R9:8 = PKTCOUNT // Get packet count
Copy to clipboard
Packet counting can be configured to operate only in specific sets of
processor modes (for example, user mode only, or guest and monitor
modes only). USR[12:10]
[User status](https://docs.qualcomm.com/doc/80-N2040-60/topic/registers.html#user-status-register)
[register](https://docs.qualcomm.com/doc/80-N2040-60/topic/registers.html#user-status-register) control the configuration for
each mode.
Packets with exceptions are not counted as committed packets.
System software controls access to these register. When access is disabled, read operations return 0.
When a value is written to a packet count register, the 64-bit packet
count value is incremented before the value is stored in the
register.
Packet count registers
| **Register** | **Name** | **Description** |
| --- | --- | --- |
| PKTCOUNTLO | Packet count (low) | Processor packet count (low 32 bits) |
| PKTCOUNTHI | Packet count (high) | Processor packet count (high 32 bits) |
| PKTCOUNT | Cycle count | Processor packet count (64 bits) |
### QTimer registers
The QTimer registers UTIMERLO and UTIMERHI provide access to the
QTimer global reference count value. The QTimer registers enable Hexagon
software to read the 64-bit time value without having to perform an
advanced high-performance bus (AHB) load. For example:
R5 = UTIMERHI // Get QTimer reference count (high)
R4 = UTIMERLO // Get QTimer reference count (low)
R5:4 = UTIMER // Get QTimer reference count
Copy to clipboard
These registers are read only and hardware automatically updates these
registers with the current QTimer value.
System software controls access to these registers. When access is disabled, read operations return 0.
QTimer registers
| **Register** | **Name** | **Description** |
| --- | --- | --- |
| UTIMERLO | QTimer (low) | QTimer global reference count (low 32 bits) |
| UTIMERHI | QTimer (high) | QTimer global reference count (high 32 bits) |
| UTIMER | QTimer | QTimer global reference count (64 bits) |
### UPMUCNT registers
The eight 32-bit read-only User PMU Count (UPMUCNT) registers count performance events. The counters increment
each time a selected event occurs and wrap-around on overflow. These registers have undefined
value on reset. SSR.PE enables access to the UPMUCNT registers.
UPMU counter registers
| **Register** | **Fields** | **Access** |
| --- | --- | --- |
| UPMUCNT0 | [31:0] PMU Counter 0 | Monitor CR map RW |
| UPMUCNT1 | [31:0] PMU Counter 1 | Monitor CR map RW |
| UPMUCNT2 | [31:0] PMU Counter 2 | Monitor CR map RW |
| UPMUCNT3 | [31:0] PMU Counter 3 | Monitor CR map RW |
| UPMUCNT4 | [31:0] PMU Counter 4 | Monitor CR map RW |
| UPMUCNT5 | [31:0] PMU Counter 5 | Monitor CR map RW |
| UPMUCNT6 | [31:0] PMU Counter 6 | Monitor CR map RW |
| UPMUCNT7 | [31:0] PMU Counter 7 | Monitor CR map RW |
Last Published: Jan 16, 2025
[Previous Topic
Revision history](https://docs.qualcomm.com/bundle/publicresource/80-N2040-60/topics/revision.md) [Next Topic
Instructions](https://docs.qualcomm.com/bundle/publicresource/80-N2040-60/topics/instructions.md)
Source: [https://docs.qualcomm.com/doc/80-N2040-60/topic/registers.html](https://docs.qualcomm.com/doc/80-N2040-60/topic/registers.html)