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

« back to all changes in this revision

Viewing changes to mess/src/emu/machine/6526cia.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
 
    MOS 6526/8520 CIA interface and emulation
4
 
 
5
 
    This function emulates all the functionality MOS6526 or
6
 
    MOS8520 complex interface adapters.
7
 
 
8
 
**********************************************************************/
9
 
 
10
 
#include "emu.h"
11
 
#include "6526cia.h"
12
 
 
13
 
/***************************************************************************
14
 
    CONSTANTS
15
 
***************************************************************************/
16
 
 
17
 
/* CIA registers */
18
 
#define CIA_PRA                 0
19
 
#define CIA_PRB                 1
20
 
#define CIA_DDRA                2
21
 
#define CIA_DDRB                3
22
 
#define CIA_TALO                4
23
 
#define CIA_TAHI                5
24
 
#define CIA_TBLO                6
25
 
#define CIA_TBHI                7
26
 
#define CIA_TOD0                8               /* 6526: 1/10 seconds   8520: bits  0- 7 */
27
 
#define CIA_TOD1                9               /* 6526: seconds        8520: bits  8-15 */
28
 
#define CIA_TOD2                10              /* 6526: minutes        8520: bits 16-23 */
29
 
#define CIA_TOD3                11              /* 6526: hours          8520: N/A */
30
 
#define CIA_SDR                 12
31
 
#define CIA_ICR                 13
32
 
#define CIA_CRA                 14
33
 
#define CIA_CRB                 15
34
 
 
35
 
#define CIA_CRA_START   0x01
36
 
#define CIA_CRA_PBON    0x02
37
 
#define CIA_CRA_OUTMODE 0x04
38
 
#define CIA_CRA_RUNMODE 0x08
39
 
#define CIA_CRA_LOAD    0x10
40
 
#define CIA_CRA_INMODE  0x20
41
 
#define CIA_CRA_SPMODE  0x40
42
 
#define CIA_CRA_TODIN   0x80
43
 
 
44
 
//**************************************************************************
45
 
//  DEVICE CONFIGURATION
46
 
//**************************************************************************
47
 
 
48
 
 
49
 
//**************************************************************************
50
 
//  LIVE DEVICE
51
 
//**************************************************************************
52
 
 
53
 
// device type definition
54
 
const device_type MOS6526R1 = &device_creator<mos6526r1_device>;
55
 
const device_type MOS6526R2 = &device_creator<mos6526r2_device>;
56
 
const device_type MOS8520 = &device_creator<mos8520_device>;
57
 
 
58
 
//-------------------------------------------------
59
 
//  mos6526_device - constructor
60
 
//-------------------------------------------------
61
 
 
62
 
mos6526_device::mos6526_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock)
63
 
    : device_t(mconfig, type, name, tag, owner, clock)
64
 
{
65
 
}
66
 
 
67
 
mos6526r1_device::mos6526r1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
68
 
    : mos6526_device(mconfig, MOS6526R1, "MOS6526r1", tag, owner, clock) { }
69
 
 
70
 
mos6526r2_device::mos6526r2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
71
 
    : mos6526_device(mconfig, MOS6526R2, "MOS6526r2", tag, owner, clock) { }
72
 
 
73
 
mos8520_device::mos8520_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
74
 
    : mos6526_device(mconfig, MOS8520, "MOS8520", tag, owner, clock) { }
75
 
 
76
 
 
77
 
//-------------------------------------------------
78
 
//  device_reset - device-specific reset
79
 
//-------------------------------------------------
80
 
 
81
 
void mos6526_device::device_reset()
82
 
{
83
 
        /* clear things out */
84
 
        m_port[0].m_latch = 0x00;
85
 
        m_port[0].m_in = 0x00;
86
 
        m_port[0].m_out = 0x00;
87
 
        m_port[0].m_mask_value = 0xff;
88
 
        m_port[1].m_latch = 0x00;
89
 
        m_port[1].m_in = 0x00;
90
 
        m_port[1].m_out = 0x00;
91
 
        m_port[1].m_mask_value = 0xff;
92
 
        m_tod = 0;
93
 
        m_tod_latch = 0;
94
 
        m_alarm = 0;
95
 
        m_icr = 0x00;
96
 
        m_ics = 0x00;
97
 
        m_irq = 0;
98
 
        m_shift = 0;
99
 
        m_loaded = 0;
100
 
        m_cnt = 1;
101
 
        m_sp = 0;
102
 
 
103
 
        /* initialize data direction registers */
104
 
        m_port[0].m_ddr = !strcmp(tag(), "cia_0") ? 0x03 : 0xff;
105
 
        m_port[1].m_ddr = !strcmp(tag(), "cia_0") ? 0x00 : 0xff;
106
 
 
107
 
        /* TOD running by default */
108
 
        m_tod_running = TRUE;
109
 
 
110
 
        /* initialize timers */
111
 
        for(int t = 0; t < 2; t++)
112
 
        {
113
 
                cia_timer *timer = &m_timer[t];
114
 
                timer->m_cia = this;
115
 
                timer->m_clock = clock();
116
 
                timer->m_latch = 0xffff;
117
 
                timer->m_count = 0x0000;
118
 
                timer->m_mode = 0x00;
119
 
        }
120
 
}
121
 
 
122
 
 
123
 
