★ 유한상태머신(FSM)
유한상태머신(Finite State Machine)은 지정된 수의 상태를 가지고 상태들 간의 전이에 의해 출력을 생성하는 회로를 총칭하며, 디지털 시스템의 제어회로 구성에 폭넓게 사용된다. FSM의 일반적인 구조는 밑의 그림과 같고, 입력과 현재상태에 따라 다음상태를 결정하는 블록(next state logic), 현재상태를 저장하는 순차회로 블록(state register), 입력과 현재상태에 따라 출력값을 결정하는 블록(output logic)등으로 구성된다.
FSM의 상태레지스터는 상태값을 이진(binary)데이터로 저장한다. 이진 데이터의 인코딩 방식에 따라 상태 레지스터의 비트 수가 달라지며, 대표적인 상태 인코딩 방식으로는 이진코드, 그레이코드, 존슨코드, 원핫코드 등이 있다. 8개의 상태를 갖는 경우의 상태 인코딩 형식은 다음과 같다.
FSM의 HDL 모델링을 위해 다음과 같은 사항들을 고려해야 한다.
1. 각각의 상태머신을 독립된 Verilog module로 설계한다. 이는 FSM모델의 유지가 용이하고, FSM합성 툴의 최적화 작업에 도움이 된다.
2. FSM의 상태 이름을 parameter로 정의하여 사용한다. 컴파일러 지시어 `define을 이용하여 상태 이름을 정의할 수 있으나, `define은 컴파일 과정에서 광역적으로 영향을 미치므로, 다수의 FSM에서 동일한 상태 이름이 사용되는 겨웅에 오류를 범한다. parameter는 국부적인 영향을 미치므로 다른 FSM에 영향을 미치지 않는다.
3. FSM이 비동기 리셋을 갖도록 설계한다. 리셋을 갖지 않는 FSM은 초기 전원 인가 후 상태 레지스터의 초기값이 불확정적이므로 정의되지 않은 상태에 갇혀서 빠져나오지 못하는 상황이 발생할 수 있다.
4. FSM을 구성하는 3개의 블록(next state logic, state register, output logic)을 분리된 always블록 또는 assign문으로 구현한다. 이는 FSM 코딩의 일관성을 좋게하고, 수정 및 변경을 용이하게 한다.
5. 상태 레지스터는 래치보다 플립플롭을 사용하는 것이 좋다.
6. Next state logic은 case문을 이용하여 모델링하는것이 가장 바람직하며, FSM에서 정의되지 않은 상태들은 default문으로 표현한다.
★ Moore FSM
위와 같은 상태 전이도를 갖는 FSM을 예를 들어 Verilog HDL 모델링 방법을 살펴본다. 위와 같이 출력신호 rd와 ds값이 지정되지 않은 경우는 0을 의미한다. 4개의 상태(IDLE, READ, DLY, DONE)에 대한 상태값은 이진 상태 인코딩을 적용하여 parameter로 정의되었으며, 따라서 상태 레지스터 state는 2비트로 선언된다.
상태 레지스터 state는 always블록에서 nonblocking할당문을 이용한 순차논리회로로 모델링되며, 다음 상태를 결정하는 조합논리회로는 always블록에 blocking할당문으로 모델링된다. FSM의 출력은 다음 코드와 같이 assign문에 의해 생성되거나 또는 다음 상태를 결정하는 always블록에서 생성 될 수 있다. (코드 A,B비교)
● A (assign문으로 출력을 생성하는 경우)
module fsm_ex1(clk,rst_n, go, ws, rd, ds);
input clk, rst_n, go, ws;
output rd, ds;
parameter IDLE = 2'b00, READ = 2'b01, DLY = 2'b10, DONE = 2'b11;
reg [1:0] state , next ;
// 상태 레지스터를 위한 always 순차회로 블록
always@(posedge clk or negedge rst_n)begin
if(!rst_n) state <= IDLE;
else state <= next;
end
// 다음상태 결정을 위한 always 조합논리회로 블록
always@(*)begin
next = 2'bx;
case(state)
IDLE : if(go) next = READ; else next = IDLE;
READ : next = DLY;
DLY : if(!ws) next = DONE; else next = READ;
DONE : next =IDLE;
endcase
end
//출력값 결정.
assign rd = ((state==READ) || (state==DLY));
assign ds = (state == DONE);
endmodule
● B (always블록에서 출력을 생성하는 경우)
module fsm_ex1(clk, rst_n, go, ws, rd, ds);
input clk, rst_n, go ,ws;
output reg rd, ds;
parameter IDLE = 2'b00, READ = 2'b01, DLY = 2'b10, DONE = 2'b11;
reg [1:0] state , next ;
// 상태 레지스터
always@(posedge clk or negedge rst_n)begin
if(!rst_n) state <= IDLE;
else state <= next;
end
//다음상태 + 출력값 결정
always@(*)begin
next = 2'bxx;
rd = 1'b0;
ds = 1'b0;
case(state)
IDLE : if(go) next = READ; else next = IDLE;
READ : begin rd = 1'b1; next = DLY; end
DLY : begin rd = 1'b1; if(!ws) next = DONE; else next = DLY; end
DONE : begin ds = 1'b1; next = IDLE end
endcase
end
endmodule
한편 FSM의 출력이 레지스터를 통해 생성되는 경우 다음과 같이 별도의 순차회로 always블록을 사용하여 모델링한다. 일반적으로, 레지스터를 통한 출력은 glitch를 갖지 않으므로 권장되는 코딩방식이다.
● C (레지스터를 통해 출력을 생성하는 경우)
module fsm_ex3(clk,rst_n, go, ws, rd, ds);
input clk, rst_n, go, ws;
output rd, ds;
parameter IDLE = 2'b00, READ = 2'b01, DLY = 2'b10, DONE = 2'b11;
reg [1:0] state , next ;
// 상태 레지스터를 위한 always 순차회로 블록
always@(posedge clk or negedge rst_n)begin
if(!rst_n) state <= IDLE;
else state <= next;
end
// 다음상태 결정을 위한 always 조합논리회로 블록
always@(*)begin
next = 2'bx;
case(state)
IDLE : if(go) next = READ; else next = IDLE;
READ : next = DLY;
DLY : if(!ws) next = DONE; else next = READ;
DONE : next =IDLE;
endcase
end
// 출력값 결정 및 출력 레지스터
always@(posedge clk or negedge rst_n)begin
if(!rst_n) begin
ds <= 1'b0;
rd <= 1'b0;
end
else begin
ds <= 1'b0;
rd <= 1'b0;
case(next)
READ : rd <= 1'b1;
DLY : rd <= 1'b1;
DONE : ds <= 1'b1;
endcase
end
end
endmodule
▣ TESTBENCH
module tb_fsm_ex1;
reg clk, rst_n, go, ws;
wire rd, ds ;
fsm_ex1 u0(clk,rst_n,go,ws,rd,ds);
always
#10 clk = ~clk;
initial begin
clk = 1'b0;
rst_n = 1'b0;
go = 1'b0; ws = 1'b0;
#40 rst_n = 1'b1;
#40 go = 1'b0;
#40 go = 1'b1;
#40 ws = 1'b1;
#40 ws = 1'b0;
end
endmodule
★ Mealy FSM
위와 같이 0또는 1이 연속해서 입력되면 1을 출력하는 시퀀스 검출기 회로는 FSM을 이용하여 설계될 수 있다. 비트 단위로 입력되는 din_bit에 00 또는 11의 패턴이 발견되면 1을 출력하고, 그 이외의 경우에는 0을 출력한다.
회로의 동작은 위와 같은 전이도를 갖는 Mealy FSM으로 구현할 수 있으며 외부입력 din_bit의 값과 FSM의 현재상태에 따라 상태 전이가 일어나는 추상적 FSM을 나타낸다. 현재상태와 입력에 따라 다음과 같은 상태 전이가 일어난다.
1. start 상태 : 입력 din_bit가 0이면 rd0_once 상태로 전이되고 출력은 0이되며, 1이 입력되면 rd1_1once상태로 전이되고 출력은 0이 된다.
2. rd0_once 상태 : 0이 입력되면 0이 연속해서 입력된 것이므로, rd0_twice 상태로 전이되고 출력은 1이된다. rd0_once상태에서 1이 입력되면 rd1_once상태로 전이되고 출력은 0이된다.
3. rd1_once 상태 : 0이 입력되면 rd0_once상태로 전이되고 출력은 0이 되며, 1이 입력되면 1이 연속해서 입력된 것이므로 rd1_twice상태로 전이되고 출력은 1이 된다.
4. rd0_twice 상태 : 0이 입력되면 0이 또다시 연속해서 입력된 것이므로, rd0_twice상태에 머물러 있으면서 출력은 1이된다. rd0_twice상태에서 1이 입력되면 rd1_once상태로 전이되고 출력은 0이 된다.
5. rd1_twice 상태 : 0이 입력되면 rd0_once상태로 전이되고 출력은 0이되며, 1이 입력되면 1이 연속해서 입력된 것이므로 rd1_twice상태에 머물러 있으면서 출력은 1이 된다.
다음 코드는 위의 상태의 시퀀스 검출기를 Mealy FSM으로 모델링한 예이다. 상태 전이도가 갖는 5가지 상태에 대한 상태값은 이진 상태 인코딩을 적용하여 parameter로 정의되었으며, 따라서 state_reg는 3비트로 선언된다. 다음 상태를 결정하는 조합논리회로는 always블록에 blocking할당문으로 모델링된다. 상태 레지스터 state_reg는 always블록에서 nonblocking할당문을 이용한 순차논리회로로 모델링 된다. 마지막 assign문은 조건 연산자를 활용하여 현재 상태가 rd_twice이고 din_bit가 0인 경우 또는 rd1_twice이고 입력 din_bit가 1인경우 dout_bit값을 1로 출력시키며, 이에 의해 Mealy 머신이 구현된다.
module fsm_mealy(clk,rst,din_bit,dout_bit);
input clk,rst,din_bit;
output dout_bit;
reg [2:0] state_reg, next_state;
parameter start=3'b000, rd0_once=3'b001, rd1_once=3'b010, rd0_twice=3'b011, rd1_twice=3'b100;
// state register
always@(posedge clk or posedge rst)begin
if(rst) state_reg <= start;
else state_reg <= next_state;
end
// next state logic
always@(*)begin
case(state_reg)
start : if(din_bit==0) next_state <= rd0_once;
else if(din_bit==1) next_state <= rd1_once;
else next_state <= start;
rd0_once : if(din_bit==0) next_state <= rd0_twice;
else if(din_bit==1) next_state <= rd1_once;
else next_state <= start;
rd1_once : if(din_bit==0) next_state <= rd0_once;
else if(din_bit==1) next_state <= rd1_twice;
else next_state <= start;
rd0_twice : if(din_bit==0) next_state <= rd0_twice;
else if(din_bit==1) next_state <= rd1_once;
else next_state <= start;
rd1_twice : if(din_bit==0) next_state <= rd0_once;
else if(din_bit==1) next_state <= rd1_twice;
else next_state <= start;
default next_state <= start;
endcase
end
// output
assign dout_bit = (((state_reg==rd0_twice)&&(din_bit==0)) ||(state==rd1_twice)&&(din_bit==1));
endmodule
▣ TESTBENCH
module tb_fsm_mealy;
reg clk,rst,din_bit;
wire dout_bit;
fsm_mealy u0(clk,rst,din_bit,dout_bit);
always
#10 clk = ~clk;
initial begin
clk = 1'b0; rst = 1'b1; din_bit =1'b0;
#20 rst = 1'b0; din_bit =1'b1;
#20 din_bit =1'b0;
#20 din_bit =1'b0;
#20 din_bit =1'b1;
#20 din_bit =1'b1;
#20 din_bit =1'b1;
#20 din_bit =1'b0;
#20 din_bit =1'b1;
#20 din_bit =1'b0;
#20 din_bit =1'b0;
end
endmodule
'UVM & RTL > Verilog HDL' 카테고리의 다른 글
[Verilog HDL] Instruction (0) | 2022.06.10 |
---|---|
[33] Verilog HDL 순차회로 설계과제 ( FSM ) (0) | 2022.03.07 |
[31] Verilog HDL 순차회로 설계과제 (카운터) (0) | 2022.03.06 |
[30] Verilog HDL 순차회로( Counter ) (0) | 2022.03.05 |
[29] Verilog HDL 순차회로 설계과제 (시프트 레지스터) (0) | 2022.03.05 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!