FPGA project : fifo_sum

实验目标:

col(列) = 4 ;line(行) = 5。相邻三行,按列求和。输出新的数据流。

实现方法:

通过rs232通信协议,输入数据流。第一行存进fifo1,第二行存进fifo2.当输入第三行第一个数据的时候,从fifo1和ffo2中读数据,并于当前输入数据相加,并输出结果与标志信号。

设计中注意的事情:

1,这个fifo,读写信号同时拉高,我进行功能仿真时,它是写满后,同时拉高,写不进数据。我放一张仿真图:

 所以我设计的时序图,fifo1和fifo2都是先读出数据,然后再写数据。

2,数据与标志信号在设计的时候,要注意时序上的对齐。这种小工程,仿真时,时序没问题没问题,上板子后出错,我觉得应该不是时序上的问题(亚稳态)。应该是代码的问题。

因为我在调用之前的uart_rs232模块,修改了参数,结果上板子出错了。就是这个uart模块的问题。苦恼了很久,一开始以为是fifo_sum的问题。我的写法和野火教程里是不完全一样的。

3,大于2的数字,尽量用参数parameter定义。在这方面,吃了大亏(uart模块又花了一个晚上重新写的)。

模块框图:

时序图:

 

代码: 

module uart_rx(
    input       wire            sys_clk   ,
    input       wire            sys_rst_n ,
    input       wire            rx        ,

    output      reg             po_flag   ,
    output      reg     [7:0]   po_data    
);

    // parameter
    parameter   CLK_UART = 50_000_000     ,
                BPS      = 9600           ;
    localparam  MAX_BPS  = CLK_UART / BPS ;

    // reg signal define
    reg             rx_reg1 ;
    reg             rx_reg2 ;
    reg             rx_reg3 ;
    wire            start   ;
    reg             work_en ;
    reg     [12:0]  cnt_bps ;
    reg     [ 3:0]  cnt_bit ;
    reg             bit_flag;
    reg     [ 7:0]  rx_data ; // 对rx_reg3采样,把串行数据转化为8bit并行数据。
    reg             rx_flag ; // 转化完拉高一个时钟周期。


