Vivado下组合逻辑模块的仿真

文章目录

  • 与门
  • 或门
  • 非门
  • 异或门
  • 同或门
  • 比较器
  • 半加器
  • 全加器
  • 乘法器
  • 数据选择器
  • 3-8 译码器
  • 三态门

组合逻辑电路的特点是任意时刻的输出仅仅取决于输入信号,输入信号变化,输出立即变化,其变化不依赖于时钟。
本文中的例子中模块名都是gate,仿真测试文件中的模块名都是sim_gate。如果你在一个工程下创建了好几个.v文件,要运行其中的一个仿真,可以选中该文件,点击Set as Top,这样仿真的就是置于顶部的那个文件了。


与门

与门的代码如下。

module gate(a,b,c);
input a;
input b;
output c;

assign c = a & b;
endmodule

仿真测试代码如下。

`timescale 1ns / 1ps
module sim_gate();
reg a;
reg b;
wire c;

initial
begin
    a = 0;
    b = 0;
    forever
    begin
	    #({$random}%100)  //生成一个0-99的随机数,以 ns 为单位延迟该随机数的时长
	    a = ~a;
	    #({$random}%100)
	    b = ~b;
    end 
end

gate uut_gate(
    .a(a),
    .b(b),
    .c(c)
);
endmodule

与门的仿真结果如下图所示,仿真运行时间设置为1us。
Vivado下组合逻辑模块的仿真_第1张图片
通过仿真图可以看出来,两个输入都为1时,输出结果才是1。
与门的RTL图如下。
Vivado下组合逻辑模块的仿真_第2张图片
如果上述例子中的a和b位宽大于1,比如a和b的位宽均为4,那么a&b就是对应位的相与,仿真结果如下图所示。
Vivado下组合逻辑模块的仿真_第3张图片
这时RTL图就是下图所示的这样。
Vivado下组合逻辑模块的仿真_第4张图片


或门

或门的代码只需要将与门代码中的"&“改为”|"即可。
或门的仿真结果如下图所示。
Vivado下组合逻辑模块的仿真_第5张图片
通过上面的输出图可以看到,两个输入中只要有一个为1,输出结果就是1。
或门的RTL图如下。
Vivado下组合逻辑模块的仿真_第6张图片


非门

非门的代码比与门的代码更简单,不再需要变量c,b=~a即可,然后把仿真文件中的代码删减一下即可。
非门的仿真结果如下图所示。
Vivado下组合逻辑模块的仿真_第7张图片
非门的输出就是将输入取反。
非门的RTL图如下。
Vivado下组合逻辑模块的仿真_第8张图片


异或门

异或门的代码只需要将与门代码中的"&“改为”^"即可。
异或门的仿真结果如下图所示。
Vivado下组合逻辑模块的仿真_第9张图片
通过上图可以看到,两个输入不同时,输出为1,输入相同时,输出为0。
异或门的RTL图如下。
Vivado下组合逻辑模块的仿真_第10张图片


同或门

同或门的代码只需要将与门代码中的"&“改为”^~"即可。
同或门的仿真结果如下图所示。
Vivado下组合逻辑模块的仿真_第11张图片
通过上图可以看到,两个输入相同时,输出为1,输入不同时,输出为0。
同或门的RTL图如下。
Vivado下组合逻辑模块的仿真_第12张图片


比较器

比较器这里以 c=a>b 为例说明,如果 a>b,那么c的值为1,否则为0。对于二进制来说,只有a=1,b=0时,c=1。
比较器的代码只需要将与门代码中的"&“改为”>"即可。
比较器的仿真结果如下图所示。
Vivado下组合逻辑模块的仿真_第13张图片
该例子中,输入a大于输入b时,即只有 a=1,b=0 时,输出才为1。
比较器的RTL图如下。
Vivado下组合逻辑模块的仿真_第14张图片


半加器

半加器和全加器是算术运算电路中的基本单元,由于半加器不考虑从低位来的进位,所以称为半加器。
半加器的真值表如下表所示。

a b sum count
0 0 0 0
0 1 1 0
1 0 1 0
1 1 0 1

半加器的代码如下。

module gate(a,b,sum,count);
input a;
input b;
output sum;
output count;

assign sum = a + b;
assign count = a & b;
endmodule

仿真测试代码如下。

`timescale 1ns / 1ps
module sim_gate();
reg a;
reg b;
wire sum;
wire count;

initial
begin
    a = 0;
    b = 0;
    forever
    begin
    #({$random}%100)
    a = ~a;
    #({$random}%100)
    b = ~b;
    end 
end

gate uut_gate(
    .a(a),
    .b(b),
    .sum(sum),
    .count(count)
);
endmodule

