【连载】【FPGA黑金开发板】Verilog HDL那些事儿低级建模 仿顺序操作(十二)

声明:本文为原创作品,版权归akuei2及黑金动力社区(http://www.heijin.org)共同所有,如需转载,请注明出处http://www.cnblogs.com/kingst/

2

第四章 低级建模 仿顺序操作

4.1 基本思路

C语言的编程,在理解上我们可以看成“顺序操作”。就如吃饭一系列步骤一样,张口,将饭入口,咬碎,吞下。Verilog HDL语言,要执行如同“顺序操作”,实际上是不可能的,但是我们可以模范“顺序操作”的执行模式,这亦是称为“仿顺序操作”。基本上要实现“仿顺序操作”,如果没有结构性的建模,结果是很糟糕。但是“低级建模”是有准则,有结构,有组织的建模方法,在实现“仿顺序操作”上,显然“低级建模”是存在优势的。

我们以 SOS信号实验 来说明“仿顺序操作”的基本思路。如果以C语言来实现 SOS信号实验,手段会是如下:

//建立S函数

void S_Function( void ) { ... }

//建立 O函数

void O_Function( void ) { ... }

//建立 SOS函数

void SOS_Function( void )

{

S_Function();

O_Function();

S_Function();

}

//调用 SOS函数

int main()

{

SOS_Function();

return 0;

}

先建立最基本的两个函数 S_Function() 和 O_Function , 然后再建立一个函数 SOS_Fucntion() 进行顺序调用两个基本函数。最后main()可以直接调用 SOS_Function() 。由于C语言是高级语言,在底层执行的“调用函数”和“函数返回”都是隐藏的。

那么要使用Verilog HDL语言来实现“顺序操作”该如何呢?

实验十一 :SOS信号之三

首先我们先要建立功能拟似 S函数 和 O函数的功能模块。

s_module.v

clip_image002

clip_image004

clip_image005

第15~45行是1ms的计数器。第17行定义了 1ms的常量,21~31行是1ms的定时器,然而 isCount 标志寄存器使能着该定时器(28|30行)。35~43行是计数器,计数的结果有rTimes寄存器控制(40行)。

47~51行是各个寄存器的声明。i寄存器控制着执行步骤(47行),rPin_Out 寄存器用于驱动 Pin_Out 输出(48行),然而 isDone 是用于驱动 Done_Sig 的输出(51行)。

(注意rTimes的复位值是除了0的随意值, 这一点请留意)第62行到79行是s_module.v的核心部分,第62行是“使能”的功能,当 Start_Sig 拉高以后 s_module.v 才能工作。

65~69行是“延时写法”,i等于 0 , 2, 4 时就设置 rPin_Out寄存器为逻辑1,然而延迟的时间是100ms(67行)。相反的,当i等于1, 3, 5 的时候就设置 rPin_Out寄存器为逻辑0,延迟的时间是50ms(71行)。

上述写法的思路如下:

当 i 等于 0 时,由于if条件未成立(66行),那么isCount就是设置为1,同时 rTimes也会被赋予100。当 isCount 设置为1时,定时器就会开始计数并且产生定时(28行),

计数器(35~43行)每1ms的间隔都会计数一次(42行),直到计数与rTimes的值一样

(40行),就会被回复与0值。在同一个瞬间,if条件成立,并且将 isCount设置为逻辑0,同时间将 rPin_Out 寄存器拉高,最后 i 寄存器递增来表示下一个步骤(66行)。

最后在73~77行产生一个高脉冲的Done_Sig。

o_module.v

clip_image007

clip_image009

clip_image010

基本上和 s_module.v 大同小异,不同的只是延迟的时间比较长(67行)。因为我们知道 o 的摩斯密码比 s的摩斯密码比较长。

sos_control_module

clip_image012

接下来我们要建立一个控制 s_module.v 和 o_module.v 执行次序的控制模块 sos_control_module.v 。

clip_image014

clip_image015

在20~21行定义了 isS 和 isO 的标志寄存器。 isS用于驱动 S_Start_Sig (57行), isO用于驱动 O_Start_Sig (58行)。

在32~53行是核心部分。32行是“使能”,只要 Start_Sig 不拉高,该模块就不会工作。

我们知道 “SOS 的产生次序”是先产生S ,产生O ,然后再产生S,然而35~45行的“仿顺序操作”便是如此。

假设一个情况:

当 i 等于 0时,由于if条件不满足(36行),然后 isS寄存器会被设置为1(37行)。然后 sos_module.v 就会等待 S_Done_Sig 的高脉冲反馈。当 S_Done_Sig 反馈高脉冲,也就是说 s_module.v 已经完成操作,这也表示 if条件满足了(36行)。然后 isS标志寄存器会被拉低,i寄存器会递增以表示下一步操作。

上述的情况会一直执行,直到42~43行。最后 Done_Sig会产生一个高脉冲。

两仪性和多义性的问题:

clip_image017

在组合 s_module.v , o_module.v 和 sos_control_module.v 之前,存在着两仪性或者多义性的问题。从图上可以知道 s_module.v 和 o_module.v 的Pin_Out输出是共享着蜂鸣器资源,但是有一个事实我们必须了解,就是“一个时间仅有一个输出”这个道理。为了有效协调Pin_Out 的输出,就添加“选择器”来控制输出。

sos_module.v

clip_image019

上图是组合模块 sos_module.v 。对模块的调用有 Start_Sig 和 Done_Sig 信号,然而,在输出的一端,添加了“选择器”来协调输出。

clip_image021

clip_image023

第15 到72行基本上和“图形”一样。实例化s_module.v,o_module.v和 sos_control_module.v 然后连线。

在62~72行是“选择器”, Pin_Out 寄存器是用来驱动 Pin_Out 输出(65行)。在67行表示“任何时候都会变化”。然而 S_Start_Sig 和 O_Start_Sig 信号,作为选择器的辨别信号。当S_Start_Sig 拉高时,驱动Pin_Out 输出就是 S_Pin_Out 连线,当 O_Start_Sig 拉高的时候,是O_Pin_Out 驱动着 Pin_Out输出。

但是有一点必须注意,就是 第70行,每一个选择器都需要一个“默认状态”,如果没有添加这一行,会出现很多编译警告。

实验十一说明:

这个实验主要是一个简单的 “仿顺序操作”实例。上述的建模完全是模范“顺序操作”-c语言,同样是设计一个SOS实验。

“仿顺序操作”的建模都有基本的“建模构造”,就是所有模块都拥有“Start_Sig”和“Done_Sig”。“Start_Sig”如同C语言中的调用指令,“Done_Sig”如同 C语言的返回指令。这两个信号的存在就是为了方便的调用模块。

最后一点就是“选择器”,选择器在组合模块里面的存在真的很需要,因为“仿顺序操作”的模块,往往对“输出资源”都有“两仪性”或者“多义性”的问题。然而“选择器”充分的使用“xx_Start_Sig”信号来达到“协调控制”。所以说“组合模块”,不仅是“组合”的工作而已。

有关“命名”的问题,虽然“命名”是没有任何强制性,但是笔者非常“建议”将“命名”的习惯倾向“理解”,而不是“方便编写”。如果“命名”的结果,容易理解而且长度短而方便调用,那是再好不过。不过往往“两全难齐美”,尽可以的话“命名”更应该倾向“理解”。

完整的扩展图:

clip_image025

实验十一结论:

“仿顺序操作”的写法或者建模,估计很多读者都很不习惯?如:“上一层模块对下一层模块的调用在时序上的问题?”

假设sos_control_module.v 向 s_modue.v 调用。在开始时 sos_control_module.v 使能 s_module.v,当 s_module.v 完成操作就会产生一个完成信号的高脉冲。

但是完成信号的产生需要使用了两个时间。在第一个时间的时候s_module.v拉高了 xx_Done_Sig 信号,在这一个瞬间 sos_control_module.v 检测到高脉冲,然后它会“不使能”s_module.v,但是该操作必须在下个时间执行才有效。在第二个时间的时候xx_Done_Sig已经被拉低,并且对 i 赋值为0,同样在这一个瞬间,sos_control_module.v 对 s_module 的不使能已经执行,但是对s_module.v 的操作来说已经结束,基本上没有任何影响。

基本上,有关“仿顺序操作”的问题点笔者都是经过多次的调式和修改了。如果读者要求更详细的信息,笔者很建议读者温习“Verilog HDL建模技巧 - 低级建模 · 仿顺序操作(思路篇)”,这一本笔记。这一本笔记就是当时笔者在进行调试和修改“仿顺序操作”的时候,完成的一本笔记,故记录比较详细。

“仿顺序操作”的建模方法,可能会使初次触碰的读者比较不习惯,希望读者可以耐性去思考和理解。实际上“仿顺序操作”的理解很简单,因为“低级建模”已经充分的简化建模的难度,如果读者在第二章和第三章的基础实验掌握好的话,估计是没有什么困难而言。

实验十一演示:

这个演示就对实验十一完成的sos_module.v调用吧。

sos_module_demo.v

clip_image027

在13行定义了 isStart 标志寄存器,是用于是使能 sos_module.v(29行)。一开始的时候isStart 被复位为1, 然后 sos_module.v 就被使能然后开始工作(17行)。直到sos_module.v 完成操作,就会经 Done_Sig 返回一个高脉冲。当检测到该脉冲(18行),isStart就会被设置为逻辑0,最后 sos_module.v 就会保持沉默。

换一句说就是,一开始 sos_module.v 会操作一次,然后操作完毕后就停止操作了。

实验十一演示说明:

在这个演示里充分的表示了Start_Sig和Done_Sig的对模块调用的方便。

实验十一演示结论:

实验十一演示,演示了对已完成的“仿顺序操作”模块调用。

总结:

在这一章,笔者使用了一个简单的实验表现了“仿顺序操作”建模的几个重点。

第一,“仿顺序操作”的基本思路和基本建模方法。

第二,Start_Sig 和 Done_Sig 的重要性

第三,“仿顺序操作”存在的两仪性或者多义性问题。

第四,组合模块中“选择器”的作用。

关于“低级建模”本身的特点,当它融入“仿顺序操作”的建模同时。在建模的“思路”上,可以和“顺序操作编程思路”一样,换句话说“在C语言设计所想的”,也可以使用在“Verilog HDL 语言上的建模”。

当然,读者你也可以把它看成是一种自低向上的建模方法,但是别忘了“低级建模”讲求的是更有结构性和理解性的建模技巧。因为“仿顺序操作”充其量只不过是模仿“顺序操作”的建模方法而已,而不是完全的将“设计C语言的习惯”建立在 Verilog HDL 语言的建模上。C语言和Verilog HDL语言是两个世界的语言,完全行不通。如果没有强力的“代码风格”,对“仿顺序操作”的建模基本上是一种噩梦。所以说,在某种程度上“低级建模”可以很好的胜任这项工作。

在“低级建模”的准则上“一个模块一个功能”。我们可以假设s_module.v含有 S_Function(), o_module.v 含有 O_Function()。此外需要“控制执行次序”,sos_control_module.v“控制模块”含有“控制执行次序”。最后关于组合模块和解决两仪性的问题,这些都是组合模块的功能。完成后的组合模块 sos_module.v 可以看成是 SOS_Function() 。读者尝试问问自己,在这一系列的建模过程中,这个“准则”存在的意义?在没有遵守“低级建模”的准则之下,“仿顺序操作”的建模时一件苦差事儿。

最后,还有一点就是关于“仿顺序操作”标志性的模块结构(Start_Sig和Done_Sig)。在“顺序操作”的角度上,它们好比是“调用指令”和“返回指令”,但是“仿顺序操作”的存在才不是为了建立“微处理器”来融入“C语言的设计习惯”。Verilog HDL语言毕竟是 Verilog HDL语言,我们要的只是“不失去Verilog HDL语言本身的特性以外,还要模范顺序操作”而已。对于“Start_Sig”和“Done_Sig”的使用,是“仿顺序操作”建模的一大特色,或者说是必需的。

原文地址:https://www.cnblogs.com/kingst/p/1834247.html