네이버 이웃 추가 / GitHub Profile / 카카오톡 채널 추가 / 방명록 / 이용 안내

[Verilog]D Flip-Flop, Register

수성컴 | 2025. 10. 18.
[Verilog]D Flip-Flop, Register

오늘은 Verilog로 D Flip-Flop과 Register를 만들어 보겠습니다.

  • IDE: Intel Quartus 18.1
  • Device: Cyclone V 5CSXFC6D6F31C6(밑에서 6번째)
  • Simulation: ModelSim-Altera, Verilog HDL

목차

1. D Flip-Flop
1.1. _dff_r.v
1.2. tb_dff_r.v
1.3. simulation\modelsim\tv_dff_r.tv
1.4. RTL View
1.5. RTL Simulation

2. Register(D Flip-Flop을 instantiation하여 구현)
2.1. _register8_dff.v
2.2. _register32_dff.v
2.3. tb_register32_dff.v
2.4. simulation\modelsim\tv_register32.tv
2.5. RTL View
2.6. RTL Simulation
2.7. Flow Summary

3. Register(reg 변수를 사용하여 구현)
3.1. _register32_reg.v
3.2. tb_register32_reg.v
3.3. simulation\modelsim\tv_register32.tv
3.4. RTL View
3.5. RTL Simulation
3.6. Flow Summary

4. 글 마무리
5. 참고 자료

1. D Flip-Flop

clk와 reset_n이 있는 D Flip-Flop을 만들어 보겠습니다.
clk는 클럭입니다. clk의 rising edge(posedge)에 q=d가 됩니다.
reset_n은 active low로 작동합니다. 즉, reset_n==0이면 d의 값에 상관없이 q=0이 됩니다.

  • Project Name & the name of Top-level: _dff_r

1.1. _dff_r.v

module _dff_r(clk, reset_n, d, q);
	input clk, reset_n, d;
	output reg q;
	
	always @ (posedge clk or negedge reset_n)
	begin
		if(reset_n==0)	q<=0;
		else	q<=d;
	end
endmodule

[Line 5]
always @ (posedge clk or negedge reset_n)
clk가 0→1 상승하거나 reset_n이 1→0 하강할 때 begin과 end 사이의 내용을 반복합니다.

[Line 7]
if(reset_n==0) q<=0;
reset_n==0이면 즉시 q<=0;을 수행합니다.

Blocking vs Non-blocking
<=는 non-blocking assignment입니다.

[Line 8]
else q<=d;
reset_n!=0이면(즉, reset_n==1이면) q<=d;를 수행합니다.

1.2. tb_dff_r.v

testvector를 사용하겠습니다.

