Wenn ich eine klassische PIO implementieren möchte, bei der man (bspw.
aus einem Softcore heraus) zur Laufzeit die Datenrichtung ändern können
möchte, dann muss ich ja irgendwo zwischen "aktiv Ausgang" und "Z" (für
Eingang) umschalten können (ggf. auch pullup, aber das ist erstmal
egal).
Nun habe ich im Hinterkopf, dass man auf Ebene einer Entity stets Busse
für Eingang und Ausgang getrennt führt, also
1
entitypiois
2
port(
3
io_out:outstd_logic_vector(7downto0);
4
io_in:instd_logic_vector(7downto0)
5
);
6
endpio;
statt
1
entitypiois
2
port(
3
io:inoutstd_logic_vector(7downto0)
4
);
5
endpio;
An irgendeiner Stelle muss man ja aus diesen aber mal den
bidirektionalen Bus zimmern, den man dann auch den FPGA-Pins zuweisen
kann. Wo und wie passiert das? Oder in diesem Falle doch eher "inout"?
Jörg W. schrieb:> Nun habe ich im Hinterkopf, dass man auf Ebene einer Entity stets Busse> für Eingang und Ausgang getrennt führt,
a) PIO auf Pins
Irgendwo muss der Input-Bus auf stabilen Pegeln gehalten werden. Dafür
hat man bei nem FPGA/CPLD Möglichkeiten das von der Logik der Pins
machen zu lassen. Musst du im Mapping dann so einstellen. Irgendwo kommt
das I/O-Umschaltsignal ran und man benutzt Latches der Pin-Treiber, die
sich vom Timing einigermaßen synchron spezifizieren lassen. Die willst
du nicht in deiner Entity haben. Niemand möchte Latches in einer Entity
haben.
b) PIO auf interne Busse
Meine Herangehensweise für Signale und Busse, die nie das Die verlassen,
wäre einsynchronisieren und statt zu latchen, den Clock für das
Einsynchronisieren zu gaten. Damit ist der input-Bus auch im Rahmen der
gewünschten Timings stabil. Das möchte man aber auch nicht in der Logik
bzw. Signalverarbeitung, die deine Entity darstellt, haben.
c) Umstellung auf getrenntes IO
Solltest du dich entscheiden, keinen PIO mehr zu wollen, sondern in
Input was rein zu werfen und auf Output dann woanders zu lesen oder
stumpf auf Out-Pins auszugeben, oder Verkettung mehrerer Entities zu
einer digitalen Verarbeitungskette, musst du die IO-Umschaltung nicht
aus deiner Entity herausoperieren.
d) Anschluss an IP-core als Peripherie
Da bekommst du ein Businterface passend zum IP-Core-Design mitgeliefert,
was dann sowas ähnliches wie b) erledigt. Das ist dann bereits auf den
Bus des IP-Cores abgestimmt (Timing etc.) und da ergibt es wenig Sinn,
das 1. selber zu bauen und auch noch in die Entity zu integrieren.
mfg mf
Achim M. schrieb:> Dafür hat man bei nem FPGA/CPLD Möglichkeiten das von der Logik der Pins> machen zu lassen. Musst du im Mapping dann so einstellen. Irgendwo kommt> das I/O-Umschaltsignal ran und man benutzt Latches der Pin-Treiber, die> sich vom Timing einigermaßen synchron spezifizieren lassen. Die willst> du nicht in deiner Entity haben.
OK, das ist dann die Stelle, die ich mir hier mal suchen muss (Lattice /
SiliconBlue iCE40).
Jörg W. schrieb:> An irgendeiner Stelle muss man ja aus diesen aber mal den> bidirektionalen Bus zimmern, den man dann auch den FPGA-Pins zuweisen> kann. Wo und wie passiert das?
Ich mache das i.d.R. im Toplevel. Auch und besonders für speziellere
Sachen, wie z.B. differentielle Buffer.
Jörg W. schrieb:> (ggf. auch pullup, aber das ist erstmal egal)
Leider haben die FPGA-Hersteller vergessen, den Pullup dynamisch
aktivieren zu können. Das geht nur statisch über die Konfiguration. Bei
den µC konnte man damit schöne Tricks machen.
Duke
Jörg W. schrieb:> Wo und wie passiert das?
Am übersichtlichsten im Toplevel. Denn nur dort, im "Toplevel" des
FPGAs, also aussen an den Pins, existiert diese Funktion real.
Duke Scarring schrieb:> Jörg W. schrieb:>> (ggf. auch pullup, aber das ist erstmal egal)> Leider haben die FPGA-Hersteller vergessen, den Pullup dynamisch> aktivieren zu können.
Ja, das könnte man glatt "kollektives Versagen" nennen. Denn der
Pullup(fet) ist ja eh' schon da und sogar schaltbar...
Unbekannter schrieb:> Die machen das genauso: intern pro Datenrichtung ein Bus, nach extern> ein inout mit Richtungsumschaltung.
Wow!
Hat das ein Erstsemesteraushilfspraktikant aus der SW-Abteilung gemacht?
Da findet man sowas:
1
PROCESS(oe,bidir)-- Behavioral representation
2
BEGIN-- of tri-states.
3
IF(oe='0')THEN
4
bidir<="ZZZZZZZZ"
5
b<=bidir;
6
ELSE
7
bidir<=a;
8
b<=bidir;
9
ENDIF;
10
ENDPROCESS;
Falsch ist hier, dass a in der Sensitivliste fehlt --> Simu passt nicht
zur Realität.
Und unnötig ist ein bidir, das sich unabhängig von oe immer auf b
auswirkt.
Und ebenso unnötig ist ein Prozess für eine if-Abfrage.
Darüber hinaus könnte man die Beschreibung mit einem (others->'Z')
wesentlich generischer machen.
Und abschließend sind Output-Enable Signale, die von aussen kommen, gern
mal low-aktiv.
Ich würde das wie jedes meiner bidirektionalen Bussignale so schreiben:
Lothar M. schrieb:> bidir <= a when oen='0' else (others->'Z');> b <= bidir;
Ja, das mache ich auch genau so.
Nur letztens bin ich damit bei Lattice Diamond reingefallen: Ich
brauchte den Input nicht und prompt machte der Synthesizer Mist. Ich
mußte den OBUFT manuell einbauen.
Duke
Jörg W. schrieb:> Nun habe ich im Hinterkopf, dass man auf Ebene einer Entity stets Busse> für Eingang und Ausgang getrennt führt
Man muss nicht, es ist aber sicherer. Vor allem, wenn nicht
sichergestellt werden kann, dass der Entity-Pin ein echter FPGA-Pin ist.
Echte Busse im FPGAkönnen beschrieben werden, diese werden dann bei
der Synthese je nach FPGA-Features automatisch in In/Out mit zugehörige
Muxer aufgebrochen. Je nach "Skill-Level" des Sythesetools kann das aber
auch schnell schief gehen.
Ansonsten kann man ohne Probleme FPGA-IO-Pins via "inout" über beliebig
viele Ebenen duch ein Design leiten und erst in einer Entity per
Inference (siehe oben) oder Primitive behandeln.
Das geht zumindest bei Xilinx seit Jahren.
So mache ich das und habe ein thematisch aufgeräumtes Top-Level, wo ich
möglichst nur Blöcke zusammen füge.
grüße