Forum: FPGA, VHDL & Co. XST und File I/O


von Daniel R. (dan066)


Lesenswert?

Ich hab in meiner architecture vor dem begin einige Funktionen 
definiert, die dazu dienen ein array mit Werten aus einer Textdatei zu 
initialisieren. Im Simulator läuft das einwandfrei, aber XST meckert 
wenn ich das 'length Attribut einer line (nach readline()) auslesen will 
und sagt mir "VHDL source expression not yet supported: 'DerefOp'.".
Wie kann ich festlegen, dass diese Funktion nicht als Komb. Logik 
synthetisiert werden soll sondern nur einmal vor der Synthese zur 
Berechnung der Initialwerte ausgeführt werden soll?

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


Lesenswert?

Daniel R. schrieb:
> Im Simulator läuft das einwandfrei
Man kann 100% (naja, fast) von VHDL simulieren. Aber bestenfalls 95% 
synthetisieren.
> aber XST meckert wenn ich das 'length Attribut einer line
> (nach readline()) auslesen will
Das File-Handling ist nicht primäre Aufgabe eines Synthesizers. Welche 
5% synthetisierbar sind, steht im Handbuch zum Synthesizer. In deinem 
Fall zum XST-Users Guide.

> ein array mit Werten aus einer Textdatei zu initialisieren.
Dafür gibt es andere Wege. Hier kocht jeder seine eigene Suppe. Ich habe 
ein externes C-Programm, das mir einen VHDL-Frame generiert, das Arrays 
mit Werten füllt und das Ande anhängt. Letztlich bekomme ich dan eine 
VHDL-Datei mit den gewünschten Werten.

Du kannst das Textfile auch parsen und als Initwerte für ein BRAM in die 
Bitstromerzeugung einfließen lassen.

von Duke Scarring (Gast)


Angehängte Dateien:

Lesenswert?

Lothar Miller schrieb:
> Das File-Handling ist nicht primäre Aufgabe eines Synthesizers.
Richtig. Obwohl da erstaunlich viel geht...

Daniel R. schrieb:
> einige Funktionen
> definiert, die dazu dienen ein array mit Werten aus einer Textdatei zu
> initialisieren.
Wie oft rufst Du denn Deine Funktion auf? Und an welcher Stelle?

> 'length Attribut
Laut UG627 sollte das funktionieren, offenbar aber nicht bei readline. 
Vielleicht findest Du einen Workaround?

> Wie kann ich festlegen, dass diese Funktion nicht als Komb. Logik
> synthetisiert werden soll sondern nur einmal vor der Synthese zur
> Berechnung der Initialwerte ausgeführt werden soll?

Hier ein Beispiel aus dem UG627:
1
...
2
architecture syn of rams_20c is
3
4
  type RamType is array(0 to 63) of bit_vector(31 downto 0);
5
6
  impure function InitRamFromFile (RamFileName : in string) return RamType is
7
    FILE RamFile : text is in RamFileName;
8
    variable RamFileLine : line;
9
    variable RAM : RamType;
10
  begin
11
    for I in RamTyperange loop
12
      readline (RamFile, RamFileLine);
13
      read (RamFileLine, RAM(I));
14
    end loop;
15
    return RAM;
16
  end function;
17
18
  signal RAM : RamType := InitRamFromFile("rams_20c.data");
19
20
begin
21
...

Duke

von Daniel R. (dan066)


Lesenswert?

Ok die Datei außerhalb zu parsen wäre auch möglich.
Ich hab das so gemacht:

Vor begin steht die Zuweisung
1
signal RAM : rom_type := rom_init("C:\Modelsim_Projects\file.txt");
Die rom_init() Funktion ist gleich darüber definiert und wird nirgendwo 
sonst aufgerufen.
Aus der Datei liest sie eine Zeile von unbekannter Länge.
Die Länge entnehme ich dann line_v'length
1
line_length_v := line_v'length; --hier Problem
und kopiere dann entsprechend viele Zeichen in den 20 Zeichen großen 
String Vector
1
read(line_v, str_line_v(1 to line_length_v));
Den String Vektor gehe ich dann in einer Schleife durch und wandel jedes 
Zeichen in einen std_logic_vector um.
Meckern tut XST beim Speichern der length in einer Variablen oben.

Der Unterschied zu dem Beispiel oben ist lediglich, dass die Zeilenlänge 
bei mir variabel sein soll (begrenzt auf maximal 20 Zeichen). Wenn ich 
die Zeilenlänge nicht angeb ist das ein Typkonflikt und erzeugt eine 
Warnung. Außerdem brauch ich die Länge um die Gesamtzahl der belegten 
Arrayfelder zu berechnen.

: Bearbeitet durch User
von Duke Scarring (Gast)


Lesenswert?

Daniel R. schrieb:
> Der Unterschied zu dem Beispiel oben ist lediglich, dass die Zeilenlänge
> bei mir variabel sein soll (begrenzt auf maximal 20 Zeichen).
Vielleicht hilft es die Datei zeichenweise zu lesen?

