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

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [VHDL/] [o8_rtc.vhd] - Blame information for rev 167

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

Line No. Rev Author Line
1 167 jshamlet
-- Copyright (c)2013 Jeremy Seth Henry
2
-- All rights reserved.
3
--
4
-- Redistribution and use in source and binary forms, with or without
5
-- modification, are permitted provided that the following conditions are met:
6
--     * Redistributions of source code must retain the above copyright
7
--       notice, this list of conditions and the following disclaimer.
8
--     * Redistributions in binary form must reproduce the above copyright
9
--       notice, this list of conditions and the following disclaimer in the
10
--       documentation and/or other materials provided with the distribution,
11
--       where applicable (as part of a user interface, debugging port, etc.)
12
--
13
-- THIS SOFTWARE IS PROVIDED BY JEREMY SETH HENRY ``AS IS'' AND ANY
14
-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
-- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
-- DISCLAIMED. IN NO EVENT SHALL JEREMY SETH HENRY BE LIABLE FOR ANY
17
-- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
-- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
-- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22
-- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
--
24
-- VHDL Units :  realtime_clock
25
-- Description:  Provides automatically updated registers that maintain the
26
--            :   time of day. Keeps track of the day of week, hours, minutes
27
--            :   seconds, and tenths of a second. Module is doubled buffered
28
--            :   to ensure time consistency during accesses. Also provides
29
--            :   a programmable periodic interrupt timer, as well as a uSec
30
--            :    tick for external use.
31
-- 
32
-- Register Map:
33
-- Offset  Bitfield Description                        Read/Write
34
--   0x0   AAAAAAAA Periodic Interval Timer in uS      (RW)
35
--   0x1   -AAAAAAA Tenths  (0x00 - 0x63)              (RW)
36
--   0x2   --AAAAAA Seconds (0x00 - 0x3B)              (RW)
37
--   0x3   --AAAAAA Minutes (0x00 - 0x3B)              (RW)
38
--   0x4   ---AAAAA Hours   (0x00 - 0x17)              (RW)
39
--   0x5   -----AAA Day of Week (0x00 - 0x06)          (RW)
40
--   0x6   -------- Update RTC regs from Shadow Regs   (WO)
41
--   0x7   A------- Update Shadow Regs from RTC regs   (RW)
42
--                  A = Update is Busy
43
 
44
library ieee;
45
use ieee.std_logic_1164.all;
46
  use ieee.std_logic_unsigned.all;
47
  use ieee.std_logic_arith.all;
48
  use ieee.std_logic_misc.all;
49
 
50
library work;
51
  use work.open8_pkg.all;
52
 
53
entity o8_rtc is
54
generic(
55
  Sys_Freq              : real;
56
  Reset_Level           : std_logic;
57
  Address               : ADDRESS_TYPE
58
);
59
port(
60
  Clock                 : in  std_logic;
61
  Reset                 : in  std_logic;
62
  uSec_Tick             : out std_logic;
63
  --
64
  Bus_Address           : in  ADDRESS_TYPE;
65
  Wr_Enable             : in  std_logic;
66
  Wr_Data               : in  DATA_TYPE;
67
  Rd_Enable             : in  std_logic;
68
  Rd_Data               : out DATA_TYPE;
69
  --
70
  Interrupt_PIT         : out std_logic;
71
  Interrupt_RTC         : out std_logic
72
);
73
end entity;
74
 
75
architecture behave of o8_rtc is
76
 
77
  -- The ceil_log2 function returns the minimum register width required to
78
  --  hold the supplied integer.
79
  function ceil_log2 (x : in natural) return natural is
80
    variable retval          : natural;
81
  begin
82
    retval                   := 1;
83
    while ((2**retval) - 1) < x loop
84
      retval                 := retval + 1;
85
    end loop;
86
    return retval;
87
  end ceil_log2;
88
 
89
  constant User_Addr    : std_logic_vector(15 downto 3)
90
                          := Address(15 downto 3);
91
  alias  Comp_Addr      is Bus_Address(15 downto 3);
92
  signal Addr_Match     : std_logic;
93
 
94
  alias  Reg_Addr       is Bus_Address(2 downto 0);
95
  signal Reg_Addr_q     : std_logic_vector(2 downto 0);
96
 
97
  signal Wr_En          : std_logic;
98
  signal Wr_Data_q      : DATA_TYPE;
99
  signal Rd_En          : std_logic;
100
 
101
  constant DLY_1USEC_VAL: integer := integer(Sys_Freq / 1000000.0);
102
  constant DLY_1USEC_WDT: integer := ceil_log2(DLY_1USEC_VAL - 1);
103
  constant DLY_1USEC    : std_logic_vector :=
