DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/mpu401.cpp
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 
00020 #include <string.h>
00021 #include "dosbox.h"
00022 #include "inout.h"
00023 #include "pic.h"
00024 #include "setup.h"
00025 #include "cpu.h"
00026 #include "support.h"
00027 #include "control.h"
00028 #include "setup.h"
00029 
00030 extern bool enable_slave_pic;
00031 
00032 void MIDI_RawOutByte(Bit8u data);
00033 bool MIDI_Available(void);
00034 
00035 static void MPU401_Event(Bitu);
00036 static void MPU401_Reset(void);
00037 static void MPU401_ResetDone(Bitu);
00038 static void MPU401_EOIHandler(Bitu val=0);
00039 static void MPU401_EOIHandlerDispatch(void);
00040 
00041 #define MPU401_VERSION  0x15
00042 #define MPU401_REVISION 0x01
00043 #define MPU401_QUEUE 32
00044 #define MPU401_TIMECONSTANT (60000000/1000.0f)
00045 #define MPU401_RESETBUSY 14.0f
00046 
00047 enum MpuMode { M_UART,M_INTELLIGENT };
00048 enum MpuDataType {T_OVERFLOW,T_MARK,T_MIDI_SYS,T_MIDI_NORM,T_COMMAND};
00049 
00050 static void MPU401_WriteData(Bitu port,Bitu val,Bitu iolen);
00051 
00052 /* Messages sent to MPU-401 from host */
00053 #define MSG_EOX                         0xf7
00054 #define MSG_OVERFLOW                    0xf8
00055 #define MSG_MARK                        0xfc
00056 
00057 /* Messages sent to host from MPU-401 */
00058 #define MSG_MPU_OVERFLOW                0xf8
00059 #define MSG_MPU_COMMAND_REQ             0xf9
00060 #define MSG_MPU_END                     0xfc
00061 #define MSG_MPU_CLOCK                   0xfd
00062 #define MSG_MPU_ACK                     0xfe
00063 
00064 static struct {
00065         bool intelligent;
00066         MpuMode mode;
00067         Bitu irq;
00068         Bit8u queue[MPU401_QUEUE];
00069         Bitu queue_pos,queue_used;
00070         struct track {
00071                 Bits counter;
00072                 Bit8u value[8],sys_val;
00073                 Bit8u vlength,length;
00074                 MpuDataType type;
00075         } playbuf[8],condbuf;
00076         struct {
00077                 bool conductor,cond_req,cond_set, block_ack;
00078                 bool playing,reset;
00079                 bool wsd,wsm,wsd_start;
00080                 bool run_irq,irq_pending;
00081                 bool send_now;
00082                 bool eoi_scheduled;
00083                 Bits data_onoff;
00084                 Bitu command_byte,cmd_pending;
00085                 Bit8u tmask,cmask,amask;
00086                 Bit16u midi_mask;
00087                 Bit16u req_mask;
00088                 Bit8u channel,old_chan;
00089         } state;
00090         struct {
00091                 Bit8u timebase,old_timebase;
00092                 Bit8u tempo,old_tempo;
00093                 Bit8u tempo_rel,old_tempo_rel;
00094                 Bit8u tempo_grad;
00095                 Bit8u cth_rate,cth_counter;
00096                 bool clock_to_host,cth_active;
00097         } clock;
00098 } mpu;
00099 
00100 int MPU401_GetIRQ() {
00101         return (int)mpu.irq;
00102 }
00103 
00104 static void QueueByte(Bit8u data) {
00105         if (mpu.state.block_ack) {mpu.state.block_ack=false;return;}
00106         if (mpu.queue_used==0 && mpu.intelligent) {
00107                 mpu.state.irq_pending=true;
00108                 PIC_ActivateIRQ(mpu.irq);
00109         }
00110         if (mpu.queue_used<MPU401_QUEUE) {
00111                 Bitu pos=mpu.queue_used+mpu.queue_pos;
00112                 if (mpu.queue_pos>=MPU401_QUEUE) mpu.queue_pos-=MPU401_QUEUE;
00113                 if (pos>=MPU401_QUEUE) pos-=MPU401_QUEUE;
00114                 mpu.queue_used++;
00115                 mpu.queue[pos]=data;
00116         } else LOG(LOG_MISC,LOG_NORMAL)("MPU401:Data queue full");
00117 }
00118 
00119 static void ClrQueue(void) {
00120         mpu.queue_used=0;
00121         mpu.queue_pos=0;
00122 }
00123 
00124 static Bitu MPU401_ReadStatus(Bitu port,Bitu iolen) {
00125     (void)iolen;//UNUSED
00126     (void)port;//UNUSED
00127         Bit8u ret=0x3f; /* Bits 6 and 7 clear */
00128         if (mpu.state.cmd_pending) ret|=0x40;
00129         if (!mpu.queue_used) ret|=0x80;
00130         return ret;
00131 }
00132 
00133 static void MPU401_WriteCommand(Bitu port,Bitu val,Bitu iolen) {
00134     (void)iolen;//UNUSED
00135     (void)port;//UNUSED
00136     if (mpu.mode==M_UART && val!=0xff) return;
00137     if (mpu.state.reset) {
00138         /* THIS CODE IN DISPUTE [https://github.com/joncampbell123/dosbox-x/issues/917#issuecomment-538717798] */
00139         if (mpu.state.cmd_pending || val!=0xff) {
00140             mpu.state.cmd_pending=val+1;
00141             return;
00142         }
00143         PIC_RemoveEvents(MPU401_ResetDone);
00144         mpu.state.reset=false;
00145     }
00146         if (val<=0x2f) {
00147                 switch (val&3) { /* MIDI stop, start, continue */
00148                         case 1: {MIDI_RawOutByte(0xfc);break;}
00149                         case 2: {MIDI_RawOutByte(0xfa);break;}
00150                         case 3: {MIDI_RawOutByte(0xfb);break;}
00151                 }
00152                 if (val&0x20) LOG(LOG_MISC,LOG_ERROR)("MPU-401:Unhandled Recording Command %x",(int)val);
00153                 switch (val&0xc) {
00154                         case  0x4:      /* Stop */
00155                                 PIC_RemoveEvents(MPU401_Event);
00156                                 mpu.state.playing=false;
00157                                 for (Bit8u i=0xb0;i<0xbf;i++) { /* All notes off */
00158                                         MIDI_RawOutByte(i);
00159                                         MIDI_RawOutByte(0x7b);
00160                                         MIDI_RawOutByte(0);
00161                                 }
00162                                 break;
00163                         case 0x8:       /* Play */
00164                                 LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Intelligent mode playback started");
00165                                 mpu.state.playing=true;
00166                                 PIC_RemoveEvents(MPU401_Event);
00167                                 PIC_AddEvent(MPU401_Event,MPU401_TIMECONSTANT/(mpu.clock.tempo*mpu.clock.timebase));
00168                                 ClrQueue();
00169                                 break;
00170                 }
00171         }
00172         else if (val>=0xa0 && val<=0xa7) {      /* Request play counter */
00173                 if (mpu.state.cmask&(1<<(val&7))) QueueByte((Bit8u)mpu.playbuf[val&7].counter);
00174         }
00175         else if (val>=0xd0 && val<=0xd7) {      /* Send data */
00176                 mpu.state.old_chan=mpu.state.channel;
00177                 mpu.state.channel=val&7;
00178                 mpu.state.wsd=true;
00179                 mpu.state.wsm=false;
00180                 mpu.state.wsd_start=true;
00181         }
00182         else
00183         switch (val) {
00184                 case 0xdf:      /* Send system message */
00185                         mpu.state.wsd=false;
00186                         mpu.state.wsm=true;
00187                         mpu.state.wsd_start=true;
00188                         break;
00189                 case 0x8e:      /* Conductor */
00190                         mpu.state.cond_set=false;
00191                         break;
00192                 case 0x8f:
00193                         mpu.state.cond_set=true;
00194                         break;
00195                 case 0x94: /* Clock to host */
00196                         mpu.clock.clock_to_host=false;
00197                         break;
00198                 case 0x95:
00199                         mpu.clock.clock_to_host=true;
00200                         break;
00201                 case 0xc2: /* Internal timebase */
00202                         mpu.clock.timebase=48;
00203                         break;
00204                 case 0xc3:
00205                         mpu.clock.timebase=72;
00206                         break;
00207                 case 0xc4:
00208                         mpu.clock.timebase=96;
00209                         break;
00210                 case 0xc5:
00211                         mpu.clock.timebase=120;
00212                         break;
00213                 case 0xc6:
00214                         mpu.clock.timebase=144;
00215                         break;
00216                 case 0xc7:
00217                         mpu.clock.timebase=168;
00218                         break;
00219                 case 0xc8:
00220                         mpu.clock.timebase=192;
00221                         break;
00222                 /* Commands with data byte */
00223                 case 0xe0: case 0xe1: case 0xe2: case 0xe4: case 0xe6: 
00224                 case 0xe7: case 0xec: case 0xed: case 0xee: case 0xef:
00225                         mpu.state.command_byte=val;
00226                         break;
00227                 /* Commands 0xa# returning data */
00228                 case 0xab:      /* Request and clear recording counter */
00229                         QueueByte(MSG_MPU_ACK);
00230                         QueueByte(0);
00231                         return;
00232                 case 0xac:      /* Request version */
00233                         QueueByte(MSG_MPU_ACK);
00234                         QueueByte(MPU401_VERSION);
00235                         return;
00236                 case 0xad:      /* Request revision */
00237                         QueueByte(MSG_MPU_ACK);
00238                         QueueByte(MPU401_REVISION);
00239                         return;
00240                 case 0xaf:      /* Request tempo */
00241                         QueueByte(MSG_MPU_ACK);
00242                         QueueByte(mpu.clock.tempo);
00243                         return;
00244                 case 0xb1:      /* Reset relative tempo */
00245             mpu.clock.old_tempo_rel=mpu.clock.tempo_rel;
00246             mpu.clock.tempo_rel=0x40;
00247                         break;
00248                 case 0xb9:      /* Clear play map */
00249                 case 0xb8:      /* Clear play counters */
00250                         for (Bit8u i=0xb0;i<0xbf;i++) { /* All notes off */
00251                                 MIDI_RawOutByte(i);
00252                                 MIDI_RawOutByte(0x7b);
00253                                 MIDI_RawOutByte(0);
00254                         }
00255                         for (Bitu i=0;i<8;i++) {
00256                                 mpu.playbuf[i].counter=0;
00257                                 mpu.playbuf[i].type=T_OVERFLOW;
00258                         }
00259                         mpu.condbuf.counter=0;
00260                         mpu.condbuf.type=T_OVERFLOW;
00261                         if (!(mpu.state.conductor=mpu.state.cond_set)) mpu.state.cond_req=0;
00262                         mpu.state.amask=mpu.state.tmask;
00263                         mpu.state.req_mask=0;
00264                         mpu.state.irq_pending=true;
00265                         break;
00266                 case 0xff:      /* Reset MPU-401 */
00267                         LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Reset %X",(int)val);
00268                         PIC_AddEvent(MPU401_ResetDone,MPU401_RESETBUSY);
00269                         mpu.state.reset=true;
00270                         if (mpu.mode==M_UART) {
00271                                 MPU401_Reset();
00272                                 return; //do not send ack in UART mode
00273                         }
00274                         MPU401_Reset();
00275                         break;
00276                 case 0x3f:      /* UART mode */
00277                         LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Set UART mode %X",(int)val);
00278                         mpu.mode=M_UART;
00279                         break;
00280                 default:;
00281                         //LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Unhandled command %X",val);
00282         }
00283         QueueByte(MSG_MPU_ACK);
00284 }
00285 
00286 static Bitu MPU401_ReadData(Bitu port,Bitu iolen) {
00287     (void)iolen;//UNUSED
00288     (void)port;//UNUSED
00289         Bit8u ret=MSG_MPU_ACK;
00290         if (mpu.queue_used) {
00291                 if (mpu.queue_pos>=MPU401_QUEUE) mpu.queue_pos-=MPU401_QUEUE;
00292                 ret=mpu.queue[mpu.queue_pos];
00293                 mpu.queue_pos++;mpu.queue_used--;
00294         }
00295         if (!mpu.intelligent) return ret;
00296 
00297         if (mpu.queue_used == 0) PIC_DeActivateIRQ(mpu.irq);
00298 
00299         if (ret>=0xf0 && ret<=0xf7) { /* MIDI data request */
00300                 mpu.state.channel=ret&7;
00301                 mpu.state.data_onoff=0;
00302                 mpu.state.cond_req=false;
00303         }
00304         if (ret==MSG_MPU_COMMAND_REQ) {
00305                 mpu.state.data_onoff=0;
00306                 mpu.state.cond_req=true;
00307                 if (mpu.condbuf.type!=T_OVERFLOW) {
00308                         mpu.state.block_ack=true;
00309                         MPU401_WriteCommand(0x331,mpu.condbuf.value[0],1);
00310                         if (mpu.state.command_byte) MPU401_WriteData(0x330,mpu.condbuf.value[1],1);
00311                 }
00312         mpu.condbuf.type=T_OVERFLOW;
00313         }
00314         if (ret==MSG_MPU_END || ret==MSG_MPU_CLOCK || ret==MSG_MPU_ACK) {
00315                 mpu.state.data_onoff=-1;
00316                 MPU401_EOIHandlerDispatch();
00317         }
00318         return ret;
00319 }
00320 
00321 static void MPU401_WriteData(Bitu port,Bitu val,Bitu iolen) {
00322     (void)iolen;//UNUSED
00323     (void)port;//UNUSED
00324         if (mpu.mode==M_UART) {MIDI_RawOutByte((Bit8u)val);return;}
00325         switch (mpu.state.command_byte) {       /* 0xe# command data */
00326                 case 0x00:
00327                         break;
00328                 case 0xe0:      /* Set tempo */
00329                         mpu.state.command_byte=0;
00330                         mpu.clock.tempo=(Bit8u)val;
00331                         return;
00332                 case 0xe1:      /* Set relative tempo */
00333                         mpu.state.command_byte=0;
00334             mpu.clock.old_tempo_rel=mpu.clock.tempo_rel;
00335             mpu.clock.tempo_rel=(Bit8u)val;
00336             if (val != 0x40) LOG(LOG_MISC,LOG_ERROR)("MPU-401:Relative tempo change value 0x%x (%.3f)",(unsigned int)val,(double)val / 0x40);
00337                         return;
00338                 case 0xe7:      /* Set internal clock to host interval */
00339                         mpu.state.command_byte=0;
00340                         mpu.clock.cth_rate=(Bit8u)(val>>2);
00341                         return;
00342                 case 0xec:      /* Set active track mask */
00343                         mpu.state.command_byte=0;
00344                         mpu.state.tmask=(Bit8u)val;
00345                         return;
00346                 case 0xed: /* Set play counter mask */
00347                         mpu.state.command_byte=0;
00348                         mpu.state.cmask=(Bit8u)val;
00349                         return;
00350                 case 0xee: /* Set 1-8 MIDI channel mask */
00351                         mpu.state.command_byte=0;
00352                         mpu.state.midi_mask&=0xff00;
00353                         mpu.state.midi_mask|=val;
00354                         return;
00355                 case 0xef: /* Set 9-16 MIDI channel mask */
00356                         mpu.state.command_byte=0;
00357                         mpu.state.midi_mask&=0x00ff;
00358                         mpu.state.midi_mask|=((Bit16u)val)<<8;
00359                         return;
00360                 //case 0xe2:    /* Set graduation for relative tempo */
00361                 //case 0xe4:    /* Set metronome */
00362                 //case 0xe6:    /* Set metronome measure length */
00363                 default:
00364                         mpu.state.command_byte=0;
00365                         return;
00366         }
00367         static Bitu length,cnt,posd;
00368         if (mpu.state.wsd) {    /* Directly send MIDI message */
00369                 if (mpu.state.wsd_start) {
00370                         mpu.state.wsd_start=0;
00371                         cnt=0;
00372                                 switch (val&0xf0) {
00373                                         case 0xc0:case 0xd0:
00374                                                 mpu.playbuf[mpu.state.channel].value[0]=(Bit8u)val;
00375                                                 length=2;
00376                                                 break;
00377                                         case 0x80:case 0x90:case 0xa0:case 0xb0:case 0xe0:
00378                                                 mpu.playbuf[mpu.state.channel].value[0]=(Bit8u)val;
00379                                                 length=3;
00380                                                 break;
00381                                         case 0xf0:
00382                                                 LOG(LOG_MISC,LOG_ERROR)("MPU-401:Illegal WSD byte");
00383                                                 mpu.state.wsd=0;
00384                                                 mpu.state.channel=mpu.state.old_chan;
00385                                                 return;
00386                                         default: /* MIDI with running status */
00387                                                 cnt++;
00388                                                 MIDI_RawOutByte(mpu.playbuf[mpu.state.channel].value[0]);
00389                                 }
00390                 }
00391                 if (cnt<length) {MIDI_RawOutByte((Bit8u)val);cnt++;}
00392                 if (cnt==length) {
00393                         mpu.state.wsd=0;
00394                         mpu.state.channel=mpu.state.old_chan;
00395                 }
00396                 return;
00397         }
00398         if (mpu.state.wsm) {    /* Directly send system message */
00399                 if (val==MSG_EOX) {MIDI_RawOutByte(MSG_EOX);mpu.state.wsm=0;return;}
00400                 if (mpu.state.wsd_start) {
00401                         mpu.state.wsd_start=0;
00402                         cnt=0;
00403                         switch (val) {
00404                                 case 0xf2:{ length=3; break;}
00405                                 case 0xf3:{ length=2; break;}
00406                                 case 0xf6:{ length=1; break;}
00407                                 case 0xf0:{ length=0; break;}
00408                                 default:
00409                                         length=0;
00410                         }
00411                 }
00412                 if (!length || cnt<length) {MIDI_RawOutByte((Bit8u)val);cnt++;}
00413                 if (cnt==length) mpu.state.wsm=0;
00414                 return;
00415         }
00416         if (mpu.state.cond_req) { /* Command */
00417                 switch (mpu.state.data_onoff) {
00418                         case -1:
00419                                 return;
00420                         case  0: /* Timing byte */
00421                                 mpu.condbuf.vlength=0;
00422                                 if (val<0xf0) mpu.state.data_onoff++;
00423                                 else {
00424                                         mpu.state.data_onoff=-1;
00425                                         MPU401_EOIHandlerDispatch();
00426                                         return;
00427                                 }
00428                                 if (val==0) mpu.state.send_now=true;
00429                                 else mpu.state.send_now=false;
00430                                 mpu.condbuf.counter=(Bits)val;
00431                                 break;
00432                         case  1: /* Command byte #1 */
00433                                 mpu.condbuf.type=T_COMMAND;
00434                                 if (val==0xf8 || val==0xf9) mpu.condbuf.type=T_OVERFLOW;
00435                                 mpu.condbuf.value[mpu.condbuf.vlength]=(Bit8u)val;
00436                                 mpu.condbuf.vlength++;
00437                                 if ((val&0xf0)!=0xe0) MPU401_EOIHandlerDispatch();
00438                                 else mpu.state.data_onoff++;
00439                                 break;
00440                         case  2:/* Command byte #2 */
00441                                 mpu.condbuf.value[mpu.condbuf.vlength]=(Bit8u)val;
00442                                 mpu.condbuf.vlength++;
00443                                 MPU401_EOIHandlerDispatch();
00444                                 break;
00445                 }
00446                 return;
00447         }
00448         switch (mpu.state.data_onoff) { /* Data */
00449                 case   -1:
00450                         return;
00451                 case    0: /* Timing byte */
00452                         if (val<0xf0) mpu.state.data_onoff=1;
00453                         else {
00454                                 mpu.state.data_onoff=-1;
00455                                 MPU401_EOIHandlerDispatch();
00456                                 return;
00457                         }
00458                         if (val==0) mpu.state.send_now=true;
00459                         else mpu.state.send_now=false;
00460                         mpu.playbuf[mpu.state.channel].counter=(Bits)val;
00461                         break;
00462                 case    1: /* MIDI */
00463                         mpu.playbuf[mpu.state.channel].vlength++;
00464                         posd=mpu.playbuf[mpu.state.channel].vlength;
00465                         if (posd==1) {
00466                                 switch (val&0xf0) {
00467                                         case 0xf0: /* System message or mark */
00468                                                 if (val>0xf7) {
00469                                                         mpu.playbuf[mpu.state.channel].type=T_MARK;
00470                                                         mpu.playbuf[mpu.state.channel].sys_val=(Bit8u)val;
00471                                                         length=1;
00472                                                 } else {
00473                                                         LOG(LOG_MISC,LOG_ERROR)("MPU-401:Illegal message");
00474                                                         mpu.playbuf[mpu.state.channel].type=T_MIDI_SYS;
00475                                                         mpu.playbuf[mpu.state.channel].sys_val=(Bit8u)val;
00476                                                         length=1;
00477                                                 }
00478                                                 break;
00479                                         case 0xc0: case 0xd0: /* MIDI Message */
00480                                                 mpu.playbuf[mpu.state.channel].type=T_MIDI_NORM;
00481                                                 length=mpu.playbuf[mpu.state.channel].length=2;
00482                                                 break;
00483                                         case 0x80: case 0x90: case 0xa0:  case 0xb0: case 0xe0: 
00484                                                 mpu.playbuf[mpu.state.channel].type=T_MIDI_NORM;
00485                                                 length=mpu.playbuf[mpu.state.channel].length=3;
00486                                                 break;
00487                                         default: /* MIDI data with running status */
00488                                                 posd++;
00489                                                 mpu.playbuf[mpu.state.channel].vlength++;
00490                                                 mpu.playbuf[mpu.state.channel].type=T_MIDI_NORM;
00491                                                 length=mpu.playbuf[mpu.state.channel].length;
00492                                                 break;
00493                                 }
00494                         }
00495                         if (!(posd==1 && val>=0xf0)) mpu.playbuf[mpu.state.channel].value[posd-1]=(Bit8u)val;
00496                         if (posd==length) MPU401_EOIHandlerDispatch();
00497         }
00498 }
00499 
00500 static void MPU401_IntelligentOut(Bit8u chan) {
00501         Bitu val;
00502         switch (mpu.playbuf[chan].type) {
00503                 case T_OVERFLOW:
00504                         break;
00505                 case T_MARK:
00506                         val=mpu.playbuf[chan].sys_val;
00507                         if (val==0xfc) {
00508                                 MIDI_RawOutByte((Bit8u)val);
00509                                 mpu.state.amask&=~(1<<chan);
00510                                 mpu.state.req_mask&=~(1<<chan);
00511                         }
00512                         break;
00513                 case T_MIDI_NORM:
00514                         for (Bitu i=0;i<mpu.playbuf[chan].vlength;i++)
00515                                 MIDI_RawOutByte(mpu.playbuf[chan].value[i]);
00516                         break;
00517                 default:
00518                         break;
00519         }
00520 }
00521 
00522 static void UpdateTrack(Bit8u chan) {
00523         MPU401_IntelligentOut(chan);
00524         if (mpu.state.amask&(1<<chan)) {
00525                 mpu.playbuf[chan].vlength=0;
00526                 mpu.playbuf[chan].type=T_OVERFLOW;
00527                 mpu.playbuf[chan].counter=0xf0;
00528                 mpu.state.req_mask|=(1<<chan);
00529         } else {
00530                 if (mpu.state.amask==0 && !mpu.state.conductor) mpu.state.req_mask|=(1<<12);
00531         }
00532 }
00533 
00534 static void UpdateConductor(void) {
00535     for (unsigned int i=0;i < mpu.condbuf.vlength;i++) {
00536         if (mpu.condbuf.value[i] == 0xfc) {
00537             mpu.condbuf.value[i] = 0;
00538             mpu.state.conductor=false;
00539             mpu.state.req_mask&=~(1<<9);
00540             if (mpu.state.amask==0) mpu.state.req_mask|=(1<<12);
00541             return;
00542         }
00543     }
00544 
00545         mpu.condbuf.vlength=0;
00546         mpu.condbuf.counter=0xf0;
00547         mpu.state.req_mask|=(1<<9);
00548 }
00549 
00550 static void MPU401_Event(Bitu val) {
00551     (void)val;//UNUSED
00552         if (mpu.mode==M_UART) return;
00553         if (mpu.state.irq_pending) goto next_event;
00554         for (Bit8u i=0;i<8;i++) { /* Decrease counters */
00555                 if (mpu.state.amask&(1<<i)) {
00556                         mpu.playbuf[i].counter--;
00557                         if (mpu.playbuf[i].counter<=0) UpdateTrack(i);
00558                 }
00559         }               
00560         if (mpu.state.conductor) {
00561                 mpu.condbuf.counter--;
00562                 if (mpu.condbuf.counter<=0) UpdateConductor();
00563         }
00564         if (mpu.clock.clock_to_host) {
00565                 mpu.clock.cth_counter++;
00566                 if (mpu.clock.cth_counter >= mpu.clock.cth_rate) {
00567                         mpu.clock.cth_counter=0;
00568                         mpu.state.req_mask|=(1<<13);
00569                 }
00570         }
00571         if (!mpu.state.irq_pending && mpu.state.req_mask) MPU401_EOIHandler();
00572 next_event:
00573         Bitu new_time;
00574         if ((new_time=(Bitu)((mpu.clock.tempo*mpu.clock.timebase*mpu.clock.tempo_rel)/0x40))==0) return;
00575         PIC_AddEvent(MPU401_Event,MPU401_TIMECONSTANT/new_time);
00576 }
00577 
00578 
00579 static void MPU401_EOIHandlerDispatch(void) {
00580         if (mpu.state.send_now) {
00581                 mpu.state.eoi_scheduled=true;
00582                 PIC_AddEvent(MPU401_EOIHandler,0.06f); //Possible a bit longer
00583         }
00584         else if (!mpu.state.eoi_scheduled) MPU401_EOIHandler();
00585 }
00586 
00587 //Updates counters and requests new data on "End of Input"
00588 static void MPU401_EOIHandler(Bitu val) {
00589     (void)val;//UNUSED
00590         mpu.state.eoi_scheduled=false;
00591         if (mpu.state.send_now) {
00592                 mpu.state.send_now=false;
00593                 if (mpu.state.cond_req) UpdateConductor();
00594                 else UpdateTrack(mpu.state.channel);
00595         }
00596         mpu.state.irq_pending=false;
00597         if (!mpu.state.playing || !mpu.state.req_mask) return;
00598         Bit8u i=0;
00599         do {
00600                 if (mpu.state.req_mask&(1<<i)) {
00601                         QueueByte(0xf0+i);
00602                         mpu.state.req_mask&=~(1<<i);
00603                         break;
00604                 }
00605         } while ((i++)<16);
00606 }
00607 
00608 static void MPU401_ResetDone(Bitu) {
00609         mpu.state.reset=false;
00610         if (mpu.state.cmd_pending) {
00611                 MPU401_WriteCommand(0x331,mpu.state.cmd_pending-1,1);
00612                 mpu.state.cmd_pending=0;
00613         }
00614 }
00615 static void MPU401_Reset(void) {
00616         PIC_DeActivateIRQ(mpu.irq);
00617         mpu.mode=(mpu.intelligent ? M_INTELLIGENT : M_UART);
00618         PIC_RemoveEvents(MPU401_EOIHandler);
00619         mpu.state.eoi_scheduled=false;
00620         mpu.state.wsd=false;
00621         mpu.state.wsm=false;
00622         mpu.state.conductor=false;
00623         mpu.state.cond_req=false;
00624         mpu.state.cond_set=false;
00625         mpu.state.playing=false;
00626         mpu.state.run_irq=false;
00627         mpu.state.irq_pending=false;
00628         mpu.state.cmask=0xff;
00629         mpu.state.amask=mpu.state.tmask=0;
00630         mpu.state.midi_mask=0xffff;
00631         mpu.state.data_onoff=-1;
00632         mpu.state.command_byte=0;
00633         mpu.state.block_ack=false;
00634         mpu.clock.tempo=mpu.clock.old_tempo=100;
00635         mpu.clock.timebase=mpu.clock.old_timebase=120;
00636         mpu.clock.tempo_rel=mpu.clock.old_tempo_rel=0x40;
00637         mpu.clock.tempo_grad=0;
00638         mpu.clock.clock_to_host=false;
00639         mpu.clock.cth_rate=60;
00640         mpu.clock.cth_counter=0;
00641         ClrQueue();
00642         mpu.state.req_mask=0;
00643         mpu.condbuf.counter=0;
00644         mpu.condbuf.type=T_OVERFLOW;
00645         for (Bitu i=0;i<8;i++) {mpu.playbuf[i].type=T_OVERFLOW;mpu.playbuf[i].counter=0;}
00646 }
00647 
00648 static void IMF_Write(Bitu port,Bitu val,Bitu iolen) {
00649     (void)iolen;//UNUSED
00650         LOG(LOG_MISC,LOG_NORMAL)("IMF:Wr %4X,%X",(int)port,(int)val);
00651 }
00652 
00653 class MPU401:public Module_base{
00654 private:
00655         IO_ReadHandleObject ReadHandler[2];
00656         IO_WriteHandleObject WriteHandler[2];
00657         bool installed; /*as it can fail to install by 2 ways (config and no midi)*/
00658 public:
00659         MPU401(Section* configuration):Module_base(configuration){
00660                 installed = false;
00661                 Section_prop * section=static_cast<Section_prop *>(configuration);
00662                 const char* s_mpu = section->Get_string("mpu401");
00663                 if(strcasecmp(s_mpu,"none") == 0) return;
00664                 if(strcasecmp(s_mpu,"off") == 0) return;
00665                 if(strcasecmp(s_mpu,"false") == 0) return;
00666                 if (!MIDI_Available()) return;
00667                 /*Enabled and there is a Midi */
00668                 installed = true;
00669 
00670         Bitu baseio = (Bitu)section->Get_hex("mpubase");
00671         if (baseio == 0) {
00672             if (IS_PC98_ARCH)
00673                 baseio = 0xE0D0; // NTS: This is based on MMD.COM I/O probing behavior
00674             else
00675                 baseio = 0x330;
00676         }
00677 
00678         if (baseio >= 0x80D2 && baseio <= 0x80DE) {
00679             /* TODO: Replace low 8 bits with low 8 bits of Sound Blaster 16 I/O base */
00680         }
00681 
00682         if (IS_PC98_ARCH) {
00683             if (baseio >= 0x80D2 && baseio <= 0x80DE)
00684                 { /* OK */ }
00685             else if (baseio >= 0xC000u && baseio <= 0xF8D0u)
00686                 { /* OK */ }
00687             else
00688                 baseio = 0xE0D0u;
00689         }
00690         else {
00691             if (baseio < 0x300 || baseio > 0x360)
00692                 baseio = 0x330;
00693         }
00694 
00695         if (baseio >= 0x80D2 && baseio <= 0x80DE) {
00696             LOG_MSG("MPU-401 Registering I/O ports as if SB16 MPU-401 at base %xh",(unsigned int)baseio);
00697             /* SB16 mapping
00698              * C8D2h, C9D2h (PC-98) */
00699             assert(IS_PC98_ARCH);
00700             WriteHandler[0].Install(baseio       ,&MPU401_WriteData,IO_MB);
00701             WriteHandler[1].Install(baseio+0x100u,&MPU401_WriteCommand,IO_MB);
00702             ReadHandler[0].Install(baseio       ,&MPU401_ReadData,IO_MB);
00703             ReadHandler[1].Install(baseio+0x100u,&MPU401_ReadStatus,IO_MB);
00704         }
00705         else {
00706             if (IS_PC98_ARCH)
00707                 LOG_MSG("MPU-401 Registering I/O ports as if PC-98 MPU-401 at base %xh",(unsigned int)baseio);
00708             else
00709                 LOG_MSG("MPU-401 Registering I/O ports as if IBM PC MPU-401 at base %xh",(unsigned int)baseio);
00710             /* 330h, 331h (IBM PC)
00711              * E0D0h, E0D2h (PC-98) */
00712             WriteHandler[0].Install(baseio                     ,&MPU401_WriteData,IO_MB);
00713             WriteHandler[1].Install(baseio+(IS_PC98_ARCH?2u:1u),&MPU401_WriteCommand,IO_MB);
00714             ReadHandler[0].Install(baseio                     ,&MPU401_ReadData,IO_MB);
00715             ReadHandler[1].Install(baseio+(IS_PC98_ARCH?2u:1u),&MPU401_ReadStatus,IO_MB);
00716         }
00717 
00718         if (IS_PC98_ARCH) {
00719         }
00720         else {
00721             /*
00722                IO_RegisterWriteHandler(0x280,&IMF_Write,IO_MB);
00723                IO_RegisterWriteHandler(0x281,&IMF_Write,IO_MB);
00724                IO_RegisterReadHandler(0x280,&IMF_Read,IO_MB);
00725                IO_RegisterReadHandler(0x281,&IMF_Read,IO_MB);
00726                */
00727             /*
00728                IO_RegisterWriteHandler(0x200,&IMF_Write,IO_MB);
00729                IO_RegisterWriteHandler(0x201,&IMF_Write,IO_MB);
00730                IO_RegisterWriteHandler(0x202,&IMF_Write,IO_MB);
00731                IO_RegisterWriteHandler(0x203,&IMF_Write,IO_MB);
00732                IO_RegisterWriteHandler(0x204,&IMF_Write,IO_MB);
00733 
00734                IO_RegisterReadHandler(0x200,&IMF_Read,IO_MB);
00735                IO_RegisterReadHandler(0x201,&IMF_Read,IO_MB);
00736                IO_RegisterReadHandler(0x202,&IMF_Read,IO_MB);
00737                IO_RegisterReadHandler(0x203,&IMF_Read,IO_MB);
00738                IO_RegisterReadHandler(0x204,&IMF_Read,IO_MB);
00739                */
00740             IO_RegisterWriteHandler(0x2A20,&IMF_Write,IO_MB);
00741             IO_RegisterWriteHandler(0x2A21,&IMF_Write,IO_MB);
00742             IO_RegisterWriteHandler(0x2A22,&IMF_Write,IO_MB);
00743             IO_RegisterWriteHandler(0x2A23,&IMF_Write,IO_MB);
00744             IO_RegisterWriteHandler(0x2A24,&IMF_Write,IO_MB);
00745             IO_RegisterWriteHandler(0x2A25,&IMF_Write,IO_MB);
00746             IO_RegisterWriteHandler(0x2A26,&IMF_Write,IO_MB);
00747             IO_RegisterWriteHandler(0x2A27,&IMF_Write,IO_MB);
00748             IO_RegisterWriteHandler(0x2A28,&IMF_Write,IO_MB);
00749             IO_RegisterWriteHandler(0x2A29,&IMF_Write,IO_MB);
00750             IO_RegisterWriteHandler(0x2A2A,&IMF_Write,IO_MB);
00751             IO_RegisterWriteHandler(0x2A2B,&IMF_Write,IO_MB);
00752             IO_RegisterWriteHandler(0x2A2C,&IMF_Write,IO_MB);
00753             IO_RegisterWriteHandler(0x2A2D,&IMF_Write,IO_MB);
00754             IO_RegisterWriteHandler(0x2A2E,&IMF_Write,IO_MB);
00755             IO_RegisterWriteHandler(0x2A2F,&IMF_Write,IO_MB);
00756         }
00757 
00758                 mpu.queue_used=0;
00759                 mpu.queue_pos=0;
00760                 mpu.mode=M_UART;
00761 
00762         if (IS_PC98_ARCH)
00763             mpu.irq=6;  /* This is said to be the MIDI card's factory default on PC-98 */
00764         else if (!enable_slave_pic)
00765             mpu.irq=2;
00766         else
00767                 mpu.irq=9;      /* Princess Maker 2 wants it on irq 9 */
00768 
00769         {
00770             int x = section->Get_int("mpuirq");
00771 
00772             if (x >= 2)
00773                 mpu.irq = (unsigned int)x;
00774 
00775             if (!IS_PC98_ARCH && enable_slave_pic && mpu.irq == 2)
00776                 mpu.irq = 9;
00777             else if (!enable_slave_pic && mpu.irq == 9)
00778                 mpu.irq = 2;
00779         }
00780 
00781         LOG(LOG_MISC,LOG_NORMAL)("MPU IRQ %d",(int)mpu.irq);
00782 
00783                 mpu.intelligent = true; //Default is on
00784                 if(strcasecmp(s_mpu,"uart") == 0) mpu.intelligent = false;
00785                 if (!mpu.intelligent) return;
00786 
00787         if (IS_PC98_ARCH) {
00788             /* Mask IRQ by default.
00789              * 
00790              * MMD.COM, a common MIDI MPU-401 driver in the PC-98 world, seems to have
00791              * IRQ detection problems unless the IRQ is masked during the detection phase.
00792              * It will fail to detect any IRQ that is unmasked during it's detection phase.
00793              * For some reason it's not totally consistent i.e. the MMD.COM driver included
00794              * with Touhou Project 2 can detect MIDI on IRQ 5 when unmasked, but not 3, 12, or 6,
00795              * or sometimes only on IRQ 6 if I/O delays are lengthened.
00796              *
00797              * Perhaps the driver assumes that if the IRQ is unmasked, that it's probably in
00798              * use and not safe to probe.
00799              *
00800              * Also noted: MMD.COM cannot detect IRQs reliably if I/O delay is disabled in
00801              *             the emulation (iodelay=0) */
00802             PIC_SetIRQMask(mpu.irq,true);
00803         }
00804         else {
00805             /*Set IRQ and unmask it(for timequest/princess maker 2) */
00806             PIC_SetIRQMask(mpu.irq,false);
00807         }
00808 
00809                 MPU401_Reset();
00810         }
00811 };
00812 
00813 static MPU401* test = NULL;
00814 
00815 void MPU401_Destroy(Section* sec){
00816     (void)sec;//UNUSED
00817         if (test != NULL) {
00818                 delete test;
00819                 test = NULL;
00820         }
00821 }
00822 
00823 void MPU401_Reset(Section* sec) {
00824     (void)sec;//UNUSED
00825         if (test == NULL) {
00826                 LOG(LOG_MISC,LOG_DEBUG)("Allocating MPU401 emulation");
00827                 test = new MPU401(control->GetSection("midi"));
00828         }
00829 }
00830 
00831 void MIDI_GUI_OnSectionPropChange(Section *x);
00832 
00833 void MIDI_OnSectionPropChange(Section *x) {
00834     delete test;
00835     test = NULL;
00836 
00837     LOG(LOG_MISC,LOG_DEBUG)("Resetting MPU401, config change");
00838 
00839     MIDI_GUI_OnSectionPropChange(x);
00840 
00841     test = new MPU401(control->GetSection("midi"));
00842 }
00843 
00844 void MPU401_Init() {
00845         LOG(LOG_MISC,LOG_DEBUG)("Initializing MPU401 emulation");
00846 
00847         AddVMEventFunction(VM_EVENT_RESET,AddVMEventFunctionFuncPair(MPU401_Reset));
00848         AddExitFunction(AddExitFunctionFuncPair(MPU401_Destroy),true);
00849 
00850         control->GetSection("midi")->onpropchange.push_back(&MIDI_OnSectionPropChange);
00851 }
00852 
00853 // save state support
00854 void *MPU401_Event_PIC_Event = (void*)((uintptr_t)MPU401_Event);
00855 
00856 void POD_Save_MPU401( std::ostream& stream )
00857 {
00858         const char pod_name[32] = "MPU401";
00859 
00860         if( stream.fail() ) return;
00861         if( !test ) return;
00862 
00863 
00864         WRITE_POD( &pod_name, pod_name );
00865 
00866         //*******************************************
00867         //*******************************************
00868         //*******************************************
00869 
00870         // - pure data
00871         WRITE_POD( &mpu, mpu );
00872 }
00873 
00874 
00875 void POD_Load_MPU401( std::istream& stream )
00876 {
00877         char pod_name[32] = {0};
00878 
00879         if( stream.fail() ) return;
00880         if( !test ) return;
00881 
00882 
00883         // error checking
00884         READ_POD( &pod_name, pod_name );
00885         if( strcmp( pod_name, "MPU401" ) ) {
00886                 stream.clear( std::istream::failbit | std::istream::badbit );
00887                 return;
00888         }
00889 
00890         //************************************************
00891         //************************************************
00892         //************************************************
00893 
00894         // - pure data
00895         READ_POD( &mpu, mpu );
00896 }