이번 글에서는 베릴로그를 활용해 링 카운터를 설계하는 방법을 소개하고자 합니다. 링 카운터는 시프트 레지스터의 한 종류로 특정 비트가 회전하는 방식으로 동작하며 여러 디지털 시스템에서 사용됩니다.
가장 간단한 형태의 링 카운터는 4비트 시프트 레지스터를 사용하여 구현됩니다. 이 카운터는 특정 비트가 이동하며 순환하는 형태로 동작합니다.
module ring_counter(
input clk, reset_p,
output reg[3 : 0] q);
always @(posedge clk or posedge reset_p) begin
if(reset_p)
q <= 4'b0001;
else begin
case(q)
4'b0001: q <= 4'b0010;
4'b0010: q <= 4'b0100;
4'b0100: q <= 4'b1000;
4'b1000: q <= 4'b0001;
endcase
end
end
endmodule
이 코드에서는 q가 클럭 신호에 따라 이동하며 리셋 신호가 들어오면 q는 초기화 됩니다.
시뮬레이션 결과입니다. counter가 순차적으로 돌아가는 모습을 볼 수 있습니다.
여기서는 LED제어를 위해 링 카운터를 조금 더 확장해 봅니다. 이 카운터는 16개의 LED를 순차적으로 켜고 끄는 역할을 합니다.
module ring_counter_led(
input clk, reset_p,
output reg [15:0] led);
reg [20:0] clk_div;
always @(posedge clk) clk_div <= clk_div + 1;
wire clk_div_nedge;
edge_detector_p ed(.clk(clk), .reset_p(reset_p), .cp(clk_div[20]), .n_edge(clk_div_nedge));
always @(posedge clk or posedge reset_p)begin
if(reset_p)
led <= 16'b0000_0000_0000_0001;
else if(clk_div_nedge) begin
if(led == 16'b1000_0000_0000_0000)
led <= 16'b0000_0000_0000_0001;
else
led <= {led[14:0], 1'b0};
end
end
endmodule
여기서 우리는 clk_div를 사용하여 클럭 신호를 나눠줍니다. edge_detecter_p모듈은 클럭 신호의 하강 엣지를 검출하여 LED제어를 더욱 안정적으로 만듭니다.
다음으로 시프트 연산을 활용한 링 카운터를 살펴보겠습니다. 이 방식을 비트를 왼쪽으로 이동시키며 마지막 비트를 첫 번째 위치로 순환시킵니다.
module ring_counter_shift(
input clk, reset_p,
output reg[3 : 0] q);
always @(posedge clk or posedge reset_p) begin
if(reset_p)
q <= 4'b0001;
else begin
if(q == 4'b1000)
q <= 4'b0001;
else
q <= {q[2:0], 1'b0};
end
end
endmodule
이 방법을 간단하면서도 효율적으로 링 카운터를 구현할 수 있는 방법입니다.
module ring_counter_fnd(
input clk, reset_p,
output reg[3 : 0] com);
reg [20 : 0] clk_div = 0;
always @(posedge clk) clk_div <= clk_div + 1;
wire clk_div_nedge;
edge_detector_p ed (.clk(clk), .reset_p(reset_p), .cp(clk_div[16]), .n_edge(clk_div_nedge));
always @(posedge clk or posedge reset_p) begin
if(reset_p)
com <= 4'b1110;
else if(clk_div_nedge) begin
if(com == 4'b0111)
com <= 4'b1110;
else
com <= {com[2:0], 1'b1};
end
end
endmodule