Hallo, nachdem ich mich bisher immer nur mit synthetisierbarem VHDL beschäftigt habe, darf ich mich in den nächsten Wochen/Monaten mit dem Titel "Verification Engineer" schmücken und bekomme jetzt also eine andere Sicht auf VHDL als ich bisher hatte. Ich habe schon ein Testbench Konzept in dem auch so unsynthetisierbare Dinge wie File I/O, dynamische Speicherverwaltung und eine Linked List drin sind. Ich denke aber, dass da noch einiges zu holen ist, insbesondere in Bezug auf Simulationsgeschwindigkeit und Speicherverbauch (zb Prozesse nicht unnötig abarbeiten, etc ...). Hat da jemand Tipps oder vielleicht Links zu guten Artikeln, die sich auch damit beschäftigen, wie der Simulator (in unserem Fall Modelsim) bestimmte Konstrukte abarbeitet? Eine Frage die mich zb beschäft ist: Ich lese eine Datei ein in der viele 4-bit Werte in ASCII Zeichen kodiert sind. Wie speichere ich diese Daten am besten in einer internen Datenstruktur sodass der Simulator zb jeweils 8 4-bit Werte in eine Integer variable packt? Eine andere Frage ist: Die klassische Form if reset = '1' then ... elsif rising_edge(clk) then ... end if; ist ja bekannt. Ist das die beste Form für die Simulation oder sind da andere Konstrukte besser geeignet? Ich freue mich über alle Antworten. Matthias
Gut, sonderlich eingeschlagen hat der Thread ja bisher nicht aber jetzt habe ich etwas hoffentlich halbwegs spannendes zu bieten: Mein aktuelles Problem ist, dass ich irgendwie sicherstellen muss, dass die Messages im Logfile immer in derselben Reihenfolge geschrieben werden. Das dürfte nicht trivial sein in VHDL, die Reihenfolge des Scheduling der aktiven Prozesse ist nicht fixiert. Noch dazu hängt diese Reihenfolge an Delta Delays, ich sehe es schon vor mir, wie ich in irgendeiner Datei eine Zuweisung ändere (zb aus einem Prozess herausziehe) und auf einmal dreht sich bei einer ganz anderen Komponente die Scheduling Order um. Auch innerhalb einer Komponente soll die Message Order nicht umgedreht werden. Folgende Lösung kommt mir bisher am besten vor: Jede Entity, die Log Messages schreiben kann, hat ihre eigene Message Liste und schreibt in diese ihre Messages hinein. Ein eigener PRozess der auf einer Clock eine ps hinter den eigentlich clocks läuft, liest dann in einer fixen Reihenfolge diese Listen aus und schreibt die Messages. Damit habe ich eine fixe Reihenfolge wenigstens unter den Entities ohne an der Abarbeitung der Prozesse durch den Simulator etwas zu drehen. Jetzt stellt sich aber immer noch das Problem der Reihenfolge innerhalb einer Entity, aber das kann ich vielleicht machen indem ich für jede Entity nur einen Prozess implementiere, der Log Messages schreibt.
Ist darum hier so wenig los? Ist ja furchtbar heute, hier im Stockwerk sind alle auf Zeitausgleich, man hört nur Tastaturen klappern und langsam mache ich mir Sorgen, dass ich an Reizarmut eingehe :D ... schöne Ostern jedenfalls allen.
Komm zur fränkischen Siemens ins Grossraumbüro, da hast Du garantiert keine Reizarmut!
Weiß vielleicht wer, wie man eine constant auf eine variable casten kann, wenn man zb an eine procedure übergibt? Man kann die constant problemlos einer variable zuweisen und diese dann übergeben, aber das muss doch auch irgendwie direkt gehen. Noch eine Frage: Jetzt weiß ich schon, wie ich einen access type dereferenziere. Aber ich finde den umgekehrten Weg nicht, wie ich zu einem statisch angelegten Objekt einen access handle bekomme. Weiß das vielleicht wer?
Ok, das mit dem casten ist nicht sinnvoll, anscheinend einfach alle in-Parameter für eine procedure als constant deklarieren, dann kann beim Call auch ein anderer Typ eingesetzt werden. Die zweite Frage ist noch offen.
Kannst Du bitte mal ein Beispiel posten, damit man versteht, worüber Du genau sprichst?
Sorry, habe den Beitrag erst jetzt gesehen. Ein Beispiel was mich beschäftigt: Ich habe zb so eine Datenstruktur: --- type Message_record; type Message_record_ptr is access Message_record; type Message_record is record Message : line; TimeStamp : time; Message_class : string(1 to 2); Message_code : string(1 to 2); Message_level : integer range 0 to 3; Next_Message : Message_record_ptr; end record Message_record; --- Diese soll Messages in einer Linked List halten. Um so eine Struktur anzulegen muss ich folgendes aufrufen: --- new_msg_ptr := new Message_record'(new string'("CSM is in idle state"), now, MCLASS_CS_INFO, MCODE_CSM_INFO, 0, null); --- Dabei ist "CSM is in idle state" ein string, damit ich daraus eine Line machen kann, muss ich einen line-Konstruktor mit dem string aufrufen. Nach meinem Verständnis liegt der String jetzt also zwei mal bei mir im Speicher. Wenn ich von dem bestehenden string die Adresse bekommen könnte, müsste ich eine line haben. Aber ich finde nichts, wie ich in VHDL die Adresse von einem bestehenden Objekt bekomme.
Ein anderes meiner Probleme/Fragen hängt mit dem Verhalten von read aus std.textio zusammen: Soweit ich es sehe, ist das read konsumierend. Dadurch entsteht für mich folgendes Problem: Die Kommandos an die Testbench werden am Anfang geparst und in eine Linked List gelegt. Aus dieser holt sich dann die eigentlich State Machine die Kommandos der Reihe nach und exekutiert sie. Ich habe im Moment eine Loop-Anweisung vorgesehen. Die State Machine soll sich, wenn sie das Loop Start Kommando findet, einen access zu diesem Kommando merken und bei der Instruktion Loop End wieder zu diesem zurückspringen, solange bis ein Loop Counter auf 0 ist. Die Folge ist, dass es beim zweiten Abarbeiten der Kommandos zu Lesefehlern kommt. Anscheinend verändere ich den line-Zeiger dadurch, dass ich ein read darauf aufrufe. Gibt es Standardfunktionen, die nicht konsumierend lesen oder müsste ich mir so etwas, wenn ich die Loops wirklich brauche, selber implementieren?
Wieso solltest Du zweimal den String im Speicher haben? Der Typ line ist ein access auf einen String. Somit sollte der Konstruktor einen Pointer auf dieses Objekt liefern. Also sollte es diesen String nur einmal geben. Mal davon abgesehen das es eh ein anonymes Objekt ist. Oder vielleicht versteh ich auch Dein Problem falsch. Es gibt im Standard keine read-Funktion die nicht konsumierend ist.
>holt sich dann die eigentlich State Machine die Kommandos der >Reihe nach und exekutiert sie Die armen Kommandos - warum werden die hingerichtet?
@Mathi: Ich denke schon, dass ich diesen String dann zweimal im Speicher habe. Ich habe folgenden Code ausprobiert (nur auszugsweise, da ich ihn in den Parser-Prozess in meinem design geschrieben habe): --- variable tmpline1 : line := new string'("if you can read this string it was not deallocated"); variable tmpline2 : line; begin -- process parse_tcs_file tmpline2 := new string'(tmpline1.all); deallocate(tmpline1); report tmpline2.all severity note; --- Wenn ich das dann laufen lasse kommt auch wirklich dieser String heraus: # ** Note: if you can read this string it was not deallocated Wenn ich vor dem report noch deallocate(tmpline2) aufrufe bekomme ich bei report dann, wie gedacht, ein SIGSEV geliefert. Mein Eindruck ist also, dass entweder der String wirklich im Speicher dupliziert wird oder aber ein reference counting implementiert ist und danach schauen mir die Ergebnisse meiner Google-Suche bisher nicht aus.
Aber Du erzeugst in dem Beipiel ja ein neues String-Objekt in tmpline2 mit dem Wert von tmpline1. Wenn ich das so richtig sehe. Dann ist das Verhalten richtig. Ich muss aber auch erst nochmal mein VHDL-Buch zu rate ziehen.
Ich habe ja nicht gesagt, dass das Verhalten falsch ist. Aber für mich existiert jetzt in beiden Fällen der String zweimal im Speicher. Das würde ich gerne vermeiden. Andere Frage: Hat jemand eine Ahnung wie man an eine VHDL language reference kommt, ohne dafür 126 dollar zu löhnen? Bei mir stapeln sich die Fragen und im Netz finde ich keine guten Antworten darauf.
Noch ein Codeausschnitt aus dem Modelsim Manual, der den Unterschied zwischen Pointer und Objekte duplizieren veranschaulicht:
1 | -- Bad VHDL (because L1 and L2 both point to the same buffer):
|
2 | READLINE (infile, L1); -- Read and allocate buffer |
3 | L2 := L1; -- Copy pointers |
4 | WRITELINE (outfile, L1); -- Deallocate buffer |
5 | |
6 | -- Good VHDL (because L1 and L2 point to different buffers):
|
7 | READLINE (infile, L1); -- Read and allocate buffer |
8 | L2 := new string’(L1.all); -- Copy contents |
9 | WRITELINE (outfile, L1); -- Deallocate buffer |
Das kannst Du aber nur vermeiden, wenn Du es auch korrekt machst. Wenn Du ein neues Objekt mit dem Wert eines anderen erzeugst und dafür scheinbar einen Copy-Konstruktor verwendest, dann ist wirst Du auch einen zweiten String im Speicher bekommen.
Es gibt in VHDL keine Lösung für dein Problem. 1) Man kann keine Pointer auf existierende Objekte anlegen. 2) Du kannst das Konsumieren nicht vermeiden. Es ist wie in Deinem Beispiel mit dem guten und schlechtem VHDL Stil. Wenn Du willst dass Du den String öfter kannst, musst Du ihn vorher kopieren. Man kann in VHDL nicht wie in C einen Pointer auf des String setzen und diesen dann beliebig verschieben.
Das habe ich schon befürchtet. Danke jedenfalls. Wenn es sich von Aufwand und Gewinn her dafür steht kann ich ja noch meine eigenen nicht-konsumierenden read-procedures schreiben. Ist jedenfalls eine gute VHDL-Übung.
Bevor ich meine Unfähigkeit der Sprache VHDL anlaste, was ist denn die Funktion, die man benutzen soll, wenn man einen std_logic_vector zu einem String konvertieren will? Und warum quälen sie einen so mit unterschiedlichen textio packages, ich hab std.textio und ieee.std_logic_textio aber mit beiden bringe ich es nicht zusammen, einen std_logic_vector in einem String unterzubringen. Manchmal frage ich mich, ob die Standardisierungsgremien das Thema VHDL und Textausgabe nur im besoffenen Zustand besprochen haben. Wenn man Fehlermeldungen bekommt wie "Conversion to string can not have string literal operand" fühlt man sich ein wenig sehr auf den Arm genommen.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.