- added instructions how to update the online documentation
[bochs-mirror.git] / iodev / sb16.cc
blob27ec032247d8f55a46e5a8149574778f0f417335
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: sb16.cc,v 1.64 2008/12/11 18:01:56 vruppert Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2002 MandrakeSoft S.A.
6 //
7 // MandrakeSoft S.A.
8 // 43, rue d'Aboukir
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 /////////////////////////////////////////////////////////////////////////
29 // This file (SB16.CC) written and donated by Josef Drexler
31 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
32 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
33 // is used to know when we are exporting symbols and when we are importing.
34 #define BX_PLUGGABLE
36 #include "iodev.h"
37 #if BX_SUPPORT_SB16
39 #include "soundlnx.h"
40 #include "soundwin.h"
41 #include "soundosx.h"
43 #define LOG_THIS theSB16Device->
45 bx_sb16_c *theSB16Device = NULL;
47 int libsb16_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
49 theSB16Device = new bx_sb16_c();
50 BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theSB16Device, BX_PLUGIN_SB16);
51 return(0); // Success
54 void libsb16_LTX_plugin_fini(void)
56 delete theSB16Device;
59 // some shortcuts to save typing
60 #define LOGFILE BX_SB16_THIS logfile
61 #define MIDIDATA BX_SB16_THIS midifile
62 #define WAVEDATA BX_SB16_THIS wavefile
63 #define MPU BX_SB16_THIS mpu401
64 #define DSP BX_SB16_THIS dsp
65 #define MIXER BX_SB16_THIS mixer
66 #define EMUL BX_SB16_THIS emuldata
67 #define OPL BX_SB16_THIS opl
69 #define BX_SB16_OUTPUT BX_SB16_THIS output
71 // here's a safe way to print out null pointeres
72 #define MIGHT_BE_NULL(x) ((x==NULL)? "(null)" : x)
74 bx_sb16_c::bx_sb16_c(void)
76 put("SB16");
77 settype(SB16LOG);
78 mpu401.timer_handle = BX_NULL_TIMER_HANDLE;
79 dsp.timer_handle = BX_NULL_TIMER_HANDLE;
80 opl.timer_handle = BX_NULL_TIMER_HANDLE;
81 midimode = 0;
82 midifile = NULL;
83 wavemode = 0;
84 wavefile = NULL;
85 loglevel = 0;
88 bx_sb16_c::~bx_sb16_c(void)
90 switch (midimode)
92 case 2:
93 if (MIDIDATA != NULL)
94 finishmidifile();
95 break;
96 case 1:
97 if (MPU.outputinit != 0)
98 BX_SB16_OUTPUT->closemidioutput();
99 break;
100 case 3:
101 if (MIDIDATA != NULL)
102 fclose(MIDIDATA);
103 break;
106 switch (wavemode)
108 case 2:
109 if (WAVEDATA != NULL)
110 finishvocfile();
111 break;
112 case 1:
113 if (DSP.outputinit != 0)
114 BX_SB16_OUTPUT->closewaveoutput();
115 break;
116 case 3:
117 if (WAVEDATA != NULL)
118 fclose(WAVEDATA);
119 break;
122 delete(BX_SB16_OUTPUT);
124 delete [] DSP.dma.chunk;
126 if ((SIM->get_param_num(BXPN_SB16_LOGLEVEL)->get() > 0) && LOGFILE)
127 fclose(LOGFILE);
129 SIM->get_param_num(BXPN_SB16_DMATIMER)->set_handler(NULL);
130 SIM->get_param_num(BXPN_SB16_LOGLEVEL)->set_handler(NULL);
132 BX_DEBUG(("Exit"));
135 void bx_sb16_c::init(void)
137 unsigned addr, i;
138 bx_list_c *base;
140 base = (bx_list_c*) SIM->get_param(BXPN_SB16);
141 if ((strlen(SIM->get_param_string("logfile", base)->getptr()) < 1))
142 SIM->get_param_num("loglevel", base)->set(0);
144 if (SIM->get_param_num("loglevel", base)->get() > 0)
146 LOGFILE = fopen(SIM->get_param_string("logfile", base)->getptr(),"w"); // logfile for errors etc.
147 if (LOGFILE == NULL)
149 BX_ERROR(("Error opening file %s. Logging disabled.", SIM->get_param_string("logfile", base)->getptr()));
150 SIM->get_param_num("loglevel", base)->set(0);
153 BX_SB16_THIS midimode = SIM->get_param_num("midimode", base)->get();
154 BX_SB16_THIS wavemode = SIM->get_param_num("wavemode", base)->get();
155 BX_SB16_THIS dmatimer = SIM->get_param_num("dmatimer", base)->get();
156 BX_SB16_THIS loglevel = SIM->get_param_num("loglevel", base)->get();
158 // let the output functions initialize
159 BX_SB16_OUTPUT = new BX_SOUND_OUTPUT_C(BX_SB16_THISP);
161 if (BX_SB16_OUTPUT == NULL)
163 writelog(MIDILOG(2), "Couldn't initialize output devices. Output disabled.");
164 BX_SB16_THIS midimode = 0;
165 BX_SB16_THIS wavemode = 0;
168 DSP.dma.chunk = new Bit8u[BX_SOUND_OUTPUT_WAVEPACKETSIZE];
169 DSP.dma.chunkindex = 0;
170 DSP.outputinit = 0;
171 MPU.outputinit = 0;
173 if (DSP.dma.chunk == NULL)
175 writelog(WAVELOG(2), "Couldn't allocate wave buffer - wave output disabled.");
176 BX_SB16_THIS wavemode = 0;
179 BX_INFO(("midi=%d,%s wave=%d,%s log=%d,%s dmatimer=%d",
180 BX_SB16_THIS midimode, MIGHT_BE_NULL(SIM->get_param_string("midifile", base)->getptr()),
181 BX_SB16_THIS wavemode, MIGHT_BE_NULL(SIM->get_param_string("wavefile", base)->getptr()),
182 BX_SB16_THIS loglevel, MIGHT_BE_NULL(SIM->get_param_string("logfile", base)->getptr()),
183 BX_SB16_THIS dmatimer));
185 // allocate the FIFO buffers - except for the MPUMIDICMD buffer
186 // these sizes are generous, 16 or 8 would probably be sufficient
187 MPU.datain.init((int) 64); // the input
188 MPU.dataout.init((int) 64); // and output
189 MPU.cmd.init((int) 64); // and command buffers
190 MPU.midicmd.init((int) 256); // and the midi command buffer (note- large SYSEX'es have to fit!)
191 DSP.datain.init((int) 64); // the DSP input
192 DSP.dataout.init((int) 64); // and output buffers
193 EMUL.datain.init((int) 64); // the emulator ports
194 EMUL.dataout.init((int) 64); // for changing emulator settings
196 // reset all parts of the hardware by
197 // triggering their reset functions
199 // reset the Emulator port
200 emul_write(0x00);
202 // reset the MPU401
203 mpu_command(0xff);
204 MPU.last_delta_time = 0xffffffff;
206 // reset the DSP
207 DSP.dma.highspeed = 0;
208 DSP.dma.mode = 0;
209 DSP.irqpending = 0;
210 DSP.midiuartmode = 0;
211 DSP.resetport = 1; // so that one call to dsp_reset is sufficient
212 dsp_reset(0); // (reset is 1 to 0 transition)
213 DSP.testreg = 0;
215 BX_SB16_IRQ = -1; // will be initialized later by the mixer reset
217 for (i=0; i<BX_SB16_MIX_REG; i++)
218 MIXER.reg[i] = 0xff;
219 MIXER.reg[0x00] = 0; // reset register
220 MIXER.reg[0x80] = 2; // IRQ 5
221 MIXER.reg[0x81] = 2; // 8-bit DMA 1, no 16-bit DMA
222 MIXER.reg[0x82] = 2 << 5; // no IRQ pending
223 MIXER.reg[0xfd] = 16; // ???
224 MIXER.reg[0xfe] = 6; // ???
225 set_irq_dma(); // set the IRQ and DMA
227 // call the mixer reset
228 mixer_writeregister(0x00);
229 mixer_writedata(0x00);
231 // reset the FM emulation
232 OPL.mode = fminit;
233 OPL.timer_running = 0;
234 opl_entermode(single);
236 // csp
237 memset(&BX_SB16_THIS csp_reg[0], 0, sizeof(BX_SB16_THIS csp_reg));
238 BX_SB16_THIS csp_reg[5] = 0x01;
239 BX_SB16_THIS csp_reg[9] = 0xf8;
241 // Allocate the IO addresses, 2x0..2xf, 3x0..3x4 and 388..38b
242 for (addr=BX_SB16_IO; addr<BX_SB16_IO+BX_SB16_IOLEN; addr++) {
243 DEV_register_ioread_handler(this, &read_handler, addr, "SB16", 1);
244 DEV_register_iowrite_handler(this, &write_handler, addr, "SB16", 1);
246 for (addr=BX_SB16_IOMPU; addr<BX_SB16_IOMPU+BX_SB16_IOMPULEN; addr++) {
247 DEV_register_ioread_handler(this, &read_handler, addr, "SB16", 1);
248 DEV_register_iowrite_handler(this, &write_handler, addr, "SB16", 1);
250 for (addr=BX_SB16_IOADLIB; addr<BX_SB16_IOADLIB+BX_SB16_IOADLIBLEN; addr++) {
251 DEV_register_ioread_handler(this, read_handler, addr, "SB16", 1);
252 DEV_register_iowrite_handler(this, write_handler, addr, "SB16", 1);
255 writelog(BOTHLOG(1),
256 "SB16 emulation initialised, IRQ %d, IO %03x/%03x/%03x, DMA %d/%d",
257 BX_SB16_IRQ, BX_SB16_IO, BX_SB16_IOMPU, BX_SB16_IOADLIB,
258 BX_SB16_DMAL, BX_SB16_DMAH);
260 // initialize the timers
261 if (MPU.timer_handle == BX_NULL_TIMER_HANDLE) {
262 MPU.timer_handle = bx_pc_system.register_timer
263 (BX_SB16_THISP, mpu_timer, 500000 / 384, 1, 1, "sb16.mpu");
264 // midi timer: active, continuous, 500000 / 384 seconds (384 = delta time, 500000 = sec per beat at 120 bpm. Don't change this!)
267 if (DSP.timer_handle == BX_NULL_TIMER_HANDLE) {
268 DSP.timer_handle = bx_pc_system.register_timer
269 (BX_SB16_THISP, dsp_dmatimer, 1, 1, 0, "sb16.dsp");
270 // dma timer: inactive, continuous, frequency variable
273 if (OPL.timer_handle == BX_NULL_TIMER_HANDLE) {
274 OPL.timer_handle = bx_pc_system.register_timer
275 (BX_SB16_THISP, opl_timer, 80, 1, 0, "sb16.opl");
276 // opl timer: inactive, continuous, frequency 80us
279 writelog(MIDILOG(4), "Timers initialized, midi %d, dma %d, opl %d",
280 MPU.timer_handle, DSP.timer_handle, OPL.timer_handle);
281 MPU.current_timer = 0;
283 // init runtime parameters
284 SIM->get_param_num(BXPN_SB16_DMATIMER)->set_handler(sb16_param_handler);
285 SIM->get_param_num(BXPN_SB16_DMATIMER)->set_runtime_param(1);
286 SIM->get_param_num(BXPN_SB16_LOGLEVEL)->set_handler(sb16_param_handler);
287 SIM->get_param_num(BXPN_SB16_LOGLEVEL)->set_runtime_param(1);
290 void bx_sb16_c::reset(unsigned type)
294 void bx_sb16_c::register_state(void)
296 unsigned i, j;
297 char name[8];
298 bx_list_c *chip, *ins_map, *item, *patch;
300 bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "sb16", "SB16 State", 8);
301 bx_list_c *mpu = new bx_list_c(list, "mpu", 8);
302 new bx_shadow_bool_c(mpu, "uartmode", &MPU.uartmode);
303 new bx_shadow_bool_c(mpu, "irqpending", &MPU.irqpending);
304 new bx_shadow_bool_c(mpu, "forceuartmode", &MPU.forceuartmode);
305 new bx_shadow_bool_c(mpu, "singlecommand", &MPU.singlecommand);
306 new bx_shadow_bool_c(mpu, "outputinit", &MPU.outputinit);
307 new bx_shadow_num_c(mpu, "current_timer", &MPU.current_timer);
308 new bx_shadow_num_c(mpu, "last_delta_time", &MPU.last_delta_time);
309 bx_list_c *patchtbl = new bx_list_c(mpu, "patchtable", BX_SB16_PATCHTABLESIZE);
310 for (i=0; i<BX_SB16_PATCHTABLESIZE; i++) {
311 sprintf(name, "0x%02x", i);
312 patch = new bx_list_c(patchtbl, name, 3);
313 new bx_shadow_num_c(patch, "banklsb", &MPU.banklsb[i]);
314 new bx_shadow_num_c(patch, "bankmsb", &MPU.bankmsb[i]);
315 new bx_shadow_num_c(patch, "program", &MPU.program[i]);
317 bx_list_c *dsp = new bx_list_c(list, "dsp", 8);
318 new bx_shadow_num_c(dsp, "resetport", &DSP.resetport, BASE_HEX);
319 new bx_shadow_num_c(dsp, "speaker", &DSP.speaker, BASE_HEX);
320 new bx_shadow_num_c(dsp, "prostereo", &DSP.prostereo, BASE_HEX);
321 new bx_shadow_bool_c(dsp, "irqpending", &DSP.irqpending);
322 new bx_shadow_bool_c(dsp, "midiuartmode", &DSP.midiuartmode);
323 new bx_shadow_num_c(dsp, "testreg", &DSP.testreg, BASE_HEX);
324 bx_list_c *dma = new bx_list_c(dsp, "dma", 16);
325 new bx_shadow_num_c(dma, "mode", &DSP.dma.mode);
326 new bx_shadow_num_c(dma, "bits", &DSP.dma.bits);
327 new bx_shadow_num_c(dma, "bps", &DSP.dma.bps);
328 new bx_shadow_num_c(dma, "format", &DSP.dma.format);
329 new bx_shadow_num_c(dma, "timer", &DSP.dma.timer);
330 new bx_shadow_bool_c(dma, "fifo", &DSP.dma.fifo);
331 new bx_shadow_bool_c(dma, "output", &DSP.dma.output);
332 new bx_shadow_bool_c(dma, "stereo", &DSP.dma.stereo);
333 new bx_shadow_bool_c(dma, "issigned", &DSP.dma.issigned);
334 new bx_shadow_bool_c(dma, "highspeed", &DSP.dma.highspeed);
335 new bx_shadow_num_c(dma, "count", &DSP.dma.count);
336 new bx_shadow_num_c(dma, "chunkindex", &DSP.dma.chunkindex);
337 new bx_shadow_num_c(dma, "chunkcount", &DSP.dma.chunkcount);
338 new bx_shadow_num_c(dma, "timeconstant", &DSP.dma.timeconstant);
339 new bx_shadow_num_c(dma, "blocklength", &DSP.dma.blocklength);
340 new bx_shadow_num_c(dma, "samplerate", &DSP.dma.samplerate);
341 new bx_shadow_bool_c(dsp, "outputinit", &DSP.outputinit);
342 new bx_shadow_data_c(list, "chunk", DSP.dma.chunk, BX_SOUND_OUTPUT_WAVEPACKETSIZE);
343 bx_list_c *csp = new bx_list_c(list, "csp_reg", 256);
344 for (i=0; i<256; i++) {
345 sprintf(name, "0x%02x", i);
346 new bx_shadow_num_c(csp, name, &BX_SB16_THIS csp_reg[i], BASE_HEX);
348 bx_list_c *opl = new bx_list_c(list, "opl", 8);
349 new bx_shadow_num_c(opl, "mode", (Bit8u*)&OPL.mode);
350 new bx_shadow_num_c(opl, "timer_running", &OPL.timer_running);
351 new bx_shadow_num_c(opl, "midichannels", &OPL.midichannels);
352 new bx_shadow_num_c(opl, "drumchannel", &OPL.drumchannel);
353 for (i=0; i<2; i++) {
354 sprintf(name, "chip%d", i+1);
355 chip = new bx_list_c(opl, name, 11);
356 new bx_shadow_num_c(chip, "index", &OPL.index[i]);
357 new bx_shadow_num_c(chip, "wsenable", &OPL.wsenable[i]);
358 new bx_shadow_num_c(chip, "timer1", &OPL.timer[i*2]);
359 new bx_shadow_num_c(chip, "timer2", &OPL.timer[i*2+1]);
360 new bx_shadow_num_c(chip, "timerinit1", &OPL.timerinit[i*2]);
361 new bx_shadow_num_c(chip, "timerinit2", &OPL.timerinit[i*2+1]);
362 new bx_shadow_num_c(chip, "tmask", &OPL.tmask[i]);
363 new bx_shadow_num_c(chip, "tflag", &OPL.tflag[i]);
364 new bx_shadow_num_c(chip, "percmode", &OPL.percmode[i]);
365 new bx_shadow_num_c(chip, "cyhhnote", &OPL.cyhhnote[i]);
366 new bx_shadow_num_c(chip, "cyhhon", &OPL.cyhhon[i]);
368 bx_list_c *oper = new bx_list_c(opl, "oper", BX_SB16_FM_NOP);
369 for (i=0; i<BX_SB16_FM_NOP; i++) {
370 sprintf(name, "%d", i);
371 item = new bx_list_c(oper, name, BX_SB16_FM_OPB);
372 for (j=0; j<BX_SB16_FM_OPB; j++) {
373 sprintf(name, "%d", j);
374 new bx_shadow_num_c(item, name, &OPL.oper[i][j]);
377 bx_list_c *chan = new bx_list_c(opl, "chan", BX_SB16_FM_NCH);
378 for (i=0; i<BX_SB16_FM_NCH; i++) {
379 sprintf(name, "%d", i);
380 item = new bx_list_c(chan, name, 19);
381 new bx_shadow_num_c(item, "nop", &OPL.chan[i].nop);
382 new bx_shadow_num_c(item, "ncarr", &OPL.chan[i].ncarr);
383 new bx_shadow_num_c(item, "opnum1", &OPL.chan[i].opnum[0]);
384 new bx_shadow_num_c(item, "opnum2", &OPL.chan[i].opnum[1]);
385 new bx_shadow_num_c(item, "opnum3", &OPL.chan[i].opnum[2]);
386 new bx_shadow_num_c(item, "opnum4", &OPL.chan[i].opnum[3]);
387 new bx_shadow_num_c(item, "freq", &OPL.chan[i].freq);
388 new bx_shadow_num_c(item, "afreq", &OPL.chan[i].afreq);
389 new bx_shadow_num_c(item, "midichan", &OPL.chan[i].midichan);
390 new bx_shadow_bool_c(item, "needprogch", &OPL.chan[i].needprogch);
391 new bx_shadow_num_c(item, "midinote", &OPL.chan[i].midinote);
392 new bx_shadow_bool_c(item, "midion", &OPL.chan[i].midion);
393 new bx_shadow_num_c(item, "midibend", &OPL.chan[i].midibend);
394 new bx_shadow_num_c(item, "outputlevel1", &OPL.chan[i].outputlevel[0]);
395 new bx_shadow_num_c(item, "outputlevel2", &OPL.chan[i].outputlevel[1]);
396 new bx_shadow_num_c(item, "outputlevel3", &OPL.chan[i].outputlevel[2]);
397 new bx_shadow_num_c(item, "outputlevel4", &OPL.chan[i].outputlevel[3]);
398 new bx_shadow_num_c(item, "midivol", &OPL.chan[i].midivol);
400 new bx_shadow_num_c(list, "mixer_regindex", &MIXER.regindex, BASE_HEX);
401 bx_list_c *mixer = new bx_list_c(list, "mixer_reg", BX_SB16_MIX_REG);
402 for (i=0; i<BX_SB16_MIX_REG; i++) {
403 sprintf(name, "0x%02x", i);
404 new bx_shadow_num_c(mixer, name, &MIXER.reg[i], BASE_HEX);
406 bx_list_c *emul = new bx_list_c(list, "emul", 2);
407 new bx_shadow_num_c(emul, "remaps", &EMUL.remaps);
408 bx_list_c *remap = new bx_list_c(emul, "remaplist", 256);
409 for (i=0; i<EMUL.remaps; i++) {
410 sprintf(name, "0x%02x", i);
411 ins_map = new bx_list_c(remap, name, 6);
412 new bx_shadow_num_c(ins_map, "oldbankmsb", &EMUL.remaplist[i].oldbankmsb);
413 new bx_shadow_num_c(ins_map, "oldbanklsb", &EMUL.remaplist[i].oldbanklsb);
414 new bx_shadow_num_c(ins_map, "oldprogch", &EMUL.remaplist[i].oldprogch);
415 new bx_shadow_num_c(ins_map, "newbankmsb", &EMUL.remaplist[i].newbankmsb);
416 new bx_shadow_num_c(ins_map, "newbanklsb", &EMUL.remaplist[i].newbanklsb);
417 new bx_shadow_num_c(ins_map, "newprogch", &EMUL.remaplist[i].newprogch);
421 void bx_sb16_c::after_restore_state(void)
423 set_irq_dma();
426 // the timer functions
427 void bx_sb16_c::mpu_timer (void *this_ptr)
429 ((bx_sb16_c *) this_ptr)->mpu401.current_timer++;
432 void bx_sb16_c::dsp_dmatimer(void *this_ptr)
434 bx_sb16_c *This = (bx_sb16_c *) this_ptr;
436 // raise the DRQ line. It is then lowered by dsp_getsamplebyte()
437 // when the next byte has been received.
438 // However, don't do this if the next byte/word will fill up the
439 // output buffer and the output functions are not ready yet.
441 if ((BX_SB16_THIS wavemode != 1) ||
442 ((This->dsp.dma.chunkindex + 1 < BX_SOUND_OUTPUT_WAVEPACKETSIZE) &&
443 (This->dsp.dma.count > 0)) ||
444 (This->output->waveready() == BX_SOUND_OUTPUT_OK)) {
445 if ((DSP.dma.bits == 8) || (BX_SB16_DMAH == 0)) {
446 DEV_dma_set_drq(BX_SB16_DMAL, 1);
447 } else {
448 DEV_dma_set_drq(BX_SB16_DMAH, 1);
453 void bx_sb16_c::opl_timer (void *this_ptr)
455 ((bx_sb16_c *) this_ptr)->opl_timerevent();
458 // the various IO handlers
460 // The DSP/FM music part
462 // dsp_reset() resets the DSP after the sequence 1/0. Returns
463 // 0xaa on the data port
464 void bx_sb16_c::dsp_reset(Bit32u value)
466 writelog(WAVELOG(4), "DSP Reset port write value %x", value);
468 // just abort high speed mode if it is set
469 if (DSP.dma.highspeed != 0)
471 DSP.dma.highspeed = 0;
472 writelog(WAVELOG(4), "High speed mode aborted");
473 return;
476 if ((DSP.resetport == 1) && (value == 0))
478 // 1-0 sequences to reset port, do one of the following:
479 // if in UART MIDI mode, abort it, don't reset
480 // if in Highspeed mode (not SB16!), abort it, don't reset
481 // otherwise reset
483 if (DSP.midiuartmode != 0)
484 { // abort UART MIDI mode
485 DSP.midiuartmode = 0;
486 writelog(MIDILOG(4), "DSP UART MIDI mode aborted");
487 return;
490 // do the reset
491 writelog(WAVELOG(4), "DSP resetting...");
493 if (DSP.irqpending != 0)
495 DEV_pic_lower_irq(BX_SB16_IRQ);
496 writelog(WAVELOG(4), "DSP reset: IRQ untriggered");
498 if (DSP.dma.mode != 0)
500 writelog(WAVELOG(4), "DSP reset: DMA aborted");
501 DSP.dma.mode = 1; // no auto init anymore
502 dsp_dmadone();
505 DSP.resetport = 0;
506 DSP.speaker = 0;
507 DSP.irqpending = 0;
508 DSP.midiuartmode = 0;
509 DSP.prostereo = 0;
511 DSP.dma.mode = 0;
512 DSP.dma.fifo = 0;
513 DSP.dma.output = 0;
514 DSP.dma.stereo = 0;
515 DSP.dma.issigned = 0;
516 DSP.dma.count = 0;
517 DSP.dma.highspeed = 0;
518 DSP.dma.chunkindex = 0;
520 DSP.dataout.reset(); // clear the buffers
521 DSP.datain.reset();
523 DSP.dataout.put(0xaa); // acknowledge the reset
525 else
526 DSP.resetport = value;
529 // dsp_dataread() reads the data port of the DSP
530 Bit32u bx_sb16_c::dsp_dataread()
532 Bit8u value = 0xff;
534 // if we are in MIDI UART mode, call the mpu401 part instead
535 if (DSP.midiuartmode != 0)
536 value = mpu_dataread();
537 else
539 // default behaviour: if none available, return last byte again
540 // if (DSP.dataout.empty() == 0)
541 DSP.dataout.get(&value);
544 writelog(WAVELOG(4), "DSP Data port read, result = %x", value);
546 return(value);
549 // dsp_datawrite() writes a command or data byte to the data port
550 void bx_sb16_c::dsp_datawrite(Bit32u value)
552 int bytesneeded;
553 Bit8u index = 0, mode = 0, value8 = 0;
554 Bit16u length = 0;
556 writelog(WAVELOG(4), "DSP Data port write, value %x", value);
558 // in high speed mode, any data passed to DSP is a sample
559 if (DSP.dma.highspeed != 0)
561 dsp_getsamplebyte(value);
562 return;
565 // route information to mpu401 part if in MIDI UART mode
566 if (DSP.midiuartmode != 0)
568 mpu_datawrite(value);
569 return;
572 if (DSP.datain.hascommand() == 1) // already a command pending, add to argument list
574 if (DSP.datain.put(value) == 0)
576 writelog(WAVELOG(3), "DSP command buffer overflow for command %02x",
577 DSP.datain.currentcommand());
580 else // no command pending, set one up
582 bytesneeded = 0; // find out how many arguments the command takes
583 switch (value)
584 { // all fallbacks intended!
585 case 0x04:
586 case 0x0f:
587 case 0x10:
588 case 0x40:
589 case 0x38:
590 case 0xe0:
591 case 0xe4:
592 case 0xf9:
593 bytesneeded = 1;
594 break;
595 case 0x05:
596 case 0x0e:
597 case 0x14:
598 case 0x16:
599 case 0x17:
600 case 0x41:
601 case 0x42:
602 case 0x48:
603 case 0x74:
604 case 0x75:
605 case 0x76:
606 case 0x77:
607 case 0x80:
608 bytesneeded = 2;
609 break;
610 // 0xb0 ... 0xbf:
611 case 0xb0:
612 case 0xb1:
613 case 0xb2:
614 case 0xb3:
615 case 0xb4:
616 case 0xb5:
617 case 0xb6:
618 case 0xb7:
619 case 0xb8:
620 case 0xb9:
621 case 0xba:
622 case 0xbb:
623 case 0xbc:
624 case 0xbd:
625 case 0xbe:
626 case 0xbf:
628 // 0xc0 ... 0xcf:
629 case 0xc0:
630 case 0xc1:
631 case 0xc2:
632 case 0xc3:
633 case 0xc4:
634 case 0xc5:
635 case 0xc6:
636 case 0xc7:
637 case 0xc8:
638 case 0xc9:
639 case 0xca:
640 case 0xcb:
641 case 0xcc:
642 case 0xcd:
643 case 0xce:
644 case 0xcf:
645 bytesneeded = 3;
646 break;
648 DSP.datain.newcommand(value, bytesneeded);
651 if (DSP.datain.commanddone() == 1) // command is complete, process it
653 writelog(WAVELOG(4), "DSP command %x with %d arg bytes",
654 DSP.datain.currentcommand(), DSP.datain.bytes());
656 switch (DSP.datain.currentcommand())
658 // DSP commands - comments are the parameters for
659 // this command, and/or the output
661 // ASP commands (Advanced Signal Processor)
662 // undocumented (?), just from looking what an SB16 does
663 case 0x04:
664 DSP.datain.get(&value8);
665 break;
667 case 0x05:
668 DSP.datain.get(&value8);
669 DSP.datain.get(&value8);
670 break;
672 case 0x0e:
673 DSP.datain.get(&index);
674 DSP.datain.get(&value8);
675 BX_SB16_THIS csp_reg[index] = value;
676 break;
678 case 0x0f:
679 DSP.datain.get(&index);
680 DSP.dataout.put(BX_SB16_THIS csp_reg[index]);
681 break;
683 // direct mode DAC
684 case 0x10:
685 // 1: 8bit sample
686 DSP.datain.get(&value8); // sample is ignored
687 break;
689 // uncomp'd, normal DAC DMA
690 case 0x14:
691 // 1,2: lo(length) hi(length)
692 DSP.datain.getw(&length);
693 dsp_dma(0xc0, 0x00, length, 0);
694 break;
696 // 2-bit comp'd, normal DAC DMA, no ref byte
697 case 0x16:
698 // 1,2: lo(length) hi(length)
699 DSP.datain.getw(&length);
700 dsp_dma(0xc0, 0x00, length, 2);
701 break;
703 // 2-bit comp'd, normal DAC DMA, 1 ref byte
704 case 0x17:
705 // 1,2: lo(length) hi(length)
706 DSP.datain.getw(&length);
707 dsp_dma(0xc0, 0x00, length, 2|8);
708 break;
710 // uncomp'd, auto DAC DMA
711 case 0x1c:
712 // none
713 dsp_dma(0xc4, 0x00, DSP.dma.blocklength, 0);
714 break;
716 // 2-bit comp'd, auto DAC DMA, 1 ref byte
717 case 0x1f:
718 // none
719 dsp_dma(0xc4, 0x00, DSP.dma.blocklength, 2|8);
720 break;
722 // direct mode ADC
723 case 0x20:
724 // o1: 8bit sample
725 DSP.dataout.put(0x80); // put a silence, for now.
726 break;
728 // uncomp'd, normal ADC DMA
729 case 0x24:
730 // 1,2: lo(length) hi(length)
731 DSP.datain.getw(&length);
732 dsp_dma(0xc8, 0x00, length, 0);
733 break;
735 // uncomp'd, auto ADC DMA
736 case 0x2c:
737 // none
738 dsp_dma(0xcc, 0x00, DSP.dma.blocklength, 0);
739 break;
741 // ? polling mode MIDI input
742 case 0x30:
743 break;
745 // ? interrupt mode MIDI input
746 case 0x31:
747 break;
749 // 0x34..0x37: UART mode MIDI output
750 case 0x34:
752 // UART mode MIDI input/output
753 case 0x35:
755 // UART polling mode MIDI IO with time stamp
756 case 0x36:
758 // UART interrupt mode MIDI IO with time stamp
759 case 0x37:
760 // Fallbacks intended - all set the midi uart mode
761 DSP.midiuartmode = 1;
762 break;
764 // MIDI output
765 case 0x38:
766 DSP.datain.get(&value8);
767 // route to mpu401 part
768 mpu_datawrite(value8);
769 break;
771 // set time constant
772 case 0x40:
773 // 1: timeconstant
774 DSP.datain.get(&value8);
775 DSP.dma.timeconstant = value8 << 8;
776 DSP.dma.samplerate = (Bit32u) 256000000L / ((Bit32u) 65536L - (Bit32u) DSP.dma.timeconstant);
777 break;
779 // set samplerate for input
780 case 0x41:
781 // (fallback intended)
783 // set samplerate for output
784 case 0x42:
785 // 1,2: hi(frq) lo(frq)
786 DSP.datain.getw1(&(DSP.dma.samplerate));
787 DSP.dma.timeconstant = 65536 - (Bit32u) 256000000 / (Bit32u) DSP.dma.samplerate;
788 break;
790 // set block length
791 case 0x48:
792 // 1,2: lo(blk len) hi(blk len)
793 DSP.datain.getw(&(DSP.dma.blocklength));
794 break;
796 // 4-bit comp'd, normal DAC DMA, no ref byte
797 case 0x74:
798 // 1,2: lo(length) hi(length)
799 DSP.datain.getw(&length);
800 dsp_dma(0xc0, 0x00, length, 4);
801 break;
803 // 4-bit comp'd, normal DAC DMA, 1 ref byte
804 case 0x75:
805 // 1,2: lo(length) hi(length)
806 DSP.datain.getw(&length);
807 dsp_dma(0xc0, 0x00, length, 4|8);
808 break;
810 // 3-bit comp'd, normal DAC DMA, no ref byte
811 case 0x76:
812 // 1,2: lo(length) hi(length)
813 DSP.datain.getw(&length);
814 dsp_dma(0xc0, 0x00, length, 3);
815 break;
817 // 3-bit comp'd, normal DAC DMA, 1 ref byte
818 case 0x77:
819 // 1,2: lo(length) hi(length)
820 DSP.datain.getw(&length);
821 dsp_dma(0xc0, 0x00, length, 3|8);
822 break;
824 // 4-bit comp'd, auto DAC DMA, 1 ref byte
825 case 0x7d:
826 // none
827 dsp_dma(0xc4, 0x00, DSP.dma.blocklength, 4|8);
828 break;
830 // 3-bit comp'd, auto DAC DMA, 1 ref byte
831 case 0x7f:
832 // none
833 dsp_dma(0xc4, 0x00, DSP.dma.blocklength, 3|8);
834 break;
836 // silence period
837 case 0x80:
838 // 1,2: lo(silence) hi(silence) (len in samples)
839 DSP.datain.getw(&length);
840 // only handled for VOC output so far
841 if (BX_SB16_THIS wavemode == 2)
843 Bit8u temparray[3] = { length & 0xff, length >> 8, DSP.dma.timeconstant >> 8 };
844 writevocblock(3, 3, temparray, 0, NULL);
846 break;
848 // 8-bit auto DAC DMA, highspeed
849 case 0x90:
850 //none
851 dsp_dma(0xc4, 0x00, DSP.dma.blocklength, 16);
852 break;
854 // 8-bit normal DAC DMA, highspeed
855 case 0x91:
856 //none
857 dsp_dma(0xc0, 0x00, DSP.dma.blocklength, 16);
858 break;
860 // 8-bit auto ADC DMA, highspeed
861 case 0x98:
862 //none
863 dsp_dma(0xcc, 0x00, DSP.dma.blocklength, 16);
864 break;
866 case 0x99: // 8-bit normal DMA
867 //none
868 dsp_dma(0xc8, 0x00, DSP.dma.blocklength, 16);
869 break;
871 // switch to mono for SBPro DAC/ADC
872 case 0xa0:
873 // none
874 DSP.prostereo = 1;
875 break;
877 // switch to stereo for SBPro DAC/ADC
878 case 0xa8:
879 //// none
880 DSP.prostereo = 2;
881 break;
883 // 0xb0 ... 0xbf:
884 // 16 bit DAC/ADC DMA, general commands
885 // fallback intended
886 case 0xb0:
887 case 0xb1:
888 case 0xb2:
889 case 0xb3:
890 case 0xb4:
891 case 0xb5:
892 case 0xb6:
893 case 0xb7:
894 case 0xb8:
895 case 0xb9:
896 case 0xba:
897 case 0xbb:
898 case 0xbc:
899 case 0xbd:
900 case 0xbe:
901 case 0xbf:
903 // 0xc0 ... 0xcf:
904 // 8 bit DAC/ADC DMA, general commands
905 case 0xc0:
906 case 0xc1:
907 case 0xc2:
908 case 0xc3:
909 case 0xc4:
910 case 0xc5:
911 case 0xc6:
912 case 0xc7:
913 case 0xc8:
914 case 0xc9:
915 case 0xca:
916 case 0xcb:
917 case 0xcc:
918 case 0xcd:
919 case 0xce:
920 case 0xcf:
921 DSP.datain.get(&mode);
922 DSP.datain.getw(&length);
923 dsp_dma(DSP.datain.currentcommand(), mode, length, 0);
924 break;
926 // pause 8 bit DMA transfer
927 case 0xd0:
928 // none
929 if (DSP.dma.mode != 0)
930 dsp_disabledma();
931 break;
933 // speaker on
934 case 0xd1:
935 // none
936 DSP.speaker = 1;
937 break;
939 // speaker off
940 case 0xd3:
941 // none
942 DSP.speaker = 0;
943 break;
945 // continue 8 bit DMA, see 0xd0
946 case 0xd4:
947 // none
948 if (DSP.dma.mode != 0)
949 dsp_enabledma();
950 break;
952 // pause 16 bit DMA
953 case 0xd5:
954 // none
955 if (DSP.dma.mode != 0)
956 dsp_disabledma();
957 break;
959 // continue 16 bit DMA, see 0xd5
960 case 0xd6:
961 // none
962 if (DSP.dma.mode != 0)
963 dsp_enabledma();
964 break;
966 // read speaker on/off (out ff=on, 00=off)
967 case 0xd8:
968 // none, o1: speaker; ff/00
969 DSP.dataout.put((DSP.speaker == 1)?0xff:0x00);
970 break;
972 // stop 16 bit auto DMA
973 case 0xd9:
974 // none
975 if (DSP.dma.mode != 0)
977 DSP.dma.mode = 1; // no auto init anymore
978 dsp_dmadone();
980 break;
982 // stop 8 bit auto DMA
983 case 0xda:
984 // none
985 if (DSP.dma.mode != 0)
987 DSP.dma.mode = 1; // no auto init anymore
988 dsp_dmadone();
990 break;
992 // DSP identification
993 case 0xe0:
994 DSP.datain.get(&value8);
995 DSP.dataout.put(~value8);
996 break;
998 // get version, out 2 bytes (major, minor)
999 case 0xe1:
1000 // none, o1/2: version major.minor
1001 DSP.dataout.put(4);
1002 if (DSP.dataout.put(5) == 0)
1004 writelog(WAVELOG(3), "DSP version couldn't be written - buffer overflow");
1006 break;
1008 case 0xe3:
1009 // none, output: Copyright string
1010 // the Windows driver needs the exact text, otherwise it
1011 // won't load. Same for diagnose.exe
1012 DSP.dataout.puts("COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.");
1013 DSP.dataout.put(0); // need extra string end
1014 break;
1016 // write test register
1017 case 0xe4:
1018 DSP.datain.get(&DSP.testreg);
1019 break;
1021 // read test register
1022 case 0xe8:
1023 DSP.dataout.put(DSP.testreg);
1024 break;
1026 // Trigger 8-bit IRQ
1027 case 0xf2:
1028 DSP.dataout.put(0xaa);
1029 DSP.irqpending = 1;
1030 MIXER.reg[0x82] |= 1; // reg 82 shows the kind of IRQ
1031 DEV_pic_raise_irq(BX_SB16_IRQ);
1032 break;
1034 // ??? - Win98 needs this
1035 case 0xf9:
1036 DSP.datain.get(&value8);
1037 switch (value8) {
1038 case 0x0e:
1039 DSP.dataout.put(0xff);
1040 break;
1041 case 0x0f:
1042 DSP.dataout.put(0x07);
1043 break;
1044 case 0x37:
1045 DSP.dataout.put(0x38);
1046 break;
1047 default:
1048 DSP.dataout.put(0x00);
1050 break;
1052 // unknown command
1053 default:
1054 writelog(WAVELOG(3), "unknown DSP command %x, ignored",
1055 DSP.datain.currentcommand());
1056 break;
1058 DSP.datain.clearcommand();
1059 DSP.datain.flush();
1063 // dsp_dma() initiates all kinds of dma transfers
1064 void bx_sb16_c::dsp_dma(Bit8u command, Bit8u mode, Bit16u length, Bit8u comp)
1066 int ret;
1067 bx_list_c *base;
1069 // command: 8bit, 16bit, in/out, single/auto, fifo
1070 // mode: mono/stereo, signed/unsigned
1071 // (for info on command and mode see sound blaster programmer's manual,
1072 // cmds bx and cx)
1073 // length: number of samples - not number of bytes
1074 // comp: bit-coded are: type of compression; ref-byte; highspeed
1075 // D0..D2: 0=none, 2,3,4 bits ADPCM
1076 // D3: ref-byte
1077 // D6: highspeed
1079 writelog(WAVELOG(4), "DMA initialized. Cmd %02x, mode %02x, length %d, comp %d",
1080 command, mode, length, comp);
1082 if ((command >> 4) == 0xb) // 0xb? = 16 bit DMA
1084 DSP.dma.bits = 16;
1085 DSP.dma.bps = 2;
1087 else // 0xc? = 8 bit DMA
1089 DSP.dma.bits = 8;
1090 DSP.dma.bps = 1;
1093 // Prevent division by zero in some instances
1094 if (DSP.dma.samplerate == 0)
1095 DSP.dma.samplerate= 10752;
1096 command &= 0x0f;
1097 DSP.dma.output = 1 - (command >> 3); // 1=output, 0=input
1098 DSP.dma.mode = 1 + ((command >> 2) & 1); // 0=none, 1=normal, 2=auto
1099 DSP.dma.fifo = (command >> 1) & 1; // ? not sure what this is
1101 DSP.dma.stereo = (mode >> 5) & 1;
1103 if (DSP.dma.stereo != 0)
1104 DSP.dma.bps *= 2;
1106 DSP.dma.blocklength = length;
1107 DSP.dma.issigned = (mode >> 4) & 1;
1108 DSP.dma.highspeed = (comp >> 4) & 1;
1110 DSP.dma.chunkindex = 0;
1111 DSP.dma.chunkcount = 0;
1113 Bit32u sampledatarate = (Bit32u) DSP.dma.samplerate * (Bit32u) DSP.dma.bps;
1114 if ((DSP.dma.bits == 16) && (BX_SB16_DMAH != 0)) {
1115 DSP.dma.count = (DSP.dma.blocklength + 1) * (DSP.dma.bps / 2) - 1;
1116 DSP.dma.timer = BX_SB16_THIS dmatimer / (sampledatarate / 2);
1117 } else {
1118 DSP.dma.count = (DSP.dma.blocklength + 1) * DSP.dma.bps - 1;
1119 DSP.dma.timer = BX_SB16_THIS dmatimer / sampledatarate;
1122 writelog(WAVELOG(5), "DMA is %db, %dHz, %s, %s, mode %d, %s, %s, %d bps, %d usec/DMA",
1123 DSP.dma.bits, DSP.dma.samplerate, (DSP.dma.stereo != 0)?"stereo":"mono",
1124 (DSP.dma.output == 1)?"output":"input", DSP.dma.mode,
1125 (DSP.dma.issigned == 1)?"signed":"unsigned",
1126 (DSP.dma.highspeed == 1)?"highspeed":"normal speed",
1127 sampledatarate, DSP.dma.timer);
1129 DSP.dma.format = DSP.dma.issigned | ((comp & 7) << 1) | ((comp & 8) << 4);
1131 // write the output to the device/file
1132 if (DSP.dma.output == 1) {
1133 if (BX_SB16_THIS wavemode == 1) {
1134 if (DSP.outputinit == 0) {
1135 ret = BX_SB16_OUTPUT->openwaveoutput(SIM->get_param_string(BXPN_SB16_WAVEFILE)->getptr());
1136 if (ret != BX_SOUND_OUTPUT_OK) {
1137 BX_SB16_THIS wavemode = 0;
1138 writelog(WAVELOG(2), "Error: Could not open wave output device.");
1139 } else {
1140 DSP.outputinit = 1;
1141 ret = BX_SB16_OUTPUT->startwaveplayback(DSP.dma.samplerate, DSP.dma.bits, DSP.dma.stereo, DSP.dma.format);
1142 if (ret != BX_SOUND_OUTPUT_OK) {
1143 BX_SB16_THIS wavemode = 0;
1144 writelog(WAVELOG(2), "Error: Could not start wave playback.");
1148 } else if ((BX_SB16_THIS wavemode == 2) ||
1149 (BX_SB16_THIS wavemode == 3)) {
1150 base = (bx_list_c*) SIM->get_param(BXPN_SB16);
1151 WAVEDATA = fopen(SIM->get_param_string("wavefile", base)->getptr(),"wb");
1152 if (WAVEDATA == NULL) {
1153 writelog (WAVELOG(2), "Error opening file %s. Wavemode disabled.",
1154 SIM->get_param_string("wavefile", base)->getptr());
1155 BX_SB16_THIS wavemode = 0;
1156 } else if (BX_SB16_THIS wavemode == 2) {
1157 initvocfile();
1162 dsp_enabledma();
1166 // dsp_enabledma(): Start the DMA timer and thus the transfer
1168 void bx_sb16_c::dsp_enabledma()
1170 bx_pc_system.activate_timer(DSP.timer_handle, DSP.dma.timer, 1);
1173 // dsp_disabledma(): Stop the DMA timer and thus the transfer, but don't abort it
1174 void bx_sb16_c::dsp_disabledma()
1176 bx_pc_system.deactivate_timer(DSP.timer_handle);
1179 // dsp_bufferstatus() checks if the DSP is ready for data/commands
1180 Bit32u bx_sb16_c::dsp_bufferstatus()
1182 Bit32u result = 0x7f;
1184 // MSB set -> not ready for commands
1185 if (DSP.datain.full() == 1) result |= 0x80;
1187 writelog(WAVELOG(4), "DSP Buffer status read, result %x", result);
1189 return(result);
1192 // dsp_status() checks if the DSP is ready to send data
1193 Bit32u bx_sb16_c::dsp_status()
1195 Bit32u result = 0x7f;
1197 // read might be to acknowledge IRQ
1198 if (DSP.irqpending != 0)
1200 MIXER.reg[0x82] &= (~0x01);
1201 writelog(WAVELOG(4), "8-bit DMA or SBMIDI IRQ acknowledged");
1202 if ((MIXER.reg[0x82] & 0x07) == 0) {
1203 DSP.irqpending = 0;
1204 DEV_pic_lower_irq(BX_SB16_IRQ);
1208 // if buffer is not empty, there is data to be read
1209 if (DSP.dataout.empty() == 0) result |= 0x80;
1211 writelog(WAVELOG(4), "DSP output status read, result %x", result);
1213 return(result);
1216 // dsp_irq16ack() notifies that the 16bit DMA IRQ has been acknowledged
1217 Bit32u bx_sb16_c::dsp_irq16ack()
1219 Bit32u result = 0xff;
1221 if (DSP.irqpending != 0)
1223 MIXER.reg[0x82] &= (~0x02);
1224 if ((MIXER.reg[0x82] & 0x07) == 0) {
1225 DSP.irqpending = 0;
1226 DEV_pic_lower_irq(BX_SB16_IRQ);
1228 writelog(WAVELOG(4), "16-bit DMA IRQ acknowledged");
1230 else
1231 writelog(WAVELOG(3), "16-bit DMA IRQ acknowledged but not active!");
1233 return result;
1237 // the DMA handlers
1239 // highlevel input and output handlers - rerouting to/from file,device
1241 // get a wave packet from the input device (not supported yet)
1242 void bx_sb16_c::dsp_getwavepacket()
1244 writelog(WAVELOG(3), "DMA reads not supported. Returning silence.");
1246 // fill the buffer with silence. Watch for 16bit transfer and signed/unsigned
1248 // these are the two different bytes in 16bit transfer (both the same for 8bit)
1249 Bit8u byteA, byteB;
1251 byteA = 0x00; // compatible with all signed transfers
1252 byteB = 0x00;
1254 if (DSP.dma.issigned == 0)
1255 byteB = 0x80;
1257 if (DSP.dma.bits == 8)
1258 byteA = byteB;
1260 for (int i = 0; i < BX_SOUND_OUTPUT_WAVEPACKETSIZE; i++)
1261 DSP.dma.chunk[i] = ((i & 1) == 0) ? byteA : byteB;
1263 DSP.dma.chunkcount = BX_SOUND_OUTPUT_WAVEPACKETSIZE;
1264 DSP.dma.chunkindex = 0;
1267 // write a wave packet to the output device
1268 void bx_sb16_c::dsp_sendwavepacket()
1270 switch (BX_SB16_THIS wavemode)
1272 case 1:
1273 BX_SB16_OUTPUT->sendwavepacket(DSP.dma.chunkindex, DSP.dma.chunk);
1274 break;
1275 case 3:
1276 fwrite(DSP.dma.chunk, 1, DSP.dma.chunkindex, WAVEDATA);
1277 break;
1278 case 2:
1279 Bit8u temparray[12] =
1280 { DSP.dma.samplerate & 0xff, DSP.dma.samplerate >> 8, 0, 0,
1281 DSP.dma.bits, DSP.dma.stereo + 1, 0, 0, 0, 0, 0, 0 };
1282 switch ((DSP.dma.format >> 1) & 7)
1284 case 2:
1285 temparray[7] = 3;
1286 break;
1287 case 3:
1288 temparray[7] = 2;
1289 break;
1290 case 4:
1291 temparray[7] = 1;
1292 break;
1294 if (DSP.dma.bits == 16)
1295 temparray[7] = 4;
1297 writevocblock(9, 12, temparray, DSP.dma.chunkindex, DSP.dma.chunk);
1298 break;
1301 DSP.dma.chunkindex = 0;
1304 // put a sample byte into the output buffer
1305 void bx_sb16_c::dsp_getsamplebyte(Bit8u value)
1307 if (DSP.dma.chunkindex < BX_SOUND_OUTPUT_WAVEPACKETSIZE)
1308 DSP.dma.chunk[DSP.dma.chunkindex++] = value;
1310 if (DSP.dma.chunkindex >= BX_SOUND_OUTPUT_WAVEPACKETSIZE)
1311 dsp_sendwavepacket();
1314 // read a sample byte from the input buffer
1315 Bit8u bx_sb16_c::dsp_putsamplebyte()
1317 if (DSP.dma.chunkindex >= DSP.dma.chunkcount)
1318 dsp_getwavepacket();
1320 return DSP.dma.chunk[DSP.dma.chunkindex++];
1323 // called when the last byte of a DMA transfer has been received/sent
1324 void bx_sb16_c::dsp_dmadone()
1326 writelog(WAVELOG(4), "DMA transfer done, triggering IRQ");
1328 if ((DSP.dma.output == 1) && (DSP.dma.mode != 2)) {
1329 dsp_sendwavepacket(); // flush the output
1331 if (BX_SB16_THIS wavemode == 1) {
1332 BX_SB16_OUTPUT->stopwaveplayback();
1333 } else if (BX_SB16_THIS wavemode != 0) {
1334 fflush(WAVEDATA);
1338 // generate the appropriate IRQ
1339 if (DSP.dma.bits == 8)
1340 MIXER.reg[0x82] |= 1;
1341 else
1342 MIXER.reg[0x82] |= 2;
1344 DEV_pic_raise_irq(BX_SB16_IRQ);
1345 DSP.irqpending = 1;
1347 // if auto-DMA, reinitialize
1348 if (DSP.dma.mode == 2)
1350 if ((DSP.dma.bits == 16) && (BX_SB16_DMAH != 0)) {
1351 DSP.dma.count = (DSP.dma.blocklength + 1) * (DSP.dma.bps / 2) - 1;
1352 } else {
1353 DSP.dma.count = (DSP.dma.blocklength + 1) * DSP.dma.bps - 1;
1355 writelog(WAVELOG(4), "auto-DMA reinitializing to length %d", DSP.dma.count);
1357 else
1359 DSP.dma.mode = 0;
1360 dsp_disabledma();
1364 // now the actual transfer routines, called by the DMA controller
1365 // note that read = from application to soundcard (output),
1366 // and write = from soundcard to application (input)
1367 void bx_sb16_c::dma_read8(Bit8u *data_byte)
1369 DEV_dma_set_drq(BX_SB16_DMAL, 0); // the timer will raise it again
1371 if (DSP.dma.count % 100 == 0) // otherwise it's just too many lines of log
1372 writelog(WAVELOG(5), "Received 8-bit DMA %2x, %d remaining ",
1373 *data_byte, DSP.dma.count);
1374 DSP.dma.count--;
1376 dsp_getsamplebyte(*data_byte);
1378 if (DSP.dma.count == 0xffff) // last byte received
1379 dsp_dmadone();
1382 void bx_sb16_c::dma_write8(Bit8u *data_byte)
1384 DEV_dma_set_drq(BX_SB16_DMAL, 0); // the timer will raise it again
1386 DSP.dma.count--;
1388 *data_byte = dsp_putsamplebyte();
1390 if (DSP.dma.count % 100 == 0) // otherwise it's just too many lines of log
1391 writelog(WAVELOG(5), "Sent 8-bit DMA %2x, %d remaining ",
1392 *data_byte, DSP.dma.count);
1394 if (DSP.dma.count == 0xffff) // last byte sent
1395 dsp_dmadone();
1398 void bx_sb16_c::dma_read16(Bit16u *data_word)
1400 DEV_dma_set_drq(BX_SB16_DMAH, 0); // the timer will raise it again
1402 if (DSP.dma.count % 100 == 0) // otherwise it's just too many lines of log
1403 writelog(WAVELOG(5), "Received 16-bit DMA %04x, %d remaining ",
1404 *data_word, DSP.dma.count);
1406 DSP.dma.count--;
1408 dsp_getsamplebyte(*data_word & 0xff);
1409 dsp_getsamplebyte(*data_word >> 8);
1411 if (DSP.dma.count == 0xffff) // last word received
1412 dsp_dmadone();
1415 void bx_sb16_c::dma_write16(Bit16u *data_word)
1417 Bit8u byte1, byte2;
1419 DEV_dma_set_drq(BX_SB16_DMAH, 0); // the timer will raise it again
1421 DSP.dma.count--;
1423 byte1 = dsp_putsamplebyte();
1424 byte2 = dsp_putsamplebyte();
1426 // all input is in little endian
1427 *data_word = byte1 | (byte2 << 8);
1429 if (DSP.dma.count % 100 == 0) // otherwise it's just too many lines of log
1430 writelog(WAVELOG(5), "Sent 16-bit DMA %4x, %d remaining ",
1431 *data_word, DSP.dma.count);
1433 if (DSP.dma.count == 0xffff) // last word sent
1434 dsp_dmadone();
1437 // the mixer, supported type is CT1745 (as in an SB16)
1438 void bx_sb16_c::mixer_writedata(Bit32u value)
1440 int i;
1442 // do some action depending on what register was written
1443 switch (MIXER.regindex)
1445 case 0: // initialize mixer
1446 writelog(BOTHLOG(4), "Initializing mixer...");
1447 MIXER.reg[0x04] = 0xcc;
1448 MIXER.reg[0x0a] = 0x00;
1449 MIXER.reg[0x22] = 0xcc;
1450 MIXER.reg[0x26] = 0xcc;
1451 MIXER.reg[0x28] = 0x00;
1452 MIXER.reg[0x2e] = 0x00;
1453 MIXER.reg[0x3c] = 0x1f;
1454 MIXER.reg[0x3d] = 0x15;
1455 MIXER.reg[0x3e] = 0x0b;
1456 for (i=0x30; i<=0x35; i++)
1457 MIXER.reg[i] = 0xc0;
1458 for (i=0x36; i<=0x3b; i++)
1459 MIXER.reg[i] = 0x00;
1460 for (i=0x3f; i<=0x43; i++)
1461 MIXER.reg[i] = 0x00;
1462 for (i=0x44; i<=0x47; i++)
1463 MIXER.reg[i] = 0x80;
1465 MIXER.regindex = 0; // next mixer register read is register 0
1466 return;
1468 case 0x04: // DAC level
1469 MIXER.reg[0x32] = (value & 0xf0) | 0x08;
1470 MIXER.reg[0x33] = ((value & 0x0f) << 4) | 0x08;
1471 break;
1473 case 0x0a: // microphone level
1474 MIXER.reg[0x3a] = (value << 5) | 0x18;
1475 break;
1477 case 0x22: // master volume
1478 MIXER.reg[0x30] = (value & 0xf0) | 0x08;
1479 MIXER.reg[0x31] = ((value & 0x0f) << 4) | 0x08;
1480 break;
1482 case 0x26: // FM level
1483 MIXER.reg[0x34] = (value & 0xf0) | 0x08;
1484 MIXER.reg[0x35] = ((value & 0x0f) << 4) | 0x08;
1485 break;
1487 case 0x28: // CD audio level
1488 MIXER.reg[0x36] = (value & 0xf0) | 0x08;
1489 MIXER.reg[0x37] = ((value & 0x0f) << 4) | 0x08;
1490 break;
1492 case 0x2e: // line in level
1493 MIXER.reg[0x38] = (value & 0xf0) | 0x08;
1494 MIXER.reg[0x39] = ((value & 0x0f) << 4) | 0x08;
1495 break;
1497 case 0x30: // master volume left
1498 MIXER.reg[0x22] &= 0x0f;
1499 MIXER.reg[0x22] |= (value & 0xf0);
1500 break;
1502 case 0x31: // master volume right
1503 MIXER.reg[0x22] &= 0xf0;
1504 MIXER.reg[0x22] |= (value >> 4);
1505 break;
1507 case 0x32: // DAC level left
1508 MIXER.reg[0x04] &= 0x0f;
1509 MIXER.reg[0x04] |= (value & 0xf0);
1510 break;
1512 case 0x33: // DAC level right
1513 MIXER.reg[0x04] &= 0xf0;
1514 MIXER.reg[0x04] |= (value >> 4);
1515 break;
1517 case 0x34: // FM level left
1518 MIXER.reg[0x26] &= 0x0f;
1519 MIXER.reg[0x26] |= (value & 0xf0);
1520 break;
1522 case 0x35: // FM level right
1523 MIXER.reg[0x26] &= 0xf0;
1524 MIXER.reg[0x26] |= (value >> 4);
1525 break;
1527 case 0x36: // CD audio level left
1528 MIXER.reg[0x28] &= 0x0f;
1529 MIXER.reg[0x28] |= (value & 0xf0);
1530 break;
1532 case 0x37: // CD audio level right
1533 MIXER.reg[0x28] &= 0xf0;
1534 MIXER.reg[0x28] |= (value >> 4);
1535 break;
1537 case 0x38: // line in level left
1538 MIXER.reg[0x2e] &= 0x0f;
1539 MIXER.reg[0x2e] |= (value & 0xf0);
1540 break;
1542 case 0x39: // line in level right
1543 MIXER.reg[0x2e] &= 0xf0;
1544 MIXER.reg[0x2e] |= (value >> 4);
1545 break;
1547 case 0x3a: // microphone level
1548 MIXER.reg[0x0a] = (value >> 5);
1549 break;
1551 case 0x3b:
1552 case 0x3c:
1553 case 0x3d:
1554 case 0x3e:
1555 case 0x3f:
1556 case 0x40:
1557 case 0x41:
1558 case 0x42:
1559 case 0x43:
1560 case 0x44:
1561 case 0x45:
1562 case 0x46:
1563 case 0x47:
1564 break;
1566 case 0x80: // IRQ mask
1567 case 0x81: // DMA mask
1568 MIXER.reg[MIXER.regindex] = value;
1569 set_irq_dma(); // both 0x80 and 0x81 handled
1570 return;
1572 default: // ignore read-only registers
1573 return;
1576 // store the value
1577 MIXER.reg[MIXER.regindex] = value;
1579 writelog(BOTHLOG(4), "mixer register %02x set to %02x",
1580 MIXER.regindex, MIXER.reg[MIXER.regindex]);
1583 Bit32u bx_sb16_c::mixer_readdata()
1585 writelog(BOTHLOG(4), "read from mixer register %02x returns %02x",
1586 MIXER.regindex, MIXER.reg[MIXER.regindex]);
1587 return(MIXER.reg[MIXER.regindex]);
1590 void bx_sb16_c::mixer_writeregister(Bit32u value)
1592 MIXER.regindex = value;
1595 void bx_sb16_c::set_irq_dma()
1597 static bx_bool isInitialized=0;
1598 int newirq;
1599 int oldDMA8, oldDMA16;
1601 // set the IRQ according to the value in mixer register 0x80
1602 switch (MIXER.reg[0x80])
1604 case 1:
1605 newirq = 2;
1606 break;
1607 case 2:
1608 newirq = 5;
1609 break;
1610 case 4:
1611 newirq = 7;
1612 break;
1613 case 8:
1614 newirq = 10;
1615 break;
1616 default:
1617 newirq = 5;
1618 writelog(BOTHLOG(3), "Bad value %02x in mixer register 0x80. IRQ set to %d",
1619 MIXER.reg[0x80], newirq);
1620 MIXER.reg[0x80] = 2;
1622 if (newirq != BX_SB16_IRQ) // a different IRQ was set
1624 if (BX_SB16_IRQ > 0)
1625 DEV_unregister_irq(BX_SB16_IRQ, "SB16");
1627 BX_SB16_IRQ = newirq;
1628 DEV_register_irq(BX_SB16_IRQ, "SB16");
1631 // set the 8 bit DMA
1632 oldDMA8=BX_SB16_DMAL;
1633 switch (MIXER.reg[0x81] & 0x0f)
1635 case 1:
1636 BX_SB16_DMAL = 0;
1637 break;
1638 case 2:
1639 BX_SB16_DMAL = 1;
1640 break;
1641 case 8:
1642 BX_SB16_DMAL = 3;
1643 break;
1644 default:
1645 BX_SB16_DMAL = 1;
1646 writelog(BOTHLOG(3), "Bad value %02x in mixer register 0x81. DMA8 set to %d",
1647 MIXER.reg[0x81], BX_SB16_DMAL);
1648 MIXER.reg[0x81] &= (~0x0f);
1649 MIXER.reg[0x81] |= (1 << BX_SB16_DMAL);
1652 // Unregister the previous DMA if initialized
1653 if ((isInitialized) && (oldDMA8 != BX_SB16_DMAL))
1654 DEV_dma_unregister_channel(oldDMA8);
1656 // And register the new 8bits DMA Channel
1657 if ((!isInitialized) || (oldDMA8 != BX_SB16_DMAL))
1658 DEV_dma_register_8bit_channel(BX_SB16_DMAL, dma_read8, dma_write8, "SB16");
1660 // and the 16 bit DMA
1661 oldDMA16=BX_SB16_DMAH;
1662 switch (MIXER.reg[0x81] >> 4)
1664 case 0:
1665 BX_SB16_DMAH = 0; // no 16-bit DMA
1666 break;
1667 case 2:
1668 BX_SB16_DMAH = 5;
1669 break;
1670 case 4:
1671 BX_SB16_DMAH = 6;
1672 break;
1673 case 8:
1674 BX_SB16_DMAH = 7;
1675 break;
1676 default:
1677 BX_SB16_DMAH = 0;
1678 writelog(BOTHLOG(3), "Bad value %02x in mixer register 0x81. DMA16 set to %d",
1679 MIXER.reg[0x81], BX_SB16_DMAH);
1680 MIXER.reg[0x81] &= (~0xf0);
1681 // MIXER.reg[0x81] |= (1 << BX_SB16_DMAH);
1682 // no default 16 bit channel!
1685 // Unregister the previous DMA if initialized
1686 if ((isInitialized) && (oldDMA16 != 0) && (oldDMA16 != BX_SB16_DMAH))
1687 DEV_dma_unregister_channel(oldDMA16);
1689 // And register the new 16bits DMA Channel
1690 if ((BX_SB16_DMAH != 0) && (oldDMA16 != BX_SB16_DMAH))
1691 DEV_dma_register_16bit_channel(BX_SB16_DMAH, dma_read16, dma_write16, "SB16");
1693 // If not already initialized
1694 if(!isInitialized) {
1695 isInitialized=1;
1696 } else {
1697 writelog(BOTHLOG(1), "Resources set to I%d D%d H%d",
1698 BX_SB16_IRQ, BX_SB16_DMAL, BX_SB16_DMAH);
1703 // now the MPU 401 part
1705 // the MPU 401 status port shows if input or output are ready
1706 // Note that the bits are inverse to their meaning
1708 Bit32u bx_sb16_c::mpu_status()
1710 Bit32u result = 0;
1712 if ((MPU.datain.full() == 1) ||
1713 ((BX_SB16_THIS midimode == 1) &&
1714 (BX_SB16_OUTPUT->midiready() == BX_SOUND_OUTPUT_ERR)))
1715 result |= 0x40; // output not ready
1716 if (MPU.dataout.empty() == 1)
1717 result |= 0x80; // no input available
1719 writelog(MIDILOG(4), "MPU status port, result %02x", result);
1721 return(result);
1724 // the MPU 401 command port
1726 void bx_sb16_c::mpu_command(Bit32u value)
1728 int i;
1729 int bytesneeded;
1731 if (MPU.cmd.hascommand() == 1) // already a command pending, abort that one
1733 if ((MPU.cmd.currentcommand() != value) ||
1734 (MPU.cmd.commanddone() == 0))
1735 // it's a different command, or the old one isn't done yet, abort it
1737 MPU.cmd.clearcommand();
1738 MPU.cmd.flush();
1741 // if it's the same one, and we just completed the argument list,
1742 // we leave it as it is and process it here
1745 if (MPU.cmd.hascommand() == 0) // no command pending, set one up
1747 bytesneeded = 0;
1748 if ((value >> 4) == 14) bytesneeded = 1;
1749 MPU.cmd.newcommand(value, bytesneeded);
1752 if (MPU.cmd.commanddone() == 1) // command is complete, process it
1754 switch (MPU.cmd.currentcommand())
1756 case 0x3f:
1757 writelog(MIDILOG(5), "MPU cmd: UART mode on");
1758 MPU.uartmode=1;
1759 MPU.irqpending=1;
1760 MPU.singlecommand=0;
1761 if (BX_SB16_IRQMPU != -1) {
1762 MIXER.reg[0x82] |= 4;
1763 DEV_pic_raise_irq(BX_SB16_IRQMPU);
1765 break;
1767 case 0xff:
1768 writelog(MIDILOG(4), "MPU cmd: Master reset of device");
1769 MPU.uartmode=MPU.forceuartmode;
1770 MPU.singlecommand=0;
1771 for (i=0; i<16; i++)
1773 MPU.banklsb[i] = 0;
1774 MPU.bankmsb[i] = 0;
1775 MPU.program[i] = 0;
1777 MPU.cmd.reset();
1778 MPU.dataout.reset();
1779 MPU.datain.reset();
1780 MPU.midicmd.reset();
1783 if (BX_SB16_IRQ != -1) {
1784 MIXER.reg[0x82] |= 4;
1785 BX_SB16_THIS devices->pic->trigger_irq(BX_SB16_IRQ);
1788 break;
1789 case 0xd0: // d0 and df: prefix for midi command
1790 case 0xdf: // like uart mode, but only a single command
1791 MPU.singlecommand = 1;
1792 writelog(MIDILOG(4), "MPU: prefix %02x received",
1793 MPU.cmd.currentcommand());
1794 break;
1795 default:
1796 writelog(MIDILOG(3), "MPU cmd: unknown command %02x ignored",
1797 MPU.cmd.currentcommand());
1798 break;
1801 // Need to put an MPU_ACK into the data port if command successful
1802 // we'll fake it even if we didn't process the command, so as to
1803 // allow detection of the MPU 401.
1804 if (MPU.dataout.put(0xfe) == 0)
1805 writelog(MIDILOG(3), "MPU_ACK error - output buffer full");
1806 MPU.cmd.clearcommand(); // clear the command from the buffer
1811 // MPU 401 data port/read: contains an MPU_ACK after receiving a command
1812 // Will contain other data as well when other than UART mode is supported
1814 Bit32u bx_sb16_c::mpu_dataread()
1816 Bit8u res8bit;
1817 Bit32u result;
1819 // also acknowledge IRQ?
1820 if (MPU.irqpending != 0)
1822 MPU.irqpending = 0;
1823 MIXER.reg[0x82] &= (~4);
1824 if ((MIXER.reg[0x82] & 0x07) == 0)
1825 DEV_pic_lower_irq(BX_SB16_IRQMPU);
1826 writelog(MIDILOG(4), "MPU IRQ acknowledged");
1829 if (MPU.dataout.get(&res8bit) == 0) {
1830 writelog(MIDILOG(3), "MPU data port not ready - no data in buffer");
1831 result = 0xff;
1833 else
1834 result = (Bit32u) res8bit;
1836 writelog(MIDILOG(4), "MPU data port, result %02x", result);
1838 return(result);
1842 // MPU 401 data port/write: This is where the midi stream comes from,
1843 // as well as arguments to any pending command
1845 void bx_sb16_c::mpu_datawrite(Bit32u value)
1847 writelog(MIDILOG(4), "write to MPU data port, value %02x", value);
1849 if (MPU.cmd.hascommand() == 1)
1850 { // there is a command pending, add arguments to it
1851 if (MPU.cmd.put(value) == 0)
1852 writelog(MIDILOG(3), "MPU Command arguments too long - buffer full");
1853 if (MPU.cmd.commanddone() == 1)
1854 BX_SB16_THIS mpu_command(MPU.cmd.currentcommand());
1856 else if ((MPU.uartmode == 0) && (MPU.singlecommand == 0))
1858 // Hm? No UART mode, but still data? Maybe should send it
1859 // to the command port... Only SBMPU401.EXE does this...
1860 writelog(MIDILOG(4), "MPU Data %02x received but no UART mode. Assuming it's a command.", value);
1861 mpu_command(value);
1862 return;
1864 else // no MPU command pending, in UART mode, this has to be midi data
1865 mpu_mididata(value);
1868 // A byte of midi data has been received
1869 void bx_sb16_c::mpu_mididata(Bit32u value)
1871 // first, find out if it is a midi command or midi data
1872 bx_bool ismidicommand = 0;
1873 if (value >= 0x80)
1874 { // bit 8 usually denotes a midi command...
1875 ismidicommand = 1;
1876 if ((value == 0xf7) && (MPU.midicmd.currentcommand() == 0xf0))
1877 // ...except if it is a continuing SYSEX message, then it just
1878 // denotes the end of a SYSEX chunk, not the start of a message
1880 ismidicommand = 0; // first, it's not a command
1881 MPU.midicmd.newcommand(MPU.midicmd.currentcommand(),
1882 MPU.midicmd.bytes());
1883 // Then, set needed bytes to current buffer
1884 // because we didn't know the length before
1888 if (ismidicommand == 1)
1889 { // this is a command, check if an old one is pending
1890 if (MPU.midicmd.hascommand() == 1)
1892 writelog(MIDILOG(3), "Midi command %02x incomplete, has %d of %d bytes.",
1893 MPU.midicmd.currentcommand(), MPU.midicmd.bytes(),
1894 MPU.midicmd.commandbytes());
1895 // write as much as we can. Should we do this?
1896 processmidicommand(0);
1897 // clear the pending command
1898 MPU.midicmd.clearcommand();
1899 MPU.midicmd.flush();
1902 // find the number of arguments to the command
1903 static const signed eventlength[] = { 2, 2, 2, 2, 1, 1, 2, 255};
1904 // note - length 255 commands have unknown length
1905 MPU.midicmd.newcommand(value, eventlength[(value & 0x70) >> 4]);
1907 else // no command, just arguments to the old command
1909 if (MPU.midicmd.hascommand() == 0)
1910 { // no command pending, ignore the data
1911 writelog(MIDILOG(3), "Midi data %02x received, but no command pending?", value);
1912 return;
1915 // just some data to the command
1916 if (MPU.midicmd.put(value) == 0)
1917 writelog(MIDILOG(3), "Midi buffer overflow!");
1918 if (MPU.midicmd.commanddone() == 1)
1920 // the command is complete, process it
1921 writelog(MIDILOG(5), "Midi command %02x complete, has %d bytes.",
1922 MPU.midicmd.currentcommand(), MPU.midicmd.bytes());
1923 processmidicommand(0);
1924 // and remove the command from the buffer
1925 MPU.midicmd.clearcommand();
1926 MPU.midicmd.flush();
1931 // The emulator port/read: See if commands were successful
1933 Bit32u bx_sb16_c::emul_read()
1935 Bit8u res8bit;
1936 Bit32u result;
1938 if (EMUL.datain.get(&res8bit) == 0)
1940 writelog(3, "emulator port not ready - no data in buffer");
1941 result = 0x00;
1943 else result = (Bit32u) res8bit;
1945 writelog(4, "emulator port, result %02x", result);
1947 return(result);
1950 // Emulator port/write: Changing instrument mapping etc.
1952 void bx_sb16_c::emul_write(Bit32u value)
1954 Bit8u value8 = 0;
1956 writelog(4, "write to emulator port, value %02x", value);
1958 if (EMUL.dataout.hascommand() == 0) // no command pending, set it up
1960 static signed char cmdlength[] = { 0, 0, 4, 2, 6, 1, 0, 0, 1, 1, 0, 1};
1961 if (value > 11)
1963 writelog(3, "emulator command %02x unknown, ignored.", value);
1964 return;
1966 writelog(5, "emulator command %02x, needs %d arguments",
1967 value, cmdlength[value]);
1968 EMUL.dataout.newcommand(value, cmdlength[value]);
1969 EMUL.datain.reset();
1970 EMUL.datain.put(0xfe);
1972 else
1973 EMUL.dataout.put(value); // otherwise just add data
1975 if (EMUL.dataout.commanddone() == 1)
1976 { // process the command
1977 writelog(4, "executing emulator command %02x with %d arguments",
1978 EMUL.dataout.currentcommand(), EMUL.dataout.bytes());
1979 switch (EMUL.dataout.currentcommand())
1981 case 0: // reinit of emulator
1982 writelog(4, "Emulator reinitialized");
1983 EMUL.remaps = 0;
1984 EMUL.dataout.reset();
1985 EMUL.datain.reset();
1986 EMUL.datain.put(0xfe);
1987 break;
1988 case 1: // dummy command to reset state of emulator port
1989 // just give a few times to end any commands
1990 break;
1991 case 2: // map bank
1992 if (EMUL.remaps >= BX_SB16_PATCHTABLESIZE) break;
1993 EMUL.dataout.get (& (EMUL.remaplist[EMUL.remaps].oldbankmsb));
1994 EMUL.dataout.get (& (EMUL.remaplist[EMUL.remaps].oldbanklsb));
1995 EMUL.remaplist[EMUL.remaps].oldprogch = 0xff;
1996 EMUL.dataout.get (& (EMUL.remaplist[EMUL.remaps].newbankmsb));
1997 EMUL.dataout.get (& (EMUL.remaplist[EMUL.remaps].newbanklsb));
1998 EMUL.remaplist[EMUL.remaps].newprogch = 0xff;
1999 EMUL.datain.put(4);
2000 writelog(4, "Map bank command received, from %d %d to %d %d",
2001 EMUL.remaplist[EMUL.remaps].oldbankmsb,
2002 EMUL.remaplist[EMUL.remaps].oldbanklsb,
2003 EMUL.remaplist[EMUL.remaps].newbankmsb,
2004 EMUL.remaplist[EMUL.remaps].newbanklsb);
2005 EMUL.remaps++;
2006 break;
2007 case 3: // map program change
2008 if (EMUL.remaps >= BX_SB16_PATCHTABLESIZE) break;
2009 EMUL.remaplist[EMUL.remaps].oldbankmsb = 0xff;
2010 EMUL.remaplist[EMUL.remaps].oldbanklsb = 0xff;
2011 EMUL.dataout.get (& (EMUL.remaplist[EMUL.remaps].oldprogch));
2012 EMUL.remaplist[EMUL.remaps].newbankmsb = 0xff;
2013 EMUL.remaplist[EMUL.remaps].newbanklsb = 0xff;
2014 EMUL.dataout.get (& (EMUL.remaplist[EMUL.remaps].newprogch));
2015 EMUL.datain.put(2);
2016 writelog(4, "Map program change received, from %d to %d",
2017 EMUL.remaplist[EMUL.remaps].oldprogch,
2018 EMUL.remaplist[EMUL.remaps].newprogch);
2019 EMUL.remaps++;
2020 break;
2021 case 4: // map bank and program change
2022 if (EMUL.remaps >= BX_SB16_PATCHTABLESIZE) break;
2023 EMUL.dataout.get (& (EMUL.remaplist[EMUL.remaps].oldbankmsb));
2024 EMUL.dataout.get (& (EMUL.remaplist[EMUL.remaps].oldbanklsb));
2025 EMUL.dataout.get (& (EMUL.remaplist[EMUL.remaps].oldprogch));
2026 EMUL.dataout.get (& (EMUL.remaplist[EMUL.remaps].newbankmsb));
2027 EMUL.dataout.get (& (EMUL.remaplist[EMUL.remaps].newbanklsb));
2028 EMUL.dataout.get (& (EMUL.remaplist[EMUL.remaps].newprogch));
2029 EMUL.datain.put(6);
2030 writelog(4, "Complete remap received, from %d %d %d to %d %d %d",
2031 EMUL.remaplist[EMUL.remaps].oldbankmsb,
2032 EMUL.remaplist[EMUL.remaps].oldbanklsb,
2033 EMUL.remaplist[EMUL.remaps].oldprogch,
2034 EMUL.remaplist[EMUL.remaps].newbankmsb,
2035 EMUL.remaplist[EMUL.remaps].newbanklsb,
2036 EMUL.remaplist[EMUL.remaps].newprogch);
2038 EMUL.remaps++;
2039 break;
2040 case 5: EMUL.dataout.get(&value8); // dump emulator state
2041 switch (value8)
2043 case 0:
2044 EMUL.datain.puts("SB16 Emulator for Bochs\n");
2045 break;
2046 case 1:
2047 EMUL.datain.puts("UART mode=%d (force=%d)\n",
2048 MPU.uartmode, MPU.forceuartmode);
2049 break;
2050 case 2:
2051 EMUL.datain.puts("timer=%d\n", MPU.current_timer);
2052 break;
2053 case 3:
2054 EMUL.datain.puts("%d remappings active\n", EMUL.remaps);
2055 break;
2056 case 4:
2057 EMUL.datain.puts("Resources are A%3x I%d D%d H%d T%d P%3x; Adlib at %3x\n",
2058 BX_SB16_IO, BX_SB16_IRQ, BX_SB16_DMAL,
2059 BX_SB16_DMAH, 6, BX_SB16_IOMPU, BX_SB16_IOADLIB);
2060 break;
2061 case 5:
2062 EMUL.datain.puts("Current OPL2/3 mode: %s",
2063 // ok, I admit that this is a bit ugly...
2064 (OPL.mode == single)?"single OPL2 (OPL3 disabled)\n":
2065 (OPL.mode == adlib)?"single OPL2 (no OPL3)\n":
2066 (OPL.mode == dual)?"double OPL2\n":
2067 (OPL.mode == opl3)?"OPL3\n":
2068 "unknown");
2069 break;
2070 default:
2071 EMUL.datain.puts("no info. Only slots 0..5 have values.\n");
2072 break;
2074 break;
2075 case 6: // close midi and wave files and/or output
2076 if ((BX_SB16_THIS midimode == 2) ||
2077 (BX_SB16_THIS midimode == 3))
2079 if (BX_SB16_THIS midimode == 2) finishmidifile();
2080 fclose(MIDIDATA);
2082 else if (BX_SB16_THIS midimode == 1)
2083 BX_SB16_OUTPUT->closemidioutput();
2084 BX_SB16_THIS midimode = 0;
2086 if ((BX_SB16_THIS wavemode == 2) ||
2087 (BX_SB16_THIS wavemode == 3))
2089 if (BX_SB16_THIS wavemode == 2) finishvocfile();
2090 fclose(WAVEDATA);
2092 else
2093 BX_SB16_OUTPUT->closewaveoutput();
2094 BX_SB16_THIS wavemode = 0;
2095 break;
2096 case 7: // clear bank/program mappings
2097 EMUL.remaps = 0;
2098 writelog(4, "Bank/program mappings cleared.");
2099 break;
2100 case 8: // set force uart mode on/off
2101 EMUL.dataout.get(&value8);
2102 MPU.forceuartmode = value8;
2103 if (value8 != 0)
2104 MPU.uartmode = MPU.forceuartmode;
2105 writelog(4, "Force UART mode = %d", MPU.forceuartmode);
2106 break;
2107 case 9: // enter specific OPL2/3 mode
2108 EMUL.dataout.get(&value8);
2109 writelog(4, "Entering OPL2/3 mode %d", value8);
2110 opl_entermode((bx_sb16_fm_mode) value8);
2111 break;
2112 case 10: // check emulator present
2113 EMUL.datain.put(0x55);
2114 break;
2115 case 11: // send data to midi device
2116 EMUL.dataout.get(&value8);
2117 mpu_mididata(value8);
2119 EMUL.dataout.clearcommand();
2120 EMUL.dataout.flush();
2124 // and finally the OPL (FM emulation) part
2126 // select a new operational mode for the FM part
2127 // this also serves as reset for the OPL chip
2128 void bx_sb16_c::opl_entermode(bx_sb16_fm_mode newmode)
2130 int i, j;
2132 // do nothing if the mode is unchanged
2133 if (OPL.mode == newmode)
2134 return;
2136 // if the old mode was 0, and the new mode is 3, then
2137 // no reset is necessary, just set the flag
2138 if ((OPL.mode == single) && (newmode == opl3))
2140 writelog(MIDILOG(4), "OPL3 mode enabled");
2141 OPL.mode = newmode;
2142 return;
2145 writelog(MIDILOG(4), "Switching to OPL mode %d from %d", newmode, OPL.mode);
2147 for (i=0; i<BX_SB16_FM_NCH; i++)
2148 opl_keyonoff(i, 0);
2150 OPL.mode = newmode;
2152 if (OPL.timer_running != 0)
2154 bx_pc_system.deactivate_timer(OPL.timer_handle);
2155 OPL.timer_running = 0;
2158 OPL.drumchannel = 10;
2160 OPL.midichannels = 0xffff; // all channels but the drum channel available
2161 OPL.midichannels &= ~(1 << OPL.drumchannel);
2163 for (i=0; i<2; i++) {
2164 OPL.wsenable[i] = 0;
2165 OPL.tmask[i] = 0;
2166 OPL.tflag[i] = 0;
2167 OPL.percmode[i] = 0;
2170 for (i=0; i<4; i++) {
2171 OPL.timer[i] = 0;
2172 OPL.timerinit[i] = 0;
2175 // initialize the operators
2176 for (i=0; i<BX_SB16_FM_NOP; i++)
2177 for (j=0; j<BX_SB16_FM_OPB; j++)
2178 OPL.oper[i][j] = 0;
2180 // TESTING for array bounds - compiler should bark if too high
2181 OPL.oper[BX_SB16_FM_NOP-1][BX_SB16_FM_OPB-1] = 0;
2183 // initialize the channels
2185 // first zero all values
2186 for (i=0; i<BX_SB16_FM_NCH; i++)
2188 OPL.chan[i].nop = 0;
2189 for (j=0; j<4; j++) {
2190 OPL.chan[i].opnum[j] = 0;
2191 OPL.chan[i].outputlevel[j] = 0;
2193 OPL.chan[i].freq = 0;
2194 OPL.chan[i].afreq = 0;
2195 OPL.chan[i].midichan = 0xff;
2196 OPL.chan[i].needprogch = 0;
2197 OPL.chan[i].midion = 0;
2198 OPL.chan[i].midinote = 0;
2199 OPL.chan[i].midibend = 0;
2200 OPL.chan[i].midivol = 0;
2203 // assign the operators
2204 for (i=0; i<BX_SB16_FM_NCH; i++)
2206 OPL.chan[i].nop = 2;
2207 // who invented this absolutely insane operator grouping??
2208 // it's like this: (ch 9...17 as 0...8 but higher operators)
2209 // ch: 0 1 2 3 4 5 6 7 8
2210 // op1: 0 1 2 6 7 8 12 13 14
2211 // op2: 3 4 5 9 10 11 15 16 17
2212 OPL.chan[i].opnum[0] = i + ((int) (i / 3)) * 3;
2213 OPL.chan[i].opnum[1] = OPL.chan[i].opnum[0] + 3;
2216 // assign 4-op operators to the appropriate channels
2217 // note- they are not used unless .nop == 4
2218 for (i=0; i<6; i++) {
2219 j = i + (i /3) * 6;
2220 OPL.chan[j].opnum[2] = OPL.chan[j + 3].opnum[0];
2221 OPL.chan[j].opnum[3] = OPL.chan[j + 3].opnum[1];
2225 // this is called whenever one of the timer elapses
2226 void bx_sb16_c::opl_timerevent()
2228 Bit16u mask;
2230 for (int i=0; i<4; i++) {
2231 if ((OPL.tmask[i/2] & (1 << (i % 2))) != 0) { // only running timers
2232 if ((i % 2) == 0) {
2233 mask = 0xff;
2234 } else {
2235 mask = 0x3ff;
2237 if (((OPL.timer[i]++) & mask) == 0) { // overflow occured, set flags accordingly
2238 OPL.timer[i] = OPL.timerinit[i]; // reset the counter
2239 if ((OPL.tmask[i/2] >> (6 - (i % 2))) == 0) { // set flags only if unmasked
2240 writelog(MIDILOG(5), "OPL Timer Interrupt: Chip %d, Timer %d", i/2, 1 << (i % 2));
2241 OPL.tflag[i/2] |= 1 << (6 - (i % 2)); // set the overflow flag
2242 OPL.tflag[i/2] |= 1 << 7; // set the IRQ flag
2249 // return the status of one of the OPL2's, or the
2250 // base status of the OPL3
2251 Bit32u bx_sb16_c::opl_status(int chipid)
2253 Bit32u status = OPL.tflag[chipid];
2254 writelog(MIDILOG(5), "OPL status of chip %d is %02x", chipid, status);
2255 return status;
2258 // set the register index for one of the OPL2's or the
2259 // base or advanced register index for the OPL3
2260 void bx_sb16_c::opl_index(Bit32u value, int chipid)
2262 OPL.index[chipid] = value;
2265 // write to the data port
2266 void bx_sb16_c::opl_data(Bit32u value, int chipid)
2268 int index = OPL.index[chipid];
2269 int opernum = -1; // OPL3 operator number; 0..35
2270 int channum = -1; // OPL3 channel number; 0..17
2271 int subopnum = -1; // channel operator; 0..nop-1
2273 writelog(MIDILOG(4), "Write to OPL(%d) register %02x: %02x",
2274 chipid, index, value);
2276 // first find out operator and/or channel numbers
2277 // case 0x20 ... 0x95: includes too many ports, but that is harmless
2278 // case 0xe0 ... 0xf5:
2279 if (((index>=0x20) && (index<=0x95)) ||
2280 ((index>=0xe0) && (index<=0xf5))) {
2281 // operator access
2282 // find the operator number. 0..17 on chip 1, 18..35 on chip 2
2284 // note, the numbers are not continuous (again...), so we need
2285 // this rather weird calculation
2286 opernum = index & 0x07;
2287 if (opernum > 5) // invalid register, has no operator associated
2289 opernum = -1;
2290 goto break_here;
2293 opernum += ((index & 0x18) >> 3) * 6;
2294 if (opernum > 17) // Operators 18+ have to be accessed on other address set
2296 opernum = -1;
2297 goto break_here;
2300 if (chipid == 1)
2301 opernum += BX_SB16_FM_NOP / 2;
2303 // find out the channel number, and which of the channel's operators this is
2304 channum = opernum % 3 + ((int) (opernum / 6)) * 3;
2305 subopnum = 0;
2307 if ((opernum % 6) > 2) // second operator
2308 subopnum = 1;
2310 // if (channel - 3) is in a four-operator mode, that is really
2311 // what this operator belongs to
2312 if (channum >= 3) {
2313 if (OPL.chan[channum - 3].nop == 4)
2315 channum -= 3;
2316 subopnum += 2;
2319 writelog(MIDILOG(5), "Is Channel %d, Oper %d, Subop %d",
2320 channum, opernum, subopnum);
2322 else if ((index>=0xa0) && (index<=0xc8)) {
2323 // channel access
2324 channum = index & 0x0f;
2325 if (OPL.chan[channum].nop == 0)
2326 channum = -1; // the channel is disabled
2327 writelog(MIDILOG(5), "Is channel %d", channum);
2330 break_here:
2332 switch (index & 0xff)
2334 // WSEnable and Test Register
2335 case 0x01:
2336 OPL.wsenable[chipid] = (value >> 5) & 1;
2337 if ((value & 0x1f) != 0)
2338 writelog(MIDILOG(3), "Warning: Test Register set to %02x", value & 0x1f);
2339 break;
2341 // the two timer counts
2342 case 0x02:
2343 OPL.timerinit[chipid * 2] = OPL.timer[chipid * 2] = value;
2344 break;
2345 case 0x03:
2346 OPL.timerinit[chipid * 2 + 1] = OPL.timer[chipid * 2 + 1] = (value << 2);
2347 break;
2349 // if OPL2: timer masks
2350 // if OPL3: 4-operator modes
2351 case 0x04:
2352 if ((chipid == 0) || (OPL.mode == dual))
2353 opl_settimermask(value, chipid);
2354 else
2355 opl_set4opmode(value & 0x3f);
2356 break;
2358 // only OPL3: OPL3 enable
2359 case 0x05:
2360 if (chipid == 1)
2362 if ((value & 1) != 0)
2363 opl_entermode(opl3);
2364 else
2365 opl_entermode(single);
2367 break;
2369 // Composite Sine Wave and Note-sel (ignored)
2370 case 0x08:
2371 if (value != 0)
2372 writelog(MIDILOG(3),
2373 "Warning: write of %02x to CSW/Note-sel ignored", value);
2374 break;
2376 // most importantly the percussion part
2377 case 0xbd:
2378 opl_setpercussion(value, chipid);
2379 break;
2381 // the operator registers
2382 // case 0x20 ... 0x35:
2383 case 0x20:
2384 case 0x21:
2385 case 0x22:
2386 case 0x23:
2387 case 0x24:
2388 case 0x25:
2389 case 0x26:
2390 case 0x27:
2391 case 0x28:
2392 case 0x29:
2393 case 0x2a:
2394 case 0x2b:
2395 case 0x2c:
2396 case 0x2d:
2397 case 0x2e:
2398 case 0x2f:
2399 case 0x30:
2400 case 0x31:
2401 case 0x32:
2402 case 0x33:
2403 case 0x34:
2404 case 0x35:
2405 // case 0x60 ... 0x75:
2406 case 0x60:
2407 case 0x61:
2408 case 0x62:
2409 case 0x63:
2410 case 0x64:
2411 case 0x65:
2412 case 0x66:
2413 case 0x67:
2414 case 0x68:
2415 case 0x69:
2416 case 0x6a:
2417 case 0x6b:
2418 case 0x6c:
2419 case 0x6d:
2420 case 0x6e:
2421 case 0x6f:
2422 case 0x70:
2423 case 0x71:
2424 case 0x72:
2425 case 0x73:
2426 case 0x74:
2427 case 0x75:
2428 // case 0x80 ... 0x95:
2429 case 0x80:
2430 case 0x81:
2431 case 0x82:
2432 case 0x83:
2433 case 0x84:
2434 case 0x85:
2435 case 0x86:
2436 case 0x87:
2437 case 0x88:
2438 case 0x89:
2439 case 0x8a:
2440 case 0x8b:
2441 case 0x8c:
2442 case 0x8d:
2443 case 0x8e:
2444 case 0x8f:
2445 case 0x90:
2446 case 0x91:
2447 case 0x92:
2448 case 0x93:
2449 case 0x94:
2450 case 0x95:
2451 if (opernum != -1)
2453 opl_changeop(channum, opernum, (index / 0x20) - 1, value);
2454 break;
2456 // else let default: catch it
2458 // case 0x40 ... 0x55:
2459 case 0x40:
2460 case 0x41:
2461 case 0x42:
2462 case 0x43:
2463 case 0x44:
2464 case 0x45:
2465 case 0x46:
2466 case 0x47:
2467 case 0x48:
2468 case 0x49:
2469 case 0x4a:
2470 case 0x4b:
2471 case 0x4c:
2472 case 0x4d:
2473 case 0x4e:
2474 case 0x4f:
2475 case 0x50:
2476 case 0x51:
2477 case 0x52:
2478 case 0x53:
2479 case 0x54:
2480 case 0x55:
2481 if (opernum != -1)
2483 opl_changeop(channum, opernum, 1, value & 0xc0);
2484 if (subopnum != -1)
2485 opl_setvolume(channum, subopnum, value & 0x3f);
2486 break;
2488 // else let default: catch it
2490 // case 0xe0 ... 0xf5:
2491 case 0xe0:
2492 case 0xe1:
2493 case 0xe2:
2494 case 0xe3:
2495 case 0xe4:
2496 case 0xe5:
2497 case 0xe6:
2498 case 0xe7:
2499 case 0xe8:
2500 case 0xe9:
2501 case 0xea:
2502 case 0xeb:
2503 case 0xec:
2504 case 0xed:
2505 case 0xee:
2506 case 0xef:
2507 case 0xf0:
2508 case 0xf1:
2509 case 0xf2:
2510 case 0xf3:
2511 case 0xf4:
2512 case 0xf5:
2513 if (opernum != -1)
2515 opl_changeop(channum, opernum, 5, value & 0x07);
2516 break;
2518 // else let default: catch it
2520 // and the channel registers
2521 // case 0xa0 ... 0xa8:
2522 case 0xa0:
2523 case 0xa1:
2524 case 0xa2:
2525 case 0xa3:
2526 case 0xa4:
2527 case 0xa5:
2528 case 0xa6:
2529 case 0xa7:
2530 case 0xa8:
2531 if (channum != -1)
2533 if (value != (Bit32u)(OPL.chan[channum].freq & 0xff)) {
2534 OPL.chan[channum].freq &= 0xff00;
2535 OPL.chan[channum].freq |= value;
2536 opl_setfreq(channum);
2538 break;
2540 // else let default: catch it
2542 // case 0xb0 ... 0xb8:
2543 case 0xb0:
2544 case 0xb1:
2545 case 0xb2:
2546 case 0xb3:
2547 case 0xb4:
2548 case 0xb5:
2549 case 0xb6:
2550 case 0xb7:
2551 case 0xb8:
2552 if (channum != -1)
2554 if ((value & 0x1f) != ((Bit32u)(OPL.chan[channum].freq >> 8) & 0x1f)) {
2555 OPL.chan[channum].freq &= 0x00ff;
2556 OPL.chan[channum].freq |= (value & 0x1f) << 8;
2557 opl_setfreq(channum);
2559 opl_keyonoff(channum, (value >> 5) & 1);
2560 break;
2562 // else let default: catch it
2565 // this is a channel access, but it belongs to the instrument
2566 // definition, so put it into value [4] of the channel's first operator
2567 // case 0xc0 ... 0xc8:
2568 case 0xc0:
2569 case 0xc1:
2570 case 0xc2:
2571 case 0xc3:
2572 case 0xc4:
2573 case 0xc5:
2574 case 0xc6:
2575 case 0xc7:
2576 case 0xc8:
2577 if (channum != -1)
2579 int needchange = 0;
2580 if ((OPL.oper[OPL.chan[channum].opnum[0]][4] & 1) != (int)(value & 1))
2581 needchange = 1;
2583 opl_changeop(channum, OPL.chan[channum].opnum[0], 4, value & 0x3f);
2585 if (needchange == 1)
2586 opl_setmodulation(channum);
2587 break;
2589 // else let default: catch it
2591 default:
2592 writelog(MIDILOG(3), "Attempt to write %02x to unknown OPL(%d) register %02x",
2593 value, chipid, index);
2594 break;
2598 // change a value of an operator
2599 void bx_sb16_c::opl_changeop(int channum, int opernum, int byte, int value)
2601 if (OPL.oper[opernum][byte] != value) {
2602 OPL.oper[opernum][byte] = value;
2603 OPL.chan[channum].needprogch = 1;
2607 // called for a write to the 4-operator mode register
2608 void bx_sb16_c::opl_set4opmode(int new4opmode)
2610 int i, channel1, channel2;
2612 writelog(MIDILOG(4), "Switching to 4-op mode %02x", new4opmode);
2614 // every bit switches a 4-op channel-pairing on or off
2615 // 4-op mode is two channels combined into the first one
2616 for (i = 0; i<6; i++)
2618 channel1 = i + (i / 3) * 6;
2619 channel2 = channel1 + 3;
2621 if (((new4opmode >> i) & 1) != 0)
2622 { // enable 4-op mode
2623 opl_keyonoff(channel1, 0);
2624 opl_keyonoff(channel2, 0);
2626 OPL.chan[channel1].nop = 4;
2627 OPL.chan[channel2].nop = 0;
2629 OPL.chan[channel1].needprogch = 1;
2631 else
2632 { // disable 4-op mode
2633 opl_keyonoff(channel1, 0);
2635 OPL.chan[channel1].nop = 2;
2636 OPL.chan[channel2].nop = 2;
2638 OPL.chan[channel1].needprogch = 1;
2639 OPL.chan[channel2].needprogch = 1;
2644 // called for a write to port 4 of either chip
2645 void bx_sb16_c::opl_settimermask(int value, int chipid)
2647 if ((value & 0x80) != 0) // reset IRQ and timer flags
2648 { // all other bits ignored!
2649 writelog(MIDILOG(5), "IRQ Reset called");
2650 OPL.tflag[chipid] = 0;
2651 return;
2654 OPL.tmask[chipid] = value & 0x63;
2655 writelog(MIDILOG(5), "New timer mask for chip %d is %02x",
2656 chipid, OPL.tmask[chipid]);
2658 // do we have to activate or deactivate the timer?
2659 if (((value & 0x03) != 0) ^ (OPL.timer_running != 0))
2661 if ((value & 0x03) != 0) // yes, it's different. Start or stop?
2663 writelog(MIDILOG(5), "Starting timers");
2664 bx_pc_system.activate_timer(OPL.timer_handle, 80, 1);
2665 OPL.timer_running = 1;
2667 else
2669 writelog(MIDILOG(5), "Stopping timers");
2670 bx_pc_system.deactivate_timer(OPL.timer_handle);
2671 OPL.timer_running = 0;
2676 // called when the modulation mode of a channel changes
2677 void bx_sb16_c::opl_setmodulation(int channel)
2679 int opernum = OPL.chan[channel].opnum[0];
2681 if ((OPL.chan[channel].nop == 0) &&
2682 (channel >= 3) &&
2683 (OPL.chan[channel].nop == 4)) channel -= 3;
2685 if (OPL.chan[channel].nop == 2)
2687 OPL.chan[channel].ncarr = (OPL.oper[opernum][4] & 1) + 1;
2688 OPL.chan[channel].needprogch = 1;
2690 else if (OPL.chan[channel].nop == 4)
2692 int opernum2 = OPL.chan[channel].opnum[2];
2693 int modmode = (OPL.oper[opernum][4] & 1) |
2694 ((OPL.oper[opernum2][4] & 1) >> 1);
2695 OPL.chan[channel].ncarr = modmode + 1 - (modmode / 2);
2696 OPL.chan[channel].needprogch = 1;
2700 // called for a write to register 0xbd, the percussion register
2701 void bx_sb16_c::opl_setpercussion(Bit8u value, int chipid)
2703 UNUSED(value);
2704 UNUSED(chipid);
2707 // called when a channel volume changes
2708 // opnum is which of the channel's operators had the change, not
2709 // the actual operator number. Thus, it's from 0..3.
2710 void bx_sb16_c::opl_setvolume(int channel, int opnum, int outlevel)
2712 UNUSED(opnum);
2713 UNUSED(outlevel);
2715 OPL.chan[channel].midivol = 127;
2719 // called when a frequency change is complete, to find out the
2720 // corresponding midi key and pitch bender values
2721 void bx_sb16_c::opl_setfreq(int channel)
2723 int block,fnum;
2725 // definition:
2726 // low-byte of freq: 8 bit F-Number, LSB's
2727 // high-byte of freq: [2 reserved][KEY-ON][3 block][2 F-Number MSB's]
2728 // [KEY-ON] is ignored by this function
2730 // the definition of the F-number is
2731 // F-Number = Frequency * 2**(20-block) / (49716 Hz)
2733 // Thus, the frequency can be calculated as
2734 // Frequency = F-Number / 2**(20-block) * 49716 Hz
2736 // (But remember that afreq is in 10^-3 Hz!)
2739 fnum = OPL.chan[channel].freq & 0x3ff;
2740 block = (OPL.chan[channel].freq >> 10) & 0x07;
2742 writelog(MIDILOG(5), "F-Num is %d, block is %d", fnum, block);
2744 Bit32u realfreq;
2745 const Bit32u freqbase = 49716000; // const is better than #define if type is important
2747 // this is a bit messy to preserve accuracy as much as possible,
2748 // otherwise we might either lose precision, or the higher bits.
2749 realfreq = ((freqbase >> 4) * fnum) >> (16 - block);
2751 OPL.chan[channel].afreq = realfreq;
2753 // now find out what MIDI key this corresponds to, and with what
2754 // pitch bender value... (the latter not implemented yet)
2755 int octave=0; // 0: Octave from 523.2511 Hz; pos=higher, neg=lower
2756 int keynum=0; // 0=C; 1=C#; 2=D; ...; 11=B
2758 if (realfreq > 8175) { // 8.175 is smallest possible frequency
2759 const Bit32u freqC = 523251; // Midi note 72; "C": 523.251 Hz
2760 Bit32u keyfreq; // Frequency scaled to the octave from freqC to 2*freqC
2762 if (realfreq > freqC) {
2763 while ((realfreq >> (++octave)) > freqC);
2764 keyfreq = realfreq >> (--octave);
2765 } else {
2766 while ((realfreq << (++octave)) < freqC);
2767 keyfreq = realfreq << octave;
2768 octave = -octave;
2771 // this is a reasonable approximation for keyfreq /= 1.059463
2772 // (that value is 2**(1/12), which is the difference between two keys)
2773 while ((keyfreq -= ((keyfreq * 1000) / 17817)) > freqC)
2774 keynum++;
2775 } else {
2776 octave = -6;
2777 keynum = 0;
2780 OPL.chan[channel].midinote = (octave + 6) * 12 + keynum;
2782 writelog(MIDILOG(5), "New frequency %.3f is key %d in octave %d; midi note %d",
2783 (float) realfreq/1000.0, keynum, octave, OPL.chan[channel].midinote);
2786 // called when a note is possibly turned on or off
2787 void bx_sb16_c::opl_keyonoff(int channel, bx_bool onoff)
2789 int i;
2790 Bit8u commandbytes[3];
2792 if (OPL.mode == fminit)
2793 return;
2795 // first check if there really is a change in the state
2796 if (onoff == OPL.chan[channel].midion)
2797 return;
2799 OPL.chan[channel].midion = onoff;
2801 // check if we have a midi channel, otherwise allocate one if possible
2802 if (OPL.chan[channel].midichan == 0xff) {
2803 for (i=0; i<16; i++)
2804 if (((OPL.midichannels >> i) & 1) != 0) {
2805 OPL.chan[channel].midichan = i;
2806 OPL.midichannels &= ~(1 << i); // mark channel as used
2807 OPL.chan[channel].needprogch = 1;
2809 if (OPL.chan[channel].midichan == 0xff)
2810 return;
2813 if (OPL.chan[channel].needprogch != 0)
2814 opl_midichannelinit(channel);
2816 commandbytes[0] = OPL.chan[channel].midichan;
2817 commandbytes[1] = OPL.chan[channel].midinote;
2818 commandbytes[2] = 0;
2820 if (onoff == 0) {
2821 commandbytes[0] |= 0x80; // turn it off
2822 } else {
2823 commandbytes[0] |= 0x90; // turn it on
2824 commandbytes[2] = OPL.chan[channel].midivol;
2827 writemidicommand(commandbytes[0], 2, & (commandbytes[1]));
2830 // setup a midi channel
2831 void bx_sb16_c::opl_midichannelinit(int channel)
2833 UNUSED(channel);
2836 /* Handlers for the midi commands/midi file output */
2838 // Write the header of the midi file. Track length is 0x7fffffff
2839 // until we know how long it's really going to be
2841 void bx_sb16_c::initmidifile()
2843 struct {
2844 Bit8u chunk[4];
2845 Bit32u chunklen; // all values in BIG Endian!
2846 Bit16u smftype;
2847 Bit16u tracknum;
2848 Bit16u timecode; // 0x80 + deltatimesperquarter << 8
2849 } midiheader =
2850 #ifdef BX_LITTLE_ENDIAN
2851 { "MTh", 0x06000000, 0, 0x0100, 0x8001 };
2852 #else
2853 { "MTh", 6, 0, 1, 0x180 };
2854 #endif
2855 midiheader.chunk[3] = 'd';
2857 struct {
2858 Bit8u chunk[4];
2859 Bit32u chunklen;
2860 Bit8u data[15];
2861 } trackheader =
2862 #ifdef BX_LITTLE_ENDIAN
2863 { "MTr", 0xffffff7f,
2864 #else
2865 { "MTr", 0x7fffffff,
2866 #endif
2867 { 0x00,0xff,0x51,3,0x07,0xa1,0x20, // set tempo 120 (0x7a120 us per quarter)
2868 0x00,0xff,0x58,4,4,2,0x18,0x08 }}; // time sig 4/4
2869 trackheader.chunk[3] = 'k';
2871 fwrite(&midiheader, 1, 14, MIDIDATA);
2872 fwrite(&trackheader, 1, 23, MIDIDATA);
2875 // write the midi command to the midi file
2877 void bx_sb16_c::writemidicommand(int command, int length, Bit8u data[])
2879 bx_list_c *base;
2880 /* We need to determine the time elapsed since the last MIDI command */
2881 int deltatime = currentdeltatime();
2883 /* Initialize output device if necessary and not done yet */
2884 if (BX_SB16_THIS midimode == 1) {
2885 if (MPU.outputinit != 1) {
2886 writelog(MIDILOG(4), "Initializing Midi output.");
2887 if (BX_SB16_OUTPUT->openmidioutput(SIM->get_param_string(BXPN_SB16_MIDIFILE)->getptr()) == BX_SOUND_OUTPUT_OK)
2888 MPU.outputinit = 1;
2889 else
2890 MPU.outputinit = 0;
2891 if (MPU.outputinit != 1) {
2892 writelog(MIDILOG(2), "Error: Couldn't open midi output. Midi disabled.");
2893 BX_SB16_THIS midimode = 0;
2894 return;
2897 BX_SB16_OUTPUT->sendmidicommand(deltatime, command, length, data);
2898 return;
2899 } else if ((BX_SB16_THIS midimode == 2) ||
2900 (BX_SB16_THIS midimode == 3)) {
2901 base = (bx_list_c*) SIM->get_param(BXPN_SB16);
2902 MIDIDATA = fopen(SIM->get_param_string("midifile", base)->getptr(),"wb");
2903 if (MIDIDATA == NULL) {
2904 writelog (MIDILOG(2), "Error opening file %s. Midimode disabled.",
2905 SIM->get_param_string("midifile", base)->getptr());
2906 BX_SB16_THIS midimode = 0;
2907 } else if (BX_SB16_THIS midimode == 2) {
2908 initmidifile();
2912 if (BX_SB16_THIS midimode < 2)
2913 return;
2915 if (BX_SB16_THIS midimode == 2)
2916 writedeltatime(deltatime);
2918 fputc(command, MIDIDATA);
2919 if ((command == 0xf0) ||
2920 (command == 0xf7)) // write event length for sysex/meta events
2921 writedeltatime(length);
2923 fwrite(data, 1, length, MIDIDATA);
2926 // determine how many delta times have passed since
2927 // this function was called last
2929 int bx_sb16_c::currentdeltatime()
2931 int deltatime;
2933 // counting starts at first access
2934 if (MPU.last_delta_time == 0xffffffff)
2935 MPU.last_delta_time = MPU.current_timer;
2937 deltatime = MPU.current_timer - MPU.last_delta_time;
2938 MPU.last_delta_time = MPU.current_timer;
2940 return deltatime;
2943 // process the midi command stored in MPU.midicmd.to the midi driver
2945 void bx_sb16_c::processmidicommand(bx_bool force)
2947 int i, channel;
2948 Bit8u value;
2949 bx_bool needremap = 0;
2951 channel = MPU.midicmd.currentcommand() & 0xf;
2953 // we need to log bank changes and program changes
2954 if ((MPU.midicmd.currentcommand() >> 4) == 0xc)
2955 { // a program change
2956 value = MPU.midicmd.peek(0);
2957 writelog(MIDILOG(1), "* ProgramChange channel %d to %d",
2958 channel, value);
2959 MPU.program[channel] = value;
2960 needremap = 1;
2962 else if ((MPU.midicmd.currentcommand() >> 4) == 0xb)
2963 { // a control change, could be a bank change
2964 if (MPU.midicmd.peek(0) == 0)
2965 { // bank select MSB
2966 value = MPU.midicmd.peek(1);
2967 writelog(MIDILOG(1), "* BankSelectMSB (%x %x %x) channel %d to %d",
2968 MPU.midicmd.peek(0), MPU.midicmd.peek(1), MPU.midicmd.peek(2),
2969 channel, value);
2970 MPU.bankmsb[channel] = value;
2971 needremap = 1;
2973 else if (MPU.midicmd.peek(0) == 32)
2974 { // bank select LSB
2975 value = MPU.midicmd.peek(1);
2976 writelog(MIDILOG(1), "* BankSelectLSB channel %d to %d",
2977 channel, value);
2978 MPU.banklsb[channel] = value;
2979 needremap = 1;
2983 Bit8u temparray[256];
2984 i = 0;
2985 while (MPU.midicmd.empty() == 0)
2986 MPU.midicmd.get(&(temparray[i++]));
2988 writemidicommand(MPU.midicmd.currentcommand(), i, temparray);
2990 // if single command, revert to command mode
2991 if (MPU.singlecommand != 0)
2993 MPU.singlecommand = 0;
2994 // and trigger IRQ?
2995 // MPU.irqpending = 1;
2996 // BX_SB16_THIS devices->pic->trigger_irq(BX_SB16_IRQMPU);
2999 if ((force == 0) && (needremap == 1))
3000 // have to check the remap lists, and remap program change if necessary
3001 midiremapprogram(channel);
3004 // check if a program change has to be remapped, and do it if necessary
3006 void bx_sb16_c::midiremapprogram(int channel)
3008 int bankmsb,banklsb,program;
3009 Bit8u commandbytes[2];
3011 bankmsb = MPU.bankmsb[channel];
3012 banklsb = MPU.banklsb[channel];
3013 program = MPU.program[channel];
3015 for(int i = 0; i < EMUL.remaps; i++)
3017 if (((EMUL.remaplist[i].oldbankmsb == bankmsb) ||
3018 (EMUL.remaplist[i].oldbankmsb == 0xff)) &&
3019 ((EMUL.remaplist[i].oldbanklsb == banklsb) ||
3020 (EMUL.remaplist[i].oldbanklsb == 0xff)) &&
3021 ((EMUL.remaplist[i].oldprogch == program) ||
3022 (EMUL.remaplist[i].oldprogch == 0xff)))
3024 writelog(5, "Remapping instrument for channel %d", channel);
3025 if ((EMUL.remaplist[i].newbankmsb != bankmsb) &&
3026 (EMUL.remaplist[i].newbankmsb != 0xff))
3027 { // write control change bank msb
3028 MPU.bankmsb[channel] = EMUL.remaplist[i].newbankmsb;
3029 commandbytes[0] = 0;
3030 commandbytes[1] = EMUL.remaplist[i].newbankmsb;
3031 writemidicommand(0xb0 | channel, 2, commandbytes);
3033 if ((EMUL.remaplist[i].newbanklsb != banklsb) &&
3034 (EMUL.remaplist[i].newbanklsb != 0xff))
3035 { // write control change bank lsb
3036 MPU.banklsb[channel] = EMUL.remaplist[i].newbanklsb;
3037 commandbytes[0] = 32;
3038 commandbytes[1] = EMUL.remaplist[i].newbanklsb;
3039 writemidicommand(0xb0 | channel, 2, commandbytes);
3041 if ((EMUL.remaplist[i].newprogch != program) &&
3042 (EMUL.remaplist[i].newprogch != 0xff))
3043 { // write program change
3044 MPU.program[channel] = EMUL.remaplist[i].newprogch;
3045 commandbytes[0] = EMUL.remaplist[i].newprogch;
3046 writemidicommand(0xc0 | channel, 1, commandbytes);
3052 // convert a number into a delta time coded value
3053 int bx_sb16_c::converttodeltatime(Bit32u deltatime, Bit8u value[4])
3055 int i, count;
3056 Bit8u outbytes[4];
3058 count = 0;
3060 if (deltatime <= 0)
3062 count = 1;
3063 value[0] = 0;
3065 else
3067 while ((deltatime > 0) && (count < 4)) // split into parts
3068 { // of seven bits
3069 outbytes[count++] = deltatime & 0x7f;
3070 deltatime >>= 7;
3072 for (i=0; i<count; i++) // reverse order and
3073 value[i] = outbytes[count - i - 1] | 0x80; // set eighth bit on
3074 value[count - 1] &= 0x7f; // all but last byte
3076 return count;
3079 // write a delta time coded value to the midi file
3080 void bx_sb16_c::writedeltatime(Bit32u deltatime)
3082 Bit8u outbytes[4];
3084 int count = converttodeltatime(deltatime, outbytes);
3086 for (int i=0; i<count; i++)
3087 fputc(outbytes[i], MIDIDATA);
3091 // close the midi file, and set the track length accordingly
3093 void bx_sb16_c::finishmidifile()
3095 struct {
3096 Bit8u delta, statusbyte, metaevent, length;
3097 } metatrackend = { 0, 0xff, 0x2f, 0 };
3099 // Meta event track end (0xff 0x2f 0x00) plus leading delta time
3100 fwrite(&metatrackend, 1, sizeof metatrackend, MIDIDATA);
3102 Bit32u tracklen = ftell(MIDIDATA);
3103 if (tracklen < 0)
3104 BX_PANIC (("ftell failed in finishmidifile"));
3105 if (tracklen < 22)
3106 BX_PANIC (("finishmidifile with track length too short"));
3107 tracklen -= 22; // subtract the midi file and track header
3108 fseek(MIDIDATA, 22 - 4, SEEK_SET);
3109 // value has to be in big endian
3110 #ifdef BX_LITTLE_ENDIAN
3111 tracklen = (tracklen << 24) | (tracklen >> 24) |
3112 ((tracklen & 0x00ff0000) >> 8) |
3113 ((tracklen & 0x0000ff00) << 8);
3114 #endif
3115 fwrite(&tracklen, 4, 1, MIDIDATA);
3119 /* Handlers for the voc file output */
3121 // Write the header of the voc file.
3123 void bx_sb16_c::initvocfile()
3125 struct {
3126 char id[20];
3127 Bit16u headerlen; // All in LITTLE Endian!
3128 Bit16u version;
3129 Bit16u chksum;
3130 } vocheader =
3131 { "Creative Voice File",
3132 #ifdef BX_LITTLE_ENDIAN
3133 0x1a, 0x0114, 0x111f };
3134 #else
3135 0x1a00, 0x1401, 0x1f11 };
3136 #endif
3138 vocheader.id[19] = 26; // Replace string end with 26
3140 fwrite(&vocheader, 1, sizeof vocheader, WAVEDATA);
3143 // write one block to the voc file
3144 void bx_sb16_c::writevocblock(int block,
3145 Bit32u headerlen, Bit8u header[],
3146 Bit32u datalen, Bit8u data[])
3148 Bit32u i;
3150 if (block > 9)
3152 writelog(WAVELOG(3), "VOC Block %d not recognized, ignored.", block);
3153 return;
3156 fputc(block, WAVEDATA);
3158 i = headerlen + datalen;
3159 #ifdef BX_LITTLE_ENDIAN
3160 fwrite(&i, 1, 3, WAVEDATA); // write the length in 24-bit little endian
3161 #else
3162 Bit8u lengthbytes[3];
3163 lengthbytes[0] = i & 0xff; i >>= 8;
3164 lengthbytes[1] = i & 0xff; i >>= 8;
3165 lengthbytes[2] = i & 0xff;
3166 fwrite(lengthbytes, 1, 3, WAVEDATA);
3167 #endif
3168 writelog(WAVELOG(5), "Voc block %d; Headerlen %d; Datalen %d",
3169 block, headerlen, datalen);
3170 if (headerlen > 0)
3171 fwrite(header, 1, headerlen, WAVEDATA);
3172 if (datalen > 0)
3173 fwrite(data, 1, datalen, WAVEDATA);
3176 // close the voc file
3177 void bx_sb16_c::finishvocfile()
3179 fputc(0, WAVEDATA); // blocktype 0: end block
3182 // static IO port read callback handler
3183 // redirects to non-static class handler to avoid virtual functions
3185 Bit32u bx_sb16_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
3187 #if !BX_USE_SB16_SMF
3188 bx_sb16_c *class_ptr = (bx_sb16_c *) this_ptr;
3189 return class_ptr->read(address, io_len);
3192 Bit32u bx_sb16_c::read(Bit32u address, unsigned io_len)
3194 #else
3195 UNUSED(this_ptr);
3196 #endif // !BX_USE_SB16_SMF
3198 switch (address)
3200 // 2x0: FM Music Status Port
3201 // 2x8 and 388 are aliases
3202 case BX_SB16_IO + 0x00:
3203 case BX_SB16_IO + 0x08:
3204 case BX_SB16_IOADLIB + 0x00:
3205 return opl_status(0);
3207 // 2x1: reserved (w: FM Music Data Port)
3208 // 2x9 and 389 are aliases
3209 case BX_SB16_IO + 0x01:
3210 case BX_SB16_IO + 0x09:
3211 case BX_SB16_IOADLIB + 0x01:
3212 break;
3214 // 2x2: Advanced Music Status Port
3215 // or (for SBPro1) FM Music Status Port 2
3216 // 38a is an alias
3217 case BX_SB16_IO + 0x02:
3218 case BX_SB16_IOADLIB + 0x02:
3219 return opl_status(1);
3221 // 2x3: reserved (w: Adv. FM Music Data Port)
3222 // or (for SBPro1) FM Music Data Port 2
3223 // 38b is an alias
3224 case BX_SB16_IO + 0x03:
3225 case BX_SB16_IOADLIB + 0x03:
3226 break;
3228 // 2x4: reserved (w: Mixer Register Port)
3229 case BX_SB16_IO + 0x04:
3230 break;
3232 // 2x5: Mixer Data Port
3233 case BX_SB16_IO + 0x05:
3234 return mixer_readdata();
3236 // 2x6: reserved (w: DSP Reset)
3237 case BX_SB16_IO + 0x06:
3238 break;
3240 // 2x7: reserved
3241 case BX_SB16_IO + 0x07:
3242 break;
3244 // 2x8: FM Music Status Port (OPL-2)
3245 // handled above
3247 // 2x9: reserved (w: FM Music Data Port)
3248 // handled above
3250 // 2xa: DSP Read Data Port
3251 case BX_SB16_IO + 0x0a:
3252 return dsp_dataread();
3254 // 2xb: reserved
3255 case BX_SB16_IO + 0x0b:
3256 break;
3258 // 2xc: DSP Buffer Status Port
3259 case BX_SB16_IO + 0x0c:
3260 return dsp_bufferstatus();
3262 // 2xd: reserved
3263 case BX_SB16_IO + 0x0d:
3264 break;
3266 // 2xe: DSP Data Status Port
3267 case BX_SB16_IO + 0x0e:
3268 return dsp_status();
3270 // 2xf: DSP Acknowledge 16bit DMA IRQ
3271 case BX_SB16_IO + 0x0f:
3272 return dsp_irq16ack();
3274 // 3x0: MPU Data Port Read
3275 case BX_SB16_IOMPU + 0x00:
3276 return mpu_dataread();
3278 // 3x1: MPU Status Port
3279 case BX_SB16_IOMPU + 0x01:
3280 return mpu_status();
3282 // 3x2: reserved
3283 case BX_SB16_IOMPU + 0x02:
3284 break;
3286 // 3x3: *Emulator* Port
3287 case BX_SB16_IOMPU + 0x03:
3288 return emul_read();
3292 // If we get here, the port wasn't valid
3293 writelog(3, "Read access to 0x%04x: unsupported port!", address);
3295 return(0xff);
3298 // static IO port write callback handler
3299 // redirects to non-static class handler to avoid virtual functions
3301 void bx_sb16_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
3303 #if !BX_USE_SB16_SMF
3304 bx_sb16_c *class_ptr = (bx_sb16_c *) this_ptr;
3305 class_ptr->write(address, value, io_len);
3308 void bx_sb16_c::write(Bit32u address, Bit32u value, unsigned io_len)
3310 #else
3311 UNUSED(this_ptr);
3312 #endif // !BX_USE_SB16_SMF
3314 switch (address)
3316 // 2x0: FM Music Register Port
3317 // 2x8 and 388 are aliases
3318 case BX_SB16_IO + 0x00:
3319 case BX_SB16_IO + 0x08:
3320 case BX_SB16_IOADLIB + 0x00:
3321 opl_index(value, 0);
3322 return;
3324 // 2x1: FM Music Data Port
3325 // 2x9 and 389 are aliases
3326 case BX_SB16_IO + 0x01:
3327 case BX_SB16_IO + 0x09:
3328 case BX_SB16_IOADLIB + 0x01:
3329 opl_data(value, 0);
3330 return;
3332 // 2x2: Advanced FM Music Register Port
3333 // or (for SBPro1) FM Music Register Port 2
3334 // 38a is an alias
3335 case BX_SB16_IO + 0x02:
3336 case BX_SB16_IOADLIB + 0x02:
3337 opl_index(value, 1);
3338 return;
3340 // 2x3: Advanced FM Music Data Port
3341 // or (for SBPro1) FM Music Data Port 2
3342 // 38b is an alias
3343 case BX_SB16_IO + 0x03:
3344 case BX_SB16_IOADLIB + 0x03:
3345 opl_data(value, 1);
3346 return;
3348 // 2x4: Mixer Register Port
3349 case BX_SB16_IO + 0x04:
3350 mixer_writeregister(value);
3351 return;
3353 // 2x5: Mixer Data Portr,
3354 case BX_SB16_IO + 0x05:
3355 mixer_writedata(value);
3356 return;
3358 // 2x6: DSP Reset
3359 case BX_SB16_IO + 0x06:
3360 dsp_reset(value);
3361 return;
3363 // 2x7: reserved
3364 case BX_SB16_IO + 0x07:
3365 break;
3367 // 2x8: FM Music Register Port (OPL-2)
3368 // handled above
3370 // 2x9: FM Music Data Port
3371 // handled above
3373 // 2xa: reserved (r: DSP Data Port)
3374 case BX_SB16_IO + 0x0a:
3375 break;
3377 // 2xb: reserved
3378 case BX_SB16_IO + 0x0b:
3379 break;
3381 // 2xc: DSP Write Command/Data
3382 case BX_SB16_IO + 0x0c:
3383 dsp_datawrite(value);
3384 return;
3386 // 2xd: reserved
3387 case BX_SB16_IO + 0x0d:
3388 break;
3390 // 2xe: reserved (r: DSP Buffer Status)
3391 case BX_SB16_IO + 0x0e:
3392 break;
3394 // 2xf: reserved
3395 case BX_SB16_IO + 0x0f:
3396 break;
3398 // 3x0: MPU Command Port
3399 case BX_SB16_IOMPU + 0x00:
3400 mpu_datawrite(value);
3401 return;
3403 // 3x1: MPU Data Port
3404 case BX_SB16_IOMPU + 0x01:
3405 mpu_command(value);
3406 return;
3408 // 3x2: reserved
3409 case BX_SB16_IOMPU + 0x02:
3410 break;
3412 // 3x3: *Emulator* Port
3413 case BX_SB16_IOMPU + 0x03:
3414 emul_write(value);
3415 return;
3418 // if we arrive here, the port is unsupported
3419 writelog(3, "Write access to 0x%04x (value = 0x%02x): unsupported port!",
3420 address, value);
3423 void bx_sb16_c::writelog(int loglev, const char *str, ...)
3425 // append a line to the log file, if desired
3426 if (BX_SB16_THIS loglevel >= loglev)
3428 fprintf(LOGFILE, FMT_TICK, bx_pc_system.time_ticks());
3429 fprintf(LOGFILE, " (%d) ", loglev);
3430 va_list ap;
3431 va_start(ap, str);
3432 vfprintf(LOGFILE, str, ap);
3433 va_end(ap);
3434 fprintf(LOGFILE, "\n");
3435 fflush(LOGFILE);
3439 // the round-robin FIFO buffers of the SB16
3440 bx_sb16_buffer::bx_sb16_buffer()
3442 length = 0; // total bytes in buffer
3443 head = 0; // pointer to next slot available for new data
3444 tail = 0; // pointer to next slot to be read from
3445 buffer = NULL; // pointer to the actual data
3448 void bx_sb16_buffer::init(int bufferlen)
3450 if (buffer != NULL) // Was it initialized before?
3451 delete buffer;
3453 length = bufferlen;
3454 buffer = new Bit8u[length];
3455 if (buffer == NULL)
3456 length = 0; // This will be checked later
3458 reset();
3461 void bx_sb16_buffer::reset()
3463 head = 0; // Reset the pointers
3464 tail = 0;
3466 clearcommand(); // no current command set
3469 bx_sb16_buffer::~bx_sb16_buffer()
3471 if (buffer != NULL)
3472 delete [] buffer;
3474 buffer = NULL;
3475 length = 0;
3478 // Report how many bytes are available
3479 int bx_sb16_buffer::bytes(void)
3481 if (empty() != 0)
3482 return 0; // empty / not initialized
3484 int bytes = head - tail;
3485 if (bytes < 0) bytes += length;
3486 return (bytes);
3489 // This puts one byte into the buffer
3490 bx_bool bx_sb16_buffer::put(Bit8u data)
3492 if (full() != 0)
3493 return 0; // buffer full
3495 buffer[head++] = data; // Write data, and increase write pointer
3496 head %= length; // wrap it around so it stays inside the data
3498 return 1; // put was successful
3501 // This writes a formatted string to the buffer
3502 bx_bool bx_sb16_buffer::puts(const char *data, ...)
3504 if (data == NULL)
3505 return 0; // invalid string
3507 //char string[length];
3508 char *string;
3509 int index = 0;
3511 string = (char *) malloc(length);
3513 va_list ap;
3514 va_start(ap, data);
3515 vsprintf(string, data, ap);
3516 va_end(ap);
3518 if ((int) strlen(string) >= length)
3519 BX_PANIC(("bx_sb16_buffer: puts() too long!"));
3521 while (string[index] != 0)
3523 if (put((Bit8u) string[index]) == 0)
3524 return 0; // buffer full
3525 index++;
3527 return 1;
3530 // This returns if the buffer is full, i.e. if a put will fail
3531 bx_bool bx_sb16_buffer::full(void)
3533 if (length == 0)
3534 return 1; // not initialized
3536 if (((head + 1) % length) == tail)
3537 return 1; // buffer full
3539 return 0; // buffer has some space left
3542 // This reads the next available byte from the buffer
3543 bx_bool bx_sb16_buffer::get(Bit8u *data)
3545 if (empty() != 0)
3547 // Buffer is empty. Still, if it was initialized, return
3548 // the last byte again.
3549 if (length > 0)
3550 (*data) = buffer[ (tail - 1) % length ];
3551 return 0; // buffer empty
3554 (*data) = buffer[tail++]; // read data and increase read pointer
3555 tail %= length; // and wrap it around to stay inside the data
3557 return 1; // get was successful
3560 // Read a word in lo/hi order
3561 bx_bool bx_sb16_buffer::getw(Bit16u *data)
3563 Bit8u dummy;
3564 if (bytes() < 2)
3566 if (bytes() == 1)
3568 get(&dummy);
3569 *data = (Bit16u) dummy;
3571 else
3572 dummy = 0;
3573 return 0;
3575 get(&dummy);
3576 *data = (Bit16u) dummy;
3577 get(&dummy);
3578 *data |= ((Bit16u) dummy) << 8;
3579 return 1;
3582 // Read a word in hi/lo order
3583 bx_bool bx_sb16_buffer::getw1(Bit16u *data)
3585 Bit8u dummy;
3586 if (bytes() < 2)
3588 if (bytes() == 1)
3590 get(&dummy);
3591 *data = ((Bit16u) dummy) << 8;
3593 else
3594 dummy = 0;
3595 return 0;
3597 get(&dummy);
3598 *data = ((Bit16u) dummy) << 8;
3599 get(&dummy);
3600 *data |= (Bit16u) dummy;
3601 return 1;
3604 // This returns if the buffer is empty, i.e. if a get will fail
3605 bx_bool bx_sb16_buffer::empty(void)
3607 if (length == 0)
3608 return 1; // not inialized
3610 if (head == tail)
3611 return 1; // buffer empty
3613 return 0; // buffer contains data
3616 // Flushes the buffer
3617 void bx_sb16_buffer::flush(void)
3619 tail = head;
3620 return;
3623 // Peeks ahead in the buffer
3624 // Warning: No checking if result is valid. Must call bytes() to check that!
3625 Bit8u bx_sb16_buffer::peek(int offset)
3627 return buffer[(tail + offset) % length];
3630 // Set a new active command
3631 void bx_sb16_buffer::newcommand(Bit8u newcmd, int bytes)
3633 command = newcmd;
3634 havecommand = 1;
3635 bytesneeded = bytes;
3638 // Return the currently active command
3639 Bit8u bx_sb16_buffer::currentcommand(void)
3641 return command;
3644 // Clear the active command
3645 void bx_sb16_buffer::clearcommand(void)
3647 command = 0;
3648 havecommand = 0;
3649 bytesneeded = 0;
3652 // return if the command has received all necessary bytes
3653 bx_bool bx_sb16_buffer::commanddone(void)
3655 if (hascommand() == 0)
3656 return 0; // no command pending - not done then
3658 if (bytes() >= bytesneeded)
3659 return 1; // yes, it's done
3661 return 0; // no, it's not
3664 // return if there is a command pending
3665 bx_bool bx_sb16_buffer::hascommand(void)
3667 return havecommand;
3670 int bx_sb16_buffer::commandbytes(void)
3672 return bytesneeded;
3675 // The dummy output functions. They don't do anything
3676 bx_sound_output_c::bx_sound_output_c(bx_sb16_c *sb16)
3678 UNUSED(sb16);
3681 bx_sound_output_c::~bx_sound_output_c()
3685 int bx_sound_output_c::waveready()
3687 return BX_SOUND_OUTPUT_OK;
3690 int bx_sound_output_c::midiready()
3692 return BX_SOUND_OUTPUT_OK;
3695 int bx_sound_output_c::openmidioutput(char *device)
3697 UNUSED(device);
3698 return BX_SOUND_OUTPUT_OK;
3701 int bx_sound_output_c::sendmidicommand(int delta, int command, int length, Bit8u data[])
3703 UNUSED(delta);
3704 UNUSED(command);
3705 UNUSED(length);
3706 UNUSED(data);
3707 return BX_SOUND_OUTPUT_OK;
3710 int bx_sound_output_c::closemidioutput()
3712 return BX_SOUND_OUTPUT_OK;
3715 int bx_sound_output_c::openwaveoutput(char *device)
3717 UNUSED(device);
3718 return BX_SOUND_OUTPUT_OK;
3721 int bx_sound_output_c::startwaveplayback(int frequency, int bits, int stereo, int format)
3723 UNUSED(frequency);
3724 UNUSED(bits);
3725 UNUSED(stereo);
3726 UNUSED(format);
3727 return BX_SOUND_OUTPUT_OK;
3730 int bx_sound_output_c::sendwavepacket(int length, Bit8u data[])
3732 UNUSED(length);
3733 UNUSED(data);
3734 return BX_SOUND_OUTPUT_OK;
3737 int bx_sound_output_c::stopwaveplayback()
3739 return BX_SOUND_OUTPUT_OK;
3742 int bx_sound_output_c::closewaveoutput()
3744 return BX_SOUND_OUTPUT_OK;
3747 // runtime parameter handler
3748 Bit64s bx_sb16_c::sb16_param_handler(bx_param_c *param, int set, Bit64s val)
3750 if (set) {
3751 char pname[BX_PATHNAME_LEN];
3752 param->get_param_path(pname, BX_PATHNAME_LEN);
3753 if (!strcmp(pname, BXPN_SB16_DMATIMER)) {
3754 BX_SB16_THIS dmatimer = (Bit32u)val;
3755 } else if (!strcmp(pname, BXPN_SB16_LOGLEVEL)) {
3756 BX_SB16_THIS loglevel = (int)val;
3757 } else {
3758 BX_PANIC(("sb16_param_handler called with unexpected parameter '%s'", pname));
3761 return val;
3764 #endif /* if BX_SUPPORT_SB16 */