From c05bbafb5d5175bdb35a1896276b0e8bff95f3ef Mon Sep 17 00:00:00 2001 From: Patryk Obara Date: Tue, 14 Apr 2020 19:33:55 +0200 Subject: [PATCH] Create byteorder header for host_to_le functions --- include/Makefile.am | 1 + include/byteorder.h | 121 ++++++++++++++++++++++++++++++++++++++ include/mem.h | 45 +------------- src/hardware/mixer.cpp | 6 +- vs/dosbox.vcxproj | 3 +- vs/dosbox.vcxproj.filters | 3 + 6 files changed, 133 insertions(+), 46 deletions(-) create mode 100644 include/byteorder.h diff --git a/include/Makefile.am b/include/Makefile.am index cfeb115b..58f6a4bd 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,6 +1,7 @@ noinst_HEADERS = \ bios_disk.h \ bios.h \ +byteorder.h \ callback.h \ compiler.h \ control.h \ diff --git a/include/byteorder.h b/include/byteorder.h new file mode 100644 index 00000000..600402cc --- /dev/null +++ b/include/byteorder.h @@ -0,0 +1,121 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Copyright (C) 2020-2020 The dosbox-staging 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_BYTEORDER_H +#define DOSBOX_BYTEORDER_H + +/* Usual way of handling endianess and byteswapping is via endian.h + * (for e.g. htole* functions) or byteswap.h (e.g. bswap_16 macro). + * + * However, these headers are non-standard and almost every OS has their own + * variations. It's easier to use compiler-provided intrinsics and builtins than + * to rely on OS libraries. + * + * This header provides functions deliberately named differently + * than popular variations on these implementations (e.g. bswap_u16 instead of + * bswap_16), to avoid conflicts. + */ + +#include "config.h" + +#include +#include + +#if !defined(_MSC_VER) + +/* Aside of MSVC, every C++11-capable compiler provides __builtin_bswap* + * as compiler intrinsics or builtin functions. + */ + +#define bswap_u16(x) __builtin_bswap16(x) +#define bswap_u32(x) __builtin_bswap32(x) +#define bswap_u64(x) __builtin_bswap64(x) + +#else + +/* MSVCS does not provide __builtin_bswap* functions, but has its own + * byteswap builtin's. MSDN lists these as library functions, but MSVC makes + * good job of inlinig them when compiling with /O2. + * + * https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/byteswap-uint64-byteswap-ulong-byteswap-ushort + */ + +#define bswap_u16(x) _byteswap_ushort(x) +#define bswap_u32(x) _byteswap_ulong(x) +#define bswap_u64(x) _byteswap_uint64(x) + +#endif // MSC_VER + +#ifdef WORDS_BIGENDIAN + +#define host_to_le16(x) bswap_u16(static_cast(x)) +#define host_to_le32(x) bswap_u32(static_cast(x)) +#define host_to_le64(x) bswap_u64(static_cast(x)) + +#define le16_to_host(x) bswap_u16(static_cast(x)) +#define le32_to_host(x) bswap_u32(static_cast(x)) +#define le64_to_host(x) bswap_u64(static_cast(x)) + +#else + +#define host_to_le16(x) static_cast(x) +#define host_to_le32(x) static_cast(x) +#define host_to_le64(x) static_cast(x) + +#define le16_to_host(x) static_cast(x) +#define le32_to_host(x) static_cast(x) +#define le64_to_host(x) static_cast(x) + +#endif + +/* 'host_to_le' functions allow for byte order conversion on big endian + * architectures while respecting memory alignment on low endian. + * + * We overload these functions to let compiler pick the correct byteswapping + * function if user is ok with that. + * + * The only caveat in here is: MSVC bswap implementations are not constexpr, + * so these functions won't compile using MSVC for big endian + * architecture, but it's unlikely to ever be a real problem. + */ + +constexpr uint8_t host_to_le(uint8_t x) noexcept { return x; } + +#ifdef WORDS_BIGENDIAN + +constexpr uint16_t host_to_le(uint16_t x) noexcept { return bswap_u16(x); } +constexpr uint32_t host_to_le(uint32_t x) noexcept { return bswap_u32(x); } +constexpr uint64_t host_to_le(uint64_t x) noexcept { return bswap_u64(x); } + +#else + +constexpr uint16_t host_to_le(uint16_t x) noexcept { return x; } +constexpr uint32_t host_to_le(uint32_t x) noexcept { return x; } +constexpr uint64_t host_to_le(uint64_t x) noexcept { return x; } + +#endif + +/* Functions 'le_to_host' and 'host_to_le' are the same function, only the user + * intent might be different. + */ + +#define le_to_host(x) host_to_le(x) + +#endif diff --git a/include/mem.h b/include/mem.h index cb51e0c7..8dc3958d 100644 --- a/include/mem.h +++ b/include/mem.h @@ -23,6 +23,8 @@ #include "dosbox.h" #endif +#include "byteorder.h" + typedef Bit32u PhysPt; typedef Bit8u * HostPt; typedef Bit32u RealPt; @@ -118,49 +120,6 @@ static INLINE void host_writed(HostPt off,Bit32u val) { #endif -// host_to_le functions allow for byte order conversion on big endian -// architectures while respecting memory alignment on low endian. -// -// It is extremely unlikely that we'll ever try to compile on big endian arch -// with a compiler missing __builtin_bswap*, so let's not overcomplicate -// things. -// -// __builtin_bswap* is supported since GCC 4.3 and Clang 3.4 - -constexpr static INLINE uint8_t host_to_le(uint8_t val) { - return val; -} - -#if defined(WORDS_BIGENDIAN) - -constexpr static INLINE int16_t host_to_le(int16_t val) { - return __builtin_bswap16(val); -} - -constexpr static INLINE uint16_t host_to_le(uint16_t val) { - return __builtin_bswap16(val); -} - -constexpr static INLINE uint32_t host_to_le(uint32_t val) { - return __builtin_bswap32(val); -} - -#else - -constexpr static INLINE int16_t host_to_le(int16_t val) { - return val; -} - -constexpr static INLINE uint16_t host_to_le(uint16_t val) { - return val; -} - -constexpr static INLINE uint32_t host_to_le(uint32_t val) { - return val; -} - -#endif - static INLINE void var_write(Bit8u * var, Bit8u val) { host_writeb(var, val); } diff --git a/src/hardware/mixer.cpp b/src/hardware/mixer.cpp index c41eab54..a779eb01 100644 --- a/src/hardware/mixer.cpp +++ b/src/hardware/mixer.cpp @@ -503,8 +503,10 @@ static void MIXER_MixData(Bitu needed) { for (size_t i = 0; i < added; i++) { const int32_t sample_1 = mixer.work[readpos][0] >> MIXER_VOLSHIFT; const int32_t sample_2 = mixer.work[readpos][1] >> MIXER_VOLSHIFT; - convert[i][0] = host_to_le(MIXER_CLIP(sample_1)); - convert[i][1] = host_to_le(MIXER_CLIP(sample_2)); + const int16_t s1 = MIXER_CLIP(sample_1); + const int16_t s2 = MIXER_CLIP(sample_2); + convert[i][0] = host_to_le(static_cast(s1)); + convert[i][1] = host_to_le(static_cast(s2)); readpos = (readpos + 1) & MIXER_BUFMASK; } CAPTURE_AddWave(mixer.freq, added, reinterpret_cast(convert)); diff --git a/vs/dosbox.vcxproj b/vs/dosbox.vcxproj index fe5acf55..f963ea49 100644 --- a/vs/dosbox.vcxproj +++ b/vs/dosbox.vcxproj @@ -272,6 +272,7 @@ + @@ -390,4 +391,4 @@ - \ No newline at end of file + diff --git a/vs/dosbox.vcxproj.filters b/vs/dosbox.vcxproj.filters index ed0ec1d0..78d8f45d 100644 --- a/vs/dosbox.vcxproj.filters +++ b/vs/dosbox.vcxproj.filters @@ -390,6 +390,9 @@ include + + include + include