Hallo zusammen, ich versuche mich aktuell an Aufgabe 1-1 von Lab 11 Xilinx HDL Design using Vivado. Als Lösung ist auch das ASM chart auf Seite 6 angegeben. Mit diesem ASM chart komme ich jedoch nicht auf das Timing Diagramm von Seite 5. Mit ein paar Änderungen habe ich das Timing Diagramm fast hinbekommen. Jedoch verstehe ich nicht was für Werte in product_int angezeigt werden, bevor das Endergebnis drinnen steht. Könnte bitte mal jemand meine ASM begutachten? Danke und Gruß Daniel
Die Simulation sieht doch gar nicht so schlecht aus, zumindest kommen auch plausible Ergebnisse raus. Bei der zweiten Berechnung (4*1) würde ich das Startsignal nur für einen Takt einschalten. Außerdem ist es hilfreich ein Signal zu haben, welches anzeigt, wann ein gültiges Ergebnis vorliegt. Und noch ein Hinweis an den Autor des Tutorials: Es ist didaktisch nicht hilfreich, wenn die Zustände einer State-Machine mit S0, S1, ..., Sn einfach nur durchnummeriert sind. Duke
Duke Scarring schrieb: > Es ist didaktisch nicht > hilfreich, wenn die Zustände einer State-Machine mit S0, S1, ..., Sn > einfach nur durchnummeriert sind. Das wäre auch zub einfach! Wo kämen wir hin, wenn aufwändige Chart-Methoden erzeugt, vermittelt und propagiert werden, um sie dann nicht einsetzen zu müssen, weil manch einer einfach einen Geradeaus-Code schreibt, der selbsterklärend ist?
Daniel P. schrieb: > Könnte bitte mal jemand meine ASM begutachten? Ja. Deine Trennung von State Machine und Berechnungen machen es unnötig unübersichtlich. Auch die zusätzliche Verwendung von CU, CD und done_int machen es nicht einfacher. Außerdem dürfte sich das falling_edge(start) im State S1 nicht synthetisieren lassen. Wenn ich so einen Multiplizierer bräuchte, würde der bei mir ungefähr so aussehen:
1 | library ieee; |
2 | use ieee.std_logic_1164.all; |
3 | use ieee.numeric_std.all; |
4 | |
5 | |
6 | entity multiply is |
7 | port
|
8 | (
|
9 | clk : in std_logic; |
10 | start : in std_logic; |
11 | multiplicand : in std_logic_vector(2 downto 0); |
12 | multiplier : in std_logic_vector(2 downto 0); |
13 | --
|
14 | product : out std_logic_vector(5 downto 0); |
15 | done : out std_logic |
16 | );
|
17 | end entity multiply; |
18 | |
19 | |
20 | architecture rtl of multiply is |
21 | |
22 | type state_type is (IDLE, ADD, SHIFT); |
23 | signal state : state_type; |
24 | --
|
25 | signal count : natural range 0 to 2; |
26 | signal ma : unsigned(2 downto 0); |
27 | signal mb : unsigned(5 downto 0); |
28 | signal result : unsigned(5 downto 0); |
29 | |
30 | begin
|
31 | |
32 | process
|
33 | begin
|
34 | wait until rising_edge(clk); |
35 | |
36 | -- default
|
37 | done <= '0'; |
38 | |
39 | case state is |
40 | |
41 | when IDLE => |
42 | if start = '1' then |
43 | state <= ADD; |
44 | count <= 2; |
45 | ma <= unsigned( multiplicand); |
46 | mb <= resize( unsigned( multiplier), mb'length); |
47 | result <= ( others => '0'); |
48 | end if; |
49 | |
50 | when ADD => |
51 | if ma( 0) = '1' then |
52 | result <= result + mb; |
53 | end if; |
54 | state <= SHIFT; |
55 | |
56 | when SHIFT => |
57 | if count > 0 then |
58 | mb <= shift_left( mb, 1); |
59 | ma <= shift_right( ma, 1); |
60 | count <= count - 1; |
61 | state <= ADD; |
62 | else
|
63 | done <= '1'; |
64 | product <= std_logic_vector( result); |
65 | state <= IDLE; |
66 | end if; |
67 | |
68 | end case; |
69 | |
70 | end process; |
71 | |
72 | end architecture rtl; |
Wahrscheinlich würde ich die States SHIFT und ADD noch zusammenfassen und in der Portmap unsigned statt std_logic_vector verwenden. Da ist nach außen hin sofort klar, was für ein Datentyp erwartet wird. Duke
Duke Scarring schrieb: > Wenn ich so einen Multiplizierer bräuchte, würde der bei mir ungefähr so > aussehen: Hallo Duke Scarring, vielen Dank für deinen Beitrag. Ich muss zugeben, deine Variante ist kürzer, übersichtlicher und auch verständlicher. Ich werde zukünftig auch die 1-Prozess Variante für die FSM benutzen. Zu Lernzwecken habe ich jedoch versucht deine 1-Prozess Schreibweise in eine 2-Prozess Schreibweise zu konvertieren. Allerdings klappt das nicht wie erhofft, daher die Frage ist das überhaupt mit vernünftigen Mitteln möglich? Oder müssen die ganzen Berechnungen dann in den getakten Prozess und im kombninatorischen Prozess kann ich nur Ausgänge und Hilfsignale setzen. Wenn das so ist, bin ich wieder ganz schnell bei meiner sehr unübersichtlichen Version von oben. Ich hätte auch noch eine Frage zur Sensitivity list. Soweit ich das verstanden habe, ist die Sensitivity list vor allem für die Simulation wichtig. Wenn ich bei der Simulation Signale in der Liste vergesse, bekomme ich eine Abweichung von der Funktion in Simulation zur Funktion in Hardware. Wie verhält es sich dann mit der Sensitivity List bei der Synthese? Hier kann ich doch meines Wissens den FPGA bzw. den Prozess nicht mit einzelnen Signalen in der Sensitivity List steuern. Fügt der Syntheskompiler dann automatisch alle im Prozess verwendeten Signale zur Liste hinzu so ähnlich wie process(all)? Daniel
:
Bearbeitet durch User
Daniel P. schrieb: > Fügt der Syntheskompiler dann automatisch alle im Prozess verwendeten > Signale zur Liste hinzu Ja. Und der Synthesizer meldet dann recht unscheinbar, dass die erzeugte Hardware nicht zur Simulation passen wird. Daniel P. schrieb: > Oder müssen die ganzen Berechnungen dann in den getakten Prozess In der 2-Prozess-FSM sind Berechnungen wie Addition und Multiplikation oder ähnliche kombinatorische Rechenvorgänge im kombinatorischen Prozess. Nur die Speicher werden getaktet und damit in der Hardware zu Flipflops.
Hallo, ich habe jetzt die Version des Multiplizieres von Duke Scarring als 2-Prozess Schreibweise ausgeführt. Dazu hätte ich zwei Fragen: 1. Ich habe zwar alle Berechnungen im kombinatorischen Teil untergebracht, aber nur mit dem Hilfskonstrukt "next" im Getaktetem Teil (count_next, ma_next, usw.). Gibt es dazu einfachere bzw. elegantere Lösungen? 2. Am Anfang hat zwar die Simulation funktioniert, aber die Funktion in Hardware nicht. Es kam eine Warnung des einige Latches eingefügt wurden. Ich habe dann am Anfang vom kombinatorischen Prozess alle Signale in der Art "result_next <= result" beschrieben. Ist das so sinnvoll oder wäre es eine Alternative jedes Signal in jedem case zu beschreiben? Danke und Gruß Daniel
:
Bearbeitet durch User
Daniel P. schrieb: > 1. Ich habe zwar alle Berechnungen im kombinatorischen Teil > untergebracht, aber nur mit dem Hilfskonstrukt "next" im Getaktetem Teil > (count_next, ma_next, usw.). Gibt es dazu einfachere bzw. elegantere > Lösungen? Da fällt mir nur die 1-Prozess-Schreibweise ein ;-) > 2. Am Anfang hat zwar die Simulation funktioniert, aber die Funktion in > Hardware nicht. Es kam eine Warnung des einige Latches eingefügt wurden. > Ich habe dann am Anfang vom kombinatorischen Prozess alle Signale in der > Art > "result_next <= result" beschrieben. Ist das so sinnvoll oder wäre es > eine Alternative jedes Signal in jedem case zu beschreiben? Speicherelemente kann man auf zwei Arten beschreiben: flankengesteuert (rising_edge), dann wird ein Flip-Flop draus oder pegelgesteuert (if level=... ohne default und ohne else), dann wird es ein Latch. Wenn es auf der Steuerleitung glitcht, können Latches Probleme machen. Darum sollte man sie vermeiden. Wenn es in Deinem kombinatorischer Prozess nicht zu allen Signale in jedem Fall eine Zuweisung gibt, hast Du Latches generiert. Entweder erstmal allen Signalen per Default einen Wert zuweisen oder zu jedem if-Zweig auch einen else-Zweig mit einer Zuweisung hinschreiben:
1 | -- Latch, da kein Takt und nicht in jedem Fall eine Zuweisung
|
2 | process
|
3 | begin
|
4 | if sig = '1' then |
5 | value_next <= value + 1; |
6 | end if; |
7 | end process; |
8 | |
9 | -- kein Latch, da in jedem Fall eine Zuweisung
|
10 | process
|
11 | begin
|
12 | if sig = '1' then |
13 | value_next <= value + 1; |
14 | else
|
15 | value_next <= value; |
16 | end if; |
17 | end process; |
18 | |
19 | -- kein Latch, da in jedem Fall eine Zuweisung
|
20 | process
|
21 | begin
|
22 | value_next <= value; |
23 | if sig = '1' then |
24 | value_next <= value + 1; |
25 | end if; |
26 | end process; |
27 | |
28 | -- kein Latch, da getaktet
|
29 | process
|
30 | begin
|
31 | wait until rising_edge( clk); |
32 | if sig = '1' then |
33 | value <= value + 1; |
34 | end if; |
35 | end process; |
Duke
Noch eine Silbe zum Code:
1 | when others => |
Es gibt für diese FSM kein "others", weil alle 4 möglichen Zustände manuell auscodiert sind. Siehe dort: http://www.lothar-miller.de/s9y/categories/25-when-others Man kann mit einem solchen "when others" also logischerweise auch niemals eine "irre gelaufene" FSM wieder "einfangen". Daniel P. schrieb: > Es kam eine Warnung des einige Latches eingefügt wurden. Hinweise auf solche Latches können auch Hinweise auf (gegatete) kombinatorische Schleifen sein. http://www.lothar-miller.de/s9y/categories/36-Kombinatorische-Schleife Und hier die Darstellung dieser Thematik mit ein oder zwei Prozessen: http://www.lothar-miller.de/s9y/archives/43-Ein-oder-Zwei-Prozess-Schreibweise-fuer-FSM.html
:
Bearbeitet durch Moderator
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.