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