Fix sblaster autoinit restart and improve the auto into single cycle transfer handling
Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@4278
This commit is contained in:
		
							parent
							
								
									0622d45e38
								
							
						
					
					
						commit
						95ac285db1
					
				
					 1 changed files with 57 additions and 35 deletions
				
			
		| 
						 | 
				
			
			@ -90,7 +90,10 @@ struct SB_INFO {
 | 
			
		|||
		bool stereo,sign,autoinit;
 | 
			
		||||
		DMA_MODES mode;
 | 
			
		||||
		Bitu rate,mul;
 | 
			
		||||
		Bitu total,left,min;
 | 
			
		||||
		Bit32u singlesize;		//size for single cycle transfers
 | 
			
		||||
		Bit32u autosize;		//size for auto init transfers
 | 
			
		||||
		Bitu left;				//Left in active cycle
 | 
			
		||||
		Bitu min;			
 | 
			
		||||
		Bit64u start;
 | 
			
		||||
		union {
 | 
			
		||||
			Bit8u  b8[DMA_BUFSIZE];
 | 
			
		||||
| 
						 | 
				
			
			@ -298,8 +301,6 @@ static void DSP_DMA_CallBack(DmaChannel * chan, DMAEvent event) {
 | 
			
		|||
//			DSP_ChangeMode(MODE_DMA_MASKED);
 | 
			
		||||
			LOG(LOG_SB,LOG_NORMAL)("DMA masked,stopping output, left %d",chan->currcnt);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (event==DMA_TRANSFEREND) {
 | 
			
		||||
		if (sb.mode==MODE_DMA) sb.mode=MODE_DMA_MASKED;
 | 
			
		||||
	} else if (event==DMA_UNMASKED) {
 | 
			
		||||
		if (sb.mode==MODE_DMA_MASKED && sb.dma.mode!=DSP_DMA_NONE) {
 | 
			
		||||
			DSP_ChangeMode(MODE_DMA);
 | 
			
		||||
| 
						 | 
				
			
			@ -308,6 +309,9 @@ static void DSP_DMA_CallBack(DmaChannel * chan, DMAEvent event) {
 | 
			
		|||
			LOG(LOG_SB,LOG_NORMAL)("DMA unmasked,starting output, auto %d block %d",chan->autoinit,chan->basecnt);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		E_Exit("Unknown sblaster dma event");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define MIN_ADAPTIVE_STEP_SIZE 0
 | 
			
		||||
| 
						 | 
				
			
			@ -414,6 +418,7 @@ static void GenerateDMASound(Bitu size) {
 | 
			
		|||
	Bitu read=0;Bitu done=0;Bitu i=0;
 | 
			
		||||
	last_dma_callback = PIC_FullIndex();
 | 
			
		||||
 | 
			
		||||
	//Determine how much you should read
 | 
			
		||||
	if(sb.dma.autoinit) {
 | 
			
		||||
		if (sb.dma.left <= size) 
 | 
			
		||||
			size = sb.dma.left;
 | 
			
		||||
| 
						 | 
				
			
			@ -422,6 +427,7 @@ static void GenerateDMASound(Bitu size) {
 | 
			
		|||
			size = sb.dma.left;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//Read the actual data, process it and send it off to the mixer
 | 
			
		||||
	switch (sb.dma.mode) {
 | 
			
		||||
	case DSP_DMA_2:
 | 
			
		||||
		read=sb.dma.chan->Read(size,sb.dma.buf.b8);
 | 
			
		||||
| 
						 | 
				
			
			@ -523,6 +529,7 @@ static void GenerateDMASound(Bitu size) {
 | 
			
		|||
		sb.mode=MODE_NONE;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	//Check how many bytes were actually read
 | 
			
		||||
	sb.dma.left-=read;
 | 
			
		||||
	if (!sb.dma.left) {
 | 
			
		||||
		PIC_RemoveEvents(END_DMA_Event);
 | 
			
		||||
| 
						 | 
				
			
			@ -530,24 +537,28 @@ static void GenerateDMASound(Bitu size) {
 | 
			
		|||
			SB_RaiseIRQ(SB_IRQ_16);
 | 
			
		||||
		else 
 | 
			
		||||
			SB_RaiseIRQ(SB_IRQ_8);
 | 
			
		||||
		//Copy the new size
 | 
			
		||||
		sb.dma.left = sb.dma.total;
 | 
			
		||||
 | 
			
		||||
		if (!sb.dma.autoinit) {
 | 
			
		||||
			if (!sb.dma.left) {
 | 
			
		||||
			//Not new single cycle transfer waiting?
 | 
			
		||||
			if (!sb.dma.singlesize) {
 | 
			
		||||
				LOG(LOG_SB, LOG_NORMAL)("Single cycle transfer ended");
 | 
			
		||||
				sb.mode = MODE_NONE;
 | 
			
		||||
				sb.dma.mode = DSP_DMA_NONE;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				//Copied this value as the count for the final single cycle
 | 
			
		||||
				sb.dma.total = 0;
 | 
			
		||||
				//A single size transfer is still waiting, handle that now
 | 
			
		||||
				sb.dma.left = sb.dma.singlesize;
 | 
			
		||||
				sb.dma.singlesize = 0;
 | 
			
		||||
				LOG(LOG_SB, LOG_NORMAL)("Switch to Single cycle transfer begun");
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if (!sb.dma.left) {
 | 
			
		||||
			if (!sb.dma.autosize) {
 | 
			
		||||
				LOG(LOG_SB,LOG_NORMAL)("Auto-init transfer with 0 size");
 | 
			
		||||
				sb.mode=MODE_NONE;
 | 
			
		||||
			}
 | 
			
		||||
			//Continue with a new auto init transfer
 | 
			
		||||
			sb.dma.left = sb.dma.autosize;
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -577,8 +588,9 @@ static void DMA_Silent_Event(Bitu val) {
 | 
			
		|||
	if (!sb.dma.left) {
 | 
			
		||||
		if (sb.dma.mode >= DSP_DMA_16) SB_RaiseIRQ(SB_IRQ_16);
 | 
			
		||||
		else SB_RaiseIRQ(SB_IRQ_8);
 | 
			
		||||
		//FIX, use the auto to single switch mechanics here as well or find a better way to silence
 | 
			
		||||
		if (sb.dma.autoinit) 
 | 
			
		||||
			sb.dma.left=sb.dma.total;
 | 
			
		||||
			sb.dma.left=sb.dma.autosize;
 | 
			
		||||
		else {
 | 
			
		||||
			sb.mode=MODE_NONE;
 | 
			
		||||
			sb.dma.mode=DSP_DMA_NONE;
 | 
			
		||||
| 
						 | 
				
			
			@ -589,7 +601,6 @@ static void DMA_Silent_Event(Bitu val) {
 | 
			
		|||
		float delay=(bigger*1000.0f)/sb.dma.rate;
 | 
			
		||||
		PIC_AddEvent(DMA_Silent_Event,delay,bigger);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void END_DMA_Event(Bitu val) {
 | 
			
		||||
| 
						 | 
				
			
			@ -660,29 +671,20 @@ static void DSP_DoDMATransfer(DMA_MODES mode,Bitu freq,bool autoinit, bool stere
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#if (C_DEBUG)
 | 
			
		||||
	LOG(LOG_SB, LOG_NORMAL)("DMA Transfer:%s %s %s freq %d rate %d size %d",
 | 
			
		||||
		type,
 | 
			
		||||
		stereo ? "Stereo" : "Mono",
 | 
			
		||||
		autoinit ? "Auto-Init" : "Single-Cycle",
 | 
			
		||||
		freq, sb.dma.rate, sb.dma.total
 | 
			
		||||
		);
 | 
			
		||||
#endif
 | 
			
		||||
	//Going from an active autoinit into a single cycle
 | 
			
		||||
	if (sb.mode >= MODE_DMA && sb.dma.autoinit && !autoinit) {
 | 
			
		||||
		//Don't do anything, the total will flip over on the next transfer
 | 
			
		||||
	}
 | 
			
		||||
	//Just a normal single cycle transfer
 | 
			
		||||
	else if (!autoinit) {
 | 
			
		||||
		sb.dma.left = sb.dma.total;
 | 
			
		||||
		sb.dma.total = 0;
 | 
			
		||||
		sb.dma.left = sb.dma.singlesize;
 | 
			
		||||
		sb.dma.singlesize = 0;
 | 
			
		||||
	}
 | 
			
		||||
	//Going into an autoinit transfer
 | 
			
		||||
	else {
 | 
			
		||||
		//Transfer full cycle again
 | 
			
		||||
		sb.dma.left = sb.dma.total;
 | 
			
		||||
		sb.dma.left = sb.dma.autosize;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	sb.dma.autoinit = autoinit;
 | 
			
		||||
	sb.dma.mode = mode;
 | 
			
		||||
	sb.dma.stereo = stereo;
 | 
			
		||||
| 
						 | 
				
			
			@ -697,26 +699,36 @@ static void DSP_DoDMATransfer(DMA_MODES mode,Bitu freq,bool autoinit, bool stere
 | 
			
		|||
	//Set to be masked, the dma call can change this again.
 | 
			
		||||
	sb.mode = MODE_DMA_MASKED;
 | 
			
		||||
	sb.dma.chan->Register_Callback(DSP_DMA_CallBack);
 | 
			
		||||
 | 
			
		||||
#if (C_DEBUG)
 | 
			
		||||
	LOG(LOG_SB, LOG_NORMAL)("DMA Transfer:%s %s %s freq %d rate %d size %d",
 | 
			
		||||
		type,
 | 
			
		||||
		stereo ? "Stereo" : "Mono",
 | 
			
		||||
		autoinit ? "Auto-Init" : "Single-Cycle",
 | 
			
		||||
		freq, sb.dma.rate, sb.dma.left
 | 
			
		||||
		);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void DSP_PrepareDMA_Old(DMA_MODES mode,bool autoinit,bool sign) {
 | 
			
		||||
	sb.dma.sign=sign;
 | 
			
		||||
	if (!autoinit) sb.dma.total=1+sb.dsp.in.data[0]+(sb.dsp.in.data[1] << 8);
 | 
			
		||||
	if (!autoinit) 
 | 
			
		||||
		sb.dma.singlesize=1+sb.dsp.in.data[0]+(sb.dsp.in.data[1] << 8);
 | 
			
		||||
	sb.dma.chan=GetDMAChannel(sb.hw.dma8);
 | 
			
		||||
	DSP_DoDMATransfer(mode,sb.freq / (sb.mixer.stereo ? 2 : 1), autoinit, sb.mixer.stereo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void DSP_PrepareDMA_New(DMA_MODES mode,Bitu length,bool autoinit,bool stereo) {
 | 
			
		||||
	Bitu freq=sb.freq;
 | 
			
		||||
 | 
			
		||||
	//equal length if data format and dma channel are both 16-bit or 8-bit
 | 
			
		||||
	sb.dma.total=length;
 | 
			
		||||
	if (mode==DSP_DMA_16) {
 | 
			
		||||
		if (sb.hw.dma16!=0xff) {
 | 
			
		||||
			sb.dma.chan=GetDMAChannel(sb.hw.dma16);
 | 
			
		||||
			if (sb.dma.chan==NULL) {
 | 
			
		||||
				sb.dma.chan=GetDMAChannel(sb.hw.dma8);
 | 
			
		||||
				mode=DSP_DMA_16_ALIASED;
 | 
			
		||||
				sb.dma.total<<=1;
 | 
			
		||||
				length *= 2;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			sb.dma.chan=GetDMAChannel(sb.hw.dma8);
 | 
			
		||||
| 
						 | 
				
			
			@ -724,9 +736,16 @@ static void DSP_PrepareDMA_New(DMA_MODES mode,Bitu length,bool autoinit,bool ste
 | 
			
		|||
			//UNDOCUMENTED:
 | 
			
		||||
			//In aliased mode sample length is written to DSP as number of
 | 
			
		||||
			//16-bit samples so we need double 8-bit DMA buffer length
 | 
			
		||||
			sb.dma.total<<=1;
 | 
			
		||||
			length *= 2;
 | 
			
		||||
		}
 | 
			
		||||
	} else sb.dma.chan=GetDMAChannel(sb.hw.dma8);
 | 
			
		||||
	//Set the length to the correct register depending on mode
 | 
			
		||||
	if (autoinit) {
 | 
			
		||||
		sb.dma.autosize = length;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		sb.dma.singlesize = length;
 | 
			
		||||
	}
 | 
			
		||||
	DSP_DoDMATransfer(mode,freq,autoinit,stereo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -762,7 +781,8 @@ static void DSP_Reset(void) {
 | 
			
		|||
	PIC_RemoveEvents(DSP_FinishReset);
 | 
			
		||||
 | 
			
		||||
	sb.dma.left=0;
 | 
			
		||||
	sb.dma.total=0;
 | 
			
		||||
	sb.dma.singlesize=0;
 | 
			
		||||
	sb.dma.autosize = 0;
 | 
			
		||||
	sb.dma.stereo=false;
 | 
			
		||||
	sb.dma.sign=false;
 | 
			
		||||
	sb.dma.autoinit=false;
 | 
			
		||||
| 
						 | 
				
			
			@ -892,9 +912,10 @@ static void DSP_DoCommand(void) {
 | 
			
		|||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case 0x24:	/* Singe Cycle 8-Bit DMA ADC */
 | 
			
		||||
		sb.dma.left=sb.dma.total=1+sb.dsp.in.data[0]+(sb.dsp.in.data[1] << 8);
 | 
			
		||||
		//Directly write to left?
 | 
			
		||||
		sb.dma.left = 1 + sb.dsp.in.data[0] + (sb.dsp.in.data[1] << 8);
 | 
			
		||||
		sb.dma.sign=false;
 | 
			
		||||
		LOG(LOG_SB,LOG_ERROR)("DSP:Faked ADC for %d bytes",sb.dma.total);
 | 
			
		||||
		LOG(LOG_SB,LOG_ERROR)("DSP:Faked ADC for %d bytes",sb.dma.left);
 | 
			
		||||
		GetDMAChannel(sb.hw.dma8)->Register_Callback(DSP_ADC_CallBack);
 | 
			
		||||
		break;
 | 
			
		||||
	case 0x14:	/* Singe Cycle 8-Bit DMA DAC */
 | 
			
		||||
| 
						 | 
				
			
			@ -922,8 +943,7 @@ static void DSP_DoCommand(void) {
 | 
			
		|||
		break;
 | 
			
		||||
	case 0x48:	/* Set DMA Block Size */
 | 
			
		||||
		DSP_SB2_ABOVE;
 | 
			
		||||
		//TODO Maybe check limit for new irq?
 | 
			
		||||
		sb.dma.total=1+sb.dsp.in.data[0]+(sb.dsp.in.data[1] << 8);
 | 
			
		||||
		sb.dma.autosize=1+sb.dsp.in.data[0]+(sb.dsp.in.data[1] << 8);
 | 
			
		||||
		break;
 | 
			
		||||
	case 0x75:	/* 075h : Single Cycle 4-bit ADPCM Reference */
 | 
			
		||||
		sb.adpcm.haveref=true;
 | 
			
		||||
| 
						 | 
				
			
			@ -967,6 +987,7 @@ static void DSP_DoCommand(void) {
 | 
			
		|||
		DSP_SB16_ONLY;
 | 
			
		||||
	case 0xd0:	/* Halt 8-bit DMA */
 | 
			
		||||
//		DSP_ChangeMode(MODE_NONE);
 | 
			
		||||
		LOG(LOG_SB, LOG_NORMAL)("Halt DMA Command");
 | 
			
		||||
//		Games sometimes already program a new dma before stopping, gives noise
 | 
			
		||||
		if (sb.mode==MODE_NONE) {
 | 
			
		||||
			// possibly different code here that does not switch to MODE_DMA_PAUSE
 | 
			
		||||
| 
						 | 
				
			
			@ -989,6 +1010,7 @@ static void DSP_DoCommand(void) {
 | 
			
		|||
	case 0xd6:	/* Continue DMA 16-bit */
 | 
			
		||||
		DSP_SB16_ONLY;
 | 
			
		||||
	case 0xd4:	/* Continue DMA 8-bit*/
 | 
			
		||||
		LOG(LOG_SB, LOG_NORMAL)("Continue DMA command");
 | 
			
		||||
		if (sb.mode==MODE_DMA_PAUSE) {
 | 
			
		||||
			sb.mode=MODE_DMA_MASKED;
 | 
			
		||||
			if (sb.dma.chan!=NULL) sb.dma.chan->Register_Callback(DSP_DMA_CallBack);
 | 
			
		||||
| 
						 | 
				
			
			@ -998,10 +1020,8 @@ static void DSP_DoCommand(void) {
 | 
			
		|||
		DSP_SB16_ONLY;
 | 
			
		||||
	case 0xda:	/* Exit Autoinitialize 8-bit */
 | 
			
		||||
		DSP_SB2_ABOVE;
 | 
			
		||||
		/* Set mode to single transfer so it ends with current block */
 | 
			
		||||
		LOG(LOG_SB, LOG_NORMAL)("Exit Autoinit command");
 | 
			
		||||
		sb.dma.autoinit=false;		//Should stop itself
 | 
			
		||||
		sb.dma.total = 0;			//This will cancel the switch to single cycle mode
 | 
			
		||||
		//Should really have some sb.dma.autoexit variable since we don't support continue autoinit dsp commands
 | 
			
		||||
		break;
 | 
			
		||||
	case 0xe0:	/* DSP Identification - SB2.0+ */
 | 
			
		||||
		DSP_FlushData();
 | 
			
		||||
| 
						 | 
				
			
			@ -1052,10 +1072,12 @@ static void DSP_DoCommand(void) {
 | 
			
		|||
	case 0xf2:	/* Trigger 8bit IRQ */
 | 
			
		||||
		//Small delay in order to emulate the slowness of the DSP, fixes Llamatron 2012 and Lemmings 3D
 | 
			
		||||
		PIC_AddEvent(&DSP_RaiseIRQEvent,0.01f); 
 | 
			
		||||
		LOG(LOG_SB, LOG_NORMAL)("Trigger 8bit IRQ command");
 | 
			
		||||
		break;
 | 
			
		||||
	case 0xf3:   /* Trigger 16bit IRQ */
 | 
			
		||||
		DSP_SB16_ONLY; 
 | 
			
		||||
		SB_RaiseIRQ(SB_IRQ_16);
 | 
			
		||||
		LOG(LOG_SB, LOG_NORMAL)("Trigger 16bit IRQ command");
 | 
			
		||||
		break;
 | 
			
		||||
	case 0xf8:  /* Undocumented, pre-SB16 only */
 | 
			
		||||
		DSP_FlushData();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue