Forum: FPGA, VHDL & Co. FSM möglichst einfach und übersichtlich


von Sally (Gast)


Lesenswert?

Hallo Forum!

Ich möchte hier jetzt keinen Glaubenskrieg hervorrufen, sondern 
lediglich ein paar dritte Meinungen einholen.

Ich designe Logic jetzt schon seit ein paar Jahren und habe in der Zeit 
viele verschiedene Sitle gesehen in denen man FSMs schreiben kann. Ganz 
früher habe ich die Ein-Prozess-Schreibweise verwendet, da ich vorher 
hauptsächlich in C++ programmiert habe. Das sah dann z.B. so aus:

1
  state_selector: process (clk, reset) is
2
  begin
3
    if reset = '0' then
4
      state <= r;
5
    elsif rising_edge(clk) then
6
      case state is
7
        when y =>
8
          state <= r;
9
          red <= '0';
10
          yellow <= '1';
11
          green <= '0';
12
        when g =>
13
          state <= y;
14
          red <= '0';
15
          yellow <= '0';
16
          green <= '1';
17
        when ry =>
18
          state <= g;
19
          red <= '1';
20
          yellow <= '1';
21
          green <= '0';
22
        when r =>
23
          state <= ry;
24
          red <= '1';
25
          yellow <= '0';
26
          green <= '0';
27
        when others => null;
28
      end case;
29
    end if;
30
  end process state_selector;

Irgendwann fand ich das dann zu unübersichtlich und habe auf die 
Zwei-Prozess-Schreibweise gewechselt:

1
  state_selector: process (clk, reset) is
2
  begin
3
    if reset = '0' then
4
      state <= r;
5
    elsif rising_edge(clk) then
6
      case state is
7
        when y => state <= r;
8
        when g => state <= y;
9
        when ry => state <= g;
10
        when r => state <= ry;
11
        when others => null;
12
      end case;
13
    end if;
14
  end process state_selector;
15
16
  output_generator: process (clk, reset) is
17
  begin
18
    if reset = '0' then
19
      red <= '1';
20
      yellow <= '0';
21
      green <= '0';
22
    elsif clk'event and clk = '1' then  -- rising clock edge
23
      case state is
24
        when r =>
25
          red <= '1';
26
          yellow <= '0';
27
          green <= '0';
28
        when y =>
29
          red <= '0';
30
          yellow <= '1';
31
          green <= '0';
32
        when g =>
33
          red <= '0';
34
          yellow <= '0';
35
          green <= '1';
36
        when ry =>
37
          red <= '1';
38
          yellow <= '1';
39
          green <= '0';
40
        when others => null;
41
      end case;
42
    end if;
43
  end process output_generator;

Während der erste Prozess jetzt schön übersichtlich ist, gefiel mir der 
zweite Prozess noch nicht wirklich. Vor allem, weil dort immer noch sehr 
viele redundante Signal-Zuweisungen sind, die viel Schreibarbeit 
bedeuten.
Also habe ich später den zweiten Prozess in ein conditional assignment 
umgeformt:

1
  state_selector: process (clk, reset) is
2
  begin
3
    if reset = '0' then
4
      state <= r;
5
    elsif rising_edge(clk) then
6
      case state is
7
        when y => state <= r;
8
        when g => state <= y;
9
        when ry => state <= g;
10
        when r => state <= ry;
11
        when others => null;
12
      end case;
13
    end if;
14
  end process state_selector;
15
16
  red <= '1' when state = r or state = ry else '0';
17
  yellow <= '1' when state = y or state = ry else '0';
18
  green <= '1' when state = g else '0';

Das ist schon mal bedeutet kürzer und übersichtlicher. Jedoch nicht ohne 
Nachteile: Zum einen sind die Ausgangssignale (red, yellow, green) nicht 
mehr synchron, was bei komplizierteren whens eventuell ein Problem sein 
könnte. Und zum anderen started die FSM nach dem Reset jetzt nicht mehr 
im State r sondern im State y. Die Funktionalität ist also anders.
Zumindest letzteres ließ sich relativ einfach fixen, indem man die 
Schreibweise für den zweiten Prozess auch für den ersten übernimmt:

1
  state_transition: process (clk, reset) is
2
  begin
3
    if rising_edge(clk) then
4
      state <= next_state;
5
    end if;
6
  end process state_transition;
7
8
  next_state <= r when state = y or reset = '0' else
9
                y when state = g else
10
                g when state = ry else
11
                ry when state = r else
12
                state;
13
14
  red <= '1' when state = r or state = ry else '0';
15
  yellow <= '1' when state = y or state = ry else '0';
16
  green <= '1' when state = g else '0';

die FSM startet jetzt wieder im State r und das ganze ist sogar noch mal 
eine Zeile kürzer. Die Ausgänge sind aber leider immer noch nicht 
synchron. Also habe ich hinter den zweiten Prozess noch ein paar 
Register gehängt und frage next_state anstatt state ab:

1
  state_transition: process (clk, reset) is
2
  begin
3
    if rising_edge(clk) then
4
      state <= next_state;
5
    end if;
6
  end process state_transition;
7
8
  next_state <= r when state = y or reset = '0' else
9
                y when state = g else
10
                g when state = ry else
11
                ry when state = r else
12
                state;
13
14
  red_tmp <= '1' when next_state = r or next_state = ry else '0';
15
  yellow_tmp <= '1' when next_state = y or next_state = ry else '0';
16
  green_tmp <= '1' when next_state = g else '0';
17
18
  output_selector: process (clk, reset) is
19
  begin
20
    if rising_edge(clk) then
21
      red <= red_tmp;
22
      yellow <= yellow_tmp;
23
      green <= green_tmp;
24
    end if;
25
  end process output_selector;

So scheint jetzt alles gut zu sein, denke ich. Oder? Natürlich wäre es 
schön, wenn man stattdessen folgendes schreiben könnte:

1
  state_transition: process (clk, reset) is
2
  begin
3
    if rising_edge(clk) then
4
      state <= next_state;
5
    end if;
6
  end process state_transition;
7
8
  next_state <= r when state = y or reset = '0' else
9
                y when state = g else
10
                g when state = ry else
11
                ry when state = r else
12
                state;
13
14
15
  output_selector: process (clk, reset) is
16
  begin
17
    if rising_edge(clk) then
18
      red <= '1' when next_state = r or next_state = ry else '0';
19
      yellow <= '1' when next_state = y or next_state = ry else '0';
20
      green <= '1' when next_state = g else '0';
21
    end if;
22
  end process output_selector;

oder gar:

1
  state_transition: process (clk, reset) is
2
  begin
3
    if rising_edge(clk) then
4
      state <= r when state = y or reset = '0' else
5
               y when state = g else
6
               g when state = ry else
7
               ry when state = r else
8
               state;
9
    end if;
10
  end process state_transition;
11
12
  output_selector: process (clk, reset) is
13
  begin
14
    if rising_edge(clk) then
15
      red <= '1' when state = r or state = ry else '0';
16
      yellow <= '1' when state = y or state = ry else '0';
17
      green <= '1' when state = g else '0';
18
    end if;
19
  end process output_selector;

Aber das geht wohl erst in VHDL 2008, meint fuse:

1
ERROR:HDLCompiler:1690 - "fsmX.vhd" Line 25: This construct is only supported in VHDL 1076-2008
2
ERROR:HDLCompiler:1690 - "fsmX.vhd" Line 36: This construct is only supported in VHDL 1076-2008
3
ERROR:HDLCompiler:1690 - "fsmX.vhd" Line 37: This construct is only supported in VHDL 1076-2008
4
ERROR:HDLCompiler:1690 - "fsmX.vhd" Line 38: This construct is only supported in VHDL 1076-2008
5
ERROR:HDLCompiler:854 - "fsmX.vhd" Line 15: Unit <behav> ignored due to previous errors.

Schade, aber das kann man nichts machen. (Oder können die Xilinx Tools 
VHDL 2008? Wenn ja, welche Command Line Switches brauche ich da?)


Naja, wie auch immer. Welche von den schreibweisen gefällt euch denn am 
besten bzw. welche benutzt ihr meistens? Ich benutze momentan meistens 
Schreibweise 4 oder 5, je nachdem ob es wichtig ist, dass die 
Ausgangssignale synchron sein müssen oder nicht. Die Schreibweisen habe 
ich bisher aber sonst nirgens gesehen. Woran könnte das liegen?

Grüße,
Sally

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


Lesenswert?

Sally schrieb:
> Welche von den schreibweisen gefällt euch denn am
> besten bzw. welche benutzt ihr meistens?
Die allererste. Weil da jeder auf Anhieb sofort sieht, was gemeint ist. 
Alles Nachfolgende ist nur noch verwaschener und verbastelter. Und ganz 
am Schluss kommen sogar 2 getaktete Prozesse raus...  :-o

