Finite state machine design (Verilog HDL)

1. Finite state machine

- Basic concepts
Finite State Machine (FSM) is a classic method of circuit design. It can usually be considered as a combination of combinational logic and register logic. Combinational logic uses For status decoding and output signal generation, registers are used to store status.

- Moore and Mealy state machines
Moore state machine: The output is only a function of the current state
Mealy state Machine: The output is a function of the current state and the current input

It doesn’t seem to be easy to understand. Let’s take a look at it based on the state machine model.

![Insert image description here](https://img-blog.csdnimg.cn/c703df85f31c4ff1995701978f8be5f2.png
It can be seen that the output of the Moore type state machine is only related to the current state (current CS)

Insert image description here
It can be seen from the figure that compared to the Moore-type state machine, the output logic of the Mealy-type state machine has one more input terminal. That is, the output of the Mealy-type state machine mentioned in the above definition is determined by the current state (current state CS) and the current input. .

- The difference between the two state machines
Due to the difference between the two models, it is not difficult to see that the output of the Mealy type state machine will change immediately when the input changes, without relying on the clock. When the input state of the Moore-type state machine changes, the output needs to be changed after clock synchronization. That is, the output of the Moore-type state machine takes one more clock cycle than the Mealy-type state machine. Practical state machines are generally designed in synchronous timing mode.

2. Verilog description of finite state machine

-The design of the state machine mainly includes the following three objects:

  • Current State, or CS (Current State, CS)
  • Next State, or NS (Next State, NS)
  • Out Logic (OL)

-Verilog description method

  • Three-paragraph description (CS, NS, OL)
  • Two-paragraph description (CS+NS, OL) or (CS, NS+OL)
  • Single paragraph description (CS+NS+OL)

-Example (Coke machine: 2.5¥ produces Coke, you can invest 0.5¥, 1¥)
1. First draw the state transition diagram, it is ugly, but it is probably like this, For the sake of simplicity, change is not considered, and no coin input is counted as input.
Insert image description here
2.Verilog description

2.1 Three-paragraph description

//三段式描述(CS、NS、OL)

module  Coke_Machine										//模块名
(
	input		wire		sys_clk		 	,				//输入时钟
	input		wire		sys_rst_n	 	,				//输入复位
	input		wire		pi_money_half	,				//输入0.5
	input		wire		pi_money_one	,				//输入1.0
	
	output	reg		po_cola
);

parameter		IDLE      = 5'b00001,			//状态编码,独热码
				HALF	  = 5'b00010,
				ONE       = 5'b00100,
				ONE_HALF  = 5'b01000,
				TWO	      = 5'b10000;

wire	[1:0]		pi_money;
reg 	[4:0]		state,next_state;

assign	pi_money = {pi_money_one,pi_money_half};				//合并输入,即输入0.5为01,输入1为10

always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		state <= IDLE;											//定义起始状态
	else
		state <= next_state;

always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		state <= IDLE;											//定义起始状态
	else	case(state)
		IDLE:		if(pi_money == 2'b01)
						next_state <= HALF;
					else if(pi_money == 2'b10)
						next_state <= ONE;
					else
						next_state <= IDLE;
		HALF:		if(pi_money == 2'b01)
						next_state <= ONE;
					else if(pi_money == 2'b10)
						next_state <= ONE_HALF;
					else
						next_state <= HALF;
		ONE:		if(pi_money == 2'b01)
						next_state <= ONE_HALF;
					else if(pi_money == 2'b10)
						next_state <= TWO;
					else
						next_state <= ONE;
		ONE_HALF:	if(pi_money == 2'b01)
						next_state <= TWO;
					else if(pi_money == 2'b10)
						next_state <= IDLE;
					else
						next_state <= ONE_HALF;
		TWO:		if(pi_money == 2'b01)
						next_state <= IDLE;
					else if(pi_money == 2'b10)
						next_state <= HALF;
					else
						next_state <= TWO;
		default:	next_state <= IDLE;
		endcase

always@(posedge sys_clk or negedge sys_rst_n)									//输出逻辑
	if(sys_rst_n == 1'b0)
		po_cola <= 1'b0;
	else if(((state == ONE_HALF) && (pi_money == 2'b10))
			|| ((state == TWO) && (pi_money == 2'b01))
			|| ((state == TWO) && (pi_money == 2'b10)))
		po_cola <= 1'b1;
	else
		po_cola <= 1'b0;
		
endmodule

2.2 Two-paragraph description (CS+NS, OL)

//两段式描述(CS+NS、OL)


module  Coke_Machine										//模块名
(
	input		wire		sys_clk		 	,				//输入时钟
	input		wire		sys_rst_n	 	,				//输入复位
	input		wire		pi_money_half	,				//输入01
	input		wire		pi_money_one	,				//输入10
	
	output	reg		po_cola
);

parameter		IDLE      = 5'b00001,			//状态编码,独热码
				HALF	  = 5'b00010,
				ONE       = 5'b00100,
				ONE_HALF  = 5'b01000,
				TWO	      = 5'b10000;

wire	[1:0]		pi_money;
reg 	[4:0]		state;

assign	pi_money = {pi_money_one,pi_money_half};				//合并输入,即输入0.5为01,输入1为10

always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		state <= IDLE;											//定义起始状态
	else	case(state)
		IDLE:		if(pi_money == 2'b01)
						state <= HALF;
					else if(pi_money == 2'b10)
						state <= ONE;
					else
						state <= IDLE;
		HALF:		if(pi_money == 2'b01)
						state <= ONE;
					else if(pi_money == 2'b10)
						state <= ONE_HALF;
					else
						state <= HALF;
		ONE:		if(pi_money == 2'b01)
						state <= ONE_HALF;
					else if(pi_money == 2'b10)
						state <= TWO;
					else
						state <= ONE;
		ONE_HALF:	if(pi_money == 2'b01)
						state <= TWO;
					else if(pi_money == 2'b10)
						state <= IDLE;
					else
						state <= ONE_HALF;
		TWO:		if(pi_money == 2'b01)
						state <= IDLE;
					else if(pi_money == 2'b10)
						state <= HALF;
					else
						state <= TWO;
		default:	state <= IDLE;
		endcase

always@(posedge sys_clk or negedge sys_rst_n)									//输出逻辑
	if(sys_rst_n == 1'b0)
		po_cola <= 1'b0;
	else if(((state == ONE_HALF) && (pi_money == 2'b10))
			|| ((state == TWO) && (pi_money == 2'b01))
			|| ((state == TWO) && (pi_money == 2'b10)))
		po_cola <= 1'b1;
	else
		po_cola <= 1'b0;
		
endmodule

2.3 Single process description

//单段式描述


module  Coke_Machine										//模块名
(
	input		wire		sys_clk		 	,				//输入时钟
	input		wire		sys_rst_n	 	,				//输入复位
	input		wire		pi_money_half	,				//输入01
	input		wire		pi_money_one	,				//输入10
	
	output	reg		po_cola
);

parameter		IDLE      = 5'b00001,			//状态编码,独热码
				HALF	  = 5'b00010,
				ONE       = 5'b00100,
				ONE_HALF  = 5'b01000,
				TWO	      = 5'b10000;

wire	[1:0]		pi_money;
reg 	[4:0]		state;

assign	pi_money = {pi_money_one,pi_money_half};				//合并输入,即输入0.5为01,输入1为10

always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		state <= IDLE;											//定义起始状态
	else	case(state)
		IDLE:		if(pi_money == 2'b01)
					begin
						state <= HALF;
						po_cola <= 1'b0;
					end
					else if(pi_money == 2'b10)
					begin
						state <= ONE;
						po_cola <= 1'b0;
					end
					else
					begin
						state <= IDLE;
						po_cola <= 1'b0;
					end
		HALF:		if(pi_money == 2'b01)
					begin
						state <= ONE;
						po_cola <= 1'b0;
					end
					else if(pi_money == 2'b10)
					begin
						state <= ONE_HALF;
						po_cola <= 1'b0;
					end
					else
					begin
						state <= HALF;
						po_cola <= 1'b0;
					end
		ONE:		if(pi_money == 2'b01)
					begin
						state <= ONE_HALF;
						po_cola <= 1'b0;
					end
					else if(pi_money == 2'b10)
					begin
						state <= TWO;
						po_cola <= 1'b0;
					end
					else
					begin
						state <= ONE;
						po_cola <= 1'b0;
					end
		ONE_HALF:	if(pi_money == 2'b01)
					begin
						state <= TWO;
						po_cola <= 1'b0;
					end
					else if(pi_money == 2'b10)
					begin
						state <= IDLE;
						po_cola <= 1'b1;
					end
					else
					begin
						state <= ONE_HALF;
						po_cola <= 1'b0;
					end
		TWO:		if(pi_money == 2'b01)
					begin
						state <= IDLE;
						po_cola <= 1'b1;
					end
					else if(pi_money == 2'b10)
					begin
						state <= HALF;
						po_cola <= 1'b1;
					end
					else
					begin
						state <= TWO;
						po_cola <= 1'b0;
					end
		default:	
					begin
						state <= IDLE;
						po_cola <= 1'b0;
					end
		endcase
		
endmodule

3. Status coding

Common encoding methods:

  1. Sequential encoding Use sequential binary numbers to encode each state. For example, there are 4 states: 00, 01, 10, 11. The advantage is that it occupies less bits. The disadvantage is that when transitioning from one state to an adjacent state, multiple bits may change at the same time, which can easily cause glitches and cause logic errors.
  2. Gray coding Use Gray code to encode each state. For example, there are 4 states: 00, 01, 11, 10. The advantage is that fewer digits save logical units. Because adjacent state transitions only change one bit, the number of transients and the possibility of glitches are also reduced.
  3. Johnson coding The Johnson code is derived based on the Johnson counter, and the highest bit of the output is inverted and then fed back to the lowest bit. For example, there are 6 states: 000, 001, 011, 111, 110, 100, the same two adjacent states are only different in one bit, but the occupied bit width is much wider.
  4. 1-bit hot code encoding (one-hot code) Use n flip-flops to encode n states. For example, there are 4 states: 0001, 0010, 0100, 1000. The one-hot code occupies the most digits, but it can effectively save and simplify the decoding circuit and is used more.

**Reference materials:
Wang Jinming. "FPGA Design and Verilog HDL Implementation". Beijing: Electronic Industry Press, 2021.** a>

Guess you like

Origin blog.csdn.net/m0_51294753/article/details/128121323