OpenCores
URL https://opencores.org/ocsvn/openarty/openarty/trunk

Subversion Repositories openarty

[/] [openarty/] [trunk/] [rtl/] [rtcdate.v] - Blame information for rev 38

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

Line No. Rev Author Line
1 30 dgisselq
////////////////////////////////////////////////////////////////////////////////
2 3 dgisselq
//
3
// Filename:    rtcdate.v
4
//              
5
// Project:     A Wishbone Controlled Real--time Clock Core
6
//
7
// Purpose:
8
//      This core provides a real-time date function that can be coupled with
9
//      a real-time clock.  The date provided is in Binary Coded Decimal (bcd)
10
//      form, and available for reading and writing over the Wishbone Bus.
11
//
12
// WARNING: Race conditions exist when updating the date across the Wishbone
13
//      bus at or near midnight.  (This should be obvious, but it bears
14
//      stating.)  Specifically, if the update command shows up at the same
15
//      clock as the ppd clock, then the ppd clock will be ignored and the 
16
//      new date will be the date of the day following midnight.  However,
17
//      if the update command shows up one clock before the ppd, then the date
18
//      may be updated, but may have problems dealing with the last day of the
19
//      month or year.  To avoid race conditions, update the date sometime
20
//      after the stroke of midnight and before 5 clocks before the next
21
//      midnight.  If you are concerned that you might hit a race condition, 
22
//      just read the clock again (5+ clocks later) to make certain you set 
23
//      it correctly.
24
//
25
//
26
// Creator:     Dan Gisselquist, Ph.D.
27
//              Gisselquist Technology, LLC
28
//
29 30 dgisselq
////////////////////////////////////////////////////////////////////////////////
30 3 dgisselq
//
31
// Copyright (C) 2015, Gisselquist Technology, LLC
32
//
33
// This program is free software (firmware): you can redistribute it and/or
34
// modify it under the terms of  the GNU General Public License as published
35
// by the Free Software Foundation, either version 3 of the License, or (at
36
// your option) any later version.
37
//
38
// This program is distributed in the hope that it will be useful, but WITHOUT
39
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
40
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
41
// for more details.
42
//
43
// You should have received a copy of the GNU General Public License along
44
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
45
// target there if the PDF file isn't present.)  If not, see
46
// <http://www.gnu.org/licenses/> for a copy.
47
//
48
// License:     GPL, v3, as defined and found on www.gnu.org,
49
//              http://www.gnu.org/licenses/gpl.html
50
//
51
//
52 30 dgisselq
////////////////////////////////////////////////////////////////////////////////
53 3 dgisselq
module rtcdate(i_clk, i_ppd, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_data,
54
                o_wb_ack, o_wb_stall, o_wb_data);
55
        input   i_clk;
56
        // A one part per day signal, i.e. basically a clock enable line that
57
        // controls when the beginning of the day happens.  This line should
58
        // be high on the very last second of any day in order for the rtcdate
59
        // module to always have the right date.
60
        input   i_ppd;
61
        // Wishbone inputs
62
        input   i_wb_cyc, i_wb_stb, i_wb_we;
63
        input   [31:0]   i_wb_data;
64
        // Wishbone outputs
65
        output  reg     o_wb_ack;
66
        output  wire    o_wb_stall;
67
        output  wire    [31:0]   o_wb_data;
68
 
69
 
70
        reg     [5:0]    r_day;
71
        reg     [4:0]    r_mon;
72
        reg     [13:0]   r_year;
73
 
74
        reg     last_day_of_month, last_day_of_year, is_leap_year;
75
        reg     [5:0]    days_per_month;
76
        initial days_per_month = 6'h31; // Remember, this is BCD
77
        always @(posedge i_clk)
78
        begin // Clock 3
79
                case(r_mon)
80
                5'h01: days_per_month <= 6'h31; // Jan
81
                5'h02: days_per_month <= (is_leap_year)? 6'h29:6'h28;
82
                5'h03: days_per_month <= 6'h31; // March
83
                5'h04: days_per_month <= 6'h30; // April
84
                5'h05: days_per_month <= 6'h31; // May
85
                5'h06: days_per_month <= 6'h30; // June
86
                5'h07: days_per_month <= 6'h31; // July
87
                5'h08: days_per_month <= 6'h31; // August
88
                5'h09: days_per_month <= 6'h30; // Sept
89
                5'h10: days_per_month <= 6'h31; // October
90
                5'h11: days_per_month <= 6'h30; // November
91
                5'h12: days_per_month <= 6'h31; // December
92
                default: days_per_month <= 6'h31; // Invalid month
93
                endcase
94
        end
95
        initial last_day_of_month = 1'b0;
96
        always @(posedge i_clk) // Clock 4
97
                last_day_of_month <= (r_day >= days_per_month);
98
        initial last_day_of_year = 1'b0;
99
        always @(posedge i_clk) // Clock 5
