Compare commits

...

2 Commits

Author SHA1 Message Date
  kaqu 37ac528260 Risq5 text/code display improved 1 day ago
  kaqu 8b26aab856 Risq5 project added 2 days ago
13 changed files with 468 additions and 1 deletions
Split View
  1. +1
    -1
      content/projekt/Neopixelar/index.md
  2. BIN
      content/projekt/Risq5/BookReference.jpg
  3. BIN
      content/projekt/Risq5/InstructionDecoder.png
  4. BIN
      content/projekt/Risq5/OverviewDebugger.png
  5. BIN
      content/projekt/Risq5/OverviewMulticoreAccess.png
  6. BIN
      content/projekt/Risq5/OverviewRemoteLoading.png
  7. BIN
      content/projekt/Risq5/OverviewSystemBus.png
  8. BIN
      content/projekt/Risq5/RamLoadingDetail1.png
  9. BIN
      content/projekt/Risq5/RamLoadingDetail2.png
  10. BIN
      content/projekt/Risq5/RefCard1.png
  11. BIN
      content/projekt/Risq5/RefCard2.png
  12. BIN
      content/projekt/Risq5/Risq5_Overview.png
  13. +467
    -0
      content/projekt/Risq5/index.md

+ 1
- 1
content/projekt/Neopixelar/index.md View File

@ -1,6 +1,6 @@
---
title: Neopixelar oder 'Wie geht FPGA?'
author: kaqu
author: Ivo Snett
status: Aktiv
difficulty: Ja ...
time: ~1d


BIN
content/projekt/Risq5/BookReference.jpg View File

Before After
Width: 195  |  Height: 240  |  Size: 32 KiB Width: 195  |  Height: 240  |  Size: 32 KiB

BIN
content/projekt/Risq5/InstructionDecoder.png View File

Before After
Width: 1920  |  Height: 1080  |  Size: 226 KiB Width: 1920  |  Height: 1080  |  Size: 226 KiB

BIN
content/projekt/Risq5/OverviewDebugger.png View File

Before After
Width: 1920  |  Height: 1080  |  Size: 111 KiB Width: 1920  |  Height: 1080  |  Size: 111 KiB

BIN
content/projekt/Risq5/OverviewMulticoreAccess.png View File

Before After
Width: 1920  |  Height: 1080  |  Size: 85 KiB Width: 1920  |  Height: 1080  |  Size: 85 KiB

BIN
content/projekt/Risq5/OverviewRemoteLoading.png View File

Before After
Width: 1920  |  Height: 1080  |  Size: 116 KiB Width: 1920  |  Height: 1080  |  Size: 116 KiB

BIN
content/projekt/Risq5/OverviewSystemBus.png View File

Before After
Width: 1920  |  Height: 1080  |  Size: 128 KiB Width: 1920  |  Height: 1080  |  Size: 128 KiB

BIN
content/projekt/Risq5/RamLoadingDetail1.png View File

Before After
Width: 1920  |  Height: 1080  |  Size: 257 KiB Width: 1920  |  Height: 1080  |  Size: 257 KiB

BIN
content/projekt/Risq5/RamLoadingDetail2.png View File

Before After
Width: 1920  |  Height: 1080  |  Size: 118 KiB Width: 1920  |  Height: 1080  |  Size: 118 KiB

BIN
content/projekt/Risq5/RefCard1.png View File

Before After
Width: 675  |  Height: 834  |  Size: 208 KiB Width: 675  |  Height: 834  |  Size: 208 KiB

BIN
content/projekt/Risq5/RefCard2.png View File

Before After
Width: 673  |  Height: 837  |  Size: 214 KiB Width: 673  |  Height: 837  |  Size: 214 KiB

BIN
content/projekt/Risq5/Risq5_Overview.png View File

Before After
Width: 1920  |  Height: 1080  |  Size: 499 KiB Width: 1920  |  Height: 1080  |  Size: 499 KiB

+ 467
- 0
content/projekt/Risq5/index.md View File

