Annotation of hatari/src/psg.c, revision 1.1.1.11

1.1       root        1: /*
1.1.1.4   root        2:   Hatari - psg.c
1.1       root        3: 
1.1.1.4   root        4:   This file is distributed under the GNU Public License, version 2 or at
                      5:   your option any later version. Read the file gpl.txt for details.
1.1.1.3   root        6: 
1.1.1.4   root        7:   Programmable Sound Generator (YM-2149) - PSG
1.1.1.3   root        8: 
1.1.1.4   root        9:   Also used for the printer (centronics) port emulation (PSG Port B, Register 15)
1.1       root       10: */
1.1.1.7   root       11: 
                     12: 
                     13: /* 2007/04/14  [NP]    First approximation to get cycle accurate accesses to ff8800/02 */
                     14: /*                     by cumulating wait state of 1 cycle and rounding the final      */
                     15: /*                     result to 4.                                                    */
                     16: /* 2007/04/29  [NP]    Functions PSG_Void_WriteByte and PSG_Void_ReadByte to handle    */
                     17: /*                     accesses to $ff8801/03. These adresses have no effect, but they */
                     18: /*                     must give a 1 cycle wait state (e.g. move.l d0,ff8800).         */
                     19: /* 2007/09/29  [NP]    Replace printf by calls to HATARI_TRACE.                        */
                     20: /* 2007/10/23  [NP]    In PSG_Void_WriteByte, add a wait state only if no wait state   */
                     21: /*                     were added so far (hack, but gives good result).                */
                     22: /* 2007/11/18  [NP]    In PSG_DataRegister_WriteByte, set unused bit to 0, in case     */
                     23: /*                     the data reg is read later (fix Mindbomb Demo / BBC).           */
1.1.1.9   root       24: /* 2008/04/20  [NP]    In PSG_DataRegister_WriteByte, set unused bit to 0 for register */
                     25: /*                     6 too (noise period).                                           */
                     26: /* 2008/07/27  [NP]    Better separation between accesses to the YM hardware registers */
                     27: /*                     and the sound rendering routines. Use Sound_WriteReg() to pass  */
                     28: /*                     all writes to the sound rendering functions. This allows to     */
                     29: /*                     have sound.c independant of psg.c (to ease replacement of       */
                     30: /*                     sound.c by another rendering method).                           */
                     31: /* 2008/08/11  [NP]    Set drive leds.                                                 */
                     32: /* 2008/10/16  [NP]    When writing to $ff8800, register select should not be masked   */
                     33: /*                     with 0xf, it's a real 8 bits register where all bits are        */
                     34: /*                     significant. This means only value <16 should be considered as  */
                     35: /*                     valid register selection. When reg select is >= 16, all writes  */
                     36: /*                     and reads in $ff8802 should be ignored.                         */
                     37: /*                     (fix European Demo Intro, which sets addr reg to 0x10 when      */
                     38: /*                     sample playback is disabled).                                   */
1.1.1.10  root       39: /* 2008/12/21  [NP]    After testing different cases on a real STF, rewrite registers  */
                     40: /*                     handling. As only pins BC1 and BDIR are used in an Atari to     */
                     41: /*                     address the YM2149, this means only 1 bit is necessary to access*/
                     42: /*                     select/data registers. Other variations of the $ff88xx addresses*/
                     43: /*                     will point to either $ff8800 or $ff8802. Only bit 1 of $ff88xx  */
                     44: /*                     is useful to know which register is accessed in the YM2149.     */
                     45: /*                     So, it's possible to access the YM2149 with $ff8801 and $ff8803 */
                     46: /*                     but under conditions : the write to a shadow address (bit 0=1)  */
                     47: /*                     can't be made by an instruction that writes to the same address */
                     48: /*                     with bit 0=0 at the same time (.W or .L access).                */
                     49: /*                     In that case, only the address with bit 0=0 is taken into       */
                     50: /*                     account. This means a write to $ff8801/03 will succeed only if  */
                     51: /*                     the access size is .B (byte) or the opcode is a movep (because  */
                     52: /*                     in that case we won't access the same register with 2 different */
                     53: /*                     addresses) (fix the game X-Out, which uses movep.w to write to  */
                     54: /*                     $ff8801/03).                                                    */
                     55: /*                     Refactorize some code for cleaner handling of these accesses.   */
                     56: /*                     Only reads to $ff8800 will return a data, reads to $ff8801/02/03*/
                     57: /*                     always return 0xff (tested on STF).                             */
                     58: /*                     When PSGRegisterSelect > 15, reads to $ff8800 also return 0xff. */
                     59: /* 2009/01/24  [NP]    Remove redundant test, as movep implies SIZE_BYTE access.       */
