人気ブログランキング |

雑多な趣味の記録帳

tom01h.exblog.jp

カテゴリ:論理設計の話( 13 )

bfloat16 型に向いている DSP 構成を提案したい その3

ちょっと前に Xilinx と Intel から次世 FPGA アーキテクチャの発表がありましたが、どちらの DSP も tiny-dnn アクセラレータで使っている 8bit 乗算をたくさん並べるのに向いていないような気がしています。
だからと言ってここで作っても何の解決にもならないのですが、まぁ、たまには昔を思いだして…

ついに、肝心の符号なし 8bitx8bit の 4並列実行の回路を作りました。
全部でこんな感じの機能を選べます。
24bitx24bit と 8bitx8bit の 4並列は、浮動少数点数用なので符号付きはありません。
何となく、符号付きの 16bitx16bit の 2並列実行が出来るのは対称性に欠ける気もしますが…
f0054075_22052354.png
とりあえずこれで完了かな?
github に置いておきました。
8bitx8bitx4 の内積とか、16bitx16bitx2 の内積とかとディレイの比較をしてみたい気もしますが…
全部でゲート6~7段くらいのディレイ増で済むのが理想です。

by tom01h | 2019-05-14 22:56 | 論理設計の話 | Trackback | Comments(0)

bfloat16 型に向いている DSP 構成を提案したい その2

今日は気分を変えて乗算器を掘っています。

ちょっと前に Xilinx と Intel から次世 FPGA アーキテクチャの発表がありましたが、どちらの DSP も tiny-dnn アクセラレータで使っている 8bit 乗算をたくさん並べるのに向いていないような気がしています。
だからと言ってここで作っても何の解決にもならないのですが、まぁ、たまには昔を思いだして…

24bit x 24bit, 32bit x 16bit, 16bit x 16bit 2個 (個別と足しこみ) を符号の有り無しでいろいろ選べます。
肝心の 8bit x 8bit 4個は、足しこむバージョンにやっと手を付けたところです。
一番欲しい 8bit の個別バージョンが最後になってしましました。
難しそうなんですよね。符号付きはいらないかな?

github に置いてあります。
なんのこっちゃ分らんかもしれませんが、こんな感じの構成です。
f0054075_18373027.png

by tom01h | 2019-05-06 20:22 | 論理設計の話 | Trackback | Comments(0)

bfloat16 型に向いている DSP 構成を提案したい

Xilinx と Intel から次世代の FPGA アーキテクチャの発表がありましたが、どちらの DSP も bfloat16 型を効率よく実装できる構造をしていないように思います。
だからと言ってこんなところで吠えてもしょうがないですが、昔取った… で DSP に望む姿を考えてみたいと思います。

手始めに、次の2つの計算ができるモジュールを作ってみました。

0. (符号なし 24bit 整数) × (符号なし 24bit 整数)
2. (符号なし 32bit 整数) × (符号なし 16bit 整数)

暇を見つけて、機能を増やしていきたいと思います。

ここ に置いておきました。

こんな感じの作りです。
f0054075_21164064.png

by tom01h | 2019-04-26 22:01 | 論理設計の話 | Trackback | Comments(0)

V-scale に使っている FPU 乗算器の話

V-scale に使っている FPU 乗算器の話です。
V-scale に使っている乗算器の話 にも書いた通り、整数乗算と FPU 乗算では 4サイクル目までの動作は同じです。
4サイクルで仮数部の乗算結果を求るのは、整数乗算器の説明の通りです。
そして、5サイクル目は正規化と丸めをします。ここは前回と変わりありません。
ただ、今回はちょっと高速化を狙って正規化シフタを変更しています。あまり効果ありませんでしたが…
ちなみに、実際に V-scale で使っている記述とは表現が全然違うのですが、構成も若干違うところがあります。
表現の違いは合成に過大な期待をしていない(加算器をたくさん生成しないとか)ため、構成の違いはディレイ対策の有無と思ってください。


by tom01h | 2017-11-19 23:45 | 論理設計の話 | Trackback | Comments(0)

サブノーマル数にも対応した FPU 乗算器の話

