Assembly Language Reference

Hardware Overview

Registers

There are eight 16-bit general purpose registers, R0 through R7. A few instructions require dedicated use of R0 and R1.

There are four status flags zero (Z), negative (N), carry (C) and overflow (V).

There is a 16-bit program counter, PC. There is also a dedicated stack for storing the program counter, which allows for three levels of subroutine calls.

Pipeline Hazards

Due to internal pipelining and the desire to minimize register bypass logic, the instructions with dedicated use of R0 require some attention. R0 must not be loaded from memory or I/O by an instruction immediately preceding any instruction using R0 as a dedicated register. The affected instructions are:

  • ld Rd, [Rs+R0]
  • st Rd, [Rs+R0]
  • jmp R0
  • jsr R0

Violating this rule will cause the previous value of R0 to be used instead of the newly loaded one.

Memory Architecture

Memory Access to Instructions and Data

Data and instruction memory addressing is 16-bit oriented (an address increment of 1 corresponds to 2 bytes). Data words and instructions are mapped to the same memory address space:

  • CC13x0/CC26x0: 2 KB AUX RAM, address range 0x0000 through 0x03FF.
  • CC13x2/CC26x2 and CC13x4/CC26x4: 4 KB AUX RAM, address range 0x0000 through 0x07FF.

Data memory is accessed through load and store instructions, supporting direct, register indirect, register indirect with post-increment and register indexed modes. Only supported access size is 16-bit.

There is no access to memory other than the AUX RAM.

I/O Access to Module Registers

The Sensor Controller can access AUX domain module registers through the I/O address space. I/O addressing is 8-bit oriented (an address increment of 1 corresponds to 1 byte), except for the register aliasing space, that is addresses 0 to 255, where each entry maps to a 16-bit register.

I/O registers are accessed through input and output instructions, supporting:

  • Direct 1-bit accesses for 8 lsbs of a 16-bit register
  • Direct or register indirect 16-bit accesses

Unaligned 16-bit accesses are not supported.

There is no access to registers outside of the AUX domain. Also, there is no access to the AUX RAM and AUX_SCE module through the I/O address space.

Program Flow

General program flow is controlled by explicit use of jump/branch, conditional branch, subroutine call and return instructions. Execution can also be halted temporarily by using the wev0 or wev1 instructions to wait for the specified event before resuming execution. Preemption is in any case not supported.

The Sensor Controller enters standby mode by executing the sleep instruction. From standby mode, it can wake up and start execution from one of N vectors:

  • CC13x0/CC26x0: There are 4 vectors, 1 of which is user-programmable. Vectors and wake-up triggers are configured through AUX_EVCTL and AON_EVENT.
  • CC13x2/CC26x2 and CC13x4/CC26x4: There are 8 vectors, 3 of which are user-programmable. Vectors and wake-up triggers are configured through AUX_SYSIF.

The Sensor Controller firmware framework handles transition to standby mode and wake-up.

Zero-Overhead Loop

There is support for one level of zero-overhead loops using the loop instructions. This stores the addresses of the first and last instruction of the loop, and starts the loop counter.

Until the zero-overhead loop is completed, the last instruction of the loop will always trigger a branch to the first instruction of the loop (without delay). This means that the last instruction of the loop cannot be a Program Flow Control instruction (for example biob0 or jmp ).

Assembler Overview

Code Placement

There is no support for placing instructions at specific memory addresses. The first instruction in the firmware framework is placed at address 0, which is the first instruction of vector 0.

The SCIF driver source code generation in Sensor Controller Studio extracts the relevant addresses of task data structures and framework control data structures, so that these data structures are accessible from C code running on the System CPU. It creates matching “struct” typedefs to make such accesses seamless.

Labels

The addr and rel instruction operands shall be given as labels. To support short labels, sub-labels starting with “/” can be used.

someLabel:
                cmp     R7, #0
                bnz     /subLabel           ; Can use sub-label in the same context
                add     R7, #1
/subLabel:
                ...

anotherLabel:
                cmp     R7, #0
                jmp     someLabel/subLabel  ; Must expand /subLabel since it is in a different context

For task data structure members, three hierarchy levels are used: task / struct / member .

Immediate values

