Annotation of qemu/hw/gusemu_hal.c, revision 1.1.1.1

1.1       root        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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.