15. fifo求和实验

本章节读者要学习掌握FIFO求和的原理和方法,为后面学习Sobel算法做铺垫。根据所学知识,使用双FIFO实现三行模拟数据的求和实验,并上板验证。

15.1. 理论学习

在这一小节我们来介绍FIFO求和的具体方法,要实现SUM求和,FIFO IP核必不可少,需要用它用来做求和数据缓存。FIFO是存储器的一种,满足先进先出原则,前面章节对它已经有了详细介绍,如有遗忘,自行翻阅前面章节,在此不再赘述。

要完成3行数据的SUM求和,需要调用2个FIFO IP核,当数据开始输入时,将数据的第0行数据存储到fifo1中,将第1行数据存储到fifo2中,当数据的第2行的第0个数据输入的同时,读取写入fifo1中的的第0个数据和写入fifo2中的第0个数据,将三个数据求和,求和结果实时输出,在完成求和的同时 ,将读取的fifo2中的第0个数据写入fifo1中,fifo1读出的数据弃之不用,将输入的第2行的数据写入fifo2中,当第2行的最后一个数据输入,完成前三行的最后一个求和运算后,第0行的数据已读取完成,第1行的数据重新写入fifo1,第2行的数据写入fifo2,当第3行数据开始传入时,开始进行第1 行、第2行和第3行的数据求和运算,如此循环,直到最后一个数据输入,完成求和运算。流程示意图具体见图 44‑1。

FIFO002

图 44‑1 SUM求和示意图

15.2. 实战演练

在上一小节中,我们学习了FIFO求和的实现方法,下面我们通过实验来具体实现3行数据的FIFO求和。

15.2.1. 实验目标

实验目标:使用Matlab生成一个*.txt文件,文件中包含模拟求和的数据,PC机通过串口RS232将数据传给FPGA,使用双fifo实现三行数据的FIFO求和,通过串口RS232将求和后的数据回传给PC机,并通过串口助手打印出求和数据。

实验要求:*.txt文件包含2500个数据,为0-49的50次循环,模拟50x50数组。

15.2.2. 程序设计

学习了SUM求和的具体方法,了解了实验的具体步骤,根据实验目标和具体要求我们来进行模块设计。

15.2.2.1. 整体说明

在本小节我们先介绍一下实验工程的整体架构,让读者对实验工程有一个整体的认识,FIFO求和实验工程的整体框图具体见图 44‑2。

FIFO003

图 44‑2 整体框图

由整体框图可知,本实验过程本实验过程包括4个模块,各模块简介,具体见表格 44‑1。

表格 44‑1 FIFO求和工程模块简介

模块名称

功能描述

fifo_sum

顶层模块

uart_rx

串口数据接收模块

uart_tx

串口数据发送模块

fifo_sum

数据求和模块

系统上电后,使用PC机通过串口助手发送待求和数据给FPGA,FPGA通过串口接收模块接收待求和数据,数据拼接完成后传入数据求和模块,经过求和运算后的数据结果通过串口数据发送模块回传给PC机,使用串口助手查看求和结果。

15.2.2.2. 数据求和模块

串口收发模块的相关内容在前面章节详细介绍过,在此不再赘述。后面我们只说一下顶层模块和数据求和模块。先来看一下数据求和模块的相关内容。

模块设计

数据求和模块的作用是,接收串口数据接收模块传来的待求和数据,计算出求和结果并输出给串口数据发送模块。数据求和模块框图,具体见图 44‑3。

FIFO004

图 44‑3 数据求和模块框图

由模块框图可知,数据求和模块包含4路输入、2路输出,共6路信号。输入输出信号简介,具体见表格 44‑2。

表格 44‑2 数据求和模块输入输出信号功能描述

信号

位宽

类型

功能描述

sys_clk

1Bit

Input

工作时钟,频率50MHz

sys_rst_n

1Bit

Input

复位信号,低电平有效

pi_flag

1Bit

Input

输入数据标志信号

pi_data

8Bit

Input

输入待求和数据

po_flag

1Bit

Output

输出数据标志信号

po_sum

8Bit

Output

输出求和后数据

输入时钟为系统时钟sys_clk,频率50MHz,输入复位信号sys_rst_n,低电平有效,输入数据pi_data和数据标志信号pi_flag由串口数据接收模块传入,传入数据按照时序写入2个FIFO中,完成求和运算后,将求和后数据po_sum和标志信号po_flag传出。

