Wednesday, January 4, 2012

New Website for Blog

I have moved this blog to www.latchesinferred.com. I will remove this blog eventually but I'm leaving it up for the time being to redirect anyone looking for the current blog.

Wednesday, May 18, 2011

Assign From God

This post is an explanation of the "assign" keyword. I remember being confused at times about when it was okay to use this keyword when I first learned Verilog.

First, assign is structural, not procedural. What does that mean? Well, structural code is just what it sounds like: it's anything that specifies structure. Basically that means wire connections to modules or gate primitives such as "and" and "or" gates. The "assign" keyword is structural because it essentially defines what a wire (or more generally, a net) is structurally. Here's an example:

assign x = a;

This means that x takes on whatever value a has. The right hand does not have to be just another symbol; it can be a logical expression, something like:
assign x = (a & b) ^ c;
That's the easy part. The confusing thing is always know exactly when and where you can use things in verilog.

Here are the rules for assign:

The symbol on the left hand of the assign must be a net (as opposed to a variable). That means a wire, wor, wand, tri0, tri1, etc.

The symbol on the right hand, however, can be either a net or a variable. Variable types include reg, real, time, etc.

You can only use assign once for any net. You cannot, for example, have the following:

assign x = a;
assign x = b;

Remember, assign specifies structure, so this doesn't make sense. You're not specifying a changing value for x over time or program execution as you might in procedural code. Which brings me to my next point...

You cannot use assign in procedural blocks. For example:

always @(*) begin
 if(a)
  assign x = b;
end

That makes no sense. Procedural code is something that is run or executed like a program. You cannot specify the structure of something procedurally. That's just crazy-talk.

So, here, in the context of a module, is a valid use of assign:
module foo(output x, input a, input b);
 assign x = a | b;
endmodule

[EDIT: The above code is apparently syntactically valid, but it does NOT do what you want. It is also deprecated and not all compilers will warn you.]

The functionality of this module is actually to be an OR gate. Alternatively, we could have achieved the same functionality with:
module foo(output reg x, input a, input b);
 always @(a,b) begin
  x = a | b;
 end
endmodule

Notice that there, x is declared as a reg and we do not use assign. That's because this is procedural code, not structural code.

Okay, that's it! :D

Saturday, March 5, 2011

Does that Register?

I'll start this blog by attempting to explain what was, for me, and I believe many of my peers, one of the single greatest sources of confusion when "programming" in Verilog: the beloved keyword reg.

Basically what this amounted to was us compiling our code, getting the message "Non reg/integer/real/time/realtime cannot be used on the left hand side of this assignment" and then having the following discussion:

Lab partner A: "Huh... try throwing reg in front of it."
Lab partner B: "But it's not a register."
A: "Whatever, just try it."
B: "Okay."
A: "Oh, hey, it works. See?"
B: "Uh... what?"

So: What does reg mean? Does it mean register? Does it mean stateful variable? (Verilog has variables?) Can it be combinational? Or is it only for sequential logic? Can I use blocking assignments on regs? So many questions!

While doing research for this post (cause heck if I actually know what the deuce reg means), I came across the following documents:


I've downloaded this helpful little reminder sheet and I suggest you do, too. Print copies and give it to all your non-blocking friends!


It's over 9000 pages long (where 9000 == 828) but it's written in simple English and actually makes a lot of things very clear. It was my primary resource while writing this blog post.

Basically, here's the deal. Verilog has two basic data types: nets and variables. regs are one kind of variable, but first I'm going to introduce nets and then variables. If you think you have a good grasp on nets, you can go ahead and skip down to variables.

Nets

Nets are data types that "represent physical connections between structural entities, such as gates."[1] With the exception of trireg, they do not store a value. Ignore trireg for now, it's used to model wires that have capacitance. I've never used one in all my time at CMU.

Here is a list of net types[2]:
  • wire
  • wand
  • wor
  • tri
  • triand
  • trior
  • tri0
  • tri1
  • trireg
  • supply0
  • supply1
