Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > VHDL > Re: Why not mix concurrent and synchronous assignments in the same process?

Reply
Thread Tools

Re: Why not mix concurrent and synchronous assignments in the same process?

 
 
KJ
Guest
Posts: n/a
 
      09-03-2012
On Sunday, September 2, 2012 7:04:43 AM UTC-4, Per Christian Corneliussen wrote:
> I've been working as a VHDL designer for about one year now, and I also have some experience with Verilog. One aspect of VHDL that I don't like is that there is no way to mix concurrent and synchronous assignments in the same process. I you want to create a Mealy-type state machine, you have to create one synchronous process and one concurrent process. This takes up a lot of additional space in the code since the concurrent process has to replicate the process-case-when structure. And worse, this will (especially for large state machines) place synchronous and concurrent assignments for eachstate on very different places in the code, making it hard to read and maintain. Creating additional _next-signals that are written to in the concurrent process and back to the corresponding synchronous signals in the synchronous process (e.g., state <= state_next) can be a more elegant solution,especially if most of the outputs of the state machine are concurrent. ButI imagine a language with a separate concurrent assignment operator would be a lot more elegant, see a hypothetical example below: process (clk_i'rising) -- Defines clock for synchronous assignments begin case state is when s_idle => if req_i = '1' then fifo_read %= '1'; -- Concurrent assignment state <= s_read_data; -- Synchronous assignment end if; (...) end case; end process; However, I haven't really thought this completely through and the fact that Verilog has the same problem leads me to believe that there's some good reason for not doing this that I haven't thought of. Any insights?


- Stop thinking in terms of 'Mealy' and 'Moore'.
- Toss out books that pontificate on how 'two process' or 'three process' is the way to design
- Code up the functional behavior you want to implement so that it is functionally correct
- Start to use variables when you get to things where you would otherwise need to copy/paste code inside your process.

Your aim here is to have the following structure:
- Single clocked process with all of the complex logic
- Possibly some loose concurrent statements for things that need to not wait a clock cycle. When you've got it down correctly, you'll find that the logic in these concurrent statements is not complex. If you find yourself longing for 'if' or 'case' statements in these concurrent statements, then you need to go back to your single clocked process and do more work.

In the example you posted, I would modify if at follows:

process (clk_i) -- Defines clock for synchronous assignments
begin
wait until rising_edge(clk_i); -- Or use "if rising_edge(clk_i) then..."
case state is
when s_idle =>
if req_i = '1' then
-- Move out fifo_read %= '1'; -- Concurrent assignment
state <= s_read_data; -- Synchronous assignment
end if;
(...)
end case;
end process

fifo_read <= to_std_logic(state = s_idle) and req_i;

Where 'to_std_logic' is a function that you can write that simply takes as input a boolean and returns a std_ulogic.

Kevin Jennings
 
Reply With Quote
 
 
 
 
rickman
Guest
Posts: n/a
 
      09-04-2012
On 9/2/2012 9:34 PM, KJ wrote:
> On Sunday, September 2, 2012 7:04:43 AM UTC-4, Per Christian Corneliussen wrote:
>> I've been working as a VHDL designer for about one year now, and I also have some experience with Verilog. One aspect of VHDL that I don't like is that there is no way to mix concurrent and synchronous assignments in the same process. I you want to create a Mealy-type state machine, you have to create one synchronous process and one concurrent process. This takes up a lot of additional space in the code since the concurrent process has to replicate the process-case-when structure. And worse, this will (especially for large state machines) place synchronous and concurrent assignments for each state on very different places in the code, making it hard to read and maintain. Creating additional _next-signals that are written to in the concurrent process and back to the corresponding synchronous signals in the synchronous process (e.g., state<= state_next) can be a more elegant solution, especially if most of the outputs of the state machine are concurrent. But I imagine a language wi

th a separate concurrent assignment operator would be a lot more elegant, see a hypothetical example below: process (clk_i'rising) -- Defines clock for synchronous assignments begin case state is when s_idle => if req_i = '1' then fifo_read %= '1'; -- Concurrent assignment state<= s_read_data; -- Synchronous assignment end if; (...) end case; end process; However, I haven't really thought this completely through and the fact that Verilog has the same problem leads me to believe that there's some good reason for not doing this that I haven't thought of. Any insights?
>
> - Stop thinking in terms of 'Mealy' and 'Moore'.
> - Toss out books that pontificate on how 'two process' or 'three process' is the way to design
> - Code up the functional behavior you want to implement so that it is functionally correct
> - Start to use variables when you get to things where you would otherwise need to copy/paste code inside your process.
>
> Your aim here is to have the following structure:
> - Single clocked process with all of the complex logic
> - Possibly some loose concurrent statements for things that need to not wait a clock cycle. When you've got it down correctly, you'll find that the logic in these concurrent statements is not complex. If you find yourself longing for 'if' or 'case' statements in these concurrent statements, then you need to go back to your single clocked process and do more work.
>
> In the example you posted, I would modify if at follows:
>
> process (clk_i) -- Defines clock for synchronous assignments
> begin
> wait until rising_edge(clk_i); -- Or use "if rising_edge(clk_i) then..."
> case state is
> when s_idle =>
> if req_i = '1' then
> -- Move out fifo_read %= '1'; -- Concurrent assignment
> state<= s_read_data; -- Synchronous assignment
> end if;
> (...)
> end case;
> end process
>
> fifo_read<= to_std_logic(state = s_idle) and req_i;
>
> Where 'to_std_logic' is a function that you can write that simply takes as input a boolean and returns a std_ulogic.
>
> Kevin Jennings


I'm at a loss here. First, I don't know what the %= symbols are
supposed to mean and I can't find it anywhere. Secondly, if the OP
intends this to mean a concurrent signal assignment, how could that
possibly work correctly in simulation? I take it to mean that all of
the conditionals define the logic without regard to the clocked process
qualifier. But in simulation how would the concurrent statement be
reached when the logic inputs change? The concurrent assignment would
not be executed until the next clock edge resulting in a big mismatch
between simulation and expected behavior, not to mention synthesis.

Am I missing something?

Rick
 
Reply With Quote
 
 
 
 
rickman
Guest
Posts: n/a
 
      09-20-2012
On 9/20/2012 9:56 AM, Per Christian Corneliussen wrote:
> On Tuesday, September 4, 2012 9:40:03 PM UTC+2, rickman wrote:
>
>> I'm at a loss here. First, I don't know what the %= symbols are
>> supposed to mean and I can't find it anywhere.

>
> I should have been more clear. The code example I gave is not supposed to be valid VHDL, it's in a hypothetical language with a different syntax. The idea is that<= is the synchronous assignment operator and %= the concurrent assignment operator. The first line ("process (clk_i'rising)") defines the clock to be used for synchronous assignments in the process. I realize that this wouldn't work with the current simulation model. A simulator for this language would need to run through the process whenever any of the signals used in concurrent assignments change (ignoring synchronous assignments) then again on positive clock edges, doing both synchronous and concurrent assignments.
>
> Note that KJ's attempt to fix my code to valid VHDL illustrates the problem I tried to describe in the original post; moving the fifo_read assignment out of the process like this makes the code harder to read (especially if the synchronous process was 500+ lines.)
>
> What I was hoping for here was some ideas to why this kind of language would be bad, or perhaps confirmation that it would be better.


Not trying to be critical, but if you don't understand why you can't
generally create async assignments in a sync process, then you don't
understand VHDL. The limitations of VHDL mostly are traceable to how to
corresponds to hardware.

Since you are using a hypothetical language, I can't say for sure, but I
would assume the statement process (clk_i'rising) means the same thing
as in VHDL, trigger the process on the clock rising edge. That means
the process won't run when inputs to the async assignment change and the
simulation won't be valid.

Of course as Andy indicated, the case where you can create async
assignments in a sync process is when the async assignments only depend
on variables that are being assigned in the process. Although the async
signals depend on the variables, the variables depend on the clock and
have no delta delay, so are updated immediately. So in effect, the
signals do depend on the clock, just indirectly.

The one limitation of doing this is if you need the state variable
outside the process, you have to assign it to a signal requiring more
code. Also, this signal will have the same timing as the async signals
which, theoretically, might require logic. In a pre-layout simulation
this would not show delta delays between the sync and async signals.
Not sure if this really matters to most simulations. I prefer for my
simulations to look as much like real logic as possible.

Rick
 
Reply With Quote
 
Andy
Guest
Posts: n/a
 
      09-20-2012
By having some statements that are only executed on some events, and other statements that are only executed on other events, you are going to have a devil of a time avoiding latches when the process triggers but the concurrent assignment is not executed.

Memory elements (latches, registers, RAM, etc.) are inferred when the description requires remembering a value assigned at a previous simulation time or delta. This usually happens when an assignment is not (or has not yet, in the case of a variable assignment) executed during a process's execution cycle (wake-up to suspend). If the process is combinatorial, a latch is inferred to remember the value. If the process is clocked, a register is inferred to remember the value.

In your example, the sensitiviy list (apparently you want it to be implied)would also need to contain the state signal.

If your example had a reset for the registers, then you would have some conditional logic surrounding the concurrent statement that would have to be ignored for the concurrent assignment (e.g. you want to concurrently assign it whether reset is active or not). Yet you also have conditional logic (the case statement) that you don't want to ignore. And yet when the state is not s_idle, you want to concurrently assign it to something, right? (to avoid the latch!)

Hopefully you can see what a mine-field of issues this seemingly simple, little statement would create...

VHDL (and verilog) synthesis starts to make a lot more sense when you understand how hardware is inferred from code BEHAVIOR, instead of from code structure. Unfortunately, most texts focus on synthesis of code structure.

Andy
 
Reply With Quote
 
Andy
Guest
Posts: n/a
 
      09-21-2012
When you start mixing sensitivity lists, beware that synthesis completely ignores them, but the simulator faithfully follows them. The result is oftena mismatch between the behavior of the RTL model and that of the resultinggate level model. Your simulation of the RTL may convince you that what you have desinged works fine, but the synthesized HW may not.

My point about latches in your original example was that if you were not inthe right state (or were in reset), there was no concurrent assignment to execute. That would create a latch on the concurrently assigned signal. Thesolution would be simple (default concurrent assignments at the beginning of the process, before the if-reset-then statement). This is also the best way to avoid latches in standard combinatorial processes.

Your proposed execution model differs very significantly from how a normal executable SW model would execute. Having specific parts of the code that "magically" execute (or not) under specific, implied, conditions makes the code's behavior much less evident to the reader. And if the behavior is muchless evident, it is much more likely to be incorrect.

If you really want to mix concurrent and sequential behavior in the same context, consider the two-process (combinatorial and clocked) model, with allof the "logic" in the combinatorial process, and only the registers in theclocked process. It would work well for what you want to do, it is available today, and it does not require adding confusing and very difficult to implement new features to the language. I would recommend pairing the two processes in a block statement, and locally declare those signals that are only accessed by the two processes. This keeps the "external" signals separated from the "internal" signals, and promotes maintainability by preventing unexpected external dependencies on otherwise internal signals. This is one reason I prefer to use variables in processes, because of the inability to access them externally. The only time I use a signal is when one process needs to talk to another.

Andy

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: Why not mix concurrent and synchronous assignments in the same process? Andy VHDL 3 09-11-2012 08:07 PM
Difference between synchronous (proactor pattern) and synchronous model in web server Rickert C++ 0 10-06-2011 04:54 AM
findcontrol("PlaceHolderPrice") why why why why why why why why why why why Mr. SweatyFinger ASP .Net 2 12-02-2006 03:46 PM
Signals and variables, concurrent and sequential assignments Taras_96 VHDL 5 04-14-2005 03:07 AM
Concurrent assignments to std_ulogic_vector slice is OK with ModelSim Nicolas Matringe VHDL 9 06-14-2004 10:10 PM



Advertisments