(2) RISC-V Simulator

Erweitern Sie den RISC-V Disassembler um eine Befehlsabarbeitung. Implementieren Sie dazu die Registerbank, den Befehlsspeicher und den Datenspeicher als eigene Klassen (sofern Sie eine objektorientierte Sprache einsetzen).

Arbeiten Sie Befehl für Befehl ab, so wie die Befehle im RISC-V Instruction Set Manual (Volume 1) definiert sind. Geben Sie am Ende der Abarbeitung die Inhalte der Register auf dem Bildschirm aus.

Eine Implementierung der Peripherie ist nicht notwendig. Aus diesem Grund werden Funktionen wie printf() nicht funktionieren.

(1) RISC-V Disassembler

Entwickeln Sie ein PC-Programm (Beispielsweise in C, C++ oder Java), das ein RISC-V Compilat disassembliert. Es soll Anweisung für Anweisung auf dem Bildschirm ausgeben.

Implementieren Sie alle Befehle des RV32I – und des RV32M Befehlssatzes. Achten Sie dabei besonders auf die korrekte Behandlung der Immediate-Values (die ja „scrambled“, also durcheinander codiert sind).

Um Testdaten (Compilate) zu generieren, gehen Sie dabei wie folgt vor:

C in RISC-V übersetzen und Hex-File generieren

Um ein C-Programm bzw. einzelne C-Funktionen in RISC-V-Code zu übersetzen, kann das Programm per

riscv32-esp-elf-c++.exe -c -march=rv32im -mabi=ilp32 .\square.c

compiliert werden (im Beispiel square.c). Die Parameter rv32im und ilp32 definieren die Zielarchitektur: RV32I + Multiply. In diesem Fall keine Compressed-Befehle, die der ESP32-C3 aber unterstützt.Das entstandene .o-File kann dann per

riscv32-esp-elf-objcopy.exe -O ihex .\square.o .\square.hex

in ein Intel-Hex-File übersetzt werden. Der generierte Inhalt sieht dann so aus:

Diese Daten können dann händisch oder per Tool in den Simulator übernommen werden.

HexFile2CArrayConverter

Mit diesem Tool kann ein generiertes Hex-File in ein C Array konvertiert werden, um dieses anschließend im Programm weiterzuverwenden.

Ein typischer generierter Output ist:

// -------------- code begin, generated Wed Nov 08 11:00:31 CET 2023
static const uint8_t squarefct_0[] = {   

0x13, 0x01, 0x01, 0xFE, 0x23, 0x2E, 0x81, 0x00, 0x13, 0x04, 0x01, 0x02, 0x23, 0x26, 0xA4, 0xFE,    

0x83, 0x27, 0xC4, 0xFE, 0xB3, 0x87, 0xF7, 0x02, 0x13, 0x85, 0x07, 0x00, 0x03, 0x24, 0xC1, 0x01,

0x13, 0x01, 0x01, 0x02, 0x67, 0x80, 0x00, 0x00};


static const uint8_t* squarefcts[] = { squarefct_0};
static const uint32_t squarefct_startaddresses[] = { 0x00000000};
static const uint32_t squarefct_arraysizes[] = { 39};
#define SQUAREFCTCOUNT 1
// -------------- code end

Aufruf des Tools:

java -jar HexFile2CArrayConverter.jar

Synopsis: HexToCConverter <file.hex> <arrayname> [-w/-b]
  converts the given HEX file; the result will be printed in the terminal
    and also copied into the Clipboard.
  the name of the created array must be provided in <arrayname>. A C style name
    shall be used.
  use -w to generate arrays of words (uint32_t), -b arrays of bytes (uint8_t)

Vergleich von Sortieralgorithmen

Implementieren Sie die Sortierverfahren Selection Sort, Bubble Sort und Quicksort und führen Sie eine Geschwindigkeitsmessung durch. Verwenden Sie dafür mehrere Durchgänge in denen Sie Zufallsdaten erzeugen und diese jeweils mit den drei Verfahren sortieren.

Können Sie die in Sortierverfahren beschriebenen Aufwände bestätigen? Verwenden Sie die in Kapitel 3 beschriebene Instrumentierung zur Bestimmung der exakten Taktzyklenzahl.