1.1.1.7   root       60: 
                     61: 
                     62: /* Emulating wait states when accessing $ff8800/01/02/03 with different 'move' variants        */
                     63: /* is a complex task. So far, adding 1 cycle wait state to each access and rounding the        */
                     64: /* final number to 4 gives some good results, but this is certainly not the way it's   */
                     65: /* working for real in the ST.                                                         */
                     66: /* The following examples show some verified wait states for different accesses :      */
                     67: /*     lea     $ffff8800,a1                                                            */
                     68: /*     lea     $ffff8802,a2                                                            */
                     69: /*     lea     $ffff8801,a3                                                            */
                     70: /*                                                                                     */
                     71: /*     movep.w d1,(a1)         ; 20 16+4       (ventura loader)                        */
                     72: /*     movep.l d1,(a1)         ; 28 24+4       (ventura loader, ulm loader)            */
                     73: /*                                                                                     */
                     74: /*     movep.l d6,0(a5)        ; 28 24+4       (SNY I, TCB)                            */
                     75: /*     movep.w d5,0(a5)        ; 20 16+4       (SNY I, TCB)                            */
                     76: /*                                                                                     */
                     77: /*     move.b d1,(a1)          ; 12 8+4                                                */
                     78: /*     move.b d1,(a2)          ; 12 8+4                                                */
                     79: /*     move.b d1,(a3)          ; 12 8+4        (crickey ulm hidden)                    */
                     80: /*                                                                                     */
                     81: /*     move.w d1,(a1)          ; 12 8+4                                                */
                     82: /*     move.w d1,(a2)          ; 12 8+4                                                */
                     83: /*     move.l d1,(a1)          ; 16 12+4       (ulm loader)                            */
                     84: /*                                                                                     */
                     85: /*     movem.l d1,(a1)         ; 20 16+4                                               */
                     86: /*     movem.l d1-d2,(a1)      ; 28 24+4                                               */
                     87: /*     movem.l d1-d3,(a1)      ; 40 32+4+4                                             */
                     88: /*     movem.l d1-d4,(a1)      ; 48 40+4+4                                             */
                     89: /*     movem.l d1-d5,(a1)      ; 60 48+4+4+4                                           */
                     90: /*     movem.l d1-d6,(a1)      ; 68 56+4+4+4                                           */
                     91: /*     movem.l d1-d7,(a1)      ; 80 64+4+4+4+4                                         */
                     92: /*     movem.l d0-d7,(a1)      ; 88 72+4+4+4+4                                         */
                     93: /*                                                                                     */
1.1.1.10  root       94: /*     movep.w d0,(a3)                         (X-Out)                                 */
                     95: /*                                                                                     */
1.1.1.7   root       96: /* This gives the following "model" :                                                  */
                     97: /*     - each access to $ff8800 or $ff8802 add 1 cycle wait state                      */
1.1.1.10  root       98: /*     - accesses to $ff8801 or $ff8803 are considered "valid" only if we don't access */
                     99: /*       the corresponding "non shadow" addresses $ff8800/02 at the same time.         */
                    100: /*       This means only .B size (move.b for example) or movep opcode will work.       */
                    101: /*       If the access is valid, add 1 cycle wait state, else ignore the write and     */
                    102: /*       don't add any cycle.                                                          */
1.1.1.7   root      103: 
                    104: 
                    105: 
1.1.1.11! root      106: const char PSG_fileid[] = "Hatari psg.c : " __DATE__ " " __TIME__;
1.1       root      107: 
                    108: #include "main.h"
1.1.1.3   root      109: #include "configuration.h"
1.1.1.4   root      110: #include "ioMem.h"
1.1.1.5   root      111: #include "joy.h"
1.1.1.7   root      112: #include "log.h"
1.1.1.4   root      113: #include "m68000.h"
1.1       root      114: #include "memorySnapShot.h"
                    115: #include "sound.h"
1.1.1.4   root      116: #include "printer.h"            /* because Printer I/O goes through PSG Register 15 */
1.1.1.3   root      117: #include "psg.h"
1.1.1.7   root      118: #if ENABLE_DSP_EMU
                    119: #include "falcon/dsp.h"
                    120: #endif
                    121: #include "video.h"
