/** * Write byte to 0xff8803. Set content of YM's data register under conditions. * Address 0xff8803 is a shadow version of 0xff8802, so both addresses can't be written * at the same time by the same instruction. This means only a .B access or * a movep will have a valid effect, other accesses are ignored. */ void PSG_ff8803_WriteByte(void) { if ( nIoMemAccessSize == SIZE_BYTE ) /* byte access or movep */ { M68000_WaitState(1); /* [NP] FIXME not 100% accurate, but gives good results */ if (LOG_TRACE_LEVEL(TRACE_PSG_WRITE)) { int FrameCycles, HblCounterVideo, LineCycles; Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); LOG_TRACE_PRINT("ym write %x=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress], FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles); } PSG_Set_DataRegister ( IoMem[IoAccessCurrentAddress] ); } else { /* do nothing, just a trace if needed */ if (LOG_TRACE_LEVEL(TRACE_PSG_WRITE)) { int FrameCycles, HblCounterVideo, LineCycles; Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); LOG_TRACE_PRINT("ym write ignored %x=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress], FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles); } } }
/** * Default information on entering the debugger */ static void DebugInfo_Default(Uint32 dummy) { int hbl, fcycles, lcycles; Video_GetPosition(&fcycles, &hbl, &lcycles); fprintf(stderr, "\nCPU=$%x, VBL=%d, FrameCycles=%d, HBL=%d, LineCycles=%d, DSP=", M68000_GetPC(), 0, fcycles, hbl, lcycles); fprintf(stderr, "N/A\n"); }
/** * Read byte from 0xff8801/02/03. Return 0xff. */ void PSG_ff880x_ReadByte(void) { M68000_WaitState(1); /* [NP] FIXME not 100% accurate, but gives good results */ IoMem[IoAccessCurrentAddress] = 0xff; if (LOG_TRACE_LEVEL(TRACE_PSG_READ)) { int FrameCycles, HblCounterVideo, LineCycles; Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); LOG_TRACE_PRINT("ym read void %x=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress], FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles); } }
/** * Write byte to 0xff8802. Set content of YM's data register. */ void PSG_ff8802_WriteByte(void) { // M68000_WaitState(4); M68000_WaitState(1); /* [NP] FIXME not 100% accurate, but gives good results */ if (LOG_TRACE_LEVEL(TRACE_PSG_WRITE)) { int FrameCycles, HblCounterVideo, LineCycles; Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); LOG_TRACE_PRINT("ym write %x=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress], FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles); } PSG_Set_DataRegister ( IoMem[IoAccessCurrentAddress] ); }
/** * Write byte to the YM address register (usually 0xff8800). This is used * as a selector for when we read/write the YM data register (0xff8802). */ void PSG_Set_SelectRegister(Uint8 val) { /* Store register used to read/write in $ff8802. This register */ /* is 8 bits on the YM2149, this means it should not be masked */ /* with 0xf. Instead, we keep the 8 bits, but we must ignore */ /* read/write to ff8802 when PSGRegisterSelect >= 16 */ PSGRegisterSelect = val; /* When address register is changed, a read from $ff8800 should */ /* return the masked value of the register. We set the value here */ /* to be returned in case PSG_Get_DataRegister is called */ PSGRegisterReadData = PSGRegisters[PSGRegisterSelect]; if (LOG_TRACE_LEVEL(TRACE_PSG_WRITE)) { int FrameCycles, HblCounterVideo, LineCycles; Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); LOG_TRACE_PRINT("ym write reg=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n", PSGRegisterSelect, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles); } }
/** * Reset variables used in PSG */ void PSG_Reset(void) { int i; if (LOG_TRACE_LEVEL(TRACE_PSG_WRITE)) { int FrameCycles, HblCounterVideo, LineCycles; Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); LOG_TRACE_PRINT("ym reset video_cyc=%d %d@%d pc=%x instr_cycle %d\n", FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles); } PSGRegisterSelect = 0; PSGRegisterReadData = 0; memset(PSGRegisters, 0, sizeof(PSGRegisters)); PSGRegisters[PSG_REG_IO_PORTA] = 0xff; /* no drive selected + side 0 after a reset */ /* Update sound's emulation registers */ for ( i=0 ; i < NUM_PSG_SOUND_REGISTERS; i++ ) Sound_WriteReg ( i , 0 ); LastStrobe=0; }
/** * Write byte to YM's register (0xff8802), store according to PSG select register (0xff8800) */ void PSG_Set_DataRegister(Uint8 val) { if (LOG_TRACE_LEVEL(TRACE_PSG_WRITE)) { int FrameCycles, HblCounterVideo, LineCycles; Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); LOG_TRACE_PRINT("ym write data reg=0x%x val=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n", PSGRegisterSelect, val, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles); } /* Is a valid PSG register currently selected ? */ if ( PSGRegisterSelect >= MAX_PSG_REGISTERS ) return; /* not valid, ignore write and do nothing */ /* Create samples up until this point with current values */ Sound_Update(false); /* When a read is made from $ff8800 without changing PSGRegisterSelect, we should return */ /* the non masked value. */ PSGRegisterReadData = val; /* store non masked value for PSG_Get_DataRegister */ /* Copy value to PSGRegisters[] */ PSGRegisters[PSGRegisterSelect] = val; /* Clear unused bits for some regs */ if ( ( PSGRegisterSelect == PSG_REG_CHANNEL_A_COARSE ) || ( PSGRegisterSelect == PSG_REG_CHANNEL_B_COARSE ) || ( PSGRegisterSelect == PSG_REG_CHANNEL_C_COARSE ) || ( PSGRegisterSelect == PSG_REG_ENV_SHAPE ) ) PSGRegisters[PSGRegisterSelect] &= 0x0f; /* only keep bits 0 - 3 */ else if ( ( PSGRegisterSelect == PSG_REG_CHANNEL_A_AMP ) || ( PSGRegisterSelect == PSG_REG_CHANNEL_B_AMP ) || ( PSGRegisterSelect == PSG_REG_CHANNEL_C_AMP ) || ( PSGRegisterSelect == PSG_REG_NOISE_GENERATOR ) ) PSGRegisters[PSGRegisterSelect] &= 0x1f; /* only keep bits 0 - 4 */ if ( PSGRegisterSelect < NUM_PSG_SOUND_REGISTERS ) { /* Copy sound related registers 0..13 to the sound module's internal buffer */ Sound_WriteReg ( PSGRegisterSelect , PSGRegisters[PSGRegisterSelect] ); } else if ( PSGRegisterSelect == PSG_REG_IO_PORTA ) { /* * FIXME: This is only a prelimary dirty hack! * Port B (Printer port) - writing here needs to be dispatched to the printer * STROBE (Port A bit5) does a short LOW and back to HIGH when the char is valid * To print you need to write the character byte to IOB and you need to toggle STROBE * (like EmuTOS does). */ /* Printer dispatching only when printing is activated */ if (ConfigureParams.Printer.bEnablePrinting) { /* Bit 5 - Centronics strobe? If STROBE is low and the LastStrobe was high, then print/transfer to the emulated Centronics port. */ if (LastStrobe && ( (PSGRegisters[PSG_REG_IO_PORTA]&(1<<5)) == 0 )) { /* Seems like we want to print something... */ Printer_TransferByteTo(PSGRegisters[PSG_REG_IO_PORTB]); /* Initiate a possible GPIP0 Printer BUSY interrupt */ MFP_InputOnChannel ( MFP_INT_GPIP0 , 0 ); /* Initiate a possible GPIP1 Falcon ACK interrupt */ if (ConfigureParams.System.nMachineType == MACHINE_FALCON) MFP_InputOnChannel ( MFP_INT_GPIP1 , 0 ); } } LastStrobe = PSGRegisters[PSG_REG_IO_PORTA]&(1<<5); /* Bit 0-2 : side and drive select */ if ( (PSGRegisters[PSG_REG_IO_PORTA]&(1<<1)) == 0 ) { /* floppy drive A is ON */ Statusbar_SetFloppyLed(DRIVE_LED_A, LED_STATE_ON); } else { Statusbar_SetFloppyLed(DRIVE_LED_A, LED_STATE_OFF); } if ( (PSGRegisters[PSG_REG_IO_PORTA]&(1<<2)) == 0 ) { /* floppy drive B is ON */ Statusbar_SetFloppyLed(DRIVE_LED_B, LED_STATE_ON); } else { Statusbar_SetFloppyLed(DRIVE_LED_B, LED_STATE_OFF); } /* Bit 3 - Centronics as input */ if(PSGRegisters[PSG_REG_IO_PORTA]&(1<<3)) { /* FIXME: might be needed if we want to emulate sound sampling hardware */ } /* handle Falcon specific bits in PORTA of the PSG */ if (ConfigureParams.System.nMachineType == MACHINE_FALCON) { /* Bit 4 - DSP reset? */ if(PSGRegisters[PSG_REG_IO_PORTA]&(1<<4)) { Log_Printf(LOG_DEBUG, "Calling DSP_Reset?\n"); #if ENABLE_DSP_EMU if (ConfigureParams.System.nDSPType == DSP_TYPE_EMU) { DSP_Reset(); } #endif } /* Bit 6 - Internal Speaker control */ if(PSGRegisters[PSG_REG_IO_PORTA]&(1<<6)) { /*Log_Printf(LOG_DEBUG, "Falcon: Internal Speaker state\n");*/ /* FIXME: add code to handle? (if we want to emulate the speaker at all? */ } /* Bit 7 - Reset IDE? */ if(PSGRegisters[PSG_REG_IO_PORTA]&(1<<7)) { Log_Printf(LOG_DEBUG, "Falcon: Reset IDE subsystem\n"); /* FIXME: add code to handle IDE reset */ } } } }