mirror of
https://github.com/joncampbell123/dosbox-x.git
synced 2025-05-08 02:53:03 +08:00
485 lines
15 KiB
C++
485 lines
15 KiB
C++
/*
|
|
* Copyright (C) 2002-2021 The DOSBox Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
|
|
#ifndef DOSBOX_DOSBOX_H
|
|
#define DOSBOX_DOSBOX_H
|
|
|
|
#if !defined (WIN32)
|
|
/* for mkdir_p, needed by emscripten */
|
|
#include <sys/stat.h>
|
|
#endif
|
|
#include <algorithm>
|
|
#include <functional>
|
|
#include <map>
|
|
#include <sstream>
|
|
#include <vector>
|
|
|
|
#include "clockdomain.h"
|
|
#include "config.h"
|
|
|
|
#if defined(OS2) && defined(C_SDL2)
|
|
#undef VERSION
|
|
#endif
|
|
|
|
#if defined(C_HAVE_LINUX_KVM) && (C_TARGETCPU == X86 || C_TARGETCPU == X86_64)
|
|
# define C_HAVE_LINUX_KVM_X86
|
|
#endif
|
|
|
|
#if defined(C_ICONV)
|
|
/* good */
|
|
#elif defined(C_ICONV_WIN32)
|
|
/* good */
|
|
#else
|
|
/* auto-pick */
|
|
#if defined(_WIN32) || defined(WINDOWS)
|
|
#define C_ICONV_WIN32 1 /* use the Win32 API */
|
|
#else
|
|
#pragma warning "iconv backend not chosen, will become mandatory at some point"
|
|
#endif
|
|
#endif
|
|
|
|
/* Mac OS X: There seems to be a problem with Macbooks where the touchpad
|
|
is seen by SDL2 as a "touchscreen", even though the screen is
|
|
not a touchscreen. The result is DOSBox-X getting mixed messages
|
|
from both the mouse cursor and the touch pad, which makes the
|
|
interface unusable. The solution is to ignore touch events on
|
|
Mac OS X.
|
|
|
|
Perhaps if DOSBox-X is someday ported to run on an iPad (with
|
|
a touchscreen) this can be made conditional to allow touch
|
|
events there. */
|
|
#if defined(C_SDL2) && defined(MACOSX)
|
|
# define IGNORE_TOUCHSCREEN
|
|
#endif
|
|
|
|
/* SANITY CHECK */
|
|
#if defined(C_HEAVY_DEBUG) && !defined(C_DEBUG)
|
|
# error If C_HEAVY_DEBUG is defined, then so must C_DEBUG
|
|
#endif
|
|
/* ------------ */
|
|
|
|
#if defined(_MSC_VER)
|
|
# include <sys/types.h>
|
|
# include <sys/stat.h>
|
|
|
|
/* Microsoft has their own stat/stat64 scheme */
|
|
# define pref_stat _stati64
|
|
# define pref_struct_stat struct _stat64
|
|
#else
|
|
/* As long as FILE_OFFSET_BITS==64 Linux is quite good at allowing stat to work with 64-bit sizes */
|
|
# define pref_stat stat
|
|
# define pref_struct_stat struct stat
|
|
#endif
|
|
|
|
// TODO: The autoconf script should test the size of long double
|
|
#if defined(_MSC_VER)
|
|
// Microsoft C++ sizeof(long double) == sizeof(double)
|
|
#elif defined(__arm__) || defined(__aarch64__)
|
|
// ARMv7 (Raspberry Pi) does not have long double, sizeof(long double) == sizeof(double)
|
|
// ARM 64 has a quadruple-precision float instead of the 80-bit extended precision one used by x87
|
|
#else
|
|
// GCC, other compilers, have sizeof(long double) == 10 80-bit IEEE
|
|
#define HAS_LONG_DOUBLE 1
|
|
#endif
|
|
|
|
GCC_ATTRIBUTE(noreturn) void E_Exit(const char * format,...) GCC_ATTRIBUTE( __format__(__printf__, 1, 2));
|
|
|
|
typedef Bits cpu_cycles_count_t;
|
|
typedef Bitu cpu_cycles_countu_t;
|
|
|
|
class Config;
|
|
class Section;
|
|
|
|
#if defined(__GNUC__)
|
|
# define DEPRECATED __attribute__((deprecated))
|
|
#else
|
|
# define DEPRECATED
|
|
#endif
|
|
|
|
enum MachineType {
|
|
MCH_HERC,
|
|
MCH_CGA,
|
|
MCH_TANDY,
|
|
MCH_PCJR,
|
|
MCH_EGA,
|
|
MCH_VGA,
|
|
MCH_AMSTRAD,
|
|
MCH_PC98,
|
|
|
|
MCH_FM_TOWNS, // STUB!!
|
|
|
|
MCH_MCGA, // IBM PS/2 model 30 Multi-Color Graphics Adapter
|
|
MCH_MDA
|
|
};
|
|
|
|
enum HerculesCard {
|
|
HERC_GraphicsCard,
|
|
HERC_GraphicsCardPlus,
|
|
HERC_InColor
|
|
};
|
|
|
|
enum SVGACards {
|
|
SVGA_None,
|
|
SVGA_S3Trio,
|
|
SVGA_TsengET4K,
|
|
SVGA_TsengET3K,
|
|
SVGA_ParadisePVGA1A,
|
|
SVGA_ATI
|
|
};
|
|
|
|
enum S3Card {
|
|
S3_Generic, // Generic emulation, minimal set
|
|
S3_86C928, // 86C928 [http://hackipedia.org/browse.cgi/Computer/Platform/PC%2c%20IBM%20compatible/Video/VGA/SVGA/S3%20Graphics%2c%20Ltd/S3%2086C928%20GUI%20Accelerator%20%281992%2d09%29%2epdf]
|
|
S3_Vision864, // Vision864 [http://hackipedia.org/browse.cgi/Computer/Platform/PC%2c%20IBM%20compatible/Video/VGA/SVGA/S3%20Graphics%2c%20Ltd/S3%20Vision864%20Graphics%20Accelerator%20%281994%2d10%29%2epdf]
|
|
S3_Vision868, // Vision868 [http://hackipedia.org/browse.cgi/Computer/Platform/PC%2c%20IBM%20compatible/Video/VGA/SVGA/S3%20Graphics%2c%20Ltd/S3%20Vision868%20Multimedia%20Accelerator%20%281995%2d04%29%2epdf]
|
|
S3_Vision964, // Vision964 [http://hackipedia.org/browse.cgi/Computer/Platform/PC%2c%20IBM%20compatible/Video/VGA/SVGA/S3%20Graphics%2c%20Ltd/S3%20Vision964%20Graphics%20Accelerator%20%281995%2d01%29%2epdf]
|
|
S3_Vision968, // Vision968 [http://hackipedia.org/browse.cgi/Computer/Platform/PC%2c%20IBM%20compatible/Video/VGA/SVGA/S3%20Graphics%2c%20Ltd/S3%20Vision968%20Multimedia%20Accelerator%20%281995%2d04%29%2epdf]
|
|
S3_Trio32, // Trio32 [http://hackipedia.org/browse.cgi/Computer/Platform/PC%2c%20IBM%20compatible/Video/VGA/SVGA/S3%20Graphics%2c%20Ltd/S3%20Trio32%e2%88%95Trio64%20Integrated%20Graphics%20Accelerators%20%281995%2d03%29%2epdf]
|
|
S3_Trio64, // Trio64 [http://hackipedia.org/browse.cgi/Computer/Platform/PC%2c%20IBM%20compatible/Video/VGA/SVGA/S3%20Graphics%2c%20Ltd/S3%20Trio32%e2%88%95Trio64%20Integrated%20Graphics%20Accelerators%20%281995%2d03%29%2epdf]
|
|
S3_Trio64V, // Trio64V+ [http://hackipedia.org/browse.cgi/Computer/Platform/PC%2c%20IBM%20compatible/Video/VGA/SVGA/S3%20Graphics%2c%20Ltd/S3%20Trio64V%2b%20Integrated%20Graphics%20and%20Video%20Accelerator%20%281995%2d07%29%2epdf]
|
|
|
|
// all cards beyond this point have S3D acceleration
|
|
|
|
S3_ViRGE, // ViRGE [http://hackipedia.org/browse.cgi/Computer/Platform/PC%2c%20IBM%20compatible/Video/VGA/SVGA/S3%20Graphics%2c%20Ltd/S3%20ViRGE%20Integrated%203D%20Accelerator%20%281996%2d08%29%2epdf]
|
|
S3_ViRGEVX // ViRGE VX [http://hackipedia.org/browse.cgi/Computer/Platform/PC%2c%20IBM%20compatible/Video/VGA/SVGA/S3%20Graphics%2c%20Ltd/S3%20ViRGE%E2%88%95VX%20Integrated%203D%20Accelerator%20(1996-06).pdf]
|
|
};
|
|
|
|
enum ATICard {
|
|
ATI_EGAVGAWonder, // ATI 18800 EGA/VGA Wonder
|
|
ATI_VGAWonder, // ATI 28800-1 VGA Wonder
|
|
ATI_VGAWonderPlus, // ATI 28800-2 VGA Wonder+
|
|
ATI_VGAWonderXL, // ATI 28800-4 VGA WonderXL
|
|
ATI_VGAWonderXL24, // ATI 28800-6 VGA Wonder
|
|
ATI_Mach8, // ATI 38800-1
|
|
ATI_Mach32, // ATI 68800-3
|
|
ATI_Mach64 // ATI 88800GX
|
|
};
|
|
|
|
typedef Bitu (LoopHandler)(void);
|
|
|
|
extern Config* control;
|
|
extern SVGACards svgaCard;
|
|
extern ATICard atiCard;
|
|
extern S3Card s3Card;
|
|
extern HerculesCard hercCard;
|
|
extern MachineType machine;
|
|
extern bool SDLNetInited, uselfn;
|
|
extern bool mono_cga;
|
|
extern bool DEPRECATED mainline_compatible_mapping;
|
|
extern bool DEPRECATED mainline_compatible_bios_mapping;
|
|
|
|
#ifdef __SSE__
|
|
extern bool sse2_available;
|
|
extern bool avx2_available;
|
|
#endif
|
|
|
|
void MSG_Add(const char*,const char*); // Add messages to the internal languagefile
|
|
const char* MSG_Get(char const *); // Get messages from the internal languagefile
|
|
std::string formatString(const char* format, ...); // Generates a formatted string using a format specifier and variable arguments.
|
|
|
|
void DOSBOX_RunMachine();
|
|
void DOSBOX_SetLoop(LoopHandler * handler);
|
|
void DOSBOX_SetNormalLoop();
|
|
|
|
/* machine tests for use with if() statements */
|
|
#define IS_TANDY_ARCH ((machine==MCH_TANDY) || (machine==MCH_PCJR))
|
|
#define IS_EGAVGA_ARCH ((machine==MCH_EGA) || (machine==MCH_VGA))
|
|
#define IS_JEGA_ARCH (machine==MCH_EGA && jp_ega)
|
|
#define IS_EGA_ARCH (machine==MCH_EGA)
|
|
#define IS_VGA_ARCH (machine==MCH_VGA)
|
|
#define IS_PC98_ARCH (machine==MCH_PC98)
|
|
|
|
#define IS_FM_TOWNS (machine==MCH_FM_TOWNS)
|
|
|
|
/* machine tests for use with switch() statements */
|
|
#define TANDY_ARCH_CASE MCH_TANDY: case MCH_PCJR
|
|
#define EGAVGA_ARCH_CASE MCH_EGA: case MCH_VGA
|
|
#define VGA_ARCH_CASE MCH_VGA
|
|
#define PC98_ARCH_CASE MCH_PC98
|
|
|
|
#define FM_TOWNS_ARCH_CASE MCH_FM_TOWNS
|
|
|
|
extern ClockDomain clockdom_PCI_BCLK;
|
|
extern ClockDomain clockdom_ISA_OSC;
|
|
extern ClockDomain clockdom_ISA_BCLK;
|
|
|
|
signed long long time_to_clockdom(ClockDomain &src,double t);
|
|
unsigned long long update_clockdom_from_now(ClockDomain &dst);
|
|
|
|
extern bool enable_pc98_jump;
|
|
|
|
#ifndef UNICODE_BOM
|
|
#define UNICODE_BOM 0xFEFF
|
|
#endif
|
|
|
|
typedef char utf8_t;
|
|
typedef uint16_t utf16_t;
|
|
|
|
/* for DOS filename handling we want a toupper that uses the MS-DOS code page within not the locale of the host */
|
|
int ascii_toupper(int c);
|
|
|
|
enum {
|
|
BOOTHAX_NONE=0,
|
|
BOOTHAX_MSDOS
|
|
};
|
|
|
|
extern uint32_t guest_msdos_LoL;
|
|
extern uint16_t guest_msdos_mcb_chain;
|
|
extern int boothax;
|
|
|
|
/* C++11 user-defined literal, to help with byte units */
|
|
typedef unsigned long long bytecount_t;
|
|
|
|
static inline constexpr bytecount_t operator "" _bytes(const bytecount_t x) {
|
|
return x;
|
|
}
|
|
|
|
static inline constexpr bytecount_t operator "" _parabytes(const bytecount_t x) { /* AKA bytes per segment increment in real mode */
|
|
return x << bytecount_t(4u);
|
|
}
|
|
|
|
static inline constexpr bytecount_t operator "" _kibibytes(const bytecount_t x) {
|
|
return x << bytecount_t(10u);
|
|
}
|
|
|
|
static inline constexpr bytecount_t operator "" _pagebytes(const bytecount_t x) { /* bytes per 4KB page in protected mode */
|
|
return x << bytecount_t(12u);
|
|
}
|
|
|
|
static inline constexpr bytecount_t operator "" _mibibytes(const bytecount_t x) {
|
|
return x << bytecount_t(20u);
|
|
}
|
|
|
|
static inline constexpr bytecount_t operator "" _gibibytes(const bytecount_t x) {
|
|
return x << bytecount_t(30u);
|
|
}
|
|
|
|
static inline constexpr bytecount_t operator "" _tebibytes(const bytecount_t x) {
|
|
return x << bytecount_t(40u);
|
|
}
|
|
|
|
/* and the same, for variables */
|
|
|
|
static inline constexpr bytecount_t _bytes(const bytecount_t x) {
|
|
return x;
|
|
}
|
|
|
|
static inline constexpr bytecount_t _parabytes(const bytecount_t x) { /* AKA bytes per segment increment in real mode */
|
|
return x << bytecount_t(4u);
|
|
}
|
|
|
|
static inline constexpr bytecount_t _kibibytes(const bytecount_t x) {
|
|
return x << bytecount_t(10u);
|
|
}
|
|
|
|
static inline constexpr bytecount_t _pagebytes(const bytecount_t x) { /* bytes per 4KB page in protected mode */
|
|
return x << bytecount_t(12u);
|
|
}
|
|
|
|
static inline constexpr bytecount_t _mibibytes(const bytecount_t x) {
|
|
return x << bytecount_t(20u);
|
|
}
|
|
|
|
static inline constexpr bytecount_t _gibibytes(const bytecount_t x) {
|
|
return x << bytecount_t(30u);
|
|
}
|
|
|
|
static inline constexpr bytecount_t _tebibytes(const bytecount_t x) {
|
|
return x << bytecount_t(40u);
|
|
}
|
|
|
|
enum {
|
|
PREVCAP_NONE=0,
|
|
PREVCAP_BLANK,
|
|
PREVCAP_INVISIBLE
|
|
};
|
|
|
|
extern unsigned int preventcap;
|
|
|
|
bool CheckPreventCap(void);
|
|
void ApplyPreventCap(void);
|
|
void ApplyPreventCapMenu(void);
|
|
|
|
#endif /* DOSBOX_DOSBOX_H */
|
|
|
|
#ifndef SAVE_STATE_H_INCLUDED
|
|
#define SAVE_STATE_H_INCLUDED
|
|
|
|
#define WRITE_POD(x,y) \
|
|
stream.write(reinterpret_cast<const char*>( (x) ), sizeof( (y) ) );
|
|
|
|
#define WRITE_POD_SIZE(x,y) \
|
|
stream.write(reinterpret_cast<const char*>( (x) ), (y) );
|
|
|
|
#define READ_POD(x,y) \
|
|
stream.read(reinterpret_cast<char*>( (x) ), sizeof( (y) ) );
|
|
|
|
#define READ_POD_SIZE(x,y) \
|
|
stream.read(reinterpret_cast<char*>( (x) ), (y) );
|
|
|
|
|
|
|
|
class SaveState
|
|
{
|
|
public:
|
|
static SaveState& instance();
|
|
|
|
typedef std::string Error;
|
|
static const size_t MAX_PAGE = 10, SLOT_COUNT = 10; //slot: [0,...,SLOT_COUNT - 1]
|
|
|
|
void save (size_t slot); //throw (Error)
|
|
void load (size_t slot) const; //throw (Error)
|
|
bool isEmpty(size_t slot) const;
|
|
void removeState(size_t slot) const;
|
|
std::string getName(size_t slot, bool nl=false) const;
|
|
|
|
//initialization: register relevant components on program startup
|
|
struct Component
|
|
{
|
|
virtual ~Component() noexcept = default;
|
|
virtual void getBytes(std::ostream& stream) = 0;
|
|
virtual void setBytes(std::istream& stream) = 0;
|
|
};
|
|
|
|
void registerComponent(const std::string& uniqueName, Component& comp); //comp must have global lifetime!
|
|
|
|
private:
|
|
SaveState() {}
|
|
SaveState(const SaveState&);
|
|
SaveState& operator=(const SaveState&);
|
|
|
|
struct CompData
|
|
{
|
|
CompData(Component& cmp) : comp(cmp) {}
|
|
Component& comp;
|
|
};
|
|
|
|
typedef std::map<std::string, CompData> CompEntry;
|
|
CompEntry components;
|
|
};
|
|
|
|
|
|
//some helper functions
|
|
template <class T>
|
|
void writePOD(std::ostream& stream, const T& data);
|
|
|
|
template <class T>
|
|
void readPOD(std::istream& stream, T& data);
|
|
|
|
void writeString(std::ostream& stream, const std::string& data);
|
|
void readString(std::istream& stream, std::string& data);
|
|
|
|
|
|
//Implementation of SaveState::Component for saving POD types only
|
|
class SerializeGlobalPOD : public SaveState::Component
|
|
{
|
|
public:
|
|
SerializeGlobalPOD(const std::string& compName)
|
|
{
|
|
SaveState::instance().registerComponent(compName, *this);
|
|
}
|
|
|
|
template <class T>
|
|
void registerPOD(T& pod) //register POD for serialization
|
|
{
|
|
podRef.push_back(POD(pod));
|
|
}
|
|
|
|
protected:
|
|
void getBytes(std::ostream& stream) override
|
|
{
|
|
std::for_each(podRef.begin(), podRef.end(), std::bind1st(WriteGlobalPOD(), &stream));
|
|
}
|
|
|
|
void setBytes(std::istream& stream) override
|
|
{
|
|
std::for_each(podRef.begin(), podRef.end(), std::bind1st(ReadGlobalPOD(), &stream));
|
|
}
|
|
|
|
private:
|
|
struct POD
|
|
{
|
|
template <class T>
|
|
POD(T& pod) : address(&pod), size(sizeof(T)) {}
|
|
void* address;
|
|
size_t size;
|
|
};
|
|
|
|
struct WriteGlobalPOD : public std::binary_function<std::ostream*, POD, void>
|
|
{
|
|
void operator()(std::ostream* stream, const POD& data) const
|
|
{
|
|
stream->write(static_cast<const char*>(data.address), data.size);
|
|
}
|
|
};
|
|
|
|
struct ReadGlobalPOD : public std::binary_function<std::istream*, POD, void>
|
|
{
|
|
void operator()(std::istream* stream, const POD& data) const
|
|
{
|
|
stream->read(static_cast<char*>(data.address), data.size);
|
|
}
|
|
};
|
|
|
|
std::vector<POD> podRef;
|
|
};
|
|
|
|
//---------------- inline implementation -------------------------
|
|
template <class T>
|
|
inline
|
|
void writePOD(std::ostream& stream, const T& data)
|
|
{
|
|
stream.write(reinterpret_cast<const char*>(&data), sizeof(T));
|
|
}
|
|
|
|
|
|
template <class T>
|
|
inline
|
|
void readPOD(std::istream& stream, T& data)
|
|
{
|
|
stream.read(reinterpret_cast<char*>(&data), sizeof(T));
|
|
}
|
|
|
|
|
|
inline
|
|
void writeString(std::ostream& stream, const std::string& data)
|
|
{
|
|
const size_t stringSize = data.size();
|
|
writePOD(stream, stringSize);
|
|
stream.write(data.c_str(), stringSize * sizeof(std::string::value_type));
|
|
}
|
|
|
|
|
|
inline
|
|
void readString(std::istream& stream, std::string& data)
|
|
{
|
|
size_t stringSize = 0;
|
|
readPOD(stream, stringSize);
|
|
data.resize(stringSize);
|
|
stream.read(&data[0], stringSize * sizeof(std::string::value_type));
|
|
}
|
|
#endif //SAVE_STATE_H_INCLUDED
|
|
|
|
#if defined (WIN32)
|
|
int _wmkdir_p(const wchar_t *pathname);
|
|
#else
|
|
int mkdir_p(const char *pathname, mode_t mode);
|
|
#endif
|
|
|