OXYGENHUB
◆ main x16-emulator / src / midi.c
38.0 KiB · C · last changed chore(): initial commit 15 days ago source blame history raw
03a3459e Andy McCall 1
// Commander X16 Emulator
2
// Copyright (c) 2024 MooingLemur
3
// All rights reserved. License: 2-clause BSD
4
5
#include <pthread.h>
6
#include <stdio.h>
7
#include "glue.h"
8
#include "midi.h"
9
#include "audio.h"
10
#include "endian.h"
11
12
#ifdef _WIN32
13
    #include <windows.h>
14
    #define LIBRARY_TYPE HMODULE
15
    #define LOAD_LIBRARY(name) LoadLibrary(name)
16
    #define GET_FUNCTION(lib, name) (void *)GetProcAddress(lib, name)
17
    #define CLOSE_LIBRARY(lib) FreeLibrary(lib)
18
#else
19
    #include <dlfcn.h>
20
    #define LIBRARY_TYPE void*
21
    #define LOAD_LIBRARY(name) dlopen(name, RTLD_LAZY)
22
    #define GET_FUNCTION(lib, name) dlsym(lib, name)
23
    #define CLOSE_LIBRARY(lib) dlclose(lib)
24
#endif
25
26
#define ASSIGN_FUNCTION(lib, var, name) {\
27
    var = GET_FUNCTION(lib, name);\
28
    if (!var) { fprintf(stderr, "Unable to find symbol for '%s'\n", name); CLOSE_LIBRARY(handle); return; }\
