题目来源于牛客网
[牛客网在线编程_Verilog篇_Verilog快速入门 (nowcoder.com)](https://www.nowcoder.com/exam/oj?page=1&tab=Verilog篇&topicId=301)
描述
在数字芯片设计中,通常把完成特定功能且相对独立的代码编写成子模块,在需要的时候再在主模块中例化使用,以提高代码的可复用性和设计的层次性,方便后续的修改。
请编写一个子模块,将输入两个8bit位宽的变量data_a,data_b,并输出data_a,data_b之中较小的数。并在主模块中例化,实现输出三个8bit输入信号的最小值的功能。
子模块的信号接口图如下:
主模块的信号接口图如下:
输入描述:
clk:系统时钟
rst_n:异步复位信号,低电平有效
a,b,c:8bit位宽的无符号数
输出描述:
d:8bit位宽的无符号数,表示a,b,c中的最小值
在Verilog中,可以使用module
关键字编写子模块。子模块是一种将较大的电路拆分为模块化部分的方法,使代码更易于维护和重复使用。
以下是一个简单的示例,展示了如何编写一个加法器子模块:
module Adder(
input [3:0] A,
input [3:0] B,
output [4:0] Sum
);
assign Sum = A + B;
endmodule
通过将子模块实例化到另一个模块中,可以在主模块中使用子模块。
下面是一个示例,展示了如何实例化并使用上述的加法器子模块:
module Top;
// 输入和输出端口声明
reg [3:0] A;
reg [3:0] B;
wire [4:0] Sum;
// 子模块实例化
Adder adder_inst(.A(A), .B(B), .Sum(Sum));
// 在这里可以使用子模块的输出Sum
// ...
endmodule
例化一个模块,该模块比较两个输入的大小,并输出较小的数。
例化两次该模块,实现三个数的比较。
注:
采用时序逻辑例化两次子模块时,第一个例化的最小值经过一个时钟周期才能得到,
此时若再拿去与第三个数比较大小进行第二次例化时,第三个数已经不是上个周期的数了,
解决办法就是将第三个数缓存一个周期,再进行第二次例化子模块,结果可以通过测试。
`timescale 1ns/1ns
module main_mod(
input clk,
input rst_n,
input [7:0]a,
input [7:0]b,
input [7:0]c,
output [7:0]d //由图可知,a,b,c,d全为wire型
);
wire [7:0] min_ab;
//第一次例化,比较a,b的大小
compare u_compare(
.clk(clk),
.rst_n(rst_n),
.data_a(a),
.data_b(b),
.data_c(min_ab)
);
/*采用时序逻辑例化两次子模块时,第一个例化的最小值经过一个时钟周期才能得到,
此时若再拿去与第三个数比较大小进行第二次例化时,第三个数已经不是上个周期的数了,
解决办法就是将第三个数缓存一个周期,再进行第二次例化子模块,结果可以通过测试。
*/
reg [7:0] c_r; //将c的值存储起来
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
c_r <= 0;
else
c_r <= c;
end
//第二次例化,比较a,b,c的大小
compare u_compare_2(
.clk(clk),
.rst_n(rst_n),
.data_a(min_ab),
.data_b(c_r),
.data_c(d)
);
endmodule
//子模块:比较data_a,data_b的大小,并且输出较小的数
module compare(
input clk,
input rst_n,
input [7:0]data_a,
input [7:0]data_b,
output [7:0]data_c
);
reg [7:0] result; //定义一个reg型,将比较结果存起来
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
result <=0;
else begin
if(data_a > data_b)
result <= data_b;
else if(data_a <= data_b)
result <= data_a;
end
end
assign data_c = result;
endmodule