前回から64bitのRISC-V搭載のK210にターゲットを切り替えたのですが、今回はまさかの問題勃発。Flashに書き込めません。というか接続するとPCの挙動が不審。どうしたものか。そこで困ったときのラズパイ頼み、Picoの母艦のラズパイ4機にK210ボードへの書き込みをお願い。OK、単精度浮動小数点add命令動いています。
※「ぐだぐだ低レベルプログラミング」投稿順indexはこちら
(今回実験に使用したコード全文は末尾に)
前回から、64bitのRISC-VコアのK210を搭載したMAiX BiTボード(マイク搭載版)にターゲットボードを切り替え。それまでと環境が変わりました。ために、32bitのRISC-VではGASで別ファイルに記述したアセンブラ関数を使っていたのを、インライン・アセンブラでの実験にスイッチ。前回は、インライン・アセンブラへの引数の渡し方をおさらいした、というところ。
さて今回は、前回の流れにそって、いよいよRISC-Vの浮動小数点命令セットRVF(単精度浮動小数)、RVD(倍精度浮動小数)に突入と思ったら、まさかの問題勃発であります。
「とりあえず」単精度浮動小数点加算命令を1つをインライン・アセンブラに置き、それにインタフェースをとるための命令を記述いたしました。ビルドはOK,これを走らせれば fadd.s 命令のサンプル動作OK,と思いきや、肝心のMAiX BiTボードに書き込みできません。仮想シリアルポート番号などは変わっていない。それどころか接続するとPCの挙動そのものが怪しいです。何が起こった。PCの電源入れなおして再トライするもダメ。
他のボードを同じUSBポートに接続するとサクサク動くので、どうも先週から今週への1週間でMAiXとの接続に何かがおきた感じです。
困ったときのラズパイ頼み
PCで作業していても煮詰まってツボにハマるばかりに思えたので、ラズパイ4に御出馬願いました。普段は、ラズパイPicoの母艦として活躍しているデバイスです。万が一、MAiXボードが壊れていたなどの事態であればラズパイ4でも動作しない筈。接続しました。
/dev/ttyUSB0 および /dev/ttyUSB1
としてMAiX Bitボードを認識しました。こころみに /dev/ttyUSB0 に端末ソフトで接続すれば、先週書き込んだプログラムが動作しているみたい。よかった、ボードは壊れてなかった。
シリアルポートが正常に動作するのであれば、プログラムの書き込みが出来る筈。GitHubにある以下のKendryteのツールはPythonベースで、Raspberry Pi OS上でも実行可能。
kflash, A Python-based Kendryte K210 UART ISP Utility
その上、PIPでインストールできます。
$ sudo pip3 install kflash
そしてPC上でビルド済のオブジェクトファイル firmware.bin をラズパイ4機へ転送。インストールした kflash ツールで一発。
$ kflash -p /dev/ttyUSB0 firmware.bin
書き込みOK、そして動作も予定通り。困ったときのラズパイ頼み。
今回実験のインラインアセンブラ
単精度浮動小数点 fadd.s 1命令をテストするために書いたインラインアセンブラは以下です。最初、浮動小数点レジスタに直接浮動小数点数を「突っ込もう」としてみたのですが、上手く行きませんでした。整数レジスタに対してはうまく動く%[Rs1]みたいな記述が、どうも浮動小数点レジスタには働かないみたいです。そこで、
整数レジスタを経由して浮動小数点レジスタに突っ込む
スタイルをとったら、インラインアセンブラが処理してくれるようになりました。そのためターゲットのfadd.sの前後に 整数/浮動小数レジスタ間移動のfmvが合計3個。イマイチですが致し方ありません。
TestFloat f0S, f1S, f2S; f0S.fDat = 0.0; f1S.fDat = 1.000001; f2S.fDat = 0.999999; asm volatile("fmv.w.x f1, %[Rs1]\n\t" "fmv.w.x f2, %[Rs2]\n\t" "fadd.s f0, f1, f2\n\t" "fmv.x.w %[Rd], f0\n\t" : [Rd] "=r" (f0S.u32Dat.LowW) : [Rs1] "r" (f1S.u32Dat.LowW), [Rs2] "r" (f2S.u32Dat.LowW) : ); Serial.printf(" %f + %f = %f\r\n", f1S.fDat, f2S.fDat, f0S.fDat); Serial.printf("HEX: %08x\r\n", f0S.u32Dat.LowW);
生成されたオブジェクトコードを確認
実際に生成されたオブジェクトを確認しないと、どんな命令が走るのだか大変不安なので何時ものとおり objdump で覗いてみます。こんな感じ。
80000634: 3f800737 lui a4,0x3f800 80000638: 0087079b addiw a5,a4,8 8000063c: 373d addiw a4,a4,-17 8000063e: f00780d3 fmv.w.x ft1,a5 80000642: f0070153 fmv.w.x ft2,a4 80000646: 0020f053 fadd.s ft0,ft1,ft2 8000064a: e00007d3 fmv.x.w a5,ft0 8000064e: f0078553 fmv.w.x fa0,a5 80000652: 0007841b sext.w s0,a5
浮動小数点数は、予定どおり「整数のつもり」で整数レジスタ上で作られて、そこから浮動小数点レジスタに送り込まれています。取り出すのも同じ。インライン・アセンブラ、結構苦労しておるな。
動作確認
先に述べたとおり、PC上で動作を確認できなかったので、以下は、PC上で生成の上記オブジェクトをラズパイ4から書き込んで動作確認したものです。
Trial: 8 1.000001 + 0.999999 = 2.000000 HEX: 40000000
このままPCで書き込みできないのは困るけれど、場合によっては開発環境から全部、ラズパイ4に移してしまうのもアリですか。。。
ぐだぐだ低レベルプログラミング(41) 64BITのRISC-Vでインライン・アセンブラ に戻る
ぐだぐだ低レベルプログラミング(43) 64bitRISC-V、レジスタとレジスタ間転送 へ進む
実験に使用したコード全文
#include <Arduino.h> typedef struct { uint32_t LowW; uint32_t HighW; } HighLowW; typedef union { uint64_t u64Dat; HighLowW u32Dat; double dDat; float fDat; } TestFloat; int counter; void setup() { pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); counter = 0; Serial.begin(9600); while (!Serial); Serial.printf("MAiX BiT ASM TEST 001.\r\n"); } void loop() { if ((counter++ % 2) == 0) { digitalWrite(LED_BUILTIN, HIGH); } else { digitalWrite(LED_BUILTIN, LOW); } Serial.printf("Trial: %d\r\n", counter); //--- DUT -------------------------------- TestFloat f0S, f1S, f2S; f0S.fDat = 0.0; f1S.fDat = 1.000001; f2S.fDat = 0.999999; asm volatile("fmv.w.x f1, %[Rs1]\n\t" "fmv.w.x f2, %[Rs2]\n\t" "fadd.s f0, f1, f2\n\t" "fmv.x.w %[Rd], f0\n\t" : [Rd] "=r" (f0S.u32Dat.LowW) : [Rs1] "r" (f1S.u32Dat.LowW), [Rs2] "r" (f2S.u32Dat.LowW) : ); Serial.printf(" %f + %f = %f\r\n", f1S.fDat, f2S.fDat, f0S.fDat); Serial.printf("HEX: %08x\r\n", f0S.u32Dat.LowW); //--- END OF DUT-------------------------- delay(5000); }