-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathtimer_controller.vhd
116 lines (100 loc) · 3.2 KB
/
timer_controller.vhd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
-- Timer Controller
-- Copyright © 2015 by Alastair M. Robinson
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty
-- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use IEEE.numeric_std.ALL;
library work;
-- Timer controller module
entity timer_controller is
generic(
prescale : integer := 1; -- Prescale incoming clock
timers : integer := 0 -- This is a power of 2, so zero means 1 counter, 4 means 16 counters...
);
port (
clk : in std_logic;
reset : in std_logic; -- active low
reg_addr_in : in std_logic_vector(7 downto 0); -- from host CPU
reg_data_in: in std_logic_vector(31 downto 0);
reg_rw : in std_logic;
reg_req : in std_logic;
ticks : out std_logic_vector(2**timers-1 downto 0)
);
end entity;
architecture rtl of timer_controller is
constant prescale_adj : integer := prescale-1;
signal prescale_counter : unsigned(15 downto 0);
signal prescaled_tick : std_logic;
type timer_counters is array (2**timers-1 downto 0) of unsigned(23 downto 0);
signal timer_counter : timer_counters;
signal timer_limit : timer_counters;
signal timer_enabled : std_logic_vector(2**timers-1 downto 0);
signal timer_index : unsigned(7 downto 0);
begin
-- Prescaled tick
process(clk,reset)
begin
if reset='0' then
prescale_counter<=(others=>'0');
elsif rising_edge(clk) then
prescaled_tick<='0';
prescale_counter<=prescale_counter-1;
if prescale_counter=X"0000" then
prescaled_tick<='1';
prescale_counter<=to_unsigned(prescale_adj,16);
end if;
end if;
end process;
-- The timers proper;
process(clk,reset)
begin
if reset='0' then
for I in 0 to (2**timers-1) loop
timer_counter(I)<=(others => '0');
end loop;
elsif rising_edge(clk) then
ticks<=(others => '0');
if prescaled_tick='1' then
for I in 0 to (2**timers-1) loop
if timer_enabled(I)='1' then
timer_counter(I)<=timer_counter(I)-1;
if timer_counter(I)=X"000000" then
timer_counter(I)<=timer_limit(I);
ticks(I)<='1';
end if;
end if;
end loop;
end if;
end if;
end process;
-- Handle CPU access to hardware registers
process(clk,reset)
begin
if reset='0' then
timer_enabled<=(others => '0');
elsif rising_edge(clk) then
if reg_req='1' and reg_rw='0' then -- Write access
case reg_addr_in is
when X"00" =>
timer_enabled<=reg_data_in(2**timers-1 downto 0);
when X"04" =>
timer_index<=unsigned(reg_data_in(7 downto 0));
when X"08" =>
timer_limit(to_integer(timer_index(timers downto 0)))<=
unsigned(reg_data_in(23 downto 0));
when others =>
null;
end case;
end if;
end if;
end process;
end architecture;