7-2. FSM 설계 예제: 시퀀스 감지기
1. 시퀀스 감지기 개요
유한 상태 기계 (Finite State Machine, FSM)는 다양한 디지털 시스템의 동작을 모델링하고 구현하는 데 매우 유용한 도구입니다. FSM은 상태(State), 입력(Input), 출력(Output) 및 전이(Transition)로 구성됩니다. FSM은 입력에 따라 상태를 변경하고, 현재 상태에 따라 출력을 생성합니다. 이러한 특성 덕분에 FSM은 제어 시스템, 통신 프로토콜, 그리고 특히 시퀀스 감지와 같은 복잡한 동작을 설계하는 데 널리 사용됩니다.
시퀀스 감지기는 특정 입력 시퀀스를 감지하는 FSM의 한 유형입니다. 예를 들어, 디지털 통신 시스템에서 특정 비트 시퀀스를 감지하거나, 보안 시스템에서 비밀번호를 입력하는 것을 감지하는 데 사용될 수 있습니다. 본 글에서는 시퀀스 감지기의 개념과 설계 방법을 자세히 살펴보고, 이를 Verilog를 사용하여 구현하는 방법을 예제를 통해 알아보겠습니다.
2. 시퀀스 감지기 동작 원리
시퀀스 감지기는 입력 데이터 스트림에서 미리 정의된 시퀀스를 감지하는 회로입니다. 이는 입력 비트 스트림을 분석하여 감지하려는 시퀀스가 나타나는지 여부를 결정합니다. 감지된 경우, 특정 신호를 활성화하여 감지를 나타냅니다. 시퀀스 감지기는 일반적으로 두 가지 유형의 출력을 제공합니다.
- 감지 신호: 시퀀스가 감지되었음을 나타내는 신호.
- 리셋 신호 (선택 사항): 감지된 시퀀스 이후 감지기를 초기 상태로 되돌리는 신호.
시퀀스 감지기의 핵심은 상태와 전이입니다. 상태는 감지기가 현재 인식하고 있는 시퀀스의 상태를 나타냅니다. 전이는 입력에 따라 상태를 변경하는 규칙을 정의합니다. 이러한 상태와 전이의 조합을 통해 감지기는 입력 시퀀스를 추적하고, 원하는 시퀀스가 나타났을 때 감지 신호를 활성화할 수 있습니다.
1) 예시: "101" 시퀀스 감지
"101" 시퀀스를 감지하는 간단한 시퀀스 감지기를 생각해 봅시다. 이 감지기는 다음과 같은 상태를 가질 수 있습니다.
S0: 초기 상태. 어떤 비트도 감지되지 않음.S1: "1"을 감지함.S2: "10"을 감지함.S3: "101"을 감지함 (감지 완료).
입력 비트에 따른 상태 전이는 다음과 같이 정의됩니다.
S0: 입력이 "1"이면S1으로, "0"이면S0으로 유지.S1: 입력이 "0"이면S2로, "1"이면S1으로 유지.S2: 입력이 "1"이면S3로, "0"이면S0으로.S3: 감지 완료 (감지 신호 활성화). 다음 입력을 받으면S1으로 이동하여 새로운 시퀀스 감지 시작.
3. 상태 다이어그램 및 Verilog 코드
시퀀스 감지기 설계를 위해서는 상태 다이어그램을 먼저 설계하는 것이 일반적입니다. 상태 다이어그램은 FSM의 동작을 시각적으로 표현하여 설계 프로세스를 용이하게 합니다. 상태 다이어그램을 바탕으로 Verilog 코드를 작성하여 하드웨어로 구현할 수 있습니다.
1) 상태 다이어그램
위에서 언급한 "101" 시퀀스 감지기의 상태 다이어그램은 다음과 같습니다.

