OpenCores
URL https://opencores.org/ocsvn/light52/light52/trunk

Subversion Repositories light52

[/] [light52/] [trunk/] [vhdl/] [light52_timer.vhdl] - Blame information for rev 15

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 ja_rd
--------------------------------------------------------------------------------
2
-- light52_timer.vhdl -- 16-bit timer with prescaler.
3
--------------------------------------------------------------------------------
4
--  Basic timer, not directly compatible to any of the original MCS51 timers. 
5
--  This timer is totally independent of the UART.
6
-- 
7
--  This is essentially a reloadable up-counter that optionally triggers an 
8
--  interrupt every time the count reaches a certain value.
9
-- 
10
--------------------------------------------------------------------------------
11
-- REGISTERS
12
-------------
13
--
14
--  The core includes 3 registers:
15
--  - A configurable prescaler register of up to 31 bits.
16
--  - A 16-bit compare register accessible through TCL and TCH.
17
--  - A 16-bit counter register accessible through TL and TH.
18
--  
19
--  Reading TL or TH will give the value of the timer register. If the registers
20
--  are read while the count is enabled, the software has to deal with a 
21
--  possibly inconsistent (TL,TH) pair and should apply the usual tricks.
22
--  
23
--  The prescaler is reset to 0 when TCON.CEN=0. When TCON.CEN=1 it counts up to 
24
--  PRESCALER_VALUE-1, then rolls over to 0 and the timer register is 
25
--  incremented.
26
--
27
--  The compare register is write-only, in order to save logic. Reading TCH or
28
--  TCL will give the value of TCON.
29
--  
30
-- OPERATION
31
-------------
32
--
33
--  The counter register is reset to 0 when TCON.CEN=0. 
34
--  When flag TCON.CEN is set to 1, the counter starts counting up at a rate
35
--  of one count every PRESCALER_VALUE clock cycles. 
36
--  When counter register = reload register, the following will happen:
37
--
38
--    - If flag ARL is 0 the core will clear flag CEN and and raise flag Irq,
39
--      triggering an interrupt. 
40
--      The counter will overflow to 0000h and stop.
41
--
42
--    - If flag ARL is 1 then flag CEN will remain high and flag Irq will be 
43
--      raised, triggering an interrupt.  
44
--      The counter will overflow to 0000h and continue counting.
45
--
46
--------------------------------------------------------------------------------
47
-- CONTROL REGISTERS
48
---------------------
49
--
50
-- The timer has a number of registers addressable with input signal addr_i:
51
--
52
-- [000] => TCON: Status/control register (r/w).
53
-- [100] => TCL: Counter register, low byte.
54
-- [101] => TCH: Counter register, high byte.
55
-- [110] => TRL: Reload register, low byte. Write only, will read TCON.
56
-- [111] => TRL: Reload register, low byte. Write only, will read TCON.
57
--
58
-- All other addresses are unused and will read TCON.
59
--
60
-- Note that the SFR address mapping is determined externally.
61
--
62
-- TCON Control/Status register flags:
63
---------------------------------------
64
--
65
--      7       6       5       4       3       2       1       0
66
--  +-------+-------+-------+-------+-------+-------+-------+-------+
67
--  |   0   |   0   |  CEN  |  ARL  |   0   |   0   |   0   |  Irq  |
68
--  +-------+-------+-------+-------+-------+-------+-------+-------+
69
--      h       h      r/w      r/w      h       h       h      W1C    
70
--
71
--  Bits marked 'h' are hardwired and can't be modified. 
72
--  Bits marked 'r' are read only; they are set and clear by the core.
73
--  Bits marked 'r/w' can be read and written to by the CPU.
74
--  Bits marked W1C ('Write 1 Clear') are set by the core when an interrupt 
75
--  has been triggered and must be cleared by the software by writing a '1'.
76
--
77
-- -# Flag CEN (Count ENable) must be set to 1 by the CPU to start the timer. 
78
--    When CEN is 0, the prescaler is reset and the timer register is stopped.
79
--    Writing a 1 to CEN will start the count up. The counter will count 
80
--    until it matches the compare register value (if ARL=1) or it overflows 
81
--    (if ARL=0). At which moment it will roll back to zero.
82
--
83
-- -# Flag ARL (Auto ReLoad) must be set to 1 for autoreload mode. Its reset 
84
--    value is 0.
85
--
86
-- -# Status bit Irq is raised when the counter reaches zero and an interrupt 
87
--    is triggered, and is cleared when a 1 is written to it.
88
--
89
-- When writing to the status/control registers, only flags TxIrq and RxIrq are
90
-- affected, and only when writing a '1' as explained above. All other flags 
91
-- are read-only.
92
--
93
--------------------------------------------------------------------------------
94
-- Copyright (C) 2012 Jose A. Ruiz
95
--                                                              
96
-- This source file may be used and distributed without         
97
-- restriction provided that this copyright statement is not    
98
-- removed from the file and that any derivative work contains  
99
-- the original copyright notice and the associated disclaimer. 
100
--                                                              
101
-- This source file is free software; you can redistribute it   
102
-- and/or modify it under the terms of the GNU Lesser General   
103
-- Public License as published by the Free Software Foundation; 
104
-- either version 2.1 of the License, or (at your option) any   
105
-- later version.                                               
106
--                                                              
107
-- This source is distributed in the hope that it will be       
108
-- useful, but WITHOUT ANY WARRANTY; without even the implied   
109
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      
110
-- PURPOSE.  See the GNU Lesser General Public License for more 
111
-- details.                                                     
112
--                                                              
113
-- You should have received a copy of the GNU Lesser General    
114
-- Public License along with this source; if not, download it   
115
-- from http://www.opencores.org/lgpl.shtml
116
--------------------------------------------------------------------------------
117
 
