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 168

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

powered by: WebSVN 2.1.0

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