同步FIFO学习笔录--

同步FIFO学习

1、撰写缘由

这几天在初步学习verilog,学习到了同步FIFO,写点东西记录一下,写写心得体会和大家一起交流学习,中间有不对的地方希望大家能多多包涵,欢迎指正,共同进步。学习时主要参考:https://www.cnblogs.com/SYoong/p/6108780.html,感谢大神的分享。本文与参考有些不同,其中我自己认为有些需要改动的地方,若不对,多多指正。其实同步FIFO在实际中应用很少,应用多的还是异步FIFO,不过作为一个新手拿来练习练习感觉是很不错的。

2、什么是FIFO

简而言之,FIFO就是先进先出的数据缓存器。没有外部读写地址线,顺序的写入与读出,数据地址由内部读写指针自动加1完成,不能像普通存储器那样由地址线读取或者写入某个指定的地址。

3、FIFO有什么作用

两个不同时钟域间数据传输使用FIFO作为缓冲;允许时钟进行DMA操作,提高数据传输速度;不同宽度的数据接口也可以使用FIFO等。

4、同步FIFO的Verilog实现

此同步FIFO深度为16,位宽位8,分为了4个子模块:(1)写地址产生模块wr_addr_gen;(2)16个8bits寄存器模块;(3)读地址产生模块;(4)标志位写满full和读空empty模块。

鼓励大家写代码时能够分模块写并且加注释,这样使代码更加清晰,可读性与可移植性更高。

(1)写地址产生模块wr_addr_gen

当写使能有效并且FIFO还没有被写满时,写地址在时钟上升沿时顺序加1。


module w_addr_gen(

input wire clk, //时钟信号

input wire full,//写满标志

input wire wr_en,//写使能

input wire rst_n,//复位信号,低电平有效

output reg [3:0] wr_addr//写地址

);

always @ (posedge clk) begin

if (!rst_n) begin

wr_addr <= 4‘b0;

end else if (!full && wr_en == 1‘b1) begin

wr_addr <= wr_addr + 1‘b1;

end

end

endmodule

(2)读地址产生模块rd_addr_gen

当读使能有效并且FIFO还没有被读空时,读地址在时钟上升沿时顺序加1。


module r_addr_gen (

input wire clk, //时钟

input wire rst_n,//复位

input wire rd_en,//读使能

input wire empty,//读空标志

output reg [3:0]rd_addr//读地址信号

);

always @ (posedge clk) begin

if (!rst_n) begin

rd_addr <= 4‘b0;

end

else if ((rd_en==1‘b1) && (empty != 1‘b1)) begin

rd_addr <= rd_addr + 1‘b1;

end

end

endmodule

(3)存储器RAM模块的实现


module RAM (

input wire clk,

input wire wr_en,

input wire [3:0] wr_addr,//写地址

input wire [7:0] data_in, //输入数据

input wire rd_en, //读使能

input wire [3:0] rd_addr,//读地址

input wire full,

input wire empty,

output reg [7:0] data_out //输出数据

);

reg [7:0] fifo [15:0]; //8bits register*16

always @ (posedge clk) begin  //write

if ((wr_en == 1‘b1) && (full!=1))

fifo[wr_addr] <= data_in;

//上一行与参考不一致,当写使能有效并且FIFO未写满时,将数据写入FIFO对应地址

//若写使能有效而FIFO已经处于满状态的话,再写入数据就会覆盖原先地址的数据,导致数据丢失

end

always @ (posedge clk) begin //read

if ((rd_en == 1‘b1) && (empty!=1))

//上一行与参考不一致,当读使能有效并且FIFO不为空时,将FIFO中对应地址中的数据读出

//若读使能有效而FIFO为空的话,再读出就会导致读出空数据出错

data_out <= fifo[rd_addr];

end

endmodule

(4)标志位产生模块flag_gen的实现


module flag_gen (

input wire clk,

input wire rst_n,

input wire rd_en,

input wire wr_en,

output wire empty,//FIFO空标志位

output wire full//FIFO满标志位

);

parameter max=5‘b10000;

reg [4:0] count;//16位的FIFO用5位的寄存器记录被写入的数据个数,见下

always @ (posedge clk) begin

if (!rst_n) begin

count <= 5‘b0;

end else case({rd_en,wr_en})

2‘b00: count <= count; //读写均无效,FIFO中被写入数据个数不变

