基于Verilog语言分模块设计32位可逆计数器及模块设计中的一些错误!!!
32位可逆计数器分模块设计:
模块划分:
在这个32位可逆计数器中,有加法计数功能和减法计数功能。所以,可以把加法计数放一个模块;同时把减法计数放一个模块;最后,同名顶层模块调用这两个模块实现可逆计数器的设计。
其他:采用同步复位;复位的值可以控制;减法计数一旦计数到0,输出一个标志位;加法计数一旦计数到最大值,输出一个标志位。
模块框图如下:
加法计数模块设计:
module add (
input clk,
input rst,
input [31:0] data,
output reg [31:0] out,
output reg [31:0] q);
always @ (posedge clk )//这里的时钟和复位的关系:同步关系
begin
if(!rst)//复位信号必须要等待时钟的上升沿
out<=data;
else if (out=={
8{
4'b1111}})
begin
q <= {
{
30{
1'b0}},2'b01};//输出标志位
out <= data;
end
else
begin
out<=out+1'b1;
q <= {
{
30{
1'b0}},2'b00};
end
end
endmodule
减法计数模块设计:
module sub (
input clk,
input rst,
input [31:0] data,
output reg [31:0] out,
output reg [31:0] q);
always @ (posedge clk )
begin
if(!rst)
out<= data; //- initial
else if (out=={
8{
4'b0000}})
begin
q <= {
{
30{
1'b0}},2'b10};
out <= data;
end
else
begin
out<=out-1'b1;
q <= {
{
30{
1'b0}},2'b00};
end
end
endmodule
顶层模块设计:
//采用新的编码方式(公司要求)
//当然,大家随意。喜欢就好。这种module的写法更加简单。不过实例化的时候就有一点不爽!!!
module top (
input clk ,
input rst ,
input en ,
input [31:0] data1 ,
input [31:0] data2 ,
output reg [31:0] out_come ,
output reg [31:0] y );
//模块之间的连接必须是线网型(wire)
wire [31:0] a1;
wire [31:0] b1;
wire [31:0] a2;
wire [31:0] b2;
//模块调用不可以放在always块中,这样会报错误。
//if case 等行为级语句必须放在always中,不然也会报错。意思就是if case中的条件错误。反正错误就是这样的。
//错误是检测不到希望调用的模块。
add u_add_0 (.clk(clk),.rst(rst),.data(data1),.out(a1),.q(b1));
sub u_sub_0 (.clk(clk),.rst(rst),.data(data2),.out(a2),.q(b2));
//虽然输出类型是reg,但是赋值方式是阻塞赋值,所以电路是组合逻辑电路。
//always中的敏感列表需要写够;不然会出现错误的逻辑。
//例如:always @ (en) 这样只是看到了表象的“输入(en)”,忽视了“其他输入”,比如a1,a2,b1.b2。
always @ (en or a1 or a2 or b1 or b2)
//always @ (*) //当敏感列表不清楚时,可以使用这个方式写。但是,这样不利于别人读代码。
if(en)
begin
out_come = a1 ;
y = b1 ;
end
else
begin
out_come = a2 ;
y = b2 ;
end
endmodule
32位可逆计数器仿真平台的搭建:
testbench:
module top_tb;
reg clk,rst,en;
reg [31:0] data1,data2;
wire [31:0] out_come;
wire [31:0] y;
top t1 (clk,rst,en,data1,data2,out_come,y);
initial
begin
clk=0;rst=0;en=1;
data1={
{
7{
4'b1111}},4'b0000};
data2={
{
7{
4'b0000}},4'b0111};
#20 rst=1;
#50 rst=0;
#240 rst=1;
#20 en=0;rst=0;
#20 rst=1;
#240 rst=0;
#20 $finish;
end
//时钟周期为12个时间单位
always #6 clk=~clk;
endmodule
仿真结果:
整体仿真图:
局部仿真:
总结:
就是一些错误和需要注意的东西而已。
感想:
本次写这个博客就是因为我发现,自己再模块之间的调用上存在一些问题,新手(如我)很容易犯的一些错误。当自己再写代码的时候,调程序自己调到奔溃。这时的我就像是溺水的人看见什么都想抓,谁知抓住了稻草,但是这样有什么用,还不是淹死了。所以说,最基本的规则不能打破,老老实实练习代码,修改代码,调试程序,看波形。根基不稳、地动山摇。