電気回路/HDL/Verilogメモ のバックアップの現在との差分(No.1)
更新- 追加された行はこの色です。
- 削除された行はこの色です。
[[電気回路/HDL]] * 内部信号線に対する pullup / pulldown の代替案 [#sdffefa8] #contents verilog ではFPGA内部に走らせるバス信号線を pullup / pulldown で引っ張ることによってすべてのドライバが highZ * 内部信号線を pullup / pulldown できないのでその対処法 [#sdffefa8] 以下は Xilinx ISE 14.2 で試した結果です。 ** pullup/pulldown の基本 [#c4a046bf] Verilog ではバス信号線などを pullup / pulldown で引っ張ることにより、すべてのドライバが highZ の時の値を 1 または 0 に決められることになっています。 通常そのようなトライステートなバスは FPGA 外部に出て行く信号線を記述するときに使います。 外部ピンをトライステートにする場合とは対照的に、~ FPGA 内部のネットを疑似トライステート的に記述した場合には、 その回路は論理合成時に マルチプレクサ/and/or などの論理回路に置き換えられて、 「結果的にトライステートの場合と同様の動作をするよう」取りはからってもらえます。 たとえばこんな回路。 LANG:verilog wire oe1, oe2, oe3; wire [BUS_BITS-1:0] data1, data2, data3; wire [BUS_BITS-1:0] bus; assign bus = oe1 ? data1 : {BUS_BITS{1'bz}}; assign bus = oe2 ? data2 : {BUS_BITS{1'bz}}; assign bus = oe3 ? data3 : {BUS_BITS{1'bz}}; これは次のような警告を出しつつ問題なく論理合成できて、 LANG:console WARNING:Xst:2042 - Unit main: 8 internal tristates are replaced by logic (pull-up yes): bus<0>, bus<2>, bus<3>, bus<4>, bus<5>, bus<6>, bus<7>. デフォルトでは pullup されているかのごとく highZ 時の値は 1 になります。 これを明示的に pulldown するには、Verilog 文法的には LANG:verilog // bus 信号線を pulldown して、何も出力されないときは 0 とする generate genvar bus_pull_i; for(bus_pull_i=0; bus_pull_i<BUS_BITS; bus_pull_i=bus_pull_i+1) begin: bus_pull pulldown bus[bus_pull_i]; pulldown(bus[bus_pull_i]); end endgenerate もちろんこれは を付け足せば良いことになるのですが・・・実は後述の通りこのコードは論理合成できません。 もちろん 3 つの assign と pulldown をまとめて LANG:verilog assign bus = oe1 ? data1 : oe2 ? data2 : oe3 ? data3 : {BUS_BITS{1'b0}}; と書いても結果は同じなのですが、~ と書いてしまえば論理合成可能で、得られる結果も同じなのですが、 data1, data2, data3 をバスに繋ぐコードは通常 あちこちのモジュールに分散しているので、 pulldown で「それ以外」の場合を一度に書けるのはうれしいのです。 pulldown で「それ以外」の場合を一度に書けたらうれしいと。 ただ、このように書いたコードを論理合成しようとすると、 Synthesis でエラーになってしまいます。 ** 内部信号線に付けた pullup/pulldown は論理合成できない [#fb524492] 曰く、 上記のコードを論理合成しようとすると、 Synthesize でエラーになります。 LANG:console ERROR:Xst:850 - "test.v" line 40: Unsupported gate instantiation. ERROR:Xst:850 - "main.v" line 40: Unsupported gate instantiation. そこで verilog のゲートプリミティブ記述 pulldown の代わりに PULLDOWN モジュールを使って Verilog のゲートプリミティブ記述 pulldown の代わりに PULLDOWN モジュールを使って LANG:verilog generate genvar bus_pull_i; for(bus_pull_i=0; bus_pull_i<BUS_BITS; bus_pull_i=bus_pull_i+1) begin: bus_pull PULLDOWN bus_pd(.O(bus[bus_pull_i])); end endgenerate のように1ビットずつ PULLDOWN してやれると Synthesis は通ります。 のように PULLDOWN してやると、Synthesize は通るようになります。 でも今度は Translate で でも Translate で LANG:console ERROR:Xst:2617 - Data Corruption(Timing): Arrival time traversal failed on Ugate element というエラーが出てしまう。 となってやはり論理合成できない。 どうやら PULLDOWN/PULLUP モジュールは IOB に対するプルアップ・プルダウン制約に 特化した記述なようで、内部信号線には使えないということみたいです。 特化した記述なようで、内部信号線には使えないみたいです。 そこで代替案なのですが、pullup/pulldown の代わりに wor/wand を使うと、 同じ結果を論理合成可能な形で得られます。 ** そこで対処法 [#bbe7f2de] LANG:verilog wire oe1, oe2, oe3; wire [BUS_BITS-1:0] data1, data2, data3; wor [BUS_BITS-1:0] bus_pulled_down = {BUS_BITS{1'b0}}; assign bus_pulled_down = oe1 ? data1 : {BUS_BITS{1'bz}}; assign bus_pulled_down = oe2 ? data2 : {BUS_BITS{1'bz}}; assign bus_pulled_down = oe3 ? data3 : {BUS_BITS{1'bz}}; wand [BUS_BITS-1:0] bus_pulled_up = {BUS_BITS{1'b1}}; assign bus_pulled_up = oe1 ? data1 : {BUS_BITS{1'bz}}; assign bus_pulled_up = oe2 ? data2 : {BUS_BITS{1'bz}}; assign bus_pulled_up = oe3 ? data3 : {BUS_BITS{1'bz}}; すみません。 2012/11/06 まで、うまくいかない対処法が書かれていました。 wor に 0 を繋いでおけば、他から 1 が繋がれれば 1 を出力しますが、 何も繋がなければゼロのままになります。これは pulldown と同じ結果です。 結局よく調べてみると Verilog レベルでできる対処は無いようでした。 同様に、~ 仕方がないので Xilinx ISE 固有の対処法になってしまうのですが、 wand に 1 を繋いでおけば、他から 0 が繋がれれば 0 を出力しますが、 何も繋がなければ 1 のままになります。これは pullup と同じ結果です。 http://forums.xilinx.com/t5/Synthesis/problem-of-quot-INOUT-quot-use-quot-internal-tristates-are/td-p/122342 ただしこのようにしてしまうと回路のバグで複数のドライバが同時に値を出力した場合にも 結果が x にならず、バグの発見が遅れてしまう可能性があります。 によれば、 仕方がないので、現在のところ シミュレーション時には pullup/pulldown を使い、 論理合成時には wand/wor を使うようなコードを書いてみています。 - Xilinx ISE ではトライステートバスを論理回路に直す時、 デフォルトでは pull up が指定されるため、pull up で構わなければ明示的な指定は必要ない - これを pull down にするためにはネットにtristate2logic_pullup属性を指定すれば良い - tristate2logic_pullup属性はあくまで論理合成時にしか働かないので、 シミュレーション用には明示的に pull up/pull down を書く必要がある ということのようです。 LANG:verilog (* tristate2logic_pullup = "yes" *) wire [BUS_BITS-1:0] bus_pulled_up; // 論理合成時には暗黙で pullup される (* tristate2logic_pullup = "no" *) wire [BUS_BITS-1:0] bus_pulled_down; // 論理合成時には暗黙で pulldown される `ifdef XILINX_ISIM wire [BUS_BITS-1:0] bus; // シミュレーション用には明示的に pull しておく必要がある generate genvar bus_pull_i; for(bus_pull_i=0; bus_pull_i<BUS_BITS; bus_pull_i=bus_pull_i+1) begin: bus_pull pulldown bus[bus_pull_i]; pullup(bus_pull_up[bus_pull_i]); pulldown(bus_pull_down[bus_pull_i]); end endgenerate `else wor [BUS_BITS-1:0] bus_pulled_down = {BUS_BITS{1'b0}}; `endif // XILINX_ISIM どなたかもっと良い方法があれば教えて下さい。 どなたか、普通ならこうするよ、とか、もっと良い方法があるよ、とかあれば教えて下さい。 * コメント [#i0f2cd0c] #article_kcaptcha
Counter: 25221 (from 2010/06/03),
today: 8,
yesterday: 0