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 177

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

Line No. Rev Author Line
1 168 jshamlet
-- VHDL Units :  realtime_clock
2
-- Description:  Provides automatically updated registers that maintain the
3
--            :   time of day. Keeps track of the day of week, hours, minutes
4
--            :   seconds, and tenths of a second. Module is doubled buffered
5
--            :   to ensure time consistency during accesses. Also provides
6
--            :   a programmable periodic interrupt timer, as well as a uSec
7
--            :    tick for external use.
8 172 jshamlet
--
9 168 jshamlet
-- Register Map:
10
-- Offset  Bitfield Description                        Read/Write
11
--   0x0   AAAAAAAA Periodic Interval Timer in uS      (RW)
12 176 jshamlet
--   0x1   -AAAAAAA Tenths  (0x00 - 0x99)              (RW)
13
--   0x2   --AAAAAA Seconds (0x00 - 0x59)              (RW)
14
--   0x3   --AAAAAA Minutes (0x00 - 0x59)              (RW)
15
--   0x4   ---AAAAA Hours   (0x00 - 0x23)              (RW)
16 168 jshamlet
--   0x5   -----AAA Day of Week (0x00 - 0x06)          (RW)
17
--   0x6   -------- Update RTC regs from Shadow Regs   (WO)
18
--   0x7   A------- Update Shadow Regs from RTC regs   (RW)
19
--                  A = Update is Busy
20 176 jshamlet
--
21
-- Note that values are stored in packed BCD, not hex
22 168 jshamlet
 
23 176 jshamlet
 
24 168 jshamlet
library ieee;
25
use ieee.std_logic_1164.all;
26
  use ieee.std_logic_unsigned.all;
27
  use ieee.std_logic_arith.all;
28
  use ieee.std_logic_misc.all;
29
 
30
library work;
31
  use work.open8_pkg.all;
32
 
33
entity o8_rtc is
34
generic(
35 177 jshamlet
  Address               : ADDRESS_TYPE;
36 168 jshamlet
  Reset_Level           : std_logic;
37 177 jshamlet
  Sys_Freq              : real
38 168 jshamlet
);
39
port(
40
  Clock                 : in  std_logic;
41
  Reset                 : in  std_logic;
42
  uSec_Tick             : out std_logic;
43
  --
44
  Bus_Address           : in  ADDRESS_TYPE;
45
  Wr_Enable             : in  std_logic;
46
  Wr_Data               : in  DATA_TYPE;
47
  Rd_Enable             : in  std_logic;
48
  Rd_Data               : out DATA_TYPE;
49
  --
50
  Interrupt_PIT         : out std_logic;
51
  Interrupt_RTC         : out std_logic
52
);
53
end entity;
54
 
55
architecture behave of o8_rtc is
56
 
57
  -- The ceil_log2 function returns the minimum register width required to
58
  --  hold the supplied integer.
59
  function ceil_log2 (x : in natural) return natural is
60
    variable retval          : natural;
61
  begin
62
    retval                   := 1;
63
    while ((2**retval) - 1) < x loop
64
      retval                 := retval + 1;
65
    end loop;
66
    return retval;
67
  end ceil_log2;
68
 
69
  constant User_Addr    : std_logic_vector(15 downto 3)
70
                          := Address(15 downto 3);
71
  alias  Comp_Addr      is Bus_Address(15 downto 3);
72
  signal Addr_Match     : std_logic;
73
 
74
  alias  Reg_Addr       is Bus_Address(2 downto 0);
75
  signal Reg_Addr_q     : std_logic_vector(2 downto 0);
76
 
77
  signal Wr_En          : std_logic;
78
  signal Wr_Data_q      : DATA_TYPE;
79
  signal Rd_En          : std_logic;
80
 
81
  constant DLY_1USEC_VAL: integer := integer(Sys_Freq / 1000000.0);
82
  constant DLY_1USEC_WDT: integer := ceil_log2(DLY_1USEC_VAL - 1);
83
  constant DLY_1USEC    : std_logic_vector :=
84
                       conv_std_logic_vector( DLY_1USEC_VAL - 1, DLY_1USEC_WDT);
85
 
86
  signal uSec_Cntr      : std_logic_vector( DLY_1USEC_WDT - 1 downto 0 )
87
                          := (others => '0');
88
  signal uSec_Tick_i      : std_logic;
89
 