半加器的仿真结果如下图所示。
Vivado下组合逻辑模块的仿真_第15张图片
将上图输出和其真值表对照,输出与预期一致。
半加器的RTL图如下。
Vivado下组合逻辑模块的仿真_第16张图片


全加器

全加器在半加器的基础上考虑来自低位的进位,因此实现起来更加复杂,参与运算的数也比半加器多一个。
全加器的真值表如下表所示。

a b cin sum count
0 0 0 0 0
0 1 0 1 0
1 0 0 1 0
1 1 0 0 1
0 0 1 1 0
0 1 1 0 1
1 0 1 0 1
1 1 1 1 1

全加器的代码如下。

module gate(a,b,sum,count,cin);
input a;
input b;
input cin;
output sum;
output count;

assign {count,sum} = a + b + cin;  //通过一个位拼接运算达到计算count和sum的目的
endmodule

仿真测试代码如下。

`timescale 1ns / 1ps
module sim_gate();
reg a;
reg b;
reg cin;
wire sum;
wire count;

initial
begin
    a = 0;
    b = 0;
    cin = 0;
    forever
    begin
    #({$random}%100)
    a = ~a;
    #({$random}%100)
    b = ~b;
    #({$random}%100)
    cin = ~cin;
    end 
end

gate uut_gate(
    .a(a),
    .b(b),
    .cin(cin),
    .sum(sum),
    .count(count)
);
endmodule

全加器的仿真结果如下图所示。
Vivado下组合逻辑模块的仿真_第17张图片
将上图输出和其真值表对照,输出与预期一致。
全加器的RTL图如下。
Vivado下组合逻辑模块的仿真_第18张图片


乘法器

乘法器这里在设置时将两个乘数设置为两位的,这样其最大表示十进制的3,相乘后最大表示十进制的9,因此需要4位二进制的输出。
乘法器的代码如下。

module gate(a,b,c);
input[1:0] a;
input[1:0] b;
output[3:0] c;

assign c = a * b;
endmodule

仿真测试代码如下。

module sim_gate();
reg[1:0] a;
reg[1:0] b;
wire[3:0] c;

initial
begin
    a = 0;
    b = 0;
    forever
    begin
    #({$random}%100)
    a = {$random}%4;
    #({$random}%100)
    b = {$random}%4;
    end 
end

gate uut_gate(
    .a(a),
    .b(b),
    .c(c)
);
endmodule

乘法器的仿真结果如下图所示。
Vivado下组合逻辑模块的仿真_第19张图片
将输入和输出以无符号的十进制数显示,可以清楚地看到两数相乘的结果。
乘法器的RTL图如下。
Vivado下组合逻辑模块的仿真_第20张图片


数据选择器

下面这个例子是四选一数据选择器,选择信号是两位,输入信号是4个,可以将其设置为1位,也可以设置为多位,输出信号与输入信号的位数一致。
四选一数据选择器的选择情况如下表所示。

sel mux
00(0) a
01(1) b
10(2) c
11(3) d

数据选择器的代码如下。

module gate(a,b,c,d,sel,mux);
input[2:0] a;
input[2:0] b;
input[2:0] c;
input[2:0] d;
input[1:0] sel;
output reg[2:0] mux;

always@(a,b,c,d,sel)
begin
    case(sel)
        2'b00 : mux = a;
        2'b01 : mux = b;
        2'b10 : mux = c;
        2'b11 : mux = d;
     endcase   
end
endmodule

仿真测试代码如下。

`timescale 1ns / 1ps
module sim_gate();
reg[2:0] a;
reg[2:0] b;
reg[2:0] c;
reg[2:0] d;
reg[1:0] sel;
wire[2:0] mux;

initial
begin
    a = 0;
    b = 0;
    c = 0;
    d = 0;
    forever
    begin
    #({$random}%100)
    a = {$random}%8;
    #({$random}%100)
    b = {$random}%8;
    #({$random}%100)
    c = {$random}%8;
    #({$random}%100)
    d = {$random}%8;
    end 
end

initial 
begin 
    sel = 2'b00;
    #250 sel = 2'b01;
    #250 sel = 2'b10;
    #250 sel = 2'b11;
end

gate uut_gate(
    .a(a),
    .b(b),
    .c(c),
    .d(d),
    .sel(sel),
    .mux(mux)
);
endmodule

输入是1位时,数据选择器的仿真结果如下图所示。
Vivado下组合逻辑模块的仿真_第21张图片
可以看到,数据选择器的输出是根据代码编写的那样进行的。
输入是3位时,数据选择器的仿真结果如下图所示。
Vivado下组合逻辑模块的仿真_第22张图片
为了直观的看到不同,将输入位数设置为3位的,输出也是按照代码编写的那样进行的。
输入是1位时,数据选择器的RTL图如下。
Vivado下组合逻辑模块的仿真_第23张图片
输入是3位时,数据选择器的RTL图如下。
Vivado下组合逻辑模块的仿真_第24张图片


