HDLBits第十四章练习及答案3

15、PS/2数据包解析器

PS/2 鼠标协议发送三个字节长的消息。但是,在连续的字节流中,消息的开始和结束位置并不明显。唯一的指示是每个三字节消息的第一个字节总是有bit[3]=1(但其他两个字节的 bit[3] 可能是 1 或 0,具体取决于数据)。

我们需要一个有限状态机,当给定输入字节流时,它会搜索消息边界。我们将使用的算法是丢弃字节,直到我们看到bit[3]=1 的字节。然后我们假设这是消息的第 1 个字节,并在接收到所有 3 个字节后(完成)发出消息接收信号。

FSM 应该在每个消息的第三个字节被成功接收后立即在周期内发出完成信号。

一些时序图来解释所需的行为:在无错误条件下,每三个字节形成一个消息:
注:in的第3位为1时,状态机启动,其他两位可能为1或0。此外,这里不允许重叠检测。

代码实现:

module top_module(
    input clk,
    input [7:0] in,
    input reset,    // Synchronous reset
    output done); //

    // State transition logic (combinational)
   parameter [1:0] First_state=2'b00, Second_state=2'b01, Third_state=2'b10, Wait_state=2'b11;
   reg [1:0] state, next_state;

    always @(*) begin
        case(state)     // State transition logic
            First_state:
                next_state <= Second_state;
           Second_state:
                next_state <= Third_state;
		   Third_state:begin
               if(in[3] == 1'b1)
                next_state <= First_state;
               else
                next_state <= Wait_state;   
               end
           Wait_state:begin
               if(in[3] == 1'b1)
                next_state <= First_state;
               else
                next_state <= Wait_state;   
               end             
        endcase
    end
    
    // State flip-flops (sequential)
    always @(posedge clk) begin
        if(reset)
            state <= Wait_state;
        else
            state <= next_state;
    end 
 
    // Output logic
    assign done = (state == Third_state);

endmodule

验证结果:
在这里插入图片描述

16、PS/2数据包解析器和数据路径

现在您有一个状态机可以识别 PS/2 字节流中的三字节消息,添加一个数据路径,该数据路径也将在收到数据包时输出 24 位(3 字节)消息 ( out_bytes[23:16]是第一个字节,out_bytes[15:8]是第二个字节,以此类推)。

当done信号为1时,输出24bit的数据,这24bit的数据高8位,中8位,低8位分别从in[3]为1开始计起,依次输出。done信号为0的时候,不关心数据信号。高8位输出仅当下一状态为Second_state才开始,此处可以简化判断逻辑。
在这里插入图片描述
代码实现:

module top_module(
    input clk,
    input [7:0] in,
    input reset,    // Synchronous reset
    output [23:0] out_bytes,
    output done); //

    // State transition logic (combinational)
   parameter [1:0] First_state=2'b00, Second_state=2'b01, Third_state=2'b10, Wait_state=2'b11;
   reg [1:0] state, next_state;
    
    // FSM from fsm_ps2
    always @(*) begin
        case(state)     // State transition logic
            First_state:begin
               if(in[3] == 1'b1)
                next_state <= Second_state;
               else
                next_state <= First_state;   
               end
           Second_state:
                next_state <= Third_state;
		   Third_state:
                next_state <= Wait_state;   
           Wait_state:begin
               if(in[3] == 1'b1)
                next_state <= Second_state;
               else
                next_state <= First_state;   
               end             
        endcase
    end
    
    // State flip-flops (sequential)
    always @(posedge clk) begin
        if(reset)
            state <= First_state;
        else
            state <= next_state;
    end 
    
    // New: Datapath to store incoming bytes.
    always @(posedge clk)begin
        if(next_state == Second_state)begin
            out_bytes[23:16] <= in;
        end
        else if(next_state == Third_state)begin
            out_bytes[15:8] <= in;
        end
        else if(next_state == Wait_state)begin
            out_bytes[7:0] <= in;
        end
        else begin
            out_bytes <= 24'd0;
        end
    end
    
    // Output logic
    assign done = (state == Wait_state); 

endmodule

验证结果:
在这里插入图片描述

17、串行接收器

在许多(较旧的)串行通信协议中,每个数据字节都与一个起始位和一个停止位一起发送,以帮助接收器从位流中分隔字节。一种常见的方案是使用 1 个起始位 (0)、8 个数据位和 1 个停止位 (1)。当没有传输任何内容(空闲)时,该线路也处于逻辑 1。

设计一个有限状态机,当给定比特流时,它将识别何时正确接收字节。它需要识别起始位,等待所有 8 个数据位,然后验证停止位是否正确。如果停止位没有按预期出现,FSM 必须等待直到找到停止位,然后才能尝试接收下一个字节。
在这里插入图片描述
提示

in信号包含了一个起始位(0),8个数据位和一个停止位(1),开始in为1,也就是idle状态,当in为0时,进入Start状态,然后经过8个周期,如果in为1,则进入Stop状态,接着如果in为0,进入第二轮Start状态,否则进入idle状态。

代码实现:

module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output done
); 

    // State transition logic (combinational)
   parameter [3:0] Start=4'd0,One=4'd1,Two=4'd2,Three=4'd3,Four=4'd4,Five=4'd5;
   parameter [3:0] Six=4'd6,Seven=4'd7,Eight=4'd8,Stop=4'd9,idle=4'd10,Wait=4'd11;
   reg [3:0] state, next_state;
    
    always @(*) begin
        case(state)     // State transition logic
            Start:
                next_state <= One;
            One:
                next_state <= Two;  
		    Two:
                next_state <= Three;  
            Three:
                next_state <= Four; 
            Four:
                next_state <= Five; 
            Five:
                next_state <= Six; 
            Six:
                next_state <= Seven; 
            Seven:
                next_state <= Eight; 
            Eight:begin
                if(in ==1'b1)
                    next_state <= Stop; 
                else
                    next_state <= Wait;
            end
            Stop:begin
                if(in ==1'b1)
                    next_state <= idle; 
                else
                    next_state <= Start;
            end
            idle:begin
                if(in ==1'b1)
                    next_state <= idle; 
                else
                    next_state <= Start;
            end
           Wait:begin
                if(in ==1'b1)
                    next_state <= idle; 
                else
                    next_state <= Wait;
            end            
        endcase
    end    

    // State flip-flops (sequential)
    always @(posedge clk) begin
        if(reset)
            state <= idle;
        else
            state <= next_state;
    end
    
    // Output logic
    assign done = (state == Stop);    
    
endmodule

验证结果:
在这里插入图片描述

18、串行接收器和数据通路

既然您有一个有限状态机,可以识别在串行比特流中正确接收字节的时间,请添加一个数据路径,以输出正确接收的数据字节。out_byte需要在done为1时有效,否则无关紧要。

请注意,串行协议首先发送最低有效位。
在这里插入图片描述
提示:本题是上一道题的扩展,不仅需要输出done信号,还需要输出数据。

代码实现:

(1)方法1

module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output [7:0] out_byte,
    output done
); //

    // State transition logic (combinational)
   parameter [3:0] Start=4'd0,One=4'd1,Two=4'd2,Three=4'd3,Four=4'd4,Five=4'd5;
   parameter [3:0] Six=4'd6,Seven=4'd7,Eight=4'd8,Stop=4'd9,idle=4'd10,Wait=4'd11;
   reg [3:0] state, next_state;
   reg [7:0] out_reg;
    
    // Use FSM from Fsm_serial    
    always @(*) begin
        case(state)     // State transition logic
            Start:begin
                next_state <= One;
                out_reg[0] <= in;
            end
            One:begin
                next_state <= Two;  
                out_reg[1] <= in;
            end
		    Two:begin
                next_state <= Three;  
                out_reg[2] <= in;
            end
            Three:begin
                next_state <= Four; 
                out_reg[3] <= in;
            end
            Four:begin
                next_state <= Five; 
                out_reg[4] <= in;
            end
            Five:begin
                next_state <= Six; 
                out_reg[5] <= in;
            end
            Six:begin
                next_state <= Seven; 
                out_reg[6] <= in;
            end
            Seven:begin
                next_state <= Eight; 
                out_reg[7] <= in;
            end
            Eight:begin
                if(in ==1'b1)
                    next_state <= Stop; 
                else
                    next_state <= Wait;
            end
            Stop:begin
                if(in ==1'b1)
                    next_state <= idle; 
                else
                    next_state <= Start;
            end
            idle:begin
                if(in ==1'b1)
                    next_state <= idle; 
                else
                    next_state <= Start;
            end
           Wait:begin
                if(in ==1'b1)
                    next_state <= idle; 
                else
                    next_state <= Wait;
            end            
        endcase
    end    

    // State flip-flops (sequential)
    always @(posedge clk) begin
        if(reset)
            state <= idle;
        else
            state <= next_state;
    end
    
    // Output logic
    assign done = (state == Stop);  
    assign out_byte = (state == Stop) ? out_reg : 8'd0;

endmodule

(2)方法2

module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output [7:0] out_byte,
    output done
); //

    parameter [2:0] IDLE = 3'd0, START = 3'd1, DATA = 3'd2, STOP = 3'd3, WAIT = 3'd4;
    reg [2:0]	current_state;
    reg [2:0]	next_state;
    reg [3:0]	counter;
    reg [7:0]	par_in;
    
    // Use FSM from Fsm_serial
    always @(*)begin
        case(current_state)
            IDLE:begin
                if(~in)
                    next_state = START;
                else 
                    next_state = IDLE;
            end
            START:
                next_state = DATA;
            DATA:begin
                if(counter == 4'd8)
                    next_state = in? STOP:WAIT;
                else 
                    next_state = DATA;
            end
            STOP:
                next_state = in? IDLE:START;
            WAIT:
                next_state = in? IDLE:WAIT;
            default:
                next_state = IDLE;
        endcase
    end
    
    always @(posedge clk)begin
        if(reset)
            current_state <= IDLE;
        else 
            current_state <= next_state;
    end

    always @(posedge clk)begin
        if(reset)begin
            done <= 1'd0;
            out_byte <= 8'd0;
            counter <= 4'd0;
        end
        else begin
            case(next_state)
                IDLE:begin
                    done <= 1'd0;
           		    out_byte <= 8'd0;
            		counter <= 4'd0;
                end
                START:begin
                    done <= 1'd0;
           		    out_byte <= 8'd0;
            		counter <= 4'd0;
                end
                DATA:begin
                    done <= 1'd0;
           		    out_byte <= 8'd0;
                    par_in[counter] <= in;
            		counter <= counter + 1'd1;
                end
                STOP:begin
                    done <= 1'd1;
           		    out_byte <= par_in;
            		counter <= 4'd0;
                end
                WAIT:begin
                    done <= 1'd0;
           		    out_byte <= 8'd0;
            		counter <= 4'd0;
                end
            endcase
        end
    end

endmodule

验证结果:
在这里插入图片描述

19、带奇偶校验的串行接收器

我们想为串行接收器添加奇偶校验。奇偶校验在每个数据字节后增加一位。我们将使用奇校验,其中接收到的 9 位中1的数量必须是奇数。例如,101001011满足奇校验(有 5 个1 s),但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

请注意,串行协议首先发送最低有效位,然后在 8 个数据位之后发送奇偶校验位。
在这里插入图片描述
代码实现:

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 [2:0] IDLE = 3'd0, START = 3'd1, DATA = 3'd2, STOP = 3'd3, WAIT = 3'd4;
    reg [2:0]	current_state;
    reg [2:0]	next_state;
    reg [3:0]	counter;
    reg [8:0]	data_in;
    reg odd_temp;
    wire Isdone;
    
    // Use FSM from Fsm_serial
    always @(*)begin
        case(current_state)
            IDLE:begin
                if(~in)
                    next_state = START;
                else 
                    next_state = IDLE;
            end
            START:
                next_state = DATA;
            DATA:begin
                if(counter == 4'd9)
                    next_state = in? STOP:WAIT;
                else 
                    next_state = DATA;
            end
            STOP:
                next_state = in? IDLE:START;
            WAIT:
                next_state = in? IDLE:WAIT;
            default:
                next_state = IDLE;
        endcase
    end
    
    always @(posedge clk)begin
        if(reset)
            current_state <= IDLE;
        else 
            current_state <= next_state;
    end

    always @(posedge clk)begin
        if(reset)begin
            done <= 1'd0;
            out_byte <= 8'd0;
            counter <= 4'd0;
        end
        else begin
            case(next_state)
                IDLE:begin
                    done <= 1'd0;
           		    out_byte <= 8'd0;
            		counter <= 4'd0;
                end
                START:begin
                    done <= 1'd0;
           		    out_byte <= 8'd0;
            		counter <= 4'd0;
                end
                DATA:begin
                    done <= 1'd0;
           		    out_byte <= 8'd0;
                    data_in[counter] <= in;
            		counter <= counter + 1'd1;
                end
                STOP:begin
                    done <= odd_temp ? 1'd1 : 1'd0;
                    out_byte <= odd_temp ? data_in[7:0] : 8'd0;
                    counter <= 4'd0;
                end
                WAIT:begin
                    done <= 1'd0;
           		    out_byte <= 8'd0;
            		counter <= 4'd0;
                end
            endcase
        end
    end
    
    // New: Add parity checking.
    assign Isdone = (next_state == START);
    parity u0(clk,Isdone,in,odd_temp);
    
endmodule

验证结果:
在这里插入图片描述

20、序列识别

Fsm hdlc

同步帧检测涉及对数据的连续位流进行解码,以寻找指示帧(数据包)开始和结束的位模式。 6个连续的1(即01111110)是表示帧边界的“标志”。 为了避免数据流意外包含“标志”,发送方必须在接收方必须检测并丢弃的每5个连续的1秒后插入一个零。 如果连续7个或更多1,我们还需要发出错误信号。

可以通过状态机来识别下面三种序列:

0111110:表示5个1后面的0bit需被忽略;

01111110:表示一帧的开始或结束;

01111111…:错误

当状态机被复位时,它应当表现为之前的输入为0;

下面是三种波形示例:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
提示:
在这里插入图片描述
代码实现:

module top_module(
    input clk,
    input reset,    // Synchronous reset
    input in,
    output disc,
    output flag,
    output err);
    
    parameter [3:0] NONE=4'd0, ONE=4'd1, TWO=4'd2, THREE=4'd3, FOUR=4'd4;
    parameter [3:0] FIVE=4'd5, SIX=4'd6, ERROR=4'd7, DISCARD=4'd8, FLAG=4'd9;
    reg [3:0] state, next_state;

    always @(*) begin
        case(state)     // State transition logic
            NONE:begin
            if( in == 1'b1 )
                next_state <= ONE;
            else
                next_state <= NONE;   
            end    
            ONE:begin
            if( in == 1'b1 )
                next_state <= TWO;
            else
                next_state <= NONE;   
            end
            TWO:begin
            if( in == 1'b1 )
                next_state <= THREE;
            else
                next_state <= NONE;   
            end  
            THREE:begin
            if( in == 1'b1 )
                next_state <= FOUR;
            else
                next_state <= NONE;   
            end   
            FOUR:begin
            if( in == 1'b1 )
                next_state <= FIVE;
            else
                next_state <= NONE;   
            end 
            FIVE:begin
            if( in == 1'b1 )
                next_state <= SIX;
            else
                next_state <= DISCARD;   
            end   
            SIX:begin
            if( in == 1'b1 )
                next_state <= ERROR;
            else
                next_state <= FLAG;   
            end   
            ERROR:begin
            if( in == 1'b1 )
                next_state <= ERROR;
            else
                next_state <= NONE;   
            end 
            DISCARD:begin
            if( in == 1'b1 )
                next_state <= ONE;
            else
                next_state <= NONE;   
            end    
            FLAG:begin
            if( in == 1'b1 )
                next_state <= ONE;
            else
                next_state <= NONE;   
            end              
        endcase
    end

    always @(posedge clk) begin
        if(reset)
            state <= NONE;
        else
            state <= next_state;// State flip-flops with asynchronous reset
    end
    
    // Output logic
    assign disc = (state == DISCARD);  
    assign flag = (state == FLAG);
    assign err = (state == ERROR);  
    
endmodule

验证结果:
在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值