[HDLBits做题]Sequential Logic --- Finite State Machines (II)


周内杂事太多,找了借口想着周末刷刷题。
结果周末看了球,大连人队降级了,十分难过,又找了借口没做题。
好吧,颓废了一周,那么新的一周,收拾好心情,重新出发!


(上接2.5Finite State Machine(I))

2.5.14 One-hot FSM [Fsm onehot]
问题描述

给定下图一个具有一个输入和两个输出的有限状态机:
image
假设该状态机使用独热编码,其中state[0]到state[9]分别对应S0到S9状态。除非另有说明,否则输出为0。
实现有限状态机的状态转换逻辑和输出逻辑部分(但不是状态触发器)。在state[9:0]中给出当前状态,并且必须生成next_state[9:0]和两个输出。假设独热编码,推导出逻辑方程。

代码
module top_module(
    input in,
    input [9:0] state,
    output [9:0] next_state,
    output out1,
    output out2);

	 parameter S0=0,S1=1,S2=2,S3=3,S4=4,S5=5,S6=6,S7=7,S8=8,S9=9;
	 
	 assign next_state[S0] = (state[S0]&~in)|(state[S1]&~in)|(state[S2]&~in)|(state[S3]&~in)|(state[S4]&~in)|(state[S7]&~in)|(state[S8]&~in)|(state[S9]&~in);
	 assign next_state[S1] = (state[S0]& in)|(state[S8]& in)|(state[S9]& in);
	 assign next_state[S2] = (state[S1]& in);
	 assign next_state[S3] = (state[S2]& in);
	 assign next_state[S4] = (state[S3]& in);
	 assign next_state[S5] = (state[S4]& in);
	 assign next_state[S6] = (state[S5]& in);
	 assign next_state[S7] = (state[S6]& in)|(state[S7]& in);
	 assign next_state[S8] = (state[S5]&~in);
	 assign next_state[S9] = (state[S6]&~in);
	 
	 assign out1 = state[S8] | state[S9];
	 assign out2 = state[S7] | state[S9];
endmodule
2.5.15 PS/2 packet parser [Fsm ps2]
问题描述

PS/2鼠标协议发送三个字节长的消息,然而,在连续的字节流中,消息的开始和结束并不明显。唯一指示是每个三字节消息的第一字节总是具有bit[3]=1(但是其他两个字节的bit[3]根据数据可以是1也可以是0)。
我们需要一个有限状态机,当给定一个输入字节流时,它将搜索消息边界。我们将使用的算法是丢弃字节,直到我们看到一个bit[3]=1,然后我们假设这是消息的字节1,并且一旦所有三个字节都被接收(完成),就用信号通知消息的接收。
FSM应在每个消息的第三个字节成功接收后立即在周期内发出完成信号。

一些时序图来解释所需行为

在这里插入图片描述

提示及状态转移图
  • 虽然in[7:0]是一个字节,但FSM只有一个输入in[3]。
  • 你需要4个状态,有三个状态可能没有作用,因为其中只有一个状态需要done输出,而对于每个接收到的信息,done仅在一个周期内使能。
    image
代码
module top_module(
    input clk,
    input [7:0] in,
    input reset,    // Synchronous reset
    output done); //
	 
	 parameter BYTE1=1,BYTE2=2,BYTE3=3,DONE=0;
	 reg [1:0] state,next_state;
    // State transition logic (combinational)
	 always@(*) begin
		case(state)
			BYTE1 : next_state = in[3] ? BYTE2 : BYTE1;
			BYTE2 : next_state = BYTE3;
			BYTE3 : next_state = DONE;
			DONE  : next_state = in[3] ? BYTE2 : BYTE1;
		endcase
	 end	
    // State flip-flops (sequential)
	 always@(posedge clk) begin
		if(reset)
			state <= BYTE1;
		else
			state <= next_state;
	 end
    // Output logic
	 assign done = (state == DONE);

endmodule
2.5.16 PS/2 packet parser and datapath [Fsm ps2data]
问题描述

现在,已经有一个可以识别PS/2字节流中三消息的有限状态机,增加一个数据通道datapath,当收到三字节消息后,该通道将会输出24位消息。
每当done信号为高电平时,out_bytes应当有效输出,其他时间的输出并不重要。
在这里插入图片描述

分析

在前一问的基础上,增加对载入数据的输出。

