Skip to content

Commit

Permalink
Add big endian support
Browse files Browse the repository at this point in the history
Co-authored-by: MookThompson <58513526+MookThompson@users.noreply.github.com>
  • Loading branch information
magiblot and MookThompson committed Jan 18, 2024
1 parent bbea05c commit a26def1
Show file tree
Hide file tree
Showing 21 changed files with 220 additions and 30 deletions.
23 changes: 23 additions & 0 deletions .github/workflows/cmake.yml
Expand Up @@ -68,6 +68,29 @@ jobs:
shell: bash
run: cmake --build . -j$(nproc)

build-linux-big-endian:
name: Linux (GCC) (Big Endian)
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3

- name: Build in container
uses: uraimo/run-on-arch-action@v2
with:
arch: s390x
distro: alpine_latest
githubToken: ${{ github.token }}
dockerRunArgs: |
--volume "${PWD}:/app"
env: |
LC_CTYPE: C.UTF-8
shell: /bin/sh
install: apk update && apk add make cmake g++ ncurses-dev gtest-dev linux-headers
run: |
cd /app
cmake . -DCMAKE_BUILD_TYPE=Debug -DTV_BUILD_USING_GPM=OFF -DTV_BUILD_APPS=OFF -DTV_BUILD_TESTS=ON -DTV_LIBRARY_UNITY_BUILD=ON
cmake --build . -j$(nproc)
build-windows-msvc32:
name: Windows (MSVC) (Win32)
runs-on: windows-latest
Expand Down
2 changes: 1 addition & 1 deletion examples/tvdemo/ascii.cpp
Expand Up @@ -226,7 +226,7 @@ void TReport::handleEvent(TEvent& event)
{
if (event.message.command == cmAsciiTableCmdBase + cmCharFocused)
{
asciiChar = event.message.infoByte;
asciiChar = (uchar)(size_t)event.message.infoPtr;
drawView();
}
}
Expand Down
6 changes: 4 additions & 2 deletions examples/tvdemo/tvdemo3.cpp
Expand Up @@ -48,10 +48,12 @@ void TVDemo::mouse()

if (mouseCage != 0)
{
int32_t mouseReverse = TEventQueue::mouseReverse;
mouseCage->helpCtx = hcOMMouseDBox;
mouseCage->setData(&(TEventQueue::mouseReverse));
mouseCage->setData(&mouseReverse);
if (deskTop->execView(mouseCage) != cmCancel)
mouseCage->getData(&(TEventQueue::mouseReverse));
mouseCage->getData(&mouseReverse);
TEventQueue::mouseReverse = mouseReverse;
}
destroy( mouseCage );

Expand Down
22 changes: 22 additions & 0 deletions include/tvision/colors.h
Expand Up @@ -57,20 +57,34 @@ inline TColorAttr reverseAttribute(TColorAttr attr)
struct TColorRGB
{
uint32_t
#ifndef TV_BIG_ENDIAN
b : 8,
g : 8,
r : 8,
_unused : 8;
#else
_unused : 8,
r : 8,
g : 8,
b : 8;
#endif

TV_TRIVIALLY_CONVERTIBLE(TColorRGB, uint32_t, 0xFFFFFF)
constexpr inline TColorRGB(uint8_t r, uint8_t g, uint8_t b);
};

constexpr inline TColorRGB::TColorRGB(uint8_t r, uint8_t g, uint8_t b) :
#ifndef TV_BIG_ENDIAN
b(b),
g(g),
r(r),
_unused(0)
#else
_unused(0),
r(r),
g(g),
b(b)
#endif
{
}

Expand All @@ -90,11 +104,19 @@ constexpr inline TColorRGB::TColorRGB(uint8_t r, uint8_t g, uint8_t b) :
struct TColorBIOS
{
uint8_t
#ifndef TV_BIG_ENDIAN
b : 1,
g : 1,
r : 1,
bright : 1,
_unused : 4;
#else
_unused : 4,
bright : 1,
r : 1,
g : 1,
b : 1;
#endif

TV_TRIVIALLY_CONVERTIBLE(TColorBIOS, uint8_t, 0xF)
};
Expand Down
7 changes: 7 additions & 0 deletions include/tvision/internal/ansidisp.h
Expand Up @@ -5,6 +5,7 @@
#include <tvision/tv.h>

#include <internal/termdisp.h>
#include <internal/endian.h>

