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 <iomanip> 00022 #include <sstream> 00023 #include "dosbox.h" 00024 #include "inout.h" 00025 #include "mixer.h" 00026 #include "dma.h" 00027 #include "pic.h" 00028 #include "control.h" 00029 #include "setup.h" 00030 #include "shell.h" 00031 #include "math.h" 00032 #include "regs.h" 00033 using namespace std; 00034 00035 #if defined(_MSC_VER) 00036 # pragma warning(disable:4244) /* const fmath::local::uint64_t to double possible loss of data */ 00037 #endif 00038 00039 enum GUSType { 00040 GUS_CLASSIC=0, 00041 GUS_MAX, 00042 GUS_INTERWAVE 00043 }; 00044 00045 //Extra bits of precision over normal gus 00046 #define WAVE_FRACT 9 00047 #define WAVE_FRACT_MASK ((1 << WAVE_FRACT)-1) 00048 #define WAVE_MSWMASK ((1 << 16)-1) 00049 #define WAVE_LSWMASK (0xffffffff ^ WAVE_MSWMASK) 00050 00051 //Amount of precision the volume has 00052 #define RAMP_FRACT (10) 00053 #define RAMP_FRACT_MASK ((1 << RAMP_FRACT)-1) 00054 00055 #define GUS_BASE myGUS.portbase 00056 #define GUS_RATE myGUS.rate 00057 #define LOG_GUS 0 00058 00059 #define VOL_SHIFT 14 00060 00061 #define WCTRL_STOPPED 0x01 00062 #define WCTRL_STOP 0x02 00063 #define WCTRL_16BIT 0x04 00064 #define WCTRL_LOOP 0x08 00065 #define WCTRL_BIDIRECTIONAL 0x10 00066 #define WCTRL_IRQENABLED 0x20 00067 #define WCTRL_DECREASING 0x40 00068 #define WCTRL_IRQPENDING 0x80 00069 00070 // fixed panning table (avx) 00071 static Bit16u const pantablePDF[16] = { 0, 13, 26, 41, 57, 72, 94, 116, 141, 169, 203, 244, 297, 372, 500, 4095 }; 00072 static bool gus_fixed_table = false; 00073 00074 Bit8u adlib_commandreg; 00075 static MixerChannel * gus_chan; 00076 static Bit8u const irqtable[8] = { 0/*invalid*/, 2, 5, 3, 7, 11, 12, 15 }; 00077 static Bit8u const dmatable[8] = { 0/*NO DMA*/, 1, 3, 5, 6, 7, 0/*invalid*/, 0/*invalid*/ }; 00078 static Bit8u GUSRam[1024*1024 + 16/*safety margin*/]; // 1024K of GUS Ram 00079 static Bit32s AutoAmp = 512; 00080 static bool unmask_irq = false; 00081 static bool enable_autoamp = false; 00082 static bool startup_ultrinit = false; 00083 static bool ignore_active_channel_write_while_active = false; 00084 static bool dma_enable_on_dma_control_polling = false; 00085 static Bit16u vol16bit[4096]; 00086 static Bit32u pantable[16]; 00087 static enum GUSType gus_type = GUS_CLASSIC; 00088 static bool gus_ics_mixer = false; 00089 static bool gus_warn_irq_conflict = false; 00090 static bool gus_warn_dma_conflict = false; 00091 00092 static IO_Callout_t gus_iocallout = IO_Callout_t_none; 00093 static IO_Callout_t gus_iocallout2 = IO_Callout_t_none; 00094 00095 class GUSChannels; 00096 static void CheckVoiceIrq(void); 00097 00098 struct GFGus { 00099 Bit8u gRegSelectData; // what is read back from 3X3. not necessarily the index selected, but 00100 // apparently the last byte read OR written to ports 3X3-3X5 as seen 00101 // on actual GUS hardware. 00102 Bit8u gRegSelect; 00103 Bit16u gRegData; 00104 Bit32u gDramAddr; 00105 Bit32u gDramAddrMask; 00106 Bit16u gCurChannel; 00107 00108 Bit8u gUltraMAXControl; 00109 Bit8u DMAControl; 00110 Bit16u dmaAddr; 00111 Bit8u dmaAddrOffset; /* bits 0-3 of the addr */ 00112 Bit8u TimerControl; 00113 Bit8u SampControl; 00114 Bit8u mixControl; 00115 Bit8u ActiveChannels; 00116 Bit8u ActiveChannelsUser; /* what the guest wrote */ 00117 Bit8u gRegControl; 00118 Bit32u basefreq; 00119 00120 struct GusTimer { 00121 float delay; 00122 Bit8u value; 00123 bool reached; 00124 bool raiseirq; 00125 bool masked; 00126 bool running; 00127 } timers[2]; 00128 Bit32u rate; 00129 Bitu portbase; 00130 Bit32u memsize; 00131 Bit8u dma1; 00132 Bit8u dma2; 00133 00134 Bit8u irq1; // GF1 IRQ 00135 Bit8u irq2; // MIDI IRQ 00136 00137 bool irqenabled; 00138 bool ChangeIRQDMA; 00139 bool initUnmaskDMA; 00140 bool force_master_irq_enable; 00141 bool fixed_sample_rate_output; 00142 bool clearTCIfPollingIRQStatus; 00143 double lastIRQStatusPollAt; 00144 int lastIRQStatusPollRapidCount; 00145 // IRQ status register values 00146 Bit8u IRQStatus; 00147 Bit32u ActiveMask; 00148 Bit8u IRQChan; 00149 Bit32u RampIRQ; 00150 Bit32u WaveIRQ; 00151 double masterVolume; /* decibels */ 00152 Bit32s masterVolumeMul; /* 1<<9 fixed */ 00153 00154 void updateMasterVolume(void) { 00155 double vol = masterVolume; 00156 if (vol > 6) vol = 6; // allow some amplification but don't let it overflow 00157 masterVolumeMul = (Bit32s)((1 << 9) * pow(10.0,vol / 20.0)); 00158 if (AutoAmp > masterVolumeMul) AutoAmp = masterVolumeMul; 00159 } 00160 } myGUS; 00161 00162 Bitu DEBUG_EnableDebugger(void); 00163 00164 static uint8_t GUS_reset_reg = 0; 00165 00166 static inline uint8_t read_GF1_mapping_control(const unsigned int ch); 00167 00168 class GUSChannels { 00169 public: 00170 Bit32u WaveStart; 00171 Bit32u WaveEnd; 00172 Bit32u WaveAddr; 00173 Bit32u WaveAdd; 00174 Bit8u WaveCtrl; 00175 Bit16u WaveFreq; 00176 00177 Bit32u RampStart; 00178 Bit32u RampEnd; 00179 Bit32u RampVol; 00180 Bit32u RampAdd; 00181 00182 Bit8u RampRate; 00183 Bit8u RampCtrl; 00184 00185 Bit8u PanPot; 00186 Bit8u channum; 00187 Bit32u irqmask; 00188 Bit32u PanLeft; 00189 Bit32u PanRight; 00190 Bit32s VolLeft; 00191 Bit32s VolRight; 00192 00193 GUSChannels(Bit8u num) { 00194 channum = num; 00195 irqmask = 1u << num; 00196 WaveStart = 0; 00197 WaveEnd = 0; 00198 WaveAddr = 0; 00199 WaveAdd = 0; 00200 WaveFreq = 0; 00201 WaveCtrl = 3; 00202 RampRate = 0; 00203 RampStart = 0; 00204 RampEnd = 0; 00205 RampCtrl = 3; 00206 RampAdd = 0; 00207 RampVol = 0; 00208 VolLeft = 0; 00209 VolRight = 0; 00210 PanLeft = 0; 00211 PanRight = 0; 00212 PanPot = 0x7; 00213 } 00214 00215 INLINE Bit32s LoadSample8(const Bit32u addr/*memory address without fractional bits*/) const { 00216 return (Bit8s)GUSRam[addr & 0xFFFFFu/*1MB*/] << Bit32s(8); /* typecast to sign extend 8-bit value */ 00217 } 00218 00219 INLINE Bit32s LoadSample16(const Bit32u addr/*memory address without fractional bits*/) const { 00220 const Bit32u adjaddr = (addr & 0xC0000u/*256KB bank*/) | ((addr & 0x1FFFFu) << 1u/*16-bit sample value within bank*/); 00221 return (Bit16s)host_readw(GUSRam + adjaddr);/* typecast to sign extend 16-bit value */ 00222 } 00223 00224 // Returns a single 16-bit sample from the Gravis's RAM 00225 INLINE Bit32s GetSample8() const { 00226 /* LoadSample*() will take care of wrapping to 1MB */ 00227 const Bit32u useAddr = WaveAddr >> WAVE_FRACT; 00228 { 00229 // Interpolate 00230 Bit32s w1 = LoadSample8(useAddr); 00231 Bit32s w2 = LoadSample8(useAddr + 1u); 00232 Bit32s diff = w2 - w1; 00233 Bit32s scale = (Bit32s)(WaveAddr & WAVE_FRACT_MASK); 00234 return (w1 + ((diff * scale) >> WAVE_FRACT)); 00235 } 00236 } 00237 00238 INLINE Bit32s GetSample16() const { 00239 /* Load Sample*() will take care of wrapping to 1MB and funky bank/sample conversion */ 00240 const Bit32u useAddr = WaveAddr >> WAVE_FRACT; 00241 { 00242 // Interpolate 00243 Bit32s w1 = LoadSample16(useAddr); 00244 Bit32s w2 = LoadSample16(useAddr + 1u); 00245 Bit32s diff = w2 - w1; 00246 Bit32s scale = (Bit32s)(WaveAddr & WAVE_FRACT_MASK); 00247 return (w1 + ((diff * scale) >> WAVE_FRACT)); 00248 } 00249 } 00250 00251 void WriteWaveFreq(Bit16u val) { 00252 WaveFreq = val; 00253 if (myGUS.fixed_sample_rate_output) { 00254 double frameadd = double(val >> 1)/512.0; //Samples / original gus frame 00255 double realadd = (frameadd*(double)myGUS.basefreq/(double)GUS_RATE) * (double)(1 << WAVE_FRACT); 00256 WaveAdd = (Bit32u)realadd; 00257 } 00258 else { 00259 WaveAdd = ((Bit32u)(val >> 1)) << ((Bit32u)(WAVE_FRACT-9)); 00260 } 00261 } 00262 void WriteWaveCtrl(Bit8u val) { 00263 Bit32u oldirq=myGUS.WaveIRQ; 00264 WaveCtrl = val & 0x7f; 00265 00266 if ((val & 0xa0)==0xa0) myGUS.WaveIRQ|=irqmask; 00267 else myGUS.WaveIRQ&=~irqmask; 00268 00269 if (oldirq != myGUS.WaveIRQ) 00270 CheckVoiceIrq(); 00271 } 00272 INLINE Bit8u ReadWaveCtrl(void) { 00273 Bit8u ret=WaveCtrl; 00274 if (myGUS.WaveIRQ & irqmask) ret|=0x80; 00275 return ret; 00276 } 00277 void UpdateWaveRamp(void) { 00278 WriteWaveFreq(WaveFreq); 00279 WriteRampRate(RampRate); 00280 } 00281 void WritePanPot(Bit8u val) { 00282 PanPot = val; 00283 PanLeft = pantable[val & 0xf]; 00284 PanRight = pantable[0x0f-(val & 0xf)]; 00285 UpdateVolumes(); 00286 } 00287 Bit8u ReadPanPot(void) { 00288 return PanPot; 00289 } 00290 void WriteRampCtrl(Bit8u val) { 00291 Bit32u old=myGUS.RampIRQ; 00292 RampCtrl = val & 0x7f; 00293 //Manually set the irq 00294 if ((val & 0xa0) == 0xa0) 00295 myGUS.RampIRQ |= irqmask; 00296 else 00297 myGUS.RampIRQ &= ~irqmask; 00298 if (old != myGUS.RampIRQ) 00299 CheckVoiceIrq(); 00300 } 00301 INLINE Bit8u ReadRampCtrl(void) { 00302 Bit8u ret=RampCtrl; 00303 if (myGUS.RampIRQ & irqmask) ret|=0x80; 00304 return ret; 00305 } 00306 void WriteRampRate(Bit8u val) { 00307 RampRate = val; 00308 if (myGUS.fixed_sample_rate_output) { 00309 double frameadd = (double)(RampRate & 63)/(double)(1 << (3*(val >> 6))); 00310 double realadd = (frameadd*(double)myGUS.basefreq/(double)GUS_RATE) * (double)(1 << RAMP_FRACT); 00311 RampAdd = (Bit32u)realadd; 00312 } 00313 else { 00314 /* NTS: Note RAMP_FRACT == 10, shift = 10 - (3*(val>>6)). 00315 * From the upper two bits, the possible shift values for 0, 1, 2, 3 are: 10, 7, 4, 1 */ 00316 RampAdd = ((Bit32u)(RampRate & 63)) << ((Bit32u)(RAMP_FRACT - (3*(val >> 6)))); 00317 #if 0//SET TO 1 TO CHECK YOUR MATH! 00318 double frameadd = (double)(RampRate & 63)/(double)(1 << (3*(val >> 6))); 00319 double realadd = frameadd * (double)(1 << RAMP_FRACT); 00320 Bit32u checkadd = (Bit32u)realadd; 00321 signed long error = (signed long)checkadd - (signed long)RampAdd; 00322 00323 if (error < -1L || error > 1L) 00324 LOG_MSG("RampAdd nonfixed error %ld (%lu != %lu)",error,(unsigned long)checkadd,(unsigned long)RampAdd); 00325 #endif 00326 } 00327 } 00328 INLINE void WaveUpdate(void) { 00329 bool endcondition; 00330 00331 if ((WaveCtrl & (WCTRL_STOP | WCTRL_STOPPED)) == 0/*voice is running*/) { 00332 /* NTS: WaveAddr and WaveAdd are unsigned. 00333 * If WaveAddr <= WaveAdd going backwards, WaveAddr becomes negative, which as an unsigned integer, 00334 * means carrying down from the highest possible value of the integer type. Which means that if the 00335 * start position is less than WaveAdd the WaveAddr will skip over the start pointer and continue 00336 * playing downward from the top of the GUS memory, without stopping/looping as expected. 00337 * 00338 * This "bug" was implemented on purpose because real Gravis Ultrasound hardware acts this way. */ 00339 Bit32u WaveExtra = 0; 00340 if (WaveCtrl & WCTRL_DECREASING/*backwards (direction)*/) { 00341 /* unsigned int subtract, mask, compare. will miss start pointer if WaveStart <= WaveAdd. 00342 * This bug is deliberate, accurate to real GUS hardware, do not fix. */ 00343 WaveAddr -= WaveAdd; 00344 WaveAddr &= ((Bitu)1 << ((Bitu)WAVE_FRACT + (Bitu)20/*1MB*/)) - 1; 00345 endcondition = (WaveAddr < WaveStart)?true:false; 00346 if (endcondition) WaveExtra = WaveStart - WaveAddr; 00347 } 00348 else { 00349 WaveAddr += WaveAdd; 00350 endcondition = (WaveAddr > WaveEnd)?true:false; 00351 WaveAddr &= ((Bitu)1 << ((Bitu)WAVE_FRACT + (Bitu)20/*1MB*/)) - 1; 00352 if (endcondition) WaveExtra = WaveAddr - WaveEnd; 00353 } 00354 00355 if (endcondition) { 00356 if (WaveCtrl & WCTRL_IRQENABLED) /* generate an IRQ if requested */ 00357 myGUS.WaveIRQ |= irqmask; 00358 00359 if ((RampCtrl & WCTRL_16BIT/*roll over*/) && !(WaveCtrl & WCTRL_LOOP)) { 00360 /* "3.11. Rollover feature 00361 * 00362 * Each voice has a 'rollover' feature that allows an application to be notified when a voice's playback position passes 00363 * over a particular place in DRAM. This is very useful for getting seamless digital audio playback. Basically, the GF1 00364 * will generate an IRQ when a voice's current position is equal to the end position. However, instead of stopping or 00365 * looping back to the start position, the voice will continue playing in the same direction. This means that there will be 00366 * no pause (or gap) in the playback. Note that this feature is enabled/disabled through the voice's VOLUME control 00367 * register (since there are no more bits available in the voice control registers). A voice's loop enable bit takes 00368 * precedence over the rollover. This means that if a voice's loop enable is on, it will loop when it hits the end position, 00369 * regardless of the state of the rollover enable." 00370 * 00371 * Despite the confusing description above, that means that looping takes precedence over rollover. If not looping, then 00372 * rollover means to fire the IRQ but keep moving. If looping, then fire IRQ and carry out loop behavior. Gravis Ultrasound 00373 * Windows 3.1 drivers expect this behavior, else Windows WAVE output will not work correctly. */ 00374 } 00375 else { 00376 if (WaveCtrl & WCTRL_LOOP) { 00377 if (WaveCtrl & WCTRL_BIDIRECTIONAL) WaveCtrl ^= WCTRL_DECREASING/*change direction*/; 00378 WaveAddr = (WaveCtrl & WCTRL_DECREASING) ? (WaveEnd - WaveExtra) : (WaveStart + WaveExtra); 00379 } else { 00380 WaveCtrl |= 1; /* stop the channel */ 00381 WaveAddr = (WaveCtrl & WCTRL_DECREASING) ? WaveStart : WaveEnd; 00382 } 00383 } 00384 } 00385 } 00386 else if (WaveCtrl & WCTRL_IRQENABLED) { 00387 /* Undocumented behavior observed on real GUS hardware: A stopped voice will still rapid-fire IRQs 00388 * if IRQ enabled and current position <= start position OR current position >= end position */ 00389 if (WaveCtrl & WCTRL_DECREASING/*backwards (direction)*/) 00390 endcondition = (WaveAddr <= WaveStart)?true:false; 00391 else 00392 endcondition = (WaveAddr >= WaveEnd)?true:false; 00393 00394 if (endcondition) 00395 myGUS.WaveIRQ |= irqmask; 00396 } 00397 } 00398 INLINE void UpdateVolumes(void) { 00399 Bit32s templeft=(Bit32s)RampVol - (Bit32s)PanLeft; 00400 templeft&=~(templeft >> 31); /* <- NTS: This is a rather elaborate way to clamp negative values to zero using negate and sign extend */ 00401 Bit32s tempright=(Bit32s)RampVol - (Bit32s)PanRight; 00402 tempright&=~(tempright >> 31); /* <- NTS: This is a rather elaborate way to clamp negative values to zero using negate and sign extend */ 00403 VolLeft=vol16bit[templeft >> RAMP_FRACT]; 00404 VolRight=vol16bit[tempright >> RAMP_FRACT]; 00405 } 00406 INLINE void RampUpdate(void) { 00407 if (RampCtrl & 0x3) return; /* if the ramping is turned off, then don't change the ramp */ 00408 00409 Bit32s RampLeft; 00410 if (RampCtrl & 0x40) { 00411 RampVol-=RampAdd; 00412 if ((Bit32s)RampVol < (Bit32s)0) RampVol=0; 00413 RampLeft=(Bit32s)RampStart-(Bit32s)RampVol; 00414 } else { 00415 RampVol+=RampAdd; 00416 if (RampVol > ((4096 << RAMP_FRACT)-1)) RampVol=((4096 << RAMP_FRACT)-1); 00417 RampLeft=(Bit32s)RampVol-(Bit32s)RampEnd; 00418 } 00419 if (RampLeft<0) { 00420 UpdateVolumes(); 00421 return; 00422 } 00423 /* Generate an IRQ if needed */ 00424 if (RampCtrl & 0x20) { 00425 myGUS.RampIRQ|=irqmask; 00426 } 00427 /* Check for looping */ 00428 if (RampCtrl & 0x08) { 00429 /* Bi-directional looping */ 00430 if (RampCtrl & 0x10) RampCtrl^=0x40; 00431 RampVol = (RampCtrl & 0x40) ? (Bit32u)((Bit32s)RampEnd-(Bit32s)RampLeft) : (Bit32u)((Bit32s)RampStart+(Bit32s)RampLeft); 00432 } else { 00433 RampCtrl|=1; //Stop the channel 00434 RampVol = (RampCtrl & 0x40) ? RampStart : RampEnd; 00435 } 00436 if ((Bit32s)RampVol < (Bit32s)0) RampVol=0; 00437 if (RampVol > ((4096 << RAMP_FRACT)-1)) RampVol=((4096 << RAMP_FRACT)-1); 00438 UpdateVolumes(); 00439 } 00440 00441 void generateSamples(Bit32s* stream, Bit32u len) { 00442 Bit32s tmpsamp; 00443 int i; 00444 00445 /* NTS: The GUS is *always* rendering the audio sample at the current position, 00446 * even if the voice is stopped. This can be confirmed using DOSLIB, loading 00447 * the Ultrasound test program, loading a WAV file into memory, then using 00448 * the Ultrasound test program's voice control dialog to single-step the 00449 * voice through RAM (abruptly change the current position) while the voice 00450 * is stopped. You will hear "popping" noises come out the GUS audio output 00451 * as the current position changes and the piece of the sample rendered 00452 * abruptly changes as well. */ 00453 if (gus_ics_mixer) { 00454 const unsigned char Lc = read_GF1_mapping_control(0); 00455 const unsigned char Rc = read_GF1_mapping_control(1); 00456 00457 // output mapped through ICS mixer including channel remapping 00458 for (i = 0; i < (int)len; i++) { 00459 // Get sample 00460 if (WaveCtrl & WCTRL_16BIT) 00461 tmpsamp = GetSample16(); 00462 else 00463 tmpsamp = GetSample8(); 00464 // Output stereo sample if DAC enable on 00465 if ((GUS_reset_reg & 0x02/*DAC enable*/) == 0x02) { 00466 Bit32s* const sp = stream + (i << 1); 00467 const Bit32s L = tmpsamp * VolLeft; 00468 const Bit32s R = tmpsamp * VolRight; 00469 00470 if (Lc & 1) sp[0] += L; 00471 if (Lc & 2) sp[1] += L; 00472 if (Rc & 1) sp[0] += R; 00473 if (Rc & 2) sp[1] += R; 00474 00475 WaveUpdate(); 00476 RampUpdate(); 00477 } 00478 } 00479 } 00480 else { 00481 // normal output 00482 for (i = 0; i < (int)len; i++) { 00483 // Get sample 00484 if (WaveCtrl & WCTRL_16BIT) 00485 tmpsamp = GetSample16(); 00486 else 00487 tmpsamp = GetSample8(); 00488 00489 // Output stereo sample if DAC enable on 00490 if ((GUS_reset_reg & 0x02/*DAC enable*/) == 0x02) { 00491 stream[i << 1] += tmpsamp * VolLeft; 00492 stream[(i << 1) + 1] += tmpsamp * VolRight; 00493 00494 WaveUpdate(); 00495 RampUpdate(); 00496 } 00497 } 00498 } 00499 } 00500 }; 00501 00502 static GUSChannels *guschan[32] = {NULL}; 00503 static GUSChannels *curchan = NULL; 00504 00505 static INLINE void GUS_CheckIRQ(void); 00506 00507 static void GUS_TimerEvent(Bitu val); 00508 00509 static void GUS_DMA_Callback(DmaChannel * chan,DMAEvent event); 00510 00511 void GUS_StopDMA(); 00512 void GUS_StartDMA(); 00513 void GUS_Update_DMA_Event_transfer(); 00514 00515 static void GUSReset(void) { 00516 unsigned char p_GUS_reset_reg = GUS_reset_reg; 00517 00518 /* NTS: From the Ultrasound SDK: 00519 * 00520 * Global Data Low (3X4) is either a 16-bit transfer, or the low half of a 16-bit transfer with 8-bit I/O. 00521 * 00522 * Global Data High (3X5) is either an 8-bit transfer for one of the GF registers or the high part of a 16-bit wide register with 8-bit I/O. 00523 * 00524 * Prior to 2015/12/29 DOSBox and DOSBox-X contained a programming error here where reset and master IRQ enable were handled from the 00525 * LOWER 8 bits, when the code should have been checking the UPPER 8 bits. Programming error #2 was the mis-interpetation of bit 0 (bit 8 of 00526 * the gRegData). According to the SDK, clearing bit 0 triggers RESET, setting bit 0 starts the card running again. The original code had 00527 * it backwards. */ 00528 GUS_reset_reg = (myGUS.gRegData >> 8) & 7; 00529 00530 if ((myGUS.gRegData & 0x400) != 0x000 || myGUS.force_master_irq_enable) 00531 myGUS.irqenabled = true; 00532 else 00533 myGUS.irqenabled = false; 00534 00535 if (GUS_reset_reg ^ p_GUS_reset_reg) 00536 LOG(LOG_MISC,LOG_DEBUG)("GUS reset with 0x%04X",myGUS.gRegData); 00537 00538 if ((myGUS.gRegData & 0x100) == 0x000) { 00539 // Stop all channels 00540 int i; 00541 for(i=0;i<32;i++) { 00542 guschan[i]->RampVol=0; 00543 guschan[i]->WriteWaveCtrl(0x1); 00544 guschan[i]->WriteRampCtrl(0x1); 00545 guschan[i]->WritePanPot(0x7); 00546 } 00547 00548 // Stop DMA 00549 GUS_StopDMA(); 00550 00551 // Reset 00552 adlib_commandreg = 85; 00553 myGUS.IRQStatus = 0; 00554 myGUS.RampIRQ = 0; 00555 myGUS.WaveIRQ = 0; 00556 myGUS.IRQChan = 0; 00557 00558 myGUS.timers[0].delay = 0.080f; 00559 myGUS.timers[1].delay = 0.320f; 00560 myGUS.timers[0].value = 0xff; 00561 myGUS.timers[1].value = 0xff; 00562 myGUS.timers[0].masked = false; 00563 myGUS.timers[1].masked = false; 00564 myGUS.timers[0].raiseirq = false; 00565 myGUS.timers[1].raiseirq = false; 00566 myGUS.timers[0].reached = true; 00567 myGUS.timers[1].reached = true; 00568 myGUS.timers[0].running = false; 00569 myGUS.timers[1].running = false; 00570 00571 PIC_RemoveEvents(GUS_TimerEvent); 00572 00573 myGUS.ChangeIRQDMA = false; 00574 myGUS.DMAControl = 0x00; 00575 myGUS.mixControl = 0x0b; // latches enabled by default LINEs disabled 00576 myGUS.TimerControl = 0x00; 00577 myGUS.SampControl = 0x00; 00578 myGUS.ActiveChannels = 14; 00579 myGUS.ActiveChannelsUser = 14; 00580 myGUS.ActiveMask=0xffffffffU >> (32-myGUS.ActiveChannels); 00581 myGUS.basefreq = (Bit32u)((float)1000000/(1.619695497*(float)(myGUS.ActiveChannels))); 00582 00583 gus_chan->FillUp(); 00584 if (!myGUS.fixed_sample_rate_output) gus_chan->SetFreq(myGUS.basefreq); 00585 else gus_chan->SetFreq(GUS_RATE); 00586 00587 myGUS.gCurChannel = 0; 00588 curchan = guschan[myGUS.gCurChannel]; 00589 00590 myGUS.dmaAddr = 0; 00591 myGUS.irqenabled = 0; 00592 myGUS.gRegControl = 0; 00593 myGUS.dmaAddrOffset = 0; 00594 myGUS.gDramAddr = 0; 00595 myGUS.gRegData = 0; 00596 00597 GUS_Update_DMA_Event_transfer(); 00598 } 00599 00600 /* if the card was just put into reset, or the card WAS in reset, bits 1-2 are cleared */ 00601 if ((GUS_reset_reg & 1) == 0 || (p_GUS_reset_reg & 1) == 0) { 00602 /* GUS classic observed behavior: resetting the card, or even coming out of reset, clears bits 1-2. 00603 * That means, if you write any value to GUS RESET with bit 0 == 0, bits 1-2 become zero as well. 00604 * And if you take the card out of reset, bits 1-2 are zeroed. 00605 * 00606 * test 1: 00607 * outb(0x3X3,0x4C); outb(0x3X5,0x00); 00608 * outb(0x3X3,0x4C); c = inb(0x3X5); <- you'll get 0x00 as expected 00609 * outb(0x3X3,0x4C); outb(0x3X5,0x07); 00610 * outb(0x3X3,0x4C); c = inb(0x3X5); <- you'll get 0x01, not 0x07 00611 * 00612 * test 2: 00613 * outb(0x3X3,0x4C); outb(0x3X5,0x00); 00614 * outb(0x3X3,0x4C); c = inb(0x3X5); <- you'll get 0x00 as expected 00615 * outb(0x3X3,0x4C); outb(0x3X5,0x01); 00616 * outb(0x3X3,0x4C); c = inb(0x3X5); <- you'll get 0x01 as expected, card taken out of reset 00617 * outb(0x3X3,0x4C); outb(0x3X5,0x07); 00618 * outb(0x3X3,0x4C); c = inb(0x3X5); <- you'll get 0x07 as expected 00619 * outb(0x3X3,0x4C); outb(0x3X5,0x06); <- bit 0 == 0, we're trying to set bits 1-2 00620 * outb(0x3X3,0x4C); c = inb(0x3X5); <- you'll get 0x00, not 0x06, card is in reset state */ 00621 myGUS.irqenabled = myGUS.force_master_irq_enable; // IRQ enable resets, unless user specified we force it on 00622 GUS_reset_reg &= 1; 00623 } 00624 00625 GUS_CheckIRQ(); 00626 } 00627 00628 static uint8_t GUS_EffectiveIRQStatus(void) { 00629 uint8_t ret = 0; 00630 00631 /* Behavior observed on real GUS hardware: Master IRQ enable bit 2 of the reset register affects only voice/wave 00632 * IRQ signals from the GF1. It does not affect the DMA terminal count interrupt nor does it affect the Adlib timers. 00633 * This is how "Juice" by Psychic Link is able to play music by GUS timer even though the demo never enables the 00634 * Master IRQ Enable bit. */ 00635 00636 /* DMA */ 00637 if (myGUS.DMAControl & 0x20/*DMA IRQ Enable*/) 00638 ret |= (myGUS.IRQStatus & 0x80/*DMA TC IRQ*/); 00639 00640 /* Timer 1 & 2 */ 00641 ret |= (myGUS.IRQStatus/*Timer 1&2 IRQ*/ & myGUS.TimerControl/*Timer 1&2 IRQ Enable*/ & 0x0C); 00642 00643 /* Voice IRQ */ 00644 if (myGUS.irqenabled) 00645 ret |= (myGUS.IRQStatus & 0x60/*Wave/Ramp IRQ*/); 00646 00647 /* TODO: MIDI IRQ? */ 00648 00649 return ret; 00650 } 00651 00652 static uint8_t gus_prev_effective_irqstat = 0; 00653 00654 static INLINE void GUS_CheckIRQ(void) { 00655 if (myGUS.mixControl & 0x08/*Enable latches*/) { 00656 uint8_t irqstat = GUS_EffectiveIRQStatus(); 00657 00658 if (irqstat != 0) { 00659 /* The GUS fires an IRQ, then waits for the interrupt service routine to 00660 * clear all pending interrupt events before firing another one. if you 00661 * don't service all events, then you don't get another interrupt. */ 00662 if (gus_prev_effective_irqstat == 0) { 00663 PIC_ActivateIRQ(myGUS.irq1); 00664 00665 if (gus_warn_irq_conflict) 00666 LOG(LOG_MISC,LOG_WARN)( 00667 "GUS warning: Both IRQs set to the same signal line WITHOUT combining! " 00668 "This is documented to cause bus conflicts on real hardware"); 00669 } 00670 } 00671 00672 gus_prev_effective_irqstat = irqstat; 00673 } 00674 } 00675 00676 static void CheckVoiceIrq(void) { 00677 Bitu totalmask=(myGUS.RampIRQ|myGUS.WaveIRQ) & myGUS.ActiveMask; 00678 if (!totalmask) { 00679 GUS_CheckIRQ(); 00680 return; 00681 } 00682 00683 if (myGUS.RampIRQ) myGUS.IRQStatus|=0x40; 00684 if (myGUS.WaveIRQ) myGUS.IRQStatus|=0x20; 00685 GUS_CheckIRQ(); 00686 for (;;) { 00687 Bit32u check=(1u << myGUS.IRQChan); 00688 if (totalmask & check) return; 00689 myGUS.IRQChan++; 00690 if (myGUS.IRQChan>=myGUS.ActiveChannels) myGUS.IRQChan=0; 00691 } 00692 } 00693 00694 static Bit16u ExecuteReadRegister(void) { 00695 Bit8u tmpreg; 00696 // LOG_MSG("Read global reg %x",myGUS.gRegSelect); 00697 switch (myGUS.gRegSelect) { 00698 case 0x8E: // read active channel register 00699 // NTS: The GUS SDK documents the active channel count as bits 5-0, which is wrong. it's bits 4-0. bits 7-5 are always 1 on real hardware. 00700 return ((Bit16u)(0xE0 | (myGUS.ActiveChannelsUser - 1))) << 8; 00701 case 0x41: // Dma control register - read acknowledges DMA IRQ 00702 if (dma_enable_on_dma_control_polling) { 00703 if (!GetDMAChannel(myGUS.dma1)->masked && !(myGUS.DMAControl & 0x01) && !(myGUS.IRQStatus & 0x80)) { 00704 LOG(LOG_MISC,LOG_DEBUG)("GUS: As instructed, switching on DMA ENABLE upon polling DMA control register (HACK) as workaround"); 00705 myGUS.DMAControl |= 0x01; 00706 GUS_StartDMA(); 00707 } 00708 } 00709 00710 tmpreg = myGUS.DMAControl & 0xbf; 00711 tmpreg |= (myGUS.IRQStatus & 0x80) >> 1; 00712 myGUS.IRQStatus&=0x7f; 00713 GUS_CheckIRQ(); 00714 return (Bit16u)(tmpreg << 8); 00715 case 0x42: // Dma address register 00716 return myGUS.dmaAddr; 00717 case 0x45: // Timer control register. Identical in operation to Adlib's timer 00718 return (Bit16u)(myGUS.TimerControl << 8); 00719 break; 00720 case 0x49: // Dma sample register 00721 tmpreg = myGUS.DMAControl & 0xbf; 00722 tmpreg |= (myGUS.IRQStatus & 0x80) >> 1; 00723 return (Bit16u)(tmpreg << 8); 00724 case 0x4c: // GUS reset register 00725 tmpreg = (GUS_reset_reg & ~0x4) | (myGUS.irqenabled ? 0x4 : 0x0); 00726 /* GUS Classic observed behavior: You can read Register 4Ch from both 3X4 and 3X5 and get the same 8-bit contents */ 00727 return ((Bit16u)(tmpreg << 8) | (Bit16u)tmpreg); 00728 case 0x80: // Channel voice control read register 00729 if (curchan) return curchan->ReadWaveCtrl() << 8; 00730 else return 0x0300; 00731 case 0x81: // Channel frequency control register 00732 if(curchan) return (Bit16u)(curchan->WaveFreq); 00733 else return 0x0000; 00734 case 0x82: // Channel MSB start address register 00735 if (curchan) return (Bit16u)(curchan->WaveStart >> 16); 00736 else return 0x0000; 00737 case 0x83: // Channel LSW start address register 00738 if (curchan) return (Bit16u)(curchan->WaveStart); 00739 else return 0x0000; 00740 case 0x84: // Channel MSB end address register 00741 if (curchan) return (Bit16u)(curchan->WaveEnd >> 16); 00742 else return 0x0000; 00743 case 0x85: // Channel LSW end address register 00744 if (curchan) return (Bit16u)(curchan->WaveEnd); 00745 else return 0x0000; 00746 00747 case 0x89: // Channel volume register 00748 if (curchan) return (Bit16u)((curchan->RampVol >> RAMP_FRACT) << 4); 00749 else return 0x0000; 00750 case 0x8a: // Channel MSB current address register 00751 if (curchan) return (Bit16u)(curchan->WaveAddr >> 16); 00752 else return 0x0000; 00753 case 0x8b: // Channel LSW current address register 00754 if (curchan) return (Bit16u)(curchan->WaveAddr); 00755 else return 0x0000; 00756 case 0x8c: // Channel pan pot register 00757 if (curchan) return (Bit16u)(curchan->PanPot << 8); 00758 else return 0x0800; 00759 case 0x8d: // Channel volume control register 00760 if (curchan) return curchan->ReadRampCtrl() << 8; 00761 else return 0x0300; 00762 case 0x8f: // General channel IRQ status register 00763 tmpreg=myGUS.IRQChan|0x20; 00764 Bit32u mask; 00765 mask=1u << myGUS.IRQChan; 00766 if (!(myGUS.RampIRQ & mask)) tmpreg|=0x40; 00767 if (!(myGUS.WaveIRQ & mask)) tmpreg|=0x80; 00768 myGUS.RampIRQ&=~mask; 00769 myGUS.WaveIRQ&=~mask; 00770 myGUS.IRQStatus&=0x9f; 00771 CheckVoiceIrq(); 00772 return (Bit16u)(tmpreg << 8); 00773 default: 00774 #if LOG_GUS 00775 LOG_MSG("Read Register num 0x%x", myGUS.gRegSelect); 00776 #endif 00777 return myGUS.gRegData; 00778 } 00779 } 00780 00781 static void GUS_TimerEvent(Bitu val) { 00782 if (!myGUS.timers[val].masked) myGUS.timers[val].reached=true; 00783 if (myGUS.timers[val].raiseirq) { 00784 myGUS.IRQStatus|=0x4 << val; 00785 GUS_CheckIRQ(); 00786 } 00787 if (myGUS.timers[val].running) 00788 PIC_AddEvent(GUS_TimerEvent,myGUS.timers[val].delay,val); 00789 } 00790 00791 00792 static void ExecuteGlobRegister(void) { 00793 int i; 00794 // if (myGUS.gRegSelect|1!=0x44) LOG_MSG("write global register %x with %x", myGUS.gRegSelect, myGUS.gRegData); 00795 switch(myGUS.gRegSelect) { 00796 case 0x0: // Channel voice control register 00797 gus_chan->FillUp(); 00798 if(curchan) curchan->WriteWaveCtrl((Bit16u)myGUS.gRegData>>8); 00799 break; 00800 case 0x1: // Channel frequency control register 00801 gus_chan->FillUp(); 00802 if(curchan) curchan->WriteWaveFreq(myGUS.gRegData); 00803 break; 00804 case 0x2: // Channel MSW start address register 00805 if (curchan) { 00806 Bit32u tmpaddr = (Bit32u)(myGUS.gRegData & 0x1fff) << 16; /* upper 13 bits of integer portion */ 00807 curchan->WaveStart = (curchan->WaveStart & WAVE_MSWMASK) | tmpaddr; 00808 } 00809 break; 00810 case 0x3: // Channel LSW start address register 00811 if(curchan != NULL) { 00812 Bit32u tmpaddr = (Bit32u)(myGUS.gRegData & 0xffe0); /* lower 7 bits of integer portion, and all 4 bits of fractional portion. bits 4-0 of the incoming 16-bit WORD are not used */ 00813 curchan->WaveStart = (curchan->WaveStart & WAVE_LSWMASK) | tmpaddr; 00814 } 00815 break; 00816 case 0x4: // Channel MSW end address register 00817 if(curchan != NULL) { 00818 Bit32u tmpaddr = (Bit32u)(myGUS.gRegData & 0x1fff) << 16; /* upper 13 bits of integer portion */ 00819 curchan->WaveEnd = (curchan->WaveEnd & WAVE_MSWMASK) | tmpaddr; 00820 } 00821 break; 00822 case 0x5: // Channel MSW end address register 00823 if(curchan != NULL) { 00824 Bit32u tmpaddr = (Bit32u)(myGUS.gRegData & 0xffe0); /* lower 7 bits of integer portion, and all 4 bits of fractional portion. bits 4-0 of the incoming 16-bit WORD are not used */ 00825 curchan->WaveEnd = (curchan->WaveEnd & WAVE_LSWMASK) | tmpaddr; 00826 } 00827 break; 00828 case 0x6: // Channel volume ramp rate register 00829 gus_chan->FillUp(); 00830 if(curchan != NULL) { 00831 Bit8u tmpdata = (Bit16u)myGUS.gRegData>>8; 00832 curchan->WriteRampRate(tmpdata); 00833 } 00834 break; 00835 case 0x7: // Channel volume ramp start register EEEEMMMM 00836 if(curchan != NULL) { 00837 Bit8u tmpdata = (Bit16u)myGUS.gRegData >> 8; 00838 curchan->RampStart = (Bit32u)(tmpdata << (4+RAMP_FRACT)); 00839 } 00840 break; 00841 case 0x8: // Channel volume ramp end register EEEEMMMM 00842 if(curchan != NULL) { 00843 Bit8u tmpdata = (Bit16u)myGUS.gRegData >> 8; 00844 curchan->RampEnd = (Bit32u)(tmpdata << (4+RAMP_FRACT)); 00845 } 00846 break; 00847 case 0x9: // Channel current volume register 00848 gus_chan->FillUp(); 00849 if(curchan != NULL) { 00850 Bit16u tmpdata = (Bit16u)myGUS.gRegData >> 4; 00851 curchan->RampVol = (Bit32u)(tmpdata << RAMP_FRACT); 00852 curchan->UpdateVolumes(); 00853 } 00854 break; 00855 case 0xA: // Channel MSW current address register 00856 gus_chan->FillUp(); 00857 if(curchan != NULL) { 00858 Bit32u tmpaddr = (Bit32u)(myGUS.gRegData & 0x1fff) << 16; /* upper 13 bits of integer portion */ 00859 curchan->WaveAddr = (curchan->WaveAddr & WAVE_MSWMASK) | tmpaddr; 00860 } 00861 break; 00862 case 0xB: // Channel LSW current address register 00863 gus_chan->FillUp(); 00864 if(curchan != NULL) { 00865 Bit32u tmpaddr = (Bit32u)(myGUS.gRegData & 0xffff); /* lower 7 bits of integer portion, and all 9 bits of fractional portion */ 00866 curchan->WaveAddr = (curchan->WaveAddr & WAVE_LSWMASK) | tmpaddr; 00867 } 00868 break; 00869 case 0xC: // Channel pan pot register 00870 gus_chan->FillUp(); 00871 if(curchan) curchan->WritePanPot((Bit16u)myGUS.gRegData>>8); 00872 break; 00873 case 0xD: // Channel volume control register 00874 gus_chan->FillUp(); 00875 if(curchan) curchan->WriteRampCtrl((Bit16u)myGUS.gRegData>>8); 00876 break; 00877 case 0xE: // Set active channel register 00878 /* Hack for "Ice Fever" demoscene production: 00879 * If the DAC is active (bit 1 of GUS reset is set), ignore writes to this register. 00880 * The demo resets the GUS with 14 channels, then after reset changes it to 16 for some reason. 00881 * Without this hack, music will sound slowed down and wrong. 00882 * As far as I know, real hardware will accept the change immediately and produce the same 00883 * slowed down sound music. --J.C. */ 00884 if (ignore_active_channel_write_while_active) { 00885 if (GUS_reset_reg & 0x02/*DAC enable*/) { 00886 LOG_MSG("GUS: Attempt to change active channel count while DAC active rejected"); 00887 break; 00888 } 00889 } 00890 00891 gus_chan->FillUp(); 00892 myGUS.gRegSelect = myGUS.gRegData>>8; //JAZZ Jackrabbit seems to assume this? 00893 myGUS.ActiveChannelsUser = 1+((myGUS.gRegData>>8) & 31); // NTS: The GUS SDK documents this field as bits 5-0, which is wrong, it's bits 4-0. 5-0 would imply 64 channels. 00894 00895 /* The GUS SDK claims that if a channel count less than 14 is written, then it caps to 14. 00896 * That's not true. Perhaps what the SDK is doing, but the actual hardware acts differently. 00897 * This implementation is based on what the Gravis Ultrasound MAX actually does with this 00898 * register. You can apparently achieve higher than 44.1KHz sample rates by programming less 00899 * than 14 channels, and the sample rate scale ramps up appropriately, except that values 00900 * 0 and 1 have the same effect as writing 2 and 3. Very useful undocumented behavior! 00901 * If Gravis were smart, they would have been able to claim 48KHz sample rates by allowing 00902 * less than 14 channels in their SDK! Not sure why they would cap it like that, unless 00903 * there are undocumented chipset instabilities with running at higher rates. 00904 * 00905 * So far only verified on a Gravis Ultrasound MAX. 00906 * 00907 * Does anyone out there have a Gravis Ultrasound Classic (original 1992 version) they can 00908 * test for this behavior? 00909 * 00910 * NOTED: Gravis Ultrasound Plug & Play (interwave) cards *do* enforce the 14-channel minimum. 00911 * You can write less than 14 channels to this register, but unlike the Classic and Max 00912 * cards they will not run faster than 44.1KHz. */ 00913 myGUS.ActiveChannels = myGUS.ActiveChannelsUser; 00914 00915 if (gus_type < GUS_INTERWAVE) { 00916 // GUS MAX behavior seen on real hardware 00917 if(myGUS.ActiveChannels < 3) myGUS.ActiveChannels += 2; 00918 if(myGUS.ActiveChannels > 32) myGUS.ActiveChannels = 32; 00919 } 00920 else { 00921 // Interwave PnP behavior seen on real hardware 00922 if(myGUS.ActiveChannels < 14) myGUS.ActiveChannels = 14; 00923 if(myGUS.ActiveChannels > 32) myGUS.ActiveChannels = 32; 00924 } 00925 00926 myGUS.ActiveMask=0xffffffffU >> (32-myGUS.ActiveChannels); 00927 myGUS.basefreq = (Bit32u)(0.5 + 1000000.0 / (1.619695497 * (double)(myGUS.ActiveChannels))); 00928 00929 if (!myGUS.fixed_sample_rate_output) gus_chan->SetFreq(myGUS.basefreq); 00930 else gus_chan->SetFreq(GUS_RATE); 00931 00932 #if LOG_GUS 00933 LOG_MSG("GUS set to %d channels fixed=%u freq=%luHz", myGUS.ActiveChannels,myGUS.fixed_sample_rate_output,(unsigned long)myGUS.basefreq); 00934 #endif 00935 for (i=0;i<myGUS.ActiveChannels;i++) guschan[i]->UpdateWaveRamp(); 00936 break; 00937 case 0x10: // Undocumented register used in Fast Tracker 2 00938 break; 00939 case 0x41: // Dma control register 00940 myGUS.DMAControl = (Bit8u)(myGUS.gRegData>>8); 00941 GUS_Update_DMA_Event_transfer(); 00942 if (myGUS.DMAControl & 1) GUS_StartDMA(); 00943 else GUS_StopDMA(); 00944 break; 00945 case 0x42: // Gravis DRAM DMA address register 00946 myGUS.dmaAddr = myGUS.gRegData; 00947 myGUS.dmaAddrOffset = 0; 00948 break; 00949 case 0x43: // LSB Peek/poke DRAM position 00950 myGUS.gDramAddr = (0xff0000 & myGUS.gDramAddr) | ((Bit32u)myGUS.gRegData); 00951 break; 00952 case 0x44: // MSW Peek/poke DRAM position 00953 myGUS.gDramAddr = (0xffff & myGUS.gDramAddr) | ((Bit32u)myGUS.gRegData>>8) << 16; 00954 break; 00955 case 0x45: // Timer control register. Identical in operation to Adlib's timer 00956 myGUS.TimerControl = (Bit8u)(myGUS.gRegData>>8); 00957 myGUS.timers[0].raiseirq=(myGUS.TimerControl & 0x04)>0; 00958 if (!myGUS.timers[0].raiseirq) myGUS.IRQStatus&=~0x04; 00959 myGUS.timers[1].raiseirq=(myGUS.TimerControl & 0x08)>0; 00960 if (!myGUS.timers[1].raiseirq) myGUS.IRQStatus&=~0x08; 00961 GUS_CheckIRQ(); 00962 break; 00963 case 0x46: // Timer 1 control 00964 myGUS.timers[0].value = (Bit8u)(myGUS.gRegData>>8); 00965 myGUS.timers[0].delay = (0x100 - myGUS.timers[0].value) * 0.080f; 00966 break; 00967 case 0x47: // Timer 2 control 00968 myGUS.timers[1].value = (Bit8u)(myGUS.gRegData>>8); 00969 myGUS.timers[1].delay = (0x100 - myGUS.timers[1].value) * 0.320f; 00970 break; 00971 case 0x49: // DMA sampling control register 00972 myGUS.SampControl = (Bit8u)(myGUS.gRegData>>8); 00973 if (myGUS.DMAControl & 1) GUS_StartDMA(); 00974 else GUS_StopDMA(); 00975 break; 00976 case 0x4c: // GUS reset register 00977 GUSReset(); 00978 break; 00979 default: 00980 #if LOG_GUS 00981 LOG_MSG("Unimplemented global register %x -- %x", myGUS.gRegSelect, myGUS.gRegData); 00982 #endif 00983 break; 00984 } 00985 return; 00986 } 00987 00988 /* Gravis Ultrasound ICS-2101 Digitally Controlled Audio Mixer emulation */ 00989 /* NTS: This was written and tested only through Ultrasound software and emulation. 00990 * I do not have a Gravis Ultrasound card with this type of mixer to test against. --J.C. */ 00991 struct gus_ICS2101 { 00992 public: 00993 // ICS2101 and how Gravis wired up the input pairs when using it, according to some BSD and Linux kernel sources 00994 // 00995 // From the header file: 00996 // 00997 // Register defs for Integrated Circuit Systems, Inc. ICS-2101 mixer 00998 // chip, used on Gravis UltraSound cards. 00999 // 01000 // Block diagram: 01001 // port # 01002 // 0 +----+ 01003 // Mic in (Right/Left) -->--->---| | 01004 // 1 | | amp --->---- amp out 01005 // Line in (Right/Left) -->--->---| | | 01006 // 2 | | | 01007 // CD in (Right/Left) -->--->---| |--->---+---+----->---- line out 01008 // 3 | | | 01009 // GF1 Out (Right/Left) -->--->---| | | 01010 // 4 | | | 01011 // Unused (Right/Left) -->--->---| | | 01012 // +----+ v 01013 // ICS 2101 | 01014 // | 01015 // To GF1 Sample Input ---<---------------+ 01016 // 01017 // Master output volume: mixer channel #5 01018 enum { 01019 MIC_IN_PORT=0, 01020 LINE_IN_PORT=1, 01021 CD_IN_PORT=2, 01022 GF1_OUT_PORT=3, 01023 UNUSED_PORT=4, 01024 MASTER_OUTPUT_PORT=5 01025 }; 01026 public: 01027 gus_ICS2101() { 01028 } 01029 public: 01030 void addressWrite(uint8_t addr) { 01031 addr_attenuator = (addr >> 3) & 7; 01032 addr_control = addr & 7; 01033 } 01034 void dataWrite(uint8_t val) { 01035 LOG(LOG_MISC,LOG_DEBUG)("GUS ICS-2101 Mixer Data Write val=%02xh to attensel=%u(%s) ctrlsel=%u(%s)", 01036 (int)val, 01037 addr_attenuator,attenuatorName(addr_attenuator), 01038 addr_control,controlName(addr_control)); 01039 01040 if (addr_control & 2) { // attenuator NTS: Only because an existing ICS patch for DOSBox does it this way... does hardware do it this way? 01041 mixpair[addr_attenuator].setAttenuation(addr_control&1,val); 01042 mixpair[addr_attenuator].debugPrintMixer(attenuatorName(addr_attenuator)); 01043 updateVolPair(addr_attenuator); 01044 } 01045 else if (addr_control & 4) { // pan/balance 01046 mixpair[addr_attenuator].Panning = val & 0xF; 01047 // FIXME: Does the panning take effect immediately, or does the chip require the DOS program 01048 // to write attenuation again to apply the panning? 01049 } 01050 else { 01051 mixpair[addr_attenuator].setControl(addr_control&1,val); 01052 } 01053 } 01054 const char *attenuatorName(const uint8_t c) const { 01055 switch (c) { 01056 case 0: return "Mic in"; 01057 case 1: return "Line in"; 01058 case 2: return "CD in"; 01059 case 3: return "GF1 out"; 01060 case 4: return "Pair 5, unused"; 01061 case 5: return "Master output"; 01062 } 01063 01064 return "?"; 01065 } 01066 const char *controlName(const uint8_t c) const { 01067 switch (c) { 01068 case 0: return "Control Left"; // 000 01069 case 1: return "Control Right"; // 001 01070 case 2: return "Attenuator Left"; // 010 01071 case 3: return "Attenuator Right"; // 011 01072 case 4: case 5: // 10x 01073 return "Pan/Balance"; 01074 } 01075 01076 return "?"; 01077 } 01078 void updateVolPair(unsigned int pair) { 01079 if (pair >= MASTER_OUTPUT_PORT) { 01080 // master volume changes everyone else. do it, through 1 level of recursion. 01081 for (unsigned int i=0;i < MASTER_OUTPUT_PORT;i++) 01082 updateVolPair(i); 01083 } 01084 else { 01085 float m[2]; 01086 01087 assert(gus_chan != NULL); 01088 01089 // copy not just attenuation but modify according to master volume 01090 for (unsigned int ch=0;ch < 2;ch++) { 01091 volpair[pair].AttenDb[ch] = mixpair[pair].AttenDb[ch] + mixpair[MASTER_OUTPUT_PORT].AttenDb[ch]; 01092 m[ch] = powf(10.0f,volpair[pair].AttenDb[ch]/20.0f); 01093 } 01094 01095 if (pair == GF1_OUT_PORT) 01096 gus_chan->SetVolume(m[0],m[1]); 01097 } 01098 } 01099 public: 01100 struct mixcontrol { 01101 public: 01102 mixcontrol() { 01103 Panning = 8; 01104 Control[0] = 0x01; 01105 Control[1] = 0x02; 01106 MapControl[0] = 0x01; 01107 MapControl[1] = 0x02; 01108 setAttenuation(0,0x7F); // FIXME: Because we want DOSBox to come up as if ULTRINIT/ULTRAMIX were run to configure the mixer 01109 setAttenuation(1,0x7F); 01110 } 01111 public: 01112 // gain() taken from an existing patch 01113 float gain(Bit8u val) { // in 0-127, out -90 to 0db, min to max 01114 float gain=(127-val)*-0.5; 01115 if(val<16) for(int i=0;i<(16-val);i++) gain+=-0.5-.13603*(i+1); // increasing rate of change, based on datasheet graph 01116 return gain; 01117 } 01118 // end borrow 01119 void setControl(const unsigned int channel,const Bit8u val) { 01120 Control[channel] = val; 01121 updateMapControl(); 01122 } 01123 void updateMapControl() { 01124 /* control mode according to Left control register, according to datasheet */ 01125 switch (Control[0]&0xE) { 01126 case 0: case 2: // normal mode 01127 MapControl[0] = Control[0]&3; 01128 MapControl[1] = Control[1]&3; 01129 break; 01130 case 4: // stereo (normal or reversed) 01131 MapControl[0] = (Control[0]&1) ? 1 : 2; // left -> left or left -> right if swapped 01132 MapControl[1] = (Control[0]&1) ? 2 : 1; // right -> right or right -> left if swapped 01133 break; 01134 case 6: // Mono 01135 MapControl[0] = 1; // Is this right?? 01136 MapControl[1] = 2; // Is this right?? 01137 break; 01138 case 8: case 12: // Balance 01139 MapControl[0] = (Control[0]&1) ? 1 : 2; // left -> left or left -> right if swapped 01140 MapControl[1] = (Control[0]&1) ? 2 : 1; // right -> right or right -> left if swapped 01141 // fixme: Do we update attenuation to reflect panning? or does the ICS chip need the 01142 // DOS program to write the attenuation registers again for the chip to apply balance/panning? 01143 break; 01144 case 10: case 14: // Pan 01145 MapControl[0] = (Control[0]&1) ? 1 : 2; // left -> left or left -> right if swapped 01146 MapControl[1] = (Control[0]&1) ? 2 : 1; // right -> right or right -> left if swapped 01147 // fixme: Do we update attenuation to reflect panning? or does the ICS chip need the 01148 // DOS program to write the attenuation registers again for the chip to apply balance/panning? 01149 break; 01150 } 01151 } 01152 void setAttenuation(const unsigned int channel,const Bit8u val) { 01153 // FIXME: I am only able to test the "normal" mode since that's the only mode used by Gravis's DOS and Windows drivers. 01154 // The code below has not been tested in "Stereo" and "Pan/Balance" mode. If any DOS drivers use it, please direct 01155 // me to them so I or anyone else can test! ---J.C. 01156 01157 if ((Control[0]&0xC) == 0) { 01158 Attenuation[channel] = val & 0x7F; 01159 AttenDb[channel] = gain(Attenuation[channel]); 01160 } 01161 else { 01162 // "stereo & balance use left control & gain, copies to right regs" says the Vogons patch I'm studying... 01163 Attenuation[0] = Attenuation[1] = val & 0x7F; 01164 AttenDb[0] = gain(Attenuation[0]); 01165 AttenDb[1] = AttenDb[0]; 01166 01167 // taken from the same Vogons patch, except potential access past array fixed 01168 if ((Control[0]&0xC) == 8/*Balance/pan mode*/) { 01169 static const float pan[16+1] = {-9,-9, -8.5, -6.5,-5.5,-4.5, -3.5,-3,-2.5,-2,-1.5,-1,-.5, 0,0,0,0}; 01170 AttenDb[0] += pan[Panning]; 01171 AttenDb[1] += pan[16-Panning]; 01172 } 01173 01174 } 01175 } 01176 void debugPrintMixer(const char *name) { 01177 LOG(LOG_MISC,LOG_DEBUG)("GUS ICS control '%s': %.3fdB %.3fdB",name,AttenDb[0],AttenDb[1]); 01178 } 01179 public: 01180 uint8_t Panning; 01181 uint8_t Control[2]; 01182 uint8_t MapControl[2]; 01183 uint8_t Attenuation[2]; // 0x00-0x7F where 0x00 is mute (max atten) and 0x7F is full volume 01184 float AttenDb[2]; // in decibels 01185 }; 01186 struct volpair { 01187 public: 01188 volpair() { 01189 AttenDb[0] = AttenDb[1] = 0; 01190 } 01191 public: 01192 float AttenDb[2]; 01193 uint32_t Fix1616Mult[2] = {}; // linear multiply to apply volume 01194 }; 01195 public: 01196 struct mixcontrol mixpair[8]; // pairs 1-5 and Master 01197 struct volpair volpair[5] = {}; // pairs 1-5 scaled by master 01198 uint8_t addr_attenuator = 0; // which attenuator is selected 01199 uint8_t addr_control = 0; // which control is selected 01200 } GUS_ICS2101; 01201 01202 static inline uint8_t read_GF1_mapping_control(const unsigned int ch) { 01203 return GUS_ICS2101.mixpair[gus_ICS2101::GF1_OUT_PORT].MapControl[ch]; 01204 } 01205 01206 /* Gravis Ultrasound MAX Crystal Semiconductor CS4231A emulation */ 01207 /* NOTES: 01208 * 01209 * This 4-port I/O interface, implemented by Crystal Semiconductors, Analog Devices, etc. and used 01210 * by sound cards in the early 1990s, is the said to be the "standardized" hardware interface of 01211 * the "Windows Sound System" standard at the time. 01212 * 01213 * According to an AD1848 datasheet, and a CS4231A datasheet, all I/O ports and indirect registers 01214 * appear to be the same, with the exception that Crystal Semiconductor adds 16 registers with the 01215 * "MODE 2" bit. 01216 * 01217 * Perhaps at some point, we can untie this from GUS emulation and let it exist as it's own C++ 01218 * class that covers CS4231A, AD1848, and other "WSS" chipset emulation on behalf of GUS and SB 01219 * emulation, much like the OPL3 emulation already present in this source tree for Sound Blaster. 01220 * 01221 */ 01222 struct gus_cs4231 { 01223 public: 01224 gus_cs4231() : address(0), mode2(false), ia4(false), trd(false), mce(true), init(false) { 01225 } 01226 public: 01227 void data_write(uint8_t addr,uint8_t val) { 01228 // LOG(LOG_MISC,LOG_DEBUG)("GUS CS4231 write data addr=%02xh val=%02xh",addr,val); 01229 01230 switch (addr) { 01231 case 0x00: /* Left ADC Input Control (I0) */ 01232 ADCInputControl[0] = val; break; 01233 case 0x01: /* Right ADC Input Control (I1) */ 01234 ADCInputControl[1] = val; break; 01235 case 0x02: /* Left Auxiliary #1 Input Control (I2) */ 01236 Aux1InputControl[0] = val; break; 01237 case 0x03: /* Right Auxiliary #1 Input Control (I3) */ 01238 Aux1InputControl[1] = val; break; 01239 case 0x06: /* Left DAC Output Control (I6) */ 01240 DACOutputControl[0] = val; break; 01241 case 0x07: /* Left DAC Output Control (I7) */ 01242 DACOutputControl[1] = val; break; 01243 case 0x0C: /* MODE and ID (I12) */ 01244 mode2 = (val & 0x40)?1:0; break; 01245 default: 01246 LOG(LOG_MISC,LOG_DEBUG)("GUS CS4231 unhandled data write addr=%02xh val=%02xh",addr,val); 01247 break; 01248 } 01249 } 01250 uint8_t data_read(uint8_t addr) { 01251 // LOG(LOG_MISC,LOG_DEBUG)("GUS CS4231 read data addr=%02xh",addr); 01252 01253 switch (addr) { 01254 case 0x00: /* Left ADC Input Control (I0) */ 01255 return ADCInputControl[0]; 01256 case 0x01: /* Right ADC Input Control (I1) */ 01257 return ADCInputControl[1]; 01258 case 0x02: /* Left Auxiliary #1 Input Control (I2) */ 01259 return Aux1InputControl[0]; 01260 case 0x03: /* Right Auxiliary #1 Input Control (I3) */ 01261 return Aux1InputControl[1]; 01262 case 0x06: /* Left DAC Output Control (I6) */ 01263 return DACOutputControl[0]; 01264 case 0x07: /* Left DAC Output Control (I7) */ 01265 return DACOutputControl[1]; 01266 case 0x0C: /* MODE and ID (I12) */ 01267 return 0x80 | (mode2 ? 0x40 : 0x00) | 0xA/*1010 codec ID*/; 01268 default: 01269 LOG(LOG_MISC,LOG_DEBUG)("GUS CS4231 unhandled data read addr=%02xh",addr); 01270 break; 01271 } 01272 01273 return 0; 01274 } 01275 void playio_data_write(uint8_t val) { 01276 LOG(LOG_MISC,LOG_DEBUG)("GUS CS4231 Playback I/O write %02xh",val); 01277 } 01278 uint8_t capio_data_read(void) { 01279 LOG(LOG_MISC,LOG_DEBUG)("GUS CS4231 Capture I/O read"); 01280 return 0; 01281 } 01282 uint8_t status_read(void) { 01283 LOG(LOG_MISC,LOG_DEBUG)("GUS CS4231 Status read"); 01284 return 0; 01285 } 01286 void iowrite(uint8_t reg,uint8_t val) { 01287 // LOG(LOG_MISC,LOG_DEBUG)("GUS CS4231 write reg=%u val=%02xh",reg,val); 01288 01289 if (init) return; 01290 01291 switch (reg) { 01292 case 0x0: /* Index Address Register (R0) */ 01293 address = val & (mode2 ? 0x1F : 0x0F); 01294 trd = (val & 0x20)?1:0; 01295 mce = (val & 0x40)?1:0; 01296 break; 01297 case 0x1: /* Index Data Register (R1) */ 01298 data_write(address,val); 01299 break; 01300 case 0x2: /* Status Register (R2) */ 01301 LOG(LOG_MISC,LOG_DEBUG)("GUS CS4231 attempted write to status register val=%02xh",val); 01302 break; 01303 case 0x3: /* Playback I/O Data Register (R3) */ 01304 playio_data_write(val); 01305 break; 01306 } 01307 } 01308 uint8_t ioread(uint8_t reg) { 01309 // LOG(LOG_MISC,LOG_DEBUG)("GUS CS4231 write read=%u",reg); 01310 01311 if (init) return 0x80; 01312 01313 switch (reg) { 01314 case 0x0: /* Index Address Register (R0) */ 01315 return address | (trd?0x20:0x00) | (mce?0x40:0x00) | (init?0x80:0x00); 01316 case 0x1: /* Index Data Register (R1) */ 01317 return data_read(address); 01318 case 0x2: /* Status Register (R2) */ 01319 return status_read(); 01320 case 0x3: /* Capture I/O Data Register (R3) */ 01321 return capio_data_read(); 01322 } 01323 01324 return 0; 01325 } 01326 public: 01327 uint8_t address; 01328 bool mode2; // read CS4231A datasheet for more information 01329 bool ia4; 01330 bool trd; 01331 bool mce; 01332 bool init; 01333 01334 uint8_t ADCInputControl[2] = {}; /* left (I0) and right (I1) ADC Input control. bits 7-6 select source. bit 5 is mic gain. bits 3-0 controls gain. */ 01335 uint8_t Aux1InputControl[2] = {}; /* left (I2) and right (I3) aux. input control. bits 5-0 control gain in 1.5dB steps. bit 7 is mute */ 01336 uint8_t DACOutputControl[2] = {}; /* left (I6) and right (I7) output control attenuation. bits 5-0 control in -1.5dB steps, bit 7 is mute */ 01337 } GUS_CS4231; 01338 01339 static Bitu read_gus_cs4231(Bitu port,Bitu iolen) { 01340 (void)iolen;//UNUSED 01341 if (myGUS.gUltraMAXControl & 0x40/*codec enable*/) 01342 return GUS_CS4231.ioread((port - GUS_BASE) & 3); // FIXME: UltraMAX allows this to be relocatable 01343 01344 return 0xFF; 01345 } 01346 01347 static void write_gus_cs4231(Bitu port,Bitu val,Bitu iolen) { 01348 (void)iolen;//UNUSED 01349 if (myGUS.gUltraMAXControl & 0x40/*codec enable*/) 01350 GUS_CS4231.iowrite((port - GUS_BASE) & 3,val&0xFF); 01351 } 01352 01353 static Bitu read_gus(Bitu port,Bitu iolen) { 01354 Bit16u reg16; 01355 01356 (void)iolen;//UNUSED 01357 // LOG_MSG("read from gus port %x",port); 01358 01359 /* 12-bit ISA decode (FIXME: Check GUS MAX ISA card to confirm) 01360 * 01361 * More than 10 bits must be decoded in order for GUS MAX extended registers at 7xx to work */ 01362 port &= 0xFFF; 01363 01364 switch(port - GUS_BASE) { 01365 case 0x206: 01366 if (myGUS.clearTCIfPollingIRQStatus) { 01367 double t = PIC_FullIndex(); 01368 01369 /* Hack: "Warcraft II" by Blizzard entertainment. 01370 * 01371 * If you configure the game to use the Gravis Ultrasound for both music and sound, the GUS support code for digital 01372 * sound will cause the game to hang if music is playing at the same time within the main menu. The bug is that there 01373 * is code (in real mode no less) that polls the IRQ status register (2X6) and handles each IRQ event to clear it, 01374 * however there is no condition to handle clearing the DMA Terminal Count IRQ flag. The routine will not terminate 01375 * until all bits are cleared, hence, the game hangs after starting a sound effect. Most often, this is visible to 01376 * the user as causing the game to hang when you click on a button on the main menu. 01377 * 01378 * This hack attempts to detect the bug by looking for rapid polling of this register in a short period of time. 01379 * If detected, we clear the DMA IRQ flag to help the loop terminate so the game continues to run. */ 01380 if (t < (myGUS.lastIRQStatusPollAt + 0.1/*ms*/)) { 01381 myGUS.lastIRQStatusPollAt = t; 01382 myGUS.lastIRQStatusPollRapidCount++; 01383 if (myGUS.clearTCIfPollingIRQStatus && (myGUS.IRQStatus & 0x80) && myGUS.lastIRQStatusPollRapidCount >= 500) { 01384 LOG(LOG_MISC,LOG_DEBUG)("GUS: Clearing DMA TC IRQ status, DOS application appears to be stuck"); 01385 myGUS.lastIRQStatusPollRapidCount = 0; 01386 myGUS.lastIRQStatusPollAt = t; 01387 myGUS.IRQStatus &= 0x7F; 01388 GUS_CheckIRQ(); 01389 } 01390 } 01391 else { 01392 myGUS.lastIRQStatusPollAt = t; 01393 myGUS.lastIRQStatusPollRapidCount = 0; 01394 } 01395 } 01396 01397 /* NTS: Contrary to some false impressions, GUS hardware does not report "one at a time", it really is a bitmask. 01398 * I had the funny idea you read this register "one at a time" just like reading the IRQ reason bits of the RS-232 port --J.C. */ 01399 return GUS_EffectiveIRQStatus(); 01400 case 0x208: 01401 Bit8u tmptime; 01402 tmptime = 0; 01403 if (myGUS.timers[0].reached) tmptime |= (1 << 6); 01404 if (myGUS.timers[1].reached) tmptime |= (1 << 5); 01405 if (tmptime & 0x60) tmptime |= (1 << 7); 01406 if (myGUS.IRQStatus & 0x04) tmptime|=(1 << 2); 01407 if (myGUS.IRQStatus & 0x08) tmptime|=(1 << 1); 01408 return tmptime; 01409 case 0x20a: 01410 return adlib_commandreg; 01411 case 0x20f: 01412 if (gus_type >= GUS_MAX || gus_ics_mixer) 01413 return 0x02; /* <- FIXME: What my GUS MAX returns. What does this mean? */ 01414 return ~0ul; // should not happen 01415 case 0x302: 01416 return myGUS.gRegSelectData; 01417 case 0x303: 01418 return myGUS.gRegSelectData; 01419 case 0x304: 01420 if (iolen==2) reg16 = ExecuteReadRegister() & 0xffff; 01421 else reg16 = ExecuteReadRegister() & 0xff; 01422 01423 if (gus_type < GUS_INTERWAVE) // Versions prior to the Interwave will reflect last I/O to 3X2-3X5 when read back from 3X3 01424 myGUS.gRegSelectData = reg16 & 0xFF; 01425 01426 return reg16; 01427 case 0x305: 01428 reg16 = ExecuteReadRegister() >> 8; 01429 01430 if (gus_type < GUS_INTERWAVE) // Versions prior to the Interwave will reflect last I/O to 3X2-3X5 when read back from 3X3 01431 myGUS.gRegSelectData = reg16 & 0xFF; 01432 01433 return reg16; 01434 case 0x307: 01435 if((myGUS.gDramAddr & myGUS.gDramAddrMask) < myGUS.memsize) { 01436 return GUSRam[myGUS.gDramAddr & myGUS.gDramAddrMask]; 01437 } else { 01438 return 0; 01439 } 01440 case 0x306: 01441 case 0x706: 01442 if (gus_type >= GUS_MAX) 01443 return 0x0B; /* UltraMax with CS4231 codec */ 01444 else if (gus_ics_mixer) 01445 return 0x06; /* revision 3.7+ with ICS-2101 mixer */ 01446 else 01447 return 0xFF; 01448 break; 01449 default: 01450 #if LOG_GUS 01451 LOG_MSG("Read GUS at port 0x%x", port); 01452 #endif 01453 break; 01454 } 01455 01456 return 0xff; 01457 } 01458 01459 01460 static void write_gus(Bitu port,Bitu val,Bitu iolen) { 01461 // LOG_MSG("Write gus port %x val %x",port,val); 01462 01463 /* 12-bit ISA decode (FIXME: Check GUS MAX ISA card to confirm) 01464 * 01465 * More than 10 bits must be decoded in order for GUS MAX extended registers at 7xx to work */ 01466 port &= 0xFFF; 01467 01468 switch(port - GUS_BASE) { 01469 case 0x200: 01470 myGUS.gRegControl = 0; 01471 myGUS.mixControl = (Bit8u)val; 01472 myGUS.ChangeIRQDMA = true; 01473 return; 01474 case 0x208: 01475 adlib_commandreg = (Bit8u)val; 01476 break; 01477 case 0x209: 01478 //TODO adlib_commandreg should be 4 for this to work else it should just latch the value 01479 if (val & 0x80) { 01480 myGUS.timers[0].reached=false; 01481 myGUS.timers[1].reached=false; 01482 return; 01483 } 01484 myGUS.timers[0].masked=(val & 0x40)>0; 01485 myGUS.timers[1].masked=(val & 0x20)>0; 01486 if (val & 0x1) { 01487 if (!myGUS.timers[0].running) { 01488 PIC_AddEvent(GUS_TimerEvent,myGUS.timers[0].delay,0); 01489 myGUS.timers[0].running=true; 01490 } 01491 } else myGUS.timers[0].running=false; 01492 if (val & 0x2) { 01493 if (!myGUS.timers[1].running) { 01494 PIC_AddEvent(GUS_TimerEvent,myGUS.timers[1].delay,1); 01495 myGUS.timers[1].running=true; 01496 } 01497 } else myGUS.timers[1].running=false; 01498 break; 01499 //TODO Check if 0x20a register is also available on the gus like on the interwave 01500 case 0x20b: 01501 if (!myGUS.ChangeIRQDMA) break; 01502 myGUS.ChangeIRQDMA=false; 01503 01504 if (myGUS.gRegControl == 6) { 01505 /* Jumper register: 01506 * 01507 * 7: reserved 01508 * 6: reserved 01509 * 5: reserved 01510 * 4: reserved 01511 * 3: reserved 01512 * 2: enable joystick port decode 01513 * 1: enable midi port address decode 01514 * 0: reserved */ 01515 /* TODO: */ 01516 LOG(LOG_MISC,LOG_DEBUG)("GUS: DOS application wrote to 2XB register control number 0x06 (Jumper) val=%02xh",(int)val); 01517 } 01518 else if (myGUS.gRegControl == 5) { 01519 /* write a 0 to clear IRQs on power up (?) */ 01520 LOG(LOG_MISC,LOG_DEBUG)("GUS: DOS application wrote to 2XB register control number 0x05 (Clear IRQs) val=%02xh",(int)val); 01521 } 01522 else if (myGUS.gRegControl == 0) { 01523 if (myGUS.mixControl & 0x40) { 01524 // GUS SDK: IRQ Control Register 01525 // Channel 1 GF1 IRQ selector (bits 2-0) 01526 // 0=reserved, do not use 01527 // 1=IRQ2 01528 // 2=IRQ5 01529 // 3=IRQ3 01530 // 4=IRQ7 01531 // 5=IRQ11 01532 // 6=IRQ12 01533 // 7=IRQ15 01534 // Channel 2 MIDI IRQ selector (bits 5-3) 01535 // 0=no interrupt 01536 // 1=IRQ2 01537 // 2=IRQ5 01538 // 3=IRQ3 01539 // 4=IRQ7 01540 // 5=IRQ11 01541 // 6=IRQ12 01542 // 7=IRQ15 01543 // Combine both IRQs using channel 1 (bit 6) 01544 // Reserved (bit 7) 01545 // 01546 // "If both channels are sharing an IRQ, channel 2's IRQ must be set to 0 and turn on bit 6. A 01547 // bus conflict will occur if both latches are programmed with the same IRQ #." 01548 if (irqtable[val & 0x7] != 0) 01549 myGUS.irq1 = irqtable[val & 0x7]; 01550 01551 if (val & 0x40) // "Combine both IRQs" 01552 myGUS.irq2 = myGUS.irq1; 01553 else if (((val >> 3) & 7) != 0) 01554 myGUS.irq2 = irqtable[(val >> 3) & 0x7]; 01555 01556 LOG(LOG_MISC,LOG_DEBUG)("GUS IRQ reprogrammed: GF1 IRQ %d, MIDI IRQ %d",(int)myGUS.irq1,(int)myGUS.irq2); 01557 01558 gus_warn_irq_conflict = (!(val & 0x40) && (val & 7) == ((val >> 3) & 7)); 01559 } else { 01560 // GUS SDK: DMA Control Register 01561 // Channel 1 (bits 2-0) 01562 // 0=NO DMA 01563 // 1=DMA1 01564 // 2=DMA3 01565 // 3=DMA5 01566 // 4=DMA6 01567 // 5=DMA7 01568 // 6=? 01569 // 7=? 01570 // Channel 2 (bits 5-3) 01571 // 0=NO DMA 01572 // 1=DMA1 01573 // 2=DMA3 01574 // 3=DMA5 01575 // 4=DMA6 01576 // 5=DMA7 01577 // 6=? 01578 // 7=? 01579 // Combine both DMA channels using channel 1 (bit 6) 01580 // Reserved (bit 7) 01581 // 01582 // "If both channels are sharing an DMA, channel 2's DMA must be set to 0 and turn on bit 6. A 01583 // bus conflict will occur if both latches are programmed with the same DMA #." 01584 01585 // NTS: This emulation does not use the second DMA channel... yet... which is why we do not bother 01586 // unregistering and reregistering the second DMA channel. 01587 01588 GetDMAChannel(myGUS.dma1)->Register_Callback(0); // FIXME: On DMA conflict this could mean kicking other devices off! 01589 01590 // NTS: Contrary to an earlier commit, DMA channel 0 is not a valid choice 01591 if (dmatable[val & 0x7] != 0) 01592 myGUS.dma1 = dmatable[val & 0x7]; 01593 01594 if (val & 0x40) // "Combine both DMA channels" 01595 myGUS.dma2 = myGUS.dma1; 01596 else if (dmatable[(val >> 3) & 0x7] != 0) 01597 myGUS.dma2 = dmatable[(val >> 3) & 0x7]; 01598 01599 GetDMAChannel(myGUS.dma1)->Register_Callback(GUS_DMA_Callback); 01600 01601 LOG(LOG_MISC,LOG_DEBUG)("GUS DMA reprogrammed: DMA1 %d, DMA2 %d",(int)myGUS.dma1,(int)myGUS.dma2); 01602 01603 // NTS: The Windows 3.1 Gravis Ultrasound drivers will program the same DMA channel into both without setting the "combining" bit, 01604 // even though their own SDK says not to, when Windows starts up. But it then immediately reprograms it normally, so no bus 01605 // conflicts actually occur. Strange. 01606 gus_warn_dma_conflict = (!(val & 0x40) && (val & 7) == ((val >> 3) & 7)); 01607 } 01608 } 01609 else { 01610 LOG(LOG_MISC,LOG_DEBUG)("GUS warning: Port 2XB register control %02xh written (unknown control reg) val=%02xh",(int)myGUS.gRegControl,(int)val); 01611 } 01612 break; 01613 case 0x20f: 01614 if (gus_type >= GUS_MAX || gus_ics_mixer) { 01615 myGUS.gRegControl = val; 01616 myGUS.ChangeIRQDMA = true; 01617 } 01618 break; 01619 case 0x302: 01620 myGUS.gCurChannel = val & 31; 01621 if (gus_type < GUS_INTERWAVE) // Versions prior to the Interwave will reflect last I/O to 3X2-3X5 when read back from 3X3 01622 myGUS.gRegSelectData = (Bit8u)val; 01623 01624 curchan = guschan[myGUS.gCurChannel]; 01625 break; 01626 case 0x303: 01627 myGUS.gRegSelect = myGUS.gRegSelectData = (Bit8u)val; 01628 myGUS.gRegData = 0; 01629 break; 01630 case 0x304: 01631 if (iolen==2) { 01632 if (gus_type < GUS_INTERWAVE) // Versions prior to the Interwave will reflect last I/O to 3X2-3X5 when read back from 3X3 01633 myGUS.gRegSelectData = val & 0xFF; 01634 01635 myGUS.gRegData=(Bit16u)val; 01636 ExecuteGlobRegister(); 01637 } else { 01638 if (gus_type < GUS_INTERWAVE) // Versions prior to the Interwave will reflect last I/O to 3X2-3X5 when read back from 3X3 01639 myGUS.gRegSelectData = val; 01640 01641 myGUS.gRegData = (Bit16u)val; 01642 } 01643 break; 01644 case 0x305: 01645 if (gus_type < GUS_INTERWAVE) // Versions prior to the Interwave will reflect last I/O to 3X2-3X5 when read back from 3X3 01646 myGUS.gRegSelectData = val; 01647 01648 myGUS.gRegData = (Bit16u)((0x00ff & myGUS.gRegData) | val << 8); 01649 ExecuteGlobRegister(); 01650 break; 01651 case 0x307: 01652 if ((myGUS.gDramAddr & myGUS.gDramAddrMask) < myGUS.memsize) 01653 GUSRam[myGUS.gDramAddr & myGUS.gDramAddrMask] = (Bit8u)val; 01654 break; 01655 case 0x306: 01656 case 0x706: 01657 if (gus_type >= GUS_MAX) { 01658 /* Ultramax control register: 01659 * 01660 * bit 7: reserved 01661 * bit 6: codec enable 01662 * bit 5: playback channel type (1=16-bit 0=8-bit) 01663 * bit 4: capture channel type (1=16-bit 0=8-bit) 01664 * bits 3-0: Codec I/O port address decode bits 7-4. 01665 * 01666 * For example, to put the CS4231 codec at port 0x34C, and enable the codec, write 0x44 to this register. 01667 * If you want to move the codec to base I/O port 0x32C, write 0x42 here. */ 01668 myGUS.gUltraMAXControl = val; 01669 01670 if (val & 0x40) { 01671 if ((val & 0xF) != ((port >> 4) & 0xF)) 01672 LOG(LOG_MISC,LOG_WARN)("GUS WARNING: DOS application is attempting to relocate the CS4231 codec, which is not supported"); 01673 } 01674 } 01675 else if (gus_ics_mixer) { 01676 if ((port - GUS_BASE) == 0x306) 01677 GUS_ICS2101.dataWrite(val&0xFF); 01678 else if ((port - GUS_BASE) == 0x706) 01679 GUS_ICS2101.addressWrite(val&0xFF); 01680 } 01681 break; 01682 default: 01683 #if LOG_GUS 01684 LOG_MSG("Write GUS at port 0x%x with %x", port, val); 01685 #endif 01686 break; 01687 } 01688 } 01689 01690 static Bitu GUS_Master_Clock = 617400; /* NOTE: This is 1000000Hz / 1.619695497. Seems to be a common base rate within the hardware. */ 01691 static Bitu GUS_DMA_Event_transfer = 16; /* DMA words (8 or 16-bit) per interval */ 01692 static Bitu GUS_DMA_Events_per_sec = 44100 / 4; /* cheat a little, to improve emulation performance */ 01693 static double GUS_DMA_Event_interval = 1000.0 / GUS_DMA_Events_per_sec; 01694 static double GUS_DMA_Event_interval_init = 1000.0 / 44100; 01695 static bool GUS_DMA_Active = false; 01696 01697 void GUS_Update_DMA_Event_transfer() { 01698 /* NTS: From the GUS SDK, bits 3-4 of DMA Control divide the ISA DMA transfer rate down from "approx 650KHz". 01699 * Bits 3-4 are documented as "DMA Rate divisor" */ 01700 GUS_DMA_Event_transfer = GUS_Master_Clock / GUS_DMA_Events_per_sec / (Bitu)(((Bitu)(myGUS.DMAControl >> 3u) & 3u) + 1u); 01701 GUS_DMA_Event_transfer &= ~1u; /* make sure it's word aligned in case of 16-bit PCM */ 01702 if (GUS_DMA_Event_transfer == 0) GUS_DMA_Event_transfer = 2; 01703 } 01704 01705 void GUS_DMA_Event_Transfer(DmaChannel *chan,Bitu dmawords) { 01706 Bitu dmaaddr = (Bitu)(myGUS.dmaAddr << 4ul) + (Bitu)myGUS.dmaAddrOffset; 01707 Bitu dmalimit = myGUS.memsize; 01708 unsigned int docount = 0; 01709 unsigned int step = 0; 01710 bool dma16xlate; 01711 Bitu holdAddr; 01712 01713 // FIXME: What does the GUS do if the DMA address goes beyond the end of memory? 01714 01715 /* is this a DMA transfer where the GUS memory address is to be translated for 16-bit PCM? 01716 * Note that there is plenty of code out there that transfers 16-bit PCM with 8-bit DMA, 01717 * and such transfers DO NOT involve the memory address translation. 01718 * 01719 * MODE XLATE? NOTE 01720 * 0x00 NO 8-bit PCM, 8-bit DMA (Most DOS programs) 01721 * 0x04 DEPENDS 8-bit PCM, 16-bit DMA (Star Control II, see comments below) 01722 * 0x40 NO 16-bit PCM, 8-bit DMA (Windows 3.1, Quake, for 16-bit PCM over 8-bit DMA) 01723 * 0x44 YES 16-bit PCM, 16-bit DMA (Windows 3.1, Quake, for 16-bit PCM over 16-bit DMA) 01724 * 01725 * Mode 0x04 is marked DEPENDS. It DEPENDS on whether the assigned DMA channel is 8-bit (NO) or 16-bit (YES). 01726 * Mode 0x04 does not appear to be used by any other DOS application or Windows drivers, only by an erratic 01727 * bug in Star Control II. FIXME: But, what does REAL hardware do? Drag out the old Pentium 100MHz with the 01728 * GUS classic and test! --J.C. 01729 * 01730 * Star Control II has a bug where, if the GUS DMA channel is 8-bit (DMA channel 0-3), it will upload 01731 * it's samples to GUS RAM, one DMA transfer per sample, and sometimes set bit 2. Setting bit 2 incorrectly 01732 * tells the GUS it's a 16-bit wide DMA transfer when the DMA channel is 8-bit. But, if the DMA channel is 01733 * 16-bit (DMA channel 5-7), Star Control II will correctly set bit 2 in all cases and samples will 01734 * transfer correctly to GUS RAM. 01735 * */ 01736 01737 /* FIXME: So, if the GUS DMA channel is 8-bit and Star Control II writes mode 0x04 (8-bit PCM, 16-bit DMA), what does the GF1 do? 01738 * I'm guessing so far that something happens within the GF1 to transfer as 8-bit anyway, clearly the developers of Star Control II 01739 * did not hear any audible sign that an invalid DMA control was being used. Perhaps the hardware engineers of the GF1 figured 01740 * out that case and put something in the silicon to ignore the invalid DMA control state. I won't have any answers until 01741 * I pull out an old Pentium box with a GUS classic and check. --J.C. 01742 * 01743 * DMA transfers noted by Star Control II that are the reason for this hack (gusdma=1): 01744 * 01745 * LOG: 157098507 DEBUG MISC:GUS DMA: terminal count reached. DMAControl=0x21 01746 * LOG: 157098507 DEBUG MISC:GUS DMA transfer 1981 bytes, GUS RAM address 0x0 8-bit DMA 8-bit PCM (ctrl=0x21) 01747 * LOG: 157098507 DEBUG MISC:GUS DMA: terminal count reached. DMAControl=0x21 01748 * LOG: 157100331 DEBUG MISC:GUS DMA: terminal count reached. DMAControl=0x21 01749 * LOG: 157100331 DEBUG MISC:GUS DMA transfer 912 bytes, GUS RAM address 0x7c0 8-bit DMA 8-bit PCM (ctrl=0x21) 01750 * LOG: 157100331 DEBUG MISC:GUS DMA: terminal count reached. DMAControl=0x21 01751 * LOG: 157100470 DEBUG MISC:GUS DMA: terminal count reached. DMAControl=0x25 01752 * LOG: 157100470 DEBUG MISC:GUS DMA transfer 1053 bytes, GUS RAM address 0xb50 16-bit DMA 8-bit PCM (ctrl=0x25) <-- What? 01753 * LOG: 157100470 DEBUG MISC:GUS DMA: terminal count reached. DMAControl=0x25 01754 * LOG: 157102251 DEBUG MISC:GUS DMA: terminal count reached. DMAControl=0x21 01755 * LOG: 157102251 DEBUG MISC:GUS DMA transfer 1597 bytes, GUS RAM address 0xf80 8-bit DMA 8-bit PCM (ctrl=0x21) 01756 * LOG: 157102251 DEBUG MISC:GUS DMA: terminal count reached. DMAControl=0x21 01757 * LOG: 157104064 DEBUG MISC:GUS DMA: terminal count reached. DMAControl=0x21 01758 * LOG: 157104064 DEBUG MISC:GUS DMA transfer 2413 bytes, GUS RAM address 0x15c0 8-bit DMA 8-bit PCM (ctrl=0x21) 01759 * LOG: 157104064 DEBUG MISC:GUS DMA: terminal count reached. DMAControl=0x21 01760 * 01761 * (end list) 01762 * 01763 * Noted: Prior to this hack, the samples played by Star Control II sounded more random and often involved leftover 01764 * sample data in GUS RAM, where with this fix, the music now sounds identical to what is played when using 01765 * it's Sound Blaster support. */ 01766 if (myGUS.dma1 < 4/*8-bit DMA channel*/ && (myGUS.DMAControl & 0x44) == 0x04/*8-bit PCM, 16-bit DMA*/) 01767 dma16xlate = false; /* Star Control II hack: 8-bit PCM, 8-bit DMA, ignore the bit that says it's 16-bit wide */ 01768 else 01769 dma16xlate = (myGUS.DMAControl & 0x4) ? true : false; 01770 01771 if (dma16xlate) { 01772 // 16-bit wide DMA. The GUS SDK specifically mentions that 16-bit DMA is translated 01773 // to GUS RAM the same way you translate the play pointer. Eugh. But this allows 01774 // older demos to work properly even if you set the GUS DMA to a 16-bit channel (5) 01775 // instead of the usual 8-bit channel (1). 01776 holdAddr = dmaaddr & 0xc0000L; 01777 dmaaddr = dmaaddr & 0x1ffffL; 01778 dmaaddr = dmaaddr << 1; 01779 dmaaddr = (holdAddr | dmaaddr); 01780 dmalimit = ((dmaaddr & 0xc0000L) | 0x3FFFFL) + 1; 01781 } 01782 01783 if (dmaaddr < dmalimit) 01784 docount = (unsigned int)(dmalimit - dmaaddr); 01785 01786 docount /= (chan->DMA16+1u); 01787 if (docount > (chan->currcnt+1u)) docount = chan->currcnt+1u; 01788 if ((Bitu)docount > dmawords) docount = dmawords; 01789 01790 // hack: some programs especially Gravis Ultrasound MIDI playback like to upload by DMA but never clear the DMA TC flag on the DMA controller. 01791 bool saved_tcount = chan->tcount; 01792 chan->tcount = false; 01793 01794 if (docount > 0) { 01795 if ((myGUS.DMAControl & 0x2) == 0) { 01796 Bitu read=(Bitu)chan->Read((Bitu)docount,&GUSRam[dmaaddr]); 01797 //Check for 16 or 8bit channel 01798 read*=(chan->DMA16+1u); 01799 if((myGUS.DMAControl & 0x80) != 0) { 01800 //Invert the MSB to convert twos compliment form 01801 Bitu i; 01802 if((myGUS.DMAControl & 0x40) == 0) { 01803 // 8-bit data 01804 for(i=dmaaddr;i<(dmaaddr+read);i++) GUSRam[i] ^= 0x80; 01805 } else { 01806 // 16-bit data 01807 for(i=dmaaddr+1;i<(dmaaddr+read);i+=2) GUSRam[i] ^= 0x80; 01808 } 01809 } 01810 01811 step = read; 01812 } else { 01813 //Read data out of UltraSound 01814 Bitu wd = (Bitu)chan->Write((Bitu)docount,&GUSRam[dmaaddr]); 01815 //Check for 16 or 8bit channel 01816 wd*=(chan->DMA16+1u); 01817 01818 step = wd; 01819 } 01820 } 01821 01822 LOG(LOG_MISC,LOG_DEBUG)("GUS DMA transfer %lu bytes, GUS RAM address 0x%lx %u-bit DMA %u-bit PCM (ctrl=0x%02x) tcount=%u", 01823 (unsigned long)step,(unsigned long)dmaaddr,(myGUS.DMAControl & 0x4) ? 16 : 8,(myGUS.DMAControl & 0x40) ? 16 : 8,myGUS.DMAControl,chan->tcount); 01824 01825 if (step > 0) { 01826 dmaaddr += (unsigned int)step; 01827 01828 if (dma16xlate) { 01829 holdAddr = dmaaddr & 0xc0000L; 01830 dmaaddr = dmaaddr & 0x3ffffL; 01831 dmaaddr = dmaaddr >> 1; 01832 dmaaddr = (holdAddr | dmaaddr); 01833 } 01834 01835 myGUS.dmaAddr = dmaaddr >> 4; 01836 myGUS.dmaAddrOffset = dmaaddr & 0xF; 01837 } 01838 01839 if (chan->tcount) { 01840 LOG(LOG_MISC,LOG_DEBUG)("GUS DMA transfer hit Terminal Count, setting DMA TC IRQ pending"); 01841 01842 /* Raise the TC irq, and stop DMA */ 01843 myGUS.IRQStatus |= 0x80; 01844 saved_tcount = true; 01845 GUS_CheckIRQ(); 01846 GUS_StopDMA(); 01847 } 01848 01849 chan->tcount = saved_tcount; 01850 } 01851 01852 void GUS_DMA_Event(Bitu val) { 01853 (void)val;//UNUSED 01854 DmaChannel *chan = GetDMAChannel(myGUS.dma1); 01855 if (chan == NULL) { 01856 LOG(LOG_MISC,LOG_DEBUG)("GUS DMA event: DMA channel no longer exists, stopping DMA transfer events"); 01857 GUS_DMA_Active = false; 01858 return; 01859 } 01860 01861 if (chan->masked) { 01862 LOG(LOG_MISC,LOG_DEBUG)("GUS: Stopping DMA transfer interval, DMA masked=%u",chan->masked?1:0); 01863 GUS_DMA_Active = false; 01864 return; 01865 } 01866 01867 if (!(myGUS.DMAControl & 0x01/*DMA enable*/)) { 01868 LOG(LOG_MISC,LOG_DEBUG)("GUS DMA event: DMA control 'enable DMA' bit was reset, stopping DMA transfer events"); 01869 GUS_DMA_Active = false; 01870 return; 01871 } 01872 01873 LOG(LOG_MISC,LOG_DEBUG)("GUS DMA event: max %u DMA words. DMA: tc=%u mask=%u cnt=%u", 01874 (unsigned int)GUS_DMA_Event_transfer, 01875 chan->tcount?1:0, 01876 chan->masked?1:0, 01877 chan->currcnt+1); 01878 GUS_DMA_Event_Transfer(chan,GUS_DMA_Event_transfer); 01879 01880 if (GUS_DMA_Active) { 01881 /* keep going */ 01882 PIC_AddEvent(GUS_DMA_Event,GUS_DMA_Event_interval); 01883 } 01884 } 01885 01886 void GUS_StopDMA() { 01887 if (GUS_DMA_Active) 01888 LOG(LOG_MISC,LOG_DEBUG)("GUS: Stopping DMA transfer interval"); 01889 01890 PIC_RemoveEvents(GUS_DMA_Event); 01891 GUS_DMA_Active = false; 01892 } 01893 01894 void GUS_StartDMA() { 01895 if (!GUS_DMA_Active) { 01896 GUS_DMA_Active = true; 01897 LOG(LOG_MISC,LOG_DEBUG)("GUS: Starting DMA transfer interval"); 01898 PIC_AddEvent(GUS_DMA_Event,GUS_DMA_Event_interval_init); 01899 01900 if (GetDMAChannel(myGUS.dma1)->masked) 01901 LOG(LOG_MISC,LOG_WARN)("GUS: DMA transfer interval started when channel is masked"); 01902 01903 if (gus_warn_dma_conflict) 01904 LOG(LOG_MISC,LOG_WARN)( 01905 "GUS warning: Both DMA channels set to the same channel WITHOUT combining! " 01906 "This is documented to cause bus conflicts on real hardware"); 01907 } 01908 } 01909 01910 static void GUS_DMA_Callback(DmaChannel * chan,DMAEvent event) { 01911 (void)chan;//UNUSED 01912 if (event == DMA_UNMASKED) { 01913 LOG(LOG_MISC,LOG_DEBUG)("GUS: DMA unmasked"); 01914 if (myGUS.DMAControl & 0x01/*DMA enable*/) GUS_StartDMA(); 01915 } 01916 else if (event == DMA_MASKED) { 01917 LOG(LOG_MISC,LOG_DEBUG)("GUS: DMA masked. Perhaps it will stop the DMA transfer event."); 01918 } 01919 } 01920 01921 static void GUS_CallBack(Bitu len) { 01922 Bit32s buffer[MIXER_BUFSIZE][2]; 01923 memset(buffer, 0, len * sizeof(buffer[0])); 01924 01925 if ((GUS_reset_reg & 0x01) == 0x01) { 01926 for (Bitu i = 0; i < myGUS.ActiveChannels; i++) { 01927 guschan[i]->generateSamples(buffer[0], len); 01928 } 01929 } 01930 01931 // FIXME: I wonder if the GF1 chip DAC had more than 16 bits precision 01932 // to render louder than 100% volume without clipping, and if so, 01933 // how many extra bits? 01934 // 01935 // If not, then perhaps clipping and saturation were not a problem 01936 // unless the volume was set to maximum? 01937 // 01938 // Time to pull out the GUS MAX and test this theory: what happens 01939 // if you play samples that would saturate at maximum volume at 16-bit 01940 // precision? Does it audibly clip or is there some headroom like some 01941 // sort of 17-bit DAC? 01942 // 01943 // One way to test is to play a sample on one channel while another 01944 // channel is set to play a single sample at maximum volume (to see 01945 // if it makes the audio grungy like a waveform railed to one side). 01946 // 01947 // Past experience with GUS cards says that at full volume their line 01948 // out jacks can be quite loud when connected to a speaker. 01949 // 01950 // While improving this code, a better audio compression function 01951 // could be implemented that does proper envelope tracking and volume 01952 // control for better results than this. 01953 // 01954 // --J.C. 01955 01956 for (Bitu i = 0; i < len; i++) { 01957 buffer[i][0] >>= (VOL_SHIFT * AutoAmp) >> 9; 01958 buffer[i][1] >>= (VOL_SHIFT * AutoAmp) >> 9; 01959 bool dampenedAutoAmp = false; 01960 01961 if (buffer[i][0] > 32767) { 01962 buffer[i][0] = 32767; 01963 if (enable_autoamp) { 01964 AutoAmp -= 4; /* dampen faster than recovery */ 01965 dampenedAutoAmp = true; 01966 } 01967 } 01968 else if (buffer[i][0] < -32768) { 01969 buffer[i][0] = -32768; 01970 if (enable_autoamp) { 01971 AutoAmp -= 4; /* dampen faster than recovery */ 01972 dampenedAutoAmp = true; 01973 } 01974 } 01975 01976 if (buffer[i][1] > 32767) { 01977 buffer[i][1] = 32767; 01978 if (enable_autoamp && !dampenedAutoAmp) { 01979 AutoAmp -= 4; /* dampen faster than recovery */ 01980 dampenedAutoAmp = true; 01981 } 01982 } 01983 else if (buffer[i][1] < -32768) { 01984 buffer[i][1] = -32768; 01985 if (enable_autoamp && !dampenedAutoAmp) { 01986 AutoAmp -= 4; /* dampen faster than recovery */ 01987 dampenedAutoAmp = true; 01988 } 01989 } 01990 01991 if (AutoAmp < myGUS.masterVolumeMul && !dampenedAutoAmp) { 01992 AutoAmp++; /* recovery back to 100% normal volume */ 01993 } 01994 } 01995 01996 gus_chan->AddSamples_s32(len, buffer[0]); 01997 CheckVoiceIrq(); 01998 } 01999 02000 // Generate logarithmic to linear volume conversion tables 02001 static void MakeTables(void) { 02002 int i; 02003 double out = (double)(1 << 13); 02004 for (i=4095;i>=0;i--) { 02005 vol16bit[i]=(Bit16u)((Bit16s)out); 02006 out/=1.002709201; /* 0.0235 dB Steps */ 02007 //Original amplification routine in the hardware 02008 //vol16bit[i] = ((256 + i & 0xff) << VOL_SHIFT) / (1 << (24 - (i >> 8))); 02009 } 02010 /* FIX: DOSBox 0.74 had code here that produced a pantable which 02011 * had nothing to do with actual panning control variables. 02012 * Instead it seemed to generate a 16-element map that started 02013 * at 0, jumped sharply to unity and decayed to 0. 02014 * The unfortunate result was that stock builds of DOSBox 02015 * effectively locked Gravis Ultrasound capable programs 02016 * to monural audio. 02017 * 02018 * This fix generates the table properly so that they correspond 02019 * to how much we attenuate the LEFT channel for any given 02020 * 4-bit value of the Panning register (you attenuate the 02021 * RIGHT channel by looking at element 0xF - (val&0xF)). 02022 * 02023 * Having made this fix I can finally enjoy old DOS demos 02024 * in GUS stereo instead of having everything mushed into 02025 * mono. */ 02026 if (gus_fixed_table) { 02027 for (i=0;i < 16;i++) 02028 pantable[i] = pantablePDF[i] * 2048u; 02029 02030 LOG(LOG_MISC,LOG_DEBUG)("GUS: using accurate (fixed) pantable"); 02031 } 02032 else { 02033 for (i=0;i < 8;i++) 02034 pantable[i] = 0; 02035 for (i=8;i < 15;i++) 02036 pantable[i]=(Bit32u)(-128.0*(log((double)(15-i)/7.0)/log(2.0))*(double)(1 << RAMP_FRACT)); 02037 02038 /* if the program cranks the pan register all the way, ensure the 02039 * opposite channel is crushed to silence */ 02040 pantable[15] = 1UL << 30UL; 02041 02042 LOG(LOG_MISC,LOG_DEBUG)("GUS: using old (naive) pantable"); 02043 } 02044 02045 LOG(LOG_MISC,LOG_DEBUG)("GUS pantable (attenuation, left to right in dB): hard left -%.3f, -%.3f, -%.3f, -%.3f, -%.3f, -%.3f, -%.3f, center(7) -%.3f, center(8) -%.3f, -%.3f, -%.3f, -%.3f, -%.3f, -%.3f, -%.3f, hard right -%.3f", 02046 ((double)pantable[0]) / (1 << RAMP_FRACT), 02047 ((double)pantable[1]) / (1 << RAMP_FRACT), 02048 ((double)pantable[2]) / (1 << RAMP_FRACT), 02049 ((double)pantable[3]) / (1 << RAMP_FRACT), 02050 ((double)pantable[4]) / (1 << RAMP_FRACT), 02051 ((double)pantable[5]) / (1 << RAMP_FRACT), 02052 ((double)pantable[6]) / (1 << RAMP_FRACT), 02053 ((double)pantable[7]) / (1 << RAMP_FRACT), 02054 ((double)pantable[8]) / (1 << RAMP_FRACT), 02055 ((double)pantable[9]) / (1 << RAMP_FRACT), 02056 ((double)pantable[10]) / (1 << RAMP_FRACT), 02057 ((double)pantable[11]) / (1 << RAMP_FRACT), 02058 ((double)pantable[12]) / (1 << RAMP_FRACT), 02059 ((double)pantable[13]) / (1 << RAMP_FRACT), 02060 ((double)pantable[14]) / (1 << RAMP_FRACT), 02061 ((double)pantable[15]) / (1 << RAMP_FRACT)); 02062 } 02063 02064 static IO_ReadHandler* gus_cb_port_r(IO_CalloutObject &co,Bitu port,Bitu iolen) { 02065 (void)co; 02066 (void)iolen; 02067 02068 /* 10-bit ISA decode. 02069 * NOTE that the I/O handlers still need more than 10 bits to handle GUS MAX/Interwave registers at 0x7xx. */ 02070 port &= 0x3FF; 02071 02072 if (gus_type >= GUS_MAX) { 02073 if (port >= (0x30C + GUS_BASE) && port <= (0x30F + GUS_BASE)) 02074 return read_gus_cs4231; 02075 } 02076 02077 return read_gus; 02078 } 02079 02080 static IO_WriteHandler* gus_cb_port_w(IO_CalloutObject &co,Bitu port,Bitu iolen) { 02081 (void)co; 02082 (void)iolen; 02083 02084 /* 10-bit ISA decode. 02085 * NOTE that the I/O handlers still need more than 10 bits to handle GUS MAX/Interwave registers at 0x7xx. */ 02086 port &= 0x3FF; 02087 02088 if (gus_type >= GUS_MAX) { 02089 if (port >= (0x30C + GUS_BASE) && port <= (0x30F + GUS_BASE)) 02090 return write_gus_cs4231; 02091 } 02092 02093 return write_gus; 02094 } 02095 02096 class GUS:public Module_base{ 02097 private: 02098 // IO_ReadHandleObject ReadHandler[12]; 02099 // IO_WriteHandleObject WriteHandler[12]; 02100 // IO_ReadHandleObject ReadCS4231Handler[4]; 02101 // IO_WriteHandleObject WriteCS4231Handler[4]; 02102 AutoexecObject autoexecline[3]; 02103 MixerObject MixerChan; 02104 bool gus_enable; 02105 public: 02106 GUS(Section* configuration):Module_base(configuration){ 02107 int x; 02108 02109 gus_enable = false; 02110 if(!IS_EGAVGA_ARCH) return; 02111 Section_prop * section=static_cast<Section_prop *>(configuration); 02112 if(!section->Get_bool("gus")) return; 02113 02114 gus_enable = true; 02115 memset(&myGUS,0,sizeof(myGUS)); 02116 memset(GUSRam,0,1024*1024); 02117 02118 ignore_active_channel_write_while_active = section->Get_bool("ignore channel count while active"); 02119 02120 unmask_irq = section->Get_bool("pic unmask irq"); 02121 enable_autoamp = section->Get_bool("autoamp"); 02122 02123 startup_ultrinit = section->Get_bool("startup initialized"); 02124 02125 dma_enable_on_dma_control_polling = section->Get_bool("dma enable on dma control polling"); 02126 02127 string s_pantable = section->Get_string("gus panning table"); 02128 if (s_pantable == "default" || s_pantable == "" || s_pantable == "accurate") 02129 gus_fixed_table = true; 02130 else if (s_pantable == "old") 02131 gus_fixed_table = false; 02132 else 02133 gus_fixed_table = true; 02134 02135 gus_ics_mixer = false; 02136 string s_gustype = section->Get_string("gustype"); 02137 if (s_gustype == "classic") { 02138 LOG(LOG_MISC,LOG_DEBUG)("GUS: Classic emulation"); 02139 gus_type = GUS_CLASSIC; 02140 } 02141 else if (s_gustype == "classic37") { 02142 LOG(LOG_MISC,LOG_DEBUG)("GUS: Classic emulation"); 02143 gus_type = GUS_CLASSIC; 02144 gus_ics_mixer = true; 02145 } 02146 else if (s_gustype == "max") { 02147 // UltraMAX cards do not have the ICS mixer 02148 LOG(LOG_MISC,LOG_DEBUG)("GUS: MAX emulation"); 02149 gus_type = GUS_MAX; 02150 } 02151 else if (s_gustype == "interwave") { 02152 // Neither do Interwave cards 02153 LOG(LOG_MISC,LOG_DEBUG)("GUS: Interwave PnP emulation"); 02154 gus_type = GUS_INTERWAVE; 02155 } 02156 else { 02157 LOG(LOG_MISC,LOG_DEBUG)("GUS: Classic emulation by default"); 02158 gus_type = GUS_CLASSIC; 02159 } 02160 02161 myGUS.clearTCIfPollingIRQStatus = section->Get_bool("clear dma tc irq if excess polling"); 02162 if (myGUS.clearTCIfPollingIRQStatus) 02163 LOG(LOG_MISC,LOG_DEBUG)("GUS: Will clear DMA TC IRQ if excess polling, as instructed"); 02164 02165 myGUS.gUltraMAXControl = 0; 02166 myGUS.lastIRQStatusPollRapidCount = 0; 02167 myGUS.lastIRQStatusPollAt = 0; 02168 02169 myGUS.initUnmaskDMA = section->Get_bool("unmask dma"); 02170 if (myGUS.initUnmaskDMA) 02171 LOG(LOG_MISC,LOG_DEBUG)("GUS: Unmasking DMA at boot time as requested"); 02172 02173 myGUS.fixed_sample_rate_output = section->Get_bool("gus fixed render rate"); 02174 LOG(LOG_MISC,LOG_DEBUG)("GUS: using %s sample rate output",myGUS.fixed_sample_rate_output?"fixed":"realistic"); 02175 02176 myGUS.force_master_irq_enable=section->Get_bool("force master irq enable"); 02177 if (myGUS.force_master_irq_enable) 02178 LOG(LOG_MISC,LOG_DEBUG)("GUS: Master IRQ enable will be forced on as instructed"); 02179 02180 myGUS.rate=(unsigned int)section->Get_int("gusrate"); 02181 02182 ultradir = section->Get_string("ultradir"); 02183 02184 x = section->Get_int("gusmemsize"); 02185 if (x >= 0) myGUS.memsize = (unsigned int)x*1024u; 02186 else myGUS.memsize = 1024u*1024u; 02187 02188 if (myGUS.memsize > (1024u*1024u)) 02189 myGUS.memsize = (1024u*1024u); 02190 02191 if ((myGUS.memsize&((256u << 10u) - 1u)) != 0) 02192 LOG(LOG_MISC,LOG_WARN)("GUS emulation warning: %uKB onboard is an unusual value. Usually GUS cards have some multiple of 256KB RAM onboard",myGUS.memsize>>10); 02193 02194 LOG(LOG_MISC,LOG_DEBUG)("GUS emulation: %uKB onboard",myGUS.memsize>>10); 02195 02196 // some demoscene stuff has music that's way too loud if we render at full volume. 02197 // the GUS mixer emulation won't fix it because it changes the volume at the Mixer 02198 // level AFTER the code has rendered and clipped samples to 16-bit range. 02199 myGUS.masterVolume = section->Get_double("gus master volume"); 02200 myGUS.updateMasterVolume(); 02201 02202 // FIXME: HUH?? Read the port number and subtract 0x200, then use GUS_BASE 02203 // in other parts of the code to compare against 0x200 and 0x300? That's confusing. Fix! 02204 myGUS.portbase = (unsigned int)section->Get_hex("gusbase") - 0x200u; 02205 02206 // TODO: so, if the GUS ULTRASND variable actually mentions two DMA and two IRQ channels, 02207 // shouldn't we offer the ability to specify them independently? especially when 02208 // GUS NMI is completed to the extent that SBOS and MEGA-EM can run within DOSBox? 02209 int dma_val = section->Get_int("gusdma"); 02210 if ((dma_val<0) || (dma_val>255)) dma_val = 3; // sensible default 02211 02212 int irq_val = section->Get_int("gusirq"); 02213 if ((irq_val<0) || (irq_val>255)) irq_val = 5; // sensible default 02214 02215 if (irq_val > 0) { 02216 string s = section->Get_string("irq hack"); 02217 if (!s.empty() && s != "none") { 02218 LOG(LOG_MISC,LOG_NORMAL)("GUS emulation: Assigning IRQ hack '%s' as instruced",s.c_str()); 02219 PIC_Set_IRQ_hack(irq_val,PIC_parse_IRQ_hack_string(s.c_str())); 02220 } 02221 } 02222 02223 myGUS.dma1 = (Bit8u)dma_val; 02224 myGUS.dma2 = (Bit8u)dma_val; 02225 myGUS.irq1 = (Bit8u)irq_val; 02226 myGUS.irq2 = (Bit8u)irq_val; 02227 02228 if (gus_iocallout != IO_Callout_t_none) { 02229 IO_FreeCallout(gus_iocallout); 02230 gus_iocallout = IO_Callout_t_none; 02231 } 02232 02233 if (gus_iocallout2 != IO_Callout_t_none) { 02234 IO_FreeCallout(gus_iocallout2); 02235 gus_iocallout2 = IO_Callout_t_none; 02236 } 02237 02238 if (gus_iocallout == IO_Callout_t_none) 02239 gus_iocallout = IO_AllocateCallout(IO_TYPE_ISA); 02240 if (gus_iocallout == IO_Callout_t_none) 02241 E_Exit("Failed to get GUS IO callout handle"); 02242 02243 if (gus_iocallout2 == IO_Callout_t_none) 02244 gus_iocallout2 = IO_AllocateCallout(IO_TYPE_ISA); 02245 if (gus_iocallout2 == IO_Callout_t_none) 02246 E_Exit("Failed to get GUS IO callout handle"); 02247 02248 { 02249 IO_CalloutObject *obj = IO_GetCallout(gus_iocallout); 02250 if (obj == NULL) E_Exit("Failed to get GUS IO callout"); 02251 obj->Install(0x200 + GUS_BASE,IOMASK_Combine(IOMASK_ISA_10BIT,IOMASK_Range(16)),gus_cb_port_r,gus_cb_port_w); 02252 IO_PutCallout(obj); 02253 } 02254 02255 { 02256 IO_CalloutObject *obj = IO_GetCallout(gus_iocallout2); 02257 if (obj == NULL) E_Exit("Failed to get GUS IO callout"); 02258 obj->Install(0x300 + GUS_BASE,IOMASK_Combine(IOMASK_ISA_10BIT,IOMASK_Range(16)),gus_cb_port_r,gus_cb_port_w); 02259 IO_PutCallout(obj); 02260 } 02261 02262 #if 0 02263 // We'll leave the MIDI interface to the MPU-401 02264 // Ditto for the Joystick 02265 // GF1 Synthesizer 02266 ReadHandler[0].Install(0x302 + GUS_BASE,read_gus,IO_MB); 02267 WriteHandler[0].Install(0x302 + GUS_BASE,write_gus,IO_MB); 02268 02269 WriteHandler[1].Install(0x303 + GUS_BASE,write_gus,IO_MB); 02270 ReadHandler[1].Install(0x303 + GUS_BASE,read_gus,IO_MB); 02271 02272 WriteHandler[2].Install(0x304 + GUS_BASE,write_gus,IO_MB|IO_MW); 02273 ReadHandler[2].Install(0x304 + GUS_BASE,read_gus,IO_MB|IO_MW); 02274 02275 WriteHandler[3].Install(0x305 + GUS_BASE,write_gus,IO_MB); 02276 ReadHandler[3].Install(0x305 + GUS_BASE,read_gus,IO_MB); 02277 02278 ReadHandler[4].Install(0x206 + GUS_BASE,read_gus,IO_MB); 02279 02280 WriteHandler[4].Install(0x208 + GUS_BASE,write_gus,IO_MB); 02281 ReadHandler[5].Install(0x208 + GUS_BASE,read_gus,IO_MB); 02282 02283 WriteHandler[5].Install(0x209 + GUS_BASE,write_gus,IO_MB); 02284 02285 WriteHandler[6].Install(0x307 + GUS_BASE,write_gus,IO_MB); 02286 ReadHandler[6].Install(0x307 + GUS_BASE,read_gus,IO_MB); 02287 02288 // Board Only 02289 02290 WriteHandler[7].Install(0x200 + GUS_BASE,write_gus,IO_MB); 02291 ReadHandler[7].Install(0x20A + GUS_BASE,read_gus,IO_MB); 02292 WriteHandler[8].Install(0x20B + GUS_BASE,write_gus,IO_MB); 02293 02294 if (gus_type >= GUS_MAX || gus_ics_mixer/*classic with 3.7 mixer*/) { 02295 /* "This register is only valid for UltraSound boards that are at or above revision 3.4. It is not valid for boards which 02296 * have a prior revision number. 02297 * On 3.4 and above boards, there is a bank of 6 registers that exist at location 2XB. Register 2XF is used to select 02298 * which one is being talked to." */ 02299 ReadHandler[9].Install(0x20F + GUS_BASE,read_gus,IO_MB); 02300 WriteHandler[9].Install(0x20F + GUS_BASE,write_gus,IO_MB); 02301 02302 /* FIXME: I'm not so sure Interwave PnP cards have this */ 02303 ReadHandler[10].Install(0x306 + GUS_BASE,read_gus,IO_MB); // Revision level 02304 ReadHandler[11].Install(0x706 + GUS_BASE,read_gus,IO_MB); // Revision level 02305 WriteHandler[10].Install(0x306 + GUS_BASE,write_gus,IO_MB); // Mixer control 02306 WriteHandler[11].Install(0x706 + GUS_BASE,write_gus,IO_MB); // Mixer data / GUS UltraMAX Control register 02307 } 02308 #endif 02309 if (gus_type >= GUS_MAX) { 02310 LOG(LOG_MISC,LOG_WARN)("GUS caution: CS4231 UltraMax emulation is new and experimental at this time and it is not guaranteed to work."); 02311 LOG(LOG_MISC,LOG_WARN)("GUS caution: CS4231 UltraMax emulation as it exists now may cause applications to hang or malfunction attempting to play through it."); 02312 02313 #if 0 02314 /* UltraMax has a CS4231 codec at 3XC-3XF */ 02315 /* FIXME: Does the Interwave have a CS4231? */ 02316 for (unsigned int i=0;i < 4;i++) { 02317 ReadCS4231Handler[i].Install(0x30C + i + GUS_BASE,read_gus_cs4231,IO_MB); 02318 WriteCS4231Handler[i].Install(0x30C + i + GUS_BASE,write_gus_cs4231,IO_MB); 02319 } 02320 #endif 02321 } 02322 02323 // DmaChannels[myGUS.dma1]->Register_TC_Callback(GUS_DMA_TC_Callback); 02324 02325 MakeTables(); 02326 02327 for (Bit8u chan_ct=0; chan_ct<32; chan_ct++) { 02328 guschan[chan_ct] = new GUSChannels(chan_ct); 02329 } 02330 // Register the Mixer CallBack 02331 gus_chan=MixerChan.Install(GUS_CallBack,GUS_RATE,"GUS"); 02332 02333 // FIXME: Could we leave the card in reset state until a fake ULTRINIT runs? 02334 myGUS.gRegData=0x000/*reset*/; 02335 GUSReset(); 02336 02337 if (myGUS.initUnmaskDMA) 02338 GetDMAChannel(myGUS.dma1)->SetMask(false); 02339 if (unmask_irq) 02340 PIC_SetIRQMask(myGUS.irq1,false); 02341 02342 gus_chan->Enable(true); 02343 02344 GetDMAChannel(myGUS.dma1)->Register_Callback(GUS_DMA_Callback); 02345 02346 if (gus_ics_mixer) { 02347 // pre-set ourself as if ULTRINIT and ULTRAMIX had been run 02348 GUS_ICS2101.mixpair[gus_ICS2101::MIC_IN_PORT].setAttenuation(0,0x7F); 02349 GUS_ICS2101.mixpair[gus_ICS2101::MIC_IN_PORT].setAttenuation(1,0x7F); 02350 GUS_ICS2101.mixpair[gus_ICS2101::LINE_IN_PORT].setAttenuation(0,0x7F); 02351 GUS_ICS2101.mixpair[gus_ICS2101::LINE_IN_PORT].setAttenuation(1,0x7F); 02352 GUS_ICS2101.mixpair[gus_ICS2101::CD_IN_PORT].setAttenuation(0,0x7F); 02353 GUS_ICS2101.mixpair[gus_ICS2101::CD_IN_PORT].setAttenuation(1,0x7F); 02354 GUS_ICS2101.mixpair[gus_ICS2101::GF1_OUT_PORT].setAttenuation(0,0x7F); 02355 GUS_ICS2101.mixpair[gus_ICS2101::GF1_OUT_PORT].setAttenuation(1,0x7F); 02356 GUS_ICS2101.mixpair[gus_ICS2101::MASTER_OUTPUT_PORT].setAttenuation(0,0x7F); 02357 GUS_ICS2101.mixpair[gus_ICS2101::MASTER_OUTPUT_PORT].setAttenuation(1,0x7F); 02358 02359 // master volume update, updates ALL pairs 02360 GUS_ICS2101.updateVolPair(gus_ICS2101::MASTER_OUTPUT_PORT); 02361 } 02362 02363 // Default to GUS MAX 1MB maximum 02364 myGUS.gDramAddrMask = 0xFFFFF; 02365 02366 // if instructed, configure the card as if ULTRINIT had been run 02367 if (startup_ultrinit) { 02368 myGUS.gRegData=0x700; 02369 GUSReset(); 02370 02371 myGUS.gRegData=0x700; 02372 GUSReset(); 02373 } 02374 } 02375 02376 void DOS_Startup() { 02377 int portat = 0x200 + int(GUS_BASE); 02378 02379 if (!gus_enable) return; 02380 02381 // ULTRASND=Port,DMA1,DMA2,IRQ1,IRQ2 02382 // [GUS port], [GUS DMA (recording)], [GUS DMA (playback)], [GUS IRQ (playback)], [GUS IRQ (MIDI)] 02383 ostringstream temp; 02384 temp << "@SET ULTRASND=" << hex << setw(3) << portat << "," 02385 << dec << (Bitu)myGUS.dma1 << "," << (Bitu)myGUS.dma2 << "," 02386 << (Bitu)myGUS.irq1 << "," << (Bitu)myGUS.irq2 << ends; 02387 // Create autoexec.bat lines 02388 autoexecline[0].Install(temp.str()); 02389 autoexecline[1].Install(std::string("@SET ULTRADIR=") + ultradir); 02390 02391 if (gus_type >= GUS_MAX) { 02392 /* FIXME: Does the Interwave have a CS4231? */ 02393 ostringstream temp2; 02394 temp2 << "@SET ULTRA16=" << hex << setw(3) << (0x30C+GUS_BASE) << "," 02395 << "0,0,1,0" << ends; // FIXME What do these numbers mean? 02396 autoexecline[2].Install(temp2.str()); 02397 } 02398 } 02399 02400 std::string ultradir; 02401 02402 void DOS_Shutdown() { /* very likely, we're booting into a guest OS where our environment variable has no meaning anymore */ 02403 autoexecline[0].Uninstall(); 02404 autoexecline[1].Uninstall(); 02405 autoexecline[2].Uninstall(); 02406 } 02407 02408 ~GUS() { 02409 if (gus_iocallout != IO_Callout_t_none) { 02410 IO_FreeCallout(gus_iocallout); 02411 gus_iocallout = IO_Callout_t_none; 02412 } 02413 02414 if (gus_iocallout2 != IO_Callout_t_none) { 02415 IO_FreeCallout(gus_iocallout2); 02416 gus_iocallout2 = IO_Callout_t_none; 02417 } 02418 02419 #if 0 // FIXME 02420 if(!IS_EGAVGA_ARCH) return; 02421 02422 myGUS.gRegData=0x1; 02423 GUSReset(); 02424 myGUS.gRegData=0x0; 02425 02426 for(Bitu i=0;i<32;i++) { 02427 delete guschan[i]; 02428 } 02429 02430 memset(&myGUS,0,sizeof(myGUS)); 02431 memset(GUSRam,0,1024*1024); 02432 #endif 02433 } 02434 }; 02435 02436 static GUS* test = NULL; 02437 02438 void GUS_DOS_Shutdown() { 02439 if (test != NULL) test->DOS_Shutdown(); 02440 } 02441 02442 void GUS_ShutDown(Section* /*sec*/) { 02443 if (test != NULL) { 02444 delete test; 02445 test = NULL; 02446 } 02447 } 02448 02449 void GUS_OnReset(Section *sec) { 02450 (void)sec;//UNUSED 02451 if (test == NULL && !IS_PC98_ARCH) { 02452 LOG(LOG_MISC,LOG_DEBUG)("Allocating GUS emulation"); 02453 test = new GUS(control->GetSection("gus")); 02454 } 02455 } 02456 02457 void GUS_DOS_Exit(Section *sec) { 02458 (void)sec;//UNUSED 02459 GUS_DOS_Shutdown(); 02460 } 02461 02462 void GUS_DOS_Boot(Section *sec) { 02463 (void)sec;//UNUSED 02464 if (test != NULL) test->DOS_Startup(); 02465 } 02466 02467 void GUS_Init() { 02468 LOG(LOG_MISC,LOG_DEBUG)("Initializing Gravis Ultrasound emulation"); 02469 02470 AddExitFunction(AddExitFunctionFuncPair(GUS_ShutDown),true); 02471 AddVMEventFunction(VM_EVENT_RESET,AddVMEventFunctionFuncPair(GUS_OnReset)); 02472 AddVMEventFunction(VM_EVENT_DOS_EXIT_BEGIN,AddVMEventFunctionFuncPair(GUS_DOS_Exit)); 02473 AddVMEventFunction(VM_EVENT_DOS_SURPRISE_REBOOT,AddVMEventFunctionFuncPair(GUS_DOS_Exit)); 02474 AddVMEventFunction(VM_EVENT_DOS_EXIT_REBOOT_BEGIN,AddVMEventFunctionFuncPair(GUS_DOS_Exit)); 02475 AddVMEventFunction(VM_EVENT_DOS_INIT_SHELL_READY,AddVMEventFunctionFuncPair(GUS_DOS_Boot)); 02476 } 02477 02478 // save state support 02479 void *GUS_TimerEvent_PIC_Event = (void*)((uintptr_t)GUS_TimerEvent); 02480 void *GUS_DMA_Callback_Func = (void*)((uintptr_t)GUS_DMA_Callback); 02481 02482 02483 void POD_Save_GUS( std::ostream& stream ) 02484 { 02485 const char pod_name[32] = "GUS"; 02486 02487 if( stream.fail() ) return; 02488 if( !test ) return; 02489 if( !gus_chan ) return; 02490 02491 02492 WRITE_POD( &pod_name, pod_name ); 02493 02494 //******************************************* 02495 //******************************************* 02496 //******************************************* 02497 02498 Bit8u curchan_idx; 02499 02500 curchan_idx = 0xff; 02501 for( int lcv=0; lcv<32; lcv++ ) { 02502 if( curchan == guschan[lcv] ) { curchan_idx = lcv; break; } 02503 } 02504 02505 // ******************************************* 02506 // ******************************************* 02507 // ******************************************* 02508 02509 // - pure data 02510 WRITE_POD( &adlib_commandreg, adlib_commandreg ); 02511 WRITE_POD( &GUSRam, GUSRam ); 02512 WRITE_POD( &vol16bit, vol16bit ); 02513 WRITE_POD( &pantable, pantable ); 02514 02515 // - pure struct data 02516 WRITE_POD( &myGUS, myGUS ); 02517 02518 02519 // - pure data 02520 for( int lcv=0; lcv<32; lcv++ ) { 02521 WRITE_POD( guschan[lcv], *guschan[lcv] ); 02522 } 02523 02524 // ******************************************* 02525 // ******************************************* 02526 // ******************************************* 02527 02528 // - reloc ptr 02529 WRITE_POD( &curchan_idx, curchan_idx ); 02530 02531 // ******************************************* 02532 // ******************************************* 02533 // ******************************************* 02534 02535 gus_chan->SaveState(stream); 02536 } 02537 02538 02539 void POD_Load_GUS( std::istream& stream ) 02540 { 02541 char pod_name[32] = {0}; 02542 02543 if( stream.fail() ) return; 02544 if( !test ) return; 02545 if( !gus_chan ) return; 02546 02547 02548 // error checking 02549 READ_POD( &pod_name, pod_name ); 02550 if( strcmp( pod_name, "GUS" ) ) { 02551 stream.clear( std::istream::failbit | std::istream::badbit ); 02552 return; 02553 } 02554 02555 //************************************************ 02556 //************************************************ 02557 //************************************************ 02558 02559 Bit8u curchan_idx; 02560 02561 //******************************************* 02562 //******************************************* 02563 //******************************************* 02564 02565 // - pure data 02566 READ_POD( &adlib_commandreg, adlib_commandreg ); 02567 READ_POD( &GUSRam, GUSRam ); 02568 READ_POD( &vol16bit, vol16bit ); 02569 READ_POD( &pantable, pantable ); 02570 02571 READ_POD( &myGUS, myGUS ); 02572 02573 for( int lcv=0; lcv<32; lcv++ ) { 02574 if( !guschan[lcv] ) continue; 02575 02576 READ_POD( guschan[lcv], *guschan[lcv] ); 02577 } 02578 02579 02580 02581 // - reloc ptr 02582 READ_POD( &curchan_idx, curchan_idx ); 02583 02584 //******************************************* 02585 //******************************************* 02586 //******************************************* 02587 02588 curchan = NULL; 02589 if( curchan_idx != 0xff ) curchan = guschan[curchan_idx]; 02590 02591 //******************************************* 02592 //******************************************* 02593 //******************************************* 02594 02595 gus_chan->LoadState(stream); 02596 }