//-------------------------------------------------
124
 
//  device_config_complete - perform any
125
 
//  operations now that the configuration is
126
 
//  complete
127
 
//-------------------------------------------------
128
 
 
129
 
void mos6526_device::device_config_complete()
130
 
{
131
 
        // inherit a copy of the static data
132
 
        const mos6526_interface *intf = reinterpret_cast<const mos6526_interface *>(static_config());
133
 
        if (intf != NULL)
134
 
                *static_cast<mos6526_interface *>(this) = *intf;
135
 
 
136
 
        // or initialize to defaults if none provided
137
 
        else
138
 
        {
139
 
                m_tod_clock = 0;
140
 
        memset(&m_out_irq_cb, 0, sizeof(m_out_irq_cb));
141
 
        memset(&m_out_pc_cb, 0, sizeof(m_out_pc_cb));
142
 
        memset(&m_out_cnt_cb, 0, sizeof(m_out_cnt_cb));
143
 
        memset(&m_out_sp_cb, 0, sizeof(m_out_sp_cb));
144
 
        memset(&m_in_pa_cb, 0, sizeof(m_in_pa_cb));
145
 
        memset(&m_out_pa_cb, 0, sizeof(m_out_pa_cb));
146
 
        memset(&m_in_pb_cb, 0, sizeof(m_in_pb_cb));
147
 
        memset(&m_out_pb_cb, 0, sizeof(m_out_pb_cb));
148
 
        }
149
 
}
150
 
 
151
 
 
152
 
//-------------------------------------------------
153
 
//  device_start - device-specific startup
154
 
//-------------------------------------------------
155
 
 
156
 
void mos6526_device::device_start()
157
 
{
158
 
        /* clear out CIA structure, and copy the interface */
159
 
        m_out_irq_func.resolve(m_out_irq_cb, *this);
160
 
        m_out_pc_func.resolve(m_out_pc_cb, *this);
161
 
        m_out_cnt_func.resolve(m_out_cnt_cb, *this);
162
 
        m_out_sp_func.resolve(m_out_sp_cb, *this);
163
 
        m_flag = 1;
164
 
 
165
 
        /* setup ports */
166
 
        m_port[0].m_read.resolve(m_in_pa_cb, *this);
167
 
        m_port[0].m_write.resolve(m_out_pa_cb, *this);
168
 
        m_port[1].m_read.resolve(m_in_pb_cb, *this);
169
 
        m_port[1].m_write.resolve(m_out_pb_cb, *this);
170
 
 
171
 
        for (int p = 0; p < (sizeof(m_port) / sizeof(m_port[0])); p++)
172
 
        {
173
 
                m_port[p].m_mask_value = 0xff;
174
 
        }
175
 
 
176
 
        /* setup timers */
177
 
        for (int t = 0; t < (sizeof(m_timer) / sizeof(m_timer[0])); t++)
178
 
        {
179
 
                cia_timer *timer = &m_timer[t];
180
 
                timer->m_timer = machine().scheduler().timer_alloc(FUNC(timer_proc), (void*)this);
181
 
                timer->m_cia = this;
182
 
                timer->m_irq = 0x01 << t;
183
 
        }
184
 
 
185
 
        /* setup TOD timer, if appropriate */
186
 
        if (m_tod_clock != 0)
187
 
        {
188
 
                machine().scheduler().timer_pulse(attotime::from_hz(m_tod_clock), FUNC(clock_tod_callback), 0, (void *)this);
189
 
        }
190
 
 
191
 
        /* state save support */
192
 
        save_item(NAME(m_port[0].m_ddr));
193
 
        save_item(NAME(m_port[0].m_latch));
194
 
        save_item(NAME(m_port[0].m_in));
195
 
        save_item(NAME(m_port[0].m_out));
196
 
        save_item(NAME(m_port[0].m_mask_value));
197
 
        save_item(NAME(m_port[1].m_ddr));
198
 
        save_item(NAME(m_port[1].m_latch));
199
 
        save_item(NAME(m_port[1].m_in));
200
 
        save_item(NAME(m_port[1].m_out));
201
 
        save_item(NAME(m_port[1].m_mask_value));
202
 
        save_item(NAME(m_timer[0].m_latch));
203
 
        save_item(NAME(m_timer[0].m_count));
204
 
        save_item(NAME(m_timer[0].m_mode));
205
 
        save_item(NAME(m_timer[0].m_irq));
206
 
        save_item(NAME(m_timer[1].m_latch));
207
 
        save_item(NAME(m_timer[1].m_count));
208
 
        save_item(NAME(m_timer[1].m_mode));
209
 
        save_item(NAME(m_timer[1].m_irq));
210
 
        save_item(NAME(m_tod));
211
 
        save_item(NAME(m_tod_latch));
212
 
        save_item(NAME(m_tod_latched));
213
 
        save_item(NAME(m_tod_running));
214
 
        save_item(NAME(m_alarm));
215
 
        save_item(NAME(m_icr));
216
 
        save_item(NAME(m_ics));
217
 
        save_item(NAME(m_irq));
218
 
        save_item(NAME(m_flag));
219
 
        save_item(NAME(m_loaded));
220
 
        save_item(NAME(m_sdr));
221
 
        save_item(NAME(m_sp));
222
 
        save_item(NAME(m_cnt));
223
 
        save_item(NAME(m_shift));
224
 
        save_item(NAME(m_serial));
225
 
}
226
 
 
227
 
 
228
 
