企业网站建设方案价位,女生学计算机应用技术可以做什么,计算机应用技术专业,湖北网站定制开发价格表异步FIFO
描述
请根据题目中给出的双口RAM代码和接口描述#xff0c;实现异步FIFO#xff0c;要求FIFO位宽和深度参数化可配置。
电路的接口如下图所示。 双口RAM端口说明#xff1a; 端口名 I/O 描述 wclk input 写数据时钟 wenc input 写使能 waddr input 写…异步FIFO
描述
请根据题目中给出的双口RAM代码和接口描述实现异步FIFO要求FIFO位宽和深度参数化可配置。
电路的接口如下图所示。 双口RAM端口说明 端口名 I/O 描述 wclk input 写数据时钟 wenc input 写使能 waddr input 写地址 wdata input 输入数据 rclk input 读数据时钟 renc input 读使能 raddr input 读地址 rdata output 输出数据
异步FIFO端口说明 端口名 I/O 描述 wclk input 写时钟 rclk input 读时钟 wrstn input 写时钟域异步复位 rrstn input 读时钟域异步复位 winc input 写使能 rinc input 读使能 wdata input 写数据 wfull output 写满信号 rempty output 读空信号 rdata output 读数据
双口RAM代码如下可在本题答案中添加并例化此代码。
module dual_port_RAM #(parameter DEPTH 16,parameter WIDTH 8)(input wclk
,input wenc
,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数得到地址的位宽。
,input [WIDTH-1:0] wdata //数据写入
,input rclk
,input renc
,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数得到地址的位宽。
,output reg [WIDTH-1:0] rdata //数据输出
);reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];always (posedge wclk) begin
if(wenc)
RAM_MEM[waddr] wdata;
end always (posedge rclk) begin
if(renc)
rdata RAM_MEM[raddr];
end endmodule
输入描述 input wclk , input rclk , input wrstn , input rrstn , input winc , input rinc , input [WIDTH-1:0] wdata 输出描述 output wire wfull , output wire rempty , output wire [WIDTH-1:0] rdata 解题思路 同步FIFO的设计原理及代码 【Verilog学习日常】—牛客网刷题—Verilog企业真题—VL68-CSDN博客 同步FIFO和异步FIFO 主要参考以下博文 1什么是异步FIFO与同步FIFO有何不同异步FIFO的设计理念和设计要点是什么同步FIFO和异步FIFO的应用场景分别是什么 - CSDN文库 同步FIFO和异步FIFO总结[通俗易懂]-腾讯云开发者社区-腾讯云 (tencent.com) 同步FIFO和异步FIFO
同步FIFO和异步FIFO是两种不同的数据传输方式。
同步FIFO是一种基于时钟的数据传输方式数据的输入和输出都是在时钟边沿进行的。在同步FIFO中数据的输入和输出操作是同步的即在每个时钟周期内输入和输出操作需要在时钟的边沿进行。这种同步方式可以确保数据的稳定性和可靠性但需要保证输入和输出的时钟频率一致。
异步FIFO是一种不依赖时钟的数据传输方式数据的输入和输出是根据输入端和输出端的请求来进行的。在异步FIFO中输入和输出操作是异步的数据可以在不同的的时间进行输入和输出操作。这种方式相对于同步FIFO来说更加灵活但需要额外的电路来处理输入和输出之间的时序问题。
同步FIFO和异步FIFO的优点
同步FIFO的优点
同步FIFO在数据读写时使用相同的时钟因此不需要考虑时钟域的问题设计和验证相对简单。同步FIFO的读写造作是同步的可以保证数据的可靠性和一致性。同步FIFO的读写指针可以通过同步逻辑进行控制可以实现更复杂的读写操作。
异步FIFO的优点
异步FIFO可以在不同的时钟域之间进行数据传输适用于异步系统或者时钟频率不同的系统。异步FIFO的读写操作是异步的可以实现更高的并发性和吞吐量。异步FIFO的读写指针可以通过异步逻辑进行控制可以实现更灵活的读写操作。 FIFO的使用场景
数据缓冲——当数据写入过快并且间隔时间长突发写入。那么通过设置一定深度的FIFO可以起到数据暂存的功能且使得后续处理流程平滑。时钟域的隔离——主要用于异步FIFO。对于不同时钟域的数据传输可以通过FIFO进行隔离避免跨时钟域的数据传输带来的设计和约束上的复杂度。同于不同宽度的数据接口。例如单片机1是8位DSP是16. 异步FIFO的设计原理 主要参考以下博文 verilog实现异步FIFO_异步fifo verilog代码-CSDN博客 同步FIFO和异步FIFO总结_synchronization stages-CSDN博客 对于FIFO的设计最重要的两点如下
读写时钟的移动FIFO队列空满检测对于异步FIFO的空满检测还涉及到一个跨时钟域问题
异步FIFO的跨时钟域问题
将一个二进制的计数值从一个时钟域同步到另一个时钟域的时候很容易出现问题。因为采用二进制计数器时所有位都有可能同时变化在同一个时钟沿同步多个信号的变化会产生亚稳态问题。而使用格雷码Gray码时只有一位变化因此在两个时钟域间同步多个位不会产生问题。所以需要一个二进制到gray码的转换电路将地址值转换为相应的gray码然后将该Gray码同步到另一个时钟域进行对比作为空满状态的检测还需添加一个二级同步器。
下面画出异步FIFO的指针同步电路 对异步FIFO的Verilog代码设计主要分为以下几个模块
1.定义读写指针
该步骤与同步FIFO类似唯一不同的点在于异步FIFO的读写操作中的时钟信号和异步复位信号是不同的 assign wenc winc (~wfull); assign renc rinc (~rempty);//定义读写指针parameter POINT_WIDTH $clog2(DEPTH);reg [POINT_WIDTH: 0] w_point_b, r_point_b, w_point_g, r_point_g;//写指针always (posedge wclk or negedge wrstn) beginif (!wrstn) w_point_b b0;else beginif (wenc) w_point_b w_point_b 1b1; //同步FIFO写法else w_point_b w_point_b; endend//读指针always (posedge rclk or negedge rrstn) beginif (!rrstn) r_point_b b0;else beginif (renc) r_point_b r_point_b 1b1; //同步FIFO写法else r_point_b r_point_b;endend
2.二进制到gray码的转换电路
//二进制码转换为Gray码Bit_To_Gray BG_W ( .Bit_Code(w_point_b), .clk(wclk), .rst_n(wrstn), .Gray_Code(w_point_g_w)); Bit_To_Gray BG_R ( .Bit_Code(r_point_b), .clk(rclk), .rst_n(rrstn), .Gray_Code(r_point_g_w)); always (*) beginw_point_g w_point_g_w;r_point_g r_point_g_w;endmodule Bit_To_Gray(input [4:0] Bit_Code,input clk,input rst_n,output reg[4:0] Gray_Code);always (posedge clk or negedge rst_n) beginif (!rst_n) Gray_Code d0;else Gray_Code (Bit_Code 1) ^ Bit_Code;
end
endmodule 3.同步信号
同步信号为空满检测的前一步
当需要从FIFO中读数据时应该将在wclk时钟域中的写指针地址w_point_g同步到rclk时钟域中因此添加了一个两级同步器最终在rclk时钟域上输出写指针地址wq_2;并且在读数据时应该进行判空操作。因此使用rclk时钟域下的读指针地址r_point_g和同步后的写指针地址wq_2来判定当前FIFO是否为空当需要从FIFO中写数据时应该将在rclk时钟域中的读指针地址r_point_g同步到wclk时钟域中因此添加了一个两级同步器最终在wclk时钟域上输出读指针地址rq_2并且在写数据时应该进行判满操作。因此使用wclk时钟域下的写指针地址w_point_g和同步后的读指针地址rq_2来判定当前FIFO时候已满
PS信号同步器的相关知识可见【Verilog学习日常】—牛客网刷题—Verilog企业真题—VL69-CSDN博客 //同步信号部分reg [POINT_WIDTH: 0] rq_1, rq_2;always (posedge wclk or negedge wrstn) beginif (!wrstn ) begin rq_1 d0; rq_2 d0; endelse begin rq_1 r_point_g; rq_2 rq_1; endendreg [POINT_WIDTH: 0] wq_1, wq_2;always (posedge rclk or negedge rrstn) beginif (!rrstn ) begin wq_1 d0; wq_2 d0; endelse begin wq_1 w_point_g; wq_2 wq_1; endend
4.空满检测
异步FIFO的判空与同步FIFO的判空相同即判断读写指针地址包含折回标志位是否完全相同
异步FIFO的判满根据格雷码的性质由于添加了一个折回标志位最高位当以0100015为对称轴时可发现前两高位互补后三低位相同因此当读写指针满足该条件时FIFO队列为满
//空满检测assign rempty (wq_2 r_point_g) ? 1b1 : 1b0;assign wfull (w_point_g[POINT_WIDTH] ! rq_2[POINT_WIDTH] w_point_g[POINT_WIDTH-1] ! rq_2[POINT_WIDTH-1] w_point_g[POINT_WIDTH-2:0] rq_2[POINT_WIDTH-2:0]) ? 1b1: 1b0;
完整代码如下
timescale 1ns/1ns/***************************************AFIFO*****************************************/
module asyn_fifo#(parameter WIDTH 8,parameter DEPTH 16
)(input wclk , //写时钟input rclk , //读时钟 input wrstn , //写时钟域异步复位input rrstn , //读时钟域异步复位input winc , //写使能input rinc , //读使能input [WIDTH-1:0] wdata , //写数据output wire wfull , //写满信号output wire rempty , //读空信号output wire [WIDTH-1:0] rdata //读数据
);assign wenc winc (~wfull); assign renc rinc (~rempty);//定义读写指针parameter POINT_WIDTH $clog2(DEPTH);reg [POINT_WIDTH: 0] w_point_b, r_point_b, w_point_g, r_point_g;//写指针always (posedge wclk or negedge wrstn) beginif (!wrstn) w_point_b b0;else beginif (wenc) w_point_b w_point_b 1b1; //同步FIFO写法else w_point_b w_point_b; endend//读指针always (posedge rclk or negedge rrstn) beginif (!rrstn) r_point_b b0;else beginif (renc) r_point_b r_point_b 1b1; //同步FIFO写法else r_point_b r_point_b;endend//读写指针的二进制码转换为格雷码wire [POINT_WIDTH:0] w_point_g_w, r_point_g_w;/*assign w_point_g_w (w_point_b 1) ^ w_point_b;assign r_point_g_w (r_point_b 1) ^ r_point_b;always (posedge wclk or negedge wrstn) beginif (!wrstn) w_point_g d0;else w_point_g w_point_g_w;endalways (posedge rclk or negedge rrstn) beginif (!rrstn) r_point_g d0;else r_point_g r_point_g_w;end*/Bit_To_Gray BG_W ( .Bit_Code(w_point_b), .clk(wclk), .rst_n(wrstn), .Gray_Code(w_point_g_w)); Bit_To_Gray BG_R ( .Bit_Code(r_point_b), .clk(rclk), .rst_n(rrstn), .Gray_Code(r_point_g_w)); always (*) beginw_point_g w_point_g_w;r_point_g r_point_g_w;end//同步信号部分reg [POINT_WIDTH: 0] rq_1, rq_2;always (posedge wclk or negedge wrstn) beginif (!wrstn ) begin rq_1 d0; rq_2 d0; endelse begin rq_1 r_point_g; rq_2 rq_1; endendreg [POINT_WIDTH: 0] wq_1, wq_2;always (posedge rclk or negedge rrstn) beginif (!rrstn ) begin wq_1 d0; wq_2 d0; endelse begin wq_1 w_point_g; wq_2 wq_1; endend//空满检测assign rempty (wq_2 r_point_g) ? 1b1 : 1b0;assign wfull (w_point_g[POINT_WIDTH] ! rq_2[POINT_WIDTH] w_point_g[POINT_WIDTH-1] ! rq_2[POINT_WIDTH-1] w_point_g[POINT_WIDTH-2:0] rq_2[POINT_WIDTH-2:0]) ? 1b1: 1b0;//例化双口RAMdual_port_RAM #(.DEPTH(DEPTH),.WIDTH(WIDTH))DR (.wclk(wclk),.wenc(wenc),.waddr(w_point_b[POINT_WIDTH-1:0]) //深度对2取对数得到地址的位宽。,.wdata(wdata) //数据写入,.rclk(rclk),.renc(renc),.raddr(r_point_b[POINT_WIDTH-1:0]) //深度对2取对数得到地址的位宽。,.rdata(rdata) //数据输出
);
endmodule//二进制码转换为Gray码
module Bit_To_Gray(input [4:0] Bit_Code,input clk,input rst_n,output reg[4:0] Gray_Code);always (posedge clk or negedge rst_n) beginif (!rst_n) Gray_Code d0;else Gray_Code (Bit_Code 1) ^ Bit_Code;
end
endmodule