Warum verschlingt dieses Verilog 30 Makrozellen und Hunderte von Produktbegriffen?

Ich habe ein Projekt, das 34 Makrozellen eines Xilinx Coolrunner II verbraucht. Ich bemerkte, dass ich einen Fehler hatte und verfolgte ihn zu diesem:

assign rlever = RL[0] ? 3'b000 :
                RL[1] ? 3'b001 :
                RL[2] ? 3'b010 :
                RL[3] ? 3'b011 :
                RL[4] ? 3'b100 :
                RL[5] ? 3'b101 :
                RL[6] ? 3'b110 :
                        3'b111;

assign llever = LL[0] ? 3'b000 :
                LL[1] ? 3'b001 :
                LL[2] ? 3'b010 :
                LL[3] ? 3'b011 :
                LL[4] ? 3'b100 :
                LL[5] ? 3'b101 :
                        3'b110 ;

Der Fehler ist, dass rleverund lleverein Bit breit sind, und ich brauche, dass sie drei Bit breit sind. Wie dumm von mir. Ich habe den Code wie folgt geändert:

wire [2:0] rlever ...
wire [2:0] llever ...

Also gab es genug Bits. Als ich das Projekt jedoch neu erstellte, kostete mich diese Änderung mehr als 30 Makrozellen und Hunderte von Produktbegriffen. Kann mir jemand erklären was ich falsch gemacht habe?

(Die gute Nachricht ist, dass es jetzt korrekt simuliert ... :-P )

BEARBEITEN -

Ich nehme an, ich bin frustriert, denn ungefähr zu dem Zeitpunkt, an dem ich glaube, dass ich Verilog und CPLD verstehe, passiert etwas, das zeigt, dass ich eindeutig kein Verständnis habe.

assign outp[0] = inp[0] | inp[2] | inp[4] | inp[6];
assign outp[1] = inp[1] | inp[2] | inp[5] | inp[6];
assign outp[2] = inp[3] | inp[4] | inp[5] | inp[6];

Die Logik zur Implementierung dieser drei Zeilen kommt zweimal vor. Das bedeutet, dass jede der 6 Zeilen von Verilog etwa 6 Makrozellen und jeweils 32 Produktterme verbraucht .

BEARBEITEN 2 - Gemäß dem Vorschlag von @ThePhoton zum Optimierungsschalter finden Sie hier Informationen von den von ISE erstellten Zusammenfassungsseiten:

Synthesizing Unit <mux1>.
    Related source file is "mux1.v".
    Found 3-bit 1-of-9 priority encoder for signal <code>.
Unit <mux1> synthesized.
(snip!)
# Priority Encoders                                    : 2
 3-bit 1-of-9 priority encoder                         : 2

Der Code wurde also eindeutig als etwas Besonderes erkannt. Das Design verbraucht jedoch immer noch enorme Ressourcen.

BEARBEITEN 3 -

Ich habe einen neuen Schaltplan erstellt, der nur den von @thePhoton empfohlenen Mux enthält. Die Synthese führte zu einem unbedeutenden Ressourcenverbrauch. Ich habe auch das von @Michael Karas empfohlene Modul synthetisiert. Dies führte auch zu einem unbedeutenden Verbrauch. Es herrscht also eine gewisse Vernunft vor.

Meine Verwendung der Hebelwerte verursacht eindeutig Bestürzung. Da kommt noch mehr.

Endgültige Bearbeitung

