|
1 Y% G% G) ~. N& }4 |3 q Verilog基础语法 / w7 t' S8 r6 b; m
/ j7 B( _" i/ L, L# C* j, W/ G2 ? 1.1 可综合模块 ( u$ v+ q8 r* B; ?- k7 H1 L 以module为单元,具体实现如下: / t" Y& @- k% R3 f* A
, d V) c! w& M* d! _ 1.1.1 时序逻辑 1 s2 e" u* W ^/ U. O: ]! H 以异步触发的D触发器为例,时序逻辑在always块里实现。 ( Y( t: M$ c+ {, p# l
主要注意点: 5 t! a) G0 I4 |& q 1. 声明模块时,输入变量一定是wire类型。 5 X7 d: G7 x' L. E2 T0 a: a 2. 声明模块时,输出变量可以是wire,也可以是reg, reg变量只能在always块中赋值。 : m6 o$ n1 z- z 3. 敏感列表既可以是边沿触发,也可以是电平触发。 4. 沿触发的逻辑里,一定采用的是非阻塞触发<=。 , d7 {3 m% C0 c* f/ s5 ^ 1.1.2 组合逻辑 以数据选择器为例,组合逻辑通常使用assign语句赋值。
主要注意点: 8 v9 r) d; ]/ f: q( F6 `$ ?& l9 ~ 1. sel = 0时,c = a;sel = 1时,c =b,即二选一数据选择器。四选一则有两个选择端,四个输入端,八选一则是三个选择端,八个输入端。 2. wire 变量一定要用连续赋值语句赋值,而且必须用阻塞赋值。 ) k* t {% L7 B: I 1.2 仿真模块 2 H! ^0 \# J" z# a X, u6 r" ?; R- J 仿真模块和可综合模块的区别: 可综合模块最终生成的bit文件会烧录进芯片运行,而仿真模块编译过后是在仿真软件(例如modelsim)上运行的。仿真模块是基于可综合模块进行例化,并通过仿真软件的模拟,可以初步验证我们写的可综合模块的实现现象。 ' n( p2 T" n: U6 N F) L 以计数器为例,可综合模块如下:
+ X% d5 K$ g6 f- y4 m9 F# G# E 基于以上可综合模块的仿真模块如下: : I- [( T: t! G8 ~8 X: o
A/ k* |; @, M! }0 z 1. 仿真的模块声明不需要输入列表。 8 [* Z7 o( o1 B$ ]2 R2 p. S 2. initial块只能对【寄存器】量进行赋值。 3. 例化模块时,如果原始模块是输出变量,则括号内必须【wire变量】。 HDL常见例子 2.1 译码器 - g, P% C( c3 }/ E 2.1.1 可综合模块(case语句) 此模块用case实现了一个数据选择的功能,先产生了一个8位计数器,通过判断计数器的值来输出不同的取值,当计数器计数到1时,o_data和o_dv分别输出5和1,当计数器为2时,输出7和1,其余均输出0。(Note:Case语句常常运用于状态机中状态的判断)
Case语句注意点: 2 Y8 e) Y' g. b6 N3 r. D r 必须有default语句,否则会形成锁存器。 - X" q& P% \ M4 v0 `' T0 o 2.1.2 仿真模块 4 y" s) e8 v8 ^4 ?0 u/ {/ X
; ?5 b3 {6 P4 ?) u+ l 2.2 状态机 % J, T K8 h, B. Q7 T( l 由于FPGA内部语句块都是并行运行的,当我们希望FPGA按照顺序执行我们的语句时,就会用到状态机。 4 t* ?" t& r% w. M; i 下面例子是使用状态机模拟的一个简单的自动售货机,该售货机中的商品 2.5 元一件,每次投币既能投入 1 元,也能投入 0.5 元,当投入 3 元时,需要设定找零。 2.2.1 状态图 7 w! F, h( u0 y l# w8 U" Z. y
( M, P4 C- h5 G 2.2.2 可综合模块(2段式状态机) - t2 O5 a& y$ r) P. u5 r
$ x2 h. Y& P4 S 2.2.3 仿真模块 ) j, H+ M1 ^" m# G- [+ a$ }
4 U" T2 A! A2 [8 D9 T ^! f& y 2.2.4 仿真脚本 - A& e" a* y5 G* C- J 仿真脚本可以省去人工操作modelsim软件图形页面的步骤,运行脚本,modelsim可以根据脚本命令自动运行包括创建工作目录,编译文件,启动仿真等步骤,以下是本例中的仿真脚本。
0 z6 y: I) N$ u8 x& x 仿真脚本编写好后,只需要进入仿真软件(本例使用的是modelsim),改变当前路径到脚本保存的路径,然后在modelsim命令行输入 do [脚本文件名] 即可。
! j" J0 u7 D1 x6 r 仿真结果:
& \% L7 i' ~# h1 m) @. I3 ` 2.2.5 上板测试 ' M3 m, h& h" b9 i* w9 H2 o 上板测试对原来的条件做了一定改动更方便观测结果,输入和输出分别使用的按键和LED灯,测试版使用的是Anlogic的EF3L40CG332B_DEV,实现的功能如下: & i/ t; }( S t: q ① 在开发板上完成自动售货机的实验,投币的动作通过按键实现, 当按一次按键(按下到抬起算一次),算作投币一次。 ② 按键有两个,按下分别代表 5 毛和 1 元,可乐售价 2.5 元。 ③ 当投入总金额为 5 毛时, led 灯亮一个,投入总金额为 1 元时, led 灯亮两个, 投入总金额为 1.5 元时, led 灯亮三个, 投入总金额为 2 元时, led 亮四个, 用单向流水灯效果充当出可乐并且不找零的情况,用双向流水灯效果充当既出可乐又找零的情况。流水灯持续十秒后熄灭,状态回到初始状态。 重新设计状态图如下: + Q7 i) a6 D9 V5 x' C5 C
代码详见工程fsm_key,笔记不再赘述,此次笔记主要记录关于顶层模块和例化的相关知识点: 工程目录如下所示: * A9 a+ Q3 P% b; w: B% \
各模块之间的关系是: 顶层文件是fsm.v,在fsm.v中调用了模块led_water_single,led_Water_double和key_debounce,这三个模块的功能分别是单向流水灯,双向流水灯和按键消抖。想在顶层文件中调用对应的模块需要在顶层文件中对相应的模块进行例化,以单向流水灯为例。 . q" K+ w: l) b Q 单向流水灯的声明如下: % F/ E h3 E: f- F5 J
(具体功能实现代码略,如有需要,请登录www.fortune-co.com留言)
那么在fsm.v中例化方法如下: / F# M6 T x. j m6 q& e/ {5 G
括号外的信号是对应的声明信号;括号内的信号是从fsm模块中传入的信号,该信号名称可以自定义。 ; {7 ^ I; O3 I 整个工程的框架如下:(由于本实验没有另外写一个总的TOP文件,而是将例化和状态机信号处理都放在了fsm模块中,因此top层和状态机模块都标注的是fsm)
其中key05,key10,就是从外界接入的信号,led[7:0]即输出信号。接入信号我们要引到对应的按键,可以参考EF3L40CG332B_DEV的原理图:
SW2和SW3对应的FPGA的管脚分别是R19和R20,同理可查,八个led的对应脚,并写出相应的管脚约束文件: : T- p# ^% O( a, b
管脚约束文件写完后,在可综合模块顶层文件中的输入输出信号就会对应到相应的物理输入输出,也可以使用图形页面设置。 完成后编译下载到板子上观测现象。 在本次实验的过程中也发生了一个编程错误问题,刚编写完上板测试时发现结果和预想的有差异,具体错处在输入3元进入双向流水灯的状态时,双向流水灯正向流水正常,当反向流水时,在倒数第二个灯会卡住,然后反复亮灭倒数一二个灯,没法完成反向流水。
由于第一次正向流水是正常的,因此推测是在反向流水时有条件判断错误使得反向流水无法正常运行,进入到led_water_double模块关于反向流水灯的操作模块,经查验发现是设置翻转标志的时候判断条件写错了。
判断条件应该是led == 8’b1111_1110,更改后,实验现象符合预期要求。 R3 o# l$ e% V: \ 1 END 1 # | F) U* k4 f2 D- ?. j' h 以上是FPGA杂记基础篇的第一部分,因文章篇幅所限,本文先分享到这里。后续会有更多基于FPGA的设计文章,敬请期待…… 0 S& L+ w* j# _; L |
微信公众号
手机版