使用頻度の高い部品のHDL記述例 -カウンタ-

3 min read読了の目安(約2700字

カウンタは、あるパルスの数を数えたり、タイミングを作るのに使ったり、様々なところで使われる基本的な回路と言えます。
使い方により様々な書き方が出来ますが、いくつか記述例を挙げます。

例1

一番単純なカウンタの記述例です。クロックを数えるだけのものです。

VHDL
process (RST,CLK) begin
    if (RST = '1')then
        counter <= (others => '0');
    elsif (CLK'event and CLK = '1') then
        counter <= counter + 1;
    end if;
end process;
verilog
always@(posedge RST or posedge CLK) begin
    if (RST == 1'b1) begin
        counter <= 'd0;
    end else begin
        counter <= counter + 1;
    end
end

この場合、最大値まで数えたら0に戻って繰り返し動作します。

例2

例1はカウントアップしていきますが、カウントダウンしていく記述例です。(8bitの例)
この場合は、0まで数えたら最大値に戻って繰り返し動作します。

VHDL
process (RST,CLK) begin
    if (RST = '1')then
        counter <= (others => '1');
    elsif (CLK'event and CLK = '1') then
        counter <= counter - 1;
    end if;
end process;
verilog
always@(posedge RST or posedge CLK) begin
    if (RST == 1'b1) begin
        counter <= 8'hFF;
    end else begin
        counter <= counter - 1;
    end
end

verilogの場合、全bit1の代入はbit数指定して最大値を入れることになり、データ幅をパラメータにした時にちょっと厄介になります。
SystemVerilogの書き方だと簡単に出来ます。

SystemVerilog
always@(posedge RST or posedge CLK) begin
    if (RST == 1'b1) begin
        counter <= '1;
    end else begin
        counter <= counter - 1;
    end
end

例3

今度はパルス信号を数えて、最大値100になったら数えるのを止めるカウンタの例です。

VHDL
process (RST,CLK) begin
    if (RST = '1')then
        counter <= (others => '0');
    elsif (CLK'event and CLK = '1') then
        if (pulse = '1') then
            if (counter < 100) then
                counter <= counter + 1;
            end if;
        end if;
    end if;
end process;
verilog
always@(posedge RST or posedge CLK) begin
    if (RST == 1'b1) begin
        counter <= 'd0;
    end else if (pulse == 1'b1) begin
        if (counter < 100) begin
            counter <= counter + 1;
        end
    end
end

例4

最大値99からパルス信号を減らしながら数えて、0になったら最大値に戻るカウンタの例です。最大値99なので7bitあればよいです。

VHDL
process (RST,CLK) begin
    if (RST = '1')then
        counter <= "1100011";--99
    elsif (CLK'event and CLK = '1') then
        if (pulse = '1') then
            if (counter = 0) then
	        counter <= "1100011";--99
	    else
                counter <= counter - 1;
            end if;
        end if;
    end if;
end process;
verilog
always@(posedge RST or posedge CLK) begin
    if (RST == 1'b1) begin
        counter <= 7'd99;
    end else if (pulse == 1'b1) begin
        if (counter == 0) begin
	    counter <= 7'd99;
	end else begin
            counter <= counter - 1;
        end
    end
end

最大値が固定値であるなら、定数を宣言して、それを使用する方がよいと思います。

上記の例では、bit幅をあまり意識しないでよい書き方をしている箇所があります。bit幅や最大値などをパラメータ化したカウンタをモジュール化してあちこちで使用するといったこともありますので、そのあたりは適宜調整いただくのがよいかと思います。