In this tool-assisted programming video, I create a portable emulator for a certain architecture that can run Linux, using C++0x. The source code is about 780 lines in total.
Approximate count of lines of code per topic, in the source code:
All resources concerning this video can be downloaded from http://bisqwit.iki.fi/jutut/kuvat/programming_examples/microblaze/ . I do not own a MicroBlaze chip, nor any FPGA platform by Xilinx or anyone else. |
For the emulator programming example that I wanted to create, I started looking for the simplest possible platform that can run Linux, and from reading GXemul source code, I initially went with DEC Alpha.
However, after writing most of the CPU emulator for Alpha, I perceived that by adding the remaining parts, such as PALCODE emulation, the emulator easily grows far beyond what people could read and understand in 15 minutes (YouTube's currently enforced limit on my account). Thus I gave up with DEC Alpha.
Then, when studying QEMU source code, I learned about MicroBlaze.
I downloaded the official documentation of MicroBlaze, and found that it was possible to emulate it with a relatively few lines of code.
I had the kernel up and booting in a few days, but I ran into serious problems when trying to get userspace programs work. Turns out, the GNU toolchain for MicroBlaze is not as robust as I thought it would be. I won't enumerate the exact list of problems I had, but metaphorically speaking, I spent two weeks wading a poisonous swamp, trying to find a way around thorny bushes that seemed to extend for miles in all directions. It was quite exhausting.
Thanks to the MicroBlaze target GCC maintainer, Michael Eager, for being patient with me and my many questions and/or complaints.
In the end, I settled for less-than-perfect and this is what you have. After all, my focus was in the emulator, not in Linux...
Examples on how the MicroBlaze CPU differs from Intel 386/Pentium family (x86):
Apologies if the text's tininess bothers anyone. From my previous videos I received feedback suggesting that I should try to maintain a broader visual to the source code rather than zooming in at times for focus, so I did exactly that. I also experimented with some ways to keep the aspect ratio natural even as it varies. Tip: HD.
The ending cuts a few seconds short due to an unidentified encoding mishap. I put the text in annotations instead.
The music in this video is played through ADLMIDI using OPL3 emulation.
The songs are from SNES games Thunder Spirits, Bahamut Lagoon and Fire Emblem 4.
I do some tool-assisted voiceover in the video. I had great fun doing that, not taking my cumbersome pronounciation too seriously. English is very difficult to pronounce, very difficult sequences of consonants and sometimes hard to choose the right phonemes to begin with. In Finnish, my native language, having more than two consonants in a row is very rare, and even when there are two, the possible combinations are very few. I have been training my English pronounciation for years, but the entire language is a tongue-twister for someone with this background. I have found Hebrew and Japanese to be significantly easier.
Anyway, does anyone want to contribute closed-captions?
LIST OF FILES README This document mbemu.cc The emulator program showcased on YouTube. Compiles on DJGPP. mbemu-full.zip Contains a version of the emulator that compiles on Linux and that contains debugging. mbemu-dos-binary.7z Contains DJGPP-precompiled version of the DOS program, mbemu. simpleImage.7z Contains simpleImage.emu.ub ... The Linux kernel used in this demonstration, with U-Boot header. Contains precompiled kernel, precompiled initramfs (as above). rootfs2.7z Contains rootfs2.cpio.lzo ... The initramfs used for the root filesystem in the Linux system. Contains precompiled busybox. Compressed using LZOP. Extract it as follows (as root, because it creates device nodes): mkdir image cd image lzop -d < ../rootfs2.cpio.lzo | cpio -i Recreate as follows (does not need to be done as root): cd image find . | cpio --quiet -H newc -o | lzop -9 > ../rootfs2.cpio.lzo Contents: bin/busybox Modified Busybox 1.19.0 binary init, bin/*, sbin/* Busybox symlinks root/.*sh_history Fabricated shell history files. etc/*, etc/init.d/rcS Configuration and other files. patch-linux-3.0.4.txt The patch to Linux kernel version 3.0.4. Summary of changes: - Add configuration ( .config, arch/microblaze/boot/dts/emu.dts ) - Fix compilation preventing problem in arch/microblaze/include/asm/futex.h - Detect Microblaze 8.20.a - Fix compilation preventing problem in arch/microblaze/kernel/head.S ("lwr" not understood by binutils) - Add some debugging here and there patch-busybox-1.19.0.txt The patch to Busybox 1.19.0. Summary of changes: - Add configuration - Disable usleep/sleep where not necessary - Add a workaround in findutils/find.c (for some reason, the argv loop gets miscompiled otherwise, and ends up in an infinite loop). - Add explicit linkage against nss_files, nss_dns and resolv (somehow they ended up being required). patch-glibc-d05156fff63ddfec09bf6a74fe53deb37731e3ba.txt The patch to Xilinx's GLIBC. Summary of changes: - Fix fcntl.h to match what is actually used by the kernel. linux-.config The configuration used for Linux kernel. (Also included in patch-linux-3.0.4.txt) Configure used for binutils 2.21.1: ../binutils-2.21.1/configure --target=microblaze-xilinx-elf make ; make install Note: Installs to /usr/local/microblaze-xilinx-elf and /usr/local/bin ! Configure used for gcc-4.6.1: ../gcc-4.6.1/configure --target=microblaze-xilinx-elf make all-gcc ; make install-all-gcc Note: Installs to /usr/local/microblaze-xilinx-elf and /usr/local/bin ! Configure used for glibc: P=..../microblaze-unknown-linux-gnu (where mb_gnu_tools_bin.tar.bz was extracted) export PATH=$P/bin:$PATH export CROSS_COMPILE=microblaze-unknown-linux-gnu- ../glibc/configure \ --build=x86_64-linux-gnu \ --host=microblaze-unknown-linux-gnu \ --target=microblaze-unknown-linux-gnu \ --enable-add-ons=linuxthreads --with-elf \ --enable-multilib --with-sysroot=/ \ --disable-shared \ CFLAGS="-D__bluecat__ -O2 -mxl-multiply-high -mno-xl-soft-mul -mcpu=v8.10.a" \ --prefix=/microblaze-unknown-linux-gnu/sys-root/usr --enable-static-nss make make install install_root=$P Compiled Linux kernel as such: WITHOUT the $P path export CROSS_COMPILE=microblaze-xilinx-elf- make ARCH=microblaze simpleImage.emu Compiled Busybox as such: WITH the $P path make ARCH=microblaze menuconfig make ARCH=microblaze Copied busybox to the initramfs image. Linux kernel headers also installed from Linux-3.0.4 under the microblaze-unkown-linux-gnu root, but I do not remember the exact procedure by which I did it. lossless_encode.mkv Lossless encode (ZMBV) of the published video (283 MB, 4620x2400 resolution @ 30fps) hq_encode.mkv High quality encode (ZMBV) of the published video (88 MB, 1280x720 resolution @ 30fps) mq_encode.mkv Medium quality encode (ZMBV) of the published video (45 MB, 852x480 resolution @ 30fps)