Forum: FPGA, VHDL & Co. Range Expression Problem


von Max (Gast)


Lesenswert?

Hallo Leute

ich habe folgedes Problem. Bei diesem Code
1
  generic(
2
    DATA_WIDTH : natural := 32
3
    );
4
  port (
5
6
...
7
8
  type tdata_t is array (0 to 3) of std_ulogic_vector(DATA_WIDTH-1 downto 0);
9
  type pos_t is array (0 to 3) of integer range 0 to DATA_WIDTH-8;
10
  signal pos              : pos_t;
11
  signal data_array       : tdata_t;
12
...
13
14
data_array(3)(pos(2)+7 downto 0) <= data_array(2)(pos(2)-1 downto 0) & "10101010";

meldet der Synthesizer:
range expression could not be resolved to a constant

Was ist denn hier genau das Problem? Simulieren kann ich das.

Dachte das es vielleicht an dem dynamischen pos signal liegt.
Aber folgende Zeile geht auch:
1
data_array(3)(pos(2)+7 downto 0) <= data_array(2)(pos(2)+7 downto 0);

Ich brauche aber unbedingt diese Lösung.
Soweit ich das sehe kann es ja nicht sein das ich über die vektor 
grenzen komme.
Könnt ihr mir sagen wie ich das sonst lösen kann?

Danke

Gruß

Max

von VHDL hotline (Gast)


Lesenswert?

Welche Toolchain?

Falls Vivado:

https://www.xilinx.com/support/answers/52302.html

von Max (Gast)


Lesenswert?

Hi,

danke für die Antwort.
Ich benutze Vivado 2019.1
So richtig klar ist es für mich leider nicht warum die untere Zeile 
supported wird und die obere nicht :(

Gruß

Max

von VHDL hotline (Gast)


Lesenswert?

Max schrieb:
> So richtig klar ist es für mich leider nicht warum die untere Zeile
> supported wird und die obere nicht :(

In der zweiten Zuweisung scheint das Tool zu erkennen, dass linke und 
rechte Anweisung einen gleich breiten Vektor haben. In der ersten 
Zuweisung kriegt das Tool das nicht mit.

Außerdem:
Max schrieb:
> pos(2)-1

Was macht das Tool, wenn pos(2) hier 0 ist?


So wie ich das verstehe, willst du einen variabel langen Teil eines 
Vektors auswählen und zuweisen. In Hardware heißt eine Bitauswahl meist, 
dass es mit einem Multiplexer beschrieben werden kann. Ein Multiplexer 
kann mit switch/case oder if/else beschrieben werden (oder mit der 
anscheinend nicht unterstützten dynamic expression wie du es versucht 
hast). switch/case ist bei einer variablen DATA_WIDTH nicht gut machbar. 
Eine Möglichkeit wäre eine ausnahmsweise mal erlaubte for loop mit einem 
if
1
-- folgendes ist nur ein Beispiel, welches NICHT deiner Logik oben entspricht
2
for i in 8 to DATA_WIDTH loop
3
  if (i < pos(2)) then       
4
    data_array(3)(i+7) <= data_array(2)(i-1);
5
  end if;
6
end loop;
7
data_array(3)(7 downto 0) <= "10101010";

Allerdings wird das schon ein ziemliches Mux-Monster, egal mit welcher 
Beschreibung. Möglicherweise gibt es eine effizienteren Ansatz das 
Gesamtproblem zu lösen, das kann man aber aus deinem Codeschnipsel nicht 
erkennen.

von VHDL hotline (Gast)


Lesenswert?

>> So richtig klar ist es für mich leider nicht warum die untere Zeile
>> supported wird und die obere nicht :(
>
> In der zweiten Zuweisung scheint das Tool zu erkennen, dass linke und
> rechte Anweisung einen gleich breiten Vektor haben. In der ersten
> Zuweisung kriegt das Tool das nicht mit.

Wenn die zweite Anweisung vom Tool verstanden wird, kannst du es 
natürlich auch mal mit einem Aufsplitten deiner ersten Anweisung 
versuchen.
1
data_array(3)(pos(2)+7 downto 8) <= data_array(2)(pos(2)-1 downto 0);
2
data_array(3)(7 downto 0) <= "10101010";

Allerdings bleibt hier immer noch das Problem, dass pos(2) für "0" nicht 
geht ( (7 downto 8) <= (-1 downto 0) ).

von Max (Gast)


Lesenswert?

VHDL hotline schrieb im Beitrag #6397105:
>>> So richtig klar ist es für mich leider nicht warum die untere
> Zeile
>>> supported wird und die obere nicht :(
>>
>> In der zweiten Zuweisung scheint das Tool zu erkennen, dass linke und
>> rechte Anweisung einen gleich breiten Vektor haben. In der ersten
>> Zuweisung kriegt das Tool das nicht mit.
>
> Wenn die zweite Anweisung vom Tool verstanden wird, kannst du es
> natürlich auch mal mit einem Aufsplitten deiner ersten Anweisung
> versuchen.
> data_array(3)(pos(2)+7 downto 8) <= data_array(2)(pos(2)-1 downto 0);
> data_array(3)(7 downto 0) <= "10101010";
>
> Allerdings bleibt hier immer noch das Problem, dass pos(2) für "0" nicht
> geht ( (7 downto 8) <= (-1 downto 0) ).

Danke für die Hilfe.
Dieser Ansatz scheint zu funktionieren.
Ich habe aber den Code jetzt ein wenig umgeschrieben:
1
data_array(3)(pos(2)+7 downto pos(2)) <= data_array(2)(31 downto 24);
2
data_array(3)(pos(2)-1 downto 0)      <= data_array(2)(pos(2)-1 downto 0);
Und das wird tatsächlich synthetisiert obwohl das Problem mit dem pos(2) 
= 0 noch besteht.
Kann es dann zu einem Laufzeitfehler kommen?

Ich habe das ganze jetzt mit einer if abgesichert:
1
data_array(3)(pos(2)+7 downto pos(2)) <= data_array(2)(31 downto 24);
2
  if(pos(2) /= 0)) then
3
         data_array(3)(pos(2)-1 downto 0) <= data_array(2)(pos(2)-1 downto 0);
4
  end if;


Gruß

Max

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Max schrieb:
> Und das wird tatsächlich synthetisiert obwohl das Problem mit dem pos(2)
> = 0 noch besteht. Kann es dann zu einem Laufzeitfehler kommen?
Nein, es kommt halt je nachdem, wie der MUX implementiert wurde, 
irgendein Blödsinn raus.

> Ich habe das ganze jetzt mit einer if abgesichert
Wenn das jetzt in einem kombinatorischen Prozess steht, hast du ein 
Latch an der Backe.

> Ich habe das ganze jetzt mit einer if abgesichert
Kurios. Wenn du in diesem Fall einfach nichts machst, dann ist doch 
irgendwie der ganze Multiplexer nicht so wichtig.

BTW: irgendwie erinnert mich das Ganze an die Sache, die Peter da im 
Beitrag "Re: Timing Optimierung bei einem Schieberegister" 
bearbeitet. Ist das das selbe Problem?

von Max (Gast)


Lesenswert?

Lothar M. schrieb:
> Max schrieb:
>> Und das wird tatsächlich synthetisiert obwohl das Problem mit dem pos(2)
>> = 0 noch besteht. Kann es dann zu einem Laufzeitfehler kommen?
> Nein, es kommt halt je nachdem, wie der MUX implementiert wurde,
> irgendein Blödsinn raus.

Wenn ich es simuliere und ich sehe das gewünschte Verhalten. Dann 
erwarte ich auch, dass nach der erfolgreichen Synthese dasselbe 
Verhalten auf dem Chip passiert. Oder etwa nicht?

>> Ich habe das ganze jetzt mit einer if abgesichert
> Wenn das jetzt in einem kombinatorischen Prozess steht, hast du ein
> Latch an der Backe.

Das war nur ein ausschnitt vom Prozess. Hier der ganze Prozess:
1
  end_stage process(aclk)
2
  begin
3
    if rising_edge(aclk) then
4
      valid_bytes_array(3) <= valid_bytes_array(2);
5
      data_array(3) <= (others => '0');
6
      pos(3) <= pos(2);
7
      if(valid_bytes_array(2)(3) = '1') then  
8
        data_array(3)(pos(2)+7 downto pos(2)) <= data_array(2)(31 downto 24);
9
        data_array(3)(pos(2)-1 downto 0) <= data_array(2)(pos(2)-1 downto 0);
10
        pos(3) <= pos(1)+7;
11
      else
12
        data_array(3)(pos(2)-1 downto 0) <= data_array(2)(pos(2)-1 downto 0);
13
      end if;
14
    end if;
15
  end process;

> BTW: irgendwie erinnert mich das Ganze an die Sache, die Peter da im
> Beitrag "Re: Timing Optimierung bei einem Schieberegister"
> bearbeitet. Ist das das selbe Problem?

Das gibts doch nicht? Wie bist du darauf gekommen? Ich bin der "Peter" 
;)
Ich sehe da überhaupt keine Ähnlichkeit zu dem Schiebergister vom 
anderen Post oO....Das ist jetzt echt unheimlich.
Das ist jetzt ein neuer Ansatz das Problem zu lösen :D
Statt das Ganze in einer Periode mit einer Loop zu shiften versuche ich 
jetzt ich es jetzt sequentiell von Periode zu Periode zu shiften. Mit 
Piplining. Schauen wir mal was dabei rauskommt^^

Gruß

Max (Peter)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Max schrieb:
> Wenn ich es simuliere und ich sehe das gewünschte Verhalten. Dann
> erwarte ich auch, dass nach der erfolgreichen Synthese dasselbe
> Verhalten auf dem Chip passiert. Oder etwa nicht?
Ich kann dir eine Schaltung beschreiben, die läuft in der Simulation 
tagelang tadellos. In der Realität versagt sie spätestens nach ein paar 
Sekunden... ;-)
Aber wie ich den Code ansehe dürfte das hier nicht passieren.

> Ich sehe da überhaupt keine Ähnlichkeit zu dem Schiebergister vom
> anderen Post oO....
Ja doch. Weil eben das damalige "Schieberegister" auch schon keines war, 
sondern ein Monstermultiplexer ;-)

> Das gibts doch nicht? Wie bist du darauf gekommen?
Soooo arg viel Traffic ist hier im FPGA-Forum nun doch nicht. Und oft 
kommen dann ganze Semesterschwärme an, die das selbe Problem zu lösen 
haben.

> Mit Piplining. Schauen wir mal was dabei rauskommt^^
So wie ich das sehe, "rückst" du die Daten jetzt Schritt für Schritt 
nach. Durch den variablen Index hast du aber wieder recht komplexe 
Multiplexer. Bin gespannt, ob das Timing hinkommt. Auf jeden Fall würde 
ich da dann eine STA machen und den kritischen Pfad ansehen.

von Max (Gast)


Lesenswert?

Lothar M. schrieb:
> Max schrieb:
>> Wenn ich es simuliere und ich sehe das gewünschte Verhalten. Dann
>> erwarte ich auch, dass nach der erfolgreichen Synthese dasselbe
>> Verhalten auf dem Chip passiert. Oder etwa nicht?
> Ich kann dir eine Schaltung beschreiben, die läuft in der Simulation
> tagelang tadellos. In der Realität versagt sie spätestens nach ein paar
> Sekunden... ;-)
> Aber wie ich den Code ansehe dürfte das hier nicht passieren.

