Assertions for strict arbitration

Ben Cohen of the SystemVerilog Assertions Handbook fame, posted a novel answer on how to check strict arbitration with SystemVerilog Assertions at Verification Academy. The core observation is that we can treat the request and grant bitvectors as an unsigned integers and compare then numerically when the highest priority isĀ  the MSB.

Unfortunately, the solution uses a generate for loop which has a noticeable performance impact on my simulator, so I sat down to see if I could shoehorn in Ben’s solution into a single assertion. Ben’s assertion needs a temporary bitvector where the request[i] bit is placed at position i+1 with which he does the less than comparison. The alternative is to mask out the granted index from the request and do a less than comparison on that result. The less than operation must still succeed if the grant is correct. Thus the assertion can be written as:

a_arbiter_is_strict: assert property(@(posedge clk) req |-> (req & ~gnt) < gnt);

Naturally, strictness alone does not work correctly if the grant is not a one-hot vector, thus I always have the following assertions with any arbiter:

a_valid_signals: assert property(@(posedge clk) !$isunknown({req, gnt}));
a_valid_grant: assert property(@(posedge clk) (req != 0) == $onehot(gnt)); 
a_valid_no_grant: assert property(@(posedge clk) (req == 0) == (gnt == 0));
a_valid_grant_source: assert property(@(posedge clk) gnt |-> (gnt & req));

Note that the parenthesis are important. Instead of ==, I could also have used iff, but my EDA tools don’t support iff yet, so == it is.

Still, one question remains: What if the priority is from LSB to MSB? Here, the numerical idea no longer works, but we can still get by with a single assertion. The idea here is to use the power of two nature of the grant and mask out the higher order bits of the request with gnt-1.

a_arbiter_is_strict: assert property(@(posedge clk) req |-> (req & (gnt-1)) == 0);

And there you have it: Fast assertions for strict arbitration.

Fixing Simulator License Acquisition Latency

Many larger semiconductor companies use global licenses for EDA tools to support their distributed teams. Unfortunately, getting a license for a simulator, the bread and butter of design and verification engineers, can be atrociously slow. I have seen waiting times of up to 20 seconds when the round trip time of a ping to the license server was 180ms and the license server still had over a hundred free licenses. Wait times above a few seconds drain productivity. It is surprising that EDA vendors accept two orders of magnitude higher latency in license acquisitions than the ideal when they compete against tools such as Verilator or Icarus Verilog with no license limits or acquisition latency.

Fortunately, most of the latency can be removed by setting the LM_LICENSE_FILE correctly and ensuring that the simulator only asks for licenses that you actually have. You need to do the following:

1. Find a time window where your chosen simulator has a lot of licenses free. Use lmstat to see how many licenses are in use.

$ lmstat -a > lmstat.out

2. Write a small dummy verilog program to use as a profiling object

module dummy;
  initial $display("Hello World");
endmodule

3. Profile the license acquisition time of your simulator

$ compile dummy.v
$ time runsim

If time spits out less than a second, you’re done. The FlexLM license server is slow. It can’t do better than a second. If time spits out multiple seconds, then there are gains to be had.

4. Find the closest license server with the simulation licenses that you are interested in. The output from lmstat -a and ping are your friend.

$ echo $LM_LICENSE_FILE
744@serv1:744@serv2:744@serv3
$ ping serv1
..... 310ms .....
$ ping serv2
..... 180ms .....

In this example serv2 is the closest license server with a simulator license. The other servers are further away or don’t have the license that I am looking for.

5. Edit the $LM_LICENSE_FILE environment variable to put the closest server first

$ export LM_LICENSE_FILE=744@serv2:744@serv1:744@serv3

Profile your simulator again. Did it help? Some EDA vendors will appear to have coded their license acquisition routine as follows:

for (server in $LM_LICENSE_FILE)
  for (license type in [CHEAP, NOT_SO_CHEAP, EXPENSIVE, REALLY_EXPENSIVE, EVERYTHING])
     ask server for that and only that license type // takes a second. FlexLM is slow