/*-------------------------------------------------
229
 
    set_port_mask_value
230
 
-------------------------------------------------*/
231
 
 
232
 
void mos6526_device::set_port_mask_value(int port, int data)
233
 
{
234
 
        m_port[port].m_mask_value = data;
235
 
}
236
 
 
237
 
/*-------------------------------------------------
238
 
    update_pc - pulse /pc output
239
 
-------------------------------------------------*/
240
 
 
241
 
void mos6526_device::update_pc()
242
 
{
243
 
        /* this should really be one cycle long */
244
 
        m_out_pc_func(0);
245
 
        m_out_pc_func(1);
246
 
}
247
 
 
248
 
/*-------------------------------------------------
249
 
    update_interrupts
250
 
-------------------------------------------------*/
251
 
 
252
 
void mos6526_device::update_interrupts()
253
 
{
254
 
        UINT8 new_irq;
255
 
 
256
 
        /* always update the high bit of ICS */
257
 
        if (m_ics & 0x7f)
258
 
        {
259
 
                m_ics |= 0x80;
260
 
        }
261
 
        else
262
 
        {
263
 
                m_ics &= ~0x80;
264
 
        }
265
 
 
266
 
        /* based on what is enabled, set/clear the IRQ via the custom chip */
267
 
        new_irq = (m_ics & m_icr) ? 1 : 0;
268
 
        if (m_irq != new_irq)
269
 
        {
270
 
                m_irq = new_irq;
271
 
                m_out_irq_func(m_irq);
272
 
        }
273
 
}
274
 
 
275
 
 
276
 
/*-------------------------------------------------
277
 
    timer_bump
278
 
-------------------------------------------------*/
279
 
 
280
 
void mos6526_device::timer_bump(int timer)
281
 
{
282
 
        m_timer[timer].update(timer, -1);
283
 
 
284
 
        if (m_timer[timer].m_count == 0x00)
285
 
        {
286
 
                timer_underflow(timer);
287
 
        }
288
 
        else
289
 
        {
290
 
                m_timer[timer].update(timer, m_timer[timer].m_count - 1);
291
 
        }
292
 
}
293
 
 
294
 
/*-------------------------------------------------
295
 
    cia_timer_underflow
296
 
-------------------------------------------------*/
297
 
 
298
 
void mos6526_device::timer_underflow(int timer)
299
 
