Ist es möglich, STD_LOGIC_VECTOR-Bereichsbeschränkungen von unten nach oben anzuwenden?

Ich weiß, dass Einheiten uneingeschränkte Array-Typen (z. B. STD_LOGIC_VECTOR) in ihrer Portliste verwenden können, deren Größe automatisch an das in der Portkarte angeschlossene Signal angepasst wird, wenn sie instanziiert wird (und möglicherweise unterschiedliche Größen für jede Instanziierung). Innerhalb der Entität können Attribute wie 'LENGTHund 'HIGHverwendet werden, um den tatsächlich instanziierten Bereich zu ermitteln.

Ich habe ein solches Objekt, bei dem es sich um einen Parallel-> Seriell-Konverter handelt (akzeptiere Eingaben jeder Größe, breitere Eingaben erfordern mehr Taktzyklen zum Ausspucken).

Ist es möglich, die Bereichsinferenz umgekehrt funktionieren zu lassen, dh den in einer Unterkomponente angegebenen Bereich auf ein uneingeschränktes Signal in der übergeordneten Komponente anzuwenden und von dort an andere Komponenten weiterzugeben?

Weitere Details:

Meine Anwendung verfügt über eine Reihe von Datenquellen-Unterkomponenten, die Datenströme unterschiedlicher Breite erzeugen, eine Arbitrierungslogik zum Abtasten und Serialisieren dieser Quellen im Round-Robin-Modus sowie Parallel-> Seriell-Konverter, die die eigentliche Serialisierung und das Handshaking mit der Busarbitrierungslogik durchführen.

Im Moment habe ich die Signalbreiten als Konstanten in einem Paket angegeben, aber das bedeutet, dass ich jedes Mal, wenn sich ein Stream-Datenformat ändert, sowohl die Quell-Unterkomponente als auch das Paket ändern muss. Ich möchte wirklich, dass die Breite nur in der Quellkomponente angegeben wird, da sich die nachgelagerten Komponenten an jede Breite anpassen.

Antworten (1)

Verwenden Sie am besten Generika. Hier ist eine Beispiel-Entity-Deklaration für ein Schieberegister:

entity shift_register is
  generic (n_bits :integer := 8);
  port (clk  :std_logic;
        din  :std_logic_vector (n_bits-1 downto 0);
        dout :std_logic);
end entity shift_register;

Wenn Sie dieses Schieberegister instanziieren, gehen Sie folgendermaßen vor:

signal data :std_logic_vector (15 downto 0);
...
U0:  shift_register 
  generic map (n_bits => data'length)
  port map (clk, din, out);

In der Entität habe ich den Standardwert von n_bits auf 8 definiert. Wenn ich es instanziiere, hätte ich das generische Map-Zeug weglassen können und dann würde der Standardwert von n_bits verwendet werden.

EDIT: Um deine Frage besser zu beantworten. "Rückwärts" zu fahren funktioniert nicht so gut, und ich würde es wenn möglich vermeiden. Aber wenn es sein muss, dann können Sie immer einige Konstanten in Ihrem Paket deklarieren und sie weiter oben verwenden. Es ist nicht sehr sauber, aber es funktioniert.

Genau das habe ich jetzt eigentlich. Und ich muss mehrere Dateien bearbeiten, wenn sich die Datenbreite ändert. Denke da kommt man nicht drum herum. Möglicherweise kann ich die Dinge neu organisieren und die Instanziierung der parallel-> seriellen Unterkomponente in die Komponente verschieben, die die Breite kennt. Dann kann ich einfach eine serielle Schnittstelle mit fester Breite bis zur obersten Ebene weitergeben.
@Ben Voigt Wenn Sie es richtig gemacht haben, sollten Sie nicht mehrere Dateien bearbeiten müssen, wenn sich die Datenbreite ändert. Meine Regel für alles ist: Wenn Sie die Informationen mehr als einmal eingeben müssen, werden Sie sie mehr als einmal falsch eingeben. Ich habe viele FPGAs gemacht, bei denen ich nur einmal eine Information eingebe und der Rest des Codes es einfach herausfindet.
@David: Ich habe eine Komponente, die die Daten bereitstellt, so etwas wie parallel_out <= some_data & some_more_data & even_more_data;. Das steuert wirklich, wie breit der Ausgangsport sein muss, wenn ich yet_more_datazum Ausgang hinzufüge, muss der Array-Bereich zunehmen. Dann brauche ich eine Konstante in einer Paketdatei, damit alle Signale, die diese Daten weiterleiten, der Breite entsprechen, und die Notwendigkeit, diese synchron zu halten, versuche ich zu eliminieren.
@Ben Sie können mit den Generika und Konstanten rechnen. Setzen Sie diese Mathematik einfach in die Berechnung Ihrer SLV-Größen ein. So etwas wie "signal parallel_out :slv (some_data_bits+some_more_data_bits+even_more_bits-1 downto 0)". Denken Sie daran: einmal Info eingeben, alles andere berechnen.
@David: Also brauche ich jetzt drei Konstanten statt einer? Das ist keine Verbesserung. Und es gibt keinen Grund für eine andere FPGA-Komponente als die Datenquelle, die Größe der einzelnen Felder zu kennen. (Natürlich muss der Mikrocontroller, der den seriellen Stream empfängt, Bescheid wissen, aber ich erwarte nicht, dass er diese Informationen zwischen C und VHDL austauschen kann.)
@Ben Entweder verstehst du es nicht oder ich verstehe nicht, was du sagst. Und Sie können Dinge zwischen C und VHDL austauschen, wenn Sie entschlossen genug sind. Das tue ich. Ich habe sogar ein Programm geschrieben, das meine PCB-Netzliste liest und die VHDL- und UCF-Dateien an die PCB anpasst.
@David: Ein Datenstrom ist beispielsweise der Batteriestatus. Der I2C-Master fragt die Batterie ab, zieht die interessierenden Bits heraus und leitet sie an einen asynchronen Sender weiter, der Framing, CRC usw. übernimmt, damit sie von einem uC-UART-Peripheriegerät empfangen werden können. Wenn mein Chef darum bittet, ein paar zusätzliche Bits zu greifen, sollte ich nur die Logik ändern müssen, die die I2C-Transaktion verfolgt und Bits des Ausgangsports zwischenspeichert. Aber leider muss die übergeordnete Entität, die die Seite der Quelle (I2C) mit der Seite der Senke (UART) verbindet, auch die Breite der parallelen Daten kennen.
Es ist jedoch komplizierter, da eingehende Daten eine Prüfsumme haben (der Ausgangsport wird nur geändert, wenn die Prüfsumme übereinstimmt) und die ausgehenden Daten mit einer Reihe anderer Streams verschachtelt sind, die um denselben UART konkurrieren.