0.10 单文件主义
单文件主义对于新手来说, 某个程度上它是一个“伟大的主义” 但是又有很多人会受限这个“伟大的主义”。单文件主义就是,所有内容的设计都是在一个模块之内完成,这一点,有点像 C 语言中 main 那样,所有动作都在 main()函数中完成。单文件主义是新手都要经过的, 当游走一段时间以后, 慢慢的我们会发现这个主义的局限性。 我们想要越过“它”,但是又不知道要如何往哪个方向 … 这就是很多新手都会遇见的“瓶颈”。
在这里, 笔者告诉读者们, 能多快就有多快远离单文件主义。 单文件主义基本上已是远离 Verilog HDL 语言的本质了,这是一个很危险的陷阱,如果读者不小心陷入,在接下来的学习路上是没有任何帮助的。 这是一个事实, 而不是笔记自身的想法。 会养成单文件主义,多半的原因还是来源于参考书,这真的使笔者很无语 …..
笔者来说说为什么单文件主义远离了 Verilog HDL 语言的本质呢? Verilog HDL 语言, 本质上是并行而且又有“面向对象” 的味道。 但是这“面向对象” 的概念和 C++语言中的概念有所不同, 然而它更接近现实中的“管理系统”(详解请看建模篇)。 读者尝试想象,
有没有可能一个系统的操作, 没有部门, 没有团队, 没有小组?对, 就是不可能。 单文件主义恰恰好就是违反了这个简单的道理。
普通人类在理解上, 都喜欢把东西分类, 然后方便于管理。 读者可以想象一个没有分类的系统, 内容究竟到底有多乱吗?是一塌糊涂的乱! 所以单文件主义的建模, 最大的缺陷就是一个字“乱”,内容真的很乱。如果 Verilog HDL 语言是顺序语言的话,结果还不至于那样糟糕,相反的, Verilog HDL 语言却是并行性质的语言 ….
上文中所说的“没有分类” 的烂漫约会,如果也“没有顺序操作” 的支持 … 会是一个
非常糟糕的情形。 因为这个系统操作(约会过程) 没有结构的支持 , 这个情形也反映出
了单文件主义的致命缺点。笔者有一句很经典的话: “解读能力差的模块是最糟糕的”,
这一句话完全迎合单文件主义下所建立的模块。
0.11 Verilog HDL 语言结构简介

在前面,笔者已经说过 Verilog HDL 语言从出生以来,它的结构是非常自由,可以说自由到没有结构。 所以学习 Verilog HDL 语言第一步就是要学会建立结构, 建立结构用另一句话说就是学习建模。同样,笔者也说过 Verilog HDL 语言我们需要自定义自己的结构,在这里就拿笔者最爱的“低级建模” 来做一些简单的扫盲。
低级建模被网友称为“自底向上” 的设计方法,其实“自底向上” 还是“自顶向下” 都无所谓啦,最重要就是建模的思路。
低级建模的基本单元有:功能模块,控制模块,组合模块。
� 功能模块的内容包含了最基本的动作。
� 控制模块的内容包含了动作的控制步骤。
� 组合模块的内容包含了所有功能模块和控制模块之间的组合。
建模层次有:基础(模块)建模,仿顺序操作建模,接口建模,系统建模。
� 基础(模块)建模的内容包含了最小功能的模块。
� 仿顺序操作建模,这一个比较特别,主要是模仿了 C 语言中的函数。
� 接口建模的内容包含了一个已经封装完成的模块。
� 系统建模的内容包含了一个特定功能的模块。
举个例子,就拿串口来作个比方:

在串口硬件模块(串口系统建模) 里, 分类了发送接口和接受接口。 发送发送接口包含了 FIFO 模块, 波特率产生模块和串口发送控制模块。 串口接收串口包含了 FIFO 模块,波特率产生模块, 串口接收控制模块。 串口发送模块是组合了波特率产生模块和串口发送控制模块,串口接收模块是组合了波特率产生模块和串口接收控制模块。
串口系统建模之间的模块基本单元分类:

在这里笔者只是简介了笔者最爱的“低级建模” 的结构分类而已, 事实上每一个基本单元和每一个层次都有严谨的定义。建模是 Verilog HDL 语言的结构,越庞大的设计建模所带来的后期影响是读者/笔者远远都猜想不到的。 故建模对于 Verilog HDL 语言来说是非常重要的基础。
好了笔者就不多话了, 有关“低级建模” 的笔记笔者已经老早准备好了。 笔者在这里只是简单的表述一下 Verilog HDL 语言结构的概念而已, 然而笔者需要再强调一下: Verilog HDL 语言的结构是自由的,然而笔者的“低级建模” 是笔者自定义的结构而已。当然读者也可以建立自己的结构。

0.12 Verilog HDL 语言使用规则(方法)简介
“一种设计,超过 10 个编辑风格” 这一句话不仅表示了一种设计有多种结构(很多设计都是单文件主义, 或者不存在结构), 而且也代表了设计中所使用的不同规则(方法)。
但是不是所有设计都有固定的使用方法,这一点读者可以诚实的问自己 : “自己的设计是否有一套的使用方法呢? ” 好吧~笔者就不故意为难了。
Verilog HDL 语言是一个非常自由的语言, 故被使用最多的方法就是“自由方法”(没有-方法) 呵呵~这是事实。 当自定义自己的方法的时候, 读者要问自己, 自己所使用的方法是“注重什么”。换做笔者,笔者注重“模块解读能力” 又或者说有一套方法可以提高模块的表达能力。故 Verilog HDL 语言的结构就是其中一环了,但是这还不够,当我们再开始设计的时候,我们还需要一套的“用法模板”。
在这里笔者向读者们推荐吧“基于仿顺序操作” 的“用法模板”(到目前为止,笔者还没有给它固定的命名,如果读者有什么好想法就告诉笔者吧 )。仿顺序操作是什么?就是利用 Verilog HDL 语言自身的特质去模仿一些顺序语言如 C 语言, 故称为“仿顺序操作”。
仿顺序操作的思想是非常有潜力的, 但是在建模篇里笔者仅是以“步骤” 作为这个用法的入门认识。 当读者对建模和时序有一定的认识以后, 读者会进一步发现这个思想非常的“变态”(潜力的另一极端用词)。 作为入门, 仿顺序操作用法都是以“步骤” 作为基本单位,这个概念和 C 语言的步骤没什么两样。
“步骤” 也可以用“简易状态机” 来理解, 但是“状态机” 的概念太死了, 笔者不怎么喜欢,还是使用“步骤” 来称呼比较情切:

always @ ( posedge CLK or negedge RSTn )if( !RSTn )begini <= 4'd0;....endelsecase( i )0:begin .... i <= i + 1'b1; end1:......endcase

i 代表了“步骤的指向” 至于 case … endcase 之间是一个完成工作的经过。 笔者举个简
单的实例,就以流水灯来说话吧:

always @ ( posedge CLK or negedge RSTn )if( !RSTn )begini <= 4'd0;rLED <= 4'b0000;endelsecase( i )0:begin rLED <= 4'b0001; i <=i + 1'b1; end1:if( Timer == T10MS ) i <= i + 1'b1; end2:begin rLED <= 4'b0010; i <=i + 1'b1; end3:if( Timer == T10MS ) i <= i + 1'b1; end4:begin rLED <= 4'b0100; i <=i + 1'b1; end5:if( Timer == T10MS ) i <= i + 1'b1; end6:begin rLED <= 4'b1000; i <=i + 1'b1; end7:if( Timer == T10MS ) i <= 4'd0; endendcase

在 case … endcase 之间,步骤 i 等于 0,2,4,6 的时候是更新 LED(流水操作),步骤 i
等于 1,3,5,7 的时候是延迟 10ms。

always @ ( posedge CLK or negedge RSTn )if( !RSTn )begini <= 4'd0;rLED <= 4'b0000;endelsecase( i )0,2,4,6:begin rLED <= { rLED[0], rLED[3:1] }; i <=i + 1'b1; end1,3,5,7:if( Timer == T10MS ) i <= i + 1'b1; end8:begin i <= 4'd0; endendcase

此外, 还可以把步骤 i 当成简单的循环。 上面一段代码表达了, 当步骤 i 等于 0,2,4,6 的
时候就更新 rLED,。反之,当步骤 i 等于 1,3,5,7 的时候就延迟 10ms。在步骤 i 等于 8
的时候是步骤返回操作。

