Forum: FPGA, VHDL & Co. Schieberegister und Latch


von Karl (Gast)


Lesenswert?

Hallo,

ich möchte in einem ALTERA MAX V mehrere Schieberegister unterbrinngen. 
Der serielle Eingang wird über einen Low aktiven Chip Select gesteuert.

Hier der Code des Schieberegisters:
1
  process(nreset, ncs, sclk)
2
  variable sreg   : std_logic_vector(15 downto 0) := x"1111";
3
  begin
4
    if ncs = '1' or nreset = '0' then
5
      par_out <= sreg;
6
    elsif rising_edge(sclk) then
7
      sreg := sreg(14 downto 0) & sin;
8
    end if;
9
  end process;

Der parallele Ausgang (par_out) soll erst aktualisiert werden, wenn die 
Übertragung vorbei ist (ncs = 1).

Nun bekomme ich folgende Warnungen:

Warning (10631): VHDL Process Statement warning at 
out_shift_register.vhd(32): inferring latch(es) for signal or variable 
"par_out", which holds its previous value in one or more paths through 
the process
Warning (335093): TimeQuest Timing Analyzer is analyzing 64 
combinational loops as latches.
Warning (332060): Node: pin_ncs[0] was determined to be a clock but was 
found without an associated clock assignment.
  Info (13166): Latch 
out_shift_register:\label_parallel_output:0:label_out_shift_register_i|p 
ar_out[1]  is being clocked by pin_ncs[0]


Gibt es eine Möglichkeit die Warnungen zu beheben? nCS kann ich nicht 
zur clock machen, da alle Clock Eingänge schon belegt sind.
Oder kann ich die Warnungen ignorieren?

Viele Grüße

Karl

von Klakx (Gast)


Lesenswert?

Dein Schieberegister+Latch ist Mist :). Zuweisung auf Latch anstatt 
Reset?
Versuchs mal ohne variable.

Dieser Stil wäre etwas Compiler freudiger:
1
  process(nreset, ncs, sclk)
2
  variable sreg   : std_logic_vector(15 downto 0) := x"1111";
3
  begin
4
    if ncs = '1' or nreset = '0' then
5
      sreg <= RESET_WERT;
6
      
7
    elsif rising_edge(sclk) then
8
      sreg <= sreg(14 downto 0) & sin;
9
    end if;
10
  end process;

wie genau NCS funktionieren woll, weiß ich nicht. Kannst du die 
Schaltung zeichnen? Willst du ein Latch, dann musst du mit der Warnung 
leben, denn die mögen FPGAs in der Regel nicht.

von Gustl B. (-gb-)


Lesenswert?

1
if ncs = '1' or nreset = '0' then
2
   par_out <= sreg;
3
elsif rising_edge(sclk) then
4
   sreg := sreg(14 downto 0) & sin;
5
end if;

Das elsif ist ja nicht ein reines "anderenfalls", sondern eine 
Kombination aus "anderenfalls" und "wenn". Sowas wie "anderenfalls UND 
wenn Folgendes zutrifft ..."

Ich würde das zur besseren Lesbarkeit so schreiben
1
if ncs = '1' or nreset = '0' then
2
   par_out <= sreg;
3
else
4
   if rising_edge(sclk) then
5
      sreg := sreg(14 downto 0) & sin;
6
   end if;
7
end if;

Und ... gibt es einen Grund für den asynchronen Reset? Also braucht es 
den wirklich?

Ausserdem:

Karl schrieb:
> Warning (10631): VHDL Process Statement warning at
> out_shift_register.vhd(32): inferring latch(es) for signal or variable
> "par_out", which holds its previous value in one or more paths through
> the process

Also wo ist hier Zeile 32? Sonst ist die Fehlermeldung klar, par_out 
wird nicht in einem getakteten Prozess zugewiesen.

Du könntest das alles takten:
1
process begin
2
wait until rising_edge(sclk);
3
   if ncs = '0' then
4
      sreg := sreg(14 downto 0) & sin;
5
   else
6
      par_out <= sreg;
7
   end if;
8
end process;

: Bearbeitet durch User
von Markus F. (mfro)


Lesenswert?

Klakx schrieb:
> variable sreg   : std_logic_vector(15 downto 0) := x"1111";
> ...
>       sreg <= RESET_WERT;
> ...

Das paßt nicht.

von Der mit dem Bit tantzt (Gast)


Lesenswert?

Markus F. schrieb:
> Klakx schrieb:
>> variable sreg   : std_logic_vector(15 downto 0) := x"1111";
>> ...
>>       sreg <= RESET_WERT;
>> ...
>
> Das paßt nicht.

ist aber VHDL-technisch nicht falsch. Gemeint war aber wohl
1
constant C_SREG_RSTVAL   : std_logic_vector(15 downto 0) := (others => '1);

von Markus F. (mfro)


Lesenswert?

Der mit dem Bit tantzt schrieb:
> ist aber VHDL-technisch nicht falsch.

doch.

signal : <=
variable : :=

von Klakx (Gast)


Lesenswert?

Markus F. schrieb:
> Der mit dem Bit tantzt schrieb:
>> ist aber VHDL-technisch nicht falsch.
>
> doch.
>
> signal : <=
> variable : :=

Ich hatte gedacht, dass das sowieso klar ist und auch natürlich nicht 
"passen" wird. Die eigentliche Frage an dich war doch, ob du überhaupt 
mit einem Latch leben kannst, oder nicht? In beiden Fällen würde ich das 
anders schreiben.

Wie wärs damit:
1
  process(nreset, ncs, sclk)
2
  variable sreg   : std_logic_vector(15 downto 0) := x"1111";
3
  begin
4
    if ncs = '1' or nreset = '0' then
5
      par_out <= sreg;
6
    end if;
7
8
    if rising_edge(sclk) then
9
      sreg := sreg(14 downto 0) & sin;
10
    end if;
11
  end process;

Das ist etwas sauberer für die Simulation und lässt einen besser das 
Latch erkennen.

von daniel__m (Gast)


Lesenswert?

Klakx schrieb:
> begin
>     if ncs = '1' or nreset = '0' then
>       par_out <= sreg;
>     end if;

hi,
es ist egal, ob Variable oder Signal, oder wie das if formatiert ist, 
der Fehler ist, dass die Reset Zuweisung nicht konstant ist, also kein 
Reset ist. Stattdessen werden Daten ohne Takt übernommen, ergo Latch.

Gustl B. schrieb:
> Du könntest das alles takten:

Wäre ein korrekte, synchrone und vor allem latchfreie Version.

von Der mit dem Bit tantzt (Gast)


Lesenswert?

Markus F. schrieb:
> Der mit dem Bit tantzt schrieb:
>> ist aber VHDL-technisch nicht falsch.
>
> doch.
>
> signal : <=
> variable : :=

Stimmt, hab ich übersehen, habs als Konstantenzuweisung interpretiert.

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


Angehängte Dateien:

Lesenswert?

Karl schrieb:
> nCS kann ich nicht zur clock machen, da alle Clock Eingänge schon
> belegt sind.
Du kannst daraus natürlich einen lokalen Takt ohne Tektnetz an die 
paar beteiligten Flipflops erzeugen.

> Der parallele Ausgang (par_out) soll erst aktualisiert werden, wenn die
> Übertragung vorbei ist (ncs = 1).
Ich würde hier statt des Latches dann auch tatsächlich Flipflops 
involvieren, und den Reset gleich weglassen. Der ist unnötig, weil ja 
für die Daten sowieso noch ein Validierungs- und 
Synchronisationsmechnismus (basierend auf dem nCS Signal) folgen muss. 
Also etwa so:
http://www.lothar-miller.de/s9y/categories/26-SPI-Slave

Oder ganz ohne Prozess etwa so:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
4
entity SPIIO is
5
    Port ( sclk : in  STD_LOGIC;
6
           sin  : in  STD_LOGIC;
7
           ncs  : in  STD_LOGIC;
8
           par_out : out  STD_LOGIC_VECTOR (15 downto 0) := x"0000");
9
end SPIIO;
10
11
architecture Behavioral of SPIIO is
12
  signal sreg     : std_logic_vector(15 downto 0) := x"1111";
13
begin
14
  par_out <= sreg when rising_edge(ncs);
15
  sreg    <= sreg(14 downto 0) & sin when rising_edge(sclk);
16
end Behavioral;

Wenn die Daten intern verwendet werden sollen, dann müssen die Daten zum 
FPGA-Mastertakt einsynchronisiert werden. Am einfacvhsten geht das über 
den nCS:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
4
entity SPIIO is
5
    Port ( clk  : in  STD_LOGIC;
6
           sclk : in  STD_LOGIC;
7
           sin  : in  STD_LOGIC;
8
           ncs  : in  STD_LOGIC;
9
           par_out : out  STD_LOGIC_VECTOR (15 downto 0) := x"0000");
10
end SPIIO;
11
12
architecture Behavioral of SPIIO is
13
  signal sreg     : std_logic_vector(15 downto 0) := x"1111";
14
  signal ncssr    : std_logic_vector(2 downto 0)  := "000";
15
begin
16
  ncssr   <= ncssr(1 downto 0) & ncs when rising_edge(clk);         -- ncs auf Mastertakt einsynchronisieren
17
  sreg    <= sreg(14 downto 0) & sin when rising_edge(sclk);        -- mit lokalem sclk einschieben
18
  par_out <= sreg when ncssr(2 downto 1)="01" and rising_edge(clk); -- auf Mastertakt synchron übernehmen
19
end Behavioral;

Karl schrieb:
> Oder kann ich die Warnungen ignorieren?
Ja, denn du willst ja solche wilden Konstrukte. Wenn du dir also 
bewusst bist, was da gemacht wird, kannst du die Warnungen in den Wind 
schreiben...

BTW mein Tipp: verwende nicht unnötigerweise irgendwelche Variablen.

: Bearbeitet durch Moderator
von Karl (Gast)


Lesenswert?

Danke für die Antwort Lothar.

Lothar M. schrieb:
> Karl schrieb:
>> nCS kann ich nicht zur clock machen, da alle Clock Eingänge schon
>> belegt sind.
> Du kannst daraus natürlich einen lokalen Takt ohne Tektnetz an die
> paar beteiligten Flipflops erzeugen.

Muss ich dafür nCS im SDC-File als Clock definieren? Oder kann ich das 
Signal dann für die paar beteiligten FFs als Takt benutzen. Quartus gibt 
entsprechende Warnungen raus.


>> Der parallele Ausgang (par_out) soll erst aktualisiert werden, wenn die
>> Übertragung vorbei ist (ncs = 1).
> Ich würde hier statt des Latches dann auch tatsächlich Flipflops
> involvieren, und den Reset gleich weglassen. Der ist unnötig, weil ja
> für die Daten sowieso noch ein Validierungs- und
> Synchronisationsmechnismus (basierend auf dem nCS Signal) folgen muss.
> Also etwa so:
> http://www.lothar-miller.de/s9y/categories/26-SPI-Slave

Danke! Genau das möchte ich implementieren. In dem Beispiel benutzt du 
SS (entspricht meinem nCS) als Takt für ein FF. Kann das auch so gemacht 
werden, wenn SS (bzw. nCS) nicht auf einen CLK Eingang am FPGA 
angeschlossen ist? Und (nochmal die gleiche Frage, Sorry) muss dann SS 
als Clock definiert (bei Altera im SCD File)?


> Wenn die Daten intern verwendet werden sollen, dann müssen die Daten zum
> FPGA-Mastertakt einsynchronisiert werden. Am einfacvhsten geht das über
> den nCS:library IEEE;
> use IEEE.STD_LOGIC_1164.ALL;
>
> entity SPIIO is
>     Port ( clk  : in  STD_LOGIC;
>            sclk : in  STD_LOGIC;
>            sin  : in  STD_LOGIC;
>            ncs  : in  STD_LOGIC;
>            par_out : out  STD_LOGIC_VECTOR (15 downto 0) := x"0000");
> end SPIIO;
>
> architecture Behavioral of SPIIO is
>   signal sreg     : std_logic_vector(15 downto 0) := x"1111";
>   signal ncssr    : std_logic_vector(2 downto 0)  := "000";
> begin
>   ncssr   <= ncssr(1 downto 0) & ncs when rising_edge(clk);         --
> ncs auf Mastertakt einsynchronisieren
>   sreg    <= sreg(14 downto 0) & sin when rising_edge(sclk);        --
> mit lokalem sclk einschieben
>   par_out <= sreg when ncssr(2 downto 1)="01" and rising_edge(clk); --
> auf Mastertakt synchron übernehmen
> end Behavioral;

Nicht nötig. Es ist kein weiterer Takt vorhanden. Par_out geht direkt 
auf FPGA Outputs.

> Karl schrieb:
>> Oder kann ich die Warnungen ignorieren?
> Ja, denn du willst ja solche wilden Konstrukte. Wenn du dir also
> bewusst bist, was da gemacht wird, kannst du die Warnungen in den Wind
> schreiben...
>
> BTW mein Tipp: verwende nicht unnötigerweise irgendwelche Variablen.

Wo verwende ich unnötige variablen? Weil sreg eine Variable und kein 
Signal ist?


Danke Karl

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


Lesenswert?

Karl schrieb:
> Kann das auch so gemacht werden, wenn SS (bzw. nCS) nicht auf einen CLK
> Eingang am FPGA angeschlossen ist?
Bei Xilinx CPLDs geht genau dieses Design ohne Fehlermeldung durch. Bei 
FPGAs bekommt man zu hören, dass für Takte doch besser ein Takteingang 
zu verwenden wäre, aber wie gesagt: für solche räumlich begrenzte 
Schieberegister kann so ein Takt auch ruhig mal per Routing verdrahtet 
werden.

> Wo verwende ich unnötige variablen?
Du verwendest keine "unnötigen Variablen", sondern du verwendest 
"unnötigerweise Variablen". Das ist ein elementarer Unterschied... ;-)
> Weil sreg eine Variable und kein Signal ist?

