From 08bc5f890a2a84024432fb36034995205a0d5800 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Mon, 27 Mar 2023 12:51:20 +0200 Subject: [PATCH] WIN32 build --- CMakeLists.txt | 27 ++++++++++++++++++++++++ console.h | 4 ++++ console_posix.cpp | 23 ++++++++++++++++++++- console_posix.h | 4 ++++ disk_backend_file.cpp | 14 +++++++++++++ disk_backend_nbd.cpp | 17 +++++++++++++-- error.cpp | 10 +++++---- log.cpp | 8 ++++++++ main.cpp | 13 +++++++++++- utils.cpp | 3 +++ windows/README.txt | 3 +++ windows/mingw64.cmake | 14 +++++++++++++ windows/win32.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++ windows/win32.h | 4 ++++ 14 files changed, 184 insertions(+), 8 deletions(-) create mode 100644 windows/README.txt create mode 100644 windows/mingw64.cmake create mode 100644 windows/win32.cpp create mode 100644 windows/win32.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d75bf1..beac89f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,30 @@ add_executable( utils.cpp ) +add_executable( + kek-win32 + bus.cpp + console.cpp + console_posix.cpp + cpu.cpp + debugger.cpp + disk_backend.cpp + disk_backend_file.cpp + disk_backend_nbd.cpp + error.cpp + kw11-l.cpp + loaders.cpp + log.cpp + main.cpp + memory.cpp + rk05.cpp + rl02.cpp + tm-11.cpp + tty.cpp + utils.cpp + windows/win32.cpp +) + include(CheckIPOSupported) check_ipo_supported(RESULT supported) @@ -45,6 +69,9 @@ set(CMAKE_THREAD_PREFER_PTHREAD TRUE) set(THREADS_PREFER_PTHREAD_FLAG TRUE) find_package(Threads) target_link_libraries(kek Threads::Threads) +target_link_libraries(kek-win32 Threads::Threads) + +target_link_libraries(kek-win32 ws2_32) include(FindPkgConfig) diff --git a/console.h b/console.h index 7ac5d84..cb41180 100644 --- a/console.h +++ b/console.h @@ -10,6 +10,10 @@ #include "bus.h" +#if defined(_WIN32) +#include "windows/win32.h" +#endif + constexpr const int t_width { 80 }; constexpr const int t_height { 25 }; diff --git a/console_posix.cpp b/console_posix.cpp index 3a5115d..baffc4d 100644 --- a/console_posix.cpp +++ b/console_posix.cpp @@ -1,9 +1,15 @@ // (C) 2018-2023 by Folkert van Heusden // Released under MIT license +#if defined(_WIN32) +#include + +#include +#else #include +#endif + #include -#include #include #include "console_posix.h" @@ -13,6 +19,7 @@ console_posix::console_posix(std::atomic_uint32_t *const stop_event, bus *const b) : console(stop_event, b) { +#if !defined(_WIN32) if (tcgetattr(STDIN_FILENO, &org_tty_opts) == -1) error_exit(true, "console_posix: tcgetattr failed"); @@ -21,22 +28,36 @@ console_posix::console_posix(std::atomic_uint32_t *const stop_event, bus *const if (tcsetattr(STDIN_FILENO, TCSANOW, &tty_opts_raw) == -1) error_exit(true, "console_posix: tcsetattr failed"); +#endif } console_posix::~console_posix() { stop_thread(); +#if !defined(_WIN32) if (tcsetattr(STDIN_FILENO, TCSANOW, &org_tty_opts) == -1) error_exit(true, "~console_posix: tcsetattr failed"); +#endif } int console_posix::wait_for_char_ll(const short timeout) { +#if defined(_WIN32) + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(STDIN_FILENO, &rfds); + + timeval to { timeout / 1000000, timeout % 1000000 }; + + if (select(STDIN_FILENO + 1, &rfds, nullptr, nullptr, &to) == 1 && FD_ISSET(STDIN_FILENO, &rfds)) + return _getch(); +#else struct pollfd fds[] = { { STDIN_FILENO, POLLIN, timeout } }; if (poll(fds, 1, timeout) == 1 && fds[0].revents) return getchar(); +#endif return -1; } diff --git a/console_posix.h b/console_posix.h index 407fe2f..661c3d7 100644 --- a/console_posix.h +++ b/console_posix.h @@ -1,7 +1,9 @@ // (C) 2018-2023 by Folkert van Heusden // Released under MIT license +#if !defined(_WIN32) #include +#endif #include "console.h" @@ -9,7 +11,9 @@ class console_posix : public console { private: +#if !defined(_WIN32) struct termios org_tty_opts { 0 }; +#endif protected: int wait_for_char_ll(const short timeout) override; diff --git a/disk_backend_file.cpp b/disk_backend_file.cpp index 2482239..bed35a8 100644 --- a/disk_backend_file.cpp +++ b/disk_backend_file.cpp @@ -36,12 +36,26 @@ bool disk_backend_file::read(const off_t offset, const size_t n, uint8_t *const { DOLOG(debug, false, "disk_backend_file::read: read %zu bytes from offset %zu", n, offset); +#if defined(_WIN32) // hope for the best + if (lseek(fd, offset, SEEK_SET) == -1) + return false; + + return ::read(fd, target, n) == ssize_t(n); +#else return pread(fd, target, n, offset) == ssize_t(n); +#endif } bool disk_backend_file::write(const off_t offset, const size_t n, const uint8_t *const from) { DOLOG(debug, false, "disk_backend_file::write: write %zu bytes to offset %zu", n, offset); +#if defined(_WIN32) // hope for the best + if (lseek(fd, offset, SEEK_SET) == -1) + return false; + + return ::write(fd, from, n) == ssize_t(n); +#else return pwrite(fd, from, n, offset) == ssize_t(n); +#endif } diff --git a/disk_backend_nbd.cpp b/disk_backend_nbd.cpp index 562a42a..56c7799 100644 --- a/disk_backend_nbd.cpp +++ b/disk_backend_nbd.cpp @@ -4,18 +4,31 @@ #include #include #include -#include #include #include "disk_backend_nbd.h" #include "log.h" #include "utils.h" -#ifdef ESP32 +#if defined(ESP32) #include #include +#elif defined(_WIN32) +// from https://stackoverflow.com/questions/12765743/implicit-declaration-of-function-getaddrinfo-on-mingw +#define _NTDDI_VERSION_FROM_WIN32_WINNT2(ver) ver##0000 +#define _NTDDI_VERSION_FROM_WIN32_WINNT(ver) _NTDDI_VERSION_FROM_WIN32_WINNT2(ver) + +#ifndef _WIN32_WINNT +# define _WIN32_WINNT 0x501 +#endif +#ifndef NTDDI_VERSION +# define NTDDI_VERSION _NTDDI_VERSION_FROM_WIN32_WINNT(_WIN32_WINNT) +#endif +#include +#include #else #include +#include #include #endif diff --git a/error.cpp b/error.cpp index c62fd80..c0f9dcd 100644 --- a/error.cpp +++ b/error.cpp @@ -8,9 +8,9 @@ #include #include #include -#include #if defined(ESP32) #include +#elif defined(_WIN32) #else #include #endif @@ -21,18 +21,20 @@ { int e = errno; +#if !defined(_WIN32) + (void)endwin(); +#endif + #if defined(ESP32) Serial.println(format); #else - (void)endwin(); - va_list ap; va_start(ap, format); (void)vfprintf(stderr, format, ap); va_end(ap); - if (sys_err == TRUE) + if (sys_err == true) fprintf(stderr, "error: %s (%d)\n", strerror(e), e); #endif diff --git a/log.cpp b/log.cpp index 2187f87..3df6975 100644 --- a/log.cpp +++ b/log.cpp @@ -7,10 +7,12 @@ #include #include #include +#include #include "error.h" #include "log.h" #include "utils.h" +#include "windows/win32.h" static const char *logfile = strdup("/tmp/myip.log"); @@ -65,11 +67,13 @@ void dolog(const log_level_t ll, const char *fmt, ...) if (!lfh) error_exit(true, "Cannot access log-file %s", logfile); +#if !defined(_WIN32) if (lf_uid != -1 && fchown(fileno(lfh), lf_uid, lf_gid) == -1) error_exit(true, "Cannot change logfile (%s) ownership", logfile); if (fcntl(fileno(lfh), F_SETFD, FD_CLOEXEC) == -1) error_exit(true, "fcntl(FD_CLOEXEC) failed"); +#endif #endif } @@ -77,8 +81,12 @@ void dolog(const log_level_t ll, const char *fmt, ...) time_t t_now = now / 1000000; tm tm { 0 }; +#if defined(_WIN32) + tm = *localtime(&t_now); +#else if (!localtime_r(&t_now, &tm)) error_exit(true, "localtime_r failed"); +#endif char *ts_str = nullptr; diff --git a/main.cpp b/main.cpp index 0efe2fc..6379a42 100644 --- a/main.cpp +++ b/main.cpp @@ -9,7 +9,9 @@ #include #include "error.h" +#if !defined(_WIN32) #include "console_ncurses.h" +#endif #include "console_posix.h" #include "cpu.h" #include "debugger.h" @@ -21,7 +23,9 @@ #include "loaders.h" #include "log.h" #include "memory.h" +#if !defined(_WIN32) #include "terminal.h" +#endif #include "tty.h" #include "utils.h" @@ -32,6 +36,7 @@ std::atomic_bool *running { nullptr }; std::atomic_bool sigw_event { false }; +#if !defined(_WIN32) void sw_handler(int s) { if (s == SIGWINCH) @@ -42,6 +47,7 @@ void sw_handler(int s) event = EVENT_TERMINATE; } } +#endif void help() { @@ -227,9 +233,12 @@ int main(int argc, char *argv[]) if (sa_set) c->setRegister(7, start_addr); +#if !defined(_WIN32) if (withUI) cnsl = new console_ncurses(&event, b); - else { + else +#endif + { DOLOG(info, true, "This PDP-11 emulator is called \"kek\" (reason for that is forgotten) and was written by Folkert van Heusden."); DOLOG(info, true, "Built on: " __DATE__ " " __TIME__); @@ -262,6 +271,7 @@ int main(int argc, char *argv[]) DOLOG(info, true, "Start running at %06o", c->getRegister(7)); +#if !defined(_WIN32) struct sigaction sa { }; sa.sa_handler = sw_handler; sigemptyset(&sa.sa_mask); @@ -272,6 +282,7 @@ int main(int argc, char *argv[]) sigaction(SIGTERM, &sa, nullptr); sigaction(SIGINT , &sa, nullptr); +#endif if (test.empty() == false) load_p11_x11(b, test); diff --git a/utils.cpp b/utils.cpp index 847e98b..6923d95 100644 --- a/utils.cpp +++ b/utils.cpp @@ -16,6 +16,9 @@ #include #include +#include "windows/win32.h" + + void setBit(uint16_t & v, const int bit, const bool vb) { const uint16_t mask = 1 << bit; diff --git a/windows/README.txt b/windows/README.txt new file mode 100644 index 0000000..a7cd717 --- /dev/null +++ b/windows/README.txt @@ -0,0 +1,3 @@ +cmake -DCMAKE_TOOLCHAIN_FILE=mingw64.cmake .. + +make kek-win32 diff --git a/windows/mingw64.cmake b/windows/mingw64.cmake new file mode 100644 index 0000000..429aa40 --- /dev/null +++ b/windows/mingw64.cmake @@ -0,0 +1,14 @@ +# cmake -DCMAKE_TOOLCHAIN_FILE=mingw64.cmake .. + +set(CMAKE_SYSTEM_NAME Windows) +set(TOOLCHAIN_PREFIX x86_64-w64-mingw32) + +set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc-posix) +set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++-posix) +set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres) + +set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX} /usr/lib/gcc/${TOOLCHAIN_PREFIX}/7.3-posix) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/windows/win32.cpp b/windows/win32.cpp new file mode 100644 index 0000000..b351afc --- /dev/null +++ b/windows/win32.cpp @@ -0,0 +1,48 @@ +#if defined(_WIN32) +// from https://stackoverflow.com/questions/40159892/using-asprintf-on-windows + +#include /* needed for vsnprintf */ +#include /* needed for malloc, free */ +#include /* needed for va_* */ + +int vscprintf(const char *format, va_list ap) +{ + va_list ap_copy; + va_copy(ap_copy, ap); + int retval = vsnprintf(NULL, 0, format, ap_copy); + va_end(ap_copy); + return retval; +} + +/* + * asprintf, vasprintf: + * MSVC does not implement these, thus we implement them here + * GNU-C-compatible compilers implement these with the same names, thus we + * don't have to do anything + */ +int vasprintf(char **strp, const char *format, va_list ap) +{ + int len = vscprintf(format, ap); + if (len == -1) + return -1; + char *str = (char*)malloc((size_t) len + 1); + if (!str) + return -1; + int retval = vsnprintf(str, len + 1, format, ap); + if (retval == -1) { + free(str); + return -1; + } + *strp = str; + return retval; +} + +int asprintf(char **strp, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + int retval = vasprintf(strp, format, ap); + va_end(ap); + return retval; +} +#endif diff --git a/windows/win32.h b/windows/win32.h new file mode 100644 index 0000000..52423ea --- /dev/null +++ b/windows/win32.h @@ -0,0 +1,4 @@ +#pragma once + +int vasprintf(char **strp, const char *format, va_list ap); +int asprintf(char **strp, const char *format, ...);