web-dev-qa-db-ja.com

RISC-VはLUIおよびADDIを使用して32ビット定数を構築します

LUI(上位の即時ロード)は、32ビット定数の作成に使用され、Uタイプのフォーマットを使用します。 LUIは、Uの即値を宛先レジスタrdの上位20ビットに配置し、最下位の12ビットをゼロで埋めます。

これはマニュアルで見つけましたが、0xffffffffをレジスタに移動したい場合、必要なコードは次のとおりです。

LUI x2, 0xfffff000
ADDI x2, x2, 0xfff

しかし、問題が発生したため、ADDIは符号を拡張して即時データを符号付きの数値に変換するため、0xfff0xffffffffに拡張されます。

x20xffffefffに変換しますが、0xffffffffは変換しません。

そして、32ビットを即座に登録するための適切な実装は何ですか?

10
Li Hanyuan

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, 0xFFFFFFFFaddi x2,x0,-1です。

8
Pavel Smirnov

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プロセッサがプログラマ(または、より一般的にはコンパイラ)からこの種の追加の作業を必要とすることは珍しいことではありません。アイデアは、「ハードウェアをシンプルにして高速に実行できるようにし、それがソフトウェアの構築を難しくするかどうかは問題ではない」です。

6
ottomeister

TL; DR:x2にロードする32ビット定数は0xffffffffで、これは-1に対応します。 -1[-2048、2047]の範囲にあるため、この定数は単一の命令でロードできます:addi x2, zero, -1li疑似命令: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を補うために、1luiの即値に追加できます。luiの即値のLSBは、ビット#12–したがって、1をこの即時の結果に追加すると、4096-4096項をキャンセルする宛先レジスタに。

単一のaddi命令で32ビット定数をロードする

上記で説明した問題は、addiの即値が通過する符号拡張によるものです。 addiの即値を符号拡張する決定は、おそらく小さな整数の読み込みを許可することでした-20482047、両方を含む–単一のaddi命令で。たとえば、addiの即値が符号拡張ではなくzero extendedである場合、-1のような頻繁な定数をロードすることはできません。 単一の命令だけでレジスタに。


lipseudoinstructionを使用して32ビット定数をロードする

いずれの場合でも、32ビット定数をロードする場合は、常にli疑似命令を使用して、ロードする定数の値を気にする必要はありません。この疑似命令は32ビットの数値をレジスタにロードできるため、lui + addiシーケンスを手動で書き込むよりも使用が簡単で、エラーが発生しにくくなります。

数値がaddiのイミディエイトフィールドに一致する場合([-2048、2047])、アセンブラはli疑似命令をaddi命令に変換します。そうでない場合、lilui + addiシーケンスと上記で説明した複雑化は、アセンブラによって自動的に処理されます。

3
眠りネロク