FPGA(五)RTL代码之一(跨时钟域设计)
文章目录
- 前言
- 一、异步FIFO
- 二、异步复位同步释放
- 三、两级触发器同步
- 四、握手CDC设计
- 五、异步双口RAM
- 总结
前言
这不马上要面试了嘛,有些慌!HDLbits的题目已经刷完了,但又知道自己还远远不够,就从一个B站UP主那里截取了一个刷题的题库,只有题目,代码都要自己去写,所以写的代码可能存在问题,我打算分成好几节把刷的题目代码放出来。仅供自己学习。如果有需要的也可以看看,若有错误,还望指出!谢谢!
一、异步FIFO
关于这部分内容,我在上一篇博客FPGA(四)数字IC面试的四个基本问题的第四章第二部分详细讲过,也是有代码的,采用的格雷码的方法。
二、异步复位同步释放
详细解释可参考异步复位同步释放原理
简单解释就是:
异步复位,同步释放就是指在复位信号到来的时候不受时钟信号的同步,而是在复位信号释放的时候受到时钟信号的同步。
RTL代码如下:
module Sys_Rst(input clk ,input rst_n ,output sys_rst
);
reg rst_r0;
reg rst_r1;
always @(posedge clk or negedge rst_n)beginif(!rst_n)beginrst_r0 <= 1'b0;rst_r1 <= 1'b0;endelse beginrst_r0 <= 1'b1;rst_r1 <= rst_r0;end
end
assign sys_rst = rst_r1;
endmodule
三、两级触发器同步
两级触发器一般就是我们常说的打两拍,可以有效降低亚稳态产生的风险,如下所示:
RTL代码:
module abit_Pulse(input clk , //输入时钟input rst_n , //复位信号input asynch_in , //输入信号 output synch_out
);
reg [1:0] signal_r;
//在快时钟域下,将传递来的信号打两拍
always @(posedge clk or negedge rst_n) beginif(!rst_n)signal_r <= 2'b00;elsesignal_r <= {signal_r[0],asynch_in};
endassign synch_out = signal_r[1];endmodule
四、握手CDC设计
FPGA逻辑设计回顾(7)多比特信号的CDC处理方式之握手同步
一种基于握手机制的跨时钟域方法及其Verilog实现
握手指的是两个设备之间通信的一种方式,用来通信的信号就是握手信号。最简单的握手信号是 valid 和 ready,也可以叫 request 和 grant。假设设备1向设备2发送数据,设备1不知道设备2什么时候可以接收数据,设备2也不知道设备1什么时候会发送数据,那么它们之间如果用握手通信可能是这样的顺序:
- 设备1将 valid 信号置1,告诉设备2,数据准备就绪了,请查收
- 设备2此刻正处于忙碌状态无法接收数据,设备2将 ready 信号保持为0
- 设备2空闲了,将 ready 信号置1接收设备1的数据
- 设备1看到设备2的 ready 为1,它知道设备2已经接收好数据了,将 valid 置0同时撤销数据,准备下一次发送
- 可以看到因为有握手控制,可以确保数据的正确传输,不会丢失。跨时钟域的握手设计就是利用握手控制这种优势,从而避免因为跨时钟域引起的数据传输错误
RTL代码:
/*************************************************************************************
输入:
·clk_a, clk_b 源时钟与目的市长
·rst 复位信号
·a_en,data_a 可以当成一种协议,检测到a_en有效(下降沿)的时候,输入数据就更新,更新数据一直持续到a_en的下一个下降沿输出:
·b_en 对a_en的同步
·data_b_out 对b的同步
·ack_a 是b时钟域的响应信号ack,同步到a时钟域后的信号,通知a时钟域(下降沿通知)可以发送下一个数据了。事实上,a_en就是该信号的下降沿
*************************************************************************************/
module syn_handshake(input wire clk_a , //源时钟input wire clk_b , //目的时钟input wire rst ,input wire a_en , //来自于外部的使能信号,脉冲持续一个时钟周期input wire [3:0] data_a_in , //外部输入信号output reg [3:0] data_b_out ,output wire b_en ,output wire ack_a );//生成a_en的下降沿 只用延迟一个周期即可reg a_en_d1 ;//reg a_en_d2 ;reg a_en_neg ;always@(posedge clk_a or posedge rst) beginif(rst) begina_en_d1 <= 1'd0;// a_en_d2 <= 1'd0;a_en_neg <= 1'd0;endelse begina_en_d1 <= a_en;// a_en_d2 <= a_en_d1;// a_en_neg <= ~a_en_d1 && a_en_d2;a_en_neg <= ~a_en && a_en_d1;endend//生成请求信号reg a_req ; wire a2_q_pos;always@(posedge clk_a or posedge rst) beginif(rst) a_req <= 1'd0;else if(a_en_neg)a_req <= 1'd1;else if(a2_q_pos) //a_req 拉低条件a_req <= 1'd0;else a_req <= a_req; end//请求信号a_req跨时钟域处理reg b1_q, b2_q;always@(posedge clk_b or posedge rst) beginif(rst) beginb1_q <= 1'd0;b2_q <= 1'd0;endelse beginb1_q <= a_req;b2_q <= b1_q;endend//生成时钟域b内的数据使能信号//b2_q信号的上升沿//b时钟域对a时钟域的响应信号reg b2_q_d1;reg b2_q_d2;reg b2_q_d3;reg ack_b;always@(posedge clk_b or posedge rst) beginif(rst) beginb2_q_d1 <= 1'd0;b2_q_d2 <= 1'd0;b2_q_d3 <= 1'd0;ack_b <= 1'd0; endelse beginb2_q_d1 <= b2_q;b2_q_d2 <= b2_q_d1;b2_q_d3 <= b2_q_d2;ack_b <= b2_q_d2;endendassign b_en = ~b2_q_d3 && b2_q_d2;//b_en有效,则表示数据有效,可以采样a时钟域的数据了always@(posedge clk_b or posedge rst) beginif(rst)data_b_out <= 4'd0;else if(b_en)data_b_out <= data_a_in;end//响应信号同步到a时钟域//a2_q上升沿作为a_req拉低的条件reg a1_q, a2_q;reg a3_q ;always@(posedge clk_a or posedge rst) beginif(rst) begina1_q <= 1'd0;a2_q <= 1'd0;a3_q <= 1'd0;endelse begina1_q <= ack_b;a2_q <= a1_q;a3_q <= a2_q;endendassign a2_q_pos = ~a3_q && a2_q;assign ack_a = a2_q; //此信号作为a_en的反馈信号,a_en取此信号的下降沿
endmodule
仿真文件
`timescale 1ns / 1ps
module tb_syn_handshake;reg clk_a ;reg clk_b ;reg rst ;reg a_en ; //来自于外部的使能信号,脉冲持续一个时钟周期reg [3:0] data_a_in ; //外部输入信号wire [3:0] data_b_out ;wire b_en ;wire ack_a ;initial beginclk_a = 1'd0;forever begin#2 clk_a = ~clk_a;endendinitial beginclk_b = 1'd0;forever begin#3 clk_b = ~clk_b;endendinitial beginrst = 1'd1;#15@(negedge clk_a);rst = 1'd0;endreg ack_a_d1;always@(posedge clk_a or posedge rst) beginif(rst) begina_en <= 1'd1;ack_a_d1 <= 1'd0;endelse beginack_a_d1 <= ack_a;a_en <= ~ack_a && ack_a_d1;endendalways@(posedge clk_a or posedge rst) beginif(rst) begindata_a_in <= 4'd0;endelse if(a_en) begindata_a_in <= $random;endendsyn_handshake u_syn_handshake(.clk_a ( clk_a ),.clk_b ( clk_b ),.rst ( rst ),.a_en ( a_en ),.data_a_in ( data_a_in ),.data_b_out ( data_b_out ),.b_en ( b_en ),.ack_a ( ack_a ));
endmodule
仿真结果
五、异步双口RAM
数字IC笔试基础:同步与异步双端口RAM实现
在FPGA设计中,经常会用到RAM,这里的RAM一般指的是静态的RAM(SRAM)。一般FPGA中就有所谓的block RAM, 它就是现成的RAM资源。通常情况下,我们使用IP核,进行设计,我们来设计自己的IP核。
RAM分为单端、伪双端、真双端三种模式。
- 单端RAM读写共享一个地址
- 伪双端RAM一个写端口,一个读端口,各自的地址和使能信号,写端口只负责写,读端口只负责读,所以称为伪双端
- 真双口RAM可以在任意时间访问任意地址,两个端口的地址是一样的,即共享内存和地址。这就会带来一个问题:同时读写一个地址会发生冲突。基于这个点矛盾就要设置限制条件
接下来,用Verilog实现一个异步双端口RAM,深度128,位宽16bit。A口写入,B口读出。支持片选,读写请求,要求代码可综合。
RTL代码
/*************************************************************************
实现一个异步双端口RAM,深度128,位宽16bit。A口写入,B口读出。支持片选,读写请求,要求代码可综合
*************************************************************************/
module Dual_Port_Sram #(parameter ADDR_WIDTH = 7, //地址位宽parameter DATA_WIDTH = 16, //数据位宽parameter DATA_DEPTH = 1 << ADDR_WIDTH //数据深度 = 2^ADDR_WIDTH
) (input clka ,input clkb ,input rst_n ,input csen_n , //片选信号,低有效
/*************Port A Signal Write********************************/input [ADDR_WIDTH-1:0] addra ,input [DATA_WIDTH-1:0] data_a ,input wrena_n ,
/*************Port B Signal Read********************************/input [ADDR_WIDTH-1:0] addrb ,input rdenb_n ,output [DATA_WIDTH-1:0] data_b
);
/************* A口写入逻辑 *********************************/
integer i;
reg [DATA_WIDTH-1:0] register[DATA_DEPTH-1:0]; //存储器定义
always @(posedge clka or negedge rst_n) beginif(!rst_n) beginfor(i = 0; i < DATA_DEPTH; i = i + 1)register[i] <= 0;endelse if(!wrena_n && !csen_n)register[addra] <= data_a;
end
/************* B口读出逻辑 *********************************/
reg [DATA_WIDTH-1:0] rddata_b;
always @(posedge clkb or negedge rst_n) beginif(!rst_n)rddata_b <= 1'b0;else if(!rdenb_n && !csen_n)rddata_b <= register[addrb];elserddata_b <= rddata_b;
end
assign data_b = rddata_b;
endmodule
仿真文件
`timescale 1ns/1ps
module tb_Dual_Port_Sram;parameter ADDR_WIDTH = 7; //地址位宽parameter DATA_WIDTH = 16; //数据位宽parameter DATA_DEPTH = 1 << ADDR_WIDTH; //数据深度 = 2^ADDR_WIDTHreg clka ;reg clkb ;reg rst_n ;reg csen_n ;reg [ADDR_WIDTH-1:0] addra ;reg [DATA_WIDTH-1:0] data_a ;reg wrena_n ;reg [ADDR_WIDTH-1:0] addrb ;reg rdenb_n ;wire [DATA_WIDTH-1:0] data_b ;Dual_Port_Sram #(.ADDR_WIDTH (ADDR_WIDTH),.DATA_WIDTH (DATA_WIDTH),.DATA_DEPTH (DATA_DEPTH))u_Dual_Port_Sram(.clka (clka ),.clkb (clkb ),.rst_n (rst_n ),.csen_n (csen_n ),.addra (addra ),.data_a (data_a ),.wrena_n (wrena_n),.addrb (addrb ),.rdenb_n (rdenb_n),.data_b (data_b )); initial beginclka = 1'd0;forever begin#2 clka = ~clka;endendinitial beginclkb = 1'd0;forever begin#3 clkb = ~clkb;endendinitial beginrst_n = 1'b0;csen_n = 1'b1;wrena_n = 1'b1;addra = 1'b0;data_a = 1'b0;rdenb_n = 1'b1;addrb = 1'b0;#50rst_n = 1'b1;csen_n = 1'b0;#10wrena_n = 1'b0;repeat (DATA_DEPTH-1) begin@(posedge clka) beginaddra = addra + 1;data_a = data_a + 1;endend#35wrena_n = 1'b1;rdenb_n = 1'b0;repeat (DATA_DEPTH-1) begin@(posedge clkb) beginaddrb = addrb + 1;endend#50rdenb_n = 1'b1;csen_n = 1'b1;#100 $stop;end
endmodule
仿真结果
总结
这是第一部分,可能也是面试中比较难的一部分,但应该也是常考的一部分。要仔细研究代码,电路图和时序图都要能够做到胸有成竹。
因为有一些东西是参考网上的,如果存在侵权,请告知,然后我删除或标注出来。
FPGA(五)RTL代码之一(跨时钟域设计)相关推荐
- (84)FPGA面试题-多bit跨时钟域
1.1 FPGA面试题-多bit跨时钟域 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)FPGA面试题-多bit跨时钟域: 5)结束语. 1.1.2 本节引言 &quo ...
- FPGA CDC跨时钟域设计学习(一)亚稳态
FPGA CDC跨时钟域设计学习(一) 亚稳态 MTBF - mean time before failure 同步器 理论 设计原则 学习资源主要来源于CummingsSNUG2008Boston_ ...
- 【Verilog】跨时钟域设计Clock Domain Crossing Design(Multi cycle path formulation with feedback acknowledge)
上次写了跨时钟域设计MCP公式不带反馈的实现[Verilog]跨时钟域设计Clock Domain Crossing (CDC) Design(MCP formulation without feed ...
- FPGA跨时钟域设计的一点总结
1. 亚稳态的概念说明 是指触发器无法在某个规定时间段内达到一个可确认的状态.当一个触发器进入亚稳态引时,既无法预测该单元的输出电平,也无法预测何时输出才能稳定在某个正确的电平上.在这个稳定期间,触发 ...
- 跨时钟域设计(结绳法,脉冲展宽法)
跨时钟域方法总结 https://www.docin.com/p-1715858862.html 异步FIFO https://blog.csdn.net/darknessdarkness/artic ...
- FPGA之道(48)跨时钟域问题
文章目录 前言 跨时钟域问题 什么是跨时钟域问题 解决跨时钟域问题的原理 两级采样法 为什么要对非本时钟域的信号用本时钟域的时钟进行采样呢? 为什么要采样两次呢? 握手法 对于时钟域A: 对于时钟域B ...
- 【 FPGA 】跨时钟域处理以及边沿检测
本文转载自:跨时钟域处理 题目:多时钟域设计中,如何处理跨时钟域 单bit:两级触发器同步(适用于慢到快) 多bit:采用异步FIFO,异步双口RAM 加握手信号 格雷码转换 题目:编写Verilog ...
- 异步fifo_数字IC校招基础知识点复习(五)——跨时钟域涉及part2(异步FIFO)
1.跨时钟域设计(CDC)-part 2 在上一篇中我们主要关注的是单比特的控制信号,而对于多比特信号的跨时钟域传输则需要一些其他的手段. 首先需要明确的是,一般不采用对多比特信号中的每个比特单独使用 ...
- CDC:跨时钟域处理
前言(还未整理好) CDC(clock domain crossing)检查(跨时钟域的检查)是对电路设计中同步电路设计的检查.非同步时钟没有固定的相位关系,这样Setup/Hold不满足而产生了亚稳 ...
最新文章
- curl抓取页面是乱码 php_php curl 获取网页内容 中文乱码
- mysql 多个if_mysql if else 多条件
- Android开发常用第三方平台
- spring boot测试_测试Spring Boot有条件的合理方式
- rman 脚本备份全过程
- Git1天打卡 day13-查看仓库文件改动状态
- Reduce归约 证明原理
- Python的逻辑操作
- 计算机c盘容易满怎么办,C盘快满了怎么办 如何清理C盘垃圾?
- html导出excel设置宽度,导出excel图片如何把大小控制
- 发卡网源码附企业发卡网源码搭建安装教程
- 怎么控制人物行走动画与移动
- 图片文字识别如何实现
- 君莫笑:小白的堆(bai_dui)
- 立秋了,愿天下人天寒心不寒,快快乐乐
- 吉他“和弦”是什么?
- 计算机会计与手工会计的区别与联系,会计电算化与手工会计的差异和共同点各是什么...
- VR虚拟展厅产品展示如何实现的
- 计算机用户删除怎么找回,电脑不小心删除的数据怎么找回
- Echarts制作态势图、热点图、轨迹图,使用百度底图,地图下钻
热门文章
- ​交易所攻占EOS超级节点
- 解决 为什么会出现 “Safari浏览器打不开该网页,因为地址无效“ 的提示
- C++ 二叉搜索树(补充)
- 《淘宝店铺营销推广一册通》一1.1 什么是网店推广
- 2020戴森设计大奖两项全球冠军揭晓
- music_悲催的键盘手
- [O2JAM劲乐团] 音乐集...
- mysql 读提交,MySQL如何实现ACID ?
- 如何使用Createjs来编写HTML5游戏(八) 通过继承扩展EaselJS中的基础元素
- Kaggle亚马逊比赛冠军专访:利用标签相关性来处理分类问题