0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于循环队列的FIFO缓存实现

Hack电子 来源:Hack电子 2023-09-11 10:12 次阅读

FIFO缓存是介于两个子系统之间的弹性存储器,其概念图如图1所示。它有两个控制信号,wr和rd,用于读操作和写操作。当wr被插入时,输入的数据被写入缓存,此时读操作被忽视。FIFO缓存的head一般情况下总是有效的,因此可在任意时间被读取。rd信号实际上就像“remove”信号;当其被插入的时候,FIFO缓存的第一个项(即head)被移除,下一个项变为可用项。

d5f8bce2-5047-11ee-a25d-92fbcf53809c.png

图1 FIFO缓存的概念框图

在许多应用中,FIFO缓存是一种临界组件,其实现的优化相当复杂。在本节中,我们介绍一种简单的、真实的基于循环序列设计的FIFO缓存。更有效的、基于指定器件实现的FIFO缓存可在Altera或Xilinx的相关手册中找到。

基于循环队列的实现

一种实现FIFO缓存的方法是给寄存器文件添加一个控制电路。寄存器文件通过两个指针像循环队列一样来排列寄存器。写指针(write poniter)指向队列的头(head);读指针(read poniter)指向队列的尾(tail)。每次读操作或写操作,指针都会前进一个位置。8-字循环队列的操作如图2所示。

d6063bd8-5047-11ee-a25d-92fbcf53809c.jpg

图2 基于循环队列的FIFO缓存

FIFO缓存通常包括两个标志信号,full和empty,相应地来指示FIFO满(即不可写)或FIFO空(即不可读)。这两种情况发生在读指针和写指针相等的时候,如图2(a)、(f)和(i)所示的情况。控制器最难的设计任务是获取一种分辨这两种情形的机制。一种方案是使用触发器来跟踪empty和full标志。当系统被初始化时,触发器被设置为1和0;然后在每一个时钟周期根据wr和rd的值来修改。

代码 FIFO缓存

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
modulefifo
#(
parameterB=8, // number of bits in a word
W=3 // number of address bits
)
(
// global clock and aysn reset
inputclk,
inputrst_n,
// fifo interface
// fifo control signnal
inputrd,
inputwr,
// fifo status signal
outputempty,
outputfull,
// fifo data bus
input[B-1:0] w_data,
output[B-1:0] r_data
);
// signal declaration
reg[B-1:0] array_reg [2**W-1:0]; // register array
reg[W-1:0] w_ptr_reg, w_ptr_next, w_ptr_succ;
reg[W-1:0] r_ptr_reg, r_ptr_next, r_ptr_succ;
regfull_reg, empty_reg, full_next, empty_next;
wirewr_en;
// body
// register file write operation
always@(posedgeclk)
if(wr_en)
array_reg[w_ptr_reg] <= w_data;
// register file read operation
assignr_data = array_reg[r_ptr_reg];
// write enabled only when FIFO is not full
assignwr_en = wr & ~full_reg;
// fifo control logic
// register for read and write pointers
always@(posedgeclk, negedgerst_n)
if(!rst_n)
begin
w_ptr_reg <= 0;
r_ptr_reg <= 0;
full_reg <= 1'b0;
empty_reg <= 1'b1;
end
else
begin
w_ptr_reg <= w_ptr_next;
r_ptr_reg <= r_ptr_next;
full_reg <= full_next;
empty_reg <= empty_next;
end
// next-state logic for read and write pointers
always@*
begin
// successive pointer values
w_ptr_succ = w_ptr_reg + 1;
r_ptr_succ = r_ptr_reg + 1;
// default: keep old values
w_ptr_next = w_ptr_reg;
r_ptr_next = r_ptr_reg;
full_next = full_reg;
empty_next = empty_reg;
case({wr, rd})
// 2'b00: no op
2'b01: // read
if(~empty_reg) // not empty
begin
r_ptr_next = r_ptr_succ;
full_next = 1'b0;
if(r_ptr_succ==w_ptr_reg)
empty_next = 1'b1;
end
2'b10: // write
if(~full_reg) // not full
begin
w_ptr_next = w_ptr_succ;
empty_next = 1'b0;
if(w_ptr_succ==r_ptr_reg)
full_next = 1'b1;
end
2'b11: // write and read
begin
w_ptr_next = w_ptr_succ;
r_ptr_next = r_ptr_succ;
end
endcase
end
// output
assignfull = full_reg;
assignempty = empty_reg;
endmodule

