【HDLBits 刷题 11】Circuits(7)Finite State Manchines 18-26

本文介绍了有限状态机在串行数据接收中的应用,包括如何设计状态机来识别和处理串行比特流中的字节,实现奇偶校验以及同步HDLC帧解码。通过实例展示了状态机的三段式设计,用于检测起始位、数据位、奇偶校验位、停止位,并处理错误情况。此外,还涉及了Mealy型状态机在2的补码计算和摩尔型状态机在串行通信中的应用。
摘要由CSDN通过智能技术生成

目录

写在前面

Finite State Manchines

Fsm serialdata

Fsm serialdp

Fsm hdlc

Design a Mealy FSM

ece241 2014 q5a

ece241 2014 q5b

2014 q3fsm

2014 q3bfsm


写在前面

HDLBits 刷题来到了最为重要的一部分---有限状态机,都说 Verilog 设计的精髓就是状态机的设计,可见状态机设计的重要性,通过三十多道的状态机的练习,可以更加熟悉状态机设计的要点,通常都设计为三段式,这样设计的状态机层次清晰且易于设计,时序上更为易懂。以下的解题方法不一定为最佳解决方案,有更好的方法欢迎提出,共同学习,共同进步!

Finite State Manchines

Fsm serialdata

设计一个有限状态机,可以识别何时在串行比特流中正确接收字节,请添加一个数据路径,该数据路径将输出正确接收的数据字节。out_byte 在完成时需要有效,并且是1,否则就不在乎。

请注意,串行协议首先发送最低有效位。

module top_module(
    input         clk,
    input         in,
    input         reset,    // Synchronous reset
    output [7:0]  out_byte,
    output        done
); 
//状态机状态申明
parameter  IDLE       =  12'b000000000001; 
parameter  START      =  12'b000000000010; 
parameter  BIT_ONE    =  12'b000000000100; 
parameter  BIT_TWO    =  12'b000000001000; 
parameter  BIT_THREE  =  12'b000000010000; 
parameter  BIT_FOUR   =  12'b000000100000; 
parameter  BIT_FIVE   =  12'b000001000000; 
parameter  BIT_SIX    =  12'b000010000000; 
parameter  BIT_SEVEN  =  12'b000100000000; 
parameter  BIT_EIGHT  =  12'b001000000000; 
parameter  STOP       =  12'b010000000000; 
parameter  WAIT       =  12'b100000000000;

reg  [11:0]   state;
reg  [11:0]   next_state;

//状态机第一段,状态初始化,时序逻辑非阻塞赋值
always @(posedge clk) begin
	if (reset) begin
		state <= IDLE;
	end
	else begin
		state <= next_state;
	end
end

//状态机第二段,状态跳转,阻塞赋值
always @(*) begin
	next_state = state;
	case(state)
		IDLE: begin
			if (~in) begin
				next_state = START;
			end
			else begin
				next_state = IDLE;
			end
		end
		START: begin
			next_state = BIT_ONE;
		end
		BIT_ONE: begin
			next_state = BIT_TWO;
		end
		BIT_TWO: begin
			next_state = BIT_THREE;
		end
		BIT_THREE:begin
			next_state = BIT_FOUR;
		end
		BIT_FOUR: begin
			next_state = BIT_FIVE;
		end
		BIT_FIVE: begin
			next_state = BIT_SIX;
		end
		BIT_SIX: begin
			next_state = BIT_SEVEN;
		end
		BIT_SEVEN: begin
			next_state = BIT_EIGHT;
		end
		BIT_EIGHT: begin
			if (in) begin
				next_state = STOP;
			end
			else begin
				next_state = WAIT;
			end
		end
		WAIT: begin
			if (in) begin
				next_state = IDLE;
			end
			else begin
				next_state = WAIT;
			end
		end
		STOP: begin
			if (in) begin
				next_state = IDLE;
			end
			else begin
				next_state = START;
			end	
		end
		default: begin
			next_state = IDLE;
		end
	endcase
end 

