数字IC笔试题(3)

学习摘自数字芯片实验室

1、 如下图所示的一个LFSR结构,初值如图所示,在4个时钟周期之后,寄存器中的值从左到右的16进制表示为?
在这里插入图片描述
变化前:X[16]、X[15]、X[14] 、X[13] 、X[12]、X[11] 、X[10]、X[9] 、X[8]、X[7]、X[6]、X[5]、X[4]、X[3]、X[2]、X[1]

变化后:X[1] 、X[16]、X[15]^ X[1]、X[14] ^ X[1]、X[13]、X[12] ^ X[1]、X[11]、X[10]、X[9]、X[8]、X[7]、X[6]、X[5]、X[4]、X[3]、X[2]

初值:10_1_01_10011100001

根据上述关系,进行4个周期的转换,然后用16进制表示

2、下图中的一个三级反相器链,第一级反相器的输入电容Ci = 4fF,最后一级反相器的负载电容CL = 32fF,为使整个反相器链的延迟最小,如果第一级反相器的大小为1,第二级反相器的大小应为?第三级反相器的大小应为?
在这里插入图片描述
在这里插入图片描述

f = 2, 所以第二级反相器的大小应为2,第三级反相器的大小应为4

3、下图的电路中,flip-flop2的setup time margin = ? ns、

在这里插入图片描述
Tmargin = 10ns + 0.6ns -0.2 ns– 0.65 ns –0.35 ns – 0.45 ns = 8.95ns

建立时间余量,100M即10ns

4、下图中的电路,器件延迟如图中标注,将框内的电路作为一个寄存器,其有效setup time = ? ns,hold time = ? ns
在这里插入图片描述
有效setup time分析:

    对于D触发器而言,Tsetup = 2ns,也就是说数据信号需要提前时钟信号2ns到达触发器D端。

考虑时钟路径延迟,Tsetup_valid = Tsetup - 1ns = 1ns ;

在考虑数路径延迟:Tsetup_valid = Tsetup - 1ns +2ns = 3ns ;

有效hold time分析:

    对于D触发器而言,Thold = 2ns,也就是说数据信号需要在时钟信号到达后保持2ns

考虑时钟路径延迟,Thold_valid = Thold + 1ns = 3ns ;

在考虑数路径延迟:Thold_valid = Thold + 1ns -2ns = 1ns ;

前几天参加乐鑫的笔试,遇到一道题目,很有价值,分享给大家。
题目要求:将一个串行执行的C语言算法转化为单拍完成的并行可综合verilog。

C语言源码如下:

unsignedcharcal_table_high_first(unsignedcharvalue)
{
    unsigned char i ;
unsigned  char checksum = value ; 
    for (i=8;i>0;--i)
    {
        if (check_sum& 0x80)
        {
            check_sum = (check_sum<<1) ^ 0x31;
        }
        else
        {
            check_sum = (check_sum << 1);
        }
    }
    return check_sum;
}

算法C语言实现:

#include<stdio.h>
int main(){
    unsignedchar cal_table_high_first(unsignedcharvalue); 
    unsignedchar data;
    for (unsignedchar i = 0; i < 16;++i)
    {
         data= cal_table_high_first(i);
         printf("value =0x%0x:check_sum=0x%0x  \n", i, data);
    }
    getchar();
}
 
 
 
unsignedchar cal_table_high_first(unsignedcharvalue)
{
    unsignedchar i;
    unsigned  char check_sum = value;
    for (i = 8; i > 0;--i)
    {
         if (check_sum &0x80)
         {
             check_sum= (check_sum << 1) ^ 0x31;
         }
         else
         {
             check_sum= (check_sum << 1);
         }
    }
    return check_sum;
}

输出结果:

value =0x0:check_sum=0x0
value =0x1:check_sum=0x31
value =0x2:check_sum=0x62
value =0x3:check_sum=0x53
value =0x4:check_sum=0xc4
value =0x5:check_sum=0xf5
value =0x6:check_sum=0xa6
value =0x7:check_sum=0x97
value =0x8:check_sum=0xb9
value =0x9:check_sum=0x88
value =0xa:check_sum=0xdb
value =0xb:check_sum=0xea
value =0xc:check_sum=0x7d
value =0xd:check_sum=0x4c
value =0xe:check_sum=0x1f
value =0xf:check_sum=0x2e

C语言作为参考模型,用于后续Verilog的功能仿真。

该算法逻辑如下:

输入一个8bit的数,首先判断最高位是否为1,如果为1则左移一位,并且和8‘b00110001异或;如果最高位不为1则左移一位。此过程执行8次。
在这里插入图片描述

