Comments
Description
Transcript
同時処理と順次処理 - 電子工学科
第5学年工学実験Ⅱ VHDL による論理回路設計 12.同時処理と順次処理 平成 26 年 4 月 電子システム工学科 香川高等専門学校 目次 1. はじめに ................................................................................................................................ 1 2. 同時処理コード ...................................................................................................................... 1 2.1 同時処理と順序処理 ............................................................................................................ 1 2.2 演算子の使用 ....................................................................................................................... 1 2.3 WHEN 文 ............................................................................................................................... 2 2.4 SELECT 文 ............................................................................................................................. 2 2.5 GENERATE 文 ........................................................................................................................ 6 2.6 同時処理を含む順序回路の実装 .......................................................................................... 9 2.7 VHDL2008 ........................................................................................................................ 11 3. 順次処理コード .................................................................................................................... 13 3.1 順次処理の概要.................................................................................................................. 13 3.2 ラッチとフリップフロップ ............................................................................................... 13 3.3 PROCESS 文 ........................................................................................................................ 13 3.4 IF 文.................................................................................................................................... 14 3.5 WAIT 文 ............................................................................................................................... 17 3.6 LOOP 文 .............................................................................................................................. 18 3.7 CASE 文............................................................................................................................... 21 3.8 CASE 文と SELECT 文 .......................................................................................................... 23 3.9 順次処理コード中の組合せ回路 ........................................................................................ 23 3.10 VHDL2008 ...................................................................................................................... 24 参考文献 ................................................................................................................................... 26 i 1. はじめに 文献[1]の 5 章同時処理コードと 6 章順次処理コードの抄訳を提供する。5 章では,同時処理文で ある when 文,select 文,generate 文等について学び,6 章では,順次処理文である process 文, および,process 文中で使用される if 文,case 文,loop 文等について学ぶ。 2. 同時処理コード 2.1 同時処理と順次処理 組合せ論理回路は,出力が現在の入力のみによって決定される回路であるから,記憶要素を持たない フィードフォワードモデルとして表現される。これに対して順序回路は出力が,以前のシステムの状態 に依存する回路であるので,記憶要素を持っている。VHDL コードは同時処理にも順序処理にもなりうる。 process,function,procedure 文内では,コードは順序処理である。しかし,VHDL コードは本質 的に同時処理であるから process 文自体は,他の文に対して同時処理である。block 文と component 文も同時処理といえるが,これらはコード生成上の観点であり,通常の文とは異なる。 純粋な同時処理文は,process やサブプログラムの外におく文であり,when,select,generate 文がそれにあたる。反対に,純粋な順序処理文は,順序処理コードの中におかれる文であり,if,wait, loop,case 文がそれにあたる。同時処理文は,組合せ論理回路の設計にのみ用いられるが,順序処理 文は組合せ回路,順序回路の両方の設計に用いられる。 注意すべきは,同時処理文では,コードの順は無意味であるということである。例えば,同時処理文 stat1,stat2,stat3 を用いるコードがあるとき,物理的には,次のように同等になる。 {stat1, stst2, stat3} = {stat3, stat2, stat1} = {stat1, stat3, stat2} 2.2 演算子の使用 回路は基本的に演算子によって記述されるとはいえ,設計上は簡単な回路の場合に限られる。次の例 は,マルチプレクサの演算子による設計例である。 例)4 入力 1 出力のマルチプレクサを演算子により記述する。演算子のみの記述は複雑で見通しが悪く なる。 libraray ieee; use ieee.std_logic_1164.all; entity mux is port (x0,x1,x2,x3; in std_logic; sel: in std_logic_vector(1 downto 0); y: out std_logic); end mux; - 1 - architectur operators_only of mux is begin y <= (not sel(1) and not sel(0) and x0) or (not sel(1) and sel(0) and x1) or ( sel(1) and not sel(0) and x2) or ( sel(1) and sel(0) and x3); end operators_only; 2.3 when 文 when 文は,最も簡単な条件文である。when 文は,順序処理の if 文とほとんど同じである。次に構 文を示す。 assignment_expression when conditions else assignment_value when conditions else ...; 例) x <= '0' when rst='0' else '1' when a='0' or b='1' else '-'; -- don't care y <= "00" when (a and b)="01" else "11" when (a and b)="10" else "ZZ"; -- high impedance when 文では複合条件が使用できる。when 文では,真理値表のすべての条件を記述する必要はないが, そうしておけば不要なラッチ回路の生成を防ぐことができる。ここで,キーワード others が有効であ る。同時処理文で有効なもう 1 つのキーワードに,unaffected がある。これはアクションがないとき に使用する。このキーワードはラッチの生成を伴うため,以前の状態を記憶しておく必要があるときに 使用する。 例)以下の 2 例は,D-FF である。2 番目の例は,すべての入力をカバーし,記憶を明示しているため, 不要なラッチを生じない。 q <= '0' when rst='1' else d when clk='1'; q <= '0' when rst='1' else d when clk='1' else unaffected; VHDL2008 では,when 文も順序処理の中で使用でき,bool 値のテストができる。 2.4 select 文 select 文は,順序処理の case 文とほとんど同じである。次に構文を示す。 - 2 - with identifier select assignment_expression when values, assignment_value when values, ...; 例) with control select y <= "000" when 0 | 1, "100" when 2 to 5, "Z--" when others; with ( a and b) select y <= "00" when "001", "11" when "100", unaffected when others; 最初の例では,複合条件を使用している。これは"|"(or)または to(range のとき)を使って指定 できる。 when value1 | value2 | ... -- value1 or value2 or ... when value1 to value2 -- range select 文では真理値表のすべての入力を包含しなければならないのでキーワード others を使用す ると便利である。unaffected も同様に有用であるが,ラッチの生成には注意を要する。さらに,信号 代入個所ではラベルが使用できる。しかしこれはあまり実用的ではないので簡単化の過程で無視される。 VHDL2008 では,select 文も select?と同様に順序処理中で使用できる。さらに don't care 入力も 使用できる。 例) when と select 文を用いたマルチプレクサの実装 上例のマルチプレクサを N ビットに変えて when 文と select 文により実装してみる。 library ieee; use ieee.std_logic_1164.all; -------------------------------------------------entity mux is generic (N: integer := 8); port(x0, x1, x2, x3: in std_logic_vector(N-1 downto 0); sel: in std_logic_vector(1 downto 0); y: out std_logic_vector(N-1 downto 0)); end entity; -------------------------------------------------- - 3 - architecture with_when of mux is begin y <= x0 when sel="00" else x1 when sel="01" else x2 when sel="10" else x3; end architecture; -------------------------------------------------architecture with_secelt of mux is begin with sel secelt y <= x0 when "00", x1 when "01", x2 when "10", x3 when others; end architecture; 論理合成では,1 つの entity に 1 つの architecture のみが許されるので,上の例では,使用しな い方の architecture はコメントにするか,以下のように configuration 文によりコンパイラに指 定する。 configuration which_mux of mux is for with_when end for; end configuration; これによりコンパイラは with_when の mux を選ぶ。1 つのコンパイルとシミュレーションが終了し たら次の mux を configuration 文で指定する。この方法の欠点は,コンパイラが両方のチェックを自 動では行わないことである。 次の例は同時処理による ALU の例である。 例)ALU ALU (Arithmetic Logic Unit)は,入力 a, b, cin, opcode と出力 y をもつ。次表に機能を 真理値表で示す。各機能は異なるオペコード(opcode)の値に対応する。上段の 8 個は論理演算,下段 は算術演算である。ALU は次のように select 文により設計される。 (1) 算術演算は signed とする。 (2) 入力 a, b のビット数は generic 宣言とする。 (3) すべての port の型は std_logic(_vector)とする。 (4) シミュレーションで解を確認する。 - 4 - Unit 論理演算 算術演算 命令 オペレーション a の補数 b の補数 AND OR NAND NOR XOR XNOR a を代入 b を代入 a を+1 b を+1 a を-1 b を-1 a,b の和 a,b のキャリー付和 y=not a y=not b y=a and b y=a or b y=a nand b y=a nor b y=a xor b y=a xnor b y=a y=b y=a+1 y=b+1 y=a-1 y=b-1 y=a+b y=a+b+cin 例) library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; -------------------------------------------------entity alu is generic (N: integer :=8); --word bits port(a, b: in std_logic_vector(N-1 downto 0); cin: in std_logic; opcode: in std_logic_vector(3 downto 0); y: out std_logic_vector(N-1 downto 0)); end entity; -------------------------------------------------architectur alu of alu is signal a_sig, b_sig: signed(N-1 downto 0); signal y_sig: signed(N-1 downto 0); signal y_unsig: std_logic_vector(N-1 downto 0); signal samll_int: integer range 0 to 1; begin ------- logic unit -----------with opcode(2 downto 0) select y_unsig <= not a when "000", not b when "001", a and b when "010", a or b when "011", a nand b when "100", a nor b when "101", a xor b when "110", a xnor b when others; - 5 - オペコード 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 ------- arithmetic unit -----------a_sig <= signed(a); b_sig <= signed(b); small_int <= 1 when cin='1' else 0; with opcode(2 downto 0) select y_sig <= a_sig when "000", b_sig when "001", a_sig+1 when "010", b_sig+1 when "011", a_sig-1 when "100", b_sig-1 when "101", a_sig+b_sig when "110", b_sig+b_sig+small_int when others; ------- mux -----------with opcode(3) select y <= y_unsig when '0', std_logic_vector(y_sig) when others; end architecture; 2.5 generate 文 generate 文も同時処理文である。generate 文の最も一般的な形は,無条件 generate であり,あ る範囲のコードを繰り返すので順序処理の loop 文にほぼ等しい。条件付き generate 文は,順序処理 の if 条件内で使用できる。 無条件 generate 文は,以下の構文によりある範囲のコードを繰り返す。ラベルは必須であり,begin は宣言文があるときのみ必要である。 label: for identifier in range generate [declarative_part begin] concurrent_statements_part end generate [label]; 例) 以下に,同等な3つのコードを示す。 signal a, b, x: bit_vector(7 downto 0); -------------------------------------------------gen: for i in 0 to 7 generate x(i) <= a(i) xor b(7-i); end generate; -------------------------------------------------gen: for i in a'range generate x(i) <= a(i) xor b(7-i); end generate; - 6 - gen: for i in a'reverse_range generate x(i) <= a(i) xor b(7-i); end generate; 次に,条件付き generate 文(または if-generate 文)の構文を示す。 label: if condition generate [declarative_part begin] concurrent_statements_part end generate [ label]; VHDL2008 では,elsif/else が使用でき,end generate の前の end と label の交換ができ, case-generate も導入された。 generate 文では,一般に範囲の指定は固定的でなければならない。例えば次の x は入力なので,論 理合成に失敗する。 NotOK: for i N in 0 to x generate ... end generate; 複数の代入のある signal にも注意を要する。variable は値が即時変化するため問題がないが signal はそうではない。 例) 最初のブロックは,x の各ビットへの代入が 1 度だけなので論理合成できる。2 番目の例は,y への代 入が数回になるため正しくない。3 番目の例も z の変更が最大 4 回になるため正しくない。 signal a, b, x, y: bit_vector(3 downto 0); signal z: integer range 0 to 7; -------------------------------------------------OK: for i in x'range generate x(i) <= '1' when (a(i) and b(i))='1' else '0'; end generate; -------------------------------------------------NotOK: for i in y'low to y'high generate y <= "1111" when (a(i) and b(i))='1' else "0000"; end generate; -------------------------------------------------NotOK: for i in 0 to 3 generate x <= z+1 when a(i)='1'; end generate; - 7 - 例)アドレスのデコード アドレスデコーダを std_logic 型の port で作成する。address へは std_logic_unsigned パッ ケージにある変換関数 conv_integer()を用いた。 library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; -------------------------------------------------entity address_decoder is generic (N: natuarl :=3); -- number of address bits port (address: in std_logic_vector(N-1 downto 0); ena: in std_logic; word_line: out std_logic_vector(2**N-1 downto 0)); end entity; -------------------------------------------------architecture decoder of address_decoder is signal addr: natural range 0 to 2**N-1; begin addr <= conv_integer(address); gen: for i in word_line'range generate word_line(i) <= '0' when i = addr and ena='1' else '1'; end generate; end architecture; generate は component の実装に有用である。次に例を示す。 例)component の実装に使用した generate 文 -----The component ------------------------------library ieee; use ieee.std_logic_1164.all; -------------------------------------------------entity mux2x1 is port(a, b, sel: in std_logic; x: out std_logic); end entity; -------------------------------------------------architecture mux2x1 of mux2x1 is begin x <= a when sel='0' else b; end architecture; - 8 - ----Main code------------------------------------library ieee; use ieee.std_logic_1164.all; -------------------------------------------------entity mux2x3 is port(a, b: in std_logic_vector(2 downto 0); sel: in std_logic; x: out std_logic_vector(2 downto 0)); end entity; -------------------------------------------------architecture mux2x3 of mux2x3 is --- component declaration----component mux2x1 is port(a, b, sel: in std_logic; x: out std_logic); end component; begin -- component instantiation --generate_muc¥x2x3: for i in 0 to 2 generate comp: mux2x1 port map (a(i), b(i), sel, x(i)); end generate generate_mux2x3; end architecture; 2.6 同時処理を含む順序回路の実装 組合せ回路は同時処理コードにより実装されるべきであるが,いかなる回路も NAND や NOR で構成で きるため,順序回路も NAND や NOR により構成できる。それゆえ,順序回路も同時処理コードで表現で きることになる。しかし,コードが複雑になりデバッグが困難であるため推奨できない。 例) 同時処理により実装した DFF entity concurrent_dff is port(d, clk: in bit; q: buffer bit); end entity; -------------------------------------------------architecture concurrent of concurrent_dff is signal p: bit; begin p <= d when clk='0' else p; -- 1st mux q <= p when clk='1' else q; -- 2nd mux end architecture; 例)演算回路の実装 演算回路は,算術演算子(+,-,*,/,**,ABS,REM,MOD)を用いて構成される。最初の 4 個はなじみ の演算子である。演算回路のインターフェイス(port)型は,integer,std_logic_vector である が , 内 部 的 に は unsigned と signed 型 を 使 用 す る 。 こ れ ら は パ ッ ケ ー ジ numeric_std と std_logic_arith にある。 これらの演算子を使用するのは関数のオペランドとして用いるサイズが必要である。 - 9 - function "+" (L, R: signed) return signed; -- result subtype: signed(max(L'length, R'length)-1 downto 0) -------------------------------------------------function "-" (L, R: signed) return signed; -- result subtype: signed(max(L'length, R'length)-1 downto 0) -------------------------------------------------function "*" (L, R: signed) return signed; -- result subtype: signed((L'length+R'length-1) downto 0) -------------------------------------------------function "/" (L, R: signed) return signed; -- result subtype: signed(L'length-1 downto 0) unsigned 型を使うと次のようになる。 signal a_uns, b_uns, sum: unsigned(7 downto 0); signal sum_uns: unsigned(9 downto 0); signal cin, cout_sum: std_logic; sum_uns <= ('0' & a_uns & cin)+('0' & b_uns & '1'); sum <= sum_uns( 8 downto 1); count_sum <= sum_uns(9); この例では,sum_uns は 10 ビットであるから cin に右に'1',左に'0'を付加している。sum_uns の LSB は不使用,MSB は cout_sum である。 signal a_sig, b_sig, sum: signed(7 downto 0); signal sum_sig: signed(9 downto 0); signal cin, cout_sum: std_logic; sum_sig <= (a_sig(7) & a_sig & cin)+(b_sig(7) & b_sig & '1'); sum <= sum_sig( 8 downto 1); count_sum <= sum_sig(9); このコードは,符号ビットの拡張が異なるだけである。しかし,この方法は減算に使えない。以下に 対策を示す。sub_sig の 3 項は符号拡張していることに注意。 signal a_sig, b_sig, sum, sub: signed(7 downto 0); signal sum_sig, sub_sig: signed(8 downto 0); signal cin, cout_sum, sout_sub: std_logic; sum_sig <= (a_sig(7) & a_sig)+(b_sig(7) & b_sig)+('0' & cin); sum <= sum_sig( 7 downto 0); count_sum <= sum_sig(8); sub_sig <= (a_sig(7) & a_sig)-(b_sig(7) & b_sig)+('0' & cin); sub <= sub_sig( 7 downto 0); count_sub <= sub_sig(8); 整数の加減算に対して,固定小数点や浮動小数点での演算では,桁落ちはない。 - 10 - 例)加減算器の実装(推奨版) library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; -------------------------------------------------entity signed_add_sub is generic (N: integer :=4); -- number of input bits port(a, b: in std_logic_vector(N-1 downto 0); cin: in std_logic; sum, sub: out std_logic_vector(N downto 0)); -- sum, sub: out std_logic_vector(N-1 downto 0); -- cout_sum, cout_sub: out std_logic); end entity; -------------------------------------------------architecture signed_add_sub of signed_add_sub is signal a_sig, b_sig: signed(N-1 downto 0); signal sum_sig, sub_sig: signed(N downto 0); begin -- convert to signed ---a_sig <= signed(a); b_sig <= signed(b); -- add and subtract ---sum_sig <= (a_sig(N-1) & a_sig)+(b_sig(N-1) & b_sig)+('0' & cin); sub_sig <= (a_sig(N-1) & a_sig)-(b_sig(N-1) & b_sig)+('0' & cin); -- output option #1 ----sum <= std_logic_vector(sum_sig); sub <= std_logic_vector(sub_sig); -- output option #2 ------sum <= std_logic_vector(sum_sig(N-1 downto 0)); --sub <= std_logic_vector(sub_sig(N-1 downto 0)); --count_sum <= std_logic(sum_sig(N)); --count_sub <= std_logic(sub_sig(N)); end architecture; 2.7 VHDL2008 VHDL2008 では,次の拡張がなされている。 (1) 同時処理文 when,select は順序処理コードの中でも使用できる。when 文は if 文に置き替え 可能であり,if 節内でも使用できる。同様に select 文は case 文に置き替えられる。 (2) when 文にはブール論理テストが使用できる。以下の 2 例は等価である。 x <= '0' when '1' when '-'; x <= '0' when '1' when '-'; rst='0' else a='0' or b='1' else not rst else not a or b else (3) don't care 文が使用できる select?が導入された。 - 11 - with interrupt select? priority <= 4 when "1---", 3 when "01--", 2 when "001-", 1 when "0001", 0 when others; (4) 条件付き if-generate 文で elsif/else が使用できる。 label: if condition generate [ declarative_part begin] concurrent_statements_part [ elsif condition generate [ declarative_part begin] concurrent_statements_part [ else generate [ declarative_part begin] concurrent_statements_part end generate [label]; (5) 新しく条件付き generate 文の case-generate 文が導入された。 label: case expression generate when condition_1 => [ declarative_part begin] concurrent_statements_part when condition_2 => [ declarative_part begin] concurrent_statements_part .... end generate [label]; (6) if-generate 文の前,end generate 文の後にラベルをおくことができる。 - 12 - 3. 順次処理コード 3.1 順次処理の概要 同時処理文は組合せ回路にのみ用いられるが,順次処理文は,組合せ回路と順序回路の両方に用いら れる。同時処理文には,when,select,generate があり,順次処理文には,if,wait,loop,case がある。VHDL では,process,function,procedure の 3 つの順次処理があり,後の 2 つはサブプ ログラム(subprogram)と呼ばれる。この章で扱う process は architecture の本体で用いられる。 ライブラリに用いられる subprogram は別途説明する。 順次処理のコードを扱う上で重要なことは signal と variable の違いを理解することである。 signal の主な特徴は以下のとおりである。 ・signal は順序処理文の外で宣言される。 ・signal は即時には更新しない。順次処理の中で変更された値は,その処理が終了して始めて使用で きる。 ・他の signal からの遷移に signal を用いる場合には,レジスタに影響する。 ・コード全体でただ 1 つの代入のみが有効である。多重代入では最後の代入が有効になる。 variable の主な特徴は以下のとおりである。 ・variable は process または subprogram 内でのみ宣言できる。shared variable はどこでも 宣言できるが,変更は順序処理文内に限られる。 ・variable は即時に変更できる。つまり,次の行では変更後の値が使われる。 ・他の signal からの遷移に variable を用いる場合には,レジスタに影響する。 ・多重代入が可能である。 3.2 ラッチとフリップフロップ フリップフロップは順序回路に欠かせないためこの節で概観しておく,また,ラッチもみておく。 ラッチには SR ラッチ(SRL)と D ラッチ(DL)があり,フリップフロップには,SRFF,DFF,TFF, JKFF の 4 種類がある。ラッチとフリップフロップの大きな違いは,ラッチがレベルで変化するのに対し て,フリップフロップはエッジで変化することである。この意味は,ラッチがクロック'1'の間は入力が 出力に伝搬され,クロックが'0'の間はブロックされるということである。フリップフロップでは,クロ ックの遷移が起こるたびに 1 回の信号伝達が生じる。'0'から'1'への遷移は立上りエッジと呼び,'1' から'0'への遷移は立下りエッジと呼ぶ。 3.3 process 文 process 文は,architecture 内におかれる順序ブロックの VHDL コードである。process 文内で は if,wait,loop,case の順序処理文のみが有効である。以下に構文を示す。 - 13 - [label:]process [(sensitivity_list)] [is] [ declarative_part] begin sequential_statements_part end process [label]; まず,ラベルはオプションであり,長いコードの可読性のために用いる。sensitivity_list は,wait を除き必須であり,このリストの信号変化により process が実行される。宣言部には,subprogram の宣言と本体,型宣言,subtype 宣言,constant 宣言,variable 宣言,file 宣言,alias 宣言, attribute 宣言,attribute 規定,use 節,group template 宣言,group 宣言がおかれる。process 文中では,signal 宣言はできない。 例) 次のコードでは process は clk,rst の変化で駆動される。 process(clk, rst) variable a, b: integer range 0 to 255; variable c: bit_vector(7 downto 0) := "00001111"; begin .... end process; VHDL2008 では,次の文も process においてよい。 subprogram 実装宣言,package 宣言,package 本体,package 実装宣言, また,sensitivity_list に all が使用できる。 3.4 if 文 process 文(subprogram も同じ)内でのみ使用される if,wait,loop,case 文の中で if 文が 最も一般的である。if-else 構造はプライオリティ無デコーダとして解釈できるので,このことはあま り重要でないように思えるが,基本的に,if 文から論理合成される回路と他の文から合成される回路は 同等である。if 文の構文を簡潔に示す。 [label:]if conditions then assignments; elsif conditions then assignments; ... else assignments; end if [label]; - 14 - 例) if (x<y) then temp := "00001111"; elsif (x=y and w='0') then temp:="11110000"; else temp:=(others => '0'); end if; VHDL2008 では,if 文内で when,select 文が使用でき,さらに,if 文の条件部には真理値テスト (boolean test)が使える。 例)リセット,クリア付 DFF 入力 d1,clk,rst,出力 q1 の DFF と入力 d2,clk,clr,出力 q2 の DFF を 1 つの architecture として記述する例を示す。これらは 1 つの process 文内に記述できるが,2 つに分けた方が検査しやす い。 library ieee; use ieee.std_logic_1164.all; -------------------------------------------------entity flipflops is port(d1, d2, clk, rst, clr: in std_logic; q1, q2: out std_logic); end entity; -------------------------------------------------architecture flipflops of flipflops is begin -- DFF with reset ---with_reset: process(clk, rst) begin if(rst='1') then q1 <= '0'; elsif(clk'event and clk='1') then q1 <= d1; end if; end process with_reset; -- DFF with clear ---with_clear: process(clk) begin if(clk'event and clk='1') then if(clr='1') then q2 <= '0'; else q2 <= d2; end if; end if; end process with_clear; end architecture; - 15 - 例)基本カウンタ 10 進 1 桁の基本的なカウンタの例を示す。 entity counter is port(clk: in bit; count: out integer range 0 to 9); end entity; -------------------------------------------------architecture counter of counter is begin process(clk) variable temp: integer range 0 to 10; begin if(clk'event and clk='1') then temp:=temp+1; if(temp=10) then temp := 0; end if; end if; count <= temp; end process; end architecture; この例では,即時変化する variable 変数 temp を用いているため,if 文内の比較は 9 ではなく,10 である。 例) シフトレジスタ シフトレジスタは,DFF を直列接続した回路である。入力を din,出力を q0 から q3 とすると直列デ ータから並列データへの変換に使用でき,出力を q3=dout のみとすれば遅延回路になる。段数 N は generic 宣言とした。 entity shift_register is generic (N: integer := 4); -- number of stages port(din, clk, rst: in std_logic; dout: out std_logic); end entity; -------------------------------------------------architecture shift_register of shift_register is begin process(clk, rst) variable q: std_logic_vector(0 to N-1); begin if(rst='1') then q := (others => '0'); elsif(clk'event and clk='1') then q := din & q(0 to N-2); end if; dout <= q(N-1); end process; end architecture; - 16 - 3.5 wait 文 wait 文には 3 種類あり,2 種類は論理合成用,他の 1 つはシミュレーション用である。wait 文を用 いる時には process 文の sensitivity list は使えない。 [label:] wait until condition; [label:] wait on sensitivity_list; [label:] wait for time_expression; (1) wait until wait until 文は,条件が満足されるまで,process 文,subprogram の実行を待つ。 以下の 2 例は同等である。同期クリアとした。wait until 文の例では,process 文に sensitivity list がないことに注意する。 ----- DFF process with if ---------------------process(clk) begin if(clk'event and clk='1') then if(clr='1') then q <= '0'; else q <= d; end if; end if; end process; ----- DFF process with wait until---------------process begin wait until (clk'event and clk='1'); if(clr='1') then q <= '0'; else q <= d; end if; end process; (2) wait on wait on 文も,リストにある信号が変化するまで,process 文,subprogram の実行を待つ。以下 の例では clk 信号がそれにあたる。wait on 文は,process 中のはじめか終わりにおく。 - 17 - ----- DFF process with wait on ---------------process begin if (clk'event and clk='1'); if(clr='1') then q <= '0'; else q <= d; end if; end if; wait on clk; end process; (3) wait for wait for はシミュレーション用であるので,他の章で扱う。以下の例は,周期 80ns のクロック信号 を生成する。 ----- DFF process with wait on ---------------wait for 40ns; clk <= not clk; 3.6 loop 文 loop 文は,あるコードの単位を繰り返す時に用いる。同時処理の generate 文に似ているが,loop 文は,if,wait,case 文と同じく順次処理にのみ用いる。 loop 文には,以下の 5 種類がある。 (1) 無条件 loop [label:] loop sequential_statements end loop [label]; 例) loop wait until clk='1'; count := count + 1; end loop; (2) loop with for - 18 - [label:] for identifier in range loop sequential_statements end loop [label]; 例)i が 5 になるまで 6 回無条件に繰り返される例 for i in 0 to 5 loop x(i) <= a(i) and b(5-i); y(0,i) <= c(i); end loop; for-loop では,for generate 同様に,繰り返しの始めと終わりは定数指定でなければならない。 つまり,"for i in 0 to x loop"において x を入力信号とすると論理合成されない。 (3) loop while [label:] while condition loop sequential_statements end loop [label]; 例) while (i<10) loop wait until clk'event and clk='1'; ... end loop; (4) loop with exit [loop_label:] [for identifier in range] loop ... [exit_label:] exit [loop_label] [ when condition] ... end loop [loop_label]; 例) data に('0')以外の値があると loop を抜ける例 for i in data'range loop case data(i) is when '0' => count := count+1; when others => exit; end case; end loop; - 19 - (5) loop with next [loop_label:] [for identifier in range] loop ... [next_label:] next [loop_label] [ when condition] ... end loop [loop_label];end loop; 例) for i in 0 to 15 loop next when i=skip; ... end loop; VHDL2008 では,loop 文中の条件判別をブール値で行うことができる。例えば, "while ena='1' loop"の代わりに,"while ena loop"としてよい。 次の例は,loop 文の中で最もよく使用される for-loop をリップルキャリー加算器に使用した例であ る。 例)リップルキャリー加算器 sum sk =ak xor bk xor ck carry ck+1=akbk+akck+bkck library ieee; use ieee.std_logic_1164.all; -------------------------------------------------entity carry_ripple_adder is generic (N: integer := 8); -- number of bits port(a, b: in std_logic_vector(N-1 downto 0); cin: in std_logic; s: out std_logic_vector(N-1 downto 0); cout: out std_logic); end entity; -------------------------------------------------architecture structure of carry_ripple_adder is begin process(a, b, cin) variable c: std_logic_vector(N downto 0); begin c(0) := cin; for i in 0 to N-1 loop a(i) <= a(i) xor b(i) xor c(i); c(i+1) := (a(i) and b(i)) or (a(i) and c(i)) or (b(i) and c(i)); end loop; cout <= c(N); end process; end architecture; - 20 - 例) 0 の個数カウンタ loop with exit の例 library ieee; use ieee.std_logic_1164.all; -------------------------------------------------entity leading_zeros is port(data: in std_logic_vector(7 downto 0); zeros: out integer range 0 to 8); end entity; -------------------------------------------------architecture behavior of leading_zeros is begin process(data) variable count: integer range 0 to 8; begin count := 0; for i in data'range loop case data(i) is when '0' => count := count + 1; when others => exit; end case; end loop; zeros <= count; end process; end architecture; 3.7 case 文 case 文の構文を示す。 [label:] case expression is when value => assignments; when value => assignments; ... end case; case 文は select 文と同様に多重値が使える,|または to で示す。 when value1 | value2 | ... when value1 to value2 例) case control is when "000" => x<=a; y<=b; when "000" | "111" => x<=b; y<='0'; when others => x<='0'; y<='1'; end case; - 21 - case 文では,すべての真理値表の条件が網羅されなければならないのでキーワード others が有用で ある。何もしない場合にはキーワード null が便利である。 case 文は process 文または subprogram 内の順次処理としてのみ使用できるが,本質的には組合せ 回路の記述に用いるため select 文によく似ている。 VHDL2008 では,同時処理文 when が case 文内で使用でき,case?と unaffected が使用できる。 例) 7 セグメント表示器と 10 進 1 桁カウンタ 7 セグメント表示器(以下 SSD, seven segment display) entity slow_counter is generic (fclk: integer := 50_000_000); --50MHz port(clk, rst: in bit; ssd: out bit_vector(6 downto 0)); end entity; -------------------------------------------------architecture counter of slow_counter is begin process(clk, rst) variable counter1: natural range 0 to fclk := 0; variable counter2: natural range 0 to 10 := 0; begin ----- counter ------if(rst='1') then counter1 := 0; counter2 := 0; elsif (clk'event and clk='1') then counter1 := counter1+1; if(counter1=fclk) then counter1 := 0; counter2 := counter2+1; if(counter2=10) then counter2 := 0; end if; end if; end if; ----- SSD driver ----case counter2 is when 0 => ssd <= "0000001"; -- "0" on SSD when 1 => ssd <= "1001111"; -- "1" on SSD when 2 => ssd <= "0010010"; -- "2" on SSD when 3 => ssd <= "0000110"; -- "3" on SSD when 4 => ssd <= "1001100"; -- "4" on SSD when 5 => ssd <= "0100100"; -- "5" on SSD when 6 => ssd <= "0100000"; -- "6" on SSD when 7 => ssd <= "0001111"; -- "7" on SSD when 8 => ssd <= "0000000"; -- "8" on SSD when 9 => ssd <= "0000100"; -- "9" on SSD when others => ssd <= "0110000"; -- "E"rror end case; end process; end architecture; - 22 - 3.8 case 文と select 文 順次処理の case 文と同時処理の select 文はよく似ているが,次の表に示すように違いもある。 項目 select 文 case 文 種別 同時処理 順次処理 コードの位置 順次処理外におく 順次処理内におく テスト入力数 真理値表のすべて 真理値表のすべて 項目毎のテスト数 複合条件が可能 複合条件が可能 1 代入文の数 アクションなし unaffected 任意 null キーワード select? 一致判別 (VHDL2008) case? (VHDL2008) 例) 以下の例は等価である。 -- with select with sel & ena select x <= a when "00" | "11", b when "01", c when others; with sel & ena select y <= "0000" when "11", "1--1" when others; --------------------------------------------------- with case case sel & ena is when "00" => x<=a; y<="1--1"; when "01" => x<=b; y<="1--1"; when "11" => x<=a; y<="0000"; when others => x<=c; y<="1--1"; end case; 3.9 順次処理コード中の組合せ回路 組合せ回路も順序処理コードとして記述できるが,その場合には,次のことに注意が必要である。 (1) 不必要なラッチを生成させないために,真理値表は完全に記述する。 (2) process 文の sensitivity list には,すべての入力信号を記述する。 例)マルチプレクサ 4 入力 a,b,c,d,制御入力 sel(1:0),2 出力 x,y のマルチプレクサの真理値表が次のように与えら れた場合の VHDL コードをみる。 - 23 - sel x Y 00 a 0 01 b 1 10 c 11 d library ieee; use ieee.std_logic_1164.all; -------------------------------------------------entity poor_design is port (a, b, c, d: in std_logic; sel: in integer range 0 to 3; x, y out std_logic); end entity; -------------------------------------------------architecture example of poor_design is begin process(a, b, c, d, sel) begin if (sel=0) then x<=a; y<='0'; elsif (sel=1) then x<=b; y<='1'; elsif (sel=2) then x<=c; else x<=d; end if; end process; end architecture; この回路における sel=2,sel=3 の場合の y の値は,それ以前の sel の値に依存するため不要なラッ チが構成されていることがわかる,真理値表の 3,4 行目の y の値は don't care とすべきである。 3.10 VHDL2008 順序処理に関して VHDL2008 では,次の拡張がなされている。 (1) process 文の宣言部では,以下の宣言が可能である。 subprogram インスタンス(instantiation)宣言,package 宣言,package body, package インスタンス宣言 (2) process 文の sensitivity list にキーワード all が使用可能。 これにより,順次処理コード中の組合せ回路の実装時のエラー低減ができる。 例) process(all) begin ... end process; - 24 - (3) 順次処理コード中に同時処理文の when,select が使用できる。 例)以下は,同等。 if (clk'event and clk='1') then if (clr='1') then q <= '0'; else q <= d; end if; end if; -------------------------------------------------if (clk'event and clk='1') then q <= '0' when clr='1' else d; end if; (4) if 文中で bool 値テストが使用できる。以下の 1 行は同等。 if (a='0' and b='0') or c='1' then ... if (not a and not b) or c then... (5) 一致演算子 case?の導入。(select?と同様) 例)以下は,同等。 with interrupt select? priority <= 4 when "1---", 3 when "01--", 2 when "001-", 1 when "0001", 0 when others; -------------------------------------------------case? interrupt is when "1---" => priority <= 4; when "01--" => priority <= 3; when "001-" => priority <= 2; when "0001" => priority <= 1; when others => priority <= 0; (6) キーワード unaffected が順次処理コード中の if 文,case 文で使用できる。 (7) loop 文中の bool 値テストが可能となった。 例)以下は,同等。 while ena='1' loop while ena loop - 25 - 文献 [1] Volnei A. Pedroni:Circuit Design and Simulation with VHDL 2 nd ed., MIT Press, 2010. - 26 -