본문 바로가기

회로설계

Verilog 기초

디지털 설계 기초 + VHDL 코드는 위 링크에 정리

 

Verilog( Xilinx vivado 20.2 버전 )

 

더보기

기본 세팅 

vivado -> create project -> next -> 한글을 넣으면 안됨(컴파일에러남), 위에는 프로젝트이름, 아래는 파일위치 -> rtl 프로젝트-> 소스 없으니 넥스트-> constraints 나중에 할꺼임

이미 프로젝트를 진행한게 있다면 open -> 파일그림있는거 선택

 

<보드 선택>
넥스트 -> 파트 옆에 보드 클릭 -> 인스톨/업데이트 보드 클릭 -> 디질런트 사에 베이시스3(초보자들이 많이씀 대중적으로 많이 사용하는 보드임/ 실습하는 애들 이거 써서 이걸로
설명한듯) -> 우클릭해서 해당 보드 인스톨 -> close -> next -> finish // 여기까지 잘못된게 있다면 프로젝트 서머리 창 누르고 수정할 수 있음

 

이제 C언어에서 .c파일 만들듯이 소스파일을 만들어야함
-> 디자인소스에 추가할꺼임 파란색 + 모양해서 추가할수도 있고 우클릭해서 추가해도 됨
-> add source -> 3가지 선택창 모두 사용할껀데 지금 당장은 가운데 create design source를 클릭해준다 -> next하면 add files(기존 만들어놓은거 추가할때)
create files(새로운거 생성할때 ) 우리는 처음 시작하는거니까 create 해준다 -> 파일이름 gates 아까 설정해준거 -> finish
다음에 생성되는 창에서 인풋 아웃풋을 선택할 수 있음 -> 필자는 여기서 추가하는거 선호하지않고 코딩하는 것을 선호함 -> ok 눌러 넘어감
design source에 하위폴더로 gates.v 파일이 생성된것을 확인할 수 있다
-> 더블클릭하면 그 소스를 볼 수 있다
-> 여기까지가 최초 기본 세팅이라고 할 수 있다.

 

잊어버리면 안되는 중요한 verilog 설계 핵심 개념 정리

더보기

1. module은 큰 블랙 박스라고 생각하고 입출력 정의를 먼저한다. ex) input a, / 모듈 괄호가 끝나고 ); endmodule 위에 그 블랙박스의 세부 내용 즉 게이트들을 위에 정의한 입출력들을 사용한다 ex) assign

2. 이미 만들어 놓은 모듈을 긁어오는 경우 전체 블랙박스 모듈 밑에 붙여넣는데 형식은 아래와 같다

(가져올 모듈 이름) (이 모듈안에서의 새로운이름)

.가져올 모듈의 입력(그 단자에 입력할 변수),

3. 큰 블랙박스 모듈의 안쪽에서 모듈안쪽에서 연결되는 선들은 선언을 해줘야함 // 위치는 아까 입출력 선언하고 ); 닫아놓은 곳 밑에 선언하면 된다.

 

4. 아래를 참고하면 이해가 쉽다.

 

module 1bit_full_adder(
    input a,
    input b,
    input cin,
    output sum,
    output carry
    );
    
    wire w_sum1; 

// 모듈안쪽에 연결되는 선을 선언해준거임 ,hf1,hf2끼리 연결되는거를 위해서
 wire w_carry1;

wire w_carry2;
    
    
half_adder HA1(
    .a(a), //half adder 입력에 full adder 입력 ()안에 넣어줌
    .b(b),
    .sum(w_sum1),
    .carry(w_carry1)
    );
  
half_adder HA2(
    .a(w_sum1), 

//a,b,는 조그만 hf의 입력단자인데 거기에 뭘 연결할꺼냐를 생각해야함
    .b(cin),
    .sum(sum), 

// sum은 최종 외부포트임
    .carry(w_carry2)
    );  

 

메인 소스파일.v -> gate들 실습 + 문법

더보기

 

문법 : 연속할당문(assign)과 primitive
c언어에서는 =은 변수에 대입의 느낌이였는데 연속할당문에서는 =는 연결이라고 생각해야함
wire와 wire를 연결한다는 의미
**나만의 규칙 암기
assign 출력 연결할 곳 = 입력 (게이트종류) 입력;
ex) assign led0 = a & b;

중요!! 결국 모듈은 전체 네모 박스를 생성한 것이고 그 안에 세부적인 연결은 assign으로 할당해주는거임
예를 들어 a,b를 입력으로 led0~5를 출력으로 사용할꺼면 module로 다 선언해주고
assign으로 그 입출력들을 어떻게 연결할껀지 만들어주는거라고 보면됨

 

