library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity Memory_Two is
port( clk : in std_logic;
data_in : in STD_LOGIC_VECTOR(3 downto 0); -- Data Bus
data_out: out STD_LOGIC_VECTOR(3 downto 0); -- Data Bus
addr : in STD_LOGIC_VECTOR(7 downto 0); -- Address Bus
wr : in STD_LOGIC -- Read/Write
);
end Memory_Two;
architecture table of Memory_Two is
type a_mem is array( 0 to 255) of std_logic_vector(3 downto 0);
signal mem : a_mem;
begin
data_out <= mem(to_integer(unsigned(addr)));
process(clk)
begin
if rising_edge(clk) then
if wr = '1' then
mem(to_integer(unsigned(addr))) <= data_in;
end if;
end if;
end process;
end table;
Learning VHDL has been a challenge (thankfully I'm pretty persistent and like challenges...) mainly because finding material on it is very difficult. I have not even managed to find a proper syntax reference, just bits and pieces here and there.
Sorry for re-using this topic but I have a related question. Can anyone recommend me an example (preferably a big project, not simple stuff) of a _good_ VHDL project? I know there is a bunch of stuff in opencores etc.
I'm learning with @hamster_nz's own tutorial:
http://hamsterworks.co.nz/mediawiki/index.php/FPGA_course
process(clk, reset)
type state is (idle, second, third);
procedure handle_delay( constant delay : in natural;
variable timer : inout natural;
constant next_state : in state;
variable state_var : out state) is
begin
timer := timer + 1;
if timer = delay then
state_var := next_state;
timer := 0;
end if;
end procedure;
variable cur_state : state;
variable timer : natural;
begin
if reset = '1' then
cur_state := idle;
timer := 0;
elsif rising_edge(clk) then
if cur_state = idle then
if input_signal = '0' then
handle_delay(666, timer, second, cur_state);
else
timer := 0;
end if;
elsif cur_state = second then
handle_delay(555, timer, third, cur_state);
report "State: second";
elsif cur_state = third then
handle_delay(444, timer, third, cur_state);
report "State: third";
end if;
end if;
end process;
I'll show an example of the type of crap I've had to deal with recently when learning, this took me and a friend a good couple hours to solve:Code: [Select]process(clk, reset)
type state is (idle, second, third);
procedure handle_delay( constant delay : in natural;
variable timer : inout natural;
constant next_state : in state;
variable state_var : out state) is
begin
timer := timer + 1;
if timer = delay then
state_var := next_state;
timer := 0;
end if;
end procedure;
variable cur_state : state;
variable timer : natural;
begin
if reset = '1' then
cur_state := idle;
timer := 0;
elsif rising_edge(clk) then
if cur_state = idle then
if input_signal = '0' then
handle_delay(666, timer, second, cur_state);
else
timer := 0;
end if;
elsif cur_state = second then
handle_delay(555, timer, third, cur_state);
report "State: second";
elsif cur_state = third then
handle_delay(444, timer, third, cur_state);
report "State: third";
end if;
end if;
end process;
If input_signal = '0' for 666 cycles or more, can anyone explain why it will enter second state exactly once (single "State: second" printout) and no more...
timer <= timer+1;
if timer = 999 then
timer <= (others => '0');
end if;
if timer = 999 then
timer <= (others => '0');
else
timer <= timer+1;
end if;
entity pulse_per_count is
port (
clk : in std_logic;
terminal_count : in std_logic_vector;
pulse : out std_logic;
)
end entity
architecture arch of pulse_per_count is
signal count : unsigned(terminal_count'high downto 0) := (others => '0');
begin
count_proc: process(clk)
begin
if rising_edge(clk) then
if count = unsigned(terminal_count) then
count <= (others => '0');
pulse <= '1';
else
pulse <= '0';
count <= count + 1;
end if;
end if;
end process;
end architecture;
Reliable signalling between clock domains is a major, major part of any non-trivial FPGA design. In a microcontroller it's all done for you by the manufacturer of the device; if a peripheral is slower than the core, or asynchronous to it, the logic is already done for you to cope with the mismatch. In an FPGA you have to do it.
IF clk'event AND clk = '1' THEN
a <= b;
b <= a;
END IF;
IF clk'event AND clk = '1' THEN
data_ready <= '0';
IF (set of very specific conditions) THEN
data_ready <= '1';
END IF;
END IF;
SIGNAL s : INTEGER;
VARIABLE v : INTEGER;
IF clk'event AND clk = '1' THEN
v := 1;
v := v + 2;
s <= v;
END IF;
SIGNAL s : INTEGER;
SIGNAL v : INTEGER;
IF clk'event AND clk = '1' THEN
v <= 1;
v <= v + 2;
s <= v;
END IF;
SIGNAL s : STD_LOGIC_VECTOR (7 DOWNTO 0);
VARIABLE t : STD_LOGIC_VECTOR (7 DOWNTO 0);
IF clk'event AND clk = '1' THEN
t := s;
FOR i IN 1 TO 4 LOOP
t (7 DOWNTO 1) := t (6 DOWNTO 0);
t (0) := '0';
END LOOP;
s <= t;
END IF;
SIGNAL s : STD_LOGIC_VECTOR (7 DOWNTO 0);
IF clk'event AND clk = '1' THEN
s (7 DOWNTO 4) <= s (3 DOWNTO 0);
s (3 DOWNTO 0) <= (OTHERS => '0');
END IF;
Thanks for the comments!
However I cannot think of a single reason to prefer signals to variables. Can you elaborate?
....
-- where addr is a signal of 'integer' type
data_out <= memory(addr);
-- increment the counter
addr_var := addr+1;
-- skip the four we don't want to see
if addr_var = 12 then
addr_var := addr_var + 4
end if;
-- reset the counter to keep it in bounds of the memory array
if addr_var = 256 then
addr_var := 0
end if;
addr <= addr_var;
....
....
-- where addr is a correctly sized unsigned signal
data_out <= memory(to_integer(addr));
-- skip over the 12,13,14 and 15 entries in every block of 16
if addr(3 downto 0) = 11 then
addr(3 downto 0) <= (others => '0');
addr(addr'high downto 4) <= addr(addr'high downto 4)+1;
else
addr(3 downto 0) <= addr(3 downto 0)+1;
end if;
....
Why would the variables not persist or why assume they wouldn't? I haven't checked what the standard says but I'm pretty sure they're guaranteed to retain their value (also they have worked as expected in the simulator and in the hardware)...
Also "invocation of a process" sounds weird to me, as far as I've understood a process just "is" and its state just gets re-evaluated when a signal in the sensitivity list changes state?