平均化をVHDL,Verilogで設計する

平均化をVHDL,Verilogで設計する

平均化のデジタル回路設計で設計の概念を解説しましたので、実際にVHDLとVerilogで設計してみます。

まず、VHDLのソースコードを示します。

--  TITLE:					"average.vhd"
--  MODULE NAME:			
--  PROJECT CODE:			
--  AUTHOR:					(****@nakaharagiken.com)
--  CREATION DATE:			2020.8.22
--  SOURCE:            		
--  LICENSE:           		Copyright (c) 2020 nakaharagiken All rights reserved. 
--  DESCRIPTION:            4回平均回路
--  NOTES TO USER:			
--  SOURCE CONTROL:			
--  REVISION HISTORY:  	    v0.1	2020.8.22	First edition
--
--
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;


entity average is
port (
	clock:				in	std_logic;							-- system clock
	nreset:				in	std_logic;							-- asynchronous reset 				____reset___|~~~normal~~~
	indata:				in	std_logic_vector(7 downto 0);		-- 入力データ
	avgdata:			out	std_logic_vector(7 downto 0)		-- 出力
);
end entity average;

architecture rtl of average is

---------------------------------------------------------------
-- SIGNALS
---------------------------------------------------------------
signal	rDFF_A:			std_logic_vector(7 downto 0);		-- 8bitレジスタ
signal	rDFF_B:			std_logic_vector(7 downto 0);		-- 8bitレジスタ
signal	rDFF_C:			std_logic_vector(7 downto 0);		-- 8bitレジスタ
signal	rDFF_D:			std_logic_vector(7 downto 0);		-- 8bitレジスタ
signal	rDFF_Ans:		std_logic_vector(7 downto 0);		-- 8bitレジスタ

signal	wMulti_A:		std_logic_vector(7 downto 0);		-- 1/4データ
signal	wMulti_B:		std_logic_vector(7 downto 0);		-- 1/4データ
signal	wMulti_C:		std_logic_vector(7 downto 0);		-- 1/4データ
signal	wMulti_D:		std_logic_vector(7 downto 0);		-- 1/4データ

begin

------------------------------------------
-- シフトレジスタ
------------------------------------------
process (clock,nreset) begin
	if nreset = '0' then									-- リセット初期化
		rDFF_A <= (others => '0');
		rDFF_B <= (others => '0');
		rDFF_C <= (others => '0');
		rDFF_D <= (others => '0');
	elsif clock' event and clock = '1' then					-- clock 立ち上がり指示
		rDFF_A <= indata;
		rDFF_B <= rDFF_A;
		rDFF_C <= rDFF_B;
		rDFF_D <= rDFF_C;
	end if;
end process;

------------------------------------------
-- 1/4計算=右2ビットシフト
-- 7 6 5 4 3 2 1 0
-- 0 0 7 6 5 4 3 2 1 0
------------------------------------------
wMulti_A <= "00" &amp; rDFF_A(7 downto 2);
wMulti_B <= "00" &amp; rDFF_B(7 downto 2);
wMulti_C <= "00" &amp; rDFF_C(7 downto 2);
wMulti_D <= "00" &amp; rDFF_D(7 downto 2);

------------------------------------------
-- 答えのラッチ
------------------------------------------
process (clock,nreset) begin
	if nreset = '0' then
		rDFF_Ans <= (others => '0');
	elsif clock' event and clock = '1' then
		rDFF_Ans <= wMulti_A + wMulti_B + wMulti_C + wMulti_D;		-- 加算
	end if;
end process;

avgdata <= rDFF_Ans;

end architecture rtl;

 47行目から8ビット×4段のシフトレジスタを作成しています。簡単にするためにクロック同期そのままで設計しています。実際に使う時にはイネーブル等でクロックを間引く事も必要になるでしょう。

 64行目から1/4の回路なので説明が必要です。平均化のデジタル回路設計で解説したように、予めシフトレジスタの値を1/4にするのですが、右にビットシフトを2bitします。2bitと言っても一気に2bitできるので、この書き方を覚えてください。

 wMulti_A <= “00” & rDFF_A(7 downto 2); はMSB側の2ビットに00を入れて、下位側はrDFF_Aの7ビット目から2ビット目までを入れます。このようにすることで、右2bitシフトしています。図で説明すると次のようになります。

 rDFF_Aが右に2ビット分ズレているのがわかるでしょうか? rDFF_A[7]はwMulti_A[5]に入力されています。つまり、1ビットずつ記載するのであれば次のようになります。

wMulti_A(7) <= ‘0’;
wMulti_A(6) <= ‘0’;
wMulti_A(5) <= rDFF_A(7);
wMulti_A(4) <= rDFF_A(6);
wMulti_A(3) <= rDFF_A(5);
wMulti_A(2) <= rDFF_A(4);
wMulti_A(1) <= rDFF_A(3);
wMulti_A(0) <= rDFF_A(2);

 上記のように1bitずつバラバラに記載するのも良いですし、wMulti_A <= “00” & rDFF_A(7 downto 2); のように1行で記載しても良いです。結果は同じです。これは記載するエンジニアの好みですが、wMulti_A <= “00” & rDFF_A(7 downto 2);のように1行で記述する方が多いのではないでしょうか。8bitぐらいでしたら、バラバラに書けるのですが、32bitぐらいになると面倒になってきますし、記述誤りが発生します。

 これは経験上の話ですが、意外にバラバラに記載してその中の1行が間違っている。というのを見つけるのは結構難しく感じます。だいたい実行結果から、ビットシフトの中に記述間違いがある。とわかるのですが、それがどのビットなのかを探すのは結構大変です。その点1行で書いていれば、必ずその1行の中に誤り(バグ)があるので、見つけるのは容易です。

 右2ビットシフトの場合、MSB側の2ビットを捨てているので、これが誤差となります。信号であればノイズになります。平均化した値の用途によってはこの誤差を許さない場合がありますので、そのような場合には、1/4する時に誤差が生じないようにビットを一旦拡大する。等の処置が必要になります。

 74行目からは計算結果をラッチ(フリップフロップ)しています。ラッチという言葉はこの場合誤っているのですが、現場ではデータを最後に揃えるような時にも「ラッチ」という言い回しをします。

 81行目が加算している部分です。単純に足し算です。これは予め1/4しているので、rDFF_Ansのビット数が加算した値をオーバーフローしない。とわかっているのでできる計算です。このようにオーバーフローしない。とわかっている。というポイントは重要です。もし、わかっていない場合には、オーバーフローしても良いようにビットを広げるか、オーバーフローを検出するような回路を追加する必要があります。

 最後に、Verilogで同じ回路を記載した例を示します。

//  TITLE:					"average.v"
//  MODULE NAME:			
//  PROJECT CODE:			
//  AUTHOR:					 (****@nakaharagiken.com)
//  CREATION DATE:			2020.8.23
//  SOURCE:            		
//  LICENSE:           		Copyright (c) 2020 nakaharagiken All rights reserved. 
//  DESCRIPTION:            4回平均回路
//  NOTES TO USER:			
//  SOURCE CONTROL:			
//  REVISION HISTORY:  	    v0.1	2020.8.23	First edition
//
//
`timescale 1ns/1ps


module average(
	clock,							//	in	std_logic;							-- system clock
	nreset,							//	in	std_logic;							-- asynchronous reset 				____reset___|~~~normal~~~
	indata,							//	in	std_logic_vector(7 downto 0);		-- 入力データ
	avgdata							//	out	std_logic_vector(7 downto 0)		-- 出力
);

input			clock;				//	in	system clock
input			nreset;				//	in	asynchronous reset 				____reset___|~~~normal~~~
input	[7:0]	indata;				//	in	std_logic_vector(7 downto 0);		-- 入力データ
output	[7:0]	avgdata;			//	out	std_logic_vector(7 downto 0)		-- 出力



///////////////////////////////////////////////////////////////
// SIGNALS
///////////////////////////////////////////////////////////////
reg		[7:0]	rDFF_A;				// 8bitレジスタ
reg		[7:0]	rDFF_B;				// 8bitレジスタ
reg		[7:0]	rDFF_C;				// 8bitレジスタ
reg		[7:0]	rDFF_D;				// 8bitレジスタ
reg		[7:0]	rDFF_Ans;			// 8bitレジスタ

wire	[7:0]	wMulti_A;			// 1/4データ
wire	[7:0]	wMulti_B;			// 1/4データ
wire	[7:0]	wMulti_C;			// 1/4データ
wire	[7:0]	wMulti_D;			// 1/4データ


//////////////////////////////////////////
// シフトレジスタ
//////////////////////////////////////////
always @ (posedge  clock, negedge nreset) begin
	if (!nreset) begin
		rDFF_A <= 8'h00;
        rDFF_B <= 8'h00;
        rDFF_C <= 8'h00;
        rDFF_D <= 8'h00;
	end else begin
		rDFF_A <= indata;
		rDFF_B <= rDFF_A;
		rDFF_C <= rDFF_B;
		rDFF_D <= rDFF_C;
	end
end


//////////////////////////////////////////
// 1/4計算=右2ビットシフト
// 7 6 5 4 3 2 1 0
// 0 0 7 6 5 4 3 2 1 0
//////////////////////////////////////////
assign wMulti_A = {2'b00,rDFF_A[7:2]};
assign wMulti_B = {2'b00,rDFF_B[7:2]};
assign wMulti_C = {2'b00,rDFF_C[7:2]};
assign wMulti_D = {2'b00,rDFF_D[7:2]};

//////////////////////////////////////////
// 答えのラッチ
//////////////////////////////////////////
always @ (posedge  clock, negedge nreset) begin
	if (!nreset) begin
		rDFF_Ans <= 8'h00;
	end else begin
		rDFF_Ans <= wMulti_A + wMulti_B + wMulti_C + wMulti_D;			// 加算
	end
end

assign avgdata = rDFF_Ans;

endmodule