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 200

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

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

powered by: WebSVN 2.1.0

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