diff --git a/src/hardware/mpu401.cpp b/src/hardware/mpu401.cpp index cb24d165..8d3cdf4f 100644 --- a/src/hardware/mpu401.cpp +++ b/src/hardware/mpu401.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2011 The DOSBox Team + * Copyright (C) 2002-2012 The DOSBox Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,12 +30,15 @@ bool MIDI_Available(void); static void MPU401_Event(Bitu); static void MPU401_Reset(void); -static void MPU401_EOIHandler(void); +static void MPU401_ResetDone(Bitu); +static void MPU401_EOIHandler(Bitu val=0); +static void MPU401_EOIHandlerDispatch(void); #define MPU401_VERSION 0x15 #define MPU401_REVISION 0x01 #define MPU401_QUEUE 32 #define MPU401_TIMECONSTANT (60000000/1000.0f) +#define MPU401_RESETBUSY 27.0f enum MpuMode { M_UART,M_INTELLIGENT }; enum MpuDataType {T_OVERFLOW,T_MARK,T_MIDI_SYS,T_MIDI_NORM,T_COMMAND}; @@ -72,8 +75,9 @@ static struct { bool wsd,wsm,wsd_start; bool run_irq,irq_pending; bool send_now; + bool eoi_scheduled; Bits data_onoff; - Bitu command_byte; + Bitu command_byte,cmd_pending; Bit8u tmask,cmask,amask; Bit16u midi_mask; Bit16u req_mask; @@ -112,12 +116,13 @@ static void ClrQueue(void) { static Bitu MPU401_ReadStatus(Bitu port,Bitu iolen) { Bit8u ret=0x3f; /* Bits 6 and 7 clear */ + if (mpu.state.cmd_pending) ret|=0x40; if (!mpu.queue_used) ret|=0x80; return ret; } static void MPU401_WriteCommand(Bitu port,Bitu val,Bitu iolen) { - mpu.state.reset=0; + if (mpu.state.reset) {mpu.state.cmd_pending=val+1;return;} if (val<=0x2f) { switch (val&3) { /* MIDI stop, start, continue */ case 1: {MIDI_RawOutByte(0xfc);break;} @@ -239,12 +244,10 @@ static void MPU401_WriteCommand(Bitu port,Bitu val,Bitu iolen) { break; case 0xff: /* Reset MPU-401 */ LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Reset %X",val); - mpu.state.reset=1; - if (CPU_Cycles > 5) { //It came from the desert wants a fast irq - CPU_CycleLeft += CPU_Cycles; - CPU_Cycles = 5; - } + PIC_AddEvent(MPU401_ResetDone,MPU401_RESETBUSY); + mpu.state.reset=true; MPU401_Reset(); + if (mpu.mode==M_UART) return;//do not send ack in UART mode break; case 0x3f: /* UART mode */ LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Set UART mode %X",val); @@ -284,7 +287,7 @@ static Bitu MPU401_ReadData(Bitu port,Bitu iolen) { } if (ret==MSG_MPU_END || ret==MSG_MPU_CLOCK || ret==MSG_MPU_ACK) { mpu.state.data_onoff=-1; - MPU401_EOIHandler(); + MPU401_EOIHandlerDispatch(); } return ret; } @@ -390,7 +393,7 @@ static void MPU401_WriteData(Bitu port,Bitu val,Bitu iolen) { if (val<0xf0) mpu.state.data_onoff++; else { mpu.state.data_onoff=-1; - MPU401_EOIHandler(); + MPU401_EOIHandlerDispatch(); return; } if (val==0) mpu.state.send_now=true; @@ -402,13 +405,13 @@ static void MPU401_WriteData(Bitu port,Bitu val,Bitu iolen) { if (val==0xf8 || val==0xf9) mpu.condbuf.type=T_OVERFLOW; mpu.condbuf.value[mpu.condbuf.vlength]=val; mpu.condbuf.vlength++; - if ((val&0xf0)!=0xe0) MPU401_EOIHandler(); + if ((val&0xf0)!=0xe0) MPU401_EOIHandlerDispatch(); else mpu.state.data_onoff++; break; case 2:/* Command byte #2 */ mpu.condbuf.value[mpu.condbuf.vlength]=val; mpu.condbuf.vlength++; - MPU401_EOIHandler(); + MPU401_EOIHandlerDispatch(); break; } return; @@ -420,7 +423,7 @@ static void MPU401_WriteData(Bitu port,Bitu val,Bitu iolen) { if (val<0xf0) mpu.state.data_onoff=1; else { mpu.state.data_onoff=-1; - MPU401_EOIHandler(); + MPU401_EOIHandlerDispatch(); return; } if (val==0) mpu.state.send_now=true; @@ -461,7 +464,7 @@ static void MPU401_WriteData(Bitu port,Bitu val,Bitu iolen) { } } if (!(posd==1 && val>=0xf0)) mpu.playbuf[mpu.state.channel].value[posd-1]=val; - if (posd==length) MPU401_EOIHandler(); + if (posd==length) MPU401_EOIHandlerDispatch(); } } @@ -540,7 +543,18 @@ next_event: PIC_AddEvent(MPU401_Event,MPU401_TIMECONSTANT/new_time); } -static void MPU401_EOIHandler(void) { + +static void MPU401_EOIHandlerDispatch(void) { + if (mpu.state.send_now) { + mpu.state.eoi_scheduled=true; + PIC_AddEvent(MPU401_EOIHandler,0.06f); //Possible a bit longer + } + else if (!mpu.state.eoi_scheduled) MPU401_EOIHandler(); +} + +//Updates counters and requests new data on "End of Input" +static void MPU401_EOIHandler(Bitu val) { + mpu.state.eoi_scheduled=false; if (mpu.state.send_now) { mpu.state.send_now=false; if (mpu.state.cond_req) UpdateConductor(); @@ -558,9 +572,18 @@ static void MPU401_EOIHandler(void) { } while ((i++)<16); } +static void MPU401_ResetDone(Bitu) { + mpu.state.reset=false; + if (mpu.state.cmd_pending) { + MPU401_WriteCommand(0x331,mpu.state.cmd_pending-1,1); + mpu.state.cmd_pending=0; + } +} static void MPU401_Reset(void) { PIC_DeActivateIRQ(mpu.irq); mpu.mode=(mpu.intelligent ? M_INTELLIGENT : M_UART); + PIC_RemoveEvents(MPU401_EOIHandler); + mpu.state.eoi_scheduled=false; mpu.state.wsd=false; mpu.state.wsm=false; mpu.state.conductor=false;