베릴로그(2)

유사인간·2023년 4월 10일
0

HDL 모델링

설계 프로그램이나 프로그래밍의 편의성을 위해 늘 그렇듯이, 라이브러리 생성을 통한 모듈식 모델링은 이러한 설계와 유지보수성에서 주효하게 작용한다. verilog 또한, 설계에서 같은 내용과 방식을 채택하는 부분을 모듈화하여 라이브러리에 추가한다면, 추후 똑같은 기능을 추가할 때 더욱 편리하고 빠르고, 정확하게 설계가 가능할 것이다.

구조적 모델링

다른 모듈의 인스턴스와 포트 매핑을 통한 모델링을 시행한다. 범위와 인스턴스 배열을 생성 가능하며, verilog에서는 모듈 이름을 생략 불가능하며 이전 포스트에서 언급했었던 기본 탑재된 라이브러리인 프리미티브 인스턴스 이름은 예외로 생략이 가능하다.

그러나 이러한 구조적 모델링에도 취약점이 있는데, 전체 시스템이 커질수록 모듈 하나하나의 연결이 설계자 입장에서 헷갈릴 수도 있다. 따라서 다음의 순서적 연결을 사용하기보다는, 직접적 포트 이름 언급을 통해 연결할 수 있게 하는 명시적 지정 기능을 가진다.

module renamed_concat(b, c, f, h);
    input       b,c;
    output      f;
    output [1:0] h;
    
    assign f = b & c;
    assign h[0] = b ^ c;
    assign h[1] = b | c;
endmodule

위와 같은 형식으로 한다면, 외부에서 포트의 개수는 4개로 보여진다. 그러나, 모듈과 모듈을 연결할 때, 포트를 사용하지 않는 것도 있고, 포트의 개수가 지금보다 비약적으로 늘어날 경우 설계자는 설계 오류를 범하기가 쉬울 것이다. 따라서, 이런 암시적 명칭 설정보다는 명시적으로 이름을 설정하여 주는 것을 추천한다.

// 명시적으로 포트를 이름을 설정함
module renamed_concat(.a({b,c}), f, .g(h[1]));
    input       b,c;
    output      f;
    output [1:0] h;
    
    assign f = b & c;
    assign h[0] = b ^ c;
    assign h[1] = b | c;
endmodule

차이점은 포트의 명칭 차이와, .(외부 포트)((내부 포트))의 형식이다. 이렇게 설정해주면, 외부에서 보여지는 포트와 내부에서 가동되는 포트는 다르게 보이지만, 직관적으로 연결을 설정해줄 수 있다.

다음으로, 모듈을 만들었으면 그 모듈을 가져와서 사용하는 법을 알아보자.

module renamed_concat(.a({b,c}), f, .g(h[1]));
    input       b,c;
    output      f;
    output [1:0] h;
    
    assign f = b & c;
    assign h[0] = b ^ c;
    assign h[1] = b | c;
endmodule

module top_temp(x, y, z);
    input           x, y;
    output [1:0]    z;
    
    renamed_concat inst_renamed_concat(.a({x,y}), .f(z[1]), .g(z[0]));
    
endmodule

모듈을 만들고, 그 모듈을 inst_(모듈 이름)으로 가져와서 그대로 사용하였다. 두 모듈의 차이점은 다음과 같다. 전자는 암시적 이름을 사용했지만, 후자는 명시적으로 포트 이름을 연결했다는 차이점이 있다.

4비트 full adder

  • 1비트짜리 가산기
module FA1(x, y, ci, co, s);
	input x, y, ci;
	output co, s;
	
	wire w1, w2, w3;
	
	assign w1 = x^y;
	assign w2 = x&y;
	assign w3 = w1&ci;
	assign co = w3|w2;
	assign s = w1^ci;
endmodule
  • 1비트 가산기를 이용한 4비트짜리 가산기 모듈
module FA4(x, y, ci, co, s);
	input	[3:0]	x, y;
	input		ci;
	inout	[3:0]	co;
	output	[3:0]	s;
	wire		w1, w2, w3;
	
	
	FA1 inst_FA1_U0 (x[0], y[0], ci, co[0], s[0]);
	FA1 inst_FA1_U1 (x[1], y[1], co[0], co[1], s[1]);
	FA1 inst_FA1_U2 (x[2], y[2], co[1], co[2], s[2]);
	FA1 inst_FA1_U3 (.x(x[3]), .y(y[3]), .ci(co[2]), .co(co[3]), .s(s[3]));
endmodule
  • 4비트 가산기 테스트벤치
`timescale	1ns/1ps

module TB_4FA;
	reg		[3:0]	x, y;
	reg		ci;
	wire	[3:0]	co;
	wire 	[3:0]	s;

	//module FA4(x, y, ci, co, s);
	FA4 inst_FA1(.x(x), .y(y), .ci(ci), .co(co), .s(s));
	
    //넣고 싶은 테스트 값을 입력
    x = 4'b0000;y =4'b0000;ci = 0; #5;
endmodule

JK 플립플롭

  • modelsim에서 제공하는 프리미티브 게이트인 NAND게이트를 이용한 플립플롭의 설계
module flipflop(clk, j, k , q, qb, rst);
	input	clk, j, k, rst;
	output	q, qb;

	wire	wa1, wa2, wb1, wb2;

	assign wa2 = rst ? 0 : wa1;
	assign wb2 = rst ? 1 : wb1;

		nand g0 (wa1, clk, j, gb);
		nand g1 (wb1, clk, k, q);
		nand g2 (q, wa2, rst, gb);
		nand g3 (qb, wb2, q);
endmodule
  • JK 플립플롭의 테스트벤치
`timescale	1ns/1ps

module	TB_flipflop;
	reg	clk, j, k, rst;
	wire	q, qb;

	flipflop inst_flipflop(.clk(clk), .j(j), .k(k), .q(q), .qb(qb), .rst(rst));
	
	initial
	begin
		clk=0;
		rst =1;#20;
		rst=0;#20;
	end
	
	always
	begin
		clk = ~clk; #30;
	end
	
	initial
	begin
		j=0;k=0;#50;
		j=0;k=0;#50;
		j=0;k=1;#50;
		j=0;k=1;#50;
		j=1;k=0;#50;
		j=1;k=0;#50;
		j=1;k=1;#50;
		j=1;k=1;#50;
		$stop;
	end

endmodule

개선점

작성한 코드는 모두 테스트 테이블을 수기로 작성하여서 길게 나타났다. 이러한 방법은 모든 경우의 수가 급격히 늘어나는 16비트 가산기 등을 제작할 경우, 2^17이라는 엄청난 경우의 수 때문에 불가능하다. 따라서 for문 등의 방법으로 이를 작성하거나, $random함수를 사용하여 무작위의 경우의 수를 집어넣어서 검증하는 테크닉이 중요하다. 이 방법은 이후 포스트에서 공부해나갈 것이다.

profile
유사 인간에 주의하세요.

0개의 댓글