实验1 在MAX10 FPGA上实现组合逻辑

时间:2022-09-29 22:00:59

实验1 在MAX10 FPGA上实现组合逻辑

    实验前的准备工作:参照讲义步骤安装Quartus,Modelsim和System Builder。阅读材料:1)推荐的文件组织形式;2)Verilog 1:概述和Verilog 2:重点是assign语句。

参考资源:友晶网站上的关于DE10-Lite实验板的资源:用户手册,工具和案例。
​​​http://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&CategoryNo=218&No=1021&PartNo=4​

 

Part 0. 使用System Bulider、Quartus和Modelsim的设计流程

A. 使用System Builder创建工程文件

在用户手册的第4章介绍了System Builder,它是一个windows平台的工具。用来生成Quartus工程文件和分配DE10-Lite实验板的I/O引脚。

(1)   运行DE10_Lite_SystemBuilder.exe

(2)   输入工程名称和勾选在工程里用到I/O设备。

如图1所示,在这里我们设定工程名是majority,勾选了LED,按键,拨动开关,7段数码管这些I/O设备。然后单击Generate按钮,将生成的文件保存到工程目录。当成功生成工程文件后,退出SystemBuilder.

 

实验1 在MAX10 FPGA上实现组合逻辑

 

图 1  SystemBuilder界面

 

    如图2所示,在工程目录中,Systembuilder生成了一系列工程文件。

 

实验1 在MAX10 FPGA上实现组合逻辑

 

图 2  SystemBuilder生成的工程文件

 

其中majority.v是顶层设计的Verilog文件模板(如图3所示)。SystemBilder已经在这个模板里把端口声明和引脚分配完成,带来很大的便利。可以更叫专注于功能描述。

//=======================================================

//  This code is generated by Terasic System Builder

//=======================================================

 

module majority(

 

    //////////// SEG7 //////////

    output           [7:0]      HEX0,

    output           [7:0]      HEX1,

    output           [7:0]      HEX2,

    output           [7:0]      HEX3,

    output           [7:0]      HEX4,

    output           [7:0]      HEX5,

 

    //////////// KEY //////////

    input            [1:0]      KEY,

 

    //////////// LED //////////

    output           [9:0]      LEDR,

 

    //////////// SW //////////

    input            [9:0]      SW

);

 

 

 

//=======================================================

//  REG/WIRE declarations

//=======================================================

 

 

 

 

//=======================================================

//  Structural coding

//=======================================================

 

 

 

endmodule

图3  Verilog模板文件

 

    在这个案例里,我们描述基本的逻辑门组成的电路功能。如同书中3.6节描述的那样(Digital Design- A System Approach).我们使用拨动开关作为电路的输入,使用LED作为电路的输出。

 

B.     使用Quartus Prime编译和编程

l  运行Quartus Prime并打开之前用SystemBuilder创建的工程文件。

l  选择File> Open Project,在工程目录,选择majority.qpf.

l  在Project Navigator窗口双击majority实体名,打开其Verilog设计文件。

l  在majority.v的功能描述部分,添加下面一条语句。

assign LEDR[1] = (SW[0]&SW[1])|(SW[0]&SW[2])|(SW[1]&SW[2]);

这里只有当3个拨动开关有至少2个都是1时,LED才被点亮。实验板上LED的电路如图4所示。

 

实验1 在MAX10 FPGA上实现组合逻辑

 

图 4  LED电路

 

l  当完成Verilog代码编辑后,选择Processing > Start Compliation。此处应该0个错误。

l  选择Tools > Programmer。通过USB电缆连接DE10-Lite实验板和电脑。如图5所示,在Hardware Setup那里设置为USB-Blaster[USB-0],如果没有,可能是驱动没有安装。确定majority.sof文件显示在下方列表并且已勾选Programe/Configure.然后单击Start按钮。

 

实验1 在MAX10 FPGA上实现组合逻辑

 