{
300
 
        assert((timer == 0) || (timer == 1));
301
 
 
302
 
        /* set the status and update interrupts */
303
 
        m_ics |= m_timer[timer].m_irq;
304
 
        update_interrupts();
305
 
 
306
 
        /* if one-shot mode, turn it off */
307
 
        if (m_timer[timer].m_mode & 0x08)
308
 
        {
309
 
                m_timer[timer].m_mode &= 0xfe;
310
 
        }
311
 
 
312
 
        /* reload the timer */
313
 
        m_timer[timer].update(timer, m_timer[timer].m_latch);
314
 
 
315
 
        /* timer A has some interesting properties */
316
 
        if (timer == 0)
317
 
        {
318
 
                /* such as cascading to timer B */
319
 
                if ((m_timer[1].m_mode & 0x41) == 0x41)
320
 
                {
321
 
                        if (m_cnt || !(m_timer[1].m_mode & 0x20))
322
 
                        {
323
 
                                timer_bump(1);
324
 
                        }
325
 
                }
326
 
 
327
 
                /* also the serial line */
328
 
                if ((m_timer[timer].m_irq == 0x01) && (m_timer[timer].m_mode & CIA_CRA_SPMODE))
329
 
                {
330
 
                        if (m_loaded || m_shift)
331
 
                        {
332
 
                                /* falling edge */
333
 
                                if (m_cnt)
334
 
                                {
335
 
                                        if (m_shift == 0)
336
 
                                        {
337
 
                                                /* load shift register */
338
 
                                                m_loaded = 0;
339
 
                                                m_serial = m_sdr;
340
 
                                        }
341
 
 
342
 
                                        /* transmit MSB */
343
 
                                        m_sp = BIT(m_serial, 7);
344
 
                                        m_out_sp_func(m_sp);
345
 
 
346
 
                                        /* toggle CNT */
347
 
                                        m_cnt = !m_cnt;
348
 
                                        m_out_cnt_func(m_cnt);
349
 
 
350
 
                                        /* shift data */
351
 
                                        m_serial <<= 1;
352
 
                                        m_shift++;
353
 
 
354
 
                                        if (m_shift == 8)
355
 
                                        {
356
 
                                                /* signal interrupt */
357
 
                                                m_ics |= 0x08;
358
 
                                                update_interrupts();
359
 
                                        }
360
 
                                }
361
 
                                else
362
 
                                {
363
 
                                        /* toggle CNT */
364
 
                                        m_cnt = !m_cnt;
365
 
                                        m_out_cnt_func(m_cnt);
366
 
 
367
 
                                        if (m_shift == 8)
368
 
                                        {
369
 
                                                m_shift = 0;
370
 
                                        }
371
 
                                }
372
 
                        }
373
 
                }
374
 
        }
375
 
}
376
 
 
377
 
/*-------------------------------------------------
378
 
    TIMER_CALLBACK( cia_timer_proc )
379
 
-------------------------------------------------*/
380
 
 
381
 
TIMER_CALLBACK( mos6526_device::timer_proc )
382
 
{
383
 
    mos6526_device *cia = reinterpret_cast<mos6526_device *>(ptr);
384
 
 
385
 
        cia->timer_underflow(param);
386
 
}
387
 
 
388
 
/*-------------------------------------------------
389
 
    bcd_increment
390
 
-------------------------------------------------*/
391
 
 
392
 
static UINT8 bcd_increment(UINT8 value)
393
 
{
394
 
        value++;
395
 
        if ((value & 0x0f) >= 0x0a)
396
 
                value += 0x10 - 0x0a;
397
 
        return value;
398
 
}
399
 
 
400
 
/*-------------------------------------------------
401
 
    cia6526_increment
402
 
-------------------------------------------------*/
403
 
 
404
 
void mos6526_device::increment()
405
 
{
406
 
        /* break down TOD value into components */
407
 
        UINT8 subsecond = (UINT8) (m_tod >>  0);
408
 
        UINT8 second    = (UINT8) (m_tod >>  8);
409
 
        UINT8 minute    = (UINT8) (m_tod >> 16);
410
 
        UINT8 hour              = (UINT8) (m_tod >> 24);
411
 
 
412
 
        subsecond = bcd_increment(subsecond);
413
 
        if (subsecond >= 0x10)
414
 
        {
415
 
                subsecond = 0x00;
416
 
                second = bcd_increment(second);
417
 
                if (second >= ((m_timer[0].m_mode & 0x80) ? 0x50 : 0x60))
418
 
                {
419
 
                        second = 0x00;
420
 
                        minute = bcd_increment(minute);
421
 
                        if (minute >= 0x60)
422
 
                        {
423
 
                                minute = 0x00;
424
 
                                if (hour == 0x91)
425
 
                                        hour = 0x00;
426
 
                                else if (hour == 0x89)
427
 
                                        hour = 0x90;
428
 
                                else if (hour == 0x11)
429
 
                                        hour = 0x80;
430
 
                                else if (hour == 0x09)
431
 
                                        hour = 0x10;
432
 
                                else
433
 
                                        hour++;
434
 
                        }
435
 
                }
436
 
        }
437
 
 
438
 
        /* update the TOD with new value */
439
 
        m_tod = (((UINT32) subsecond)   <<  0)
440
 
                  | (((UINT32) second)          <<  8)
441
 
                  | (((UINT32) minute)          << 16)
442
 
                  | (((UINT32) hour)            << 24);
443
 
}
444
 
 
445
 
