IC面试经验
作者:互联网
常见问题
一、设计
技术面试,根据项目来,会让你画系统框图,具体的性能指标
1、建立时间、保持时间、亚稳态的出现与消除、传染性
建立时间:触发器的时钟上升沿到来前,数据保持不变的时间
保持时间:触发器的时钟上升沿到来后,数据保持不变的时间
触发器的建立时间和保持时间在时钟沿上定义了一个窗口,如果触发器数据输入端口上的数据在这个窗口内发生变化,那么就产生了时序违例。此时触发器的晶体管不能可靠地设置为逻辑0或逻辑1,就是亚稳态。
触发器输出保持亚稳态的时间是随机的,打两拍不一定能解决亚稳态问题。
2、Verilog阻塞与非阻塞
3、同步fifo与异步fifo,位宽转换、fifo深度计算(考虑背靠背的情况)
4、fifo将满,将空
https://blog.csdn.net/darknessdarkness/article/details/104726798
5、逻辑等 和 case等
6、跨时钟域
6.1 单bit跨时钟域
(1)脉冲展宽
1、 慢到快:
如果快时钟域的时钟频率是慢时钟域的1.5倍以上,那么同步较慢的控制信号到快时钟域通常不会有问题,只需采用双触发(打两拍)即可。
2、 快到慢:
将目标信号展宽到接收时钟域(慢时钟域)时钟周期的1.5倍以上,这样至少会稳定采样一次。
缺点:当设计发生改变,设计者忘记重新分析
(2)握手法:
握手法的缺点:显而易见,该方法存在极大的时延,因为信号未被接收时钟域正确接收前是不能释放的,无法传递下一个数值。
(3)双触发(打两拍):
6.2 多bit跨时钟域:
(1)控制信号合并:
(2)DMUX(多周期路径规划)
(3)异步fifo
跨时钟域传输,单bit和多bit信号传输怎么实现;打两拍和握手一般在什么场合下使用,为什么?
(4)双口ram
异步时钟域的缓存只要是双口器件(伪双口、真双口)都可以完成。但FIFO不需对地址进行控制,是最方便的。
7、速度优化 与 面积优化
7.1 速度优化(时序优化)
(1)关键路径重组,迟置信号后移
(2)逻辑复制减少大扇出
(3)插流水
(4)寄存器平衡减少逻辑级数
(5)串行转并行
(6)if-else转case或者并行if
7.2 面积优化(资源优化)
(1)操作符平衡(面积速度都能得到优化)
(2)资源共享,时分复用
(3)打破流水
(4)减少ram使用,能流水就不存
(5)减少不必要的复位
(6)从器件角度:利用厂家原语、巧用触发器控制端口、多路选择器优化
8、然后是用二选一选择器构成与、或、异或该怎么做
或:assign out = b ? 1 : a;
与:assign out = b ? a : 1;
异或:assign out = b? ~a : a;
9、FPGA的基本资源与内部构造。
UltraScale布线架构能够完全消除布线拥塞问题。
可配置逻辑块CLB
CLB是主要的逻辑资源,用于实现时序和组合逻辑电路。
每个CLB包含一个切片Slice,每个Slice提供8个6输入的查找表和16个触发器。UltraScale架构包含两种类型的切片,SliceL和SliceM。
10、FPGA的时钟资源及构造。
11、同步时钟和异步时钟。时钟相移之后还是同步的吗?倍频或者分频呢?
12、PLL+MMCM。他们的输入输出,使用的注意点等等。
13、对于FDCE,LDCE的实现
14、为什么要优化关键路径?
关键路径就是电路中调用频繁且延迟过长,产生意外机率比较大的电路;
同步电路的最高工作频率就受限于电路中的几条关键路径;
可以通过对关键路径进行分析,减少组合逻辑级数,关键路径后移等方法就能优化关键路径。
15、SRAM的种类有哪些?双端口实现有什么缺点?SRAM和LUT的异同,怎么选择,为什么?
16、同步复位、异步复位、异步复位同步释放
1. 同步复位应用
一些IP可以等到时钟翻转后再复位,时钟翻转前即使没有复位也没关系,那么就可用同步复位。
2. 同步复位的优点:
(1)需要时钟,避免了复位信号毛刺的影响,增加了系统的抗干扰能力
(2)同步复位是同步电路,避免了亚稳态。STA可以像分析其他数据路径那样分析同步复位
3. 同步复位的缺点:
(1)耗费资源
带来了额外的资源消耗
(2)增大了数据路径延迟
4. 异步复位应用
(1)同步复位需要时钟,而异步复位不需要。如果模块需要在没有时钟的时候复位,那么就得作异步复位,这也是绝大多数芯片的上电复位信号。
5. 异步复位的优点:
(1)省资源
异步复位消耗更少的逻辑资源
(2)不增加数据路径的延迟
没有像同步复位那样插入到数据路径中,对寄存器之间数据到达时间不产生任何负面影响
(3)即刻生效,不依赖于时钟
6. 异步复位的缺点:
(1)潜在的亚稳态问题,因为不能进行时序分析
(2)对噪声的易感染性
复位信号的毛刺可能会导致虚假的复位
(3)异步复位释放时无法同时到达每一个触发器
例如独热码状态机,可能在释放时从 IDLE4’b0001 跳转 S04’b0010时,第二个触发器比第一个触发器晚一个时钟周期释放,就会导致状态跳转为4’b0000,出现错误状态。
17、异步FIFO怎么实现?当读写地址相同怎么办,如果使用格雷码发生亚稳态,应该怎么办?
18、状态机有哪几种?编码方式
moore:输出与当前输入无关
mealy:输出与当前数入有关
状态编码
(1)二进制
(2)独热码
这种方法在状态机中为每一种状态分配一个触发器
(3)格雷码
相邻状态编码间只有一个bit变化。
优缺点
(1)独热码实现结构简单
译码简单,组合逻辑最少;
使用触发器最多,能够工作在高时钟频率下。
(2)格雷码减少过渡状态产生,降低翻转次数,低功耗
由于时钟偏斜,时钟到达各个触发器的延时往往有一些差异,这种差异会导致状态转换时产生过渡状态,如2’b01跳转2’b10时,容易产生2’b00和2’b11;当这种差异加大时,还有可能使得状态跳转到过渡状态上去。
用格雷码可以大大降低产生过渡状态的概率,但是如果状态跳转有多种路径,那么就不能保证状态跳转只有1bit变化了。
19、对低功耗设计有多少了解?有哪些低功耗设计方法,使用门控时钟对slack有什么影响 ?
电路功耗分为浪涌、动态功耗和静态功耗
1. 浪涌
浪涌电流指器件上电时产生的最大瞬时电流,在应用中也称启动电流。
2. 静态功耗
也称待机功耗,与元件的电气特性密切相关,主要由漏电流产生。
3. 动态功耗
主要是门电路输出切换时,由逻辑转换所引起的功耗。
动态功耗在大规模IC设计中占主要地位,在典型应用中占了总功耗的80%
4. 低功耗技术
降低功耗应当在所有设计层次上进行,在系统级、逻辑级(寄存器传输级+逻辑/门级)和物理级(晶体管级)。层次越高对功耗降低越有效。
1)系统级低功耗技术
(1)片上系统:由于I/O使用比芯片内核逻辑更高的电压供电,使得其占用总功耗的50%以上。如果整个系统包含多个芯片,芯片间连线将消耗大量功耗。
(2)软硬件划分
(3)低功耗软件
2)体系结构级降低功耗技术
(1)多阈值电压技术:满足性能要求时尽量使用高阈值电压
(2)门控电源技术
(3)多电压供电
(4)存储器电源门控
3)逻辑级
(1)并行化处理,降低系统工作频率,从而可能降低功耗
(2)状态机编码:采用格雷码,格雷码相邻状态翻转最少,功耗低
(3)门控时钟:将EN与CLK进行与操作,完成门控。当en为0时,该时钟被关掉。
(4)独热码多路器:
(5)去除多余的转换
(6)资源共享
20、为什么使用格雷码,格雷码一定能有效保证一次只变化1bit吗?如果布线延迟影响了格雷码的输出怎么办?
(1)不能。在顺序跳转时格雷码可以一次保证只变化1bit,如果不是顺序变化就不行了。
(2)不影响,要么保持,要么变化,不会采到错位的数值,下一时钟周期就采到了。
21、ASIC设计流程
SPEC到RTL设计与功能验证
DC逻辑综合概述
从某种意义而言,综合就是将设计的HDL描述转化为门级网表的过程。
Synopsys公司提供的综合工具DC把综合分为三个步骤进行:
synthesis=translation+mapping+optimization。
(1)Translation是指把设计的HDL描述转化为GTECH库元件组成的逻辑电路;GTECH库是Synopsys公司提供的通用的、独立于工艺的元件库。
(2)Mapping是指将GTECH库元件映射到某一特定的半导体工艺库上,此时的电路网表包含了相关的工艺参数。
(3)Optimization是根据设计者设定的时延、面积、线负载模型等综合约束条件对电路网表进一步优化的过程。
形式验证formality
STA: PT
DFT(Design for testability)
PD(Physical Design)版图设计:ICC布局布线
23、verilog操作符优先级
24、无符号数与有符号数运算结果
无符号数
25、串行为什么比并行快
并行接口速度比串行接口速度快,这是若干年前的情况了。
在实际时钟频率比较低的情况下,并口因为可以同时传输若干比特,速率确实比串口快。
但是,随着技术的发展,时钟频率越来越高,并行导线之间的相互干扰越来越严重。并行接口因为有多条并行且紧密的导线,但时钟频率提高的一定程度时,传输的数据已经无法恢复。
而串口因为导线少,线间干扰容易控制,反而可以通过不断提高时钟频率来提高传输速率。而且串口的端子也会比较小。这就是为什么现在高速传输都采用串行方式的原因。
串行传输之所以走红,是由于将单端信号传输转变为差分信号传输,并提升了控制器工作频率的原因,而“在相同频率下并行通信速度更高”这个基本道理是永远不会错的,通过增加位宽来提高数据传输率的并行策略仍将发挥重要作用。当然,前提是有更好的措施来解决并行传输的种种问题。
26、经典MIPS五级流水介绍
27、各种RAM
单口RAM与伪双口RAM、真双口RAM的区别在于:
单口RAM
只有一个时钟(clka)(时钟上升沿到来时对数据进行写入或读出)、一组输入输出数据线(dina&douta)、一组地址线(addra)、一个使能端(ena)(ena==1时可以进行读或写的操作,ena == 0时无法进行读或写的操作)、一个写使能端(wea)(在ena == 1的情况下,wea == 1时只写不读,wea == 0时,只读不写)。单口RAM,读写无法同时进行,只能或读或写。
伪双口RAM
有两个时钟(clka&clkb)、一组输入输出数据线(dina&doutb)、两组地址线(addra&addrb)、两个使能端(ena&enb),一个写使能(wea),一个端口只读(porta),另一个端口只写(portb)。整体上,读、写可以同时进行。
真双口RAM
有两个时钟(clka&clkb)、两组输入输出数据线(dina&douta&dinb&doutb)、两组地址线(addra&addrb)、两个使能端(ena&enb)、两个写使能端(wea&web)。两个端口都可以进行读写操作(porta和portb可以一起读或者一起写或者一个读一个写)。整体上读写可以同时进行。
单口ROM和双口ROM的区别
单口ROM
只有一个时钟(clka)、一组输出数据线(douta)、一组地址线(addra),一个使能端(ena)。只能进行读操作,且一个时钟只能读出某个地址上的一组数据。
双口ROM
有两个时钟(clka&clkb)、两组数据数据线(douta&doutb)、两组地址线(addra&addrb)、两个使能端口(ena&enb)。也是只能进行读操作,且每个端口中,一个时钟只能读出某个地址上的一组数据,其实和单端口ROM没什么区别,其实可以当成是两个单口ROM拼接而成,只是存储的数据是共享的。
二、手撕代码
1、异步fifo
2、优先译码器
3、最长上升子序列寻找,并输出首尾值
4、抢答器
5、C语言描述的串行处理过程,转换为单拍完成的并行处理,并verilog实现
6、自动饮料售卖机
7、判断32bit中1的个数,多种方法实现:移位、遍历、二分法
8、时钟消抖电路
//题目描述:设计一个电路,使用时序逻辑对一个单bit信号进行毛刺滤除操作。高电平或者低电平宽度小于4个时钟周期的为毛刺。用verilog写出代码
// 可以这么理解,只有idata为1超过4个clk时,odata才能为1;idata为0超过4个clk时,odata才能为0。
module BurrFilter(
input clk,
input rst,
input i_data,
output reg o_data
);
reg [1:0] cnt_high;
reg [1:0] cnt_low;
always @ (posedge clk) begin
if ( rst )
cnt_high <= 2'd0;
else if (~i_data)
cnt_high <= 2'd0;
else
cnt_high <= cnt_high + 1'b1;
end
always @ (posedge clk) begin
if ( rst )
cnt_low <= 2'd0;
else if ( i_data )
cnt_low <= 2'd0;
else
cnt_low <= cnt_low + 1'b1;
end
always @ (posedge clk) begin
if ( rst )
o_data <= 1'b0;
else if ((cnt_low==2'd3 && ~i_data)||(cnt_high==2'd3 && i_data))// 此处当cnt_low==2'd3时采用的i_data是第4clk的输入,若第4clk输入仍为0,则不是毛刺
o_data <= i_data;
end
endmodule
9、用verilog写一个I2C接口的pad
10、分频电路
(1)整数倍偶数分频
使用D触发器与计数器,或摩尔状态机
(2)整数倍奇数分频电路
50%占空比,N分频电路(N为奇数)
步骤:
(1)创建上升沿触发计数器,计数至N-1归零
(2)上升沿触发器,在计数器值为0时翻转
(3)下降沿触发器,在计数器值为(N+1/2)时翻转
(4)N分频输出为两触发器输出异或
N=3:
(3)非整数倍分频电路
N=2.5:
验证
1、SystemVerilog中的4种数组,与数组遍历for、foreach
1)定宽数组
int array2[0:7][0:3]; // 8行4列,完整声明
若从一个越界地址读取数据,那么SV将返回数组缺省值,4状态类型返回X,2状态类型返回0,而线网在没有驱动的时候输出是Z
2)常量数组
int array[4] = '{0, 1, 2, 3}; // 对4个元素进行初始化
3)合并数组
对于某些数据类型,既希望把它作为一个整体来访问,也可以分解成更小的单元,比如拼4个8bit为一个字。与非合并数组不同,他们的存放方式是连续bit合集,中间没有任何闲置空间。
bit [3:0][7:0] bytes; // 4个字节组装成32bit
什么时候用合并数组:
(1)当需要标量相互转换时
同时需要以字节,或者以字为单位对存储单元进行操作。任何数组类型都可以合并,包括动态数组、队列和关联数组。
(2)当需要等待数组中的变化:@
@操作符只能用于标量或者合并数组
5)动态数组
使用动态数组而不是定宽数组,可以在仿真时根据需要分配空间或调整宽度,使用最少的存储量,避免存储空间的浪费。
1.只要基本数据类型相同,定宽数据和动态数组之间就可以相互赋值
2.在元素数目相同的情况下,可以把动态数组的值复制到定宽数组
6)队列
队列比链表更高效,队列可以像数组一样通过索引实现任意访问,而不需要像链表那样去遍历目标元素前的所有元素。
7)关联数组
如果需要创建超大容量数组,但只访问其中很少的地址,用关联数组。
遍历数组
可以用for和foreach,但对稀疏的关联数组,for不能。如果想控制得更好,可以在do…while循环中用first()和next()
2、function和task
function不能消耗时间,而task可以
Verilog中function不能调用task,task可以调用function
3、ref
ref端口的行为其实是对变量的引用,它的值是该变量的最后一次赋值。如果将同一个变量连接到多个ref端口,就可能产生竞争,因为多个模块的端口都可能更新同一个变量。
4、4态变量和2态变量,2态数据类型与4态数据类型对仿真速度的影响
verilog中两种基本变量类型:变量和线网(net),都是4态数据类型。
变量
RTL使用变量存放组合和时序值,变量可以是
(1)单bit或多bit无符号数:reg [7:0] m;
(2)32bit无符号数:integer i;
(3)64bit无符号数:time 或 real
4状态变量:logic,
线网
尽管线网有许多用法,但是大多数设计者还是使用标量或矢量wire来连接各个设计模块的端口。
SystemVerilog增加了许多种新数据类型
logic:4态类型,reg的改进,除作为一个变量外,还可以被连续赋值,门单元和模块所驱动。
任何使用线网的地方均可以使用logic,但要求logic不能有多个结构性驱动,例如在对双向总线建模的时候,就需用用线网类型,如wire,SystemVerilog会对多个数据来源解析后确定最终值。
双状态数据类型
有利于提高仿真器的性能并减少内存使用量。
bit [n-1:0] m; 双状态,无符号
int unsigned ui; 双状态,32bit无符号
int i;双状态,有符号
byte b8;
real r; 双状态,双精度浮点
四状态数据类型
integer i4;四状态,32bit有符号
time; 四状态,64bit无符号
5、类型向下转换
类型向下转换指将一个指向父类的指针转换成一个指向子类的指针。
(1)将一个子类句柄赋值给一个父类句柄,即让一个父类句柄指向子类对象是安全的,因为子类对象中包含父类句柄能够调用的一切属性和方法。
(2)反之则不然,将一个父类句柄赋值给子类句柄,就使得子类句柄指向了一个父类对象,这时子类句柄就可能调用其所指向父类对象中不存在的,只存在于子类对象中的属性和方法。
(3)SystemVerilog会对句柄类型作静态检查,直接将父类句柄赋值给子类句柄的语句将不会被编译,如:
Base_class basehandle;
Extends_class exhandle;
exhandle = basehandle;
但是将一个父类句柄赋值给子类句柄的操作并不总是违法的,当父类句柄确实指向一个子类对象时是允许的。
c
a
s
t
子
程
序
会
检
查
句
柄
并
检
查
句
柄
所
指
向
的
对
象
。
如
果
源
对
象
跟
目
的
对
象
是
同
一
类
型
,
或
者
是
目
的
类
的
扩
展
类
,
就
可
以
从
父
类
句
柄
中
拷
贝
对
象
的
地
址
给
子
类
句
柄
。
(
4
)
当
将
cast子程序会检查句柄并检查句柄所指向的对象。如果源对象跟目的对象是同一类型,或者是目的类的扩展类,就可以从父类句柄中拷贝对象的地址给子类句柄。 (4)当将
cast子程序会检查句柄并检查句柄所指向的对象。如果源对象跟目的对象是同一类型,或者是目的类的扩展类,就可以从父类句柄中拷贝对象的地址给子类句柄。(4)当将cast()作为一个函数使用时,类型失配时返回0,否则返回非零值并拷贝。如:
if( !$cast(exhandle, basehandle) )
$display(“cannot assign basehandle to exhandle!”);
(5)当作为一个任务使用时,类型失配时给出一个错误报告,否则拷贝。
$cast(exhandle, basehandle);
6、随机约束 dist
rand int src, dst;
constraint c_dist{
src dist{0:=40,[1:3]:=60};
}
constraint c_dist2{
dst dist{0:/40,[1:3]:/60};
}
7、验证的边界值
边界值分析法
边界值分析方法是对等价类划分方法的补充.
(1)边界值分析方法的考虑:
长期的测试工作经验告诉我们,大量的错误是发生在输入或输出范围的边界上,而不是发生在输入输出范围的内部.因此针对各种边界情况设计测试用例,可以查出更多的错误.
使用边界值分析方法设计测试用例,首先应确定边界情况.通常输入和输出等价类的边界,就是应着重测试的边界情况.应当选取正好等于,刚刚大于或刚刚小于边界的值作为测试数据,而不是选取等价类中的典型值或任意值作为测试数据.
(2)基于边界值分析方法选择测试用例的原则:
1)如果输入条件规定了值的范围,则应取刚达到这个范围的边界的值,以及刚刚超越这个范围边界的值作为测试输入数据.
2)如果输入条件规定了值的个数,则用最大个数,最小个数,比最小个数少一,比最大个数多一的数作为测试数据.
3)根据规格说明的每个输出条件,使用前面的原则1).
4)根据规格说明的每个输出条件,应用前面的原则2).
5)如果程序的规格说明给出的输入域或输出域是有序集合,则应选取集合的第一个元素和最后一个元素作为测试用例.
6)如果程序中使用了一个内部数据结构,则应当选择这个内部数据结构的边界上的值作为测试用例.
7)分析规格说明,找出其它可能的边界条件.
8、验证流程
(1).看design spec
(2).了解相关协议
(3).编写test plan及verification spec
(4).搭建验证平台
(5).依据test plan创建测试用例testcases
(6).仿真和debug,包括环境和design的bug,花费时间最多。工具是VCS/verdi
debug的手段主要有:查看log,看波形
(7). regression 和覆盖率
(8). code review
9、验证环境怎么搭
构建验证环境的4要素:
(1)单元组件的自闭性
单元组件uvm_agent或者uvm_env可以独立行为,不依赖于其他并行组件。
(2)回归创建
上一级组件在例化自身(执行new()函数)之后的执行各个phase阶段,通过build phase进一步创建子组件,子组件通过一样的办法创建下一级的组件。回归创建的实现依赖于自顶向下顺序执行的build phase。这保证了父类组件必先于子组件创建。
(3)通信端口连接
(4)顶层配置
10、写一个driver class基本的结构,手撕代码
local string name;
loacl virtual chnl_intf vif;
mailbox #(chnl_trans) req_mb;
mailbox #(chnl_trans) rsp_mb;
funciton new(string name = “”);
task run();
fork
this.do_drive();
this.do_reset();
join
endtask
task do_reset();
task do_drive();
chnl_trans req, rsp;
@(negedge vif.rst );
forever begin
this.req_mb.get(req);
this.chnl_write();
rsp = new req;
this.rsp_mb.put(rsp);
end
endtask
task chnl_write();
endtask
req_mb.get();
endtask
task chnl_idle();
11、`uvm_component_utils有什么用
将类注册到工厂
12、 ifndef,
define,`endif有什么用
防止头文件被重复包含和编译。 头文件重复包含会增大程序大小,重复编译增加编译时间。
https://blog.csdn.net/baidu_27690801/article/details/95016120
13、UVM中的factory机制有什么好处
(1)可以更方便地替换验证环境中的实例或已注册的类
(2)同时工厂的注册机制带来配置的灵活性
uvm_object和uvm_component类是进出工厂的主要模具和生产对象,利用注册可以利用工厂完成对象创建;
之所以对象由工厂生产,是利用了工厂生产模具具有可灵活替代的好处(覆盖机制),这使得在不修改原有验证环境层次和验证包的同时,实现对环境内部组件类型或对象的覆盖。
14、有没有用过process
15、run_phase和main_phase的区别
main_phase是run_phase细分的12个phase中的一个,run_phase任务和细分的12个phase是并行的
16、寄存器模型的方法(write,mirror等)
17、TLM怎么用
18、覆盖率分类
1.功能覆盖率
功能覆盖率是和设计意图紧密相连的,有时也被称为“规范覆盖率”。仿真器通过对信号进行监测以得到功能覆盖率。
2.代码覆盖率
(1)行覆盖率
(2)路径覆盖率
(3)翻转覆盖率
(4)有限状态机覆盖率
(5)分支覆盖率
(6)条件覆盖率
代码覆盖率衡量的是测试对于设计规范的实现究竟有多彻底,而非针对验证计划。
3.漏洞率
4.断言覆盖率
19、形式验证有哪些,有没有用过formality
20、SVA——断言属性之序列(sequence与property的用法)蕴含符
21、仿真工具有哪些
22、所知道的协议有哪些
23、验证VIP
24、FIFO验证的技术点有哪些?
在动手写测试代码之前,需要预先弄清楚相关设计的 关键特性、边界情形 和可能的故障模式,这其实就是验证计划的内容。
典型的例子就是FIFO:
(1)关键特性:写进N个数据,能否成功读出所有的数据
(2)边界情形:FIFO的边界情况是空和满,如果能够使FIFO从空(复位以后的状态)变为满再有满变为空的话,那就已经覆盖了其中的所有情形了。
如果设计信号的数量范围太大
26、三次握手
27、UVM工厂机制
28、UVM phase机制
29、UVM的objection
raise
drop
阻止仿真退出,一般只在run_phase中使用。
30、SV的虚方法
31、继承、多态和封装问题。
32、uvm_component和uvm_object
uvm验证环境由两部分构成,一部分构成环境层次,由uvm_component扩展而来,这些类的对象构成仿真环境的层次组件,需要在仿真一开始就创建好,有明确的继承关系;
uvm_component是一个虚类。
另一部分构成环境的属性(比如Packet类,uvm_sequence)和数据传输,这一部分通过uvm_object类完成:需要动态创建的对象,不是在仿真一开始就要创建的
uvm_component继承自uvm_object
33、sv产生一个抖动的时钟
标签:异步,触发器,经验,复位,句柄,面试,数组,IC,时钟 来源: https://blog.csdn.net/qq_40800500/article/details/118890233