--Selector[1:0] | Boundary enable | Output [N: 0]
----------------------------------------------------------------
--00 0 or 1 0
--01 0 Increment count by 7 from Boundary to 255 every half second and stop
--10 0 Decrement count by 9 from 255 to Boundary every half second and stop
--11 0 Increment count by 11 from Boundary to 255 then decrement by 15 to Boundary every half second and stop
--01 1 Increment count by 8 from 1 to Boundary every half second and stop
--10 1 Decrement count by 13 from Boundary to 0 every half second and stop
--11 1 Increment count by 14 from 1 to Boundary then decrement by 6 to 0 every half second and stop
-----------------------------------------------------------------
--clk dividor
-----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity clk_div is
generic (
N: integer := 12499999
);
port (
clk : in std_logic;
rst_n : in std_logic;
clk_out : out std_logic
);
end entity clk_div;
architecture behavioral of clk_div is
signal clk_cnt : integer range 0 to N;
signal clk_out_tmp : std_logic;
begin
--counter for half second
process(clk, rst_n)
begin
if(rst_n = '0')then
clk_cnt <= 0;
clk_out_tmp <= '0';
elsif(clk'event and clk = '1') then
--when counter reaches to half second,
--need to reset the counter to 0
if(clk_cnt = N) then
clk_cnt <= 0;
clk_out_tmp <= not (clk_out_tmp);
else
clk_cnt <= clk_cnt + 1;
clk_out_tmp <= clk_out_tmp;
end if;
end if;
end process;
clk_out <= clk_out_tmp;
end behavioral;
-----------------------------------------------------------------
--counter
-----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity counter is
port (
clk_in : in std_logic;
rst_n : in std_logic;
selector : in std_logic_vector(1 downto 0);
boundary_en : in std_logic;
boundary_data : in std_logic_vector(7 downto 0);
data : out std_logic_vector(7 downto 0)
);
end entity counter;
architecture behavioral of counter is
--signal declaration in architecture
signal cnt : integer range 0 to 255;
signal cnt_nxt : integer range 0 to 255;
signal cnt_end : integer range 0 to 255;
signal cnt_end_data : integer range 0 to 255;
signal cnt_inc_end : integer range 0 to 255;
signal cnt_inc_end_for_rvs : integer range 0 to 255;
signal cnt_inc_end_data : integer range 0 to 255;
signal cnt_st_data : integer range 0 to 255;
signal boundary_data_integer : integer range 0 to 255;
signal selector_ff1 : std_logic_vector(1 downto 0);
signal selector_ff2 : std_logic_vector(1 downto 0);
signal selector_ff3 : std_logic_vector(1 downto 0);
signal selector_trig : std_logic_vector(3 downto 0);
signal selector_trig_for_rvs : std_logic_vector(3 downto 0);
signal selector_trig_ff1 : std_logic_vector(3 downto 0);
signal reverse : std_logic;
signal reverse_ff1 : std_logic;
signal reverse_trig : std_logic ;
signal boundary_en_ff1 : std_logic ;
signal boundary_en_ff2 : std_logic ;
signal boundary_en_ff3 : std_logic ;
signal boundary_en_trig : std_logic ;
signal boundary_data_ff1 : std_logic_vector(7 downto 0) ;
signal boundary_data_ff2 : std_logic_vector(7 downto 0) ;
signal boundary_data_ff3 : std_logic_vector(7 downto 0) ;
signal boundary_data_trig : std_logic ;
constant select01_boundary0_inc : integer range 0 to 255 := 7;
constant select01_boundary1_inc : integer range 0 to 255 := 8;
constant select10_boundary0_dec : integer range 0 to 255 := 9;
constant select10_boundary1_dec : integer range 0 to 255 := 13;
constant select11_boundary0_inc : integer range 0 to 255 := 11;
constant select11_boundary1_inc : integer range 0 to 255 := 14;
constant select11_boundary0_dec : integer range 0 to 255 := 15;
constant select11_boundary1_dec : integer range 0 to 255 := 6;
--function to convert boolean to std_logic
function to_stdulogic(V: Boolean) return std_ulogic is
begin
if V then
return '1';
else
return '0';
end if;
end to_stdulogic;
--begin of architecture
begin
--change boundary data from std_logic to integer
boundary_data_integer <= to_integer(unsigned(boundary_data_ff2));
--solve metastability issue, so 2 flip-flops are needed
--sample the change of selector, so 3 flip-flops are needed
--so add 3 flip-flops
process(clk_in, rst_n)
begin
if(rst_n = '0') then
selector_ff1 <= b"00";
selector_ff2 <= b"00";
selector_ff3 <= b"00";
boundary_en_ff1 <= '0' ;
boundary_en_ff2 <= '0' ;
boundary_en_ff3 <= '0' ;
boundary_data_ff1 <= x"00" ;
boundary_data_ff2 <= x"00" ;
boundary_data_ff3 <= x"00" ;
selector_trig_ff1 <= x"0" ;
elsif(clk_in'event and clk_in = '1') then
selector_ff1 <= selector;
selector_ff2 <= selector_ff1;
selector_ff3 <= selector_ff2;
boundary_en_ff1 <= boundary_en ;
boundary_en_ff2 <= boundary_en_ff1 ;
boundary_en_ff3 <= boundary_en_ff2 ;
boundary_data_ff1 <= boundary_data ;
boundary_data_ff2 <= boundary_data_ff1 ;
boundary_data_ff3 <= boundary_data_ff2 ;
selector_trig_ff1 <= selector_trig ;
end if;
end process;
--sample the change of selector
--use each bit to represent one selector
boundary_data_trig <= to_stdulogic(boundary_data_ff2 /= boundary_data_ff3);
boundary_en_trig <= to_stdulogic(boundary_en_ff2 /= boundary_en_ff3);
--sample the change of selector
--use each bit to represent one selector
selector_trig_for_rvs(0) <= to_stdulogic(
((selector_ff2 = b"00") and (selector_ff3 /= b"00")) or
(((boundary_data_trig = '1') or (boundary_en_trig = '1')) and (selector_ff2 = b"00"))
);
selector_trig_for_rvs(1) <= to_stdulogic(
((selector_ff2 = b"01") and (selector_ff3 /= b"01")) or
(((boundary_data_trig = '1') or (boundary_en_trig = '1')) and (selector_ff2 = b"01"))
);
selector_trig_for_rvs(2) <= to_stdulogic(
((selector_ff2 = b"10") and (selector_ff3 /= b"10")) or
(((boundary_data_trig = '1') or (boundary_en_trig = '1')) and (selector_ff2 = b"10"))
);
selector_trig_for_rvs(3) <= to_stdulogic(
((selector_ff2 = b"11") and (selector_ff3 /= b"11")) or
(((boundary_data_trig = '1') or (boundary_en_trig = '1')) and (selector_ff2 = b"11"))
);
selector_trig <= to_stdulogic(
((selector_ff2 = b"11") and (selector_ff3 /= b"11")) or
(((boundary_data_trig = '1') or (boundary_en_trig = '1') or (reverse_trig = '1')) and (selector_ff2 = b"11"))
) & selector_trig_for_rvs(2) & selector_trig_for_rvs(1) & selector_trig_for_rvs(0);
--when selector is change, calculate the next data displayed on screen
process(clk_in, rst_n)
begin
if(rst_n = '0') then
cnt_st_data <=0;
elsif(rising_edge(clk_in)) then
case selector_trig is
when b"0001" =>
cnt_st_data <= 0;
when b"0010" =>
if(boundary_en_ff2 = '0') then
cnt_st_data <= boundary_data_integer;
else
cnt_st_data <= 1;
end if;
when b"0100" =>
if(boundary_en_ff2 = '0') then
cnt_st_data <= 255;
else
cnt_st_data <= boundary_data_integer;
end if;
when b"1000" =>
if(boundary_en_ff2 = '0') then
if(reverse = '1') then
cnt_st_data <= 255 - select11_boundary0_dec;
else
cnt_st_data <= boundary_data_integer;
end if;
else
if(reverse = '1') then
cnt_st_data <= boundary_data_integer - select11_boundary1_dec;
else
cnt_st_data <= 1;
end if;
end if;
when others =>
cnt_st_data <= cnt_st_data;
end case;
end if;
end process;
--when counter cannot counter but has not reached the last data, calculate the last data to display
process(clk_in, rst_n)
begin
if(rst_n = '0') then
cnt_end_data <= 0;
elsif(rising_edge(clk_in)) then
case selector_trig is
when b"0001" =>
cnt_end_data <= 0;
when b"0010" =>
if(boundary_en_ff2 = '0') then
cnt_end_data <= 255;
else
cnt_end_data <= boundary_data_integer;
end if;
when b"0100" =>
if(boundary_en_ff2 = '0') then
cnt_end_data <= boundary_data_integer;
else
cnt_end_data <= 0;
end if;
when b"1000" =>
if(boundary_en_ff2 = '0') then
if(reverse = '1') then
cnt_end_data <= boundary_data_integer;
else
cnt_end_data <= 255;
end if;
else
if(reverse = '1') then
cnt_end_data <= 0;
else
cnt_end_data <= boundary_data_integer;
end if;
end if;
when others =>
cnt_end_data <= cnt_end_data;
end case;
end if;
end process;
--when counter increase or decrease, get the last data that the counter can reach when counting
process(clk_in, rst_n)
begin
if(rst_n = '0') then
cnt_end <= 0;
elsif(rising_edge(clk_in)) then
case selector_trig is
when b"0010" =>
if(boundary_en_ff2 = '0') then
cnt_end <= 255 - select01_boundary0_inc;
else
cnt_end <= boundary_data_integer - select01_boundary1_inc;
end if;
when b"0100" =>
if(boundary_en_ff2 = '0') then
cnt_end <= boundary_data_integer + select10_boundary0_dec;
else
cnt_end <= 0 + select10_boundary1_dec;
end if;
when b"1000" =>
if(boundary_en_ff2 = '0') then
cnt_end <= boundary_data_integer + select11_boundary0_dec;
else
cnt_end <= 0 + select11_boundary1_dec;
end if;
when others =>
cnt_end <= cnt_end;
end case;
end if;
end process;
--when counter increase in mode 3, get the last data that the counter can reach when counting
process(clk_in, rst_n)
begin
if(rst_n = '0') then
cnt_inc_end <= 0;
elsif(rising_edge(clk_in)) then
case selector_trig is
when b"1000" =>
if(boundary_en_ff2 = '0') then
cnt_inc_end <= 255 - select11_boundary0_inc;
else
cnt_inc_end <= boundary_data_integer - select11_boundary1_inc;
end if;
when others =>
cnt_inc_end <= cnt_inc_end;
end case;
end if;
end process;
--when counter increase in mode 3, get the last data that the counter can reach when counting
process(clk_in, rst_n)
begin
if(rst_n = '0') then
cnt_inc_end_for_rvs <= 0;
elsif(rising_edge(clk_in)) then
case selector_trig is
when b"1000" =>
if(boundary_en_ff2 = '0') then
cnt_inc_end_for_rvs <= 255 - select11_boundary0_inc - select11_boundary0_inc;
else
cnt_inc_end_for_rvs <= boundary_data_integer - select11_boundary1_inc - select11_boundary1_inc;
end if;
when others =>
cnt_inc_end_for_rvs <= cnt_inc_end_for_rvs;
end case;
end if;
end process;
--when counter cannot counter but has not reached the last data in mode 3, calculate the last data to display
process(clk_in, rst_n)
begin
if(rst_n = '0') then
cnt_inc_end_data <= 0;
elsif(rising_edge(clk_in)) then
case selector_trig is
when b"1000" =>
if(boundary_en_ff2 = '0') then
cnt_inc_end_data <= 255;
else
cnt_inc_end_data <= boundary_data_integer;
end if;
when others =>
cnt_inc_end_data <= cnt_inc_end_data;
end case;
end if;
end process;
--counter state machine
--counter to count how many half seconds
process(selector_trig_ff1, selector_ff3, cnt, reverse_ff1, boundary_en_ff3, cnt_st_data, cnt_end, cnt_end_data, cnt_inc_end_data, cnt_inc_end)
begin
--when selector change, this counter need to reset
if(selector_trig_ff1 /= x"0") then
cnt_nxt <= cnt_st_data;
else
case selector_ff3 is
--when in selector 1, counter should increase after each half second
when b"01" =>
if(boundary_en_ff3 = '0') then
if(cnt >= cnt_end) then
cnt_nxt <= 255;
else
cnt_nxt <= cnt + select01_boundary0_inc;
end if;
else
if(cnt >= cnt_end) then
cnt_nxt <= cnt_end_data;
else
cnt_nxt <= cnt + select01_boundary1_inc;
end if;
end if;
--when in selector 2, counter should decrease after each half second
when b"10" =>
if(boundary_en_ff3 = '0') then
if(cnt <= cnt_end) then
cnt_nxt <= cnt_end_data;
else
cnt_nxt <= cnt - select10_boundary0_dec;
end if;
else
if(cnt <= cnt_end) then
cnt_nxt <= 0;
else
cnt_nxt <= cnt - select10_boundary1_dec;
end if;
end if;
--when in selector 3, counter should increase after each half second
--and after reaches the last data, counter will decrease after each half second
when b"11" =>
if(reverse_ff1 = '0') then
if(boundary_en_ff3 = '0') then
if(cnt >= cnt_inc_end) then
cnt_nxt <= 255;
else
cnt_nxt <= cnt + select11_boundary0_inc;
end if;
else
if(cnt >= cnt_inc_end) then
cnt_nxt <= cnt_inc_end_data;
else
cnt_nxt <= cnt + select11_boundary1_inc;
end if;
end if;
else
if(boundary_en_ff3 = '0') then
if(cnt <= cnt_end) then
cnt_nxt <= cnt_end_data;
else
cnt_nxt <= cnt - select11_boundary0_dec;
end if;
else
if(cnt <= cnt_end) then
cnt_nxt <= 0;
else
cnt_nxt <= cnt - select11_boundary1_dec;
end if;
end if;
end if;
--when in selector 0, counter should be 0
--for other unknown selectors, set counter to 0
when others =>
cnt_nxt <= 0;
end case;
end if;
end process;
--when in mode3, reverse will be changed to 1 when counter reach to the last data when increasing
process(clk_in, rst_n)
begin
if(rst_n = '0') then
reverse <= '0';
elsif(clk_in'event and clk_in = '1') then
if(selector_trig_for_rvs /= x"0") then
reverse <= '0';
elsif(selector_ff2 = b"11") then
if(reverse = '0') then
if(cnt >= cnt_inc_end_for_rvs) then
reverse <= '1';
else
reverse <= reverse;
end if;
else
reverse <= reverse;
end if;
else
reverse <= '0';
end if;
end if;
end process;
--delay reverse one cycle
process(clk_in, rst_n)
begin
if(rst_n = '0') then
reverse_ff1 <= '0';
elsif(clk_in'event and clk_in = '1') then
reverse_ff1 <= reverse;
end if;
end process;
reverse_trig <= reverse and (not reverse_ff1);
--flip-flop the counter
process(clk_in, rst_n)
begin
if(rst_n = '0') then
cnt <= 0;
elsif(clk_in'event and clk_in = '1') then
cnt <= cnt_nxt;
end if;
end process;
--send the counter data out
data <= std_logic_vector(to_unsigned(cnt, 8));
end behavioral;
--end of architecture
-----------------------------------------------------------------
--convert to segment
-----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity hex2segment is
port (
hex : in std_logic_vector(3 downto 0);
segment : out std_logic_vector(6 downto 0)
);
end entity hex2segment;
architecture behavioral of hex2segment is
begin
process(hex)
begin
case hex is
--decode from hex to segment
when x"0" => segment <= b"1000000";
when x"1" => segment <= b"1111001";
when x"2" => segment <= b"0100100";
when x"3" => segment <= b"0110000";
when x"4" => segment <= b"0011001";
when x"5" => segment <= b"0010010";
when x"6" => segment <= b"0000010";
when x"7" => segment <= b"1111000";
when x"8" => segment <= b"0000000";
when x"9" => segment <= b"0010000";
when x"a" => segment <= b"0001000";
when x"b" => segment <= b"0000011";
when x"c" => segment <= b"1000110";
when x"d" => segment <= b"0100001";
when x"e" => segment <= b"0000110";
when x"f" => segment <= b"0001110";
--when in selector 1, counter should add 1 after each half second
--for other unknown selectors, set counter to 0
when others => segment <= b"1000000";
end case;
end process;
end behavioral;
-----------------------------------------------------------------
--top
-----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity top is
generic (
M: integer := 7;
N: integer := 12499999
);
port (
clk : in std_logic;
rst_n : in std_logic;
selector : in std_logic_vector(1 downto 0);
boundary_en : in std_logic;
boundary_data : in std_logic_vector(7 downto 0);
data : out std_logic_vector(7 downto 0);
segment0 : out std_logic_vector(M-1 downto 0);
segment1 : out std_logic_vector(M-1 downto 0)
);
end entity top;
architecture behavioral of top is
--signal declaration in architecture
signal clk_out : std_logic;
signal data_tmp : std_logic_vector(7 downto 0);
signal hex : std_logic_vector(11 downto 0);
component clk_div is
generic (
N: integer := 12499999
);
port (
clk : in std_logic;
rst_n : in std_logic;
clk_out : out std_logic
);
end component;
component counter is
port (
clk_in : in std_logic;
rst_n : in std_logic;
selector : in std_logic_vector(1 downto 0);
boundary_en : in std_logic;
boundary_data : in std_logic_vector(7 downto 0);
data : out std_logic_vector(7 downto 0)
);
end component;
component hex2segment is
port (
hex : in std_logic_vector(3 downto 0);
segment : out std_logic_vector(6 downto 0)
);
end component;
--begin of architecture
begin
--instance clock dividor
u_clk_div: clk_div generic map (
N => N
) PORT MAP (
clk => clk ,
rst_n => rst_n ,
clk_out => clk_out
);
--instance counter
u_counter: counter PORT MAP (
clk_in => clk_out ,
rst_n => rst_n ,
selector => selector ,
boundary_en => boundary_en ,
boundary_data => boundary_data ,
data => data_tmp
);
data <= data_tmp;
--instance segment0
u_hex2segment_0: hex2segment PORT MAP (
hex => data_tmp(3 downto 0),
segment => segment0
);
--instance segment1
u_hex2segment_1: hex2segment PORT MAP (
hex => data_tmp(7 downto 4),
segment => segment1
);
end behavioral;
--end of architecture
No comments:
Post a Comment