Forum: FPGA, VHDL & Co. Nicht-Spezifische Latch-Warnung


von engineer_on_tour (Gast)


Lesenswert?

Hallo zusammen,

ich arbeite mit einem XILINX Spartan 6 und bekommen bei einem scheinbar 
einfachen STateMachine-Code eine Warnung, dessen grund und Ursache ich 
nicht finden kann.

Die Warnung lautet:

Xst:3002 - This design contains one or more registers/latches that are 
directly
   incompatible with the Spartan6 architecture. The two primary causes 
of this is
   either a register or latch described with both an asynchronous set 
and
   asynchronous reset, or a register or latch described with an 
asynchronous
   set or reset which however has an initialization value of the 
opposite
   polarity (i.e. asynchronous reset with an initialization value of 1).


Könnt ihr euch einen Reim auf die Warnung machen und/oder mir sagen, was 
ich anders machen sollte?

(eine Reset aller:
if reset = '1' then
 state <= PART_1;
elsif (rising_edge(in_SPI_CS)) then ...

brings nicht)




Der entsprechende VHDL-Auszug lautet:
1
type   int_t_AllStates is (PART_1,PART_2_READ,PART_2_WRITE);
2
signal int_s_CurrentState: int_t_AllStates;
3
4
5
STATEMACHINE:process(in_SPI_CS)
6
begin
7
  if rising_edge(in_SPI_CS) then 
8
  
9
    case int_s_CurrentState is
10
    
11
      when PART_1 =>
12
        if int_DataRX = x"0060" then
13
          int_s_CurrentState <= PART_2_READ;
14
        else
15
          int_s_CurrentState <= PART_2_WRITE;
16
        end if;
17
      when PART_2_READ =>
18
        int_s_CurrentState <= PART_1;
19
      when PART_2_WRITE =>
20
        int_s_CurrentState <= PART_1;
21
      when OTHERS =>
22
        int_s_CurrentState <= PART_1;
23
    end case;
24
    
25
  end if;    
26
end process;
27
28
SIGNALMANIPULATION:process (int_s_CurrentState,i_FIFO_DataOut)
29
begin  
30
  case int_s_CurrentState is
31
  
32
    when PART_1 =>
33
      int_SlaveOut <= x"1234";
34
    when PART_2_READ =>
35
      int_SlaveOut <= i_FIFO_DataOut;
36
    when PART_2_WRITE =>
37
      int_SlaveOut <= x"5678";
38
    when OTHERS =>
39
      int_SlaveOut <= x"0000";      
40
  end case;
41
end process;

: Bearbeitet durch Moderator
von Joe (Gast)


Lesenswert?

Versuch mal
1
SIGNALMANIPULATION:process (int_s_CurrentState,i_FIFO_DataOut)
2
begin
3
  int_SlaveOut <= x"0000";
4
5
  case int_s_CurrentState is
6
    when PART_1 =>
7
      int_SlaveOut <= x"1234";
8
    when PART_2_READ =>
9
      int_SlaveOut <= i_FIFO_DataOut;
10
    when PART_2_WRITE =>
11
      int_SlaveOut <= x"5678";     
12
  end case;
13
end process;



Joe

von engineer_on_tour (Gast)


Lesenswert?

Hi Joe,

das hat leider keine Änderung gebracht :(

von abcd (Gast)


Lesenswert?

Ich hab keine Ahnung von VHDL, nur Verilog, also haut mich bitte nicht 
:-)

Der Prozess "SIGNALMANIPULATION" ist doch kombinatorisch. D.h. alle 
signale die sich ändern müssen in die Sensitivity list, sonst wirds ein 
latch.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

engineer_on_tour schrieb:
> rising_edge(in_SPI_CS)
Sorgenfalten machen sich auf der Stirn breit...
Wieviele Takte hast du? Wie synchronisiertst du die Übergänge?

> bekommen bei einem scheinbar einfachen STateMachine-Code eine Warnung,
> dessen grund und Ursache ich nicht finden kann.
Ich vermute stark, der Fehler liegt ausserhalb des geposteten 
Codeausschnittes...