代码
module top_module(
    input clk,
    input [7:0] in,
    input reset,    // Synchronous reset
    output reg [23:0] out_bytes,
    output done); //
	 
	 parameter BYTE1=1,BYTE2=2,BYTE3=3,DONE=0;
	 reg [1:0] state,next_state;
    // State transition logic (combinational)
	 always@(*) begin
		case(state)
			BYTE1 : next_state = in[3] ? BYTE2 : BYTE1;
			BYTE2 : next_state = BYTE3;
			BYTE3 : next_state = DONE;
			DONE  : next_state = in[3] ? BYTE2 : BYTE1;
		endcase
	 end	
    // State flip-flops (sequential)
	 always@(posedge clk) begin
		if(reset)
			state <= BYTE1;
		else
			state <= next_state;
	 end
    // Output logic
	 always@(posedge clk) begin
		case(state)
			BYTE1 : out_bytes[23:16] <= in;
			BYTE2 : out_bytes[15:8] <= in;
			BYTE3 : out_bytes[7:0] <= in;
			DONE  : out_bytes[23:16] <= in;
		endcase
	 end
	 
	 assign done = (state == DONE);

endmodule
2.5.17 Serial receiver [Fsm serial]
问题描述

在很多(较老)的串口通信协议当中,每个数据字节都会发送一个起始位和一个停止位,以帮助接收器从比特流中分隔字节。一种常见的方案是使用一位起始比特0,8位数据和一位终止比特1.当没有数据传输时,线路也处于逻辑1(空闲)。
设计一个有限状态机,当给定一个比特流时,它能够识别何时正确的接受了字节。它需要识别起始位,等待所有8个比特,然后验证停止位是否正确。如果停止位未按照预期出现,FSM必须等待直到找到停止位后再尝试接收下一个字节。

时序图举例

在这里插入图片描述

分析

注意当状态转移到ERROR情况下的时候,如果输入端的比特仍然是低位,并不代表找到了下一个起始位,而是应该等到下一次空闲状态之后重新找到起始位。
根据题意理解,设置了idle、start、read、error、done五个状态,其中转移的参数主要涉及当前输入比特in以及用于计算数据位数的cntBytes,具体状态转移的情况可以依据下图。

状态转移图

在这里插入图片描述

代码
module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output done
); 
	parameter IDLE=0,START=1,READ=2,ERROR=3,DONE=4;
	reg [2:0] state,next_state;
	reg [3:0] cntBytes;
	
	always@(posedge clk) begin
		if(reset) 
			state <= IDLE;
		else
			state <= next_state;
	end
	
	always@(*) begin
		case(state)
			IDLE  : next_state = in ? IDLE : START;
			START : next_state = READ;
			READ  : 
				if(cntBytes<8) 
					next_state = READ;
				else
					next_state = in ? DONE : ERROR;
			ERROR : next_state = in ? IDLE : ERROR;
			DONE  : next_state = in ? IDLE : START;
		endcase
	end
	
	always@(posedge clk) begin
		case(next_state)
			START : cntBytes <= 0;
			READ  : cntBytes <= cntBytes + 1;
			default : cntBytes <= cntBytes;
		endcase
	end
	
	assign done = (state==DONE);
endmodule
2.5.18 Serial receiver and datapath [Fsm serialdata]
问题描述

根据上一题,已经得到一个有限状态机,可以识别在串行比特流中何时能够正确接收数据字节,添加一个数据路径用于输出正确接收的数据字节。out_byte必须在done=1时有效,其他时候不在乎它的值。
需要注意的是,串行协议首先发送数据的最低有效位。
在这里插入图片描述

提示 串行比特流需要一次移位一个比特,然后并行读出。

代码
module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
	 output [7:0] out_byte,
    output done
); 
	parameter IDLE=0,START=1,READ=2,ERROR=3,DONE=4;
	reg [2:0] state,next_state;
	reg [3:0] cntBytes;
	
	always@(posedge clk) begin
		if(reset) 
			state <= IDLE;
		else
			state <= next_state;
	end
	
	always@(*) begin
		case(state)
			IDLE  : next_state = in ? IDLE : START;
			START : next_state = READ;
			READ  : 
				if(cntBytes<8) 
					next_state = READ;
				else
					next_state = in ? DONE : ERROR;
			ERROR : next_state = in ? IDLE : ERROR;
			DONE  : next_state = in ? IDLE : START;
		endcase
	end
	
	always@(posedge clk) begin
		case(next_state)
			START : cntBytes <= 0;
			READ  : cntBytes <= cntBytes + 1;
			default : cntBytes <= cntBytes;
		endcase
	end
	
	always@(posedge clk) begin
		case(state) 
			START : out_byte[7] <= in; 
			READ  : begin
				if(cntBytes<8) begin
					out_byte = out_byte >> 1;
					out_byte[7] <= in;
				end
			end
		endcase
	end
	
	assign done = (state==DONE);
endmodule
2.5.19 Serial receiver with parity checking [Fsm serialdp]
问题描述