위 다이어그램에서, 원은 상태를 나타내고, 화살표는 상태 전이를 나타냅니다. 각 화살표는 입력 비트(0 또는 1)에 따라 어떤 상태로 이동하는지를 나타냅니다. S3 상태에 도달하면 시퀀스가 감지되었음을 의미하며, 감지 신호 (예: detect)를 활성화합니다.
2) Verilog 코드
위의 상태 다이어그램을 바탕으로 Verilog 코드를 작성할 수 있습니다. 다음은 "101" 시퀀스 감지기의 Verilog 코드 예시입니다.
module sequence_detector (
input logic clk,
input logic rst,
input logic data_in,
output logic detect
);
// 상태 정의
typedef enum logic [1:0] {
S0, // 초기 상태
S1, // "1" 감지
S2, // "10" 감지
S3 // "101" 감지 (시퀀스 감지)
} state_type;
state_type current_state, next_state;
// 출력 초기화
always_ff @(posedge clk or posedge rst) begin
if (rst) begin
current_state <= S0;
detect <= 1'b0;
end else begin
current_state <= next_state;
end
end
// 상태 전이 로직
always_comb begin
next_state = current_state; // 기본값: 현재 상태 유지
detect = 1'b0; // 기본값: 감지 안 됨
case (current_state)
S0: begin
if (data_in) next_state = S1;
end
S1: begin
if (data_in) next_state = S1;
else next_state = S2;
end
S2: begin
if (data_in) begin
next_state = S3;
end else begin
next_state = S0;
end
end
S3: begin
detect = 1'b1;
next_state = S1; // 다음 시퀀스를 위해 S1으로
end
endcase
end
endmodule
위 코드에서 current_state는 현재 상태를 저장하는 레지스터이며, next_state는 다음 상태를 계산하는 조합 논리입니다. always_ff 블록은 클럭의 상승 에지 또는 리셋 신호에 반응하여 상태를 업데이트합니다. always_comb 블록은 상태 전이 로직을 구현합니다. case 문을 사용하여 현재 상태와 입력에 따라 다음 상태를 결정하고, 감지 신호를 적절하게 설정합니다.
4. 코드 설명 및 동작 원리
1) 모듈 선언 및 포트 정의
module sequence_detector(...) 문은 모듈의 시작을 정의합니다. 모듈은 독립적인 하드웨어 블록으로, 입출력 포트를 통해 다른 모듈과 연결됩니다. 위 코드에서는 다음과 같은 입출력 포트를 정의합니다.
input logic clk: 클럭 입력. 모든 순차 로직을 동기화합니다.input logic rst: 리셋 입력. 시스템을 초기 상태로 만듭니다.input logic data_in: 데이터 입력. 감지할 비트 시퀀스를 입력받습니다.output logic detect: 감지 출력. 시퀀스가 감지되면 활성화됩니다.
2) 상태 정의
typedef enum logic [1:0] {
S0, // 초기 상태
S1, // "1" 감지
S2, // "10" 감지
S3 // "101" 감지 (시퀀스 감지)
} state_type;
typedef enum 문은 FSM의 상태를 정의합니다. enum은 각 상태에 고유한 이름을 할당하여 코드를 더 읽기 쉽게 만듭니다. logic [1:0]은 각 상태를 2비트로 표현함을 의미합니다.
3) 상태 변수 및 출력 변수 선언
state_type current_state, next_state;는 현재 상태와 다음 상태를 저장하는 데 사용되는 변수를 선언합니다. detect는 감지 신호를 나타내는 출력 변수입니다.
4) 순차 로직 (상태 업데이트)
always_ff @(posedge clk or posedge rst) begin
if (rst) begin
current_state <= S0;
detect <= 1'b0;
end else begin
current_state <= next_state;
end
end
always_ff 블록은 플립플롭을 모델링합니다. 이 블록은 클럭의 상승 에지 (posedge clk) 또는 리셋 (posedge rst) 신호에 의해 트리거됩니다.
rst가 활성화되면 (rst <mark class="highlight"> 1),current_state는 초기 상태인S0으로 초기화되고,detect는 0으로 초기화됩니다.rst가 비활성화되면 (rst </mark> 0),current_state는next_state의 값으로 업데이트됩니다.
5) 조합 로직 (상태 전이 및 출력 결정)
always_comb begin
next_state = current_state; // 기본값: 현재 상태 유지
detect = 1'b0; // 기본값: 감지 안 됨
case (current_state)
S0: begin
if (data_in) next_state = S1;
end
S1: begin
if (data_in) next_state = S1;
else next_state = S2;
end
S2: begin
if (data_in) begin
next_state = S3;
end else begin
next_state = S0;
end
end
S3: begin
detect = 1'b1;
next_state = S1; // 다음 시퀀스를 위해 S1으로
end
endcase
end
always_comb 블록은 조합 논리를 모델링합니다. 이 블록은 입력 (data_in, current_state)의 변화에 따라 즉시 실행됩니다.
next_state와detect는 초기값으로 각각current_state와 0으로 설정됩니다. 이는 기본적으로 상태가 변경되지 않고 감지되지 않음을 의미합니다.case문은 현재 상태에 따라 다음 상태와 출력을 결정합니다. 예를 들어, 현재 상태가S0이고data_in이 1이면,next_state는S1이 됩니다.S3상태에서는detect가 1로 설정되어 시퀀스가 감지되었음을 나타냅니다. 또한,S3에서 다음 시퀀스 감지를 위해next_state는S1으로 설정됩니다.
5. 시뮬레이션 및 테스트
Verilog 코드를 작성한 후에는 시뮬레이션을 통해 동작을 검증해야 합니다. 시뮬레이션은 코드의 정확성을 확인하고, 하드웨어에서 예상대로 작동하는지 확인하는 중요한 단계입니다.
1) 테스트벤치 작성
테스트벤치는 시뮬레이션을 위한 환경을 제공합니다. 여기에는 클럭 신호 생성, 리셋 신호 설정, 입력 데이터 제공, 그리고 출력 신호 확인 등이 포함됩니다. 다음은 "101" 시퀀스 감지기를 위한 간단한 테스트벤치 예시입니다.
module sequence_detector_tb;
// 시뮬레이션 파라미터
parameter CLK_PERIOD = 10; // 클럭 주기 (10ns)
// 신호 선언
logic clk;
logic rst;
logic data_in;
logic detect;
// DUT (Device Under Test) 인스턴스
sequence_detector uut (
.clk(clk),
.rst(rst),
.data_in(data_in),
.detect(detect)
);
// 클럭 생성
always # (CLK_PERIOD / 2) clk = ~clk;
// 초기화 및 리셋
initial begin
clk = 0;
rst = 1;
# (CLK_PERIOD * 2) // 리셋 기간
rst = 0;
end
// 입력 데이터 시퀀스 및 검증
initial begin
// 테스트 케이스 1: "101" 감지
data_in = 1'b0; # CLK_PERIOD;
data_in = 1'b1; # CLK_PERIOD;
data_in = 1'b0; # CLK_PERIOD;
data_in <mark class="highlight"><strong><u> 1'b1; # CLK_PERIOD; // detect </u></strong></mark> 1 (시퀀스 감지)
$display("Test Case 1: detect = %b", detect);
// 테스트 케이스 2: "1101" 감지
data_in = 1'b1; # CLK_PERIOD;
data_in = 1'b1; # CLK_PERIOD;
data_in = 1'b0; # CLK_PERIOD;
data_in <mark class="highlight"><strong><u> 1'b1; # CLK_PERIOD; // detect </u></strong></mark> 1 (시퀀스 감지)
$display("Test Case 2: detect = %b", detect);
// 테스트 케이스 3: "0000" (시퀀스 미감지)
data_in = 1'b0; # CLK_PERIOD;
data_in = 1'b0; # CLK_PERIOD;
data_in = 1'b0; # CLK_PERIOD;
data_in <mark class="highlight"><strong><u> 1'b0; # CLK_PERIOD; // detect </u></strong></mark> 0 (시퀀스 미감지)
$display("Test Case 3: detect = %b", detect);
$finish;
end
endmodule
위 테스트벤치는 다음과 같은 기능을 수행합니다.
- 클럭 신호 생성:
always블록을 사용하여 클럭 신호를 생성합니다. - 리셋 신호:
initial블록을 사용하여 리셋 신호를 설정합니다. - 입력 데이터 설정:
initial블록 내에서data_in신호를 설정하여 다양한 입력 시퀀스를 시뮬레이션합니다. - 출력 검증:
$display를 사용하여detect신호의 값을 확인합니다.
2) 시뮬레이션 결과
테스트벤치를 실행하면 시뮬레이터는 입력 데이터에 따라 detect 신호의 변화를 보여줍니다. "101" 시퀀스가 입력되면 detect가 1로 설정되고, 그렇지 않은 경우에는 0으로 유지됩니다. 시뮬레이션 결과를 통해 코드의 정확성을 확인할 수 있습니다.
6. 고급 설계 고려 사항
1) 중첩 시퀀스 감지
더 복잡한 시퀀스 감지기를 설계할 수 있습니다. 예를 들어, "10110"과 같은 더 긴 시퀀스를 감지하거나, 중첩된 시퀀스를 감지할 수 있습니다. 중첩 시퀀스 감지의 경우, "101101"과 같은 시퀀스를 감지할 때, "101" 시퀀스가 감지된 후 "1101" 시퀀스를 감지하는 것과 같은 방식으로 설계할 수 있습니다. 이러한 경우, 더 많은 상태가 필요하고 상태 다이어그램이 복잡해집니다.
2) 오버랩 시퀀스 감지
오버랩 시퀀스 감지는 시퀀스가 겹치는 경우에도 감지하는 것을 의미합니다. 예를 들어, "101101" 시퀀스를 감지할 때, "101"과 "101"이 겹쳐서 감지될 수 있습니다. 이러한 경우, FSM은 현재 감지된 시퀀스를 추적하고, 새로운 시퀀스가 시작될 때 올바르게 전이하도록 설계되어야 합니다.
3) 효율적인 상태 코딩
상태 코딩은 FSM의 상태를 이진수로 표현하는 방법입니다. 상태 코딩 방법에는 이진 코딩, 그레이 코드, 원-핫 코딩 등 다양한 방법이 있습니다. 원-핫 코딩은 각 상태를 하나의 비트로 표현하는 방식이며, 상태 전이 로직을 간단하게 만들 수 있지만, 더 많은 플립플롭을 필요로 합니다. 상태 코딩 방법은 하드웨어 리소스 사용량과 성능에 영향을 미치므로, 설계 요구 사항에 따라 적절한 방법을 선택해야 합니다.
7. 결론
시퀀스 감지기는 FSM 설계를 통해 구현할 수 있는 강력한 도구입니다. 본 글에서는 시퀀스 감지기의 기본적인 개념, 설계 방법, 그리고 Verilog를 이용한 구현 예시를 살펴보았습니다. 상태 다이어그램을 사용하여 FSM의 동작을 시각적으로 표현하고, 이를 바탕으로 Verilog 코드를 작성하는 방법을 익혔습니다. 또한, 시뮬레이션을 통해 코드의 정확성을 검증하는 방법을 배웠습니다.
FSM 설계는 디지털 시스템 설계를 위한 핵심 기술이며, 시퀀스 감지기는 FSM의 기본적인 응용 중 하나입니다. 이러한 예제를 통해 FSM 설계 능력을 향상시키고, 더 복잡한 디지털 시스템 설계를 위한 기반을 다질 수 있습니다. 더 나아가, 중첩 시퀀스 감지, 오버랩 시퀀스 감지, 효율적인 상태 코딩과 같은 고급 설계 기법을 학습하여 FSM 설계 능력을 더욱 발전시킬 수 있습니다.
비슷한 글 추천
7-1. Verilog의 유한 상태 기계(FSM) 설계
유한 상태 기계의 개념과 Verilog를 이용한 FSM 설계 방법을 설명합니다. Moore 및 Mealy 머신을 다룹니다.
1-2. 디지털 시스템 설계 과정
Verilog를 이용한 디지털 시스템 설계의 전반적인 과정을 설명합니다. 설계, 시뮬레이션, 합성, 검증 단계를 소개합니다.
6-4. 실습: 시프트 레지스터 설계
시프트 레지스터 설계 실습을 통해 순차 논리 회로 설계를 이해하고, Verilog 코드를 작성합니다.
7-5. FSM 설계 고급: 상태 코딩 기법
FSM 상태 코딩 방식(One-hot, Gray code 등)에 대한 설명 및 장단점 비교.
Comments (0)
No comments yet. Be the first to comment!
Please to write a comment.