シフトレジスタ

シフトレジスタ

 シフトレジスタはDFFを連ねた回路ですが、いろいろな回路の基本となる事が多く、必ずマスターしておかなくてはならない回路構成です。

 単純なシフトレジスタは入力の信号をクロック分遅延させる。という回路になります。この動作を応用して、シリアルデータの生成やその逆、高度な物ですと、ランダマイザや暗号化などに応用されています。

 今回は一番単純なシフトレジスタを紹介します。回路構成は次のようになっています。

 この場合DFFが8個繋がっていますので、8ビットのシフトレジスタと呼びます。シフトレジスタは普通このように1ビットデータを遅延させる構成になっています。同じように1ビットではなく8ビットなどのバスを遅延させる回路もあるのですが、そちらはあまりシフトレジスタとは呼ばないようで、FIFO(ファイフォまたはエフアイエフオー)と呼ばれています。

 DFFに入力されるクロックは同期回路なので同じクロックになります。そのクロックのタイミングで随時データが流れるようになります。一般的にシフトレジスタ回路は立ち上がりエッジを使います。立下りエッジで使ってはいいけない。という事は無いのですが、FPGAで立下りエッジを使うことはまずありません。(DDRメモリは仕様で立下りを使います)

 入力された信号は1個目のDFFに入って、1クロック後に出力されます。そして、次のDFFに入るので、最後に出てくるまでに8クロックの遅延が発生します。この遅延を得るための回路という事になります。

 動作波形を図示してみました。

 Verilogの書き方で説明します。上の図のように縦に並べてみるとわかりやすいと思います。rDFF[0]が一番左(入力側)のDFFなので、rDFF[7]にまでデータが送られている様子がわかります。

 この場合、入力信号に1クロック幅分の’1’を入力したので、1つのパルスが順次送られている様子がわかりますが、たとえば、2クロック分の’1’が入力されたなら、出力も8クロック遅れて「2クロック分の’1’」が出てきます。

 VHDLとVerilogのソースコードを掲載しますが、ソースコードではイネーブル機能を追加しました。enableが1の時にシフトレジスタが動作して、enable=0の時にはシフトレジスタが停止します。シフトレジスタは同期回路以外作りようがないのですが、それゆえにクロックの間引きみたいな使い方をすることがあります。それで、このようにenableを追加したシフトレジスタというのが良く使われます。

 初心者がこの回路を見て、まず躓くのがDFFの遅延を頭に入れていないからです。

 上の図のようにすべてのDFFの入力と出力の間に遅延があります。なので、同じクロックをDFFに入れていても、全部が同じ値にはならずに、少しづつ遅れてデータが伝わるのです。

  Verilog で説明すると、

    if (enable == 1'b1) begin
        rDFF[0] <= indata;
        rDFF[7:1] <= rDFF[6:0];
    end

この部分がシフトレジスタを生成している回路ですが、このように入力信号をrDFF[0]に接続した後は、rDFF[7:1] <= rDFF[6:0]; のようにして一気に記述することができます。VHDLでも同じ事ができます。ソースコードを参照してください。これは、

rDFF[1] <= rDFF[0];
rDFF[2] <= rDFF[1];
rDFF[3] <= rDFF[2];
rDFF[4] <= rDFF[3];
rDFF[5] <= rDFF[4];
rDFF[6] <= rDFF[5];
rDFF[7] <= rDFF[6];

というように記述しても同じ事です。どちらで書いても良いと思います。

以下にソースコードを掲載いたします。VHDLとVerilogの両方を掲載いたしますので、比較もできると思います。

--  TITLE:					"shift.vhd"
--  MODULE NAME:			
--  PROJECT CODE:			
--  AUTHOR:					 (****@nakaharagiken.com)
--  CREATION DATE:			2020.7.11
--  SOURCE:            		
--  LICENSE:           		Copyright (c) 2020 nakaharagiken All rights reserved. 
--  DESCRIPTION:            シフトレジスタ
--  NOTES TO USER:			
--  SOURCE CONTROL:			
--  REVISION HISTORY:  	    v0.1	2020.7.11	First edition
--
--
--
--
--
--
--
--
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;


entity shift is
port (
	clock:				in	std_logic;						-- system clock
	nreset:				in	std_logic;						-- asynchronous reset 				____reset___|~~~normal~~~
	enable:				in	std_logic;						-- イネーブル						_________|~|_____________
	indata:				in	std_logic;						-- 入力データ
	shiftout:			out	std_logic						-- 出力
);
end entity shift;

architecture rtl of shift is

---------------------------------------------------------------
-- SIGNALS
---------------------------------------------------------------
signal	rDFF:			std_logic_vector(7 downto 0);		-- 8bitシフトレジスタ


begin

------------------------------------------
-- 8bit シフトレジスタ
------------------------------------------
process (clock,nreset) begin
	if nreset = '0' then									-- リセット初期化
		rDFF <= (others => '0');
	elsif clock' event and clock = '1' then					-- clock 立ち上がり指示
		if (enable = '1') then
			rDFF(0)<= indata;
			rDFF(7 downto 1) <= rDFF(6 downto 0);
		end if;
	end if;
end process;


shiftout <= rDFF(7);

end architecture rtl;

 

//  TITLE:					"shift.v"
//  MODULE NAME:			
//  PROJECT CODE:			
//  AUTHOR:					 (****@nakaharagiken.com)
//  CREATION DATE:			2020.7.10
//  SOURCE:            		
//  LICENSE:           		Copyright (c) 2020 nakaharagiken All rights reserved. 
//  DESCRIPTION:            シフトレジスタ
//  NOTES TO USER:			
//  SOURCE CONTROL:			
//  REVISION HISTORY:  	    v0.1	2020.7.10	First edition
//
//
//
//
//
//
//
//
`timescale 1ns/1ps


module shift(
	clock,							//	in	system clock
	nreset,							//	in	asynchronous reset 				____reset___|~~~normal~~~
	enable,							//	in	イネーブル						_________|~|_____________
	indata,							//	in	入力データ
	shiftout						//	out	出力
);

input	clock;						//	in	system clock
input	nreset;						//	in	asynchronous reset 				____reset___|~~~normal~~~
input	enable;						//	in	イネーブル						_________|~|_____________
input	indata;						//	in	入力データ
output	shiftout;					//	out	出力



///////////////////////////////////////////////////////////////
// SIGNALS
///////////////////////////////////////////////////////////////
reg		[7:0]	rDFF;				// 8bitシフトレジスタ


//////////////////////////////////////////
// 8bit シフトレジスタ
//////////////////////////////////////////
always @ (posedge  clock, negedge nreset) begin
	if (!nreset) begin
		rDFF <= 8'h00;
	end else begin
		if (enable == 1'b1) begin
			rDFF[0] <= indata;
			rDFF[7:1] <= rDFF[6:0];
		end
	end
end


// output 接続
assign	shiftout = rDFF[7];


endmodule

以下は各々のテストベンチです。

--  TITLE:					"TB_shift.vhd"
--  MODULE NAME:			TB_sshift
--  PROJECT CODE:			
--  AUTHOR:					 (****@nakaharagiken.com)
--  CREATION DATE:			2020.7.11
--  SOURCE:            		
--  LICENSE:           		Copyright (c) 2020 nakaharagiken All rights reserved. 
--  DESCRIPTION:            shift.vhdのテストベンチ
--  NOTES TO USER:			
--  SOURCE CONTROL:			
--  REVISION HISTORY:  	    v0.1	2020.7.11	First edition
--
--
--
--
--
--
--
--
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;

entity TB_shift is
end TB_shift;

architecture sim of TB_shift is

component shift is
port (
	clock:				in	std_logic;						-- system clock
	nreset:				in	std_logic;						-- asynchronous reset 				____reset___|~~~normal~~~
	enable:				in	std_logic;						-- イネーブル						_________|~|_____________
	indata:				in	std_logic;						-- 入力データ
	shiftout:			out	std_logic						-- 出力
);
end component;


constant SYSCLK_PERIOD : time := 100 ns; 				-- 10MHz

signal	i_clock:		std_logic;						-- system clock
signal	i_nreset:		std_logic;						--  asynchronous reset 				____reset___|~~~normal~~~
signal	i_enable:		std_logic;						--	イネーブル						_________|~|_____________
signal	i_indata:		std_logic;						--  入力信号
signal	o_shiftout:		std_logic;						--  出力

begin

inst_shift : shift
port map(
	clock			=>	i_clock,						-- system clock
	nreset			=>	i_nreset,						-- asynchronous reset 				____reset___|~~~normal~~~
	enable			=>	i_enable,						-- イネーブル						_________|~|_____________
	indata			=>	i_indata,						-- 入力データ
	shiftout		=>	o_shiftout						-- 出力
);


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


------------------------------------
-- 信号作成
------------------------------------
process begin

	i_nreset <= '0';									--	初期値
	i_indata <= '0';
	i_enable <= '0';

	wait for (SYSCLK_PERIOD / 10);
	wait for (SYSCLK_PERIOD * 50);

	i_nreset <= '1';
	wait for (SYSCLK_PERIOD * 100);

	i_enable <= '1';
	i_indata <= '1';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '0';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '0';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '1';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '0';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '1';
	i_enable <= '0';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '0';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '1';
	i_enable <= '0';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '1';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '1';
	i_enable <= '0';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '0';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '0';
	i_enable <= '1';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '1';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '0';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '0';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '1';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '0';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '1';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '1';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '1';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '1';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '0';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '1';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '0';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '1';
	i_enable <= '0';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '0';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '1';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '0';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '1';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '0';
	wait for (SYSCLK_PERIOD * 1);
	i_enable <= '1';
	i_indata <= '0';
	wait for (SYSCLK_PERIOD * 1);
	i_indata <= '0';
	wait;

end process;

end sim;

//  TITLE:					"TB_shift.v"
//  MODULE NAME:			TB_shift
//  PROJECT CODE:			
//  AUTHOR:					 (****@nakaharagiken.com)
//  CREATION DATE:			2020.7.10
//  SOURCE:            		
//  LICENSE:           		Copyright (c) 2020 nakaharagiken All rights reserved. 
//  DESCRIPTION:            shift.vのテストベンチ
//  NOTES TO USER:			
//  SOURCE CONTROL:			
//  REVISION HISTORY:  	    v0.1	2020.7.10	First edition
//
//
//
//
//
//
//
//
`timescale 1ns/1ps

module TB_shift;

parameter SYSCLK_PERIOD = 100;		// 10MHz


reg		i_clock;					// system clock
reg		i_nreset;					// asynchronous reset 				____reset___|~~~normal~~~
reg		i_enable;					// イネーブル
reg		i_indata;					// 入力信号
wire	o_shiftout;					// 出力信号


//////////////////////////////////////////////////////////////////////
// Clock Driver
//////////////////////////////////////////////////////////////////////
always @(i_clock)
    #(SYSCLK_PERIOD / 2.0) i_clock <= !i_clock;


//////////////////////////////////////////////////////////////////////
// Main
//////////////////////////////////////////////////////////////////////
initial
begin

	i_clock <= 0;
	i_nreset <= 0;									//	初期値
	i_indata <= 0;
	i_enable <= 0;

	repeat(50) @(posedge i_clock);
	i_nreset <= 1;
	repeat(100) @(posedge i_clock);

	i_enable <= 1'b1;
	i_indata <= 1'b1;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b0;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b0;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b1;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b0;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b1;
	i_enable <= 1'b0;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b0;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b1;
	i_enable <= 1'b0;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b1;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b1;
	i_enable <= 1'b0;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b0;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b0;
	i_enable <= 1'b1;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b1;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b0;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b0;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b1;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b0;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b1;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b1;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b1;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b1;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b0;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b1;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b0;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b1;
	i_enable <= 1'b0;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b0;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b1;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b0;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b1;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b0;
	repeat(1) @(posedge i_clock);
	i_enable <= 1'b1;
	i_indata <= 1'b0;
	repeat(1) @(posedge i_clock);
	i_indata <= 1'b0;



end

shift inst_shift(
	.clock		(i_clock),							//	in	system clock
	.nreset		(i_nreset),							//	in	asynchronous reset 				____reset___|~~~normal~~~
	.enable		(i_enable),							//	in	イネーブル						_________|~|_____________
	.indata		(i_indata),							//	in	入力データ
	.shiftout	(o_shiftout)						//	out	出力
);

endmodule