`timescale 1ns/100ps
 
module tb_dff_r();
	reg clk, reset;
	reg reset_n, d, q_expected;
	wire q;
	reg [31:0] vectornum, errors;	//bookkeeping variables
	reg [31:0] testvectors[10000:0];	//array of testvectors
	
	//instantiate device under test
	_dff_r dut(clk, reset_n, d, q);
	
	//generate clock
	always
		begin
			clk=1; #5; clk=0; #5;
		end
	
	//at start of test, load vectors and pulse reset
	initial
		begin
			$readmemb("./tv_dff_r.tv", testvectors);	//Put testvector file at simulation\modelsim
			vectornum=0; errors=0;
			reset=1; #27; reset=0;
		end
		
	//apply test vectors on rising edge of clk
	always @(posedge clk)
		begin
			#2; {reset_n, d, q_expected}=testvectors[vectornum];
		end
		
	//check results on falling edge of clk
	always @(negedge clk)
		if(~reset) begin //skip during reset==1
			#6;
			if(q!==q_expected) begin
				$display("Error: inputs=%b", {reset_n, d});
				$display("	outputs=%b (%b expected)", q, q_expected);
				errors=errors+1;
			end
			
	//increment array index and read next testvector
			vectornum=vectornum+1;
			if(testvectors[vectornum]===32'bx) begin
				$display("%d tests completed with %d errors.", vectornum, errors);
				$finish;
			end
		end
endmodule

[Line 1~2]
clk는 testbench와 D Flip-Flop에서 공용으로 사용하겠습니다.
reset은 testbench에서 단독으로 사용하겠습니다.
reset_n은 D Flip-Flop에서 단독으로 사용하겠습니다.

[Line 30]
#2; {reset_n, d, q_expected}=testvectors[vectornum];
#2;를 쓰지 않으면 D Flip-Flop이 다음 클럭에 작동하므로 #2;를 써서 지연 시간을 줄였습니다. #1이 아니고 하필 #2;인 이유는 36행에서 negedge clk에 #6;이 붙는 것이 겹치지 않게 하기 위해서입니다.

[Line 36]
#6;
clk의 rising edge(posedge)가 일어난 후 값을 측정하도록 합니다.

Testbench를 작성했으면 Simulation 설정에서 추가해 주어야 합니다. 여기서는 설명하지 않겠습니다. Testbench를 Intel Quartus에서 추가하는 방법을 모르신다면 Intel Quartus에서 Verilog testbench 사용하기 2번 문단을 참고하시길 바랍니다.

1.3. simulation\modelsim\tv_dff_r.tv

00_0
01_0
00_0
01_0
10_0
11_1
10_0
11_1
00_0
01_0
00_0
01_0
10_0
11_1
10_0
11_1

각 줄이 <reset_n><d>_<q_expected>입니다.
예) 10_0reset_n=1, d=0, q_expected=0을 의미합니다.

1.4. RTL View

D Flip-Flop RTL View
D Flip-Flop이 그려져 있고, D에 d가, CLK에 clk가, Q에 q가 연결되어 있으며, CLRN에 reset_n이 invert되어 들어가는 것으로 되어 있습니다.

1.5. RTL Simulation

D Flip-Flop RTL Simulation
vectornum과 errors는 10진수(Decimal)로 표시하도록 설정했습니다. q 값의 변화는 clk의 rising edge(posedge)에만 일어나는 것을 보실 수 있습니다.

2. Register(D Flip-Flop을 instantiation하여 구현)

Register는 D Flip-Flop을 연결하여 만듭니다. 앞서 D Flip-Flop을 구현했으므로 그것을 instantiation하여 32-bit register를 구현해 보겠습니다.

  • Project Name & the name of Top-level: _register32_dff
  • Add files: _dff_r.v(1.1절 파일 활용)

2.1. _register8_dff.v

한 번에 D Flip-Flop 32개를 instantiation하는 것은 번거로우므로 8-bit register를 먼저 만들겠습니다.

module _register8(clk, reset_n, d, q);
	input clk, reset_n;
	input [7:0] d;
	output [7:0] q;
	
	_dff_r U0_dff_r(clk, reset_n, d[0], q[0]);
	_dff_r U1_dff_r(clk, reset_n, d[1], q[1]);
	_dff_r U2_dff_r(clk, reset_n, d[2], q[2]);
	_dff_r U3_dff_r(clk, reset_n, d[3], q[3]);
	_dff_r U4_dff_r(clk, reset_n, d[4], q[4]);
	_dff_r U5_dff_r(clk, reset_n, d[5], q[5]);
	_dff_r U6_dff_r(clk, reset_n, d[6], q[6]);
	_dff_r U7_dff_r(clk, reset_n, d[7], q[7]);
endmodule

2.2. _register32_dff.v

8-bit register 4개를 연결하여 32-bit register를 만듭니다.

module _register32_dff(clk, reset_n, d, q);
	input clk, reset_n;
	input [31:0] d;
	output [31:0] q;
	
	_register8 U0_register8(clk, reset_n, d[7:0], q[7:0]);
	_register8 U1_register8(clk, reset_n, d[15:8], q[15:8]);
	_register8 U2_register8(clk, reset_n, d[23:16], q[23:16]);
	_register8 U3_register8(clk, reset_n, d[31:24], q[31:24]);
endmodule

2.3. tb_register32_dff.v

`timescale 1ns/100ps
 
