Verilog의 자료형에는 두 가지 종류가 있다.
모듈 혹은 게이트 간의 물리적인 연결을 나타내는 net 자료형과, 절차적 할당문에서 값을 임시로 저장하기 위한 variable 자료형이 있다.
대개 모듈을 설계할 때 wire과 reg, integer만으로 모듈을 설계했었기 때문에, 나머지 자료형에 대한 개념이 부족하여 정리하였다.
wand와 wor는 각각 wired AND와 wired OR를 뜻한다.
wire의 확장형인데, wire는 내부에 함축된 논리적 동작이나 기능 없이 단순한 연결을 위한 net인 반면, wand와 wor는 연결될 때마다 암묵적인 동작이 수행된다.
가변 개수의 입력을 받아서 각각 논리곱과 논리합을 출력한다고 보면 될 것 같다.
아래의 예제를 보자.
`ifndef __TEST_WAND_V__
`define __TEST_WAND_V__
module test_wand(
output wand x,
input a, b, c, d, e, f, g, h, i
);
assign x = a;
assign x = b;
assign x = c;
assign x = d;
assign x = e;
assign x = f;
assign x = g;
assign x = h;
assign x = i;
endmodule
`endif /* __TEST_WAND_V__ */
`timescale 1ms/1ms
`include "test_wand.v"
module tb_test_wand();
reg a, b, c, d, e, f, g, h, i;
wire x;
test_wand _test_wand(
.x(x),
.a(a), .b(b), .c(c),
.d(d), .e(e), .f(f),
.g(g), .h(h), .i(i)
);
initial begin
// for simulation
$dumpfile("test_wand.vcd");
$dumpvars(-1, _test_wand);
// initialize
a <= 0; b <= 0; c <= 0;
d <= 0; e <= 0; f <= 0;
g <= 0; h <= 0; i <= 0;
// start
#1 a = 1; #1 b = 1; #1 c = 1;
#1 d = 1; #1 e = 1; #1 f = 1;
#1 g = 1; #1 h = 1; #1 i = 1;
// end
#1
$finish;
end
endmodule
a-i까지 9개의 입력을 x에 연결하였는데, assign을 할 때마다 x에 입력 핀이 AND 연산으로 연결되기 때문에 최종적으로 9입력 AND게이트가 만들어진다.
모듈 생성 후 시뮬레이션을 실행한다.
> iverilog -o test_wand test_wand.v
> vvp test_wand.vvp
> gtkwave test_wand.vcd
실행하면 아래와 같이 a-i 까지의 입력이 모두 1일 때 x에 1이 출력되는 것을 볼 수 있다.
아래의 예제를 보자.
`ifndef __TEST_WOR_V__
`define __TEST_WOR_V__
module test_wor(
output wor y,
input a, b, c, d, e, f, g, h, i
);
assign y = a;
assign y = b;
assign y = c;
assign y = d;
assign y = e;
assign y = f;
assign y = g;
assign y = h;
assign y = i;
endmodule
`endif /* __TEST_WOR_V__ */
`timescale 1ms/1ms
`include "test_wor.v"
module tb_test_wor();
reg a, b, c, d, e, f, g, h, i;
wire y;
test_wor _test_wor(
.y(y),
.a(a), .b(b), .c(c),
.d(d), .e(e), .f(f),
.g(g), .h(h), .i(i)
);
initial begin
// for simulation
$dumpfile("test_wor.vcd");
$dumpvars(-1, _test_wor);
// initialize
a <= 0; b <= 0; c <= 0;
d <= 0; e <= 0; f <= 0;
g <= 0; h <= 0; i <= 0;
// start
#1 a = 1; #1 b = 1; #1 c = 1;
#1 d = 1; #1 e = 1; #1 f = 1;
#1 g = 1; #1 h = 1; #1 i = 1;
// end
#1
$finish;
end
endmodule
a-i까지 9개의 입력을 y에 연결하였는데, assign을 할 때마다 y에 입력 핀이 OR 연산으로 연결되기 때문에 최종적으로 9입력 OR게이트가 만들어진다.
모듈 생성 후 시뮬레이션을 실행한다.
> iverilog -o test_wor test_wor.v
> vvp test_wor.vvp
> gtkwave test_wor.vcd
실행하면 아래와 같이 a-i 까지의 입력이 하나라도 1이면 y에 1이 출력되는 것을 볼 수 있다.
tri는 wire와 동일하지만 하드웨어에서 3상태가 되는 점이 wire와 다르다고 한다.
tri1과 tri0은 tri와 같지만 고임피던스 신호가 들어왔을 때 각각 1(pull up)과 0(pull down)값을 가진다.
코드를 통해 확인해보자.
module test_tri();
wire w1, w2, w3;
tri t1, t2, t3;
tri1 t01, t02, t03;
tri0 t11, t12, t13;
assign w1 = 0;
assign t1 = 0;
assign t01 = 0;
assign t11 = 0;
assign w2 = 1;
assign t2 = 1;
assign t02 = 1;
assign t12 = 1;
assign w3 = 1'bz;
assign t3 = 1'bz;
assign t03 = 1'bz;
assign t13 = 1'bz;
initial
begin
$display("[%g] w1 = %b, w2 = %b, w3 = %b", $time, w1, w2, w3);
$display("[%g] t1 = %b, t2 = %b, t3 = %b", $time, t1, t2, t3);
$display("[%g] t01 = %b, t02 = %b, t03 = %b", $time, t01, t02, t03);
$display("[%g] t11 = %b, t12 = %b, t13 = %b", $time, t11, t12, t13);
end
endmodule
wire, tri, tri1, tri0에 각각 0, 1, Z값을 대입했을 때의 결과를 출력한다.
모듈 생성 후 실행한다.
> iverilog -o test_tri test_tri.v
> vvp test_tri.vvp
실행하면 아래와 같이 출력된다.
[0] w1 = 0, w2 = 1, w3 = z
[0] t1 = 0, t2 = 1, t3 = z
[0] t01 = 0, t02 = 1, t03 = 1
[0] t11 = 0, t12 = 1, t13 = 0
t03과 t13를 보면, 각각 Z를 넣었을 때 tri1은 1을, tri0은 0을 갖는 것을 볼 수 있다.
나머지는 모두 동일하다.
추가로 wire와 tri의 차이는 위 결과로 확인하긴 어려운 것 같다.
triand는 tri와 wand가 결합된 구조이며, trior는 tri와 wor가 결합된 구조이다. 가변 입력을 받아 각각 wired AND와 wired OR를 출력하며, 하드웨어 상에서 3상태를 가진다.
예제 생략쓰..
supply1은 전원에서 끌어오는 선을 표현할 때, supply0은 접지에서 끌어오는 선을 표현할 때 사용한다고 한다. supply1은 constant logic 1, supply0은 constant logic 0을 갖는다고 한다.
아래 글에 의하면 Verilog에는 신호 강도(Strength)라는 개념이 있어서, net 자료형에 보다 정확한 값을 할당하기 위해 Strength level이란 걸 두어 사용한다고 한다. https://www.hdlworks.com/hdl_corner/verilog_ref/items/Strengths.htm
자료형의 supply와 신호 강도의 supply가 동일한 건지는 잘 모르겠다.
예제를 통해 확인해보자.
module test_supply();
wire z1, z0;
supply1 s1;
supply0 s0;
reg w;
assign (supply1, strong0) z1 = s1 | w;
assign (supply0, strong1) z0 = s0 & w;
initial
begin
$monitor("Strength(z1) = %v, Value(z1) = %b, Strength(z1) = %v, Value(z1) = %b", z1, z1, z0, z0);
w = 1'b0; #1;
w = 1'b1; #1;
$finish;
end
endmodule
제대로 만든 예제인지 잘 모르겠다. 우선 돌려보자.
모듈 생성 후 실행한다.
> iverilog -o test_supply.vvp test_supply.v
> vvp test_supply.vvp
그러면 아래와 같이 출력된다.
[0] w = 0, Strength(z1) = Su1, Value(z1) = 1, Strength(z1) = Su0, Value(z1) = 0
[1] w = 1, Strength(z1) = Su1, Value(z1) = 1, Strength(z1) = Su0, Value(z1) = 0
w 값에 따른 z1과 z0의 신호 강도 및 결과값을 출력하였는데, 이게 의미있는 결과인지 잘 모르겠다. 추후 다시 작성 예정.
tri와 reg의 결합 형태로, 이전 값을 저장하는 기능이 있는 3상태 wire이다. 고임피던스가 인가될 때 이전 값을 출력한다.
trireg는 net 자료형임에 주의하자.
예제를 통해 확인해보자.
module test_trireg();
trireg out;
reg cs, in;
assign out = (cs) ? in : 1'bz;
initial begin
$monitor("[%g] out = %b cs = %b in = %b", $time, out, cs, in);
cs = 0; in = 0;
#1 cs = 1;
#1 cs = 0;
#1 in = 1;
#1 cs = 1;
#1 cs = 0;
#1 $finish;
end
endmodule
cs가 1에서 0으로 떨어질 때 out의 값을 살펴보자.
모듈 생성 후 실행하면 아래와 같이 출력된다.
[0] out = x cs = 0 in = 0
[1] out = 0 cs = 1 in = 0
[2] out = 0 cs = 0 in = 0
[3] out = 0 cs = 0 in = 1
[4] out = 1 cs = 1 in = 1
[5] out = 1 cs = 0 in = 1
cs가 0->1로 바뀌면 out의 값이 in 값으로 동기화되지만, 1->0으로 바뀌면 고임피던스를 가지지 않고 이전 값을 가지는 것을 볼 수 있다.
추가로, iverilog에서 trireg를 컴파일하면 아래와 같이 지원하지 않는다고 뜨는데,
test_trireg.v:3: sorry: trireg nets not supported.
알아보니 iverilog에서는 trireg를 지원하지 않는다고 한다.
https://github.com/steveicarus/iverilog/blob/master/README.txt
위 링크에서 Unsupported Constructs 로 검색하면 iverilog에서 지원하지 않는 자료형들을 확인할 수 있으니 참고하면 될 것 같다.