Mich würde der Resourcenverbrauch der kleinsten RISC V Cpu
interessieren.
Hier gibt es die "Potato CPU":
https://github.com/skordal/potato
Ist das die Minimalste? Wie gut passt die auf ein MAX1000?
Moin.
Zum MAX1000 kann ich dir leider nichts getestetes sagen. Aber einen
RV32I kriegt man sicher drauf, zwei oder mehr schätze ich wird
aufwendiger.
Minimalste Implementierung eines Risc-v halte ich aber mal nach
schnellem Blick für unwahrscheinlich. Laut dem Repo implementiert der
Prozessor RV32I, d. h. Es lassen sich schon mal 512 weitere FFs
einsparen, wenn man auf RV32E umbaut. Außerdem frage ich mich, ob man
mit weniger Pipelinestufen nicht auch noch etwas Platz durch weniger FFs
spart.
Moin,
mit rund 850 Xilinx-Slices muss man wohl fuer eine pipelined rv32i
rechnen. Die Potato ist da nicht wirklich 'minimal'.
Tricksen kann man noch mit non-pipelined-Ansaetzen, wie es auch die
picorv32 macht, da schafft man es meist so auf die Haelfte.
Wenn du strenge Anforderungen an Kompaktheit (incl. Opcodes) hast,
wuerde ich zur ZPU-Architektur greifen. Da gibt's alles, was es bei
RISC-V auch gibt, nur wird der GCC nur noch unter der Hand gewartet.
Strubi
>Tricksen kann man noch mit non-pipelined-Ansaetzen, wie es auch die>picorv32 macht, da schafft man es meist so auf die Haelfte.
Interessanter Hinweis, danke.
https://github.com/cliffordwolf/picorv32
Leider ist die CPU in Verilog geschrieben. Ich bin nur mit VHDL
unterwegs.
Bei der Potato-CPU scheint es Optionen zu geben, auf nicht
laufzeitoptimierte Varianten umzuschalten.
FrüherVogel
>Es lassen sich schon mal 512 weitere FFs>einsparen, wenn man auf RV32E umbaut.
Auch ein interessanter Hinweis. Wenn ich es richtig verstehe, hat die
E-Version nur weniger Register, aber ansonsten den gleichen Befehlssatz.
Ist der angehängte der Richtige?
Also wenn wir über minimale Implementierungen reden muss ich den
bit-seriellen Serv von Olof Kindgren (RISC-V Ambassador) erwähnen:
Repo:
https://github.com/olofk/serv
Eine der vielen Präsentationen vom RISC-V Workshop (gibt auch irgendwo
aktuellere):
https://www.youtube.com/watch?v=xjIxORBRaeQ
Dazu hat er den CoreScore eingeführt (https://corescore.store/) eine Art
Benchmark für Place&Route und FPGAs (muss man natuerlich relativ sehen).
Wenn man die minimalen Resourcenverbrauch anschauen muss ist es
natürlich gefährlich bei einer minimalen Implementierung die benötigte
Peripherie zu vergessen. Ich habe selber mal einen kleinen RV32I core
implementiert, mit Peripherie irgendwo um 1900 LUTs und 900 FFs auf
7-Series (plus X-BRAM jenach benötigtem RAM/ROM wenn man das onboard
machen will). Wobei viel das Routing zum BRAM Speicher und
UART/Timer/Interrupt/... ausmacht. Der pure Core wäre vllt bei etwa
1/3-1/2 davon.
PS: Ist es wichtig die CPU in VHDL zu haben? Wrappe die doch einfach in
dein VHDL, falls du groß was daran ändern willst natürlich schwierig.
Fast jede (gute) OpenSource Implementierung ist in Verilog.
chris_ schrieb:> Wenn ich es richtig verstehe, hat die> E-Version nur weniger Register, aber ansonsten den gleichen Befehlssatz.>> Ist der angehängte der Richtige?
Du verstehst richtig :)
Das Dokument sieht ziemlich richtig aus. Falls du was damit selber bauen
willst, empfehle ich aber direkt zur offiziellen Spec zu greifen.
lexi schrieb:> Wie wäre es mit dem **NEORV32**? https://github.com/stnolting/neorv32>> Ist in VHDL geschrieben, hat ein Datenblatt [sic] und ein komplettes SoC> mit Software-Libraries drumherum.
Das sieht wirklich ziemlich vorbildlich aus. Da juckt es schon wieder in
den Fingern, die FPGA-Boards doch noch einmal wieder auszupacken. Wenn
doch nur die Toolchains nicht so nervig wären...
Tim . (cpldcpu)
07.03.2021 14:06
>Das sieht wirklich ziemlich vorbildlich aus. Da juckt es schon wieder in>den Fingern, die FPGA-Boards doch noch einmal wieder auszupacken. Wenn>doch nur die Toolchains nicht so nervig wären...
Ich hab's jetzt mal auf eine DE0-Nano mit dem hier probiert:
https://github.com/stnolting/neorv32/tree/master/boards/de0-nano-test-setup
Mit Quartus war es relativ problemlos: Ich musste nur die VHDL-Files ins
Projekt ziehen, den richtigen Chipt des DE0-Nano vorher auswählen und
die Pinkonfiguration anpassen.
( einfach ins qsf-File kopieren )
1
set_location_assignment PIN_R8 -to clk_i
2
set_location_assignment PIN_L3 -to gpio_o[7]
3
set_location_assignment PIN_B1 -to gpio_o[6]
4
set_location_assignment PIN_F3 -to gpio_o[5]
5
set_location_assignment PIN_D1 -to gpio_o[4]
6
set_location_assignment PIN_A11 -to gpio_o[3]
7
set_location_assignment PIN_B13 -to gpio_o[2]
8
set_location_assignment PIN_A13 -to gpio_o[1]
9
set_location_assignment PIN_A15 -to gpio_o[0]
10
set_location_assignment PIN_J15 -to rstn_i
11
set_location_assignment PIN_C3 -to uart0_txd_o
12
set_location_assignment PIN_A3 -to uart0_rxd_i
Beim DE0-Nano braucht man einen externen FDTI-Adapter für die serielle
Schnittstelle und die in der Doku beschriebenen Baudrate von 19200
stimmt nicht. Man muss 9600 Baud einstellen.
Das Blinkbeispiel in C kann man einfach mit "make" erzeugen:
https://github.com/stnolting/neorv32/tree/master/sw/example/blink_led
Allerdings will ich, um RISC-V richtig kennen zu lernen, reinen
Assembler verwenden.
Ich kann zwar schon irgendwie kompilieren, aber blinken tut's noch
nicht:
Beitrag "Re: RISC-V Gnu Assembler"
chris_ schrieb:> Beim DE0-Nano braucht man einen externen FDTI-Adapter für die serielle> Schnittstelle und die in der Doku beschriebenen Baudrate von 19200> stimmt nicht. Man muss 9600 Baud einstellen.
Wenn du die Dateien selber zu einem Projekt hinzufügst, musst du die
Taktrate über ein Generic einstellen:
1
CLOCK_FREQUENCY:natural:=50000000;-- clock frequency of clk_i in Hz
chris_ schrieb:> Das Blinkbeispiel in C kann man einfach mit "make" erzeugen:> https://github.com/stnolting/neorv32/tree/master/sw/example/blink_led>> Allerdings will ich, um RISC-V richtig kennen zu lernen, reinen> Assembler verwenden.> Ich kann zwar schon irgendwie kompilieren, aber blinken tut's noch> nicht:
Im selben Verzeichnis gibt es auch eine reine ASM-Version zum blinken
der LEDs (blink_led_in_asm.S). Die kann man per define anstelle der
C-Version nehmen:
1
/** Use the custom ASM version for blinking the LEDs defined (= uncommented) */
>Die kann man per define anstelle der C-Version nehmen:
Danke für den Hinweis. Ich habe schon alle möglichen Verrenkungen
ausprobiert, um das ASM-File zu kompilieren. Wo ist das #define zu
finden?
>#define USE_ASM_VERSION
Hab's gefunden .. mitten im C-File.
Ich will das Ganze auf's Wesentliche reduzieren, aber in dem Beispiel
wird die gesamte Compiler Initialisierung mitkompiliert. Zum Blinken
einer LED müssen ein paar Zeilen Assembler ohne riesen C-Framework
Overhead reichen.
Wieviel Bytes braucht man mit einem RISC-V, um eine LED sichtbar blinken
zu lassen?
chris_ schrieb:> Ich will das Ganze auf's Wesentliche reduzieren, aber in dem Beispiel> wird die gesamte Compiler Initialisierung mitkompiliert. Zum Blinken> einer LED müssen ein paar Zeilen Assembler ohne riesen C-Framework> Overhead reichen.
Du musst erstmal herausfinden, wie man überhaupt die LED ansteuert. Wenn
das Ausgangsregister irgendwo in den Adressraum eingeblendet ist, kann
man das bestimmt ganz einfach machen. Ich würde das so versuchen:
1
li x1, 123456 // Adresse des LED Ausgangsregister
2
3
start:
4
li x2, 1000 // Wartezeit
5
6
loop: // Warteschleife
7
addi x2, x2, -1 // x2 dekrementieren
8
bne x2, x0, loop // zu loop springen wenn x2 nicht null
9
10
// memory-mapped LED toggeln
11
lw x2, 0(x1) // aktuellen Status der LED lesen
12
xori x2, x2, 1 // invertieren
13
sw x2, 0(x1) // neuen Status schreiben
14
15
j start
Allerdings wirst du wahrscheinlich noch zusätzlichen Code brauchen, um
die CPU überhaupt erst mal zu initialisieren. Aber das ist natürlich
absolut Hardware-spezifisch.
chris_ schrieb:> Wieviel Bytes braucht man mit einem RISC-V, um eine LED sichtbar blinken> zu lassen?
Wenn jede Anweisung 32-bit entspricht, dann wären das 8x4 = 32 Bytes.
Verwendet man die komprimierten Instruktionen lässt sich das auf 16
Bytes halbieren
> von lexi (Gast)
Hier ist dein Blink-programm mit einem Direktzugriff auf die
Portadresse.
Die Warteschleifenzähler muss deutlich höher als 1000 sein, da der
Prozessor mit 100MHz getaktet wird.
Das Programm funktioniert nur als Subroutine wenn sie vom Main
aufgerufen wird. Es sieht also so aus, als wenn diese Architektur
tatsächlich noch eine Initialisierung braucht. Ich tippe vorerst auf die
Interruptvektoren....
1
.file"blink_led_in_asm.S"
2
.section.text
3
.balign4
4
.globalblink_led_asm
5
6
blink_led_asm:
7
lix1,0xFFFFFF84// Adresse des LED Ausgangsregister
8
9
start:
10
11
lix2,1000000// Wartezeit
12
13
loop:// Warteschleife
14
15
addix2,x2,-1// x2 dekrementieren
16
17
bnex2,x0,loop// zu loop springen wenn x2 nicht null
18
19
// memory-mapped LED toggeln
20
21
lwx2,0(x1)// aktuellen Status der LED lesen
22
23
xorix2,x2,0xAA// jedes zweite Bit invertieren (4 Leuchtidioden gleichzeitig)
>https://github.com/stnolting/neorv32/
Weiß jemand, wie man am besten vorgeht, wenn man bei dem Projekt eigene
Peripherie hinzufügt?
Es mach ja wenig Sinn, nur vorgefertigte Module zu konfigurieren. Da
könnte man gleich einen normalen, passen Mikrocontroller aussuchen.
Ich will einen Sigma-Delta-Wandler implementieren und der einfachste Weg
scheint mir zu sein, die PWM-Unit "auszubeinen" und durch den
Wandlercode zu ersetzen.
Wenn ich das richtig sehe, bedeutet das für eigene Module, dass man an
die ganzen Stellen etwas dazu bauen muss. Da fände ich ein einfacheres,
besser entkoppeltes Interface praktischer.
chris_ schrieb:>>Bei dem Projekt gibt es auch ein Modul für Anwenderhardware:
Ich meinte das "Custom Functions Subsystem". Schau einfach mal nach CFS
ins der Doku bzw. im Code.
chris_ schrieb:> Wenn man aber nach den Signalen des Moduls sucht, sind die kreuz und> quer im Toplevel verteilt
Der interne Bus erinnert stark an Wishbone. Das eigentliche
Bus-Interconnect ist hier nicht als eigenes Modul instantiert, sonder
eben direkt in der Top beschrieben. Bei dem Rückkanal zur CPU handelt es
sich im Endeffekt nur um einige breite Oder-Gatter, die eben z.B. für
das ACK an der von dir angemerkten Stelle implementiert sind.
my 50 Cents schrieb:> Welche Anwendungsfälle deckt ihr denn mit solchen RISC CPUs ab? Das sind> doch meist kleine Sächelchen die sich auch direkt realisieren ließen,> oder?
In meinem Fall zum Beispiel, um "online" Bitstreams zu laden. Das kann
man natürlich auch über eine State-Machine machen, aber ein Softcore ist
- meiner Meinung nach - einfacher und deutlich flexibler. C-Entwicklung
geht viiiiel schneller als VHDL-Entwicklung.
my 50 Cents (Gast)
>Welche Anwendungsfälle deckt ihr denn mit solchen RISC CPUs ab?
Ich habe eine CPU-Emulation mit eigenem Befehlssatz und ich wollte mal
sehen, wie schnell das mit dem RISCV Befehlssatz läuft.
Im Moment experimentiere ich aber nur mit dem NEO-Projekt und schaue,
was man damit machen kann.
Als einfaches Beispiel könnte man einen reziproken Frequenzzähler
basteln, so wie hier diskutiert:
Beitrag "Re: FPGA reziproker Frequenzzähler"
Man könnte einen eigenen Frequenzzählerblock machen und den via AXI an
die CPU hängen.
Ich frage mich aber, ob ein 32Bit-Bus im FPGA nicht zu viel Resourcen
verbraucht und man das Modul nicht besser über SPI anbindet.
chris_ schrieb:> Ich frage mich aber, ob ein 32Bit-Bus im FPGA nicht zu viel Resourcen> verbraucht und man das Modul nicht besser über SPI anbindet.
Also wenn es um eine Verbindung INNEHALB eines FPGAs geht, dann würde
ich vom Gefühl her sagen, dass eine direkte parallele Verbindung weniger
Resourcen braucht als eine serielle. Bei der seriellen must du erst
serialisieren und dann in der Peripherie wieder de-serialisieren +
Controller overhead...
Wenn man nur einen Controller mit ein wenig Peripherie verbinden will
und man nicht unbedingt Gb/s zwischen Peripherie und Beschleuniger
braucht, dann würde ich die über ein vereinfachtes Wishbone koppeln.