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

« back to all changes in this revision

Viewing changes to mess/src/emu/machine/68681.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
 
    68681 DUART
3
 
 
4
 
    Written by Mariusz Wojcieszek
5
 
    Updated by Jonathan Gevaryahu AKA Lord Nightmare
6
 
*/
7
 
 
8
 
#include "emu.h"
9
 
#include "68681.h"
10
 
 
11
 
#define VERBOSE 0
12
 
#define LOG(x)  do { if (VERBOSE) logerror x; } while (0)
13
 
 
14
 
static const char *const duart68681_reg_read_names[0x10] =
15
 
{
16
 
        "MRA", "SRA", "BRG Test", "RHRA", "IPCR", "ISR", "CTU", "CTL", "MRB", "SRB", "1X/16X Test", "RHRB", "IVR", "Input Ports", "Start Counter", "Stop Counter"
17
 
};
18
 
 
19
 
static const char *const duart68681_reg_write_names[0x10] =
20
 
{
21
 
        "MRA", "CSRA", "CRA", "THRA", "ACR", "IMR", "CRUR", "CTLR", "MRB", "CSRB", "CRB", "THRB", "IVR", "OPCR", "Set OP Bits", "Reset OP Bits"
22
 
};
23
 
 
24
 
#define INT_INPUT_PORT_CHANGE           0x80
25
 
#define INT_DELTA_BREAK_B                       0x40
26
 
#define INT_RXRDY_FFULLB                        0x20
27
 
#define INT_TXRDYB                                      0x10
28
 
#define INT_COUNTER_READY                       0x08
29
 
#define INT_DELTA_BREAK_A                       0x04
30
 
#define INT_RXRDY_FFULLA                        0x02
31
 
#define INT_TXRDYA                                      0x01
32
 
 
33
 
#define STATUS_RECEIVED_BREAK           0x80
34
 
#define STATUS_FRAMING_ERROR            0x40
35
 
#define STATUS_PARITY_ERROR                     0x20
36
 
#define STATUS_OVERRUN_ERROR            0x10
37
 
#define STATUS_TRANSMITTER_EMPTY        0x08
38
 
#define STATUS_TRANSMITTER_READY        0x04
39
 
#define STATUS_FIFO_FULL                        0x02
40
 
#define STATUS_RECEIVER_READY           0x01
41
 
 
42
 
#define MODE_RX_INT_SELECT_BIT          0x40
43
 
 
44
 
#define RX_FIFO_SIZE                            3
45
 
 
46
 
typedef struct
47
 
{
48
 
        /* Registers */
49
 
        UINT8 CR;  /* Command register */
50
 
        UINT8 CSR; /* Clock select register */
51
 
        UINT8 MR1; /* Mode register 1 */
52
 
        UINT8 MR2; /* Mode register 2 */
53
 
        UINT8 MR_ptr; /* Mode register pointer */
54
 
        UINT8 SR;  /* Status register */
55
 
 
56
 
        /* State */
57
 
        int   baud_rate;
58
 
 
59
 
        /* Receiver */
60
 
        UINT8 rx_enabled;
61
 
        UINT8 rx_fifo[RX_FIFO_SIZE];
62
 
        int   rx_fifo_read_ptr;
63
 
        int   rx_fifo_write_ptr;
64
 
        int   rx_fifo_num;
65
 
 
66
 
        /* Transmitter */
67
 
        UINT8 tx_enabled;
68
 
        UINT8 tx_data;
69
 
        UINT8 tx_ready;
70
 
        emu_timer *tx_timer;
71
 
 
72
 
} DUART68681_CHANNEL;
73
 
 
74
 
typedef struct
75
 
{
76
 
        /* device */
77
 
        device_t *device;
78
 
 
79
 
        /* config */
80
 
        const duart68681_config *duart_config;
81
 
 
82
 
        /* registers */
83
 
        UINT8 ACR;  /* Auxiliary Control Register */
84
 
        UINT8 IMR;  /* Interrupt Mask Register */
85
 
        UINT8 ISR;  /* Interrupt Status Register */
86
 
        UINT8 IVR;  /* Interrupt Vector Register */
87
 
        UINT8 OPCR; /* Output Port Conf. Register */
88
 
        UINT8 OPR;  /* Output Port Register */
89
 
        PAIR  CTR;  /* Counter/Timer Preset Value */
90
 
 
91
 
        /* state */
92
 
        UINT8 IP_last_state; /* last state of IP bits */
93
 
 
94
 
        /* timer */
95
 
        emu_timer *duart_timer;
96
 
 
97
 
        /* UART channels */
98
 
        DUART68681_CHANNEL channel[2];
99
 
 
100
 
} duart68681_state;
101
 
 
102
 
INLINE duart68681_state *get_safe_token(device_t *device)
103
 
{
104
 
        assert(device != NULL);
105
 
        assert(device->type() == DUART68681);
106
 
 
107
 
        return (duart68681_state *)downcast<legacy_device_base *>(device)->token();
108
 
}
109
 
 
110
 
static void duart68681_update_interrupts(duart68681_state *duart68681)
111
 
