DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/gameblaster.cpp
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 }