当前位置:   article > 正文

【Verilog实战】生成38译码器和全加器_译码器编程

译码器编程

3-8译码器

Logisim evolution仿真

Decoder_38

逻辑真值表

i0i1i2o001o2o3o4o5o6o7
00010000000
00101000000
01000100000
01100010000
10000001000
10100000100
11000000010
11100000001

分析上述真值表,可以发现输入是三位的二进制数字,38译码器将其转化为十进制数字。如想要得到5,即o5对应输出端口为1,输入则是101。

Verilog实战

打开Quartus,采用Verilog编程(if-else或者case)设计一个3-8译码器,生成RTL原理电路图;

写法一
运用case语句声明所有情况,即每个输入对应的输出,直接生成RTL原理电路图。

module decode38(
  output reg [7:0] out,  //由于后面采用always语句,此处赋值必须为reg
  input  [2:0] in
);
  always
    case (in)
	    0:out=8'b00000001;
		1:out=8'b00000010;
		2:out=8'b00000100;
		3:out=8'b00001000;
		4:out=8'b00010000;
		5:out=8'b00100000;
		6:out=8'b01000000;
		7:out=8'b10000000;
	endcase
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

decoder0

写法二

module decode38(
  output reg [7:0] out,
  input  [2:0] in
);
  integer i;
  always
    for(i=0;i<7;i=i+1)
	   out[i]=(in==i);
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

写法二
可以看出,不一样的语言描述,会画出不一样的原理图。

注意事项

1)Verilog 综合生成的3-8译码器电路原理图与原始设计电路存在一定差异,尤其是不详细描写其内部结构后,差异尤其明显,但是仿真测试生成的结果都与真值表一致。

2) Verilog代码设计的3-8译码器模块的输出信号之所以定义为reg类型而不用默认wire(导线)类型,是因为后面运用了过程语句always,因此被赋值的只能说reg变量。改成wire型(即把 output reg [7:0] out 改为 output [7:0] out)后,相应地也要将alway语句改为连续赋值语句assign。

全加器

一位全加器

先用Verilog的门级描述方式写一个“1位全加器”, 生成RTL电路,与Logisim的“1位全加器”进行对比。
Logisim的“1位全加器”图样如下:
在这里插入图片描述
Verilog代码:
1.功能级写法

module fulladder_1 {A,B,Cin,Sum,Cout};
   input A,B,Cout;
   output Sum,Cout;
   assign {Cout,Sum}=A+B+Cin;
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述
2行为级写法

module fulladder_1(
    input a,b,cin,
	output sum,cout
);
    assign sum=a^b^cin;
	assign cout=(a&b)|(a&cin)|(b&cin);
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述

四位全加器

module FA(
   input x,y,cin,
	output f,cout
);
   assign f=x^y^cin;
	assign cout=(x&y)|(x&cin)|(y&cin);
endmodule

module CRA(
   input [3:0]x,y,
	input cin,
	output [3:0]f,
	output cout
);
   wire [4:0]c;
   assign c[0]=cin;
   FA fa0(x[0],y[0],c[0],f[0],c[1]);
 	FA fa1(x[1],y[1],c[1],f[1],c[2]);
	FA fa2(x[2],y[2],c[2],f[2],c[3]);
	FA fa3(x[3],y[3],c[3],f[3],c[4]);
	assign cout=c[4];
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在这里插入图片描述
采用Verilog设计一个8位全加器模块。


```c
module FA(
   input x,y,cin,
	output f,cout
);
   assign f=x^y^cin;
	assign cout=(x&y)|(x&cin)|(y&cin);
endmodule

module FA_8(
   input [7:0]x,y,
	input cin,
	output [7:0]f,
	output cout
);
   wire [8:0]c;
   assign c[0]=cin;
   FA fa0(x[0],y[0],c[0],f[0],c[1]);
 	FA fa1(x[1],y[1],c[1],f[1],c[2]);
	FA fa2(x[2],y[2],c[2],f[2],c[3]);
	FA fa3(x[3],y[3],c[3],f[3],c[4]);
	FA fa4(x[4],y[4],c[4],f[4],c[5]);
 	FA fa5(x[5],y[5],c[5],f[5],c[6]);
	FA fa6(x[6],y[6],c[6],f[6],c[7]);
	FA fa7(x[7],y[7],c[7],f[7],c[8]);
	assign cout=c[8];
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

在这里插入图片描述

16位ALU

Verilog设计

module ALU_16#(
    parameter n=16
)(
    input [n-1:0] opA,    // 输入操作数A,长度为n
    input [n-1:0] opB,    // 输入操作数B,长度为n
    input [3:0] S,        // 输入选择信号S,长度为4
    input wire M,         // 输入M,控制加/减操作
    input wire Cin,       // 输入进位信号Cin
    output reg[n-1:0] DO, // 输出结果DO,长度为n
    output wire C,        // 输出进位信号C
    output wire V,        // 输出溢出信号V
    output wire N,        // 输出负数信号N
    output wire Z         // 输出零信号Z
);

    reg [n-1:0] p;         // 中间变量p
    reg [n-1:0] g;         // 中间变量g
    reg [n:0] carry;       // 进位寄存器carry

    always@(opA,opB,S,M,Cin)
    begin
        carry[0]=Cin;                                                 // 进位寄存器的第一个位等于Cin
        g={n{S[3]}}&opA&opB | {n{S[2]}}&opA&(~opB) | {n{(~M)}};        // 计算g
        p=~({n{S[3]}})&opA&opB | {n{S[2]}}&opA&(~opB) | {n{S[1]}}&(~opA)&opB | {n{S[0]}}&(~opA)&(~opB);  // 计算p
        carry[n:1]=g | (p & carry[n-1:0]);                             // 更新进位寄存器carry
        DO=p^carry[n-1:0];                                             // 计算结果DO
    end

    assign C=carry[n];                                                  // 连接进位信号C
    assign V=(opA[n-1]&opB[n-1]&~DO[n-1]) | (~opA[n-1]&~opB[n-1]&DO[n-1]); // 计算溢出信号V
    assign N=DO[n-1];                                                    // 连接负数信号N
    assign Z=(!(DO))?1:0;                                                // 计算零信号Z

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

RTL电路

在这里插入图片描述

实验总结

Verilog的许多编程思路同C语言相似,语法也相近。要格外注意使用过程语句编程时,输出端口要注意reg赋值。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/563556
推荐阅读
相关标签
  

闽ICP备14008679号