数字IC秋招真题回忆整理

持续更新中....

以下均为秋招做过的真题。

因为一些众所周知的原因,就不透露是具体是哪些公司的题了

祝大家都收到心仪的offer!


一、手撕

1.全加器

半加器:只有两个加数,无进位;S = A ^ B; Cout=AB;

全加器:S = A^B^C;  Cout = AB + Cin(A^B)

求和位:奇数个1,求和为1,所以是异或

进位:两个加数都为1;进位为1,一个以上的加数为1;

组合逻辑写法:

module full_adder_combinational (
    input [3:0] A,
    input [3:0] B,
    input cin,
    output [3:0] sum,
    output cout
);
    
    wire [3:0] carry;
    
    // 第一位全加器
    assign sum[0] = A[0] ^ B[0] ^ cin;
    assign carry[0] = (A[0] & B[0]) | (A[0] & cin) | (B[0] & cin);
    
    // 第二位全加器
    assign sum[1] = A[1] ^ B[1] ^ carry[0];
    assign carry[1] = (A[1] & B[1]) | (A[1] & carry[0]) | (B[1] & carry[0]);
    
    // 第三位全加器
    assign sum[2] = A[2] ^ B[2] ^ carry[1];
    assign carry[2] = (A[2] & B[2]) | (A[2] & carry[1]) | (B[2] & carry[1]);
    
    // 第四位全加器
    assign sum[3] = A[3] ^ B[3] ^ carry[2];
    assign carry[3] = (A[3] & B[3]) | (A[3] & carry[2]) | (B[3] & carry[2]);
    
    assign cout = carry[3];
    
endmodule
时序逻辑写法

module full_adder_sequential (
    input clk,
    input rst,
    input [3:0] A,
    input [3:0] B,
    input cin,
    output reg [3:0] sum,
    output reg cout
);
    
    reg [3:0] A_reg, B_reg;
    reg cin_reg;
    reg [3:0] carry;
    
    always @(posedge clk or posedge rst) begin
        if (rst) begin
            A_reg <= 4'b0;
            B_reg <= 4'b0;
            cin_reg <= 1'b0;
            sum <= 4'b0;
            cout <= 1'b0;
            carry <= 4'b0;
        end else begin
            // 锁存输入
            A_reg <= A;
            B_reg <= B;
            cin_reg <= cin;
            
            // 计算每一位的和与进位
            sum[0] <= A_reg[0] ^ B_reg[0] ^ cin_reg;
            carry[0] <= (A_reg[0] & B_reg[0]) | (A_reg[0] & cin_reg) | (B_reg[0] & cin_reg);
            
            sum[1] <= A_reg[1] ^ B_reg[1] ^ carry[0];
            carry[1] <= (A_reg[1] & B_reg[1]) | (A_reg[1] & carry[0]) | (B_reg[1] & carry[0]);
            
            sum[2] <= A_reg[2] ^ B_reg[2] ^ carry[1];
            carry[2] <= (A_reg[2] & B_reg[2]) | (A_reg[2] & carry[1]) | (B_reg[2] & carry[1]);
            
            sum[3] <= A_reg[3] ^ B_reg[3] ^ carry[2];
            carry[3] <= (A_reg[3] & B_reg[3]) | (A_reg[3] & carry[2]) | (B_reg[3] & carry[2]);
            
            cout <= carry[3];
        end
    end
    
endmodule

2.奇数分频器

5分频,占空比50%,依然计数5,两个高电平。

module exercise(
    input  clk, rst,
    output wire clk5
);

reg [2:0] cnt1,cnt2;
reg q0,q1;

