RTL Design/Verilog RTL 설계
Verilog RTL 설계(7월 16일 - 2, Prescaler)
유로 청년
2024. 7. 17. 11:31
1. Prescaler
- basys3의 기본 Clock Pulse의 주기는 10ns를 갖는다.
- 짧은 주기를 갖는 Clock pulse를 가지고 이보다 긴 펄스파형을 생성하거나 낮은 주파수를 갖는 파형을 생성하고 싶을 때, Prescaler 기법을 사용할 수 있다.
- Prescaler의 주요 기능에 대해서 요약하면 다음과 같다.
▶ 고주파 클럭 신호를 낮은 주파수를 갖는 신호로 변환하고자 하는 경우
▶ 짧은 주기를 갖는 클럭 신호를 상대적으로 더 긴 주기를 갖는 신호로 변환하고자 하는 경우
▶ 입력 클럭 주파수를 일정한 비율로 나누고자 하는 경우
- Q) Prescaler 기법은 어떻게 기본 Clock Pulse를 주기가 더 긴 파형으로 변환할 수 있는가?
A) 여러 개의 펄스 파형을 하나의 묶음으로 묶은 뒤, 이를 하나의 펄스 파형으로 인식하고, 이렇게 새롭게 정의된 펄스 파형을 Counting하게 되면 기본 Clock Pulse의 주기보다 긴 파형으로 변환할 수 있고, 이를 이용하여 Counter가 카운트 할 수 있는 범위를 늘릴 수 있다.
2. 100 분주비 (100 Prescaler)
- basys3는 기본 클럭 펄스의 주기는 10ns이다.
- basys3의 기본 클럭 펄스를 분주시켜 주기를 1us 갖는 새로운 펄스 파형을 만들고자 한다.
- 1us를 10ns로 나누게 되면 1us / 10ns = 100 이라는 값이 나오게 되며, 해당 값이 분주비가 되는 것이다.
- 주기가 10ns인 클럭을 100분주한다는 것은 하나의 10ns 펄스를 100개로 묶어 하나의 주기가 10ns인 새로운 펄스 만든다는 것을 의미한다,
- 따라서 주기가 10ns인 클럭을 100분주함으로서 주기가 1us인 펄스를 생성할 수 있는 것이다.
2.1. 그럼, 어떻게 분주를 통해 새로운 펄스파를 생성할 수 있는것인가?
- 바로 Counter를 사용하는 것이다.
- Clock Pulse의 edge을 감지하여 edge 마다 Counter값을 1씩 늘려간다.
- 따라서 Counter 값이 0 ~ 49일 때까지는 0을 출력하고, 50 ~ 99일 때까지는 1을 출력하게 되면 0 ~ 490ns 까지는 Low 레벨을 갖고, 500ns ~ 990ns 까지는 High 레벨을 갖는 1us 펄스파가 생성되게 된다.
- 위 과정을 통해 알 수 있듯이 이렇게 생성된 펄스파는 Duty cycle을 50% 갖게 된다.
2.2. Vivado를 통한 100 Prescale
< Source >
module Prescaler_100_CP_10ns(
input clk, enable, reset_p,
output clk_div_100 );
reg [6:0] counter;
always @(negedge clk or posedge reset_p) begin
if(reset_p) counter = 0;
else if(enable) begin
if(counter >=99) counter = 0;
else counter = counter + 1;
end
end
assign clk_div_100 = (counter <50) ? 0 : 1;
endmodule
- Q) counter는 얼마의 크기를 가져야 하는가?
- A) n bit 크기를 갖는 Counter는 0 부터 어디까지 카운트할 수 있는가? 0 ~ 2^n - 1까지 카운트가 가능하다.
ex) 4bit Counter는 0 ~ 15까지 카운트 가능하다.
10bit Counter는 0 ~ 1023까지 카운트 가능하다.
따라서 0 ~ 100까지 카운트를 하기 위해서 최소한 7bit counter 가져야 0 ~ 127까지 카운트가 가능해야
100까지의 카운트가 가능ㅎ다.
< Simulation >
- 시뮬레이션을 통해 주기가 10ns인 Clock Pulse을 100분주하여 새로 생성된 펄스 파형은 주기를 1us를 갖는 것을 확인할 수 있다.
3. 100 분주시켜 새롭게 생성된 파형에 Edge detector를 설치
- 위 구현에서는 주기가 10ns인 기본 클럭을 100 분주화하여 주기가 1us인 펄스 파형을 생성했다.
- 이번에는 새롭게 생성된 주기가 1us인 펄스 파형에 Negative edge detector를 달아 보겠다.
- 따라서 Negative edge detector는 1us마다 Negative edge가 발생할 때마다 One cycle pulse를 출력으로 내보낼 것이다.
< Source , Negative edge detector >
// Negative edge detector
module edge_detector_n (
input clk, reset_p,
input cp,
output n_edge );
reg flip_flop_current, flip_flop_old;
always @(negedge clk or posedge reset_p) begin
if(reset_p) begin
flip_flop_current <= 0;
flip_flop_old <= 0;
end
else begin
flip_flop_current <= cp;
flip_flop_old <= flip_flop_current;
end
end
assign n_edge = ({flip_flop_current, flip_flop_old} == 2'b01)? 1 : 0;
endmodule
- Edge detector의 개념 및 설계는 아래 게시글 참고 바란다.
Verilog RTL 설계(7월 12일 - 6, Edge detector) (tistory.com)
Verilog RTL 설계(7월 12일 - 6, Edge detector)
flip_flop_current = cp;flip_flop_old = flip_flop_current;1. Verilog에서 동기순차회로를 설계할 때에는 Clock Pulse와 Reset만 Sensitive variable로 사용하고, 나머지 변수에 대해서는 Sensitive variable로 사용하지 않는다.PD
jbhdeve.tistory.com
< Source , Prescaler 100 >
// Prescaler 100
module Prescaler_100_One_Cycle_Pulse (
input clk, reset_p,
output clk_div_100,
output clk_div_100_nedge );
reg [6:0] count;
always @(posedge clk or posedge reset_p) begin
if(reset_p) count = 0;
else begin
if(count >= 99) count = 0;
else count = count + 1;
end
end
assign clk_div_100 = (count < 50)? 0 : 1;
edge_detector_n negative_edge_detector (clk, reset_p, clk_div_100, clk_div_100_nedge);
endmodule
- CP 값으로 100 분주를 통해 새로 생성된 주기가 1us인 파형을 argument 값으로 넘겨준다.
- negative edge detector로 clk_div_100_nedge 값을 argument으로 넘겨주면 clk_div_100_nedge는 Negative edge 때마다 One Cycle Pulse를 발생시켜 출력시키게 된다.
< Simulation >
4. 100분주한 뒤, 다시 1000분주 시켜 주기가 1ms인 파형을 생성하기
- 주기가 10ns인 기본 클럭을 100분주화하여 주기가 1us인 펄스 파형을 생성하였고, 이를 Negative edge detector를 통해 Negative edge 때마다 One cycle pulse를 출력했다.
- 이번에는 이렇게 1us 펄스에서 negative edge 때마다 negative edge detector가 내보내는 One cycle pulse를 감지하여 해당 값이 1일 때마다 1씩 카운트하겠다.
- Counter는 0 ~ 999까지 Counting할 수 있어야 하기 때문에 Counter의 크기는 최소 10bit 이상을 가져야 하며, 0 ~ 499까지는 Low 레벨을 출력하며, 500 ~ 999까지는 High 레벨을 출력한다.
- 따라서 100분주된 주기가 1us인 펄스파를 다시 1000분주 하였기 때문에 새로 생성된 파형은 10ns * 100 * 1000 = 1ms 주기를 갖는다.
- 마지막으로, 100분주하고, 다시 1000분주하여 새롭게 생성된 클럭 펄스는 1ms의 주기를 가지며, 이를 다시 Negative edge detector를 사용하여 1ms 마다 발생하는 Negative edgd에서 One cycle pulse를 발생시키도록 할 것이다.
< Source , Negative edge detector >
module edge_detector_n_new (
input clk, enable, reset_p,
input cp,
output n_edge );
reg flip_flop_current, flip_flop_old;
always @(negedge clk or posedge reset_p) begin
if(reset_p) begin
flip_flop_current <= 0;
flip_flop_old <= 0;
end
else if(enable) begin
flip_flop_current <= cp;
flip_flop_old <= flip_flop_current;
end
end
assign n_edge = ({flip_flop_current, flip_flop_old} == 2'b01) ? 1 : 0;
endmodule
< Source , Prescaler 1000 >
module Prescaler_1000_CP_10ns_One_Cycle_Pulse(
input clk, enable, reset_p,
input clk_div_100,
output clk_div_1000,
output clk_div_1000_nedge);
reg [9:0] counter;
// 100분주를 통해 생성된 주기 1us인 파형의 하강 엣지에서 출력되는 One cycle detector
wire detect_One_Cycle_Pulse;
// 주기가 1us인 펄스 파의 negative edge 감지.
edge_detector_n_new negative_edge_detector_0 (clk, enable, reset_p, clk_div_100, detect_One_Cycle_Pulse);
always @(negedge clk or posedge reset_p) begin
if(reset_p) counter <= 0;
else if(enable && detect_One_Cycle_Pulse) begin
if(counter >= 999) counter = 0;
else counter = counter + 1;
end
end
// 1000분주를 통해 생성된 주기가 1ms인 파형
assign clk_div_1000 = (counter <= 499) ? 0 : 1;
// 주기가 1ms인 파형의 하강엣지에서 출력되는 One cycle detector
edge_detector_n_new negative_edge_detector_1 (clk, enable, reset_p, clk_div_1000, clk_div_1000_nedge);
endmodule
< Analysis Source Code >
- 변수들의 기능 및 역활은 다음과 같다.
- clk_div_100은 주기가 10ns인 CP를 100분주하여 주기가 1us인 펄스파형을 의미한다.
- clk_div_1000은 주기가 1us인 Pulse를 1000분주하여 주기가 1ms인 펄스파형을 의미한다.
- clk_div_1000_nedge는 clk_div_1000을 Negative edge detector에 넣어 Negative edge 때마다 발생되는 One Cycle Pulse 파형을 의미한다.
- detect_One_Cycle_Pulse는 주기가 1us인 Pulse를 Negative edge detector에 넣어 Negative edge 때마다 발생되는 One Cycle Pulse 파형을 의미한다. - 위 코드의 알고리즘은 다음과 같다.
- 1단계) 주기가 10ns인 기본 클럭을 100분주하여 주기가 1us인 펄스 파를 생성한다. (생략)
- 2단계) Negative edge detector에 CP 값으로 주기가 1us인 펄스 파를 넣어 하강 엣지때마다 One Cycle Pulse을 발생시키도록 한 뒤, One Cycel Pulse를 detect_One_Cycle_Pulse 변수가 받기.
- 3단계) detect_One_Cycle_Pulse 변수 값이 1일 때마다 Counter가 1씩 증가하기.
- 4단계) assign clk_div_1000 = (counter <= 499) ? 0 : 1; 명령문을 통해 주기가 1ms인 파형을 출력
- 5단계) 주기가 1ms인 파형을 Negative edge detector에 CP 값으로 넣어서 하강 엣지때마다 One Cycle Pulse을 발생시키도록 한 뒤, One Cycel Pulse를 clk_div_1000_nedge 변수가 받아서 출력으로 내보내기.
< Simulation >
- 1000분주를 통해 생성된 파형은 1ms 마다 하강 엣지가 발생하기 때문에 이를 Negative edge detector가 감지하여 One Cycle Pulse를 1ms마다 출력시키는 것을 확인할 수 있다.