1
/*********************************************************************
5
TMS5501 input/output controller
7
Krzysztof Strzecha, Nathan Woods, 2003
8
Based on TMS9901 emulator by Raphael Nabet
10
21-May-2004 - Fixed interrupt queue overflow bug (not really fixed
12
06-Mar-2004 - Fixed bug in sensor input.
13
01-Mar-2004 - Interrupt queue overrun problem fixed.
14
19-Oct-2003 - Status register added. Reset fixed. Some cleanups.
20
*********************************************************************/
26
/***************************************************************************
28
***************************************************************************/
30
#define DEBUG_TMS5501 0
32
#define LOG_TMS5501(device, message, data) do { if (DEBUG_TMS5501) logerror ("\nTMS5501 %s: %s %02x", device->tag(), message, data); } while (0)
35
#define TMS5501_FRAME_ERROR 0x01
36
#define TMS5501_OVERRUN_ERROR 0x02
37
#define TMS5501_SERIAL_RCVD 0x04
38
#define TMS5501_RCV_BUFFER_LOADED 0x08
39
#define TMS5501_XMIT_BUFFER_EMPTY 0x10
40
#define TMS5501_INTERRUPT_PENDING 0x20
41
#define TMS5501_FULL_BIT_DETECT 0x40
42
#define TMS5501_START_BIT_DETECT 0x80
45
#define TMS5501_RESET 0x01
46
#define TMS5501_BREAK 0x02
47
#define TMS5501_INT_7_SELECT 0x04
48
#define TMS5501_INT_ACK_ENABLE 0x08
49
#define TMS5501_TEST_BIT_1 0x10
50
#define TMS5501_TEST_BIT_2 0x20
51
#define TMS5501_COMMAND_LATCHED_BITS 0x3e
53
/* interrupt mask register */
54
#define TMS5501_TIMER_0_INT 0x01
55
#define TMS5501_TIMER_1_INT 0x02
56
#define TMS5501_SENSOR_INT 0x04
57
#define TMS5501_TIMER_2_INT 0x08
58
#define TMS5501_SERIAL_RCV_LOADED_INT 0x10
59
#define TMS5501_SERIAL_XMIT_EMPTY_INT 0x20
60
#define TMS5501_TIMER_3_INT 0x40
61
#define TMS5501_TIMER_4_INT 0x80
62
#define TMS5501_INT_7_INT 0x80
64
#define TMS5501_PIO_INT_7 0x80
67
/***************************************************************************
69
***************************************************************************/
71
typedef struct _tms5501_t tms5501_t;
74
/* internal registers */
75
UINT8 status; /* status register */
76
UINT8 command; /* command register, bits 1-5 are latched */
78
UINT8 sio_rate; /* SIO configuration register */
79
UINT8 sio_input_buffer; /* SIO input buffer */
80
UINT8 sio_output_buffer; /* SIO output buffer */
82
UINT8 pio_input_buffer; /* PIO input buffer */
83
UINT8 pio_output_buffer; /* PIO output buffer */
85
UINT8 interrupt_mask; /* interrupt mask register */
86
UINT8 pending_interrupts; /* pending interrupts register */
87
UINT8 interrupt_address; /* interrupt vector register */
89
UINT8 sensor; /* sensor input */
92
UINT8 timer_counter[5];
98
/***************************************************************************
100
***************************************************************************/
102
INLINE tms5501_t *get_token(device_t *device)
104
assert(device != NULL);
105
assert(device->type() == TMS5501);
106
return (tms5501_t *) downcast<legacy_device_base *>(device)->token();
110
INLINE const tms5501_interface *get_interface(device_t *device)
112
assert(device != NULL);
113
assert(device->type() == TMS5501);
114
return (const tms5501_interface *) device->static_config();
117
static const UINT8 timer_name[] = { TMS5501_TIMER_0_INT, TMS5501_TIMER_1_INT, TMS5501_TIMER_2_INT, TMS5501_TIMER_3_INT, TMS5501_TIMER_4_INT };
119
/***************************************************************************
121
***************************************************************************/
123
/*-------------------------------------------------
125
-------------------------------------------------*/
127
static int find_first_bit(int value)
134
while (! (value & 1))
136
value >>= 1; /* try next bit */
144
/*-------------------------------------------------
145
tms5501_field_interrupts
146
-------------------------------------------------*/
148
static void tms5501_field_interrupts(device_t *device)
150
static const UINT8 int_vectors[] = { 0xc7, 0xcf, 0xd7, 0xdf, 0xe7, 0xef, 0xf7, 0xff };
152
tms5501_t *tms = get_token(device);
153
const tms5501_interface *intf = get_interface(device);
154
UINT8 current_ints = tms->pending_interrupts;
156
/* disabling masked interrupts */
157
current_ints &= tms->interrupt_mask;
159
LOG_TMS5501(device, "Pending interrupts", tms->pending_interrupts);
160
LOG_TMS5501(device, "Interrupt mask", tms->interrupt_mask);
161
LOG_TMS5501(device, "Current interrupts", current_ints);
165
/* selecting interrupt with highest priority */
166
int level = find_first_bit(current_ints);
167
LOG_TMS5501(device, "Interrupt level", level);
169
/* resetting proper bit in pending interrupts register */
170
tms->pending_interrupts &= ~(1<<level);
172
/* selecting interrupt vector */
173
tms->interrupt_address = int_vectors[level];
174
LOG_TMS5501(device, "Interrupt vector", int_vectors[level]);
176
if ((tms->command & TMS5501_INT_ACK_ENABLE))
178
if (intf->interrupt_callback)
179
(*intf->interrupt_callback)(device, 1, int_vectors[level]);
182
tms->status |= TMS5501_INTERRUPT_PENDING;
186
if ((tms->command & TMS5501_INT_ACK_ENABLE))
188
if (intf->interrupt_callback)
189
(*intf->interrupt_callback)(device, 0, 0);
192
tms->status &= ~TMS5501_INTERRUPT_PENDING;
197
/*-------------------------------------------------
198
tms5501_timer_decrementer
199
-------------------------------------------------*/
201
static void tms5501_timer_decrementer(device_t *device, UINT8 mask)
203
tms5501_t *tms = get_token(device);
205
if ((mask != TMS5501_TIMER_4_INT) || ((mask == TMS5501_TIMER_4_INT) && (!(tms->command & TMS5501_INT_7_SELECT))))
206
tms->pending_interrupts |= mask;
208
tms5501_field_interrupts(device);
212
/*-------------------------------------------------
213
TIMER_CALLBACK(tms5501_timer_decrementer_callback)
214
-------------------------------------------------*/
216
static TIMER_CALLBACK(tms5501_timer_decrementer_callback)
218
device_t *device = (device_t *) ptr;
221
tms5501_timer_decrementer(device, mask);
225
/*-------------------------------------------------
227
-------------------------------------------------*/
229
static void tms5501_timer_reload(device_t *device, int timer)
231
tms5501_t *tms = get_token(device);
232
const tms5501_interface *intf = get_interface(device);
234
if (tms->timer_counter[timer])
235
{ /* reset clock interval */
236
tms->timer[timer]->adjust(attotime::from_double((double) tms->timer_counter[0] / (intf->clock_rate / 128.)), timer_name[timer], attotime::from_double((double) tms->timer_counter[timer] / (intf->clock_rate / 128.)));
239
{ /* clock interval == 0 -> no timer */
242
case 0: tms5501_timer_decrementer(device, TMS5501_TIMER_0_INT); break;
243
case 1: tms5501_timer_decrementer(device, TMS5501_TIMER_1_INT); break;
244
case 2: tms5501_timer_decrementer(device, TMS5501_TIMER_2_INT); break;
245
case 3: tms5501_timer_decrementer(device, TMS5501_TIMER_3_INT); break;
246
case 4: tms5501_timer_decrementer(device, TMS5501_TIMER_4_INT); break;
248
tms->timer[timer]->enable(0);
253
/*-------------------------------------------------
254
DEVICE_RESET( tms5501 )
255
-------------------------------------------------*/
257
static DEVICE_RESET( tms5501 )
259
tms5501_t *tms = get_token(device);
262
tms->status &= ~(TMS5501_RCV_BUFFER_LOADED|TMS5501_FULL_BIT_DETECT|TMS5501_START_BIT_DETECT|TMS5501_OVERRUN_ERROR);
263
tms->status |= TMS5501_XMIT_BUFFER_EMPTY|TMS5501_SERIAL_RCVD;
265
tms->pending_interrupts = TMS5501_SERIAL_XMIT_EMPTY_INT;
269
tms->timer_counter[i] = 0;
270
tms->timer[i]->enable(0);
273
LOG_TMS5501(device, "Reset", 0);
277
/*-------------------------------------------------
278
DEVICE_START( tms5501 )
279
-------------------------------------------------*/
281
static DEVICE_START( tms5501 )
284
tms5501_t *tms = get_token(device);
286
for (i = 0; i < 5; i++)
288
tms->timer[i] = device->machine().scheduler().timer_alloc(FUNC(tms5501_timer_decrementer_callback), (void *) device);
289
tms->timer[i]->set_param(i);
292
tms->interrupt_mask = 0;
293
tms->interrupt_address = 0;
297
tms->sio_input_buffer = 0;
298
tms->sio_output_buffer = 0;
299
tms->pio_input_buffer = 0;
300
tms->pio_output_buffer = 0;
303
LOG_TMS5501(device, "Init", 0);
307
/*-------------------------------------------------
308
tms5501_set_pio_bit_7
309
-------------------------------------------------*/
311
void tms5501_set_pio_bit_7 (device_t *device, UINT8 data)
313
tms5501_t *tms = get_token(device);
315
if (tms->command & TMS5501_INT_7_SELECT)
317
if (!(tms->pio_input_buffer & TMS5501_PIO_INT_7) && data)
318
tms->pending_interrupts |= TMS5501_INT_7_INT;
320
tms->pending_interrupts &= ~TMS5501_INT_7_INT;
323
tms->pio_input_buffer &= ~TMS5501_PIO_INT_7;
325
tms->pio_input_buffer |= TMS5501_PIO_INT_7;
327
if (tms->pending_interrupts & TMS5501_INT_7_INT)
328
tms5501_field_interrupts(device);
332
/*-------------------------------------------------
334
-------------------------------------------------*/
336
void tms5501_sensor (device_t *device, UINT8 data)
338
tms5501_t *tms = get_token(device);
340
if (!(tms->sensor) && data)
341
tms->pending_interrupts |= TMS5501_SENSOR_INT;
343
tms->pending_interrupts &= ~TMS5501_SENSOR_INT;
347
if (tms->pending_interrupts &= TMS5501_SENSOR_INT)
348
tms5501_field_interrupts(device);
352
/*-------------------------------------------------
353
READ8_DEVICE_HANDLER( tms5501_r )
354
-------------------------------------------------*/
356
READ8_DEVICE_HANDLER( tms5501_r )
358
tms5501_t *tms = get_token(device);
359
const tms5501_interface *intf = get_interface(device);
366
case 0x00: /* Serial input buffer */
367
data = tms->sio_input_buffer;
368
tms->status &= ~TMS5501_RCV_BUFFER_LOADED;
369
LOG_TMS5501(device, "Reading from serial input buffer", data);
371
case 0x01: /* PIO input port */
372
if (intf->pio_read_callback)
373
data = (*intf->pio_read_callback)(device);
374
LOG_TMS5501(device, "Reading from PIO", data);
376
case 0x02: /* Interrupt address register */
377
data = tms->interrupt_address;
378
tms->status &= ~TMS5501_INTERRUPT_PENDING;
380
case 0x03: /* Status register */
383
case 0x04: /* Command register */
385
LOG_TMS5501(device, "Command register read", data);
387
case 0x05: /* Serial rate register */
388
data = tms->sio_rate;
389
LOG_TMS5501(device, "Serial rate read", data);
391
case 0x06: /* Serial output buffer */
392
case 0x07: /* PIO output */
394
case 0x08: /* Interrupt mask register */
395
data = tms->interrupt_mask;
396
LOG_TMS5501(device, "Interrupt mask read", data);
398
case 0x09: /* Timer 0 address */
399
case 0x0a: /* Timer 1 address */
400
case 0x0b: /* Timer 2 address */
401
case 0x0c: /* Timer 3 address */
402
case 0x0d: /* Timer 4 address */
409
/*-------------------------------------------------
410
WRITE8_DEVICE_HANDLER( tms5501_w )
411
-------------------------------------------------*/
413
WRITE8_DEVICE_HANDLER( tms5501_w )
415
tms5501_t *tms = get_token(device);
416
const tms5501_interface *intf = get_interface(device);
421
case 0x00: /* Serial input buffer */
422
case 0x01: /* Keyboard input port, Page blanking signal */
423
case 0x02: /* Interrupt address register */
424
case 0x03: /* Status register */
425
LOG_TMS5501(device, "Writing to read only port", offset&0x000f);
426
LOG_TMS5501(device, "Data", data);
431
bit 1: send break, '1' - serial output is high impedance
432
bit 2: int 7 select: '0' - timer 5, '1' - IN7 of the DCE-bus
433
bit 3: int ack enable, '0' - disabled, '1' - enabled
434
bits 4-5: test bits, normally '0'
435
bits 6-7: not used, normally '0'
436
bits 1-5 are latched */
438
tms->command = data & TMS5501_COMMAND_LATCHED_BITS;
439
LOG_TMS5501(device, "Command register write", data);
441
if (data & TMS5501_RESET)
445
/* Serial rate register
453
bit 7: '0' - two stop bits, '1' - one stop bit */
455
tms->sio_rate = data;
456
LOG_TMS5501(device, "Serial rate write", data);
458
case 0x06: /* Serial output buffer */
459
tms->sio_output_buffer = data;
460
LOG_TMS5501(device, "Serial output data", data);
462
case 0x07: /* PIO output */
463
tms->pio_output_buffer = data;
464
if (intf->pio_write_callback)
465
(*intf->pio_write_callback)(device, tms->pio_output_buffer);
466
LOG_TMS5501(device, "Writing to PIO", data);
469
/* Interrupt mask register
470
bit 0: Timer 1 has expired (UTIM)
471
bit 1: Timer 2 has expired
472
bit 2: External interrupt (STKIM)
473
bit 3: Timer 3 has expired (SNDIM)
474
bit 4: Serial receiver loaded
475
bit 5: Serial transmitter empty
476
bit 6: Timer 4 has expired (KBIM)
477
bit 7: Timer 5 has expired or IN7 (CLKIM) */
479
tms->interrupt_mask = data;
480
LOG_TMS5501(device, "Interrupt mask write", data);
482
case 0x09: /* Timer 0 counter */
483
case 0x0a: /* Timer 1 counter */
484
case 0x0b: /* Timer 2 counter */
485
case 0x0c: /* Timer 3 counter */
486
case 0x0d: /* Timer 4 counter */
488
tms->timer_counter[offset] = data;
489
tms5501_timer_reload(device, offset);
490
LOG_TMS5501(device, "Write timer", offset);
491
LOG_TMS5501(device, "Timer counter set", data);
497
/*-------------------------------------------------
498
DEVICE_GET_INFO( tms5501 )
499
-------------------------------------------------*/
501
DEVICE_GET_INFO( tms5501 )
505
/* --- the following bits of info are returned as 64-bit signed integers --- */
506
case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(tms5501_t); break;
507
case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
509
/* --- the following bits of info are returned as pointers to data or functions --- */
510
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(tms5501); break;
511
case DEVINFO_FCT_STOP: /* Nothing */ break;
512
case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(tms5501); break;
514
/* --- the following bits of info are returned as NULL-terminated strings --- */
515
case DEVINFO_STR_NAME: strcpy(info->s, "TMS5501"); break;
516
case DEVINFO_STR_FAMILY: strcpy(info->s, "TMS5501"); break;
517
case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
518
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
519
case DEVINFO_STR_CREDITS: /* Nothing */ break;
523
DEFINE_LEGACY_DEVICE(TMS5501, tms5501);