Contents

This section is a loose collection of tips, tricks and know-abouts about Embedded Linux, Xilinx Virtex-II-Pro FPGAs and the Xilinx ML300/ML310 development boards. If you find this page useful or have any suggestions, please contact me.

Please choose your destination:

    . Xilinx ML300/ML310 Prototyping Boards (2005-01-15)
    . Porting Linux to the ML300 (2004-01-17, updated 2005-01-15)
    . Booting Linux from an ACE file (2004-03-06)


Xilinx ML300/ML310 Prototyping Boards  2004-01-17, updated 2005-01-15

The Xilinx ML300 and Xilinx ML310 are prototyping boards targeting on the development of embedded systems and systems-on-chip. Both boards boast a Xilinx Virtex2Pro FPGA with one (ML300) respectively two (ML310) integrated PowerPC cores (PPC405). The PPC CPUs are clocked at 300MHz+. They connect to the extensive list of I/O devices by means of IBM's CoreConnect bus architecture.


Xilinx ML300

Xilinx ML310

Here is an excerpt from the ML300's list of features:

  • V2P7-FF672 FPGA with 11,088 logic cells (130nm fabric)
  • 4 gigabit ethernet ports
  • 10/100 ethernet
  • 128 MB DDR SDRAM
  • 1GB IBM Microdrive for startup configuration via SystemACE
  • 6,4" VGA TFT with touchscreen
  • AC97 audio codec
  • 32 external general purpose I/Os
  • COM, USB and parallel ports

The board ships with the soft logic analyzer ChipScope Pro. This tool provides the ability to embed logic analyzer and bus analyzer cores into the FPGA design. Thus it enables all the internal signals and nodes within the FPGA to be viewed without the need of a hardware logic analyzer.

The ML310 is a more sophisticated board featuring the far bigger V2P30. This reconfigurable logic device offers two PPC405 cores, 30,816 reconfigurable logic cells, and 2,448 Kbits of on-chip memory. The ML310 comes in ATX form factor and has 4 PCI slots as well as 122 external general purpose I/Os. Thus it is suitable for a broad range of applications.

Proposed operating systems include Linux and WindRiver VxWorks RTOS. A commercial Linux port is offered by MontaVista, but due to the GPL, all relevant device drivers are available for free.


Porting Linux to the ML300  2004-01-17, updated 2005-01-15

In this section you'll find a short description on how to port Linux to the ML300. Some parts of this tutorial assume that you use the Xilinx EDK 3.2 (Embedded Development Kit) and hence are somewhat outdated. For a guide on how to incorporate the driver library (BSP) of Xilinx EDK 6.x, check this great site from Dan Burke, James Player, and Nach Navarro.

    1. Getting the kernel sources
    2. Configuring the kernel
    3. Building a PowerPC cross compile toolchain
    4. Compiling the kernel
    5. Booting the kernel via JTAG
    6. Building the root filesystem
    7. Mounting the root filesystem via NFS

1. Getting the kernel sources

At first you need to pick up the Linux for PowerPC kernel sources. You either can download the official kernel tree from www.kernel.org and apply the latest PowerPC patches, or you chose to get a clone of the current linux-ppc development tree with BitKeeper. BitKeeper is a source control system (similar to CVS) and is traditionally used for PowerPC kernel development.

To get the ppc-kernel-2.4 development tree, install BitKeeper on your Linux box (gentoo users do a emerge bitkeeper) and type:

$ bk clone bk://ppc.bkbits.net/linuxppc_2_4_devel <directory>
If you experience problems, try the MontaVista mirror:
$ bk clone bk://source.mvista.com/linuxppc_2_4_devel <directory>

You could download the current kernel 2.5 sources, too, but I wouldn't recommend that by now for the ML300. For completeness, here's the command:

$ bk clone bk://ppc.bkbits.net/linuxppc-2.5 <directory>

Now take a look at the newly acquired sources. Unless you're familiar with BitKeeper, you'll possibly wonder where all the downloaded files hide out. Since BitKeeper is a version control system, it doesn't download the latest version of the kernel sources only, but also all preceding changes. To extract the latest version from these incremental change files, type:

$ cd <directory>
$ bk -r edit

If you plan to extend, hack or patch the kernel sources by yourself (you are going to become a highly gifted kernel developer), you should create a local clone of the BitKeeper tree, which is related to the local tree, not to the official. This ensures that any updates first go to the local repository:

$ bk clone <my_parent> <local_clone>

