* 이 장에서 배우는 것
- function
- clock gating
- enable
이번에는 verilog function block을 사용하여 뺄셈기를 설계해 보자.
function block은 C언어에서의 함수와 같이 특정 코드 블록을 모아 호출할 수 있는 기능을 제공해 준다. verilog에서는 주로 조합회로를 구현 하기 위해 사용한다. 특정 조합회로를 function으로 구현하면 같은 기능을 필요로 하는 곳에 중복해서 코딩을 할 필요 없이 function을 호출하면 된다. 뺄셈기의 기본 설계 개념은 시퀀셜 가산기와 동일하다. 아래는 완성된 뺄셈기 코드이다.
module subtractor (
input clock,
input resetn,
input en,
input wire [7:0] a,
input wire [7:0] b,
output reg [7:0] y
);
function [7:0] sub (input [7:0] a, input [7:0] b);
begin
sub = a - b;
end
endfunction
always @(posedge clock or negedge resetn)
begin
if (~resetn)
y <= 0;
else if (en)
y <= sub(a, b);
end
endmodule
11라인 부터 15라인까지 'sub'라는 이름의 뺄셈 기능을 function으로 구현한 것이다.
verilog function은 여러개의 입력을 받을 수 있지만 출력은 하나만 가능하고 출력 변수는 함수 이름과 동일하다.
'function [7:0] sub'의 의미는 8bit의 sub라는 출력 값을 리턴하는 함수라는 의미이다. 함수 이름 'sub' 뒤에는 입력 목록을 기술한다. 여기서는 8bit 입력 'a'와 8bit 입력 'b'를 입력 파라메터로 받고 있음을 알 수 있다.
17라인에서 23라인 까지는 DFF의 코드와 동일한 패턴으로 시퀀셜 로직을 구현하고 있다. DFF의 입력 값이 함수 리턴 값으로 바뀌어 있는 것을 알 수 있다. 즉 8bit 'y' 레지스터의 입력이 뺄셈 로직의 출력 값이 되는 것이다. 그리고 이번에는 'else if'부분이 추가 되었는데 이는 'en'신호가 '1'일 때만 입력을 출력에 전달한다는 의미이다. 이런 패턴으로 코딩하는 이유는 합성기에서 이 부분에 clock gating 로직을 추가하기 위함이다. DFF이 실제 하드웨어로 구현 될 때 CMOS logic으로 구현된다. CMOS 로직은 클록신호의 edge에서만 전류를 흐르게 하므로 클록이 동작 할 때마다 DFF이 동작한다면 전류 소모가 많아 지게 된다. 이를 방지 하기 위해 필요할 때만 clock이 입력 되도록 하는 데 위의 코드와 같이 'else if'구문으로 enable 신호를 만들어 주면 합성기가 자동으로 clock gating, 즉 clock 차단 로직을 만들어 준다. 이렇게 함으로써 다이나믹 전류를 많이 줄일 수 있어 저전력 회로 구현에 이 기법은 필수적으로 사용된다.
아래는 뺄셈기를 테스트 하는 테스트벤치 코드이다. 덧셈기의 테스트 벤치와 거의 동일하고 'en' 신호가 추가 되었다.
`timescale 1ns/1ns
module test_sub;
// delare variables
reg clock;
reg resetn;
reg [7:0] a;
reg [7:0] b;
reg en;
wire [7:0] y;
// clock generation
always #10 clock = ~clock;
// subtractor instantiation
subtractor u_sub (
.clock (clock),
.resetn (resetn),
.en (en),
.a (a),
.b (b),
.y (y)
);
// create wave dump file
initial
begin
$dumpfile("sub.vcd");
$dumpvars(0, test_sub);
end
// input stimulus
initial
begin
a = 0;
b = 0;
en = 0;
clock = 0;
resetn = 0;
#100;
resetn = 1;
a = 2;
b = 3;
@(posedge clock);
en = 1;
a = 4;
b = 5;
@(posedge clock);
a = 10;
b = 30;
@(posedge clock);
#100;
a = 33;
b = 13;
en = 0;
@(posedge clock);
#100;
a = 100;
b = 50;
en = 1;
@(posedge clock);
#100;
$finish();
end
endmodule
아래와 같이 프롬프트 창에서 iverilog로 컴파일하고 a.out file을 실행시킨다. 그리고 gtkwave로 dump file을 열어본다.
>>iverilog test_sub.v subtractor.v
>>./a.out
>>gtkwave sub.vcd
아래는 gtkwave로 찍어 본 각 신호의 wave form이다.
위의 그림을 보면 'en'이 1인 경우에만 뺄셈이 수행 되는 것을 알 수 있는데 뭔가 이상하다. 빨간색 마커를 살펴 보면 clock의 positive edge에서 'en'신호가 1인 것처럼 동작한다. 하지만 실제 하드웨어를 합성하여 F/F이 생긴다면 'en'을 0으로 인식할 것이다. 왜 이런 현상이 발생할 까? 이는 테스트 벤치에서 입력 변수들을 대입할 때 blocking assignment를 사용했기 때문이다. 즉 clock의 positive edge에서 F/F의 입력인 'en'신호가 1로 업데이트 될 때까지 다음 구문이 실행되지 않기 때문에 F/F의 assignment 구문이 실행 될 때 'en'신호는 1이 되어 있는 것이다. 이런 현상을 해결하려면 테스트 벤치에서도 non-blocking assignment를 사용하면 된다. 아래는 non-blocking assignment를 사용한 테스트 벤치이다.
`timescale 1ns/1ns
module test_sub;
// delare variables
reg clock;
reg resetn;
reg [7:0] a;
reg [7:0] b;
reg en;
wire [7:0] y;
// clock generation
always #10 clock = ~clock;
// subtractor instantiation
subtractor u_sub (
.clock (clock),
.resetn (resetn),
.en (en),
.a (a),
.b (b),
.y (y)
);
// create wave dump file
initial
begin
$dumpfile("sub.vcd");
$dumpvars(0, test_sub);
end
// input stimulus
initial
begin
a <= 0;
b <= 0;
en <= 0;
clock <= 0;
resetn <= 0;
#100;
resetn <= 1;
@(posedge clock);
a <= 2;
b <= 3;
@(posedge clock);
en <= 1;
a <= 4;
b <= 5;
@(posedge clock);
a <= 10;
b <= 30;
@(posedge clock);
a <= 33;
b <= 11;
en <= 0;
@(posedge clock);
a <= 100;
b <= 50;
en <= 1;
@(posedge clock);
#100;
$finish();
end
endmodule
이렇게 하면 아래와 같이 wave form에서 'en' 신호를 제대로 인식함을 볼 수 있다. 이것은 입력 'a', 'b'에 대해서도 마찬가지이다.
빨간색 마커에서 clock의 positive edge event에 대하여 'en' 신호는 0으로 인식함을 알 수 있다. 다음 번 사이클인 하얀색 마커를 보면 'en'을 1로 인식하고 그 때 입력인 4-5를 계산한 결과 -1을 제대로 출력하는 것을 볼 수 있다. 다시 한 번 blocking assignment와 non-blocking assignment를 언제 사용하는지 정리해 보자.
1. blocking assignment
- cominational logic (조합회로)를 기술 할 때.
- begin/end 안에서 대입 문이 순차적으로 실행 되어야 할 때.
2. non-blocking assignment
- sequential logic (순차회로)를 기술 할 때.
- 일련의 대입 문이 병렬로 동시에 수행되어야 할 때.
'실전! Verilog HDL RTL Design' 카테고리의 다른 글
[Verilog HDL] 11. ALU (Arithmetic Logic Unit) 설계 (2) | 2022.06.03 |
---|---|
[Verilog HDL] 10. task를 이용한 shifter 설계 (0) | 2022.05.16 |
[Verilog HDL] 8. 순차논리 (Sequential Logic) Adder 설계 (0) | 2022.05.04 |
[Verilog HDL] 7. 순차논리 (Sequential Logic) 회로 설계 (D F/F) (0) | 2022.04.10 |
[Verilog HDL] 6. Simulation (0) | 2022.03.28 |