generateで自動的に回路を生成する

今日は久しぶりにVerilog書いてた。

何をしていたのかというと数独を解く回路を作るためですね。

以前からやろうと思ってたのだけど、ちょうど暇なのでちょうどいい。


数独を解く方法だが、縦・横・3×3のブロックそれぞれに含まれる数字を列挙して、これらいずれの枠にも含まれない数字が候補になる。

今日は縦・横・3×3のブロックそれぞれに含まれる数字を列挙することをやっていた。

各マスの数字を3なら9’b001000000のように何番目かのビットを1にすることで示すことにする。

これを縦・横・3×3のブロックの全てのマスの値についてORを取れば、含まれる数字全てが選ばれた状態になる。

問題はこれをどうやってORを取るかだ。全部手で書くのが手っ取り早い気もするがちょっとそれはかっこわるい。

そこでVerilogのgenerateを使ってやってみた。


まずgenerateの使い方の例だがこんな風にする。

wire [7:0] a,b,c,e;
generate
  genvar i;
  for(i=0;i<8;i=i+1) begin :gen
    assign b=~a;
    always @(posedge clk)  c<=b;
    Module1 m(a,e);
  end
endgenerate

generateのブロックを作って、その中で生成に使う変数のgenvarを宣言してforループを回す。

forの後1文で終わらないからbegin~endでくくるが、ここで:genなどしておくと、genという名前がついたブロックにできる。

名前をつけたらその名前が階層につくそうですがくわしくは知らない。

この下にはalways・assignとモジュールの実体化ができるようだ。


しかし問題はどうやって9つの変数のORをgenerateを使って生成するかである。

assign y=x[0]|x[1]|x[2]|x[3]|x[4]|x[5]|x[6]|x[7]|x[8];

ようはこういうことを手で書かずにgenerateで書く方法があるかということだ。

assignを組み合わせてやってみた。

ORとったやつをwireに一旦assignして、それと次のやつをOR取ってassignしてという風にやった。

結果こんな風な記述になった。

wire [7:0] t[0:7]
generate
  genvar i;
  for(i=0;i<9;i=i+1) begin :ors
    if     (i==0)  t[i]=x[i];
    else if(i==8)  y   =t[i-1]|x[i];
    else           t[i]=t[i-1]|x[i];
  end
end

こうすれば最終的には最初に書いたように9つのORを取った値がyにassignされる。


ただでさえまどろっこいしい記述だが、実際には縦・横・3×3のブロックについて計算しなければならないのでかなり複雑になってしまった。

ただ基本となっているところはこの通りで、あとはgenerateのforを入れ子にしたりとかその程度のこと。

もっとも複雑なのは記述だけで、実際には合成されれば一旦assignしただけのwireなどはなくなってしまう。

だからできる回路もおそらく最初に書いたような記述によりできる回路と差はないはずだ。

だからgenerateをつかうことによる害はほぼないはずなのでどうぞ。