If there’s one thing I’ve learned since coming to Mentor early last year, it’s that the SystemVerilog language gives developers options for writing one line of code a lot of different ways. As one of the Product Engineers responsible for Questasim SystemVerilog support, the variety is impossible to ignore.
Take something as simple as assigning a new value to a logic property in your testbench. You could use a continuous assignment for that. Unless maybe you prefer a procedural assignment? Can’t decide between blocking or non-blocking? How about a procedural continuous assignment with an assign or force instead? But then where do you put it? An always* block? Or maybe an always_comb? Or you could fork threads from an initial block and use level or edge sensitive events to control when it happens. And… oh… I see the value is coming from a variable in a clocking block. Hmmm…
Get the idea? There’s a lot of different ways this could go. And why do all these options matter?
Race conditions – non-determinism created where a variable is written and/or read by multiple threads simultaneously – are a big reason why all these options matter. It’s not too bad for design engineers because the requirement of synthesizable RTL cuts down the possibilities. But for verification engineers it’s a different story. Race conditions for us can be an absolute nightmare. There are so many ways to code race conditions into a testbench; truly insidious ways that can take hours, even days to diagnose, understand and fix.
Given the importance of understanding how non-determinism and race conditions can wreak havoc in a development team, we thought it’d be fun to put out a challenge to see how well we all understand them. I’ve been working on a code example with fellow Mentor Product Engineer Scott McClain that includes the types of race conditions we help customers debug. Beyond the usual boring code snippets, we’ve coded races in a sports theme that covers…
- Basketball (blocking and non-blocking assignments)
- Ping-pong (unknowns at time 0)
- Football (incomplete sensitivity lists)
- Track and field (fork/join)
- Baseball (assignments in multiple threads)
- Hockey (edge sensitive events)
- Cricket (named events)
- Weight Training (procedural force/release)
- Volleyball (NBA functions)
- Beach time! (procedural and continuous assignments)
If you’re a student, design engineer, verification engineer, team lead or even a manager who appreciates a challenge, this is for you. Here’s how to get started:
- Visit the Race Condition Challenge page on EDA Playground
- For each of the 10 code snippets:
- Identify the race condition/non-determinism
- Update the code to remove the non-determinism
Some of the races are easy to spot, others not so much. A couple aren’t technically races but they produce an ambiguous result. For all of them, do the best you can; on your own, with a colleague, with a classmate or turn it into a challenge for your team.
If you simulate the code, I’ll warn you that some code snippets will evaluate the way you expect and others won’t. But keep in mind that this is less about understanding how races are evaluated and more about recognizing and avoiding coding habits that result in races. In short, this is a static analysis exercise that doesn’t really require a simulator. You could do it on paper.
In a follow-up, we’ll post a response in a couple weeks so you can see how you did. That answer key – complete with colour commentary – will come from resident SystemVerilog language expert Dave Rich. Dave’s been helping folks in the design/verification communities for a long time when it comes to language usage so his coding recommendations will be something we can all look forward to.
Again, here’s the link to EDA Playground to get started.
See you back in a few weeks!