首页 > 试题广场 >

使用子模块实现三输入数的大小比较

[编程题]使用子模块实现三输入数的大小比较
  • 热度指数:95420 时间限制:C/C++ 5秒,其他语言10秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解


在数字芯片设计中,通常把完成特定功能且相对独立的代码编写成子模块,在需要的时候再在主模块中例化使用,以提高代码的可复用性和设计的层次性,方便后续的修改。

请编写一个子模块,将输入两个8bit位宽的变量data_a,data_b,并输出data_a,data_b之中较小的数。并在主模块中例化,实现输出三个8bit输入信号的最小值的功能。

子模块的信号接口图如下:


主模块的信号接口图如下:


使用Verilog HDL实现以上功能并编写testbench验证。



输入描述:
clk:系统时钟
rst_n:异步复位信号,低电平有效
a,b,c:8bit位宽的无符号数


输出描述:
d:8bit位宽的无符号数,表示a,b,c中的最小值
采用时序逻辑例化两次子模块时,第一个例化的最小值经过一个时钟周期才能得到,此时若再拿去与第三个数比较大小进行第二次例化时,第三个数已经不是上个周期的数了,解决办法就是将第三个数缓存一个周期,再进行第二次例化子模块,结果可以通过测试。
`timescale 1ns/1ns
module main_mod(
    input clk,
    input rst_n,
    input [7:0]a,
    input [7:0]b,
    input [7:0]c,
    
    output [7:0]d
);

    wire [7:0] c_out1;
    slave_mod s1(
        .clk(clk),
        .rst_n(rst_n),
        .a(a),
        .b(b),
        .c_out(c_out1)
    );
 
    reg [7:0] c1;
    always @(posedge clk, negedge rst_n) begin
        if(!rst_n)
            c1 <= 8'b0;
        else
            c1 <= c;
    end

        slave_mod s2(
        .clk(clk),
        .rst_n(rst_n),
        .a(c_out1),
        .b(c1),
        .c_out(d)
    );   
           
endmodule

module slave_mod(
    input clk,
    input rst_n,
    input [7:0]a,
    input [7:0]b,
    output [7:0] c_out
);
    reg [7:0] c_out;
    always @(posedge clk,negedge rst_n) begin
        if(!rst_n)
            c_out <= 8'b0;
        else
            if(a>b)
                c_out <= b;
            else
                c_out <= a;
    end
            
endmodule

发表于 2022-04-21 18:12:45 回复(5)
不能只例化两次子模块,因为主模块例化的子模块在综合时是复制一样的电路,在执行时是并行执行的。如果只例化两次,第二次例化的值并不是第一个子模块输出的最小值
发表于 2022-03-11 10:04:13 回复(1)
比较器直接构造纯组合逻辑,a、b比较的结果与c比较,比较结果在时钟上升沿所存到FF;
两个比较器就可以了,单时钟周期完成,因此输出结果较testbench提前一个时钟周期
发表于 2022-03-05 12:24:06 回复(9)
一开始是打算例化两个子模块,写出来后发现时序不对,发现如果使用两个子模块的话,由于子模块之间是并行运行的,那么会导致后一个模块的c不会和当前周期的min(a,b)比较,只和前一个周期比较,那么只需要再增加一个模块,第一个模块比较(a,b),第二个模块比较(a,c),第三个模块比较min(a,b)和min(a,c)
发表于 2022-09-13 19:46:59 回复(0)
易错点:该电路为时序逻辑,先选择a、b最小的输出m,然后再将m与c比较输出d,因此需要2拍延迟。如果a、b最小值m直接与c进行比较,则时序错误,c永远比较的都是m的前一拍的值,故需要将c打一拍即可,完成时序对其。

个人觉得这跟综合是否会复制电路没关系,verilog执行每个子module都是并行的,理解输入、输出的时序关系就很好理解了
发表于 2022-05-30 11:41:48 回复(0)
tb里想的是比较器用时序逻辑写,例化3个子模块,这样需要2个周期计算出结果
实际上例化2个子模块也可以,比较器里也可以用组合逻辑写
如果比较器里用组合逻辑写,例化2个或者3个子模块都可以,这样子当前周期就可以直接计算出结果,那么做完之后将输出结果打2拍就和tb结果一致了
如果比较器里用时序逻辑写,例化3个子模块,是和tb一致
如果比较器里用时序逻辑写,例化2个子模块,其中第一个子模块输入a、b,第二个子模块输入ab的最小值和c_1d,这样需要1个周期计算出结果,所以将结果打1拍就可以和tb结果一致

用组合逻辑+2个子模块的代码:
wire [7:0] min_a_b;
    gen_min Inst_a_b (
        .clk    (clk),
        .rst_n    (rst_n),
        .a    (a),
        .b    (b),
        .c    (min_a_b)
    );
    
    wire [7:0] min_a_b_c;
    gen_min Inst_a_b_c (
        .clk    (clk),
        .rst_n    (rst_n),
        .a    (min_a_b),
        .b    (c),
        .c    (min_a_b_c)
    );
    
    reg [7:0] min_abc_1d;
    reg [7:0] min_abc_2d;
    always @ (posedge clk&nbs***bsp;negedge rst_n) begin
        if (~rst_n) begin
            min_abc_1d <= 'd0;
            min_abc_2d <= 'd0;
        end
        else begin
            min_abc_1d <= min_a_b_c;
            min_abc_2d <= min_abc_1d;
        end
    end
    
    assign d = min_abc_2d;


endmodule
module gen_min (
    input clk,
    input rst_n,
    input [7:0] a,
    input [7:0] b,
    
    output reg [7:0] c
);
    
    always @ (*) begin
        if (~rst_n) begin
            c <= 'd0;
        end
        else begin
            if (a <= b) begin
                c <= a;
            end
            else begin
                c <= b;
            end
        end
    end
    

endmodule



发表于 2022-03-13 17:53:42 回复(2)
1.子模块写成组合逻辑,一个周期就可以比较完。比答案早一个周期,要对的话要打一拍。
2,子模块也带时序,用两个模块先比较a和b,a和c。再用一个模块比较它两的结果,跟答案一样。
3,子模块也带时序,一个模块比较a和b得到d1;将c打一拍,再用一个模块比较d2和c,在d1出现的下一个周期得到结果。
发表于 2023-02-09 20:39:23 回复(0)
不能只例化两次模块,逻辑是正确的,但是忽略了时序问题,两个模块同时运行的,第一个模块还没必出结果第二个模块就开始运行了,需要打一拍解决时序问题
发表于 2024-09-01 16:43:21 回复(0)
您提交的代码无法完成编译
:
testbench.v:8: error: Unable to bind wire/reg/memory `testbench' in `test'
1 error(s) during elaboration.
为什么我写完之后自测运行出现这个了
发表于 2024-04-08 16:19:33 回复(2)
注意,题目的时序要求 输出相比输入延迟2拍。因此,如果采用纯组合逻辑实现子模块,需要将输出寄存2拍。
发表于 2023-03-30 20:38:28 回复(0)
正常逻辑比较两次即可,先比较ab,再将ab的最小值和c比较,也就是只需要两个例化模块。然而这样做会报错,改用三个例化模块就没有报错。第一个时钟,比较ab得min_ab,比较ac得min_ac,第二个时钟比较min_ab,min_ac得d
发表于 2022-03-31 16:36:24 回复(0)

