Es geht um die mehrfache Instanziierung eines softcore mit verschiedenen Programmen. Bei den softcores, mit denen ich bisher zu tun hatte (OpenRISC mor1kx, RISC-V neorv32) wird das Programm als VHDL-Konstante in einen BRAM initialisiert. Man kompiliert also die ganze uC-source und den Befehlsspeicher mit der Initialisierung. Von Haus aus ist es zumindest bei den zweien anscheinend nicht vorgesehen, mehrere Instanzen des uC mit verschiedenen Befehlsspeichern zu haben (siehe z.B. [1],[2]). Idealerweise müsste man theoretisch nur einmal die uC-source (für Sim [Modelsim] / Syn [Vivado]) kompilieren und mehrere Befehlsspeicher generisch einbinden. Meine Frage geht nun in die Richtung best practices, Anpassungen vorzunehmen, um mehrere softcore-Instanzen zu unterstützen. Bzw. eigentlich genauer: Wie kann ich möglichst aufwandsarm und sauber verschiedene Befehlsspeicher einbinden? Meine Lösungsansätze bisher gehen in drei Richtungen. ######### Zum einen wäre die Trennung über "namespaces", sprich man kompiliert jeweils die komplette uC-Source mit Befehlsspeicher in verschiedene libraries. Die sourcen muss man jeweils so umschreiben, dass z.B. statt "library neorv32" jeweils "library work" in den uC-sourcen verwendet wird und eine lib pro uC-Instanz zur Compilezeit festgelegt wird. Sim: Modelsim kommt damit klar; Syn: Vivado will nicht eine Datei selben Namens in verschiedene libraries packen(?) Vorteil: minimal invasiv bzgl. uC-source; Nachteil: man muss die uC-sourcen mehrmals in verschiedene libraries kompilieren ######### Eine andere Möglichkeit ist, den Befehlsspeicher halbwegs generisch umzuschreiben. Entweder über den HDL-Weg, dass verschiedene Befehlsspeicher bzw. VHDL-Konstanten inkludiert werden oder über den "make"-Weg, wo man vor Sim/Syn mehrere passende Dateien erzeugt und Ersetzungen vornimmt. HDL-Weg: zwar schöner, aber man muss die Änderungen dann immer wieder reinpatchen, wenn man sich Änderungen des softcore aus upstream holt; weiterhin müssen neben HDL tlw. auch die mitgelieferten Tools angepasst werden, die aus dem C-Kompilat den HDL-Befehlsspeicher erzeugen (oder das Resultat dieser Tools muss während des Bauprozesses nochmal nach-prozessiert werden) make-Weg: fricklig, aber man muss die sourcen nicht direkt anfassen; man bestimmt von extern, welche uC-Instanz welches Programm bekommt, was schön ist, da man extern ja auch erstmal den C-Compiler anwirft und den output dann irgendwohin zuordnet, an genau dieser einen Stelle im workflow und nicht verteilt über makefile und HDL ######### Für die Synthese habe ich den Weg, per Vivado-tcl-Befehlen den BRAM-Inhalt im Bitstream zu ändern. Dafür muss der Befehlsspeicher umgeschrieben werden, dass er nicht mehr inferiert wird, sondern per Primitiven instanziiert. Die Programmzuordnung für mehrere Instanzen würde damit funktionieren, eine Initialisierung per immer gleicher default-Konstante ist erstmal egal. Um dieses Prinzip für die Simulation zu übernehmen, bräuchte es dann aber einen dritten workflow (neben default HDL-Konstante und Vivado tcl), was ich unpraktisch finde. Den BRAM-Update-Weg würde ich in diesem Thread sogar explizit außen vor lassen, da der etwas per Technologie-Workflow speziell löst, was ich eigentlich per HDL allgemein lösen wollen würde. ######### Hat jemand Ideen, wie man die beschriebene mehrfache Instanziierung am besten macht? Vielleicht gibt es ja bei anderen softcores dafür schon gute Lösungen? Beispiel für neorv32: [1] https://github.com/stnolting/neorv32/blob/main/rtl/core/neorv32_application_image.vhd [2] https://github.com/stnolting/neorv32/blob/main/rtl/core/mem/neorv32_imem.default.vhd
Ich glaube ich verstehe deinen Aufbau nicht so ganz... Wie sieht denn dein Multicore-Setup generell aus? Also wie reden die einzelnene Kerne miteinander? Hängen die alle an einem Bus und haben Zugriff auf den gleichen Adressraum? Oder kommunizieren die über Mailboxen/FIFOs/Whatever und jeder Kern hat seinen eigenen Programmspeicher?
Lexxi schrieb: > Wie sieht denn > dein Multicore-Setup generell aus? Also wie reden die einzelnene Kerne > miteinander? Das sind mehrere unabhängige softcores in der FPGA fabric. Die können, müssen aber nicht miteinander reden. Bzgl. Befehls-/Datenspeicher und Adressraum hat jeder seinen eigenen. Die Anwendung/Architektur ist für mein Problem nicht unbedingt wichtig. Mir geht es darum, wie ich mehrere dieser softcores mit verschiedener SW vom workflow her am besten in einem FPGA-Design instanziiert kriege.
Dann würde ich die Kern-ID per Generic bis zum Programmspeicher herunterreichen und dann darüber die jeweile "Memory-Init-Datei" auswählen. Die einzelnen init-Files vorher per Skript erzeugen lassen und als progmem_core_xx.vhd (xx = Kern ID) in das Projekt einfügen. Dazu müsste man aber natürlich die Codebasis ändern... Ist vielleicht nicht die beste Idee, aber so würde ich das erstmal versuchen.
Jeder bekommt einen Bootloader und lädt sich aus einem Flash sein Programm. Der Bootloader erlaubt das erneute Flashen.
Das ist sogar noch besser. Man müsste dann nur einen Kommunikation zwischen den Kernen ermöglichen, damit mat den Zugriff aufs Flash koordinieren kann (egal ob es ein globales SPI Module gibt oder jeder Kern sein eigenes hat). Wenn Flash keine Option ist und du noch ordentlich viel Speicher im FPGA hast, könntest du auch alle Programme zu einem Paket kombinieren, in einem großen globalen Speicher ablegen und dann holt sich jeder Kern von da seinen Code - also kopiert den von da in den Kern-lokalen Speicher.
Softcore ist anlocken mit leckeren Erdbeeren. Hardcore ist mit der Peitsche. Das funktioniert nur bei nicht hormongesteuerten µC nicht. Lexxi schrieb: > Wenn Flash keine Option ist und du noch ordentlich viel Speicher im FPGA > hast, könntest du auch alle Programme zu einem Paket kombinieren, ... Du könntest das Programm komprimiert ablegen im Flash. Jeder Kern holt sich dann sein Programm entpackt in den RAM. Die Häufigkeit in den Flash zu schreiben ist bekanntlich limitiert.
Als klassische State of the Art gilt u.A. die BF561-Doppelkern-Architektur. Da sollte man sich möglichst nah dran orientieren, wenn man nicht in exotische Prozessorgefilde abdriften will. Die Frage ist immer, welcher Kern mit welchem Daten austauschen muss. Jeweils zwei können über Shared Dual-Port-RAM Daten austauschen, wenn Peripherie im Spiel ist, empfiehlt sich Autobuffer-DMA, wo nur noch Deskriptorenlisten unterhalten werden müssen. Dann muss man die FIFO-Bufferqueues nur noch richtig in der Software 'verzahnen'. Was die SW angeht: per Linkerscript alloziert man die gesamte Software inkl Libraries einfach in ein ELF-Binary, ein Loader muss dann die Adressbereiche in die entsprechenden CPU-Bänke mappen. Das ELF kannst du mit div. bestehenden Lösungen in VHDL für die einzelnen Bänke umwandeln, so dass ein vorinitialiertes TDP-Memory bei rauskommt (portabel). Ein CPU-Kern ist bei mir immer Master-Controller und lädt die anderen. Und um das alles auf Jahre hinweg robust unterhaltbar zu halten: Make-Lösung. Ist ein bisschen die Frage, wieviele CPU-Kerne du da brauchst, ob der neorv32 die Performance bringt oder das eher auf einen Flaschenhals rausläuft und du andere Architekturen nehmen musst.
Danke für eure Antworten. Lexxi schrieb: > Dann würde ich die Kern-ID per Generic bis zum Programmspeicher > herunterreichen und dann darüber die jeweile "Memory-Init-Datei" > auswählen. Ja, im Prinzip eine Anpassung der HDL wie im Eingangspost beschrieben mit allen damit verbundenen Vor- und Nachteilen. uwe schrieb: > Jeder bekommt einen Bootloader und lädt sich aus einem Flash sein > Programm. Lexxi schrieb: > alle Programme zu einem Paket kombinieren, in > einem großen globalen Speicher ablegen und dann holt sich jeder Kern von > da seinen Code - also kopiert den von da in den Kern-lokalen Speicher. Da ist kein Flash. Im einfachsten Fall soll es funktionieren, dass das Design per JTAG in den SRAM-basierten FPGA geladen wird und keine externe Peripherie benötigt. Fitzebutze schrieb: > Als klassische State of the Art gilt u.A. die > BF561-Doppelkern-Architektur. Ich möchte ja keine neue Architektur. Die Kerne brauchen noch nicht mal miteinander zu kommunizieren. Die sollen im einfachsten Fall nur ein paar einigermaßen flexible FSMs implementieren oder einen bestimmten performance-unkritischen Algorithmus bereitstellen. Dabei finde ich es gerade vorteilhaft, wenn die Cores alle unabhängig voneinander sind, keine elf-files kombiniert werden müssen, ich die Standard-Tools des softcore verwenden kann usw. . Auf was ich hoffe, ist etwas Richtung Kniff in VHDL, vielleicht ein geschickter wrapper für den Befehlsspeicher (ohne die eigentlichen sourcen anfassen zu müssen), oder irgendwas mit generic packages, eine minimale Anpassung der sourcen usw. . Ich bin ja bestimmt nicht der erste, der z.B. einen Softcore einfach zweimal für unabhängige Aufgaben in einem FPGA-Design einsetzen möchte. Die HDL-Beschreibung bzw. der default-workflow bei den o.g. cores verhindert das aber leider und ich suche einen best practice-Weg, das zu ändern.
Wenn du den neorv32 verwendest kannst du da ja mal auf GitHub im "Forum" fragen. Vielleicht hat einer eine Idee oder die können dein Feature direkt auf die TODO-Liste setzen.
VHDL hotline schrieb im Beitrag #7169146: > Auf was ich hoffe, ist etwas Richtung Kniff in VHDL, vielleicht ein > geschickter wrapper für den Befehlsspeicher (ohne die eigentlichen > sourcen anfassen zu müssen), oder irgendwas mit generic packages, eine > minimale Anpassung der sourcen usw. . Ich bin ja bestimmt nicht der > erste, der z.B. einen Softcore einfach zweimal für unabhängige Aufgaben > in einem FPGA-Design einsetzen möchte. Die HDL-Beschreibung bzw. der > default-workflow bei den o.g. cores verhindert das aber leider und ich > suche einen best practice-Weg, das zu ändern. Ja, gemacht haben das schon einige. Wenn es aber nur um ROM-Generierung geht, hat dein Problem kaum noch mit Multicore-Architektur zu tun, sondern nur, wie du elegant das ROM als HDL generierst. Das wird hier mit Python-Skripten aus dem Opensource-Fundus (https://github.com/hackfin/MaSoCist) generiert. Aus dem ELF werden damit ROM-Files in VHDL die als generics übergeben werden. Damit wird auch das komplette Multicore-System (4 Kerne) gebaut und simuliert. Die Makefiles (an Linux kconfig angelehnt) muss man sich für seine Zwecke anpassen und seinen Wunsch-Core ev. selber anbinden. Wenn die Cores komplett unabhängig voneinander laufen sollen, spielt es auch nicht die grosse Rolle, welche CPU-Architektur man auswählt.
Fitzebutze schrieb: > Ja, gemacht haben das schon einige. Wenn es aber nur um ROM-Generierung > geht, hat dein Problem kaum noch mit Multicore-Architektur zu tun, > sondern nur, wie du elegant das ROM als HDL generierst. Genau, die Suche nach diesem eleganten Weg ist die Intention hier. Fitzebutze schrieb: > Das wird hier > mit Python-Skripten aus dem Opensource-Fundus > (https://github.com/hackfin/MaSoCist) generiert. Danke, schau ich mir mal an.
VHDL hotline schrieb im Beitrag #7168597: > Zum einen wäre die Trennung über "namespaces", sprich man kompiliert > jeweils die komplette uC-Source mit Befehlsspeicher in verschiedene > libraries. Die sourcen muss man jeweils so umschreiben, dass z.B. statt > "library neorv32" jeweils "library work" in den uC-sourcen verwendet > wird und eine lib pro uC-Instanz zur Compilezeit festgelegt wird. Meinst du damit nicht so etwas wie die VHDL configurations? Also dort, wo man angeben kann, welche genaue Instanz jetzt inferiert werden soll für einen Component. Damit sollte auch der Synthesizer klar kommen.
Christoph Z. schrieb: > Meinst du damit nicht so etwas wie die VHDL configurations? > Also dort, wo man angeben kann, welche genaue Instanz jetzt inferiert > werden soll für einen Component. Damit sollte auch der Synthesizer klar > kommen. Du hast recht, mit configurations könnte das klappen. Die hatte ich gar nicht auf dem Schirm, zwar irgendwann im Studium mal gehört aber seitdem nie produktiv benutzt. Danke für den Tipp!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.