1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * Win32 interface
5 *
6 * Copyright 1997 Mathias Ortmann
7 * Copyright 1997-2001 Brian King
8 * Copyright 2000-2002 Bernd Roesch
9 */
10 
11 #define NATIVBUFFNUM 4
12 #define RECORDBUFFER 50 //survive 9 sec of blocking at 44100
13 
14 #include "sysconfig.h"
15 #include "sysdeps.h"
16 
17 #ifdef AHI
18 
19 #include <ctype.h>
20 #include <assert.h>
21 
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 
26 #include "options.h"
27 #include "audio.h"
28 #include "uae/memory.h"
29 #include "events.h"
30 #include "custom.h"
31 #include "newcpu.h"
32 #include "traps.h"
33 #include "sounddep/sound.h"
34 #include "dxwrap.h"
35 #include "parser.h"
36 #include "enforcer.h"
37 #include "ahidsound.h"
38 #include "picasso96.h"
39 #include "uaenative.h"
40 #include "uae/ahi.h"
41 
42 #ifdef FSUAE
43 #if defined(WINDOWS) && !defined(_WIN32)
44 #define _WIN32
45 #endif
46 #endif
47 
48 static long samples, playchannel, intcount;
49 static int record_enabled;
50 int ahi_on;
51 static uae_u8 *sndptrmax;
52 static uae_u8 soundneutral;
53 
54 //static LPSTR lpData,sndptrout;
55 extern uae_u32 chipmem_mask;
56 static uae_u8 *ahisndbuffer, *sndrecbuffer;
57 static int ahisndbufsize, *ahisndbufpt, ahitweak;;
58 int ahi_pollrate = 40;
59 
60 int sound_freq_ahi, sound_channels_ahi, sound_bits_ahi;
61 
62 static int vin, devicenum;
63 static int amigablksize;
64 
65 static DWORD sound_flushes2 = 0;
66 
67 #ifdef _WIN32
68 extern HWND hAmigaWnd;
69 #ifdef FSUAE
70 HWND hAmigaWnd;
71 #endif
72 #endif
73 
74 struct winuae	//this struct is put in a6 if you call
75 	//execute native function
76 {
77 #ifdef _WIN32
78 	HWND amigawnd;    //adress of amiga Window Windows Handle
79 #else
80     void *amigawnd; // dummy
81 #endif
82 	unsigned int changenum;   //number to detect screen close/open
83 	void *z3offset;    //the offset to add to acsess Z3 mem from Dll side
84 };
85 static struct winuae uaevar;
86 
uaenative_get_uaevar(void)87 void *uaenative_get_uaevar(void) {
88 #ifdef _WIN32
89     uaevar.amigawnd = hAmigaWnd;
90 #endif
91     uaevar.z3offset = get_real_address (0x10000000) - 0x10000000;
92     return &uaevar;
93 }
94 
ahi_close_sound(void)95 void ahi_close_sound (void)
96 {
97 	if (!ahi_on)
98 		return;
99 	ahi_on = 0;
100 	record_enabled = 0;
101 	ahisndbufpt = (int*)ahisndbuffer;
102 #if 0
103 	if (lpDSB2) {
104 		hr = IDirectSoundBuffer_Stop (lpDSB2);
105 		if(FAILED (hr))
106 			write_log (_T("AHI: SoundStop() failure: %s\n"), DXError (hr));
107 	} else {
108 		write_log (_T("AHI: Sound Stopped...\n"));
109 	}
110 
111 	if (lpDSB2)
112 		IDirectSoundBuffer_Release (lpDSB2);
113 	lpDSB2 = NULL;
114 	if (lpDSBprimary2)
115 		IDirectSoundBuffer_Release (lpDSBprimary2);
116 	lpDSBprimary2 = NULL;
117 	if (lpDS2)
118 		IDirectSound_Release (lpDS2);
119 	lpDS2 = NULL;
120 
121 	if (lpDSB2r)
122 		IDirectSoundCaptureBuffer_Release (lpDSB2r);
123 	lpDSB2r = NULL;
124 	if (lpDS2r)
125 		IDirectSound_Release (lpDS2r);
126 	lpDS2r = NULL;
127 #endif
128 	if (ahisndbuffer)
129 		free (ahisndbuffer);
130 	ahisndbuffer = NULL;
131 }
132 
ahi_updatesound(int force)133 void ahi_updatesound(int force)
134 {
135 #if 0
136 	HRESULT hr;
137 	DWORD pos;
138 	DWORD dwBytes1, dwBytes2;
139 	LPVOID dwData1, dwData2;
140 	static int oldpos;
141 
142 	if (sound_flushes2 == 1) {
143 		oldpos = 0;
144 		intcount = 1;
145 		INTREQ (0x8000 | 0x2000);
146 		hr = lpDSB2->Play (0, 0, DSBPLAY_LOOPING);
147 		if(hr == DSERR_BUFFERLOST) {
148 			lpDSB2->Restore ();
149 			hr = lpDSB2->Play (0, 0, DSBPLAY_LOOPING);
150 		}
151 	}
152 
153 	hr = lpDSB2->GetCurrentPosition (&pos, 0);
154 	if (hr != DSERR_BUFFERLOST) {
155 		pos -= ahitweak;
156 		if (pos < 0)
157 			pos += ahisndbufsize;
158 		if (pos >= ahisndbufsize)
159 			pos -= ahisndbufsize;
160 		pos = (pos / (amigablksize * 4)) * (amigablksize * 4);
161 		if (force == 1) {
162 			if (oldpos != pos) {
163 				intcount = 1;
164 				INTREQ (0x8000 | 0x2000);
165 				return; //to generate amiga ints every amigablksize
166 			} else {
167 				return;
168 			}
169 		}
170 	}
171 
172 	hr = lpDSB2->Lock (oldpos, amigablksize * 4, &dwData1, &dwBytes1, &dwData2, &dwBytes2, 0);
173 	if(hr == DSERR_BUFFERLOST) {
174 		write_log (_T("AHI: lostbuf %d %x\n"), pos, amigablksize);
175 		IDirectSoundBuffer_Restore (lpDSB2);
176 		hr = lpDSB2->Lock (oldpos, amigablksize * 4, &dwData1, &dwBytes1, &dwData2, &dwBytes2, 0);
177 	}
178 	if(FAILED(hr))
179 		return;
180 
181 	if (currprefs.sound_stereo_swap_ahi) {
182 		int i;
183 		uae_s16 *p = (uae_s16*)ahisndbuffer;
184 		for (i = 0; i < (dwBytes1 + dwBytes2) / 2; i += 2) {
185 			uae_s16 tmp;
186 			tmp = p[i + 0];
187 			p[i + 0] = p[i + 1];
188 			p[i + 1] = tmp;
189 		}
190 	}
191 
192 	memcpy (dwData1, ahisndbuffer, dwBytes1);
193 	if (dwData2)
194 		memcpy (dwData2, (uae_u8*)ahisndbuffer + dwBytes1, dwBytes2);
195 
196 	sndptrmax = ahisndbuffer + ahisndbufsize;
197 	ahisndbufpt = (int*)ahisndbuffer;
198 
199 	IDirectSoundBuffer_Unlock (lpDSB2, dwData1, dwBytes1, dwData2, dwBytes2);
200 
201 	oldpos += amigablksize * 4;
202 	if (oldpos >= ahisndbufsize)
203 		oldpos -= ahisndbufsize;
204 	if (oldpos != pos) {
205 		intcount = 1;
206 		INTREQ (0x8000 | 0x2000);
207 	}
208 #endif
209 }
210 
211 
ahi_finish_sound_buffer(void)212 void ahi_finish_sound_buffer (void)
213 {
214 #if 0
215 	sound_flushes2++;
216 	ahi_updatesound(2);
217 #endif
218 }
219 
ahi_init_record_win32(void)220 static int ahi_init_record_win32 (void)
221 {
222 #if 0
223 	HRESULT hr;
224 	DSCBUFFERDESC sound_buffer_rec;
225 	// Record begin
226 	hr = DirectSoundCaptureCreate (NULL, &lpDS2r, NULL);
227 	if (FAILED (hr)) {
228 		write_log (_T("AHI: DirectSoundCaptureCreate() failure: %s\n"), DXError (hr));
229 		record_enabled = -1;
230 		return 0;
231 	}
232 	memset (&sound_buffer_rec, 0, sizeof (DSCBUFFERDESC));
233 	sound_buffer_rec.dwSize = sizeof (DSCBUFFERDESC);
234 	sound_buffer_rec.dwBufferBytes = amigablksize * 4 * RECORDBUFFER;
235 	sound_buffer_rec.lpwfxFormat = &wavfmt;
236 	sound_buffer_rec.dwFlags = 0 ;
237 
238 	hr = IDirectSoundCapture_CreateCaptureBuffer (lpDS2r, &sound_buffer_rec, &lpDSB2r, NULL);
239 	if (FAILED (hr)) {
240 		write_log (_T("AHI: CreateCaptureSoundBuffer() failure: %s\n"), DXError(hr));
241 		record_enabled = -1;
242 		return 0;
243 	}
244 
245 	hr = IDirectSoundCaptureBuffer_Start (lpDSB2r, DSCBSTART_LOOPING);
246 	if (FAILED (hr)) {
247 		write_log (_T("AHI: DirectSoundCaptureBuffer_Start failed: %s\n"), DXError (hr));
248 		record_enabled = -1;
249 		return 0;
250 	}
251 	record_enabled = 1;
252 	write_log (_T("AHI: Init AHI Audio Recording \n"));
253 	return 1;
254 #endif
255     return 0;
256 }
257 
setvolume_ahi(int vol)258 void setvolume_ahi (int vol)
259 {
260 #if 0
261 	HRESULT hr;
262 	if (!lpDS2)
263 		return;
264 	hr = IDirectSoundBuffer_SetVolume (lpDSB2, vol);
265 	if (FAILED (hr))
266 		write_log (_T("AHI: SetVolume(%d) failed: %s\n"), vol, DXError (hr));
267 #endif
268 }
269 
ahi_init_sound(void)270 static int ahi_init_sound (void)
271 {
272 #if 0
273 	HRESULT hr;
274 	DSBUFFERDESC sound_buffer;
275 	DSCAPS DSCaps;
276 
277 	if (lpDS2)
278 		return 0;
279 
280 	enumerate_sound_devices ();
281 	wavfmt.wFormatTag = WAVE_FORMAT_PCM;
282 	wavfmt.nChannels = sound_channels_ahi;
283 	wavfmt.nSamplesPerSec = sound_freq_ahi;
284 	wavfmt.wBitsPerSample = sound_bits_ahi;
285 	wavfmt.nBlockAlign = wavfmt.wBitsPerSample / 8 * wavfmt.nChannels;
286 	wavfmt.nAvgBytesPerSec = wavfmt.nBlockAlign * sound_freq_ahi;
287 	wavfmt.cbSize = 0;
288 
289 	write_log (_T("AHI: Init AHI Sound Rate %d, Channels %d, Bits %d, Buffsize %d\n"),
290 		sound_freq_ahi, sound_channels_ahi, sound_bits_ahi, amigablksize);
291 
292 	if (!amigablksize)
293 		return 0;
294 	soundneutral = 0;
295 	ahisndbufsize = (amigablksize * 4) * NATIVBUFFNUM;  // use 4 native buffer
296 	ahisndbuffer = xmalloc (uae_u8, ahisndbufsize + 32);
297 	if (!ahisndbuffer)
298 		return 0;
299 	if (sound_devices[currprefs.win32_soundcard]->type != SOUND_DEVICE_DS)
300 		hr = DirectSoundCreate (NULL, &lpDS2, NULL);
301 	else
302 		hr = DirectSoundCreate (&sound_devices[currprefs.win32_soundcard]->guid, &lpDS2, NULL);
303 	if (FAILED (hr)) {
304 		write_log (_T("AHI: DirectSoundCreate() failure: %s\n"), DXError (hr));
305 		return 0;
306 	}
307 	memset (&sound_buffer, 0, sizeof (DSBUFFERDESC));
308 	sound_buffer.dwSize = sizeof (DSBUFFERDESC);
309 	sound_buffer.dwFlags = DSBCAPS_PRIMARYBUFFER;
310 	sound_buffer.dwBufferBytes = 0;
311 	sound_buffer.lpwfxFormat = NULL;
312 
313 	DSCaps.dwSize = sizeof(DSCAPS);
314 	hr = IDirectSound_GetCaps (lpDS2, &DSCaps);
315 	if (SUCCEEDED (hr)) {
316 		if (DSCaps.dwFlags & DSCAPS_EMULDRIVER)
317 			write_log (_T("AHI: Your DirectSound Driver is emulated via WaveOut - yuck!\n"));
318 	}
319 	if (FAILED (IDirectSound_SetCooperativeLevel (lpDS2, hMainWnd, DSSCL_PRIORITY)))
320 		return 0;
321 	hr = IDirectSound_CreateSoundBuffer (lpDS2, &sound_buffer, &lpDSBprimary2, NULL);
322 	if (FAILED (hr)) {
323 		write_log (_T("AHI: CreateSoundBuffer() failure: %s\n"), DXError(hr));
324 		return 0;
325 	}
326 	hr = IDirectSoundBuffer_SetFormat (lpDSBprimary2, &wavfmt);
327 	if (FAILED (hr)) {
328 		write_log (_T("AHI: SetFormat() failure: %s\n"), DXError (hr));
329 		return 0;
330 	}
331 	sound_buffer.dwBufferBytes = ahisndbufsize;
332 	sound_buffer.lpwfxFormat = &wavfmt;
333 	sound_buffer.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLVOLUME
334 		| DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE;
335 	sound_buffer.guid3DAlgorithm = GUID_NULL;
336 	hr = IDirectSound_CreateSoundBuffer (lpDS2, &sound_buffer, &lpDSB2, NULL);
337 	if (FAILED (hr)) {
338 		write_log (_T("AHI: CreateSoundBuffer() failure: %s\n"), DXError (hr));
339 		return 0;
340 	}
341 
342 	setvolume_ahi (0);
343 
344 	hr = IDirectSoundBuffer_GetFormat (lpDSBprimary2,&wavfmt,500,0);
345 	if (FAILED (hr)) {
346 		write_log (_T("AHI: GetFormat() failure: %s\n"), DXError (hr));
347 		return 0;
348 	}
349 
350 	ahisndbufpt =(int*)ahisndbuffer;
351 	sndptrmax = ahisndbuffer + ahisndbufsize;
352 	memset (ahisndbuffer,  soundneutral, amigablksize * 8);
353 	ahi_on = 1;
354 	return sound_freq_ahi;
355 #endif
356     return 0;
357 }
358 
ahi_open_sound(void)359 int ahi_open_sound (void)
360 {
361 	int rate;
362 
363 	uaevar.changenum++;
364 	if (!sound_freq_ahi)
365 		return 0;
366 	if (ahi_on)
367 		ahi_close_sound ();
368 	sound_flushes2 = 1;
369 	if ((rate = ahi_init_sound ()))
370 		return rate;
371 	return 0;
372 }
373 
374 
375 static void *bswap_buffer = NULL;
376 static uae_u32 bswap_buffer_size = 0;
377 static double syncdivisor;
378 
ahi_demux(TrapContext * context)379 uae_u32 REGPARAM2 ahi_demux (TrapContext *context)
380 {
381 	//use the extern int (6 #13)
382 	// d0 0=opensound      d1=unit d2=samplerate d3=blksize ret: sound frequency
383 	// d0 6=opensound_new  d1=unit d2=samplerate d3=blksize ret d4=channels d5=bits d6=zero: sound frequency
384 	// d0 1=closesound     d1=unit
385 	// d0 2=writesamples   d1=unit a0=addr     write blksize samples to card
386 	// d0 3=readsamples    d1=unit a0=addr     read samples from card ret: d0=samples read
387 	// make sure you have from amigaside blksize*4 mem alloced
388 	// d0=-1 no data available d0=-2 no recording open
389 	// d0 > 0 there are more blksize Data in the que
390 	// do the loop until d0 get 0
391 	// if d0 is greater than 200 bring a message
392 	// that show the user that data is lost
393 	// maximum blocksbuffered are 250 (8,5 sec)
394 	// d0 4=writeinterrupt d1=unit d0=0 no interrupt happen for this unit
395 	// d0=-2 no playing open
396 	//note units for now not support use only unit 0
397 	// d0 5=?
398 	// d0=10 get clipboard size  d0=size in bytes
399 	// d0=11 get clipboard data  a0=clipboarddata
400 	//Note: a get clipboard size must do before
401 	// d0=12 write clipboard data	 a0=clipboarddata
402 	// d0=13 setp96mouserate	 d1=hz value
403 	// d0=100 open dll		 d1=dll name in windows name conventions
404 	// d0=101 get dll function addr	 d1=dllhandle a0 function/var name
405 	// d0=102 exec dllcode		 a0=addr of function (see 101)
406 	// d0=103 close dll
407 	// d0=104 screenlost
408 	// d0=105 mem offset
409 	// d0=106 16Bit byteswap
410 	// d0=107 32Bit byteswap
411 	// d0=108 free swap array
412 	// d0=200 ahitweak		 d1=offset for dsound position pointer
413 
414 	int opcode = m68k_dreg (regs, 0);
415 	printf("AHI demux opcode %d\n", opcode);
416 
417 	switch (opcode)
418 	{
419 		uae_u32 src, num_vars;
420 		static int cap_pos, clipsize;
421 		static TCHAR *clipdat;
422 
423 	case 0:
424 		cap_pos = 0;
425 		sound_bits_ahi = 16;
426 		sound_channels_ahi = 2;
427 		sound_freq_ahi = m68k_dreg (regs, 2);
428 		amigablksize = m68k_dreg (regs, 3);
429 		sound_freq_ahi = ahi_open_sound();
430 		uaevar.changenum--;
431 		return sound_freq_ahi;
432 	case 6: /* new open function */
433 		cap_pos = 0;
434 		sound_freq_ahi = m68k_dreg (regs, 2);
435 		amigablksize = m68k_dreg (regs, 3);
436 		sound_channels_ahi = m68k_dreg (regs, 4);
437 		sound_bits_ahi = m68k_dreg (regs, 5);
438 		sound_freq_ahi = ahi_open_sound();
439 		uaevar.changenum--;
440 		return sound_freq_ahi;
441 
442 	case 1:
443 		ahi_close_sound();
444 		sound_freq_ahi = 0;
445 		return 0;
446 
447 	case 2:
448 		{
449 			int i;
450 			uaecptr addr = m68k_areg (regs, 0);
451 			for (i = 0; i < amigablksize * 4; i += 4)
452 				*ahisndbufpt++ = get_long (addr + i);
453 			ahi_finish_sound_buffer();
454 		}
455 		return amigablksize;
456 
457 	case 3:
458 		{
459 #if 0
460 			LPVOID pos1, pos2;
461 			DWORD t, cur_pos;
462 			uaecptr addr;
463 			HRESULT hr;
464 			int i, todo;
465 			DWORD byte1, byte2;
466 
467 			if (!ahi_on)
468 				return -2;
469 			if (record_enabled == 0)
470 				ahi_init_record_win32();
471 			if (record_enabled < 0)
472 				return -2;
473 			hr = lpDSB2r->GetCurrentPosition(&t, &cur_pos);
474 			if (FAILED(hr))
475 				return -1;
476 
477 			t =  amigablksize * 4;
478 			if (cap_pos <= cur_pos)
479 				todo = cur_pos - cap_pos;
480 			else
481 				todo = cur_pos + (RECORDBUFFER * t) - cap_pos;
482 			if (todo < t) //if no complete buffer ready exit
483 				return -1;
484 			hr = lpDSB2r->Lock(cap_pos, t, &pos1, &byte1, &pos2, &byte2, 0);
485 			if (FAILED(hr))
486 				return -1;
487 			if ((cap_pos + t) < (t * RECORDBUFFER))
488 				cap_pos = cap_pos + t;
489 			else
490 				cap_pos = 0;
491 			addr = m68k_areg (regs, 0);
492 			uae_u16 *sndbufrecpt = (uae_u16*)pos1;
493 			t /= 4;
494 			for (i = 0; i < t; i++) {
495 				uae_u32 s1, s2;
496 				if (currprefs.sound_stereo_swap_ahi) {
497 					s1 = sndbufrecpt[1];
498 					s2 = sndbufrecpt[0];
499 				} else {
500 					s1 = sndbufrecpt[0];
501 					s2 = sndbufrecpt[1];
502 				}
503 				sndbufrecpt += 2;
504 				put_long (addr, (s1 << 16) | s2);
505 				addr += 4;
506 			}
507 			t *= 4;
508 			lpDSB2r->Unlock(pos1, byte1, pos2, byte2);
509 			return (todo - t) / t;
510 #endif
511             return -1;
512 		}
513 
514 	case 4:
515 		{
516 			int i;
517 			if (!ahi_on)
518 				return -2;
519 			i = intcount;
520 			intcount = 0;
521 			return i;
522 		}
523 
524 	case 5:
525 		if (!ahi_on)
526 			return 0;
527 		ahi_updatesound ( 1 );
528 		return 1;
529 
530 	case 10:
531 #if 0
532 		if (OpenClipboard (0)) {
533 			clipdat = (TCHAR*)GetClipboardData (CF_UNICODETEXT);
534 			if (clipdat) {
535 				clipsize = _tcslen (clipdat);
536 				clipsize++;
537 				return clipsize;
538 			}
539 		}
540 #endif
541 		return 0;
542 
543 	case 11:
544 		{
545 #if 0
546 			put_byte (m68k_areg (regs, 0), 0);
547 			if (clipdat) {
548 				char *tmp = ua (clipdat);
549 				int i;
550 				for (i = 0; i < clipsize && i < strlen (tmp); i++)
551 					put_byte (m68k_areg (regs, 0) + i, tmp[i]);
552 				put_byte (m68k_areg (regs, 0) + clipsize - 1, 0);
553 				xfree (tmp);
554 			}
555 			CloseClipboard ();
556 #endif
557 		}
558 		return 0;
559 
560 	case 12:
561 		{
562 #if 0
563 			TCHAR *s = au ((char*)get_real_address (m68k_areg (regs, 0)));
564 			static LPTSTR p;
565 			int slen;
566 
567 			if (OpenClipboard (0)) {
568 				EmptyClipboard();
569 				slen = _tcslen (s);
570 				if (p)
571 					GlobalFree (p);
572 				p = (LPTSTR)GlobalAlloc (GMEM_MOVEABLE, (slen + 1) * sizeof (TCHAR));
573 				if (p) {
574 					TCHAR *p2 = (TCHAR*)GlobalLock (p);
575 					if (p2) {
576 						_tcscpy (p2, s);
577 						GlobalUnlock (p);
578 						SetClipboardData (CF_UNICODETEXT, p);
579 					}
580 				}
581 				CloseClipboard ();
582 			}
583 			xfree (s);
584 #endif
585 		}
586 		return 0;
587 
588 	case 13: /* HACK */
589 		{ //for higher P96 mouse draw rate
590 			set_picasso_hack_rate (m68k_dreg (regs, 1) * 2);
591 		} //end for higher P96 mouse draw rate
592 		return 0;
593 
594 	case 20:
595 		return enforcer_enable(m68k_dreg (regs, 1));
596 
597 	case 21:
598 		return enforcer_disable();
599 
600 	case 25:
601 		flushprinter ();
602 		return 0;
603 
604 	case 100:
605 		return uaenative_open_library (context, UNI_FLAG_COMPAT);
606 
607 	case 101:
608 		return uaenative_get_function (context, UNI_FLAG_COMPAT);
609 
610 	case 102:
611         return uaenative_call_function(context, UNI_FLAG_COMPAT);
612 
613 	case 103:
614 		return uaenative_close_library (context, UNI_FLAG_COMPAT);
615 
616 	case 104:        //screenlost
617 		{
618 			static int oldnum = 0;
619 			if (uaevar.changenum == oldnum)
620 				return 0;
621 			oldnum = uaevar.changenum;
622 			return 1;
623 		}
624 
625 #ifndef CPU_64_BIT
626 	case 105:   //returns memory offset
627 		return (uae_u32) get_real_address (0);
628 #endif
629 
630 #if defined(X86_MSVC_ASSEMBLY)
631 
632 	case 106:   //byteswap 16bit vars
633 		//a0 = start address
634 		//d1 = number of 16bit vars
635 		//returns address of new array
636 		src = m68k_areg (regs, 0);
637 		num_vars = m68k_dreg (regs, 1);
638 
639 		if (bswap_buffer_size < num_vars * 2) {
640 			bswap_buffer_size = (num_vars + 1024) * 2;
641 			free(bswap_buffer);
642 			bswap_buffer = (void*)malloc(bswap_buffer_size);
643 		}
644 		if (!bswap_buffer)
645 			return 0;
646 
647 		__asm {
648 			mov esi, dword ptr [src]
649 			mov edi, dword ptr [bswap_buffer]
650 			mov ecx, num_vars
651 
652 				mov ebx, ecx
653 				and ecx, 3
654 				je BSWAP_WORD_4X
655 
656 BSWAP_WORD_LOOP:
657 			mov ax, [esi]
658 			mov dl, al
659 				mov al, ah
660 				mov ah, dl
661 				mov [edi], ax
662 				add esi, 2
663 				add edi, 2
664 				loopne BSWAP_WORD_LOOP
665 
666 BSWAP_WORD_4X:
667 			mov ecx, ebx
668 				shr ecx, 2
669 				je BSWAP_WORD_END
670 BSWAP_WORD_4X_LOOP:
671 			mov ax, [esi]
672 			mov dl, al
673 				mov al, ah
674 				mov ah, dl
675 				mov [edi], ax
676 				mov ax, [esi+2]
677 			mov dl, al
678 				mov al, ah
679 				mov ah, dl
680 				mov [edi+2], ax
681 				mov ax, [esi+4]
682 			mov dl, al
683 				mov al, ah
684 				mov ah, dl
685 				mov [edi+4], ax
686 				mov ax, [esi+6]
687 			mov dl, al
688 				mov al, ah
689 				mov ah, dl
690 				mov [edi+6], ax
691 				add esi, 8
692 				add edi, 8
693 				loopne BSWAP_WORD_4X_LOOP
694 BSWAP_WORD_END:
695 		}
696 		return (uae_u32) bswap_buffer;
697 
698 	case 107:   //byteswap 32bit vars - see case 106
699 		//a0 = start address
700 		//d1 = number of 32bit vars
701 		//returns address of new array
702 		src = m68k_areg (regs, 0);
703 		num_vars = m68k_dreg (regs, 1);
704 		if (bswap_buffer_size < num_vars * 4) {
705 			bswap_buffer_size = (num_vars + 16384) * 4;
706 			free(bswap_buffer);
707 			bswap_buffer = (void*)malloc(bswap_buffer_size);
708 		}
709 		if (!bswap_buffer)
710 			return 0;
711 		__asm {
712 			mov esi, dword ptr [src]
713 			mov edi, dword ptr [bswap_buffer]
714 			mov ecx, num_vars
715 
716 				mov ebx, ecx
717 				and ecx, 3
718 				je BSWAP_DWORD_4X
719 
720 BSWAP_DWORD_LOOP:
721 			mov eax, [esi]
722 			bswap eax
723 				mov [edi], eax
724 				add esi, 4
725 				add edi, 4
726 				loopne BSWAP_DWORD_LOOP
727 
728 BSWAP_DWORD_4X:
729 			mov ecx, ebx
730 				shr ecx, 2
731 				je BSWAP_DWORD_END
732 BSWAP_DWORD_4X_LOOP:
733 			mov eax, [esi]
734 			bswap eax
735 				mov [edi], eax
736 				mov eax, [esi+4]
737 			bswap eax
738 				mov [edi+4], eax
739 				mov eax, [esi+8]
740 			bswap eax
741 				mov [edi+8], eax
742 				mov eax, [esi+12]
743 			bswap eax
744 				mov [edi+12], eax
745 				add esi, 16
746 				add edi, 16
747 				loopne BSWAP_DWORD_4X_LOOP
748 
749 BSWAP_DWORD_END:
750 		}
751 		return (uae_u32) bswap_buffer;
752 
753 	case 108: //frees swap array
754 		bswap_buffer_size = 0;
755 		free (bswap_buffer);
756 		bswap_buffer = NULL;
757 		return 0;
758 
759 	case 110:
760 		{
761 			LARGE_INTEGER p;
762 			QueryPerformanceFrequency (&p);
763 			put_long (m68k_areg (regs, 0), p.HighPart);
764 			put_long (m68k_areg (regs, 0) + 4, p.LowPart);
765 		}
766 		return 1;
767 
768 	case 111:
769 		{
770 			LARGE_INTEGER p;
771 			QueryPerformanceCounter (&p);
772 			put_long (m68k_areg (regs, 0), p.HighPart);
773 			put_long (m68k_areg (regs, 0) + 4, p.LowPart);
774 		}
775 		return 1;
776 
777 #endif
778 
779 	case 200:
780 		ahitweak = m68k_dreg (regs, 1);
781 		ahi_pollrate = m68k_dreg (regs, 2);
782 		if (ahi_pollrate < 10)
783 			ahi_pollrate = 10;
784 		if (ahi_pollrate > 60)
785 			ahi_pollrate = 60;
786 		return 1;
787 
788 	default:
789 		return 0x12345678;     // Code for not supported function
790 	}
791 }
792 
793 #endif // AHI
794