BG/Q designersim

The BG/Q designersim tools streamline the testing of new VHDL. You can perform verification on your component with no Fusion knowledge, exploring the design and getting a cleaner component before you integrate.
run until cycle == 250 || Slow_count_q >= 0xFEABC;
warn "Timeout never fired" if cycle == 1000 and Timeout == 0
rndput Wrdata if Ack == 1


Simulation setup:

  1. If you've never run the tools before, see here.
  2. Getting new VHDL into designer sim consists of a single step, running newdir. It will prompt for unit name (VHDL library) and entity.
  3. The tool sets up a working directory under designersim in the bgq tree.  It will offer to compile the VHDL and build a model.
  4. When newdir completes, press middle mouse button, then enter. This takes you to the working directory for simulation.

Starting a simulation:

  1. Starting simulator: From working directory, run desi for interactive sim.
  2. Starting waves:  Type mantis  from the desi command line to start the waveform viewer. Run at least one cycle first; the waves won't come up without a non-zero-length AET file. In Mantis, press Alt-6 (or select Windows->AET control)  to bring up the small AetControl window. (If you are running Hummingbird Exceed, use the Alt key at the right of the spacebar). 

Running simulation:

  1. run to advance time.  Signal setting/viewing commands. myperl user scripts.
  2. Updating waves: Press Reload in the AetControl window, or  hold Alt and press 6R.
  3. Writing and running scripted routines: add them to the file myperl; run reload to pick up the changes

Iterating on a design:

  1. Compile: respin from the desi command line rebuilds the VHDL and returns simulation to the current point, or displays the logfile if compilation fails.
  2. The waveform window can stay up between simulations. It's OK for the AET to be overwritten, even by a shorter AET. The Reload button will show the new waveform.

If you've never run the tools before:

  1. The tools run only under Linux. They've been tested in the bg machines in the Linux cluster. They do not work on the pcserv machines that are still running FC3.
  2. If you haven't already, set the environment variable BGQHOME in your login profile (.bashrc, .cshrc, etc). This is the path up to but not including your bgq directory. If you don't yet have a bgq directory, the the tool will create one at $BGQHOME.
  3. Add $BGQHOME/bgq/hwsim/src/fusion/designersim to your path.
  4. For the newdir step, run /gsa/yktgsa/projects/b/bgq/web/verification/designer_sim/newdir. If you don't have a hwsim directory or ddx directory, newdir will offer to install them. newdir will also install itself, so you no longer need to use the path.
  5. To stay abreast of designersim updates, subscribe to the designersim_envt category in Issues.


What's covered here

This document describes an interactive interface to the Mesa simulator, driven by interactive commands and Perl scripts, for early debug and small-scale semiautomated verification.

The environment doesn't synthesize stimulus or checkers. You write these. But it does away with routine tasks like hooking up clocks and declaring signal names, and lets you drive and observe your design with high-level commands. The hope is that simple tests are simple to write, that getting a design into simulation is effortless, and that design-compile-debug iteration is fast and straightforward.

Part of the motivation for this environment is that the same environment, and same simulator, can also be hooked up with more complex and production-oriented tools -- FLite for stimulus and checking, and Fusion for interfacing with other tools (Bugspray, PSL). The environment in fact uses both. 

Signal names

Signal names used in desi are net names with the first letter capitalized:

reset        Reset
  → Slow_clock_q

To select a bit, use parens:


To select a bit range, use comma or dot-dot (not colon); the notations are equivalent:



Dots in the net name (for hierarchy) are changed to underscores, as are hashmarks (on signals created by Portals from VHDL generate statments) and percent marks (from who knows where):

ctrl.reset  Ctrl_reset

CLEAR_F.LL.BIT#0.LP.ZZ.VITALBEHAVIOR.L1CLK →  Clear_f_ll_bit_0_lp_zz_vitalbehavior_l1clk   

It's possible that the underscore mapping will give the same name to more than one net; the tool reports this:

        (W) Multiple nets map to signal name Dut_lu_srt_en: DUT.LU_SRT_EN and DUT.LU.SRT_EN at /ltmp/bjn/bgq/hwsim/src/fusion/designersim/ line 198, <$LNET> line 456.

This isn't automatically a problem. It matters only if these are signals you plan to manipulate through desi (there's no effect on Fusion or Mesa). There's a mechanism to sidestep the problem; see me.

If a default name is cumbersome, it's easy to alias a shorter one:

sub Little_me {Bicstop_fast_ll_bit_0_lp_zz_vitalbehavior_l1clk(@_)};