`timescale 1ns/1ns
module sub_mod (
    input clk,
    input rst_n,
    input [7:0] a,
    input [7:0] b,
    output reg [7:0] c
);
    wire [8:0] less;
	wire [7:0] d;
	wire [7:0] e;
	generate
		genvar i;
		assign less[0] = 0;
		for(i=7;i>=0;i=i-1)begin
			// assign less[i+1]= (a[i]^b[i])?a[i]:less[i];
			assign e[i] = a[i]^b[i];
			assign less[i+1]= (e[i]&a[i])|((~e[i])&less[i]);
			assign d[i] = (less[8]&b[i])|((~less[8])&a[i]);
		end

	endgenerate
	

    always@(posedge clk&nbs***bsp;negedge rst_n) begin
        if(!rst_n)
            c <= 8'b0;
        else 
            c <= d;
    end
     

endmodule
module main_mod(
	input clk,
	input rst_n,
	input [7:0]a,
	input [7:0]b,
	input [7:0]c,
	
	output wire [7:0]d
);


    wire [7:0] min_ab;
    wire [7:0] min_ac;
    wire [7:0] min_abc;
     
    sub_mod sub_mod_U0(
        .clk      (clk),
        .rst_n    (rst_n),
        .a        (a),
        .b        (b),
        .c        (min_ab)
    );
     
    sub_mod sub_mod_U1(
        .clk      (clk),
        .rst_n    (rst_n),
        .a        (a),
        .b        (c),
        .c        (min_ac)
    );
 
    sub_mod sub_mod_U2(
        .clk      (clk),
        .rst_n    (rst_n),
        .a        (min_ab),
        .b        (min_ac),
        .c        (min_abc)
    );
 
    assign d = min_abc;
endmodule

发表于 2023-08-05 00:20:34 回复(0)
例化三次,也会慢一个时钟周期吗?我仿真时无论例化两个还是三个,都慢一个时钟周期。
发表于 2022-03-25 03:40:39 回复(0)
`timescale 1ns/1ns
module main_mod(
    input clk,
    input rst_n,
    input [7:0]a,
    input [7:0]b,
    input [7:0]c,
    output reg[7:0] m,
    output reg[7:0]d
);
//比较ab找到ab最小值
always@(posedge clk or negedge rst_n)begin
if(!rst_n) begin m<=0;end
else begin
    if(a<b) begin m<=a;end
    else begin m<=b;end
