[Verilog15]HDLBits习题_Modules: Hierarchy

HDLBits习题讲解_Modules: Hierarchy

元件例化

  • 当我们在调用别人已经写好的IP核,或者使用自己的IP核时,需要对IP核进行元件例化操作
  • 例化的目的是在上一级模块中调用例化的模块完成代码功能,在 Verilog 里例化信号的格式如下:模块名必须和要例化的模块名一致,包括模块信号名也必须一致。连接信号为 TOP 程序跟模块之间传递的信号,模块与模块之间的连接信号不能相互冲突,否则会产生编译错误。
  • 实际使用中,会有两种例化形式,具体格式如下:
//按信号位置例化(不推荐)
mudule_name  new_module_name(new_signal_1,new_signal_2,new_signal_3);
//按信号名称例化(推荐)
mudule_name  new_module_name
(
    .signal_1   (new_signal_1),
    .signal_2   (new_signal_2),
    .signal_3   (new_signal_3)
);

Modules

  • 题目要求使用原件例化,连接mod_a模块。mod_a的模块代码如下:
module mod_a ( input in1, input in2, output out );
    // Module body
endmodule
  • 代码如下:
//按信号位置例化(不推荐)
module top_module ( input a, input b, output out );
    mod_a u_mod_a(a,b,out);
endmodule
//按信号名称例化(推荐)
module top_module ( input a, input b, output out );
    mod_a u_mod_a(
        .in1(a),
        .in2(b),
        .out(out)
    );
endmodule

Connecting ports by position

  • 题目要求使用原件例化,连接mod_a模块。mod_a的模块代码如下:
module mod_a ( output, output, input, input, input, input );
    //module body
endmodule
  • 要求按信号位置进行例化,连接顺序为out1,out2,a,b,c,d,代码如下:
module top_module ( 
    input a, 
    input b, 
    input c,
    input d,
    output out1,
    output out2
);
    mod_a u_mod_a(out1,out2,a,b,c,d);
endmodule

Three modules

  • 已有一个模块my_dff,其中有两个输入和一个输出(D触发器)。实例化三个D触发器然后将它们连接在一起,实现一个长度为3的移位寄存器。clk端口需要连接到所有my_dff实例。my_dff的模块代码如下:
module my_dff ( input clk, input d, output q );
  • 按如图所示的顺序例化并连接三个模块,代码如下:
module top_module ( input clk, input d, output q );
    wire q0,q1;
    my_dff u0_my_dff(
        .clk(clk),
        .d(d),
        .q(q0)
    );
    my_dff u1_my_dff(
        .clk(clk),
        .d(q0),
        .q(q1)
    );
    my_dff u3_my_dff(
    	.clk(clk),
        .d(q1),
        .q(q)
    );
endmodule

__tips:__在命名wire和例化module时,名称必须是独一无二的

Modules and vectors

  • 有一个模块my_dff8,它具有两个输入和一个输出(实现一组8位的D触发器)。实例化其中的三个,然后将它们连接在一起,实现一个长度为3的8位宽移位寄存器。另外,构造一个4-1多路选择器,根据sel[1:0]选择输出值。本质上,sel选择的是延迟输入的周期。
  • 已有模块代码如下:
module my_dff8 ( input clk, input [7:0] d, output [7:0] q );
  • 按如图所示的顺序例化并连接,代码如下:
module top_module ( 
    input clk, 
    input [7:0] d, 
    input [1:0] sel, 
    output [7:0] q 
);
    wire [7:0] q0,q1,q2;
    
    my_dff8 u0_my_dff8(
        .clk(clk),
        .d(d),
        .q(q0)
    );
    my_dff8 u1_my_dff8(
        .clk(clk),
        .d(q0),
        .q(q1)
    );
    my_dff8 u3_my_dff8(
    	.clk(clk),
        .d(q1),
        .q(q2)
    );
    assign q = sel[1]? (sel[0]?q2:q1):(sel[0]?q0:d);//多路选择器
endmodule

Adder 1

  • 题目要求使用两个带进位的16bit加法器组成一个32bit加法器。一个加法器用于计算结果的低16位,而另一个加法器用于计算结果的高16位。所提供的模块声明如下:
