Skip to content

Experiment 2: Data Processing and Memory Operations ​

Complete Lab Manual

For the complete experiment including learning objectives, theoretical background, and detailed explanations, download the PDF manual: Download Experiment 2 PDF

Learning Objectives ​

After completing this experiment, you will be able to:

  • Perform arithmetic, logical, and shift/rotate operations using data-processing instructions (including Operand2 with the barrel shifter).
  • Move data between registers and memory using load/store instructions with immediate, register-offset, and pre-/post-indexed addressing modes.
  • Declare and initialize data objects (arrays, strings, buffers) with assembler directives, and use pointers to access and modify them.
  • Trace how instructions affect registers and xPSR flags using the Keil uVision5 debugger (breakpoints, single-step, register/memory views).

Experiment Overview ​

This experiment develops fluency with the ARM Cortex-M4 instruction set for data manipulation and memory access. You will practice arithmetic, logical, and shift/rotate instructions, apply various addressing modes for load/store operations, and define data structures with assembler directives. By the end of this lab, you will be able to write assembly routines that perform register-level computation and structured memory access, providing the foundation for flow control and procedure calls in later experiments.

Theoretical Background ​

As mentioned in Experiment 1, assembly instructions are split into three main categories: data processing, load/store, and branch instructions. This experiment focuses on data processing instructions, load/store instructions and their addressing modes. Branch instructions and flow control will be covered in the next experiment.

Data Processing Instructions ​

Data processing instructions perform arithmetic and logical operations on data stored in registers. They can also manipulate the condition flags in the xPSR based on the results of the operations. Common data processing instructions take the following form:

{LABEL}   OPCODE{<cond>}{S} Rd, Rn, Operand2

where:

  • LABEL: optional label for branching.
  • OPCODE: the operation to be performed (e.g., ADD, SUB, AND, ORR).
  • <cond>: optional condition code that predicates execution.
  • S: optional suffix indicating whether to update the condition flags.
  • Rd: destination register where the result is stored.
  • Rn: first operand register.
  • Operand2: second operand, which can be an immediate value limited to 8 bits, a register, or a barrel shifter operation.

Arithmetic Instructions ​

Arithmetic instructions perform basic mathematical operations. Some common arithmetic instructions include addition, subtraction, multiplication, and their variants.

Instr.SyntaxOperationDescription
ADDADD{S} Rd, Rn, Operand2Rd←Rn+Operand2Operand2 may be a register, an immediate, or a shifted register.
ADCADC{S} Rd, Rn, Operand2Rd←Rn+Operand2+CAdds carry-in C.
SUBSUB{S} Rd, Rn, Operand2Rd←Rnβˆ’Operand2Standard subtraction.
SBCSBC{S} Rd, Rn, Operand2Rd←Rnβˆ’Operand2βˆ’C―Subtract with carry. If carry flag is clear, result is reduced by one. Used for multiword arithmetic.
RSBRSB{S} Rd, Rn, Operand2Rd←Operand2βˆ’RnReverse subtract.
MULMUL{S} Rd, Rn, RmRd←(RnΓ—Rm)[31:0]32Γ—32 β†’ low 32 bits.
MLAMLA Rd, Rn, Rm, RaRd←(RnΓ—Rm)+RaMultiply-accumulate.
MLSMLS Rd, Rn, Rm, RaRd←Raβˆ’(RnΓ—Rm)Multiply-subtract.
UMULLUMULL RdLo, RdHi, Rn, Rm{RdHi,RdLo}←RnΓ—RmUnsigned 32Γ—32 β†’ 64-bit product.
SMULLSMULL RdLo, RdHi, Rn, Rm{RdHi,RdLo}←RnΓ—RmSigned 32Γ—32 β†’ 64-bit product.
UDIVUDIV Rd, Rn, RmRd←RnΓ·RmUnsigned division.
SDIVSDIV Rd, Rn, RmRd←RnΓ·RmSigned division.

