Conditional Assignments in a 'With Select' block - vhdl

Is it possible to add conditional asignments to a signal from within a 'with select' block. eg.
with state select
Data <= x"00" when IDLE,
(x"01" when Count = 0 else x"10") when DATA,
x"FF" when others;
This doesn't compile, but is it possible to include a second variable within this block?

Short answer is no.
You could do something like this instead.
process (Count, state)
variable countData : std_logic_vector (7 downto 0);
begin
if Count = 0 then
countData := x"01";
else
countData := x"10";
end if;
case state is
when IDLE => Data <= x"00";
when DATA => Data <= countData;
when others => Data <= x"FF";
end case;
end process;

Related

Error (10327): can't determine definition of operator ""="" -- found 0 possible definitions

In VHDL '93 the compiler told me it found 0 possible definitions for operator "=".
It causes an error with the following error message:
Error (10327): VHDL error at mst_fifo_fsm.vhd(171): can't determine definition of operator ""="" -- found 0 possible definitions
Line 171 is at the first assignment of ifsm_cond(0):
process(clk, rst_n)
begin
if (rst_n = '0') then
ifsm_cond <= "0000";
elsif (rising_edge(clk)) then
if (mltcn = '0') then
ifsm_cond(0) <= (cur_stap1 = IDLE) AND (not imst_rd_n(0)) AND (not rxf_n) AND (not ibuf_ful(0));
ifsm_cond(1) <= (cur_state = MTRD) AND ( imst_rd_n(0) OR (rxf_n AND (not rxf_n_p1)) OR ibuf_ful(0)) ;
ifsm_cond(2) <= (cur_state = MDLE) AND (not imst_wr_n(0)) AND (not txe_n)& (ibuf_nep(0) OR stren OR w_1byte) AND (not w_1flag);
ifsm_cond(3) <= (cur_stap3 = MTWR) AND ( imst_wr_n(0) OR (txe_n AND (not txe_n_p1)) OR r_oobe OR ((not ififonempt(0)) AND (not stren) AND (not prefnempt(0))));
else
ifsm_cond(0) <= (not imst_rd_n(conv_integer(ichannel))) AND (not irxf_n(conv_integer(ichannel))) AND (not ibuf_ful(conv_integer(ichannel))) AND (cur_stap3 = IDLE);
ifsm_cond(1) <= ( imst_rd_n(conv_integer(ichannel)) OR (rxf_n & (not rxf_n_p1)) OR ibuf_ful(conv_integer(ichannel))) AND (cur_state = MTRD);
ifsm_cond(2) <= (not imst_wr_n(conv_integer(ichannel))) AND (not itxe_n(conv_integer(ichannel))) AND (ibuf_nep(conv_integer(ichannel)) OR stren) AND (cur_stap3 = MDLE);
ifsm_cond(2) <= (not imst_wr_n(conv_integer(ichannel))) AND (not itxe_n(conv_integer(ichannel))) AND (ibuf_nep(conv_integer(ichannel)) OR stren) AND (cur_stap3 = MDLE);
ifsm_cond(3) <= ( imst_wr_n(conv_integer(ichannel)) OR (rxf_n AND
(not rxf_n_p1)) OR ((not ififonempt(conv_integer(ichannel)) AND (not stren)
AND (not prefnempt(conv_integer(ichannel)))))) AND (cur_stap3 = MTWR);
end if;
end if;
end process;
I guess it is at the statement (cur_stap1 = IDLE).
cur_stap1 is a user defined signal with the following declaration:
type states is (IDLE, MTRD, MDLE, MTWR);
signal cur_state, next_statem, cur_stap1, cur_stap2, cur_stap3, cur_stap4 :
states;
I thougt of one possible solution to clarify first in a conditional concurrent signal assignment if cur_stap1 is IDLE and assign this to a signal which replaces (cur_stap1 = IDLE). But I have some more lines with other statements like this.
Is there a better solution to solve this issue? This concurrent signal assignment is done in a process. Should I rather try an IF ELSIF END IF statement for the whole line?
Thank you in advance.
The problem is that not imst_rd_n(0) returns a std_logic type, while cur_stap1 = IDLE returns a boolean type. There is no and operator that accepts both types, thus the compiler tries to solve it another way: by looking for an = operator defined for your custom type (state) that returns a std_logic, which there isn't. Hence the error.
Instead of not imst_rd_n(0), you should write imst_rd_n(0)='0' and so on. This returns a boolean and a boolean and operator is defined. Imho it's also better for readability.
You should then write your assignment in an if statement.
If [boolean expression] then
[Signal] <= '1';
Else
[Signal] <= '0';
End if;
Also try to design a state machine with a simple output:
Case [current_state] is
When [state 1] =>
If ....
When ....
End case;
You can work with default assignment.
Example:
if rising_edge(clk) then
ifsm_cond <= (others => '0'); -- default assignment
case cur_state is
when IDLE =>
if imst_rd_n(0)='0' AND rxf_n='0' AND ibuf_ful='0' then
ifsm_cond(0) <= '1';
end if;
when MTRD =>
if imst_rd_n(0)='1' OR (rxf_n='1' AND rxf_n_p1='0') OR ibuf_ful(0)='1' then
ifsm_cond(1) <= '1';
end if;
etc.
I would not write a function for operator = for two input's type states that returns a std_logic, as that could lead to other unwanted conflicts. I would instead propose to make a casting function from boolean to std_logic. E.g.:
function to_std_logic(input : boolean) return std_ulogic is
begin
if input then
return '1';
end if;
return '0';
end function;
Usage example: ifsm_cond(0) <= to_std_logic(cur_stap1 = IDLE) AND (not imst_rd_n(0)) AND (not rxf_n) AND (not ibuf_ful(0));