29
}
30
31
enum MIDI_states {
32
    MSTATE_Normal,
33
    MSTATE_Param,
34
    MSTATE_SysEx,
35
};
36
37
struct midi_serial_regs
38
{
39
    LOW_HIGH_UNION(dl, dll, dlm);
40
41
    bool ier_erbi;
42
    bool ier_etbei;
43
    bool ier_elsi;
44
    bool ier_edssi;
45
46
    uint8_t iir;
47
48
    bool fcr_fifo_enable;
49
    uint8_t fcr_ififo_trigger_level_bytes;
50
51
    uint8_t lcr_word_length_bits;
52
    bool lcr_stb;
53
    bool lcr_pen;
54
    bool lcr_eps;
55
    bool lcr_stick;
56
    bool lcr_break;
57
    bool lcr_dlab;
58
59
    bool mcr_dtr;
60
    bool mcr_rts;
61
    bool mcr_out1;
62
    bool mcr_out2;
63
    bool mcr_loop;
64
    bool mcr_afe;
65
66
    bool lsr_oe;
67
    bool lsr_pe;
68
    bool lsr_fe;
69
    bool lsr_bi;
70
    bool lsr_eif;
71
72
    bool msr_dcts;
73
    bool msr_ddsr;
74
    bool msr_teri;
75
    bool msr_ddcd;
76
    bool msr_cts;
77
    bool msr_dsr;
78
    bool msr_ri;
79
    bool msr_dcd;
80
81
    uint8_t obyte_bits_remain;
82
    uint8_t ibyte_bits_remain;
83
    uint8_t rx_timeout;
84
    bool rx_timeout_enabled;
85
86
    bool thre_intr;
87
    uint8_t thre_bits_remain;
88
89
    uint8_t scratch;
90
    uint8_t ififo[16];
91
    uint8_t ifsz;
92
    uint8_t ofifo[16];
93
    uint8_t ofsz;
94
95
    int64_t clock; // 40.24 fixed point
96
    int32_t clockdec; // 8.24 fixed point
97
98
    time_t last_warning;
99
100
    uint8_t midi_event_fifo[256];
101
    int mfsz;
102
    uint8_t in_midi_last_command;
103
104
    pthread_mutex_t fifo_mutex;
105
    pthread_mutexattr_t fifo_mutex_attr;
106
};
107
108
struct midi_serial_regs mregs[2];
109
static bool serial_midi_mutexes_initialized = false;
110
111
void midi_serial_iir_check(uint8_t sel);
112
bool fs_midi_in_connect = false;
113
114
#ifdef HAS_FLUIDSYNTH
115
116
int handle_midi_event(void* data, fluid_midi_event_t* event);
117
118
static uint8_t sysex_buffer[1024];
119
static int sysex_bufptr;
120
121
static enum MIDI_states midi_state[2] = {MSTATE_Normal, MSTATE_Normal};
122
static uint8_t out_midi_last_command[2] = {0, 0};
123
static uint8_t out_midi_first_param[2];
124
static uint16_t out_midi_nrpn[2][16];
125
static uint16_t out_midi_rpn[2][16];
126
static bool out_midi_nrpn_active[2][16];
127
128
static bool midi_initialized = false;
129
130
static fluid_settings_t* fl_settings;
131
static fluid_midi_driver_t* fl_mdriver;
132
static fluid_synth_t* fl_synth;
133
static int fl_sf2id;
134
135
typedef fluid_settings_t* (*new_fluid_settings_f_t)(void);
136
typedef fluid_synth_t* (*new_fluid_synth_f_t)(fluid_settings_t*);
137
typedef fluid_audio_driver_t* (*new_fluid_audio_driver_f_t)(fluid_settings_t*, fluid_synth_t*);
138
typedef fluid_midi_driver_t* (*new_fluid_midi_driver_f_t)(fluid_settings_t*, handle_midi_event_func_t, void*);
139
typedef int (*fluid_settings_setnum_f_t)(fluid_settings_t*,const char*, double);
140
typedef int (*fluid_settings_setint_f_t)(fluid_settings_t*,const char*, int);
141
typedef int (*fluid_settings_setstr_f_t)(fluid_settings_t*,const char*, const char*);
142
typedef int (*fluid_synth_sfload_f_t)(fluid_synth_t*, const char *, int);
143
typedef int (*fluid_synth_program_change_f_t)(fluid_synth_t*, int, int);
144
typedef int (*fluid_synth_channel_pressure_f_t)(fluid_synth_t*, int, int);
145
typedef int (*fluid_synth_system_reset_f_t)(fluid_synth_t*);
146
typedef int (*fluid_synth_noteoff_f_t)(fluid_synth_t*, int, int);
147
typedef int (*fluid_synth_noteon_f_t)(fluid_synth_t*, int, int, int);
148
typedef int (*fluid_synth_key_pressure_f_t)(fluid_synth_t*, int, int, int);
149
typedef int (*fluid_synth_cc_f_t)(fluid_synth_t*, int, int, int);
150
typedef int (*fluid_synth_pitch_bend_f_t)(fluid_synth_t*, int, int);
151
typedef int (*fluid_synth_sysex_f_t)(fluid_synth_t*, const char*, int, char*, int*, int*, int);
152
typedef int (*fluid_synth_write_s16_f_t)(fluid_synth_t*, int, void*, int, int, void*, int, int);
153
typedef int (*fluid_midi_event_get_channel_f_t)(const fluid_midi_event_t*);
154
typedef int (*fluid_midi_event_get_control_f_t)(const fluid_midi_event_t*);
155
typedef int (*fluid_midi_event_get_key_f_t)(const fluid_midi_event_t*);
156
typedef int (*fluid_midi_event_get_lyrics_f_t)(const fluid_midi_event_t*, void**, int*);
157
typedef int (*fluid_midi_event_get_pitch_f_t)(const fluid_midi_event_t*);
158
typedef int (*fluid_midi_event_get_program_f_t)(const fluid_midi_event_t*);
159
typedef int (*fluid_midi_event_get_text_f_t)(const fluid_midi_event_t*, void**, int*);
160
typedef int (*fluid_midi_event_get_type_f_t)(const fluid_midi_event_t*);
161
typedef int (*fluid_midi_event_get_value_f_t)(const fluid_midi_event_t*);
162
typedef int (*fluid_midi_event_get_velocity_f_t)(const fluid_midi_event_t*);
163
typedef int (*fluid_midi_event_set_type_f_t)(fluid_midi_event_t*, int);
164
165
static new_fluid_settings_f_t dl_new_fluid_settings;
166
static new_fluid_synth_f_t dl_new_fluid_synth;
167
static new_fluid_audio_driver_f_t dl_new_fluid_audio_driver;
168
static new_fluid_midi_driver_f_t dl_new_fluid_midi_driver;
169
static fluid_settings_setnum_f_t dl_fluid_settings_setnum;
170
static fluid_settings_setint_f_t dl_fluid_settings_setint;
171
static fluid_settings_setstr_f_t dl_fluid_settings_setstr;
172
static fluid_synth_sfload_f_t dl_fs_sfload;
173
static fluid_synth_program_change_f_t dl_fs_program_change;
174
static fluid_synth_channel_pressure_f_t dl_fs_channel_pressure;
175
static fluid_synth_system_reset_f_t dl_fs_system_reset;
176
static fluid_synth_noteoff_f_t dl_fs_noteoff;
177
static fluid_synth_noteon_f_t dl_fs_noteon;
178
static fluid_synth_key_pressure_f_t dl_fs_key_pressure;
179
static fluid_synth_cc_f_t dl_fs_cc;
180
static fluid_synth_pitch_bend_f_t dl_fs_pitch_bend;
181
static fluid_synth_sysex_f_t dl_fs_sysex;
182
static fluid_synth_write_s16_f_t dl_fs_write_s16;
183
static fluid_midi_event_get_channel_f_t dl_fluid_midi_event_get_channel;
184
static fluid_midi_event_get_control_f_t dl_fluid_midi_event_get_control;
185
static fluid_midi_event_get_key_f_t dl_fluid_midi_event_get_key;
186
static fluid_midi_event_get_lyrics_f_t dl_fluid_midi_event_get_lyrics;
187
static fluid_midi_event_get_pitch_f_t dl_fluid_midi_event_get_pitch;
188
static fluid_midi_event_get_program_f_t dl_fluid_midi_event_get_program;
189
static fluid_midi_event_get_text_f_t dl_fluid_midi_event_get_text;
190
static fluid_midi_event_get_type_f_t dl_fluid_midi_event_get_type;
191
static fluid_midi_event_get_value_f_t dl_fluid_midi_event_get_value;
192
static fluid_midi_event_get_velocity_f_t dl_fluid_midi_event_get_velocity;
193
static fluid_midi_event_set_type_f_t dl_fluid_midi_event_set_type;
194
195
196
void midi_init()
197
{
198
    if (midi_initialized) {
199
        return;
200
    }
201
202
#ifdef _WIN32
203
    LIBRARY_TYPE handle = LOAD_LIBRARY("libfluidsynth-3.dll");
204
#elif __APPLE__
205
    LIBRARY_TYPE handle = LOAD_LIBRARY("libfluidsynth.dylib");
206
#else
207
    LIBRARY_TYPE handle = LOAD_LIBRARY("libfluidsynth.so.3");
208
#endif
209
210
    if (!handle) {
211
        // Handle the error on both platforms
212
#ifdef _WIN32
213
        fprintf(stderr, "Could not load MIDI synth library: error code %lu\n", GetLastError());
214
#else
215
        fprintf(stderr, "Could not load MIDI synth library: %s\n", dlerror());
216
#endif
217
        return;
218
    }
219
220
#ifndef _WIN32
221
    dlerror();
222
#endif
223
224
    ASSIGN_FUNCTION(handle, dl_new_fluid_settings, "new_fluid_settings");
225
    ASSIGN_FUNCTION(handle, dl_new_fluid_synth, "new_fluid_synth");
226
    ASSIGN_FUNCTION(handle, dl_new_fluid_audio_driver, "new_fluid_audio_driver");
227
    ASSIGN_FUNCTION(handle, dl_new_fluid_midi_driver, "new_fluid_midi_driver");
228
    ASSIGN_FUNCTION(handle, dl_fluid_settings_setnum, "fluid_settings_setnum");
229
    ASSIGN_FUNCTION(handle, dl_fluid_settings_setint, "fluid_settings_setint");
230
    ASSIGN_FUNCTION(handle, dl_fluid_settings_setstr, "fluid_settings_setstr");
231
    ASSIGN_FUNCTION(handle, dl_fs_sfload, "fluid_synth_sfload");
232
    ASSIGN_FUNCTION(handle, dl_fs_program_change, "fluid_synth_program_change");
233
    ASSIGN_FUNCTION(handle, dl_fs_channel_pressure, "fluid_synth_channel_pressure");
234
    ASSIGN_FUNCTION(handle, dl_fs_system_reset, "fluid_synth_system_reset");
235
    ASSIGN_FUNCTION(handle, dl_fs_noteoff, "fluid_synth_noteoff");
236
    ASSIGN_FUNCTION(handle, dl_fs_noteon, "fluid_synth_noteon");
237
    ASSIGN_FUNCTION(handle, dl_fs_key_pressure, "fluid_synth_key_pressure");
238
    ASSIGN_FUNCTION(handle, dl_fs_cc, "fluid_synth_cc");
239
    ASSIGN_FUNCTION(handle, dl_fs_pitch_bend, "fluid_synth_pitch_bend");
240
    ASSIGN_FUNCTION(handle, dl_fs_sysex, "fluid_synth_sysex");
241
    ASSIGN_FUNCTION(handle, dl_fs_write_s16, "fluid_synth_write_s16");
242
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_channel, "fluid_midi_event_get_channel");
243
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_control, "fluid_midi_event_get_control");
244
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_key, "fluid_midi_event_get_key");
245
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_lyrics, "fluid_midi_event_get_lyrics");
246
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_pitch, "fluid_midi_event_get_pitch");
247
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_program, "fluid_midi_event_get_program");
248
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_text, "fluid_midi_event_get_text");
249
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_type, "fluid_midi_event_get_type");
250
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_value, "fluid_midi_event_get_value");
251
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_velocity, "fluid_midi_event_get_velocity");
252
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_set_type, "fluid_midi_event_set_type");
253
254
    fl_settings = dl_new_fluid_settings();