namespace tvision
{
Expand All @@ -30,6 +31,9 @@ struct TermColor

TermColor& operator=(uint32_t val) noexcept
{
#ifdef TV_BIG_ENDIAN
reverseBytes(val);
#endif
memcpy(this, &val, sizeof(*this));
return *this;
static_assert(sizeof(*this) == 4, "");
Expand All @@ -38,6 +42,9 @@ struct TermColor
{
uint32_t val;
memcpy(&val, this, sizeof(*this));
#ifdef TV_BIG_ENDIAN
reverseBytes(val);
#endif
return val;
}
TermColor(uint8_t aIdx, TermColorTypes aType) noexcept
Expand Down
29 changes: 29 additions & 0 deletions include/tvision/internal/endian.h
@@ -0,0 +1,29 @@
#ifndef TVISION_ENDIAN_H
#define TVISION_ENDIAN_H

#include <stdint.h>

namespace tvision
{

inline void reverseBytes(uint16_t &val)
{
val = (val << 8) | (val >> 8);
}

inline void reverseBytes(uint32_t &val)
{
val = ((val << 8) & 0xFF00FF00U) | ((val >> 8) & 0x00FF00FF);
val = (val << 16) | (val >> 16);
}

inline void reverseBytes(uint64_t &val)
{
val = ((val << 8) & 0xFF00FF00FF00FF00ULL) | ((val >> 8) & 0x00FF00FF00FF00FFULL);
val = ((val << 16) & 0xFFFF0000FFFF0000ULL) | ((val >> 16) & 0x0000FFFF0000FFFFULL);
val = (val << 32) | (val >> 32);
}

} // namespace tvision

#endif // TVISION_ENDIAN_H
16 changes: 7 additions & 9 deletions include/tvision/internal/strings.h
@@ -1,19 +1,17 @@
#ifndef TVISION_STRINGS_H
#define TVISION_STRINGS_H

#ifndef _TV_VERSION
#include <tvision/tv.h>
#endif

namespace tvision
{

template<class Int>
inline constexpr Int string_as_int(TStringView s) noexcept
// CAUTION: It is not endian-safe to reinterpret the result as an array of bytes.
{
Int res = 0;
for (size_t i = 0; i < min(s.size(), sizeof(res)); ++i)
// CAUTION: Assumes Little Endian.
res |= uint64_t(uint8_t(s[i])) << 8*i;
return res;
}
Expand All @@ -32,15 +30,15 @@ struct alignas(4) btoa_lut_elem_t
using btoa_lut_t = constarray<btoa_lut_elem_t, 256>;

inline char *fast_btoa(uint8_t value, char *buffer) noexcept
// Pre: the capacity of 'buffer' is at least 4 bytes.
{
extern const btoa_lut_t btoa_lut;
const auto &lut = (btoa_lut_elem_t (&) [256]) btoa_lut;
// CAUTION: Assumes Little Endian.
// We can afford to write more bytes into 'buffer' than digits.
uint32_t asInt;
memcpy(&asInt, &lut[value], 4);
memcpy(buffer, &asInt, 4);
return buffer + (asInt >> 24);
// Optimization: read and write the whole LUT entry at once in order to
// minimize memory accesses. We can afford to write more bytes into 'buffer'
// than digits.
memcpy(buffer, &lut[value], 4);
return buffer + (uint8_t) buffer[3];
static_assert(sizeof(btoa_lut_elem_t) == 4, "");
}

Expand Down
7 changes: 6 additions & 1 deletion include/tvision/internal/utf8.h
@@ -1,7 +1,9 @@
#ifndef TVISION_UTF8_H
#define TVISION_UTF8_H

#include <internal/strings.h>
#include <tvision/tv.h>

#include <internal/endian.h>

#include <stdint.h>
#include <string.h>
Expand Down Expand Up @@ -66,6 +68,9 @@ inline size_t utf32To8(uint32_t u32, char u8[4]) noexcept
(( u32 & 0b00111111) | 0b10000000) << 24;
length = 4;
}
#ifdef TV_BIG_ENDIAN
reverseBytes(asInt);
#endif
memcpy(u8, &asInt, 4);
return length;
}
Expand Down
5 changes: 3 additions & 2 deletions include/tvision/scrncell.h
Expand Up @@ -76,13 +76,14 @@ struct TCellChar

inline void TCellChar::moveChar(char ch)
{
moveInt((uchar) ch);
memset(this, 0, sizeof(*this));
_text[0] = ch;
}

inline void TCellChar::moveInt(uint32_t mbc, bool wide)
// Pre: 'mbc' is a bit-casted multibyte-encoded character.
{
memset(this, 0, sizeof(*this));
// CAUTION: Assumes Little Endian.
memcpy(_text, &mbc, sizeof(mbc));
_flags = -int(wide) & fWide;
}
Expand Down
5 changes: 5 additions & 0 deletions include/tvision/system.h
Expand Up @@ -187,8 +187,13 @@ inline void TMouse::registerHandler( unsigned mask, void (_FAR *func)() )

struct CharScanType
{
#if !defined( TV_BIG_ENDIAN )
uchar charCode;
uchar scanCode;
#else
uchar scanCode;
uchar charCode;
#endif
};

struct KeyDownEvent
Expand Down
11 changes: 11 additions & 0 deletions source/CMakeLists.txt
Expand Up @@ -74,6 +74,17 @@ target_compile_definitions(${PROJECT_NAME} PRIVATE
TVISION_NO_STL
)

include(TestBigEndian)

TEST_BIG_ENDIAN(IS_BIG_ENDIAN)

if (IS_BIG_ENDIAN)
tv_message(STATUS "Big endian system detected")
target_compile_definitions(${PROJECT_NAME} PUBLIC
TV_BIG_ENDIAN
)
endif()

# Dependencies

if (NOT WIN32)
Expand Down
6 changes: 5 additions & 1 deletion source/platform/ansidisp.cpp
Expand Up @@ -156,9 +156,13 @@ struct alignas(8) colorconv_r
uint8_t unused[2];

colorconv_r() = default;
colorconv_r(TermColor aColor, TColorAttr::Style aExtraFlags=0) noexcept
colorconv_r(TermColor aColor, TColorAttr::Style aExtraFlags = 0) noexcept
{
// Optimization: do bit-casting manually, just like with TermColor.
uint64_t val = aColor | (uint64_t(aExtraFlags) << 32);
#ifdef TV_BIG_ENDIAN
reverseBytes(val);
#endif
memcpy(this, &val, 8);
static_assert(sizeof(*this) == 8, "");
}
Expand Down
2 changes: 1 addition & 1 deletion source/platform/buffdisp.cpp
Expand Up @@ -340,7 +340,7 @@ inline void FlushScreenAlgorithm::writeCell() noexcept
inline void FlushScreenAlgorithm::writeSpace() noexcept
{
TCellChar ch;
ch.moveInt(' ');
ch.moveChar(' ');
writeCell(ch, cell->attr, 0);
}

Expand Down
19 changes: 19 additions & 0 deletions source/platform/far2l.cpp
Expand Up @@ -6,6 +6,7 @@
#include <internal/constmap.h>
#include <internal/base64.h>
#include <internal/events.h>
#include <internal/endian.h>

#include <time.h>

Expand Down Expand Up @@ -97,6 +98,16 @@ ParseResult parseFar2lInput(GetChBuf &buf, TEvent &ev, InputState &state) noexce
memcpy(&kev.dwControlKeyState, &out[6], 4);
memcpy(&kev.uChar.UnicodeChar, &out[10], 4);

#ifdef TV_BIG_ENDIAN
// The protocol states that "all integer values are in
// little-endian format", so convert them.
reverseBytes(kev.wRepeatCount);
reverseBytes(kev.wVirtualKeyCode);
reverseBytes(kev.wVirtualScanCode);
reverseBytes(kev.dwControlKeyState);
reverseBytes((uint32_t &) kev.uChar.UnicodeChar);
#endif

if (uint16_t keyCode = virtualKeyCodeToKeyCode[kev.wVirtualKeyCode])
{
kev.wVirtualScanCode = keyCode >> 8;
Expand All @@ -120,6 +131,14 @@ ParseResult parseFar2lInput(GetChBuf &buf, TEvent &ev, InputState &state) noexce
memcpy(&mev.dwControlKeyState, &out[8], 4);
memcpy(&mev.dwEventFlags, &out[12], 4);

#ifdef TV_BIG_ENDIAN
reverseBytes((uint16_t &) mev.dwMousePosition.X);
reverseBytes((uint16_t &) mev.dwMousePosition.Y);
reverseBytes(mev.dwButtonState);
reverseBytes(mev.dwControlKeyState);
reverseBytes(mev.dwEventFlags);
#endif

getWin32Mouse(mev, ev, state);
return Accepted;
}
Expand Down
2 changes: 1 addition & 1 deletion source/platform/win32con.cpp
Expand Up @@ -413,7 +413,7 @@ bool getWin32Key(const KEY_EVENT_RECORD &KeyEvent, TEvent &ev, InputState &state

ev.what = evKeyDown;
ev.keyDown.charScan.scanCode = KeyEvent.wVirtualScanCode;
ev.keyDown.charScan.charCode = KeyEvent.uChar.AsciiChar;
ev.keyDown.charScan.charCode = (uchar) KeyEvent.uChar.UnicodeChar;
ev.keyDown.controlKeyState = KeyEvent.dwControlKeyState & (
kbShift | kbCtrlShift | kbAltShift |
kbScrollState | kbNumState | kbCapsState | kbEnhanced
Expand Down

0 comments on commit a26def1

Please sign in to comment.