FIFO IP核
转载:
说白了,IP核就是别人做好了的硬件模块,提供完整的用户接口和说明文档,更复杂的还有示例工程,你只要能用好这个IP核,设计已经完成一半了。说起来容易,从冗长的英文文档和网上各个非标准教程中汲取所需,并灵活运用还是需要下一番功夫的。
我认为其中最重要的几点如下:
1) 提供给IP核正确的时钟和复位条件;
2) 明确各个重要用户接口功能;
3) 掌握所需指令的操作时序;
4) 知道内部寄存器地址及功能和配置方式、顺序;
5) 会从官方示例工程中学会IP核正确使用方式;
今天来讲讲一个最常用的IP核,FIFO。可以说它是FPGA能如此灵活处理数据的基础,常用于异步时钟域处理、位宽转换以及需要数据缓存的场合。先来说明下,对于初学者和刚接触一个IP核的人来说,不要过分关注IP核的每一个参数和功能,更没必要知道内部的具体结构和工作原理(还没忘之前使用的ILA吧,反正我是不知道具体怎么设计出来的)只需掌握最常用的和最重要的,把IP核用起来就大功告成了。先从生成IP核开始吧:
配置向导中第一页中是选择FIFO的接口模式和实现方式。这里我们用原始的接口方式。箭头处是实现方式,如果需要异步时钟域处理选择读写独立时钟模式。
第二页中需要特意强调的是读模式的选择。其实这里的First Word Fall Through对应的就是Altera FPGA中FIFO IP核读模式中的Show ahead模式嘛,换个名字而已。这个读模式的特点是在读使能有效之前,即把FIFO中第一个数据从读数据端口持续送出。在这种模式下,读使能信号倒像是“读清”信号,把上一次的数据清除掉,让FIFO送出下一个数据。这样做的处是符合dout 和dout_vld相配合的输出信号方式。
第三页是配置一些可选的标志位,可以根据需要灵活实现一些标志位和握手特性(我是从来没用过)。
第四页可选FIFO内缓存数据量计数器,由于我开始选择的是异步FIFO模式,所以此处有两个计数器分别与读侧和写侧时钟上升沿同步。注意一点:这两个计数器均表示FIFO缓存数据量,只不过在时钟上有些偏差,切不可错误理解为是写入了或者读出了多少个数据。
最后总结页,把前边的参数和配置汇总下。没有问题可以点击OK了!
IP核生成好了,接下来要正确用起来。我们把以太网接口数据传输作为案例背景,通常来说是FPGA逻辑+MAC IP核+外部PHY芯片的架构。若想让MAC IP核正确接收待发送数据,需要将数据进行封包并加入MAC头部信息。
为简化设计,先只考虑对封包后数据添加MAC头部的功能,也就是说此时输入的数据即是长度符合以太网规范,且具有数据包格式的数据。由于在数据部分输出前加额外的信息,所以先要缓存输入的数据直到MAC头输出完成再将写入数据发送出来,因此需要用FIFO缓存数据。进一步分析,经过封包后的数据格式如下:
其中sop和eop分别是包头,包尾指示信号,data_vld是数据有效指示信号。由于数据位宽此处是32位,而数据的最小单元是字节,所以每个32位数据不一定包含4个字节有效数据,使用data_mod指示出无效字节数。为了让该模块输出端知道何时输出完一个数据包,要把eop信号和数据信号拼接写入FIFO中,这样输出端发出eop时进入新一轮循环。如果根据写入sop信号来作为开始发送MAC头部和数据部分的标志,试想当一个短包紧跟着一个长包写进FIFO中时,输出端正在送出上一长包剩下的几个数据,无法响应短包的sop信号指示,那么短包即被“丢弃”了。为了避免丢包现象,需要满足“读写隔离规则”,即FIFO读操作和写操作两者不能根据一方的情况来决定另一方的行为。进一步引出“双FIFO架构”,使用数据FIFO缓存数据,而信息FIFO保留指示信息,这样讲写侧的指示信号写入信息FIFO中,数据FIFO可以根据信息FIFO读侧的信息来判断读的行为,也就满足了读写隔离规则。
在该模块中,可以在写侧出现sop信号时写入信息FIFO一个指示信息,所以当信息FIFO非空即表示有一个数据包正在进来,此时发送MAC头信息,随之读取数据FIFO中缓存数据,当读侧出现eop信号则读清信息FIFO,循环往复完成了添加头部信息的工作。
MAC头部信息为14字节,而数据位宽是32位,即一次发送四个字节,所以相当于头部为三个半数据。因此在发送第三个头部数据时,低16位要用数据部分填充,后边的数据也要跟着移位。如此移位操作后,数据部分就晚了一拍输出最后16位。如果最后这16位数据中有有效字节,那么mac_data_vld当前节拍也要有效,且mac_data_eop和mac_data_mod跟着晚一拍输出;如果无有效字节,则按照正常情况输出。在代码中我使用end_normal和end_lag信号来区分上述两种情况。需要特别注意的是,在移位操作后数据包中包含的无效字节个数也会发生变化。为了理清思路和时序,画出核心信号时序图:
有了项目需求,设计思路后明确模块接口列表:
开始编写代码了:
1 `timescale 1ns / 1ps
2
3 module add_mac_head(
4 input clk,
5 input rst_n,
6 input [31:0] app_data,
7 input app_data_vld,
8 input app_data_sop,
9 input app_data_eop,
10 input [1:0] app_data_mod,//无效字节数
11
12 input mac_tx_rdy,//MAC IP发送准备就绪信号
13 output reg [31:0] mac_data,
14 output reg mac_data_vld,
15 output reg mac_data_sop,
16 output reg mac_data_eop,
17 output reg [1:0] mac_data_mod
18 );
19
20 reg [34:0] wdata;
21 reg wrreq,rdreq;
22 reg wdata_xx;
23 reg wrreq_xx,rdreq_xx;
24 reg [1:0] head_cnt;
25 reg head_flag,head_tmp,rd_flag,rd_flag_tmp;
26 reg [34:0] q_tmp;
27
28 wire [31:0] data_shift;
29 wire add_head_cnt,end_head_cnt;
30 wire head_neg;
31 wire [34:0] q;
32 wire rdempty_xx;
33 wire sop_in;
34 wire [2:0] head_len;
35 wire [111:0] mac_head;
36 wire [47:0] des_mac,sour_mac;
37 wire [15:0] pack_type;
38 wire rd_neg;
39
40 fifo_generator_0 fifo_data (
41 .clk(clk), // input wire clk
42 .din(wdata), // input wire [34 : 0] din
43 .wr_en(wrreq), // input wire wr_en
44 .rd_en(rdreq), // input wire rd_en
45 .dout(q), // output wire [34 : 0] dout
46 .full(), // output wire full
47 .empty() // output wire empty
48 );
49
50 fifo_generator_1 fifo_message (
51 .clk(clk), // input wire clk
52 .din(wdata_xx), // input wire [0 : 0] din
53 .wr_en(wrreq_xx), // input wire wr_en
54 .rd_en(rdreq_xx), // input wire rd_en
55 .dout(), // output wire [0 : 0] dout
56 .full(), // output wire full
57 .empty(rdempty_xx) // output wire empty
58 );
59
60 //数据fifo写数据
61 always@(posedge clk or negedge rst_n)begin
62 if(!rst_n)
63 wdata <= 0;
64 else if(app_data_vld)
65 wdata <= {app_data_eop,app_data_mod,app_data};
66 end
67
68 always@(posedge clk or negedge rst_n)begin
69 if(!rst_n)
70 wrreq <= 0;
71 else if(app_data_vld)
72 wrreq <= 1;
73 else
74 wrreq <= 0;
75 end
76
77 always@(posedge clk or negedge rst_n)begin
78 if(!rst_n)
79 wdata_xx <= 0;
80 else if(sop_in)
81 wdata_xx <= 1;
82 else
83 wdata_xx <= 0;
84 end
85
86 assign sop_in = app_data_vld && app_data_sop;
87
88 //当写侧出现sop时表明有一个数据包正在写入,此时写信息FIFO任意数据告知读侧开始发送MAC头部信息
89 always@(posedge clk or negedge rst_n)begin
90 if(!rst_n)
91 wrreq_xx <= 0;
92 else if(sop_in)
93 wrreq_xx <= 1;
94 else
95 wrreq_xx <= 0;
96 end
97
98 //MAC头部有14个字节 数据位宽是32位,即一个数据4个字节,需要发送4个数据(最后一个数据只有2个字节是头部)
99 always@(posedge clk or negedge rst_n)begin
100 if(!rst_n)
101 head_cnt <= 0;
102 else if(add_head_cnt)begin
103 if(end_head_cnt)
104 head_cnt <= 0;
105 else
106 head_cnt <= head_cnt + 1'b1;
107 end
108 end
109
110 assign add_head_cnt = head_flag && mac_tx_rdy;
111 assign end_head_cnt = add_head_cnt && head_cnt == head_len - 1 - 1;
112 assign head_len = 4;
113
114 //发送MAC头部标志位
115 always@(posedge clk or negedge rst_n)begin
116 if(!rst_n)
117 head_flag <= 0;
118 else if(end_head_cnt)
119 head_flag <= 0;
120 else if(!rdempty_xx && !rd_flag)
121 head_flag <= 1;
122 end
123
124 //读数据FIFO标志位
125 always@(posedge clk or negedge rst_n)begin
126 if(!rst_n)
127 rd_flag <= 0;
128 else if(end_head_cnt)
129 rd_flag <= 1;
130 else if(rd_eop)
131 rd_flag <= 0;
132 end
133
134 assign rd_eop = rdreq && q[34];
135
136 always@(*)begin
137 if(rd_flag && mac_tx_rdy)
138 rdreq <= 1;
139 else
140 rdreq <= 0;
141 end
142
143 //读侧出现eop读取完整版报文,此时读清信息FIFO
144 always@(*)begin
145 if(rd_eop)
146 rdreq_xx <= 1;
147 else
148 rdreq_xx <= 0;
149 end
150
151 //寄存头部标志位找出下降沿
152 always@(posedge clk or negedge rst_n)begin
153 if(!rst_n)
154 head_tmp <= 0;
155 else
156 head_tmp <= head_flag;
157 end
158
159 assign head_neg = head_flag == 0 && head_tmp == 1;
160
161 //寄存q用于移位操作
162 always@(posedge clk or negedge rst_n)begin
163 if(!rst_n)
164 q_tmp <= 0;
165 else
166 q_tmp <= q;
167 end
168
169 assign data_shift = {q_tmp[15:0],q[31:16]};
170
171 //MAC头 14字节
172 assign mac_head = {des_mac,sour_mac,pack_type};
173 assign des_mac = 48'hD0_17_C2_00_E5_40 ;//目的MAC PC网卡物理地址
174 assign sour_mac = 48'h01_02_03_04_05_06 ;//源MAC地址为01_02_03_04_05_06
175 assign pack_type = 16'h0800 ;//IP数据报
176
177 always@(posedge clk or negedge rst_n)begin
178 if(!rst_n)
179 rd_flag_tmp <= 0;
180 else
181 rd_flag_tmp <= rd_flag;
182 end
183
184 assign rd_neg = rd_flag == 0 && rd_flag_tmp == 1;
185
186 //数据输出
187 always@(posedge clk or negedge rst_n)begin
188 if(!rst_n)
189 mac_data_sop <= 0;
190 else if(add_head_cnt && head_cnt == 0)
191 mac_data_sop <= 1;
192 else
193 mac_data_sop <= 0;
194 end
195
196 always@(posedge clk or negedge rst_n)begin
197 if(!rst_n)
198 mac_data_eop <= 0;
199 else if(end_normal || end_lag)
200 mac_data_eop <= 1;
201 else
202 mac_data_eop <= 0;
203 end
204
205 assign end_normal = rd_eop && q[33:32] > 2'd1;
206 assign end_lag = rd_neg && q_tmp[33:32] <= 2'd1;
207
208 always@(posedge clk or negedge rst_n)begin
209 if(!rst_n)
210 mac_data <= 0;
211 else if(add_head_cnt)//由于MAC不是32位数据的整数倍,需要对数据进行移位
212 mac_data <= mac_head[111 - head_cnt*32 -: 32];
213 else if(head_neg)
214 mac_data <= {mac_head[15:0],q[31:16]};
215 else
216 mac_data <= data_shift;
217 end
218
219 always@(posedge clk or negedge rst_n)begin
220 if(!rst_n)
221 mac_data_vld <= 0;
222 else if(head_flag || rd_flag || end_lag)
223 mac_data_vld <= 1;
224 else
225 mac_data_vld <= 0;
226 end
227
228 //输出无效字节个数 由于输出端进行了数据移位,导致无效数据个数发生变化
229 always@(posedge clk or negedge rst_n)begin
230 if(!rst_n)
231 mac_data_mod <= 0;
232 else if(end_normal)
233 mac_data_mod <= q[33:32] - 2;
234 else if(end_lag && q_tmp[33:32] == 2'd1)
235 mac_data_mod <= 1;
236 else if(end_lag && q_tmp[33:32] == 0)
237 mac_data_mod <= 2;
238 else
239 mac_data_mod <= 0;
240 end
241
242 endmodule
编写测试激励验证功能:
1 `timescale 1ns / 1ps
2
3 module add_mac_head_tb;
4
5
6 reg clk,rst_n;
7 reg [31:0] app_data;
8 reg app_data_sop,app_data_eop,app_data_vld;
9 reg [1:0] app_data_mod;
10 reg mac_tx_rdy;
11
12 wire [31:0] mac_data;
13 wire mac_data_vld,mac_data_sop,mac_data_eop;
14 wire [1:0] mac_data_mod;
15
16 add_mac_head add_mac_head(
17 .clk(clk),
18 .rst_n(rst_n),
19 .app_data(app_data),
20 .app_data_vld(app_data_vld),
21 .app_data_sop(app_data_sop),
22 .app_data_eop(app_data_eop),
23 .app_data_mod(app_data_mod),//无效字节数
24
25 .mac_tx_rdy(mac_tx_rdy),//MAC IP发送准备就绪信号
26 .mac_data(mac_data),
27 .mac_data_vld(mac_data_vld),
28 .mac_data_sop(mac_data_sop),
29 .mac_data_eop(mac_data_eop),
30 .mac_data_mod(mac_data_mod)
31 );
32
33 parameter CYC = 5,
34 RST_TIME = 2;
35
36 integer i;
37
38 initial begin
39 clk = 1;
40 forever #(CYC / 2.0) clk = ~clk;
41 end
42
43 initial begin
44 rst_n = 1;
45 #1;
46 rst_n = 0;
47 #(CYC*RST_TIME);
48 rst_n = 1;
49 end
50
51 initial begin
52 #1;
53 app_data = 0;
54 app_data_sop = 0;
55 app_data_eop = 0;
56 app_data_mod = 0;
57 app_data_vld = 0;
58 mac_tx_rdy = 1;
59 #(CYC*RST_TIME);
60 packet_gen(10,0);
61 packet_gen(5,0);
62 packet_gen(15,2);
63 #1000;
64 $stop;
65 end
66
67 task packet_gen;
68 input [15:0] length;
69 input [1:0] invld_num;
70 begin
71 app_data_vld = 1;
72 app_data_sop = 1;
73 app_data = 32'h01020300;
74 for(i = 0;i < length;i = i + 1'b1)begin
75 if(i == 1)
76 app_data_sop = 0;
77 else if(i == length - 1)begin
78 app_data_mod = invld_num;
79 app_data_eop = 1;
80 end
81 app_data = app_data +1'b1;
82 #(CYC*1);
83 end
84 app_data_eop = 0;
85 app_data_vld = 0;
86 app_data_mod = 0;
87 end
88 endtask
89
90 endmodule
连续输入三个长度不同的报文,此处为了设计重用,用可参数化的task对激励报文进行封装。需要输入报文时只需调用packet_gen任务即可实现具有不同长度,不同无效字节个数的数据包。观察输出波形:
mac侧输出三个包文数据如下:
可以看出mac侧数据发送正确。本博文由于主要讲述FIFO应用,这里只做出行为仿真,读者可以灵活运用,添加在自己的项目中。
FIFO IP核的更多相关文章
- FIFO IP核仿真
FIFO IP核仿真 1.FIFO IP核配置 2.FIFO测试逻辑代码 首先往FIFO里面写入512个数据(FIFO深度的一半),然后再开始同时往FIFO里面写入,读出数据.FIFO读和写的时钟域不 ...
- Altera FIFO IP核时序说明
ALTERA在LPM(library of parameterized mudules)库中提供了参数可配置的单时钟FIFO(SCFIFO)和双时钟FIFO(DCFIFO).FIFO主要应用在需要数据 ...
- FPGA基础学习(2) -- FIFO IP核(Quartus)
ALTERA在LPM(library of parameterized mudules)库中提供了参数可配置的单时钟FIFO(SCFIFO)和双时钟FIFO(DCFIFO).FIFO主要应用在需要数据 ...
- IP核之初——FIFO添加以太网MAC头部
本文设计思路源自明德扬至简设计法.在之前的几篇博文中,由于设计比较简单,所有的功能都是用verilogHDL代码编写实现的.我们要学会站在巨人的肩膀上,这时候就该IP核登场了! 说白了,IP核就是别人 ...
- IP核——FIFO
一.Quartus 1.打开Quartus ii,点击Tools---MegaWizard Plug-In Manager 2.弹出创建页面,选择Creat a new custom megafunc ...
- Lattice 的 Framebuffer IP核使用调试笔记之IP核生成与参数设置
本文由远航路上ing 原创,转载请标明出处. 这节笔记记录IP核的生成以及参数设置. 先再IP库里下载安装Framebuffer 的ipcore 并安装完毕. 一.IP核的生成: 1.先点击IP核则右 ...
- 7 Series GTP IP核使用总结 IP核配置篇
FPGA内嵌收发器相当于以太网中的PHY芯片,但更灵活更高效,线速率也在随着FPGA芯片的发展升级.本文对7系列FPGA内部高速收发器GTP IP核的配置和使用做些简单的总结,以备后续回顾重用.本文是 ...
- 浅析Xilinx 三速以太网MAC IP核
之前在使用Altera的三速以太网MAC IP的基础上,完成了UDP协议数据传输.此次为了将设计移植到xilinx FPGA上,需要用到xilinx的三速以太网MAC IP核,当然也可以自己用HDL编 ...
- xilinx IP核配置,一步一步验证Xilinx Serdes GTX最高8.0Gbps
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u010161493/article/details/77658599 目录(?)[+] 之前 ...
随机推荐
- FAST特征点检测算法
一 原始方法 简介 在局部特征点检测快速发展的时候,人们对于特征的认识也越来越深入,近几年来许多学者提出了许许多多的特征检测算法及其改进算法,在众多的特征提取算法中,不乏涌现出佼佼者. 从最早期的Mo ...
- Oracle EBS AP 取消发票
--取消发票 created by jenrry 20170425 declare l_result BOOLEAN; l_message_name VARCHAR2(240); l_invoice_ ...
- 大话存储 3 - 七种磁盘RAID技术
RAID技术 Redundant Array of Independent Disks 由独立的磁盘组成的具有冗余特性的阵列. 有两个特性: 阵列:需要很多磁盘来组成 冗余:允许某块磁盘损坏之后,数据 ...
- 56_实现类似spring的可配置的AOP框架
> config.properties 配置文件 key=类名 > BeanFactory Bean工厂,负责得到bean getBean("xxx") &g ...
- 邮件客户端修改密码—OWA
邮件客户端修改密码—OWA 1.登录OWA 2.输入用户名 3.点击选项 4.更改密码
- 【优质】React的学习资源
React的学习资源 github 地址: https://github.com/LeuisKen/react-collection https://github.com/reactnativecn/ ...
- 【转】开篇python--明白python文件如何组织,理解建立源文件
在Python 中引用是非常简单的事情,这里需要清楚三个概念就可以了包.模块.类.类这个就不用说了. 模块对应的是一个.py 文件,那么module_name 就是这个文件去掉.py 之后的文件名,p ...
- react如何引入外部文件的整理
1 引入组件 首先就应该是安装了,安装在环境中后通过 import { Select, Button, Icon, QueueAnim } from 'antd'; 就可以把需要的组件引用进来了~ 2 ...
- javascript实现百度地图鼠标滑动事件显示、隐藏
其实现思路是给label设置样式,我们来看下具体做法吧 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var label = new BMap.Labe ...
- snmpwalk,iptables
-A RH-Firewall-1-INPUT -i lo -j ACCEPT -A INPUT -s 1.1.1.1 -p udp -d 2.2.2.2 --dport 161 -j ACCEPT - ...