/*-------------------------------------------------
446
 
    cia_clock_tod - Update TOD on CIA A
447
 
-------------------------------------------------*/
448
 
 
449
 
void mos6526_device::clock_tod()
450
 
{
451
 
        if (m_tod_running)
452
 
        {
453
 
                if ((type() == MOS6526R1) || (type() == MOS6526R2))
454
 
                {
455
 
                        /* The 6526 split the value into hours, minutes, seconds and
456
 
             * subseconds */
457
 
                        increment();
458
 
                }
459
 
                else if (type() == MOS8520)
460
 
                {
461
 
                        /* the 8520 has a straight 24-bit counter */
462
 
                        m_tod++;
463
 
                        m_tod &= 0xffffff;
464
 
                }
465
 
 
466
 
                if (m_tod == m_alarm)
467
 
                {
468
 
                        m_ics |= 0x04;
469
 
                        update_interrupts();
470
 
                }
471
 
        }
472
 
}
473
 
 
474
 
 
475
 
/*-------------------------------------------------
476
 
    clock_tod_callback
477
 
-------------------------------------------------*/
478
 
 
479
 
TIMER_CALLBACK( mos6526_device::clock_tod_callback )
480
 
{
481
 
    mos6526_device *cia = reinterpret_cast<mos6526_device *>(ptr);
482
 
        cia->clock_tod();
483
 
}
484
 
 
485
 
 
486
 
/*-------------------------------------------------
487
 
    cnt_w
488
 
-------------------------------------------------*/
489
 
 
490
 
void mos6526_device::cnt_w(UINT8 state)
491
 
{
492
 
        /* is this a rising edge? */
493
 
        if (!m_cnt && state)
494
 
        {
495
 
                if (m_timer[0].m_mode & CIA_CRA_START)
496
 
                {
497
 
                        /* does timer #0 bump on CNT? */
498
 
                        if (m_timer[0].m_mode & CIA_CRA_INMODE)
499
 
                        {
500
 
                                timer_bump(0);
501
 
                        }
502
 
                }
503
 
 
504
 
                /* if the serial port is set to input, the CNT will shift the port */
505
 
                if (!(m_timer[0].m_mode & CIA_CRA_SPMODE))
506
 
                {
507
 
                        m_serial <<= 1;
508
 
                        m_shift++;
509
 
 
510
 
                        if (m_sp)
511
 
                        {
512
 
                                m_serial |= 0x01;
513
 
                        }
514
 
 
515
 
                        if (m_shift == 8)
516
 
                        {
517
 
                                m_sdr = m_serial;
518
 
                                m_serial = 0;
519
 
                                m_shift = 0;
520
 
                                m_ics |= 0x08;
521
 
                                update_interrupts();
522
 
                        }
523
 
                }
524
 
 
525
 
                /* does timer #1 bump on CNT? */
526
 
                if ((m_timer[1].m_mode & 0x61) == 0x21)
527
 
                {
528
 
                        timer_bump(1);
529
 
                }
530
 
        }
531
 
 
532
 
        m_cnt = state;
533
 
}
534
 
 
535
 
void mos6526_device::flag_w(UINT8 state)
536
 
{
537
 
        /* falling edge */
538
 
        if (m_flag && !state)
539
 
        {
540
 
                m_ics |= 0x10;
541
 
                update_interrupts();
542
 
        }
543
 
 
544
 
        m_flag = state;
545
 
}
546
 
 
547
 
/*-------------------------------------------------
548
 
    reg_r
549
 
-------------------------------------------------*/
550
 
 
551
 
UINT8 mos6526_device::reg_r(UINT8 offset)
552
 