You're probably quite familiar with wire. It's used to connect inputs and outputs of modules. They have to be driven by something to have a value of 0 or 1. If nothing drives them, they hold the value "z" (which, in Verilog, means high impedance, i.e., disconnected). If multiple things drive them and they conflict (or either is x), then they have value x. [3]

As an aside, you might be wondering why these things are called "nets". I don't really know myself. I think "net" comes from "network" where each wire can form a network since it can split into many parts which go to different gates or modules or whatever. If anyone knows for sure, please let me know cause I'm curious.

Anyway, that's wire. Also, wire and tri are "identical in their syntax and functions"[4]. Same goes for wand and triand, wor and trior, which I haven't explained. Basically they behave differently when two things are trying to drive the same net at the same time. They're for another time, though.

Why two different names for things which are identical in syntax and function? Because labeling something as "tri" helps indicate that you intend for it to be driven by different things are different times. That is, you want for it to have tri-state logic (1, 0, and z). This happens when, say, there is a bus between two modules and sometimes module A is driving the bus and sometimes module B is driving the bus. When neither of them are driving it, the bus has a value of z on it. Use "wire" when you don't anticipate this usage (i.e., you expect exactly one thing to drive the net and to do so at all times e.g., a wire which directly connects two modules).

So, those are nets. Onto variables!

Variables

"A variable is an abstraction of a data storage element."[5] That is, they store a value from one assignment to the next.

Here's a list of variable types:
  • integer
  • real
  • realtime
  • time
and last but not least:
  • reg
Unlike nets, which initialize to z (with the exception of trireg), variables initialize to x (that is, "unknown" or "undefined") or 0.0 in the case of real and realtime.

I use integer pretty often in testbenches, but I don't really use others. reg is by far the most commonly used variable type.

Source of Confusion

Here comes what I believe to be the source of alll the confusion caused by the reg keyword: "Since the reg holds a value between assignments, it can be used to model hardware registers. [...] A reg needs not represent a hardware storage element since it can also be used to represent combinatorial logic." [6]

If that doesn't confuse you, it should. Combinational (combinatorial?) logic is logic that is stateless or memoryless. Its outputs are purely a function of the present inputs; they do not depend on prior inputs or events. For example, if I say "what is 5+7?" the answer doesn't change if I just asked you to calculate 2+2. The answer is 12 and you can determine this without knowing any thing about the past inputs I've provided you with.

Sequential logic, on the other hand, can potentially depend on all prior inputs. Whenever there is memory in a system, if it is being used, it is sequential, not combinational. For example, if I am inputting a series of numbers between clock cycles and the output is the sum of all the inputs up to the present, then that uses sequential logic. Computers would be pretty boring (and useless) without this.

Now, getting back to the excerpt above: regs hold values between assignments (i.e., they have memory) and yet they can represent combinatorial logic (which is memoryless).

How can this be?

Well, technically combinational logic can be thought of as a subset of sequential logic. To make this clear, think about the constant function f(x) = c. Is this a constant function or is it a linear function? Well, it's both. It really comes down to what we mean by constant vs. linear. Does linear exclude constant? Does the linear term need to be non-zero for the function to be linear? Are squares rectangles? You get the idea.

Combinational logic is sequential logic where the past state doesn't show up in the function for determining the outputs. For example "A or B" is combinational logic, but in a way it is sequential logic that happens to not depend on any prior inputs. (Now, usually the word "sequential logic" means that it does depend on prior state just as rectangle usually means excluding squares. So, don't go using the word this way, you'll confuse the hell out of everyone and make yourself look dumb.)

So, when we want to model combinational logic, we can use regs; we just need to make sure their contents do not depend on prior state. If they do, we no longer have combinational logic, we have sequential logic. Obviously reg isn't confusing when we actually want a register, it's only confusing when we use it in a context where we want combinational logic, so let's look at that.

Some Sample Code

Okay, so where's an example of having to use reg when we want combinational logic? Let's start with something simple: a multiplexer.
/* WRONG multiplexer */
module mux(y,sel,a,b);
output y;
input sel,a,b;

always @(*) begin
if(sel)
y = b;
else
y = a;
end

