Forum: FPGA, VHDL & Co. I/O Port so OK?


von Marko B. (glagnar)


Angehängte Dateien:

Lesenswert?

Hi,

vorgestern habe ich mit VHDL angefangen. Erstes Projekt sollte ein 8-bit 
I/O Port mit Datenrichtungsregister (Port laesst sich bitweise auf 
Eingang oder Ausgang umschalten) und Intel-Bus (z.B. fuer 8051) sein. 
Hier ist mein Code, der fehlerfrei synthetisiert wird (ISE 13.1) und 
auch in der Simulation korrekt laeuft (s. Anhang).

1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
4
-- Uncomment the following library declaration if using
5
-- arithmetic functions with Signed or Unsigned values
6
--use IEEE.NUMERIC_STD.ALL;
7
8
-- Uncomment the following library declaration if instantiating
9
-- any Xilinx primitives in this code.
10
--library UNISIM;
11
--use UNISIM.VComponents.all;
12
13
entity intelbus is
14
    Port ( data : inout  STD_LOGIC_VECTOR (7 downto 0);  -- data bus
15
           addr : in  STD_LOGIC;                  -- address bit
16
        p0 : inout STD_LOGIC_VECTOR (7 downto 0);    -- i/o port
17
           rd : in  STD_LOGIC;                  -- /RD
18
           wr : in  STD_LOGIC;                  -- /WR
19
           res : in  STD_LOGIC;                  -- /RESET
20
           cs : in  STD_LOGIC);                  -- /CS
21
end intelbus;
22
23
architecture Behavioral of intelbus is
24
25
signal p0reg: std_logic_vector (7 downto 0);
26
signal ddr0: std_logic_vector (7 downto 0);
27
28
begin
29
30
process(res,rd,wr,cs,data) is
31
begin
32
33
  if (cs = '1') then
34
    data <= (others => 'Z');
35
36
  else  
37
    if falling_edge(wr) then
38
      if(addr = '0') then
39
        p0reg <= data;
40
      else
41
        ddr0 <= data;
42
      end if;
43
    end if;
44
  
45
    if falling_edge(rd) then
46
      if(addr = '0') then
47
        data <= p0;
48
      else
49
        data <= ddr0;
50
      end if;
51
    end if;
52
  end if;
53
54
  --asynchronous reset
55
  if (res = '0') then
56
    p0reg <= (others => '0');
57
    ddr0 <= (others => '0');
58
  end if;
59
  
60
  if (rd = '1') then
61
    data <= (others => 'Z');
62
  end if;
63
  
64
end process;
65
66
G: for i in 0 to 7 generate
67
  p0(i) <= p0reg(i) when ddr0(i) = '1' else 'Z';
68
end generate G;
69
70
end Behavioral;

Wuerde mich freuen wenn jemand kommentieren koennte ob alles OK ist oder 
ob man etwas besser/anders machen koennte.

von D. I. (Gast)


Lesenswert?

Dir fehlt jegliche Synchronisation auf einen Takt und noch dazu ein 
asynchroner Reset.

Das wird in realer Hardware nur sehr glitchig laufen, denn du versuchst 
auf Kontrollsignale taktmäßig zu triggern.

Eigentlich ist da alles falsch, was ein Anfänger falsch machen kann.

von Marko B. (glagnar)


Angehängte Dateien:

Lesenswert?

Aha, was waeren Deine konkreten Vorschlaege?

Ich will Dich ja nicht belehren, aber der Intel-Bus ist asynchron, da 
gibts keinen Takt.

Der Schaltplan (s. Anhang) sieht fuer mich OK aus (etwas vereinfachter 
Code, damit die Multiplexer rausfallen): die Register werden ueber das 
/WR-Signal getaktet.

Das ganze ist uebrigens fuer ein CPLD gedacht (XC9500).

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


Lesenswert?

Marko B. schrieb:
> Aha, was waeren Deine konkreten Vorschlaege?
Das muß nicht alles in 1 Prozess, dann passiert es auch nicht, dass 
unnötige Signale in der Sensitivliste auftauchen (data)...

Die Richtungsumschaltung machst du besser concurrent:
1
signal din  : STD_LOGIC_VECTOR (7 downto 0);
2
signal dout : STD_LOGIC_VECTOR (7 downto 0);
3
:
4
:
5
  -- Schreiben
6
  process (res,wr) begin
7
    if (res = '0') then
8
      p0reg <= (others => '0');
9
      ddr0 <= (others => '0');
10
    elsif rising_edge(wr) then  --< ressourcenschonender
11
--  elsif (wr='0') then         --< eigentlich richtiger
12
      if(addr = '0') then
13
        p0reg <= din;
14
      else
15
        ddr0 <= din;
16
      end if;
17
    end if;
18
  end process;
19
20
  -- Daten fürs Lesen bereitstellen
21
  dout <= p0 when addr = '0' else
22
          ddr0;
23
24
  -- Busverwaltung
25
  din  <= data;
26
  data <= (others => 'Z') when rd='1' or cs='1' else
27
          dout;

> Erstes Projekt sollte ein 8-bit I/O Port mit Datenrichtungsregister
> (Port laesst sich bitweise auf Eingang oder Ausgang umschalten) und
> Intel-Bus (z.B. fuer 8051) sein.
Diese Busse sind eigentlich nicht getaktet (auch nicht auf rd bzw. wr). 
Sondern da wird bei low-aktivem Signal gelatcht. Der richtige 
Zeitpunkt zur Datenübernahme ist also die steigende Flanke des 
wr-Signals...

Marko B. schrieb:
> Das ganze ist uebrigens fuer ein CPLD gedacht (XC9500).
Das hätte ganz an den Anfang der Frage hingehört. Es ist nämlich ein 
eklatanter Unterschied, ob du ein synchrones Design auf einem FPGA hast, 
oder irgendwelche Tricksereien auf einem CPLD... :-/

von Lattice User (Gast)


Lesenswert?

Du hast recht, dein Takt ist das wr Signal. Da glitcht nichts wenn der 
Busmaster sich an die Spec hält, und davon sollte man ausgehen können. 
Auch ein 8051 benimmt sich nicht wenn man ihn falsch ansteuert.

Zum Lesen würde ich allerdings nicht falling_edge(rd) verwenden, das 
lässt sich rein kombinatorisch ausführen.

von Lattice User (Gast)


Lesenswert?

Bah, ich schreibe zu langsam, bzw denke zuviel dabei.

Lothar Miller schrieb:
> Das hätte ganz an den Anfang der Frage hingehört. Es ist nämlich ein
> eklatanter Unterschied, ob du ein synchrones Design auf einem FPGA hast,
> oder irgendwelche Tricksereien auf einem CPLD... :-/

Für die Aufgabe ist das finde ich egal. Es ist nunmal kein getaktetes 
Design mit einer ständigen Clock.

Fertig hinschreiben hätte meine Ansicht nach nicht sein müssen, was 
lernt er jetzt noch?

PS: Ich habe in meiner Antwort 8051 mit 8255 verwechselt.

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


Lesenswert?

Lattice User schrieb:
> Für die Aufgabe ist das finde ich egal. Es ist nunmal kein getaktetes
> Design mit einer ständigen Clock.
Klar, in so ein CPLD passt ja nicht arg viel mehr rein...  ;-)

Aber man müsste die Sache wesentlich tiefer angehen, wenn da eine zweite 
Taktdomäne mit im Spiel wäre...

von Marko B. (glagnar)


Lesenswert?

Lothar Miller schrieb:

> Das muß nicht alles in 1 Prozess, dann passiert es auch nicht, dass
> unnötige Signale in der Sensitivliste auftauchen (data)...

Hatte ich sogar anfangs versucht, wurde aber durch "multiple drivers" 
Fehler frustriert.

