From fdaf29f23571cb4bfb88f54370e37ad6db53375b Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Fri, 22 Apr 2022 13:18:30 +0200 Subject: [PATCH] initial commit --- .gitignore | 1 + .gitmodules | 3 + EMBARK | 1 + README.md | 134 ++++++++++++++++++++++++++++++++++ debugging.md | 32 ++++++++ hello-world.asm | 18 +++++ setup-scripts/setup-gcc.sh | 41 +++++++++++ setup-scripts/setup-python.sh | 21 ++++++ 8 files changed, 251 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 160000 EMBARK create mode 100644 README.md create mode 100644 debugging.md create mode 100644 hello-world.asm create mode 100755 setup-scripts/setup-gcc.sh create mode 100755 setup-scripts/setup-python.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ceb386 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +venv diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..216e061 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "EMBARK"] + path = EMBARK + url = https://github.com/AntonLydike/EMBARK diff --git a/EMBARK b/EMBARK new file mode 160000 index 0000000..a3cc3cc --- /dev/null +++ b/EMBARK @@ -0,0 +1 @@ +Subproject commit a3cc3cccbd1c804f3240f1adf6b2249dde9dab81 diff --git a/README.md b/README.md new file mode 100644 index 0000000..568de9b --- /dev/null +++ b/README.md @@ -0,0 +1,134 @@ +# RISC-V Playground + +Willkommen in dem RISC-V Playground! + + +## Installation + +*Dieser Schritt ist in der gelieferten VM bereits abgeschlossen* + + 1. Um den RISC-V Emulator zu installieren brauchst du Python 3 und den Python Package Manger pip. Unter Linux ist das in dem Paketmanager deiner Distribution enthalten. + 2. Installiere den Emulator als pip Paket (das Paket heißt `riscemu`): `pip install riscemu` + 3. Teste deine Installation mit `python3 -m riscemu --version`, es sollte mindestens Version `2.0.3` installiert sein. + + +## RISC-V Code Ausführen + +*Das folgende Beispiel findet auf der Konsole statt, der RISC-V Emulator hat nur ein Konsoleninterface. In Ubuntu kann mit hilfe des Kontextmenüs (Rechtsklick) im Dateibrowser die Eintrag "Im Terminal öffnen" ein Terminal öffnen, in dem bereits der Ordner geöffnet ist.* + +Betrachten wir das beispiel: `hello-world.asm` + +``` +# hello-world.asm +# print "hello world" to stdout and exit +.data + +text: .asci "Hello World\n" + +.text + li a0, 1 + la a1, text + li a2, 12 + li a7, 64 + ecall + + li a0, 0 + li a7, 93 + ecall +``` + +Das Programm kann auf der konsole mit dem dem Befehl `python3 -m riscemu hello-world.asm` ausgeführt werden. Dafür solltest du in der Konsole in dem gleichen Ordner wie dein assembly program sein. Es sollte das folgende Output in deiner Konsole erscheinen: + +``` +> python3 -m riscemu hello-world.asm +Hello World +``` + +Der emulator kann mit verschiedenen Parametern gestartet werden, z.B. kann mit `-v` die `verbosity` (die menge an Informationen die ausgegeben werden) erhöht werden. Das wiederholen der "v"s erhöht das level weiter. So wird z.B. mit dem ersten `-v` bei jedem Sprung das Sprungziel ausgegeben sowie mehr informationen über den Start und Stopp. Ab `-vv` wird jeder ausgeführte assembly Befehl ausgegeben: + +``` +> python3 -m riscemu -vv hello-world.asm + Running 0x00000110: li a0, 1 + Running 0x00000114: la a1, text + Running 0x00000118: li a2, 12 + Running 0x0000011C: li a7, 64 + Running 0x00000120: ecall +Hello World + Running 0x00000124: li a0, 0 + Running 0x00000128: li a7, 93 + Running 0x0000012C: ecall +[CPU] Program exited with code 0 +``` + +## Debugging + +Der RISC-V Standard hat einen befehl reserviert der als sogenannter "Breakpoint" agiert. Wenn der Emulator diesen befehl erkennt, wird ein interaktiver Debugger gestartet. Lass uns nun hinter den ersten `ecall` Befehl in `hello-world.asm` einen Breakpoint-Befehl einfügen: + + +``` +# ... +.text + li a0, 1 + la a1, text + li a2, 12 + li a7, 64 + ecall + ebreak # Breakpoint um den Debugger zu starten + + li a0, 0 + li a7, 93 + ecall +``` + +Wenn das Programm nun ausgeführt wird, erscheint das folgende Output generiert: + +``` +Hello World +Debug instruction encountered at 0x00000127 +[CPU] Debugger launch requested! + +>>> +```` + +Dies ist der interaktive Debugger. Hier kann der Zustand der Register, des CPUs und des Arbeitsspeichers betrachtet werden. Eine übersicht der wichtigsten Funktionen sind in der debugging.md Datei zu finden. + + +## Installation der RISC-V Gnu Toolchain + +*Auch dieser Schritt ist in der VM schon erledigt.* + +Für die Installatio unter Linux (Ubuntu) ist ein installationsskript beigelegt, welches die RISC-V toolchain für die Nutzung im Rahmen der Vorlesung konfiguriert und kompiliert. Ich bin mir nicht sicher ob die toolchain unter Windows kompilierbar ist, nehmt dafür am besten das [WSL](https://docs.microsoft.com/en-us/windows/wsl/install) + +Falls das Skript für eure Platform nicht funktioniert, hier noch ein paar tips: + + + - Ihr braucht ca 8 Gigabyte Festplattenplatz um RISC-V GCC zu kompilieren. (Ein teil kann nach der Installation gelöscht werden). + - In der [GitHub Readme](https://github.com/riscv-collab/riscv-gnu-toolchain#readme) findet ihr die genauen pakete, die ihr auf eurer Distro installierne müsst. + - Klont das Repository mit `git clone --depth 1 https://github.com/riscv-collab/riscv-gnu-toolchain.git` um nicht die ganze git history mit herunter zu laden. + - Konfiguriert die Installation mit dem folgenden Befehl (dafür müsst ihr in die geklonte repo rein `cd`'en): `./configure --prefix=$(pwd)/../toolchain/ --with-arch=rv32ima --disable-linux --disable-gdb --disable-multilib`. Der Zielordner muss unbedingt vorher angelegt werden! Also `mkdir $(pwd)/../toolchain/` (Legt den ordner `toolchain` im Überordner der Repo an). + - Baut den compiler mit allen verfügbaren threads: `make -j `. + +Nach der installation sollte es möglich sein C und RISC-V Assembly in RISC-V Objektdateien und executables zu kompilieren und den bytecode aus zu geben: + +``` +# "riscv32-unknown-elf" ist das präfix, und as der befehl für den Assembler: +> riscv32-unknown-elf-as hello-world.asm -o hello-world.out +# gleiches präfix, hier benutzen wir objdump um den Inhalt zu decodieren: +> riscv32-unknown-elf-objdump -SF hello-world.out + +hello-world.out: file format elf32-littleriscv + + +Disassembly of section .text: + +00000000 <.text> (File Offset: 0x34): + 0: 00100513 li a0,1 + 4: 00000597 auipc a1,0x0 + 8: 00058593 mv a1,a1 + c: 00c00613 li a2,12 + 10: 04000893 li a7,64 + 14: 00000073 ecall + 18: 00000513 li a0,0 + 1c: 05d00893 li a7,93 + 20: 00000073 ecall +``` diff --git a/debugging.md b/debugging.md new file mode 100644 index 0000000..afda757 --- /dev/null +++ b/debugging.md @@ -0,0 +1,32 @@ +# Debugging mit RiscEmu + +Der Debugger des Emulators kann mit dem `ebreak` Breakpint-Befehl gestartet werden. + +## Verfügbare Objekte und Funktionen + +In dem interaktiven Debugger sind folgende Variablen definiert: + + * `cpu` Der CPU der den `ebreak` gelesen hat + * `mem` und `mmu` ermöglichen Zugriff auf den Arbeisspeicher + * `regs` representiert die Register des CPUs + +Des weiteren sind ein paar hilfsfunktionen verfügbar: + + * `run_ins('name', 'arg1', 'arg2', 'arg3')` führt den befehl `name arg1, arg2, arg3` an der aktuellen Stelle im CPU aus. + * `step()` führt den nächte Befehl aus + * `cont()` beendet den debugger + * `dump(address)` gibt den Inhalt des Arbeitsspeichers an der Adresse `address` aus, das Verhalten der Funktion ist durch einige Parameter anpassbar, die später weiter erklärt werden. + + + +## Die `dump()` Funktion + +Mit hilfe dieser Funktion kann der Arbeitsspeicher angezeigt werden. Die Signator der Funktion ist etwas komplexer: + +`dump(start, [end], [fmt], [bytes_per_row], [rows], [group], [highlight])` + +Es ist möglich einen festgelegten bereich an zu zeigen, in dem `start` und `end` angegeben werden. Es ist auch möglich nur `start` zu verwenden, dann werden `rows` (standardmäßig 10) zeilen um die adresse `start` herum ausgegeben, und die Werte an der Adresse hervorgehoben. Eine andere Stelle zum hervorheben kann mit `highlight` bestimmt werden. + +Mit `bytes_per_row` kann angegeben werden, wie viele bytes pro zeile ausgegeben werden, und `group` gibt an, wie viele bytes zusammen zu einem Wert gruppiert werden (z.B. praktisch um 32bit Inteegers an zu schauen). + +Das Ausgabeformat kann mit dem `fmt` Argument angegeben werden, standardmäßig ist das `hex`, andere möglichkeiten sind `int`, `uint` für Ganzzahlen und `char` für Ascii-Text. diff --git a/hello-world.asm b/hello-world.asm new file mode 100644 index 0000000..2560dcb --- /dev/null +++ b/hello-world.asm @@ -0,0 +1,18 @@ +# hello-world.asm +# print "hello world" to stdout and exit +.data + +text: .ascii "Hello World\n" + +.text + li a0, 1 + la a1, text + li a2, 12 + li a7, 64 + ecall + + + + li a0, 0 + li a7, 93 + ecall diff --git a/setup-scripts/setup-gcc.sh b/setup-scripts/setup-gcc.sh new file mode 100755 index 0000000..8cf2f85 --- /dev/null +++ b/setup-scripts/setup-gcc.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# this script installs https://github.com/riscv-collab/riscv-gnu-toolchain + +set -eu + +if ! command -v apt &> /dev/null +then + echo "This script was written for Debian based Linux Systems. It seems like \ +you are using something else. Please change this script to work with your OS." + echo "You can find further infos at https://github.com/riscv-collab/riscv-gnu-toolchain" + exit 1 +fi + +function print_step { + echo "===========" + echo -e ">>> \033[0;36m $@\033[0m" + echo "===========" +} + +if test -d riscv-gnu-toolchain; then + echo "Skipping steps 1..3" + cd riscv-gnu-toolchain +else + + print_step "[1] Installing dependencies" + sudo apt-get install -y autoconf automake autotools-dev curl python3 libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev git + + + print_step "[2] Cloning repository" + + git clone --depth 1 https://github.com/riscv-collab/riscv-gnu-toolchain + + print_step "[3] Configuring build" + cd riscv-gnu-toolchain + ./configure --prefix=$(pwd)/../toolchain/ --with-arch=rv32ima --disable-linux --disable-gdb --disable-multilib +fi + +print_step "[4] Compiling" +echo "This might take up to an hour! Be patient!" +# call make with as many threads as the system has available +make -j $(grep -c ^processor /proc/cpuinfo) diff --git a/setup-scripts/setup-python.sh b/setup-scripts/setup-python.sh new file mode 100755 index 0000000..1b49712 --- /dev/null +++ b/setup-scripts/setup-python.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# this script sets up a python virtual environment + +if ! command -v apt &> /dev/null +then + echo "This script was written for Debian based Linux Systems. It seems like \ +you are using something else. Please change these scripts to work with your OS." + exit 1 +fi + + +sudo apt install -y python3 python3-venv python3-pip + +if [ ! -d venv ]; then + python3 -m venv venv +fi + +source venv/bin/activate + +pip install --upgrade riscemu +