{
553
 
        cia_timer *timer;
554
 
        cia_port *port;
555
 
        UINT8 data = 0x00;
556
 
 
557
 
        offset &= 0x0F;
558
 
 
559
 
        switch(offset)
560
 
        {
561
 
                /* port A/B data */
562
 
                case CIA_PRA:
563
 
                case CIA_PRB:
564
 
                        port = &m_port[offset & 1];
565
 
                        data = port->m_read(0);
566
 
                        data = ((data & ~port->m_ddr) | (port->m_latch & port->m_ddr)) & port->m_mask_value;
567
 
 
568
 
                        port->m_in = data;
569
 
 
570
 
                        if (offset == CIA_PRB)
571
 
                        {
572
 
                                /* timer #0 can change PB6 */
573
 
                                if (m_timer[0].m_mode & 0x02)
574
 
                                {
575
 
                                        m_timer[0].update(0, -1);
576
 
                                        if (m_timer[0].m_count != 0)
577
 
                                        {
578
 
                                                data |= 0x40;
579
 
                                        }
580
 
                                        else
581
 
                                        {
582
 
                                                data &= ~0x40;
583
 
                                        }
584
 
                                }
585
 
 
586
 
                                /* timer #1 can change PB7 */
587
 
                                if (m_timer[1].m_mode & 0x02)
588
 
                                {
589
 
                                        m_timer[1].update(1, -1);
590
 
                                        if (m_timer[1].m_count != 0)
591
 
                                        {
592
 
                                                data |= 0x80;
593
 
                                        }
594
 
                                        else
595
 
                                        {
596
 
                                                data &= ~0x80;
597
 
                                        }
598
 
                                }
599
 
 
600
 
                                /* pulse /PC following the read */
601
 
                                update_pc();
602
 
                        }
603
 
                        break;
604
 
 
605
 
                /* port A/B direction */
606
 
                case CIA_DDRA:
607
 
                case CIA_DDRB:
608
 
                        port = &m_port[offset & 1];
609
 
                        data = port->m_ddr;
610
 
                        break;
611
 
 
612
 
                /* timer A/B low byte */
613
 
                case CIA_TALO:
614
 
                case CIA_TBLO:
615
 
                        timer = &m_timer[(offset >> 1) & 1];
616
 
                        data = timer->get_count() >> 0;
617
 
                        break;
618
 
 
619
 
                /* timer A/B high byte */
620
 
                case CIA_TAHI:
621
 
                case CIA_TBHI:
622
 
                        timer = &m_timer[(offset >> 1) & 1];
623
 
                        data = timer->get_count() >> 8;
624
 
                        break;
625
 
 
626
 
                /* TOD counter */
627
 
                case CIA_TOD0:
628
 
                case CIA_TOD1:
629
 
                case CIA_TOD2:
630
 
                case CIA_TOD3:
631
 
                        if (type() == MOS8520)
632
 
                        {
633
 
                                if (offset == CIA_TOD2)
634
 
                                {
635
 
                                        m_tod_latch = m_tod;
636
 
                                        m_tod_latched = TRUE;
637
 
                                }
638
 
                        }
639
 
                        else
640
 
                        {
641
 
                                if (offset == CIA_TOD3)
642
 
                                {
643
 
                                        m_tod_latch = m_tod;
644
 
                                        m_tod_latched = TRUE;
645
 
                                }
646
 
                        }
647
 
                        if (offset == CIA_TOD0)
648
 
                        {
649
 
                                m_tod_latched = FALSE;
650
 
                        }
651
 
 
652
 
                        if (m_tod_latched)
653
 
                        {
654
 
                                data = m_tod_latch >> ((offset - CIA_TOD0) * 8);
655
 
                        }
656
 
                        else
657
 
                        {
658
 
                                data = m_tod >> ((offset - CIA_TOD0) * 8);
659
 
                        }
660
 
                        break;
661
 
 
662
 
                /* serial data ready */
663
 
                case CIA_SDR:
664
 
                        data = m_sdr;
665
 
                        break;
666
 
 
667
 
                /* interrupt status/clear */
668
 
                case CIA_ICR:
669
 
                        data = m_ics;
670
 
                        m_ics = 0; /* clear on read */
671
 
                        update_interrupts();
672
 
                        break;
673
 
 
674
 
                /* timer A/B mode */
675
 
                case CIA_CRA:
676
 
                case CIA_CRB:
677
 
                        timer = &m_timer[offset & 1];
678
 
                        data = timer->m_mode;
679
 
                        break;
680
 
        }
681
 
 
682
 
        return data;
683
 
}
684
 
 
685
 
/*-------------------------------------------------
686
 
    reg_w
687
 
-------------------------------------------------*/
688
 
 
689
 
void mos6526_device::reg_w(UINT8 offset, UINT8 data)
690
 