图 5  编程窗口

   

    现在,可以在实验板上验证这个逻辑门电路的设计。通过拨动SW[2]、SW[1]和SW[0],观察LEDR[1]的亮灭,其中只有在两个或两个以上开关推上去时,LEDR[1]亮,反之则灭。

 

C.     使用Testbench在ModelSim里仿真

使用功能仿真和时序仿真来仿真设计是一种功能强大的调试技术。它比把设计的电路下载到FPGA里来调试好太多了。因为:1)在功能仿真里,可以像观察I/O端口一样观察电路的内部信号;2)使用testbench节省了每次下载验证所需的下载时间。

我们将使用testbench来做电路的功能仿真。虽然可以手绘波形激励,但最好的方法是编写testbench产生电路的输入并监视输出。

图6列出了逻辑门电路的testbench内容。

module tb_majority;

 

reg [2:0] count;

 

wire [7:0] HEX5;

wire [7:0] HEX4;

wire [7:0] HEX3;

wire [7:0] HEX2;

wire [7:0] HEX1;

wire [7:0] HEX0;

wire [9:0] LEDR;

wire [9:0] SW;

 

assign SW[2:0] = count;

 

majority maj1(.HEX0(HEX0),

              .HEX1(HEX1),

              .HEX2(HEX2),

              .HEX3(HEX3),

              .HEX4(HEX4),

              .HEX5(HEX5),

              .KEY(KEY),

              .LEDR(LEDR),

              .SW(SW)

              );

             

initial

begin

                count = 3'b0;

                repeat(8)

                begin

                    #100

                    $display("in = %b, out = %b",count,LEDR[1]);

                    count = count + 1'b1;

                end

end

 

endmodule

图6  testbench

 

Testbench文件不能综合成实际的电路,只是用来做仿真。因此,它可以使用不可综合的Verilog语句,如延时#,display,initial等。testbench例化被测试的模块,产生输入激励并监视输出。在ModelSim里,波形查看器是一个很方便的检测电路响应的工具。

ModelSim里功能仿真步骤如下:

1) 在majority.v同目录下,新建tb_majority.v文件,并编辑。

2) 在Quartus工程目录,创建一个名为Simulation的子目录,用来存储仿真文件。

3) 运行ModelSime。

4) 选择File > New > Project打开新建工程对话框。设定路径(如前所述)和工程名。其它设置缺省不修改。单击OK。

5) 在Add Items to the Project窗口,添加majority.v和tb_majority.v文件,选择Reference from current location.

6) 选择Compile > Compile All。此处应该0错误。

7) 单击Simulate > Start Simulation,选择Desing > work > tb_majority。

8) 查看仿真波形。选择View > Wave。然后,在Objects窗口选择count,右击,选择Add Wave。这样就把count信号添加到波形窗口。再展开LEDR信号,把LEDR[1]添加到波形窗口。这样在波形窗口就可以看到逻辑门电路的输入/出信号。

9) 执行仿真可以通过菜单操作:Simulate > Run > Run 100或者在命令窗口输入run执行。这样将使仿真运行100个时间单位,缺省是100ps。如图7所示,是仿真运行800ps的波形。

实验1 在MAX10 FPGA上实现组合逻辑

 

 

图 7 仿真波形

 

在ModelSim的控制窗口,也可以看到testbench的输出信息,如图8所示,其输入/出信息通图7波形显示结果。

 

实验1 在MAX10 FPGA上实现组合逻辑

 

图 8  控制台窗口信息

 

Part 1. 在DE10-Lite实验板上实现基本的组合逻辑门电路

    参照Part 0的设计,新建一个工程,实现逻辑门电路的可以,可以使用2-4输入的与门、与非门、或门和或非门。也可以用按键直接操控LED和7段数码管。这里需要注意,DE10-Lite上的7段数码管是共阳极的连接。下载验证。并编写testbench测试。

 

实验1 在MAX10 FPGA上实现组合逻辑

 

图 9 共阳7段数码管

 

