よくわからないFPGAのこととか

よくわからないFPGAとか回路とか数学とかについて

遅延可変シフトレジスタ(VHDL)

概要

遅延サイクルと幅を設定可能なシフトレジスタVHDL版です。
FF生成は本モジュールをパラメーターを変えて使いまわすと楽そう。
ModelSimで動作確認、Vivado2018.1にて実装確認をしました。

f:id:manaka1122:20200719040441p:plain
Shift Register Module

ソースコード


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 TOPからパラメーターでデータ幅とサイクル数を定義
      • shift_reg_i1.shift_reg.vhd width:12 cycle数: 5
      • shift_reg_i2.vhd width:32 cycle数:11
      • shift_reg_i3.vhd width: 1 cycle数:22

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サイクル

f:id:manaka1122:20200712140114j:plain
ModelSIm確認


ツール合成(Vivado2018.1)

verilogintelのQuartus13.1で生成回路を確認したため、VHDL版はXilinxのVivado2018.1を用いて検証してみる。


Elaborated Design

Vivado2018.1にてElaborated Designを確認。FFが125サイクルと3211サイクルと1*22サイクル生成されている。

f:id:manaka1122:20200712140159j:plain
Elaborated確認01
f:id:manaka1122:20200712140203j:plain
Elaborated確認02
f:id:manaka1122:20200712140156j:plain
Elaborated確認03


Synthesized Design

テクノロジーマッピングDFFが並ぶわけでなくQuartusの時の経験上なにか工夫があると踏んでいたが、やはりありそうだ。
ただパッと見たところ何が起こっているかわからない。

i1-i3ができている。中を見てみると...

f:id:manaka1122:20200712140508j:plain
テクノロジーマッピング01

やはりFFの羅列ではなさそうだ。

f:id:manaka1122:20200712140513j:plain
テクノロジーマッピング02

i3(1bit32段シフト)を拡大してみる。

f:id:manaka1122:20200712140517j:plain
テクノロジーマッピング03

解析を行い以下の図に簡略化した。基本的にSRLC16Eまたは32Eが使用されている。これはLUTの分散メモリをFF的に使用できる仕組みのようである。
これだけでもFFの仕組みが完成しそうだが、遅延させた'1'信号とANDさせている。おそらく分散メモリの指定アドレスまでデータが詰まるまでに意図しない値が出ないようにするための処理と推測される。
ゲートのためのシフト信号を作るためにFDCE(プリミティブ:D Flip-Flop with Clock Enable and Asynchronous Clear)を1番シフトが大きいシンボルで生成し、あとは必要段数を他のロジックに渡して使いまわしている。

f:id:manaka1122:20200712140521j:plain
テクノロジーマッピング04

Xilinxの7シリーズアーキテクチャはさすがと感じたが、QuartusはCyclone3で見ていたためIntel(Altera)も同様になにかしら進化していると考えられる。