104
                       conv_std_logic_vector( DLY_1USEC_VAL - 1, DLY_1USEC_WDT);
105
 
106
  signal uSec_Cntr      : std_logic_vector( DLY_1USEC_WDT - 1 downto 0 )
107
                          := (others => '0');
108
  signal uSec_Tick_i      : std_logic;
109
 
110
  signal interval       : DATA_TYPE;
111
  signal timer_cnt      : DATA_TYPE;
112
  signal timer_ro       : std_logic;
113
 
114
  signal rtc_frac       : std_logic_vector(15 downto 0);
115
  signal frac_ro        : std_logic;
116
 
117
  signal rtc_tens       : DATA_TYPE;
118
  signal tens_ro        : std_logic;
119
 
120
  signal rtc_secs       : DATA_TYPE;
121
  signal secs_ro        : std_logic;
122
 
123
  signal rtc_mins       : DATA_TYPE;
124
  signal mins_ro        : std_logic;
125
 
126
  signal rtc_hours      : DATA_TYPE;
127
  signal hours_ro       : std_logic;
128
 
129
  signal rtc_dow        : DATA_TYPE;
130
 
131
  signal shd_tens       : DATA_TYPE;
132
  signal shd_secs       : DATA_TYPE;
133
  signal shd_mins       : DATA_TYPE;
134
  signal shd_hours      : DATA_TYPE;
135
  signal shd_dow        : DATA_TYPE;
136
 
137
  signal update_rtc     : std_logic;
138
  signal update_shd     : std_logic;
139
  signal update_ctmr    : std_logic_vector(3 downto 0);
140
 
141
begin
142
 
143
  uSec_Tick             <= uSec_Tick_i;
144
  Addr_Match            <= '1' when Comp_Addr = User_Addr else '0';
145
 
146
  Interrupt_PIT         <= timer_ro;
147
  Interrupt_RTC         <= frac_ro;
148
 
149
  io_reg: process( Clock, Reset )
150
  begin
151
    if( Reset = Reset_Level )then
152
      uSec_Cntr         <= (others => '0');
153
      uSec_Tick_i       <= '0';
154
 
155
      interval          <= x"00";
156
      timer_cnt         <= x"00";
157
      timer_ro          <= '0';
158
 
159
      rtc_frac          <= (others => '0');
160
      frac_ro           <= '0';
161
 
162
      rtc_tens          <= (others => '0');
163
      tens_ro           <= '0';
164
 
165
      rtc_secs          <= (others => '0');
166
      secs_ro           <= '0';
167
 
168
      rtc_mins          <= (others => '0');
169
      mins_ro           <= '0';
170
 
171
      rtc_hours         <= (others => '0');
172
      hours_ro          <= '0';
173
 
174
      rtc_dow           <= (others => '0');
175
 
176
      shd_tens          <= (others => '0');
177
      shd_secs          <= (others => '0');
178
      shd_mins          <= (others => '0');
179
      shd_hours         <= (others => '0');
180
      shd_dow           <= (others => '0');
181
 
182
      update_rtc        <= '0';
183
      update_shd        <= '0';
184
      update_ctmr       <= (others => '0');
185
 
186
      Wr_Data_q         <= (others => '0');
187
      Reg_Addr_q        <= (others => '0');
188
      Wr_En             <= '0';
189
      Rd_En             <= '0';
190
      Rd_Data           <= x"00";
191
 
192
    elsif( rising_edge( Clock ) )then
193
 
194
      uSec_Cntr         <= uSec_Cntr - 1;
195
      uSec_Tick_i       <= '0';
196
      if( uSec_Cntr = 0 )then
197
        uSec_Cntr       <= DLY_1USEC;
198
        uSec_Tick_i     <= or_reduce(Interval);
199
      end if;
200
 
201
      timer_ro          <= '0';
202
      frac_ro           <= '0';
203
      tens_ro           <= '0';
204
      secs_ro           <= '0';
205
      mins_ro           <= '0';
206
      hours_ro          <= '0';
207
 
208
      -- Periodic Interval Timer
209
      timer_cnt         <= timer_cnt - uSec_Tick_i;
210
      if( or_reduce(timer_cnt) = '0' )then
211
        timer_cnt       <= interval;
212
        timer_ro        <= or_reduce(interval); -- Only issue output on Int > 0
213
      end if;
214
 
215
      -- Fractional decisecond counter - cycles every 10k microseconds
216
      rtc_frac          <= rtc_frac - uSec_Tick_i;
217
      if( or_reduce(rtc_frac) = '0' or update_rtc = '1' )then
218
        rtc_frac        <= x"2710";
219
        frac_ro         <= not update_rtc;
220
      end if;
221
 
