VHDL syn_looplimit and synthesis - vhdl

I have a problem in synthesis with my VHDL code : I am trying to get the logarithm value of an input signal S_ink:
My code :
entity ....
....
architecture rtl of myEntity is
attribute syn_looplimit : integer;
attribute syn_looplimit of loopabc : label is 16384;
logcalc:process(I_clk)
variable temp : integer;
variable log : integer;
begin
if(I_clk'event and I_clk='1') then
if (IN_rst='0') then
S_klog<=0;
temp:=0;
log:=0;
else
temp := S_ink+1; --S_ink is an input of my entity (integer)
log:=0;
loopabc:while (temp/=0) loop
temp:=temp/2;
log :=log+1;
end loop loopabc;
S_klog<=3*log;
end if;
end if;
end process;
It works very well in simulation but doesn't synthesize.
The error message is : "While loop is not terminating. You can set the maximum of loop iterations with the syn_looplimit attribute"
However, this code synthesize (but that is not what I want)
entity ....
....
architecture rtl of myEntity is
attribute syn_looplimit : integer;
attribute syn_looplimit of loopabc : label is 16384;
logcalc:process(I_clk)
variable temp : integer;
variable log : integer;
begin
if(I_clk'event and I_clk='1') then
if (IN_rst='0') then
S_klog<=0;
temp:=0;
log:=0;
else
temp := 3000; -- a random constant value
log:=0;
loopabc:while (temp/=0) loop
temp:=temp/2;
log :=log+1;
end loop loopabc;
S_klog<=3*log;
end if;
end if;
end process;

When the synthesis tool translates the design, it will make a circuit with a topology that does not depend on the data values, but where the wires carries the data values. The circuit must have a fixed calculation latency between each level of flip-flops, so timing analysis can determine if the amount of logic between flip-flops can fit for the specified frequency. In this process any loops are unrolled, and you can think of this as converting the loop to a long sequence of ordinary (non-loop) statements. To do this unrolling, the synthesis tool must be able to determine the number of iterations in the loops, so it can repeated the loop body this number of times when doing loop unrolling.
In the first code example the number of iterations in the loop depends on the S_ink value, so the synthesis tool can't unroll the loop to a fixed circuit, since the circuit depends on the data value.
In the second code example the synthesis tool can determine the number of iterations in the loop, thus do the unrolling to a fixed circuit.
One way to address this is make the algorithm with a fixed number of iteration, where this number of iterations can handle the worst case input data, and where any superfluous iteration on other input data will not change the result.

Solution :
process(I_clk)
variable temp : integer;
variable log : integer;
begin
if(I_clk'event and I_clk='1') then
if (IN_rst='0') then
S_klog<=0;
temp:=0;
log:=0;
else
temp := S_ink+1;
log:=0;
for I in 1 to 14 loop
temp := temp/2;
if (temp /=0) then
log :=log+1;
end if;
end loop;
S_klog<=3*log; -- 3*log because of my application
end if;
end if;
end process;

Related

In the below vhdl code though i have specified the range of variable it is counting endlessly. How to over come this problem

the temp variable is storing data out of its range. The range is used to store the maximum final value but it is holding the previous value and goes on incrementing. The functionality of for loop which is condition based is not satisfingenter image description here
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity counter is
Port (clk,rst:in std_logic;
o:out integer range 0 to 15
);
end counter;
architecture Behavioral of counter is
signal temp2:integer range 1 to 15:=0;
begin
process(clk) is
begin
if rising_edge(clk) then
if rst='1' then
temp2<=0;
else
for i in 1 to 15
loop
temp2<=temp2+1;
end loop;
end if;
end if;
end process;
o<=temp2;
end Behavioral;
Range puts a constraint on an object (here the signal temp2) that says it is illegal, and hence, fail if this object receives a value that is outside of the range.
Your code then must take the actions (such as mod) to make this so.
Since your code assigns the value 0, I am assuming that you need to update your declaration as follows:
signal temp : integer range 0 to 15 ;
. . .
temp2<= (temp2+1) mod 16;

Reading a txt file to array in vhdl

I want to read data from a text file one line at a time. And output at specific instance.
For that I have created to process. The code is used for generating stimulus signals in a test bench.
1st Process:-
Here we are trying to pre-read the data in an array. Also we want to count the no. of data values in one line.
data_count: process
variable anc_line : line;
variable anc_data : std_logic_vector(9 downto 0);
variable data_available : boolean;
variable result : anc_array;
variable count : integer := 0;
begin
file_open(file_anc, "file_anc.txt", read_mode); -- open file
if read_line_enable = '1' then -- read line only when it is high
readline(file_anc, anc_line); -- read 1st line
hread(anc_line, result(1), data_available); -- directing readin into the array and checking
-- data_available boolean. Return false when no data in line remain
while (data_available = true) loop -- LOops till the last data in one line is reached
for i in result'range loop -- initialising the array
hread(anc_line, anc_data, data_available); --redaing one data from the line
result(i) := anc_data;
data_counter <= count + 1; -- counting the no. of data values in one line. Will be used later
end loop;
wait until rising_edge(video_clk);
end loop;
end if;
file_close(file_anc);
wait;
end process;
2nd Process :-
Want to generate the enable signal on basis of condition. Then compare the hcount with the data_count signal to output the array. Hcout is basically a counter increasing with +1 at every clk. We output the data till the hcoutn is greater than the no. of data values in one line.
create_enable: process (video_clk)
begin
if rising_edge(video_clk) then -- creating the enable signal
if vcount = true and hcount = 0 then -- checking for conditions
read_line_enable <= '1';
else
read_line_enable <= '0';
end if;
-- insert data
if hcount <= data_counter then -- output data when condition is met
din_anc <= arr(hcount); -- output data<= array with index using hcoutn
else -- cause hcount increases from 0 to +1 at every clk
-- cycle.
din_anc <= "00"&x"20"; -- if hcount gets greater than the amnt of data in one line
-- put 20h in output
end if;
end if;
end process;
Problem?
1.Text File doesn't open.
2. Values not being read from txt to array
Summary :-
Can someone help in debugging the code. How can I read a text file to a array and then output it at specif condition. Or maybe you have some other way of doing it?

VHDL record assignment through for loop

I have a for loop in process, which works fine with std_logic arrays, but not with record arrays. I use Xilinx ISE along with ISIM and the code is vhdl-93. The target will be a Spartan 3.
Here is the record definition:
TYPE spi_rx_t IS RECORD
CS : std_logic;
MOSI : std_logic;
CLK : std_logic;
END RECORD;
constant SYNC_LATCHES : integer := 2;
Here is the array definition and declaration:
type spi_rx_array_t is array (0 to SYNC_LATCHES) of spi_rx_t;
signal spi_in_array : spi_rx_array_t;
Below is the process:
spi_in_array(0).MOSI <= SPI_MOSI;
spi_in_array(0).CLK <= SPI_CLK;
spi_in_array(0).CS <= SPI_CS;
sync_p: process (clk_100)
begin
if rising_edge(clk_100) then
-- for I in 1 to SYNC_LATCHES loop
-- spi_in_array(I) <= spi_in_array(I - 1);
-- end loop;
spi_in_array(1) <= spi_in_array(0);
spi_in_array(2) <= spi_in_array(1);
end if;
end process;
The 2 lines below the commented code works exactly as expected (allowing me to synchronize external signals to clk_100), but I'd rather implement them as a for loop (such the commented one).
However, these commented lines does not produce the same result in my ISIM test bench (spi_in_array stays in unknown state when using the for loop). Why?
Please kindly help me with this.
As commented by Morten Zilmer, this is due to the VHDL concept "longest static prefix". This SO answer is similar to my issue.
In my case, the simplest way to resolve the issue was to move the assignment of the first element of the array into the same process as the for loop. I also had to decrease SYNC_LATCHES constant from 2 to 1, because spi_in_array(0) is now latched with clk_100.
sync_p: process (clk_100)
begin
if rising_edge(clk_100) then
spi_in_array(0).MOSI <= SPI_MOSI;
spi_in_array(0).CLK <= SPI_CLK;
spi_in_array(0).CS <= SPI_CS;
for I in 1 to SYNC_LATCHES-1 loop
spi_in_array(I) <= spi_in_array(I - 1);
end loop;
end if;
end process;

Will a VHDL compiler optimise this away or not?

If I have an operation like the one below that depends on a constant parameter will the compiler see that this if statement will always be the first case and therefore optimise it away or not?
entity Thing is
generic(
constant N : integer := 32;
constant M : integer := 24
);
...
architecture behaviour of Thing is
...
process(clk)
begin
if(rising_edge(clk)) then
...
if N > M then
-- do a thing
else
-- do a different thing
end if;
...
end if;
end process;
end behaviour;
In any synthesis tool that I have used, any constants (including generics) get propagated through the design in order to produce the simplest possible output. This is good for performance in general.

Continuous assignment seemingly not working

I'm working on a FIR filter, specifically the delay line. x_delayed is initialized to all zeros.
type slv32_array is array(natural range <>) of std_logic_vector(31 downto 0);
...
signal x_delayed : slv32_array(0 to NTAPS-1) := (others => (others => '0'));
This does not work:
x_delayed(0) <= x; -- Continuous assignment
DELAYS : process(samp_clk)
begin
if rising_edge(samp_clk) then
for i in 1 to NTAPS-1 loop
x_delayed(i) <= x_delayed(i-1);
end loop;
end if; -- rising_edge(samp_clk)
end process;
But this does:
DELAYS : process(samp_clk)
begin
if rising_edge(samp_clk) then
x_delayed(0) <= x; -- Registering input
for i in 1 to NTAPS-1 loop
x_delayed(i) <= x_delayed(i-1);
end loop;
end if; -- rising_edge(samp_clk)
end process;
The problem with this "solution" is that the first element in x_delayed is delayed by one sample, which it should not be. (The rest of the code expects x_delayed(0) to be the current sample).
I'm using Xilinx ISE 13.2, simulating with ISim, but this was also confirmed simulating with ModelSim.
What gives?
Edit:
The problem was essentially that, even though x_delayed(0) didn't appear to be driven inside the process, it was.
After implementing Brian Drummond's idea it works perfectly:
x_delayed(0) <= x;
-- Synchronous delay cycles.
DELAYS : process(samp_clk)
begin
-- Disable the clocked driver, allowing the continuous driver above to function correctly.
-- https://stackoverflow.com/questions/18247955/#comment26779546_18248941
x_delayed(0) <= (others => 'Z');
if rising_edge(samp_clk) then
for i in 1 to NTAPS-1 loop
x_delayed(i) <= x_delayed(i-1);
end loop;
end if; -- rising_edge(samp_clk)
end process;
Edit 2:
I took OllieB's suggestion for getting rid of the for loop. I had to change it, since my x_delayed is indexed from (0 to NTAPS-1), but we end up with this nice looking little process:
x_delayed(0) <= x;
DELAYS : process(samp_clk)
begin
x_delayed(0) <= (others => 'Z');
if rising_edge(samp_clk) then
x_delayed(1 to x_delayed'high) <= x_delayed(0 to x_delayed'high-1);
end if; -- rising_edge(samp_clk)
end process;
Edit 3:
Following OllieB's next suggestion, it turns out the x_delayed(0) <= (others => 'Z') was unnecessary, following his previous change. The following works just fine:
x_delayed(0) <= x;
DELAYS : process(samp_clk)
begin
if rising_edge(samp_clk) then
x_delayed(1 to x_delayed'high) <= x_delayed(0 to x_delayed'high-1);
end if;
end process;
In the first case, the x_delayed(0) actually has two drivers, out outside the
process, being x_delayed(0) <= x, and an implicit one inside the DELAY
process.
The driver inside the process is a consequence of a VHDL standard concept
called "longest static prefix", described in VHDL-2002 standard (IEEE Std
1076-2002) section "6.1 Names", and the loop construction with a loop variable
i, whereby the longest static prefix for x_delayed(i) is x_delayed.
The VHDL standard then further describes drives for processes in section
"12.6.1 Drivers", which says "... There is a single driver for a given scalar
signal S in a process statement, provided that there is at least one signal
assignment statement in that process statement and that the longest static
prefix of the target signal of that signal assignment statement denotes S ...".
So as a (probably surprising) consequence the x_delayed(0) has a driver in
the DELAY process, which drives all std_logic elements to 'U' since unassigned,
whereby the std_logic resolution function causes the resulting value to be 'U',
no matter what value is driven by the external x_delayed(0) <= x.
But in the case of your code, there seems to be more to it, since there actually are some "0" values in the simulation output for x_delayed(0), for what I can see from the figures. However, it is hard to dig further into this when I do not have the entire code.
One way to see that the loop is the reason, is to manually roll out the loop by
replacing the for ... loop with:
x_delayed(1) <= x_delayed(1-1);
x_delayed(2) <= x_delayed(2-1);
...
x_delayed(NTAPS) <= x_delayed(NTAPS-1);
This is of course not a usable solution for configurable modules with NTAPS as
a generic, but it may be interesting to see that the operation then is as
intuitively expected.
EDIT: Multiple solutions are listed in "edit" sections after the question above, based on comments. A solution with variable, which allows for complex expressions if required, is shown below. If complex expression is not required, then as per OllieB's suggestion it is possible to reduce the assign to x_delayed(1 to x_delayed_dir'high) <= x_delayed(0 to x_delayed_dir'high-1):
x_delayed(0) <= x;
DELAYS : process(samp_clk)
variable x_delayed_v : slv32_array(1 to NTAPS-1);
begin
if rising_edge(samp_clk) then
for i in 1 to NTAPS-1 loop
x_delayed_v(i) := x_delayed(i-1); -- More complex operations are also possible
end loop;
x_delayed(1 to x_delayed_dir'high) <= x_delayed_v;
end if; -- rising_edge(samp_clk)
end process;
During elaboration, drivers are created for all elements in x_delayed, regardless of the range of loop iterator. Hence, x_delayed(0) has two drivers associated with it. Std_Logic and Std_Logic_Vector are resoved types(i.e., when multiple drivers are associated with the signal with these types, the resolved function will determine the value of the signal by looking up a table in std package. Please refer to VHDL Coding Styles and Methodologies for more details.
the reason you have a problem is that the logic thinks you have two things assigning into the same signal simultaneously - both the continues assignment and the register assignment loop.
keep with the register implementation.
edit
if you have modelsim, you can use the 'trace x' option and see where it comes from.
might be that the other simulator also have this feature, but for modelsim i'm certain it works
In you not working example
x_delayed(0) <= x;
is aquvalent to
process(x)
begin
x_delayed(0) <= x;
end process;
So the process will assign x_delayed(0) only when x changes. Because this is a signal asignment the x_delayed(0) will not change immediatly, it will change after a delta cycle. Therefore, when process DELAYS is called assignment for x_delayed(0) is not happened yet!
Use a variable for x_delayed in your process, if you could.
x_delayed(0) := x;

Resources