[吾题有解] HDLBits : Fsm serialdp

张开发
2026/4/4 4:53:13 15 分钟阅读
[吾题有解] HDLBits : Fsm serialdp
本题带奇偶校验且有数据输出的序列接收器是HDLBits中这个小系列的最后一题相当于在第一题的基础上加入了数据输出和奇偶校验的功能所以本篇博客实际上涵盖了三道题的内容。代码中奇校验复位标志位的设置和done输出参考了博主“Julio吼”的这篇文章HDL Bits代码记录-Fsm serialdp首先分析状态机的三要素输入时钟clk串行数据输入in同步复位信号reset输出传输正确信号done、正确数据输出[7:0] out_byte状态默认状态IDLE若未接收到开始标志位则保持这个状态起始状态S接收到开始标志位in 1’b0后进入这个状态接收到数据位状态bit1~bit8在起始状态之后根据接下来的8个in输入依次进入接收到校验位状态PAR完成接收8个数据状态之后进入结束状态E表示接收正常结束即在校验位之后是高电平错误状态ERR在校验位之后未收到in 1’b0进入此外由于需要检查输入的9-bits是否通过奇校验即要求数据位校验位中1的个数为奇数应当借助系统给出的校验模块parity进行判断。moduleparity(input clk,input reset,input in,output reg odd);always (posedge clk)if(reset)odd0;elseif(in)odd~odd;endmodule校验模块parity的逻辑是这样的模块复位后输出为odd 1’b0当接收到输入in 1’b1时对输出信号进行翻转例如串行输入数据中有3个1’b1该模块输出翻转3次最终输出为1’b1表示数据中有奇数个1通过奇校验若串行输入数据中有2个1’b1输入该模块输出翻转2次最终输出为1’b0表示数据串中有偶数个1不通过奇校验。这里就引申出两个问题如何保证参与奇校验的位恰好是“8个数据位1个校验位”而不受其他位影响如何在恰当的时候输出奇校验结果对于第1点其关键是设置复位标志位在“进入需要进行校验的位”以及“离开需要校验的位”时对校验模块进行复位其他情况下则不复位让校验模块保持启用。这里由于起始状态标志位固定为0不会导致校验模块输出翻转并不对校验产生影响所以也把它算进去了这样看来校验模块总共判断了10bit输入实际上校验模块复位只发生在进入起始状态之前的状态体现在状态图中因为在只在结束状态E时需要校验结果参与done信号的输出判断参见下面关于第2点的解释之后直到下次数据传送开始之前并不关心校验模块输出值。对于第2点其关键是将校验模块的输出再延迟一个时钟周期可将判断结果与结束状态E对齐即在数据串进入结束状态E时判断结果也同时出现。这么做的原因是校验模块的输出本就odd延后输入in一个时钟周期模块内采用时序逻辑此时最终的判断结果是与“接收到校验位状态”对齐的之后如果输入in 1’b1则进入“结束状态”。此时若将输出odd再延迟一个时钟周期则最终输出结果与“结束状态”对齐。当然由于在判断done是否输出1’b1时是状态与校验结果一起判断即使校验结果正确但是当前状态不为结束状态Edone信号仍然输出1’b0。明确了系统的输入、输出以及状态后可以画出如下状态图图中还对应当将复位标志位置1’b1的状态做了标注设计中每一位数据比特均设置了状态这里出于简化作图的目的用一个“DATA”状态代替这个状态共接收了8次in输入在第9次接收in输入后跳出其中有效数据输出逻辑和之前的题目Fsm ps2 / Fsm ps2data中获取输出其实是一个思路由于先输入的是LSB所以每个数据比特状态对应的数据输出寄存器应当先从最低位开始赋值。这里数据比特寄存采用次态的原因是可以将数据寄存位置与输入对齐这样在done信号输出为1的时候有效数据恰好同时输出其余位置则不关心输出情况。最后给出本题Verilog HDLmoduletop_module(input clk,input in,input reset,// Synchronous resetoutput[7:0]out_byte,output done);//// Modify FSM and datapath from Fsm_serialdatalocalparam IDLE1,S2,E3,bit14,bit25,bit36,bit47,bit58,bit69,bit710,bit811,bit912,ERR13,parity14;reg[3:0]state;reg[3:0]next_state;wire odd,parity_reset;// 用来输出校验结果以及给校验模块复位reg check_1;// 将odd输出再延后一个时钟周期always (posedge clk)if(reset)stateIDLE;elsestatenext_state;always (*)begin parity_reset1b0;case(state)IDLE:begin next_statein?IDLE:S;parity_reset1b1;end S:next_statebit1;bit1:next_statebit2;bit2:next_statebit3;bit3:next_statebit4;bit4:next_statebit5;bit5:next_statebit6;bit6:next_statebit7;bit7:next_statebit8;bit8:next_statebit9;bit9:next_statein?E:ERR;E:begin next_statein?IDLE:S;parity_reset1b1;end ERR:next_statein?IDLE:ERR;default:next_stateIDLE;endcase end// New: Datapath to latch input bits.reg[8:1]regbyte;always (posedge clk)if(reset)regbyte8d0;elsecase(next_state)bit1:regbyte[1]in;bit2:regbyte[2]in;bit3:regbyte[3]in;bit4:regbyte[4]in;bit5:regbyte[5]in;bit6:regbyte[6]in;bit7:regbyte[7]in;bit8:regbyte[8]in;default:regbyteregbyte;endcase// New: Add parity checking.parityparity_inst(.clk(clk),.reset(reset|parity_reset),.in(in),.odd(odd));always (posedge clk)if(reset)check_11b0;elsecheck_1odd;assign done(stateE)check_1;assign out_byteregbyte;endmodule其实只用语言描述会让整个状态机的逻辑看起来不是很清晰……大家可以结合自己手绘时序图对题目逻辑与代码进行分析理解起来并不困难。

更多文章