侧边栏壁纸
    • 累计撰写 302 篇文章
    • 累计收到 527 条评论
    联发科2024年数字IC设计验证实习生考题解析
    我的学记|刘航宇的博客

    联发科2024年数字IC设计验证实习生考题解析

    刘航宇
    2023-04-23 / 0 评论 / 1,132 阅读 / 正在检测是否收录...


    1、(20分)逻辑化简:


    (1)列出真值表
    (2)列出其卡诺图
    (3)写出Z的最简表达式
    答:卡诺图:卡诺图画完后勾1就完事了

    提示:约束项的一般形式为:与或式 = 0 (如果不是此种形式,化为此种形式);如此题的BC = 0;或者AB +CD = 0;ABC + CD = 0;等等。BC=0(即B=1,且C=1)对应的格子画X。

    2、(5分)ASIC flow 中综合工具的作用是什么?综合的时候需要SDC文件进行约束,请列举3条SDC的语法。

    答:ASIC flow 中综合工具的作用是将RTL级的硬件描述语言转换为与特定工艺库相匹配的门级网表,同时进行优化以满足时序、面积和功耗等约束。

    综合的时候需要SDC文件进行约束,SDC文件是一种基于Tcl的格式,用于指定设计的时序约束34。SDC文件中的常用时序约束语法有:

    create_clock -name <clock_name> -period <clock_period> [get_ports <clock_port>] 用于创建时钟源并指定时钟周期。
    set_input_delay -clock <clock_name> <delay_value> [get_ports <input_port>] 用于指定输入端口相对于时钟源的延迟。
    set_output_delay -clock <clock_name> <delay_value> [get_ports <output_port>] 用于指定输出端口相对于时钟源的延迟。
    set_clock_uncertainty -setup <setup_value> -hold <hold_value> <clock_name> 用于指定时钟源的不确定性,包括建立时间和保持时间。
    set_false_path -from [get_ports <source_port>] -to [get_ports <destination_port>] 用于指定不需要进行时序分析的路径。
    set_multicycle_path -setup -from [get_clocks <source_clock>] -to [get_clocks <destination_clock>] <cycle_number> 用于指定多周期路径,即源时钟和目标时钟之间有多个周期的时间差。

    3、(10分)智力题

    (1)2 12 1112 3112 132112 ,下一个数?给理由;
    答:第一个数是2,第二个数是12,表示前一个数有1个2;第三个数是1112,表示前一个数有1个1和1个2;以此类推。所以,下一个数是1113122112,表示前一个数有1个1,1个3,2个1和2个2
    (2)有一个小偷费劲力气进入到了银行的金库里。在金库里他找到了一百个箱子,每一个箱子里都装满了金币。不过,只有一个箱子里装的是真的金币,剩下的99个箱子里都是假的。真假金币的外形和质感完全一样,任何人都无法通过肉眼分辨出来。它们只有一个区别:真金币每一个重量为101克,而假金币的重量是100克。在金库里有一个电子秤,它可以准确地测量出任何物品的重量,精确到克。但很不幸的是,这个电子秤和银行的报警系统相连接,只要被使用一次就会立刻失效。请问,小偷怎么做才能只使用一次电子秤就找到装着真金币的箱子呢?
    答:小偷可以这样做:从第一个箱子里拿出1个金币,从第二个箱子里拿出2个金币,从第三个箱子里拿出3个金币,以此类推,直到从第一百个箱子里拿出100个金币。然后,把所有拿出来的金币放在电子秤上,测量它们的总重量。如果所有的金币都是假的,那么总重量应该是5050克(等于1+2+3+…+100)。如果有一个箱子里是真的金币,那么总重量会比5050克多出一些。这个多出来的部分就是真金币的数量乘以1克。例如,如果第十一个箱子里是真的金币,那么总重量会比5050克多出11克,因为从第十一个箱子里拿出了11个真金币。所以,小偷只要看电子秤上显示的数字减去5050,就能知道哪个箱子里是真的金币了。

    4、(10分)选择参与过的任一个项目,简述项目内容以及流程,讲述您在项目中承担的任务,挑一项你认为难的地方并阐述解决方案。

    答:优先答ASIC的设计与验证项目,其次是FPGA项目(如基于FPGA的图像处理、天线阵、雷达、加速器等等),其它项目不要答。

    5、(5分)用python写一个冒泡排序的函数以及测试程序。

    # 定义冒泡排序函数
    def bubble_sort(lst):
        # 获取列表长度
        n = len(lst)
        # 遍历列表n-1次
        for i in range(n-1):
            # 设置一个标志,用于判断是否发生交换
            swapped = False
            # 遍历未排序的部分
            for j in range(n-1-i):
                # 如果前一个元素大于后一个元素,交换位置
                if lst[j] > lst[j+1]:
                    lst[j], lst[j+1] = lst[j+1], lst[j]
                    # 标志设为True,表示发生了交换
                    swapped = True
            # 如果没有发生交换,说明列表已经有序,提前结束循环
            if not swapped:
                break
        # 返回排序后的列表
        return lst
    
    # 定义测试程序
    # 创建一个乱序的列表
    lst = [5, 3, 8, 2, 9, 1, 4, 7, 6]
    # 打印原始列表
    print("Original list:", lst)
    # 调用冒泡排序函数,对列表进行排序
    lst = bubble_sort(lst)
    # 打印排序后的列表
    print("Sorted list:", lst)

    结果图
    image.png

    6、(15分)用Verilog 写一个 Round Robin 仲裁器。模块端口如下:

    input clock;
    
    input reset_b;
    
    input [N-1:0] request;
    
    input [N-1] lock;
    
    output [N-1] grant; //one-hot

    此处的 lock 输入信号,表示请求方收到了仲裁许可,在对应的lock拉低之前,仲裁器不可以开启新的仲裁。(可简单理解为仲裁器占用)
    该题要求参数化编程,在模块例化时可调整参数。也即是说你不能写一个固定参数,比如N=8的模块。
    参考波形图:
    image.png
    答:

    // 功能:
    //         -1- Round Robin 仲裁器
    //      -2- 仲裁请求个数N可变
    //         -3- 加入lock机制(类似握手)
    //         -4- 复位时的最高优先级定为 0 ,次优先级:1 -> 2 …… -> N-2 -> N-1
    `timescale 1ns / 1ps
    module RoundRobinArbiter #(
    parameter         N = 4 //仲裁请求个数
    )(
    input                             clock,
    input                             reset_b,
    input             [N-1:0]            request,
    input             [N-1:0]            lock,
    output reg         [N-1:0]         grant//one-hot
        );
    // 模块内部参数
     
    localparam IDLE             = 3'b001;// 复位进入空闲状态,接收并处理系统的初次仲裁请求
    localparam WAIT_REQ_GRANT  = 3'b010;// 等待后续仲裁请求到来,并进行仲裁
    localparam WAIT_LOCK        = 3'b100;// 等待LOCK拉低
     
    // 模块内部信号
    reg [2:0]   R_STATUS; //请求状态
    reg [N-1:0] R_MASK; //掩码
    wire [N-1:0] W_REQ_MASKED;
     
    assign W_REQ_MASKED = request & R_MASK; //屏蔽低位
     
    always @ (posedge clock)
    begin
        if(~reset_b)
        begin
            R_STATUS <= IDLE;
            R_MASK <= 0;
            grant <= 0;
        end
        else
        begin
            case(R_STATUS)
            IDLE:
            begin
                if(|request) //首次仲裁请求,不全为0
                begin
                    R_STATUS <= WAIT_LOCK;
    //首先需要找到request中优先级最高的比特位,对优先级最高的比特位给出许可信号。
    //这一步可以通过request和它的2的补码按位与。这是因为一个数和它的补码相与,得到的结果是一个独热码,独热码为1的那一位是这个数最低的1
                    grant <= request & ((~request)+1);
                    R_MASK <= ~((request & ((~request)+1))-1 | (request & ((~request)+1)));    
    //得到掩码的方法是,对第一步的许可信号grant-1,再与grant本身相或,相或的结果再取反。
                end
                else
                begin
                    R_STATUS <= IDLE;
                end
            end     
            WAIT_REQ_GRANT://处理后续的仲裁请求
            begin
                if(|request)
                begin
                    R_STATUS <= WAIT_LOCK;
    //在下一轮仲裁中,已经被仲裁许可的比特位变成了最低优先级,而未被仲裁许可的比特位将会被仲裁。
    //因此对第一步中给出许可的比特位(假设是第2位)以及它的低比特位进行屏蔽,对request中的第5位到第3位进行保持
    //这个操作可以利用掩码111000和request相与实现得到。
                    if(|(request & R_MASK))//不全为零
                    begin
                        grant <= W_REQ_MASKED & ((~W_REQ_MASKED)+1);
                        R_MASK <= ~((W_REQ_MASKED & ((~W_REQ_MASKED)+1))-1 | (W_REQ_MASKED & ((~W_REQ_MASKED)+1)));
                    end
                    else
                    begin
                        grant <= request & ((~request)+1);
                        R_MASK <= ~((request & ((~request)+1))-1 | (request & ((~request)+1)));
                    end
                end
                else
                begin
                    R_STATUS <= WAIT_REQ_GRANT;            
                    grant <= 0;            
                    R_MASK <= 0;            
                end
            end
    //通过第二步得到第2位到第0位被屏蔽的request_new信号,
    //判断request_new是否为全0信号,如果是全0信号,代表此时不存在需要被仲裁的比特位,则返回第一步:找到request中优先级最高的比特位,
    //对优先级最高的比特位给出许可信号,然后进行第二步。如果request_new不是全0信号,代表存在未被仲裁的比特位,
    //则找到request_new中优先级最高的比特位,对优先级最高的比特位给出许可信号,然后进行第二步。
            WAIT_LOCK:
            begin
                if(|(lock & grant)) //未释放仲裁器        
                begin        
                    R_STATUS <= WAIT_LOCK;        
                end        
                else if(|request) //释放的同时存在仲裁请求         
                begin        
                    R_STATUS <= WAIT_LOCK;
                    if(|(request & R_MASK))//不全为零
                    begin
                        grant <= W_REQ_MASKED & ((~W_REQ_MASKED)+1);
                        R_MASK <= ~((W_REQ_MASKED & ((~W_REQ_MASKED)+1))-1 | (W_REQ_MASKED & ((~W_REQ_MASKED)+1)));
                    end
                    else
                    begin
                        grant <= request & ((~request)+1);
                        R_MASK <= ~((request & ((~request)+1))-1 | (request & ((~request)+1)));
                    end        
                end
                else
                begin
                    R_STATUS <= WAIT_REQ_GRANT;
                    grant <= 0;            
                    R_MASK <= 0;
                end        
            end        
            default:        
            begin
                R_STATUS <= IDLE;
                R_MASK <= 0;
                grant <= 0;
            end
            endcase
        end
    end
    endmodule

    测试代码

    `timescale 1ns / 1ps
    module RoundRobinArbiter_tb;
    
      parameter N = 4; // 可以在测试时调整参数
    
      // 定义测试信号
      reg clock;
      reg reset_b;
      reg [N-1:0] request;
      reg [N-1:0] lock;
      wire [N-1:0] grant;
    
     // 定义时钟信号
    initial clock = 0;
    always #10 clock = ~clock;
    
    
      // 实例化仲裁器模块
      RoundRobinArbiter  #(
            .N(N)
        ) inst_RoundRobinArbiter (
            .clock   (clock),
            .reset_b (reset_b),
            .request (request),
            .lock    (lock),
            .grant   (grant)
        );
    
      // 定义时钟周期和初始值
      initial begin
        reset_b <= 1'b0;
        request <= 0;
        lock <= 0;
      end
    
      // 定义请求和锁定信号的变化
      initial begin
        #20;
        reset_b <= 1'b1;
        @(posedge clock)
        request <= 2;
        lock <= 2;
     
        @(posedge clock)
        request <= 0;
     
        @(posedge clock)
        request <= 5;
        lock <= 7;
     
        @(posedge clock)
        lock <= 5;
     
        @(posedge clock)
        request <= 1;
     
        @(posedge clock)
        lock <= 1;
     
        @(posedge clock)
        request <= 0;
     
        @(posedge clock)
        lock <= 0;
        #1000 $stop; // 测试结束
       end
    
       // 显示测试结果和波形图
       initial begin
         $monitor("Time=%t, clock=%b, reset_b=%b, request=%b, lock=%b, grant=%b",
                  $time, clock, reset_b, request, lock, grant);
         $dumpfile("RoundRobinArbiter_tb.vcd");
         $dumpvars(0,RoundRobinArbiter_tb);
       end
    
    endmodule

    结果:
    image.png
    如果对波形图无法理解可以看此博文
    https://blog.csdn.net/m0_49540263/article/details/114967443

    7、(15分)关于DMA寄存器配置,DMA寄存器(地址 0x81050010)表:

    image.png
    image.png
    Type 表示读写类型。Reset 表示复位值。

    写一个C函数 void dma_driver(void),按步骤完成以下需求:

    分配DMA所需的源地址(0x30)
    分配DMA所需的目的地址(0x300)
    设置传输128 Byte 数据
    开始DMA传输
    等待DMA传输结束
    答:

    // 假设有以下宏定义
    #define DMA_REG 0x81050010 // DMA控制寄存器的地址
    #define DMA_SRC_ADDR 0x30 // DMA源地址
    #define DMA_DST_ADDR 0x300 // DMA目的地址
    #define DMA_SIZE 128 // DMA传输大小
    #define DMA_START 1 // DMA开始传输的标志位
    
    // 定义C函数 void dma_driver(void)
    void dma_driver(void) {
      // 定义一个指向DMA控制寄存器的指针
      volatile uint32_t *dma_reg = (volatile uint32_t *)DMA_REG;
      // 清空DMA控制寄存器的值
      *dma_reg = 0;
      // 设置DMA源地址,目的地址和传输大小
      *dma_reg |= (DMA_SRC_ADDR << 2) | (DMA_DST_ADDR << 13) | (DMA_SIZE << 24);
      // 开始DMA传输
      *dma_reg |= DMA_START;
      // 等待DMA传输结束
      while (*dma_reg & DMA_START) {
        // 可以在这里做一些其他的事情,比如打印日志或者检查错误
        // printf("Waiting for DMA to finish...\n");
        // check_error();
      }
    }

    8、(20分)二阶带通滤波器,利用RC组件搭建,通带范围 1kHz~30kHz ,两个电阻 R 均为10kΩ ,问两个电容容值多少?

    答:第一步首得知道二阶带通(RC)滤波器的电路长啥样,高、低通组合一下就是带通,自己思考一下高、低通组合:如串联或并联,会得到带通还是带组?
    电路图:
    H___H21L__E34_WC@43F1_8.jpg
    这个一看就是总传递函数=A1*A2(模电二阶有源或无源滤波器绝对有)
    _LIYXIHR_08YNK__EV8SXDH.jpg
    然后化简
    X25LO__~TXMGO59LTLV@9S9.jpg
    根据推导得到的表达式,对于 jwRC2 ,这一项,当 w 趋于无穷大时,uo/ui 趋于零。那么高频的临界点就是 wRC2 = 1+2C2/C1;(此时忽略低频项1/jwRC1)
    同理,对于低频项 1 /jwRC1, w 趋于无穷小时,uo/ui 趋于零 ,那么低频的临界点就是 1/wRC1 = 1+2C2/C1;然后解二元一次方程两个电容就被解出来了
    这里提供一种更简单方法:
    二阶带通滤波器的中心频率 f0 和品质因数 Q 可以用下面的公式计算:
    image.png
    已知 R1 = R2 = 10kΩ,f0 = (1kHz + 30kHz) / 2 = 15.5kHz,Q = f0 / (30kHz - 1kHz) = 0.54,代入上面的公式,可以求得:
    image.png
    这是一个二元一次方程组,可以用任意方法求解,例如消元法或代入法。为了方便起见,我们假设 C1 和 C2 的值相近,那么可以近似地认为 C1 = C2 = 3.45nF。这样就得到了两个电容的容值。当然,也可以选择其他的电容值,只要满足上面的方程组即可。

    7
    机器学习代码实现:线性回归与岭回归
    « 上一篇 2023-05-15
    MIMO波束赋形技术简介
    下一篇 » 2023-04-17

    评论 (0)

    取消