Basys3 보드에는 100MHz의 시계 크리스털(oscillator)이 탑재되어 있으며, 이 클럭은 FPGA 내부의 clk 입력 포트로 전달됩니다.

Vivado에서 사용하는 제약 파일(.xdc)에서도 이를 명확히 확인할 수 있는데, 아래 Basys-3-Master.xdc 파일을 확인해보면 create_clock 명령을 통해 -period 10.00으로 설정되어 있어 클럭의 주기가 10ns, 즉 100MHz 클럭인 것을 확인할 수 있습니다.

// Basys-3-Master.xdc
## Clock signal
set_property -dict { PACKAGE_PIN W5   IOSTANDARD LVCMOS33 } [get_ports clk]
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clk]

⚠️ 그런데 왜 클럭을 "나눠야" 할까?

❌ 고속 클럭 그대로 쓰면 생기는 문제

아래 코드는 실제로 회로 설계할 때 사용하는 정상적인 코드가 아닙니다. 단지 클럭을 그대로 출력에 연결하면 어떻게 보일까? 라는 개념을 설명하기 위한 비유적 예시라고 생각해보겠습니다.

assign led = clk;

Basys 3 보드에서 아래와 같이 코드를 작성하면 LED가 10ns마다 on/off합니다. 즉, 초당 50,000,000번 깜빡이는 셈입니다. 따라서 이 동작은 너무 빨라서 LED는 '항상 켜져 있는 것처럼' 보이게 되고 우리가 처음 설계하려고 했던 동작과 일치하지 않습니다.

❗ 그뿐만 아니라, 주변 장치들도 느립니다.

FPGA는 수백 MHz로 동작하지만, 연결되는 주변 장치들은 대부분 저속 디지털 기기입니다. 그래서 필요한 게 "클럭 분주기”입니다.

지금부터 설계하려는 클럭 분주기는 고속 클럭을 원하는 주기로 "나눠서" 사람 눈과 주변 장치가 이해할 수 있는 느린 속도로 만들어주는 회로입니다.

ℹ️ Verilog Code(clk_div3)

지금부터 설계하려는 clk_div클럭을 3으로 나누는 Clock Divider 회로이며, 양의 엣지(posedge)와 음의 엣지(negedge)를 모두 활용한 분주기입니다.

clk_div 모듈은 input으로 100MHz인 clk와 초기화 신호인 reset 신호를 받습니다. 출력은 3분주된 클럭인 clk_div3가 됩니다.

module clk_div (
    input  clk,
    input  reset,
    output clk_div3
);

아래 코드에서는 3비트 크기의 레지스터 두 개 r_countr_count_neg를 선언하여, 각각 클럭의 상승 엣지(posedge clk)와 하강 엣지(negedge clk)에서 동작하도록 구성되어 있습니다. 각 레지스터는 0부터 시작하여 1, 2까지 카운트한 뒤 다시 0으로 초기화되며, 즉 0 → 1 → 2 → 0의 순환을 반복하게 됩니다.

reg [2:0] r_count, r_count_neg;

아래 로직은 상승 엣지에서 카운트되는 r_count와, 하강 엣지에서 카운트되는 r_count_reg하나라도 값이 2에 도달했을 때 출력 신호 **clk_div3**을 HIGH로 설정합니다. 즉, 두 카운터가 각각 0 → 1 → 2 → 0 순으로 반복되며, 각각의 3번째 엣지마다 clk_div3가 한 번씩 HIGH가 됩니다.

assign clk_div3 = ((r_count == 2) | (r_count_neg == 2));

이 회로에서는 입력 클럭의 상승 엣지(posedge)와 하강 엣지(negedge)를 각각 감지하여 별도의 카운터를 사용합니다. 두 카운터 모두 0 → 1 → 2 → 0의 순환을 반복하며 3개 클럭 엣지를 기준으로 동작하도록 설계되어 있습니다.