After downloading the ppc kernel sources -- I currently use version 2.4.21, which works well for me -- you should pause for a moment and think about a wise directory structure. Later in development, when you decide to write shell scripts for doing recurrent jobs, it can be very useful to work with suitable directory names. My development tree looks like this:

  ml300_linux -- ppc linux sources
  ml300_rootfs -- sources and scripts for building the root filesystem for the ML300
  ml300_toolchain -- gcc powerpc cross compiler toolchain
  ml300_fpga -- ressources for building the v2p fpga configuration (from Xilinx EDK)
  ml300_bsp -- ressources for building non-linux applications for ML300 (from Xilinx EDK)
  ml300_demos -- small demo programs for playing around with the ML300


2. Configuring the kernel

Now that the sources are there, it is time to play around with the build configuration. Edit the root Makefile and change the line beginning with "ARCH := " to

ARCH := ppc
Then Type
$ make menuconfig
or, for a graphical TCL/TK frontend
$ make xconfig
to compile and run the kernel configuration tool. Enable and disable features to one's heart content, but don't worry if you experience sticky compiler error messages during the build process (which is described in section 4). There are a lot of configurations that won't work for the ML300. But with a little patience, it is possible to discover the perfect combination.

Thanks to MontaVista and Xilinx, there already are a lot of device drivers for the ML300 available. These include drivers for the TFT display and touchscreen with framebuffer support, the SystemACE interface, the UART-lite serial port, the ethernet controller and other peripherals.

With some of the ML300 device drivers I experienced problems due to missing constant definitions. Definitions for the use of Hardware-IP blocks concerning address ranges etc. are recorded in the file arch/ppc/platforms/xilinx_ocp/xparameters_ml300.h. This file is auto-generated by the Xilinx EDK. You should replace or merge it with your own version (in your Xilinx EDK directories) if you experience the same problems.

Here are some must-have options for the ML300 kernel configuration:

+- Code matury level options
   +- Prompt for development and/or incomplete code/drivers
	 +- Prompt for advanced kernel configuration options
+- Platform support
   +- (40x) Processor Type
	 +- (Xilinx-ML300) Machine Type
+- Networking device support
   +- Ethernet (10 or 100MBit)
      +- Xilinx on-chip ethernet
+- Console drivers 
   +- Frame-buffer support 
      +- Xilinx LCD display support
         +- Rotate display
+- Character devices 
   +- Virtual terminal
      +- Support for console on virtual terminal
   +- Standard/generic serial support
	 +- Xilinx on-chip GPIO
	 +- Xilinx touchscreen
To prevent compilation errors, make sure the following option is excluded:
+- Character devices 
   +- /dev/agpgart (AGP Support)  <-- DISABLE
If you don't feel like being plagued with configuring the kernel, you can download my favorite kernel configuration here: ML300 linux-ppc-2.4.21 kernel configuration. Copy this file to the top-level directory of your kernel sources.


3. Building a PowerPC cross compile toolchain

This step describes the process of building a gcc 3.3.x cross compile toolchain for the ML300. You can generously skip to step 4 if you already count a PowerPC cross compile toolchain to the things that are installed on your system.

Suppose you're sitting in front of a Linux or Solaris box and have a working gcc 3.3.x compiler toolchain, that's quite good for the beginning. Unfortunately, you can't use this compiler for building the ML300 Linux, since it will produce binaries that run on your build system, not on the PowerPC. Accordingly, what you need is a PowerPC cross compiler, which in fact runs on your build system but produces binaries for the PowerPC.

The process of compiling a gcc cross compiler is somewhat difficult. There are a lot of traps you can run into, and it takes a lot of time to read through the vast amounts of available documentation which give an idea of how the gnu compiler collection is composed. Luckily Dan Kegel composed a really cool shell script (thanks, Dan), which does all the work for you. The script, Crosstool, even downloads missing sources and patches.

To build your PowerPC toolchain, download Crosstool and untar. Edit the file demo.sh and uncomment the line

eval `cat powerpc-405-native.dat` `cat gcc3.3.1-glibc2.3.2.dat` sh all.sh --notest
Make sure that all other lines are commented out. To have the build process run through gratifying, declare the following variables:
$ export TARGET=powerpc-405-linux
$ export PREFIX=/opt/${TARGET}
PREFIX defines where the binaries will be installed. If you leave it undefined, it defaults to /usr/local, which may be just fine if you have root permissions on the host machine.

Make sure the installed binaries will be in your search path

$ export PATH=${PREFIX}/bin:${PATH}
and launch Crosstool:
$ sh demo.sh
Depending on your machines capabilities, this can be a long long process. Tons of log messages will scroll by. You can review them in the file demo.log. I recommend having an extensive and refreshing trip on inline skates for this kind of situations.


