Can I make a nested with-select-when statement in VHDL? - vhdl

I've yet to see anywhere show an example of this, and I've yet to need it until now.
I have 2 control signals, and I need to make a nested with-select-when statement for them. I can easily nest things with case statements, but I have recently realized that I need this bit of code outside of a process because it screws with the timing. Here is the code I currently have:
case OpcodeIn is =>
when "000000" =>
case FunctIn is =>
when "00000" =>
...
when "00001" ==>
...
end case;
when "000001" =>
...
end case;
Also, I cannot just concatenate like:
controlSig <= OpcodeIn & FunctIn;
and then use:
with controlSig select output <=
...
because the FunctIn is only valid depending on certain values of OpcodeIn. Thus it would only work if there was a wildcard character like:
"0010" when "000001***********";

Try it, see if it works! There's no reason that the language prohibits this behavior. You're actually incorrect that VHDL does not support a case statement with Don't Cares. As of VHDL-2008, this feature is supported. See below for an example:
process (Request)
begin
case? Request is
when "1---" => Grant <= "1000" ;
when "01--" => Grant <= "0100" ;
when "001-" => Grant <= "0010" ;
when "0001" => Grant <= "0001" ;
when others => Grant <= "0000" ;
end case? ;
end process ;
The one thing to note is that the more decode logic you add to this process, the harder it will be to meet timing.

The concurrent form is:
with Request select?
Grant <= "1000" when "1---",
"0100" when "01--",
"0010" when "001-",
"0001" when "0001",
"0000" when others ;
As noted above, it is unlikely this works in Xilinx tools. Please be sure to submit a bug report against Xilinx tools. Each bug report helps them understand the importance of implementing the new features. Some how they missed the market statistics that clearly show that VHDL is the dominant FPGA design and verification language.
The above code example is borrowed from: http://www.synthworks.com/papers/vhdl_2008_2012_2up.pdf

Related

Is this VHDL code making an assignment conflict?

In VHDL and other hardware languages, it is my understanding that all conditions from true logic in a process happen at the same time. I have a std_logic FLAG variable that appears to me to have a conflict. I saw this code in a publication and I do not understand it. It looks like the FLAG variable can be assigned two values. Is this bad code or am I missing something? (The Process has some input triggers but no CLK.)
The variable names were changed to protect the innocent.
...
process(op_state, ...)
begin
FLAG <= '0';
case op_state is
when STATE_SLEEP =>
FLAG <= '1';
when some other cases not containing FLAG
end case;
end process;
I am going to assume both assignments are in the same process.
That coding style is allowed. If there are multiple assignment in a process the LAST one 'wins' from the previous one. This is even on part of a vector.
I often use this to set a default:
-- Default set all read bits to zero
axil_rdata<= (others => '0');
case (radrs) is
when X"00" => axil_rdata( 7 downto 0) <= control;
when X"04" => axil_rdata(15 downto 0) <= status;
when X"08" => axil_rdata <= counter;
...
Thus all bits of axil_rdata are first set to zero. Then some bits get assigned a new value.

What is the disadvantage of this approach to VHDL state machine design?

