Forum: FPGA, VHDL & Co. PIO implementieren: in + out oder inout?


von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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
entity pio is
2
  port (
3
    io_out: out std_logic_vector(7 downto 0);
4
    io_in: in std_logic_vector(7 downto 0)
5
  );
6
end pio;

statt
1
entity pio is
2
  port (
3
    io: inout std_logic_vector(7 downto 0)
4
  );
5
end pio;

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"?

von Achim M. (minifloat)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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).

von Duke Scarring (Gast)


Lesenswert?

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

von Unbekannter (Gast)


Lesenswert?

Intel/Altera hat da ein schönes Beispiel in VHDL:

https://www.intel.com/content/www/us/en/programmable/support/support-resources/design-examples/design-software/vhdl/v_bidir.html

Die machen das genauso: intern pro Datenrichtung ein Bus, nach extern 
ein inout mit Richtungsumschaltung.

HTH

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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
        END IF;
10
    END PROCESS;
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:
1
    bidir <= a when oen='0' else (others->'Z');
2
    b     <= bidir;

: Bearbeitet durch Moderator
von Duke Scarring (Gast)


Lesenswert?

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

von daniel__m (Gast)


Lesenswert?

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 FPGA kö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

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.