連載
» 2015年10月13日 07時00分 公開

FPGAでのLチカをVerilog HDLで理解するMAX 10 FPGAで学ぶFPGA開発入門(3)(3/5 ページ)

[大原 雄介,MONOist]

組み合わせ回路の記述

 いよいよメインとなる組み合わせ回路の記述部である。組み合わせ回路は実際には幾つかあり、後述する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.