找回密码
 注册
关于网站域名变更的通知
查看: 423|回复: 1
打印 上一主题 下一主题

FPGA设计用好的代码实现0仿真0调试

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2019-3-20 13:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
FPGA设计用好的代码实现0仿真0调试
# t" ^$ ]$ P9 x; f( X! q2 B1 S$ S  u. n
在正式开始之前,我们先看看一位FPGA工程师的工作日常:
8 E. R* n0 N, Z( z0 J; l$ b( }& H5 P开始设计代码$ [, |9 y, |* q& N/ v; D+ d
开始写第一个always代码2 H& Q# A, Q' L0 p4 k0 t
发现要增加一个信号,因此写第二个always,设计这个新增的信号
' X+ j2 @3 q# n1 R- u3 g回到第一个always上,继续完善这个代码3 }7 @3 V$ F$ Q8 m  [8 A. @$ |. A
开始写第三个always代码
9 Q6 C% }: T& @# @感觉第一个always有情况没考虑到9 ?8 l: k9 P9 v" `
一阵重新思考2 X# ^% M$ L1 w2 ~. g  O
回去修改第一个always的代码* X5 M5 N& M' t$ E: D( W
写完后,得了,不检查代码了,仿真再说吧。
6 _" }$ T/ ?! N* ~+ g/ R" T% W% e( ]( c5 Q$ o9 k$ ^' ~
仿真过程:
9 b# C8 w: x( d- X5 h/ u3 D每个时钟上升沿一个一个检查3 ?& _  K" A6 R& {( u: Q
发现这时某信号没有变高2 g' n5 D+ f6 R$ D3 X7 f
检查代码,把BUG补上
- A5 k) n$ C. B5 L继续检查波形,继续补BUG: A1 j, I; q. z# c
发现信号A和B时序对不齐- B8 B+ A: O% d9 I" L% b9 z. H
思考是打补丁呢还是打补丁呢" T2 |$ O; n  x( Q- O
是改这个信号呢,还是改那个信号,还是加一个信号8 Z  G# w7 U: ]2 `5 E8 l. u
一番折腾后,终于对齐了
/ F7 L# B0 z2 ]' ^) w0 i6 M修改测试文件,再测试! q5 x& |8 ~+ z5 D( P; }
还是有BUG,继续打补丁
6 a: l7 |5 g1 w7 l' M
9 e" U, s; x. D' |0 X3 C% j该上板调试了) Z+ H) X6 K1 B
系统跑一会没问题,长时间跑就出BUG
5 T1 o) c" r: [- W( [) {. n0 \用调试工具各种分析各种定位$ i! ^5 z- g$ I& E! F
一番折腾后,终于找到BUG
* Z+ @" W0 F3 Z! D2 e8 y4 n; C一个corner没想到/粗心大意漏了个条件/8 T6 [  D5 V2 i" k! m
早知道,要没这BUG,我早就做完了( t$ ]7 F, P! g" \8 Z  X& I0 _' y" M
  ]3 w8 N( i8 y' V. v4 u: e
又出现BUG了,又要来折腾啦。
8 f8 R, e$ P; w% ]- _& U3 K+ n, C! D, u# w
这个场景是不是觉得很熟悉?还有下面这些情形也许都遇到过:一个项目看上去很简单,精心设置了架构,结果越做发现冲突越多,直到整个逻辑完全混乱。本来一天可以的完成的事不知道怎么搞的一个星期还没有完成;本来只需要做一行更改,结果却涉及到N个模块;出现了一个非常小的BUG打了一个补丁,然后补丁越来越多,到最后无法解决。诸如此类等等情况不一而足,究其原因,总离不开“混乱”两个字。这些混乱的根源是什么?又该如何解决呢?
一个好的FPGA项目的设计作品,不仅依赖于架构设计,优秀的代码也是必不可少的关键因素。而好的代码最基本的就是清晰整洁。整洁的代码运行稳定,也是后期维护和升级的基础。正如C++语言发明者Bjarne  Stroustrup说的那样:“代码逻辑应当直截了当,叫缺陷难以隐藏;尽量减少依赖关系,使之便于维护;依据某种分层战略完善错误处理代码;性能调至最优,避免其他人优化时不知所措从而出现混乱状态。整洁的代码只做好一件事。”
这段话说得实在太好了,整洁的代码只去做好一件事。事实上,有两点只要做到了,就可以大大提高自己代码的整洁度。第一、写简单的代码;第二、把复杂的代码简单化。下面我们通过一个小的实例来说明一下。我们先来看这样一组代码:
  