/********************************************************/
    // reg             rx_reg1 ;
    // reg             rx_reg2 ;
    // reg             rx_reg3 ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            rx_reg1 <= 1'b1 ; // 由于空闲状态,rx是高电平。
            rx_reg2 <= 1'b1 ;
            rx_reg3 <= 1'b1 ;
        end else begin
            rx_reg1 <= rx      ;
            rx_reg2 <= rx_reg1 ;
            rx_reg3 <= rx_reg2 ;
        end
    end
    // reg             start   ; // 检测到下降沿,拉高一个sys_clk.
    assign start = ~rx_reg2 && rx_reg3 ;
    // reg             work_en ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            work_en <= 1'b0 ;
        else if((cnt_bit == 4'd0 && start) || (cnt_bit == 4'd8 && bit_flag)) // 正常来讲,这个两个条件应该是交替出现的。
            work_en <= ~work_en ;
        else 
            work_en <= work_en ;
    end
    // reg     [12:0]  cnt_bps ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_bps <= 13'd0 ;
        else if(work_en && cnt_bps == (MAX_BPS - 1))
            cnt_bps <= 13'd0 ;
        else if(work_en)
            cnt_bps <= cnt_bps + 1'b1 ;
        else 
            cnt_bps <= 13'd0 ;
    end
    // reg             bit_flag;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            bit_flag <= 1'b0 ;
        else if(cnt_bps == MAX_BPS - 1) // 波特率计数器的最大值
            bit_flag <= 1'b1 ;
        else 
            bit_flag <= 1'b0 ;
    end
    // reg     [ 3:0]  cnt_bit ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            cnt_bit <= 4'd0 ;
        else if(bit_flag && cnt_bit == 4'd8)
            cnt_bit <= 4'd0 ;
        else if(bit_flag)
            cnt_bit <= cnt_bit + 1'b1 ;
        else 
            cnt_bit <= cnt_bit ;
    end
    // reg     [ 7:0]  rx_data ; // 对rx_reg3采样,把串行数据转化为8bit并行数据。
    // always @(posedge sys_clk or negedge sys_rst_n) begin
    //     if(~sys_rst_n)
    //         rx_data <= 8'd0 ;
    //     else if(work_en == 1'b1 && (cnt_bit >= 1) && (cnt_bps == MAX_BPS/2))
    //             rx_data <= {rx_reg3,rx_data[7:1]} ; // 由于rx是先发低位,所以rx_reg3放在前面.右移。
    //     else if(work_en == 1'b1 && (cnt_bit >= 1))
    //             rx_data <= rx_data ;
    //     else 
    //         rx_data <= rx_data ;
    // end
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            rx_data <= 8'd0 ;
        else if(work_en == 1'b1 && (cnt_bit >= 1)) begin
            if(cnt_bps == MAX_BPS/2)
                rx_data <= {rx_reg3,rx_data[7:1]} ;
            else 
                rx_data <= rx_data ;
        end else begin
            rx_data <= rx_data ;
        end 
    end
    // reg             rx_flag ; // 转化完拉高一个时钟周期。
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            rx_flag <= 1'b0 ;
        else if(cnt_bit == 4'd8 && bit_flag)
            rx_flag <= 1'b1 ;
        else 
            rx_flag <= 1'b0 ; 
    end

/***********************************************************/
    // output signal
    // po_falg   ,
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            po_flag <= 1'b0 ;
        else if(rx_flag) // 可以理解为打一拍子或者使用时序逻辑采样
            po_flag <= 1'b1 ;
        else
            po_flag <= 1'b0 ;
    end
    // po_data    
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            po_data <= 8'd0 ;
        else if(rx_flag) // 可以理解为打一拍子或者使用时序逻辑采样
            po_data <= rx_data ;
        else
            po_data <= po_data ; // 可以归零,也可以保持。
    end
endmodule
module uart_tx (
    input       wire            sys_clk     ,
    input       wire            sys_rst_n   ,
    input       wire            pi_flag     ,
    input       wire    [7:0]   pi_data     ,

    output      reg             tx          
);
    // parameter
    parameter   SUB_1K   = 1000           , // 缩减第十位,空闲位的时间。
                CLK_UART = 50_000_000     ,
                BPS      = 9600           ;
    localparam  MAX_BPS  = CLK_UART / BPS ;

    // reg signal define
    reg             pi_flag_reg1 ;
    reg     [ 7:0]  pi_data_reg1 ;
    reg             work_en      ;
    reg     [12:0]  cnt_bps      ;
    reg     [ 3:0]  cnt_bit      ;
    reg             bit_flag     ;

/**********************************************/
    // reg             pi_flag_reg1 ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            pi_flag_reg1 <= 1'b0 ;
        else 
            pi_flag_reg1 <= pi_flag ;
    end
    // reg             pi_data_reg1 ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            pi_data_reg1 <= 8'd0 ;
        else 
            pi_data_reg1 <= pi_data ;
    end
    // reg             work_en      ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            work_en <= 1'b0 ;
        else if(((cnt_bit == 4'd0) && pi_flag_reg1) || (cnt_bit == 4'd9) && (bit_flag))
            work_en <= ~work_en ;
        else 
            work_en <= work_en ;
    end
    // reg     [12:0]  cnt_bps      ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            cnt_bps <= 13'd0 ;
        else if(work_en && cnt_bps == MAX_BPS - 1) // 波特率计数器计数到最大值。
            cnt_bps <= 13'd0 ;
        else if(work_en)
            cnt_bps <= cnt_bps + 1'b1 ;
        else 
            cnt_bps <= 13'd0 ;
    end
    // reg             bit_flag     ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            bit_flag <= 1'b0 ;
        else if((work_en && cnt_bps == MAX_BPS - 1) || (work_en && cnt_bps == MAX_BPS - SUB_1K && cnt_bit == 9))
            bit_flag <= 1'b1 ;
        else 
            bit_flag <= 1'b0 ;
    end
    // reg     [ 3:0]  cnt_bit      ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            cnt_bit <= 4'd0 ;
        else if(work_en && bit_flag && cnt_bit == 4'd9) // 传递完第十位,位计数器要归零。
            cnt_bit <= 4'd0 ;
        else if(work_en && bit_flag)
            cnt_bit <= cnt_bit + 1'b1 ;
        else if(work_en)
            cnt_bit <= cnt_bit ;
        else 
            cnt_bit <= 4'd0 ;
    end

/****************************************/
    // output signal
    // tx
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            tx <= 1'b1 ;
        else if(work_en) begin
            case (cnt_bit)
                0  : tx <= 1'b0 ;
                1  : tx <= pi_data_reg1[0] ; // 先发最低位。
                2  : tx <= pi_data_reg1[1] ;
                3  : tx <= pi_data_reg1[2] ;
                4  : tx <= pi_data_reg1[3] ;
                5  : tx <= pi_data_reg1[4] ;
                6  : tx <= pi_data_reg1[5] ;
                7  : tx <= pi_data_reg1[6] ;
                8  : tx <= pi_data_reg1[7] ;
                9  : tx <= 1'b1 ;
            default: tx <= 1'b1 ;
            endcase   
        end else begin
            tx <= 1'b1 ;
        end
    end
endmodule
module fifo_sum(
    input       wire            sys_clk     ,
    input       wire            sys_rst_n   ,
    input       wire    [7:0]   data_in     ,
    input       wire            data_flag   ,

    output      reg     [7:0]   po_data     ,
    output      reg             po_data_falg
);

    // parameter 
    parameter 	XLINE_SUM = 3 ,
                MAX_LINE  = 5 ,
                MAX_COL   = 4 ;

    // reg signal define
    reg		[7:0]	cnt_line 	;
    reg  	[7:0]	cnt_col  	;
    reg   			rdreq_r    	; // fifo1 fifo2 公用一个读使能。
    reg    			wrreq1_r 	;
    reg     [7:0]	dataF1_in_r ;
    reg    			wrreq2_r    ;
    reg     [7:0]	dataF2_in_r ;
    reg     [7:0]	data_in_reg1;
    reg     [7:0]	data_in_reg2;
    reg   			flag_sum_r  ;

    // 例化连线
    wire   			rdreq       ;
    wire    [7:0]	dataF1_in   ;
    wire  			wrreq1 		;
    wire			empty1 		;
    wire  			full1  		;
    wire    [7:0]   dataF1_out  ;
    wire  	[2:0]	usedw1 		;
    wire    [7:0]	dataF2_in   ;
    wire  			wrreq2 		;
    wire			empty2 		;
    wire  			full2  		;
    wire    [7:0]   dataF2_out  ;
    wire  	[2:0]	usedw2 		;
/*************************************************************/
    // reg [7:0] cnt_line
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            cnt_line <= 8'd0 ;
        else if(data_flag && cnt_col == MAX_COL - 1 && cnt_line == MAX_LINE - 1)
            cnt_line <= 8'd0 ;
        else if(data_flag && cnt_col == MAX_COL - 1)
            cnt_line <= cnt_line + 1'b1 ;
        else 
            cnt_line <= cnt_line ;
    end
    // reg [7:0] cnt_col
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            cnt_col <= 8'd0 ;
        else if(data_flag && cnt_col == MAX_COL - 1)
            cnt_col <= 8'd0 ;
        else if(data_flag)
            cnt_col <= cnt_col + 1'b1 ;
        else 
            cnt_col <= cnt_col ;
    end
    // reg   			rdreq_r    	; // fifo1 fifo2 公用一个读使能。
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            rdreq_r <= 1'b0 ;
        else if(cnt_line >= XLINE_SUM - 1)
            rdreq_r <= data_flag ;
        else 
            rdreq_r <= 1'b0 ;
    end
    // reg    			wrreq1_r 	;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            wrreq1_r <= 1'b0 ;
        else if(cnt_line == 0)
            wrreq1_r <= data_flag ;
        else if((cnt_line == (XLINE_SUM - 1) && cnt_col != 0) || (cnt_line > (XLINE_SUM - 1) && cnt_line <= (MAX_LINE - 2)) || (cnt_line == (MAX_LINE - 1) && cnt_col == 0))
            wrreq1_r <= wrreq2_r ;
        else 
            wrreq1_r <= 1'b0 ;
    end
    // reg     [7:0]	dataF1_in_r ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            dataF1_in_r <= 8'd0 ;
        else if(cnt_line == 0)
            dataF1_in_r <= data_in ;
        else if((cnt_line >= (XLINE_SUM - 1) && cnt_line <= (MAX_LINE - 2)) || (cnt_line == (MAX_LINE - 1) && cnt_col == 0))
            dataF1_in_r <= dataF2_out ;
        else 
            dataF1_in_r <= dataF1_in_r ;
    end
    // reg    			wrreq2_r    ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            wrreq2_r <= 1'b0 ;
        else if(cnt_line == 1)
            wrreq2_r <= data_flag ;
        else if((cnt_line >= (XLINE_SUM - 1) && cnt_line <= (MAX_LINE - 2)) || (cnt_line == (MAX_LINE - 1) && cnt_col == 0))
            wrreq2_r <= rdreq_r ;
    end
    // reg     [7:0]	dataF2_in_r ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            dataF2_in_r <= 8'd0 ;
        else if(cnt_line == 1)
            dataF2_in_r <= data_in ;
        else if((cnt_line >= (XLINE_SUM - 1) && cnt_line <= (MAX_LINE - 2)) || (cnt_line == (MAX_LINE - 1) && cnt_col == 0))
            dataF2_in_r <= data_in_reg1 ;
        else 
            dataF2_in_r <= dataF2_in_r ;
    end
    // reg flag_sum_r ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            flag_sum_r <= 1'b0 ;
        else
            flag_sum_r <= rdreq_r ;
    end
/**********************************************************/
    // reg     [7:0]   po_data      ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            po_data <= 8'd0 ;
        else if(flag_sum_r) 
            po_data <= dataF1_out + dataF2_out + data_in_reg2 ;
        else 
            po_data <= po_data ;
    end
    // reg             po_data_falg ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            po_data_falg <= 1'b0 ;
        else if(flag_sum_r) 
            po_data_falg <=1'b1 ;
        else 
            po_data_falg <= 1'b0 ;
    end
    // reg     [7:0]	data_in_reg1;
    // reg     [7:0]	data_in_reg2;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            data_in_reg1 <= 8'd0 ;
            data_in_reg2 <= 8'd0 ;
        end else begin
            data_in_reg1 <= data_in      ;
            data_in_reg2 <= data_in_reg1 ;
        end
    end
/*************************************************************/
    assign	dataF1_in	= dataF1_in_r ;
    assign	wrreq1		= wrreq1_r	  ;
    assign	rdreq		= rdreq_r     ;
    assign	dataF2_in	= dataF2_in_r ;
    assign	wrreq2		= wrreq2_r	  ;

fifo_8x8 fifo_8x8_inst1( // 我测试了一下这个fifo 写满了之后读写信号同时拉高,要写的数据不会被写进去。除非有余量才能同时拉高,并且写入数据。
    .clock				( sys_clk    ) ,
    .data				( dataF1_in  ) ,
    .rdreq				( rdreq      ) ,
    .wrreq				( wrreq1     ) ,
    .empty				( empty1     ) ,
    .full				( full1      ) ,
    .q					( dataF1_out ) ,
    .usedw				( usedw1 	 )
);
fifo_8x8 fifo_8x8_inst2(  
    .clock				( sys_clk    ) ,
    .data				( dataF2_in  ) ,
    .rdreq				( rdreq      ) ,
    .wrreq				( wrreq2     ) ,
    .empty				( empty2     ) ,
    .full				( full2      ) ,
    .q					( dataF2_out ) ,
    .usedw				( usedw2 	 )
);

endmodule
module top(
    input       wire            sys_clk   ,
    input       wire            sys_rst_n ,
    input       wire            rx        ,

    output      wire            tx        
);

    // 例化间连线
    wire            po_flag   ;
    wire    [7:0]   po_data   ; 
    wire            sum_flag  ;
    wire    [7:0]   sum_data  ; 
    
uart_rx uart_rx_inst(
    .sys_clk                    ( sys_clk   ) ,
    .sys_rst_n                  ( sys_rst_n ) ,
    .rx                         ( rx        ) ,

    .po_flag                    ( po_flag   ) ,
    .po_data                    ( po_data   )    
);

fifo_sum fifo_sum_inst(
    .sys_clk                    ( sys_clk   ) ,
    .sys_rst_n                  ( sys_rst_n ) ,
    .data_in                    ( po_data   ) ,
    .data_flag                  ( po_flag   ) ,

    .po_data                    ( sum_data  ) ,
    .po_data_falg               ( sum_flag  )
);

uart_tx uart_tx_inst(
    .sys_clk                    ( sys_clk   ) ,
    .sys_rst_n                  ( sys_rst_n ) ,
    .pi_flag                    ( sum_flag  ) ,
    .pi_data                    ( sum_data  ) ,

    .tx                         ( tx        )          
);


endmodule

`timescale 1ns/1ns
module test_top();
    reg             sys_clk   ;
    reg             sys_rst_n ;
    reg             rx        ;

    wire            tx        ;
// Instantiation
top top_inst(
    .sys_clk            ( sys_clk   ) ,
    .sys_rst_n          ( sys_rst_n ) ,
    .rx                 ( rx        ) ,

    .tx                 ( tx        )          
);
    parameter CYCLE = 20 ;
    defparam  top_inst.uart_rx_inst.CLK_UART = 50_000_0 ;
    defparam  top_inst.uart_tx_inst.CLK_UART = 50_000_0 ;
    defparam  top_inst.uart_tx_inst.SUB_1K   = 10       ;
    
    task rx_bit ;
    input   [7:0]   data ;
    integer i ;
    for (i = 0;i <= 9 ;i = i  + 1 ) begin
        case (i)
            0: rx <= 1'b0 ;
            1: rx <= data[i - 1];
            2: rx <= data[i - 1];
            3: rx <= data[i - 1];
            4: rx <= data[i - 1];
            5: rx <= data[i - 1];
            6: rx <= data[i - 1];
            7: rx <= data[i - 1];
            8: rx <= data[i - 1];
            9: rx <= 1'b1 ;
            default: rx <= 1'b1 ;
        endcase
        #(CYCLE * 52) ;
    end
    endtask

    initial begin
        sys_clk    = 1'b1 ;
        sys_rst_n <= 1'b0 ;
        rx        <= 1'b1 ;
        #( CYCLE * 10 )   ;
        sys_rst_n <= 1'b1 ;
        #( 210 )          ;
        sys_rst_n <= 1'b0 ;
        #( 10 )           ;
        #( CYCLE * 10 )   ;
        sys_rst_n <= 1'b1 ;
        #( CYCLE * 100  ) ;
        rx_bit(8'd1) ;
        rx_bit(8'd1) ;
        rx_bit(8'd2) ;
        rx_bit(8'd2) ;
        rx_bit(8'd3) ;
        rx_bit(8'd3) ;
        rx_bit(8'd4) ;
        rx_bit(8'd4) ;
        rx_bit(8'd5) ;
        rx_bit(8'd5) ;
        rx_bit(8'd6) ;
        rx_bit(8'd6) ;
        rx_bit(8'd7) ;
        rx_bit(8'd7) ;
        rx_bit(8'd8) ;
        rx_bit(8'd8) ;
        rx_bit(8'd9) ;
        rx_bit(8'd9) ;
        rx_bit(8'd1) ;
        rx_bit(8'd1) ;

        
        rx_bit(8'd1) ;
        rx_bit(8'd1) ;
        rx_bit(8'd1) ;
        rx_bit(8'd1) ;

        rx_bit(8'd2) ;
        rx_bit(8'd2) ;
        rx_bit(8'd2) ;
        rx_bit(8'd2) ;

        rx_bit(8'd1) ;
        rx_bit(8'd1) ;
        rx_bit(8'd1) ;
        rx_bit(8'd1) ;

        rx_bit(8'd3) ;
        rx_bit(8'd3) ;
        rx_bit(8'd3) ;
        rx_bit(8'd3) ;

        rx_bit(8'd3) ;
        rx_bit(8'd3) ;
        rx_bit(8'd3) ;
        rx_bit(8'd3) ;

        $stop        ;
    end

    always #( CYCLE / 2 ) sys_clk = ~sys_clk ;

endmodule

 仿真波形:

忘记截图了。

上板验证:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值