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