gate primitive -> 이미 정해져있는 기능 / 위에 연산할당문과 동일한 기능임
형식 : gate 이름(출력, 입력,입력);


module gates(
    input a,
    input b,
    output led0,
    output led1,
    output led2,
    output led3,
    output led4,
    output led5

    );
    /*
    assign led0 = a & b; //연속할당문
    assign led1 = a | b;
    assign led2 = ~(a & b); //nand
    assign led3 = ~(a | b); // nor
    assign led4 =  a ^ b; // xor
    assign led5 =  ~a; // not
    */
    //gate primitive
    and(led0, a, b);
    or(led1, a, b);
    nand(led2, a, b);
    nor(led3, a, b);
    xor(led4, a, b);
    not(led5, a);
endmodule

 

-> 코딩은 완료했지만 여기서 a,b led들을 보드의 어느 포트에 할당할지는 아직 모르니까 연결을 해줘야함 
-> 아까 3종류뜬 설정 창에서 첫번째 add or create constraionts 클릭할꺼임 
방법 : source 창에서 파란색+네모 클릭 -> 1번 선택 -> add files ->아까 받은 베이시스3 파일을 찾아야함(gates 만든 파일에 들어가서 Basys3.xdc 찾음) //그래서 바로 RTL 분석에서 open해서 게이트레벨로 회로 그림

고정되어있는 초록색은 PCB에 고정되어서 바꿀수없음
우리는 스위치 0번 1번을 사용할꺼라했음 input a,b로

즉 스위치쪽에 주석을 지워주고 get ports 뒤에 부분 sw로 되어있는거를 a,,b로 바꿔주면 됨
----------
-> run RTL 해주고 8 i/o ports 눌러보면 밑에 리스트가 쫙뜸 -

package pin에 설정한대로 들어가있고, LVCMOS33 -> 3.3v로 하겠다.

-> 이 코드 스케메틱은 논리적인 값인거고 이제 실제로 물리적인 형태 코드를 실제 하드웨어적으로 변경시키는작업 즉 synthesis(합성) 작업을 해야함 // 코드 -> 하드웨어로

만약 기본 논리게이트들로 이루어진 회로를 그려보고 싶다면 Run RTL 하고 schematic 바로 보면 됨


----------

<보드에 적용>
run synthesis 클릭 -> 넘벌오프잡스 (제일 큰거 18로 하셈 우리가 사용하는 컴퓨터 코어 개수임) -> 오른쪽위에 동글동글 돌아갈꺼임 + 프로젝트 서머리 보면 어떤 작업하고 있다고 동그라미 돌고 있음 + 아래 message 부분
에서 나옴
-> 컴플리트 됐으면 synthesis 부분에서 스케메틱스 눌러보면 fpga 회로에 맞게끔 회로도 다시 나옴
-> implementation 눌러서 -> 나온 netlist 바탕으로 fpga 회로에 매치 시키기 -> 스케메틱하고 똑같이 뜰꺼임
( 나오는 그림은 보드 칩의 회로도임)

-> 이제 만들어진걸 보드로 넣어야함 -> 보드에 입력되는 파일을 bitstream이라고 함 (implementation 아래쪽에)

-> generate bitstream 클릭  -> 파일 만들어졌으면 보드 연결시켜놓고 -> 나오는 창에서 open hardware manager 선택 -> hardware 부분에 보드가 뜨면 정상임 난 연결 안해서 안뜸

-> 정상적으로 연결되어 있다고 가정하고 진행
program device 창이 자동으로 뜨고 bitstream 파일이 자동적으로 쳐져 있을꺼임 (.bit 파일)
-> 확인 버튼 누르면 프로그램이 다운될꺼임 -> 보드에 적용된거임 스위치 led 작동할꺼임

 

보드 입출력 사용

고정되어있는 초록색은 PCB에 고정되어서 바꿀수없음
우리는 스위치 0번 1번을 사용할꺼라했음 input a,b로

즉 스위치쪽에 주석을 지워주고 get ports 뒤에 부분 sw로 되어있는거를  a,b로 바꿔주면 됨 -> 내가 설정한 입력변수

 

시뮬레이션

 

더보기

-> 코드를 만들고 나서 계속 다운로드해서 보드에서 확인하게되면 시간이 너무 오래걸리고 하니까
컴퓨터 상에서 시뮬레이션을 해봐야함

-> 방법 : 시뮬레이션용 모듈을 다시 만들어서 가져오는거임 -> c언어에서 함수에서 함수부르는것처럼
첫번째 실습에선 gate들 전체가 하나의 모듈이였음

시뮬레이션에선 입력값을 값을 넣어서 출력으로 확인하는거임
module test bench -> 이 모듈은 우리가 만든거랑 다르게 입력 출력이 필요 없음