{
112
 
        /* update SR state and update interrupt ISR state for the following bits:
113
 
    SRn: bits 7-4: handled elsewhere.
114
 
    SRn: bit 3 (TxEMTn) (we can assume since we're not actually emulating the delay/timing of sending bits, that as long as TxRDYn is set, TxEMTn is also set since the transmit byte has 'already happened', therefore TxEMTn is always 1 assuming tx is enabled on channel n and the MSR2n mode is 0 or 2; in mode 1 it is explicitly zeroed, and mode 3 is undefined)
115
 
    SRn: bit 2 (TxRDYn) (we COULD assume since we're not emulating delay and timing output, that as long as tx is enabled on channel n, TxRDY is 1 for channel n and the MSR2n mode is 0 or 2; in mode 1 it is explicitly zeroed, and mode 3 is undefined; however, tx_ready is already nicely handled for us elsewhere, so we can use that instead for now, though we may need to retool that code as well)
116
 
    SRn: bit 1 (FFULLn) (this bit we actually emulate; if the receive fifo for channel n is full, this bit is 1, otherwise it is 0. the receive fifo should be three words long.)
117
 
    SRn: bit 0 (RxRDYn) (this bit we also emulate; the bit is always asserted if the receive fifo is not empty)
118
 
    ISR: bit 7: Input Port change; this should be handled elsewhere, on the input port handler
119
 
    ISR: bit 6: Delta Break B; this should be handled elsewhere, on the data receive handler
120
 
    ISR: bit 5: RxRDYB/FFULLB: this is handled here; depending on whether MSR1B bit 6 is 0 or 1, this bit holds the state of SRB bit 0 or bit 1 respectively
121
 
    ISR: bit 4: TxRDYB: this is handled here; it mirrors SRB bit 2
122
 
    ISR: bit 3: Counter ready; this should be handled by the timer generator
123
 
    ISR: bit 2: Delta Break A; this should be handled elsewhere, on the data receive handler
124
 
    ISR: bit 1: RxRDYA/FFULLA: this is handled here; depending on whether MSR1A bit 6 is 0 or 1, this bit holds the state of SRA bit 0 or bit 1 respectively
125
 
    ISR: bit 0: TxRDYA: this is handled here; it mirrors SRA bit 2
126
 
    */
127
 
        UINT8 ch = 0;
128
 
        //logerror("DEBUG: 68681 int check: upon func call, SRA is %02X, SRB is %02X, ISR is %02X\n", duart68681->channel[0].SR, duart68681->channel[1].SR, duart68681->ISR);
129
 
        for (ch = 0; ch < 2; ch++)
130
 
        {
131
 
                //if ( duart68681->channel[ch].rx_enabled )
132
 
                //{
133
 
                        if ( duart68681->channel[ch].rx_fifo_num > 0 )
134
 
                        {
135
 
                                duart68681->channel[ch].SR |= STATUS_RECEIVER_READY;
136
 
                        }
137
 
                        else
138
 
                        {
139
 
                                duart68681->channel[ch].SR &= ~STATUS_RECEIVER_READY;
140
 
                        }
141
 
                        if ( duart68681->channel[ch].rx_fifo_num == RX_FIFO_SIZE )
142
 
                        {
143
 
                                duart68681->channel[ch].SR |= STATUS_FIFO_FULL;
144
 
                        }
145
 
                        else
146
 
                        {
147
 
                                duart68681->channel[ch].SR &= ~STATUS_FIFO_FULL;
148
 
                        }
149
 
                //}
150
 
                //else
151
 
                //{
152
 
                //duart68681->channel[ch].SR &= ~STATUS_RECEIVER_READY;
153
 
                //duart68681->channel[ch].SR &= ~STATUS_FIFO_FULL;
154
 
                //}
155
 
                // Handle the TxEMT and TxRDY bits based on mode
156
 
                switch( duart68681->channel[ch].MR2&0xC0) // what mode are we in?
157
 
                        {
158
 
                        case 0x00: // normal mode
159
 
                                if ( duart68681->channel[ch].tx_enabled )
160
 
                                {
161
 
                                        duart68681->channel[ch].SR |= STATUS_TRANSMITTER_EMPTY;
162
 
                                }
163
 
                                else
164
 
                                {
165
 
                                        duart68681->channel[ch].SR &= ~STATUS_TRANSMITTER_EMPTY;
166
 
                                }
167
 
                        break;
168
 
                        case 0x40: // automatic echo mode
169
 
                                duart68681->channel[ch].SR &= ~STATUS_TRANSMITTER_EMPTY;
170
 
                                duart68681->channel[ch].SR &= ~STATUS_TRANSMITTER_READY;
171
 
                        break;
172
 
                        case 0x80: // local loopback mode
173
 
                                if ( duart68681->channel[ch].tx_enabled )
174
 
                                {
175
 
                                        duart68681->channel[ch].SR |= STATUS_TRANSMITTER_EMPTY;
176
 
                                }
177
 
                                else
178
 
                                {
179
 
                                        duart68681->channel[ch].SR &= ~STATUS_TRANSMITTER_EMPTY;
180
 
                                }
181
 
                        break;
182
 
                        case 0xC0: // remote loopback mode
183
 
                                // write me, what the txrdy/txemt regs do for remote loopback mode is undocumented afaik, for now just clear both
184
 
                                duart68681->channel[ch].SR &= ~STATUS_TRANSMITTER_EMPTY;
185
 
                                duart68681->channel[ch].SR &= ~STATUS_TRANSMITTER_READY;
186
 
                        break;
187
 
                        }
188
 
                // now handle the ISR bits
189
 
                if ( duart68681->channel[ch].SR & STATUS_TRANSMITTER_READY )
190
 
                {
191
 
                        if (ch == 0)
192
 
                                duart68681->ISR |= INT_TXRDYA;
193
 
                        else
194
 
                                duart68681->ISR |= INT_TXRDYB;
195
 
                }
196
 
                else
197
 
                {
198
 
                        if (ch == 0)
199
 
                                duart68681->ISR &= ~INT_TXRDYA;
200
 
                        else
201
 
                                duart68681->ISR &= ~INT_TXRDYB;
202
 
                }
203
 
                //logerror("DEBUG: 68681 int check: before receiver test, SR%c is %02X, ISR is %02X\n", (ch+0x41), duart68681->channel[ch].SR, duart68681->ISR);
204
 
                if ( duart68681->channel[ch].MR1 & MODE_RX_INT_SELECT_BIT )
205
 
                {
206
 
                        if ( duart68681->channel[ch].SR & STATUS_FIFO_FULL )
207
 
                        {
208
 
                                duart68681->ISR |= ((ch == 0) ? INT_RXRDY_FFULLA : INT_RXRDY_FFULLB);
209
 
                        }
210
 
                        else
211
 
                        {
212
 
                                duart68681->ISR &= ((ch == 0) ? ~INT_RXRDY_FFULLA : ~INT_RXRDY_FFULLB);
213
 
                        }
214
 
                }
215
 
                else
216
 
                {
217
 
                        if ( duart68681->channel[ch].SR & STATUS_RECEIVER_READY )
218
 
                        {
219
 
                                duart68681->ISR |= ((ch == 0) ? INT_RXRDY_FFULLA : INT_RXRDY_FFULLB);
220
 
                        }
221
 
                        else
222
 
                        {
223
 
                                duart68681->ISR &= ((ch == 0) ? ~INT_RXRDY_FFULLA : ~INT_RXRDY_FFULLB);
224
 
                        }
225
 
                }
226
 
                //logerror("DEBUG: 68681 int check: after receiver test, SR%c is %02X, ISR is %02X\n", (ch+0x41), duart68681->channel[ch].SR, duart68681->ISR);
227
 
        }
228
 
        if ( (duart68681->ISR & duart68681->IMR) != 0 )
229
 
        {
230
 
                if ( duart68681->duart_config->irq_handler )
231
 
                {
232
 
                        LOG(( "68681: Interrupt line active (IMR & ISR = %02X)\n", (duart68681->ISR & duart68681->IMR) ));
233
 
                        duart68681->duart_config->irq_handler( duart68681->device, duart68681->IVR );
234
 
                }
235
 
        }
236
 
};
237
 
 
238
 
