目次: Zephyr
JTAGが繋がった(2021年6月5日の日記参照)記念にZephyrをHiFive Unleashedで動かしてみました。使うハードウェアはUARTだけ、コードもJTAGでITMにロードして動作させるだけなら楽勝だろと思いきや、全然UARTから文字が出力されず1日掛かってしまいました。
*** Booting Zephyr OS build zephyr-v2.6.0-39-g2bf63134e8f0 *** thread_a: Hello World from cpu 0 on hifive_unleashed! thread_b: Hello World from cpu 0 on hifive_unleashed! thread_a: Hello World from cpu 0 on hifive_unleashed! thread_b: Hello World from cpu 0 on hifive_unleashed! thread_a: Hello World from cpu 0 on hifive_unleashed! thread_b: Hello World from cpu 0 on hifive_unleashed!
原因はコアのPLL設定が間違っていて、コアクロックから分周して作るUARTのボーレートもおかしな周波数になっていたからです。
FU540のリセット直後は外部クロック源(33.33MHz)をそのまま使って動きます。起動後PLLを1GHz(33.33 / 1 * 120 / 4 = 999.9MHz)に設定し、コアクロックをPLL側に切り替えなければなりません。
PLLの設定はFSBLという2段目のブートローダーが行うので、通常はOSが気にする必要はありません。しかしRTOSは大抵ブートローダーを経由しませんから、ブートローダーに隠れた設定も拾ってきて実装しないと動かないことがあります。
ブートローダーがあって当たり前のリッチ系SoCでRTOSを動かそうとすると、大抵この「暗黙のうちに設定されている何か」が抜け落ちて動かなかったりおかしくなったり、何かと面倒が起きます。
幸いなことにSiFiveのブートローダーはコードが公開されており、完全ブラックボックスのSoCと比べれば、難易度は低い部類です。ありがたいですね。
メモ: 技術系の話はFacebookから転記しておくことにした。加筆。
この記事にコメントする
目次: RISC-V
昔買ったHiFive Unleashedというボード、JTAGはちょっと特殊なコネクタが必要だと思っていて接続を諦めていました。ところが今日、ファンを掃除したあと動作確認をした際に、USB Serialと一緒にUSB JTAGも用意されていることに気づきました。
HiFive Unleashedはディスコンでもう手に入りませんし、後継機種のHiFive Unmatchedも買った今となっては、かなり今更感ありますが……。
ちょっと試したところ、簡単にOpenOCDが繋がりSMPモードにすると5コア(rv64imacなE51とrv64gcなU54 x 4)が見えました。
adapter speed 10000
adapter driver ftdi
ftdi_device_desc "Dual RS232-HS"
ftdi_vid_pid 0x0403 0x6010
ftdi_layout_init 0x0008 0x001b
ftdi_layout_signal nSRST -oe 0x0020 -data 0x0020
set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000913
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME -rtos hwthread
target create $_TARGETNAME.1 riscv -chain-position $_TARGETNAME -coreid 1
target create $_TARGETNAME.2 riscv -chain-position $_TARGETNAME -coreid 2
target create $_TARGETNAME.3 riscv -chain-position $_TARGETNAME -coreid 3
target create $_TARGETNAME.4 riscv -chain-position $_TARGETNAME -coreid 4
target smp $_TARGETNAME.0 $_TARGETNAME.1 $_TARGETNAME.2 $_TARGETNAME.3 $_TARGETNAME.4
init
halt
SiFiveのSoCはFU540も後継のFU740も命令セットの違うコアを混載するのが好きですね。混載は良いとしてせめて同じ命令セットにしてほしかったです。単純なSMPしか持ってないOSだと制御できないじゃん……。
メモ: 技術系の話はFacebookから転記しておくことにした。加筆。
この記事にコメントする
目次: OpenCL
引き続き、独自アクセラレータのテンプレート実装pocl/lib/CL/devices/accelの細かな問題を調べます。デバイス数の取得の問題を回避すると、次はデバイスのパラメータを渡す問題に遭遇します。
// pocl/lib/CL/devices/accel/accel.cc
void pocl_accel_init_device_ops(struct pocl_device_ops *ops) {
ops->device_name = "accel"; //★★デバイス名はaccel
ops->init = pocl_accel_init;
...
// pocl/lib/CL/devices/devices.c
cl_int
pocl_init_devices ()
{
...
dev_index = 0;
/* Init infos for each probed devices */
for (i = 0; i < POCL_NUM_DEVICE_TYPES; ++i)
{
if (pocl_devices_init_ops[i] == NULL)
continue;
str_toupper (dev_name, pocl_device_ops[i].device_name); //★★dev_nameはデバイス名を大文字に変換したACCELになる
assert(pocl_device_ops[i].init);
for (j = 0; j < device_count[i]; ++j)
{
...
/* Check if there are device-specific parameters set in the
POCL_DEVICEn_PARAMETERS env. */
POCL_GOTO_ERROR_ON (
(snprintf (env_name, 1024, "POCL_%s%d_PARAMETERS", dev_name, j) //★★環境変数名を生成する箇所
< 0),
CL_OUT_OF_HOST_MEMORY, "Unable to generate the env string.");
errcode = pocl_devices[dev_index].ops->init (
j, &pocl_devices[dev_index], getenv (env_name));
...
実装ではpocl_accel_init() にて環境変数の値をパースしてデバイスのパラメータを取得します。環境変数名はデバイス番号によって変化しますが、0番目のデバイスであればPOCL_ACCEL0_PARAMETERSという名前になります。環境変数名は上記にあるとおりpocl_init_devices() で決めています。
困ったことに環境変数が見つからないとabort() してしまうので、環境変数には最低でも何か1つ数値を渡す必要があります。なお1つ目の値はレジスタ領域のベースアドレスだと解釈されるようです。
他の実装(pthreadとcuda)は環境変数を使わないので、同様の問題は存在しません。最終的にはaccelも環境変数に頼らない実装に変えていく必要がありますが、今はそのままにしておきます。
この記事にコメントする
目次: OpenCL
独自アクセラレータのテンプレート実装pocl/lib/CL/devices/accelはデバイスタイプがCUSTOMになっているのが最大の難関ですが、その他にも色々問題があります。
最初に遭遇する問題はデバイス数を取得する処理のエラー処理が間違っていることです。現状のコードだとちょっと特殊な環境変数を渡さないと動きません。
// pocl/lib/CL/devices/devices.c
static unsigned device_count[POCL_NUM_DEVICE_TYPES];
...
cl_int
pocl_init_devices ()
{
...
/* Init operations */
for (i = 0; i < POCL_NUM_DEVICE_TYPES; ++i)
{
...
/* Probe and add the result to the number of probed devices */
assert(pocl_device_ops[i].probe);
device_count[i] = pocl_device_ops[i].probe(&pocl_device_ops[i]); //★デバイス数を取得する★
pocl_num_devices += device_count[i];
}
...
dev_index = 0;
/* Init infos for each probed devices */
for (i = 0; i < POCL_NUM_DEVICE_TYPES; ++i)
{
if (pocl_devices_init_ops[i] == NULL)
continue;
str_toupper (dev_name, pocl_device_ops[i].device_name);
assert(pocl_device_ops[i].init);
for (j = 0; j < device_count[i]; ++j) //★デバイス数42億と誤解したまま処理しようとしてクラッシュする★
{
// pocl/lib/CL/devices/accel/accel.cc
unsigned int pocl_accel_probe(struct pocl_device_ops *ops) {
//★POCL_DEVICESという環境変数が見つからないとき、-1というエラー値を返す★
//★本来エラー値である -1だが、デバイス数として解釈され42億になってしまう★
int env_count = pocl_device_get_env_count(ops->device_name);
return env_count;
}
// pocl/lib/CL/devices/devices.c
/**
* Get the number of specified devices from environment
*/
int pocl_device_get_env_count(const char *dev_type)
{
const char *dev_env = getenv(POCL_DEVICES_ENV);
char *ptr, *saveptr = NULL, *tofree, *token;
unsigned int dev_count = 0;
if (dev_env == NULL)
{
return -1; //★ここにくる★
}
ptr = tofree = strdup(dev_env);
while ((token = strtok_r (ptr, " ", &saveptr)) != NULL)
{
if(strcmp(token, dev_type) == 0)
dev_count++;
ptr = NULL;
}
POCL_MEM_FREE(tofree);
return dev_count;
}
このような実装になっておりaccelのデバイス数が42億(!)と解釈されてしまい、42億回デバイスを列挙しようとしてクラッシュします。バグのような気がしますけど、サンプル実装ですのであまり文句を言っても仕方ありません。
環境変数POCL_DEVICES="pthread -1 CUDA -1 accel 1" のようにデバイス数を明示的に渡せば回避可能です。最終的にはpocl_accel_probe() が正しくデバイス数を返すような実装を追加する必要があるでしょうが、この場は環境変数で切り抜けます。
この記事にコメントする
目次: OpenCL
CPUでもGPUでもないデバイスでOpenCLを動かすとしたらどうしたら良いでしょうか?答えとしては、その1で紹介したとおり、CL_DEVICE_TYPE_ACCELERATORを実装すれば良いです。が、イチから作るのはとっても大変です。
素晴らしいことにpoclにはテンプレートらしき実装がpocl/lib/CL/devices/accelに用意されています。やりたいこととは微妙に違うことが後々わかりますが、イチから作るよりははるかにマシです。このテンプレートを改造しましょう。
テンプレートの名前はaccelでいかにもアクセラレータに見えますが、デバイスタイプはCL_DEVICE_TYPE_ACCELERATORではなくCL_DEVICE_TYPE_CUSTOMです。CUSTOMは「コンパイルが可能なデバイス」ではなく、ビルトインカーネルのみを実行するデバイスです。ユーザー定義のカーネルを実行することは考えられていません。
ユーザー定義カーネルが実行できることが独自アクセラレータの売りですから、何とかしてCUSTOMではなくACCELERATORになるように実装を改造する必要があります。これはなんとも先が長そうです……。
この記事にコメントする
目次: ベンチマーク
(参考)コード一式はGitHubに置きました(GitHubへのリンク)
Linuxが動くRISC-Vボードを買ったので、RISC-V 64でもmemsetをやってみました。環境はボードがSiFive HiFive Unmatchedで、SoCがSiFive Freedom U740で、コアがU74-MCです。動作周波数は書いてないですね。OSはSiFive独自?環境のFreedom USDKです。メモリはDDR4-2400のようです(Schematics hifive-unmatched-schematics-v3.pdfより)。
特徴的な点は、
あと個人的に残念だった点としては、U74コアの速度です。前世代のHiFive Unleashedに搭載されていたU54コアはCortex-A53の足下にも及びませんでした(2019年5月27日の日記参照)。
U74はCortex-A72レベルとまでは言いませんが、Cortex-A53は超えてくると期待していましたが、少なくともmemsetに関しては負けています。半分くらいの速度しか出ていません……。
この記事にコメントする
目次: RISC-V
SiFiveのHiFive Unmatchedを購入しました。現状、世界最速のLinuxが動作するRISC-V 64bit SoC とのことです。
ボードにはSDカードが付属しておりSiFive独自環境のFreedom USDKがインストールされています。ボード上にはUSB接続のシリアル端子があり、電源を入れればLinuxが起動し、ユーザroot、パスワードsifiveでログインできるようになっています。
ぱっと見はPCと同じmini-ITXマザーボードですけど、バックパネルを見るとSDカードの差し込み口、USBシリアル用のmicroB端子が出ていて、どちらかといえばSBC(シングルボードコンピュータ)です。PCっぽさがありません。
本当はグラフィックカードを装着してGUIを使うべきですが、昨今のグラフィックカード品薄&異常な値上がりのおかげで全く買う気が起きないので、しばらくシリアルコンソールで使おうと思います。
インストールされているカーネルは、
Linux unmatched 5.11.10 #1 SMP Wed Apr 7 17:37:34 UTC 2021 riscv64 riscv64 riscv64 GNU/Linux
でした。5.11はStableカーネルではあるものの、既にEOLです。まあ、開発用ボードだしこんなもんか。
Crowd Supplyから購入しました。本体 $679, 消費税が7,100円、合計で7万円くらいでした。HiFive Unleashedほどではないにせよ、SBCにしては良いお値段です。
UPSが米国→日本まで持ってきて、国内はクロネコヤマトが運びます。受け取りの際に、消費税を着払いでクロネコに払う必要があります。私は消費税のことを忘れていて、何だこの金は??と混乱しました。Unleashedのときと全く同じでした。海外からものを買うことがほとんどなくて、消費税の存在をすぐ忘れちゃうんですよね……。
この記事にコメントする
| < | 2021 | > | ||||
| << | < | 06 | > | >> | ||
| 日 | 月 | 火 | 水 | 木 | 金 | 土 |
| - | - | 1 | 2 | 3 | 4 | 5 |
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 | - | - | - |
25年10月15日
25年10月18日
22年5月5日
25年10月19日
23年4月11日
06年4月22日
25年10月17日
25年10月6日
25年10月13日
20年10月23日
25年10月12日
20年8月29日
19年1月13日
18年10月13日
18年9月3日
18年8月20日
18年7月23日
18年7月22日
18年10月14日
18年11月10日
wiki
Linux JM
Java API
2002年
2003年
2004年
2005年
2006年
2007年
2008年
2009年
2010年
2011年
2012年
2013年
2014年
2015年
2016年
2017年
2018年
2019年
2020年
2021年
2022年
2023年
2024年
2025年
過去日記について
アクセス統計
サーバ一覧
サイトの情報合計:
本日: