호타리 2025. 7. 7. 17:49

2025.07.07

 

순차회로와 FSM

 

조합회로 (Combinational Logic)
- 값을 저장하지 못함
- 클럭을 사용하지 않음
- 입력의 변화가 출력에 바로 반영됨
- 예 : adders, multiplexers, decoders, encoders, gates

순차회로 (Sequential Logic)
- 값을 저장하는 래치, 플립플롭, 레지스터, 메모리 등의 소자가 있어 상태를 저장
- 클럭을 사용하여 값을 저장
- 입력이 변화해도 주로 클럭의 에지에서 값이 반영됨
- 예 : counter, register, clock divider, FSM (Finite State Machine)

 

 

순차 회로의 종류


FSM (한정된 상태를 갖는 머신)
- Counter (계수기)
- Clock divider (클럭 분주기)
- FSM

Register (레지스터)
- Shift register
- Parallel register

 

조합회로

 

FSM 타입의 회로

 

TV channel 버튼
- 0, 1, 2, …, 9 채널이 있는 TV가 있다고 가정하고 채널 UP과 DN 버튼으로 채널을 선택한다면
- 채널 UP 버튼을 눌렀을 때
     현재 상태가 3이면 다음 상태는 4
     현재 상태가 9라면 다음 상태는 10
- 채널 DN 버튼을 눌렀을 때
     현재 상태가 3이면 다음 상태는 2
     현재 상태가 9라면 다음 상태는 8
- 다음 상태는 입력과 현재상태에 의해 결정
- 출력은 현재상태를 바로 출력으로 사용


현재상태를 저장하는 순차회로로만 가능하며 조합회로로는 불가능

 

FSM의 세부 블록 구분

 

 

FSM (Finite State Machine), 유한 상태 머신의 개념
- 유한한 개수의 상태를 가지고 있으며
- 입력과 현재상태에 따라 다음상태가 결정되고
- (입력과) 현재상태에 따라 출력이 결정되는 머신

 

FSM 세부 블록
- Next state logic (조합회로)
     입력(input) + 현재상태(present state) → 조합회로 → 다음상태(next state)

- State register (순차회로, F/F)
     다음상태(next state) → clock edge에서 저장 → 현재상태(present state)

- Output logic (조합회로)
     Moore machine의 경우 : 현재상태(present state) → 조합회로 → 다음상태(next state)
     Mealy machine의 경우 : 입력(input) + 현재상태(present state) → 조합회로 → 다음상태

 

- 상태 다이어그램의 일반적인 표기법
- 현재상태가 st0일 경우
     출력 done = 1
     만약 in=1 이면 출력은 out = 0, 다음 상태는 st1

 

상태표 (State Table)

 

TV Channel 버튼 Verilog code

 

tv_channel.v

`timescale 1ns / 1ps

module tv_channel(
    input wire clk,
    input wire rstn,
    input wire up,
    input wire dn,
    output [3:0] ch
    );

    reg [3:0] state, next_state;

    always @(up or dn or state) begin
        if (up & ~dn) begin
            if (state == 9) 
                next_state = 0;
            else 
                next_state = state + 1;
        end
        else if (~up & dn) begin
            if (state == 0) 
                next_state = 9;
            else 
                next_state = state - 1;
        end else begin
            next_state = state;
        end
    end

    always @(posedge clk or negedge rstn) begin
        if (!rstn) 
            state <= 4'h0;
        else 
            state <= next_state;
    end

    assign ch = state;

endmodule

 

tb_tv_channel.v

`timescale 1ns / 1ps

module tb_ch();


    reg clk, rstn;
    reg up, dn;
    wire [3:0] ch;


    tv_channel dut_tv(
    .clk(clk),
    .rstn(rstn),
    .up(up), .dn(dn),
    .ch(ch)
    );


    initial clk = 0;
    always #5 clk = ~ clk;

    initial begin
        #0 rstn = 1; up = 1'b1; dn = 1'b0;
        #90 up = 1'b0; dn = 1'b1;
        #50 up = 1'b1;
        #20 up = 1'b0; dn = 1'b0;
        #30 up = 1'b0; dn = 1'b0;
        #120 $finish;
    end
endmodule

 

TV Channel 버튼 Simulation 결과

 

레지스터 회로

 

파이프라인(Pipeline) 형태의 회로

 

Blocking과 Nonblocking 할당문

코딩 가이드라인
- 가이드라인-1:순차회로 또는 래치를 모델링하는 always 블록에서는 nonblocking 할당문을 사용한다.
- 가이드라인-2:조합논리회로를 모델링하는 always 블록에서는 blocking 할당문을 사용한다.

 

- 가이드라인-3:동일한 always 블록에서 순차회로와 조합논리회로를 함께 표현하는 경우에는 nonblocking 할당문을 사용한다.

