1
0
Fork 0

add possibility to close dma controllers;

remove second dma controller when tandy sound is enabled and machine=vga


Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@2377
This commit is contained in:
Sebastian Strohhäcker 2005-11-16 20:27:40 +00:00
parent 07be3858f1
commit f22e8d5041
6 changed files with 207 additions and 142 deletions

View file

@ -16,7 +16,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* $Id: dma.h,v 1.14 2005-03-24 10:18:45 qbix79 Exp $ */
/* $Id: dma.h,v 1.15 2005-11-16 20:27:39 c2woody Exp $ */
#ifndef DOSBOX_DMA_H
#define DOSBOX_DMA_H
@ -31,19 +31,6 @@ enum DMAEvent {
class DmaChannel;
typedef void (* DMA_CallBack)(DmaChannel * chan,DMAEvent event);
class DmaController {
public:
bool flipflop;
Bit8u ctrlnum;
Bit8u chanbase;
public:
DmaController(Bit8u num) {
flipflop = false;
ctrlnum = num;
chanbase = num * 4;
}
};
class DmaChannel {
public:
Bit32u pagebase;
@ -85,7 +72,37 @@ public:
Bitu Write(Bitu size, Bit8u * buffer);
};
extern DmaChannel *DmaChannels[8];
extern DmaController *DmaControllers[2];
class DmaController {
private:
Bit8u ctrlnum;
bool flipflop;
DmaChannel *DmaChannels[4];
public:
IO_ReadHandleObject DMA_ReadHandler[0x11];
IO_WriteHandleObject DMA_WriteHandler[0x11];
DmaController(Bit8u num) {
flipflop = false;
ctrlnum = num; /* first or second DMA controller */
for(Bit8u i=0;i<4;i++) {
DmaChannels[i] = new DmaChannel(i+ctrlnum*4,ctrlnum==1);
}
}
~DmaController(void) {
for(Bit8u i=0;i<4;i++) {
delete DmaChannels[i];
}
}
DmaChannel * GetChannel(Bit8u chan) {
if (chan<4) return DmaChannels[chan];
else return NULL;
}
void WriteControllerReg(Bitu reg,Bitu val,Bitu len);
Bitu ReadControllerReg(Bitu reg,Bitu len);
};
DmaChannel * GetDMAChannel(Bit8u chan);
void CloseSecondDMAController(void);
bool SecondDMAControllerAvailable(void);
#endif

View file

@ -16,7 +16,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* $Id: dosbox.cpp,v 1.89 2005-11-10 18:05:10 c2woody Exp $ */
/* $Id: dosbox.cpp,v 1.90 2005-11-16 20:27:39 c2woody Exp $ */
#include <stdlib.h>
#include <stdarg.h>
@ -341,7 +341,7 @@ void DOSBOX_Init(void) {
MSG_Add("SPEAKER_CONFIGFILE_HELP",
"pcspeaker -- Enable PC-Speaker emulation.\n"
"pcrate -- Sample rate of the PC-Speaker sound generation.\n"
"tandy -- Enable Tandy Sound System emulation (false,true,auto).\n"
"tandy -- Enable Tandy Sound System emulation (off,on,auto).\n"
" For auto Tandysound emulation is present only if machine is set to tandy.\n"
"tandyrate -- Sample rate of the Tandy 3-Voice generation.\n"
"disney -- Enable Disney Sound Source emulation.\n"

View file

@ -25,37 +25,100 @@
#include "paging.h"
#include "setup.h"
DmaChannel *DmaChannels[8];
DmaController *DmaControllers[2];
/* read a block from physical memory */
static void DMA_BlockRead(PhysPt pt,void * data,Bitu size) {
Bit8u * write=(Bit8u *) data;
for ( ; size ; size--, pt++) {
Bitu page = pt >> 12;
if (page < LINK_START)
if (page < LINK_START) /* cares for EMS pageframe etc. */
page = paging.firstmb[page];
*write++=phys_readb(page*4096 + (pt & 4095));
}
}
/* write a block into physical memory */
static void DMA_BlockWrite(PhysPt pt,void * data,Bitu size) {
Bit8u * read=(Bit8u *) data;
for ( ; size ; size--, pt++) {
Bitu page = pt >> 12;
if (page < LINK_START)
if (page < LINK_START) /* cares for EMS pageframe etc. */
page = paging.firstmb[page];
phys_writeb(page*4096 + (pt & 4095), *read++);
}
}
static void DMA_WriteControllerReg(DmaController * cont,Bitu reg,Bitu val,Bitu len) {
DmaChannel * GetDMAChannel(Bit8u chan) {
if (chan<4) {
/* channel on first DMA controller */
if (DmaControllers[0]) return DmaControllers[0]->GetChannel(chan);
} else if (chan<8) {
/* channel on second DMA controller */
if (DmaControllers[1]) return DmaControllers[1]->GetChannel(chan-4);
}
return NULL;
}
/* remove the second DMA controller (ports are removed automatically) */
void CloseSecondDMAController(void) {
if (DmaControllers[1]) {
delete DmaControllers[1];
DmaControllers[1]=NULL;
}
}
/* check availability of second DMA controller, needed for SB16 */
bool SecondDMAControllerAvailable(void) {
if (DmaControllers[1]) return true;
else return false;
}
static void DMA_Write_Port(Bitu port,Bitu val,Bitu iolen) {
if (port<0x10) {
/* write to the first DMA controller (channels 0-3) */
DmaControllers[0]->WriteControllerReg(port,val,1);
} else if (port>=0xc0 && port <=0xdf) {
/* write to the second DMA controller (channels 4-7) */
DmaControllers[1]->WriteControllerReg((port-0xc0) >> 1,val,1);
} else switch (port) {
/* write DMA page register */
case 0x81:GetDMAChannel(2)->SetPage(val);break;
case 0x82:GetDMAChannel(3)->SetPage(val);break;
case 0x83:GetDMAChannel(1)->SetPage(val);break;
case 0x89:GetDMAChannel(6)->SetPage(val);break;
case 0x8a:GetDMAChannel(7)->SetPage(val);break;
case 0x8b:GetDMAChannel(5)->SetPage(val);break;
}
}
static Bitu DMA_Read_Port(Bitu port,Bitu iolen) {
if (port<0x10) {
/* read from the first DMA controller (channels 0-3) */
return DmaControllers[0]->ReadControllerReg(port,iolen);
} else if (port>=0xc0 && port <=0xdf) {
/* read from the second DMA controller (channels 4-7) */
return DmaControllers[1]->ReadControllerReg((port-0xc0) >> 1,iolen);
} else switch (port) {
/* read DMA page register */
case 0x81:return GetDMAChannel(2)->pagenum;
case 0x82:return GetDMAChannel(3)->pagenum;
case 0x83:return GetDMAChannel(1)->pagenum;
case 0x89:return GetDMAChannel(6)->pagenum;
case 0x8a:return GetDMAChannel(7)->pagenum;
case 0x8b:return GetDMAChannel(5)->pagenum;
}
return 0;
}
void DmaController::WriteControllerReg(Bitu reg,Bitu val,Bitu len) {
DmaChannel * chan;Bitu i;
Bitu base=cont->chanbase;
switch (reg) {
/* set base address of DMA transfer (1st byte low part, 2nd byte high part) */
case 0x0:case 0x2:case 0x4:case 0x6:
chan=DmaChannels[base+(reg >> 1)];
cont->flipflop=!cont->flipflop;
if (cont->flipflop) {
chan=GetChannel(reg >> 1);
flipflop=!flipflop;
if (flipflop) {
chan->baseaddr=(chan->baseaddr&0xff00)|val;
chan->curraddr=(chan->curraddr&0xff00)|val;
} else {
@ -63,10 +126,11 @@ static void DMA_WriteControllerReg(DmaController * cont,Bitu reg,Bitu val,Bitu l
chan->curraddr=(chan->curraddr&0x00ff)|(val << 8);
}
break;
/* set DMA transfer count (1st byte low part, 2nd byte high part) */
case 0x1:case 0x3:case 0x5:case 0x7:
chan=DmaChannels[base+(reg >> 1)];
cont->flipflop=!cont->flipflop;
if (cont->flipflop) {
chan=GetChannel(reg >> 1);
flipflop=!flipflop;
if (flipflop) {
chan->basecnt=(chan->basecnt&0xff00)|val;
chan->currcnt=(chan->currcnt&0xff00)|val;
} else {
@ -80,63 +144,67 @@ static void DMA_WriteControllerReg(DmaController * cont,Bitu reg,Bitu val,Bitu l
//TODO Warning?
break;
case 0xa: /* Mask Register */
chan=DmaChannels[base+(val & 3 )];
chan=GetChannel(val & 3);
chan->SetMask((val & 0x4)>0);
break;
case 0xb: /* Mode Register */
chan=DmaChannels[base+(val & 3 )];
chan=GetChannel(val & 3);
chan->autoinit=(val & 0x10) > 0;
chan->increment=(val & 0x20) > 0;
//TODO Maybe other bits?
break;
case 0xc: /* Clear Flip/Flip */
cont->flipflop=false;
flipflop=false;
break;
case 0xd: /* Master Clear/Reset */
for (i=0;i<4;i++) {
DmaChannels[base+i]->SetMask(true);
DmaChannels[base+i]->tcount=false;
chan=GetChannel(i);
chan->SetMask(true);
chan->tcount=false;
}
cont->flipflop=false;
flipflop=false;
break;
case 0xe: /* Clear Mask register */
for (i=0;i<4;i++) {
DmaChannels[base+i]->SetMask(false);
chan=GetChannel(i);
chan->SetMask(false);
}
break;
case 0xf: /* Multiple Mask register */
for (i=0;i<4;i++) {
DmaChannels[base+i]->SetMask(val & 1);
chan=GetChannel(i);
chan->SetMask(val & 1);
val>>=1;
}
break;
}
}
static Bitu DMA_ReadControllerReg(DmaController * cont,Bitu reg,Bitu len) {
Bitu DmaController::ReadControllerReg(Bitu reg,Bitu len) {
DmaChannel * chan;Bitu i,ret;
Bitu base=cont->chanbase;
switch (reg) {
/* read base address of DMA transfer (1st byte low part, 2nd byte high part) */
case 0x0:case 0x2:case 0x4:case 0x6:
chan=DmaChannels[base+(reg >> 1)];
cont->flipflop=!cont->flipflop;
if (cont->flipflop) {
chan=GetChannel(reg >> 1);
flipflop=!flipflop;
if (flipflop) {
return chan->curraddr & 0xff;
} else {
return (chan->curraddr >> 8) & 0xff;
}
/* read DMA transfer count (1st byte low part, 2nd byte high part) */
case 0x1:case 0x3:case 0x5:case 0x7:
chan=DmaChannels[base+(reg >> 1)];
cont->flipflop=!cont->flipflop;
if (cont->flipflop) {
chan=GetChannel(reg >> 1);
flipflop=!flipflop;
if (flipflop) {
return chan->currcnt & 0xff;
} else {
return (chan->currcnt >> 8) & 0xff;
}
case 0x8:
case 0x8: /* Status Register */
ret=0;
for (i=0;i<4;i++) {
chan=DmaChannels[base+i];
chan=GetChannel(i);
if (chan->tcount) ret|=1 << i;
chan->tcount=false;
if (chan->callback) ret|=1 << (i+4);
@ -149,53 +217,21 @@ static Bitu DMA_ReadControllerReg(DmaController * cont,Bitu reg,Bitu len) {
return 0xffffffff;
}
static void DMA_Write_Port(Bitu port,Bitu val,Bitu iolen) {
if (port<0x10) {
DMA_WriteControllerReg(DmaControllers[0],port,val,1);
} else if (port>=0xc0 && port <=0xdf) {
DMA_WriteControllerReg(DmaControllers[1],(port-0xc0) >> 1,val,1);
} else switch (port) {
case 0x81:DmaChannels[2]->SetPage(val);break;
case 0x82:DmaChannels[3]->SetPage(val);break;
case 0x83:DmaChannels[1]->SetPage(val);break;
case 0x89:DmaChannels[6]->SetPage(val);break;
case 0x8a:DmaChannels[7]->SetPage(val);break;
case 0x8b:DmaChannels[5]->SetPage(val);break;
}
}
static Bitu DMA_Read_Port(Bitu port,Bitu iolen) {
if (port<0x10) {
return DMA_ReadControllerReg(DmaControllers[0],port,iolen);
} else if (port>=0xc0 && port <=0xdf) {
return DMA_ReadControllerReg(DmaControllers[1],(port-0xc0) >> 1,iolen);
} else switch (port) {
case 0x81:return DmaChannels[2]->pagenum;
case 0x82:return DmaChannels[3]->pagenum;
case 0x83:return DmaChannels[1]->pagenum;
case 0x89:return DmaChannels[6]->pagenum;
case 0x8a:return DmaChannels[7]->pagenum;
case 0x8b:return DmaChannels[5]->pagenum;
}
return 0;
}
DmaChannel::DmaChannel(Bit8u num, bool dma16) {
masked = true;
callback = NULL;
if(num == 4) return;
channum = num;
DMA16 = dma16 ? 0x1 : 0x0;
pagenum = 0;
pagebase = 0;
baseaddr = 0;
curraddr = 0;
basecnt = 0;
currcnt = 0;
increment = true;
autoinit = false;
tcount = false;
masked = true;
callback = NULL;
if(num == 4) return;
channum = num;
DMA16 = dma16 ? 0x1 : 0x0;
pagenum = 0;
pagebase = 0;
baseaddr = 0;
curraddr = 0;
basecnt = 0;
currcnt = 0;
increment = true;
autoinit = false;
tcount = false;
}
Bitu DmaChannel::Read(Bitu want, Bit8u * buffer) {
@ -226,6 +262,7 @@ again:
}
return done;
}
Bitu DmaChannel::Write(Bitu want, Bit8u * buffer) {
Bitu done=0;
again:
@ -256,40 +293,42 @@ again:
}
class DMA:public Module_base{
private:
IO_ReadHandleObject ReadHandler[0x22];
IO_WriteHandleObject WriteHandler[0x22];
public:
DMA(Section* configuration):Module_base(configuration){
Bitu i;
DmaControllers[0] = new DmaController(0);
DmaControllers[1] = new DmaController(1);
if (machine==MCH_VGA) DmaControllers[1] = new DmaController(1);
for(i=0;i<8;i++) {
DmaChannels[i] = new DmaChannel(i,i>=4);
}
for (i=0;i<0x10;i++) {
Bitu mask=IO_MB;
if (i<8) mask|=IO_MW;
WriteHandler[i].Install(i,DMA_Write_Port,mask);
ReadHandler[i].Install(i,DMA_Read_Port,mask);
/* install handler for first DMA controller ports */
DmaControllers[0]->DMA_WriteHandler[i].Install(i,DMA_Write_Port,mask);
DmaControllers[0]->DMA_ReadHandler[i].Install(i,DMA_Read_Port,mask);
if (machine==MCH_VGA) {
WriteHandler[0x10+i].Install(0xc0+i*2,DMA_Write_Port,mask);
ReadHandler[0x10+i].Install(0xc0+i*2,DMA_Read_Port,mask);
/* install handler for second DMA controller ports */
DmaControllers[1]->DMA_WriteHandler[i].Install(0xc0+i*2,DMA_Write_Port,mask);
DmaControllers[1]->DMA_ReadHandler[i].Install(0xc0+i*2,DMA_Read_Port,mask);
}
}
WriteHandler[0x20].Install(0x81,DMA_Write_Port,IO_MB,3);
WriteHandler[0x21].Install(0x89,DMA_Write_Port,IO_MB,3);
ReadHandler[0x20].Install(0x81,DMA_Read_Port,IO_MB,3);
ReadHandler[0x21].Install(0x89,DMA_Read_Port,IO_MB,3);
/* install handlers for ports 0x81-0x83 (on the first DMA controller) */
DmaControllers[0]->DMA_WriteHandler[0x10].Install(0x81,DMA_Write_Port,IO_MB,3);
DmaControllers[0]->DMA_ReadHandler[0x10].Install(0x81,DMA_Read_Port,IO_MB,3);
if (machine==MCH_VGA) {
/* install handlers for ports 0x81-0x83 (on the second DMA controller) */
DmaControllers[1]->DMA_WriteHandler[0x10].Install(0x89,DMA_Write_Port,IO_MB,3);
DmaControllers[1]->DMA_ReadHandler[0x10].Install(0x89,DMA_Read_Port,IO_MB,3);
}
}
~DMA(){
delete DmaControllers[0];
delete DmaControllers[1];
for(Bitu i=0;i<8;i++) {
delete DmaChannels[i];
if (DmaControllers[0]) {
delete DmaControllers[0];
DmaControllers[0]=NULL;
}
if (DmaControllers[1]) {
delete DmaControllers[1];
DmaControllers[1]=NULL;
}
}
};

View file

@ -83,8 +83,8 @@ struct GFGus {
} timers[2];
Bit32u rate;
Bit16u portbase;
Bit16u dma1;
Bit16u dma2;
Bit8u dma1;
Bit8u dma2;
Bit16u irq1;
Bit16u irq2;
@ -568,7 +568,7 @@ static void ExecuteGlobRegister(void) {
break;
case 0x41: // Dma control register
myGUS.DMAControl = (Bit8u)(myGUS.gRegData>>8);
DmaChannels[myGUS.dma1]->Register_Callback(
GetDMAChannel(myGUS.dma1)->Register_Callback(
(myGUS.DMAControl & 0x1) ? GUS_DMA_Callback : 0);
break;
case 0x42: // Gravis DRAM DMA address register
@ -597,7 +597,7 @@ static void ExecuteGlobRegister(void) {
break;
case 0x49: // DMA sampling control register
myGUS.SampControl = (Bit8u)(myGUS.gRegData>>8);
DmaChannels[myGUS.dma1]->Register_Callback(
GetDMAChannel(myGUS.dma1)->Register_Callback(
(myGUS.SampControl & 0x1) ? GUS_DMA_Callback : 0);
break;
case 0x4c: // GUS reset register

View file

@ -518,7 +518,7 @@ static void DSP_RaiseIRQEvent(Bitu val) {
SB_RaiseIRQ(SB_IRQ_8);
}
static void DSP_DoDMATranfser(DMA_MODES mode,Bitu freq,bool stereo) {
static void DSP_DoDMATransfer(DMA_MODES mode,Bitu freq,bool stereo) {
char * type;
sb.mode=MODE_DMA_MASKED;
sb.chan->FillUp();
@ -576,8 +576,8 @@ static void DSP_DoDMATranfser(DMA_MODES mode,Bitu freq,bool stereo) {
static void DSP_PrepareDMA_Old(DMA_MODES mode,bool autoinit) {
sb.dma.autoinit=autoinit;
if (!autoinit) sb.dma.total=1+sb.dsp.in.data[0]+(sb.dsp.in.data[1] << 8);
sb.dma.chan=DmaChannels[sb.hw.dma8];
DSP_DoDMATranfser(mode,sb.freq / (sb.mixer.stereo ? 2 : 1),sb.mixer.stereo);
sb.dma.chan=GetDMAChannel(sb.hw.dma8);
DSP_DoDMATransfer(mode,sb.freq / (sb.mixer.stereo ? 2 : 1),sb.mixer.stereo);
}
static void DSP_PrepareDMA_New(DMA_MODES mode,Bitu length,bool autoinit,bool stereo) {
@ -585,14 +585,14 @@ static void DSP_PrepareDMA_New(DMA_MODES mode,Bitu length,bool autoinit,bool ste
sb.dma.total=length;
sb.dma.autoinit=autoinit;
if (mode==DSP_DMA_16) {
if (sb.hw.dma16!=0xff) sb.dma.chan=DmaChannels[sb.hw.dma16];
if (sb.hw.dma16!=0xff) sb.dma.chan=GetDMAChannel(sb.hw.dma16);
else {
sb.dma.chan=DmaChannels[sb.hw.dma8];
sb.dma.chan=GetDMAChannel(sb.hw.dma8);
mode=DSP_DMA_16_ALIASED;
freq/=2;
}
} else sb.dma.chan=DmaChannels[sb.hw.dma8];
DSP_DoDMATranfser(mode,freq,stereo);
} else sb.dma.chan=GetDMAChannel(sb.hw.dma8);
DSP_DoDMATransfer(mode,freq,stereo);
}
@ -650,19 +650,21 @@ static void DSP_DoReset(Bit8u val) {
static void DSP_E2_DMA_CallBack(DmaChannel * chan, DMAEvent event) {
if (event==DMA_UNMASKED) {
Bit8u val=sb.e2.value;
DmaChannels[sb.hw.dma8]->Register_Callback(0);
DmaChannels[sb.hw.dma8]->Write(1,&val);
DmaChannel * chan=GetDMAChannel(sb.hw.dma8);
chan->Register_Callback(0);
chan->Write(1,&val);
}
}
static void DSP_ADC_CallBack(DmaChannel * chan, DMAEvent event) {
if (event!=DMA_UNMASKED) return;
Bit8u val=128;
DmaChannel * ch=GetDMAChannel(sb.hw.dma8);
while (sb.dma.left--) {
DmaChannels[sb.hw.dma8]->Write(1,&val);
ch->Write(1,&val);
}
SB_RaiseIRQ(SB_IRQ_8);
DmaChannels[sb.hw.dma8]->Register_Callback(0);
ch->Register_Callback(0);
}
Bitu DEBUG_EnableDebugger(void);
@ -684,7 +686,7 @@ static void DSP_DoCommand(void) {
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);
LOG(LOG_SB,LOG_ERROR)("DSP:Faked ADC for %d bytes",sb.dma.total);
DmaChannels[sb.hw.dma8]->Register_Callback(DSP_ADC_CallBack);
GetDMAChannel(sb.hw.dma8)->Register_Callback(DSP_ADC_CallBack);
break;
case 0x14: /* Singe Cycle 8-Bit DMA DAC */
case 0x91: /* Singe Cycle 8-Bit DMA High speed DAC */
@ -794,7 +796,7 @@ static void DSP_DoCommand(void) {
if ((sb.dsp.in.data[0] >> i) & 0x01) sb.e2.value += E2_incr_table[sb.e2.count % 4][i];
sb.e2.value += E2_incr_table[sb.e2.count % 4][8];
sb.e2.count++;
DmaChannels[sb.hw.dma8]->Register_Callback(DSP_E2_DMA_CallBack);
GetDMAChannel(sb.hw.dma8)->Register_Callback(DSP_E2_DMA_CallBack);
}
break;
case 0xe3: /* DSP Copyright */
@ -1105,12 +1107,14 @@ private:
else if (!strcasecmp(sbtype,"sb16")) type=SBT_16;
else if (!strcasecmp(sbtype,"none")) type=SBT_NONE;
else type=SBT_16;
if (machine!=MCH_VGA && type==SBT_16) type=SBT_PRO2;
if (type==SBT_16) {
if ((machine!=MCH_VGA) || !SecondDMAControllerAvailable()) type=SBT_PRO2;
}
/* OPL/CMS Init */
const char * omode=config->Get_string("oplmode");
if (!strcasecmp(omode,"none")) opl_mode=OPL_none;
if (!strcasecmp(omode,"none")) opl_mode=OPL_none;
else if (!strcasecmp(omode,"cms")) opl_mode=OPL_cms;
else if (!strcasecmp(omode,"opl2")) opl_mode=OPL_opl2;
else if (!strcasecmp(omode,"dualopl2")) opl_mode=OPL_dualopl2;
@ -1186,7 +1190,6 @@ public:
}
~SBLASTER() {
Bitu i;
Section_prop * section=static_cast<Section_prop *>(m_configuration);
OPL_Mode opl_mode;
Find_Type_And_Opl(section,sb.type,opl_mode);

View file

@ -27,6 +27,7 @@
#include "mem.h"
#include "setup.h"
#include "pic.h"
#include "dma.h"
#define DAC_CLOCK 3570000
#define MAX_OUTPUT 0x7fff
@ -308,7 +309,7 @@ static void SN76496_set_gain(int gain)
class TANDYSOUND: public Module_base {
private:
IO_WriteHandleObject WriteHandler[2];
IO_WriteHandleObject WriteHandler[3];
MixerObject MixerChan;
public:
TANDYSOUND(Section* configuration):Module_base(configuration){
@ -318,16 +319,21 @@ public:
if (machine==MCH_TANDY) {
/* enable tandy sound if tandy=true/auto */
if ((strcmp(section->Get_string("tandy"),"true")!=0) &&
(strcmp(section->Get_string("tandy"),"on")!=0) &&
(strcmp(section->Get_string("tandy"),"auto")!=0)) return;
} else {
/* only enable tandy sound if tandy=true */
if (strcmp(section->Get_string("tandy"),"true")!=0) return;
if ((strcmp(section->Get_string("tandy"),"true")!=0) &&
(strcmp(section->Get_string("tandy"),"on")!=0)) return;
/* ports from second DMA controller conflict with tandy ports */
CloseSecondDMAController();
WriteHandler[2].Install(0x1e0,SN76496Write,IO_MB,2);
}
if (machine==MCH_TANDY) {
WriteHandler[0].Install(0xc0,SN76496Write,IO_MB,2);
WriteHandler[1].Install(0xc4,TandyDACWrite,IO_MB,4);
} else WriteHandler[0].Install(0x1e0,SN76496Write,IO_MB,2);
WriteHandler[0].Install(0xc0,SN76496Write,IO_MB,2);
WriteHandler[1].Install(0xc4,TandyDACWrite,IO_MB,4);
Bit32u sample_rate = section->Get_int("tandyrate");