lhzx
Load Halfword and Zero Indexed - 7C 00 01 16
lhzx

Instruction Syntax

Mnemonic Format Flags
lhzx rD,rA,rB -

Instruction Encoding

0
1
1
1
1
1
D
D
D
D
D
A
A
A
A
A
B
B
B
B
B
0
1
0
0
0
1
0
1
1
1
/

Field Bits Description
Primary Opcode 0-5 011111 (0x1F)
rD 6-10 Destination register
rA 11-15 Source register A
rB 16-20 Source register B
XO 21-30 279 (Extended opcode)
Rc 31 Reserved (0)

Operation

if rA = 0 then EA ← (rB)
else EA ← (rA) + (rB)
rD ← 0x0000 || MEM(EA, 2)

A halfword (16 bits) is loaded from memory and placed in the low-order 16 bits of register rD. The upper 16 bits of rD are set to zero. The effective address is computed by adding the contents of registers rA and rB, or just rB if rA is 0.

Note: This indexed form is particularly useful for array access and pointer arithmetic with 16-bit data. As specified in the Iowa State PowerPC Assembly Quick Reference, this instruction performs rD ← M[rA + rB]₁₅..₀. If rA=0, it is treated as the value 0, not the contents of register r0.

Affected Registers

None - This instruction does not affect any condition register fields or XER register bits.

For more information on memory addressing see Section 2.1.6, "Effective Address Calculation," in the PowerPC Microprocessor Family: The Programming Environments manual.

Examples

Halfword Array Access

# Access 16-bit array element by index
lis r3, short_array@ha
addi r3, r3, short_array@l
li r4, 15               # Array index
slwi r5, r4, 1          # Multiply by 2 (sizeof(short))
lhzx r6, r3, r5         # Load short_array[15]

# Access with computed offset
li r7, 10               # Base index
li r8, 5                # Offset
add r9, r7, r8          # Combined index (15)
slwi r10, r9, 1         # Convert to byte offset
lhzx r11, r3, r10       # Load short_array[15]

Unicode String Character Access

# Access Unicode character at specific position
lis r3, unicode_text@ha
addi r3, r3, unicode_text@l
lwz r4, char_index(r0)  # Load character index
slwi r5, r4, 1          # Convert to byte offset (2 bytes per char)
lhzx r6, r3, r5         # Load Unicode character

# Check Unicode character ranges
cmpwi r6, 0x0020        # Check for space
beq found_space
cmpwi r6, 0x0041        # Check for 'A'
blt not_uppercase
cmpwi r6, 0x005A        # Check for 'Z'
ble is_uppercase

# Check for lowercase
cmpwi r6, 0x0061        # Check for 'a'
blt not_lowercase
cmpwi r6, 0x007A        # Check for 'z'
ble is_lowercase

# Check for accented characters
cmpwi r6, 0x00C0        # Start of Latin-1 supplement
bge accented_character

b regular_character

found_space:
    bl handle_space
    b char_done

is_uppercase:
    # Convert to lowercase
    addi r7, r6, 32     # Add 32 to convert to lowercase
    slwi r8, r4, 1      # Recalculate offset
    sthx r7, r3, r8     # Store back converted character
    b char_done

is_lowercase:
    # Convert to uppercase  
    subi r7, r6, 32     # Subtract 32 to convert to uppercase
    slwi r8, r4, 1      # Recalculate offset
    sthx r7, r3, r8     # Store back converted character
    b char_done

accented_character:
not_lowercase:
not_uppercase:
regular_character:
char_done:

Image Pixel Manipulation

# Access 16-bit pixels (RGB565) in 2D image
lis r3, image_buffer@ha
addi r3, r3, image_buffer@l
lwz r4, image_width(r0)
li r5, 200              # Y coordinate
li r6, 150              # X coordinate

# Calculate pixel offset: (y * width + x) * 2
mullw r7, r5, r4        # y * width
add r8, r7, r6          # + x coordinate
slwi r9, r8, 1          # * 2 bytes per pixel
lhzx r10, r3, r9        # Load RGB565 pixel

# Extract RGB components
rlwinm r11, r10, 27, 27, 31 # Extract red (bits 11-15)
rlwinm r12, r10, 21, 26, 31 # Extract green (bits 5-10)
rlwinm r13, r10, 16, 27, 31 # Extract blue (bits 0-4)

# Apply color transformation (increase red component)
addi r11, r11, 4        # Increase red
cmpwi r11, 31           # Check maximum (5-bit)
ble red_ok
li r11, 31              # Clamp to maximum

red_ok:
# Reconstruct RGB565 value
slwi r14, r11, 11       # Red to bits 11-15
slwi r15, r12, 5        # Green to bits 5-10
or r16, r14, r15        # Combine red and green
or r17, r16, r13        # Add blue

# Store modified pixel back
sthx r17, r3, r9        # Store to image buffer

Audio Sample Buffer Access

