HDL/Verilog

Verilog HDL로 synchronous control 구문 작성과 테스트 벤치(Test Bench)로 결과 확인하기

Torrance 2023. 10. 1. 07:00

안녕하세요,
이번 글에서는 synchronous control을 구현하고, 그 결과를 테스트 벤치(Test Bench)로 확인하겠습니다.
clock이 실행되면서 clock enable이 활성화될 때, reset 신호에 따라 data를 출력하거나 0으로 reset 합니다. 

환경

  • HDL : Verilog’ 2001 spec
  • RTL Synthesis : Intel(Altera), Quartus prime 18.1
  • Functional Simulation : Intel(Altera), ModelSim 10.5b

Quatus의 [File] → [New]에서 Verilog HDL File을 선택합니다.

synchronous control를 구현했습니다.

module reg16(

	input				clk		,
	input				sclr_n	,
	input				clk_ena	,
	input		[15:0]	data_in	,
	output 	reg	[15:0] 	reg_out	
);

	always @ (posedge clk) begin

		if (clk_ena) begin
		
			if(!sclr_n)
				reg_out <= 16'd0 ;
			else
				reg_out <= data_in;
		end
		
	end
	
endmodule

Verilog HDL Check point

  • always @ (posedge clk) 는 clk의 상승(positve의 pos) 엣지(edge)에서만 그 안에 있는 구문을 실행한다는 뜻입니다. 
  • if else 구문은 always, initial block에 속해 있으므로 꼭 always, initial 구문 안에서 사용해야 합니다.
  • sclr_n은 하강(negative의 neg) 엣지(edge)에서만 반응하므로 꼭 !를 붙여야 합니다. 그렇지 않으면 에러가 납니다.

 

Test Bench를 작성했습니다.

`timescale 1 ns/1 ns

module reg16_tb();
	
	reg  clk ;
	reg  sclr_n ;
	reg  clk_ena ;
	reg  [15:0] data_in ;
	wire [15:0] reg_out ;
	
	reg16 uReg16_0(
	
		 .clk	 (clk	 ),	
         .sclr_n (sclr_n ),	
         .clk_ena(clk_ena),	
         .data_in (data_in ),	
         .reg_out(reg_out)	
	);

	
	initial	begin
	clk = 0 ;
	forever
		#1 clk = ~ clk ;
	end
	
	initial begin
	clk_ena = 1'b0 ;
	sclr_n = 1'b0 ;
	data_in = 16'h1F1F ;
	
	#4 ;
	clk_ena = 1'b1 ;
	
	#4 ;
	sclr_n = 1'b1 ;
	
	#4 ;
	data_in = 16'h4567 ;
	clk_ena = 1'b0 ;
	
	#4 ;
	clk_ena = 1'b1 ;
	
	#4 ;
	sclr_n = 1'b0 ;
	end
	
endmodule

Test Bench Check point

  • module과 endmodule로 module 시작 및 종료했습니다
  • `timescale 1 ns/1 ns에서 앞의 1ns는 기본 단위 설정이며, 뒤의 1ns이며 이것을 구현하는 해상도는 1ns라는 뜻입니다.
    https://semiconwide.tistory.com/64 를 보시면 더욱 이해가 잘 될 것입니다.
  • forever #1 clk = ~clk ; 구문에서 처음 clk 값은 0으로 할당되고, 1단위인 1ns 유지 후, ~clk인 1값이 됩니다. 다시 이것을 1ns 유지 후 0으로 바뀌고 이것을 계속 반복하는 clock을 생성합니다. 
  • 입력은 register인 reg로, 결과는 wire로 선언했습니다.
  • reg16 uReg16_0은 instantation으로 Port name을 직접 Association 하는 방식을 사용했습니다.
    다른 방식도 있으나 디버깅 효율을 높이기 위해 이 방법을 택했습니다.

이제 ModelSim에서 시뮬레이션을 하기 위한 tcl파일을 만들겠습니다.

Quatus의 [File] → [New]에서 Tcl Script File을 선택합니다.

 

즉, 1번의 시뮬레이션을 위해서는 총 3개의 파일(Verilog HDL 기능 구현, TestBench, TCL)이 필요합니다.

vlib work
vlog reg16.v reg16_tb.v
vsim work.reg16_tb

add wave -radix hex /data_in
add wave -radix hex /reg_out

add wave -radix binary /clk
add wave -radix binary /clk_ena
add wave -radix binary /sclr_n

run 20 ns

TCL file Check point

  • vlib work, vlog, vsim work은 필수 항목입니다.
    vlog 다음엔 verilog HDL 파일과 test bench 파일 이름이 나와야 합니다.
    vsim work 다음 test bench 파일이 나와야 합니다.
  • add wave는 파형 추가입니다. dec는 decimal인 10진법입니다.
  • '/' 다음 결과를 보고자 하는 변수를 입력하면 됩니다.
  • run 이후 시뮬레이션 시간을 입력하면 됩니다.

 

최종 결과

1. 시작 후 4ns까지 clk_ena = 0 이므로, reg_out은 변화하지 않습니다. 게다가 초기 값이 설정되지 않아 값이 없습니다.

4ns까지 reg_out 할당 값 x

2. 4ns 직후 clk_ena = 1이 되지만 그 당시 clk는 negedge이므로 reg_out이 변하지 않습니다.
5ns에서 clk_ena = 1이면서 clk가 posedge이고, sclr_n = 0이므로 reg_out이 0000으로 할당(초기화)됩니다.

5ns reg_out 0000 초기화

3. 9ns에서 clk_ena = 1, clk posedge, sclr_n = 1이므로 비로소 reg_out에 data_in 값인 1f1f가 할당됩니다.

4. 12ns에서 clk_ena = 1, sclr_n = 1 이면서 data_in 값이 4567로 바뀌지만 clk가 negedge라 변하지 않습니다.

그래서 posedge인 13ns에서 reg_out에 4567이 할당됩니다.