HaskellでFPGAの最小のサンプル
入力を反転するだけのコード
$ stack exec -- clash --interactive CLaSHi, version 0.99 (using clash-lib, version 0.99): http://www.clash-lang.org/ :? for help Clash.Prelude> :cd ../worka Clash.Prelude> :! ls Clash01.hs Clash.Prelude> :l Clash01.hs [1 of 1] Compiling Clash01 ( Clash01.hs, interpreted ) Ok, modules loaded: Clash01. *Clash01>
Verilog生成
*Clash01> :verilog Loading dependencies took 2.500923s Compiling: Clash01.topEntity Applied 64 transformations Normalisation took 1.056631s Netlist generation took 0.006391s Compiling: Clash01.testBench Applied 219 transformations Testbench normalisation took 0.550645s Testbench netlist generation took 0.030401s Total compilation took 4.170923s *Clash01> :! ls Clash01.dyn_hi Clash01.dyn_o Clash01.hi Clash01.hs Clash01.o verilog *Clash01> :! tree . ├── Clash01.dyn_hi ├── Clash01.dyn_o ├── Clash01.hi ├── Clash01.hs ├── Clash01.o └── verilog └── Clash01 ├── Clash01_testBench │ ├── Clash01_outputVerifier.v │ ├── Clash01_stimuliGenerator.v │ └── Clash01_testBench.v ├── Clash01_testBench.vcd ├── Clash01_topEntity.manifest ├── Clash01_topEntity.v └── main.exe 3 directories, 12 files *Clash01>
波形ファイルを作るためにテストベンチを修正
波形ファイル生成
$ find . -name "*.v" | xargs iverilog -o main.exe $ ./main.exe VCD info: dumpfile Clash01_testBench.vcd opened for output.
波形ファイルの確認
ターゲット指定のcabalのrepl
cabalファイルで複数のターゲットを作り、cabal repl
すると起動ができなくなります。
$ cabal repl cabal: The 'repl' command does not support multiple targets at once. $
また、ターゲットの名前が重複すると起動しません。
$ cabal repl myprotobuf cabal: Ambiguous build target 'myprotobuf'. It could be: exe:myprotobuf (component) lib:myprotobuf (component)
この場合、cabal repl 種別:名称
で指定します。
$ cabal repl exe:myprotobuf
$ cabal repl lib:myprotobuf
$ cabal repl test:MyTestSuite01
cabal
ファイルで記載する場所の例は下記です。
name: myprotobuf version: 0.1.0.0 ... executable myprotobuf ### ここの名称 main-is: TCP01.hs other-extensions: BangPatterns, DeriveDataTypeable, DeriveGeneric, FlexibleInstances, MultiParamTypeClasses ... library lib-xproto ### ここの名称 ... exposed-modules: DataBase.MySQLX.CRUD ... Test-Suite MyTestSuite01 ### ここの名称 type: exitcode-stdio-1.0
Haskellのドキュメント生成
haddock
コマンド自体はディレクトリを指定してその配下にあるhs
ファイルを再帰的に処理してくれるオプションはないようです。xargs
を使うのが手っ取り早いようです。
haskell - how to generate documentations with haddock? - Stack Overflow
$ find . -name '*.hs' | xargs haddock --html -o doc_dir
Implicit Parameters
Clash
のプログラミングでサンプルを作り始めたところ、?変数名 :: 型
というシグネチャが出てきました。
*> :t notM notM :: (?rst::Reset domain synchronous, ?clk::Clock domain gated) => Signal domain Bool -> Signal domain Bool
Implicit Paremters
という機能でした。
https://www.haskell.org/hugs/pages/users_guide/implicit-parameters.html
Readerモナドに似た挙動をするようです。
まずは、このような関数を考えてみます。
*> let foo = (*2) . (+2) *> :t foo foo :: Num c => c -> c *> foo 1 6 *> foo 2 8 *> foo 3 10
次に、上の関数の実装内で2つあった関数((*2)
と(+2)
)の1番目の関数を、パラメータとして外出しします。
*> let foo' z = z . (+2) *> :t foo' foo' :: Num b => (b -> c) -> b -> c *> foo' (*2) 1 6 *> foo' (*2) 2 8 *> foo' (*2) 3 10
さらに、上の関数で外出ししたパラメータを暗黙化します。
*> let foo'' = undefined :: (Num a, ?z::a->a) => a -> a *> let foo'' = let ?z=(*2) in ?z . (+2) :: (Num a, ?z::a->a) => a -> a *> foo'' 1 6 *> foo'' 2 8 *> foo'' 3 10
参考情報
2018/01時点のClash
Github
から取得してclash
をインストールした場合、2018/01時点では、hackage
にあるチュートリアルはのコード動かないようです。
tutorial
にあるソースをコンパイルするとパッケージがないとのエラーメッセージがでます。
Clash.Prelude> :l MAC.hs [1 of 1] Compiling MAC ( MAC.hs, interpreted ) MAC.hs:3:1: error: Could not find module ‘CLaSH.Prelude’ Perhaps you meant Clash.Prelude (from clash-prelude-0.99) Use -v to see a list of the files searched for. | 3 | import CLaSH.Prelude | ^^^^^^^^^^^^^^^^^^^^ Failed, modules loaded: none.
CLasH.Prelude
をClash.Prelude
に変更してコンパイルしてもエラーになります。
Clash.Prelude> :l MAC.hs [1 of 1] Compiling MAC ( MAC.hs, interpreted ) MAC.hs:14:14: error: • Expecting one more argument to ‘Signal (Signed 9, Signed 9)’ Expected a type, but ‘Signal (Signed 9, Signed 9)’ has kind ‘* -> *’ • In the type signature: topEntity :: Signal (Signed 9, Signed 9) -> Signal (Signed 9) | 14 | topEntity :: Signal (Signed 9, Signed 9) -> Signal (Signed 9) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ MAC.hs:14:21: error: • Expected kind ‘Domain’, but ‘(Signed 9, Signed 9)’ has kind ‘*’ • In the first argument of ‘Signal’, namely ‘(Signed 9, Signed 9)’ In the type signature: topEntity :: Signal (Signed 9, Signed 9) -> Signal (Signed 9) | 14 | topEntity :: Signal (Signed 9, Signed 9) -> Signal (Signed 9) | ^^^^^^^^^^^^^^^^^^^^ MAC.hs:14:45: error: • Expecting one more argument to ‘Signal (Signed 9)’ Expected a type, but ‘Signal (Signed 9)’ has kind ‘* -> *’ • In the type signature: topEntity :: Signal (Signed 9, Signed 9) -> Signal (Signed 9) | 14 | topEntity :: Signal (Signed 9, Signed 9) -> Signal (Signed 9) | ^^^^^^^^^^^^^^^^^ MAC.hs:14:53: error: • Expected kind ‘Domain’, but ‘Signed 9’ has kind ‘*’ • In the first argument of ‘Signal’, namely ‘(Signed 9)’ In the type signature: topEntity :: Signal (Signed 9, Signed 9) -> Signal (Signed 9) | 14 | topEntity :: Signal (Signed 9, Signed 9) -> Signal (Signed 9) | ^^^^^^^^ Failed, modules loaded: none.
どうやら、諸々APIが変わっているようです。
サンプルは、リポジトリから取得した中にexample
があるのでそれを使います。
clash-compiler/examples at master · clash-lang/clash-compiler · GitHub
起動
$ stack exec -- clash --interactive CLaSHi, version 0.99 (using clash-lib, version 0.99): http://www.clash-lang.org/ :? for help
サンプルの確認
Clash.Prelude> :! ls MAC.hs *MAC> :! cat MAC.hs module MAC where import Clash.Prelude ma acc (x,y) = acc + x * y macT acc (x,y) = (acc',o) where acc' = ma acc (x,y) o = acc mac = macT `mealy` 0 topEntity :: SystemClockReset => Signal System (Signed 9,Signed 9) -> Signal System (Signed 9) topEntity = mac {-# NOINLINE topEntity #-} testBench :: Signal System Bool testBench = done' where testInput = stimuliGenerator $(listToVecTH [(1,1) :: (Signed 9,Signed 9),(2,2),(3,3),(4,4)]) expectedOutput = outputVerifier $(listToVecTH [0 :: Signed 9,1,5,14]) done = expectedOutput (topEntity testInput) done' = withClockReset (tbSystemClockGen (not <$> done')) systemResetGen done *MAC>
ロード(コンパイル)
Clash.Prelude> :l MAC.h MAC.hi MAC.hs Clash.Prelude> :l MAC.hs [1 of 1] Compiling MAC ( MAC.hs, interpreted ) [flags changed] Ok, modules loaded: MAC.
verilog
生成
*MAC> :verilog Loading dependencies took 2.235453s Compiling: MAC.topEntity Applied 133 transformations Normalisation took 1.062433s Netlist generation took 0.011033s Compiling: MAC.testBench Applied 425 transformations Testbench normalisation took 0.557544s Testbench netlist generation took 0.013983s Total compilation took 3.906076s *MAC>
生成内容の確認
*MAC> :! tree verilog/ verilog/ └── MAC ├── MAC_testBench │ ├── MAC_outputVerifier.v │ ├── MAC_stimuliGenerator.v │ └── MAC_testBench.v ├── MAC_topEntity.manifest └── MAC_topEntity.v 2 directories, 5 files *MAC>
FPGAプログラミング大全 Xilinx編でZyboを使うとはまるところ
- 作者: 小林優
- 出版社/メーカー: 秀和システム
- 発売日: 2016/12/15
- メディア: 単行本
- この商品を含むブログ (1件) を見る
5章、6章はソフトマクロCPU MicroBlaze の解説になっています。その解説は、ArtyとBasys3向けの説明になっており、Zyboを使う場合は、適宜読み替える必要があります。Zybo用の設定はAppendixに記載されているのでそれに従えばよいです。ですが、書籍には明示的に記載されていない読み替え(実際は、読み飛ばし!)が必要でした。
書籍の手順通りに進めると下記のようなメッセージがでました。
メッセージの一部をテキスト化しました。
[Place 30-58] IO placement is infeasible. Number of unplaced terminals (1) is greater than number of available sites (0). The following are banks with available pins: IO Group: 0 with : SioStd: LVCMOS18 VCCO = 1.8 Termination: 0 TermDir: In RangeId: 1 has only 0 sites available on device, but needs 1 sites. Term: RXD
[Place 30-374] IO placer failed to find a solution Below is the partial placement that can be analyzed to see if any constraint modifications will make the IO placement problem easier to solve. +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | IO Placement : Bank Stats | +----+-------+-------+------------------------------------------------------------------------+------------------------------------------+--------+--------+--------+-----+ | Id | Pins | Terms | Standards | IDelayCtrls | VREF | VCCO | VR | DCI | +----+-------+-------+------------------------------------------------------------------------+------------------------------------------+--------+--------+--------+-----+ | 0 | 0 | 0 | | | | | | | | 13 | 0 | 0 | | | | | | | | 34 | 50 | 1 | LVCMOS33(1) | | | +3.30 | YES | | | 35 | 50 | 5 | LVCMOS33(5) | | | +3.30 | YES | | +----+-------+-------+------------------------------------------------------------------------+------------------------------------------+--------+--------+--------+-----+ | | 100 | 6 | | | | | | | +----+-------+-------+------------------------------------------------------------------------+------------------------------------------+--------+--------+--------+-----+ IO Placement: +--------+----------------------+-----------------+----------------------+----------------------+----------------------+ | BankId | Terminal | Standard | Site | Pin | Attributes | +--------+----------------------+-----------------+----------------------+----------------------+----------------------+ | 34 | RST | LVCMOS33 | IOB_X0Y36 | Y16 | | +--------+----------------------+-----------------+----------------------+----------------------+----------------------+ | 35 | CLK | LVCMOS33 | IOB_X0Y78 | L16 | | | | LED[0] | LVCMOS33 | IOB_X0Y54 | M14 | | | | LED[1] | LVCMOS33 | IOB_X0Y53 | M15 | | | | LED[2] | LVCMOS33 | IOB_X0Y99 | G14 | | | | LED[3] | LVCMOS33 | IOB_X0Y93 | D18 | | +--------+----------------------+-----------------+----------------------+----------------------+----------------------+
端子の数が合わないってどういうことなんでしょうか?
結論から言えば、Zyboでは、UARTブロックの追加をする必要がないということでした。 5章P.195に「UARTを接続」がありますが、この部分をまるっと無視する必要があります。
理由は、Appendixに「Zyboボード上のUSBシリアルインターフェースは、PSのMIOに接続されているので、PL側の回路では使用できません。(中略)JTAG経由でシリアル出力しますので、RDXやTXDなどの端子は不要です。」と説明されています。
なのでブロック図は下記のようになります。
UARTを接続をせずに手順通りに進めるとHelloWorldがだせました。
記念にHello FPGA Worldとしてみました。
つまらないところで、嵌ってしまいました。