always @ ( posedge CLK or negedge RSTn )if( !RSTn )begini <= 4'd0;rLED <= 4'b0001;endelsecase( i )0:begin rLED <= {rLED[0] , rLED[3:1]} ; i <=i + 1'b1; end1if( Timer == T10MS ) i <= i - 1'b1; endendcase

又或者更进一步的压缩步骤,使得代码更直接而且更节省资源。在上面一段代码当中,只有两个步骤,亦即步骤 0 和 1。步骤 0 是更新 rLED,步骤 1 是延迟 10ms,然而这两个步骤之间交互交替使而产生流水灯效果。
当然,步骤 i 的用法不仅而已,如果把“时序” 的概念引入的话:

always @ ( posedge CLK or negedge RSTn )if( !RSTn )begini <= 4'd0;Mper <= 8'd0;Mcand <= 8'd0;Sum <= 8'd0;endelsecase( i )0:begin Mper <= Mper_Sig; Mcand <= Mcand_Sig ; Sum <= 8'd0i <=i + 1'b1; end1if( Mcand == 0 ) i <= i + 1'b1;else Sum <= Sum + Mper; Mcand <= Mcand - 1'b1; end......endcase

以上一段代码是简单的乘法运算, Mper 是乘数的暂存器, Mcand 是被乘数的暂存器,Sum 是累加空间。当步骤 i 等于 0 的时候初始化相关的寄存器,在步骤 i 等于 1 的时候执行乘法操作 … 在这里读者也可这样说: “在 T0 的时候初始化相关的寄存器, 在接下来的时钟执行乘法操作 … ”
总结之下,这个用法可以伸缩的范围非常之大。除外,它所带来的好处也非常之多:
� 提供了 Verilog HDL 语言顺序操作的支持。
� 提高了模块的表达能力。
� 提供了仿顺序操作· 建模的结构基础。。
但是它也带来一些限制:
� 不推荐嵌套 case … endcase 和 if。
� 该用法不推荐出现过多在同一个模块中。
这些限制是笔者标记下来的, 这之间和“低级建模” 有多少关系。 当然, 如果读者不遵
守的话也没有问题。 显然这个用法也不是万能的, 尤其是一些紧密的 RTL 级建模, 如:
VGA 驱动,它就显得无用武之地了。事实上这个用法到目前为止,笔者还在不停的研
究当中,越深入学习它,就越发现它的潜能很深 …

好了,之一章节笔者就介绍到那么多,自定义使用规则(用法)对于 Verilog HDL 语言
来说是非常自由但也非常重要,没有固定的使用方法,模块的解读能力会大打折扣。 这
些简单的道理,也只有当读者不停深入学习 Verilog HDL 语言的时候自然就会明白。
0.13 认识 RTL 级设计(建模)
笔者差不多也要结束这一章 Verilog HDL 语言的扫盲文了,在结束之前笔者或多或少都有责任加强读者们对 RTL 级设计(建模) 的认识。 在前面, 笔者曾经说过 RTL 级建模最受注意的特征就是“时钟” 亦即 CLK 信号, 要明白 CLK 的定义笔者就要乘坐时光机回到读学院的时候。
用凡人的话来说 CLK 代表了一个模块的心跳节拍,这个心跳节拍提供模块可以消耗的动力。但是 CLK 信号真正可以被模块所用到不是它的高电平又或者低电平,而是上升沿(低电平到高电平的变化)和下降沿(高电平到低电平的变化)。

always @ ( posedge CLK )
......

在上面一段代码中的 always @ ( posedge CLK ) 表达了 always @ () 以下的内容在每一个 CLK 的上升沿发成操作:

假设有一串长长而且连续的 CLK 就会产生最基本的时序图(没有 CLK 基本上是没有时序图),如图 0.13a 所示。
对于 RTL 级设计来说 CLK 是模块的心跳, 没有心跳模块就不能活动, 没有心跳就没有时序图。 换另一句话说, 构成 RTL 级最基本的设计需要“寄存器” 为最小的建模单位,然后再加上模块可以活动的 CLK 信号。

always @ ( posedge CLK )Counter1 <= Counter1 + 1'b1;
always @ ( posedge CLK1/2 )Counter2 <= Counter2 + 1'b1;