- 가이드라인-4:동일한 always 블록 내에서 blocking 할당문과 nonblocking 할당문을 혼합해서 사용하지 않는다.

- 가이드라인-5:다수의 always 블록에서 동일한 reg 변수에 값을 할당하지 않는다.

 

원하지 않는 래치의 합성
일반적으로, case 문에 모든 가능한 case 항목들이 포함되지 않거나 if 조건문에서
else 블록이 생략되는 경우가 있을 수 있다. case 문과 if 조건문에 모든 가능한 조건들이 포함되지 않은 경우를 ‘불완전한 조건 지정’이라고 한다.
조합논리회로의 HDL 모델링에서는 입력의 모든 경우에 대해 출력값이 지정되어야 한다. case 문에서 입력의 모든 가능한 경우에 대하여 명시적으로 출력값이 지정되지 않으면,
출력값이 지정되지 않은 입력 조건에 대해서는 이전에 지정된 출력값을 계속 유지하는 것으로 해석될 수 있으므로 논리 합성 툴은 암시적으로 래치를 생성하게 된다. 래치가 포함된 회로는
순차논리회로가 되므로 합성된 회로는 원래 의도했던 조합논리회로로 동작하지 않게 된다.
따라서 case 문 또는 if 조건문으로 조합논리회로를 모델링하는 경우에는 모든 가능한 입력 조건들에 대해 출력값을 명시적으로 지정하거나, 또는 default 값을 지정해야 한다.

 

1. 원하지 않는 래치의 합성

case 문에 모든 가능한 case 항목들이 포함되지 않는 경우
if 조건문에서 else 블록이 생략되는 경우

 

= 순수한 조합논리회로의 합성

모든 가능한 입력 조건들에 대해 출력값을 명시적으로 지정
default 값을 지정

 

순차회로
     현재의 입력과 현재 상태에 의해 다음 상태와 출력이 결정되는 회로
     기억소자(래치, 플립플롭, SRAM)와 조합논리회로로 구성
     레지스터, 주파수 분주기, 계수기(counter), 유한상태머신(Finite State Machine; FSM)


래치와 플립플롭
     래치(latch) : 클록의 레벨(즉, 0 또는 1)에 따라 동작하는 저장소자 => 사용안함
     플립플롭(Flip/flop) : 클록의 상승 또는 하강에지에 동기되어 동작하는 저장소자


순차회로의 모델링
     always 구문만을 사용
     이벤트 리스트에는 edge-sensitive이므로 posedge 또는 negedge가 있는 clock이나 reset, preset만을 사용
     변수는 reg로 선언
     할당문은 nonblocking(<=) 을 사용

 

래치(latch)
     값을 저장할 수 있는 소자
     가장 간단한 래치는 NOR 게이트 2개 또는 NAND 게이트 2개로 만들 수 있음
     NAND 게이트가 NOR 게이트보다 레이아웃 크기가 작기 때문에 NAND 게이트로 만든 래치를 주로 설명

 

SR래치의 동작

 

SR래치의 파형

- S와 R신호는 active-low 신호로 생각한다.

 

S=0, R=0으로 모두 active 된 경우

→ 다시 S=0, R=0이 되었을 때 set이 될 지 reset이 될 지 모름
→  이러한 값이 입력되지 않도록 해야 함 

 

SR래치의 상태표(state table)

 

D Latch

- 일반적으로 가장 많이 사용되는 Latch

 

D Latch의 상태표

 

D Latch의 파형

- EN = 1일 때 Q는 입력 D를 그대로 출력하므로 transparent latch라고도 함

 


Cross-coupled inverter
- Cross-coupled inverter는 bi-stable 회로로 2가지의 값을 안정적으로 저장
- SR latch도 cross-coupled inverter를 기본으로 하고 있음

 

Cross-coupled inverter
- Vi1=Vo2=1, Vi2=Vo1=0 또는 Vi1=Vo2=0, Vi2=Vo1=1 일 때 안정된 상태

 

D latch
- Cross-coupled inverter와 transmission gate 2개를 사용하여 만들 수 있음

 

D Latch의 동작

 

래치(latch)의 사용
- 래치를 사용하여 회로를 꾸밀 때에는 주로 two phase non-overlapping clock 등을 사용
- 그러나 클럭 스큐 등의 문제가 있어 회로가 복잡해지면 사용이 쉽지 않음
- 오히려 래치는 만들지 말아야 할 것으로 인식됨
- Verilog 사용자가 조합회로를 만들었으나 실수를 하여 래치가 만들어지는 경우가 발생
    → 이를 방지하기 위해서는 모든 입력의 경우의 수에 대하여 출력을 명시하면 됨
    → 모든 경우에 대하여 명시가 어렵다면 상황에 따라 default 문장, else 문장, 출력 초기화를 사용
    → 기타 방법으로 “full_case parallel_case”를 사용하는 방법이 있으나 권장되지는 않음

 

