Verilog写题笔记9--使用子模块实现三输入数的大小比较
使用子模块实现三输入数的大小比较
https://www.nowcoder.com/practice/bfc9e2f37fe84c678f6fd04dbce0ad27?tpId=301&tqId=5000623&ru=/exam/oj&qru=/ta/verilog-start/question-ranking&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3DVerilog%25E7%25AF%2587%26topicId%3D301
这个题是第一道分子模块的题目:
子模块有四个输入:
1、时钟信号clk
2、复位信号rst_n
3、8位数据a
4、8位数据b
一个输出:
8位数据c
子模块要完成的任务是两个数比大小,这几乎没有难度,也没什么好说的,直接把代码放出来:
module zimokuai( input clk, input rst_n, input [7:0]a, input [7:0]b, output reg [7:0] d_reg ); always@(posedge clk or negedge rst_n) if(rst_n == 1'b0) d_reg <= 8'd0; else if(a < b) d_reg <= a; else d_reg <= b; endmodule这个题主要想考察的还是子模块的调用
Verilog子模块的调用相对于c还是有些麻烦的。Verilog的模块调用主要有一下几点要注意的:
1、顶层模块的所有变量都必须是wire型
理解起来也不是很难,子模块是一个黑盒子,顶层模块只需要将线连到子模块中即可,所以是wire型也就顺理成章了
2、如果是多个子模块调用,子模块的中间输出也必须在顶层模块声明。(当然也是wire型)
这个题就是一个例子,顶层模块调用了 三次子模块,且子模块之间是有联系的,这时顶层模块必须将中间输出也声明出来。
3、子模块的调用的语法结构如下:
子模块名 (必须与子模块名完全相同) 顶层模块名(可以随便起)(
.子模块变量1(必须与子模块中变量名完全相同)(顶层模块变量1),
.子模块变量2(必须与子模块中变量名完全相同)(顶层模块变量2),
...
);
这个是子模块调用的结构。结构的讲解我这里不再赘述。如果读者看不懂,可以先查阅其他资料学习Verilog语法,不用急于做题。
顶层模块需要比较三个数的值,然后再输出最小的。如果我们编译的是c语言,我们很容易想到,只输出极值的比较题,只需要调用两次子模块就好了,第一次比较a和b,然后再将ab的最小值跟c去比即可。
但是,在Verilog中,这个思路是不行的。如果我们按照c语言的思路只用两次子模块,会输出错误的结果。问题在于时序,FPGA是并行执行的,如图所示:
在第一个上升沿,ab进入第一个比较器,c进入第二个比较器。但是比较器输出是需要时间的,在第一个上升沿,c立刻进入第二个比较器,但ab比较器的输出会较晚的进入第二个比较器,这就造成了输入时间不同步,从而造成输出错误。
解决办法也很简单,用三个比较器即可。
用三个比较器的目的是让输入子模块的时间都相等,这样就不会出现进入时间不同导致的错误。
所有代码如下:
`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 ); wire [7:0] x,y; zimokuai zimokuai_inst1( .clk(clk), .rst_n(rst_n), .a(a), .b(b), .d_reg(x) ); zimokuai zimokuai_inst2( .clk(clk), .rst_n(rst_n), .a(a), .b(c), .d_reg(y) ); zimokuai zimokuai_inst3( .clk(clk), .rst_n(rst_n), .a(x), .b(y), .d_reg(d) ); endmodule module zimokuai( input clk, input rst_n, input [7:0]a, input [7:0]b, output reg [7:0] d_reg ); always@(posedge clk or negedge rst_n) if(rst_n == 1'b0) d_reg <= 8'd0; else if(a < b) d_reg <= a; else d_reg <= b; endmodule
verilog写题笔记 文章被收录于专栏
写Verilog题目的一些笔记备忘