我们想在串行接收器中增加奇偶校验。奇偶校验在每个数据字节后添加一个额外的位。我们将使用奇校验,其中接收到的9位中的1必须是奇数,例如101001011满足而001001011不满足。
更改FSM和datapath,当只有一个字节被正确接收并且它的奇偶校验通过时,才算成功接收。与前面两题一样,该FSM也需要识别起始位,等待所有九个(数据8位+校验1位),然后验证停止位是否正确。如果发现停止位未按预期出现,则FSM需等待到找到停止位后重新尝试接收下一个字节。
你可以使用下述模块用于计算输入流的奇偶校验(有重置位的TFF)。

module parity(
    input clk,
    input reset,
    input in,
    output reg odd
);
    always@(posedge clk) begin
        if(reset) odd<=0;
        else if (in) odd<= ~odd;
    end
endmodule

请注意,串行协议首先发送最低有效位,8个数据位之后发送奇校验位。

代码
module parity (
    input clk,
    input reset,
    input in,
    output reg odd);

    always @(posedge clk)
        if (reset) odd <= 0;
        else if (in) odd <= ~odd;
endmodule

module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output reg [7:0] out_byte,
    output done
); 
	parameter IDLE=0,START=1,READ=2,CHECK=3,ERROR=4,DONE=5;
	reg [3:0] state,next_state,cnt;
	wire start,odd;
	reg checked,rst;
	//
	parity oddcheck(.clk(clk),.reset(rst|reset),.in(in),.odd(odd));
	//
	always@(posedge clk) begin
		if(reset)
			state <= IDLE;
		else
			state <= next_state;
	end
	
	always@(*) begin
		case(state)
			IDLE 	: next_state = in ? IDLE : START;
			START : next_state = READ;
			READ 	: next_state = (cnt==7) ? CHECK : READ;
			CHECK	: next_state = in ? DONE : ERROR;
			ERROR	: next_state = in ? IDLE : ERROR;
			DONE	: next_state = in ? IDLE : START;
		endcase
	end
	
	always@(posedge clk) begin
		case(state)
			START : cnt <= 0;
			READ 	: cnt <= cnt + 1;
			default : cnt<=cnt;
		endcase
	end
	
	always@(*) begin
		case(next_state)
			START	: rst <= 1;
			default: rst <= 0;
		endcase
	end
	
	always@(posedge clk) begin
		case(next_state)
			DONE : checked <= odd;
			default : checked<=checked;
		endcase
	end
	
	always@(posedge clk) begin
		case(state) 
			START : out_byte[7] <= in;
			READ  : begin
				if(cnt<7) begin
					out_byte = out_byte >> 1;
					out_byte[7] <= in;
				end
			end
		endcase
	end	
	assign done = (state == DONE) & checked;
endmodule

这个题真的是捯饬了挺久的,主要卡在了rst(即奇偶校验模块的重置)信号上,一开始用的是非阻塞赋值,一直到自己重新把时序图顺了一遍才发现是奇偶校验模块的问题,又过了一遍最后才确定问题是出现在rst的那个部分。整体的思路上其实与前一题没有什么大的改变,只不过是在读入之后多了一个校验状态。这数据8bit和校验1bit总共组成的9个bit通过奇偶校验模块得到checked信号为高电平,同时处于DONE状态时,即done信号置高电平。

2.5.20 Sequence recognition [Fsm hdlc]
问题描述

同步HDLC成帧涉及对连续数据位流进行解码,以查找指示帧(数据包)的开始和结束。当正好看到连续6个连续的1时(即,01111110),就是指示帧边界的标志。为了避免在数据流中意外包含开始或结束标志,发送方会在每5个连续的1之后插入一个0,接收方则需要检测并丢弃这一位。而当出现7个或7个以上连续的1出现时,我们还需要发出错误信号。
创建一个有限状态机来识别这三种序列:

  • 0111110 : 信号中内插的0需要被遗弃(disc)
  • 01111110 : 标记帧的开始或结束(flag)
  • 01111111…:错误帧(连续7个或更多1)(err)

当FSM复位时他应该处于一种像先前的输入为0时的状态。
下面是一些说明所需操作的时序图示例:
在这里插入图片描述

状态转移图

题目当中提示给出了一个十个状态的有限状态机如下图所示:
image
这个状态转移图也十分的清晰,可以直接写。

代码
module top_module(
    input clk,
    input reset,    // Synchronous reset
    input in,
    output disc,
    output flag,
    output err);
	 
	 parameter NONE=0,ONE=1,TWO=2,THREE=3,FOUR=4,FIVE=5,SIX=6,ERROR=7,DISCARD=8,FLAG=9;
	 reg [3:0] state,next_state;
	 
	 always@(posedge clk) begin
		if(reset)
			state <= NONE;
		else
			state <= next_state;
	 end
	 
	 always@(*) begin
		case(state)
			NONE		: next_state = in ? ONE : NONE;
			ONE		: next_state = in ? TWO : NONE;
			TWO		: next_state = in ? THREE : NONE;
			THREE		: next_state = in ? FOUR : NONE;
			FOUR		: next_state = in ? FIVE : NONE;
			FIVE		: next_state = in ? SIX : DISCARD;
			SIX		: next_state = in ? ERROR : FLAG;
			ERROR		: next_state = in ? ERROR : NONE;
			DISCARD	: next_state = in ? ONE : NONE;
			FLAG 		: next_state = in ? ONE : NONE;
		endcase
	 end
	 
	 assign disc = (state == DISCARD);
	 assign flag = (state == FLAG);
	 assign err  = (state == ERROR);
	 
endmodule
2.5.21 Q8:Design a Mealy FSM [Exams/ece241 2013 q8]
问题描述

实现一个Mealy类有限状态机,识别输入信号x中的序列“101”。FSM应该有一个输出信号z,当检测到有101序列出现时,这个信号应该被置为1,同时这个FSM还应该具有低电平有效异步复位功能。要求该状态机中只能有3个状态,同时该有限状态机应该能够识别重叠的序列。

分析

要求仅使用三个状态,故设置IDLE、ONE、TWO三个状态,分别表示空闲状态,检测到输入为1状态,检测到输入为0状态。
空闲状态即复位或一直没有检测到1的输入时的状态,ONE状态为检测到第一个或第三个(重叠序列的第一个)1,ZERO状态为检测到第一个1后输入的0的状态。输出的结果z为高电平应该在ZERO状态同时输入为1时。

状态转移图

在这里插入图片描述

复位为异步低电平复位,置IDLE状态。

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

	 parameter IDLE=0,ONE=1,ZERO=2;
	 reg [1:0] state,next_state;
	 
	 always@(posedge clk or negedge aresetn) begin
		if(!aresetn)
			state <= IDLE;
		else
			state <= next_state;
	 end
	 
	 always@(*) begin
		case(state)
			IDLE	: next_state <= x ? ONE : IDLE;
			ONE	: next_state <= x ? ONE : ZERO;
			ZERO	: next_state <= x ? ONE : IDLE;
		endcase
	 end
	 
	 assign z = (state == ZERO) & (x == 1);
endmodule
2.5.22 Q5a:Serial two’s complementer(Moore FSM) [Exams/ece241 2014 q5a]
问题描述

请设计一个单输入单输出串行2的补码摩尔有限状态机。输入(x)是从数字的最低有效位开始的一些位数(每个时钟周期一个),输出(Z)是输入x的2的补码形式。机器将接受任意长度的输入数字。电路需要异步复位。数的转换在复位释放时开始,复位置位时停止。
例如:
在这里插入图片描述

分析

对于补码规则来说,正数的补码为原码,负数的补码为原码取反加一。
对于初始化后输入一直为0时,定义为IDLE状态,输出与输入一致。
对于遇到第一个输入为1时,输出保持为1,但对于后续继续输入的0输出1,输入的1输出0(即取反)。
则有如下状态转移图:
在这里插入图片描述

代码
module top_module (
    input clk,
    input areset,
    input x,
    output z
); 
	parameter IDLE = 0,s1 = 1,s2 = 2;
	reg [1:0] state,next_state;
	always@(posedge clk or posedge areset) begin
		if(areset)
			state <= IDLE;
		else
			state <= next_state;
	end

	always@(*) begin
		case(state)
			IDLE	: next_state = x ? s1 : IDLE;
			s1		: next_state = x ? s2 : s1;
			s2		: next_state = x ? s2 : s1;
		endcase
	end
	
	assign z = state == s1;
	
endmodule
2.5.23 Q5b:Serial two’s complementer(Mealy FSM) [Exams/ece241 2014 q5b]
问题描述

下图是2的补码的Mealy状态机实现,请使用独热编码实现。
image
在这里插入图片描述

分析

从时序图中可以看出,输出z与输入x与上一题中有所不同,上一题中输出晚于输入一个时钟节拍,本题是在同一时钟节拍输入输出。对于独热编码,两个状态因此分别为01、10 两个状态。

代码
module top_module (
    input clk,
    input areset,
    input x,
    output z
); 
	parameter A=2'b01,B=2'b10;
	reg [1:0] state,next_state;

	always@(posedge clk or posedge areset) begin
		if(areset)
			state <= A;
		else 
			state <= next_state;
	end
	
	always@(*) begin
		case(state)
			A	: next_state = x ? B : A;
			B	: next_state = x ? B : B;
		endcase
	end
	
	assign z = (state==A & x) | (state==B & ~x);

endmodule

这个系列主要是记录一下自己的学习过程和简单的思考过程,参考了许多他人的思路。题目均为HDLBits上的题目,借助翻译器与自己的理解组织了题目描述,如果有问题欢迎批评指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值