Sally schrieb:
> Aber das geht wohl erst in VHDL 2008, meint fuse:
Ja, das ist eigentlich ein Concurrent Statement in einem Prozess. Man 
kann ja Kraut und Rüben und Kohl und Kartoffeln mischen und mixen. Wenns 
einem hinterher schmeckt...


Ich würde da anpacken, wo die meisten Zeilen anfallen: bei der 
Farbengeschichte. Und dann sähe das so aus:
1
signal colors : std_logic_vector(2 downto 0) := "010"; // R G B
2
:
3
:
4
  process begin
5
    wait until rising_edge(clk); 
6
    case state is
7
      when y =>
8
        state <= r;
9
        lamps <= "010";
10
      when g =>
11
        state <= y;
12
        lamps <= "001";
13
      when ry =>
14
        state <= g;
15
        lamps <= "110";
16
      when r =>
17
        state <= ry;
18
        lamps <= "100"
19
--      when others => null; -- unnötig und nutzlos, wenn state mit 4 Zuständen (y,g,r,ry) definiert ist!
20
      end case;
21
  end process;    
22
23
  red    <= lamps[2];
24
  yellow <= lamps[1];
25
  green  <= lamps[0];
Und weil lamps synchron ist, sind auch die Ausgänge red, yellow 
und green synchron.

von Sally (Gast)


Lesenswert?

> Die allererste. Weil da jeder auf Anhieb sofort sieht, was gemeint ist.
> Alles Nachfolgende ist nur noch verwaschener und verbastelter.
> Und ganz am Schluss kommen sogar 2 getaktete Prozesse raus...  :-o

Interessant. Ich finde es übersichtlicher, wenn alles schön säuberlich 
getrennt ist. Und es sieht nicht mehr so nach prozedualem Code aus, was 
VHDL ja nicht ist.

Du programmierst vermutlich mehr in C als in VHDL, oder? Das würde 
deinen prozedualen Stil in VHDL erklären. ^^

> Ja, das ist eigentlich ein Concurrent Statement in einem Prozess. Man
> kann ja Kraut und Rüben und Kohl und Kartoffeln mischen und mixen. Wenns
> einem hinterher schmeckt...

Würde mir durchaus schmecken. Es ist deutlich kürzer und dadurch finde 
ich es einfacher lesbar. Aber Xilinx kann ja leider kein VHDL 2008...

> Ich würde da anpacken, wo die meisten Zeilen anfallen: bei der
> Farbengeschichte. Und dann sähe das so aus:
> [...]
> Und weil lamps synchron ist, sind auch die Ausgänge red, yellow
> und green synchron.

Sehr hübsch und bei diesem einfachen Beispiel geht das auch ganz gut. 
Wenn du aber mehrere unabhängige Signale hast, die alles etwas 
unterschiedliches tun, wird das schnell sehr hässlich. ;)

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


Lesenswert?

Sally schrieb:
> Du programmierst vermutlich mehr in C als in VHDL, oder?
Nein, ich "programmiere" gar nicht ind VHDL. Ich stelle mir meine 
Schaltung vor und beschreibe die dann mit VHDL.

> Das würde deinen prozedualen Stil in VHDL erklären. ^^
Nein, ich habe quasi einen Synthesizer "im Kopf" (Übung), der mir diese 
Verhaltensbeschreibung beim Schreiben in einen RTL-Plan umsetzt. Ich 
kann mir also gut erklären, warum ich das genau so hingeschrieben habe.

> Sehr hübsch und bei diesem einfachen Beispiel geht das auch ganz gut.
> Wenn du aber mehrere unabhängige Signale hast, die alles etwas
> unterschiedliches tun, wird das schnell sehr hässlich. ;)
Ich kann dir das Gegenteil beweisen...   ;-)

Schreib du mal, hmmm... naja, sagen wir eine serielle Schnittstelle mit 
dieser Entity:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity RS232 is
6
    Generic ( Quarz_Taktfrequenz : integer   := 50000000;  -- Hertz 
7
              Baudrate           : integer   := 9600       -- Bits/Sec
8
             ); 
9
    Port ( -- Empfang
10
           RXD      : in   STD_LOGIC;
11
           RX_Data  : out  STD_LOGIC_VECTOR (7 downto 0);
12
           RX_Busy  : out  STD_LOGIC;
13
           -- Senden
14
           TXD      : out  STD_LOGIC;
15
           TX_Data  : in   STD_LOGIC_VECTOR (7 downto 0);
16
           TX_Start : in   STD_LOGIC;
17
           TX_Busy  : out  STD_LOGIC;
18
           -- The one and only: CLK!
19
           CLK      : in   STD_LOGIC
20
           );
