언어로서 VHDL의 구문은 선언문(declare), 할당문(assign), 제어문(control)으로 나뉠 수 있다. ENTITY와 ARCHITECTURE 및 Function, Procedure, Package 및 Package Body 와 같은 sub-design 모듈과 SIGNAL, VARIABLE, CONSTANT와 같은 객체들의 선언이 있으며 할당문의 경우 SIGNAL할당(<=)과 순차적인 VARIABLE할당(:=)으로 나뉘어 진다. 제어문은 조건문(conditional statement), 선택문(selectional statement), 반복문(loop statement)등이 있다. HDL은 순차구문(sequential statement)과 병렬구문(concurrent statement)을 모두 지원 하고 있으므로 각각 구문에 대하여 사용할 수 있는 제어문이 다르다. 이번에는 이들 제어문의 종류와 사용방법 그리고 제어구문과 디지털 회로의 관계에 대하여 살펴보기로 한다. 이미 언급한 바와 같이 VHDL의 구문상 병렬구문과 순차구문이 곧 디지털 회로의 조합회로와 순차회로를 위미하는 것은 아니다. 기술하는 방법에 따라 병렬구문, 순차구문 모두 조합회로 혹은 순차회로의 표현이 가능하며 VHDL에서 순차구문과 병렬구문을 구분하기 위하여 순차구문은 반드시 PROCESS 블록 내에서 만 기술된다는 점을 기억하자.
조건문은 논리연산의 결과(TRUE/FALSE)에 따라 구문 수행의 변화를 갖는 구문들이다. VHDL의 조건문은 다음과 같다.
Data Flow 조건문 (병렬구문)은 WHEN~ELSE의 형태이다.
------------------------------------------------------- signal_out <= signal_0 WHEN condition_0 ELSE signal_1 WHEN condition_1 ELSE signal_2; -------------------------------------------------------
condition_0가 "참(TRUE)" 일 경우 signal_0이 signal_ouit에 할당되며 condition_1이 "참(TRUE)" 일 경우 signal_1가 signal_out에 할당되고 그 이외의 경우 signal_2가 signal_out에 할당된다.
Behavioral 조건문 (순차구문)은 IF~THEN~ELSE~END IF의 형태로서 다음과 같이 기술한다.
------------------------------------------------------- IF condition_0 THEN signal_out <= signal_0; ELSIF condition_1 THEN signal_out <= signal_1; ELSE signal_out <= signal_2; END IF; -------------------------------------------------------
ELSE의 사용은 조건문에서 반드시 필요한 것은 아니다. 다만 ELSE를 사용하지 않은 경우 조건식이 "거짓(FALSE)" 이면 할당될 값이 없다는 것을 의미하며 이는 곧, 조건식이 "참(TRUE)"일 때 까지 이전의 값을 유지해야 한다는 뜻이므로 Latch혹은 F/F과 같은 순차회로가 된다. 다음은 조건문의 사용 예 이다. 각 예의 합성결과를 잘 살펴보자. ELSE의 기술 여부에 따라 Latch혹은 F/F이 형성된 것을 볼 수 있다.
[예제 1] Data Flow 조건문의 예
library ieee; use ieee.std_logic_1164.all; ENTITY test_conditional IS PORT ( x : IN std_logic_vector(7 DOWNTO 0); y : IN std_logic_vector(7 DOWNTO 0); z : IN std_logic_vector(7 DOWNTO 0); a : IN integer range 0 to 3; output_signal : OUT std_logic_vector(7 DOWNTO 0) ); END test_conditional; ARCHITECTURE DataFlow OF test_conditional IS BEGIN output_signal <= x WHEN a=1 ELSE y WHEN a=2 ELSE z WHEN a=3 ELSE (others=>'0'); END DataFlow; |
[예제 2] Behavioral 조건문의 예
library ieee; use ieee.std_logic_1164.all; ENTITY test_conditional IS PORT ( x : IN std_logic_vector(7 DOWNTO 0); y : IN std_logic_vector(7 DOWNTO 0); z : IN std_logic_vector(7 DOWNTO 0); a : IN integer range 0 to 3; output_signal : OUT std_logic_vector(7 DOWNTO 0) ); END test_conditional; ARCHITECTURE Behavioral OF test_conditional IS BEGIN PROCESS (x, y, z, a) BEGIN IF (a=1) THEN output_signal <= x; ELSIF (a=2) THEN output_signal <= y; ELSIF (a=3) THEN output_signal <= z; ELSE output_signal <= (others=>'0'); END IF; END PROCESS; END Behavioral; |
위의 조건문 예제 1과 2는 합성할 경우 동일한 회로가 된다. 합성 결과는 그림 1과 같다.
그림 1. 조건문의 합성예
[예제 3] ELSE가 없는 조건문
조건문에서 ELSE가 없는경우 latch가 될수 있음에 유의해야 한다. 합성 결과는 그림 2와 같다.
library ieee; use ieee.std_logic_1164.all; ENTITY test_conditional IS PORT ( x : IN std_logic_vector(7 DOWNTO 0); y : IN std_logic_vector(7 DOWNTO 0); z : IN std_logic_vector(7 DOWNTO 0); a : IN integer range 0 to 3; output_signal : OUT std_logic_vector(7 DOWNTO 0) ); END test_conditional; ARCHITECTURE DataFlow OF test_conditional IS BEGIN output_signal <= x WHEN a=1 ELSE y WHEN a=2 ELSE z WHEN a=3; END DataFlow; |
library ieee; use ieee.std_logic_1164.all; ENTITY test_conditional IS PORT ( x : IN std_logic_vector(7 DOWNTO 0); y : IN std_logic_vector(7 DOWNTO 0); z : IN std_logic_vector(7 DOWNTO 0); a : IN integer range 0 to 3; output_signal : OUT std_logic_vector(7 DOWNTO 0) ); END test_conditional; ARCHITECTURE Behavioral OF test_conditional IS BEGIN PROCESS (x, y, z, a) BEGIN IF (a=1) THEN output_signal <= x; ELSIF (a=2) THEN output_signal <= y; ELSIF (a=3) THEN output_signal <= z; END IF; END PROCESS; END Behavioral; |
그림 2. ELSE 가 없는 조건문의 합성예
[예제 4] 에지 트리거 플립 플롭
ELSE가 없는 조건문에 의하여 에지 트리거 플립 플롭(Edge-Trigger)을 표현할 수 있다. [예제 3]의 경우는
Level-Sensitive Latch를 표현한 것이다. 에지 트리거 플립 플롭을 표현하기 위해서는 SGINAL의
event속성(attribute)을 이용한다. event 속성을 사용한 에지트리거 플립플롭을 표현한 조건문은 ELSE를
사용하면 합성 불가능이다.
Data Flow 조건문에 의한 에지 트리거 는 다음과 같다.
library ieee; use ieee.std_logic_1164.all; ENTITY test_conditional IS PORT ( x : IN std_logic_vector(7 DOWNTO 0); clk: IN std_logic; output_signal : OUT std_logic_vector(7 DOWNTO 0) ); END test_conditional; ARCHITECTURE DataFlow OF test_conditional IS BEGIN output_signal <= x WHEN clk'event and clk='1'; END DataFlow; |
합성기에 따라 Data Flow 조건문에서 'event 속성을 지원하지 않는 경우도 있으므로 Behavioral 조건문을
이용하도록한다.
library ieee; use ieee.std_logic_1164.all; ENTITY test_conditional IS PORT ( x : IN std_logic_vector(7 DOWNTO 0); clk : IN std_logic; output_signal : OUT std_logic_vector(7 DOWNTO 0) ); END test_conditional; ARCHITECTURE Behavioral OF test_conditional IS BEGIN PROCESS (clk, x) BEGIN IF (clk'event and clk='1') THEN output_signal <= x; END IF; END PROCESS; END Behavioral; |
에지 트리거 조건을 정할 때 (clk'event and clk='1') 이면 상승 에지(rising edge) 이며, (clk'event and clk='0')
이면 하강 에지(falling edge) 가 된다. 그러나 (clk'event) 만을 조건으로 주면 합성 불가능이다. 상승 에지
트리거 플립 플롭의 합성 결과는 그림 3과 같다.
그림 3. 상승 에지트리거(rising edge-trigger) 플립 플롭(Flip-Flop)
선택문은 swich~case문과 같은 형태이다. VHDL의 조건문은 병렬구문과 순차구문으로 나뉘어진다.
Data Flow 선택문(병렬구문)은 WITH~SELECT~WHEN의 형태이다.
------------------------------------------------------- WITH signal_sel SELECT signal_out <= signal_0 WHEN constant_0, signal_1 WHEN constant_1, signal_2 WHEN constant_2, ...... signal_others WHEN OTHERS; -------------------------------------------------------
Behavioral 선택문(순차구문)은 CASE~WHEN의 형태로서 다음과 같이 기술한다.
------------------------------------------------------- CASE sig_var_sel IS WHEN constant_0 => signal_out <= signal_0; WHEN constant_1 => signal_out <= signal_1; WHEN constant_2 => signal_out <= signal_2; ...... WHEN OTHERS => signal_out <= signal_others; END CASE; -------------------------------------------------------
sig_var_sel이 상수 constant_0의 조건에 맞을 때 signal_0가 signal_out으로 할당 된다. 순차구문인 Behavioral 선택문에서 조건신호의 모든 경우에 대하여 WHEN에 지정되어 있지 않을 경우 기타조건을 나타내는 WHEN OTHERS가 없으면 래치가 될 수 있으므로 주의하여야 한다.
[예제 5] Data Flow 선택문 예
Data Flow 선택문의 예는 다음과 같다. 3비트 선택신호 "sel"에 대하여 3개의 조건만을 사용하고 있다. 그러나 병렬구문에서는 기타조건을 WHEN OTHERS를 사용하여 나타내지 않더라도 불필요한 래치를 생성하지는 않는다. 그러나 합성기에 따라 다를수 있으며 '-'(don't care)로 할당해 줌으로서 논리 최적화에 유리할수 있으므로 WHEN OTHERS를 사용하는 것이 좋다. 합성 결과는 그림 4와 같다.
library ieee; use ieee.std_logic_1164.all; ENTITY test_selection IS PORT ( x : IN std_logic_vector(7 DOWNTO 0); y : IN std_logic_vector(7 DOWNTO 0); z : IN std_logic_vector(7 DOWNTO 0); sel : IN std_logic_vector(2 DOWNTO 0); mux_out : OUT std_logic_vector(7 DOWNTO 0); latch_out : OUT std_logic_vector(7 DOWNTO 0) ); END test_selection; ARCHITECTURE DataFlow OF test_selection IS BEGIN WITH sel SELECT mux_out <= x WHEN "000", y WHEN "010", z WHEN "100", (others=>'-') WHEN OTHERS; WITH sel SELECT latch_out <= y WHEN "000", z WHEN "010", x WHEN "100"; END DataFlow; |
그림 4. Data Flow 선택문 합성 결과
[예제 6] Behavioral 선택문 예
순차구문인 Behavioral 선택문의 예는 다음과 같다. PROCESS 블록에 순차구문을 사용하면 상당히 복잡한 기술이 가능하다. Data Flow의 경우 1개의 신호에 대한 할당문을 사용할 수 있는 반면 순차구문 블록에서는 여러 할당문장의 기술이 가능하다. 순차구문에서는 기타조건을 WHEN OTHERS를 사용하여 나타내지 않을 경우 래치를 생성한다는 점에 유의하도록 한다. 합성 결과는 그림 5를 보면 WHEN OTHER할당에 '0'를 사용하는 경우 4입력 8비트 MUX인데 비하여 '-'(don't care)를 사용하는 경우 3입력 MUX로 최적화 되었음을 알 수 있다.
library ieee; use ieee.std_logic_1164.all; ENTITY test_selection IS PORT ( x : IN std_logic_vector(7 DOWNTO 0); y : IN std_logic_vector(7 DOWNTO 0); z : IN std_logic_vector(7 DOWNTO 0); sel : IN std_logic_vector(2 DOWNTO 0); mux_out : OUT std_logic_vector(7 DOWNTO 0); latch_out : OUT std_logic_vector(7 DOWNTO 0) ); END test_selection; ARCHITECTURE Behavioral OF test_selection IS BEGIN process(x, y, z, sel) begin CASE sel IS WHEN "000" => mux_out <= x; latch_out <= y; WHEN "010" => mux_out <= y; latch_out <= z; WHEN "100" => mux_out <= z; latch_out <= x; WHEN OTHERS => mux_out <= (OTHERS=>'-'); END CASE; END PROCESS; END Behavioral; |
(a) WHEN OTHERS에 '0'을 할당한 경우
(b)WHEN OTHERS에 '-'을 할당한 경우
그림 5. Behavioral 선택문 합성 결과
VHDL의 반복문은 FOR LOOP 와 WHILE LOOP가 있다. 1비트 연산회로를 n 비트 짜리로 확장하거나 쉬프트레지스터를 만들거나 할때 처럼 반복적인 연산회로에 많이 사용된다. 이러한 반복문은 순차구문(behavior)에서만 사용할 수 있다.
FOR LOOP 반복구문은 다음과 같다.
------------------------------------------------------- FOR loop_var IN loop_range LOOP -- Statements END LOOP; -------------------------------------------------------
반복에 사용되는 loop_var은 FOR LOOP~ END LOOP에 유효한 것으로 선언 되지 않고 사용한다.
WHILE LOOP 구문은 다음과 같다.
------------------------------------------------------- WHILE (condition) LOOP -- Statements; END LOOP; -------------------------------------------------------
조건식이 "참(TRUE)"일 동안 WHLE LOOP가 반복된다. 이대 조건식에 사용되는 변수는 VARIABLE로 선언 되어야 한다.
FOR/WHLE 반복구문은 제한적으로 합성 가능하다. FOR LOOP 의 경우 반복 범위가 지정되어 있으므로 일반적으로 합성가능 하지만 WHILE LOOP의 경우 반복 수행도중 반복 변수가 새로 갱신되는 경우에는 합성이 불가능해진다. 이는 이미 만들어진 하드웨어를 새로 조정하는 경우와 같기 때문이다. 순차구문으로서 반복을 중단하기 위해서 LOOP 내에 NEXT 또는 EXIT 구문을 사용할 수 있지만 합성을 위해서는 바람직하지 않다.
병렬구문(Data Flow)에서는 FOR GENERATE 반복구문을 사용할수 있다. 병렬구문이므로 반복 중간에 EXIT/NEXT등은 사용 불가능하며 합성 가능한 구문이다.
------------------------------------------------------- FOR loop_var IN loop_range GENERATE -- Concurrent Statements END LOOP; -------------------------------------------------------
[예 7] 8비트 가산기
FOR LOOP 반복문을 이용하여 8비트 가산기를 표현한 예이다. 합성 결과는 그림 6과 같다.
LIBRARY ieee; USE ieee.std_logic_1164.all; ENTITY test_for IS PORT( C_in : IN std_logic; L_val, R_val : IN std_logic_vector(7 downto 0); Sum_out : OUT std_logic_vector(7 downto 0); C_out : OUT std_logic ); END test_for; ARCHITECTURE behave OF test_for IS BEGIN PROCESS(C_in, R_val, L_val) VARIABLE carry : STD_LOGIC_VECTOR(8 DOWNTO 0); VARIABLE sum : STD_LOGIC_VECTOR(7 DOWNTO 0); BEGIN carry(0) := C_in; FOR i IN 0 TO 7 LOOP sum(i) := L_val(i) XOR R_val(i) XOR carry(i) ; carry(i+1) := (L_val(i) AND R_val(i)) OR (L_val(i) AND carry(i)) OR (R_val(i) AND carry(i)) ; END LOOP ; Sum_out <= sum; C_out <= carry(8); END PROCESS; END behave; |
그림 6. FOR LOOP를 이용한 8비트 가산기 합성결과
[예 8] WHILE LOOP의 EXIT/NEXT의 예
다음의 예는 WHILE LOOP에서 EXIT/NEXT 구문을 사용한 예이다. 아래의 예는 일부 합성기에서 합성가능 하지만 일반적으로 권장할만한 기술방법이 아니다. 그림
LIBRARY ieee; USE ieee.std_logic_1164.all; ENTITY test_while IS PORT( ena : IN std_logic; input_sig : IN std_logic_vector(7 downto 0); result : OUT std_logic_vector(7 downto 0) ); END test_while; ARCHITECTURE behave OF test_while IS BEGIN PROCESS(ena, input_sig) VARIABLE i : integer; BEGIN i:=0; WHILE TRUE LOOP i:=i+1; EXIT WHEN (i>5); if (input_sig(i-1)='0') then result(i-1) <= '0'; next; end if; result(i-1) <= ena; END LOOP; END PROCESS; END behave; |
그림 7. WHILE LOOP에서 EXIT/NEXT사용 예의 합성결과
[예 9] FOR GENERATE의 예
FOR GENERATE는 병렬구문에서 사용돼는 반복문이므로 다수의 COMPONENT들을 사용할 수 있다. 합성 결과는 그림 8과 같다.
library ieee; use ieee.std_logic_1164.all; entity test_shift is port( clk : in std_logic; s : in std_logic; q : out std_logic ); end test_shift; architecture behave of test_shift is component d_ff port( clk : in std_logic; d : in std_logic; q : out std_logic ); end component; signal q_i : std_logic_vector(7 downto 0); begin q_i(0) <= s; q <= q_i(7); sh : for i in 7 downto 1 generate u_dff : d_ff port map ( clk, q_i(i-1), q_i(i)); end generate sh; end behave; |
그림 8. FOR GENERATE구문을 이용한 COMPONENT의 사용예에대한 합성결과
VHDL의 각종 제어구문과 이들 구문과 합성후의 회로에 대하여 살펴보았다. VHDL구문에 의한 디지털 회로의 기술에 있어서 병렬구문과 순차구문의 차이를 이해하는 것과 이에 따른 조합 디지털 회로 혹은 순차 디지털 회로의 관계에 대한 이해가 중요하다. 언어에 의한 회로 설계는 스케마틱 설계와 같이 구성요소를 이용하는 것이 아닌, 회로의 행동을 묘사하는 것이므로 실제 회로로 합성되었을 때 설계자의 의도와 다르게 될 수 있다. 합성 결과 가장 큰 문제가 되는 부분은 불필요한 래치나 플립 플롭의 생성이므로 제어문에 특히 주의를 기울여야 한다.
다음달에는 좋은 합성 결과를 얻기 위한 적절한 VHDL기술방법(coding style)에 대하여 살펴보고 합성결과를 비교해 보기로 한다.