CSDN的Markdown不支持Verilog语法高亮(lll¬ω¬) , 代码段颜值大幅下降
Verilog HDL
1.led_test
设计文档:
module led_test(a,b,key_in,led_out);//模块开始,模块名与项层名保持一致
//(端口a,端口b,按键输入,灯的输出)
//定义端口
input a;//输入端口A input表示输入类型ab分 开写利于写注释
input b;//输入端口B
input key_in;//按键输入, 实现输入通道选择
output led_out;//led 控制输出端口
//端口定义完毕,下面进行逻辑设计
//按键按下,低电平,输出与端口A保持一致
//当key_in == 0时,led_out = a
assign led_out = (key_in == 0) ? a : b; //assign--连续赋值语句设计组合逻辑() ?:选择语句
endmodule//模块结尾
仿真文档:
`timescale 1ns/1ps //定义仿真时间精度 延时1纳秒/精度为1皮秒
module led_test_tb;
//激励信号定义,对应连接待测试模块的输入端口
reg signal_a;
reg signal_b;
reg signal_c;
//待检测信号定义,对应连接到待测试模块的输出端口
wire led;
//例化待测试模块
//将定义的三个端子连接在下面的模块上
led_test led_test0( //引入模块并命名为led_test0
.a(signal_a),
.b(signal_b),
.key_in(signal_c),
.led_out(led));
//产生激励
initial begin //开始仿真
signal_a = 0; signal_b = 0; signal_c = 0; //三个按键的初始状态
#100; //延时100ns
signal_a = 0; signal_b = 0; signal_c = 1;
#100; //延时100ns
signal_a = 0; signal_b = 1; signal_c = 0;
#100; //延时100ns
signal_a = 0; signal_b = 1; signal_c = 1;
#100; //延时100ns
signal_a = 1; signal_b = 0; signal_c = 0;
#100; //延时100ns
signal_a = 1; signal_b = 0; signal_c = 1;
#100; //延时100ns
signal_a = 1; signal_b = 1; signal_c = 0;
#100; //延时100ns
signal_a = 1; signal_b = 1; signal_c = 0;
#200;
$stop;//仿真结束,不然会陷入循环
end //这里容易忘记
endmodule
易错点总结
- 文件名和模块名要保持一致
- 模块endmodule,还有仿真激励的end要记得写
2. 3-8译码器、4-16译码器的实现
3-8 译码器
A | B | C | out |
---|---|---|---|
0 | 0 | 0 | 0000_0001 |
0 | 0 | 1 | 0000_0010 |
0 | 1 | 0 | 0000_0100 |
0 | 1 | 1 | 0000_1000 |
1 | 0 | 0 | 0001_0000 |
1 | 0 | 1 | 0010_0000 |
1 | 1 | 0 | 0100_0000 |
1 | 1 | 1 | 1000_0000 |
设计文档
第一版
module my3_8(a,b,c,out);//端口列表
//定义端口类型
input a;//输入端口A
input b;//输入端口B
input c;//输入端口C
//输出端口
output [7:0]out;//[7:0]表示位宽=7+1=8位,高位在前,低位在后
//assign 连续赋值语句
//always@()一旦出现括号中的内容,就开始执行begin和end之间的语句
always@(a,b,c)begin
case({a,b,c})//case语法和C语言差不多 //{}表示位拼接,这里是把abc三个一位的拼接成三位的信号
3'b000:out = 8'b0000_0001;//3位bit 000 //_是占位符,不影响逻辑,只是为了好看
3'b001:out = 8'b0000_0010;
3'b010:out = 8'b0000_0100;
3'b011:out = 8'b0000_1000;
3'b100:out = 8'b0001_0000;
3'b101:out = 8'b0010_0000;
3'b110:out = 8'b0100_0000;
3'b111:out = 8'b1000_0000;
//如果注释了上一句 可以写default:out = 8'b1000_0000;
//两种写法结果相同 同C语言
endcase
end
endmodule
- 但是会出现如下报错
- 报错原因:没有定义output的类型,这里因为使用了always@赋值,所以只能把输出定义为reg
- 只需要在output声明下面加一句:
//输出端口
output [7:0]out;//[7:0]表示位宽=7+1=8位,高位在前,低位在后
reg [7:0]out;
//assign 连续赋值语句
编译结果分析
仿真文件
`timescale 1ns/1ns
module my3_8_tb;
//激励信号源 reg
reg a;
reg b;
reg c;
//观测信号、输出信号 wire
wire [7:0] out;
my3_8 u1( //复制粘贴待仿真文件名及端口列表
.a(a),
.b(b),
.c(c),
.out(out)
);
initial begin
a = 0; b = 0; c = 0;
#200;
a = 0; b = 0; c = 1;
#200;
a = 0; b = 1; c = 0;
#200;
a = 0; b = 1; c = 1;
#200;
a = 1; b = 0; c = 0;
#200;
a = 1; b = 0; c = 1;
#200;
a = 1; b = 1; c = 0;
#200;
a = 1; b = 1; c = 1;
#200;
$stop;
end
endmodule
时域仿真误差分析
- 0000_0001翻转为0000_0010时需要变化两位,而这两位变化的速度不同,所以会出现一个极短的暂态0000_0000
4-16 译码器
类比3-8译码器,不再赘述
易错点总结
- 新建工程时要避免工程名以数字开头,如3-8译码器工程名不可以写“3_8code”,可以写“my3_8code”
- reg是寄存器类型的输出,如果使用了always@进行赋值,只能把输出定义为reg型
- 输出类型有两种reg–寄存器型,wire–线网型