static TIMER_CALLBACK( duart_timer_callback )
239
 
{
240
 
        device_t *device = (device_t *)ptr;
241
 
        duart68681_state        *duart68681 = get_safe_token(device);
242
 
 
243
 
        duart68681->ISR |= INT_COUNTER_READY;
244
 
        duart68681_update_interrupts(duart68681);
245
 
 
246
 
//  if ((duart68681->OPCR & 0x0c)== 0x04) {
247
 
//      duart68681->OPR ^= 0x08;
248
 
//      if (duart68681->duart_config->output_port_write)
249
 
//          duart68681->duart_config->output_port_write(duart68681->device, duart68681->OPR ^ 0xff);
250
 
//
251
 
//  }
252
 
};
253
 
 
254
 
static void duart68681_write_MR(duart68681_state *duart68681, int ch, UINT8 data)
255
 
{
256
 
        if ( duart68681->channel[ch].MR_ptr == 0 )
257
 
        {
258
 
                duart68681->channel[ch].MR1 = data;
259
 
                duart68681->channel[ch].MR_ptr = 1;
260
 
        }
261
 
        else
262
 
        {
263
 
                duart68681->channel[ch].MR2 = data;
264
 
        }
265
 
        duart68681_update_interrupts(duart68681);
266
 
};
267
 
 
268
 
static void duart68681_write_CSR(duart68681_state *duart68681, int ch, UINT8 data, UINT8 ACR)
269
 
{
270
 
        static const int baud_rate_ACR_0[] = { 50, 110, 134, 200, 300, 600, 1200, 1050, 2400, 4800, 7200, 9600, 38400, 0, 0, 0 };
271
 
        static const int baud_rate_ACR_1[] = { 75, 110, 134, 150, 300, 600, 1200, 2000, 2400, 4800, 1800, 9600, 19200, 0, 0, 0 };
272
 
 
273
 
        duart68681->channel[ch].CSR = data;
274
 
 
275
 
        if ( BIT(ACR,7) == 0 )
276
 
        {
277
 
                duart68681->channel[ch].baud_rate = baud_rate_ACR_0[data & 0x0f];
278
 
 
279
 
                if (ch == 0)
280
 
                {
281
 
                        if ((data & 0xf) == 0xe)
282
 
                        {
283
 
                                duart68681->channel[ch].baud_rate = duart68681->duart_config->ip3clk/16;
284
 
                        }
285
 
                        else if ((data & 0xf) == 0xf)
286
 
                        {
287
 
                                duart68681->channel[ch].baud_rate = duart68681->duart_config->ip3clk;
288
 
                        }
289
 
                }
290
 
                else if (ch == 1)
291
 
                {
292
 
                        if ((data & 0xf) == 0xe)
293
 
                        {
294
 
                                duart68681->channel[ch].baud_rate = duart68681->duart_config->ip5clk/16;
295
 
                        }
296
 
                        else if ((data & 0xf) == 0xf)
297
 
                        {
298
 
                                duart68681->channel[ch].baud_rate = duart68681->duart_config->ip5clk;
299
 
                        }
300
 
                }
301
 
        }
302
 
        else
303
 
        {
304
 
                duart68681->channel[ch].baud_rate = baud_rate_ACR_1[data & 0x0f];
305
 
        }
306
 
        if ( duart68681->channel[ch].baud_rate == 0 )
307
 
        {
308
 
                LOG(( "Unsupported transmitter clock: channel %d, clock select = %02x\n", ch, data ));
309
 
        }
310
 
};
311
 
 
312
 
