Thousand = x /1000
Hundred = x % 1000 / 100
Ten = x % 1000 % 100 / 10
One = x % 10
以上的公式估计不陌生,有学习过单片机基础的同学都知道,是取“千”,“百”,“十”,“个”位的公式。这类有“除”又有“求余”的公式,会大大降低处理的效率。
我们设计“千位取位逻辑”时,不肯能直接照搬来用。但是很庆幸的是Quartus II 老早就为用户准备了“LPM”, LPM用傻瓜的话来说“可配置的自定义模块”。要达到以上公式的效果,我们只要使用“3个”除法器便可实现。
以上是"千位取位逻辑"的示意图。该构思有一个缺点,就是输入数是有限制。在SF-EP1V2板子上,只有4位而已,故我将设计限制在0~9999之间。另外,随着输入数的不同,“位宽”也会改变。
接下来的载图是演示如何调用除法器的LPM。
5)输入被除数( numerator )的位宽和除数( denominator )的位宽。都是无符号型。
6)选择速度优化“Speed”
注意点:
“被除数”(numberator)和“除数”(denominator)可以配置位宽,但是“商数”和“余数”必须跟随着前者的设置(图5)。 除此之外,我们放弃了面积和优化而倾向速度,因为组合逻辑尽可以的话就是要“快”。(图6)
我总共创建了3个除法器:“divide_thousand”,“divide_hundred”和“divide_ten”,以下是
项目导航操作:
1.module number_module
2.(
3. Data_In,
4. Thousand, Hundred, Ten, One
5.);
6.
7. input [25:0]Data_In;
8. output [3:0]Thousand;
9. output [3:0]Hundred;
10. output [3:0]Ten;
11. output [3:0]One;
12.
13. /*********************************/
14.
15. wire [17:0]U1_Remain_Sig;
16. reg [17:0]rThousand_Const;
17.
18. divide_thousand U1
19. (
20. .denom ( rThousand_Const ),
21. .numer ( Data_In ),
22. .quotient ( Thousand ),
23. .remain ( U1_Remain_Sig )
24. );
25.
26. reg [15:0]rHundred_Const;
27. wire [7:0]U2_Remain_Sig;
28.
29. divide_hunred U2
30. (
31. .denom ( rHundred_Const ),
32. .numer ( U1_Remain_Sig ),
33. .quotient ( Hundred ),
34. .remain ( U2_Remain_Sig )
35. );
36.
37. reg [7:0]rTen_Const;
38.
39. divide_ten U3
40. (
41. .denom ( rTen_Const ),
42. .numer ( U2_Remain_Sig ),
43. .quotient ( Ten ),
44. .remain ( One )
45. );
46.
47. /***************************/
48.
49. always @ ( Data_In )
50. begin
51. rHundred_Const = 16'd100;
52. rTen_Const = 8'd10;
53. rThousand_Const = 18'd1000;
54. end
55.
56. /***************************/
57.
58.endmodule
1. 建立了一个Top模块用来阻止这些除法器。组织过后的效果如下:
示意图如下:
2. 从上面的示意图可以看到,个个除法器的都是超过“4位”的位宽,当引出到外面的时
候,除了“前4位”,其余的都被“吃掉”。乍看是很不好的习惯,实际上输出影响不
大,尽可以的话就避免吧,我为了贪图“方便”。
3. 在49行到54行。Data_In无论如何产生变化。都不会有任何改变,这是一个赋值“常数”
的一个“手段”而已。
Testbench 代码:
1.module number_module_vlg_tst();
2. reg [25:0] Data_In;
3.
4. wire [3:0] Hundred;
5. wire [3:0] One;
6. wire [3:0] Ten;
7. wire [3:0] Thousand;
8.
9. number_module i1
10. (
11. .Data_In(Data_In),
12. .Hundred(Hundred),
13. .One(One),
14. .Ten(Ten),
15. .Thousand(Thousand)
16. );
17.
18. initial
19. begin
20. Data_In = 26'd7821;
21. end
22.
23.endmodule
仿真载图:
问1: 在建立除法器的时候,有“Pipeline function”也就是流水功能?加和没加有什么特别?
答:这个问题确实有点... 我也尝试过点击这个功能,而延迟为1个时钟,效果也是一样。是
在很对不起,以目前的知识,实在是很难解释...(⊙o⊙)!
问2: 建立除法器意外,还要建立顶层模块组织它们起来。老实说真的很烦?为什么不直接使
用公式呢?
答:这个问题,我想你也很清楚,乘法或者除法的运算时非常慢。可能你又会问?那么建
立除法器和建立公式又有什么不同?建立除法器的概念是“硬件运算”,而建立公式的
概念是“软件运算”。“硬件运算”和“软件运算”,哪一个比较快呢?
问3: 你“吃掉”输出的位宽(eg:Thousand的商数输出是26位,但是被载致4位),会发生
什么怪事?
答: 从多次仿真的结果看来,没有事情发生。但是不保证不会发生事情...
这一章的实验与以往比较不同。对于我本身也觉得很微妙,当初就只有一个想法而已,想不到既然会实现出来!?我一开始尝试使用公式来达到效果,但是结果都很不理想。浑浑噩噩中在网上冲浪,需找“求余”的Verilog代码,但结果都是空空如也。无奈之下就产生这样的一个念头“IP?LPM?可配置模块?除法器?”
补充一点:在使用LPM时最后将“xxx.qip”和“xxx.v”的文件加入“项目导航”的“文件中”。否者的话,编译器会一直“警告”“警告”的“吠”,真的很烦。
源码:
用户1373959 2010-5-18 21:19
用户1609127 2010-5-18 19:53