在2.1 章理解了 "顺序操作" 和 “并行操作”的区别之后,这一章我们要讨论并且习惯 “并行操作” 的思考。
上图是一个组合模块,里边包含了两个功能模块。一是对闪耀灯控制的功能模块,二是对流水灯控制的功能模块。假设我要利用“顺序操作”实现如图的功能模块。实际上是怎样的一个效果呢?
我们以“C语言”作为“顺序操作”的代表,来分析一下过程。.
While ( 1 ) //大循环
{
Flash_Funct(); //闪耀功能模块
Run_Funct(); //流水灯功能模块
}
如果按照上面的代码,程序一开始就会先执行闪耀功能模块( Flash_Funct() ),然后再执行流水灯功能模块( Run_Funct() )。但是在现实中,由于控制器的扫描速度很快快,使得人类的肉眼看到错觉“两个模块并行执行着”。事实上,无论控制器的扫描速度怎么快,也是会存在着“上一步延迟”。
亦即 Run_Funct() 要执行前,必须等待 Flash_Funct() 执行完毕,Flash_Funct() 要重复执行,必须等待 Run_Funct() 执行完毕。 除此之外,在“理解上”,人类的思维也非常习惯化的以“顺序”的方式去理解上面的代码。
1. 执行 Flash_Funct();
2. 执行 Run_Funct();
3. 重复步骤1.
如此一来我们明白了一个道理,“顺序操作”不能满足上图组合模块的功能要求。
module top_module ( ...... );
flash_module U1 //功能模块1实例化
(
......
);
run_module U2 //功能模块2实例化
(
......
);
endmodule
上面内容是Verilog HDL语言的实例化过程。在建立实例 U1 和 U2,我们只要确保连接正确而已。在前面说过 "并行操作" 的功能模块都是独立执行。在“设计上”,编辑 flash_module 和 run_module 的工作都是“分开进行”,而在“理解上”两个实例都是 “独立执行”。
换一句话说,上图的组合模块非常适合使用“并行操作”来建模。不同于“顺序操作”,要实现上图的组合模块,除非依靠“高频扫描”或者“任务调度程序”以外,但是无论怎么“依靠”什么,都不是真正意义上的“并行操作”。
功能模块 | 执行频率 | 资源占用 |
闪耀灯功能模块 flash_module.v | 10hz (100ms) | 一位LED |
流水灯功能模块 run_module.v | 3.3Hz (300ms) | 三位LED |
实验二主要是建立如上图的功能模块。乘着这个实验的时机,来解释一下,一个长久以来美丽的误会。
扫描频率?闪耀频率?
闪耀频率是指一个LED开和关说的周期时间。实验二中的 flash_module 所制定的输出如上。
扫描频率是指一次完成流水灯动作所的时间周期。实验二中的 run_module 所制定的扫描输出如上。
回忆以前,记得我在入门单片机的时候,实现的流水灯实验,可能是入门的关系吧?我过分在乎肉眼中所看到的效果,而忘记了这些重要的信息。估计很多人也是吧?但是经过前面2.1章和2.2章的实验创作,要我明白“小小的实验,大大的道理”的道理。原来流水灯实验,不仅是经典,而且包含了很多的知识。有时候做人太注重着外面的世界,不小心之间忘记了心里的世界。
注意: 详细信息请参考 “./Experiment02” 下的原项目。建模过程请参考 建模视频 “video_exp02” 。配置过程请参考 “实验二配置”
flash_module.v 是一个10hz,50%占空比输出的功能模块。说得简单点就是定时开关...
代码比较简单。
run_module.v 是一个3.3hz扫描频率的流水灯,采用“控制模块”形式编写。16~24行是1ms的计数器。28~36行是基于count1的100ms的计数器。40~52行是3Bit的移位操作,45行表示每间隔100微妙发生一次移位操作。48行,判断移位末期。而51行是移位的代码。
mix_module.v 是组合模块,代码很容易明白。自己看着明白吧。
无论是实验二结果,还是理解上的思维,或者设计上的方向。“并行操作”完全符合实验二的要求。所以:
思维倾向“并行操作”对,VerilogHDL + FPGA理解或者设计是非常重要。
黑金版的FPGA型号:CYCLONE II EP2C8Q208C8
包含的.v文件如上图。
编译成功后产生的层次关系。
引脚配置(资源和实验一一样)
用户388551 2011-2-20 18:19