数字IC笔试题(2)

学习摘自数字芯片实验室

1、复数计算(a + bj)*(c + dj) = (ac – bd) + (bc + ad)j,需要四个乘法器才能在一个时钟周期里计算完成,如何优化才能只需要三个乘法器在一个时钟周期里计算完成。

思路1:

ac -bd = (a – b)d + (c – d)a
ad+ bc = (a - b)d + (c + d)b

(a- b)d可以复用

思路2:

ac-bd =a(c-d)+d(a-b)
bc+ad =c(a+b)-a(c-d)

a(c-d)可以复用

和思路1和思路2相似的,还有很多

思路3:

bc + ad = (a+b)(c+d) – ac-bd

ac和bd可以复用

思路4:

bc + ad = (a-b)(d-c) +ac+bd

ac和bd可以复用

和思路3和思路4相似的,还有很多

2、时钟输入clk_in, sel为时钟控制信号,sel=0输出clk_in, sel = 1 输出clk_i的四分频,要求异步复位,保持时钟信号的完整性。

module clk_div(
    input clk_in,
    input rst_n,
    output clk_div4
);
 
reg[1:0] cnt;
 
always@ (posedge clk_in or negedge rst_n)
    if (~rst_n) begin
        cnt <= 2'b0;
    end else begin
        cnt <= cnt + 1'b1;
    end
 
 
assign clk_div4 = cnt[1];
 
endmodule
 
 
module clk_switch(
    input  wire    clk_a,
    input  wire    clk_b,
    input  wire    rst_n,
    input  wire    sel  ,
    output wire    clk_o
 );
 
 // variable declaration
 reg    clk_a_en ;
 reg    clk_b_en ;
 
 // logic
 always @(negedge clk_a or negedge rst_n) begin
     if(~rst_n)                          clk_a_en     <= 1'b0               ;
     else                                clk_a_en     <= ~sel & ~clk_b_en   ;
 end
 always @(negedge clk_b or negedge rst_n) begin
     if(~rst_n)                          clk_b_en     <= 1'b0               ;
     else                                clk_b_en     <= sel  & ~clk_a_en   ;
 end
 assign clk_o   =   (clk_a & clk_a_en) | (clk_b &clk_b_en) ;
 
 
 endmodule
 
module clk_switch_top(
    input clk_in,
    input sel,
    input rst_n,
    output clk_o
);
wire clk_b;
clk_div clk_div_inst(
    .clk_in(clk_in),
    .rst_n(rst_n),
    .clk_div4(clk_b)
);
 
clk_switch clk_switch_inst(
    .clk_a(clk_in),
    .clk_b(clk_b),
    .rst_n(rst_n),
    .sel(sel),
    .clk_o(clk_o)
);
 
endmodule

Testbench:

module clk_switch_tb;
 
 reg    clk_in   ;
 reg    rst_n   ;
 reg    sel     ;
 wire   clk_o   ;
 
 always #3 clk_in = ~clk_in;
 
 initial
 begin
     clk_in = 0;
     sel = 0;
     rst_n = 1;
     #10
     rst_n = 0;
     #7
     rst_n = 1;
     #10
     sel = 1;
     #10
     sel = 0;
     #37
     sel = 1;
 
 
 end
clk_switch_top top_inst(
    .clk_in(clk_in),
    .sel(sel),
    .rst_n(rst_n),
    .clk_o(clk_o)
);
 
endmodule

在这里插入图片描述
需要注意的是,需要避免开关过程中产生毛刺,需要使用下降沿驱动。使用上升沿驱动的话,结果会如下图所示:(箭头处出现毛刺)
在这里插入图片描述

3、一个16bit序列,每个clk左移一位,要求检测5的倍数。

思路:把这个16bit数看作是4个16进制数

那么假设该数为ABCD,则这个数字10进制为A163+B*162+C161+D*160,可以展开为A*(15+1)3+B*(15+1)2+C*(15+1)+D,移除能被5整除的项→A+B+C+D,所以只需要判断A+B+C+D能否被5整除。

module five(
   input clk,
   input rst_n,
   input a,
   output reg b
);
reg [15:0] seq;
always @ (posedge clk or negedgerst_n)
   if (!rst_n)
       seq <= 16'b0;
   else
       begin
            seq <= {seq[14:0],a};
            b <=(((seq[15:12]+seq[11:8]+seq[7:4]+seq[3:0])%5)==0);
       end
endmodule


module five_tb;
reg clk;
reg rst_n;
reg a;
wire b;


always #1 clk=~clk;

initial
begin
   clk=0;
   rst_n=1;
   a=0;
   #4
   rst_n=0;
   #4
   rst_n=1;
   #2
   a=0;
   #2
   a=1;
   #2
   a=0;
   #2
   a=1;
   #2
   a=0;
   #30
   $stop;
end

five five_inst(
   .clk(clk),
   .rst_n(rst_n),
   .a(a),
   .b(b)
);
endmodule

原题是:一个16bit序列,每个clk左移一位,要求检测5的倍数。

前面的第二种思路

可以使用一个状态机实现。

在这里插入图片描述

s0表示余0,s1表示余1,s3表示余3,s4表示余4

一开始16bit全为0,所以是s0状态(余0),如果下一bit进来1,那就是16’h0001,就是s1状态(余1),如果下一bit进来0,那就是16’h0002,就是s2状态(余2),以此类推。只有在s0状态,out输出1

five_2.v:

module five_2(
    input clk,
    input rst_n,
    input a,
    output reg b
);
 
reg[15:0] seq;
 
rega_reg ;
always@ (posedge clk or negedge rst_n) begin
    if (!rst_n)
        a_reg <= 0;
    else
        begin
            a_reg <= a;
        end
end
 
always@ (posedge clk or negedge rst_n) begin
    if (!rst_n)
        seq <= 16'b0;
    else
        begin
            seq <= {seq[14:0],a_reg};
        end
end
 
parameterS0 = 3'b000,S1 = 3'b001,S2 = 3'b010,S3 = 3'b011,S4 = 3'b100 ;
reg[2:0] current_state,next_state ;
always@(posedgeclk or negedge rst_n) begin
    if(!rst_n) begin
        current_state <= S0 ;
        b <= 1'b0 ;
    end
    else begin
        current_state <= next_state ;
        if(current_state == S0) begin
            b <= 1 ;
        end
        else begin
            b <= 0 ;
        end
    end
end
 
always@(*)begin
    case(current_state)
        S0:begin
            if(a == 1'b1) next_state = S1 ;
            else next_state = S0 ;
        end
        S1:begin
            if(a == 1'b1) next_state = S3 ;
            else next_state = S2 ;
        end
        S2:begin
            if(a == 1'b1) next_state = S0 ;
            else next_state = S4 ;
        end
        S3:begin
            if(a == 1'b1) next_state = S2 ;
            else next_state = S1 ;
        end
        S4:begin
            if(a == 1'b1) next_state = S4 ;
            else next_state = S3 ;
        end
    endcase
end
 
 
endmodule

使用之前同样的Testbench

在这里插入图片描述

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

猜你喜欢

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