//状态机第三段,结果输出,组合逻辑
always @(posedge clk) begin
	if (reset) begin
		done     <= 'd0;
		out_byte <= 'd0;
	end
	else begin
        case(next_state)
			IDLE: begin
				done     <= 'd0;
				out_byte <= 'd0;				
			end
			START: begin
				done     <= 'd0;
				out_byte <= 'd0;
			end
			BIT_ONE: begin
				done        <= 'd0;
				out_byte[0] <= in; 
			end
			BIT_TWO: begin
				done        <= 'd0;
				out_byte[1] <= in; 
			end
			BIT_THREE: begin
				done        <= 'd0;
				out_byte[2] <= in; 
			end
			BIT_FOUR: begin
				done        <= 'd0;
				out_byte[3] <= in; 
			end
			BIT_FIVE: begin
				done        <= 'd0;
				out_byte[4] <= in; 
			end
			BIT_SIX: begin
				done        <= 'd0;
				out_byte[5] <= in; 
			end
			BIT_SEVEN: begin
				done        <= 'd0;
				out_byte[6] <= in; 
			end
			BIT_EIGHT: begin
				done        <= 'd0;
				out_byte[7] <= in; 
			end
			WAIT: begin
				done     <= in;
				out_byte <= out_byte;
			end
			STOP: begin
				done     <= 'd1;
				out_byte <= out_byte;
			end
			default: begin
				done     <= 'd0;
				out_byte <= 'd0;
			end
		endcase
	end
end

endmodule

Fsm serialdp

我们希望将奇偶校验添加到串行接收器。奇偶校验在每个数据字节后添加一个额外的位。我们将使用奇偶校验,其中接收的9位中的1s数必须是奇数。例如,101001011满足奇偶校验(有 5 个 1秒),但001001011则不满足奇偶校验。

更改 FSM 和数据路径以执行奇数奇偶校验。仅当正确接收到一个字节并且其奇偶校验通过时才置位完成的信号。喜欢串行接收器 FSM,此 FSM 需要识别起始位,等待所有 9 个(数据和奇偶校验)位,然后验证停止位是否正确。如果停止位未按预期出现,则 FSM 必须等到找到停止位后再尝试接收下一个字节。

为您提供了以下模块,可用于计算输入流的奇偶校验(它是具有重置功能的TFF)。预期用途是应为它提供输入位流,并在适当的时间重置,以便计算每个字节中的1位数。

module top_module(
    input         clk,
    input         in,
    input         reset,    // Synchronous reset
    output [7:0]  out_byte,
    output        done
); 
//状态机状态申明
parameter  IDLE       =  13'b0000000000001; 
parameter  START      =  13'b0000000000010; 
parameter  BIT_ONE    =  13'b0000000000100; 
parameter  BIT_TWO    =  13'b0000000001000; 
parameter  BIT_THREE  =  13'b0000000010000; 
parameter  BIT_FOUR   =  13'b0000000100000; 
parameter  BIT_FIVE   =  13'b0000001000000; 
parameter  BIT_SIX    =  13'b0000010000000; 
parameter  BIT_SEVEN  =  13'b0000100000000; 
parameter  BIT_EIGHT  =  13'b0001000000000;
parameter  PARITY_BIT =  13'b0010000000000;
parameter  STOP       =  13'b0100000000000; 
parameter  WAIT       =  13'b1000000000000;

reg  [12:0]   state;
reg  [12:0]   next_state;
reg           odd;

//状态机第一段,状态初始化,时序逻辑非阻塞赋值
always @(posedge clk) begin
	if (reset) begin
		state <= IDLE;
	end
	else begin
		state <= next_state;
	end
end

//状态机第二段,状态跳转,阻塞赋值
always @(*) begin
	next_state = state;
	case(state)
		IDLE: begin
			if (~in) begin
				next_state = START;
			end
			else begin
				next_state = IDLE;
			end
		end
		START: begin
			next_state = BIT_ONE;
		end
		BIT_ONE: begin
			next_state = BIT_TWO;
		end
		BIT_TWO: begin
			next_state = BIT_THREE;
		end
		BIT_THREE:begin
			next_state = BIT_FOUR;
		end
		BIT_FOUR: begin
			next_state = BIT_FIVE;
		end
		BIT_FIVE: begin
			next_state = BIT_SIX;
		end
		BIT_SIX: begin
			next_state = BIT_SEVEN;
		end
		BIT_SEVEN: begin
			next_state = BIT_EIGHT;
		end
		BIT_EIGHT: begin
			next_state = PARITY_BIT;
		end
		PARITY_BIT: begin
			if (in) begin
				next_state = STOP;
			end
			else begin
				next_state = WAIT;
			end
		end
		WAIT: begin
			if (in) begin
				next_state = IDLE;
			end
			else begin
				next_state = WAIT;
			end
		end
		STOP: begin
			if (in) begin
				next_state = IDLE;
			end
			else begin
				next_state = START;
			end	
		end
		default: begin
			next_state = IDLE;
		end
	endcase
end 

