Verilog编程基础练习

本文介绍了使用Verilog编程实现3-8译码器的逻辑设计、真值表验证以及使用if-else/case结构。接着详细讨论了全加器的门级和行为级描述,包括1位、4位和8/16位ALU的设计。文章强调了Verilog的不同建模方式及其在数字电路设计中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、3-8译码器

1.使用Logsim绘制

在这里插入图片描述

三八译码器的真值表:

ABCY1Y2Y3Y4Y5Y6Y7Y8
00010000000
00101000000
01000100000
01100010000
10000001000
10100000100
11000000010
11100000001

2.采用Verilog编程(if-else或者case)

具体代码如下:

module decoder_3to8
(
 input wire in1 , //输入信号 in1
 input wire in2 , //输入信号 in2
 input wire in3 , //输入信号 in3
 output reg [7:0] out //输出信号 out
 );

 always@(*)
 case({in1, in2, in3})
	3'b000 : out = 8'b0000_0001; 
	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'b0000_0001;
 endcase
 endmodule

RTL图:
请添加图片描述

4.问题回答

(1)Verilog 综合生成的3-8译码器电路原理图与原始设计电路存在什么差异? 仿真测试生成的结果是否与真值表一致?
答:由Verilog 综合生成的3-8译码器电路原理图把原始电路中的内部复杂结构封装起来了,仿真测试生成的结果与真值表一致。
2) Verilog代码设计的3-8译码器模块的输出信号 为何要定义为 reg类型而不用默认wire(导线)类型?改成wire型是否可以? (即是否可以把 output reg [7:0] out 改为 output [7:0] out) 修改后会出现什么错误?为什么会出错?
答:Verilog代码设计的3-8译码器模块的输出信号定义为reg类型是因为译码器的输出需要根据输入信号进行逻辑运算,输出结果需要被存储在寄存器或内存中以便后续使用。因此,输出信号需要定义为reg类型以便对其进行赋值操作。如果将输出信号定义为默认的wire类型,会导致编译错误。因为wire类型的信号只能用于连接不同模块之间的数据通路,不能直接赋值操作,而在3-8译码器的实现过程中,输出信号需要通过逻辑运算得到并存储在寄存器或内存中,所以必须定义为reg类型。如果把output reg [7:0] out改为output [7:0] out,编译器会报错:“Error (10137): Verilog HDL Procedural Assignment error at decoder_3to8.v(11): object “out” on left-hand side of assignment must have a variable data type”意思是Verilog HDL过程赋值错误在decoder_3to8.v(11):对象"out"在左侧的赋值必须有一个变量数据类型,这是因为在Verilog中,对reg类型的输出信号进行赋值时使用的是赋值语句(如assign、always等),而对wire类型的信号进行赋值时使用的是连线(wire)语句。因此,如果将output reg [7:0] out改为output wire [7:0] out,编译器会认为你在对wire类型的信号进行赋值操作,从而导致编译错误。
请添加图片描述

二、全加器

1.门级描述“1位全加器”

请添加图片描述

1、多输入门只有单个输出,有单个或多个输入端。Verilog 内置多输入门如下:and(与门) nand(与非门) or(或门) nor(或非门) xor(异或门) xnor(同或门)
2、门级单元第一个端口是输出,后面端口是输入。
具体代码如下:
门级描述一位全加器

module adder(
	input A,B,Cin,
	output S,Cout
);
	wire t1,t2,t3;
	xor u1(t1,A,B);
	and u2(t3,A,B);
	xor	u3(S,t1,Cin);
	and u4(t2,t1,Cin);
	or	u5(Cout,t3,t2);
endmodule

用Quartus 生成的RTL图如下:
请添加图片描述

2. 4位全加器

1.模块调用:

module adder_4(// 1-位全加器模块
	input x,y,cin,
	output f,cout
);
	assign f=x^y^cin;
	assign cout=(x&y)|(x&cin)|(y&cin);
endmodule 

module adder_1(// 4-位加法器模块
	input [3:0]x,y,
	input cin,
	output [3:0]f,
	output cout
);
	wire [4:0]c;
	assign c[0]=cin;
	adder_4 fa0(x[0],y[0],c[0],f[0],c[1]); //子模块实现 4 位全加器
	adder_4 fa1(x[1],y[1],c[1],f[1],c[2]);
	adder_4 fa2(x[2],y[2],c[2],f[2],c[3]);
	adder_4 fa3(x[3],y[3],c[3],f[3],c[4]);
	assign cout=c[4];
