HDLbits刷题 Fsm serial Fsm serialdata

原题
In many (older) serial communications protocols, each data byte is sent along with a start bit and a stop bit, to help the receiver delimit bytes from the stream of bits. One common scheme is to use one start bit (0), 8 data bits, and 1 stop bit (1). The line is also at logic 1 when nothing is being transmitted (idle).

Design a finite state machine that will identify when bytes have been correctly received when given a stream of bits. It needs to identify the start bit, wait for all 8 data bits, then verify that the stop bit was correct. If the stop bit does not appear when expected, the FSM must wait until it finds a stop bit before attempting to receive the next byte.

在这里插入图片描述
注意: 这一题的输入高电平是代表结束位。记录这一题是因为状态机在串口通信中的应用实例。
下面是解答

module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output done
); 
    parameter idle = 0,start = 1,getData = 2,stop = 3,error = 4;
    reg [3:0] state,next_state;
    reg [7:0] count;
    reg doneFlag;
    
    always @(*)begin
        next_state = idle;
        case(state)
            idle:next_state = in?idle:start;
            start:next_state = getData;
            getData:next_state = (count == 8)?(in?stop:error):getData;
            error:next_state = in?idle:error;
            stop:next_state = in?idle:start;
            default:next_state = idle;  
        endcase
    end
    
    always @(posedge clk)begin
        if(reset)
            state <= idle;
        else
            state <= next_state;
    end
    
    always @(posedge clk)begin
        if(reset)begin
            count <= 0;
            doneFlag <= 0;
        end
        else begin
                case(next_state)
                getData:begin
                    count <= count + 8'b1;
                    doneFlag <= 0;
                end
                stop:begin
                    count <= 0;
                    doneFlag <= 1;
                end
                default:begin
                    count <= 0;
                    doneFlag <= 0;       
                end                                       
                endcase      
        end
    end
assign done = doneFlag;
endmodule

串口的通信一起有三个题目,下面是第二道题,相比第一道是增加了一个数据的输出,所以代码里面要将数据存起来。

题目二
Fsm serialdata
Now that you have a finite state machine that can identify when bytes are correctly received in a serial bitstream, add a datapath that will output the correctly-received data byte. out_byte needs to be valid when done is 1, and is don’t-care otherwise.

Note that the serial protocol sends the least significant bit first.
在这里插入图片描述
下面是解答:

module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output [7:0] out_byte,
    output done
); //
    parameter idle=0,start=1,getData=2,stop=3,error=4;
    reg [3:0] state,next_state;
    
    reg doneFlag;
    reg [7:0] count;
    reg [7:0] data;
    
    // only state flip-flop
    always @(*)begin
        next_state = idle;
        case(state)
            idle:next_state = in?idle:start;
            start:next_state = getData;
            getData:next_state = (count==8)?(in?stop:error):getData;
            error:next_state = in?idle:error;
            stop:next_state = in?idle:start;
            default:next_state = idle;
        endcase    
    end
    
    always @(posedge clk)begin
        if(reset)
            state <= idle;
    	else
        state <= next_state;
    end
    
    always@(posedge clk)begin
        case(next_state)
            getData:begin
                count <= count+ 8'b1;
                data[count] <= in;
                doneFlag <= 0;
            end
            stop:begin
                count <= 8'd0;
                doneFlag <= 1;
         		out_byte <= data;
            end
            default:begin
                count <= 8'd0;
                doneFlag <= 0;
                data <= 8'd0;
            end
        endcase
    end
   
	assign done = doneFlag;
endmodule

第三题: Fsm serialdp
We want to add parity checking to the serial receiver. Parity checking adds one extra bit after each data byte. We will use odd parity, where the number of 1s in the 9 bits received must be odd. For example, 101001011 satisfies odd parity (there are 5 1s), but 001001011 does not.

Change your FSM and datapath to perform odd parity checking. Assert the done signal only if a byte is correctly received and its parity check passes. Like the serial receiver FSM, this FSM needs to identify the start bit, wait for all 9 (data and parity) bits, then verify that the stop bit was correct. If the stop bit does not appear when expected, the FSM must wait until it finds a stop bit before attempting to receive the next byte.

You are provided with the following module that can be used to calculate the parity of the input stream (It’s a TFF with reset). The intended use is that it should be given the input bit stream, and reset at appropriate times so it counts the number of 1 bits in each byte.

module parity (
    input clk,
    input reset,
    input in,
    output reg odd);

    always @(posedge clk)
        if (reset) odd <= 0;
        else if (in) odd <= ~odd;

endmodule

这里多了一个零一校验的环节,所以要在收取数据和结束的中间再增加一个检验的状态。
相比第二题,这里的解答对全局变量的更新将更加分散化
这样写有两个好处
1:逻辑上更加清晰,因为一次只有一个变量的控制所以不会轻易使人困惑。
2:便于进行后续模块的添加,即模块之间的耦合性是非常低的。

下面是解答代码:(里面对过程进行了标注

module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output [7:0] out_byte,
    output done
); //
    parameter idle=0,start=1,getData=2,stop=3,error=4,check=5;
    reg [3:0] state,next_state;
    
    reg odd_reg;
    reg odd_reset;
    wire odd;
    
  
    reg [7:0] count;
    reg [7:0] data;
    
    // instance parity check 
    parity u1(
        .clk(clk),
        .reset(reset | odd_reset),
        .in(in),
        .odd(odd)
    );
    
    // only state flip-flop
    always @(*)begin
        next_state = idle;
        case(state)
            idle:next_state = in?idle:start;
            start:next_state = getData;
            getData:next_state = (count==8)?check:getData;
            check:next_state = in?stop:error;
            error:next_state = in?idle:error;
            stop:next_state = in?idle:start;
            default:next_state = idle;
        endcase    
    end
    
    //control state flip
    always @(posedge clk)begin
        if(reset)
            state <= idle;
    	else
        state <= next_state;
    end
    
    // control count
    always @(posedge clk)begin
        if(reset)
            count <= 0;
        else begin
            case(next_state)
                getData:count <= count + 1;
                default: count <= 0;
            endcase
        end
    end

    //control data receive
    always@(posedge clk)begin
        if(reset)
            data <= 8'bx;
        else if( next_state == getData) begin
            data[count] <= in;
        end   
    end
    
    //control odd reg
    always @(posedge clk)begin
        if(reset)
            odd_reg <= 0;
        else
            odd_reg <= odd;
    end
    
    //control odd reset
    always@(posedge clk)begin
        if(reset)
            odd_reset <= 0;
        else begin
            case(next_state)
                idle:odd_reset <= 1;
                stop:odd_reset <= 1;
                default:odd_reset <= 0;
            endcase
        end    
    end
    
    // calculate output which depends on the state of system and global variant
    assign done = (state == stop) & odd_reg;
    assign out_byte = done?data:8'bx;
       
endmodule

到这里串口的接收三道题目就结束了,能够看到三道题目是循序渐进的,第一次只是输出一个接收结束的标志,第二次增加了数据的输出,第三次增加了奇偶校验。所以这也对逻辑的设计提供一个要求,要具有拓展性,不能因为增加一个模块而把代码带来过大的改动冲击。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值