本系列内容来自于知乎专栏,链接如下:https://zhuanlan.zhihu.com/c_1131528588117385216 本系列文章将和读者一起巡礼数字逻辑在线学习网站 HDLBits 的教程与习题,并附上解答和一些作者个人的理解,相信无论是想 7 分钟精通 Verilog,还是对 Verilog 和数电知识查漏补缺的同学,都能从中有所收获。
Problem 135 PS/2 packet parser and datapath / Fsm ps2data
牛刀小试
现在,已经写了一个PS/2接口的状态机,该状态机可以标识PS/2字节流中的三字节消息。请在这个状态机中添加一条数据路径,该数据路径可以在接收数据包的同时输出24bits(3字节)的消息(out_bytes[23:16]为第一字节,out_bytes[15:8]为第二字节,以此类推)。
当发出接收完成信号done时,out_bytes必须是有效的,其他时候可以输出任何的内容(即不在乎输出什么。)
小提示:使用前一题Problem 134 PS/2 packet parser / Fsm ps2 中的状态机,并添加用于捕捉输入字节的数据路径即可。
解答与分析
本题在前一题的三个没有输出动作的状态上添加out_bytes等于输入即可完成。值得注意的是状态4可以跳转为状态2,所以状态4也需要对out_bytes赋值。
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output [23:0] out_bytes,
output done); //
// FSM from fsm_ps2
parameter A = 2'b00;
parameter B = 2'b01;
parameter C = 2'b10;
parameter D = 2'b11;
reg [1:0] state,next_state;
always@(posedge clk)
if(reset)
state<=A;
else
state<=next_state;
always@(*)
case(state)
A:next_state=in[3]?B:A;
B:next_state=C;
C:next_state=D;
D:next_state=in[3]?B:A;
endcase
assign done = state ==D;
// New: Datapath to store incoming bytes.
always@(posedge clk)
case(state)
A:out_bytes[23:16]<=in;
B:out_bytes[15: 8]<=in;
C:out_bytes[ 7: 0]<=in;
D:out_bytes[23:16]<=in;
endcase
endmodule
Problem136 ~ Problem138 为串行接收器的部分,已经由小伙伴们完成了。附上链接,又可以偷懒啦~~~感谢
@近朱者赤
近朱者赤:HDLBits:Serial Receiver系列问题zhuanlan.zhihu.com
Problem 139 Sequuence recognition / Fsm hdlc
同步HDLC帧涉及从连续的比特流中解码寻找某一帧(即数据包)的开始和结束位置的位模式。(对位模式不太理解的可以参见zhuanlan.zhihu.com/p/46)。如果接收到连续的6个1(即01111110),即是帧边界的“标志”。同时为了避免输入的数据流中意外包含这个帧边界“标志”,数据的发送方必须在数据中连续的5个1之后插入一个0,而数据的接收方必须将这个多余的0检测出来并丢弃掉。同时,如果输入检测到了了连续7个或更多的1时,接收方还需要发出错误信号。
牛刀小试
下面请创建一个有限状态机来识别上述的三个序列:
重置FSM时,其状态应恢复到之前输入0的状态。
以下是一些示例序列,详细的说明了状态机所需的操作。
输入0111110,需要舍弃后面的0
输入01111110,判断为帧的开始/结束
复位逻辑和输入连续7个以上的1
小提示:
1、请使用10个状态以内的摩尔机。
2、状态图:
状态图
解答与分析
这道题可能比较难理解,不知道题干在说什么,但是看了下面的波形图还是能理解一些的,就是对连续输入的比特流进行判断,当连续输入5个1时,下一拍disc=1,当连续输入6个1时,flag=1,当输入的1数量超过7个时,将err置1,如果一旦有0输入,则返回初始状态。
此题还是建议自己去想一下状态转移是怎么样的,需要很多个状态,检测到1向下跳,检测到0返回初始状态,需要的状态比较多,但不要灰心,慢慢画一下。
module top_module(
input clk,
input reset, // Synchronous reset
input in,
output disc,
output flag,
output err);
parameter none=4'd0;
parameter one=4'd1;
parameter two=4'd2;
parameter three=4'd3;
parameter four=4'd4;
parameter five=4'd5;
parameter six=4'd6;
parameter error=4'd7;
parameter discard=4'd8;
parameter flag_=4'd9;
reg [3:0] state;
reg [3:0] next_state;
always@(posedge clk)
if(reset)
state<=none;
else
state<=next_state;
always@(*)
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
assign disc = state == discard;
assign flag = state == flag_;
assign err = state == error;
endmodule