今回はサブノーマル数に対応します。回路化は全く考えていない構成ですが、機能的にはすべてが実装されます。
サブノーマル数は指数フィールドが0で示され、その値は↓です。
((-1)^F[31]) * (0.F[22:0]) * (2^(1-127)) ^はべき乗です
つまり、サブノーマル入力を考慮した指数は
expx = (x[30:23]==8'h00) ? 8'h01 : x[30:23];
で表され、仮数は
fracx = {(x[30:23]!=8'h00),x[22:0]};
で表されます。
また、正規化数しか入力されない場合は、正規化シフトはシフトなしか1ビットの右シフトの2通りから選ぶだけでした。
サブノーマル数が入力された場合は左シフトも必要になります。この先どうせ立派なのが必要になるので、63ビットまでのシフト量に対応した正規化シフタを追加します。
ちなみにこの正規化シフタは、サブノーマル数を出力可能とするために正規化後の指数が1となるところで止まります。
あと、今は必要ないですが、仮数が負の数にも対応しています。
また、サブノーマル数の出力にはこれだけじゃ足りなくて、正規化前の指数が負になっちゃった場合は仮数を大きく右シフトして、その分を指数に足してあげます。
そして、正規化シフタで指数が1となるところまで戻してあげると、サブノーマル数が出力できます。
具体的な実装は Github を確認してください。

by tom01h | 2017-11-12 12:43 | 論理設計の話 | Trackback | Comments(0)

FPU のフラグの話

FPU は演算結果と同時に例外フラグを生成する必要があります。
V-scale で使っている演算器の場合は
ビット0が不正確フラグで、演算中に精度落ちがあった場合に通知します。
ビット1がアンダーフローフラグで、こいつはとっても複雑なので下のほうで。
ビット2がオーバーフローフラグで、演算の結果が正規化数で表すことができないくらい大きくなった場合に通知します。
ビット3が0除算フラグで、除数0の除算を通知します。ただし、被除数も0の場合はエラーを優先します。
ビット4がエラーフラグで、例えば0×無限大などの答えを決められない場合に通知します。

アンダーフロー検出について。
アンダーフローはTininessか検出されて、かつ、精度落ちがあったときに通知されます。
Tininessの検出は丸め前検出と丸め後検出を選ぶことができますが、同一のアーキテクチャの中では一貫している必要があります。
Tininessの丸め前検出の場合は簡単で、指数の範囲、演算精度ともに制限なしで計算した結果が正規化数で表すことのできる最小の値よりも小さいときに検出されます。
RISC-Vで使うのは丸め後検出なのですが、こいつが厄介で、演算精度がフォーマットの定める桁数で、指数の範囲の制限なしで計算した結果が正規化数で… 以下同文です。
これの何が厄介かというと、サブノーマル数の演算結果を得るためには正規化シフトは指数を見て止める必要がありますが、Tininessの検出には正規化シフトを止めてはいけないという矛盾が生じます。
でも2つの正規化シフタを持つのは現実的じゃないし…
演算結果がサブノーマル数の場合はTininessを検出してよい。これで足りないのは指数を気にせず正規化シフトした場合の指数が0で、仮数が以下の1番上のケース。この値だけが、正規化シフトを指数に応じて止めてから丸めた時だけ最小値に昇格します。

Tininess 検出のときには丸めで桁上げがない。
1.11111111111|0xxxxxx |は有効桁数の境目
サブノーマル数の演算結果を得るために正規化シフトを止めちゃった場合は桁上げがある。
0.11111111111|10xxxxx |は有効桁数の境目
ただ、演算結果がサブノーマル数になる数を余分に検出しちゃっても構わないので、
0.xxxxxxxxxxxx|x0xxxxx |は有効桁数の境目
を検出すればよい。

この考え方で作った回路が Berkeley Test Float をパスするので、多分この考えで正しいかと思います。

by tom01h | 2017-11-08 20:26 | 論理設計の話 | Trackback | Comments(0)

無限大と非数に対応した FPU 乗算器の話

今回は無限大と非数に対応します。また、検証環境として Berkeley Testfloat を導入します。
無限大は大体の想像がつくと思いますが、単精度浮動小数の場合は指数としてとれる範囲が 1~254 であるので、その範囲で表現できる数を超えた大きな数は無限大として扱います。正の場合が 7f800000 で 負の場合は ff800000 です。
非数は、例えば無限大×0とかどうして良いか分からないときの演算結果として生成されます。一度生成されるとその後の演算で伝搬されます。ほかにもいろいろあるのですが、詳しく知りたい方は IEEE 754 を調べてみることをお勧めします。
乗算の場合には以下の優先順で判定します。
  1. 入力のどちらかが非数の場合には非数入力を伝搬する。
  2. 無限大×0は非数を生成する。
  3. 演算途中の仮数が0なら答えは0。
  4. 演算途中の指数が小さければ答えは0。
  5. 演算途中の指数が大きければ答えは無限大。
  6. どれでもなければ普通に計算。
次に Berkeley Testfloat ですが、簡単に言うと膨大に生成した入力データと Berkeley Softfloat という FPU シミュレーションソフトで生成した期待値を使って、FPU の検証を行うソフトです。ホスト CPU の検証をすることが主な目的?なのかもしれませんが、入力値と期待の演算結果を標準出力に表示するテストがあるのでそれを利用します。
例えば
$ ./build/Linux-x86_64-GCC/testfloat_gen -f32_mul
とか打つと、入力×2 期待演算結果 期待フラグの順に表示します。
8683F7FF C07F3FFF 07839504 01
00000000 3C072C85 00000000 00
こんな感じのがすごくたくさん出てきます。これを標準入力から受け取って、FPU 乗算器に演算させた結果と比較して、合否判定をするテストベンチを作成しました。まだサブノーマル数に対応していないので、↓みたいに実行してもらえるとサブノーマル関連のエラーを除くことができます。
$ {PATHto}/testfloat_gen -f32_mul | ./sim/Vfmul_1 | grep FAIL | grep -v " 00[0-7]" | grep -v " 80[0-7]"


by tom01h | 2017-11-05 19:41 | 論理設計の話 | Trackback | Comments(0)

正規化数だけに対応した FPU 乗算器の話

FPU 乗算の話です。FPU で扱うデータは正規化数以外にサブノーマル数や無限大から、数字じゃないデータまであるのですが、今回は正規化数に限った話。32bit で表現する単精度浮動小数で言うなら以下のようになります。
ビット31が符号を表す。
ビット30~23が指数を表す。正規化数の場合は1~254。
ビット22~0が仮数の小数点以下の部分を表す。ただし、仮数は 1.**** で表す。
で、F[31:0] の値は↓です。
((-1)^F[31]) * (1.F[22:0]) * (2^(F[30:23]-127)) ^はべき乗です
A[31:0]*B[31:0] を考えた時、
F[47:0]={1'b1,A[22:0]}*{1'b1,B[22:0]}
が仮数の掛け算の結果です。小数点以上が1桁、小数点以下が23桁の数同士の掛け算なので、小数点以上が2桁、小数点以下が46桁の乗算結果が得られます。つまり、F[46]の下に小数点があります。この結果を再度、浮動小数点フォーマットに戻すために、1.**** の形式に変換する必要があります。具体的にはF[47]の値によって分岐する必要があり、
F[47]==0の場合は桁上げ無しなので指数は A[30:23]+B[30:23]-127 になります。
仮数はF[45]が小数点以下第1位になって、[23]が最下位ビットでそれ以下は四捨五入をします。ただ FPU の四捨五入はちょっと特殊で、ちょうど真ん中、つまり[22]が1で[21:0]==0の時は、[23]=0となるように切り上げたり切り捨てたり、[23]によって動作が異なります。
F[47]==1の場合は桁上げ有りなので、指数は A[30:23]+B[30:23]-127+1 になります。
仮数はF[46]が小数点以下… 以下同文
だらだら言葉で説明してもわかりにくいので、Github を見てください。

by tom01h | 2017-11-04 21:25 | 論理設計の話 | Trackback | Comments(0)

V-scale に使っている乗算器の話

いよいよ V-scale に使っている乗算器の話です。
V-scale の乗算器は3入力加算器が64bit幅のものと32bit幅のものを1個ずつ持ちます。この2個の加算器を使って5サイクルで32bit乗算をします。後々同じ回路でFloatの乗算もしたいので、4サイクルで24bitの乗算もできるように準備をしておきます。
前回同様、32bit乗算器の部分積は下図のようになります。そして、赤枠で囲ってある部分がFloat用の部分積です。こっちは符号なし限定です。
f0054075_23284224.png
オレンジの部分を64bitの加算器で足しこみ、紫の部分を32bitの加算器で足しこみますが、その前に、右上部分を下にずらして考えます。
f0054075_00095435.png
そして、前回と同じ要領で赤枠内のオレンジと紫のそれぞれを3サイクルかけて1個ずつにまとめます。
f0054075_23520922.png
その後2サイクルは64bitの加算器だけを使って32bit乗算完了です。Github 更新しました。


by tom01h | 2017-10-27 23:57 | 論理設計の話 | Trackback | Comments(0)

繰り返し足しこんでいく乗算器の話

少ない資源を繰り返し使って乗算結果を得る話です。
今時こんなケチな設計はあまりやらないと思うのですが、V-Scaleに使った乗算器は結構しょぼいのでその説明の前哨戦です。
verilog 上ではちゃんと記述していませんが、X+Y+Z=S+C*2 となるような計算を桁上げなしで計算する回路をCarrySaveAdderと呼びます。ちなみに*2はただの1ビットシフトなので、回路上は何もないようなものです。
贅沢な乗算器ではこのCSAをたくさん使い、部分積が2個になるまで計算してから最後にキャリー伝搬のある加算器で積を求めます。
ここでは、CSA1段に加算器を付けて3入力の加算器として使います。
V-Scaleでは3入力加算器を64bit幅のものを1個と32bit幅のものを1個使っていますが、まずは簡単な64bitの3入力加算器1個のバージョンです。
まぁ、最初の1回は3個の部分積を足す。2回目以降はその加算結果に2個づつ部分積を足しこんでいく。というだけなのですが…
f0054075_22525223.png
32bit乗算では上のような感じにたくさんの部分積ができるのですが、最初の1回は最下位3個、つまり上の3行を足しこんで、
f0054075_22550229.png
2回目以降はその結果を4bitシフトしてさらに2個の部分積を足しこみます。
f0054075_22572798.png
ちなみに下にはみ出ているSと上位に拡張しているSは意味が違って(ややこしくてすみません)、はみ出ているのは×-1の時のインクリメントの意味で、上位に拡張しているのは前回説明した符号拡張の省略形です。
そして、一番下にはみ出している赤字のSですが、符号なしの場合は最上位が×-1倍のわけないので必要ないし、符号付きの場合はそもそも最上位の部分積が必要ないことがわかります。
あまり面白くないですが、Github 更新しました。


by tom01h | 2017-10-23 23:52 | 論理設計の話 | Trackback | Comments(0)