数据求和模块内部还例化了两个FIFO,目的是缓存待求和数据。

波形图绘制

模块设计之后,我们对数据求和模块的具体功能做了说明,对输入输出信号做了简单介绍,那么如何利用模块输入信号实现模块功能,输出我们想要得到的数据信号呢?在波形图绘制部分,我们会通过绘制波形图,对各信号做详细讲解,带领读者学习掌握模块功能的实现方法。

数据求和模块参考波形图,具体见图 44‑4。

FIFO005

图 44‑4 数据求和模块参考波形图

上图是最终绘制生成的数据求和模块的参考波型图,接下来我们会分步讲解波形的绘制思路。

第一部分:行计数器cnt_row、列计数器cnt_col信号波形的设计与实现

本实验是要实现3行数据的求和,那么需要对参与求和运算的每行数据个数进行计数,同样也需要对参与求和运算的各行进行计数,所以我们需要声明两个计数器行计数器cnt_row、列计数器cnt_col。

变量cnt_row是行计数器,计数每行数据的个数,我们可以以输入数据标志信号pi_flag为约束条件进行计数。cnt_row计数器初值为0,pi_flag信号每拉高一次,计数器加1,当cnt_row计数器计到最大值(一行数据个数减1,本实验一行数据50个,计数器计数最大值为50-1=49),行计数器 归0,开始下一行计数;

cnt_col是列计数器,对输入数据进行列计数(计数行个数),计数器初值为0,行计数器计数到最大值且pi_flag信号有效时,列计数器加1,列计数器计到最大值(行个数减1,本实验数据共有50行,计数器计数最大值为50-1=49),列计数器归0。两计数器计数器信号波形如下。

FIFO006

图 44‑5 cnt_row、cnt_col信号波形图

第二部分:FIFO缓存相关信号波形的设计与实现

因为串口每次只输入单字节数据,要想实现多行数据求和,必须要使用FIFO对输入数据进行缓存,本实验要实现3行数据的求和,需要使用两个FIFO进行数据缓存。那么FIFO的相关信号的波形就需要设计一下了。

我们在模块中实例化两个FIFO,分别为fifo_data_inst1和fifo_data_inst2,接下来对两个FIFO的相关信号进行详细说明。

两个FIFO的输入输出信号端口相同,输入端口有4路,输出端口1路,共5路信号。

fifo_data_inst1中,输入时钟信号与串口接收模块的工作时钟相同为系统时钟信号sys_clk;数据写使能信号为wr_en1、写入数据为data_in1,当串口接收模块传入第0行数据时,即cnt_col=0且pi_flag=1时,wr_en1信号赋值为高电平,相同条件下, pi_data赋值 给data_in1,将第0行的数据暂存到fifo_data_inst1中;当第1行数据输入,wr_en1信号赋值为低电平,data_in1无数据输入,因为第1行的数据要暂存到fifo_data_inst2中;自第2行数据开始传入到倒数第二行数据传输完成,wr_en1信号由dout_flag信号赋值, 当rd_en和wr_en2信号均为高电平时,dout_flag信号赋值高电平,其他时刻均为低电平。当dout_flag有效时,将fifo_data_inst2的读出数据data_out2赋值给data_in1。

fifo_data_inst2中,输入时钟信号与串口接收模块的工作时钟相同为系统时钟信号sys_clk;wr_en2为数据写使能信号,data_in2为写入数据,自第1行数据开始输入到倒数第二行数据输入完成,wr_en2写使能信号由 pi_flag信号赋值,时序上滞后pi_flag信号1个时钟周期,wr_en2赋值为高电平,fifo_data_inst2写使能有效,其他时刻写使能无效,写使能信号wr_en2有效时,将传入的数据pi_data赋值给data_in2。

rd_en是两FIFO共用的读使能信号,自第2行数据开始传入到最后一行数据传输完成, pi_flag信号赋值给读使能rd_en,时序上rd_en滞后pi_flag信号1个时钟周期,其他时刻rd_en信号始终保持低电平;data_out1数据输出受控于rd_en读使能信号,读使能有效,data_out 1数据输出,否者保持之前状态,时序上data_out1滞后于rd_en读使能信号1个时钟周期。data_out2数据输出同样受控于rd_en读使能信号,读使能有效,data_out2数据输出,否者保持之前状态,时序上data_out2滞后于rd_en读使能信号1个时钟周期。

