하만(Harman) 세미콘 반도체 설계 과정/Verilog를 이용한 RTL 시스템 반도체 설계

하만(Harman) 세미콘 아카데미 13일차 - Verilog HDL 설계(Verilog의 버스, 배열, 모듈, 포트, Half Adder를 이용한 Full Adder 설계)

semicon_circuitdesigner 2024. 3. 25. 11:43

[2024.03.25.월] 인천인력개발원 하만 세미콘 아카데미


Verilog를 이용한 RTL 시스템 반도체 설계


Verilog의 버스 & 배열


1. Verilog 버스

  • 버스: 비트의 모음
    • 모든 wire나 reg 데이터 타입은 버스로 표현 가능
    • reg 버스: reg 비트의 모음
    • wire 버스: wire 비트의 모음
       - 예시: 버스를 선언할 때 상수나 변수 사용 가능
      module cntr64 (input...);
      `define data_msb 63
      wire [`data_msb:0] data_bus;​
  • 비트 선택: 벡터나 배열 내의 개별 비트 표시
    • 선언 예시
      wire [31:0] data_bus;
      wire [0:7] h_byte;
      reg [15:0] control;
      
      int i, j;
      
      assign h_byte[i] = control[j];
      assign h_byte[7] = control[14];​

      [31:0]으로 선언 시 위와 같이 생성

      [0:7]으로 선언 시 위와 같이 생성
  • 부분 선택
    • reg [7:0] cntrl_bus = 8'b11100011;로 선언 시
       - 부분 선택 지시: 본래의 버스 선언 형식과 일치해야 함(cntrl_bus [3:0]은 가능하나 cntrl_bus[0:3]은 오류 발생)
       - cntrl_bus [10:7] -> xxx1을 반환
       - cntrl_bus [3:0] -> 값 3(001)
    • 사용 예시1
      wire [31:0] data_Bus;
      wire [0:7] h_byte;
      reg [15:0] control;
      
      assign data_bus [31:28] = h_byte [4:7];​
    • 사용 예시2
      reg [31:0] a_bus;
      
      for(i = 0; i<4; i = i+1)
      n_byte = a_bus[(i*8)+:8];​
      - a_bus [ 0+:8 ]은 0번째 비트에서 시작하는 8개의 비트를 의미
      - a_bus [ 8+:8 ] = a_bus[ 15:8 ]
      - a_bus [ 16+:8 ] = a_bus[ 23:16 ]
      - a_bus [ 8+:8 ] = a_bus[ 15:8 ]

2. Verilog 배열

  • 배열: 같은 자료형의 모음
  • 선언 예시
    reg [7:0] array_a; //8비트 벡터
    reg mem [7:0]; //​

3. Verilog 문자열

  • 큰따옴표 내의 문자의 집합
  • 선언 예시
    parameter chars = 25;
    reg [ 8*chars-1 : 0 ] my_string;
    ...
    initial
    my_string = "Welcome from AMD, Inc."; //큰 따옴표 내의 모든 문자가 my_string에 할당​



 Verilog의 모듈과 포트


1. Verilog의 모듈_p.65

  • 모듈: 논리 기술의 기본 단위
  • 선언 방법: module <module name> #(parameter(s)) (port declarations);
  • 사용 예시
    module adder ( input [3:0] a, b, 
    				output [3:0] sum,
                    output c_out );
    	
        wire [4:0] total;
        
        assign total = ( a+b );	//데이터 흐름 구조
        assign sum = total [ 3:0 ];
        assign c_out = total[4];
    endmodule

2. Verilog의 포트

  • 포트 지정 방법
    adder adder_i0 (.a(a_i), .b(b_i), .sum(sum_out), .c_out(carry_out)); -> 포트에 (신호)할당
     - adder: 하위 모듈 이름
     - adder_i0: wire 이름

실습 1: Half Adder을 이용하여 Full Adder 설계


[ 실습 순서 ]

