/** * 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; }
/** * 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; }
/** * 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; }
/* 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
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; }
/** * 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; }
/** * 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); }
/** * 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; }
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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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); }
/** * 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; }
/** * 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); }
/** * 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; } }
/** * 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); }
/** * 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; } }
/** * 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; }
/** * 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); }
/** * 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); }