Hallo.
Es geht um folgendes Projekt:
https://www.mikrocontroller.net/articles/Retrocomputing_auf_FPGA
-> Siehe Kapitel Takt.
Dort wird aus 50MHz Boardtakt mittels eines DCM 40MHz für VGA und
3.125MHz als CPU Takt (cpu_clk) der internen T80 (Z80) CPU, Ram, Rom,
PIO etc. erzeugt.
Wie häufig, bei alten Spielen, sind die 3.125MHz aber zu schnell und
Spiele
sind dadurch quasi 'unspielbar'.
Jetzt meine Frage:
Wie kann ich anstatt 3.125MHz die synthetisierten z1013 Komponenten mit
z.B. der Hälfte=1.5625MHz laufen lassen?
1
--Input: 50 MHz Startekit
2
--Output, used: 40 MHz for VGA 600x800@60
3
-- 3.125 MHz for CPU (the lowest what the dcm can madefrom 50 MHz)
4
-- 50 MHz (out of DCM for 7seg etc)
5
-- Status (for debug)
6
--40MHz pixel clock
7
--Design Name: dcm_sys
8
--Device: xc3s200-ft256-5
9
--4 BUFG; 1 IBUFG; DCM
10
11
libraryieee;
12
useieee.std_logic_1164.ALL;
13
useieee.numeric_std.ALL;
14
libraryUNISIM;
15
useUNISIM.Vcomponents.ALL;
16
17
entitydcm_sysis
18
port(CLKIN_IN:instd_logic;--incoming from pcb
19
CLKDV_OUT:outstd_logic;
20
CLKFX_OUT:outstd_logic;
21
CLKIN_IBUFG_OUT:outstd_logic;
22
CLK0_OUT:outstd_logic;
23
CLK180_OUT:outstd_logic;
24
status_o:outstd_logic_vector(7downto0));
25
enddcm_sys;
1
architecturearchofsk_topis
2
componentdcm_sys
3
port(
4
CLKIN_IN:instd_logic;
5
CLKDV_OUT:outstd_logic;-- wird mit cpu_clk verbunden
da du wahrscheinlich nicht das ganze Design auf Clock_enable umschreiben
willst, empfehle ich einfach den Takt nach der DCM per Flipflop zu
teilen. Für die Frequenz sollte das gut machbar sein.
Danach den Ausgang noch auf ein BUFG schalten.
In etwa so (bufg nochmal nachschauen):
Tim schrieb:> Danach den Ausgang noch auf ein BUFG schalten.
Genau soetwas war zu erwarten!
Wenn schon, dann bitte einen weiteren DCM nehmen und diesen
eleganterweise davor einsetzen, der bereits den eingehenden Takt "teilt"
und am Ausgang einen ordentlichen, berechenbaren Takt ermöglicht. Die
Dinger kann man bedenkenlos kaskadieren, sogar über nicht dediziertes
Taktrouting. Das ist zehnmal besser, als einen verhackstückten Takt.
Bei einer CPU reicht es oft nur den Einstieg(erste Stage in der Kette)
per Clock enable zu versehen.
Das hat zudem den Vorteil, das man schneller Takten kann, wenn
erwünscht.
(Turbomode).
Habe ich bei meinem Z80 Nachbau(siehe Gameboy Thread bei den Projekten)
so gemacht.
So läuft die CPU mit 4/8 Mhz, wie im Original, auf Tastendruck gibt es
kurzzeitig 100Mhz + Frameskip, z.b. um Ladezeiten zu überspringen.
Bei Xilinx haben die aber eine untere Grenze. Zumindest im Wizard. Da
muss der Eingangstakt 10 MHz oder mehr sein und als Ausgang sind
irgendwas zwischen 4,xxx und 800 MHz erlaubt.
Was spricht denn gegen das Teilen mit einem FF wenn das dann nur an
einer Stelle auf ein Taktnetz geht? Das wäre doch dann so wie wenn man
extern einen Takt teilt und über einen Clock Pin dem FPGA zuführt.
Wie Oben zT ja schon geschrieben kannst du eine
gated Clock erzeugen (z.B. per DDS oder einfach
per simplen Counter). Das gilt zwar unter
FPGA-Entwicklern als NoGo, da die Frequenz aber
"extrem" klein ist (ein paar MHz), ist das für
dein Ziel absolut akzeptabel. Denn du hast ja
z.B. bei 1MHz eine Signallaufzeit von 1000ns.
Und ob du da über BUFGs gehst oder direkte
Verbindungen wählst ist absolut irrelevant.
Relevant wird es aber, sobald IO-Bausteine ins
Spiel kommen, wie z.B.VGA. Hier müssen dann
alle Signale entsprechend auf eine Non-Gated
Clockdomaine gehievt werden. Das sollte aber
kein Problem sein.
Das ganze habe ich schon bei zig Retro-Nachbauten
gemacht, lief immer problemlos. Allerdings hatte
eine VGA-Ausgabe der gated Clockdomain oft einen
Pixelversatz, aber per Einsyncronisation lies
sich das immer problemlos beheben.
Sigi schrieb:> Und ob du da über BUFGs gehst oder direkte> Verbindungen wählst ist absolut irrelevant.
Bei dem geringen Takt vielleicht. Aber eigentlich kommt es doch vor
allem bei hohen Frequenzen drauf an, dass der Takt möglichst zeitgleich
überall ankommt. Und das passiert doch wenn das über ein Taktnetz geht.
Ob der Takt dann intern durch ein FF erzeugt wurde oder extern von einem
Oszillator kommt ist dann doch eigentlich egal?! Ja, das hat dann
vielleicht mehr Jitter, aber zu jedem Takt erreicht die Flanke
einigermaßen zeitgleich alle Ziele.
Ich hatte damit bisher nur Probleme wenn ich kein Taktnetz verwendet
habe. Wenn man den Code aber sowieso selbst neu schreibt sind Clock
Enables sinnvoller, dann kann man intern den normalen Takt verwenden.
Gustl B. schrieb:> Bei dem geringen Takt vielleicht. Aber eigentlich kommt es doch vor> allem bei hohen Frequenzen drauf an, dass der Takt möglichst zeitgleich> überall ankommt. Und das passiert doch wenn das über ein Taktnetz geht.
Es kommt immer darauf an, dass alle FFs "möglichst gleichzeitig"
den Takt bekommen, egal ob niedrige oder hohe Tahtrate! Denn
sonst könnte ja ein FF A den Takt deutlich nach FF B bekommen,
aber von B lesen. In dieser Situation liest also A den nächsten
Wert von B und nicht den eigentlich aktuellen Wert. Und bei
deiner Bemerkung fällt mir gerade auf, dass ich vergessen habe,
bei direkter Verbindung der Clock die From-To-Constraints zu
erwähnen. Ohne die passiert eben genau dies. Im Prinzip hast
du natürlich recht, dass ein Einspeisen ins Clock-Netzwerk
besser und unkomplizierter ist. (aber nur so als Nebenbemerkung:
bei einigen Familien gibt es evtl. keine Möglichkeit, ein komb.
oder FF-Signal ins Clock-Netz einzuspeisen oder umgekehrt ein
Komb./FF-Signal direkt als Clock-Signal zu verwenden, von daher
habe ich mir vor langer Zeit beide Möglichkeiten ausgedacht)
Gustl B. schrieb:> Ob der Takt dann intern durch ein FF erzeugt wurde oder extern von einem> Oszillator kommt ist dann doch eigentlich egal?!
Wenn's nur um die internen Abläufe geht, da hast du recht.
Aber z.B. bei VGA-Signalen kann durch eigene Logik erzeugte
Taktsignale das Jittern so gross sein, dass sich je nach
Zeile die Pixels um eine Position nach Hintern verschieben
können.
Gustl B. schrieb:> Bei Xilinx haben die aber eine untere Grenze. Zumindest im Wizard. Da> muss der Eingangstakt 10 MHz oder mehr sein und als Ausgang sind> irgendwas zwischen 4,xxx und 800 MHz erlaubt.
Ja, wobei:
Hier geht es ja konkret um den Spartan 3. Der kann auch niedriger
getaktet werden, wenn man die PLL-Funktion mit phase lock nicht
verwendet. Dann liegt die untere GF bei glaube ich 5MHz.
Gustl B. schrieb:> Ja, das hat dann> vielleicht mehr Jitter, aber zu jedem Takt erreicht die Flanke> einigermaßen zeitgleich alle Ziele.
Weil die Möglichkeit besteht, von einem nicht-Taktnetz über einen BUFG
doch wieder in eine Taktnetz zu gelangen. Gleichwohl ist das nicht so
ideal, weil von der heute angewendeten timing driven synthesis nicht
(gut) zu berechnen. Das konnte man bei "langsamen" FPGAs unter 100MHz
und ISE machen.
Ich würde einen Clock-Buffer mit Teiler 1:2 nehmen, um die Frequenz an
den DCM zu kriegen.
ISE kann übrigens doppelte DCMs konfigurieren.
Jürgen S. schrieb:> Weil die Möglichkeit besteht, von einem nicht-Taktnetz über einen BUFG> doch wieder in eine Taktnetz zu gelangen. Gleichwohl ist das nicht so> ideal, weil von der heute angewendeten timing driven synthesis nicht> (gut) zu berechnen.
Bei den für Retro-Systeme üblichen Frequenzen sind
alle Timing-Berechnungen idR komplett überflüssig,
denn wo hat man schon mal eine z.B. Kombinatorik
einer Beschreibung, die mehr als 1000ns Laufzeit
braucht. Selbst 100ns (=> 10MHz) sind relativ egal.
Sigi schrieb:> Aber z.B. bei VGA-Signalen kann durch eigene Logik erzeugte> Taktsignale das Jittern so gross sein, dass sich je nach> Zeile die Pixels um eine Position nach Hintern verschieben> können.
Gut wenn man das MSB eines großen Akkus wie bei der DDFS als neuen Takt
verwendet hat man natürlich massiv Jitter.
Aber wenn ich durch eine Zweierpotenz teilen will dann sollte das recht
gut klappen. Auch ganzzahlige feste Teiler sind doch ok weil dann nimmt
man eben einen Zähler der bis zu einem bestimmten Wert zählt. Dann hat
der neue Takt zwar oft kein 50:50 Tastverhältnis, aber er hat eine feste
Periodendauer.
Jürgen S. schrieb:> Gleichwohl ist das nicht so> ideal, weil von der heute angewendeten timing driven synthesis nicht> (gut) zu berechnen.
Erkennt die Synthese das als neuen Takt, wenn ich einen Takt mit einem
FF teile, in ein Taktnetz einspeise?
Erkennt die Synthese feste Clock-Enables im Sinne von "alle n Takte ist
das Enable für einen Takt aktiv"?
Für manche Rechnungen habe ich diese Multi-cycle-constraints gesetzt. Da
wäre es schon schick, wenn man das "langsamer" mit Clock-Enables bauen
könnte. Nicht wirklich langsamer, weil der Takt ja gleich hoch bleibt,
aber das Ergebnis wird eben erst zum nächsten Clock-Enable ein paar
Takte später erwartet.
Wenn ich mich erinnere, gab es damals xilinxspezif. Gründe warum ich das
Design nicht auf 1MHz setzte. Ich schlage daher einen Alternativen Weg
zum Abbremsen vor: Der Z80-Cpu sollte man Wartezeiten aufzwingen können,
indem man bspw. ihr Bus per BUSRQ entzieht . Dann könnte man den Takt
belassen wo er ist.
So ein Modul hatte ich mal angefangen, es könnte sich aber aus
beruflichen Gründen (grad beim Selbstständigmachen) noch Monate
hinziehen.
Peter S. schrieb:> Wie häufig, bei alten Spielen, sind die 3.125MHz aber zu schnell und> Spiele sind dadurch quasi 'unspielbar'.
Original liefen die ersten Z1013 meines Wissens nach mit 1 MHz
Taktfrequenz, später dann mit 2 MHz.
Die 3.125 MHz (oder die Hälfte davon) haben mit dem Original nicht viel
zu tun.
Peter S. schrieb:> dcm_sys_1 : dcm_sys> port map (> CLKIN_IN => sys_clk, --incoming clock before BUFG> CLKDV_OUT => cpu_clk, --divided for Z80 clk> CLKFX_OUT => video_clk,> CLKIN_IBUFG_OUT => open, --incoming clock behind BUFG> CLK0_OUT => clk_50m, --clock after DCM> CLK180_OUT => open,> status_o => open);
Wird CLK0_OUT noch irgendwo verwendet oder kann das weg?
Bei CLKFX und CLK0 bzw. CLK180 liegt die Mindestfrequenz bei 5 MHz
(CLK2X0 -> 10 MHz). Also geht nur CLKDV.
Die möglichen Teiler für CLKDV liegen zwischen 1.5 und 16. Du bräuchtest
einen Teiler von 25 um von 50 MHz auf 2 MHz zu kommen.
Ich würde auch mit zwei DCMs arbeiten und jeweils die Frequenz durch 5
teilen.
1
dcm_sp_1st_instance:dcm_sp
2
genericmap(
3
clkin_divide_by_2=>false,
4
clkdv_divide=>5.0,
5
clk_feedback=>"1x"
6
)
7
portmap(
8
clkin=>sys_clk,
9
clk0=>clk0,
10
clkdv=>clkdv0,
11
clkfb=>clk_fb0
12
);
13
clk_fb0<=clk0;
14
15
dcm_sp_2nd_instance:dcm_sp
16
genericmap(
17
startup_wait=>true,
18
clkdv_divide=>5.0,
19
clk_feedback=>"1x"
20
)
21
portmap(
22
clkin=>clkdv0,
23
clk0=>clk1,
24
clkdv=>cpu_clk,
25
clkfb=>clk_fb1
26
);
27
clk_fb1<=clk1;
Der erhöhte Jitter dürfte hier keine Rolle spielen, sondern eher zum
Retrofeeling beitragen...
Duke
Sigi schrieb:> Bei den für Retro-Systeme üblichen Frequenzen sind> alle Timing-Berechnungen idR komplett überflüssig,> denn wo hat man schon mal eine z.B. Kombinatorik> einer Beschreibung, die mehr als 1000ns Laufzeit
Auf den ersten Blick mag die Betrachtung stimmen, aber die
Retro-FPGA-Systeme sind wie im Beispiel oben auch gerne mit einem
Retro-FPGA bestückt, für die 100MHz utopisch sind. Man darf auch die
Anforderungen der Chips nicht unterschätzen: Einen Grafik-Controller
oder Sound-Chip wie den SID emuliert man nicht 1:1 mit FPGA-Silizum. Es
kann durchaus nötig sein, gewisse Verzögerungen zwischen Komponenten
fein aufzulösen, was entsprechende Taktraten erfordert und bei 20MHz
sind an anderer Stelle 50ns schnell aufgebraucht, z.B. für 2 verkettete
Multiplier.
Duke Scarring schrieb:> Der erhöhte Jitter dürfte hier keine Rolle spielen, sondern eher zum> Retrofeeling beitragen...
Den Jitter wird man kaum merken, aber dessen Berücksichtigung erschwert
das Abschließen des Timings durch die Synthese.
Ok, bei dem Design mag das eine untergeordnete Rolle spielen.
Jürgen S. schrieb:> Einen Grafik-Controller> oder Sound-Chip wie den SID emuliert man nicht 1:1 mit FPGA-Silizum.
Da hast du natürlich recht, z.B. muss für den VIC
wesentlich mehr an MHz investiert werden, für den
VIC-II reicht aber eine Schaltung mit 8MHz.
Beim SID wiederum ist der Digitalteil überhaupt
nicht kritisch, da reichen sub-sub-MHze.
Kritisch sind die Filter. Die habe ich aber komplett
durchgemessen (z.B. mit Terasic-NEEK, denn hast
du ja auch, hier ist der Wolfson-Audio-Chip zum
Samplen und Ausgeben interessant, in Verbindung mit
dem FPGA ideal zum systematischen!! Durchmessen),
eine HDL-Simulation aller Komponenten habe ich auch
schon gemacht., nur noch nicht komplett zu einem
SID zusammengefasst. Selbst da sind nur kleine
MHz-Bereiche ausreichend (meine Beobachtung/Messung
bis jetzt, du bist aber Audio-Profi -- ich Laie! --
und wirst bei meinen Ansätzen sicherlich noch
Fehler finden).
Ebenso beim Amiga. Und da sind Frequenzen bis
8 bzw. 16 MHz. Und auch da: Timing-Constrainst
irrelavant.
Und schnellere Retro-Geschichten wie z.B.
Playstation 1 oder Gar N64 kann man wohl vergessen.
(da sind dann Timings sehr schnell kritisch)
Ich (als VHDL noob) habe es jetzt erst einmal so 'gelöst' (soll heißen,
es scheint zu funktionieren = synthetisiert und Spiel läuft etwas
langsamer):
in sk_wrapper.vhd:
1
...
2
componentclk_div
3
port(
4
CLK_IN:instd_logic;
5
CLK_OUT:outstd_logic);
6
endcomponent;
7
...
8
signalclk_50m:std_logic;
9
signalvideo_clk:std_logic;
10
signalcpu_clk:std_logic;
11
signalcpu_clk2:std_logic;-- new
12
...
13
---
14
dcm_sys_1:dcm_sys
15
portmap(
16
CLKIN_IN=>sys_clk,--incoming clock before BUFG
17
CLKDV_OUT=>cpu_clk2,--3.125MHz divided for Z80 clk
Hier ist noch ein mit dem Projekt kompatibler t80:
https://github.com/mist-devel/T80
Der obige hat clk_n in clk geändert oder umgekehrt - läuft daher nicht
ohne Anpassungen!
VG