1.1.1.9   root      122: #include "statusbar.h"
                    123: #include "mfp.h"
                    124: 
1.1       root      125: 
1.1.1.4   root      126: Uint8 PSGRegisterSelect;        /* 0xff8800 (read/write) */
                    127: Uint8 PSGRegisters[16];         /* Register in PSG, see PSG_REG_xxxx */
                    128: 
1.1.1.9   root      129: static unsigned int LastStrobe=0; /* Falling edge of Strobe used for printer */
1.1       root      130: 
                    131: 
                    132: /*-----------------------------------------------------------------------*/
1.1.1.7   root      133: /**
                    134:  * Reset variables used in PSG
                    135:  */
1.1       root      136: void PSG_Reset(void)
                    137: {
1.1.1.4   root      138:        PSGRegisterSelect = 0;
                    139:        memset(PSGRegisters, 0, sizeof(PSGRegisters));
1.1.1.9   root      140:        LastStrobe=0;
1.1       root      141: }
                    142: 
1.1.1.2   root      143: 
                    144: /*-----------------------------------------------------------------------*/
1.1.1.7   root      145: /**
                    146:  * Save/Restore snapshot of local variables ('MemorySnapShot_Store' handles type)
                    147:  */
1.1.1.9   root      148: void PSG_MemorySnapShot_Capture(bool bSave)
1.1       root      149: {
1.1.1.4   root      150:        /* Save/Restore details */
                    151:        MemorySnapShot_Store(&PSGRegisterSelect, sizeof(PSGRegisterSelect));
                    152:        MemorySnapShot_Store(PSGRegisters, sizeof(PSGRegisters));
1.1.1.9   root      153:        MemorySnapShot_Store(&LastStrobe, sizeof(LastStrobe));
1.1       root      154: }
                    155: 
1.1.1.2   root      156: 
                    157: /*-----------------------------------------------------------------------*/
1.1.1.7   root      158: /**
1.1.1.10  root      159:  * Write byte to the YM address register (usually 0xff8800). This is used
                    160:  * as a selector for when we read/write the YM data register (0xff8802).
1.1.1.7   root      161:  */
1.1.1.10  root      162: void PSG_Set_SelectRegister(Uint8 val)
1.1       root      163: {
1.1.1.9   root      164:        /* Store register used to read/write in $ff8802. This register */
                    165:        /* is 8 bits on the YM2149, this means it should not be masked */
                    166:        /* with 0xf. Instead, we keep the 8 bits, but we must ignore */
                    167:        /* read/write to ff8802 when PSGRegisterSelect >= 16 */
1.1.1.10  root      168:        PSGRegisterSelect = val;
1.1.1.7   root      169: 
1.1.1.11! root      170:        if (LOG_TRACE_LEVEL(TRACE_PSG_WRITE))
        !           171:        {
        !           172:                int FrameCycles, HblCounterVideo, LineCycles;
        !           173:                Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
        !           174:                LOG_TRACE_PRINT("ym write reg=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n",
        !           175:                                PSGRegisterSelect, FrameCycles, LineCycles, HblCounterVideo,
        !           176:                                M68000_GetPC(), CurrentInstrCycles);
        !           177:        }
1.1       root      178: }
                    179: 
1.1.1.2   root      180: 
                    181: /*-----------------------------------------------------------------------*/