21
end RS232;

Wenn du dir dazu dann mal Gedanken gemacht hast, darfst du auch meine 
Lösung ansehen:
http://www.lothar-miller.de/s9y/categories/42-RS232

von Martin S. (strubi)


Lesenswert?

Moin,

haha, ein provokanter Klassiker.
Leider liegt's wie immer im Auge des Betrachters. Einige Kollegen sind 
"harte Elektroniker" und lesen VHDL am leichtesten, wenn die 74XX-Logik 
irgendwie dahinter erkennbar ist. Manche wiederum (wie meinereiner) 
mögens's pragmatisch aufgeräumt und möglichst zentral verwaltet.

Persönlich ziehe ich es vor, ab einer gewissen Anzahl Dekodierungen die 
aus den States erzeugten Signale aus dem Haupt-FSM-Prozess 
herauszuziehen. Und zwar ab dem Zeitpunkt, wo der Process nicht mehr auf 
eine Bildschirmseite geht.
Was Zweiprozess-Methode angeht: Die nutze ich nur, wenn einige Prozesse 
vorausschauend auf den "next_state" reagieren müssen, oder Ereignisse 
zwischen speziellen State-Übergängen decodiert werden sollen.
Kommt aber eher selten vor, genauer, solche fiesen Sachen waren nur bei 
Hardwaredebugger-Implementationen nötig.

Generell gilt wohl: Alles was gut in LUTs passt, ist des FPGAs Freund 
(wenig Resourcenverbrauch). Wenn man sich die Synthese-Logs diverser 
Tools anschaut, findet man oft auch Hinweise, die zur vereinfachten 
Codierung und Lesbarkeit beitragen...
Und ab einer gewissen Komplexität ist ein kleiner stupider Softcore 
(Sequenzer) mit selbstdefinierten Opcodes die bessere State-Machine.

von Sally (Gast)


Lesenswert?

> Nein, ich "programmiere" gar nicht ind VHDL. Ich stelle mir meine
> Schaltung vor und beschreibe die dann mit VHDL.

Ach komm schon, auf dieser Ebene müssen wir nicht streiten. Wir sind 
doch beide Erwachsen, oder? Du weißt doch ganz genau, was ich meine. ;)

> Nein, ich habe quasi einen Synthesizer "eingebaut" (Übung), der mir
> diese Verhaltensbeschreibung beim Schreiben in einen RTL-Plan umsetzt.
> Ich kann mir also gut erklären, warum ich das genau so hingeschrieben
> habe.

Das höre ich oft von Leuten, die noch nicht lange mit VHDL arbeiten. 
Meistens ist das was man sich da vorstellt nicht sehr nahe am 
Syntheseergebnis. ^^

> Ich kann dir das Gegenteil beweisen...   ;-)
> Schreib du mal, hmmm... naja, sagen wir eine serielle Schnittstelle mit
> dieser Entity:

Danke, das habe ich schon hinter mir. Im Moment beschäftige ich mich mit 
Ethernet Frames, das ist ein bisschen komplizierter. ;)

> Wenn du dir dazu dann mal Gedanken gemacht hast, darfst du auch meine
> Lösung ansehen:
> http://www.lothar-miller.de/s9y/categories/42-RS232

Wie von dir erwartet auch sehr prozedual gehalten. ^^

Wenn ich z.B. wissen möchte, wann sich txcnt ändert, muss ich den 
gesamten Prozess absuchen, dabei könnte man das auch schön in einer 
Zeile schreiben (wie in meinem Beispiel 3ff oben) Dann laufe ich auch 
nicht Gefahr in einem Zweig mal eine Zuweisung zu vergessen und 
generiere keine unerwünschten Latches, die bei komplizierteren FSMs zu 
scheinbar unerklärlichem Verhalten führen.

Aber wenn du mit der prozedualen Schreibweise besser zurecht kommst, ist 
das natürlich in Ordnung. Ich mache ja nur eine Meinungsumfrage. ;)

Andere Meinungen dazu?

von Sally (Gast)


Lesenswert?

> Generell gilt wohl: Alles was gut in LUTs passt, ist des FPGAs Freund
> (wenig Resourcenverbrauch). Wenn man sich die Synthese-Logs diverser
> Tools anschaut, findet man oft auch Hinweise, die zur vereinfachten
> Codierung und Lesbarkeit beitragen...