@ -0,0 +1,467 @@
---
title: Risq5 (noch'n Klon - aber mit FPU!)
author: Ivo Snett
status: Aktiv
difficulty: Ja ...
time: ~1d
date: 2021-04-08
image: Risq5_Overview.png
keywords: FPGA, RISC-V, RV32IMF, FPU, IEEE754, Litex, migen, colorlight-5a-75b
---
Für ein besseres Verständnis wird dringend geraten, zuerst
[diesen Artikel hier](https://www.hacknology.de/projekt/2020/neopixelar/)
durchzuarbeiten ...
## Motivation
Dies ist jetzt die angedrohte [RISC-V](https://en.wikipedia.org/wiki/RISC-V) Geschichte!
Nachdem ich vor 3 Monaten die
[Neopixel-FPGA Lösung](https://www.hacknology.de/projekt/2020/neopixelar/)
beendet hatte, war klar, das auch die Realisierung einer kompletten CPU
(['Turing-Maschine'](https://de.wikipedia.org/wiki/Turing-Maschine)) möglich sein würde.
Wenn sich jetzt Google & Apple ihre eigenen CPUs bauen (lassen), warum dann nicht auch jeder andere? [*]
Das wär' doch mal was - eine selbst gebaute CPU in migen/LiteX/Python auf einem FPGA!
{{< image alt="Showtime" src="Risq5_Overview.png" size="1920x1080 q90">}}
[*] Eine rhetorische Frage, mittlerweile baut 'gefühlt' jede größere Bude oder Uni ihre eigenen Chips
(siehe https://github.com/riscv/riscv-cores-list u.ä.)!
## 1. RISC-V Einstieg
Warum gerade eine RISC-V CPU?
1. Das war im Herbst letzten Jahres nun mal die Ausgangsfrage ...
2. Warum nicht? RISC-V ist in den letzten Jahren ein regelrechter Hype - und ich mach'
doch jeden Blödsinn mit ... Realitätsnäher: Es gibt jede Menge Referenz-Implementierungen
(nicht zuletzt auch in LiteX - leider jedoch nur in Verilog & nmigen, nicht in migen - oder
ich hab' sie nicht gefunden ...).
Ich fand diese Sourcen eher spärlich dokumentiert (Wolfgang ist hier anderer Meinung - ☮ man!) und
auch nicht vollständig (keine F-Extension für IEEE754 Fließkommabehandlung etc.) - mal
schaun, ob sich zumindest im FPU-Bereich die Lage verbessern läßt ...
3. Auf dem von mir bereits früher verwendeten Colorlight-Board
[(s.Artikel)](https://www.hacknology.de/projekt/2020/neopixelar/)
ist bereits eine RISC-V (Soft-)CPU aktiv ('vexriscv'), damit hatte ich bereits (Assembler-)
Übung aus dem letzten Projekt - immer eine schön stumpfe Begründung!
Um reinzukommen habe ich mir zunächst ein paar YouTube Videos zum Thema RISC-V angesehen.
Dabei fand ich auch [diesen Vortrag](https://www.youtube.com/watch?v=vCG5_nxm2G4) von Megan
Wachs (von SiFive - 'der' RISC-V Firma!) in dem - unter anderem - drei Buchvorschläge gemacht werden.
Nachdem ich mich separat über die jeweiligen Inhalte informiert hatte, entschied ich mich für das 'Mittlere'
([Patterson, Waterman 'The RISC-V Reader'](http://www.riscvbook.com/)) - das ist schön knapp.
{{< image alt="Book" src="BookReference.jpg" size="320x240 q90" size="195x240 q90" >}}
Es beschreibt die RISC-V Architektur ('ISA' - Instruction set architecture), die zugrunde
liegenden Ideen der Beteiligten (von den 'Erfindern' selbst - also total distanzlos ...),
enthält Assembly-Beispiele & Grafiken (z.B. die 'Reference Card', s.u.) sowie eine Liste aller
Befehle inkl. der optionalen Befehlserweiterungen - die bei RISC-V eine große Bedeutung haben!
Außerdem enthält es einige Rüpeleien gegen andere Architekturen (ARM/Intel/MIPS), sehr lustig 🎃!
Als einzig satisfaktionsfähige (Alternativ-)Architektur gilt hier übrigens Xtensa (also ESP)
mit seinem Register-Fenster ...
<div class="pure-g">
{{< image alt="RefCard1" src="RefCard1.png" size="675x834 q90" class="pure-u-1 pure-u-md-1-2" >}}
{{< image alt="RefCard2" src="RefCard2.png" size="673x837 q90" class="pure-u-1 pure-u-md-1-2" >}}
</div>
Obige Grafiken zeigen die in diesem Projekt realisierten RISC-V Ausbaustufen (gelb gerahmt):
- I (Base): Integer (Basis)
- M (Extension): Integer multiply (& divide) support
- F (Extension): Floating point (32-bit) support
Die Bezeichnung für die im Projekt realisierte CPU lautet daher offiziell: __RV32IMF__.
Es steht daher nur der 'Machine Mode' zur Verfügung (d.h. nur eine Auswahl der Control & Status Register [CSR]).
Die (ISA-)Spezifikation kann natürlich auch direkt hier bezogen werden:
[Vol.1 ](https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMAFDQC/riscv-spec-20191213.pdf)
& [Vol.2](https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMFDQC-and-Priv-v1.11/riscv-privileged-20190608.pdf).
## 2. Was macht eine [CPU](https://de.wikipedia.org/wiki/CPU) ('Central Processing Unit')?
Eine CPU liest Werte aus dem Speicher ('das Programm' oder auch 'die Applikation').
Diese Werte werden als Befehle ('Opcode') vom Prozessor interpretiert.
Im Ergebnis werden bei der Interpretation Daten aus dem Speicher gelesen
(ja, parallel zum Laden des Programms!), in den internen Prozessor-Registern je nach
Opcode verschoben bzw. verarbeitet und dann Ergebnisse ggf. zurück in den
Speicher geschrieben (jedenfalls typischerweise ...).
Bei RISC-V ist das in den Befehlen sauber getrennt:
- Es gibt Befehle zum Laden von Werten aus dem Speicher (und NUR dafür)
- Es gibt Befehle zum internen Bearbeiten (und NUR dafür)
- Es gibt Befehle zum Schreiben von Werten zurück in den Speicher (und NUR dafür)
- Außerdem gibt es noch Verzweigungs- bzw. Sprungbefehle
__Mal 'ne Referenz:__
Eine CPU ist folglich Teil einer konkreten Form einer
[Turing-Maschine](https://en.wikipedia.org/wiki/Turing_machine)
(umständlichlicher ging gerade nicht 💀!).
Das Symbolband ist der Speicher, der Schreib-/Lesekopf bilden Load- & Store-Unit der CPU.
Zustandsregister und Instruktionstabelle werden als interne Register und interne
Verarbeitungslogik umgesetzt.
## 3. Wie baut ('synthetisiert') man eine CPU?
Hierzu wusste ich zunächst recht wenig, daher entschloß ich mich, ein paar Vorträge zum
Thema zu hören (YouTube!). Ich entschied mich für [MIT 6.004](https://www.youtube.com/watch?v=n-YWa8hTdH8)
aus dem Herbst 2019 - bis L15 hab' ich's mir dann auch reingetan ...
Leider wird dort mit bluespec/minispec gearbeitet - KEIN migen! Ein bisschen Transferleistung
mußte also noch zusätzlich erbracht werden 🏋.
Hätte ich mich an alle dort gegebenen Tipps gehalten, wäre das Resultat wahrscheinlich überzeugender
ausgefallen ... hier habe ich einfach Hardware so aufgebaut, wie ich einen Software-Emulator
geschrieben hätte.
Das hieß auch, erst einmal einen Automaten bauen der einen (kleinen) Speicherbereich aus dem DRAM
lädt, und jedes (32-Bit-)Wort einzeln anpacken kann. Außerdem mußte der Automat fernsteuerbar
sein (über den Wishbone-Systembus) zwecks Debugging - was auch hieß: Parallel muß gleich ein
Debugger hochgezogen werden (um überhaupt testen zu können, was so intern abgeht ... 🤔 ).
Von hier aus kann man sich dann von Befehl(-simplementation) zu Befehl(-simplementation) hangeln.
## 4. Praktische Umsetzung
Zunächst beließ ich die mitgelieferte 'vexriscv' CPU parallel noch in Betrieb.
Hiermit passte immerhin noch die 'Basis' Integer-Version von RISC-V auf's FPGA (bei ca. 1/2h
Stunde Übersetzungslauf), genannt __RV32I__ (für 32-Bit) mit 32 X-Registern (Integer).
{{< image alt="Overview Debugger" src="OverviewMulticoreAccess.png" >}}
Um die M-Extension zu realisieren, musste ich jedoch bereits die 2. CPU entfernen (Konfigurationsänderung).
Anschließend habe ich gleich noch den integrierten Cache, den Wishbone-Zugriff und Flash/BIOS-Zugriff
entfernt. Damit sanken die Übersetzungszeiten in migen/LiteX dann auf ca. 10 Minuten (alle Zeiten gemessen
in VM mit 4 Kernen auf i7/3rd gen.).
Jetzt konnte ich auch den 32-Bit Fließkommateil ('F-Extension') noch komplett integrieren - mit einer
Einschränkung: Es passen nur noch jeweils vier X- & F-Register in das Lattice ECP5-25 FPGA (von eigentlich 32
Stück)! Die Logik geht aber komplett drauf - bei durchaus erträglichen Übersetzungszeiten von um die
20 Minuten.
Die Logik arbeitet mit 2 oder 5 Addressbits für das interne Registerfile, kann folglich 4 bzw. 32 Register
adressieren (lediglich zwei Variablen müssen angepasst werden um 'full blown' auf einem größeren FPGA zu
arbeiten ...).
## 5. Debugging
Zunächst habe ich im normalen BIOS-Terminal gearbeitet (wie gehabt), die laufende Applikation (auf der
'alten' vexriscv CPU!) IST dann der Debugger. Später bin ich darauf gekommen, das Debugging-Interface
am Wishbone-Systembus direkt über Ethernet anzusprechen, ein entsprechender PC-seitiger 'Server' ist
im Wishbone-Tool bereits enthalten. Damit kann der Debugger komplett separat in Python erstellt werden
und auf dem PC laufen (s. Übersichtsbild oben).
Hier mal die grundsätzliche (boardseitige) Anbindung:
{{< image alt="Overview Debugger" src="OverviewDebugger.png" >}}
Bild zeigt den Aufbau noch mit dem zweiten 'alten' Core parallel.
## 6. Instruktionsverarbeitung
Der Verarbeitungskern ('core') besteht aus Programmladeeinheit (L1-Cache - korrekter wäre wohl L0?),
der Datenladeeinheit (LU - load unit) und der komplementären Speichereinheit (SU - store unit),
dem Basisdecoder und dem FPU-Decoder sowie der (über den Wishbone-Systembus fernsteuerbaren)
Abarbeitungslogik (hier etwas irreführend als ALU bezeichnet 🤔, eigentlich handelt es sich eher um
sowas wie 'data flow').
Der L1-Cache lädt sich zunächst selbst von der Boot-Adresse (RISC-V: 0h!) und signalisiert dann 'Bereit'
an die ALU (deren Programmzähler 'PC' ebenfalls zunächst auf 0h steht 🎉 !), diese lädt daraufhin den ersten
Befehl ('opcode') und prüft, ob der Laufstatus freigegeben ist (der Debugger erlaubt sowohl Single-Stepping
wie auch 'Freilauf' - übrigens auch bis 'Breakpoint' ...).
Außerdem kann der PC im Debugger geändert werden, die ALU signalisiert dann dem L1-Cache ein Neuladen ab
PC und wartet entsprechend. Auch bei sonstigen Bedarfen (Interrupt-Routine, Sprüngen im Programmcode in einen
Bereich außerhalb des gerade geladenen Cache-Ranges - oder auch schlicht nächster Befehl ...) signalisiert
die ALU dem L1-Cache Entsprechendes.
Bei freigegebener Ausführung ('Execution') wird der Opcode mit dem Decoder verarbeitet.
{{< image alt="Instruction Decode" src="InstructionDecoder.png" size="1920x1080 q90">}}
Die Grafik zeigt den Basisdecoder(-Automaten) inkl. dem Teil für die M-Extension (integer multiply/divide).
Die F-Extension ist erst später entstanden als obige Grafik und als Automat nicht sehr ergiebig insofern,
als viele Befehle einfach eigene Verarbeitungsketten durchlaufen da hier nur wenige Konverterfunktionen
gemeinsam genutzt werden können. Generell triggert der Basisdecoder den FPU-Decoder und wartet anschließend
schlicht auf Fertigmeldung ...
## 7. Test
Für das Testen kann der gcc für RISC-V genutzt werden. Über Aufrufparameter kann die Zielplattform
exakt eingestellt werden. Praktisch hieß das zunächst (im Projektablauf) für RV32I übersetzen, später
für RV32IM und letztlich für RV32IMF. Die Unterschiede zeigen sich deutlich im generierten Assemblat.
__Ein Beispiel:__
```c
unsigned int result;
int m1,m2;
m1 = 12345;
m2 = 67890;
result = m1 * m2;
m2 = result / m1;
```
__gcc Parameter -march=rv32i -mabi=ilp32 (für RV32I ohne Optimierungen):__
```asm
...
addi sp,sp,-32 # Local variable reservation on stack (notice: extra space allocated!)
sw ra,28(sp) # Notice: Additional save because of lib. call!
lui a5,0x03
addi a5,a5,57 # 12345
sw a5,12(sp) # m1=
lui a5,0x11
addi a5,a5,-1742 # 67890
sw a5,8(sp) # m2=
lw a1,8(sp)
lw a0,12(sp)
auipc ra,0x0
jalr ra # 0x68 Library call (unlinked) a0 = __mulsi3(a0,a1)
mv a5,a0
sw a5,4(sp) # result=
lw a5,12(sp)
mv a1,a5
lw a0,4(sp)
auipc ra,0x0
jalr ra # 0x84 Library call (unlinked) a0 = __udivsi3(a0,a1)
mv a5,a0
sw a5,8(sp) # m2=
...
```
__-march=rv32im -mabi=ilp32 (für RV32IM):__
```asm
...
addi sp,sp,-16 # Local variable reservation on stack
# Notice: Additional space for ra save (ra='return adress')
# but not used as there is no function call
lui a5,0x3
addi a5,a5,57 # 12345
sw a5,12(sp) # m1=
lui a5,0x11
addi a5,a5,-1742 # 67890
sw a5,8(sp) # m2=
lw a4,12(sp)
lw a5,8(sp)
mul a5,a4,a5 # a5 = a4 * a5
sw a5,4(sp) # result=
lw a5,12(sp)
lw a4,4(sp)
divu a5,a4,a5 # a5 = a4 / a5
sw a5,8(sp) # result=
...
```
.
__Und noch ein Beispiel mit Floats:__
```c
float result;
float m1,m2;
m1 = 1.234;
m2 = 6.789;
result = m1 * m2;
m2 = result / m1;
```
__-march=rv32i -mabi=ilp32 (für RV32I):__
```asm
...
addi sp,sp,-32 # Local var. reservation
sw ra,28(sp) # Due to lib. calls ...
lui a5,0x0
lw a5,0(a5) # From address: 0x0
sw a5,12(sp) # Constant load fixup during link phase?!
lui a5,0x0
lw a5,0(a5) # From address: 0x0
sw a5,8(sp)
lw a1,8(sp)
lw a0,12(sp)
auipc ra,0x0
jalr ra # 0x68 library call: a0 = __mulsf3(a0,a1)
mv a5,a0
sw a5,4(sp)
lw a1,12(sp)
lw a0,4(sp)
auipc ra,0x0
jalr ra # 0x80 library call: a0 = __divsf3(a0,a1)
mv a5,a0
sw a5,8(sp) # m2=
...
```
__-march=rv32imf -mabi=ilp32 (für RV32IMF):__
```asm
...
addi sp,sp,-16
lui a5,0x40192
flw fa5,64(a5) # from address: 0x40192040
fsw fa5,12(sp) # m1=
lui a5,0x40192
flw fa5,68(a5) # from address: 0x40192044
fsw fa5,8(sp) # m2=
flw fa4,12(sp)
flw fa5,8(sp)
fmul.s fa5,fa4,fa5 # f15 = f14 * f15 (actual register file 'raw' names)
fsw fa5,4(sp) # result=
flw fa4,4(sp)
flw fa5,12(sp)
fdiv.s fa5,fa4,fa5 # f15 = f14 / f15
fsw fa5,8(sp) # m2=
...
```
.
Bei RV32I werden für viele Dinge Library-Routinen benötigt, die auf RV32IMF 'native' (und damit: erheblich
schneller) laufen können. Außerdem kann offensichtlich Stack-Space gespart werden (und der Code schrumpft
auch!). Interessant: Fließkommakonstanten werden separat abgelegt ...
Das Laden geschieht wieder über das Wishbone-Tool, zum Testen in einen festen Bereich (wäre aber grundsätzlich
egal - Hauptsache DRAM!). Die Ladeadresse ist so gewählt (0x40190000), daß sie nicht mit den Bereichen des
'alten' Kerns (vexriscv) kollidiert.
{{< image alt="DRAM Loading #1" src="RamLoadingDetail1.png" >}}
{{< image alt="DRAM Loading #2" src="RamLoadingDetail2.png" >}}
.
## 8. F-Extension: Einfach-genaue 32-Bit-Fließkommazahlen gemäß IEEE 754
Fliesskommazahlen sind kein 'natürliches' Format für Computer (das wäre ein Binärsystem).
Es bedarf spezieller Annahmen und einer speziellen Behandlung um sinnvolle Ausgaben produzieren zu können.
Die Umsetzung von dezimal zu binär basiert auf der Festlegung eines festen Formats (gemäß
[IEEE 754](https://en.wikipedia.org/wiki/IEEE754) - einem Standard, den heutzutage jeder Prozessorhersteller
anbietet), hier für 32-Bit Zahlen wie folgt:
0000 0000 0000 0000 0000 0000 0000 0000
Seee eeee eMMM MMMM MMMM MMMM MMMM MMMM
S ist das Vorzeichen ('sign', 0='+' / 1='-')
e ist der Exponent (8 bit)
M ist die Mantisse (23 bit)
Dezimalzahlen werden gemäß folgender Formel dargestellt:
xd = (-1)^S * 1.M * 2^(e - 127)
Es wird also eine fixe eins vor dem Komma angenommen, der Bereich der Mantisse liegt dann zwischen eins
und zwei. Außerdem wird der Exponent von 0..255 auf den Bereich 128..-127 transformiert.
Man kann das mit [diesem Simulator](https://www.h-schmidt.net/FloatConverter/IEEE754.html) selbst testen.
Wenn man glaubt, alles verstanden zu haben (also nach reichlich 🌍-Recherche ... die bei mir immer
ein bisschen U.S.-lastig ausfällt, wahrscheinlich weil ich DDG benutze 🤔?), kann es nützlich sein,
das Gelernte zunächst einmal in einem Testprogramm auszuprobieren (die FPGA-Übersetzung wäre einfach zu
zeitaufwendig!).
Hier mal ein Beispiel für ein Testprogramm für das flt.s mnemonic (Vergleichen auf f1 kleiner f2 - 'less-than'),
das Ergebnis landet später als 0 oder 1 in einem (integer) x-Register:
```c
// Extraction
#define IEEE754_SIGN(v) ((unsigned int)(v) & 0x80000000)
#define IEEE754_EXP(v) (((unsigned int)(v) & 0x7F800000) >> 23)
#define IEEE754_MANT(v) ((unsigned int)(v) & 0x007FFFFF)
// Synthesis
#define SIGN_IEEE754 0x80000000
#define EXP_IEEE754(v) ((v) << 23)
#define MANT_IEEE754(v) (v)
unsigned int f_lt_s(float f1, float f2)
{
unsigned int *ui1 = (unsigned int *) &f1, *ui2 = (unsigned int *) &f2;
// 0. Dissection
signed char e1 = IEEE754_EXP(*ui1) - 127;
signed char e2 = IEEE754_EXP(*ui2) - 127;
unsigned int m1 = IEEE754_MANT(*ui1);
unsigned int m2 = IEEE754_MANT(*ui2);
// Simple sign compare ahead
if(IEEE754_SIGN(*ui1) ^ IEEE754_SIGN(*ui2)) { // Sign mismatch? That's easy!
if(IEEE754_SIGN(*ui1)) // f1 negative -> hence f1 smaller!
return 1;
else // f2 negative, f1 is not less than
return 0;
}
// Same sign: Compare exponents, then (maybe) mantissas
if(e1 < e2) { // f1 smaller (absolute number)?
if(IEEE754_SIGN(*ui1)) // But in negative range?
return 0; // f1 not as small as f2!
else // Positive
return 1;
}
else { // f2 smaller/equal absolute value
if(e2 < e1) { // f2 smaller (absolute value)
if(IEEE754_SIGN(*ui1)) // But f1 in negative range?
return 1;
else // Positive
return 0;
}
else { // Equal exponents?
if(m1 < m2) { // Compare mantissas: f1 smaller
if(IEEE754_SIGN(*ui1)) // But negative?
return 0;
else // Positive
return 1;
}
else { // f2 smaller/equal
if(IEEE754_SIGN(*ui1)) // But negative?
return 1;
else // Positive
return 0;
}
}
}
}
```
Das sieht doch nur noch halb so kompliziert aus! Von hier ist es dann ein Kinderspiel zur migen
Umsetzung ('Python'!).
## 9. Das Projekt
Das Projekt-Repository findet sich [hier](https://git.hacknology.de/projekte/Risq5) auf unserem Git-Server.
Es enthält reichlich Kommentierung und vielleicht noch nützliche weitere Informationen zur Umsetzung (wenn
auch vermutlich zu wenig - wie immer ...).
## 10. Mängel
1. Das Ganze muß noch auf eine andere Zielplattform mit größerem FPGA verschoben werden (für jeweils volle
32 Integer & Float-Register)
2. Der Zugriff auf den Wishbone-Systembus durch die CPU selbst ist derzeit nicht vorhanden (weil ich das
Ding komplett von Scratch hochgezogen habe - und damit nicht analog zu den mit LiteX installierten
Alternativ-Kernen - 🗣 Depp!).
3. Dann kann auch das BIOS wieder aktiviert werden um überhaupt von Flash booten zu können ...
4. Die Performance ist wahrscheinlich recht gruselig (kein Pipelining, keine µOps) ... aber echte Messungen stehen noch aus.
5. Grausamer Flächenverbrauch (für einen echten Chip), schlechte Energiebilanz
6. fence/fence.i sind ohne Funktion (wie: nop)
## 11. Ausblick & Ideen
- Wenn man die Sache mit den Fließkommazahlen einmal verstanden hat, sollte es nicht schwer
sein, ähnlich aufgebaute Formate zu realisieren. Wie wäre es als Nächstes mit FP16 (gemäß
IEEE 754-2008) innerhalb eines KI-Beschleunigers? Mal schaun ...
- Mit diesem Rahmen könnte man sich eigentlich auch eine eigene 32-Bit ISA überlegen - vielleicht
mit einer Spezialisierung für bestimmte Aufgaben (DSP, ik hör' dir trapsen)?
Falls universelle ISA: Und dann den gcc anpassen - der Compilerbau soll ja einige Fortschritte
gemacht haben seit den Zeiten meines alten 'Dragon Books' ...
Interessante Möglichkeiten tun sich auf!

Loading…
Cancel
Save