static void duart68681_write_CR(duart68681_state *duart68681, int ch, UINT8 data)
313
 
{
314
 
        duart68681->channel[ch].CR = data;
315
 
 
316
 
        switch( (data >> 4) & 0x07 )
317
 
        {
318
 
                case 0: /* No command */
319
 
                        break;
320
 
                case 1: /* Reset MR pointer. Causes the Channel A MR pointer to point to MR1 */
321
 
                        duart68681->channel[ch].MR_ptr = 0;
322
 
                        break;
323
 
                case 2: /* Reset channel A receiver (disable receiver and flush fifo) */
324
 
                        duart68681->channel[ch].rx_enabled = 0;
325
 
                        duart68681->channel[ch].SR &= ~STATUS_RECEIVER_READY;
326
 
                        duart68681->channel[ch].SR &= ~STATUS_OVERRUN_ERROR; // is this correct?
327
 
                        duart68681->channel[ch].rx_fifo_read_ptr = 0;
328
 
                        duart68681->channel[ch].rx_fifo_write_ptr = 0;
329
 
                        duart68681->channel[ch].rx_fifo_num = 0;
330
 
                        break;
331
 
                case 3: /* Reset channel A transmitter */
332
 
                        duart68681->channel[ch].tx_enabled = 0;
333
 
                        duart68681->channel[ch].SR &= ~STATUS_TRANSMITTER_READY;
334
 
                        if (ch == 0)
335
 
                                duart68681->ISR &= ~INT_TXRDYA;
336
 
                        else
337
 
                                duart68681->ISR &= ~INT_TXRDYB;
338
 
                        duart68681->channel[ch].tx_timer->adjust(attotime::never, ch);
339
 
                        break;
340
 
                case 4: /* Reset Error Status */
341
 
                        duart68681->channel[ch].SR &= ~(STATUS_RECEIVED_BREAK | STATUS_FRAMING_ERROR | STATUS_PARITY_ERROR | STATUS_OVERRUN_ERROR);
342
 
                        break;
343
 
                case 5: /* Reset Channel break change interrupt */
344
 
                        if ( ch == 0 )
345
 
                        {
346
 
                                duart68681->ISR &= ~INT_DELTA_BREAK_A;
347
 
                        }
348
 
                        else
349
 
                        {
350
 
                                duart68681->ISR &= ~INT_DELTA_BREAK_B;
351
 
                        }
352
 
                        break;
353
 
                /* TODO: case 6 and case 7 are start break and stop break respectively, which start or stop holding the TxDA or TxDB line low (space) after whatever data is in the buffer finishes transmitting (following the stop bit?), or after two bit-times if no data is being transmitted  */
354
 
                default:
355
 
                        LOG(( "68681: Unhandled command (%x) in CR%d\n", (data >> 4) & 0x07, ch ));
356
 
                        break;
357
 
        }
358
 
        duart68681_update_interrupts(duart68681);
359
 
 
360
 
        if (BIT(data, 0)) {
361
 
                duart68681->channel[ch].rx_enabled = 1;
362
 
        }
363
 
        if (BIT(data, 1)) {
364
 
                duart68681->channel[ch].rx_enabled = 0;
365
 
                duart68681->channel[ch].SR &= ~STATUS_RECEIVER_READY;
366
 
        }
367
 
 
368
 
        if (BIT(data, 2)) {
369
 
                duart68681->channel[ch].tx_enabled = 1;
370
 
                duart68681->channel[ch].tx_ready = 1;
371
 
                duart68681->channel[ch].SR |= STATUS_TRANSMITTER_READY;
372
 
                if (ch == 0)
373
 
                        duart68681->ISR |= INT_TXRDYA;
374
 
                else
375
 
                        duart68681->ISR |= INT_TXRDYB;
376
 
        }
377
 
        if (BIT(data, 3)) {
378
 
                duart68681->channel[ch].tx_enabled = 0;
379
 
                duart68681->channel[ch].tx_ready = 0;
380
 
                duart68681->channel[ch].SR &= ~STATUS_TRANSMITTER_READY;
381
 
                if (ch == 0)
382
 
                        duart68681->ISR &= ~INT_TXRDYA;
383
 
                else
384
 
                        duart68681->ISR &= ~INT_TXRDYB;
385
 
        }
386
 
 
387
 
};
388
 
 
389
 
static UINT8 duart68681_read_rx_fifo(duart68681_state *duart68681, int ch)
390
 
{
391
 
        UINT8 r;
392
 
 
393
 
        if ( duart68681->channel[ch].rx_fifo_num == 0 )
394
 
        {
395
 
                LOG(( "68681: rx fifo underflow\n" ));
396
 
                return 0x0;
397
 
        }
398
 
 
399
 
        r = duart68681->channel[ch].rx_fifo[duart68681->channel[ch].rx_fifo_read_ptr++];
400
 
        if ( duart68681->channel[ch].rx_fifo_read_ptr == RX_FIFO_SIZE )
401
 
        {
402
 
                duart68681->channel[ch].rx_fifo_read_ptr = 0;
403
 
        }
404
 
 
405
 
        duart68681->channel[ch].rx_fifo_num--;
406
 
        duart68681_update_interrupts(duart68681);
407
 
 
408
 
        return r;
409
 
};
410
 
 
411
 
