[System Verilog] Overview – 1 introduction, data type

시스템 베릴로그(System Verilog)는 기존에 하드웨어의 동작을 기술함으로써 반도체 설계에 사용되는 HDL(Hardware Description Language)인 Verilog를 확장 언어로, 검증(verification)에 최적화된 HDVL(Hardware Design and Verification Language)입니다.

System Verilog Introduction

System verilog VS Verilog

HDL로 반도체 설계가 끝나면 더 이상 업데이트를 할 수 없기 때문에 세세한 검증이 필요합니다. 기존에 사용하던 Verilog로도 검증을 할 수 있지만, 디자인이 복잡해짐에 따라 검증에 특화된 환경이 필요했습니다. System Verilog는 기존 HDL 대비 다음과 같은 차이가 있습니다.

  • Random stimuli 생성 가능 -> 검증에 용이
  • OOP(Object Oriented Programming) 기반, 체계적이고 reusable coding 가능
  • Concurrency features (ex: fork – join)
  • Assertion feature

System Verilog 구조

DUT(Design Under Test)를 포함한 System Verilog testbench의 기본적인 구조는 다음과 같습니다.

글 설명 이미지, System verilog 구조
System Verilog testbench structure
  • Generator: DUT를 구동할 다양한 입력 stimulus를 생성(랜덤 변수 제공)
  • Driver: 생성된 신호를 DUT에 전송
  • Interface: 생성된 신호와 DUT로부터 monitor 할 신호 연결 정의
  • Monitor: DUT에서 나오는 신호를 확인
  • Scoreboard: DUT의 출력을 예상하는 결과와 비교하여 검증
  • Environment: 위에 언급된 모든 component를 인스턴스화하여 포함
  • Test: Testcase 별로 설정을 조정하여 test 환경 구성

System Verilog data type

Data type(System Verilog VS Verilog)
Data type

logic

Verilog에서 주로 사용하는 자료형은 wire와 reg가 있었고, 각각 연속 할당(assign)과 절차 할당(initial 문, always 문)을 사용했습니다. System Verilog의 logic은 연속 할당, 절차 할당, module의 port 선언에 모두 사용될 수 있습니다.

module top();
  
  logic [3:0] data;
  logic       enable;
  
  initial begin
    $display ("data = 0x%0h, en = %0b", data, enable);
    data = 4'ha;
    $display ("data = 0x%0h, en = %0b", data, enable);
    #10;
    $display ("data = 0x%0h, en = %0b", data, enable);
  end
  
  assign enable = data[0];
  
endmodule

>> data = 0xx, en = x
>> data = 0xa, en = x
>> data = 0xa, en = 0

bit

일반적으로 Verilog의 testbench에서는 x(unknown), z(high impedance) signal을 module의 input port에 가하지 않기 때문에 4-state data가 필요 없습니다. bit는 System Verilog의 2-state data로 주로 testbench에서 사용됩니다. bit를 사용함으로써 simulation time과 memory 사용을 최적화할 수 있습니다.

만약, bit에 x나 z가 할당되면 0으로 변환됩니다.

shortint, int, longint

integer는 정수형 signed data로, data size에 따라 shortint, int, longint로 사용할 수 있습니다.

module top();
  
  shortint int_1;
  int      int_2;
  longint  int_3;
  
  initial begin
    $display("#####################");
    int_1 = 64'hFFFF_FFFF_FFFF_FFFF;
    int_2 = 64'hFFFF_FFFF_FFFF_FFFF;
    int_3 = 64'hFFFF_FFFF_FFFF_FFFF;
    
    $display("short int = 0x%0h", int_1);
    $display("int       = 0x%0h", int_2);
    $display("long int  = 0x%0h", int_3);
    $display("#####################");
    $display("#####################");
    
    #10
    int_1 = 16'h7FFF;
    int_2 = 32'h7FFF_FFFF;
    int_3 = 64'h7FFF_FFFF_FFFF_FFFF;
    
    $display("short int = %0d", int_1);
    $display("int       = %0d", int_2);
    $display("long int  = %0d", int_3);
    $display("#####################");
    $display("#####################");
    
    #10
    int_1 += 1;
    int_2 += 1;
    int_3 += 1;
    
    $display("short int = %0d", int_1);
    $display("int       = %0d", int_2);
    $display("long int  = %0d", int_3);
    $display("#####################");
    $display("#####################");
  end
  
endmodule

Simulation 결과는 다음과 같습니다.

Simulation result
Simulation result

int data를 unsigned로 설정하면 정수 범위가 달라집니다.