Jepp.
Stell einfach mal deinen mentalen Default bei VHDL auf "Signal". Und 
verwende Variablen nur dort, wo sie für Beschrechungszwischenschritte 
wirklich nötig sind. Du tust dir langfristig einen Gefallen.

: Bearbeitet durch Moderator
von Karl (Gast)


Lesenswert?

Lothar M. schrieb:
> Karl schrieb:
>> Kann das auch so gemacht werden, wenn SS (bzw. nCS) nicht auf einen CLK
>> Eingang am FPGA angeschlossen ist?
> Bei Xilinx CPLDs geht genau dieses Design ohne Fehlermeldung durch. Bei
> FPGAs bekommt man zu hören, dass für Takte doch besser ein Takteingang
> zu verwenden wäre, aber wie gesagt: für solche räumlich begrenzte
> Schieberegister kann so ein Takt auch ruhig mal per Routing verdrahtet
> werden.

Beim Altera Max V (Altera führt den unnter CPLDs) bekommte ich leider 
eine entsprechende Warnung, dass nCS keine Clock ist.
Aber was ist genau die Folge davon ein normales Signal als Clock zu 
verwenden?

>> Wo verwende ich unnötige variablen?
> Du verwendest keine "unnötigen Variablen", sondern du verwendest
> "unnötigerweise Variablen". Das ist ein elementarer Unterschied... ;-)
>> Weil sreg eine Variable und kein Signal ist?
>
> Jepp.
> Stell einfach mal deinen mentalen Default bei VHDL auf "Signal". Und
> verwende Variablen nur dort, wo sie für Beschrechungszwischenschritte
> wirklich nötig sind. Du tust dir langfristig einen Gefallen.

