예제 #1
0
/**
 * Check Bios call and see if we need to re-direct to our own routines.
 * Return true if we've handled the exception, else return false to let
 * TOS attempt it
 */
bool Bios(void)
{
	Uint32 Params;
	Uint16 BiosCall;

	/* Get call */
	Params = Regs[REG_A7];
	BiosCall = STMemory_ReadWord(Params);
	Params += SIZE_WORD;

	/* Intercept? */
	switch(BiosCall)
	{
	case 0x0:
		LOG_TRACE(TRACE_OS_BIOS, "BIOS 0x00 Getmpb(0x%X)\n",
			  STMemory_ReadLong(Params));
		break;

	case 0x3:
		LOG_TRACE(TRACE_OS_BIOS, "BIOS 0x03 Bconout(%i, 0x%02hhX)\n",
			  STMemory_ReadWord(Params),
			  STMemory_ReadWord(Params)+SIZE_WORD);
		break;

	case 0x4:
		Bios_RWabs(Params);
		break;

	case 0x5:
		LOG_TRACE(TRACE_OS_BIOS, "BIOS 0x05 Setexc(0x%hX, 0x%X)\n",
			  STMemory_ReadWord(Params),
			  STMemory_ReadLong(Params)+SIZE_WORD);
		break;

	case 0x1:
	case 0x2:
	case 0x7:
	case 0x8:
	case 0x9:
	case 0xB:
		/* commands taking a single word */
		LOG_TRACE(TRACE_OS_BIOS, "BIOS 0x%02hX %s(0x%hX)\n",
			  BiosCall, Bios_Call2Name(BiosCall),
			  STMemory_ReadWord(Params));
		break;

	case 0x6:
	case 0xA:
		/* commands taking no args */
		LOG_TRACE(TRACE_OS_BIOS, "BIOS 0x%02hX %s()\n",
			  BiosCall, Bios_Call2Name(BiosCall));
		break;

	default:
		Log_Printf(LOG_WARN, "Unknown BIOS call 0x%x!\n", BiosCall);
		break;
	}
	return false;
}
예제 #2
0
파일: natfeats.c 프로젝트: denizt/hatari
/**
 * Set retval to internal ID for requested Native Feature,
 * or zero if feature is unknown/unsupported.
 * 
 * Return true if caller is to proceed normally,
 * false if there was an exception.
 */
bool NatFeat_ID(Uint32 stack, Uint32 *retval)
{
	const char *name;
	Uint32 ptr;
	int i;

	ptr = STMemory_ReadLong(stack);
	if (!STMemory_ValidArea(ptr, FEATNAME_MAX)) {
		M68000_BusError(ptr, BUS_ERROR_READ);
		return false;
	}

	name = (const char *)STRAM_ADDR(ptr);
	Dprintf(("NF ID(0x%x)\n", ptr));
	Dprintf(("   \"%s\"\n", name));

	for (i = 0; i < ARRAYSIZE(features); i++) {
		if (strcmp(features[i].name, name) == 0) {
			*retval = IDX2MASTERID(i);
			return true;
		}
	}
	/* unknown feature */
	*retval = 0;
	return true;
}
예제 #3
0
파일: natfeats.c 프로젝트: r-type/hatari
/**
 * Set retval to internal ID for requested Native Feature,
 * or zero if feature is unknown/unsupported.
 *
 * Return true if caller is to proceed normally,
 * false if there was an exception.
 */