end
end
//将c延迟一个时钟周期
reg[7:0] c1;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin c1<=0; end
        else begin c1<=c;end
end
//将ab的最小值m和延迟过后的c1进行比较得到三个数的最小值
always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin d<=0; end
    else
    if(m<c1) begin d<=m;end
    else begin d<=c1;end
end

endmodule
发表于 2025-03-11 01:04:18 回复(0)
我觉得我这样写也没问题,资源占用更少,不受时钟影响。
`timescale 1ns/1ns
module main_mod(
    input clk,
    input rst_n,
    input [7:0]a,
    input [7:0]b,
    input [7:0]c,
   
    output  [7:0]d
);

wire [7:0] w_m;
wire [7:0] w_n;
main_sub_compare main_sub_compare_inst0(
     .i_clk     ( clk   )
    ,.i_rst_n   ( rst_n )
    ,.i_a       ( a     )
    ,.i_b       ( b     )
    ,.o_c       ( w_m   )
);

main_sub_compare main_sub_compare_inst1(
     .i_clk     ( clk   )
    ,.i_rst_n   ( rst_n )
    ,.i_a       ( c     )
    ,.i_b       ( b     )
    ,.o_c       ( w_n   )
);

main_sub_compare main_sub_compare_inst2(
     .i_clk     ( clk   )
    ,.i_rst_n   ( rst_n )
    ,.i_a       ( w_m   )
    ,.i_b       ( w_n   )
    ,.o_c       ( d     )
);

endmodule

module main_sub_compare(
     input          i_clk
    ,input          i_rst_n
    ,input  [7:0]   i_a
    ,input  [7:0]   i_b

    ,output [7:0]   o_c
);

assign o_c = (i_a > i_b) ? i_b : i_a;   //我觉得去掉o_c的reg这样也可以 这题也许有歧义?

endmodule
发表于 2025-01-10 22:58:35 回复(0)
`timescale 1ns/1ns
module main_mod(
	input clk,
	input rst_n,
	input [7:0]a,
	input [7:0]b,
	input [7:0]c,
	
	output [7:0]d
);

wire [ 7:0] tmp;
reg [ 7:0] a_tmp;
reg [ 7:0] b_tmp;
reg [ 7:0] c_tmp;
reg [ 1:0] cnt;