Duke

von Daniel R. (dan066)


Lesenswert?

Naja, aber ich seh da nur die Funktionen:
readline() zum holen der kompletten nächsten Zeile und
read() zum auslesen der Zeile in eine Variable der passenden Größe. 
Vielleicht geht es irgendwie, dass man eine Zeile zeichenweise ausliest 
bis man was ungültiges zurück kriegt, aber ich wüsste jetzt nicht mit 
welchen Funktionen das gehen würde.
Möglicherweise könnte man
1
procedure READ (L: inout LINE; VALUE: out CHARACTER;
2
                               GOOD: out BOOLEAN);
Immer wieder aufrufen bis GOOD = false ist (falls es da intern einen 
Iterator gibt der aufs nächste Zeichen springt).

: Bearbeitet durch User
von Duke Scarring (Gast)


Angehängte Dateien:

Lesenswert?

Daniel R. schrieb:
> Vielleicht geht es irgendwie, dass man eine Zeile zeichenweise ausliest
> bis man was ungültiges zurück kriegt

Im Anhang ist ein Stück Code, welches eine Textdatei einliest. Ich hab 
das jetzt nur im Simulator getestet, aber es sollte auch im Synthesizer 
funktionieren:
1
vcom test_vhdl_read.vhd
2
# Model Technology ModelSim SE-64 vcom 10.3d Compiler 2014.10 Oct  7 2014
3
# vcom -reportprogress 300 test_vhdl_read.vhd 
4
# -- Loading package STANDARD
5
# -- Loading package TEXTIO
6
# -- Loading package std_logic_1164
7
# -- Loading package NUMERIC_STD
8
# -- Compiling entity test_vhdl_read
9
# -- Compiling architecture test of test_vhdl_read
10
# Errors: 0, Warnings: 0
11
vsim -novopt test_vhdl_read
12
# vsim 
13
# 
14
# Loading std.standard
15
# Refreshing work.test_vhdl_read(test)
16
# Loading std.textio(body)
17
# Loading ieee.std_logic_1164(body)
18
# Loading ieee.numeric_std(body)
19
# Loading work.test_vhdl_read(test)
20
# ** Note: read 6 bytes from ram_data.txt
21
#    Time: 0 ps  Iteration: 0  Instance: /test_vhdl_read File: test_vhdl_read.vhd
22
# ** Note: read 3 lines from ram_data.txt
23
#    Time: 0 ps  Iteration: 0  Instance: /test_vhdl_read File: test_vhdl_read.vhd
24
run -all
25
# ** Note: 0 --> 65
26
# ** Note: 1 --> 66
27
# ** Note: 2 --> 66
28
# ** Note: 3 --> 67
29
# ** Note: 4 --> 67
30
# ** Note: 5 --> 67
31
# ** Note: 6 --> 0
32
# ** Note: 7 --> 0
33
# ** Note: 8 --> 0
34
# ** Note: 9 --> 0
35
# ** Note: 10 --> 0

Duke

von Daniel R. (dan066)


Lesenswert?

Vielen Dank für die ausführliche Antwort.
Im Simulator läuft meine Lösung auch, wenn ich die line so wie in deinem 
Beispiel zeichenweise einlese.
Aber im Synthesetool leider nicht!
Es lässt einfach nicht zu, dass die line-Attribute 'range oder 'length 
abgefragt werden.
Frage ich 'length ab sagt XST: "VHDL source expression not yet 
supported: 'DerefOp'."
Und frage ich 'range ab sagt XST: "Bad object specification in qualified 
expression."

Wie auch immer, wenn ich die Attribute nicht benutze sondern mir einenn 
End-Marker in jeder Zeile definier z.B. ';' dann läuft die Schleife zwar 
an aber nur für 64 Iterationen. Danach kommt die Meldung "Loop has 
iterated 64 times. Use "set -loop_iteration_limit XX" to iterate more."

Ich finde es unschön soeinen Parameter per Hand in die .xst Datei 
schreiben zu müssen. Außerdem soll die Funktion ja gar nicht 
synthetisiert werden. Kann man nicht irgendwie Sachen markieren, die 
nicht synthetisiert werden sollen?

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


Lesenswert?

Daniel R. schrieb:
> Es lässt einfach nicht zu, dass die line-Attribute 'range oder 'length
> abgefragt werden.
Eigentlich schon: im XST Users Guide zur Version 14 steht:
1
VHDL Specifications
2
• Supported for some predefined attributes only:
3
– HIGHLOW
4
– LEFT
5
– RIGHT
6
– RANGE
7
– REVERSE_RANGE
8
– LENGTH
9
– POS
10
– ASCENDING
11
– EVENT
12
– LAST_VALUE

> Es lässt einfach nicht zu, dass die line-Attribute 'range oder 'length
> abgefragt werden.
WIE frägst du die denn exakt ab? Im Beispiel von Duke kommt kein 'length 
vor...