Ja, das stimmt wohl. ^^ Ich sehe es leider zu oft bei Anfängern, dass 
die ganzen nützlichen Warnungen ignoriert werden. ;)

Vielen Dank für deine Meinung! :)

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


Lesenswert?

Sally schrieb:
> Wie von dir erwartet auch sehr prozedual gehalten. ^^
Klar. Warum nicht? Die Tools geben das her.

> Wenn ich z.B. wissen möchte, wann sich txcnt ändert
Dann suche ich nach txcnt. So oft kommt der ja nicht vor.
Und meist ist ja nicht die Frage, wann bzw. wo er sich ändert, 
sondern wohin. Also: was ist der nächste Wert.
Und in einem zusätzlichen kombinatorischen Prozess, der txcnt_next 
ausrechnet, habe ich auch wieder zig Stellen und ein zusätzliches 
Signal.

> Aber wenn du mit der prozedualen Schreibweise besser zurecht kommst, ist
> das natürlich in Ordnung. Ich mache ja nur eine Meinungsumfrage. ;)
>
> Andere Meinungen dazu?
Der ist gut...   ;-)


BTW: mit der letzten (doppelt getakteten) Schreibweise bekommst du 
leicht mal unverhofft einen Takt Latency.

von dito (Gast)


Lesenswert?

Martin S. schrieb:
> Und ab einer gewissen Komplexität ist ein kleiner stupider Softcore
> (Sequenzer) mit selbstdefinierten Opcodes die bessere State-Machine.

Das würde mich näher interessieren. Meinst du mit Sequencer den 
Picoblaze o.ä. oder gibt es für so etwas eine herstellerunabhängige 
"Schablone"?

von Falk B. (falk)


Lesenswert?

@  Sally (Gast)

>Zeile schreiben (wie in meinem Beispiel 3ff oben) Dann laufe ich auch
>nicht Gefahr in einem Zweig mal eine Zuweisung zu vergessen und
>generiere keine unerwünschten Latches, die bei komplizierteren FSMs zu
>scheinbar unerklärlichem Verhalten führen.

Quark. Die Ein-Prozess Methode kann gar keine Latches erzeugen, weil 
voll getaktet. Die Zwei-Prozess-Methode ist da das Problemkind. Naja, 
ich sag da nur "Projektion".
Und Latches spuckt jeder Compiler als Warning aus, wer die ignoriert 
muss halt noch etwas Lehrgeld zahlen ;-)

von berndl (Gast)


Lesenswert?

Falk Brunner schrieb:
> Die Zwei-Prozess-Methode ist da das Problemkind

Meine Meinung und auch mein Senf dazu: Ich schreibe meistens 
1-Prozess-Schreibweise, ganz selten 2-Prozess. Und wenn 2-Prozess dann 
eigentlich immer den 'next_state' mit Concurrent-Anweisungen: 
Uebersichtlicher und vermeidet fast automatisch die Latches. Und man 
'ahnt' bei laenglichen statements, dass Place&Route damit einiges zu tun 
haben.

Damit bin ich in ~15 Jahren VHDL und auch Verilog (mit Unterbrechungen) 
immer ganz gut klar gekommen und auch das Timing lag in etwa im 
erwarteten Bereich...

von Martin S. (strubi)


Lesenswert?

dito schrieb:
> Martin S. schrieb:
>> Und ab einer gewissen Komplexität ist ein kleiner stupider Softcore
>> (Sequenzer) mit selbstdefinierten Opcodes die bessere State-Machine.
>
> Das würde mich näher interessieren. Meinst du mit Sequencer den
> Picoblaze o.ä. oder gibt es für so etwas eine herstellerunabhängige
> "Schablone"?

