题目背景
- 笔试时间:2022.06.22
- 应聘岗位:FPGA开发工程师
题目评价
- 难易程度:★★☆☆☆
- 知识覆盖:★☆☆☆☆
- 超纲范围:☆☆☆☆☆
- 值得一刷:★☆☆☆☆
文章目录
- 1. 使用最少的电路实现二分频,给出原理图。
- 2. 解释环形振荡器的构成和原理
- 3. 什么是建立时间和保持时间?
- 4. 建立时间和保持时间哪个和时钟速率有关?列出建立时间和保持时间违例的情况。
- 5. 详细给出建立时间和保持时间裕量的计算方法
- 6. 介绍FPGA SLICEL 的基本构成单元。
- 7. 不需要流水线。给出两种8bit a/b 的实现方法。
- 8. 介绍同步复位和异步复位的优缺点,写出异步复位同步释放的代码。
- 9. 分析如下电路可能产生的问题,解决?
- 10.统计1024个连续 8bit 输入数据的直方图,实时输出当前出现次数最多的数字。
1. 使用最少的电路实现二分频,给出原理图。
2. 解释环形振荡器的构成和原理
环形振荡器的构成:
奇数个反相器首尾连接而成。
环形振荡器的原理:
利用门电路的固有传输延迟。电路没有稳态,静态下(假定没有振荡时)任何一个反相器的输入和输出都不可能稳定在高电平或低电平,只能处于高低电平之间,处于放大状态。
3. 什么是建立时间和保持时间?
建立时间:有效时钟沿到来之前数据必须保持稳定的时间。
保持时间:有效时钟沿到来之后数据必须保持稳定的时间。
4. 建立时间和保持时间哪个和时钟速率有关?列出建立时间和保持时间违例的情况。
建立关系:与工作频率有关
t
l
a
u
n
c
h
+
t
c
l
k
2
q
+
t
l
o
g
i
c
+
t
s
e
t
u
p
<
t
c
a
p
t
u
r
e
+
t
c
y
c
l
e
t_{launch} + t_{clk2q} + t_{logic} + t_{setup}< t_{capture} + t_{cycle}
tlaunch+tclk2q+tlogic+tsetup<tcapture+tcycle
保持关系:
t
l
a
u
n
c
h
+
t
c
l
k
2
q
+
t
l
o
g
i
c
<
t
c
a
p
t
u
r
e
+
t
h
o
l
d
t_{launch} + t_{clk2q} + t_{logic} < t_{capture} + t_{hold}
tlaunch+tclk2q+tlogic<tcapture+thold
题目问法有点问题,理论上建立时间和保持时间都是时序器件固有属性,与时钟频率都无关,应该是想问建立关系和保持关系哪个和时钟速率有关。
建立时间违例的情况:从建立关系就可以推断
- 组合逻辑过于复杂,时延较大。
- 负时钟偏斜较大。
- 时钟频率过大。时序关系太严格。
- 工艺库较落后。
保持时间违例的情况:
- 正时间偏斜较大。
- 工艺库较落后。
5. 详细给出建立时间和保持时间裕量的计算方法
图片来源:《Static timing analysis for nanometer designs_ a practical approach》 Figure 8-2 Data and clock signals for setup timing check
对于max延迟分析(setup/recovery):
- 裕量 = 数据需要的时间 - 数据到达的时间
对于min延迟分析(hold/removal):
- 裕量 = 数据到达的时间 - 数据需要的时间
建立时间裕量:
(
t
c
a
p
t
u
r
e
+
t
c
y
c
l
e
−
t
s
e
t
u
p
)
−
(
t
l
a
u
n
c
h
+
t
c
l
k
2
q
+
t
l
o
g
i
c
)
(t_{capture} + t_{cycle} - t_{setup}) - (t_{launch} + t_{clk2q} + t_{logic} )
(tcapture+tcycle−tsetup)−(tlaunch+tclk2q+tlogic)
保持时间裕量:
(
t
c
a
p
t
u
r
e
+
t
h
o
l
d
)
−
(
t
l
a
u
n
c
h
+
t
c
l
k
2
q
+
t
l
o
g
i
c
)
(t_{capture} + t_{hold}) - (t_{launch} + t_{clk2q} + t_{logic})
(tcapture+thold)−(tlaunch+tclk2q+tlogic)
6. 介绍FPGA SLICEL 的基本构成单元。
参考:可配置逻辑块(configurable logic block,CLB)资源学习
SLiceL的基本构成单元:
- LUT6*4:每个LUT有六个独立的输入(A1-A6),两个独立的输出(O5-O6)。一个SLice中的四个LUT分别以A B C D编号。
- 多路选择器*3: 用于查找表的尾款拓展
- 进位链*1:时间超前进位逻辑。
- 触发器*8:每个slice有8个存储单元。四个可以配置为边沿触发D型触发器或电平敏感的锁存器。
7. 不需要流水线。给出两种8bit a/b 的实现方法。
参考:除法器的实现(恢复余数、不恢复余数、级数展开、Newton-Raphson)
8. 介绍同步复位和异步复位的优缺点,写出异步复位同步释放的代码。
复位类型 | 优点 | 缺点 |
---|---|---|
同步复位 | ①抗干扰性能强,可以剔除复位信号中周期短于时钟周期的毛刺。 | ①占用更多的逻辑资源。 |
②有利于STA工具分析。 | ②对复位信号脉宽有要求,必须大于时钟周期,很难保证复位信号到达各寄存器的时序。 | |
③有利于基于周期的仿真工具的仿真。 | ③复位信号依赖于时钟,如果电路时钟出现问题无法复位。 | |
异步复位 | ①无需额外逻辑资源,实现简单。可保证复位引脚到个寄存器始终偏斜最小。 | ①复位信号易受外界干扰,对毛刺敏感。 |
②复位信号不依赖于时钟。 | ②复位信号释放的随机性,产生时序违例导致电路处于亚稳态。 |
异步复位同步释放的代码:
reg R_rstn;
reg R1_rstn;
always @(posedge clk or negedge rstn)
begin
if(~rstn)
begin
R_rstn <= 1'b0;
R1_rstn <= 1'b0;
end
else
begin
R_rstn <= 1'b1;
R1_rstn <= R_rstn;
end
end
always @(posedge clk or negedge R1_rstn)
begin
if(~R1_rstn)
begin
// 用户逻辑
end
else
begin
// 用户逻辑
end
end
9. 分析如下电路可能产生的问题,解决?
类似多bit数据跨时钟域问题,可能会导致亚稳态或数据无法正确跨时钟域。
不能直接采样,需要加入对于处理电路,首先将多bit信号组合逻辑输出在CLK_a寄存一拍,然后进行单bit跨时钟域处理。
如果CLK_a比CLK_b慢,可以采用打两拍的方法。
如果CLK_a比CLK_b快,可以采用脉冲同步器或者握手处理。
10.统计1024个连续 8bit 输入数据的直方图,实时输出当前出现次数最多的数字。
题目没有限制要用尽量少的逻辑资源,简单的写法可以generate 256 个寄存器,来一个对应数据就加一,这样在实现上是比较简单的。如果考虑到综合实现,用一个ram来存比较合适。
实时输出当前出现次数最多的数字?这个有点难,意味着要持续完成256个出现次数的比较,并且还要得到最大次数对应的地址。
每帧数据输出最大值还差不多?T_T
这里只实现了直方图统计,比较简单
实现RTL:
`timescale 1ns/1ps
module histogram(
input clk ,
input rstn ,
input en_i ,
input [7:0] data_i
);
//--- internal signal definitions ---
//=== parameter definitions ===
//=== reg definitions ===
reg en_r ;
reg [7:0] data_r ;
reg en_r1 ;
reg [7:0] data_r1 ;
reg wr_en_r ;
reg [7:0] wr_addr_r;
reg [9:0] wr_din_r ;
reg rd_en_r ;
reg [7:0] rd_addr_r;
//=== wire definitions ===
wire [9:0] rd_dout_w;
//--- Main body of code ---
always @(posedge clk or negedge rstn)
begin
if(~rstn)
begin
en_r <= 1'd0;
data_r <= 8'd0;
en_r <= 1'd0;
data_r <= 8'd0;
end
else
begin
en_r <= en_i ;
data_r <= data_i;
en_r1 <= en_r ;
data_r1 <= data_r;
end
end
always @(posedge clk or negedge rstn)
begin
if(~rstn)
begin
rd_en_r <= 1'b0;
rd_addr_r <= 8'b0;
end
else
begin
rd_en_r <= en_i;
rd_addr_r <= data_i;
end
end
always @(posedge clk or negedge rstn)
begin
if(~rstn)
begin
wr_en_r <= 1'b0;
wr_addr_r <= 8'b0;
wr_din_r <= 10'b0;
end
else
begin
wr_en_r <= en_r1;
wr_addr_r <= data_r1;
wr_din_r <= rd_dout_w + 1'b1;
end
end
dpram dpram_u(
.clk (clk ),
.rstn (rstn ),
.wr_en (wr_en_r ),
.wr_addr(wr_addr_r),
.wr_din (wr_din_r ),
.rd_en (rd_en_r ),
.rd_addr(rd_addr_r),
.rd_dout(rd_dout_w)
);
endmodule
//只是模拟RAM,代码不可综合。
module dpram(
input clk,
input rstn,
input wr_en,
input [7:0] wr_addr,
input [9:0] wr_din,
input rd_en,
input [7:0] rd_addr,
output reg [9:0] rd_dout
);
reg [9:0] mem [0:255] ;
always @(posedge clk)
begin
if (wr_en)
begin
mem[wr_addr] <= wr_din;
end
end
always @(posedge clk)
begin
if (rd_en)
begin
rd_dout <= mem[rd_addr];
end
end
always @(negedge rstn) begin
if (~rstn)
begin
data_rst();
end
end
task data_rst();
begin:data_rst
integer i;
for (i = 0; i < 256; i = i + 1) begin
mem[i] = 0;
end
end
endtask
endmodule
testbench:
`timescale 1ns/1ps
module histogram_tb ();
parameter T = 10;
reg clk ;
reg rstn ;
reg en_i ;
reg [7:0] data_i;
initial begin
clk = 'd1;
rstn = 'd0;
en_i = 'd0;
data_i = 'd0;
#(T*10)
rstn = 'd1;
#(T*5)
data_gen();
$finish();
end
always #(T/2) clk <= ~clk;
task data_gen();
begin:data_gen
integer i;
for (i = 0; i < 1024; i = i + 1) begin
@(negedge clk);
en_i <= 'd1;
data_i <= {$random} % 256;
end
@(posedge clk);
en_i <= 'd0;
end
endtask
histogram histogram_u(
.clk (clk ),
.rstn (rstn ),
.en_i (en_i ),
.data_i(data_i)
);
endmodule
Modelsim脚本:
vlib work
vlog histogram.v histogram_tb.v
vsim -novopt work.histogram_tb