这里决定用KEY[1]和KEY[0]相与后驱动LEDR1和HEX0,设计代码和testbench如下:

//=======================================================

//  This code is generated by Terasic System Builder

//=======================================================

 

module part2(

 

    //////////// SEG7 //////////

    output           [7:0]      HEX0,

    output           [7:0]      HEX1,

    output           [7:0]      HEX2,

    output           [7:0]      HEX3,

    output           [7:0]      HEX4,

    output           [7:0]      HEX5,

 

    //////////// KEY //////////

    input            [1:0]      KEY,

 

    //////////// LED //////////

    output           [9:0]      LEDR,

 

    //////////// SW //////////

    input            [9:0]      SW

);

 

 

 

//=======================================================

//  REG/WIRE declarations

//=======================================================

 

 

 

 

//=======================================================

//  Structural coding

//=======================================================

assign LEDR[1] = (KEY[0]&KEY[1]);

assign HEX0 = ~(KEY[1]&KEY[0])?8'b0100_0000:8'b1111_1111;

 

 

endmodule

 

测试代码:

module tb_part2;

 

reg [1:0] count;

 

wire [7:0] HEX0;

wire [7:0] HEX1;

wire [7:0] HEX2;

wire [7:0] HEX3;

wire [7:0] HEX4;

wire [7:0] HEX5;

wire [1:0] KEY;

wire [9:0] SW;

wire [9:0] LEDR;

 

assign KEY = count;

 

part2 p1(.HEX0(HEX0),

              .HEX1(HEX1),

                  .HEX2(HEX2),

                  .HEX3(HEX3),

                  .HEX4(HEX4),

                  .HEX5(HEX5),

                  .KEY(KEY),

                  .LEDR(LEDR),

                  .SW(SW)

                  );

 

initial

begin

  count = 2'b00;

  repeat(4)

  begin

  #100

  $display("in = %b, out = %b",count,LEDR[1]);

  count = count +1'b1;

  end

end 

 

endmodule

 

仿真结果如图10所示:

 

实验1 在MAX10 FPGA上实现组合逻辑

 

图 10  part 2 仿真结果

 

 

实验1 在MAX10 FPGA上实现组合逻辑

 

图 11  监视输出

 

Part 2. 为 4 位开关输入实现组合逻辑十进制 7 段显示

    设计一个组合逻辑电路,用SW[3]-SW[0]作输入,HEX1,HEX0作输出。使数码管根据输入显示00、01、02、。。。、13、14、15。另外4个数码管HEX5-HEX2关闭。

    按以下步骤完成:

1)  写出真值表(输入是SW[4]-SW[0],输出是HEX1和HEX0的每段);

2)  卡诺图化简;

3)  使用assign语句描述7段数码管每一段的逻辑表达式;

4)  用testbench测试输入的16种情况;

5)  编译并下载验证。

后面会学习使用其它描述方式描述真值表,比如case语句,就不需要推导数码管每一段的逻辑表达式。

参考代码如下:

//=======================================================

//  This code is generated by Terasic System Builder

//=======================================================

 

module lab1_part2(

 

    //////////// SEG7 //////////

    output           [7:0]      HEX0,

    output           [7:0]      HEX1,

    output           [7:0]      HEX2,

    output           [7:0]      HEX3,

    output           [7:0]      HEX4,

    output           [7:0]      HEX5,

 

    //////////// KEY //////////

    input            [1:0]      KEY,

 

    //////////// LED //////////

    output           [9:0]      LEDR,

 

    //////////// SW //////////

    input            [9:0]      SW

);

 

 

 

//=======================================================

//  REG/WIRE declarations

//=======================================================

 

 

 

 

//=======================================================

//  Structural coding

//=======================================================

assign HEX1[6] = 1'b1;

assign HEX1[5] = SW[3]&SW[2] | SW[3]&SW[1];

assign HEX1[4] = SW[3]&SW[2] | SW[3]&SW[1];