Note: C denotes the carry flag in xPSR.

Logical and Move Instructions ​

Logical instructions perform bitwise operations on data, while move instructions transfer data between registers or load immediate values.

Instr.SyntaxOperationDescription
ANDAND Rd, Rn, Operand2Rd←Rn&Operand2Bitwise AND.
ORRORR Rd, Rn, Operand2$Rd \leftarrow Rn ,, Operand2$
EOREOR Rd, Rn, Operand2Rd←RnβŠ•Operand2Bitwise XOR.
BICBIC Rd, Rn, Operand2Rd←Rn&Β¬Operand2Bit clear.
MVNMVN Rd, Operand2Rd←¬Operand2Bitwise NOT of operand.
MOVMOV Rd, Operand2Rd←Operand2Register or immediate move.
MOVWMOVW Rd, #imm16Rd[15:0]←imm16Write low halfword.
MOVTMOVT Rd, #imm16Rd[31:16]←imm16Write high halfword (low preserved).

In this experiment, you will work with bitwise logical instructions to manipulate individual bits within registers. Such operations are fundamental in microcontroller programming, where control and status registers often contain multiple configuration fields packed into a single 32-bit word.

Set and Clear Bits:

  • ORR Rd, Rn, #mask: Sets bits in Rd where the corresponding bits in mask are 1.
  • BIC Rd, Rn, #mask: Clears bits in Rd where the corresponding bits in mask are 1.
  • EOR Rd, Rn, #mask: Toggles bits in Rd where the corresponding bits in mask are 1.

BIC is essentially an AND operation with the negated mask, i.e., BIC Rd, Rn, #mask is equivalent to AND Rd, Rn, #~mask.

Check Bits:

  • AND Rd, Rn, #mask: Isolates bits in Rn where the corresponding bits in mask are 1.
  • Use CMP Rd, #0 to determine if the result is zero.
  • Alternatively, use TST Rn, #mask, which performs the AND operation and updates the condition flags without storing the result.

Shift and Rotate Instructions ​

Instr.SyntaxOperationDescription
LSLLSL Rd, Rm, #sh|RsRd←Rmβ‰ͺshLogical left shift by immediate or by register.
LSRLSR Rd, Rm, #sh|RsRd←Rm≫shLogical right shift (zero fill).
ASRASR Rd, Rm, #sh|RsRd←Rm≫shArithmetic right shift (sign fill).
RORROR Rd, Rm, #sh|RsRd←ROR(Rm,sh)Rotate right by immediate or by register.
RRXRRX Rd, RmRd←RORC(Rm,1)Rotate right 1 bit through carry.

Note: Shift amount can be an immediate #sh (0–31) or a register Rs (low 8 bits used).

Not all shift/rotate instructions are explicitly present in the ARMv7-M ISA. For example, there is no ROL (rotate left) or ASL (arithmetic shift left) instruction, as these operations can be achieved using existing shift instructions.

Barrel Shifter ​

The barrel shifter is a hardware feature that allows for efficient shifting and rotating of register values as part of data processing instructions. It can perform operations such as logical shifts (left or right), arithmetic shifts, and rotations on the second operand (Operand2) before it is used in the instruction without wasting extra instructions or cycles.

Examples of barrel shifter usage:

asm
    ADD    R0, R2, R1, LSL #2    ; R0 = R2 + (R1 << 2) using barrel shifter
    SUB    R3, R4, R5, LSR #1    ; R3 = R4 - (R5 >> 1) using barrel shifter
    ORR    R6, R7, R8, ROR #3    ; R6 = R7 | (R8 rotated right by 3)

Load and Store Instructions ​

Since the ARM Cortex-M4 follows the RISC design philosophy, it uses a load/store architecture. This means that arithmetic and logical instructions operate only on registers. Any data in memory must first be loaded into a register before processing, and results must be stored back to memory if they need to be preserved.

