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 190

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 190 jshamlet
        uSec_Tick_i     <= '1';
201 168 jshamlet
      end if;
202
 
203
      -- Periodic Interval Timer
204
      pit.timer_cnt     <= pit.timer_cnt - uSec_Tick_i;
205 190 jshamlet
      pit.timer_ro      <= '0';
206 168 jshamlet
      if( or_reduce(pit.timer_cnt) = '0' )then
207
        pit.timer_cnt   <= interval;
208
        pit.timer_ro    <= or_reduce(interval); -- Only issue output on Int > 0
209
      end if;
210
 
211
      -- Fractional decisecond counter - cycles every 10k microseconds
212
      rtc.frac          <= rtc.frac - uSec_Tick_i;
213 190 jshamlet
      rtc.frac_ro       <= '0';
214 168 jshamlet
      if( or_reduce(rtc.frac) = '0' or update_rtc = '1' )then
215
        rtc.frac        <= DECISEC;
216
        rtc.frac_ro     <= not update_rtc;
217
      end if;
218
 
219
      -- Decisecond counter (lower)
220
      rtc.tens_l        <= rtc.tens_l + rtc.frac_ro;
221 190 jshamlet
      rtc.tens_l_ro     <= '0';
222 168 jshamlet
      if( update_rtc = '1' )then
223
        rtc.tens_l      <= shd_tens(3 downto 0);
224
      elsif( rtc.tens_l > x"9")then
225
        rtc.tens_l      <= (others => '0');
226
        rtc.tens_l_ro   <= '1';
227
      end if;
228
 
229
      -- Decisecond counter (upper)
230
      rtc.tens_u        <= rtc.tens_u + rtc.tens_l_ro;
231 190 jshamlet
      rtc.tens_u_ro     <= '0';
232 168 jshamlet
      if( update_rtc = '1' )then
233
        rtc.tens_u      <= shd_tens(7 downto 4);
234
      elsif( rtc.tens_u > x"9")then
235
        rtc.tens_u      <= (others => '0');
236
        rtc.tens_u_ro   <= '1';
237
      end if;
238
 
239
      -- Second counter (lower)
240
      rtc.secs_l        <= rtc.secs_l + rtc.tens_u_ro;
241 190 jshamlet
      rtc.secs_l_ro     <= '0';
242 168 jshamlet
      if( update_rtc = '1' )then
243
        rtc.secs_l      <= shd_secs(3 downto 0);
244
      elsif( rtc.secs_l > x"9")then
245
        rtc.secs_l      <= (others => '0');
246
        rtc.secs_l_ro   <= '1';
247
      end if;
248
 
249
      -- Second counter (upper)
250
      rtc.secs_u        <= rtc.secs_u + rtc.secs_l_ro;
251 190 jshamlet
      rtc.secs_u_ro     <= '0';
252 168 jshamlet
      if( update_rtc = '1' )then
253
        rtc.secs_u      <= shd_secs(7 downto 4);
254
      elsif( rtc.secs_u > x"5")then
255
        rtc.secs_u      <= (others => '0');
256
        rtc.secs_u_ro   <= '1';
257
      end if;
258
 
259
      -- Minutes counter (lower)
260
      rtc.mins_l        <= rtc.mins_l + rtc.secs_u_ro;
261 190 jshamlet
      rtc.mins_l_ro     <= '0';
262 168 jshamlet
      if( update_rtc = '1' )then
263
        rtc.mins_l      <= shd_mins(3 downto 0);
264
      elsif( rtc.mins_l > x"9")then
265
        rtc.mins_l      <= (others => '0');
266
        rtc.mins_l_ro   <= '1';
267
      end if;
268
 
269
      -- Minutes counter (upper)
270
      rtc.mins_u        <= rtc.mins_u + rtc.mins_l_ro;
271 190 jshamlet
      rtc.mins_u_ro     <= '0';
272 168 jshamlet
      if( update_rtc = '1' )then
273
        rtc.mins_u      <= shd_mins(7 downto 4);
274
      elsif( rtc.mins_u > x"5")then
275
        rtc.mins_u      <= (others => '0');
276
        rtc.mins_u_ro   <= '1';
277
      end if;
278
 
279
      -- Hour counter (lower)
280
      rtc.hours_l       <= rtc.hours_l + rtc.mins_u_ro;
281 190 jshamlet
      rtc.hours_l_ro    <= '0';
282 168 jshamlet
      if( update_rtc = '1' )then
283
        rtc.hours_l     <= shd_hours(3 downto 0);
284
      elsif( rtc.hours_l > x"9")then
285
        rtc.hours_l     <= (others => '0');
286
        rtc.hours_l_ro  <= '1';
287
      end if;
288
 
289
      -- Hour counter (upper)
290
      rtc.hours_u       <= rtc.hours_u + rtc.hours_l_ro;
291
      if( update_rtc = '1' )then
292
        rtc.hours_u     <= shd_hours(7 downto 4);
293
      end if;
294
 
295 190 jshamlet
      rtc.hours_u_ro    <= '0';
296 168 jshamlet
      if( rtc.hours_u >= x"2" and rtc.hours_l > x"3" )then
297
        rtc.hours_l     <= (others => '0');
298
        rtc.hours_u     <= (others => '0');
299
        rtc.hours_u_ro  <= '1';
300
      end if;
301
 
302
      -- Day of Week counter
303
      rtc.dow           <= rtc.dow + rtc.hours_u_ro;
304
      if( update_rtc = '1' )then
305
        rtc.dow        <= shd_dow(2 downto 0);
306
      elsif( rtc.dow = x"07")then
307
        rtc.dow         <= (others => '0');
308
      end if;
309
 
310
      -- Copy the RTC registers to the shadow registers when the coherency
311
      --  timer is zero (RTC registers are static)
312
      if( update_shd = '1' and or_reduce(update_ctmr) = '0' )then
313
        shd_tens        <= rtc.tens_u & rtc.tens_l;
314
        shd_secs        <= rtc.secs_u & rtc.secs_l;
315
        shd_mins        <= rtc.mins_u & rtc.mins_l;
316
        shd_hours       <= rtc.hours_u & rtc.hours_l;
317
        shd_dow         <= "00000" & rtc.dow;
318
        update_shd      <= '0';
319
      end if;
320
 
321
      Reg_Addr_q        <= Reg_Addr;
322
      Wr_Data_q         <= Wr_Data;
323
 
324
      Wr_En             <= Addr_Match and Wr_Enable;
325
      update_rtc        <= '0';
326
      if( Wr_En = '1' )then
327
        case( Reg_Addr_q )is
328
          when "000" =>
329
            interval    <= Wr_Data_q;
330
 
331
          when "001" =>
332
            shd_tens    <= Wr_Data_q;
333
 
334
          when "010" =>
335
            shd_secs    <= Wr_Data_q;
336
 
337
          when "011" =>
338
            shd_mins    <= Wr_Data_q;
339
 
340
          when "100" =>
341
            shd_hours   <= Wr_Data_q;
342
 
343
          when "101" =>
344
            shd_dow     <= Wr_Data_q;
345
 
346
          when "110" =>
347
            update_rtc  <= '1';
348
 
349
          when "111" =>
350
            update_shd  <= '1';
351
 
352
          when others => null;
353
        end case;
354
      end if;
355
 
356
      -- Coherency timer - ensures that the shadow registers are updated with
357
      --  valid time data by delaying updates until the rtc registers have
358
      --  finished cascading.
359
      update_ctmr       <= update_ctmr - or_reduce(update_ctmr);
360
      if( rtc.frac_ro = '1' )then
361
        update_ctmr     <= (others => '1');
362
      end if;
363
 
364
      Rd_Data           <= (others => '0');
365
      Rd_En             <= Addr_Match and Rd_Enable;
366
      if( Rd_En = '1' )then
367
        case( Reg_Addr_q )is
368
          when "000" =>
369
            Rd_Data     <= interval;
370
          when "001" =>
371
            Rd_Data     <= shd_tens;
372
          when "010" =>
373
            Rd_Data     <= shd_secs;
374
          when "011" =>
375
            Rd_Data     <= shd_mins;
376
          when "100" =>
377
            Rd_Data     <= shd_hours;
378
          when "101" =>
379
            Rd_Data     <= shd_dow;
380
          when "110" =>
381
            null;
382
          when "111" =>
383
            Rd_Data     <= update_shd & "0000000";
384
          when others => null;
385
        end case;
386
      end if;
387
 
388
    end if;
389
  end process;
390
 
391
end architecture;

powered by: WebSVN 2.1.0

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