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

Constant declaraion with calculation in VHDL

Altera_Forum
Honored Contributor II
4,072 Views

Hi, 

I have some constants declared in VHDL with the "third one" being dependent on the value of the other two. As my experience is, that I normally forget to change the "third" when changing either one, it would be best to have the compiler to calculate the third one. Thus I declared: 

 

CONSTANT PWM_DC_min : STD_LOGIC_VECTOR (11 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(120,12); 

CONSTANT PWM_Crossover : STD_LOGIC_VECTOR (11 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(6,12); 

CONSTANT RAG_max : STD_LOGIC_VECTOR (11 DOWNTO 0) := (x"7FE"-PWM_DC_min-PWM_Crossover); 

CONSTANT RAG_min : STD_LOGIC_VECTOR (11 DOWNTO 0) := (x"802"+PWM_DC_min+PWM_Crossover); 

 

Unfortunately the compiler failed to calculate the Constants RAG_max and RAG_min correctly. Changing these constant definitions to  

 

CONSTANT RAG_max : STD_LOGIC_VECTOR (11 DOWNTO 0) := x"780"; 

CONSTANT RAG_min : STD_LOGIC_VECTOR (11 DOWNTO 0) := x"880";  

 

works perfect. 

Is there any failure in declaration or are those multiple arithmetic defintions not supported in VHDL at all? 

 

Thanks a lot,  

Carlhermann
0 Kudos
12 Replies
Altera_Forum
Honored Contributor II
2,170 Views

My suggestion is to put these within the main architecture as signals, completely determined by constants: 

 

RAG_max <= x"7FE"-PWM_DC_min-PWM_Crossover; RAG_min <= x"802"+PWM_DC_min+PWM_Crossover; I have had similar issues in the past and have resorted to this paradigm of VHDL implementation in Quartus. -James
0 Kudos
Altera_Forum
Honored Contributor II
2,170 Views

I must confess that I didn't yet come across the apparently existing problems with derived constants. They are working for me in a number of applications, may be there's something special with the involved types. 

 

Can you give more details under which conditions you see a wrong calculation? Do you know if it depends on specific Quartus versions? Did Altera confirm a Quartus bug? 

 

Thanks in advance, 

Frank
0 Kudos
Altera_Forum
Honored Contributor II
2,170 Views

Which libraries are you using? I assume that you use one or more of the SYNOPSYS libraries. In this case I suggest to use the numeric_std library instead and try the following code: 

 

LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; ENTITY constant_math IS END ENTITY constant_math; ARCHITECTURE rtl OF constant_math IS CONSTANT PWM_DC_min : std_logic_vector(11 DOWNTO 0) := std_logic_vector(to_unsigned(120, 12)); CONSTANT PWM_Crossover : std_logic_vector(11 DOWNTO 0) := std_logic_vector(to_unsigned(6, 12)); CONSTANT RAG_max : std_logic_vector(11 DOWNTO 0) := std_logic_vector(2046 - unsigned(PWM_DC_min) - unsigned(PWM_Crossover)); CONSTANT RAG_min : std_logic_vector(11 DOWNTO 0) := std_logic_vector(2050 + unsigned(PWM_DC_min) + unsigned(PWM_Crossover)); BEGIN -- ARCHITECTURE rtl END ARCHITECTURE rtl;
0 Kudos
Altera_Forum
Honored Contributor II
2,170 Views

 

--- Quote Start ---  

Which libraries are you using? I assume that you use one or more of the SYNOPSYS libraries. In this case I suggest to use the numeric_std library instead and try the following code. 

--- Quote End ---  

 

Yes the code in the initial post is apparently using legacy std_logic_arith and std_logic_unsigned, but I was'n able to reproduce the problem at first attempt with these libraries.
0 Kudos
Altera_Forum
Honored Contributor II
2,170 Views

Actually, I think the issue may be not explicitly declaring the 2047 inside the third type as unsigned. For example: 

 

constant XX : std_logic_vector(15 downto 0) := to_unsigned(2047,16) - alpha - beta, etc. 

 

I checked some code that I recently did, where I used a derived constant, and it synthesized fine.  

 

library IEEE; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.math_real.all; entity calibrate is generic (regSize : integer := 16); port( MCLK : in std_logic; HRST : in std_logic; ENABLE : in std_logic; START : in std_logic; Xin : in std_logic_vector(regSize-1 downto 0); Xout : out std_logic_vector(regSize-1 downto 0); DONE : out std_logic ); end calibrate; architecture rtl of calibrate is constant Nsamples : integer := 4; constant Z : integer := integer(ROUND(LOG2(1.0*real(Nsamples)))); constant N : integer := integer(Z) + regSize; type accumType is record val : signed(N-1 downto 0); end record; signal accum : accumType; type counterType is record start : std_logic; done : std_logic; val : integer range 0 to Nsamples-1; end record; signal counter : counterType; signal load : std_logic; signal doneDly : std_logic; begin /*-------------------------------------- Accumulate offset --------------------------------------*/ FX: process(all) begin if HRST then accum.val <= (others => '0'); elsif rising_edge(MCLK) then if load then accum.val <= (others => '0'); elsif START and not(counter.done) then accum.val <= accum.val + resize(signed(Xin),N); end if; end if; end process FX; process(all) begin if HRST then Xout <= (others => '0'); elsif rising_edge(MCLK) then if counter.done then Xout <= std_logic_vector(accum.val(N-1 downto Z)) ; end if; end if; end process; Uedge1 : entity work.POS_EDGE(rtl) port map( CLK => MCLK, HRST => HRST, X => counter.done, Y => doneDly ); Udff1 : entity work.D_FF(rtl) port map( CLK => MCLK, HRST => HRST, X => doneDly, Y => DONE ); /*-------------------------------------- Edge detect enable mode --------------------------------------*/ Uedge : entity work.POS_EDGE(RTL) port map( CLK => MCLK, HRST => HRST, X => ENABLE, Y => load ); /*------------------------------------------- Count the number of samples ---------------------------------------------*/ counter.start <= START; process(all) begin if HRST then counter.val <= 0; counter.done <= '0'; elsif rising_edge(MCLK) then if load then counter.val <= Nsamples-1; counter.done <= '0'; elsif counter.start then if counter.val > 0 then counter.val <= counter.val - 1; counter.done <= '0'; else counter.done <= '1'; end if; end if; end if; end process; end rtl;
0 Kudos
Altera_Forum
Honored Contributor II
2,170 Views

Hi all, 

well I'm currently working with Quartus II, v12.0, while the code was originally written and compiled with v11.1, SP2. I did not yet compiled with any older version to confirm this to be related to v12.0.  

The used libraries are 

 

USE IEEE.STD_LOGIC_1164.ALL; 

USE IEEE.STD_LOGIC_ARITH.ALL; 

USE IEEE.STD_LOGIC_SIGNED.ALL; 

 

The intention is that I have a control loop which has a vector "RAG" as output value, which is 12Bit, signed. This vector must be limited to the symmetric window given by RAG_max to RAG_min (with RAG_min being -RAG_max) to generate the correct output by the PWM module connected (the minimum Duty Cycle and Crossover between the PWM output are limited by connected hardware). 

RAG_max as the positive limit is +max-1 for a 12Bit signed vector (being 2047-1=2046) reduced by PWM_DC_min and PWM_Crossover, i.e. +2046-120-6=1921 or x"780" in 12Bit Hex, signed representation (x"7FE"-x"78"-x"6"). Similarly RAG_min should be the max negative value for 12 Bit signed increased by PWM_DC_min and PWM_Crossover. (RAG_min = -RAG_max would be equivalent equation). 

 

Regarding the different version of Quartus, I would have to recompile the code using 11.1SP2 (for any older version I would have to reinstall these).
0 Kudos
Altera_Forum
Honored Contributor II
2,170 Views

Instead of posting just a code snippet, could you post the file where the problem occurs? Are you sure its not a problem of localised constants?

0 Kudos
Altera_Forum
Honored Contributor II
2,170 Views

To avoid wrong conclusions of mine, can you post a code example using the said constants that shows the wrong behaviour. 

 

I guess, that the problem is caused by ambiguities of the Synopsys STD_LOGIC_SIGNED library. But it can only show in comparisons, there's no actual difference between signed or unsigned in add and sub operations. If you add X"7FF" and X"100", the result is always X"8FF", either if the results represents a signed or unsigned quantity. 

 

I asked about Quartus versions, because I tried to understand why I never faced a similar problem. But now I assume, it's due to the fact that I never use the weakly typed STD_LOGIC_XXX libraries.
0 Kudos
Altera_Forum
Honored Contributor II
2,169 Views

FvM; Yes, I would agree it is caused by the ambiguities of the ieee std_logic_signed library versus using numeric_std. In my earlier post I alluded to this; and in a derived calculation each data type must be explicitly declared, i.e. : 

 

derived_constant : std_logic_vector(15 downto 0) := to_unsigned(2047,16) - constant_1 - constant_2 

 

where ieee.numeric_std.all is declared versus signed or unsigned libraries.  

 

James
0 Kudos
Altera_Forum
Honored Contributor II
2,169 Views

Hi, 

well this is part of a VHDL File "using" a Cyclone IV EPC4CE15 by 95%. The code is neither handy nor am I allowed to post it here as whole. I agree just posting snipets makes things not easier to investigate or explain. 

Regarding the libraries used - this is a "relict" of the first lines being written somewhat 20 years ago. While the content (the "working code") changed over the years the header of the VHDL file was copied each time... 

I played around a little with the suggested nummeric_std - this requires modification of the library declaration and to the code, does it? 

(i.e. SIGNAL xyz: STD_LOGIC_VECTOR(...) changes to either SIGNAL xyz: SIGNED () or UNSIGNED (), CONV_STD_LOGIC_VECTOR changes to TO_SIGNED () or TO_UNSIGNED ()...) 

While this is a lot of work, this might be a point to review more detailled the complete code and get rid of all those "historical" constructs. 

 

Carlhermann
0 Kudos
Altera_Forum
Honored Contributor II
2,169 Views

 

--- Quote Start ---  

In my earlier post I alluded to this; and in a derived calculation each data type must be explicitly declared, i.e. : 

 

derived_constant : std_logic_vector(15 downto 0) := to_unsigned(2047,16) - constant_1 - constant_2 

 

where ieee.numeric_std.all is declared versus signed or unsigned libraries.  

--- Quote End ---  

 

 

The bit string for RAG_min that's calculated in the first expression doesn't change if the individual terms are either interpreted as signed or unsigned quantities. A problem arises, if the signedness of the constant is assumed wrong in a sign sensitive expression, e.g. a compare. Or if we imagine, that Quartus doesn't calculate the bit string but inserts the right hand side similar to a# define macro in the further calculations. 

CONSTANT RAG_min : STD_LOGIC_VECTOR (11 DOWNTO 0) := (x"802"+PWM_DC_min+PWM_Crossover); CONSTANT RAG_min : STD_LOGIC_VECTOR (11 DOWNTO 0) := x"880";  

 

 

--- Quote Start ---  

well this is part of a VHDL File "using" a Cyclone IV EPC4CE15 by 95%. The code is neither handy nor am I allowed to post it here as whole. I agree just posting snipets makes things not easier to investigate or explain. 

--- Quote End ---  

 

 

I didn't ask for the full code. The way you described the problem suggested a clearly detectable wrong evaluation of the said derived constants in a specific expression. If so, it should be possible to post a few lines that reproduce the issue. At least, the involved arithmetic operation should be known, e.g. compare, sign extension or different? Otherwise you can ask if the assumption about the nature of the problem actually holds. 

 

Personally, I'm first of all interested to know if there's a hidden Quartus problem with derived constants.  

 

For the time being, I conclude that there may be a limited problem with derived std_logic_vector constants under ieee.std_logic_signed.  

 

Thanks, 

Frank
0 Kudos
Altera_Forum
Honored Contributor II
2,169 Views

Ok, I have to blame myself and you may as well... 

I did some further checks, used the initial programming file generated with QII 11.1 SP2 and recompiled with QII 12.0 to check, if there is a difference, well there wasn't and I even did not got my problem again... 

Ok, to cut a long story short: 

The value to be limited (RAG) is calculated as 32Bit vector by 

 

RAG = kp*(FG-RG-Offset).  

 

with Kp being a gain and FG as the demand (both via CAN), RG is the actual value (by external sensors) and the Offset is measured on power up and should be nearby zero (the system is normally well trimmed). As I had to change the ADC between my development units and this prototype the Power-UP timing changed and the Offset was measured during system voltages (in the analog circuit) stabilizes (not being stable). Thus the offset was far from zero (as I believed)... To complete the list of faliures of mine, I visualized the limited RAG using a panel in CANoe (CAN-Tool), having this box configured to show IEEE values rather binary coded one...  

As I started with: I'm to blame... 

Well - normally I use the JTAG I/F during development (thus voltages are stable when FPGA starts) but (when things go wrong...) that case I had only access to the active serial I/F and thus system started from the scratch (with the voltages rising and so on). This resulted in a permanent offset which caused the switchover from -1LSB to 0 at FG = 0 and RG = 0 but at FG = -Offset... which was half the maximum (well, when things go wrong)... 

 

But: I learned that I should replace the used libraries :-) 

 

Sorry for causing confusion, 

Carlhermann
0 Kudos
Reply