周内杂事太多,找了借口想着周末刷刷题。
结果周末看了球,大连人队降级了,十分难过,又找了借口没做题。
好吧,颓废了一周,那么新的一周,收拾好心情,重新出发!
(上接2.5Finite State Machine(I))
2.5.14 One-hot FSM [Fsm onehot]
问题描述
给定下图一个具有一个输入和两个输出的有限状态机:
假设该状态机使用独热编码,其中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仅在一个周期内使能。
代码
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时的状态。
下面是一些说明所需操作的时序图示例:
状态转移图
题目当中提示给出了一个十个状态的有限状态机如下图所示:
这个状态转移图也十分的清晰,可以直接写。
代码
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状态机实现,请使用独热编码实现。
分析
从时序图中可以看出,输出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上的题目,借助翻译器与自己的理解组织了题目描述,如果有问题欢迎批评指正。