• a wire by any other name

    From TJ Edmister@21:1/5 to All on Sat Apr 18 00:18:26 2020
    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?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kevin Neilson@21:1/5 to TJ Edmister on Sun Apr 19 09:25:09 2020
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rick C@21:1/5 to Kevin Neilson on Sun Apr 19 22:53:00 2020
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kevin Neilson@21:1/5 to Rick C on Mon Apr 20 10:16:07 2020
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rick C@21:1/5 to Kevin Neilson on Mon Apr 20 11:02:15 2020
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kevin Neilson@21:1/5 to Rick C on Mon Apr 20 14:19:08 2020
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rick C@21:1/5 to Kevin Neilson on Tue Apr 21 21:02:43 2020
    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.


    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.

    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Gabor@21:1/5 to TJ Edmister on Sat May 2 11:30:43 2020
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kevin Neilson@21:1/5 to All on Mon May 4 15:36:00 2020
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From EML@21:1/5 to All on Sun May 17 09:54:32 2020
    There is, unusually, an SO Q/A that addresses the 'why' (https://stackoverflow.com/a/33504420/785194).

    Basically, it's just historic confusion. If you go back to the early pre-IEEE LRMs it's obvious that a 'reg' really was meant to be a register, and the concept of 'continuously driving' wasn't well understood. This wasn't really rationalised until SV.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)