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

FPGA设计代码整洁之道(2)

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
本帖最后由 House 于 2019-3-21 17:57 编辑
9 e2 E, @" p$ b) c* c4 n/ t# I& F$ k
FPGA设计代码整洁之道(2)
$ @4 Y3 O% W- n& V( u1 }1 \
0 B! ?/ R4 \, T- d% g
《极限编程实施》作者Ron  Jeffries 仔细研究了贝克的简单代码规则,并依其重要顺序分别列为:
&  能通过所有测试
&  没有重复代码
&  体现系统中的全部涉及理念
&  包括尽量少的实体,比如类、方法、函数等
能通过所有测试这一点,后文中在架构设计方面详细说明,这里我们还是借助一个小的例子说明“没有重复代码”的一些技巧。
曾经有一次我将多份不同的程序代码用A4纸打印出来,平摊到我的床上对照时,还在上小学的女儿在旁边说道:爸比,你每天就是看这几只毛毛虫爬来爬去吗?always、if、else,begin,对了,还有end,大概就是这几只。小孩子幼稚的话语引得我哈哈大笑,当我回头看向这些代码时,突然记起一位大师说过的话:大部分程序都是由极为相似的元素构成。诚哉斯言!同时,由于这种相似性,许多程序中出现了重复的代码。我们来看一下下面这组代码:
  
1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
  
12
  
13
  
14
  
15
  
16
  
17
  
18
  
19
  
  
assign data0 = {1'b1,din0,1'b0};
  
assign data1 = {1'b1,din1,1'b0};
  
assign data2 = {1'b1,din2,1'b0};
   
always   @(posEDGE clk or negedge rst_n)begin
  
     if(rst_n==1'b0)begin
  
         dout <= 0 ;
  
     end
  
     else if(sel0)begin
  
         dout <= data0[9-cnt2];
  
     end
  
     else if(sel1)begin
  
         dout <= data1[9-cnt2];
  
     end
  
     else begin
  
         dout <= data2[9-cnt2];
  
     end
  
end
这是一个串口发送程序的代码,所实现的功能是发送0、1、2三个数据。很明显,在第2到第4行中,相当于程序中同样的事情做了三遍。第10到第19行也是选了三次,这就属于重复的代码。随着信号越来越多,就需要不断的四个、五个……N个。程序越来越累赘。
同一段代码的反复出现,“唯一性”的边界变得模糊,也容易出现混乱。或者说,作者的想法没有得到最佳的实现。在本例中假设通过搜索引擎输入“?”就会得到相似的?个结果。还记得前文中提到的“做简单的事”吗,这时我们应该思考是代码自身赘余还是对象功能是否太多。如果是前者,应该从有效命名等去改善它;如果是后者,那就“把复杂的事情简单化”,采取某种手段重构它,使功能可以清晰的被说明以及被实现。
如上面的代码,正确的思路和做法应该是什么呢?我们来看下面这份代码。
  
1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
  
12
  
13
  
14
  
15
  
16
  
17
  
18
  
19
  
always   @(*)begin
  
     if(sel0)
  
         din_sel = din0 ;
  
     else if(sel1)
  
         din_sel = din1 ;
  
     else
  
         din_sel = din2 ;
  
end
   
assign data = {1'b1,din_sel,1'b0};
   
always   @(posedge clk or negedge rst_n)begin
  
     if(rst_n==1'b0)begin
  
         dout <= 0 ;
  
     end
  
     else begin
  
         dout <= data[9-cnt2];
  
     end
  
end
首先先把din0,1,2选出来,如果se10的情况下,那么din-se1等于din0;否则,在se11的情况下,那么din-se1等于din1;否则,din-se1等于din2;
接下来我们再来补充0和1;
接着选择时序。dout的变化为XXXXXX,到此代码完成。
通过比较不难看出,第二份代码中,无论是补0补1,还是dout送出,都只做一次,一行代码只做一件事且做好这件事,让编程语言看起来像是专为解决这个问题而存在的。
还有一点,在本节的两个例子中,验证时前一份代码要依次验证,送出的信号din0,din,din2……din N,这个过程中任何一点出现错误都非常麻烦;而第二份代码仅需要验证它们之间的逻辑关系正确即可。
需要注意的是,本节是以一个非常小的信号输出代码为例。越是大型的、复杂的代码,这两种方法之间的效率和质量差距越大。
$ f9 B) {" U9 I, E
游客,如果您要查看本帖隐藏内容请回复
1 i0 B5 x; q3 B4 G! F
0 V, }' V1 D' R! d4 {

) n' `) a! z1 G4 D2 f% z1 p5 m
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

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

EDA365公众号

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

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

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

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

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