第9回: 順序回路のHDL記述(1): フリップフロップ・カウンタ

同期リセットつきレジスタ

[p.79] いわゆるDフリップフロップで、クロックclkの立ち上がり時に、 リセットrst=0ならば出力q=0となり、rst=1ならばq=dとなる、 というもので、次のようなVHDL記述になります。 (ここでは出力、入力がともに8本あるものの例を示しています。 このようなタイプのDフリップフロップの束を、 値を記憶するもの、という意味で、レジスタ、と呼ぶことが多いようです)
library ieee;
use ieee.std_logic_1164.all;

entity sync_reg8 is
  port (
    clk: in std_logic;
    d: in std_logic_vector(7 downto 0);
    q: out std_logic_vector(7 downto 0)
  );
end sync_reg8;

architecture arch of sync_reg8 is
begin
  process (clk) begin
    if (clk'event and clk = '1') then
      if (rst = '0') then
        q <= "00000000";
      else
        q <= d;
      end if;
    end if;
  end process;
end arch;
process文の中のif文の中で、「'event」という記述がありますが、 これは、clkのエッジ、つまり0→1に変わるタイミング、あるいは逆に0→1に 変わるタイミング、のときに真になります。 つまり、その条件と、もう1つのclK='1'で、clkが0→1に変わる 立ち上がりをとらえていることになります。

非同期セットつきレジスタ

[p.80] 今度は、リセットが、clkの立ち上がりとは無関係にかけられる レジスタ、です。
library ieee;
use ieee.std_logic_1164.all;

entity async_reg8 is
  port (
    clk: in std_logic;
    d: in std_logic_vector(7 downto 0);
    q: out std_logic_vector(7 downto 0)
  );
end async_reg8;

architecture arch of async_reg8 is
begin
  process (clk, rst) begin
    if (rst == '0') then
      q <= "00000000";
    elseif (clk'event and clk = '1') then
      q <= d;
    end if;
  end process;
end arch;
さきほどの同期リセットつきレジスタの場合との違いに注意しておきましょう。

単純なカウンタ

clkの立ち上がりごとに、値が1ずつ増えていくカウンタも、 VHDLで記述することができます。
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity count8 is
  port (
    clk: in std_logic;
    q: out std_logic_vector(7 downto 0);
  );
end count8;

architecture arch of count8 is
  signal q_reg: std_logic_vector(7 downto 0);
begin
  process (clk) begin
    if (clk'event and clk = '1') then
      if (rst = '0') then
        q_reg <= "00000000";
      else
        q_reg <= q_reg + 1;
      end if;
    end if;
  end process;
  q <= q_reg;
end arch;
基本的には、レジスタの場合と同じで、クロックの立ち上がりに、 値を1ずつ足している、つまり出力の値が1ずつ増えていく、という動作を していることに注意しておきましょう。

レジスタファイル

[p.82] 1バイト(8ビット)のデータを、8個、記憶できるメモリの一種として、 レジスタファイルをVHDLで記述してみます。
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity regfile is
  port (
    clk, rst: in std_logic;
    d: in std_logic_vector(7 downto 0);
    n: in std_logic_vector(2 downto 0);
    w: in std_logic;
    q: out std_logic_vector(7 downto 0);
  );
end regfile;

architecture arch of regfile is
  type t_reg_f is array (integer range 0 to 7)
      of std_logic_vector(7 downto 0);
  signal regf: t_regf;
begin
  process (clk) begin
    if (clk'event and clk = '1') then
      if (rst = '0') then
        for i in 0 to 7 loop
          regf(i) <= "00000000";
        end loop;
      elsif (w = '1') then
        regf(to_integer(n)) <= d;
      end if;
    end if;
  end process;
  q <= regf(to_integer(n));
end arch;
typeという、型宣言を行う記述が出てきました。 t_reg_fという型を、1バイトのデータ(std_logic_vector(7 downto 0))の、 添え字が0〜7の配列という型として定義して、 その型のregfという名前のsignalを宣言して、これをレジスタファイルとして 使っています。

clkの立ち上がり時に、w=1ならばn番目のレジスタに書き込み、 また出力qに、n番目のレジスタの値が出力されています。


配布資料
この回のソボクな疑問集
戻る