Forum: FPGA, VHDL & Co. Bussystem in VHDL


von S. R. (svenska)


Lesenswert?

Hallo,

ich habe mir ein minimales Kommunikationsprotokoll zwischen 
verschiedenen Entities ausgedacht (Clock, Request, Adresse, Read- und 
Write-Daten, Acknowledgement). Das funktioniert auch.

Jetzt möchte ich aber mehr als zwei Entities dort anschließen, aber ohne 
zentral die Adressen dekodieren zu müssen, also ein klassisches 
Bussystem aufbauen. Ein Master, drölfzig Slaves, die jeweils mit ihrer 
Basisadresse instantiiert werden und an sie gerichtete Anfragen 
beantworten.

Wie kriege ich die Signale von den Slaves zum Master (also 
Acknowledgement und Read-Daten) hin? Tristate scheint es im FPGA nicht 
zu geben...

Der Hintergrund ist, dass ich in einem Block einen Master habe, der auf 
Block-RAM und weitere Blöcke zugreifen soll. Außerdem gibt es eine 
Schnittstelle nach draußen, die das ebenfalls können soll. Das Block-RAM 
ist dualported, aber die anderen Blöcke sind es nicht und ich wollte 
ungern eine massive Crossbar in die Mitte klatschen, die ich jedesmal 
aufwändig anpassen muss, wenn ich einen neuen Block einklebe.

Wie löst ihr solche Probleme normalerweise?

Gruß,
svenska

von Markus F. (mfro)


Lesenswert?

S. R. schrieb:
> Wie kriege ich die Signale von den Slaves zum Master (also
> Acknowledgement und Read-Daten) hin? Tristate scheint es im FPGA nicht
> zu geben...

Wenn's kein inout gibt, hat eben jedes Modul einen "in"- und einen 
"out"-Bus sowie ein zugehöriges "sel", das es aktiviert, wenn es sich 
als angesprochen erkannt hat. Die Busse werden auf dem Toplevel-Entity 
zusammengeführt und das bekommt einen Buscontroller, der die 
"out"-Signale des Moduls, das "sel" aktiviert hat, wieder auf den 
"in"-Bus legt. Dort wird dann auch die Tristate-Steuerung "nach draußen" 
implementiert.

War das deine Frage?

: Bearbeitet durch User
von C. A. Rotwang (Gast)


Lesenswert?

Markus F. schrieb:
> S. R. schrieb:
>> Wie kriege ich die Signale von den Slaves zum Master (also
>> Acknowledgement und Read-Daten) hin? Tristate scheint es im FPGA nicht
>> zu geben...
>
> Wenn's kein inout gibt, hat eben jedes Modul einen "in"- und einen
> "out"-Bus sowie ein zugehöriges "sel", das es aktiviert, wenn es sich
> als angesprochen erkannt hat. Die Busse werden auf dem Toplevel-Entity
> zusammengeführt und das bekommt einen Buscontroller, der die
> "out"-Signale des Moduls, das "sel" aktiviert hat, wieder auf den
> "in"-Bus legt.

Alternativ kann man alle von den Slaves weggehneden signale ver-ODER-n, 
das ist einfacher als der beschriebene Muxer für die ACK. Das geht auch 
halbwegs generisch, alle ack in einen bitvektor o.ä. stecken und mit 
bspw or_reduce immer den gesamten vector verdödeln. 
http://electronics.stackexchange.com/questions/85922/vhdl-or-ing-bits-of-a-vector-together

Ansonsten schau mal in die Wishbone spec, da werden verschiedenen 
Bus-topologien auf ihre FPGA-tauglichkeit untersucht, bspw zentrale 
versus verteilter adressdecoder 
https://opencores.org/cdn/downloads/wbspec_b4.pdf S121 ff.

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


Lesenswert?

S. R. schrieb:
> Tristate scheint es im FPGA nicht zu geben...
Seit der Jahrtausendwende nicht mehr. Alle Busse müssen zu Multiplexern 
aufgelöst werden.

> Wie löst ihr solche Probleme normalerweise?
Über einen übergeorneten Arbiter. Denn dein "Master-Slave-Konzept" geht 
offenbar davon aus, dass auch die Slaves von sich aus was senden 
könnten. Das ist dann eben kein Master-Slave mehr, sondern ein 
Multimaster...

von C. A. Rotwang (Gast)


Lesenswert?

S. R. schrieb:

>  und ich wollte
> ungern eine massive Crossbar in die Mitte klatschen, die ich jedesmal
> aufwändig anpassen muss, wenn ich einen neuen Block einklebe.


Vielleicht ist das dein Problem, man kann eine crossbar so schreiben das 
eine erweiterung mit ein paar wenigen Zeilen in einem Package erweitert 
ist.
bspw. mit generate über einen index aller slaves.

von Klakx (Gast)


Lesenswert?

Warum nicht ein bestehendes Bussystem nehmen? Wishbone, AXI, Avalon, 
AHB, APB, ... da gibt es einige. OR-Reduce Busse sind auch nett.

Spätestens bei mehreren Mastern greife ich auf schon bestehende 
Spezifikationen. Das tolle daran ist auch die Wiederverwendbarkeit.

von Markus F. (mfro)


Lesenswert?

C. A. Rotwang schrieb:
> und mit
> bspw or_reduce immer den gesamten vector verdödeln.
> 
http://electronics.stackexchange.com/questions/85922/vhdl-or-ing-bits-of-a-vector-together

