VHDLでfunctionを使う

VHDLでfunctionを使う

 以前に組み合わせ回路について記述しました。VHDLで組み合わせ回路を記述するにあたり、functionを使うと便利です。processは順序回路ですが、組み合わせ回路でひとつの塊を作るのがfunctionです。

 functionを使う理由は様々ですが、大きく2つあります。

  • 同じ組み合わせ回路を何度も使いまわししたい。
  • 一つの塊にすることで、後からソースを読んでわかりやすくしたい。

 プログラムの経験のある方でしたら、「関数」を思い浮かべると良いと思います。

 functionは以下のような形式で記述します。

function ファンクション名 (パラメータ名1 : パラメータタイプ := 初期値;
                         パラメータ名2 : パラメータタイプ := 初期値;
                                        ... )
   return リターンタイプ is (constant or variable) ;
begin
    ここに順序回路を記述する
    return <value>
end function;

 かなり簡単な例になりますが、functionの使い方としてカウンタを回してその値によってLEDを点滅させる回路を例に示します。実際にはクロックが早すぎてLEDは点灯しませんが、functionの使用例としてソースコードを読んでください。

--  TITLE:					"LED.vhd"
--  MODULE NAME:			
--  PROJECT CODE:			
--  AUTHOR:					 (xxxx@nakaharagiken.com)
--  CREATION DATE:			2021.2.16
--  SOURCE:            		
--  LICENSE:           		Copyright (c) 2021 nakaharagiken.com
--  DESCRIPTION:            ffunction練習
--  NOTES TO USER:			
--  SOURCE CONTROL:			
--  REVISION HISTORY:  	    v0.0	2021.2.16
--
--
--
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;
--use ieee.numeric_std.all;

entity LED is
port (
	clock:				in		std_logic;						-- system clock
	nreset:				in		std_logic;						-- asynchronous reset 							____reset___|~~~normal~~~
	LED_out:			out		std_logic						-- LED出力
);
end entity LED;

architecture rtl of LED is
---------------------------------------------------------------
-- SIGNALS
---------------------------------------------------------------
signal	rcount:	std_logic_vector(3 downto 0) := (others => '0');		-- カウンタ



---------------------------------------------------------------
-- function
---------------------------------------------------------------
function fJudgement (
	count : std_logic_vector(3 downto 0))
	return std_logic is
	variable ans : std_logic;					-- 0=点灯 1=消灯
	begin
		case count is 
			when "0000" =>	ans := '0';
			when "0001" =>	ans := '0';
			when "0010" =>	ans := '0';
			when "0011" =>	ans := '0';
			when "1011" =>	ans := '0';
			when "1100" =>	ans := '0';
			when "1101" =>	ans := '0';
			when others => 	ans := '1';
		end case;
	return std_logic(ans);
end;

begin

-----------------------------------------------------------
--
-- カウンタを回す
--
-----------------------------------------------------------
process (clock,nreset) begin
	if nreset = '0' then
		rcount <= (others => '0');
	elsif clock' event and clock = '1' then
		rcount <= rcount + '1';
	end	if;
end process;


LED_out <= fJudgement(rcount);

end rtl;

 次にテストベンチを記載いたします。

--  TITLE:					"TB_LED.vhd"
--  MODULE NAME:			Test Bench
--  PROJECT CODE:			
--  AUTHOR:					
--  CREATION DATE:			
--  REVISION HISTORY:  	    
--  SOURCE:            		
--  LICENSE:           		Copyright (c) 2021 nakaharagiken.com
--  DESCRIPTION:            
--  NOTES TO USER:      	
--  SOURCE CONTROL:  	    
--
--
--
--
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
--use std.TEXTIO.all;					--	textio package
--use ieee.std_logic_textio.all;		--	textio package


entity TB_LED is
end TB_LED;

architecture sim of TB_LED is

component LED is
port (
	clock:				in		std_logic;						-- system clock
	nreset:				in		std_logic;						-- asynchronous reset 							____reset___|~~~normal~~~
	LED_out:			out		std_logic						-- LED出力
);
end component;


constant SYSCLK_PERIOD : time := 25 ns; -- 40MHz


-- 信号の宣言
signal	rclock:				std_logic;						-- system clock
signal	rnreset:			std_logic;						-- asynchronous reset 					____reset___|~~~normal~~~
signal	wLED_out:			std_logic;						-- LED出力

begin

inst_LED : LED
port map(
	clock				=>	rclock,				--	in		std_logic;						-- system clock
	nreset				=>	rnreset,			--	in		std_logic;						-- asynchronous reset 							____reset___|~~~normal~~~
	LED_out				=>	wLED_out			--	out		std_logic						-- LED出力
);


-- Clock Driver
process begin
	rclock <= '1';
	wait for SYSCLK_PERIOD / 2;
	rclock <= '0';
	wait for SYSCLK_PERIOD / 2;
end process;

-- reset
process begin
	rnreset <= '0';
	wait for (SYSCLK_PERIOD * 2);
	rnreset <= '1';
	wait;
end process;


end sim;

 かなり簡単な回路なので、テストベンチについては解説しません。

 LED.vhdのファイルで、40行目がfunctionの部分です。この場合には別にfunctionを使う必要は無いと思いますが、組み合わせ回路を一つの塊として管理するには、このようなデコーダのような回路が多くなると思います。

 私がfunctionを使う例として多いのは、何かの判断回路です。判断回路に何らかのルールがある場合には、数式にしてしまえば良いのですが、ルールが数式化できないような場合には、表のようなものを作って入力の値に沿って出力を決める必要が生じるので、functioncを使って判断する事が多いです。

 もちろん、functionを使わなくてもこのLED.vhdのような回路は記述できるのですが、たとえばシーケンサの中で判断するような場合に、ソースコードとして可読性が悪くなるので、functionを使って判断回路を明確にしたりします。

 本来、functionはもっと多用されるべき記述方法なのですが、私の周りでもあまり使う人が少ないので紹介しました。可読性を良くすることは後のメンテナンスにも影響しますので、ぜひfunctionを利用してください。