1. Project -> add source my_hadder.v > add source my_fadder.v(Output A, B, Ci / Output S, Co)
2. my_fadder.v code
3. open elobrated
4. run synthesis -> open synthesis
5. run implementation
6. bitstream
7. H/W program
 

 
*참고사항: verilog 코드(~~.v) 위치: Verilog_lab\프로젝트명 폴더\프로젝트명.srcs\source_1\new\파일명.v

[ 실습 ]

1. Create Project - my_fadder_2 생성 - Next - RTL Project(Do not specify sources at this time 체크) - Next

 
2. Default Part 설정 - Next

 
3. Summary 확인 후 Finish

 
 
4.Add Sources - Add or create design sources(RTL code 생성)

simulation sources - 검증하기 위한 파일

 
5. 기존에 사용한 Half Adder을 사용하기 위해 Add files 이용

위에서 언급한 위치를 참조하여 .v파일을 찾아 추가

 

추가한 파일의 소스를 프로젝트로 부러오기 위해 선택사항 두 개 체크

 
6. Design Sources의 my_hadder.v파일 추가 확인

 
7.  fadder.v파일 추가를 위해 Create File - my_fadder.v 생성(A, B, Ci Input / S, Co Output)
 
8. my_fadder.v를 열어 module 내 이름 확인

 
9. wire 지정하여 코드 작성

 
 
10. my_hadder.v를 열어 module 파트를 복사 - my_fadder.v에 붙여넣기 후 포트와 신호 지정

아래 그림을 코드로 표현

 
11. 오른쪽의 반가산기에 포트와 신호를 지정하기 위해 코드 추가

ha1_s와 ha1_c까지의 코드
Output S와 Co를 할당하는 과정만 남았다

 
12. Save 후 Design sources의 변화 확인

 
13. 최종 출력 부분 S와 Co를 할당하기 위해 코드 작성

 
14. Open Elaborated Design - Schematic 확인

위의 그림과 같은 형태로 표현 완료

 
15. Run Synthesis - Open Synthesized Design - 우측 상단의 Default Layout - Netlist의 my_fadder 우클릭 - schematic

 
16. Co_OBUF_inst_i_1을 클릭하여 좌측의 진리표 확인