Das Design ist nicht mehr verrückt. Ich bin mir jedoch nicht sicher, was passiert ist. Ich habe viele Änderungen vorgenommen, um neue Algorithmen zu implementieren. Ein Faktor, der dazu beitrug, war ein „ROM“ mit 111 15-Bit-Elementen. Dies verbrauchte eine bescheidene Anzahl von Makrozellen, aber vielvon Produktbegriffen - fast alle auf dem xc2c64a verfügbaren. Ich suche danach, hatte es aber nicht bemerkt. Ich glaube, mein Fehler wurde durch die Optimierung versteckt. Die "Hebel", von denen ich spreche, werden verwendet, um Werte aus dem ROM auszuwählen. Ich gehe davon aus, dass ISE bei der Implementierung des (kaputten) 1-Bit-Prioritätscodierers einen Teil des ROM wegoptimiert hat. Das wäre ein ziemlicher Trick, aber es ist die einzige Erklärung, die mir einfällt. Diese Optimierung reduzierte den Ressourcenverbrauch deutlich und wiegte mich in der Erwartung einer bestimmten Grundlinie ein. Als ich den Priority-Encoder (wie in diesem Thread) repariert habe, habe ich den Overhead des Priority-Encoders und des zuvor optimierten ROMs gesehen und dies ausschließlich dem ersteren zugeschrieben.

Nach all dem war ich gut mit Makrozellen, hatte aber meine Produktkonditionen erschöpft. Die Hälfte des ROM war wirklich ein Luxus, da es nur die 2er-Zusammenstellung der ersten Hälfte war. Ich habe die negativen Werte entfernt und sie an anderer Stelle durch eine einfache Berechnung ersetzt. Dadurch konnte ich Makrozellen gegen Produktbedingungen eintauschen.

Im Moment passt dieses Ding in den xc2c64a; Ich habe 81 % bzw. 84 % meiner Makrozellen bzw. Produktbegriffe verwendet. Natürlich muss ich es jetzt testen, um sicherzustellen, dass es das tut, was ich will ...

Danke an ThePhoton und Michael Karas für die Hilfe. Zusätzlich zu der moralischen Unterstützung, die sie mir bei der Lösung dieses Problems gewährt haben, habe ich aus dem von ThePhoton veröffentlichten Xilinx-Dokument gelernt und den von Michael vorgeschlagenen Prioritäts-Encoder implementiert.

impliziert nicht jedes Fragezeichen dort effektiv einen Multiplexer, und strukturell haben Sie sie auch kaskadiert? Wie viele Makrozellen haben Sie erwartet?
Ich weiß nicht, wie viele Makrozellen das Konstrukt verbrauchen sollte. Wenn man jedoch bedenkt, dass mein Projekt derzeit 34 Makrozellen verbraucht, einschließlich dieser beiden 1-Bit-Multiplexer, und dass diese nur ein kleiner Teil des Projekts sind, bin ich von diesem Ergebnis überrascht.
Welches Werkzeug verwenden Sie?
ISE von Xilinx...
Im Code in Ihrer Bearbeitung möchten Sie meiner Meinung |nach anstelle von ||.
@ThePhoton Ja, das war der nächste, heh. Ich habe die zusammenfassenden Informationen gepostet, aus denen hervorgeht, dass Ihr Optimierungsvorschlag von ISE/XST erkannt und implementiert wurde.
@ThePhoton hat den Code geändert, um das bitweise OR zu verwenden, kein wesentlicher Unterschied.
Diese Probleme scheinen immer völlig blockiert zu sein, bis Sie den einen Hinweis finden, der sie aufbricht. ROM in einem CPLD ist wahrscheinlich sehr ressourcenhungrig ... es muss im Grunde mit Logik emuliert werden. Dieses Design scheint für ein (sehr kleines) FPGA besser geeignet zu sein als für ein CPLD ... wenn Sie die Möglichkeit haben, auf dieser Ebene neu zu entwerfen. Eines der neueren Altera- oder Lattice-CPLDs (die eigentlich FPGAs mit eingebautem Konfigurationsspeicher sind) könnte auch gut passen.

Antworten (2)

Der angezeigte Code ist im Wesentlichen ein Prioritätscodierer. Das heißt, es hat einen Eingang für viele Signale, und sein Ausgang zeigt an, welches dieser Signale gesetzt ist, wobei dem am weitesten links stehenden gesetzten Signal Priorität gegeben wird, wenn mehr als eines gesetzt ist.

Ich sehe jedoch widersprüchliche Definitionen des Standardverhaltens für diese Schaltung an den beiden Stellen, die ich überprüft habe.