1.1.1.7   root      182: /**
1.1.1.10  root      183:  * Read byte from 0xff8800, return PSG data
1.1.1.7   root      184:  */
1.1.1.10  root      185: Uint8 PSG_Get_DataRegister(void)
1.1       root      186: {
1.1.1.9   root      187:        /* Is a valid PSG register currently selected ? */
                    188:        if ( PSGRegisterSelect >= 16 )
1.1.1.10  root      189:                return 0xff;                            /* not valid, return 0xff */
1.1.1.9   root      190: 
1.1.1.5   root      191:        if (PSGRegisterSelect == 14)
                    192:        {
                    193:                /* Second parallel port joystick uses centronics strobe bit as fire button: */
                    194:                if (ConfigureParams.Joysticks.Joy[JOYID_PARPORT2].nJoystickMode != JOYSTICK_DISABLED)
                    195:                {
                    196:                        if (Joy_GetStickData(JOYID_PARPORT2) & 0x80)
                    197:                                PSGRegisters[14] &= ~32;
                    198:                        else
                    199:                                PSGRegisters[14] |= 32;
                    200:                }
                    201:        }
                    202:        else if (PSGRegisterSelect == 15)
                    203:        {
                    204:                /* PSG register 15 is parallel port data register - used by parallel port joysticks: */
                    205:                if (ConfigureParams.Joysticks.Joy[JOYID_PARPORT1].nJoystickMode != JOYSTICK_DISABLED)
                    206:                {
                    207:                        PSGRegisters[15] &= 0x0f;
                    208:                        PSGRegisters[15] |= ~Joy_GetStickData(JOYID_PARPORT1) << 4;
                    209:                }
                    210:                if (ConfigureParams.Joysticks.Joy[JOYID_PARPORT2].nJoystickMode != JOYSTICK_DISABLED)
                    211:                {
                    212:                        PSGRegisters[15] &= 0xf0;
                    213:                        PSGRegisters[15] |= ~Joy_GetStickData(JOYID_PARPORT2) & 0x0f;
                    214:                }
                    215:        }
                    216: 
1.1.1.4   root      217:        /* Read data last selected by register */
1.1.1.10  root      218:        return PSGRegisters[PSGRegisterSelect];
1.1       root      219: }
                    220: 
1.1.1.2   root      221: 
                    222: /*-----------------------------------------------------------------------*/
