DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 #include "dosbox.h" 00020 #include "inout.h" 00021 #include "mixer.h" 00022 #include "mem.h" 00023 #include "hardware.h" 00024 #include "setup.h" 00025 #include "support.h" 00026 #include "pic.h" 00027 #include <cstring> 00028 #include <math.h> 00029 00030 #include "mame/emu.h" 00031 #include "mame/saa1099.h" 00032 00033 #define MASTER_CLOCK 7159090 00034 00035 //My mixer channel 00036 static MixerChannel * cms_chan; 00037 //Timer to disable the channel after a while 00038 static Bit32u lastWriteTicks; 00039 static Bit32u cmsBase; 00040 static saa1099_device* device[2]; 00041 00042 static void write_cms(Bitu port, Bitu val, Bitu /* iolen */) { 00043 if(cms_chan && (!cms_chan->enabled)) cms_chan->Enable(true); 00044 lastWriteTicks = (Bit32u)PIC_Ticks; 00045 switch ( port - cmsBase ) { 00046 case 1: 00047 device[0]->control_w(0, 0, (u8)val); 00048 break; 00049 case 0: 00050 device[0]->data_w(0, 0, (u8)val); 00051 break; 00052 case 3: 00053 device[1]->control_w(0, 0, (u8)val); 00054 break; 00055 case 2: 00056 device[1]->data_w(0, 0, (u8)val); 00057 break; 00058 } 00059 } 00060 00061 static void CMS_CallBack(Bitu len) { 00062 enum { 00063 BUFFER_SIZE = 2048 00064 }; 00065 00066 if ( len > BUFFER_SIZE ) 00067 return; 00068 00069 if ( cms_chan ) { 00070 00071 //Have there been 10 seconds of no commands, disable channel 00072 if ( lastWriteTicks + 10000 < PIC_Ticks ) { 00073 cms_chan->Enable( false ); 00074 return; 00075 } 00076 Bit32s result[BUFFER_SIZE][2]; 00077 Bit16s work[2][BUFFER_SIZE]; 00078 Bit16s* buffers[2] = { work[0], work[1] }; 00079 device_sound_interface::sound_stream stream; 00080 device[0]->sound_stream_update(stream, 0, buffers, (int)len); 00081 for (Bitu i = 0; i < len; i++) { 00082 result[i][0] = work[0][i]; 00083 result[i][1] = work[1][i]; 00084 } 00085 device[1]->sound_stream_update(stream, 0, buffers, (int)len); 00086 for (Bitu i = 0; i < len; i++) { 00087 result[i][0] += work[0][i]; 00088 result[i][1] += work[1][i]; 00089 } 00090 cms_chan->AddSamples_s32( len, result[0] ); 00091 } 00092 } 00093 00094 // The Gameblaster detection 00095 static Bit8u cms_detect_register = 0xff; 00096 00097 static void write_cms_detect(Bitu port, Bitu val, Bitu /* iolen */) { 00098 switch ( port - cmsBase ) { 00099 case 0x6: 00100 case 0x7: 00101 cms_detect_register = (Bit8u)val; 00102 break; 00103 } 00104 } 00105 00106 static Bitu read_cms_detect(Bitu port, Bitu /* iolen */) { 00107 Bit8u retval = 0xff; 00108 switch ( port - cmsBase ) { 00109 case 0x4: 00110 retval = 0x7f; 00111 break; 00112 case 0xa: 00113 case 0xb: 00114 retval = cms_detect_register; 00115 break; 00116 } 00117 return retval; 00118 } 00119 00120 00121 class CMS:public Module_base { 00122 private: 00123 IO_WriteHandleObject WriteHandler; 00124 IO_WriteHandleObject DetWriteHandler; 00125 IO_ReadHandleObject DetReadHandler; 00126 MixerObject MixerChan; 00127 00128 public: 00129 CMS(Section* configuration):Module_base(configuration) { 00130 Section_prop * section = static_cast<Section_prop *>(configuration); 00131 Bitu sampleRate = (Bitu)section->Get_int( "oplrate" ); 00132 cmsBase = (Bit32u)section->Get_hex("sbbase"); 00133 WriteHandler.Install( cmsBase, write_cms, IO_MB, 4 ); 00134 00135 // A standalone Gameblaster has a magic chip on it which is 00136 // sometimes used for detection. 00137 const char * sbtype=section->Get_string("sbtype"); 00138 if (!strcasecmp(sbtype,"gb")) { 00139 DetWriteHandler.Install( cmsBase + 4, write_cms_detect, IO_MB, 12 ); 00140 DetReadHandler.Install(cmsBase,read_cms_detect,IO_MB,16); 00141 } 00142 00143 /* Register the Mixer CallBack */ 00144 cms_chan = MixerChan.Install(CMS_CallBack,sampleRate,"CMS"); 00145 00146 lastWriteTicks = (Bit32u)PIC_Ticks; 00147 00148 #if 0 // unused? 00149 Bit32u freq = 7159000; //14318180 isa clock / 2 00150 #endif 00151 00152 machine_config config; 00153 device[0] = new saa1099_device(config, "", 0, 7159090); 00154 device[1] = new saa1099_device(config, "", 0, 7159090); 00155 00156 device[0]->device_start(); 00157 device[1]->device_start(); 00158 } 00159 00160 ~CMS() { 00161 cms_chan = 0; 00162 delete device[0]; 00163 delete device[1]; 00164 } 00165 }; 00166 00167 00168 static CMS* test = NULL; 00169 00170 void CMS_Init(Section* sec) { 00171 if (test == NULL) 00172 test = new CMS(sec); 00173 } 00174 void CMS_ShutDown(Section* sec) { 00175 (void)sec;//UNUSED 00176 if (test) { 00177 delete test; 00178 test = NULL; 00179 } 00180 } 00181 00182 // save state support 00183 void POD_Save_Gameblaster( std::ostream& stream ) 00184 { 00185 const char pod_name[32] = "CMS"; 00186 00187 if( stream.fail() ) return; 00188 if( !test ) return; 00189 if( !cms_chan ) return; 00190 00191 WRITE_POD( &pod_name, pod_name ); 00192 00193 //******************************************* 00194 //******************************************* 00195 //******************************************* 00196 00197 // - pure data 00198 WRITE_POD( &lastWriteTicks, lastWriteTicks ); 00199 WRITE_POD( &cmsBase, cmsBase ); 00200 WRITE_POD( &cms_detect_register, cms_detect_register ); 00201 00202 //************************************************ 00203 //************************************************ 00204 //************************************************ 00205 00206 for (int i=0; i<2; i++) { 00207 device[i]->SaveState(stream); 00208 } 00209 00210 cms_chan->SaveState(stream); 00211 } 00212 00213 00214 void POD_Load_Gameblaster( std::istream& stream ) 00215 { 00216 char pod_name[32] = {0}; 00217 00218 if( stream.fail() ) return; 00219 if( !test ) return; 00220 if( !cms_chan ) return; 00221 00222 00223 // error checking 00224 READ_POD( &pod_name, pod_name ); 00225 if( strcmp( pod_name, "CMS" ) ) { 00226 stream.clear( std::istream::failbit | std::istream::badbit ); 00227 return; 00228 } 00229 00230 //******************************************* 00231 //******************************************* 00232 //******************************************* 00233 00234 // - pure data 00235 READ_POD( &lastWriteTicks, lastWriteTicks ); 00236 READ_POD( &cmsBase, cmsBase ); 00237 READ_POD( &cms_detect_register, cms_detect_register ); 00238 00239 //************************************************ 00240 //************************************************ 00241 //************************************************ 00242 00243 for (int i=0; i<2; i++) { 00244 device[i]->LoadState(stream); 00245 } 00246 00247 cms_chan->LoadState(stream); 00248 }