Instruction Syntax
Mnemonic | Format | Flags |
lhzx | rD,rA,rB | - |
Instruction Encoding
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: