수업/Digital Design & Lab

Verilog 기초

hw-ani 2022. 10. 30. 15:03
이 카테고리의 이 글 바로 직전에 썼던 글에 잘못된 정보가 꽤 있었다. 당시에 수업을 두번정도만 듣고 나름 찾아보며 정리했던 글이라 그랬다. 내 개인적인 생각도 많이 들어갔었고, 애초에 잘못된 정보도 있었고... 그래서 어느 정도 배우고 중간고사가 지난 지금 다시 한번 정리해볼까한다.
(기존 글은 필요한 내용과 핵심 내용만 여기로 가져오고 원본은 삭제함)

 

배경

우리가 아는 Java 같은 고수준 PL의 아래엔 무엇이 있을까? 무엇을 기반으로 했기에 그런 언어를 이용한 설계가 기능할 수 있는걸까? 갑자기 하늘에서 떨어진건 아닐 것이다.

그 기반을 살펴보기 위해 물리학까지 내려가자면 끝도 없을 것이고,, 납득할만한 수준에서 보자면 그 시작은 트렌지스터이다.

트렌지스터 없이 회로의 한 지점에서 다른 지점까지 정보를 전달하기는 쉽지 않았다. 하지만 트렌지스터가 등장하며 전류/전압을 전류/전압으로 통제할 수 있게 되면서 전압을 낮게줬다가 높게줬다가 조절하며 정보를 전달할 수 있게 됐다. 트렌지스터는 정보전달의 스위치 기능을 해준다. 몇 볼트 이상이면 1, 몇 볼트 이하면 0, 이런 식으로 하여 이진수를 표현하는 것이다.

트랜지스터 덕분에 지금의 모든 복잡한 정보 기술들이 나왔다고해도 과언이 아니다.

 

이런 트렌지스터들을 회로로 어찌어찌 잘 구성하면 AND/OR/NAND/... 같은 logic gate를 만들 수 있다.

회로에 따라 해당 논리 연산에 맞는 값이 결과로 나온다. logic gate들도 사실 모두 회로이다.

(AND gate, OR gate는 NAND gate를 기반으로 만들어진다.)

 

다음 단계로는 이 logic gate를 조합한다. 얘네를 조합하면 Adder라던가 Counter라던가 하는걸 만들어서 훨씬 더 고수준 작업을 할 수 있다.

이런걸 만드는 방법은 논리회로에서 자세하게 배운다. truth table만들고.. 뭐 어쩌고저쩌고

이렇게 gate들을 엮고 엮어서 CPU라던가 우리가 아는 훨씬 복잡한 HW를 만들어낸다.

 

과거에는 CPU를 만들기 위한 설계를 종이도면 위에 했지만, 최근 CPU를 그렇게 설계하긴 매우 힘들다.(사실상 불가능하다.) 그렇게 설계해버리면, 설계는 둘째치더라도 TEST하는게 사실상 불가능하다.

그래서 HDL(Hardware Description Language)을 주로 사용한다. HDL을 이용하면, 비교적 간단하게 설계할 수 있고 test하기도 편리하기 때문이다.

verilog도 이런 배경에서 등장한 HDL 중 하나이다.

 

그렇다고 HDL이 만능은 아니다. 회로 논리를 구현해보고, test case 넣어서 시뮬레이션 돌리고 확인해보고 이정도 수준이지 실제 하드웨어 설계에선 작은 부분이다. 실제로 설계할땐 회로 선 길이까지 다 정해야한다.

(HDL을 쓰는 이유는 경제적인 이유도 있다. 실제로 칩 만들려면 억단위로 들어가는데, 만들고 수정하고 하기엔 너무 낭비가 심하다.)

 

간단하게 상위수준 SW까지 쭉 쌓아올려진 단계를 보자면..

Device<Circuit<Gate<RTL<System<Processor<OS<그 외 브라우저라던가 많은 SW가 다 OS위에 있는 것

verilog로는 Gate Level(혹은 Switch Level)~RTL를 구현한다. 여기서 RTL이란 Dataflow level과 Behavioral level을 합친 것을 말한다.

 


Verilog

명심하고 들어갈게 있는데, Verilog같은 Hardware Description Language는 Hardware를 설계하는 언어다. 즉, 회로를 그려보는 Tool 같은 것이다. 언어로 표현돼서 C 같은 놈이랑 유사성이 있을 거라고 생각하는 것이지, 실체는 CAD 같은 것에 더 가까울 것이다. C랑 문법은 비슷하지만, 의미는 상당부분 다르다.

 

우선 큰 그림부터 잡자면, 하드웨어 설계시에는

(1)module과 (2)test bench 이렇게 두개를 만들어야 한다.(둘 다 .v file이다.)
module로 회로를 실제로 설계하고, test bench로 해당 회로에 입출력을 주고 받으며 테스트를 하는 것이다.

test bench 또한 verilog의 기능들을 활용해서 구현된다. test bench는 (1)test bench의 내부에서 module을 instantiate해서 값을 주며 테스트 하는 방법과 (2)더미모듈에서 test bench와 module을 instantiate시켜서 둘이 상호작용하며 값을 주고 받도록 테스트 하는 방법이 있다.

 

verilog로 설계가 끝나면 synthesis라는 과정을 거친다.

왜냐하면 베릴로그로 표현하다보면 실제 회로와는 다를 수있기 때문이다.
논리적인 부분을 중심으로 설계하다보면 실제 회로에선 이상할법한 문법이 나올 수 있는데, 이런걸 정리해서 회로도로 뽑아주는 과정이 synthesis이다.
예를들어 NOR 게이트를 베릴로그에서 표현하면 ~(A|B) 식으로 되기도 한다. 그런데 실제 NOR 게이트는 그냥 NOR게이트일 뿐이지 not과 or의 조합이 아니다. 오히려 OR가 NOR에 NOT을 한 것이다. 이걸 보고 그대로 회로를 그리면 매우 비효율적이니 synthesis 과정을 거친다.

synthesis 덕분에 (sythesis가 알아서 다 변환해주니) 우리는 다양한 level에서 HW를 설계할 수 있는 것이다.

 

 

 

verilog에서 hardware를 설계할때 네가지 추상화 레벨을 이용할 수 있다.
1. Behavioral Level     : RTL
2. Dataflow Level        : RTL
3. Gate Level
4. Switch Level (이 부분은 수업시간에 다루지 않음)

이제 우리(우리 == 초보자들)는 이 각각 level에 맞는 문법(사용법)과 설계 방법을 배워서 그걸 그대로 적용하기만 하면 된다. 레벨을 섞어쓰든 어찌하든 원하는 HW를 설계하기만 하면 된다.

Programming 언어 배우듯이 굳이 다른 레벨의 문법을 섞어가며 이건 되나? 이건 안 되나? 하며 고민할 필요가 없다. HW에도 당연히 SW처럼 추상화 단계가 있을 것이고, 그 추상화 단계별로 어떻게 하드웨어를 설명(설계)하는지 배우기만 하면 그만이다.
즉, "각 level에서 지원하는 문법을 따로 익히고, 특정 level을 설계해야할때 해당 문법을 따르자."는 것이 지금 내가 가져야 할 자세다. 비유를 하자면, 우리가 한글 프로그램으로 문서를 만든다고 해보자. 표는 그냥 표 기능을 사용해서 만들면 그만이다. 굳이 사각형들 하나하나 그려서 이어붙여보고 '표를 이렇게 만들면 안되나?'하는 고민은 필요없다는 말이다.

규칙에 맞게 잘 코딩만 해두면 알아서 잘 합성해준다.

Sequentail Circuit도 dataflow 레벨로 구현할 수 있고, Combination Ccircuit도 behavioral 레벨로 구현할 수 있다. 단지, SC를 behavioral level에서 구현하는게 편하기 때문에 그 경우를 많이 볼 뿐이다.
어쨌든 중요한건, 각 레벨은 각 레벨대로 문법을 익혀서 그 틀에 맞게 잘 쓰기만 하면 된다. 이제 각 레벨별로 간략하게 살펴보자.

 

 

 

(1) Gate Level

Gate Level은 말 그대로 논리 게이트 수준의 설계이다. verilog에 미리 정의된 and, or 등의 module을 instantiate해서 사용하면 된다. 이런 predefined 모듈은 매개변수로 초반에 output, 뒤에 input을 받는다.

(Gate Level에서 설계하는 자세한 방법 및 예시는 ppt Chatper 4 참고)

 

 

(2) Dataflow Level

Dataflow Level은 말 그대로 데이터 흐름 단계에서 설계를 하는 것이다. 어떤 데이터가 어디서 어떻게 어디로 가는지를 기술하기만 하면 된다.

그렇기때문에 여기서 주로 쓰는 문법이 continuous assignment라는 것이다. continuous assignment가 바로 data가 "어디로" 흘러가는지를 정의해주는 것이다.

이 continous assignment내에선 ""무조건 wire"" type만 쓰일 수 있다.

그 외에도 각종 연산자들(더하기 빼기 논리연산자 bitwise reduction concatenation ...)을 이용해 각 데이터가 "어떻게" 변환되는지를 기술할 수 있다.

즉, continous assignment + operators 가 Dataflow Level에서의 주된 도구이다.
(truth table을 그대로 이용해 설계할 수 있는데, input 데이터를 concatenate해서 truth table에서 해당되는 값이 assign되도록 ternary operator를 사용하면 된다. dataflow level에서는 주로 이 방법을 사용한다고 함.)

(Dataflow Level에서 설계하는 자세한 방법 및 예시는 ppt Chapter 5 참고)


(3) Behavioral Level

Behavioral Level은 말 그대로 행동 단계에서 설계한다. 여기선 하부 하드웨어가 어떻게 구성되는지 전혀 신경 쓸 필요가 없다. 그냥 말 그대로 특정 HW의 "행동을 카피"해서 똑같이 해주기만 하면 된다.

Behavioral modeling에서 사용할 수 있는 가장 큰 블럭은 always문과 initial문이다.

무조건 이 두 구문 내에 다른 Behavioral 문법들(if나 case나)이 쓰여야한다.

그리고 always/initial 구문 내에는 wire(net)가 올 수 없다. always/initial 문 내에선 ""무조건 reg"" type만 쓰일 수 있다.

참고로 ★verilog의 코드들은 동시에 실행된다.★ 무슨 말이냐면, 같은 모듈 내의 assign/initial/always 은 모두 모듈이 실행되면 동시에 시작한다. 각 assign/initial/always의 내부에서는 순차적으로 실행된다.

always는 무한반복되고(@로 조건을 주면 그 조건일때만 실행됨), initial은 한번만 실행된다.

always와 거의 같은 기능을하는 forever라는 것도 있다.

always와 initial은 nested될 수 없는데, forever는 initial/always 안에서 쓰일 수 있다는 것이 always와의 차이이다.

 

initial/always 내에서 쓰이는 assignment는 procedural assignment라고 한다.(dataflow에선 continuous assignment라고 했었음)

procedural assignment는 blocking과 non-blocking 두가지 방식이 있다.

자세한 방식과 차이는 강의 자료 참고.

 



always문과 blocking/nonblocking을 쓰는 방법은 정형화 돼있다. 제일 아래 참고.

 

Q. Behavioral modeling에서만 reg를 쓰는 이유가 뭘까?

A. 추측이긴하나, reg 같은 개념은 실제 회로도에는 보이지(쓰이지) 않는다. 해봐야 게이트만 있을 뿐이다.

사실상 dataflow 모델링까지만해도, 말 그대로 data 흐름만 만들어 주면 되니 실제 회로엔 없는 reg 같은게 필요없는게 아

닐까 싶다. behavioral 부터는 우리가 행동에 맞게 값을 저장하기도 해야하니 reg가 있는 것이고..
근데 또 이렇게 생각하면 회로에 gate라는 것도 우리가 만든 더 높은 레벨의 개념일 뿐이다. 즉 reg라는 것도 우리가 하드웨어 추상화 레벨을 높이다가 Behavioral level에서 필요해진 개념이라 여기서만 쓰는게 아닌가 추측해본다.

 

 


추가

 

PDF 파일 참고:

Behavioral modeling시!!!

SC는 always@(posedge clk) 등으로 기술하고, 내부에선 non blocking을 사용하라.

CC는 always@(*)로 기술하고, 내부에선 blocking을 사용하라.

(이걸 깊이있게 탐구할 시간/이유/의욕은 딱히 없으니 그냥 PDF에서 말하는 근거 수준에서 받아들이자.)

 

 

How to know if a verilog code is SC or CC?
: always @*  해도 SC로 합성될 수 있음. 어떤 회로인지 알려면 의미 파악을 잘하자.

 

 

always 문에서 이벤트조건 줄때 input port에만 반응 하는 것 같다. 뭔 말이냐면 그냥 "@*" 로 하면 "always 안에 있는 애들 중에 input 포트에 연결된 애들"이 바껴야지만 반응하는거 같음. 주의하자. (어디서 본건 아니고 내 경험이긴 함)

 

 

> Delay

reg/wire a = b+c;에서 Delay는 어떤 level이든 보통 변수명(a) 앞에 온다.

b앞에 올 수도 있는데, 이러면 의미가 달라진다.

a 앞에 오면 해당 delay 후에 연산을 수행하지만, b 앞에 오면 미리 연산을 수행해두고, 해당 delay 후에 assign이 된다.

 

 

 

 

'수업 > Digital Design & Lab' 카테고리의 다른 글

SHA-256  (2) 2022.12.26
간단한 컴퓨터 구조와 HDL  (2) 2022.09.05