Modules
The code for module mod_a
looks like this:
module mod_a ( input in1, input in2, output out );
// Module body
endmodule
By position: mod_a instance1 ( wa, wb, wc );
By name: mod_a instance2 ( .out(wc), .in1(wa), .in2(wb) );
Notice the period immediately preceding the port name in this syntax.
在 top_module
中 按名称实例化子模块
Solution
module top_module ( input a, input b, output out );
//mod_a 是已知的
mod_a u1 (.in1(a), .in2(b), .out(out));
endmodule
Connecting ports by position
Solution
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a u1 (out1,out2,a,b,c,d);
endmodule
Connecting ports by name
Solution
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a u1(.out1(out1), .out2(out2), .in1(a), .in2(b), .in3(c), .in4(d));
endmodule
Three modules
Solution
module top_module ( input clk, input d, output q );
wire q1; //别忘了写“;”
my_dff u1 (clk,d,q1);
wire q2;
my_dff u2 (clk,q1, q2);
my_dff u3 (clk,q2,q);
endmodule
Modules and vectors
Solution
module top_module (
input clk,
input [7:0] d,
input [1:0] sel,
output [7:0] q
);
wire [7:0] q1;
my_dff8 u1 (clk, d, q1);
wire [7:0] q2;
my_dff8 u2 (clk, q1, q2);
wire [7:0] q3;
my_dff8 u3 (clk, q2, q3);
always @(*) begin
case (sel)
2'b00: q = d;
2'b01: q = q1;
2'b10: q = q2;
2'b11: q = q3;
default: q = d;
endcase
end
endmodule
always @(*)
里的 (*)
是一种 隐式敏感列表 语法,用于自动推断组合逻辑的触发条件。
作用:当块内所有被读取的信号发生变化时,自动触发块内代码执行。
编写组合逻辑时优先使用 @(*)
,避免敏感列表遗漏导致的错误。
Adder 1
Solution
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire cout_low;
add16 u1 (a[15:0], b[15:0],1'b0, sum[15:0],cout_low);
add16 u2 (a[31:16], b[31:16],cout_low, sum[31:16]);
endmodule
Adder 2
Solution
module top_module (
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire cout_low;
// 用 add1 链接 add16 是题目已知条件
add16 u1 (
.a(a[15:0]),
.b(b[15:0]),
.cin(1'b0),
.sum(sum[15:0]),
.cout(cout_low)
);
add16 u2 (
.a(a[31:16]),
.b(b[31:16]),
.cin(cout_low),
.sum(sum[31:16]),
.cout()
);
endmodule
module add1 ( input a, input b, input cin, output sum, output cout );
// Full adder module here
assign sum = a ^ b ^ cin;
assign cout = (a & b) | (b & cin) | (a & cin);
endmodule
Carry-select adder
进位选择加法器的典型实现:
并行计算 + 多路选择
Solution
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
// 1. 低16位加法:计算a[15:0]+b[15:0],cin=0
wire [15:0] sum_low; // 低16位和
wire cout_low; // 低16位进位输出
add16 u1 (
.a(a[15:0]),
.b(b[15:0]),
.cin(1'b0),
.sum(sum_low),
.cout(cout_low)
);
// 2. 高16位并行计算两种进位假设
wire [15:0] sum_high0; // 假设cin=0时的高16位和
wire [15:0] sum_high1; // 假设cin=1时的高16位和
// 高16位,cin=0
add16 u2 (
.a(a[31:16]),
.b(b[31:16]),
.cin(1'b0),
.sum(sum_high0),
.cout() // 忽略进位输出
);
// 高16位,cin=1
add16 u3 (
.a(a[31:16]),
.b(b[31:16]),
.cin(1'b1),
.sum(sum_high1),
.cout() // 忽略进位输出
);
// 3. 多路选择器:根据cout_low选择高16位的和
assign sum[31:16] = cout_low ? sum_high1 : sum_high0;
assign sum[15:0] = sum_low; // 低16位和直接赋值
endmodule
Adder-subtractor
Adder-subtractor 工作原理:
在二进制运算中,减法 A - B
可通过 “加上 B 的补码” 实现,即: A - B = A + (-B)
.
其中,-B
是 B 的 2 的补码(二进制中最常用的补码形式)。而 2 的补码计算规则为:-B = ~B + 1
(~B
表示对 B 的每一位取反,即 1 的补码,再加 1)。
Solution
module top_module(
input [31:0] a,
input [31:0] b,
input sub,
output [31:0] sum
);
wire [31:0] b_xor; // b与sub异或后的结果(取反控制)
wire cout_lo; // 低16位加法器的进位输出,连接高16位的进位输入
wire [15:0] sum_lo; // 低16位的和
wire [15:0] sum_hi; // 高16位的和
// 1. 对b进行异或处理:sub=1时b取反,sub=0时保持原码
assign b_xor = b ^ {32{sub}}; // {32{sub}}将sub扩展为32位,每一位与b异或
// 2. 实例化低16位加法器(add16_lo)
add16 add16_lo (
.a(a[15:0]), // 低16位输入a
.b(b_xor[15:0]), // 低16位输入b(已异或处理)
.cin(sub), // 进位输入:sub=1时实现"加1",完成补码转换
.sum(sum_lo), // 低16位和输出
.cout(cout_lo) // 低16位进位输出,连接高16位的cin
);
// 3. 实例化高16位加法器(add16_hi)
add16 add16_hi (
.a(a[31:16]), // 高16位输入a
.b(b_xor[31:16]), // 高16位输入b(已异或处理)
.cin(cout_lo), // 低16位的进位作为高16位的进位输入
.sum(sum_hi), // 高16位和输出
.cout() // 高16位进位无需输出(32位结果已包含所有信息)
);
// 4. 拼接低16位和高16位的结果
assign sum = {sum_hi, sum_lo};
endmodule