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

Instantiating LPM Functions in VHDL: parallel adder

Altera_Forum
Geehrter Beitragender II
11.315Aufrufe

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 Antworten
Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

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.
Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

 

--- 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 ;
Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

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)

Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

 

--- 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.
Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

 

--- 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 !!
Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

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 ?
Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

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

Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

 

--- 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.
Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

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 ?
Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

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

Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

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] ?
Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

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

Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

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 !
Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

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.
Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

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.
Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

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.
Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

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).
Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

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 !
Altera_Forum
Geehrter Beitragender II
7.054Aufrufe

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.
Altera_Forum
Geehrter Beitragender II
6.961Aufrufe

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

 

Thank you !
Antworten