/*
 * UAE - The Un*x Amiga Emulator
 * 
 * Win32 interface
 *
 * Copyright 1997 Mathias Ortmann
 * Copyright 1997-2001 Brian King
 * Copyright 2000-2002 Bernd Roesch
 */
    
#define NATIVBUFFNUM 4
#define RECORDBUFFER 50 //survive 9 sec of blocking at 44100

#include "sysconfig.h"

#if defined(AHI)

#include <ctype.h>
#include <assert.h>

#include <windows.h>
#include <stdlib.h>
#include <stdarg.h>
#include <dsound.h>
#include <stdio.h>

#include "sysdeps.h"
#include "options.h"
#include "memory.h"
#include "events.h"
#include "custom.h"
#include "newcpu.h"
#include "traps.h"
#include "od-win32/win32.h"
#include "picasso96_win.h"
#include "sounddep/sound.h"
#include "dxwrap.h"
#include "win32.h"
#include "parser.h"
#include "enforcer.h"
#include "ahidsound.h"

static long samples, playchannel, intcount;
static int record_enabled;
int ahi_on;
static char *sndptrmax, soundneutral, sndptr;

static LPSTR lpData,sndptrout;
extern uae_u32 chipmem_mask;
unsigned int *sndbufrecpt;
static char *ahisndbuffer,*sndrecbuffer; 
static int ahisndbufsize,*ahisndbufpt,ahitweak;;
int ahi_pollrate = 40;

int sound_freq_ahi, sound_channels_ahi, sound_bits_ahi;

static int vin,devicenum;
static int amigablksize;

static DWORD sound_flushes2 = 0;

extern HWND hAmigaWnd;

static LPDIRECTSOUND lpDS2 = NULL;
static LPDIRECTSOUNDBUFFER lpDSBprimary2 = NULL;
static LPDIRECTSOUNDBUFFER lpDSB2 = NULL;
static LPDIRECTSOUNDNOTIFY lpDSBN2 = NULL;

// for record
static LPDIRECTSOUNDCAPTURE lpDS2r = NULL;
static LPDIRECTSOUNDCAPTUREBUFFER lpDSBprimary2r = NULL;
static LPDIRECTSOUNDCAPTUREBUFFER lpDSB2r = NULL;

struct winuae	//this struct is put in a6 if you call 
		//execute native function
{
    HWND amigawnd;    //adress of amiga Window Windows Handle
    unsigned int changenum;   //number to detect screen close/open 
    unsigned int z3offset;    //the offset to add to acsess Z3 mem from Dll side
};
static struct winuae uaevar;
static struct winuae *a6;

#if defined(X86_MSVC_ASSEMBLY)

#define CREATE_NATIVE_FUNC_PTR2 uae_u32 (* native_func)( uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, \
	uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32,uae_u32,uae_u32)
#define SET_NATIVE_FUNC2(x) native_func = (uae_u32 (*)(uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32,uae_u32,uae_u32))(x)
#define CALL_NATIVE_FUNC2( d1,d2,d3,d4,d5,d6,d7,a1,a2,a3,a4,a5,a6,a7) if(native_func) return native_func( d1,d2,d3,d4,d5,d6,d7,a1,a2,a3,a4,a5,a6,a7,regs_ )