Laut Wikipedia nummeriert der Standard-Prioritäts-Encoder seine Eingänge von 1 an. Das heißt, wenn das niederwertigste Eingangsbit gesetzt ist, gibt er 1 aus, nicht 0. Der Wikipedia-Prioritäts-Encoder gibt 0 aus, wenn keines der Eingangsbits gesetzt ist.

Das XST-Benutzerhandbuch von Xilinx (S. 80) definiert jedoch einen Prioritäts-Encoder, der näher an dem liegt, was Sie codiert haben. Die Eingänge sind von 0 an nummeriert, wenn also das lsb des Eingangs gesetzt ist, ergibt es einen 0-Ausgang. Die Xilinx-Definition gibt jedoch keine Spezifikation für die Ausgabe an, wenn alle Eingabebits gelöscht sind (Ihr Code gibt 3'd7 aus).

Das Xilinx-Benutzerhandbuch bestimmt natürlich, was die Xilinx-Synthesesoftware erwartet. Der Hauptpunkt ist, dass (*priority_extract ="force"*)XST eine spezielle Anweisung benötigt, um diese Struktur zu erkennen und optimale Syntheseergebnisse zu erzielen.

Hier ist das von Xilinx empfohlene Formular für einen 8-zu-3-Prioritätscodierer:

(* priority_extract="force" *)
module v_priority_encoder_1 (sel, code);
input [7:0] sel;
output [2:0] code;
reg [2:0] code;
always @(sel)
begin
    if (sel[0]) code = 3’b000;
    else if (sel[1]) code = 3’b001;
    else if (sel[2]) code = 3’b010;
    else if (sel[3]) code = 3’b011;
    else if (sel[4]) code = 3’b100;
    else if (sel[5]) code = 3’b101;
    else if (sel[6]) code = 3’b110;
    else if (sel[7]) code = 3’b111;
    else code = 3’bxxx;
end
endmodule

Wenn Sie Ihre Umgebungslogik neu anordnen können, damit Sie den von Xilinx empfohlenen Codierungsstil verwenden können, ist dies wahrscheinlich der beste Weg, um ein besseres Ergebnis zu erzielen.

Ich denke, Sie können dies erreichen, indem Sie das Xilinx-Encodermodul mit instanziieren

v_priority_encoder_1 pe_inst (.sel({~|{RL[6:0]}, RL[6:0]}), .code(rlever));

Ich habe alle Bits zusammengefügt RL[6:0], um ein 8. Eingangsbit zu erhalten, das den 3'b111-Ausgang auslöst, wenn alle RL-Bits niedrig sind.

Für die lleverLogik können Sie wahrscheinlich die Ressourcennutzung reduzieren, indem Sie ein modifiziertes Encodermodul nach der Xilinx-Vorlage erstellen, das jedoch nur 7 Eingangsbits benötigt (Ihre 6 Bits LLplus ein zusätzliches Bit, das hoch geht, wenn die anderen 6 alle niedrig sind).

Die Verwendung dieser Vorlage setzt voraus, dass Ihre ISE-Version die XST-Synthese-Engine verwendet. Es scheint, als würden sie die Synthesewerkzeuge bei jeder größeren Version von ISE ändern, also überprüfen Sie, ob das von mir verlinkte Dokument tatsächlich Ihrer Version von ISE entspricht. Wenn nicht, überprüfen Sie den empfohlenen Stil in Ihrer Dokumentation, um zu sehen, was Ihr Tool erwartet.

Danke, das wird einige Zeit dauern, um es zu verdauen. Meine ISE verwendet XST, obwohl ich nicht weiß, welche Version.
Der Schlüssel ist, die Ausgabe zu haben (* priority_extract="force" *)und wahrscheinlich auch explizit die Ausgabe von egal zu enthalten, obwohl Sie jede mögliche Eingabe abdecken. (Ohne sie versucht XST wahrscheinlich, eine vollständige Nachschlagetabelle zu erstellen, weshalb so viele Produktbegriffe vorhanden sind.) Versuchen Sie zuerst, die Option "egal" hinzuzufügen. Wenn es nicht funktioniert, versuchen Sie es genau mit der Xilinx-Boilerplate.
Ich habe einen vollständigen Rip des obigen Codes implementiert und kein verbessertes Ergebnis erhalten. Die ISE-Zusammenfassungsseiten zeigen an, dass ein MUX erkannt wurde, obwohl die Erkennung nicht so stark war wie bei anderen Konstrukten. Ich werde die relevanten Informationen in ein paar Minuten posten.
bearbeiten - ignorieren Sie den obigen Kommentar zu "starker Wiedererkennung" - es ist da, ich habe es gestern Abend gerade verpasst; Ich habe die Arbeit überarbeitet und die Realität funktioniert korrekt.

Die Antwort von ThePhoton ist ausgezeichnet. Ich möchte hier einige zusätzliche Informationen zu Ihrer Überlegung hinzufügen. Dies rührt von der Tatsache her, dass wir, obwohl wir hochmoderne, ausgefallene FPGA- und CPLD-Geräte haben, die HDLs und Synthesewerkzeuge verwenden, aufschlussreich sein können, Dinge, die vor Jahren entwickelt wurden, genau zu betrachten. Bleiben Sie bei mir, während ich dies bis zu meiner Empfehlung am Ende durchgehe.

Es gibt diskrete Logikteile, die die Prioritätscodierfunktion ausführen. Die durch diese Teile implementierte Logik gibt es schon lange, als es wichtig war, die Anzahl der Transistoren auf ein absolutes Minimum zu reduzieren. Sie können im Internet nach Logikteilen mit generischen Teilenummern wie 74HC148 oder MC14532B suchen, um Datenblätter zu finden, die entsprechende Logikdiagramme für diese Teile enthalten. Das folgende Diagramm ist ein Beispiel aus dem TI-Datenblatt für das Teil 74HC148 .

Geben Sie hier die Bildbeschreibung ein

Diese Logik implementiert die folgende Wahrheitstabelle (aus demselben Datenblatt):

Geben Sie hier die Bildbeschreibung ein

Beachten Sie, dass die obige Teilefamilie niedrige aktive Eingangssignale verwendet. Ein weiteres Datenblatt für das MC14532B-Teil von ON Semiconductor zeigt eine Wahrheitstabelle für die Encoder-Funktion, die Active-High-Eingangssignale ähnlich Ihrem Verilog-Beispiel verwendet.

Geben Sie hier die Bildbeschreibung ein

Das gleiche Datenblatt zeigt die logischen Gleichungen für den MC14532B wie folgt:

Geben Sie hier die Bildbeschreibung ein

Möglicherweise möchten Sie ähnliche Gleichungen direkt in Ihren Verilog-Code codieren, um zu sehen, wie er mit Ihrem aktuellen Beispiel verglichen wird. Es ist sehr wahrscheinlich, dass es zu einem viel günstigeren Ergebnis führt.

Danke, das werde ich tun. Dieses Problem bringt mich um. Ich glaube, es war früher effizienter zu synthetisieren. Und dann habe ich etwas geändert. /selbstfick
Danke, ich habe es umgesetzt. Es hat leider keinen materiellen Unterschied gemacht.
Gute Antwort. Lassen Sie uns Tony sehen, wie viele Produktbegriffe benötigt werden sollten , um diese Logik zu implementieren. Tony, wenn Sie entweder die Boilerplate von Xilinx oder die Gleichungen von Michael verwenden und immer noch Hunderte von Produktbegriffen generieren, müssen Sie an einer anderen Stelle in Ihrem Code nach einer subtilen Änderung suchen, die das Problem verursacht haben könnte. oder schauen Sie sich die Syntheseprotokolldatei sehr genau an, um zu sehen, ob etwas passiert, das Sie nicht erwarten.
Ich stimme @ThePhoton vollkommen zu. Ich habe etwas abgespritzt. Ich bin mir so sicher wie ich sein kann, dass das früher funktioniert hat - ich habe nicht einmal bemerkt, dass der Verbrauch so gering war. Nun ja, das ist eine gute Ausrede, um mehr über die Zusammenfassungsinformationen zu erfahren.