The good thing about this is that the vendors will give you the cheapest license that you can get away with. The bad news is that larger companies only buy the global version of the REALLY EXPENSIVE or the EVERYTHING licenses, so their license acquisition time is slower than the cheapskates. If you put the closest license server with the licenses, that you want, first, then you won’t have to wait for the loop to go through all the other license servers. Unfortunately, you are still waiting for FlexLM to tell your simulator that it doesn’t have licenses for the cheap versions.

6. Open the documentation for the simulator. Somewhere there is a command line option, or an environment variable that lets you specify the order of searching for a license. Find it and try it out in your sandbox environment. Below I am assuming that the cheapest license that I have is “REALLY_EXPENSIVE” and that there is a command line option is called force_license:

$ time runsim --force_license REALLY_EXPENSIVE

These two changes did it for me. I went from 20 seconds down to 1.4 seconds. The simulator documentation gave me some further options regarding environment variables, such as alternatives to LM_LICENSE_FILE, but these were only able to cut maybe another 100ms.

I hope that this will help you keep your productivity and your sanity.

Side note: Almost all simulators have a profiling command line option which will give you extra information, such as the amount of time spent waiting for a license. For this dummy file it should be just below 100%. In general, you should use the profiler of your simulator. It is your friend.

Customizing the US International keyboard

Scandinavia and Germany have a small number of special characters in their alphabet. Coders from this region should consider moving to the US International keyboard in order to get easier access to brackets [], braces {} and other special characters which are commonly found in programming languages. Unfortunately, the US International keyboard has marked some of the special character keys as dead keys in order to support southern European languages. For many northern coders these dead keys are annoying. Fortunately, Microsoft has Microsoft Keyboard Layout Creator which lets us remove the dead keys. The process is relatively straightforward:

  1. Install Microsoft Keyboard Layout Creator
  2. Run it
  3. Load an existing keyboard: File -> Load Existing Keyboard… -> US International
  4. Click on the Dead Keys (See Legend in the GUI) -> All… -> Tick the “Dead Key View”
  5. Untick “Dead Key?”
  6. Save Source File
  7. Validate Layout
  8. Build DLL and Setup Package
  9. Follow the GUI
  10. Run the generated setup.exe
  11. Change the Keyboard Layout in your Windows Preferences
  12. You may need to restart programs or the machine. YMMV

All in all, it took me about an hour of playing around and writing this up. I hope that it helps you.

Prefer isunknown over unary xor equals

Stuart Sutherland and Don Mills have a good introduction to using SystemVerilog Assertions [1]. Unfortunately they like checking for unknown signals with the construct ^value !== 1'bx. I disagree with this construct. It is easy to forget the 1 in 1'bx, mistake 1'bx as equivalent to 'bx – which it is not – or mistype the construct so that the assertion becomes useless. It is far better to use !$isunknown(value). This construct is safer and immediately conveys the intent. The only drawback is that it costs two extra characters over Stuart and Don’s construct.

I have personally mistyped ^value !== 1'bx enough times to drop it completely in favor of !$isunknown(value).

[1] SystemVerilog Assertions Are For Design Engineers Too!

Mapping between MMR addresses and UVM registers

Using logical names instead of hard coded addresses is an advantage for any software development – including verification. That doesn’t mean that logical names are always better than addresses. Some times an address is handy and other times I would really have wished for the register name. Fortunately UVM has methods to convert from one to another:

function uvm_reg_addr_t uvm_reg::get_address(uvm_reg_map map = null)
function uvm_reg_addr_t uvm_mem::get_address(uvm_reg_addr_t offset = 0, uvm_reg_map map = null)
function uvm_reg uvm_reg_map::get_reg_by_offset(uvm_reg_addr_t offset, bit read = 1)

Example one-liners:

uvm_reg_addr_t addr;
uvm_reg rg;
uvm_mem mem;
addr = regmodel0.MY_BLOCK0.MY_REG0.get_address();
addr = regmodel0.MY_BLOCK0.MY_MEM0.get_address(addr);
rg = regmodel0.default_map.get_reg_by_offset(addr);
mem = regmodel0.default_map.get_mem_by_offset(addr);

Note that the UVM Register Layer allows a register to span multiple addresses.