版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、FPGA 流水灯实验花了几天通过流水灯实验把学习的 verilogHDL 的建模技巧总结了一下。写一份总结,给制定一套规范,方便以后查看和解决问题。实现目标:通过流水灯的实验实现了串行工作,流水线工作(时间并行),并行流水线工作(空间并行)。串行工作是 CPU 的工作方式,也就是一个时间只能做一件事。通过 verilogHDL 完全可以模仿这种工作方式,也就是说通过 CPU 实现的算法和驱动程序完全可以转换成对应的verilogHDL。并且结构化程序设计的思想(顺序,选择,循环)也可以通过verilogHDL 实现。除了串行工作外,verilogHDL 还有CPU 很难实现的流水线(时间并行)
2、和并行处理(空间并行)的优势。当然现在的多核CPU 通过多线程编程也可以实现并行处理,但实现相对比较复杂。FPGA 只要逻辑资源足够多,理论上可以实现无限并行处理。这也就是我最喜欢FPGA 的。只需要学习一种硬件描述语言,编写的可综合模块可以在不同厂家的FPAG,ASIC 或CPLD 上实现。可移植性强。可以不需要学习各种不同的单片机。和顺序处理最大的问题,驱动不同模块一次只能处理一个模块,停下另外模块,导致实时性不好。流水灯实验通过以流水灯为原型简单的实现了串行和并行工作方式。通过 4 个LED 灯表示完成一件事情的 4 个不同的步骤,LED 闪烁一次表示完成一个步骤。1顺序工作:DCBAD
3、CBDCBDCBDCBDCBA说明:顺序工作在 T0 时刻准备数据,在T1 到 T4 时刻处理 A 数据,直到A 处理完后才能开始处理B 数据,一直到T16 时刻处理完成 4个数据,处理数据共用 16 个时刻(步骤数 m*数据数 n),时间复杂度为O(m*n)。顺序时序图如下:2AAAA流水线工作:DCBADCBDCDADCBA说明:流水线工作在 T0 时刻准备数据,在 T1 到 T4 时刻为首次执行时间,接下来每个时钟完成一个数据。处理数据共用 7 个时刻。(步3DCBDCBACBABAA骤数 m+(数据数 n-1),时间复杂度为 O(n)。并行流水线工作:BADCBADCBADCBADC4
4、说明:并行流水线工作是多条流水线同时工作,在 T0 时刻准备数据,在 T1 到T2 时刻为首次执行时间,接下来每个时钟处理一个数据。处理数据共用 3 个时刻。(步骤数m+(数据数n/流水线条数 t-t),时间复杂度为 O( n/t )。从上面三种工作方式的时间复杂度可以得到流水线处理数据的时间是串行方式的 1/m,而并行流水线处理数据的时间则是单流水线的1/t。这是以空间换时间的方式,可以得到更高的效率,代价是消耗的空间。对于如今超大规模集成电路的产生,成本降低低,以空间换时间可以获得更高的性价比。而 verilogHDL 使得这种设计方式便的非常简单,并行流水处理数据也是通用处理器所无法代替
5、的。代码约定:VerilogHDL 是一个在不断完善的面向过程的语言,看了相关的语法书,发现没有找到一套合适的完整的语法结构。大多数 VerilogHDL语法书只是讲了相关的用法,状态机的写法也时分繁琐,各种综合语言和验证语言混在一起,学起来就像盲人摸象,找不到方向。在编写5代码的过程中,按照代码编写的原则找到了一套约定,来规范建模。发挥出verilogHDL 更大的可能行的。编写代码的历史是从开始的代码程序,到模块程序,再到如今的对象程序的过程。面向对象编程语言好坏,如今的是争议的。而我在开始制定约定之前就有想法把面向对象的编程引入对每个模块实现,然后通过模块内部的功能任务对外提供接口,以实
6、现高度的抽象。达到像操作现实中的事物一样建模。但在尝试的过程中失败了。VerilogHDL 并没有提供这类的语法支持,VerilogHDL 中的任务和函数也不像高级语言一样。不过面向对象做为一种思考方式确简单的。比如一个 LED 对象,它有打开LED 和关闭LED 两种操作。分析出有关特性后进行建模会把问题变得简单。而且VerilogHDL 中模块也有类似于面向对象中类的特性。编写代码的首要任务是管理复杂度,研究表明人能同时关注的智力模型为 7+2,而嵌套关注通常不超过 5 层。编写一段代码的同时关注点很容易会超过 9 个。通过智力训练提供关注智力模型数的效果微乎其微。所以为了能编写任意大规模
7、的代码,把同一时间关注的智力模型数降低的是很有效的。而且工程也是在制定相关的编程规范,对编程限制的基础上发展起来的。VerilogHDL 虽然是硬件描述语言,但它已经摆脱了原始的电路图输入的方式,具有更高的抽象性,所以它应该可以应该开发中的类似的结论来提高开发效率。就像高级语言相对于 01 机器码编程一样。我觉得在 verilogHDL 在模仿顺序操作上更像汇编语言,因为它没有实现顺序,选择,循环结构的相6关语句。结构化设计是编程上的一个里程碑,是已经被证明有效的技巧,所以把结构化设计引入 verilogHDL 进行建模可以提高建模效率。结构化设计是建立在任何程序都可以用顺序,选择和迭代(常常
8、也称作循环)三种结构实现的理论基础上的。结构化设计原则简单的来说就是,程序的流程按照自上而下方式设计,不用在流程中随意跳转。对于小规模的编程,在任意跳转是非常灵活和快速的。但不符合人的逻辑思考方式。逻辑思考是自上而下的,在思考后面的时候很容易忘记前面。所以按照结构化程序设计,对硬件进行建模符合人的逻辑模式,可以直线式的从上到下进行设计。因为高级语言编程和 VerilogHDL 建模虽然有很多类似的概念,但在实质上是不同的,VerilogHDL 是对硬件进行设计的。为了区分概念在下面,把VerilogHDL 的编写代码叫做建模。变量名约定在建模中我采用了类似于 java 的变量约定,应为 jav
9、a 的变量名约定是与java 语言一起完成的,具有一定的完整性和普遍性。reg 和wire 等普通变量名采用首字母小写,后面的每个字母开头大写,其它字母小写的形式。宏常量定义名采用全部大写。任务、函数和模块名采用每个字母开头大写,其它字母小写的形式。这里还涉及带 4 个特殊变量名,时钟(clk),复位(rst_n),模块调用开始(StartSig),模块反馈结束信号(DoneSig)。这四个变量是模块常用的输入输出变量。所以在建模中这四个变量名不再作其它变量命名。7前缀reg 表示驱动某个输出变量的寄存器变量,is 表示驱动某个输出变量的使能寄存器变量,_n 表示输入输出变量的低电平有效。在建
10、模中发现模块可以大致分为四类,所以大致的约定四个后缀:_Interfac 接口模块,该模块中不含任何,只用来建立于外部元件的接口; _Dirve 驱动模块,该模块是包含功能的与外部模块进行连接的模块具有的驱动功能;_Control模块,是用来协调各个模块之间功能的模块;其它没有后缀的模块为功能模块,每个模块能够完成的功能。变量命名规则只是一个参考,并不能当作约束。实际情况中变量名命名是很复杂的。要利用约定发挥管理复杂度的优势。当有更理由不使用约定时一定要使用,避免出错。建模说明:在建模的过程中运用了编程的几种技巧贯彻整个建模过程中,系统的复杂度。遵循抽象性,性,高内聚,松散耦合的建模技巧,并且
11、采用了建立原型,和代码阅读的审查,及时查找错误,把修改错误成本降到最低。首先从顶层以 LED 灯为对象建立抽象数据类型,LED 灯能的操作只有简单的开和关。然后从底层以代码的角度出发建立 LED 灯的最小原型。我在最开始建立的最小原型是一个模块中包含一个定时器和一个LED 翻转两部分时序逻辑的原型,实现了能够定时开关 LED 灯的功能。并且通过了时序的正确性。最后通过代码阅读对代码的逻辑合理性进行检查。8相关实验数据表明这种编程是高效的。因为检查出错误的时间距产生错误的时间越晚,需要修改错误的成本也就越高,甚至可能导致无法修复错误,只能重建。所以即使检查和修改错误是提高效率和质量的有效,通常采
12、用这种开发周期和一次完成率是很高的。完成原型后的第就是实现对模块的,按照一个模块一个功能的原则,把定时器时序逻辑,和 LED 翻转时序逻辑。期间复杂度并没有降低,只是转移到两个模块中,这样在一个时间所关注的代码就被有效的了。通过这种可以任意大的系统复杂度。使得实现超大系统成为可能。下面以流水灯的代码为例来详细说明建模中的各种技巧,按照自顶到下的顺序:这里是 Led_Control 模块和 Led_Driver 模块。Led_Driver 实现了对LED 开关的高度抽象和。使得每一个LED 都只需要给它一个闪烁周期和开始信号,LED 就会按照一个闪烁周期不停的闪烁,并且每闪烁一次完成给出了个完成
13、信号。9这个模块是以模块数组的形式建立的。这里需要注意的是它建立了LED_SIZE 个Led_Driver,其中的每个输入输出端口是(端口位数*LED_SIZE)个,外部信号输入输出时按照对于位数自动匹配。信号位不足的会自动重复,例如 LED_SIZE 个 Led_Driver 有 LED_SIZE 个时钟,但输入的时钟位只有 1 位,所以这 1 位时钟会自动扩展到LED_SIZE 位。还有其中的 Led_Driver 有一个设定闪烁周期的信号有13 位,LED_SIZE 个Led_Driver 就有LED_SIZE*13,这样输入信号的13:0匹配第一个Led_Driver 的对应的 13
14、位闪烁周期,输入信号的26:14匹配第二个Led_Driver 的对应的13 位闪烁周期,依次类推。使用模块数组是一个很有效的,避免了把 Led_Driver 重复的写多遍,割裂了它们的。使得修改其中一个时,要多个一起修改,导致修改漏掉,很难查找错误。通过模块数组也可以解决这个问题,还可以帮助和抽象模块。我在最开始的代码中为了实现 4 个流水灯的闪烁效果把重复模块写在一个模块中,并且 4 个LED 翻转模块由同 1 个定时器翻转。在过程中发现,这个有 4 个LED 驱动的模块没有实现高内聚性,也就是 4 个LED 模块共享 1 个定时器。而模块数组表明了每个 Led_Driver 都是的,4
15、个 LED 灯应该像1 个LED 灯一样。然后我就把 1 个LED 模块和 1 个定时器成一个 Led_Driver。通过模块数组实例化 4 次。因为每个 Led_Driver模块都是的,所以降低了每个 LED 之间的耦合度,实现了松散耦合。使得可以很容易的把对 4 个 LED 的扩展到任意数量的。这是通过模块数组达到的高内聚和松散耦合的效果,同时也完成10了对Led_Driver 更次的操作,使得操作每个LED 站在了抽象层,而不是是底层。在底层你需要考虑定时器翻转多少次才能到这个时间,然后还要用这个时间打开或关闭LED,这样需要考虑的问题很复杂也容易出错。在抽象层你只需要给什么时候打开或关
16、闭 LED 就够了,它就会自动的完成翻转工作。抽象性也是人脑处理的方式,例如的家你甚至说不清门是什么颜色的,门的把手是什么样式的。人脑对门的处理是抽象的,它是一个可以开和关的门。你只需要知道这个就可以进入家中,根本不需要记得门的颜色是什么。在这个模块的头部有几个宏定义,用来集中管理需要设置的常量。可以实现代码的移植,在这里定义的是 4 个 LED,可以很方便的变成8 个,只需要修改一次,而不用在代码中到处修复神秘数字,减小出错的可能性。同时,使用宏定义破坏了模块之间的松散耦合,同一个宏定义可能在多个模块中,有时不注意会出现意想不到的问题,使得查找问题不能集中在一个模块中。相对而言,使用参数量(
17、parameter)代替宏定义,定义一个模块中相同常量的神秘数字,达到集中修改的目的可以管理复杂度,使得模块松散耦合。这里使用宏定义的好处是把相关常量集中到开头,移植时只需要在同一个地方修改,避免了在代码中到处寻找参数量。所以这里的原则是优先使用参数量定义神秘数字,集中常量。然后再根据需要在抽象的过程11中换用宏定义。不需要修改的常量就让它以参数量的形式定义。Led_Control 模块:自上而下这是一个模块是的时序逻辑电路的部分,的模板也就是这个样子。从 always 开始看,时序逻辑都有时钟和复位信号,所以标准的 always 头就是这么写,时钟上升沿工作,复位下降沿异步复位。通过 if
18、复位条件把 always 块中用到所以寄存器全部复位。这些寄存器定义在对于 always 块的上面。原则在哪里使用,在哪里定义。尽量让使用在一屏内显示,减小变量的生存周期和使用跨度,可以管理同一时间关注变量的个数。这里用到了变量i,j,k 来模仿结构化设计,的用i 表示执行12顺序,用 j 来计算循环次数,进行循环跳转。这样就可以模仿结构化设计的顺序、选择和循环结构。如果需要嵌套调用可以把 i 作为外层的执行顺序,j 作为内层的执行顺序,用 k 来做循环计数。在建模中这 3 个变量不在作。来说嵌套超过 3 层就很难管理,这时应该把内层嵌套提前出来变成模块的调用。所以的这 3 个变量就已经足以应
19、对很多情况。这里的 case 语句中的功能类似于状态机通过输入的变化进行状态间的跳转。但这里的思想并不是传统的状态机。这样借用了Verilog 那些事中的仿顺序建模思想。状态机所实现的算法与软件实现的算法本质是相同的,可以相互转换。但是传统的状态机需要先分析各种情况,然后画出状态转换图,才能成对应的代码。其中状态机中有很多冗余的空转部分,转换到另一个状态需要两个时钟。通过这种顺序建模思想可以把算法直接到代码,略去传统状态机中的冗余部分。使得步骤之间的转换只需要一时钟。这时设计和理解就更符合逻辑思维方式了。例如,case 代码中的第一步调用串行流水灯任务,结束后返回。第二步,调用流水线流水灯任务
20、,结束后返回。第三步,调用并行流水线流水灯任务,结束后返回。第四步,重复第一步。把程序设计中的结构化设计引入对硬件的建模,使得通过硬件实现逻辑算法变得和程序设计一样简单,并且硬件还可以很容易的是流水线和并行处理。充分发挥了硬件逻辑的优势,和消除了硬件实现算法的复杂过程。最后的assign 块是用来对组合逻辑建模,其中没有时序,13输入立刻输出,但输出时间无法。在这样通常用来对模块的输出信号进行赋值。这里没有把输出信号直接成reg 类型,而是通过中间变量的寄存器把always 块中时序逻辑部分的量转出到assign 块的输出 wire 类型。通过这种技巧把组合逻辑和时序逻辑考虑,管理复杂度。在生
21、成的模块逻辑数量上是相同的。assign 块后面的代码是上面三个调用任务的具体实现过程。在封装成任务之前都是在 always 块中建立了原型,反复测试实现功能后通过任务起来的。在任务的接口处是需要通过修改传入的参数。任务里的 j、k 变量并没有通过传参数的进行,而是与所在模块共享,统一管理。因过传参数需要的输入输出变量,反而会增加复杂度。所以这里没有进行处理。否则继续循环这是任务中对循环结构的模拟,类似于汇编语言中 JMP 的用法。汇编语言中没有像高级语言中循环结构,通过条件和跳转可以模拟实现结构化。这里用了类似的思想。这里用的是直到型循环(类似于 dowhile( )),也可以通过条件和转跳
22、轻松实现当型循环14直到条件满足跳出循环(while( ))和计数循环(for( ))。类似的条件结构(ifelse)也可以模拟。这样就了结构化编程的三种基本结构。可以模拟任何程序。但这里的模拟还会出现类似于 c 语言中 goto 语句的问题。这么跳转方式在语法上是没有限制的,可以一会儿执行前面的代码,一会儿执行后面的代码,所以在使用的时候要按自上到下的结构化设计思想,避免逻辑混乱。原则跳转语句只向后跳转。这段代码中的循环结构并没有这样原则,因为循环结构是同一段代码重复多次,在同一个地方打圈后,继续向下执行,并没有跳到前面的部分。总体来说这段代码是符合结构化设计。已经证明任何程序都可以通过结构
23、化设计实现,所以类似 goto 这样随意跳转的语句只会增加复杂度,导致逻辑混乱。在这里提到了循环,在 verilogHDL 中也有类似于C 语言的 while和for 语句,但这些语句和高级语言中的循环语句是不同的。高级语言是顺序执行的,所以循环语句重复的代码可以被执行多遍。而verliogHDL 中的 while 和 for 重复的语句会生成重复的实例原件,并不能达到多次执行的效果。这里需要区分理解,只是看起来一样,实质是不同的。15这两个任务中实现的是并行处理的流水线和多条流水线结构,verilogHDL 能够很容易的实现流水线处理,提高数据处理速度。但要建立流水线有一定的限制,流水线各个
24、步骤必须是同步的才能发挥出最大的效率。如果流水线不同步,就会造成第二步的数据还没处理完,第一步的数据就来到,冲掉第二步的数据。这里可以用到互锁机制和同步 FIFO 来解决不同步的问题。但这样就不能发挥流水线最大的处理效率,不过在并行性上相对串行处理也要快不少。这是以空间换取时间的方式。对于超大规模集成电路发展,相对来说并对价格有16太大的影响,反而提高了性能。在这里可以得到一个结论,凡是类似于 LED 这种顺序处理时,每步都相同的操作可以转换成对应的流水线,提高处理数据的能力。类似的例子有乘法器和除法器要用到连续移位操作的,都可以转换成流水线设计。使得不同步骤可以同时工作。这个 LED_Con
25、trol 模块已经很长了,虽然中间应用的任务,大大降低以复杂度,但也是足够复杂的了。这三个任务全部写在一个always 块中,复杂度将是难以想象的,稍有不慎就会出错,并且同时在几百行代码中查找错误的时间代价也是很高了。如果这个功能模块还要增加功能,就要把这些功能到不同的功能调用模块,然后再用一个模块对它们进行调用。分而治之的原则是一个功能一个模块,类似的功能用一个功能集中管理调用,不同的功能模块划分成部分的部分。通过这种,高内聚,松散耦合的思想来实现高度抽象,使得建立超大规模系统成为可能。Led_Driver 模块:Led_Driver 模块是整个LED 流水灯的,但却相对来说简单得多。因为它
26、已经实现了高度抽象,仅仅只需要一个设定时间和开始信17号就可以工作。Led_Driver_Control 用来协调外部的时间到内部闪烁周期的转换,和内部闪烁一次结束信号的输出。就像在内部和外部之间建立了一道栅栏,完成内外之间的。对外把内部的隐藏起来,使得外部只看得到接口,看不到内部是怎么工作。这样做的好处就是当外部需要挂接到其他器上是只需要修改这道栅栏就可以了,内部不用做很大的调整。如果没有这层栅栏,内部和外部混在一起,外部的变化会可能会导致要重建整个内部来适应变化。这种思想类似于数据库的三级模式与两级和的原理。建立这层栅栏来实现是很有价值的。接下来的是定时器模块和 LED 接口模块,都是很简
27、单的 always 实现的没有用到步骤的概念。定时器是时序逻辑电路的基础,产确的定时是上层能够正常工作的保证。这是对另一个定时器计数的定时器。这里需要注意的是开始信号的位置以及对于的 else 条件中表18。if 中的 else 条件和 case 语句中的 default 条件是容易出错的,所以要认真考虑。以及对什么信号计数(MSIn)?什么时候清零计数?这里清零的条件是当(setMSTimes-1)个 MSIn 到来时,清零计数器。这里容易出错的是数的个数,从 0 到 setMSTimes,数 MSIn 共 setMSTimes+1 次。这里容易1(off by one)的错误。可以通过数一个小
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 员工个人总结怎么写2021
- 指导培养教师工作计划
- 2022年高中工作计划
- 2025年柔性自动化装备项目合作计划书
- 自行车车形容2篇
- 2025年耐高温滤料合作协议书
- 入职竞业协议书(2篇)
- 2025年高纯石英纤维正交三向织物项目发展计划
- 2025年青霉素类抗菌药物合作协议书
- 地下车库租赁协议
- 三年级上册数学课件北师大版专项复习 操作题、图形题专项
- 黄土高原水土流失说课
- 河北省石家庄市药品零售药店企业药房名单目录
- 《来自地球的力》名师教案
- 食堂亏损分析报告范文5篇
- 锚杆锚索钻机操作规程
- 《录音技术与艺术》课程教学大纲
- 部编版七年级语文上下册教材解读分析精编ppt
- InternationalSettlementsLecture3InternationalClearingSystems
- (完整版)景观园林工程施工规范和技术要求
- (完整版)六年级转述句练习题
评论
0/150
提交评论