Hi everyone
Thanks a lot for your replies, VHDL makes a lot more sense now

. I
do have a few resulting questions; they're a bit late because I had to
think about the contents for a while (warning: long post).
Blocking and blocking assignments in VHDL & Verilog
---------------------------------------------------
I was hoping someone could tell me if the following analysis was
correct, as I'm a bit rusty?
Example 1:
Assume
a = 1
b = 2
c = 3
a<=b; //a is scheduled to be assigned 2
c<=a; //c is scheduled to be assigned 1
b = b + a; //b is assigned 3 - nb: this does not create race
conditions because variable assignments (blocking) are local to the
process. As a side effect, there is no need for other non-blocking
assignments in other processes to run up to this point (contrast with
Verilog below)
f<=b; //f is scheduled to be assigned 3
g<=a; //g is scheduled to be assigned 1 (ie: a<=b hasn't been executed
yet) - correct?
Example 2:
a<=b //a scheduled to be assigned 2
c<=a //c scheduled to be assigned 1
b:=c //b is set to 3
d<=b //d scheduled to be assigned 3
Example 3:
always@(posedge clock)
begin
a<=b;
c<=a;
b = b + a; // the simulator must wait for 5 & 6 to execute before
proceeding - (is this correct?)
f<=b;
end
always@(posedge clock)
begin
g <= b //5
f <= b + a //6
d = c + b //7
end
Sequential Assignment
---------------------------------------------------
The 'sequentiality' comes from being able to do this:
a<=b
a<=c
this wouldn't make sense in concurrent VHDL for synthesis because it
represents:
------b----
|------a---------
------c----
>Yes and no. The *results* would certainly be the same. The key is
>that you are making nonblocking assignment ("signal assignment" in
>VHDL-speak) to two DIFFERENT signals, so it doesn't matter in which
>order they are executed.
So are you saying that my code was the same because the signals were
different. However, with something like that shown below, it wouldn't
be the same:
eg 1:
process(clk)
begin
if rising_edge(clk) then
a<=b;
end if;
end process;
process(clk)
begin
if rising_edge(clk) then
if (complicated expression) then
a<=c
end if;
end if;
end process
is NOT the same as eg 2:
process(clk)
begin
if rising_edge(clk) then
a<=b
if (complicated expression) then
a<=c
end if;
end if;
end process;
The first instance requires the value of 'a' to be resolved, while the
second example will just 'overwrite' the value to be assigned to 'a' (I
think).
Concurrent assignments are approximately the same as assignments in
Verilog processes in VHDL corresponds to always blocks in Verilog.
Having said that, I would like to discuss some general design
guidelines, referring to Mike's way.
I think what Mike is suggesting is that, using his example:
Instead of writing (in VHDL pseudocode):
shift_result <= shift(input);
mask_result <= mask_inversion(shift_result);
add_result <= mask_result + 42;
process (clock)
if rising_edge(clock) then
output <= add_result;
end if;
end process;
We write:
process (clock)
shift_result := shift(input);
mask_result := mask_inversion(shift_result);
if rising_edge(clock) then
output <= mask_result+42;
end if;
end process;
What is the advantage of the bottom notation? Or is this more obvious
in more complex examples (admittedly I haven't read the linked article
in depth, in particular the UART example).
The top example maps into Verilog as:
assign shift_result = shift(input);
assign mask_result = mask_inversion(shift_result);
assign sum_result = mask_result + 42;
always@(posedge clock)
begin
output <= sum_result;
end
While the bottom example maps (I think) into Verilog as:
always@(posedge clock)
begin
shift_result = shift(input);
mask_result = mask_inversion(shift_result);
output <= mask_result + 42;
end
I was taught these basic rules for Verilog coding:
1) Do not use complex combinational relationships in
assign values (I didn't know why at first, but I found this quote
on a Usenet board:
"If you wanted the latch or combinational logic. I would decide which
construct to use based on the other features available in continuous
assignments vs. procedural assignments. These are delays and strengths.
You can give strengths to wires and not regs (so you would use the
continuous assignment if you wanted this feature). The delay semantics
for a continuous assignment and a procedural assignment are very
different (see the IEEE1364-1995 spec).)"
2) If you wish to model combinational logic, use an
always@(/*AUTOSENSE*/) block with blocking assignments (AUTOSENSE
automatically generates a complete sensitivity list, thus avoiding
latch inference)
3) If you wish to model synchronous logic, use an always@(posedge
clock) block with non-blocking assignments.
4) Never mix the two blocks:
Some quotes from Usenet:
"In summary then, one should use non-blocking assignments to
synchronous signals and blocking assignments in combinational
constructs. Don't mix them together. "
...."sequential blocks use non-blocking <=
combinational blocks use blocking ="
Now, the bottom example in Verilog, which is what Mike suggests what
variables are 'good' for, mixes both blocking and non-blocking
statements, which breaks guideline 4. Any comments?
Additionally, I'm considering using the following 'template' for the
code I wish to write:
architecture behavioural of blah is
//signal definitions
begin
//do the combinational logic part here
//using concurrent assignments
//assign the result to some 'temporary
//variable' called comb_out for example
process (clock)
begin
if rising_edge(clock) then
//possibly do some muxing here to
//choose the input based on the state
//for example if(reset) then module_out<= 0;
module_out<=comb_out;
end if;
end process;
end behavioural;
Apart from the problems highlighted in the document linked by Mike, is
there any problems with doing this? The additional problem with using
the method suggested in the document linked by Mike is that a fair bit
of trust is put in the synthesiser. Usually this wouldn't be a
problem, but the chip I'm designing, an RSA decryption chip, should be
resistant to 'Timing Analysis' attacks, which means that every
decryption should take *exactly* the same amount of time. This means
that in some instances we may do an add and store it in a dummy
register even if we don't require the results of the add. I'm afraid
that the synthesiser might 'optimise away' this required architecture,
and thus maybe my template is the best approach - any ideas?
Egbert
---------------------------------------------------
On a final note, with Egbert's example, I was initially a bit confused
about why in the bottom example, b:=c synthesises into a flip-flop. My
initial train of thought was "but b can only be assigned to c on the
rising edge of the clock, however the synthesis results tell us that b
is always the value of c!". I think the answer to this is: I remember
reading somewhere (I can't find where now, annoyingly), that variables
retain their values until the next process execution. This means that
while the process isn't executing, b == c, thus, for all time, b == c
(even though the assignment is done within the clocked process)
Thanks again everyone
Taras