HDLbits练习记录(三)全程更新
作者:互联网
Modules: Hierarchy
1.Modules
功能:
学会使用实例化模块,类似于函数。
收获:
不同级别的模块的调用,分为两种情况,一种是使用名字接口,另外一种是使用地址接口。
使用地址接口如,mod_a instance1 ( wa, wb, wc ),对于使用地址接口容易产生一种问题就是如果模块的端口列表发生更改,那么还需要找到并更改模块实例化。
使用名字接口如,mod_a instance2 ( .out(wc), .in1(wa), .in2(wb) ),这种是非常常用的一种方式,即使端口列表发生变化,也不用进行太大改动。
代码:
2.Connecting ports by position
功能:
使用地址接口进行实例化。
收获:可以直接使用地址进行接口
代码:
3.Connecting ports by name
功能:使用端口名字进行接口
收获:
代码:
4.Three modules
功能:
使用三个D触发器连接起来。
收获:每一个子模块都要是独一无二的,之间的连接用wire表示线。
代码:
5.Modules and vectors
功能:
练习使用不匹配的矢量长度连接,选择器,always模块。
收获:
always是一个循环模块,也可以不加条件使用。
case 需要在 选择的状态之后加上: case()之后不用加东西。
代码:
6.Adder 1
功能:一个32位加32位的加法器,由两个16位加法器组成,考虑内部进位情况。
收获:
输出端口可以先赋值给一个线性wire,再给输出,也可以直接拼接到输出上。
以后要逐渐养成把定义和主程序分开,前边定义声明部分最好用//分开,这样比较清晰。
代码:
7.Adder 2
功能:
32位加法器,但是是由16个一位加法器和一个16位加法器组合而成,一位加法器的模块需要自己编写。
收获:
1.一位带进位加法器可以不使用case语句的只需要使用 assign {cout,sum} = a + b + cin; 更简单方便。
代码:
注:下边的代码有问题,在addr1模块always模块里边不应该出现给wire型直接赋值的语句,谨记!!!
如果使用复杂代码应该将<=给reg型,或者直接使用assign {a,b}更简单,更方便。
module top_module (
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
//
wire link;
//
add16 add16_inst0(
.a(a[15:0]),
.b(b[15:0]),
.cin(1'b0),
.cout(link),
.sum(sum[15:0])
);
add16 add16_inst1(
.a(a[31:16]),
.b(b[31:16]),
.cin(link),
.cout(),
.sum(sum[31:16])
);
endmodule
module add1 ( input a, input b, input cin, output sum, output cout );
//
// wire [1:0]c;
//
assign {cout,sum} = a + b + cin; //更简单
/* assign c = a + b + cin;
always
begin
case(c)
2'b00:
begin
sum <= 1'b0;
cout <= 1'b0;
end
2'b01:
begin
sum <= 1'b1;
cout <= 1'b0;
end
2'b10:
begin
sum <= 1'b0;
cout <= 1'b1;
end
2'b11:
begin
sum <= 1'b1;
cout <= 1'b1;
end
endcase
end*/
endmodule
问题:
刚开始没有使用两个提供的add16,而是使用自己写的add1,将16个add1串联起来,但是仿真总是在第5340ms出问题,即第1068处,并且之后也会出现大量错误,出现的提示如图所示,我将自己写的16个add1串联的替换成了,add16,可以正常使用,不会产生问题。
但是由于看不到太久之后的仿真,于是我决定在vivado上自己写一个仿真,看一下到底是哪里出错了。
在vivado上运行,发现写的add1麻烦的代码出现了问题,不允许将值直接赋值给输出变量,找到问题了,原来是犯了低级的语法错误!在always语句中,所有变量都必须是reg变量,不能出现wire变量,之前只顾得在项目中学习代码,时不时犯一些低级错误,这次暴露的问题更加说明雕琢基础的重要性,刷完这个,还是要看一下语法书的,基础不牢,地动山摇。
仿真程序无法运行。。。。。。总是卡在current time:0fs
解决:
在写第八部分的时候,突然想到这个问题可能出在哪里了,首先之前自己写的串联的16个addr1是没有使能和选择的,那么在低位进行计算的时候,高位同时也在计算,是并行发生的,但是此时对于高位就会产生问题,在刚开始仿真的时候高位的cin都默认当作0来计算了,之后的仿真中,也会出现两种错误,一种是某个高位的次低位没有进行两个一相加,所以不会产生进位,所以计算结果仍然正确,但是计算过程其实少算了一个cin的值,因为其值并没有更改。第二个错误就是因为计算是并行发生的所以低位计算出来产生了进制一,但由于是并行计算的,所以此时高位已经计算完成数据并且传走了,那么这个进制1很有可能就会传输到下次计算来进行使用了,如果下次计算的次低位还没有产生进制一,那么这个高位计算就会产生错误,计算结果就会有误。
8.Carry-select adder
功能:
选择加法器,之前的串行加法器会产生一些问题,第一速度较慢,需要低位计算完成之后,将进位情况传到高位,高位才能开始计算。第二,个人认为没有使能情况,会导致如果进位情况没有传到cin,可能就会拿之前产生的cin当作了新的cin从而会产生计算错误,而产生这个的原因其实也可以归结于第一个原因,需要等待低位计算结果,但是对于高位来说,除了进位情况所有的都已经准备好了,那么在没有使能情况下,就会产生之前写的那种错误,所以使能个人认为还是很重要的,当然对于选择器来说,选择也是一种使能,这样可以保证了计算进位的正确性。
收获:选择输出可以使用条件运算符
代码:
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
//
wire sel;
wire [15:0]out1,out2;
//
assign sum[31:16] = sel?out2:out1;
add16 add16_inst0(
.a(a[15:0]),
.b(b[15:0]),
.cin(1'b0),
.cout(sel),
.sum(sum[15:0])
);
add16 add16_inst1(
.a(a[31:16]),
.b(b[31:16]),
.cin(1'b0),
.cout(),
.sum(out1)
);
add16 add16_inst2(
.a(a[31:16]),
.b(b[31:16]),
.cin(1'b1),
.cout(),
.sum(out2)
);
endmodule
9.Adder-subtracto
功能:
加法减法器
收获:
代码:
module top_module(
input [31:0] a,
input [31:0] b,
input sub,
output [31:0] sum
);
//
wire [31:0]c;
wire link;
//
assign c = sub?(~b):b;
add16 add16_inst0(
.a(a[15:0]),
.b(c[15:0]),
.cin(sub),
.cout(link),
.sum(sum[15:0])
);
add16 add16_inst1(
.a(a[31:16]),
.b(c[31:16]),
.cin(link),
.cout(),
.sum(sum[31:16])
);
endmodule
标签:16,31,练习,cin,HDLbits,全程,add16,input,sum 来源: https://blog.csdn.net/Kshayebudong/article/details/115565252