Forum: FPGA, VHDL & Co. frage zur Latch Beseitigung


von Stephan S. (stephan_s)


Lesenswert?

Servus!
Ich habe hier ein stück Code bei dem mir zwei Latches erzeugt werden. 
Einmal durch das Signal "segment_select" und durch "segment_output". 
Kann mir jemand von euch bitte sagen, wie ich das beheben kann? Leider 
kenne ich mich in VHDL noch nicht gut genug aus.
Hier ist der code:
1
output: process(clk, count, segment7a, segment7b, segment7c, segment7d)   begin
2
  
3
      if(count=1) then
4
        segment_select<="1110";
5
        segment_output<=segment7d;
6
        end if;
7
      if (count=2) then
8
        segment_select<="1110";
9
        segment_output<="1111111";
10
        end if;
11
      if (count=3) then
12
        segment_select<="1101";
13
        segment_output<=segment7c;
14
        end if;
15
      if (count=4) then
16
        segment_select<="1101";
17
        segment_output<="1111111";
18
        end if;
19
      if(count=5) then
20
        segment_select<="1011";
21
        segment_output<=segment7b;
22
        end if;
23
      if (count=6) then
24
        segment_select<="1011";
25
        segment_output<="1111111";
26
        end if;
27
      if (count=7) then
28
        segment_select<="0111";
29
        segment_output<=segment7a;
30
        end if;
31
      if (count=8) then
32
        segment_select<="0111";
33
        segment_output<="1111111";
34
        end if;        
35
  
36
end process;
ich hab jetzt nur den process mit den beiden signalen exportiert, ich 
hoffe das reicht.
Vielen Dank schonmal!

von Oli (Gast)


Lesenswert?

Das passiert, weil nicht in jedem Fall eine Zuordnung an segment_select 
und segment_output geschieht. Des weiteren wird die Synthese sich wohl 
darüber beschweren, dass die beiden Signale 'multiple drivers' haben - 
nämlich in jedem der if-Statements.

Du kannst beide Probleme lösen, indem du obigen Code durch eine 
if-elsif-...-elsif-else-Konstruktion ersetzt.

von P. K. (pek)


Lesenswert?

...oder noch besser: Benutze "case" und am Schluss "when others =>" für 
die Default-Festlegung. Das wird dann in einem Mux realisiert. Bei der 
"elsif"-Kette hast Du tendenziell mehr Logiklevels (aneinander gereihte 
AND), was zum Problem werden kann, wenn der Pfad zeitkritisch ist.

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


Lesenswert?

Oli schrieb:
> Du kannst beide Probleme lösen, indem du obigen Code durch eine
> if-elsif-...-elsif-else-Konstruktion ersetzt.
Aber nur, wenn Count nicht noch größer als 8 werden könnte...  :-o

Stephan S. schrieb:
> ich hab jetzt nur den process mit den beiden signalen exportiert, ich
> hoffe das reicht.
Mir nicht. Was hat in diesem Prozess der clk zu suchen?
So wie das hier aussieht, machst du was einfaches unglaublich 
kompliziert. Denn das, was da steht, ist ein ganz hübsch großer 
Multiplexer. Wolltest du sowas?

von Duke Scarring (Gast)


Lesenswert?

Oli schrieb:
> Des weiteren wird die Synthese sich wohl
> darüber beschweren, dass die beiden Signale 'multiple drivers' haben -
> nämlich in jedem der if-Statements.
Bullshit!
Dafür steht es ja im process.

Duke

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


Lesenswert?

Duke Scarring schrieb:
>> nämlich in jedem der if-Statements.
> Bullshit!
> Dafür steht es ja im process.
Und der Trick am Prozess ist, dass die letzte Signalzuweisung "gewinnt". 
Wenn man das weiß, dann kann man das auch gewinnbringend verwenden...

von Stephan S. (stephan_s)


Lesenswert?

Das CLK in der sensitivitylist ist nicht beabsichtigt... wahrscheinlich 
stammt das aus irgendeiner uralten version des codes

der count ist nur von 1 bis 8 deklariert, daher hatte ich mir gedacht da 
müsste er doch sehen, dass es andere möglichkeiten nicht gehen.
Ich hab das jetzt jetzt in ein case statement mit others umgeschrieben 
und er meckert nicht mehr. Danke!

In dem Fall habe ich jetzt verstanden, warum er gemeckert hat, aber ich 
habe hier noch einen anderen Fall, bei dem auch latches erzeugt werden:
1
comb_process: process (PS,send,actual_value,biggest_value, a_sm_b, a_eq_b, a_gt_b,headroom_buffer )
2
begin
3
  case PS is
4
    --start
5
    when ST0 =>
6
      biggest_value<=biggest_value;
7
      headroom<=headroom_buffer;
8
      headroom_buffer<=headroom_buffer;
9
      if (send ='1') then NS <=ST3;
10
      elsif (a_sm_b='1') then NS <=ST1;
11
      elsif (a_eq_b = '1' or a_gt_b='1') then NS <= ST2;
12
      else NS <= ST0;
13
      end if;
14
      --compared
15
    when ST1 =>
16
      biggest_value<=biggest_value;
17
      headroom<=headroom_buffer;
18
      headroom_buffer<=headroom_buffer;
19
      if (send ='1') then NS <=ST3;
20
      else NS <= ST0;
21
      end if;
22
      --compared
23
    when ST2 =>
24
      biggest_value<=actual_value;
25
      headroom<=headroom_buffer;
26
      headroom_buffer<=headroom_buffer;
27
      if (send = '1') then NS <= ST3;
28
      else NS <= ST0;
29
      end if;
30
      --send 
31
    when ST3 =>
32
      headroom<=biggest_value;
33
      biggest_value<=biggest_value;
34
      headroom_buffer<=biggest_value;
35
      if (send = '1') then NS <= ST3;
36
      else NS <=ST4;
37
      end if;
38
      --neustart
39
    when ST4 =>
40
      biggest_value<="000000000000";
41
      headroom<=headroom_buffer;
42
      headroom_buffer<=headroom_buffer;
43
      NS <= ST0;
44
    when others =>
45
      NS <= St0;
46
  end case;
47
end process;
in diesem fall werden drei latches erzeugt für: biggest_value, 
headroom_buffer und headroom.

zum Code:
Es geht darum, während einer bestimmten Zeitspanne (deren Ende mit 
send=1 signalisiert wird), den größten werd zu messen und diesen für 
eine spätere Ausgabe zu speichern. Es wird der Eingang(=actual_value) 
mit dem biggest_value verglichen. Dies geschieht über einen Komparator, 
der entsprechend a<b (a_sm_b), a=b (a_eq_b) und a>b (a_gt_b) auf eins 
setzt. Falls der wert größer oder gleich groß ist, wird er in 
biggest_value abgespeichert und dann im nächsten Durchgang wieder 
verglichen. Wenn nun das Signal zum senden kommt, wird der größte wert 
in headroom und headroom_buffer abgespeichert. dann geht wieder alles 
von vorne los.
Der wert headroom wird immer ausgegeben.

Ich hoffe ihr könnt mir helfen und schon mal Danke im voraus!

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


Lesenswert?

Stephan S. schrieb:
> der count ist nur von 1 bis 8 deklariert, daher hatte ich mir gedacht da
> müsste er doch sehen, dass es andere möglichkeiten nicht gehen.
Und wie ist der Count da definiert? Als Integer?

> in diesem fall werden drei latches erzeugt für: biggest_value,
> headroom_buffer und headroom.
Wieso gibt es da ein
    when others =>
       NS <= St0;
Wie ist PS definiert?

von P. K. (pek)


Lesenswert?

Die Latches sind weg, sobald Du für die betreffenden Werte ein Default 
setzt. Entweder vor dem "case"-Statement (bevorzuge ich persönlich), 
oder aber im "when others". Im Moment ist weder noch der Fall.

von Stephan S. (stephan_s)


Lesenswert?

@lkmiller
ich hab count so definiert:
1
signal count : integer range 1 to 8 :=1;

PS ist folgendermaßen deklariert:
1
  type state_type is (ST0,ST1,ST2,ST3,ST4);
2
   signal PS,NS : state_type;

soll das when others bei einer statemachine nicht verwendet werden? oder 
worauf ziehlt deine frage ab?

@pek
die signale werden von mir am anfang deklariert:
1
  signal biggest_value: std_logic_vector(11 downto 0):="000000000000";
2
  signal headroom_buffer: std_logic_vector(11 downto 0):="000000000000";
das signal headroom kommt ja von außen, wie kann ich dem einen default 
geben?

von Oli (Gast)


Lesenswert?

Lothar Miller schrieb:
> Duke Scarring schrieb:
>>> nämlich in jedem der if-Statements.
>> Bullshit!
>> Dafür steht es ja im process.
> Und der Trick am Prozess ist, dass die letzte Signalzuweisung "gewinnt".
> Wenn man das weiß, dann kann man das auch gewinnbringend verwenden...

Ok, nicht gewusst, thx! :-)

von P. K. (pek)


Lesenswert?

Stephan S. schrieb:
> @pek
> die signale werden von mir am anfang deklariert:  signal biggest_value: 
std_logic_vector(11 downto 0):="000000000000";
>
>   signal headroom_buffer: std_logic_vector(11 downto 0):="000000000000";

Das reicht eben nicht (Initialwert != Default in einem sequentiellen 
Prozess). Was ist ein Latch? Eigentlich nichts anderes als ein Speicher, 
um einen Wert zu speichern. Genau das passiert in Deinem Fall in dem 
sequentiellen Prozess, wenn nicht für jeden Clockzyklus definiert ist, 
was das Signal für einen Wert annehmen soll. Dann geht der Synthesizer 
davon aus, dass Du den alten Wert beibehalten willst => Latch.

> das signal headroom kommt ja von außen, wie kann ich dem einen default
> geben?

Bist Du sicher?

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


Lesenswert?

Stephan S. schrieb:
> soll das when others bei einer statemachine nicht verwendet werden?
Es ist bei vollständig auscodierten FSM unnötig:
http://www.lothar-miller.de/s9y/categories/25-when-others

> das signal headroom kommt ja von außen, wie kann ich dem einen default
> geben?
Ein Initialisierungswert ist was anderes als ein Defaultwert!

Ich dein Problem erkannt: du beschreibst ein Latch. Dann muss der 
Synthesizer das auch machen...
1
      headroom_buffer <= headroom_buffer; -- das ist ein klassisches explizites Latch!
Und in so einem Fall wird auch ein Defaultwert nichts helfen, denn: die 
letzte Signalzuweisung im Prozess gewinnt. Und die sagt headroom_buffer 
muss gespeichert werden.

von Stephan S. (stephan_s)


Lesenswert?

so, jetzt hab ich ein paar sachen geändert:
1
comb_process: process (PS,send,actual_value,biggest_value, a_sm_b, a_eq_b, a_gt_b,headroom_buffer )
2
begin
3
  case PS is
4
    --start
5
    when ST0 =>
6
      headroom<=headroom_buffer;
7
      if (send ='1') then NS <=ST3;
8
      elsif (a_sm_b='1') then NS <=ST1;
9
      elsif (a_eq_b = '1' or a_gt_b='1') then NS <= ST2;
10
      else NS <= ST0;
11
      end if;
12
      --compared
13
    when ST1 =>
14
      headroom<=headroom_buffer;
15
      if (send ='1') then NS <=ST3;
16
      else NS <= ST0;
17
      end if;
18
      --compared
19
    when ST2 =>
20
      biggest_value<=actual_value;
21
      headroom<=headroom_buffer;
22
      if (send = '1') then NS <= ST3;
23
      else NS <= ST0;
24
      end if;
25
      --send 
26
    when ST3 =>
27
      headroom<=biggest_value;
28
      headroom_buffer<=biggest_value;
29
      if (send = '1') then NS <= ST3;
30
      else NS <=ST4;
31
      end if;
32
      --neustart
33
    when ST4 =>
34
      biggest_value<="000000000000";
35
      headroom<=headroom_buffer;
36
      NS <= ST0;
37
  end case;
38
end process;

jetzt wird für headroom kein latch mehr erzeugt, aber für 
headroom_buffer und biggest_value immer noch.

wie gebe ich denen jetzt nen default wert? einfach im process vor dem 
case statement einen wert zuweisen? falls ja, dann hab ich eine 
Verständnisfrage zu dem process:
durch das hinzufügen des default wertes, wird doch dann bei jedem aufruf 
der process funktion diese wieder neu angewandt, oder? dadürch würde ja 
immer anfang der default wert zugewiesen werden und es sich ja dann 
keinen wert merken. in meinem fall muss ja das signal biggest_value und 
headroom_buffer gemerkt werden, bis sie bei einem sendebefehl neu 
beschrieben werden.

von P. K. (pek)


Lesenswert?

Stephan S. schrieb:
> dadürch würde ja
> immer anfang der default wert zugewiesen werden und es sich ja dann
> keinen wert merken.

Wenn Du Dir einen Wert _merken_ willst, dann brauchst Du dazu 
natürlich ein Register.

Falls es nur kombinatorische Verknüpungen sein sollen, dann brauchst Du 
vor dem "case"-Staement Default-Zuweisungen, z.B.
1
 headroom_buffer <= (others <= '0');
2
 biggest_value   <= (others <= '0');

ode im "case"-Statement ein "when others =>". Auch wenn Du alle Zustände 
auflistest, sind es nicht 2^^N, es bleiben also nach wie vor 3 
unbenutzte bis 2^^3 = 8.

von lkmiller (Gast)


Lesenswert?

Peter K. schrieb:
> Auch wenn Du alle Zustände
> auflistest, sind es nicht 2^^N, es bleiben also nach wie vor 3
> unbenutzte bis 2^^3 = 8.
Du gehst offenbar von einer binär codierten FSM aus. Bei einer 
One-hot-FSM stimmt das sicher nicht mehr. Und: hast du meinen Link von 
weiter oben schon gesehen?

von berndl (Gast)


Lesenswert?

Stephan S. schrieb:
> wie gebe ich denen jetzt nen default wert? einfach im process vor dem
> case statement einen wert zuweisen? falls ja, dann hab ich eine
> Verständnisfrage zu dem process:
> durch das hinzufügen des default wertes, wird doch dann bei jedem aufruf
> der process funktion diese wieder neu angewandt, oder? dadürch würde ja
> immer anfang der default wert zugewiesen werden und es sich ja dann
> keinen wert merken. in meinem fall muss ja das signal biggest_value und
> headroom_buffer gemerkt werden, bis sie bei einem sendebefehl neu
> beschrieben werden.

also nimm's mir nicht uebel, aber du hast kein Problem mit VHDL. Dein 
Problem scheint mir zu sein, dass du nicht weisst was
a) kombinatorische Logik
b) Latch
c) Flip-Flop
jeweils ist und wie man das in einer HDL beschreibt! Du hast oben 
geantwortet, dass du es jetzt verstanden haettest. Aber trotzdem baust 
du dir ein Latch nach dem anderen ein...

Vielleicht mal als Hinweis:
1.) Kombinatorik schreibt man am besten als 'concurrent statement'
2.) Ein Latch entsteht, wenn man ohne Takt/Clock einem Signal entweder 
gar nix zuweist oder eben den alten Wert (Latch: Zustandsgesteuerter 
Speicher!)
3.) Ein FF uebernimmt einen Logikwert aus der Prozessbeschreibung oder 
einem concurrent assignment

PS: Und lies dir mal die Antworten hier durch, da steht das auch schon 
alles!

von Vanilla (Gast)


Lesenswert?

berndl schrieb:
> jeweils ist und wie man das in einer HDL beschreibt! Du hast oben
>
> geantwortet, dass du es jetzt verstanden haettest. Aber trotzdem baust
>
> du dir ein Latch nach dem anderen ein...

Hallo Bernd,

der TO ist doch einen Schritt weiter.
Am Anfang hat er die Latches nur implizit erzeugt.

Zum Schluß schon explizit.
Das ist doch schon ein Fortschritt mit Lerneffekt für Ihn und andere die 
diesen Thread lesen.

