LUI(上位の即時ロード)は、32ビット定数の作成に使用され、Uタイプのフォーマットを使用します。 LUIは、Uの即値を宛先レジスタrdの上位20ビットに配置し、最下位の12ビットをゼロで埋めます。
これはマニュアルで見つけましたが、0xffffffffをレジスタに移動したい場合、必要なコードは次のとおりです。
LUI x2, 0xfffff000
ADDI x2, x2, 0xfff
しかし、問題が発生したため、ADDIは符号を拡張して即時データを符号付きの数値に変換するため、0xfff
は0xffffffff
に拡張されます。
x2
を0xffffefff
に変換しますが、0xffffffff
は変換しません。
そして、32ビットを即座に登録するための適切な実装は何ですか?
RISC-Vアセンブラは、疑似命令li x2, 0xFFFFFFFF
をサポートしています。
N
を符号付きの2の補数32ビット整数としましょう。
li x2,N
の一般的なケースの実装は次のとおりです。
# sign extend low 12 bits
M=(N << 20) >> 20
# Upper 20 bits
K=((N-M) >> 12) <<12
# Load upper 20 bits
LUI x2,K
# Add lower bits
ADDI x2,x2,M
もちろん、短いイミディエートli
をロードするには
addi x2,x0,imm
したがって、li x2, 0xFFFFFFFF
はaddi x2,x0,-1
です。
「ORI
の代わりにADDI
を使用する」と言っていたのですが、命令セットマニュアルを読んだところ、それでも機能しないことがわかりました。論理演算であっても、オペランドは符号拡張されます。
AFAICTは、下位12ビットを設定するために使用する命令の効果を予測する方法で、上位20ビットに入れる値をバイアスする必要があります。したがって、上位20ビットの値Xで終了し、ADDI
を使用して下位12ビットを設定する場合、これらの下位12ビットの左端に1があり、 _LUI X
_ではなくLUI (X+1)
を実行する必要があります。同様に、XORI
を使用して下位12ビットを設定し、それらの下位12ビットの左端に1がある場合、LUI (~X)
を実行する必要があります(つまり、ビット単位の逆X)の_LUI X
_ではなく。
しかし、それを行う前に、アセンブラに、これを処理する何らかの「即時ロード」疑似命令またはマクロがすでにあるかどうかを確認します。そうでない場合は、作成できるかどうかを確認してください:-)
RISCプロセッサがプログラマ(または、より一般的にはコンパイラ)からこの種の追加の作業を必要とすることは珍しいことではありません。アイデアは、「ハードウェアをシンプルにして高速に実行できるようにし、それがソフトウェアの構築を難しくするかどうかは問題ではない」です。
TL; DR:x2
にロードする32ビット定数は0xffffffff
で、これは-1に対応します。 -1は[-2048、2047]の範囲にあるため、この定数は単一の命令でロードできます:addi x2, zero, -1
。 li
疑似命令:li, x2, -1
を使用して、アセンブラがaddi x2, zero, -1
に変換することもできます。
lui
+ addi
シーケンスで32ビット定数をロードする一般的に、32ビット定数をレジスタにロードするには、lui
+ addi
シーケンス(2つの命令)が必要です。 lui
命令は20ビットの即値をエンコードしますが、addi
命令は12ビットの即値をエンコードします。 lui
およびaddi
を使用して、それぞれ32ビット定数の上位20ビットと下位12ビットをロードできます。
[〜#〜] n [〜#〜]をレジスターにロードしたい32ビット定数とします:N≡n31 ... n。次に、この定数を上位20ビットと下位12ビットに分割できますNUおよびNL、それぞれ:NU ≡n31 ... n12; NL ≡n11 ... n
原則として、NをエンコードしますUlui
およびNの直後Laddi
内のイミディエート内。それでも、処理が難しいaddi
の12ビットの即値の最上位ビットが 1addi
命令にエンコードされた即値は 符号拡張 32ビットに。この場合、addi
命令はNではなく宛先レジスタに追加されますL、 だが - NL -4096代わりに—-4096(または-212)は、上位20ビットが 1sと下位12ビットは s。
不要な用語-4096を補うために、1をlui
の即値に追加できます。lui
の即値のLSBは、ビット#12–したがって、1をこの即時の結果に追加すると、4096-4096項をキャンセルする宛先レジスタに。
addi
命令で32ビット定数をロードする上記で説明した問題は、addi
の即値が通過する符号拡張によるものです。 addi
の即値を符号拡張する決定は、おそらく小さな整数の読み込みを許可することでした-2048と2047、両方を含む–単一のaddi
命令で。たとえば、addi
の即値が符号拡張ではなくzero extendedである場合、-1のような頻繁な定数をロードすることはできません。 単一の命令だけでレジスタに。
li
pseudoinstructionを使用して32ビット定数をロードするいずれの場合でも、32ビット定数をロードする場合は、常にli
疑似命令を使用して、ロードする定数の値を気にする必要はありません。この疑似命令は32ビットの数値をレジスタにロードできるため、lui
+ addi
シーケンスを手動で書き込むよりも使用が簡単で、エラーが発生しにくくなります。
数値がaddi
のイミディエイトフィールドに一致する場合([-2048、2047])、アセンブラはli
疑似命令をaddi
命令に変換します。そうでない場合、li
はlui
+ addi
シーケンスと上記で説明した複雑化は、アセンブラによって自動的に処理されます。