Instr.Syntax ExampleDescription
LDR / STRLDR/STR Rt, [Rn, #off]Load/store a 32-bit word.
LDRB / STRBLDRB/STRB Rt, [Rn, #off]Load/store an 8-bit byte.
LDRH / STRHLDRH/STRH Rt, [Rn, #off]Load/store a 16-bit halfword.
LDRSB / LDRSHLDRSB/LDRSH Rt, [Rn, #off]Load signed byte/halfword and sign-extend to 32 bits.
LDRD / STRDLDRD/STRD Rt, Rt2, [Rn, #off]Load/store a 64-bit doubleword (two registers).

Declaring Data in Memory ​

Data in assembly is defined using assembler directives that reserve and optionally initialize memory. Common directives include DCD, DCW, and DCB, which define words, halfwords, and bytes, respectively.

  • DCD β€” Define Constant Word (32 bits per element)
  • DCW β€” Define Constant Halfword (16 bits per element)
  • DCB β€” Define Constant Byte (8 bits per element)
  • SPACE β€” Reserve uninitialized memory (in bytes)
  • FILL β€” Fill memory with a specified value for a given length
asm
            AREA    CONSTANTS, DATA, READONLY
NUMBERS     DCD     10, 20, 30, 40        ; array of 32-bit integers
BYTES       DCB     1, 2, 3, 4            ; array of bytes
TEXT        DCB     "HELLO",0             ; null-terminated ASCII string
            AREA    MYDATA, DATA, READWRITE
BUFFER      SPACE   64                    ; reserve 64 bytes (uninitialized)
PATTERN     FILL    0xFF, 64              ; fill 64 bytes with 0xFF

Each label marks the starting address of a data object in memory.

Understanding Pointer Declarations ​

The directive YPTR DCD YVAL reserves a 32-bit word at the label YPTR and initializes it with the address of YVAL. In other words, YPTR acts as a pointer variable that holds the address of another variable (YVAL). Executing LDR Rn, YPTR loads the 32-bit contents stored at YPTRβ€”that is, the address of YVALβ€”into Rn.

AddressLabelContents
0x2000XVAL0x12345678
0x2004YPTR0x2008 (address of YVAL)
0x2008YVAL0x00000000

Loading Addresses and Values: LDR, LDR =, and ADR ​

  • LDR Rn, label: Loads the 32-bit value stored at the memory address identified by label into register Rn.
  • LDR Rn, =label: Loads the address of label into Rn, rather than the data stored at that address.
  • ADR Rn, label: Loads the address of label into Rn by computing it relative to the current program counter. This method requires no literal pool or memory access but only works for nearby addresses (about Β±4 KB in Thumb mode).

Addressing Modes ​

Addressing modes define how the effective address or operand value is obtained by an instruction. The ARM Cortex-M4 supports several common addressing modes:

ModeSyntax ExampleDescription
ImmediateMOV R0, #10Operand is a constant value encoded in the instruction.
Register DirectMOV R0, R1Operand is taken directly from a register.
Register IndirectLDR R0, [R1]Register holds the address of the operand in memory.
Register OffsetLDR R0, [R1, R2]Effective address = base register + offset register.
Immediate OffsetLDR R0, [R1, #4]Effective address = base register + constant offset.
Pre-indexedLDR R0, [R1, #4]!Base updated first, then memory access.
Post-indexedLDR R0, [R1], #4Memory access first, then base register updated.
asm
; Immediate Offset
    LDR     R0, [R1, #4]     ; R0 = word at memory[R1 + 4]
; Register Offset
    LDR     R0, [R1, R2]    ; R0 = word at memory[R1 + R2]
; Pre-indexed
    LDR     R0, [R1, #4]!    ; R1 = R1 + 4, then load R0 = [R1]
; Post-indexed
    LDR     R0, [R1], #4     ; load R0 = [R1], then R1 = R1 + 4