> or a register or latch described with an asynchronous set or reset
> which however has an initialization value of the opposite polarity
> (i.e. asynchronous reset with an initialization value of 1).
> Könnt ihr euch einen Reim auf die Warnung machen...?
Das ist sowas:
1
   signal s : std_logic := '1';
2
3
   if reset='1' then
4
      s <= '0';
5
   else
6
      :
7
      :
8
   end if;


abcd schrieb:
> Der Prozess "SIGNALMANIPULATION" ist doch kombinatorisch. D.h. alle
> signale die sich ändern müssen in die Sensitivity list, sonst wirds ein
> latch.
Falsch.
In die Sensitivliste müssen alle die Signale, die eine Änderung eines 
andere Wertes bewirken. Dann berechnet der Simulator bei einer 
Änderung des Wertes in der Sensitivliste die Ergebnisse des Prozesses 
neu.
Der Synthese (die oben die Warnung erzeugt) schert sich einen feuchten 
Kehrricht um eine unvollständige Sensitivliste. Sie erweitert diese 
Leiste einfach eigenständig.
Mit der Sensitivliste kann also das Verhalten des FPGAs in keiner Weise 
gesteuert werden.

: Bearbeitet durch Moderator
von user (Gast)


Lesenswert?

ich würde mal das Signal i_FIFO_DataOut genauers anschauen

das wird aufjedenfall hier zugewiesen

 when PART_2_READ =>
      int_SlaveOut <= i_FIFO_DataOut;

von engineer_on_tour (Gast)


Lesenswert?

user schrieb:
> ich würde mal das Signal i_FIFO_DataOut genauers anschauen
>
> das wird aufjedenfall hier zugewiesen
>
>  when PART_2_READ =>
>       int_SlaveOut <= i_FIFO_DataOut;

Wird diese Zuweisung nicht verwendet, tritt die Wranung dennoch auf.



Lothar Miller schrieb:
> Ich vermute stark, der Fehler liegt ausserhalb des geposteten
> Codeausschnittes...

Dann poste ich einfach mal den gesamten Code. Es handelt sich um eine 
Erweiterung einer funtionierenden SPI-Slave-Instanz. Diese soll immer 
mit zwei Nachrichten (Befehl + Daten) oder (Anfrage + Antwort) 
angesprochen werden und je nach Befehl/Anfrage reagieren. Daher wird 
nach dem ersten empfangenen Datenpaket getestet:

if int_DataRX = x"0060" then
          int_s_CurrentState <= PART_2_READ;
        else
          int_s_CurrentState <= PART_2_WRITE;

Der komplette Code hier:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
4
5
6
entity cSPI is
7
  port
8
  (
9
    in_SPI_Clock            :   in    STD_LOGIC;
10
    in_SPI_Mosi              :   in   STD_LOGIC;
11
    out_SPI_Miso            :   out  STD_LOGIC;
12
    in_SPI_Cs              :   in   STD_LOGIC;  
13
    
14
    i_FIFO_DataOut            :   in    STD_LOGIC_VECTOR (16-1 downto 0);    
15
      
16
    o_SPI_ReceivedData        :   out  STD_LOGIC_VECTOR (16-1 downto 0);
17
    o_SPI_Wr_Clk            :   out   STD_LOGIC;    
18
    o_SPI_Rr_Clk            :   out   STD_LOGIC  
19
  );
20
end cSPI;
21
22
23
24
25
architecture VERHALTEN of cSPI is
26
----------------------------------
27
signal int_DataRx   : STD_LOGIC_VECTOR (16-1 downto 0); 
28
signal int_DataTx   : STD_LOGIC_VECTOR (16-1 downto 0);
29
signal int_SlaveOut   : STD_LOGIC_VECTOR (16-1 downto 0);
30
31
32
33
type   int_t_AllStates     is   (    
34
                          PART_1,                          
35
                          PART_2_READ,                          
36
                          PART_2_WRITE
37
                      );