90
  type PIT_TYPE is record
91
    timer_cnt           : DATA_TYPE;
92
    timer_ro            : std_logic;
93
  end record;
94
 
95
  signal pit            : PIT_TYPE;
96
 
97
  type RTC_TYPE is record
98
    frac                : std_logic_vector(15 downto 0);
99
    frac_ro             : std_logic;
100
 
101
    tens_l              : std_logic_vector(3 downto 0);
102
    tens_l_ro           : std_logic;
103
 
104
    tens_u              : std_logic_vector(3 downto 0);
105
    tens_u_ro           : std_logic;
106
 
107
    secs_l              : std_logic_vector(3 downto 0);
108
    secs_l_ro           : std_logic;
109
 
110
    secs_u              : std_logic_vector(3 downto 0);
111
    secs_u_ro           : std_logic;
112
 
113
    mins_l              : std_logic_vector(3 downto 0);
114
    mins_l_ro           : std_logic;
115
 
116
    mins_u              : std_logic_vector(3 downto 0);
117
    mins_u_ro           : std_logic;
118
 
119
    hours_l             : std_logic_vector(3 downto 0);
120
    hours_l_ro          : std_logic;
121
 
122
    hours_u             : std_logic_vector(3 downto 0);
123
    hours_u_ro          : std_logic;
124
 
125
    dow                 : std_logic_vector(2 downto 0);
126
  end record;
127
 
128
  constant DECISEC      : std_logic_vector(15 downto 0) :=
129
                           conv_std_logic_vector(10000,16);
130
 
131
  signal rtc            : RTC_TYPE;
132
 
133
  signal interval       : DATA_TYPE;
134
 
135
  signal shd_tens       : DATA_TYPE;
136
  signal shd_secs       : DATA_TYPE;
137
  signal shd_mins       : DATA_TYPE;
138
  signal shd_hours      : DATA_TYPE;
139
  signal shd_dow        : DATA_TYPE;
140
 
141
  signal update_rtc     : std_logic;
142
  signal update_shd     : std_logic;
143
  signal update_ctmr    : std_logic_vector(3 downto 0);
144
 
145
begin
146
 
147
  uSec_Tick             <= uSec_Tick_i;
148
  Addr_Match            <= '1' when Comp_Addr = User_Addr else '0';
149
 
150
  Interrupt_PIT         <= pit.timer_ro;
151
  Interrupt_RTC         <= rtc.frac_ro;
152
 
153
  io_reg: process( Clock, Reset )
154
  begin
155
    if( Reset = Reset_Level )then
156
      uSec_Cntr         <= (others => '0');
157
      uSec_Tick_i       <= '0';
158
 
159
      pit.timer_cnt     <= x"00";
160
      pit.timer_ro      <= '0';
161
 
162
      rtc.frac          <= DECISEC;
163
      rtc.frac_ro       <= '0';
164
 
165
      rtc.tens_l        <= (others => '0');
166
      rtc.tens_l_ro     <= '0';
167
 
168
      rtc.tens_u        <= (others => '0');
169
      rtc.tens_u_ro     <= '0';
170
 
171
      rtc.secs_l        <= (others => '0');
172
      rtc.secs_l_ro     <= '0';
173
 
174
      rtc.secs_u        <= (others => '0');
175
      rtc.secs_u_ro     <= '0';
176
 
177
      rtc.mins_l        <= (others => '0');
178
      rtc.mins_l_ro     <= '0';
179
 
180
      rtc.mins_u        <= (others => '0');
181
      rtc.mins_u_ro     <= '0';
182
 
183
      rtc.hours_l       <= (others => '0');
184
      rtc.hours_l_ro    <= '0';
185
 
186
      rtc.hours_u       <= (others => '0');
187
      rtc.hours_u_ro    <= '0';
188
 
189
      rtc.dow           <= (others => '0');
190
 
191
      shd_tens          <= (others => '0');
192
      shd_secs          <= (others => '0');
193
      shd_mins          <= (others => '0');
194
      shd_hours         <= (others => '0');
195
      shd_dow           <= (others => '0');
196
 
197
      update_rtc        <= '0';
198
      update_shd        <= '0';
199
      update_ctmr       <= (others => '0');
200
 
201
      interval          <= x"00";
202
 
203
      Wr_Data_q         <= (others => '0');
204
      Reg_Addr_q        <= (others => '0');