bool NatFeat_ID(Uint32 stack, Uint32 *retval)
{
    const char *name;
    Uint32 ptr;
    int i;

    ptr = STMemory_ReadLong(stack);
    if ( !STMemory_CheckAreaType ( ptr, FEATNAME_MAX, ABFLAG_RAM | ABFLAG_ROM ) ) {
        M68000_BusError(ptr, BUS_ERROR_READ, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
        return false;
    }

    name = (const char *)STMemory_STAddrToPointer ( ptr );
    LOG_TRACE(TRACE_NATFEATS, "NF ID(0x%x \"%s\")\n", ptr, name);

    for (i = 0; i < ARRAYSIZE(features); i++) {
        if (strcmp(features[i].name, name) == 0) {
            *retval = IDX2MASTERID(i);
            return true;
        }
    }
    /* unknown feature */
    *retval = 0;
    return true;
}
예제 #4
0
파일: evaluate.c 프로젝트: denizt/hatari
/* last parsed value, last param. flag, trigonometric mode	*/
static long long close_bracket (long long value)
{
	/* returns the value of the parenthesised expression	*/

	if (id.valid) {			/* preceded by an operator	*/
		if (par.idx > 0) {	/* prenthesis has a pair	*/
			Uint32 addr;

			/* calculate the value of parenthesised exp.	*/
			operation (value, LOWEST_PREDECENCE);
			/* fetch the indirect ST RAM value */
			addr = val.buf[val.idx];
			value = STMemory_ReadLong(addr);
			fprintf(stderr, "  value in RAM at ($%x).l = $%llx\n", addr, value);
			/* restore state before parenthesis */
			op.idx = par.opx[par.idx] - 1;
			val.idx = par.vax[par.idx] - 1;
			par.idx --;

			/* next operator */
			id.valid = true;
		} else
			id.error = CLAC_PAR_ERR;
	} else
		id.error = CLAC_GEN_ERR;

	return value;
}
예제 #5
0
파일: natfeats.c 프로젝트: r-type/hatari
/**
 * NF_EXIT - exit emulator with given exit code
 * Stack arguments are:
 * - emulator's int32_t exit value
 */
static bool nf_exit(Uint32 stack, Uint32 subid, Uint32 *retval)
{
    Sint32 exitval;

    ConfigureParams.Log.bConfirmQuit = false;
    exitval = STMemory_ReadLong(stack);
    LOG_TRACE(TRACE_NATFEATS, "NF_EXIT(%d)\n", exitval);
    Main_RequestQuit(exitval);
    return true;
}
예제 #6
0
파일: natfeats.c 프로젝트: r-type/hatari
/**
 * NF_FASTFORWARD - set fast forward state
 * Stack arguments are:
 * - state 0: off, >=1: on
 */
static bool nf_fastforward(Uint32 stack, Uint32 subid, Uint32 *retval)
{
    Uint32 val;

    val = STMemory_ReadLong(stack);
    *retval = ConfigureParams.System.bFastForward;
    LOG_TRACE(TRACE_NATFEATS, "NF_FASTFORWARD(%d -> %d)\n", *retval, val);
    ConfigureParams.System.bFastForward = ( val ? true : false );
    return true;
}
예제 #7
0
/**
 * DebugInfo_GetSysbase: get and validate system base
 * return on success sysbase address (+ set rombase), on failure return zero
 */
static Uint32 DebugInfo_GetSysbase(Uint32 *rombase)
{
	Uint32 sysbase = STMemory_ReadLong(OS_SYSBASE);

	if (!STMemory_ValidArea(sysbase, OS_HEADER_SIZE)) {
		fprintf(stderr, "Invalid TOS sysbase RAM address (0x%x)!\n", sysbase);
		return 0;
	}
	/* under TOS, sysbase = os_beg = TosAddress, but not under MiNT -> use os_beg */
	*rombase = STMemory_ReadLong(sysbase+0x08);
	if (!STMemory_ValidArea(*rombase, OS_HEADER_SIZE)) {
		fprintf(stderr, "Invalid TOS sysbase ROM address (0x%x)!\n", *rombase);
		return 0;
	}
	if (*rombase != TosAddress) {
		fprintf(stderr, "os_beg (0x%x) != TOS address (0x%x), header in RAM not set up yet?\n",
			*rombase, TosAddress);
		return 0;
	}
	return sysbase;
}
예제 #8
0
파일: xbios.c 프로젝트: diablodiab/hatari
/**
 * XBIOS remote control interface for Hatari
 * Call 255
 */
static bool XBios_HatariControl(Uint32 Params)
{
	const char *pText;
	pText = (const char *)STRAM_ADDR(STMemory_ReadLong(Params));
	LOG_TRACE(TRACE_OS_XBIOS, "XBIOS 0x%02X HatariControl(%s) at PC 0x%X\n", HATARI_CONTROL_OPCODE, pText, M68000_GetPC());

	if (!bXBiosCommands)
		return false;

	Control_ProcessBuffer(pText);
	Regs[REG_D0] = 0;
	return true;
}
예제 #9
0
파일: natfeats.c 프로젝트: denizt/hatari
static bool nf_name(Uint32 stack, Uint32 subid, Uint32 *retval)
{
	Uint32 ptr, len;
	const char *str;
	char *buf;

	ptr = STMemory_ReadLong(stack);
	len = STMemory_ReadLong(stack + SIZE_LONG);
	Dprintf(("NF name[%d](0x%x, %d)\n", subid, ptr, len));

	if (!STMemory_ValidArea(ptr, len)) {
		M68000_BusError(ptr, BUS_ERROR_WRITE);
		return false;
	}
	if (subid) {
		str = PROG_NAME;
	} else {
		str = "Hatari";
	}
	buf = (char *)STRAM_ADDR(ptr);
	*retval = snprintf(buf, len, "%s", str);
	return true;
}
예제 #10
0
파일: natfeats.c 프로젝트: r-type/hatari
/**
 * NF_NAME - emulator name
 * Stack arguments are:
 * - pointer to buffer for emulator name, and
 * - uint32_t for its size
 * If subid is set, emulator name includes also version information
 */
static bool nf_name(Uint32 stack, Uint32 subid, Uint32 *retval)
{
    Uint32 ptr, len;
    const char *str;
    char *buf;

    ptr = STMemory_ReadLong(stack);
    len = STMemory_ReadLong(stack + SIZE_LONG);
    LOG_TRACE(TRACE_NATFEATS, "NF_NAME[%d](0x%x, %d)\n", subid, ptr, len);

    if ( !STMemory_CheckAreaType ( ptr, len, ABFLAG_RAM | ABFLAG_ROM ) ) {
        M68000_BusError(ptr, BUS_ERROR_WRITE, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
        return false;
    }
    if (subid) {
        str = PROG_NAME;
    } else {
        str = "Hatari";
    }
    buf = (char *)STMemory_STAddrToPointer ( ptr );
    *retval = snprintf(buf, len, "%s", str);
    return true;
}
예제 #11
0
/**
 * BIOS Read/Write disk sector
 * Call 4
 */
static void Bios_RWabs(Uint32 Params)
{
	Uint32 pBuffer;
	Uint16 RWFlag, Number, RecNo, Dev;

	/* Read details from stack */
	RWFlag = STMemory_ReadWord(Params);
	pBuffer = STMemory_ReadLong(Params+SIZE_WORD);
	Number = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
	RecNo = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG+SIZE_WORD);
	Dev = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG+SIZE_WORD+SIZE_WORD);

	LOG_TRACE(TRACE_OS_BIOS, "BIOS 0x04 Rwabs(%d,0x%lX,%d,%d,%i)\n",
	          RWFlag, STRAM_ADDR(pBuffer), Number, RecNo, Dev);
}
예제 #12
0
파일: bios.c 프로젝트: hskinnemoen/hatari
/**
 * BIOS Read/Write disk sector
 * Call 4
 */
static bool Bios_RWabs(Uint32 Params)
{
	Uint32 pBuffer;
	Uint16 RWFlag, Number, RecNo, Dev;

	/* Read details from stack */
	RWFlag = STMemory_ReadWord(Params+SIZE_WORD);
	pBuffer = STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD);
	Number = STMemory_ReadWord(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG);
	RecNo = STMemory_ReadWord(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG+SIZE_WORD);
	Dev = STMemory_ReadWord(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG+SIZE_WORD+SIZE_WORD);

	HATARI_TRACE(HATARI_TRACE_OS_BIOS, "BIOS RWabs %i,%d,0x%lX,%d,%d\n",
			Dev, RWFlag, STRAM_ADDR(pBuffer), RecNo, Number);

	return FALSE;
}
예제 #13
0
파일: natfeats.c 프로젝트: denizt/hatari
static bool nf_stderr(Uint32 stack, Uint32 subid, Uint32 *retval)
{
	const char *str;
	Uint32 ptr;

	ptr = STMemory_ReadLong(stack);
	//Dprintf(("NF stderr(0x%x)\n", ptr));

	if (!STMemory_ValidArea(ptr, 1)) {
		M68000_BusError(ptr, BUS_ERROR_READ);
		return false;
	}
	str = (const char *)STRAM_ADDR(ptr);
	*retval = fprintf(stderr, "%s", str);
	fflush(stderr);
	return true;
}
예제 #14
0
파일: natfeats.c 프로젝트: r-type/hatari
/**
 * NF_STDERR - print string to stderr
 * Stack arguments are:
 * - pointer to buffer containing the string
 */