Nee, eher noch primitiver als Picoblaze, aber hängt auch wiederum von 
der Aufgabe ab. Also gibt es auch nicht wirklich eine universelle 
Schablone, sondern du passt dir deinen eigenen "Prozessor" der Aufgabe 
an.
Nimm z.B. eine typische Multiply-Accumulate Unit, wie sie in praktisch 
allen DSP steckt. Für gewisse Signalfilter brauchst du davon ev. ein 
paar kaskadiert, aber auch "multiplexed", also eine Unit macht 
Operationen für ev. mehrere Datenpfade zu unterschiedlicher Zeit. 
Anstatt alles hart in eine FSM zu codieren, macht da ein "Programm" mit 
selbstdefinierten Opcodes (Quelle, Operation[Modus], Ziel) mehr Sinn. Du 
baust Dir also deine Verarbeitungsblöcke als Module und der Sequencer 
bestimmt, wann welches unter gewissen Bedingungen drankommt.
Allerdings nutze ich auch einen fertigen CPU-Softcore als Front-End, um 
den eigentlichen Microcode (also das "Programm") für die DSP-Pipeline 
ggf. zu modifizieren und debuggen.
Nachteil ist, dass im ersten Design die opcodes meist recht lang werden 
(wegen der plumpen Codierung einiger parallel arbeitender Units). Sobald 
dann eine Verarbeitungs-Pipeline feststeht, kann man die fest in 
Hardware codieren (Stichwort LUTs!) und das eigentliche Programm 
schrittweise vereinfachen.
Meist hat sich dabei sogar herausgestellt, dass die längliche Version 
weniger Resourcen kostet als eine komplizierte FSM, u.a. dadurch, dass 
für das Programm auch BlockRAM genutzt wird.
Die Tools (zumindest die von Xilinx) sind nämlich ab einem gewissen 
Punkt nicht mehr schlau genug, zu komplexe hart codierte FSM zu 
vereinfachen und klauen dir dann eine Menge Logik-Resourcen auf dem FPGA 
weg.


Grüsse,

- Strubi

von berndl (Gast)


Lesenswert?

Martin S. schrieb:
> Anstatt alles hart in eine FSM zu codieren, macht da ein "Programm" mit
> selbstdefinierten Opcodes (Quelle, Operation[Modus], Ziel) mehr Sinn.

Hatte ich auch schon. Zwar ohne DSP Funktionalitaet aber halt eine 
bloede vielzyklische FSM (mit variabler Pipelinetiefe, dazu noch mehrere 
Zugriffe auf BRAM-Daten): Sauber in einem Prozess hingeschrieben und da 
haben die Tools doch wunderbar distributed RAM erkannt und verwendet. 
Timing war danach ueberhaupt kein Problem mehr, auch bei 
Erweiterungen/Aenderungen...
Und schoen kompakt war's dann auch...

von Klaus (Gast)


Lesenswert?

Sally schrieb:
> Du programmierst vermutlich mehr in C als in VHDL, oder? Das würde
> deinen prozedualen Stil in VHDL erklären. ^^

Ja, genau so ist es. Der Loddar hat nämlich gar keine Ahnung von VHDL. 
:D

*wer Ironie findet, darf die behalten... ;-)

von Fritz J. (fritzjaeger)


Lesenswert?

Die Übersichtlichste Darstellung einer digitlanen Schaltung ist ein 
Diagramm -> mit einer vollständigen Dokumentation erspart man sich alle 
Verrenkungen im Code.

In diesem Zusamenhang sei auch auf die Möglichkeit verwiesen aus 
FSM-Graphen automatisch Code zu erzogen, bspw. mit Mentor Graphics 
HDL-Designer.

MfG

von DuArte (Gast)


Lesenswert?

>Ich sehe es leider zu oft bei Anfängern, dass
>die ganzen nützlichen Warnungen ignoriert werden. ;)

Allein die Tatsache, dass Sally sich mit solchen "Ich verschiebe mal den 
Code in eine andere Schreibweise"-Lapalien beschäftigt, zeigt mir, dass 
der Kreis der Anfänger doch größer ist als angenommen ;-)

von Flogian (Gast)


Lesenswert?

Sally schrieb:
> Du programmierst vermutlich mehr in C als in VHDL, oder? Das würde
> deinen prozedualen Stil in VHDL erklären. ^^

Das was du hier machst ähnelt in etwa dem Spruch: "Hey Chuck Norris wie 
läufts beim Ballet?"

von Philip (Gast)


Lesenswert?

Ich finde ebenfalls die erste Schreibweise am besten und kriege immer 
die Krise, wenn ich sehe dass jemand eine FSM nach getaktetem und 
kombinatorischem Teil trennt. Ich finde das irgendwie unintuitiv und 
schlecht lesbar...
Was das damit zu tun haben soll, ob man vorher Software geschrieben hat, 
ist mir nicht klar.

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


Lesenswert?

Philip schrieb:
> Ich finde das irgendwie unintuitiv und schlecht lesbar...
Naja, das kommt aus der Automatentheorie mit getakteten Speichergliedern 
und einer Logik/Rechenwerk für die Weiterschaltung.

Das ist in meinen Augen wie Assemblerprogrammierung:
Gut, wenn man die Erfahrung mal gemacht hat...