always@(posedge clk or negedge rst)
    if(!rst)            cnt1 <= 0;
    else if(cnt1 == 3'd4) cnt1 <= 0;
    else                cnt1 <= cnt1 + 1;

always@(negedge clk or negedge rst)
    if(!rst)            cnt2 <= 0;
    else if(cnt2 == 3'd4)  cnt2 <= 0;
    else                cnt2 <= cnt2 + 1;

always@(posedge clk or negedge rst)
    if(!rst)            q0 <= 0;
    else if((cnt1 == 0) || (cnt1 == 3'd2 ))     q0 <= ~q0;
    else  q0 <= q0;

always@(negedge clk or negedge rst)
    if(!rst)            q1 <= 0;
    else if((cnt2 == 0) || (cnt2 == 3'd2 ))     q1 <= ~q1;
    else  q1 <= q1;

 assign   clk5 = q0 | q1;

endmodule

使用DC命令定义时钟,并约束关联时钟之间的关系

3.双边沿检测电路

module dual_edge_detector (
    input wire clk,      
    input wire rst_n,    
    input wire signal,   // 输入信号
    output reg any_edge  // 双边沿检测输出
);

    reg signal_dly;      // 输入信号延迟一拍

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            signal_dly <= 1'b0;
            any_edge <= 1'b0;
        end else begin
            signal_dly <= signal;               // 缓存上一拍的值
            any_edge <= signal ^ signal_dly;    // 检测任何变化
        end
    end

endmodule

4.求输入序列中最大的两个值

module top2_sort
#(
    parameter DWIDTH = 8  // 数据位宽参数
)
(
    input                 clk    ,   // 时钟
    input                 rst_n  ,   // 异步复位(低有效)
    input                 srst   ,   // 同步复位
    input  [DWIDTH -1:0]  din    ,   // 串行输入数据
    input                 din_vld,   // 输入数据有效信号
    output reg [DWIDTH -1:0] dout_top1, // 输出最大值
    output reg [DWIDTH -1:0] dout_top2, // 输出次大值
    output reg              dout_vld  // 输出有效信号
);

// 时序逻辑:在时钟上升沿、复位时更新最大/次大值
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin  
        dout_top1 <= {DWIDTH{1'b0}};
        dout_top2 <= {DWIDTH{1'b0}};
        dout_vld <= 1'b0;
    end else if (srst) begin  // 同步复位:同样初始化
        dout_top1 <= {DWIDTH{1'b0}};
        dout_top2 <= {DWIDTH{1'b0}};
        dout_vld <= 1'b0;
    end else begin
        if (din_vld) begin  // 输入数据有效时,进行最大、次大值的更新
            if (din > dout_top1) begin  // 新数据比当前最大值还大
                dout_top2 <= dout_top1; // 原最大值降级为“次大值”
                dout_top1 <= din;       // 新数据成为“最大值”
            end else if (din > dout_top2) begin  // 新数据小于最大值、但大于次大值
                dout_top2 <= din;       // 新数据成为“次大值”
            end
            dout_vld <= 1'b1;  
        end
    end
end

endmodule

二、时序

三、问答

说明同步复位,异步复位,同步复位异步释放的实现方法以及各自的优缺点。

  • 同步复位:复位信号只在时钟的有效边沿(上升沿或下降沿)起作用,即只有时钟边沿来临时,才会检测复位信号。优点是抗干扰能力强,可靠性高,利于静态时序分析;缺点复位必须等待时钟有效沿才能起作用,所以复位信号可能较长。、
  • 异步复位:复位信号一旦有效,会立即生效,无需等待时钟边沿。优点是响应快,但缺点是复位信号的不正确释放可能会导致亚稳态问题。
  • 异步复位,同步释放:复位信号是异步有效的(立即生效),但复位释放是同步的(避免亚稳态)。优点是响应快,且由于是同步释放,即在复位结束后能更稳定的进入工作状态,电路更稳定。缺点是设计更复杂,增加设计和验证的工作量。(同步释放需要多一个always块来给复位信号进行至少1级打拍,输出和时钟同步后的复位信号供后面的电路使用)
异步释放,同步复位
module reset_sync (
    input wire clk,
    input wire async_rst_n, // 来自外部的异步复位
    output wire sync_rst_n  // 同步化后的复位信号
);

reg rst_n_meta, rst_n_sync;

always @(posedge clk or negedge async_rst_n) begin
    if (!async_rst_n) begin
        // 异步复位有效时,两级寄存器都清零
        rst_n_meta <= 1'b0;
        rst_n_sync <= 1'b0;
    end else begin
        // 异步复位释放后,通过两级DFF同步
        rst_n_meta <= 1'b1;
        rst_n_sync <= rst_n_meta;
    end
end

assign sync_rst_n = rst_n_sync; // 将同步化后的复位信号输出

endmodule

低电平复位的意思:在低电平时系统在进行复位;虽然写成@negedge rstn,看似是检测到下降沿系统复位,但实际是等到rstn变成低电平后系统才开始复位。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值