static uae_u32 REGPARAM2 emulib_ExecuteNativeCode2 (TrapContext *context)
{ 
    unsigned int espstore;
    uae_u8* object_UAM = (uae_u8*) m68k_areg(&context->regs, 0);
    uae_u32 d1 = m68k_dreg(&context->regs, 1);
    uae_u32 d2 = m68k_dreg(&context->regs, 2);
    uae_u32 d3 = m68k_dreg(&context->regs, 3);
    uae_u32 d4 = m68k_dreg(&context->regs, 4);
    uae_u32 d5 = m68k_dreg(&context->regs, 5);
    uae_u32 d6 = m68k_dreg(&context->regs, 6);
    uae_u32 d7 = m68k_dreg(&context->regs, 7);
    uae_u32 a1 = m68k_areg(&context->regs, 1);
    uae_u32 a2 = m68k_areg(&context->regs, 2);
    uae_u32 a3 = m68k_areg(&context->regs, 3);
    uae_u32 a4 = m68k_areg(&context->regs, 4);
    uae_u32 a5 = m68k_areg(&context->regs, 5);
    uae_u32 a7 = m68k_areg(&context->regs, 7);
    uae_u32 regs_ = (uae_u32)&context->regs;
    CREATE_NATIVE_FUNC_PTR2;
    uaevar.z3offset = (uae_u32)(get_real_address (0x10000000) - 0x10000000);
    uaevar.amigawnd = hAmigaWnd;
    a6 = &uaevar;    
    if(object_UAM)  {
	SET_NATIVE_FUNC2(object_UAM);
    __asm
	{   mov espstore,esp
	    push regs_
	    push a7
	    push a6
	    push a5
	    push a4
	    push a3
	    push a2
	    push a1
	    push d7
	    push d6
	    push d5
	    push d4
	    push d3
	    push d2
	    push d1
	    call native_func
	    mov esp,espstore
	}
	//CALL_NATIVE_FUNC2( d1, d2,d3, d4, d5, d6, d7, a1, a2, a3, a4 , a5 , a6 , a7);
    } else {
    	return 0;
    }
}

#endif

void ahi_close_sound (void)
{
    HRESULT hr = DS_OK;
   
    if (!ahi_on)
	return;
    ahi_on = 0;
    record_enabled = 0;
    ahisndbufpt = (int*) ahisndbuffer;

    if (lpDSB2) {
	hr = IDirectSoundBuffer_Stop (lpDSB2);
	if(FAILED(hr))
	    write_log( "AHI: SoundStop() failure: %s\n", DXError(hr));
    } else {
	write_log( "AHI: Sound Stopped...\n" );
    }

    if (lpDSB2)
	IDirectSoundBuffer_Release (lpDSB2);
    lpDSB2 = NULL;
    if (lpDSBprimary2)
	IDirectSoundBuffer_Release (lpDSBprimary2);
    lpDSBprimary2 = NULL;
    if (lpDS2)
	IDirectSound_Release (lpDS2);
    lpDS2 = NULL;
    
    if (lpDSB2r)
	IDirectSoundCaptureBuffer_Release (lpDSB2r);
    lpDSB2r = NULL;
    if (lpDS2r)
	IDirectSound_Release (lpDS2r);
    lpDS2r = NULL;
    if (ahisndbuffer)
	free(ahisndbuffer);
    ahisndbuffer = NULL;
}

void ahi_updatesound(int force)
{
    HRESULT hr;
    int pos;
    unsigned int dwBytes1, dwBytes2;
    LPVOID dwData1, dwData2;
    static int oldpos;

    if(sound_flushes2 == 1) {
	oldpos = 0;
	intcount = 1;
	INTREQ(0x8000 | 0x2000);
	hr = IDirectSoundBuffer_Play(lpDSB2, 0, 0, DSBPLAY_LOOPING);
	if(hr == DSERR_BUFFERLOST) {
	    IDirectSoundBuffer_Restore(lpDSB2);
	    hr = IDirectSoundBuffer_Play(lpDSB2, 0, 0, DSBPLAY_LOOPING);
	}
    }

    hr = IDirectSoundBuffer_GetCurrentPosition(lpDSB2, &pos, 0);
    if(hr != DSERR_BUFFERLOST) {
	pos -= ahitweak;
	if (pos < 0)
	    pos += ahisndbufsize;                  
	if (pos >= ahisndbufsize)
	    pos -= ahisndbufsize;
	pos = (pos / (amigablksize * 4)) * (amigablksize * 4);
	if (force == 1) {
	    if (oldpos != pos) {
		intcount = 1;
		INTREQ(0x8000 | 0x2000);
		return; //to generate amiga ints every amigablksize
	    } else {
		return;
	    }
	}
    }

    hr = IDirectSoundBuffer_Lock(lpDSB2, oldpos, amigablksize * 4, &dwData1, &dwBytes1, &dwData2, &dwBytes2, 0);
    if(hr == DSERR_BUFFERLOST) {
	write_log("AHI: lostbuf %d %x\n", pos, amigablksize);
	IDirectSoundBuffer_Restore(lpDSB2);
	hr = IDirectSoundBuffer_Lock(lpDSB2, oldpos, amigablksize * 4, &dwData1, &dwBytes1, &dwData2, &dwBytes2, 0);
    }
    if(FAILED(hr))
	return;

    if (currprefs.sound_stereo_swap_ahi) {
	int i;
	uae_s16 *p = (uae_s16*)ahisndbuffer;
	for (i = 0; i < (dwBytes1 + dwBytes2) / 2; i += 2) {
	    uae_s16 tmp;
	    tmp = p[i + 0];
	    p[i + 0] = p[i + 1];
	    p[i + 1] = tmp;
	}
    }

    memcpy(dwData1, ahisndbuffer, dwBytes1);
    if (dwData2)
	memcpy(dwData2, (uae_u8*)ahisndbuffer + dwBytes1, dwBytes2);

    sndptrmax = ahisndbuffer + ahisndbufsize;
    ahisndbufpt = (int*)ahisndbuffer;
 
    IDirectSoundBuffer_Unlock(lpDSB2, dwData1, dwBytes1, dwData2, dwBytes2); 

    oldpos += amigablksize * 4;
    if (oldpos >= ahisndbufsize)
	oldpos -= ahisndbufsize;
    if (oldpos != pos) {
	intcount = 1;
	INTREQ(0x8000 | 0x2000);
    }
}


