Forum: FPGA, VHDL & Co. FPGA z1013 mit halber Taktfrequenz


von Peter S. (petersieg)


Lesenswert?

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
library ieee;
12
use ieee.std_logic_1164.ALL;
13
use ieee.numeric_std.ALL;
14
library UNISIM;
15
use UNISIM.Vcomponents.ALL;
16
17
entity dcm_sys is
18
   port ( CLKIN_IN        : in    std_logic;  --incoming from pcb 
19
          CLKDV_OUT       : out   std_logic; 
20
          CLKFX_OUT       : out   std_logic; 
21
          CLKIN_IBUFG_OUT : out   std_logic; 
22
          CLK0_OUT        : out   std_logic; 
23
          CLK180_OUT      : out   std_logic;
24
          status_o        : out   std_logic_vector(7 downto 0));
25
end dcm_sys;
1
architecture arch of sk_top is
2
  component dcm_sys
3
    port (
4
      CLKIN_IN        : in  std_logic;
5
      CLKDV_OUT       : out std_logic; -- wird mit cpu_clk verbunden
6
      CLKFX_OUT       : out std_logic;
7
      CLKIN_IBUFG_OUT : out std_logic;
8
      CLK0_OUT        : out std_logic;
9
      CLK180_OUT      : out std_logic;
10
      STATUS_O        : out std_logic_vector(7 downto 0));
11
  end component;
12
13
14
  component redz0mb1e
15
    port (
16
      video_clk    : in  std_logic;
17
      cpu_clk      : in  std_logic;
18
      clk_50m      : in  std_logic;
19
      keys_in      : in  std_logic_vector(2 downto 0);
20
      --
21
...
22
  dcm_sys_1 : dcm_sys
23
    port map (
24
      CLKIN_IN        => sys_clk,       --incoming clock before BUFG
25
      CLKDV_OUT       => cpu_clk,       --divided for Z80 clk
26
      CLKFX_OUT       => video_clk,
27
      CLKIN_IBUFG_OUT => open,          --incoming clock behind BUFG
28
      CLK0_OUT        => clk_50m,       --clock after DCM
29
      CLK180_OUT      => open,
30
      status_o        => open);

Also quasi zwischen dcm output (alter cpu_clk (*2)) einen Teiler/2 
dazwischen schalten um damit dann alle anderen Komponenten zu takten.

Peter

von Tim (Gast)


Lesenswert?

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):
1
signal cpu_clk_div2 : std_logic := '0';
2
3
if rising_edge(cpu_clk)
4
   cpu_clk_div2 <= not cpu_clk_div2;
5
end
6
7
bufg_i : bufg
8
port map (
9
 CLKIN => cpu_clk_div2
10
 CLKOUT => cpu_clk_bufg );

von Bildverarbeiter (Gast)


Lesenswert?

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.

von Robert P. (fpgazumspass) Benutzerseite


Lesenswert?

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.

: Bearbeitet durch User
von Gustl B. (-gb-)


Lesenswert?

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.

von Sigi (Gast)


Lesenswert?

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.

von Gustl B. (-gb-)


Lesenswert?

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.

von Sigi (Gast)


Lesenswert?

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.

von J. S. (engineer) Benutzerseite


Lesenswert?

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.

von Sigi (Gast)


Lesenswert?

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.

von Gustl B. (-gb-)


Lesenswert?

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.

von Fpgakuechle K. (Gast)


Lesenswert?

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.

von Peter S. (petersieg)


Lesenswert?

ok. Ich habe es nicht eilig ;-)

Peter

von Duke Scarring (Gast)


Lesenswert?

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
    generic map (
3
        clkin_divide_by_2 => false,
4
        clkdv_divide      => 5.0,
5
        clk_feedback      => "1x"
6
    )
7
    port map (
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
    generic map (
17
        startup_wait      => true,
18
        clkdv_divide      => 5.0,
19
        clk_feedback      => "1x"
20
    )
21
    port map (
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

von J. S. (engineer) Benutzerseite


Lesenswert?

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.

: Bearbeitet durch User
von Sigi (Gast)


Lesenswert?

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)

von Peter S. (petersieg)


Lesenswert?

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
  component clk_div
3
    port (
4
      CLK_IN       : in  std_logic;
5
      CLK_OUT      : out std_logic);
6
  end component;
7
...
8
  signal clk_50m                  : std_logic;
9
  signal video_clk                : std_logic;
10
  signal cpu_clk                  : std_logic; 
11
  signal cpu_clk2                 : std_logic; -- new
12
...
13
---
14
  dcm_sys_1 : dcm_sys
15
    port map (
16
      CLKIN_IN        => sys_clk,       --incoming clock before BUFG
17
      CLKDV_OUT       => cpu_clk2,      --3.125MHz divided for Z80 clk
18
      CLKFX_OUT       => video_clk,
19
      CLKIN_IBUFG_OUT => open,          --incoming clock behind BUFG
20
      CLK0_OUT        => clk_50m,       --clock after DCM
21
      CLK180_OUT      => open,
22
      status_o        => open);
23
24
  clk_div_1 : clk_div
25
    port map (
26
      CLK_IN        => cpu_clk2,        --3.125MHz from dcm
27
      CLK_OUT       => cpu_clk);        --1.5625 divided for Z80 clk
28
29
...

Plus neue Datei clk_div.vhd unter kleinkram inkludiert:
1
-- clk divider/2
2
3
library ieee;
4
use ieee.std_logic_1164.all;
5
use ieee.numeric_std.all;
6
7
entity clk_div is
8
  port(
9
    clk_in  : in  std_logic;
10
    clk_out : out std_logic);
11
end entity clk_div;
12
13
architecture Behavioral of clk_div is
14
15
signal clk_sig : std_logic := '0';
16
17
begin
18
  Process (clk_in) 
19
  begin
20
    if (rising_edge(clk_in)) then
21
      clk_sig <= not (clk_sig);
22
    end if;
23
  end Process;
24
  clk_out <= clk_sig;
25
end Behavioral;

Peter

: Bearbeitet durch User
von petersieg (Gast)


Lesenswert?

Moin.

Wollte mir das Projekt gerade nochmal ziehen von:

http://www.mikrocontroller.net/svnbrowser/redz0mb1e/

wird aber nicht mehr gefunden?!

Hier gibts evtl.noch was im Archive?:
https://archive.org/details/microcontroller.net_svn_svnrdump_20170901

SVN habe ich aber nicht, bzw. kenn ich mich auch nicht mit aus.

Hat jemand das Projekt ggf. noch als ZIP Datei?

(Ggf. sollte es dann auf github o.ä.)

VG Peter

von Peter S. (petersieg)


Lesenswert?

Hier gibt es eine webarchive Sicherung von VGARefComp:
https://web.archive.org/web/20150315060023/http://www.digilentinc.com/Data/Documents/Reference%20Designs/VGA%20RefComp.zip

Und hier ist evtl. der t80 sogar Fehlerbereinigt.
https://github.com/EisernSchild/t80

...nun mal sehen, ob das alles auch noch zusammen läuft..

VG

: Bearbeitet durch User
von Peter S. (petersieg)


Lesenswert?

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

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
Noch kein Account? Hier anmelden.