1.1.1.7   root      223: /**
1.1.1.10  root      224:  * Write byte to YM's register (0xff8802), store according to PSG select register (0xff8800)
1.1.1.7   root      225:  */
1.1.1.10  root      226: void PSG_Set_DataRegister(Uint8 val)
1.1.1.4   root      227: {
1.1.1.11! root      228:        if (LOG_TRACE_LEVEL(TRACE_PSG_WRITE))
        !           229:        {
        !           230:                int FrameCycles, HblCounterVideo, LineCycles;
        !           231:                Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
        !           232:                LOG_TRACE_PRINT("ym write data reg=0x%x val=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n",
        !           233:                                PSGRegisterSelect, val, FrameCycles, LineCycles,
        !           234:                                HblCounterVideo, M68000_GetPC(), CurrentInstrCycles);
        !           235:        }
1.1.1.9   root      236: 
                    237:        /* Is a valid PSG register currently selected ? */
                    238:        if ( PSGRegisterSelect >= 16 )
                    239:                return;                                 /* not valid, ignore write and do nothing */
                    240: 
1.1.1.8   root      241:        /* Create samples up until this point with current values */
                    242:        Sound_Update();
                    243: 
1.1.1.10  root      244:        /* Copy value to PSGRegisters[] */
                    245:        PSGRegisters[PSGRegisterSelect] = val;
1.1.1.4   root      246: 
1.1.1.9   root      247:        /* Clear unused bits for some regs */
1.1.1.7   root      248:        if ( ( PSGRegisterSelect == PSG_REG_CHANNEL_A_COARSE ) || ( PSGRegisterSelect == PSG_REG_CHANNEL_B_COARSE )
                    249:                || ( PSGRegisterSelect == PSG_REG_CHANNEL_C_COARSE ) || ( PSGRegisterSelect == PSG_REG_ENV_SHAPE ) )
                    250:          PSGRegisters[PSGRegisterSelect] &= 0x0f;      /* only keep bits 0 - 3 */
                    251: 
                    252:        else if ( ( PSGRegisterSelect == PSG_REG_CHANNEL_A_AMP ) || ( PSGRegisterSelect == PSG_REG_CHANNEL_B_AMP )
1.1.1.9   root      253:                || ( PSGRegisterSelect == PSG_REG_CHANNEL_C_AMP ) || ( PSGRegisterSelect == PSG_REG_NOISE_GENERATOR ) )
1.1.1.7   root      254:          PSGRegisters[PSGRegisterSelect] &= 0x1f;      /* only keep bits 0 - 4 */
                    255: 
                    256: 
                    257: 
1.1.1.9   root      258:        if ( PSGRegisterSelect < NUM_PSG_SOUND_REGISTERS )
1.1.1.4   root      259:        {
1.1.1.9   root      260:                /* Copy sound related registers 0..13 to the sound module's internal buffer */
                    261:                Sound_WriteReg ( PSGRegisterSelect , PSGRegisters[PSGRegisterSelect] );
                    262:        }
1.1.1.4   root      263: 
1.1.1.9   root      264:        else if ( PSGRegisterSelect == PSG_REG_IO_PORTA )
                    265:        {
                    266:        /*
                    267:         * FIXME: This is only a prelimary dirty hack!
                    268:         * Port B (Printer port) - writing here needs to be dispatched to the printer
                    269:         * STROBE (Port A bit5) does a short LOW and back to HIGH when the char is valid
                    270:         * To print you need to write the character byte to IOB and you need to toggle STROBE
                    271:         * (like EmuTOS does).
                    272:         */
1.1.1.4   root      273:                /* Printer dispatching only when printing is activated */
                    274:                if (ConfigureParams.Printer.bEnablePrinting)
                    275:                {
1.1.1.9   root      276:                        /* Bit 5 - Centronics strobe? If STROBE is low and the LastStrobe was high,
                    277:                                        then print/transfer to the emulated Centronics port.
1.1.1.7   root      278:                         */
1.1.1.9   root      279:                        if (LastStrobe && ( (PSGRegisters[PSG_REG_IO_PORTA]&(1<<5)) == 0 ))
1.1.1.4   root      280:                        {
                    281:                                /* Seems like we want to print something... */
1.1.1.9   root      282:                                Printer_TransferByteTo(PSGRegisters[PSG_REG_IO_PORTB]);
                    283:                                /* Initiate a possible GPIP0 Printer BUSY interrupt */
                    284:                                MFP_InputOnChannel(MFP_GPIP_0_BIT,MFP_IERB,&MFP_IPRB);
                    285:                                /* Initiate a possible GPIP1 Falcon ACK interrupt */
                    286:                                if (ConfigureParams.System.nMachineType == MACHINE_FALCON)
                    287:                                        MFP_InputOnChannel(MFP_GPIP_1_BIT,MFP_IERB,&MFP_IPRB);
1.1.1.4   root      288:                        }
                    289:                }
1.1.1.9   root      290:                LastStrobe = PSGRegisters[PSG_REG_IO_PORTA]&(1<<5);
                    291: 
                    292:                /* Bit 0-2 : side and drive select */
                    293:                if ( (PSGRegisters[PSG_REG_IO_PORTA]&(1<<1)) == 0 )
                    294:                {
                    295:                        /* floppy drive A is ON */
1.1.1.11! root      296:                        Statusbar_SetFloppyLed(DRIVE_LED_A, true);
1.1.1.9   root      297:                }
                    298:                else
                    299:                {
1.1.1.11! root      300:                        Statusbar_SetFloppyLed(DRIVE_LED_A, false);
1.1.1.9   root      301:                }
                    302:                if ( (PSGRegisters[PSG_REG_IO_PORTA]&(1<<2)) == 0 )
                    303:                {
                    304:                        /* floppy drive B is ON */
1.1.1.11! root      305:                        Statusbar_SetFloppyLed(DRIVE_LED_B, true);
1.1.1.9   root      306:                }
                    307:                else
                    308:                {
1.1.1.11! root      309:                        Statusbar_SetFloppyLed(DRIVE_LED_B, false);
1.1.1.9   root      310:                }
                    311: 
1.1.1.7   root      312:                /* Bit 3 - Centronics as input */
                    313:                if(PSGRegisters[PSG_REG_IO_PORTA]&(1<<3))
                    314:                {
                    315:                        /* FIXME: might be needed if we want to emulate sound sampling hardware */
                    316:                }
                    317:                
                    318:                /* handle Falcon specific bits in PORTA of the PSG */
                    319:                if (ConfigureParams.System.nMachineType == MACHINE_FALCON)
                    320:                {
                    321:                        /* Bit 4 - DSP reset? */
                    322:                        if(PSGRegisters[PSG_REG_IO_PORTA]&(1<<4))
                    323:                        {
                    324:                                Log_Printf(LOG_DEBUG, "Calling DSP_Reset?\n");
                    325: #if ENABLE_DSP_EMU
                    326:                                if (ConfigureParams.System.nDSPType == DSP_TYPE_EMU) {
                    327:                                        DSP_Reset();
                    328:                                }
                    329: #endif
                    330:                        }
                    331:                        /* Bit 6 - Internal Speaker control */
                    332:                        if(PSGRegisters[PSG_REG_IO_PORTA]&(1<<6))
                    333:                        {
                    334:                                /*Log_Printf(LOG_DEBUG, "Falcon: Internal Speaker state\n");*/
                    335:                                /* FIXME: add code to handle? (if we want to emulate the speaker at all? */
                    336:                        }
                    337:                        /* Bit 7 - Reset IDE? */
                    338:                        if(PSGRegisters[PSG_REG_IO_PORTA]&(1<<7))
                    339:                        {
                    340:                                Log_Printf(LOG_DEBUG, "Falcon: Reset IDE subsystem\n");
                    341:                                /* FIXME: add code to handle IDE reset */
                    342:                        }
                    343:                }
1.1.1.9   root      344:        
1.1.1.4   root      345:        }
1.1       root      346: }
                    347: 