Clock 신호
- Clock 신호는 주기적인 square wave 임
- Clock 신호는 의미있는 정보를 보낸다기 보다는 타이밍을 맞추기 위해 사용
- Clock에 맞추어 Latch 또는 플립플롭들이 동시에 정보를 저장

 

플립플롭 개요
- 플립플롭(F/F)은 Clock 신호가 변화(transition)하는 시점인 edge(에지)에 맞추어 동작 (Edge-sensitive) (Latch는 Clock 신호 값의 수준에 맞추어 동작 (Level-sensitive))
- Rising edge에 맞추어 동작하는 F/F을 rising edge triggered F/F 이라 함
- Falling edge에 맞추어 동작하는 F/F을 falling edge triggered F/F 이라 함

 

Classical D F/F
- 전통적인 구조의 rising edge-triggered D F/F
- C=0 이면 S=1와 R=1이므로 Q와 Q는 값을 유지
- C=0 에서 C=1이 되고 이 때 D=0이라면 오른쪽 SR래치에 S=1, R=0이 입력되어 Q=0이 됨
- 따라서 C=0에서 C=1이 되는 순간(rising edge)에 D=0의 값을 받아 Q=0이 됨

 

Classical D F/F
- C=0 이면 S=1와 R=1이므로 Q와 Q는 값을 유지
- C=0 에서 C=1이 되고 이 때 D=1이라면 오른쪽 SR래치에 S=0, R=1이 입력되어 Q=1이 됨
- 따라서 C=0에서 C=1이 되는 순간(rising edge)에 D=1의 값을 받아 Q=1이 됨

 

D F/F 상태표

 

Edge-triggered D F/F
- Edge-triggered D F/F = Pulse transition detector + D Latch
- Pulse transition detector가 아주 짧은 시간만 D latch의 EN=1로 하므로 마치 edge에 값을 받아들이는 동작의 효과를 냄

 

Pulse transition detector 회로
- 신호가 inverter를 통과할 때의 지연시간을 이용하여 짧은 시간 동안만 1이 되는 일종의 glitch(spike)를 발생시킴

 

Master-slave D F/F
- 앞의 2가지 D F/F과 동작이 같음
- 2개의 D latch를 사용하여 구성

 

Master-slave D F/F (회로의 다른 표현)

 

Mater-slave D F/F의 동작 매커니즘

 

비동기 리셋 D F/F
- 동기(Synchronous) : 클럭 신호에 맞추어 값이 변할 경우
- 비동기(Asynchronous) : 클럭 신호와 상관없이 값이 변할 경우

 

비동기 리셋 D F/F의 상태표

 

D Latch와 D F/F의 파형

 

Propagation delay time, 전달(전파) 지연 시간
- Tclk-q : Clock의 edge로부터 값이 출력되기까지의 시간

 

D Latch와 D F/F의 차이점

 

F/F 타이밍 고찰
- 실제로는 tclk-to-q 지연시간 때문에 q1, q0가 clock edge 보다 늦게 변하므로 clock edge 기준 앞의 값을 받아들이는 것으로 생각한다

 

레지스터 회로

 

파이프라인(Pipeline) 형태의 회로

 

F/F의 셋업(setup)과 홀드(hold) 시간
- Setup time : Clock의 edge 전 미리 입력 데이터가 안정되어야 하는 최소 시간
- Hold time : Clock의 edge 후 입력 데이터가 유지되고 있어야 하는 최소 시간

 

유한상태 머신(Finite State Machine; FSM)
- 지정된 수의 상태를 가지고 상태의 천이에 의해 출력을 생성하는 회로
- 디지털 시스템의 제어회로 구성에 사용
- Moore 머신 : 출력이 현재상태에 의해서만 결정
- Mealy 머신 : 출력이 현재상태와 입력에 의해 결정

 

 

Mealy FSM

fsm.v

`timescale 1ns / 1ps

module fsm (
    input  wire clk,
    input  wire rstn,
    input  wire done,
    output ack,
    output reg [1:0] current_state  // 상태를 외부에서도 관찰 가능하게
);

    // 상태 인코딩 정의
    parameter READY = 2'b00;
    parameter TRANS = 2'b01;
    parameter WRITE = 2'b10;
    parameter READ  = 2'b11;

    reg [1:0] next_state;

    // 순차 논리: 상태 전이
    always @(posedge clk or negedge rstn) begin
        if (!rstn)
            current_state <= READY;
        else
            current_state <= next_state;
    end

    // 조합 논리: next state 계산
    always @(current_state or done) begin
        case (current_state)
            READY:  next_state = (done == 1) ? TRANS : READY;
            TRANS:  next_state = (done == 0) ? TRANS : WRITE;
            WRITE:  next_state = (done == 1) ? READ  : WRITE;
            READ:   next_state = (done == 0) ? READ  : READY;
            default: next_state = READY;
        endcase
    end

    assign ack = 1;

endmodule

tb_fsm.v

`timescale 1ns / 1ps