2‘b01: if (count!=max) count <= count + 1‘b1;//当写有效且FIFO未被写满,计数加1

2‘b10: if (count!=5‘b0000) count <= count - 1‘b1;//当读有效且FIFO未被读空,计数减1

2‘b11: count <= count;

default: count <= count;

endcase

end

assign full = (count == max);//当计数等于16时,产生满信号,所以用5位的count

//若count==4‘b1111产生满信号,会导致FIFO中一个存储空间不能被写入数据,仿真可以试一下

assign empty = (count == 5‘b0000);

endmodule

(5)顶层模块syn_fifo_top的实现

用wire将各个模块连接起来即可。


module syn_fifo_top(

input wire clk,

input wire rst_n,

input wire wr_en,

input wire rd_en,

input wire [7:0] data_in,

output wire [7:0] data_out

);

wire [3:0] wr_addr;

wire [3:0] rd_addr;

RAM iRAM(

.clk(clk),

.wr_en(wr_en),

.wr_addr(wr_addr),

.data_in(data_in),

.rd_en(rd_en),

.rd_addr(rd_addr),

.data_out(data_out),

.full(full),

.empty(empty)

);

r_addr_gen ir_addr_gen(

.clk(clk),

.rst_n(rst_n),

.rd_en(rd_en),

.empty(empty),

.rd_addr(rd_addr)

);

w_addr_gen iw_addr_gen(

.clk(clk),

.full(full),

.wr_en(wr_en),

.rst_n(rst_n),

.wr_addr(wr_addr)

);

flag_gen iflag_gen(

.clk(clk),

.rst_n(rst_n),

.rd_en(rd_en),

.wr_en(wr_en),

.empty(empty),

.full(full)

);

endmodule

(6)仿真testbench的实现


`timescale 1ns/1ps

`define clk_period 20

module syn_fifo_tb();

reg clk;

reg rst_n;

reg wr_en,rd_en;

reg [7:0] data_in;

wire [7:0] data_out;

syn_fifo_top isyn_fifo_top(

.clk(clk),

.rst_n(rst_n),

.wr_en(wr_en),

.rd_en(rd_en),

.data_in(data_in),

.data_out(data_out)

);

initial begin

clk = 1‘b0;

end

always #(`clk_period/2) clk = ~clk;

initial begin

wr_en = 1‘b1;

rd_en = 1‘b0;

rst_n = 1‘b0;

data_in =8‘b0;

#(`clk_period+1) rst_n = 1‘b1;

repeat(16) begin

#(`clk_period+1)

data_in = data_in + 1‘b1;

end

# (`clk_period*20+1)

rd_en = 1‘b1;

wr_en =1‘b0;

# (`clk_period*200+1)

$finish;

end

endmodule

5、标志位产生模块flag_gen的另一种实现方法

分别将读/写地址寄存器扩展一位,将最高位设置为状态位,其余低位作为地址位,指针由地址位以及状态位组成。首先把读、写状态位全部复位,如果地址循环了奇数次,则状态位置1,偶数次则又重新复位,应用地址位和状态位的结合实现对空、满标志位的控制。当读写指针的地址位和状态位全部吻合的时候,读写指针经历了相同次数的循环移动,也就是说,FIFO 处于空状态;如果读写指针的地址位相同而状态位相反,写指针比读指针多循环一次,标志FIFO处于满状态。


module flag_gen (

input wire [4:0] wr_addr,

input wire [4:0] rd_addr,

output wire empty,

output wire full

);

assign full = ((wr_addr[4]!=rd_addr[4]) && (wr_addr[3:0]==rd_addr[3:0]));

assign empty = (wr_addr == rd_addr);

endmodule

注意深度为16的FIFO,方法1使用4位的地址线即可,方法二需要使用5位的地址线,即需要将每个模块中的[3:0]wr_addr、[3:0]rd_addr替换为[4:0]wr_addr、[4:0]rd_addr,需要注意一下。

原文地址:https://www.cnblogs.com/muzili86/p/8562904.html

时间: 2024-11-09 04:02:22

同步FIFO学习笔录--的相关文章

Verilog学习笔记简单功能实现(八)...............同步FIFO

Part 1,功能定义: 用16*8 RAM实现一个同步先进先出(FIFO)队列设计.由写使能端控制该数据流的写入FIFO,并由读使能控制FIFO中数据的读出.写入和读出的操作(高电平有效)由时钟的上升沿触发.当FIFO的数据满和空的时候分别设置相应的高电平加以指示.FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,它与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成