module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );
  • 代码编写如下:
module top_module(
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
	wire cout_0;
    add16 u0_add16(
        .a(a[15:0]),
        .b(b[15:0]),
        .cin(1'b0),
        .sum(sum[15:0]),
        .cout(cout_0)
    );
    add16 u1_add16(
        .a(a[31:16]),
        .b(b[31:16]),
        .cin(cout_0),
        .sum(sum[31:16]),
        .cout()
    );
endmodule

Adder 2

  • 如图中所示的模块结构,我们的top_module例化了2个16位的加法器予以实现,而每个16位的加法器又是例化了16个1位的全加器加以实现。题目要求,自定义一个1bit的全加器,构成一个16bit全加器,然后用两个16bit全加器完成32bit加法模块的搭建,忽略进位。具体任务如下
  1. 定义一个1bit全加器。
  2. 在顶层完成两个16bit全加器的调用。
  • 题目提供一个16位加法器模块,具体代码如下:
module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );
  • 需要用户自行编写并声明的1位加法器,输入输出接口定义如下:
module add1 ( input a, input b, input cin, output sum, output cout );
  • 代码编写如下:
module top_module (
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);//
    wire cout_0;
	add16 u0_add16 (
        .a(a[15:0]),
        .b(b[15:0]),
        .cin(0),
        .sum(sum[15:0]),
        .cout(cout_0)
    );
    add16 u1_add16(
        .a(a[31:16]),
        .b(b[31:16]),
        .cin(cout_0),
        .sum(sum[31:16]),
        .cout()
    );
endmodule

module add1 ( input a, input b, input cin,   output sum, output cout );
// Full adder module here
    assign {cout,sum} = a + b + cin;
endmodule

Carry-select adder

  • 传统的级联加法器,随着加法器的数量不断增加,加法器的速度会变得越来越慢,这是因为每一个后级均在等待前一级的计算结果。故若我们更加追求执行速度而不在意资源使用的话,可使用超前进位加法器以获得更小的时延。
  • 本题将两个带进位的16位数字相加,并生成一个输出进位和16位的和。并将输出进位用于控制一个16位2-1多路选择器,用于选择高位的计算结果。题目提供一个16位加法器模块,具体代码如下:
module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );
  • 代码编写如下:
module top_module(
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
    wire [15:0] highout0;
    wire [15:0] highout1;
    wire cout;
    add16 u_add16_low(
        .a(a[15:0]),
        .b(b[15:0]),
        .cin(0),
        .sum(sum[15:0]),
        .cout(cout)
    );
    add16 u_add16_high0(
        .a(a[31:16]),
        .b(b[31:16]),
        .cin(0),
        .sum(highout0),
        .cout()
    );
    add16 u_add16_high1(
        .a(a[31:16]),
        .b(b[31:16]),
        .cin(1),
        .sum(highout1),
        .cout()
    );
    assign sum[31:16] = (cout)? highout1:highout0;
endmodule

Adder-subtractor

  • 题目要求利用sub信号和两个16bit的全加器,实现32bit的加减法运算。对输入的sub信号进行判断,如果sub=0,则输出(a + b + 0);如果sub=1,则输出(a + ~b + 1)。题目提供一个16位加法器模块,具体代码如下:
module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0]sum, output cout );
  • 代码编写如下:
module top_module(
    input [31:0] a,
    input [31:0] b,
    input sub,
    output [31:0] sum
);
    wire [31:0] b_processed;
    wire cout_temp;
    assign b_processed = b ^ {32{sub}}; 
    add16 u_add16_lower(
        .a(a[15:0]),
        .b(b_processed[15:0]),
        .cin(sub),
        .sum(sum[15:0]),
        .cout(cout_temp)
    );
    add16 u_add16_higher(
        .a(a[31:16]),
        .b(b_processed[31:16]),
        .cin(cout_temp),
        .sum(sum[31:16]),
        .cout()
    );
endmodule

参考:
HDLBits
HDLBits答案(3)_Verilog模块的例化与调用