[VerilogHDL] FSM 코딩(Moore, Mealy) - 버튼, UpCounterVerilogHDL/Study2024. 5. 19. 23:59
Table of Contents
1. FSM(Finite State Machine)
(1) Moore 머신 : 출력이 현재 상태에 의해서만 결정
Present State | Next State | Output | |
input 0 | input 1 | ||
S0 | S1 | S0 | 0 |
S1 | S1 | S0 | 1 |
(2) Mealy 머신 : 출력이 현재 상태와 입력에 의해서 결정
Present State | Next State | Output | ||
input 0 | input 1 | input 0 | input 1 | |
S0 | S1 | S0 | 1 | 0 |
S1 | S1 | S0 | 1 | 0 |
- Next-State Logic
- Next State를 계산, 결정하는 회로
- 현재 상태 및 입력에 따라 다음 상태를 결정
- State Register
- clk edge에서 현재 State update(저장) ← state = next_state 형식으로..
- Output Logic
- 현재 State Register에 저장된 값을 출력
2. FSM - 버튼 LED 조작
- 버튼 누르면 LED ON
- 버튼 누르면 LED OFF
구현
`timescale 1ns / 1ps
module LEDToggle (
input clk,
input reset,
input button,
output reg led
);
parameter LED_OFF = 1'b0, LED_ON = 1'b1;
reg state, state_next; // 상태 저장 레지스터
// state register, 현재 상태 레지스터에 저장
always @(posedge clk, posedge reset) begin
if (reset) begin
state <= LED_OFF;
end else begin
state <= state_next; // next State
end
end
// Next state Combinational Logic Circuit
always @(state, button) begin
state_next = state;
case (state)
LED_OFF: begin
if (button == 1'b1) state_next = LED_ON;
else
state_next = state; // 버튼 누르지 않으면 상태 변화 없음
end
LED_ON: begin
if (button == 1'b1) state_next = LED_OFF;
else
state_next = state; // 버튼 누르지 않으면 상태 변화 없음
end
endcase
end
// Output Combinational Logic Circuit
// Moore Machine
always @(state) begin
led = 1'b0;
case (state)
LED_OFF:
led = 1'b0; // 상태에 따라 출력 결정(Moore Machine)
LED_ON: led = 1'b1;
endcase
end
// Output Combinational Logic Circuit
// Mealy Machine
always @(state, button) begin
led = 1'b0;
case (state)
LED_OFF: begin
if (button == 1'b1)
led = 1'b1; // 상태에 따라 출력 결정(Moore Machine)
else led = 1'b0;
end
LED_ON: begin
if (button == 1'b1)
led = 1'b0; // 상태에 따라 출력 결정(Moore Machine)
else led = 1'b1;
end
endcase
end
endmodule
`timescale 1ns / 1ps
module LEDToggle (
input clk,
input reset,
input button,
output reg led
);
parameter LED_OFF = 1'b0, LED_ON = 1'b1;
reg state, state_next; // 상태 저장 레지스터
// state register, 현재 상태 레지스터에 저장
always @(posedge clk, posedge reset) begin
if (reset) begin
state <= LED_OFF;
end else begin
state <= state_next; // next State
end
end
// Next state Combinational Logic Circuit
always @(state, button) begin
state_next = state;
case (state)
LED_OFF: begin
if (button == 1'b1) state_next = LED_ON;
else
state_next = state; // 버튼 누르지 않으면 상태 변화 없음
end
LED_ON: begin
if (button == 1'b1) state_next = LED_OFF;
else
state_next = state; // 버튼 누르지 않으면 상태 변화 없음
end
endcase
end
// Output Combinational Logic Circuit
// Moore Machine
always @(state) begin
led = 1'b0;
case (state)
LED_OFF:
led = 1'b0; // 상태에 따라 출력 결정(Moore Machine)
LED_ON: led = 1'b1;
endcase
end
// Output Combinational Logic Circuit
// Mealy Machine
always @(state, button) begin
led = 1'b0;
case (state)
LED_OFF: begin
if (button == 1'b1)
led = 1'b1; // 상태에 따라 출력 결정(Moore Machine)
else led = 1'b0;
end
LED_ON: begin
if (button == 1'b1)
led = 1'b0; // 상태에 따라 출력 결정(Moore Machine)
else led = 1'b1;
end
endcase
end
endmodule
- Moore Machine에서는 출력부의 입력에 현재 상태만 들어가고
- Mealy Machine에서는 현재 상태와 버튼 입력이 들어간다.
버튼 채터링 보완 회로
- shift register 이용
구현
`timescale 1ns / 1ps
module button(
input clk,
input in,
output out
);
localparam N = 3;
reg [N-1:0] q_reg, q_next;
always @(posedge clk) begin
q_reg <= q_next;
end
// next state logic
always @(q_reg, in) begin
q_next = {in, q_reg[N-1:1]};
end
// output logic
assign out = (&q_reg[N-1:1] & ~q_reg[0]); // rising edge trigger
//assign out = (~(&q_reg[N-1:1]) & q_reg[0]); // falling edge trigger
endmodule
`(&q_reg[N-1:1] & ~q_reg[0])` 에서 `(&q_reg[N-1:0])` 으로 하지 않은 이유는???
(`(&q_reg[N-1:0]`)으로 사용하면 채터링 무시하고 N클럭 동안 버튼의 입력이 1이라고 알 수 있지 않나…?)
- `~q_reg[0]` 을 사용함으로써 N클럭 전 버튼의 입력이 0이었다는 것을 알 수 있음
- 그로인해 버튼이 눌렸음(0 → 1)을 알 수 있음!!
- 만약 `(&q_reg[N-1:0])` 이렇게 사용하면 버튼을 계속 누르고 있으면 out이 계속 1로 출력됨
→ out == 1일 때 LED state를 변경하는 회로를 구성했을 때 LED state가 계속 변하는 결과를 가져옴……
→ 버튼이 눌렸을 때 딱 한번만 state를 변경해야 하는 경우 위와 같이 LSB가 0 이라는 것을 판별해야함.
버튼 시뮬레이션
더보기
`timescale 1ns / 1ps
module tb_button ();
reg clk;
reg in;
wire out;
button dut (
.clk(clk),
.in (in),
.out(out)
);
always #5 clk = ~clk;
initial begin
clk = 1'b0;
in = 1'b0;
end
initial begin
#60 in = 1'b1;
#2 in = 1'b0;
#2 in = 1'b1;
#2 in = 1'b1;
#2 in = 1'b0;
#2 in = 1'b1;
#2 in = 1'b0;
#2 in = 1'b1;
#2 in = 1'b0;
#2 in = 1'b0;
#2 in = 1'b0;
#2 in = 1'b1;
#2 in = 1'b1;
#2 in = 1'b0;
#2 in = 1'b1;
#2 in = 1'b0;
#2 in = 1'b1;
#2 in = 1'b0;
#2 in = 1'b0;
#60 in = 1'b1;
#60 in = 1'b1;
#60 in = 1'b1;
#60 in = 1'b0;
#2 in = 1'b0;
#2 in = 1'b1;
#2 in = 1'b1;
#2 in = 1'b0;
#2 in = 1'b1;
#2 in = 1'b0;
#2 in = 1'b0;
#2 in = 1'b1;
#2 in = 1'b0;
#2 in = 1'b1;
#2 in = 1'b0;
#2 in = 1'b0;
end
endmodule
버튼 채터링 방지 코드 추가
더보기
`timescale 1ns / 1ps
module LEDToggle (
input clk,
input reset,
input button,
output led
);
wire w_button;
button U_Button (
.clk(clk),
.in (button),
.out(w_button)
);
led_fsm U_FSM (
.clk(clk),
.reset(reset),
.button(w_button),
.led(led)
);
endmodule
module led_fsm (
input clk,
input reset,
input button,
output reg led
);
parameter LED_OFF = 1'b0, LED_ON = 1'b1;
reg state, state_next; // 상태 저장 레지스터
// state register, 현재 상태 레지스터에 저장 -> Next State Circuit
always @(posedge clk, posedge reset) begin
if (reset) begin
state <= LED_OFF;
end else begin
state <= state_next; // next State
end
end
// Next state Combinational Logic Circuit
always @(state, button) begin
state_next = state;
case (state)
LED_OFF: begin
if (button == 1'b1) state_next = LED_ON;
else
state_next = state; // 버튼 누르지 않으면 상태 변화 없음
end
LED_ON: begin
if (button == 1'b1) state_next = LED_OFF;
else
state_next = state; // 버튼 누르지 않으면 상태 변화 없음
end
endcase
end
// Output Combinational Logic Circuit
// Moore Machine
always @(state) begin
led = 1'b0;
case (state)
LED_OFF:
led = 1'b0; // 상태에 따라 출력 결정(Moore Machine)
LED_ON: led = 1'b1;
endcase
end
// // Output Combinational Logic Circuit
// // Mealy Machine
// always @(state, button) begin
// led = 1'b0;
// case (state)
// LED_OFF: begin
// if (button == 1'b1)
// led = 1'b1; // 출력 결과가 입력과 상태에 따라 결정
// else led = 1'b0;
// end
// LED_ON: begin
// if (button == 1'b1) led = 1'b0;
// else led = 1'b1;
// end
// endcase
// end
endmodule
결과
3. FSM - Up Counter
`timescale 1ns / 1ps
module UpCounter #(
parameter MAX_NUM = 10000
) (
input clk, // system operation clock, 100MHz
input reset,
input tick, // time clock ex) 100Hz 0.01s
input en,
output [$clog2(MAX_NUM)-1:0] counter
);
reg [$clog2(MAX_NUM)-1:0] counter_reg, counter_next;
// state register
always @(posedge clk, posedge reset) begin // clk rising edge일 때만 출력값(counter_reg) update
if (reset) begin
counter_reg <= 0;
end else begin
counter_reg <= counter_next;
end
end
//next state combinational logic <- 다음 state 값 upcount
always @(*) begin
if (tick & en) begin // tick이 들어오고(x초에 한번) en 신호가 1일 때만 카운트 동작
if (counter_reg == MAX_NUM - 1) begin
counter_next = 0;
end else begin
counter_next = counter_reg + 1;
end
end else begin
counter_next = counter_reg;
end
end
// output combinational logic
assign counter = counter_reg;
endmodule
module clkDiv #(
parameter HERZ = 100
) (
input clk,
input reset,
output o_clk
);
reg [$clog2(100_000_000/HERZ)-1 : 0] counter;
reg r_clk;
assign o_clk = r_clk;
always @(posedge clk, posedge reset) begin
if (reset) begin
counter <= 0;
r_clk <= 1'b0;
end else begin
if (counter == (100_000_000 / HERZ - 1)) begin
counter <= 0;
r_clk <= 1'b1;
end else begin
counter <= counter + 1;
r_clk <= 1'b0;
end
end
end
endmodule
→ tick이 발생하고 바로 counter가 업데이트 되는 것이 아니라 그 다음 clk에서 업데이트 됨.
Made By Minseok KIM
'VerilogHDL > Study' 카테고리의 다른 글
[VerilogHDL] UART Tx(2) (0) | 2024.05.22 |
---|---|
[VerilogHDL] UpCounter, 디버깅, UART Tx (0) | 2024.05.20 |
[VerilogHDL] 조합 논리 회로 & 순차 논리 회로, Latch & FlipFlop (0) | 2024.05.19 |
[VerilogHDL] C&Verilog차이, SystemVerilog 기본, 8bit Adder FND, 만진 카운터 (0) | 2024.05.16 |
[VerilogHDL] System Verilog, 4bit Adder FND 출력 (0) | 2024.05.16 |
@민바Minba :: Minba's blog
Let's Be Happy!
도움이 되었으면 좋겠어요 :)