static TIMER_CALLBACK( tx_timer_callback )
412
 
{
413
 
        device_t *device = (device_t *)ptr;
414
 
        duart68681_state        *duart68681 = get_safe_token(device);
415
 
        int ch = param & 1;
416
 
 
417
 
        // send the byte unless we're in loopback mode;
418
 
        // in loopback mode do NOT 'actually' send the byte: the TXn pin is held high when loopback mode is on.
419
 
        if ((duart68681->duart_config->tx_callback) && ((duart68681->channel[ch].MR2&0xC0) != 0x80))
420
 
                duart68681->duart_config->tx_callback(device, ch, duart68681->channel[ch].tx_data);
421
 
 
422
 
        // if local loopback is on, write the transmitted data as if a byte had been received
423
 
        if ((duart68681->channel[ch].MR2 & 0xC0) == 0x80)
424
 
        {
425
 
                if (duart68681->channel[ch].rx_fifo_num >= RX_FIFO_SIZE)
426
 
                {
427
 
                        LOG(( "68681: FIFO overflow\n" ));
428
 
                        duart68681->channel[ch].SR |= STATUS_OVERRUN_ERROR;
429
 
                }
430
 
                else
431
 
                {
432
 
                        duart68681->channel[ch].rx_fifo[duart68681->channel[ch].rx_fifo_write_ptr++]
433
 
                                        = duart68681->channel[ch].tx_data;
434
 
                        if (duart68681->channel[ch].rx_fifo_write_ptr == RX_FIFO_SIZE)
435
 
                        {
436
 
                                duart68681->channel[ch].rx_fifo_write_ptr = 0;
437
 
                        }
438
 
                        duart68681->channel[ch].rx_fifo_num++;
439
 
                }
440
 
        }
441
 
 
442
 
        duart68681->channel[ch].tx_ready = 1;
443
 
        duart68681->channel[ch].SR |= STATUS_TRANSMITTER_READY;
444
 
 
445
 
        if (ch == 0)
446
 
                duart68681->ISR |= INT_TXRDYA;
447
 
        else
448
 
                duart68681->ISR |= INT_TXRDYB;
449
 
 
450
 
        duart68681_update_interrupts(duart68681);
451
 
        duart68681->channel[ch].tx_timer->adjust(attotime::never, ch);
452
 
};
453
 
 
454
 
static void duart68681_write_TX(duart68681_state* duart68681, int ch, UINT8 data)
455
 
{
456
 
        attotime period;
457
 
 
458
 
        duart68681->channel[ch].tx_data = data;
459
 
 
460
 
        duart68681->channel[ch].tx_ready = 0;
461
 
        duart68681->channel[ch].SR &= ~STATUS_TRANSMITTER_READY;
462
 
 
463
 
        if (ch == 0)
464
 
                duart68681->ISR &= ~INT_TXRDYA;
465
 
        else
466
 
                duart68681->ISR &= ~INT_TXRDYB;
467
 
 
468
 
        duart68681_update_interrupts(duart68681);
469
 
 
470
 
        period = attotime::from_hz(duart68681->channel[ch].baud_rate / 10 );
471
 
        duart68681->channel[ch].tx_timer->adjust(period, ch);
472
 
 
473
 
};
474
 
 
475
 
READ8_DEVICE_HANDLER(duart68681_r)
476
 
