2
* midi.c - MIDI (6850 UART) emulation.
5
* Hannu Nuotio <hannu.nuotio@tut.fi>
8
* Andr� Fachat <fachat@physik.tu-chemnitz.de>
10
* This file is part of VICE, the Versatile Commodore Emulator.
11
* See README for copyright notice.
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.
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.
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
39
#include "interrupt.h"
46
#include "resources.h"
47
#include "translate.h"
53
/******************************************************************/
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)
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)
75
/* - Status register */
76
/* Interrupt Request */
77
#define MIDI_STATUS_IRQ 0x80
79
#define MIDI_STATUS_PE 0x40
80
/* Receiver Overrun */
81
#define MIDI_STATUS_OVRN 0x20
83
#define MIDI_STATUS_FE 0x10
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)
95
/******************************************************************/
99
static int fd_in = -1;
100
static int fd_out = -1;
102
static alarm_t *midi_alarm = NULL;
103
static unsigned int midi_int_num;
105
static int midi_ticks = 0; /* number of clock ticks per char */
106
static int intx = 0; /* indicates that a transmit is currently ongoing */
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 */
114
static log_t midi_log = LOG_ERR;
116
static void int_midi(CLOCK offset, void *data);
118
static BYTE midi_last_read = 0; /* the byte read the last time (for RMW) */
120
/******************************************************************/
122
static CLOCK midi_alarm_clk = 0;
124
static int midi_irq = IK_NONE;
125
static int midi_irq_res;
128
/******************************************************************/
130
static void midi_set_int(int midiirq, unsigned int int_num, int value)
132
if(midiirq == IK_IRQ) {
133
maincpu_set_irq(int_num, value);
135
if(midiirq == IK_NMI) {
136
maincpu_set_nmi(int_num, value);
140
static int midi_set_irq(int new_irq_res, void *param)
143
static const int irq_tab[] = { IK_NONE, IK_IRQ, IK_NMI };
145
if (new_irq_res < 0 || new_irq_res > 2) {
149
new_irq = irq_tab[new_irq_res];
151
if(midi_irq != new_irq) {
152
midi_set_int(midi_irq, midi_int_num, IK_NONE);
154
midi_set_int(new_irq, midi_int_num, new_irq);
158
midi_irq_res = new_irq_res;
163
static int get_midi_ticks(void)
165
return (int)(machine_get_cycles_per_second() / 31250);
168
int midi_set_mode(int new_mode, void *param)
170
if(new_mode < 0 || new_mode > 4) {
174
if(midi_set_irq(midi_interface[new_mode].irq_type, 0)) {
178
midi_mode = new_mode;
180
midi_ticks = get_midi_ticks();
185
static int set_midi_enabled(int val, void *param)
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 },
197
int midi_resources_init(void)
199
if (resources_register_int(resources_int) < 0) {
203
return mididrv_resources_init();
206
void midi_resources_shutdown(void)
208
mididrv_resources_shutdown();
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,
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,
225
int midi_cmdline_options_init(void)
227
if (cmdline_register_options(cmdline_options) < 0) {
231
return mididrv_cmdline_options_init();
234
/******************************************************************/
236
static void clk_overflow_callback(CLOCK sub, void *var)
239
midi_alarm_clk -= sub;
245
midi_int_num = interrupt_cpu_status_int_new(maincpu_int_status, "MIDI");
247
midi_alarm = alarm_new(maincpu_alarm_context, "MIDI", int_midi, NULL);
249
clk_guard_add_callback(maincpu_clk_guard, clk_overflow_callback, NULL);
251
if(midi_log == LOG_ERR) {
252
midi_log = log_open("MIDI");
259
static void midi_suspend(void)
262
log_message(midi_log, "suspend");
264
status = MIDI_STATUS_DEFAULT;
277
alarm_unset(midi_alarm);
281
midi_set_int(midi_irq, midi_int_num, 0);
285
void midi_reset(void)
288
log_message(midi_log, "reset");
290
ctrl = MIDI_CTRL_DEFAULT;
291
midi_ticks = get_midi_ticks();
295
static void midi_activate(void)
298
log_message(midi_log, "activate");
300
fd_in = mididrv_in_open();
301
fd_out = mididrv_out_open();
303
midi_alarm_clk = maincpu_clk + 1;
304
alarm_set(midi_alarm, midi_alarm_clk);
309
void REGPARM2 midi_store(WORD a, BYTE b)
312
log_message(midi_log, "store(%x,%02x)", a, b);
314
if(maincpu_rmw_flag) {
316
maincpu_rmw_flag = 0;
317
midi_store(a, midi_last_read);
321
a &= midi_interface[midi_mode].mask;
323
if(a == midi_interface[midi_mode].ctrl_addr) {
325
log_message(midi_log, "store ctrl: %02x", b);
328
midi_ticks = get_midi_ticks();
330
if(MIDI_CTRL_CD(ctrl) == midi_interface[midi_mode].midi_cd) {
333
} else if(MIDI_CTRL_CD(ctrl) == MIDI_CTRL_RESET) {
338
} else if(a == midi_interface[midi_mode].tx_addr) {
339
status &= ~MIDI_STATUS_IRQ;
341
log_message(midi_log, "store tx: %02x", b);
343
if((status & MIDI_STATUS_TDRE) && !(MIDI_CTRL_CD(ctrl) == MIDI_CTRL_RESET)) {
344
status &= ~MIDI_STATUS_TDRE;
347
midi_alarm_clk = maincpu_clk + 1;
348
alarm_set(midi_alarm, midi_alarm_clk);
360
BYTE REGPARM1 midi_read(WORD a)
363
log_message(midi_log, "read(%x)", a);
365
midi_last_read = 0xff;
366
a &= midi_interface[midi_mode].mask;
368
if(a == midi_interface[midi_mode].status_addr) {
370
log_message(midi_log, "read status: %02x", status);
372
midi_last_read = status;
373
} else if(a == midi_interface[midi_mode].rx_addr) {
375
log_message(midi_log, "read rx: %02x (%02x)", rxdata, status);
377
status &= ~MIDI_STATUS_OVRN;
379
status &= ~MIDI_STATUS_IRQ;
380
midi_set_int(midi_irq, midi_int_num, 0);
383
if(status & MIDI_STATUS_RDRF) {
384
status &= ~MIDI_STATUS_RDRF;
385
midi_last_read = rxdata;
389
return midi_last_read;
392
int REGPARM1 midi_test_read(WORD a)
394
a &= midi_interface[midi_mode].mask;
396
return ((a == midi_interface[midi_mode].status_addr)
397
||(a == midi_interface[midi_mode].rx_addr));
400
static void int_midi(CLOCK offset, void *data)
405
log_message(midi_log, "int_midi(offset=%ld, clk=%d", (long int)offset, (int)maincpu_clk);
407
if((intx == 2) && (fd_out >= 0)) {
415
if((fd_in >= 0) && (!(status & MIDI_STATUS_RDRF)) && (mididrv_in(&rxdata) == 1)) {
416
status |= MIDI_STATUS_RDRF;
419
log_message(midi_log, "int got %02x", rxdata);
423
if(rxirq && (ctrl & MIDI_CTRL_RIE)) {
424
midi_set_int(midi_irq, midi_int_num, 1);
425
status |= MIDI_STATUS_IRQ;
428
log_message(midi_log, "int_midi IRQ offset=%ld, clk=%d", (long int)offset, (int)maincpu_clk);
432
if(status & MIDI_STATUS_TDRE) {
433
status |= MIDI_STATUS_TDRE;
437
midi_alarm_clk = maincpu_clk + midi_ticks;
438
alarm_set(midi_alarm, midi_alarm_clk);