跳转至

与非门

在学习过第一节的内容之后,部分同学应该已经使用硬件描述语言进行了部分尝试,比如实现其他逻辑门,在模块体中加入更多内容等等。

有的同学会问出这样一个问题:在 c++ 中,我们可以进行函数的调用,那么在硬件描述语言当中,我们能不能进行模块的“调用”呢?本节将会通过与非门这个例子来解决大家的问题。

非门

在实现与非门之前,我们还需要实现另一个非门模块,这与上一节中的与门类似,这里不多赘述。

module not_gate (
    input wire a_i,
    output wire b_o
);
    assign b_o = ~a_i;
endmodule

值得一提的是,在硬件描述语言当中,所有 c++ 中的位运算 (&, |,~, ^) 均可使用,且功能与 c++ 中一致。

与非门

现在我们已经有了与门和非门了,只需要在新的与非门模块中,"调用" 这两个模块,并将与门的输出连接到非门的输入,将与非门的输入输出分别和与门输入和非门输出连接就可以了。这里明确一个概念,在硬件描述语言中,一个模块 A 要在内部引用另一个模块 B 的功能,我们称做在 A 中 "(实) 例化" (instantiate) B。

为此,我们首先定义与非门模块:

module nand_gate (
    input wire nand_a_i,
    input wire nand_b_i,
    output wire nand_c_o
);
    // TODO
endmodule

然后就是接入与门和非门模块了。

首先,我们需要一个额外导线,用来连接与门的输出和非门的输入。为此需要在模块体中进行定义,语法与 c++ 中的变量声明类似。代码如下:

wire and_o;

注意到,由于这里是定义内部信号,因此不再需要像模块的输入输出一样指明信号的方向。

Verilog / System Verilog 中的模块例化与 c++ 中的自定义类型的变量声明类似,例化与门的代码如下。

and_gate a1 (
    .a_i(nand_a_i),
    .b_i(nand_b_i),
    .c_o(and_o)
);

可以看到,例化一个模块需要确认其模块类型,同时给这个例化出来的模块一个模块名字,并在后面的参数列表中进行连线。连线需要明确用自己的什么信号,与模块中的什么信号进行连接。当上述这些内容都确定好之后,一个模块的例化就完成了。

类似地,进行非门的例化,代码如下:

not_gate n1 (
    .a_i(and_o),
    .b_o(nand_c_o)
);

这样就完成了与非门的设计和编写了,全部代码整理如下:

module nand_gate (
    input wire nand_a_i,
    input wire nand_b_i,
    output wire nand_c_o
);
    wire and_o;

    and_gate a1 (
        .a_i(nand_a_i),
        .b_i(nand_b_i),
        .c_o(and_o)
    );

    not_gate n1 (
        .a_i(and_o),
        .b_o(nand_c_o)
    );
endmodule

小结

模块例化语法:

<module-type> <module-name> (
    <connection-list>
);

例化连线语法:

.<module's-signal-name>(<expression>) // separate by ,

中间连线信号定义语法:

wire <signal-name>;

最后更新: 2023年4月4日
作者:cuibst (98.33%), Jiajie Chen (1.67%)