上面有一段代码是 Counter1 + CLK 和 Counter2 + CLK1/2 促成最简单的 RTL 级设计。
Counter1 在每一个 CLK 时钟内递增,然而 Counter2 在每一个 CLK1/2 时钟内递增。到目前为止 Counter1 和 Counter2 还是独立关系。

图 0.13b 是 Counter1 + CLK 和 Counter2 + CLK1/2 产生的时序图。 在这里 Counter2 所使用的频率是 Counter1 的一半。 在每一个 CLK 的上升沿 Counter1 都递增, 然而在每一个 CLK1/2 的上升沿 Counter2 都递增。

always @ ( posedge CLK )
Counter1 <= Counter1 + 1'b1;
always @ ( posedge CLK1/2 )
Counter2 <= Counter1;

假设笔者把 Counter1 和 Counter2 联系起“关系” 的话,如上面的一段代码所述。又会产生怎样的时序图呢?

图 0.13c 是 Counter1 和 Counter2 建立关系以后多产生的时序图。 在 CLK 是 T0 的时候,CLK_1/2 也是在 T0。 由于在 T0 之前 Counter1 什么也没有, 所以 Counter 什么也读不到(一般上 0 为复位值)。在 CLK_1/2 是 T1, Counter2 尝试读取 Counter1 的“过去值”,结果 Counter2 读到值 2,所以在 CLK_1/2 的 T1, Counter2 的“未来值” 是 2。类似的事情也发生在 CLK_1/2 的 T2, T3 和 T4 的时候。
在这里读者先不用管“过去值” 和“未来值” 的定义,这是笔者在时序篇里的专用词。读者需要焦距的是,每一次 Counter1 成功递增是发生在 CLK 的上升沿,然而 Counter2每一次成功读取 Counter1 的值都是发生在 CLK_1/2 的上升沿。换句话说, CLK 的上升沿是触发 Counter1 递增, CLK_1/2 的上升沿是触发 Counter 读取 Counter1 的过去值。以上的内容就是 RTL 级设计最基本的思想。
至于组合逻辑级设计呢?在 Verilog HDL 语言中,如果我们把 Verilog HDL 语言看成是理想的语言,那么组合逻辑就可以直接无视被 CLK 的影响,因为组合逻辑取得的是即时的结果。
举个简单的组合逻辑级的设计:

always @ ( * )
Sum = A + B + C

这是一个由组合逻辑所组成的简单 3 路加法器。

上面的图标表示了3路加法器求得的即时结果 … 在这里CLK信号对于它来说已经再也不重要了。
假设读者不把 Verilog HDL 语言看成是“理想” 的话, 组合逻辑会产生“物理” 上的延迟。但是笔者还是建议读者把 Verilog HDL 语言看成是一个理想的工具为好。换另一个角度来看的话, C 语言和 Verilog HDL 语言都是工具, 难道 C 语言会产生“物理” 上的延迟吗?此外这样的想法对于 Verilog HDL 语言的设计会带来很大的好处,尤其是看懂
波形图(时序图)哪一环,效果会更加明显。