How to make startup process in VHDL

How to make a process that executes only once on powering up?
It is easy to make a process that executes when reset button is pressed, but how to make it run when you plug in the power supply without touching the reset button?
In my example I want to initialize the LCD on startup and I need to send some commands to it in the beginning, but I don't need it in the process that is dependent on some signal like reset(just let's suppose there is no reset button at all).
The state (first run) is stored in a single FF, which is initialized with '1':
signal IsStartup : STD_LOGIC := '1';
FF process without reset:
process(clk)
begin
if rising_edge(clk) then
IsStartup <= '0';
end if;
end process;
Usage example (FSM):
process(clk)
begin
if rising_edge(clk) then
if (Reset = '1') then
State <= ST_RESET;
else
State <= NextState;
end if;
end if;
end process;
process(State, IsStartup)
begin
NextState <= State;
case State is
when ST_RESET =>
if (IsStartup = '1') then
NextState <= ST_STARTUP;
else
NextState <= ST_IDLE;
end if;
-- ...
end case;
end process;
Just use a wait statement with no sensativity list.
process
begin
assignment <= "101";
wait;
end process;
That being said, I'd recommend that you instead build this as a state machine.

VHDL, if statements, and process names

I've got two processes that handle the inputs and output of a single LVDS receiver on a design for an FPGA. Now I need these same two processes concurrently repeated 8 times (for 8 separate LVDS receivers) with slightly different signal names (i.e. sigout1 vs. sigout0). Is there any way I can accomplish this with a for loop? Here are my two processes:
IBUFDS_inst : IBUFDS
generic map (DIFF_TERM => FALSE,
IBUF_LOW_PWR => FALSE,
IOSTANDARD => "DEFAULT")
port map (O => lvds_internal,
I => sigin0_p,
IB => sigin0_n);
lvdsFlop:PROCESS(clk)
BEGIN
IF (clk = '1' AND clk'EVENT) THEN
IF (reset_l = '0') THEN
sigout0 <= '0';
ELSE
sigout0 <= lvds_internal;
END IF;
END IF;
END PROCESS;
I was hoping to use a for loop in the following way:
FOR i IN 0 TO 7 LOOP
--Do the two processes, with signal names dependent on i:
--sigout0 first iteration, sigout1 next iteration, etc for all
--signals.
END LOOP;
If possible I'd like to have each of the processes name depend on i too (for simulation purposes) So I'd have IBUFDS_inst0, IBUFDS_inst1, etc. However, the above implementation does not pass a syntax check.
Edit: Thanks for the help guys, here is my updated VHDL:
--Instantiate LVDS receivers and LVCMOS output for each channel
GEN_LVDS: FOR i IN sigout'RANGE GENERATE
BEGIN
--Input LVDS buffer
IBUFDS_inst : IBUFDS
generic map (DIFF_TERM => FALSE,
IBUF_LOW_PWR => FALSE,
IOSTANDARD => "DEFAULT")
port map (O => lvds_internal(i),
I => sigin_p(i),
IB => sigin_n(i));
END GENERATE GEN_LVDS;
--LVCMOS output flip-flop
lvds_Flop:PROCESS(clk_fast)
BEGIN
IF (clk_fast = '1' AND clk_fast'EVENT) THEN
IF (reset_l = '0') THEN
sigout <= (others => '0');
ELSE
sigout <= lvds_internal;
END IF;
END IF;
END PROCESS lvds_Flop;
Have not tested in hardware yet but it simulates well.
IBUFDS_inst is a label, not a process name. You can't have it's name depends on i, but you can achieve what you want, and you will be able to distinguish between them.
To do that, sigout, sigin_p, sigin_n and lvds_internal must be std_logic_vector instead of std_logic. Here is a sample code:
entity lvds_test is
port map (
clk : in std_logic;
reset_l : in std_logic;
sigin_p : in std_logic_vector(7 downto 0);
sigin_n : in std_logic_vector(7 downto 0);
sigout : out std_logic_vector(7 downto 0)
);
end entity lvds_test;
architecture rtl of lvds_test is
signal lvds_internal : std_logic_vector(sigin_p'range);
begin
LVDS_GEN: for i in lvds_internal'range generate
IBUFDS_inst: IBUFDS
generic map (
DIFF_TERM => FALSE,
IBUF_LOW_PWR => FALSE,
IOSTANDARD => "DEFAULT"
) port map (
O => lvds_internal(i),
I => sigin_p(i),
IB => sigin_n(i)
);
end generate LVDS_GEN;
lvdsFlop: process(clk)
begin
if rising_edge(clk) then
if reset_l = '0' then
sigout <= (others => '0');
else
sigout <= lvds_internal;
end if;
end if;
end process lvdsFlop;
end architecture rtl;
You need to use a generate statement:
gen : for i in 0 to 7 generate
[Optional: local signals]
begin
[...]
my : process(...)
begin
[...]
end process;
end generate;
The full name of the process is now gen[i].my. Additionally, you should use vectors for your signals, so you can address them by index.

VHDL syntax issue

I'm getting an error during CheckSyntax for the following code I've tried. The error says:
"Line 48. parse error, unexpected VARIABLE Line 53. Undefined symbol 'InOutDetector'.
Line 57. InOutDetector: Undefined symbol (last report in this block)".
Can you let me know how should I fix this?
Here is an image of my code, as I could not paste it.
https://www.dropbox.com/s/ay8pjq4ojoep6ry/RoomLightController.png?dl=0
entity Room_Light_Controller is
port (
clk, sA, sB: IN STD_LOGIC;
sL: OUT STD_LOGIC
);
end Room_Light_Controller;
architecture Behavioral of Room_Light_Controller is
-- assuming sensors are variables sA and sB, and lights switch is sL
SIGNAL People : INTEGER:=0;
SIGNAL AllowNextCount : BIT:='0';
--unsigned int People=0; -- counter for people inside the room
--char AllowNextCount=0; -- boolean indicating if allowing next count or not
--short int InOutDetector; -- 1 = entering; -1 = exiting
begin
variable InOutDetectorDetector: integer;
process (clk)
begin
if ((sA = '0') and (sB = '1')) then
-- entering
InOutDetector := 1;
end if;
if ((sA = '1') and (sb = '0')) then
-- exiting
InOutDetector := -1;
end if;
if ((sA ='1') and (sB = '1') and (AllowNextCount = '1')) then
-- only when both sensors are touched validate the people counter
People := People+InOutDetector;
-- count once then block counting until the same person has finished entering/exiting
AllowNextCount <= '0';
end if;
if ((sA = '0') and (sB = '0')) then
-- it gets 0;0 only when someone has finished entering/exiting
-- pr at turn on; so now allow to counting again
AllowNextCount <= '1';
end if;
if (People > 0) then
sL <= '1'; -- Turn/keep lights on as long as People greater than 0
else
sL <= '0'; -- otherwise, turn them off
end if;
end process;
end Behavioral;
In addition to the error Amir notes that there is a name mismatch and the variable is declared in the wrong place, there is an additional error with the assignment to People:
library ieee;
use ieee.std_logic_1164.all;
entity Room_Light_Controller is
port (
clk, sA, sB: in std_logic;
sL: out std_logic
);
end entity Room_Light_Controller;
architecture Behavioral of Room_Light_Controller is
-- assuming sensors are variables sA and sB, and lights switch is sL
signal people: integer := 0;
signal allownextcount: bit := '0';
--unsigned int People=0; -- counter for people inside the room
--char AllowNextCount=0; -- boolean indicating if allowing next count or not
--short int InOutDetector; -- 1 = entering; -1 = exiting
begin
-- variable InOutDetectorDetector: integer;
process (clk)
variable InOutDetector: integer; -- as per Amir
begin
if sA = '0' and sB = '1' then
-- entering
InOutDetector := 1;
end if;
if sA = '1' and sb = '0' then
-- exiting
InOutDetector := -1;
end if;
if sA ='1' and sB = '1' and AllowNextCount = '1' then
-- only when both sensors are touched validate the people counter
People <= People + InOutDetector; -- was :=, signal assignment
-- count once then block counting until the same person has finished entering/exiting
AllowNextCount <= '0';
end if;
if sA = '0' and sB = '0' then
-- it gets 0;0 only when someone has finished entering/exiting
-- pr at turn on; so now allow to counting again
AllowNextCount <= '1';
end if;
if People > 0 then
sL <= '1'; -- Turn/keep lights on as long as People greater than 0
else
sL <= '0'; -- otherwise, turn them off
end if;
end process;
end architecture Behavioral;
People is a signal and requires the signal assignment symbol (<=) not the variable assignment symbol (:=).
After the two changes the VHDL design specification analyzes and elaborates.
Notice a context clause has been added to make your code a Minimal, Verifiable and Complete example.
Also note in the Help Center web page on Minimal, Complete, and Verifiable example the section Minimal and readable,
..Use consistent naming and indentation, and include comments if needed to explain portions of the code.
If this code were intended to be synthesize you might likely need to constrain the integers.
For execution efficiency all the independent if statements could be consolidated using elsif. That's hardly an issue in a small design, but the binary patterns described for sA and sB are mutually exclusive (while not exhaustive for type std_logic).
You neglected to provide the complete error messages, which appear to be output from XST. Historically the recommended design flow includes simulation, which if for no other purpose provides better syntax error messages from VHDL analysis.
XST historically assumes you are handing it a design description that is syntax error free, and is other wise quite sparse in providing adequate error messages.
The error message prefix (e.g. ERROR:HDLParsers:1209) can tell you how to find the problem via Xilinx's support site and/or documentation.
Declare the variable inside the process and rename it to (InOutDetector). You used (InOutDetector) inside the process.
Then if you want to run the process on clk rising edge, complete your process such as the following code :
process(clk)
variable InOutDetector : integer;
begin
if clk = '1' and clk'event then
-- your code
end if;
end process;
However if you don't want to use the clk rising edge, just complete the sensitivity list with parameters that you read or check it inside the process (sA,sB,AllowNextCount,People) and remove clk from the process sensitivity list.
Also be careful about incomplete if statements. Latches may be generated from incomplete case or if statements.

VHDL 'generate' FSM states

I have a variable number of modules linked to another module via a signal bus : std_logic_vector(NUM-1 downto 0), with each component using 8 bits, so that:
bus(7 downto 0) = first module
bus(15 downto 8) = second module
As for creating the instances and doing the port mapping, that is easily done with a
INST: for i in 0 to NUM-1 generate
Inst_module port map ( bus => bus(i*8+7 downto i*8) );
end generate INST;
My question:
I would like to be able to interface with each module via a FSM (since it needs to do some other things too), so would like to be able to 'generate' the following code, rather than having to write out each state manually (Where signal empty : std_logic_vector(NUM-1 downto 0) is a status flag for each module)
type state_type is (st0_idle, st1_work0, st1_work1 --,etc.)
signal state : state_type;
begin
process(empty)
begin
if RESET = '1' then
--reset FSM
state <= st0_idle;
else
if CLK'event and CLK='1' then
case state is
when st0_idle =>
if empty(0) = '0' then
state <= st1_work0;
elsif empty(1) = '1' then
state <= st1_work1;
--etc.
end if;
when st1_work0 =>
bus(7 downto 0) <= SOMETHING;
state <= st0_idle;
when st1_work1 =>
bus(15 downto 8) <= SOMETHINGELSE;
state <= st0_idle;
--etc..
end if;
end if;
end process;
As you can see, there is a lot of repetition. But I can't simply put a for-generate inside the case, so what should I do?
One good way to make processes with state machines more readable is to merge common code into procedures defined within the process. For example:
process (empty) is
procedure assign_something (
index : natural;
something : std_logic_vector(7 downto 0)
next_state : state_type
) is
begin
bus(index*8+7 downto index*8) <= something;
state <= next_state;
end procedure;
begin
wait until rising_edge(clk);
case state is
when st0_idle => ...
when st1_work0 => assign_something(0, something, st0_idle);
when st1_work1 => assign_something(1, something_else, st0_idle);
-- ... etc ...
end case;
if reset = '1' then
state <= st0_idle;
end if;
end procedure;
Hopefully you get the idea. Depending on how regular the state machine structure is, you may also want to replace the enumerated state variables that correspond to each index with a simple count or index variable that you keep track of along with the named state.
That's all up to you, but however you do it, using procedures to factor out common code whenever you can will probably make your VHDL much easier to work with.
Applying this change would make the code look something like this:
architecture ...
type state_type is (st_idle, st_work);
signal state : state_type;
signal index : integer range 0 to NUM-1;
...
begin
...
process (empty) is
procedure assign_something (
index : natural;
something : std_logic_vector(7 downto 0)
next_state : state_type
) is
begin
bus(index*8+7 downto index*8) <= something;
state <= next_state;
end procedure;
begin
wait until rising_edge(clk);
case state is
when st_idle =>
for i in 0 to NUM-1 loop
if empty(i) = '1' then
index := i;
exit;
end if;
end loop;
when st_work => assign_something(index, something, st_idle);
end case;
if reset = '1' then
state <= st_idle;
end if;
end procedure;
Obviously this has to be changed to match exactly what you want to do ... =)

Resources