3-8 译码器

3-8 译码器的译码情况如下表所示。

addr decoder
000(0) 11111110
001(1) 11111101
010(2) 11111011
011(3) 11110111
100(4) 11101111
101(5) 11011111
110(6) 10111111
111(7) 01111111

3-8 译码器的代码如下。

module gate(addr,decoder);
input[2:0] addr;
output reg[7:0] decoder;

always@(addr)
begin
    case(addr)
        3'b000 : decoder = 8'b1111_1110;
        3'b001 : decoder = 8'b1111_1101;
        3'b010 : decoder = 8'b1111_1011;
        3'b011 : decoder = 8'b1111_0111;
        3'b100 : decoder = 8'b1110_1111;
        3'b101 : decoder = 8'b1101_1111;
        3'b110 : decoder = 8'b1011_1111;
        3'b111 : decoder = 8'b0111_1111;
     endcase   
end
endmodule

仿真测试代码如下。

`timescale 1ns / 1ps
module sim_gate();
reg[2:0] addr;
wire[7:0] decoder;

initial 
begin 
    addr = 3'b000;
    #125 addr = 3'b001;
    #125 addr = 3'b010;
    #125 addr = 3'b011;
    #125 addr = 3'b100;
    #125 addr = 3'b101;
    #125 addr = 3'b110;
    #125 addr = 3'b111;
end

gate uut_gate(
    .addr(addr),
    .decoder(decoder)
);
endmodule

3-8 译码器的仿真结果如下图所示。
Vivado下组合逻辑模块的仿真_第25张图片
由上述仿真结果可以看到,译码输出和代码中编写的是一致的。
3-8 译码器的RTL图如下。
Vivado下组合逻辑模块的仿真_第26张图片


三态门

三态门是FPGA中经常用到的器件,使能信号用于打开或关闭三态门。
三态门的代码如下。

module gate(en,in,out);
input en;
input in;
output out;

assign out = en ? in : 1'bz;
endmodule

仿真测试代码如下。

`timescale 1ns / 1ps
module sim_gate();
reg en;
reg in;
wire out;

initial 
begin 
    en = 1;
    #250 en = 0;
    #250 en = 1;
    #250 en = 0;
end

initial 
begin 
    in = 0;
    forever
    begin
        #({$random}%100)
        in = ~in;
    end
end

gate uut_gate(
    .en(en),
    .in(in),
    .out(out)
);
endmodule

三态门的仿真结果如下图所示。
Vivado下组合逻辑模块的仿真_第27张图片
可以看到,使能信号为1时,输出等于输入信号,使能信号为0时,输出为高阻状态。
三态门的RTL图如下。
Vivado下组合逻辑模块的仿真_第28张图片
接下来在三态门的基础上增加一个输入输出口,将两个三态门进行关联,从而实现双向的输入和输出。
Vivado下组合逻辑模块的仿真_第29张图片
如上图,当en0为0,en1为1时,1通道打开,双向IO bio就等于1通道的in1,故1通道向外发送数据,0通道接收数据,out0等于bio;当en0为1,en1为0时,0通道打开,双向IO bio就等于0通道的in0,0通道向外发送数据,1通道接收数据,out1等于bio。
双向的输入和输出的代码如下。

module gate(en,in,out,bio);
input en;
input in;
output out;
inout bio;

assign bio = en ? in : 1'bz;
assign out = bio;
endmodule

仿真测试代码如下。

module sim_gate();
reg en0;
reg in0;
wire out0;
reg en1;
reg in1;
wire out1;
wire bio;

initial 
begin 
    en0 = 0;
    en1 = 1;
    #200
    en0 = 0;
    en1 = 0;
    #50
    en0 = 1;
    en1 = 0;
    #200
    en0 = 0;
    en1 = 0;
    #50
    en0 = 0;
    en1 = 1;
    #250
    en0 = 1;
    en1 = 0;
end

initial 
begin 
    in0 = 0;
    in1 = 0;
    forever
    begin
        #({$random}%100)
        in0 = ~in0;
        #({$random}%100)
        in1 = ~in1;
    end
end

gate uut_gate0(
    .en(en0),
    .in(in0),
    .out(out0),
    .bio(bio) 
);

gate uut_gate1(
    .en(en1),
    .in(in1),
    .out(out1),
    .bio(bio) 
);
endmodule

双向的输入和输出的仿真结果如下图所示。
Vivado下组合逻辑模块的仿真_第30张图片
这里out0和out1的值是一样的,因为在定义时,它们都等于bio的值。


参考资料:
ZYNQ 开发平台 FPGA 教程 AX7020

你可能感兴趣的:(fpga,Verilog,Vivado)