Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
17264 Discussions

Instantiating LPM Functions in VHDL: parallel adder

Altera_Forum
Honored Contributor II
11,297 Views

Hello guys... 

 

I'm trying instatniating some altera MF directly in my top design. 

 

From what I have understand I have two use two libraries: 

library altera_mf; use altera_mf.altera_mf.components.all; library lpm; use lpm.lpm_components.all; 

 

The first libray is used to avoid the components declarations and the second is used to instantiate directly the lpm objects. 

 

 

So, as I want to use a parallel adder, I wrote: 

parallel_add_inst : parallale_add GENERIC MAP(....) PORT MAP(...); 

 

 

By the way, looking at the Integer Arithmetic Megafunctions User 

Guide, the port map of the parallel adder is: 

data:in altera_mf_logic_2D(size - 1 downto 0,width- 1 downto 0); clock : in std_logic := '1'; aclr : in std_logic := '0'; clken : in std_logic := '1'; result : out std_logic_vector(widthr - 1 downto 0));  

 

So, how should I write the port map if I want to add two input signals (eg dataa[15..0] and datab[15..0]) ? 

 

Thank you ! 

 

Have a nice day !
0 Kudos
21 Replies
Altera_Forum
Honored Contributor II
7,038 Views

This is going to be complicated by the fact Altera uses the altera_mf_logic_2D type in this design (instead of just making an array of std_logic_vectors like any normal person would). 

 

For a start, if you're just using two inputs, use the lpm_add_sub block instead, or just do an add in your code: 

 

a <= b + c; 

 

for parellel add, you have to map each bit individually to the bits on the bus, because of VHDL's strong typing. so: 

 

data(0,0) => dataa(0); 

data(0,1) => dataa(1); 

--etc 

 

data(1,0) => datab(0); 

data(2,0) => datab(1); 

 

For this stupid reason, I would be inclinded to write you own type conversion function: 

 

function slv_to_alteras_stupid_2d_type( a : std_logic_vector; b : std_logic_vector) return altera_mf_logic_2D is variable ret : altera_mf_logic_2D( begin for i in a'range loop ret(0,i) := a(i); ret(1,i) := b(i); end loop; return ret; end function;  

 

It could easily be modified to convert an array of std_logic_vectors into a 2d array type.
0 Kudos
Altera_Forum
Honored Contributor II
7,038 Views

 

--- Quote Start ---  

Hello guys... 

 

I'm trying instatniating some altera MF directly in my top design. 

 

From what I have understand I have two use two libraries: 

library altera_mf; use altera_mf.altera_mf.components.all; library lpm; use lpm.lpm_components.all; 

 

The first libray is used to avoid the components declarations and the second is used to instantiate directly the lpm objects. 

 

 

So, as I want to use a parallel adder, I wrote: 

parallel_add_inst : parallale_add GENERIC MAP(....) PORT MAP(...); 

 

 

By the way, looking at the Integer Arithmetic Megafunctions User 

Guide, the port map of the parallel adder is: 

data:in altera_mf_logic_2D(size - 1 downto 0,width- 1 downto 0); clock : in std_logic := '1'; aclr : in std_logic := '0'; clken : in std_logic := '1'; result : out std_logic_vector(widthr - 1 downto 0));  

 

So, how should I write the port map if I want to add two input signals (eg dataa[15..0] and datab[15..0]) ? 

 

Thank you ! 

 

Have a nice day ! 

--- Quote End ---  

 

 

The altera_mf_logic_2D type is identical to the std_logic_2D type declared in the lpm-library. Unfortunately Altera hasn't declared any user functions/procedures to work with these types.  

I started using the std_logic_2D type several years back to instantiate AHDL modules where you could use arrays like A[1..0][15..0] (which were represented by std_logic_2D by the generated VHDL components). As such I wrote quite some functions / procedures to work with std_logic_2D. Now a std_logic_2D is a true 2D type where you have a n by m array of (single) bits. This is different to 1Dx1D arrays where you have a vector of vectors. (see e.g. Volnei A. Pedroni: Circuit Design with VHDL page 30 and following). 

 

In your case what you need (so far as I can see) is a simple procedure to map the two source std_logic_vectors to a std_logic_2D array: 

procedure insert_std_logic_2D( signal destination : inout std_logic_2D ; idx : in integer ; source : in std_logic_vector ) is begin -- select maximum to provoke an error when not equal for i in 0 to maximum(source'high , destination'high(2)) loop destination(idx , i) <= source(i) ; end loop ; end procedure ;
0 Kudos
Altera_Forum
Honored Contributor II
7,038 Views

