DOSBox-X
|
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 }