Immediate values can be given as expressions, using the following syntax:

<expr>          ::= '(' <expr> ' ' <op2> ' ' <expr> ')'
                |   '(' <op1> <expr> ')'
                |   '(' <expr> ')'
                |   <value>

<op2>           ::= '<' | '<=' | '==' | '!=' | '>' | '>=' | '/' | '*' | '+' | '-' | '%'
                |   '|' | '||' | '&' | '&&' | '^' | '<<' | '>>'

<op1>           ::= '-' |
                |   '~' | '!'

<value>         ::= label (for example someLabel/subLabel or anotherLabel)
                |   hexadecimal value (for example 0x12AB)
                |   decimal value (for example 14 or -42)

A small subset of the immediate values, simm and rel , are signed, and will be sign-extended to 16 bits. All other immediate values are unsigned.

Immediate Value Range and Value Masking

To allow larger than 16-bit intermediate values, expression calculation works on 32-bit signed integers.

The assembler does not automatically mask out most significant bits when calculating expressions for immediate value operands. It will instead generate an error “Immediate value out of range” if the value is too high or too low. Manual masking (using the & operator) is therefore required when using:

  • Negative values with unsigned immediate value operands
  • The ~ operator, which inverts all 32 bits in the expression calculation

Instruction Prefix

Some instructions with 8- or 10-bit immediate value may be extended to 16-bit immediate value by executing a prefix instruction, pfix , immediately before it. The prefix is valid for the next instruction only.

The last column below indicates which immediate value may be extended, if any.

The assembler adds prefix instructions automatically as needed, and detects immediate values that are invalid or out of range.

Instruction Set

Instruction Timing

CC13x0/CC26x0: The Sensor Controller runs at 24 MHz in active mode.

CC13x2/CC26x2 and CC13x4/CC26x4: The Sensor Controller runs at 24 MHz or 2 MHz in active mode (statically configurable). The Sensor Controller runs at 2 MHz in low-power mode.

All Sensor Controller instructions use 2 clock cycles, with the following exceptions:

  • I/O accesses ( in , out , iobset , iobclr and iobtst ) to AUX_TIMER2 registers (CC13x2/CC26x2 and CC13x4/CC26x4 only), AUX_ADI4 registers and AUX_DDI0_OSC registers, which go through multi-cycle interfaces
  • CC13x2/CC26x2 and CC13x4/CC26x4 only: I/O accesses ( in , out , iobset , iobclr and iobtst ) to certain registers in AUX_SPIM and AUX_MAC will block until ongoing module activities have completed
  • Power management instructions ( wev0 , wev1 and sleep ), which are used to wait for event signals

The Sensor Controller has priority over System CPU and uDMA when accessing memory and module registers. ADI and DDI accesses can however be delayed due to ongoing System CPU accesses.

Status Bit Updates

In the tables below:

  • x indicates that the instruction updates the status bit
  • 0 indicates that the instruction always clears the status bit
  • - indicates that the instruction does not update the status bit

The status bits are updated as follows:

  • Z (zero) is set if the result is 0
  • N (negative) is equal to the most significant bit of the result
  • C (carry) update depends on the instruction type:
    • I/O bit access: Set according to the value of the tested bit
    • Logical operations: Always cleared.
    • Arithmetic operations: Set according to a carry or borrow out of the most significant bit of the result
    • Shift operations: Set according to the last bit shifted out, being it through the most significant or least significant bit. Set to 0 for shift by 0 bits.
  • V (overflow) update depends on the instruction type:
    • Logical operations: Always cleared
    • Arithmetic operations: Set if arithmetic signed overflow occurs, cleared otherwise
    • Shift operations: Always cleared

Memory Word Access

