一、关于Quartus和ModelSim的安装
请自行搜索方法,比较简单,本文使用quartus ii 13.1和Modelsim SE-10.4进行练习。
二、关于3-8译码器的实验仿真
(一)对比分析Verilog生成的电路原理图和原始设计电路
使用Logsim绘制一个3-8译码器的电路图:
真值表:
利用Verilog代码生成RTL电路图:
module decoder3_8
(
input wire in1 , //输入信号 in1
input wire in2 , //输入信号 in2
input wire in3 , //输入信号 in3
output reg [7:0] out //输出信号 out
);
//out:根据输入的 3bit in 信号选择输出对应的 8bit out 信号
always@(*)
case({in1, in2, in3})
3'b000 : out = 8'b0000_0001; //输入与输出的 8 种译码对应关系
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;
//因为 case 中列举了 in 所有可能输入的 8 种情况,且每种情况都有对应确定的输出
//所以此处 default 可以省略,但是为了以后因不能够完全列举而产生 latch
//所以我们默认一定要加上 default,并任意指定一种确定的输出情况
default: out = 8'b0000_0001;
endcase
endmodule
测试文件:
`timescale 1ns/1ns
module tb_decoder3_8();
//reg define
reg in1;
reg in2;
reg in3;
//wire define
wire [7:0] out;
//初始化输入信号
initial begin
in1 <= 1'b0;
in2 <= 1'b0;
in3 <= 1'b0;
end
//in1:产生输入随机数,模拟输入端 1 的输入情况
always #10 in1 <= {$random} % 2;
//in2:产生输入随机数,模拟输入端 2 的输入情况
always #10 in2 <= {$random} % 2;
//in3:产生输入随机数,模拟输入端 3 的输入情况
always #10 in3 <= {$random} % 2;
//------------------------------------------------------------
initial begin
$timeformat(-9, 0, "ns", 6);
$monitor("@time %t:in1=%b in2=%b in3=%b out=%b",$time,in1,in2,in3,out);
end
//------------------------------------------------------------
//-------------decoder3_8_inst----------------
decoder3_8 decoder3_8_ins
(
.in1(in1), //input in1
.in2(in2), //input in2
.in3(in3), //input in3
.out(out) //output [7:0] out
);
endmodule
在Modelsim中仿真分析生成波形图和transcript结果:
通过对比,可以看出两者的电路图思路是一样的,不过verilog生成的电路图把中间复杂的接线部分改成了一个模块,看起来更简洁。
同时,仿真测试的结果与真值表是一致的。
这里有一个问题,Verilog代码设计的3-8译码器模块的输出信号为何要定义为reg类型而不用默认wire(导线)类型?改成wire型是否可以?(即是否可以把outputreg[7:0]out改为output[7:0]out)修改后会出现什么错误?为什么会出错?
分析:在Verilog中,reg类型表示寄存器类型,用于always模块内被赋值的信号。而wire类型表示导线类型,用于always模块内未被赋值的信号。因为3-8译码器模块的输出信号out是在always块中被赋值的,所以必须定义为reg类型。如果将output reg [7:0] out改为output [7:0] out,会出现“Multiple drivers”错误,因为wire类型的信号可以有多个驱动器,而reg类型的信号只能有一个驱动器。因此,如果将out定义为wire类型,会出现多个驱动器的情况,从而导致错误。
三、关于全加器的实验仿真
(一)Verilog的1位全加器和4位全加器(门级描述方式)
1.一位全加器:
Verilog代码:
module FullAdder_gate_level (
input A, B, Cin,
output Sum, Cout
);
wire X1, X2, X3, X4;
// XOR gates
assign X1 = A ^ B;
assign X2 = X1 ^ Cin;
// AND gates
assign X3 = A & B;
assign X4 = X1 & Cin;
// OR gates
assign Sum = X2;
assign Cout = X3 | X4;
endmodule
1位全加器RTL电路图:
对比1位全加器logisim电路:
2.四位全加器
Verilog代码:
module FourBitAdder_gate_level (
input [3:0] A, B, Cin,
output [3:0] Sum, Cout
);
wire C1, C2, C3;
wire S1, S2, S3;
FullAdder_gate_level f1 (.A(A[0]), .B(B[0]), .Cin(Cin), .Sum(S1), .Cout(C1));
FullAdder_gate_level f2 (.A(A[1]), .B(B[1]), .Cin(C1), .Sum(S2), .Cout(C2));
FullAdder_gate_level f3 (.A(A[2]), .B(B[2]), .Cin(C2), .Sum(S3), .Cout(C3));
FullAdder_gate_level f4 (.A(A[3]), .B(B[3]), .Cin(C3), .Sum(Sum[3]), .Cout(Cout));
endmodule
module FullAdder_gate_level (
input A, B, Cin,
output Sum, Cout
);
wire X1, X2, X3, X4;
// XOR gates
assign X1 = A ^ B;
assign X2 = X1 ^ Cin;
// AND gates
assign X3 = A & B;
assign X4 = X1 & Cin;
// OR gates
assign Sum = X2;
assign Cout = X3 | X4;
endmodule
4位全加器RTL电路图:
对比4位全加器logisim电路:
(二)Verilog的1位全加器和4位全加器(行为级描述方式)
1.一位全加器
Verilog代码:
module FullAdder_functional_level (
input A, B, Cin,
output Sum, Cout
);
// Full Adder logic
assign {Cout, Sum} = A + B + Cin;
endmodule
1位全加器RTL电路图:
对比1位全加器logisim电路:
2.四位全加器
Verilog代码:
module FullAdder_functional_level (
input A, B, Cin,
output Sum, Cout
);
// Full Adder logic
assign {Cout, Sum} = A + B + Cin;
endmodule
module FourBitAdder_functional_level (
input [3:0] A, B, Cin,
output [3:0] Sum,
output Cout
);
wire c1, c2, c3;
FullAdder_functional_level fa1(A[0], B[0], Cin, Sum[0], c1);
FullAdder_functional_level fa2(A[1], B[1], c1, Sum[1], c2);
FullAdder_functional_level fa3(A[2], B[2], c2, Sum[2], c3);
FullAdder_functional_level fa4(A[3], B[3], c3, Sum[3], Cout);
endmodule
4位全加器RTL电路图:
对比4位全加器logisim电路:
(三)Verilog的8位全加器模块设计
Verilog代码:
module eight_bit_adder(
input [7:0] a,
input [7:0] b,
input cin,
output [7:0] sum,
output cout
);
wire [7:0] c;
full_adder fa0(a[0], b[0], cin, sum[0], c[0]);
full_adder fa1(a[1], b[1], c[0], sum[1], c[1]);
full_adder fa2(a[2], b[2], c[1], sum[2], c[2]);
full_adder fa3(a[3], b[3], c[2], sum[3], c[3]);
full_adder fa4(a[4], b[4], c[3], sum[4], c[4]);
full_adder fa5(a[5], b[5], c[4], sum[5], c[5]);
full_adder fa6(a[6], b[6], c[5], sum[6], c[6]);
full_adder fa7(a[7], b[7], c[6], sum[7], cout);
endmodule
module full_adder(
input a,
input b,
input cin,
output sum,
output cout
);
assign sum = a ^ b ^ cin;
assign cout = (a & b) | (a & cin) | (b & cin);
endmodule
生成的RTL电路图:
四、拓展实验
学习利用并行加法器原理(先行进位加法器),完成一个16位ALU(算术逻辑单元)的电路设计,采用Verilog设计模式,生成RTL电路。
Verilog代码:
module ALU_16bit (
input [15:0] operand_A,
input [15:0] operand_B,
input [2:0] opcode,
input cin,
output reg [15:0] result,
output cout,
output zero
);
reg [15:0] temp_result;
always @*
case(opcode)
3'b000: temp_result = operand_A + operand_B;
3'b001: temp_result = operand_A - operand_B;
3'b010: temp_result = operand_A & operand_B;
3'b011: temp_result = operand_A | operand_B;
3'b100: temp_result = operand_A ^ operand_B;
3'b101: temp_result = operand_A + 1;
3'b110: temp_result = operand_A - 1;
3'b111: temp_result = ~operand_A;
default: temp_result = 16'b0;
endcase
assign cout = (temp_result[15] == 1) ? 1'b1 : 1'b0; // Fix index to 15
assign zero = (temp_result == 16'b0) ? 1'b1 : 1'b0;
always @*
if (cin)
result = temp_result + 1;
else
result = temp_result;
endmodule
RTL电路图:
测试文件:文章来源:https://www.toymoban.com/news/detail-770731.html
module ALU_16bit_tb;
reg [15:0] operand_A;
reg [15:0] operand_B;
reg [2:0] opcode;
reg cin;
wire [15:0] result;
wire cout;
wire zero;
ALU_16bit uut (
.operand_A(operand_A),
.operand_B(operand_B),
.opcode(opcode),
.cin(cin),
.result(result),
.cout(cout),
.zero(zero)
);
initial begin
// Test case 1: Addition
operand_A = 16'b1010101010101010;
operand_B = 16'b0101010101010101;
opcode = 3'b000;
cin = 1'b0;
#10;
// Test case 2: Subtraction
operand_A = 16'b1010101010101010;
operand_B = 16'b0101010101010101;
opcode = 3'b001;
cin = 1'b0;
#10;
// Add more test cases as needed
$stop;
end
endmodule
Modelsim仿真结果:
文章来源地址https://www.toymoban.com/news/detail-770731.html
到了这里,关于Verilog基础编程练习的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!