0.14 过渡中,沉住气!朋友!
到了这一章节笔者不知不觉又寂寞了,基本上有关 Verilog HDL 语言的扫盲文需要告一段落了。 学习 Verilog HDL 语言不像学习一些高级语言, 对于高级语言来说它们已经是完成品了,其外它们还有很多被隐藏的指令,这些好处无疑是减轻了学习者的负担。 相反的 Verilog HDL 语言既是完成品,既不是完成品,就是因为它太自由了 … 所以往往会让学习者感到疑惑,很疲惫和浮躁(我不学了!)。
学习 Verilog HDL 语言需要一段过渡期的,快则半年,普通则 1~2 年,慢则很多年。即使经过了过渡期这也不表示已经掌握 Verilog HDL 语言了。 所以呀朋友, 希望你们可以沉住气, “欲速则不达” 这是老祖先的智慧,它非常适合用在学习 Verilog HDL 语言的路上。 Verilog HDL 语言可以延长到的范围完完全全超过参考书的内容,对于笔者来说也看不到尽头。
那些有学习单片机经验的朋友, 最好不让学习单片机的思想主宰了你。 就如笔者在前面所说的那样, Verilog HDL 语言既不是顺序语言而且也非常的自由, Verilog HDL 语言不像 C 语言那样有丰富的库支持, 甚至库的概念也不适合用在它身上。 但是即使它们是两个世界的居民, 但是偶尔 Verilog HDL 语言可以在很多地方向 C 语言借签。 相反的 C 语
言就不能向 Verilog HDL 语言借签了。
此外 Verilog HDL 语言还有两大阵列,就是综合语言和验证语言,这更是给学习者雪上加霜。太多的学习者会困惑在这两种语言的中间,所谓的困惑是思路的困惑。在这里,笔者建议先无视验证语言, 先把综合语言学好(综合语言也没有什么好学的, 就如在前面章节笔者所举例的那样, 关键字和操作符少得可怜), 最重要还是掌握结构(建模)和使用规则(用法)。它们就像挥动着倚天剑和屠龙宝刀的招式,没有了这些招式倚天剑和屠龙宝刀不过是一件单纯的金属而已。 至于验证语言, 在未来有需要的时候再学也不迟。
当阅读他人模块的时候, 不要过于转牛角尖的看懂他人的思路, 只要明白其中的内容就好。最重要还是如何使用自己的结构和方法去建立他人的思路,从中读者会学得更多。这一点是绝对的事实。 就算现在的读者没有能力建立自己的结构也没有关系, 来日方长读者有的就是时间。 如果读者很钟爱笔者所建立的结构和方法, 笔者很乐意也很荣欣被应用(这也是笔者写笔记的初衷)。
最后的最后还是那么一句话,沉住气朋友,掌握 Verilog HDL 语言需要的不只是技术而已, 最重要是那颗安静的心, 安静的心会带读者乘风破浪, 一方通行。 此外记录笔记的习惯更为重要, 向自己学习比起向他人学习更有学习的价值。 如果有时间的话, 就坐下来研究研究 Verilog HDL 语言这个怪家伙吧。

总结:

这一章终于到总结了, 从第一章节到最后一个章节, 从最简单的问题:“什么是 HDL 语言? ”, 直到一些困惑度极高的问题: “Verilog HDL 语言的结构? ”,“Verilog HDL 语言的使用规则(用法)? ”,甚至学习 Verilog HDL 语言该保持的心情,笔者也不放过。
不过这短短的二十几页, 应该足够达到扫盲的作用了吧?虽然这一章的扫盲文, 效果不足覆盖所有言内容, 但是只要有效的开了一个入门的口子, 对于接下来的路就简单许多。
人们常说: “入门,入门”,学习要从入门开始,如果门都没有,又要如何进入呢?
笔者学习 Verilog HDL 语言也有一段时间了,对于入门的心得多少都有。所以笔者觉得比起如何入门,先知道个大概来得更重要。有一句笑话说过 : “既然你要入门,你至少需要知道,你要进入那一扇门的形状?圆的还是方的?要是不清楚,就算有门在哪儿,你也进不了门, 结果“进入门的门都没有” …… ” 所以说, 扫盲的作用是把目标建立出大概的轮廓 … 不然真的进入门的门都没有~啊哈哈哈!好了好了,笔者也不多话了, 是时候画上句号了。