38
signal int_s_CurrentState      :     int_t_AllStates:=PART_1;
39
40
41
----------------------------------
42
begin
43
-----------------------------------------------------------------------------
44
RX:process(in_SPI_Clock,in_SPI_CS)
45
begin
46
  if falling_edge(in_SPI_Clock) then                  
47
    if (in_SPI_CS = '0') then                  
48
      int_DataRx <= int_DataRx(16-2 downto 0) & in_SPI_MOSI;
49
    end if;
50
  end if;
51
end process;
52
-----------------------------------------------------------------------------
53
TX:process(in_SPI_CS, in_SPI_Clock,int_SlaveOut)   
54
begin
55
  if (in_SPI_CS='1') then
56
    int_DataTx <= int_SlaveOut;
57
  elsif rising_edge(in_SPI_Clock) then                  
58
    int_DataTx <= int_DataTx(16-2 downto 0) & '0';
59
  end if;
60
end process;
61
-----------------------------------------------------------------------------
62
out_SPI_Miso <= int_DataTx(15) when in_SPI_Cs='0' else 'Z';  
63
-----------------------------------------------------------------------------
64
RXCS:process(in_SPI_CS)
65
begin
66
  if rising_edge(in_SPI_CS) then 
67
    o_SPI_ReceivedData <= int_DataRX;    
68
  end if;
69
end process;
70
-----------------------------------------------------------------------------
71
-----------------------------------------------------------------------------
72
-----------------------------------------------------------------------------
73
STATEMACHINE:process(in_SPI_CS)
74
begin
75
  if rising_edge(in_SPI_CS) then
76
77
    case int_s_CurrentState is
78
79
      when PART_1 =>
80
        if int_DataRX = x"0060" then
81
          int_s_CurrentState <= PART_2_READ;
82
        else
83
          int_s_CurrentState <= PART_2_WRITE;
84
        end if;
85
      when PART_2_READ =>
86
        int_s_CurrentState <= PART_1;
87
      when PART_2_WRITE =>
88
        int_s_CurrentState <= PART_1;
89
      when OTHERS =>
90
        int_s_CurrentState <= PART_1;
91
    end case;
92
93
  end if;
94
end process;
95
-------------------------------------------------------------------------------
96
-------------------------------------------------------------------------------
97
-------------------------------------------------------------------------------
98
SIGNALMANIPULATION:process (int_s_CurrentState,i_FIFO_DataOut)
99
begin
100
101
  case int_s_CurrentState is
102
    when PART_1 =>
103
      int_SlaveOut <= x"1234";
104
    when PART_2_READ =>
105
      int_SlaveOut <= i_FIFO_DataOut;
106
    when PART_2_WRITE =>
107
      int_SlaveOut <= x"5678"; 
108
   when OTHERS =>
109
    int_SlaveOut <= x"FFFF";     
110
  end case;
111
end process;
112
113
-------------------------------------------------------------------------------
114
115
o_SPI_Wr_Clk <= in_SPI_Cs; 
116
117
o_SPI_Rr_Clk <= in_SPI_Cs when int_s_CurrentState=PART_2_READ else '1'; 
118
119
end VERHALTEN;

: Bearbeitet durch Moderator
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

engineer_on_tour schrieb:
> Dann poste ich einfach mal den gesamten Code.
1
Wichtige Regeln - erst lesen, dann posten!
2
    Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
Seis drum...

> when PART_2_READ =>
>   int_SlaveOut <= i_FIFO_DataOut;
> Wird diese Zuweisung nicht verwendet, tritt die Wranung dennoch auf.
Weil int_SalveOut verwendet wird. Ich hab ihn:
1
  if (in_SPI_CS='1') then
2
    int_DataTx <= int_SlaveOut;
3
  elsif rising_edge(in_SPI_Clock) then                  
4
    :
Ein nicht konstanter Resetwert. Sowas ist mit den Flipflops in einem 
FPGA nicht möglich...

: Bearbeitet durch Moderator
von engineer_on_tour (Gast)


Lesenswert?