void ahi_finish_sound_buffer( void )
{
    sound_flushes2++;
    ahi_updatesound(2);
}

extern GUID sound_device_guid[];

static WAVEFORMATEX wavfmt;

static int ahi_init_record_win32 (void)
{
    HRESULT hr;
    DSCBUFFERDESC sound_buffer_rec;
    // Record begin
    hr = DirectSoundCaptureCreate(NULL, &lpDS2r, NULL);
    if (FAILED(hr)) {
	write_log( "AHI: DirectSoundCaptureCreate() failure: %s\n", DXError(hr));
	record_enabled = -1;
	return 0;
    }
    memset (&sound_buffer_rec, 0, sizeof(DSCBUFFERDESC));
    sound_buffer_rec.dwSize = sizeof(DSCBUFFERDESC);
    sound_buffer_rec.dwBufferBytes = amigablksize * 4 * RECORDBUFFER;
    sound_buffer_rec.lpwfxFormat = &wavfmt;
    sound_buffer_rec.dwFlags = 0 ;
  
    hr = IDirectSoundCapture_CreateCaptureBuffer(lpDS2r, &sound_buffer_rec, &lpDSB2r, NULL);
    if (FAILED(hr)) {
        write_log ("AHI: CreateCaptureSoundBuffer() failure: %s\n", DXError(hr));
        record_enabled = -1;
	return 0;
    }

    hr = IDirectSoundCaptureBuffer_Start(lpDSB2r, DSCBSTART_LOOPING);
    if (FAILED(hr)) {
	write_log("AHI: DirectSoundCaptureBuffer_Start failed: %s\n", DXError(hr));
	record_enabled = -1;
	return 0;
    }
    record_enabled = 1;
    write_log("AHI: Init AHI Audio Recording \n");
    return 1;
}

void setvolume_ahi (LONG vol)
{
    HRESULT hr;
    if (!lpDS2)
	return;
    hr = IDirectSoundBuffer_SetVolume (lpDSB2, vol);
    if (FAILED(hr))
        write_log ("AHI: SetVolume(%d) failed: %s\n", vol, DXError (hr));
}