Verilog实现同步FIFO

作为实现RS232串行通信的Verilog实现的预备工作,使用Verilog实现了同步FIFO的功能,其代码段如下 //this program segment realize the function of fifo IPcore //synchronous fifo module fifo_ip #( parameter Addr_Width=8,Bit_Width=8 ) (clk,rst,wren,rden,full,empty,din,dout,counter); input clk,

同步FIFO design and IP level verification

一.前言 应聘IC前端相关岗位时,FIFO是最常考也是最基本的题目.FIFO经常用于数据缓存.位宽转换.异步时钟域处理.随着芯片规模的快速增长,灵活的system verilog成为设计/验证人员的基本功.本文从简易版的同步FIFO开始,熟悉IP设计与验证的基础技能. 二.IP设计 FIFO这一IP核已经相当成熟,因此网上资料也是一抓一大把.其中笔者认为较好的一个在文末附录中,需要详细了解FIFO工作原理的朋友可以仔细看看.这里简单介绍下本文设计FIFO的原理与结构.FIFO的内部存储单元是常见

同步FIFO的verilog描述

1 /****************************************************** 2 A fifo controller verilog description. 3 ******************************************************/ 4 module fifo(datain, rd, wr, rst, clk, dataout, full, empty); 5 input [7:0] datain; 6 input

【设计开发】 典型同步电路设计- 同步FIFO

一.前言 FIFO (First-In-First-Out) 是一种先进先出的数据交互方式,在数字ASIC设计中常常被使用.FIFO按工作时钟域的不同又可以分为:同步FIFO和异步FIFO. 同步FIFO的写时钟和读时钟为同一个时钟,FIFO内部所有逻辑都是同步逻辑,常常用于交互数据缓冲.异步FIFO的写时钟和读时钟为异步时钟,FIFO内部的写逻辑和读逻辑的交互需要异步处理,异步FIFO常用于跨时钟域交互. 本文介绍同步FIFO的典型设计方法. 二.原理 典型同步FIFO有三部分组成: (1)

同步fifo的verilogHDL设计实例

原创 设计一个fifo,输入16bit,输出16bit的data,寻址宽度5bit,有空满标志. top 层如下所示: 1 /* 2 date : 2014/10/14 3 version : modelsim 10.1e-altera 4 design : pengxiaoen 5 function : 同步fifo设计 6 */ 7 module test2 ( 8 clock , 9 reset, 10 in_data , 11 12 ou_data , 13 wr_full , 14 r

Gradle 编译学习笔录

Gradle下载与配置 下载路径: http://www.gradle.org/downloads 配置: 下载完gradle后, 解压缩到你的目录盘, 然后打开gradle的bin目录并将其路径复制, 打开环境变量, 将复制的内容加到Path中. 配置完毕后,可以打开cmd命令工具, 运行gradle –version 如果出现正确的版本号 那么将配置成功 ! Gradle简单命令介绍 build 编译命令: 使用cmd命令进入到项目目录下, 然后运行gradle build . 编译成功后可

同步FIFO设计Spec

为什么要写Spec文档: 记得刚进公司实习的时候,导师安排我写一个SM4算法AHB接口模块,要求写代码前 写出详细的设计文档,详细到什么程度呢,看着文档就能把代码写好,作为一个只 在学校写过数字钟的小白来说有点不太理解,后面看的Spec多了,好的Spec的确能够看 着Spec把代码给敲了,能够方便别人理解你的设计思路,特别是当你遇到一份注释不太 清楚,逻辑难懂的代码时,是多么渴望来一份Spec帮助理解. 网页上编辑图和格式不是很方便,就写的简单点吧 1.同步FIFO(First In First

FPGA之FIFO学习心得

FIFO FIFO: 中文意思:先进先出[类似于堆栈] 作用: 在FPGA中,一般用于不同时域之间的数据传递,比如FIFO的一端是AD采集,另一端是计算机PCI总线,假设AD的采集速度一般都是几百Kb/s,PCI总线的速度为200Mb/s,在这俩个的时域中传递数据时就可以采用FIFO来作为数据缓冲.同时FIFO还可以作为不同数据宽度之间的传递FIFO也是可以胜任的,比如UART收到的数据传递给USB.UART收到的数据是8位的数据,USB传递的16数据,如果之间传递,他们是不同的时域,传输的速度