static bool nf_stderr(Uint32 stack, Uint32 subid, Uint32 *retval)
{
    const char *str;
    Uint32 ptr;

    ptr = STMemory_ReadLong(stack);
    LOG_TRACE(TRACE_NATFEATS, "NF_STDERR(0x%x)\n", ptr);

    if ( !STMemory_CheckAreaType ( ptr, 1, ABFLAG_RAM | ABFLAG_ROM ) ) {
        M68000_BusError(ptr, BUS_ERROR_READ, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
        return false;
    }
    str = (const char *)STMemory_STAddrToPointer ( ptr );
    *retval = fprintf(stderr, "%s", str);
    fflush(stderr);
    return true;
}
예제 #15
0
파일: natfeats.c 프로젝트: r-type/hatari
/**
 * NF_COMMAND - execute Hatari (cli / debugger) command
 * Stack arguments are:
 * - pointer to command string
 */
static bool nf_command(Uint32 stack, Uint32 subid, Uint32 *retval)
{
    const char *buffer;
    Uint32 ptr;

    ptr = STMemory_ReadLong(stack);

    if ( !STMemory_CheckAreaType ( ptr, 1, ABFLAG_RAM | ABFLAG_ROM ) ) {
        M68000_BusError(ptr, BUS_ERROR_READ, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
        return false;
    }
    buffer = (const char *)STMemory_STAddrToPointer ( ptr );
    LOG_TRACE(TRACE_NATFEATS, "NF_COMMAND(0x%x \"%s\")\n", ptr, buffer);

    Control_ProcessBuffer(buffer);
    return true;
}
예제 #16
0
파일: xbios.c 프로젝트: diablodiab/hatari
/**
 * XBIOS Floppy Write
 * Call 9
 */
static bool XBios_Flopwr(Uint32 Params)
{
	Uint32 pBuffer;
	Uint16 Dev,Sector,Side,Track,Count;

	/* Read details from stack */
	pBuffer = STMemory_ReadLong(Params);
	Dev = STMemory_ReadWord(Params+SIZE_LONG+SIZE_LONG); /* skip reserved long */
	Sector = STMemory_ReadWord(Params+SIZE_LONG+SIZE_LONG+SIZE_WORD);
	Track = STMemory_ReadWord(Params+SIZE_LONG+SIZE_LONG+SIZE_WORD+SIZE_WORD);
	Side = STMemory_ReadWord(Params+SIZE_LONG+SIZE_LONG+SIZE_WORD+SIZE_WORD+SIZE_WORD);
	Count = STMemory_ReadWord(Params+SIZE_LONG+SIZE_LONG+SIZE_WORD+SIZE_WORD+SIZE_WORD+SIZE_WORD);

	LOG_TRACE(TRACE_OS_XBIOS, "XBIOS 0x09 Flopwr(0x%x, %d, %d, %d, %d, %d) at PC 0x%X for: %s\n",
		  pBuffer, Dev, Sector, Track, Side, Count,
		  M68000_GetPC(), EmulationDrives[Dev].sFileName);
	return false;
}
예제 #17
0
파일: natfeats.c 프로젝트: denizt/hatari
/**
 * Do given Native Feature, if it is supported
 * and set 'retval' accordingly.
 * 
 * Return true if caller is to proceed normally,
 * false if there was an exception.
 */
bool NatFeat_Call(Uint32 stack, bool super, Uint32 *retval)
{
	Uint32 subid = STMemory_ReadLong(stack);
	unsigned int idx = MASTERID2IDX(subid);
	subid = MASKOUTMASTERID(subid);

	if (idx >= ARRAYSIZE(features)) {
		Dprintf(("ERROR: invalid NF ID %d requested\n", idx));
		return true; /* undefined */
	}
	if (features[idx].super && !super) {
		Dprintf(("ERROR: NF function %d called without supervisor mode\n", idx));
		Exception(8, 0, M68000_EXC_SRC_CPU);
		return false;
	}
	stack += SIZE_LONG;
	return features[idx].cb(stack, subid, retval);
}
예제 #18
0
파일: hatari-glue.c 프로젝트: r-type/hatari
/**
 * This function will be called at system init by the cartridge routine
 * (after gemdos init, before booting floppies).
 * The GEMDOS vector (#$84) is setup and we also initialize the connected
 * drive mask and Line-A  variables (for an extended VDI resolution) from here.
 */
unsigned long OpCode_SysInit(uae_u32 opcode)
{
	/* Add any drives mapped by TOS in the interim */
	ConnectedDriveMask |= STMemory_ReadLong(0x4c2);
	/* Initialize the connected drive mask */
	STMemory_WriteLong(0x4c2, ConnectedDriveMask);

	if (!bInitGemDOS)
	{
		/* Init on boot - see cart.c */
		GemDOS_Boot();

		/* Update LineA for extended VDI res
		 * D0: LineA base, A1: Font base
		 */
		VDI_LineA(regs.regs[0], regs.regs[9]);
	}

	CpuDoNOP ();
	return 4;
}
예제 #19
0
파일: natfeats.c 프로젝트: r-type/hatari
/**
 * Do given Native Feature, if it is supported
 * and set 'retval' accordingly.
 *
 * Return true if caller is to proceed normally,
 * false if there was an exception.
 */
bool NatFeat_Call(Uint32 stack, bool super, Uint32 *retval)
{
    Uint32 subid = STMemory_ReadLong(stack);
    unsigned int idx = MASTERID2IDX(subid);
    subid = MASKOUTMASTERID(subid);

    if (idx >= ARRAYSIZE(features)) {
        LOG_TRACE(TRACE_NATFEATS, "ERROR: invalid NF ID %d requested\n", idx);
        return true; /* undefined */
    }
    if (features[idx].super && !super) {
        LOG_TRACE(TRACE_NATFEATS, "ERROR: NF function %d called without supervisor mode\n", idx);
#ifndef WINUAE_FOR_HATARI
        M68000_Exception(8, M68000_EXC_SRC_CPU);
#else
        M68000_Exception(8, M68000_EXC_SRC_CPU);
#endif
        return false;
    }
    stack += SIZE_LONG;
    return features[idx].cb(stack, subid, retval);
}
예제 #20
0
/**
 * DebugInfo_CurrentBasepage: get and validate currently running program basepage.
 * if given sysbase is zero, use system sysbase.
 */
static Uint32 DebugInfo_CurrentBasepage(Uint32 sysbase)
{
	Uint32 basepage;
	Uint16 osversion, osconf;

	if (!sysbase) {
		Uint32 rombase;
		sysbase = DebugInfo_GetSysbase(&rombase);
		if (!sysbase) {
			return 0;
		}
	}
	osversion = STMemory_ReadWord(sysbase+0x02);
	if (osversion >= 0x0102) {
		basepage = STMemory_ReadLong(sysbase+0x28);
	} else {
		osconf = STMemory_ReadWord(sysbase+0x1C);
		if((osconf>>1) == COUNTRY_SPAIN) {
			basepage = 0x873C;
		} else {
			basepage = 0x602C;
		}
	}
예제 #21
0
/**
 * Set default memory configuration, connected floppies, memory size and
 * clear the ST-RAM area.
 * As TOS checks hardware for memory size + connected devices on boot-up
 * we set these values ourselves and fill in the magic numbers so TOS
 * skips these tests.
 */
void STMemory_SetDefaultConfig(void)
{
	int i;
	int screensize, limit;
	int memtop, phystop;
	Uint8 nMemControllerByte;
	Uint8 nFalcSysCntrl;

	static const int MemControllerTable[] =
	{
		0x01,   /* 512 KiB */
		0x05,   /* 1 MiB */
		0x02,   /* 2 MiB */
		0x06,   /* 2.5 MiB */
		0x0A    /* 4 MiB */
	};

	if (bRamTosImage)
	{
		/* Clear ST-RAM, excluding the RAM TOS image */
		STMemory_Clear(0x00000000, TosAddress);
		STMemory_Clear(TosAddress+TosSize, STRamEnd);
	}
	else
	{
		/* Clear whole ST-RAM */
		STMemory_Clear(0x00000000, STRamEnd);
	}

	/* Mirror ROM boot vectors */
	STMemory_WriteLong(0x00, STMemory_ReadLong(TosAddress));
	STMemory_WriteLong(0x04, STMemory_ReadLong(TosAddress+4));

	/* Fill in magic numbers to bypass TOS' memory tests for faster boot or
	 * if VDI resolution is enabled or if more than 4 MB of ram are used
	 * or if TT RAM added in Falcon mode.
	 * (for highest compatibility, those tests should not be bypassed in
	 *  the common STF/STE cases as some programs like "Yolanda" rely on
	 *  the RAM content after those tests) */
	if ( ConfigureParams.System.bFastBoot
	  || bUseVDIRes
	  || ( ConfigureParams.Memory.nMemorySize > 4 && !bIsEmuTOS )
	  || ( ( ConfigureParams.System.nMachineType == MACHINE_FALCON ) && TTmemory ) )
	{
		/* Write magic values to sysvars to signal valid config */
		STMemory_WriteLong(0x420, 0x752019f3);    /* memvalid */
		STMemory_WriteLong(0x43a, 0x237698aa);    /* memval2 */
		STMemory_WriteLong(0x51a, 0x5555aaaa);    /* memval3 */

		/* If ST RAM detection is bypassed, we must also force TT RAM config if enabled */
		if ( TTmemory )
			STMemory_WriteLong ( 0x5a4 , 0x01000000 + TTmem_size );		/* ramtop */
		else
			STMemory_WriteLong ( 0x5a4 , 0 );		/* ramtop */
		STMemory_WriteLong ( 0x5a8 , 0x1357bd13 );		/* ramvalid */

		/* On Falcon, set bit6=1 at $ff8007 to simulate a warm start */
		/* (else memory detection is not skipped after a cold start/reset) */
		if ( ConfigureParams.System.nMachineType == MACHINE_FALCON )
			STMemory_WriteByte ( 0xff8007, IoMem_ReadByte(0xff8007) | 0x40 );

		/* On TT, set bit0=1 at $ff8e09 to simulate a warm start */
		/* (else memory detection is not skipped after a cold start/reset) */
		if ( ConfigureParams.System.nMachineType == MACHINE_TT )
			STMemory_WriteByte ( 0xff8e09, IoMem_ReadByte(0xff8e09) | 0x01 );
	}

	/* Set memory size, adjust for extra VDI screens if needed. */
	screensize = VDIWidth * VDIHeight / 8 * VDIPlanes;
	/* Use 32 kiB in normal screen mode or when the screen size is smaller than 32 kiB */
	if (!bUseVDIRes || screensize < 0x8000)
		screensize = 0x8000;
	/* mem top - upper end of user memory (right before the screen memory)
	 * memtop / phystop must be dividable by 512 or TOS crashes */
	memtop = (STRamEnd - screensize) & 0xfffffe00;
	/* phys top - 32k gap causes least issues with apps & TOS
	 * as that's the largest _common_ screen size. EmuTOS behavior
	 * depends on machine type.
	 *
	 * TODO: what to do about _native_ TT & Videl resolutions
	 * which size is >32k?  Should memtop be adapted also for
	 * those?
	 */
	switch (ConfigureParams.System.nMachineType)
	{
	case MACHINE_FALCON:
		/* TOS v4 doesn't work with VDI mode (yet), and
		 * EmuTOS works with correct gap, so use that */
		phystop = STRamEnd;
		break;
	case MACHINE_TT:
		/* For correct TOS v3 memory detection, phystop should be
		 * at the end of memory, not at memtop + 32k.
		 *
		 * However:
		 * - TOS v3 crashes/hangs if phystop-memtop gap is larger
		 *   than largest real HW screen size (150k)
		 * - NVDI hangs if gap is larger than 32k in any other than
		 *   monochrome mode
		 */
		if (VDIPlanes == 1)
			limit = 1280*960/8;
		else
			limit = 0x8000;
		if (screensize > limit)
		{
			phystop = memtop + limit;
			fprintf(stderr, "WARNING: too large VDI mode for TOS v3 memory detection to work correctly!\n");
		}
		else
			phystop = STRamEnd;
		break;
	default:
		phystop = memtop + 0x8000;
	}
	STMemory_WriteLong(0x436, memtop);
	STMemory_WriteLong(0x42e, phystop);
	if (bUseVDIRes)
		fprintf(stderr, "VDI mode memtop: 0x%x, phystop: 0x%x (screensize: %d kB, memtop->phystop: %d kB)\n",
			memtop, phystop, (screensize+511) / 1024, (phystop-memtop+511) / 1024);

	/* Set memory controller byte according to different memory sizes */
	/* Setting per bank: %00=128k %01=512k %10=2Mb %11=reserved. - e.g. %1010 means 4Mb */
	if (ConfigureParams.Memory.nMemorySize <= 4)
		nMemControllerByte = MemControllerTable[ConfigureParams.Memory.nMemorySize];
	else
		nMemControllerByte = 0x0f;
	STMemory_WriteByte(0x424, nMemControllerByte);
	IoMem_WriteByte(0xff8001, nMemControllerByte);

	if (ConfigureParams.System.nMachineType == MACHINE_FALCON)
	{
		/* Set the Falcon memory and monitor configuration register:

		         $ffff8006.b [R]  76543210  Monitor-memory
		                          ||||||||
		                          |||||||+- RAM Wait Status
		                          |||||||   0 =  1 Wait (default)
		                          |||||||   1 =  0 Wait
		                          ||||||+-- Video Bus size ???
		                          ||||||    0 = 16 Bit
		                          ||||||    1 = 32 Bit (default)
		                          ||||++--- ROM Wait Status
		                          ||||      00 = Reserved
		                          ||||      01 =  2 Wait (default)
		                          ||||      10 =  1 Wait
		                          ||||      11 =  0 Wait
		                          ||++----- Falcon Memory
		                          ||        00 =  1 MB
		                          ||        01 =  4 MB
		                          ||        10 = 14 MB
		                          ||        11 = no boot !
		                          ++------- Monitor-Typ
		                                    00 - Monochrome (SM124)
		                                    01 - Color (SC1224)
		                                    10 - VGA Color
		                                    11 - Television

		Bit 1 seems not to be well documented. It's used by TOS at bootup to compute the memory size.
		After some tests, I get the following RAM values (Bits 5, 4, 1 are involved) :

		00 =  512 Ko	20 = 8192 Ko
		02 = 1024 Ko	22 = 14366 Ko
		10 = 2048 Ko	30 = Illegal
		12 = 4096 Ko	32 = Illegal

		I use these values for Hatari's emulation.
		I also set the bit 3 and 2 at value 01 are mentioned in the register description.
		*/

		if (ConfigureParams.Memory.nMemorySize == 14)     /* 14 Meg */
			nFalcSysCntrl = 0x26;
		else if (ConfigureParams.Memory.nMemorySize == 8) /* 8 Meg */
			nFalcSysCntrl = 0x24;
		else if (ConfigureParams.Memory.nMemorySize == 4) /* 4 Meg */
			nFalcSysCntrl = 0x16;
		else if (ConfigureParams.Memory.nMemorySize == 2) /* 2 Meg */
			nFalcSysCntrl = 0x14;
		else if (ConfigureParams.Memory.nMemorySize == 1) /* 1 Meg */
			nFalcSysCntrl = 0x06;
		else
			nFalcSysCntrl = 0x04;                     /* 512 Ko */

		switch(ConfigureParams.Screen.nMonitorType) {
			case MONITOR_TYPE_TV:
				nFalcSysCntrl |= FALCON_MONITOR_TV;
				break;
			case MONITOR_TYPE_VGA:
				nFalcSysCntrl |= FALCON_MONITOR_VGA;
				break;
			case MONITOR_TYPE_RGB:
				nFalcSysCntrl |= FALCON_MONITOR_RGB;
				break;
			case MONITOR_TYPE_MONO:
				nFalcSysCntrl |= FALCON_MONITOR_MONO;
				break;
		}
		STMemory_WriteByte(0xff8006, nFalcSysCntrl);
	}

	/* Set TOS floppies */
	STMemory_WriteWord(0x446, nBootDrive);          /* Boot up on A(0) or C(2) */

	/* Create connected drives mask (only for harddrives, don't change floppy drive detected by TOS) */
	ConnectedDriveMask = STMemory_ReadLong(0x4c2);  // Get initial drive mask (see what TOS thinks)
	if (GEMDOS_EMU_ON)
	{
		for (i = 0; i < MAX_HARDDRIVES; i++)
		{
			if (emudrives[i] != NULL)     // Is this GEMDOS drive enabled?
				ConnectedDriveMask |= (1 << emudrives[i]->drive_number);
		}
	}
	/* Set connected drives system variable.
	 * NOTE: some TOS images overwrite this value, see 'OpCode_SysInit', too */
	STMemory_WriteLong(0x4c2, ConnectedDriveMask);
}
예제 #22
0
파일: xbios.c 프로젝트: diablodiab/hatari
/**
 * Check if we need to re-direct XBios call to our own routines
 */
bool XBios(void)
{
	Uint32 Params;
	Uint16 XBiosCall;

	/* Find call */
	Params = Regs[REG_A7];
	XBiosCall = STMemory_ReadWord(Params);
	Params += SIZE_WORD;

	switch (XBiosCall)
	{
		/* commands with special handling */
	case 8:
		return XBios_Floprd(Params);
	case 9:
		return XBios_Flopwr(Params);
	case 15:
		return XBios_Rsconf(Params);
	case 20:
		return XBios_Scrdmp(Params);
	case 139:
		return XBios_Devconnect(Params);
	case HATARI_CONTROL_OPCODE:
		return XBios_HatariControl(Params);

	case 2:		/* Physbase */
	case 3:		/* Logbase */
	case 4:		/* Getrez */
	case 17:	/* Random */
	case 23:	/* Gettime */
	case 24:	/* Bioskeys */
	case 34:	/* Kbdvbase */
	case 37:	/* Vsync */
	case 39:	/* Puntaes */
	case 81:	/* EgetShift */
	case 89:	/* VgetMonitor */
	case 103:	/* Dsp_GetWordSize */
	case 104:	/* Dsp_Lock */
	case 105:	/* Dsp_Unlock */
	case 113:	/* Dsp_RequestUniqueAbility */
	case 114:	/* Dsp_GetProgAbility */
	case 115:	/* Dsp_FlushSubroutines */
	case 121:	/* Dsp_Hf2 */
	case 122:	/* Dsp_Hf3 */
	case 125:	/* Dsp_Hstat */
	case 128:	/* Locksnd */
	case 129:	/* Unlocksnd */
		/* commands with no args */
		LOG_TRACE(TRACE_OS_XBIOS, "XBIOS 0x%02hX %s() at PC 0x%X\n",
			  XBiosCall, XBios_Call2Name(XBiosCall),
			  M68000_GetPC());
		return false;
		
	case 1:		/* Ssbrk */
	case 14:	/* Iorec */
	case 26:	/* Jdisint */
	case 27:	/* Jenabint */
	case 29:	/* Offgibit */
	case 30:	/* Ongibit */
	case 33:	/* Setprt */
	case 44:	/* Bconmap */
	case 64:	/* Blitmode */
	case 80:	/* EsetShift */
	case 82:	/* EsetBank */
	case 86:	/* EsetGray */
	case 87:	/* EsetSmear */
	case 88:	/* VsetMode */
	case 90:	/* VsetSync */
	case 91:	/* VgetSize */
	case 102:	/* Dsp_RemoveInterrupts */
	case 112:	/* Dsp_TriggerHC */
	case 117:	/* Dsp_InqSubrAbility */
	case 118:	/* Dsp_RunSubroutine */
	case 119:	/* Dsp_Hf0 */
	case 120:	/* Dsp_Hf1 */
	case 132:	/* Setmode */
	case 134:	/* Setmontracks */
	case 136:	/* Buffoper */
	case 140:	/* Sndstatus */
		/* ones taking single word */
		LOG_TRACE(TRACE_OS_XBIOS, "XBIOS 0x%02hX %s(0x%hX) at PC 0x%X\n",
			  XBiosCall, XBios_Call2Name(XBiosCall),
			  STMemory_ReadWord(Params),
			  M68000_GetPC());
		return false;

	case 6:		/* Setpalette */
	case 22:	/* Settime */
	case 32:	/* Dosound */
	case 36:	/* Ptrblt */
	case 38:	/* Supexec */
	case 48:	/* Metainit */
	case 141:	/* Buffptr */
		/* ones taking long or pointer */
		LOG_TRACE(TRACE_OS_XBIOS, "XBIOS 0x%02hX %s(0x%X) at PC 0x%X\n",
			  XBiosCall, XBios_Call2Name(XBiosCall),
			  STMemory_ReadLong(Params),
			  M68000_GetPC());
		return false;

	case 7:		/* Setcolor */
	case 21:	/* Cursconf */
	case 28:	/* Giaccess */
	case 35:	/* Kbrate */
	case 41:	/* Floprate */
	case 83:	/* EsetColor */
	case 130:	/* Soundcmd */
	case 133:	/* Settracks */
	case 137:	/* Dsptristate */
	case 135:	/* Setinterrupt */
	case 138:	/* Gpio */
		/* ones taking two words */
		LOG_TRACE(TRACE_OS_XBIOS, "XBIOS 0x%02hX %s(0x%hX, 0x%hX) at PC 0x%X\n",
			  XBiosCall, XBios_Call2Name(XBiosCall),
			  STMemory_ReadWord(Params),
			  STMemory_ReadWord(Params+SIZE_WORD),
			  M68000_GetPC());
		return false;

	case 12:	/* Midiws */
	case 13:	/* Mfpint */
	case 25:	/* Ikbdws */
		/* ones taking word length/index and pointer */
		LOG_TRACE(TRACE_OS_XBIOS, "XBIOS 0x%02hX %s(%hd, 0x%X) at PC 0x %X\n",
			  XBiosCall, XBios_Call2Name(XBiosCall),
			  STMemory_ReadWord(Params),
			  STMemory_ReadLong(Params+SIZE_WORD),
			  M68000_GetPC());
		return false;

	case 11:	/* Dbmsg */
	case 84:	/* EsetPalette */
	case 85:	/* EgetPalette */
	case 93:	/* VsetRGB */
	case 94:	/* VgetRGB */
		/* ones taking word, word and long/pointer */
		LOG_TRACE(TRACE_OS_XBIOS, "XBIOS 0x%02hX %s(0x%hX, 0x%hX, 0x%X) at PC 0x%X\n",
			  XBiosCall, XBios_Call2Name(XBiosCall),
			  STMemory_ReadWord(Params),
			  STMemory_ReadWord(Params+SIZE_WORD),
			  STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD),
			  M68000_GetPC());
		return false;

	case 106:	/* Dsp_Available */
	case 107:	/* Dsp_Reserve */
	case 111:	/* Dsp_LodToBinary */
	case 126:	/* Dsp_SetVectors */
		/* ones taking two longs/pointers */
		LOG_TRACE(TRACE_OS_XBIOS, "XBIOS 0x%02hX %s(0x%X, 0x%X) at PC 0x%X\n",
			  XBiosCall, XBios_Call2Name(XBiosCall),
			  STMemory_ReadLong(Params),
			  STMemory_ReadLong(Params+SIZE_LONG),
			  M68000_GetPC());
		return false;

	case 5:		/* Setscreen */
		if (STMemory_ReadWord(Params+SIZE_LONG+SIZE_LONG) == 3) {
			/* actually VSetscreen with extra parameter */
			LOG_TRACE(TRACE_OS_XBIOS, "XBIOS 0x%02hX VsetScreen(0x%X, 0x%X, 3, 0x%hX) at PC 0x%X\n",
				  XBiosCall, STMemory_ReadLong(Params),
				  STMemory_ReadLong(Params+SIZE_LONG),
				  STMemory_ReadWord(Params+SIZE_LONG+SIZE_LONG+SIZE_WORD),
				  M68000_GetPC());
			return false;			
		}
	case 109:	/* Dsp_ExecProg */
	case 110:	/* Dsp_ExecBoot */
	case 116:	/* Dsp_LoadSubroutine */
	case 150:	/* VsetMask */
		/* ones taking two longs/pointers and a word */
		LOG_TRACE(TRACE_OS_XBIOS, "XBIOS 0x%02hX %s(0x%X, 0x%X, 0x%hX) at PC 0x%X\n",
			  XBiosCall, XBios_Call2Name(XBiosCall),
			  STMemory_ReadLong(Params),
			  STMemory_ReadLong(Params+SIZE_LONG),
			  STMemory_ReadWord(Params+SIZE_LONG+SIZE_LONG),
			  M68000_GetPC());
		return false;

	default:  /* rest of XBios calls */
		LOG_TRACE(TRACE_OS_XBIOS, "XBIOS 0x%02hX (%s)\n",
			  XBiosCall, XBios_Call2Name(XBiosCall));
		return false;
	}
}
예제 #23
0
/**
 * Check whether this is VDI/AES call and see if we need to re-direct
 * it to our own routines. Return true if VDI_Complete() function
 * needs to be called on OS call exit, otherwise return false.
 *
 * We enter here with Trap #2, so D0 tells which OS call it is (VDI/AES)
 * and D1 is pointer to VDI/AES vectors, i.e. Control, Intin, Ptsin etc...
 */
bool VDI_AES_Entry(void)
{
	Uint16 call = Regs[REG_D0];
	Uint32 TablePtr = Regs[REG_D1];

#if ENABLE_TRACING
	/* AES call? */
	if (call == 0xC8)
	{
		if (!STMemory_ValidArea(TablePtr, 24))
		{
			Log_Printf(LOG_WARN, "AES call failed due to invalid parameter block address 0x%x+%i\n", TablePtr, 24);
			return false;
		}
		/* store values for debugger "info aes" command */
		AESControl = STMemory_ReadLong(TablePtr);
		AESGlobal  = STMemory_ReadLong(TablePtr+4);
		AESIntin   = STMemory_ReadLong(TablePtr+8);
		AESIntout  = STMemory_ReadLong(TablePtr+12);
		AESAddrin  = STMemory_ReadLong(TablePtr+16);
		AESAddrout = STMemory_ReadLong(TablePtr+20);
		AESOpCode  = STMemory_ReadWord(AESControl);
		LOG_TRACE(TRACE_OS_AES, "AES call %3hd (%s)\n",
			  AESOpCode, AES_Opcode2Name(AESOpCode));

		/* using same special opcode trick doesn't work for
		 * both VDI & AES as AES functions can be called
		 * recursively and VDI calls happen inside AES calls.
		 */
		return false;
	}
#endif

	/* VDI call? */
	if (call == 0x73)
	{
		if (!STMemory_ValidArea(TablePtr, 20))
		{
			Log_Printf(LOG_WARN, "VDI call failed due to invalid parameter block address 0x%x+%i\n", TablePtr, 20);
			return false;
		}
		/* store values for extended VDI resolution handling
		 * and debugger "info vdi" command
		 */
		VDIControl = STMemory_ReadLong(TablePtr);
		VDIIntin   = STMemory_ReadLong(TablePtr+4);
		VDIPtsin   = STMemory_ReadLong(TablePtr+8);
		VDIIntout  = STMemory_ReadLong(TablePtr+12);
		VDIPtsout  = STMemory_ReadLong(TablePtr+16);
		VDIOpCode  = STMemory_ReadWord(VDIControl);
#if ENABLE_TRACING
		{
		Uint16 subcode = STMemory_ReadWord(VDIControl+2*5);
		LOG_TRACE(TRACE_OS_VDI, "VDI call %3hd/%3hd (%s)\n",
			  VDIOpCode, subcode,
			  VDI_Opcode2Name(VDIOpCode, subcode));
		}
#endif
		/* Only workstation open needs to be handled at trap return */
		return bUseVDIRes && VDI_isWorkstationOpen(VDIOpCode);
	}

	LOG_TRACE((TRACE_OS_VDI|TRACE_OS_AES), "Trap #2 with D0 = 0x%hX\n", call);
	return false;
}
예제 #24
0
파일: vdi.c 프로젝트: libretro/hatari
/**
 * Output AES call info, including some of args
 */
static void AES_OpcodeInfo(FILE *fp, Uint16 opcode)
{
	int code = opcode - 10;
	fprintf(fp, "AES call %3hd ", opcode);
	if (code >= 0 && code < ARRAYSIZE(AESName_10) && AESName_10[code])
	{
		bool first = true;
		int i, items;

		fprintf(fp, "%s(", AESName_10[code]);

		items = 0;
		/* there are so few of these that linear search is fine */
		for (i = 0; i < ARRAYSIZE(AESStrings); i++)
		{
			/* something that can be shown? */
			if (AESStrings[i].code == opcode)
			{
				items = AESStrings[i].count;
				break;
			}
		}
		/* addrin array size in longs enough for items? */
		if (items > 0 && items <= STMemory_ReadWord(AESControl+SIZE_WORD*3))
		{
			const char *str;
			fputs("addrin: ", fp);
			for (i = 0; i < items; i++)
			{
				if (first)
					first = false;
				else
					fputs(", ", fp);
				str = (const char *)STRAM_ADDR(STMemory_ReadLong(AESAddrin+SIZE_LONG*i));
				fprintf(fp, "\"%s\"", str);
			}
		}
		/* intin array size in words */
		items = STMemory_ReadWord(AESControl+SIZE_WORD*1);
		if (items > 0)
		{
			if (!first)
			{
				fputs(", ", fp);
				first = true;
			}
			fputs("intin: ", fp);
			for (i = 0; i < items; i++)
			{
				if (first)
					first = false;
				else
					fputs(",", fp);
				fprintf(fp, "0x%x", STMemory_ReadWord(AESIntin+SIZE_WORD*i));
			}
		}
		fputs(")\n", fp);
	}
	else
		fputs("???\n", fp);
	fflush(fp);
}
예제 #25
0
파일: stMemory.c 프로젝트: denizt/hatari
/**
 * Set default memory configuration, connected floppies, memory size and
 * clear the ST-RAM area.
 * As TOS checks hardware for memory size + connected devices on boot-up
 * we set these values ourselves and fill in the magic numbers so TOS
 * skips these tests.
 */
void STMemory_SetDefaultConfig(void)
{
	int i;
	int screensize;
	int memtop;
	Uint8 nMemControllerByte;
	Uint8 nFalcSysCntrl;

	static const int MemControllerTable[] =
	{
		0x01,   /* 512 KiB */
		0x05,   /* 1 MiB */
		0x02,   /* 2 MiB */
		0x06,   /* 2.5 MiB */
		0x0A    /* 4 MiB */
	};

	if (bRamTosImage)
	{
		/* Clear ST-RAM, excluding the RAM TOS image */
		STMemory_Clear(0x00000000, TosAddress);
		STMemory_Clear(TosAddress+TosSize, STRamEnd);
	}
	else
	{
		/* Clear whole ST-RAM */
		STMemory_Clear(0x00000000, STRamEnd);
	}

	/* Mirror ROM boot vectors */
	STMemory_WriteLong(0x00, STMemory_ReadLong(TosAddress));
	STMemory_WriteLong(0x04, STMemory_ReadLong(TosAddress+4));

	/* Fill in magic numbers to bypass TOS' memory tests for faster boot or
	 * if VDI resolution is enabled or if more than 4 MB of ram are used.
	 * (for highest compatibility, those tests should not be bypassed in
	 *  the common STF/STE cases as some programs like "Yolanda" rely on
	 *  the RAM content after those tests) */
	if (ConfigureParams.System.bFastBoot || bUseVDIRes
	    || (ConfigureParams.Memory.nMemorySize > 4 && !bIsEmuTOS))
	{
		/* Write magic values to sysvars to signal valid config */
		STMemory_WriteLong(0x420, 0x752019f3);    /* memvalid */
		STMemory_WriteLong(0x43a, 0x237698aa);    /* memval2 */
		STMemory_WriteLong(0x51a, 0x5555aaaa);    /* memval3 */
	}

	/* Set memory size, adjust for extra VDI screens if needed.
	 * Note: TOS seems to set phys_top-0x8000 as the screen base
	 * address - so we have to move phys_top down in VDI resolution
	 * mode, although there is more "physical" ST RAM available. */
	screensize = VDIWidth * VDIHeight / 8 * VDIPlanes;
	/* Use 32 kiB in normal screen mode or when the screen size is smaller than 32 kiB */
	if (!bUseVDIRes || screensize < 0x8000)
		screensize = 0x8000;
	/* mem top - upper end of user memory (right before the screen memory).
	 * Note: memtop / phystop must be dividable by 512, or TOS crashes */
	memtop = (STRamEnd - screensize) & 0xfffffe00;
	STMemory_WriteLong(0x436, memtop);
	/* phys top - This must be memtop + 0x8000 to make TOS happy */
	STMemory_WriteLong(0x42e, memtop+0x8000);

	/* Set memory controller byte according to different memory sizes */
	/* Setting per bank: %00=128k %01=512k %10=2Mb %11=reserved. - e.g. %1010 means 4Mb */
	if (ConfigureParams.Memory.nMemorySize <= 4)
		nMemControllerByte = MemControllerTable[ConfigureParams.Memory.nMemorySize];
	else
		nMemControllerByte = 0x0f;
	STMemory_WriteByte(0x424, nMemControllerByte);
	IoMem_WriteByte(0xff8001, nMemControllerByte);

	if (ConfigureParams.System.nMachineType == MACHINE_FALCON)
	{
		/* Set the Falcon memory and monitor configuration register:

		         $ffff8006.b [R]  76543210  Monitor-memory
		                          ||||||||
		                          |||||||+- RAM Wait Status
		                          |||||||   0 =  1 Wait (default)
		                          |||||||   1 =  0 Wait
		                          ||||||+-- Video Bus size ???
		                          ||||||    0 = 16 Bit
		                          ||||||    1 = 32 Bit (default)
		                          ||||++--- ROM Wait Status
		                          ||||      00 = Reserved
		                          ||||      01 =  2 Wait (default)
		                          ||||      10 =  1 Wait
		                          ||||      11 =  0 Wait
		                          ||++----- Falcon Memory
		                          ||        00 =  1 MB
		                          ||        01 =  4 MB
		                          ||        10 = 14 MB
		                          ||        11 = no boot !
		                          ++------- Monitor-Typ
		                                    00 - Monochrome (SM124)
		                                    01 - Color (SC1224)
		                                    10 - VGA Color
		                                    11 - Television

		Bit 1 seems not to be well documented. It's used by TOS at bootup to compute the memory size.
		After some tests, I get the following RAM values (Bits 5, 4, 1 are involved) :

		00 =  512 Ko	20 = 8192 Ko
		02 = 1024 Ko	22 = 14366 Ko
		10 = 2048 Ko	30 = Illegal
		12 = 4096 Ko	32 = Illegal

		I use these values for Hatari's emulation.
		I also set the bit 3 and 2 at value 01 are mentioned in the register description.
		*/

		if (ConfigureParams.Memory.nMemorySize == 14)     /* 14 Meg */
			nFalcSysCntrl = 0x26;
		else if (ConfigureParams.Memory.nMemorySize == 8) /* 8 Meg */
			nFalcSysCntrl = 0x24;
		else if (ConfigureParams.Memory.nMemorySize == 4) /* 4 Meg */
			nFalcSysCntrl = 0x16;
		else if (ConfigureParams.Memory.nMemorySize == 2) /* 2 Meg */
			nFalcSysCntrl = 0x14;
		else if (ConfigureParams.Memory.nMemorySize == 1) /* 1 Meg */
			nFalcSysCntrl = 0x06;
		else
			nFalcSysCntrl = 0x04;                     /* 512 Ko */

		switch(ConfigureParams.Screen.nMonitorType) {
			case MONITOR_TYPE_TV:
				nFalcSysCntrl |= FALCON_MONITOR_TV;
				break;
			case MONITOR_TYPE_VGA:
				nFalcSysCntrl |= FALCON_MONITOR_VGA;
				break;
			case MONITOR_TYPE_RGB:
				nFalcSysCntrl |= FALCON_MONITOR_RGB;
				break;
			case MONITOR_TYPE_MONO:
				nFalcSysCntrl |= FALCON_MONITOR_MONO;
				break;
		}
		STMemory_WriteByte(0xff8006, nFalcSysCntrl);
	}

	/* Set TOS floppies */
	STMemory_WriteWord(0x446, nBootDrive);          /* Boot up on A(0) or C(2) */

	/* Create connected drives mask: */
	ConnectedDriveMask = STMemory_ReadLong(0x4c2);  // Get initial drive mask (see what TOS thinks)
	ConnectedDriveMask |= 0x03;                     // Always use A: and B:
	if (GEMDOS_EMU_ON)
	{
		for (i = 0; i < MAX_HARDDRIVES; i++)
		{
			if (emudrives[i] != NULL)     // Is this GEMDOS drive enabled?
				ConnectedDriveMask |= (1 << emudrives[i]->drive_number);
		}
	}
	/* Set connected drives system variable.
	 * NOTE: some TOS images overwrite this value, see 'OpCode_SysInit', too */
	STMemory_WriteLong(0x4c2, ConnectedDriveMask);
}