• 【黑金原创教程】【Modelsim】【第二章】Modelsim就是电视机


    声明:本文为黑金动力社区(http://www.heijin.org)原创教程,如需转载请注明出处,谢谢!


    黑金动力社区2013年原创教程连载计划:

    http://www.cnblogs.com/alinx/p/3362790.html


    《FPGA那些事儿—Modelsim仿真技巧》REV2.0 PDF下载地址:

    http://www.heijin.org/forum.php?mod=viewthread&tid=22419&extra=page%3D1


    第二章 Modelsim就是电视机

    2.1 连接 Modelsim

    2.2 自动编译,半自动编译,手动编译

    2.3 自动编译的预先设置

    2.4 常用界面

    2.5 自动编译与半自动编译

    2.6 操作Wave界面

    总结


    第二章 Modelsim就是电视机

    2.1 连接 Modelsim

    传统CRT电视给人印象笨重不过操作却非常简单,现代液晶电视给人印象轻便不过操作却非常麻烦。如果传统CRT电视与现代液晶电视不小心结合起来,结果就成为现在的Modelsim。许多朋友常认为学习 Modelsim等价与学习仿真,不过这也是美丽的误会而已。Modelsim不过是仿真所需的重要工具而已,然而Modelsim常用的功能如下:

    (一)编译软模块成为仿真对象。

    (二)播放波形图。

    根据笔者的认识,不管模块是否综合成功,只要一天未下载到开发板都视为本质理想的软模块。仿真之前,软模块必须经过 Modelsim编译成为仿真对象才行。此外,播放波形图Modelsim 最为重要的任务,也是学习 Modelsim最为重要的课题。基本上只要掌握上述两项功能,就已经足够了。不过。首先我们需要搞懂启动 Modelsim 的方法。

    Altera公司的集成环境——Quartus II,传闻说版本10.0以前自带官方的仿真工具,但是自认不如的它已经心灰意冷回老家去了。Quartus II升级为版本10.0以后,Modelsim自然而然就取代它的位置。这个故事告诉我们,Modelsim是一位外来者,预想使用Modelsim之前,Modelsim必须做好连接Quartus II的工作。

    Modelsim启动文件名是 modelsim.exe,一般藏身在以下路径:

    C:\altera\12.1\modelsim_ase\win32aloem\modelsim.exe //第二方免费版本

    笔者所使用的Modelsim是Altera自定义的版本,亦即 Modelsim Altera Started Edition,简称ase,源目录一般都放置在 altera的目录之下。除了 Started Edition 以外,Altera还有自定义的付费版本,亦即 Modelsim Altera Edition,简称 ae,然而默认路劲如下:

    C:\altera\12.1\modelsim_ae\win32aloem\modelsim.exe //第二方付费版本

    好奇的同学可能想问道“免费版本付费版本究竟差异何在?”。根据笔者的理解,两者之间的差别就在于付费版本的“仿真库”远胜免费版本,而且付费版本也没有行数限制。不过笔者却认为,只要巧用理想时序与仿真技巧,免费版本已经足够应用了,因为逝去的老嬷嬷一直告诉笔者“东西够用就好,多了就是浪费”,所以笔者不会烦恼什么付费版本,再加上付费版本一年要九百多刀 ... 真是吓死人。那么,什么又是仿真库?在此先留个悬念。

    抱歉,笔者不知不觉又离题了,让我们切回话题吧。首先找到Modelsim启动文件的藏在目录,笔者的话是:

    C:\altera\12.1\modelsim_ase\win32aloem

    clip_image002

    图2.1.1

    然后打开 Quartus II,接着调出 Tool 菜单,往下打开 Option,过程如图2.1.1所示。

    clip_image004

    图2.1.2

    随后,点击右边菜单树下的 Eda Tool Options,再将原先的路径拷贝到 Modelsim-Aletra 的空白处,完后点击 Ok生效。就这样,Modelsim连接QuartusII的工作就完成了,真是可喜可贺!

    2.2 自动编译,半自动编译,手动编译

    Modelsim开始执行仿真之前需要执行一堆让人觉得猥琐的准备工作,然而这些准备工作到底又包含那些步骤呢?

    (一)创建仿真设计

    (二)加载 .v 文件

    (三)加载 .vt 文件

    (四)生成仿真对象

    (五)生成仿真环境

    (六)启动仿真

    (七)加载仿真信号

    (八)播放仿真

    一般,准备工作包含上述8个步骤,具体解释往下继续 ...

    clip_image006

    图2.2.1 创建仿真设计

    其一,创建仿真设计如图2.2.1所示,有时候也称为创建仿真项目,自动编译与半自动编译会简化该步骤。

    clip_image008

    clip_image010

    图2.2.2 加载 .v 和 .vt 文件。

    其二,其三如图2.2.2所示,既加载 .v 文件和 .vt 文件,自动编译与半自动编译会简化该步骤。

    clip_image012

    图2.2.3 生成仿真对象和生成激励文本。

    其四,其五皆如图2.2.3所示,既生成仿真对象还有仿真环境,俗称编译,自动编译会简化该步骤。

    clip_image014

    图2.2.4 启动仿真。

    其六,如图2.2.4所示,既是启动仿真,用笔者的话来说就是激活仿真环境,自动编译会简化该步骤。

    clip_image016

    图2.2.5 加载仿真信号。

    其七,如图2.2.5所示,既添加仿真信号,自动编译会简化该步骤。

    clip_image018

    图2.2.6 播放仿真。

    其八,如图2.2.6所示,即播放仿真时间,自动编译会简化该步骤。

    每起仿真执行之前,我们就必须重复上述8个令人厌烦的步骤,不过黑暗总是存在光明。

    根据笔者的认识,上述这些准备工作有分为3个类,亦即自动编译,半自动编译,还有手动编译。笔者是一位节能意识非常强的男人,所以特别喜欢自动编译,还有半自动编译,些许讨厌手动编译。三种编译方法之间的差异,如表2.2.1所示。

    表2.2.1 各种编译办法。

    准备工作

    自动编译

    半自动编译

    手动编译

    创建仿真设计

    自动

    自动

    手动

    加载 .v 文件

    自动

    自动

    手动

    加载 .vt 文件

    自动

    自动

    手动

    生成仿真对象

    自动

    手动

    手动

    生成仿真环境

    自动

    手动

    手动

    启动仿真

    自动

    手动

    手动

    加载仿真信号

    自动

    手动

    手动

    播放仿真

    自动

    手动

    手动

    笔者之所以那么爱死自动编译,原因如表2.2.1所示,所有准备工作 Modelsim都会自动完成,啊 ... 多么节能的手段。换之,半自动编译除了前3个步骤以外,亦即创建仿真设计,加载 .v 与 .vt 文件以外,余下的5个步骤都必须手动执行。半自动编译虽然不想自动编译那么省事,不过笔者也爱它。反之,笔者却有点讨厌手动编译,因为上述所有准备工作都必须人为执行,话说死不死呀。

    clip_image020

    图2.2.7 自动创建仿真项目。

    一寸光阴一寸金,寸金难买寸光阴,伟大的祖辈教诲后代要珍惜时间,创建仿真设计还有加载 .v 与 .vt 文件这些个步骤往往是整个准备工作当中最浪费时间的,因为我们必须人为创建仿真项目,然而自动编译还有半自动编译会将仿真项目添加在设计项目的目录下,如图2.2.7所示,这是一个非常节能的手段。

    虽然在便利的范畴上,自动编译无疑是最好的选择,不过自动编译也有局限的地方,亦即自由度不大,这句话是什么意思呢?假设第一次的仿真结果无法符合预期的预想,结果读者必须重新启动 Modelsim,不然那些更动以后的文件都无法生效。如果读者的计算机条件很好,哪倒没什么问题,重启Modelsim也是小片刻的等待而已。但是,那些计算机条件不好的同学,等待可谓是一场漫长的恶梦。

    相反的,自动编译还有手动编译的自由度可大了,两者虽然用不着重启 Modelsim便可生效更动过的文件。但是手动编译相较自动编译,手动编译较为费力。经过种种的排除以后,最后我们会发现半自动编译会是我们最好的选择。站在节能的角度上,笔者当然推荐自动编译还有半自动编译。不过作为初学,笔者还是建议读者先习惯手动编译为好,因为接续的例子,笔者都是使用手动编译来执行仿真。

    2.3 自动编译的预先设置

    如果Modelsim经由集成环境(Quartus II)启动,这个过程就称为自动编译,但是我们在执行自动编译执行之前,我们必须预先设置编译信息,好让笨蛋的集成环境知晓一切。首先将Experiment01的项目打开,那是笔者在以前设计过的传统乘法器,不过那是一只实验性的小白鼠而已。

    clip_image022

    图2.3.1 菜单Assignment,还有 Settings选项。

    接着,调出 Assignment 菜单,然后进入Settings界面。如图2.3.1所示。

    clip_image024

    图2.3.2 界面 Settings。

    打开 Settings 界面后,我们会看见各种意义不明的选项,暂时无视它们,然后读者只要展开 EDA Tool Settings,再点击 Simulation,Simulation界面随之就会浮现在右边的窗口。沿着下方我们会看见NativeLink Setting,顺手点击 Compile test bench 左边的圈圈,结果如图2.3.2所示。最后点击 Test benches 按键即可。

    (确保 Tool name 设置为 Modelsim-Altera)

    clip_image026

    图2.3.3 窗口 Test Benches。

    事后,Test Benches 窗口会浮现在眼前,如图2.3.3所示。此刻窗口空空如也,因为我们还没未输入相关的编译信息。沿着右边,点击New按键。

    clip_image028

    图2.3.4 窗口 New Test Bench Settings。

    如图2.3.4所示,New Test Bench Settings 窗口会浮现在眼前,该窗口有3个部分,其一是激励文件名(上段),最大仿真时间(中段),还有激励文件的具体路劲(下段) 。

    实验一的模块名为multiplier_module.v,然而激励文本则名为 multiplier_module.vt。在此,Test bench name 是指激励文本名,亦即 multiplier_module(省略后缀 .vt)。

    clip_image030

    图2.3.5 激励文件 multipllier_module.vt 的仿真环境取名。

    Top level module in test bench 中文译名为顶层激励模块,任笔者怎么翻译都觉得怪怪的,所以笔者索性称呼它为仿真环境。如图2.3.5所示,名为 multiplier_module.vt 的激励文本,内容所属的仿真环境取名为 multiplier_module_simulation。

    clip_image032

    图2.3.6 激励文件名设置完成。

    完后,激励文件信息的基本设置如图2.3.6所示,也就是 Test bench name 输入为 multiplier_module, Top level module in test bench 输入为 multiplier_module_simulation。

    clip_image033

    图2.3.7 设置仿真时间。

    clip_image034

    图2.3.8 最大仿真时间为10us。

    New Test Bench Settings 窗口中段是仿真时间的设置,如图2.3.7所示。不管默认选项是什么东西,读者只要使能 End simualtion at 左边的圈圈,然后在右边的文本框中输入10us即可,既是最大仿真时间为10us。完后,如图2.3.8所示。

    clip_image035

    图2.3.9 设置激励文件路径。

    clip_image037

    图2.3.10 资源管理窗口——选择文件。

    如图2.3.9所示,New Test Bench Settings 窗口的下段是设置路径。沿着 File name 右边,点击 <...>,然后资源管理窗口就会浮现在眼前,在此寻找 multiplier_module.vt 文件,随后点击 Open按键更新选择,过程如图2.3.10所示。

    clip_image039

    图2.3.11 激励文件路径显示。

    clip_image041

    图2.3.12 激励文件路径添加。

    过后,File name 会显示之前选择的路径,如图2.3.11所示。接着,沿着右边点击 Add按键添加路径,如图2.3.12所示。

    clip_image043

    图2.3.13,整体效果。

    clip_image045

    图2.3.14 激励信息设置完成。

    设置完后,整体效果如图2.3.13所示,接着点击 OK 按键生效设置, 然后返回Test Bench窗口。此刻,我们已经完成激励信息的输入,作为证明,方才的设置内容都会显示在 Test Bench窗口之中,如图2.3.14所示。最后点击 OK按键更新设置。

    clip_image047

    图2.3.15 编译信息输入完毕。

    接着我们会返回 Settings 界面,沿着 Compile test bench的右边 multiplier_module的激励信息会显示在文本框中,以此证明编译信息输入完毕,结果如图2.3.15所示。最后点击 OK 更新设置。

    clip_image049

    图2.3.16 Modelsim启动,自动编译执行。

    确认一切设置办妥以后,打开 Tools菜单,沿着 Run Simulation Tool选项的右方,点击 RTL Simulation,过后Modelsim会自行启动,而且自动编译也会开始执行。过程如果2.3.16所示。

    clip_image050

    图2.3.17 仿真项目自动创建。

    对于自动编译与半自动编译而言,设计库(工作库)的默认名为 work,结果 work文件夹会自动添加在设计项目的目录下。期间,自动编译需要一定的执行时间,然而块与慢完全根据个人的计算机配置。

    clip_image052

    图2.3.18 Modelsim启动成功,自动编译执行成功。

    如果一切错误皆没有发生的话,Modelsim的界面会成功显示在电脑屏幕上,结果如图2.3.18所示。

    2.4 常用界面

    Modelsim 是一款功能强大的电视机,除了播放属于Verilog 的节目(波形图)以外,Modelsim 还可以播放其它节目,为此Modelsim 旗下如果拥有多个界面,我们一点也不用觉得奇怪。那些不擅长软件的朋友,可说是一场恶梦,然而很庆幸的是,我们用不着学习全部。根据笔者的理解,仿真仅需要以下几个界面而已:

    (一)Project界面

    (二)File界面

    (三)Library界面

    (四)Transcript界面

    (五)Simulation界面

    (六)Wave界面

    接着,让笔者逐个为大伙介绍。

    clip_image054

    图2.4.1 Project界面

    如图2.4.1所示,Project界面故名思议就是仿真项目界面,然而Project界面的使用程度并不频繁,因为自动编译还有半自动编译会省略创建仿真设计的步骤,余下也只有手动编译才会使用 Project 界面。总之,读者先看个大概,暂时把 Project界面的功能想象成为收纳东西的文件夹一样。往后,笔者自然会在手动编译的小节介绍它。

    clip_image056

    图2.4.2 File界面

    如图2.4.2所示,File界面有时候也称为文件界面,任何与仿真有关的文件都会显示在这个界面上。以实验一为例,multiplier_module.v 文件还有 multiplier_module.vt 文件都展示在资源树之下。File界面除了展示仿真相关的所有文件以外,什么作用也没有。顺便一提,不管自动编译还是手动编译,File界面都会使用到。

    clip_image058

    图2.4.3 Library界面

    如图2.4.3所示,Library界面有时候也称为仿真库界面,然而Library界面的作用却不怎么单纯。仿真库界面一般有两个作用,其一就是储存自定义IP所需的仿真信息,例如自定义关键字信息,自定义功能,延迟等信息。所谓的仿真库质量就是仿真信息的支持程度。此外,Library界面一般都是有两大分类,亦即设计库(工作库)与资源库。不管怎么样,详细内容往后详谈。

    clip_image060

    图2.4.4 自动编译创建名为 work的仿真设计。

    设计库别名也有工作库。设计库好比仿真所需的暂存空间,所有相关的仿真信息都会储存在这里。但是自动编译会擅自将它取名为work,以实验一为例,实验一的仿真对象是multiplier_module,仿真环境则是 multiplier_module_simulation,结果两者信息就这样储存在 work里边(如图2.4.4所示)。

    仿真库界面看似麻烦不过却非常好用,我们可以直接在这里更新(编译)仿真对象又或者更新(编译)仿真环境,还是启动仿真也可以。

    clip_image062

    图2.4.5 Transcript 界面。

    如图2.4.5所示,Transcript界面也是终端(Console)界面,故名思议 Transcript界面的作用就是显示打印信息还有接受 TCL命令(工具命令语言)。Modelsim虽然可以支持相关的TCL命令实现相关的操作,然而笔者却不建议学习 TCL命令。笔者认为,只要了解界面,善用界面,即使不学习 TCL命令也可以实现一样的操作。实际上这写都是笔者犯懒的借口而已,因为TCL命令学起来很麻烦。

    结果而言,笔者比较喜欢将 Transcript界面称为信息界面,一些有用的错误反馈信息或者打印信息都会显示在其中。不过,笔者偶尔也会被海量的信息打败,所以要好好控制信息的打印数量,不然结果就会自讨苦吃。

    clip_image064

    图2.4.6 Simulation界面 。

    clip_image066 clip_image068

    图2.4.7 添加仿真信号。

    如图2.4.6所示,sim界面是 simulation界面的缩写,然而笔者却称为仿真信号界面。一些可以仿真的信号都会放置在这里。此外,我们也可以手动添其它仿真信号,以实验一为例:假设,笔者想要观察仿真对象U1,U1是仿真对象multiplier_module的实例名,因此,笔者需要先展开仿真环境 multiplier_module_simulation,接着右键点击U1,然后选择 Add Wave,此刻仿真对象U1的内部一切将成为仿真信号,过程如图2.4.7所示。

    sim界面虽然有用但是自动编译却会忽略它。换之,半自动编译还有手动编译比较受到爱戴。

    clip_image070

    图2.4.8 Wave界面。

    如图2.4.8所示,Wave界面也称为波形图界面,也是最常用,最重要的界面,而且“学习Modelsim就是学习Wave界面”——这种说法一点也不过分。Wave界面的作用就是显示仿真信号,Wave界面虽然看似复杂但是操作却非常傻瓜,学起来也非常轻松。我们知道仿真对象不会使用人类的语言述自述,换之仿真对象会经由波形图显示活动记录,学习 Wave界面真正的困难之处就是如何解读这些波形图。

    clip_image072

    图2.4.9 显示相关界面。

    最后,让笔者做个简单的总结,上述6个界面是仿真最常用的界面,我们可以透过View菜单打开或者关闭它们,过程如图2.4.9所示。然而,根据编译方法的不同,界面的使用程度也会跟着不同,因此笔者绘出表2.4.1:

    表2.4.1 仿真常用界面。

    仿真常用界面

    自动编译

    半自动编译

    手动编译

    Project界面

    无用

    无用

    有用

    File界面

    有用

    有用

    有用

    Library界面

    有用

    有用

    有用

    Transcript界面

    有用

    有用

    有用

    Sim 界面

    无用

    有用

    有用

    Wave 界面

    有用

    有用

    有用

    虽然Modelsim还存在许多界面,但是对笔者而言,只要上述掌握上述6个界面就足够应付仿真了。学习仿真的过程是非常耗神耗气的,因此节能学习才是学习仿真的上上之道。

    2.5 自动编译与半自动编译

    在这个小节里,我们会透过实验一去理解各种编译方法的不同之处。笔者曾在小节2.3讲解过自动编译的预先设置,事实上自动编译是上天给予懒人的礼物,我们可以透过预设将麻烦的准备工作交由集成环境劳动。

    自动编译一般如流程如下:

    预先设置 → 启动功能仿真 → 自动创建仿真项目 → 自动加载 .v 与 .vt文件 → 自动编译 .v 与 .vt 文件 → 自动启动仿真 → 自动添加仿真信号 → 自动播放仿真

    除了预先设置可视之外,直至Wave界面显示波形图,其余步骤都是集成环境在暗地里执行。自动编译最大的好处就是节能,不过自动编译也有坏处,每当我们更新 .v 与 .vt文件以后,如果我们想要更新波形图,我们必须重新启动Modelsim才行。重启Modelsim至少需要几个呼吸的时间,笔者则认为那是短暂放松,然而那些性格比较焦急的朋友,可能是痛苦的等待。由此,半自动编译就诞生了。

    半自动编译一般如流程如下:

    预先设置 → 启动功能仿真 → 自动创建仿真项目 → 自动加载 .v 与 .vt文件 → 自动编译 .v 与 .vt 文件 → 自动启动仿真 → 自动添加仿真信号 → 自动播放仿真

    更动 .v 与 .vt 文件以后,预想更新波形图,流程如下:

    手动编译 .v 与 .vt 文件 → 手动启动仿真 → 手动添加输出 → 手动播放仿真

    半自动编译是经由自动编译执行一番以后,再手动执行几个步骤。具体过程如下:

    clip_image074

    图2.5.1 执行功能仿真(启动自动编译)。

    首先是经过Quartus 的Tools菜单,沿着 Run Simulation Tool 选项的右边,点击 RTL Simulation,然后自动编译就会执行,如图2.5.1所示。这样作的目的是经由自动编译,让集成环境做好仿真前的工作,好使我们节省气力。

    clip_image076

    图2.5.2 波形图出现在Wave界面。

    经过一段小时间以后,Wave界面会呈现波形图,亦即自动编译执行成功,如图2.5.2所示。当然前提条件必须确保 .v 文件还有 .vt 文件没有语法错误。此刻,一切准备工作已经经由自动编译执行完成。

    clip_image078

    图2.5.3 更动 .vt 文件内容。

    假设笔者手痒,更新 .vt 文件其中一段内容,如图2.5.3所示。但是笔者又不想重启Modelsim,于是半自动编译发生了。同样,必须先确保更改内容的语法是正确无误。

    clip_image080

    图2.5.4 打开 Compile 窗口。

    clip_image082

    图2.5.5 选择更新文件,手动编译。

    鼠标指向 Compile菜单,然后点击 Compile选项,如图2.5.4所示。接着,资源管理窗口会浮现在眼前,选择要更新的文件,在此是 multiplier_module.vt,确定以后沿着右下方依序点击 Compile随之点击 Done即可。此刻,最新的 multiplier_module.vt 内容就会生效。(步骤手动编译 .v文件与 .vt 文件完成)

    clip_image084

    图2.5.6 打开 Start Simulation 窗口。

    clip_image086

    图2.5.7 Start Simulation 窗口,启动仿真。

    事后,沿着 Simulate菜单,点击 Start Simulation 选项,如图2.5.6所示。如图2.5.7所示,Start Simulation 窗口接着会浮现在眼前,展开Design子窗口下的设计库work,

    选择仿真环境 multiplier_module_simulation, 然后鼠标致右下方点击OK,仿真就开始启动。(步骤手动启动仿真完成)

    clip_image088

    图2.5.8 Library界面,手动编译文件还有手动启动仿真。

    事实上,上述两个步骤(手动编译文件还有手动启动仿真)都可以经由 Library界面完成,如图2.5.8所示,展开仿真库work以后,会有仿真对象 multiplier_module还有仿真环境 multiplier_module_simulation。右键点击仿真环境,其中小窗口就有 Recompile(再编译)和Simulate(启动仿真)等选项,只要依序点击 Recompile 还有 Simulate,同样的操作也会发生。

    clip_image090

    图2.5.9 Wave界面什么也没有。

    clip_image092

    图2.5.10 Sim界面,手动添加仿真信号。

    一段等待以后,仿真就启动完毕。不过,此刻wave界面什么也没有,结果如图2.5.9所示。因此,我们必须手动添加仿真信号,首先打开 Sim界面,仿真环境 multiplier_module_simulation会是最高的父选择。如果,读者仅需要显示仿真对象的出入端而已,那么右键点击仿真环境,然后选择Add Wave,过程如图2.5.10所示。

    clip_image094

    图2.5.11 手动添加仿真信号。

    如图2.5.11所示,仿真信号手动添加成功后,那么仿真信号就会显示在 Wave界面的左框中。但是,此刻 Wave 界面(右框)还没有显示任何波形图,为什么呢?原因很单纯,因为播放键还没有按下。(步骤手动添加仿真信号完成)

    clip_image096

    图2.5.12 手动播放仿真。

    clip_image098

    图2.5.13手动播放仿真完毕。

    读者是否还记得,我们曾经在预设当中将仿真最大时间设置为10us,然后自动编译会自动播放仿真直至10us。同样,我们也可以手动播放仿真时间,如图2.5.12所示,输入预想播放时间在播放文本框当中。在此,笔者输入10us,然后沿着右方点击“↓”按键,稍等一会后,波形图就会播放完成,结果如图2.5.13所示。我们可以一次播放最大仿真时间之余,我们也可以多次播放片刻仿真时间。(步骤手动播放仿真完成)

    到目前为止,半自动编译的所有步骤我们已经执行完成,真是可喜可贺。在此,稍微让我们来思考一下:

    自动编译虽然方便,不过它也有不足之处,即自由度很小。其一必须重启Modelsim不然更新文件无法生效;其二不能随意添加仿真信号,因为自动编译仅针对仿真对象的出入端而已。为此,半自动编译就是为了弥补自动编译这两点不足之处才会降临到这个世界上。讨论完结自动编译还有半自动编译以后,接下来让我们来讨论手动编译。

    ===================================================================

    手动编译一般流程:

    手动创建仿真项目 → 手动加载 .v 与 .vt文件 → 手动编译 .v 与 .vt 文件 → 手动启动仿真 → 手动添加仿真信号 → 手动播放仿真

    正如上述流程所示,手动编译相较自动编译只是少了步骤“预先设置”之余,还有自动改为手动而已。况且在效果上,半自动编译有点类似手动编译,因此不得不让人思考,我们为何还要手动编译呢?

    假设笔者是一粒穷光蛋,没有钱购买Quartus II,因此笔者无法实现自动编译还有半自动编译。此刻Modelsim就会成为另一个集成环境,为此让我们暂时抛开 Quartus II,尝试使用 Modelsim 执行手动编译好让自己有个深刻的理解。

    clip_image100

    clip_image102

    图2.5.14 手动创建仿真项目

    首先打开Modelsim,然后切换到 Project界面,随之选择File菜单,沿着New选项右边再点击 Project,过程如图2.5.14所示。过不了一会,Create Project窗口就会浮现在眼前:

    (一)Project Name的作用不大随意输入就好,笔者取名为 mannual;

    (二)Project Location 是仿真设计的路径;

    (三)Default Library Name是设计库的取名,默认为work笔者取名为

    mannual_work;

    (四)点击OK生效。(步骤手动创建项目完成)

    clip_image104

    图2.5.15 Add item to the Project窗口

    clip_image105

    图2.5.16 Add file to the Project窗口

    clip_image106

    图2.5.17 添加以后文件。

    clip_image108

    图2.5.18 文件添加完成。

    手动创建项目完成以后,Add item to the Project窗口会浮现在眼见。如图2.5.15所示,其中有4个选项,而且意义也很直接,在此笔者就不解释了。点击 Add Existing File,Add file to Project窗口就会浮现在眼前,结果如图2.5.16所示,沿着右方点击 Browse按键,将 Multiplier_module.v 还有 multiplier_module.vt 这两个已有文件添加进来,过程如图2.5.17所示。时候,Project界面就会出现方才添加进来的两个文件,结果如图2.5.18所示。(步骤手动添加文件完成)

    clip_image110

    图2.5.19 手动编译。

    如图2.5.19所示,右键点击任意文件,然后沿着 Compile选项选择 Compile All,编译所有文件(步骤手动编译文件完成)。

    clip_image112

    图2.5.20 手动启动仿真。

    事后,切换到 Library界面,向下拉动滚条直至找到 mannual_work 这个自定义的设计库,暂开之后右键点击仿真环境 multiplier_module_simualtion,接着选择 Simulate,然后仿真就会启动。(步骤手动启动仿真完成)

    clip_image114

    图2.5.21 手动添加仿真信号。

    clip_image116

    图2.5.22 仿真信号手动添加完毕。

    稍等一会后,仿真就会启动完毕,借此 Sim界面也会跟着浮出水面。假设笔者想观察仿真对象multiplier_module的全体输出,笔者可以展开仿真环境,右键点击U1,接着选择 AddWave,过程如图2.5.21所示。切换至 wave 界面,仔细观察一下 wave 界面的左框,已经出现密密麻麻的仿真信号,结果如图2.5.22所示。在此我们可以断定,手动添加仿真信号已经完成。(步骤手动添加仿真信号完成)

    clip_image118

    图2.5.23 手动播放仿真。

    clip_image120

    图2.5.24 手动播放仿真完毕。

    10us的仿真时间对于实验一来说过于充足了,在此笔者输入1us的仿真时间,结果如图2.5.23所示,然后沿着右方点击“↓”按钮,开始播放仿真。经过几个呼吸的时间以后,wave界面的右框就会出现波形图,结果如图2.5.24所以。此刻我们可以断定,手动播放仿真已经完毕。(步骤手动播放仿真完成)

    手动编译一般是辛苦的劳动,啊!不是 ... 是缺少集成环境(如Quartus II)的情况下,才会选择的下下策。手动编译与半自动编译虽然相似,但是笔者却一直喜欢不上它,是否笔者太懒,还是手动编译太麻烦了?不管怎么样,初学者一般建议使用自动编译,然后再选择性使用半自动编译。至于手动编译,除非是学习作用,不然就无视它。

    2.6 操作Wave界面

    Wave界面是Modelsim所有界面之中最有用的界面,wave界面好比电视屏幕,用来显示节目,亦即波形图。操作wave界面近似操作老式CRT电视,又似操作现代液晶电视,这句话听起来虽然觉得有点矛盾。举例而言,如果读者只是“看爽”波形图而已,亦即看看形状然后傻笑自认看懂,结果就是老式CRT电视,操作程度非常傻瓜。反之,如果读者要仔细观察每一个时钟具体的时序情况,那么就是现代液晶电视,操作程度非常细腻。

    操作wave界面主要分为两种,针对老式CRT电视称为傻瓜操作;针对现代液晶电视称为细腻操作。傻瓜操作没什么好谈的,换之细腻操作是仿真技巧不可缺少的手段之一。

    不过,读者别担心,细腻操作界面也没有印象中那么困难,前提条件除了耐心以外,还是耐心,因为细腻操作wave 界面非常耗费精力还有时间,稍微一个不留心也会自乱阵脚。

    clip_image122

    图2.6.1 自动编译实验一。

    好了,开场白就讲到这里。首先经由自动编译启动实验一的仿真,然后再切换到wave界面作为本节的开端,过程如图2.6.1所示。

    clip_image124

    图2.6.2 Wave界面简介。

    为了减轻读者的学习压力,图2.6.2是经过笔者打码以后的wave界面。Wave界面一般有3大显示框:

    (一)波形图显式框

    (二)仿真信号显示框

    (三)光标信息显示框

    其一,波形图显示框顾名思义就是用来显示波形图的地方,亦即Modelsim的图形输出;其二,仿真信号显示框主要是用来显示仿真信号,还有仿真信号当前时钟的结果;其三,光标信息显示框是用来指示光标信息,如光标名还有光标位置。显示框不同,工具也不同,常用的工具如图2.6.2所示,表2.6.1则是工具的简单归类。

    表2.6.1 各种工具归类。

    其他

    波形图显式框

    光标信息显示框

    仿真信号显示框

    播放工具

    常规工具

    屏幕工具

    标签工具

    光标工具

    搜索工具

    clip_image126

    图2.6.3 播放工具。

    如图2.6.3所示,那是读者再熟悉不过的播放工具,不过笔者还是循例来讲一下。有作为的功能如图2.6.3所示,亦即重新播放,播放时间还有播放。

    l 重新播放如字面上的意思就从0时间开始起播放仿真,而不是重启整个仿真;

    l 播放时间也是播放进度;

    l 播放亦即开始播放;

    clip_image128

    图2.6.4 常规工具。

    clip_image130

    图2.6.5缩放模式。

    图2.6.4是常规工具也称为模式工具。常用的模式除了自由模式以外还有就是缩放模式。自由模式也是默认模式,当自由模式启动以后我们可以任意点击波形图显示框任意地方,缩放模式主要用来放大某个时间段。如图2.6.5所示,笔者启动缩放模式以后,笔者放大0~309ps的时间段,事后0~309ps时间段就会充溢整个波形图显示框。然而缩放模式,笔者也是偶尔的情况下才会使用而已。

    clip_image132

    图2.6.6屏幕工具。

    clip_image134

    ①屏幕标准的结果

    clip_image136

    ②屏幕放大的结果

    clip_image138

    ③屏幕放小的结果

    clip_image140

    ④屏幕按光标放大的结果

    clip_image142

    ⑤屏幕全局放大的结果,最大播放时间1.2ns左右

    clip_image144

    ⑥屏幕全局放大的结果,最大播放时间2ns左右

    图2.6.7 各种显示结果。

    图2.6.6所示是屏幕工具,常用功能有屏幕放大,屏幕放小,按光标放大,还有全局放大,各种显示结果如图2.6.7所示。①是标准显示;②是标准显示根据放大以后的结果;③是标准显示放小以后的结果;④是标准显示按光标放大以后的结果,然而②与④的不同之处就在于④是基于光标为中心的位置——3.9ns放大显示;

    ⑤与⑥都是标准显示按全局放大以后的结果,然而⑤的最大播放时间只有1.2ns左右,反之⑥的最大播放时间只有2ns左右,根据最大仿真时间的不同,全局放大也会产生不同的显示结果。反观笔者,究竟那种功能才是最常用的呢?笔者很懒,笔者比较喜欢按着 <Ctrl> + 滑鼠滚动键,缩放屏幕,因为这样作比较省力。

    clip_image146

    图2.6.8 标签工具。

    标签是保存当前波形图显示框状态最好的工具,如图2.6.8所示,常用的标签功能有:

    l 添加标签,亦即为当前波形图显示状态插入标签;

    l 删除所有标签,顾名思义就是清楚所有标签记录;

    l 读取标签,则是读取标签记录;

    l 管理标签,如字面上的意思,也有标签综合功能之称。

    clip_image148

    ①预想保存当前显示状态。

    clip_image150

    ②图2.6.10 显示状态经搅乱以后。

    clip_image152

    ③读取标签记录

    clip_image154

    ④显示状态读取完毕

    图2.6.9 标签工具使用过程。

    图2.6.9是标签工具使用过程,假设①是笔者预想保存的显示状态,然后笔者可以点击“添加标签“功能将当前显示状态记录起来。②是笔者不小心搅乱显示状态的后果,不甘心的笔者,如③所示点击”读取标签“功能,调回①的显示状态。④是读取标签的结果,①与④相较之下并没有差别。

    对于波形图显式框而言,标签工具是非常方便的工具,有时候时序记录过于庞大或者过度复杂,由于波形图显式框的长度有限,这时候标签工具就派上用场了。善用标签工具会节省将波形图显式框拖来拖去的劳动,我们可以将某个时间段的显示状态记录起来,又或者保存屏幕缩放结果。所以说,标签工具和笔者的相性是非常好。

    clip_image156

    图2.6.10 光标工具。

    光标是一个非常好用的工具,光标的作用好比补助线,参考线或者对齐线,然而光标也可以充当计算时间个数的好帮手。光标工具的常用功能如图2.6.10所示:

    l 添加光标,就是添加新光标;

    l 删除光标,就是删除当前选择光标;

    l 上一个信号沿,就是将当前光标移至当前信号的上一个信号沿;

    l 下一个信号沿,就是将当前光标移至当前信号的下一个信号沿;

    l 上一个下降沿,就是将当前光标移至当前信号的上一个下降沿;

    l 下一个下降沿,就是将当前光标移至当前信号的下一个下降沿;

    l 上一个上升沿,就是将当前光标移至当前信号的上一个上升沿;

    l 下一个上升沿,就是将当前光标移至当前信号的下一个上升沿。

    信号沿是时序基础的基础,所谓触发沿,有时候也称为触发沿,亦即信号发生状态变化的那一刻。下降沿,意指由高变低的信号沿;换之,上升沿意指由低变高的信号沿。不管物理时序还是理想时序,信号沿的概念也是相同的。为了让读者有感知认识一下光标工具的作用,笔者稍微示范几个光标工具常用的例子。

    clip_image158

    图2.6.11 添加光标,选择信号,光标信息。

    如图2.6.11所示,笔者新添加一个光标,光标信息显示框表示该光标名为 Cursor4(简称C4——塑料炸弹~笑),指向位置为0.01ns。单条光标的作用下,C4作为信号的对齐补助线。

    说点题外话。人的大脑是非常喜欢偷懒的东西,其中有这样的实验说过:当一个人步入一间四方空间以后,大脑为了省事,就会记录四方空间8个对角,作为平衡校准。同样的道理发生在光标的身上,时序图是一种并行可视化的记录,在此对齐作用的补助线可以减轻眼睛还有大脑的负担。

    clip_image160

    图2.6.12 随着信号的上升沿移动光标

    举例CLK信号与C4光标同时被选中。我们知道CLK信号一般将上升沿作为触发沿,如果笔者预想来回移动在于CLK信号之间的上升沿,笔者可以执行上一个上升沿还有下一个上升沿功能,结果如图2.6.12所示,C4已经移动至 0.15ns的位置。

    clip_image162

    图2.6.13 计算信号的周期时间。

    假设笔者预想结出 Start_Sig信号的周期,于是笔者再新添加一个光标,名为Cursor5(简称C5)。C4移至0.01ns的位置,然而C5移至0.29ns的位置,然后光标工具之间会自动求出时间差。如图2.6.13所示,Start_sig信号位于C4~C5之间一共占有0.28ns时间。如果笔者为进一步求出Start_Sig信号位于C4~C5之间一共占用多少个时钟,笔者可以这样计算:

    Start_Sig信号周期 / 时钟周期 = 0.28ns / 0.02ns

    = 14

    结果而言,Start_Sig信号位于C4~C5之间,一共占用14个时钟。

    clip_image164

    图2.6.14 锁定光标。

    光标是一种非常顽皮的工具,时常跑来跑去,因此我们可以配合光标信息显示框的锁定功能来固定光标。如图2.6.14所示,笔者沿着左下方点击锁定按键以后,C4就这样被固定住了,换之C5却没有。除了锁定功能以外,光标信息框还有两个像极 ”把手“ 还有 ”禁止进入“的按键,前者是配置光标,后者是删除光标,总之是非常单纯的功能,用不着笔者特意解释吧?

    锁定功能算是笔者比较常用的光标功能之一,像笔者这种喜欢作记录的男人,有时候为了标记详细的时序过程,动不动就会用上十几来个光标。如果每个光标都跑来跑去的话,笔者会直接发疯的,因此锁定功能在某种意义上已经多次拯救笔者的小命。

    clip_image124[1]

    图2.6.2 Wave界面简介。

    图2.6.2显示,除了波形图显示框或者光标信息显示框以外,还有一个名为仿真信号显示框的东西。笔者曾在2.5小节演示过,仿真信号可经由自动编译自行添加又或者人为后期添加都行。仿真信号显示框相较其它,自身隐藏的功能不仅丰富而且也非常实用。仿真信号显示框的左边是仿真信号的命名,右边则是信号处于当前时钟的结果。前者可以更动,后者则不行。

    clip_image166

    ①单位宽信号

    clip_image168

    ②多位宽信号

    图2.6.15 单位宽与多位宽仿真信号。

    仿真信号一般分为两种,亦即单位宽信号还有多位宽信号,如图2.6.15所示。单位宽信号例子有 CLK信号,RSTn信号,Start_Sig信号还有 Done_Sig信号,一般格式皆为 Logic逻辑。多位宽信号例子有 Multiplicand信号,Multiplier信号,Product信号还有i信号,一般格式皆为 Literal。

    clip_image170

    图2.6.16 展开多位宽信号。

    我们可以经过右键点击任意信号,然后沿着Format的右方更换格式也有可能,不过一般却不会这么作。Logic顾名思义不是零既是一,然而Literal在此则是添加的意思。所谓的多位宽仿真信号是由N个单位宽仿真信号叠加而成,如图2.6.16所示,笔者故意展开仿真信号i,然而里边都是单位宽仿真信号。

    clip_image172

    图2.6.16 多位宽仿真信号的模拟格式。

    多位宽仿真信号还有另一个有趣的显示格式,亦即模拟格式(Analog)。如图2.6.16所示,笔者选择 Product 信号作为小白鼠,然后更改模拟格式。紧接着,Product信号的波形图再也不是叠加格式而是模拟格式。模拟格式有 Automatic(自动)与Custom(自定义)。

    clip_image174

    ① 模拟格式——阶梯式。

    clip_image176

    ② 模拟格式——加入式。

    clip_image178

    ③ 模拟格式——后退式。

    图2.6.17 各种模拟格式。

    自动模拟格式会执行设置,显示高度(Height),还有最大值(Max)和最小值(Min)的范围,阶梯式作为默认模拟格式,反之自定义模式必须手动设置上述几个选项。此外,除了默认的阶梯式①以外,模拟格式还有加入式②,或者后退式③(预想知道什么式请自行谷歌),各种效果如图2.6.17所示。模拟格式的程度仿真AC/DC或者波形算法以外才使用而已,普通情况下很少用上。

    clip_image180

    图2.6.18 更改进制。

    多位宽仿真信号除了可以更改格式(Format)以外,还能更改基数(Radix)。如图2.6.18所示,笔者将 Multiplicand信号,Multiplier信号,Product信号,还有 i信号更改为十进制。此刻,仿真信号显示框,还有波形显示框的文字信息都为十进制表示。曾经有同学问过笔者,如何批量更改仿真信号的显示基数?方法非常简单,只要按住<Ctrl>键或者<Shift>键多项选择仿真信号,然后右键点击其中一个选中信号再更改基数,结果其它被选中的仿真信号也会跟着变动。

    Modelsim可以支持的基数如表2.6.1所示:

    表2.6.1 Modelsim可以支持的显示基数。

    Symbolic作用不明

    Binary二进制

    Octal 八进制

    Unsigned 无符号位

    Hexadecimal 十六进制

    ASCII 字符

    Time 时钟单位

    Fixed Point 定点

    UseGlobalRadix 作用不明

    Numeric Enums作用不明

    Symbolic Enums 作用不明

               

    如果表2.6.1所示,尽是常见的基数,不过如Time 或者 Fixed Point它们是比较特殊的基数,此外还有一些作用不明的基数,怒笔者知识有限不懂说明,有兴趣的朋友可以自行研究看看。

    有时候我们会遇见仿真信号过多,结果逼不得已不分组仿真信号。根据笔者的习惯,仿真信号一共有3种分组方法,亦即 New Window Pane分组,Add Divider 分组,还有 Group 分组。

    clip_image182

    图2.6.19 New Window Pane 分组。

    如图2.6.19所示,随便右键任意仿真信号,然后沿着 Add 选择 New Window Pane,然后Modelsim会自动向下添加新Window Pane,接着利用滑鼠手动拖拽仿真信号进入即可。

    clip_image184

    图2.6.20 删除 Window Pane。

    New Window Pane 分组有一个非常头疼的问题,Window Pane虽然容易添加,不过删除 Window Pane却比较麻烦。如图2.6.20所示,我们可以经由 Edit菜单选择 Delete Window Pane 来删除当前选择的 Window Pane,但是连同组内信号都会一同删除。New Window Pane 分组看似作用不大,不过如果解读时序比较随意,好比使用卫生纸擦完既丢的话,New Window Pane分组不差是一个好方法。

    clip_image186

    图2.6.21 Add Divider分组。

    Add Divider 分组是笔者常用的分组方法之一。如图2.6.1所示,右键点击任意仿真信号,沿着Add 然后选择New Divider。Add Divider分组可以注释组名,图中笔者将仿真信号分为四组,亦即 Environment Signal,Input Signal,Output Signal,还有Misc。如果解读时序仔细而且又不是最终的话,Add Divider是不错的分组方法。此外,Add Divider 生成的分割线可以当成仿真信号按 <Delete> 键删除。

    clip_image188

    图2.6.22 Group分组。

    最后还有一个分组方法就是 Group 分组,我们可以选择预想分成一组的仿真信号,然后右键点击任一仿真信号,再者选择Group,过程如图2.6.22所示。图中,笔者将所有仿真信号分为四组。

    clip_image190

    图2.6.23 暂开或者回收Group分组仿真信号。

    Group 分组相较 Add Divider 分组,前者可以注释组名以外,也可以任意暂开或者回收相关的分组,效果如图2.6.23所示。

    clip_image192

    图2.6.24 撤销Group分组。

    除此之外,撤销Group分组也非常简单,如图2.6.24所示,选择预想撤销的分组,然后右键点击 Ungroup即可。Group 分组不管上看下看还是左看右看都是最好的分组方法,除了注释组名以外,组名也可以一同显示在波形图显示框当中,而且展开回收分组功能也助于仿真信号管理。如果波形图不是供人欣赏,笔者一般都不会使用它。

    clip_image194

    ①右键点选择Properties。

    clip_image196

    ②选择颜色。

    图2.6.25 信号选择颜色。

    仿真信号显示框还有较为花俏的功能,亦即更改信号波形的颜色。如图2.6.25所示,①笔者右键点击 CLK信号,然后选择 Properties。不一会儿,②Wave Properties窗口就会浮现在眼前,沿着Wave Color 点击 <Colors>按键,结果又会跳出颜色小窗口,笔者选择黄色。事后,CLK信号的波形图颜色就会让上黄色,过程诶图2.6.25所示。

    clip_image198

    图2.6.26 酷爆的波形图。

    只要读者存有几分心思为各组信号染上不同的颜色,最终会产生预想之外的效果。如图2.6.26所示,是笔者心血来潮的艺术成果,读者是不是觉得很酷呢?只要读者有心,专业波形图其实一点也不难做出来。

    clip_image200

    图2.6.27 搜索工具。

    如图2.6.27所示是搜索工具,然而常用的功能有:

    l 搜索信息,亦即寻找信息;

    l 向后搜索,让当前光标在当前信号上向左寻找搜索信息;

    l 向前搜索,让当前光标在当前信号上向右寻找搜索信息。

    clip_image202

    图2.6.28 使用搜索工具。

    搜索工具虽说是综合工具,但是也只有仿真信号显示框使用而已。如图2.6.28所示,笔者同时选择 Product 信号还有光标C2,接着笔者又在搜索信息输入框中写入”-55“,然后按回车键。回车键默认是向前寻找搜索信息,结果光标C2停留在Product信号 -55的地方。搜索工具的作用一般都是在海量信息种寻找某个结果。

    clip_image204

    clip_image206

    图2.6.29 保存Wave界面。

    当我们完成Wave界面的最终设置以后,我们可以将当前wave界面保存下来。沿着File菜单点击 Save Format,不一会 Save Format窗口就会浮在眼前。左下方记得勾选 Waveform formarts,然后输入任意名字,.do文件就会保存在仿真项目的目录下。在此,笔者将图2.6.26的wave界面取名为 ArtWaveWorm,并且保存下来。这样作有两个目的,其一就是为未来做好复习的准备;其二就是与人分享。

    虽然还有许多工具未曾涉及其中,不管初学也好还是熟烂也好,只要掌握上述方法,基本上已经足够应付仿真了。享受节目当然要选择清晰的画面啦,然而操作Wave界面好比调节电视机的显示状态,只要wave界面足够显示时序细节,那么操作就到此为止。

    余下,我们应该保留更多精力用来解读时序,难道会有傻子使用电视不是观赏节目,而是研究电视机的构造或者产生原理吗?

    总结:

    Modelsim 是否等价仿真?答案当然是否定的,原因很单纯,因为Modelsim只是一架性能比较优秀的电视机而已。然而,如何摆弄这架电视机使它播放最有用的节目才是学习 Modelsim的真正目的。不过,观赏节目之前我们必须学会如何打开电视机,根据笔者的习惯,Modelsim有三种启动方法,亦即:自动编译,半自动编译还有手动编译。

    作为初学或者已经熟透Modelsim的朋友,不管怎么样,笔者还是强烈推荐使用自动编译,然后再选择性使用半自动编译,至于手动编译除非有特殊因数,不然就无视。仿真本来就是非常费劲耗力的差事,而且启动modelsim 的过程也非常猥琐,我们不应该耗费过多的尽力在作用性不大的地方。因此,自动编译无疑是我们最好的节能手段,不过自动编译也有局限性的弱点,结果选择性使用半自动编译就是弥补这方面的不足。

    当Modelsim启动成功以后,各种作用界面也会跟着浮现在我们的面前。常见的界面有, Project界面,File界面,Library界面,Transcript界面,Simulation界面,还有wave界面。自动编译会省略 Project界面的执行过程,然而编译成功以后的信息会保存在默认设计库——Work里边。Library界面有,除了临时作用的设计库以外,也有相关的资源库。此外Library界面也可以充当“更新文件(编译文件)”,还有“启动仿真”的快捷入口。

    Simulation界面需要启动仿真成功以后才会浮现的仿真界面,Simulation界面一般省略名为sim界面。Sim界面的里边隐藏大量仿真信号,不过自动编译仅将仿真对象的输入端作为仿真信号而已,换之半自动编译还有手动编译可以随意添加仿真信号。仿真信号添加成功以后,便会移至wave界面的仿真信号显示框当中。

    如说Wave界面是Modelsim最重要的界面,话语一点也不过分。Wave界面的作用就是可视化Verilog HDL语言,也是俗称的波形图播放。Wave界面主要分为三个显示框,亦即波形图显示框,仿真信号显示框,光标信息显示框。波形图显示框最为重要,而且操作工具也是最多;仿真信号显示框,作用仅此与波形图显示框,它虽然没有丰富的操作工具,不过本身自带许多操作功能;光标信息显示框,顾名思义就是用来显示光标的信息还有管理光标,作用程度虽然不及前面两者,但是也很重要。

    如何操作wave界面,就是如何摆弄以上3个显示框而已,然后再善用操作工具还有显示框自带的操作功能,以致将时序细节有多清晰就多清晰般显示出来。根据笔者的习惯,对齐信号是非常重要的,因为可以节约眼睛的注意力还有大脑的焦距力,对此我们可以使用光标充当补助线。

    除此之外,分组信号也非常重要,分组信号不仅造就管理仿真信号变成更加省力,而且解读时序也能更加集中。然而,分组信号最根本的原因是让波形图变得更加整洁和美观,因为顺眼的东西可以柔化焦急的心情,打造仿真的好心境,好心情自然会产生好结果,这是千古不变的事实。

  • 相关阅读:
    coding
    我的大学
    《活出生命的意义》读后感
    《世界是数字的》读后感
    学习进度表
    阅读《我是一只IT小小鸟有感》
    《软件工程师职业规范》心得
    软件工程第二次结对作业
    软件工程第三次作业
    软件工程第二次作业
  • 原文地址:https://www.cnblogs.com/alinx/p/3394061.html
Copyright © 2020-2023  润新知