一个采集周期内如何读取寄存器的值里需要采集的数据没采集完会怎么样?采集时间不够用了,会延长采集时间直到采完吗?

面经1 自我介绍,三个项目 等待完善好文章合集面经1:知乎2 跨时钟域,输入输出要跨时钟,怎么做的CDC(Clock Domain Conversion)跨时钟域分单bit和多bit传输,其中:1. 单bit(慢时钟域到快时钟域):用快时钟打两拍,直接采一拍大概率也是没问题的,两拍的主要目的是消除亚稳态;其中:(1)为了更长的平均无故障时间 MTBF( Mean Time Between Failures),需要配合一个 ASYNC_REG 的约束,把用作简单同步器的多个寄存器放入同一个 SLICE,以降低走线延时的不一致和不确定性。ASYNC_REG属性通常应用在跨时钟域的数据同步上。4) 如果应用ASYNC_REG,放置器将确保同步链上的触发器紧密地放置在一起,以最大化MTBF。5) 假设被ASYNC_REG约束的寄存器有相同控制信号且寄存器总量不超过SLICE/CLB可用资源,则被约束的寄存器会放在单个SLICE/CLB中。(* ASYNC_REG = "TRUE" *) reg rst_reg_0;(* ASYNC_REG = "TRUE" *) reg rst_reg_1;(2)或者:直接在约束文件里进行约束set_property ASYNC_REG TRUE [get_cells [list rst_reg_0 rst_reg_1]] 2. 单bit(快时钟域到慢时钟域):握手(脉冲展宽)、异步FIFO、异步双口RAM;快时钟域的信号脉宽较窄,慢时钟域不一定能采到,可以通过握手机制让窄脉冲展宽,慢时钟域采集到信号后再“告诉”快时钟域已经采集到信号,确保能采集到;对于异步时钟,通常会使用set_clock_groups、set_false_path做时序约束,使得不对跨异步时钟做时序分析。这样做可以缩短综合编译时间,且将宝贵的片内资源用在其他必要的时序约束上。set_clock_groups 将不会对不同group的时钟做时序分析,对同一group的时钟不受影响。不同于set_false_path约束,set_false_path是有方向的(-from -to 只能做单方向的时序约束),set_clock_groups 将会对-group的不同group的时钟双向约束。3. 多bit跨时钟域:异步FIFO、异步双口RAM、握手、格雷码;(1)使用异步FIFO的IP 实际上是用 FPGA 内部的 BRAM 来搭建,所有的控制逻辑都在 BRAM 内部,是推荐的 FIFO 实现方式。
时序约束简单,进行时序例外约束,只需要 set_clock_groups 将读写时钟约束为异步时钟组即可,简单高效。set_property -asynchronous
-group [get_clocks write_clock] \(2)自己写外部控制逻辑的FIFO 格雷码做异步 FIFO 的跨时钟域处理,计数器和读写控制逻辑在 BRAM 或者 RAM 的外部,除了代码的合理设计以外,还需要进行额外的时序例外约束,不能简单使用 set_clock_groups 约束异步时钟组,还需要考虑外部的读写逻辑的约束。Xilinx建议这里设置set_max_delay来约束跨时钟域路径,约束的原则是:最大路径延时等于或者略小于目的时钟的一个周期。
写逻辑从cell1到cell2的约束中,cell2的驱动时钟周期为5,如下所示,读逻辑约束进行相应约束。set_max_delay 5 –from [get_cells cell1] –to [get_cells cell2] –datapath_only 多bit中,强烈推荐使用异步FIFO的IP来实现,我在实际工程中使用多次,简单方便。1.什么是同步时钟?两个时钟之间的相位关系是固定的。一般这种情况下,这两个时钟具有相同的源时钟。比如一个主时钟和一个被2分频的生成时钟。生成时钟一般是通过PLL、CMT等生成。2.什么是异步时钟?两个时钟无法明确其相位关系。比如两个时钟通过两个晶振产生,这种情况下,这两个时钟的相位关系是不确定的。————————————————版权声明:本文为CSDN博主「cigarliang1」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:3 序列检测解法1:Moore状态机`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 03/18/2022 11:02:33 AM
// Design Name:
// Module Name: sequence_y
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module sequence_y(
input clk,
input reset,
input seque,
output out
);
reg [2:0] state, next;
parameter [2:0] idle=3'd0, s1=3'd1, s2=3'd2, s3=3'd3, s4=3'd4;
always @ (*) begin
case(state)
idle: next = seque ? s1 : idle;
s1: next = seque ? s2 : idle;
s2: next = seque ? s2 : s3;
s3: next = seque ? s4 : idle;
s4: next = seque ? s2 : idle;
endcase
end
always @ (posedge clk) begin
if(reset)
state <= idle;
else
state <= next;
end
assign out = (state == s4);
endmodule
对应tb`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 03/18/2022 11:02:33 AM
// Design Name:
// Module Name: sequence_y
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module sequence_y(
input clk,
input reset,
input seque,
output out
);
reg [2:0] state, next;
parameter [2:0] idle=3'd0, s1=3'd1, s2=3'd2, s3=3'd3, s4=3'd4;
always @ (*) begin
case(state)
idle: next = seque ? s1 : idle;
s1: next = seque ? s2 : idle;
s2: next = seque ? s2 : s3;
s3: next = seque ? s4 : idle;
s4: next = seque ? s2 : idle;
endcase
end
always @ (posedge clk) begin
if(reset)
state <= idle;
else
state <= next;
end
assign out = (state == s4);
endmodule
即刻就检测到1101,没有再打一拍。因为输出时采用组合逻辑,没有采用时序逻辑,解法2:输出也采用时序逻辑,实现了打一拍`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 03/18/2022 11:02:33 AM
// Design Name:
// Module Name: sequence_y
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module sequence_y(
input clk,
input reset,
input seque,
output
reg out
);
reg [2:0] state, next;
parameter [2:0] idle=3'd0, s1=3'd1, s2=3'd2, s3=3'd3, s4=3'd4;
always @ (*) begin
case(state)
idle: next = seque ? s1 : idle;
s1: next = seque ? s2 : idle;
s2: next = seque ? s2 : s3;
s3: next = seque ? s4 : idle;
s4: next = seque ? s2 : idle;
endcase
end
always @ (posedge clk) begin
if(reset)
state <= idle;
else
state <= next;
end
//
assign out = (state == s4);
always @ (posedge clk) begin
if(reset)
out <= 1'b0;
else
out <= (state == s4);
end
endmodule
4 讲一下AXI-FULL协议,怎么用的,为什么内部用自己的协议,仲裁怎么做的? axi协议和仲裁5 基本上只要你简历里重点提到的和自我介绍讲的还有他感兴趣的.面经2:牛客1 系统中的CDC(跨时钟域)是怎么处理的,你还了解其他的处理方式吗,项目中异步FIFO的深度怎么确定的?CDC总结的非常好,仔细看:异步FIFO最小深度连续的两个10等于20简单的算术题,算对了,yep2
提到了布线拥塞,问什么会导致布线拥塞?拥塞介绍在芯片设计或者FPGA设计中,硬件资源可分为逻辑资源和布线资源,当我们的设计工程较大或较复杂时,可能逻辑资源仍然在合理范围内,但是布线资源却超出固有资源或者较为不合理。这时候可能会产生congestion(拥塞)问题,也就是布线资源紧张导致的。影响串扰:在数字芯片设计中,如果拥塞问题严重,会使信号线拥挤,从而产生串扰噪声。但本文想探讨的是另一个重要影响,时序收敛。时序收敛困难时序收敛是芯片后端或者FPGA设计中常见的问题,包括建立时间违例和保持时间违例。简单的时序收敛问题,比如逻辑级数过高或者组合逻辑过长,我们可以通过插入寄存器的方式来解决。或者一些跨时钟路径如果我们不关心,比如说一些寄存器输入数据,变化很缓慢甚至我们只需要最后时段采集到正确值,那么我们可以将该路径设为假路径(set false path),也可以用端口时序约束的方式,来让对应寄存器输入或输出端口的时序更为宽松。这样后端工具不会浪费过多精力和算法来优化此端口,使其更多的精力放在其他关键路径上。除了插寄存器和时序约束之外,我们还可以设置物理约束,比如对某些逻辑功能模块划一块面积,来手动约束我们的逻辑,比如画PBlock。但是,根本的时序收敛原则应该是,首先更改设计代码和增加合理的时序约束,如果代码没有可改的前提下,再考虑物理约束。产生原因布线资源使用过多的主要原因是信号扇出(fanout)过多,或者是使用了过多的LUT,或者是局部资源集中导致局部拥塞等等。解决方法1、减少或控制扇出无时钟控制信号还有高扇出的容易产生拥塞,所以可以将LUT扇出改为寄存器扇出,寄存器扇出能力较强且vivado会自动复制。如果不考虑延迟也可以设置全局缓存(BUFG),或者设置reg信号最大扇出,用下面的代码指令:控制信号复位,数据信号尽量避免复位。由于复位信号天生具有扇出大的特性,所以数据信号可以不复位,用准确的控制信号控制数据正确传输。如果是芯片设计则要考虑动态功耗,那么可以加适当的clock gating。但是在FPGA设计中,功耗不是重要问题,所以可以少用clock gating,减少使能信号的扇出和逻辑复杂度。2、时序约束如果某些路径时序约束不合理或者无约束,可以适当增加端口约束或者设计假路径,来放宽约束。3、资源平衡如果资源使用过多,比如Block ram,DSP,LUT等等,达到80%使用率,则要考虑进行资源平衡,尤其是LUT资源,其对时序影响更大,对布线资源要求更多。所以假设我们在实际设计中,用了较多的LUT ram,可以考虑将一些平衡到Block ram。4、策略与技巧如果前面的方法试过了,可以考虑策略与技巧。比如可以在implementation设置中勾选phys_opt_design步骤,增加优化。在Tools Options -> Strategies选择-Explore或者SpreadLogic_high/medium/low的策略。减少或取消综合阶段的查找表整合(LUT combining),输入(-no_lc),通过增加LUT资源使用但是减少CLB(可编程逻辑块)中LUT的输入来减少拥塞。物理约束,画pblock,如果局部拥塞可以画大pblock,或者将一部分逻辑画到另一块位置。3
什么是关键路径,怎么处理关键路径;1. 组合逻辑中插入寄存器(插入流水线)组合逻辑的延时过长,就会成为关键路径,这时可以考虑在该路径上插入额外的寄存器,这种方法也称为插入流水线,多用于高度流水的设计中,因为这种设计中额外插入寄存器增加的时钟周期延时并不会违反整个设计的规范要求,从而不会影响设计的总体功能性实现,也即额外插入的寄存器在保持吞吐量不变的情况下改善了设计的时序性能。当然,其不可避免地会带来部分面积的增加,如图6-11所示。在插入寄存器时,要在组合逻辑中选择合适的位置进行插入,使得插入寄存器后被分割出的几块小的组合逻辑延时基本一致,也相当于下图所示的先加入寄存器,再对寄存器进行重定时Retiming。2. 寄存器平衡(重定时Retiming)在不增加寄存器个数的前提下,通过改变寄存器的位置来优化关键路径,可以对比和流水线插入寄存器的不同。3. 操作符平衡(加法树、乘法树) 平衡前,a和b均经过3个乘法器带来的延时,c经历2个,d经历1个,最长延时为3个乘法器延时。平衡后,树形结构,a、b、c、d均经历2个乘法器延时,最长延时为2个乘法器延时。4. 消除代码优先级(case代替if…else)本身确实不需要优先级的地方,可以使用case代替if…else,使得顺序执行的语句编程并行执行。如果确实有优先级兵,则不能这样做。这种消除代码中的优先级的策略也称为代码结构平坦化技术,主要针对那些带优先级的编码结构。5. 逻辑复制当某个信号的扇出fanout比较大时,会造成该信号到各个目的逻辑节点的路径变得过长,从而成为设计中的关键路径,此时可以通过对该信号进行复制来降低扇出。高扇出的危害是大大增加了布局布线的难度,这样其扇出的节点也就无法被布局得彼此靠近,所以就导致了布线长度过大的问题。6. 关键信号后移关键输入应该在逻辑最后一级提供,其中关键输入为芯片、Slice、或者LUT提供的时延最大的输入,比如在if…else if…链中,将关键信号放在第一级。4 手撕代码(1)异步FIFO,同一作者,同步和异步代码差异挺大的。异步FIFO,记住游戏那些模块,读写两个控制模块,和两个时钟同步模块,和一个FIFOmemory模块,一共五个模块。写控制端用于判断是否可以写入数据读控制端用于判断是否可以读取数据FIFO Memory用于存储数据两个时钟同步端用于将读写时钟进行同步处理刚才说过,读/写控制端用于判断能否写入/读取数据,判断能否写入/读取数据关键在于:写操作时,写使能有效且FIFO未满读操作时,读使能有效且FIFO未空因此两个使能信号和空满判断信号都连接到控制端上最后我们再加上时钟信号和复位信号(2) 同步FIFO同步FIFO写代码时出现的问题:一些异步信号的细节比如判断复位时empty full信号怎么赋值忘记了?1:fifo_full怎么判断?有几位不一样?2:判断fifo_empty 或者 full时复位应该是对应信号置零吧?错误代码1:1 reg [$clog2(Width):0] wr_ptr, rd_ptr;应该考根据深度来算读写指针位宽`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 03/18/2022 10:23:21 PM
// Design Name:
// Module Name: fifo_tong
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module fifo_tong #(
parameter Depth=8,
parameter Width=8
)
(
input clk,
input rstn,
input wr_en,
input [Width-1:0] wr_data,
input rd_en,
output reg [Width-1:0] rd_data,
output reg fifo_empty,
output reg fifo_full
);
//dingyi read write ptr
reg [$clog2(Width):0] wr_ptr, rd_ptr;
// define fifo
reg [Width-1:0] fifo[Depth-1:0];
//write data
always @ (posedge clk, negedge rstn) begin
if(!rstn) begin
wr_ptr <= 0;
end
else if(wr_en && !fifo_full) begin
fifo[wr_ptr] <= wr_data;
wr_ptr <= wr_ptr + 1;
end
else
wr_ptr <= wr_ptr;
end
// read data
always @ (posedge clk, negedge rstn) begin
if(!rstn) begin
rd_ptr <= 0;
rd_data <= 0;
end
else if(rd_en && !fifo_empty) begin
rd_data <= fifo[rd_ptr];
rd_ptr <= rd_ptr + 1;
end
else
rd_ptr <= rd_ptr;
end
//judge fifo_empty
always @ (posedge clk, negedge rstn) begin
if(!rstn) begin
fifo_empty <= 1'b0;
end
else if(rd_ptr == wr_ptr) begin
fifo_empty <= 1'b1;
end
else
fifo_empty <= 1'b0;
end
//judge fifo_full
always @ (posedge clk, negedge rstn) begin
if(!rstn) begin
fifo_full <= 1'b0;
end
else if((rd_ptr[$clog2(Width)] != wr_ptr[$clog2(Width)]) && (rd_ptr[$clog2(Width)-1:0] == wr_ptr[$clog2(Width)-1:0])) begin
fifo_full <= 1'b1;
end
else
fifo_full <= 1'b0;
end
endmodule
正确代码:看了波形图,好像没啥问题啊`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 03/18/2022 10:23:21 PM
// Design Name:
// Module Name: fifo_tong
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module fifo_tong #(
parameter Depth=8,
parameter Width=8
)
(
input clk,
input rstn,
input wr_en,
input [Width-1:0] wr_data,
input rd_en,
output reg [Width-1:0] rd_data,
output reg fifo_empty,
output reg fifo_full
);
//dingyi read write ptr from depth
reg [$clog2(Depth):0] wr_ptr, rd_ptr;
// define fifo
reg [Width-1:0] fifo[Depth-1:0];
//write data
always @ (posedge clk, negedge rstn) begin
if(!rstn) begin
wr_ptr <= 0;
end
else if(wr_en && !fifo_full) begin
fifo[wr_ptr] <= wr_data;
wr_ptr <= wr_ptr + 1;
end
else
wr_ptr <= wr_ptr;
end
// read data
always @ (posedge clk, negedge rstn) begin
if(!rstn) begin
rd_ptr <= 0;
rd_data <= 0;
end
else if(rd_en && !fifo_empty) begin
rd_data <= fifo[rd_ptr];
rd_ptr <= rd_ptr + 1;
end
else
rd_ptr <= rd_ptr;
end
//judge fifo_empty
always @ (posedge clk, negedge rstn) begin
if(!rstn) begin
fifo_empty <= 1'b0;
end
else if(rd_ptr == wr_ptr) begin
fifo_empty <= 1'b1;
end
else
fifo_empty <= 1'b0;
end
//judge fifo_full
always @ (posedge clk, negedge rstn) begin
if(!rstn) begin
fifo_full <= 1'b0;
end
else if((rd_ptr[$clog2(Width)] != wr_ptr[$clog2(Width)]) && (rd_ptr[$clog2(Width)-1:0] == wr_ptr[$clog2(Width)-1:0])) begin
fifo_full <= 1'b1;
end
else
fifo_full <= 1'b0;
end
endmodule
对应tb:`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 03/18/2022 10:23:21 PM
// Design Name:
// Module Name: fifo_tong
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module fifo_tong #(
parameter Depth=8,
parameter Width=8
)
(
input clk,
input rstn,
input wr_en,
input [Width-1:0] wr_data,
input rd_en,
output reg [Width-1:0] rd_data,
output reg fifo_empty,
output reg fifo_full
);
//dingyi read write ptr from depth
reg [$clog2(Depth):0] wr_ptr, rd_ptr;
// define fifo
reg [Width-1:0] fifo[Depth-1:0];
//write data
always @ (posedge clk, negedge rstn) begin
if(!rstn) begin
wr_ptr <= 0;
end
else if(wr_en && !fifo_full) begin
fifo[wr_ptr] <= wr_data;
wr_ptr <= wr_ptr + 1;
end
else
wr_ptr <= wr_ptr;
end
// read data
always @ (posedge clk, negedge rstn) begin
if(!rstn) begin
rd_ptr <= 0;
rd_data <= 0;
end
else if(rd_en && !fifo_empty) begin
rd_data <= fifo[rd_ptr];
rd_ptr <= rd_ptr + 1;
end
else
rd_ptr <= rd_ptr;
end
//judge fifo_empty
always @ (posedge clk, negedge rstn) begin
if(!rstn) begin
fifo_empty <= 1'b0;
end
else if(rd_ptr == wr_ptr) begin
fifo_empty <= 1'b1;
end
else
fifo_empty <= 1'b0;
end
//judge fifo_full
always @ (posedge clk, negedge rstn) begin
if(!rstn) begin
fifo_full <= 1'b0;
end
else if((rd_ptr[$clog2(Width)] != wr_ptr[$clog2(Width)]) && (rd_ptr[$clog2(Width)-1:0] == wr_ptr[$clog2(Width)-1:0])) begin
fifo_full <= 1'b1;
end
else
fifo_full <= 1'b0;
end
endmodule
(2) 序列检测;前面代码已经给出

我要回帖

更多关于 如何读取寄存器的值 的文章