MicroBlaze emulator example (written in C++0x)

Skip to the download section

First published at http://youtube.com/watch?v=1e0OCwlaEZM

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:
  • 80 lines, CPU: Registers and constants
  • 230 lines, CPU: Interpreting and parsing CPU opcodes
  • 80 lines, CPU: Exceptions and Interrupts
  • 100 lines, CPU: Memory Management Unit (MMU)
  • 50 lines, I/O framework: Memory map, endianness and integer sizes
  • 50 lines, Device: UART (console I/O)
  • 60 lines, Device: Timer
  • 50 lines, Device: Interrupt Controller
  • 20 lines, Loading of Linux kernel from disk file
  • 60 lines, (other, and inaccuracies in the above numbers)

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.
I just wanted to create an emulator that can run Linux, inspired by Fabrice Bellard's JSLinux at http://bellard.org/jslinux/ .

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)