Fixes to the gus timers
More accurate timing using dosbox internal events Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@1834
This commit is contained in:
parent
31fe898cf5
commit
38cb5b88ca
1 changed files with 60 additions and 70 deletions
|
@ -65,10 +65,12 @@ struct GFGus {
|
|||
Bit32s muperchan;
|
||||
|
||||
struct GusTimer {
|
||||
Bit16u bytetimer;
|
||||
Bit32s countdown;
|
||||
Bit32s setting;
|
||||
bool active;
|
||||
Bit8u value;
|
||||
bool reached;
|
||||
bool raiseirq;
|
||||
bool masked;
|
||||
bool running;
|
||||
Bit32u delay;
|
||||
} timers[2];
|
||||
Bit32u rate;
|
||||
Bit16u portbase;
|
||||
|
@ -86,8 +88,7 @@ struct GFGus {
|
|||
struct IRQStat {
|
||||
bool MIDITx;
|
||||
bool MIDIRx;
|
||||
bool T1;
|
||||
bool T2;
|
||||
bool T[2];
|
||||
bool Resv;
|
||||
bool WaveTable;
|
||||
bool VolRamp;
|
||||
|
@ -503,19 +504,22 @@ static void GUSReset(void)
|
|||
myGUS.irqenabled = false;
|
||||
}
|
||||
|
||||
myGUS.timers[0].active = false;
|
||||
myGUS.timers[1].active = false;
|
||||
myGUS.timers[0].bytetimer = 0x0;
|
||||
myGUS.timers[1].bytetimer = 0x0;
|
||||
myGUS.timers[0].raiseirq = false;
|
||||
myGUS.timers[1].raiseirq = false;
|
||||
myGUS.timers[0].reached = false;
|
||||
myGUS.timers[1].reached = false;
|
||||
myGUS.timers[0].running = false;
|
||||
myGUS.timers[1].running = false;
|
||||
|
||||
myGUS.timers[0].value = 0xff;
|
||||
myGUS.timers[1].value = 0xff;
|
||||
|
||||
// Stop all channels
|
||||
int i;
|
||||
for(i=0;i<32;i++) {
|
||||
guschan[i]->WriteVoiceCtrl(0x3);
|
||||
|
||||
}
|
||||
IRQFifo.stackpos = -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -601,6 +605,15 @@ static Bit16u ExecuteReadRegister(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void GUS_TimerEvent(Bitu val) {
|
||||
if (!myGUS.timers[val].masked) myGUS.timers[val].reached=true;
|
||||
if (myGUS.timers[val].raiseirq) {
|
||||
myGUS.irq.T[val]=true;
|
||||
PIC_ActivateIRQ(myGUS.irq1);
|
||||
}
|
||||
if (myGUS.timers[val].running) PIC_AddEvent(GUS_TimerEvent,myGUS.timers[val].delay,val);
|
||||
};
|
||||
|
||||
|
||||
static void ExecuteGlobRegister(void) {
|
||||
int i;
|
||||
|
@ -721,21 +734,18 @@ static void ExecuteGlobRegister(void) {
|
|||
break;
|
||||
case 0x45: // Timer control register. Identical in operation to Adlib's timer
|
||||
myGUS.TimerControl = (Bit8u)(myGUS.gRegData>>8);
|
||||
if((myGUS.TimerControl & 0x08) !=0) myGUS.timers[1].countdown = myGUS.timers[1].setting;
|
||||
if((myGUS.TimerControl & 0x04) !=0) myGUS.timers[0].countdown = myGUS.timers[0].setting;
|
||||
myGUS.irq.T1 = false;
|
||||
myGUS.irq.T2 = false;
|
||||
PIC_DeActivateIRQ(myGUS.irq1);
|
||||
myGUS.timers[0].raiseirq=(myGUS.TimerControl & 0x04)>0;
|
||||
if (!myGUS.timers[0].raiseirq) myGUS.irq.T[0]=false;
|
||||
myGUS.timers[1].raiseirq=(myGUS.TimerControl & 0x08)>0;
|
||||
if (!myGUS.timers[1].raiseirq) myGUS.irq.T[1]=false;
|
||||
break;
|
||||
case 0x46: // Timer 1 control
|
||||
myGUS.timers[0].bytetimer = (Bit8u)(myGUS.gRegData>>8);
|
||||
myGUS.timers[0].setting = ((Bit32s)0xff - (Bit32s)myGUS.timers[0].bytetimer) * ((Bit32s)80 << 10);
|
||||
myGUS.timers[0].countdown = myGUS.timers[0].setting;
|
||||
myGUS.timers[0].value = (Bit8u)(myGUS.gRegData>>8);
|
||||
myGUS.timers[0].delay = (0x100 - myGUS.timers[0].value) * 80;
|
||||
break;
|
||||
case 0x47: // Timer 2 control
|
||||
myGUS.timers[1].bytetimer = (Bit8u)(myGUS.gRegData>>8);
|
||||
myGUS.timers[1].setting = ((Bit32s)0xff - (Bit32s)myGUS.timers[1].bytetimer) * ((Bit32s)360 << 10);
|
||||
myGUS.timers[1].countdown = myGUS.timers[1].setting;
|
||||
myGUS.timers[1].value = (Bit8u)(myGUS.gRegData>>8);
|
||||
myGUS.timers[1].delay = (0x100 - myGUS.timers[1].value) * 320;
|
||||
break;
|
||||
case 0x49: // DMA sampling control register
|
||||
myGUS.SampControl = (Bit8u)(myGUS.gRegData>>8);
|
||||
|
@ -759,8 +769,8 @@ static Bitu read_gus(Bitu port,Bitu iolen) {
|
|||
temp = 0;
|
||||
if(myGUS.irq.MIDITx) temp |= 1;
|
||||
if(myGUS.irq.MIDIRx) temp |= 2;
|
||||
if(myGUS.irq.T1) temp |= 4;
|
||||
if(myGUS.irq.T2) temp |= 8;
|
||||
if(myGUS.irq.T[0]) temp |= 4;
|
||||
if(myGUS.irq.T[1]) temp |= 8;
|
||||
if(myGUS.irq.Resv) temp |= 16;
|
||||
if(myGUS.irq.WaveTable) temp |= 32;
|
||||
if(myGUS.irq.VolRamp) temp |= 64;
|
||||
|
@ -770,9 +780,11 @@ static Bitu read_gus(Bitu port,Bitu iolen) {
|
|||
case 0x208:
|
||||
Bit8u tmptime;
|
||||
tmptime = 0;
|
||||
if(myGUS.irq.T1) tmptime |= (1 << 6);
|
||||
if(myGUS.irq.T2) tmptime |= (1 << 5);
|
||||
if((myGUS.irq.T1) || (myGUS.irq.T2)) tmptime |= (1 << 7);
|
||||
if (myGUS.timers[0].reached) tmptime |= (1 << 6);
|
||||
if (myGUS.timers[1].reached) tmptime |= (1 << 5);
|
||||
if (tmptime & 0x60) tmptime |= (1 << 7);
|
||||
if (myGUS.irq.T[0]) tmptime|=(1 << 2);
|
||||
if (myGUS.irq.T[1]) tmptime|=(1 << 1);
|
||||
return tmptime;
|
||||
case 0x20a:
|
||||
return adlib_commandreg;
|
||||
|
@ -810,8 +822,25 @@ static void write_gus(Bitu port,Bitu val,Bitu iolen) {
|
|||
break;
|
||||
case 0x209:
|
||||
//TODO adlib_commandreg should be 4 for this to work else it should just latch the value
|
||||
myGUS.timers[0].active = ((val & 0x1) > 0);
|
||||
myGUS.timers[1].active = ((val & 0x2) > 0);
|
||||
if (val & 0x80) {
|
||||
myGUS.timers[0].reached=false;
|
||||
myGUS.timers[1].reached=false;
|
||||
return;
|
||||
}
|
||||
myGUS.timers[0].masked=(val & 0x40)>0;
|
||||
myGUS.timers[1].masked=(val & 0x20)>0;
|
||||
if (val & 0x1) {
|
||||
if (!myGUS.timers[0].running) {
|
||||
PIC_AddEvent(GUS_TimerEvent,myGUS.timers[0].delay,0);
|
||||
myGUS.timers[0].running=true;
|
||||
}
|
||||
} else myGUS.timers[0].running=false;
|
||||
if (val & 0x2) {
|
||||
if (!myGUS.timers[1].running) {
|
||||
PIC_AddEvent(GUS_TimerEvent,myGUS.timers[1].delay,1);
|
||||
myGUS.timers[1].running=true;
|
||||
}
|
||||
} else myGUS.timers[1].running=false;
|
||||
break;
|
||||
//TODO Check if 0x20a register is also available on the gus like on the interwave
|
||||
case 0x20b:
|
||||
|
@ -830,7 +859,6 @@ static void write_gus(Bitu port,Bitu val,Bitu iolen) {
|
|||
LOG_GUS("Attempt to assign GUS to wrong DMA - at %x, assigned %x", myGUS.dma1, dmatable[temp]);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x302:
|
||||
myGUS.gCurChannel = val ;
|
||||
|
@ -850,7 +878,6 @@ static void write_gus(Bitu port,Bitu val,Bitu iolen) {
|
|||
myGUS.gRegData = (0x00ff & myGUS.gRegData) | val << 8;
|
||||
ExecuteGlobRegister();
|
||||
break;
|
||||
|
||||
case 0x307:
|
||||
if(myGUS.gDramAddr < sizeof(GUSRam)) GUSRam[myGUS.gDramAddr] = val;
|
||||
break;
|
||||
|
@ -916,39 +943,11 @@ static void GUS_CallBack(Bit8u * stream,Bit32u len) {
|
|||
}
|
||||
bufptr[i] = (Bit16s)(sample);
|
||||
}
|
||||
|
||||
if(myGUS.irqenabled) {
|
||||
if(IRQFifo.stackpos >= 0) {
|
||||
PIC_ActivateIRQ(myGUS.irq1);
|
||||
}
|
||||
}
|
||||
|
||||
if(myGUS.timers[0].active) {
|
||||
myGUS.timers[0].countdown-=(len * (Bit32u)myGUS.mupersamp);
|
||||
if(!myGUS.irq.T1) {
|
||||
// Expire Timer 1
|
||||
if(myGUS.timers[0].countdown < 0) {
|
||||
if((myGUS.TimerControl & 0x04) !=0) {
|
||||
PIC_ActivateIRQ(myGUS.irq1);
|
||||
}
|
||||
myGUS.irq.T1 = true;
|
||||
//LOG_GUS("T1 timer expire");
|
||||
//myGUS.timers[0].countdown = myGUS.timers[0].setting;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(myGUS.timers[1].active) {
|
||||
if(!myGUS.irq.T2) {
|
||||
myGUS.timers[1].countdown-=(len * (Bit32u)myGUS.mupersamp);
|
||||
// Expire Timer 2
|
||||
if(myGUS.timers[1].countdown < 0) {
|
||||
if((myGUS.TimerControl & 0x08) !=0) {
|
||||
PIC_ActivateIRQ(myGUS.irq1);
|
||||
}
|
||||
myGUS.irq.T2 = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -979,8 +978,6 @@ void MakeTables(void)
|
|||
|
||||
|
||||
void GUS_Init(Section* sec) {
|
||||
|
||||
|
||||
memset(&myGUS,0,sizeof(myGUS));
|
||||
memset(GUSRam,0,1024*1024);
|
||||
|
||||
|
@ -995,11 +992,6 @@ void GUS_Init(Section* sec) {
|
|||
myGUS.irq2 = section->Get_int("irq2");
|
||||
strcpy(&myGUS.ultradir[0], section->Get_string("ultradir"));
|
||||
|
||||
adlib_commandreg = 85;
|
||||
myGUS.timers[0].active = false;
|
||||
myGUS.timers[1].active = false;
|
||||
|
||||
|
||||
memset(&myGUS.irq, 0, sizeof(myGUS.irq));
|
||||
IRQFifo.stackpos = -1;
|
||||
myGUS.irqenabled = false;
|
||||
|
@ -1049,13 +1041,11 @@ void GUS_Init(Section* sec) {
|
|||
for(i=0;i<=32;i++) {
|
||||
guschan[i] = new GUSChannels(i);
|
||||
}
|
||||
|
||||
// Register the Mixer CallBack
|
||||
|
||||
gus_chan=MIXER_AddChannel(GUS_CallBack,GUS_RATE,"GUS");
|
||||
MIXER_SetMode(gus_chan,MIXER_16STEREO);
|
||||
MIXER_Enable(gus_chan,false);
|
||||
|
||||
GUSReset();
|
||||
int portat = 0x200+GUS_BASE;
|
||||
// ULTRASND=Port,DMA1,DMA2,IRQ1,IRQ2
|
||||
SHELL_AddAutoexec("SET ULTRASND=%3X,%d,%d,%d,%d",portat,myGUS.dma1,myGUS.dma2,myGUS.irq1,myGUS.irq2);
|
||||
|
|
Loading…
Add table
Reference in a new issue