Hallo,
habe derzeit ein Design mit Registern, die über einen rein internen
Tristate bus gelesen werden.
Das sieht so aus:
(Din und Dout sind jeweils 32 Bit breit)
1
goutputbit:foriinReg.lowertoReg.uppergenerate
2
Dout(i)<=Din(i)whenReg.Adr=Adrelse'Z';
3
endgenerate;
Von diesen Registern kann es mehrere pro 32 Bit geben und insgesamt sind
es mehrere hundert im gesamten Design, verteilt über viele Hierarchien.
Gebaut werden soll hier halt ein Wired-Or, das durchgängig entweder 0
oder 1 liefert für nicht definierte Bits/Adressen.
Ob 0 oder 1 ist mir egal, soll nur konsistent sein.
Timing-technisch ist das gar kein Problem, für die Simulation und die
Altera/Intel und Synplify Synthese auch nicht.
Vivado hingegen hat damit ein starkes Problem:
- befindet sich Dout in einem Record, dann baut er den Bus manchmal so
das dieser immer nur 0 liefert, egal wo man liest
- ist der Bus auf dem Toplevel verfügbar, dann baut er den Bus manchmal
so das dieser immer nur 0 liefert, egal wo man liest
- es gibt unzählige Warnungsmeldungen
Mit alle dem konnte ich noch irgendwie leben. Seit heute jedoch läuft
die Synthese gar nicht mehr durch: Endlosschleife oder Crash.
Deshalb: eine neue Lösung muss her.
Derzeit fällt mir nur ein jedes Register von Hand pro Entity zu
verodern.
Das ist so hässlich und fehleranfällig, das ich wohl lieber eine
automatische Konvertierung der Sourcefiles extra für Vivado bauen würde,
eine Art Präprozessor. Spaß macht das aber bestimmt auch nicht.
Hat jemand eine bessere Idee wie das funktionieren kann?
Wie löst ihr das?
Robert P. schrieb:> Wie löst ihr das?
On-chip-bus. Da gibt es diverse zum Auswählen, die von verschiedenen
Ecken/Firmen herkommen. Unsere Firma hat noch einen eigenen Bus
erfunden, den wir verwenden "dürfen". Vielleicht können wir das in
Zukunft ändern.
Naja, für sowas simples wie einzelne Register und wired-or will ich mir
eigentlich nicht AXI oder ganz allgemein fremde IP quer durchs FPGAs
legen.
Habe jetzt doch erstmal alles auf Wired-or händisch umgebaut. Bläht die
Module nicht so immens auf und die Synthese funktioniert wieder ohne
Warnungen.
Zwar crasht Vivado immer noch, was aber wohl doch an etwas anderem
liegt.
Zumindest kann ich jetzt "Flatten Design" abschalten und damit die
Designphase überspringen welche crasht, was mit Tristate-Bus nicht geht,
weil es sonst harte multiple-drivers Fehler gibt.
für einen internen Tristate-Bus sollte es schon einen ganz triftigen
Grund geben. Falls dieser überhaupt implementierbar ist im FPGA, was ich
stark bezweifle. Selbst mein alter Prof an der Uni hielt schon davon
nichts. In der Regel eigentlich immer eine mittelgroße Katastrophe.
Wired-OR Bus kann man machen. Das kenne ich auch für kleine Designs. Der
Spaß hört dann auf, wenn der Bus zu groß wird. Ein APB oder Wishbone
sind ein netter Zwischenschritt. Damit sind deine Cores auch wesentlich
wiederverwendbarer. Ein Hauptgrund für einen Standard.
Danke erstmal!
Ja, der interne TriStateBus ist nicht implementierbar, zumindest die
Synthesewerkzeuge die ich bisher verwendet habe (Quartus und Synplify
Pro) bauen daraus aber genau das was man haben will. Scheint wohl also
nicht völlig abstrus zu sein.
Mein Hauptanliegen ist wirklich die Lesbarkeit und Wartbarkeit. Zudem
möchte ich es gern kompakt haben.
Deswegen will ich da auch ungern Wishbone/AXI verwenden, das wird für
diese Anzahl an Registern ja nur noch aufwändiger und umständlicher.
Soweit ich das weiß(kann mich irren, habe bisher nur AXI rudimentär
verwendet) hätten die beide auch große Probleme mit Registern die auf
der gleichen Adresse liegen, aber unterschiedliche Bits aus dem 32 Bit
Datenbus bedienen und in völlig verschiedenen Entities zu finden sind.
Bevor Fragen aufkommen: die Registerbeschreibung ist fix vorgegeben,
d.h. ich kann das nicht einfach "schöner" anordnen.
Meine aktuelle Beschreibung braucht:
- einen Eintrag in der Portliste: ein Inout Signal bei dem im Record
alles drin ist: datain, dataout, adresse, byteenable, RnW, enable, done
- eine Zeile für jedes Register: eine Instanzierung der Registerentity
mit Clk, dem Bus, und den 2 Datenports. Über ein Generic wird angegeben
welches Register.
Beispiel:
Das finde ich halt persönlich sehr elegant und gut verständlich und
wartbar.
Es scheint aber so das es wohl keine Alternative gibt, die eine ähnlich
kompakte Schreibweise ermöglicht und nur "Basisfunktionen" von VHDL
benutzt UND von allen Synthesetools beherrscht wird.
Robert P. schrieb:> Mein Hauptanliegen ist wirklich die Lesbarkeit und Wartbarkeit.
Dann würde ich mir keinen Tristate-Bus mit inout-Signalen antuen.
Zeig mal ein vollständiges Beispiel mit entity+architecture und wenn
noch ein Submodul aufgerufen wird, dann das gleiche dazu.
Robert P. schrieb:> Soweit ich das weiß(kann mich irren, habe bisher nur AXI rudimentär> verwendet) hätten die beide auch große Probleme mit Registern die auf> der gleichen Adresse liegen, aber unterschiedliche Bits aus dem 32 Bit> Datenbus bedienen und in völlig verschiedenen Entities zu finden sind.
Am Ende willst du doch eine Registermap als Komponente. Die kann man für
jeden x-beliebigen Bus schreiben. Die internen Interface-Signale können
dann auch an andere Module gehen.
Klar geben viele Interfaces byte-Schreibzugriffe vor. Das hat aber den
Vorteil, dass der der die Software schreibt noch durchsieht. Wenn mich
das stört dann lege ich die zwei Register nicht auf die gleiche Adresse.
Richtig wartbar wird es, wenn dir ein Skript das VHDL-Modul schreibt
(..und gleich den C-Header, die Doku und das Package für den Test).
Elegant ist es auch, wenn die Tools dich nicht mit Warnings überhäufen.
Hier aus einem fertigen Projekt.
Busbeschreibung und generisches Registermodul:
https://github.com/MiSTer-devel/GBA_MiSTer/blob/master/rtl/proc_bus_gba.vhd
Registerbeschreibungs-Package:
https://github.com/MiSTer-devel/GBA_MiSTer/blob/master/rtl/reggba_keypad.vhd
Entity + Architecture in welchem diese 2 Register verwendet sind:
https://github.com/MiSTer-devel/GBA_MiSTer/blob/master/rtl/gba_joypad.vhd
Insgesamt sind ~300 solche Register im Design verteilt, gebaut von
Quartus in einem Cyclone 4/5 und betrieben bei 100 Mhz ohne
Delay/waitcycles.
Habe für diese Registerbeschreibungen bereits Skripte die mir aus der
VHDL Registerbeschreibung dann Code für C++, C# und Lua erzeugen.
Nicht falsch verstehen, ich bin durchaus offen für Veränderung, deswegen
schreibe ich hier ja.
Vielleicht fehlt mir einfach die Vorstellungskraft wie sowas mit
Wishbone/Axi/etc aussehen könnte und trotzdem übersichtlich wird.
Kenne die beide aus allen Beispielen immer nur als recht lange Liste an
Signalen/Ports die überall durchgeroutet werden müssen.
Robert P. schrieb:> Kenne die beide aus allen Beispielen immer nur als recht lange Liste an> Signalen/Ports die überall durchgeroutet werden müssen.
Weil die alle, aus mir völlig unverständlichen Gründen, offensichtlich
noch nie was von Records gehört haben. Gerade ein Bus bietet sich ja
sowas von an, in Records gepackt zu werden...
Christoph Z. schrieb:> Weil die alle, aus mir völlig unverständlichen Gründen,> offensichtlich noch nie was von Records gehört haben.
Man braucht aber immer einen Record pro Richtung, oder irre ich mich?
Oder kann ich alle Bussignale in einen Record packen (sowohl
read/write+data und ack)?
Genau das habe ich ja in meiner Variante getan: alles in einem Record
und an den Ports Inout.
VHDL gibt das her, weil intern einfach jedes Element seperat aufgelöst
werden kann.
Klappt leider nicht mit Vivado, bzw. nicht immer. Bei dem oben
verlinkten Design z.b. für genau 3(!) der über 300 Register nicht, da
baut Vivado einfach mal das immer eine 0 zurückgelesen wird. Andere
Register in der gleichen Entity hingegen sind zugreifbar. Trennt man die
Signale nach In und Out auf klappt es.
Bei sowas reagiere ich leider sehr allergisch. Ich mag nicht wenn die
Synthese etwas anderes baut als das was die Simulation macht.
Deswegen bin ich jetzt auf wired-or und 2 Ports gegangen: einen
In-Record für die Richtung Master->Register(Adr, RnW, Ena, ByteEna, Din)
und einen 32Bit-Out-SLV für die Rückrichtung.
Die Schreibarbeit ist da nicht soooo viel Größer und ich habe den
Rückweg so geschrieben wie Supachris hier bschrieben hat:
Beitrag "Ausgangssignale mehrerer Blöcke OR'en"
Beispiel:
Damit habe ich in meiner Register Portliste nur einen Eintrag mehr: die
Rückgabe in ein Array.
Das Array wird automatisch ver-odert ohne das ich den process jemals
wieder anfassen muss.
Wenn ich ein neues Register einfüge muss ich damit nur das Array 1
größer machen. Vergesse ich das oder weise die Daten dem gleichen
Arrayindex zu gibt es einen harten Fehler, was gut ist, weil man so
nichts übersehen kann.
Das einzige was hier noch marginal stört, ist das man die Zahl selbst
hochzählen muss. Damit kann ich aber leben.
hirq:std_logic_vector(NAHBIRQ-1downto0);-- interrupt bus
21
hconfig:ahb_config_type;-- memory access reg.
22
hindex:integerrange0toNAHBSLV-1;-- diagnostic use only
23
endrecord;
Xilinx hat es leider nicht geschafft, das geschickt ins Vivado
einzubauen. Da darf man sich dann für AXI wieder mit fehlerträchtigen
Listen rumschlagen...
Das sieht doch für Wishbone schön übersichtlich aus.
Hast du eventuell ein Beispiel wie das dat und ack aus dem
wishbone_bus_out dann für mehrere Teilnehmer verbunden wird?
Robert P. schrieb:> Bei sowas reagiere ich leider sehr allergisch. Ich mag nicht wenn die> Synthese etwas anderes baut als das was die Simulation macht.
Dein Denkfehler ist hier, dass du in der Simulation ein Bauteilverhalten
simulierst, welches zwar von echten Treibern geleistet werden kann, in
FPGAs aber nur in den IO-Zellen, weil dort eben diese parallelen Input
und Output Pfade existieren und physikalsich verbunden sind.
Daraus kann man nicht ableiten, dass es ein Problem ist, wenn das innen
im FPGA nicht geht. Die Mehrfachverwendung von records, die BIDIR sind
und sowohl Port- als auch IO-Port-Beschreibungen sein sollen, ist also
das Problem. Definiere mal ein sauberes Package für das wired OR und es
wird klappen.
Ich rate auch allgemein davon ab, solche Doppelkonstrukte zu verwenden,
die dann der Compiler erst wieder in Machbares übersetzen soll. ES ist
einfach unsinnig, nur wegen Beschreibungsfaulheit auch
Sparbeschreibungen mit scheinbaren bidir-Signalen zu setzen (ob records
oder nicht ist dabei auch egal) und dann zu hoffen, dass dort was
rauskommen kann.
AXI und andere Busse sind SIGNALBUSSE und keine Physikalischen Busse.
Die haben nichts bidirektionales an sich, weil eine Information immer
nur in eine Richtung fliessen kann.
Xilinx ist aber selber Schuld, weil die hauptsächlich diejenigen sind,
die Physik ins design schleppen, mit angeblichen lo-Aktiven Signalen für
resets und Allemmöglichen.
Das hat mir Denkfehler nichts zu tun. Ich schrieb ja selbst das ich die
Konstrukte loswerden will ohne Übersichtlichkeit aufzugeben und mögliche
(menschliche) Fehlerquellen einzubauen.
Meiner Ansicht nach spricht nichts dagegen, das ich diese Dinge(Bidir
Records und interne TriState Busse die automatisch zu wired-or
degradieren) mittlerweile über 10 Jahre problemfrei in Altera und Xilinx
Designs(mit Synplify als Synthesewerkzeug) verwendet habe.
Warum soll man etwas aufgeben, das alle Tools die man nutzt beherschen?
Dann kommt der Nächste und sagt "Initialwerte kann ja nicht jedes
Tool/FPGA, nimm sowas nicht".
Wenn dann ein Tool es nicht beherscht muss man halt eine Lösung finden.
Aber doch bitte mit vertretbaren Aufwand und in sinnvoller Weise.
Ich habe auch prinzipiell kein Problem damit eine Lösung zu benutzen die
noch kompatibler ist, wenn der Mehraufwand und die Nachteile in einem
vernünftigen Rahmen bleiben.
Ich sehe aber nicht, warum ich mich absichtlich geißeln muss, nur um den
Tools zu gefallen. Das mache ich nur soweit, wie ich gezwungen bin.
Es ist ja nicht so das ich einen realen Vorteil davon habe, sondern im
besten Fall wird mit der alternativen Beschreibung exakt die gleiche
Logik gebaut.
Wishbone hätte ja zumindest noch den Vorteil geläufiger zu sein, das
wäre mir zumindest noch etwas Wert.
Die händische Bschreibung als wired-or und Auftrennen in mehrere Record
hingegen ist wirklich NUR für das Tool, für mich als denjenigen der die
Logik beschreiben muss ergeben sich daraus nur Nachteile.
Robert P. schrieb:> Hat jemand eine bessere Idee wie das funktionieren kann?> Wie löst ihr das?
Ich generiere mir aus einer XML-Geraetebeschreibung die Decoder fuer die
Memory-Mapped-Register (plus Header, Registertabellen usw, wie nach
Methode 'Klakx' oben).
Mit wired-or erzeugst du nur eine Menge LUTs und hast ev. irgendwann
einen Flaschenhals.
Machen die 'Grossen' mit IP-XACT aehnlich, nur von hinten durch die
Brust, indem noch eine weitere Register-Language erfunden wurde..
Und inout in die Tiefen zu routen kann bei einigen FPGA-Tools echt ueble
obskure Fehler provozieren. Nicht tun :-).
Das es weniger Flaschenhals als Wired-or haben soll, damit hast du mich
jetzt neugierig gemacht.
Wie kommt das? 1 bis mehrere Takte Delay?
Hast du eventuell mal irgendein Beispiel wo man das sieht?
Mir geht es dabei vor allem um so einen generierten Decoder.
Das wäre echt nett mal etwas Code dazu zu sehen.
Robert P. schrieb:> Das es weniger Flaschenhals als Wired-or haben soll, damit hast du mich> jetzt neugierig gemacht.> Wie kommt das? 1 bis mehrere Takte Delay?
Ja, beim Lesen kommst du daran wohl nicht vorbei, beim Schreiben kann
man's notfalls (bei riesigen Maps) pipelinen. Der Flaschenhals tritt im
Bus-Generator ebenfalls auf, wenn man den Delay abschaltet (dann hast du
wieder Multiplexer-Verstopfung).
Den ganzen Code-Moloch dazu gibt's hier:
https://github.com/hackfin/MaSoCist
Achtung, Linux-lastig.
Die Peripherie musst du allerdings erzeugen, d.h. das Ding im Container
(siehe Readme) einmal bauen. Dann liegen in
`~/src/masocist-opensource/gen` o.ae. die erzeugten VHDL-Decoder. Die
Gesamtstruktur laesst sich dann am besten aus der Wave-Trace der
Simulation per GTKWave rauslesen.
Um die XML-Maps zu editieren macht der 'xxe' als grafischer Editor Sinn,
siehe auch Screenshot hier:
https://hackaday.io/project/162259-netpp-node (das ist die 'reale'
Hardware-Umsetzung von obigen SoC).
Habe mir mal das anhand des generierten "decode_uart" angesehen und über
die Instanzen verfolgt.
Verstehe damit auch warum man das dann erzeugen muss. Diese Struktur
lässt sich fehlerfrei kaum noch selbst hinschreiben.
Ehrlich gesagt ist mir das aber viel zu viel Code, weil mein
vordergründiges Problem, mehrere mögliche Signale auf möglichst
kompaktem Weg durch das System zu bekommen, damit nicht erfüllt wird:
Alle Multiplexer sind in ihrer Komplettheit abgebildet und
ausgeschrieben und jedes Register steht ausgeschrieben mit dem
kompletten Buszugriff im Code.
Klar, kann man ja alles generieren und verschwindet irgendwo in
niedrigeren Hierarchieebenen, ist mir am Ende aber zu umständlich für
das was es leisten soll.
Nicht falsch verstehen, das funktioniert für deinen Anwendungsfall
sicher gut, für mich passt es leider nicht.
Auf jeden Fall vielen Dank, es war sehr hilfreich mal einen anderen
Lösungsvorschlag zu sehen!
Nja, ich habe noch keine kompaktere (explizite/debugbare/portable)
Variante gesehen, die auf allen mir bekannten Tools von A/I/L/X/S und
yosys genau das macht, was sie soll und einem nicht um die Ohren fliegt.
Kompakter geht es nur noch in Python/MyHDL, intern wird aber wieder
dasselbe generiert.
Also, der Apfel bleibt sauer :-) Irgend einen Busdecoder wirst du
stricken muessen, den die Tools richtig umsetzen. Tristate-Hacks mit
komplizierter Treiberstruktur sind aus einer langen Liste von Gruenden
no-go und viel Schreibarbeit wird irgendwann zum Verwaltungsmoloch. Da
spare ich mir lieber Zeit mit einem 'make all'.
Am Ende führen viele Wege wohl zum Ergebnis.
Die oben erwähnte Variante mit wired-or dürfte jetzt wohl auch auf allen
Tools funktionieren, da ist ja nichts ungewöhnliches mehr drin (kein
Bidir, kein TriState)
Probiert habe ich es bisher aber erst mit Vivado und Modelsim.
Mir gings ja hier im Thread auch weniger um den Weg von der
Registerbeschreibung zur Dekodierung, sondern um den Rückweg der Daten
von mehreren Registern zum Master.
Scheinbar gibt es aber keinen Weg in VHDL der so kompakt wie Tristate
ist, jedoch von allen Tools akzeptiert wird. Das war ja übersprünglich
meine Hoffnung.
Das "multiple drivers" Problem bei der Nutzung von nur einer Leitung
lässt sich wohl einfach nicht umgehen.
Robert P. schrieb:> Scheinbar gibt es aber keinen Weg in VHDL der so kompakt wie> Tristate ist, jedoch von allen Tools akzeptiert wird. Das war> ja übersprünglich meine Hoffnung.
Da bin ich vor einigen Jahren auch auf die Nase gefallen mit der
Hoffnung.
Das Argument "dann generiert man das halt extern" ist ... naja,
eigentlich ein gutes Zeichen, dass die Sprache doch irgendwo ein
bisschen schlecht riecht.
Robert P. schrieb:> Am Ende führen viele Wege wohl zum Ergebnis.>
Siehe nochmal oben, Kommentar von Klakx. IMHO gibt es fuer Busdekoder
nicht viele praktikable Wege, die skalierbar und vernuenftig debugbar,
geschweige verifizierbar bleiben.
Wired-OR kann man bei einfachen Controllern o.ae. machen, aber es
skaliert schlecht. 300 Register willst du so implementieren und dann
allenfalls debuggen?
> Scheinbar gibt es aber keinen Weg in VHDL der so kompakt wie Tristate> ist, jedoch von allen Tools akzeptiert wird. Das war ja übersprünglich> meine Hoffnung.>
Es gibt einen ziemlich triftigen Hauptgrund, warum das mit Tristate
Murks ist:
Man kann recht leicht kombinatorische Logik erzeugen, die nicht nach
Treiber und Empfaenger sauber aufloesbar ist ('resolving').
Der Simulator arbeitet ereignisbasiert, die klassischen Synthesizer
nicht: sie analysieren die Code-Syntax und versuchen, die Konstrukte
aufzuloesen.
Da gibt es uneindeutige Szenarien, die deswegen zu Unterschieden bei
Sim/Synth fuehren koennen..Dauerklassiker seit Isim, Season two mit
Vivado..
GHDL wuerde dir einiges, was bei Isim 'funktioniert' mit einem 'X'
(undefiniert) markieren, und du kannst dann in der Trace die
Fehlerquelle suchen.
Deswegen sind in vielen Design-Regeln solche Konstrukte komplett
verboten. Man schiesst sich damit sinnlos ins Knie, und kann das Design,
wenn's mal soweit kommt, nicht verifizieren.
Drum fuehren manche HDL ein explizites `TristateSignal` ein, die einen
klar definierten 'Besitzer' (Master) haben, intern darf kein anderer
Teilhaber treiben. Und auch dann muss man's sparsam verwenden, sonst
wird die Simulation fuerchterlich lahm (aufgrund vieler
Ereignisquellen).
Aber nuja, ausprobieren.
Martin S. schrieb:> 300 Register willst du so implementieren und dann> allenfalls debuggen
Habe ich ja schon gemacht und es ist mMn sehr übersichtlich, Design ist
oben verlinkt und läuft.
Die Register sind übersichtlich im Package definiert und werden in einem
Einzeiler instantiiert.
Weiß auch nicht was daran zu debuggen wäre...kann jedes Register in
Simulation und auf Hardware per GUI oder Script zum testen lesen und
schreiben. Was will man da noch debuggen? Mehr sollen die doch gar nicht
können...
Ist dort noch als Tristate beschrieben, sieht aber mit Wired-or nicht
groß anders aus, kommt hauptsächlich der Process für das OR einmal pro
Entity dazu.
Martin S. schrieb:> GHDL wuerde dir einiges, was bei Isim 'funktioniert' mit einem 'X'> (undefiniert) markieren, und du kannst dann in der Trace die> Fehlerquelle suchen.
Kann ich nicht sagen, arbeite aktuell weder mit Isim noch GHDL, nur
Modelsim.
Wenn ich dort ein X sehe, dann frage ich nach "drivers signalname"
und bekomme gelistet was da gleichzeitig treibt.
Bei dem Tristate Bus den ich bisher benutzt habe kann das aber nicht
passieren, weil alle Zugriffe auf den Inhalt des Busses den generischen
Entities überlassen sind. Niemand sonst fasst das Dout an. Damit sind
doppelte Treiber auf 2 Register mit gleicher Adresse beschränkt.
Dafür gibts ein Script das einen Sanity Check für die Register macht.
Ich will ja auch gar nicht bei Tristate bleiben und mir ist bewusst das
es ungünstig ist, sonst gäbe es den Thread hier ja gar nicht.
Was mir aber immer noch nicht gefällt sind die "Krücken" um genau das
gleiche Ergebnis zu bekommen.
Im Prinzip ist das alles nur umständliche Syntax um es der Synthese
irgendwie klar zu machen.
Zum Vergleich: bei der gleichen Implementierung in C schreibe ich
einfach von x-beliebigen Positionen im Code in ein globales Array per
Adresse.
Ein vergleichbares Konzept gibt VHDL leider nur schwer her, obwohl die
Darstellung aller Register als großen, in Register implementierten,
Speicherbereich mit einem Port pro FF ganz gut passen würde.
Sowas würde man ja höchstens als Signalarray in einem Package schaffen
und das macht bei der Synthese sicher keine Freude mehr...
Robert P. schrieb:> kommt hauptsächlich der Process für das OR einmal pro Entity dazu.
Wozu ein Prozess? Das ist doch Kombinatorik, das geht Concurrent... ;-)
Martin S. schrieb:>> Scheinbar gibt es aber keinen Weg in VHDL der so kompakt wie Tristate>> ist, jedoch von allen Tools akzeptiert wird. Das war ja übersprünglich>> meine Hoffnung.> Es gibt einen ziemlich triftigen Hauptgrund, warum das mit Tristate> Murks ist:
Es gibt kein Tristate imFPGA. Das ist ganz einfach so. Also kann
der Synthesizer die Tristate-Beschreibung nicht so wie beschrieben
umsetzen. Er warnt völig zu Recht, denn er weiß ja nicht, dass das der
gewollte Beschreibungsstil ist. Deshalb ist es extrem unsauber (und im
Prinzip ledigleich der seit 10 Jahren angewöhnten Schreibfaulheit
entgegenkommend), den Synthesizer den Busmultiplexer implizit aus den
lokalen Adressdekodern, die den Tristate steuern, herausklamüsern zu
lassen und die entsprechenden Warnungen in den Wind zu schlagen.
Robert P. schrieb:> Ist dort noch als Tristate beschrieben, sieht aber mit Wired-or nicht> groß anders aus
Es gibt auch kein Wired-Or im altbekannten Sinne, dass alle Treiber von
der HIGH-Side auf eine einzige Leitung treiben, und der LOW-Pegel durch
einen Pulldown erreicht wird:
https://de.wikipedia.org/wiki/Wired-OR-Verkn%C3%BCpfung
Letztlich ist so ein Wired-Or auch nur eine Verknüpfung von 'Z' und '1'.
Und das Thema 'Z' im FPGA ist ein paar Zeilen weiter oben beschrieben.
Ok, dann gibt es den Namen wohl auch für was anderes, war mir nicht
bekannt.
Ich verbinde hier nur '0' und '1' und kein 'z', von daher
unproblematisch.
Und ganz ehrlich, wenn es nur nach Synthesewarnungen geht muss ich noch
viel mehr umbauen.
Z.b. warnt mich Vivado bei jedem inferierten Dualport-Ram ich solle doch
bitte mit 2 Prozessen schreiben, sonst würde er wahrscheinlich kein
Blockram daraus machen.
Macht er aber trotzdem und auf 2 Prozesse baue ich sicher nicht um,
sonst kann ich das Modul nicht mehr simulieren, weil das Signal aus 2
Prozessen getrieben wird.
Derjenige, der ein komplexes Design ohne Vivado/Quartus Warnungen gebaut
bekommt, der werfe den ersten Stein...
Tut mir leid, aber der Umstieg von Quartus auf Vivado nervt echt.
Wahrscheinlich ist es umgedreht genauso schlimm, aber aufgrund der
Richtung muss jetzt Xilinx herhalten :)
Lothar, wenn du einen Vorschlag für Concurrent hast der ähnlich knapp
ist wie die Lösung von Supachris(siehe oben), nur her damit, das tausche
ich gerne aus.
Mir ist da noch nichts eingefallen.
Robert P. schrieb:> Derjenige, der ein komplexes Design ohne Vivado/Quartus Warnungen gebaut> bekommt, der werfe den ersten Stein...
Warst nicht du derjenige, der sich an diesen Warnungen stört und sie
loswerden will? Ich meinte, im ersten Post sowas gelesen zu haben...
;-)
> Lothar, wenn du einen Vorschlag für Concurrent hast der ähnlich knapp> ist wie die Lösung von Supachris(siehe oben), nur her damit, das tausche> ich gerne aus.
Sieh dir mal die Funktion or_reduce() aus der std_logic_misc an. Die
macht, was du dir unter einem Wired-Or vorstellst.
Soiehe dazu auch dort:
https://stackoverflow.com/questions/28973387/or-reduce-an-array-of-vectors
Lothar M. schrieb:> Es gibt kein Tristate im FPGA. Das ist ganz einfach so. Also kann> der Synthesizer die Tristate-Beschreibung nicht so wie beschrieben> umsetzen. Er warnt völig zu Recht, denn er weiß ja nicht, dass das der> gewollte Beschreibungsstil ist. Deshalb ist es extrem unsauber (und im
Dass der obige 'interne' Tristate emuliert wird, ist allen bereits klar.
Las sich vermutlich missverstaendlich.
Nebenbei: es gibt durchaus physikalisch-internen Tristate in einigen
gehaerteten Architekturen (z.B. die, die Rekonfiguration im laufenden
Betrieb machen). Aber verhaelt sich halt wie ein eigener Block.
Ansonsten gilt fuer Xilinx wohl, dass in der deren Synth-Engine (xst)
noch eine Menge haesslicher 'legacy' rumliegt (aus den Zeiten, wo
interne Tristate noch 'kompakter' waren als die heutigen Zellen).
Deswegen auch die Mismatches zwischen Simulation und der
Hardware-Emulation bei Isim/Vivado und dem Synthese-Ergebnis. Andere
Syns spucken Warnungen oder sogar Fehler aus.
GHDL setzt da streng die VHDL-Standards um, Isim hat Xilinx-spezifische
'Toleranzen'. Deswegen Stolperfalle. Wenn GHDL ein 'X' ausgibt, Isim
aber nicht, darf man GHDL glauben.
Ansonsten: die syn-engines verhalten sich bei sowas hoechst
unterschiedlich, xst kann gewisse loops eben wie genannt nicht aufloesen
und es kommt Mist hintenraus, die andere Toolchain generiert sinnlos
viele Muxer, um den Tristate komplett zu emulieren. In der
Post-synthesis-Verifikation gibt es natuerlich 'Z' dann nicht, das muss
man sich dann aus zwei Signalen wieder rekonstruieren.
Robert P. schrieb:> Derjenige, der ein komplexes Design ohne Vivado/Quartus Warnungen gebaut> bekommt, der werfe den ersten Stein...
Ich hatte mal so eine Anforderung fuer XST. Ja, macht keinen Spass. Aber
wie gesagt, in einen sauren Apfel musst du beissen. Entweder schreibst
du dir die Finger in VHDL wund (entweder konform nach Standard, oder
nach dem Willen deines Tools) oder generierst den Kram nach den
Designregeln (deines Tools). Mit MyHDL geht sowas einigermassen
portabel, oder du schreibst fuer jede Architektur in VHDL eine Variante.
Such dir's aus.
Lothar M. schrieb:> Sieh dir mal die Funktion or_reduce() aus der std_logic_misc an.
Das sieht gut aus, damit werde ich die Prozesse los und habe das
Verodern des kompletten Arrays in einer Zeile.
War davon ausgegangen du meinst eine "echte" concurrent Zuweisung, aber
so ist ja noch viel besser.
Ich denke mal ich werde dabei auch erstmal bleiben. Tristate weg, Bidir
weg und nicht zuviel Mehrarbeit. Das sollte so robust funktionieren.
Vielen Dank nochmal an alle Diskussionsteilnehmer!
Robert P. schrieb:> Lothar M. schrieb:>> Sieh dir mal die Funktion or_reduce() aus der std_logic_misc an.VHDL 2008 hat or_reduce() übrigens als unären Operator im Sprachstandard
(und braucht kein std_logic_misc mehr dazu):
nur leider, wie so oft, ist die Unterstützung dafür bei den
einschlägigen Tools meist - wenn überhaupt - höchst rudimentär. Der
Standard ist ja schliesslich erst zwölf Jahre alt, wie kann man da schon
Support erwarten?
Robert P. schrieb:> Zum Vergleich: bei der gleichen Implementierung in C schreibe ich> einfach von x-beliebigen Positionen im Code in ein globales Array per> Adresse.>> Ein vergleichbares Konzept gibt VHDL leider nur schwer her, obwohl die> Darstellung aller Register als großen, in Register implementierten,> Speicherbereich mit einem Port pro FF ganz gut passen würde.
Willkommen in der schönen neuen Zeit. Das was du hier gerade mit VHDL
lernst, wird dir auch in C zugute kommen, da nämlich dein C Beispiel
funktioniert, solange du kein Multithreading machst. Da aber alle
modernen Plattformen (Fernseher, Handy, PC, Frequenzumrichter,...) ihre
Leistung nur dank Multi-core Prozessoren erreichen, muss auch in C das
"multiple-drivers" Problem adressiert werden (Typischerweise mit
Semaphoren).
Das Äquivalent zu unserer Hardwaredenkweise hier (in so unabhängigen
Blöcken mit internen Daten und Zuständen) wird in der Software "Actor
based" Parallelisierung genannt.
Ach ja, hier geht es ja um Retrocomputing, da kommt das Problem erst
beim Nachbau einer Transputer-Workstation oder Cray zum Tragen ;-)
Christoph Z. schrieb:> da nämlich dein C Beispiel> funktioniert, solange du kein Multithreading machst
Korrektur: "solange du kein Multithreading auf diesem Array machst".
Solange nur ein Teilnehmer eine Zelle schreiben kann und beliebig viele
nur Lesen, sollte das klappen.(Außer vielleicht Cache Kohärenz, aber das
ist ein anderes Thema)
Bei den verwendeten Registern habe ich ja genau das:
Ein Readwrite Register kann nur vom Controller/Prozessor geschrieben
werden, jedoch sowohl vom verwendenden Modul und vom Prozessor gelesen.
Ein Readonly Register kann nur das verwendende Modul Schreiben.
Der "Computer" den ich aktuell nachbaue hat sogar 2 Prozessoren, ist
aber auch nicht mehr so ganz Retro(2004).
Dort wird es auch so gelöst: jedes Register hat genau einen Teilnehmer
der es beschreiben kann.
Einzige Außnahme sind spezielle IPC Register. Aber auch die sind nur
scheinbar von 2 Seiten zu schreiben, in Wirklichkeit gibt es diese
doppelt vorhanden und Schreib/Leseseite ist vertauscht.
Robert P. schrieb:> Einzige Außnahme sind spezielle IPC Register. Aber auch die sind nur> scheinbar von 2 Seiten zu schreiben, in Wirklichkeit gibt es diese> doppelt vorhanden und Schreib/Leseseite ist vertauscht.
Und die Konsistenz wird dann manuell hergestellt? Warum ist das kein
DP-BRAM?
Nicht manuell, die Logik stellt das sehr schön zur Verfügung.
1.Register: Prozessor A darf schreiben und sein Geschriebenes Lesen,
Prozessor B darf nur lesen.
2. Register: Prozessor B darf schreiben und sein Geschriebenes Lesen,
Prozessor A darf nur lesen.
Das ganze gibts dann auch nochmal als zwei 16 DWord große Fifos(Einer
darf nur Schreiben, einer nur Lesen) inklusive 2 aktivierbaren
Interrupts wenn Daten angekommen sind und/oder wenn die Gegenseite alles
abgeholt hat.