205
      Wr_En             <= '0';
206
      Rd_En             <= '0';
207
      Rd_Data           <= x"00";
208
 
209
    elsif( rising_edge( Clock ) )then
210
 
211
      uSec_Cntr         <= uSec_Cntr - 1;
212
      uSec_Tick_i       <= '0';
213
      if( uSec_Cntr = 0 )then
214
        uSec_Cntr       <= DLY_1USEC;
215 176 jshamlet
        uSec_Tick_i     <= '1';
216 168 jshamlet
      end if;
217
 
218
      pit.timer_ro      <= '0';
219
 
220
      rtc.frac_ro       <= '0';
221
      rtc.tens_l_ro     <= '0';
222
      rtc.tens_u_ro     <= '0';
223
      rtc.secs_l_ro     <= '0';
224
      rtc.secs_u_ro     <= '0';
225
      rtc.mins_l_ro     <= '0';
226
      rtc.mins_u_ro     <= '0';
227
      rtc.hours_l_ro    <= '0';
228
      rtc.hours_u_ro    <= '0';
229
 
230
      -- Periodic Interval Timer
231
      pit.timer_cnt     <= pit.timer_cnt - uSec_Tick_i;
232
      if( or_reduce(pit.timer_cnt) = '0' )then
233
        pit.timer_cnt   <= interval;
234
        pit.timer_ro    <= or_reduce(interval); -- Only issue output on Int > 0
235
      end if;
236
 
237
      -- Fractional decisecond counter - cycles every 10k microseconds
238
      rtc.frac          <= rtc.frac - uSec_Tick_i;
239
      if( or_reduce(rtc.frac) = '0' or update_rtc = '1' )then
240
        rtc.frac        <= DECISEC;
241
        rtc.frac_ro     <= not update_rtc;
242
      end if;
243
 
244
      -- Decisecond counter (lower)
245
      rtc.tens_l        <= rtc.tens_l + rtc.frac_ro;
246
      if( update_rtc = '1' )then
247
        rtc.tens_l      <= shd_tens(3 downto 0);
248
      elsif( rtc.tens_l > x"9")then
249
        rtc.tens_l      <= (others => '0');
250
        rtc.tens_l_ro   <= '1';
251
      end if;
252
 
253
      -- Decisecond counter (upper)
254
      rtc.tens_u        <= rtc.tens_u + rtc.tens_l_ro;
255
      if( update_rtc = '1' )then
256
        rtc.tens_u      <= shd_tens(7 downto 4);
257
      elsif( rtc.tens_u > x"9")then
258
        rtc.tens_u      <= (others => '0');
259
        rtc.tens_u_ro   <= '1';
260
      end if;
261
 
262
      -- Second counter (lower)
263
      rtc.secs_l        <= rtc.secs_l + rtc.tens_u_ro;
264
      if( update_rtc = '1' )then
265
        rtc.secs_l      <= shd_secs(3 downto 0);
266
      elsif( rtc.secs_l > x"9")then
267
        rtc.secs_l      <= (others => '0');
268
        rtc.secs_l_ro   <= '1';
269
      end if;
270
 
271
      -- Second counter (upper)
272
      rtc.secs_u        <= rtc.secs_u + rtc.secs_l_ro;
273
      if( update_rtc = '1' )then
274
        rtc.secs_u      <= shd_secs(7 downto 4);
275
      elsif( rtc.secs_u > x"5")then
276
        rtc.secs_u      <= (others => '0');
277
        rtc.secs_u_ro   <= '1';
278
      end if;
279
 
280
      -- Minutes counter (lower)
281
      rtc.mins_l        <= rtc.mins_l + rtc.secs_u_ro;
282
      if( update_rtc = '1' )then
283
        rtc.mins_l      <= shd_mins(3 downto 0);
284
      elsif( rtc.mins_l > x"9")then
285
        rtc.mins_l      <= (others => '0');
286
        rtc.mins_l_ro   <= '1';
287
      end if;
288
 
289
      -- Minutes counter (upper)
290
      rtc.mins_u        <= rtc.mins_u + rtc.mins_l_ro;
291
      if( update_rtc = '1' )then
292
        rtc.mins_u      <= shd_mins(7 downto 4);
293
      elsif( rtc.mins_u > x"5")then
294
        rtc.mins_u      <= (others => '0');
295
        rtc.mins_u_ro   <= '1';
