いよいよメインとなる組み合わせ回路の記述部である。組み合わせ回路は実際には幾つかあり、後述するassign以外にもあるが、ここではベーシックなinitialとalwaysである。ここでinitialは「電源投入時、もしくはリセット後に一度だけ実行される回路」、alwaysは「常に動いている回路」となる。arduino的に言えば前者がvoid init()、後者がvoid loop()にあたると理解していただくと早い。今回の回路では、initialは3種類のカウンタを0クリアするのだけに使っている。
initial begin div_cntr1 = 0; div_cntr2 = 0; dec_cntr = 0; end
always@(posedge clk) begin div_cntr1 <= div_cntr1 + 1; if (div_cntr1 == 0) if (div_cntr2 == 762) begin div_cntr2 <= 0; half_sec_pulse <= 1; end else div_cntr2 <= div_cntr2 + 1; else half_sec_pulse <= 0; if (half_sec_pulse == 1) dec_cntr <= !dec_cntr; end
さて、メインとなる部分はalwaysからだ。最初の
always@(posedge clk)
はクロック信号を取り込み、この信号の正の立ち上がりのタイミングでbegin以下を実行するという意味である。コメントにもあるようにクロック信号は50MHzが供給されるので、always以下のbegin〜endのブロックは毎秒50M回実行されることになる。
ただ目的は1秒単位のLEDのOn/Offなので、これはあまりに高速すぎる。そこでまずdiv_cntr1を使ってこれを分周する。initialのところでdiv_cntl1は0に初期化し、でalwaysのbegin直下でいきなりdiv_ctrl1に1を追加してる( <=は代入の意味なので、C風に書けばdiv_cntrl++; ということになる)。そのあとでdiv_cntl1が0かどうかチェックしてるのは誤解を招きそうだが、要するにdiv_cntl1は毎秒50M回加算をされることになる。ただしdiv_cntl1は16bitのレジスタなので、65535の後で0に戻る事になる。要するに
begin div_cntr1 <= div_cntr1 + 1; if (div_cntr1 == 0) : : : : else half_sec_pulse <= 0;
とすることで、"…………"の部分が呼ばれる頻度は毎秒 50M÷65536=762.939……で毎秒763回になるわけだ。で、呼ばれていない間は常にhalf_sec_pulseというカウンタを0にしているだけである。
さて、では"…………"の中身は?というと、こちらの中ではさらにdiv_cntl2というカウンタを回している。こちらは10bitのカウンタなので、1024まで達すると0に戻るが、1秒にするためには763にしておかないと都合が悪いので、明示的に762になったかどうかを判断して、762に達したらhalf_sec_pulseを1にセットし、div_cntl2を0に戻す。そうでなければdiv_cntl2を1増やすというシンプルなものだ。この結果、if(div_cntr1 == 0)...から始まるifブロックが終了するとき、約1秒に1回だけhalf_sec_pulseが1になり、他の時には0になるというわけだ。
dec_cntrは純粋にLEDのOn/Offの状態を保持するもので、見て分かる通り、half_sec_pulseが1の時だけ値をひっくり返すという処理になる。
Copyright © ITmedia, Inc. All Rights Reserved.