1.1.1.2   root      348: 
                    349: /*-----------------------------------------------------------------------*/
1.1.1.7   root      350: /**
1.1.1.10  root      351:  * Read byte from 0xff8800. Return current content of data register
1.1.1.7   root      352:  */
1.1.1.10  root      353: void PSG_ff8800_ReadByte(void)
1.1       root      354: {
1.1.1.10  root      355:        M68000_WaitState(1);                            /* [NP] FIXME not 100% accurate, but gives good results */
                    356: 
                    357:        IoMem[IoAccessCurrentAddress] = PSG_Get_DataRegister();
                    358: 
1.1.1.11! root      359:        if (LOG_TRACE_LEVEL(TRACE_PSG_READ))
        !           360:        {
        !           361:                int FrameCycles, HblCounterVideo, LineCycles;
        !           362:                Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
        !           363:                LOG_TRACE_PRINT("ym read data %x=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n",
        !           364:                                IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress],
        !           365:                                FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles);
        !           366:        }
1.1.1.10  root      367: }
                    368: 
                    369: 
                    370: /*-----------------------------------------------------------------------*/
                    371: /**
                    372:  * Read byte from 0xff8801/02/03. Return 0xff.
                    373:  */
                    374: void PSG_ff880x_ReadByte(void)
                    375: {
                    376:        M68000_WaitState(1);                            /* [NP] FIXME not 100% accurate, but gives good results */
1.1.1.4   root      377: 
1.1.1.8   root      378:        IoMem[IoAccessCurrentAddress] = 0xff;
1.1.1.10  root      379: 
1.1.1.11! root      380:        if (LOG_TRACE_LEVEL(TRACE_PSG_READ))
        !           381:        {
        !           382:                int FrameCycles, HblCounterVideo, LineCycles;
        !           383:                Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
        !           384:                LOG_TRACE_PRINT("ym read void %x=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n",
        !           385:                                IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress],
        !           386:                                FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles);
        !           387:        }
1.1       root      388: }
1.1.1.7   root      389: 
                    390: 
                    391: 
                    392: /*-----------------------------------------------------------------------*/
                    393: /**
1.1.1.10  root      394:  * Write byte to 0xff8800. Set content of YM's address register.
1.1.1.7   root      395:  */
1.1.1.10  root      396: void PSG_ff8800_WriteByte(void)
1.1.1.7   root      397: {
1.1.1.10  root      398: //     M68000_WaitState(4);
                    399:        M68000_WaitState(1);                            /* [NP] FIXME not 100% accurate, but gives good results */
1.1.1.7   root      400: 
1.1.1.11! root      401:        if (LOG_TRACE_LEVEL(TRACE_PSG_WRITE))
        !           402:        {
        !           403:                int FrameCycles, HblCounterVideo, LineCycles;
        !           404:                Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
        !           405:                LOG_TRACE_PRINT("ym write %x=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n",
        !           406:                                IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress],
        !           407:                                FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles);
        !           408:        }