黑金xlinix FPGA学习笔记(一)verilogHDL扫盲文-(2)相关推荐

  1. FPGA学习笔记之Altera FPGA使用JIC文件配置固化教程

    FPGA学习笔记之Altera FPGA使用JIC文件配置固化教程 很多做过单片机的朋友都知 道,我们在对MCU烧写完程序固件后,那么该程序固件就存储在了该MCU内部.即使MCU断电了再重新上电,程序 ...

  2. FPGA学习笔记(七): DSB调制解调的仿真

    笔记七是DSB调制解调的仿真实现. DSB调制解调的实现原理:首先使用DDS产生低频正弦波信号作为调制信号,再用DDS产生高频信号作为载波信号,然后使用乘法器将两者相乘产生DSB信号,DSB信号与载波 ...

  3. FPGA学习笔记(1)简单的时序逻辑电路——流水灯

    FPGA学习笔记(1)简单的时序逻辑电路--流水灯 编程语言为Verilog HDL 原理 (1)设计一个计数器,使开发板上的4个LED状态每500ms翻转一次.开发板上的晶振输出时钟频率为50MHz ...

  4. FPGA学习笔记(八)同步/异步信号的打拍分析处理及亚稳态分析

    系列文章目录 一.FPGA学习笔记(一)入门背景.软件及时钟约束 二.FPGA学习笔记(二)Verilog语法初步学习(语法篇1) 三.FPGA学习笔记(三) 流水灯入门FPGA设计流程 四.FPGA ...

  5. FPGA学习笔记_ROM核调用与调试

    FPGA学习笔记 ROM核调用与调试 1. ROM存储器IP核的使用 2. 创建.mif文件 3. In system memory content editor内存查看工具的使用 4. Signal ...

  6. FPGA 学习笔记:Vivado 2020.2 MicroBlaze MIG 测试 DDR3 篇尾

    FPGA 学习笔记:Vivado 2020.2 MicroBlaze MIG 测试 DDR3 篇一 FPGA 学习笔记:Vivado 2020.2 MicroBlaze MIG 测试 DDR3 篇二 ...

  7. FPGA学习笔记(十二)IP核之FIFO的学习总结

    系列文章目录 一.FPGA学习笔记(一)入门背景.软件及时钟约束 二.FPGA学习笔记(二)Verilog语法初步学习(语法篇1) 三.FPGA学习笔记(三) 流水灯入门FPGA设计流程 四.FPGA ...

  8. FPGA学习笔记——分频电路设计

    FPGA学习笔记--分频电路设计 发布时间:2015-10-3023:29:52 分频就是用一个时钟信号通过一定的电路结构变成不同频率的时钟信号,这里介绍一下整数分频电路的设计方法.整数分频电路有偶数 ...

  9. 小梅哥FPGA学习笔记

    小梅哥FPGA学习笔记 一.38译码器 功能: 译码器其任一时刻的稳态输出,仅仅与该时刻的输入变量的取值有关,它是一种多输入多输出的组合逻辑电路,负责将二进制代码翻译为特定的对象(如逻辑电平等).38 ...

  10. FPGA学习笔记_UART串口协议_串口接收端设计

    FPGA学习笔记 1. UART串口协议以及串口接收端设计 1 原理图 2 Verilog 代码 3 Modelsim仿真 4. FPGA板级验证 1.1 串口协议接收端设计 目标:FPGA接收其他设 ...

最新文章

  1. Clipboard.js:不用Flash实现剪贴板功能的轻量级JavaScript库
  2. TFS2010迁移后Web工作项访问提示:error HRESULT E_FAIL has been returned from a call to a COM component....
  3. 啃碎并发(二):Java线程的生命周期
  4. 自学python推荐书-学习python求推荐一波书籍?
  5. 管理感悟:独当一面,很难
  6. ARM架构及ARM指令集、Thumb指令集你了解多少?
  7. Unity3D项目五:简单打飞碟
  8. 关于a标签 中特有的tilte属性 和 字符串文字换行
  9. idea一个工作空间打开多个项目
  10. 清除计算机策略,怎么删除组策略
  11. 外汇EA黄金外汇避险抗膨胀
  12. 不忘初心,能偷懒就偷懒:C#操作Word文件
  13. 豆瓣电影评分(微信小程序)——Day1
  14. skynet 游戏服务器探索(1)--熟悉skynet(网络)
  15. 业务痛点、个人成长以及未来发展的一些思考
  16. Dubbo2.6.5入门——简单的HelloWorld
  17. 三重邪骨手机版怎么登录服务器未响应,三重邪骨锁血版
  18. 模块电路选型(1)----电源模块
  19. javascript表格信息增添与删除
  20. 计算机技能大赛主持人串词,专业技能大赛主持人串词

热门文章

  1. 二代证|港澳台居民居住证|电子护照阅读器 读卡器MEPR200+的应用与二次开发攻略
  2. 中国剩余定理(CRT)
  3. 基于RT1052 Aworks 测试PXP图像混合功能(十三)
  4. 红米note4 android8.0,红米Note 4首个安卓8.0刷机包放出,开发者:可日常使用
  5. android 实现果冻动画效果,Android高仿path小球刷新效果,类似IOS果冻效果
  6. 字节跳动Data数据平台/数据分析招聘
  7. 华硕无线网卡测试软件,高端便携无线网卡来了 华硕USB-AC68首测
  8. 7654:等差数列末项计算
  9. Prematurely reached end of stream
  10. 从菜鸟到架构师(三)