A frequently used style for state machines is to change state in a very simple clocked process and either in the same process or another one, a combinatorial section which defines the transition to the next state: (here I use a synchronous reset, because I have a master reset synchronizer)
process( aclk, state, next_state, bob, alice )
begin
if rising_edge( aclk ) then
if resetn = '0' then
state <= IDLE;
else
state <= next_state;
end if;
end if;
next_state <= state;
case state is
when IDLE =>
if bob = alice then
next_state <= ANOTHER_STATE;
...and so on. Some prefer to put the combinatorial section in another process, styles vary. I split the machine and various things such as counters which control state transitions into separate small processes, but I know some dislike this style.
Is there any serious problem with keeping everything in the synchronous block, as in:
process( aclk )
begin
if rising_edge( aclk ) then
if resetn = '0' then
state <= IDLE;
else
case state is
when IDLE =>
if bob = alice then
state <= ANOTHER_STATE;
end if;
when others =>
null;
end case;
end if;
end if;
end process;
I ask because when I started programming (very badly, as a software person!) I used to use the second method, and am wondering if I should rewrite the code.
I have a friend who wrote some of the ARM logic, (not Sophie! I think she used a pencil and paper...) who tells me his rule was never to create processes with anything other than the clock in the sensitivity list.
Best regards
Geoff
I don't think you can prescribe what to do. As with many coding styles some people prefer the one others the other. There is definitely not a good or a bad style.
For small simple state-machines I use the first method.
For big, complex state-machines I prefer the second method.
Tricks I like about the second method:
e.g. in state X you need a register R to have the value A. In the first method you have to track down every state transition which goes to X and add: R <= A;. Also if you make changes your state-machines you should not forget that.
The second method normally has a state and next_state variable. Then you can write:
if (next_state==X) R <= A;. You can now play around with your code and know that when you get to state X, R will be have been assigned the value A.
Break out: Suppose you need to have an 'emergency stop' or the user negates the 'enable' bit and the whole FSM needs to stop. In method 1 you have to start every state condition with: if (stop_everything) state<=IDLE else...
In method two you register part becomes:
if (stop_everything)
state <= IDLE;
else
state <= next_state;
I have worked with IP from a big CPU core vendor (You can guess their name). In their code you see only the second method even for the simplest of code. I assume it is a mandatory coding style if you work for them.

VHDL process does not synthesize as expected

I have a bit of trivial looking VHDL code which is driving me crazy. I have an external logic bit connected to a signal called 'inint'. The signal is then used in a process that looks as follows:
process(inint)
begin
if rising_edge(inint) then
extint <= '1';
end if;
if falling_edge(inint) then
extint <= '0';
end if;
end process;
When I synthesize tis code though, only the lower part of the code is synthesized and not the upper part. What am I missing here?
I am guessing it is something very elementary but cannot put a finger on it. Any help would be greatly appreciated.
Regards,
Shailesh
The correct way to do this is with a double data rate register. Otherwise you can't synthesize logic that toggles at the clock rate. The Xilinx primitive you need is called an ODDR and is documented in the Select IO Resources User guide for your device (here is the one for the Artix-7, see page 127).
It can be instantiated to do what you're trying to do like this:
ODDR_INST1 : ODDR
generic map (
DDR_CLK_EDGE => "SAME_EDGE",
INIT => '0',
SRTYPE => "SYNC"
)
port map (
Q => extint,
C => inint,
CE => '1',
D1 => '1',
D2 => '0',
R => '0',
S => '0'
);
As an added note trying to imply a double data rate output (which is what your code does) is not a good idea. Its probably not supported, but also as a general rule if you need special purpose hardware (which you do), you should instantiate it directly because its hard to guarantee when the tools will infer (though they are much more deterministic than they used to be).

VDHL loop with variable outside of the process (how to be)