module top();
  
  shortint unsigned int_1;
  int      unsigned int_2;
  longint  unsigned int_3;
  
  initial begin
    $display("#####################");
    int_1 = 16'hFFFF;
    int_2 = 32'hFFFF_FFFF;
    int_3 = 64'hFFFF_FFFF_FFFF_FFFF;
    
    $display("short int = %0d", int_1);
    $display("int       = %0d", int_2);
    $display("long int  = %0d", int_3);
    $display("#####################");
    #10
    $display("#####################");
    int_1 += 1;
    int_2 += 1;
    int_3 += 1;
    
    $display("short int = %0d", int_1);
    $display("int       = %0d", int_2);
    $display("long int  = %0d", int_3);
    $display("#####################");
    $display("#####################");
  end
  
endmodule

Simulation 결과는 다음과 같습니다.

Simulation result
Simulation result

byte

byte는 int type보다 더 짧은 data size일 때 사용하며, int와 마찬가지로 signed와 unsigned로 설정할 수 있습니다.

unsigned byte 범위: 0 ~ 255

signed byte 범위: -128 ~ 127

String

String은 System Verilog에서 새롭게 나온 data type으로, ordered collection of characters입니다.

MethodDefinitionComments
str.len()function int len()Returns the number of characters in the string
str.putc()function void putc (int i, byte c);Replaces the ith character in the string with the given character
str.getc()function byte getc (int i);Returns the ASCII code of the ith character in str
str.tolower()function string tolower();Returns a string with characters in str converted to lowercase
str.compare(s)function int compare (string s);Compares str and s, as in the ANSI C strcmp function
str.icompare(s)function int icompare (string s);Compares str and s, like the ANSI C strcmp function
str.substr (i, j)function string substr (int i, int j);Returns a new string that is a substring formed by characters in position i through j of str
String method
module top();
  
  string string_1;
  
  initial begin
    $display("%s", string_1);
    
    string_1 = "HelloW";
    $display("%s", string_1);
    
    foreach(string_1[i])
      $display("%s", string_1[i]);
    
    $display("Length = %0d", string_1.len());
    string_1.putc(0,"O");
    $display("Replace(0,O) = %s", string_1);
    $display("Getting character(5) = %s", string_1.getc(5));
    $display("Lower character = %s", string_1.tolower());
  end
  
endmodule

간단한 예시의 결과만 보고 넘어가겠습니다.

Simulation result
Simulation result

Enumeration

Enumeration(enum)은 열거형으로, 특정한 상수 값을 정의하는 데 사용되는 data type입니다. enum은 이름을 숫자로 시작할 수 없다는 특징이 있습니다. 또한 enum의 기본 type은 int이며 첫번째 변수의 기본값은 0으로 시작합니다.

enum 각각의 data는 값을 직접 지정해 줄 수 있고, 지정하지 않는다면 이전 data 값에서 1 증가한 값을 가집니다. 또한, 한 enum에 포함된 data 같은 값을 가지면 안 됩니다.

//enum           {Red0, Green0, Blue0} colors_0; //int type
//enum bit [1:0] {Red1, Green1, Blue1} colors_1; //bit type
module top();
  
  enum bit [1:0] {Red0, Green0, Blue0}         colors_0;
  enum           {Red1 = 3, Green1, Blue1}     colors_1;
  enum           {Red2 = 3, Green2, Blue2 = 9} colors_2;
  
  initial begin
    $display("color_0 = {Red0(%0d), Green0(%0d), Blue0(%0d)}", Red0, Green0, Blue0);
    $display("color_1 = {Red1(%0d), Green1(%0d), Blue1(%0d)}", Red1, Green1, Blue1);
    $display("color_2 = {Red2(%0d), Green2(%0d), Blue2(%0d)}", Red2, Green2, Blue2);
  end
  
endmodule

Simulation 결과는 다음과 같습니다.

Simulation result
Simulation result
MethodDefinitionComments
first()function enum first();Returns the value of the first member of the enumeration
last()function enum last();Returns the value of the last member of the enumeration
next()function enum next (int unsigned N = 1);Returns the Nth next enumeration value starting from the current value of the given variable
prev()function enum prev (int unsigned N = 1);Returns the Nth previous enumeration value starting from the current value of the given variable
num()function int num();Returns the number of elements in the given enumeration
name()function string name();Returns the string representation of the given enumeration value
Enum method

Array

Array는 동일한 type data들의 집합입니다. System Verilog에서 array는 크게 packed array와 unpacked array로, unpacked array는 다시 Static array, Dynamic array, Associative array, 그리고 Queue로 구분됩니다.