-> 맨 위에 프로젝트 매니저를 클릭 -> 오른쪽 source부분에서 +파란색 더하기 클릭 -> 3번째 시뮬레이션 있음
-> create-> 파일이름은 폴더_tb로 통일하자 -> finish-> ok

소스쪽에서 시뮬레이션 소스-> sim1 쪽 펼쳐보면 파일 생긴거 볼수있음 -> 더블클릭해서 들어가봄

모듈만 있는거 보임 -> 얘는 입출력 없으니까 소괄호 안쪽에 내용 쓸 필요 없음

 

<tb 파일 작성>

1. tb 괄호 닫기 ();

2. 원래 파일에서 모듈부터 복사하고 endmodule 전까지 복사해와서 붙여넣기

3. module은 지우고 이름 뒤에 dut 붙이고 내용 수정  .led2(led2), 이런식으로

4. 2번에서 복사해온 내용 3번 만든거 위에 다시 붙여넣기

5.   input -> reg 로, output -> wire로 수정해주기

6.     initial begin
    #00 a = 1'b0; b = 1'b0;
    #10 a = 1'b0; b = 1'b1;
    #10 a = 1'b1; b = 1'b0;
    #10 a = 1'b1; b = 1'b1;
    #10 $finish;

시뮬레이션 값 넣어주기



 

 시뮬레이션 소스
module gates_tb();
    reg a;
    reg b;
    wire led0;
    wire led1;
    wire led2;
    wire led3;
    wire led4;
    wire led5;
    
    gates dut(
     .a(a),
     .b(b),
     .led0(led0),
     .led1(led1),

 //걍 .뒤에는 원래 출력 module 설정한거 -> 괄호 안에는 시뮬레이션 화면에서 출력 어떤 이름으로 볼꺼라고 생각
     .led2(led2),
     .led3(led3),
     .led4(led4),
     .led5(led5)
    );
    initial begin
    #00 a = 1'b0; b = 1'b0;
    #10 a = 1'b0; b = 1'b1;
    #10 a = 1'b1; b = 1'b0;
    #10 a = 1'b1; b = 1'b1;
    #10 $finish;
    end
    

endmodule

 

 

이제 왼쪽 시뮬레이션 메뉴에서 run -> 제일 위에꺼 선택

소스에서 확인해보면 dut : gates가 정상적으로 떠있으면 위에 gates.v 파일에서 제대로 참조된거임
시뮬레이션 화면에서 대각선 4방향되어있는거 누르면 한화면에 쫙들어옴

(wire는 전선 연결이라는 의미, 저장은 못함)
gates dut -> gates는 테스트하고 싶은 모듈이름이고 dut는 인스턴스 즉 실체화하는거임

그 실체화한 박스에 reg자료형을 연결시켜줌, led0~5까지 선을 연결해준거

initial은 시뮬레이션용으로 합성이 안됨 -> 이 키워드를 가지고 코딩을 해도 하드웨어적으로 변환이 안된다는 뜻
이제 아까 reg로 만든 변수 변수에 값을 넣어주는거임

a = 1'b0; -> 1은 data길이 비트길이 , b는 진법(binary), 0은 값임 // b는 2진수, d는 10진수, h는 16진수
숫자만 있는 값은 32비트짜리 10진수임

#숫자는 -> 딜레이임 단위는 nano로 되어있음 / 즉 10 나노sec후에 a b 에 0 1 넣는거임
마지막  #10 $finish;

코드옆에 동그라미는 시뮬레이터가 확인중인거 
시뮬레이션 ->정상적으로 동작하는 것 확인완료

verilog 단축어 정리

더보기

Vivado에서 Verilog 코드를 작성하거나 디버깅할 때 사용할 수 있는 유용한 단축키는 다음과 같습니다.

일반 편집기 단축키
Ctrl + Space: 자동완성 창을 표시합니다. 코드 작성 시 필요한 변수명, 함수명, 모듈명 등을 자동으로 완성합니다.
Ctrl + / (슬래시): 현재 줄을 주석 처리하거나 주석을 해제합니다.
Ctrl + Shift + F: 코드 포맷팅 기능으로, 코드를 자동으로 정렬하여 가독성을 높입니다.
Ctrl + Z: 실행 취소(Undo) 기능입니다.
Ctrl + Y: 다시 실행(Redo) 기능입니다.
코드 탐색 및 편집
Ctrl + F: 찾기(Find) 창을 엽니다.
Ctrl + H: 바꾸기(Replace) 창을 엽니다.
Ctrl + G: 지정한 줄로 이동합니다.
F3: 찾은 결과의 다음 항목으로 이동합니다.
Shift + F3: 찾은 결과의 이전 항목으로 이동합니다.
Ctrl + D: 현재 줄을 복제합니다.
프로젝트 관리
Ctrl + N: 새 파일을 만듭니다.
Ctrl + S: 현재 파일을 저장합니다.
Ctrl + Shift + S: 모든 파일을 저장합니다.
Ctrl + W: 현재 탭(파일)을 닫습니다.
Ctrl + Shift + W: 모든 탭을 닫습니다.
시뮬레이션 및 디버깅
F9: 시뮬레이션을 실행합니다.
F11: 한 줄씩 디버그(단계 실행)합니다.
F5: 디버깅을 계속 진행합니다.
Ctrl + R: 시뮬레이션을 다시 실행합니다.
Ctrl + Shift + F9: 전체 디자인을 컴파일하고 시뮬레이션합니다.
3. 사용자 정의 단축키 설정
Vivado에서는 사용자가 단축키를 커스터마이징할 수 있습니다. 사용자 정의 단축키를 설정하려면:

