遅延可変シフトレジスタ(VHDL)
概要
遅延サイクルと幅を設定可能なシフトレジスタのVHDL版です。
FF生成は本モジュールをパラメーターを変えて使いまわすと楽そう。
ModelSimで動作確認、Vivado2018.1にて実装確認をしました。
ソースコード
shift_reg.vhd
-- shift_reg.vhd -- author:manaka -- date:19/09/07 -- Description:First -- History -- v0.1 first -- Library library IEEE; use IEEE.std_logic_1164.all; -- entity entity SHIFT_REG is generic ( SHIFT_CYCLE : integer := 5 ; SHIFT_WIDTH : integer := 12 ); port ( RST : in std_logic; CLK : in std_logic; DATA_IN : in std_logic_vector( SHIFT_WIDTH - 1 downto 0); DATA_OUT : out std_logic_vector( SHIFT_WIDTH - 1 downto 0) ); end SHIFT_REG; -- architecture architecture RTL of SHIFT_REG is subtype DATA_WIDTH is std_logic_vector( SHIFT_WIDTH-1 downto 0 ); type DFF_ARRAY_WIRE is array ( SHIFT_CYCLE downto 0 ) of DATA_WIDTH; type DFF_ARRAY_REG is array ( SHIFT_CYCLE downto 1 ) of DATA_WIDTH; signal data_ff : DFF_ARRAY_WIRE; signal data_ff_r : DFF_ARRAY_REG; begin GEN_SHIFT: for reg_lp in 0 to SHIFT_CYCLE-1 generate process(RST,CLK) begin if(RST = '1')then data_ff_r(reg_lp+1) <= (others => '0'); elsif(CLK'event and CLK = '1')then data_ff_r(reg_lp+1) <= data_ff(reg_lp); end if; end process; end generate GEN_SHIFT; GEN_WIRE: for wire_lp in 1 to SHIFT_CYCLE generate data_ff(wire_lp) <= data_ff_r(wire_lp); end generate GEN_WIRE; -- external port -- data_ff(0) <= data_in ; data_out <= data_ff(SHIFT_CYCLE) ; end RTL;
検証環境
- shift_reg_tb.vhd
shift_reg_top.vhd
-- shift_reg_top.vhd -- author:manaka -- date:19/09/07 -- Description:First -- History -- v0.1 first -- Library library IEEE; use IEEE.std_logic_1164.all; -- entity entity SHIFT_REG_TOP is port ( RST : in std_logic; CLK : in std_logic; DATA_IN_01 : in std_logic_vector(11 downto 0); DATA_OUT_01 : out std_logic_vector(11 downto 0); DATA_IN_02 : in std_logic_vector(31 downto 0); DATA_OUT_02 : out std_logic_vector(31 downto 0); DATA_IN_03 : in std_logic_vector( 0 downto 0); DATA_OUT_03 : out std_logic_vector( 0 downto 0) ); end SHIFT_REG_TOP; -- architecture architecture RTL of SHIFT_REG_TOP is component SHIFT_REG is generic ( SHIFT_CYCLE : integer := 5 ; SHIFT_WIDTH : integer := 12 ); port ( RST : in std_logic; CLK : in std_logic; DATA_IN : in std_logic_vector( SHIFT_WIDTH - 1 downto 0); DATA_OUT : out std_logic_vector( SHIFT_WIDTH - 1 downto 0) ); end component; begin ------------------------ -- shift_reg module ------------------------ shift_reg_i1: SHIFT_REG generic map( SHIFT_CYCLE => 5, SHIFT_WIDTH => 12 ) port map( RST => RST, CLK => CLK, DATA_IN => DATA_IN_01, DATA_OUT => DATA_OUT_01 ); shift_reg_i2: SHIFT_REG generic map( SHIFT_CYCLE => 11, SHIFT_WIDTH => 32 ) port map( RST => RST, CLK => CLK, DATA_IN => DATA_IN_02, DATA_OUT => DATA_OUT_02 ); -- shorten Description shift_reg_i3: SHIFT_REG generic map(22,1)port map(RST,CLK,DATA_IN_03,DATA_OUT_03); -- shift_reg_i3: SHIFT_REG -- generic map( -- SHIFT_CYCLE => 22, -- SHIFT_WIDTH => 1 -- ) -- port map( -- RST => RST, -- CLK => CLK, -- DATA_IN => DATA_IN_03, -- DATA_OUT => DATA_OUT_03 -- ); end RTL;
shift_reg_tb.vhd
-- shift_reg.vhd -- author:manaka -- date:19/09/07 -- Description:First -- History -- v0.1 first -- Library library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; -- entity entity SHIFT_REG_TB is end SHIFT_REG_TB; architecture SIM of SHIFT_REG_TB is signal CLK : std_logic; constant clk_period : time := 100 ns; signal RST : std_logic; signal DATA_IN_01 : std_logic_vector(11 downto 0); signal DATA_OUT_01 : std_logic_vector(11 downto 0); signal DATA_IN_02 : std_logic_vector(31 downto 0); signal DATA_OUT_02 : std_logic_vector(31 downto 0); signal DATA_IN_03 : std_logic_vector( 0 downto 0); signal DATA_OUT_03 : std_logic_vector( 0 downto 0); -- Test Module component SHIFT_REG_TOP is port ( RST : in std_logic; CLK : in std_logic; DATA_IN_01 : in std_logic_vector(11 downto 0); DATA_OUT_01 : out std_logic_vector(11 downto 0); DATA_IN_02 : in std_logic_vector(31 downto 0); DATA_OUT_02 : out std_logic_vector(31 downto 0); DATA_IN_03 : in std_logic_vector( 0 downto 0); DATA_OUT_03 : out std_logic_vector( 0 downto 0) ); end component; begin -- generate clk process begin CLK <= '1'; wait for clk_period/2; CLK <= '0'; wait for clk_period/2; end process; -- Instance0 shift_reg_top_i0: SHIFT_REG_TOP port map( RST => RST , CLK => CLK , DATA_IN_01 => DATA_IN_01 ,--: in std_logic_vector(11 downto 0); DATA_OUT_01 => DATA_OUT_01 ,--: out std_logic_vector(11 downto 0); DATA_IN_02 => DATA_IN_02 ,--: in std_logic_vector(31 downto 0); DATA_OUT_02 => DATA_OUT_02 ,--: out std_logic_vector(31 downto 0); DATA_IN_03 => DATA_IN_03 ,--: in std_logic_vector( 0 downto 0); DATA_OUT_03 => DATA_OUT_03 --: out std_logic_vector( 0 downto 0) ); -- INITIALIZE process begin RST <= '1'; DATA_IN_01 <= (others => '0'); DATA_IN_02 <= (others => '0'); DATA_IN_03 <= (others => '0'); wait for clk_period*10; RST <= '0'; wait for clk_period*10; DATA_IN_01 <= X"AAA"; DATA_IN_02 <= X"55555555"; DATA_IN_03 <= "1"; wait for clk_period*50; DATA_IN_01 <= (others => '0'); DATA_IN_02 <= (others => '0'); DATA_IN_03 <= (others => '0'); wait for clk_period*50; std.env.finish; end process; end SIM; configuration BEHAVIOR OF SHIFT_REG_TB IS for SIM end for; end BEHAVIOR;
検証結果
シミュレーション検証
TOPで宣言したモジュールがパラメーターにより遅延されることを確認。
- 12bit 5サイクル
- 32bit 11サイクル
- 1bit 22サイクル
ツール合成(Vivado2018.1)
verilogはintelのQuartus13.1で生成回路を確認したため、VHDL版はXilinxのVivado2018.1を用いて検証してみる。
Elaborated Design
Vivado2018.1にてElaborated Designを確認。FFが125サイクルと3211サイクルと1*22サイクル生成されている。
Synthesized Design
テクノロジーマッピングはDFFが並ぶわけでなくQuartusの時の経験上なにか工夫があると踏んでいたが、やはりありそうだ。
ただパッと見たところ何が起こっているかわからない。
i1-i3ができている。中を見てみると...
やはりFFの羅列ではなさそうだ。
i3(1bit32段シフト)を拡大してみる。
解析を行い以下の図に簡略化した。基本的にSRLC16Eまたは32Eが使用されている。これはLUTの分散メモリをFF的に使用できる仕組みのようである。
これだけでもFFの仕組みが完成しそうだが、遅延させた'1'信号とANDさせている。おそらく分散メモリの指定アドレスまでデータが詰まるまでに意図しない値が出ないようにするための処理と推測される。
ゲートのためのシフト信号を作るためにFDCE(プリミティブ:D Flip-Flop with Clock Enable and Asynchronous
Clear)を1番シフトが大きいシンボルで生成し、あとは必要段数を他のロジックに渡して使いまわしている。
Xilinxの7シリーズアーキテクチャはさすがと感じたが、QuartusはCyclone3で見ていたためIntel(Altera)も同様になにかしら進化していると考えられる。