VHDL: Demultiplexen eines Signals zu einem von vielen Ausgängen, während unbenutzte Ausgänge auf „0“ gesetzt werden

Ich versuche, synthetisierbares VHDL zu erstellen, das einen kontinuierlichen Ein-Bit-Signalstrom an einen von vielen Ausgängen demultiplext. Die Ausgänge, die dieser Stream nicht sendet, sollten auf '0' gesetzt werden. Siehe Bild unten für eine Vorstellung davon, was ich zu erreichen versuche.

Demux-Diagramm

Der Code, den ich geschrieben habe, um diese Funktionalität zu erstellen, lautet:

send_s         <= (line_select_s => prbs_i(0), others => '0');

wobei 'prbs_i(0)' der Signalstrom ist.

Leider ist dies in Vivado nicht synthetisierbar und gibt den Fehler aus:

[Synth 8-211] could not evaluate expression: aggregate choice expression

Gibt es einen geeigneten Weg, dies zu tun? Das VHDL simuliert gut, wird aber nicht synthetisiert.

Antworten (2)

Das Problem mit Ihrem Code ist, dass eine Zuweisung des Formulars:

a <= (3 => '0', others => '1');

müssen Konstanten für die zugewiesenen Offsets verwenden (in diesem Fall 3).

Wenn Sie möchten, dass der Offset variiert, müssen Sie ihn in zwei Zuweisungen aufteilen. Beachten Sie, dass dies nur innerhalb eines Prozesses funktioniert; Bei zwei gleichzeitigen Zuweisungen würden Sie auf ein Problem mit mehreren Treibern stoßen.

process (line_select_s, prbs_i)
begin
  send_s <= (others => '0');
  send_s(line_select_s) <= prbs_i(0);
end process;

Dies funktioniert, weil wir zwar mit der Zuweisung '0'an den gesamten Vektor beginnen, die letzte Zuweisung an ein bestimmtes Signal in einem Prozess jedoch Vorrang hat.

Eine Alternative ist die Verwendung einer Schleife:

process (line_select_s, prbs_i)
begin
  send_s <= (others => '0');
  for i in send_s'range loop
    if (i = line_select_s) then
      send_s(i) <= prbs_i(0);
    end if;
  end loop;
end process;

Dies hat den Vorteil, dass, wenn Ihr Auswahlsignal einen Versatz darstellen kann, der größer ist als die Breite Ihres Zielvektors, kein Fehler in der Simulation erzeugt wird. Ein Beispielszenario wäre ein 3-Bit-Auswahlsignal, aber ein Zielvektor mit nur 5 Elementen; Das erste Verfahren würde einen Fehler erzeugen, wenn das Auswahlsignal 6, 7 oder 8 darstellen würde, das zweite jedoch nicht.

Als Nebenbemerkung möchten Sie vielleicht einen Prozess wie diesen synchronisieren, wenn Sie die beste Leistung (in Bezug auf die maximale Betriebsfrequenz) aus Ihrem Design herausholen möchten.

Nur um zu erweitern, warum Sie die Schleife nicht vereinfachen können send_s(line_select_s) <= prbs_i(0);: Denken Sie daran, dass dieser Prozess Hardware generieren muss, damit jeder Ausgang das Signal tragen kann (daher die Schleife) und nur den ausgewählten ansteuern kann (daher das if). Die Schleife wird effektiv durch Synthese entrollt, wodurch eine Reihe von Treibern generiert wird, die parallel arbeiten, einer für jeden Ausgang.
Großartig, danke @scary_jeff! Das macht Sinn. Vergessen zu erwähnen - ich hatte dies bereits in einem synchronen Prozess, sodass Ihre Idee einfach zu meinem vorhandenen Code hinzugefügt werden konnte. @BrianDrummond, ich hatte es vermutet, war aber enttäuscht, dass der Synthesizer / VHDL-Standard nicht "intelligent genug" war, um den einzeiligen Ansatz zu ermöglichen.
Das ist der Unterschied zwischen Simulation (wo es funktionieren sollte) und syntheseerzeugender Hardware. Synthesizer-Tools sind viel intelligenter geworden, aber sie arbeiten im Wesentlichen immer noch, indem sie Designmuster (wie diese Schleife) sehen und sie transformieren.
@BrianDrummond du hast mich dazu gebracht, an mir selbst zu zweifeln, ich verstehe nicht, warum es send_s <= (others => '0'); send_s(line_select_s) <= prbs_i(0);nicht funktionieren würde?
Bearbeitete Antwort zur Vereinfachung. Die Schleife war nicht erforderlich.
Ha! und tatsächlich synthetisiert Xilinx XST (14.4) beide Versionen in fünf LUTs! Gut gefragt, Jeff! (Ich habe Synplicity- oder Altera-Tools nicht ausprobiert)
Danke @BrianDrummond, ich denke, die Loop-Methode kann doch einen Vorteil haben, siehe meine zweite Bearbeitung. Beifall.
Ähhh. Ich habe bessere Typen gewählt ... meine Auswahl war natural range 0 to 4(oder der Bereich des Ausgangsports), sodass solche Fehler nicht möglich waren. Aber ich sehe gerne beide Ansätze in der Antwort, man weiß nie, wann die Schleife notwendig sein kann.

Viele Wege sind da. Eine einfache Möglichkeit ist, nach Datenflussmodell:

with line_select_s select
send_s <= (send_s & "0000") when "000",
        ('0' & send_s & "000") when "001",
        ("00" & send_s & "00") when "010",
        ("000" & send_s & '0') when "011";
        ("0000" & send_s) when "100";
         "00000" when others;
Dies würde funktionieren, ist jedoch nicht wirklich verwendbar, wenn Sie mehr als ein paar Ausgabezeilen haben. In meinem Fall habe ich über 30.
Dieses Codesegment wäre um 30 Zeilen länger. Denken Sie jedoch daran, dass die Codegröße und die Größe der synthetisierten Hardware in keiner Beziehung zueinander stehen.
Aber Ihr Code ist nicht wartbar. Ein Demux kann in 3 Zeilen beschrieben werden: for-generate-Anweisung und ein einfaches UND-Gatter! Der zweite Eingang des UND-Gatters ist die Onehot-codierte Version des Auswahlsignals. Die Onehot-Codierung kann in einer Funktion erfolgen. Dies skaliert auf Bits jeder Größe und behält einen wartbaren/lesbaren Code bei.
Wartbarkeit. Ok stimmte zu. Aber das Ergebnis ist immer noch die gleiche Hardware. Das bedeutet nicht, dass meine Antwort falsch ist oder so, um eine Ablehnung zu erzielen.