일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
- 코딩테스트
- 가속컴퓨팅
- verilog
- Rtl
- verilog HDL
- 모델링
- 백준
- 비트마스크
- 비트마스킹
- verilogHDL
- testbench
- Module
- dfs연습문제
- 비트마스크알고리즘
- 15683
- 가속기시스템
- 스타트와링크
- boj
- 감시
- 최적화
- 14889
- HDL
- 알고리즘
- HW
- RTLEngineer
- DFS
- 모듈
- HWEngineer
- Today
- Total
oohyoo 님의 블로그
[verilog HDL] (3)Verilog 개요 - 모듈과 모델링 본문
지난 포스팅에서는 Verilog HDL을 이용하여 회로를 설계하는 과정에 대해 개략적으로 살펴보았다.
하드웨어 사양이 주어지면 이를 파악하여 HDL 코딩으로 회로를 작성하는 것이 첫번째 단계였다. 그렇다면 HDL 코딩은 어떤 구조로 이루어져 있을까?
HDL(Hardware Description Language)은 하드웨어의 동작을 기술하는 언어로, C언어나 Java 같은 소프트웨어 개발 언어와는 다르게 하드웨어 설계에 특화되어 있다. 하드웨어 구성 요소 간의 상호 연결과 병렬성을 중점으로 작성하기 위해, 기본 설계 단위로 "module"을 이용한다.
Verilog HDL에서 모듈(Module)이란, 기본 설계 단위를 의미한다. C언어를 알고 있는 사람이라면 모듈을 하나의 함수라고 생각해도 좋다. 그러나 HDL에서는 하나의 파일에 하나의 모듈만 들어가는 것이 수정 및 관리에 적합하며, HDL에서 존재하는 함수를 관리하는 역할이 모듈이기 때문에, 모듈은 함수를 포함하는 개념이다.
모듈의 구조는 다음과 같다.
module module_name (port_list); port 선언 reg 선언 wire 선언 parameter 선언 --------------------------------------- 하위 모듈 호출 always/initial 문 function/ task 정의문 assign문 function/task 호출문 endmodule |
1) 포트 리스트
이 부분에서는 "포트"들을 선언한다. 포트는 회로에서 입/출력이 이루어지는 부분을 의미한다. 어느 복잡하고 다양한 기능을 하는 회로도를 다룰 때 특정 기능을 하는 집단을 하나로 묶어보면 간단하게 입력단과 출력단을 추려낼 수 있다. 마치 전자회로에서 "black box"기법을 이용했던 것과 비슷하다. 즉 모듈은 하나의 black box이다. 모듈에 입력되거나 출력되는 것들을 모두 포트라고 한다.
2) 선언부 (port/reg/wire/parameter 선언)
포트 리스트에 선언된 포트들이 입력에 해당하는지, 출력에 해당하는지, 또한 몇 비트로 이루어져 있는지 작성해주는 부분이다. 추가적으로 변수를 선언해줄 수 있는데, 주로 회로를 연결해주는 wire를 이름과 함께 선언한다. 여기서 wire는 자료형에 해당한다.
3) 동작 코드 작성
- Gate Primitive를 불러서 사용
기본적으로 제공되는 논리 게이트들을 이용한다. NAND, NOR, NOT, XOR 등 기본적인 논리게이트들의 경우, 기본적으로 제공되므로 그대로 사용하면 된다. 다음은 반가산기(half-adder)의 모듈링 예시이다.
module half_adder(a, b, sum, cout); input a, b; output sum, cout; wire cout_bar; xor (sum, a, b); nand (cout_bar, a, b); not(cout, cout_bar); endmodule |
![]() |
게이트 프리미티브 괄호 내에는 출력이 우선적으로 쓰이고, 이후에 입력 변수들이 나열된다. 따라서 인스턴스의 수는 2개에서부터 여러개가 나올 수 있다.
기본적으로 정의된 게이트 외에 사용자 정의 프리미티브( UDP, User Defined Primitive)를 사용할 수도 있다.
- 연속 할당문 이용
연속 할당문은 "assign" 키워드를 이용하여 작성한다. assign 뒤에는 할당문이 나오는데, 등호(=)로 표시된 우변에 좌변을 할당한다는 의미이다. 따라서 좌변은 output이거나, wire자료형이 될 수 있다.
module half_adder2 (a, b, sum, cout); input a, b; output sum, cout; assign cout = a & b; assign sum = a ^ b; endmodule |
![]() |
cout에는 a와 b를 비트 "AND" 연산한 값을 할당하였으며, sum에는 a와 b를 비트 "XOR" 연산한 값을 할당하였다. &, ^등 비트 연산이 적용된 것을 볼 수 있다. 연속할당문은 하드웨어 신호의 연결을 의미한다. 즉, 이 구문은 지속적으로 갱신되며 값이 변경될 때마다 즉각적으로 반영된다. 이는 하드웨어에서 선이나 신호선이 물리적으로 계속 연결된 상태를 반영한 것이다.
우리가 C언어를 생각했을때, 코드는 한줄씩 위에서 아래로 실행된다. 즉, 절차적 특성을 가진다. 그러나 이러한 특성과 다르게 verilog HDL은 하드웨어를 다루기 때문에 하드웨어적인 특성이 적용된다. 즉 절차적 특성과는 반대로 코드 실행 순서가 바뀌어도 시뮬레이션 결과에는 영향을 끼치지 않는다.
아래 두 그림은 논리게이트의 위치가 바뀌었지만, 기능적으로는 여전히 반가산기의 역할을 한다.
![]() |
![]() |
이처럼 assign문은 하드웨어의 특성에 따라 순서가 바뀌어도 회로 합성이나 시뮬레이션 결과에 영향을 미치지 않는다.
- 행위 수준 모델링
행위 수준 모델링은 always, initial 키워드를 이용하여 작성된다. 디지털 논리회로는 조합회로와 순차회로로 나누어지는데, 이 두가지 종류에 따라 행위 수준 모델링의 구현 방식이 달라진다.
조합논리회로 (2:1 MUX) | 순차회로 (D- type Flip Flop) |
module mux2b_if(in0, in1, sel, out); input [1:0] in0, in1; input sel; output [1:0] out; reg [1:0] out; always @(sel or in0 or in1) begin if (sel == 0) out = in0; else out = in1; end endmodule |
module D_ff (clk, din, rst, q); input clk, din, rst; output q; reg q; always @(posedge clk or posedge rst) begin if (rst == 1) q <= 0; else q <= din; end endmodule |
두가지 회로에서 always 블럭은 공통적인 구조를 갖는다. '@'는 event operator라고 하며, 괄호 내의 신호들의 변화를 감지한다. 즉 괄호 내에는 감지 신호 목록이 열거되어 있으며 감지신호의 변화가 없으면 begin 내부가 실행되지 않는다. 이를 변화 기반 시뮬레이션(event-driven simulation)이라고 한다. 조합논리회로의 모듈 선언부에서 [1:0]은 해당 변수가 2bit라는 의미이다. 2의 0의 제곱 자리부터 2의 1의 제곱자리까지 차지하겠다는 뜻이다.
세미콜론의 여부나 줄맞춤은 C언어와 매우 유사하다.
always문 내부에서 할당문을 볼 수 있는데, 값을 할당받는 객체는 반드시 reg 자료형으로 선언되어야 한다. HDL 코드는 기본적으로 코드가 순차적으로 실행되지 않아도 되는데, always문은 절차형 할당문이기 때문이다. 절차형 할당문 내부의 변수는 반드시 variable 자료형으로 선언되어야 하며, reg는 variable 자료형에 포함되는 대표적인 자료형이다.
module D_ff (clk, din, rst, q); input clk, din, rst; output q; reg q; always @(posedge clk or posedge rst) begin if (rst == 1) q <= 0; else q <= din; end endmodule |
![]() |
추가적으로, D-FF 코드를 보면 posedge라는 용어가 나온다. posedge는 positive edge의 약자로 상승엣지를 검출하겠다는 의미이다. 클락 엣지가 1로 상승하는 순간이거나, rst(리셋)이 1로 상승하는 경우에 always 블럭을 실행하게 된다. D Flip-Flop은 클락신호가 들어올 때 리셋신호가 0인지 1인지에 따라 원래 데이터를 저장하거나 0으로 초기화한다. 참고로 이 FF를 비동기식 D-FF라고 부른다.
- 하위 모듈 인스턴스를 이용한 구조적 모델링
![]() |
module full_add(a, b, cin, sum, cout); input a, b, cin; output sum, cout; wire w1, w2, w3; half_adder U1(.a(a), .b(b), .sum(w1), .cout(w2)); half_adder U2(w1, cin, sum, w3); or U3(cout, w2, w3); endmodule |
전가산기는 반가산기 두개를 합쳐 만들 수 있다. 이를 표현한 코드가 위와 같다. 반가산기 모듈이 이미 파일에 저장되어있으며 모듈 이르밍 half_adder라고 하면, U1과 U2는 half_adder 모듈의 변수명이다. U1과 U2는 다른 방법으로 모듈 포트에 신호를 연결하고 있다. U1은 '이름에 의한 매핑', U2는 '순서에 의한 매핑'이다.
U1의 괄호 내부를 보면, 반가산기의 포트 리스트가 .포트명(신호) 로 표현되어 있다. U2의 경우는 반가산기 모듈에서 정의된 포트리스트의 순서와 동일한 순서로 매핑할 신호를 적은 것이다. U3는 게이트 프리미티브 인스턴스를 호출한 경우이다. or 논리게이트가 U3라는 이름으로 사용되었으며, 전에 설명했듯이 게이트 프리미티브는 괄호 내의 첫번쨰 변수가 출력, 나머지 변수가 입력이다.
'verilog HDL' 카테고리의 다른 글
[verilog HDL] 반도체 설계 엔지니어의 첫걸음! verilog HDL 연습하기 (14) | 2025.08.14 |
---|---|
[verilog HDL] (4)테스트 벤치(Test Bench) 모듈 (3) | 2024.09.13 |
[verilog HDL] (2) verilog HDL이란 무엇인가 (0) | 2024.08.21 |
[verilog HDL] (1)가속기 시스템이란? (0) | 2024.08.20 |