Hallo,
ich bin gerade dabei ein 4-Bit CPU in LOAD-STORE Akkumulator Architektur
zu implementieren. Es ist mein erster Versuch, mehrere VHDL Komponenten
miteinander zu verschalten.
Die Komponenten selbst sind:
- Kontrolleinheit (mit PC)
- Adressierungseinheit mit einem Adressregister
- Speicher (Xilinx IP Core)
- ALU
Dadurch ergeben sich folgende Pfade:
Control <-> Adress <-> Memory
Control <-> ALU
ALU <-> Adress
(Vielleicht wichtig zu erwähnen: die Datenbusse von der Adresseinheit
zur Control und Adresseinheit zur ALU sind dieselben, quasi verzweigt)
Nun zu meinem eigentlichen Problem:
Wenn ich nun an der Kontrolleinheit eine Adresse zum Auslesen der
nächsten Instruktion/Datum anlege, so liegt die ausgelesene
Instruktion/Datum an der Kontrolleinheit und an der ALU einen halben
Takt später an (nur Verhaltens-Simulation).
Zur Kompensation hört die ALU auf die fallende Taktflanke des Clks, die
Kontrolleinheit auf die steigende. Auf die weise funktioniert das
Speichern von Daten in den Akkumulator gut. Ist das bisher schon falsch
gelöst oder noch ok?
Das eigentliche Problem besteht nun darin, Daten vom Akkumulator in den
Speicher zu schreiben. Der Akkumulator besitzt 8-Bit, der Bus zur
Adresseinheit nur 4. Die Steuereinheit muss also über ein Steuersignal
das hochwertige/niederwertige Nibble des Akkus multiplexen. Da das
Steuersignal also 2 Takte anliegt, die ALU aber auf die fallenden Flanke
des Clks hört, liegt das Chip Enable Signal für die Speichereinheit
(Dauer: auch 2 Takte) einen halben Takt zu kurz an ...
Ich gehe mal davon aus, dass meine Lösung in irgendeiner Weise falsch
ist. Deshalb meine Frage: wie synchronisiere ich mehrere Komponenten
korrekt? :)
Vielen Dank für eure Überlegungen,
F.
P.S: Ich habe keinen Code gepostet, da alle Komponenten zusammen etwas
zuviel ist ...
> liegt die ausgelesene Instruktion/Datum an der Kontrolleinheit> und an der ALU einen halben Takt später an (nur Verhaltens-Simulation).
Wie das? Woher kommt hier die Verzögerungs-Zeit?
Oder ist da eine Komponente, die auch schon auf den fallenden Takt
reagiert?
> Zur Kompensation hört die ALU auf die fallende Taktflanke des Clks, die> Kontrolleinheit auf die steigende. Auf die weise funktioniert das> Speichern von Daten in den Akkumulator gut.> Ist das bisher schon falsch gelöst oder noch ok?
Sehr unsauber.
Solche takt-versetzten Designs kann man machen, wenn das Gerät schon in
der Auslieferung ist, und das dann die einzige Rettung vor einem
Hardware-Redesign ist.
> Der Akkumulator besitzt 8-Bit...
Dann ist das m.E. ein 8-Bit-Core mit gemultiplextem Datenbus.
Zip das Projekt mal zusammen, und poste das.
Dann hat die Raterei ein Ende ;-)
Hi Lothar,
erstmal danke für deine Hilfsbereitschaft.
In dem gezippten Projekt befindet sich bislang nur mal der Code zur
Adresseinheit (da das problem scheinbar darin ensteht), der Xilinx IP
RAM Core und eine Testbench.
Falls du mehr benötigst, poste ich es nach.
Danke im Voraus,
F.
Hier sieht man auch schön das unschöne Latch, denn wenn keine andere
Bedingung zutrifft, wird der Wert von DataToMemory einfach nur gehalten.
EDIT:
Ein paar Zeilen weiter dann die überdefinierte Sens-List.
Hier sind MemEn, SelectSource, AdressBusIn unnötig, da nur eine
Änderung von Reset und/oder Clk etwas am Ergebnis des Prozesses
bewirken.
Denn wenn sich eines der drei anderen Signale ändert, dann wird sowieso
bis zum nächsten Takt gewartet, bis ein neuer Zustand berechnet wird.
Am besten baust du das auch gleich auf synchronen Reset um, das ist für
den Syntesizer wesentlich einfacher (such mal hier im Forum zum Thema
synchroner und asynchroner Reset), und dann ist nur noch der Clk in der
Sensitivity-List ;-)
Hi Lothar,
ich danke dir für deine Hilfe, vorallem für die Tips bzgl.
Sensitivity-Lists.
Das Latch habe ich dann auch erkannt (bzw. das Xilinx Tool hat es mir im
Report gemeldet), als ich eine Timing-Simulation durchführen wollte.
Allerdings durchschaue ich noch nicht, wieso ich Anweisungen wie
Concurrent machen muss. Was ist so schlecht an einem eigenen Prozess
(einmal abgesehen von meiner unvollständigen Sens-List ;-))?
Viele Grüsse,
F.
P.S: Das Delay von einem halben Takt kam in der Testbench auf. Der Reset
war zur fallenden Clk-Flanke beendet, und sofort startete das MemEn...
Felix wrote:
> Allerdings durchschaue ich noch nicht, wieso ich Anweisungen wie ...> Concurrent machen muss. Was ist so schlecht an einem eigenen Prozess?
Musst du nicht, es ist aber viel kompakter und (dadurch automatisch)
übersichtlicher ;-)
Und das Latch (igitt) siehst du schon beim Schreiben, nicht erst bei der
Synthese. Ein Tipp: so ein Latch ist wirklich nichts, was man in einem
FPGA brauchen kann, weil es ein transparentes Latch (als Komponente) im
FPGA einfach nicht gibt. Statt dessen wird ein FF so beschaltet, dass es
sich wie ein Latch verhält. Probiers einfach mal aus ;-)
> P.S: Das Delay von einem halben Takt kam in der Testbench auf. Der Reset> war zur fallenden Clk-Flanke beendet, und sofort startete das MemEn...
Was wäre passiert, wenn der Reset (noch wesentlich ungünstiger) gerade
um die steigende Flanke deaktiviert worden wäre? Richtig: in der Praxis
ist das eine Setup/Hold-Zeit Verletzung.
Dazu ist nur zu sagen, dass der Reset das asynchrone Signal
schlechthin ist. Und jedes asynchrone Signal gehört sauber (über
mindestens 2 FF) einsynchronisiert und dann erst im FPGA verwendet. So
is das ;-)
Dein Problem mit dem "halben Takt später" hat folgenden Grund:
Du hast ein synchrones Design gebaut, das bei einer steigenden
Taktflanke etwas liefert. In deiner Testbench startet dein clk bei 0 zum
Zeitpunkt 0. Dann wartest du eine Taktperiode, bis du etwas anlegst.
Eine halbe Periode später geht clk auf 1 (steigende Flanke), eine
weitere halbe Periode später auf 0 (fallende Flanke). Du legst in deiner
Testbench also etwas zur fallenden Flanke an, worauf dein Design zur
steigenden Flanke reagiert. Dein Design macht das also wahrscheinlich
schon richtig. Das Anlegen könnte auch zu jedem anderen beliebigen
Zeitpunkt (als der fallenden Flanke) geschehen, dein Design würde immer
zur steigenden Flanke arbeiten.
Wenn du zum Beispiel in der TB als Initialisierungswert für clk:= '1'
nimmst, sieht das ganze wahrscheinlich eher so aus, wie du es dir
vorstellst.
Weiterhin das Problem was Lothar erwähnt hat: das zeitgleiche
anlegen/abschalten der Signale zur Flanke. Für die Verhaltenssimulation
hilft hier z.B.
wait for 1 ps;
oder ähnliches ganz am Anfang des stim_proc.
Ja, das habe ich auch festgestellt. Zur Kompensation verwende ich nach
dem Reset ein
1
waituntilrising_edge(Clk);
2
:
3
MemEn<='1'afterclk_period/5ns;
4
:
Aber mal eine ganz andere Frage:
Wie sieht eigentlich die Simulation in der realen Praxis aus? Wird da
nur auf Verhaltensebene simuliert und darauf geachtet, dass für die
Synthese die Timing Constraints eingehalten werden? Oder wird auch mit
Post-Route Simulation gearbeitet?
Viele Grüsse,
F.
Felix wrote:
> Ja, das habe ich auch festgestellt. Zur Kompensation verwende ich nach> dem Reset ein
1
waituntilrising_edge(Clk);
2
:
3
MemEn<='1'afterclk_period/5ns;
4
:
Es ist die falsche Vorgehensweise, eine Testbench so hinzuschreiben,
dass das Design durchkommt (also in der Testbench auf eine Flanke des
Taktsignals zu warten). Denn dann wird dein Design auch in der Realität
nur unter diesen Rahmenbedingungen funktionieren.
D.h. du musst (von aussen) garantieren, dass der Reset mit zum richtigen
Zeitpunkt weggeht, und auch deine anderen Signale zum richtigen
Zeitpunkt angelegt werden. So ist ja auch deine simulation ;-)
Weil du das in der Praxis nicht kannst, müssen alle externen
asynchronen Signale (incl. Reset) einsynchronisiert werden.
> Aber mal eine ganz andere Frage:> Wie sieht eigentlich die Simulation in der realen Praxis aus? Wird da> nur auf Verhaltensebene simuliert und darauf geachtet, dass für die> Synthese die Timing Constraints eingehalten werden?
Sich vorher ausführlich Gedanken zum Design zu machen reicht i.A. aus.
Denn du kannst eine Testbench nie so schreiben, dass alle Grenzfälle aus
der Praxis abgedeckt sind.
>Oder wird auch mit Post-Route Simulation gearbeitet?
Wie gesagt: vorher überlegen und sinnvolle Constraints setzen.
In der statischen Timinganalyse stehen dann noch ein paar Zahlen, die
eine aussage zu den Design-reserven zulassen.