How can I avoid variable in this loop (outside the process)?
variable var1 : std_logic_vector (ADRESS_WIDTH-1 downto 0) := (others => '0');
for i in 0 to ADRESS_WIDTH-2 loop
var1 := var1 + '1';
with r_addr select
fifo_data_out <= array_reg(i) when var1,
end loop;
array_reg(ADRESS_WIDTH-1) when others;
This version (in process) isn't correct too - syntax errors
process (r_addr, r_addr1, fifo_data_out, array_reg, r_data1)
variable var1 : std_logic_vector (ADRESS_WIDTH-1 downto 0) := (others => '0');
begin
case r_addr is
when "0000000000" => fifo_data_out <= array_reg(0);
for i in 1 to ADRESS_WIDTH-2 loop
when var1 => fifo_data_out <= array_reg(i);
var1 := var1 + '1';
end loop;
when others => fifo_data_out <= array_reg(ADRESS_WIDTH-1);
end case;
There's a bunch of things that aren't quite right on your implementation. Completely agnostic of what you're trying to accomplish there are some things with VHDL that should be remembered:
Every opening statement must have a closing one.
Every nesting level must have a closing statement to "un-nest" it
You can't put portions of one statement set (the case internals) inside another statement (the for loop), this seems odd, but think about it, what case is it going to attach itself to.
VHDL and hardware programming in general is ridiculously parallel, from one iteration to the next the process is completely independent of all other processes.
Now, looking at your code I see what looks like what you want to accomplish, and this is a perfect example of why you should know a little bit of scripting in another language to help out hardware level programming. You should be as specific as possible when creating a process, know what you want to accomplish and in what bounds, I know this is like every other languages but hardware programming gives you all the tools to hang yourself very very thoroughly. Here's the best that I can make out from your code to clean things up.
async_process : process (r_addr, fifo_data_out, array_reg)
begin
case r_addr is
when "0000000000" => fifo_data_out <= array_reg(0);
when "0000000001" => fifo_data_out <= array_reg(1);
when "0000000002" => fifo_data_out <= array_reg(2);
when others => fifo_data_out <= array_reg(ADRESS_WIDTH-1);
end case;
end process;
r_addr_inc_process : process (clock <or other trigger>, reset)
<This is where you would deal with the bounds of the register address.
If you still want to deal with that variable, do it here.>
end process;
So, as you can see from this, you want to update as few things as possible when you're dealing with a process, this way your sensitivity list is extremely specific, and you can force most updating to occur synchronously instead of asynchronously. The reason your async process can be as such is that it will update every time r_addr is updated, and that happens every clock read, or on some flag, and it gives you a consistent reset state.
With how iterative the process is, you can see how using a scripting language to fill in the 100's of register values would help it from being very time consuming.

Struggling with waiting for transfer completion with VHDL