Remember to follow the capitalization convention and append (@_) as shown; that allows bit ranges in the alias to be transferred to the real signal. 

You can drop a vhdl netname from the X clipboard to the command line using xg, which translates it to a desi signal name.

Signal values

0x for hex, 0b for binary, otherwise, decimal. There's no convenient way to denote octal. Leading 0 is not treated as octal. No quotes.

(Cyc:0) st Reset, 10
        trimming 0xa to 0x0 to fit bit range 0..0

You can insert underscores for readability:

(Cyc:97) $x = 123_456_789_876_543_210
(Cyc:97) print "$x\n"

By default, values print as decimal. Use ->as_hex() to see hex; don't use printf "%x".

(Cyc:97) print "$x\n"
(Cyc:97) print $x->as_hex, "\n"
(Cyc:97) printf "%x\n", $x

These operators can be used directly with signal operands:


The "+0" trick

Notice that values can be arbitrarily large, permitting you to read and write buses with thousands of bits. Perl is doing magic when it sees digits; it converts the number to an infinite-precision type.

Unfortunately, when it doesn't see digits, it messes up. You would expect this to work:

my $data = int rand(8192);
stick L1p_upc_mmio_in(17,80), $data

but it returns
Can't call method "as_hex" without a package or object reference at /ltmp/bjn/bgq/hwsim_unitsim/src/fusion/designersim/ line 176.

The rand output is being treated as a plain integer rather than being converted to an infinite-precision type, causing other parts of the code which expect the type to fail. The fix is easy: add 0 to the result of the function:

my $data = int rand(8192) + 0;
stick L1p_upc_mmio_in(17,80), $data

The digit triggers an infinite-precision conversion, and the code works as expected.

Subtraction, multiplication, division

Subtraction, division, and multiplication of signals can be buggy due to problems in the Perl library. Contact me if you need this in a script, or consider shifting at least this part of the coding to FLite.

Of course there are no restrictions on ordinary arithmetic expressions without signal operands.

Signal assignment gotcha -- you've been warned...

Beware: Although much effort has gone into making signals act like numbers, the charade breaks in variable assignment. You might very reasonably write this to store a signal value:

$old_ctrl = Ctrl;

but it doesn't behave like it looks. It in fact acts like a pointer assignment. The variable becomes an alias for the signal, so when Ctrl changes, $old_ctrl changes as well. 

To avoid this, use ->as_number:

$old_ctrl = Ctrl->as_number;

Assigning to a signal

You also can't assign anything to a signal. If you try it:

Reset = 0;

you'll get stopped immediately:

Assigning to signal? in scalar assignment at (eval 101) line 2, at EOF

Random generation

Returns a random integer in an indicated range (inclusive of x and y). Big numbers and big ranges are OK; it isn't limited to 32 or 64 bits. 

(Cyc:97) $x = random_range(0xFFFF_FFFF, 0xF_FFFF_FFFF)
(Cyc:97) print "$x\n"
(Cyc:97) print $x->as_hex, "\n"

To assign a random value to a signal, see the rndstick, etc., commands below.

Commands on signals

put signalnamevalue
p  signalnamevalue    # same command, shorter name
stick signalnamevalue
st signalnamevalue   # same command, shorter name

These take effect after the next simulator clock. On subsequent cycles, drivers in the design can override a put value but not a stick value. 

pi signalnamevalue  # same command, shorter name

 signalnamevalue # same command, shorter name

