...

同時処理と順次処理 - 電子工学科

by user

on
Category: Documents
36

views

Report

Comments

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 -
Fly UP