创建一个下级模块 mod_a,将其的三个端口 in1 ,in2 ,out 按照图中的连接方式,分别连接到顶层模块的 a ,b,out 端口上。
Solution:module top_module ( input a, input b, output out ); mod_a mod_a ( .in1(a), .in2(b), .out(out) ); endmodule
PS:虽然不同的模块写在不同的 .v 文件中,但只要这些模块在开发软件中处于一个 Project。综合器就能在例化模块时,找到对应的模块和 .v 文件。模块中可以例化其他模块,但不允许再定义其他模块。
Timing Diagram: Problem 20: Connecting ports by position(Module pos) Requirement:给出了一个名为 mod_a 的模块,该模块按顺序具有 2 个输出和 4 个输入。将 6 个端口按位置顺序与顶层的端口 out1,out2,a,b,c 和 d 相连接。已知 module mod_a ( output, output, input, input, input, input );
Solution:module top_module ( input a, input b, input c, input d, output out1, output out2 ); mod_a mod_a ( out1, out2, a, b, c, d ); endmodule
PS:对于给出的模块来说,不知道 mod_a 这个模块的端口名是什么,所以只能按照位置的顺序来连接,注意对应好输出输出。
Timing Diagram: Problem 21: Connecting ports by name(Module name) Requirement:给出了一个名为 mod_a 的模块,该模块按某种顺序具有 2 个输出和 4 个输入。将 6 个端口按名字与顶层的端口相连接。已知 module mod_a ( output out1, output out2, input in1, input in2, input in3, input in4);
Solution:module top_module ( input a, input b, input c, input d, output out1, output out2 ); mod_a mod_a ( .in1(a), .in2(b), .in3(c), .in4(d), .out1(out1), .out2(out2), ); endmoduleTiming Diagram: Problem 22: Three modules(Module shift) Requirement:
给出了一个名为 my_dff 的模块,包含两个输入和一个输出(实现D触发器的功能)。实例化三个 my_dff,然后将它们连接在一起,构成长度为 3 的移位寄存器。已知:module my_dff ( input clk, input d, output q );
Solution:module top_module ( input clk, input d, output q ); wire w12,w23; my_dff d1 ( .clk(clk), .d(d), .q(w12) ); my_dff d2 ( .clk(clk), .d(w12), .q(w23) ); my_dff d3 ( .clk(clk), .d(w23), .q(q) ); endmodule
PS:要在模块内部进行连接,需要先声明一些连线。
Timing Diagram: Problem 23: Modules and vectors(Module shift8) Requirement:本题给出了一个名为 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 );
Solution:module top_module ( input clk, input [7:0] d, input [1:0] sel, output reg [7:0] q ); wire [7:0] w1,w2,w3; my_dff8 my_dff81 ( .clk(clk), .d(d), .q(w1) ); my_dff8 my_dff82 ( .clk(clk), .d(w1), .q(w2) ); my_dff8 my_dff83 ( .clk(clk), .d(w2), .q(w3) ); always @(*) begin case (sel) 0: begin q <= d; end 1: begin q <= w1; end 2: begin q <= w2; end 3: begin q <= w3; end endcase end endmodule
PS:向量可以取代单根连接线作为模块的端口。正如 Verilog 的语法一样,端口的向量长度不必与连接到它的导线匹配,但这将导致向量的零填充或截断(高位填充,高位截断)。
注意:没有给出多路复用器,一种实现方法是在一个always块内使用case语句。必须在 always 块内才能使用 case 语句,否则报错。还有 case 中的 q 必须是 reg 型,不能是 wire 型,因为不能持续地赋值(assign),得有记忆性。
Why:case 语句属于行为级建模,必须用在过程块中,即 always 或者 initial 中的 begin…end 或者 fork…join 语句中,但是由于 initial 语句块一般只用于测试,不可综合,因此只考虑 always 语句块中使用 case 语句。
Timing Diagram: Problem 24: Adder 1(Module add) Requirement:给出了一个可以做 16bit 加法的模块 add16,实例化两个 add16 以达到 32bit 加法。一个 add16 模块计算结果的低 16 位,另一个 add16 模块在接收到第一个的进位后计算结果的高 16 位。此 32bit 加法器不需要处理输入进位(假设为0)和输出进位(无需进位),但为了结果的正确仍要处理进位信号。也就是 add16 模块执行 16bit 的 a+b+cin,而顶层模块执行 32bit 的 a+b。
已知 16 bit 的模块声明为:
module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );
Solution:module top_module( input [31:0] a, input [31:0] b, output [31:0] sum ); parameter z = 0; wire w; add16 add1 ( .a(a[15:0]), .b(b[15:0]), .cin(z), .sum(sum[15:0]), .cout(w) ); add16 add2 ( .a(a[31:16]), .b(b[31:16]), .cin(w), .sum(sum[31:16]) ); endmodule
PS:进位信号没有线网所连接就不用写了。
Timing Diagram: Problem 25: Adder 2(Module fadd) Requirement:在本题中,您将描述一个具有两级层次结构的电路。在 top_module 中,实例化两个 add16 模块,每个 add16 中实例化 16 个 add1 实例。与 Problem 24 一样,32 位加法器同样不需要处理进位输入(假设为0)和进位输出(无需进位)信号。
已知:module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );
总之,本题中一共有三个模块:
1、top_module:包含两个 16 位加法器的顶层模块;
2、add16(已给出):一个16bit的加法器,由16个全加器构成;
3、add(未给出):1bit全加器。
需要描述两个模块:top_module 和 add1。
小提示:全加器的逻辑表达式
Solution:module top_module ( input [31:0] a, input [31:0] b, output [31:0] sum ); wire w; add16 add1 ( .a(a[15:0]), .b(b[15:0]), .cin(1'b0), .sum(sum[15:0]), .cout(w) ); add16 add2 ( .a(a[31:16]), .b(b[31:16]), .cin(w), .sum(sum[31:16]) ); endmodule module add1 ( input a, input b, input cin, output sum, output cout ); assign sum = a ^ b ^ cin; assign cout = (a & b) | (a&cin) | (b & cin); endmoduleTiming Diagram: Problem 26: Carry-select adder (Module cseladd) Requirement:
Problem 25 实现的加法器叫做行波进位加法器(RCA: Ripple-Carry Adder),缺点是计算进位输出的延迟是相当慢的(最坏的情况下,来自于进位输入),前一级加法器计算完成之前,后一级加法器不能开始计算,使得加法器的计算延迟变大。
这次来实现一个改进型的加法器,第一级加法器保持不变,第二级加法器实现两个,一个假设进位为0,另一个假设进位为1。然后使用第一级结果和 2 选 1 选择器来选择哪一个结果是正确的。
已知模块 add16 为:module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );
Solution:module top_module ( input [31:0] a, input [31:0] b, output reg [31:0] sum ); wire w; reg [15:0] s0,s1; add16 add1 ( .a(a[15:0]), .b(b[15:0]), .cin(1'b0), .sum(sum[15:0]), .cout(w) ); add16 add2 ( .a(a[31:16]), .b(b[31:16]), .cin(1'b0), .sum(s0) ); add16 add3 ( .a(a[31:16]), .b(b[31:16]), .cin(1'b1), .sum(s1) ); always @(*) begin if (w == 0) begin sum[31:16] = s0; end else begin sum[31:16] = s1; end end endmodule
改进:二选一直接用问号冒号语句就行,还能用 wire 类型。
assign sum[31:16] = w ? s1 : s0;
PS:这是选择进位加法器(CSA: Carry-Select Adder),相对于上一题的行波进位加法器(也叫逐级进位加法器,RCA: Ripple-Carry Adder)延迟小一半左右,但是比增多了50%的逻辑资源。
Timing Diagram: Problem 27: Adder–subtractor (Module addsub) Requirement:减法器可以由加法器来构建,对其中一个数取相反数(逐位取反加1)即可。
已知:module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );
如下图所示构建加减法器,要求实例化两次 add16:
当 sub 为 1 时,使用 32 位的异或门对 b 进行取反(这也可以被视为 b[31:0] 与 sub 复制 32 次相异或),同时 sub 信号连接到加法器的进位。
Solution:module top_module( input [31:0] a, input [31:0] b, input sub, output [31:0] sum ); wire w; wire [31:0] b_xor; assign b_xor = b ^ {32{sub}}; add16 add1( .a(a[15:0]), .b(b_xor[15:0]), .cin(sub), .sum(sum[15:0]), .cout(w) ); add16 add2( .a(a[31:16]), .b(b_xor[31:16]), .cin(w), .sum(sum[31:16]) ); endmodule
PS:异或门也可以看作是可编程的非门,其中一个输入控制输出为另一个输入或是其反。以下两个电路都是异或门:
Timing Diagram:PS:还有好多题啊,俗话说的好,一口气吃不成一个胖子,继续加油哇!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)