FC2カウンター FPGAの部屋 Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路4(Verilogコーディング中)
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路4(Verilogコーディング中)

さて、Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路のVerilogコーディング中だ。暑いので、やる気が失せている。ほんとうに暑い。今朝は少し涼しく部屋の温度計は28.0度だが、昨日は29.8度だった。昨日、夏休みで家にいた息子が室温が36度になって流石にエアコンを点けたと言っていた。皆さん、夏バテしないようにご注意ください。私も夏の予定が目白押しなので、気をつけようと思います。
さて、VerilogコーディングはVGA_Display_Controller.vをコーディング中だ。一部を下に示す。
CamDispCntrler_DDR2_6_100722.png
(2010/07/22 修正:Verilogコードが間違っていたので修正しました)

暑いけど頑張って作ろうと思う。今回はOVLを使用してアサーションをする予定だ。VGA_Display_Controller.vにはOVL_NEVERを使って、非同期FIFOがoverflow, underflow しないかを監視させることにする。OVLに関しては、”アサーション事始め”や”ISimでOVLのVHDL, Verilog混在シミュレーション(OVLライブラリのコンパイルと登録)”、”ISimでOVLのVHDL, Verilog混在シミュレーション(ISimでシミュレーション)”を参照のこと。
下が取り敢えず書いてみたOVL_NEVERのVerilogコード。下のその様子を示す。
CamDispCntrler_DDR2_7_100722.png

いろいろ次の企画も考えているが、今のところVerilogコーディングが忙しく手がついていない。なかなか忙しい。
  1. 2010年07月22日 05:39 |
  2. 画像処理
  3. | トラックバック:0
  4. | コメント:8

コメント

モジュールへの分割

こんにちは。いつも参考にさせていただいてます。

さて、私はもともとソフトウェア開発から来た人間
というのもあってか、Verilog でもコードを細かく
モジュールに分けるのが好きなので、以下のようなのを
思い浮かべました。

module YUV2RGB (
input wire [7:0] y,
input wire [7:0] u,
input wire [7:0] v,
output wire [7:0] r,
output wire [7:0] g,
output wire [7:0] b
);
// saturate 処理前の値
wire [18:0] r_int, g_int, b_int;
YUV2RGB_core YUV2RGB_core ( y, u, v, r_int, g_int, b_int );

// saturate 処理
rgb_saturate r_saturate ( r_int, r );
rgb_saturate g_saturate ( g_int, g );
rgb_saturate b_saturate ( b_int, b );

endmodule

(* MULT_STYLE="LUT" *)
module YUV2RGB_core (
input wire [7:0] y,
input wire [7:0] u,
input wire [7:0] v,
output wire [18:0] r,
output wire [18:0] g,
output wire [18:0] b
);
// 8 ビット目が1の位で、それ以下は端数
assign r = y * 'h100 + v * 'h164 - 'hb380;
assign g = y * 'h100 - v * 'h0b7 - u * 'h058 + 'h8780;
assign b = y * 'h100 + u * 'h1c6 - 'he300;
endmodule

module rgb_saturate (
input wire [18:0] in,
output wire [7:0] out
);
// 8 ビット目が1の位で、それ以下は端数
assign out =
in[18] ? 'h00 : // マイナス
in[17] || in[16] ? 'hff : // オーバーフロー
in[15:8]; // 通常は小数部を切り捨て
endmodule

テストしてないので細かいところで違ってるかもしれ
ないのですが、コーディングスタイルの話も面白いかも、
と思ったので書き込ませていただきました。
どうでしょうね。

(途中にレジスタを挟まないと演算遅延がすごいことに
なっている気がしますが・・・それは別の話題として)
  1. 2010/07/22(木) 22:31:48 |
  2. URL |
  3. 武内 #-
  4. [ 編集 ]

インデント

あれ、コード中のインデントが失われて、とっても見難くなってしまいました。
HTMLソースではインデントされたコードが見られるようなので、すみませんがそちらを参照して下さい。
  1. 2010/07/22(木) 22:37:45 |
  2. URL |
  3. 武内 #-
  4. [ 編集 ]

こんにちは。武内さん。
このVerilogコードはVHDLコードを直したものです。元はここです。
http://marsee101.blog19.fc2.com/blog-entry-1313.html
武内さんの様に書いたほうが記述量も少なくて見やすいと思うのですが、特にsignedでビット幅が中途半端な場合は、途中でどのように推論されて演算されるかわからないと思っているので、ギチギチに書いています。
それから、私はC言語でも3項演算子?を使うのが苦手で、たまには使いますが、めったに使いません。assignの時は使います。
細かくモジュールには分けたほうが良いと思います。そのほうがフロアプランするときも便利ですから。。。ただ、この回路は25MHz動作で制約が緩いので、モジュールには分けない(面倒なので)ようにしました。(ブログに書いてる都合上、速く作りたいというのもあります)
DDR2 SDRAMコントローラはフロアプランを考えて、もう少し細かくモジュールにわかれています。
自分であとで見返すことを考えると、この記事に書いたくらいのモジュール化がいいのかな?とは思います。
  1. 2010/07/23(金) 04:29:12 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

