Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Understanding some details regarding to process in VHDL language.

Status
Not open for further replies.

FlyingDutch

Advanced Member level 1
Joined
Dec 16, 2017
Messages
457
Helped
45
Reputation
92
Reaction score
55
Trophy points
28
Location
Bydgoszcz - Poland
Activity points
4,959
Hello,

I have some doubts regarding "programming" FPGAs in VHDL language. I know that every step in simulation is performed in so called "delta" time which is equal to zero. I would like to ask how execution of Process in normal runtime of FPGA (after configuration file has been written in FPGA flash memory) is related to main clock signal of FPGA circuit?

Let assume that I have top entity of such definition:

Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity top_spi is
Port (
    clk_iT             : in  STD_LOGIC;
    en_i_LowT         : in  STD_LOGIC;
    data_ready_oT     : out STD_LOGIC;
    cs_oT             : out STD_LOGIC;
    sclk_oT         : out STD_LOGIC;
    mosi_oT         : out STD_LOGIC;
    miso_iT         : in  STD_LOGIC
);
end top_spi;


architecture Behavioral of top_spi is
 
  component lw_spi_master is
    generic (
      c_clkfreq             : integer := 12_000_000;
      c_sclkfreq             : integer := 5_000_000;
      c_cpol                : std_logic := '0';
      c_cpha                : std_logic := '0'
    );
    Port (
       clk_i             : in  STD_LOGIC;
       en_i_Low         : in  STD_LOGIC;
       mosi_data_i         : in  STD_LOGIC_VECTOR (7 downto 0);
       miso_data_o         : out STD_LOGIC_VECTOR (7 downto 0);
       data_ready_o     : out STD_LOGIC;
       cs_o             : out STD_LOGIC;
       sclk_o             : out STD_LOGIC;
       mosi_o             : out STD_LOGIC;
       miso_i             : in  STD_LOGIC
    );
  end component;

signal in_data    : std_logic_vector (7 downto 0)     := (others => '0');   
signal out_data    : std_logic_vector (7 downto 0)     := (others => '0');   
signal cnt: std_logic_vector(7 downto 0) := (others=>'0');
signal en_i_INT        : std_logic := '0';
signal valid : boolean := False;

type byte_array is array (0 to 8) of std_logic_vector(7 downto 0);
signal dane_spi : byte_array;


begin
  dane_spi(0)<= x"AA"; --170
  dane_spi(1)<= x"FF"; --255
  dane_spi(2)<= x"08"; --8
  dane_spi(3)<= x"01"; --1
  dane_spi(4)<= x"C2"; --194
  dane_spi(5)<= x"A4"; --164
  dane_spi(6)<= x"11"; --17
  dane_spi(7)<= x"66"; --146

SPI_MAS : lw_spi_master
 generic map(
    c_clkfreq  =>    27_000_000,
    c_sclkfreq  =>     5_000_000,
    c_cpol    => '0',
    c_cpha    => '0'
 )
 port map(
     clk_i           =>  clk_iT,
    en_i_Low       =>  en_i_LowT,
    mosi_data_i   =>  in_data,
    miso_data_o   =>  out_data,
    data_ready_o  =>  data_ready_oT,
    cs_o           =>  cs_oT,
    sclk_o           =>  sclk_oT,
    mosi_o           =>  mosi_oT,
    miso_i           =>  miso_iT
);

---------------------------------------------------
Change_data: process
begin
    for I in 0 to 8 loop
      in_data <= dane_spi(I);
    end loop;
end process;

end Behavioral;