endmodule
Recall that a multiplexer simply selects one of 2^n inputs to drive a single output using n select-bits. This is a purely combinational function as the input selected is determined entirely by the present input "sel".

So, what's wrong with the code above? Answer: y is not declared as a reg. Keep in mind that y does not represent a register. When this code is synthesized to a device, there won't be any register. So why do we need to declare it as a reg? Well, it's because y, while not modeling a register, does have state--in the simulator. This is because y will continue to have whatever value it presently holds until something in the sensitivity list of the always block changes its value, thus triggering the execution of the next blocking assignment for y. In this case, when "sel" changes, y will change in a way entirely determined by the value of sel.

What is important to keep in mind here, and what gives rise to this whole issue, is that there is a difference between simulation and synthesis. From the perspective of the simulator, y has state since it continues to store its value until it must be recalculated when sel changes. From the perspective of synthesis, however, no actual register is necessary to implement this function since we have a definition for what y should be in all input cases (sel being 0 or 1) and it is the same every time i.e., it is combinational.

What would happen if we were to take out the "else" clause in the if-else block above? Well, then the simulator would not change y when sel becomes 0. From the simulator's perspective, this isn't really different in any fundamental way from the code before; y is still stateful.

The function, however, is no longer combinational because now our value for y depends on whether or not sel has been set to 1 yet. If it hasn't, y is x (remember that the default value for variables is x). Consequently, the synthesizer must implement y as an actual register now. Your simulator will warn you that a latch (a flip-flop or one-bit register) has been inferred. Hence the fine name of this blog!

You should now understand why reg is needed even when dealing with combinational logic in procedural blocks.

In case you're curious, how is another way that we could have written the above code to avoid using the keyword reg:
/* RIGHT multiplexer */
module mux(y,sel,a,b);
output y;
input sel,a,b;

assign y = (sel) ? b : a;

endmodule
This takes advantage of continuous assign. Since this is not inside of a procedural block (unlike the always block in the prior code), it is not something that is getting executed upon certain events. y has been assigned to the logical function of being b when sel is 1 and a when sel is 0. It's function is set in stone and its not as though y contains a state or value. It is simply a wire, now, which propagates the function of a multiplexer. This is why you cannot assign something more than once: it's not something that gets executed as the simulation runs through time. It's not within a procedural block so when would it even get executed?

Before ending, let's look at yet one more way to specify a multiplexer:
module mux(y,sel,a,b);
output y;
input sel,a,b;

and(y0,~sel,a);
and(y1,sel,b);
or(y,y0,y1);

endmodule
Here we've specified the mux entirely with structure of primitive logic gates. Thus we only specifying the connections between input and output ports. That means we don't need reg since wires are what specify port connections. They are driven by whatever the outputs and inputs of the various modules are.

Hopefully this makes clears up the whole issue. If any of this is confusing or flawed, please let me know! Happy coding non-blockers!

[2] Ibid., p. 25
[3] Ibid.
[4] Ibid.
[5] Ibid., p. 22
[6] Ibid., p. 31

Statement of Purpose

I'm launching a blog today. It's spring break and I've got nothing better to do for a couple days (aside from computer architecture lab) and I've been kicking this idea around in the back of my head for a few weeks so I figure I'll give it a shot.

Basically this blog is meant to provide tips and tricks for leaning Verilog and SystemVerilog. When I first starting learning Verilog in a course called "Structure and Design of Digital Systems" (course no. 18-240 at CMU), I remember being pretty confused by certain aspects of Verilog. For example, "reg". To those who know, need I say more?

To those who don't yet but want to, this blog is for you. Hopefully the things I have to say will save you some of the pain and misery I endured. Then again, some see that as a right-of-passage.

Perhaps with time I might expand this blog to include more than simply Verilog and SystemVerilog. I might occasionally post things about other topics in electrical and computer engineering, code-related or otherwise.

Oh yeah, and a little disclaimer: I'm a junior undergrad student which means I'm no expert and potentially everything I say or piece of advice I give here could be totally wrong, stupid, and all-around lousy. Read at your own risk.

And remember, always_comb your hair!

Paul Mueller Kennedy