Datum:
Guten Tag an alle!!! Ich brauche paar tipps zum Thema VHDL. Mein Design funktioniert zwar, aber ich hatte viele Timing-Probleme (die ich bereits schot gelöst habe). Trotzdem mache ich mir immer noch gedanken um "richtigkeit" meines VHDL-Codes. So sieht's bei mir aus...
PORT_CS <= '1' when cpu_IORQ = '0' and cpu_WR = '0' and cpu_A(15 downto 8) = "01110011" else '0'; process (clk25,reset) begin if reset = '0' then RAM_Page <= "00"; ROM_Page <= '0'; elsif rising_edge(clk25) then if P7ORT_CS = '1' then RAM_Page <= cpu_DO(1 downto 0); ROM_Page <= cpu_DO(3); end if; end if; end process; |
Jetzt weiss ich nicht ob es besser wäre die Bedingug direkt im "IF" zu schreiben:
process (clk25,reset) begin if reset = '0' then RAM_Page <= "00"; ROM_Page <= '0'; elsif rising_edge(clk25) then if cpu_IORQ = '0' and cpu_WR = '0' and cpu_A(15 downto 8) = "01110011" then RAM_Page <= cpu_DO(1 downto 0); ROM_Page <= cpu_DO(3); end if; end if; end process; |
Macht es überhaupt underschiede? Wenn ja, welche???
Datum:
>Macht es überhaupt underschiede?
Nein, schau dir einfach mal die RTL-Schematics an.
Die 2. Lösung ist einfach schöner lesbar, weil kompakter...
Ein Tipp:
Nimm den Reset mit in den synchronen Teil des Prozesses, auch wenn die
allgegenwärtigen Code-Beispiele anders aussehen.process (clk25) begin if rising_edge(clk25) then if reset = '0' then RAM_Page <= "00"; ROM_Page <= '0'; elsif cpu_IORQ = '0' and cpu_WR = '0' and cpu_A(15 downto 8) = "01110011" then RAM_Page <= cpu_DO(1 downto 0); ROM_Page <= cpu_DO(3); end if; end if; end process; |
1. Grund: Was würde in deinem Design passieren, wenn der Reset super knapp vor der steigenden Flanke des Taktes inaktiv würde? Bekommen das alle FFs gleich- und rechtzeitig mit? Läuft dann dein ganzes FPGA zuverlässig an? Nein: der Reset ist ein asynchrones Signal (das asynchrone Signal schlechthin), der muss auch auf deinen Takt einsynchronisiert werden (wie jedes andere asynchrone Signal). Und wenn der Reset dann schon synchron ist, gehört er auch in den getakteten Teil. 2. Grund: Der ganze Rest des Designs ist synchron, nur für den asynchronen Reset zwingst du das Synthesetool, asynchrone FFs zu verwenden. Der Synthesizer verwendet dann sozusagen die "falschen" FFs. Und mit diesen FFs kann der synchrone Teil der Schaltung (und das ist der, der die Arbeit tut) nicht so schön optimiert werden. 3. Grund: wozu brauchst du einen Reset? Für den allgegenwärtigen Reset-Taster? Ist der es Wert, wertvolle Resourcen zu vergeuden? Dazu auch: http://www.xilinx.com/support/documentation/white_... Meine Aussagen gelten für Xilinx, inwiefern das für andere Architekturen passt: bitte selber überprüfen.
Datum:
Vielen dank für die Info!!!! Alles super erklärt! Zu Punkt 3. Ein Reset brauche ich schon, kann aber 90% davon wegschmeissen. Ich werde heute noch alles ändern. :) Es ist mir einfach SEHR interessant, wie sich die Laufzeiten ändern! p.S. ich dachte immer das "reset" eines FlipFlops keine zusätzliche Resourcen verwendet, da die FlipFlops SET- und RESET- eingänge haben und diese werden dafür verwendet.
Datum:
Angehängte Dateien:Dimi wrote: > p.S. ich dachte immer das "reset" eines FlipFlops keine > zusätzliche Resourcen verwendet Richtig: es werden für den Reset keine zusätzlichen Ressourcen verschwendet, die sind alle schon da. Nur werden für den asynchronen Reset dann auch asynchrone FFs eingesetzt. Und so ein FF kann nur entweder asynchron (FDCP, mit preset und clear) oder synchron (FDRS, mit set und reset) konfiguriert werden. Und bei einem synchronen Design kann der Synthesizer mit einem synchronen FF wesentlich mehr anfangen. > da die FlipFlops SET- und RESET- eingänge haben Ja, es gibt wie gesagt grundlegend 2 verschiedene Möglichkeiten, die FFs zu konfigurieren (mal von den DDR-FFs abgesehen). Ein kleines Beispiel: Asynchroner Reset
architecture Behavioral of Reset_1 is -- AsyncSync signal do : std_logic; begin process (clk) begin if (reset='1') then -- async. Reset do <= '0'; elsif rising_edge(clk) then if (set='1') then -- sync. Set do <= '1'; elsif (load='1') then -- laden do <= din; else do <= do; -- speichern end if; end if; end process; dout <= do; end Behavioral; |
Und im Anhang die RTL-Schematic. Schön aufwendig, nicht wahr? : : :
Datum:
Angehängte Dateien:: : Und dann: Synchroner Reset
architecture Behavioral of Reset_1 is -- Synchron signal do : std_logic; begin process (clk) begin if rising_edge(clk) then if (reset='1') then -- sync. Reset do <= '0'; elsif (set='1') then -- sync. Set do <= '1'; elsif (load='1') then -- laden do <= din; else do <= do; -- speichern end if; end if; end process; dout <= do; end Behavioral; |
Schön einfach, nicht wahr? Welche der beiden Lösungen dürfte schneller sein? Spätestens jetzt sollte der Groschen fallen... ;-)
Datum:
Meine Lieblingsschreibweise wäre dann so:
architecture Behavioral of Reset_1 is -- Synchron signal do : std_logic; begin process begin wait until rising_edge(clk); if (reset='1') then do <= '0'; -- sync. Reset elsif (set='1') then do <= '1'; -- sync. Set elsif (load='1') then do <= din; -- laden -- else do <= do; -- speichern: implizit end if; end process; dout <= do; end Behavioral; |
Schöner gehts nimmer... ;-)
Datum:
VIELEN VIELEN DANK!!! Die Ergebnisse kommen noch :)
Datum:
@lkmiller: Könntest du, nachdem du das ganze schon parat hast, das ganze noch umdrehen, also im Reset '1' zuweisen und im synchronen Set '0'. Dann müsste sich das Ganze, wenigstens bei Xilinx, wieder ziemlich ändern, weil das Reset an sich eine höhere Priorität hat als das Set und das Synthesetool das wieder so hinbauen muss. Würde mich interessieren, ob ich mit dieser Vermutung recht habe.
Datum:
Angehängte Dateien:>Würde mich interessieren, ob ich mit dieser Vermutung recht habe.
Hier geht die Geschichte unentschieden aus:
beide Lösungen brauchen gleich viel zusätzliche Logik.
Ansatz:
(Beispiel: synchron)
wait until rising_edge(clk);
if (reset='1') then -- sync. Reset
do <= '1'; -- auf '1'
elsif (set='1') then -- sync. Set
do <= '0'; -- auf '0'
elsif (load='1') then -- laden
do <= din;
else
do <= do; -- speichern
end if;
|
Im Bild: oben asynchrones FF unten synchrones FF Fazit: man muss dem FPGA schon ein wenig "nach dem Maul" programmieren ;-)
Datum:
Danke für die Mühe. Theoretisch könnte man ja auch die Daten an Eingang und Ausgang invertieren, dann könnte man auch das Set/Reset Assignment umdrehen und das Synthesetool könnte wieder die Priorisierung der verschiedenen Eingänge ausnutzen. Wobei das wohl auch Hirnw*chserei ist, nachdem man für eine Invertierung ja erst wieder über eine LUT gehen muss. Aber spannend ist das Thema jedenfalls :) . Lesetipp dazu ist übrigens das Xilinx WP275 "Get your priorities right".
Datum:
>nachdem man für eine Invertierung ja erst wieder über eine LUT gehen muss
Nein, das ist nicht nur theoretische Kunst. Natürlich wirst du nicht
jeden Pfad optimal hinbekommen. Aber wenn du den kritischen Logikpfad
u.U. durch das Herausnehmen einer Logikebene und Einfügen derselben in
den Set/Reset-Pfad schneller bekommst, dann hat das was.
Wichtig ist hier zuerst das Wissen oder wenigstens eine Ahnung, _was
überhaupt_ aus der Beschreibung gemacht werden wird. Wenn man nicht
alles falsch macht, hat man schon Vieles richtig gemacht.
Datum:
Es kann jedenfalls nicht schaden, zu verstehen, wie die HW die man da bearbeitet, funktioniert. In diesem speziellen Fall braucht man aber auch für den ungünstigen Fall nur eine Logikebene (wenn ich es richtig sehe), wenn man Daten davor und danach invertieren will aber zwei. Darum hab ich das doppelte Invertieren mal nur in die Ecke Spielerei geschoben. Und wenn man gerade so an der Grenze ist mit dem Timing würden viele wohl einfach einen schnelleren Speedgrade nehmen, ist vermutlich auch wirtschaftlich die vernünftigere Entscheidung. Aber ein wenig Spielerei muss ja auch sein :) .
Datum:
> In diesem speziellen Fall... Richtig, hier wird sowieso nur 1 LUT nötig sein. Aber sobald in die Set- und Reset-Abfragen etwas mehr reinkommt (Adressdecoder, States) könnten unnötigerweise 2 Logikebenen synthetisiert werden. Und auf einmal ("Ich habe doch fast nichts geändert") ist es zu langsam oder zu groß. > verstehen, wie die HW die man da bearbeitet, funktioniert... Das ist wie mit dem Wissen, wie die rote Ampel funktioniert: Die Strasse darunter ist an sich immer gleich gut befahrbar. Aber mit dem Wissen, dass die Ampel zur Strasse gehört, wirds dann auch ungefährlich. Sonst geht das Überqueren mal gut und und mal nicht... ;-)
Datum:
@Lothar Miller: Jetzt musst Du nur noch die C-like Klammern in den if-Abfragen einsparen. Da wäre es perfekt :-) Rick
Datum:
Danke für die Blumen, aber wenn ich tippe geht nach if( automatisch die Klammer auf. Egal ob C oder VHDL, ich kann da gar nicht anders... ;-)
Datum:
Die Klammern machen schon Sinn, wenn man zwsichen C<->VHDL wechselt. "Die 2. Lösung ist einfach schöner lesbar, weil kompakter..." Ich nicht! Ich finde die erste mit dem explizieten chip select die bessere.
Datum:
>Ich finde die erste mit dem explizieten chip select die bessere.
Wenn ich aus einem ganzen Adressraum mehrere Adressbereiche selektieren
will, dann erzeuge ich mir auch einzelne Chip-Selects für jeden Bereich.
Nur bestehen die dann nicht wie hierPORT_CS <= '1' when cpu_IORQ = '0' and cpu_WR = '0' and cpu_A(15 downto 8) = "01110011" else '0'; |
aus einer ganzen Latte Kombinatorik, sondern eben nur aus den Adressleitungen. So etwa:
PORT_CS <= '1' when (cpu_A(15 downto 8) = "01110011") else '0'; : : elsif (cpu_IORQ='0' and cpu_WR='0' and PORT_CS) then : |
Und am eigentlichen Verwendungsort werden dann RD bzw WR dazu kombiniert.
Datum:
und wo ist da der Unterschied ? Der Synthese juckt das nicht.


