Hallo zusammen,
Es ist ja möglich mit Generate-Anweisungen bestimmte Varianten
kompilieren zu lassen. Beispielsweise so:
code-Ausschnitt wird nur berücksichtigt wenn DEBUG = 1:
1
DEBUG_TEIL : if DEBUG = 1 generate
2
...
3
VHDL Beschreibung die genutzt wird für für den Fall DEBUG = 1
4
...
5
end generate DEBUG_TEIL;
Nun möchte ich für den Fall, dass ich eine Komponente simuliere,
automatisch eine Abwandlung des VHDL-Designs für die Simulation nutzen.
Für die eigentliche Synthese als Grundlage für die Implementation dann
aber eine andere Abwandlung. Also irgendwas in dieser Art:
1
SIMU_TEIL : if SIMULATION = 1 generate
2
...
3
VHDL Beschreibung die genutzt wird für für den Fall, dass simuliert wird.
4
...
5
end generate DEBUG_TEIL;
1
IMPL_TEIL : if IMPLEMENTATION = 1 generate
2
...
3
VHDL Beschreibung die genutzt wird für für den Fall, dass implementiert wird.
4
...
5
end generate DEBUG_TEIL;
Allerdings soll das automatisch gehen, so dass ich vor der Simulation
oder Implementation nichts händisch ändern muss.
Simulationstool (falls relevant): Model Sim
Viele Grüße,
Mike
Du kannst beim Aufruf von modelsim so etwas angeben wie
+define+SIMULATION, dann ist dieses Symbol definiert. Ich weiß nicht
mehr genau die Syntax ist, aber ich habe das mal benutzt vor längerer
Zeit, allerdings in Systemverilog. Für die Synthese wertest du dann aus,
ob das Symbol nicht definiert ist.
Ich habe gerade nochmal nachgeschaut. Das +define+SIMULATION habe ich
als Parameter für vlog angegeben, also den Compiler. Allerdings in einem
Script. Wie das in der GUI geht, kann ich nicht sagen.
Idealerweise wuerde ich fuer sowas VUnit nehmen um Generics fuer
verschiedene Testszenarien zu verwalten. Macht alles viel einfacher.
Du kannst Generics beim Aufruf von vsim mitgeben, welche dann in deiner
Testbench bis an dein HDL Modul weitergegeben werden. Der entsprechende
CLI Switch ist -g, siehe:
http://www.pldworld.com/_hdl/2/_ref/se_html/manual_html/c_vcmds191.html#11034046
Macht das denn Sinn, eine Simulation anders zu formulieren?
Soweit es meine Sachen angeht, braucht es doch nur Ersatzmodule für
PLLs, Transceiver, IOs, SERDES und alles, was irgendein wichtiges
Zeitverhalten hat. Die kann man doch leicht austauschen, d.h. im
Toplevel der Synthese andere Module verwenden, als in der für die
Simulation. Das schleift man einfach durch und entscheidet innen an der
Entity welche Module genutzt werden. So hat man immer nur ein Mapping
drin, statt riesen Blöcke an VHDL.
Jep, es gibt z.B. Faelle in denen du die Simulation beschleunigen
willst. Ein Beispiel ist die Init Routine eines Speichers oder der
Startup bis MGTs bereit sind.
In umfangreichen Projekten kannst du so z.B. nicht mehr nach jedem
Commit Regression Tests laufen lassen. Dann ueberlegst du dir das ganze
mehrstufig zu fahren, z.B. Tests die innerhalb weniger Minuten
durchlaufen so dass du eine "Commit early and often" Strategie fahren
kannst. In diesen Faellen geht es oft nicht anderst.
Viele IPs bringen einen solchen Sim Speedup Switch schon mit,
entsprechend angenehm ist die Handhabung. :-)
Andere Beispiele sind wenn du nicht synthetisierbaren Code zu
Debugzwecke hast, z.B. Ausgabe von Logfiles. Da kann so ein Switch einem
auch das Leben einfacher machen. :-)
Nick schrieb:> Macht das denn Sinn, eine Simulation anders zu formulieren?
Das Problem tritt immer dann auf, wenn ein IP-Core verwendet wird, der
nicht im RTL-Code vorliegt. Dann braucht man ein explizites
Simulationsmodell, das auch nur bei der Simulation eingebunden wird. Bei
der Synthese würde das einen Fehler verursachen (weil es gar nicht
synthetisierbar ist oder extrem ineffizient für die Implementierung
wäre).
Die Unterscheidung wird meistens in einem Wrapper getroffen. Als
Designer muss man nur den Wrapper einbinden, aber under the hood wird
dann jeweils das richtige Modul ausgewählt für Simulation und Synthese.
Das ist bei fast allen kommerziellen IPs so. PLDA z.B. würde dir sicher
nicht den RTL-Code seiner PCIe-Bridge zur Simulation bereitstellen,
sondern nur ein vereinfachtes Modell, das aber nicht synthetisierbar
ist.
Beim ASIC-Design liegen die meisten IPs ohnehin schon als Hardmacros für
die jeweilige Technologie vor, die sind dann nicht mehr simulierbar und
werden auch nicht mehr synthetitisiert, sondern erst bei der
Maskengenerierung in der FAB eingebaut. Da muss man entweder das
Simulationsmodell einbauen oder einen Platzhalter.
@Mike: Wenn du nur Komponenten umschalten musst, faehrst du allenfalls
mit einer `configuration` eleganter (und musst den Code nicht mit
generates verunstalten).
Also was in dem Stil:
1
configuration virtualjtag of tb_breakout is
2
use work.breakout_top;
3
4
for sim
5
for uut : breakout_top
6
use configuration work.vjtag;
7
end for;
8
end for;
9
10
end virtualjtag;
Fuer den jeweiligen Target tauschst du dann nur noch entsprechend die
configuration-VHDL-Files. Sollte Modelsim eigentlich auch koennen, ich
nutze hier GHDL.
Wahlweise geht auch das, was ja der Idee von ktorkelson entspricht:
1
constantsimulation_active:boolean:=false
2
-- pragma translate_off
3
ortrue
4
-- pragma translate_on
5
;
Eigentlich sind die VHDL-configurations dafür gedacht, aber irgendein
Tool kam damals, wo ich das gebraucht habe, nicht klar damit. ModelSim
war es nicht, das unterstützt configurations.
In einem CI-System würde ich die Parameter eher per Generics +
Kommandozeile mitgeben.
Duke
Vancouver schrieb:> Das Problem tritt immer dann auf, wenn ein IP-Core verwendet wird, der> nicht im RTL-Code vorliegt. Dann braucht man ein explizites> Simulationsmodell, das auch nur bei der Simulation eingebunden wird.
Ist mir alles klar, nur die Frage ist, WIE man das einbindet.
Wenn ich eine Simulation habe, instanziiere ich direkt nur die Modelle
(egal, woher sie kommen).
Ich denke, es geht wohl darum, wie man das in der Tiefe des Designs
macht. Ich habe bisher einfach einen std_logic mitgegeben, z.B.
"design_confing_vector (15 downto 0" der an alle entities geht und
durchgereicht wird. An den kann ich dann "unten" anschließen was ich
will. Als Beispiel bezieht ein Design unten drin bei der Simulation
seine Takte dann aus einem einfachen not-Konstrukt statt einer echten
PLL und das Ergebnis einer umfangreichen Berechnung wird als Ersatzwert
ausgegeben (mit Latenz) statt es alles zu berechnen.
Nick schrieb:> Wenn ich eine Simulation habe, instanziiere ich direkt nur die Modelle
Genau das soll automatisiert werden. Man möchste einfach keine zwei
Designs pflegen, eins für die Simulation und eins für Synthese. Das ist
bei größeren Projekten eine erhebliche Fehlerquelle. Überall dort, wo
Synthese- und Simulationsmodell verschieden sind, soll automatisch das
richtige Modell ausgewählt werden. Wenn du das manuell machst, kommst
irgendwann in Teufels Küche (ich war mehrmals dort...)
In deinem Fall würde man einen Wrapper für die Taktgenerierung bauen, in
dem entweder ein rückgekoppelter Inverter oder eine echte PLL
instanziiert wird. Das erspart dir den config-vector, du musst nichts
mehr "umklemmen" für die Synthese.
Vancouver schrieb:> Das erspart dir den config-vector,
Dann muss ich in einer anderen Weise definieren, welches der VHDL Module
eingebunden werden soll.
Den Vektor benutze ich auch für die Instanzierung unterschiedlicher
Versionen von VHDL-Modulen für verschiedene Versionen der Software (also
der synthetisierten Software).
Die Quelle dieses Vektors ist ein Version-Modul (ein VHDL) in dem ein
Versions-Code hinterlegt ist.
Dieser Versions-Code ist von der Software auslesbar. Damit lässt sich in
jedem Gerät eindeutig erkennen, welche Module an sind und welche Version
sie haben.
Man muss also nur im Versionsmodul einen Code ändern. Z.B. so:
VersionCode <= "001" & "101" & x"210402" & "0010" & "0101" & "0110";
Heisst: Version 1.5 - vom 2.APR.2021 mit den SW-Versionen 2,5,6 für die
SW-Teile, die austauschbare Versionen haben. Eine 1 vorne ist eine
Simulationsversion. Dazu gibt es Schalter für Debug-Versionen. Dann
kommen nur Module hinein, die zum Debuggen gebraucht werden.
Der Tipp kam so von einem Typen auf einem PLC2-Seminar.