FPGA/IC 秋招笔试/面试题总结
Posted Crazzy_M
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FPGA/IC 秋招笔试/面试题总结相关的知识,希望对你有一定的参考价值。
持续更新,请根据目录浏览,觉得有用三连支持一下也是一种鼓励~。
文章目录
- 一、FPGA内部资源
- 二、同步时钟、同步/异步电路
- 三、同步复位/异步复位
- 四、同步FIFO/异步FIFO
- 五、FIFO最小深度计算
- 六、逻辑电平
- 七、建立时间与保持时间
- 八、recovery time和removal time
- 九、亚稳态
- 十、竞争与冒险
- 十一、 奇数分频
- 十二、 时钟抖动(Clock Jitter)和时钟偏斜(Clock Skew)
- 十三、Verilog的结构化、数据流、行为级描述方式
- 十四、函数(function)和任务(task)
- 十五、波特率
- 十六、锁存器/触发器
- 十七、组合逻辑/时序逻辑
- 十八、阻塞/非阻塞赋值
- 十九、跨时钟域处理
- 二十、位宽计算(N bit数和M bit数相加、相乘后需要多少bit?)
- 二十一 、IIC
- 二十二、SPI
- 二十三、 AXI
- 二十四、RAM/SRAM/DRAM/SDRAM/DDR
- 二十五、ROM/PROM/EPROM/E2PROM/FLASH
- 二十六、硬核/软核/固核
- 二十七、浮点数与定点数
一、FPGA内部资源
1. 什么是FPGA
FPGA是一种可以重构电路的芯片,是一种硬件可重构的体系结构。Field Programmable Gate Array,中文名是 现场可编程门阵列。通过编程,用户可以随时改变它的应用场景,它可以模拟CPU、GPU等硬件的各种并行运算。通过与目标硬件的高速接口互联,FPGA可以完成目标硬件运行效率比较低的部分,从而在系统层面实现加速。
2.FPGA内部资源
目前主流的FPGA都采用了SRAM工艺的查找表(LUT)结构,LUT本质上就是个RAM。FPGA内部组成主要有:可编程输入/输出块(IOB)、可配置逻辑块(CLB)、嵌入式块RAM(BRAM)、丰富的布线资源、底层内嵌功能资源、内嵌专用硬核资源等。
1、可编程输入/输出块(IOB):为了便于管理和适应多种电气标准,FPGA的IOB被划分为若干个组(bank),每个bank的接口标准由由其接口电压VCCO决定,一个bank只能有一种VCCO,但是不同的bank的VCCO可以不同。只有相同标准的端口才能连接在一起,VCCO电压相同是接口标准的基本条件。
2、可配置逻辑块(CLB):由查找表和可编程寄存器组成,查找表(LUT)完成纯组合逻辑,内部寄存器可配置成触发器或者锁存器。在Xilinx公司的FPGA器件中,CLB由多个(一般为4个或2个) 相同的Slice和附加逻辑构成。每个CLB模块不仅可以用于实现组合逻辑、时序逻辑,还可以配置为分布式RAM和分布式ROM。
Slice:Slice是Xilinx公司定义的基本逻辑单位,,一个Slice由两个4输入的函数、进位 逻辑、算术逻辑、存储逻辑和函数复用器组成。算术逻辑包括一个异或门(XORG)和一个专用与门(MULTAND),一个异或门可以使一个Slice实现 2bit全加操作,专用与门用于提高乘法器的效率;进位逻辑由专用进位信号和函数复用器(MUXC)组成,用于实现快速的算术加减法操作;4输入函数发生 器用于实现4输入LUT、分布式RAM或16比特移位寄存器(Virtex-5系列芯片的Slice中的两个输入函数为6输入,可以实现6输入LUT或 64比特移位寄存器)(根据不同型号去看);进位逻辑包括两条快速进位链,用于提高CLB模块的处理速度。
上图中左边为SliceM ,右边为 SliceL 。
SliceM 相比 SliceL 多出的功能在于可以配置成 Distribute RAM(分布式RAM)。
SliceM 相比 SliceL 多了做存储器和移位的功能。
SliceM 相比 SliceL 中含有能够把LUT资源重新整合为RAM和ROM的逻辑。
LUT:目前FPGA中多使用4输入的LUT,所以每一个LUT可以看成一个有 4位地址线的16x1的RAM。 当用户通过原理图或HDL语言描述了一个逻辑电路以后,FPGA开发软件会自动计算逻辑电路的所有可能的结果,并把结果事先写入RAM,这样,每输入一个信号进行逻辑运算就等于输入一个地址进行查表,找出地址对应的内容,然后输出即可。
分布式RAM(DRAM):查找表存储器
只有成为SLICEM的逻辑块里的查找表(LUT)才可以用做分布式RAM。
利用查找表为电路实现存储器,既可以实现芯片内部存储,又能提高资源利用率。分布式RAM的特点是可以实现BRAM不能实现的异步访问。 不过使用分布式RAM实现大规模的存储器会占用大量的LUT,可用来实现逻辑的查找表就会减少。因此建议仅在需要小规模存储器时,使用这种分布式RAM。
3、嵌入式块RAM:可配置成单端口RAM、双端口RAM、内容地址存储器(CAM)以及FIFO的常用的存储结构。RAM资源使用详解
Block RAM都有两套访问存储器所需的地址总线、数据总线及控制信号灯信号,因此其既可以作为单端口存储器,也可以作为双端口存储器。需要注意的时访问BRAM需要和时钟同步,异步访问不支持的。
单口RAM(Single Port RAM):只有一组数据线和地址线,因此读写不能同时进行。
伪双口RAM(Simple Dual Port RAM):一个端口只读,另一个端口只写。
双口RAM(True Dual Port RAM):两个端口都可以读写。
RAM构成:
比如在7系列的Xilinx器件中,每个36Kb的RAM由两个18Kb的RAM组成,每个BRAM有36Kbit的容量,既可以作为一个36Kbit的存储器使用,也可以拆分为两个独立的18Kbit存储器使用。反过来相邻两个BRAM可以结合起来实现72Kbit存储器,而且不消耗额外的逻辑资源。
RAM资源使用:
在器件选择的时候我们可以看到使用器件的资源详细信息,比如XCKU040这款拥有600个RAM块。
总容量:600×36Kb=21600Kb=21.1Mb。
我们例化一个RAM,看看资源占用情况:
数据深度:20480
宽度:18
占用BRAM内存:20480×18=20×18 Kbit=10×36 Kbit
通过以上的分析正好为10个36Kbit,应该占用10个36Kb的BRAM即10个BRAM。
调用ILA也是会消耗BRAM的资源的
ila IP配置如下
ila数据总宽度:55
ila数据深度:1024
55*1024=56320=55Kbits
需要BRAM 至少55/36=1.52→2个(往上取整)。
4、丰富的布线资源:布线资源连通FPGA内部的所有单元。而连线的长度和工艺决定信号在连线上的驱动能力和传输速度。主要分为四类:全局布线资源、长线资源、短线资源、分布式布线资源。FPGA中的布局布线资源主要包括三部分:CB、SB和行列连线。布线资源的目的是为了能够让位于不同位置的逻辑资源块、时钟处理单元、BRAM、DSP和接口模块等资源能够相互通信,从而协调合作,完成所需功能。FPGA中的布线资源,就好比绘制PCB板时的连线资源一样,虽然器件A和器件B的位置和连接关系没有任何改变,但很可能因为周边电路的布局、布线的一些变化,使得前后两次A、B之间的连线形态发生很大的变化。因此,与采用固定长度的金属线将所有宏单元连接在一起的CPLD不同,FPGA中任意两点之间的线延迟是无法预测的,必须等到布局、布线完成之后才能确定。这也是为什么在FPGA的开发中,时序约束和时序分析这两样工作是必不可少的。
5、底层内嵌的功能单元:主要包括DLL、PLL、DSP、CPU等,现在越来越丰富的内嵌功能单元,使得FPGA称为了系统级的设计工具,时其具备了软硬件联合设计的能力。
PLL:
PLL的英文全称是Phase Locked Loop,即锁相环,是一种反馈控制电路。
锁相环作为一种反馈控制电路,其特点是利用外部输入的参考信号控制环路内部震荡信号的频率和相位。因为锁相环可以实现输出信号频率对输入信号频率的自动跟踪,所以锁相环通常用于闭环跟踪电路。锁相环在工作的过程中,当输出信号的频率与输入信号的频率相等时,输出电压与输入电压保持固定的相位差值,即输出电压与输入电压的相位被锁住,这就是锁相环名称的由来。
6、内嵌专用的硬核资源:内嵌的专用硬核是相对底层软核而言的,指FPGA处理能力强大的硬核,等效于ASIC电路。主要有乘法器、高速收发器、PCIe、以太网控制器等。
二、同步时钟、同步/异步电路
1.同步时钟
当两个时钟的相位关系是固定关系,则可以称这个时钟为同步时钟(synchronous clock),经过一个PLL产生相位不同,但是相位固定的两个时钟,他们依旧是同步时钟。而如果是两个晶振产生的时钟,因为两个晶振在上电时相位差是随机的,而且不同晶振时钟漂移抖动也不一样,所以相位是不固定的。当无法判断两个时钟间的相位时,则可以称这两个时钟为异步时钟(asynchronous clocks)。
2.同步/异步电路
异步电路:
a) 电路核心逻辑是用组合电路实现;
b) 异步时序电路的最大缺点是容易产生毛刺;
c) 不利于器件移植;
d) 不利于静态时序分析(STA)、验证设计时序性能。
同步时序电路:
a) 电路核心逻辑是用各种触发器实现;
b) 电路主要信号、输出信号等都是在某个时钟沿驱动触发器产生的;
c) 同步时序电路可以很好的避免毛刺;
d) 利于器件移植;
e) 利于静态时序分析(STA)、验证设计时序性能。
三、同步复位/异步复位
1.同步复位
同步复位只有在时钟沿到来时复位信号才起作用,则复位信号持续的时间应该超过一个时钟周期才能保持系统复位。
同步复位代码:
//同步复位
module top
(
input clk,
input rst_n,
input a,
output reg b
);
always@(posedge clk)
begin
if(!rst_n)
b <= 1'b0;
else
b <= a;
end
endmodule
同步复位RTL视图:
同步复位优点: 一般能够保证电路百分百同步。确保复位只发生在有效沿,可以作为过滤掉毛刺的手段
同步复位的缺点: 复位信号的有效时长必须大于时钟周期,才能真正被系统识别并完成复位。同时还要考虑如:时钟偏斜、组合逻辑路径延时、复位延时等因素。由于大多数的厂商目标库内的触发器都只有异步复位端口,采用同步复位的话,就会耗费较多的逻辑资源。
2. 异步复位
只要有复位信号系统马上复位,因此异步复位抗干扰能力差,有些噪声也能使系统复位,因此有时候闲的不够稳定,要想设计一个好的复位最好使用异步复位同步释放。
异步复位代码:
//异步复位
module top
(
input clk,
input rst_n,
input a,
output reg b
);
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
b <= 1'b0;
else
b <= a;
end
endmodule
异步复位RTL视图:
异步复位优点:异步复位信号识别方便,而且可以很方便的使用全局复位。由于大多数的厂商目标库内的触发器都有异步复位端口(CLR)(在这个端口一般接低电平有效的复位信号rst_n,即使设计中是高电平复位,实际综合后也会把异步复位信号反向后接到CLR端)可以节约逻辑资源。
异步复位缺点:复位信号容易受到毛刺的影响。复位结束时刻恰在亚稳态窗口内时,无法决定现在的复位状态是1还是0,会导致亚稳态。
通过一下实例分析异步复位存在的隐患:
//异步复位存在的隐患实例
module top
(
input clk,
input rst_n,
input a,
output reg b,
output reg c
);
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
b <= 1'b0;
else
b <= a;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
c <= 1'b0;
else
c <= b;
end
endmodule
正常情况下,在clk 的上升沿将c的值更新为b,b的值更新为a。一但进入复位,b,c都清零,但是并不能确定复位信号rst_n会在什么时候结束。
涉及到 建立时间和保持时间 参考博客:建立时间和保持时间
如果结束于b_reg和c_reg的{latch edge-setup,latch edge+hold time}时间之外,那么一切都会正常。如果出现在之内,复位信号的撤销(由低变高)出现在clk锁存数据的建立时间或者保持时间之内,此时clk检测到rst_n的状态就会是一个亚稳态(不确定是0还是1),就会导致输出数据的错误。
也有可能一个reg处于复位,另一个reg跳出了复位,均会影响系统的正常工作,如果更大的项目隐患就更大了。
3. 异步复位同步释放
使用异步复位同步释放就可以消除上述缺点。所谓异步复位,同步释放就是在复位信号到来的时候不受时钟信号的同步,而是在复位信号释放的时候受到时钟信号的同步,为了消除亚稳态的产生,利用两个同一时钟沿触发的层叠寄存器,将异步信号同步化。
//异步复位、同步释放
module top
(
input clk,
input rst_n,
input a,
output reg b
);
reg rst_n_r;
reg rst_n_rr;
always@(posedge clk)
begin
{rst_n_rr,rst_n_r} <= {rst_n_r,rst_n};
end
always@(posedge clk or negedge rst_n_rr)
begin
if(!rst_n_rr)
b <= 1'b0;
else
b <= a;
end
endmodule
四、同步FIFO/异步FIFO
FIFO本质上还是RAM,是一种先进先出的数据缓存器(先存入的数据先取出)。它与普通存储器的区别:没有外部读写地址线,只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1,不像其他存储器可以由地址线决定读取或写入某个指定的地址,异步FIFO读写时钟不同,读写是相互独立的。
一般用途:
(1)跨时钟域多bit传输:读写可以由不同的时钟控制,使用异步FIFO可以在两个不同时钟系统之间快速方便的传输数据。
(2)数据匹配:对于不同宽度的数据接口可以使用FIFO,比如写入数据宽度为8bit,读取数据宽度为16bit,通过FIFO数据缓存器就可以达到数据匹配。
1.同步FIFO
同步FIFO的写时钟和读时钟为同一个时钟,FIFO内部所有逻辑都是同步逻辑,常常用于交互数据缓冲。
FIFO空、满信号的检测:
在设计FIFO时最重要的就是空满信号的检测,FIFO的主要是通过空(empty)信号、满信号(full)来控制数据的读写的,如果FIFO为空还读取数据势必会出现数据的错误,FIFO已满再写数据就会导致FIFO溢出同样会导致数据出错。那FIFO的空、满信号是怎么产生的呢。首先我们要明白读写FIFO的时候我们不用操作读写地址,但是我们在写入数据或者读出数据时FIFO内部会通过写入或读出数据的操作在内部进行地址的自动增加。当FIFO满或者空时我们通过内部读写地址的特征就会判断出FIFO的状态。
例如我们设计深度为8的FIFO即最大可以存放8个数据,地址所需位数为3,在设计FIFO时我们将地址为扩展为4位根据我们的扩展位可以判断FIFO的空满状态。
8深度的FIFO经过以下4个操作:(下面方框代表地址)
1、 当FIFO为空时,读指针为0_000B,写指针为0_000B,此时FIFO里面没有数据,FIFO的状态为空。
2、当FIFO写入8个数据时,写指针指向1_000B,读指针还为0_000B,此时FIFO里有8个数据,FIFO状态应该为满。
3、当FIFO读出8个数据时,写指针还指向1_000B,读指针为1_000B,此时FIFO里面没有数据,FIFO的状态为空。
4、向FIFO再写入8个数据,写指针指向0_000B,读指针还为1_000B,此时FIFO里有8个数据,FIFO状态应该为满。
通过上述观察发现地址除了最高位余下的3位为地址0-7的循环。
观察上图FIFO满时读写地址的高2位不同其余位均相同;FIFO空时读写地址完全相同。
所以
判断FIFO空的条件:读写地址完全相同。
判断FIFO满的条件:读写地址的最高位不同其余位均相同。
同步FIFO设计:
设计深度为16,数据位宽为16的同步FIFO
//深度16 位宽16
module top
#
(
parameter depth = 16,
parameter width = 16
)
(
input clk,
input rst_n,
input wr_en,
input [width-1:0] data_in,
input rd_en,
output [width-1:0] data_out,
output full,
output empty
);
reg [width-1:0] mem [depth:0]; //深度16 位宽16的mem
reg [4:0] waddr; //写指针
reg [4:0] raddr; //读指针
reg [width:0] temp_rdata;
//写指针
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
waddr <= 5'b0_0000;
else if(wr_en == 1'b1)
waddr <= waddr + 1;
else
waddr <= waddr;
end
//读指针
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
raddr <= 5'b0_0000;
else if(rd_en == 1'b1)
raddr <= raddr + 1;
else
raddr <= raddr;
end
//写数据
always@(posedge clk)
begin
mem[waddr] <= data_in;
end
//读数据 1 latency
assign data_out = temp_rdata;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
temp_rdata <= {width{1'b0}};
else
temp_rdata <= mem[raddr];
end
//空信号判断
assign empty = (waddr == raddr)?1'b1:1'b0;
//满信号判断
assign full = ({~waddr[4],waddr[3:0]} == raddr)?1'b1:1'b0;
endmodule
testbench:
module top_test;
reg clk;
reg rst_n;
reg wr_en;
reg[15:0] data_in;
reg rd_en;
wire full;
wire empty;
top u1
(
.clk (clk),
.rst_n (rst_n),
.wr_en (wr_en),
.data_in (data_in),
.rd_en (rd_en),
.full (full),
.empty (empty)
);
initial
begin
clk = 0;
rst_n = 0;
wr_en = 0;
rd_en = 0;
data_in = 16'h0000;
repeat(5)@(posedge clk);
rst_n = 1;
repeat(5)@(posedge clk);
drive_w();
repeat(5)@(posedge clk);
drive_r();
end
task drive_w;
integer i;
begin
for(i=0;i<16;i=i+1)
begin
wr_en <= 1;
data_in <= i[15:0];
@(posedge clk);
wr_en <= 0;
end
end
endtask
task drive_r;
integer i;
begin
for(i=0;i<16;i=i+1)
begin
rd_en <= 1;
@(posedge clk);
rd_en <= 0;
end
end
endtask
always # 10 clk = ~clk;
endmodule
同步FIFO波形:
2.异步FIFO
异步FIFO的写时钟和读时钟为异步时钟,FIFO内部的写逻辑和读逻辑的交互需要异步处理,异步FIFO常用于跨时钟域交互。因为FIFO为异步设计,读写都有不同的时钟,读写是相互独立的,因为空满信号的判断是借助于读写地址进行的,所以涉及到了不同的时钟域,当二进制读地址从0111向1000变化时,地址所有位都要变化,如果写时钟恰好在读地址的变化时刻采样,写所得到的读地址值有可能是从0000到1111中的任何一个(即亚稳态的发生),可以采用格雷码形式。由于格雷码每次只变化一位,采用格雷码可以降低亚稳态的发生概率。
方法:两级寄存器同步 + 格雷码
读指针同步到写时钟域、写指针同步到读时钟域时要通过两级D触发器来进行同步处理。
由于设计的时候读写指针用了至少两级寄存器同步,同步会消耗至少两个时钟周期,势必会使得判断空或满有所延迟,这会不会导致设计出错呢?
异步FIFO通过比较读写指针进行满空判断,但是读写指针属于不同的时钟域,所以在比较之前需要先将读写指针进行同步处理,
① 将写指针同步到读时钟域再和读指针比较进行FIFO空状态判断,因为在同步写指针时需要时间,而在这个同步的时间内有可能还会写入新的数据,因此同步后的写指针一定是小于或者等于当前实际的写指针,所以此时判断FIFO为空不一定是真空,这样更加保守,一共不会出现空读的情况,虽然会影响FIFO的性能,但是并不会出错。
②将读指针同步到写时钟域再和写指针比较进行FIFO满状态判断,同步后的读指针一定是小于或者等于当前的读指针,所以此时判断FIFO为满不一定是真满。
这样更保守,这样可以保证FIFO的特性:FIFO空之后不能继续读取,FIFO满之后不能继续写入。 总结来说异步逻辑转到同步逻辑不可避免需要额外的时钟开销,这会导致满空趋于保守,但是保守并不等于错误,这么写会稍微有性能损失,但是不会出错。
格雷码:
码表:
十进制数 | 二进制码 | 格雷码 |
---|---|---|
0 | 0000 | 0000 |
1 | 0001 | 0001 |
2 | 0010 | 0011 |
3 | 0011 | 0010 |
4 | 0100 | 0110 |
5 | 0101 | 0111 |
6 | 0110 | 0101 |
7 | 0111 | 0100 |
8 | 1000 | 1100 |
9 | 1001 | 1101 |
10 | 1010 | 1111 |
11 | 1011 | 1110 |
12 | 1100 | 1010 |
13 | 1101 | 1011 |
14 | 1110 | 1001 |
15 | 1111 | 1000 |
二进制至格雷码的转换:
二进制转格雷码代码:
module top(
input sys_clk,
input rst_n,
input [4:0]bin_code,
output [4:0]gray_code
);
assign gray_code = (bin_code>>1)^bin_code;
endmodule
波形:
例如深度为8采用格雷码判断空满的条件:
引入格雷码(原因往下看):
FIFO操作 | 写地址指向(B) | Gray | 读地址指向(B) | Gray | FIFO状态 |
---|---|---|---|---|---|
空FIFO | 0_000 | 0000 | 0_000 | 0000 | 空 |
写入8个数据 | 1_000 | 1100 | 0_000 | 0000 | 满 |
读出8个数据 | 1_000 | 1100 | 1_000 | 1100 | 空 |
写入8个数据 | 0_000 | 0000 | 1_000 | 1100 | 满 |
读出8个数据 | 0_000 | 0000 | 0_000 | 0000 | 空 |
判断异步FIFO空的条件:读写地址(格雷码)完全相同。
判断异步FIFO满的条件:读写地址(格雷码)的高2位不同,其余位均相同。
异步FIFO代码设计:
//深度为16 宽度为16
module top
#
(
parameter depth = 16,
parameter width = 16
)
(
input wr_clk,
input rst_n,
input wr_en,
input [width-1:0] data_in,
input rd_clk,
input rd_en,
output [width-1:0] data_out,
output full,
output empty
);
reg [width-1:0] mem [depth-1:0];
reg [width-1:0] temp_data;
reg [4:0] waddr;
wire[4:0] waddr_gray;
reg [4:0] waddr_w2r1;
reg [4:0] waddr_w2r2;
reg [4:0] raddr;
wire[4:0] raddr_gray;
reg [4:0] raddr_r2w1;
reg [4:0] raddr_r2w2;
//写指针
always@(posedge wr_clk or negedge rst_n)
begin
if(!rst_n)
waddr <= 5'b0_0000;
else if(wr_en)
waddr <= waddr + 1;
else
waddr <= waddr;
end
//写指针转换为格雷码
assign waddr_gray = (waddr>>1)^waddr;
//写指针同步到读时钟域
always@(posedge wr_clk or negedge rst_n)
begin
if(!rst_n)
{waddr_w2r2,waddr_w2r1} <= {2{5'b0_0000}};
else
{waddr_w2r2,waddr_w2r1} <= {waddr_w2r1,waddr_gray};
end
//读指针
always@(posedge rd_clk or negedge rst_n)
begin
if(!rst_n)
raddr <= 5'b0_0000;
else if(rd_en)
raddr <= raddr + 1;
else
raddr <= raddr;
end
//读指针转换为格雷码
assign raddr_gray = (raddr>>1)^raddr;
//读指针同步到写时钟域
always@(posedge rd_clk or negedge rst_n)
begin
if(!rst_n)
{raddr_r2w2,raddr_r2w1} <= {2{5'b0_0000}};
else
{raddr_r2w2,raddr_r2w1} <= {raddr_r2w1,raddr_gray};
end
//写数据
always@(posedge wr_clk)
begin
mem[waddr] <= data_in;
end
//读数据 1 latency
assign data_out = temp_data;
always@(posedge rd_clk or negedge rst_n)
begin
if(!rst_n)
temp_data <= {width{1'b0}};
else if(rd_en==1)
temp_data <= mem[raddr];
else
temp_data <= temp_data;
end
//空信号检测(写指针同步到rd_clk后与读指针进行比较)
assign empty = (waddr_w2r2 == raddr_gray)?1'b1:1'b0;
//满信号检测(读指针同步到wr_clk后与写指针进行比较)以上是关于FPGA/IC 秋招笔试/面试题总结的主要内容,如果未能解决你的问题,请参考以下文章
2021最新秋招Java软件工程师面试笔试必备面试题及答案汇总