4. Compiling the kernel

Finally, the gcc cross compiler is standing by and the kernel configuration is settled. Open the root Makefile with your favorite editor and change the line beginning with CROSS_COMPILE to

CROSS_COMPILE = powerpc-405-linux-gnu-
Now type the magic words:
$ make dep && make zImage && make modules
Did it run through without any error? Wow, congrats! Otherwise don't worry. You'd rather get familiar with it, because you reached the point where the thrilling phase of identifying and fixing errors begins :-)


5. Booting the kernel via JTAG

Holding a freshly squeezed PowerPC Linux kernel image in your brave hands, you should give it a try. Therefore we'll make use of the JTAG interface on your ML300 board. Connect the Xilinx parallel cable IV with the ML300 and your PC and start the gnu debugger powerpc-eabi-gdb from the Xilinx board-support-package as follows:

$ cd <your ppc-linux directory>
$ cp arch/ppc/boot/images/zImage.elf <your test directory>
$ cd <your test directory>
$ powerpc-eabi-gdb -nw zImage.elf
At the gdb prompt, type the following commands:
set architecture powerpc:405
target ocd xilinx
set download-write-size 0
load
Note: you can automate this process by creating a text file with the name gdb.ini and copying the commands from above into this file.

gdb now should have uploaded the image (which takes a while) and your kernel should boot. When frame buffer support was enabled in the kernel configuration, you should see the boot messages on the TFT display. Otherwise connect a nullmodem cable to the ML300's serial port COM1 and watch the messages scroll by on a terminal window (e.g. miniterm).

However, the boot process will come to an abrupt stop when the kernel tries to mount the root filesystem. Building and mounting a root filesystem is covered by the next chapter. Since booting via JTAG again and again can be quite annoying, chapter 7 will describe how to build an ACE file which can be copied to the microdrive. Afterwards the system will boot from the microdrive within only a few seconds.


6. The root filesystem

The root filesystem (rootfs) must at least contain those programs that are necessary to gain a running Linux system. After mounting the rootfs, the kernel starts the init process, which is "the mother of all processes". init (which incidentally resides in /sbin) parses the file /etc/inittab and runs the commands contained in it. A simple inittab could look like the following:

::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r
::restart:/sbin/init
::respawn:/sbin/getty 115200 tts/0

Besides init, there are a lot of programs necessary to create a running and, above all, a useful Linux system. Namely, these are basic file utilities like ls or cat, system tools like mount and ifconfig and, last but not least, a command shell like bash or tcsh.

Building Linux from scratch can be a long and time-consuming process, in particular on embedded systems. Even though the above-mentioned programs all are available as tarballs on the net, many of them were not initially designed for cross compile. Hence, a lot of patching and hacking is required when going to compile some of them for the ML300 or rather PowerPC.

6.1 BusyBox

In order to sail around the above-mentioned problems but yet don't go without the Linux shell utilities, I use BusyBox. BusyBox is a superb all-in-one utility, which gathers all important and/or useful utilities in one single binary. It comes with a kernel-like configuration interface and is indented to be cross compiled.

Download the latest BusyBox archive from www.busybox.net and untar it to your ${HOME}/ml300_rootfs directory. Change into this directory and run

$ make menuconfig
Be sure to enter the correct cross compiler prefix at the build options section. In the installation options section, enter the target directory. On my system, this is /tftpboot/ml300_rootfs. In step 7 we will mount this directory on the ML300 via NFS (network file system).

6.2 mkrootfs

Since building the root filesystem consists of quite a lot of steps, it seems likely to write a shell script. You may download my script

mkrootfs
at your convenience. In addition, this tarball contains an example /etc directory tree with samples for all necessary system configuration files.

Before use, mkrootfs.sh must be configured. To this end, only a few variables in the first lines of the script have to be altered.

mkrootfs.sh builds a fully functional userland for your ML300 from scratch. It does not only create the entire linux directory structure, but also takes care of putting inittab and other important config files to the right place. Furthermore, as described below, somewhat existing kernel modules are copied to your rootfs and the glibc libraries from your cross compiler are dealt with.

Feel free to extend the script to fulfill your special requirements. I'd really be glad to receive advancements from you.

6.3 Kernel modules