always @(posedge clk, negedge rst_n) begin
	if (rst_n == 1'h0)
		cnt <= 1'h0;
	else if (cnt == 'h2)
		cnt <= 1'h0;
	else 
		cnt <= cnt + 1'h1;
end

always @(posedge clk, negedge rst_n) begin
	if (rst_n == 1'h0) begin
		a_tmp <= 1'h0;
		b_tmp <= 1'h0;
		c_tmp <= 1'h0;
	end
	else if (cnt == 1'h0) begin
		a_tmp <= a;
		b_tmp <= b;
		c_tmp <= c;
	end
end

sub_mod sub_mod_inst (
	clk,
	rst_n,
	a_tmp,
	b_tmp,
	tmp
);

sub_mod sub_mod_inst1 (
	clk,
	rst_n,
	tmp,
	c_tmp,
	d
);


endmodule


//*********************************************************


module sub_mod (
	input clk,
	input rst_n,
	input [ 7:0] a,
	input [ 7:0] b,
	output [ 7:0] c
);

assign c = a > b ? b : a;


endmodule

发表于 2024-10-25 00:18:52 回复(0)
wire [7:0] c_1;

slave_mod slave_mod_1
(
    .clk(clk),
    .rst_n(rst_n),
    .a(a),
    .b(b),
    .c(c_1)
);

reg [7:0] c_data;

always@(posedge clk or negedge rst_n)
    if(!rst_n)
        c_data <= 1'b0;
    else    
        c_data <= c;

reg c_1_data,c_2_data;

slave_mod slave_mod_3
(
    .clk(clk),
    .rst_n(rst_n),
    .a(c_1),
    .b(c_data),
    .c(d)
);

endmodule

module slave_mod
(
    input clk,
    input rst_n,
    input [7:0]a,
    input [7:0]b,
    output reg [7:0]c
);

always@(posedge clk or negedge rst_n)
    if(!rst_n)
        c <= 1'b0;
    else if(a>b)    
        c <= b;
    else
        c <= a;
发表于 2024-09-01 15:24:53 回复(0)
verilog中,主函数对子函数的调用,子函数不需要写在主函数的上面吗?
发表于 2024-05-01 08:31:45 回复(0)
为什么自测输入会显示时间过长或者复杂富过高呀
`timescale 1ns/1ps
module test();
    reg signed [7:0] a,b,c;
    reg clk,rst_n;
    wire [7:0]d;
    initial  begin
        clk =0;
        rst_n = 0;
        #2
        rst_n = 1;
    end
   
initial begin
    $dumpfile("out.vcd");
    $dumpvars(0,test);
end


initial begin
    a = 8'd15;
    b = 8'd20;
    c = 8'd3;
end

always #10 clk = !clk;

main_mod test(
    .clk(clk),
    .rst_n(rst_n),
    .a(a),
    .b(b),
    .c(c),
    .d(d)
);

endmodule

发表于 2024-03-20 10:56:19 回复(0)
有大佬可以解释一下为什么12,13行报错吗。我感觉我的语法没出现啥问题。
timescale 1ns/1ns
module main_mod(
	input clk,
	input rst_n,
	input [7:0]a,
	input [7:0]b,
	input [7:0]c,
	
	output [7:0]d
);
wire [7:0]w1;
 compare_1(.clk(clk),.rst_n(rst_n),.a(a),.b(b),.c(w1));
 compare_2(.clk(clk),.rst_n(rst_n),.a(w1),.b(c),.c(d));

endmodule

module compare(
	input clk,
	input rst_n,
	input [7:0]a,
	input [7:0]b,
	output [7:0]c
);
always @(posedge clk&nbs***bsp;negedge rst_n)
begin 
	if(~rst_n)
	c=0;
	else 
	if (a<b)
	c=a;
	else
	c=b;
end
endmodule



编辑于 2024-02-29 17:33:17 回复(0)

问题信息

难度:
42条回答 1016浏览

热门推荐

通过挑战的用户

查看代码
使用子模块实现三输入数的大小比较