今回は珍しくメンドクない命令です。浮動小数のロード、ストアです。アドレスの指定は通常のロード、ストア同様に整数レジスタに12ビットのディスプレースメントを加える方式。これだけ。シンプル。RISCだもんね。
※「ぐだぐだ低レベルプログラミング」投稿順indexはこちら
※以下は単精度浮動小数点命令について述べています。なお実機動作は、64bit RISC-V搭載、Kendryte K210上で行っています。
浮動小数のロードとストア命令
命令のエンコードとしてはどちらも3オペランドの命令です。
-
- flw rd, offset(rs1)
- fsw rs2, offset(rs1)
ロードもストアも12ビットのオフセットをとり、その値を符号拡張した上で、rs1で指定される整数レジスタ x[rs1] に格納されているメモリアドレスと加算してロード、ストアの対象となるメモリアドレスを得ます。
flwの場合は、そのアドレスから単精度浮動小数を読み出してrdで指定される浮動小数レジスタ f[rd] に格納します。
fswの場合は、rs2で指定される浮動小数レジスタ f[rs2] の内容を上記のアドレスに格納します。
被テスト関数のソース
ロードしただけでは結果が観察できないので、ロードしたらおとなりのメモリアドレスにストアすることにしました。被テスト関数も1個になってラクチン。いいのかそういうことで。
void tst_Flw_sw(uint32_t tnum, float arg1) { TestFloat f0S; float work[8]; float *adr; f0S.fDat = 0.0f; work[0] = 0.2345f; work[1] = arg1; work[2] = 2.4567f; work[3] = 3.4567f; adr = &work[1]; asm volatile("fmv.w.x f0, %[Rd]\n\t" "flw f0, (%[Rs1])\n\t" "fsw f0, 4(%[Rs1])\n\t" "fmv.x.w %[Rd], f0\n\t" : [Rd] "=r" (f0S.u32Dat.LowW) : [Rs1] "r" (adr) : ); Serial.printf("TEST-flw_fsw #%u\r\n", tnum); Serial.printf("%f <- flw 0(ADR)\r\n", f0S.fDat); Serial.printf("%f <- fsw 4(ADR)\r\n", work[2]); Serial.printf(" HEX: %08x\r\n", f0S.u32Dat.LowW); for(int i=0; i<4; i++) { Serial.printf("work[%d]: %f\r\n", i, work[i]); } Serial.printf("\r\n"); }
テストケース
テストケースもおざなり、わずか3ケースのみです。手抜き。
tst_Flw_sw(0, 1.3333f); tst_Flw_sw(1, -1.3333f); tst_Flw_sw(2, 2.5f);
実機動作結果
実機動作結果は、冒頭のアイキャッチ画像に貼り付けました。実機はRaspberry Pi 4機のUSBポートに刺してあるので、USBシリアルに垂れ流されてくる結果をminicomで見ているものです。
まあ予定通りに動いている感じ。いつもこんなに簡単だと良いけれど。実は知っています。浮動小数関係の命令の中でもメンドクセー奴らの一群がまだ隠れていることを。。。次回は気が重いな。