The Quartus® Prime software includes inherently parameterized megafunctions, including library of parameterized modules (LPM) functions. For example, parameters are used to specify the width of a port or whether a block of RAM should be implemented as synchronous or asynchronous memory. Parameterized functions can contain other subdesigns, which may be parameterized or unparameterized, however, primitives cannot be parameterized. All Quartus® Prime logic functions can be used to create hierarchical logic designs. Megafunctions are automatically installed in the \quartus\libraries\megafunctions directory created during installation; primitive logic is built into AHDL.
Parameterized functions are instantiated with an in-line logic function reference or an Instance Declaration in the same way as unparameterized functions, as described in Using Altera-Provided Unparameterized Functions, with a few additional steps:
The inputs, outputs, and parameters of the function are declared with a Function Prototype Statement. The Quartus® Prime software provides AHDL Include Files (.inc) that contain Function Prototypes for all Quartus® Prime megafunctions in the \quartus\libraries\megafunctions directory.
The lpm_add1.tdf file shown below implements an 8-bit adder with an in-line logic function reference to the parameterized lpm_add_sub megafunction:
INCLUDE "lpm_add_sub.inc"; SUBDESIGN lpm_add1 ( a[8..1], b[8..1] : INPUT; c[8..1] : OUTPUT; carry_out : OUTPUT; ) BEGIN % Megafunction instance with positional port association % (c[], carry_out, ) = lpm_add_sub(GND, a[], b[], GND,,) WITH (LPM_WIDTH=8, LPM_REPRESENTATION="unsigned"); % Equivalent instance with named port association % -- (c[], carry_out, ) = lpm_add_sub(.dataa[]=a[], .datab[]=b[], -- .cin=GND, .add_sub=GND) -- WITH (LPM_WIDTH=8, -- LPM_REPRESENTATION="unsigned"); END;
The Function Prototype for lpm_add_sub, which is stored in the AHDL Include File lpm_add_sub.inc, is shown below:
FUNCTION lpm_add_sub(cin, dataa[LPM_WIDTH-1..0], datab[LPM_WIDTH-1..0], add_sub) WITH (LPM_WIDTH, LPM_REPRESENTATION, LPM_DIRECTION, ADDERTYPE, ONE_INPUT_IS_CONSTANT) RETURNS (result[LPM_WIDTH-1..0], cout, overflow);
Only the LPM_WIDTH parameter is required, and the instance of the lpm_add_sub function in lpm_add1.tdf specifies parameter values only for the LPM_WIDTH and LPM_REPRESENTATION parameters.
The lpm_add2.tdf file shown below is identical to lpm_add1.tdf, but implements the 8-bit adder with an Instance Declaration:
INCLUDE "lpm_add_sub.inc"; SUBDESIGN lpm_add2 ( a[8..1], b[8..1] : INPUT; c[8..1] : OUTPUT; carry_out : OUTPUT; ) VARIABLE 8bitadder : lpm_add_sub WITH (LPM_WIDTH=8, LPM_REPRESENTATION="unsigned"); BEGIN 8bitadder.cin = GND 8bitadder.dataa[] = a[] 8bitadder.datab[] = b[] 8bitadder.add_sub = GND c[] = 8bitadder.result[] carry_out = 8bitadder.cout END;