Warum tue ich mir damit einen gefallen? Ich finde Variablen deutlich 
übersichtlicher.


Danke Karl

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


Lesenswert?

Karl schrieb:
> Warum tue ich mir damit einen gefallen?
> Ich finde Variablen deutlich übersichtlicher.
Das größte Manko: du kannst eine Variable nicht in die Sensitivliste 
eines Prozesses aufnehmen. Und das ist bei speichernden Variablen 
schlecht. Aber wiederum nur, wenn sie Latches bilden.

Siehe den Klassiker:
Beitrag "Variable vs Signal"

> Ich finde Variablen deutlich übersichtlicher.
Warum? Wofür?
Etwa nur, weil sie ihren Wert "gleich ändern" und du sie "von C kennst"?

> Beim Altera Max V (Altera führt den unnter CPLDs) bekommte ich leider
> eine entsprechende Warnung, dass nCS keine Clock ist.
> Aber was ist genau die Folge davon ein normales Signal als Clock zu
> verwenden?
Es wird nicht über ein dediziertes Taktnetz verteilt und hat deshalb 
einen größeren Skew. Aber diesen Skew kannst du bei einer handvoll 
Flipflops getrost ignorieren...

: Bearbeitet durch Moderator
von Karl (Gast)


Lesenswert?

Lothar M. schrieb:
> Das größte Manko: du kannst eine Variable nicht in die Sensitivliste
> eines Prozesses aufnehmen. Und das ist bei speichernden Variablen
> schlecht. Aber wiederum nur, wenn sie Latches bilden.

In einem Synchronen Design steht in der Sensitivliste bei mir eh immer 
nur reset und clock.

> Siehe den Klassiker:
> Beitrag "Variable vs Signal"

sollte ich mir vielleicht mal reinziehen :-)

>> Ich finde Variablen deutlich übersichtlicher.
> Warum? Wofür?
> Etwa nur, weil sie ihren Wert "gleich ändern" und du sie "von C kennst"?

NEIN. Weil ich die Variable sreg im URSPRÜNGLICHEM Beispiel NUR in dem 
einen Process brauche!

>> Beim Altera Max V (Altera führt den unnter CPLDs) bekommte ich leider
>> eine entsprechende Warnung, dass nCS keine Clock ist.
>> Aber was ist genau die Folge davon ein normales Signal als Clock zu
>> verwenden?
> Es wird nicht über ein dediziertes Taktnetz verteilt und hat deshalb
> einen größeren Skew. Aber diesen Skew kannst du bei einer handvoll
> Flipflops getrost ignorieren...

Damit kann ich in der Tat leben.

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


Lesenswert?

Karl schrieb:
> Weil ich die Variable sreg im URSPRÜNGLICHEM Beispiel NUR in dem einen
> Process brauche!
Du hast hiermit "hinten rum" meinen C-Programmierer-Verdacht bestätigt, 
denn diese Denkweise ist die typische "Funktionsaufruf mit lokalen 
Variablen"-Strategie.
Wie gesagt: lass dich auf Signale ein. Es lohnt sich. ;-)

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.