{
691
 
        cia_timer *timer;
692
 
        cia_port *port;
693
 
        int shift;
694
 
 
695
 
        offset &= 0x0F;
696
 
 
697
 
        switch(offset)
698
 
        {
699
 
                /* port A/B data */
700
 
                case CIA_PRA:
701
 
                case CIA_PRB:
702
 
                        port = &m_port[offset & 1];
703
 
                        port->m_latch = data;
704
 
                        port->m_out = (data & port->m_ddr) | (port->m_in & ~port->m_ddr);
705
 
                        port->m_write(0, port->m_out);
706
 
 
707
 
                        /* pulse /PC following the write */
708
 
                        if (offset == CIA_PRB)
709
 
                        {
710
 
                                update_pc();
711
 
                        }
712
 
 
713
 
                        break;
714
 
 
715
 
                /* port A/B direction */
716
 
                case CIA_DDRA:
717
 
                case CIA_DDRB:
718
 
                        port = &m_port[offset & 1];
719
 
                        port->m_ddr = data;
720
 
                        break;
721
 
 
722
 
                /* timer A/B latch low */
723
 
                case CIA_TALO:
724
 
                case CIA_TBLO:
725
 
                        timer = &m_timer[(offset >> 1) & 1];
726
 
                        timer->m_latch = (timer->m_latch & 0xff00) | (data << 0);
727
 
                        break;
728
 
 
729
 
                /* timer A latch high */
730
 
                case CIA_TAHI:
731
 
                case CIA_TBHI:
732
 
                        timer = &m_timer[(offset >> 1) & 1];
733
 
                        timer->m_latch = (timer->m_latch & 0x00ff) | (data << 8);
734
 
 
735
 
                        /* if the timer is one-shot, then force a start on it */
736
 
                        if (timer->m_mode & 0x08)
737
 
                        {
738
 
                                timer->m_mode |= 1;
739
 
                                timer->update((offset >> 1) & 1, timer->m_latch);
740
 
                        }
741
 
                        else
742
 
                        {
743
 
                                /* if the timer is off, update the count */
744
 
                                if (!(timer->m_mode & 0x01))
745
 
                                {
746
 
                                        timer->update((offset >> 1) & 1, timer->m_latch);
747
 
                                }
748
 
                        }
749
 
                        break;
750
 
 
751
 
                /* time of day latches */
752
 
                case CIA_TOD0:
753
 
                case CIA_TOD1:
754
 
                case CIA_TOD2:
755
 
                case CIA_TOD3:
756
 
                        shift = 8 * ((offset - CIA_TOD0));
757
 
 
758
 
                        /* alarm setting mode? */
759
 
                        if (m_timer[1].m_mode & 0x80)
760
 
                        {
761
 
                                m_alarm = (m_alarm & ~(0xff << shift)) | (data << shift);
762
 
                        }
763
 
                        /* counter setting mode */
764
 
                        else
765
 
                        {
766
 
                                m_tod = (m_tod & ~(0xff << shift)) | (data << shift);
767
 
                        }
768
 
 
769
 
                        if (type() == MOS8520)
770
 
                        {
771
 
                                if (offset == CIA_TOD2)
772
 
                                {
773
 
                                        m_tod_running = FALSE;
774
 
                                }
775
 
                        }
776
 
                        else
777
 
                        {
778
 
                                if (offset == CIA_TOD3)
779
 
                                {
780
 
                                        m_tod_running = FALSE;
781
 
                                }
782
 
                        }
783
 
                        if (offset == CIA_TOD0)
784
 
                        {
785
 
                                m_tod_running = TRUE;
786
 
                        }
787
 
                        break;
788
 
 
789
 
                /* serial data ready */
790
 
                case CIA_SDR:
791
 
                        m_sdr = data;
792
 
                        if (m_timer[0].m_mode & 0x40)
793
 
                        {
794
 
                                m_loaded = 1;
795
 
                        }
796
 
                        break;
797
 
 
798
 
                /* interrupt control register */
799
 
                case CIA_ICR:
800
 
                        if (data & 0x80)
801
 
                        {
802
 
                                m_icr |= data & 0x7f;
803
 
                        }
804
 
                        else
805
 
                        {
806
 
                                m_icr &= ~(data & 0x7f);
807
 
                        }
808
 
                        update_interrupts();
809
 
                        break;
810
 
 
811
 
                /* timer A/B modes */
812
 
                case CIA_CRA:
813
 
                case CIA_CRB:
814
 
                        timer = &m_timer[offset & 1];
815
 
                        timer->m_mode = data & 0xef;
816
 
 
817
 
                        /* force load? */
818
 
                        if (data & 0x10)
819
 
                        {
820
 
                                timer->update(offset & 1, timer->m_latch);
821
 
                        }
822
 
                        else
823
 
                        {
824
 
                                timer->update(offset & 1, -1);
825
 
                        }
826
 
                        break;
827
 
        }
828
 
}
829
 
 
830
 