static int ahi_init_sound_win32 (void)
{
    HRESULT hr;
    DSBUFFERDESC sound_buffer;
    DSCAPS DSCaps;
    
    if (lpDS2)
	return 0;

    enumerate_sound_devices (0);
    wavfmt.wFormatTag = WAVE_FORMAT_PCM;
    wavfmt.nChannels = sound_channels_ahi;
    wavfmt.nSamplesPerSec = sound_freq_ahi;
    wavfmt.wBitsPerSample = sound_bits_ahi;
    wavfmt.nBlockAlign = wavfmt.wBitsPerSample / 8 * wavfmt.nChannels;
    wavfmt.nAvgBytesPerSec = wavfmt.nBlockAlign * sound_freq_ahi;
    wavfmt.cbSize = 0;

    soundneutral = 0;
    ahisndbufsize = (amigablksize * 4) * NATIVBUFFNUM;  // use 4 native buffer
    ahisndbuffer = malloc(ahisndbufsize + 32);
    if (!ahisndbuffer)
	return 0;
    hr = DirectSoundCreate(&sound_device_guid[currprefs.win32_soundcard], &lpDS2, NULL);
    if (FAILED(hr)) {
	write_log( "AHI: DirectSoundCreate() failure: %s\n", DXError(hr));
	return 0;
    }
    memset (&sound_buffer, 0, sizeof(DSBUFFERDESC));
    sound_buffer.dwSize = sizeof(DSBUFFERDESC);
    sound_buffer.dwFlags = DSBCAPS_PRIMARYBUFFER;
    sound_buffer.dwBufferBytes = 0;
    sound_buffer.lpwfxFormat = NULL;

    DSCaps.dwSize = sizeof(DSCAPS);
    hr = IDirectSound_GetCaps(lpDS2, &DSCaps);
    if(SUCCEEDED(hr)) {
	if(DSCaps.dwFlags & DSCAPS_EMULDRIVER)
	    write_log( "AHI: Your DirectSound Driver is emulated via WaveOut - yuck!\n" );
    }
    if FAILED(IDirectSound_SetCooperativeLevel(lpDS2, hMainWnd, DSSCL_PRIORITY))
	return 0;
    hr = IDirectSound_CreateSoundBuffer(lpDS2, &sound_buffer, &lpDSBprimary2, NULL);
    if(FAILED(hr)) {
	write_log("AHI: CreateSoundBuffer() failure: %s\n", DXError(hr));
	return 0;
    }
    hr = IDirectSoundBuffer_SetFormat(lpDSBprimary2, &wavfmt);
    if(FAILED(hr)) {
	write_log( "AHI: SetFormat() failure: %s\n", DXError(hr));
	return 0;
    }
    sound_buffer.dwBufferBytes = ahisndbufsize;
    sound_buffer.lpwfxFormat = &wavfmt;
    sound_buffer.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLVOLUME
	| DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE;
    sound_buffer.guid3DAlgorithm = GUID_NULL;
    hr = IDirectSound_CreateSoundBuffer(lpDS2, &sound_buffer, &lpDSB2, NULL);
    if (FAILED(hr)) {
	write_log("AHI: CreateSoundBuffer() failure: %s\n", DXError(hr));
	return 0;
    }

    setvolume_ahi (0);

    hr = IDirectSoundBuffer_GetFormat(lpDSBprimary2,&wavfmt,500,0);
    if(FAILED(hr)) {
	write_log("AHI: GetFormat() failure: %s\n", DXError(hr));
	return 0;
    }

    ahisndbufpt =(int*)ahisndbuffer;
    sndptrmax = ahisndbuffer + ahisndbufsize;
    memset(ahisndbuffer,  soundneutral, amigablksize * 8);
    write_log("AHI: Init AHI Sound Rate %d, Channels %d, Bits %d, Buffsize %d\n",
	sound_freq_ahi, sound_channels_ahi, sound_bits_ahi, amigablksize); 
    ahi_on = 1;
    return sound_freq_ahi;
}

int ahi_open_sound (void)
{  
    int rate;

    uaevar.changenum++;
    if (!sound_freq_ahi)
	return 0;
    if (ahi_on)
	ahi_close_sound();
    sound_flushes2 = 1;
    if ((rate = ahi_init_sound_win32 ()))
	return rate;
    return 0;
} 


static void *bswap_buffer = NULL;
static uae_u32 bswap_buffer_size = 0;
static double syncdivisor;

