~ubuntu-branches/ubuntu/raring/mame/raring-proposed

« back to all changes in this revision

Viewing changes to mess/src/emu/machine/rp5c15.c

  • Committer: Package Import Robot
  • Author(s): Jordi Mallach, Jordi Mallach, Emmanuel Kasper
  • Date: 2011-12-19 22:56:27 UTC
  • mfrom: (0.1.2)
  • Revision ID: package-import@ubuntu.com-20111219225627-ub5oga1oys4ogqzm
Tags: 0.144-1
[ Jordi Mallach ]
* Fix syntax errors in DEP5 copyright file (lintian).
* Use a versioned copyright Format specification field.
* Update Vcs-* URLs.
* Move transitional packages to the new metapackages section, and make
  them priority extra.
* Remove references to GNU/Linux and MESS sources from copyright.
* Add build variables for s390x.
* Use .xz tarballs as it cuts 4MB for the upstream sources.
* Add nplayers.ini as a patch. Update copyright file to add CC-BY-SA-3.0.

[ Emmanuel Kasper ]
* New upstream release. Closes: #651538.
* Add Free Desktop compliant png icons of various sizes taken from
  the hydroxygen iconset
* Mess is now built from a new source package, to avoid possible source
  incompatibilities between mame and the mess overlay.
* Mame-tools are not built from the mame source package anymore, but
  from the mess source package

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/**********************************************************************
2
 
 
3
 
    Ricoh RP5C15 Real Time Clock emulation
4
 
 
5
 
    Copyright MESS Team.
6
 
    Visit http://mamedev.org for licensing and usage restrictions.
7
 
 
8
 
*********************************************************************/
9
 
 
10
 
/*
11
 
 
12
 
    TODO:
13
 
 
14
 
    - 12 hour clock
15
 
    - test register
16
 
    - timer reset
17
 
 
18
 
*/
19
 
 
20
 
#include "rp5c15.h"
21
 
 
22
 
 
23
 
 
24
 
//**************************************************************************
25
 
//  MACROS / CONSTANTS
26
 
//**************************************************************************
27
 
 
28
 
#define LOG 0
29
 
 
30
 
 
31
 
// registers
32
 
enum
33
 
{
34
 
        REGISTER_1_SECOND = 0, REGISTER_CLOCK_OUTPUT = REGISTER_1_SECOND,
35
 
        REGISTER_10_SECOND, REGISTER_ADJUST = REGISTER_10_SECOND,
36
 
        REGISTER_1_MINUTE,
37
 
        REGISTER_10_MINUTE,
38
 
        REGISTER_1_HOUR,
39
 
        REGISTER_10_HOUR,
40
 
        REGISTER_DAY_OF_THE_WEEK,
41
 
        REGISTER_1_DAY,
42
 
        REGISTER_10_DAY,
43
 
        REGISTER_1_MONTH,
44
 
        REGISTER_10_MONTH, REGISTER_12_24_SELECT = REGISTER_10_MONTH,
45
 
        REGISTER_1_YEAR, REGISTER_LEAP_YEAR = REGISTER_1_YEAR,
46
 
        REGISTER_10_YEAR,
47
 
        REGISTER_MODE,
48
 
        REGISTER_TEST,
49
 
        REGISTER_RESET
50
 
};
51
 
 
52
 
 
53
 
// clock output select
54
 
enum
55
 
{
56
 
        CLKOUT_Z = 0,
57
 
        CLKOUT_16384_HZ,
58
 
        CLKOUT_1024_HZ,
59
 
        CLKOUT_128_HZ,
60
 
        CLKOUT_16_HZ,
61
 
        CLKOUT_1_HZ,
62
 
        CLKOUT_1_DIV_60_HZ,
63
 
        CLKOUT_L
64
 
};
65
 
 
66
 
 
67
 
// register write mask
68
 
static const int REGISTER_WRITE_MASK[2][16] =
69
 
{
70
 
        { 0xf, 0x7, 0xf, 0x7, 0xf, 0x3, 0x7, 0xf, 0x3, 0xf, 0x1, 0xf, 0xf, 0xf, 0xf, 0xf },
71
 
        { 0x3, 0x1, 0xf, 0x7, 0xf, 0x3, 0x7, 0xf, 0x3, 0x0, 0x1, 0x3, 0x0, 0xf, 0xf, 0xf }
72
 
};
73
 
 
74
 
 
75
 
// days per month
76
 