255
    dl_fluid_settings_setnum(fl_settings, "synth.sample-rate", 
256
    AUDIO_SAMPLERATE);
257
    dl_fluid_settings_setnum(fl_settings, "synth.gain", FL_DEFAULT_GAIN);
258
    dl_fluid_settings_setstr(fl_settings, "midi.portname", "Commander X16 Emulator");
259
    dl_fluid_settings_setint(fl_settings, "midi.autoconnect", fs_midi_in_connect);
260
    fl_synth = dl_new_fluid_synth(fl_settings);
261
    if (fs_midi_in_connect) {
262
        fl_mdriver = dl_new_fluid_midi_driver(fl_settings, handle_midi_event, &mregs[0]);
263
    }
264
265
    midi_initialized = true;
266
    fprintf(stderr, "Initialized MIDI synth at $%04X.\n", midi_card_addr);
267
}
268
269
void midi_load_sf2(uint8_t* filename)
270
{
271
    if (!midi_initialized) return;
272
    fl_sf2id = dl_fs_sfload(fl_synth, (const char *)filename, true);
273
    if (fl_sf2id == FLUID_FAILED) {
274
        fprintf(stderr, "Unable to load soundfont.\n");
275
    }
276
}
277
278
// Receive a byte from client
279
// Store state, or dispatch event
280
void midi_byte_out(uint8_t sel, uint8_t b)
281
{
282
    uint8_t chan = out_midi_last_command[sel] & 0xf;
283
284
    if (!midi_initialized) return;
285
    switch (midi_state[sel]) {
286
        case MSTATE_Normal:
287
            if (b < 0x80) {
288
                if ((out_midi_last_command[sel] & 0xf0) == 0xc0) { // patch change
289
                    dl_fs_program_change(fl_synth, out_midi_last_command[sel] & 0xf, b);
290
                } else if ((out_midi_last_command[sel] & 0xf0) == 0xd0) { // channel pressure
291
                    dl_fs_channel_pressure(fl_synth, out_midi_last_command[sel] & 0xf, b);
292
                } else if (out_midi_last_command[sel] >= 0x80) { // two-param command
293
                    out_midi_first_param[sel] = b;
294
                    midi_state[sel] = MSTATE_Param;
295
                }
296
            } else {
297
                if (b < 0xf0) {
298
                    out_midi_last_command[sel] = b;
299
                } else if (b == 0xf0) {
300
                    sysex_bufptr = 0;
301
                    midi_state[sel] = MSTATE_SysEx;
302
                    out_midi_last_command[sel] = 0;
303
                } else if (b == 0xff) {
304
                    dl_fs_system_reset(fl_synth);
305
                    out_midi_last_command[sel] = 0;
306
                } else if (b < 0xf8) {
307
                    out_midi_last_command[sel] = 0;
308
                }
309
            }
310
            break;
311
        case MSTATE_Param:
312
            switch (out_midi_last_command[sel] & 0xf0) {
313
                case 0x80: // note off
314
                    dl_fs_noteoff(fl_synth, chan, out_midi_first_param[sel]); // no release velocity
315
                    break;
316
                case 0x90: // note on
317
                    if (b == 0) {
318
                        dl_fs_noteoff(fl_synth, chan, out_midi_first_param[sel]);
319
                    } else {
320
                        dl_fs_noteon(fl_synth, chan, out_midi_first_param[sel], b);
321
                    }
322
                    break;
323
                case 0xa0: // aftertouch
324
                    dl_fs_key_pressure(fl_synth, chan, out_midi_first_param[sel], b);
325
                    break;
326
                case 0xb0: // controller
327
                    switch (out_midi_first_param[sel]) {
328
                        case 98:
329
                            out_midi_nrpn_active[sel][chan] = true;
330
                            out_midi_nrpn[sel][chan] = (out_midi_nrpn[sel][chan] & 0x00ff) | (b << 8);
331
                            break;
332
                        case 99:
333
                            out_midi_nrpn_active[sel][chan] = true;
334
                            out_midi_nrpn[sel][chan] = (out_midi_nrpn[sel][chan] & 0xff00) | b;
335
                            break;
336
                        case 100:
337
                            out_midi_nrpn_active[sel][chan] = false;
338
                            out_midi_rpn[sel][chan] = (out_midi_rpn[sel][chan] & 0x00ff) | (b << 8);
339
                            break;
340
                        case 101:
341
                            out_midi_nrpn_active[sel][chan] = false;
342
                            out_midi_rpn[sel][chan] = (out_midi_rpn[sel][chan] & 0xff00) | b;
343
                            break;
344
                    }
345
                    dl_fs_cc(fl_synth, chan, out_midi_first_param[sel], b);
346
                    if (out_midi_nrpn_active[sel][chan] && out_midi_nrpn[sel][chan] == 0x0121 && out_midi_first_param[sel] == 6) {
347
                        dl_fs_cc(fl_synth, chan, 71, b); // Translate NRPN 0x0121 -> Controller 71 (Timbre/Resonance)
348
                    }
349
                    break;
350
                case 0xe0: // pitch bend
351
                    dl_fs_pitch_bend(fl_synth, chan, ((uint16_t)out_midi_first_param[sel]) | (uint16_t)b << 7);
352
                    break;
353
            }
354
            midi_state[sel] = MSTATE_Normal;
355
            break;
356
        case MSTATE_SysEx:
357
            if (b & 0x80) { // any command byte can terminate a SYSEX, not just 0xf7
358
                if (sysex_bufptr < (sizeof(sysex_buffer) / sizeof(sysex_buffer[0]))-1) { // only if buffer didn't fill
359
                    sysex_buffer[sysex_bufptr] = 0;
360
                    if (!strncmp((char *)sysex_buffer, "\x7F\x7F\x04\x01\x00", sysex_bufptr-1)) {
361
                        // Handle Master Volume SysEx
362
                        dl_fluid_settings_setnum(fl_settings, "synth.gain", FL_DEFAULT_GAIN*((float)sysex_buffer[sysex_bufptr-1]/127));
363
                    } else if (!strncmp((char *)sysex_buffer, "\x7E\x7F\x09\x01", sysex_bufptr)) {
364
                        // Handle General MIDI reset SysEx
365
                        dl_fs_system_reset(fl_synth);
366
                    } else {
367
                        dl_fs_sysex(fl_synth, (char *)sysex_buffer, sysex_bufptr, NULL, NULL, NULL, 0);
368
                    }
369
                }
370
                midi_state[sel] = MSTATE_Normal;
371
                return midi_byte_out(sel, b);
372
            } else {
373
                sysex_buffer[sysex_bufptr] = b;
374
                // we can't do much about a runaway sysex other than continue to absorb it
375
                // but we throw it all away later if the buffer filled
376
                if (sysex_bufptr < (sizeof(sysex_buffer) / sizeof(sysex_buffer[0]))-1) {
377
                    sysex_bufptr++;
378
                }
379
            }
380
            break;
381
    }
382
}
383
384
void midi_synth_render(int16_t* buf, int len)
385
{
386
    if (midi_initialized) {
387
        dl_fs_write_s16(fl_synth, len, buf, 0, 2, buf, 1, 2);
388
    } else {
389
        memset(buf, 0, len * 2 * sizeof(int16_t));
390
    }
391
}
392
393
void midi_event_enqueue_byte(struct midi_serial_regs* mrp, uint8_t val)
394
{
395
    if (mrp->mfsz >= 256) return;
396
    mrp->midi_event_fifo[mrp->mfsz++] = val;
397
}
398
399
void midi_event_enqueue_short(struct midi_serial_regs* mrp, uint8_t cmd, uint8_t val)
400
{
401
    if (mrp->mfsz >= 255) {
402
        mrp->in_midi_last_command = 0;
403
        return;
404
    }
405
    if (mrp->in_midi_last_command != cmd) {
406
        mrp->midi_event_fifo[mrp->mfsz++] = cmd;
407
        mrp->in_midi_last_command = cmd;
408
    }
409
    mrp->midi_event_fifo[mrp->mfsz++] = val;
410
}
411
412
void midi_event_enqueue_normal(struct midi_serial_regs* mrp, uint8_t cmd, uint8_t key, uint8_t val)
413
{
414
    if (mrp->mfsz >= 254) {
415
        mrp->in_midi_last_command = 0;
416
        return;
417
    }
418
    if (mrp->in_midi_last_command != cmd) {
419
        mrp->midi_event_fifo[mrp->mfsz++] = cmd;
420
        mrp->in_midi_last_command = cmd;
421
    }
422
    mrp->midi_event_fifo[mrp->mfsz++] = key;
423
    mrp->midi_event_fifo[mrp->mfsz++] = val;
424
}
425
426
void midi_event_enqueue_sysex(struct midi_serial_regs* mrp, uint8_t *bufptr, int buflen)
427
{
428
    int i;
429
430
    mrp->in_midi_last_command = 0;
431
    if (mrp->mfsz >= 255L - (buflen + 2)) { // too full
432
        return;
433
    }
434
435
    mrp->midi_event_fifo[mrp->mfsz++] = 0xf0;
436
    for (i = 0; i < buflen; i++) {
437
        mrp->midi_event_fifo[mrp->mfsz++] = bufptr[i];
438
    }
439
    mrp->midi_event_fifo[mrp->mfsz++] = 0xf7;
440
}
441
442
int handle_midi_event(void* data, fluid_midi_event_t* event)
443
{
444
    struct midi_serial_regs* mrp = (struct midi_serial_regs*)data;
445
    pthread_mutex_lock(&mrp->fifo_mutex);
446
447
    uint8_t type = dl_fluid_midi_event_get_type(event);
448
    uint8_t chan = dl_fluid_midi_event_get_channel(event);
449
    uint8_t cmd = (type < 0x80 || type >= 0xf0) ? type : (type | (chan & 0xf));
450
    uint8_t key, val;
451
    uint8_t *bufptr;
452
    int buflen;
453
454
    switch (type) {
455
        case FS_NOTE_OFF:
456
        case FS_NOTE_ON:
457
            key = dl_fluid_midi_event_get_key(event);
458
            val = dl_fluid_midi_event_get_velocity(event);
459
            midi_event_enqueue_normal(mrp, cmd, key, val);
460
            break;
461
        case FS_KEY_PRESSURE:
462
            key = dl_fluid_midi_event_get_key(event);
463
            val = dl_fluid_midi_event_get_value(event);
464
            midi_event_enqueue_normal(mrp, cmd, key, val);
465
            break;
466
        case FS_CONTROL_CHANGE:
467
            key = dl_fluid_midi_event_get_control(event);
468
            val = dl_fluid_midi_event_get_value(event);
469
            midi_event_enqueue_normal(mrp, cmd, key, val);
470
            break;
471
        case FS_PITCH_BEND:
472
            key = dl_fluid_midi_event_get_pitch(event) & 0x7f;
473
            val = (dl_fluid_midi_event_get_pitch(event) >> 7) & 0x7f;
474
            midi_event_enqueue_normal(mrp, cmd, key, val);
475
            break;
476
        case FS_PROGRAM_CHANGE:
477
        case FS_CHANNEL_PRESSURE:
478
            val = dl_fluid_midi_event_get_program(event);
479
            midi_event_enqueue_short(mrp, cmd, val);
480
            break;
481
        case FS_MIDI_TIME_CODE:
482
            val = dl_fluid_midi_event_get_value(event);
483
            midi_event_enqueue_short(mrp, type, val);
484
            mrp->in_midi_last_command = 0;
485
            break;
486
        case FS_MIDI_TUNE_REQUEST:
487
        case 0xF4:
488
        case 0xF5:
489
            midi_event_enqueue_byte(mrp, type);
490
            mrp->in_midi_last_command = 0;
491
            break;
492
        case FS_MIDI_SYNC:
493
        case FS_MIDI_TICK:
494
        case FS_MIDI_START:
495
        case FS_MIDI_CONTINUE:
496
        case FS_MIDI_STOP:
497
        case FS_MIDI_ACTIVE_SENSING:
498
        case FS_MIDI_SYSTEM_RESET:
499
            midi_event_enqueue_byte(mrp, type);
500
            break;
501
        case FS_MIDI_SYSEX:
502
            // FluidSynth doesn't offer a get_sysex function, but internally
503
            // a text event is equivalent to a sysex event, in terms of what
504
            // parts of the event structure are populated
505
            //
506
            // Unfortunately that means we have to fool it in order to
507
            // access the data.
508
            dl_fluid_midi_event_set_type(event, FS_MIDI_TEXT);
509
            if (dl_fluid_midi_event_get_text(event, (void **)&bufptr, &buflen) == FLUID_OK && bufptr != NULL) {
510
                midi_event_enqueue_sysex(mrp, bufptr, buflen);
511
            }
512
            break;
513
    }
514
515
    //fprintf(stderr, "Debug: MIDI IN: Type: %02X Chan: %02X\n", type, chan);
516
517
    pthread_mutex_unlock(&mrp->fifo_mutex);
518
    return FLUID_OK;
519
}
520
521
522
#else
523
void midi_load_sf2(uint8_t* filename)
524
{
525
    // no-op
526
}
527
528
void midi_init()
529
{
530
    fprintf(stderr, "No FluidSynth support.\n");
531
}
532
533
void midi_byte_out(uint8_t sel, uint8_t b)
534
{
535
    // no-op
536
}
537
538
void midi_synth_render(int16_t* buf, int len)
539
{
540
    // no synth, return zeroed buffer
541
    memset(buf, 0, len * 2 * sizeof(int16_t));
542
}
543
544
#endif
545
546
void midi_serial_init()
547
{
548
    uint8_t sel;
549
550
    for (sel=0; sel<2; sel++) {
551
        mregs[sel].ier_erbi = false;
552
        mregs[sel].ier_etbei = false;
553
        mregs[sel].ier_elsi = false;
554
        mregs[sel].ier_edssi = false;
555
556
        mregs[sel].iir = 0x01;
557
558
        mregs[sel].fcr_fifo_enable = false;
559
        mregs[sel].fcr_ififo_trigger_level_bytes = 1;
560
561
        mregs[sel].lcr_word_length_bits = 5;
562
        mregs[sel].lcr_stb = false;
563
        mregs[sel].lcr_pen = false;
564
        mregs[sel].lcr_eps = false;
565
        mregs[sel].lcr_stick = false;
566
        mregs[sel].lcr_break = false;
567
        mregs[sel].lcr_dlab = false;
568
569
        mregs[sel].mcr_dtr = false;
570
        mregs[sel].mcr_rts = false;
571
        mregs[sel].mcr_out1 = false;
572
        mregs[sel].mcr_out2 = false;
573
        mregs[sel].mcr_loop = false;
574
        mregs[sel].mcr_afe = false;
575
576
        mregs[sel].lsr_oe = false;
577
        mregs[sel].lsr_pe = false;
578
        mregs[sel].lsr_fe = false;
579
        mregs[sel].lsr_bi = false;
580
        mregs[sel].lsr_eif = false;
581
582
        mregs[sel].msr_dcts = false;
583
        mregs[sel].msr_ddsr = false;
584
        mregs[sel].msr_teri = false;
585
        mregs[sel].msr_ddcd = false;
586
587
        mregs[sel].msr_cts = false;
588
        mregs[sel].msr_dsr = false;
589
        mregs[sel].msr_ri = false;
590
        mregs[sel].msr_dcd = false;
591
592
        mregs[sel].obyte_bits_remain = 0;
593
        mregs[sel].rx_timeout = 0;
594
        mregs[sel].rx_timeout_enabled = false;
595
        mregs[sel].thre_intr = false;
596
        mregs[sel].thre_bits_remain = 0;
597
598
        mregs[sel].ibyte_bits_remain = 7;
599
600
        mregs[sel].ifsz = 0;
601
        mregs[sel].ififo[0] = 0;
602
        mregs[sel].ofsz = 0;
603
        mregs[sel].clock = 0;
604
        mregs[sel].clockdec = 0;
605
        mregs[sel].last_warning = 0;
606
607
        mregs[sel].mfsz = 0;
608
        mregs[sel].in_midi_last_command = 0;
609
    }
610
611
    if (!serial_midi_mutexes_initialized) {
612
        for (sel=0; sel<2; sel++) {
613
            pthread_mutexattr_init(&mregs[sel].fifo_mutex_attr);
614
            pthread_mutex_init(&mregs[sel].fifo_mutex, &mregs[sel].fifo_mutex_attr);
615
        }
616
        serial_midi_mutexes_initialized = true;
617
    }
618
}
619
620
void midi_serial_iir_check(uint8_t sel)
621
{
622
    uint8_t fifoen = (uint8_t)mregs[sel].fcr_fifo_enable << 6 | (uint8_t)mregs[sel].fcr_fifo_enable << 7;
623
    if (mregs[sel].ier_elsi && (mregs[sel].lsr_oe || mregs[sel].lsr_pe || mregs[sel].lsr_fe || mregs[sel].lsr_bi)) {
624
        mregs[sel].iir = (0x06 | fifoen); // Receiver line status interrupt
625
    } else if (mregs[sel].ier_erbi && !mregs[sel].fcr_fifo_enable && mregs[sel].ifsz > 0) {
626
        mregs[sel].iir = (0x04 | fifoen); // Received data available interrupt (16450 mode)
627
    } else if (mregs[sel].ier_erbi && mregs[sel].fcr_fifo_enable && mregs[sel].ifsz >= mregs[sel].fcr_ififo_trigger_level_bytes) {
628
        mregs[sel].iir = (0x04 | fifoen); // Received data available interrupt (16550 mode)
629
    } else if (mregs[sel].ier_erbi && mregs[sel].fcr_fifo_enable && mregs[sel].ifsz > 0 && mregs[sel].rx_timeout_enabled && mregs[sel].rx_timeout == 0) {
630
        mregs[sel].iir = (0x0c | fifoen); // Received data available interrupt (timeout, 16550 mode)
631
    } else if (mregs[sel].ier_etbei && mregs[sel].thre_intr) {
632
        mregs[sel].iir = (0x02 | fifoen); // Transmitter holding register empty interrupt
633
    } else if (mregs[sel].ier_edssi && ((!mregs[sel].mcr_afe && mregs[sel].msr_dcts) || mregs[sel].msr_ddcd || mregs[sel].msr_ddsr || mregs[sel].msr_teri)) {
634
        mregs[sel].iir = (0x00 | fifoen); // Modem status register interrupt
635
    } else {
636
        mregs[sel].iir = (0x01 | fifoen); // no interrupt waiting
637
    }
638
}
639
640
void midi_serial_step(int clocks)
641
{
642
    uint8_t sel, i;
643
    for (sel=0; sel<2; sel++) {
644
        mregs[sel].clock -= (int64_t)mregs[sel].clockdec * clocks;
645
        while (mregs[sel].clock < 0) {
646
            // process uart
647
            pthread_mutex_lock(&mregs[sel].fifo_mutex);
648
649
            if (mregs[sel].obyte_bits_remain > 0) {
650
                mregs[sel].obyte_bits_remain--;
651
            }
652
            if (mregs[sel].ofsz > 0) {
653
                if (mregs[sel].obyte_bits_remain == 0) {
654
                    midi_byte_out(sel, mregs[sel].ofifo[0]);
655
                    mregs[sel].ofsz--;
656
                    if (mregs[sel].ofsz > 0) {
657
                        for (i=0; i<mregs[sel].ofsz; i++) {
658
                            mregs[sel].ofifo[i] = mregs[sel].ofifo[i+1];
659
                        }
660
                    } else if (mregs[sel].thre_bits_remain == 0) {
661
                        mregs[sel].thre_intr = true;
662
                    }
663
                    mregs[sel].obyte_bits_remain = 2 + mregs[sel].lcr_word_length_bits + mregs[sel].lcr_stb + mregs[sel].lcr_pen;
664
                }
665
            } else {
666
                if (mregs[sel].thre_bits_remain > 0) {
667
                    mregs[sel].thre_bits_remain--;
668
                    if (mregs[sel].thre_bits_remain == 0) {
669
                        mregs[sel].thre_intr = true;
670
                    }
671
                }
672
            }
673
674
            if (mregs[sel].rx_timeout > 0) {
675
                mregs[sel].rx_timeout--;
676
            }
677
678
            if (mregs[sel].ibyte_bits_remain > 0 && mregs[sel].mfsz > 0) {
679
                mregs[sel].ibyte_bits_remain--;
680
            }
681
            if (mregs[sel].ibyte_bits_remain == 0 && mregs[sel].mfsz > 0) {
682
                if (mregs[sel].ifsz < (mregs[sel].fcr_fifo_enable ? 16 : 1)) {
683
                    mregs[sel].ififo[mregs[sel].ifsz++] = mregs[sel].midi_event_fifo[0];
684
                    mregs[sel].rx_timeout_enabled = true;
685
                    mregs[sel].rx_timeout = 4 * (2 + mregs[sel].lcr_word_length_bits + mregs[sel].lcr_stb + mregs[sel].lcr_pen);
686
                } else {
687
                    mregs[sel].lsr_oe = true; // inbound FIFO overflow
688
                    if (!mregs[sel].fcr_fifo_enable) {
689
                        // RBR is overwritten by RSR in this mode
690
                        // whenever overflow happens
691
                        mregs[sel].ififo[mregs[sel].ifsz-1] = mregs[sel].midi_event_fifo[0];
692
                    }
693
                }
694
                mregs[sel].mfsz--;
695
                if (mregs[sel].mfsz > 0) {
696
                    for (i=0; i<mregs[sel].mfsz; i++) {
697
                        mregs[sel].midi_event_fifo[i] = mregs[sel].midi_event_fifo[i+1];
698
                    }
699
                }
700
                mregs[sel].ibyte_bits_remain = 2 + mregs[sel].lcr_word_length_bits + mregs[sel].lcr_stb + mregs[sel].lcr_pen;
701
            }
702
703
            pthread_mutex_unlock(&mregs[sel].fifo_mutex);
704
            mregs[sel].clock += 0x1000000LL;
705
            midi_serial_iir_check(sel);
706
        }
707
    }
708
}
709
710
uint8_t midi_serial_dequeue_ibyte(uint8_t sel)
711
{
712
    pthread_mutex_lock(&mregs[sel].fifo_mutex);
713
    uint8_t ret = mregs[sel].ififo[0];
714
    uint8_t i;
715
716
    if (mregs[sel].ifsz > 0) {
717
        mregs[sel].ifsz--;
718
        if (mregs[sel].ifsz == 0) {
719
            mregs[sel].rx_timeout_enabled = false;
720
        } else {
721
            for (i=0; i<mregs[sel].ifsz; i++) {
722
                mregs[sel].ififo[i] = mregs[sel].ififo[i+1];
723
            }
724
            mregs[sel].rx_timeout_enabled = true;
725
            mregs[sel].rx_timeout = 4 * (2 + mregs[sel].lcr_word_length_bits + mregs[sel].lcr_stb + mregs[sel].lcr_pen);
726
        }
727
        midi_serial_iir_check(sel);
728
    }
729
730
    pthread_mutex_unlock(&mregs[sel].fifo_mutex);
731
    return ret;
732
}
733
734
void midi_serial_enqueue_obyte(uint8_t sel, uint8_t val)
735
{
736
    pthread_mutex_lock(&mregs[sel].fifo_mutex);
737
    if (mregs[sel].ofsz < (mregs[sel].fcr_fifo_enable ? 16 : 1)) {
738
        mregs[sel].ofifo[mregs[sel].ofsz] = val;
739
        mregs[sel].thre_intr = false;
740
        mregs[sel].ofsz++;
741
        if (mregs[sel].ofsz == 1) { // We were empty
742
            if (mregs[sel].fcr_fifo_enable) {
743
                // We delay a bit longer to reraise the THRE interrupt if we're coming from 0
744
                mregs[sel].thre_bits_remain = 1 + mregs[sel].lcr_word_length_bits + mregs[sel].lcr_stb + mregs[sel].lcr_pen;
745
            }
746
        } else {
747
            mregs[sel].thre_bits_remain = 0;
748
        }
749
    } else {
750
        fprintf(stderr, "Serial MIDI: Warning: UART %d TX Overflow\n", sel);
751
    }
752
    midi_serial_iir_check(sel);
753
    pthread_mutex_unlock(&mregs[sel].fifo_mutex);
754
}
755
756
uint8_t midi_serial_read(uint8_t reg, bool debugOn)
757
{
758
    //printf("midi_serial_read %d\n", reg);
759
    uint8_t sel = (reg & 8) >> 3;
760
    switch (reg & 7) {
761
        case 0x0:
762
            if (mregs[sel].lcr_dlab) {
763
                return mregs[sel].dll;
764
            } else {
765
                if (debugOn) {
766
                    return mregs[sel].ififo[0];
767
                } else {
768
                    return midi_serial_dequeue_ibyte(sel);
769
                }
770
            }
771
            break;
772
        case 0x1:
773
            if (mregs[sel].lcr_dlab) {
774
                return mregs[sel].dlm;
775
            } else {
776
                return (((uint8_t)mregs[sel].ier_edssi << 3) |
777
                        ((uint8_t)mregs[sel].ier_elsi << 2) |
778
                        ((uint8_t)mregs[sel].ier_etbei << 1) |
779
                        ((uint8_t)mregs[sel].ier_erbi));
780
            }
781
            break;
782
        case 0x2: {
783
            uint8_t ret = mregs[sel].iir;
784
            if (!debugOn) {
785
                mregs[sel].thre_intr = false;
786
                midi_serial_iir_check(sel);
787
            }
788
            return ret;
789
            break;
790
        }
791
        case 0x3:
792
            return (((uint8_t)mregs[sel].lcr_dlab << 7) |
793
                    ((uint8_t)mregs[sel].lcr_break << 6) |
794
                    ((uint8_t)mregs[sel].lcr_stick << 5) |
795
                    ((uint8_t)mregs[sel].lcr_eps << 4) |
796
                    ((uint8_t)mregs[sel].lcr_pen << 3) |
797
                    ((uint8_t)mregs[sel].lcr_stb << 2) |
798
                    ((mregs[sel].lcr_word_length_bits - 5) & 0x3));
799
            break;
800
        case 0x4:
801
            return (((uint8_t)mregs[sel].mcr_afe << 5) |
802
                    ((uint8_t)mregs[sel].mcr_loop << 4) |
803
                    ((uint8_t)mregs[sel].mcr_out2 << 3) |
804
                    ((uint8_t)mregs[sel].mcr_out1 << 2) |
805
                    ((uint8_t)mregs[sel].mcr_rts << 1) |
806
                    ((uint8_t)mregs[sel].mcr_dtr));
807
            break;
808
        case 0x5: {
809
            uint8_t ret = (((uint8_t)mregs[sel].lsr_eif << 7) |
810
                    ((uint8_t)(mregs[sel].obyte_bits_remain == 0 && mregs[sel].ofsz == 0) << 6) |
811
                    ((uint8_t)(mregs[sel].ofsz == 0) << 5) |
812
                    ((uint8_t)mregs[sel].lsr_bi << 4) |
813
                    ((uint8_t)mregs[sel].lsr_fe << 3) |
814
                    ((uint8_t)mregs[sel].lsr_pe << 2) |
815
                    ((uint8_t)mregs[sel].lsr_oe << 1) |
816
                    ((uint8_t)(mregs[sel].ifsz > 0)));
817
            if (!debugOn) {
818
                mregs[sel].lsr_oe = false;
819
                mregs[sel].lsr_pe = false;
820
                mregs[sel].lsr_fe = false;
821
                mregs[sel].lsr_bi = false;
822
            }
823
            return ret;
824
            break;
825
        }
826
        case 0x6:
827
            return (((uint8_t)mregs[sel].msr_dcd << 7) |
828
                    ((uint8_t)mregs[sel].msr_ri << 6) |
829
                    ((uint8_t)mregs[sel].msr_dsr << 5) |
830
                    ((uint8_t)mregs[sel].msr_cts << 4) |
831
                    ((uint8_t)mregs[sel].msr_ddcd << 3) |
832
                    ((uint8_t)mregs[sel].msr_teri << 2) |
833
                    ((uint8_t)mregs[sel].msr_ddsr << 1) |
834
                    ((uint8_t)mregs[sel].msr_dcts));
835
            break;
836
        case 0x7:
837
            return mregs[sel].scratch;
838
            break;
839
    }
840
    return 0x00;
841
}
842
843
void midi_serial_calculate_clk(uint8_t sel)
844
{
845
    double uart_clks_per_cpu = (MIDI_UART_OSC_RATE_MHZ / MIDI_UART_PRIMARY_DIVIDER) / MHZ;
846
    if (mregs[sel].dl > 0) {
847
        uart_clks_per_cpu /= mregs[sel].dl;
848
        mregs[sel].clockdec = uart_clks_per_cpu * 0x1000000L; // convert to 8.24 fixed point
849
    } else {
850
        mregs[sel].clockdec = 0;
851
    }
852
}
853
854
void midi_serial_write(uint8_t reg, uint8_t val)
855
{
856
    time_t now = time(NULL);
857
858
    //printf("midi_serial_write %d %d\n", reg, val);
859
    uint8_t sel = (reg & 8) >> 3;
860
    switch (reg & 7) {
861
        case 0x0:
862
            if (mregs[sel].lcr_dlab) {
863
                mregs[sel].dll = val;
864
                midi_serial_calculate_clk(sel);
865
            } else {
866
                if (mregs[sel].lcr_word_length_bits != 8 || mregs[sel].lcr_stb || mregs[sel].lcr_pen) {
867
                    if (mregs[sel].last_warning + 60 < now) {
868
                        unsigned char par = 'N';
869
                        if (mregs[sel].lcr_pen) {
870
                            switch ((uint8_t)(mregs[sel].lcr_eps << 1) | (uint8_t)mregs[sel].lcr_stick) {
871
                                case 0:
872
                                    par = 'O';
873
                                    break;
874
                                case 1:
875
                                    par = 'M';
876
                                    break;
877
                                case 2:
878
                                    par = 'E';
879
                                    break;
880
                                case 3:
881
                                    par = 'S';
882
                                    break;
883
                            }
884
                        }
885
                        fprintf(stderr, "Serial MIDI: Warning: improper LCR %d%c%d for UART %d, must be set to 8N1.\n", mregs[sel].lcr_word_length_bits, par, 1+(uint8_t)mregs[sel].lcr_stb, sel);
886
                        mregs[sel].last_warning = now;
887
                    }
888
                } else if (mregs[sel].lcr_break && mregs[sel].last_warning + 60 < now) {
889
                    fprintf(stderr, "Serial MIDI: Warning: break improperly set for UART %d.\n", sel);
890
                    mregs[sel].last_warning = now;
891
                } else if (mregs[sel].dl != 32 && mregs[sel].last_warning + 60 < now) {
892
                    fprintf(stderr, "Serial MIDI: Warning: improper divisor %d for UART %d, must be set to 32 for standard MIDI bitrate.\n", mregs[sel].dl, sel);
893
                    mregs[sel].last_warning = now;
894
                } else {
895
                    midi_serial_enqueue_obyte(sel, val);
896
                }
897
            }
898
            break;
899
        case 0x1:
900
            if (mregs[sel].lcr_dlab) {
901
                mregs[sel].dlm = val;
902
                midi_serial_calculate_clk(sel);
903
            } else {
904
                mregs[sel].ier_erbi = !!(val & 1);
905
                mregs[sel].ier_etbei = !!(val & 2);
906
                mregs[sel].ier_elsi = !!(val & 4);
907
                mregs[sel].ier_edssi = !!(val & 8);
908
            }
909
            break;
910
        case 0x2:
911
            if (val & 1) {
912
                mregs[sel].fcr_fifo_enable = true;
913
                switch ((val & 0xc0) >> 6) {
914
                    case 0:
915
                        mregs[sel].fcr_ififo_trigger_level_bytes = 1;
916
                        break;
917
                    case 1:
918
                        mregs[sel].fcr_ififo_trigger_level_bytes = 4;
919
                        break;
920
                    case 2:
921
                        mregs[sel].fcr_ififo_trigger_level_bytes = 8;
922
                        break;
923
                    case 3:
924
                        mregs[sel].fcr_ififo_trigger_level_bytes = 14;
925
                        break;
926
                }
927
            } else {
928
                mregs[sel].fcr_fifo_enable = false;
929
                mregs[sel].fcr_ififo_trigger_level_bytes = 1;
930
            }
931
            if (val & 2) {
932
                mregs[sel].ifsz = 0;
933
            }
934
            if (val & 4) {
935
                mregs[sel].ofsz = 0;
936
            }
937
            if (mregs[sel].thre_bits_remain == 0) { 
938
                mregs[sel].thre_intr = true;
939
            }
940
            midi_serial_iir_check(sel);
941
            break;
942
        case 0x3:
943
            mregs[sel].lcr_word_length_bits = (val & 0x03)+5;
944
            mregs[sel].lcr_stb = !!(val & 0x04);
945
            mregs[sel].lcr_pen = !!(val & 0x08);
946
            mregs[sel].lcr_eps = !!(val & 0x10);
947
            mregs[sel].lcr_stick = !!(val & 0x20);
948
            mregs[sel].lcr_break = !!(val & 0x40);
949
            mregs[sel].lcr_dlab = !!(val & 0x80);
950
            if (mregs[sel].mfsz == 0) {
951
                mregs[sel].ibyte_bits_remain = 2 + mregs[sel].lcr_word_length_bits + mregs[sel].lcr_stb + mregs[sel].lcr_pen;
952
            }
953
            break;
954
        case 0x4:
955
            mregs[sel].mcr_dtr = !!(val & 0x01);
956
            mregs[sel].mcr_rts = !!(val & 0x02);
957
            mregs[sel].mcr_out1 = !!(val & 0x04);
958
            mregs[sel].mcr_out2 = !!(val & 0x08);
959
            mregs[sel].mcr_loop = !!(val & 0x10);
960
            mregs[sel].mcr_afe = !!(val & 0x20);
961
962
            if (mregs[sel].mcr_loop) {
963
                mregs[sel].msr_dcts |= mregs[sel].msr_cts ^ mregs[sel].mcr_dtr;
964
                mregs[sel].msr_cts = mregs[sel].mcr_dtr;
965
966
                mregs[sel].msr_ddsr |= mregs[sel].msr_dsr ^ mregs[sel].mcr_rts;
967
                mregs[sel].msr_dsr = mregs[sel].mcr_rts;
968
969
                if (mregs[sel].msr_ri) {
970
                    mregs[sel].msr_teri |= mregs[sel].msr_ri ^ mregs[sel].mcr_out1;
971
                }
972
                mregs[sel].msr_ri = mregs[sel].mcr_out1;
973
974
                mregs[sel].msr_ddcd |= mregs[sel].msr_dcd ^ mregs[sel].mcr_out2;
975
                mregs[sel].msr_dcd = mregs[sel].mcr_out2;
976
977
            } else {
978
                // DTR tied to RI on opposite UART, wired this way on the official X16 MIDI card
979
                if (mregs[sel ^ 1].msr_ri && !mregs[sel].mcr_dtr) {
980
                    mregs[sel ^ 1].msr_teri = true;
981
                }
982
                mregs[sel ^ 1].msr_ri = mregs[sel].mcr_dtr;
983
            }
984
985
            break;
986
        case 0x7:
987
            mregs[sel].scratch = val;
988
            break;
989
    }
990
}
991
992
bool midi_serial_irq(void)
993
{
994
    bool uart0int = (mregs[0].iir & 1) == 0 && mregs[0].mcr_out2;
995
    bool uart1int = (mregs[1].iir & 1) == 0 && mregs[1].mcr_out2;
996
    return (uart0int | uart1int);
997
}