I wouldn't call Altera's std_logic_2D type stupid. Until VHDL 2008 you could not use a 1Dx1D array in a generic way (as one dimension has to be fixed). The 2D is both elegant and pure. Altera's (and other FPGA vendors, EDA vendors included) fault was not to provide a standard library for it. With VHDL 2008 you can declare a 1D array of unconstrained std_logic_vector. And I certainly recommend this. Unfortunately I have too much legacy code to convert. (Altera did not support this either until a few versions of Quartus back, and then it once disappeared and reappeared)

0 Kudos
Altera_Forum
Honored Contributor II
7,038 Views

 

--- Quote Start ---  

I wouldn't call Altera's std_logic_2D type stupid. Until VHDL 2008 you could not use a 1Dx1D array in a generic way (as one dimension has to be fixed). The 2D is both elegant and pure. Altera's (and other FPGA vendors, EDA vendors included) fault was not to provide a standard library for it. With VHDL 2008 you can declare a 1D array of unconstrained std_logic_vector. And I certainly recommend this. Unfortunately I have too much legacy code to convert. (Altera did not support this either until a few versions of Quartus back, and then it once disappeared and reappeared) 

--- Quote End ---  

 

 

Ok, not stupid, like you said its more laziness on the part of altera. 

It could probably have put people off using the blocks.
0 Kudos
Altera_Forum
Honored Contributor II
7,038 Views

 

--- Quote Start ---  

This is going to be complicated by the fact Altera uses the altera_mf_logic_2D type in this design (instead of just making an array of std_logic_vectors like any normal person would). 

 

For a start, if you're just using two inputs, use the lpm_add_sub block instead, or just do an add in your code: 

 

a <= b + c; 

 

for parellel add, you have to map each bit individually to the bits on the bus, because of VHDL's strong typing. so: 

 

data(0,0) => dataa(0); 

data(0,1) => dataa(1); 

--etc 

 

data(1,0) => datab(0); 

data(2,0) => datab(1); 

 

For this stupid reason, I would be inclinded to write you own type conversion function: 

 

