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 189

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

powered by: WebSVN 2.1.0

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