分享

FPGA整洁代码之道3-信号命名和定义应该明确

 goandlove 2019-08-21

在设计中,我们不断的给目录、源代码、文件、函数、变量、参数、类、封包进行命名与定义。当一件工作需要进行的次数非常之多,足以证明它是不可或缺的基本工作。我们一定要知道一点,基础工作是整个项目的基石。忽视抑或是轻视基础工作是一件非常错误的工作理念。我们需要用最严谨认真的态度去对待,同时作为回报,它将令你的作品显得专业而优雅。

我们以信号的定义为例来说明这个问题。先来看这么一组代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

4344

45

464748

always @(posedge clk or negedge rst_n)begin

if(!rst_n)begin

cnt <=>

end

else if(add_cnt)begin

if(end_cnt)

cnt <=>

else

cnt <= cnt="" +="">

end

end

assign add_cnt = flag1||flag2 ;

assign end_cnt = add_cnt && cnt==x-1 ;

always @(posedge clk or negedge rst_n)begin

if(rst_n==1'b0)begin

flag1 <=>

end

else if(en1)begin

flag1 <=>

end

else if(end_cnt)begin

flag1 <=>

end

end

always @(posedge clk or negedge rst_n)begin

if(rst_n==1'b0)begin

flag2 <=>

end

else if(en2)begin

flag2 <=>

end

else if(end_cnt)begin

flag2 <=>

end

end

always @(*)begin

if(flag1)

x = 5;

else if(flag2)

x = 7;

else begin

x = 0;

end

end

这组代码的功能是当en1时计数5下;en2计数7下。在这组代码中,en1时flag1拉高;end-cnt时flag1变低;en2时flag2拉高;end-cnt时flag2变低;也就是在flag1或者flag2时加一,然后用flag1和flag2分别区分计数5下和7下。

尽管能够实现功能,但是在这组代码中,存在信号定义不明确得现象。flag1和flag2到底是什么意思?是表示flag1(flag2)时en1产生,还是en1(en2)时的计数状态?为说明这一点就得用到XXXXX (写加一条件时需要用到add_cnt = flag1||flag2)语句。

这里重申一下我们很重要的那条简单原则,一个代码(信号)只做一件事且做好这件事!按照这个规则,思路就是这样了:用一个信号flag1来表示计数状态,另外一个信号flag2表示是由en1还是en2所产生。那么,加一与否的条件非常简单,就是是否处于工作状态(flag1);同理,计数5或者7下只需要使用flag2一个信号。那么代码就会是这样:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

3839

404142

43

44

45

always @(posedge clk or negedge rst_n)begin

if(!rst_n)begin

cnt <=>

end

else if(add_cnt)begin

if(end_cnt)

cnt <=>

else

cnt <= cnt="" +="">

end

end

assign add_cnt = flag1 ;

assign end_cnt = add_cnt && cnt==x-1 ;

always @(posedge clk or negedge rst_n)begin

if(rst_n==1'b0)begin

flag1 <=>

end

else if(en1||en2 )begin

flag1 <=>

end

else if(end_cnt)begin

flag1 <=>

end

end

always @(posedge clk or negedge rst_n)begin

if(rst_n==1'b0)begin

flag2 <=>

end

else if(en1)begin

flag2 <=>

end

else if(en2)begin

flag2 <=>

end

end

always @(*)begin

if(flag==0)

x = 5;

else

x = 7;

end

看到这里,也许有些朋友会觉得:好像区别没那么大啊?ok,我们假设一下,如果程序中不仅是是en1,en2,而是有en3,en4……enX,又或者将来需要维护和优化,这两者的区别将会天壤之别。

关于信号定义方面,《至简设计法》的作者潘文明给出了一个近乎完美的答案。例如在计数器代码设计中的“架构八步法”,第一步就是明确定义信号,用具体、清晰且无疑异的语句,定义每个信号所要实现的功能,以及重点描述信号的变化情况。如下图中的信号列表。

信号列表。(4)(用文字版)

信号名

I/O

位宽

说明

clk

I

1

系统工作时钟

rst_n

I

1

系统复位信号

Din_sop

I

1

当vld=1时才有效,输入报文头指示信号

Din_eop

I

1

当vld=1时才有效,输入报文尾指示信号

Din_vld

I

1

输入数据有效标志,高电平有效

Din_err

I

1

输入报文错误标志,在eop有效时才有效

din

I

8

输入数据总线

Dout_sop

O

1

当vld=1时才有效,输出报文头指示信号

Dout_eop

O

1

当vld=1时才有效,输出报文尾指示信号

Dout_vld

O

1

输出数据有效标志,高电平有效

dout

O

8

输出数据总线

Dout_err

O

1

输出报文错误标志,在eop有效时才有效

从中可以看出,优秀的FPGA设计师一开始就从顶层结构明确定义信号,将可能出现的混乱从根源上解决。这样的思路和方法实在非常值得我们每一位从业者学习和借鉴。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多