~ubuntu-branches/ubuntu/raring/vice/raring

1.2.2 by Laszlo Boszormenyi (GCS)
Import upstream version 2.1.dfsg
1
/*
2
 * midi.c - MIDI (6850 UART) emulation.
3
 *
4
 * Written by
5
 *  Hannu Nuotio <hannu.nuotio@tut.fi>
6
 *
7
 * Based on code by
8
 *  André Fachat <fachat@physik.tu-chemnitz.de>
9
 *
10
 * This file is part of VICE, the Versatile Commodore Emulator.
11
 * See README for copyright notice.
12
 *
13
 *  This program is free software; you can redistribute it and/or modify
14
 *  it under the terms of the GNU General Public License as published by
15
 *  the Free Software Foundation; either version 2 of the License, or
16
 *  (at your option) any later version.
17
 *
18
 *  This program is distributed in the hope that it will be useful,
19
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 *  GNU General Public License for more details.
22
 *
23
 *  You should have received a copy of the GNU General Public License
24
 *  along with this program; if not, write to the Free Software
25
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26
 *  02111-1307  USA.
27
 *
28
 */
29
30
#include "vice.h"
31
32
#ifdef HAVE_MIDI
33
#include <stdio.h>
34
35
#include "alarm.h"
36
#include "archdep.h"
37
#include "clkguard.h"
38
#include "cmdline.h"
39
#include "interrupt.h"
40
#include "lib.h"
41
#include "log.h"
42
#include "machine.h"
43
#include "maincpu.h"
44
#include "midi.h"
45
#include "mididrv.h"
46
#include "resources.h"
47
#include "translate.h"
48
#include "types.h"
49
#include "util.h"
50
51
#undef DEBUG
52
53
/******************************************************************/
54
55
/* - Control register */
56
/* Receive Interrupt Enable */
57
#define MIDI_CTRL_RIE   0x80
58
/* Transmit Control */
59
#define MIDI_CTRL_TC2   0x40
60
#define MIDI_CTRL_TC1   0x20
61
#define MIDI_CTRL_TC(x)  (((MIDI_CTRL_TC2 | MIDI_CTRL_TC1) & x) >> 5)
62
/* Word Select */
63
#define MIDI_CTRL_WS3   0x10
64
#define MIDI_CTRL_WS2   0x08
65
#define MIDI_CTRL_WS1   0x04
66
#define MIDI_CTRL_WS(x)  (((MIDI_CTRL_WS3 | MIDI_CTRL_WS2 | MIDI_CTRL_WS1) & x) >> 2)
67
/* Counter Divide Select */
68
#define MIDI_CTRL_CD2   0x02
69
#define MIDI_CTRL_CD1   0x01
70
#define MIDI_CTRL_CD(x)  ((MIDI_CTRL_CD2 | MIDI_CTRL_CD1) & x)
71
#define MIDI_CTRL_RESET 0x03
72
/* Defaults after reset */
73
#define MIDI_CTRL_DEFAULT   (MIDI_CTRL_RESET)
74
75
/* - Status register */
76
/* Interrupt Request */
77
#define MIDI_STATUS_IRQ  0x80
78
/* Parity Error */
79
#define MIDI_STATUS_PE   0x40
80
/* Receiver Overrun */
81
#define MIDI_STATUS_OVRN 0x20
82
/* Framing Error */
83
#define MIDI_STATUS_FE   0x10
84
/* Clear to Send */
85
#define MIDI_STATUS_CTS  0x08
86
/* Data Carrier Detect */
87
#define MIDI_STATUS_DCD  0x04
88
/* Transmit Data Register Empty */
89
#define MIDI_STATUS_TDRE 0x02
90
/* Receive Data Register Full */
91
#define MIDI_STATUS_RDRF 0x01
92
/* Defaults after reset */
93
#define MIDI_STATUS_DEFAULT  (MIDI_STATUS_TDRE)
94
95
/******************************************************************/
96
97
int midi_enabled = 0;
98
99
static int fd_in = -1;
100
static int fd_out = -1;
101
102
static alarm_t *midi_alarm = NULL;
103
static unsigned int midi_int_num;
104
105
static int midi_ticks = 0; /* number of clock ticks per char */
106
static int intx = 0;    /* indicates that a transmit is currently ongoing */
107
static int irq = 0;
108
static BYTE ctrl;       /* control register */
109
static BYTE status;     /* status register */
110
static BYTE rxdata;     /* data that has been received last */
111
static BYTE txdata;     /* data prepared to send */
112
static int alarm_active = 0;    /* if alarm is set or not */
113
114
static log_t midi_log = LOG_ERR;
115
116
static void int_midi(CLOCK offset, void *data);
117
118
static BYTE midi_last_read = 0;  /* the byte read the last time (for RMW) */
119
120
/******************************************************************/
121
122
static CLOCK midi_alarm_clk = 0;
123
124
static int midi_irq = IK_NONE;
125
static int midi_irq_res;
126
int midi_mode = 0;
127
128
/******************************************************************/
129
130
static void midi_set_int(int midiirq, unsigned int int_num, int value)
131
{
132
    if(midiirq == IK_IRQ) {
133
        maincpu_set_irq(int_num, value);
134
    }
135
    if(midiirq == IK_NMI) {
136
        maincpu_set_nmi(int_num, value);
137
    }
138
}
139
140
static int midi_set_irq(int new_irq_res, void *param)
141
{
142
    int new_irq;
143
    static const int irq_tab[] = { IK_NONE, IK_IRQ, IK_NMI };
144
145
    if (new_irq_res < 0 || new_irq_res > 2) {
146
        return -1;
147
    }
148
149
    new_irq = irq_tab[new_irq_res];
150
151
    if(midi_irq != new_irq) {
152
        midi_set_int(midi_irq, midi_int_num, IK_NONE);
153
        if(irq) {
154
            midi_set_int(new_irq, midi_int_num, new_irq);
155
        }
156
    }
157
    midi_irq = new_irq;
158
    midi_irq_res = new_irq_res;
159
160
    return 0;
161
}
162
163
static int get_midi_ticks(void)
164
{
165
    return (int)(machine_get_cycles_per_second() / 31250);
166
}
167
168
int midi_set_mode(int new_mode, void *param)
169
{
170
    if(new_mode < 0 || new_mode > 4) {
171
        return -1;
172
    }
173
174
    if(midi_set_irq(midi_interface[new_mode].irq_type, 0)) {
175
        return -1;
176
    }
177
178
    midi_mode = new_mode;
179
180
    midi_ticks = get_midi_ticks();
181
182
    return 0;
183
}
184
185
static int set_midi_enabled(int val, void *param)
186
{
187
    midi_enabled = val;
188
    return 0;
189
}
190
191
static const resource_int_t resources_int[] = {
192
    { "MIDIEnable", 0, RES_EVENT_STRICT, (resource_value_t)0,
193
      &midi_enabled, set_midi_enabled, NULL },
194
    { NULL }
195
};
196
197
int midi_resources_init(void)
198
{
199
    if (resources_register_int(resources_int) < 0) {
200
        return -1;
201
    }
202
203
    return mididrv_resources_init();
204
}
205
206
void midi_resources_shutdown(void)
207
{
208
    mididrv_resources_shutdown();
209
}
210
211
static const cmdline_option_t cmdline_options[] = {
212
    { "-midi", SET_RESOURCE, 0,
213
      NULL, NULL, "MIDIEnable", (resource_value_t)1,
214
      USE_PARAM_STRING, USE_DESCRIPTION_ID,
215
      IDCLS_UNUSED, IDCLS_ENABLE_MIDI_EMU,
216
      NULL, NULL },
217
    { "+midi", SET_RESOURCE, 0,
218
      NULL, NULL, "MIDIEnable", (resource_value_t)0,
219
      USE_PARAM_STRING, USE_DESCRIPTION_ID,
220
      IDCLS_UNUSED, IDCLS_DISABLE_MIDI_EMU,
221
      NULL, NULL },
222
    { NULL }
223
};
224
225
int midi_cmdline_options_init(void)
226
{
227
    if (cmdline_register_options(cmdline_options) < 0) {
228
        return -1;
229
    }
230
231
    return mididrv_cmdline_options_init();
232
}
233
234
/******************************************************************/
235
236
static void clk_overflow_callback(CLOCK sub, void *var)
237
{
238
    if(alarm_active) {
239
        midi_alarm_clk -= sub;
240
    }
241
}
242
243
void midi_init(void)
244
{
245
    midi_int_num = interrupt_cpu_status_int_new(maincpu_int_status, "MIDI");
246
247
    midi_alarm = alarm_new(maincpu_alarm_context, "MIDI", int_midi, NULL);
248
249
    clk_guard_add_callback(maincpu_clk_guard, clk_overflow_callback, NULL);
250
251
    if(midi_log == LOG_ERR) {
252
        midi_log = log_open("MIDI");
253
    }
254
    mididrv_init();
255
    midi_reset();
256
}
257
258
259
static void midi_suspend(void)
260
{
261
#ifdef DEBUG
262
    log_message(midi_log, "suspend");
263
#endif
264
    status = MIDI_STATUS_DEFAULT;
265
    intx = 0;
266
267
    if(fd_in >= 0) {
268
        mididrv_in_close();
269
    }
270
    fd_in = -1;
271
272
    if(fd_out >= 0) {
273
        mididrv_out_close();
274
    }
275
    fd_out = -1;
276
277
    alarm_unset(midi_alarm);
278
    alarm_active = 0;
279
    intx = 0;
280
281
    midi_set_int(midi_irq, midi_int_num, 0);
282
    irq = 0;
283
}
284
285
void midi_reset(void)
286
{
287
#ifdef DEBUG
288
    log_message(midi_log, "reset");
289
#endif
290
    ctrl = MIDI_CTRL_DEFAULT;
291
    midi_ticks = get_midi_ticks();
292
    midi_suspend();
293
}
294
295
static void midi_activate(void)
296
{
297
#ifdef DEBUG
298
    log_message(midi_log, "activate");
299
#endif
300
    fd_in = mididrv_in_open();
301
    fd_out = mididrv_out_open();
302
    if(!intx) {
303
        midi_alarm_clk = maincpu_clk + 1;
304
        alarm_set(midi_alarm, midi_alarm_clk);
305
        alarm_active = 1;
306
    }
307
}
308
309
void REGPARM2 midi_store(WORD a, BYTE b)
310
{
311
#ifdef DEBUG
312
    log_message(midi_log, "store(%x,%02x)", a, b);
313
#endif
314
    if(maincpu_rmw_flag) {
315
        maincpu_clk--;
316
        maincpu_rmw_flag = 0;
317
        midi_store(a, midi_last_read);
318
        maincpu_clk++;
319
    }
320
321
    a &= midi_interface[midi_mode].mask;
322
323
    if(a == midi_interface[midi_mode].ctrl_addr) {
324
#ifdef DEBUG
325
        log_message(midi_log, "store ctrl: %02x", b);
326
#endif
327
        ctrl = b;
328
        midi_ticks = get_midi_ticks();
329
330
        if(MIDI_CTRL_CD(ctrl) == midi_interface[midi_mode].midi_cd) {
331
            /* TODO check WS */
332
            midi_activate();
333
        } else if(MIDI_CTRL_CD(ctrl) == MIDI_CTRL_RESET) {
334
            midi_reset();
335
        } else {
336
            midi_suspend();
337
        }
338
    } else if(a == midi_interface[midi_mode].tx_addr) {
339
        status &= ~MIDI_STATUS_IRQ;
340
#ifdef DEBUG
341
        log_message(midi_log, "store tx: %02x", b);
342
#endif
343
        if((status & MIDI_STATUS_TDRE) && !(MIDI_CTRL_CD(ctrl) == MIDI_CTRL_RESET)) {
344
            status &= ~MIDI_STATUS_TDRE;
345
            txdata = b;
346
            if(!intx) {
347
                midi_alarm_clk = maincpu_clk + 1;
348
                alarm_set(midi_alarm, midi_alarm_clk);
349
                alarm_active = 1;
350
                intx = 2;
351
            } else {
352
                if(intx == 1) {
353
                    intx++;
354
                }
355
            }
356
        }
357
    }
358
}
359
360
BYTE REGPARM1 midi_read(WORD a)
361
{
362
#ifdef DEBUG
363
    log_message(midi_log, "read(%x)", a);
364
#endif
365
    midi_last_read = 0xff;
366
    a &= midi_interface[midi_mode].mask;
367
368
    if(a == midi_interface[midi_mode].status_addr) {
369
#ifdef DEBUG
370
        log_message(midi_log, "read status: %02x", status);
371
#endif
372
        midi_last_read = status;
373
    } else if(a == midi_interface[midi_mode].rx_addr) {
374
#ifdef DEBUG
375
        log_message(midi_log, "read rx: %02x (%02x)", rxdata, status);
376
#endif
377
        status &= ~MIDI_STATUS_OVRN;
378
        if(irq) {
379
            status &= ~MIDI_STATUS_IRQ;
380
            midi_set_int(midi_irq, midi_int_num, 0);
381
            irq = 0;
382
        }
383
        if(status & MIDI_STATUS_RDRF) {
384
            status &= ~MIDI_STATUS_RDRF;
385
            midi_last_read = rxdata;
386
        }
387
    }
388
389
    return midi_last_read;
390
}
391
392
int REGPARM1 midi_test_read(WORD a)
393
{
394
    a &= midi_interface[midi_mode].mask;
395
396
    return ((a == midi_interface[midi_mode].status_addr)
397
          ||(a == midi_interface[midi_mode].rx_addr));
398
}
399
400
static void int_midi(CLOCK offset, void *data)
401
{
402
    int rxirq = 0;
403
404
#if 0 /*def DEBUG */
405
    log_message(midi_log, "int_midi(offset=%ld, clk=%d", (long int)offset, (int)maincpu_clk);
406
#endif
407
    if((intx == 2) && (fd_out >= 0)) {
408
        mididrv_out(txdata);
409
    }
410
411
    if(intx) {
412
        intx--;
413
    }
414
415
    if((fd_in >= 0) && (!(status & MIDI_STATUS_RDRF)) && (mididrv_in(&rxdata) == 1)) {
416
        status |= MIDI_STATUS_RDRF;
417
        rxirq = 1;
418
#ifdef DEBUG
419
       log_message(midi_log, "int got %02x", rxdata);
420
#endif
421
    }
422
423
    if(rxirq && (ctrl & MIDI_CTRL_RIE)) {
424
        midi_set_int(midi_irq, midi_int_num, 1);
425
        status |= MIDI_STATUS_IRQ;
426
        irq = 1;
427
#ifdef DEBUG
428
        log_message(midi_log, "int_midi IRQ offset=%ld, clk=%d", (long int)offset, (int)maincpu_clk);
429
#endif
430
    }
431
432
    if(status & MIDI_STATUS_TDRE) {
433
        status |= MIDI_STATUS_TDRE;
434
        /* TODO: TX IRQ */
435
    }
436
437
    midi_alarm_clk = maincpu_clk + midi_ticks;
438
    alarm_set(midi_alarm, midi_alarm_clk);
439
    alarm_active = 1;
440
}
441
442
#endif