module tb_register32_dff();
	reg clk, reset;
	reg reset_n;
	reg [31:0] d, q_expected;
	wire [31:0] q;
	reg [127:0] vectornum, errors;	//bookkeeping variables
	reg [127:0] testvectors[10000:0];	//array of testvectors
	
	//instantiate device under test
	_register32_dff dut(clk, reset_n, d, q);
	
	//generate clock
	always
		begin
			clk=1; #5; clk=0; #5;
		end
	
	//at start of test, load vectors and pulse reset
	initial
		begin
			$readmemh("./tv_register32.tv", testvectors);	//Put testvector file at simulation\modelsim
			vectornum=0; errors=0;
			reset=1; #27; reset=0;
		end
		
	//apply test vectors on rising edge of clk
	always @(posedge clk)
		begin
			#2; {reset_n, d, q_expected}=testvectors[vectornum];
		end
		
	//check results on falling edge of clk
	always @(negedge clk)
		if(~reset) begin //skip during reset==1
			#6;
			if(q!==q_expected) begin
				$display("Error: inputs=%b", {reset_n, d});
				$display("	outputs=%b (%b expected)", q, q_expected);
				errors=errors+1;
			end
			
	//increment array index and read next testvector
			vectornum=vectornum+1;
			if(testvectors[vectornum]===128'bx) begin
				$display("%d tests completed with %d errors.", vectornum, errors);
				$finish;
			end
		end
endmodule

[Line 23]
$readmemh(“./tv_register32.tv”, testvectors);
1.2절 tb_dff_r.v에서는 $readmemb를 썼지만, 여기 tb_register32_dff.v에서는 $readmemh를 씁니다.
$readmemb는 파일을 2진수로 읽어서 배열에 저장하고, $readmemh는 파일을 16진수로 읽어서 배열에 저장합니다.
testvector를 작성할 때 32bit를 2진수로 쓰면 너무 길기 때문에 16진수로 했습니다. 참고로 16진수 1자리는 2진수로 변환하면 4자리가 됩니다.

2.4. simulation\modelsim\tv_register32.tv

000000000_00000000
000000001_00000000
000000020_00000000
00000a003_00000000
100000000_00000000
100000001_00000001
100000020_00000020
10000a003_0000a003
000000000_00000000
000000001_00000000
000000020_00000000
00000a003_00000000
100000000_00000000
100000001_00000001
100000020_00000020
10000a003_0000a003

각 줄이 <reset_n><d>_<q_expected>입니다.
dq_expected는 16진수로 8자리씩 됩니다.
예) 10000a003_0000a003reset_n=1, d=0000a003, q=0000a003입니다.

2.5. RTL View

_register32_dff RTL View
d가 _register8 4개로 나뉘어 들어갑니다.

_register8 RTL View
_register8을 확대해 보면 이렇게 생겼습니다.

2.6. RTL Simulation

_register32_dff RTL Simulation
d와 q_expected와 q는 16진수(Hexadecimal)로, vectornum과 errors는 10진수(Decimal)로 표시하도록 설정했습니다.
D Flip-Flop과 마찬가지로 q 값의 변화는 clk의 rising edge(posedge)에만 일어나는 것을 보실 수 있습니다.

2.7. Flow Summary

_register32_dff Flow Summary
Logic utiliazation은 9, Total registers는 32, Total pins는 66이 나오네요.

3. Register(reg 변수를 사용하여 구현)

이번에는 그냥 32-bit reg 변수를 선언하여 Register를 구현해 보겠습니다. 물론 그렇다고 해서 그냥 “reg 변수 선언, 끝!”은 아니고 input과 output, always문 등을 사용하도록 하겠습니다.

  • Project Name & the name of Top-level: _register32_reg

3.1. _register32_reg.v

module _register32_reg(clk, reset_n, d, q);
	input clk, reset_n;
	input [31:0] d;
	output reg [31:0] q;
	
	always @ (posedge clk or negedge reset_n)
	begin
		if(reset_n==0)	q<=0;
		else	q<=d;
	end
