HDLBits刷题合集—17 Finite State Machines-3
HDLBits-133 Fsm onehot
Problem Statement
给定以下具有1个输入和2个输出的状态机:
假设此状态机使用独热编码,其中state[0]至state[9]分别对应于状态S0至S9。 除非另有说明,否则输出为零。
实现状态机的状态转换逻辑和输出逻辑部分(但不实现状态触发器)。 你将给定state[9:0]中的当前状态,并且必须产生next_state [9:0]和两个输出。通过假设独热编码,通过检验推导出逻辑方程 。(测试台将使用非独热码输入进行测试,以确保你没有尝试做更复杂的事情)。
Hint:可以通过查看状态转换图的in部分,来推导出独热状态转换逻辑的逻辑方程式。
代码如下:
module top_module(
input in,
input [9:0] state,
output [9:0] next_state,
output out1,
output out2);
assign next_state[0] = ~in & (state[0]|state[1]|state[2]|state[3]|state[4]|state[7]|state[8]|state[9]);
assign next_state[1] = in & (state[0] | state[8] | state[9]);
assign next_state[2] = in & state[1];
assign next_state[3] = in & state[2];
assign next_state[4] = in & state[3];
assign next_state[5] = in & state[4];
assign next_state[6] = in & state[5];
assign next_state[7] = in & (state[6] | state[7]);
assign next_state[8] = ~in & state[5];
assign next_state[9] = ~in & state[6];
assign out1 = state[8] | state[9];
assign out2 = state[7] | state[9];
endmodule
HDLBits-134 Fsm ps2
Problem Statement
PS / 2鼠标协议发送三字节长的消息。 但是,在连续的字节流中,消息的开始和结束位置并不明显。 唯一的指示是,每个三字节消息的第一个字节始终具有bit[3] = 1(但其他两个字节的bit [3]取决于数据,可能是1或0)。
我们需要一个有限状态机,当给定输入字节流时它将搜索消息边界。 我们将使用的算法是丢弃字节,直到看到bit [3] = 1的字节为止。 然后,我们假定这是消息的字节1,并且一旦接收到所有3个字节(完成),就发出接收消息的信号。
在成功接收到每个消息的第三个字节之后,FSM应该立即在周期中发出完成信号。
在无错误条件下,每三个字节形成一条消息:
请注意,这与1xx序列识别器不同。 此处不允许重叠序列:
Hint:尽管in[7:0]是一个字节,但是FSM只有一个输入:in[3]。你需要大约4个状态。 三种状态可能不起作用,因为其中一种状态需要断言完成,并且对于每个收到的消息,仅在一个周期内断言完成状态。
代码如下:
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output done); //
reg [1:0] state,state_next;
parameter S0 = 0, S1 = 1, S2 = 2, S3 = 3;
// State transition logic (combinational)
always @(*) begin
case (state)
S0 : begin
if (in[3]==1) state_next <= S1;
else state_next <= S0;
end
S1 : begin
state_next <= S2;
end
S2 : begin
state_next <= S3;
end
S3 : begin
if (in[3]==1) state_next <= S1;
else state_next <= S0;
end
endcase
end
// State flip-flops (sequential)
always @(posedge clk) begin
if (reset)
state <= S0;
else
state <= state_next;
end
// Output logic
assign done = (state == S3);
endmodule
HDLBits-135 Fsm ps2data
Problem Statement
另请参阅:上一题Fsm ps2。
现在已经有了一个状态机,该状态机将标识PS / 2字节流中的三字节消息,添加一个数据路径,该数据路径将在接收到数据包时也输出24位(3字节)消息(out_bytes [23:16] 是第一个字节,out_bytes [15:8]是第二个字节,依此类推)。
断言完成信号时,out_bytes必须有效。 你可能会在其他时间输出任何内容(即,don’t-care)。
例如:
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output [23:0] out_bytes,
output done); //
// FSM from fsm_ps2
reg [1:0] state,state_next;
reg [23:0] data;
parameter S0 = 0, S1 = 1, S2 = 2, S3 = 3;
// State transition logic (combinational)
always @(*) begin
case (state)
S0 : begin
if (in[3]==1) state_next <= S1;
else state_next <= S0;
end
S1 : begin
state_next <= S2;
end
S2 : begin
state_next <= S3;
end
S3 : begin
if (in[3]==1) state_next <= S1;
else state_next <= S0;
end
endcase
end
// State flip-flops (sequential)
always @(posedge clk) begin
if (reset)
state <= S0;
else
state <= state_next;
end
// Output logic
assign done = (state == S3);
// New: Datapath to store incoming bytes.
always @(posedge clk) begin
if (reset) begin
data <= 24'd0;
end
else begin
data[23:16] <= data[15:8];
data[15:8] <= data[7:0];
data[7:0] <= in;
end
end
assign out_bytes = (done) ? data : 24'd0;
endmodule
HDLBits-136 Fsm serial
Problem Statement
在许多(较旧的)串行通信协议中,每个数据字节都与起始位和停止位一起发送,以帮助接收器从比特流中分隔字节。 一种常见的方案是使用一个起始位(0),8个数据位和1个停止位(1)。 当没有任何传输(空闲)时,线路也处于逻辑1。
设计一个有限状态机,当给定比特流时,它将识别何时正确接收了字节。 它需要标识开始位,等待所有8个数据位,然后验证停止位是否正确。 如果在预期的情况下没有出现停止位,则FSM必须等待直到找到停止位,然后再尝试接收下一个字节。
无错误的情况:
未找到停止位。第一个字节被丢弃:
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output done
);
reg [3:0] state, state_next;
parameter START=0, S0=1, S1=2, S2=3, S3=4, S4=5, S5=6, S6=7, S7=8, S8=9, DONE0=10, DONE1=11;
always @(*) begin
case (state)
START : begin
if (in == 0) state_next <= S0;
else state_next <= START;
end
S0 : begin
state_next <= S1;
end
S1 : begin
state_next <= S2;
end
S2 : begin
state_next <= S3;
end
S3 : begin
state_next <= S4;
end
S4 : begin
state_next <= S5;
end
S5 : begin
state_next <= S6;
end
S6 : begin
state_next <= S7;
end
S7 : begin
state_next <= S8;
end
S8 : begin
if (in == 1) state_next <= DONE1;
else state_next <= DONE0;
end
DONE0 : begin
if (in == 1) state_next <= START;
else state_next <= DONE0;
end
DONE1 : begin
if (in == 1) state_next <= START;
else state_next <= S0;
end
default: begin
state_next <= START;
end
endcase
end
always @(posedge clk) begin
if(reset)
state <= START;
else
state <= state_next;
end
assign done = (state == DONE1);
endmodule
HDLBits-137 Fsm serialdata
Problem Statement
另请参阅:上一题Fsm serial。
现在已经有了一个有限状态机,可以确定何时在串行位流中正确接收了字节,添加一个数据路径,它将输出正确接收的数据字节。 当完成为1时,out_byte需要有效,否则don’t-care。
请注意,串行协议首先发送最低有效位。
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
); //
reg [3:0] state, state_next;
parameter START=0, S0=1, S1=2, S2=3, S3=4, S4=5, S5=6, S6=7, S7=8, S8=9, DONE0=10, DONE1=11;
always @(*) begin
case (state)
START : begin
if (in == 0) state_next <= S0;
else state_next <= START;
end
S0 : begin
state_next <= S1;
end
S1 : begin
state_next <= S2;
end
S2 : begin
state_next <= S3;
end
S3 : begin
state_next <= S4;
end
S4 : begin
state_next <= S5;
end
S5 : begin
state_next <= S6;
end
S6 : begin
state_next <= S7;
end
S7 : begin
state_next <= S8;
end
S8 : begin
if (in == 1) state_next <= DONE1;
else state_next <= DONE0;
end
DONE0 : begin
if (in == 1) state_next <= START;
else state_next <= DONE0;
end
DONE1 : begin
if (in == 1) state_next <= START;
else state_next <= S0;
end
default: begin
state_next <= START;
end
endcase
end
reg [7:0] out_byte_mid;
always @(posedge clk) begin
if(reset)
state <= START;
else
state <= state_next;
end
assign done = (state == DONE1);
always@(*) begin
case(state)
START: begin
;
end
S0: begin
out_byte_mid[0] <= in;
end
S1: begin
out_byte_mid[1] <= in;
end
S2: begin
out_byte_mid[2] <= in;
end
S3: begin
out_byte_mid[3] <= in;
end
S4: begin
out_byte_mid[4] <= in;
end
S5: begin
out_byte_mid[5] <= in;
end
S6: begin
out_byte_mid[6] <= in;
end
S7: begin
out_byte_mid[7] <= in;
end
S8: begin
;
end
DONE0: begin
;
end
DONE1: begin
;
end
default: begin
;
end
endcase
end
assign out_byte = (done == 1) ? out_byte_mid : 'bz;
endmodule
HDLBits-138 Fsm serialdp
Problem Statement
另请参阅:上一题Fsm serialdata。
我们要向串行接收器添加奇偶校验。奇偶校验在每个数据字节后增加一个额外的位。我们将使用奇数奇偶校验,其中接收到的9位中1的数量必须为奇数。例如,101001011满足奇偶校验(有5个1),而001001011不满足。
更改上面的FSM和数据路径以执行奇偶校验。仅当正确接收到一个字节并且其奇偶校验通过时,才声明完成信号。与串行接收器FSM一样,该FSM需要标识起始位,等待所有9位(数据和奇偶校验),然后验证停止位是否正确。如果在预期的情况下没有出现停止位,则FSM必须等待直到找到停止位,然后再尝试接收下一个字节。
提供了以下模块,该模块可用于计算输入流的奇偶校验(这是带复位的TFF)。预期的用途是应为它提供输入位流,并在适当的时间进行重置,以便它计算每个字节中1位的数目。
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 [7:0] out_byte,
output done
); //
// Modify FSM and datapath from Fsm_serialdata
parameter idle = 4'd0, start = 4'd1, trans0 = 4'd2,trans1 = 4'd3, trans2 = 4'd4, trans3 = 4'd5;
parameter trans4 = 4'd6, trans5 = 4'd7, trans6 = 4'd8, trans7 = 4'd9, stop = 4'd10, err = 4'd11, pari = 4'd12;
reg [3:0] state, next_state;
reg [7:0] data;
wire odd, reset_p;
reg done_reg;
always @(*) begin
case (state)
idle: next_state <= in ? idle : start;
start: next_state <= trans0;
trans0: next_state <= trans1;
trans1: next_state <= trans2;
trans2: next_state <= trans3;
trans3: next_state <= trans4;
trans4: next_state <= trans5;
trans5: next_state <= trans6;
trans6: next_state <= trans7;
trans7: next_state <= pari;
pari: next_state <= in ? idle : err;
err: next_state <= in ? idle : err;
endcase
end
always @(posedge clk) begin
if (reset) begin
state <= idle;
end
else begin
state <= next_state;
end
end
// New: Add parity checking.
always @(posedge clk) begin
if (reset) begin
data <= 8'd0;
reset_p <= 1'b1;
done_reg <= 1'b0;
end
else begin
if (next_state == trans0 || next_state == trans1 || next_state == trans2 || next_state == trans3 || next_state == trans4 || next_state == trans5 || next_state == trans6 || next_state == trans7) begin
data <= {in, data[7:1]};
end
else if (next_state == start) begin
data <= 8'd0;
reset_p <= 1'b0;
done_reg <= 1'b0;
end
else if (next_state == idle) begin
done_reg <= odd;
end
else if (next_state == pari) begin
reset_p <= 1'b1;
end
end
end
assign done = done_reg;
assign out_byte = done ? data : 8'd0;
parity par_mod(clk, reset | reset_p, in, odd);
endmodule
HDLBits-139 Fsm hdlc
Problem Statement
Synchronous HDLC framing涉及对数据的连续位流进行解码,以寻找指示帧(数据包)开始和结束的位模式。 恰好看到6个连续的1(即01111110)是表示帧边界的“flag”。 为了避免数据流意外包含“flag”,发送方必须在每5个连续的1秒后插入一个零,接收方必须检测并丢弃。 如果连续7个或更多1,我们还需要发出错误信号。
创建一个有限状态机来识别这三个序列:
0111110:信号位需要丢弃(disc)。
01111110:标记帧的开始/结束(flag)。
01111111 …:错误(7或更多1s)(err)。
重置FSM时,其状态应类似于先前的输入为0。
以下是一些示例序列,它们说明了所期望的操作。
Discard 0111110:
Flag 01111110:
Reset behaviour and error 01111111…:
Hint:
使用一个大约有10个状态的莫尔型状态机。
module top_module(
input clk,
input reset, // Synchronous reset
input in,
output disc,
output flag,
output err);
parameter S0=0, S1=1, S2=2, S3=3, S4=4, S5=5, S6=6, DISC=7, FLAG=8, ERR=9;
reg [3:0] state, state_next;
always @(*) begin
case (state)
S0 : begin
if (in) state_next <= S1;
else state_next <= S0;
end
S1 : begin
if (in) state_next <= S2;
else state_next <= S0;
end
S2 : begin
if (in) state_next <= S3;
else state_next <= S0;
end
S3 : begin
if (in) state_next <= S4;
else state_next <= S0;
end
S4 : begin
if (in) state_next <= S5;
else state_next <= S0;
end
S5 : begin
if (in) state_next <= S6;
else state_next <= DISC;
end
S6 : begin
if (in) state_next <= ERR;
else state_next <= FLAG;
end
DISC : begin
if (in) state_next <= S1;
else state_next <= S0;
end
FLAG : begin
if (in) state_next <= S1;
else state_next <= S0;
end
ERR : begin
if (in) state_next <= ERR;
else state_next <= S0;
end
endcase
end
always @(posedge clk)
begin
if (reset) state <= S0;
else state <= state_next;
end
assign disc = (state == DISC);
assign flag = (state == FLAG);
assign err = (state == ERR);
endmodule
Note
新手一枚,主要分享博客,记录学习过程,后期参考大佬代码或思想会一一列出。欢迎大家批评指正!