If you want to use kernel modules on the ML300, you possibly have noticed that make modules_install fails with an error message. This happens because the built-in depmod tool cannot generate the module dependencies on the build system when cross compiling. In order to solve this problem, the perl script depmod.pl is included in the mkrootfs tar archive that you can download above. Copy depmod.pl and make_modules_install.sh to your ml300_linux directory and run make_modules_install.sh everytime when you want to recompile your kernel modules (maybe you'll have to adapt the linux version number in make_modules_install.sh).

Afterwards, the script mkrootfs automatically copies the kernel module binaries to your ML300 root filesystem.


7. Mounting the root filesystem via NFS

During the development process of an embedded device it is desirable to have the possibility of changing the contents of the root filesystem on- the-fly. To this end, we'll use Linux' capability to mount the root filesystem via NFS (network file system). But first, the ML300 FPGA has to be configured properly for making use of the on-chip 10/100 ethernet module. Xilinx EDK (Embedded Devlopment Kit) includes an IP core for the ethernet PHY on the ML300. The accessory device driver is already included with the ppc_linux-2_4_devel tree. Thus, in the first place create a FPGA bit file that includes the Xilinx ethernet IP core. Secondly, enable the Xilinx on-chip ethernet driver in your Linux kernel configuration.

7.1 Preparing the Linux kernel

Type make menuconfig and activate the following options:

+- Networking options
   +- TCP/IP networking
      +- IP: kernel level autoconfiguration
         +- IP: BOOTP support       	    	
+- File Systems 
   +- Network File Systems 
      +- NFS file system support
      +- Root file system on NFS
Do not enable the DHCP and RARP options, since we want Linux to use the bootp method and only the bootp method for searching the rootfs NFS server.

7.2 Installing and setting up the bootp server

Bootp is a simple protocol that helps clients to discover network boot servers. The client sends an ethernet broadcast frame and waits for answers. The server responds with a bootp frame, containing it's own IP address, the directory of the root filesystem and the IP address for the client. Afterwards, the client configures it's TCP/IP networking by using the just received parameters. On success, the client mounts the root filesystem via NFS as announced by the server.

On your Linux host, install bootpd as a bootp server. Create a file /etc/bootptab with the following content:

.default:\
	:ht=ethernet:\
	:hd=:bf=null:\
	:sm=255.255.255.0:\
	:hn:
	
# ML300
ml300:tc=.default:rp=/tftpboot/ml300_rootfs:ha=000A350010A0
Replace 000A350010A0 with the MAC address of your ML300 board (as printed on the label that can be found at the flip side of the power board).

You either can start bootpd manually as root or let xinetd do the job. For the latter case, add a file bootp-DD2 to your /etc/xinetd.d directory and insert the following lines:

service bootpd
{
	socket_type	= dgram
	protocol	= udp
	wait		= yes
	user		= root
	group		= root
	server		= /usr/sbin/bootpd
	server_args	= -c /tftpboot
	disable		= no
}

7.3 Installing and setting up the NFS server

Most Linux distributions come with a pre-installed NFS server. Otherwise, fetch the packet nfsd and follow the installation instructions. The authorization of remote accesses is configured with the file /etc/exports. Add the following line, in order to achieve that your ML300 mounts it's root filesystem via NFS:

/tftpboot ml300(rw,no_root_squash,sync)
The option no_root_squash is important. It prevents the nfs server to map root (uid 0) accesses from the ML300 to another uid (which is usually done for security reason).

At last, when your bootp and nfs servers are properly configured and running, you're done! Your ML300 now should boot as if by magic :-)


Booting Linux on the ML300 from an ACE file  2004-03-06

When developping hardware and software with your Linux-driven ML300, you soon might consider booting Linux via JTAG to be quite annoying. Luckily, Xilinx equipped the ML300 with the capability to boot it's operating software from the flash interface. In this section I will briefly describe how to embed the Linux kernel into a bootable SystemACE file, which will reside on your IBM Microdrive.

1. Development Tools

In order to create a bootable SystemACE file, I use the Xilinx Embedded Development Kit design flow from EDK 3.2. Therefore, the following tools have to be installed:

  • Xilinx EDK 3.2
  • Xilinx ISE 5.1i or newer

To simplify matters, I assume that your tools are installed on a Linux box. Obviously the following steps can be done on a Windows PC, too.

With EDK 3.2 under Linux, I first had some problems with the shell script v2pro_setup. This script sets up some environment variables and seems to be originally written for tcsh. Hence, my bash didn't like it. As a work-around I wrote the following script, which can be sourced into ${HOME}/.bashrc:

#!/bin/sh
export V2PRO=/opt/cad/ml300  # the place where your EDK resides
export V2PRO_HOST_OSTYPE=linux
export XILINX_GNUTOOLS=$V2PRO/tools/linux/gnu
export PATH=${XILINX_GNUTOOLS}/bin:${V2PRO}/tools/${V2PRO_HOST_OSTYPE}/xilinx/bin:${PATH}
export CORECONNECT=${V2PRO}/CoreConnect
export BFC_SIM=verilog
export OPB_DCL=${CORECONNECT}/tk/TOOLKIT_DCL/
export PLB_DCL=${CORECONNECT}/tk/TOOLKIT_DCL/
export DCR_DCL=${CORECONNECT}/tk/TOOLKIT_DCL/
export PATH=${V2PRO}/proc_coregen:${PATH}
export XIL_CG_LICENSE_DIR=${V2PRO}/proc_coregen/.Xilinx/Coregen/CoreLicenses
export MANPATH=${XILINX_GNUTOOLS}/man:${MANPATH}
if [ ! -z "${LD_LIBRARY_PATH}" ]
then
    export LD_LIBRARY_PATH=${V2PRO}/tools/linux/xilinx/bin:${LD_LIBRARY_PATH}
else
    export LD_LIBRARY_PATH=${V2PRO}/tools/linux/xilinx/bin
fi

2. Creating the ACE file

Since the Virtex-II Pro Platform FPGA Developer's Kit gives a detailed description of the FPGA design flow, I here will provide a brief step-by-step tutorial only.

Step 1: Change to the ${V2PRO}/platforms directory and create a copy of the ml300_embedded_verilog directory tree. Place this copy into ~/ml300_fpga.

Step 2: Change to the ${V2PRO}/source directory and create a copy of the sw and sw_old directory trees. Place these copies into ~/ml300_bsp.

Step 3: Change to your ${HOME}/ml300_fpga directory. Open flow.cfg with your favourite editor and change the following lines to the values given below:

USER_SW_APP  = bootloop
USER_SW_TYPE    = release
USER_SW_TARGET  = 0
SW_MAKE         = make -C ../ml300_bsp/sw/apps/$(USER_SW_APP)/src \
                  clean app_ml300_$(USER_SW_TYPE) SIM=$(USER_SW_TARGET)
SW_ELF          = ../ml300_bsp/sw/apps/$(USER_SW_APP)/build/ml300/\
                  $(USER_SW_TYPE)/$(USER_SW_APP).elf
NGDBUILD_OPT    = -nt on -verbose
MAP_OPT         = -pr b -detail
PAR_OPT         = -ol high -xe 1
TRCE_OPT        = -v 10 -skew
BITGEN_OPT      = -g userid:0x11090223 -g GWE_cycle:Done -g GTS_cycle:Done \
                  -g DriveDone:Yes -g DCMShutdown:Enable
NGD2VER_OPT     = -ne
DOWNLOAD_TYPE   = ace
If you have access to Synplicity's verilog compiler Synplify, you'd like to change the following lines, too:
SYN_TOOL = synplicity
SYN_CMD = synplify_pro
SYN_OPT = -batch
By specifying bootloop as user application, we instruct EDK to build a small ACE file which only consists of the FPGA hardware configuration and a tiny stable startup application in the BRAM memory. The various options for ISE's place and route process ensure that highest effort is made to optimize the hardware configuration.

Step 4: Give it a try:

$ cd ~/ml300_fpga
$ make fpga && make bit
Since the FPGA is really full with the default configuration, this step takes ~40 minutes on my 3GHz P4 machine. Our multiprocessor Solaris box doesn't make it better, though.

Step 5: Now everything is prepared to embed Linux into your ACE file. Again, edit flow.cfg and change the following lines (assuming that your linux-ppc sources reside at ~/ml300_linux):

SW_MAKE =
SW_ELF  = ../ml300_linux/arch/ppc/boot/images/zImage.embedded
Let EDK have a close look at your Linux kernel image:
$ make download
If it found it useful, you now should have a somewhat large top.ace file in your par/v2p subdirectory. This file combines your FPGA hardware configuration with the embedded Linux kernel and causes the ML300 to automatically boot the kernel after programming of the FPGA was done.

3. Downloading the ACE file

The last remaining thing to do is copying the top.ace file onto your Microdrive. You can either copy the file to the root directory (and delete all other stuff on the drive) or make use of SystemACE's multi-boot feature. For the latter, take a look at the initial directory structure of your Microdrive and make sure that the SystemACE MODE switch is set properly.

Now re-insert your Microdrive into the ML300 and turn on the main power. If all went well, Linux should come up after a few seconds. Keep in mind that it takes a while until Linux enables the TFT display. If you want to watch some early boot messages, enable the corresponding option in your kernel configuration and connect a serial console to your ML300.


Copyright © 2004-2006