Forum: FPGA, VHDL & Co. Datenregister im FPGA


von Tobias P. (hubertus)


Lesenswert?

Hallo,
ich habe nun zum ersten mal auf einem selber gebauten Board einen FPGA 
und uC miteinander verbunden via 8 Bit breiten Daten- und Adressbus.
Und soweit funktioniert alles perfekt!
Nun habe ich aber ein paar fragen.

Grundsätzlich: der uC führt das interne CPU-Taktsignal nach aussen, und 
dieses ist mit dem FPGA verbunden. Alle Signale vom uC sind zu diesem 
Taktsignal synchron, weshalb ich mir dachte, dass ich die 
Einsynchronisierung der einzelnen Signale sparen kann (was ich hier im 
Forum gelesen habe - anscheinend ist das zulässig).

So, ich habe im FPGA nun verschiedene "Register", auf die der uC 
zugreifen kann, wo bestimmte Daten gelesen oder geschrieben werden.

Mit folgendem Code wird dies realisiert:
1
signal q : std_logic_vector(7 downto 0);
2
signal register1 : std_logic_vector(7 downto 0);
3
signal register2 : std_logic_vector(7 downto 0);
4
5
process begin --write
6
  wait until falling_edge(clk);
7
  if ce = '0' and oe = '1' and we = '0' then
8
    if adressbus = 0 then
9
      register1 <= datenbus;
10
    elsif adressbus = 1 then
11
      register2 <= datenbus;
12
    end if;
13
  end if;
14
end process;
15
16
process begin --read
17
  wait until falling_edge(clk);
18
  if ce = '0' and oe = '0' and we = '1' then
19
    if adressbus = 0 then
20
      q <= register1;
21
    elsif adressbus = 1 then
22
      q <= register2;
23
    else
24
      q <= (others => '0');
25
    end if;
26
  end if;
27
end process;
28
29
datenbus <= q when ce = '0' and oe = '0' and we = '1' else (others => 'Z');

so könnte man das beliebig weiter stricken und für jedes Register eine 
if-Abfrage machen. Das gefällt mir aber nicht so recht; geht das auch 
irgendwie eleganter?

dann, die nächste Frage. Ich habe in einem Register die Bits INTEN, 
SWINT, IRQF, SRST und TST. Jedes der Bits ist in Wirklichkeit natürlich 
ein Signal im FPGA, womit sich dann irgendwelche Dinge ein-, aus- oder 
umschalten lassen. Was ist besser:
1
process begin --write
2
  wait until falling_edge(clk);
3
  if ce = '0' and oe = '1' and we = '0' then
4
    if adressbus = 3 then
5
      INTEN <= datenbus(0);
6
      SWINT <= datenbus(1);
7
      IRQF <= datenbus(2);
8
      SRST <= datenbus(3);
9
      TST <= datenbus(4);
10
    end if;
11
  end if;
12
end process;
13
14
process begin --read
15
  wait until falling_edge(clk);
16
  if ce = '0' and oe = '0' and we = '1' then
17
    if adressbus = 3 then
18
      q <= "000" & TST & SRST & IRQF & SWINT & INTEN;
19
    else
20
      q <= (others => '0');
21
    end if;
22
  end if;
23
end process;

oder das:
1
process begin --write
2
  wait until falling_edge(clk);
3
  if ce = '0' and oe = '1' and we = '0' then
4
    if adressbus = 3 then
5
      testregister <= datenbus;
6
    end if;
7
  end if;
8
end process;
9
10
process begin --read
11
  wait until falling_edge(clk);
12
  if ce = '0' and oe = '0' and we = '1' then
13
    if adressbus = 3 then
14
      q <= testregister;
15
    else
16
      q <= (others => '0');
17
    end if;
18
  end if;
19
end process;
20
21
INTEN <= testregister(0);
22
SWINT <= testregister(1);
23
IRQF <= testregister(2);
24
SRST <= testregister(3);
25
TST <= testregister(4);

Funktionieren tut, gemäss meinen Experimenten, beides. Aber ich bin 
sicher, wenn es funktioniert, muss es noch nicht unbedingt gut sein :-)

Ich bin gespannt auf eure Posts.

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


Lesenswert?

Tobias Plüss schrieb:
> Alle Signale vom uC sind zu diesem Taktsignal synchron,
Es kommt dann nur noch darauf an, welche Flanke relevant ist. Aber du 
hast offenbar die fallende Flanke als geeigneter gefunden...

> geht das auch irgendwie eleganter?
Nicht unbedingt, aber du kannst dir das Registrieren des Ausgangs q 
sparen und das Tristaten des Datenbusses dort gleich mit reinnehmen:
1
process (ce,oe,we,adressbus,register1,register2) --read
2
  datenbus <=  (others => 'Z');    -- default hochohmig
3
  if ce = '0' and oe = '0' and we = '1' then
4
    datenbus  <= (others => '0');  -- wenn selektiert: default "000"
5
    if adressbus = 0 then
6
        datenbus  <= register1;
7
    elsif adressbus = 1 then
8
        datenbus  <= register2;
9
    end if;
10
  end if;
11
end process;
Und wenn das Ganze dann sowieso kombinatorisch ist geht es auch so:
1
  datenbus <=  register1 when ce='0' and oe='0' and we='1' and adressbus=0 else
2
               register2 when ce='0' and oe='0' and we='1' and adressbus=1 else               
3
               (others => '0') when ce='0' and oe='0' and we='1'  else
4
               (others => 'Z');    -- default hochohmig
Mit einem Hilfssignal (z.B. rd) liest es sich dann leichter:
1
  rd <= '1' when ce='0' and oe='0' and we='1' else '0';
2
  datenbus <=  register1       when rd='1' and adressbus=0 else
3
               register2       when rd='1' and adressbus=1 else      
4
               (others => '0') when rd='1'  else
5
               (others => 'Z');    -- default hochohmig

> Was ist besser:
Das ist schlichtweg egal. Besser ist das, was du nach 1 Jahr noch ohne 
Aufwand kapierst... ;-)
Alternativ könntest du auf den Ressourcenverbrauch schauen, aber der 
dürfte sich nicht signifikant unterscheiden.

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.