function slv_to_alteras_stupid_2d_type( a : std_logic_vector; b : std_logic_vector) return altera_mf_logic_2D is variable ret : altera_mf_logic_2D( begin for i in a'range loop ret(0,i) := a(i); ret(1,i) := b(i); end loop; return ret; end function;  

 

It could easily be modified to convert an array of std_logic_vectors into a 2d array type. 

--- Quote End ---  

 

 

Thank you tricky ! for now I will go with the lpm_add_sub. The drawback is that I have to add a leading 0 to each input signal each time I use it. 

 

By the way, using your function will introduce some delay between inputs and outputs ? 

 

Thank you for help !!
0 Kudos
Altera_Forum
Honored Contributor II
7,038 Views

Thank you as well josyb. 

 

I will take a look !! 

 

If I decide to use your procedure or the function provided by tricky how can use it in my vhdl design ?? It's c-style based ?
0 Kudos
Altera_Forum
Honored Contributor II
7,038 Views

Have a read of a VHDL tutorial on functions and how to use them. Type conversions are logic free.

0 Kudos
Altera_Forum
Honored Contributor II
7,038 Views

 

--- Quote Start ---  

Thank you tricky ! for now I will go with the lpm_add_sub. The drawback is that I have to add a leading 0 to each input signal each time I use it. 

 

--- Quote End ---  

 

 

Why do you need to add leading 0s? you can specify the input widths from the generics. you would have the same problem with the parallel add.
0 Kudos
Altera_Forum
Honored Contributor II
7,038 Views

The parallel_add returns a nbit+1 output with 2 nbit input as I can see, viceversa the lpm_add_sub gives you a nbit out whith 2 nbit input. So if I don't want to incur in overflow problems I've thought to add a 0 on each of the two inputs.. 

 

Am I right ?
0 Kudos
Altera_Forum
Honored Contributor II
7,038 Views

The add-Sub component has a cout port, which is the MSB of the output word (it also has an overflow bit)/

0 Kudos
Altera_Forum
Honored Contributor II
7,038 Views

Thank you tricky. 

 

From the lpm_guide I see that cout is defined as:  

Carry-out (borrow-in) of the most significant bit (MSB). The cout port has a physical interpretation as the carry-out (borrow-in) of the MSB. The cout port detects overflow in UNSIGNED operations. The cout port operates in the same manner for SIGNED and UNSIGNED operations. 

 

I can't really understand it very much.. Is that similar to say: 

dataa+datab == [cout dataout] ?
0 Kudos
Altera_Forum
Honored Contributor II
7,038 Views

the carry out bit is the MSB of an add function, so you are correct.

0 Kudos
Altera_Forum
Honored Contributor II
7,038 Views

Thank you tricky. I ended up with your function suggestion. 

 

One more thing, I have an entity that has a std_logic_vector input. By the way this time I have to assign it only a std_logic signal that is on output of another entity. the question is: Is it possible to do something like: 

 

stdLogicVectorIn(0)=>stdLogic 

 

And then left without assignement the other elements of stdLogicVectorIn ? 

There is a better way ? 

 

Thank you guys !! Your help is really appreciated !
0 Kudos
Altera_Forum
Honored Contributor II
7,038 Views

a std_logic_vector is an array of std_logic. 

Your method is the best way.  

But the other bits of an Input must be connected to something, even if it is '0' or '1', otherwise it is and error.
0 Kudos
Altera_Forum
Honored Contributor II
7,038 Views

Thank you tricky. The vector was a std_logic_vector( 0 downto 0). The problem was only caused by a type mismatch.. 

 

Trying to compèile the whole code there are some issues using: 

function slv_to_alteras_stupid_2d_type( a : std_logic_vector; b : std_logic_vector) return altera_mf_logic_2D is variable ret : altera_mf_logic_2D( begin for i in a'range loop ret(0,i) := a(i); ret(1,i) := b(i); end loop; return ret; end function; 

 

in the case of 

function slv_to_alteras_stupid_2d_type(bus1(18 downto 3), bus(15 downto 0)) 

 

I will try with some other attributes in the for loop.
0 Kudos
Altera_Forum
Honored Contributor II
7,038 Views

Hello guys.. ended up with  

 

function slv_to_alteras_stupid_2d_type( a : std_logic_vector; b : std_logic_vector) return altera_mf_logic_2D is variable ret : altera_mf_logic_2D(0 downto 0, (a'high-a'low) downto 0); -- the two inputs have the same size but can have different subsciript: a(16 downto 1), b(18 downto 3) variable j: integer :=0; begin for i in a'range loop ret(0,j) := a(i); j:=j+1; end loop; for i in b'range loop j:=0; ret(1,j) := b(i); j:=j+1; end loop; return ret; end function; 

 

By the way when I call 

my_par_add : parallel_add generic map (...) port map(clk=>my_clock, data=>slv_to_altera2d_type(('0' & bus1), bus2)) result=> dataout); 

running modelsim I get the following error: 

Actual expression (function call "slv_to_altera_2d_type") of formal "data" is not globally static 

 

What I am supposed to do now ?? 

 

Thank you for your help guys. have a nice day.
0 Kudos
Altera_Forum
Honored Contributor II
7,038 Views

you need to create an intermediate signal to call the function.  

 

my_intermediate_signal <= slv_to_altera2d_type(('0' & bus1), bus2)); 

 

.... 

data => my_intermediate_signal; 

 

 

But your function has errors in it. The return value has 0 downto 0 as the first dimension, but you try and access 1 when you assign to it (out of range error).
0 Kudos
Altera_Forum
Honored Contributor II
7,038 Views

Thank you tricky, finally I ended up with this: 

function slv_to_altera_2d_type(dataa : std_logic_vector; datab : std_logic_vector) return altera_mf_logic_2d is variable ret : altera_mf_logic_2D(1 downto 0,(dataa'high - dataa'low) downto 0); variable temp_dataa,temp_datab : std_logic_vector((dataa'high - dataa'low) downto 0); begin temp_dataa:=dataa; temp_datab:=datab; for i in temp_dataa'range loop ret(0,i) :=temp_dataa(i); ret(1,i) :=temp_datab(i); end loop; return ret; end function; 

 

It seems to work smoothly. 

 

One last question.. The lpm_mux uses a STD_LOGIC_2D input type. Can I assign it directly like 

input(0,16 downto 0)<=signal1(16 downto 0); input(1,16 downto 0)<=signal2(16 downto 0); 

 

Thank you all guys. have a nice day !
0 Kudos
Altera_Forum
Honored Contributor II
7,038 Views

One last question.. The lpm_mux uses a STD_LOGIC_2D input type. Can I assign it directly like 

input(0,16 downto 0)<=signal1(16 downto 0); input(1,16 downto 0)<=signal2(16 downto 0); 

 

--- Quote End ---  

 

 

No. If you could, I wouldnt have suggested the function.
0 Kudos
Altera_Forum
Honored Contributor II
6,945 Views

Yep, I thought it was only due to the alt_mf_2d type... 

 

Thank you !
0 Kudos
Reply