Wo Du natürlich recht hast, ist dass der TO wohl den Unterschied 
ziwschen Register, Latches und kombinatorischer Logik noch nicht 
vollumfänlglich verinnerlicht hat.

Aber klar ist dass er ein Latch haben will , auch wenn er es sich noch 
nicht eingestanden hat...

Sein Problem im Moment ist, dass Ihm die Toolchain sagt, Latches sind 
böse und sein Code enthällt Latches.

@Stephan S
Du möchtest bei einer bestimmten Eingangskombination einen Zustand am 
ausgang festhalten?!
Das ist ein Speicherelement.

Wenn Du einen Clock hernehmen kannst um das zu synchronisieren, bist Du 
raus aus dem Schneider indem Du das ganze als (clock)synchronen Prozess 
beschreibst.
Sollte das nicht gehen, dann greift die Warnung deiner Toolchain:

Weißt Du auf was Du dich einlässt? Wenn ja dann beschreibe deine Logik 
mit einem Latch.
Hierzu musst Du allerdings einiges an Erfahrung und Wissen über den 
inneren Aufbau deines FPGAs kennen um zu wissen, was da dann draus 
synthetisiert wird...


Gruß

Vanilla

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


Lesenswert?

Vanilla schrieb:
> Aber klar ist dass er ein Latch haben will , auch wenn er es sich noch
> nicht eingestanden hat...
Aber unklar ist, ob er überhaupt eines braucht!

> Weißt Du auf was Du dich einlässt?
Lass mich mal schätzen: Nein, das weiss er nicht.

> dass Ihm die Toolchain sagt, Latches sind böse
Klar, weil sie die Laufzeiten nicht mehr zuverlässig berechnen kann, und 
weil aus einem solchen Latch gern mal eine (versteckte) kombinatorische 
Schleife wird...

von P. K. (pek)


Lesenswert?

lkmiller schrieb:
> Peter K. schrieb:
>> Auch wenn Du alle Zustände
>> auflistest, sind es nicht 2^^N, es bleiben also nach wie vor 3
>> unbenutzte bis 2^^3 = 8.
> Du gehst offenbar von einer binär codierten FSM aus. Bei einer
> One-hot-FSM stimmt das sicher nicht mehr. Und: hast du meinen Link von
> weiter oben schon gesehen?

Ja, ich ging von einer binär codierten FSM aus. Bei One-hot stimmt die 
Rechnung natürlich nicht, da hast Du noch einige unbenutzte Zustände 
mehr (alle wo mehr als ein FF den Wert 1 hat).

Bei Leuten, die ausschliesslich in FPGA zuhause sind vermutlich kein 
Problem. Verlässt man die (heile) FPGA-Welt, vielleicht weil der Code 
auch in einem ASIC zum Einsatz kommen könnte, und ist zudem "graceful 
recovery" ein Thema, macht das "when others" durchaus Sinn. Sicher 
nicht, um dort ein Error-Signal zu setzen das sonst immer '0' ist, 
sondern um z.B. eine Statemachine in einen sinnvollen Zustand 
zurückzuführen (e.g. nach IDLE).

Verlieren tut man damit auf jeden Fall sicher nichts...

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


Lesenswert?

Peter K. schrieb:
> Verlieren tut man damit auf jeden Fall sicher nichts...
Platz? Silizium?

> Verlässt man die (heile) FPGA-Welt, vielleicht weil der Code
> auch in einem ASIC zum Einsatz kommen könnte, und ist zudem "graceful
> recovery" ein Thema, macht das "when others" durchaus Sinn.
Es gibt aber in einer FSM, bei der alle definierten States verwendet 
wurden, keine anderen Zustände mehr. Es müssen also zusätzliche, nicht 
in VHDL abhandelbare Konstrukte her, die so etwas steuern könnten...
Bei Xilinx ist das in den Syntheseoptinen versteckt und heißt "Implement 
Failsafe FSM". Damit wird sichergestellt, dass unabhängig von der 
tatsächlichen Implementierung (Binär, Gray, One-Hot, ...) 
ausschliesslich die definierten Zustände auftauchen können. Von einem 
solchen Verhalten geht aber ein Simulator auf VHDL-Ebene sowieso 
zwingend aus.

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.