ich hab' mal wieder nicht verstanden, warum das or_reduce im Link so 
aussieht, wie's aussieht. Erscheint mir viel zu kompliziert, 
letztendlich ist das or_reduce() ja nichts anderes als ein Vergleich mit 
(others => '0):
1
function or_reduce(V : std_logic_vector) return std_ulogic is
2
    constant cmp : std_logic_vector(V'range) := (others => '0');
3
begin
4
    if cmp = V then
5
        return '0';
6
    else
7
        return '1';
8
    end if;
9
end function or_reduce;
10
    
11
?

von René D. (Firma: www.dossmatik.de) (dose)


Lesenswert?

Ich stand vor dem gleichen Problem und kam zu dem Ergebnis:
 Tristate gibt es nicht und inout ist unbrauchbar.

Es gibt einen Busmaster und der hat die Kontrolle über den Bus.
Diese Busmaster gibt das Handshaking aus mit welchen Slave komuniziert 
wird.
Meine Definition habe ich sogar niedergeschrieben und komme damit sehr 
gut klar.

http://www.dossmatik.de/mais/bus_spec.pdf
Alle Signalnamen fangen mit B für Bus an, erhöht die Lesbarkeit des 
Codes.

Die Daten vom Master zum Slave heißen BWDATA. (W steht für write)

Jetzt die eigentliche Antwort zu deiner Urfrage:
Die Daten vom Slave zum Master wird über eine eigene Datenleitung vom 
Slave zum Master übertragen. Bei mir heißt diese Leitung "BRDATA". R für 
read.

Alle Daten habe ich je nach Datenrichtung in je ein Record 
zusammengefasst und binde diese mit einem package in meinem Code ein. 
Das erspart Schreibarbeit und macht die Sache sehr übersichtlich. Nur 
BCLK habe ich nicht mit in das Record gepackt. Da habe ich die Erfahrung 
gemacht der Fitter hat kommt zu besseren Ergebnissen.

Problem tauchen erst wirder bei mehreren Busmastern aus. Das habe ich 
noch nicht gebraucht.

von bitwurschtler (Gast)


Lesenswert?

Markus F. schrieb:
> Erscheint mir viel zu kompliziert,
> letztendlich ist das or_reduce() ja nichts anderes als ein Vergleich mit
> (others => '0):

Weil ein vergleich type boolean liefert, aber ein Or-Gatter Typ 
Standard_ulogic o.ä liefert resp. liefern muß?!.

Damit auch solche Fälle wie mehrere Gatterausgänge kurzgeschlossen 
abgefangen werden können. In echt, gibt es halt mehr Zustände als true 
und false, da gibt es noch die Untermenge "verboten".

von Strubi (Gast)


Lesenswert?

Moin,

guck mal in 
http://www.section5.ch/downloads/masocist-opensource-v0.10beta_eval.tgz, 
gen/soc_mmr_perio.vhdl.

Da ist das mit einem Wishbone-Interface implementiert, allerdings wird 
der ganze ACK-Krempel für die einfache Ansteuerung der Peripherie nicht 
benötigt.
In dieser Konfig ist allerdings Verstopfung bei viel Peripherie 
vorprogrammiert (da keine Delays).
Wenn nicht unbedingt nötig, würde ich den Wishbone-Overhead nicht bis zu 
den untersten Core-Instanzen durchziehen, jeder überflüssige MUX macht 
Aua.

Dein sekundärer Master klingt nach einem DMA-Controller. Beim DP-RAM 
würde ich den einfach durch die Hintertür mit einem zweiten dedizierten 
Bus aufsetzen, komplett an der top level Arbitrierung vorbei. So machen 
es einige DSP-Architekturen.

von S. R. (svenska)


Lesenswert?

Markus F. schrieb:
> War das deine Frage?

Ja.

C. A. Rotwang schrieb:
> Alternativ kann man alle von den Slaves weggehneden signale ver-ODER-n,
> das ist einfacher als der beschriebene Muxer für die ACK.

Das ist mir beim Schreiben auch aufgefallen. Klingt für die 
Datenleitungen (N x 32 Bit) aber auch aufwändig...

Lothar M. schrieb:
> Über einen übergeorneten Arbiter. Denn dein "Master-Slave-Konzept" geht
> offenbar davon aus, dass auch die Slaves von sich aus was senden
> könnten. Das ist dann eben kein Master-Slave mehr, sondern ein
> Multimaster...

Nein, der Master treibt den Request (R/W), auf den der Slave antwortet. 
Slaves können selbst keine Requests auslösen. Es gibt allerdings zwei 
Master, s.u.

Klakx schrieb:
> Warum nicht ein bestehendes Bussystem nehmen?

Das hatte sich so ergeben. Ursprünglich bestand das Konzept aus 3 
Blöcken (2 Master und ein DP-RAM), die einfach miteinander verklebt 
wurden. Das fasert gerade auf, weil da zusätzliche Peripherie rein soll.

Strubi schrieb:
> Dein sekundärer Master klingt nach einem DMA-Controller. Beim DP-RAM
> würde ich den einfach durch die Hintertür mit einem zweiten dedizierten
> Bus aufsetzen, komplett an der top level Arbitrierung vorbei. So machen
> es einige DSP-Architekturen.

Ist ein NoC-Interface.

Ja, für den BRAM sind zwei Master kein Problem (Adresskonflikte kann ich 
vermeiden), allerdings sollen beide Master auch auf die gleiche 
Peripherie zugreifen können. Ich wollte vermeiden, an mehreren Stellen 
die RAM-Größe festlegen zu müssen.

Das wird einfach etwas haarig für meine Anfängerkenntnisse.

René D. schrieb:
> Ich stand vor dem gleichen Problem und kam zu dem Ergebnis:
> http://www.dossmatik.de/mais/bus_spec.pdf

Hmm. Im Prinzip so ähnlich wie mein Entwurf, nur etwas komplexer und 
dein Master dekodiert die Adressräume zentral. Wie schließt du die 
SPB_out-Records der einzelnen Blöcke zusammen? Über einen Muxer mit den 
Select-Signalen?

Das scheint aber der sinnvollste Weg für mich zu sein.

von Strubi (Gast)


Lesenswert?

S. R. schrieb:
> Ja, für den BRAM sind zwei Master kein Problem (Adresskonflikte kann ich
> vermeiden), allerdings sollen beide Master auch auf die gleiche
> Peripherie zugreifen können. Ich wollte vermeiden, an mehreren Stellen
> die RAM-Größe festlegen zu müssen.

Wenn deine beiden Master CPUs sind, die 'stall'en können, würde ich 
konkurrierende Zugriffe auf die Peripherie nach Möglichkeit vermeiden. 
Das macht auch bei gut getesteten Architekturen teils echte Probleme. 
Lieber nen einigermassen asynchronen Transaction-Layer einbauen.
Da gibt es übrigens einige nette Konzepte aus den 90ern, u.a. die 
MUSIC-Architektur von der ETH.

Bei so komplexen Sachen empfiehlt sich allenfalls der IP-XACT Ansatz, 
die Komponenten zu generieren, aber da müsstest du ev. etwas Vorlaufzeit 
einplanen um die Tools in den Griff zu kriegen. Dafür sparst du viel 
Konfigurations-Gefuddel und VHDL-bedingten Overhead.

von S. R. (svenska)


Lesenswert?

Strubi schrieb:
> Wenn deine beiden Master CPUs sind, die 'stall'en können, würde ich
> konkurrierende Zugriffe auf die Peripherie nach Möglichkeit vermeiden.

Einer der Master ist eine CPU, der andere Master ist ein NoC-Interface. 
Fürs Debugging ist es äußerst nützlich, wenn ich die Peripherie auch von 
außen konfigurieren (oder zumindest reingucken) kann. Die CPU darf 
währenddessen gerne stallen.

Ich werde wohl einen Arbitrator für Peripheriezugriffe bauen, der die 
Peripherieadressen zentral dekodiert und verteilt, und zwei 
Direktzugriffe in den RAM legen.

Danke für die Ansätze.

von Welt (Gast)


Lesenswert?

Lothar M. schrieb:
> Seit der Jahrtausendwende nicht mehr. Alle Busse müssen zu Multiplexern
> aufgelöst werden.
Gefühlt ist das schon 50 Jahre nicht mehr der Fall :-)

von René D. (Firma: www.dossmatik.de) (dose)


Lesenswert?

://www.dossmatik.de/mais/bus_spec.pdf
>
> Hmm. Im Prinzip so ähnlich wie mein Entwurf, nur etwas komplexer und
> dein Master dekodiert die Adressräume zentral. Wie schließt du die
> SPB_out-Records der einzelnen Blöcke zusammen? Über einen Muxer mit den
> Select-Signalen?
>

Ja mit einem Muxer erschlagen, der sehr Pflegeleicht ist.
1
---BUS multiplexer  
2
    BBUS_out <= slave(0) when BSEL(0)='1' else  --DRAM
3
    slave(1)             when BSEL(2)='1' else  --UART
4
    slave(2);   --Bus Dummy

Für die Selektleitungen nutze ich die Adressbereiche und habe hier ein 
hex zu N Dekoder hinterlegt. Welche select Leitung der Slave nutzt gebe 
ich der Componente als generic mit.
1
  --SLAVE 1 -- UART
2
  HB_UART : SPB_UART  generic map(
3
    sim            => sim,
4
    BSEL           => 2,
5
  baudrate       => 115200,
6
    clk_freq       => board_clk_frq)
7
8
  port map(
9
    BCLK          => board_clk,
10
    BRESET        => BRESET,
11
    BBUS_in       => BBUS_in,
12
    BBUS_out      => slave(1),
13
14
    uart_irq      => IRQ_UART,
15
    rx            => rx,
16
    tx            => tx);

Der Code ist aus der Mais CPU.
http://www.dossmatik.de/mais-cpu.html

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.