These take immediate effect (don't wait for a simulator clock):

unstick signalname

Remove the forcing behavior of a stick. If a stick and unstick are driven the same cycle, the unstick wins, regardless of the order in which they were applied. It's not necessary to unstick a signal before sticking it to a new value.

get  signalname
g  signalname                # same command, shorter name
getc signalname
View a signal value: get displays hex values, getc displays binary. To see X's during multilevel sim, use getc; ordinary get will display 0's.
rndput  signalname
rndstick  signalname
rndputi signalname
rndsticki signalname

Drive a signal to a random values. Every invocation drives a new random value. (To drive a different random signal every cycle, they need to be called each cycle.) The commands use the Fusion seed, so if a session is run again with the same Fusion seed, the same numbers are generated. The reload command resets the seed used by all Perl randoms to the seed's value at the beginning of simulation.  All these commands, and also random_range,  share one random generator, so if you add a random command A ahead of random command B, B's outputs will change even if the seed is unchanged.  For an example of a routine that runs at random times (rather than supplying random values at known times), see myperl.

Put and stick: cycle sim vs event sim

put gives you control of a net for just one simulator cycle. After that cycle, the simulator goes back to driving the net. If  you're driving an input pin,put works fine on any cycle, because nothing else in the simulation is trying to drive it. But if it's an internal signal, put needs to be strategically timed so it's at a latch input on the sim cycle before the latch is clocked. If you drive it on another cycle, the simulator will wrest away your put value before the latch can see it.

This is unexpected if you're used to event simulation. An event simulator would leave your put alone until an upstream net changes.

It's easier to apply stick, but stick isn't self-canceling; to free the simulator to drive the net again you need to unstick. The challenge in stick is not staying but getting out in time.

Here is a possible sequence for coding a put  for an x16 latch. The example uses the desi command sim_clocks_to_xN, which returns the number of sim clocks till the next xN clock.

(Cyc:545) run until sim_clocks_to_xN(16) == 1  # go one sim cycle short of a full x16 clock
(Cyc:576) puti Slow_count_d, 0xdeadbeef # put immediate

The clock grabs the input, and then the latch drives it:
(Cyc:576) run 2 # x16 clock grabs value on first clock; latch shows output on second
(Cyc:578) get Slow_count_q # shows 0xdeadbeef
        SLOW_COUNT_Q(0:38)      0x00deadbeef

The business of inching up to the clock has been automated with the command pput (for precision put, or power put).
(Cyc:576) pput 'x16', Slow_count_q, 0xdeadbeef

Using stick:

(Cyc:833) run 7 # any arbitrary sim cycle
(Cyc:840) sticki  Slow_count_d, 0xdeadbeef # stick immediate
(Cyc:840) runx16 # hit a latch clock
(Cyc:865) unstick Slow_count_d # job's done
(Cyc:865) run 1 # look at latch output
(Cyc:866) get Slow_count_q # shows 0xdeadbeef
        SLOW_COUNT_Q(0:38)      0x00deadbeef

How the put sequence looks in the waves:
Waveform showing put

0xdeadbeef is put on slow_count_d one sim cycle before the rising x16 clock (where the marker is). Notice that on the next sim cycle, the simulator goes back to driving slow_count_d. But the latch has picked up 0xdeadbeef, and it's visible on slow_count_q in the cycle after clkx16 goes high. The VHDL feeds back slow_count_q to slow_count_d, so 0xdeadbeef now also appears on slow_count_d.


run cycles

Advance cycles simulator clocks (default 1). Each simulator clock is half an x1 cycle.

runx1 cycles
runx2 cycles
runx4  cycles
runx8  cycles
runx16 cycles

With no args, or cycles = 1, run to the next rising edge of the named xN clock (eg, x16 clock for runx16). This can be less than a full xN cycle if you are in the middle of an xN cycle. Subsequent cycles, if any (cycles > 1), will be full xN clocks. An xN clock cycle is 2*N simulator cycles.

Take simulation to the falling edge of reset. No effect if reset has already fallen.


Return the current cycle; used in scripts. Fusion maintains the cycle as a 64-bit number; cycle returns only the lower 32 bits. I didn't expect interactive sessions to last much beyond 4 billion cycles.



Return the current xN cycle (the number of xN-clock rising edges since cycle 0). The answer is floating-point, which permits a test like cyclex16 == 23 to return true only at the 23rd rising edge but also gives a useful answer on cycles between edges. (Precision is adequate for practical runtimes).


End the session from the command line. To end the session from a script, use quit().


The command-line and scripting language is Perl. Along with the usual C-like syntax,

 while (Reset == 0) {

Perl also allows surprisingly natural expressions

run until Reset == 1

Desi allows signals of any size to be compared and manipulated with the familiar operators (&, >>, !=, +, etc):

stick Foo, Bzz + 1

Signals can be passed as arguments:

stick Count_threshold_slow_q, Count_q + 7;

sets the threshold to 7 past the current count.

But assignments (including ++, etc) are not allowed:

(Cyc:1) Reset += 1
        Assigning to signal? in addition (+) at (eval 27) line 2, at EOF

One reason is that it's not known whether the assignment is meant to be a stick, put, stick immediate, or put immediate. 

The run-until idiom is particularly useful in interactive simulation. Simulation can be automatically advanced to a condition of arbitrary complexity. It isn't necessary to inch forward while keeping an eye on the waves:

run until Reset == 1 || cycle > 300 && Fast_count_q > 0xdeadbeef

If you see something is about to go wrong, you have the opportunity to force a correct value and continue simulating.

Run-while, the complementary idiom, is also available:

run while Reset != 1 && (cycle <= 300 || Fast_count_q <= 0xdeadbeef)

Nothing happens if the termination conditions are true when the command is invoked.

Run-if  and run-unless are also possible but don't iterate (they advance 1 or 0 cycles). 

Other actions can take place in addition to run. Here are two ways to print something each cycle until the run completes:

run, print "Time is ", cycle, " and all's well\n" until Reset == 1 || cycle > 300
do {run; print "Time is ", cycle, " and all's well\n"} until Reset == 1 || cycle > 300

Note that in the first example, the actions are comma-separated. Like the earlier examples, it will not run if the terminal conditions are already met. The 'do' in the second example is like a run-until; it runs before the test is applied so it runs at least once.

C-style syntax works, too:

until (Reset == 1 || cycle > 300 && Fast_count_q > 0xdeadbeef) {run; print "Time is ", cycle, " and all's well\n"}

This style can be useful with multiple actions; the punctuation between actions is less tricky than the comma. The braces here are always required, even if they contain just one statement.

When setting multiple actions, be sure one of them is run, runx16, or some other command that will cause the tested conditions to change. If there's nothing to change the conditions you'll loop forever.

myperl gives an example of a driver called repeatedly at random cycles.

Semicolons are command separators. They're not needed to terminate an interactive command.  An interactive command can't span more than one line -- backslash can't be used for continuation. A single line can have more than one command, delimited by semicolons.

Dotdot not

The Perl '..' syntax (as in for $i (0..22)) doesn't work in designersim (you'll get an "as_hex" error).  This is a known limitation of  the Perl bignum library which, in compensation, provides many of designersim's nice features.

Global and local variables

A variable that you simply use with no declaration is global. All subroutines can see it (and change it), and its value persists across subroutine invocations. To make a variable behave like a C automatic -- scoped locally and created fresh with every subroutine invocation -- use my, with or without an assignment:

my $x;
my $y = cycle + 7;

Commands starting new windows


Open an editor with the vhdl source file, user script, or command log. You can then pick up your vhdl changes by running respin; your myperl changes by running reload, or your cmdlog changes by running rerun.  Uses the editor in the EDITOR environment variable. To use these commands you should have an editor like emacs that opens a new window; don't use if your editor is vi.


Opens the waveform viewer. Once open, the viewer can stay open between simulation sessions.

Waveform contents

Running newdir creates a starter set of waves -- clocks, reset, and input and output pins. The waves are in in the work directory; this is the file the mantis command reads.

There are a number of ways to change the set of waves displayed:
  1. Edit directly
  2. Type or paste signal names in the command field at the bottom of the waves
  3. Select the name of a signal or signals in the left pane of the viewer (they turn white when selected) and ctrl-E.
To go directly to the latest time, point mouse near the end of the time slider and press ctrl-middle mouse button. Alternatively, select or type END in the Go to: window at upper left.

Mantis can also be started independently of desi. Run mantis in a work directory. A nonzero-length AET file needs to exist; it can be an AET from a previous simulation. It's ok for the AET to get overwritten (even with a shorter AET) while the waveform viewer is up.

The script file

Sequences of commands -- for initialization, test sequences, etc -- can be put into subroutines and run on the command line.

So typing a command like


will execute

    put  Cs_bic_stopped, 0;
    put  Enable_slow_q, 0;
    put  Inc_slow_q, 0;
    put  Clear_slow_count_q, 0;
    put  Clear_clock_stop_slow_q, 0;
    put  Count_threshold_slow_q, 0;
    put  Enable_bic_cs_stop, 0;

if you've put a subroutine

sub clear_dcr_outputs {
    put  Cs_bic_stopped, 0;

    put  Enable_slow_q, 0;
    put  Inc_slow_q, 0;
    put  Clear_slow_count_q, 0;
    put  Clear_clock_stop_slow_q, 0;
    put  Count_threshold_slow_q, 0;
    put  Enable_bic_cs_stop, 0;

in myperl.  You can add and modify subroutines on the fly and load them into the current session by typing reload. This also reinitializes the random seed.

The subroutines are in Perl, with transparent extensions to handle signal names and big values.

myperl has three subroutines to which you can add user code. They get called automatically at specific times in the simulation:
  1. run_at_startup -- You would add here initialization code that should run only at the beginning of simulation.
  2. run_at_reload -- You would add here code that should run when myperl is reloaded -- for instance, to reinitialize variables by setting them back to undef.
  3. run_each_cycle -- Anything scheduled to run in the future, once or repeatedly, goes here -- checkers as well as drivers. See comments in myperl for details and examples.

Note: If myperl contains errors, the error messages may refer to You can treat the messages as referring to myperl. is identical to myperl except that parens have been added to signal names. Parens are also added (invisibly) when you type on the command line. (The parens resolve Perl's parsing of commands like Count_q < 1, where < is used as the "less-than" operator with a signal;  without parens Perl sees an unfinished <> operator.)  Scripts included in myperl using Perl's do command won't get preprocessed.

Session logging and recovery

Two logfiles enable you to review and/or rerun a session:

1) desi.log is a full transcript including user input and system messages.  Like a log from the Unix script command, it may contain unprintable cursor-control characters; use less -r to get a clean view:

less -r desi.log

If grep complains about a binary file, use the grep option --binary-files=text

2) desi.cmdlog contains only your commands. If you make a mistake, you can use this to return to where you were. Edit desi.cmdlog to remove or correct the mistake , and then:

All Fusion parms from the earlier session (eg seed) are reused.  See Starting over for commands that replay a session using desi.cmdlog.

The logfiles are overwritten every time desi runs (including when it runs with the -rerun option)

Working directories

newdir creates directories with the path


for example:


These are the designersim working directories, where design-specific files and scripts are kept and tools like desi are invoked. 

"Working directory" does not refer to the bgq/work path. 

newdir options

If newdir fails (eg because of a VHDL compile error), it's safe to run it again. It's also safe to run newdir if the directory already exists; it won't clobber existing files.
Typing newdir -h  (or -help, or --help, or --h) shows available options:

> newdir -h

      Creates a working directory for designer sim.
      Can do CVS and SVN checkouts if needed. Can compile and build model if none exists.
      By default, will not overwrite existing files.
      Requires environment variable BGQHOME.

         newdir (no args): prompts for unit ( = DDX directory = VHDL library, eg "clockstop")
                           and entity ( = VHDL filename, or VHDL filename minus .vhdl, eg
                           "cs" or "cs.vhdl")
         newdir <entity> : create workdir for another entity in the same library as this workdir
         newdir <unit> <entity>
After running newdir, you can get to the new work directory by pressing the middle mouse button and enter.

For the entity it's OK to use the VHDL filename instead (cs.vhdl instead of cs).

VHDL requirements

All designs currently (12/25/07) in CVS already meet these requirements. VHDL requirements are case-insensitive.

  1. VHDL file name same as entity (entity x → x.vhdl). Filename lowercase.
  2. Architecture named golden 
  3. DCR ports have the form
  4. Each port signal declared on a separate line (no commas).
  5. Reset input named reset.
  6. Clock pin  names as specified by  and declared  as vec_clock_type.  At present only the processor-clock multiples are supported (x1, x2, x4, x8, x16). Network clock (clk_n500) will be added (and possibly PCIe?).

Where Portals/Mesa output files are

The results of a model build are placed in $BGQHOME/bgq/ddx/dadb_2. This directory can be deleted to give the equivalent of a "make clean." Model files have the extension m2msod or m3msmod (for three-state). desi uses whichever was created more recently.

For the interactive session, the the aet is in the older AE1 format to permit cycle-by-cycle updates. (The newer AE2 style has buffering.) Commands for AE2 files (the AE2-enhanced List Signals option for instance, or, unfortunately, the Fusion functions that write directly to AETs) will not work.

Error messages

By default the tools replace several standard Perl error messages with ones that are application-specific or just simpler. $desiparms::informal_messages (initially 1) controls this feature:

(Cyc:1) $desiparms::informal_errmsgs = 0
(Cyc:1) foo
Bareword "foo" not allowed while "strict subs" in use at (eval 24) line 1, <$LNET> line 1242.

(Cyc:1) $desiparms::informal_errmsgs = 1
(Cyc:1) foo
        What's "foo"?

Not all messages could be tamed. If you forget a comma between arguments:

(Cyc:97) stick Reset 27
Number found where operator expected at (eval 80) line 1, near ") 27"
        (Missing operator before 27?)
syntax error at (eval 80) line 1, near ") 27"

If you forget arguments altogether:

(Cyc:97) get
Use of uninitialized value in concatenation (.) or string at /ltmp/bjn/bgq/hwsim/src/fusion/designersim/ line 44.
unrecognized signal  at /ltmp/bjn/bgq/hwsim/src/fusion/designersim/ line 44.

In scripts, misspelling a signal name (or forgetting the initial capital letter) leads to:

Bareword "foo" not allowed while "strict subs" in use at ./ line 77.

Testcase 1.1 FAILED

When writing interactive commands it's easy to accidentally write a nonterminating condition:

(Cyc:23) run until cycle == 21

Unfortunately there's no way to recover; simulation will run to the end and give the message

Testcase 1.1 FAILED

This message means that simulation time reached a user-specified timeout. The timeout is specified via the in.parms file:

// Sim timeout value (sim will fail if it reaches MaxTime cycles)
Fusion.MaxTime = 10000;

Feel free to modify it. A short timeout means fewer moments of helpless watching when your session runs away, but can also surprise you in the middle of a longer session.

If you die in the middle of useful work, remember that you can get desi to play back your previous session so you resume where you were.

Starting over

It's not directly possible to start again from time zero; the simulator needs to be quit and restarted. There are a couple of commands in desi to make this easier.


Restart the simulator, rerunning the commands of the current session from desi.cmdlog. You might do this while debugging a script in myperl.  Parms of the current session are preserved. It's possible to edit  desi.cmdlog first to remove commands you don't want to run again.


Restart the simulator with a new session, and keep the last session's parms, but don't replay the last session's commands.


Rebuild the VHDL and rerun the simulation. You'd use this if you're debugging the VHDL. If there's an error rebuilding, respin doesn't restart the sim but shows the error log instead.  Parms and Mesa model type (m3msmod or m2msmod) are preserved. Like rerun, you can edit desi.cmdlog first.

For these commands Fusion parms are read from the most recent out.1.*.parms file, created during each Mesa run. If you delete these files for housekeeping, leave the most recent one. If you delete them all,  desi won't be able to recover the Fusion parms and will fail at startup.

Quasi-drag-and-drop signal names

The desi command xg (for "X grab") translates a net name on the X windows clipboard to a signal name. Select a net name (from the waves, from an editor or web browser, etc.) and type 'xg<return>' in the simulator. The middle mouse button's paste function will then deposit the translation.

Run xg:
(Cyc:0) xg
Can then paste the signal name into a command:
(Cyc:0) g Clear_f_ll_bit_0_lp_zz_vitalbehavior_l1clk

Using SVN

The initial work directory comes to you ready for check-in into Subversion. The CVS commands add, commit, and update work in Subversion; so does diff:

svn add
svn commit
svn update
svn diff

You're encouraged to use Subversion to save versions of your work and make it accessible to others.  

On the other hand, it's best to commit only the files that you've have modified (svn commit by default will commit everything). This makes it easier to do updates of the designersim code.


Set to the path up to but not including your bgq directory. The newdir tool will prompt if BGQHOME is not set. If there's no bgq directory, newdir will create one at $BGQHOME.

Most of the BGQ simulation tools -- not just designer sim, but unit sim and full-chip sim as well -- depend on BGQHOME being set; you should have it in your profile.


Nearly all the designersim programs are in this directory.  If you sometimes need to change BGQHOME, you can still add designersim to PATH; see this note. If you have religious objections to changing PATH, the tools will work but you'll need to specify the path on the command line or write aliases.

Shell commands

All are run from a working directory. Most of these would normally be run either automatically by the tools or from the desi command line.

Open the waveform viewer.
Compile and build model. They pick up the names they need (library and entity) from the current working directory.
makevhdl viewlog
View logfiles from the VHDL build. Opens the most recently created logfile and highlights the first occurrence of the word 'error'.

Create a starter set of waves in If already exists, it won't clobber it.  It can be run only after model build.

Like the desi command, recompiles VHDL and makes a new model, then reruns desi.cmdlog. Displays the relevant logfile if Portals or Mesabld fails.

Native Fusion interface

The designersim user interface significantly extends the interface described in the Perl Interface chapter of the Fusion user guide.  The echoing of commands like put and stick shows the underlying Perl Fusion command.

Some of the commands described in that chapter might be usable in designer sim (caution:  untested):

Function Interactive version
fusion::aet aet
fusion::bspReset bspReset
fusion::figtreeGet figtreeGet
fusion::figtreeSe t figtreeSet
fusion::info info
fusion::warning warning
fusion::error error
fusion::pass pass
fusion::debug debug

Don't use the other commmands in the chapter. They will not work, or will work differently, or will interfere; and in general they provide less functionality.

Some ways the designersim user interface differs from the native Fusion interface:
  1. desi works with integers of any size. In the native interface, users must choose between string and integer representations of signal values; neither is perfectly suited for simulation. Strings support signals of any size but don't support any of the familiar bit, arithmetic, or comparison operations (&,+,<=); even a string test for equality can be deceived by leading zeros. Also, users must remember to add quotes around values. Integers, while they do support bit ops, can't be used for signals wider than 32 bits. The designersim tools make use of Perl's big-integer library and constant overloading to allow expressions with unquoted integer literals of any size.
  2. Signal names can be used directly in expressions like Slow_count_q + 1 or Slow_count_q == 0x7fffffff. It is not necessary to first call a function to retrieve the signal's value. Perl operator overloading makes this transparency possible.
  3. By controlling the clock via the run() subroutine, designersim also provides the run_at_startup, run_at_reload, and run_each_cycle interfaces.
  4. Signals in scripts or on the command line never need to be declared. When a signal name is used for the first time in a script or the command line, the tools find the net and declare it automatically.
  5. The designer-sim tools attempt to provide more user feedback. In the native interface, command-line errors are not always reported. desi reports not only errors, but also warns if, say, it's truncating a value to fit a signal width.

Long goodbyes

There's a bug in interactive Perl Fusion, unrelated to desi, that causes it to dump core when the user quits. The bug has been reported and we await a fix. It wouldn't be design automation if it didn't have at least one irritating how-could-they-have-missed-this bug.

attempts to make the problem invisible. Generation of the coredump file is suppressed and the end-of-the-world message is not displayed.

But if you have an error in your script, so that desi doesn't load, you'll see the message when you quit.  Sometimes Fusion hangs on its way out; then you'll need to kill desi from another window. The command desikill, typed at a Unix command line, will kill all desi sessions you have open..

Noninteractive designer sim

Some designs can't be run interactively for long before dumping core. This is a problem in interactive Perl Fusion, not desi itself, and is known to the Fusion team. Fortunately, noninteractive Perl Fusion is not affected, and a noninteractive designersim version, desibatch, is provided for these cases.  For noninteractive sim, whatever you want to run must be invoked via run_at_startup. The sim will terminate  after your last run command. When using desibatch the print and echo commands continue to write to the screen; you may prefer to write to the out.SUM file, using commands like fusion::info(). (Unfortunately fusion::error() crashes the sim, so you may want to print a fail message to the console yourself.) If you do send all output to the screen, you may want to turn off Fusion's Cyc 0000098: Evaluate:   000.269 sec elapsed, 936 KBytes used messages by setting the parm Fusion.TimerEnabled=false either when invoking desibatch or in the in.parms file.

Suspending Mesa ASSERT messages

Sometimes ASSERT messages appear at startup, particularly in multilevel ('X') simulation. Asserts can be suspended at startup and reenabled at a user-specified time via the parm ResetDriver.restore_asserts_cycle, which can be specified on the command line:

desi ResetDriver.restore_asserts_cycle=XXX;

or in the in.parms file. By default, this parm is 0 and asserts are never disabled.

Perl and FLite

News flash: FLite does not work on the 64-bit machines. It's a simple fix for the Fusion developers, but it's not clear when they will add it.

desi as debugger

desi can be completely driven and checked by Perl scripts. Alternatively, the interactive environment can be run as a kind of debugger. You write stimulus and checkers in FLite or standard Fusion which can run unattended, but rather than running these with runmesa, you start desi, which enables you to examine and force signals, to "single-step" via runxN, and to set "breakpoints" via run until.

Perl is analogous to the ncsim command line, and FLite is analogous to a VHDL testbench.  Compared to a VHDL testbench, FLite gives more control and visibility, because it is not restricted to ports, and C++ is arguably a more productive language than VHDL.

Adding FLite modules

Perl and FLite already coexist in desi. Any entity with a reset pin is driven by  ResetDriver.flt  in the designersim directory. You can add your own module by including it in FLite.ModuleFilenameList in the in.parms file in the work directory:

FLite.ModuleFilenameList = ResetDriver.flt, dcr.flt, SomethingYouWrote.flt;

The module can go in the work directory or in the "unit-level" directory above the working directory. Don't add FLite library files (as opposed to modules). Library files will be found automatically if they're in either directory.

Multiple stimuli in Perl

It's easy to write a single stimulus in the desi environment. It advances time whenever it needs to via runxN:

runx16, 12;
put Count_q, 0x2727;

runx16, 22;
put Count_q, 0;

You can't boss time like this if you want to concurrently run independent stimuli. In that case, the stimuli run under run_each_cycle, each waiting for the right cycle to come around: 

put Count_q, 0x2727 if x16 == 12;
put Count_q, 0 if x16 == 12+22;

"12+22" is clearer than 34. The commands can go directly in run_each_cycle or into a subroutine called from run_each_cycle. To move time forward you would have a  run or run until in run_at_startup

The "12+22+..." style can require changes down the line if one of the times changes, and it doesn't support random times. The sequence can be expressed instead as a series of offsets.

do {$t = x16; put Count_q, 0x2727} if x16 == 12;
do {$t = x16; put Count_q, 0} if x16 == $t + 22;

In this second case, the stimulus has state that will remain intact between invocations. To guarantee that $t is not clobbered by another $t, uniquify it, either manually

do {$FancifulName_t = cycle; put Count_q, 0x2727} if x16 == 12;
do {$FancifulName_t = cycle; put Count_q, 0} if x16 == $t + 22;

or by using Perl's package command:

        package FancifulName; 
     do {$t = cycle; put Count_q, 0x2727} if cycle == 12;
     do {$t=cycle; put Count_q, 0} if cycle == $t + 22;
Don't use my to isolate $t; the variable won't stick around across invocations.

Multiple stimuli in FLite

For serious simulation with concurrent stimulus, FLite is a better tool. It's fine if multiple threads contain clock() commands:

put Count_q, 0x2727;

put Count_q, 0;

because clock() doesn't drive the clock; it's a wait-for-clock. FLite threads act like VHDL processes.

It might be possible to add a semantic like this to the desi environment, but there's none currently.

desi and Bugspray, PSL

Bugspray seems a natural complement do some or all simulation checking. Bugspray can go into Fusion or VHDL.  PSL is also a possibility;  here again there's a choice of VHDL (VHDL 2000 includes PSL) or Fusion (Fusion now can include PSL directly). I'd like to work with anyone who wants to include these.

Desi and Fusion

Designersim can be used as a fast start for RTX development. You can start writing code without having to set up an environment. Later the RTX can be moved to a permanent location and the missing pieces (eg, clock vector and reset) added.
  1. Copy Makefile.sample from designersim to the working directory (naming it just Makefile). Customize TARGET to your .so name.
  2. Add your .so to in.mesa.dll (below libdesigner).
  3. You can create SimRiseClock instances as you normally would, or piggyback on bgqClockVec, which fires on the same cycles, by declaring an alias:
#include "obj/ObjectAliasSpec.h"
static ObjectAliasSpec clkx2a("", "bgqClockVec[_x2,_x16]", "%.SimRiseClock[_x2,_x16]");

Perl Fusion allows coordination between Perl code and RTX, using an object that can exchange strings with the Perl side. I've created the object (the documentation is incorrect) and gotten the communication to work, but I'm not currently exploiting it. One application might be to augment the Perl UI with features that are normally available only from RTX. Another might be to control RTX from Perl, where Perl writes a string telling the RTX when to start, the RTX runs concurrently, and then the RTX writes a string telling Perl that it's finished.

Re-pathing designersim

If you sometimes change BGQHOME, the designersim in $PATH needs to track the change. One way to do this is to change BGQHOME using a bash function / tcsh alias (I named mine reworld )

reworld newdir

which changes not only BGQHOME but other environment variables that depend on it.

For bash or ksh, include a function in .bashrc/.kshrc:

reworld() {
    export BGQHOME=$1;
    export DESIGNERSIM=$BGQHOME/bgq/hwsim/src/fusion/designersim;
    if [[ -n "$old_designersim" ]]; then
        export PATH=${PATH//$old_designersim/$DESIGNERSIM};
        export PATH=$PATH:$DESIGNERSIM;

The if clause replaces the previous DESIGNERSIM on the path with the new one. The else covers the case where DESIGNERSIM hadn't previously been set.

You can include in the function other environment variables and aliases that use BGQHOME:

export BGQ=$BGQHOME/bgq
alias bgq="cd $BGQ"

When you run reworld to change BGQHOME, the variable and alias will track the changes.

You can also decide how to handle the case where no argument is given -- for instance, to set BGQHOME to the current directory, or to revert to a default BGQHOME setting.

For tcsh, create a reworld.csh script:

setenv BGQHOME $1
set new_designersim = ${BGQHOME}/bgq/hwsim/src/fusion/designersim
if ( $?DESIGNERSIM ) then
   set path = `eval echo '$path:'gs^$DESIGNERSIM^$new_designersim^`
   set path = ($path $new_designersim)

setenv DESIGNERSIM $new_designersim

and an alias
alias reworld "source /path/reworld.csh \!*"

As with bash/ksh, you can include in reworld.csh additional environment variables and aliases that reference BGQHOME:

setenv BGQ $BGQHOME/bgq
alias bgq "cd $BGQ"

The variable and alias will track BGQHOME as it changes.

You can also decide how to handle the case where no argument is given -- for instance, to set BGQHOME to the current directory, or to revert to a default BGQHOME setting.

This page administered by
Ben Nathanson <>
Written in 2008 in peasant HTML. Cosmeticized slightly in 2020 with CSS, with mixed results.