Verilog编程基础练习

一、软件安装

        自行安装配置Quartus II和ModelSim软件,本人使用Quartus II 13.1 (64-bit)和Modelsim SE-64 10.4版本的软件。

二、3-8译码器

1.使用Logsim绘制一个3-8译码器电路图

2.3-8译码器真值表

 

3.采用Verilog编程设计3-8译码器 

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
 

3.通过上方代码在Quartus II中生成的RTL原理电路图如下:

4.编写仿真测试文件,对3-8译码器进行仿真测试 

仿真测试文件如下:

`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

5.输出其测试波形图和Transcript结果

        通过Logisim和Quartus II两种软件分别做3-8译码器电路图可以看出Verilog 综合生成的3-8译码器电比之原始设计电路更加简洁,而且综合工具可能会使用不同的逻辑门类型来实现相同的功能。原始设计电路相对来说比较容易理解,而且画图过程中能更好的理解逻辑关系。 由图可知仿真测试生成的结果是否与真值表一致。

        在这里有一个问题 Verilog代码设计的3-8译码器模块的输出信号 为何要定义为 reg类型而不用默认wire(导线)类型?改成wire型是否可以? (即是否可以把 output reg [7:0] out  改为 output  [7:0] out) 修改后会出现什么错误?为什么会出错?

        在Verilog代码设计的3-8译码器模块中,将输出信号定义为reg类型是有原因的。首先,对于输出信号来说,使用reg类型是合适的,因为它表示一个寄存器或存储元素。输出信号需要在时钟边沿上进行更新,并且需要在整个时钟周期内保持其值。通过使用reg类型,我们可以在时钟边沿上更新输出值,并且该值会在整个时钟周期内保持不变。如果将输出信号定义为默认的wire类型,即output [7:0] out,会导致编译错误。这是因为wire类型表示一个连接线,它只能用于传递信号,在时钟边沿上不能直接更新其值。当我们尝试在时钟边沿上对wire类型的信号进行赋值时,编译器会报错,因为这是不允许的。因此,为了正确地表示输出信号的行为,我们需要将其定义为reg类型,以便在时钟边沿上更新其值。这样可以确保输出信号在整个时钟周期内保持稳定和一致。总结起来,对于需要在时钟边沿上进行更新的信号,如输出信号,使用reg类型是必要的,而将其定义为wire类型会导致编译错误。

三、全加器

门级描述方式:

1.一位全加器:

(1)Logsim绘制的一位全加器电路图

(2)采用Verilog编程设计一位全加器

module Full_Adder(

  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

(3)在Quartus II中生成的RTL原理电路图: 

 

2.四位全加器:

(1)使用Logsim绘制四位全加器

(2)采用Verilog编程设计四位全加器

module Four_Full_Adder(

  input [3:0] A, B, Cin,

  output [3:0] Sum, Cout

);

  
  wire C1, C2, C3;

  wire S1, S2, S3;

  Full_Adder f1 (.A(A[0]), .B(B[0]), .Cin(Cin), .Sum(S1), .Cout(C1));

  Full_Adder f2 (.A(A[1]), .B(B[1]), .Cin(C1), .Sum(S2), .Cout(C2));

  Full_Adder f3 (.A(A[2]), .B(B[2]), .Cin(C2), .Sum(S3), .Cout(C3));

  Full_Adder f4 (.A(A[3]), .B(B[3]), .Cin(C3), .Sum(Sum[3]), .Cout(Cout));


endmodule


module Full_Adder(

  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

(3)在Quartus II中生成的RTL原理电路图如下: 

行为级描述方式:

 1.一位全加器:

(1)Logsim绘制的一位全加器电路图

(2)采用Verilog编程设计一位全加器

module Full_Adder(

  input A, B, Cin,

  output Sum, Cout

);


  // Full Adder logic

  assign {Cout, Sum} = A + B + Cin;

endmodule

(3)在Quartus II中生成的RTL原理电路图:  

 2.四位全加器:

(1)Logsim绘制的4位全加器电路图

(2)采用Verilog编程设计4位全加器

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

(3)在Quartus II中生成的RTL原理电路图:

3.8位全加器

(1)采用Verilog编程设计8位全加器

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

(2)在Quartus II中生成的RTL原理电路图:

四、拓展实验

 学习教材上的 并行加法器原理(先行进位加法器),完成一个16位ALU(算术逻辑单元)的电路设计,采用Verilog设计模式,生成RTL电路。

(1)采用Verilog编程设计一个16位ALU

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

(2)在Quartus II中生成的RTL原理电路图:

测试文件: 

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仿真结果如下:

  • 20
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值