此时我们来看一下异或操作的真值表
在这里插入图片描述
我们可以看出:任何数与0异或都等于它本身,即0^x=x。所以我们可以把算法流程变换为:
在这里插入图片描述
8’h31 = 8’b00110001, 8’h00 = 8’b00000000,设左移前最高位为M,可以将判断左移前最高位是否为1的过程省略,直接与8’b00MM000M异或,此时流程图可以简化为:
在这里插入图片描述
由此,我们可以将循环解开,设输入为一个8bit数C[7:0],下面为解循环过程。
在这里插入图片描述
根据上述结果,可以用verilog描述。

module loop1(
   input clk,
   input rst_n,
   input [7:0] check_sum,
   output reg [7:0] check_sum_o
);
//reg [7:0] check_sum_o;
always @ (posedge clk or negedge rst_n)
       if(!rst_n)
              begin
                     check_sum_o<= 8'h0;
              end
       else
              begin
                     check_sum_o[7]<= check_sum[3]^check_sum[2]^check_sum[5];
                     check_sum_o[6]<= check_sum[2]^check_sum[1]^check_sum[4]^check_sum[7];
                     check_sum_o[5]<= check_sum[1]^check_sum[7]^check_sum[0]^check_sum[3]^check_sum[6];
                     check_sum_o[4]<= check_sum[7]^check_sum[0]^check_sum[3]^check_sum[6];
                     check_sum_o[3]<= check_sum[3]^check_sum[7]^check_sum[6];
                     check_sum_o[2]<= check_sum[2]^check_sum[6]^check_sum[5];
                     check_sum_o[1]<= check_sum[1]^check_sum[5]^check_sum[4]^check_sum[7];
                     check_sum_o[0]<= check_sum[0]^check_sum[4]^check_sum[3]^check_sum[6];
              end
      
endmodule

testbench:

module loop1_tb;
reg clk;
reg rst_n;
reg [7:0] check_sum;
wire [7:0] check_sum_o;
always #1 clk=~clk;
initial
begin
clk = 0;
rst_n = 0;
#10
rst_n = 1;
for (check_sum=0;check_sum<16;check_sum=check_sum+1)
       begin
       #2
        //check_sum = i;
        $display ("check_sum = %h",check_sum_o);
        if (check_sum == 15) $stop;
       end
//$stop;
end
loop1 loop1_i1(
       .clk(clk),
       .rst_n(rst_n),
       .check_sum(check_sum),
       .check_sum_o(check_sum_o)
);
endmodule

打印结果为:

check_sum = 00
check_sum = 31
check_sum = 62
check_sum = 53
check_sum = c4
check_sum = f5
check_sum = a6
check_sum = 97
check_sum = b9
check_sum = 88
check_sum = db
check_sum = ea
check_sum = 7d
check_sum = 4c
check_sum = 1f
check_sum = 2e
loop2.v的实现和loop1.v类似,只是代码量更少。

module loop2(
   input clk,
   input rst_n,
   input [7:0] check_sum,
   output  reg [7:0] check_sum_o
);
integer i;
//reg [7:0] check_sum_o;
reg [7:0] ccc;
always @ (posedge clk or negedge rst_n)
       if(!rst_n)
              begin
                     check_sum_o= 8'h0;
              end
       else
              begin
           ccc = check_sum;
                     for(i=0;i<8;i=i+1)
                begin
                    ccc ={ccc[6:0],1'b0}^({8{ccc[7]}} & 8'h31);
                end
           check_sum_o = ccc;
              end
      
endmodule

其实也可以将C语言函数封装成Verilog的function,然后在在单周期内进行赋值。

module loop3(
   input clk,
   input rst_n,
   input [7:0] check_sum,
   output  reg [7:0] check_sum_o
 
);
 
integer i;
 
function [7:0] cal_table_high_first;
       input[7:0] value;
       reg[7:0] ccc ;
       reg[7:0] flag ;
              begin
                                   ccc= value;
                                   for(i=0;i<8;i=i+1)
                                          begin
                                                 flag= ccc & 8'h80 ;
                                                 if(flag!= 0 ) ccc = (ccc <<1) ^ 8'h31 ;
                                                 elseccc = (ccc <<1)  ;
                                         
                                          end
                                   cal_table_high_first= ccc;
              end
 
endfunction
 
always @ (posedge clk or negedge rst_n)
       if(!rst_n)
              begin
                     check_sum_o= 8'h0;
              end
       else
              begin
                    check_sum_o<= cal_table_high_first(check_sum) ;
              end
      
endmodule

综上,loop1.v和loop2.v的主要贡献是解开了算法实现的if-else判断。至于loop3.v中,将C语言描述的功能封装成fucntion,直接单周期完成赋值的实现方式在逻辑综合后是否增加了if-else判断语句的硬件开销不在本文讨论范围内。

这和设计者施加的时序约束和综合工具算法有关。

发布了32 篇原创文章 · 获赞 2 · 访问量 1511

猜你喜欢

转载自blog.csdn.net/qq_36248682/article/details/105289784