{
477
 
        duart68681_state* duart68681 = get_safe_token(device);
478
 
        UINT8 r = 0xff;
479
 
 
480
 
        offset &= 0xf;
481
 
 
482
 
        LOG(( "Reading 68681 (%s) reg %x (%s) ", device->tag(), offset, duart68681_reg_read_names[offset] ));
483
 
 
484
 
        switch (offset)
485
 
        {
486
 
                case 0x00: /* MR1A/MR2A */
487
 
                        if ( duart68681->channel[0].MR_ptr == 0 )
488
 
                        {
489
 
                                r = duart68681->channel[0].MR1;
490
 
                                duart68681->channel[0].MR_ptr = 1;
491
 
                        }
492
 
                        else
493
 
                        {
494
 
                                r = duart68681->channel[0].MR2;
495
 
                        }
496
 
                        break;
497
 
                case 0x01: /* SRA */
498
 
                        r = duart68681->channel[0].SR;
499
 
                        break;
500
 
                case 0x03: /* Rx Holding Register A */
501
 
                        r = duart68681_read_rx_fifo(duart68681, 0);
502
 
                        break;
503
 
                case 0x04: /* IPCR */
504
 
                        {
505
 
                                UINT8 IP;
506
 
                                if ( duart68681->duart_config->input_port_read != NULL )
507
 
                                        IP = duart68681->duart_config->input_port_read(duart68681->device);
508
 
                                else
509
 
                                        IP = 0x0;
510
 
 
511
 
                                r = (((duart68681->IP_last_state ^ IP) & 0x0f) << 4) | (IP & 0x0f);
512
 
                                duart68681->IP_last_state = IP;
513
 
                                duart68681->ISR &= ~INT_INPUT_PORT_CHANGE;
514
 
                                duart68681_update_interrupts(duart68681);
515
 
                        }
516
 
                        break;
517
 
                case 0x05: /* ISR */
518
 
                        r = duart68681->ISR;
519
 
                        break;
520
 
                case 0x08: /* MR1B/MR2B */
521
 
                        if ( duart68681->channel[1].MR_ptr == 0 )
522
 
                        {
523
 
                                r = duart68681->channel[1].MR1;
524
 
                                duart68681->channel[1].MR_ptr = 1;
525
 
                        }
526
 
                        else
527
 
                        {
528
 
                                r = duart68681->channel[1].MR2;
529
 
                        }
530
 
                        break;
531
 
                case 0x09: /* SRB */
532
 
                        r = duart68681->channel[1].SR;
533
 
                        break;
534
 
                case 0x0b: /* RHRB */
535
 
                        r = duart68681_read_rx_fifo(duart68681, 1);
536
 
                        break;
537
 
                case 0x0d: /* IP */
538
 
                        if ( duart68681->duart_config->input_port_read != NULL )
539
 
                                r = duart68681->duart_config->input_port_read(duart68681->device);
540
 
                        else
541
 
                                {
542
 
                                        r = 0xff;
543
 
#if 0
544
 
                                        if (device->machine().input().code_pressed(KEYCODE_1)) r ^= 0x0001;
545
 
                                        if (device->machine().input().code_pressed(KEYCODE_2)) r ^= 0x0002;
546
 
                                        if (device->machine().input().code_pressed(KEYCODE_3)) r ^= 0x0004;
547
 
                                        if (device->machine().input().code_pressed(KEYCODE_4)) r ^= 0x0008;
548
 
                                        if (device->machine().input().code_pressed(KEYCODE_5)) r ^= 0x0010;
549
 
                                        if (device->machine().input().code_pressed(KEYCODE_6)) r ^= 0x0020;
550
 
                                        if (device->machine().input().code_pressed(KEYCODE_7)) r ^= 0x0040;
551
 
                                        if (device->machine().input().code_pressed(KEYCODE_8)) r ^= 0x0080;
552
 
#endif
553
 
                                }
554
 
                        break;
555
 
                case 0x0e: /* Start counter command */
556
 
                        switch( (duart68681->ACR >> 4) & 0x07 )
557
 
                        {
558
 
                                /* TODO: implement modes 0,1,2,4,5 */
559
 
                                case 0x03: /* Counter, CLK/16 */
560
 
                                        {
561
 
                                                attotime rate = attotime::from_hz(2*device->clock()/(2*16*16*duart68681->CTR.w.l));
562
 
                                                duart68681->duart_timer->adjust(rate, 0, rate);
563
 
                                        }
564
 
                                        break;
565
 
                                case 0x06: /* Timer, CLK/1 */
566
 
                                        {
567
 
                                                attotime rate = attotime::from_hz(2*device->clock()/(2*16*duart68681->CTR.w.l));
568
 
                                                duart68681->duart_timer->adjust(rate, 0, rate);
569
 
                                        }
570
 
                                        break;
571
 
                                case 0x07: /* Timer, CLK/16 */
572
 
                                        {
573
 
                                                //double hz;
574
 
                                                //attotime rate = attotime::from_hz(duart68681->clock) * (16*duart68681->CTR.w.l);
575
 
                                                attotime rate = attotime::from_hz(2*device->clock()/(2*16*16*duart68681->CTR.w.l));
576
 
                                                //hz = ATTOSECONDS_TO_HZ(rate.attoseconds);
577
 
                                                duart68681->duart_timer->adjust(rate, 0, rate);
578
 
                                        }
579
 
                                        break;
580
 
                        }
581
 
                        break;
582
 
                case 0x0f: /* Stop counter command */
583
 
                        duart68681->ISR &= ~INT_COUNTER_READY;
584
 
                        if (((duart68681->ACR >>4)& 0x07) < 4) // if in counter mode...
585
 
                        duart68681->duart_timer->adjust(attotime::never); // shut down timer
586
 
                        duart68681_update_interrupts(duart68681);
587
 
                        break;
588
 
                default:
589
 
                        LOG(( "Reading unhandled 68681 reg %x\n", offset ));
590
 
                        break;
591
 
        }
592
 
        LOG(("returned %02x\n", r));
593
 
 
594
 
        return r;
595
 
}
596
 
 
597
 
WRITE8_DEVICE_HANDLER(duart68681_w)
598
 
