728x90
반응형
[오류 발생한 Part 체크]
📌 Simulation을 이용한 방법
테스트벤치를 만들어 오류가 발생한 part를 체크하고 수정할 수 있다.
📌 LED를 이용한 방법
가장 쉽고 간단한 방법이다.
시뮬레이션을 활용하려면, 테스트벤치를 만들고 레지스터 등록하는 등 해줘야할 것이 많다.
하지만 LED를 각 모듈의 출력과 연결시켜서 테스트하면,
LED가 들어오지 않는 곳이 오류가 발생한 부분이므로 오류를 쉽게 도출해낼 수 있다.
// LED를 활용한 오류 도출 방법
assign LED_bar[0] = lap_input; // 버튼을 누르면 LED_bar가 켜짐 -> 버튼 회로 문제 검출 과정
assign LED_bar[1] = lap_btn; // Edge Detector는 system clock 1만큼만 on되어서 눈으로 보기 어렵다.
assign LED_bar[2] = lap;
[Prescaler 간소화]
msec 모듈과 sec 모듈은 둘 다 1000분주하여 상위 단계의 clock을 출력해낸다.
따라서 1000분주 모듈을 만들어 인스턴스하여 사용하는 것으로 모듈을 간소화할 수 있다.
// 1000분주 clock
module clock_div_1000(
input clk, clk_source, reset_p,
output clk_div_1000
);
reg [8:0] cnt_clk_source;
reg cp_div_1000; // cp : clock pulse
always @(posedge clk, posedge reset_p) begin
if(reset_p) cnt_clk_source = 0; // reset이 들어오면 cnt = 0
else if(clk_source) begin
if (cnt_clk_source >= 499) begin
cnt_clk_source = 0; // 0부터 499번까지 카운트하면 다시 0으로
cp_div_1000 = ~cp_div_1000;
end
else cnt_clk_source = cnt_clk_source + 1;
end
end // 이렇게 카운트가 짝수일 경우, 위와 같이 코딩하여 1bit 줄일 수 있다.
// 비정규 clock이므로 동기화가 필요하다.
edge_detector_n edg_div_1000(.clk(clk), .cp_in(cp_div_1000), .rst(reset_p), .n_edge(clk_div_1000)); /// 안 쓰는 출력은 빼버리면 된다.
endmodule
// Prescaler Instance
wire clk_usec, clk_msec, clk_sec;
clock_usec_stopwatch usec_clk(.clk(clk), .reset_p(reset_p), .clk_usec(clk_usec));
clock_div_1000 msec_clk(.clk(clk), .clk_source(clk_usec), .reset_p(reset_p), .clk_div_1000(clk_msec));
clock_div_1000 sec_clk(.clk(clk), .clk_source(clk_msec), .reset_p(reset_p), .clk_div_1000(clk_sec));
clock_min min_clk(.clk(clk), .clk_sec(clk_sec), .reset_p(reset_p), .clk_min(clk_min));
[Mission]
📌 Mission
Q1.
: sec와 msec가 출력되는 Stopwatch의 Block Diagram을 그리고 해당 기능을 구현하여라.
Q2 - Advanced
: LED bar를 활용하여 min 단위를 출력하여라.
📌 Block Diagram
📌 Result(Counter 활용)
Clock Library
// Cora board sys clock : 125MHz
// 1 clock 당, 8ns
// Micro sec clock
module clock_usec_stopwatch(
input clk, reset_p,
input enable,
output clk_usec
);
// 125개 카운트하면 1us
reg [6:0] cnt_8nsec;
wire cp_usec; // cp : clock pulse
always @(posedge clk, posedge reset_p) begin
if(reset_p) cnt_8nsec = 0; // reset이 들어오면 cnt = 0
else if(cnt_8nsec >= 124) cnt_8nsec = 0; // 0부터 124번까지 카운트하면 다시 0으로
else cnt_8nsec = cnt_8nsec + 1;
end
assign cp_usec = cnt_8nsec < 63 ? 0 : 1; // 0~62 : 0, 63~124 : 1
// 비정규 clock이므로 동기화가 필요하다.
edge_detector_n edg(.clk(clk), .cp_in(cp_usec), .rst(reset_p), .n_edge(clk_usec)); /// 안 쓰는 출력은 빼버리면 된다.
endmodule
// min clock
module clock_min(
input clk, clk_sec, reset_p,
output clk_min
);
// 60개 카운트하면 1s
reg [5:0] cnt_sec;
reg cp_min; // cp : clock pulse
always @(posedge clk, posedge reset_p) begin
if(reset_p) cnt_sec = 0; // reset이 들어오면 cnt = 0
else if(clk_sec) begin
if (cnt_sec >= 29) begin
cnt_sec = 0; // 0부터 번까지 카운트하면 다시 0으로
cp_min = ~cp_min;
end
else cnt_sec = cnt_sec + 1;
end
end // 이렇게 카운트가 짝수일 경우, 위와 같이 코딩하여 1bit 줄일 수 있다.
// 비정규 clock이므로 동기화가 필요하다.
edge_detector_n edg_min(.clk(clk), .cp_in(cp_min), .rst(reset_p), .n_edge(clk_min)); /// 안 쓰는 출력은 빼버리면 된다.
endmodule
// 1000분주 clock
module clock_div_1000(
input clk, clk_source, reset_p,
output clk_div_1000
);
reg [8:0] cnt_clk_source;
reg cp_div_1000; // cp : clock pulse
always @(posedge clk, posedge reset_p) begin
if(reset_p) cnt_clk_source = 0; // reset이 들어오면 cnt = 0
else if(clk_source) begin
if (cnt_clk_source >= 499) begin
cnt_clk_source = 0; // 0부터 499번까지 카운트하면 다시 0으로
cp_div_1000 = ~cp_div_1000;
end
else cnt_clk_source = cnt_clk_source + 1;
end
end // 이렇게 카운트가 짝수일 경우, 위와 같이 코딩하여 1bit 줄일 수 있다.
// 비정규 clock이므로 동기화가 필요하다.
edge_detector_n edg_div_1000(.clk(clk), .cp_in(cp_div_1000), .rst(reset_p), .n_edge(clk_div_1000)); /// 안 쓰는 출력은 빼버리면 된다.
endmodule
Source_Counter
// 100bit_Counter
module counter_dec_100_stopwatch(
input clk, reset_p,
input clk_time,
output reg [3:0] dec1, dec10, dec100
);
always @(posedge clk, posedge reset_p) begin
if(reset_p) begin
dec1 = 0;
dec10 = 0;
dec100 = 0;
end
else if(clk_time) begin
if(dec1 >= 9) begin
dec1 <= 0;
if(dec10 >= 9) begin
dec10 = 0;
if(dec100 >= 9)
dec100 = 0;
else dec100 <= dec100 + 1;
end
else dec10 <= dec10 + 1;
end
else dec1 <= dec1 + 1;
end
end
endmodule
// 60bit_Counter
module counter_dec_60_stopwatch(
input clk, reset_p,
input clk_time,
output reg [3:0] dec1, dec10
);
always @(posedge clk, posedge reset_p) begin
if(reset_p) begin
dec1 = 0;
dec10 = 0;
end
else if(clk_time) begin
if(dec1 >= 9) begin
dec1 <= 0;
if(dec10 >= 5) dec10 = 0;
else dec10 <= dec10 + 1;
end
else dec1 <= dec1 + 1;
end
end
endmodule
StopWatch_Top
module Mission_Stop_Watch(
input clk,
input reset_p,
input [1:0] btn, // 버튼 2개 쓸 것이므로
output [3:0] com,
output [7:0] seg_7,
output reg [7:0] LED_bar
);
wire start_stop_input, start_stop, start_stop_btn;
// DFF를 위한 분주기
reg [16:0] clk_div;
always @(posedge clk) clk_div = clk_div + 1;
// Start_stop 기능 구현 - usec과 연결
D_flip_flop_n debnc_60(.d(btn[0]), .clk(clk_div[16]), .rst(reset_p), .q(start_stop_input)); // 바운싱 제거용 DFF
edge_detector_n edg_start_stop(.clk(clk), .cp_in(start_stop_input), .rst(reset_p), .n_edge(start_stop_btn)); // Edga Detector
t_flip_flop_p tff_start_stop(.clk(clk), .rst(reset_p), .t(start_stop_btn), .q(start_stop)); // start_stop 버튼 토글 기능
// Lap 기능 구현
wire lap_input, lap_btn, lap;
D_flip_flop_n debnc_lap(.d(btn[1]), .clk(clk_div[16]), .rst(reset_p), .q(lap_input)); // 바운싱 제거용 DFF
edge_detector_n edg_lap(.clk(clk), .cp_in(lap_input), .rst(reset_p), .n_edge(lap_btn)); // Edga Detector
t_flip_flop_p tff_lap(.clk(clk), .rst(reset_p), .t(lap_btn), .q(lap)); // 토글을 위한 TFF
// // 시뮬레이션보다 좀 더 간편한 방법.
// assign LED_bar[0] = lap_input; // 버튼을 누르면 LED_bar가 켜짐 -> 버튼 회로 문제 검출 과정
// assign LED_bar[1] = lap_btn; // Edge Detector는 system clock 1만큼만 on되어서 눈으로 보기 어렵다.
// assign LED_bar[2] = lap;
// 분주기 인스턴스
wire clk_usec, clk_msec, clk_sec;
wire clk_start;
assign clk_start = start_stop ? 0 : clk_usec;
clock_usec_stopwatch usec_clk(.clk(clk), .reset_p(reset_p), .clk_usec(clk_usec));
clock_div_1000 msec_clk(.clk(clk), .clk_source(clk_start), .reset_p(reset_p), .clk_div_1000(clk_msec));
clock_div_1000 sec_clk(.clk(clk), .clk_source(clk_msec), .reset_p(reset_p), .clk_div_1000(clk_sec));
clock_min min_clk(.clk(clk), .clk_sec(clk_sec), .reset_p(reset_p), .clk_min(clk_min));
// 카운터 인스턴스
wire [3:0] msec1, msec10, msec100;
counter_dec_100_stopwatch cnt_100_msec(.clk(clk), .reset_p(reset_p), .clk_time(clk_msec), .dec1(msec1), .dec10(msec10), .dec100(msec100));
wire [3:0] sec1, sec10; // sec1 : 1의자리, sec10 : 10의 자리
counter_dec_60_stopwatch cnt_60_sec(.clk(clk), .reset_p(reset_p), .clk_time(clk_sec), .dec1(sec1), .dec10(sec10)); // sec count
wire [3:0] min1, min10; // min1 : 1의자리, min10 : 10의 자리
counter_dec_60_stopwatch cnt_60_min(.clk(clk), .reset_p(reset_p), .clk_time(clk_min), .dec1(min1), .dec10(min10)); // min count
// Lap Value / value Select
reg [15:0] lap_value;
always @(posedge clk, posedge reset_p) begin
if(reset_p) lap_value = 0;
else if(lap_btn) // lap_btn 나올 때 저장
lap_value = {sec10, sec1, msec100, msec10};
end
// lap 버튼에 따른 FND 출력
wire [15:0] value;
assign value = lap ? lap_value : {sec10, sec1, msec100, msec10};
assign value = lap ? lap_value : {sec10, sec1, msec_b2d[11:4]};
FND_4digit_cntr fnd_cntr(.clk(clk), .rst(reset_p), .value(value), .com(com), .seg_7(seg_7)); /// 컨트롤러가 분주기 가지고 있으니 그냥 clk준다.
// min을 LED_bar를 통하여 출력
always @(posedge clk, posedge reset_p) begin
if(reset_p) LED_bar = 0;
for (integer i = 0; i < 8; i = i + 1) begin
LED_bar[i] = (min1 >= i + 1) ? 1 : 0;
end
end
endmodule
📌 Result(Bin_to_dec 활용)
Clock Library
위와 동일
Bin_to_dec
module bin_to_dec_stopwatch( //// 12bit binary를 받아서 16bit decimal로 변환
input [11:0] bin,
output reg [15:0] bcd /// 올림수가 하나만 나와도 4자리 다 읽어야 해서 vector : 16
);
reg [3:0] i;
always @(bin) begin //// FND 출력할 때 자주 써먹게 될 것임.
bcd = 0;
for (i=0 ; i<12 ; i=i+1) begin
bcd = {bcd[14:0], bin[11-i]}; //// 쉬프트 연산을 결합연산자로 표현(회로가 더 간단해진다.)
//// 좌로 1bit 쉬프트하고, 빈 자리에는 bin[11-i]를 넣어 준다.
if ( i < 11 && bcd[3:0] > 4) bcd[3:0] = bcd[3:0] + 3;
if ( i < 11 && bcd[7:4] > 4) bcd[7:4] = bcd[7:4] + 3;
if ( i < 11 && bcd[11:8] > 4) bcd[11:8] = bcd[11:8] + 3;
if ( i < 11 && bcd[15:12] > 4) bcd[15:12] = bcd[15:12] + 3;
end
end
endmodule
StopWatch_Top
module Mission_Stop_Watch(
input clk,
input reset_p,
input [1:0] btn, // 버튼 2개 쓸 것이므로
output [3:0] com,
output [7:0] seg_7,
output reg [7:0] LED_bar
);
wire start_stop_input, start_stop, start_stop_btn;
// DFF를 위한 분주기
reg [16:0] clk_div;
always @(posedge clk) clk_div = clk_div + 1;
// Start_stop 기능 구현 - usec과 연결
D_flip_flop_n debnc_60(.d(btn[0]), .clk(clk_div[16]), .rst(reset_p), .q(start_stop_input)); // 바운싱 제거용 DFF
edge_detector_n edg_start_stop(.clk(clk), .cp_in(start_stop_input), .rst(reset_p), .n_edge(start_stop_btn)); // Edga Detector
t_flip_flop_p tff_start_stop(.clk(clk), .rst(reset_p), .t(start_stop_btn), .q(start_stop)); // start_stop 버튼 토글 기능
// Lap 기능 구현
wire lap_input, lap_btn, lap;
D_flip_flop_n debnc_lap(.d(btn[1]), .clk(clk_div[16]), .rst(reset_p), .q(lap_input)); // 바운싱 제거용 DFF
edge_detector_n edg_lap(.clk(clk), .cp_in(lap_input), .rst(reset_p), .n_edge(lap_btn)); // Edga Detector
t_flip_flop_p tff_lap(.clk(clk), .rst(reset_p), .t(lap_btn), .q(lap)); // 토글을 위한 TFF
// 분주기 인스턴스
wire clk_usec, clk_msec, clk_sec;
wire clk_start;
assign clk_start = start_stop ? 0 : clk_usec;
clock_usec_stopwatch usec_clk(.clk(clk), .reset_p(reset_p), .clk_usec(clk_usec));
clock_div_1000 msec_clk(.clk(clk), .clk_source(clk_start), .reset_p(reset_p), .clk_div_1000(clk_msec));
clock_div_1000 sec_clk(.clk(clk), .clk_source(clk_msec), .reset_p(reset_p), .clk_div_1000(clk_sec));
clock_min min_clk(.clk(clk), .clk_sec(clk_sec), .reset_p(reset_p), .clk_min(clk_min));
reg [9:0] cnt_clk_msec;
always @(posedge clk, posedge reset_p) begin
if(reset_p) cnt_clk_msec = 0; // reset이 들어오면 cnt = 0
else if(clk_msec) begin
if (cnt_clk_msec >= 999) begin
cnt_clk_msec = 0;
end
else cnt_clk_msec = cnt_clk_msec + 1;
end
end
wire [15:0] msec_b2d;
bin_to_dec_stopwatch msec_clk_b2d(.bin({2'b00, cnt_clk_msec}), .bcd(msec_b2d));
// 카운터 인스턴스
wire [3:0] sec1, sec10; // sec1 : 1의자리, sec10 : 10의 자리
counter_dec_60_stopwatch cnt_60_sec(.clk(clk), .reset_p(reset_p), .clk_time(clk_sec), .dec1(sec1), .dec10(sec10)); // sec count
wire [3:0] min1, min10; // min1 : 1의자리, min10 : 10의 자리
counter_dec_60_stopwatch cnt_60_min(.clk(clk), .reset_p(reset_p), .clk_time(clk_min), .dec1(min1), .dec10(min10)); // min count
// Lap Value / value Select
reg [15:0] lap_value;
always @(posedge clk, posedge reset_p) begin
if(reset_p) lap_value = 0;
else if(lap_btn) // lap_btn 나올 때 저장
lap_value = {sec10, sec1, msec_b2d[11:4]};
end
// lap 버튼에 따른 FND 출력
wire [15:0] value;
assign value = lap ? lap_value : {sec10, sec1, msec_b2d[11:4]};
FND_4digit_cntr fnd_cntr(.clk(clk), .rst(reset_p), .value(value), .com(com), .seg_7(seg_7)); /// 컨트롤러가 분주기 가지고 있으니 그냥 clk준다.
// min을 LED_bar를 통하여 출력
always @(posedge clk, posedge reset_p) begin
if(reset_p) LED_bar = 0;
for (integer i = 0; i < 8; i = i + 1) begin
LED_bar[i] = (min1 >= i + 1) ? 1 : 0;
end
end
endmodule
✅ Bin_to_Dec이 궁금하다면?
728x90
반응형