Co와 Sum 진리표 확인

 
17. 우측 상단의 I/O Planning 선택 후 포트 할당

  • LED1_B(G14)를 Caryy로, LED0_B(L15(를 Sum으로 할당
  • A, B, Ci는 각각 Y18, Y19, Y16에 할당

 
18. I/O Std 선택

 
19. Run Implementation - Save Constraints - OK - Launch Runs - OK

 
20. Generate Bitstream - Open H/W manager

 
20. Open Target - Auto Connect - Program Device - Program

 
21. Program - Programmed 확인 후 작동 확인

 
22. 작동 영상


실습 2: 2Bit Adder 설계


  • Full Adder 2개를 이용하여 계층적 구조로 설계
  • 내부 wire C0, C1 선언
  • 모듈 선언부
    input [1:0] A
    input [1:0] B,
    output [1:0] S;
               Co;

2 Bit Adder

 
1. 위 실습과 동일하게 my_4bitadder 프로젝트 생성 후 Add Sources로 my_adder.v 생성 - Finish

 
2. 입력 포트와 출력 포트 설정(A, B, S에 버스 선택m MSB 1)

 
3. 코드 작성

  • A, B, S를 버스로 선언

 
4. 저장 후 Open Elaborated Design - Schematic 확인

 

 
 
5. 핀 설정

A0, A1, B0, B1을 Y18, Y19, Y16, Y17로 설정 / S0과 S1을 LED0_G, LED1_G로 설정, Carry는 LED0_B로 설정

 
 
6. Run Synthesis

 
7. Run Implementation - Generate Bitstream - Open H/W Manager

 
8. Program Device 후 실행 확인

[2bit adder 진리표]

LED1은 왼쪽, LED0은 오른쪽 LED. LED1_B와 LED1_G가 모두 1이면 왼쪽 LED에 청록색 빛이 발광한다

 
9.실행 원리: A[1]A[0](2) + B[1]B[0](2) = Co S[1] S[0](2) = LED1_B   LED0_G   LED1_G
 
10. 정상 작동 확인
 


Verilog 연산자


1. Operator 종류: Bitwise, Logical, Relational, Equality, Reduction, Conditional, Concatenation, Replication, Shift, Arithmetic Operators
 
2. Bitwise 연산자(AND, NAND, OR, NOR, NOT, XOR, XNOR)

  • AND 연산자
    • 연산기호: &
    • 2개의 피연산자  필요
    • 사용 예시
      a = 4'b1011;
      b = 4'b0001;
      assign out = a & b;	//결과: 4'b0001​
  • NAND 연산자
    • 연산기호: ~&
    • 2개의 피연산자  필요
    • 사용 예시
      a = 4'b1011;
      b = 4'b0001;
      assign out = a ~& b;	//결과: 4'b1110
  • OR 연산자
    • 연산기호: |
    • 2개의 피연산자  필요
    • 사용 예시
      a = 4'b1011;
      b = 4'b0001;
      c = 4'b0001;
      assign out = a | b;	//결과: 4'b1011​
      assign out = b | c; //결과: 4'b10x1
  • NOR 연산자
    • 연산기호: &
    • 2개의 피연산자  필요
    • 사용 예시
      a = 4'b1011;
      b = 4'b0001;
      assign out = a ~| b;	//결과: 4'b0100​​
  • NOT 연산자
    • 연산기호: ~
    • 1개의 피연산자  필요
    • 사용 예시
      a = 4'b0001;
      assign out = ~a; // 결과값 4'b1110​
  • XOR 연산자
    • 연산기호: ^
    • 2개의 피연산자  필요
    • 사용 예시
      a = 4'b1011;
      c = 4'b111x;
      assign out = a ^ c; //결과: 4'b010x​​
       
  • XNOR 연산자
    • 연산기호: ~^
    • 2개의 피연산자 필요
    • 사용 예시
      a = 4'b0001;
      c = 4'b111x;
      assign out = a ~^ c; // 결과값 4'b101x​

 
3. 논리 연산자 (&&, ||, ! -> 조건을 따지는 연산자)

  • Logical AND
    • 연산기호: &&
    • 2개의 피연산자 필요
    • 사용 예시
      a - 4'b1011, b = 4'b0000, c = 4'b000x
      assign out = a && b; //결과값 1'b0(FALSE)
      assign out = a && c; //결과값 1'bx(UNKNOWN)
      assign out = (a == 4'b1011) && (b==4'b1111) // 결과값 1'b0​
  • Logical OR
    • 연산기호: ||
    • 두 개의 피연산자 필요
      a = 4'b1011;
      b = 4'b0000;
      assign out = a || b//결과값 1'b1(TRUE)​
  • Logical NOT
    • 연산기호 !
    • 한 개의 피연산자 필요
      a = 4'b0000;
      assign out =! a // 결과값 1'b1​

 
4. 비교 연산자(>, <, >=, <=) -> 모두 2개의 피연산자 필요

  • >: 피연산자보다 큰지 비교
    • 사용 예시
      a = 4'b1011;
      b = 4'b0001;
      assign out = a > b//결과값 1'b1(TRUE)​​
  • <: 피연산자보다 작은지 비교
    • 사용 예시
      a = 4'b1011;
      b = 4'b0001;
      assign out = a < b//결과값 1'b0(FALSE)​​​
  • >=: 피연산자보다 크거나 같은지 비교
    • 사용 예시
      a = 4'b1011;
      b = 4'b111x;
      assign out = a >= b//결과값 1'bx(UNKNOWN)​​​
  • <=: 피연산자보다 작거나 같은지 비교
    • 사용 예시
      a = 4'b1011;
      b = 4'b0001;
      assign out = a <= b//결과값 1'b0(FALSE)​​​

5. Equality 연산자: 두 피연산자의 일치 여부를 비교하여 1, 0 반환, 2개의 피연산자 필요

  • ==: 논리적으로 동일한지 비교
    • 사용 예시
      a = 4'b1011;
      b = 4'b111x;
      c = 4'b1010;
      assign out = a == b; //결과값 1'bx
      assign out = a == c; //1'b0
  • !=: 논리적으로 다른지 비교
    • 사용 예시
      a = 4'b1011;
      b = 4'b0001;
      assign out = a != b//결과값 1'b1
  • ===: 두 피연산자의 형변환 없이 같은지 확인(True ~= 1)
    • 사용 예시
      a = 4'b111x;
      b = 4'b10z0;
      c = 4'b111x;
      assign out = a===c; //결과값 1'b1
      assign out = a===b; //결과값 1'b0
  • !==: 두 피연산자의 형변환 없이 다른지 확인  
    • 사용 예시

6. Reduction 연산자: MSB부터 각 비트를 다음 비트와 비교하는 연산자

  • &: 각 비트를 다음 비트와 AND연산 -> 모든 비트가 1일 때만 결과 1
  • ~&: NOTAND 연산
  • ^: 각 비트를 다음 비트와 XOR연산 -> 비트 내의 1의 개수가 짝수면 0, 홀수면 1 반환
  • ~^: NOTXOR연산
  • |: 각 비트를 다음 비트와 OR연산
  • ~|: NOTOR 연산

7. Conditional 연산자: if문과 동일한 작용(3개의 피연산자 필요)

  • 연산 기호:  ? : ;
  • assign out1 = sel ? a : b;로 선언 -> sel이 True면 a, False면 b 실행

8. Concatenation 연산자: 신호나 버스를 묶을 때 사용

  • 연산 기호: {, }
  • 2개의 피연산자 필요
  • 사용 예시
    a = 4'b1011;
    b = 4'b0011;
    c = 4'b111x;
    assign out_bus = {a, b} //8'b1011_0011 생성
    assign out_bus = {a, c} //8'b1011_111x 생성​

9. Replication 연산자: 반복 연산자

  • 연산 기호: {{ }}
  • 2개의 피연산자 필요
  • 사용 예시
    a = 4'b1011;
    b = 4'b0011;
    c = 4'b111x;
    c = 4'b10z0;
    assign out_bus = {3{a}}; //= 12'b1011_1011_1011
    assign out_bus = {{2{d}}, c}; //= 12'b10z0_10z0_111x​

10. Shift 연산자: 비트를 이동하는 연산자, 2개의 피연산자 필요

  • >>: 오른쪽으로 비트 이동(빈자리에는 0으로)
    • 사용 예시
      a = 4'b1011;
      b = 4'b10z0;
      
      assign out = a >> 2 // = 4'b0010
      assign out = b >> 1 // = 4'b010z​
  • <<: 왼쪽으로 비트 이동 (빈자리에는 0으로)
    • 사용 예시
      a = 4'b1011;
      b = 4'b10z0;
      
      assign out = a << 2 
      // 답은 비트의 크기에 따라 다름(6bits -> out = 6'b101100 / 4bits -> out = 4'b1100)
  • >>>: 오른쪽으로 비트 이동(빈자리에는 1으로)
    • 사용 예시
      a = 4'b1011;
      b = 4'b10z0;
      
      assign out = a >>> 2 // = 4'b1110
      assign out = b >>> 1 // = 4'b110z​
  • <<<: 왼쪽으로 비트 이동 (빈자리에는 0으로, <<와 동일)
    • 사용 예시
      a = 4'b1011;
      b = 4'b10z0;
      
      assign out = a <<< 2; //out = 4'b1100)​

11. 산술 연산자(-(unary) 외 모두 2개의 피연산자 필요)

  • +: 덧셈 연산자
  • -: 뺄셈 연산자
  • *: 곱셈 연산자
  • /: 나눗셈 연산자
  • %: 나머지 연산자
  • -(단항): 1개의 피연산자 필요. 단항 값의 부호를 바꾸는 연산자
  • **: 지수 계산 시 사용