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