//状态机第三段,结果输出,组合逻辑
always @(posedge clk) begin
	if (reset) begin
		out_byte <= 'd0;
		done <= 'd0;
	end
	else begin
		case(next_state)
			IDLE: begin
				out_byte <= 'd0;
				done <= 'd0;
			end
			START: begin
				out_byte <= 'd0;
				done <= 'd0;
			end
			BIT_ONE: begin
				out_byte[0] <= in;
				done <= 'd0;
			end
			BIT_TWO: begin
				out_byte[1] <= in;
				done <= 'd0; 
			end
			BIT_THREE: begin
				out_byte[2] <= in;
				done <= 'd0;
			end
			BIT_FOUR: begin
				out_byte[3] <= in;
				done <= 'd0;
			end
			BIT_FIVE: begin
				out_byte[4] <= in;
				done <= 'd0;
			end
			BIT_SIX: begin
				out_byte[5] <= in;
				done <= 'd0; 
			end
			BIT_SEVEN: begin
				out_byte[6] <= in;
				done <= 'd0;
			end
			BIT_EIGHT: begin
				out_byte[7] <= in;
				done <= 'd0; 
			end
			PARITY_BIT: begin
				out_byte <= out_byte;
				done <= 'd0;
				
			end
			WAIT: begin
				out_byte <= out_byte;
				done <= 'd0;
			end
			STOP: begin
				out_byte <= out_byte;
				if (odd=='d1) begin
					done <= 'd1;	
				end
				else begin
					done <= 'd0;
				end
			end
			default: begin
				out_byte <= 'd0;
				done <= 'd0;
			end
		endcase
	end
end
// always @(posedge clk) begin
// 	if (reset) begin
// 		done <= 'd0;
// 	end
// 	else if (next_state==STOP && odd=='d1) begin
// 		done <= 'd1;
// 	end
// 	else begin
// 		done <= 'd0;
// 	end
// end

wire   rst;  
assign rst = (reset == 1'b1 || next_state == IDLE || next_state == START);

parity u_parity(
	.clk        (clk		),
    .reset      (rst     	),
    .in         (in			),
    .odd        (odd		)
);

endmodule

Fsm hdlc

同步 HDLC 成帧涉及解码连续的位数据流,以查找指示帧(数据包)开始和结束的位模式。看到 6 个连续的 1(即01111110)是一个指示帧边界的“标志”。为了避免数据流意外包含“标志”,发送方在每5个连续的1之后插入一个零,接收方必须检测并丢弃。如果连续有 7 个或更多个 1,我们还需要发出错误信号。

创建一个有限状态机来识别这三个序列:

  • 0111110:需要丢弃一个位的信号(丢弃)。
  • 01111110:标记帧的开头/结尾(标志)。
  • 01111111...: 错误 (7 或更多 1 ) (错误)。

重置 FSM 时,它应处于行为类似于上一个输入为 0 的状态。

下面是一些示例序列,用于说明所需的操作。

module top_module(
    input       clk,
    input       reset,    // Synchronous reset
    input       in,
    output      disc,
    output      flag,
    output      err
);

parameter  IDLE       =  10'b0000000001; 
parameter  BIT_ONE    =  10'b0000000010; 
parameter  BIT_TWO    =  10'b0000000100; 
parameter  BIT_THREE  =  10'b0000001000; 
parameter  BIT_FOUR   =  10'b0000010000; 
parameter  BIT_FIVE   =  10'b0000100000; 
parameter  BIT_SIX    =  10'b0001000000; 
parameter  STOP       =  10'b0010000000; 
parameter  DIS        =  10'b0100000000;
parameter  ERROR      =  10'b1000000000;

reg  [9:0]   state;
reg  [9:0]   next_state;

//状态机第一段,状态初始化,时序逻辑非阻塞赋值
always @(posedge clk) begin
	if (reset) begin
		state <= IDLE;
	end
	else begin
		state <= next_state;
	end
end

//状态机第二段,状态跳转,阻塞赋值
always @(*) begin
	next_state = state;
	case(state)
		IDLE: begin
			if (in) begin
				next_state = BIT_ONE;
			end
			else begin
				next_state = IDLE;
			end
		end
		BIT_ONE: begin
			if (in) begin
				next_state = BIT_TWO;
			end
			else begin
				next_state = IDLE;
			end
		end
		BIT_TWO: begin
			if (in) begin
				next_state = BIT_THREE;
			end
			else begin
				next_state = IDLE;
			end
		end
		BIT_THREE: begin
			if (in) begin
				next_state = BIT_FOUR;
			end
			else begin
				next_state = IDLE;
			end
		end
		BIT_FOUR: begin
			if (in) begin
				next_state = BIT_FIVE;
			end
			else begin
				next_state = IDLE;
			end
		end
		BIT_FIVE: begin
			if (in) begin
				next_state = BIT_SIX;
			end
			else begin
				next_state = DIS;
			end
		end
		BIT_SIX: begin
			if (~in) begin
				next_state = STOP;
			end
			else begin
				next_state = ERROR;
			end
		end
		STOP: begin
			if (in) begin
				next_state = BIT_ONE;
			end
			else begin
				next_state = IDLE;
			end
		end
		DIS: begin
			if (in) begin
				next_state = BIT_ONE;
			end
			else begin
				next_state = IDLE;
			end
		end
		ERROR: begin
			if (in) begin
				next_state = ERROR;
			end
			else begin
				next_state = IDLE;
			end
		end
		default: begin
			next_state = IDLE;
		end
	endcase
end

//状态机第三段,结果输出,时序逻辑非阻塞赋值
always @(posedge clk) begin
	if (reset) begin
		disc <= 'd0;
		flag <= 'd0;
		err  <= 'd0;
	end
	else begin
		case(next_state)
			DIS: begin
				disc <= 'd1;
				flag <= 'd0;
				err  <= 'd0;
			end
			STOP: begin
				disc <= 'd0;
				flag <= 'd1;
				err  <= 'd0;							
			end
			ERROR: begin
				disc <= 'd0;
				flag <= 'd0;
				err  <= 'd1;
			end
			default: begin
				disc <= 'd0;
				flag <= 'd0;
				err  <= 'd0;
			end
		endcase
	end
end
 
endmodule

Design a Mealy FSM

实现一个 Mealy 型有限状态机,该状态机在名为 x 的输入信号上识别序列“101”。您的 FSM 应具有一个输出信号 z,当检测到“101”序列时,该信号被置位到逻辑-1。您的 FSM 还应具有低电平有效异步复位。您的状态机中可能只有 3 个状态。您的 FSM 应识别重叠序列。

module top_module (
    input      clk,
    input      aresetn,    // Asynchronous active-low reset
    input      x,
    output     z 
);

//状态定义
parameter  IDLE       =  4'b0001;
parameter  BIT_ONE    =  4'b0010;
parameter  BIT_TWO    =  4'b0100;
parameter  BIT_THREE  =  4'b1000;

//现态和次态
reg  [3:0]   state;
reg  [3:0]   next_state;

//状态机第一段,初始化状态,时序逻辑非阻塞赋值
always @(posedge clk or negedge aresetn) begin
	if (!aresetn) begin
		state <= IDLE;
	end
	else begin
		state <= next_state;
	end
end

//状态机第二段,状态跳转,阻塞赋值
always @(*) begin
	next_state = state;
	case(state)
		IDLE: begin
			if (x) begin
				next_state = BIT_ONE;
			end
			else begin
				next_state = IDLE;
			end
		end
		BIT_ONE: begin
			if (~x) begin
				next_state = BIT_TWO;
			end
			else begin
				next_state = BIT_ONE;
			end
		end
		BIT_TWO: begin
			if (x) begin
				next_state = BIT_THREE;
			end
			else begin
				next_state = IDLE;
			end
		end
		BIT_THREE: begin
			if (x) begin
				next_state = BIT_ONE;
			end
			else begin
				next_state = BIT_TWO;
			end
		end
		default: begin
			next_state = IDLE;
		end
	endcase
end

//状态机第三段,结果输出,组合逻辑
assign z = (next_state==BIT_THREE);

endmodule

ece241 2014 q5a

设计一个单输入一输出串行2的补码器摩尔状态机。输入(x)是一系列位(每个时钟周期一个),从数字的最低有效位开始,输出(Z)是输入的2的补码。机器将接受任意长度的输入数字。该电路需要异步复位。释放重置时开始转换,断言重置时停止转换。

module top_module (
    input       clk,
    input       areset,
    input       x,
    output      z
); 

parameter  MSB    =  3'b001;
parameter  OUT_1  =  3'b010;
parameter  OUT_0  =  3'b100;

reg  [2:0]     state;
reg  [2:0]     next_state;

//状态机第一段,状态初始化,时序逻辑非阻塞赋值
always @(posedge clk or posedge areset) begin
	if (areset) begin
		state <= MSB;
	end
	else begin
		state <= next_state;
	end
end

//状态机第二段,状态跳转,阻塞赋值
always @(*) begin
	next_state = state;
	case(state)
		MSB: begin
			if (x) begin
				next_state = OUT_1;
			end
			else begin
				next_state = MSB;
			end
		end
		OUT_1: begin
			if (x) begin
				next_state = OUT_0;
			end
			else begin
				next_state = OUT_1;
			end
		end
		OUT_0: begin
			if (~x) begin
				next_state = OUT_1;
			end
			else begin
				next_state = OUT_0;
			end
		end
		default: begin
			next_state = MSB;
		end
	endcase
end

//状态机第三段,结果输出,组合逻辑
assign z = (state==OUT_1);

endmodule

ece241 2014 q5b

利用独热码编写一下的米利状态机。

module top_module (
    input       clk,
    input       areset,
    input       x,
    output      z
); 

parameter  A  =  2'b01;
parameter  B  =  2'b10;

reg  [1:0]     state;
reg  [1:0]     next_state;

//状态机第一段,状态初始化,时序逻辑非阻塞赋值
always @(posedge clk or posedge areset) begin
	if (areset) begin
		state <= A;
	end
	else begin
		state <= next_state;
	end
end

//状态机第二段,状态跳转,阻塞赋值
always @(*) begin
	next_state = state;
	case(state)
		A: begin
			if (x) begin
				next_state = B;
				z = 'd1;
			end
			else begin
				next_state = A;
				z = 'd0;
			end
		end
		B: begin
			next_state = B;
			if (x) begin
				z = 'd0;
			end
			else begin
				z = 'd1;
			end
		end
	endcase
end

endmodule

2014 q3fsm

module top_module (
    input       clk,
    input       reset,   // Synchronous reset
    input       s,
    input       w,
    output      z
);

parameter  IDLE =  5'b00001;
parameter  A    =  5'b00010;
parameter  B    =  5'b00100;
parameter  C    =  5'b01000;
parameter  D    =  5'b10000;

reg  [4:0]    state;
reg  [4:0]    next_state;
reg  [10:0]   cnt;

//状态机第一段,状态初始化,时序逻辑非阻塞赋值
always @(posedge clk) begin
	if (reset) begin
		state <= IDLE;
	end
	else begin
		state <= next_state;
	end
end

//状态机第二段,状态跳转,阻塞赋值
always @(*) begin
	case(state)
		IDLE: begin
			if (s) begin
				next_state = A;
			end
			else begin
				next_state = IDLE;
			end
		end
		A: begin
			next_state = B;
		end
		B: begin
			next_state = C;
		end
		C: begin
			next_state = D;
		end
		D: begin
			next_state = B;
		end
		default: begin
			next_state = IDLE;
		end
	endcase
end

always @(posedge clk) begin
	if (reset) begin
		cnt <= 'd0;
	end
	else begin
		case(next_state)
			IDLE: begin
				cnt <= 'd0;
			end
			A: begin
				cnt <= 'd0;
			end
			B: begin
				if (w) begin
					cnt <= 'd1;
				end
				else begin
					cnt <= 'd0;
				end
			end
			C: begin
				if (w) begin
					cnt <= cnt + 'd1;
				end
				else begin
					cnt <= cnt;
				end
			end
			D: begin
				if (w) begin
					cnt <= cnt + 'd1;
				end
				else begin
					cnt <= cnt;
				end
			end
		endcase
	end
end

assign z = (state==D && cnt=='d2);

endmodule

2014 q3bfsm

给定如下所示的状态分配表,实现有限状态机。重置应将 FSM 重置为状态 000。

module top_module (
    input      clk,
    input      reset,   // Synchronous reset
    input      x,
    output     z
);

parameter  A  =  3'b000;
parameter  B  =  3'b001;
parameter  C  =  3'b010;
parameter  D  =  3'b011;
parameter  E  =  3'b100;

reg  [2:0]  state;
reg  [2:0]  next_state;

//状态机第一段,状态初始化,时序逻辑非阻塞赋值
always @(posedge clk) begin
	if (reset) begin
		state <= A;
	end
	else begin
		state <= next_state;
	end
end

//状态机第二段,状态跳转,阻塞赋值
always @(*) begin
	next_state = state;
	case(state)
		A: begin
			if (x) begin
				next_state = B;
			end
			else begin
				next_state = A;
			end
		end
		B: begin
			if (x) begin
				next_state = E;
			end
			else begin
				next_state = B;
			end
		end
		C: begin
			if (x) begin
				next_state = B;
			end
			else begin
				next_state = C;
			end
		end
		D: begin
			if (x) begin
				next_state = C;
			end
			else begin
				next_state = B;
			end
		end
		E: begin
			if (x) begin
				next_state = E;
			end
			else begin
				next_state = D;
			end
		end
		default: begin
			next_state = A;
		end
	endcase
end

//状态机第三段,结果输出,组合逻辑
assign z = (state==D) || (state==E);

endmodule
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linest-5

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值