{
599
 
        duart68681_state* duart68681 = get_safe_token(device);
600
 
 
601
 
        offset &= 0x0f;
602
 
        LOG(( "Writing 68681 (%s) reg %x (%s) with %04x\n", device->tag(), offset, duart68681_reg_write_names[offset], data ));
603
 
 
604
 
        switch(offset)
605
 
        {
606
 
                case 0x00: /* MRA */
607
 
                        duart68681_write_MR(duart68681, 0, data);
608
 
                        break;
609
 
                case 0x01: /* CSRA */
610
 
                        duart68681_write_CSR(duart68681, 0, data, duart68681->ACR);
611
 
                        break;
612
 
                case 0x02: /* CRA */
613
 
                        duart68681_write_CR(duart68681, 0, data);
614
 
                        break;
615
 
                case 0x03: /* THRA */
616
 
                        duart68681_write_TX(duart68681, 0, data);
617
 
                        break;
618
 
                case 0x04: /* ACR */
619
 
                        duart68681->ACR = data;
620
 
                        //       bits 6-4: Counter/Timer Mode And Clock Source Select
621
 
                        //       bits 3-0: IP3-0 Change-Of-State Interrupt Enable
622
 
                        switch ((data >> 4) & 0x07)
623
 
                        {
624
 
                                case 0: case 1: case 2: case 4: case 5: // TODO: handle these cases!
625
 
                                logerror( "68681 (%s): Unhandled timer/counter mode %d\n", device->tag(), (data >> 4) & 0x07);
626
 
                                break;
627
 
                                case 3: case 6: case 7:
628
 
                                break;
629
 
                        }
630
 
                        duart68681_write_CSR(duart68681, 0, duart68681->channel[0].CSR, data);
631
 
                        duart68681_write_CSR(duart68681, 1, duart68681->channel[1].CSR, data);
632
 
                        duart68681_update_interrupts(duart68681); // need to add ACR checking for IP delta ints
633
 
                        break;
634
 
                case 0x05: /* IMR */
635
 
                        duart68681->IMR = data;
636
 
                        duart68681_update_interrupts(duart68681);
637
 
                        break;
638
 
                case 0x06: /* CTUR */
639
 
                        duart68681->CTR.b.h = data;
640
 
                        break;
641
 
                case 0x07: /* CTLR */
642
 
                        duart68681->CTR.b.l = data;
643
 
                        break;
644
 
                case 0x08: /* MRB */
645
 
                        duart68681_write_MR(duart68681, 1, data);
646
 
                        break;
647
 
                case 0x09: /* CSRB */
648
 
                        duart68681_write_CSR(duart68681, 1, data, duart68681->ACR);
649
 
                        break;
650
 
                case 0x0a: /* CRB */
651
 
                        duart68681_write_CR(duart68681, 1, data);
652
 
                        break;
653
 
                case 0x0b: /* THRB */
654
 
                        duart68681_write_TX(duart68681, 1, data);
655
 
                        break;
656
 
                case 0x0c: /* IVR */
657
 
                        duart68681->IVR = data;
658
 
                        break;
659
 
                case 0x0d: /* OPCR */
660
 
                        if (data != 0x00)
661
 
                                logerror( "68681 (%s): Unhandled OPCR value: %02x\n", device->tag(), data);
662
 
                        duart68681->OPCR = data;
663
 
                        break;
664
 
                case 0x0e: /* Set Output Port Bits */
665
 
                        duart68681->OPR |= data;
666
 
                        if (duart68681->duart_config->output_port_write)
667
 
                                duart68681->duart_config->output_port_write(duart68681->device, duart68681->OPR ^ 0xff);
668
 
                        break;
669
 
                case 0x0f: /* Reset Output Port Bits */
670
 
                        duart68681->OPR &= ~data;
671
 
                        if (duart68681->duart_config->output_port_write)
672
 
                                duart68681->duart_config->output_port_write(duart68681->device, duart68681->OPR ^ 0xff);
673
 
                        break;
674
 
        }
675
 
}
676
 
 
677
 
void duart68681_rx_data( device_t* device, int ch, UINT8 data )
678
 
{
679
 
        duart68681_state *duart68681 = get_safe_token(device);
680
 
 
681
 
        if ( duart68681->channel[ch].rx_enabled )
682
 
        {
683
 
                if ( duart68681->channel[ch].rx_fifo_num >= RX_FIFO_SIZE )
684
 
                {
685
 
                        LOG(( "68681: FIFO overflow\n" ));
686
 
                        duart68681->channel[ch].SR |= STATUS_OVERRUN_ERROR;
687
 
                        return;
688
 
                }
689
 
                duart68681->channel[ch].rx_fifo[duart68681->channel[ch].rx_fifo_write_ptr++] = data;
690
 
                if ( duart68681->channel[ch].rx_fifo_write_ptr == RX_FIFO_SIZE )
691
 
                {
692
 
                        duart68681->channel[ch].rx_fifo_write_ptr = 0;
693
 
                }
694
 
                duart68681->channel[ch].rx_fifo_num++;
695
 
                duart68681_update_interrupts(duart68681);
696
 
        }
697
 
};
698
 
 
699
 
/*-------------------------------------------------
700
 
    device start callback
701
 
-------------------------------------------------*/
702
 
 
703
 
static DEVICE_START(duart68681)
704
 
