文章目录

  • 前言
  • 一、异步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. 设备1将 valid 信号置1,告诉设备2,数据准备就绪了,请查收
  2. 设备2此刻正处于忙碌状态无法接收数据,设备2将 ready 信号保持为0
  3. 设备2空闲了,将 ready 信号置1接收设备1的数据
  4. 设备1看到设备2的 ready 为1,它知道设备2已经接收好数据了,将 valid 置0同时撤销数据,准备下一次发送
  5. 可以看到因为有握手控制,可以确保数据的正确传输,不会丢失。跨时钟域的握手设计就是利用握手控制这种优势,从而避免因为跨时钟域引起的数据传输错误

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分为单端、伪双端、真双端三种模式。

  1. 单端RAM读写共享一个地址
  2. 伪双端RAM一个写端口,一个读端口,各自的地址和使能信号,写端口只负责写,读端口只负责读,所以称为伪双端
  3. 真双口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代码之一(跨时钟域设计)相关推荐

  1. (84)FPGA面试题-多bit跨时钟域

    1.1 FPGA面试题-多bit跨时钟域 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)FPGA面试题-多bit跨时钟域: 5)结束语. 1.1.2 本节引言 &quo ...

  2. FPGA CDC跨时钟域设计学习(一)亚稳态

    FPGA CDC跨时钟域设计学习(一) 亚稳态 MTBF - mean time before failure 同步器 理论 设计原则 学习资源主要来源于CummingsSNUG2008Boston_ ...

  3. 【Verilog】跨时钟域设计Clock Domain Crossing Design(Multi cycle path formulation with feedback acknowledge)

    上次写了跨时钟域设计MCP公式不带反馈的实现[Verilog]跨时钟域设计Clock Domain Crossing (CDC) Design(MCP formulation without feed ...

  4. FPGA跨时钟域设计的一点总结

    1. 亚稳态的概念说明 是指触发器无法在某个规定时间段内达到一个可确认的状态.当一个触发器进入亚稳态引时,既无法预测该单元的输出电平,也无法预测何时输出才能稳定在某个正确的电平上.在这个稳定期间,触发 ...

  5. 跨时钟域设计(结绳法,脉冲展宽法)

    跨时钟域方法总结 https://www.docin.com/p-1715858862.html 异步FIFO https://blog.csdn.net/darknessdarkness/artic ...

  6. FPGA之道(48)跨时钟域问题

    文章目录 前言 跨时钟域问题 什么是跨时钟域问题 解决跨时钟域问题的原理 两级采样法 为什么要对非本时钟域的信号用本时钟域的时钟进行采样呢? 为什么要采样两次呢? 握手法 对于时钟域A: 对于时钟域B ...

  7. 【 FPGA 】跨时钟域处理以及边沿检测

    本文转载自:跨时钟域处理 题目:多时钟域设计中,如何处理跨时钟域 单bit:两级触发器同步(适用于慢到快) 多bit:采用异步FIFO,异步双口RAM 加握手信号 格雷码转换 题目:编写Verilog ...

  8. 异步fifo_数字IC校招基础知识点复习(五)——跨时钟域涉及part2(异步FIFO)

    1.跨时钟域设计(CDC)-part 2 在上一篇中我们主要关注的是单比特的控制信号,而对于多比特信号的跨时钟域传输则需要一些其他的手段. 首先需要明确的是,一般不采用对多比特信号中的每个比特单独使用 ...

  9. CDC:跨时钟域处理

    前言(还未整理好) CDC(clock domain crossing)检查(跨时钟域的检查)是对电路设计中同步电路设计的检查.非同步时钟没有固定的相位关系,这样Setup/Hold不满足而产生了亚稳 ...

最新文章

  1. curl抓取页面是乱码 php_php curl 获取网页内容 中文乱码
  2. mysql 多个if_mysql if else 多条件
  3. Android开发常用第三方平台
  4. spring boot测试_测试Spring Boot有条件的合理方式
  5. rman 脚本备份全过程
  6. Git1天打卡 day13-查看仓库文件改动状态
  7. Reduce归约 证明原理
  8. Python的逻辑操作
  9. 计算机c盘容易满怎么办,C盘快满了怎么办 如何清理C盘垃圾?
  10. html导出excel设置宽度,导出excel图片如何把大小控制
  11. 发卡网源码附企业发卡网源码搭建安装教程
  12. 怎么控制人物行走动画与移动
  13. 图片文字识别如何实现
  14. 君莫笑:小白的堆(bai_dui)
  15. 立秋了,愿天下人天寒心不寒,快快乐乐
  16. 吉他“和弦”是什么?
  17. 计算机会计与手工会计的区别与联系,会计电算化与手工会计的差异和共同点各是什么...
  18. VR虚拟展厅产品展示如何实现的
  19. 计算机用户删除怎么找回,电脑不小心删除的数据怎么找回
  20. Echarts制作态势图、热点图、轨迹图,使用百度底图,地图下钻

热门文章

  1. ​交易所攻占EOS超级节点
  2. 解决 为什么会出现 “Safari浏览器打不开该网页,因为地址无效“ 的提示
  3. C++ 二叉搜索树(补充)
  4. 《淘宝店铺营销推广一册通》一1.1 什么是网店推广
  5. 2020戴森设计大奖两项全球冠军揭晓
  6. music_悲催的键盘手
  7. [O2JAM劲乐团] 音乐集...
  8. mysql 读提交,MySQL如何实现ACID ?
  9. 如何使用Createjs来编写HTML5游戏(八) 通过继承扩展EaselJS中的基础元素
  10. Kaggle亚马逊比赛冠军专访:利用标签相关性来处理分类问题