FPGA/IC笔试——联芸科技
3.1 请解释D触发器和Latch的区别,解释同步复位和异步复位的区别及优缺点。
一、D触发器和Latch的区别
Latch有电平触发,非同步控制。在使能信号有效时Latch相当于通路,在使能信号无效时Latch保持输出状态。D触发器由时钟沿触发,同步控制。
Latch容易产生毛刺,D触发器则不易产生毛刺。
如果使用门电路来搭建Latch和D触发器,则Latch消耗的门资源比D触发器要少,这是Latch比D触发器优越的地方。所以在ASIC中使用Latch的集成度比D触发器高,但在FPGA中恰好相反,因为FPGA中没有标准的Latch单元,但有D触发器单元,一个Latch需要多个LE才能实现。
二、同步复位和异步复位的区别
异步复位:异步复位只要有复位信号系统马上就复位,因此异步复位抗干扰能力差,有些噪声也是能系统复位,因此有时候显得不够稳定,要想设计一个好的复位最好使用异步复位同步释放。
同步复位:
优点:
有利于仿真器仿真;
可以使用所设计的系统成为100%同步时序电路,这大大有利于时序分析,而且综合出来的fmax一般较高。
因为他只有在时钟有效电平到来时才有效,所以可以滤掉高于时钟频率的毛刺。
缺点:
复位信号的有效时长必须大于时钟周期,才能真正被系统识别并完成复位任务。同时还要考虑,诸如:clk skew,组合逻辑路径延>时,复位延时等因素;
由于大多数的逻辑器件的目标库内的DFF都只有异步复位端口,所以,倘若采用同步复位的话,综合器就会在寄存器的寄存器的数据输入端口插入组合逻辑,这样就会耗费较多的逻辑资源。
异步复位:
优点:
大多数目标器件库的DFF都有异步复位端口,因此采用异步复位可以节省资源;
设计相对简单;
异步复位信号识别方便,而且可以很方便的使用FPGA的全局复位端口GSR。
缺点:
在复位信号释放(release)的时候很容易出现问题,倘若复位释放时恰好在时钟有效沿附近,就很容易使寄存器输出出现亚稳态,从而导致亚稳态。
复位信号容易收到毛刺影响。
3.2 解释什么叫clock gating?并说明一下通常情况下为什么要做clock gating?简单列举通常实现的方法有哪些?
门控时钟计数(clock gating)是一种非常简单和有效的功耗控制方法,它的基本原理就是通过关闭芯片上暂时用不到的功能和它的时钟,从而实现节省电流消耗的目的。 clk信号和clk_enable相与。
时钟门控(Clock-Gating)一直以来都是降低微处理器功耗的重要手段,主要针对寄存器翻转带来的动态功耗。如何更加有效地设计时钟门控对于最大限度地降低功耗,同时保证处理器的性能至关重要。多核多线程微处理器中,多个功能部件可能不是同时工作的,对于无执行任务的功能部件就可以将其时钟关闭,减少其随时钟翻转进行多余的内部寄存器翻转,从而降低产生功耗的浪费和热量聚集。
3.3 实现一个可以1-8分频任意切换的分频器,要求无论是奇数分频还是偶数分频,分频后的时钟的duty cycle都是50%。
1 //占空比模块
2 module Duty_Cycle#(
3 parameter HIGH_TIME = 1, //高电平时间
4 LOW_TIME = 2, //低电平时间
5 BIT_WIDTH = 2 //位宽
6 )(
7 input clk, //时钟
8 input rst_n, //异步复位
9 output reg clk_out //输出
10 );
11
12 reg [BIT_WIDTH-1:0] count; //计数器
13
14 always_ff @(posedge clk, negedge rst_n) begin
15 if(!rst_n) begin
16 count <= '0;
17 end
18 else if(count < HIGH_TIME) begin
19 count <= count + 1;
20 clk_out <= '1;
21 end
22 else if((count < HIGH_TIME+LOW_TIME-1) && (count >= HIGH_TIME))begin
23 clk_out <= '0;
24 count <= count + 1;
25 end
26 else if(count >= HIGH_TIME+LOW_TIME-1)begin
27 clk_out <= '0;
28 count <= '0;
29 end
30 else begin
31 clk_out <= clk_out;
32 count <= count;
33 end
34 end
35
36 endmodule
37
38 //分频模块===================================================
39 module Frequency_Divider#(
40 parameter DIV_COEFF = 3, //分频系数
41 BIT_WIDTH = 2 //分频系数位宽
42 )(
43 input clk, //时钟
44 input rst_n, //复位
45
46 output clk_out //分频时钟
47 );
48 //======================================================
49 //奇偶判断,0为偶
50 wire odd_even;
51 wire [BIT_WIDTH-1:0] div_coeff;
52
53 assign div_coeff = DIV_COEFF;
54 assign odd_even = div_coeff[0];
55 //======================================================
56 //计算高低占空比时间
57 parameter HIGH_TIME = DIV_COEFF/2;
58 parameter LOW_TIME = DIV_COEFF-HIGH_TIME;
59 //======================================================
60 //根据奇偶分频分配时钟
61 reg clk_p,clk_n;
62
63 always_comb begin
64 if(odd_even)begin
65 clk_p = clk;
66 clk_n = ~clk;
67 end
68 else begin
69 clk_p = clk;
70 clk_n = clk;
71 end
72
73 end
74
75 wire clk_out_p,clk_out_n;
76
77 Duty_Cycle#(
78 .HIGH_TIME (HIGH_TIME),
79 .LOW_TIME (LOW_TIME),
80 .BIT_WIDTH (BIT_WIDTH)
81 )u1_Duty_Cycle(
82 .clk (clk_p),
83 .rst_n (rst_n),
84 .clk_out (clk_out_p)
85 );
86
87 Duty_Cycle#(
88 .HIGH_TIME (HIGH_TIME),
89 .LOW_TIME (LOW_TIME),
90 .BIT_WIDTH (BIT_WIDTH)
91 )u2_Duty_Cycle(
92 .clk (clk_n),
93 .rst_n (rst_n),
94 .clk_out (clk_out_n)
95 );
96
97 assign clk_out = clk_out_p | clk_out_n;
98
99 endmodule
3.5 现有三个输入信号分别是a,b,c,并且前级DFF Clock到a,b,c的延时分别是Ta,Tb,Tc(Ta>Tb>Tc),请用两个二输入选择器对a,b,c实现三输入选择输出,画电路图并解释设计思路,不需要考虑Clock Skew的影响。
3.6 请画出下列数字电路D触发器输出Q0,Q1的波形图(复位之后Q0,Q1均为0,画出复位后8个时钟周期)。
可见,Q0(n+1)=~Q1(n) ;Q1(n+1)= Q0(n) ^ Q1(n) = ~Q1(n-1) ^ Q1(n) = Q1(n-1) ~^ Q1(n) ,即Q1的前一状态与前前状态同或。
Q0 | Q1 | |
---|---|---|
RESET | 0 | 0 |
第一个CLK | 1 | 0 |
第二个CLK | 1 | 1 |
第三个CLK | 0 | 0 |
第四个CLK | 1 | 0 |
第五个CLK | 1 | 1 |
第六个CLK | 0 | 0 |
第七个CLK | 1 | 0 |
第八个CLK | 1 | 1 |
可看出Q0、Q1复位后出现00、10、11循环。
3.7 分析代码覆盖率时,verilog语句if(a||b&&c)有那几个条件需要覆盖?请用表格列出每种状况下a/b/c的值(a/b/c均为bit类型,如果是0或1都无所谓,请用“-”表示)。
A | B | C | A||B&&C (逻辑与优先于逻辑或) |
---|---|---|---|
1 | - | - | 1 |
0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 |
0 | 1 | 0 | 0 |
- | 1 | 1 | 1 |
a为真或b&&c为真,结果为真; a和b&&c都为假时,结果为假。
3.8 使用任意一种编程或脚本语言(C,Verilog,SystemVerilog,shell,perl,Python)实现32位十六进制转化为二进制数(如abcd0123->10101011110011010000000100100011)。
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 void HextoTwo(int num)
5 {
6 int res;
7 int i = 0;
8 char buf[BUFSIZ][5] = {"0000"};
9 char reference[16][5] = {"0000","0001","0010","0011",\
10 "0100","0101","0110","0111",\
11 "1000","1001","1010","1011",\
12 "1100","1101","1110","1111"};
13
14 while(num / 16 != 0)
15 {
16 res = num % 16;
17 strcpy(buf[i++], reference[res]);
18 num = num / 16;
19 }
20
21 res = num % 16;
22 strcpy(buf[i++], reference[res]);
23
24 while(i > 0)
25 printf("%s ", buf[--i]);
26 }
27 //采用递归
28 void HextoTwo(int num)
29 {
30 int remainder;
31 char buf[16][5] = {"0000","0001","0010","0011",\
32 "0100","0101","0110","0111",\
33 "1000","1001","1010","1011",\
34 "1100","1101","1110","1111"};
35 if(0 == num)
36 return;
37
38 remainder = num % 16;
39 HextoTwo(num >> 4);
40 printf("%s ", buf[remainder]);
41 }
42
43 int main()
44 {
45 int num = 0xfa;
46 HextoTwo(num);
47 return EXIT_SUCCESS;
48 }
3.9 使用C或Verilog/SystemVerilog,定义并实现一个函数,传递三个int类型参数A,B,C,函数返回后,A的值不变,B的值变为A+B,C的值变为A-C,请写出函数原型定义与函数体的实现。
1 module A;
2
3 int A;
4 int B;
5 int C;
6
7 initial begin
8 A=1;
9 B=2;
10 C=3;
11
12 $display("%d,%d,%d",A,B,C);
13 #1;
14
15 func1(A,B,C);
16
17 $display("%d,%d,%d",A,B,C);
18 end
19 //System Verilog中ref表明参数是使用引用传递当函数需要返回多个值或者任务需要返回一个以上值的时候,通过引用传递就用得上。
20 function automatic viod func1(ref int A,ref int B,ref int C);
21 A=A;
22 B=A+B;
23 C=A-C;
24 endfunction
25 endmodule
CPU通过APB接口读写寄存器,interrupt为中断输出信号。模块内有如下寄存器,每个bit对应一种中断源,当某个中断enable位配置为1时,内部逻辑被允许对中断status位进行置位操作;当任意一位status被置位1,且其mask位为0时,则interrupt输出为高电平。CPU通过APB将status位写1清0。如果所有status位都被清0后,interrupt输出低电平。
中断使能寄存器reg_int_enable[7:0]; 中断屏蔽寄存器reg_init_mask[7:0]; 中断状态寄存器reg_int_status[7:0](所有位都是W1C,即“写1清0”)。
-
APB总线对三个寄存器任意一位读写操作功能测试;
-
reg_int_status寄存器任意一位W1C功能测试;
-
APB总线配置reg_int_enable寄存器任意一位为1,对应位status置位功能测试;
-
寄存器reg_int_enable和reg_int_status对应位置位时,且reg_int_mask对应位置0时,信号interrupt拉高功能测试;
-
reg_int_status寄存器所有位W1C操作,信号interrupt拉低功能测试。