module timer_top(
input clk, reset_p, // 시스템 클록과 비동기 리셋 입력 (reset_p: active-high)
input [3:0] btn, // 버튼 입력: [0] 시작/정지, [1] 초 증가, [2] 분 증가, [3] 알람 끄기
output [7:0] seg_7, // 7세그먼트 제어 신호 (a~g, dp)
output [3:0] com, // 7세그먼트 공통 단자
output reg alarm, // 알람 상태 출력 (1일 때 알람 울림)
output alarm_led, // 알람 상태를 LED로 출력
output start_led // 타이머 동작 상태를 LED로 출력
);
// 버튼 음에지(떼는 순간) 감지 신호
wire btn_start, btn_inc_sec, btn_inc_min, btn_alarm_off;
// 각 버튼에 대해 디바운서 + 네거티브 엣지 감지 모듈 인스턴스
button_cntr btn0(.clk(clk), .reset_p(reset_p), .btn(btn[0]), .btn_nedge(btn_start)); // 시작/정지 버튼
button_cntr btn1(.clk(clk), .reset_p(reset_p), .btn(btn[1]), .btn_nedge(btn_inc_sec)); // 초 증가 버튼
button_cntr btn2(.clk(clk), .reset_p(reset_p), .btn(btn[2]), .btn_nedge(btn_inc_min)); // 분 증가 버튼
button_cntr btn3(.clk(clk), .reset_p(reset_p), .btn(btn[3]), .btn_nedge(btn_alarm_off)); // 알람 끄기 버튼
// 현재 시간 및 저장 시간 관련 레지스터
wire [15:0] cur_time; // 현재 시간 (분:초를 16비트로 묶음)
reg [15:0] set_time; // 사용자가 시작 시점에 설정한 시간 저장
reg start_stop; // 타이머 동작 상태 (1: 작동 중, 0: 멈춤)
// LED 출력 신호 연결
assign alarm_led = alarm; // 알람이 켜지면 LED 점등
assign start_led = start_stop; // 타이머 작동 중일 때 LED 점등
// 타이머 상태 제어 로직 (시작, 정지, 알람 트리거)
always @(posedge clk, posedge reset_p) begin
if(reset_p) begin
start_stop = 0; // 정지 상태 초기화
alarm = 0; // 알람 초기화
set_time = 0; // 설정 시간 초기화
end
else if(btn_start && start_stop == 0 && cur_time != 0) begin
start_stop = 1; // 타이머 시작
set_time = cur_time; // 시작 시점의 시간을 저장
end
else if(btn_start && start_stop) begin
start_stop = 0; // 타이머 정지
end
else if({cnt_min, cnt_sec} == 0 && start_stop == 1) begin
start_stop = 0; // 시간이 0이 되면 정지
alarm = 1; // 알람 ON
end
else if(btn_alarm_off) begin
alarm = 0; // 알람 OFF
end
end
// 클록 카운터 및 시간 저장 레지스터
reg [26:0] cnt_sysclk; // 1Hz 분주용 카운터 (100MHz 기준이면 1초 = 99,999,999)
reg [7:0] cnt_sec, cnt_min; // 초 및 분 카운터
assign cur_time = {cnt_min, cnt_sec}; // 현재 시간 = 분(상위 8비트) + 초(하위 8비트)
// 시간 증가/감소 및 설정 복구 로직
always @(posedge clk, posedge reset_p) begin
if(reset_p) begin
cnt_sysclk = 0;
cnt_sec = 0;
cnt_min = 0;
end
else begin
if(start_stop) begin // 타이머 작동 중
if(cnt_sysclk >= 99_999_999) begin // 1초 경과
cnt_sysclk = 0;
if(cnt_sec == 0) begin
if(cnt_min == 1) begin
cnt_sec = 59;
cnt_min = cnt_min - 1;
end
// cnt_min == 0이면 그대로 유지 (알람 제어에서 종료됨)
end
else begin
cnt_sec = cnt_sec - 1;
end
end
else begin
cnt_sysclk = cnt_sysclk + 1;
end
end
else begin // 정지 상태에서는 시간 설정 가능
if(btn_inc_sec) begin
if(cnt_sec >= 59)
cnt_sec = 0;
else
cnt_sec = cnt_sec + 1;
end
else if(btn_inc_min) begin
if(cnt_min >= 99)
cnt_min = 0;
else
cnt_min = cnt_min + 1;
end
else if(btn_alarm_off) begin
// 알람을 끄면 마지막 설정 시간으로 복구
cnt_sec = set_time[7:0];
cnt_min = set_time[15:8];
end
end
end
end
// BCD 변환 및 7세그먼트 표시
wire [7:0] sec, min;
bin_to_dec bcd_sec(.bin(cnt_sec), .bcd(sec)); // 초 -> BCD 변환
bin_to_dec bcd_min(.bin(cnt_min), .bcd(min)); // 분 -> BCD 변환
// FND 표시: MMSS 포맷으로 출력
fnd_4digit_cntr fnd(
.clk(clk),
.reset_p(reset_p),
.value({min, sec}), // 4자리 FND: min(2자리), sec(2자리)
.seg_7(seg_7),
.com(com));
endmodule