1.1.1.10  root      409: 
                    410:        PSG_Set_SelectRegister ( IoMem[IoAccessCurrentAddress] );
                    411: }
                    412: 
                    413: 
                    414: /*-----------------------------------------------------------------------*/
                    415: /**
                    416:  * Write byte to 0xff8801. Set content of YM's address register under conditions.
                    417:  * Address 0xff8801 is a shadow version of 0xff8800, so both addresses can't be written
                    418:  * at the same time by the same instruction. This means only a .B access or
                    419:  * a movep will have a valid effect, other accesses are ignored.
                    420:  */
                    421: void PSG_ff8801_WriteByte(void)
                    422: {
                    423:        if ( nIoMemAccessSize == SIZE_BYTE )            /* byte access or movep */
                    424:        {       
                    425:                M68000_WaitState(1);                    /* [NP] FIXME not 100% accurate, but gives good results */
                    426:        
1.1.1.11! root      427:                if (LOG_TRACE_LEVEL(TRACE_PSG_WRITE))
        !           428:                {
        !           429:                        int FrameCycles, HblCounterVideo, LineCycles;
        !           430:                        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
        !           431:                        LOG_TRACE_PRINT("ym write %x=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n",
        !           432:                                        IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress],
        !           433:                                        FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles);
        !           434:                }
1.1.1.10  root      435:        
                    436:                PSG_Set_SelectRegister ( IoMem[IoAccessCurrentAddress] );
                    437:        }
                    438: 
                    439:        else
                    440:        {                                               /* do nothing, just a trace if needed */
1.1.1.11! root      441:                if (LOG_TRACE_LEVEL(TRACE_PSG_WRITE))
        !           442:                {
        !           443:                        int FrameCycles, HblCounterVideo, LineCycles;
        !           444:                        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
        !           445:                        LOG_TRACE_PRINT("ym write ignored %x=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n",
        !           446:                                        IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress],
        !           447:                                        FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles);
        !           448:                }
1.1.1.10  root      449:        }
1.1.1.7   root      450: }
                    451: 
                    452: 
1.1.1.10  root      453: /*-----------------------------------------------------------------------*/
                    454: /**
                    455:  * Write byte to 0xff8802. Set content of YM's data register.
                    456:  */
                    457: void PSG_ff8802_WriteByte(void)
                    458: {
                    459: //     M68000_WaitState(4);
                    460:        M68000_WaitState(1);                            /* [NP] FIXME not 100% accurate, but gives good results */
                    461: 
1.1.1.11! root      462:        if (LOG_TRACE_LEVEL(TRACE_PSG_WRITE))
        !           463:        {
        !           464:                int FrameCycles, HblCounterVideo, LineCycles;
        !           465:                Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
        !           466:                LOG_TRACE_PRINT("ym write %x=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n",
        !           467:                                IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress],
        !           468:                                FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles);
        !           469:        }
1.1.1.10  root      470: 
                    471:        PSG_Set_DataRegister ( IoMem[IoAccessCurrentAddress] );
                    472: }
                    473: 
1.1.1.7   root      474: 
                    475: /*-----------------------------------------------------------------------*/
                    476: /**
1.1.1.10  root      477:  * Write byte to 0xff8803. Set content of YM's data register under conditions.
                    478:  * Address 0xff8803 is a shadow version of 0xff8802, so both addresses can't be written
                    479:  * at the same time by the same instruction. This means only a .B access or
                    480:  * a movep will have a valid effect, other accesses are ignored.
1.1.1.7   root      481:  */
1.1.1.10  root      482: void PSG_ff8803_WriteByte(void)
1.1.1.7   root      483: {
1.1.1.10  root      484:        if ( nIoMemAccessSize == SIZE_BYTE )            /* byte access or movep */
                    485:        {       
                    486:                M68000_WaitState(1);                    /* [NP] FIXME not 100% accurate, but gives good results */
                    487:        
1.1.1.11! root      488:                if (LOG_TRACE_LEVEL(TRACE_PSG_WRITE))
        !           489:                {
        !           490:                        int FrameCycles, HblCounterVideo, LineCycles;
        !           491:                        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
        !           492:                        LOG_TRACE_PRINT("ym write %x=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n",
        !           493:                                        IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress],
        !           494:                                        FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles);
        !           495:                }
1.1.1.10  root      496:                
                    497:                PSG_Set_DataRegister ( IoMem[IoAccessCurrentAddress] );
                    498:        }
                    499: 
                    500:        else
                    501:        {                                               /* do nothing, just a trace if needed */
1.1.1.11! root      502:                if (LOG_TRACE_LEVEL(TRACE_PSG_WRITE))
        !           503:                {
        !           504:                        int FrameCycles, HblCounterVideo, LineCycles;
        !           505:                        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
        !           506:                        LOG_TRACE_PRINT("ym write ignored %x=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n",
        !           507:                                        IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress],
        !           508:                                        FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles);
        !           509:                }
1.1.1.10  root      510:        }
1.1.1.7   root      511: }

unix.superglobalmegacorp.com

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