> Die Richtungsumschaltung machst du besser concurrent:
>
1
> signal din  : STD_LOGIC_VECTOR (7 downto 0);
2
> signal dout : STD_LOGIC_VECTOR (7 downto 0);
3
> :
4
> :
5
>   -- Schreiben
6
>   process (res,wr) begin
7
>     if (res = '0') then
8
>       p0reg <= (others => '0');
9
>       ddr0 <= (others => '0');
10
>     elsif rising_edge(wr) then  --< ressourcenschonender
11
> --  elsif (wr='0') then         --< eigentlich richtiger
12
>       if(addr = '0') then
13
>         p0reg <= din;
14
>       else
15
>         ddr0 <= din;
16
>       end if;
17
>     end if;
18
>   end process;
19
> 
20
>   -- Daten fürs Lesen bereitstellen
21
>   dout <= p0 when addr = '0' else
22
>           ddr0;
23
> 
24
>   -- Busverwaltung
25
>   din  <= data;
26
>   data <= (others => 'Z') when rd='1' or cs='1' else
27
>           dout;
28
>

Ah, super. Das ist natuerlich deutlich eleganter :)

>> Erstes Projekt sollte ein 8-bit I/O Port mit Datenrichtungsregister
>> (Port laesst sich bitweise auf Eingang oder Ausgang umschalten) und
>> Intel-Bus (z.B. fuer 8051) sein.

> Diese Busse sind eigentlich nicht getaktet (auch nicht auf rd bzw. wr).
> Sondern da wird bei low-aktivem Signal gelatcht.

Ich hatte als erstes eine Level-getriggerte Version versucht, aber die 
ganzen Warnungen bzgl. "Latch found" haben mich dann auf die obige 
Version gefuehrt.

> Der richtige Zeitpunkt zur Datenübernahme ist also die steigende
> Flanke des wr-Signals...

Das hatte ich aber anders gelesen:

"If the 8051 is writing data, it appears on the bus following the 
address information, and the active-low write signal, WR_, indicates 
that the data is available. The falling edge of WR_ is typically used to 
capture the data from the bus."

http://www.design-reuse.com/articles/8692/fpga-design-from-the-outside-in.html

Fuer RD ist die kombinatorische Variante natuerlich viel eleganter.

>> Das ganze ist uebrigens fuer ein CPLD gedacht (XC9500).

> Das hätte ganz an den Anfang der Frage hingehört. Es ist nämlich ein
> eklatanter Unterschied, ob du ein synchrones Design auf einem FPGA hast,
> oder irgendwelche Tricksereien auf einem CPLD... :-/

Wieso dieses? Koennte man obigen Code so nicht in ein FPGA packen?

Danke uebrigens fuer den Code und die Erklaerungen!

Lattice User schrieb:

> Fertig hinschreiben hätte meine Ansicht nach nicht sein müssen, was
> lernt er jetzt noch?

Ich glaube fuer einen Anfaenger ist es schon extrem hilfreich, wenn man 
einen kompletten lauffaehigen Code hat, an dem man sich orientieren 
kann. Ausserdem ist das ja nur ein Hello World. Als naechstes kommt eine 
DMA Engine fuer einen 6502 :D

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


Lesenswert?

Marko B. schrieb:
> Hatte ich sogar anfangs versucht, wurde aber durch "multiple drivers"
> Fehler frustriert.
Und dann hast du dir selber was in die Tasche gelogen und alles in 1 
Prozess gepackt...   :-o

> The falling edge of WR_ is typically used to capture the data from the
> bus."
Sieh dir die Timing-Diagramme an: an der steigenden Flanke hast du 
wesentlich mehr Setupt-Zeit. Und die brauchst du eher, als die lange 
Hold-Zeit...

> Koennte man obigen Code so nicht in ein FPGA packen?
Doch, aber idR. läuft so ein FPGA-Design mit einem Takt um 50-100MHz. 
Und der externe uC/ISA ist dazu asynchron und damit wie ein solches 
Signal zu behandeln. Will heissen: Einsynchronisieren tut Not.

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.