296
      end if;
297
 
298
      -- Hour counter (lower)
299
      rtc.hours_l       <= rtc.hours_l + rtc.mins_u_ro;
300
      if( update_rtc = '1' )then
301
        rtc.hours_l     <= shd_hours(3 downto 0);
302
      elsif( rtc.hours_l > x"9")then
303
        rtc.hours_l     <= (others => '0');
304
        rtc.hours_l_ro  <= '1';
305
      end if;
306
 
307
      -- Hour counter (upper)
308
      rtc.hours_u       <= rtc.hours_u + rtc.hours_l_ro;
309
      if( update_rtc = '1' )then
310
        rtc.hours_u     <= shd_hours(7 downto 4);
311
      end if;
312
 
313
      if( rtc.hours_u >= x"2" and rtc.hours_l > x"3" )then
314
        rtc.hours_l     <= (others => '0');
315
        rtc.hours_u     <= (others => '0');
316
        rtc.hours_u_ro  <= '1';
317
      end if;
318
 
319
      -- Day of Week counter
320
      rtc.dow           <= rtc.dow + rtc.hours_u_ro;
321
      if( update_rtc = '1' )then
322
        rtc.dow        <= shd_dow(2 downto 0);
323
      elsif( rtc.dow = x"07")then
324
        rtc.dow         <= (others => '0');
325
      end if;
326
 
327
      -- Copy the RTC registers to the shadow registers when the coherency
328
      --  timer is zero (RTC registers are static)
329
      if( update_shd = '1' and or_reduce(update_ctmr) = '0' )then
330
        shd_tens        <= rtc.tens_u & rtc.tens_l;
331
        shd_secs        <= rtc.secs_u & rtc.secs_l;
332
        shd_mins        <= rtc.mins_u & rtc.mins_l;
333
        shd_hours       <= rtc.hours_u & rtc.hours_l;
334
        shd_dow         <= "00000" & rtc.dow;
335
        update_shd      <= '0';
336
      end if;
337
 
338
      Reg_Addr_q        <= Reg_Addr;
339
      Wr_Data_q         <= Wr_Data;
340
 
341
      Wr_En             <= Addr_Match and Wr_Enable;
342
      update_rtc        <= '0';
343
      if( Wr_En = '1' )then
344
        case( Reg_Addr_q )is
345
          when "000" =>
346
            interval    <= Wr_Data_q;
347
 
348
          when "001" =>
349
            shd_tens    <= Wr_Data_q;
350
 
351
          when "010" =>
352
            shd_secs    <= Wr_Data_q;
353
 
354
          when "011" =>
355
            shd_mins    <= Wr_Data_q;
356
 
357
          when "100" =>
358
            shd_hours   <= Wr_Data_q;
359
 
360
          when "101" =>
361
            shd_dow     <= Wr_Data_q;
362
 
363
          when "110" =>
364
            update_rtc  <= '1';
365
 
366
          when "111" =>
367
            update_shd  <= '1';
368
 
369
          when others => null;
370
        end case;
371
      end if;
372
 
373
      -- Coherency timer - ensures that the shadow registers are updated with
374
      --  valid time data by delaying updates until the rtc registers have
375
      --  finished cascading.
376
      update_ctmr       <= update_ctmr - or_reduce(update_ctmr);
377
      if( rtc.frac_ro = '1' )then
378
        update_ctmr     <= (others => '1');
379
      end if;
380
 
381
      Rd_Data           <= (others => '0');
382
      Rd_En             <= Addr_Match and Rd_Enable;
383
      if( Rd_En = '1' )then
384
        case( Reg_Addr_q )is
385
          when "000" =>
386
            Rd_Data     <= interval;
387
          when "001" =>
388
            Rd_Data     <= shd_tens;
389
          when "010" =>
390
            Rd_Data     <= shd_secs;
391
          when "011" =>
392
            Rd_Data     <= shd_mins;
393
          when "100" =>
394
            Rd_Data     <= shd_hours;
395
          when "101" =>
396
            Rd_Data     <= shd_dow;
397
          when "110" =>
398
            null;
399
          when "111" =>
400
            Rd_Data     <= update_shd & "0000000";
401
          when others => null;
402
        end case;
403
      end if;
404
 
405
    end if;
406
  end process;
407
 
408
end architecture;

powered by: WebSVN 2.1.0

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