I had declared array of 8 indexes of std_logic_vector((7 downto 0):
Code:
type byte_array is array (0 to 8) of std_logic_vector(7 downto 0);
signal dane_spi : byte_array;

and after begin of architecture implementation a I am giving values to dane_spi:
Code:
begin
  dane_spi(0)<= x"AA"; --170
  dane_spi(1)<= x"FF"; --255
  dane_spi(2)<= x"08"; --8
  dane_spi(3)<= x"01"; --1
  dane_spi(4)<= x"C2"; --194
  dane_spi(5)<= x"A4"; --164
  dane_spi(6)<= x"11"; --17
  dane_spi(7)<= x"66"; --146
--- Updated ---

and after that I have for loop which is assigning data from defined array dane_spi to in_data signal. see process code:
Code:
Change_data: process
begin
    for I in 0 to 8 loop
      in_data <= dane_spi(I);
    end loop;
end process;

My question is: when after that I define process wich has in sensitivity list in_data :
Code:
Check_data: process (in_data)
begin
    and here some code
end process;

How changes (transaction of in_data) will be related to main clock cycle (input: clk_i ). I am not sure if changes will be detected at all? Could I ask more experienced coleagues for claryfing that question?

Thanks in advance and Regards
 
Last edited:

Code:
Change_data: process
begin
    for I in 0 to 8 loop
      in_data <= dane_spi(I);
    end loop;
end process;
Is effectively performing
Code:
in_data <= dane_spi(8);
the assignments of dane_spi(0) to dane_spi(7) are immediately overwritten and have no effect.

In other words, the code demonstrates a basic lack of understanding sequential HDL code "execution".
 

Code:
Change_data: process
begin
    for I in 0 to 8 loop
      in_data <= dane_spi(I);
    end loop;
end process;
Is effectively performing
Code:
in_data <= dane_spi(8);
the assignments of dane_spi(0) to dane_spi(7) are immediately overwritten and have no effect.

In other words, the code demonstrates a basic lack of understanding sequential HDL code "execution".
Hello,

It is just as I thought. I assumed that this code is performed in delta zero time and has no effect.
Thanks for confirmation.

Best Regards
 

Hello,

It is just as I thought. I assumed that this code is performed in delta zero time and has no effect.
Thanks for confirmation.

Best Regards
It is nothing to do with delta zero time. You need to separate between code meant to settle at compile time and final code passed for synthesis. The compiler has a mind of its own...
The compiler sees that you want to drive a target in a loop from multiple sources. Which one? Priority is given to last statement when you unroll the loop.
 

Hi,

so it´s not the FPGA´s intention to do task step by step or clock cycle by clock cycle.
It´s the person´s job who writes the VHDL code.

.. like: do something "on every rising edge of clock"

So on the first clock edge edge it does something .. on the next clock edge it does something ... and so on.

I guess you should have a look at some tutorial videos

Klaus
 

Hi,

so it´s not the FPGA´s intention to do task step by step or clock cycle by clock cycle.
It´s the person´s job who writes the VHDL code.

.. like: do something "on every rising edge of clock"

So on the first clock edge edge it does something .. on the next clock edge it does something ... and so on.

I guess you should have a look at some tutorial videos

Klaus
Hi,

I know the theory, and I just thought that in result of given code the last array element will be assigned to in_data, but I wasn't sure. What I need is writing more code in HDL languages - both Verilog and VHDL. I am software developer for many years and I have bad habits from languages like C/C++ or Java. FPGAs are just my hobby, and I have to learn how to resolve particular problems in HDL code, like i did for languages like C or Java before. Tutorials related to FPGAs are often too general to teach such use cases. Nothing can replace experience in coding in particular language (especially HDL languages).

Thanks all for answers
 

Hi,

Try HDL not to think as software. (FOR ...LOOP is like software, where several commands are processed one after the other then all the commands are processed in a loop)

Think like hardware: Counter, FFs, gates, signals, clock.
In hardware (HDL) all signals are processed at the same time (not one after the other).

Clock:
Often just one common system clock. All FFs get this clock, just the FF_ENAble determines wheter the clock (edge) is used or not.

Example:
if the system clock is 50MHz and you want to generate a SPI with 1MHz clock frequency:
* you don´t generate a 1MHz clock that controls the shift register
* but you generate a 1MHz SPI_SHIFT_ENA signal to control the shift registers
* BUT you generate a 1MHz signal (that is not treated as FPGA_CLK) but used as SPI_SCK (= standard FPGA signal)
Mind: to generate a 1MHz signal (with a TFF for example) you need to use a 2MHz ENA signal.

Good habit:
All signals that are internally generated with combinatorial loigc but routed to pins should be "synced" with the system clock to avoid nasty glitches.

Klaus
 
It is nothing to do with delta zero time. You need to separate between code meant to settle at compile time and final code passed for synthesis. The compiler has a mind of its own...
The compiler sees that you want to drive a target in a loop from multiple sources. Which one? Priority is given to last statement when you unroll the loop.
technically, this explanation is not right. but in practice, we could say that yes, the last assignment has "priority"
 
technically, this explanation is not right. but in practice, we could say that yes, the last assignment has "priority"
It is correct. The code, as written (and corrected to have a sensitivity list) will assing the same bit over and over in the same delta from the different bits of dane_spi. Because the last one is always assigned when the process suspends, then dane_spi(8) is always assigned.
 
no assignment has priority over another, they are executed sequentially but in zero time. that is why I don't believe the explanation is technically correct. my issue is with the word priority here.
 

Yes they do. There are rules as to what is assigned based on assignment order set in VHDL LRM. Because a signal is not immediately assigned, it is scheduled to be assigned at some point in the future. Without a "after <time> " specification with the assignment, this future point is at the end of the current delta. Hence multiple assignments all get overriden and only the last one is actually assigned.
 

overwritten? yes. priority? no. they are all the same type of assignment. there is no notion of one assignment being stronger than others, which then would imply priority.
 

overwritten? yes. priority? no. they are all the same type of assignment. there is no notion of one assignment being stronger than others, which then would imply priority.
Take it easy mate...it is not a mystery. The compiler deletes what it sees as meaningless and doesn't pass it to next stage. No need to keep digging in this trivial issue. Be practical. The compiler is done by human like you and is not a mystery.
 

Hi,

in my understanding (I may be wrong..)

the above FOR ... LOOP does exist only in the source file.
The compiler does the preprocessing and finds out that only dane_spi(8) is assigned and thus all the others are ignored.
The compiler processes it in the order like in the source code, but the silicon doesn´t know about loop states 0..7 because they are removed (useless).

Consequently on the silicon there is "no time" for the loop 0..7, because it is not processed at all.

***

I wonder if one really can do an unclocked 0..8 loop on the silicon.

Klaus
 
Hi,

in my understanding (I may be wrong..)

the above FOR ... LOOP does exist only in the source file.
The compiler does the preprocessing and finds out that only dane_spi(8) is assigned and thus all the others are ignored.
The compiler processes it in the order like in the source code, but the silicon doesn´t know about loop states 0..7 because they are removed (useless).

Consequently on the silicon there is "no time" for the loop 0..7, because it is not processed at all.

***

I wonder if one really can do an unclocked 0..8 loop on the silicon.

Klaus
The FPGA vendors are very keen to fit logic in their devices and achieve speed rather than stuff it up. So a lot of effort is done at compile time to reduce and optimise unnecessary statements including extreme cases when nothing is left for target device in some Uni projects.
 

VHDL language rules don't leave any uncertainty about the behaviour of the discussed piece of code, nothing that would depend on specific tool behaviour. Part of the well defined behaviour is that the last of multiple assignments in a sequential process to the same target "wins" and the previous are disregarded.

As written in post #1, the loop statement is just useless. It could be supplemented by a condition to make useful code. E.g. only one of 9 potential assignments is "executed". A default assignment is necessary to avoid latch generation.
Code:
Change_data: process
begin
    in_data <= default_value;
    for I in 0 to 8 loop
       if condition(I) then
         in_data <= dane_spi(I);
       end if;
    end loop;
end process;
 
Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top