100
                last_day_of_year <= (last_day_of_month) && (r_mon == 5'h12);
101
 
102
        reg     year_divisible_by_four, century_year, four_century_year;
103
        always @(posedge i_clk) // Clock 1
104
                year_divisible_by_four<= ((~r_year[0])&&(r_year[4]==r_year[1]));
105
        always @(posedge i_clk) // Clock 1
106
                century_year <= (r_year[7:0] == 8'h00);
107
        always @(posedge i_clk) // Clock 1
108
                four_century_year <= ((~r_year[8])&&((r_year[12]==r_year[9])));
109
        always @(posedge i_clk) // Clock 2
110
                is_leap_year <= (year_divisible_by_four)&&((~century_year)
111
                        ||((century_year)&&(four_century_year)));
112
 
113
 
114
        // Adjust the day of month
115
        reg     [5:0]    next_day, fixd_day;
116
        always @(posedge i_clk)
117
                if (last_day_of_month)
118
                        next_day <= 6'h01;
119
                else if (r_day[3:0] != 4'h9)
120
                        next_day <= { r_day[5:4], (r_day[3:0]+4'h1) };
121
                else
122
                        next_day <= { (r_day[5:4]+2'h1), 4'h0 };
123
        always @(posedge i_clk)
124
                if ((r_day == 0)||(r_day > 6'h31)||(r_day[3:0] > 4'h9))
125
                        fixd_day <= 6'h01;
126
                else
127
                        fixd_day <= r_day;
128
 
129
        initial r_day = 6'h01;
130
        always @(posedge i_clk)
131
        begin // Depends upon 9 inputs
132
                if (i_ppd)
133
                        r_day <= next_day;
134
                else if (~o_wb_ack)
135
                        r_day <= fixd_day;
136
 
137
                if ((i_wb_stb)&&(i_wb_we)&&(~i_wb_data[7]))
138
                        r_day <= i_wb_data[5:0];
139
        end
140
 
141
        // Adjust the month of the year
142
        reg     [4:0]    next_mon, fixd_mon;
143
        always @(posedge i_clk)
144
                if (last_day_of_year)
145
                        next_mon <= 5'h01;
146
                else if ((last_day_of_month)&&(r_mon[3:0] != 4'h9))
147
                        next_mon <= { r_mon[4], (r_mon[3:0] + 4'h1) };
148
                else if (last_day_of_month)
149
                begin
150
                        next_mon[3:0] <= 4'h0;
151
                        next_mon[4] <= 1;
152
                end else
153
                        next_mon <= r_mon;
154
 
155
        always @(posedge i_clk)
156
                if ((r_mon == 0)||(r_mon > 5'h12)||(r_mon[3:0] > 4'h9))
157
                        fixd_mon <= 5'h01;
158
                else
159
                        fixd_mon <= r_mon;
160
        initial r_mon = 5'h01;
161
        always @(posedge i_clk)
162
        begin // Depeds upon 9 inputs
163
                if (i_ppd)
164
                        r_mon <= next_mon;
165
                else if (~o_wb_ack)
166
                        r_mon <= fixd_mon;
167
 
168
                if ((i_wb_stb)&&(i_wb_we)&&(~i_wb_data[15]))
169
                        r_mon <= i_wb_data[12:8];
170
        end
171
 
172
        // Adjust the year
173
        reg     [13:0]   next_year;
174
        reg     [2:0]    next_year_c;
175
        always @(posedge i_clk)
176
        begin // Takes 5 clocks to propagate
177
                next_year_c[0] <= (r_year[ 3: 0]>=4'h9);
178
                next_year_c[1] <= (r_year[ 7: 4]>4'h9)||((r_year[ 7: 4]==4'h9)&&(next_year_c[0]));
179
                next_year_c[2] <= (r_year[11: 8]>4'h9)||((r_year[11: 8]==4'h9)&&(next_year_c[1]));
180
                next_year[ 3: 0] <= (next_year_c[0])? 4'h0:(r_year[ 3: 0]+4'h1);
181
                next_year[ 7: 4] <= (next_year_c[1])? 4'h0:
182
                                        (next_year_c[0])?(r_year[ 7: 4]+4'h1)
183
                                        : (r_year[7:4]);
184
                next_year[11: 8] <= (next_year_c[2])? 4'h0:
185
                                        (next_year_c[1])?(r_year[11: 8]+4'h1)
186
                                        : (r_year[11: 8]);
187
                next_year[13:12] <= (next_year_c[2])?(r_year[13:12]+2'h1):r_year[13:12];
188
        end
189
 
190
        initial r_year = 14'h2000;
191
        always @(posedge i_clk)
192
        begin // 11 inputs
193
                // Deal with any out of bounds conditions
194
                if (r_year[3:0] > 4'h9)
195
                        r_year[3:0] <= 4'h0;
196
                if (r_year[7:4] > 4'h9)
197
                        r_year[7:4] <= 4'h0;
198
                if (r_year[11:8] > 4'h9)
199
                        r_year[11:8] <= 4'h0;
200
                if ((i_ppd)&&(last_day_of_year))
201
                        r_year <= next_year;
202
 
203
                if ((i_wb_stb)&&(i_wb_we)&&(~i_wb_data[31]))
204
                        r_year <= i_wb_data[29:16];
205
        end
206
 
207
        always @(posedge i_clk)
208
                o_wb_ack <= (i_wb_stb);
209
        assign  o_wb_stall = 1'b0;
210
        assign  o_wb_data = { 2'h0, r_year, 3'h0, r_mon, 2'h0, r_day };
211
endmodule

powered by: WebSVN 2.1.0

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