Verilog 学习之路(三)——牛客刷题篇

1.输入序列连续的序列检测

  • 题面
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k6Je97EX-1690946333718)(https://s2.loli.net/2023/07/26/HJPXR2mhbaVCG6d.png)]
  • 思路

对于序列检测题目,常规的解法有两种:状态机法和序列缓存对比法。
状态机法的过程类似于:在初始状态中,先判断第一位是否符合,若符合则进入下一个状态,判断第二位是否符合;若第一位不符合则保持在初始状态,直到第一位匹配。如前两位匹配,则判断第三位是否符合,若第一位匹配,最新输入的数值和目标序列的第二位不匹配,则根据最新一位是否匹配第一位,进入第一位匹配状态或者初始状态。依次类推。
序列缓存对比法,则是将八个时刻的数据缓存,作为一个数组,每个时刻的输入位于数组的末尾,数组其它元素左移,把最早输入的数据移出。然后将数组和目标序列对比,如果数组和目标序列相等,则说明出现目标序列。
序列缓存对比法在实现上比较简单。首先声明一个数组,缓存八个时刻的a输入的数值。移位可以通过位截取操作和位拼接操作实现:a_tem[6:0]表示截取a_tem的低7位,{a_tem[6:0],a}表示把a_tem[6:0]和新输入的数值a拼接,a位于低位。

  • 代码
`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input a,
	output reg match
	);
	reg [7:0] a_tem;
	always @(posedge clk or negedge rst_n) begin
		if (!rst_n) begin
			match <=1'b0;
		end
		else if (a_tem == 8'b0111_0001) begin
			match <= 1'b1;
		end
		else begin
			match <= 1'b0;
		end
	end

	always @(posedge clk or negedge rst_n) begin
		if (!rst_n) begin
			a_tem <= 8'b0;
		end
		else begin
			a_tem <= {a_tem[6:0],a};
		end
	end
  
endmodule

2.含有无关项的序列检测

  • 题面
    在这里插入图片描述
  • 思路

序列缓存对比法,则是将九个时刻的数据缓存,作为一个数组,每个时刻的输入位于数组的末尾,数组其它元素左移,把最早输入的数据移出。然后截取数组的前三位和目标序列011对比,截取数组的后三位和目标序列110对比,如果两段数组都和目标序列相等,则说明出现目标序列。
序列缓存对比法在实现上比较简单,本题采用该方法实现。首先声明一个数组,缓存九个时刻的a输入的数值。移位可以通过位截取操作和位拼接操作实现:a_tem[7:0]表示截取a_tem的低7位,{a_tem[7:0],a}表示把a_tem[7:0]和新输入的数值a拼接,a位于低位。

  • 代码
`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input a,
	output match
	);
    reg [8:0] a_tem;
    reg match_f;
    reg match_b;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            match_f <=1'b0;
        end
        else if (a_tem[8:6] == 3'b011) begin
            match_f <= 1'b1;
        end
        else begin
            match_f <= 1'b0;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            match_b <= 1'b0;
        end
        else if (a_tem[2:0] == 3'b110) begin
            match_b <= 1'b1;
        end
        else begin
            match_b <= 1'b0;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            a_tem <= 9'b0;
        end 
        else begin
            a_tem <= {a_tem[7:0],a};
        end
    end

    assign match = match_b && match_f;
endmodule
  • 解法2
`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input a,
	output reg match
	);
    reg [8:0] sequence;

	always @(posedge clk or negedge rst_n) begin
		if (~rst_n) begin
			sequence <= 9'b0;
		end
		else begin
			sequence <= {sequence[7:0],a};
		end
	end

	always @(posedge clk or negedge rst_n) begin
		if (~rst_n) begin
			match <= 0;
		end
		else if (sequence[8:6] == 3'b011 && sequence[2:0] == 3'b110) begin
			match <= 1;
		end
		else begin
			match <= 0;
		end
	end

endmodule
  • 解法3
`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input a,
	output reg match
	);
    reg [8:0] val;
    
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            val <= 9'b0;
        end else begin
            val <= {val[7:0],a};
        end
    end
    
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            match <= 1'b0;
        end else begin
            casex (val)
                9'b011xxx110 : match <= 1'b1;
                default : match <= 1'b0;
            endcase
        end
    end
  
endmodule

3. 不重叠序列检测

  • 题意
    在这里插入图片描述
    题目描写错误,应该是001110,而题目是011100,差评。
  • 思路

使用数选器选择出来对应的位,再做同或与最后做与运算,资源用的也很少。

  • 代码
`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input data,
	output reg match,
	output reg not_match
	);
    
    reg [2:0] cnt;
    reg cmp;
    reg  detect_cmp;
    parameter detect = 6'b011100;
    
    always@(posedge clk or negedge rst_n)begin
        if(! rst_n) 
            cnt  <=  3'd0;
        else if(cnt == 3'd5)
            cnt  <=  3'd0;
        else 
            cnt  <=  cnt  + 3'd1;
    end
    always@(*)begin
        case(cnt)
        3'd0: cmp = 1'd0;
        3'd1: cmp = 1'd1;
        3'd2: cmp = 1'd1;
        3'd3: cmp = 1'd1;
        3'd4: cmp = 1'd0;
        3'd5: cmp = 1'd0;
        default: cmp = 1'd0;
        endcase
    end
    
    always@(posedge clk or negedge rst_n) begin
        if(! rst_n)
                detect_cmp <= 1'd1;
                else if(cnt == 3'd5)
                        detect_cmp  <=  1'd1;
        else
            detect_cmp <= detect_cmp && (~( cmp^ data));
    end
                
    always@(posedge clk or negedge rst_n) begin
        if(! rst_n)
                match <= 1'd0;
        else if((detect_cmp )&&(cnt == 3'd5))
                match <= 1'd1;
        else
                match <= 1'd0;
    end
                
     always@(posedge clk or negedge rst_n) begin
        if(! rst_n)
                not_match <= 1'd0;
         else if((!detect_cmp)&&(cnt == 3'd5))
                not_match <= 1'd1;
        else
                not_match <= 1'd0;
    end
endmodule

4. 简易秒表

  • 题意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kY64tO5e-1690946333720)(https://s2.loli.net/2023/07/26/Zylt2eT9h3uGEWO.png)]

  • 思路

首先确定second的取值逻辑:当minute=60时停止计数,即保持second为0;当second=60时,下一个周期second置为1。其余情况second 等于前一时刻的值加一。 然后明确minute的取值逻辑:当second=60,minute等于前一时刻的值加一。其余情况,minute保持不变。

  • 代码
`timescale 1ns/1ns

module count_module(
	input clk,
	input rst_n,

    output reg [5:0]second,
    output reg [5:0]minute
	);
	
	always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            minute <= 6'd0;
        end 
        else if (second == 6'd60) begin
            minute <= minute + 1;
        end
        else begin
            minute <= minute;
        end
    end
	
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            second <= 6'd0;
        end 
        else if (second == 6'd60) begin
            second <= 6'd1;
        end
        else if (minute == 60) begin
            second <=0;
        end 
        else 
            second <= second + 1'd1;
    end
endmodule

5. 可置位计数器

  • 题意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u6mrVnCX-1690946333720)(https://s2.loli.net/2023/07/26/dg8SMpxfuBGT97Q.png)]

  • 思路

​ 首先明确number的取值逻辑,声明number变量为4位无符号数,数值每个时钟加一,则每次数值达到15,下一个时钟因为位宽的限制,自动变为1,可以实现十六进制计数。当set信号为1时,将set_num的值赋给number。

然后确定zero的取值逻辑,在默认情况下为0,当number=0时,zero值为1。

因为判断number4’d0需要一个时钟,zero信号为1,总是滞后number0一个时钟周期。所以可以考虑将number延迟一个时钟再输出。使用num变量代替上述的number,再通过以下语句实现number延迟一个时钟输出。【因为number是寄存器类型,无法通过组合逻辑进行阻塞赋值同时匹配。 如果直接使用number进行zero的判断来说,zero肯定是比number过“0”时刻慢一拍的; 所以不妨使用num_reg,进行延迟; 因为zero肯定是比num_reg慢一拍的,所以再通过num_reg延迟一拍给number,则number与zero同步输出匹配;】

  • 代码
`timescale 1ns/1ns

module count_module(
	input clk,
	input rst_n,
	input set,
	input [3:0] set_num,
	output reg [3:0]number,
	output reg zero
	);
    reg [3:0] num;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            zero = 1'd0;
        end 
        else if (num == 4'd0) begin
            zero <= 1'b1;
        end 
        else begin
            zero <= 1'b0;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            num <= 4'b0;
        end
        else if (set) begin
            num <= set_num;
        end
        else begin
            num <= num + 1'd1;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            number <= 1'd0;
        end
        else begin
            number <= num;
        end
    end
endmodule

6. 加减计数器

  • 题意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tgHdRB9I-1690946333721)(https://s2.loli.net/2023/07/26/sOD1nVqmpaLbWyC.png)]

  • 思路

​ 首先确定zero的取值逻辑,在默认情况下为0,当number=0时,zero值为1。 always @(posedge clk or negedge rst_n)

​ 然后将mode的值作为if-else的判断条件,当mode为1时,number每个时钟周期加一,当mode为0时,number每个时钟周期减一。

​ 按照以上代码,因为判断number4’d0需要一个时钟,zero信号为1,总是滞后number0一个时钟周期。所以可以考虑将number延迟一个时钟再输出。使用num变量代替上述的number,再通过以下语句实现number延迟一个时钟输出。

  • 代码
`timescale 1ns/1ns

module count_module(
	input clk,
	input rst_n,
	input mode,
	output reg [3:0]number,
	output reg zero
	);
    reg [3:0] num;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            zero <= 1'd0;
        end
        else if (num == 4'd0) begin
            zero <= 1'b1;
        end
        else begin
            zero <= 1'b0;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            num <= 4'b0;
        end 
        else if (mode) begin
            if (num == 9) 
				num <= 0;
            else 
				num <= num + 1'd1;
        end 
		else if (!mode) begin
            if (num == 0) num <= 9;
            else num <= num - 1'd1;
        end
        else 
			num <= num ;
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            number <= 4'd0;
        end 
        else begin
            number <= num;
        end
    end
endmodule

7.RAM的简单实现

  • 题意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gOXdfKjA-1690946333722)(https://s2.loli.net/2023/07/26/5AKM8VZ72XdDgCm.png)]

  • 思路

要实现RAM,首先要声明数据的存储空间,例如:[3:0] rom [7:0];变量名称ram之前的[3:0]表示每个数据具有多少位,指位宽;变量名称ram之后的[7:0]表示需要多少个数据,指深度,注意这里深度为8,应该是使用[7:0],而不是[2:0];

​ 声明存储变量之后,需要对ram进行初始化,写入数据,当write_en有效,向write_addr写入write_data,当read_en有效,根据输入的read_addr输出read_data。需要注意的是,题目要求实现真双端口RAM,即可以同时写入和读出,所以需要使用两个always语句块实现写入和读出逻辑,不可以在同一个always块中使用if-else if-else if结果。

  • 代码
`timescale 1ns/1ns
module ram_mod(
	input clk,
	input rst_n,
	
	input write_en,
	input [7:0]write_addr,
	input [3:0]write_data,
	
	input read_en,
	input [7:0]read_addr,
	output reg [3:0]read_data
);
    reg [3:0] myRAM [7:0];
    reg [8:0] i;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            for (i = 0;i < 256;i = i+1)
                myRAM[i] = 0;
        end
        else begin
            myRAM[write_addr] <= write_en ? write_data:myRAM[write_addr];
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (~rst_n) begin
            read_data <= 0;
        end
        else 
            read_data <= read_en?myRAM[read_addr]:read_data;
    end
endmodule

8. 单端口RAM

  • 题意
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mLXVUwhb-1690946333723)(https://s2.loli.net/2023/07/27/anzKjiMc1mdbe5x.png)]

  • 思路

建立一个reg的数组,将数据存储进来,进行的是读、写互不干扰的读写机制,即要么读要么写。这个时侯需要设置enb,进行读写的开关控制。需要注意的是,写是对寄存器进行写,因此必须有时序电路构成。

  • 代码
`timescale 1ns/1ns

module RAM_1port(
    input clk,
    input rst,
    input enb,
    input [6:0]addr,
    input [3:0]w_data,
    output wire [3:0]r_data
);
//*************code***********//
    reg [6:0] mem[127:0];
    integer i;
    always @(posedge clk or negedge rst) begin
        if (!rst) begin
            for (i = 0;i < 127;i ++) begin
                mem[i] <= 1'b0;
            end
        end
        else if (enb) begin
            mem[addr] <= w_data;
        end
    end
    assign r_data = (!enb)?mem[addr]:1'b0;
//*************code***********//
endmodule

9. 4位数比较器

  • 题意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KFYF9HxO-1690946333723)(https://s2.loli.net/2023/07/27/4BLiHUldXDCq3yV.png)]

  • 思路

门级描述,无非就是将<,>,==三个符号用门级电路来表示,然后根据行为级描述进行替换。

a == b --> ~(a^b)

a > b --> (a^b)&a

a < b --> (a^b)&b

  • 代码
assign Y1 = ~(A[0]^B[0]) & ~(A[1]^B[1]) & ~(A[2]^B[2]) & ~(A[3]^B[3]);
    
assign Y2 = ((A[3]^B[3])&A[3]) |
         (~(A[3]^B[3]) & ((A[2]^B[2])&A[2])) |
        (~(A[3]^B[3]) & ~(A[2]^B[2]) & ((A[1]^B[1])&A[1])) |
        (~(A[3]^B[3]) & ~(A[2]^B[2]) & ~(A[1]^B[1]) & ((A[0]^B[0])&A[0]));
                
assign Y0 = ((A[3]^B[3])&B[3]) |
        (~(A[3]^B[3]) & ((A[2]^B[2])&B[2])) |
        (~(A[3]^B[3]) & ~(A[2]^B[2]) & ((A[1]^B[1])&B[1])) |
        (~(A[3]^B[3]) & ~(A[2]^B[2]) & ~(A[1]^B[1]) & ((A[0]^B[0])&B[0]));
  • 解法2
````timescale 1ns/1ns

module comparator_4(
	input		[3:0]       A   	,
	input	   [3:0]		B   	,
 
 	output	 reg		Y2    , //A>B
	output   reg       Y1    , //A=B
    output   reg        Y0      //A<B
);
    
    always @ (A or B) 
      begin
            if(A>B)
                begin
                Y2=1;
                Y1=0;
                Y0=0;
                end
            else if (A<B)
                begin
                Y2=0;
                Y1=0;
                Y0=1;
                end
            else
                begin
                Y2=0;
                Y1=1;
                Y0=0;
                end
        end
endmodule
  • 解法3
`timescale 1ns/1ns

module comparator_4(
	input		[3:0]       A   	,
	input	   [3:0]		B   	,
 
 	output	 wire		Y2    , //A>B
	output   wire        Y1    , //A=B
    output   wire        Y0      //A<B
);

    assign Y2 = (A>B)?1:0;
    assign Y1 = (A==B)?1:0;
    assign Y0 = (A<B)?1:0;
    
endmodule

10.4bit超前进位加法器电路

  • 题意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IGGLnOKB-1690946333724)(https://s2.loli.net/2023/07/27/EtzQDw8syVqelcb.png)]

  • 思路

超前进位加法器原理与设计

`timescale 1ns/1ns

module lca_4(
	input		[3:0]       A_in  ,
	input	    [3:0]		B_in  ,
    input                   C_1   ,
 
 	output	 wire			CO    ,
	output   wire [3:0]	    S
);
    wire [3:0] C;

    assign S[0] = A_in[0] ^ B_in[0] ^ C_1;
    assign S[1] = A_in[1] ^ B_in[1] ^ C[0];
    assign S[2] = A_in[2] ^ B_in[2] ^ C[1];
    assign S[3] = A_in[3] ^ B_in[3] ^ C[2];

    assign C[0] = (A_in[0] & B_in[0]) || ((A_in[0] ^ B_in[0]) & C_1);
    assign C[1] = (A_in[1] & B_in[1]) || ((A_in[1] ^ B_in[1]) & C[0]);
    assign C[2] = (A_in[2] & B_in[2]) || ((A_in[2] ^ B_in[2]) & C[1]);
    assign C[3] = (A_in[3] & B_in[3]) || ((A_in[3] ^ B_in[3]) & C[2]);

    assign CO = C[3];
endmodule
  • 附录
半加器

半加器是最简单的加法器。它不考虑进位输入。其中AB是两个加数,S是和,C_o是进位输出。

assign S     = A ^ B;
assign C_out = A & B;
全加器

全加器是多bit加法器的基础。 C i C_i Ci 是进位输入。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L2C3EKBe-1690946333725)(https://s2.loli.net/2023/07/27/Gnh5cNXWHxsbqvC.png)]

下图中红色路径是全加器的关键路径。

img

module full_adder(
    input  A,
    input  B,
    input  C_i,
    output S,
    output C_o
);
    assign S    = A ^ B ^ C_i;
    assign C_o  = A & B | C_i&(a^b);
    // assign C_o  = A & B | A & C_i | B & C_i; // 也可以
endmodule

行波进位加法器

Ripple-carry adder, RCA。将全加器串联起来。 虽然 RCA 结构简单易于理解,但容易看出,每一位的运算结果 S k S_k Sk 都要依赖进位 C k C_k Ck 才能得出。如下图所示,这会使得 RCA 的关键路径变得很长,而长关键路径会让电路难以满足时序要求。

img

module rca #(
    parameter width = 4
)(
    input  [width-1:0] A,
    input  [width-1:0] B,
    output [width-1:0] S,
    
    input  C_i,
    output C_o
);
    wire [width:0] C;
    genvar i;
    generate
      	for (i=0; i<width; i=i+1)begin
            full_adder myadder(
                .A    (A[i]),
                .B    (B[i]),
                .C_i  (C[i]),
                .S    (S[i]),
                .C_o  (C[i+1]),
            );
        end
    endgenerate
  	assign C[0] = C_i;
    assign C_o  = C[width];
endmodule

11.优先编码器电路①

  • 题意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SeVmcbZM-1690946333727)(https://s2.loli.net/2023/07/27/C1BrOihzMQSmJFg.png)]

  • 思路

关于casecasezcasex参考这篇文章。简单地说,三者都是可以综合的。case进行全等匹配,casez忽略?z对应的位进行匹配,casex忽略x?z对应的位进行匹配。

  • 代码
`timescale 1ns/1ns
module encoder_0(
   input      [8:0]         I_n   ,
   
   output reg [3:0]         Y_n   
);
    always@(*) begin
        casez (I_n)
            9'b1_1111_1111: Y_n = 4'b1111;
            9'b0_????_????: Y_n = 4'b0110;
            9'b1_0???_????: Y_n = 4'b0111;
            9'b1_10??_????: Y_n = 4'b1000;
            9'b1_110?_????: Y_n = 4'b1001;
            9'b1_1110_????: Y_n = 4'b1010;
            9'b1_1111_0???: Y_n = 4'b1011;
            9'b1_1111_10??: Y_n = 4'b1100;
            9'b1_1111_110?: Y_n = 4'b1101;
            9'b1_1111_1110: Y_n = 4'b1110;
            default: Y_n = 4'b0000;
        endcase
    end
endmodule

12. 用优先编码器实现键盘编码电路

  • 题意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-saeMgwuv-1690946333728)(https://s2.loli.net/2023/07/27/3pl9vBh6UWKTrIt.png)]

  • 思路
  1. 首先确定电路输出L是8421BCD码,即是高电平有效的,而题目中给出的优先编码器输出Y_n是低电平有效的,故应当明确L和Y_n两者的状态是恰好相反的;

  2. 注意:键盘有10个按键,而所给的优先编码器是只有9个输入的;

  3. 此题关键在于着重理解: “键盘编码电路要有工作状态标志,以区分没有按键按下和按键0按下两种情况。” : 这句话的潜台词是 按键按下和按键0按下时,电路的输出L的状态是一样的,因此在这种情况下可以通过GS信号来区分键盘是否处在工作状态,对应的真值表如下;

键盘状态S[9:0]L[3:0]GS
无按键按下1_1111_111100000
按键0按下1_1111_111000001
  • 代码
`timescale 1ns/1ns
module encoder_0(
   input      [8:0]         I_n   ,
   
   output reg [3:0]         Y_n   
);

always @(*)begin
   casex(I_n)
      9'b111111111 : Y_n = 4'b1111;
      9'b0xxxxxxxx : Y_n = 4'b0110;
      9'b10xxxxxxx : Y_n = 4'b0111;
      9'b110xxxxxx : Y_n = 4'b1000;
      9'b1110xxxxx : Y_n = 4'b1001;
      9'b11110xxxx : Y_n = 4'b1010;
      9'b111110xxx : Y_n = 4'b1011;
      9'b1111110xx : Y_n = 4'b1100;
      9'b11111110x : Y_n = 4'b1101;
      9'b111111110 : Y_n = 4'b1110;
      default      : Y_n = 4'b1111;
   endcase    
end 
     
endmodule

module key_encoder(
      input      [9:0]         S_n   ,         
 
      output wire[3:0]         L     ,
      output wire              GS
);
    wire [3:0] L_temp; 
    
    encoder_0 encoder (S_n[9:1], L_temp);
    
    assign GS = ~((&(~L)) & S_n[0]);
    
    assign L = ~L_temp;
        
endmodule

13. 8线-3线优先编码器

  • 题意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PtVldSbG-1690946333728)(https://s2.loli.net/2023/07/27/3I4Kt8oDlPBugAq.png)]

  • 思路

分析编码器的功能表:

当El=1时,编码器工作:而当E1=0时,禁止编码器工作,此时不论8个输入端为何种状态,3个输出端均为低电平,且GS和EO均为低电平。

只有在EI为1,且所有输入端都为0时,EO输出为1.它可与另一片编码器的EI连接,以便组成更多输入端的优先编码器。

GS的功能是,当EI为1,且至少有一个输入端有高电平信号输入时,GS为1.表明编码器处于工作状态,否则GS为0,由此可以区分当电路所有输入端均无高电平输人,或者只有I[0]输入端有高电平时,Y[2:0]均为000的情况

根据功能表推导出各输出端的逻辑表达式为

Y[2] = EI(I[7]+I[6]+I[5]+I[4]);

Y[1] = EI(I[7]+I[6]+~I[5]~I[4] I[3] +~I[5]~I[4] I[2]);

Y[0] = EI(I[7]+~I[6] I[5]+ ~I[6]~I[4] I[3]+ ~I[6]~I[4]~ I[2]I[1]);

EO=EI(~I[7] ~I[6] ~I[5] ~I[4] ~I[3] ~I[2] ~I[1] ~I[0]);

GS=EI(I[7]+ I[6]+ I[5]+ I[4]+ I[3]+ I[2]+ I[1]+ I[0])
  • 代码
`timescale 1ns/1ns

module encoder_83(
   input      [7:0]       I   ,
   input                  EI  ,
   
   output wire [2:0]      Y   ,
   output wire            GS  ,
   output wire            EO    
);
assign Y[2] = EI & (I[7] | I[6] | I[5] | I[4]);
assign Y[1] = EI & (I[7] | I[6] | ~I[5]&~I[4]&I[3] | ~I[5]&~I[4]&I[2]);
assign Y[0] = EI & (I[7] | ~I[6]&I[5] | ~I[6]&~I[4]&I[3] | ~I[6]&~I[4]&~I[2]&I[1]);

assign EO = EI&~I[7]&~I[6]&~I[5]&~I[4]&~I[3]&~I[2]&~I[1]&~I[0];

assign GS = EI&(I[7] | I[6] | I[5] | I[4] | I[3] | I[2] | I[1] | I[0]);
//assign GS = EI&(| I);
         
endmodule

14. 使用8线-3线优先编码器Ⅰ实现16线-4线优先编码器

  • 题意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-US4MapYw-1690946333729)(https://s2.loli.net/2023/07/27/YAJa9xIWkbRDE6l.png)]

  • 思路

电路连接图

img

当EI1=0时、U1禁止编码,其输出端Y为000,GS1、EO1均为0。同时EO1使EI0=0,U0也禁止编码,其输出端及GS0、EO0均为0。由电路图可知GS=GS1+GS0=0,表示此时电路输出端的代码L=0000是非编码输出。

当E=1时,U1允许编码,若A[15:8]均无有效电平输人,则EO1=1,使EI0=1,从而允许U0编码,因此U1的优先级高于U0。

此时A[15:8]没有有效电平输入,U1的输出均为0。使4个或门都打开,L[2:0]取决于U0的输出,而L[3]=GS1总是等于0,所以输出代码在0000-0111之间变化。若只有A[0]有高电平输入,输出为0000,若A[7]及其他输入同时有高电平输人,则输出为0111。A[0]的优先级别最低。

(3)当EI1=1且A[15:8]中至少有一个为高电平输人时,EO1=0,使EI0=0,U0禁止编码,此时L[3]=GS1=1,L[2:0]取决于U1的输出,输出代码在1000~1111之间变化,并且A的优先级别最高。

  • 代码
`timescale 1ns/1ns
module encoder_83(
   input      [7:0]       I   ,
   input                  EI  ,
   
   output wire [2:0]      Y   ,
   output wire            GS  ,
   output wire            EO    
);
assign Y[2] = EI & (I[7] | I[6] | I[5] | I[4]);
assign Y[1] = EI & (I[7] | I[6] | ~I[5]&~I[4]&I[3] | ~I[5]&~I[4]&I[2]);
assign Y[0] = EI & (I[7] | ~I[6]&I[5] | ~I[6]&~I[4]&I[3] | ~I[6]&~I[4]&~I[2]&I[1]);

assign EO = EI&~I[7]&~I[6]&~I[5]&~I[4]&~I[3]&~I[2]&~I[1]&~I[0];

assign GS = EI&(I[7] | I[6] | I[5] | I[4] | I[3] | I[2] | I[1] | I[0]);
//assign GS = EI&(| I);
         
endmodule

module encoder_164(
   input      [15:0]      A   ,
   input                  EI  ,
   
   output wire [3:0]      L   ,
   output wire            GS  ,
   output wire            EO    
);
    wire    EO1;
    wire [2:0] Y0;
    wire [2:0] Y1;
    wire    GS0;
    encoder_83 U0(
        .I  (A[7:0]),
        .EI (EO1),
        .Y  (Y0),
        .GS (GS0),
        .EO (EO)
    );
    encoder_83 U1(
        .I  (A[15:8]),
        .EI (EI),
        .Y  (Y1),
        .GS (GS1),
        .EO (EO1)
    );
    assign L[3] = GS1;
    assign L[2] = Y1[2] | Y0[2];
    assign L[1] = Y1[1] | Y0[1];
    assign L[0] = Y1[0] | Y0[0];

    assign GS = GS1 | GS0;
    
endmodule

15.实现3-8译码器①

  • 题意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5JEeRDnZ-1690946333731)(https://s2.loli.net/2023/07/27/CjKxLaqU6RMSuPV.png)]

  • 思路

根据该电路的真值表,可列出逻辑表达式,最简结果如下。

Y0_n = (E·(A2)·(A1)·(A0));

Y1_n = (E·(A2)·(~A1)·(A0));

Y2_n = (E·(A2)·(A1)·(~A0));

Y3_n = (E·(A2)·(A1)·(A0));

Y4_n = (E·(A2)·(A1)·(~A0));

Y5_n = (E·(A2)·(A1)·(A0));

Y6_n = (E·(A2)·(A1)·(A0));

Y7_n = ~(E·(A2)·(A1)·(A0));

  • 代码
`timescale 1ns/1ns


module decoder_38(
   input             E1_n   ,
   input             E2_n   ,
   input             E3     ,
   input             A0     ,
   input             A1     ,
   input             A2     ,
   
   output wire       Y0_n   ,  
   output wire       Y1_n   , 
   output wire       Y2_n   , 
   output wire       Y3_n   , 
   output wire       Y4_n   , 
   output wire       Y5_n   , 
   output wire       Y6_n   , 
   output wire       Y7_n   
);
wire E ;
assign E = E3 & ~E2_n & ~E1_n;
assign  Y0_n = ~(E & ~A2 & ~A1 & ~A0);
assign  Y1_n = ~(E & ~A2 & ~A1 &  A0);
assign  Y2_n = ~(E & ~A2 &  A1 & ~A0);
assign  Y3_n = ~(E & ~A2 &  A1 &  A0);
assign  Y4_n = ~(E &  A2 & ~A1 & ~A0);
assign  Y5_n = ~(E &  A2 & ~A1 &  A0);
assign  Y6_n = ~(E &  A2 &  A1 & ~A0);
assign  Y7_n = ~(E &  A2 &  A1 &  A0);
     
endmodule

16. 用3-8译码器实现全减器

  • 题意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5mAbG1HI-1690946333732)(https://s2.loli.net/2023/07/27/AhT9Ru4ybsMHzZ8.png)]

  • 思路

3-8译码器代码如下,可将参考代码添加并例化到本题答案中。

module decoder_38(
   input             E      ,
   input             A0     ,
   input             A1     ,
   input             A2     ,
   
   output reg       Y0n    ,  
   output reg       Y1n    , 
   output reg       Y2n    , 
   output reg       Y3n    , 
   output reg       Y4n    , 
   output reg       Y5n    , 
   output reg       Y6n    , 
   output reg       Y7n    
);

always @(*)begin
   if(!E)begin
      Y0n = 1'b1;
      Y1n = 1'b1;
      Y2n = 1'b1;
      Y3n = 1'b1;
      Y4n = 1'b1;
      Y5n = 1'b1;
      Y6n = 1'b1;
      Y7n = 1'b1;
   end  
   else begin
      case({A2,A1,A0})
         3'b000 : begin
                     Y0n = 1'b0; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; 
                     Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1;
                  end 
         3'b001 : begin
                     Y0n = 1'b1; Y1n = 1'b0; Y2n = 1'b1; Y3n = 1'b1; 
                     Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1;
                  end 
         3'b010 : begin
                     Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b0; Y3n = 1'b1; 
                     Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1;
                  end 
         3'b011 : begin
                     Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b0; 
                     Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1;
                  end 
         3'b100 : begin
                     Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; 
                     Y4n = 1'b0; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1;
                  end 
         3'b101 : begin
                     Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; 
                     Y4n = 1'b1; Y5n = 1'b0; Y6n = 1'b1; Y7n = 1'b1;
                  end 
         3'b110 : begin
                     Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; 
                     Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b0; Y7n = 1'b1;
                  end 
         3'b111 : begin
                     Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; 
                     Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b0;
                  end 
         default: begin
                     Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; 
                     Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1;
                  end
      endcase  
   end 
end    
     
endmodule

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GGh3L5uV-1690946333734)(https://s2.loli.net/2023/07/27/DPCKUNFBeAGVaR3.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-06WTo0xb-1690946333735)(https://s2.loli.net/2023/07/27/SMrKPcTlye3GxoI.png)]

  • 代码
`timescale 1ns/1ns

module decoder_38(
   input             E      ,
   input             A0     ,
   input             A1     ,
   input             A2     ,
   
   output reg       Y0n    ,  
   output reg       Y1n    , 
   output reg       Y2n    , 
   output reg       Y3n    , 
   output reg       Y4n    , 
   output reg       Y5n    , 
   output reg       Y6n    , 
   output reg       Y7n    
);

always @(*)begin
   if(!E)begin
      Y0n = 1'b1;
      Y1n = 1'b1;
      Y2n = 1'b1;
      Y3n = 1'b1;
      Y4n = 1'b1;
      Y5n = 1'b1;
      Y6n = 1'b1;
      Y7n = 1'b1;
   end  
   else begin
      case({A2,A1,A0})
         3'b000 : begin
                     Y0n = 1'b0; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; 
                     Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1;
                  end 
         3'b001 : begin
                     Y0n = 1'b1; Y1n = 1'b0; Y2n = 1'b1; Y3n = 1'b1; 
                     Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1;
                  end 
         3'b010 : begin
                     Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b0; Y3n = 1'b1; 
                     Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1;
                  end 
         3'b011 : begin
                     Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b0; 
                     Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1;
                  end 
         3'b100 : begin
                     Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; 
                     Y4n = 1'b0; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1;
                  end 
         3'b101 : begin
                     Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; 
                     Y4n = 1'b1; Y5n = 1'b0; Y6n = 1'b1; Y7n = 1'b1;
                  end 
         3'b110 : begin
                     Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; 
                     Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b0; Y7n = 1'b1;
                  end 
         3'b111 : begin
                     Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; 
                     Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b0;
                  end 
         default: begin
                     Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; 
                     Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1;
                  end
      endcase  
   end 
end    
     
endmodule

module decoder1(
    input  wire       A,
    input  wire       B,
    input  wire       Ci,
    
    output wire       D,
    output wire       Co
);
    wire [7:0] Y;
    assign D  = ~Y[1] + ~Y[2] + ~Y[4] + ~Y[7];
  assign Co = ~Y[1] + ~Y[4] + ~Y[5] + ~Y[7];
    decoder_38 myDecoder(
        .E  (1   ), 
        .A0 (B   ), 
        .A1 (A   ), 
        .A2 (Ci  ), 
        .Y0n(Y[0]),
        .Y1n(Y[1]),
        .Y2n(Y[2]),
        .Y3n(Y[3]),
        .Y4n(Y[4]),
        .Y5n(Y[5]),
        .Y6n(Y[6]),
        .Y7n(Y[7])
    );
endmodule

17 数据选择器实现逻辑电路

  • 题意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kBsifET9-1690946333736)(https://s2.loli.net/2023/07/27/OFbBh2nZo1m7ayd.png)]

  • 思路

数据选择器代码如下,可在本题答案中添加并例化此数据选择器。

module data_sel(
   input             S0     ,
   input             S1     ,
   input             D0     ,
   input             D1     ,
   input             D2     ,
   input             D3     ,
   
   output wire        Y    
);

assign Y = ~S1 & (~S0&D0 | S0&D1) | S1&(~S0&D2 | S0&D3);
     
endmodule
  • 思路

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CUAIEJ9Q-1690946333737)(https://s2.loli.net/2023/07/27/skfPxvhXZoJRNYq.png)]

将变量A、B接入4选1数据选择器选择输入端S0 S1。将变量C分配在数据输入端。从表中可以看出输出L与变量C的关系。

当AB=00时选通D0而此时L=0,所以数据端D0接0:当AB=01时选通D1,由真值表得此时L=C,即D1应接C:当AB为10和11时,D2和D3分别接~C和1。A接S1,B接S0。

  • 代码
`timescale 1ns/1ns


module data_sel(
   input             S0     ,
   input             S1     ,
   input             D0     ,
   input             D1     ,
   input             D2     ,
   input             D3     ,
   
   output wire        Y    
);

assign Y = ~S1 & (~S0&D0 | S0&D1) | S1&(~S0&D2 | S0&D3);
     
endmodule

module sel_exp(
   input             A     ,
   input             B     ,
   input             C     ,
   
   output wire       L            
);
                  

data_sel U0(
   .S0     (B),
   .S1     (A),
   .D0     (0),
   .D1     (C),
   .D2     (~C),
   .D3     (1),
 
   .Y      (L)
);

endmodule

企业真题

【哲库】

1. 根据RTL图编写Verilog程序

  • 题意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B6qOQbV5-1690946333738)(https://s2.loli.net/2023/07/27/xnOm7qFpTzUVHSc.png)]

  • 思路

观察题目给出的RTL图,主要的器件是两个D触发器,一个与门。D触发器含有异步复位信号,且为低电平有效。data_in输入到D触发器,D触发器的输出Q是前一时刻的data_in,即data_in打一拍得到data_in_reg。与门表示data_out = data_in && !data_in_reg。再通过一个D触发器输出,这样子处理使data_in上升沿出现的时候,data_out保持一个时钟的高电平。由此可见,RTL实现了求data_in上升沿的功能。

  • 代码
`timescale 1ns/1ns

module RTL(
	input clk,
	input rst_n,
	input data_in,
	output reg data_out
	);
    reg data_in_reg;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            data_in_reg <= 1'b0;
        end 
        else begin
            data_in_reg <= data_in;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            data_out <= 1'b0;
        end 
        else if (data_in && !data_in_reg) begin
            data_out <= 1'b1;
        end
        else begin
            data_out <= 1'b0;
        end
     end
endmodule

2. 自动售卖机

  • 题意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dGl074sc-1690946333739)(https://s2.loli.net/2023/07/28/6rKeuFZvcXfGJCW.png)]

img

  • 思路

  • 代码

`timescale 1ns/1ns

module sale(
   input                clk   ,
   input                rst_n ,
   input                sel   ,//sel=0,5$dranks,sel=1,10&=$drinks
   input          [1:0] din   ,//din=1,input 5$,din=2,input 10$
 
   output   reg  [1:0] drinks_out,//drinks_out=1,output 5$ drinks,drinks_out=2,output 10$ drinks
   output	reg        change_out   
);
    reg [1:0] temp;
    wire [1:0] total = din+temp;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            drinks_out <= 2'd0;
            change_out <= 1'd0;
        end
        else begin
            case ({sel,total})
                3'd111: begin
                    drinks_out <= 2'd2;
                    change_out <= 1'd1;
                end
                3'd110: begin
                    drinks_out <= 2'd2;
                    change_out <= 1'd0;
                end 
                3'd010: begin
                    drinks_out <= 2'd1;
                    change_out <= 1'd0;
                end
                3'd001: begin
                    drinks_out <= 2'd1;
                    change_out <= 1'd0;
                end
            endcase
        end
    end
    always @(posedge clk or drinks_out) begin
        if (!rst_n) begin
            temp <= 2'd0;
        end
        else begin
            if (drinks_out) begin
                temp <= 2'd0;
            end
            else begin
                temp <= din;
            end
        end
    end
endmodule

3. 序列发生器

  • 题意
    在这里插入图片描述

  • 思路

用一个数据存储序列,不断移位,然后一直发送某一位,感觉代码更简单一点。

  • 代码
`timescale 1ns/1ns

module sequence_generator(
	input clk,
	input rst_n,
	output reg data
	);
    reg [5:0] q;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            q <= 6'b001011;
        end
        else begin
            q <= {q[4:0],q[5]};
        end
    end
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            data <= 1'd0;
        end
        else begin
            data <= q[5];
        end
    end
endmodule

【华为】

1. VL63 并串转换

  • 题意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BL9P2cKb-1690946333741)(https://s2.loli.net/2023/07/31/AStcHjgieDW9zay.png)]

  • 思路

核心思想就是移位。串转并就是把1位的输入放到N位reg的最低位,然后N位reg左移一位,在把1位输入放到左移后的reg的最低位,这样循环,就可以得到,以最高位开始传输,最低位传输完成的N位数据了;并转串就是把并行的N位数据的最高位给1位输出,然后类似的循环左移就可以了。

  • 代码
`timescale 1ns/1ns
module huawei5(
	input wire clk  ,
	input wire rst  ,
	input wire [3:0]d ,
	output wire valid_in ,
	output wire dout
	);

//*************code***********//
	reg [3:0] data = 'd0;
    reg [1:0] cnt;
    reg valid;
    assign dout = data[3];
    assign valid_in = valid;

    always @(posedge clk or negedge rst) begin
        if (!rst) begin
            data <= 'd0;
            cnt <= 'd0;
            valid <= 'd0;
        end
        else begin
            if (cnt == 'd3) begin
                data <= d;
                cnt <= 'd0;
                valid <= 1;
            end
            else  begin
                cnt <= cnt + 'd1;
                valid <= 0;
                data <= {data[2:0],data[3]};
            end
        end

    end
//*************code***********//

endmodule

2. VL67 十六进制计数器

  • 题意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EQHnrQev-1690946333741)(https://s2.loli.net/2023/07/31/XZYiT1OchPKQ4BC.png)]

  • 思路

自动溢出。Q属于是4bit

  • 代码
`timescale 1ns/1ns

module counter_16(
   input                clk   ,
   input                rst_n ,
 
   output   reg  [3:0]  Q      
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            Q <= 4'b0;
        end else begin
            Q <= Q +1'b1;
        end
    end
endmodule

3. 同步FIFO

  • 题意

image-20230802094720587

image-20230802100617191

image-20230802100637889

  • 思路

待补

4. 状态机与时钟分频

  • 题意

image-20230802101322887

  • 思路

  • 代码

`timescale 1ns/1ns

module huawei7(
	input wire clk  ,
	input wire rst  ,
	output reg clk_out
);

//*************code***********//
    parameter [1:0] s0 = 2'b00,
                    s1 = 2'b01,
                    s2 = 2'b10,
                    s3 = 2'b11;

    reg [1:0] state,next_state;
    always @(posedge clk or negedge rst) begin
        if (!rst) begin
            state <= s0;
        end
        else begin
            state <= next_state;
        end
    end

    always @(state) begin
        case(state)
            s0:begin
                next_state <= s1;
                clk_out <= 1'b0;
            end 
            s1:begin
                next_state <= s2;
                clk_out <= 1'b1;
            end
            s2:begin
                next_state <= s3;
                clk_out <= 1'b0;
            end
            s3: begin
                next_state <= s0;
            end
            default:begin
                next_state <= s0;
                clk_out <= 1'b0;
            end
        endcase
    end
//*************code***********//
endmodule
  • 解法2
`timescale 1ns/1ns

module huawei7(
	input wire clk  ,
	input wire rst  ,
	output reg clk_out
);

//*************code***********//
    reg[1:0] cnt; 
    always@(posedge clk or negedge rst)
        if(!rst)
            cnt <= 0;
        else
            cnt <= cnt+1;
    
    always@(*)
        clk_out = cnt==1;

//*************code***********//
endmodule

5. 超前进位加法器

  • 题意

image-20230802102053274

  • 思路

img

一级加法器进位信号如下

这里‘+’ ‘·’符号不是‘加’和‘乘’,是‘或’和 ‘与’

则4级可以表示为如下,这里P和G是传播信号和生成信号:

img

因此,应该得到两个子模块:一位运算和四位逻辑

  • 代码
`timescale 1ns/1ns

module huawei8//四位超前进位加法器
(
	input wire [3:0]A,
	input wire [3:0]B,
	output wire [4:0]OUT
);

//*************code***********//
   wire [3:0] G;
   wire [3:0] P;
   wire [3:0] F;
   wire [4:1] C;
   Add1 u1
   ( .a(A[0]),
      .b(B[0]),
      .C_in(1'b0),
      .f(F[0]),
      .g(G[0]),
      .p(P[0])
   );
   Add1 u2
   ( .a(A[1]),
      .b(B[1]),
      .C_in(C[1]),
      .f(F[1]),
      .g(G[1]),
      .p(P[1])
   );
      Add1 u3
   ( .a(A[2]),
      .b(B[2]),
      .C_in(C[2]),
      .f(F[2]),
      .g(G[2]),
      .p(P[2])
   );
      Add1 u4
   ( .a(A[3]),
      .b(B[3]),
      .C_in(C[3]),
      .f(F[3]),
      .g(G[3]),
      .p(P[3])
   );
   CLA_4 uut
   (
      .P(P),
      .G(G),
      .C_in(1'b0),
      .Ci(C),
      .Gm(),
      .Pm()
   );
   assign OUT={C[4],F};

//*************code***********//
endmodule



//下面是两个子模块

module Add1
(
		input a,
		input b,
		input C_in,
		output f,
		output g,
		output p
		);
    assign f = a^b^C_in;
    assign g = a&b;
    assign p = a|b;
endmodule






module CLA_4(
		input [3:0]P,
		input [3:0]G,
		input C_in,
		output [4:1]Ci,
		output Gm,
		output Pm
	);
	assign Ci[1] = G[0]|P[0]&C_in;
    assign Ci[2] = G[1]|P[1]&G[0]|P[1]&P[0]&C_in;
    assign Ci[3] = G[2]|P[2]&G[1]|P[2]&P[1]&G[0]|P[2]&P[1]&P[0]&C_in;
    assign Ci[4] = G[3]|P[3]&G[2]|P[3]&P[2]&G[1]|P[3]&P[2]&P[1]&G[0]|P[3]&P[2]&P[1]&P[0]&C_in;
 
    assign Gm = G[3]|P[3]&G[2]|P[3]&P[2]&G[1]|P[3]&P[2]&P[1]&G[0];
    assign Pm = P[3]&P[2]&P[1]&P[0];
endmodule

【阿里】

1. 求最小公倍数

  • 题意

image-20230802103900922

  • 思路

待补

  • 代码

2.任意奇数倍时钟分频

  • 题意

image-20230802110801365

  • 思路

实现偶数倍的n分频时,每当计数器从0计数到n/2 - 1时,输出时钟信号跳变,同时计数器归零从新开始计数。

题目要求的是奇数倍分频,且要求占空比为50%,则需要稍加调整:以五分频为例,需要输出时钟信号保持2.5个输入时钟的1,然后保持2.5个时钟的0。比如在第一个时钟的上升沿跳变为1,则在第三个时钟的下降沿跳变为0,在第六个时钟的上升沿再一次跳变为1。即需要对上升/下降两个时钟沿的进行计数。

由此得出实现奇数倍数分频的方法:加入两个中间信号flag_1,flag_2,分别使用输入时钟信号的上升/下降沿驱动。以五分频为例,flag_1的变化由上升沿驱动,flag_2的变化由下降沿驱动。当计数器计数到(n-1)/2=2和(n-1)=4时,flag_1、flag_2发生跳变(即取反)。再将flag_1,flag_2相或即可得到分频之后的时钟信号。

如下图所示。红色框分别为flag_1,flag_2,持续两个时钟,相或得到蓝色部分刚好占2.5个时钟,实现五分频。

  • 代码
`timescale 1ns/1ns

module clk_divider
    #(parameter dividor = 5)
( 	input clk_in,
	input rst_n,
	output clk_out
);
//定义计数器的位宽,$clog2()为取对数操作,在编译过程中执行完成。因此在模块运行过程中CNT_WIDTH是一个确定的数值。
parameter CNT_WIDTH = $clog2(dividor-1);	

reg flag_1;
reg flag_2;
reg [CNT_WIDTH :0] cnt;

always @(posedge clk_in or negedge rst_n)
	if (!rst_n)
		cnt <= 0;
	else if(cnt == dividor-1)
		cnt <= 0;
	else cnt <= cnt + 1'd1;
	
always @(posedge clk_in or negedge rst_n)
	if (!rst_n)
		flag_1 <= 0;
	else if(cnt == (dividor-1>>1))
		flag_1 <= ~flag_1;
	else if(cnt == dividor-1)
		flag_1 <= ~flag_1;		
	else flag_1 <= flag_1;
	
always @(negedge clk_in or negedge rst_n)
	if (!rst_n)
		flag_2 <= 0;
	else if(cnt == (dividor-1 >>1))
		flag_2 <= ~flag_2;
	else if(cnt == dividor-1)
		flag_2 <= ~flag_2;
	else flag_2 <= flag_2;	
	
	assign clk_out = flag_1 || flag_2;
endmodule
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯狂的码泰君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值