# Access 16-bit audio samples in stereo buffer
lis r3, audio_buffer@ha
addi r3, r3, audio_buffer@l
lwz r4, sample_index(r0) # Current sample position
li r5, 2                # Stereo (2 channels)

# Load left channel sample
mullw r6, r4, r5        # sample_index * 2 channels
slwi r7, r6, 1          # * 2 bytes per sample
lhzx r8, r3, r7         # Load left channel

# Load right channel sample  
addi r9, r7, 2          # Offset to right channel
lhzx r10, r3, r9        # Load right channel

# Convert unsigned to signed (if needed)
cmpwi r8, 32768         # Check left channel
blt left_positive
subi r8, r8, 65536      # Convert to signed

left_positive:
cmpwi r10, 32768        # Check right channel
blt right_positive
subi r10, r10, 65536    # Convert to signed

right_positive:
# Apply stereo effect (cross-mix)
add r11, r8, r10        # Sum channels
srwi r11, r11, 1        # Average
sub r12, r8, r10        # Difference
srwi r12, r12, 2        # Reduce difference

# Create new stereo samples
add r13, r11, r12       # New left = avg + diff/4
sub r14, r11, r12       # New right = avg - diff/4

# Convert back to unsigned and store
cmpwi r13, 0
bge left_unsigned
addi r13, r13, 65536

left_unsigned:
cmpwi r14, 0
bge right_unsigned
addi r14, r14, 65536

right_unsigned:
# Store processed samples
sthx r13, r3, r7        # Store left channel
sthx r14, r3, r9        # Store right channel

Lookup Table Operations

# Use indexed addressing for table lookups
lis r3, lookup_table@ha
addi r3, r3, lookup_table@l
lbz r4, input_byte(r0)  # Load input value (0-255)

# Lookup table contains 16-bit values
slwi r5, r4, 1          # Convert to halfword offset
lhzx r6, r3, r5         # Load lookup_table[input_byte]

# Example: sine lookup table for fixed-point values
# Table contains 256 entries of 16-bit sine values (0-360 degrees)
# Input: angle in degrees (0-255 maps to 0-360 degrees)
lis r7, sine_table@ha
addi r7, r7, sine_table@l
lbz r8, angle_degrees(r0)
slwi r9, r8, 1          # Convert to byte offset
lhzx r10, r7, r9        # Load sine value (fixed-point)

# Use sine value for rotation calculation
lwz r11, radius(r0)     # Load radius
mullw r12, r10, r11     # radius * sin(angle)
srwi r13, r12, 8        # Scale down (assuming 8.8 fixed point)

# Similarly for cosine
lis r14, cosine_table@ha
addi r14, r14, cosine_table@l
lhzx r15, r14, r9       # Load cosine value
mullw r16, r15, r11     # radius * cos(angle)
srwi r17, r16, 8        # Scale down

Network Protocol Processing

# Parse network packet with indexed field access
lis r3, packet_data@ha
addi r3, r3, packet_data@l
li r4, 0                # Field index

# Ethernet header field offsets (in halfwords)
field_offsets:
    .short 6, 8, 12     # dest_mac, src_mac, ethertype offsets

parse_ethernet:
    # Load destination MAC (first 3 halfwords)
    slwi r5, r4, 1      # Convert index to byte offset
    lhzx r6, r3, r5     # Load dest_mac[0]
    addi r4, r4, 1
    slwi r5, r4, 1
    lhzx r7, r3, r5     # Load dest_mac[1]
    addi r4, r4, 1
    slwi r5, r4, 1
    lhzx r8, r3, r5     # Load dest_mac[2]

    # Skip source MAC (next 3 halfwords)
    addi r4, r4, 4      # Skip to ethertype

    # Load EtherType
    slwi r5, r4, 1
    lhzx r9, r3, r5     # Load EtherType

    # Check EtherType and branch to appropriate handler
    cmpwi r9, 0x0800    # IPv4
    beq parse_ipv4
    cmpwi r9, 0x86DD    # IPv6
    beq parse_ipv6
    cmpwi r9, 0x0806    # ARP
    beq parse_arp

parse_ipv4:
    # IPv4 header starts after Ethernet header (14 bytes = 7 halfwords)
    addi r4, r4, 1      # Move past EtherType
    
    # Load IP header fields (each halfword)
    slwi r5, r4, 1
    lhzx r10, r3, r5    # Version/IHL + TOS
    addi r4, r4, 1
    slwi r5, r4, 1
    lhzx r11, r3, r5    # Total Length
    addi r4, r4, 1
    slwi r5, r4, 1
    lhzx r12, r3, r5    # Identification

    # Continue processing IPv4 header...
    b packet_done

parse_ipv6:
    # Process IPv6 packet
    b packet_done

parse_arp:
    # Process ARP packet
    b packet_done

packet_done:

Game Data Structure Access

# Access game object properties using indexed addressing
lis r3, game_objects@ha
addi r3, r3, game_objects@l
lwz r4, object_id(r0)   # Load object ID to access
li r5, 32               # sizeof(GameObject) in bytes

