sh

sh

RISC-V Assembly Reference

lyszt.net covers sh and other RISC-V instructions in more detail.

Encoding format

R
31–25funct7
24–20rs2
19–15rs1
14–12funct3
11–7rd
6–0opcode
I
31–20imm[11:0]
19–15rs1
14–12funct3
11–7rd
6–0opcode
S
31–25imm[11:5]
24–20rs2
19–15rs1
14–12funct3
11–7imm[4:0]
6–0opcode
B
31–25imm[12,10:5]
24–20rs2
19–15rs1
14–12funct3
11–7imm[4:1,11]
6–0opcode
U
31–12imm[31:12]
11–7rd
6–0opcode
J
31–12imm[20,10:1,11,19:12]
11–7rd
6–0opcode

Description

sh writes a halfword, 16 bits or 2 bytes, to memory. It matches the lh and lhu loads and stores the narrower size where sw stores the full word. The form is shown below. It takes the value in source register rs2 and writes its lowest 16 bits to the address in base register rs1 plus the offset. The layout matches sw, with the source register named first.

sh rs2, offset(rs1)

A register holds 32 bits and only 16 are stored, so sh keeps the lowest 16 and drops the upper 16. Stores have no signed or unsigned choice. That choice belongs to loads, where a narrow value must be widened to fill a register and the missing bits need a rule. A store narrows the value, and keeping the low bits is the only behavior that makes sense. If the register holds a value too large for 16 bits, the extra bits are lost with no warning, so check the range before storing.

The RISC-V manual says sh stores the low 16 bits of register rs2 to memory at the address of rs1 plus the sign-extended 12-bit offset. Halfword stores at even addresses are naturally aligned and never raise an alignment error. A store to an address that is not naturally aligned behaves as the execution environment defines, and the manual says it can run extremely slowly.

sh writes every 16-bit format that lh and lhu read back, such as audio samples, 16-bit pixel data and halfword arrays. A common pattern is read, modify and write. Load a halfword with lhu, adjust it in the register and store it back with sh. Only the targeted 2 bytes change and the bytes around them stay as they were. Halfwords sit 2 bytes apart, so loops move the address by 2.

Example

la t0, slot
li t1, -5
sh t1, 0(t0)   # memory at slot now holds the low 16 bits of -5