endmodule

[Line 3~4]
d와 q를 각각 [31:0]으로 선언합니다.

[Line 6]
always @ (posedge clk or negedge reset_n)
clk가 0→1 상승하거나 reset_n이 1→0 하강할 때 begin과 end 사이의 내용을 반복합니다.

[Line 8]
if(reset_n==0) q<=0;
reset_n==0이면 즉시 q<=0;을 수행합니다.

[Line 9]
else q<=d;
reset_n!=0이면(즉, reset_n==1이면) q<=d;를 수행합니다.

3.2. tb_register32_reg.v

`timescale 1ns/100ps
 
module tb_register32_reg();
	reg clk, reset;
	reg reset_n;
	reg [31:0] d, q_expected;
	wire [31:0] q;
	reg [127:0] vectornum, errors;	//bookkeeping variables
	reg [127:0] testvectors[10000:0];	//array of testvectors
	
	//instantiate device under test
	_register32_reg dut(clk, reset_n, d, q);
	
	//generate clock
	always
		begin
			clk=1; #5; clk=0; #5;
		end
	
	//at start of test, load vectors and pulse reset
	initial
		begin
			$readmemh("./tv_register32.tv", testvectors);	//Put testvector file at simulation\modelsim
			vectornum=0; errors=0;
			reset=1; #27; reset=0;
		end
		
	//apply test vectors on rising edge of clk
	always @(posedge clk)
		begin
			#2; {reset_n, d, q_expected}=testvectors[vectornum];
		end
		
	//check results on falling edge of clk
	always @(negedge clk)
		if(~reset) begin //skip during reset==1
			#6;
			if(q!==q_expected) begin
				$display("Error: inputs=%b", {reset_n, d});
				$display("	outputs=%b (%b expected)", q, q_expected);
				errors=errors+1;
			end
			
	//increment array index and read next testvector
			vectornum=vectornum+1;
			if(testvectors[vectornum]===128'bx) begin
				$display("%d tests completed with %d errors.", vectornum, errors);
				$finish;
			end
		end
endmodule

3.3. simulation\modelsim\tv_register32.tv

2.4절과 똑같이 했습니다. 스크롤 올리기 귀찮으신 분들을 위해 한 번 더 써 드리겠습니다.

000000000_00000000
000000001_00000000
000000020_00000000
00000a003_00000000
100000000_00000000
100000001_00000001
100000020_00000020
10000a003_0000a003
000000000_00000000
000000001_00000000
000000020_00000000
00000a003_00000000
100000000_00000000
100000001_00000001
100000020_00000020
10000a003_0000a003

3.4. RTL View

_register32_reg RTL View
register가 사각형 하나에 그려져 있고, D에 d[31..0]이, CLK에 clk가, Q에 q[31..0]이 연결되어 있으며, CLRN에 reset_n이 invert되어 들어가는 것으로 되어 있습니다.

3.5. RTL Simulation

_register32_reg RTL Simulation
d와 q_expected와 q는 16진수(Hexadecimal)로, vectornum과 errors는 10진수(Decimal)로 표시하도록 설정했습니다.
q 값의 변화는 clk의 rising edge(posedge)에만 일어나는 것을 보실 수 있습니다.

3.6. Flow Summary

_register32_reg Flow Summary
D Flip-Flop을 instantiation했을 때와 마찬가지로 Logic utiliazation은 9, Total registers는 32, Total pins는 66이 나옵니다.

4. 글 마무리

제 글을 읽어 주셔서 감사합니다. 다음에 만나요!

5. 참고 자료

1) David Money Harris, Sarah L. Harris. 2013. Digial Design and Computer Architecture. 2nd Edition. Elsevier Korea L.L.C.
2) @SEMICIRCUIT. 2025. “[Verilog] “=”(blocking)과 “<=”(non-blocking) 할당의 차이”, SEMICIRCUIT. (2025. 10. 18. 방문). https://semicircuit.tistory.com/199