Verilog——38译码器(包括仿真文件和约束文件的格式)

Verilog——38译码器(包括仿真文件和约束文件的格式)_第1张图片

描述方式

之前说过,verilog属于高级语言,需要软件设计硬件结构来实现,也说过描述方式是有很多种的,下面介绍一下。
Verilog——38译码器(包括仿真文件和约束文件的格式)_第2张图片
结构描述十分底层,相当于自己搭电路;
行为描述最简单,只需要写出输入对应的输出就行,例子中需要case语句。
数据流描述比较玄学,还需要找关系,感觉也不太好。

对于题目38译码器这样一个简单的器件,我们选择行为描述的方式最简单(要是有个十几个输入,case语句直接爆炸,所以这种方式也是有限制的

代码:

`timescale 1ns / 1ps        //时钟信号的精度和周期

module decoder_38(
    input [2:0] data_i,     //输入数据
    input [2:0] en_i,       //使能端,高低有效看要求,这里是0、1位低有效,2位高有效
    output reg [7:0] data_o //输出的八位数据
);
always @(*) begin
    if(en_i[0] || en_i[1] || !en_i[2])  //注意一下,译码器一般默认是低有效,所以全1相当于使能端无效
        data_o = 8'b1111_1111;
    else 
        case (data_i)
            3'b000: data_o = 8'b1111_1110;
            3'b001: data_o = 8'b1111_1101;
            3'b010: data_o = 8'b1111_1011;
            3'b011: data_o = 8'b1111_0111;
            3'b100: data_o = 8'b1110_1111;
            3'b101: data_o = 8'b1101_1111;
            3'b110: data_o = 8'b1011_1111;
            3'b111: data_o = 8'b0111_1111;
        endcase
end
endmodule

(虽然说是低有效,但是最后连接板子上的led还是高有效的,然后就会全反了……实际需要还是按需求改一下吧)

仿真文件

先贴代码(因为verilog就是仿C的,这里直接使用了C的代码块)

`timescale 1ns / 1ps

module decoder_38_sim ();
// 输入端口
reg [2:0] data_in;
reg [2:0] en;
// 输出端口
wire [7:0] data_out;
// 结合自己的实现完成实例化
decoder_38 U_dec38_0(
    .data_i (data_in),
    .en_i (en),
    .data_o (data_out)
);
initial begin
// 构造输入激励信号
    #5 begin en = 3'b100; data_in = 3'b000; end
    #5 begin en = 3'b100; data_in = 3'b001; end
    #5 begin en = 3'b100; data_in = 3'b010; end
    #5 begin en = 3'b100; data_in = 3'b011; end
    #5 begin en = 3'b100; data_in = 3'b100; end
    #5 begin en = 3'b100; data_in = 3'b101; end
    #5 begin en = 3'b100; data_in = 3'b110; end
    #5 begin en = 3'b100; data_in = 3'b111; end
    // 使能端无效
    #5 begin en = 3'b101; data_in = 3'b000; end 
    // 结束仿真
    #5 $stop;
end
endmodule
  • 第一行,1ns是时间间隔,也就是仿真上的一个单位长度,但是其精度达到了1np,当然这些都是套话,不用管就行。
  • module decoder_38_sim ()是文件创建自带的,我们不需要这个模块,不用管他
  • 创建reg和wire型变量,眼尖的人就会看出这些变量刚好就是decoder_38的输入输出(reg输入wire输出),如果分不清reg和wire区别这样记也还好。
  • reg需要赋初值,不然仿真会有不定态;wire千万别赋值,赋值biss
  • 调用之前写好的译码器模块,调用注意事项:
  1. 首先要知道,sim和代码文件都是.v文件,也就意味着两者书写规则基本上差不多,只不过一个因为有变量赋值可以跑出来波形而已。
  2. 模块调用不但是这里,包括在源文件如果有多个模块,也需要这样调用,最后只能有一个顶层模块被使用。
  3. 模块调用的基本格式:被调模块+被调模块在该部分的小名+变量列表(小名的意义在于一个模块调用相同模块多次)
  4. 模块调用和高级语言的函数差不多,被调模块的输入输出都要给出。
  5. 模块调用的方式有两种,上面的形式比较标准,.被调模块变量名(调用模块变量名)不要搞反了,这种情况下变量顺序不做要求
  6. 另外一种比较简短的形式就是直接调用,直接(data_in,en,data_out),这时候就不需要被调模块的变量名了,但是一定要对齐

仿真文件本质上就是调用模块并按照一定的时间给输入变量赋值,然后观看调用模块后的输出变量是怎样的,所以需要我们决定怎么赋值和赋值的时间问题。

赋值原则:要全面、要有边界条件(反正就是看着舒服,仿真的目的不就是让人放心吗)

#+数字:相隔时间,在initial语句中时间是累加的,
比如我先#5,那么这个语句就是在#5时有效;下一句#5则是在第十个时间单位有效。
always语句块略有不同,不过一般是在时序电路给时钟信号赋值才用得上,先不急。

仿真截图:(因为data_in没有初值,出现不定态,也就是红色部分)
Verilog——38译码器(包括仿真文件和约束文件的格式)_第3张图片

约束文件

记一下模板就好
set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN 管脚名 } [get_ports 变量名]
不论是数组还是单个变量,我们都可以在板子的手册上找到对应的一个管脚,将其写上就行。
(这里的LVCMOS33表示高有效,一般用不上改)

另一种形式:
set_property PACKAGE_PIN 管脚名 [get_ports ]
set_property IOSTANDARD LVCMOS33 [get_ports 变量名]
(不就是拆开了吗,这种一般不用)

下板的后序操作在之前的博客有提到,这里不做赘述。

你可能感兴趣的:(Verilog)