/*-------------------------------------------------
831
 
    is_timer_active
832
 
-------------------------------------------------*/
833
 
 
834
 
static int is_timer_active(emu_timer *timer)
835
 
{
836
 
        attotime t = timer->expire();
837
 
        return (t != attotime::never);
838
 
}
839
 
 
840
 
/*-------------------------------------------------
841
 
    update - updates the count and emu_timer for
842
 
    a given CIA timer
843
 
-------------------------------------------------*/
844
 
 
845
 
void mos6526_device::cia_timer::update(int which, INT32 new_count)
846
 
{
847
 
        /* sanity check arguments */
848
 
        assert((new_count >= -1) && (new_count <= 0xffff));
849
 
 
850
 
        /* update the timer count, if necessary */
851
 
        if ((new_count == -1) && is_timer_active(m_timer))
852
 
        {
853
 
                UINT16 current_count = (m_timer->elapsed() * m_clock).as_double();
854
 
                m_count = m_count - MIN(m_count, current_count);
855
 
        }
856
 
 
857
 
        /* set the timer if we are instructed to */
858
 
        if (new_count != -1)
859
 
        {
860
 
                m_count = new_count;
861
 
        }
862
 
 
863
 
        /* now update the MAME timer */
864
 
        if ((m_mode & 0x01) && ((m_mode & (which ? 0x60 : 0x20)) == 0x00))
865
 
        {
866
 
                /* timer is on and is connected to clock */
867
 
                attotime period = attotime::from_hz(m_clock) * (m_count ? m_count : 0x10000);
868
 
                m_timer->adjust(period, which);
869
 
        }
870
 
        else
871
 
        {
872
 
                /* timer is off or not connected to clock */
873
 
                m_timer->adjust(attotime::never, which);
874
 
        }
875
 
}
876
 
 
877
 
/*-------------------------------------------------
878
 
    get_count - get the count for a given CIA
879
 
    timer
880
 
-------------------------------------------------*/
881
 
 
882
 
UINT16 mos6526_device::cia_timer::get_count()
883
 
{
884
 
        UINT16 count;
885
 
 
886
 
        if (is_timer_active(m_timer))
887
 
        {
888
 
                UINT16 current_count = (m_timer->elapsed() * m_clock).as_double();
889
 
                count = m_count - MIN(m_count, current_count);
890
 
        }
891
 
        else
892
 
        {
893
 
                count = m_count;
894
 
        }
895
 
 
896
 
        return count;
897
 
}
898
 
 
899
 
/***************************************************************************
900
 
    TRAMPOLINES
901
 
***************************************************************************/
902
 
 
903
 
void cia_set_port_mask_value(device_t *device, int port, int data) { downcast<mos6526_device *>(device)->set_port_mask_value(port, data); }
904
 
 
905
 
READ8_DEVICE_HANDLER( mos6526_r ) { return downcast<mos6526_device *>(device)->reg_r(offset); }
906
 
WRITE8_DEVICE_HANDLER( mos6526_w ) { downcast<mos6526_device *>(device)->reg_w(offset, data); }
907
 
 
908
 
READ8_DEVICE_HANDLER( mos6526_pa_r ) { return downcast<mos6526_device *>(device)->pa_r(offset); }
909
 
READ8_DEVICE_HANDLER( mos6526_pb_r ) { return downcast<mos6526_device *>(device)->pb_r(offset); }
910
 
 
911
 
READ_LINE_DEVICE_HANDLER( mos6526_irq_r ) { return downcast<mos6526_device *>(device)->irq_r(); }
912
 
 
913
 
WRITE_LINE_DEVICE_HANDLER( mos6526_tod_w ) { downcast<mos6526_device *>(device)->tod_w(state); }
914
 
 
915
 
READ_LINE_DEVICE_HANDLER( mos6526_cnt_r ) { return downcast<mos6526_device *>(device)->cnt_r(); }
916
 
WRITE_LINE_DEVICE_HANDLER( mos6526_cnt_w ) { downcast<mos6526_device *>(device)->cnt_w(state); }
917
 
 
918
 
READ_LINE_DEVICE_HANDLER( mos6526_sp_r ) { return downcast<mos6526_device *>(device)->sp_r(); }
919
 
WRITE_LINE_DEVICE_HANDLER( mos6526_sp_w ) { downcast<mos6526_device *>(device)->sp_w(state); }
920
 
 
921
 
WRITE_LINE_DEVICE_HANDLER( mos6526_flag_w ) { downcast<mos6526_device *>(device)->flag_w(state); }