endmodule

生成的RTL图如下:
在这里插入图片描述
2.门级描述:
Logsim的“4位全加器”电路:
请添加图片描述
门级描述四位全加器

module adder_4bit
(
  input [3:0] A, B, Cin,
  output [3:0] Sum, Cout
);
  wire C1, C2, C3;
  wire S1, S2, S3;
  Adder_1bit f1 (.A(A[0]), .B(B[0]), .Cin(Cin), .Sum(S1), .Cout(C1));
  Adder_1bit f2 (.A(A[1]), .B(B[1]), .Cin(C1), .Sum(S2), .Cout(C2));
  Adder_1bit f3 (.A(A[2]), .B(B[2]), .Cin(C2), .Sum(S3), .Cout(C3));
  Adder_1bit f4 (.A(A[3]), .B(B[3]), .Cin(C3), .Sum(Sum[3]), .Cout(Cout));
endmodule
module Adder_1bit (
  input A, B, Cin,
  output Sum, Cout
);
  wire X1, X2, X3, X4;
  assign X1 = A ^ B;
  assign X2 = X1 ^ Cin;
  assign X3 = A & B;
  assign X4 = X1 & Cin;
  assign Sum = X2;
  assign Cout = X3 | X4;
endmodule

RTL图:
请添加图片描述

3.行为级描述

行为级描述是一种常用的建模方法,可以方便地描述数字电路的行为和功能。 通过使用Verilog行为级描述,可以提高数字电路设计的效率和可靠性。
用Verilog行为级描述的建模方法,重复实验
(1)1位全加器

module adder(
	input A,B,Cin,
	output S,Cout
);
	assign {Cout,S}=A+B+Cin;
endmodule

(2)四位全加器

module adder(
	input [3:0]A,B,
	input Cin,
	output [3:0]S,
	output Cout
);
	assign {Cout,S}=A+B+Cin;
endmodule

4.制作8位全加器

.利用子模块调用的方法制作8位全加器

module adder_8(//单一的全加器模块
	input x,y,cin,
	output f,cout
);
	assign f=x^y^cin;
	assign cout=(x&y)|(x&cin)|(y&cin);
endmodule 
module adder(
	input [7:0]x,y,
	input cin,
	output [7:0]f,
	output cout
);
	wire [8:0]c;
	assign c[0]=cin;
	adder_8 fa0(x[0],y[0],c[0],f[0],c[1]);
	adder_8 fa1(x[1],y[1],c[1],f[1],c[2]);
	adder_8 fa2(x[2],y[2],c[2],f[2],c[3]);
	adder_8 fa3(x[3],y[3],c[3],f[3],c[4]);
	adder_8 fa4(x[4],y[4],c[4],f[4],c[5]);
	adder_8 fa5(x[5],y[5],c[5],f[5],c[6]);
	adder_8 fa6(x[6],y[6],c[6],f[6],c[7]);
	adder_8 fa7(x[7],y[7],c[7],f[7],c[8]);
	assign cout=c[8];
endmodule

拓展实验:16位ALU

module ALU_16bit (
  input [15:0] A,
  input [15:0] B,
  input [2:0]  op,
  input       cin,
  output reg [15:0] result,
  output      cout,
  output      zero
);
  reg [15:0] t;
  always @*
    case(op)
      3'b000: t = A + B;
      3'b001: t = A - B;
      3'b010: t = A & B;
      3'b011: t =A | B;
      3'b100: t = A ^ B;
      3'b101: t = A + 1;
      3'b110: t = A - 1;
      3'b111: t = ~A;
      default: t = 16'b0;
    endcase
  assign cout = (t[15] == 1) ? 1'b1 : 1'b0; 
  assign zero = (t == 16'b0) ? 1'b1 : 1'b0;
  always @*
    if (cin)
      result = t + 1;
    else
      result = t;
endmodule

RTL:
在这里插入图片描述

三、实验总结

通过本次实验我掌握了Verilog编程语言的三种建模方式,其中门级建模(结构化建模)方式直接反映了硬件电路的结构,使得设计者可以精确地控制每个组件的连接关系,而行为建模更加抽象,更关注电路的功能,而不是具体的硬件结构。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值