Packed/Unpacked array의 구분은 array의 dimension 선언이 array 이름 앞에 있느냐 뒤에 있느냐에 따라 결정됩니다.

  bit [3:0] packed_array; //(= vector)
  bit       unpacked_array [3:0];

Packed array

Packed array는 bit 들의 연속적인 집합으로, bit 별로 값을 할당할 수도 있고 한꺼번에 할당할 수도 있습니다.

module top();
  
  bit [3:0] data;
  
  initial begin
    data[3] = 1'b0;
    data[2] = 1'b1;
    data[1] = 1'b0;
    data[0] = 1'b1;
    
    $display("data = %b", data);
    
    data = 4'hc;
    
    foreach (data[i]) begin
      $display("data[%0d] = %0b", i, data[i]);
    end
  end
  
endmodule

>> data = 0101

>> data[3] = 1
>> data[2] = 1
>> data[1] = 0
>> data[0] = 0

또한, packed array를 multi-dimension으로 정의할 수 있습니다.

module top();
  
  bit [3:0] [7:0] data;
  
  initial begin
    data[3] = 8'hDE;
    data[2] = 8'hAD;
    data[1] = 8'hCA;
    data[0] = 8'hFE;
    
    $display("data = 0x%0h", data);
  end
  
endmodule

>> data = 0xdeadcafe

Unpacked array

Unpacked array는 모든 data type으로 정의될 수 있으며 array_name 뒤에 size를 정의합니다.

  bit [7:0] Array[2:0]

위의 Array를 그림으로 확인해볼까요?

Unpacked array
Unpacked array
Static array

Fixed-sized array 라고도 하는 Static array는 array_name 뒤에 있는 dimension의 값이 정해져 있는 array입니다.

Dynamic array

Dynamic array는 simulation run time 중에 array size가 정해지거나 변경될 수 있는 array입니다. Size의 default value는 0입니다.

//[data_type] [array_name] [];
module top();
  
  int array [];
  
  initial begin
    array = new[5];
    array = '{91, 38, 64, 71, 25};
    
    foreach(array[i]) begin
      $display("array[%0d] = %0d", i, array[i]);
    end
  end
  
endmodule

>> array[0] = 91
>> array[1] = 38
>> array[2] = 64
>> array[3] = 71
>> array[4] = 25

FunctionDescription
function int size ();Returns the current size of the array, 0 if array has not been created
function void delete ();Empties the array resulting in a zero-sized array
Dynamic array method
Associative array

앞에서 설명한 dynamic array는 size를 조절할 수 있고, 인덱스가 0부터 시작해서 1씩 늘어납니다. 만약 이 저장소에 값이 띄엄띄엄 채워져 있다면 이러한 인덱싱은 불필요한 공간을 만들고, 이는 resource 사용에 제한을 줄 겁니다.

Associative array는 실제 data가 입력되기 전까지 array size가 정의되지 않습니다. 그리고 인덱싱 type을 숫자가 아니라 직접 지정할 수 있어, key로 array의 data를 찾습니다. 그래서 simulation 속도는 느리지만 memory 성능이 강화된다는 장점이 있습니다.

Associative array declare
Associative array declare

예시를 한 번 볼까요?

//[data_type] [array_name] [index_type];
module tb();

  int array_1[int];
  bit array_2[string];
  
  initial begin
    array_1[5] = 10;
    array_1[8] = 20;
        
    array_2["True"]  = 1;
    array_2["False"] = 0;
       
    foreach(array_1[i]) 
      $display("array_1[%0d] = %0d",i,array_1[i]);
    
    foreach(array_2[i]) 
      $display("array_2[%s]  = %0d",i,array_2[i]);
  end
  
endmodule

Simulation 결과는 다음과 같습니다.

Simulation result
Simulation result
MethodDescription
num()returns the number of entries in the associative array
delete(index)removes the entry at the specified index.exa_array.delete(index)
exists(index)returns 1 if an element exists at the specified index else returns 0
first(var)assigns the value of first index to the variable var
last(var)assigns the value of last index to the variable var
next(var)assigns the value of next index to the variable var
prev(var)assigns the value of previous index to the variable var
Associative array method
Queue

Queue는 FIFO(First-In-First-Out) 방식으로 작동하여, System Verilog의 array 중 데이터의 삽입과 삭제가 용이한 data type입니다.

Unbounded queue
Unbounded queue