Tools 메뉴로 이동합니다.
Options를 선택합니다.
Key Bindings 섹션으로 이동하여 원하는 명령어에 대한 단축키를 설정합니다.

Ctrl + 클릭: 원하는 위치에 멀티 커서를 추가하려면, Ctrl 키를 누른 상태에서 클릭합니다. 이를 반복하면 여러 줄에 커서를 추가할 수 있습니다.

Vivado에서 자동완성 끄기
Vivado를 엽니다.
Tools 메뉴로 이동합니다.
Settings을 선택합니다.
설정 창에서 Text Editor 또는 General 섹션을 찾습니다. (버전마다 이름이 다를 수 있습니다.)
Auto-Completion 또는 Code Completion 관련 설정 항목을 찾습니다.
Enable Auto-Completion 또는 Enable Code Completion의 체크를 해제합니다.
Apply를 클릭하고 OK를 눌러 변경 사항을 저장합니다.

 

1bit Full adder 실습

 

더보기

먼저 HA.v 파일 만들고 디자인소스 누르고 + 눌러서 파일 하나 더 만들어 이름은 FA

module half_adder(
    input a;
    input b;
    output sum;
    output carry;
    );
    
    xor(sum,a,b);
    and(carry,a,b);
end module

 

반가산기를 만들었으니 이제 다시 디자인소스에서 새로운 파일을 add 하고 FA를 만들어준다.

 

module 1bit_full_adder(
    input a,
    input b,
    input cin,
    output sum,
    output carry
    );
    
    wire w_sum1; // 모듈안쪽에 연결되는 선을 선언해준거임 ,hf1,hf2끼리 연결되는거를 위해서
    wire w_carry1, wire w_carry2;
    
    
half_adder HA1(
    .a(a), //half adder 입력에 full adder 입력 ()안에 넣어줌
    .b(b),
    .sum(w_sum1),
    .carry(w_carry1)
    );
  
half_adder HA2(
    .a(w_sum1), //a,b,는 조그만 hf의 입력단자인데 거기에 뭘 연결할꺼냐를 생각해야함
    .b(cin),
    .sum(sum), // sum은 최종 외부포트임
    .carry(w_carry2)
    );  
    
    //assign carry = w_carry1 | w_carry2; 
    or(carry, w_carry1,w_carry2);
    
endmodule

 

디자인소스에서 정상적으로 HA1,HA2가 full adder 모듈에 들어가있는 것을 확인 가능

이제 run RTL로 1bit FA를 schematic으로 확인해보면 정상적으로 만들어 진 것을 확인가능하다.

 

FullAdder_4bit 실습

 

더보기

4bit full adder -> 벡터형 활용

module FullAdder_4bit(
    input [3:0] a,
    input [3:0] b,
    input cin,
    output [3:0] sum,
    output carry
    );
    wire [2:0] W_carry;
    
    Fulladder FA0(
        .a(a[0]),
        .b(b[0]),
        .cin(cin),
        .sum(sum[0]),
        .carry(w_carry0)    
    );

    Fulladder FA1(
        .a(a[1]),
        .b(b[1]),
        .cin(cin),
        .sum(sum[1]),
        .carry(w_carry1)    
    );    

    Fulladder FA2(
        .a(a[2]),
        .b(b[2]),
        .cin(cin),
        .sum(sum[2]),
        .carry(w_carry2)    
    );

    Fulladder FA3(
        .a(a[3]),
        .b(b[3]),
        .cin(cin),
        .sum(sum[3]),
        .carry(carry)    
    );        
endmodule

'회로설계' 카테고리의 다른 글

[cadence] 1k*4bit SRAM full-custom 설계(0.5um PDK)  (4) 2024.09.22
RTL 디지털 설계 (VHDL)  (0) 2024.08.19
EDA_cadence_VLSI_설계, 기초 단축키  (0) 2024.08.01