Lothar Miller schrieb:
> Wichtige Regeln - erst lesen, dann posten!
>     Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Aso, dann weiß ich für die Zukunft bescheid :)

Lothar Miller schrieb:
> Weil int_SalveOut verwendet wird. ... Ein nicht konstanter Resetwert.

Verstehe ich das richtig (leider habe ich nicht die Zeit, in aller ruhe 
VHDL zu lernen und muss es "leaning by doing" im Schnellverfahren 
lernen), dass sich der Wert int_SlaveOut theoretisch während des 
TX-Prozesses veränden kann und so zu diesem Fehler führt?

Anders gefragt: Wie kann ich es realisieren, dass je nach Zustand ein 
anderer Wert über den MISO-Kanal gesendet wird?

von Fpgakuechle K. (Gast)


Lesenswert?

engineer_on_tour schrieb:
> Lothar Miller schrieb:
>> Wichtige Regeln - erst lesen, dann posten!
>>     Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
>
> Aso, dann weiß ich für die Zukunft bescheid :)
>
> Lothar Miller schrieb:
>> Weil int_SalveOut verwendet wird. ... Ein nicht konstanter Resetwert.
>
> Verstehe ich das richtig (leider habe ich nicht die Zeit, in aller ruhe
> VHDL zu lernen und muss es "leaning by doing" im Schnellverfahren
> lernen), dass sich der Wert int_SlaveOut theoretisch während des
> TX-Prozesses veränden kann und so zu diesem Fehler führt?

In Hardware denken bitte!

Die Fehlermeldung besagt, das kein Flipflop beschrieben wurde sondern 
ein Latch.
Verkürzt dargestellt
Ein FF hat einen D- Eingang , dessen wert wird beim Eintreffen der 
taktflanke ( rising_edge() abgespeichert und an FF-Ausgang Q 
wiedergegeben.

IN VHDL beschrieben sieht das (verkürzt) so aus
1
 if rising_edge(clk) then
2
  Q <= D;

Daneben hat es noch RESET/SET- Eingänge, die bewirken das unabhängig von 
D die Speicherzelle auf '0' (when RESET Eingang aktiv) oder auf '1' 
(when SET eingang aktiv) gesetzt wird.
in VHDL sieht das so aus:
1
IF    R = '1' then Q <= '0' ;
2
elsif S = '1' then Q <= '1';
3
end if;

was du dagegen beschreibst ist kein FF (flankensensitiv) sondern ein 
Latch (zustandsgesteuert) deswegen warnt dich die Synthese.
Willst du ein Latch oder ein Flipflop hier?

MfG,

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

engineer_on_tour schrieb:
> dass sich der Wert int_SlaveOut theoretisch während des TX-Prozesses
> veränden kann und so zu diesem Fehler führt?
Nein, es liegt primär daran, dass es keinen "Load"-Eingang an einem 
FPGA-Flipflop gibt.

> Anders gefragt: Wie kann ich es realisieren, dass je nach Zustand ein
> anderer Wert über den MISO-Kanal gesendet wird?
Entweder baust du das gesamte Design auf eine synchrone Datenübertragung 
um oder du akzeptierst diese "Unsauberkeit" an dieser Stelle. Du weißt 
ja, woher der Fehler kommt...

engineer_on_tour schrieb:
> eine Erweiterung einer funtionierenden SPI-Slave-Instanz.
Schön, dass die funktioniert, die kommt mir bekannt vor...   ;-)
Und was wurde erweitert? Trat vor der Erweiterung diese Warnung nicht 
auf? Was war da anders?

von engineer_on_tour (Gast)


Lesenswert?

Hallo Lothar,

ich habe einen Workaround gefunden und denken, damit jetzt weiter 
arbeiten zu können.

Den problematischen Teil

 case int_s_CurrentState is
    when PART_1 =>
      int_SlaveOut <= x"1234";
    when PART_2_READ =>
      int_SlaveOut <= i_FIFO_DataOut;
    when PART_2_WRITE =>
      int_SlaveOut <= x"5678";
   when OTHERS =>
    int_SlaveOut <= x"FFFF";
  end case;
