Hallo!
Ich stehe im Moment vor der Aufgabe, einen programmierbaren Taktteiler
zu schreiben, der mir leider große Probleme bereitet. Grundsätzlich soll
er so arbeiten, wie es die Simulation von meinem bisherigen Code
darstellt: Ausgehend von einem 275MHz Takt soll jeweils nach einer, von
einem Teiler (DIVISOR) einstellbaren Taktzahl ein Impuls erzeugt werden
(CLK_DIV). Der Impuls muss vier Takte des 275MHz Clocks lang High sein.
Ein zweites Signal (SEL) muss mit der fallenden Flanke des CLK_DIV
Signals auf Low gehen, mit der steigenden Flanke des CLK_DIV Signals
wieder auf High.
Der Gedanke hinter meinem bisherigen Code ist, dass kombinatorisch das
nächste Signal vorbereitet und dann durch einen getakteten Prozess
übernommen wird. Das Funktioniert bisher in der Simulation und auch auf
dem FPGA - jedoch nur bis etwa 200MHz. Darüber hinaus macht das SEL
Signal nur noch mist. Das Codefragment:
1
elsif(next_cnt(2)='1')and(sel_cnt='0')then
scheint durch laufzeitunterschiede nicht mehr richtig zu arbeiten,
weswegen das CLK_DIV Signal praktisch mit im SEL Signal auftaucht. Ich
habe leider kein Bild um das Verhalten zu zeigen.
Wie müsste ich den Taktteiler umsetzen, damit er "sauber" ist, also
nicht mehr von laufzeitunterschieden abhängig ist? Klar, CE Eingang von
FFs, aber ehrlich gesagt komm ich auch mit der Info nicht weiter.
Ich würde mich über jede Antwort freuen.
Viele Grüße, Marcus
> Ein zweites Signal (SEL) muss mit der fallenden Flanke des CLK_DIV> Signals auf Low gehen, mit der steigenden Flanke des CLK_DIV Signals> wieder auf High.
Lies dir den Satz nochmal genau durch.
Nach dieser Beschreibung wären die beiden Signale genau gleich... :-/
> auch auf dem FPGA
Welches FPGA?
> jedoch nur bis etwa 200MHz.
200MHz ist schnell. Das Wort "nur" ist hier fehl am Platz.
Du könntest u.U. von der Gigahertz-Manie bei PCs fehlgeleitet sein...
Wenn es dir zu langsam ist, mußt du den kritischen Pfad herausfinden und
überarbeiten. Dazu verwendest du am besten die statische Timing-Analyse.
> Ausgehend von einem 275MHz Takt
Woher kommt der Takt?
@Lothar Miller
>Lies dir den Satz nochmal genau durch.
Ach mist - ja, da hast du natürlich recht. Was ich meine ist wohl am
Besten am Screenshot der Simulation zu erkennen. Also bei der fallenden
Flanke von einem CLK_DIV Impuls auf Low, bei der steigenden Flanke des
nächsten Impulses wieder High, fallende Flanke des nächsten Impulses
wieder Low und so weiter.
>Welches FPGA?
Spartan 3
>200MHz ist schnell. Das Wort "nur" ist hier fehl am Platz.>Du könntest u.U. von der Gigahertz-Manie bei PCs fehlgeleitet sein...
Klar ist das extrem schnell und das ich darauf zurück greifen musste hat
mir von Anfang an Bauchschmerzen bereitet. Ohne jetzt ins Detail zu
gehen bin ich gezwungen mit einem so hohen Takt arbeiten zu müssen. Er
wird aus 25MHz mit einem DCM erzeugt.
>Wenn es dir zu langsam ist, mußt du den kritischen Pfad herausfinden und>überarbeiten
Den problematischen Pfad habe ich ja im Prinzip schon rausgefunden
(siehe Ursprungsposting). Die Frage ist, wie ich diese Bedingung anders
beschreiben kann, damit sie schneller läuft - bzw. ob die gesamte
Herangehensweise vielleicht murks ist und ich die Sache neu aufsetzen
sollte, und wenn ja, wie.
@Lothar Miller
Wenn ich dich schon am Wickel habe ;)
Ich lese hier schon länger und meistens passiv mit und wollte nur mal
sagen, dass ich's toll finde, das jemand mit Erfahrung sich die Zeit
nimmt anfängern unter die Arme zu greifen und Hilfestellung zu geben. Du
schreibst hier so regelmäßig rein, dass ein dickes Danke angesagt ist.
Deine Beschreibung von next_sel und next_clk_div erzeugt Latche, das
solltest du auf alle Fälle beheben.
An ein paar Stellen kannst du die Geschwindigkeit auf Kosten der Größe
auch noch erhöhen.
> if cnt = (div-1)
Hier könntest du div-1 schon einen Takt vorher berechnen und das
Ergebnis in ein Register packen.
Außerdem benutzt du
> if next_cnt = 0 then
Hier solltest du besser gleich das praktisch äquivalente "cnt = (div-1)"
benutzen, das sollte ebenfalls Zeit sparen.
> auch auf dem FPGA - jedoch nur bis etwa 200MHz.> Darüber hinaus macht das SEL Signal nur noch mist.
Bis zu welcher Geschwindigkeit sagt dir der Report, das das gehen
sollte?
Hast du Timing-Constraints gesetzt?
Wenn ich deinen Code synthetisiere, erhalte ich
-- Minimum input arrival time before clock: 5.341ns
3
-- Maximum output required time after clock: 6.280ns
Überleg dir, ob du diese Signale in der Kombinatorik brauchst:
EN_CLK_DIV : in std_logic;
EN_SEL : in std_logic;
Das bringt dir schnell mal eine Lut mehr in den Logikpfad, und das
kannst du bei 275MHz nicht brauchen...
BTW:
An deinem Zwei-Prozess-Zähler-Code sieht man schön, wie schnell man
damit ein Latch an der Backe hat.
@ Lothar Miller und Jan M.
Vielen Dank für eure Ratschläge und besonderen Dank an Lothar Miller für
deine - zugegeben weitaus "elegantere" - Version! Ich setze mich nochmal
daran auf Basis von Lothars Code das Modul neu zu schreiben und dann mit
(bisher nicht gesetzten) Timing Constraint zu optimieren.
Ich wünsche noch einen schönen Abend :)
viele Grüße, Marcus
Ich habe gerade nochmal einen kurzen Blick auf Lothars Code geworfen:
Mit einem up- statt dem down-counter wird es schneller (197MHz, Spartan
3) - das Laden der Register mit einem variablen Wert ist aufwändiger als
ein 10bit Vergleicher, der dann gebraucht wird.
Auch interessant: Der Virtex4 kann hier sein schnelleres Routing voll
ausspielen und schafft fast die doppelte Geschwindigkeit: 379 MHz.
> Ich habe gerade nochmal einen kurzen Blick auf Lothars Code geworfen
Ich auch, und dabei noch das Schieberegister rausgeschmissen, das bringt
hier nichts, der kritische Pfad liegt woanders (nämlich in der
Verdrahtung).
Mit diesem Code
1
architectureBEHAVEofTaktteileris
2
signalcnt:unsigned(9downto0):=(others=>'0');
3
signaltoggle:std_logic:='0';
4
begin
5
processbegin
6
waituntilrising_edge(clk_275);
7
if(cnt<unsigned(DIVIDER))then
8
cnt<=cnt+1;
9
else
10
cnt<=(others=>'0');
11
endif;
12
endprocess;
13
14
processbegin
15
waituntilrising_edge(clk_275);
16
if(toggle='1'andcnt=4)then
17
SEL<='0';
18
endif;
19
if(cnt=4)then
20
CLK_DIV<='0';
21
endif;
22
if(cnt=0)then-- setzen, wenn cnt=0
23
SEL<='1';
24
CLK_DIV<='1';
25
toggle<=nottoggle;
26
endif;
27
endprocess;
28
29
endBehave;
komme ich bei Spartan 3 Speedgrade -5 auf den von Jan angesprochenen
Takt:
275 mit S3 sollte harter broken sein:
habe physikalisch in FPGA gemessen
S3 (normal speedgrade) bei 375MHz ist fabric TOTAL tot
fur V4 ist das aber 975MHz
275Mhz beduetet ja nicht das design mit 275 laufen muss
aber mit 300+, da temp/vcc toleranzen und CLOCK JITTER
ja auch beruksichigt werden muss.
375MHz in S3 ging wirklich nur "bis nachste LUT" nicht viel
weiter, wenn mit nahe 300mhz ein zahler und noch was laufen
sollte ist schon ganz gut nahe zu allerlezten grenze
(mindestens niegrige speedgrade)
Antti
> Aber knapp daneben ist auch vorbei :-/
Naja, das sind doch die Ausgaben der Synthese oder? Eventuell schafft
der P&R noch etwas Optimierung und wird dann schneller. Sehe ich bei
unseren Designs oft hier.
> Eventuell schafft der P&R noch etwas Optimierung und wird dann schneller.
Auch schon rumgespielt, bringt ein paar ps, aber das Problem ist das
Routing, das ist so dermaßen langsam. Mit maximalem
Optimierungseinstellungen komme ich beim S3 auf 4.495ns = 222 MHz.
hallo
hast du an schiebe registergedacht ?
es kann auch dafür geeignet sein du kannst ein bit am Anfang des
registers legen und in eine beliebige stelle wieder emfangen und den
wiederum als clk benutzen
Ich habe einen 32Bit Zähler im Spartan3AN implementiert, der bei 200MHz
läuft.
Im Prinzip habe ich die Aufgabe heruntergebrochen auf jeweils
4Bit-Zähler, mit einer Art Look-Ahead Technik. Braucht mehr rescourcen,
ist aber der einzige Weg, wenn der Vergleicher zu langsam ist.
Jeder 4Bit-Zähler ist wie ein klassischer Zähler aufbegaut. Das Carry
Out jedoch wird am Ausgang nochmals zwischengepuffert. Die Erzeugung des
Carry out habe ich so angepasst, dass einen Takt vor dem Ablauf schon
"Expired" erzeugt wird. Anschließend noch schnell per Generate in ein
Counter der Breite 4xN umgestöpselt.
Code finde ich leider gerade nicht.
Stimmt, kannst auch eine MLS bauen mit Schieberegister.
Müsstest dann per Lookup deinen Countwert umbauen,
und auf ein bestimmtes Wort warten um den Counter neu zu laden.