symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/gusemu_hal.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * GUSEMU32 - bus interface part
       
     3  *
       
     4  * Copyright (C) 2000-2007 Tibor "TS" Schütz
       
     5  *
       
     6  * Permission is hereby granted, free of charge, to any person obtaining a copy
       
     7  * of this software and associated documentation files (the "Software"), to deal
       
     8  * in the Software without restriction, including without limitation the rights
       
     9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       
    10  * copies of the Software, and to permit persons to whom the Software is
       
    11  * furnished to do so, subject to the following conditions:
       
    12  *
       
    13  * The above copyright notice and this permission notice shall be included in
       
    14  * all copies or substantial portions of the Software.
       
    15  *
       
    16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       
    17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       
    18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
       
    19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       
    20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       
    21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
       
    22  * THE SOFTWARE.
       
    23  */
       
    24 
       
    25 /*
       
    26  * TODO: check mixer: see 7.20 of sdk for panning pos (applies to all gus models?)?
       
    27  */
       
    28 
       
    29 #include "gustate.h"
       
    30 #include "gusemu.h"
       
    31 
       
    32 #define GUSregb(position) (*            (gusptr+(position)))
       
    33 #define GUSregw(position) (*(GUSword *) (gusptr+(position)))
       
    34 #define GUSregd(position) (*(GUSdword *)(gusptr+(position)))
       
    35 
       
    36 /* size given in bytes */
       
    37 unsigned int gus_read(GUSEmuState * state, int port, int size)
       
    38 {
       
    39     int             value_read = 0;
       
    40 
       
    41     GUSbyte        *gusptr;
       
    42     gusptr = state->gusdatapos;
       
    43     GUSregd(portaccesses)++;
       
    44 
       
    45     switch (port & 0xff0f)
       
    46     {
       
    47         /* MixerCtrlReg (read not supported on GUS classic) */
       
    48         /* case 0x200: return GUSregb(MixerCtrlReg2x0); */
       
    49     case 0x206:                          /* IRQstatReg / SB2x6IRQ */
       
    50         /* adlib/sb bits set in port handlers */
       
    51         /* timer/voice bits set in gus_irqgen() */
       
    52         /* dma bit set in gus_dma_transferdata */
       
    53         /* midi not implemented yet */
       
    54         return GUSregb(IRQStatReg2x6);
       
    55     /* case 0x308:                       */ /* AdLib388 */
       
    56     case 0x208:
       
    57         if (GUSregb(GUS45TimerCtrl) & 1)
       
    58             return GUSregb(TimerStatus2x8);
       
    59         return GUSregb(AdLibStatus2x8);  /* AdLibStatus */
       
    60     case 0x309:                          /* AdLib389 */
       
    61     case 0x209:
       
    62         return GUSregb(AdLibData2x9);    /* AdLibData */
       
    63     case 0x20A:
       
    64         return GUSregb(AdLibCommand2xA); /* AdLib2x8_2xA */
       
    65 
       
    66 #if 0
       
    67     case 0x20B:                          /* GUS hidden registers (read not supported on GUS classic) */
       
    68         switch (GUSregb(RegCtrl_2xF) & 0x07)
       
    69         {
       
    70         case 0:                                 /* IRQ/DMA select */
       
    71             if (GUSregb(MixerCtrlReg2x0) & 0x40)
       
    72                 return GUSregb(IRQ_2xB);        /* control register select bit */
       
    73             else
       
    74                 return GUSregb(DMA_2xB);
       
    75             /* case 1-5:                        */ /* general purpose emulation regs  */
       
    76             /*  return ...                      */ /* + status reset reg (write only) */
       
    77         case 6:
       
    78             return GUSregb(Jumper_2xB);         /* Joystick/MIDI enable (JumperReg) */
       
    79         default:;
       
    80         }
       
    81         break;
       
    82 #endif
       
    83 
       
    84     case 0x20C:                          /* SB2xCd */
       
    85         value_read = GUSregb(SB2xCd);
       
    86         if (GUSregb(StatRead_2xF) & 0x20)
       
    87             GUSregb(SB2xCd) ^= 0x80; /* toggle MSB on read */
       
    88         return value_read;
       
    89         /* case 0x20D:                   */ /* SB2xD is write only -> 2xE writes to it*/
       
    90     case 0x20E:
       
    91         if (GUSregb(RegCtrl_2xF) & 0x80) /* 2xE read IRQ enabled? */
       
    92         {
       
    93             GUSregb(StatRead_2xF) |= 0x80;
       
    94             GUS_irqrequest(state, state->gusirq, 1);
       
    95         }
       
    96         return GUSregb(SB2xE);           /* SB2xE */
       
    97     case 0x20F:                          /* StatRead_2xF */
       
    98         /*set/clear fixed bits */
       
    99         /*value_read = (GUSregb(StatRead_2xF) & 0xf9)|1; */ /*(LSB not set on GUS classic!)*/
       
   100         value_read = (GUSregb(StatRead_2xF) & 0xf9);
       
   101         if (GUSregb(MixerCtrlReg2x0) & 0x08)
       
   102             value_read |= 2;    /* DMA/IRQ enabled flag */
       
   103         return value_read;
       
   104     /* case 0x300:                      */ /* MIDI (not implemented) */
       
   105     /* case 0x301:                      */ /* MIDI (not implemented) */
       
   106     case 0x302:
       
   107         return GUSregb(VoiceSelReg3x2); /* VoiceSelReg */
       
   108     case 0x303:
       
   109         return GUSregb(FunkSelReg3x3);  /* FunkSelReg */
       
   110     case 0x304:                         /* DataRegLoByte3x4 + DataRegWord3x4 */
       
   111     case 0x305:                         /* DataRegHiByte3x5 */
       
   112         switch (GUSregb(FunkSelReg3x3))
       
   113         {
       
   114     /* common functions */
       
   115         case 0x41:                      /* DramDMAContrReg */
       
   116             value_read = GUSregb(GUS41DMACtrl); /* &0xfb */
       
   117             GUSregb(GUS41DMACtrl) &= 0xbb;
       
   118             if (state->gusdma >= 4)
       
   119                 value_read |= 0x04;
       
   120             if (GUSregb(IRQStatReg2x6) & 0x80)
       
   121             {
       
   122                 value_read |= 0x40;
       
   123                 GUSregb(IRQStatReg2x6) &= 0x7f;
       
   124                 if (!GUSregb(IRQStatReg2x6))
       
   125                     GUS_irqclear(state, state->gusirq);
       
   126             }
       
   127             return (GUSbyte) value_read;
       
   128             /* DramDMAmemPosReg */
       
   129             /* case 0x42: value_read=GUSregw(GUS42DMAStart); break;*/
       
   130             /* 43h+44h write only */
       
   131         case 0x45:
       
   132             return GUSregb(GUS45TimerCtrl);         /* TimerCtrlReg */
       
   133             /* 46h+47h write only */
       
   134             /* 48h: samp freq - write only */
       
   135         case 0x49:
       
   136             return GUSregb(GUS49SampCtrl) & 0xbf;   /* SampCtrlReg */
       
   137         /* case 4bh:                                */ /* joystick trim not supported */
       
   138         /* case 0x4c: return GUSregb(GUS4cReset);   */ /* GUSreset: write only*/
       
   139     /* voice specific functions */
       
   140         case 0x80:
       
   141         case 0x81:
       
   142         case 0x82:
       
   143         case 0x83:
       
   144         case 0x84:
       
   145         case 0x85:
       
   146         case 0x86:
       
   147         case 0x87:
       
   148         case 0x88:
       
   149         case 0x89:
       
   150         case 0x8a:
       
   151         case 0x8b:
       
   152         case 0x8c:
       
   153         case 0x8d:
       
   154             {
       
   155                 int             offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
       
   156                 offset += ((int) GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */
       
   157                 value_read = GUSregw(offset);
       
   158             }
       
   159             break;
       
   160     /* voice unspecific functions */
       
   161         case 0x8e:                                  /* NumVoice */
       
   162             return GUSregb(NumVoices);
       
   163         case 0x8f:                                  /* irqstatreg */
       
   164             /* (pseudo IRQ-FIFO is processed during a gus_write(0x3X3,0x8f)) */
       
   165             return GUSregb(SynVoiceIRQ8f);
       
   166         default:
       
   167             return 0xffff;
       
   168         }
       
   169         if (size == 1)
       
   170         {
       
   171             if ((port & 0xff0f) == 0x305)
       
   172                 value_read = value_read >> 8;
       
   173             value_read &= 0xff;
       
   174         }
       
   175         return (GUSword) value_read;
       
   176     /* case 0x306:                                  */ /* Mixer/Version info */
       
   177         /*  return 0xff; */ /* Pre 3.6 boards, ICS mixer NOT present */
       
   178     case 0x307:                                     /* DRAMaccess */
       
   179         {
       
   180             GUSbyte        *adr;
       
   181             adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
       
   182             return *adr;
       
   183         }
       
   184     default:;
       
   185     }
       
   186     return 0xffff;
       
   187 }
       
   188 
       
   189 void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
       
   190 {
       
   191     GUSbyte        *gusptr;
       
   192     gusptr = state->gusdatapos;
       
   193     GUSregd(portaccesses)++;
       
   194 
       
   195     switch (port & 0xff0f)
       
   196     {
       
   197     case 0x200:                 /* MixerCtrlReg */
       
   198         GUSregb(MixerCtrlReg2x0) = (GUSbyte) data;
       
   199         break;
       
   200     case 0x206:                 /* IRQstatReg / SB2x6IRQ */
       
   201         if (GUSregb(GUS45TimerCtrl) & 0x20) /* SB IRQ enabled? -> set 2x6IRQ bit */
       
   202         {
       
   203             GUSregb(TimerStatus2x8) |= 0x08;
       
   204             GUSregb(IRQStatReg2x6) = 0x10;
       
   205             GUS_irqrequest(state, state->gusirq, 1);
       
   206         }
       
   207         break;
       
   208     case 0x308:                /* AdLib 388h */
       
   209     case 0x208:                /* AdLibCommandReg */
       
   210         GUSregb(AdLibCommand2xA) = (GUSbyte) data;
       
   211         break;
       
   212     case 0x309:                /* AdLib 389h */
       
   213     case 0x209:                /* AdLibDataReg */
       
   214         if ((GUSregb(AdLibCommand2xA) == 0x04) && (!(GUSregb(GUS45TimerCtrl) & 1))) /* GUS auto timer mode enabled? */
       
   215         {
       
   216             if (data & 0x80)
       
   217                 GUSregb(TimerStatus2x8) &= 0x1f; /* AdLib IRQ reset? -> clear maskable adl. timer int regs */
       
   218             else
       
   219                 GUSregb(TimerDataReg2x9) = (GUSbyte) data;
       
   220         }
       
   221         else
       
   222         {
       
   223             GUSregb(AdLibData2x9) = (GUSbyte) data;
       
   224             if (GUSregb(GUS45TimerCtrl) & 0x02)
       
   225             {
       
   226                 GUSregb(TimerStatus2x8) |= 0x01;
       
   227                 GUSregb(IRQStatReg2x6) = 0x10;
       
   228                 GUS_irqrequest(state, state->gusirq, 1);
       
   229             }
       
   230         }
       
   231         break;
       
   232     case 0x20A:
       
   233         GUSregb(AdLibStatus2x8) = (GUSbyte) data;
       
   234         break;                 /* AdLibStatus2x8 */
       
   235     case 0x20B:                /* GUS hidden registers */
       
   236         switch (GUSregb(RegCtrl_2xF) & 0x7)
       
   237         {
       
   238         case 0:
       
   239             if (GUSregb(MixerCtrlReg2x0) & 0x40)
       
   240                 GUSregb(IRQ_2xB) = (GUSbyte) data; /* control register select bit */
       
   241             else
       
   242                 GUSregb(DMA_2xB) = (GUSbyte) data;
       
   243             break;
       
   244             /* case 1-4: general purpose emulation regs */
       
   245         case 5:                                    /* clear stat reg 2xF */
       
   246             GUSregb(StatRead_2xF) = 0; /* ToDo: is this identical with GUS classic? */
       
   247             if (!GUSregb(IRQStatReg2x6))
       
   248                 GUS_irqclear(state, state->gusirq);
       
   249             break;
       
   250         case 6:                                    /* Jumper reg (Joystick/MIDI enable) */
       
   251             GUSregb(Jumper_2xB) = (GUSbyte) data;
       
   252             break;
       
   253         default:;
       
   254         }
       
   255         break;
       
   256     case 0x20C:                /* SB2xCd */
       
   257         if (GUSregb(GUS45TimerCtrl) & 0x20)
       
   258         {
       
   259             GUSregb(TimerStatus2x8) |= 0x10; /* SB IRQ enabled? -> set 2xCIRQ bit */
       
   260             GUSregb(IRQStatReg2x6) = 0x10;
       
   261             GUS_irqrequest(state, state->gusirq, 1);
       
   262         }
       
   263     case 0x20D:                /* SB2xCd no IRQ */
       
   264         GUSregb(SB2xCd) = (GUSbyte) data;
       
   265         break;
       
   266     case 0x20E:                /* SB2xE */
       
   267         GUSregb(SB2xE) = (GUSbyte) data;
       
   268         break;
       
   269     case 0x20F:
       
   270         GUSregb(RegCtrl_2xF) = (GUSbyte) data;
       
   271         break;                 /* CtrlReg2xF */
       
   272     case 0x302:                /* VoiceSelReg */
       
   273         GUSregb(VoiceSelReg3x2) = (GUSbyte) data;
       
   274         break;
       
   275     case 0x303:                /* FunkSelReg */
       
   276         GUSregb(FunkSelReg3x3) = (GUSbyte) data;
       
   277         if ((GUSbyte) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */
       
   278         {
       
   279             int             voice;
       
   280             if (GUSregd(voicewavetableirq)) /* WavetableIRQ */
       
   281             {
       
   282                 for (voice = 0; voice < 31; voice++)
       
   283                 {
       
   284                     if (GUSregd(voicewavetableirq) & (1 << voice))
       
   285                     {
       
   286                         GUSregd(voicewavetableirq) ^= (1 << voice); /* clear IRQ bit */
       
   287                         GUSregb(voice << 5) &= 0x7f; /* clear voice reg irq bit */
       
   288                         if (!GUSregd(voicewavetableirq))
       
   289                             GUSregb(IRQStatReg2x6) &= 0xdf;
       
   290                         if (!GUSregb(IRQStatReg2x6))
       
   291                             GUS_irqclear(state, state->gusirq);
       
   292                         GUSregb(SynVoiceIRQ8f) = voice | 0x60; /* (bit==0 => IRQ wartend) */
       
   293                         return;
       
   294                     }
       
   295                 }
       
   296             }
       
   297             else if (GUSregd(voicevolrampirq)) /* VolRamp IRQ */
       
   298             {
       
   299                 for (voice = 0; voice < 31; voice++)
       
   300                 {
       
   301                     if (GUSregd(voicevolrampirq) & (1 << voice))
       
   302                     {
       
   303                         GUSregd(voicevolrampirq) ^= (1 << voice); /* clear IRQ bit */
       
   304                         GUSregb((voice << 5) + VSRVolRampControl) &= 0x7f; /* clear voice volume reg irq bit */
       
   305                         if (!GUSregd(voicevolrampirq))
       
   306                             GUSregb(IRQStatReg2x6) &= 0xbf;
       
   307                         if (!GUSregb(IRQStatReg2x6))
       
   308                             GUS_irqclear(state, state->gusirq);
       
   309                         GUSregb(SynVoiceIRQ8f) = voice | 0x80; /* (bit==0 => IRQ wartend) */
       
   310                         return;
       
   311                     }
       
   312                 }
       
   313             }
       
   314             GUSregb(SynVoiceIRQ8f) = 0xe8; /* kein IRQ wartet */
       
   315         }
       
   316         break;
       
   317     case 0x304:
       
   318     case 0x305:
       
   319         {
       
   320             GUSword         writedata = (GUSword) data;
       
   321             GUSword         readmask = 0x0000;
       
   322             if (size == 1)
       
   323             {
       
   324                 readmask = 0xff00;
       
   325                 writedata &= 0xff;
       
   326                 if ((port & 0xff0f) == 0x305)
       
   327                 {
       
   328                     writedata = (GUSword) (writedata << 8);
       
   329                     readmask = 0x00ff;
       
   330                 }
       
   331             }
       
   332             switch (GUSregb(FunkSelReg3x3))
       
   333             {
       
   334                 /* voice specific functions */
       
   335             case 0x00:
       
   336             case 0x01:
       
   337             case 0x02:
       
   338             case 0x03:
       
   339             case 0x04:
       
   340             case 0x05:
       
   341             case 0x06:
       
   342             case 0x07:
       
   343             case 0x08:
       
   344             case 0x09:
       
   345             case 0x0a:
       
   346             case 0x0b:
       
   347             case 0x0c:
       
   348             case 0x0d:
       
   349                 {
       
   350                     int             offset;
       
   351                     if (!(GUSregb(GUS4cReset) & 0x01))
       
   352                         break;  /* reset flag active? */
       
   353                     offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
       
   354                     offset += (GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /*  = Voice*32 + Funktion*2 */
       
   355                     GUSregw(offset) = (GUSword) ((GUSregw(offset) & readmask) | writedata);
       
   356                 }
       
   357                 break;
       
   358                 /* voice unspecific functions */
       
   359             case 0x0e:         /* NumVoices */
       
   360                 GUSregb(NumVoices) = (GUSbyte) data;
       
   361                 break;
       
   362             /* case 0x0f:      */ /* read only */
       
   363                 /* common functions */
       
   364             case 0x41:         /* DramDMAContrReg */
       
   365                 GUSregb(GUS41DMACtrl) = (GUSbyte) data;
       
   366                 if (data & 0x01)
       
   367                     GUS_dmarequest(state);
       
   368                 break;
       
   369             case 0x42:         /* DramDMAmemPosReg */
       
   370                 GUSregw(GUS42DMAStart) = (GUSregw(GUS42DMAStart) & readmask) | writedata;
       
   371                 GUSregb(GUS50DMAHigh) &= 0xf; /* compatibility stuff... */
       
   372                 break;
       
   373             case 0x43:         /* DRAMaddrLo */
       
   374                 GUSregd(GUSDRAMPOS24bit) =
       
   375                     (GUSregd(GUSDRAMPOS24bit) & (readmask | 0xff0000)) | writedata;
       
   376                 break;
       
   377             case 0x44:         /* DRAMaddrHi */
       
   378                 GUSregd(GUSDRAMPOS24bit) =
       
   379                     (GUSregd(GUSDRAMPOS24bit) & 0xffff) | ((data & 0x0f) << 16);
       
   380                 break;
       
   381             case 0x45:         /* TCtrlReg */
       
   382                 GUSregb(GUS45TimerCtrl) = (GUSbyte) data;
       
   383                 if (!(data & 0x20))
       
   384                     GUSregb(TimerStatus2x8) &= 0xe7;    /* sb IRQ dis? -> clear 2x8/2xC sb IRQ flags */
       
   385                 if (!(data & 0x02))
       
   386                     GUSregb(TimerStatus2x8) &= 0xfe;    /* adlib data IRQ dis? -> clear 2x8 adlib IRQ flag */
       
   387                 if (!(GUSregb(TimerStatus2x8) & 0x19))
       
   388                     GUSregb(IRQStatReg2x6) &= 0xef;     /* 0xe6; $$clear IRQ if both IRQ bits are inactive or cleared */
       
   389                 /* catch up delayed timer IRQs: */
       
   390                 if ((GUSregw(TimerIRQs) > 1) && (GUSregb(TimerDataReg2x9) & 3))
       
   391                 {
       
   392                     if (GUSregb(TimerDataReg2x9) & 1)   /* start timer 1 (80us decrement rate) */
       
   393                     {
       
   394                         if (!(GUSregb(TimerDataReg2x9) & 0x40))
       
   395                             GUSregb(TimerStatus2x8) |= 0xc0;    /* maskable bits */
       
   396                         if (data & 4) /* timer1 irq enable */
       
   397                         {
       
   398                             GUSregb(TimerStatus2x8) |= 4;       /* nonmaskable bit */
       
   399                             GUSregb(IRQStatReg2x6) |= 4;        /* timer 1 irq pending */
       
   400                         }
       
   401                     }
       
   402                     if (GUSregb(TimerDataReg2x9) & 2)   /* start timer 2 (320us decrement rate) */
       
   403                     {
       
   404                         if (!(GUSregb(TimerDataReg2x9) & 0x20))
       
   405                             GUSregb(TimerStatus2x8) |= 0xa0;    /* maskable bits */
       
   406                         if (data & 8) /* timer2 irq enable */
       
   407                         {
       
   408                             GUSregb(TimerStatus2x8) |= 2;       /* nonmaskable bit */
       
   409                             GUSregb(IRQStatReg2x6) |= 8;        /* timer 2 irq pending */
       
   410                         }
       
   411                     }
       
   412                     GUSregw(TimerIRQs)--;
       
   413                     if (GUSregw(BusyTimerIRQs) > 1)
       
   414                         GUSregw(BusyTimerIRQs)--;
       
   415                     else
       
   416                         GUSregw(BusyTimerIRQs) =
       
   417                             GUS_irqrequest(state, state->gusirq, GUSregw(TimerIRQs));
       
   418                 }
       
   419                 else
       
   420                     GUSregw(TimerIRQs) = 0;
       
   421 
       
   422                 if (!(data & 0x04))
       
   423                 {
       
   424                     GUSregb(TimerStatus2x8) &= 0xfb; /* clear non-maskable timer1 bit */
       
   425                     GUSregb(IRQStatReg2x6)  &= 0xfb;
       
   426                 }
       
   427                 if (!(data & 0x08))
       
   428                 {
       
   429                     GUSregb(TimerStatus2x8) &= 0xfd; /* clear non-maskable timer2 bit */
       
   430                     GUSregb(IRQStatReg2x6)  &= 0xf7;
       
   431                 }
       
   432                 if (!GUSregb(IRQStatReg2x6))
       
   433                     GUS_irqclear(state, state->gusirq);
       
   434                 break;
       
   435             case 0x46:          /* Counter1 */
       
   436                 GUSregb(GUS46Counter1) = (GUSbyte) data;
       
   437                 break;
       
   438             case 0x47:          /* Counter2 */
       
   439                 GUSregb(GUS47Counter2) = (GUSbyte) data;
       
   440                 break;
       
   441             /* case 0x48:       */ /* sampling freq reg not emulated (same as interwave) */
       
   442             case 0x49:          /* SampCtrlReg */
       
   443                 GUSregb(GUS49SampCtrl) = (GUSbyte) data;
       
   444                 break;
       
   445             /* case 0x4b:       */ /* joystick trim not emulated */
       
   446             case 0x4c:          /* GUSreset */
       
   447                 GUSregb(GUS4cReset) = (GUSbyte) data;
       
   448                 if (!(GUSregb(GUS4cReset) & 1)) /* reset... */
       
   449                 {
       
   450                     GUSregd(voicewavetableirq) = 0;
       
   451                     GUSregd(voicevolrampirq) = 0;
       
   452                     GUSregw(TimerIRQs) = 0;
       
   453                     GUSregw(BusyTimerIRQs) = 0;
       
   454                     GUSregb(NumVoices) = 0xcd;
       
   455                     GUSregb(IRQStatReg2x6) = 0;
       
   456                     GUSregb(TimerStatus2x8) = 0;
       
   457                     GUSregb(AdLibData2x9) = 0;
       
   458                     GUSregb(TimerDataReg2x9) = 0;
       
   459                     GUSregb(GUS41DMACtrl) = 0;
       
   460                     GUSregb(GUS45TimerCtrl) = 0;
       
   461                     GUSregb(GUS49SampCtrl) = 0;
       
   462                     GUSregb(GUS4cReset) &= 0xf9; /* clear IRQ and DAC enable bits */
       
   463                     GUS_irqclear(state, state->gusirq);
       
   464                 }
       
   465                 /* IRQ enable bit checked elsewhere */
       
   466                 /* EnableDAC bit may be used by external callers */
       
   467                 break;
       
   468             }
       
   469         }
       
   470         break;
       
   471     case 0x307:                /* DRAMaccess */
       
   472         {
       
   473             GUSbyte        *adr;
       
   474             adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
       
   475             *adr = (GUSbyte) data;
       
   476         }
       
   477         break;
       
   478     }
       
   479 }
       
   480 
       
   481 /* Attention when breaking up a single DMA transfer to multiple ones:
       
   482  * it may lead to multiple terminal count interrupts and broken transfers:
       
   483  *
       
   484  * 1. Whenever you transfer a piece of data, the gusemu callback is invoked
       
   485  * 2. The callback may generate a TC irq (if the register was set up to do so)
       
   486  * 3. The irq may result in the program using the GUS to reprogram the GUS
       
   487  *
       
   488  * Some programs also decide to upload by just checking if TC occurs
       
   489  * (via interrupt or a cleared GUS dma flag)
       
   490  * and then start the next transfer, without checking DMA state
       
   491  *
       
   492  * Thus: Always make sure to set the TC flag correctly!
       
   493  *
       
   494  * Note that the genuine GUS had a granularity of 16 bytes/words for low/high DMA
       
   495  * while later cards had atomic granularity provided by an additional GUS50DMAHigh register
       
   496  * GUSemu also uses this register to support byte-granular transfers for better compatibility
       
   497  * with emulators other than GUSemu32
       
   498  */
       
   499 
       
   500 void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int count, int TC)
       
   501 {
       
   502     /* this function gets called by the callback function as soon as a DMA transfer is about to start
       
   503      * dma_addr is a translated address within accessible memory, not the physical one,
       
   504      * count is (real dma count register)+1
       
   505      * note that the amount of bytes transfered is fully determined by values in the DMA registers
       
   506      * do not forget to update DMA states after transferring the entire block:
       
   507      * DREQ cleared & TC asserted after the _whole_ transfer */
       
   508 
       
   509     char           *srcaddr;
       
   510     char           *destaddr;
       
   511     char            msbmask = 0;
       
   512     GUSbyte        *gusptr;
       
   513     gusptr = state->gusdatapos;
       
   514 
       
   515     srcaddr = dma_addr; /* system memory address */
       
   516     {
       
   517         int             offset = (GUSregw(GUS42DMAStart) << 4) + (GUSregb(GUS50DMAHigh) & 0xf);
       
   518         if (state->gusdma >= 4)
       
   519             offset = (offset & 0xc0000) + (2 * (offset & 0x1fff0)); /* 16 bit address translation */
       
   520         destaddr = (char *) state->himemaddr + offset; /* wavetable RAM adress */
       
   521     }
       
   522 
       
   523     GUSregw(GUS42DMAStart) += (GUSword)  (count >> 4);                           /* ToDo: add 16bit GUS page limit? */
       
   524     GUSregb(GUS50DMAHigh)   = (GUSbyte) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */
       
   525 
       
   526     if (GUSregb(GUS41DMACtrl) & 0x02)   /* direction, 0 := sysram->gusram */
       
   527     {
       
   528         char           *tmpaddr = destaddr;
       
   529         destaddr = srcaddr;
       
   530         srcaddr = tmpaddr;
       
   531     }
       
   532 
       
   533     if ((GUSregb(GUS41DMACtrl) & 0x80) && (!(GUSregb(GUS41DMACtrl) & 0x02)))
       
   534         msbmask = (const char) 0x80;    /* invert MSB */
       
   535     for (; count > 0; count--)
       
   536     {
       
   537         if (GUSregb(GUS41DMACtrl) & 0x40)
       
   538             *(destaddr++) = *(srcaddr++);               /* 16 bit lobyte */
       
   539         else
       
   540             *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 8 bit */
       
   541         if (state->gusdma >= 4)
       
   542             *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 16 bit hibyte */
       
   543     }
       
   544 
       
   545     if (TC)
       
   546     {
       
   547         (GUSregb(GUS41DMACtrl)) &= 0xfe;        /* clear DMA request bit */
       
   548         if (GUSregb(GUS41DMACtrl) & 0x20)       /* DMA terminal count IRQ */
       
   549         {
       
   550             GUSregb(IRQStatReg2x6) |= 0x80;
       
   551             GUS_irqrequest(state, state->gusirq, 1);
       
   552         }
       
   553     }
       
   554 }