コード例 #1
0
ファイル: rsidengine.c プロジェクト: wothke/websid
/*
 * handle a potentially endless running main program (e.g. started from "init_addr").
 * @param npc 			0 means that interrupted main program is continued (whereever it was)
 * @param cycleLimit	limit the number of available CPU cycles before the processing stops
 * @return 				0= run to completion; 1= interrupted by cyclelimit or due to number of produced digi samples
 */
static uint8_t callMain(uint16_t npc, uint8_t na, uint32_t startTime, int32_t cycleLimit) {

	/*
		the way how the sequence of main and INT calls is scheduled is obviously incorrect, and
		the logic below tries to at least workaround (which does not always work) some the flaws.
		the problems arise when:
				
		scenario 1: main program is interrupted by some INT and when it later resumes it expects to
                    continue with the register content it had at the time of the interrupt (why
					is special handling needed here: any well behaved INT would perform that cleanup
					anyway.. but various songs do seem to benefit from a respective hack.. see 
					comment in cpuRegSave)	

		scenario 2: supposing a chain of INTs does not expect any interference from MAIN and registers
					are just passed on from one INT call to the next (see Jevers_Bannys_and_the_Master_Mixers.sid):
					a main call should then under no circumstances mess with the registers... (caution: doing
					too much here will harm songs like: Storebror.sid, Wonderland XII part1.sid, Comalight 13 tune4.sid)
	*/
	
	initCycleCount(0, startTime); // use new timestamps for potential digi-samples & cycleLimit check

	if (npc == 0) cpuRegSave(1, 1);

	if (npc == 0) {
		cpuRegRestore(0,0);
	} else {
		cpuReset(npc, na);	// sid init call: with 'start addr' and 'seleced track' in acc
	}
    while (cpuPcIsValid()) {
		// if a main progs is already producing samples then it is done with the "init" phase and
		// we interrupt it when we have enough samples for one screen (see Suicide_Express.sid)

		if (((cycleLimit >0) && (cpuCycles() >=cycleLimit)) || (digiGetOverflowCount() >0)) {	
			cpuRegSave(0,0);
			
			if (npc == 0) cpuRegRestore(1, 1);
			return 1;
		}		
		vicSimRasterline();
		cpuParse();
	}
	
	if (npc == 0) cpuRegRestore(1, 1);
	return 0;
}
コード例 #2
0
ファイル: rsidengine.c プロジェクト: gbraad/websid
unsigned long processInterrupt(unsigned long intMask, unsigned short npc, unsigned long startTime, signed long cycleLimit) {
	// known limitation: if the code uses ROM routines (e.g. register restore/return sequence) then we will 
	// be missing those cpu cycles in our calculation..
	
	unsigned long originalDigiCount= sDigiCount;
	
	if (isPsidDummyIrqVector()) {
		// no point in trying to keep the stack consistent for a PSID
		cpuReset();
	}

	// provide dummy return address - which we use to return from the emulation:
	// in case of RTI (e.g. progs implementing $fffe/f vector directly) this will be used "as is".
	// if some program was to return with "RTS" (e.g. legacy PSID) the address would be returned as $0001.
	
	push(0);	// addr high
	push(0);	// addr low
	push(p);	// processor status (processor would do this in case of interrupt...)	

	
	// only set pc and keep current stackpointer and registers in case player directly passes 
	// them between calls (see Look_sharp.sid)
	pc= npc;
		
	sProgramMode= intMask;
	
	initCycleCount( (intMask == NMI_OFFSET_MASK) ? 7 : 0, startTime);

    while (pc > 1 && ((cycleLimit <0) || (sCycles <cycleLimit)))
        cpuParse();
		
	sProgramMode= MAIN_OFFSET_MASK;

	if (intMask == IRQ_OFFSET_MASK) {
		sCurrentVolume= getmem(0xd418);
	}
	
	markSampleOrigin(intMask, startTime, originalDigiCount);		

	return sCycles;
}
コード例 #3
0
ファイル: rsidengine.c プロジェクト: wothke/websid
static uint32_t processInterrupt(uint32_t intMask, uint16_t npc, uint32_t startTime, int32_t cycleLimit) {
	// known limitation: if the code uses ROM routines calculation is flawed (see mock-up ROM routines).
	uint16_t originalDigiCount= digiGetCount();
	uint16_t originalDigiOverflowCount= digiGetOverflowCount();
	
	sidResetVolumeChangeCount();
	
	if (isPsidDummyIrqVector()) {
		// no point in trying to keep the stack consistent for a PSID
		cpuRegReset();
	}

	cpuResetToIrq(npc);
	cpuSetProgramMode(intMask);
	
	initCycleCount(intMask, startTime);
	
	if (intMask == IRQ_OFFSET_MASK)	{
		vicSyncRasterIRQ();
		
		// FIXME the cpu interrupt flag should also be set before starting the interrupt handler!
		// but since no one seems to have missed it yet..
	}
	
    while (cpuPcIsValid() && ((cycleLimit <0) || (cpuCycles() <cycleLimit))) {
		vicSimRasterline();
        cpuParse();
	}
	cpuSetProgramMode(MAIN_OFFSET_MASK);
	
	digiTagOrigin(intMask, startTime, originalDigiCount, originalDigiOverflowCount);		
	
	if (intMask == IRQ_OFFSET_MASK) _volUpdates+= sidGetNumberOfVolumeChanges();	// number of updates to the volume	
	
	return cpuCycles();
}