end process;


lasse ich vorläufig weg und werde diesen eventuell später anderweitig 
implementieren (zumindest versuche ich es). Aber da das nicht Prio 1 ist 
mache ich erst mal mit anderen Dingen weiter.

In jedem fall vielen Dank für deine Hilfe! ... So konnte ich schnell 
erkennen, was der Fehler ist und mich für ein weiteres Vorgehen 
entscheiden.

von engineer_on_tour (Gast)


Lesenswert?

Hallo zusammen,

ich konnte das Problem nun auf die eigentliche SPI eingrenzen, die ein 
Problem hat, sobald die zu senden Daten (i_TxData) nicht mehr konstant 
sind (sondern sich je nach empfangenen Daten oder Zustand ändern 
sollen).

TX:process(in_CLK)--,i_TxData,in_CS)
begin
  if (in_CS='1') then
    int_DataTx <= i_TxData;
  elsif rising_edge(in_CLK) then
    int_DataTx <= int_DataTx(16-2 downto 0) & '0';
  end if;
end process;

Jetzt mache ich mich endweder auf die Suche nach einer anedren 
SPI-Implementierung oder muss selber eine schreiben.

von Fpgakuechle K. (Gast)


Lesenswert?

engineer_on_tour schrieb:
> Hallo zusammen,
>
> ich konnte das Problem nun auf die eigentliche SPI eingrenzen, die ein
> Problem hat, sobald die zu senden Daten (i_TxData) nicht mehr konstant
> sind (sondern sich je nach empfangenen Daten oder Zustand ändern
> sollen).
>
> TX:process(in_CLK)--,i_TxData,in_CS)
> begin
>   if (in_CS='1') then
>     int_DataTx <= i_TxData;
>   elsif rising_edge(in_CLK) then
>     int_DataTx <= int_DataTx(16-2 downto 0) & '0';
>   end if;
> end process;
>
> Jetzt mache ich mich endweder auf die Suche nach einer anedren
> SPI-Implementierung oder muss selber eine schreiben.

Das ist IMHO keine reguläre Beschreibung eines Schieberegisters oder 
eines Registers überhaupt. Da steckt genau wieder der der nichtkonstante 
Reset drin. Rausstreichen aus der sensitive List bewirkt da keine 
Verbesserung.
Vorschlag: Zeichne ein Blockbild deines SPI-Interfaces. Vergleiche das 
mit Blockbildern anderer SPI-Interfaces und identifiziere so die 
Signale:

-systemtakt
-systemreset
-parallele Daten rein/raus

-SPI serielle Daten rein
-SPI serielle Daten raus
-SPI Chipselect
-SPI bit clock

Insbesonders der Unterschied zwischen SPI bit-takt und FPGA Systemtakt 
scheint dir nicht ganz bewußt zu sein.

Davon ausgehend schreibe eine Entity (portliste). Und erst dann kann man 
anfangen hinter dieser Portliste ein parallel zugreifbares 
Schieberegister zu beschreiben (den mehr ist SPI im Kern nicht).

MfG,

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

engineer_on_tour schrieb:
> ich konnte das Problem nun auf die eigentliche SPI eingrenzen, die ein
> Problem hat, sobald die zu senden Daten (i_TxData) nicht mehr konstant
> sind.
Ja, weil die Flipflops des FPGAs (wie oben schon erwähnt) keinen 
Load-Eingang haben. Aber weil dir der Grund bekannt ist kannst du die 
Warnung hier ignorieren.

> Jetzt mache ich mich endweder auf die Suche nach einer anedren
> SPI-Implementierung oder muss selber eine schreiben.
Mach dir die Ursache des Problems klar, dann wirst du erkennen: so 
richtig einfach wird das nicht, wenn der SPI-Takt tatsächlich gleich der 
Schiebetakt sein soll.
Wenn der SPI Takt hinreichend langsam ist, dann kannst du das übliche 
Verfahren mit Einsynchronisieren und schnellem Masterclock (3-4 mal 
höher) machen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.