module tb_fsm();

    reg clk, rstn;
    reg done;
    wire ack;
    wire [1:0] current_state;

    // ✅ 모듈 이름 일치시키기 (fsm)
    fsm dut_fsm (
        .clk(clk), 
        .rstn(rstn), 
        .done(done), 
        .ack(ack),
        .current_state(current_state)
    );

    // 클럭 생성
    initial clk = 0;
    always #5 clk = ~clk;  // 10ns 주기

    // 테스트 시나리오
    initial begin
        // 파형 출력
        $dumpfile("fsm_tb.vcd");
        $dumpvars(0, tb_fsm);

        // 초기 조건
        rstn = 0; done = 0;

        // 리셋 → READY
        #20 rstn = 1;

        // 상태 전이 시퀀스
        #10 done = 0; // READY, ack = 1
        #10 done = 1; // TRANS, ack = 1
        #10 done = 1; // TRANS 유지
        #10 done = 0; // WRITE
        #10 done = 0; // WRITE 유지
        #10 done = 1; // READ
        #10 done = 0; // READ 유지
        #10 done = 1; // READY
        #10 done = 0; // READY
        #10 done = 1; // TRANS
        #10 rstn = 0; // 다시 RESET
        #10 rstn = 1; // RESET OFF

        #20 $finish;
    end

endmodule

 

Moore FSM

moore_fsm.v

`timescale 1ns / 1ps

module fsm_moore (
    input  wire clk,
    input  wire rstn,
    input  wire done,
    output reg ack,                      // reg로 변경 (Moore는 상태 기반 출력)
    output reg [1:0] current_state       // 상태 관찰용 출력
);

    // 상태 인코딩
    parameter READY = 2'b00;
    parameter TRANS = 2'b01;
    parameter WRITE = 2'b10;
    parameter READ  = 2'b11;

    reg [1:0] next_state;

    // 상태 전이 (순차 논리)
    always @(posedge clk or negedge rstn) begin
        if (!rstn)
            current_state <= READY;
        else
            current_state <= next_state;
    end

    // 다음 상태 결정 (조합 논리)
    always @(*) begin
        case (current_state)
            READY:  next_state = (done) ? TRANS : READY;
            TRANS:  next_state = (done) ? WRITE : TRANS;
            WRITE:  next_state = (done) ? READ  : WRITE;
            READ:   next_state = (done) ? READY : READ;
            default: next_state = READY;
        endcase
    end

    // Moore 출력 로직: 상태에 따라 출력 결정
    always @(*) begin
        case (current_state)
            READY:  ack = 1'b0;
            TRANS:  ack = 1'b0;
            WRITE:  ack = 1'b0;
            READ:   ack = 1'b1;   // 예: READ 상태일 때만 ack=1
            default: ack = 1'b0;
        endcase
    end

endmodule

tb_moore_fsm.v

`timescale 1ns / 1ps

module tb_fsm_moore();

    reg clk, rstn;
    reg done;
    wire ack;
    wire [1:0] current_state;

    // ✅ Moore FSM DUT 인스턴스
    fsm_moore dut (
        .clk(clk),
        .rstn(rstn),
        .done(done),
        .ack(ack),
        .current_state(current_state)
    );

    // ✅ 클럭 생성: 10ns 주기 (100MHz)
    initial clk = 0;
    always #5 clk = ~clk;

    // ✅ 시뮬레이션 시나리오
    initial begin
        $dumpfile("fsm_moore_tb.vcd");  // 파형 저장 파일
        $dumpvars(0, tb_fsm_moore);

        // 초기값
        rstn = 0;
        done = 0;

        // 리셋 해제
        #20 rstn = 1;

        // 상태 전이 순서 (Moore FSM 기준)
        #10 done = 0; // READY 유지
        #10 done = 1; // TRANS로 전이
        #10 done = 1; // WRITE로 전이
        #10 done = 1; // READ로 전이
        #10 done = 1; // READY로 전이
        #10 done = 1; // TRANS로 전이
        #10 done = 0; // TRANS 유지
        #10 done = 1; // WRITE로 전이
        #10 done = 1; // READ로 전이
        #10 done = 0; // READ 유지
        #10 done = 1; // READY로 전이

        // 리셋 테스트
        #10 rstn = 0;
        #10 rstn = 1;
        #20 done = 0;

        #20 $finish;
    end

endmodule