Fsm serialdp - HDLBits (01xz.net)https://hdlbits.01xz.net/wiki/Fsm_serialdp编这段的时候还没形成脑子里有波形图写代码的能力,都是尝试调整时序逼近答案,想着要训练先有图后有码的能力,这种纯靠脑部试出来的不会总靠谱的,应该先画出时序图来。
这里学习了一下画时序图的工具Wavedrom,画出了例中的时序,并按照自己的代码,补充了状态变化、计数器以及输出值,便于理解。
WaveDrom代码:
{signal: [
{name:'clk', wave: 'P...............'},
{name:'reset',wave:'10..............'},
{name:'cnt',wave:'=...============',data:['0','1','2','3','4','5','6','7','8','9','10','0','1']},
{name:'state',wave:'=..=.........===',data:['Idle','STA','STP','STA']},
{name:'in',wave:'1...0.1...0.1.0.=..1.0.1...0....',period:0.5},
{name:'out_reg1',wave:'2.==============',data:['0','0x80','0x40','0xA0','0xD0','0x68','0xB4','0x5A','0x4D','0x96','0x4B','0xA5','0xD2']},
{name:'out_byte',wave:'2...============',data:['0','0x80','0x40','0xA0','0xD0','0x68','0xB4','0x5A','0x4D','0x96','0x4B','0xA5','0xD2']},
{name:'odd',wave:'x...10.1..0.10xx'},
{name:'odd_reg',wave:'x....10.1..0.10x'},
{name:'done',wave:'x0...........10.'},
]}
出图:
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output reg[7:0] out_byte,
output done
); //
// Modify FSM and datapath from Fsm_serialdata
// New: Add parity checking.
parameter IDLE=4'b0001,START=4'b0010,STOP=4'b0100,WAIT=4'b1000;
reg [3:0]state,next_state;
always@(posedge clk)if(reset)state<=IDLE;else state<=next_state;
reg [7:0]out_reg1,out_reg2;
wire odd_out;
reg odd_out_reg;
reg [31:0]cnt;
always@(posedge clk)begin
out_reg1<={in,out_reg1[7:1]};//实际上由于in信号不是同步信号,本时序块事实上完成的是两拍寄存(以一个字节作为输入来看,而不是以out_reg1的高7位来看)
out_reg2<=out_reg1;
out_byte<=out_reg2;
end
always@(*)begin
case(state)
IDLE:if(in)
next_state=IDLE;
else
next_state=START;
START:if(cnt==9) begin//由于下一状态转移是组合逻辑,所以这一变化是在跳变之间的持续阶段持续发生的,这很难解释,多去感悟。
if(in)
next_state=STOP;
else
next_state=WAIT;
end
else
next_state=START;
STOP:if(in)
next_state=IDLE;//与前文不同的是,STOP未必直接输出DONE信号,它还需要与奇偶校验做与输出才是DONE信号
else
next_state=START;
WAIT:if(in)
next_state=IDLE;
else
next_state=WAIT;
default :next_state=IDLE;
endcase
end
always@(posedge clk)begin
if(reset)
cnt<=0;
else if(state==START)
cnt<=cnt+1;
else
cnt<=0;
end
reg odd_reset;
always@(posedge clk)begin
odd_out_reg<=odd_out;
end
assign odd_reset=(state!=START);
parity parity_inst(.clk(clk),.reset(odd_reset),.in(in),.odd(odd_out));
assign done=(odd_out_reg==out_reg1[7])&(state==STOP);
endmodule
本题的奇偶校验给出了亦或的另一种实现方式:将每一位作为输入,若1则取反。这是串行实现奇偶校验的方式,之前那题属于并行的。