Esempio n. 1
0
static int initint (TrapContext *ctx)
{
	uae_u32 tmp1;
	uaecptr p;

	if (irq_init)
		return 1;
	m68k_dreg (regs, 0) = 26;
	m68k_dreg (regs, 1) = 65536 + 1;
	p = CallLib (ctx, get_long (4), -0xC6); /* AllocMem */
	if (!p)
		return 0;
	tmp1 = here ();
	calltrap (deftrap2 (uaenet_int_handler, TRAPFLAG_EXTRA_STACK, _T("uaenet_int_handler")));
	put_word (p + 8, 0x020a);
	put_long (p + 10, ROM_netdev_resid);
	put_long (p + 18, tmp1);
	m68k_areg (regs, 1) = p;
	m68k_dreg (regs, 0) = 3; /* PORTS */
	dw (0x4a80); /* TST.L D0 */
	dw (0x4e75); /* RTS */
	CallLib (ctx, get_long (4), -168); /* AddIntServer */
	irq_init = 1;
	return 1;
}
Esempio n. 2
0
uaecptr libemu_InstallFunctionFlags (TrapFunction f, uaecptr libbase, int offset,
				     int flags, const char *tracename)
{
    int i;
    uaecptr retval;
    uaecptr execbase = get_long (four);
    int trnum;
    uaecptr addr = here();
    calltrap (trnum = deftrap2 (f, flags, tracename));
    dw (RTS);

    _68k_areg(1) = libbase;
    _68k_areg(0) = offset;
    _68k_dreg(0) = addr;
    retval = CallLib (execbase, -420);

    trapoldfunc[trnum] = retval;
#if 0
    for (i = 0; i < n_libpatches; i++) {
	if (libpatches[i].libbase == libbase)
	    break;
    }
    if (i == n_libpatches) {
	int j;
	libpatches[i].libbase = libbase;
	for (j = 0; j < 300; j++)
	    libpatches[i].functions[j] = NULL;
	n_libpatches++;
    }
    libpatches[i].functions[-offset/6] = f;
#endif
    return retval;
}
Esempio n. 3
0
uaecptr libemu_InstallFunctionFlags (TrapFunction f, uaecptr libbase, int offset,
				     int flags, const char *tracename)
{
    int i;
    uaecptr retval;
    uaecptr execbase = get_long (four);
    int trnum;
    uaecptr addr = here();
    calltrap (trnum = deftrap2 (f, flags, tracename));
    dw (RTS);

    _68k_areg(1) = libbase;
    _68k_areg(0) = offset;
    _68k_dreg(0) = addr;
    retval = CallLib (execbase, -420);

    trapoldfunc[trnum] = retval;
    return retval;
}
Esempio n. 4
0
uae_u32 trap_call_lib(TrapContext *ctx, uaecptr base, uae_s16 offset)
{
	uae_u32 v;
	if (trap_is_indirect_null(ctx)) {
		uae_u8 *p = ctx->host_trap_data + RTAREA_TRAP_DATA_EXTRA;
		for (int i = 0; i < 16; i++) {
			if (ctx->calllib_reg_inuse[i]) {
				put_long_host(p , ctx->calllib_regs[i]);
				ctx->calllib_reg_inuse[i] = 0;
			} else {
				put_long_host(p, ctx->saved_regs.regs[i]);
			}
			p += 4;
		}
		v = call_hardware_trap_back(ctx, TRAPCMD_CALL_LIB, base, offset, ctx->amiga_trap_data + RTAREA_TRAP_DATA_EXTRA, 0);
	} else {
		uae_u32 storedregs[16];
		bool storedregsused[16];
		for (int i = 0; i < 16; i++) {
			storedregsused[i] = false;
			if (ctx->calllib_reg_inuse[i]) {
				if ((i & 7) >= 2) {
					storedregsused[i] = true;
					storedregs[i] = regs.regs[i];
				}
				regs.regs[i] = ctx->calllib_regs[i];
			}
			ctx->calllib_reg_inuse[i] = 0;
		}
		v = CallLib(ctx, base, offset);
		for (int i = 0; i < 16; i++) {
			if (storedregsused[i]) {
				regs.regs[i] = storedregs[i];
			}
		}
	}
	return v;
}
Esempio n. 5
0
static uae_u32 REGPARAM2 dev_close_2 (TrapContext *context)
{
	uae_u32 request = m68k_areg (regs, 1);
	struct priv_s2devstruct *pdev = getps2devstruct (request);
	struct s2devstruct *dev;

	if (!pdev) {
		write_log (_T("%s close with unknown request %08X!?\n"), SANA2NAME, request);
		return 0;
	}
	dev = gets2devstruct (pdev->unit);
	if (!dev) {
		write_log (_T("%s:%d close with unknown request %08X!?\n"), SANA2NAME, pdev->unit, request);
		return 0;
	}
	if (log_net)
		write_log (_T("%s:%d close, open=%d req=%08X\n"), SANA2NAME, pdev->unit, dev->opencnt, request);
	put_long (request + 24, 0);
	dev->opencnt--;
	pdev->inuse = 0;
	if (!dev->opencnt) {
		dev->exclusive = 0;
		if (pdev->tempbuf) {
			m68k_areg (regs, 1) = pdev->tempbuf;
			m68k_dreg (regs, 0) = pdev->td->mtu + ETH_HEADER_SIZE + 2;
			CallLib (context, get_long (4), -0xD2); /* FreeMem */
			pdev->tempbuf = 0;
		}
		ethernet_close (pdev->td, dev->sysdata);
		xfree (dev->sysdata);
		dev->sysdata = NULL;
		write_comm_pipe_u32 (&dev->requests, 0, 1);
		write_log (_T("%s: opencnt == 0, all instances closed\n"), SANA2NAME);
	}
	put_word (m68k_areg (regs, 6) + 32, get_word (m68k_areg (regs, 6) + 32) - 1);
	return 0;
}
Esempio n. 6
0
void uae_FreeMem (TrapContext *context, uaecptr memory, uae_u32 size)
{
	m68k_dreg (regs, 0) = size;
	m68k_areg (regs, 1) = memory;
	CallLib (context, x_get_long (4), -0xD2); /* FreeMem */
}
Esempio n. 7
0
uaecptr uae_AllocMem (TrapContext *context, uae_u32 size, uae_u32 flags)
{
	m68k_dreg (regs, 0) = size;
	m68k_dreg (regs, 1) = flags;
	return CallLib (context, x_get_long (4), -198); /* AllocMem */
}
Esempio n. 8
0
void uae_FreeMem (uaecptr memory, uae_u32 size)
{
    m68k_dreg (regs, 0) = size;
    m68k_areg (regs, 1) = memory;
    CallLib (get_long (4), -0xD2); /* FreeMem */
}
Esempio n. 9
0
uaecptr uae_AllocMem (uae_u32 size, uae_u32 flags)
{
    m68k_dreg (regs, 0) = size;
    m68k_dreg (regs, 1) = flags;
    return CallLib (get_long (4), -198); /* AllocMem */
}
Esempio n. 10
0
uaecptr uae_AllocMem (TrapContext *ctx, uae_u32 size, uae_u32 flags, uaecptr sysbase)
{
	trap_set_dreg(ctx, 0, size);
	trap_set_dreg(ctx, 1, flags);
	return CallLib (ctx, sysbase, -198); /* AllocMem */
}
Esempio n. 11
0
void uae_FreeMem (TrapContext *ctx, uaecptr memory, uae_u32 size, uaecptr sysbase)
{
	trap_set_dreg(ctx, 0, size);
	trap_set_areg(ctx, 1, memory);
	CallLib (ctx, sysbase, -0xD2); /* FreeMem */
}
Esempio n. 12
0
static uae_u32 REGPARAM2 dev_open_2 (TrapContext *context)
{
	uaecptr ioreq = m68k_areg (regs, 1);
	uae_u32 unit = m68k_dreg (regs, 0);
	uae_u32 flags = m68k_dreg (regs, 1);
	uaecptr buffermgmt;
	struct s2devstruct *dev = gets2devstruct (unit);
	struct priv_s2devstruct *pdev = 0;
	int i;
	uaecptr tagp, tagpnext;

	if (!dev)
		return openfail (ioreq, IOERR_OPENFAIL);
	if (!initint(context))
		return openfail (ioreq, IOERR_SELFTEST);
	if (log_net)
		write_log (_T("opening %s:%d opencnt=%d ioreq=%08X\n"), SANA2NAME, unit, dev->opencnt, ioreq);
	if (get_word (ioreq + 0x12) < IOSTDREQ_SIZE)
		return openfail (ioreq, IOERR_BADLENGTH);
	if ((flags & SANA2OPF_PROM) && dev->opencnt > 0)
		return openfail (ioreq, IOERR_UNITBUSY);

	for (i = 0; i < MAX_OPEN_DEVICES; i++) {
		pdev = &pdevst[i];
		if (pdev->inuse == 0)
			break;
	}
	if (i == MAX_OPEN_DEVICES)
		return openfail (ioreq, IOERR_UNITBUSY);

	put_long (ioreq + 24, pdev - pdevst);
	pdev->unit = unit;
	pdev->flags = flags;
	pdev->inuse = 1;
	pdev->td = td ? td[unit] : NULL;
	pdev->promiscuous = (flags & SANA2OPF_PROM) ? 1 : 0;

	if (pdev->td == NULL || pdev->td->active == 0)
		return openfail (ioreq, IOERR_OPENFAIL);

	if (dev->opencnt == 0) {
		dev->unit = unit;
		dev->sysdata = xcalloc (uae_u8, ethernet_getdatalenght (pdev->td));
		if (!ethernet_open (pdev->td, dev->sysdata, dev, uaenet_gotdata, uaenet_getdata, pdev->promiscuous)) {
			xfree (dev->sysdata);
			dev->sysdata = NULL;
			return openfail (ioreq, IOERR_OPENFAIL);
		}
		write_log (_T("%s: initializing unit %d\n"), getdevname (), unit);
		dev->td = pdev->td;
		dev->adapter = pdev->td ? pdev->td->active : 0;
		if (dev->adapter) {
			dev->online = 1;
			dev->configured = 1;
		}
		start_thread (dev);
	}

	if (kickstart_version >= 36) {
		m68k_areg (regs, 0) = get_long (4) + 350;
		m68k_areg (regs, 1) = timerdevname;
		CallLib (context, get_long (4), -0x114); /* FindName('timer.device') */
		pdev->timerbase = m68k_dreg (regs, 0);
	}

	pdev->copyfrombuff = pdev->copytobuff = pdev->packetfilter = 0;
	pdev->tempbuf = 0;
	if (get_word (ioreq + 0x12) >= SANA2_IOREQSIZE) {
		buffermgmt = get_long (ioreq + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES * 2 + 4 + 4 + 4);
		tagpnext = buffermgmt;
		while (tagpnext) {
			uae_u32 tag = get_long (tagpnext);
			uae_u32 val = get_long (tagpnext + 4);
			tagp = tagpnext;
			tagpnext += 8;
			switch (tag)
			{
			case TAG_DONE:
				tagpnext = 0;
				break;
			case TAG_IGNORE:
				break;
			case TAG_MORE:
				tagpnext = val;
				break;
			case TAG_SKIP:
				tagpnext = tagp + val * 8;
				break;
			case S2_CopyToBuff:
				pdev->copytobuff = val;
				break;
			case S2_CopyFromBuff:
				pdev->copyfrombuff = val;
				break;
			case S2_PacketFilter:
				pdev->packetfilter = val;
				break;
			}
		}
		if (log_net)
			write_log (_T("%s:%d CTB=%08x CFB=%08x PF=%08x\n"),
			getdevname(), unit, pdev->copytobuff, pdev->copyfrombuff, pdev->packetfilter);
		m68k_dreg (regs, 0) = dev->td->mtu + ETH_HEADER_SIZE + 2;
		m68k_dreg (regs, 1) = 1;
		pdev->tempbuf = CallLib (context, get_long (4), -0xC6); /* AllocMem */
		if (!pdev->tempbuf) {
			if (dev->opencnt == 0) {
				ethernet_close (pdev->td, dev->sysdata);
				xfree (dev->sysdata);
				dev->sysdata = NULL;
			}
			return openfail (ioreq, S2ERR_BAD_ARGUMENT);
		}
		/* buffermanagement */
		put_long (ioreq + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES * 2 + 4 + 4 + 4, pdev->tempbuf);
	}
	dev->exclusive = flags & SANA2OPF_MINE;
	dev->opencnt++;
	put_word (m68k_areg (regs, 6) + 32, get_word (m68k_areg (regs, 6) + 32) + 1);
	put_byte (ioreq + 31, 0);
	put_byte (ioreq + 8, 7);
	return 0;
}
Esempio n. 13
0
static uae_u32 REGPARAM2 uaenet_int_handler (TrapContext *ctx)
{
	int i, j;
	int gotit;
	struct asyncreq *ar;

	if (uae_sem_trywait (&async_sem)) {
		uaenet_int_requested = 0;
		uaenet_int_late = 1;
		return 0;
	}
	for (i = 0; i < MAX_OPEN_DEVICES; i++)
		pdevst[i].tmp = 0;

	for (i = 0; i < MAX_TOTAL_NET_DEVICES; i++) {
		struct s2devstruct *dev = &devst[i];
		struct s2packet *p;
		if (dev->online) {
			while (dev->readqueue) {
				uae_u16 type;
				p = dev->readqueue;
				type = (p->data[2 * ADDR_SIZE] << 8) | p->data[2 * ADDR_SIZE + 1];
				ar = dev->ar;
				gotit = 0;
				while (ar) {
					if (!ar->ready) {
						uaecptr request = ar->request;
						int command = get_word (request + 28);
						uae_u32 packettype = get_long (request + 32 + 4);
						if (command == CMD_READ && (packettype == type || (packettype <= 1500 && type <= 1500))) {
							struct priv_s2devstruct *pdev = getps2devstruct (request);
							if (pdev && pdev->tmp == 0) {
								if (handleread (ctx, pdev, request, p->data, p->len, command)) {
									if (log_net)
										write_log (_T("-> %p Accepted, CMD_READ, REQ=%08X LEN=%d\n"), p, request, p->len);
									ar->ready = 1;
									write_comm_pipe_u32 (&dev->requests, request, 1);
									dev->packetsreceived++;
									gotit = 1;
									pdev->tmp = 1;
								} else {
									if (log_net)
										write_log (_T("-> %p PacketFilter() rejected, CMD_READ, REQ=%08X LEN=%d\n"), p, request, p->len);
									pdev->tmp = -1;
								}
							}
						}
					}
					ar = ar->next;
				}
				ar = dev->ar;
				while (ar) {
					if (!ar->ready) {
						uaecptr request = ar->request;
						int command = get_word (request + 28);
						if (command == S2_READORPHAN) {
							struct priv_s2devstruct *pdev = getps2devstruct (request);
							if (pdev && pdev->tmp <= 0) {
								if (log_net)
									write_log (_T("-> %p Accepted, S2_READORPHAN, REQ=%08X LEN=%d\n"), p, request, p->len);
								handleread (ctx, pdev, request, p->data, p->len, command);
								ar->ready = 1;
								write_comm_pipe_u32 (&dev->requests, request, 1);
								dev->packetsreceived++;
								dev->unknowntypesreceived++;
								gotit = 1;
								pdev->tmp = 1;
							}
						}
					}
					ar = ar->next;
				}
				if (!gotit) {
					if (log_net)
						write_log (_T("-> %p packet dropped, LEN=%d\n"), p, p->len);
					for (j = 0; j < MAX_OPEN_DEVICES; j++) {
						if (pdevst[j].unit == dev->unit) {
							if (pdevst[j].tracks[type])
								pdevst[j].packetsdropped++;
						}
					}
				}
				dev->readqueue = dev->readqueue->next;
				freepacket (p);
			}
		} else {
			while (dev->readqueue) {
				p = dev->readqueue;
				dev->readqueue = dev->readqueue->next;
				freepacket (p);
			}
		}

		ar = dev->ar;
		while (ar) {
			if (!ar->ready) {
				uaecptr request = ar->request;
				int command = get_word (request + 28);
				if (command == S2_ONLINE) {
					struct priv_s2devstruct *pdev = getps2devstruct (request);
					dev->packetsreceived = 0;
					dev->packetssent = 0;
					dev->baddata = 0;
					dev->overruns = 0;
					dev->unknowntypesreceived = 0;
					dev->reconfigurations = 0;
					if (pdev && pdev->timerbase) {
						m68k_areg (regs, 0) = pdev->tempbuf;
						CallLib (ctx, pdev->timerbase, -0x42); /* GetSysTime() */
					} else {
						put_long (pdev->tempbuf + 0, 0);
						put_long (pdev->tempbuf + 4, 0);
					}
					dev->online_secs = get_long (pdev->tempbuf + 0);
					dev->online_micro = get_long (pdev->tempbuf + 4);
					checkevents (dev, S2EVENT_ONLINE, 0);
					dev->online = 1;
					ar->ready = 1;
					write_comm_pipe_u32 (&dev->requests, request, 1);
					uaenet_vsync_requested--;
				} else if (command == CMD_FLUSH) {
					/* do not reply CMD_FLUSH until all other requests are gone */
					if (dev->ar->next == NULL) {
						if (log_net)
							write_log (_T("CMD_FLUSH replied %08x\n"), request);
						ar->ready = 1;
						write_comm_pipe_u32 (&dev->requests, request, 1);
						uaenet_vsync_requested--;
					} else {
						struct priv_s2devstruct *pdev = getps2devstruct (request);
						if (pdev) {
							dev->flush_timeout--;
							if (dev->flush_timeout <= 0) {
								dev->flush_timeout = FLUSH_TIMEOUT;
								if (dev->flush_timeout_cnt > 1)
									write_log (_T("WARNING: %s:%d CMD_FLUSH possibly frozen..\n"), getdevname(), pdev->unit);
								dev->flush_timeout_cnt++;
								flush (pdev);
							}
						}
					}
				}
			}
			ar = ar->next;
		}
	}
	if (uaenet_int_late)
		uaenet_int_requested = 1;
	else
		uaenet_int_requested = 0;
	uaenet_int_late = 0;
	uae_sem_post (&async_sem);
	return 0;
}
Esempio n. 14
0
static uae_u32 hardfile_beginio (void)
{
	uae_u32 tmp1, tmp2, dataptr, offset;
	uae_u32 retval = m68k_dreg(regs, 0);
	int unit;
	struct hardfiledata *hfd;
	
	tmp1 = m68k_areg(regs, 1);
	unit = get_long (tmp1 + 24);
#undef DEBUGME
#ifdef DEBUGME
	printf ("hardfile: unit = %d\n", unit);
	printf ("hardfile: tmp1 = %08lx\n", (unsigned long)tmp1);
	printf ("hardfile: cmd  = %d\n", (int)get_word(tmp1+28));
#endif
	hfd = get_hardfile_data (unit);
	
	put_byte (tmp1+8, NT_MESSAGE);
	put_byte (tmp1+31, 0); /* no error yet */
	tmp2 = get_word (tmp1+28); /* io_Command */
	/*    put_byte (tmp1 + 30, get_byte (tmp1 + 30) & ~1);*/
	switch (tmp2) {
		case CMD_READ:
			gui_data.hdled = HDLED_READ;
			
			dataptr = get_long (tmp1 + 40);
			if (dataptr & 1)
				goto bad_command;
			offset = get_long (tmp1 + 44);
			if (offset & 511)
				goto bad_command;
			tmp2 = get_long (tmp1 + 36); /* io_Length */
			if (tmp2 & 511)
				goto bad_command;
			if (tmp2 + offset > (uae_u32)hfd->size)
				goto bad_command;
			
			put_long (tmp1 + 32, tmp2); /* set io_Actual */
#ifdef __SYMBIAN32__
			lseek (fileno(hfd->fd), offset, SEEK_SET);
#else
			fseek (hfd->fd, offset, SEEK_SET);
#endif
			while (tmp2) {
				int i;
				char buffer[512];
#ifdef __SYMBIAN32__
				/* See the comment in CMD_WRITE */
				read (fileno(hfd->fd), buffer, 512);
#else
				fread (buffer, 1, 512, hfd->fd);
#endif
				for (i = 0; i < 512; i++, dataptr++)
					put_byte(dataptr, buffer[i]);
				tmp2 -= 512;
			}
			break;
			
		case CMD_WRITE:
		case 11: /* Format */
			gui_data.hdled = HDLED_WRITE;
			
			dataptr = get_long (tmp1 + 40);
			if (dataptr & 1)
				goto bad_command;
			offset = get_long (tmp1 + 44);
			if (offset & 511)
				goto bad_command;
			tmp2 = get_long (tmp1 + 36); /* io_Length */
			if (tmp2 & 511)
				goto bad_command;
			if (tmp2 + offset > (uae_u32)hfd->size)
				goto bad_command;
			
			put_long (tmp1 + 32, tmp2); /* set io_Actual */
#ifdef __SYMBIAN32__
			lseek (fileno(hfd->fd), offset, SEEK_SET);
#else
			fseek (hfd->fd, offset, SEEK_SET);
#endif
			while (tmp2) {
				char buffer[512];
				int i;
				for (i=0; i < 512; i++, dataptr++)
					buffer[i] = get_byte(dataptr);
#ifdef __SYMBIAN32__
				/* For some reason, fwrite() *appends* data at the end of the HDF file,
				 * instead of writing it at fseek() offset, even though fopen() was called
				 * with "r+b" parameter, and not "a+"!
				 * write() works correctly.
				 */
				write (fileno(hfd->fd), buffer, 512);
#else
				fwrite (buffer, 1, 512, hfd->fd);
#endif			
				tmp2 -= 512;
			}
			break;
			
			bad_command:
			break;
			
		case 18: /* GetDriveType */
			printf ("Shouldn't happen\n");
			put_long (tmp1 + 32, 1); /* not exactly a 3.5" drive, but... */
			break;
			
		case 19: /* GetNumTracks */
			printf ("Shouldn't happen 2\n");
			put_long (tmp1 + 32, 0);
			break;
			
			/* Some commands that just do nothing and return zero */
		case CMD_UPDATE:
		case CMD_CLEAR:
		case 9: /* Motor */
		case 10: /* Seek */
		case 12: /* Remove */
		case 13: /* ChangeNum */
		case 14: /* ChangeStatus */
		case 15: /* ProtStatus */
		case 20: /* AddChangeInt */
		case 21: /* RemChangeInt */
			put_long (tmp1+32, 0); /* io_Actual */
			retval = 0;
			break;
			
		default:
			/* Command not understood. */
			put_byte (tmp1+31, (uae_u8)-3); /* io_Error */
			retval = 0;
			break;
	}
#if 0
	if ((get_byte (tmp1+30) & 1) == 0) {
		/* Not IOF_QUICK -- need to ReplyMsg */
		m68k_areg(regs, 1) = tmp1;
		CallLib (get_long(4), -378);
	}
#endif
	return retval;
}
Esempio n. 15
0
uae_u32 uaenative_call_function (TrapContext *context, int flags)
{
    if (!currprefs.native_code) {
        return UNI_ERROR_NOT_ENABLED;
    }

    struct uni uni;
    uni.function = m68k_areg (regs, 0);
    if (flags & UNI_FLAG_COMPAT) {
        uni.library = 0;
#ifdef AHI
        uni.uaevar_compat = uaenative_get_uaevar();
#else
        uni.uaevar_compat = NULL;
#endif
    }
    else if (flags & UNI_FLAG_NAMED_FUNCTION) {
        uni.library = m68k_dreg (regs, 0);
    }
    else {
        uni.library = 0;
    }

    struct library_data *library_data;

    if (uni.library) {
        // library handle given, function is pointer to function name
        const char *function = (const char *) get_real_address (uni.function);

        library_data = get_library_data_from_handle (uni.library);
        if (library_data == NULL) {
            write_log (_T("uni: get_function - invalid library (%d)\n"),
                    uni.library);
            return UNI_ERROR_INVALID_LIBRARY;
        }

        uni.native_function = dl_symbol (library_data->dl_handle, function);
        if (uni.native_function == NULL) {
            write_log (_T("uni: get_function - function (%s) not found ")
                       _T("in library %d (%p)\n"), function, uni.library,
                                                   library_data->dl_handle);
            return UNI_ERROR_FUNCTION_NOT_FOUND;
        }
    }
    else {
        // library handle not given, function argument is function handle
        int index = uni.function - (uae_u32) 0x80000000;
        if (index >= 0 && index <= g_max_handle) {
            uni.native_function = g_handles[index].function;
            library_data = g_handles[index].library;
        }
        else {
            uni.native_function = NULL;
        }
        if (uni.native_function == NULL) {
            // printf ("UNI_ERROR_INVALID_FUNCTION\n");
            return UNI_ERROR_INVALID_FUNCTION;
        }
    }

    if (context == NULL) {
        // we have no context and cannot call into m68k space
        flags &= ~UNI_FLAG_ASYNCHRONOUS;
    }

    uni.d1 = m68k_dreg (regs, 1);
    uni.d2 = m68k_dreg (regs, 2);
    uni.d3 = m68k_dreg (regs, 3);
    uni.d4 = m68k_dreg (regs, 4);
    uni.d5 = m68k_dreg (regs, 5);
    uni.d6 = m68k_dreg (regs, 6);
    uni.d7 = m68k_dreg (regs, 7);
    uni.a1 = m68k_areg (regs, 1);
    uni.a2 = m68k_areg (regs, 2);
    uni.a3 = m68k_areg (regs, 3);
    uni.a4 = m68k_areg (regs, 4);
    uni.a5 = m68k_areg (regs, 5);
    uni.a7 = m68k_areg (regs, 7);

    uni.flags = flags;
    uni.error = 0;

    if (flags & UNI_FLAG_ASYNCHRONOUS) {
        uaecptr sysbase = get_long (4);
        uni.task = get_long (sysbase + 276); // ThisTask

        // make sure signal bit is cleared
        m68k_dreg (regs, 0) = 0;
        m68k_dreg (regs, 1) = 1 << SIGBIT;
        CallLib (context, sysbase, -0x132); // SetSignal

        // start thread if necessary
        if (!library_data->thread_id) {
            uae_sem_init (&library_data->full_count, 0, 0);
            // we don't have a queue as such, the thread only processes
            // one item at a time with a "queue size" of 1
            uae_sem_init (&library_data->empty_count, 0, 1);
            uae_start_thread (_T("uaenative"), uaenative_thread,
                              library_data, &library_data->thread_id);
        }

        // signal async thread to process new function call
        uae_sem_wait(&library_data->empty_count);
        library_data->uni = &uni;
        uae_sem_post(&library_data->full_count);

        // wait for signal
        m68k_dreg (regs, 0) = 1 << SIGBIT;
        CallLib (context, sysbase, -0x13e); // Wait
        write_log (_T("uni: -- Got async result --\n"));
    }
    else {
        // synchronous mode, just call the function here and now
        do_call_function(&uni);
    }
    return uni.result;
}