플립플랍(flip-flop)
플립플랍은 디지털 시스템에서 매우 많이 쓰이는 기억 소자입니다. 현재 상태나 계산 결과 등등 다양한 정보를 저장해야 할 때 다양한 기억 소자(memory element)를 사용할 수 있지만, 가장 쉽게 사용할 수 있는 기억 소자가 플립플랍입니다. 이번 글에서는 플립플랍에 대해서 설명드립니다. 플립플랍은 줄여서 그냥 플랍이라고만 말하기도 해요.
D, JK, T 플립플랍 등등 많은 종류의 플립플랍들이 있는데, 우선은 D 플립플랍만 알고 계셔도 됩니다. RTL 설계에서 다른 플립플랍들은 요즘에는 거의 신경 쓰지 않아요. 나중에 필요할 때 배우셔도 됩니다.
D Flip-flop (FF)
1bit — 0 또는 1을 저장할 수 있는 기억 소자입니다. 플립플랍들이 많이 모이면 8bit, 256bit 등 더 큰 데이터를 저장할 수 있겠죠? 참고로, 플립플랍들의 묶음은 레지스터라고 부릅니다.
그림으로는 아래와 같이 표현합니다. 왼쪽은 동기 리셋(synchronous reset)을 사용하는 플립플랍, 오른쪽은 비동기 리셋(asynchronous reset)을 사용하는 플립플랍입니다. 리셋에 대해서는 아래에서 더 자세하게 설명드릴게요.
입력은 D, CLK, Reset이고 출력은 Q이에요. 각 핀의 의미를 알아볼까요?
D (Data)
데이터 입력입니다. 0을 저장하고 싶으면 low, 1을 저장하고 싶으면 high 신호를 주면 됩니다.
Q (Output)
데이터 출력입니다. 플립플랍에 저장되어 있는 데이터가 출력되고 있습니다.
CLK (Clock)
우리가 데이터를 저장할 때 ‘저장 버튼’을 누를 때가 있습니다. CLK는 저장 버튼과 같은 역할을 한다고 생각하시면 됩니다. D 입력이 연속적으로 변하더라도 CLK 신호의 엣지에서만 데이터가 저장됩니다.
클럭의 엣지에서만 데이터가 저장된다는 건 매우 중요해요. 모든 플립플랍 등의 기억 소자의 값이 클럭 신호에 동기화되어 업데이트된다는 점은 매우 큰 장점입니다. 클럭 신호와 관계없이 값이 업데이트된다면 타이밍 계산이나 피드백 관련 문제 등등 많은 설계상의 어려움이 발생해요. 참고로, 플립플랍과 비슷하지만 클럭에 관계없이 신호 레벨에 따라 값을 저장하는 기억 소자를 래치라고 합니다. 그래서 보통 디지털 회로를 설계할 때는 래치 사용을 피합니다.
클럭 엣지는 positive edge(rising edge)와 negative edge(faling edge) 두 가지가 있어요. positive edge는 신호가 low에서 high로 올라갈 때, negative edge는 신호가 high에서 low로 내려갈 때를 말합니다. 아래 그림은 positive edge에서 데이터를 저장하는 플립플랍의 waveform입니다. Positive edge에서의 D 입력이 약간의 딜레이 이후 Q에서 출력되는 것을 볼 수 있습니다.
Reset
디지털 시스템의 전원을 처음 켰을 때 플립플랍에는 어떤 데이터가 저장되어 있을까요? 정답은 아무도 모릅니다. 어떤 플립플랍에는 0이 저장되어 있을 수 있고 다른 플립플랍에는 1이 저장되어 있을 수도 있어요. 이게 문제가 없는 경우도 있을 수 있지만 State machine과 같은 어떤 로직에게는 처음에 저장되어 있는 값이 매우 중요한 경우도 있습니다. 따라서 플립플랍들을 초기화해주기 위한 리셋 기능이 필요합니다.
리셋 없는 플립플랍을 사용하는 경우도 있습니다만, 이 글을 읽는 여러분은 이제 디지털 회로 설계를 공부하기 시작한 분이겠죠? 그런 분들은 리셋 없는 플립플랍은 생각하지 마시고 항상 리셋이 있는 플립플랍을 사용하시기 바랍니다. 리셋 없는 플립플랍을 사용할 때 실수가 많이 발생하기 때문입니다. 다시 한번 강조하지만 항상 리셋을 사용하세요.
위에서 언급했듯이 리셋 방식에는 sync reset과 async reset이 있습니다. 학생분들은 FPGA 많이 사용하실텐데, AMD FPGA의 경우 sync reset을 권장합니다.
각각의 방법들과 코드에 대해 더 자세히 설명드리겠습니다.
Synchrounous reset (동기 리셋)
클럭의 엣지에서 reset 신호에 따라 mux에서 0 또는 d가 출력되어 플립플랍의 입력으로 들어갑니다. Verilog 코드는 아래와 같이 작성합니다.
// synchronous reset을 사용하는 플립플랍
// clk의 positive edge에서 rst_n 신호가 low이면 0, high면 d가 저장됩니다.
reg q;
always@(posedge clk) begin
if(!rst_n) q <= 0;
else q <= d;
end
Asynchronous reset (비동기 리셋)
Asynchronous라는 말은 클럭 신호와 관계없이 reset 신호가 active 상태일 때 초기화된다는 뜻이에요. Reset 신호가 low일 때 초기화되는 active-low asyncronous reset 플립플랍의 verilog 코드는 아래와 같이 표현합니다.
// active-low asynchronous reset을 사용하는 플립플랍
// 클럭 신호와 관계없이 rst_n 신호가 low일 때 q가 0으로 초기화됩니다.
reg q;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) q <= 0;
else q <= d;
end
몰라도 되는 사소한 이야기
그런데 위에 코드에서 이상한 점이 있습니다. async reset은 edge sensitive가 아니라 level sensitive입니다. 이 말은 리셋 신호가 active 상태라면 입력과 클럭 신호와 관계없이 항상 리셋 상태를 유지한다는 말입니다. 그런데 코드를 보면 sensitivity list에 rst_n 신호의 negedge가 들어가 있죠. 코드는 마치 rst_n의 negative edge에서만 리셋되는 것처럼 작성되어 있네요? 분명 async reset은 edge sensitive가 아니라 level sensitive 한 동작일 텐데요.
이유는 verilog 언어 자체가 event에 기반한 시뮬레이션 언어이기 때문에, 시뮬레이션의 한계 또는 편의를 위해 위와 같이 표현합니다. 위의 방식으로 코드를 작성하시면 툴이 알아서 level sensitive 한 async reset을 사용하는 회로로 합성해 줍니다.
출처 : https://www.edaboard.com/threads/verilog-edge-sensitive-reset.258930/
Implementation
Gate level에서는 여러 방식으로 D flip-flop을 구현할 수 있습니다. RTL(Register Transfer Level)에서 설계를 한다면 플립플랍이 어떤 방식으로 게이트로 구현될지는 logic synthesis 툴이 알아서 결정하겠죠? Edge-triggered D flip-flop이나 Master–slave D flip-flop 등의 더 자세한 구현 방식이 궁금하시다면 Wikipedia — flip-flop을 참고해 보세요.
Leave a comment