联发科2024年数字IC设计验证实习生考题解析
我的学记|刘航宇的博客

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

刘航宇
2年前发布 /正在检测是否收录...
温馨提示:
本文最后更新于2023年04月23日,已超过702天没有更新,若内容或图片失效,请留言反馈。


1、(20分)逻辑化简:

图片[1] - 联发科2024年数字IC设计验证实习生考题解析 - 我的学记|刘航宇的博客
(1)列出真值表
(2)列出其卡诺图
(3)写出Z的最简表达式
答:卡诺图:卡诺图画完后勾1就完事了

提示:约束项的一般形式为:与或式 = 0 (如果不是此种形式,化为此种形式);如此题的BC = 0;或者AB +CD = 0;ABC + CD = 0;等等。BC=0(即B=1,且C=1)对应的格子画X。
图片[2] - 联发科2024年数字IC设计验证实习生考题解析 - 我的学记|刘航宇的博客
图片[3] - 联发科2024年数字IC设计验证实习生考题解析 - 我的学记|刘航宇的博客

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。这样就得到了两个电容的容值。当然,也可以选择其他的电容值,只要满足上面的方程组即可。

© 版权声明
THE END
喜欢就支持一下吧
点赞 8 分享 赞赏
评论 抢沙发
取消