If you are wondering about how the <= operator works; it is what is called a 'nonblocking assignment.' What this means is that the left hand side of all of the <= are performed for a particular event (e.g. rising clock edge) and then once those are all evaluated, the result is placed in the output. This allows you to write shift registers without temporary variables. None of the values change until the left hand calculations are completed, then the results are moved over to the right hand side. It is generally not a good idea to use nonblocking assignments for combinatorial logic. Generally they are only used to create latches and registers and you use regular blocking assignments for combinatorial logic. When synchronized with a clock signal, you can generally consider <= operations to be D flip-flops that sample the input and transfer it to the output atomically on a single clock edge.
'Race conditions' where intermediate indeterminate results appear on the outputs of combinatorial functions are hard to avoid and they can depend greatly on how the design is actually implemented on an ASIC or FPGA. However, most designs are synchronous and so as long as the output settles within one clock period this is not a problem. There are tools that can check the timing performance of a design to check all of the path delays to ensure that the results will always be valid for a given clock frequency, but this is highly dependent not on the actual HDL code but on the way the design is placed and routed.
Synthesizers (not compilers!!!!) will generally perform optimization on combinatorial logic. There are limits to how much the synthesizer can do (e.g. it will not re-architect your system) so you have to know more or less how it will end up being implemented. If you're working on an FPGA, generally the synthesis and place and route will pack any logic function that fits onto LUTs. So if you can separate out a single logic function with up to 4 inputs and 1 output, this will end up on a single LUT and the only delay that matters is the propagation delay of the LUT, which is the same for all of its inputs. In the case of your example function, both pieces of code may be implemented identically on one LUT with three inputs and one output.
Only sequential statements are allowed inside a process statement. An architecture statement part is comprised of zero or more concurrent statements. rtl appears to be the name of architecture and a process statement is a concurrent statement.
Notice from your referenced code you are having problems with:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity circularshift is port (
sn : in std_logic_vector(5 downto 1); -- number of rotate steps
di : in std_logic_vector(32 downto 1); -- data in
encdec : in std_logic ; -- enc or dec
do : out std_logic_vector(32 downto 1) -- data out
);
end circularshift;
architecture Behavioral of circularshift is
signal d0 : std_logic_vector(32 downto 1);
signal d1 : std_logic_vector(32 downto 1);
signal d2 : std_logic_vector(32 downto 1);
signal d3 : std_logic_vector(32 downto 1);
signal d4 : std_logic_vector(32 downto 1);
signal r1 : std_logic_vector(32 downto 1);
signal r2 : std_logic_vector(32 downto 1);
signal r4 : std_logic_vector(32 downto 1);
signal r8 : std_logic_vector(32 downto 1);
signal d5 : std_logic_vector(32 downto 1);
signal r16 : std_logic_vector(32 downto 1);
begin
p1 : process (encdec)
begin
if encdec <= '1' then
r1 <= d0(32-1 downto 1) & d0(32);
r2 <= d1(32-2 downto 1) & d1(32 downto 32-1);
r4 <= d2(32-4 downto 1) & d2(32 downto 32-3);
r8 <= d3(32-8 downto 1) & d3(32 downto 32-7);
r16 <= d4(32-16 downto 1) & d4(32 downto 32-15);
d0 <= di;
d1 <= r1 when (sn(1)='1') else d0;
d2 <= r2 when (sn(2)='1') else d1;
d3 <= r4 when (sn(3)='1') else d2;
d4 <= r8 when (sn(4)='1') else d3;
d5 <= r16 when (sn(5)='1') else d4;
do <= d5;
else
r1 <= d0(1) & d0(32 downto 2 );
r2 <= d1(2 downto 1) & d1(32 downto 3);
r4 <= d2(4 downto 1) & d2(32 downto 5);
r8 <= d3(8 downto 1) & d3(32 downto 9);
r16 <= d4(16 downto 1) & d4(32 downto 17);
d0 <= di;
d1 <= r1 when (sn(1)='1') else d0;
d2 <= r2 when (sn(2)='1') else d1;
d3 <= r4 when (sn(3)='1') else d2;
d4 <= r8 when (sn(4)='1') else d3;
d5 <= r16 when (sn(5)='1') else d4;
do <= d5;
end if;
end process;
end Behavioral;
-- I'm getting the following Error messages for my code posted below. (I'm using the xilinx 8.1.03i and modelsim )
-- When I run check syntax, the following is displayed:
-- Compiling vhdl file "C:/Xilinx/rcc2/rc5pi/circularshift.vhd" in Library work.
-- ERROR:HDLParsers:164 - "C:/Xilinx/rcc2/rc5pi/circularshift.vhd" Line 38. parse error, unexpected WHEN, expecting SEMICOLON
-- ERROR:HDLParsers:164 - "C:/Xilinx/rcc2/rc5pi/circularshift.vhd" Line 39. parse error, unexpected WHEN, expecting SEMICOLON
-- ERROR:HDLParsers:164 - "C:/Xilinx/rcc2/rc5pi/circularshift.vhd" Line 40. parse error, unexpected WHEN, expecting SEMICOLON
-- ERROR:HDLParsers:164 - "C:/Xilinx/rcc2/rc5pi/circularshift.vhd" Line 41. parse error, unexpected WHEN, expecting SEMICOLON
-- ERROR:HDLParsers:164 - "C:/Xilinx/rcc2/rc5pi/circularshift.vhd" Line 42. parse error, unexpected WHEN, expecting SEMICOLON
-- ERROR:HDLParsers:164 - "C:/Xilinx/rcc2/rc5pi/circularshift.vhd" Line 49. parse error, unexpected WHEN, expecting SEMICOLON
-- ERROR:HDLParsers:164 - "C:/Xilinx/rcc2/rc5pi/circularshift.vhd" Line 50. parse error, unexpected WHEN, expecting SEMICOLON
-- ERROR:HDLParsers:164 - "C:/Xilinx/rcc2/rc5pi/circularshift.vhd" Line 51. parse error, unexpected WHEN, expecting SEMICOLON
-- ERROR:HDLParsers:164 - "C:/Xilinx/rcc2/rc5pi/circularshift.vhd" Line 52. parse error, unexpected WHEN, expecting SEMICOLON
-- ERROR:HDLParsers:164 - "C:/Xilinx/rcc2/rc5pi/circularshift.vhd" Line 53. parse error, unexpected WHEN, expecting SEMICOLON
That the line you ask about in your question is line 54:
d3 <= r4 when (sn(3)='1') else d2;
And that this a concurrent signal assignment and yet it is showing up in a process statement (the domain of sequential statements).
The form of this is a 'conditional signal assignment', which happens to have been added to sequential signal assignments by IEEE Std 1076-2008 (10.5.3 Conditional signal assignments, § 10 is entitled Sequential statements).
And from this we can infer that while Modelsim supports the 2008 VHDL standard, your XST doesn't (error messages of the form 'ERROR:HDLParsers:' are XST messages).
If and when Xilinx would support synthesis of conditional signal assignment statements within a process (as sequential signal assignment) is a matter of versions and/or policy. There's no particular difference in difficulty of synthesis to support it, while representing significant change in the parser.
VHDL is case insensitive except in extended identifiers and character literals.
From IEEE Std 1076-2008 15.2 Character set:
The only characters allowed in the text of a VHDL description (except
within comments—see 15.9, and within text treated specially due to the
effect of tool directives—see 15.11) are the graphic characters and
format effectors. Each graphic character corresponds to a unique code
of the ISO eight-bit coded character set (ISO/IEC 8859-1:1998) and is
represented (visually) by a graphical symbol.
basic_graphic_character ::=
upper_case_letter | digit | special_character | space_character
graphic_character ::=
basic_graphic_character | lower_case_letter | other_special_character
basic_character ::=
basic_graphic_character | format_effector
The basic character set is sufficient for writing any description,
other than a PSL declaration, a PSL directive, or a PSL verification
unit.
And 15.4 Identifiers:
All characters of a basic identifier are significant, including any
underline character inserted between a letter or digit and an adjacent
letter or digit. Basic identifiers differing only in the use of
corresponding uppercase and lowercase letters are considered the same.
addendum
Thanks a lot for the answer, how about the Inside_process vs
Outside_process ? Out_signal <= signal1 and (not signal2); Out_signal
is being assigned once inside and once outside, but the result doesn't
change, circuit still works, no warnings? So is this a sequential
assignment or concurrent? If concurrent, how can it be inside the
process, if sequential, how can it be outside the process? – Anarkie
6 hours ago
There's an obvious difference between the two processes. The one with the concurrent signal assignment(Outside_process
) will have Out_signal
show change immediately upon change update for signals signal1
and signal2
because the concurrent signal assignment will have an equivalent process containing a sequential signal assignment statement and a sensitivity list equivalent containing signal1
and signal2
. (Every signal appearing on the right hand side of a signal assignment statement).
The process Inside_process
only has clk
in the sensitivity list, meaning in simulation Out_signal
will be assigned at the next clk'EVENT
, an apparent half clock delay because the assignments to your two shift register signals are visible in the next delta cycle.
See this stackoverflow answer The VHDL Simulation Cycle as well as this one - Unexpected delays with register VHDL.
Interestingly enough both will probably synthesize identically because the sensitivity list will either be disregarded or updated (assumed to include signal1
and signal2
in Inside_process
). Any assumptions should likely show up in warnings.
Elaboration devolves a design description into block statements (maintaining hierarchy), process statements and function calls. All concurrent statements have a process statement equivalent, potentially within block statements (or nested block statements). In the case of simple signal assignment statements there is little observable difference between signal assignment inside or outside a process (except the sensitivity list which in this case is incomplete for Inside_process
).
A design specification will be elaborated before simulation and as a predicate for synthesis as well.
Best Answer
It comes back to draw the picture of what you proposed and then think about the implications.
Rising_edge has a special meaning. It designates the signal that connects to the clock pin of a flip-flop.
First consider signals that come from the output of regular logic. These are not suitable as clocks because they can glitch. In old board designs, we were able to remove glitches by creating logic with redundant terms, however, in FPGAs and ASICs we generally do not know if the target implementation will glitch or not. In addition, synthesis tools work hard to remove redundant logic - yes we can stop them from doing that, but no it is not fun. In addition, clocks generated off of logic have poor timing characteristics (delays, skew, ...). The old board designs were slow, so this wasn't too bad.
Now consider signals that come from the output of another flip-flop. Historically board designs did use these as clocks. We don't do this so much in ASIC and FPGA design. One reason is the design is considerably larger and the timing analysis becomes more challenging. Another reason is that we want to minimize the number of clock domains as any clock domain crossing must be done properly or it is problematic.
Generally in ASIC and FPGA designs, we try to minimize the number of clock domains. We try to keep good skew control of the clocks we do have - hence, we do not gate (add logic including inverters) to the clocks unless we are using a methodology that supports this.
In an FPGA, generally this means we are using a clock wizard or instantiating a vendors clock block. Those that know me may be giggling at that as my usual answer is write the code, wizards are evil (because the lock you into a particular vendor).