VHDL - making the logic synthesizable - vhdl

I'm designing a relatively simple memory arbiter, with two states.
State 1: Port 1 is connected to the memory (default state)
State 2: Port 2 is connected to the memory (only if there are requests)
The simulation in ModelSim works just fine and proves that my arbiter operates as required. However I was told that code I've written is not synthesizable. I've included the relevant process' code below.
The enable signal goes high upon request, and setting the enable signal low acknowledges that port has been served. Requirement is that if there are two simultaneous requests, port 2 should be connected. However if port 1 is already connected due to previous request, the port 2 should wait until port 1 has been served.
My questions are:
What are problems with the code that I've written (and why)?
What would be your approach for making this code synthesizable (not aksing for final solution, but hopefully for useful hints)
Because of the problem with formatting the code part of this post I've included code as image as well.
transition: process (clk)
begin
if rising_edge(clk) then
if reset = '1' then
state <= port1;
else
if (state = port1) and (req_p2.enable='1') and
(req_p1.enable='0' or rising_edge(req_p1.enable)) then
state <= port2;
elsif(state = port2) and (req_p2.enable='0') then
state <= port1;
end if;
end if;
end if;
end process;

This line of your code is not synthesisable:
rising_edge(req_p1.enable)
To make it synthesisable you need to replace the rising_edge function with some actual logic that detects a rising edge - a synchronous rising edge detector. Something along the lines of this should work (I don't know your requirements):
sync_rising_edge: process (clk)
begin
if rising_edge(clk) then
if reset = '1' then
req_p1_enable_d <= '0';
else
req_p1_enable_d <= req_p1.enable;
end if;
end if;
end process;
transition: process (clk)
begin
if rising_edge(clk) then
if reset = '1' then
state <= port1;
else
if (state = port1) and (req_p2.enable='1') and
(req_p1.enable='0' or (req_p1_enable_d = '0' and req_p1.enable = '1')) then
state <= port2;
elsif(state = port2) and (req_p2.enable='0') then
state <= port1;
end if;
end if;
end if;
end process;
The rising_edge function is synthesisable if there it is used in the conventional way inside a clocked process. See my answer here.

Related

Why does this FSM not reach 100% code coverage?

I have the following simple FSM description in VHDL:
library ieee;
use ieee.std_logic_1164.all;
entity coverage1 is
port (
clk : in std_logic;
rst : in std_logic;
req : in std_logic;
ack : out std_logic
);
end entity coverage1;
architecture rtl of coverage1 is
type STATES is (IDLE, RUNNING, FINISH);
signal fsm_cs : STATES := IDLE;
signal fsm_ns : STATES;
begin
process (fsm_cs, req) is
begin
fsm_ns <= fsm_cs;
ack <= '0';
case fsm_cs is
when IDLE =>
if req = '1' then
fsm_ns <= RUNNING;
end if;
when RUNNING =>
fsm_ns <= FINISH;
when FINISH =>
ack <= '1';
fsm_ns <= IDLE;
when others =>
null;
end case;
end process;
process (clk) is
begin
if rising_edge(clk) then
if rst = '1' then
fsm_cs <= IDLE;
else
fsm_cs <= fsm_ns;
end if;
end if;
end process;
end architecture;
And this testbench:
library ieee;
use ieee.std_logic_1164.all;
entity coverage1_tb is
end entity coverage1_tb;
architecture tb of coverage1_tb is
signal clk : std_logic := '1';
signal rst : std_logic;
signal req : std_logic;
signal ack : std_logic;
signal finished : boolean := false;
begin
coverage1_1: entity work.coverage1
port map (
clk => clk,
rst => rst,
req => req,
rdy => rdy,
ack => ack);
clk <= not clk after 5 ns when not finished else unaffected;
process
begin
rst <= '1';
wait until rising_edge(clk);
rst <= '0';
req <= '0';
wait until rising_edge(clk);
req <= '1';
wait until rising_edge(clk);
req <= '0';
wait until rising_edge(clk) and ack = '1';
wait until rising_edge(clk);
finished <= true;
wait;
end process;
end architecture tb;
The FSM does not reach 100% code coverage in ModelSim/QuestaSim. I found two issues:
The others case, which is not required because the enumeration is fully covered by all choices, is requested to be covered. But this branch is not reachable... Why does QuestaSim expect coverage for this branch?
QuestaSim shows a false state diagram for my example FSM. The diagram contains self-edges for the states: RUNNING and FINISH. These edges do not exist nor can they be covered.
If I remove the default assignment fsm_ns <= fsm_cs; and add an else branch in the IDLE state, I'll get full coverage.
if req = '1' then
fsm_ns <= RUNNING;
else
fsm_ns <= IDLE;
end if;
Why does the state diagram show false edges and why can't I use default assignments?
I could live with bullet item 1, but item 2 is a problem. If I write my FSMs in that style, I'm duplicating a lot of unneeded code and most synthesizers won't recognize the FSM pattern! So I'll lose FSM optimizations and checking in synthesis.
Some observations, again using ghdl.
Commenting out the rdy port, ghdl again reports 100% coverage.
Ironically the null in "others" clause gets 20 hits ... which is suspicious. As it's the last active line in the process I believe any events that wake the process but don't do anything are recorded here.
A null; added after end case collects these 20 hits, confirming this - but the others case still isn't recorded as a coverage hole (despite having no hits). My hypothesis is that because null generates no code it isn't being tracked. Adding a harmless but trackable action fsm_ns <= IDLE; to the when others branch now gives a coverage hole (which, annoyingly, receives spurious hits when the null after end case is removed.
Summary :
it's worth testing the effect of an active statement as a hook for tracking coverage in when others, and a null after end case so that "end of process" code isn't incorrectly logged on the last case arm
ghdl needs some tidying up in these two areas, perhaps translating null as a 'nop' to hook the coverage to.
Sorry I can't shed light on Modelsim's behaviour here.
However, code that is present but not reachable - "dead code" - is seen as representing a design error in high integrity practices, so I regard Modelsim as correct to highlight it, and ghdl as incorrect in cases where it does not.
It's somewhat related to the issue of safe state machine design where an SEU (perhaps from a cosmic ray) corrupts the state register. Note that with less than 2**n members of STATES, there WILL be an "other" state, and with a null action, this SM will lock up there if it ever reaches that state. (However, deleting the "others" clause won't correct that, and a synthesis tool may conclude the "others" clause is unreachable and delete it anyway. Safe SM design is another topic)
The when others is shown as not covered, as expected. You can exclude it with:
-- coverage off
when others => null;
-- coverage on
I do this in every case statement where the others case can't be
hit.
I get 100% state coverage, even without the else branch. The if conditional in IDLE state has 100% branch coverage, even without an else branch (Active: 4, True Hits: 1, AllFalse: 3). For 100% FSM coverage you should exclude the implicit changes by the reset signal, or you have to pull the reset in every FSM state. You can exclude the reset state changes with -nofsmresettrans swith when compiling.
I get the same behaviour using Modelsim DE 10.5c and 10.6 and Questa 10.6.
BTW: I can't get FSM coverage if parts of the FSM are inside a generate block which depends on a generic, so I had to outcomment the generate stuff and only leave in one of the reset processes. I think this is an Modelsim/Questa limitation that it don't recognizes FSMs inside of generate blocks, but I'm not. The help also hints that FSMs using generics aren't regognized. Maybe that's the case here.

VHDL: having multiple clock enables in one process

Hello I am new to VHDL and I want to ask if it is ok to have a process like this
where I have multiple clocks in one process
C256Hz and C4Hz are clock enables driven from the 50MHz clock
process (Reset, C50Mhz, Go, start_flag, C256Hz, C4Hz)
begin
if reset = '1' then
start_flag <= '0';
elsif rising_edge (C50Mhz) then
if C4Hz = '1' then
if count4 = "11" and single_run_flag = '0' then
start_flag <= '0';
end if;
end if;
if C256Hz = '1' then
if Go = '1' and start_flag = '0' then
start_flag <= '1';
end if;
end if;
end if;
end process; `
It is okay, but whether synthesis will generate a good result depends on the fabric.
The sensitivity list should have just reset and C50MHz, because these are the only events that actually change signals. When C4Hz toggles, then rising_edge(C50MHz) is false, because these are not synchronized, and nothing would happen if the process were to run then.
The separate enable can be assumed to be available everywhere -- clock fanout is so high that everyone implements separate clock distribution networks, and the enable on the registers is required then. So this is safe to use.
The asynchronous reset might not be available on all fabrics, but usually is. Some devices will support asynchronous load (i.e. you can decide the value to be taken on reset), others only reset (i.e. you can set the register to zero only, and initializing to one would generate an inverted table, a register with reset-to-zero, and an inverter in the next LE.
So in general, this is fairly safe, this can be synthesized as
-- intermediates
do_clear_start_flag := C4Hz = '1' and count4 = "11" and single_run_flag = '0';
do_set_start_flag := C256Hz = '1' and Go = '1' and start_flag = '0';
-- to register
enable_start_flag := do_clear_start_flag or do_set_start_flag;
new_start_flag := do_set_start_flag;
The check for the old value of start_flag in do_set_start_flag cannot be optimized out even if setting start_flag has no effect if it has been set before, because it might just be reset in the current clock cycle.
If the block beginning with if C256Hz = '1' were an elsif instead, the second intermediate would read
do_set_start_flag := C256Hz = '1' and Go = '1' and do_clear_start_flag = '0'

VHDL: button debounce inside a Mealy State Machine

Hi I'm trying to implement a mealy machine using VHDL, but I'll need to debounce the button press. My problem is I'm not sure where should I implement the debouncing. My current work is like this:
process(clk)
begin
if(clk' event and clk = '1') then
if rst = '1' then
curr_state <= state0;
else
curr_state <= next_state;
end if;
end if;
end process;
process(curr_state, op1,op0,rst) --here op1,op0 and rst are all physical buttons and I need to debounce op1 and op0
begin
if rst = '1' then
...some implementation
else
...implement the debounce logic first
...process some input
case curr_state is
when state0=>...implementation
...similar stuff
end case;
end process;
I'm not sure whether I'm doing in the right way or not. In the second process, should I put the rst processing like this, or should I put it inside when state0 block? Also, as the processing of debounce requires counting, do I put it outside the case block like this? Thank you!
I would use a completely separate block of code to debounce any button signals, allowing your state machine process to focus on just the state machine, without having to worry about anything else.
You could use a process like this to debounce the input. You could of course exchange variables for signals in this example (with associated assignment operator replacements).
process (clk)
constant DEBOUNCE_CLK_PERIODS : integer := 256; -- Or whatever provides enough debouncing
variable next_button_state : std_logic := '0'; -- Or whatever your 'unpressed' state is
variable debounce_count : integer range 0 to DEBOUNCE_CLK_PERIODS-1 := 0;
begin
if (rising_edge(clk)) then
if (bouncy_button_in /= next_button_state) then
next_button_state := bouncy_button_in;
debounce_count := 0;
else
if (debounce_count /= DEBOUNCE_CLK_PERIODS-1) then
debounce_count := debounce_count + 1;
else
debounced_button_out <= next_button_state;
end if;
end if;
end if;
end process;
Another option would be to sample the bouncy_button_in at a slow rate:
process (clk)
constant DEBOUNCE_CLK_DIVIDER : integer := 256;
variable debounce_count : integer range 0 to DEBOUNCE_CLK_DIVIDER-1 := 0;
begin
if (rising_edge(clk)) then
if (debounce_count /= DEBOUNCE_CLK_DIVIDER-1) then
debounce_count := debounce_count + 1;
else
debounce_count := 0;
debounced_button_out <= bouncy_button_in;
end if;
end if;
end process;
The advantage of the first method is that it will reject glitches in the input. In either case, you would use the debounced_button_out (or whatever you want to call it, perhaps rst) in your state machine, whose code then contains only the core state machine functionality.
If you wanted even more debouncing, you could use another counter to create an enable signal for the processes above, to effectively divide down the clock rate. This could be better than setting the division constant to a very high number, because you may not be able to meet timing if the counter gets beyond a certain size.
You could even create a debounce entity in a separate file, which could be instantiated for each button. It could have a generic for the constant in the above process.
There's also hardware debouncing, but I suppose that's outside the scope of this question.
In the second process, should I put the rst processing like this, or
should I put it inside when state0 block?
Only put it in the State0 block
Also, as the processing of
debounce requires counting, do I put it outside the case block like
this?
Counting needs to be done in a clocked process. Since you are doing a two process statemachine, you cannot do it in the case block. I typically put these sort of resources in a separate clocked process anyway.
For states, you need: IS_0, TO_1, IS_1, TO_0.
The TO_1 and TO_0 are your transition states. I transition from TO_1 to IS_1 when I see a 1 for 16 ms. I transition from TO_0 to IS_0 when I see a 0 for 16 ms. Run your counter when you are in the TO_1 or TO_0 state. Clear your counter when you are in the IS_1 or IS_0 state.
This should get you stated.

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 Pullup Resisters

I am fairly new to vhdl, I am working to understand if I can use it for a project.
I created a project to see how to implement pullup resisters and see how they work. I must have done something wrong.
My constraints entry for the wire is
net "rx_i" PULLUP;
net "rx_i" loc="p88";
the process for the project is
Process (clk_i)
type state_type is (qInit, qZero, qZero1, qZero2, qZero3, qZero4);
variable state: state_type:= qInit;
Begin
if (rising_edge(clk_i)) then
case state is
when qInit =>
if (rx_i = '0') then
led_o(0) <= '1';
state := qZero;
end if;
when qZero =>
if (rx_i = '0') then
led_o(1) <= '1';
state := qZero1;
end if;
when qZero1 =>
if (rx_i = '0') then
led_o(2) <= '1';
state := qZero2;
end if;
when qZero2 =>
if (rx_i = '0') then
led_o(3) <= '1';
state := qZero3;
end if;
when qZero3 =>
if (rx_i = '0') then
led_o(4) <= '1';
state := qZero4;
end if;
when qZero4 =>
if (rx_i = '0') then
led_o(5) <= '1';
state := qInit;
end if;
end case;
end if;
End Process;
All of the led's 0 thru 5 light up. If the wire is pulled up high I would expect maybe a few spurious 0's but not 6 in a row. Any help would be appreciated.
First: you never set the value of your leds back to '0'. Once you have set all values to '1' in this state machine, you keep driving '1'. You could add a line like led_o <= (others => '0'); before your case statement.
Even then, you will be running through the states at the speed of your clock. Your leds will be blinking so fast that your eyes just sees them as "on", but slightly less bright. perhaps you can add a counter in each state, or check for another condition like a button pushed.
Finally, the code you have posted shows nothing of a pull-up. I'm just assuming you are using that in another part of your code. The problems I can see have nothing to do with pull-ups.
Your constraints file is only used when the code gets synthesized and turned into a bitstream to be loaded onto the FPGA. It has nothing to do with simulation. In simulation you can create a pullup by driving 'H' (high) onto a signal.
If you want led_o to be the signal pulled up you could do:
led_o <= 'H';
led_o <= LED_DRIVE;
So when LED_DRIVE is high impedance (Z) then the pullup will take over and pull the signal high. This is how you would implement a bidirectional interface such as I2C. But I think now that I've gone over your head. The tutorial here shows how you could create a simple LED blinker: http://www.nandland.com/vhdl/tutorials/tutorial-your-first-vhdl-program-part1.html

Resources