VHDL だと連接がずっと見やすく書けるんですね。
「動いている回路に手を加えない」 は鉄則なので、そのあたりも
ありましたか。

あと、signed になる、あるいはオーバーフロー or アンダーフローが
生じる可能性があるときは、ガチガチの方が間違いが少ないのも
納得できます。

ガチガチの方針で行くのであれば、

function [18:0] lut_multiply;
  input [7:0] a;
  input [8:0] b;
  assign lut_multiply =
    ( a[0] ? { 10'b00_0000_0000, b } : 0 ) +
    ( a[1] ? { 9'b0_0000_0000, b, 1'b0 } : 0 ) +
    ...
endfunction

を用意して、

assign r = lut_multiply( y, 9'h100 )
     + lut_multiply( v, 9'h164 )
     - 9'hb380;

などとするのもありかな、と思いました。

50MHz 以下の周波数だと、このくらいの回路であれば遅延については
結構大丈夫なのですね。100MHz 以上だとすぐツールに文句を
言われるので、そのあたりの感覚がまだ身についてません(汗
Spartan3 をちょっと見直しました(^^

別件ですが、ModelSim では $display の代わりに $messagelog
を使うと非常に便利ですね。エラー箇所をグラフ上で一目で
見つけられるのがすばらしいです。
  1. 2010/07/23(金) 08:04:07 |
  2. URL |
  3. 武内 #-
  4. [ 編集 ]

こんにちは。

>function [18:0] lut_multiply;
>  input [7:0] a;
>  input [8:0] b;
>  assign lut_multiply =
>    ( a[0] ? { 10'b00_0000_0000, b } : 0 ) +
>    ( a[1] ? { 9'b0_0000_0000, b, 1'b0 } : 0 ) +
>    ...
>endfunction

これ良いですね。今度、このアイデアを使わせていただこうと思います。よろしくお願いします。

VHDLだとintegerでやって(つまり32ビット幅)、後で、必要なビット数に切り出すという事でも良いかな?と思っています。必要ないビットはXSTが削除してくれるでしょうし、十分なビット幅があるので、演算で変な事態にはならない気がします。Verilogでも大丈夫かな?演算的にはいける気がします。

$messagelog ですか?使ったことがないですが、今度やってみます。
#なかなか、ModelSimをVerilogで使うことがないですが、今度使ってみたいと思います。
  1. 2010/07/23(金) 09:44:36 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

先の書き込みでは function の書式が違ってましたね。assign は必要なかったです。
あと、a と b との計算を逆にした方が、b が定数という感じがより出た
かもしれません。合成結果は変わらないんだと思いますが・・・

さらに、今の場合は引数が unsigned になっていることが重要
だったので、

function [18:0] unsigned_multiply;
  input [7:0] a;
  input [8:0] b;
  unsigned_multiply = a * b; // unsigned として掛け算する
endfunction

として使うだけでも良いかもしれませんね。
上の書き方で、a, b, unsigned_multiply はすべて unsigned として
扱われることが保証されていると思います。

この場合、YUV2RGB_core に (* MULT_STYLE="LUT" *) を
付けることになります。function あるいは代入行に制約を
付けても効いてくれませんでした。
  1. 2010/07/23(金) 10:19:42 |
  2. URL |
  3. 武内 #-
  4. [ 編集 ]

すみません、掛け算の前に幅を拡張しておかないとだめですね。

function [18:0] unsigned_multiply;
  input [7:0] a;
  input [8:0] b;

  // unsigned として掛け算する
  unsigned_multiply = {11'b0, a} * {10'b0, b};
endfunction

でしょうか。
  1. 2010/07/23(金) 10:29:02 |
  2. URL |
  3. 武内 #-
  4. [ 編集 ]

こんにちは。
いろいろ解説ありがとうございます。ニューラルネットワークも、ブログに書いた方式で演算しています。とても人間の頭ではVHDLが書けないので、RubyでCSVで書かれた係数を食わせて、VHDLを吐かせていますが、これでやれば、簡単に行けそうですね。
  1. 2010/07/24(土) 15:11:23 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
https://marsee101.blog.fc2.com/tb.php/1531-6e60a3b8
この記事にトラックバックする(FC2ブログユーザー)