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

Subversion Repositories datetime

[/] [datetime/] [trunk/] [rtl/] [verilog/] [Datetime.v] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 robfinch
`timescale 1ns / 1ps
2
//=============================================================================
3
//      (C) 2007,2012  Robert T Finch
4
//      All rights reserved.
5
//      robfinch<remove>@opencores.org
6
//
7
//      Datetime.v
8
//      
9
//
10
// This source file is free software: you can redistribute it and/or modify 
11
// it under the terms of the GNU Lesser General Public License as published 
12
// by the Free Software Foundation, either version 3 of the License, or     
13
// (at your option) any later version.                                      
14
//                                                                          
15
// This source file is distributed in the hope that it will be useful,      
16
// but WITHOUT ANY WARRANTY; without even the implied warranty of           
17
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            
18
// GNU General Public License for more details.                             
19
//                                                                          
20
// You should have received a copy of the GNU General Public License        
21
// along with this program.  If not, see <http://www.gnu.org/licenses/>.    
22
//
23
//
24
//
25
//      BCD representations are used
26
//      - BCD allows direct visual indication of values without
27
//      needing to convert hexidecimal values
28
//
29
//
30
//      Address  Reg
31
//              
32
//      DC0400    0     DT - Date/Time register
33
//                      [ 7: 0] read / write jiffies
34
//                      [15: 8] read / write seconds
35
//                      [23:16] read / write minutes
36
//                      [31:24] read / write hours
37
//                              [39:32] read/write day
38
//                              [47:40] read/write month
39
//                              [63:48] read/write year
40
//
41
//      DC0408    1 ALM - alarm register same format as 0, but contain alarm setting
42
//
43
//  DC0410        2     CR - control register
44
//                      [ 7: 0] write - which bytes to match for alarm
45
//                      [8] - time of day enable
46
//                      [10: 9] - 00=100 Hz, 01=60Hz, 10=50Hz
47
//                      [16] - mars timekeeping
48
//
49
//      DC0418   3 SN
50
//                              writing this register triggers a snapshot
51
//                              - trigger a snapshot before reading the date / time
52
//                              registers
53
//                              - the snapshot allows the date / time value to be
54
//                              read without having to worry about an update occuring
55
//                              during the read
56
//                              - a copy of the current date and time is stored in
57
//                              the output registers
58
//
59
//=============================================================================
60
//
61
module Datetime
62
#(
63
        parameter pIOAddress = 24'hDC0400,
64
        parameter pMars = 1'b0
65
)
66
(
67
// Syscon
68
input rst_i,            // reset
69
input clk_i,            // system clock
70
 
71
// System bus
72
input cyc_i,            // valid bus cycle
73
input stb_i,            // data transfer strobe
74
output ack_o,           // transfer acknowledge
75
input we_i,                     // 1=write
76
input [7:0] sel_i,       // byte select
77
input [23:0] adr_i,      // address
78
input [63:0] dat_i,      // data input
79
output reg [63:0] dat_o, // data output
80
 
81
input tod,                      // tod pulse (eg 60 Hz)
82
output reg alarm                // alarm match
83
);
84
 
85
reg [1:0] tod_freq;
86
wire [7:0] max_jcnt = tod_freq==2'b00 ? 8'h99 : tod_freq==2'b01 ? 8'h59 : tod_freq==2'b10 ? 8'h49 : 8'h99;
87
reg tod_en;
88
reg mars;
89
reg snapshot;
90
wire IsLeapYear;
91
wire IsDuckYear;
92
 
93
// internal counters
94
reg [3:0] dayL, dayH;            // 1-99
95
reg [3:0] monthL, monthH;        // 1-99
96
reg [3:0] yearN0, yearN1, yearN2, yearN3;        // 
97
reg [3:0] jiffyL, secL, minL, hourL;
98
reg [3:0] jiffyH, secH, minH, hourH;
99
 
100
// output latches
101
reg [3:0] dayLo, dayHo;          // 1-99
102
reg [3:0] monthLo, monthHo;      // 1-99
103
reg [3:0] yearN0o, yearN1o, yearN2o, yearN3o;    // 
104
reg [3:0] jiffyLo, secLo, minLo, hourLo;
105
reg [3:0] jiffyHo, secHo, minHo, hourHo;
106
 
107
// alarm
108
reg [7:0] alarm_care;
109
wire [63:0] alarm_carex = {
110
        {8{alarm_care[7]}},
111
        {8{alarm_care[6]}},
112
        {8{alarm_care[5]}},
113
        {8{alarm_care[4]}},
114
        {8{alarm_care[3]}},
115
        {8{alarm_care[2]}},
116
        {8{alarm_care[1]}},
117
        {8{alarm_care[0]}}
118
};
119
reg [3:0] alm_dayL, alm_dayH;            // 1-99
120
reg [3:0] alm_monthL, alm_monthH;        // 1-99
121
reg [3:0] alm_yearN0, alm_yearN1, alm_yearN2, alm_yearN3;        // 
122
reg [3:0] alm_jiffyL, alm_secL, alm_minL, alm_hourL;
123
reg [3:0] alm_jiffyH, alm_secH, alm_minH, alm_hourH;
124
 
125
 
126
// update detects
127
wire incJiffyH = jiffyL == 4'd9;
128
wire incSecL = {jiffyH,jiffyL}==max_jcnt;
129
wire incSecH = incSecL && secL==4'h9;
130
wire incMinL = incSecH && secH==4'h5;
131
wire incMinH = incMinL && minL==4'h9;
132
wire incHourL = incMinH && minH==4'h5;
133
wire incHourH = incHourL && hourL==4'h9;
134
 
135
wire incDayL    = mars ?
136
                                        {hourH,hourL,minH,minL,secH,secL,jiffyH,jiffyL} == {24'h243721,max_jcnt} :
137
                                        {hourH,hourL,minH,minL,secH,secL,jiffyH,jiffyL} == {24'h235959,max_jcnt}
138
                                        ;
139
wire incDayH = incDayL && dayL==4'h9;
140
 
141
// 668.5991     
142
reg incMarsMonth;
143
always @(monthH,monthL,dayH,dayL)
144
        begin
145
        case({monthH,monthL})   // synopsys full_case parallel_case
146
        8'h01:  incMarsMonth = {dayH,dayL}==8'h33;
147
        8'h02:  incMarsMonth = {dayH,dayL}==8'h33;
148
        8'h03:  incMarsMonth = {dayH,dayL}==8'h33;
149
        8'h04:  incMarsMonth = {dayH,dayL}==8'h34;
150
        8'h05:  incMarsMonth = {dayH,dayL}==8'h34;
151
        8'h06:  incMarsMonth = {dayH,dayL}==8'h33;
152
        8'h07:  incMarsMonth = {dayH,dayL}==8'h33;
153
        8'h08:  incMarsMonth = {dayH,dayL}==8'h33;
154
        8'h09:  incMarsMonth = {dayH,dayL}==8'h34;
155
        8'h10:  incMarsMonth = {dayH,dayL}==8'h34;
156
        8'h11:  incMarsMonth = {dayH,dayL}==8'h33;
157
        8'h12:  incMarsMonth = {dayH,dayL}==8'h33;
158
        8'h13:  incMarsMonth = {dayH,dayL}==8'h33;
159
        8'h14:  incMarsMonth = {dayH,dayL}==8'h34;
160
        8'h15:  incMarsMonth = {dayH,dayL}==8'h34;
161
        8'h16:  incMarsMonth = {dayH,dayL}==8'h33;
162
        8'h17:  incMarsMonth = {dayH,dayL}==8'h33;
163
        8'h18:  incMarsMonth = {dayH,dayL}==8'h33;
164
        8'h19:  incMarsMonth = {dayH,dayL}==8'h34;
165
        8'h20:  incMarsMonth = IsDuckYear ? {dayH,dayL}==8'h34 : {dayH,dayL}==8'h35;
166
        endcase
167
        end
168
 
169
reg incEarthMonth;
170
always @(monthH,monthL,dayH,dayL)
171
        begin
172
        case({monthH,monthL})   // synopsys full_case parallel_case
173
        8'h01:  incEarthMonth = {dayH,dayL}==8'h31;
174
        8'h02:  incEarthMonth = IsLeapYear ? {dayH,dayL}==8'h29 : {dayH,dayL}==8'h28;
175
        8'h03:  incEarthMonth = {dayH,dayL}==8'h31;
176
        8'h04:  incEarthMonth = {dayH,dayL}==8'h30;
177
        8'h05:  incEarthMonth = {dayH,dayL}==8'h31;
178
        8'h06:  incEarthMonth = {dayH,dayL}==8'h30;
179
        8'h07:  incEarthMonth = {dayH,dayL}==8'h31;
180
        8'h08:  incEarthMonth = {dayH,dayL}==8'h31;
181
        8'h09:  incEarthMonth = {dayH,dayL}==8'h30;
182
        8'h10:  incEarthMonth = {dayH,dayL}==8'h31;
183
        8'h11:  incEarthMonth = {dayH,dayL}==8'h30;
184
        8'h12:  incEarthMonth = {dayH,dayL}==8'h31;
185
        endcase
186
        end
187
 
188
wire incMonthL  = incDayL && (mars ? incMarsMonth : incEarthMonth);
189
wire incMonthH  = incMonthL && monthL==4'd9;
190
wire incYearN0  = incMonthL && (mars ? {monthH,monthL} == 8'h20 : {monthH,monthL} == 8'h12);
191
wire incYearN1  = incYearN0 && yearN0 == 4'h9;
192
wire incYearN2  = incYearN1 && yearN1 == 4'h9;
193
wire incYearN3  = incYearN2 && yearN2 == 4'h9;
194
 
195
 
196
wire cs = cyc_i && stb_i && (adr_i[23:5]==pIOAddress[23:5]);
197
 
198
reg ack1;
199
always @(posedge clk_i)
200
        ack1 <= cs;
201
assign ack_o = cs ? (we_i ? 1'b1 : ack1) : 1'b0;
202
 
203
// Synchronize external tod signal
204
wire tods;
205
sync2s sync0(.rst(rst_i), .clk(clk_i), .i(tod), .o(tods));
206
 
207
// Edge detect the incoming tod signal.
208
wire tod_edge;
209
edge_det ed_tod(.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(tods), .pe(tod_edge), .ne(), .ee());
210
 
211
// Output alarm pulse on match
212
wire isAlarm =
213
                {
214
                        alm_jiffyH,alm_jiffyL,
215
                        alm_secH,alm_secL,
216
                        alm_minH,alm_minL,
217
                        alm_hourH, alm_hourL,
218
                        alm_dayH,alm_dayL,
219
                        alm_monthH,alm_monthL,
220
                        alm_yearN1,alm_yearN0,
221
                        alm_yearN3,alm_yearN2
222
                } & alarm_carex ==
223
                {
224
                        jiffyH,jiffyL,
225
                        secH,secL,
226
                        minH,minL,
227
                        hourH,hourL,
228
                        dayH,dayL,
229
                        monthH,monthL,
230
                        yearN1,yearN0,
231
                        yearN3,yearN3
232
                } & alarm_carex;
233
 
234
 
235
reg oalarm;
236
 
237
always @(posedge clk_i)
238
        if (rst_i) begin
239
                oalarm <= 1'b0;
240
                mars <= pMars;
241
                tod_en <= 1'b1;
242
                tod_freq = 2'b00;
243
 
244
                jiffyL <= 4'h0;
245
                jiffyH <= 4'h0;
246
                secL <= 4'h0;
247
                secH <= 4'h0;
248
                minL <= 4'h6;
249
                minH <= 4'h0;
250
                hourL <= 4'h3;
251
                hourH <= 4'h1;
252
 
253
                dayL <= 4'h0;
254
                dayH <= 4'h1;
255
                monthL <= 4'h6;
256
                monthH <= 4'h0;
257
                yearN0 <= 4'h2;
258
                yearN1 <= 4'h1;
259
                yearN2 <= 4'h0;
260
                yearN3 <= 4'h2;
261
 
262
                alarm_care <= 8'hFF;
263
                alm_jiffyL <= 4'h0;
264
                alm_jiffyH <= 4'h0;
265
                alm_secL <= 4'h0;
266
                alm_secH <= 4'h0;
267
                alm_minL <= 4'h0;
268
                alm_minH <= 4'h0;
269
                alm_hourL <= 4'h0;
270
                alm_hourH <= 4'h0;
271
 
272
                alm_dayL <= 4'h0;
273
                alm_dayH <= 4'h0;
274
                alm_monthL <= 4'h0;
275
                alm_monthH <= 4'h0;
276
                alm_yearN0 <= 4'h0;
277
                alm_yearN1 <= 4'h0;
278
                alm_yearN2 <= 4'h0;
279
                alm_yearN3 <= 4'h0;
280
 
281
                snapshot <= 1'b0;
282
 
283
        end
284
        else begin
285
 
286
                oalarm <= isAlarm;
287
                snapshot <= 1'b0;       // ensure it only pulses
288
 
289
                if (isAlarm & !oalarm)
290
                        alarm <= 1'b1;
291
 
292
                // Handle register updates
293
                if (cs & we_i) begin
294
                        case(adr_i[4:3])
295
 
296
                        2'd0:   begin
297
                                        if (sel_i[0]) begin jiffyL <= dat_i[3:0]; jiffyH <= dat_i[7:4]; end
298
                                        if (sel_i[1]) begin secL <= dat_i[3:0]; secH <= dat_i[7:4]; end
299
                                        if (sel_i[2]) begin minL <= dat_i[3:0]; minH <= dat_i[7:4]; end
300
                                        if (sel_i[3]) begin hourL <= dat_i[3:0]; hourH <= dat_i[7:4]; end
301
                                        if (sel_i[4]) begin dayL <= dat_i[3:0]; dayH <= dat_i[7:4]; end
302
                                        if (sel_i[5]) begin monthL <= dat_i[3:0]; monthH <= dat_i[7:4]; end
303
                                        if (sel_i[6]) begin yearN0 <= dat_i[3:0]; yearN1 <= dat_i[7:4]; end
304
                                        if (sel_i[7]) begin yearN2 <= dat_i[3:0]; yearN3 <= dat_i[7:4]; end
305
                                        end
306
 
307
                        2'd1:   begin
308
                                        if (sel_i[0]) begin alm_jiffyL <= dat_i[3:0]; alm_jiffyH <= dat_i[7:4]; end
309
                                        if (sel_i[1]) begin alm_secL <= dat_i[3:0]; alm_secH <= dat_i[7:4]; end
310
                                        if (sel_i[2]) begin alm_minL <= dat_i[3:0]; alm_minH <= dat_i[7:4]; end
311
                                        if (sel_i[3]) begin alm_hourL <= dat_i[3:0]; alm_hourH <= dat_i[7:4]; end
312
                                        if (sel_i[4]) begin alm_dayL <= dat_i[3:0]; alm_dayH <= dat_i[7:4]; end
313
                                        if (sel_i[5]) begin alm_monthL <= dat_i[3:0]; alm_monthH <= dat_i[7:4]; end
314
                                        if (sel_i[6]) begin alm_yearN0 <= dat_i[3:0]; alm_yearN1 <= dat_i[7:4]; end
315
                                        if (sel_i[7]) begin alm_yearN2 <= dat_i[3:0]; alm_yearN3 <= dat_i[7:4]; end
316
                                        end
317
 
318
                        2'd2:   begin
319
                                        if (sel_i[0]) alarm_care <= dat_i[7:0];
320
                                        if (sel_i[1])   begin
321
                                                                        tod_en <= dat_i[8];
322
                                                                        tod_freq <= dat_i[10:9];
323
                                                                        end
324
                                        if (sel_i[2]) mars <= dat_i[16];
325
                                        end
326
 
327
                        // writing to register 3 triggers a snapshot
328
                        2'd3:   snapshot <= 1'b1;
329
 
330
                        endcase
331
                end
332
                if (cs) begin
333
                        case(adr_i[4:3])
334
                        2'd0:   dat_o <= {yearN3o,yearN2o,yearN1o,yearN0o,monthHo,monthLo,dayHo,dayLo,hourHo,hourLo,minHo,minLo,secHo,secLo,jiffyHo,jiffyLo};
335
                        2'd1:   begin
336
                                                dat_o <= {alm_yearN3,alm_yearN2,alm_yearN1,alm_yearN0,alm_monthH,alm_monthL,alm_dayH,alm_dayL,alm_hourH,alm_hourL,alm_minH,alm_minL,alm_secH,alm_secL,alm_jiffyH,alm_jiffyL};
337
                                                alarm <= 1'b0;
338
                                        end
339
                        2'd2:   dat_o <= {mars,5'b0,tod_freq,tod_en,alarm_care};
340
                        2'd3:   dat_o <= 0;
341
                        endcase
342
                end
343
                else
344
                        dat_o <= 64'd0;
345
 
346
 
347
                // Clock updates
348
                if (tod_en & tod_edge) begin
349
 
350
                        jiffyL <= jiffyL + 4'h1;
351
 
352
                        if (incJiffyH) begin
353
                                jiffyL <= 4'h0;
354
                                jiffyH <= jiffyH + 4'h1;
355
                        end
356
 
357
                        // Seconds
358
                        if (incSecL) begin
359
                                jiffyH <= 4'h0;
360
                                secL <= secL + 4'h1;
361
                        end
362
                        if (incSecH) begin
363
                                secL <= 4'h0;
364
                                secH <= secH + 4'h1;
365
                        end
366
 
367
                        if (incMinL) begin
368
                                minL <= minL + 4'h1;
369
                                secH <= 4'h0;
370
                        end
371
                        if (incMinH) begin
372
                                minL <= 4'h0;
373
                                minH <= minH + 4'h1;
374
                        end
375
 
376
                        if (incHourL) begin
377
                                minH <= 4'h0;
378
                                hourL <= hourL + 4'h1;
379
                        end
380
                        if (incHourH) begin
381
                                hourL <= 4'h0;
382
                                hourH <= hourH + 4'h1;
383
                        end
384
 
385
                        // day increment
386
                        // reset the entire time when the day increments
387
                        // - the day may not be exactly 24 hours long
388
                        if (incDayL) begin
389
                                dayL <= dayL + 4'h1;
390
                                jiffyL <= 4'h0;
391
                                jiffyH <= 4'h0;
392
                                secL <= 4'h0;
393
                                secH <= 4'h0;
394
                                minL <= 4'h0;
395
                                minH <= 4'h0;
396
                                hourL <= 4'h0;
397
                                hourH <= 4'h0;
398
                        end
399
                        if (incDayH) begin
400
                                dayL <= 4'h0;
401
                                dayH <= dayH + 4'h1;
402
                        end
403
 
404
                        if (incMonthL) begin
405
                                dayL <= 4'h1;
406
                                dayH <= 4'h0;
407
                                monthL <= monthL + 4'h1;
408
                        end
409
                        if (incMonthH) begin
410
                                monthL <= 4'h0;
411
                                monthH <= monthH + 4'h1;
412
                        end
413
 
414
                        if (incYearN0) begin
415
                                monthL <= 4'h1;
416
                                monthH <= 4'h0;
417
                        end
418
                        if (incYearN1) begin
419
                                yearN0 <= 4'h0;
420
                                yearN1 <= yearN1 + 4'h1;
421
                        end
422
                        if (incYearN2) begin
423
                                yearN1 <= 4'h0;
424
                                yearN2 <= yearN2 + 4'h1;
425
                        end
426
                        if (incYearN3) begin
427
                                yearN2 <= 4'h0;
428
                                yearN3 <= yearN3 + 4'h1;
429
                        end
430
                end
431
        end
432
 
433
 
434
// Take snapshot of date / time
435
always @(posedge clk_i)
436
        if (rst_i) begin
437
                jiffyLo <= 4'h0;
438
                jiffyHo <= 4'h0;
439
                secLo <= 4'h0;
440
                secHo <= 4'h0;
441
                minLo <= 4'h0;
442
                minHo <= 4'h0;
443
                hourLo <= 4'h0;
444
                hourHo <= 4'h0;
445
                dayLo <= 4'h0;
446
                dayHo <= 4'h0;
447
                monthLo <= 4'h0;
448
                monthHo <= 4'h0;
449
                yearN0o <= 4'h0;
450
                yearN1o <= 4'h0;
451
                yearN2o <= 4'h0;
452
                yearN3o <= 4'h0;
453
        end
454
        else if (snapshot) begin
455
                jiffyLo <= jiffyL;
456
                jiffyHo <= jiffyH;
457
                secLo <= secL;
458
                secHo <= secH;
459
                minLo <= minL;
460
                minHo <= minH;
461
                hourLo <= hourL;
462
                hourHo <= hourH;
463
                dayLo <= dayL;
464
                dayHo <= dayH;
465
                monthLo <= monthL;
466
                monthHo <= monthH;
467
                yearN0o <= yearN0;
468
                yearN1o <= yearN1;
469
                yearN2o <= yearN2;
470
                yearN3o <= yearN3;
471
        end
472
 
473
//   int IsLeapYear() const {
474
//      return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
475
//   };
476
//
477
// We don't need to convert the whole year to binary to determine if it's divisble by four,
478
// only the lowest two order nybbles need be converted.
479
wire [7:0] binyear =
480
                        yearN0
481
                        + {yearN1,3'b0} + {yearN1,1'b0} // yearN1 * 10
482
//                      + {yearN2,6'b0} + {yearN2,5'b0} + {yearN2,2'b0} // yearN2 * 100
483
//                      + {yearN3,9'b0} + {yearN3,8'b0} + {yearN3,7'b0} + {yearN3,6'b0} + {yearN3,5'b0} + {yearN3,3'b0}
484
                        ;
485
 
486
// convert century to binary to see if it's divisible by four
487
wire [7:0] bincent = {yearN3,3'b0} + {yearN3,1'b0} + yearN2;
488
 
489
assign IsLeapYear = binyear[1:0]==2'b00 && ({yearN1,yearN0}!=8'h00 || (bincent[1:0]==2'b00 && {yearN1,yearN0}==8'h00));
490
 
491
assign IsDuckYear = yearN0==4'h1 || yearN0==4'h3 || yearN0==4'h6 || yearN0==4'h8;
492
 
493
endmodule
494
 

powered by: WebSVN 2.1.0

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