lha
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