1
  
2
  
3
  
4
  
5
   
6
  
7
  
8
  
9
  
10
  
11
  
12
  
13
  
14
  
15
  
16
  
always   @(posEDGE clk or negedge rst_n)begin
  
     if(rst_n==1'b0)begin
  
         shi_ge <= 0 ;
  
     end
  
     else if(((set_flag == 1'b1 && set_sel == 4)&& (key_vld  == 1 && key_num == 4'b0010)) || shi_ge_add)begin
  
         if(shi_shi ==2 && shi_ge == 3)begin
  
            shi_ge <= 0 ;
  
         end
  
         else if((shi_shi == 0 || shi_shi ==1) && shi_ge == 9)begin
  
            shi_ge <= 0 ;
  
         end
  
         else begin
  
            shi_ge <= shi_ge + 1 ;
  
         end
  
     end
  
end
这个程序时一个数字时钟功能的其中一份关于小时个位的代码。小时个位复位等于0(第3行代码);设置的语句(第5行代码),意思是当你选中小时的个位并且按键按下去,小时个位+1,或者说正常情况下一个小时+1。这里需要注意的是:首先小时的计数方式在0:00——9:00,10:00——19:00,20:00——23:00情况下+1;另外几个时间点清零。
我们来分析一下,在这份代码的设计中需要考虑到很多因素。第一、需要考虑按键;第二、按下去时与正常计数的关系;第三、需要数多少次清零,比如说9点、19点、23点清零;当很多因素混在一起去考虑,特别是格式没有被规范的时候,就容易出现混乱、遗漏点或是相互之间出现冲突,出错的可能性随之变大。
接下来我们来看另外一组代码的思路和操作。
首先,我们建立一个通用的计数器模板,命名为jsq。每次遇到计数器,只需要输入JSq,即可调入该模板。(注:关于模板的设置以后章节介绍)
  
1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
  
12
  
13
  
14
  
always @(posedge clk or negedge  rst_n)begin
  
     if(!rst_n)begin
  
         cnt <= 0;
  
     end
  
     else if(add_cnt)begin
  
         if(end_cnt)
  
            cnt <= 0;
  
         else
  
            cnt <= cnt + 1;
  
     end
  
end
   
assign add_cnt = ;      
  
assign end_cnt = add_cnt && cnt==  ;
接下来设置什么时候个位+1,分为两种情况:1、按键按下去;2、自然计数+1;(第13行)
采用变量法设置X-1;即先不用去管数多少下,反正数完就清零;(第14行)
最后我们设置数多少下。20:00时数4下;其它时候数10下;(16~21行)
  
1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
  
12
  
13
   
14
  
15
  
16
  
17
  
18
  
19
  
20
  
21
  
always @(posedge clk or negedge  rst_n)begin
  
     if(!rst_n)begin
  
         cnt <= 0;
  
     end
  
     else if(add_cnt)begin
  
         if(end_cnt)
  
            cnt <= 0;
  
         else
  
            cnt <= cnt + 1;
  
     end
  
end
   
assign add_cnt =((set_flag == 1'b1  && set_sel == 4)&& (key_vld == 1 && key_num ==  4'b0010)) || shi_ge_add ;      
  
assign end_cnt = add_cnt && cnt==  x-1 ;
   
always   @(*)begin
  
     if(shi_s == 2)
  
         x = 4 ;
  
     else
  
         x = 10 ;
  
end

6 c. P2 y0 ~+ V) {' O) g
现在我们来回顾一下这段代码,从中不难发现,设计的总体思路有着严密的逻辑和步骤,并采取了便捷工具(模板)来规范了代码编写,减少了设计量。最重要的是设计者的意图清晰了然,控制语句直截了当,代码之间相互依赖性非常低,作者之外的开发者阅读和增补非常轻松。
2 B# s. o1 X& f; i# E; _6 V
游客,如果您要查看本帖隐藏内容请回复
& |: Q9 @6 A* G

该用户从未签到

2#
发表于 2019-3-20 15:47 | 只看该作者
回复看看隐藏内容
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-7-28 20:22 , Processed in 0.125000 second(s), 26 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表