I'm needing to do continual SPI communication to read values from a dual channel ADC I have, and have written a kinda state-machine to do so. However, it doesn't seem to be getting into the state that reads the second channel and I can't figure out why. here's the VHDL...
SPI_read: process (mclk)
--command bits: Start.Single.Ch.MSBF....
constant query_x: unsigned(ADC_datawidth-1 downto 0) := "11010000000000000"; -- Query ADC Ch0 ( inclinometer x-axis)
constant query_y: unsigned(ADC_datawidth-1 downto 0) := "11110000000000000"; -- Query ADC Ch1 ( inclinometer y-axis)
begin
if rising_edge(mclk) then
-- when SPI is not busy, change state and latch Rx data from last communication
if (SPI_busy = '0') then
case SPI_action is
when SETUP =>
SPI_pol <= '0'; -- Clk low when not active
SPI_pha <= 1; -- First edge is half an SCLK period after CS activated
SPI_action <= READ_X;
when READ_X =>
SPI_Tx_buf <= query_x; -- Load in command
y_data <= "00000" & SPI_Rx_buf(11 downto 1);
SPI_send <= '1';
SPI_action <= READ_Y;
when READ_Y =>
SPI_Tx_buf <= query_y; -- Load in command
x_data <= "00000" & SPI_Rx_buf(11 downto 1);
SPI_send <= '1';
SPI_action <= READ_X;
end case;
else
SPI_send <= '0'; -- Deassert send pin
end if;
end if;
end process SPI_read;
The command is sent to the Tx buffer, and the value from the last received data is written to a signal which is output to some seven segment displays. A pulse from SPI_send is required to start the transfer, and when started, SPI_busy is set high until the transfer is completed.
Right now it'll only send the query_x over SPI, and I can know this since I can see it on the scope. Interestingly, however, It's outputting the same value to both displays which leads me to think that it's still getting into it's READ_Y state, but not changing the Tx Data it's outputting.
I've been staring at this code for hours now, and I can't figure it out. Sometimes a fresh pair of eyes makes life easier, so if you spot anything please let me know.
Also, I'm very open to suggestions of better ways to deal with this, I'm just learning VHDL so I'm not even sure I'm doing things the right way mostly!
Summarizing my comments so far into an answer.
Simulate this process/module with your SPI master component.
Your approach is generally correct but I would suggest you re-architect your state machine slightly to put explicit wait states in between each spi transaction (wait_x, wait_y) and maybe have a more robust handshake between the modules, ie stay in read_x until busy goes high, then stay in wait_x until busy goes low.
It looks like send is getting asserted for two cycles and you are transition through both read_x and read_y each cycle.
Drawn from this program
http://wavedrom.googlecode.com/svn/trunk/editor.html
with this source:
{ "signal" : [
{ "name": "clk", "wave": "P........" },
{ "name": "busy", "wave": "0..1.|0..1"},
{ "name": "SPI_Action", "wave": "====.|.==.", "data": ["SETUP", "READ_X", "READ_Y", "READ_X", "READ_Y", "READ_X", "READ_Y", ] },
{ "name": "SPI_send", "wave": "0.1.0|.1.0", "data": ["0", "1", "Load", "Start","WaitA"] },
{ "name": "SPI_Tx_buf", "wave": "x.===|..==", "data": ["query_x","query_y","query_x","query_y","query_x"],},
]}
You are thinking along the right basic lines, but there are various things not-quite-right with your state machine - as the other answers say - and these are easy to discover in simulation.
For example
when READ_X =>
SPI_Tx_buf <= query_x; -- Load in command
y_data <= "00000" & SPI_Rx_buf(11 downto 1);
SPI_send <= '1';
SPI_action <= READ_Y;
Now if SPI_Busy stays low for a second cycle, this will clearly not stay in state READ_X but transition directly to READ_Y which is probably not what you want.
A more normal state machine would treat the states as outermost, and interpret the input signals differently for each state :
case SPI_Action is
when READ_X =>
if SPI_Busy = '0' then -- Wait here if busy
SPI_Tx_buf <= query_x; -- Load in command
y_data <= "00000" & SPI_Rx_buf(11 downto 1);
SPI_send <= '1';
SPI_action <= READING_X;
end if;
when READING_X =>
if SPI_Busy = '1' then -- command accepted
SPI_action <= READ_Y; -- ready to send next one
end if;
when READ_Y =>
if SPI_Busy = '0' then -- Wait here if busy
You can see that this version treats the Busy signal as a handshake, and only progresses when Busy changes state. I am certain you can make your approach (IF outermost) work if you want, but you will have tofigure out how to apply the handshaking principle yourself.
There is also no "Idle" state where neither X or Y is being read; this SM will read X and Y alternately as fast as it can. Commonly you would read them both, then return to Idle until some other Start signal commanded you to leave Idle and perform a fresh set of reads.
You can possibly also make the state machine more robust with a "when others" clause. It's not a must, if you guarantee to cover all your defined states, but it can make maintenance easier. On the other hand, without such a clause, the compilers will let you know of any uncovered states, guarding against mistakes.
There is a myth that a "when others" clause is essential and synthesis tools generate safer but less optimal state machines from a "when others" clause. However there are synthesis attributes or command line options to control how synth tools generate state machines.
I have to agree with the issues raised by David and add a few notes.
There are a few things that are not very good with your code, first of all, you must have a "when others =>" in the list of your states.
None of your signals seems to have a default value except the SPI_send. It also not a good idea to put the state machine inside the if statement. And if you have to do it, then you must set all the signals in both cases or else you end up with latches instead of flip-flops. One easy way to do this is to set all the signals at the begging of your code to their default value and then change them when needed.
This way the synthesis tool knows how to handle them and you get correct.
Well, this is from a VHDL-for-synthesis document from Siemence:
If a signal or a variable is not assigned a value in all possible
*branches of an if statement, a latch is inferred*. If the intention is
not to infer a latch, then the signal or variable must be assigned a
value explicitly in all branches of the statement.
You can find the guide in PDF format at: http://web.ewu.edu/groups/technology/Claudio/ee360/Lectures/vhdl-for-synthesis.pdf

Resources