[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
- a_bus [ 0+:8 ]은 0번째 비트에서 시작하는 8개의 비트를 의미reg [31:0] a_bus; for(i = 0; i<4; i = i+1) n_byte = a_bus[(i*8)+: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 ]
- reg [7:0] cntrl_bus = 8'b11100011;로 선언 시
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 생성)

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


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. 오른쪽의 반가산기에 포트와 신호를 지정하기 위해 코드 추가


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을 클릭하여 좌측의 진리표 확인



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;

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. 핀 설정


6. Run Synthesis


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



8. Program Device 후 실행 확인
[2bit adder 진리표]

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개의 피연산자 필요. 단항 값의 부호를 바꾸는 연산자
- **: 지수 계산 시 사용