Soviel Erfahrung habe ich dafür noch nicht :)
Da fällt mir spontan höchstens ein Metastabilitätsproblem ein

>> Ich sehe da überhaupt keine Ähnlichkeit zu dem Schiebergister vom
>> anderen Post oO....
> Ja doch. Weil eben das damalige "Schieberegister" auch schon keines war,
> sondern ein Monstermultiplexer ;-)

Ja diese "In-Hardware" Denkweise geht mir leider noch etwas ab :-/

>> Mit Piplining. Schauen wir mal was dabei rauskommt^^
> So wie ich das sehe, "rückst" du die Daten jetzt Schritt für Schritt
> nach. Durch den variablen Index hast du aber wieder recht komplexe
> Multiplexer. Bin gespannt, ob das Timing hinkommt. Auf jeden Fall würde
> ich da dann eine STA machen und den kritischen Pfad ansehen.

Mir ist leider kein anderer Ansatz eingefallen.
Ich lass es euch wissen ob es klapt ;)

Gruß

Max

von Weltbester FPGA-Pongo (Gast)


Lesenswert?

Ist eigentlich schon jemandem aufgefallen, dass dieser Konstrukt:
>data_array(3)(pos(2)+7 downto 0) <= data_array(2)(pos(2)-1

...gar nicht eindeutig darstellbar ist?

Der Synthesizer müsste ALLE möglichen Kombinationen von pos und den 
jeweiligen  Bits abwärts realisieren und dann mit einem ena einen davon 
auswählen.

Ich habe so eine Ahnung was das werden soll und bin sehr sicher, dass 
man das mit einem dynamischen shift zur Laufzeit ohne diesen MUX-Wald 
lösen kann. Hier wurde einmal mehr probiert, einen klassischen 
Softwarekonstrukt, den man so in C bauen würde, ins VHDL reinzuhacken, 
ohne aber zu kapieren, dass hier eine HW rauskommt, die parallel 
aufgebaut wird und dann folglich nur einer von N Pfaden aktiv ist. Kein 
Mensch baut sowas.

Das ist ein klassischer Fall, es sequentiell zu belassen, um Platz zu 
sparen. Der MUX-Wald wird nämlich schneckenlangsam, wenn er für ein 
großes Array aufbaut werden muss und geht dann sehr schnell über mehr, 
als nur 2 Takte, die es im anderen Fall kosten würde. Diese Array laufen 
nämlich über BRAMS und es ist in allen solchen Fällen immer 
zweckmässiger die RAM-Adressen, die letztlich rauskommen explizit 
berechnen zu lassen, damit dann interne MUX im BRAM arbeiten. So kommt 
hier eine MUX-Struktur raus, die viel fabric logic verbrät, teuer, 
langsam und aufwändig ist.

von Max (Gast)


Lesenswert?

Weltbester FPGA-Pongo schrieb im Beitrag #6397832:
> Ist eigentlich schon jemandem aufgefallen, dass dieser Konstrukt:
>>data_array(3)(pos(2)+7 downto 0) <= data_array(2)(pos(2)-1
>
> ...gar nicht eindeutig darstellbar ist?
>
> Der Synthesizer müsste ALLE möglichen Kombinationen von pos und den
> jeweiligen  Bits abwärts realisieren und dann mit einem ena einen davon
> auswählen.
>
> Ich habe so eine Ahnung was das werden soll und bin sehr sicher, dass
> man das mit einem dynamischen shift zur Laufzeit ohne diesen MUX-Wald
> lösen kann. Hier wurde einmal mehr probiert, einen klassischen
> Softwarekonstrukt, den man so in C bauen würde, ins VHDL reinzuhacken,
> ohne aber zu kapieren, dass hier eine HW rauskommt, die parallel
> aufgebaut wird und dann folglich nur einer von N Pfaden aktiv ist. Kein
> Mensch baut sowas.
>
> Das ist ein klassischer Fall, es sequentiell zu belassen, um Platz zu
> sparen. Der MUX-Wald wird nämlich schneckenlangsam, wenn er für ein
> großes Array aufbaut werden muss und geht dann sehr schnell über mehr,
> als nur 2 Takte, die es im anderen Fall kosten würde. Diese Array laufen
> nämlich über BRAMS und es ist in allen solchen Fällen immer
> zweckmässiger die RAM-Adressen, die letztlich rauskommen explizit
> berechnen zu lassen, damit dann interne MUX im BRAM arbeiten. So kommt
> hier eine MUX-Struktur raus, die viel fabric logic verbrät, teuer,
> langsam und aufwändig ist.

Hi,
das befürchte ich auch, dass das ganze viele Recoursen verbrauchen wird. 
Nur leider fällt mir momentan keine andere Lösung ein.
Und ja es wird viel mehr als nur 2 takte kosten.
Ich wäre dankbar für Tipps wie man das besser lösen kann.
Hast du vielleicht ein Beispiel wie man sowas mit einem dynamischen 
shift lösen kann?
Danke

von Malte (Gast)


Lesenswert?

Wie wäre es hiermit (ungetestet):
1
data_array(3)(7 downto 0) <= x"AA";
2
for i in 31 downto 8 loop
3
  if (pos(2) >= i-7) then
4
    data_array(3)(i) <= data_array(2)(i-8);
5
  end if;
6
end loop;

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
Noch kein Account? Hier anmelden.