OT:
> unintuitiv
Was ist das Gegenteil von "ineffiziet"? Richtig: "effizient".
Was das Gegenteil von "intolerant"? Ja: "tolerant".
Und von "inakzeptabel"? Korrekt: "akzeptabel".
Was ist also logischerweise das Gegenteil von "intuitv"?

Ich finde z.B. die Bedienung von manchem Programm sehr tuitiv!  ;-)

von Philip (Gast)


Lesenswert?

Und das Gegenteil von möglich ist demnach inmöglich? :-)

von Daniel M. (daniel__m)


Lesenswert?

Philip schrieb:
> Ich finde ebenfalls die erste Schreibweise am besten und kriege immer
> die Krise, wenn ich sehe dass jemand eine FSM nach getaktetem und
> kombinatorischem Teil trennt. Ich finde das irgendwie unintuitiv und
> schlecht lesbar...

Nach etlichem hin und her bin ich aktuell meist bei der 
2-Prozess-Darstellung, 1 Prozess getaktet, der Andere kombinatorisch. 
Das liegt daran, dass ich immer mal wieder eine Latenz 0 benötige, bzw. 
nur so die benötigte Performance bekomme (also Mealy-Automat). Ansonsten 
nutze ich die 1-Prozess-Darstellung (Moore-Automat).

Bei der 2-Prozess-Darstellung versuche ich dann auch, die 
State-Dekodierung nur an einer Stelle zu machen, was dann darauf 
hinausläuft, dass der kombinatorische Prozess alles macht und der 
getaktete Prozess die Signale nur speichert (soweit möglich, wegen 
Latenz)


Wenn jetzt jemand meint, na dann mache ich eine 1-Prozess-Darstellung 
und die Latenz-0-Signale per Concurrent-Statement (z.B. mit when oder 
with), dann ist das für mich nur eine andere Form der 
2-Prozess-Darstellung (eigentlich sogar noch mehr Prozesse, wenn man im 
Simulator sieht, dass jede Concurrent-Anweisung in einem eigenen Prozess 
dargestellt werden)

von DuArte (Gast)


Lesenswert?

>Das liegt daran, dass ich immer mal wieder eine Latenz 0 benötige

Hast du mal ein kleines schnuckeliges Beispiel?

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


Lesenswert?

Daniel M. schrieb:
> dass jede Concurrent-Anweisung in einem eigenen Prozess dargestellt
Eine Concurrent-Beschreibung ist ja nur ein degenerierter Prozess, bei 
dem alle verwendeten Signale implizit in der Sensitivliste stehen.

> bin ich aktuell meist bei der 2-Prozess-Darstellung ...
> Das liegt daran, dass ich immer mal wieder eine Latenz 0 benötige, bzw.
> nur so die benötigte Performance bekomme (also Mealy-Automat)
Man muss auch mit der 1-Prozess-Schreibweise nicht immer unnötig einen 
Takt vertrödeln...

von Daniel M. (daniel__m)


Lesenswert?

DuArte schrieb:
>>Das liegt daran, dass ich immer mal wieder eine Latenz 0 benötige
>
> Hast du mal ein kleines schnuckeliges Beispiel?

Weitergabe eines Read- oder Ready-Signals (z. B. an ein FIFO) in 
Abhängigkeit vom State?

Ich verwende hier einen DDR3 mittels Xilinx MIG und benötige eine hohe 
Bandbreite (Videoanwendung). Da gilt es, jede unnötige Latenz zwischen 
app_en und app_rdy bzw. app_wdf_en und app_wdf_rdy zu vermeiden.

Als ein Beispiel.

von Daniel M. (daniel__m)


Lesenswert?

Lothar Miller schrieb:
> Man muss auch mit der 1-Prozess-Schreibweise nicht immer unnötig einen
> Takt vertrödeln...

Die Frage ist, was ist unnötig?

Eine reine 1-Prozess-Darstellung hat die minimale Latenz 1. Frühestens 
im nächsten Takt ist eine Reaktion auf ein Signal sichtbar.

Und das ist mir in speziellen Situationen bereits zu langsam.

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


Lesenswert?

Daniel M. schrieb:
> Eine reine 1-Prozess-Darstellung hat die minimale Latenz 1. Frühestens
> im nächsten Takt ist eine Reaktion auf ein Signal sichtbar.
Aber jetzt weißt du schon, was als nächstes kommen wird. Bei der 
2-Prozess-Methode explizit, bei der 1-Prozess-Methode implizit...

von Daniel M. (daniel__m)


Lesenswert?

Ich weiss es, aber das nützt nichts, wenn ich dazu ein Signal 
benötige.

Beispiel:

Ein Modul generiert ein Read-Signal, welches bedeutet, im nächsten Takt 
erwartet es Daten am Eingang (normales FIFO-Verhalten).

Jetzt wird dieses Modul nicht direkt angeschlossen sondern über eine 
FSM. Bei einer reinen 1-Prozess-FSM bedeutet das für mich, die FSM sieht 
das Read-Signal und veranlasst zb ein State-Wechsel zum Auslesen eines 
FIFOs. Dies ist jedoch erst im nächsten Takt sichtbar. Und die Daten 
kommen nochmal einen Takt später. Das heißt das Modul bekäme die Daten 1 
Takt zu spät.
1
one_process : process(clk)
2
begin
3
  if rising_edge(clk) then
4
    o_fifo_read <= '0';
5
    case state is
6
      when ST_WAITING =>
7
        if i_read = '1' then
8
          state       <= ST_READ;
9
          o_fifo_read <= '1';
10
        end if;
11
12
      when ST_READ =>
13
        (irgendwas)
14
15
    end case;
16
  end if;
17
end process;
Latenz = 1!

oder sogar:
1
one_process : process(clk)
2
begin
3
  if rising_edge(clk) then
4
    o_fifo_read <= '0';
5
    case state is
6
      when ST_WAITING =>
7
        if i_read = '1' then
8
          state       <= ST_READ;
9
        end if;
10
11
      when ST_READ =>
12
        o_fifo_read <= '1';
13
        (irgendwas)
14
15
    end case;
16
  end if;
17
end process;
Latenz = 2!



Klar kann ich das kombinatorisch beschreiben:
1
  o_fifo_read <= i_read when state = ST_WAITING else '0';
Jedoch ist das für mich nichts anderes als die 2-Prozess-Darstellung in 
anderer Form.

von Strubi (Gast)


Lesenswert?

Moin,

es gibt da noch ein längeres schlagendes Argument für die 
2-process-Methode, dem eigentlich nichts mehr hinzuzufügen ist:

http://www.gaisler.com/doc/structdes.pdf

Darauf kommt man aber auch, wenn man sich bei komplexen Projekten 
einfach ganz akademisch befreit ein paar Gedanken zum Thema 
Codeverwaltung macht - es kommt nämlich durchaus öfters vor, dass 
mehrere Module von einer zentralen FSM abhängen und daraus Signale 
dekodieren, z.B. ein Soft-Core mit einem optionalen Debug-Modul mit dem 
typischen "1 clock Latenz ist zuviel"-Problem.

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


Lesenswert?

Daniel M. schrieb:
> Klar kann ich das kombinatorisch beschreiben:
>  o_fifo_read <= i_read when state = ST_WAITING else '0';
Das kapiert wirklich jeder. Ohne lange Suche...   ;-)
> Jedoch ist das für mich nichts anderes als die 2-Prozess-Darstellung in
> anderer Form.
Für die Erzeugung solcher kombinatorischer Signale nehme ich natürlich 
auch kombinatorische Beschreibungen, da ist ein zusätzliches Register, 
das bei der purifizierten 1-Prozess-Schreibweise entstehen würde, 
unnötig.
Nur: was hat dieses Signal mit der FSM zu tun? Die Weiterschaltung und 
FSM-Verwaltung kannst du ja bedenkenlos in 1-Prozess machen.

Auch ich nehme die 2-Prozess (oder 1-Prozess + Concurrent) Methode, wenn 
sie von Vorteil ist. Allerdings ist meine Defaulteinstellung auf FSM = 
1-Prozess.


Strubi schrieb:
> http://www.gaisler.com/doc/structdes.pdf
Der Prophet, der über (quasi globale) Variablen auch Softwareprogram- 
mierern FPGAs näher bringen will.
Dem einen gefällts, der andere findet es zu aufwendig und verwirrend, 
wie im Beitrag "Gaisler-Religion?" aufgeführt.

von P. K. (pek)


Lesenswert?

Sally schrieb:
> Ich möchte hier jetzt keinen Glaubenskrieg hervorrufen...

Und schon haben wir ihn. Ist aber auch logisch, denn es ist 
psychologisch gezeigt, dass der Mensch Negationen tendenziell ignoriert. 
(Schon mal versucht nicht an einen rosaroten Elephanten zu denken?)

Wie auch immer: Soll jeder nach seiner Art glücklich werden. ;-)

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


Lesenswert?

Peter K. schrieb:
> Schon mal versucht nicht an einen rosaroten Elephanten zu denken?
Was ist das?    ;-)

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.