FIFO007

图 44‑6 FIFO缓存相关信号波形图

第三部分:数据输出相关信号波形的设计与实现

两FIFO共用的读使能信号rd_en有效时,从FIFO中分别读取两个待相加数据,两数据与此时输入的数据pi_data做求和运算,这里我们需要声明一个新的标志信号做这三个数据求和运算的标志信号。

以读使能信号rd_en滞后一个时钟信号生成求和运算标志信号po_flag_reg。当po_flag_reg信号为高电平时,将读出两FIFO的数据data_out1、data_out2与此时输入的pi_data做求和运算得出求和结果po_sum并输出;同时要输出与po_sum信号匹配的数据标志信号po _flag,利用po_flag_reg信号滞后一个时钟周期生成po_flag信号并输出,生成的po_flag与与op_sum信号同步。上述各信号波形如下图。

FIFO008

图 44‑7 数据输出相关信号波形图

将上述各信号波形整合后,得到本模块整体波形图,但本模块设计思路仅供参考,并非唯一实现方式,读者可根据所学知识,自行设计模块。

15.2.2.3. 代码编写

参照上述设计模块波形图,编写模块参考代码。fifo_sum_ctrl模块参考代码具体见代码清单 44‑1。

代码清单 44‑1 FIFO求和模块参考代码(fifo_sum_ctrl.v)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
module fifo_sum_ctrl
(
input wire sys_clk , //频率为50MHz
input wire sys_rst_n , //复位信号,低有效
input wire [7:0] pi_data , //rx传入的数据信号
input wire pi_flag , //rx传入的标志信号

output reg [7:0] po_sum , //求和运算后的信号
output reg po_flag //输出数据标志信号
);
////
//\* Parameter and Internal Signal \//
////
//parameter define
parameter CNT_ROW_MAX = 7'd49 , //行计数最大值
CNT_COL_MAX = 7'd49 ; //列计数最大值
//wire define
wire [7:0] data_out1 ; //fifo1数据输出
wire [7:0] data_out2 ; //fifo2数据输出
//reg define
reg [6:0] cnt_row ; //行计数
reg [6:0] cnt_col ; //场计数
reg wr_en1 ; //fifo1写使能
reg wr_en2 ; //fifo2写使能
reg [7:0] data_in1 ; //fifo1写数据输入
reg [7:0] data_in2 ; //fifo2写数据输入
reg rd_en ; //fifo1、fifo2共用的读使能
reg dout_flag ; //控制fifo1,2-84行的写使能
reg po_flag_reg ; //输出标志位缓存,rd_en延后一拍得到,控制计算po_sum
////
//\* Main Code \//
////
//cnt_row:行计数器,计数一行数据个数
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 1'b0)
cnt_row <= 7'd0;
else if((cnt_row == CNT_ROW_MAX) && (pi_flag == 1'b1))
cnt_row <= 7'd0;
else if(pi_flag == 1'b1)
cnt_row <= cnt_row + 1'b1;
end
//cnt_col:列计数器,计数数据行数
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 1'b0)
cnt_col <= 7'd0;
else if((cnt_col == CNT_COL_MAX) && (pi_flag == 1'b1) && (cnt_row == CNT_ROW_MAX))
cnt_col <= 7'd0;
else if((cnt_row == CNT_ROW_MAX) && (pi_flag == 1'b1))
cnt_col <= cnt_col + 1'b1;
end
//wr_en1:fifo1写使能信号,高电平有效
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 1'b0)
wr_en1 <= 1'b0;
else if((cnt_col == 7'd0) && (pi_flag == 1'b1))
wr_en1 <= 1'b1; //第0行写入fifo1
else
wr_en1 <= dout_flag; //2-84行写入fifo1
end
//wr_en2:fifo2写使能信号,高电平有效
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 1'b0)
wr_en2 <= 1'b0;
else if((cnt_col >= 7'd1) && (cnt_col <= CNT_COL_MAX - 1'b1) && (pi_flag == 1'b1))
wr_en2 <= 1'b1; //2-CNT_COL_MAX行写入fifo2
else
wr_en2 <= 1'b0;
end
//data_in1:fifo1数据输入
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 1'b0)
data_in1 <= 8'b0;
else if((pi_flag == 1'b1) && (cnt_col == 7'd0))
data_in1 <= pi_data; //第0行数据暂存fifo1中
else if(dout_flag == 1'b1)
data_in1 <= data_out2;//第2-CNT_COL_MAX-1行时,fifo2读出数据存入fifo1
else
data_in1 <= data_in1;
end
//data_in2:fifo2数据输入
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 1'b0)
 data_in2 <= 8'b0;
 else if((pi_flag == 1'b1)&&(cnt_col >= 7'd1)&&(cnt_col <= (CNT_COL_MAX - 1'b1)))
 data_in2 <= pi_data;
 else
 data_in2 <= data_in2;
 end

 //rd_en:fifo1和fifo2的共用读使能信号
 always@(posedge sys_clk or negedge sys_rst_n)
 begin
 if(sys_rst_n == 1'b0)
 rd_en <= 1'b0;
 else if((pi_flag == 1'b1)&&(cnt_col >= 7'd2)&&(cnt_col <= CNT_COL_MAX))
 rd_en <= 1'b1;
 else
 rd_en <= 1'b0;
 end

 //dout_flag:控制2-CNT_COL_MAX-1行wr_en1信号
 always@(posedge sys_clk or negedge sys_rst_n)
 begin
 if(sys_rst_n == 1'b0)
 dout_flag <= 0;
 else if((wr_en2 == 1'b1) && (rd_en == 1'b1))
 dout_flag <= 1'b1;
 else
 dout_flag <= 1'b0;
 end

 //po_flag_reg:输出标志位缓存,延后rd_en一拍,控制po_sum信号
 always@(posedge sys_clk or negedge sys_rst_n)
 begin
 if(sys_rst_n == 1'b0)
 po_flag_reg <= 1'b0;
 else if(rd_en == 1'b1)
 po_flag_reg <= 1'b1;
 else
 po_flag_reg <= 1'b0;
 end

 //po_flag:输出标志信号,延后输出标志位缓存一拍,与po_sum同步输出
 always@(posedge sys_clk or negedge sys_rst_n)
 begin
 if(sys_rst_n == 1'b0)
 po_flag <= 1'b0;
 else
 po_flag <= po_flag_reg;
 end

 //po_sum:求和数据输出
 always@(posedge sys_clk or negedge sys_rst_n)
 begin
 if(sys_rst_n == 1'b0)
 po_sum <= 8'b0;
 else if(po_flag_reg == 1'b1)
 po_sum <= data_out1 + data_out2 + pi_data;
 else
 po_sum <= po_sum;
 end

 ////
 //\* Instantiation \//
 ////

 //------------- fifo_data_inst1 --------------
 fifo_data fifo_data_inst1
 (
 .clock (sys_clk ), //input clock
 .data (data_in1 ), //input [7:0] data
 .wrreq (wr_en1 ), //input wrreq
 .rdreq (rd_en ), //input rdreq

 .q (data_out1 ) //output [7:0] q
 );

 //------------- fifo_data_inst2 --------------
 fifo_data fifo_data_inst2
 (
 .clock (sys_clk ), //input clock
 .data (data_in2 ), //input [7:0] data
 .wrreq (wr_en2 ), //input wrreq
 .rdreq (rd_en ), //input rdreq

 .q (data_out2 ) //output [7:0] q
 );

 endmodule

模块参考代码是参照绘制波形图进行编写的,在波形图绘制小节已经对模块各信号有了详细的说明,本小节不再过多叙述。

在此不再对数据求和模块单独进行仿真,我们在介绍完顶层模块之后,对实验工程进行整体仿真,届时再对本模块进行仿真波形分析。

15.2.2.4. 顶层模块

代码编写

顶层模块将众多模块实例化,对应信号相互连接,较为容易理解,在此只列出代码,不再讲解,具体见代码清单 44‑2。

代码清单 44‑2 顶层模块fifo_sum代码(fifo_sum.v)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
module fifo_sum
(
input wire sys_clk , //输入系统时钟,50MHz
input wire sys_rst_n , //复位信号,低电平有效
input wire rx , //串口数据接收

output wire tx //串口数据发送
);

////
//\* Parameter and Internal Signal \//
////

//wire define
wire [7:0] pi_data ; //输入待求和数据
wire pi_flag ; //输入数据标志信号
wire [7:0] po_sum ; //输出求和后数据
wire po_flag ; //输出数据标志信号

////
//\* Instantiation \//
////

//------------- uart_rx_inst --------------
uart_rx uart_rx_inst
(
.sys_clk (sys_clk ), //系统时钟50MHz
.sys_rst_n (sys_rst_n ), //全局复位
.rx (rx ), //串口接收数据

.po_data (pi_data ), //串转并后的数据
.po_flag (pi_flag ) //串转并后的数据有效标志信号
);

//------------- fifo_sum_ctrl_inst --------------
fifo_sum_ctrl fifo_sum_ctrl_inst
(
.sys_clk (sys_clk ), //频率为50MHz
.sys_rst_n (sys_rst_n ), //复位信号,低有效
.pi_data (pi_data ), //rx传入的数据信号
.pi_flag (pi_flag ), //rx传入的标志信号

.po_sum (po_sum ), //求和运算后的信号
.po_flag (po_flag ) //输出数据标志信号
);

//------------- uart_tx_inst --------------
uart_tx uart_tx_inst
(
.sys_clk (sys_clk ), //系统时钟50MHz
.sys_rst_n (sys_rst_n ), //全局复位
.pi_data (po_sum ), //并行数据
.pi_flag (po_flag ), //并行数据有效标志信号

.tx (tx ) //串口发送数据
);

endmodule

RTL视图

实验工程通过仿真验证后,使用 Quartus 软件对实验工程进行编译,编译完成后,我们查看一下 RTL 视图, RTL 视图展示信息与顶层模块框图一致,各信号正确连接,具体见 图 44‑8。

FIFO009

图 44‑8 RTL视图

15.2.2.5. 仿真验证

仿真代码编写

顶层模块参考代码介绍完毕,开始对顶层模块进行仿真,对顶层模块的仿真就是对实验工程的整体仿真。顶层模块仿真参考代码,具体见代码清单 44‑3。

代码清单 44‑3 顶层模块仿真参考代码(tb_fifo_sum.v)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
\`timescale 1ns/1ns
module tb_fifo_sum();
////
//\* Parameter and Internal Signal \//
////
//wire define
wire tx ;

//reg define
reg clk ;
reg rst_n ;
reg rx ;
reg [7:0] data_men[2499:0] ;

////
//\* Main Code \//
////
//读取数据
initial
$readmemh("E:/sources/fifo_sum/matlab/fifo_data.txt",data_men);

//生成时钟和复位信号
initial
begin
clk = 1'b1;
rst_n <= 1'b0;
#30
rst_n <= 1'b1;
end

always #10 clk = ~clk;

//rx赋初值,调用rx_byte
initial
begin
rx <= 1'b1;
#200
rx_byte();
end

//rx_byte
task rx_byte();
integer j;
for(j=0;j<2500;j=j+1)
rx_bit(data_men[j]);
endtask

//rx_bit
task rx_bit(input[7:0] data);//data是data_men[j]的值。
integer i;
for(i=0;i<10;i=i+1)
begin
case(i)
0: rx <= 1'b0; //起始位
1: rx <= data[0];
2: rx <= data[1];
3: rx <= data[2];
4: rx <= data[3];
5: rx <= data[4];
6: rx <= data[5];
7: rx <= data[6];
8: rx <= data[7]; //上面8个发送的是数据位
9: rx <= 1'b1; //停止位
endcase
#1040;
end
endtask

//重定义defparam,用于修改参数
defparam fifo_sum_inst.uart_rx_inst.BAUD_CNT_END = 52 ;
defparam fifo_sum_inst.uart_rx_inst.BAUD_CNT_END_HALF = 26 ;
defparam fifo_sum_inst.uart_tx_inst.BAUD_CNT_END = 52 ;

////
//\* Instantiation \//
////
//------------- fifo_sum_inst --------------
fifo_sum fifo_sum_inst
(
.sys_clk (clk ),
.sys_rst_n (rst_n ),
.rx (rx ),

.tx (tx )
);

endmodule

仿真波形分析

在此小结中我们只分析fifo_sum_ctrl模块的仿真波形图,uart_rx、uart_tx模块波形分析可参阅之前章节。

fifo_sum_ctrl模块整体仿真波形图,具体见图 44‑9。

FIFO010

图 44‑9 fifo_sum模块仿真波形图

行计数器cnt_row初值均为0,pi_flag拉高一个时钟周期,cnt_row自加1,当cnt_row计数到最大值,下一个pi_flag信号拉高时,cnt_归0,重新开始计数,列计数器cnt_col自加1,当cnt_row和cnt_col均计数到最大值,pi_flag信号最后一次拉高,即传输最后一 个数据,cnt_row和cnt_col均归0,且保持为0,具体见 图 44‑10。

FIFO011

图 44‑10 行、列计数器波形图

fifo1写使能信号wr_en1在第0行数据传入,即cnt_row等于0且pi_flag等于1时,wr_en1赋值为高电平,此时写使能有效,将pi_data传入的数据写入fifo1数据写入端口data_in1;自第1行开始,fifo1写使能信号wr_en1由dout_flag赋值,fifo2读出数据 data_out2传给fifo1数据输入端口data_in1,具体见图 44‑11。

FIFO012

图 44‑11 fifo1写数据、写使能信号仿真波形图

fifo2写使能信号wr_en2在第0行数据传入,即cnt_row等于0时,始终保持低电平,data_in2无数据输入,保持初值0;当第2-48行数据写入时,fifo2写使能信号wr_en2由pi_flag赋值,pi_flag传入的数据写入data_in2,当最后一行数据传入,fifo2写使能信号w r_en2保持低电平,写使能无效,数据写入无效,具体见图 44‑12。

FIFO013

图 44‑12 fifo2写数据、写使能信号仿真波形图

fifo1、fifo2共用读使能信号rd_en,在第2行数据输入之前,即cnt_col = 0,1时,rd_en保持低电平,读使能无效;自第2行数据输入至所有数据传输完成,rd_en由pi_flag信号赋值,rd_en为高电平时,同时读取fifo1、fifo2中暂存的数据,具体见图 44‑13。

FIFO014

图 44‑13 读使能信号rd_en仿真波形图

自第1行数据开始传入时,fifo1的写使能信号wr_en1由dout_flag信号赋值,当fifo2写使能信号wr_en2与读使能信号rd_en 同时有效时,dout_flag信号有效,赋值高电平;否则,dout_flag信号无效,保持低电平,具体见图 44‑14。

FIFO015

图 44‑14 信号 dout_flag仿真波形图

po_flag_reg信号滞后rd_en读使能信号1个时钟周期,po_flag_reg信号有效时,将fifo1、fifo2读出的数据与此时传入的数据pi_data进行求和运算,将求和结果赋值给po_sum;po_flag_reg信号无效时,求和结果po_sum保持不变。输出结果标志信号po_flag 滞后po_flag_reg信号1个时钟周期,为的是要与输出结果po_sum同步,具体见图 44‑15。

FIFO016

图 44‑15 输出信号仿真波形图

15.3. 上板验证

15.3.1. 引脚约束

仿真验证通过后,准备上板验证,上板验证之前先要进行引脚约束。工程中各输入输出信号与开发板引脚对应关系如表格 40‑3所示。

表格 44‑3 引脚分配表

信号名

信号类型

对应引脚

备注

sys_clk

Input

E1

输入系统时钟

sys_rst_n

Input

M15

复位信号

rx

Output

N6

串口接收数据

tx

Output

N5

串口发送数据

下面进行管脚分配,管脚的分配方法在前面章节已有所讲解,在此就不再过多叙述,管脚的分配如下图 44‑16所示。

FIFO017

图 44‑16 管脚分配

15.3.1.1. 结果验证

如图 44‑17所示,开发板连接12V直流电源、USB-Blaster下载器JTAG端口、USB数据线和短路帽。线路正确连接后,打开开关为板卡上电。

FIFO018

图 44‑17 程序下载连线图

如图 44‑18所示,使用“Programmer”为开发板下载程序。

FIFO019

图 44‑18 程序下载窗口

程序下载完成后,使用串口助手向板卡发送待求和数据,随后串口助手接收到求和后的数据,如所示;求和数据正确,上板验证成功。

FIFO020

图 44‑19 串口助手收发数据

15.4. 章末总结

经过本章学习后,读者应该掌握使用双FIFO实现3行数据SUM求和的具体方法,这不仅是为了给Sobel算法的学习做铺垫,在以后的学习中也会涉及到,同样读者也要学会举一反三,能够推理出n行或n列数据的求和方法。

15.5. 拓展训练

1、根据所学知识,读者自行设计一个4行数据求和实验工程,实现4行数据求和并验证实验结果。

2、自行设计一个3列数据求和实验工程,实现3列数据求和并验证实验结果。