Verilog (4) - 8진 카운터 감가산기

유사인간·2023년 4월 17일
0
post-thumbnail

카운터?

말 그대로 숫자를 세는 카운터이다. JK플립플롭을 기반으로 하여, 이전에 설계했었던 add에 뺄셈을 할 수 있도록 설계한 카운터라고 할 수 있다. 컴퓨터의 논리구조로는 덧셈과 곱셈만 할 수 있다. 다음을 참고해보자.

//a - b를 실행하려고 할 때

a = 8
b = 10

a == 4'b1000;
b == 4'b1010;

1000(2) - 1010(2) = (-)0010(2) ...?

이상한 결과가 나오지 않는가? -가 앞에 붙는다. 또한 언급했듯이 덧셈과 곱셉만 할 수 있는 컴퓨터로써는 이런 결과를 실행할수 없다. 따라서 빼려는 b의 1의 보수를 취해 그것을 더한다면 뺄셈이 가능하다!

a = 8
b = 10

a == 4'b1000;
b == 4'b1010;

//b의 1의 보수는 0101;

1000(2) + 0101(2) = 1101(2) = 13....?

이번 결과도 이상하다. 8 + 5가 되어버렸다. 이것은 보수의 성질을 간과한 결과이다. 보수를 취했을 때, 2진수의 첫째 자리를 부호로 삼는 것이다. 또한 (1)1111을 0으로, (1)1110을 -1로 거꾸로 센다. 따라서 1/0101은 -10이다. 다시 계산하면

(0)1000(2) + (1)0101(2) = (1)1101(2) = -2

올바른 결과가 나왔다. 사람들의 인식으로는 엄청나게 쉬운 계산이지만, 컴퓨터는 이러한 복잡한 과정을 거쳐서 계산하게 된다. 이 사실을 토대로 다음과 같은 8진 카운터 감가산기를 설계하여 보았다.

설계코드

module	ADD_p	(A, B, Cin, S, Cout);
	parameter			BW	=[계산하고자 하는 비트 숫자];
	input		[BW -1:0]	A, B;
	input				Cin;
	output		[BW -1:0]	S;
	output				Cout;
	wire		[BW -1:0]	A, B;
	wire		[BW -1:0]	S;
	wire		[BW:0]		tc;
	genvar 				i;
	
	assign				tc[0] 	=Cin;
	assign				Cout	=tc[BW];

	generate
		for (i = 0; i < BW; i = i + 1) begin : add
			assign	S[i] = A[i] ^ B[i] ^ tc[i];
			assign	tc[i + 1] = (A[i] & B[i]) | (A[i] & tc[i]) | (B[i] & tc[i]);
		end
	endgenerate
endmodule

A, B는 더하는 숫자, Cin은 전 자릿수에서 올라오는 carry, 올림수이다. 또한 아웃의 S는 덧셈 이후의 자릿수를 의미하며, Cout은 연산 이후의 다음 자리 숫자에 더하는 것이다. 근데 왜 쌩뚱맞게 덧셈을 하는지 궁금할 것이다. 그 이유는 다음과 같다.

module	ADSB4 (x, y, s, sum, cout);
	parameter		BW	=8;
	input	[BW-1:0]	x, y;
	input			s;
	output	[BW-1:0]	sum;
	output			cout;

	wire	[BW-1:0]	x, y, ty;
	wire	[BW-1:0]	sum;
	
	assign		ty	= s ? ~y : y;

	ADD_p U0 (.A(x), .B(ty), .Cin(s), .S(sum), .Cout(cout));

endmodule	

ADD_p에 assign문장 하나를 더해준 감산기 ADSB4이다. 위 카운터 문단에서 언급했듯이, 빼주려는 y값을 반전시켜 1의 보수로 취함으로써 더해주면, 다음과 같은 식이 완성된다.

x + (-y)

따라서 훌륭하게 뺄셈이 완료되었다! 테스트벤치 파일을 작성하여서 감가산기의 결과를 살펴보자.

`timescale	1ns/1ps

module	TB_ADSB4;
	parameter		BW	=8;
	reg	[BW-1:0]	x, y;
	reg			s;
	wire	[BW-1:0]	sum1, sum2;
	wire		cout1, cout2;
	
	ADSB4 inst_ADSB4 (.x(x), .y(y), .s(s), .sum(sum1), .cout(cout1));

	ADD_p inst_ADD_p (.A(x), .B(y), .Cin(s), .S(sum2), .Cout(cout2));


	initial begin
	#10;	x = $random();	y = $random();	s = $random();
	#10;	x = $random();	y = $random();	s = $random();	
	#10;	x = $random();	y = $random();	s = $random();	
	#10;	x = $random();	y = $random();	s = $random();	
	#10;	x = $random();	y = $random();	s = $random();	
	#10;	x = $random();	y = $random();	s = $random();	
	#10;	x = $random();	y = $random();	s = $random();		
	#10;	x = $random();	y = $random();	s = $random();	
	#10;	x = $random();	y = $random();	s = $random();	
	#10;	x = $random();	y = $random();	s = $random();	
	#10;	x = $random();	y = $random();	s = $random();	
	end
endmodule

여러 개의 랜덤 함수를 쓰는 것은 너무 귀찮고 예쁘지도 않다. 추후 테스트벤치를 작성할 때는 for문이나 while문을 사용해서 쉽게 랜덤 함수를 출력하려고 한다.

위와 같은 예쁜 그래프가 나타났다. 그래프를 살펴보면, 연산 결과가 훌륭하게 나타나는 것을 확인해볼 수 있다.

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

0개의 댓글