<commit_before>/* cpu.h
 *
 * Runtime CPU detection library.
 * (C) 2009-2012 <NAME>.
 * Hackipedia DOS library.
 *
 * This code is licensed under the LGPL.
 * <insert LGPL legal text here>
 *
 */

#ifndef __HW_CPU_CPU_H
#define __HW_CPU_CPU_H

#include <stdint.h>
#include <i86.h>        /* FP_SEG/FP_OFF */

#if !defined(FAR)
# if defined(TARGET_WINDOWS) && !defined(TARGET_VXD)
#  include <windows.h>
# else
#  if TARGET_MSDOS == 32
#   define FAR
#  else
#   define FAR far
#  endif
# endif
#endif

#ifdef __cplusplus
extern "C" {
#endif

/* FIX: Open Watcom does not provide inpd/outpd in 16-bit real mode, so we have to provide it ourself */
/*      We assume for the same stupid reasons the pragma aux function can't be used because it's a 386 level instruction */
#if TARGET_MSDOS == 16
uint32_t __cdecl inpd(uint16_t port);
void __cdecl outpd(uint16_t port,uint32_t data);
#endif

#if TARGET_MSDOS == 16
static inline uint32_t ptr2phys(void far *p) {
	return (((uint32_t)FP_SEG(p)) << 4UL) +
		((uint32_t)FP_OFF(p));
}
#endif

#pragma pack(push,1)
struct cpu_cpuid_features {
	union {
		uint32_t		raw[4];	/* EAX, EBX, EDX, ECX */
		struct {
			uint32_t	todo[4];
		} f;
	} a;
};

struct cpu_cpuid_ext_features {
	union {
		uint32_t		raw[4];	/* EAX, EBX, ECX, EDX */
		struct {
			uint32_t	todo[4];
		} f;
	} a;
};

struct cpu_cpuid_ext_cache_tlb {
	union {
		uint32_t		raw[4];	/* EAX, EBX, ECX, EDX */
		struct {
			uint32_t	todo[4];
		} f;
	} a;
};

struct cpu_cpuid_ext_cache_tlb_l2 {
	union {
		uint32_t		raw[4];	/* EAX, EBX, ECX, EDX */
		struct {
			uint32_t	todo[4];
		} f;
	} a;
};

struct cpu_cpuid_ext_longmode {
	union {
		uint32_t		raw[4];	/* EAX, EBX, ECX, EDX */
		struct {
			uint32_t	todo[4];
		} f;
	} a;
};

struct cpu_cpuid_ext_apm {
	union {
		uint32_t		raw[1]; /* EAX */
		struct {
			uint32_t	todo[1];
		} f;
	} a;
};

struct cpuid_result {
	uint32_t			eax,ebx,ecx,edx;
};
#pragma pack(pop)

/* "Basic" CPU level */
enum {
	CPU_8086=0,		/* 0 */
	CPU_186,
	CPU_286,
	CPU_386,
	CPU_486,
	CPU_586,
	CPU_686,
	CPU_MAX
};

extern const char *			cpu_basic_level_str[CPU_MAX];
extern char				cpu_cpuid_vendor[13];
extern struct cpu_cpuid_features	cpu_cpuid_features;
extern signed char			cpu_basic_level;
extern uint32_t				cpu_cpuid_max;
extern unsigned short			cpu_flags;
extern uint16_t				cpu_tmp1;

/* compatability */
#define cpu_v86_active (cpu_flags & CPU_FLAG_V86_ACTIVE)

#define cpu_basic_level_to_string(x) (x >= 0 ? cpu_basic_level_str[x] : "?")

/* CPU flag: CPU supports CPUID */
#define CPU_FLAG_CPUID			(1 << 0)
#define CPU_FLAG_FPU			(1 << 1)
#define CPU_FLAG_CPUID_EXT		(1 << 2)
#define CPU_FLAG_V86_ACTIVE		(1 << 3)
#define CPU_FLAG_PROTECTED_MODE		(1 << 4)
#define CPU_FLAG_PROTECTED_MODE_32	(1 << 5)
/*      ^ Windows-specific: we are not only a 16-bit Win16 app, but Windows is running in 386 enhanced mode
 *                          and we can safely use 32-bit registers and hacks. This will always be set for
 *                          Win32 and 32-bit DOS, obviously. If set, PROTECTED_MODE is also set. */
#define CPU_FLAG_DONT_WRITE_RDTSC	(1 << 6)
#define CPU_FLAG_CR4_EXISTS		(1 << 7)
/* There are some v86-based environments where the CPU has RDTSC but we can't use it because
 * the v86 monitor doesn't have it enabled for user-mode use (Windows 95 EMM386.EXE). */
#define CPU_FLAG_DONT_USE_RDTSC (1 << 8)

void cpu_probe();
int cpu_basic_probe(); /* external assembly language function */

static void _cli();
#pragma aux _cli = "cli"
static void _sti();
#pragma aux _sti = "sti"

static inline void _sti_if_flags(unsigned int f) {
	if (f&0x200) _sti(); /* if IF bit was set, then restore interrupts by STI */
}

/* NTS: remember for Watcom: 16-bit realmode sizeof(int) == 2, 32-bit flat mode sizeof(int) == 4 */
static unsigned int get_cpu_flags();
#if TARGET_MSDOS == 32
#pragma aux get_cpu_flags = \
	"pushfd"	\
	"pop	eax"	\
	value [eax];
#else
#pragma aux get_cpu_flags = \
	"pushf"		\
	"pop	ax"	\
	value [ax];
#endif

static void set_cpu_flags(unsigned int f);
#if TARGET_MSDOS == 32
#pragma aux set_cpu_flags = \
	"push	eax"	\
	"popfd	"	\
	parm [eax];
#else
#pragma aux set_cpu_flags = \
	"push	ax"	\
	"popf	"	\
	parm [ax];
#endif

#if (defined(TARGET_WINDOWS) || defined(TARGET_OS2)) && TARGET_MSDOS == 32
/* Watcom does not offer int86/int386 for Win32s/Win9x/NT/etc */
#else
static inline void just_int86(unsigned char c,union REGS *r1,union REGS *r2) {
# ifdef __386__<commit_msg>Save/restore CPU flags (PUSHF/POPF) try #2<commit_after>/* cpu.h
 *
 * Runtime CPU detection library.
 * (C) 2009-2012 <NAME>.
 * Hackipedia DOS library.
 *
 * This code is licensed under the LGPL.
 * <insert LGPL legal text here>
 *
 */

#ifndef __HW_CPU_CPU_H
#define __HW_CPU_CPU_H

#include <stdint.h>
#include <i86.h>        /* FP_SEG/FP_OFF */

#if !defined(FAR)
# if defined(TARGET_WINDOWS) && !defined(TARGET_VXD)
#  include <windows.h>
# else
#  if TARGET_MSDOS == 32
#   define FAR
#  else
#   define FAR far
#  endif
# endif
#endif

#ifdef __cplusplus
extern "C" {
#endif

/* FIX: Open Watcom does not provide inpd/outpd in 16-bit real mode, so we have to provide it ourself */
/*      We assume for the same stupid reasons the pragma aux function can't be used because it's a 386 level instruction */
#if TARGET_MSDOS == 16
uint32_t __cdecl inpd(uint16_t port);
void __cdecl outpd(uint16_t port,uint32_t data);
#endif

#if TARGET_MSDOS == 16
static inline uint32_t ptr2phys(void far *p) {
	return (((uint32_t)FP_SEG(p)) << 4UL) +
		((uint32_t)FP_OFF(p));
}
#endif

#pragma pack(push,1)
struct cpu_cpuid_features {
	union {
		uint32_t		raw[4];	/* EAX, EBX, EDX, ECX */
		struct {
			uint32_t	todo[4];
		} f;
	} a;
};

struct cpu_cpuid_ext_features {
	union {
		uint32_t		raw[4];	/* EAX, EBX, ECX, EDX */
		struct {
			uint32_t	todo[4];
		} f;
	} a;
};

struct cpu_cpuid_ext_cache_tlb {
	union {
		uint32_t		raw[4];	/* EAX, EBX, ECX, EDX */
		struct {
			uint32_t	todo[4];
		} f;
	} a;
};

struct cpu_cpuid_ext_cache_tlb_l2 {
	union {
		uint32_t		raw[4];	/* EAX, EBX, ECX, EDX */
		struct {
			uint32_t	todo[4];
		} f;
	} a;
};

struct cpu_cpuid_ext_longmode {
	union {
		uint32_t		raw[4];	/* EAX, EBX, ECX, EDX */
		struct {
			uint32_t	todo[4];
		} f;
	} a;
};

struct cpu_cpuid_ext_apm {
	union {
		uint32_t		raw[1]; /* EAX */
		struct {
			uint32_t	todo[1];
		} f;
	} a;
};

struct cpuid_result {
	uint32_t			eax,ebx,ecx,edx;
};
#pragma pack(pop)

/* "Basic" CPU level */
enum {
	CPU_8086=0,		/* 0 */
	CPU_186,
	CPU_286,
	CPU_386,
	CPU_486,
	CPU_586,
	CPU_686,
	CPU_MAX
};

extern const char *			cpu_basic_level_str[CPU_MAX];
extern char				cpu_cpuid_vendor[13];
extern struct cpu_cpuid_features	cpu_cpuid_features;
extern signed char			cpu_basic_level;
extern uint32_t				cpu_cpuid_max;
extern unsigned short			cpu_flags;
extern uint16_t				cpu_tmp1;

/* compatability */
#define cpu_v86_active (cpu_flags & CPU_FLAG_V86_ACTIVE)

#define cpu_basic_level_to_string(x) (x >= 0 ? cpu_basic_level_str[x] : "?")

/* CPU flag: CPU supports CPUID */
#define CPU_FLAG_CPUID			(1 << 0)
#define CPU_FLAG_FPU			(1 << 1)
#define CPU_FLAG_CPUID_EXT		(1 << 2)
#define CPU_FLAG_V86_ACTIVE		(1 << 3)
#define CPU_FLAG_PROTECTED_MODE		(1 << 4)
#define CPU_FLAG_PROTECTED_MODE_32	(1 << 5)
/*      ^ Windows-specific: we are not only a 16-bit Win16 app, but Windows is running in 386 enhanced mode
 *                          and we can safely use 32-bit registers and hacks. This will always be set for
 *                          Win32 and 32-bit DOS, obviously. If set, PROTECTED_MODE is also set. */
#define CPU_FLAG_DONT_WRITE_RDTSC	(1 << 6)
#define CPU_FLAG_CR4_EXISTS		(1 << 7)
/* There are some v86-based environments where the CPU has RDTSC but we can't use it because
 * the v86 monitor doesn't have it enabled for user-mode use (Windows 95 EMM386.EXE). */
#define CPU_FLAG_DONT_USE_RDTSC (1 << 8)

void cpu_probe();
int cpu_basic_probe(); /* external assembly language function */

static void _cli();
#pragma aux _cli = "cli"
static void _sti();
#pragma aux _sti = "sti"

static inline void _sti_if_flags(unsigned int f) {
	if (f&0x200) _sti(); /* if IF bit was set, then restore interrupts by STI */
}

/* NTS: remember for Watcom: 16-bit realmode sizeof(int) == 2, 32-bit flat mode sizeof(int) == 4 */
static unsigned int get_cpu_flags();
#if TARGET_MSDOS == 32
#pragma aux get_cpu_flags = \
	"pushfd"	\
	"pop	eax"	\
	value [eax];
#else
#pragma aux get_cpu_flags = \
	"pushf"		\
	"pop	ax"	\
	value [ax];
#endif

static void set_cpu_flags(unsigned int f);
#if TARGET_MSDOS == 32
#pragma aux set_cpu_flags = \
	"push	eax"	\
	"popfd	"	\
	parm [eax];
#else
#pragma aux set_cpu_flags = \
	"push	ax"	\
	"popf	"	\
	parm [ax];
#endif

#if TARGET_MSDOS == 16
// 16-bit WCC uses the BP register to refer to local variables and parameters on the stack.
// PUSHF and POPF are safe to use, apparently.
//
// It is NOT safe to do this with 32-bit WCC386 because the 386 instruction set allows WCC386
// to generate code that directly references locals relative to ESP, and PUSHFD/POPFD change ESP.
//
// I'm going to ask jmalak if an extension to Open Watcom can be added to make this function part of the compiler
// and therefore part of the stack-relative locals management code.
# define SAVE_CPUFLAGS          { __asm { pushf }; {
# define RESTORE_CPUFLAGS       } __asm { popf }; }
#else
// more generic safe code
# define SAVE_CPUFLAGS          { unsigned int __cpu_flags = get_cpu_flags(); {
# define RESTORE_CPUFLAGS       } set_cpu_flags(__cpu_flags); }
#endif

#if (defined(TARGET_WINDOWS) || defined(TARGET_OS2)) && TARGET_MSDOS == 32
/* Watcom does not offer int86/int386 for Win32s/Win9x/NT/etc */
#else
static inline void just_int86(unsigned char c,union REGS *r1,union REGS *r2) {
# ifdef __386__
{'fraction_non_alphanumeric': 0.1201558335042034, 'fraction_numerical': 0.040598728726676234, 'mean_word_length': 3.5372093023255813, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2519139', 'n_tokens_mistral': 4306, 'n_tokens_neox': 3915, 'n_words': 1122}