2017-05-30 03:38:38 +02:00
|
|
|
/*
|
|
|
|
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
|
|
|
|
* running old operating systems and software designed for IBM
|
|
|
|
|
* PC systems and compatibles from 1981 through fairly recent
|
|
|
|
|
* system designs based on the PCI bus.
|
|
|
|
|
*
|
|
|
|
|
* This file is part of the 86Box distribution.
|
|
|
|
|
*
|
|
|
|
|
* Roland MPU-401 emulation.
|
|
|
|
|
*
|
2020-01-23 06:40:20 +01:00
|
|
|
* Version: @(#)snd_mpu401.c 1.0.20 2020/01/23
|
2017-05-30 03:38:38 +02:00
|
|
|
*
|
2017-09-25 04:31:20 -04:00
|
|
|
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
2017-05-30 03:38:38 +02:00
|
|
|
* DOSBox Team,
|
|
|
|
|
* Miran Grca, <mgrca8@gmail.com>
|
|
|
|
|
* TheCollector1995, <mariogplayer@gmail.com>
|
2017-10-17 01:59:09 -04:00
|
|
|
*
|
2020-01-19 05:45:05 +01:00
|
|
|
* Copyright 2008-2020 Sarah Walker.
|
|
|
|
|
* Copyright 2008-2020 DOSBox Team.
|
|
|
|
|
* Copyright 2016-2020 Miran Grca.
|
2017-05-30 03:38:38 +02:00
|
|
|
*/
|
2018-05-21 19:04:05 +02:00
|
|
|
#include <stdarg.h>
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <stdint.h>
|
2018-05-21 19:04:05 +02:00
|
|
|
#include <stdio.h>
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <wchar.h>
|
2018-05-21 19:04:05 +02:00
|
|
|
#define HAVE_STDARG_H
|
2017-10-17 01:59:09 -04:00
|
|
|
#include "../86box.h"
|
2017-06-03 20:32:58 +02:00
|
|
|
#include "../device.h"
|
2020-01-01 20:20:16 +01:00
|
|
|
#include "../plat.h"
|
2017-05-09 21:45:20 +02:00
|
|
|
#include "../io.h"
|
2018-09-11 23:08:51 +02:00
|
|
|
#include "../machine/machine.h"
|
2018-09-03 13:55:09 +02:00
|
|
|
#include "../mca.h"
|
2017-05-09 21:45:20 +02:00
|
|
|
#include "../pic.h"
|
|
|
|
|
#include "../timer.h"
|
2017-06-03 20:32:58 +02:00
|
|
|
#include "sound.h"
|
2017-05-09 21:45:20 +02:00
|
|
|
#include "snd_mpu401.h"
|
2017-09-25 04:31:20 -04:00
|
|
|
#include "midi.h"
|
2017-05-09 21:45:20 +02:00
|
|
|
|
2020-01-19 05:45:05 +01:00
|
|
|
|
|
|
|
|
static uint32_t MPUClockBase[8] = {48,72,96,120,144,168,192};
|
|
|
|
|
static uint8_t cth_data[16] = {0,0,0,0,1,0,0,0,1,0,1,0,1,1,1,0};
|
|
|
|
|
|
2017-05-10 22:52:11 +02:00
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
enum {
|
|
|
|
|
STATUS_OUTPUT_NOT_READY = 0x40,
|
|
|
|
|
STATUS_INPUT_NOT_READY = 0x80
|
2017-05-09 21:45:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2017-06-03 20:32:58 +02:00
|
|
|
int mpu401_standalone_enable = 0;
|
|
|
|
|
|
2020-01-19 05:45:05 +01:00
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
static void MPU401_WriteCommand(mpu_t *mpu, uint8_t val);
|
2020-01-01 20:20:16 +01:00
|
|
|
static void MPU401_IntelligentOut(mpu_t *mpu, uint8_t track);
|
|
|
|
|
static void MPU401_EOIHandler(void *priv);
|
2017-11-23 21:45:10 -05:00
|
|
|
static void MPU401_EOIHandlerDispatch(void *p);
|
2020-01-01 20:20:16 +01:00
|
|
|
static void MPU401_NotesOff(mpu_t *mpu, int i);
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
|
2018-05-21 19:04:05 +02:00
|
|
|
#ifdef ENABLE_MPU401_LOG
|
|
|
|
|
int mpu401_do_log = ENABLE_MPU401_LOG;
|
|
|
|
|
|
|
|
|
|
|
2017-05-10 22:52:11 +02:00
|
|
|
static void
|
2018-05-21 19:04:05 +02:00
|
|
|
mpu401_log(const char *fmt, ...)
|
2017-05-10 22:52:11 +02:00
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
|
|
if (mpu401_do_log) {
|
|
|
|
|
va_start(ap, fmt);
|
2018-05-21 19:04:05 +02:00
|
|
|
pclog_ex(fmt, ap);
|
2017-05-10 22:52:11 +02:00
|
|
|
va_end(ap);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-10-19 00:39:32 +02:00
|
|
|
#else
|
|
|
|
|
#define mpu401_log(fmt, ...)
|
|
|
|
|
#endif
|
2017-05-10 22:52:11 +02:00
|
|
|
|
|
|
|
|
|
2020-01-01 20:20:16 +01:00
|
|
|
static void
|
|
|
|
|
MPU401_ReCalcClock(mpu_t *mpu)
|
|
|
|
|
{
|
2020-01-04 03:32:20 +01:00
|
|
|
int32_t maxtempo = 240, mintempo = 16;
|
|
|
|
|
int32_t freq;
|
|
|
|
|
|
2020-01-23 06:40:20 +01:00
|
|
|
if (mpu->clock.timebase < 72) {
|
|
|
|
|
maxtempo = 240;
|
|
|
|
|
mintempo = 32;
|
|
|
|
|
} else if (mpu->clock.timebase < 120) {
|
|
|
|
|
maxtempo = 240;
|
|
|
|
|
mintempo = 16;
|
|
|
|
|
} else if (mpu->clock.timebase < 168) {
|
2020-01-04 03:32:20 +01:00
|
|
|
maxtempo = 208;
|
2020-01-23 06:40:20 +01:00
|
|
|
mintempo = 8;
|
|
|
|
|
} else {
|
|
|
|
|
maxtempo = 179;
|
|
|
|
|
mintempo = 8;
|
|
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
|
|
|
|
|
mpu->clock.freq = ((uint32_t)(mpu->clock.tempo * 2 * mpu->clock.tempo_rel)) >> 6;
|
|
|
|
|
mpu->clock.freq = mpu->clock.timebase * (mpu->clock.freq < (mintempo * 2) ? mintempo :
|
|
|
|
|
((mpu->clock.freq / 2) < maxtempo ? (mpu->clock.freq / 2) : maxtempo));
|
|
|
|
|
|
|
|
|
|
if (mpu->state.sync_in) {
|
|
|
|
|
freq = (int32_t)((float)(mpu->clock.freq) * mpu->clock.freq_mod);
|
2020-01-01 20:20:16 +01:00
|
|
|
if ((freq > (mpu->clock.timebase * mintempo)) && (freq < (mpu->clock.timebase * maxtempo)))
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu->clock.freq = freq;
|
|
|
|
|
}
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
|
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
|
2020-01-01 20:20:16 +01:00
|
|
|
static void
|
|
|
|
|
MPU401_StartClock(mpu_t *mpu)
|
|
|
|
|
{
|
2020-01-04 03:32:20 +01:00
|
|
|
if (mpu->clock.active)
|
|
|
|
|
return;
|
|
|
|
|
if (!(mpu->state.clock_to_host || mpu->state.playing || (mpu->state.rec == M_RECON)))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
mpu->clock.active = 1;
|
|
|
|
|
timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC);
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
|
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
|
2020-01-01 20:20:16 +01:00
|
|
|
static void
|
|
|
|
|
MPU401_StopClock(mpu_t *mpu)
|
|
|
|
|
{
|
2020-01-04 03:32:20 +01:00
|
|
|
if (mpu->state.clock_to_host || mpu->state.playing || (mpu->state.rec == M_RECON))
|
|
|
|
|
return;
|
|
|
|
|
mpu->clock.active = 0;
|
|
|
|
|
timer_disable(&mpu->mpu401_event_callback);
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
|
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
|
2020-01-01 20:20:16 +01:00
|
|
|
static void
|
|
|
|
|
MPU401_RunClock(mpu_t *mpu)
|
|
|
|
|
{
|
2020-01-04 03:32:20 +01:00
|
|
|
if (!mpu->clock.active) {
|
|
|
|
|
timer_disable(&mpu->mpu401_event_callback);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC);
|
|
|
|
|
mpu401_log("Next event after %i us (time constant: %i)\n", (uint64_t) ((MPU401_TIMECONSTANT/mpu->clock.freq) * 1000 * TIMER_USEC), (int) MPU401_TIMECONSTANT);
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
|
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
static void
|
2020-01-23 06:40:20 +01:00
|
|
|
MPU401_QueueByteEx(mpu_t *mpu, uint8_t data, int irq)
|
2017-05-09 21:45:20 +02:00
|
|
|
{
|
2017-11-23 21:45:10 -05:00
|
|
|
if (mpu->state.block_ack) {
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.block_ack = 0;
|
2017-11-23 21:45:10 -05:00
|
|
|
return;
|
|
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
|
|
|
|
|
if (mpu->queue_used == 0) {
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.irq_pending = 1;
|
2020-01-23 06:40:20 +01:00
|
|
|
if (irq)
|
|
|
|
|
picint(1 << mpu->irq);
|
2017-11-23 21:45:10 -05:00
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
if (mpu->queue_used < MPU401_QUEUE) {
|
|
|
|
|
int pos = mpu->queue_used+mpu->queue_pos;
|
|
|
|
|
|
|
|
|
|
if (mpu->queue_pos >= MPU401_QUEUE)
|
|
|
|
|
mpu->queue_pos -= MPU401_QUEUE;
|
|
|
|
|
if (pos>=MPU401_QUEUE)
|
|
|
|
|
pos-=MPU401_QUEUE;
|
|
|
|
|
|
|
|
|
|
mpu->queue_used++;
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->queue[pos] = data;
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
|
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
|
2020-01-23 06:40:20 +01:00
|
|
|
static void
|
|
|
|
|
MPU401_QueueByte(mpu_t *mpu, uint8_t data)
|
|
|
|
|
{
|
|
|
|
|
MPU401_QueueByteEx(mpu, data, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-01-01 20:20:16 +01:00
|
|
|
static void
|
|
|
|
|
MPU401_RecQueueBuffer(mpu_t *mpu, uint8_t *buf, uint32_t len, int block)
|
|
|
|
|
{
|
2020-01-04 03:32:20 +01:00
|
|
|
uint32_t cnt = 0;
|
|
|
|
|
int pos;
|
2020-01-02 18:19:22 +01:00
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
while (cnt < len) {
|
2020-01-01 20:20:16 +01:00
|
|
|
if (mpu->rec_queue_used < MPU401_INPUT_QUEUE) {
|
2020-01-04 03:32:20 +01:00
|
|
|
pos = mpu->rec_queue_used + mpu->rec_queue_pos;
|
|
|
|
|
if (pos >= MPU401_INPUT_QUEUE)
|
|
|
|
|
pos -= MPU401_INPUT_QUEUE;
|
|
|
|
|
mpu->rec_queue[pos] = buf[cnt];
|
|
|
|
|
mpu->rec_queue_used++;
|
|
|
|
|
if ((!mpu->state.sysex_in_finished) && (buf[cnt] == MSG_EOX)) {
|
|
|
|
|
/* finish sysex */
|
|
|
|
|
mpu->state.sysex_in_finished = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
cnt++;
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mpu->queue_used == 0) {
|
2020-01-01 20:20:16 +01:00
|
|
|
if (mpu->state.rec_copy || mpu->state.irq_pending) {
|
|
|
|
|
if (mpu->state.irq_pending) {
|
2020-01-04 03:32:20 +01:00
|
|
|
picintc(1 << mpu->irq);
|
|
|
|
|
mpu->state.irq_pending = 0;
|
|
|
|
|
}
|
2020-01-01 20:20:16 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
mpu->state.rec_copy = 1;
|
|
|
|
|
if (mpu->rec_queue_pos >= MPU401_INPUT_QUEUE)
|
|
|
|
|
mpu->rec_queue_pos -= MPU401_INPUT_QUEUE;
|
|
|
|
|
MPU401_QueueByte(mpu, mpu->rec_queue[mpu->rec_queue_pos]);
|
|
|
|
|
mpu->rec_queue_used--;
|
|
|
|
|
mpu->rec_queue_pos++;
|
2020-01-04 03:32:20 +01:00
|
|
|
}
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2017-11-23 21:45:10 -05:00
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
static void
|
2020-01-01 20:20:16 +01:00
|
|
|
MPU401_ClrQueue(mpu_t *mpu)
|
2017-05-09 21:45:20 +02:00
|
|
|
{
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->queue_used = 0;
|
|
|
|
|
mpu->queue_pos = 0;
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu->rec_queue_used = 0;
|
|
|
|
|
mpu->rec_queue_pos = 0;
|
|
|
|
|
mpu->state.sysex_in_finished = 1;
|
|
|
|
|
mpu->state.irq_pending = 0;
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
MPU401_Reset(mpu_t *mpu)
|
2017-05-09 21:45:20 +02:00
|
|
|
{
|
2017-11-23 21:45:10 -05:00
|
|
|
uint8_t i;
|
|
|
|
|
|
2018-09-15 20:17:13 +02:00
|
|
|
if (mpu->mode == M_INTELLIGENT) {
|
|
|
|
|
picintc(1 << mpu->irq);
|
|
|
|
|
mpu->state.irq_pending = 0;
|
|
|
|
|
}
|
2020-01-01 20:20:16 +01:00
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->mode = M_INTELLIGENT;
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu->midi_thru = 0;
|
|
|
|
|
mpu->state.rec = M_RECOFF;
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu->state.eoi_scheduled = 0;
|
|
|
|
|
mpu->state.wsd = 0;
|
|
|
|
|
mpu->state.wsm = 0;
|
|
|
|
|
mpu->state.conductor = 0;
|
|
|
|
|
mpu->state.cond_req = 0;
|
|
|
|
|
mpu->state.cond_set = 0;
|
|
|
|
|
mpu->state.playing = 0;
|
|
|
|
|
mpu->state.run_irq = 0;
|
|
|
|
|
mpu->state.cmask = 0xff;
|
|
|
|
|
mpu->state.amask = mpu->state.tmask = 0;
|
|
|
|
|
mpu->state.midi_mask = 0xffff;
|
|
|
|
|
mpu->state.command_byte = 0;
|
|
|
|
|
mpu->state.block_ack = 0;
|
|
|
|
|
mpu->clock.tempo = mpu->clock.old_tempo = 100;
|
|
|
|
|
mpu->clock.timebase = mpu->clock.old_timebase = 120;
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->clock.tempo_rel = mpu->clock.old_tempo_rel = 0x40;
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu->clock.freq_mod = 1.0;
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu->clock.tempo_grad = 0;
|
2020-01-04 03:32:20 +01:00
|
|
|
MPU401_StopClock(mpu);
|
|
|
|
|
MPU401_ReCalcClock(mpu);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
|
mpu->clock.cth_rate[i] = 60;
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu->clock.cth_counter = 0;
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu->clock.midimetro = 12;
|
|
|
|
|
mpu->clock.metromeas = 8;
|
|
|
|
|
mpu->filter.rec_measure_end = 1;
|
|
|
|
|
mpu->filter.rt_out = 1;
|
|
|
|
|
mpu->filter.rt_affection = 1;
|
|
|
|
|
mpu->filter.allnotesoff_out = 1;
|
|
|
|
|
mpu->filter.all_thru = 1;
|
|
|
|
|
mpu->filter.midi_thru = 1;
|
|
|
|
|
mpu->filter.commonmsgs_thru = 1;
|
|
|
|
|
|
|
|
|
|
/* Reset channel reference and input tables. */
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->chanref[i].on = 1;
|
|
|
|
|
mpu->chanref[i].chan = i;
|
|
|
|
|
mpu->ch_toref[i] = i;
|
2020-01-04 03:32:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++) {
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->inputref[i].on = 1;
|
|
|
|
|
mpu->inputref[i].chan = i;
|
|
|
|
|
if (i > 3)
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu->ch_toref[i] = 4; /* Dummy reftable. */
|
|
|
|
|
}
|
2017-11-23 21:45:10 -05:00
|
|
|
|
2020-01-01 20:20:16 +01:00
|
|
|
MPU401_ClrQueue(mpu);
|
|
|
|
|
mpu->state.data_onoff = -1;
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
mpu->state.req_mask = 0;
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->condbuf.counter = 0;
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu->condbuf.type = T_OVERFLOW;
|
|
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
for (i = 0; i < 8; i++) {
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu->playbuf[i].type = T_OVERFLOW;
|
|
|
|
|
mpu->playbuf[i].counter = 0;
|
|
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
|
|
|
|
|
/* Clear MIDI buffers, terminate notes. */
|
|
|
|
|
midi_clear_buffer();
|
|
|
|
|
|
|
|
|
|
for (i = 0xb0; i <= 0xbf; i++) {
|
|
|
|
|
midi_raw_out_byte(i);
|
|
|
|
|
midi_raw_out_byte(0x7b);
|
|
|
|
|
midi_raw_out_byte(0);
|
|
|
|
|
}
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
MPU401_ResetDone(void *priv)
|
2017-05-09 21:45:20 +02:00
|
|
|
{
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu_t *mpu = (mpu_t *)priv;
|
2017-05-10 20:39:46 +02:00
|
|
|
|
2018-05-21 19:04:05 +02:00
|
|
|
mpu401_log("MPU-401 reset callback\n");
|
2017-05-10 20:39:46 +02:00
|
|
|
|
Added the IBM 5161 ISA expansion for PC and XT;
Cleaned up the parallel port emulation, added IRQ support, and made enabling/disabling per port;
Added the Award 430NX and the Intel Classic/PCI (Alfredo, 420TX);
Finished the 586MC1;
Added 8087 emulation;
Moved Cyrix 6x86'es to the Dev branch;
Sanitized/cleaned up memregs.c/h and intel.c/h;
Split the chipsets from machines and sanitized Port 92 emulation;
Added support for the 15bpp mode to the Compaq ATI 28800;
Moved the MR 386DX and 486 machines to the Dev branch;
Ported the new dynamic recompiler from PCem, but it remains in Dev branch until after v2.00;
Ported the new timer code from PCem;
Cleaned up the CPU table of unused stuff and better optimized its structure;
Ported the Open-XT and Open-AT from VARCem, the Open-AT is in the Dev branch;
Ported the XT MFM controller rewrite and adding of more controllers (incl. two RLL ones), from VARCem;
Added the AHA-1540A and the BusTek BT-542B;
Moved the Sumo SCSI-AT to the Dev branch;
Minor IDE, FDC, and floppy drive code clean-ups;
Made NCR 5380/53C400-based cards' BIOS address configurable;
Got rid of the legacy romset variable;
Unified (video) buffer and buffer32 into one and make the unified buffer 32-bit;
Added the Amstead PPC512 per PCem patch by John Elliott;
Switched memory mapping granularity from 16k to 4k (less than 1k not possible due to internal pages);
Rewrote the CL-GD 54xx blitter, fixes Win-OS/2 on the 54x6 among other thing;
Added the Image Manager 1024 and Professional Graphics Controller per PCem patch by John Elliott and work done on VARCem;
Added Headland HT-216, GC-205 and Video 7 VGA 1024i emulation based on PCem commit;
Implemented the fuction keys for the Toshiba T1000/T1200/T3100 enhancement;
Amstrad MegaPC does now works correctly with non-internal graphics card;
The SLiRP code no longer casts a packed struct type to a non-packed struct type;
The Xi8088 and PB410a no longer hang on 86Box when PS/2 mouse is not present;
The S3 Virge on BeOS is no longer broken (was broken by build #1591);
OS/2 2.0 build 6.167 now sees key presses again;
Xi8088 now work on CGA again;
86F images converted from either the old or new variants of the HxC MFM format now work correctly;
Hardware interrupts with a vector of 0xFF are now handled correctly;
OPTi 495SX boards no longer incorrectly have 64 MB maximum RAM when 32 MB is correct;
Fixed VNC keyboard input bugs;
Fixed AT RTC periodic interrupt - Chicago 58s / 73f / 73g / 81 MIDI play no longer hangs with the build's own VTD driver;
Fixed mouse polling with internal mice - Amstrad and Olivetti mice now work correctly;
Triones ATAPI DMA driver now correctly reads a file at the end of a CD image with a sectors number not divisible by 4;
Compaq Portable now works with all graphics cards;
Fixed various MDSI Genius bugs;
Added segment limit checks and improved page fault checks for several CPU instructions - Memphis 15xx WINSETUP and Chicago 58s WINDISK.CPL no longer issue a GPF, and some S3 drivers that used to have glitches, now work correctly;
Further improved the 808x emulation, also fixes the noticably choppy sound when using 808x CPU's, also fixes #355;
OS/2 installer no logner locks up on splash screen on PS/2 Model 70 and 80, fixes #400.
Fixed several Amstead bugs, GEM no longer crashes on the Amstrad 1640, fixes #391.
Ported John Elliott's Amstrad fixes and improvement from PCem, and fixed the default language so it's correctly Engliish, fixes #278, fixes #389.
Fixed a minor IDE timing bug, fixes #388.
Fixed Toshiba T1000 RAM issues, fixes #379.
Fixed EGA/(S)VGA overscan border handling, fixes #378;
Got rid of the now long useless IDE channel 2 auto-removal, fixes #370;
Fixed the BIOS files used by the AMSTRAD PC1512, fixes #366;
Ported the Unicode CD image file name fix from VARCem, fixes #365;
Fixed high density floppy disks on the Xi8088, fixes #359;
Fixed some bugs in the Hercules emulation, fixes #346, fixes #358;
Fixed the SCSI hard disk mode sense pages, fixes #356;
Removed the AMI Unknown 386SX because of impossibility to identify the chipset, closes #349;
Fixed bugs in the serial mouse emulation, fixes #344;
Compiled 86Box binaries now include all the required .DLL's, fixes #341;
Made some combo boxes in the Settings dialog slightly wider, fixes #276.
2019-09-20 14:02:30 +02:00
|
|
|
timer_disable(&mpu->mpu401_reset_callback);
|
2017-05-10 20:39:46 +02:00
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.reset = 0;
|
2020-01-01 20:20:16 +01:00
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
if (mpu->state.cmd_pending) {
|
2018-09-11 22:41:14 +02:00
|
|
|
MPU401_WriteCommand(mpu, mpu->state.cmd_pending - 1);
|
|
|
|
|
mpu->state.cmd_pending = 0;
|
2017-11-23 21:45:10 -05:00
|
|
|
}
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
MPU401_WriteCommand(mpu_t *mpu, uint8_t val)
|
2017-05-09 21:45:20 +02:00
|
|
|
{
|
2020-01-04 03:32:20 +01:00
|
|
|
uint8_t i, j, was_uart, recmsg[3];
|
2017-06-04 16:19:11 +02:00
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
if (mpu->state.reset)
|
|
|
|
|
mpu->state.cmd_pending = val + 1;
|
|
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
/* The only command recognized in UART mode is 0xFF: Reset and return to Intelligent mode. */
|
|
|
|
|
if ((val != 0xff) && (mpu->mode == M_UART))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* In Intelligent mode, UART-only variants of the MPU-401 only support commands 0x3F and 0xFF. */
|
2018-09-11 22:41:14 +02:00
|
|
|
if ((val != 0x3f) && (val != 0xff) && !mpu->intelligent)
|
2020-01-04 03:32:20 +01:00
|
|
|
return;
|
2017-11-23 21:45:10 -05:00
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
/* Hack: Enable midi through after the first mpu401 command is written. */
|
|
|
|
|
mpu->midi_thru = 1;
|
2020-01-01 20:20:16 +01:00
|
|
|
|
|
|
|
|
if (val <= 0x2f) { /* Sequencer state */
|
|
|
|
|
int send_prchg = 0;
|
|
|
|
|
if ((val & 0xf) < 0xc) {
|
|
|
|
|
switch (val & 3) { /* MIDI realtime messages */
|
|
|
|
|
case 1:
|
|
|
|
|
mpu->state.last_rtcmd = 0xfc;
|
|
|
|
|
if (mpu->filter.rt_out)
|
|
|
|
|
midi_raw_out_rt_byte(0xfc);
|
|
|
|
|
mpu->clock.meas_old = mpu->clock.measure_counter;
|
|
|
|
|
mpu->clock.cth_old = mpu->clock.cth_counter;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
mpu->state.last_rtcmd = 0xfa;
|
|
|
|
|
if (mpu->filter.rt_out)
|
|
|
|
|
midi_raw_out_rt_byte(0xfb);
|
|
|
|
|
mpu->clock.measure_counter = mpu->clock.meas_old = 0;
|
|
|
|
|
mpu->clock.cth_counter = mpu->clock.cth_old = 0;
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
mpu->state.last_rtcmd = 0xfc;
|
|
|
|
|
if (mpu->filter.rt_out)
|
|
|
|
|
midi_raw_out_rt_byte(0xfa);
|
|
|
|
|
mpu->clock.measure_counter = mpu->clock.meas_old;
|
|
|
|
|
mpu->clock.cth_counter = mpu->clock.cth_old;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
switch (val & 0xc) { /* Playing */
|
|
|
|
|
case 0x4: /* Stop */
|
|
|
|
|
mpu->state.playing = 0;
|
|
|
|
|
MPU401_StopClock(mpu);
|
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
|
MPU401_NotesOff(mpu, i);
|
|
|
|
|
mpu->filter.prchg_mask = 0;
|
|
|
|
|
break;
|
|
|
|
|
case 0x8: /* Start */
|
|
|
|
|
mpu->state.playing = 1;
|
|
|
|
|
MPU401_StartClock(mpu);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
switch (val & 0x30) { /* Recording */
|
|
|
|
|
case 0: /* check if it waited for MIDI RT command */
|
|
|
|
|
if (((val & 3) < 2) || !mpu->filter.rt_affection || (mpu->state.rec != M_RECSTB))
|
|
|
|
|
break;
|
|
|
|
|
mpu->state.rec = M_RECON;
|
|
|
|
|
MPU401_StartClock(mpu);
|
|
|
|
|
if (mpu->filter.prchg_mask)
|
|
|
|
|
send_prchg = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 0x10: /* Stop */
|
|
|
|
|
mpu->state.rec = M_RECOFF;
|
|
|
|
|
MPU401_StopClock(mpu);
|
|
|
|
|
MPU401_QueueByte(mpu, MSG_MPU_ACK);
|
|
|
|
|
MPU401_QueueByte(mpu, mpu->clock.rec_counter);
|
|
|
|
|
MPU401_QueueByte(mpu, MSG_MPU_END);
|
|
|
|
|
mpu->filter.prchg_mask = 0;
|
|
|
|
|
mpu->clock.rec_counter = 0;
|
|
|
|
|
return;
|
|
|
|
|
case 0x20: /* Start */
|
|
|
|
|
if (!(mpu->state.rec == M_RECON)) {
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu->clock.rec_counter = 0;
|
|
|
|
|
mpu->state.rec = M_RECSTB;
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
|
|
|
|
if ((mpu->state.last_rtcmd == 0xfa) || (mpu->state.last_rtcmd == 0xfb)) {
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu->clock.rec_counter = 0;
|
|
|
|
|
mpu->state.rec = M_RECON;
|
|
|
|
|
if (mpu->filter.prchg_mask)
|
|
|
|
|
send_prchg = 1;
|
|
|
|
|
MPU401_StartClock(mpu);
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
break;
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2017-11-23 21:45:10 -05:00
|
|
|
}
|
2020-01-01 20:20:16 +01:00
|
|
|
MPU401_QueueByte(mpu, MSG_MPU_ACK);
|
|
|
|
|
/* record counter hack: needed by Prism, but sent only on cmd 0x20/0x26 (or breaks Ballade) */
|
|
|
|
|
uint8_t rec_cnt = mpu->clock.rec_counter;
|
|
|
|
|
if (((val == 0x20) || (val == 0x26)) && (mpu->state.rec == M_RECON))
|
|
|
|
|
MPU401_RecQueueBuffer(mpu, &rec_cnt, 1, 0);
|
|
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
if (send_prchg) {
|
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
|
|
|
if (mpu->filter.prchg_mask & (1 << i)) {
|
|
|
|
|
recmsg[0] = mpu->clock.rec_counter;
|
|
|
|
|
recmsg[1] = 0xc0 | i;
|
|
|
|
|
recmsg[2] = mpu->filter.prchg_buf[i];
|
|
|
|
|
MPU401_RecQueueBuffer(mpu, recmsg, 3, 0);
|
|
|
|
|
mpu->filter.prchg_mask &= ~(1 << i);
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
} else if ((val >= 0xa0) && (val <= 0xa7)) /* Request play counter */
|
2020-01-01 20:20:16 +01:00
|
|
|
MPU401_QueueByte(mpu, mpu->playbuf[val & 7].counter);
|
2020-01-04 03:32:20 +01:00
|
|
|
else if ((val >= 0xd0) && (val <= 0xd7)) { /* Send data */
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->state.old_track = mpu->state.track;
|
|
|
|
|
mpu->state.track= val & 7;
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu->state.wsd = 1;
|
|
|
|
|
mpu->state.wsm = 0;
|
|
|
|
|
mpu->state.wsd_start = 1;
|
2020-01-04 03:32:20 +01:00
|
|
|
} else if ((val < 0x80) && (val >= 0x40)) { /* Set reference table channel */
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->chanref[(val >> 4) - 4].on = 1;
|
|
|
|
|
mpu->chanref[(val >> 4) - 4].chan = val & 0x0f;
|
|
|
|
|
mpu->chanref[(val >> 4) - 4].trmask = 0;
|
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
|
mpu->chanref[(val >> 4) - 4].key[i] = 0;
|
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
|
|
|
if (mpu->ch_toref[i] == ((val >> 4) - 4))
|
|
|
|
|
mpu->ch_toref[i] = 4;
|
|
|
|
|
}
|
|
|
|
|
mpu->ch_toref[val & 0x0f] = (val >> 4) - 4;
|
2017-11-23 21:45:10 -05:00
|
|
|
} else switch (val) {
|
2020-01-01 20:20:16 +01:00
|
|
|
case 0x30: /* Configuration 0x30 - 0x39 */
|
|
|
|
|
mpu->filter.allnotesoff_out = 0;
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
2020-01-01 20:20:16 +01:00
|
|
|
case 0x32:
|
|
|
|
|
mpu->filter.rt_out = 0;
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
2020-01-01 20:20:16 +01:00
|
|
|
case 0x33:
|
|
|
|
|
mpu->filter.all_thru = 0;
|
|
|
|
|
mpu->filter.commonmsgs_thru = 0;
|
|
|
|
|
mpu->filter.midi_thru = 0;
|
|
|
|
|
for (i = 0; i < 16; i++) {
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu->inputref[i].on = 0;
|
2020-01-14 19:11:40 +01:00
|
|
|
for (j = 0; j < 4; j++)
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu->inputref[i].key[j] = 0;
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
2020-01-01 20:20:16 +01:00
|
|
|
case 0x34:
|
|
|
|
|
mpu->filter.timing_in_stop = 1;
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
2020-01-01 20:20:16 +01:00
|
|
|
case 0x35:
|
|
|
|
|
mpu->filter.modemsgs_in = 1;
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
2020-01-01 20:20:16 +01:00
|
|
|
case 0x37:
|
|
|
|
|
mpu->filter.sysex_thru = 1;
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
2020-01-01 20:20:16 +01:00
|
|
|
case 0x38:
|
|
|
|
|
mpu->filter.commonmsgs_in = 1;
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
2020-01-01 20:20:16 +01:00
|
|
|
case 0x39:
|
|
|
|
|
mpu->filter.rt_in = 1;
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
2020-01-01 20:20:16 +01:00
|
|
|
case 0x3f: /* UART mode */
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu401_log("MPU-401: Set UART mode %X\n",val);
|
2020-01-01 20:20:16 +01:00
|
|
|
MPU401_QueueByte(mpu, MSG_MPU_ACK);
|
|
|
|
|
mpu->mode = M_UART;
|
|
|
|
|
return;
|
|
|
|
|
case 0x80: /* Internal clock */
|
|
|
|
|
if (mpu->clock.active && mpu->state.sync_in) {
|
|
|
|
|
timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC);
|
|
|
|
|
mpu->clock.freq_mod = 1.0;
|
|
|
|
|
}
|
|
|
|
|
mpu->state.sync_in = 0;
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
2020-01-01 20:20:16 +01:00
|
|
|
case 0x81: /* Sync to tape signal */
|
|
|
|
|
case 0x82: /* Sync to MIDI */
|
|
|
|
|
mpu->clock.ticks_in = 0;
|
|
|
|
|
mpu->state.sync_in = 1;
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
2020-01-01 20:20:16 +01:00
|
|
|
case 0x86: case 0x87: /* Bender */
|
|
|
|
|
mpu->filter.bender_in = !!(val & 1);
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
2020-01-01 20:20:16 +01:00
|
|
|
case 0x88: case 0x89: /* MIDI through */
|
|
|
|
|
mpu->filter.midi_thru = !!(val & 1);
|
|
|
|
|
for (i = 0; i < 16; i++) {
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu->inputref[i].on = mpu->filter.midi_thru;
|
|
|
|
|
if (!(val & 1)) {
|
|
|
|
|
for (j = 0; j < 4; j++)
|
|
|
|
|
mpu->inputref[i].key[j] = 0;
|
|
|
|
|
}
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
2020-01-01 20:20:16 +01:00
|
|
|
case 0x8a: case 0x8b: /* Data in stop */
|
|
|
|
|
mpu->filter.data_in_stop = !!(val & 1);
|
|
|
|
|
break;
|
|
|
|
|
case 0x8c: case 0x8d: /* Send measure end */
|
|
|
|
|
mpu->filter.rec_measure_end = !!(val & 1);
|
|
|
|
|
break;
|
|
|
|
|
case 0x8e: case 0x8f: /* Conductor */
|
|
|
|
|
mpu->state.cond_set = !!(val & 1);
|
|
|
|
|
break;
|
|
|
|
|
case 0x90: case 0x91: /* Realtime affection */
|
|
|
|
|
mpu->filter.rt_affection = !!(val & 1);
|
|
|
|
|
break;
|
|
|
|
|
case 0x94: /* Clock to host */
|
|
|
|
|
mpu->state.clock_to_host = 0;
|
|
|
|
|
MPU401_StopClock(mpu);
|
|
|
|
|
break;
|
|
|
|
|
case 0x95:
|
|
|
|
|
mpu->state.clock_to_host = 1;
|
|
|
|
|
MPU401_StartClock(mpu);
|
|
|
|
|
break;
|
|
|
|
|
case 0x96: case 0x97: /* Sysex input allow */
|
|
|
|
|
mpu->filter.sysex_in = !!(val & 1);
|
|
|
|
|
if (val & 1)
|
|
|
|
|
mpu->filter.sysex_thru = 0;
|
|
|
|
|
break;
|
|
|
|
|
case 0x98: case 0x99: case 0x9a: case 0x9b: /* Reference tables on/off */
|
|
|
|
|
case 0x9c: case 0x9d: case 0x9e: case 0x9f:
|
|
|
|
|
mpu->chanref[(val - 0x98) / 2].on = !!(val & 1);
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
|
|
|
|
/* Commands 0xa# returning data */
|
|
|
|
|
case 0xab: /* Request and clear recording counter */
|
2020-01-01 20:20:16 +01:00
|
|
|
MPU401_QueueByte(mpu, MSG_MPU_ACK);
|
|
|
|
|
MPU401_QueueByte(mpu, 0);
|
2017-11-23 21:45:10 -05:00
|
|
|
return;
|
|
|
|
|
case 0xac: /* Request version */
|
2020-01-01 20:20:16 +01:00
|
|
|
MPU401_QueueByte(mpu, MSG_MPU_ACK);
|
|
|
|
|
MPU401_QueueByte(mpu, MPU401_VERSION);
|
2017-11-23 21:45:10 -05:00
|
|
|
return;
|
|
|
|
|
case 0xad: /* Request revision */
|
2020-01-01 20:20:16 +01:00
|
|
|
MPU401_QueueByte(mpu, MSG_MPU_ACK);
|
|
|
|
|
MPU401_QueueByte(mpu, MPU401_REVISION);
|
2017-11-23 21:45:10 -05:00
|
|
|
return;
|
|
|
|
|
case 0xaf: /* Request tempo */
|
2020-01-01 20:20:16 +01:00
|
|
|
MPU401_QueueByte(mpu, MSG_MPU_ACK);
|
|
|
|
|
MPU401_QueueByte(mpu, mpu->clock.tempo);
|
2017-11-23 21:45:10 -05:00
|
|
|
return;
|
|
|
|
|
case 0xb1: /* Reset relative tempo */
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->clock.old_tempo_rel = mpu->clock.tempo_rel;
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->clock.tempo_rel = 0x40;
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
|
|
|
|
case 0xb8: /* Clear play counters */
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->state.last_rtcmd = 0;
|
2018-09-11 22:41:14 +02:00
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
|
mpu->playbuf[i].counter = 0;
|
|
|
|
|
mpu->playbuf[i].type = T_OVERFLOW;
|
2017-11-23 21:45:10 -05:00
|
|
|
}
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->condbuf.counter = 0;
|
|
|
|
|
mpu->condbuf.type = T_OVERFLOW;
|
|
|
|
|
mpu->state.amask = mpu->state.tmask;
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->state.conductor = mpu->state.cond_set;
|
|
|
|
|
mpu->clock.cth_counter = mpu->clock.cth_old = 0;
|
|
|
|
|
mpu->clock.measure_counter = mpu->clock.meas_old = 0;
|
|
|
|
|
break;
|
|
|
|
|
case 0xb9: /* Clear play map */
|
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
|
MPU401_NotesOff(mpu, i);
|
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
|
mpu->playbuf[i].counter = 0;
|
|
|
|
|
mpu->playbuf[i].type = T_OVERFLOW;
|
|
|
|
|
}
|
|
|
|
|
mpu->state.last_rtcmd = 0;
|
|
|
|
|
mpu->clock.cth_counter = mpu->clock.cth_old = 0;
|
|
|
|
|
mpu->clock.measure_counter = mpu->clock.meas_old = 0;
|
|
|
|
|
break;
|
|
|
|
|
case 0xba: /* Clear record counter */
|
|
|
|
|
mpu->clock.rec_counter = 0;
|
|
|
|
|
break;
|
|
|
|
|
case 0xc2: case 0xc3: case 0xc4: /* Internal timebase */
|
|
|
|
|
case 0xc5: case 0xc6: case 0xc7: case 0xc8:
|
|
|
|
|
mpu->clock.timebase = MPUClockBase[val-0xc2];
|
|
|
|
|
MPU401_ReCalcClock(mpu);
|
|
|
|
|
break;
|
|
|
|
|
case 0xdf: /* Send system message */
|
|
|
|
|
mpu->state.wsd = 0;
|
|
|
|
|
mpu->state.wsm = 1;
|
|
|
|
|
mpu->state.wsd_start = 1;
|
|
|
|
|
break;
|
|
|
|
|
/* Commands with data byte */
|
|
|
|
|
case 0xe0: case 0xe1: case 0xe2: case 0xe4: case 0xe6:
|
|
|
|
|
case 0xe7: case 0xec: case 0xed: case 0xee: case 0xef:
|
|
|
|
|
mpu->state.command_byte = val;
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
|
|
|
|
case 0xff: /* Reset MPU-401 */
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu401_log("MPU-401: Reset %X\n", val);
|
Added the IBM 5161 ISA expansion for PC and XT;
Cleaned up the parallel port emulation, added IRQ support, and made enabling/disabling per port;
Added the Award 430NX and the Intel Classic/PCI (Alfredo, 420TX);
Finished the 586MC1;
Added 8087 emulation;
Moved Cyrix 6x86'es to the Dev branch;
Sanitized/cleaned up memregs.c/h and intel.c/h;
Split the chipsets from machines and sanitized Port 92 emulation;
Added support for the 15bpp mode to the Compaq ATI 28800;
Moved the MR 386DX and 486 machines to the Dev branch;
Ported the new dynamic recompiler from PCem, but it remains in Dev branch until after v2.00;
Ported the new timer code from PCem;
Cleaned up the CPU table of unused stuff and better optimized its structure;
Ported the Open-XT and Open-AT from VARCem, the Open-AT is in the Dev branch;
Ported the XT MFM controller rewrite and adding of more controllers (incl. two RLL ones), from VARCem;
Added the AHA-1540A and the BusTek BT-542B;
Moved the Sumo SCSI-AT to the Dev branch;
Minor IDE, FDC, and floppy drive code clean-ups;
Made NCR 5380/53C400-based cards' BIOS address configurable;
Got rid of the legacy romset variable;
Unified (video) buffer and buffer32 into one and make the unified buffer 32-bit;
Added the Amstead PPC512 per PCem patch by John Elliott;
Switched memory mapping granularity from 16k to 4k (less than 1k not possible due to internal pages);
Rewrote the CL-GD 54xx blitter, fixes Win-OS/2 on the 54x6 among other thing;
Added the Image Manager 1024 and Professional Graphics Controller per PCem patch by John Elliott and work done on VARCem;
Added Headland HT-216, GC-205 and Video 7 VGA 1024i emulation based on PCem commit;
Implemented the fuction keys for the Toshiba T1000/T1200/T3100 enhancement;
Amstrad MegaPC does now works correctly with non-internal graphics card;
The SLiRP code no longer casts a packed struct type to a non-packed struct type;
The Xi8088 and PB410a no longer hang on 86Box when PS/2 mouse is not present;
The S3 Virge on BeOS is no longer broken (was broken by build #1591);
OS/2 2.0 build 6.167 now sees key presses again;
Xi8088 now work on CGA again;
86F images converted from either the old or new variants of the HxC MFM format now work correctly;
Hardware interrupts with a vector of 0xFF are now handled correctly;
OPTi 495SX boards no longer incorrectly have 64 MB maximum RAM when 32 MB is correct;
Fixed VNC keyboard input bugs;
Fixed AT RTC periodic interrupt - Chicago 58s / 73f / 73g / 81 MIDI play no longer hangs with the build's own VTD driver;
Fixed mouse polling with internal mice - Amstrad and Olivetti mice now work correctly;
Triones ATAPI DMA driver now correctly reads a file at the end of a CD image with a sectors number not divisible by 4;
Compaq Portable now works with all graphics cards;
Fixed various MDSI Genius bugs;
Added segment limit checks and improved page fault checks for several CPU instructions - Memphis 15xx WINSETUP and Chicago 58s WINDISK.CPL no longer issue a GPF, and some S3 drivers that used to have glitches, now work correctly;
Further improved the 808x emulation, also fixes the noticably choppy sound when using 808x CPU's, also fixes #355;
OS/2 installer no logner locks up on splash screen on PS/2 Model 70 and 80, fixes #400.
Fixed several Amstead bugs, GEM no longer crashes on the Amstrad 1640, fixes #391.
Ported John Elliott's Amstrad fixes and improvement from PCem, and fixed the default language so it's correctly Engliish, fixes #278, fixes #389.
Fixed a minor IDE timing bug, fixes #388.
Fixed Toshiba T1000 RAM issues, fixes #379.
Fixed EGA/(S)VGA overscan border handling, fixes #378;
Got rid of the now long useless IDE channel 2 auto-removal, fixes #370;
Fixed the BIOS files used by the AMSTRAD PC1512, fixes #366;
Ported the Unicode CD image file name fix from VARCem, fixes #365;
Fixed high density floppy disks on the Xi8088, fixes #359;
Fixed some bugs in the Hercules emulation, fixes #346, fixes #358;
Fixed the SCSI hard disk mode sense pages, fixes #356;
Removed the AMI Unknown 386SX because of impossibility to identify the chipset, closes #349;
Fixed bugs in the serial mouse emulation, fixes #344;
Compiled 86Box binaries now include all the required .DLL's, fixes #341;
Made some combo boxes in the Settings dialog slightly wider, fixes #276.
2019-09-20 14:02:30 +02:00
|
|
|
timer_set_delay_u64(&mpu->mpu401_reset_callback, MPU401_RESETBUSY * 33LL * TIMER_USEC);
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.reset = 1;
|
|
|
|
|
was_uart = (mpu->mode == M_UART);
|
2017-11-23 21:45:10 -05:00
|
|
|
MPU401_Reset(mpu);
|
2018-09-11 22:41:14 +02:00
|
|
|
if (was_uart)
|
2020-01-23 06:40:20 +01:00
|
|
|
return;
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
|
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
/* default:
|
|
|
|
|
mpu401_log("MPU-401:Unhandled command %X",val); */
|
2017-11-23 21:45:10 -05:00
|
|
|
}
|
|
|
|
|
|
2020-01-01 20:20:16 +01:00
|
|
|
MPU401_QueueByte(mpu, MSG_MPU_ACK);
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
MPU401_WriteData(mpu_t *mpu, uint8_t val)
|
2017-05-09 21:45:20 +02:00
|
|
|
{
|
2020-01-01 20:20:16 +01:00
|
|
|
static int length, cnt;
|
|
|
|
|
uint8_t i;
|
2018-09-11 22:41:14 +02:00
|
|
|
|
|
|
|
|
if (mpu->mode == M_UART) {
|
2020-01-01 20:20:16 +01:00
|
|
|
midi_raw_out_byte(val);
|
2018-09-11 22:41:14 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!mpu->intelligent) {
|
|
|
|
|
mpu->state.command_byte = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-05-09 21:45:20 +02:00
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
switch (mpu->state.command_byte) { /* 0xe# command data */
|
|
|
|
|
case 0x00:
|
|
|
|
|
break;
|
|
|
|
|
case 0xe0: /* Set tempo */
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.command_byte = 0;
|
2020-01-01 20:20:16 +01:00
|
|
|
if (mpu->clock.tempo < 8)
|
|
|
|
|
mpu->clock.tempo = 8;
|
|
|
|
|
else if (mpu->clock.tempo > 250)
|
|
|
|
|
mpu->clock.tempo = 250;
|
|
|
|
|
else
|
|
|
|
|
mpu->clock.tempo = val;
|
|
|
|
|
MPU401_ReCalcClock(mpu);
|
2017-05-09 21:45:20 +02:00
|
|
|
return;
|
2017-11-23 21:45:10 -05:00
|
|
|
case 0xe1: /* Set relative tempo */
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.command_byte = 0;
|
|
|
|
|
mpu->clock.old_tempo_rel = mpu->clock.tempo_rel;
|
|
|
|
|
mpu->clock.tempo_rel = val;
|
2020-01-01 20:20:16 +01:00
|
|
|
MPU401_ReCalcClock(mpu);
|
2017-05-09 21:45:20 +02:00
|
|
|
return;
|
2020-01-01 20:20:16 +01:00
|
|
|
case 0xe2: /* Set gradation for relative tempo */
|
|
|
|
|
mpu->clock.tempo_grad = val;
|
|
|
|
|
MPU401_ReCalcClock(mpu);
|
|
|
|
|
return;
|
|
|
|
|
case 0xe4: /* Set MIDI clocks for metronome ticks */
|
|
|
|
|
mpu->state.command_byte = 0;
|
|
|
|
|
mpu->clock.midimetro = val;
|
|
|
|
|
return;
|
|
|
|
|
case 0xe6: /* Set metronome ticks per measure */
|
|
|
|
|
mpu->state.command_byte = 0;
|
|
|
|
|
mpu->clock.metromeas = val;
|
|
|
|
|
return;
|
2017-11-23 21:45:10 -05:00
|
|
|
case 0xe7: /* Set internal clock to host interval */
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.command_byte = 0;
|
2020-01-01 20:20:16 +01:00
|
|
|
if (!val)
|
|
|
|
|
val = 64;
|
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
|
mpu->clock.cth_rate[i] = (val >> 2) + cth_data[(val & 3) * 4 + i];
|
|
|
|
|
mpu->clock.cth_mode = 0;
|
2017-11-23 21:45:10 -05:00
|
|
|
return;
|
|
|
|
|
case 0xec: /* Set active track mask */
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.command_byte = 0;
|
|
|
|
|
mpu->state.tmask = val;
|
2017-11-23 21:45:10 -05:00
|
|
|
return;
|
|
|
|
|
case 0xed: /* Set play counter mask */
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.command_byte = 0;
|
|
|
|
|
mpu->state.cmask = val;
|
2017-11-23 21:45:10 -05:00
|
|
|
return;
|
|
|
|
|
case 0xee: /* Set 1-8 MIDI channel mask */
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.command_byte = 0;
|
|
|
|
|
mpu->state.midi_mask &= 0xff00;
|
|
|
|
|
mpu->state.midi_mask |= val;
|
2017-11-23 21:45:10 -05:00
|
|
|
return;
|
|
|
|
|
case 0xef: /* Set 9-16 MIDI channel mask */
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.command_byte = 0;
|
|
|
|
|
mpu->state.midi_mask &= 0x00ff;
|
|
|
|
|
mpu->state.midi_mask |= ((uint16_t) val) << 8;
|
2017-11-23 21:45:10 -05:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
default:
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.command_byte = 0;
|
2017-11-23 21:45:10 -05:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-01 20:20:16 +01:00
|
|
|
if (mpu->state.wsd && !mpu->state.track_req && !mpu->state.cond_req) {
|
2017-11-23 21:45:10 -05:00
|
|
|
/* Directly send MIDI message */
|
|
|
|
|
if (mpu->state.wsd_start) {
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.wsd_start = 0;
|
|
|
|
|
cnt = 0;
|
|
|
|
|
switch (val & 0xf0) {
|
|
|
|
|
case 0xc0: case 0xd0:
|
2020-01-01 20:20:16 +01:00
|
|
|
length = mpu->playbuf[mpu->state.track].length = 2;
|
|
|
|
|
mpu->playbuf[mpu->state.track].type = T_MIDI_NORM;
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
2018-09-11 22:41:14 +02:00
|
|
|
case 0x80: case 0x90: case 0xa0: case 0xb0:case 0xe0:
|
2020-01-01 20:20:16 +01:00
|
|
|
length = mpu->playbuf[mpu->state.track].length = 3;
|
|
|
|
|
mpu->playbuf[mpu->state.track].type = T_MIDI_NORM;
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0xf0:
|
2018-09-11 22:41:14 +02:00
|
|
|
/* mpu401_log("MPU-401:Illegal WSD byte\n"); */
|
|
|
|
|
mpu->state.wsd = 0;
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->state.track = mpu->state.old_track;
|
2017-05-09 21:45:20 +02:00
|
|
|
return;
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
default: /* MIDI with running status */
|
|
|
|
|
cnt++;
|
2020-01-01 20:20:16 +01:00
|
|
|
length = mpu->playbuf[mpu->state.track].length;
|
|
|
|
|
mpu->playbuf[mpu->state.track].type = T_MIDI_NORM;
|
2017-11-23 21:45:10 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
if (cnt < length) {
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->playbuf[mpu->state.track].value[cnt] = val;
|
2018-09-11 22:41:14 +02:00
|
|
|
cnt++;
|
|
|
|
|
}
|
2017-11-23 21:45:10 -05:00
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
if (cnt == length) {
|
2020-01-01 20:20:16 +01:00
|
|
|
MPU401_IntelligentOut(mpu, mpu->state.track);
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.wsd = 0;
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->state.track = mpu->state.old_track;
|
2017-11-23 21:45:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-01 20:20:16 +01:00
|
|
|
if (mpu->state.wsm && !mpu->state.track_req && !mpu->state.cond_req) { /* Send system message */
|
2017-11-23 21:45:10 -05:00
|
|
|
if (mpu->state.wsd_start) {
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.wsd_start = 0;
|
|
|
|
|
cnt = 0;
|
2017-11-23 21:45:10 -05:00
|
|
|
switch (val) {
|
|
|
|
|
case 0xf2:
|
2018-09-11 22:41:14 +02:00
|
|
|
length = 3;
|
2017-05-09 21:45:20 +02:00
|
|
|
break;
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
case 0xf3:
|
2018-09-11 22:41:14 +02:00
|
|
|
length = 2;
|
2017-05-09 21:45:20 +02:00
|
|
|
break;
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
case 0xf6:
|
2018-09-11 22:41:14 +02:00
|
|
|
length = 1;
|
2017-05-09 21:45:20 +02:00
|
|
|
break;
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
case 0xf0:
|
2018-09-11 22:41:14 +02:00
|
|
|
length = 0;
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->state.wsm = 0;
|
|
|
|
|
return;
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
2020-01-01 20:20:16 +01:00
|
|
|
} else if (val & 0x80) {
|
|
|
|
|
midi_raw_out_byte(MSG_EOX);
|
|
|
|
|
mpu->state.wsm = 0;
|
|
|
|
|
return;
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
2017-11-23 21:45:10 -05:00
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
if (!length || (cnt < length)) {
|
2020-01-01 20:20:16 +01:00
|
|
|
midi_raw_out_byte(val);
|
2017-11-23 21:45:10 -05:00
|
|
|
cnt++;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
if (cnt == length)
|
|
|
|
|
mpu->state.wsm = 0;
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mpu->state.cond_req) {
|
|
|
|
|
/* Command */
|
|
|
|
|
switch (mpu->state.data_onoff) {
|
|
|
|
|
case -1:
|
2017-05-09 21:45:20 +02:00
|
|
|
return;
|
2017-11-23 21:45:10 -05:00
|
|
|
case 0: /* Timing byte */
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->condbuf.length = 0;
|
2018-09-11 22:41:14 +02:00
|
|
|
if (val < 0xf0)
|
|
|
|
|
mpu->state.data_onoff++;
|
|
|
|
|
else {
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->state.cond_req = 0;
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.data_onoff = -1;
|
2017-05-09 21:45:20 +02:00
|
|
|
MPU401_EOIHandlerDispatch(mpu);
|
2020-01-01 20:20:16 +01:00
|
|
|
break;
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.send_now = !val ? 1 : 0;
|
|
|
|
|
mpu->condbuf.counter = val;
|
2017-05-09 21:45:20 +02:00
|
|
|
break;
|
2017-11-23 21:45:10 -05:00
|
|
|
case 1: /* Command byte #1 */
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->condbuf.type = T_COMMAND;
|
2020-01-01 20:20:16 +01:00
|
|
|
if ((val == 0xf8) || (val == 0xf9) || (val == 0xfc))
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->condbuf.type = T_OVERFLOW;
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->condbuf.value[mpu->condbuf.length] = val;
|
|
|
|
|
mpu->condbuf.length++;
|
|
|
|
|
if ((val & 0xf0) != 0xe0) { /*no cmd data byte*/
|
|
|
|
|
MPU401_EOIHandler(mpu);
|
|
|
|
|
mpu->state.data_onoff = -1;
|
|
|
|
|
mpu->state.cond_req = 0;
|
|
|
|
|
} else
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.data_onoff++;
|
2017-05-09 21:45:20 +02:00
|
|
|
break;
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
case 2:/* Command byte #2 */
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->condbuf.value[mpu->condbuf.length]=val;
|
|
|
|
|
mpu->condbuf.length++;
|
|
|
|
|
MPU401_EOIHandler(mpu);
|
|
|
|
|
mpu->state.data_onoff = -1;
|
|
|
|
|
mpu->state.cond_req = 0;
|
2017-05-09 21:45:20 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2017-11-23 21:45:10 -05:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (mpu->state.data_onoff) {
|
|
|
|
|
/* Data */
|
|
|
|
|
case -1:
|
2020-01-01 20:20:16 +01:00
|
|
|
break;
|
2017-11-23 21:45:10 -05:00
|
|
|
case 0: /* Timing byte */
|
2018-09-11 22:41:14 +02:00
|
|
|
if (val < 0xf0)
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->state.data_onoff++;
|
2018-09-11 22:41:14 +02:00
|
|
|
else {
|
|
|
|
|
mpu->state.data_onoff = -1;
|
2017-11-23 21:45:10 -05:00
|
|
|
MPU401_EOIHandlerDispatch(mpu);
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->state.track_req = 0;
|
2017-11-23 21:45:10 -05:00
|
|
|
return;
|
|
|
|
|
}
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.send_now = !val ? 1 : 0;
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->playbuf[mpu->state.track].counter = val;
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
|
|
|
|
case 1: /* MIDI */
|
2020-01-01 20:20:16 +01:00
|
|
|
cnt = 0;
|
|
|
|
|
mpu->state.data_onoff++;
|
|
|
|
|
switch (val & 0xf0) {
|
|
|
|
|
case 0xc0: case 0xd0: /* MIDI Message */
|
|
|
|
|
length = mpu->playbuf[mpu->state.track].length = 2;
|
|
|
|
|
mpu->playbuf[mpu->state.track].type = T_MIDI_NORM;
|
|
|
|
|
break;
|
|
|
|
|
case 0x80: case 0x90: case 0xa0: case 0xb0: case 0xe0:
|
|
|
|
|
length = mpu->playbuf[mpu->state.track].length = 3;
|
|
|
|
|
mpu->playbuf[mpu->state.track].type = T_MIDI_NORM;
|
|
|
|
|
break;
|
2017-11-23 21:45:10 -05:00
|
|
|
case 0xf0: /* System message or mark */
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->playbuf[mpu->state.track].sys_val = val;
|
2018-09-11 22:41:14 +02:00
|
|
|
if (val > 0xf7) {
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->playbuf[mpu->state.track].type = T_MARK;
|
|
|
|
|
if (val == 0xf9)
|
|
|
|
|
mpu->clock.measure_counter = 0;
|
2017-11-23 21:45:10 -05:00
|
|
|
} else {
|
2018-09-11 22:41:14 +02:00
|
|
|
/* mpu401_log("MPU-401:Illegal message"); */
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->playbuf[mpu->state.track].type = T_OVERFLOW;
|
2017-11-23 21:45:10 -05:00
|
|
|
}
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->state.data_onoff = -1;
|
|
|
|
|
MPU401_EOIHandler(mpu);
|
|
|
|
|
mpu->state.track_req = 0;
|
|
|
|
|
return;
|
|
|
|
|
default: /* MIDI with running status */
|
|
|
|
|
cnt++;
|
|
|
|
|
length = mpu->playbuf[mpu->state.track].length;
|
|
|
|
|
mpu->playbuf[mpu->state.track].type = T_MIDI_NORM;
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
|
|
|
|
}
|
2020-01-01 20:20:16 +01:00
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
if (cnt < length) {
|
|
|
|
|
mpu->playbuf[mpu->state.track].value[cnt] = val;
|
|
|
|
|
cnt++;
|
|
|
|
|
}
|
|
|
|
|
if (cnt == length) {
|
|
|
|
|
mpu->state.data_onoff = -1;
|
|
|
|
|
mpu->state.track_req = 0;
|
|
|
|
|
MPU401_EOIHandler(mpu);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2017-11-23 21:45:10 -05:00
|
|
|
}
|
2020-01-01 20:20:16 +01:00
|
|
|
|
|
|
|
|
return;
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
static void
|
2020-01-01 20:20:16 +01:00
|
|
|
MPU401_IntelligentOut(mpu_t *mpu, uint8_t track)
|
2017-05-09 21:45:20 +02:00
|
|
|
{
|
2020-01-01 20:20:16 +01:00
|
|
|
uint8_t chan, chrefnum, key, msg;
|
|
|
|
|
int send, retrigger;
|
2017-11-23 21:45:10 -05:00
|
|
|
uint8_t i;
|
|
|
|
|
|
2020-01-01 20:20:16 +01:00
|
|
|
switch (mpu->playbuf[track].type) {
|
2017-11-23 21:45:10 -05:00
|
|
|
case T_OVERFLOW:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case T_MARK:
|
2020-01-01 20:20:16 +01:00
|
|
|
if (mpu->playbuf[track].sys_val == 0xfc) {
|
|
|
|
|
midi_raw_out_rt_byte(mpu->playbuf[track].sys_val);
|
|
|
|
|
mpu->state.amask&=~(1<<track);
|
2017-11-23 21:45:10 -05:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case T_MIDI_NORM:
|
2020-01-01 20:20:16 +01:00
|
|
|
chan = mpu->playbuf[track].value[0] & 0xf;
|
|
|
|
|
key = mpu->playbuf[track].value[1] & 0x7f;
|
|
|
|
|
chrefnum = mpu->ch_toref[chan];
|
|
|
|
|
send = 1;
|
|
|
|
|
retrigger = 0;
|
|
|
|
|
switch (msg = mpu->playbuf[track].value[0] & 0xf0) {
|
|
|
|
|
case 0x80: /* note off */
|
|
|
|
|
if (mpu->inputref[chan].on && (mpu->inputref[chan].M_GETKEY))
|
|
|
|
|
send = 0;
|
|
|
|
|
if (mpu->chanref[chrefnum].on && (!(mpu->chanref[chrefnum].M_GETKEY)))
|
|
|
|
|
send = 0;
|
|
|
|
|
mpu->chanref[chrefnum].M_DELKEY;
|
|
|
|
|
break;
|
|
|
|
|
case 0x90: /* note on */
|
|
|
|
|
if (mpu->inputref[chan].on && (mpu->inputref[chan].M_GETKEY))
|
|
|
|
|
retrigger = 1;
|
|
|
|
|
if (mpu->chanref[chrefnum].on && (!(mpu->chanref[chrefnum].M_GETKEY)))
|
|
|
|
|
retrigger = 1;
|
|
|
|
|
mpu->chanref[chrefnum].M_SETKEY;
|
|
|
|
|
break;
|
|
|
|
|
case 0xb0:
|
|
|
|
|
if (mpu->playbuf[track].value[1] == 123) { /* All notes off */
|
|
|
|
|
MPU401_NotesOff(mpu, mpu->playbuf[track].value[0] & 0xf);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (retrigger) {
|
|
|
|
|
midi_raw_out_byte(0x80 | chan);
|
|
|
|
|
midi_raw_out_byte(key);
|
|
|
|
|
midi_raw_out_byte(0);
|
|
|
|
|
}
|
|
|
|
|
if (send) {
|
|
|
|
|
for (i = 0; i < mpu->playbuf[track].length; i++)
|
|
|
|
|
midi_raw_out_byte(mpu->playbuf[track].value[i]);
|
|
|
|
|
}
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
2020-01-01 20:20:16 +01:00
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2020-01-01 20:20:16 +01:00
|
|
|
UpdateTrack(mpu_t *mpu, uint8_t track)
|
2017-11-23 21:45:10 -05:00
|
|
|
{
|
2020-01-01 20:20:16 +01:00
|
|
|
MPU401_IntelligentOut(mpu, track);
|
2017-11-23 21:45:10 -05:00
|
|
|
|
2020-01-01 20:20:16 +01:00
|
|
|
if (mpu->state.amask&(1<<track)) {
|
|
|
|
|
mpu->playbuf[track].type = T_OVERFLOW;
|
|
|
|
|
mpu->playbuf[track].counter = 0xf0;
|
|
|
|
|
mpu->state.req_mask |= (1 << track);
|
2017-11-23 21:45:10 -05:00
|
|
|
} else {
|
2018-09-11 22:41:14 +02:00
|
|
|
if ((mpu->state.amask == 0) && !mpu->state.conductor)
|
|
|
|
|
mpu->state.req_mask |= (1 << 12);
|
2017-11-23 21:45:10 -05:00
|
|
|
}
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
|
2020-01-01 20:20:16 +01:00
|
|
|
#if 0
|
2017-11-23 21:45:10 -05:00
|
|
|
static void
|
|
|
|
|
UpdateConductor(mpu_t *mpu)
|
2017-05-09 21:45:20 +02:00
|
|
|
{
|
2018-09-11 22:41:14 +02:00
|
|
|
if (mpu->condbuf.value[0] == 0xfc) {
|
|
|
|
|
mpu->condbuf.value[0] = 0;
|
|
|
|
|
mpu->state.conductor = 0;
|
|
|
|
|
mpu->state.req_mask &= ~(1 << 9);
|
|
|
|
|
if (mpu->state.amask == 0)
|
|
|
|
|
mpu->state.req_mask |= (1 << 12);
|
2017-11-23 21:45:10 -05:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->condbuf.vlength = 0;
|
|
|
|
|
mpu->condbuf.counter = 0xf0;
|
|
|
|
|
mpu->state.req_mask |= (1 << 9);
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
2020-01-01 20:20:16 +01:00
|
|
|
#endif
|
2017-05-09 21:45:20 +02:00
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
/* Updates counters and requests new data on "End of Input" */
|
2017-11-23 21:45:10 -05:00
|
|
|
static void
|
|
|
|
|
MPU401_EOIHandler(void *priv)
|
2017-05-09 21:45:20 +02:00
|
|
|
{
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu_t *mpu = (mpu_t *)priv;
|
|
|
|
|
uint8_t i;
|
2017-05-10 20:39:46 +02:00
|
|
|
|
2018-05-21 19:04:05 +02:00
|
|
|
mpu401_log("MPU-401 end of input callback\n");
|
2017-05-09 21:45:20 +02:00
|
|
|
|
Added the IBM 5161 ISA expansion for PC and XT;
Cleaned up the parallel port emulation, added IRQ support, and made enabling/disabling per port;
Added the Award 430NX and the Intel Classic/PCI (Alfredo, 420TX);
Finished the 586MC1;
Added 8087 emulation;
Moved Cyrix 6x86'es to the Dev branch;
Sanitized/cleaned up memregs.c/h and intel.c/h;
Split the chipsets from machines and sanitized Port 92 emulation;
Added support for the 15bpp mode to the Compaq ATI 28800;
Moved the MR 386DX and 486 machines to the Dev branch;
Ported the new dynamic recompiler from PCem, but it remains in Dev branch until after v2.00;
Ported the new timer code from PCem;
Cleaned up the CPU table of unused stuff and better optimized its structure;
Ported the Open-XT and Open-AT from VARCem, the Open-AT is in the Dev branch;
Ported the XT MFM controller rewrite and adding of more controllers (incl. two RLL ones), from VARCem;
Added the AHA-1540A and the BusTek BT-542B;
Moved the Sumo SCSI-AT to the Dev branch;
Minor IDE, FDC, and floppy drive code clean-ups;
Made NCR 5380/53C400-based cards' BIOS address configurable;
Got rid of the legacy romset variable;
Unified (video) buffer and buffer32 into one and make the unified buffer 32-bit;
Added the Amstead PPC512 per PCem patch by John Elliott;
Switched memory mapping granularity from 16k to 4k (less than 1k not possible due to internal pages);
Rewrote the CL-GD 54xx blitter, fixes Win-OS/2 on the 54x6 among other thing;
Added the Image Manager 1024 and Professional Graphics Controller per PCem patch by John Elliott and work done on VARCem;
Added Headland HT-216, GC-205 and Video 7 VGA 1024i emulation based on PCem commit;
Implemented the fuction keys for the Toshiba T1000/T1200/T3100 enhancement;
Amstrad MegaPC does now works correctly with non-internal graphics card;
The SLiRP code no longer casts a packed struct type to a non-packed struct type;
The Xi8088 and PB410a no longer hang on 86Box when PS/2 mouse is not present;
The S3 Virge on BeOS is no longer broken (was broken by build #1591);
OS/2 2.0 build 6.167 now sees key presses again;
Xi8088 now work on CGA again;
86F images converted from either the old or new variants of the HxC MFM format now work correctly;
Hardware interrupts with a vector of 0xFF are now handled correctly;
OPTi 495SX boards no longer incorrectly have 64 MB maximum RAM when 32 MB is correct;
Fixed VNC keyboard input bugs;
Fixed AT RTC periodic interrupt - Chicago 58s / 73f / 73g / 81 MIDI play no longer hangs with the build's own VTD driver;
Fixed mouse polling with internal mice - Amstrad and Olivetti mice now work correctly;
Triones ATAPI DMA driver now correctly reads a file at the end of a CD image with a sectors number not divisible by 4;
Compaq Portable now works with all graphics cards;
Fixed various MDSI Genius bugs;
Added segment limit checks and improved page fault checks for several CPU instructions - Memphis 15xx WINSETUP and Chicago 58s WINDISK.CPL no longer issue a GPF, and some S3 drivers that used to have glitches, now work correctly;
Further improved the 808x emulation, also fixes the noticably choppy sound when using 808x CPU's, also fixes #355;
OS/2 installer no logner locks up on splash screen on PS/2 Model 70 and 80, fixes #400.
Fixed several Amstead bugs, GEM no longer crashes on the Amstrad 1640, fixes #391.
Ported John Elliott's Amstrad fixes and improvement from PCem, and fixed the default language so it's correctly Engliish, fixes #278, fixes #389.
Fixed a minor IDE timing bug, fixes #388.
Fixed Toshiba T1000 RAM issues, fixes #379.
Fixed EGA/(S)VGA overscan border handling, fixes #378;
Got rid of the now long useless IDE channel 2 auto-removal, fixes #370;
Fixed the BIOS files used by the AMSTRAD PC1512, fixes #366;
Ported the Unicode CD image file name fix from VARCem, fixes #365;
Fixed high density floppy disks on the Xi8088, fixes #359;
Fixed some bugs in the Hercules emulation, fixes #346, fixes #358;
Fixed the SCSI hard disk mode sense pages, fixes #356;
Removed the AMI Unknown 386SX because of impossibility to identify the chipset, closes #349;
Fixed bugs in the serial mouse emulation, fixes #344;
Compiled 86Box binaries now include all the required .DLL's, fixes #341;
Made some combo boxes in the Settings dialog slightly wider, fixes #276.
2019-09-20 14:02:30 +02:00
|
|
|
timer_disable(&mpu->mpu401_eoi_callback);
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.eoi_scheduled = 0;
|
2017-11-23 21:45:10 -05:00
|
|
|
if (mpu->state.send_now) {
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.send_now = 0;
|
2020-01-01 20:20:16 +01:00
|
|
|
if (mpu->state.cond_req) {
|
|
|
|
|
mpu->condbuf.counter = 0xf0;
|
|
|
|
|
mpu->state.req_mask |= (1 << 9);
|
|
|
|
|
} else UpdateTrack(mpu, mpu->state.track);
|
2017-11-23 21:45:10 -05:00
|
|
|
}
|
|
|
|
|
|
2020-01-01 20:20:16 +01:00
|
|
|
if (mpu->state.rec_copy || !mpu->state.sysex_in_finished)
|
|
|
|
|
return;
|
|
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.irq_pending = 0;
|
2017-11-23 21:45:10 -05:00
|
|
|
|
2020-01-01 20:20:16 +01:00
|
|
|
if (!(mpu->state.req_mask && mpu->clock.active))
|
2018-09-11 22:41:14 +02:00
|
|
|
return;
|
2017-11-23 21:45:10 -05:00
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
i = 0;
|
2017-11-23 21:45:10 -05:00
|
|
|
do {
|
2018-09-11 22:41:14 +02:00
|
|
|
if (mpu->state.req_mask & (1 << i)) {
|
2020-01-01 20:20:16 +01:00
|
|
|
MPU401_QueueByte(mpu, 0xf0 + i);
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.req_mask &= ~(1 << i);
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
2018-09-11 22:41:14 +02:00
|
|
|
} while ((i++) < 16);
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
MPU401_EOIHandlerDispatch(void *priv)
|
2017-05-09 21:45:20 +02:00
|
|
|
{
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu_t *mpu = (mpu_t *)priv;
|
|
|
|
|
|
2018-09-04 13:26:07 +02:00
|
|
|
mpu401_log("EOI handler dispatch\n");
|
2017-11-23 21:45:10 -05:00
|
|
|
if (mpu->state.send_now) {
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.eoi_scheduled = 1;
|
2020-01-01 20:20:16 +01:00
|
|
|
timer_advance_u64(&mpu->mpu401_eoi_callback, 60LL * TIMER_USEC); /* Possibly a bit longer */
|
2017-11-23 21:45:10 -05:00
|
|
|
} else if (!mpu->state.eoi_scheduled)
|
|
|
|
|
MPU401_EOIHandler(mpu);
|
2017-05-10 20:39:46 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
imf_write(uint16_t addr, uint8_t val, void *priv)
|
2017-05-10 20:39:46 +02:00
|
|
|
{
|
2018-05-21 19:04:05 +02:00
|
|
|
mpu401_log("IMF:Wr %4X,%X\n", addr, val);
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
void
|
|
|
|
|
MPU401_ReadRaiseIRQ(mpu_t *mpu)
|
|
|
|
|
{
|
|
|
|
|
/* Clear IRQ. */
|
|
|
|
|
picintc(1 << mpu->irq);
|
|
|
|
|
mpu->state.irq_pending = 0;
|
|
|
|
|
|
|
|
|
|
if (mpu->queue_used) {
|
|
|
|
|
/* Bytes remaining in queue, raise IRQ again. */
|
|
|
|
|
mpu->state.irq_pending = 1;
|
|
|
|
|
picint(1 << mpu->irq);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
uint8_t
|
|
|
|
|
MPU401_ReadData(mpu_t *mpu)
|
2017-05-10 18:29:16 +02:00
|
|
|
{
|
2017-11-23 21:45:10 -05:00
|
|
|
uint8_t ret;
|
2017-05-10 18:29:16 +02:00
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
ret = MSG_MPU_ACK;
|
2020-01-02 18:19:22 +01:00
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
if (mpu->queue_used) {
|
2018-09-11 22:41:14 +02:00
|
|
|
if (mpu->queue_pos >= MPU401_QUEUE)
|
|
|
|
|
mpu->queue_pos -= MPU401_QUEUE;
|
|
|
|
|
ret = mpu->queue[mpu->queue_pos];
|
|
|
|
|
mpu->queue_pos++;
|
|
|
|
|
mpu->queue_used--;
|
2017-11-23 21:45:10 -05:00
|
|
|
}
|
2017-05-10 18:29:16 +02:00
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
/* Shouldn't this check mpu->mode? */
|
2018-09-15 20:17:13 +02:00
|
|
|
if (mpu->mode == M_UART) {
|
2020-01-04 03:32:20 +01:00
|
|
|
MPU401_ReadRaiseIRQ(mpu);
|
2018-09-11 22:41:14 +02:00
|
|
|
return ret;
|
2018-09-15 20:17:13 +02:00
|
|
|
}
|
2017-05-10 18:29:16 +02:00
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
if (mpu->state.rec_copy && !mpu->rec_queue_used) {
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->state.rec_copy = 0;
|
|
|
|
|
MPU401_EOIHandler(mpu);
|
|
|
|
|
return ret;
|
2020-01-04 03:32:20 +01:00
|
|
|
}
|
2020-01-01 20:20:16 +01:00
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
/* Copy from recording buffer. */
|
|
|
|
|
if (!mpu->queue_used && mpu->rec_queue_used) {
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->state.rec_copy = 1;
|
|
|
|
|
if (mpu->rec_queue_pos >= MPU401_INPUT_QUEUE)
|
|
|
|
|
mpu->rec_queue_pos -= MPU401_INPUT_QUEUE;
|
|
|
|
|
MPU401_QueueByte(mpu, mpu->rec_queue[mpu->rec_queue_pos]);
|
|
|
|
|
mpu->rec_queue_pos++;
|
|
|
|
|
mpu->rec_queue_used--;
|
2018-09-15 20:17:13 +02:00
|
|
|
}
|
2017-11-23 21:45:10 -05:00
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
MPU401_ReadRaiseIRQ(mpu);
|
|
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
if ((ret >= 0xf0) && (ret <= 0xf7)) {
|
2017-11-23 21:45:10 -05:00
|
|
|
/* MIDI data request */
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->state.track = ret & 7;
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.data_onoff = 0;
|
|
|
|
|
mpu->state.cond_req = 0;
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->state.track_req = 1;
|
2017-11-23 21:45:10 -05:00
|
|
|
}
|
|
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
if (ret == MSG_MPU_COMMAND_REQ) {
|
|
|
|
|
mpu->state.data_onoff = 0;
|
|
|
|
|
mpu->state.cond_req = 1;
|
|
|
|
|
if (mpu->condbuf.type != T_OVERFLOW) {
|
|
|
|
|
mpu->state.block_ack = 1;
|
2017-11-23 21:45:10 -05:00
|
|
|
MPU401_WriteCommand(mpu, mpu->condbuf.value[0]);
|
|
|
|
|
if (mpu->state.command_byte)
|
|
|
|
|
MPU401_WriteData(mpu, mpu->condbuf.value[1]);
|
2020-01-01 20:20:16 +01:00
|
|
|
mpu->condbuf.type = T_OVERFLOW;
|
2017-05-10 18:29:16 +02:00
|
|
|
}
|
2017-11-23 21:45:10 -05:00
|
|
|
}
|
|
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
if ((ret == MSG_MPU_END) || (ret == MSG_MPU_CLOCK) || (ret == MSG_MPU_ACK) || (ret == MSG_MPU_OVERFLOW))
|
2017-11-23 21:45:10 -05:00
|
|
|
MPU401_EOIHandlerDispatch(mpu);
|
|
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
return ret;
|
2017-05-10 18:29:16 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
mpu401_write(uint16_t addr, uint8_t val, void *priv)
|
2017-05-09 21:45:20 +02:00
|
|
|
{
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu_t *mpu = (mpu_t *)priv;
|
|
|
|
|
|
2018-05-21 19:04:05 +02:00
|
|
|
/* mpu401_log("MPU401 Write Port %04X, val %x\n", addr, val); */
|
2017-11-23 21:45:10 -05:00
|
|
|
switch (addr & 1) {
|
|
|
|
|
case 0: /*Data*/
|
2017-05-09 21:45:20 +02:00
|
|
|
MPU401_WriteData(mpu, val);
|
2018-05-21 19:04:05 +02:00
|
|
|
mpu401_log("Write Data (0x330) %X\n", val);
|
2017-05-09 21:45:20 +02:00
|
|
|
break;
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
case 1: /*Command*/
|
2017-05-09 21:45:20 +02:00
|
|
|
MPU401_WriteCommand(mpu, val);
|
2018-05-21 19:04:05 +02:00
|
|
|
mpu401_log("Write Command (0x331) %x\n", val);
|
2017-05-09 21:45:20 +02:00
|
|
|
break;
|
2017-11-23 21:45:10 -05:00
|
|
|
}
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
static uint8_t
|
|
|
|
|
mpu401_read(uint16_t addr, void *priv)
|
2017-05-09 21:45:20 +02:00
|
|
|
{
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu_t *mpu = (mpu_t *)priv;
|
|
|
|
|
uint8_t ret = 0;
|
|
|
|
|
|
|
|
|
|
switch (addr & 1) {
|
2018-09-11 22:41:14 +02:00
|
|
|
case 0: /* Read Data */
|
2017-11-23 21:45:10 -05:00
|
|
|
ret = MPU401_ReadData(mpu);
|
2018-05-21 19:04:05 +02:00
|
|
|
mpu401_log("Read Data (0x330) %X\n", ret);
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
|
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
case 1: /* Read Status */
|
2020-01-04 03:32:20 +01:00
|
|
|
if (mpu->state.cmd_pending)
|
|
|
|
|
ret = STATUS_OUTPUT_NOT_READY;
|
|
|
|
|
if (!mpu->queue_used)
|
|
|
|
|
ret = STATUS_INPUT_NOT_READY;
|
2018-08-17 21:01:12 +02:00
|
|
|
ret |= 0x3f;
|
2017-11-23 21:45:10 -05:00
|
|
|
|
2018-05-21 19:04:05 +02:00
|
|
|
mpu401_log("Read Status (0x331) %x\n", ret);
|
2017-11-23 21:45:10 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-21 19:04:05 +02:00
|
|
|
/* mpu401_log("MPU401 Read Port %04X, ret %x\n", addr, ret); */
|
2017-11-23 21:45:10 -05:00
|
|
|
return(ret);
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
static void
|
|
|
|
|
MPU401_Event(void *priv)
|
2017-05-09 21:45:20 +02:00
|
|
|
{
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu_t *mpu = (mpu_t *)priv;
|
|
|
|
|
uint8_t i;
|
2020-01-04 03:32:20 +01:00
|
|
|
int max_meascnt;
|
2017-05-10 20:39:46 +02:00
|
|
|
|
2018-05-21 19:04:05 +02:00
|
|
|
mpu401_log("MPU-401 event callback\n");
|
2017-11-23 21:45:10 -05:00
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
if (mpu->mode == M_UART) {
|
Added the IBM 5161 ISA expansion for PC and XT;
Cleaned up the parallel port emulation, added IRQ support, and made enabling/disabling per port;
Added the Award 430NX and the Intel Classic/PCI (Alfredo, 420TX);
Finished the 586MC1;
Added 8087 emulation;
Moved Cyrix 6x86'es to the Dev branch;
Sanitized/cleaned up memregs.c/h and intel.c/h;
Split the chipsets from machines and sanitized Port 92 emulation;
Added support for the 15bpp mode to the Compaq ATI 28800;
Moved the MR 386DX and 486 machines to the Dev branch;
Ported the new dynamic recompiler from PCem, but it remains in Dev branch until after v2.00;
Ported the new timer code from PCem;
Cleaned up the CPU table of unused stuff and better optimized its structure;
Ported the Open-XT and Open-AT from VARCem, the Open-AT is in the Dev branch;
Ported the XT MFM controller rewrite and adding of more controllers (incl. two RLL ones), from VARCem;
Added the AHA-1540A and the BusTek BT-542B;
Moved the Sumo SCSI-AT to the Dev branch;
Minor IDE, FDC, and floppy drive code clean-ups;
Made NCR 5380/53C400-based cards' BIOS address configurable;
Got rid of the legacy romset variable;
Unified (video) buffer and buffer32 into one and make the unified buffer 32-bit;
Added the Amstead PPC512 per PCem patch by John Elliott;
Switched memory mapping granularity from 16k to 4k (less than 1k not possible due to internal pages);
Rewrote the CL-GD 54xx blitter, fixes Win-OS/2 on the 54x6 among other thing;
Added the Image Manager 1024 and Professional Graphics Controller per PCem patch by John Elliott and work done on VARCem;
Added Headland HT-216, GC-205 and Video 7 VGA 1024i emulation based on PCem commit;
Implemented the fuction keys for the Toshiba T1000/T1200/T3100 enhancement;
Amstrad MegaPC does now works correctly with non-internal graphics card;
The SLiRP code no longer casts a packed struct type to a non-packed struct type;
The Xi8088 and PB410a no longer hang on 86Box when PS/2 mouse is not present;
The S3 Virge on BeOS is no longer broken (was broken by build #1591);
OS/2 2.0 build 6.167 now sees key presses again;
Xi8088 now work on CGA again;
86F images converted from either the old or new variants of the HxC MFM format now work correctly;
Hardware interrupts with a vector of 0xFF are now handled correctly;
OPTi 495SX boards no longer incorrectly have 64 MB maximum RAM when 32 MB is correct;
Fixed VNC keyboard input bugs;
Fixed AT RTC periodic interrupt - Chicago 58s / 73f / 73g / 81 MIDI play no longer hangs with the build's own VTD driver;
Fixed mouse polling with internal mice - Amstrad and Olivetti mice now work correctly;
Triones ATAPI DMA driver now correctly reads a file at the end of a CD image with a sectors number not divisible by 4;
Compaq Portable now works with all graphics cards;
Fixed various MDSI Genius bugs;
Added segment limit checks and improved page fault checks for several CPU instructions - Memphis 15xx WINSETUP and Chicago 58s WINDISK.CPL no longer issue a GPF, and some S3 drivers that used to have glitches, now work correctly;
Further improved the 808x emulation, also fixes the noticably choppy sound when using 808x CPU's, also fixes #355;
OS/2 installer no logner locks up on splash screen on PS/2 Model 70 and 80, fixes #400.
Fixed several Amstead bugs, GEM no longer crashes on the Amstrad 1640, fixes #391.
Ported John Elliott's Amstrad fixes and improvement from PCem, and fixed the default language so it's correctly Engliish, fixes #278, fixes #389.
Fixed a minor IDE timing bug, fixes #388.
Fixed Toshiba T1000 RAM issues, fixes #379.
Fixed EGA/(S)VGA overscan border handling, fixes #378;
Got rid of the now long useless IDE channel 2 auto-removal, fixes #370;
Fixed the BIOS files used by the AMSTRAD PC1512, fixes #366;
Ported the Unicode CD image file name fix from VARCem, fixes #365;
Fixed high density floppy disks on the Xi8088, fixes #359;
Fixed some bugs in the Hercules emulation, fixes #346, fixes #358;
Fixed the SCSI hard disk mode sense pages, fixes #356;
Removed the AMI Unknown 386SX because of impossibility to identify the chipset, closes #349;
Fixed bugs in the serial mouse emulation, fixes #344;
Compiled 86Box binaries now include all the required .DLL's, fixes #341;
Made some combo boxes in the Settings dialog slightly wider, fixes #276.
2019-09-20 14:02:30 +02:00
|
|
|
timer_disable(&mpu->mpu401_event_callback);
|
2017-11-23 21:45:10 -05:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mpu->state.irq_pending) goto next_event;
|
2020-01-01 20:20:16 +01:00
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
if (mpu->state.playing) {
|
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
|
/* Decrease counters. */
|
|
|
|
|
if (mpu->state.amask & (1 << i)) {
|
|
|
|
|
mpu->playbuf[i].counter--;
|
|
|
|
|
if (mpu->playbuf[i].counter <= 0)
|
|
|
|
|
UpdateTrack(mpu, i);
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-11-23 21:45:10 -05:00
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
if (mpu->state.conductor) {
|
|
|
|
|
mpu->condbuf.counter--;
|
|
|
|
|
if (mpu->condbuf.counter <= 0) {
|
|
|
|
|
mpu->condbuf.counter = 0xf0;
|
|
|
|
|
mpu->state.req_mask |= (1 << 9);
|
|
|
|
|
}
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2017-11-23 21:45:10 -05:00
|
|
|
}
|
|
|
|
|
|
2020-01-01 20:20:16 +01:00
|
|
|
if (mpu->state.clock_to_host) {
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu->clock.cth_counter++;
|
2020-01-01 20:20:16 +01:00
|
|
|
if (mpu->clock.cth_counter >= mpu->clock.cth_rate[mpu->clock.cth_mode]) {
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->clock.cth_counter = 0;
|
2020-01-08 19:01:24 +01:00
|
|
|
mpu->clock.cth_mode++;
|
|
|
|
|
mpu->clock.cth_mode %= 4;
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->state.req_mask |= (1 << 13);
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
2017-11-23 21:45:10 -05:00
|
|
|
}
|
|
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
if (mpu->state.rec == M_RECON) {
|
|
|
|
|
/* Recording. */
|
|
|
|
|
mpu->clock.rec_counter++;
|
|
|
|
|
if (mpu->clock.rec_counter>=240) {
|
|
|
|
|
mpu->clock.rec_counter=0;
|
|
|
|
|
mpu->state.req_mask|=(1<<8);
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
}
|
2020-01-01 20:20:16 +01:00
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
if (mpu->state.playing || (mpu->state.rec == M_RECON)) {
|
|
|
|
|
max_meascnt = (mpu->clock.timebase * mpu->clock.midimetro * mpu->clock.metromeas) / 24;
|
|
|
|
|
if (max_meascnt != 0) {
|
|
|
|
|
/* Measure end. */
|
|
|
|
|
if (++mpu->clock.measure_counter >= max_meascnt) {
|
|
|
|
|
if (mpu->filter.rt_out)
|
|
|
|
|
midi_raw_out_rt_byte(0xf8);
|
|
|
|
|
mpu->clock.measure_counter = 0;
|
|
|
|
|
if (mpu->filter.rec_measure_end && (mpu->state.rec == M_RECON))
|
|
|
|
|
mpu->state.req_mask |= (1 << 12);
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
|
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
}
|
|
|
|
|
if (!mpu->state.irq_pending && mpu->state.req_mask)
|
2018-09-11 22:41:14 +02:00
|
|
|
MPU401_EOIHandler(mpu);
|
2017-11-23 21:45:10 -05:00
|
|
|
|
2017-05-09 21:45:20 +02:00
|
|
|
next_event:
|
2020-01-04 03:32:20 +01:00
|
|
|
MPU401_RunClock(mpu);
|
|
|
|
|
if (mpu->state.sync_in)
|
|
|
|
|
mpu->clock.ticks_in++;
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
|
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
|
2020-01-01 20:20:16 +01:00
|
|
|
static void
|
|
|
|
|
MPU401_NotesOff(mpu_t *mpu, int i)
|
|
|
|
|
{
|
2020-01-04 03:32:20 +01:00
|
|
|
int j;
|
|
|
|
|
uint8_t key;
|
|
|
|
|
|
|
|
|
|
if (mpu->filter.allnotesoff_out && !(mpu->inputref[i].on &&
|
|
|
|
|
(mpu->inputref[i].key[0] | mpu->inputref[i].key[1] |
|
|
|
|
|
mpu->inputref[i].key[2] | mpu->inputref[i].key[3]))) {
|
|
|
|
|
for (j=0;j<4;j++)
|
|
|
|
|
mpu->chanref[mpu->ch_toref[i]].key[j]=0;
|
|
|
|
|
midi_raw_out_byte(0xb0 | i);
|
|
|
|
|
midi_raw_out_byte(123);
|
|
|
|
|
midi_raw_out_byte(0);
|
|
|
|
|
} else if (mpu->chanref[mpu->ch_toref[i]].on) {
|
|
|
|
|
for (key = 0; key < 128; key++) {
|
|
|
|
|
if ((mpu->chanref[mpu->ch_toref[i]].M_GETKEY) &&
|
|
|
|
|
!(mpu->inputref[i].on && (mpu->inputref[i].M_GETKEY))) {
|
|
|
|
|
midi_raw_out_byte(0x80|i);
|
|
|
|
|
midi_raw_out_byte(key);
|
|
|
|
|
midi_raw_out_byte(0);
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu->chanref[mpu->ch_toref[i]].M_DELKEY;
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
}
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
|
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
|
2020-01-01 20:20:16 +01:00
|
|
|
/*Input handler for SysEx */
|
2020-01-19 05:45:05 +01:00
|
|
|
int
|
|
|
|
|
MPU401_InputSysex(void *p, uint8_t *buffer, uint32_t len, int abort)
|
2020-01-01 20:20:16 +01:00
|
|
|
{
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu_t *mpu = (mpu_t *)p;
|
|
|
|
|
int i;
|
|
|
|
|
uint8_t val_ff = 0xff;
|
|
|
|
|
|
|
|
|
|
mpu401_log("MPU401 Input Sysex\n");
|
|
|
|
|
|
|
|
|
|
if (mpu->filter.sysex_in) {
|
|
|
|
|
if (abort) {
|
|
|
|
|
mpu->state.sysex_in_finished=1;
|
|
|
|
|
mpu->rec_queue_used=0;/*reset also the input queue*/
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (mpu->state.sysex_in_finished) {
|
2020-01-02 18:19:22 +01:00
|
|
|
if (mpu->rec_queue_used>=MPU401_INPUT_QUEUE)
|
2020-01-01 20:20:16 +01:00
|
|
|
return len;
|
2020-01-04 03:32:20 +01:00
|
|
|
MPU401_RecQueueBuffer(mpu, &val_ff, 1, 1);
|
|
|
|
|
mpu->state.sysex_in_finished=0;
|
|
|
|
|
mpu->clock.rec_counter=0;
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
if (mpu->rec_queue_used>=MPU401_INPUT_QUEUE)
|
|
|
|
|
return len;
|
|
|
|
|
int available = MPU401_INPUT_QUEUE - mpu->rec_queue_used;
|
|
|
|
|
|
|
|
|
|
if (available >= len) {
|
|
|
|
|
MPU401_RecQueueBuffer(mpu, buffer, len, 1);
|
|
|
|
|
return 0;
|
|
|
|
|
} else {
|
|
|
|
|
MPU401_RecQueueBuffer(mpu,buffer, available, 1);
|
|
|
|
|
if (mpu->state.sysex_in_finished)
|
|
|
|
|
return 0;
|
|
|
|
|
return (len - available);
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
} else if (mpu->filter.sysex_thru && mpu->midi_thru) {
|
|
|
|
|
midi_raw_out_byte(0xf0);
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
|
midi_raw_out_byte(*(buffer+i));
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*Input handler for MIDI*/
|
2020-01-19 05:45:05 +01:00
|
|
|
void
|
|
|
|
|
MPU401_InputMsg(void *p, uint8_t *msg)
|
2020-01-01 20:20:16 +01:00
|
|
|
{
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu_t *mpu = (mpu_t *)p;
|
|
|
|
|
int i, tick;
|
|
|
|
|
static uint8_t old_msg = 0;
|
|
|
|
|
uint8_t len = msg[3], key;
|
|
|
|
|
uint8_t recdata[2], recmsg[4];
|
|
|
|
|
int send = 1, send_thru = 0;
|
2020-01-15 01:03:54 +01:00
|
|
|
int retrigger_thru = 0, chan, chrefnum;
|
2020-01-04 03:32:20 +01:00
|
|
|
|
|
|
|
|
/* Abort if sysex transfer is in progress. */
|
|
|
|
|
if (!mpu->state.sysex_in_finished) {
|
|
|
|
|
mpu401_log("SYSEX in progress\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-01-01 20:20:16 +01:00
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu401_log("MPU401 Input Msg\n");
|
2020-01-02 18:19:22 +01:00
|
|
|
|
2020-01-04 03:32:20 +01:00
|
|
|
if (mpu->mode == M_INTELLIGENT) {
|
|
|
|
|
if (msg[0] < 0x80) {
|
|
|
|
|
/* Expand running status */
|
|
|
|
|
msg[2] = msg[1];
|
|
|
|
|
msg[1] = msg[0];
|
|
|
|
|
msg[0] = old_msg;
|
|
|
|
|
}
|
|
|
|
|
old_msg = msg[0];
|
|
|
|
|
chan = msg[0] & 0xf;
|
|
|
|
|
chrefnum = mpu->ch_toref[chan];
|
|
|
|
|
key = msg[1] & 0x7f;
|
|
|
|
|
if (msg[0] < 0xf0) {
|
|
|
|
|
/* If non-system msg. */
|
|
|
|
|
if (!(mpu->state.midi_mask & (1 << chan)) && mpu->filter.all_thru)
|
|
|
|
|
send_thru = 1;
|
|
|
|
|
else if (mpu->filter.midi_thru)
|
|
|
|
|
send_thru = 1;
|
|
|
|
|
switch (msg[0] & 0xf0) {
|
|
|
|
|
case 0x80: /* Note off. */
|
|
|
|
|
if (send_thru) {
|
|
|
|
|
if (mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY))
|
|
|
|
|
send_thru = 0;
|
|
|
|
|
if (!mpu->filter.midi_thru)
|
|
|
|
|
break;
|
|
|
|
|
if (!(mpu->inputref[chan].M_GETKEY))
|
|
|
|
|
send_thru = 0;
|
|
|
|
|
mpu->inputref[chan].M_DELKEY;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 0x90: /* Note on. */
|
|
|
|
|
if (send_thru) {
|
|
|
|
|
if (mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY))
|
|
|
|
|
retrigger_thru = 1;
|
|
|
|
|
if (!mpu->filter.midi_thru)
|
|
|
|
|
break;
|
|
|
|
|
if (mpu->inputref[chan].M_GETKEY)
|
|
|
|
|
retrigger_thru = 1;
|
|
|
|
|
mpu->inputref[chan].M_SETKEY;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 0xb0:
|
|
|
|
|
if (msg[1] >= 120) {
|
|
|
|
|
send_thru = 0;
|
|
|
|
|
if (msg[1] == 123) {
|
|
|
|
|
/* All notes off. */
|
|
|
|
|
for (key = 0; key < 128; key++) {
|
2020-01-08 19:05:21 +01:00
|
|
|
if (!(mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY))) {
|
2020-01-04 03:32:20 +01:00
|
|
|
if (mpu->inputref[chan].on && mpu->inputref[chan].M_GETKEY) {
|
|
|
|
|
midi_raw_out_byte(0x80 | chan);
|
|
|
|
|
midi_raw_out_byte(key);
|
|
|
|
|
midi_raw_out_byte(0);
|
|
|
|
|
}
|
2020-01-02 18:19:22 +01:00
|
|
|
mpu->inputref[chan].M_DELKEY;
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2020-01-04 03:32:20 +01:00
|
|
|
}
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
}
|
|
|
|
|
if ((msg[0] >= 0xf0) || (mpu->state.midi_mask & (1 << chan))) {
|
|
|
|
|
switch (msg[0] & 0xf0) {
|
|
|
|
|
case 0xa0: /* Aftertouch. */
|
|
|
|
|
if (!mpu->filter.bender_in)
|
|
|
|
|
send = 0;
|
|
|
|
|
break;
|
|
|
|
|
case 0xb0: /* Control change. */
|
|
|
|
|
if (!mpu->filter.bender_in && (msg[1] < 64))
|
|
|
|
|
send = 0;
|
|
|
|
|
if (msg[1] >= 120) {
|
|
|
|
|
if (mpu->filter.modemsgs_in)
|
|
|
|
|
send = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 0xc0: /* Program change. */
|
|
|
|
|
if ((mpu->state.rec != M_RECON) && !mpu->filter.data_in_stop) {
|
|
|
|
|
mpu->filter.prchg_buf[chan] = msg[1];
|
|
|
|
|
mpu->filter.prchg_mask |= 1 << chan;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 0xd0: /* Ch pressure. */
|
|
|
|
|
case 0xe0: /* Pitch wheel. */
|
|
|
|
|
if (!mpu->filter.bender_in)
|
|
|
|
|
send = 0;
|
|
|
|
|
break;
|
|
|
|
|
case 0xf0: /* System message. */
|
|
|
|
|
if (msg[0] == 0xf8) {
|
|
|
|
|
send = 0;
|
|
|
|
|
if (mpu->clock.active && mpu->state.sync_in) {
|
|
|
|
|
send = 0; /* Don't pass to host in this mode? */
|
|
|
|
|
tick = mpu->clock.timebase / 24;
|
|
|
|
|
if (mpu->clock.ticks_in != tick) {
|
|
|
|
|
if (!mpu->clock.ticks_in || (mpu->clock.ticks_in > (tick * 2)))
|
|
|
|
|
mpu->clock.freq_mod *= 2.0;
|
|
|
|
|
else {
|
|
|
|
|
if (ABS(mpu->clock.ticks_in-tick) == 1)
|
|
|
|
|
mpu->clock.freq_mod /= mpu->clock.ticks_in / (float) (tick * 2);
|
|
|
|
|
else
|
|
|
|
|
mpu->clock.freq_mod /= mpu->clock.ticks_in / (float) (tick);
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
MPU401_ReCalcClock(mpu);
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu->clock.ticks_in = 0;
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
} else if (msg[0] > 0xf8) { /* Realtime. */
|
|
|
|
|
if (!(mpu->filter.rt_in && (msg[0] <= 0xfc) && (msg[0] >= 0xfa))) {
|
|
|
|
|
recdata[0] = 0xff;
|
|
|
|
|
recdata[1] = msg[0];
|
|
|
|
|
MPU401_RecQueueBuffer(mpu, recdata, 2, 1);
|
|
|
|
|
send = 0;
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
} else { /* Common or system. */
|
|
|
|
|
send = 0;
|
|
|
|
|
if ((msg[0] == 0xf2) || (msg[0] == 0xf3) || (msg[0] == 0xf6)) {
|
|
|
|
|
if (mpu->filter.commonmsgs_in)
|
|
|
|
|
send = 1;
|
|
|
|
|
if (mpu->filter.commonmsgs_thru)
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
|
midi_raw_out_byte(msg[i]);
|
2020-01-01 20:20:16 +01:00
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
}
|
|
|
|
|
if (send) {
|
|
|
|
|
recmsg[0] = 0xff;
|
|
|
|
|
recmsg[1] = msg[0];
|
|
|
|
|
recmsg[2] = msg[1];
|
|
|
|
|
recmsg[3] = msg[2];
|
|
|
|
|
MPU401_RecQueueBuffer(mpu, recmsg, len + 1, 1);
|
|
|
|
|
}
|
|
|
|
|
if (mpu->filter.rt_affection) {
|
|
|
|
|
switch(msg[0]) {
|
|
|
|
|
case 0xf2: case 0xf3:
|
|
|
|
|
mpu->state.block_ack = 1;
|
|
|
|
|
MPU401_WriteCommand(mpu, 0xb8); /* Clear play counters. */
|
2020-01-01 20:20:16 +01:00
|
|
|
break;
|
|
|
|
|
case 0xfa:
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu->state.block_ack = 1;
|
|
|
|
|
MPU401_WriteCommand(mpu, 0xa); /* Start, play. */
|
2020-01-02 18:19:22 +01:00
|
|
|
if (mpu->filter.rt_out)
|
2020-01-01 20:20:16 +01:00
|
|
|
midi_raw_out_rt_byte(msg[0]);
|
|
|
|
|
break;
|
|
|
|
|
case 0xfb:
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu->state.block_ack = 1;
|
|
|
|
|
MPU401_WriteCommand(mpu, 0xb); /* Continue, play. */
|
2020-01-02 18:19:22 +01:00
|
|
|
if (mpu->filter.rt_out)
|
2020-01-01 20:20:16 +01:00
|
|
|
midi_raw_out_rt_byte(msg[0]);
|
|
|
|
|
break;
|
|
|
|
|
case 0xfc:
|
2020-01-04 03:32:20 +01:00
|
|
|
mpu->state.block_ack = 1;
|
|
|
|
|
MPU401_WriteCommand(mpu, 0xd) ;/* Stop: Play, rec, midi */
|
2020-01-02 18:19:22 +01:00
|
|
|
if (mpu->filter.rt_out)
|
2020-01-01 20:20:16 +01:00
|
|
|
midi_raw_out_rt_byte(msg[0]);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
if (send_thru && mpu->midi_thru) {
|
|
|
|
|
if (retrigger_thru) {
|
|
|
|
|
midi_raw_out_byte(0x80 | (msg[0] & 0xf));
|
|
|
|
|
midi_raw_out_byte(msg[1]);
|
|
|
|
|
midi_raw_out_byte(msg[2]);
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
|
midi_raw_out_byte(msg[i]);
|
|
|
|
|
}
|
|
|
|
|
if (send) {
|
|
|
|
|
if (mpu->state.rec == M_RECON) {
|
|
|
|
|
recmsg[0] = mpu->clock.rec_counter;
|
|
|
|
|
recmsg[1] = msg[0];
|
|
|
|
|
recmsg[2] = msg[1];
|
|
|
|
|
recmsg[3] = msg[2];
|
|
|
|
|
MPU401_RecQueueBuffer(mpu, recmsg, len + 1, 1);
|
|
|
|
|
mpu->clock.rec_counter = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (mpu->filter.data_in_stop) {
|
|
|
|
|
if (mpu->filter.timing_in_stop) {
|
|
|
|
|
recmsg[0] = 0;
|
|
|
|
|
recmsg[1] = msg[0];
|
|
|
|
|
recmsg[2] = msg[1];
|
|
|
|
|
recmsg[3] = msg[2];
|
|
|
|
|
MPU401_RecQueueBuffer(mpu, recmsg, len + 1, 1);
|
|
|
|
|
} else {
|
|
|
|
|
recmsg[0] = msg[0];
|
|
|
|
|
recmsg[1] = msg[1];
|
|
|
|
|
recmsg[2] = msg[2];
|
|
|
|
|
recmsg[3] = 0;
|
|
|
|
|
MPU401_RecQueueBuffer(mpu, recmsg, len, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-02 18:19:22 +01:00
|
|
|
}
|
2020-01-04 03:32:20 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* UART mode input. */
|
2020-01-23 06:40:20 +01:00
|
|
|
for (i = 0; i < len; i++)
|
2020-01-04 03:32:20 +01:00
|
|
|
MPU401_QueueByte(mpu, msg[i]);
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
void
|
2020-01-19 05:45:05 +01:00
|
|
|
mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode, int receive_input)
|
2017-05-09 21:45:20 +02:00
|
|
|
{
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu->status = STATUS_INPUT_NOT_READY;
|
|
|
|
|
mpu->irq = irq;
|
|
|
|
|
mpu->queue_used = 0;
|
|
|
|
|
mpu->queue_pos = 0;
|
|
|
|
|
mpu->mode = M_UART;
|
2017-05-10 14:52:38 +02:00
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
/* Expalantion:
|
|
|
|
|
MPU-401 starting in intelligent mode = Full MPU-401 intelligent mode capability;
|
|
|
|
|
MPU-401 starting in UART mode = Reduced MPU-401 intelligent mode capability seen on the Sound Blaster 16/AWE32,
|
|
|
|
|
only supporting commands 3F (set UART mode) and FF (reset). */
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu->intelligent = (mode == M_INTELLIGENT) ? 1 : 0;
|
2018-05-21 19:04:05 +02:00
|
|
|
mpu401_log("Starting as %s (mode is %s)\n", mpu->intelligent ? "INTELLIGENT" : "UART", (mode == M_INTELLIGENT) ? "INTELLIGENT" : "UART");
|
2017-05-10 14:52:38 +02:00
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
if (addr)
|
|
|
|
|
io_sethandler(addr, 2,
|
|
|
|
|
mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu);
|
2017-11-23 21:45:10 -05:00
|
|
|
io_sethandler(0x2A20, 16,
|
|
|
|
|
NULL, NULL, NULL, imf_write, NULL, NULL, mpu);
|
2020-01-19 05:45:05 +01:00
|
|
|
timer_add(&mpu->mpu401_event_callback, MPU401_Event, mpu, 0);
|
|
|
|
|
timer_add(&mpu->mpu401_eoi_callback, MPU401_EOIHandler, mpu, 0);
|
|
|
|
|
timer_add(&mpu->mpu401_reset_callback, MPU401_ResetDone, mpu, 0);
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
MPU401_Reset(mpu);
|
2020-01-19 05:45:05 +01:00
|
|
|
|
|
|
|
|
if (receive_input)
|
|
|
|
|
midi_in_handler(1, MPU401_InputMsg, MPU401_InputSysex, mpu);
|
2017-05-09 21:45:20 +02:00
|
|
|
}
|
2017-06-03 20:32:58 +02:00
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
mpu401_device_add(void)
|
2017-06-03 20:32:58 +02:00
|
|
|
{
|
2020-01-04 03:32:20 +01:00
|
|
|
if (!mpu401_standalone_enable)
|
|
|
|
|
return;
|
2017-06-03 20:32:58 +02:00
|
|
|
|
2018-09-11 23:08:51 +02:00
|
|
|
if (machines[machine].flags & MACHINE_MCA)
|
2018-09-11 22:41:14 +02:00
|
|
|
device_add(&mpu401_mca_device);
|
|
|
|
|
else
|
|
|
|
|
device_add(&mpu401_device);
|
2018-09-03 13:55:09 +02:00
|
|
|
}
|
|
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
|
|
|
|
|
static uint8_t
|
|
|
|
|
mpu401_mca_read(int port, void *p)
|
2018-09-03 13:55:09 +02:00
|
|
|
{
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu_t *mpu = (mpu_t *)p;
|
|
|
|
|
|
|
|
|
|
return mpu->pos_regs[port & 7];
|
2018-09-03 13:55:09 +02:00
|
|
|
}
|
|
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
mpu401_mca_write(int port, uint8_t val, void *p)
|
2018-09-03 13:55:09 +02:00
|
|
|
{
|
|
|
|
|
mpu_t *mpu = (mpu_t *)p;
|
2018-09-11 22:41:14 +02:00
|
|
|
uint16_t addr;
|
|
|
|
|
|
|
|
|
|
if (port < 0x102)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
addr = (mpu->pos_regs[2] & 2) ? 0x0330 : 0x1330;
|
|
|
|
|
|
|
|
|
|
port &= 7;
|
|
|
|
|
|
|
|
|
|
mpu->pos_regs[port] = val;
|
|
|
|
|
|
|
|
|
|
if (port == 2) {
|
|
|
|
|
io_removehandler(addr, 2,
|
|
|
|
|
mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu);
|
|
|
|
|
|
|
|
|
|
addr = (mpu->pos_regs[2] & 2) ? 0x1330 : 0x0330;
|
|
|
|
|
|
|
|
|
|
io_sethandler(addr, 2,
|
|
|
|
|
mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu);
|
|
|
|
|
}
|
2017-06-03 20:32:58 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
|
Added the IBM 5161 ISA expansion for PC and XT;
Cleaned up the parallel port emulation, added IRQ support, and made enabling/disabling per port;
Added the Award 430NX and the Intel Classic/PCI (Alfredo, 420TX);
Finished the 586MC1;
Added 8087 emulation;
Moved Cyrix 6x86'es to the Dev branch;
Sanitized/cleaned up memregs.c/h and intel.c/h;
Split the chipsets from machines and sanitized Port 92 emulation;
Added support for the 15bpp mode to the Compaq ATI 28800;
Moved the MR 386DX and 486 machines to the Dev branch;
Ported the new dynamic recompiler from PCem, but it remains in Dev branch until after v2.00;
Ported the new timer code from PCem;
Cleaned up the CPU table of unused stuff and better optimized its structure;
Ported the Open-XT and Open-AT from VARCem, the Open-AT is in the Dev branch;
Ported the XT MFM controller rewrite and adding of more controllers (incl. two RLL ones), from VARCem;
Added the AHA-1540A and the BusTek BT-542B;
Moved the Sumo SCSI-AT to the Dev branch;
Minor IDE, FDC, and floppy drive code clean-ups;
Made NCR 5380/53C400-based cards' BIOS address configurable;
Got rid of the legacy romset variable;
Unified (video) buffer and buffer32 into one and make the unified buffer 32-bit;
Added the Amstead PPC512 per PCem patch by John Elliott;
Switched memory mapping granularity from 16k to 4k (less than 1k not possible due to internal pages);
Rewrote the CL-GD 54xx blitter, fixes Win-OS/2 on the 54x6 among other thing;
Added the Image Manager 1024 and Professional Graphics Controller per PCem patch by John Elliott and work done on VARCem;
Added Headland HT-216, GC-205 and Video 7 VGA 1024i emulation based on PCem commit;
Implemented the fuction keys for the Toshiba T1000/T1200/T3100 enhancement;
Amstrad MegaPC does now works correctly with non-internal graphics card;
The SLiRP code no longer casts a packed struct type to a non-packed struct type;
The Xi8088 and PB410a no longer hang on 86Box when PS/2 mouse is not present;
The S3 Virge on BeOS is no longer broken (was broken by build #1591);
OS/2 2.0 build 6.167 now sees key presses again;
Xi8088 now work on CGA again;
86F images converted from either the old or new variants of the HxC MFM format now work correctly;
Hardware interrupts with a vector of 0xFF are now handled correctly;
OPTi 495SX boards no longer incorrectly have 64 MB maximum RAM when 32 MB is correct;
Fixed VNC keyboard input bugs;
Fixed AT RTC periodic interrupt - Chicago 58s / 73f / 73g / 81 MIDI play no longer hangs with the build's own VTD driver;
Fixed mouse polling with internal mice - Amstrad and Olivetti mice now work correctly;
Triones ATAPI DMA driver now correctly reads a file at the end of a CD image with a sectors number not divisible by 4;
Compaq Portable now works with all graphics cards;
Fixed various MDSI Genius bugs;
Added segment limit checks and improved page fault checks for several CPU instructions - Memphis 15xx WINSETUP and Chicago 58s WINDISK.CPL no longer issue a GPF, and some S3 drivers that used to have glitches, now work correctly;
Further improved the 808x emulation, also fixes the noticably choppy sound when using 808x CPU's, also fixes #355;
OS/2 installer no logner locks up on splash screen on PS/2 Model 70 and 80, fixes #400.
Fixed several Amstead bugs, GEM no longer crashes on the Amstrad 1640, fixes #391.
Ported John Elliott's Amstrad fixes and improvement from PCem, and fixed the default language so it's correctly Engliish, fixes #278, fixes #389.
Fixed a minor IDE timing bug, fixes #388.
Fixed Toshiba T1000 RAM issues, fixes #379.
Fixed EGA/(S)VGA overscan border handling, fixes #378;
Got rid of the now long useless IDE channel 2 auto-removal, fixes #370;
Fixed the BIOS files used by the AMSTRAD PC1512, fixes #366;
Ported the Unicode CD image file name fix from VARCem, fixes #365;
Fixed high density floppy disks on the Xi8088, fixes #359;
Fixed some bugs in the Hercules emulation, fixes #346, fixes #358;
Fixed the SCSI hard disk mode sense pages, fixes #356;
Removed the AMI Unknown 386SX because of impossibility to identify the chipset, closes #349;
Fixed bugs in the serial mouse emulation, fixes #344;
Compiled 86Box binaries now include all the required .DLL's, fixes #341;
Made some combo boxes in the Settings dialog slightly wider, fixes #276.
2019-09-20 14:02:30 +02:00
|
|
|
static uint8_t
|
|
|
|
|
mpu401_mca_feedb(void *p)
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
static void *
|
2018-03-19 01:02:04 +01:00
|
|
|
mpu401_standalone_init(const device_t *info)
|
2017-06-03 20:32:58 +02:00
|
|
|
{
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu_t *mpu;
|
2018-09-11 22:41:14 +02:00
|
|
|
int irq;
|
|
|
|
|
uint16_t base;
|
2017-06-03 20:32:58 +02:00
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu = malloc(sizeof(mpu_t));
|
|
|
|
|
memset(mpu, 0, sizeof(mpu_t));
|
2020-01-19 05:45:05 +01:00
|
|
|
|
2018-05-21 19:04:05 +02:00
|
|
|
mpu401_log("mpu_init\n");
|
2017-06-03 20:32:58 +02:00
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
if (info->flags & DEVICE_MCA) {
|
Added the IBM 5161 ISA expansion for PC and XT;
Cleaned up the parallel port emulation, added IRQ support, and made enabling/disabling per port;
Added the Award 430NX and the Intel Classic/PCI (Alfredo, 420TX);
Finished the 586MC1;
Added 8087 emulation;
Moved Cyrix 6x86'es to the Dev branch;
Sanitized/cleaned up memregs.c/h and intel.c/h;
Split the chipsets from machines and sanitized Port 92 emulation;
Added support for the 15bpp mode to the Compaq ATI 28800;
Moved the MR 386DX and 486 machines to the Dev branch;
Ported the new dynamic recompiler from PCem, but it remains in Dev branch until after v2.00;
Ported the new timer code from PCem;
Cleaned up the CPU table of unused stuff and better optimized its structure;
Ported the Open-XT and Open-AT from VARCem, the Open-AT is in the Dev branch;
Ported the XT MFM controller rewrite and adding of more controllers (incl. two RLL ones), from VARCem;
Added the AHA-1540A and the BusTek BT-542B;
Moved the Sumo SCSI-AT to the Dev branch;
Minor IDE, FDC, and floppy drive code clean-ups;
Made NCR 5380/53C400-based cards' BIOS address configurable;
Got rid of the legacy romset variable;
Unified (video) buffer and buffer32 into one and make the unified buffer 32-bit;
Added the Amstead PPC512 per PCem patch by John Elliott;
Switched memory mapping granularity from 16k to 4k (less than 1k not possible due to internal pages);
Rewrote the CL-GD 54xx blitter, fixes Win-OS/2 on the 54x6 among other thing;
Added the Image Manager 1024 and Professional Graphics Controller per PCem patch by John Elliott and work done on VARCem;
Added Headland HT-216, GC-205 and Video 7 VGA 1024i emulation based on PCem commit;
Implemented the fuction keys for the Toshiba T1000/T1200/T3100 enhancement;
Amstrad MegaPC does now works correctly with non-internal graphics card;
The SLiRP code no longer casts a packed struct type to a non-packed struct type;
The Xi8088 and PB410a no longer hang on 86Box when PS/2 mouse is not present;
The S3 Virge on BeOS is no longer broken (was broken by build #1591);
OS/2 2.0 build 6.167 now sees key presses again;
Xi8088 now work on CGA again;
86F images converted from either the old or new variants of the HxC MFM format now work correctly;
Hardware interrupts with a vector of 0xFF are now handled correctly;
OPTi 495SX boards no longer incorrectly have 64 MB maximum RAM when 32 MB is correct;
Fixed VNC keyboard input bugs;
Fixed AT RTC periodic interrupt - Chicago 58s / 73f / 73g / 81 MIDI play no longer hangs with the build's own VTD driver;
Fixed mouse polling with internal mice - Amstrad and Olivetti mice now work correctly;
Triones ATAPI DMA driver now correctly reads a file at the end of a CD image with a sectors number not divisible by 4;
Compaq Portable now works with all graphics cards;
Fixed various MDSI Genius bugs;
Added segment limit checks and improved page fault checks for several CPU instructions - Memphis 15xx WINSETUP and Chicago 58s WINDISK.CPL no longer issue a GPF, and some S3 drivers that used to have glitches, now work correctly;
Further improved the 808x emulation, also fixes the noticably choppy sound when using 808x CPU's, also fixes #355;
OS/2 installer no logner locks up on splash screen on PS/2 Model 70 and 80, fixes #400.
Fixed several Amstead bugs, GEM no longer crashes on the Amstrad 1640, fixes #391.
Ported John Elliott's Amstrad fixes and improvement from PCem, and fixed the default language so it's correctly Engliish, fixes #278, fixes #389.
Fixed a minor IDE timing bug, fixes #388.
Fixed Toshiba T1000 RAM issues, fixes #379.
Fixed EGA/(S)VGA overscan border handling, fixes #378;
Got rid of the now long useless IDE channel 2 auto-removal, fixes #370;
Fixed the BIOS files used by the AMSTRAD PC1512, fixes #366;
Ported the Unicode CD image file name fix from VARCem, fixes #365;
Fixed high density floppy disks on the Xi8088, fixes #359;
Fixed some bugs in the Hercules emulation, fixes #346, fixes #358;
Fixed the SCSI hard disk mode sense pages, fixes #356;
Removed the AMI Unknown 386SX because of impossibility to identify the chipset, closes #349;
Fixed bugs in the serial mouse emulation, fixes #344;
Compiled 86Box binaries now include all the required .DLL's, fixes #341;
Made some combo boxes in the Settings dialog slightly wider, fixes #276.
2019-09-20 14:02:30 +02:00
|
|
|
mca_add(mpu401_mca_read, mpu401_mca_write, mpu401_mca_feedb, mpu);
|
2018-09-11 22:41:14 +02:00
|
|
|
mpu->pos_regs[0] = 0x0F;
|
|
|
|
|
mpu->pos_regs[1] = 0x6C;
|
|
|
|
|
base = 0; /* Tell mpu401_init() that this is the MCA variant. */
|
|
|
|
|
irq = 2; /* According to @6c0f.adf, the IRQ is fixed to 2. */
|
|
|
|
|
} else {
|
|
|
|
|
base = device_get_config_hex16("base");
|
|
|
|
|
irq = device_get_config_int("irq");
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-19 05:45:05 +01:00
|
|
|
mpu401_init(mpu, base, irq, M_INTELLIGENT, device_get_config_int("receive_input"));
|
2020-01-01 20:20:16 +01:00
|
|
|
|
2018-09-11 22:41:14 +02:00
|
|
|
return(mpu);
|
2017-06-03 20:32:58 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
mpu401_standalone_close(void *priv)
|
2017-06-03 20:32:58 +02:00
|
|
|
{
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu_t *mpu = (mpu_t *)priv;
|
2017-06-03 20:32:58 +02:00
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
free(mpu);
|
2017-06-03 20:32:58 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
static const device_config_t mpu401_standalone_config[] =
|
2017-06-03 20:32:58 +02:00
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
"base", "MPU-401 Address", CONFIG_HEX16, "", 0x330,
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
"0x300", 0x300
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"0x330", 0x330
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"irq", "MPU-401 IRQ", CONFIG_SELECTION, "", 9,
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
"IRQ 9", 9
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"IRQ 3", 3
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"IRQ 4", 4
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"IRQ 5", 5
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"IRQ 7", 7
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"IRQ 10", 10
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
2020-01-19 05:45:05 +01:00
|
|
|
{
|
|
|
|
|
.name = "receive_input",
|
|
|
|
|
.description = "Receive input",
|
|
|
|
|
.type = CONFIG_BINARY,
|
|
|
|
|
.default_int = 1
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"", "", -1
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const device_config_t mpu401_standalone_mca_config[] =
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
.name = "receive_input",
|
|
|
|
|
.description = "Receive input",
|
|
|
|
|
.type = CONFIG_BINARY,
|
|
|
|
|
.default_int = 1
|
|
|
|
|
},
|
2017-06-03 20:32:58 +02:00
|
|
|
{
|
|
|
|
|
"", "", -1
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-11-23 21:45:10 -05:00
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
const device_t mpu401_device = {
|
2018-09-11 22:46:11 +02:00
|
|
|
"Roland MPU-IPC-T",
|
2018-09-03 13:55:09 +02:00
|
|
|
DEVICE_ISA, 0,
|
2017-11-23 21:45:10 -05:00
|
|
|
mpu401_standalone_init, mpu401_standalone_close, NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
mpu401_standalone_config
|
2017-06-03 20:32:58 +02:00
|
|
|
};
|
2018-09-03 13:55:09 +02:00
|
|
|
|
|
|
|
|
const device_t mpu401_mca_device = {
|
2018-09-11 22:41:14 +02:00
|
|
|
"Roland MPU-IMC",
|
2018-09-03 13:55:09 +02:00
|
|
|
DEVICE_MCA, 0,
|
|
|
|
|
mpu401_standalone_init, mpu401_standalone_close, NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
2020-01-19 05:45:05 +01:00
|
|
|
mpu401_standalone_mca_config
|
2018-09-03 13:55:09 +02:00
|
|
|
};
|