Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VHDL driving signal from different processes

Tags:

vhdl

I have a little problem with following VHDL code:

process (zbroji)
begin
    if rising_edge(zbroji) then
        oduzima <= '0';
        ucitanPrvi <= '1';
        broj1 <= ulaz_broj;
    end if;
end process;

process (oduzmi)
begin
    if rising_edge(oduzmi) then
        oduzima <= '1';
        ucitanPrvi <= '1';
        broj1 <= ulaz_broj;
    end if;

end process;

The problem is that signal ucitanPrvi always has value X. If I don't try to set it's value in two processes, then I don't have any problems ... So I know that I mustn't drive one signal from multiple processes, but I don't know how to write this differently ... Does anyone have an idea how I could resolve this problem ?

Thanks !

EDIT: Thank you all guys for replying :) Now I understand why I can't drive one signal from multiple processes (at least in the way I wanted it to work).

like image 351
xx77aBs Avatar asked Jan 31 '12 18:01

xx77aBs


People also ask

Can you have multiple processes in VHDL?

there is basically no limit in the number of processes or FSMs in a VHDL architecture.

How do I assign a signal in VHDL?

Signals are defined in the architecture before the begin statement. Variables are assigned using the := assignment symbol. Signals are assigned using the <= assignment symbol. Variables that are assigned immediately take the value of the assignment.

What is sensitivity list in VHDL?

Sensitivity lists are parameters to a process which lists all the signals that the process is sensitive to. If any of the signals change, the process will wake up, and the code within it is executed.


3 Answers

If you want to synthesize your design for a real FPGA or ASIC, you are going to have to think of VHDL in terms of real hardware (wires, flip flops, gates, etc.). Also, if you want to perform a real rising edge detect in hardware, you will need a system clock that drives a flip flop. Given your original code sample, it doesn't seem that zbroji or oduzmi are system clocks, but just std_logic signals. I wrote this code example assuming basic functionality from your example, hopefully, you can take my code and comments and accomplish what you need.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity example is
  port (Reset      : in  std_logic;
        SysClk     : in  std_logic;
        zbroji     : in  std_logic;
        oduzmi     : in  std_logic;
        ulaz_broj  : in  std_logic;
        oduzima    : out std_logic;
        ucitanPrvi : out std_logic;
        broj1      : out std_logic
        );

end example;

architecture Behavioral of example is

  -- Delayed version of input signals (1 clock cycle delay)
  signal zbroji_d : std_logic;
  signal oduzmi_d : std_logic;

  signal zbrojiRE : std_logic;
  signal oduzmiRE : std_logic;

