Questasim on Ubuntu 16.04

Questasim on Ubuntu 16.04

Mentor Questasim is officially only supported on RHEL. However, I’m using Ubuntu 16.04 on my desktop, on which it won’t run by default. Here’s how to get that fixed. This probably works on all Debian-like systems.

Installation

As detailed in this blog post by Eldon Nelson, the installer won’t work if you only have 64-bit libraries installed. So, first step: installing 32-bit ones.

# apt install ia32-libs

Now Questasim can be installed, and its bin path added to your $PATH.

License manager

However, the FLEXnet license manager it uses won’t run. As shown in the mentioned blog post, you’ll get this error:

# lmgrd
bash: lmgrd: No such file or directory

ARM’s website says to solve this by installing a package that make Ubuntu completely Linux Standard Base, whatever that might mean:

# apt install lsb

This indeed fixes the license manager issue, and it’s at this point Eldon’s blog post ends. Unfortunately, that didn’t quite do the trick for me, because I still couldn’t actually run Questasim.

Linking code

Part 1 – Environment variable

The design I wanted to simulate requires SystemVerilog, Verilog, VHDL and SystemC, which means GCC is required. Questasim comes with its own bundled GCC 4.7.4, which compiled the code just fine. Unfortunately, linking generated the following errors:

${LONG_QUESTA_PATH}/ld: cannot find crti.o: No such file or directory
${LONG_QUESTA_PATH}/ld: something something -lc
${LONG_QUESTA_PATH}/ld: cannot find crt1.o: No such file or directory
collect2: ld returned 1 exit status

Now, first of all, let’s make sure these files are actually installed on the system. We’ll also need a linker later on, so let’s make sure that’s installed as well.

# apt install binutils g++-multilib

Now the issue is that in RHEL these .o files are in /usr/lib64, whereas on Ubuntu they are in /usr/lib/x86_64-linux-gnu. We could help the linker out a bit by setting the following environment variable:

# export LIBRARY_PATH="/usr/lib/x86_64-linux-gnu"

That only gets you so far though. The linker now finds the files but, as also described in this bug report, you will be greeted by the following error:

${LONG_QUESTA_PATH}/ld: /usr/lib/x86_64-linux-gnu/crti.o: unrecognized relocation (0x2a) in section `.init'
${LONG_QUESTA_PATH}/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status

This is because the GCC version that comes with Questasim is quite old. However, the object files we’re telling it to link with aren’t. At some point in time, the tools with which these .o files are compiled started adding extra information into them, which Questasim’s GCC 4.7.4 can’t handle. The system’s (newer) linker can though. So we somehow have to get Questa to compile everything using it’s own compiler and then link it using the system’s linker.

Part 2 – Replacing Questasim’s linker

There’s three ways to make Questasim use the system’s linker, the first two of which are discussed in the bug report mentioned earlier.

The first one is to supply sccom (Questasim’s GCC) with the “-B/usr/bin” argument. This tells GCC to look for binaries in /usr/bin when it calls ld to link. This solution works fine for compilation, but failed for me when actually running a simulation with vsim. While loading the design, vsim compiles another object file, encode_tramp.o, and linking it fails as before. As far as I could find, there’s no arguments to vsim equivalent to the “-B” flag for sccom/gcc. Another drawback of this method is that is requires modifying your build scripts.

The second way is to simply replace Questasim’s ld with the system’s ld. However, this requires you to have root access to the Questa install location. That rather crude and won’t work in many environments, e.g. in my case Questasim is installed on a central server and is mounted read-only over NFS. Furthermore, the installation might be used on different systems, in which case replacing ld for everyone is out of the question as well.

Still, replacing ld seems like the foolproof way to go. Which brings us to the third way. The solution is quite simple and elegant: use a union file system. Mount the existing Questasim installation as read-only in the union and on top of this mount a directory structure which contains a single symlink to the system’s linker. The beauty is that you can do this on only those systems that require it, without having to touch any of your build scripts or the Questasim installation itself.

The choices for such a setup are UnionFS, aufs or OverlayFS. Be warned though that there’s a bug with OverlayFS if the lower layer is an NFS read-only mount backed by certain file systems such as glusterfs. Since I ran into this bug, I used aufs instead.

# # Assuming Questasim install at /questasim-original
# mkdir -p /questasim-ubuntu/questasim/gcc-4.7.4-linux_x86_64/libexec/gcc/x86_64-unknown-linux-gnu/4.7.4
# ln -s /usr/bin/ld $_/ld
# mkdir /questasim
# # No need to modify the union, so mount as read-only
# mount -t aufs -o ro,br=/questasim-ubuntu:/questasim-original none /questasim

That’s it! Simply point your build scripts to the merged directory and enjoy Questasim on Ubuntu 16.04!

Automatically mounting the union

One minor issue with the solution so far is that the union mount will be gone when you reboot. If you have Questasim installed locally, you could simply add the mount information to /etc/fstab. That didn’t work for me though, because my Questasim installation is mounted by autofs over NFS. To work around this, I created a systemd service to mount the union once the Questasim installation is reachable. For the sake of completeness, here is how that works.

First I put together a short script to do the mounting. Note that it is rather specific, you’ll most likely have to adapt it a bit for your particular setup. I put this in /usr/local/sbin/mount_questasim.sh:

#!/bin/bash
# To be executed by e.g. systemd upon boot. Needs root access.

# Make sure automount is found.
PATH=/bin:/usr/bin:/sbin:/usr/sbin

# Don't do anything if mount already exists.
mount | grep --quiet '/questasim.*aufs' && exit 0

# Ensure autofs can access the questasim dir. Use automount so no
# iteration over multiple sources inside an automount is required.
automount -m | grep --quiet questasim || exit 1

# Make sure all required directories exist.
if [ ! -d /questasim-original ] || [ ! -d /questasim-ubuntu ] || [ ! -d /questasim ]; then
  exit 1
fi

# Make sure NFS directory is mounted by autofs, otherwise union mount fails
ls /questasim-original/ &>/dev/null

# Create the union mount
mount -t aufs -o ro,br=/questasim-ubuntu:/questasim-patty none /questasim

Next up, I created the following systemd service file in /etc/systemd/system/mount_questasim.service:

[Unit]
Description=Mount union fs on /questasim
Requires=nfs-client.target network-online.target autofs.service
After=nfs-client.target network-online.target autofs.service
RequiresMountsFor=/questasim-original

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/mount_questasim.sh

[Install]
WantedBy=multi-user.target

Then simply activate the service to run at boot:

# systemctl enable mount_questasim.service