static const int DAYS_PER_MONTH[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
77
 
 
78
 
 
79
 
// modes
80
 
enum
81
 
{
82
 
        MODE00 = 0,
83
 
        MODE01
84
 
};
85
 
 
86
 
 
87
 
// mode register
88
 
#define MODE_MASK                       0x01
89
 
#define MODE_ALARM_EN           0x04
90
 
#define MODE_TIMER_EN           0x08
91
 
 
92
 
 
93
 
// test register
94
 
#define TEST_0                          0x01
95
 
#define TEST_1                          0x02
96
 
#define TEST_2                          0x04
97
 
#define TEST_3                          0x08
98
 
 
99
 
 
100
 
// reset register
101
 
#define RESET_ALARM                     0x01
102
 
#define RESET_TIMER                     0x02
103
 
#define RESET_16_HZ                     0x04
104
 
#define RESET_1_HZ                      0x08
105
 
 
106
 
 
107
 
 
108
 
//**************************************************************************
109
 
//  GLOBAL VARIABLES
110
 
//**************************************************************************
111
 
 
112
 
// devices
113
 
const device_type RP5C15 = &device_creator<rp5c15_device>;
114
 
 
115
 
 
116
 
 
117
 
//**************************************************************************
118
 
//  INLINE HELPERS
119
 
//**************************************************************************
120
 
 
121
 
//-------------------------------------------------
122
 
//  set_alarm_line -
123
 
//-------------------------------------------------
124
 
 
125
 
inline void rp5c15_device::set_alarm_line()
126
 
{
127
 
        int alarm = ((m_mode & MODE_ALARM_EN) ? m_alarm_on : 1) &
128
 
                                ((m_reset & RESET_16_HZ) ? 1 : m_16hz) &
129
 
                                ((m_reset & RESET_1_HZ) ? 1 : m_1hz);
130
 
 
131
 
        if (m_alarm != alarm)
132
 
        {
133
 
                if (LOG) logerror("RP5C15 '%s' Alarm %u\n", tag(), alarm);
134
 
 
135
 
                m_out_alarm_func(alarm);
136
 
                m_alarm = alarm;
137
 
        }
138
 
}
139
 
 
140
 
 
141
 
//-------------------------------------------------
142
 
//  read_counter -
143
 
//-------------------------------------------------
144
 
 
145
 
inline int rp5c15_device::read_counter(int counter)
146
 
{
147
 
        return (m_reg[MODE00][counter + 1] * 10) + m_reg[MODE00][counter];
148
 
}
149
 
 
150
 
 
151
 
//-------------------------------------------------
152
 
//  write_counter -
153
 
//-------------------------------------------------
154
 
 
155
 
inline void rp5c15_device::write_counter(int counter, int value)
156
 
{
157
 
        m_reg[MODE00][counter] = value % 10;
158
 
        m_reg[MODE00][counter + 1] = value / 10;
159
 
}
160
 
 
161
 
 
162
 
//-------------------------------------------------
163
 
//  advance_seconds -
164
 
//-------------------------------------------------
165
 
 
166
 
inline void rp5c15_device::advance_seconds()
167
 
{
168
 
        int seconds = read_counter(REGISTER_1_SECOND);
169
 
 
170
 
        seconds++;
171
 
 
172
 
        if (seconds > 59)
173
 
        {
174
 
                seconds = 0;
175
 
 
176
 
                advance_minutes();
177
 
        }
178
 
 
179
 
        write_counter(REGISTER_1_SECOND, seconds);
180
 
}
181
 
 
182
 
 
183
 
//-------------------------------------------------
184
 
//  advance_minutes -
185
 
//-------------------------------------------------
186
 
 
187
 
inline void rp5c15_device::advance_minutes()
188
 
{
189
 
        int minutes = read_counter(REGISTER_1_MINUTE);
190
 
        int hours = read_counter(REGISTER_1_HOUR);
191
 
        int days = read_counter(REGISTER_1_DAY);
192
 
        int month = read_counter(REGISTER_1_MONTH);
193
 
        int year = read_counter(REGISTER_1_YEAR);
194
 
        int day_of_week = m_reg[MODE00][REGISTER_DAY_OF_THE_WEEK];
195
 
 
196
 
        minutes++;
197
 
 
198
 
        if (minutes > 59)
199
 
        {
200
 
                minutes = 0;
201
 
                hours++;
202
 
        }
203
 
 
204
 
        if (hours > 23)
205
 
        {
206
 
                hours = 0;
207
 
                days++;
208
 
                day_of_week++;
209
 
        }
210
 
 
211
 
        if (day_of_week > 6)
212
 
        {
213
 
                day_of_week++;
214
 
        }
215
 
 
216
 
        if (days > DAYS_PER_MONTH[month - 1])
217
 
        {
218
 
                days = 1;
219
 
                month++;
220
 
        }
221
 
 
222
 
        if (month > 12)
223
 
        {
224
 
                month = 1;
225
 
                year++;
226
 
                m_reg[MODE01][REGISTER_LEAP_YEAR]++;
227
 
                m_reg[MODE01][REGISTER_LEAP_YEAR] &= 0x03;
228
 
        }
229
 
 
230
 
        if (year > 99)
231
 
        {
232
 
                year = 0;
233
 
        }
234
 
 
235
 
        write_counter(REGISTER_1_MINUTE, minutes);
236
 
        write_counter(REGISTER_1_HOUR, hours);
237
 
        write_counter(REGISTER_1_DAY, days);
238
 
        write_counter(REGISTER_1_MONTH, month);
239
 
        write_counter(REGISTER_1_YEAR, year);
240
 
        m_reg[MODE00][REGISTER_DAY_OF_THE_WEEK] = day_of_week;
241
 
 
242
 
        check_alarm();
243
 
        set_alarm_line();
244
 
}
245
 
 
246
 
 
247
 
//-------------------------------------------------
248
 
//  adjust_seconds -
249
 
//-------------------------------------------------
250
 
 
251
 
inline void rp5c15_device::adjust_seconds()
252
 
{
253
 
        int seconds = read_counter(REGISTER_1_SECOND);
254
 
 
255
 
        if (seconds < 30)
256
 
        {
257
 
                write_counter(REGISTER_1_SECOND, 0);
258
 
        }
259
 
        else
260
 
        {
261
 
                write_counter(REGISTER_1_SECOND, 0);
262
 
                advance_minutes();
263
 
        }
264
 
}
265
 
 
266
 
 
267
 
//-------------------------------------------------
268
 
//  check_alarm -
269
 
//-------------------------------------------------
270
 
 
271
 
inline void rp5c15_device::check_alarm()
272
 
{
273
 
        bool all_match = true;
274
 
        bool all_zeroes = true;
275
 
 
276
 
        for (int i = REGISTER_1_MINUTE; i < REGISTER_1_MONTH; i++)
277
 
        {
278
 
                if (m_reg[MODE01][i] != 0) all_zeroes = false;
279
 
                if (m_reg[MODE01][i] != m_reg[MODE00][i]) all_match = false;
280
 
        }
281
 
 
282
 
        m_alarm_on = (all_match || (!m_alarm_on && all_zeroes)) ? 0 : 1;
283
 
}
284
 
 
285
 
 
286
 
 
287
 
//**************************************************************************
288
 
//  LIVE DEVICE
289
 
//**************************************************************************
290
 
 
291
 
//-------------------------------------------------
292
 
//  rp5c15_device - constructor
293
 
//-------------------------------------------------
294
 
 
295
 
rp5c15_device::rp5c15_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
296
 
        : device_t(mconfig, RP5C15, "RP5C15", tag, owner, clock),
297
 
          device_rtc_interface(mconfig, *this),
298
 
          m_alarm(1),
299
 
          m_alarm_on(1),
300
 
          m_1hz(1),
301
 
          m_16hz(1),
302
 
          m_clkout(1)
303
 
{
304
 
}
305
 
 
306
 
 
307
 
//-------------------------------------------------
308
 
//  device_config_complete - perform any
309
 
//  operations now that the configuration is
310
 
//  complete
311
 
//-------------------------------------------------
312
 
 
313
 
void rp5c15_device::device_config_complete()
314
 
{
315
 
        // inherit a copy of the static data
316
 
        const rp5c15_interface *intf = reinterpret_cast<const rp5c15_interface *>(static_config());
317
 
        if (intf != NULL)
318
 
                *static_cast<rp5c15_interface *>(this) = *intf;
319
 
 
320
 
        // or initialize to defaults if none provided
321
 
        else
322
 
        {
323
 
                memset(&m_out_alarm_cb, 0, sizeof(m_out_alarm_cb));
324
 
                memset(&m_out_clkout_cb, 0, sizeof(m_out_clkout_cb));
325
 
        }
326
 
}
327
 
 
328
 
 
329
 
//-------------------------------------------------
330
 
//  device_start - device-specific startup
331
 
//-------------------------------------------------
332
 
 
333
 
void rp5c15_device::device_start()
334
 
{
335
 
        // resolve callbacks
336
 
        m_out_alarm_func.resolve(m_out_alarm_cb, *this);
337
 
        m_out_clkout_func.resolve(m_out_clkout_cb, *this);
338
 
 
339
 
        // allocate timers
340
 
        m_clock_timer = timer_alloc(TIMER_CLOCK);
341
 
        m_clock_timer->adjust(attotime::from_hz(clock() / 16384), 0, attotime::from_hz(clock() / 16384));
342
 
 
343
 
        m_16hz_timer = timer_alloc(TIMER_16HZ);
344
 
        m_16hz_timer->adjust(attotime::from_hz(clock() / 1024), 0, attotime::from_hz(clock() / 1024));
345
 
 
346
 
        m_clkout_timer = timer_alloc(TIMER_CLKOUT);
347
 
 
348
 
        // state saving
349
 
        save_item(NAME(m_reg[MODE00]));
350
 
        save_item(NAME(m_reg[MODE01]));
351
 
        save_item(NAME(m_mode));
352
 
        save_item(NAME(m_reset));
353
 
        save_item(NAME(m_alarm));
354
 
        save_item(NAME(m_alarm_on));
355
 
        save_item(NAME(m_1hz));
356
 
        save_item(NAME(m_16hz));
357
 
        save_item(NAME(m_clkout));
358
 
}
359
 
 
360
 
 
361
 
//-------------------------------------------------
362
 
//  device_timer - handler timer events
363
 
//-------------------------------------------------
364
 
 
365
 
void rp5c15_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
366
 
{
367
 
        switch (id)
368
 
        {
369
 
        case TIMER_CLOCK:
370
 
                if (m_1hz && (m_mode & MODE_TIMER_EN))
371
 
                {
372
 
                        advance_seconds();
373
 
                }
374
 
 
375
 
                m_1hz = !m_1hz;
376
 
                set_alarm_line();
377
 
                break;
378
 
 
379
 
        case TIMER_16HZ:
380
 
                m_16hz = !m_16hz;
381
 
                set_alarm_line();
382
 
                break;
383
 
 
384
 
        case TIMER_CLKOUT:
385
 
                m_clkout = !m_clkout;
386
 
                m_out_clkout_func(m_clkout);
387
 
                break;
388
 
        }
389
 
}
390
 
 
391
 
 
392
 
//-------------------------------------------------
393
 
//  rtc_set_time - called to initialize the RTC to
394
 
//  a known state
395
 
//-------------------------------------------------
396
 
 
397
 
void rp5c15_device::rtc_set_time(int year, int month, int day, int day_of_week, int hour, int minute, int second)
398
 
{
399
 
        write_counter(REGISTER_1_YEAR, year);
400
 
        write_counter(REGISTER_1_MONTH, month);
401
 
        write_counter(REGISTER_1_DAY, day);
402
 
        m_reg[MODE00][REGISTER_DAY_OF_THE_WEEK] = day_of_week;
403
 
        write_counter(REGISTER_1_HOUR, hour);
404
 
        write_counter(REGISTER_1_MINUTE, minute);
405
 
        write_counter(REGISTER_1_SECOND, second);
406
 
}
407
 
 
408
 
 
409
 
//-------------------------------------------------
410
 
//  read -
411
 
//-------------------------------------------------
412
 
 
413
 
READ8_MEMBER( rp5c15_device::read )
414
 
{
415
 
        UINT8 data = 0;
416
 
 
417
 
        switch (offset & 0x0f)
418
 
        {
419
 
        case REGISTER_MODE:
420
 
                data = m_mode;
421
 
                break;
422
 
 
423
 
        case REGISTER_TEST:
424
 
        case REGISTER_RESET:
425
 
                // write only
426
 
                break;
427
 
 
428
 
        default:
429
 
                data = m_reg[m_mode & MODE_MASK][offset];
430
 
                break;
431
 
        }
432
 
 
433
 
        if (LOG) logerror("RP5C15 '%s' Register %u Read %02x\n", tag(), offset & 0x0f, data);
434
 
 
435
 
        return data & 0x0f;
436
 
}
437
 
 
438
 
 
439
 
//-------------------------------------------------
440
 
//  write -
441
 
//-------------------------------------------------
442
 
 
443
 
WRITE8_MEMBER( rp5c15_device::write )
444
 
{
445
 
        int mode = m_mode & MODE_MASK;
446
 
 
447
 
        switch (offset & 0x0f)
448
 
        {
449
 
        case REGISTER_MODE:
450
 
                m_mode = data & 0x0f;
451
 
 
452
 
                if (LOG)
453
 
                {
454
 
                        logerror("RP5C15 '%s' Mode %u\n", tag(), data & MODE_MASK);
455
 
                        logerror("RP5C15 '%s' Timer %s\n", tag(), (data & MODE_TIMER_EN) ? "enabled" : "disabled");
456
 
                        logerror("RP5C15 '%s' Alarm %s\n", tag(), (data & MODE_ALARM_EN) ? "enabled" : "disabled");
457
 
                }
458
 
                break;
459
 
 
460
 
        case REGISTER_TEST:
461
 
                if (LOG) logerror("RP5C15 '%s' Test %u not supported!\n", tag(), data);
462
 
                break;
463
 
 
464
 
        case REGISTER_RESET:
465
 
                m_reset = data & 0x0f;
466
 
 
467
 
                if (data & RESET_ALARM)
468
 
                {
469
 
                        int i;
470
 
 
471
 
                        // reset alarm registers
472
 
                        for (i = REGISTER_1_MINUTE; i < REGISTER_1_MONTH; i++)
473
 
                        {
474
 
                                m_reg[MODE01][i] = 0;
475
 
                        }
476
 
                }
477
 
 
478
 
                if (LOG)
479
 
                {
480
 
                        if (data & RESET_ALARM) logerror("RP5C15 '%s' Alarm Reset\n", tag());
481
 
                        if (data & RESET_TIMER) logerror("RP5C15 '%s' Timer Reset not supported!\n", tag());
482
 
                        logerror("RP5C15 '%s' 16Hz Signal %s\n", tag(), (data & RESET_16_HZ) ? "disabled" : "enabled");
483
 
                        logerror("RP5C15 '%s' 1Hz Signal %s\n", tag(), (data & RESET_1_HZ) ? "disabled" : "enabled");
484
 
                }
485
 
                break;
486
 
 
487
 
        default:
488
 
                switch (mode)
489
 
                {
490
 
                case MODE00:
491
 
                        m_reg[mode][offset & 0x0f] = data & REGISTER_WRITE_MASK[mode][offset & 0x0f];
492
 
                        break;
493
 
 
494
 
                case MODE01:
495
 
                        switch (offset & 0x0f)
496
 
                        {
497
 
                        case REGISTER_CLOCK_OUTPUT:
498
 
                                switch (data & 0x07)
499
 
                                {
500
 
                                case CLKOUT_16384_HZ:
501
 
                                        m_clkout_timer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock()));
502
 
                                        break;
503
 
 
504
 
                                case CLKOUT_1024_HZ:
505
 
                                        m_clkout_timer->adjust(attotime::from_hz(clock() / 16), 0, attotime::from_hz(clock() / 16));
506
 
                                        break;
507
 
 
508
 
                                case CLKOUT_128_HZ:
509
 
                                        m_clkout_timer->adjust(attotime::from_hz(clock() / 128), 0, attotime::from_hz(clock() / 128));
510
 
                                        break;
511
 
 
512
 
                                case CLKOUT_16_HZ:
513
 
                                        m_clkout_timer->adjust(attotime::from_hz(clock() / 1024), 0, attotime::from_hz(clock() / 1024));
514
 
                                        break;
515
 
 
516
 
                                case CLKOUT_1_HZ:
517
 
                                        m_clkout_timer->adjust(attotime::from_hz(clock() / 16384), 0, attotime::from_hz(clock() / 16384));
518
 
                                        break;
519
 
 
520
 
                                case CLKOUT_1_DIV_60_HZ:
521
 
                                        // TODO
522
 
                                        break;
523
 
 
524
 
                                case CLKOUT_L:
525
 
                                case CLKOUT_Z:
526
 
                                        m_clkout = 1;
527
 
                                        m_clkout_timer->adjust(attotime::zero, 0);
528
 
                                        break;
529
 
                                }
530
 
 
531
 
                                m_reg[mode][offset & 0x0f] = data & REGISTER_WRITE_MASK[mode][offset & 0x0f];
532
 
                                break;
533
 
 
534
 
                        case REGISTER_ADJUST:
535
 
                                if (BIT(data, 0))
536
 
                                {
537
 
                                        adjust_seconds();
538
 
                                }
539
 
                                m_reg[mode][offset & 0x0f] = data & REGISTER_WRITE_MASK[mode][offset & 0x0f];
540
 
                                break;
541
 
 
542
 
                        default:
543
 
                                m_reg[mode][offset & 0x0f] = data & REGISTER_WRITE_MASK[mode][offset & 0x0f];
544
 
                                break;
545
 
                        }
546
 
                        break;
547
 
                }
548
 
 
549
 
                if (LOG) logerror("RP5C15 '%s' Register %u Write %02x\n", tag(), offset & 0x0f, data);
550
 
                break;
551
 
        }
552
 
}