> Und frage ich 'range ab sagt XST: "Bad object specification in qualified
> expression."
Zeig DEN Code, der diesen Fehler hervorruft. Ein 'range ist 
selbstverständlich synthetisierbar. Fast jede Konvertierungsfunktion 
verwendet das...
Die Funktion TO_01 in der numeric_std sieht z.B. so aus:
1
-- function TO_01 is used to convert vectors to the
2
--          correct form for exported functions,
3
--          and to report if there is an element which
4
--          is not in (0,1,h,l).
5
--    Assume the vector is normalized and non-null.
6
--    The function is duplicated for SIGNED and UNSIGNED types.
7
8
function TO_01(S : SIGNED ; xmap : STD_LOGIC:= '0') return SIGNED is
9
variable RESULT: SIGNED(S'length-1 downto 0);
10
variable bad_element : boolean := FALSE;
11
alias xs : SIGNED(s'length-1 downto 0) is S;
12
begin
13
  for i in RESULT'range loop                               --- 'RANGE
14
    case xs(i) is
15
      when '0' | 'L' => RESULT(i):='0';
16
      when '1' | 'H' => RESULT(i):='1';
17
      when others => bad_element := TRUE;
18
      end case;
19
    end loop;
20
  if bad_element then
21
    assert NO_WARNING
22
      report "numeric_std.TO_01: Array Element not in {0,1,H,L}"
23
      severity warning;
24
    for i in RESULT'range loop                             --- 'RANGE
25
      RESULT(i) := xmap;        -- standard fixup
26
      end loop;
27
    end if;
28
  return RESULT;
29
  end TO_01;
Und die Funktion ist tadellos synthetisierbar.

> Außerdem soll die Funktion ja gar nicht synthetisiert werden.
Warum ist sie dann da drin? Die sollte dann doch eher zur Testbench nach 
ausserhalb gehören....

: Bearbeitet durch Moderator
von Daniel R. (dan066)


Lesenswert?

Naja aber XST beschwert sich bei der Verwendung von 'range einer line
1
variable line_v : line;
2
begin
1
readline (rom_file, line_v);
2
for j in line_v'range loop --Zeile 132
Und ich krieg die Meldung:
"... line 132: Bad object specification in qualified expression.
INTERNAL_ERROR:Xst:cmain.c:3464:1.56 -  Process will terminate. For 
technical support on this issue, please open a WebCase with this project 
attached at http://www.xilinx.com/support.";

Ich umgehe das Problem dann gezwungenermaßen mit einem Trennzeichen am 
Ende um die Abfrage zu vermeiden.

von Daniel R. (dan066)


Lesenswert?

Oh man,
XST sagt zu meinen Initialisierungsschleifen
"Loop body will iterate zero times"
und
"Index value(s) does not match array range, simulation mismatch."
Dabei stimmt das gar nicht.

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


Lesenswert?

Daniel R. schrieb:
> XST beschwert sich bei der Verwendung von 'range einer linevariable
> readline (rom_file, line_v);
> for j in line_v'range loop --Zeile 132
Nein. Der Synthesizer kann einfach nur nichts mit dynamischen Grenzen 
bei einer for-Schleife anfangen. Das braucht er im restlichen Leben auch 
nie...

Daniel R. schrieb:
> "Loop body will iterate zero times"
Gleicher Fall: der Synthesizer kann nichts mit variablen Grenzen bei 
einer for-Schleife anfangen...

Das steht aber ganz klar&deutlich im bereits des öfteren erwähnten XST 
Users Guide:
1
VHDL For-Loop Statements
2
XST supports VHDL for-loop statements for:
3
• Constant bounds
4
...
Wie Lothar Miller schrieb:
>>>> Welche 5% synthetisierbar sind, steht im Handbuch zum Synthesizer. In
>>>> deinem Fall im XST Users Guide.

: Bearbeitet durch Moderator
von Daniel R. (dan066)


Lesenswert?

Ok, aber selbst wenn ich die dynamischen durch feste Grenzen ersetze 
kommt es zur selben Meldung.
1
for i in 0 to 50 loop
2
  for j in 0 to 50 loop
3
    if count_v < x and ... then
4
      count_v := count_v + 1;
5
    end if;
6
  end loop;
7
end loop;
Außerdem beißt er sich ziemlich lange daran fest.

: Bearbeitet durch User
von Daniel R. (dan066)


Lesenswert?

Durch die Ausgabe auf dem Display habe ich festgestellt, dass XST 
anscheinend irgendwelche Fehler bei der Verwendung der TextIO Methoden 
macht. Im Simulator enthält mein array alle Werte, wie gewünscht. Bei 
XST nicht (da sind die verschoben und unvollständig).
Der Übersichtlichkeit halber tendiere ich nun zum erstgenannten 
Vorschlag, nämlich in C++ einen Textfile-Parser zu schreiben, der eine 
vhdl Datei ausspuckt, die das fertige Array bzw. spezifischen 
Adressdekoder enthält.

: Bearbeitet durch User
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.