# Calculate object address
mullw r6, r4, r5        # object_id * sizeof(GameObject)
add r7, r3, r6          # Base address of object

# GameObject structure (offsets in bytes):
# 0-1: health (halfword)
# 2-3: mana (halfword)  
# 4-5: x_position (halfword)
# 6-7: y_position (halfword)
# 8-9: sprite_id (halfword)
# 10-11: status_flags (halfword)

# Load object properties using indexed access
li r8, 0
lhzx r9, r7, r8         # Load health

li r8, 2
lhzx r10, r7, r8        # Load mana

li r8, 4
lhzx r11, r7, r8        # Load x_position

li r8, 6
lhzx r12, r7, r8        # Load y_position

li r8, 8
lhzx r13, r7, r8        # Load sprite_id

li r8, 10
lhzx r14, r7, r8        # Load status_flags

# Check if object is alive
cmpwi r9, 0             # Check health
beq object_dead

# Check status flags
andi. r15, r14, 0x0001  # Check active flag
beq object_inactive

andi. r15, r14, 0x0002  # Check visible flag
beq object_invisible

# Object is alive, active, and visible - update position
lwz r16, velocity_x(r0)
lwz r17, velocity_y(r0)

add r18, r11, r16       # new_x = x + velocity_x
add r19, r12, r17       # new_y = y + velocity_y

# Bounds checking
cmpwi r18, 0
bge x_positive
li r18, 0               # Clamp to left edge

x_positive:
lwz r20, screen_width(r0)
cmpw r18, r20
ble x_in_bounds
mr r18, r20             # Clamp to right edge

x_in_bounds:
cmpwi r19, 0
bge y_positive
li r19, 0               # Clamp to top edge

y_positive:
lwz r21, screen_height(r0)
cmpw r19, r21
ble y_in_bounds
mr r19, r21             # Clamp to bottom edge

y_in_bounds:
# Store updated position
li r8, 4
sthx r18, r7, r8        # Store new x_position
li r8, 6
sthx r19, r7, r8        # Store new y_position

object_dead:
object_inactive:
object_invisible:

Digital Signal Processing

# Process 16-bit audio samples with indexed FIR filter
lis r3, input_samples@ha
addi r3, r3, input_samples@l
lis r4, filter_coeffs@ha
addi r4, r4, filter_coeffs@l
lis r5, output_samples@ha
addi r5, r5, output_samples@l
lwz r6, num_samples(r0)     # Number of samples to process
lwz r7, filter_taps(r0)     # Number of filter taps
li r8, 0                    # Current sample index

filter_loop:
    cmpw r8, r6             # Check if done
    bge filtering_done
    
    li r9, 0                # Accumulator
    li r10, 0               # Tap index
    
tap_loop:
    cmpw r10, r7            # Check if done with taps
    bge tap_done
    
    # Calculate sample index for this tap
    sub r11, r8, r10        # sample_index - tap_index
    cmpwi r11, 0            # Check bounds
    blt skip_tap            # Skip if before start
    
    # Load input sample and filter coefficient
    slwi r12, r11, 1        # Convert to byte offset
    lhzx r13, r3, r12       # Load input sample
    
    slwi r14, r10, 1        # Convert tap to byte offset
    lhzx r15, r4, r14       # Load filter coefficient
    
    # Convert samples to signed if needed
    cmpwi r13, 32768
    blt sample_signed
    subi r13, r13, 65536    # Convert to signed
    
sample_signed:
    cmpwi r15, 32768
    blt coeff_signed
    subi r15, r15, 65536    # Convert to signed
    
coeff_signed:
    # Multiply and accumulate
    mullw r16, r13, r15     # sample * coefficient
    add r9, r9, r16         # accumulate
    
skip_tap:
    addi r10, r10, 1        # Next tap
    b tap_loop

tap_done:
    # Scale result (assuming coefficients are scaled)
    srwi r17, r9, 8         # Scale down by 256
    
    # Clamp to 16-bit range
    lis r18, 0x7FFF         # Maximum positive
    ori r18, r18, 0xFFFF
    cmpw r17, r18
    ble check_min
    mr r17, r18             # Clamp to max
    b store_result
    
check_min:
    lis r19, 0x8000         # Maximum negative
    cmpw r17, r19
    bge store_result
    mr r17, r19             # Clamp to min
    
store_result:
    # Convert back to unsigned for storage
    cmpwi r17, 0
    bge result_unsigned
    addi r17, r17, 65536    # Convert to unsigned
    
result_unsigned:
    # Store filtered sample
    slwi r20, r8, 1         # Convert index to byte offset
    sthx r17, r5, r20       # Store to output array
    
    addi r8, r8, 1          # Next sample
    b filter_loop

filtering_done:

Related Instructions

lhz, lhzu, lhzux, sthx, lbzx, lwzx

Back to Index