2021年5月3日 星期一

HBLbits_Verilog Basic_Fsm serialdp

HBLbits_Verilog Basic_Fsm serialdp

See also: Serial receiver and datapath

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

Note that the serial protocol sends the least significant bit first, and the parity bit after the 8 data bits.

Some timing diagrams

No framing errors. Odd parity passes for first byte, fails for second byte.


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 ID = 0, D1 = 1, D2 = 2, D3 = 3, D4 = 4, D5 = 5, D6 = 6; 
    parameter D7 = 7, D8 = 8, DP = 9, STOP = 10, DONE = 11, FAL = 12, WAIT = 13;
    
    reg[3:0] state , next;
    wire p_s, odd;
    
    always @(*) begin
        case(state)
            ID: next = (~in) ? D1 : ID;
            D1: next = D2;
            D2: next = D3; 
            D3: next = D4; 
            D4: next = D5;
            D5: next = D6; 
            D6: next = D7; 
            D7: next = D8;
            D8: next = DP;
            DP: next = STOP;
            STOP: begin 
                if(in & odd)
                    next = DONE;
                else if (in & ~odd)
                    next = FAL;
                else
                    next = WAIT;
            end
            DONE: next = in ? ID : D1;
            WAIT: next = in ? ID : WAIT;
            FAL:  next = in ? ID : D1;
        endcase
    end
    
    always @ (posedge clk)  begin
        if(reset)begin
            state <= ID;    end
        else
            state <= next;
    end
   // New: Add parity checking.
    assign p_s = ((state == D1) | (state == D2) | (state == D3) | (state == D4) | (state == D5) | (state == D6) | (state == D7) | (state == D8) | (state == DP) );
    
    wire p_in;
    assign p_in = p_s & in;
    wire p_rst;
    
    assign p_rst = (reset | (state == ID) | (state == DONE));
    
    parity ptest(
        .clk(clk),
        .reset(p_rst),
        .in(p_in),
        .odd(odd));
    
    
    //output done and byte
    assign done =  (state == DONE);
     
    reg[9:0]d_s;
    always @(posedge clk)   begin
        if(reset)
            d_s <= 10'b0;
        else    begin
            d_s[9] <= in;
            d_s[8] <= d_s[9];
            d_s[7] <= d_s[8];
            d_s[6] <= d_s[7];
            d_s[5] <= d_s[6];
            d_s[4] <= d_s[5];
            d_s[3] <= d_s[4];
            d_s[2] <= d_s[3];
            d_s[1] <= d_s[2];
            d_s[0] <= d_s[1];
        end
    end
    
    assign out_byte = done ? d_s[7:0] : 8'b0;
endmodule

//另一方法
module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output [7:0] out_byte,
    output done
); //
parameter IDLE = 3'd0,DATA = 3'd1,REC_PAR = 3'd2,DECTION = 3'd3,STOP= 3'd4,WAIT= 3'd5;
    //IDLE空閒狀態,只有當in拉低時,跳轉到接收資料狀態
    //DATA接收資料狀態,重複8次,當counter為7時,跳轉到接收同位狀態
    //REC_PAR接收同位狀態
    //DECTION 檢測in是否拉高,同時奇偶檢驗,只有同時滿足跳轉到stop狀態,這個狀態和空閒狀態是一樣的可以合併
    //WAIT等候狀態,檢測in是否拉高,拉高跳轉到空閒狀態
    
    reg [2:0] state,next_state;
    reg done_reg;
    reg [7:0] data;//保存8bit資料
    reg [2:0] counter;//計數器
    
    //連接同位模組信號
    wire par_enable;//這個信號是給同位模組reset埠的
    wire odd;
    
    always@(posedge clk)begin
        if(reset)begin
            state <= IDLE;
        end
        else begin
            state <= next_state;
        end
    end
    
    always@(*)begin
        case(state)
            IDLE:begin
                if(in)begin
                    next_state <= IDLE;
                end
                else begin
                    next_state <= DATA;
                end
            end
            DATA:begin
                if(counter == 3'd7)begin
                    next_state <= REC_PAR;
                end
                else begin
                    next_state <= DATA;
                end
            end
            REC_PAR:next_state <= DECTION;
            DECTION:begin
                if(in)begin
                    next_state <= STOP;
                end
                else begin
                    next_state <= WAIT;
                end
            end
            STOP:begin
                if(in)begin
                    next_state <= IDLE;
                end
                else begin
                    next_state <= DATA;
                end
            end
            WAIT:begin
                if(in)begin
                    next_state <= IDLE;
                end
                else begin
                    next_state <= WAIT;
                end
            end
            default:next_state <= IDLE;
        endcase
    end
    
    always@(posedge clk)begin
        if(reset)begin
            done_reg <= 0;
            par_enable <= 1;//這個信號是給同位模組reset埠的
            data <= 0;//保存8bit資料
            counter <= 0;
        end
        else begin
            case(state)
                IDLE:begin
                if(in)begin
                    par_enable = 1;
                end
                else begin
                    par_enable = 0;
                end
            end
            DATA:begin
                counter <= counter + 1;
                data[counter] <= in;
            end
            REC_PAR:begin
                counter <= 0;
                par_enable = 1;//這一條是最關鍵的一條,只有當下一個週期par_enable信號拉高才正確
            end
            DECTION:begin
                if(in)begin
                    done_reg <= odd;
                end
                else begin
                    done_reg <= 0;
                end
            end
            STOP:begin
                done_reg <= 0;
                if(in)begin
                    par_enable = 1;
                end
                else begin
                    par_enable = 0;
                end
            end
            WAIT:begin
                done_reg <= 0;
                if(in)begin
                    par_enable = 1;
                end
                else begin
                    par_enable = 1;
                end
            end
            default:begin
                done_reg <= 0;
                par_enable <= 1;//這個信號是給同位模組reset埠的
                data <= 0;//保存8bit資料
                counter <= 0;
        end
            endcase
        end
    end
    
    assign done = done_reg;
    assign out_byte = done ? data : 0;
    
parity p1(
    .clk(clk),
    .reset(par_enable),
    .in(in),
    .odd(odd));   
 
endmodule


沒有留言:

張貼留言

Messaging API作為替代方案

  LINE超好用功能要沒了!LINE Notify明年3月底終止服務,有什麼替代方案? LINE Notify將於2025年3月31日結束服務,官方建議改用Messaging API作為替代方案。 //CHANNEL_ACCESS_TOKEN = 'Messaging ...