代码被分为寄存器文件和FIFO控制器两部分。控制器由两个指针和两个标志触发器组成,它们的次态逻辑会检测wr和rd信号,以采取相应的动作。举例说,在“10”条件下,即暗示只发生写操作。先检查标志触发器,以确保缓存不为满。如果满足条件,我们将写指针前进一位,并清除空标志。再多存储一个字(偏移地址为1所对应的数据)可能使得FIFO缓存满,即新的写指针赶上了读指针,我们使用w_ptr_succ==r_ptr_reg表达式来描述这一情况。

根据图2,我写了下面的testbench,其RTL仿真结果与图2一致。

代码 FIFO缓存的testbench

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
`timescale1ns/1ns
modulefifo_tb;
localparam T=20; // clock period
// global clock and asyn reset
regclk, rst_n;
// fifo interface
regrd, wr;
wireempty, full;
reg[7:0] w_data;
wire[7:0] r_data;
// fifo instantiation
fifo #(.B(8), .W(3)) fifo_inst
(
.clk(clk), .rst_n(rst_n),
.rd(rd), .wr(wr),
.empty(empty), .full(full),
.w_data(w_data), .r_data(r_data)
);
// clcok
always
begin
clk = 1'b0;
#(T/2);
clk = 1'b1;
#(T/2);
end
// reset
initial
begin
rst_n = 1'b0;
#(T/2)
rst_n = 1'b1;
end
// stimulus body
initial
begin
// initial input; empty
rd=0; wr=0; w_data=8'h00;
@(posedgerst_n); // wait to deassert rst_n
@(negedgeclk); // wait for a clock
// 1 write
wr=1; w_data=8'h11;
@(negedgeclk); // wait to assert wr
wr=0;
@(negedgeclk); // wait to deassert wr
// 3 writes
wr=1;
repeat(3)
begin
w_data=w_data+8'h11;
@(negedgeclk);
end
wr=0;
@(negedgeclk);
// 1 read
rd=1;
@(negedgeclk); // wait to assert rd
rd=0;
@(negedgeclk) // wait to deassert rd
// 4 writes
wr=1;
repeat(4)
begin
w_data=w_data+8'h11;
@(negedgeclk);
end
wr=0;
@(negedgeclk);
// 1 write; full
wr=1; w_data=8'hAA;
@(negedgeclk);
wr=0;
@(negedgeclk);
// 2 reads
rd=1;
repeat(2) @(negedgeclk);
rd=0;
@(negedgeclk);
// 5 reads
rd=1;
repeat(5) @(negedgeclk);
rd=0;
@(negedgeclk);
// 1 read; empty
rd=1;
@(negedgeclk);
rd=0;
@(negedgeclk);
$stop;
end
endmodule

d6272ca8-5047-11ee-a25d-92fbcf53809c.png

图3 RTL级仿真波形

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    30

    文章

    5032

    浏览量

    117741
  • fifo
    +关注

    关注

    3

    文章

    369

    浏览量

    43069
  • Verilog
    +关注

    关注

    28

    文章

    1327

    浏览量

    109302
  • 缓存
    +关注

    关注

    1

    文章

    220

    浏览量

    26443
  • RTL
    RTL
    +关注

    关注

    1

    文章

    377

    浏览量

    59069

原文标题:Verilog设计FIFO

文章出处:【微信号:Hack电子,微信公众号:Hack电子】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    FIFO队列原理简述

    FIFO队列机制中最简单的,每个接口上只有一个FIFO队列,表面上看FIFO队列并没有提供什么
    发表于 07-10 09:22 1395次阅读

    基于循环队列FIFO缓存设计实现

    FIFO缓存是介于两个子系统之间的弹性存储器,其概念图如图1所示。它有两个控制信号,wr和rd,用于读操作和写操作。
    发表于 09-08 09:06 261次阅读
    基于<b class='flag-5'>循环</b><b class='flag-5'>队列</b>的<b class='flag-5'>FIFO</b><b class='flag-5'>缓存</b>设计<b class='flag-5'>实现</b>

    一种简单的、真实的基于循环序列的FIFO缓存设计

    FIFO缓存是介于两个子系统之间的弹性存储器,其概念图如图1所示。它有两个控制信号,wr和rd,用于读操作和写操作
    发表于 09-11 09:12 270次阅读
    一种简单的、真实的基于<b class='flag-5'>循环</b>序列的<b class='flag-5'>FIFO</b><b class='flag-5'>缓存</b>设计

    labview能实现循环队列吗?

    救助:请问高手:labview能实现循环队列吗?
    发表于 08-13 15:02

    基于队列函数实现并行循环间传输数据

    数据经过入队列和出队列两个函数过程得到传递,本程序使用队列函数,实现两个并行循环间的数据传递。循环
    发表于 04-23 09:40

    怎么利用异步FIFO和PLL结构来实现高速缓存?

    结合高速嵌入式数据采集系统,提出一种基于CvcloneⅢ FPGA实现的异步FIFO和锁相环(PLL)结构来实现高速缓存,该结构可成倍提高数据流通速率,增加数据采集系统的实时性。采用F
    发表于 04-30 06:19

    队列FIFO——支持网络QoS的重要芯片

    摘要:在IP网络中支持QoS是近年来研究的热点,而IDT公司推出的新型存储器件——多队列FIFO能够支持QoS的应用。因其具有单器件下支持可配置的多个队列,并具有可
    发表于 03-11 13:22 1049次阅读
    多<b class='flag-5'>队列</b><b class='flag-5'>FIFO</b>——支持网络QoS的重要芯片

    FIFO队列原理简述 拥塞避免原理

    拥塞管理是指网络在发生拥塞时,如何进行管理和控制。FIFO队列不对报文进行分类,按报文到达接口的先后顺序让报文进入队列,采用尽力而为的转发模式,PQ队列是针对关键业务应用设计的。
    发表于 02-23 08:35 9448次阅读
    <b class='flag-5'>FIFO</b><b class='flag-5'>队列</b>原理简述 拥塞避免原理

    单片机实现FIFO循环队列的代码和资料免费下载

    和顺序栈相类似,在队列的顺序存储结构中,除了用一组地址连续的存储单元依次存放从队列头到队列尾的元素之外,尚需附设两个指针front和rear分别之时队列头元素和
    发表于 09-19 17:19 2次下载
    单片机<b class='flag-5'>实现</b><b class='flag-5'>FIFO</b><b class='flag-5'>循环</b><b class='flag-5'>队列</b>的代码和资料免费下载

    数据处理时为什么要从DMA缓存空间中获取?

    1、初始化时开启串口的空闲中断,并且初始化为循环DMA。2、触发空闲中断时,更新索引,这个索引表示当前写入索引值,用于上层判断缓存空间已写入的数据(鱼鹰前面写了关于循环FIFO的笔记,
    的头像 发表于 06-24 11:28 3610次阅读

    基于多级队列的云服务并发量分级缓存机制

    基于多级队列的云服务并发量分级缓存机制
    发表于 06-24 11:35 15次下载

    队列实现数据循环外显示源码下载

    队列实现数据循环外显示源码下载
    发表于 11-26 09:21 4次下载

    FPGA学习-基于FIFO的行缓存结构

    在FPGA中对图像的一行数据进行缓存时,可以采用FIFO这一结构,如上图所示,新一行图像数据流入到FIFO1中,FIFO1中会对图像数据进行缓存
    的头像 发表于 05-10 09:59 3195次阅读

    嵌入式环形队列和消息队列实现

    嵌入式环形队列和消息队列实现数据缓存和通信的常见数据结构,广泛应用于嵌入式系统中的通信协议和领域。
    的头像 发表于 04-14 11:52 1062次阅读

    嵌入式环形队列和消息队列是如何去实现的?

    嵌入式环形队列和消息队列实现数据缓存和通信的常见数据结构,广泛应用于嵌入式系统中的通信协议和领域。
    发表于 05-20 14:55 671次阅读