118
library ieee;
119
use ieee.std_logic_1164.all;
120
use ieee.numeric_std.all;
121
 
122
use work.light52_pkg.all;
123
 
124
entity light52_timer is
125
    generic (
126
        PRESCALER_VALUE : natural := 1
127
    );
128
    port(
129
        irq_o     : out std_logic;
130
 
131
        data_i    : in std_logic_vector(7 downto 0);
132
        data_o    : out std_logic_vector(7 downto 0);
133
 
134
        addr_i    : in std_logic_vector(2 downto 0);
135
        wr_i      : in std_logic;
136
        ce_i      : in std_logic;
137
 
138
        clk_i     : in std_logic;
139
        reset_i   : in std_logic
140
 
141
    );
142
end entity light52_timer;
143
 
144
 
145
architecture plain of light52_timer is
146
 
147
constant PRESCALER_WIDTH : natural := log2(PRESCALER_VALUE);
148
 
149
signal clk, reset :         std_logic;
150
 
151
signal prescaler_ctr_reg :  unsigned(PRESCALER_WIDTH-1 downto 0);
152
signal prescaler_overflow : std_logic;
153
signal counter_reg :        unsigned(15 downto 0);
154
signal compare_reg :        unsigned(15 downto 0);
155
signal counter_match :      std_logic;
156
signal load_enable :        std_logic;
157
signal load_status_reg :    std_logic;
158
 
159
signal flag_autoreload_reg: std_logic;
160
signal flag_counting_reg :  std_logic;
161
signal flag_irq_reg :       std_logic;
162
signal status_reg :         std_logic_vector(7 downto 0);
163
 
164
 
165
begin
166
 
167
clk <= clk_i;
168
reset <= reset_i;
169
 
170
-- If the prescaler is longer than a reasonable arbitrary value, kill the
171
-- synthesis and let the user deal with this -- possibly modifying this 
172
-- file if a long prescaler is actually necessary.
173
assert PRESCALER_WIDTH <= 31
174
report "Timer prescaler is wider than 31 bits."
175
severity failure;
176
 
177
prescaler_counter:
178
process(clk)
179
begin
180
    if clk'event and clk='1' then
181
        if status_reg(5)='0' or reset='1' then
182
            -- Disabling the count initializes the prescaler too.
183
            prescaler_ctr_reg <= (others => '0');
184
        else
185
            if prescaler_overflow='1' then
186
                prescaler_ctr_reg <= (others => '0');
187
            else
188
                prescaler_ctr_reg <= prescaler_ctr_reg + 1;
189
            end if;
190
        end if;
191
    end if;
192
end process prescaler_counter;
193
 
194
prescaler_overflow <= '1' when to_integer(prescaler_ctr_reg)=PRESCALER_VALUE-1
195
                      else '0';
196
 
197
 
198
timer_counter:
199
process(clk)
200
begin
201
    if clk'event and clk='1' then
202
        if reset='1' then
203
            compare_reg <= (others => '1');
204
            counter_reg <= (others => '0');
205
        else
206
            if load_enable='1' and addr_i(2)='1' then
207
                case addr_i(1 downto 0) is
208
                when "00" =>    counter_reg(7 downto 0) <= unsigned(data_i);
209
                when "01" =>    counter_reg(15 downto 8) <= unsigned(data_i);
210
                when "10" =>    compare_reg(7 downto 0) <= unsigned(data_i);
211
                when others =>  compare_reg(15 downto 8) <= unsigned(data_i);
212
                end case;
213
            else
214
                if flag_counting_reg='0' then
215
                    counter_reg <= (others => '0');
216
                else
217
                    if prescaler_overflow='1' then
218
                        if (counter_match and flag_autoreload_reg)='1' then
219
                            counter_reg <= (others => '0');
220
                        else
221
                            counter_reg <= counter_reg + 1;
222
                        end if;
223
                    end if;
224
                end if;
225
            end if;
226
        end if;
227
    end if;
228
end process timer_counter;
229
 
230
counter_match <= '1' when counter_reg=compare_reg else '0';
231
 
232
 
233
---- Status register -----------------------------------------------------------
234
 
235
status_register:
236
process(clk)
237
begin
238
    if clk'event and clk='1' then
239
        if reset='1' then
240
            flag_irq_reg <= '0';
241
            flag_autoreload_reg <= '0';
242
            flag_counting_reg <= '0';
243
        else
244
            if (counter_match and prescaler_overflow)='1' then
245
                flag_irq_reg <= '1';
246
            elsif load_status_reg='1' then
247
                if data_i(0)='1' then
248
                    flag_irq_reg <= '0';
249
                end if;
250
            end if;
251
            if load_status_reg='1' then
252
                flag_autoreload_reg <= data_i(4);
253
                flag_counting_reg <= data_i(5);
254
            elsif (counter_match and not flag_autoreload_reg)='1' then
255
                flag_counting_reg <= '0';
256
            end if;
257
        end if;
258
    end if;
259
end process status_register;
260
 
261
status_reg <= "00" & flag_counting_reg & flag_autoreload_reg &
262
              "000" & flag_irq_reg;
263
 
264
 
265
---- SFR interface -------------------------------------------------------------
266
 
267
load_enable <= '1' when wr_i='1' and ce_i='1' else '0';
268
load_status_reg   <= '1' when load_enable='1' and addr_i="000" else '0';
269
 
270
with addr_i select data_o <=
271
    std_logic_vector(counter_reg( 7 downto  0))     when "100",
272
    std_logic_vector(counter_reg(15 downto  8))     when "101",
273
    status_reg                                      when others;
274
 
275
irq_o <= flag_irq_reg;
276
 
277
 
278
end architecture plain;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.