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

« back to all changes in this revision

Viewing changes to src/midi.c

  • Committer: Bazaar Package Importer
  • Author(s): Laszlo Boszormenyi (GCS)
  • Date: 2009-03-31 00:37:15 UTC
  • mfrom: (1.1.7 upstream) (9.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20090331003715-i5yisvcfv7mgz3eh
Tags: 2.1.dfsg-1
* New major upstream release (closes: #495937).
* Add desktop files (closes: #501181).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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