- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I am using a bunch of variables to do some math. These variables, X and Y coordinates, are converted to different numeric types for ease of math operations. The outputs, Xm and Ym, are SLV's and depend on the intermediary variables Xc and Yc. Xm and Ym are simulated correctly using Quartus II 9.1 native simulator, but the intermediary variables Xp and Yp, who also depend on Xc and Yc, are not. How could this be? Here are the relevant snipets of my code:
--- use ieee.numeric_std.all; ... generic(dst_max : positive := 300000); ... Xm, Ym : out std_logic_vector(19 downto 0); ... variable d1, d2, d3, d4 : natural range 0 to dst_max; variable Xc, Yc, Xc1, Yc1, Xp, Yp : integer range -dst_max to dst_max; variable Xc_sv, Yc_sv, Xc_sv1, Yc_sv1 : signed(19 downto 0); ... elsif (d2 /= 0) and (d4 /= 0) then Xc1 := (d4 - d2); Xc_sv1 := to_signed(Xc1, 20); Xc_sv := Xc_sv1(19) & Xc_sv1(19 downto 1); -- shift right by 1 to divide by 2 Xc := to_integer(Xc_sv); else Xc := Xp; -- use previous end if; ... elsif (d1 /= 0) and (d3 /= 0) then Yc1 := (d3 - d1); Yc_sv1 := to_signed(Yc1, 20); Yc_sv := Yc_sv1(19) & Yc_sv1(19 downto 1); -- shift right by 1 to divide by 2 Yc := to_integer(Yc_sv); else Yc := Yp; end if; Xp := Xc; -- update previous Yp := Yc; -- Xp and Yp DO NOT SIMULATE CORRECTLY Xm <= std_logic_vector(to_signed(-Xc, 20)); -- move Ym <= std_logic_vector(to_signed(-Yc, 20)); -- Xm and Ym SIMULATE CORRECTLY --- Simulation Results: d1 = 1955, d2 = 300000, d3 = 158100, d4 = 23456 Xp should be -138272, but is 430016 Yp should be 78072, but is -369448 Xm is 138272 (correct) Ym is -78072 (correct) Xc* and Yc* could not be displayed by the simulatorLink Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There is nothing here to show a problem. Are you sure the problem isnt elsewhere?
Out of interest, why do you do so many conversions? If this is not the top level, why not just leave all the ports as integers? Also. If you want to divide by 2, do a divide by 2. The synthesisor will recognise it as a right shift: Yx_sv <= Yx_sc1/2;- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I didn't calculate the expectable Xp result, but I think, it can't be -138272. In the expression Xc1 := (d4 - d2), d4 and d2 are both of the natural type, so (d4-d2) causes an overflow but doesn't have a negative result.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- I didn't calculate the expectable Xp result, but I think, it can't be -138272. In the expression Xc1 := (d4 - d2), d4 and d2 are both of the natural type, so (d4-d2) causes an overflow but doesn't have a negative result. --- Quote End --- because natural is a subtype of integer, (d4-d2) is actually an integer. its only when it's assigned is range checking done, so can go negative.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- because natural is a subtype of integer, (d4-d2) is actually an integer. its only when it's assigned is range checking done, so can go negative. --- Quote End --- So you mean, (d4-d2) will get the correct numeric value? I'm not sure from which type property this could be derived. Actually, integer types are converted to signed and unsigned before synthesis, so I fear, the subtype doesn't mean anything here. Furthermore, the bit width is increased by one in the assignment. P.S.: Perhaps more important, it's impossible to guess how the code is synthesized from the shown snippets. The various variables used in the design, including d1 to d4 aren't real design objects unless they convert to registers or LE outputs.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- So you mean, (d4-d2) will get the correct numeric value? I'm not sure from which type property this could be derived. Actually, integer types are converted to signed and unsigned before synthesis, so I fear, the subtype doesn't mean anything here. Furthermore, the bit width is increased by one in the assignment. --- Quote End --- I was refering the RTL level simulation, rather than post synthesis. But yes, Quartus may keep d4 and d2 as an unsigned, and so when the subtraction occurs it may underflow before asignment into the signed variable. The safest way around this may be to keep everything in the same type (integer or signed), rather than constant changing from natural (which quartus may treat as an unsigned when converted to bits) to signed.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- There is nothing here to show a problem. Are you sure the problem isnt elsewhere? Out of interest, why do you do so many conversions? If this is not the top level, why not just leave all the ports as integers? Also. If you want to divide by 2, do a divide by 2. The synthesisor will recognise it as a right shift: Yx_sv <= Yx_sc1/2; --- Quote End --- The problem is that Xp and Yp are not simulated as expected, while Xm and Ym are. Both are derived from Xc and Yc as my previous code snippet shows: --- Xp := Xc; -- update previous Yp := Yc; -- Xp and Yp DO NOT SIMULATE CORRECTLY Xm <= std_logic_vector(to_signed(-Xc, 20)); -- move Ym <= std_logic_vector(to_signed(-Yc, 20)); -- Xm and Ym SIMULATE CORRECTLY --- The previous coordinates Xp and Yp are needed if the current coordinates Xc and Yc are invalid. This entity is not the top level, but Xm and Ym will be output pins at the top level. If I have them as output integers at this level, how do I read them to convert them to SLV's at the top level? Since you can't read outputs, can I have them as buffer integers at this level? The synthesizer really will recognize the divide by 2 as a right shift? Is this true for all powers of 2? I thought division was a very costly operation. Here's the simple math I wanted to implement: Xc = (d4-d2)/2 = (23456-300000)/2 = (-276544)/2 = -138272 Xp = Xc = -138272 Xm = -Xc = 138272 I subtyped and range-limited my variables to reduce the bits/LE's used for synthesis.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If it is a constant 2^n, then it should recognise it as a shift register.
As for why it is not working, are you doing a RTL or post-synthesis simulation?- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I am doing a post-synthesis timing simulation using Quartus 9.1 native simulator.
I changed my d# variables from type natural to (unsigned) integer. They represent distances, so cannot be negative. I got rid of the intermediary variables Xc_* and Yc_*, but kept Xm and Ym as output SLVs. But I still get the same results: d1 = 1955, d2 = 300000, d3 = 158100, d4 = 23456 Xp should be -138272, but is 430016 Yp should be 78072, but is -369448 Xm is 138272 (correct) Ym is -78072 (correct) Xc* and Yc* could not be displayed by the simulator Here's my revised code snippet: --- generic(dst_max : positive := 300000); ... Xm, Ym : out std_logic_vector(19 downto 0); ... variable d1, d2, d3, d4 : integer range 0 to dst_max; variable Xc, Yc, Xc1, Yc1, Xp, Yp : integer range -dst_max to dst_max; ... Xc1 := (d4 - d2); Xc := Xc1/2; ... Yc1 := (d3 - d1); Yc := Yc1/2; ... Xp := Xc; -- update previous center Yp := Yc; Xm <= std_logic_vector(to_signed(-Xc, 20)); -- move back to center Ym <= std_logic_vector(to_signed(-Yc, 20)); --- I don't understand how Xp and Yp have the unexpected simulation values while Xm and Ym have the correct simulation values, when both are representations of Xc and Yc.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- Xc* and Yc* could not be displayed by the simulator --- Quote End --- Yes, because they are variables. You can use signals to make them visible. My previous comment about d1 to d4 is still valid, I fear. --- Quote Start --- Perhaps more important, it's impossible to guess how the code is synthesized from the shown snippets. The various variables used in the design, including d1 to d4 aren't real design objects unless they convert to registers or LE outputs. --- Quote End --- To ask explicitely: how do you load the values for d1 to d4? --- Quote Start --- I changed my d# variables from type natural to (unsigned) integer. They represent distances, so cannot be negative. --- Quote End --- May be, but you possibly don't understand the side-effects of implicite type conversion during assignment. I think, this previous suggestion is quite reasonable. --- Quote Start --- The safest way around this may be to keep everything in the same type --- Quote End ---
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- Yes, because they are variables. You can use signals to make them visible. My previous comment about d1 to d4 is still valid, I fear. To ask explicitely: how do you load the values for d1 to d4? May be, but you possibly don't understand the side-effects of implicite type conversion during assignment. I think, this previous suggestion is quite reasonable. --- Quote End --- I do know the difference b/t variables and signals. I wanted to use variables because they don't represent HW and I don't have to wait for the clock to change them. I did try using signals before posting this thread, and got even more unexpected simulation results. But I haven't tried using signals since changing them all to integers. I'll give this a try. Here's how I load the values for d1 to d4: --- dst1, dst2, dst3, dst4 : in integer range 0 to dst_max; valid1, valid2, valid3, valid4 : in std_logic; ... if valid1 = '1' then d1 := dst1; -- same for d2, d3, d4 --- I already stated that I changed all my variables to type integer. So the only type conversion I am doing is for the outputs Xm and Ym: Xm <= std_logic_vector(to_signed(-Xc, 20)); There are no type conversions for Xp and Yp, but they are incorrect. If there's a problem w/ d1 to d4, why are Xm and Ym correct, though I had to type convert Xc and Yc?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
the fact you are doing post synthesis simulation probably explains why they are not working. Quartus is probably converting everything to a signed number during synthesis, or you are showing them in the simulator as signed when actually they are unsigned.
--- Quote Start --- I do know the difference b/t variables and signals. I wanted to use variables because they don't represent HW and I don't have to wait for the clock to change them. --- Quote End --- This shows you clearly do not understand variables. Just because they are updated immediatly does not mean they do not represent hardware. At the very least, variables may represent a wire between one register to the next. And in some circumstances they can be used to instantiate anything a signal can. Consider the following two bits of code. The first one has a single register between the input and output.
process(clk)
variable v : std_logic;
begin
if rising_edge(clk) then
v := input;
output <= v;
end if;
end process;
Now this code:
process(clk)
variable v : std_logic;
begin
if rising_edge(clk) then
output <= v;
v := input;
end if;
end process;
Now v represents an additional register in the pipeline, so there are 2 registers between the input and output instead of just 1.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The problem with variables is, that they can represent hardware, as Tricky has shown, but they can be also purely virtual, removed during synthesis. This won't be a problem normally, but if arithmetic overflows and implicite type conversions "happen" to the data, the result may be difficult to predict.
--- Quote Start --- I already stated that I changed all my variables to type integer. So the only type conversion I am doing is for the outputs Xm and Ym. --- Quote End --- As already mentioned, I see a possible overflow and an implicite type conversion in Xc1 := (d4 - d2). The input is unsigned integer and the output signed integer. As previously discussed, there's a possible ambiguousity, because the integer subtypes are synthesized as signed and unsigned by the compiler. So the synthesized result may be different from expectable integer behaviour or ModelSim simulation. What to do? You can either complain about possible incorrect synthesis of integer subtypes by Quartus, or try to avoid these ambiguousities by a clearer typing.- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page