VHDL 문법 정리 (1): 설계 단위와 기본 구조(entity/architecture)
VHDL을 “문법만 맞춰서 컴파일 되게” 쓰는 것과, “합성 가능한 RTL을 일정한 규칙으로 쌓아가는 것” 사이에는 간극이 있다. 그 간극의 대부분은 entity/architecture 같은 기본 구조를 제대로 이해하지 못해서라기보다, 설계 단위(design unit)가 어떤 층위로 쪼개지고, 각 층위가 어떤 책임을 갖는지에 대한 정리가 부족해서 생긴다고 본다. 실무에서는 이 정리의 유무가 곧바로 파일 구조, 재사용성, 컴파일 순서, 라이브러리 관리 문제로 이어진다.
이 글은 VHDL 문법을 “정의부터” 시작하지 않는다. 실제로 코드를 쓰다가 부딪히는 지점을 기준으로, 설계 단위의 구성을 먼저 잡고, 그 위에 entity/architecture, package, configuration 같은 문법 요소를 어디에 배치해야 하는지 정리한다. 기준은 VHDL-2008 문법이며, Vivado/Quartus 같은 상용 툴과 GHDL 같은 오픈소스 툴에서 공통으로 통하는 관점에 우선순위를 둔다12.
시리즈 목차
- 1편: 설계 단위와 기본 구조(
entity/architecture,package, 라이브러리) - 2편: 타입/신호/변수, 동시/순차 문장, 프로세스 기본
- 3편: 클럭/리셋 패턴, generate/generic, 구조화(컴포넌트/인스턴스)
이제 “파일 하나에 무엇을 넣을 것인가”부터 정리한다.
설계 단위 개요
VHDL 소스는 툴이 보기에는 여러 “설계 단위”의 묶음이다. 이 설계 단위를 어떻게 쪼개느냐가 재사용성과 디버깅 난이도를 좌우한다.
entity: 외부 인터페이스 정의(포트/제너릭)architecture: 구현 정의(동작/구조)package: 타입/상수/함수/컴포넌트 선언의 공유 레이어package body: 함수/프로시저 구현부(필요 시)configuration: 특정entity에 어떤architecture를 바인딩할지 지정(현대 RTL에서는 드묾)
여기서 중요한 포인트는, entity는 “인터페이스 계약”이고 architecture는 “구현 선택지”라는 점이다. 이 둘을 분리해 두면 합성/시뮬레이션/리팩터링 단계에서 선택지가 생긴다.
최소 실행 예제: entity/architecture/package 한 번에 보기
아래 코드는 “파일을 3개로 쪼개기 전에”, VHDL 설계 단위를 한 번에 머릿속에 넣기 위한 예제다. 목적은 신호 처리 자체가 아니라, 문법 블록의 경계를 확실히 보는 데 있다.
-- file: util_pkg.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package util_pkg is
function inc_u(x : unsigned) return unsigned;
end package;
package body util_pkg is
function inc_u(x : unsigned) return unsigned is
begin
return x + 1;
end function;
end package body;
-- file: counter.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.util_pkg.all;
entity counter is
generic (
WIDTH : natural := 8
);
port (
clk : in std_logic;
rst_n : in std_logic;
q : out std_logic_vector(WIDTH-1 downto 0)
);
end entity;
architecture rtl of counter is
signal r : unsigned(WIDTH-1 downto 0);
begin
process(clk)
begin
if rising_edge(clk) then
if rst_n = '0' then
r <= (others => '0');
else
r <= inc_u(r);
end if;
end if;
end process;
q <= std_logic_vector(r);
end architecture;
코드가 길어 보이지만, 실무적으로 중요한 부분은 사실 몇 줄이다.
use work.util_pkg.all;
패키지가 work 라이브러리에 컴파일되어 있다는 전제에서, 선언을 가져온다. 여기서 work는 “현재 컴파일 결과가 쌓이는 기본 라이브러리”라는 관념으로 이해하는 것이 실무적으로 유리하다. 프로젝트/라이브러리 구성이 복잡해질수록 work에만 몰아넣는 방식은 한계가 있지만, 기본 구조를 설명하기에는 적합하다.
entity counter is
generic ( WIDTH : natural := 8 );
port ( ... );
end entity;
entity는 합성 가능한 구현을 쓰지 않아도 “인터페이스 계약”만으로 충분히 의미를 가진다. generic은 파라미터화의 핵심이며, 단순히 폭만 조절하는 용도라도 타입을 natural로 고정해 두는 편이 의도와 합성 제약을 동시에 명확히 한다.
architecture rtl of counter is
signal r : unsigned(WIDTH-1 downto 0);
begin
...
end architecture;
architecture는 구현부다. 이 글에서는 rtl이라는 이름을 관례적으로 썼지만, 이름 자체는 중요하지 않다. 대신 “동일한 entity에 여러 architecture가 존재할 수 있다”는 가능성을 항상 남겨두는 것이 포인트다. 예를 들어 시뮬레이션 전용 모델(behav)과 합성 모델(rtl)을 분리할 수 있다.
library/use: 가져오는 범위를 좁히는 습관
VHDL에서 흔히 use ieee.all; 같은 식으로 “다 가져오기”를 시도하는 경우가 있는데, 합성/시뮬레이션 툴마다 해석 차이가 생기기 쉽다. 실무에서는 다음 정도로 좁혀두는 편이 안정적이다.
ieee.std_logic_1164.all:std_logic,std_logic_vectorieee.numeric_std.all:unsigned/signed, 산술 연산
이 두 개만으로도 대부분의 RTL은 작성된다. std_logic_arith 같은 비표준 계열은 레거시 코드 유지보수에서는 만날 수 있지만, 신규 설계에서는 지양하는 편이 좋다3.
entity/architecture를 분리하는 이유
entity/architecture를 굳이 분리해 두는 이유는 “깔끔해서”가 아니라, 빌드/검증 단계에서 이점이 있기 때문이다.
- 인터페이스 변경의 영향 범위 최소화
- 동일 인터페이스에 대한 구현 교체 용이성
- 테스트벤치에서의 더미 구현(모델) 주입 가능성
- 합성/시뮬레이션 격리(비합성 구문을 모델에만 한정)
이 맥락은 2편에서 다룰 “동시/순차 문장과 프로세스”로 자연스럽게 이어진다. architecture 안에서 무엇이 동시(concurrent)로 평가되고, 무엇이 순차(sequential)로 평가되는지 이해해야 구현 교체가 의미가 생긴다.
configuration은 언제 쓰나
VHDL 문서에서는 configuration을 중요한 기능으로 다루지만, RTL 설계에서는 툴 플로우가 이미 인스턴스 바인딩을 결정해 주는 경우가 많다. 다만 “같은 entity 이름을 유지한 채로 구현을 바꿔 끼우는” 구성을 강하게 요구받는 환경(대형 시뮬레이션 모델, 검증 프레임워크)에서는 여전히 등장한다1.
현대 FPGA RTL에서는 다음 정도로 이해하면 충분하다.
- 기본 원칙: 인스턴스/라이브러리/파일 컴파일 순서로 사실상 바인딩 결정
- 예외 상황: 구성 관리가 필요한 대규모 시뮬레이션에서
configuration고려
다음 편으로의 연결
이제 설계 단위를 쪼개는 기준을 잡았으니, 다음 단계는 architecture 안에서 문장이 평가되는 방식(동시/순차)과, 그 과정에서 타입/신호/변수가 어떤 역할을 갖는지 정리하는 일이다. 2편에서는 signal과 variable의 차이를 “문법”이 아니라 “시뮬레이터/합성기의 시간 모델” 관점에서 정리한다.
References
-
IEEE Standard for VHDL Language Reference Manual - VHDL(IEEE 1076) 언어 정의 문서다. ↩ ↩2
-
GHDL Documentation - 오픈소스 VHDL 시뮬레이터/컴파일러의 사용 및 언어 지원 범위를 확인할 수 있다. ↩
-
IEEE numeric_std package rationale (Doulos VHDL style articles) -
numeric_std중심 스타일과 비표준 산술 패키지의 리스크를 정리한 자료다. ↩