컴퓨터 cpu에는 여러가지 게이트 구조들이 있다. 예, 아니오를 판별하는 논리 게이트의 무한정 분기를 허용하여 프로그램과 데이터를 읽기도 한다. 그 중, 우리로 하여금 2진수를 읽지 않고, 10진수를 사용할 수 있게 하며 덧셈과 뺄셈, 나눗셈, 곱셈을 할 수 있게 해주는 기초인 카운터에 대해서 소개하고자 한다.
카운터는 기본적으로, 이전 상태라고 하는 state라는 개념으로 출발해야 한다. 카운터는 여러 개의 FlipFlop으로 구성되어 있으며, 이들은 1bit의 정보를 저장할 수 있다. 이들을 참고하여 카운터는 다음 숫자를 셀 수 있는 것이다.
다음 코드를 보면 어떤 사실을 알 수 있다.
module cnt8 (clk, rst, en, q, tco);
input clk, rst, en;
output [2:0] q;
output tco;
reg [2:0] q;
reg tco;
always @ (posedge clk or posedge rst)
if (rst)
begin
q <= 3'b000;
tco <= 1'b0;
end
else if (en)
if (q == 3'b110)
begin
q <= q + 1'b1;
tco <= 1'b1;
end
else if (q == 3'b111)
begin
q <= 3'b000;
tco <= 1'b0;
end
else
begin
q <= q + 1'b1;
tco <= 1'b0;
end
endmodule
카운터는 기본적으로 rst 신호와 en 신호를 받고 동작하며, clk의 상승엣지마다 동작함을 확인할 수 있다. 또한 이 카운터는 3bit짜리 카운터이므로, 한 자리에서 0~7까지 셀 수 있다. 6까지 세면, 이 카운터는 다음과 같은 행동을 한다.
else if (en)
if (q == 3'b110)
begin
q <= q + 1'b1;
tco <= 1'b1;
end
else if (q == 3'b111)
begin
q <= 3'b000;
tco <= 1'b0;
end
7을 세었을 때, 0으로 초기화하는 행동과 다음 캐리를 내보내는 행동을 진행하지 않고 6부터 이 행동을 시작하는 것을 관찰할 수 있다. 이것은 카운터의 확장성과 관련이 있다. 카운터가 확장을 용이하게 하려면 동기형으로 진행되어야 하는데, 카운터가 만약 비동기형이라면 clk 신호가 따로따로 주어져야 하고, 3개가 연속으로 비동기형 카운터가 연결되었을 시, 신호가 한 템포 느려지는 현상이 발생하기 때문이다.
TestBench와 Gragh를 통해 확인해보자.
`timescale 1ns/1ps
module TB_cnt8;
reg clk, rst, en;
wire [2:0] q;
wire tco;
cnt8 U0 (.clk(clk), .rst(rst), .en(en), .q(q), .tco(tco));
always #5 clk = ~clk;
initial begin
clk = 1'b0;
rst = 1'b0;
en = 1'b1;
end
initial begin
rst = 1'b1; #20; rst = 1'b0;
end
initial begin
#50; en = 1'b0; #20; en = 1'b1;
end
endmodule
en은 여기서 이전 캐리가 넘어왔을 시, 동작할 수 있게 하는 tco의 명시적 연결형이다. 따라서, 다음 en은 tco이어야만 en이 1으로 진행하였을 때 동작하여 다음 카운터가 캐리를 받을 수 있다.
따라서 2주기 전에 tco를 1로 넘겨야 1주기 전에 tco에 반영되고, 다음 카운터의 en에 정확한 타이밍에 전달된다는 사실을 알 수 있다.