I am very new to VHDL and trying to write code for a project at school. What I want is to have a one dimensional pong game using the LEDs to act as the ball. Note that I do not have a structured understanding of VHDL, I wrote the following code by looking up state machine designs in VHDL and tried to come up with my own. I have an asynchronous RESET and two asynchronous inputs corresponding to the button presses of each player to return the ball. They are asynchronous because I want the players to be able to return the ball even if the button is pressed for a very short time during a clock cycle.
In Xilinx 10.1, simulation runs just the way I want but when I try to synthesise, this is the error I get for the following code:
ERROR:Xst:827 - "C:/Users/Emre/LED_pong/pong.vhd" line 49: Signal present_state cannot be synthesized, bad synchronous description. The description style you are using to describe a synchronous element (register, memory, etc.) is not supported in the current software release.
When I remove the elsif statements containing PAD1 and PAD2, it synthesizes, but loses its functionality.
entity pong is
Port ( CLK : in STD_LOGIC;
RST : in STD_LOGIC;
PAD1 : in STD_LOGIC;
PAD2 : in STD_LOGIC;
LEDS : out STD_LOGIC_VECTOR (7 downto 0));
end pong;
architecture Behavioral of pong is
type state is ( P1_SERVE, A1, A2, A3, A4, A5, A6, A7,
B0, B1, B2, B3, B4, B5, B6, P2_SERVE,
WAIT_FOR_P1, WAIT_FOR_P2, P1_HIT_EARLY, P2_HIT_EARLY,
P1_SCORED, P2_SCORED );
signal present_state: state;
signal temp : STD_LOGIC_VECTOR (7 downto 0) := "00000000";
begin
process (CLK, RST, PAD1, PAD2) begin
if (RST = '1') then
temp <= "10000000";
present_state <= P1_SERVE;
elsif (rising_edge(CLK)) then
case present_state is
when P1_SERVE =>
temp <= "10000000";
when P2_SERVE =>
temp <= "00000001";
when P1_SCORED =>
temp <= "00000000";
present_state <= P2_SERVE;
when P2_SCORED =>
temp <= "00000000";
present_state <= P1_SERVE;
when A1 =>
temp <= "01000000";
present_state <= A2;
when A2 =>
temp <= "00100000";
present_state <= A3;
when A3 =>
temp <= "00010000";
present_state <= A4;
when A4 =>
temp <= "00001000";
present_state <= A5;
when A5 =>
temp <= "00000100";
present_state <= A6;
when A6 =>
temp <= "00000010";
present_state <= A7;
when A7 =>
temp <= "00000001";
present_state <= WAIT_FOR_P2;
when WAIT_FOR_P2 =>
temp <= "00000000";
present_state <= P2_SERVE;
when B6 =>
temp <= "00000010";
present_state <= B5;
when B5 =>
temp <= "00000100";
present_state <= B4;
when B4 =>
temp <= "00001000";
present_state <= B3;
when B3 =>
temp <= "00010000";
present_state <= B2;
when B2 =>
temp <= "00100000";
present_state <= B1;
when B1 =>
temp <= "01000000";
present_state <= B0;
when B0 =>
temp <= "10000000";
present_state <= WAIT_FOR_P1;
when WAIT_FOR_P1 =>
temp <= "00000000";
present_state <= P1_SERVE;
when P1_HIT_EARLY =>
temp <= "10000000";
present_state <= P2_SCORED;
when P2_HIT_EARLY =>
temp <= "00000001";
present_state <= P1_SCORED;
when others =>
null;
end case;
elsif (PAD1 = '1') then
case present_state is
when P1_SERVE =>
present_state <= A1;
when B0 =>
present_state <= P1_HIT_EARLY;
when WAIT_FOR_P1 =>
present_state <= A1;
when others =>
null;
end case;
elsif (PAD2 = '1') then
case present_state is
when P2_SERVE =>
present_state <= B6;
when A7 =>
present_state <= P2_HIT_EARLY;
when WAIT_FOR_P2 =>
present_state <= B6;
when others =>
null;
end case;
end if;
end process;
LEDS <= temp;
end Behavioral;
You're trying to use PAD1 and PAD2 as latch enables for present_state in addition to an asynchronous reset and clocked loads in the case statement.
Your preferred implementation of the behavior you desire doesn't reflect hardware. For instance you are peering at present_state in the later two case statements while you are using PAD1 and PAD2 as latch enables, effectively combinatorial clocks.
You may want to capture PAD1 and PAD2 as events that are cleared every clock sort of like catching edges for interrupts. Depending on your clock rate you may need to impulse filter them, the question being whether or not you can get both make and break bounce from the buttons. There's also the case of setup time to the clock edge to consider, meaning you might want to sample during a particular window insuring setup time. The model is a flip flop using either PAD1 and PAD2 as clocks followed by a latch.
With event capture you'd merge all the case statements into one under the rising_edge(CLK) evaluation. The effect is to give two possible output states in some state cases, based on either PAD1 or PAD2 (stored) events.
There is a conceptual problem in your code (it is not VHDL’s fault).
You are trying to implement a finite state machine, and, as in any FSM, the present state must be registered (i.e., stored into a flip-flop bank). This you are doing in the first case statement because the assignments to present_state are governed by clock transitions (i.e., they are under the if rising_edge(clk) statement).
The problem is that in the next two case statements (asserted by PAD1 and PAD2) you are trying to modify the value of present_state asynchronously. Recall that the value of present_state is registered, so it is produced by a flip-flop bank. Since the output value of a flip-flop can only be modified by acting on its reset input or by modifying its data input, and none of these cases corresponds to the situations in the last two case statements, your code can simply not be translated into hardware (as David properly pointed out already).
My suggestion: Draw a detailed state transition diagram for your FSM (never skip this phase in any FSM design), which will then make clear the roles of all signals involved (including PAD1 and PAD2). Re-writing the code should then be straightforward.
Related
I have a function that should return the count of Islands found.
I name this function Count_Islands that takes in a parameter of
Map_Array of type Map, of which Map is an array of Islands.
Islands is an enumerator type with set of Land, Water.
I have the function specification in the .ads and the body in the
.adb
The problem I face now is how to proof that my function
Count_Islands'Result will be less than (X * Y)
I have tried: with post => Count_Islands'Result < X * Y
-- Whenever I ran prove all I got: medium: postcondition might
fail cannot prove Count_Islands'Result < X * Y
Function in .ads:
function Count_Islands(Map_Array : Map)
return Integer with Pre => Map_Array'Length /= 0,
Post => Count_Islands'Result < X * Y;
Function in .adb:
function Count_Islands(Map_Array : Map) return Integer
is
Visited_Array : Visited := (others => (others=> False));
Count : Integer := 0;
begin
if (Map_Array'Length = 0)then
return 0;
end if;
for i in X_Range loop
for j in Y_Range loop
if (Map_Array(i, j) = Land and then not Visited_Array(i,j)) then
Visited_Array := Visit_Islands(Map_Array, i, j,Visited_Array);
Count := Count + 1;
end if;
end loop;
end loop;
return Count;
end Count_Islands;
In a matrix of 4 * 5 for instance,i.e my X = 4 And Y = 5:
I expect the output result of an Islands(Lands) found to be 1 which is less than 4 * 5. But GNATprove cannot prove my initial code to analyze that,using Post => Count_Islands'Result < X * Y;
Is there any better way to prove this arithmetic? Thanks for your help.
As the example is not complete, I took the liberty to change it a little bit. You can prove the post condition by adding loop invariants. The program below proves in GNAT CE 2019:
main.adb
procedure Main with SPARK_Mode is
-- Limit the range of the array indices in order to prevent
-- problems with overflow, i.e.:
--
-- Pos'Last * Pos'Last <= Natural'Last
--
-- Hence, as Natural'Last = 2**31 - 1,
--
-- Pos'Last <= Sqrt (2**31 - 1) =approx. 46340
--
-- If Pos'Last >= 46341, then overflow problems might occur.
subtype Pos is Positive range 1 .. 46340;
type Map_Item is (Water, Land);
type Map is
array (Pos range <>, Pos range <>) of Map_Item;
type Visited is
array (Pos range <>, Pos range <>) of Boolean;
function Count_Islands (Map_Array : Map) return Natural with
Post => Count_Islands'Result <= Map_Array'Length (1) * Map_Array'Length (2);
-------------------
-- Count_Islands --
-------------------
function Count_Islands (Map_Array : Map) return Natural is
Visited_Array : Visited (Map_Array'Range (1), Map_Array'Range (2)) :=
(others => (others => False));
Count : Natural := 0;
begin
for I in Map_Array'Range (1) loop
pragma Loop_Invariant
(Count <= (I - Map_Array'First (1)) * Map_Array'Length (2));
for J in Map_Array'Range (2) loop
pragma Loop_Invariant
(Count - Count'Loop_Entry <= J - Map_Array'First (2));
if Map_Array(I, J) = Land and then not Visited_Array(I, J) then
Visited_Array (I, J) := True; -- Simplified
Count := Count + 1;
end if;
end loop;
end loop;
return Count;
end Count_Islands;
begin
null;
end Main;
I have been trying to implement a method by which i can concatenate an array of vectors to a vector. Essentially i need something like:
data_received((rx_length_int + 5) * 8)downto 0) <= rx_ident & rx_length & rx_data & rx_checksum;
data_received(BUILD2_RX_PKT_LEN downto ((rx_length_int + 5) * 8)) <= (others => '0');
where BUILD2_RX_PKT_LEN is a constant size, rx_data has a variable number of bytes, but is defined as:
type t_rx_data is array (0 to MAX_PLD) of STD_LOGIC_VECTOR((ADDRESS_WIDTH - 1) downto 0)
I have implemented a few methods, such as a for loop to iterate through rx_data up to rx_length_int, but this has issues with concatenation to data_received as it grows in size... I'm sure there is a very simple solution to this, but I have been unable to come up with one. Any help would be appreciated.
Instead of an unconstrained aggregate, (others => 0), which relies on the result type to constrain the range, you can build an aggregate with a specified range, such as (7 downto 2 => '0').
So why not
data_received <= (BUILD2_RX_PKT_LEN downto ((rx_length_int + 5) * 8) => '0')
& rx_ident & rx_length & rx_data & rx_checksum;
However it's unreadably clumsy. A better approach would be a padding function:
function pad_packet (data : std_logic_vector) return std_logic_vector is
variable temp : std_logic_vector (BUILD2_RX_PKT_LEN downto 1) := (others => '0');
-- NB "downto 0" would be an off-by-1 error if LEN is actual length
-- Initialised vhole vector to zero
begin
temp (data'length downto 1) := data;
return temp;
end pad_packet;
...
data_received <= pad_packet ( rx_ident & rx_length & rx_data & rx_checksum );
Much clearer...
I am new to vhdl and am attempting to write vhdl odd parity checker using Case within a process. When I compile there are no errors, but the output vector waveform for the output is flat for some reason. What am I doing wrong? Can someone assist me with this or point me in the right direction? Is there another way of doing this?
Here is my code:
library ieee;
use ieee.std_logic_1164.all;
entity test3 is
port (
w, x, y, z : in std_logic;
g1_562 : out std_logic);
end entity test3;
architecture sig of test3 is
signal inputs : std_logic_vector(3 downto 0);
signal outputs: std_logic;
begin
process(inputs) is
begin
case inputs is
when "0000" => outputs <= '1';
when "0011" => outputs <= '1';
when "0101" => outputs <= '1';
when "0110" => outputs <= '1';
when "1001" => outputs <= '1';
when "1010" => outputs <= '1';
when "1100" => outputs <= '1';
when "1111" => outputs <= '1';
when others => outputs <= '0';
g1_562 <= outputs;
end case;
end process;
end architecture sig;
The output is: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
but should be: 1 0 0 1 0 1 1 0 0 1 1 0 1 0 0 1
Thank you
Your signal inputs are never assigned to anything. You need a line outside the process where you concatenate the inputs w, x, y and z. Such as:
inputs <= w & x & y & z;
You should also move g1_562 <= outputs; outside the process.
I am trying to start a counter (0 to 9) with a condition, such as when the condition occurs the counter resets itself and starts counting till 10 and then starts from 0. But it doesn't work.
What I already have is:
always #(posedge clk ) begin
if (enable & sample)
counter <= 4'b0;
else
counter <= counter + 4'b1;
if ( counter == 4'd9 )
counter <= 4'b0;
else
counter <= counter + 4'b1;
end
Any help?
It looks like 'enable and sample' clear, other wise it increments. Also in your example the comparison to 9 overrides the previous value, this check will reset to 0 or increment. You need to put this condition inside the else.
always #(posedge clk ) begin
if (enable & sample) begin
counter <= 4'b0;
end
else begin
if ( counter == 4'd9 ) begin
counter <= 4'b0;
end
else begin
counter <= counter + 4'b1;
end
end
end
I suspect that you actually do not want it to increment when enable is low? which means the initial synch reset logic needs to be updated.
I want to create one 16-bit-vector from two 8-bit-vectors but have errors like below. How to solve it?
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
ENTITY Binary2Gray IS
-- Declarations
port(data : in STD_LOGIC_VECTOR (3 downto 0);
data_out : inout STD_LOGIC_VECTOR (3 downto 0);
data1 : inout std_logic_vector (1 downto 0);
data2 : inout std_logic_vector (1 downto 0);
CLK_I : in std_logic;
y1 : out std_logic_vector (7 downto 0);
y2 : out std_logic_vector (7 downto 0);
op : out std_logic_vector (15 downto 0)
);
END Binary2Gray ;
-----------------------------
ARCHITECTURE rtl OF Binary2Gray IS
signal op : std_logic_vector (15 downto 0);
begin
process(CLK_I)
BEGIN
data_out(3) <=data(3);
data_out(2) <=data(3) xor data (2);
data_out(1) <=data(2) xor data (1);
data_out(0) <=data(1) xor data (0);
label_1: for data_out in 0 to 3 loop
if(data_out = 0 ) then
data1(0) <=data(1) xor data (0);
elsif (data_out = 1 ) then
data1(1) <=data(2) xor data (1);
elsif (data_out = 2 ) then
data2(0) <=data(3) xor data (2);
else
data2(1) <=data(3);
end if;
end loop label_1;
end process;
with data1 select y1 <=
"00110011" when "00",
"00111101" when "01",
"11010011" when "10",
"11011101" when others;
with data2 select y2 <=
"00110011" when "00",
"00111101" when "01",
"11010011" when "10",
"11011101" when others;
op <= y1 & y2 ;
END rtl;
Errors:
# Error: ELAB1_0008: QAM.vhd : (56, 8): Cannot read output : "y1".
# Error: ELAB1_0008: QAM.vhd : (56, 8): Cannot read output : "y2".
In VHDL-2002 (and earlier) it is not allowed to read an output port like y1
and y2, hence the error.
Possible fixes are any of:
declared y1 and y2 as buffer ports
create intermediate signals y1_sig and y2_sig with the values and
assign these to y1, y2, and op
use VHDL-2008 if possible in the tool chain.
Note that op should not be declared as signal when an output port. Note
also that the process does probably not work as expected, since it is not a
clocked process due to missing if rising_edge(CLK_I) then statement, nor a combinatorial
process due to missing data in sensitivity list.