Booting a Microblaze processor + software using Compact Flash

This post was written by eli on July 29, 2011
Posted Under: FPGA,Microblaze

This is a small guide to loading a standalone application + bitstream to an FPGA using the CompactFlash card. Or put otherwise, how to make the System ACE chip happy.

For loading a Linux kernel in the same way, I suggest referring to a special post in that subject.

Formatting the flash

Rule #1: Don’t format it unless you have to. And if you have to, read the System ACE CompactFlash Solution datasheet (DS080.pdf), in particular “System ACE CF Formatting Requirements” which basically says that if you format the flash under XP, it won’t work. To summarize it shortly,

  • Make it a FAT12 or FAT16, and not a FAT32 (the usual choice)
  • More than one sector per cluster
  • Only one reserved sector (XP may very well allocate more)
  • Maximum 2GB capacity (note that when it says 2GB commercially, it’s usually slightly less, but can be more. Partitioning is recommended)

It’s recommended to rewrite the partition table, as it may arrive messy. With fdisk, this is a desired final format (give or take sizes):

Disk /dev/sdd: 2017 MB, 2017419264 bytes
64 heads, 63 sectors/track, 977 cylinders
Units = cylinders of 4032 * 512 = 2064384 bytes
Disk identifier: 0x00000000

 Device Boot      Start         End      Blocks   Id  System
/dev/sdd1               1         977     1969600+   6  FAT16

NOTE: My Flash Disk appeared as /dev/sdd, yours may appear as something else. Don’t forget to fix this when running these commands, or you may wipe your hard disk!

Note the file system ID 6 (FAT16).  The card originally arrived with type 4, which is “FAT16 < 32MB”. To format the Compact Flash correctly in Linux, go (change sdd1 with the correct device, or erase something you didn’t want to):

# mkdosfs -R 1 -F 16 /dev/sdd1

And then verify that you got one single reserved sector (it’s likely you got it wrong):

# hexdump -n 32 -C /dev/sdd1
00000000  eb 3c 90 6d 6b 64 6f 73  66 73 00 00 02 20 01 00  |.<.mkdosfs... ..|
00000010  02 00 02 00 00 f8 f5 00  3f 00 40 00 00 00 00 00  |........?.@.....

The 16-bit word at 0x0e is the reserved sector count, as detailed in Wikipedia. If it isn’t as shown above, SystemACE won’t boot. Unfortunately, recent version of mkdosfs has a new “feature” which silently rounds up the number of reserved sectors to align with clusters. So it gets wrong. The solution for this is to downgrade this simple utility, possibly by downloading it from here. Version 3.0.9 is too new, 2.11 is fine.

Minimalistic setting

If there’s no xilinx.sys file in the root directory, and there is a file with an .ace extension, System ACE will boot from that file. Make sure there’s only one file with the .ace extension in flash’ the root directory. This setting doesn’t take advantage of the possibility to configure which image to boot from at powerup, but it’s easy to start off with.

Configurable setting

We shall now look on a setting which has only one .ace image to boot from, but is easily expanded to several images, chosen by the levels of three pins of the System ACE chip at powerup.

In the root directory, there should be a xilinx.sys file, saying something like this:

# Any comment goes here
dir = trydir;
cfgaddr0 = cfg0;
cfgaddr1 = cfg0;
cfgaddr2 = cfg0;
cfgaddr3 = cfg0;
cfgaddr4 = cfg0;
cfgaddr5 = cfg0;
cfgaddr6 = cfg0;
cfgaddr7 = cfg0;

The eight different cfgaddr lines tell the (Xilinx) System ACE chip which directory to go to, depending on the state of the three CFGADDR pins of the chip. So different profiles can be chosen from with DIP switches and such. In the case above, all eight configuration point at the same directory, cfg0.

The first line, declares the main working directory, which is trydir.

So in the case above, the root directory must have a directory called trydir, and within that directory, there must be a directory called cfg0.

And in cfg0, there must be a single file with .ace suffix, which is the ACE file to be loaded into the FPGA. Or more precisely, the ACE file is a translation of an SVF file, which is a sequence of JTAG instructions.

In order to allow configuration at powerup, create other directories (cfg1, cfg2 etc) and assign them to the desired cfgaddrN in the xilinx.sys file.

Generating the ACE file

Everything said here is related to the software arriving with ISE 13.2. It looks like there have been some significant changes from past versions.

In the Xilinx Platform Studio (EDK), pick Hardware > Generate bitstream on the processor configured. Basically, this generates netlists, builds them, and run the map, place and route and bitgen which creates a file such as system.bit.

Export the hardware format to SDK (Project > Export hardware design to SDK…), and then develop with SDK based upon that hardware. The bundle includes a hardware description as an XML file as well as the bitfile.

Once the project is built, it generates an .elf file, usually in the Debug subfolder. Its name and path is easily found in the Executable tab at the bottom of the SDK. Back in the EDK, pick Project > Select ELF file… and choose the relevant executable (for implementation). Then pick Device Configuration > Update Bitstream. That creates download.bit. This step is mandatory every time the ELF is changed, even though things will most likely work even without updating download.bit every time, since the relevant parts stay the same.

Create a directory to gather the relevant files, and copy the following into it:

  • The Tcl script generating ACE file: ISE_DS/EDK/data/xmd/genace.tcl (relative to the path where Xilinx ISE is installed)
  • The bitstream (download.bit) file
  • The ELF file

Open a command shell (Project > Launch Xilinx Shell if you like), change to this directory and go:

xmd -tcl genace.tcl -hw download.bit -elf myelf.elf -ace myace.ace -board sp605 -target mdm

which generates a lot of junk files (.svf most notably, which contain JTAG commands in a portable format), and eventually the myace.ace is created (any file name is OK, of course).

In the example above, I assumed that the target is the SP605 board. Looking at the genace.tcl script reveals easily which boards are supported. If it isn’t, it’s not such a big deal. The only reason the board matters is because the System ACE needs to know which device in the JTAG chain to talk with plus some programming parameters. The -board flags to this scrips allows setting the options in a “genace option file” (whatever that means). I would hack the script, though. It looks easier. See here for more information.

A test run

At times, the SP605 board’s green LED went on, but nothing happened. Pressing SYS_ACE_RESET is pressed (the middle button out of three close to the Compact Flash jack) caused a reload, which was OK. Probably some kind of race condition during powerup.


The walkthrough above is based upon this somewhat outdated guide. The BIST sources ( are indeed recommended for download, because of other issues of interest:

  • The ready_for_download subdirectory, which shows another example of a Compact Flash layout
  • The bootloader/src subdirectory, which has sources for loading executables from the Flash’ filesystem in SREC format (using sysace_fopen and the like).
  • The file in the ready_for_download subdirectory, showing how to create SREC files from ELFs with mb-objcopy.


Reader Comments

Newer versions of mkdosfs have a flag to disable the sector rounding behavior. Specify -a. There’s also a -v (verbose) flag that will print out all the parameters as it creates the filesystem to make sure it did it right.

Written By Phil Rutschman on May 23rd, 2013 @ 02:30

Hello Bill,

sudo mkdosfs -R 1 -F 16 -a /dev/sda1

The -a enforces it since:
Select the minimal number of reserved sectors. With FAT32
format at least 2 reserved sectors are needed, the default is
32. Otherwise the default is 1 (only the boot sector). Note
that this is minimal number and it may be increased by
mkfs.fat due to alignment of structures. See also mkfs.fat
option -a.

Written By Goran Marinkovic on November 29th, 2021 @ 14:05

Add a Comment

required, use real name
required, will not be published
optional, your blog address