0

私は、組み合わせ論理と行動論理の組み合わせに頭を悩ませようとしています。4つのLEDと66MHzのクロック入力を備えた小さなFPGAがあります。アイデアは、それらのうちの2つを光らせ(1つは上昇、1つは下降)、もう2つは点滅させることでした。だから私は次のコードを思いついた:

module ledflash(input wire CLK,
        input wire USER_RESET,
        output wire LED[3:0]);

   reg [26:0]           cnt;
   reg [4:0]            pwm;

   wire             led_enable = ~USER_RESET;

   always @(posedge CLK)
     begin
    if (led_enable)
      begin
         cnt <= cnt + 1;
         pwm <= pwm[3:0] + (cnt[26] ? cnt[25:22] : ~cnt[25:22]);
      end
    else
      begin
         cnt <= 0;
         pwm <= 0;
      end
   end

   assign LED[0] = led_enable ? (cnt[26] ? pwm[4] : ~pwm[4]) : 0;
   assign LED[1] = led_enable ? (cnt[26] ? ~pwm[4] : pwm[4]) : 0;

   assign LED[2] = led_enable ? cnt[25] : 0;
   assign LED[3] = led_enable ? ~cnt[25] : 0;

endmodule

ベンダー固有のDCMを使用したくなかったので、66MHzのクロックを備えた単純なビット加算器が魔法のように機能します。そもそも全体の設計が間違っているかもしれませんが(たとえば、2つのクロック分周器を使用し、2つのレジスタを少し反転させて(ほぼ)同じことを実現できたかもしれません)、この状況に遭遇したので、不思議に思いました。 ..

通常のソフトウェア開発者の観点からは、継続的な割り当てには冗長に見える部分がいくつかあります。たとえば、追加のレジスタを使用できるため、実行される作業が少なくなるように見えます。例えば:

module ledglow(input wire CLK,
        input wire USER_RESET,
        output wire LED[3:0]);

   reg [26:0]           cnt;
   reg [4:0]            pwm;
   reg              led_pair1;
   reg              led_pair2;

   wire             led_enable = ~USER_RESET;

   always @(posedge CLK)
     begin
    if (led_enable)
      begin
         cnt <= cnt + 1;
         pwm <= pwm[3:0] + (cnt[26] ? cnt[25:22] : ~cnt[25:22]);
      end
    else
      begin
         cnt <= 0;
         pwm <= 0;
      end
    led_pair1 <= cnt[26] ? pwm[4] : ~pwm[4];
    led_pair2 <= cnt[25];
     end

   assign LED[0] = led_enable ? led_pair1 : 0;
   assign LED[1] = led_enable ? ~led_pair1 : 0;

   assign LED[2] = led_enable ? led_pair2 : 0;
   assign LED[3] = led_enable ? ~led_pair2: 0;

endmodule

私は上記の2つのアプローチのシンセサイザーレポートの違いを掘り下げてHDL回路図を調べようとしていましたが、私のような経験の浅い人には複雑すぎます。

合成ツールが組み合わせロジックを非常にうまく最適化することは間違いありませんが、右側の式が非常に複雑でワンライナーなどであると仮定すると、このようなことを言う方法はありますか?

   if (some_reg_var) begin
       assign net0 = 1;
       assign net1 = 0;
    end
   else
    begin
       assign net0 = 0;
       assign net1 = 1;
    end

それともそうすることは理にかなっていますか?そうでない場合は、動作部分を単純化するために、そのような場合にレジスタを導入することは理にかなっていますか?少なくともいくつかのルールや親指があると確信しています。どんな助けでも大歓迎です。

4

1 に答える 1

2

あなたの質問は少し冗長ですが、私はあなたが何をしているのか理解していると思います(私が間違っている場合は私を訂正してください)。

alwaysブロックのregと同様に、if / elseロジックを使用するために長いassignステートメントを分割する方法があるかどうかを知りたいですか?

Verilogは、このように私にはいつも少しおかしいように見えましたが、何かを宣言したからといって、「reg」データ型がレジスタに合成されることを意味するわけではありません。保存する状態がある場合にのみ、実際にレジスタを作成します。そうは言っても、次の2つのステートメントはまったく同じものに統合されるはずです。

ケース1:

wire a;
wire b;
assign a = b ? 0 : 1; 

ケース2:

reg a;
wire b;

always @(b)
   if(b)
       a <= 0;
   else
       a <= 1;

これらは両方とも、まったく同じロジックを作成する必要があります(単純に、a =!bのインバーター)。regを宣言した2番目のケースでも、覚えておくべきことは何もないため、実際にはレジスタをインスタンス化しません(すべての入力が感度リストにあります)。

このため、コードを単純化するために複雑なif / elseロジックを自由に記述できます。これは、余分なレジスタを合成するというペナルティを支払うことを意味するものではありません。ですから、あなたにとって最も快適な方法で自由に書いてください。(alwaysブロックを使用する場合は、考えられるすべてのケースに割り当てを設定してください。そうしないと、おそらく不要なラッチが推測されます)。

于 2012-04-23T01:28:12.430 に答える