●FPU・ライブラリ進捗(3/14)
・今日はライブラリを見直しました
-繰り返しの回数を減らし、極力定数の計算を減らしました。
変更の影響のあったsin,cos,atanについてランダムな100万パターンの
テストを行いました。lib-03-14.mlで上げておきます。
●FPU今のところの仕様
entity FPU is
port(SRC1,SRC2 : in std_logic_vector(31 downto 0);
FUNC : in std_logic_vector(3 downto 0);
CLK : in std_logic;
START : in std_logic;
FIN : out std_logic;
OUTPUT : out std_logic_vector(31 downto 0));
end FPU;
・FUNCに対応したcomponentからの出力をOUTPUTに出力
・STARTはFPUを使用する場合最初の2clock間'1'に、それ以外は'0'
・CLKの立ち上がりにFINが'1'になる時点でOUTPUTから結果が出ている
・指数部が1~254が正規化数
・指数部が0の数はすべて0
・指数部が255の場合は
-仮数部が0のとき±∞
-仮数部が0でないときNaN
・以下では、
-+Inf = "0 11111111 00000000000000000000000"(+∞)
--Inf = "1 11111111 00000000000000000000000"(-∞)
-Nans = "0 11111111 10000000000000000000000"
とする。
・上記の非正規化数のサポートは一応行ったが、最終的には外した
・FADD
-動作確認済み。
-オペランドの符号が異なる場合は適切な処理後、FSUBに投げる。
-仮数部を Gbit切り上げ により丸め
-(±0) + (±0) = +0(複号任意)
・FSUB
-動作確認済み。
-オペランドの符号が異なる場合は適切な処理後、FADDに投げる。
-仮数部を Gbit切り上げ により丸め
-2つのオペランドが同じ値である場合には、+0を出力。(IEEE 754に準拠)
-(±0) - (±0) = +0(複号任意)
・FMUL
-動作確認済み。
-仮数部を Gbitの切り上げ により丸め
-オペランドの少なくとも一方が±0のとき、出力は+0
・FLESS
-trueなら"11111111111111111111111111111111"
falseなら"00000000000000000000000000000000"を返す。
- -0 < +0 とする。指数部8bitが0であれば同じ0.0として扱う
-動作確認済み。
・ITOF
-Gbit切り上げ
・FTOI
-小数点以下四捨五入
-結果がsigned intの最大値(最小値)を超える場合はINT_MAX(INT_MIN)を返す
- +0.0 -> +0 , -0.0 -> +0
-NaN を受け取った場合は +0 を出力
・FDIV
-4bitずつの引き算の繰り返しでCLKを使わず実装
-この実装がまずい場合は作り直す
-0で割ったときにはNans(="0 11111111 10000000000000000000000")を返す
-丸めは今のところは行わない(Gbit、Rbitは作ってあるので必要ならすぐ実装できる)
-(±0) ÷ (±0) = +0 (複号任意)
-(±Normal) ÷ (±Inf) = +0 (複号任意)
-(±0) ÷ (±Normal)= +0 (複号任意)
-(±0) ÷ (±Inf) = +0 (複号任意)
-±0で割る場合、出力の符合はSRC1の符号と一致
->(-5) ÷ (-0) = -∞
-結局不使用
・SQRT
-2bitずつ筆算の様に計算する方式
-入力が負(-0含む)ときにはNans(="0 11111111 10000000000000000000000")を出力
-仮数部をround evenで丸め
-結局不使用
・FINVSQRT
-SQRTとFDIVで計算ニュートン法により実装
-入力が負のときの出力は絶対値を入力としたものとなる
-入力が0.0のときは0.0を出力
-仮数部をround evenで丸めGbit切り上げ
・INV
-ニュートン法で実装
-仮数部を Gbit切り上げ により丸め
-結局不使用
下記の表について、非正規化数のサポートは最終的に行わない予定
SRC1 |
SRC2 |
| |
FADD |
FSUB |
FMUL |
FDIV |
FLESS |
Normal |
Normal |
| |
Normal |
Normal |
Normal |
Normal |
t or f |
Normal |
+Inf |
| |
+Inf |
-Inf |
+Inf |
+0 |
true |
Normal |
-Inf |
| |
-Inf |
+Inf |
-Inf |
+0 |
false |
+Inf |
Normal |
| |
+Inf |
+Inf |
+Inf |
+Inf |
false |
-Inf |
Normal |
| |
-Inf |
-Inf |
-Inf |
-Inf |
true |
NaN |
Normal |
| |
Nans |
Nans |
Nans |
Nans |
Nans |
Normal |
NaN |
| |
Nans |
Nans |
Nans |
Nans |
Nans |
+Inf |
+Inf |
| |
+Inf |
Nans |
+Inf |
Nans |
Nans |
+Inf |
-Inf |
| |
Nans |
+Inf |
-Inf |
Nans |
false |
-Inf |
+Inf |
| |
Nans |
-Inf |
-Inf |
Nans |
true |
-Inf |
-Inf |
| |
-Inf |
Nans |
+Inf |
Nans |
Nans |
NaN |
±Inf |
| |
Nans |
Nans |
Nans |
Nans |
Nans |
±Inf |
NaN |
| |
Nans |
Nans |
Nans |
Nans |
Nans |
NaN |
NaN |
| |
Nans |
Nans |
Nans |
Nans |
Nans |
SRC |
| |
SQRT |
FINVSQRT |
FTOI |
INV |
+Normal |
| |
+Normal |
+Normal |
+integer |
+Normal |
-Normal |
| |
Nans |
Nans |
-integer |
-Normal |
+Inf |
| |
+Inf |
+0.0 |
INT_MAX |
+0.0 |
-Inf |
| |
Nans |
Nans |
INT_MIN |
+0.0 |
NaN |
| |
Nans |
Nans |
0 |
Nans |
+0.0 |
| |
+0.0 |
Nans |
0 |
+Inf |
-0.0 |
| |
Nans |
Nans |
0 |
-Inf |
○過去の進捗
●3/13
・buyobuyon氏にご指摘いただいた部分を訂正しました。
-訂正した部分は、fpu-sim-03-13.zipにまとめてあげておきます。
・FADD,FSUBがまずいようなのでしばらくソースを見てみます
・とりあえず現時点でのFPUのソースを上げておきます。(fpu-03-13.zip)
-サイズ27%、Slices 1277/5120(24%)
-最長の遅延時間は
1クロック命令で16.500ns
2クロック命令で29.042ns
5クロック命令で91.188ns
- シミュレート関数の方も、変更に対応しておきました。
一応、buyobuyonのページにあげておきました(raichu_fpu.c)。
FADDとFSUB…、本当に何なのでしょうね?
何回か書き換える際にチェックしてきたのですが、
特にまずそうな点は見つからないのですよね…。 -- buyobuyon (2007-03-13 19:39:15)
- 入力が0.0の場合のあらゆるパターン(+-や入力のどちらが0.0か)と
入力が0.0でない場合の符号についてのあらゆるパターン(加算器、減算器どちらを使うかや
どちらの入力の絶対値が大きいか)について、手計算とModelSim上の波形のテストをしてみました。
でもやっぱり問題は見つからないんですよね…。
シミュレート関数のほうも見てみます。 -- tsuy (2007-03-13 19:56:29)
- 試しに、符号が同じ値同士の加算の丸めをいわゆる銀行丸め方式に
してレイトレを実行してみたのですが、結果は変わらず…。
となると精度とかの問題ではなく、何らかの例外を見逃していることに
なると思うのですが…、何だろう…。
銀行丸めのやり方を間違えた可能性もありますが…。 -- buyobuyon (2007-03-13 20:10:50)
- ごめんなさい、とんでもない勘違いをしていたようです。
私のシミュレート関数で、C言語の論理シフトの法を考慮していなかったのが悪かったようです。
いろいろ試してみたら、何か非常に複雑なことになっていて、
(0xffffffffU << 32)のようにシフト量が定数の場合は、(定数 mod 256)だけ左シフトして、
(0xffffffffU << p)のようにシフト量が変数の場合は、(変数 mod 32)だけ左シフトするみたいです。
しかもひどいことに、p = 43; (0xffffffffU << p)のようなことをすると、
定数畳み込みされるらしく、(43 mod 256)だけ左シフトされる、すなわち値は0になるみたいです…。
いろいろとお手数おかけいたしました。
とりあえずシフト部分を全て修正してみます。 -- buyobuyon (2007-03-13 20:56:18)
- なんとも複雑な文法ですね…
ともあれ、白い点の問題は解消されたようで何よりです。 -- tsuy (2007-03-13 21:32:57)
- なんとも複雑な…。
というか、そこに気づいたbuyobuyon氏もすごいですね…。
お疲れ様ですm(_ _)m -- yastak (2007-03-13 23:55:28)
●3/12
・ITOFなど、Gbitの切り上げを行う命令で指数部が1増える場合の処理を忘れて
いたので追加しました。
-ITOFでは遅延時間が18.7nsにまで増え、どうなることかと思いましたが、
その後制約なしで16.3nsにまで減りました。いいアイデアをくれたbuyobuyon氏に
感謝です。これで1クロックで動くといいのですが。
-FMULの遅延時間も増えましたが、同じ要領で16ns以内に収まりました。(テストも終了)
FADD,FSUB,FINVSQRTについては明日高速化を行う予定です
- 一応、確認を。
あげていただいたfpu-sim-03-12のReadme.txtに
「FTOI,FMULは指数部の処理に加え高速化も行い…」
と書かれていますが、このFTOIってたぶんITOFの間違いですよね? -- buyobuyon (2007-03-13 11:05:55)
- itofですが、SRC(31)='1'のときにSRC_absを求める場合、
先に最上位に'0'を付加してから、+1するのでないと、
0x80000000U(INT_MIN)が与えられたときに、途中でオーバーフローするのでうまくいかないのでは? -- buyobuyon (2007-03-13 11:13:27)
- あ、ちなみに↑に関連して。
こちらでC言語で書いているときには、in1の絶対値を求めるときに、
mask = ((signed int)in1) >> 31;
in1_abs = (in1 ^ mask) - mask;
ということをやっています。
(signed int)とかやっているのは、直後のシフトを算術シフトにするため。
maskはin1の符号が正ならビット列0000...0、負なら1111...1となるので、
in1が正ならin1_absはin1, in1が負なら(not in1) + 1となります。
ハードでこの方針をとると速いのかどうかはわかりませんが、まぁ参考までに。 -- buyobuyon (2007-03-13 11:29:56)
- 一応、シミュレート関数の修正が終わったのですが、
FINVSQRTに関して気になる点がありまして。
入力が、指数部が0で、仮数部が0でないような値の場合でも、
もし計算の結果、nextXが"111111111111111111111111"と
なってしまうことがあれば、GBit切り上げによって、指数部に1足されて
出力が0でなくなってしまうような気がするのですが…。
もし支障がなければ、やはり入力の指数部が0なら出力は(others => '0')に
してしまった方が良いと思うのですがいかがでしょう。 -- buyobuyon (2007-03-13 13:53:17)
- ご指摘ありがとうございます。
一つ目の件についてですが、書き間違いです。すみません。
ITOFとFINVSQRTについては修正します。 -- tsuy (2007-03-13 15:49:16)
- ええと、FINVSQRTについてもう一つ。
Zero = '1'のときには、MANTを0にするのでなく、
OUTPUTを '0' & EXP & "000...0"にするようにしてください。
引数が0のときと同様、EXP部が+1されてしまうことがあるようです。
EXP部が+1されるなんてこと、ごく稀にしか起こらないだろうと思ったら、
結構な頻度で起こるようで、レイトレ画像の変化がすごかったです。 -- buyobuyon (2007-03-13 16:57:23)
- 了解しました -- tsuy (2007-03-13 17:33:14)
●3/11
・buyobuyon氏から指摘・要望等があった部分を書き換えています。
とりあえず最低限必要そうなもの(FLESSの0.0の扱いやFINVSQRTへの0.0入力、ITOFの修正)を優先します。
・FPU外部からの入力ですが、FINが'1'として出力されるまでは
-SRC1,SRC2,FUNCはそのまま
-STARTは最初の1クロックのみ'1'、(2クロック以上かかる命令では)以降の
クロックは'0'でお願いします。
-FINは1クロック間はずっと同じ値をとります。連続して1クロック命令が
入力された場合は、ずっと'1'のままになります
・書き換えが終わった部分
-ITOFの入力が0のときのバグを修正
-ITOFの出力を四捨五入で丸め
-FLESSの+0.0,-0.0を同一視
-FINVSQRTの入力が0.0のときの出力を0.0に(ただし、仮数部は0でない)
-FMULの丸めをGbit切り上げに
-FADD,FSUBの丸めをGbit切り上げに
-FINVSQRTの丸めをGbit切り上げに(戻す可能性あり)
-FTOIの改良
・書き換えた命令のうち、
-ITOF,FLESS,FINVSQRT,FTOIについて、手動で入力が0の場合のテストを行いました。
-全命令について、25万パターンの入力に対するテストを行いました。
・出力のタイミングも恐らく大丈夫だと思うので、使えると思われるFPUがとりあえず出来たことになります。
-サイズは27%、Slicesは1243/5120(24%)
-各演算部分は組み合わせ回路、遅延時間は
1クロック命令で最長が16.094ns
2クロック命令で26.712ns
5クロック命令で91.170ns
・現時点でのFPUのソース(fpu-03-11.zip)をこのページに上げておきます。
- FPUを乗せてコンパイルしてみました。
乗算器があふれたものの(cf.yastak->13個使用)
ALUのDivを変えたらおさまって、
コンパイルは通りました!
Device utilization summary:
Number of External IOBs 94 out of 432 21%
Number of LOCed External IOBs 94 out of 94 100%
Number of MULT18X18s 33 out of 40 82%
Number of RAMB16s 1 out of 40 2%
Number of SLICEs 2241 out of 5120 43%
Number of BUFGMUXs 1 out of 16 6%
あと、Warningの一つで、
FF/Latch <CountClock2_3> is unconnected in block <FINVSQRT_n>.
というのを発見したのですが、大丈夫ですか? -- yastak (2007-03-12 00:52:55)
- Warningは多分、ラッチで保持された信号が使われていない?といった意味かと思います。
実際その信号は使わないので、おそらく大丈夫かと思います。
乗算器が1つ足りないようですね。
FINVSQRTに使うのを1つ、精度を落とさないように減らせるかもしれないし減らせないかも
しれないという感じなのですが、DIVの方はどうですか? -- tsuy (2007-03-12 01:37:38)
- ええと、FPU変更部分をシミュレート関数の方にも反映させておきました。
それで、1つ気になることがありまして。
ITOF/FINVSQRT/FMUL/FADD/FSUBと、
今回切り上げ処理が追加されましたが、
これって、"1111...1"というようなビット列が与えられたときに
この切り上げ処理をすると"0000...0"になってしまいませんか?
一応、ITOFに関しては、実際に(2^25)-1を引数として与えたときに、
最上位ビットの上への繰り上がりが反映されずに間違った値が出力される
ことを確認したのですが。 -- buyobuyon (2007-03-12 07:52:22)
- 丸め方式を変えた新しいバージョンでレイトレ実行してみましたが、
やっぱり白い点ができてしまいますね。
おそらくFADD/FSUBに気づかないバグ(私がシミュレート関数を
作成した段階でできたバグかもしれません)があるか、もしくは
誤差の蓄積が問題なのだと思うのですが…。
とりあえず、各プログラムの整理・アップが終わったらもう一度見てみますね。 -- buyobuyon (2007-03-12 09:43:54)
- 乗算器はDIVを書き換えた現時点で33個(cf.Device Utilization summary)なので
になったので大丈夫かと思います。
今後書き換える必要もありそうですが…。 -- yastak (2007-03-12 11:00:44)
- FADD,FSUB,FMUL,FINVSQRTあたりは、仮数部が"111…1"になるときに
切り上げを考慮して指数部を1増やすという機能があったのですが、
切り捨てにしたときにはずしたのを忘れていました。
今日ITOFも含めてその機能を戻してみます。
サイズはともかく遅延時間の増加が怖いですが…
乗算器は足りると考えてよさそうですね。安心しました。 -- tsuy (2007-03-12 11:24:31)
●3/9
・パイプライン化は必要なかったようなので戻します
-FINVSQRTが6clockから5clockになるので有利、サイズも減る
・FPUのentityにSTART,FINの信号を追加します
詳しくは下の仕様をご覧ください
2clock以上かかる命令について、FPUが処理を行っている間(2から5clock間)はSRC1,SRC2は変化せず、
CLKは通常通りのクロック、STARTは最初の1clockのみ'1'で以降は'0'、
FUNCは最初の1clockのみOPCODEを示し、次以降のclockは"1111"という入力を想定しています
特にFUNCはこのようにして頂けると実装が簡単になるのですが、問題ありませんよね?
すみません、混乱しました。今日中に実際に動かせるものを仕上げる予定でしたが、START,FIN
を入れるのが思いのほか難しいので、また後日にします。
・サイズに余裕が出来れば丸め方式を元に戻すかも
・基盤について、harryさんとともに配線を行い、教官の方からOKをいただきました。
決めてもらうこともあるので、次に皆集まるときに半田付けを行う予定です。
・INVの求め方について、考えてみましたがいい案は思いつきませんでした。
(inv y)をライブラリでif文を使って処理するのもだめですよね…
- if文で処理する → 2命令 + 遅延スロット増 なので、
たぶん現在用いている、ビット操作で符号ビットを付加するやり方の方がまだ速いかと。
まぁ正しい値は求まるので、とりあえずINVはこのままでいきましょう。
また何か思いついたらお願いします。 -- buyobuyon (2007-03-09 23:12:19)
- harryさんのところにあるシミュレータFPU部分の実装が、
Cライブラリを用いたものなので、
とりあえずうちの班のFPUの演算精度でレイトレ画像を生成したときにどの程度ノイズが入るか
(もしくは入らないか)をシミュレータ上でテストできるよう、
うちの班のFPUの挙動をビット列操作でそのままシミュレートした関数をこれから作成します。
FADD, FSUB, FMUL, FINVSQRT, FLESS, FTOI, ITOFを一通り実装した方が良いかと思うのですが、
このページにあるvhdlソースファイルを元にすれば良いですか?
あと、精度のテストに使ったPerlのソースファイルがあれば見せていただきたいのですが。 -- buyobuyon (2007-03-10 13:42:08)
- 現時点でのソースをまとめ直して上げますので、少々お待ちください。 -- tsuy (2007-03-10 14:09:49)
- あ、お願いします。 -- buyobuyon (2007-03-10 14:22:07)
- アップロードしました。
fpu-sim.zipがそれです。
FINVSQRTあたりは、シミュレート関数作成が少々面倒かもしれません。 -- tsuy (2007-03-10 14:44:46)
- アップロードしたソースのうち、finvsqrt_table.vhdがあまりに
読みにくいので修正したものを上げておきました。 -- tsuy (2007-03-10 14:58:14)
- ありがとうございます。
関数作成、やっぱり結構時間かかりますかね…。
関数作成にかかる時間も気がかりですが、あまり複雑な関数だと
シミュレータで実行する際にひどく時間がかかりそうで…。
でも、やっぱりシミュレータ上でテストしておいた方が良いですよね…。
テストするなら、一番誤差を生じやすいfinvsqrtをテストしないと仕方がないですし…。
まぁ、とりあえずやってみます。 -- buyobuyon (2007-03-10 15:02:02)
- すみません、手伝えたらいいのですが締め切り間近の連続系の課題が残ってまして…
関数作成頑張って下さい。 -- tsuy (2007-03-10 15:46:13)
- あ、大丈夫ですよ。
私は前に時間をいただいていたので最低限の課題は出し終えていますし。
連続系の方を優先してください。
ひとつだけ確認しておきたいのですが、
FPUの回路はループのない組み合わせ回路と考えてしまって大丈夫ですよね? -- buyobuyon (2007-03-10 16:13:36)
- ありがとうございます。
FPUの計算部分はパイプライン化していないので完全にループなし組み合わせ回路です。
f_adsb.vhdとfinvsqrt_n.vhdでクロックを読んでますが
計算にはかかわらないので無視して大丈夫かと思います。
また、FINVSQRTでは、
finvsqrt_repeat_1.vhdの前半が初期値の表引き、
その後半とfinvsqrt_repeat_2.vhd、finvsqrt_repeat_3.vhdが繰り返し計算1回目、
finvsqrt_repeat_4.vhd、finvsqrt_repeat_5.vhd、finvsqrt_repeat_6.vhdの前半が繰り返し計算2回目、
finvsqrt_repeat_6.vhdの後半が整形して出力
となっているので、同じコードで使いまわせるはずです。 -- tsuy (2007-03-10 16:52:57)
- 了解です。
演算量を少なくしようとすると結構大変…。 -- buyobuyon (2007-03-10 20:09:36)
- 気になったことはここに書き込んでいきますので、後で余裕ができたら見てみてください。
ちなみに、こちらはfaddが終わったところです。
・FSUB_S_2のNeqは無くても(常に引数が異なるものとしても)良いのでは?(Neqが'0'のときは呼び出し元でEqualが'1'となり、0x00000000Uを返すようになっているから) -- buyobuyon (2007-03-10 20:53:38)
- ・FMULの整数乗算の分割の仕方、highのbit数を増やしてlowのbit数を減らし、
low×lowを無視するようにすれば、乗算器1個不要かな…、なんて思ったのですが。
ただ、出力値は現在のものから1変化する場合があるかもしれませんね
(良くなる場合も悪くなる場合もあるはず…、たぶん)。 -- buyobuyon (2007-03-11 00:37:00)
- ご指摘ありがとうございます。
SUBの方は余裕があったら高速化したいと思っているので、そのときに試してみます。
MULの方は、その分割はしたのですが速度だったかサイズだったかが悪くなったので
現在の分割に落ち着きました。掛け算の分割はほかの部分でも使うので、いろいろな
パターンを試しました。 -- tsuy (2007-03-11 00:55:11)
- あ、分割の仕方を変えてしまうとかえって遅くなるのですか。
普通に考えたら均等なビット幅で分けるのが一番速そうなものですが…、
FPGAって難しいですね。 -- buyobuyon (2007-03-11 01:31:42)
- バグ…、かな?
ITOFで引数が0のときの例外処理を忘れているので、
ITOF(0)が1.0になってしまいます。
とりあえず、シミュレート関数の方では、
関数のトップで、引数が0だったら0x00000000Uを返すようにしておきますね。 -- buyobuyon (2007-03-11 04:16:46)
- ああー バグですね… なんと初歩的な…
とりあえず明日テストしてバグであることを確認して直そうかと思います。
何だかデバッグしてもらっている状態になってしまってすみません -- tsuy (2007-03-11 04:47:17)
- あ、いえいえ。
こちらとしても、精練されたFPUのソースコードを読むことで、
非常に勉強になっていますので。
自分の側の部分にも、ちょっとした問題を見つけまして…。
fsqrtで引数が0のときにどうするかを考えていなかったのですが、
(fsqrt x) → (finv (finvsqrt x))
(finv x) → (finvsqrt (x *. x)) xor (x and 0x80000000U)
としているので、もし(finvsqrt 0)が0と定義されていればこのままでOK、
逆にこのように定義されていないと、sqrtで正しい値を返すためには
余計な命令を付加する必要が生じてしまい、sqrtの効率が落ちてしまいます。
また、(finvsqrt x) → (finv (finv (finvsqrt x)))とならなくなるので、
最適化がしにくくなります。
そのため、もし支障がなければ、(finvsqrt 0)が0となるようにFPUの方で
してもらいたいのですが、いかがでしょうか?
(まだfinvsqrtのソースは読んでいないので、もし既にそうなっていたらすみません。) -- buyobuyon (2007-03-11 05:15:04)
- 了解しました。
遅延時間とサイズが増えるのが怖いですが、実装自体は簡単なので明日(というか今日)やってみます。 -- tsuy (2007-03-11 05:40:43)
- よろしくお願いします。
元の回路が大きいからそれほど変化しないと思う(思いたい)のですが…。
あと、また気づいたことなのですが
(あ、夜遅いので気にせずにお休みになってくださいね。勝手に書き込んでいるだけなので。)、
ftoiの引数が0の時の例外処理なのですが、
非正規化数を実装していた頃の名残が残っているようで、
やや冗長になっているような気がします(返す値は正しいと思いますが)。
たぶん、INT_abs_bufを得るための式の0に関する例外処理を外し、
OUTPUTを得るための式における、引数が0であるかの判定式をEXP=0に
変えても大丈夫だと思います。 -- buyobuyon (2007-03-11 05:46:58)
- 確かにそうですね。これも今日書き換えてテストしてみます。
何というか、自分ひとりだと気付かないところがやっぱり多いものですね。
(ちなみにまだ起きているのは未だに連続形が終わらないからだったりします) -- tsuy (2007-03-11 06:03:29)
- ならなおさら、こんな書き込み見ていないで連続系に専念してください!
後で忘れないように書き留めているだけですので。
一応、続きを書いておきます。連続系が終わってから読むこと。
先ほどのFTOIの話ですが、おそらく引数が0.0である場合の例外処理自体が
いらないような気がします。
引数が0.0なら、Zeroが'1'、故にINT_abs_roundedが0となり、
最終的に引数が+0.0の場合も-0.0の場合もOUTPUTは0になるはずです。
また、Zeroが'1'のときは必ずOUTPUTが0になるので、途中式でのZeroの使用を省き、
OUTPUTを求める際の場合分けでZero='1'なら0を返すようにすると
良いのではないでしょうか。
って、おそらくもとから速い&サイズの小さいFTOIを
最適化してもあまり意味はないのですよね…。 -- buyobuyon (2007-03-11 06:20:12)
- 連続系終わりましたー
いえね、プログラムの結果が出るまでの待ち時間が中途半端に長いもので、
ついついここを覗いてしまうのですよ。
夜が明けたようなのでこれから寝て、目が覚めたらFPUの修正と改良を
行おうかと思います。
buyobuyonさんもあまり無理はしないでくださいね -- tsuy (2007-03-11 07:32:18)
- あ、お疲れ様です。
そういえば常微分方程式とかは結構時間がかかりましたね。
ゆっくりお休みになってくださいね。
私ももう少ししたら休みます。
ええと、一つ戻って、ITOFのことなのですが、
四捨五入で丸めないとコンテストルールに反するような気がします。
まぁ、2^24を超えるような値を入れてITOFすることは稀だとは思いますけど…。 -- buyobuyon (2007-03-11 07:52:37)
- 見たところ、 (-0.0) < (+0.0) としたことは
特にFLESSの高速化につながっているわけではなさそうですね。
FLESSの単純化のために-0.0の導入を提案したのですが…。
たぶん、指数部が0なら全て0.0、という仕様になって、
0.0を特別視する必要が出てきたからですよね。
それならいっそのこと、もう-0.0と+0.0を区別せず、
符号にかかわらず、指数部が0なら+0.0としてしまいませんか?
まだfinvsqrtは見ていませんが、それ以外は-0.0を+0.0に変えても特に
問題は生じないはずですし、
ちょうど、2種類の0.0があったことでFISNEGの仕様をどうすればよいか
決めかねていたもので(-0.0より真に小さければtrueとするのが妥当に見えるが、
それではコンテストルールを満たさないため)、 -0.0 = +0.0 とした方が
こちらとしては助かるのですが。 -- buyobuyon (2007-03-11 08:27:00)
●3/8
・パイプライン化は多分終了、現在テスト中
・同じ命令がずっと続く場合(1クロック目:FADD、2クロック目:FADD、…など)
のテスト終了
・複数の命令が混じる場合はまた今度
・シミュレータ上でうまくいっても実機でうまくいかないかもしれないので不安です
・FINVSQRT:6クロック、FADD,FSUB:2クロック、その他は1クロック
・複数の命令の結果が重なる場合(例えば1クロック目にFADD,2クロック目にFMULを入力した場合の
3クロック目の立ち上がりの出力)の優先順位
-finvsqrt>fadd,fsub>(その他の1クロック命令)
- 私の方のページにも書いたのですが、
この前決めた方針ではy<0のときに(x /. y)が正しく求まらないことに先ほど気づきました。
最適化のことを考えて、できれば(x *. (inv y))として(x /. y)を求めるようにしたいのですが、
なかなか良い(inv y)の求め方が思い浮かばないもので…。
もし良い方法が見つかったら教えてください。
とりあえずは、( (invsqrt (y *. y)) xor (y and 0x80000000U))として求めるようにしておきます。
(こうすると、引数が負のときに値の保証が要らないsqrtで損をするのがもったいないのですが…)。 -- buyobuyon (2007-03-08 23:17:59)
- 確かにそうですね。
ライブラリで
let rec fdiv x y = if y < 0.0 then …
とするのもよくなさそうですね。
しばらく考えてみます。 -- tsuy (2007-03-08 23:38:23)
- えと、CPUのロジックはパイプライン2段で、
n番目の命令を実行している最中(exw)に、n+1番目の命令を読み込む(fdr)、
という仕様になっています。
n番目の命令の実行・書き込みが終了するまでn+1番目の命令はexwの回路にはやってこないので、
mクロック目でFADDがきて、m+1クロックでFADDがくる、といったことは生じ得ないのですが…。
すみません、今まで私が「パイプライン」の意味を誤解していたようです…。
FPU命令に複数クロックかかるのはまったく構わないのですが…。 -- yastak (2007-03-09 11:53:48)
●3/7
・FINVSQRTをパイプライン化中
-6段にする予定だが、2段目と5段目が20nsで収まるか分からないので8段になる可能性も
-分割終了 想定通りに動くか明日テスト
-サイズは意外と大丈夫でした。現時点で26%
・FADD,FSUBの動作チェックもまだ
・25MHzならこのページに上げたFPUのファイルで動かせるつもりだったが、多分ミスを発見
●3/6
・ライブラリfloorができたのでこのページに上げておきます
・コンパイルも(多分)通ったし、テストも一応問題ないはず
・FADD,FSUBをパイプライン化中
- floor実装、ありがとうございます。
何かテストが大変だったみたいですね。
とりあえずこれでmin-rtを実行するための道具は全てそろったはず…。
明日、シミュレータのバグ(たぶん私が記述したメモリ操作部あたりに問題があるのだと思うのですが)を
チェックして、直ったら実行してみましょうね。コンパイラのバグが露呈しそうで怖い…。 -- buyobuyon (2007-03-07 00:46:11)
●3/5
・高速化を行った全命令についてテスト終了
-テスト方法は年末に行った、ランダムな100万パターンの入力に対しての出力と
Perlで行った計算の結果を比較する方法
-FADD,FSUB,FMUL,FTOI,ITOF,FINVSQRT問題なし
-FLESSのVHDLとテストプログラムにミス(高速化部分とは関係なし)発見
また、高速化も結果にあまり自信がないのでやめておきました
FLESS:64,6.296ns
・テスト結果待ちの間にライブラリのfloorを作っています
-他の数値計算ライブラリに比べて簡単に出来ると思いきや、
困ったことに我々が使うint_of_floatが四捨五入なのに対して、
OCamlのint_of_floatは切捨てらしい→テストが大変そう
・入力xと0.5を足したものに対して切捨て版int_of_floatを適用すると、
-入力が非常に小さいとき(x+0.5=0.5となるとき)
・x>0.0とすると、floor(x)=0.0となればよい。
float_of_int(int_of_float(x+0.5))=0.0となり、
x>0.0なので出力は0.0となり、OK
・x<0.0とすると、floor(x)=-1.0となればよい。
float_of_int(int_of_float(x-0.5))=0.0となり、
x<0.0なので出力は-1.0となり、OK
-入力が大きいとき、
・|x|≧2^(23)ならばint_of_floatは使わないので問題なし
・x<2^(23)で最大のfloat数となる2^(23)-0.5について、
floor(x)=2^(23)-1となればよい。
float_of_int(int_of_float(x+0.5))=2^(23)となり、
2^(23)-0.5<2^23なので出力は2^(23)-1となり、OK
・x>-2^(23)で最小のfloat数となる-2^(23)+0.5について、
floor(x)=-2^(23)となればよい。
float_of_int(int_of_float(x-0.5))=-2^(23)となり、
-2^(23)+0.5>-2^23なので出力は-2^(23)となり、OK
・以上から、我々の使う四捨五入のint_of_float(x)は、
OCamlの切捨てのint_of_float(x+0.5)(負ならint_of_float(x-0.5))
と同じものと考えてよいはずなので、
テストはOCamlの0.5加えたもの(引いたもの)で行い、このページに上げるのは0.5
加えてないもの(引いてないもの)にします。
●3/3
・FINVSQRT:403,87.558ns->329,87.858ns
●3/2
・ITOF:204,15.006ns->129,13.797ns
-大幅に書き換えたので実行テスト必須
・FPU全体のスライス数:1265->1226
・FADD:426,26.243ns->412,26.193ns
-肝心のFADDがあまり速くならない…
・FINVSQRT
-4時間かけて成果なし
- 何というか、大幅に速くなっていますね…。 -- buyobuyon (2007-03-02 13:17:26)
- まだ実行テストをしていないので、ぬか喜びになる可能性もありますけどね。
パイプライン化でどの程度サイズが増えるか分からないので、そこも不安です。
みなさんも順調に進んでいるようで何よりです。 -- tsuy (2007-03-02 13:36:19)
この後のコンパイラ組み込み関数に関する相談は
こちらに移動しました。(buyobuyon)
●3/1
・FTOI:170,13.778ns->166,12.212ns->139,11.432ns
・FMUL:58,17.356ns->52,14.743ns
-指数部にずれが生じるかも
・FINVSQRT:404,87.558ns->403,87.558ns
●2/27
・FADD,FSUBの高速化中
・FADD,FSUB,FMUL,FLESS,FTOI,ITOF,FINVSQRT個別のサイズの合計よりも
すべてまとめたサイズの方が予想外に大きいためサイズオーバーになりそうという事と、
5~6時間FADDの高速化をしているのですが0.001nsも速くならないので、とりあえず
FADDはパイプライン化して2clockで動かすという方向で進めようかと思います
FADDの高速化は余裕があったらということで
・現在、多少遅くなってもいいのでサイズを小さくする方向でソースを書き換えています
FADD:546,26.151ns->536,26.149ns->426,26.243ns
-ulpの下の1bitの切り上げにより丸めを行っていましたが、切り捨てにするとなぜか大幅にサイズを
減らせるようなので、丸め方式は切り捨てにします
FMUL:80,17.396ns ->58,17.356ns
-丸めを切り捨てにしました
FINVSQRT:430,90.781ns ->404,87.558ns
-丸めを切り捨てにしました
FTOI:171,15.159ns->170,13.778ns
-なぜかNaNのサポートが残っていたので外しました
FLESS:64,7.482ns->33,3.627ns
-指数部の8bitが"00000000"の数を0として扱っていました
(例えば"00000000011111111111111111111111"も"00000000000000000000000000000001"も
"00000000000000000000000000000000"と同等として扱っていた)
が、この特別扱いをやめて単純に指数部と仮数部をあわせたものを比較するようにしました
FPUの他の命令の出力で指数部が0になるものは仮数部もすべて0となっている は ず
なので問題はないかと思うのですが、大丈夫ですよね?
・これらの書き換えに対しての動作確認をする必要があるので、近いうちに大学に行きます
・非常にサイズが厳しいです…
●今後の予定や疑問点など(2006)
・FPUは今後は高速化・省サイズ化
・50MHz・1clockに収まらないものはパイプライン化を行う
・18×18の乗算器の数が足りないので、現時点ではINVとFINVSQRT両方をハードで実現できない
-ニュートン法以外の方法を探すか諦めてソフトウェア実装するか
-乗算器を使わないとなるとサイズが大きくならざるを得ないと思うので、諦める気配が濃厚
・恐らく1月中間発表向けにレイトレを動かす段階では50MHz・1clockでは動かない
-時間的にパイプライン化などをする余裕はなさそう
-必要最低限の命令は25MHz・1clockで動くはずなので、1月は25MHzにしていただけるとありがたい
-この段階ではINV,FINVSQRTはソフトウェアで動かすつもり
・ライブラリはどんな命令を実装しましょうか?
-sin,cos,atan,INV,FINVSQRTの他には?
最終更新:2009年06月07日 10:58