Exemple #1
0
void C6821::SetCB2(BYTE byData)
{
  byData = byData ? 1 : 0;

  // CA2 is in input mode
  if ( C2_INPUT( m_byCTLB ) )
  {
    // the new state has caused a transition
    if ( m_byICB2 ^ byData )
    {
      // handle the active transition
      if ( ( byData && C2_LOW_TO_HIGH( m_byCTLB ) ) ||
        ( !byData && C2_HIGH_TO_LOW( m_byCTLB ) ) )
      {
        // mark the IRQ
        SET_IRQ2( m_byCTLB );

        // update externals
        UpdateInterrupts();
      }
    }
  }

  // set the new value for CA2
  m_byICB2 = byData;
}
Exemple #2
0
void C6821::SetCA1(BYTE byData)
{
  byData = byData ? 1 : 0;

  // the new state has caused a transition
  if ( m_byCA1 ^ byData )
  {
    // handle the active transition
    if ( ( byData && C1_LOW_TO_HIGH( m_byCTLA ) ) ||
      ( !byData && C1_HIGH_TO_LOW( m_byCTLA ) ) )
    {
      // mark the IRQ
      SET_IRQ1(m_byCTLA);

      // update externals
      UpdateInterrupts();

      // CA2 is configured as output and in read strobe mode and cleared by a CA1 transition
      if ( C2_OUTPUT( m_byCTLA ) && C2_STROBE_MODE( m_byCTLA ) && STROBE_C1_RESET( m_byCTLA ) )
      {
        // call the CA2 output function
        if ( !m_byOCA2 )
          PIA_W_CALLBACK( m_stOutCA2, 1 );

        // clear CA2
        m_byOCA2 = 1;
      }
    }
  }

  // set the new value for CA1
  m_byCA1 = byData;
}
void CEXIChannel::AddDevice(IEXIDevice* pDevice, const int device_num, bool notifyPresenceChanged)
{
	_dbg_assert_(EXPANSIONINTERFACE, device_num < NUM_DEVICES);

	// delete the old device
	if (m_pDevices[device_num] != NULL)
	{
		delete m_pDevices[device_num];
		m_pDevices[device_num] = NULL;
	}

	// replace it with the new one
	m_pDevices[device_num] = pDevice;

	if(notifyPresenceChanged)
	{
		// This means "device presence changed", software has to check
		// m_Status.EXT to see if it is now present or not
		if (m_ChannelId != 2)
		{
			m_Status.EXTINT = 1;
			UpdateInterrupts();
		}
	}
}
Exemple #4
0
void GenerateSIInterrupt(SIInterruptType _SIInterrupt)
{
	switch(_SIInterrupt)
	{
	case INT_RDSTINT:	g_ComCSR.RDSTINT = 1; break;
	case INT_TCINT:		g_ComCSR.TCINT = 1; break;
	}

	UpdateInterrupts();
}
Exemple #5
0
void GenerateDSPInterrupt(DSPInterruptType type, bool _bSet)
{
	switch (type)
	{
	case INT_DSP:  g_dspState.DSPControl.DSP  = _bSet ? 1 : 0; break;
	case INT_ARAM: g_dspState.DSPControl.ARAM = _bSet ? 1 : 0; if (_bSet) g_dspState.DSPControl.DMAState = 0; break;
	case INT_AID:  g_dspState.DSPControl.AID  = _bSet ? 1 : 0; break;
	}

	UpdateInterrupts();
}
void GenerateDIInterrupt(DI_InterruptType _DVDInterrupt)
{
	switch(_DVDInterrupt) 
	{
	case INT_DEINT:		m_DISR.DEINT	= 1; break;
	case INT_TCINT:		m_DISR.TCINT	= 1; break;
	case INT_BRKINT:	m_DISR.BRKINT	= 1; break;
	case INT_CVRINT:	m_DICVR.CVRINT	= 1; break;
	}

	UpdateInterrupts();
}
void Write32(const u32 _iValue, const u32 _iAddress)
{
	DEBUG_LOG(DVDINTERFACE, "(w32): 0x%08x @ 0x%08x", _iValue, _iAddress);

	switch (_iAddress & 0xFF)
	{
	case DI_STATUS_REGISTER:
		{
			UDISR tmpStatusReg(_iValue);

			m_DISR.DEINITMASK	= tmpStatusReg.DEINITMASK;
			m_DISR.TCINTMASK	= tmpStatusReg.TCINTMASK;
			m_DISR.BRKINTMASK	= tmpStatusReg.BRKINTMASK;
			m_DISR.BREAK		= tmpStatusReg.BREAK;

			if (tmpStatusReg.DEINT)		m_DISR.DEINT = 0;
			if (tmpStatusReg.TCINT)		m_DISR.TCINT = 0;
			if (tmpStatusReg.BRKINT)	m_DISR.BRKINT = 0;

			if (m_DISR.BREAK)
			{
				_dbg_assert_(DVDINTERFACE, 0);
			}
			
			UpdateInterrupts();
		}
		break;

	case DI_COVER_REGISTER:	
		{
			UDICVR tmpCoverReg(_iValue);

			m_DICVR.CVRINTMASK = tmpCoverReg.CVRINTMASK;

			if (tmpCoverReg.CVRINT)	m_DICVR.CVRINT = 0;

			UpdateInterrupts();
		}
		break;

	case DI_COMMAND_0:				m_DICMDBUF[0].Hex = _iValue; break;
	case DI_COMMAND_1:				m_DICMDBUF[1].Hex = _iValue; break;
	case DI_COMMAND_2:				m_DICMDBUF[2].Hex = _iValue; break;

	case DI_DMA_ADDRESS_REGISTER:
		{
			m_DIMAR.Hex = _iValue & ~0xfc00001f;
		}
		break;
	case DI_DMA_LENGTH_REGISTER:
		{
			m_DILENGTH.Hex = _iValue & ~0x1f;
		}
		break;
	case DI_DMA_CONTROL_REGISTER:	
		{
			m_DICR.Hex = _iValue & 7;
			if (m_DICR.TSTART)
			{
				if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bFastDiscSpeed)
				{
					u64 ticksUntilTC = m_DILENGTH.Length * 
						(SystemTimers::GetTicksPerSecond() / (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii?DISC_TRANSFER_RATE_WII:DISC_TRANSFER_RATE_GC)) + 
						(SystemTimers::GetTicksPerSecond() * DISC_ACCESS_TIME_MS / 1000);
					CoreTiming::ScheduleEvent((int)ticksUntilTC, tc);
				}
				else
				{
					ExecuteCommand(m_DICR);
				}
			}
		}
		break;

	case DI_IMMEDIATE_DATA_BUFFER:	m_DIIMMBUF.Hex = _iValue; break;

	case DI_CONFIG_REGISTER:
		{
			WARN_LOG(DVDINTERFACE, "Write to DICFG, ignored as it's read-only");
		}
		break;

	default:
		_dbg_assert_msg_(DVDINTERFACE, 0, "Write to unknown DI address 0x%08x", _iAddress);
		break;
	}
}
Exemple #8
0
void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
{
	// Declare all the boilerplate direct MMIOs.
	struct {
		u32 addr;
		u16* ptr;
		bool align_writes_on_32_bytes;
	} directly_mapped_vars[] = {
		{ AR_INFO, &g_ARAM_Info.Hex },
		{ AR_MODE, &g_AR_MODE },
		{ AR_REFRESH, &g_AR_REFRESH },
		{ AR_DMA_MMADDR_H, MMIO::Utils::HighPart(&g_arDMA.MMAddr) },
		{ AR_DMA_MMADDR_L, MMIO::Utils::LowPart(&g_arDMA.MMAddr), true },
		{ AR_DMA_ARADDR_H, MMIO::Utils::HighPart(&g_arDMA.ARAddr) },
		{ AR_DMA_ARADDR_L, MMIO::Utils::LowPart(&g_arDMA.ARAddr), true },
		{ AR_DMA_CNT_H, MMIO::Utils::HighPart(&g_arDMA.Cnt.Hex) },
		// AR_DMA_CNT_L triggers DMA
		{ AUDIO_DMA_START_HI, MMIO::Utils::HighPart(&g_audioDMA.SourceAddress) },
		{ AUDIO_DMA_START_LO, MMIO::Utils::LowPart(&g_audioDMA.SourceAddress) },
	};
	for (auto& mapped_var : directly_mapped_vars)
	{
		u16 write_mask = mapped_var.align_writes_on_32_bytes ? 0xFFE0 : 0xFFFF;
		mmio->Register(base | mapped_var.addr,
			MMIO::DirectRead<u16>(mapped_var.ptr),
			MMIO::DirectWrite<u16>(mapped_var.ptr, write_mask)
		);
	}

	// DSP mail MMIOs call DSP emulator functions to get results or write data.
	mmio->Register(base | DSP_MAIL_TO_DSP_HI,
		MMIO::ComplexRead<u16>([](u32) {
			if (dsp_slice > DSP_MAIL_SLICE && dsp_is_lle)
			{
				dsp_emulator->DSP_Update(DSP_MAIL_SLICE);
				dsp_slice -= DSP_MAIL_SLICE;
			}
			return dsp_emulator->DSP_ReadMailBoxHigh(true);
		}),
		MMIO::ComplexWrite<u16>([](u32, u16 val) {
			dsp_emulator->DSP_WriteMailBoxHigh(true, val);
		})
	);
	mmio->Register(base | DSP_MAIL_TO_DSP_LO,
		MMIO::ComplexRead<u16>([](u32) {
			return dsp_emulator->DSP_ReadMailBoxLow(true);
		}),
		MMIO::ComplexWrite<u16>([](u32, u16 val) {
			dsp_emulator->DSP_WriteMailBoxLow(true, val);
		})
	);
	mmio->Register(base | DSP_MAIL_FROM_DSP_HI,
		MMIO::ComplexRead<u16>([](u32) {
			if (dsp_slice > DSP_MAIL_SLICE && dsp_is_lle)
			{
				dsp_emulator->DSP_Update(DSP_MAIL_SLICE);
				dsp_slice -= DSP_MAIL_SLICE;
			}
			return dsp_emulator->DSP_ReadMailBoxHigh(false);
		}),
		MMIO::InvalidWrite<u16>()
	);
	mmio->Register(base | DSP_MAIL_FROM_DSP_LO,
		MMIO::ComplexRead<u16>([](u32) {
			return dsp_emulator->DSP_ReadMailBoxLow(false);
		}),
		MMIO::InvalidWrite<u16>()
	);

	mmio->Register(base | DSP_CONTROL,
		MMIO::ComplexRead<u16>([](u32) {
			return (g_dspState.DSPControl.Hex & ~DSP_CONTROL_MASK) |
			       (dsp_emulator->DSP_ReadControlRegister() & DSP_CONTROL_MASK);
		}),
		MMIO::ComplexWrite<u16>([](u32, u16 val) {
			UDSPControl tmpControl;
			tmpControl.Hex = (val & ~DSP_CONTROL_MASK) |
				(dsp_emulator->DSP_WriteControlRegister(val) & DSP_CONTROL_MASK);

			// Not really sure if this is correct, but it works...
			// Kind of a hack because DSP_CONTROL_MASK should make this bit
			// only viewable to dsp emulator
			if (val & 1 /*DSPReset*/)
			{
				g_audioDMA.AudioDMAControl.Hex = 0;
			}

			// Update DSP related flags
			g_dspState.DSPControl.DSPReset     = tmpControl.DSPReset;
			g_dspState.DSPControl.DSPAssertInt = tmpControl.DSPAssertInt;
			g_dspState.DSPControl.DSPHalt      = tmpControl.DSPHalt;
			g_dspState.DSPControl.DSPInit      = tmpControl.DSPInit;

			// Interrupt (mask)
			g_dspState.DSPControl.AID_mask  = tmpControl.AID_mask;
			g_dspState.DSPControl.ARAM_mask = tmpControl.ARAM_mask;
			g_dspState.DSPControl.DSP_mask  = tmpControl.DSP_mask;

			// Interrupt
			if (tmpControl.AID)  g_dspState.DSPControl.AID  = 0;
			if (tmpControl.ARAM) g_dspState.DSPControl.ARAM = 0;
			if (tmpControl.DSP)  g_dspState.DSPControl.DSP  = 0;

			// unknown
			g_dspState.DSPControl.unk3 = tmpControl.unk3;
			g_dspState.DSPControl.pad  = tmpControl.pad;
			if (g_dspState.DSPControl.pad != 0)
			{
				PanicAlert("DSPInterface (w) g_dspState.DSPControl (CC00500A) gets a value with junk in the padding %08x", val);
			}

			UpdateInterrupts();
		})
	);

	// ARAM MMIO controlling the DMA start.
	mmio->Register(base | AR_DMA_CNT_L,
		MMIO::DirectRead<u16>(MMIO::Utils::LowPart(&g_arDMA.Cnt.Hex)),
		MMIO::ComplexWrite<u16>([](u32, u16 val) {
			g_arDMA.Cnt.Hex = (g_arDMA.Cnt.Hex & 0xFFFF0000) | (val & ~31);
			Do_ARAM_DMA();
		})
	);

	// Audio DMA MMIO controlling the DMA start.
	mmio->Register(base | AUDIO_DMA_CONTROL_LEN,
		MMIO::DirectRead<u16>(&g_audioDMA.AudioDMAControl.Hex),
		MMIO::ComplexWrite<u16>([](u32, u16 val) {
			g_audioDMA.AudioDMAControl.Hex = val;
			g_audioDMA.ReadAddress = g_audioDMA.SourceAddress;
			g_audioDMA.BlocksLeft = g_audioDMA.AudioDMAControl.NumBlocks;
		})
	);

	// Audio DMA blocks remaining is invalid to write to, and requires logic on
	// the read side.
	mmio->Register(base | AUDIO_DMA_BLOCKS_LEFT,
		MMIO::ComplexRead<u16>([](u32) {
			return (g_audioDMA.BlocksLeft > 0 ? g_audioDMA.BlocksLeft - 1 : 0);
		}),
		MMIO::InvalidWrite<u16>()
	);

	// 32 bit reads/writes are a combination of two 16 bit accesses.
	for (int i = 0; i < 0x1000; i += 4)
	{
		mmio->Register(base | i,
			MMIO::ReadToSmaller<u32>(mmio, base | i, base | (i + 2)),
			MMIO::WriteToSmaller<u32>(mmio, base | i, base | (i + 2))
		);
	}
}
Exemple #9
0
static void GenerateAudioInterrupt()
{
  m_Control.AIINT = 1;
  UpdateInterrupts();
}
Exemple #10
0
void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
{
  mmio->Register(
      base | AI_CONTROL_REGISTER, MMIO::DirectRead<u32>(&m_Control.hex),
      MMIO::ComplexWrite<u32>([](u32, u32 val) {
        AICR tmpAICtrl(val);

        if (m_Control.AIINTMSK != tmpAICtrl.AIINTMSK)
        {
          DEBUG_LOG(AUDIO_INTERFACE, "Change AIINTMSK to %d", tmpAICtrl.AIINTMSK);
          m_Control.AIINTMSK = tmpAICtrl.AIINTMSK;
        }

        if (m_Control.AIINTVLD != tmpAICtrl.AIINTVLD)
        {
          DEBUG_LOG(AUDIO_INTERFACE, "Change AIINTVLD to %d", tmpAICtrl.AIINTVLD);
          m_Control.AIINTVLD = tmpAICtrl.AIINTVLD;
        }

        // Set frequency of streaming audio
        if (tmpAICtrl.AISFR != m_Control.AISFR)
        {
          // AISFR rates below are intentionally inverted wrt yagcd
          DEBUG_LOG(AUDIO_INTERFACE, "Change AISFR to %s", tmpAICtrl.AISFR ? "48khz" : "32khz");
          m_Control.AISFR = tmpAICtrl.AISFR;
          g_AISSampleRate = tmpAICtrl.AISFR ? 48000 : 32000;
          g_sound_stream->GetMixer()->SetStreamInputSampleRate(g_AISSampleRate);
          g_CPUCyclesPerSample = SystemTimers::GetTicksPerSecond() / g_AISSampleRate;
        }
        // Set frequency of DMA
        if (tmpAICtrl.AIDFR != m_Control.AIDFR)
        {
          DEBUG_LOG(AUDIO_INTERFACE, "Change AIDFR to %s", tmpAICtrl.AIDFR ? "32khz" : "48khz");
          m_Control.AIDFR = tmpAICtrl.AIDFR;
          g_AIDSampleRate = tmpAICtrl.AIDFR ? 32000 : 48000;
          g_sound_stream->GetMixer()->SetDMAInputSampleRate(g_AIDSampleRate);
        }

        // Streaming counter
        if (tmpAICtrl.PSTAT != m_Control.PSTAT)
        {
          DEBUG_LOG(AUDIO_INTERFACE, "%s streaming audio", tmpAICtrl.PSTAT ? "start" : "stop");
          m_Control.PSTAT = tmpAICtrl.PSTAT;
          g_LastCPUTime = CoreTiming::GetTicks();

          CoreTiming::RemoveEvent(et_AI);
          CoreTiming::ScheduleEvent(GetAIPeriod(), et_AI);
        }

        // AI Interrupt
        if (tmpAICtrl.AIINT)
        {
          DEBUG_LOG(AUDIO_INTERFACE, "Clear AIS Interrupt");
          m_Control.AIINT = 0;
        }

        // Sample Count Reset
        if (tmpAICtrl.SCRESET)
        {
          DEBUG_LOG(AUDIO_INTERFACE, "Reset AIS sample counter");
          m_SampleCounter = 0;

          g_LastCPUTime = CoreTiming::GetTicks();
        }

        UpdateInterrupts();
      }));

  mmio->Register(base | AI_VOLUME_REGISTER, MMIO::DirectRead<u32>(&m_Volume.hex),
                 MMIO::ComplexWrite<u32>([](u32, u32 val) {
                   m_Volume.hex = val;
                   g_sound_stream->GetMixer()->SetStreamingVolume(m_Volume.left, m_Volume.right);
                 }));

  mmio->Register(base | AI_SAMPLE_COUNTER, MMIO::ComplexRead<u32>([](u32) {
                   return m_SampleCounter +
                          static_cast<u32>((CoreTiming::GetTicks() - g_LastCPUTime) /
                                           g_CPUCyclesPerSample);
                 }),
                 MMIO::ComplexWrite<u32>([](u32, u32 val) {
                   m_SampleCounter = val;
                   g_LastCPUTime = CoreTiming::GetTicks();
                   CoreTiming::RemoveEvent(et_AI);
                   CoreTiming::ScheduleEvent(GetAIPeriod(), et_AI);
                 }));

  mmio->Register(base | AI_INTERRUPT_TIMING, MMIO::DirectRead<u32>(&m_InterruptTiming),
                 MMIO::ComplexWrite<u32>([](u32, u32 val) {
                   DEBUG_LOG(AUDIO_INTERFACE, "AI_INTERRUPT_TIMING=%08x@%08x", val,
                             PowerPC::ppcState.pc);
                   m_InterruptTiming = val;
                   CoreTiming::RemoveEvent(et_AI);
                   CoreTiming::ScheduleEvent(GetAIPeriod(), et_AI);
                 }));
}
void UpdateInterrupts_Wrapper(u64 userdata, int cyclesLate)
{
	UpdateInterrupts(userdata);
}
Exemple #12
0
void C6821::Write(BYTE byRS, BYTE byData)
{
  byRS &= 3;

  switch( byRS )
  {
    /******************* port A output/DDR write *******************/
  case PIA_DDRA:

    // write output register
    if ( OUTPUT_SELECTED( m_byCTLA ) )
    {
      // update the output value
      m_byOA = byData;

      // send it to the output function
      if ( m_byDDRA )
        PIA_W_CALLBACK( m_stOutA, m_byOA & m_byDDRA );
    }

    // write DDR register
    else
    {
      if ( m_byDDRA != byData )
      {
        m_byDDRA = byData;

        // send it to the output function
        if ( m_byDDRA )
          PIA_W_CALLBACK( m_stOutA, m_byOA & m_byDDRA );
      }
    }
    break;

    /******************* port B output/DDR write *******************/
  case PIA_DDRB:

    // write output register
    if ( OUTPUT_SELECTED( m_byCTLB ) )
    {
      // update the output value
      m_byOB = byData;

      // send it to the output function
      if ( m_byDDRB )
        PIA_W_CALLBACK( m_stOutB, m_byOB & m_byDDRB );

      // CB2 is configured as output and in write strobe mode
      if ( C2_OUTPUT( m_byCTLB ) && C2_STROBE_MODE( m_byCTLB ) )
      {
        // this will cause a transition low; call the output function if we're currently high
        if ( m_byOCB2 )
          PIA_W_CALLBACK( m_stOutCB2, 0 );
        m_byOCB2 = 0;

        // if the CB2 strobe is cleared by the E, reset it right away
        if ( STROBE_E_RESET( m_byCTLB ) )
        {
          PIA_W_CALLBACK( m_stOutCB2, 1 );
          m_byOCB2 = 1;
        }
      }
    }
    // write DDR register
    else
    {
      if ( m_byDDRB != byData )
      {
        m_byDDRB = byData;

        // send it to the output function
        if ( m_byDDRB )
          PIA_W_CALLBACK( m_stOutB, m_byOB & m_byDDRB );
      }
    }
    break;

    /******************* port A control write *******************/
  case PIA_CTLA:
    // Bit 7 and 6 read only
    byData &= 0x3f;

    // CA2 is configured as output and in set/reset mode
    if ( C2_OUTPUT( byData ) )
    {
      // determine the new value
      int temp = SET_C2( byData ) ? 1 : 0;

      // if this creates a transition, call the CA2 output function
      if ( m_byOCA2 ^ temp)
        PIA_W_CALLBACK( m_stOutCA2, temp );

      // set the new value
      m_byOCA2 = temp;
    }

    // update the control register
    m_byCTLA = ( m_byCTLA & ~0x3F ) | byData;

    // update externals
    UpdateInterrupts();
    break;

    /******************* port B control write *******************/
  case PIA_CTLB:

    /* Bit 7 and 6 read only - PD 16/01/00 */

    byData &= 0x3f;

    // CB2 is configured as output and in set/reset mode
    if ( C2_OUTPUT( byData ) )
    {
      // determine the new value
      int temp = SET_C2( byData ) ? 1 : 0;

      // if this creates a transition, call the CA2 output function
      if ( m_byOCB2 ^ temp)
        PIA_W_CALLBACK( m_stOutCB2, temp );

      // set the new value
      m_byOCB2 = temp;
    }

    // update the control register
    m_byCTLB = ( m_byCTLB & ~0x3F ) | byData;

    // update externals
    UpdateInterrupts();
    break;
  }

}
Exemple #13
0
BYTE C6821::Read(BYTE byRS)
{
  BYTE retval = 0;
  byRS &= 3;
  switch ( byRS )
  {
    /******************* port A output/DDR read *******************/
  case PIA_DDRA:
    // read output register
    if ( OUTPUT_SELECTED(m_byCTLA) )
    {
      // combine input and output values
      retval = ( m_byOA & m_byDDRA ) | ( m_byIA & ~m_byDDRA );
      // IRQ flags implicitly cleared by a read
      CLEAR_IRQ1( m_byCTLA );
      CLEAR_IRQ1( m_byCTLB );
      UpdateInterrupts();
      // CA2 is configured as output and in read strobe mode
      if ( C2_OUTPUT(m_byCTLA) && C2_STROBE_MODE(m_byCTLA) )
      {
        // this will cause a transition low; call the output function if we're currently high
        if ( m_byOCA2 )
          PIA_W_CALLBACK( m_stOutCA2, 0 );
        m_byOCA2 = 0;

        // if the CA2 strobe is cleared by the E, reset it right away
        if ( STROBE_E_RESET( m_byCTLA ) )
        {
          PIA_W_CALLBACK( m_stOutCA2, 1 );
          m_byOCA2 = 1;
        }
      }
    }
    // read DDR register
    else
    {
      retval = m_byDDRA;
    }
    break;

    /******************* port B output/DDR read *******************/
  case PIA_DDRB:

    // read output register
    if ( OUTPUT_SELECTED( m_byCTLB ) )
    {
      // combine input and output values
      retval = ( m_byOB & m_byDDRB ) + ( m_byIB & ~m_byDDRB );

      // IRQ flags implicitly cleared by a read
      CLEAR_IRQ2( m_byCTLA );
      CLEAR_IRQ2( m_byCTLB );
      UpdateInterrupts();
    }
    /* read DDR register */
    else
    {
      retval = m_byDDRB;
    }
    break;

    /******************* port A control read *******************/
  case PIA_CTLA:
    // read control register
    retval = m_byCTLA;
    // when CA2 is an output, IRQA2 = 0, and is not affected by CA2 transitions.
    if ( C2_OUTPUT( m_byCTLA ) )
      retval &= ~PIA_IRQ2;
    break;

    /******************* port B control read *******************/
  case PIA_CTLB:
    retval = m_byCTLB;
    // when CB2 is an output, IRQB2 = 0, and is not affected by CB2 transitions.
    if ( C2_OUTPUT( m_byCTLB ) )
      retval &= ~PIA_IRQ2;
    break;

  }

  return retval;
}
Exemple #14
0
void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
{
	DEBUG_LOG(EXPANSIONINTERFACE, "(w32) 0x%08x channel: %i  reg: %s",
		_iValue, m_ChannelId, Debug_GetRegisterName(_iRegister));

	switch (_iRegister)
	{
	case EXI_STATUS:
		{
			UEXI_STATUS newStatus(_iValue);

			m_Status.EXIINTMASK		= newStatus.EXIINTMASK;
			if (newStatus.EXIINT)	m_Status.EXIINT = 0;

			m_Status.TCINTMASK		= newStatus.TCINTMASK;
			if (newStatus.TCINT)	m_Status.TCINT = 0;

			m_Status.CLK			= newStatus.CLK;

			if (m_ChannelId == 0 || m_ChannelId == 1)
			{
				m_Status.EXTINTMASK	= newStatus.EXTINTMASK;
				if (newStatus.EXTINT)	m_Status.EXTINT = 0;
			}

			if (m_ChannelId == 0)
				m_Status.ROMDIS		= newStatus.ROMDIS;

			IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT ^ newStatus.CHIP_SELECT);
			m_Status.CHIP_SELECT	= newStatus.CHIP_SELECT;
			if (pDevice != NULL)
				pDevice->SetCS(m_Status.CHIP_SELECT);

			UpdateInterrupts();
		}
		break;

	case EXI_DMAADDR:
		INFO_LOG(EXPANSIONINTERFACE, "Wrote DMAAddr, chan %i", m_ChannelId);
		m_DMAMemoryAddress = _iValue;
		break;

	case EXI_DMALENGTH:
		INFO_LOG(EXPANSIONINTERFACE, "Wrote DMALength, chan %i", m_ChannelId);
		m_DMALength = _iValue;
		break;

	case EXI_DMACONTROL:
		INFO_LOG(EXPANSIONINTERFACE, "Wrote DMAControl, chan %i", m_ChannelId);
		m_Control.Hex = _iValue;

		if (m_Control.TSTART)
		{
			IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT);
			if (pDevice == NULL)
				return;

			if (m_Control.DMA == 0)
			{
				// immediate data
				switch (m_Control.RW)
				{
					case EXI_READ: m_ImmData = pDevice->ImmRead(m_Control.TLEN + 1); break;
					case EXI_WRITE: pDevice->ImmWrite(m_ImmData, m_Control.TLEN + 1); break;
					case EXI_READWRITE: pDevice->ImmReadWrite(m_ImmData, m_Control.TLEN + 1); break;
					default: _dbg_assert_msg_(EXPANSIONINTERFACE,0,"EXI Imm: Unknown transfer type %i", m_Control.RW);
				}
				m_Control.TSTART = 0;
			}
			else
			{
				// DMA
				switch (m_Control.RW)
				{
					case EXI_READ: pDevice->DMARead (m_DMAMemoryAddress, m_DMALength); break;
					case EXI_WRITE: pDevice->DMAWrite(m_DMAMemoryAddress, m_DMALength); break;
					default: _dbg_assert_msg_(EXPANSIONINTERFACE,0,"EXI DMA: Unknown transfer type %i", m_Control.RW);
				}
				m_Control.TSTART = 0;
			}

			if(!m_Control.TSTART) // completed !
			{
				m_Status.TCINT = 1;
				UpdateInterrupts();
			}
		}
		break;

	case EXI_IMMDATA:
		INFO_LOG(EXPANSIONINTERFACE, "Wrote IMMData, chan %i", m_ChannelId);
		m_ImmData = _iValue;
		break;
	}
}