校招

数字IC基础知识总结(笔试、面试向)-持续更新

2020-05-17  本文已影响0人  月见樽

该总结生成于找工作准备期,更新做笔试题中常见的题目涉及到的知识点,同时也是对数字IC基础知识的一些总结。列入内容来自:1.笔试题知识点;2.个人觉得需要总结的一些知识。其中verilog语法部分过于庞杂,因此仅总结一些平常可能用到的但是不是特别明确的部分。同时有些知识因为间隔太过久远或疫情期间查不到比较权威的纸质资料可能总结的不正确,欢迎大家留言批评指正。由于本文持续更新,因此有需要转载的同学可以等持续更新删除后再转载,转载请务必征得本人同意且注明作者和出处

2020.05.18

2020.05.19

2020.05.20

2020.06.05

2020.06.06

数制相关

二进制-十进制转换

例子:14->二进制1110

数字 除2结果 除2取模
14 7 0
7 3 1
3 1 1
1 0 1

例子:0.6875->二进制1011

数字 乘2结果
0.6875 1.375 1
0.375 0.75 0
0.75 1.5 1
0.5 1 1

原码、反码与补码

其区别主要在于负数的表达,具体要求如下:

举例:以4bit码为例

十进制 原码 反码 补码
4 0100 0100 0100
-4 1100 1011 1100
-7 1111 1000 1001
-8 - - 1000

BCD码与余3码

BCD码为使用4个bit表示一个十进制位数,即123的BCD码为0x123,余3码表示BCD码基础上加3(十进制),例子如下,对于26而言:

格雷码

格雷码的优势在于相邻的数之间的二进制表达仅有一个bit发生变化,在跨时钟域中不会产生竞争冒险,格雷码-二进制转换如下所示:

确定方式 运算 结果
取最高位 1 1
异或 1 xor 0 1
异或 0 xor 0 0
异或 0 xor 1 1
确定方式 运算 结果
取最高位 1 1
异或 0 xor 1 1
异或 0 xor 1 1
异或 1 xor 1 0

数字逻辑相关

布尔逻辑运算律

名称 运算律
结合律 (a + b) + c = a + (b + c)a(bc) = (ab)c
交换律 a + b = b + aa \cdot b = b \cdot a
分配律 a(b + c) = ab + ac
吸收律 a + ab = a
幂等律 a + a = aaa = a
德摩根律 (a + b)' = a'b'(ab)'=a' + b'
互补律 a + a' = 1a \cdot a' = 0
零一律 a + 1 = 1a \cdot 1 = aa + 0 = a a + 1 =1

卡诺图

卡诺图的思路为可视化的将电路逻辑转为最小乘积项,再通过合并最小乘积项进行化简,如这一个例子:
Y = AB' + A'C + BC + C'D
对应的卡诺图为:

AB\CD 00 01 11 10
00 1 1 1
01 1 1 1
11 1 1 1
10 1 1 1 1

表中为1表示有这一个乘积项,例如在AB=01、CD=00有一个1,即表示逻辑表达式含有项A'BC'D'。随后绘制框,绘制框的过程即为将最小项进行组合化简的过程:同时包括0和1的乘积项可消去,如下图所示:

框越大,可消去的项越多,根据以上卡诺图,化简结果为:
Y = A + B + CD'
除了化简外,卡诺图还可用于判定竞争冒险,当存在相切的框时,存在竞争冒险

竞争冒险

组合竞争冒险即信号在实际电路中的传输存在延迟(Delay),所以由于信号到达同一元件的时间并不一致,到达的时间可能存在延迟。导致组合逻辑电路在某些时刻的结果看上去可能是错误的。竞争冒险的检查方法有:

解决方法有以下几种:

同步复位与异步复位

同步复位的优点:

同步复位的缺点:

异步复位优点:

异步复位缺点:

(以上优缺点内容来自知乎用户Kevin Zhang的回答,如有侵权可联系本人删除)

异步复位电路需要注意以下两点:

异步复位同步释放的代码表达如下所示:

// rst_n_out为处理后的复位信号
always @ (posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        rst_n_buff <= 1'b0;
        rst_n_out  <= 1'b0;
    end else begin
        rst_n_buff <= 1'b1;
        rst_n_out  <= rst_n_buff;
    end
end

建立时间与保持时间

建立时间和保持时间的定义如下所示:

违反建立时间和保持时间可能产生亚稳态,对于一个一般的时序逻辑模型如下所示:

为了满足后一个寄存器的建立时间要求,需要满足:
T_{clk} > T_{c-q} + T_{comb} + T_{steup}
为了满足后一个寄存器的保持时间要求,需要满足:
T_{c-q} + T_{comb} > T_{hold}
由以上公式,可以推断出理想状态下的:

非理想时钟

非理想时钟因素包括时钟偏差(skew)和时钟抖动(jitter):

偏差和抖动对电路性能均有影响,对于时钟偏差而言:
T_{clk} + \delta > T_{c-q} + T_{comb} + T_{steup} \\ T_{c-q} + T_{comb} > T_{hold} + \delta
这里的\delta即为skew,表示后级寄存器相对于前一级寄存器的时钟偏差,亦可理解为“时钟的从前级到后级的传播延迟”,其值可以为正也可以为负(时钟流向与数据流向反向)。对于抖动而言:
T_{clk} - 2t_j > T_{c-q} + T_{comb} + T_{steup} \\ T_{c-q} + T_{comb} > T_{hold} + 2t_j
其中t_j为时钟抖动,表示抖动的最大值(绝对值)。当同时考虑时钟skew和jitter时,有:
T_{clk} + \delta -2t_j > T_{c-q} + T_{comb} + T_{steup} \\ T_{c-q} + T_{comb} > T_{hold} + \delta + 2t_j
产生非理想时钟的原因可能包括:

跨时钟域

在跨时钟域过程中,可能会产生以下问题:

解决方法有:

根据时钟频率区别,在跨时钟域传输时还需要以下操作:

另外,还有一种脉冲同步器需要注意,这种脉冲同步器的方法为在发送时钟域中,每接收到一次脉冲,传递信号的电平发生一次跳变,传递信号通过同步器传递到接收时钟域后使用边沿检测还源出脉冲。

线性反馈移位寄存器

线性反馈移位寄存器用于生成伪随机码,其结构如下所示:

其中Gx为0表示没有这一条连接,为1表示有这一条连接,每一种连接对应一种多项式,如下所示:
Y = G_n x^n + G_{n-1}x^{n-1} + ... + G_{2} x^2 + G_1 x + G_0
当该多项式为本原多项式(不可再因式分解)时,可生成覆盖2^n-1个数据。

Verilog语法

位宽推断

verilog的位宽推断的基本准则为:中间值的位宽=整个表达式中所有操作数(包括结果,即等号左边的数字),例如:

a[7:0] = b[9:0] + c[4:0]

该表达式b+c的结果为10bit,赋值给a的时候舍去最高2bit,再例如:

a[7:0] = b[7:0] + c[7:0]

该表达式b+c的结果为8bit,因此很容易产生数据溢出的问题(255+255->254)

宏定义

宏定义的方式为使用``define A B进行,声明一个宏定义A,内容是B,使用时需要使用\A表示这是一个宏定义。宏定义的使用可以理解为“字符串呼唤”,即在代码中使用`A从字符串角度等效于B,如下例子:

`define SUM A+B+C
assign a = `SUM;   // 使用宏定义
assign a = A+B+C;  // 宏定义等效

注意宏定义不需要使用;结尾,否则;也会被替换,如下:

`define SUM A+B+C;
assign a = `SUM;   // 使用宏定义
assign a = A+B+C;; // 宏定义等效

默认值

对于定义了但是没有赋值过的数据,不同类型具有不同默认值:

还有一种情况是没有指定变量(net)的类型,默认类型为wire

运算符优先级

优先级 运算符类型 运算符
0(最高) 连接运算符 {}、{{}}
1 一元运算符 !、~、&、|、^
2 算数运算符 *、/、%、+、-
3 移位运算符 <<、>>
4 关系运算符 >、<、<=、>=
5 相等运算符 ==、!=、===、!==
6 按位运算符 &、~、|
7 逻辑运算符 &&、||
8 条件运算符 ?:

数字信号处理相关

香农公式

香农公式描述了信噪比-带宽-信道容量之间的关系,公式如下所示:
C = B \times log_2(1 + \frac{S}{N})
其中,\frac{S}{N}为信噪比,B为带宽,C为信道容量

FPGA相关

FPGA基本知识有:

SOC设计常识

功耗公式

数字集成电路的功耗主要由两个来源:

动态功耗的来源主要有以下几种:

动态功耗中开关功耗的公式如下所示:
P_{switch} = \alpha C_LV_D^2f
其中,C_L为等效负载电容,V_D为电源电压,f为频率,\alpha为翻转率,即平均时间内单个节点在单位时钟周期之内翻转的概率。短路功耗的公式如下:
P_{dp} = t_{sc}V_DI_{peak}f
其中t_{sc}为单位时间内两个期间同时导通的时间,V_D为电源电压,I_{peak}为短路电流,f为频率。除了动态功耗外,还存在静态功耗,静态功耗的来源是各种漏电,公式为:
P = V_DI_{peak}
其中V_D为电源电压,I_{peak}为等效漏电电流

低功耗相关

低功耗技术分为以下几种:

这里需要着重介绍的是门控时钟,门控时钟的基本结构如下所示:

该电路消除了直接使用AND门控制产生的毛刺问题,即仅当CLK为低时,控制信号才可以发生变化,因此不会产生毛刺问题(本来CLK为高时直接被控制信号关断)

DFT相关

设计流程

步骤 流程 工具
1 前端设计 VCS(仿真器)、Verdi(波形查看)、nLint(代码检查)、Incisive(仿真器)、NCsim(仿真器)
2 逻辑综合:将RTL代码综合为门级网表 Design Compiler、Genus
3 形式验证:通过数学等价性的理论性方法验证两个设计的等价性,不需要测试向量 Formality
4 Floorplan:布局,放置macro cell,建立电源网络 ICC(IC Compiler)、Innovus
5 Placement:放置stand cell ICC(IC Compiler)、Innovus
6 Clock Tree Synthesis:时钟网络综合 ICC(IC Compiler)、Innovus
7 Routing:布线 ICC(IC Compiler)、Innovus
8 静态时序分析(STA) StarRC+PT
9 物理验证:LVS、DRC和ERC(电气规则检查) calibre、Hercules、Diva/dracula

常见硬件编程

序列检测器

module sequence_detection #(
    parameter SEQ = 5'b10010,
    parameter SEQ_WIDTH = 5
) (
    input clk,    // Clock
    input rst_n,  // Asynchronous reset active low

    input val,
    input din,

    output reg dout
);
    
reg [SEQ_WIDTH - 1:0] buf_din;
wire [SEQ_WIDTH - 1:0] next_buf_din = {buf_din[SEQ_WIDTH - 2:0],din};
always @ (posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        buf_din <= {SEQ_WIDTH{1'b0}};
    end else if (val) begin
        buf_din <= next_buf_din;
    end
end 

always @ (posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        dout <= 1'b0;
    end else if (val && next_buf_din == SEQ) begin
        dout <= 1'b1;
    end else begin
        dout <= 1'b0;
    end
end

endmodule

基本自动售货机
只有一种商品,售价为10分,可投入硬币5分或10分,考虑找零

module store (
    input clk,    // Clock
    input rst_n,  // Asynchronous reset active low

    input corn_val,
    input corn_type,

    output reg return_corn,
    output reg return_commodity
    
);

localparam NOW_0 = 1'b0;
localparam NOW_5 = 1'b1;

reg mode,next_mode;
always @ (posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        mode <= NOW_0;
    end else begin
        mode <= next_mode;
    end
end

wire is_5 = corn_val && !corn_type;
wire is_10 = corn_val && corn_type;
always @ (*) begin
    case (mode)
        NOW_0:begin
            if (is_5) begin
                next_mode = NOW_5;
            end else begin
                next_mode = NOW_0;
            end
        end
        NOW_5:begin
            if (corn_val) begin
                next_mode = NOW_0;
            end else begin
                next_mode = NOW_5;
            end
        end
        default : next_mode = NOW_0;
    endcase
end

always @ (posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        return_corn <= 1'b0;
    end else if (mode == NOW_5 && is_10) begin
        return_corn <= 1'b1;
    end else begin
        return_corn <= 1'b0;
    end
end

always @ (posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        return_commodity <= 1'b0;
    end else if (mode == NOW_5 && corn_val) begin
        return_commodity <= 1'b1;
    end else if (mode == NOW_0 && is_10) begin
        return_commodity <= 1'b1;
    end else begin
        return_commodity <= 1'b0;
    end
end

endmodule

扩展自动售货机

有两种商品A和商品B,A商品售价5分,B商品售价10分,可投入5分或10分的硬币,考虑找零

module store_plus (
    input clk,    // Clock
    input rst_n,  // Asynchronous reset active low

    input want_val,
    input want_type,

    input corn_val,
    input corn_type,

    output reg return_corn,
    output reg return_store 
);

localparam INIT = 2'd00;
localparam CORN = 2'd01;
localparam RETU = 2'd10;

reg [1:0] mode,next_mode;
always @ (posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        mode <= INIT;
    end else begin
        mode <= next_mode;
    end
end

reg is_corn_finish;
always @ (*) begin
    case (mode)
        INIT:begin
            if (want_val) begin
                next_mode = CORN;
            end else begin
                next_mode = INIT;
            end
        end
        CORN:begin
            if (is_corn_finish) begin
                next_mode = RETU;
            end else begin
                next_mode = CORN;
            end
        end
        RETU:next_mode = INIT;
        default : next_mode = INIT;
    endcase
end

reg store_type;
always @ (posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        store_type <= 1'b0;
    end else if(want_val)begin
        store_type <= want_type;
    end
end

reg [1:0]corn_num,next_corn_num;
always @ (posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        corn_num <= 2'd0;
    end else if (mode == INIT) begin
        corn_num <= 2'd0;
    end else if (mode == CORN && corn_val) begin
        corn_num <= next_corn_num;
    end
end
always @ (*) begin
    if (corn_type == 1'b0) begin
        next_corn_num = corn_num + 1'd1;
    end else begin
        next_corn_num = corn_num + 2'd2;
    end
end

always @ (*) begin
    if (store_type == 1'b0 && next_corn_num >= 2'd1) begin
        is_corn_finish = 1'b1;
    end else if (store_type == 1'b1 && next_corn_num >= 2'd2) begin
        is_corn_finish = 1'b1;
    end else begin
        is_corn_finish = 1'b0;
    end
end

always @ (posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        return_store <= 1'b0;
    end else if (next_mode == RETU) begin
        return_store <= 1'b1;
    end else begin
        return_store <= 1'b0;
    end
end
always @ (posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        return_corn <= 1'b0;
    end else if (next_mode == RETU && !store_type && next_corn_num > 2'd1) begin
        return_corn <= 1'b1;
    end else if (next_mode == RETU && store_type && next_corn_num > 2'd2) begin
        return_corn <= 1'b1;
    end else begin
        return_corn <= 1'b0;
    end
end

endmodule

50%占空比分频器

module frequence_divider #(
    parameter CWIDTH = 8
) (
    input clk,    // Clock
    input rst_n,  // Asynchronous reset active low
    
    input cfg_val,
    input [CWIDTH - 1:0]cfg_data,

    output reg clock_div

);

reg [CWIDTH - 1:0] cfg;
always @ (posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        cfg <= {CWIDTH{1'b0}};
    end else if (cfg_val) begin
        cfg <= cfg_data;
    end
end

reg [CWIDTH - 1:0] count_pos;
always @ (posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        count_pos <= {CWIDTH{1'b0}};
    end else if (count_pos >= cfg) begin
        count_pos <= {CWIDTH{1'b0}};
    end else begin
        count_pos <= count_pos + 1'b1;
    end
end

reg [CWIDTH - 1:0] count_neg;
always @ (negedge clk or negedge rst_n) begin
    if (~rst_n) begin
        count_neg <= {CWIDTH{1'b0}};
    end else begin
        count_neg <= count_pos;
    end
end

wire [CWIDTH - 1:0] judge = {1'b0,cfg_data[CWIDTH - 1:1]} + 1'b1;

always @ (*) begin
    if (cfg == {CWIDTH{1'b0}}) begin
        clock_div = clk;
    end else if (cfg[0] == 'b1) begin
        clock_div = (count_pos < judge)?1'b1:1'b0;
    end else begin
        clock_div = (count_pos < judge && count_neg < judge)?1'b1:1'b0;
    end
end

endmodule

格雷码计数器

第一种写法,节约寄存器,时序比较慢

module gray_count #(
    parameter WIDTH = 4
) (
    input clk,    // Clock
    input rst_n,  // Asynchronous reset active low

    output reg [WIDTH - 1:0] dout_gray
);

one methed
wire [WIDTH - 1:0] count_bin,next_count_bin,next_count_gray;

genvar i;
generate
    for (i = 0; i < WIDTH; i = i + 1) begin:gray
        if (i == WIDTH - 1) begin
            assign count_bin[i] = dout_gray[i];
            assign next_count_gray[i] = next_count_bin[i];
        end else begin
            assign count_bin[i] = dout_gray[i] ^ count_bin[i + 1];
            assign next_count_gray[i] = next_count_bin[i] ^ next_count_bin[i + 1];
        end
    end
endgenerate
assign next_count_bin = count_bin + 1'b1;

always @ (posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        dout_gray <= {WIDTH{1'b0}};
    end else begin
        dout_gray <= next_count_gray;
    end
end
endmodule

第二种写法,多用一套寄存器,时序较好

module gray_count #(
    parameter WIDTH = 4
) (
    input clk,    // Clock
    input rst_n,  // Asynchronous reset active low

    output reg [WIDTH - 1:0] dout_gray
);

reg [WIDTH - 1:0]count_bin;
wire [WIDTH - 1:0] next_count_bin = count_bin + 1'b1;
always @ (posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        count_bin <= {WIDTH{1'b0}};
    end else begin
        count_bin <= next_count_bin;
    end
end

wire [WIDTH - 1:0] next_count_gray;
genvar i;
generate
    for (i = 0; i < WIDTH; i = i + 1) begin:gray
        if (i == WIDTH - 1) begin
            assign next_count_gray[i] = next_count_bin[i];
        end else begin
            assign next_count_gray[i] = next_count_bin[i] ^ next_count_bin[i + 1];
        end
    end
endgenerate

always @ (posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        dout_gray <= {WIDTH{1'b0}};
    end else begin
        dout_gray <= next_count_gray;
    end
end
endmodule

常见协议

I2C

I2C是由 Phiilps提出的一种串行协议,具有两根信号线,分别为:

静默时,SCL和SDA均为1,传输开始和结束如下所示:

具体如下图所示:

其中S为SCL高且SDA拉低,表示传输开始;P为SCL高且SDA拉高,表示传输结束。数据部分输入与输出共享信号线SDA,数据的传输需要满足以下要求:

如下图所示:

整体传输如下图所示:

主机发送开始信号即可开始传输数据,发送8bit后有一个ACK信号需要传输,即主机发送第9个脉冲,同时释放总线,若从机在第9个脉冲为高前将其数据拉低并保持到第9个脉冲结束,则表示为ACK,从机响应主机传输,可继续传输;否则为NACK,应当结束传输。

UART

UART为一个全双工的双线协议,每一根线负责一个方向,分为TX和RX,每根线上一次传输如下:

由于线上没有相关时钟,因此时钟靠通信双方进行约定。当通信双方时钟不同时,会出现数据乱码问题。时钟的约定靠波特率完成,在UART中波特率一般与比特率等效,即每秒钟发送的bit数量。对于一个下图的传输,需要1bit起始位,7bit数据位,1bit校验位,1bit停止位,一次传输一共需要10bit,以波特率为9600为例,1s可以发送9600bit,因此一共可以进行960次传输,此时时钟频率被约定为1/9600。

根据上图,起始状态为高,当需要发送数据时,将该信号拉低,即第一个bit为起始帧。随后发送数据,低位优先,发送约定好的数据bit位数后,发送奇偶检验位,最后拉高,表示一次数据发送完成。

SPI

上一篇 下一篇

猜你喜欢

热点阅读