Verilog HDL 이론
목차 (1/3) Verilog HDL 소개 및 Design Flow Verilog HDL 기본 구성 요소 (1) 수표현 논리값 표현 신호 강도 식별자 (identifier) Module Port Primitives Net Register Vector Parameter 연산자 산술연산자 관계연산자 논리연산자 비트 연산자 단항 비트 연산자 기타 연산자 연산자 우선 순위
목차 (2/3) Verilog HDL 구문 구성 요소 Block Always문 Initial문 If문 Case문 For문 Repeat문 While문 Forever문 Function문 Blocking Assignment Non-blocking Assignment
목차 (3/3) System Task Test Bench Finite State Machine RAM Design Test Bench Example 1 – Adder Test Bench Example 2 – Counter Test Bench Example 3 – 곱셈기 Finite State Machine Mealy Machine Design Moore Machine Design RAM Design MAC Design Copyrightⓒ2005 ITSOC 검정사업단
Behavioral Description Functional Verification Automatic Place & Route Frontend Design Flow module mult16(a,b,c); input [15:0] a, b; output [31:0] c; assign c = a * b; endmodule Design Specification Behavioral Description RTL Description (HDL) Functional Verification and Testing Logic Synthesis Gate-Level Netlist Physical Layout Layout Verification Logical Verification Floor Planning Automatic Place & Route module mult16 ( a, b, c ); input [15:0] a; input [15:0] b; output [31:0] c; wire \mul_4/ab[13][0] , \mul_4/ab[9][1] , \mul_4/ab[3][13] , \mul_4/CARRYB[10][]
HDL이란 하드웨어 기술(표현) 언어 (Hardware Description Language) Digital System의 동작특성을 정해진 문법과 키워드 그리고 사용자 정의 객체들을 이용해 기술(description) 프로그래밍 언어와 다른 점 프로그래밍 언어는 순차구문(sequential statements)으로 구성되며 시간의 개념이 없다. HDL은 순차구문과 함께 병렬구문(concurrent statements)과 Clock, Delay등 일반 프로그래밍 언어에 없는 개념이 존재한다.
HDL의 종류 Verilog HDL(IEEE 1364) : 문법이 C언어와 유사하여 VHDL에 비해 배우기 쉬운 장점이 있다. Simulation시 PLI (Programming Language Interface)를 통하여 C언어 루틴과 연동할 수 있는 기능이 있다. VHDL(IEEE 1164) : Ada언어에 기원을 두고 있으며 Verilog HDL에서 제공하지 않는 고급 자료 구조(Records, Enums)등을 제공한다. SystemC : C++기반의 설계 Library로 알고리즘 레벨에서 RTL 레벨까지 단일 언어 환경에서 설계를 진행할 수 있는 장점이 있다. 기타 SystemVerilog, SpecC등의 설계언어가 있다.
Verilog HDL Language Verilog HDL은 Digital System을 기술하고 Simulation하기 위한 언어로 여러 단계의 추상화 레벨을 제공한다. 설계 초기단계에는 System의 기능을 Behavior 수준에서 기술하는 Behavioral 레벨 설계를 진행하며 이후 동작이 검증된 구조의 개선 및 최적화를 위해 Structural 레벨의 기술 방법을 사용한다. 대규모 System의 설계 복잡도를 줄이기 위해 계층적인 기술 방법을 이용한다.
Verilg HDL 기본 구성 요소 수표현 논리값 표현 신호 강도 식별자 (identifier) Module Port Primitives Net Register Vector Array Parameter 연산자 산술연산자 관계연산자 논리연산자 비트 연산자 단항 비트 연산자 기타 연산자 연산자 우선 순위
수 표현 (2/2) 수 표현에서는 대문자를 허용함 읽기 편하게 하기 위해 숫자에 언더바(_) 사용 가능 수 표현의 예 구 분 구 분 표현형식 의 미 일반적인 표 현 4’b1111 12’habc 16’d255 4 bit 2진수 12 bit 16진수 16 bit 10진수 <크기>가 지정되지 않은 경우 23456 ‘hc3 ‘o21 32 bit 10진수 32 bit 16진수 32 bit 8진수 음수 표현 -6’d3 3의 2의 보수로써 음수 X, z의 표현 12’h13x 6’hx 32’bz 12 bit 16진수, 마지막 4개 bit는 unknown 6 bit 16진수 32 bit 2진수, Hi-impedance 값
수 표현 (1/2) 형식 <크기>는 숫자의 비트 개수를 지정, 10진수만 가능, <크기>가 지정되지 않은 숫자는 Simulator마다 다른 기본값을 갖는다. <기본형식>은 4가지로 표현, 선택하지 않으면 10진수 취급 <숫자>는 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f를 연속적으로 나열함으로써 표현, 지정된 <기본형식>보다 낮은 수만을 사용 수 표현에 있어 Unknown값은 x로, Hi-impedance값은 z로 표현 음수의 표현은 숫자의 <크기>앞에 음수 부호를 붙임, 부호와 상관없이 <크기>는 항상 양의 값을 가짐 <크기> <기본형식> <숫자> ’d :10진수, ’h : 16진수, ’b : 2진수, ’o : 8진수
논리 값 표현 논리값 수준 하드웨어 회로에서의 상태 1 x z 논리적 0, 거짓 상태 논리적1, 참 상태 알 수 없는 값 Verilog HDL에서는 4개의 논리값만 사용 논리값 수준 하드웨어 회로에서의 상태 1 x z 논리적 0, 거짓 상태 논리적1, 참 상태 알 수 없는 값 하이 임피던스
신호 강도 서로 다른 강도의 두 신호가 동일한 wire에 흐르면, 더 강한 강도의 신호가 우세 같은 강도의 신호가 동일한 wire에 흐르면, 결과는 x 신호 강도 신호 강도 형 정 도 supply strong pull large weak medium small high-z driving storage Hi - impedance 강도가 높음 강도가 낮음
식별자(Identifier) 식별자(identifier는 설계시 객체들을 참조할 수 있게 하기 위해 객체에 주어진 이름이다. 알파벳, 숫자, 언더바(_), 달러기호($)로 구성 대소문자를 구별 알파벳이나 언더바(_)로 시작될 수 있으며, 숫자나 달러기호($)로 시작될 수 없다. reg value; input clk; 식별자
Module Verilog language는 Digital System을 Module의 집합으로 기술한다. 행위 또는 알고리듬 수준(Behavioral or Algorithmic level) 자세한 하드웨어 구현에 관계없이 원하는 디자인 알고리듬을 바로 사용함으로써 모듈을 구현. C 프로그래밍과 매우 유사. 데이터 플로우 수준(Dataflow level) 데이터의 흐름을 명백히 나타냄으로써 모듈을 구현. 게이트 수준(Gate level) 논리 게이트와 게이트 사이의 연결에 의해 모듈을 구현. 게이트 수준 논리 다이어그램에 의해서 묘사하는 것과 유사. 스위치 수준(Switch level) 추상화의 가장 하위 수준. 스위치와 기억 노드, 그리고 그것들의 연결에 의해서 모듈을 구현. module의 정의는 항상 키워드 “module”로 시작하여 맨 마지막에는 항상 “endmodule”을 쓴다.
Port (1/2) 포트 선언 Verilog Key Word Port의 형 input output inout 입력 포트 포트 리스트의 모든 포트는 모듈 안에서 선언 입력(input) 내부적으로 반드시 net형, 외부적으로 reg 또는 net 변수와 연결 출력(output) 내부적으로 reg 또는 net형, 외부적으로 반드시 net과 연결 입출력(inout) 내부적으로 반드시 net형, 외부적으로 반드시 net과 연결 Verilog Key Word Port의 형 input output inout 입력 포트 출력 포트 양방향 포트
Port (2/2) 예 module fulladd4(sum, c_out, a, b, c_in); // 포트 선언 시작 부분 output [3:0] sum; output c_out; input [3:0] a, b; input c_in; // 포트 선언 끝부분 … <모듈내용> end module
Primitives modules 내에서만 사용 가능 Combinational logic Three State MOS Gates CMOS Bi- Directional Pull and nand or nor xor xnor buf not bufif0 bufif1 notif0 notif1 nmos pmos rnmos rpmos cmos rcmos tran tranif0 tranif1 rtran rtranif0 rtranif1 pullup pulldown
Net 게이트 또는 모듈 사이의 연결을 나타내며 신호가 저장되지 않는다. 네트 값이 변할 때 자동으로 네트에 새로운 값이 전달 크기를 정하는 벡터를 지정하지 않으면 1bit net 형식 범위 : 벡터 혹은 비트로 지정 지연 : Simulation에서 사용 네트 정의의 예 네트 형 [범위] [지연] 네트 이름, …, 네트 이름; wire a; // net a를 정의 wire b, c; // net b, c를 정의 wire d = 1’b0; // net d는 논리값 0으로 선언
레지스터형 [범위] [지연] 레지스터이름, … , 레지스터 이름; Register Data를 저장하기 위한 변수 네트와는 달리 새로운 값이 할당될 때 까지는 현재값을 유지 형식 Register 사용의 예 레지스터형 [범위] [지연] 레지스터이름, … , 레지스터 이름; reg A; // 1 bit 레지스터 A reg [5:0] A, B; // 6 bit 레지스터 A, N integer A; // 32 bit 정수 A integer A, B; // 32 bit 정수 A,B reg reset; initial begin reset = 1’b1; #100 reset = 1’b0; end Register형 reset을 정의 reset을 1로 초기화 100 단위 시간 후 reset값은 0으로 변경
Vector 표현 의 미 busA[7] bus[2:0] virtual_adder[0:1] bus[0:2] 형식 Vector 표현의 예 예약어 [MSB : LSB] 신호 이름; 표현 의 미 busA[7] bus[2:0] virtual_adder[0:1] bus[0:2] 벡터 busA의 7번 bit 벡터 bus의 3개의 하위 bit virtual_adder의 2개의 상위 bit 잘못된 표현 →significant bit는 범위지정에서 항상 왼쪽에 와야 하기 때문
<배열이름> [<서브스크립트>] Array Verilog HDL에서는 reg, integer, time, vector register data형의 배열이 제공 형식 다차원 배열은 제공되지 않음 벡터는 n bit의 폭을 가지는 하나의 원소인 반면, 배열은 1 bit를 가지는 여러 원소 <배열이름> [<서브스크립트>] integer count[0:7]; // 8 count 변수의 배열 reg bool[31:0]; // 32 1bit boolean 레지스터 변수의 배열 time chk_point[1:100]; // 100 time checkpoint 변수의 배열 reg [4:0] port_id[0:7]; // 8 port_id의 배열, 각 port_id는 5bit count[5]; // count 변수 배열의 5번째 원소 chk_point[100]; // check point 값이 100번째 시간 port_id[3]; // port_id 배열의 3번째 원소, 5 bit
Parameter 키워드 Parameter로 Module내서 상수를 정의 변수로 사용할 수 없음 파라미터 사용의 예 parameter port_id = 7 ; parameter cashe_line_width = 256;
연산자(Operator) (1/3) 연산자의 형태와 기호 (1) 형 태 기 호 연 산 자 역 할 형 식 산 술 연산자 + - 형 태 기 호 연 산 자 역 할 형 식 산 술 연산자 + - * / % 덧 셈 뺄 셈 곱하기 나누기 나머지 A + B A - B A * B A / B A % B 관 계 > < >= <= == != 크 다 작 다 크거나 같다 작거나 같다 같 다 다르다 A > B A < B A >= B A <= B A == B A != B
연산자(Operator) (2/3) 연산자의 형태와 기호 (2) 형태 기호 연산자 역할 예 논 리 연산자 && || ! 논 리 연산자 && || ! 논리 and 논리 or 논리 not A && B A || B !A 비 트 ~ & | ^ ^~ or ~^ 비트단위 not 비트단위 and 비트단위 or 비트단위 xor 비트단위 xnor ~A A & B A | B A ^ B A ~^ B)
연산자(Operator) (3/3) 연산자의 형태와 기호(3) 형태 기호 연산자 역할 예 단 항 비 트 연산자 & ~& | 단 항 비 트 연산자 & ~& | ~| ^ ^~ or ~^ 비트단항 and 비트단항 nand 비트단항 or 비트단항 nor 비트단항 xor 비트단항 xnor & (0101) = 0 ~& (0101) = 1 | (0101) = 1 ~| (0101) = 0 ^ (0101) = 0 ~^(1010) = 1 Shift >> << 오른쪽으로 이동 왼쪽으로 이동 0011 >> 1 (결과: 0001) 1100 << 1 (결과: 1000) 그밖의 연산자 {} {{}} ?: 결합 연산자 중복 연산자 조건 연산자 { A, B } { {A} } A ? B : C
산술 연산자 덧셈, 뺄셈, 곱셈, 나눗셈, 나머지 연산자 이항 연산자는 2개의 피연산자를 가짐 피연산자의 어떤 비트가 x값이면, 전체 결과는 x +, - 연산자는 단항연산자 처럼 쓰여, 피연산자의 부호를 나타내는데 사용되기도 한다. 산술 연산자의 사용 예 A = 4’b0011; B = 4’b0100; C = 4’b101x; A + B // 결과값은 4’b0111 A – B // 결과값은 4’b0001 A * B // 결과값은 4’b100 A / B // 결과값은 1, 나머지는 버림 13 % 3 // 결과값은 1 -5 // 음수 5를 나타냄 +5 // 양수 5를 나타냄
관계 연산자 수식 안에서 사용될때, 수식의 결과가 참이면 논리값 1(참)을, 거짓이면 논리값 0(거짓)을 되돌린다. 수식 안에서 사용될때, 수식의 결과가 참이면 논리값 1(참)을, 거짓이면 논리값 0(거짓)을 되돌린다. 수식의 피연산자 중 ‘x’나 ‘z’값을 가진다면, 결과로 ‘x’값을 되돌린다. 2개의 피연산자들을 비트별로 비교하며, 두 피연산자의 길이가 다를 때는 길이가 짧은 피연산자의 앞에 0을 채운다. 관계 연산자 사용의 예 A = 7; B = 5; X = 4’b1010; Y = 4’b1101; Z = 4’b1xxx; A <= B // 결과값은 0 (거짓) A > B // 결과값은 1 (참) Y >= X // 결과값은 1 (참) Y < Z // 결과값은 x A == B // 결과값은 0 (거짓) X != B // 결과값은 1 (참)
논리 연산자 항상 1 bit의 결과를 생성 ‘0’은 거짓, ‘1’은 참을 나타내며, ‘x’는 결과가 참도 거짓도 아닌 경우 피연산자가 ‘0’이 아닌경우 항상 참(1)으로 인식 논리 연산자는 변수 또는 수식을 피연산자로 취함 논리 연산자 사용의 예 A = 3; B = 0; C = 2’b0x; D = 2’b01; A && B // 결과값은 0 ( ‘ 논리 1 && 논리 0 ’을 계산 ) A || B // 결과값은 1 ( ‘ 논리 1 || 논리 0 ’을 계산 ) !A // 결과값은 0 ( ‘ not (논리 1) ’을 계산 ) !B // 결과값은 1 ( ‘ not (논리 0) ’을 계산 ) C && B // 결과값은 x ( ‘ x && 논리 1 ’을 계산 ) (a==2) && (b==3) // (a==2)와 (b==3)이 모두 참이면 결과값은 1 // 둘중에 하나라도 거짓이면 결과값은 0
비트 연산자 피연산자를 비트 단위로 연산 비트 연산자 사용의 예 비트 연산자와 논리 연산자의 비교 X = 4’b1010; Y = 4’b1101; Z = 4’bb10x1 ~X // 결과값은 4’b0101 X & Y // 결과값은 4’b1000 X | Y // 결과값은 4’b1111 X ^ Y // 결과값은 4’b0111 X ^~ Y // 결과값은 4’b1000 X & Z // 결과값은 4’b10x0 X = 4’b1010; Y = 4’b0000 X | Y // 비트 연산, 결과값은 4’b1010 X || Y // 논리 연산, 결과값은 1 ( ‘1 || 0’ 을 계산 )
단항 비트 연산자 한 개의 피연산자만을 가짐 피연산자의 오른쪽 비트에서부터 왼쪽 비트까지 비트별로 연산 단항 비트 연산자 사용의 예 단항 비트 연산자 ‘xor’나 ‘xnor’는 벡터의 짝수/홀수 패리티 확인에 사용되기도 한다. X = 4’b1010; &X // 결과값은 1’b0 ( ‘1 & 0 & 1 & 0’을 계산 ) |X // 결과값은 1’b1 ( ‘1 | 0 | 1 | 0’을 계산 ) ^X // 결과값은 1’b0 ( ‘1 ^ 0 ^ 1 ^ 0’을 계산 )
기타 연산자 Shift 연산자 결합 연산자 주어진 값만큼 오른쪽 혹은 왼쪽으로 자리 이동 비워진 자리는 0으로 채워짐 여러 개의 피연산자들을 한데 묶음 결합 연산자 사용의 예 X = 4’b1100; Y = X >>1; // 오른쪽으로 1 bit 자리 이동, Y = 4’b0110 Y = X <<2; // 왼쪽으로 2 bit 자리 이동, Y = 4’b0000 A = 1’b1; B = 2’b00; C = 2b’10; Y = { A, B, C, 3’b001 } // Y = 8’b10010001 Y = { A, B[0], C[1] } // Y = 3’b101
기타 연산자 반복 연산자 조건 연산자 같은 숫자들의 결합을 주어진 값만큼 반복 반복 연산자 사용의 예 형식 조건 연산자 사용의 예 A = 1’b1; B = 2’b00; Y = { 4{A}, 2{B}} // Y = 8’b11110000 조건식 ? 참 조건시 수식 : 거짓 조건시 수식; assign out = control ? in1 : in0; // 2:1 mux의 기능적 모델
연산자 우선 순위 연산자의 우선 순위표 우선순위 연 산 자 설 명 높음 낮음 +, -, !, ~ *, /, % 단항 연산자 연 산 자 설 명 높음 낮음 +, -, !, ~ *, /, % 단항 연산자 곱셈, 나눗셈, 나머지 +, -, <<, >> 덧셈, 뺄셈, shift <, <=, >, >= ==, !=, ===, !== 관계 연산자 등가 연산자 &, ~&, ^, ^~, |, ~| &&, || 단항 비트 연산자 논리연산자 ? : 조건 연산자
Verilog HDL 구문 구성 요소 Block Always문 Initial문 If문 Case문 For문 Repeat문 While문 Forever문 Function문 Blocking Assignment Non-blocking Assignment
Block 문 (statement) Block 문 형식 ‘ assign A = B; ’와 같이 세미콜론(;)으로 구분한 것을 의미 내부에 여러 개의 문을 쓰려면 블록문을 사용 Block 문 여러 개의 문(statement)을 하나의 문으로 취급 기술된 내용을 보기 편함 형식 이름있는 블록안에서는 지역변수선언 가능 이름없는 블록안에서는 지역변수 선언 불가능 begin : 블록 이름 reg 지역변수; integer 지역변수; parameter 지역변수; … 문장 … end 블록 이름은 생략가능 지역변수는 필요한 경우에만 선언 begin과 end에는 세미콜론(;)이 없다!
always 문 (1/3) @이벤트 신호의 값들 중 하나라도 변화하면, 쓰여진 문장 순서대로 처리되며, 마지막 문장까지 실행이 끝나면 처음으로 돌아가서, 다음의 이벤트 신호가 변화될 때까지 기다린다. always문의 예 always @ (이벤트·신호 or … or 이벤트·신호) begin 순차적인 assign문 if, case 문 등 loop, function, task call 등 end 계속해서 순차적으로 실행 블록문이 없는 경우는 한 문장만 실행
always 문 (2/3) 조합회로에서 사용시 주의점 순차회로에서 사용시 주의점 여러 개의 always문을 사용할 수 있다 조합회로에 공급되는 모든 신호는 “@(이벤트 ·신호)”내에 있어야 한다. always의 동작은 일종의 레지스터로 생각하기 때문에 블록에서 할당된 신호들은 반드시 reg 혹은 integer로 선언되어야 한다. 블록킹 대입문(=)을 사용하지 않고, 논·블록킹 대입문(<=)을 사용하여야 한다. 순차회로에서 사용시 주의점 “@(이벤트 ·신호)”없이 사용할 경우 블록 내에 이벤트를 일으키는 식이 포함되어 있어야 한다. 벡터의 비트(Q[2])는 사용할 수 없다. 여러 개의 always문을 사용할 수 있다
always 문 (3/3) always문을 이용한 2×1 멀티플렉서 설계 module MUX (A, B, SEL, Y); //모듈선언 input A, B, SEL; //입력정의 output Y; //출력정의 reg Y; //always블록에서 Y값을 할당하기 때문에 Y를 reg로 다시 선언 //always블록 always @(A or B or SEL) // 모든 입력은 이벤트 신호에 포함 begin if (SEL) Y <= A; //SEL=1이면 Y=A else Y <= B; //SEL=0이면 Y=B end endmodule
initial 문 블록으로 설정된 부분을 순차적으로 한번 실행 시뮬레이션 할 때만 사용(합성되지 않음) initial문의 예 순서대로 한번만 실행 블록문이 없는 경우는 한 문장만 실행 initial begin “assign”문 조건처리문 if, case 문 등 end
if 문 (1/3) 조건이 참(true)이면 if문 다음의 문장을 실행하고, 그렇지 않으면 (거짓 : false) else문 다음의 문장을 실행 형식 if (조건식) 문장1; // <조건식>이 참이면 실행 else /* 이 이하는 생략 가능하지만 조합회로에서 생략하면 불필요한 래치가 만들어짐*/ 문장2; // <조건식>이 거짓이면 실행 if (조건식) begin … 문장 … ; // <조건식>이 참이면 블록을 실행 end else … 문장 … ; // <조건식>이 거짓이면 블록을 실행
if 문 (2/3) if 문을 이용한 3x8 Decoder의 설계 module DECODER(A, Y); input [2:0] A ; // 3 bit input output [7:0] Y ; // 8 bit output assign Y = FUNC_DEC (A) ; // function을 call, return 값을 Y로 출력 /* decoder function, return 값은 func_DEC 8 bit */ function [7:0] FUNC_DEC ; input [2:0] A ; // 3 bit input if (A == 3’b000) // A가 “000”인 경우 FUNC_DEC = 8’b0000_0001; else if ( A == 3’b001) // A가 “001”인 경우 FUNC_DEC = 8’b0000_0010;
if 문 (3/3) else if ( A == 3’b010) // A가 “010”인 경우 FUNC_DEC = 8’b0000_0100; else if ( A == 3’b011) // A가 “011”인 경우 FUNC_DEC = 8’b0000_1000; else if ( A == 3’b100) // A가 “100”인 경우 FUNC_DEC = 8’b0001_0000; else if ( A == 3’b101) // A가 “101”인 경우 FUNC_DEC = 8’b0010_0000; else if ( A == 3’b110) // A가 “110”인 경우 FUNC_DEC = 8’b0100_0000; else if ( A == 3’b111) // A가 “111”인 경우 FUNC_DEC = 8’b1000_0000; else // 조건이 맞는 경우가 없을 경우 FUNC_DEC = 8’b0000_0000; endfunction // function문 끝 endmodule
case 문 (1/3) 논리식의 값에 따라서 실행할 문장을 선택 형식 casex, casez : don’t care condition 사용가능 case (판정식) 항1 : 처리문1 ; // 판정식이 항1과 같으면, 처리문1을 실행 항2 : 처리문2 ; // 판정식이 항2와 같으면, 처리문2을 실행 : 항N : 처리문N ; // 판정식이 항N과 같으면, 처리문N을 실행 default : 처리문 N+1 ; // 판정식이 항N까지 일치하지 않으면 // 처리문 N+1을 실행 endcase
case 문 (2/3) case 문을 이용한 3x8 Decoder의 설계 module DECODER(A, Y); input [2:0] A ; // 3 bit input output [7:0] Y ; // 8 bit output assign Y = FUNC_DEC (A) ; // function을 call, return 값을 Y로 출력 /* decoder function, return 값은 func_DEC 8 bit */ function [7:0] FUNC_DEC ; input [2:0] A ; // 3 bit input case (A) 0 : FUNC_DEC = 8’b0000_0001 ; // A가 “000”인 경우 1 : FUNC_DEC = 8’b0000_0010 ; // A가 “001”인 경우 2 : FUNC_DEC = 8’b0000_0100 ; // A가 “010”인 경우 3 : FUNC_DEC = 8’b0000_1000 ; // A가 “011”인 경우
case 문 (3/3) 4 : FUNC_DEC = 8’b0001_0000 ; // A가 “100”인 경우 // 조건이 모두 나열되었으므로 default항은 없어도 된다. default : FUNC_DEC = 8’b0000_0000 ; // A가 일치되는 값이 없을 경우 endcase // case문 끝 endfunction // function문 끝 endmodule
for 문 한 문장 또는 문장 블록을 조건식에서 지정한 만큼 반복 loop commands(for, repeat, while, forever)는 기본적으로 순차회로(always문, initial문) 내에서만 사용 형식 for 문에서 사용하는 index는 integer로 선언 되어야 한다. for 루프의 예 for (초기값 ; 조건식 ; 오퍼레이션) 처리문 or 블록 처리문 integer count; initial for (count = 0; count <128; count = count +1) $display(“count = %d”, count); // 0에서부터 127까지 증가시키고 출력
repeat 문 정해진 횟수만큼 루프를 수행 형식 repeat 루프의 예 repeat ( 상수 or 상수로 정의된 변수 ) integer count; initial begin count = 0; repeat(128) // 0에서 부터 127까지 증가시키고 출력 $display(“count = %d”, count); count = count +1; end
while 문 while-수식이 거짓이 될 때까지 계속 수행 형식 while 루프의 예 while ( 조건문 ) integer count; initial begin count = 0; while (count < 128) $display(“count = %d”, count); count = count +1; end count가 127이 될때까지 루프를 수행 count 가 128일때 종료
forever 문 $finish task를 만날 때까지 계속 루프가 수행 즉, 항상 참 값을 갖는 while 루프와 동일 일반적으로 타이밍 제어 구조와 같이 쓰임 형식 while 루프의 예 forever 문장 ; // clock 생성, always 블록 대신에 forever 루프를 사용 reg clock; initial begin clock = 1’b0; forever #10 clock = ~clock; // 20 단위의 주기를 가진 clock end
function 문 (1/2) function내의 처리문에서 둘이상의 문장을 사용하려면 ‘ begin ~ end ’ 블록으로 둘러싸야함 function내에 선언된 지역변수는 일시적인 것으로 취급되며 wire로합성 function의 정의는 module 안에서 이루어져야 하며 타이밍을 정의하는 문장 포함 불가 function은 task를 사용할 수 없는 반면, task에서는 function사용 가능 함수 선언 형식 함수 호출 형식 function [범위] 함수이름 함수 선언문 처리문 end function function의 return 값은 범위를 지정하지 않으면 1 bit로 return return 값은 함수이름으로 return 네트 = function 이름 ( 인수이름, … , 인수이름 )
function 문 (2/2) 함수 예제 module parity; 함수 calc_parity를 포함한 모듈 정의 … reg [31:0] addr; reg parity; always @(addr) begin parity = calc_parity(addr); $display(“Parity calculated = %d”, calc_parity(addr) ); end function calc_parity; input [31:0] address; cal_parity = ^address; end function endmodule 함수 calc_parity를 포함한 모듈 정의 주소값이 변할 때마다 새로운 parity를 계산 calc_parity의 첫번째 호출 calc_parity의 두번째 호출 parity 계산 함수 정의 모든 주소 비트의 xor를 되돌린다
Blocking Assignments 하나의 대입이 끝나고 나서 다음을 대입한다. 기술된 순서에 따라 회로동작이 다르기 때문에 순차 회로에는 부적합 초기값 A=5; B=3; C=10; D=2; 실행 순서 wire [3:0] A, B, C, D; always @(posedge CLK) begin C=B; B=A; A=D; end 결과값 A=2; B=5; C=3; D=2; A=2; B=2; C=3; D=2; (A=D의 결과가 B=A에 영향)
Non Blocking Assignments always문 블록내의 대입식에서 오른쪽 처리가 완전히 끝나고, 일제히 왼쪽에 대입 기술된 순서와 무관하게 회로동작이 되므로 순차회로에 적합 초기값 A=5; B=3; C=10; D=2; 실행 순서 wire [3:0] A, B, C, D; always @(posedge CLK) begin C<=B; B<=A; A<=D; end 결과값 A=2; B=5; C=3; D=2;
System Task (1/7) Verilog에서는 routine연산을 하기 위한 표준 system task가 제공 형식 C언어의 printf 와 매우 유사 $display(p1, p2, p3, … , pn); // p1, p2, … , pn은 문자열, 변수, 수식
System Task (2/7) 화면출력 task 문자열 포맷 포 맷 출 력 %d or %D %b or %B %s or %S 포 맷 출 력 %d or %D %b or %B %s or %S %h or %H %c or %C %m or %M %v or %V %o or %O %t or %T %e or %E %f or %F %g or %G 10진수로 변수를 출력 2진수를 변수로 출력 문자열을 출력 16진수로 변수를 출력 ASCII 문자를 출력 계층 이름을 출력(인자가필요하지 않다) 강도를 출력 8진수로 변수를 출력 현재 시간 포맷으로 출력 실수를 과학적 표기법으로 출력 (예 3e10) 실수를 십진 표기법으로 출력 (예 2.13) 실수를 과학적 표기법과 십진 표기법 중 짧은 것으로 출력
System Task (3/7) 모니터링 task 신호의 값이 변할 때만다 그 신호를 출력하기 위한 task 형식 한 개 이상의 $monitor 문장이 시뮬레이션에 존재하면, 마지막 $monitor 문장만 수행 모니터링을 on, off하기 위한 task 시뮬레이션을 시작할 때는 기본적으로 모니터링이 on 상태 $monitor(p1, p2, p3, … , pn); // p1, p2, … , pn은 변수, 신호이름, 문자열 $monitoron; $monitoroff;
System Task (4/7) 시뮬레이션 중단 task 시뮬레이션 종료 task 형식 상호작용 모의 시뮬레이션에서 사용 설계자가 시뮬레이션 중단을 원하거나 신호의 값을 조사하고자 할 때마다 사용 시뮬레이션 종료 task 시뮬레이션을 끝내기 위한 task $stop; $finish;
System Task (5/7) 시뮬레이션 시간을 return하는 task 구 분 형 식 형식 구 분 형 식 현재의 시뮬레이션 시간(64 bit)을 return $time; 현재의 시뮬레이션 시간(32 bit)을 return $stime; 실수로 return $realtime; 난수를 32 bit 부호 있는 정수로 return $random;
System Task (6/7) file 열기 task file 쓰기 task 멀티채널디스크립터(multichannel descriptor)라 불리는 32 bit값을 반환 형식 file 쓰기 task $fdisplay, $fmonitor, $fwrite, $fstrobe를 사용 $fopen(“<fine_name>”); $<file_handle> = $fopen(“<file_name>”); $fdisplay(<file_descriptor>, p1, p2, … , pn); $fmonitor(<file_descriptor>, p1, p2, … , pn); // p1, p2, … , pn은 변수, 신호명, 인용된 문자열
System Task (7/7) file 닫기 task file이 한번 닫히면 그 파일에는 쓸 수 없다. 멀티채널 디스크립터(multichannel descriptor) 안에서 대응되는 bit는 0으로 set되며, 그 다음번 $fopen 호출이 그 bit를 재 사용할 수 있다. 형식 $fclose(“<fine_handle>”);
Test Bench 설계하고자 하는 Block이 완성되면 검증을 위해 Simulation이 필요하다. 이를 위해 설계 Block에 입력을 넣어주고 출력을 받을 Stimulus Block이 추가적으로 필요하다. Stimulus Block은 일반적으로 Test Bench라 불리며 설계 Block의 검증할 입력 값들을 포함하고 있다. Test Bench는 initial문 등 합성이 불가능한 요소를 포함하므로 설계 Block과는 다른 File로 저장 관리하는 것이 좋다.
Test Bench Example 1 – Adder (1/4) Test Bench Block은 Simulation이 시작되면 설계 Block으로 Stimulus를 인가한다. 설계 Block에서 계산된 결과가 Test Bench로 다시 입력된다.
Test Bench Example 1 – Adder (2/4) 4 Bit Adder 설계 Block 4 Bit 입력 input_1과 input_2를 입력 받아 값을 더한 후 out으로 출력한다. Adder.v module adder(input_1,input_2,out); input [3:0] input_1, input_2; output [3:0] out; assign out = input_1 + input_2; endmodule
Test Bench Example 1 – Adder (3/4) Adder_stim.v module adder_stim; reg [3:0] input_1, input_2; wire [3:0] out; adder adder_1(input_1,input_2,out); initial begin input_1 = 4'D3; input_2 = 4'D3; #100; input_1 = 4'D6; input_2 = 4'D9; #100; input_1 = 4'D4; input_2 = 4'D0; #100; input_1 = 4'D2; input_2 = 4'D5; #100; $finish; end endmodule Test Bench는 일반적으로 In/Out Port를 갖지 않는다. 설계 Block의 instance를 포함한다. 시간에 따라 원하는 Stimulus를 입력한다. Simulation을 종료한다.
Test Bench Example 1 – Adder (4/4) Adder_stim.v의 adder_stim Test Bench Module에서 나온 input_1, input_2의 값들은 Adder.v의 adder Module로 들어가며 계산된 결과는 다시 adder_stim Module의 out을 통해서 확인 할 수 있다.