本文介绍如何在Quartus II里使用Altera的模块库。
范例电路
参数化模块库
使用LPM的扩展电路(Arguemented Circuit)
扩展设计的结果
实际设计中经常包含通用的电路块,比如:加法器、减法器、乘法器、译码器、计数器和移位寄存器。Altera以模块库的
形式提供这些电路块,可在Verilog设计中例化。编译器可以识别模块库里用Verilog代码指定的标准功能,这样就会自动推断这个模块。但是,很多模块库提供太复杂的功能而不能被自动识别。这些模块必须被用户在设计里明确的例化。
Quartus II包含一个参数化的模块库(LPM)。这些模块采用通用结构,并且需要修该指定的参数值来实现指定的应用。
完成本文,读者将学会:
本文范例的细节由Quartus II 9.1截取,其他版本类似。
作为范例,我们使用图1所示的加/减器电路。它可以加、减,并以2的补码表示运算n-bit的数。2个主要的输入是数A=
an-1an-2…a0和B=bn-1bn-2…b0,主要的输出是Z=zn-1zn-2…z0。另一个输入是控制信号AddSub,当AddSub
=0时Z=A+B;当AddSub=1时,Z=A-B.第2个输入控制信号Sel被用来选择运算模式的操作。当Sel=0时,Z=A+-B;
当Sel=1时,B被从当前Z的值加到或减去。如果加法或减法操作的结果溢出,一个输出信号Overflow被激活。
为了较容易处理异步输入信号,在时钟上升沿它们被加载到触发器。因此,输入A和B将被加载到寄存器Areg和Breg,
而Sel和AddSub将被加载到触发器SelR和AddSubR。加/减器电路的结果放在寄存器Zreg。
图 1
需要的电路如图2 描述。在我们的例子里,我们用一个16位的电路,指定n=16.实现的过程如下:
design_files。
代码:
1 // Top-level module
2 module addersubtractor(A,B,Clock,Reset,Sel,AddSub,Z,Overflow);
3 parameter n = 16 ;
4 input [n - 1 : 0 ]A,B;
5 input Clock,Reset,Sel,AddSub;
6 output [n - 1 : 0 ]Z;
7 output Overflow;
8 reg SelR,AddSubR,Overflow;
9 reg [n - 1 : 0 ]Areg,Breg,Zreg;
10 wire [n - 1 : 0 ]G,H,M,Z;
11 wire carryout,over_flow;
12
13 // Define combinational logic circuit
14 assign H = Breg ^ {n{AddSubR}};
15 mux2to1 multiplexer(Areg,Z,SelR,G);
16 defparam multiplexer.k = n;
17 adderk nbit_adder(AddSubR,G,H,M,carryout);
18 defparam nbit_adder.k = n;
19 assign over_flow = carryout ^ G[n - 1 ] ^ H[n - 1 ] ^ M[n - 1 ];
20 assign Z = Zreg;
21
22 // Define flip-flops and registers
23 always @( posedge Reset or posedge Clock)
24 if (Reset == 1 )
25 begin
26 Areg <= 0 ;
27 Breg <= 0 ;
28 Zreg <= 0 ;
29 SelR <= 0 ;
30 AddSubR <= 0 ;
31 Overflow <= 0 ;
32 end
33 else
34 begin
35 Areg <= A;
36 Breg <= B;
37 Zreg <= M;
38 SelR <= Sel;
39 AddSubR <= AddSub;
40 Overflow <= over_flow;
41 end
42 endmodule
43
44 // k-bit 2-to-1 multiplexer
45 module mux2to1(V,W,Sel,F);
46 parameter k = 8 ;
47 input [k - 1 : 0 ]V,W;
48 input Sel;
49 output [k - 1 : 0 ]F;
50 reg [k - 1 : 0 ]F;
51
52 always @(V or W or Sel)
53 if (Sel == 0 )
54 F = V;
55 else
56 F = W;
57 endmodule
58
59 // k-bit adder
60 module adderk(carryin,X,Y,S,carryout);
61 parameter k = 8 ;
62 input carryin;
63 input [k - 1 : 0 ]X,Y;
64 output [k - 1 : 0 ]S;
65 output carryout;
66 reg [k - 1 : 0 ]S;
67 reg carryout;
68
69 always @(X or Y or carryin)
70 {carryout,S} = X + Y + carryin;
71 endmodule
LPM采用通用结构,通过指定参数值来应用。选择Help > Megafunctions/LPM打开可用的LPM列表。其中一个是加/减器
模块,lpm_add_sub megafunction。选择这个模块,查看其描述。这个模块有一些输入和输出,其中部分可省略。几个
参数可用来定义指定的操作。比如,操作数的位由参数LPM_WIDTH指定。参数LPM_REPRESENTATION指定操作数作为
有符号数还是无符号数,等等。在模块描述中给出如何例化一个LPM的模板。使用这些模板稍微不便,因此Quartus II提供
一个更容易的例化向导。
我们将使用lpm_add_sub模块来简化图1和图2的加/减器。修改电路如图3.lpm_add_sub模块例化为megaddsub,代
替加法电路里提供加法输入H的异或门。既然运算溢出是LPM的一个输出,就没必要单独用一个异或门生成。
要完成这个加减器电路,创建一个新的目录tutorial_lpm,并创建一个新工程addersubtractor2。
图 3
新的设计将包括目标LPM子电路,并在顶层设计模块例化。LPM子电路的Verilog 模块生成步骤如下:
图 4
图 5
3. 在图5的窗口提供可用的LPM列表。展开arithmetic子列表并选择LPM_ADD_SUB。选择输出文件类型为Verilog HDL。指定输出文件名megaddsub.v和路径。单击Next。
图 6
4. 在图6中指定输入数据的位宽为16位,通过一个端口指定操作模式,执行加或减运算。在窗口的左上角可以看到这个
LPM的符号。注意,当add_sub=1时,result=A+B;反之,result=A-B.这个图1的设计不同。在图3中已经提到。
单击Next.
图 7
5. 在图7的窗口,选择输入值都可改变,单击Next。
图 8
6. 在图8窗口选择Create an overflow output,单击Next。
图 9
7. 在图9窗口,选择No,单击next。
8. 图10给出向导创建的文件的总结。单击Finish。
图 10
在修改的设计中将使用megaddsub.v。
代码megaddsub.v
// synopsys translate_off
`timescale 1 ps / 1 ps
// synopsys translate_on
module megaddsub (
add_sub,
dataa,
datab,
overflow,
result);
input add_sub;
input [ 15 : 0 ] dataa;
input [ 15 : 0 ] datab;
output overflow;
output [ 15 : 0 ] result;
wire sub_wire0;
wire [ 15 : 0 ] sub_wire1;
wire overflow = sub_wire0;
wire [ 15 : 0 ] result = sub_wire1[ 15 : 0 ];
lpm_add_sub lpm_add_sub_component (
.dataa (dataa),
.add_sub (add_sub),
.datab (datab),
.overflow (sub_wire0),
.result (sub_wire1)
// synopsys translate_off
,
.aclr (),
.cin (),
.clken (),
.clock (),
.cout ()
// synopsys translate_on
);
defparam
lpm_add_sub_component.lpm_direction = " UNUSED " ,
lpm_add_sub_component.lpm_hint = " ONE_INPUT_IS_CONSTANT=NO,CIN_USED=NO " ,
lpm_add_sub_component.lpm_representation = " UNSIGNED " ,
lpm_add_sub_component.lpm_type = " LPM_ADD_SUB " ,
lpm_add_sub_component.lpm_width = 16 ;
endmodule
修改后的加减器代码如下。将这个代码加入文件tutorial_lpm\addersubtractor2。为了方便,DE2附带光盘也提供了这个
文件。这个代码和前面的不同之处在于:
取反以适合这个控制信号在LPM里的用法。
代码 addersubtractor2
1 // Top-level module
2 module addersubtractor2(A,B,Clock,Reset,Sel,AddSub,Z,Overflow);
3 parameter n = 16 ;
4 input [n - 1 : 0 ]A,B;
5 input Clock,Reset,Sel,AddSub;
6 output [n - 1 : 0 ]Z;
7 output Overflow;
8 reg SelR,AddSubR,Overflow;
9 reg [n - 1 : 0 ]Areg,Breg,Zreg;
10 wire [n - 1 : 0 ]G,M,Z;
11 wire over_flow;
12
13 // Define combinational logic circuit
14 mux2to1 multiplexer(Areg,Z,SelR,G);
15 defparam multiplexer.k = n;
16 megaddsub nbit_adder( ~ AddSubR,G,Breg,M,over_flow);
17 assign Z = Zreg;
18
19 // Define flip-flop and register
20 always @( posedge Reset or posedge Clock)
21 if (Reset == 1 )
22 begin
23 Areg <= 0 ;
24 Breg <= 0 ;
25 Zreg <= 0 ;
26 SelR <= 0 ;
27 AddSubR <= 0 ;
28 Overflow <= 0 ;
29 end
30 else
31 begin
32 Areg <= A;
33 Breg <= B;
34 Zreg <= M;
35 SelR <= Sel;
36 AddSubR <= AddSub;
37 Overflow <= over_flow;
38 end
39 endmodule
40
41 // k-bit 2-to-1 multiplexer
42 module mux2to1(V,W,Selm,F);
43 parameter k = 8 ;
44 input [k - 1 : 0 ]V,W;
45 input Selm;
46 output [k - 1 : 0 ]F;
47 reg [k - 1 : 0 ]F;
48
49 always @(V or W or Selm)
50 if (Selm == 0 )
51 F = V;
52 else
53 F = W;
54 endmodule
55
添加megaddsub.v到工程。选择Porject > Add/Remove Files in Project(图13)。文件addersubtractor2.v已经存在,添加megaddsub.v,单击Ok。
图 13
图 14
编译设计,查看总结,图15.注意修改后的电路使用52个le。因为本例比较简单,使用LPM的优势并不明显。在更复杂的设
计中使用LPM,优势比较明显。当有合适的LPM时,建议使用。
图 15
Using Library Modules in Verilog Designs