assign HEX1[3] = SW[3]&SW[2] | SW[3]&SW[1];

assign HEX1[2] = 1'b0;

assign HEX1[1] = 1'b0;

assign HEX1[0] = SW[3]&SW[2] | SW[3]&SW[1];

 

assign HEX0[6] = ~SW[3]&~SW[2]&~SW[1] |

                 ~SW[3]&SW[2]&SW[1]&SW[0] |

                     SW[3]&~SW[2]&SW[1];

assign HEX0[5] = SW[3]&SW[2]&~SW[1] |

                 ~SW[3]&~SW[2]&SW[0] |

                     ~SW[3]&~SW[2]&SW[1] |

                     ~SW[3]&SW[1]&SW[0] |

                     ~SW[2]&SW[1]&SW[0];

assign HEX0[4] = SW[0] | ~SW[3]&SW[2]&~SW[1] |

                     SW[3]&SW[2]&SW[1];

assign HEX0[3] = ~SW[3]&SW[2]&~SW[1]&~SW[0] |

                 ~SW[3]&~SW[2]&~SW[1]&SW[0] |

                     ~SW[3]&SW[2]&SW[1]&SW[0] |

                     SW[3]&SW[2]&SW[1]&~SW[0] |

                     SW[3]&~SW[2]&SW[1]&SW[0];

assign HEX0[2] = SW[3]&SW[2]&~SW[1]&~SW[0] |

                 ~SW[3]&~SW[2]&SW[1]&~SW[0];

assign HEX0[1] = ~SW[3]&SW[2]&~SW[1]&SW[0] |

                 SW[3]&SW[2]&SW[1]&SW[0] |

                     ~SW[3]&SW[2]&SW[1]&~SW[0];

assign HEX0[0] = ~SW[3]&~SW[2]&~SW[1]&SW[0] |

                 ~SW[3]&SW[2]&~SW[1]&~SW[0] |

                     SW[3]&SW[2]&SW[1]&~SW[0] |

                     SW[3]&~SW[2]&SW[1]&SW[0];

 

                    

//turn off HEX5-HEX2                    

assign HEX5 = 8'b1111_1111;

assign HEX4 = 8'b1111_1111;

assign HEX3 = 8'b1111_1111;

assign HEX2 = 8'b1111_1111;

 

endmodule

 

测试代码如下:

module  tb_p2;

 

reg [3:0] count;

 

wire [9:0] SW;

wire [1:0] KEY;

wire [9:0] LEDR;

wire [6:0] HEX5,HEX4,HEX3,HEX2,HEX1,HEX0;

 

assign SW[3:0] = count;

 

lab1_part2 p1(.KEY(KEY),

              .SW(SW),

              .LEDR(LEDR),

              .HEX5(HEX5),

              .HEX4(HEX4),

              .HEX3(HEX3),

              .HEX2(HEX2),

              .HEX1(HEX1),

              .HEX0(HEX0)

              );

 

initial

begin

  count = 4'd0;

  repeat(16)

  begin

    #100

    $display("in = %b, out = %b",count,{HEX1,HEX0});

    count = count + 1'b1;

  end

end

 

endmodule

 

仿真结果如图12所示,类似之前列出的真值表,对应16种SW的组合,生成相应的HEX1和HEX0的状态.

 

实验1 在MAX10 FPGA上实现组合逻辑

 

图12  仿真结果

 

评分标准:

1)  共60分,其中,Part 1占25分,Part 2占35分;

2)  10分,设计Part 1和Part 2的Verilog代码;

3)  10分,Part 2的真值表,卡诺图,逻辑表达式;

4)  20分,Part 1和Part 2的testbench及仿真结果。

 

References:

1.University of California, Davis
Department of Electrical and Computer Engineering
EEC180 DIGITAL SYSTEMS II Spring 2021
Lab 1: Implementing Combinational Logic in the MAX10 FPGA

 

Written by YongfengXie

2022/06/17