{
705
 
        duart68681_state *duart68681 = get_safe_token(device);
706
 
 
707
 
        /* validate arguments */
708
 
        assert(device != NULL);
709
 
 
710
 
        duart68681->duart_config = (const duart68681_config *)device->static_config();
711
 
        duart68681->device = device;
712
 
 
713
 
        duart68681->channel[0].tx_timer = device->machine().scheduler().timer_alloc(FUNC(tx_timer_callback), (void*)device);
714
 
        duart68681->channel[1].tx_timer = device->machine().scheduler().timer_alloc(FUNC(tx_timer_callback), (void*)device);
715
 
        duart68681->duart_timer = device->machine().scheduler().timer_alloc(FUNC(duart_timer_callback), (void*)device);
716
 
 
717
 
        device->save_item(NAME(duart68681->ACR));
718
 
        device->save_item(NAME(duart68681->IMR));
719
 
        device->save_item(NAME(duart68681->ISR));
720
 
        device->save_item(NAME(duart68681->IVR));
721
 
        device->save_item(NAME(duart68681->OPCR));
722
 
        device->save_item(NAME(duart68681->CTR));
723
 
        device->save_item(NAME(duart68681->IP_last_state));
724
 
 
725
 
        device->save_item(NAME(duart68681->channel[0].CR));
726
 
        device->save_item(NAME(duart68681->channel[0].CSR));
727
 
        device->save_item(NAME(duart68681->channel[0].MR1));
728
 
        device->save_item(NAME(duart68681->channel[0].MR2));
729
 
        device->save_item(NAME(duart68681->channel[0].MR_ptr));
730
 
        device->save_item(NAME(duart68681->channel[0].SR));
731
 
        device->save_item(NAME(duart68681->channel[0].baud_rate));
732
 
        device->save_item(NAME(duart68681->channel[0].rx_enabled));
733
 
        device->save_item(NAME(duart68681->channel[0].rx_fifo));
734
 
        device->save_item(NAME(duart68681->channel[0].rx_fifo_read_ptr));
735
 
        device->save_item(NAME(duart68681->channel[0].rx_fifo_write_ptr));
736
 
        device->save_item(NAME(duart68681->channel[0].rx_fifo_num));
737
 
        device->save_item(NAME(duart68681->channel[0].tx_enabled));
738
 
        device->save_item(NAME(duart68681->channel[0].tx_data));
739
 
        device->save_item(NAME(duart68681->channel[0].tx_ready));
740
 
 
741
 
        device->save_item(NAME(duart68681->channel[1].CR));
742
 
        device->save_item(NAME(duart68681->channel[1].CSR));
743
 
        device->save_item(NAME(duart68681->channel[1].MR1));
744
 
        device->save_item(NAME(duart68681->channel[1].MR2));
745
 
        device->save_item(NAME(duart68681->channel[1].MR_ptr));
746
 
        device->save_item(NAME(duart68681->channel[1].SR));
747
 
        device->save_item(NAME(duart68681->channel[1].baud_rate));
748
 
        device->save_item(NAME(duart68681->channel[1].rx_enabled));
749
 
        device->save_item(NAME(duart68681->channel[1].rx_fifo));
750
 
        device->save_item(NAME(duart68681->channel[1].rx_fifo_read_ptr));
751
 
        device->save_item(NAME(duart68681->channel[1].rx_fifo_write_ptr));
752
 
        device->save_item(NAME(duart68681->channel[1].rx_fifo_num));
753
 
        device->save_item(NAME(duart68681->channel[1].tx_enabled));
754
 
        device->save_item(NAME(duart68681->channel[1].tx_data));
755
 
        device->save_item(NAME(duart68681->channel[1].tx_ready));
756
 
}
757
 
 
758
 
/*-------------------------------------------------
759
 
    device reset callback
760
 
-------------------------------------------------*/
761
 
 
762
 
static DEVICE_RESET(duart68681)
763
 
{
764
 
        duart68681_state *duart68681 = get_safe_token(device);
765
 
        emu_timer *save0, *save1;
766
 
 
767
 
        duart68681->ACR = 0;  /* Interrupt Vector Register */
768
 
        duart68681->IVR = 0x0f;  /* Interrupt Vector Register */
769
 
        duart68681->IMR = 0;  /* Interrupt Mask Register */
770
 
        duart68681->ISR = 0;  /* Interrupt Status Register */
771
 
        duart68681->OPCR = 0; /* Output Port Conf. Register */
772
 
        duart68681->OPR = 0;  /* Output Port Register */
773
 
        duart68681->CTR.d = 0;  /* Counter/Timer Preset Value */
774
 
        duart68681->IP_last_state = 0;  /* last state of IP bits */
775
 
        // "reset clears internal registers (SRA, SRB, IMR, ISR, OPR, OPCR) puts OP0-7 in the high state, stops the counter/timer, and puts channels a/b in the inactive state"
776
 
        save0 = duart68681->channel[0].tx_timer;
777
 
        save1 = duart68681->channel[1].tx_timer;
778
 
        memset(duart68681->channel, 0, sizeof(duart68681->channel));
779
 
        duart68681->channel[0].tx_timer = save0;
780
 
        duart68681->channel[1].tx_timer = save1;
781
 
 
782
 
        if (duart68681->duart_config->output_port_write)
783
 
                duart68681->duart_config->output_port_write(duart68681->device, duart68681->OPR ^ 0xff);
784
 
 
785
 
        // reset timers
786
 
        duart68681->channel[0].tx_timer->adjust(attotime::never);
787
 
        duart68681->channel[1].tx_timer->adjust(attotime::never, 1);
788
 
}
789
 
 
790
 
/*-------------------------------------------------
791
 
    device get info callback
792
 
-------------------------------------------------*/
793
 
 
794
 
DEVICE_GET_INFO(duart68681)
795
 
{
796
 
        switch (state)
797
 
        {
798
 
                /* --- the following bits of info are returned as 64-bit signed integers --- */
799
 
                case DEVINFO_INT_TOKEN_BYTES:                   info->i = sizeof(duart68681_state);     break;
800
 
                case DEVINFO_INT_INLINE_CONFIG_BYTES:   info->i = sizeof(duart68681_config);    break;
801
 
 
802
 
                /* --- the following bits of info are returned as pointers to data or functions --- */
803
 
                case DEVINFO_FCT_START:                                 info->start = DEVICE_START_NAME(duart68681); break;
804
 
                case DEVINFO_FCT_STOP:                                  /* nothing */ break;
805
 
                case DEVINFO_FCT_RESET:                                 info->reset = DEVICE_RESET_NAME(duart68681);break;
806
 
 
807
 
                /* --- the following bits of info are returned as NULL-terminated strings --- */
808
 
                case DEVINFO_STR_NAME:                                  strcpy(info->s, "DUART 68681");                 break;
809
 
                case DEVINFO_STR_FAMILY:                                strcpy(info->s, "DUART");                               break;
810
 
                case DEVINFO_STR_VERSION:                               strcpy(info->s, "1.0");                                 break;
811
 
                case DEVINFO_STR_SOURCE_FILE:                   strcpy(info->s, __FILE__);                              break;
812
 
                case DEVINFO_STR_CREDITS:                               strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
813
 
        }
814
 
}
815
 
 
816
 
DEFINE_LEGACY_DEVICE(DUART68681, duart68681);