uae_u32 REGPARAM2 ahi_demux (TrapContext *context)
{
//use the extern int (6 #13)  
// d0 0=opensound      d1=unit d2=samplerate d3=blksize ret: sound frequency
// d0 6=opensound_new  d1=unit d2=samplerate d3=blksize ret d4=channels d5=bits d6=zero: sound frequency
// d0 1=closesound     d1=unit
// d0 2=writesamples   d1=unit a0=addr     write blksize samples to card     
// d0 3=readsamples    d1=unit a0=addr     read samples from card ret: d0=samples read
	// make sure you have from amigaside blksize*4 mem alloced 
	// d0=-1 no data available d0=-2 no recording open
	// d0 > 0 there are more blksize Data in the que
	// do the loop until d0 get 0
	// if d0 is greater than 200 bring a message
	// that show the user that data is lost
	// maximum blocksbuffered are 250 (8,5 sec)
// d0 4=writeinterrupt d1=unit d0=0 no interrupt happen for this unit
	// d0=-2 no playing open
	//note units for now not support use only unit 0
// d0 5=?
    // d0=10 get clipboard size  d0=size in bytes
// d0=11 get clipboard data  a0=clipboarddata
				  //Note: a get clipboard size must do before
// d0=12 write clipboard data	 a0=clipboarddata
// d0=13 setp96mouserate	 d1=hz value
// d0=100 open dll		 d1=dll name in windows name conventions
// d0=101 get dll function addr	 d1=dllhandle a0 function/var name 
// d0=102 exec dllcode		 a0=addr of function (see 101)
// d0=103 close dll
// d0=104 screenlost
// d0=105 mem offset
// d0=106 16Bit byteswap
// d0=107 32Bit byteswap
// d0=108 free swap array
// d0=200 ahitweak		 d1=offset for dsound position pointer

    int opcode = m68k_dreg (&context->regs, 0);
    switch (opcode)
    {
	uae_u32 src, num_vars;
	static int cap_pos, clipsize;
	static LPTSTR clipdat;

	case 0:
	    cap_pos = 0;
	    sound_bits_ahi = 16;
	    sound_channels_ahi = 2;
	    sound_freq_ahi = m68k_dreg (&context->regs, 2);
	    amigablksize = m68k_dreg (&context->regs, 3);
	    sound_freq_ahi = ahi_open_sound();
	    uaevar.changenum--;
	return sound_freq_ahi;
	case 6: /* new open function */
	    cap_pos = 0;
	    sound_freq_ahi = m68k_dreg (&context->regs, 2);
	    amigablksize = m68k_dreg (&context->regs, 3);
	    sound_channels_ahi = m68k_dreg (&context->regs, 4);
	    sound_bits_ahi = m68k_dreg (&context->regs, 5);
	    sound_freq_ahi = ahi_open_sound();
	    uaevar.changenum--;
	return sound_freq_ahi;

	case 1:
	    ahi_close_sound();
	    sound_freq_ahi = 0;
	return 0;

	case 2:
	{
	    int i;
	    uaecptr addr = m68k_areg (&context->regs, 0);
	    for (i = 0; i < amigablksize * 4; i += 4)
		*ahisndbufpt++ = get_long(addr + i);
	    ahi_finish_sound_buffer();
	}
	return amigablksize;

	case 3:
	{
	    LPTSTR pos1,pos2;
	    uaecptr addr;
	    HRESULT hr;
	    int i, t, todo, byte1, byte2, cur_pos;

	    if (!ahi_on)
		return -2;
	    if (record_enabled == 0)
		ahi_init_record_win32();
	    if (record_enabled < 0)
		return -2;
	    hr = IDirectSoundCaptureBuffer_GetCurrentPosition(lpDSB2r, &t, &cur_pos);
	    if (FAILED(hr))
		return -1;

	    t =  amigablksize * 4;
	    if (cap_pos <= cur_pos)
		todo = cur_pos - cap_pos;
	    else
		todo = cur_pos + (RECORDBUFFER * t) - cap_pos;
	    if (todo < t) //if no complete buffer ready exit
		return -1;
	    hr = IDirectSoundCaptureBuffer_Lock(lpDSB2r, cap_pos, t, &pos1, &byte1, &pos2, &byte2, 0);
	    if (FAILED(hr))
		return -1;
	    if ((cap_pos + t) < (t * RECORDBUFFER))
		cap_pos = cap_pos + t;
	    else
		cap_pos = 0;  
	    addr = m68k_areg (&context->regs, 0);
	    sndbufrecpt = (unsigned int*)pos1;
	    t /= 4;
	    for (i = 0; i < t; i++) {
		put_long(addr, *sndbufrecpt++);
		addr += 4;
	    }
	    t *= 4;
	    IDirectSoundCaptureBuffer_Unlock(lpDSB2r, pos1, byte1, pos2, byte2);
	    return (todo - t) / t;
	}

	case 4:
	{
	    int i;
	    if (!ahi_on)
		return -2;
	    i = intcount;
	    intcount = 0;
	    return i;
	}

	case 5:
	    if (!ahi_on)
		return 0;
	    ahi_updatesound ( 1 );
	return 1;

	case 10:
	    if (OpenClipboard(0)) {
		clipdat=GetClipboardData(CF_TEXT);
		if (clipdat) {
		    clipsize=strlen(clipdat);
		    clipsize++;
		    return clipsize;
		}
	    }
	return 0;

	case 11:
	{
	    int i;
	    for (i = 0; i < clipsize; i++)
		put_byte(m68k_areg (&context->regs, 0) + i, clipdat[i]);
	    CloseClipboard();
	}
	return 0;

	case 12:
	{
	    uae_u8 *addr = get_real_address (m68k_areg (&regs, 0));
	    static LPTSTR p;
	    int slen;
	    LPTSTR p2;

	    if (OpenClipboard (0)) {
		EmptyClipboard();
		slen = strlen(addr);
		if (p)
		    GlobalFree (p);
		p = GlobalAlloc (GMEM_MOVEABLE,slen+2);
		if (p) {
		    p2 = GlobalLock (p);
		    if (p2) {
			memcpy (p2, addr, slen);
			p2[slen] = 0;
			GlobalUnlock (p);
			SetClipboardData (CF_TEXT,p2);
		    }
                }
		CloseClipboard ();
	    }
	}
	return 0;

	case 13: /* HACK */
	{ //for higher P96 mouse draw rate
	    extern int p96hack_vpos2,hack_vpos,p96refresh_active;
	    extern uae_u16 vtotal;
	    extern unsigned int new_beamcon0;
	    p96hack_vpos2 = 0;
	    if (m68k_dreg (&context->regs, 1) > 0)
	    p96hack_vpos2 = 15625 / m68k_dreg (&context->regs, 1);
	    p96refresh_active=1;
	    picasso_refresh (0);
	} //end for higher P96 mouse draw rate
	return 0;

	case 20:
	return enforcer_enable(m68k_dreg (&context->regs, 1));

	case 21:
	return enforcer_disable();

	case 25:
	    flushprinter ();
	return 0;

#if defined(X86_MSVC_ASSEMBLY)

	case 100: // open dll
	{
	    char *dllname;
	    uae_u32 result;
	    dllname = (char *) m68k_areg (&context->regs, 0);
	    dllname = (char *)get_real_address ((uae_u32)dllname);
	    result=(uae_u32) LoadLibrary(dllname);
	    write_log("%s windows dll/alib loaded at %d (0 mean failure)\n",dllname,result); 
	    syncdivisor = (3580000.0 * CYCLE_UNIT) / (double)syncbase;
	    return result;
	}

	case 101:	//get dll label
	{
	    HMODULE m;
	    char *funcname;
	    m = (HMODULE) m68k_dreg (&context->regs, 1);
	    funcname = (char *)m68k_areg (&context->regs, 0);
	    funcname = (char *)get_real_address ((uae_u32)funcname);
	    return (uae_u32) GetProcAddress(m,funcname);
	}

	case 102:	//execute native code
	{
	    uae_u32 ret;
	    unsigned long rate1;
	    double v;
	    rate1 = read_processor_time(); 
	    ret = emulib_ExecuteNativeCode2 (context);
	    rate1 = read_processor_time() - rate1;
	    v = syncdivisor * rate1;
	    if (v > 0) {
		if (v > 1000000 * CYCLE_UNIT)
		    v = 1000000 * CYCLE_UNIT;
		do_extra_cycles((unsigned long)(syncdivisor * rate1)); //compensate the time stay in native func
	    }
	    return ret;
	}

	case 103:	//close dll
	{
	    HMODULE libaddr;
	    libaddr = (HMODULE) m68k_dreg (&context->regs, 1);
	    FreeLibrary(libaddr);
	    return 0;
	}
#endif

	case 104:        //screenlost
	{
	    static int oldnum = 0;
	    if (uaevar.changenum == oldnum)
		return 0;
	    oldnum = uaevar.changenum;
	    return 1;
	}

#if defined(X86_MSVC_ASSEMBLY)

	case 105:   //returns memory offset
	    return (uae_u32) get_real_address(0);

	case 106:   //byteswap 16bit vars
		    //a0 = start address
		    //d1 = number of 16bit vars
		    //returns address of new array
	    src = m68k_areg(&context->regs, 0);
	    num_vars = m68k_dreg(&context->regs, 1);

	    if (bswap_buffer_size < num_vars * 2) {
		bswap_buffer_size = (num_vars + 1024) * 2;
		free(bswap_buffer);
		bswap_buffer = (void*)malloc(bswap_buffer_size);
	    }
	    __asm {
		mov esi, dword ptr [src]
		mov edi, dword ptr [bswap_buffer]
		mov ecx, num_vars

		mov ebx, ecx
		and ecx, 3
		je BSWAP_WORD_4X

		BSWAP_WORD_LOOP:
		mov ax, [esi]
		mov dl, al
		mov al, ah
		mov ah, dl
		mov [edi], ax
		add esi, 2
		add edi, 2
		loopne BSWAP_WORD_LOOP

		BSWAP_WORD_4X:
		mov ecx, ebx
		shr ecx, 2
		je BSWAP_WORD_END
		BSWAP_WORD_4X_LOOP:
		mov ax, [esi]
		mov dl, al
		mov al, ah
		mov ah, dl
		mov [edi], ax
		mov ax, [esi+2]
		mov dl, al
		mov al, ah
		mov ah, dl
		mov [edi+2], ax
		mov ax, [esi+4]
		mov dl, al
		mov al, ah
		mov ah, dl
		mov [edi+4], ax
		mov ax, [esi+6]
		mov dl, al
		mov al, ah
		mov ah, dl
		mov [edi+6], ax
		add esi, 8
		add edi, 8
		loopne BSWAP_WORD_4X_LOOP
		BSWAP_WORD_END:
	    }
	return (uae_u32) bswap_buffer;

	case 107:   //byteswap 32bit vars - see case 106
		    //a0 = start address
		    //d1 = number of 32bit vars
		    //returns address of new array
	    src = m68k_areg(&context->regs, 0);
	    num_vars = m68k_dreg(&context->regs, 1);
	    if (bswap_buffer_size < num_vars * 4) {
		bswap_buffer_size = (num_vars + 16384) * 4;
		free(bswap_buffer);
		bswap_buffer = (void*)malloc(bswap_buffer_size);
	    }
	    __asm {
		mov esi, dword ptr [src]
		mov edi, dword ptr [bswap_buffer]
		mov ecx, num_vars
		
		mov ebx, ecx
		and ecx, 3
		je BSWAP_DWORD_4X

		BSWAP_DWORD_LOOP:
		mov eax, [esi]
		bswap eax
		mov [edi], eax
		add esi, 4
		add edi, 4
		loopne BSWAP_DWORD_LOOP

		BSWAP_DWORD_4X:
		mov ecx, ebx
		shr ecx, 2
		je BSWAP_DWORD_END
		BSWAP_DWORD_4X_LOOP:
		mov eax, [esi]
		bswap eax
		mov [edi], eax
		mov eax, [esi+4]
		bswap eax
		mov [edi+4], eax
		mov eax, [esi+8]
		bswap eax
		mov [edi+8], eax
		mov eax, [esi+12]
		bswap eax
		mov [edi+12], eax
		add esi, 16
		add edi, 16
		loopne BSWAP_DWORD_4X_LOOP

		BSWAP_DWORD_END:
	    }
	return (uae_u32) bswap_buffer;

	case 108: //frees swap array
	    bswap_buffer_size = 0;
	    free(bswap_buffer);
	    bswap_buffer = NULL;
	return 0;
#endif

	case 200:
	    ahitweak = m68k_dreg (&context->regs, 1);
	    ahi_pollrate = m68k_dreg (&context->regs, 2);
	    if (ahi_pollrate < 10)
		ahi_pollrate = 10;
	    if (ahi_pollrate > 60)
		ahi_pollrate = 60;
	return 1;

	default:
	return 0x12345678;     // Code for not supportet function
    }
}

#endif