Syntax Description Operation Z N C V Encoding [15:0] Prefix
ld Rd, [#addr] Load direct Rd = mem[addr]         0ddd.10aa.aaaa.aaaa addr
ld Rd, [Rs] Load indirect Rd = mem[Rs]         1ddd.1111.0000.1sss  
ld Rd, [Rs++] Load indirect, post-increment Rd = mem[Rs], Rs++         1ddd.1111.0001.0sss  
ld Rd, [Rs+R0) Load indexed Rd = mem[Rs+R0]         1ddd.1111.0001.1sss  
st Rd, [#addr] Store direct mem[addr] = Rd         0ddd.11aa.aaaa.aaaa addr
st Rd, [Rs] Store indirect mem[Rs] = Rd         1ddd.1111.0010.1sss  
st Rd, [Rs++] Store indirect, post-increment mem[Rs] = Rd, Rs++         1ddd.1111.0011.0sss  
st Rd, [Rs+R0] Store indexed mem[Rs+R0] = Rd         1ddd.1111.0011.1sss  

I/O Word Access

Syntax Description Operation Z N C V Encoding [15:0] Prefix
in Rd, [#addr] Input direct Rd = reg[addr]         1ddd.1001.aaaa.aaaa addr
in Rd, [Rs] Input indirect Rd = reg[Rs]         1ddd.1111.0000.0sss  
out Rd, [#addr] Output direct reg[addr] = Rd         1ddd.1011.aaaa.aaaa addr
out Rd, [Rs] Output indirect reg[Rs] = Rd         1ddd.1111.0010.0sss  

I/O Bit Access

Syntax Description Operation Z N C V Encoding [15:0] Prefix
iobclr #imm, [#addr] I/O bit clear direct reg[addr] &= ~2^imm         010i.01ii.aaaa.aaaa addr
iobset #imm, [#addr] I/O bit set direct reg[addr] |= 2^imm         011i.01ii.aaaa.aaaa addr
iobtst #imm, [#addr] I/O bit test direct reg[addr] & 2^imm     x   001i.01ii.aaaa.aaaa addr

Register Access

Syntax Description Operation Z N C V Encoding [15:0] Prefix
ld Rd, #simm Load immediate Rd = simm         0ddd.00ii.iiii.iiii simm
ld Rd, Rs Load register Rd = Rs         1ddd.1101.0100.0sss  

Logical Operations

Syntax Description Operation Z N C V Encoding [15:0] Prefix
and Rd, #imm AND immediate Rd &= imm x x 0 0 1ddd.0000.iiii.iiii imm
or Rd, #imm OR immediate Rd |= imm x x 0 0 1ddd.0010.iiii.iiii imm
xor Rd, #imm XOR immediate Rd ^= imm x x 0 0 1ddd.0100.iiii.iiii imm
tst Rd, #imm Test immediate Rd & imm x x 0 0 1ddd.1100.iiii.iiii imm
and Rd, Rs AND register Rd &= Rs x x 0 0 1ddd.1101.0000.0sss  
or Rd, Rs OR register Rd |= Rs x x 0 0 1ddd.1101.0000.1sss  
xor Rd, Rs XOR register Rd ^= Rs x x 0 0 1ddd.1101.0001.0sss  
tst Rd, Rs Test register Rd & Rs x x 0 0 1ddd.1101.0011.0sss  
inv Rd Invert register Rd = ~Rd x x 0 0 1ddd.1101.1001.0010  

Arithmetic Operations

Syntax Description Operation Z N C V Encoding [15:0] Prefix
add Rd, #simm Add immediate Rd += simm x x x x 1ddd.1000.iiii.iiii simm
cmp Rd, #simm Compare immediate Rd - simm x x x x 1ddd.1010.iiii.iiii simm
sub Rd, Rs Subtract register Rd -= Rs x x x x 1ddd.1101.0001.1sss  
add Rd, Rs Add register Rd += Rs x x x x 1ddd.1101.0010.0sss  
cmp Rd, Rs Compare register Rd - Rs x x x x 1ddd.1101.0010.1sss  
subr Rd, Rs Subtract reverse register Rd = Rs - Rd x x x x 1ddd.1101.0011.1sss  
abs Rd Absolute register Rd = (Rd >= 0) ? Rd : -Rd x x x x 1ddd.1101.1001.0000  
neg Rd Negate register Rd = -Rd x x x x 1ddd.1101.1001.0001  

Shift Operations

Syntax Description Operation Z N C V Encoding [15:0] Prefix
lsl Rd, Rs Logical shift left register Rd <<= Rs[3:0] x x x 0 1ddd.1101.1000.0sss  
lsr Rd, Rs Logical shift right register Rd >>= Rs[3:0] x x x 0 1ddd.1101.1000.1sss  
asr Rd, Rs Arithmetic shift right register Rd >>= Rs[3:0], preserve sign x x x 0 1ddd.1101.1001.1sss  
lsl Rd, #imm Logical shift left immediate* Rd <<= imm x x x 0 1ddd.1101.1010.0iii  
lsr Rd, #imm Logical shift right immediate* Rd >>= imm x x x 0 1ddd.1101.1010.1iii  
asr Rd, #imm Arithmetic shift right immediate* Rd >>= imm, preserve sign x x x 0 1ddd.1101.1011.1iii  

* Shift immediate can be 1 to 8 bits, where imm = 0 corresponds to 8 bits.

Program Flow Control

Syntax Description Operation Z N C V Encoding [15:0] Prefix
jmp addr Jump direct pc = addr         0000.01aa.aaaa.aaaa addr
jsr addr Jump subroutine direct push(stack, pc + 1), pc = addr         0001.01aa.aaaa.aaaa addr
jmp R0 Jump indirect pc = R0         1000.1101.1011.0111  
jsr R0 Jump subroutine indirect push(stack, pc + 1), pc = R0         1001.1101.1011.0111  
rts Return subroutine pc = pop(stack)         1010.1101.1011.0111  
bra rel Branch relative pc = pc + 1 + rel         1000.1110.rrrr.rrrr  
b<cc> rel Branch relative if condition is met if (cc) pc = pc + 1 + rel         1ccc.c110.rrrr.rrrr  
bev0 #ev, rel Branch if event 0 if (!events[ev]) pc = pc + 1 + rel         1eee.0001.rrrr.rrrr  
bev1 #ev, rel Branch if event 1 if (events[ev]) pc = pc + 1 + rel         1eee.0011.rrrr.rrrr  

For all other instructions, and also when not taking a conditional branch, the program counter is incremented by 1: pc = pc + 1.

Conditions

Syntax <cc> Description Condition Encoding [3:0]
gtu Greater than, unsigned !C & !Z 0010
geu / iob0 Greater or equal, unsigned / Tested I/O bit = 0 !C 0100
eq / z Equal / Zero Z 0110
novf Not overflow !V 1000
pos Positive !N 1010
ges Greater or equal, signed (N & V) | (!N & !V) 1100
gts Greater than, signed ((N & V) | (!N & !V)) & !Z 1110
leu Less or equal, unsigned C | Z 0011
ltu / iob1 Less than, unsigned / Tested I/O bit = 1 C 0101
neq / nz Not equal / Non-zero !Z 0111
ovf Overflow V 1001
neg Negative N 1011
lts Less than, signed (N & !V) | (!N & V) 1101
les Less or equal, signed (N & !V) | (!N & V) | Z 1111

Loop Flow Control

Syntax Description Operation Z N C V Encoding [15:0] Prefix
loop R1, rel Loop register, n = 1..255* lc = LSB(R1), ls = pc + 1, le = pc + rel         1000.0101.rrrr.rrrr  
loop #n, rel Loop immediate, n = 2^x (x = 1..7)* lc = n, ls = pc + 1, le = pc + rel         1nnn.0101.rrrr.rrrr  

* The assembler offsets the end-of-loop label so it can be placed after the last instruction of the loop.

Note that rel is signed, as for the relative branch instructions.

Power Management

Syntax Description Operation Z N C V Encoding [15:0] Prefix
wev0 #ev Wait for event 0 Stop until events[ev] == 0         1eee.1101.1011.0000  
wev1 #ev Wait for event 1 Stop until events[ev] == 1         1eee.1101.1011.0001  
sleep Sleep Stop until wakeup, then pc = 2 * vector         1011.1101.1011.0111  

Miscellaneous

Syntax Description Operation Z N C V Encoding [15:0] Prefix
nop No operation R7 = R7 (no effect)         1111.1101.0100.0111  
pfix #imm Prefix* Use prefix on next instruction         1000.0110.iiii.iiii  
dw #imm Data word Inserts 16-bit immediate data value         iiii.iiii.iiii.iiii  

* The prefix instruction is inserted automatically by the assembler where needed. Do not insert this instruction manually.