222
      -- Decisecond counter
223
      rtc_tens          <= rtc_tens + frac_ro;
224
      if( update_rtc = '1' )then
225
        rtc_tens        <= shd_tens;
226
      elsif( rtc_tens = x"64")then
227
        rtc_tens        <= (others => '0');
228
        tens_ro         <= '1';
229
      end if;
230
 
231
      -- Second counter
232
      rtc_secs          <= rtc_secs + tens_ro;
233
      if( update_rtc = '1' )then
234
        rtc_secs        <= shd_secs;
235
      elsif( rtc_secs = x"3C")then
236
        rtc_secs        <= (others => '0');
237
        secs_ro         <= '1';
238
      end if;
239
 
240
      -- Minute counter
241
      rtc_mins          <= rtc_mins + secs_ro;
242
      if( update_rtc = '1' )then
243
        rtc_mins        <= shd_mins;
244
      elsif( rtc_mins = x"3C")then
245
        rtc_mins        <= (others => '0');
246
        mins_ro         <= '1';
247
      end if;
248
 
249
      -- Hour counter
250
      rtc_hours         <= rtc_hours + mins_ro;
251
      if( update_rtc = '1' )then
252
        rtc_hours       <= shd_hours;
253
      elsif( rtc_hours = x"18")then
254
        rtc_hours       <= (others => '0');
255
        hours_ro        <= '1';
256
      end if;
257
 
258
      -- Day of Week counter
259
      rtc_dow           <= rtc_dow + hours_ro;
260
      if( update_rtc = '1' )then
261
        rtc_dow        <= shd_dow;
262
      elsif( rtc_dow = x"07")then
263
        rtc_dow         <= (others => '0');
264
      end if;
265
 
266
      -- Coherency timer - ensures that the shadow registers are updated with
267
      --  valid time data by delaying updates until the rtc registers have
268
      --  finished cascading.
269
      update_rtc        <= '0';
270
      update_ctmr       <= update_ctmr - or_reduce(update_ctmr);
271
      if( frac_ro = '1' )then
272
        update_ctmr     <= x"9";
273
      end if;
274
 
275
      -- Copy the RTC registers to the shadow registers when the coherency
276
      --  timer is zero (RTC registers are static)
277
      if( update_shd = '1' and or_reduce(update_ctmr) = '0' )then
278
        shd_tens        <= rtc_tens;
279
        shd_secs        <= rtc_secs;
280
        shd_mins        <= rtc_mins;
281
        shd_hours       <= rtc_hours;
282
        shd_dow         <= rtc_dow;
283
        update_shd      <= '0';
284
      end if;
285
 
286
      Reg_Addr_q        <= Reg_Addr;
287
      Wr_Data_q         <= Wr_Data;
288
 
289
      Wr_En             <= Addr_Match and Wr_Enable;
290
      if( Wr_En = '1' )then
291
        case( Reg_Addr_q )is
292
          when "000" =>
293
            interval    <= Wr_Data_q;
294
 
295
          when "001" =>
296
            shd_tens    <= '0' & Wr_Data_q(6 downto 0);
297
 
298
          when "010" =>
299
            shd_secs    <= "00" & Wr_Data_q(5 downto 0);
300
 
301
          when "011" =>
302
            shd_mins    <= "00" & Wr_Data_q(5 downto 0);
303
 
304
          when "100" =>
305
            shd_hours   <= "000" & Wr_Data_q(4 downto 0);
306
 
307
          when "101" =>
308
            shd_dow     <= "00000" & Wr_Data_q(2 downto 0);
309
 
310
          when "110" =>
311
            update_rtc  <= '1';
312
 
313
          when "111" =>
314
 
315
            update_shd  <= '1';
316
 
317
          when others => null;
318
        end case;
319
      end if;
320
 
321
      Rd_Data           <= (others => '0');
322
      Rd_En             <= Addr_Match and Rd_Enable;
323
      if( Rd_En = '1' )then
324
        case( Reg_Addr_q )is
325
          when "000" =>
326
            Rd_Data     <= interval;
327
          when "001" =>
328
            Rd_Data     <= shd_tens;
329
          when "010" =>
330
            Rd_Data     <= shd_secs;
331
          when "011" =>
332
            Rd_Data     <= shd_mins;
333
          when "100" =>
334
            Rd_Data     <= shd_hours;
335
          when "101" =>
336
            Rd_Data     <= shd_dow;
337
          when "110" =>
338
            null;
339
          when "111" =>
340
            Rd_Data     <= update_shd & "0000000";
341
          when others => null;
342
        end case;
343
      end if;
344
 
345
    end if;
346
  end process;
347
 
348
end architecture;

powered by: WebSVN 2.1.0

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