Queue는 선언 방식에 따라 bounded queue와 unbounded queue로 나뉩니다. Bounded queue는 선언될 때 depth가 정해져서, 그 이상의 데이터가 input 되면 FIFO 방식으로 가장 먼저 들어온 데이터가 삭제됩니다.

//[data_type] [queue_name] [$:N]; Bounded queue
//[data_type] [queue_name] [$]; Unbounded queue
module tb();
  
  string fruits_1[$];   //Unbounded
  string fruits_2[$:1]; //Bounded
  
  initial begin
    $display("fruits_1 = %p", fruits_1);
    $display("fruits_2 = %p", fruits_2);
    $display("#######################");
    
    fruits_1.push_front("apple1");
    fruits_2.push_front("apple2");
    
    $display("fruits_1 = %p", fruits_1);
    $display("fruits_2 = %p", fruits_2);
    $display("#######################");
    
    fruits_1.push_front("banana1");
    fruits_2.push_front("banana2");
    
    $display("fruits_1 = %p", fruits_1);
    $display("fruits_2 = %p", fruits_2);
    $display("#######################");
        
    fruits_1.push_front("kiwi1");
    fruits_2.push_front("kiwi2");
    
    $display("fruits_1 = %p", fruits_1);
    $display("fruits_2 = %p", fruits_2);
    $display("#######################");
  end
  
endmodule

Simulation 결과는 다음과 같습니다.

Simulation result
Simulation result
MethodDescription
size()returns the number of items in the queue
insert()inserts the given item at the specified index position
delete()deletes the item at the specified index position
push_front()inserts the given element at the front of the queue
push_back()inserts the given element at the end of the queue
pop_front()removes and returns the first element of the queue
pop_back()removes and returns the last element of the queue
Queue Methods

Structure

System Verilog의 structure는 동일한 type의 집합인 array와 달리 여러 type의 data 집합입니다. Structure는 유저가 세팅하지 않는 이상, 기본적으로 unpacked structure type입니다.

Unpacked structure

//struct {
//  [list of variables]
//} struct_name;

module top();
  
  struct {
    string fruit;
    int    count;
    byte   expiry;
  } st_fruit;
  
  initial begin
    st_fruit = '{"apple", 4, 15};
    
    $display("st_fruit = %p", st_fruit);
    
    st_fruit.fruit = "pineapple";
    st_fruit.expiry = 7;
    
    $display("st_fruit = %p", st_fruit);
  end
  
endmodule

Simulation 결과는 다음과 같습니다.

Simulation result
Simulation result

위의 예시에서는 하나의 structure만 나왔는데요, 동일한 구조의 structure가 여러 개가 필요하다면 어떻게 해야 할까요?? 하나씩 일일이 선언해야 할까요? “typedef struct”를 통해 불필요한 structure 선언을 줄일 수 있습니다.

module top();
  
  typedef struct {
    string fruit;
    int    count;
    byte   expiry;
  } st_fruit;
  
  initial begin
    st_fruit fruit1 = '{"apple", 4, 15};
    st_fruit fruit2;
    
    $display("fruit1 = %p, fruit2 = %p", fruit1, fruit2);
    
    fruit2 = fruit1;
    $display("fruit1 = %p, fruit2 = %p", fruit1, fruit2);
    
    fruit1.fruit = "pineapple";
    fruit1.expiry = 23;
    
    $display("fruit1 = %p, fruit2 = %p", fruit1, fruit2);
  end
  
endmodule

typedef struct는 module 안에 선언해도 되고, 밖에 선언해도 됩니다.

Simulation result
Simulation result

Packed structure

Structure를 packed로 선언할 수도 있습니다, packed라고 하니까 당연히 bit 들의 집합이 되겠죠?

typedef struct packed {
  bit [7:0] byte_user;
  bit       bit_user;
  bit       en;
} packed_struct_ex;

User-defined Data Type

앞에서 나온 data type은 특정 조건을 추가할 수 있습니다. 이와 같이 data type의 조건이 많아질 경우, typedef를 통해 간편하게 만들 수 있습니다.

//typedef data_type type_name
module top();
  
  typedef shortint unsigned u_shorti;
  typedef enum {RED, YELLOW, GREEN} e_light;
  typedef bit [7:0] ubyte;
  
  initial begin
    u_shorti data = 16'hCAFE;
    e_light  light = GREEN;
    ubyte    cnt = 8'h5a;
    
    $display("light = %s, data = 0x%0h, cnt = %0d", light.name(), data, cnt);
  end
  
endmodule

Simulation 결과는 다음과 같습니다.

>> light = GREEN, data = 0xcafe, cnt = 90

참고: chip verify

유사한 게시물