FPGA output pins outputting wrong state - output

I am writing a LCD controller for an FPGA and am having a really weird (for me at least) problem. The state machine that's supposed to output the needed bits to the screen misbehaves and gets the output pins "stuck" in an old state, while it clearly has moved on to later states.
Here is the relevant parts of the state machine:
PROCESS (clk)
VARIABLE count: INTEGER RANGE 0 TO clk_divider; -- clk_divider is a generic positive.
BEGIN
IF (clk'EVENT AND clk = '1') THEN
count := count + 1;
IF (count = clk_divider) THEN
EAUX <= NOT EAUX;
count := 0;
END IF;
END IF;
END PROCESS;
....
PROCESS (EAUX)
BEGIN
IF (EAUX'EVENT AND EAUX = '1') THEN
pr_state <= nx_state;
END IF;
END PROCESS;
....
PROCESS (pr_state)
BEGIN
CASE pr_state IS
WHEN EntryMode => --6=1,7=Cursor increment/decrement, 8=Display shift on/off
RSs <='0';
DB(7 DOWNTO 0) := "00000110";
nx_state <= WriteData;
WHEN WriteData => --Write data to LCD:
RSs <='1';
YLED <= '1';
DB(7 DOWNTO 0) := "01011111";
i := i + 1;
IF (i < chars) THEN
nx_state <= WriteData;
ELSE
i := 0;
nx_state <= ReturnHome;
END IF;
WHEN ReturnHome => --Return cursor
RSs <='0';
YLED <= '1';
DB(7 DOWNTO 0) := "01011111";
nx_state <= WriteData;
END CASE;
END PROCESS;
Where the bits in the variable DB is assigned to the signal DBOUT:
DBOUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0) -- In entity
SHARED VARIABLE DB : STD_LOGIC_VECTOR(7 DOWNTO 0) := "00000000"; -- In Architecture
DBOUT <= DB;
DBOUT is outputted (in the .ucf-file) as:
NET "DBOUT(0)" LOC = P10;
NET "DBOUT(1)" LOC = P11;
NET "DBOUT(2)" LOC = P12;
NET "DBOUT(3)" LOC = P13;
NET "DBOUT(4)" LOC = P15;
NET "DBOUT(5)" LOC = P16;
NET "DBOUT(6)" LOC = P18;
NET "DBOUT(7)" LOC = P19;
Using an oscilloscope on the pins I can see that it is clearly stuck outputting the "EntryMode" bits and the "RSs" is set at low, while the YLED (the internal led on the FPGA) is on (it's off at all other states). The really weird thing is (and this took a real long time to find) is that if I change the EntryMode bits from
"00000110"
to
"00000100"
it successfully passes the state and outputs the correct bits. It might be true for other changes as well, but I don't really feel like testing that too much. Any help or tips would be highly appreciated!
UPDATE:
After popular request I explicitly put YLED to low in all the early states and switched (back) DB to be a signal. The result is that I can't reach the later states at all, or at least stay in them (even when fiddling with the magic bits, which I guess is a good thing) as the YLED only stays on for a split second after booting the FPGA.

There is a complete example, including theory, state machine, and VHDL code on pages 279-290 of "Finite State Machines in Hardware: Theory and Design...", by Volnei Pedroni, MIT Press, Dec. 2013.

Related

Xilinx VHDL latch warning troubleshooting

Xilinx is inferring a latch for a VHDL code i've written. I've looked up the possible causes for this and found that it's often due to incomplete if or case statements. I've gone through and made sure to include else and when others statements, but i'm still receiving the warning. I believe this is also affecting another project i'm working on so i'd like to understand why this is the case.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity state_machine is
port(trig, en: in std_logic; cstate,nstate: out std_logic_vector(0 to 2));
end state_machine;
architecture Behavioral of state_machine is
signal cstate_s,nstate_s: std_logic_vector(0 to 2);
begin
cstate <= cstate_s;
nstate <= nstate_s;
process(en, cstate_s)
begin
if en = '1' then
nstate_s <= "111";
if cstate_s = "111" then
nstate_s <= "011";
elsif cstate_s = "011" then
nstate_s <= "100";
elsif cstate_s = "100" then
nstate_s <= "101";
elsif cstate_s = "101" then
nstate_s <= "110";
elsif cstate_s = "110" then
nstate_s <= "111";
else
null;
end if;
else
null;
end if;
end process;
process(trig, nstate_s)
begin
if rising_edge(trig) then
cstate_s <= nstate_s;
else
null;
end if;
end process;
end Behavioral;
WARNING:Xst:737 - Found 3-bit latch for signal . Latches may
be generated from incomplete case or if statements. We do not
recommend the use of latches in FPGA/CPLD designs, as they may lead to
timing problems.
For there to be no latches synthesised when a combinational process is synthesised, there must be no path between begin and end process; where all the outputs of the process are not assigned. This is called complete assignment. An output of the process is any signal assigned anywhere within it.
You have such paths. When any path with your null statements are executed, the output of your first process (nstate_s) is not assigned to. Therefore, you will get latches synthesised. There is no point in just having a null statement. If you genuinely don't care what value is assigned to your outputs in these paths, assign the outputs to '-', which means don't care in VHDL.
By the way (assuming trig is a clock), your second process is not combinational (it is sequential) and so you don't need to obey complete assignment; your else branch is unnecessary.

Mathematical operations within function argument

Is it possible to perform mathematical operations within the argument when calling a function?
For example:
answer = to_integer(dividend/divisor);
While Phillipe exaggerates the efficiency of the average VHDL coder, it's not a difficult thing to try.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity foo is
end entity;
architecture fum of foo is
signal dividend: unsigned (7 downto 0) := ("11111111"); -- 255
signal divisor: unsigned (7 downto 0) := ("00001111"); -- 15
signal answer: integer;
begin
process
begin
answer <= to_integer(dividend/divisor);
wait for 0 ns;
report "answer = " & integer'image(answer);
wait;
end process;
end architecture;
The result:
foo.vhdl:17:9:#0ns:(report note): answer = 17
The wait for 0 ns; allows answer to assume the value of the operation (it's a signal, and assignments don't occur when any process is executing or has not yet suspended). For 0 ns will cause a delta cycle delay.
If answer were a variable declared in the process it's value would be available immediately and the wait wouldn't be necessary.
The last wait statement without a delay prevents the process from executing repeatedly.

VHDL: std logic vector not holding value between process calls

I have the following code snippet:
SIGNAL ALU_hilo : STD_LOGIC_VECTOR(63 downto 0);
PROCESS ( ALU_ctl, Ainput, Binput )
BEGIN
-- Select ALU operation
CASE ALU_ctl IS
-- ALU performs ALUresult = A_input AND B_input
WHEN "0000" => ALU_Internal <= Ainput AND Binput;
-- ALU performs ALUresult = A_input OR B_input
WHEN "0001" => ALU_Internal <= Ainput OR Binput;
-- ALU performs ALUresult = A_input + B_input
WHEN "0010" => ALU_Internal <= Ainput + Binput;
-- ALU performs ?
WHEN "0011" => ALU_Internal <= X"00000000";
-- ALU performs ?
WHEN "0100" => ALU_Internal <= X"00000000";
-- ALU performs ?
WHEN "0101" => ALU_Internal <= X"00000000";
-- ALU performs ALUresult = A_input - B_input
WHEN "0110" => ALU_Internal <= Ainput - Binput;
-- ALU performs SLT
WHEN "0111" => ALU_Internal <= Ainput - Binput ;
-- ALU performs MFHI
WHEN "1101" => ALU_Internal <= ALU_hilo(63 downto 32);
-- ALU performs MFLO
WHEN "1100" => ALU_Internal <= ALU_hilo(31 downto 0);
-- ALU performs MULT
when "1000" => ALU_hilo <= Ainput * Binput;
WHEN "1001" => ALU_Internal <= Binput(15 downto 0) & X"0000";
WHEN OTHERS => ALU_Internal <= X"00000000";
END CASE;
END PROCESS;
All of the other signals here are declared previously and work fine. My problem is that ALU_hilo is being overwritten with 0x0 on subsequent process calls where ALU_ctl is not "1000". How can I fix this so that ALU_hilo holds its value unless ALU_ctl is 1000?
You're creating latches for signals that are only assigned for specific conditions of one of the signals in the sensitivity list.
You're more than likely seeing an event on Ainput or Binput (or both) while ALU_ctl is still "1000".
Without controlling when you enable latches specifically, this process may not synthesize to your intended function. If you intend to create latches here you should use an enable that's only valid when all other signals used in the process are unchanging.
You could similarly us a clock edge and create registers instead of latches where ALU_ctl serves as an address to select which register is updated. It would imply that Ainput and Binput occur on the same clock.
(And processes aren't called, their execution is resumed when one of their sensitivity list elements has an event. There's an implied wait on ALU_ctl, Ainput, Binput; as the last statement of the process. A process is a sequence of statements that will repeat unless stopped.)

Getting warning error in vhdl code

I keep getting a strange error in my code, it compiles fine but I keep getting a warning:
Warning: Unconnected, internal signal \s(0)D\ is promoted to input PIN.
Warning: Unconnected, internal signal \s(1)D\ is promoted to input PIN.
The code is for a basic register which resets, shifts to the left and inserts S_IN, and loads the values set into the register using Pload. Can anyone help me figure out what is wrong with it?
library IEEE;
use ieee.std_logic_1164.all;
entity special_register is
port( DATA: in std_logic_vector(3 downto 0);
Reset: in std_logic;
PLoad: in std_logic;
S_Right: in std_logic;
S_IN: in std_logic;
clock : in std_logic;
S: in std_logic_vector(1 downto 0);
D: out std_logic_vector(3 downto 0);
Q : out std_logic_vector(3 downto 0));
end special_register;
architecture behav of special_register is
begin
process(clock, data, Reset, S_IN, S, S_Right, PLoad)
begin
if rising_edge(clock) then
S(0) <= (S_Right);
S(1) <= (PLoad);
if (S(1) = '1') then
D(3) <= DATA(3);
D(2) <= DATA(2);
D(1) <= DATA(1);
D(0) <= DATA(0);
else if (S(0) = '0') then
D(0) <= Q(1);
D(1) <= Q(2);
D(2) <= Q(3);
D(3) <= S_IN;
end if;
end if;
end if;
end process;
Q(3) <= (NOT Reset) AND D(3);
Q(2) <= (NOT Reset) AND D(2);
Q(1) <= (NOT Reset) AND D(1);
Q(0) <= (NOT Reset) AND D(0);
end behav;
In addition to Brian's answer you could note that this design specification is not VHDL compliant and the presumed synthesis tool isn't either:
ghdl -a special_register.vhdl
special_register.vhdl:21:2: port "s" can't be assigned
special_register.vhdl:22:2: port "s" can't be assigned
special_register.vhdl:29:14: port "q" cannot be read
special_register.vhdl:30:14: port "q" cannot be read
special_register.vhdl:31:14: port "q" cannot be read
special_register.vhdl:37:26: port "d" cannot be read
special_register.vhdl:38:26: port "d" cannot be read
special_register.vhdl:39:26: port "d" cannot be read
special_register.vhdl:40:26: port "d" cannot be read
ghdl: compilation error
(It would seem you are trying to read an output port as well).

Incompatible modes for port vhdl

I am getting the following error with my code: ** Failure: (vsim-3808) Incompatible modes for port "d_out".
I specified a new component, defined its entity, connected its ports, everything seemd ok and even compiled but when I ran a tb it wrote an error that appears in the headline
this is part of the code:
signal jal_nor_out: std_logic;
jal_unit: jal_nor
port map(
data_in(5 downto 0) => instruction(31 downto 26),
d_out => jal_nor_out
);
jal_writedata_mux : Mux_2to1_xN
port map(
sel => jal_nor_out,
d_in1 => WriteData,
d_in2 => pc_inc,
d_out => data_mux_out
);
and on another file I have:
entity jal_nor is
port(
data_in : in std_logic_vector(5 downto 0);
d_out : out std_logic
);
end jal_nor;
architecture bhv of jal_nor is
begin
process (data_in)
begin
if data_in="000011" then
d_out <= '1';
else
d_out <= '0';
end if;
end process;
end bhv;
this is the Mux code
entity Mux_2to1_xN is
generic(
WIDTH : integer := 32);
port(
sel : in std_logic;
d_in1 : in std_logic_vector((WIDTH - 1) downto 0);
d_in2 : in std_logic_vector((WIDTH - 1) downto 0);
d_out : out std_logic_vector((WIDTH - 1) downto 0));
end Mux_2to1_xN;
any help?
Sounds like the compiler thinks you have told it two different things about the ports. Have you used any component declarations?
debugging advice:
Make a smaller testcase - keep chopping code out until you have the tiniest subset of the code which causes the error. Take out ports which don't matter, signals that are unused, everything else. In the process of doing this you'll find a very small code subset is causing the problem, and probably be able to fix it yourself. If not, you have a small self-contained piece of code you can post here for us to look at. Just the tiniest code, not with lots of lines commented out. And make sure what you post compiles to the same error...