begin

  -- Generate 1 clock cycle delayed version of
  -- signals we want to detect the rising edge
  -- Assumes active high reset
  -- Note: You should only use the rising_edge macro
  -- on an actual global or regional clock signal. FPGA's and
  -- ASICs place timing constraints on defined clock signals
  -- that make it possible to use rising_edge, otherwise, we have
  -- to generate our own rising edge signals by comparing delayed
  -- versions of a signal with the current signal.
  -- Also, with any respectable synthesizer / simulator using
  -- rising_edge is almos exactly the same as (clk'event and clk='1')
  -- except rising_edge only returns a '1' when the clock makes a
  -- valid '0' to '1' transition. (see link below)
  EdgeDetectProc : process (Reset, SysClk)
  begin
    if Reset = '1' then
      zbroji_d <= '0';
      oduzmi_d <= '0';
    elsif rising_edge(SysClk) then
      zbroji_d <= zbroji;
      oduzmi_d <= oduzmi;
    end if;
  end process EdgeDetectProc;

  -- Assert risinge edge signals for one clock cycle 
  zbrojiRE <= '1' when zbroji = '1' and zbroji_d = '0' else '0';
  oduzmiRE <= '1' when oduzmi = '1' and oduzmi_d = '0' else '0';

  -- Assumes that you want a single cycle pulse on ucitanPrvi on the
  -- rising edege of zbroji or oduzmi;
  ucitanPrvi <= zbrojiRE or oduzmiRE;

  -- Based on your example, I can't tell what you want to do with the
  -- broj1 signal, but this logic will drive broj1 with ulaz_broj on
  -- either the zbroji or oduzmi rising edge, otherwise '0'.
  broj1 <= ulaz_broj when zbrojiRE = '1' else
           ulaz_broj when oduzmiRE = '1' else
           '0';

  -- Finally, it looks like you want to clear oduzima on the rising
  -- edge of zbroji and assert oduzima on the rising edge of
  -- oduzmi
  LatchProc : process (Reset, SysClk)
  begin
    if Reset = '1' then
      oduzima <= '0';
    elsif rising_edge(SysClk) then
      if zbrojiRE = '1' then
        oduzima <= '0';
      elsif oduzmiRE = '1' then
        oduzima <= '1';
      end if;
    end if;
  end process LatchProc;

end Behavioral;

The previous code assumes you have a system clock. In a simulator like ModelSim (free student edition), you can generate a 100 MHz clock with non-synthesizable testbench code like this...

ClockProc : process
begin 
   SysClk <= '0';
   wait for 5 ns;
   SysClk <= '1';
   wait for 5 ns;
end process ClockProc;

In an actual FPGA/ASIC implementation, you will probably want to use an external oscillator that you run into your chip, drive the signal into a DCM (Digital clock manager), which will output a very clean clock signal to all of your VHDL logic, so you can have a glitch free design.

And finally, here is a great explanation on the differences between rising_edge and (clk'event and clk='1')

http://vhdlguru.blogspot.com/2010/04/difference-between-risingedgeclk-and.html

Hope that helps.

like image 153
SyllogismRXS Avatar answered Oct 16 '22 11:10

SyllogismRXS


If you drive a std_logic signal from more than one process (and remember that a continuous assignment outside of a process also creates an implied process!) then all but one of them must be driving Z onto the signal. To a first approximation, the resolution function (that decides what the final value should be) will produce Xs unless this happens.

I'm not sure how best to change your code - you need to decide when a particular process should not drive the signal and have it drive a Z at that point.


The full definition of how the multiple drivers are resolved is defined in the ieee.std_logic_1164 package and covers all possibilities, such as a 1 and an L driving etc. The IEEE get shirty about copyright, so I'm not going to post even an excerpt here, but you'll be able to find it in the source libraries of your simulator.

like image 33
Martin Thompson Avatar answered Oct 16 '22 11:10

Martin Thompson


Driving signals from multiple processes is a bad idea unless you really know what you're doing. You can re-write this code in a single process like this.

process (zbroji, oduzmi)
begin
    if rising_edge(zbroji) then
        oduzima <= '0';
        ucitanPrvi <= '1';
        broj1 <= ulaz_broj;
    end if;
    if rising_edge(oduzmi) then
        oduzima <= '1';
        ucitanPrvi <= '1';
        broj1 <= ulaz_broj;
    end if;
end process;

Note that if you do this, and you get a rising edge on both zbroji & oduzmi then oduzima will get the value 1 as it happens last in the process. Before you'd have been trying to set it to 0 and 1 at the same time. That would simulate to X, and probably wouldn't synthesize. If it did synthesize you'd be connecting power and ground together in a CMOS design.


An alternative method is to have each process drive it's own version of the signal, and then resolve them externally with what ever function you like (or another process). In this case I used or:

process (zbroji)
begin
    if rising_edge(zbroji) then
        ucitanPrvi_1 <= '1';
    end if;
end process;

process (oduzmi)
begin
    if rising_edge(oduzmi) then
        ucitanPrvi_2 <= '1';
    end if;

end process;

ucitanPrvi <= ucitanPrvi_1 or ucitanPrvi_2;
like image 40
Paul S Avatar answered Oct 16 '22 10:10

Paul S