Hey Leute, ich bin gerade dabei mich mit FPGA Programmierung zu beschäftigen und komme von C-Welt, kenne mich einigermaßen mit objektorientierten Sprachen (Modelica) und Ingenieurszeugs wie MATLAB. Jetzt bin ich auf VHDL gestoßen und konnte nach langem Hin und Her die ersten Texte verstehen lernen. Ein eigenes Programm auf „Blanko“ zu schreiben fällt mir noch schwer, da muss ich noch sehr oft auf fertig geschriebene Quellcodes zurückgreifen. So zum aktuellen Stand: ich habe jetzt eigene Zustandsdiagramme erstellt für Bitmustererkennungen oder sonstiges also einfache Mealy/Moore Automaten etc. Kann ich noch realisieren. Jetzt bin ich auf eine synchrone sequenzielle Schaltung gestoßen und frage mich echt was hier abgeht. Im Internet finde ich einfach keine Erklärung, die mich weiter bringt… EDIT: habe ein Bild hinterlassen, da der Code sonst nicht lesbar ist! library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity aufgabe3 is Port ( CLK, S0, S1, S2, S4, S3 : in std_logic; D : in unsigned(4 downto 0); Q : out unsigned(4 downto 0)); end aufgabe3; architecture Behavioral of aufgabe3 is signal QINT: unsigned(4 downto 0); begin P1: process(S0, CLK) begin if S0 = '1' then QINT <= "0000"; elsif rising_edge(CLK) then if S1 = '1' then QINT <= "0000"; else if S2 = '0' then QINT <= D; else if S3 = '1' then if S4 = '0' then QINT <= QINT - 2; else QINT <= QINT + 1; end if; end if; end if; end if; end if; end process P1; Q <= QINT; end Behavioral; Das ist der Quelltext und ich bin baff. Ich würde gerne gemeinsam mit euch erarbeiten, was hier eigentlich passiert und was das ganze für einen Sinn hat, wenn es überhaupt einen hat? Ist jemand bereit mir dabei zu helfen ? Ich verlange ausdrücklich keine Lösung im Sinne von ihr sagt mir was passiert ist (könnt ihr gerne machen für Kontrollzwecke machen), sondern würde ich lieber das ganze erarbeiten, damit der Lerneffekt auch entsprechend gegeben ist. Ich wäre extrem dankbar für jeden Hinweis, jede Anregung, jede Idee!!! Mein Problem beginnt schon bei der Variablendeklaration, ich verstehe nicht wieso wir jetzt hier zwei mal Inputs definieren, geschweige denn was die Clock da abstellt. Die vorherigen Programme waren viel einfacher…
:
Bearbeitet durch User
>Jetzt bin ich auf VHDL gestoßen und konnte nach langem Hin und Her die >ersten Texte verstehen lernen. Ein eigenes Programm auf „Blanko“ zu >schreiben fällt mir noch schwer, da muss ich noch sehr oft auf fertig >geschriebene Quellcodes zurückgreifen. Das erste, was du verstehen musst, ist, dass du mit VHDL kein Programm schreibst, sondern eine Schaltung beschreibst. z.B. if S4 = '0' then QINT <= QINT - 2; else QINT <= QINT + 1; end if; Hier wird abhängig von der Eingangsleitung "S4" entwder der Schalungspfad gewählt, der QINT um zwei erniedrigt oder QINT um 1 erhöht. Das passiert jeweils abhängig vom Taktsignal CLK bei der steigenden Flanke.
Hey, vielen Dank erstmal für die Antwort! Ja ich bin leider etwas „voreingenommen“ durch meine alten Erfahrungen, danke erst mal für den Hinweis, ich habe es nämlich als ein Programm betrachtet. Also ist das im Ansatz grob gesagt, ein Vorwärts Rückwärtszähler ? Kann man hierzu eig auch die sogenannten Karnaugh Tafeln zu malen? Immerhin haben wir ja jetzt Zwei Deklarationen, die sich auf Inputs beziehen? Hoffe meine Fragen sind nicht allzu blöd, das ist alles Neuland für mich …
Ja, mit dem Wort 'Programm' und 'Variablen' wirst du hier wieder eine Menge sophistischer Kommentare triggern... Tips in Kurzform: - Such' dir eine Simulationsumgebung (z.B. GHDL, diverse Online-hdlplaygrounds) - Probiere Testbenches aus mit diversen Stimuli ( - Uebe Reverse-Engineering an (noch) 'obskuren' Schaltungen wie oben - Erst mal Signal-Typen verwenden, dann Variablen Bei VHDL ist grundsaetzlich viel Verwirrung mit im Spiel (Signale vs. Variablen), dazu kommt, dass du eine Menge in VHDL modellieren kannst, was die Tools nicht (oder nicht korrekt) in Hardware umsetzen. Gibt da inzwischen modernere Ansaetze fuer den Einstieg. Allerdings schadet es laengerfristig nicht, wenn du VHDL oder Verilog lesen kannst.
Tobi A. schrieb: > Also ist das im Ansatz grob gesagt, ein Vorwärts Rückwärtszähler ? Bingo! Man sollte den S0 ... S4 dazu sinnvollere Namen geben. Außerdem enthält die Aufgabenstellung einen Fehler: Bei QINT <= "0000"; fehlt eine Null. Zum besseren Verständnis hab ich mal eine Testbench hochgeladen. Damit kannst du das simulieren und siehst schön das Verhalten von der Beschreibung.
Danke dir für die Rückmeldung! Das kann gut sein haha. Dafür bin ich jetzt etwas schlauer und kann auf meine Wortwahl in Zukunft achten =D Ich habe mir bereits Vivado von Xilinx runtergeladen und kopiere da manche Quellcodes rein, da sie dort entspannter zu lesen sind und die Plattform auch VHDL konform ist. Habt ihr vielleicht Tipps, wie ihr solche Schaltungen, die von fremder Hand verfasst sind, versteht? Für mich ist das immer bisschen schwierig, da jeder seinen eigenen Stil mit sich bringt …
Hey Wow vielen Dank !!! Das ganze auch mal visuell zu sehen hilft enorm, da man sich die ganzen Signalläufe schlecht vorstellen kann !!! Was ist denn der Sinn von einem Vorwarts Rückwärts Zähler, also wo findet sowas seine Anwendung, wenn ich fragen darf ? Wozu braucht man eine Clock dafür, lässt sich das nicht ohne realisieren ? Indem man zB das ganze flankensteuert? Und wieso haben wir hier zwei mal Inputs generiert, die Schaltungen, die ich bis jetzt gesehen habe, hatten lediglich 1 Eingang und ein Ausgang und falls man mal mehrere gebraucht hat, wurde das entsprechend als Vector definiert.
tobi.python schrieb: > Ich habe mir bereits Vivado von Xilinx runtergeladen und kopiere da > manche Quellcodes rein, da sie dort entspannter zu lesen sind und die > Plattform auch VHDL konform ist. Das geht auch gut mit Notepad++ den finde ich sogar dem Editor in Vivado überlegen. Simulieren kannst du schön mit der gratis Version von Modelsim. tobi.python schrieb: > Habt ihr vielleicht Tipps, wie ihr solche Schaltungen, die von fremder > Hand verfasst sind, versteht? Übung. Sehr viel Übung. Lese einfach regelmäßig hier im Forum mit und löse die Probleme Anderer. Das ist ein prima Training.
Hallo Tobi, ich glaube, den besten Einstieg bekommst Du, wenn Du Dir erst einmal klar machst, was der Unterschied zwischen Programmieren eines Mikroprozessors/-controllers und dem Programmieren eines FPGAs ist. Beim Mikroprozessor hast Du eine CPU-Einheit, und Du fütterst mit Deinem Programm sequenzielle Anweisungen (tu dies, tu das) in die CPU. Die arbeitet alles nacheinander ab. Beim VHDL ist es so, dass wie Herbert es geschrieben hat, im FPGA funktionsfreie Einheiten (Flip Flops, Logik) mit Verdrahtungswegen vor liegen. Der Chip macht so erst einmal gar nichts. Im VHDL beschreibst Du dann, erst einmal eine Grundfunktionalität, wie eine dieser Einheiten fiktiv zu einer Schaltung zusammen geschaltet werden (zum Beispiel Zähler, Multiplexer, Vergleicher....). In der Mechanik ist das wie eine Zeichnung einer Schraube. Man sieht wie so was funktioniert, aber es ist noch nicht real vorhanden, sondern nur eine Skizze. Im zweiten Schritt Instanzierst Du dann diese Definition, d.h. Du sagst mit dem VHDL wie viel von Deinen Zählern, Multiplexern usw. real im FPGA zusammen gebaut werden sollen und wie die Verdrahtet werden müssen. Das ist fast wie beim Schaltplan-Zeichnen, wo Du auch die Komponenten IC1 mit IC2 mit einem Strich verbindest. In der Mechanik ist das wie eine Zusammenbauanleitung, und der Compiler baut dann das "Schränkchen" mit x-Schrauben (gemäß Zeichnung aus Schritt eins) zusammen. Im dritten Schritt verbindest Du dann die Eingangs- und Ausgangssignale mit den Pins des FPGAs (Pin-Mapping). Ganz wichtiger Unterschied zwischen Mikroprozessor und FPGA-Programmierung: Beim Mikroprozessor ergibt sich eine sequenzielle Abarbeitung des Codes automatisch durch das Programm. Gleichzeitigkeit ist erst einmal was exotisches und schafft Probleme (Mutex, Semaphore...). Beim FPGA passiert grundsätzlich alles gleichzeitig, d.h. wenn Du einen Addierer definierst und instanzierst, dann gibt der auch schon ein Ergebnis raus, wenn noch gar keine Operanden zum addieren da waren. Da musst Du aktiv Vorgänge sequenzialisieren (z.B. über eine Statemaschine), um ungewollte Effekte zu vermeiden. Der Vorteil der Gleichzeitigkeit ist, natürlich, dass es rasend schnell geht, und die Realität ist ja auch ein Ort, wo vieles gleichzeitig passiert. Da kann ein FPGA auch ohne Verklemmung so was verarbeiten. Wenn man das mit dem Umdenken geschafft hat, ist VHDL ganz witzig.
tobi.python schrieb: > Was ist denn der Sinn von einem Vorwarts Rückwärts Zähler, also wo > findet sowas seine Anwendung, wenn ich fragen darf ? Vielleicht Uhr und Stoppuhr? Wobei hier beim runterzählen immer -2 gerechnet wird. tobi.python schrieb: > Wozu braucht man eine Clock dafür, lässt sich das nicht ohne realisieren > ? Indem man zB das ganze flankensteuert? Woher sollen die Flanken denn kommen? elsif rising_edge(CLK) then macht genau das, es reagiert auf Flanken. Eine Clock hat den Vorteil, dass die Flanken einigermaßen den gleichen Abstand haben, also die Frequenz fest ist. Du kannst statt Clock natürlich auch einen Taster verwenden und da händisch draufdrücken. tobi.python schrieb: > Und wieso haben wir hier zwei > mal Inputs generiert, die Schaltungen, die ich bis jetzt gesehen habe, > hatten lediglich 1 Eingang und ein Ausgang und falls man mal mehrere > gebraucht hat, wurde das entsprechend als Vector definiert. Ein Vector ist quasi ein Bündel aus Leitungen. Hier sind D und Q jeweils ein Bündel aus 5 Leitungen die gleich als vorzeichenlose Zahl, unsigned, interpretiert werden. Die anderen Eingänge CLK, S0, ... haben jeweils unterschiedliche Aufgaben in der Beschreibung. Aber natürlich könnte man auch diese zu einem Vektor zusammenfassen. Dann leidet aber die Lesbarkeit deutlich. Also lieber die Ein- und Ausgänge nach Funktion zusammenfassen. Wie du siehst ist so Code oft schwer zu verstehen, also schreibe lieber etwas längeren, einfach zu verstehenden Code als kryptischen kurzen Code. Jennifer S. schrieb: > Wenn man das mit dem > Umdenken geschafft hat, ist VHDL ganz witzig. Exakt! Die Lernkurve ist recht mühsam, aber es lohnt sich.
:
Bearbeitet durch User
Danke dir Gustl, das sind sehr hilfreiche Tipps!
Hey Jennifer vielen Dank für die ausführliche Erörterung, das hat mir vieles in einer verständlichen Sprache rübergebracht, auch die Beispiele fand ich super. Ja da sagst du was der Umstieg ist nicht so leicht! Okay das macht tatsächlich Sinn! Ich bin wirklich sehr dankbar Gustl für die vielen Erklärungen und für eure (deine) Zeit. Da frage ich mich, muss das nicht irgendwie aufhören, also gibt es einen Reset in dieser Schaltung oder läuft diese einfach endlos ab ?
Eines ist auch noch bisschen schwammig: was sind denn die ganzen S Signale S1-S4.reicht der D-Vector nicht um Von 0-15 zu zählen vollkommen aus ?
Tobi A. schrieb: > Da frage ich mich, > muss das nicht irgendwie aufhören, also gibt es einen Reset in dieser > Schaltung oder läuft diese einfach endlos ab ? Nein, das hört nicht auf. Das ist Hardware, eben eine Schaltung. Aber ob diese Schaltung etwas tut oder nicht hängt natürlich von den Eingangssignalen ab. Wenn du da den Takt wegnimmst oder den Reset einschaltest, dann macht die nicht mehr viel. Wenn das im FPGA steckt dann kannst du den Strom wegnehmen. Tobi A. schrieb: > was sind denn die ganzen S > Signale S1-S4.reicht der D-Vector nicht um Von 0-15 zu zählen vollkommen > aus ? Nein mit D wird nicht gezählt. QINT wird als Zähler verwendet. D wird als Zahl angesehen die man in den Zähler mit S2 = '0' hineinladen kann. Damit kann man also von außen einen Zählerstand setzen. Die anderen Sx Signale werden zur Steuerung verwendet, die haben alle ihre Funktion, siehe die Testbench datei die ich oben hochgeladen hatte: S0 <= counter_reset; S1 <= counter_clear; S2 <= counter_not_load; S3 <= counter_enable; S4 <= counter_direction; Aber hier ist auch noch ein Bild mit den benannten Signalen statt den Sx Signalen.
Ich bin dir sehr dankbar für den Aufwand, das ist sehr lieb, dass du nochmal die Signale mit Passenderen Namen benannt hast. Ich bin glaub ich auch kurz davor die Schaltung zu verstehen, habe aber noch Rückfragen: „ S0 <= counter_reset; S1 <= counter_clear; S2 <= counter_not_load; S3 <= counter_enable; S4 <= counter_direction;“ • Also der Reset bedeutet ja, dass wir wieder bei 0 anfangen zu zählen. • Dasselbe passiert aber auch beim Clear, was ist denn der Unterschied ? • Counter Not load habe ich überhaupt nicht verstanden… Sorgt der bei einer 0 für eine zufällige Zahl bei der wir die Zählung beginnen ? • Counter Enable heißt dann, solange es auf 1 ist, dass er zählt und während er 0 ist, wird nicht gezählt, deswegen z.B. der lange Übergang von 29 auf 0. • Counter Direction bestimmt die Zählrichtung. Ich hoffe, dass ich es einigermaßen verstanden habe.
tobi.python schrieb: > „ S0 <= counter_reset; S1 <= counter_clear; S2 <= counter_not_load; S3 > <= counter_enable; S4 <= counter_direction;“ Das ist nur eine Zuordnung in der Testbench. Denn ich wollte in der Testbench nicht S0 ... S4 verwenden sondern sprechendere Namen. tobi.python schrieb: > Also der Reset bedeutet ja, dass wir wieder bei 0 anfangen zu zählen. Ja, und zwar unabhängig davon was alle anderen Signale (auch der Takt) machen. Das nennt man asynchronen Restet weil der zu jedem Zeitpunkt und unabhängig vom Rest ausgeführt wird. tobi.python schrieb: > • Dasselbe passiert aber auch beim Clear, was ist denn der Unterschied ? Clear ist abhängig vom Takt. Also auch eine Art Reset, aber synchron. Eben zu dem Takt. Wenn kein Takt anliegt, also keine Flanken an CLK ankommen, dann funktioniert auch das Clear nicht. tobi.python schrieb: > • Counter Not load habe ich überhaupt nicht verstanden… Sorgt der bei > einer 0 für eine zufällige Zahl bei der wir die Zählung beginnen ? Nein. Das ist das Signal um dem am Eingang D anliegenden Wert als aktuellen Zählerstand zu laden. Und zwar active low. Sprich das wird gemacht wenn das SIgnal '0' ist. Daher habe ich das not_load genannt weil es eben den Wert von D in den Zähler lädt wenn es '0' ist. Die Zahl ist auch nicht zufällid sondern eben genau das was an D anliegt. In meiner Testbench habe ich vorher die 26 an D angelegt D <= to_unsigned(26,5); dann warte ich einen Takt wait for 10 ns; setze not_load auf '0' damit es D in den Zähler legt counter_not_load <= '0'; warte wieder einen Takt wait for 10 ns; und höre auf mit dem Laden, setze not_load also nach einem Takt wieder auf '1'. Damit ist not_load genau für einen Takt lang auf '0' und somit aktiv. counter_not_load <= '1'; tobi.python schrieb: > • Counter Enable heißt dann, solange es auf 1 ist, dass er zählt und > während er 0 ist, wird nicht gezählt, deswegen z.B. der lange Übergang > von 29 auf 0. Genau. tobi.python schrieb: > • Counter Direction bestimmt die Zählrichtung. Exakt! tobi.python schrieb: > Ich hoffe, dass ich es einigermaßen verstanden habe. Sieht ganz gut aus (-:
Gustl B. schrieb: > tobi.python schrieb: >> Wozu braucht man eine Clock dafür, lässt sich das nicht ohne realisieren >> ? Indem man zB das ganze flankensteuert? > > Woher sollen die Flanken denn kommen? > elsif rising_edge(CLK) then > macht genau das, es reagiert auf Flanken. Eine Clock hat den Vorteil, > dass die Flanken einigermaßen den gleichen Abstand haben, also die > Frequenz fest ist. Du kannst statt Clock natürlich auch einen Taster > verwenden und da händisch draufdrücken. Der Clock ist eigentlich eine total praktische Sache. Die Transistoren im Sizlizum des FPGAs haben ein paar bemerkenswerte physikalische Eigenschaften. So haben die eine "Propagation Delay" d.h. eine Durchlaufzeit, die abhängig von der Zelle ist. Nun sind die Zellen alle im gleichen Prozess gemacht und viele auch gleich groß, d.h. sie sind sehr ähnlich schnell. Allerdings werden die Zellen bei kälte schneller und bei Wärme langsamer. Vor vielen Jahren hatten wir einmal einen Grafikkontroller mit Grafikbeschleunigung in einem FPGA implementiert. Wir haben die Kiste gequält und im Klimaschrank bei 85°C laufen lassen und freuten uns, dass alles stabil lief - bis einer auf die Idee kam, das Teil einmal bei -40°C zu testen. Das RAM-Timing verschob sich und nichts ging mehr. Jetzt kommt die Magie mit dem Clock ins Spiel. Wenn die einzelnen Funktionalen Einheiten immer wieder mit einem Clock auf ein gemeinsames Verständnis von Zeit und Zeitpunkt eingeschworen werden, verschwinden (bei konsequenter Benutzung) diese thermischen (auch Exemplarstreuung usw.) Effekte, so lange der Clock etwas langsamer wie die Gatter laufen und für Synchronität sorgen. Das ist wie beim Tanzen: ohne Musik macht jeder wie er mag, sieht lustig aus, aber ab und an gibt es Zusammenstöße. Mit dem Takt der Musik geht es dann besser. Erkauft wird dieser Effekt damit, dass der Clock natürlich die Performance des FPGAs mindert. Es gab einmal in der FAU Erlangen Studenten, die sich mit der asynchronen Programmierung von FPGAs beschäftigt haben. Dabei laufen die Signale wie Wellen durch das FPGA, limitiert nur von der Laufzeit der Gatter. An den Grenzen der Funktionsdomänen wird es dann interessant, denn da treten dann die Problematiken auf, wann man alle Signale zur Weiterverarbeitung hat. Das ist wohl beherrschbar, aber deutlich schwieriger zu beherrschen und Du musst damit leben, dass Deine Applikation wie ein Thermometer funktioniert, mal schneller mal langsamer und bei einem anderen Speedgrade eines anderen FPGAs geht es dann wieder los...No Gain without Pain...
ICH DANKE EUCH ALLEN VIELMALS, IHR HABT MEINEN LERNERFOLG ENORM ERHÖHT !!! Wünsche euch allen noch ein angenehmes Wochenende, passt auf euch auf!
Gustl B. schrieb: > Tobi A. schrieb: >> Da frage ich mich, >> muss das nicht irgendwie aufhören, also gibt es einen Reset in dieser >> Schaltung oder läuft diese einfach endlos ab ? Der Reset ist ein Hilfsmittel um einmal geordnete Verhältnisse herzustellen. Das hilft beim Konstruieren/Programmieren und beim Testen. Wenn Du mehrere Statemaschines hast, die miteinander interagieren und am Anfang stehen die Zustands-Flip Flops irgend wie, dann kannst Du graue Haare bekommen. Entweder die Teile entwirren sich mit der Zeit (Wenn dahinter eine Steuerung für eine Walzstraße ist, könnte das zu spät sein) oder Du kommst in nicht vorher gesehene Zustände wo der eine Teilnehmer sagt: "Leg auf" und der andere sagt "Nein, leg Du auf" und der erste sagt "Nein, leg Du auf" und so fort. Bei Prozessoren gibt es den Brownout (Angelehnt an den Blackout), der tritt auf, wenn die Spannungsversorgung eines Prozessors so weit ab sinkt, dass er unter der Spezifikation ist, aber der Resetcontroller es dummerweise nicht mit bekommen hat. Dann kann es passieren, dass große Teile des Prozessors dank Designreserve gar nichts mit bekommen, aber andere Teile, die gerade ihre Energie mit Flankenwechseln verbraten haben, plötzlich ins leere Spannungsversorgungsregal greifen. Einige Flip Flops sind dann angepisst und nehmen irgend einen Zustand ein. Wenn das ein Funktionaler Teil ist, den man nicht benutzt, Glück gehabt, beim nächsten Reset ist wieder alles in Ordnung. Wenn das aber ein Interface, ein Speichercontroller oder das Interruptregister ist, dann Hängt der Rechner ganz jämmerlich. Kurzer Exkurs in ein real existierendes Problem. Jetzt zurück zu unserem FPGA-Reset. Wenn Du den Reset nicht nutzt, bekommst Du bei komplexen Designs solche zufälligen Zustände wie sie beim Brownout vor kommen können als default, also immer. Das willst Du nicht wirklich. Der Reset ist also für den definierten Anfang, nicht um eine Arbeit im FPGA zu beenden (aber man kann das Teil natürlich am Schluß im Reset halten, macht aber niemand). Dann lieber intern eine Variable definieren und wenn die gesetzt ist, dann gehen alle Zustandautomaten in den Zustand Halt und die Ausgänge sind definiert. Ein erneuter Reset weckt dann die Schaltung wieder auf - deutlich eleganter.
Jennifer S. schrieb: > Jetzt zurück zu unserem FPGA-Reset. Wenn Du den Reset nicht nutzt, > bekommst Du bei komplexen Designs solche zufälligen Zustände Nein, das passiert nicht. Beim Powerup wird ein RAM-basiertes FPGA (also fast alle bis auf Microsemi/Actel) aus einem Flash mit definierten Werten geladen. Nach diesem Ladevorgang hat jedes Flipflop eine definierten Zustand und läuft immer gleich los. Kein einziges meiner Designs hat einen Reset-Knopf und deshalb auch keinen dedizierten Reset. Nötigenfalls wird einfach das FPGA neu geladen. Und wenn du einen Reset einbaust, dann sorge unbedingt dafür, dass der taktsynchron inaktiv wird. Denn sonst bekommst du Designs, die ab&zu gleich beim Start austicken,wenn die aber mal gestartet sind, dann laufen sie tagelang problemlos. Zum Hintergrund siehe dort: http://www.lothar-miller.de/s9y/categories/35-Einsynchronisieren Mein Tipp: lass dich nicht von gleichen Namen verführen. Die Begriffe, die du von C oder SONST einer prozeduralen Programmiersprache kennst, "funktionieren" in VHDL oft anders. Eine VHDL for-Schleife wird in der erzeugten Hardware "aufgerollt" und führt zu paralleler Hardware. Und noch ein Tipp: sieh dir hin&wieder den RTL-Schaltplan des Synthesizers an und kontrolliere, ob der deine Hardwarebeschreibung verstanden und in die gewünschte Schaltung umgesetzt hat.
Ein paar Begriffe, die du verwendet hast, müsste ich jetzt erstmal nachschlagen =D danke dir für den zusätzlichen Input! Leider ist das tatsächlich bisschen umständlich, wenn man eine andere Sprache gewohnt war….
Tobi A. schrieb: > Da frage ich mich, > muss das nicht irgendwie aufhören, also gibt es einen Reset in dieser > Schaltung oder läuft diese einfach endlos ab? Endlos? Fast. Das läuft solange, bis jemand kommt und den Stecker zieht :-) Diskrete Schaltungen, z.B. aus 7400-Gattern, hören auch nicht irgendwie auf. Duke
Hallo liebe VHDLer, ich oute mich auch gleich mal als Anfänger und lese mich gerade in die Thematik ein. Erlaubt mir bitte gleich mal eine Frage zu dem oben genannten Beispiel-VHDL. Warum wird der Umweg über das “interne” Signal QINT gemacht und nicht direkt mit dem Port Signal Q gearbeitet? Danke schon mal!
Carsten H. schrieb: > Warum wird der Umweg über das “interne” Signal QINT gemacht und nicht > direkt mit dem Port Signal Q gearbeitet? Weil ein Port normalerweise kein speicherndes Verhalten besitzt, das ist nur ein Draht/Drahtbündel. Für einen Zähler braucht man aber Speicher, hier Flipflops. Die entstehen (werden verwendet) wenn man Signale getaktet verwendet. Mit den Ports ginge das auch wenn man Buffer verwendet. Das ist aber keine übliche Beschreibung.
Irgendwie kommt mir der Codeschnippsel bekannt vor. Wo kommt der denn her? Kann es sein, dass der zufälligerweise aus einer Klausur von der TU-Informatik stammt?
Carsten H. schrieb: > Warum wird der Umweg über das “interne” Signal QINT gemacht und nicht > direkt mit dem Port Signal Q gearbeitet? Weil out-Ports nicht rücklesbar sind und man den out-Port sonst fälschlicherweise als inout oder buffer deklarieren müsste. Es gilt zurecht als fristloser Kündigungsgrund, wenn man sowas nur aus Schreibfaulheit macht. Abgesehen davon bekommt man in der Simulation ab&zu seltsame Effekte, wenn ein Port unnötigerweise als bidirektionaler inout deklariert wird. Aber das muss wohl jeder selbst herausfinden...
Carsten H. schrieb: > Warum wird der Umweg über das “interne” Signal QINT gemacht und nicht > direkt mit dem Port Signal Q gearbeitet? weil Port und signal zwei grundverschiedene Dinge sind. Bei Port kann die Eigenschaft 'Richtung' unterschiedliche Eigenschaften haben, ein Signal ist prinzipiell immer bidirektional . Ferner kann ein port auf ein Signal richtungs-konform gemappt werden, während es bei signalen nur die unidirektionale Zuweisung ('<=') gibt . Man beachte also den Unterschied zwischen dem '<=' als Signal assignment und dem '=>' in einer 'port map'. Deshalb verlangen VHDL Styleguides oft das port-namen je nach Richtung auf einen Suffix _o, _i, oder '_io' enden, während signale den Präfix s_ erhalten:
1 | LIBRARY ieee; |
2 | USE ieee.std_logic_1164.ALL; |
3 | USE ieee.numeric_std.ALL; |
4 | |
5 | ENTITY e_aufgabe3 IS |
6 | PORT (clk, s0_i, s1_i, s2_i, s4_i, s3_i : IN std_logic; |
7 | d_i : IN unsigned(4 DOWNTO 0); |
8 | q_o : OUT unsigned(4 DOWNTO 0)); |
9 | END e_aufgabe3; |
10 | |
11 | ARCHITECTURE behavioral OF e_aufgabe3 IS |
12 | SIGNAL s_qint : unsigned(4 DOWNTO 0); |
13 | |
14 | BEGIN
|
15 | P1 : PROCESS(s0_i, clk) |
16 | BEGIN
|
17 | IF s0_i = '1' THEN |
18 | s_qint <= "0000"; |
19 | ELSIF rising_edge(clk) THEN |
20 | IF s1_i = '1' THEN |
21 | s_qint <= "0000"; |
22 | ELSE
|
23 | IF s2_i = '0' THEN |
24 | s_qint <= d_i; |
25 | ELSE
|
26 | IF s3_i = '1' THEN |
27 | IF s4_i = '0' THEN |
28 | s_qint <= s_qint - 2; |
29 | ELSE
|
30 | s_qint <= s_qint + 1; |
31 | END IF; |
32 | END IF; |
33 | END IF; |
34 | END IF; |
35 | END IF; |
36 | END PROCESS P1; |
37 | q_o <= s_ qint; |
38 | END behavioral; |
wie man sieht macht eine style guide regel nicht gleich einen besser lesparen Code, aber es ist schon mal ein Anfang. -- PS: der berühmt-berüchtigte E.W. Djistrka würde wahrscheinlich in Anlehnung am sein Zitat zu BASIC und professinelles Programmieren sagen: “It is practically impossible to teach good FPGA/ASIC-design to students that have had a prior exposure to C-programming: as potential programmers they are mentally mutilated beyond hope of regeneration.” (engl. "mentally mutilated" -> dt. "geistig verzogen") ;-) https://www.goodreads.com/quotes/79997-it-is-practically-impossible-to-teach-good-programming-to-students
Verstanden - Danke für die zahlreichen Antworten und dass ihr mich vor einer fristlosen Kündigung gerettet habt ;-)
Georg A. schrieb: > Irgendwie kommt mir der Codeschnippsel bekannt vor. Wo kommt der denn > her? Kann es sein, dass der zufälligerweise aus einer Klausur von der > TU-Informatik stammt? Ich bin mir inzwischen recht sicher, dass die Aufgabe von mir ist. Ist mein Coding-Style und auch mein typisches TeX-Layout der Klausuren ERA/ETI (Einführung in die Rechnerarchitektur bzw. Technische Informatik). Die habe ich von 1997 bis 2013 an der TUM verbrochen, also VIELE (inkl. Unteraufgaben und natürlich auch Wiederholungsklausuren), daher kann ich mich so ganz konkret nicht mehr dran erinnern ;) Ist übrigens Erstsemesterstoff. Aber evtl. zur Einordnung: Immer gab es da Aufgaben, irgendeine Logik und Automaten aus einer mehr oder weniger sinnvollen technischen Anforderung zu erstellen. Je nach Lust und Laune aber auch mal etwas drüber hinaus, hier also aus einem gegebenen Code das Verhalten nachzuvollziehen. Deswegen auch die aussagelosen Steuersignale S*. Wäre ja langweilig, wenn die schon CLEAR, LOAD, ENABLE, ADD1 oder SUB2 heissen würden... Vermutlich gab es eine Skizze mit einem vorgegebenen Diagramm für alle Eingangssignale, und man sollte dann den jeweiligen Stand von QINT hinzeichnen. Da in Vorlesung/Übungen kein Tristate für VHDL in der "echten" Anwendung erklärt wurde, gabs auch immer nur in oder out als Portmode. Daher der Umweg über das interne QINT-Signal, damit man nicht mit inout oder buffer rumspielen muss. Haben aber egal bei welcher Aufgabe eh immer irgendwelche Knalltüten ohne technischen Zwang gemacht. Keine Ahnung wer ihnen das beigebracht hat, ich jedenfalls nicht ;) Es kann auch sehr gut sein, dass das mit dem QINT<="0000" kein unbeabsichtigter Fehler in der Angabe war, sondern tatsächlich noch eine kleine 1Punkt-Zusatzaufgabe ala "der Code enthält einen kleinen Fehler, wo?". Die meisten dieser Zählautomaten waren nämlich immer mit 4 Bit (3 downto 0). Deswegen ist es spannend, wer bei Abweichung von den üblichen Aufgaben was merkt (d.h. verstanden hat) oder wer nur auswendig gelernt hat.
Lothar M. schrieb: > Weil out-Ports nicht rücklesbar sind und man den out-Port sonst > fälschlicherweise als inout oder buffer deklarieren müsste. Sie sind doch rücklesbar ab VHDL-2008. Was spricht dagegen dieses Feature zu nutzen?
raX schrieb: > Sie sind doch rücklesbar ab VHDL-2008. Was spricht dagegen dieses > Feature zu nutzen? Synthetisierbarkeit! Und Ausgangsport sind im real life nicht rücklesbar. Was rücklesbar ist, ist das out-FF das vor dem output-port liegt. Nochmals VHDL ist für die Simualtion, aber nicht für die Synthese standardisiert.
Lerninstructor schrieb: > Was rücklesbar ist, > ist das out-FF das vor dem output-port liegt. wenn es benutzt wird, was im code ja explizit erzeugt werden muss, um zu verhindern, dass es dem routing zum opfer fällt und damit ein Signal vorliegt, an das man ankoppeln kann. Ich empfehle, sich NICHT an die Ausgänge von Modulen dranzuhängen, insbesondere dann nicht, wenn man die Module nur wegen der Übersichtlichkeit eingeführt hat und in Wirklichkeit alles plattoptimieren will.
Ich habe solche "Tricks" den Studis nicht beigebracht, weil damit auch der Eindruck einer "normalen" Programmiersprachen erweckt wird. Es geht aber in der Vorlesung eben genau darum, die Unterschiede deutlich zu machen. Mit der Art der eventgesteuerten Signalverarbeitung inkl. Deltacycles als deren zwangsläufiger Entsprechung von realer HW haben die meisten Erstsemester ohnehin schon genug Probleme ("wie, ich kann nach einer <=-Zuweisung nicht gleich auf den aktuellen Wert zugreifen?"). Da brauch ich jetzt nicht noch irgendwelche nerdigen syntaktischen Vereinfachungen aus VHDL-4711, die Leute müssen die generelle Struktur kapieren. Daher ist die Trennung von internem Zustand und der Ausgabe (die hier auch nur zufälligerweise mit dem internen Zustand identisch ist) auch nochmal etwas, um das hervorzuheben.
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.