Instruction Syntax
Mnemonic | Format | Flags |
lha | rD,d(rA) | - |
Instruction Encoding
Field | Bits | Description |
Primary Opcode | 0-5 | 101010 (0x2A) |
rD | 6-10 | Destination register |
rA | 11-15 | Source register A |
d | 16-31 | 16-bit signed displacement |
Operation
if rA = 0 then EA ← EXTS(d) else EA ← (rA) + EXTS(d) rD ← EXTS(MEM(EA, 2))
A halfword (16 bits) is loaded from memory and sign-extended to 32 bits, then placed in register rD. The effective address is computed by adding the sign-extended displacement to the contents of register rA, or zero if rA is 0.
Note: Unlike lhz
which zero-extends, this instruction sign-extends the loaded halfword, preserving the sign for signed 16-bit values. This is essential for processing signed integer data such as audio samples, sensor readings, and signed array indices. If rA=0, it is treated as the value 0, not the contents of register r0.
Affected Registers
None (load instruction does not affect condition registers).
For more information on memory addressing see Section 2.1.6, "Effective Address Calculation," in the PowerPC Microprocessor Family: The Programming Environments manual.
Examples
Audio Processing - 16-bit Signed Samples
# Process signed 16-bit audio samples lis r3, audio_buffer@ha addi r3, r3, audio_buffer@l lwz r4, num_samples(r0) # Number of audio samples audio_processing_loop: lha r5, 0(r3) # Load signed 16-bit audio sample # Apply audio effects (sample is properly sign-extended) # Amplification: multiply by gain factor lwz r6, gain_factor(r0) # Load gain (fixed-point) mullw r7, r5, r6 # Apply gain srawi r8, r7, 8 # Scale back (assuming 8-bit fractional part) # Clipping to prevent overflow cmpwi r8, 32767 # Check upper bound ble check_lower_bound li r8, 32767 # Clip to maximum check_lower_bound: cmpwi r8, -32768 # Check lower bound bge store_sample li r8, -32768 # Clip to minimum store_sample: sth r8, 0(r3) # Store processed sample addi r3, r3, 2 # Next sample (2 bytes) subi r4, r4, 1 # Decrement counter cmpwi r4, 0 bne audio_processing_loop # Continue processing
Sensor Data Acquisition
# Read signed sensor values from ADC lis r3, sensor_readings@ha addi r3, r3, sensor_readings@l lwz r4, num_sensors(r0) # Number of sensors sensor_loop: lha r5, 0(r3) # Load signed sensor reading # Convert to engineering units # Value = (ADC_reading * scale_factor) + offset lwz r6, scale_factor(r0) # Load scale factor mullw r7, r5, r6 # Multiply by scale lwz r8, offset_value(r0) # Load offset add r9, r7, r8 # Add offset # Store calibrated value stw r9, calibrated_readings(r4) # Store in calibrated array addi r3, r3, 2 # Next sensor reading subi r4, r4, 1 # Decrement counter cmpwi r4, 0 bne sensor_loop # Continue processing
Graphics Coordinate Processing
# Process signed 2D coordinates lis r3, vertex_data@ha addi r3, r3, vertex_data@l lwz r4, num_vertices(r0) # Number of vertices vertex_loop: lha r5, 0(r3) # Load signed X coordinate lha r6, 2(r3) # Load signed Y coordinate # Transform coordinates (translation) lwz r7, viewport_x(r0) # Viewport X offset lwz r8, viewport_y(r0) # Viewport Y offset add r9, r5, r7 # Translate X add r10, r6, r8 # Translate Y # Clip to viewport bounds lwz r11, viewport_width(r0) lwz r12, viewport_height(r0) # Check X bounds cmpwi r9, 0 # Check lower bound bge check_x_upper li r9, 0 # Clip to 0 check_x_upper: cmpw r9, r11 # Check upper bound blt check_y_bounds mr r9, r11 # Clip to viewport width check_y_bounds: cmpwi r10, 0 # Check Y lower bound bge check_y_upper li r10, 0 # Clip to 0 check_y_upper: cmpw r10, r12 # Check Y upper bound blt store_vertex mr r10, r12 # Clip to viewport height store_vertex: sth r9, 0(r3) # Store transformed X sth r10, 2(r3) # Store transformed Y addi r3, r3, 4 # Next vertex (4 bytes = 2 halfwords) subi r4, r4, 1 # Decrement counter cmpwi r4, 0 bne vertex_loop # Continue processing
Digital Signal Processing - FIR Filter
# Implement FIR filter with signed coefficients and data lis r3, signal_input@ha addi r3, r3, signal_input@l lis r4, filter_coefficients@ha addi r4, r4, filter_coefficients@l lwz r5, filter_order(r0) # Number of filter taps lwz r6, signal_length(r0) # Number of input samples fir_filter_loop: li r7, 0 # Initialize accumulator mr r8, r5 # Filter tap counter mr r9, r3 # Input pointer for this sample mr r10, r4 # Coefficient pointer tap_loop: cmpwi r8, 0 # Check if done with taps beq sample_complete lha r11, 0(r9) # Load signed input sample lha r12, 0(r10) # Load signed filter coefficient # Multiply and accumulate: acc += input * coefficient mullw r13, r11, r12 # Multiply sample by coefficient add r7, r7, r13 # Accumulate subi r9, r9, 2 # Previous input sample addi r10, r10, 2 # Next coefficient subi r8, r8, 1 # Decrement tap counter b tap_loop # Continue filter taps sample_complete: # Scale result (assuming coefficients have fractional scaling) srawi r14, r7, 8 # Scale down (8-bit fractional part) # Store filtered output sth r14, filtered_output(r0) addi r3, r3, 2 # Next input sample subi r6, r6, 1 # Decrement sample counter cmpwi r6, 0 bne fir_filter_loop # Continue filtering
Data Compression - Delta Encoding
# Perform delta encoding on signed 16-bit data lis r3, raw_data@ha addi r3, r3, raw_data@l lis r4, delta_encoded@ha addi r4, r4, delta_encoded@l lwz r5, data_length(r0) # Number of data points # Store first value as-is (no delta) lha r6, 0(r3) # Load first value sth r6, 0(r4) # Store first value unchanged mr r7, r6 # Previous value for delta calculation addi r3, r3, 2 # Next input sample addi r4, r4, 2 # Next output position subi r5, r5, 1 # One less sample to process delta_encoding_loop: lha r8, 0(r3) # Load current signed sample # Calculate delta: delta = current - previous sub r9, r8, r7 # Calculate delta # Check if delta fits in 16-bit signed range cmpwi r9, 32767 # Check upper bound ble check_delta_lower # Delta too large - store full value with escape code li r10, 0x8000 # Escape code for full value sth r10, 0(r4) # Store escape code addi r4, r4, 2 # Next output position sth r8, 0(r4) # Store full value b delta_stored check_delta_lower: cmpwi r9, -32768 # Check lower bound bge store_delta # Delta too small - store full value with escape code li r10, 0x8000 # Escape code for full value sth r10, 0(r4) # Store escape code addi r4, r4, 2 # Next output position sth r8, 0(r4) # Store full value b delta_stored store_delta: sth r9, 0(r4) # Store delta value delta_stored: mr r7, r8 # Update previous value addi r3, r3, 2 # Next input sample addi r4, r4, 2 # Next output position subi r5, r5, 1 # Decrement counter cmpwi r5, 0 bne delta_encoding_loop # Continue encoding
Network Protocol - Signed Field Processing
# Process network packet with signed header fields lis r3, packet_header@ha addi r3, r3, packet_header@l # Custom protocol with signed fields lha r4, 0(r3) # Load signed packet type lha r5, 2(r3) # Load signed sequence number lha r6, 4(r3) # Load signed acknowledgment offset lha r7, 6(r3) # Load signed window size # Validate packet type cmpwi r4, -100 # Check minimum valid type blt invalid_packet cmpwi r4, 100 # Check maximum valid type bgt invalid_packet # Process sequence number wraparound lwz r8, expected_sequence(r0) # Load expected sequence sub r9, r5, r8 # Calculate sequence difference # Handle wraparound in signed arithmetic cmpwi r9, 16384 # Half of 16-bit range blt check_negative_wrap subi r9, r9, 65536 # Adjust for positive wraparound check_negative_wrap: cmpwi r9, -16384 # Negative half of range bgt sequence_ok addi r9, r9, 65536 # Adjust for negative wraparound sequence_ok: cmpwi r9, 0 # Check if in order bge packet_in_order # Handle out-of-order packet bl handle_out_of_order packet_in_order: # Process acknowledgment offset (signed relative to current position) lwz r10, current_ack_base(r0) add r11, r10, r6 # Calculate absolute acknowledgment # Validate acknowledgment range lwz r12, min_valid_ack(r0) lwz r13, max_valid_ack(r0) cmpw r11, r12 # Check minimum blt invalid_ack cmpw r11, r13 # Check maximum bgt invalid_ack # Process window size (can be negative for flow control) cmpwi r7, 0 # Check if window closed bge window_open # Handle closed window bl handle_flow_control b packet_complete window_open: # Update flow control window stw r7, peer_window_size(r0) packet_complete: bl process_packet_payload b packet_done invalid_packet: bl handle_invalid_packet invalid_ack: bl handle_invalid_ack packet_done:
Mathematical Computation - Fixed-Point Arithmetic
# Perform fixed-point arithmetic with signed 16.16 format lis r3, fixed_point_array@ha addi r3, r3, fixed_point_array@l lwz r4, array_size(r0) # Number of elements # Each element is 32-bit: high 16 bits = integer, low 16 bits = fraction # We'll load the high part as signed for proper arithmetic fixed_point_loop: lwz r5, 0(r3) # Load full 32-bit fixed-point value # Extract integer and fractional parts lha r6, 0(r3) # Load high 16 bits (integer part, signed) lhz r7, 2(r3) # Load low 16 bits (fractional part, unsigned) # Perform mathematical operation: sqrt approximation using Newton's method # For demonstration: x_new = (x + n/x) / 2 # Convert to approximate floating-point for calculation slwi r8, r6, 16 # Shift integer part to high bits or r9, r8, r7 # Combine integer and fractional parts # Simple square root approximation (for positive values) cmpwi r6, 0 # Check if positive ble skip_sqrt # Skip negative values # Initial guess: x0 = n/2 (very rough) srawi r10, r9, 1 # x0 = n/2 # Newton iteration: x1 = (x0 + n/x0) / 2 divw r11, r9, r10 # n/x0 add r12, r10, r11 # x0 + n/x0 srawi r13, r12, 1 # (x0 + n/x0) / 2 # Second iteration for better accuracy divw r14, r9, r13 # n/x1 add r15, r13, r14 # x1 + n/x1 srawi r16, r15, 1 # Final approximation # Store result back in fixed-point format stw r16, 0(r3) # Store computed square root b continue_processing skip_sqrt: # For negative numbers, store absolute value neg r17, r9 # Absolute value stw r17, 0(r3) # Store absolute value continue_processing: addi r3, r3, 4 # Next fixed-point value subi r4, r4, 1 # Decrement counter cmpwi r4, 0 bne fixed_point_loop # Continue processing
Game Engine - Sprite Animation
# Process sprite animation with signed offset values lis r3, sprite_data@ha addi r3, r3, sprite_data@l lwz r4, num_sprites(r0) # Number of sprites sprite_animation_loop: # Load sprite position and animation data lwz r5, 0(r3) # Base X position lwz r6, 4(r3) # Base Y position lha r7, 8(r3) # Signed X animation offset lha r8, 10(r3) # Signed Y animation offset lha r9, 12(r3) # Animation frame (can be negative for reverse) lha r10, 14(r3) # Animation speed (signed for direction) # Update animation frame add r11, r9, r10 # frame += speed # Check animation bounds cmpwi r11, 0 # Check if frame went negative bge check_upper_bound li r11, 0 # Clamp to 0 check_upper_bound: lwz r12, max_animation_frame(r0) cmpw r11, r12 # Check if exceeded maximum ble frame_ok mr r11, r12 # Clamp to maximum frame_ok: # Calculate current sprite position with animation offset add r13, r5, r7 # current_x = base_x + offset_x add r14, r6, r8 # current_y = base_y + offset_y # Apply frame-based animation displacement mullw r15, r11, r10 # frame * speed srawi r16, r15, 4 # Scale down animation displacement add r17, r13, r16 # Apply horizontal animation # Check screen bounds cmpwi r17, 0 # Check left bound bge check_right_bound li r17, 0 # Clamp to left edge check_right_bound: lwz r18, screen_width(r0) cmpw r17, r18 # Check right bound blt check_vertical mr r17, r18 # Clamp to right edge check_vertical: cmpwi r14, 0 # Check top bound bge check_bottom_bound li r14, 0 # Clamp to top edge check_bottom_bound: lwz r19, screen_height(r0) cmpw r14, r19 # Check bottom bound blt update_sprite mr r14, r19 # Clamp to bottom edge update_sprite: # Store updated sprite data stw r17, 0(r3) # Store new X position stw r14, 4(r3) # Store new Y position sth r11, 12(r3) # Store updated animation frame # Render sprite at new position bl render_sprite # Render sprite addi r3, r3, 16 # Next sprite (16 bytes per sprite) subi r4, r4, 1 # Decrement counter cmpwi r4, 0 bne sprite_animation_loop # Continue animation