a wire by any other name

T

TJ Edmister

Guest
Even though you can't use a wire the same way you can use a reg (ie.
inside an always or conditional block), can't a reg end up behaving just
like a wire if you put it in an always @(*) block? By that I mean, it
changes asynchronously depending only on its inputs? For instance, these
examples:

// program 1

wire [3:0] news = friday ? goodnews : badnews;

// program 2

reg [3:0] news;

always @(*) begin

if (friday) news <= goodnews;
else news <= badnews;

end

Any difference in how these would synthesize?
 
On Friday, April 17, 2020 at 10:18:24 PM UTC-6, TJ Edmister wrote:
Even though you can't use a wire the same way you can use a reg (ie.
inside an always or conditional block), can't a reg end up behaving just
like a wire if you put it in an always @(*) block? By that I mean, it
changes asynchronously depending only on its inputs? For instance, these
examples:

// program 1

wire [3:0] news = friday ? goodnews : badnews;

// program 2

reg [3:0] news;

always @(*) begin

if (friday) news <= goodnews;
else news <= badnews;

end

Any difference in how these would synthesize?

Yes; those would synthesize the same (but it's recommended that you use blocking assignments (=) in an always@(*) block).

Using the keyword "reg" for combinational and clocked logic can cause a lot of confusion. I would prefer it if the language had you explicitly declare whether something is combinational or registered, and that would make it easier to intermix combinational and clocked logic in the same process and to modify pipelining without rewriting as much code. Nobody asked me when they were writing the spec, though.

In Verilog-2009, you can use the keyword "logic" instead of "reg", but I don't believe the synthesizer treats it any differently.
 
On Sunday, April 19, 2020 at 12:25:11 PM UTC-4, Kevin Neilson wrote:
Yes; those would synthesize the same (but it's recommended that you use blocking assignments (=) in an always@(*) block).

Using the keyword "reg" for combinational and clocked logic can cause a lot of confusion. I would prefer it if the language had you explicitly declare whether something is combinational or registered, and that would make it easier to intermix combinational and clocked logic in the same process and to modify pipelining without rewriting as much code. Nobody asked me when they were writing the spec, though.

In Verilog-2009, you can use the keyword "logic" instead of "reg", but I don't believe the synthesizer treats it any differently.

Can anyone explain to me why wire and reg are distinguished? What does that accomplish? Why not have a single type of declaration that works everywhere?

--

Rick C.

- Get 1,000 miles of free Supercharging
- Tesla referral code - https://ts.la/richard11209
 
On Sunday, April 19, 2020 at 11:53:03 PM UTC-6, Rick C wrote:
On Sunday, April 19, 2020 at 12:25:11 PM UTC-4, Kevin Neilson wrote:

Yes; those would synthesize the same (but it's recommended that you use blocking assignments (=) in an always@(*) block).

Using the keyword "reg" for combinational and clocked logic can cause a lot of confusion. I would prefer it if the language had you explicitly declare whether something is combinational or registered, and that would make it easier to intermix combinational and clocked logic in the same process and to modify pipelining without rewriting as much code. Nobody asked me when they were writing the spec, though.

In Verilog-2009, you can use the keyword "logic" instead of "reg", but I don't believe the synthesizer treats it any differently.

Can anyone explain to me why wire and reg are distinguished? What does that accomplish? Why not have a single type of declaration that works everywhere?

--

Rick C.

- Get 1,000 miles of free Supercharging
- Tesla referral code - https://ts.la/richard11209

A 'wire' is a simple continuous assignment that can be written outside a process. I guess it makes sense to have those. A 'reg' can be combinational or clocked. That is where the confusion comes in. I would do things differently, but to answer your question you'd probably have to go back to Phil Moorby in 1984 and ask him. Both VHDL and Verilog were written as modeling (not synthesis) languages.
 
On Monday, April 20, 2020 at 1:16:09 PM UTC-4, Kevin Neilson wrote:
On Sunday, April 19, 2020 at 11:53:03 PM UTC-6, Rick C wrote:
On Sunday, April 19, 2020 at 12:25:11 PM UTC-4, Kevin Neilson wrote:

Yes; those would synthesize the same (but it's recommended that you use blocking assignments (=) in an always@(*) block).

Using the keyword "reg" for combinational and clocked logic can cause a lot of confusion. I would prefer it if the language had you explicitly declare whether something is combinational or registered, and that would make it easier to intermix combinational and clocked logic in the same process and to modify pipelining without rewriting as much code. Nobody asked me when they were writing the spec, though.

In Verilog-2009, you can use the keyword "logic" instead of "reg", but I don't believe the synthesizer treats it any differently.

Can anyone explain to me why wire and reg are distinguished? What does that accomplish? Why not have a single type of declaration that works everywhere?

--

Rick C.

- Get 1,000 miles of free Supercharging
- Tesla referral code - https://ts.la/richard11209

A 'wire' is a simple continuous assignment that can be written outside a process. I guess it makes sense to have those. A 'reg' can be combinational or clocked. That is where the confusion comes in. I would do things differently, but to answer your question you'd probably have to go back to Phil Moorby in 1984 and ask him. Both VHDL and Verilog were written as modeling (not synthesis) languages.

So can a reg be written outside a process or is that the real difference? Wires are for continuous assignment and reg for assignment inside a process and never the twain shall meet?

The people I know who use Verilog just use it and don't really seem to know the rules, so they can't even tell me what they are much less why.

I know VHDL was designed by eggheads not at all unlike mathematicians. One guy who worked on the standard wrote some books on using VHDL and had a blog. People would ask him why? questions and it was clear he could only address the how and not the why. Many of the restrictions early on must have had some purpose, but eventually they were removed. I'm guessing most made compiler writing easier.

But wire vs. reg, who cares? VHDL has signals and variables, but they are very different. It's odd that no one seems to understand the why of languages.

--

Rick C.

+ Get 1,000 miles of free Supercharging
+ Tesla referral code - https://ts.la/richard11209
 
On Monday, April 20, 2020 at 12:02:19 PM UTC-6, Rick C wrote:
On Monday, April 20, 2020 at 1:16:09 PM UTC-4, Kevin Neilson wrote:
On Sunday, April 19, 2020 at 11:53:03 PM UTC-6, Rick C wrote:
On Sunday, April 19, 2020 at 12:25:11 PM UTC-4, Kevin Neilson wrote:

Yes; those would synthesize the same (but it's recommended that you use blocking assignments (=) in an always@(*) block).

Using the keyword "reg" for combinational and clocked logic can cause a lot of confusion. I would prefer it if the language had you explicitly declare whether something is combinational or registered, and that would make it easier to intermix combinational and clocked logic in the same process and to modify pipelining without rewriting as much code. Nobody asked me when they were writing the spec, though.

In Verilog-2009, you can use the keyword "logic" instead of "reg", but I don't believe the synthesizer treats it any differently.

Can anyone explain to me why wire and reg are distinguished? What does that accomplish? Why not have a single type of declaration that works everywhere?

--

Rick C.

- Get 1,000 miles of free Supercharging
- Tesla referral code - https://ts.la/richard11209

A 'wire' is a simple continuous assignment that can be written outside a process. I guess it makes sense to have those. A 'reg' can be combinational or clocked. That is where the confusion comes in. I would do things differently, but to answer your question you'd probably have to go back to Phil Moorby in 1984 and ask him. Both VHDL and Verilog were written as modeling (not synthesis) languages.

So can a reg be written outside a process or is that the real difference? Wires are for continuous assignment and reg for assignment inside a process and never the twain shall meet?

The people I know who use Verilog just use it and don't really seem to know the rules, so they can't even tell me what they are much less why.

I know VHDL was designed by eggheads not at all unlike mathematicians. One guy who worked on the standard wrote some books on using VHDL and had a blog. People would ask him why? questions and it was clear he could only address the how and not the why. Many of the restrictions early on must have had some purpose, but eventually they were removed. I'm guessing most made compiler writing easier.

A reg must be inside a process (normally an 'always' process). The most common usage is for a flip-flop inside a clocked process.

It can also be used for combinational logic which requires reassignments that you couldn't do in a continuous assignment. For example:

input [31:0] bits_in; // bits to sum
....
reg [6:0] bitsum; // sum of 1s in bits_in, range 0-32
always@(*) begin
bitsum = 0;
for (int ii=0; ii<32; ii++) bitsum = bitsum + bits_in[ii];
end

I suspect that some of original motivation for this type of combinational process was to speed sims back when computers were slow. You could put a limited number of signals in the sensitivity list which would speed things up a lot. Now, to prevent simulation errors resulting from an oversight in the sensitivity list, we almost always use the wildcard (*) sensitivity list which includes everything.

In the hardware, there are 32 intermediate sums, so maybe in the sim there should really be an array of bitsums, but again, back when computers were slow and RAM was expensive, with this scheme you could reuse a single CPU integer for "bitsum".

You can change this to a clocked process by changing the sensitivity list, but if you do, it's recommended to use an internal var and transfer that using a nonblocking assignment (<=), so that in the sim, 'bitsum' will only be updated at the clock edge:

input [31:0] bits_in; // bits to sum
....
reg [6:0] bitsum; // sum of 1s in bits_in, range 0-32
always@(posedge clk) begin: bitsummer
reg [6:0] bitsum_var; // internal combinational var
bitsum_var = 0; // latch inferred if you forget this!
for (int ii=0; ii<32; ii++) bitsum_var = bitsum_var + bits_in[ii];
bitsum <= bitsum_var; // transfer to flipflops using nonblocking assignment
end

Coders will usually keep combinational regs in unclocked processes. That often makes things hard to read, though. FSMs that are split between unclocked and clocked processes are unwieldy.

I don't like all this and I don't know all the reasons. I don't think there should be two types for combinational logic, and I don't really like that a 'reg' can be either combinational or registered.

Something to keep in mind is that latches used to be much more common, because they use fewer gates. I suspect that the non-clocked form of 'reg' was really meant to be used to model latches, which are more like flipflops than like combinational logic:

reg [31:0] data_hold; // a latch
always@(data_vld) begin
if (data_vld) data_hold = data; // This infers a latch
end

Nowadays this just causes trouble because if you use unclocked processes you can infer latches if you are not careful. If you put an 'else data_hold=0;' after the 'if', then the latch becomes combinational logic.

I also think it was a massive oversight not to allow inline delay lines so that pipelines could be easily adjusted. I think there is something like this in Systemverilog, but it's not synthesizable:

parameter RAM_LATENCY=3; // read_req->data_out latency
always@(posedge clk) begin
if (read_req##RAM_LATENCY) // valid 3 cycles after read_req asserted
do_stuff...
end

Because of this, changing pipelining is always a big headache. These are things Phil Moorby wasn't thinking about, I guess. Again, he was really making a modeling language. Also, I think the initial concentration was on gate-level modeling and less on RTL.
 
On Monday, April 20, 2020 at 5:19:11 PM UTC-4, Kevin Neilson wrote:
On Monday, April 20, 2020 at 12:02:19 PM UTC-6, Rick C wrote:

So can a reg be written outside a process or is that the real difference? Wires are for continuous assignment and reg for assignment inside a process and never the twain shall meet?

The people I know who use Verilog just use it and don't really seem to know the rules, so they can't even tell me what they are much less why.

I know VHDL was designed by eggheads not at all unlike mathematicians. One guy who worked on the standard wrote some books on using VHDL and had a blog. People would ask him why? questions and it was clear he could only address the how and not the why. Many of the restrictions early on must have had some purpose, but eventually they were removed. I'm guessing most made compiler writing easier.

A reg must be inside a process (normally an 'always' process). The most common usage is for a flip-flop inside a clocked process.

It can also be used for combinational logic which requires reassignments that you couldn't do in a continuous assignment. For example:

input [31:0] bits_in; // bits to sum
...
reg [6:0] bitsum; // sum of 1s in bits_in, range 0-32
always@(*) begin
bitsum = 0;
for (int ii=0; ii<32; ii++) bitsum = bitsum + bits_in[ii];
end

I suspect that some of original motivation for this type of combinational process was to speed sims back when computers were slow. You could put a limited number of signals in the sensitivity list which would speed things up a lot. Now, to prevent simulation errors resulting from an oversight in the sensitivity list, we almost always use the wildcard (*) sensitivity list which includes everything.

In the hardware, there are 32 intermediate sums, so maybe in the sim there should really be an array of bitsums, but again, back when computers were slow and RAM was expensive, with this scheme you could reuse a single CPU integer for "bitsum".

You can change this to a clocked process by changing the sensitivity list, but if you do, it's recommended to use an internal var and transfer that using a nonblocking assignment (<=), so that in the sim, 'bitsum' will only be updated at the clock edge:

input [31:0] bits_in; // bits to sum
...
reg [6:0] bitsum; // sum of 1s in bits_in, range 0-32
always@(posedge clk) begin: bitsummer
reg [6:0] bitsum_var; // internal combinational var
bitsum_var = 0; // latch inferred if you forget this!
for (int ii=0; ii<32; ii++) bitsum_var = bitsum_var + bits_in[ii];
bitsum <= bitsum_var; // transfer to flipflops using nonblocking assignment
end

VHDL is pretty much the same. It's been so long since I've coded I've rather forgotten a lot, but signals are assigned with <= and are non-blocking, variables are only used in processes, assigned with := and are blocking.. That's why I asked about wires vs. regs, it's not the same as VHDL.


> Coders will usually keep combinational regs in unclocked processes. That often makes things hard to read, though. FSMs that are split between unclocked and clocked processes are unwieldy.

I see that sometimes. The details of the register usually aren't so complicated so the clocked process is small and simple. The combinational process has all the work in it. The advantage is you can have unregistered outputs from the combinational process while with the single process an unclocked signal has to be added externally anyway.

Hmmm... I say that, but in VHDL a clocked process has an IF (rising_edge(clk)) to qualify the clocking. If you put assignments outside the IF statement they will be combinatorial logic, but in simulation only updated on the two edges of the clock.

signal reg : std_logic;

process (clk)
variable foo : std_logic;
begin
foo := stuff and other_stuff;
if (rising_edge(clk)) then
reg <= foo or more_stuff;
end if;
end;

I think this would work but very unconventional. Foo would be updated prior to being used and reg would be a register updated when the process stops.


> I don't like all this and I don't know all the reasons. I don't think there should be two types for combinational logic, and I don't really like that a 'reg' can be either combinational or registered.

Yeah, VHDL doesn't separate based on combinational vs. registered either, the type distinctions are about assignment types which is worth something I suppose.


> Something to keep in mind is that latches used to be much more common, because they use fewer gates. I suspect that the non-clocked form of 'reg' was really meant to be used to model latches, which are more like flipflops than like combinational logic:

Yeah, that's possible.


data_hold; // a latch
always@(data_vld) begin
if (data_vld) data_hold = data; // This infers a latch
end

Nowadays this just causes trouble because if you use unclocked processes you can infer latches if you are not careful. If you put an 'else data_hold=0;' after the 'if', then the latch becomes combinational logic.

In VHDL they warn you about incomplete conditionals in combinational processes creating latches.


I also think it was a massive oversight not to allow inline delay lines so that pipelines could be easily adjusted. I think there is something like this in Systemverilog, but it's not synthesizable:

parameter RAM_LATENCY=3; // read_req->data_out latency
always@(posedge clk) begin
if (read_req##RAM_LATENCY) // valid 3 cycles after read_req asserted
do_stuff...
end

Because of this, changing pipelining is always a big headache. These are things Phil Moorby wasn't thinking about, I guess. Again, he was really making a modeling language. Also, I think the initial concentration was on gate-level modeling and less on RTL.

I guess we should be glad he wasn't trying to do transistor level simulations.

--

Rick C.

-- Get 1,000 miles of free Supercharging
-- Tesla referral code - https://ts.la/richard11209
 
On Saturday, 4/18/2020 12:18 AM, TJ Edmister wrote:
Even though you can't use a wire the same way you can use a reg (ie.
inside an always or conditional block), can't a reg end up behaving just
like a wire if you put it in an always @(*) block? By that I mean, it
changes asynchronously depending only on its inputs? For instance, these
examples:

// program 1

wire [3:0] news = friday ? goodnews : badnews;

// program 2

reg [3:0] news;

always @(*) begin

if (friday) news <= goodnews;
    else news <= badnews;

end

Any difference in how these would synthesize?

The names wire and register come from the historical use of Verilog for
modelling or simulation. The language is really written from the
perspective of the person writing a simulator. A reg implies that
storage is required to simulate the value, whether or not the resultant
function is combinatorial or sequential. A wire does not require
storage as it can be reconstructed from its inputs. Of course this is a
very simplistic look at a wire, and I'm sure most simulators use storage
for wires to simplify the implementation of delays among other reasons.

By the way, there's no need to put * in parentheses for always @*
blocks. In fact some text editors get confused by (*) because of the
Verilog 2001 (* attribute = value *) syntax.

--
Gabor
 
By the way, there's no need to put * in parentheses for always @*
blocks. In fact some text editors get confused by (*) because of the
Verilog 2001 (* attribute = value *) syntax.

--
Gabor

My Emacs Verilog mode gets confused when I write @*. I haven't updated my Emacs in quite a while, though.
 

Welcome to EDABoard.com

Sponsor

Back
Top