LJgibbs · 2020年09月22日

HDLBits:在线学习Verilog( 五 · Problem 20-24)

转载自:知乎
本系列文章将和读者一起巡礼数字逻辑在线学习网站 HDLBits 的教程与习题,并附上解答和一些作者个人的理解,相信无论是想 7 分钟精通 Verilog,还是对 Verilog 和数电知识查漏补缺的同学,都能从中有所收获。

传送门:Module pos - HDLBits

Problem 20: Connecting ports by position(Module pos)

牛刀小试

本题与前一个问题(Problem 19: Modules)相似。给出了一个名为mod\_a的模块,该模块按顺序具有2个输出和4个输入。必须将6个端口按位置顺序与顶层的端口out1,out2,a,b,c和d相连接。

给出的模块如下:

module mod_a ( output, output, input, input, input, input );

解答与分析

module top_module ( 
    input a, 
    input b, 
    input c,
    input d,
    output out1,
    output out2
);

    mod_a name(out1,out2,a,b,c,d);
    
endmodule

从Problem 19开始进入了模块层次类,主要考查的是模块之间的连接问题,模块之间有两种连接模式,在Problem 19中应该已经尝试过这两种连接模式了。

但是在本题中对于给出的模块来说,我们并不知道mod\_a这个模块的端口名是什么,所以对于本题来说,只能按照位置的顺序来连接。

对于题中给出的模块来说,如果在写文档的时候这样只表注输入输出端口而没有名字是不规范的。自己写文档的时候要避免。

Problem 21: Connecting ports by name(Module name)

牛刀小试

这道题仍然与Problem 19: Modules相似。给出了一个名为mod\_a的模块,该模块按某种顺序具有2个输出和4个输入。必须将6个端口通过按名字的方法与顶层的端口相连接。

给出的模块如下:

module mod_a ( output out1, output out2, input in1, input in2, input in3, input in4);

解答与分析

module top_module ( 
    input a, 
    input b, 
    input c,
    input d,
    output out1,
    output out2
);

    mod_a name(
        .out1(out1),
        .out2(out2),
        .in1(a),
        .in2(b),
        .in3(c),
        .in4(d));
    
endmodule

这道题有人拿到手说跟上一题一样,本质是一样的,但是本题必须写成这种按模块端口名称的连接方式,因为这种方式可以不按顺序来连接,所以题目给出的out1, out2, a, b, c, d不是mod\_a正确的顺序,可以尝试一下,本题如果按上题来解答,写成下面的形式的话会报错的。

mod_a name(out1,out2,a,b,c,d);

Problem 22: Three modules(Module shift)

牛刀小试

给出了一个名为my\_dff的模块,包含两个输入和一个输出(实现D触发器的功能)。实例化三个my\_dff,然后将它们连接在一起,构成长度为3的移位寄存器。注意:clk端口需要连接到所有的寄存器实例上。

给出的模块如下:

module my_dff ( input clk, input d, output q );

注意:要在模块内部进行连接,您可能需要先声明一些连线。 注意命名连线和模块实例时,它们的名字必须是唯一的。

module top_module (
    input clk,
    input d,
    output q
);

    wire a, b;    // 声明两个wire变量,命名为a, b

    // 对my_dff进行了三次实例化,用了三个不用的名字 (d1, d2, and d3).
    // 端口使用了位置连接的方式( input clk, input d, output q)
    my_dff d1 ( clk, d, a );
    my_dff d2 ( clk, a, b );
    my_dff d3 ( clk, b, q );

endmodule

Problem 23: Modules and vectors(Module shift8)

本题是Problem 22: Connecting ports by name(Module shift8)的扩展。我们现在知道了向量可以取代单根连接线作为模块的端口。在连接时使用的也是向量连接而不是单根导线。正如Verilog的语法一样,端口的向量长度不必与连接到它的导线匹配,但这将导致向量的零填充或截断。在本练习中不使用具有不匹配的向量连接。

牛刀小试

给出了一个名为my\_dff8的模块,包含两个输入和一个输出(实现一个8bit的D触发器)。请实例化三个,并将它们连接在一起,形成一个长度为3的8bit移位寄存器。此外,再写出一个4选1多路复用器(未提供模块模型),根据输入的sel[1:0]选择要输出的内容:输入D的值,在第一个D触发器之后的值,第二个或第三个D触发器之后的值。(可以说sel选择的是输入延迟的的周期数,0~3个时钟周期不等。)

给出的模块如下:

module my_dff8 ( input clk, input [7:0] d, output [7:0] q );

没有给出多路复用器。 一种实现方法是在一个always块内使用case语句。(另见:Problem62: 9-to-1 multiplexer(Mux9to1v))

解答与分析

module top_module (
    input clk,
    input [7:0] d,
    input [1:0] sel,
    output reg [7:0] q
);

    wire [7:0] o1, o2, o3;        // 声明每一个触发器的输出
    
    // Instantiate three my_dff8s
    my_dff8 d1 ( clk, d, o1 );
    my_dff8 d2 ( clk, o1, o2 );
    my_dff8 d3 ( clk, o2, o3 );

    // 这是实现4选1选择器的一种方法
    always @(*)        // 组合逻辑always块
        case(sel)
            2'h0: q = d;
            2'h1: q = o1;
            2'h2: q = o2;
            2'h3: q = o3;
        endcase

endmodule

Problem 24: Adder 1(Module add)

牛刀小试

给出了一个可以做16bit加法的模块add16,实例化两个add16以达到32bit加法的。一个add16模块计算结果的低16位,另一个add16模块在接收到第一个的进位后计算结果的高16位。此32bit加法器不需要处理输入进位(假设为0)和输出进位(无需进位),但为了内部模块为了结果的正确仍要处理进位信号。(换句话说,add16模块执行16bit的a+b+cin,而顶层模块执行32bit的a+b)

将模块如下图所示连接在一起,给出的模块如下:

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 cout1;
    
    add16 add1(a[15:0],b[15:0],1'b0,sum[15:0],cout1);
    add16 add2(a[31:16],b[31:16],cout1,sum[31:16],);//注意这里进位信号没有线网所连接
    
endmodule

推荐阅读

关注此系列,请关注专栏FPGA的逻辑
推荐阅读
关注数
10596
内容数
559
FPGA Logic 二三事
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息